diff --git a/agents/integrations/providers.md b/agents/integrations/providers.md index bafdd652d1..dde977fac6 100644 --- a/agents/integrations/providers.md +++ b/agents/integrations/providers.md @@ -3,12 +3,14 @@ ## Source Of Truth - `src/shared/core/agents/agent-provider-registry.ts` +- `packages/plugins/src/agents/impl/*` +- `packages/plugins/src/agents/registry.ts` - `src/main/core/dependencies/dependency-managers.ts` - `src/main/core/pty/` -## Current Providers (32) +## Current Providers (34) -codex, claude, grok, devin, qwen, qoder, droid, gemini, antigravity, cursor, copilot, amp, commandcode, opencode, hermes, charm, auggie, goose, kimi, kilocode, kiro, rovo, cline, continue, codebuff, freebuff, mistral, jules, junie, pi, autohand, letta +codex, claude, grok, devin, qwen, qoder, droid, gemini, antigravity, cursor, copilot, amp, commandcode, opencode, hermes, charm, auggie, goose, kimi, kilocode, kiro, rovo, cline, continue, codebuff, freebuff, mistral, jules, junie, pi, autohand, letta, mimocode, zero ## Provider Metadata Includes @@ -39,8 +41,10 @@ or notify an inferred status for that event. ## Adding Or Changing A Provider 1. update `src/shared/core/agents/agent-provider-registry.ts` -2. update allowlisted agent env vars in `src/main/core/pty/pty-env.ts` if needed -3. add or update hook/plugin installation in `src/main/core/agent-hooks/` if the provider +2. add or update the provider plugin under `packages/plugins/src/agents/impl/*` +3. register the plugin in `packages/plugins/src/agents/registry.ts` +4. update allowlisted agent env vars in `src/main/core/pty/pty-env.ts` if needed +5. add or update hook/plugin installation in `src/main/core/agent-hooks/` if the provider supports explicit events -4. validate detection behavior in `src/main/core/dependencies/` -5. add or update tests for any non-standard behavior +6. validate detection behavior in `src/main/core/dependencies/` +7. add or update tests for any non-standard behavior diff --git a/apps/emdash-desktop/src/assets/images/zero.svg b/apps/emdash-desktop/src/assets/images/zero.svg new file mode 100644 index 0000000000..f1d20dc1de --- /dev/null +++ b/apps/emdash-desktop/src/assets/images/zero.svg @@ -0,0 +1,4 @@ + + + 0 + diff --git a/apps/emdash-desktop/src/shared/core/agents/agent-provider-registry.ts b/apps/emdash-desktop/src/shared/core/agents/agent-provider-registry.ts index e37fba5561..a3e7556403 100644 --- a/apps/emdash-desktop/src/shared/core/agents/agent-provider-registry.ts +++ b/apps/emdash-desktop/src/shared/core/agents/agent-provider-registry.ts @@ -32,6 +32,7 @@ export const AGENT_PROVIDER_IDS = [ 'letta', 'autohand', 'mimocode', + 'zero', ] as const; export type AgentProviderId = (typeof AGENT_PROVIDER_IDS)[number]; @@ -732,6 +733,21 @@ export const AGENT_PROVIDERS: AgentProviderDefinition[] = [ terminalOnly: true, supportsHooks: true, }, + { + id: 'zero', + name: 'Zero', + description: + 'Terminal coding agent with multi-provider model support, local-first configuration, and terminal-first coding workflows.', + docUrl: 'https://zero.gitlawb.com/', + installCommand: 'npm install -g @gitlawb/zero', + commands: ['zero'], + versionArgs: ['--version'], + cli: 'zero', + useKeystrokeInjection: true, + icon: 'zero.svg', + alt: 'Zero CLI', + terminalOnly: true, + }, ]; const PROVIDER_MAP = new Map( diff --git a/packages/plugins/src/agents/impl/zero/icon.ts b/packages/plugins/src/agents/impl/zero/icon.ts new file mode 100644 index 0000000000..9474ab5891 --- /dev/null +++ b/packages/plugins/src/agents/impl/zero/icon.ts @@ -0,0 +1,12 @@ +import type { AgentIconAsset } from '@emdash/core/agents/plugins'; + +export const icon: AgentIconAsset = { + kind: 'svg', + alt: 'Zero CLI', + variants: [ + { + minSize: 0, + light: `0`, + }, + ], +}; diff --git a/packages/plugins/src/agents/impl/zero/index.test.ts b/packages/plugins/src/agents/impl/zero/index.test.ts new file mode 100644 index 0000000000..4cd3f5ea6b --- /dev/null +++ b/packages/plugins/src/agents/impl/zero/index.test.ts @@ -0,0 +1,43 @@ +import type { CommandContext } from '@emdash/core/agents/plugins'; +import { describe, expect, it } from 'vitest'; +import { pluginRegistry } from '../../registry'; + +const zero = pluginRegistry.get('zero')!; + +function build(ctx: CommandContext) { + return zero.behavior.prompt!.buildCommand(ctx); +} + +describe('zero plugin', () => { + it('registers install metadata and binary name', () => { + expect(zero).toBeDefined(); + expect(zero.metadata.websiteUrl).toBe('https://zero.gitlawb.com/'); + expect(zero.capabilities.hostDependency.binaryNames).toEqual(['zero']); + expect(zero.capabilities.hostDependency.installCommands.macos?.[0]?.command).toBe( + 'npm install -g @gitlawb/zero' + ); + expect(zero.capabilities.hostDependency.updates).toMatchObject({ + kind: 'supported', + releaseSource: { kind: 'npm', package: '@gitlawb/zero' }, + }); + expect(zero.capabilities.mcp.kind).toBe('none'); + expect(zero.capabilities.sessions.kind).toBe('stateless'); + }); + + it('starts the TUI and leaves prompt delivery to keystroke injection', () => { + expect(zero.capabilities.prompt.kind).toBe('keystroke'); + + const result = build({ + cli: 'zero', + autoApprove: true, + initialPrompt: 'Fix the bug', + sessionId: 'conv-1', + isResuming: false, + model: '', + }); + + expect(result.command).toBe('zero'); + expect(result.args).toEqual([]); + expect(result.env).toEqual({}); + }); +}); diff --git a/packages/plugins/src/agents/impl/zero/index.ts b/packages/plugins/src/agents/impl/zero/index.ts new file mode 100644 index 0000000000..1de4755560 --- /dev/null +++ b/packages/plugins/src/agents/impl/zero/index.ts @@ -0,0 +1,29 @@ +import { definePlugin, registerPluginBehavior } from '@emdash/core/agents/plugins'; +import { buildStandardCommand, npmDependency } from '@emdash/core/agents/plugins/helpers'; +import { icon } from './icon'; + +export const plugin = definePlugin( + { + id: 'zero', + name: 'Zero', + description: + 'Terminal coding agent with multi-provider model support, local-first configuration, and terminal-first coding workflows.', + websiteUrl: 'https://zero.gitlawb.com/', + }, + { + hostDependency: npmDependency({ id: 'zero', package: '@gitlawb/zero' }), + prompt: { + kind: 'keystroke', + }, + sessions: { + kind: 'stateless', + }, + }, + { icon } +); + +export const provider = registerPluginBehavior(plugin, { + prompt: { + buildCommand: (ctx) => buildStandardCommand(ctx, {}), + }, +}); diff --git a/packages/plugins/src/agents/registry.ts b/packages/plugins/src/agents/registry.ts index b6298be8a6..9d69a072e4 100644 --- a/packages/plugins/src/agents/registry.ts +++ b/packages/plugins/src/agents/registry.ts @@ -33,6 +33,7 @@ import { provider as pi } from './impl/pi'; import { provider as qoder } from './impl/qoder'; import { provider as qwen } from './impl/qwen'; import { provider as rovo } from './impl/rovo'; +import { provider as zero } from './impl/zero'; export const pluginRegistry = createPluginRegistry(); @@ -70,6 +71,7 @@ for (const p of [ qoder, qwen, rovo, + zero, ]) { pluginRegistry.register(p); }