@jini-ai/agent-runtime 0.3.8 → 0.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/auth.d.ts CHANGED
@@ -13,11 +13,13 @@ export declare function antigravityAuthGuidance(hostName?: string): string;
13
13
  export declare function antigravityQuotaGuidance(): string;
14
14
  export declare function reasonixAuthGuidance(hostName?: string): string;
15
15
  export declare function claudeAuthGuidance(hostName?: string): string;
16
+ export declare function geminiAuthGuidance(hostName?: string): string;
16
17
  export declare function isCursorAuthFailureText(text: string): boolean;
17
18
  export declare function isAntigravityAuthFailureText(text: string): boolean;
18
19
  export declare function isDeepSeekAuthFailureText(text: string): boolean;
19
20
  export declare function isReasonixAuthFailureText(text: string): boolean;
20
21
  export declare function isClaudeAuthFailureText(text: string): boolean;
22
+ export declare function isGeminiAuthFailureText(text: string): boolean;
21
23
  export declare function classifyAgentAuthFailure(agentId: string, text: string, hostName?: string): AgentAuthProbeResult | null;
22
24
  export type AgentServiceFailureCode = 'AGENT_AUTH_REQUIRED' | 'RATE_LIMITED' | 'UPSTREAM_UNAVAILABLE';
23
25
  export declare function classifyAgentServiceFailure(text: string): AgentServiceFailureCode | null;
package/dist/auth.js CHANGED
@@ -55,6 +55,17 @@ function reasonixAuthGuidanceText(hostName) {
55
55
  function claudeAuthGuidanceText(hostName) {
56
56
  return `Claude Code is installed but is not authenticated. Run \`claude auth login\` or open \`claude\` and complete login in a terminal, then rescan. If ${hostName} was launched outside an interactive shell, your shell rc files (e.g. ~/.zshrc) may not be loaded into its environment.`;
57
57
  }
58
+ // Gemini CLI has two distinct sign-in failures, and one fix covers both. With no auth method
59
+ // configured, headless mode exits with "Please set an Auth method in your <settings.json> or
60
+ // specify one of the following environment variables before running: GEMINI_API_KEY,
61
+ // GOOGLE_GENAI_USE_VERTEXAI, GOOGLE_GENAI_USE_GCA". With "Login with Google" on a free / Google AI
62
+ // Pro / Ultra account it dies with `IneligibleTierError: This client is no longer supported for
63
+ // Gemini Code Assist for individuals` (Google stopped serving those tiers on 2026-06-18; API keys,
64
+ // Vertex AI and Code Assist licenses still work). Signing in again cannot fix the second one, so
65
+ // the guidance points at an API key or Antigravity instead of a re-login.
66
+ function geminiAuthGuidanceText(hostName) {
67
+ return `Gemini CLI is installed but has no usable sign-in. Google no longer serves Gemini CLI's "Login with Google" for free, Google AI Pro or Ultra accounts. Use a Gemini API key instead: run \`gemini\` in a terminal, type /auth, choose "Use Gemini API key", and make GEMINI_API_KEY available to ${hostName}'s process environment (or configure Vertex AI). Google's replacement for individual accounts is Antigravity (\`agy\`), which you can pick here instead.`;
68
+ }
58
69
  export function cursorAuthGuidance(hostName = DEFAULT_HOST_NAME) {
59
70
  return cursorAuthGuidanceText(hostName);
60
71
  }
@@ -73,6 +84,9 @@ export function reasonixAuthGuidance(hostName = DEFAULT_HOST_NAME) {
73
84
  export function claudeAuthGuidance(hostName = DEFAULT_HOST_NAME) {
74
85
  return claudeAuthGuidanceText(hostName);
75
86
  }
87
+ export function geminiAuthGuidance(hostName = DEFAULT_HOST_NAME) {
88
+ return geminiAuthGuidanceText(hostName);
89
+ }
76
90
  export function isCursorAuthFailureText(text) {
77
91
  const value = String(text || '');
78
92
  if (!value.trim())
@@ -145,6 +159,16 @@ export function isClaudeAuthFailureText(text) {
145
159
  /authentication required/i.test(value) ||
146
160
  /please (?:sign|log)[ _-]?in/i.test(value));
147
161
  }
162
+ export function isGeminiAuthFailureText(text) {
163
+ const value = String(text || '');
164
+ if (!value.trim())
165
+ return false;
166
+ return (/please set an auth method/i.test(value) ||
167
+ /IneligibleTierError/.test(value) ||
168
+ /no longer supported for gemini code assist/i.test(value) ||
169
+ /error authenticating/i.test(value) ||
170
+ /api key not valid/i.test(value));
171
+ }
148
172
  export function classifyAgentAuthFailure(agentId, text, hostName = DEFAULT_HOST_NAME) {
149
173
  if (agentId === 'claude') {
150
174
  if (!isClaudeAuthFailureText(text))
@@ -171,6 +195,11 @@ export function classifyAgentAuthFailure(agentId, text, hostName = DEFAULT_HOST_
171
195
  return null;
172
196
  return { status: 'missing', message: reasonixAuthGuidance(hostName) };
173
197
  }
198
+ if (agentId === 'gemini') {
199
+ if (!isGeminiAuthFailureText(text))
200
+ return null;
201
+ return { status: 'missing', message: geminiAuthGuidance(hostName) };
202
+ }
174
203
  return null;
175
204
  }
176
205
  // A bare HTTP status number (`500`, `429`, …) is too noisy to trust on its own
@@ -250,7 +279,7 @@ function genericAuthGuidance(agentName, hostName) {
250
279
  // regex (e.g. cursor-agent's healthy `status` output mentions "login" in
251
280
  // ways the generic matcher would misread). The generic classifier is only a
252
281
  // fallback for adapters with no tailored classifier of their own.
253
- const TAILORED_AUTH_AGENTS = new Set(['claude', 'cursor-agent', 'deepseek', 'antigravity', 'reasonix']);
282
+ const TAILORED_AUTH_AGENTS = new Set(['claude', 'cursor-agent', 'deepseek', 'antigravity', 'reasonix', 'gemini']);
254
283
  function hasNonEmptyEnv(env, keys) {
255
284
  return keys.some((key) => {
256
285
  const value = env[key];
@@ -0,0 +1,13 @@
1
+ export declare const auggieAgentDef: {
2
+ id: string;
3
+ name: string;
4
+ bin: string;
5
+ versionArgs: string[];
6
+ fetchModels: (resolvedBin: string, env: import("../types.js").RuntimeEnv) => Promise<import("../types.js").RuntimeModelOption[]>;
7
+ fallbackModels: import("../types.js").RuntimeModelOption[];
8
+ buildArgs: () => string[];
9
+ streamFormat: string;
10
+ externalMcpInjection: "acp-merge";
11
+ imageDelivery: "native";
12
+ };
13
+ //# sourceMappingURL=auggie.d.ts.map
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @module defs/auggie
3
+ *
4
+ * Augment Code's Auggie CLI (`auggie`, npm `@augmentcode/auggie`). Runs over ACP: `auggie --acp`
5
+ * is the launch command the official ACP registry lists
6
+ * (<https://github.com/agentclientprotocol/registry>, `auggie/agent.json`). Sign-in is
7
+ * `auggie login` in a terminal.
8
+ */
9
+ import { detectAcpModels, DEFAULT_MODEL_OPTION } from './shared.js';
10
+ export const auggieAgentDef = {
11
+ id: 'auggie',
12
+ name: 'Auggie CLI',
13
+ bin: 'auggie',
14
+ versionArgs: ['--version'],
15
+ fetchModels: async (resolvedBin, env) => detectAcpModels({
16
+ bin: resolvedBin,
17
+ args: ['--acp'],
18
+ env,
19
+ timeoutMs: 15_000,
20
+ defaultModelOption: DEFAULT_MODEL_OPTION,
21
+ }),
22
+ fallbackModels: [DEFAULT_MODEL_OPTION],
23
+ buildArgs: () => ['--acp'],
24
+ streamFormat: 'acp-json-rpc',
25
+ externalMcpInjection: 'acp-merge',
26
+ // ACP's `resource_link` prompt blocks carry images natively for every
27
+ // `acp-json-rpc` def — see `types.ts#RuntimeAgentDef.imageDelivery`'s doc.
28
+ imageDelivery: 'native',
29
+ };
30
+ //# sourceMappingURL=auggie.js.map
@@ -14,6 +14,7 @@ export declare const claudeAgentDef: {
14
14
  '--add-dir': string;
15
15
  '--effort': string;
16
16
  '--append-system-prompt': string;
17
+ '--setting-sources': string;
17
18
  };
18
19
  fallbackModels: import("../types.js").RuntimeModelOption[];
19
20
  fallbackModelsAssertedAt: string;
@@ -27,6 +28,9 @@ export declare const claudeAgentDef: {
27
28
  promptInputFormat: "stream-json";
28
29
  streamFormat: string;
29
30
  externalMcpInjection: "claude-mcp-json";
31
+ env: {
32
+ ENABLE_TOOL_SEARCH: string;
33
+ };
30
34
  systemPromptDelivery: {
31
35
  strategy: "append-flag";
32
36
  flag: string;
@@ -108,6 +108,7 @@ export const claudeAgentDef = {
108
108
  '--add-dir': 'addDir',
109
109
  '--effort': 'effort',
110
110
  '--append-system-prompt': 'appendSystemPrompt',
111
+ '--setting-sources': 'settingSources',
111
112
  },
112
113
  // `claude` has no list-models subcommand, so the model list is answered from the best source
113
114
  // available, in this order:
@@ -238,6 +239,15 @@ export const claudeAgentDef = {
238
239
  if (options.allowedTools && options.allowedTools.length > 0) {
239
240
  args.push('--allowedTools', ...options.allowedTools);
240
241
  }
242
+ // See `RuntimeBuildOptions.settingSources`. Probe-gated like `--effort`: an older build
243
+ // rejects an unknown option with exit 1, which would kill the chat rather than degrade it.
244
+ if (options.settingSources !== undefined && caps.settingSources) {
245
+ args.push('--setting-sources', options.settingSources.join(','));
246
+ }
247
+ // See `RuntimeBuildOptions.settings`. Not probe-gated: `--settings` long predates `--setting-sources`.
248
+ if (options.settings) {
249
+ args.push('--settings', options.settings);
250
+ }
241
251
  return args;
242
252
  },
243
253
  promptViaStdin: true,
@@ -247,6 +257,14 @@ export const claudeAgentDef = {
247
257
  // so the daemon writes the user's external MCP servers there before
248
258
  // launching (server.ts handles the cwd guard).
249
259
  externalMcpInjection: 'claude-mcp-json',
260
+ // Load MCP tools up front instead of deferring them behind the CLI's ToolSearch tool.
261
+ // Deferral cost every run one extra model round (a `select:` ToolSearch call, ~3 s) before its
262
+ // first real tool call, while the run's MCP set is only what the daemon stages
263
+ // (`--strict-mcp-config`; 11 tools for the Tovu host), so loading it eagerly is cheap. Documented at
264
+ // code.claude.com/docs/en/mcp ("`false` — All MCP tools loaded upfront, no deferral"); verified
265
+ // in the installed 2.1.283 binary (a defined-falsy value selects the "standard" tool mode).
266
+ // A default only: a run's own env can still set ENABLE_TOOL_SEARCH (see agent-executor).
267
+ env: { ENABLE_TOOL_SEARCH: 'false' },
250
268
  // Formerly inline in `buildArgs` above (see the comment there) — moved to the declarative
251
269
  // shape every def now uses to receive `RuntimeBuildOptions.systemPromptOverlay`. Same flag,
252
270
  // same probe gate (`capabilityFlags['--append-system-prompt']` above), same "append, never
@@ -0,0 +1,13 @@
1
+ export declare const clineAgentDef: {
2
+ id: string;
3
+ name: string;
4
+ bin: string;
5
+ versionArgs: string[];
6
+ fetchModels: (resolvedBin: string, env: import("../types.js").RuntimeEnv) => Promise<import("../types.js").RuntimeModelOption[]>;
7
+ fallbackModels: import("../types.js").RuntimeModelOption[];
8
+ buildArgs: () => string[];
9
+ streamFormat: string;
10
+ externalMcpInjection: "acp-merge";
11
+ imageDelivery: "native";
12
+ };
13
+ //# sourceMappingURL=cline.d.ts.map
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @module defs/cline
3
+ *
4
+ * Cline CLI (`cline`, npm `cline`). Runs over ACP: `cline --acp` is both the launch command the
5
+ * official ACP registry lists (<https://github.com/agentclientprotocol/registry>, `cline/agent.json`)
6
+ * and what an installed `cline` 3.0.60 answered live — `initialize` returned
7
+ * `promptCapabilities.image: true` and three `authMethods`, and `session/new` on a machine with no
8
+ * sign-in failed with "Authentication required: Call authenticate before starting a session",
9
+ * which `auth.ts`'s generic classifier already reads as a missing sign-in (fix: `cline auth`).
10
+ */
11
+ import { detectAcpModels, DEFAULT_MODEL_OPTION } from './shared.js';
12
+ export const clineAgentDef = {
13
+ id: 'cline',
14
+ name: 'Cline',
15
+ bin: 'cline',
16
+ versionArgs: ['--version'],
17
+ fetchModels: async (resolvedBin, env) => detectAcpModels({
18
+ bin: resolvedBin,
19
+ args: ['--acp'],
20
+ env,
21
+ timeoutMs: 15_000,
22
+ defaultModelOption: DEFAULT_MODEL_OPTION,
23
+ }),
24
+ fallbackModels: [DEFAULT_MODEL_OPTION],
25
+ buildArgs: () => ['--acp'],
26
+ streamFormat: 'acp-json-rpc',
27
+ externalMcpInjection: 'acp-merge',
28
+ // ACP's `resource_link` prompt blocks carry images natively for every
29
+ // `acp-json-rpc` def — see `types.ts#RuntimeAgentDef.imageDelivery`'s doc.
30
+ imageDelivery: 'native',
31
+ };
32
+ //# sourceMappingURL=cline.js.map
@@ -0,0 +1,11 @@
1
+ export declare const crushAgentDef: {
2
+ id: string;
3
+ name: string;
4
+ bin: string;
5
+ versionArgs: string[];
6
+ fallbackModels: import("../types.js").RuntimeModelOption[];
7
+ buildArgs: (_prompt: string, _imagePaths: string[], _extra: string[] | undefined, options?: import("../types.js").RuntimeBuildOptions | undefined) => string[];
8
+ promptViaStdin: true;
9
+ streamFormat: string;
10
+ };
11
+ //# sourceMappingURL=crush.d.ts.map
@@ -0,0 +1,37 @@
1
+ /**
2
+ * @module defs/crush
3
+ *
4
+ * Charm's Crush (`crush`). Checked against upstream source (`internal/cmd/run.go` / `root.go`):
5
+ * `crush run [prompt...]` runs one prompt non-interactively and exits; with no prompt args, piped
6
+ * stdin becomes the whole prompt ("no prompt provided" only when both are empty). The answer is
7
+ * plain text on stdout, the spinner goes to stderr and `--quiet` hides it. `--yolo` (root flag)
8
+ * skips permission requests; `--model` takes `model` or `provider/model`.
9
+ *
10
+ * No `externalMcpInjection`: Crush reads MCP servers from its `crush.json` config, with no
11
+ * per-run flag to point it elsewhere.
12
+ */
13
+ import { DEFAULT_MODEL_OPTION } from './shared.js';
14
+ export const crushAgentDef = {
15
+ id: 'crush',
16
+ name: 'Crush',
17
+ bin: 'crush',
18
+ versionArgs: ['--version'],
19
+ // Models come from the providers the user configured in Crush; there is no stable default
20
+ // list to ship, so the picker offers the CLI default and accepts any typed id.
21
+ fallbackModels: [DEFAULT_MODEL_OPTION],
22
+ buildArgs: (_prompt, _imagePaths, _extra, options = {}) => {
23
+ const args = ['run', '--quiet'];
24
+ // See `RuntimeBuildOptions.permissionMode`'s doc: bypass is the default (unchanged
25
+ // behavior) unless a caller explicitly opts into a restricted run.
26
+ if (options.permissionMode !== 'restricted') {
27
+ args.push('--yolo');
28
+ }
29
+ if (options.model && options.model !== 'default') {
30
+ args.push('--model', options.model);
31
+ }
32
+ return args;
33
+ },
34
+ promptViaStdin: true,
35
+ streamFormat: 'plain',
36
+ };
37
+ //# sourceMappingURL=crush.js.map
@@ -0,0 +1,11 @@
1
+ export declare const droidAgentDef: {
2
+ id: string;
3
+ name: string;
4
+ bin: string;
5
+ versionArgs: string[];
6
+ fallbackModels: import("../types.js").RuntimeModelOption[];
7
+ buildArgs: (_prompt: string, _imagePaths: string[], _extra: string[] | undefined, options?: import("../types.js").RuntimeBuildOptions | undefined) => string[];
8
+ promptViaStdin: true;
9
+ streamFormat: string;
10
+ };
11
+ //# sourceMappingURL=droid.d.ts.map
@@ -0,0 +1,38 @@
1
+ /**
2
+ * @module defs/droid
3
+ *
4
+ * Factory's Droid CLI (`droid`). Uses the documented headless mode, `droid exec`
5
+ * (<https://docs.factory.ai/reference/cli-reference>, <https://docs.factory.ai/droid-exec/overview>):
6
+ * the prompt can be piped on stdin (`cat file | droid exec`), `--output-format text` prints the
7
+ * final answer, and `-m/--model` picks the model. `droid exec` is read-only unless given an
8
+ * autonomy level; `--skip-permissions-unsafe` lifts every permission check (it cannot be combined
9
+ * with `--auto`). Auth is `FACTORY_API_KEY` or a prior `droid` login.
10
+ *
11
+ * Not ACP: the ACP registry launches Droid with `droid exec --output-format acp-daemon`, but that
12
+ * value is not in the CLI reference, newer builds were reported to switch to `acp`, and the daemon
13
+ * variant was reported to fail with stdio MCP servers. The documented text mode is the stable one.
14
+ * No `externalMcpInjection` for the same reason.
15
+ */
16
+ import { DEFAULT_MODEL_OPTION } from './shared.js';
17
+ export const droidAgentDef = {
18
+ id: 'droid',
19
+ name: 'Factory Droid',
20
+ bin: 'droid',
21
+ versionArgs: ['--version'],
22
+ fallbackModels: [DEFAULT_MODEL_OPTION],
23
+ buildArgs: (_prompt, _imagePaths, _extra, options = {}) => {
24
+ const args = ['exec', '--output-format', 'text'];
25
+ // See `RuntimeBuildOptions.permissionMode`'s doc: bypass is the default (unchanged
26
+ // behavior); a restricted run keeps `droid exec`'s own read-only default.
27
+ if (options.permissionMode !== 'restricted') {
28
+ args.push('--skip-permissions-unsafe');
29
+ }
30
+ if (options.model && options.model !== 'default') {
31
+ args.push('--model', options.model);
32
+ }
33
+ return args;
34
+ },
35
+ promptViaStdin: true,
36
+ streamFormat: 'plain',
37
+ };
38
+ //# sourceMappingURL=droid.js.map
@@ -0,0 +1,17 @@
1
+ export declare const geminiAgentDef: {
2
+ id: string;
3
+ name: string;
4
+ bin: string;
5
+ versionArgs: string[];
6
+ versionProbeTimeoutMs: number;
7
+ helpArgs: string[];
8
+ capabilityFlags: {
9
+ "--skip-trust": string;
10
+ };
11
+ fallbackModels: import("../types.js").RuntimeModelOption[];
12
+ buildArgs: (_prompt: string, _imagePaths: string[], extraAllowedDirs?: string[] | undefined, options?: import("../types.js").RuntimeBuildOptions | undefined) => string[];
13
+ promptViaStdin: true;
14
+ streamFormat: string;
15
+ eventParser: string;
16
+ };
17
+ //# sourceMappingURL=gemini.d.ts.map
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @module defs/gemini
3
+ *
4
+ * Google's Gemini CLI (`gemini`, npm `@google/gemini-cli`). Checked against an installed
5
+ * `gemini` 0.58.0 (`gemini --help` and the bundled headless code path) and the upstream headless
6
+ * docs (<https://geminicli.com/docs/cli/headless>):
7
+ *
8
+ * - Headless mode starts whenever stdin is not a TTY; the whole piped stdin becomes the prompt
9
+ * (`-p` is only needed to pass the prompt in argv, and would be "appended to input on stdin").
10
+ * So the prompt goes over stdin, like the Qwen Code fork, which avoids Windows `spawn
11
+ * ENAMETOOLONG` on large composed prompts.
12
+ * - `--output-format stream-json` emits the JSONL `init` / `message` / `tool_use` /
13
+ * `tool_result` / `error` / `result` events that `json-event-stream.ts`'s `gemini` parser
14
+ * already reads.
15
+ * - `--approval-mode yolo` auto-approves every tool (the `--yolo` alias does the same).
16
+ * - Since folder trust landed, a headless run in an untrusted directory exits with "Gemini CLI
17
+ * is not running in a trusted directory. To proceed, either use `--skip-trust`, …". The host
18
+ * already chose the run's cwd, so the def trusts it for this session only. Older builds
19
+ * reject unknown flags, so `--skip-trust` is gated on the `--help` capability probe.
20
+ * - `--include-directories` (repeatable) widens the workspace to dirs outside the cwd.
21
+ *
22
+ * Auth: since 2026-06-18 Google no longer serves Gemini CLI's "Login with Google" for free /
23
+ * Google AI Pro / Ultra individual accounts (the run dies with `IneligibleTierError: This client
24
+ * is no longer supported for Gemini Code Assist for individuals`). A Gemini API key, Vertex AI,
25
+ * or a Gemini Code Assist license still works. There is no side-effect-free auth-status
26
+ * subcommand, so no `authProbe`; `auth.ts#classifyAgentAuthFailure` turns the failure text into
27
+ * setup guidance instead.
28
+ */
29
+ import { DEFAULT_MODEL_OPTION } from './shared.js';
30
+ import { agentCapabilities } from '../capabilities.js';
31
+ const SKIP_TRUST_FLAG = '--skip-trust';
32
+ export const geminiAgentDef = {
33
+ id: 'gemini',
34
+ name: 'Gemini CLI',
35
+ bin: 'gemini',
36
+ versionArgs: ['--version'],
37
+ // A cold `gemini --version` took 4.7 s on the dev machine (warm ~2 s), past the 3 s default.
38
+ versionProbeTimeoutMs: 10_000,
39
+ helpArgs: ['--help'],
40
+ capabilityFlags: {
41
+ [SKIP_TRUST_FLAG]: 'skipTrust',
42
+ },
43
+ // No `models` subcommand. `auto` and the concrete ids below are the ones the installed
44
+ // 0.58.0 bundle and the upstream model docs name; any other id can still be typed in.
45
+ fallbackModels: [
46
+ DEFAULT_MODEL_OPTION,
47
+ { id: 'auto', label: 'auto' },
48
+ { id: 'gemini-3.1-pro-preview', label: 'gemini-3.1-pro-preview' },
49
+ { id: 'gemini-3.5-flash', label: 'gemini-3.5-flash' },
50
+ { id: 'gemini-3-pro-preview', label: 'gemini-3-pro-preview' },
51
+ { id: 'gemini-3-flash-preview', label: 'gemini-3-flash-preview' },
52
+ { id: 'gemini-2.5-pro', label: 'gemini-2.5-pro' },
53
+ { id: 'gemini-2.5-flash', label: 'gemini-2.5-flash' },
54
+ ],
55
+ buildArgs: (_prompt, _imagePaths, extraAllowedDirs = [], options = {}) => {
56
+ const args = ['--output-format', 'stream-json'];
57
+ if (agentCapabilities.get('gemini')?.skipTrust) {
58
+ args.push(SKIP_TRUST_FLAG);
59
+ }
60
+ // See `RuntimeBuildOptions.permissionMode`'s doc: bypass is the default (unchanged
61
+ // behavior) unless a caller explicitly opts into a restricted run.
62
+ if (options.permissionMode !== 'restricted') {
63
+ args.push('--approval-mode', 'yolo');
64
+ }
65
+ if (options.model && options.model !== 'default') {
66
+ args.push('--model', options.model);
67
+ }
68
+ const dirs = (extraAllowedDirs || []).filter((d) => typeof d === 'string' && d.length > 0);
69
+ for (const d of dirs)
70
+ args.push('--include-directories', d);
71
+ return args;
72
+ },
73
+ promptViaStdin: true,
74
+ streamFormat: 'json-event-stream',
75
+ eventParser: 'gemini',
76
+ // No `externalMcpInjection` yet: Gemini CLI reads `mcpServers` from `settings.json` (user,
77
+ // project `.gemini/settings.json`, or a system file named by
78
+ // `GEMINI_CLI_SYSTEM_SETTINGS_PATH`), with no per-run `--mcp-config` flag. A run-scoped
79
+ // system-settings file is the likely strategy, but it is not wired or verified live.
80
+ };
81
+ //# sourceMappingURL=gemini.js.map
@@ -0,0 +1,13 @@
1
+ export declare const gooseAgentDef: {
2
+ id: string;
3
+ name: string;
4
+ bin: string;
5
+ versionArgs: string[];
6
+ fetchModels: (resolvedBin: string, env: import("../types.js").RuntimeEnv) => Promise<import("../types.js").RuntimeModelOption[]>;
7
+ fallbackModels: import("../types.js").RuntimeModelOption[];
8
+ buildArgs: () => string[];
9
+ streamFormat: string;
10
+ externalMcpInjection: "acp-merge";
11
+ imageDelivery: "native";
12
+ };
13
+ //# sourceMappingURL=goose.d.ts.map
@@ -0,0 +1,33 @@
1
+ /**
2
+ * @module defs/goose
3
+ *
4
+ * Block's goose (`goose`). Runs over ACP: `goose acp` is the launch command the official ACP
5
+ * registry lists (<https://github.com/agentclientprotocol/registry>, `goose/agent.json`). The
6
+ * provider and model come from goose's own config, so `goose configure` has to have been run once.
7
+ *
8
+ * Name clash: `pressly/goose` (a Go database-migration tool) also installs a `goose` binary. On a
9
+ * machine that has only that one, detection will list goose as installed and the first run will
10
+ * fail on the unknown `acp` command.
11
+ */
12
+ import { detectAcpModels, DEFAULT_MODEL_OPTION } from './shared.js';
13
+ export const gooseAgentDef = {
14
+ id: 'goose',
15
+ name: 'goose',
16
+ bin: 'goose',
17
+ versionArgs: ['--version'],
18
+ fetchModels: async (resolvedBin, env) => detectAcpModels({
19
+ bin: resolvedBin,
20
+ args: ['acp'],
21
+ env,
22
+ timeoutMs: 15_000,
23
+ defaultModelOption: DEFAULT_MODEL_OPTION,
24
+ }),
25
+ fallbackModels: [DEFAULT_MODEL_OPTION],
26
+ buildArgs: () => ['acp'],
27
+ streamFormat: 'acp-json-rpc',
28
+ externalMcpInjection: 'acp-merge',
29
+ // ACP's `resource_link` prompt blocks carry images natively for every
30
+ // `acp-json-rpc` def — see `types.ts#RuntimeAgentDef.imageDelivery`'s doc.
31
+ imageDelivery: 'native',
32
+ };
33
+ //# sourceMappingURL=goose.js.map
@@ -10,13 +10,19 @@ export * from './aider.js';
10
10
  export * from './amp.js';
11
11
  export * from './amr.js';
12
12
  export * from './antigravity.js';
13
+ export * from './auggie.js';
13
14
  export * from './claude.js';
15
+ export * from './cline.js';
14
16
  export * from './codebuddy.js';
15
17
  export * from './codex.js';
16
18
  export * from './copilot.js';
19
+ export * from './crush.js';
17
20
  export * from './cursor-agent.js';
21
+ export * from './droid.js';
22
+ export * from './gemini.js';
18
23
  export * from './deepseek.js';
19
24
  export * from './devin.js';
25
+ export * from './goose.js';
20
26
  export * from './grok-build.js';
21
27
  export * from './hermes.js';
22
28
  export * from './kilo.js';
@@ -10,13 +10,19 @@ export * from './aider.js';
10
10
  export * from './amp.js';
11
11
  export * from './amr.js';
12
12
  export * from './antigravity.js';
13
+ export * from './auggie.js';
13
14
  export * from './claude.js';
15
+ export * from './cline.js';
14
16
  export * from './codebuddy.js';
15
17
  export * from './codex.js';
16
18
  export * from './copilot.js';
19
+ export * from './crush.js';
17
20
  export * from './cursor-agent.js';
21
+ export * from './droid.js';
22
+ export * from './gemini.js';
18
23
  export * from './deepseek.js';
19
24
  export * from './devin.js';
25
+ export * from './goose.js';
20
26
  export * from './grok-build.js';
21
27
  export * from './hermes.js';
22
28
  export * from './kilo.js';
@@ -4,6 +4,26 @@ type FetchedRuntimeModels = {
4
4
  models: RuntimeModelOption[];
5
5
  source: RuntimeModelSource;
6
6
  };
7
+ /**
8
+ * Makes sure `agentCapabilities` holds this def's `--help`-probed flags before its `buildArgs` runs.
9
+ *
10
+ * Why this exists: `agentCapabilities` used to be filled ONLY by {@link detectAgents}. A host whose
11
+ * run process never calls `detectAgents` (it lists agents with its own lighter probe, or not at
12
+ * all) left the map empty for every run, so every probe-gated flag stayed off for good — for
13
+ * `claude` that meant no `--include-partial-messages` (no streamed text) and no `--effort`, even on
14
+ * a CLI that supports both. The run path calls this with the exact launch path and env it is about
15
+ * to spawn, so the gate reflects the binary that actually runs.
16
+ *
17
+ * A no-op when the def declares no probe or the map already has an entry (a `detectAgents` result
18
+ * wins). Probes once per def id + launch path for the life of the process. A failed probe records
19
+ * nothing, which keeps the safe baseline (no optional flags), and is not retried on every run.
20
+ *
21
+ * @param def - The def about to be spawned.
22
+ * @param launchPath - The resolved executable the run will spawn.
23
+ * @param env - The env the run will spawn with.
24
+ * @complexity O(1) after the first call per def + path; the first call costs one `--help` spawn (5 s cap).
25
+ */
26
+ export declare function ensureAgentCapabilities(def: RuntimeAgentDef, launchPath: string, env: NodeJS.ProcessEnv): Promise<void>;
7
27
  /** Result of {@link probeAgentModels}: the models to surface and where they came from. */
8
28
  export type ProbedAgentModels = FetchedRuntimeModels;
9
29
  /**
package/dist/detection.js CHANGED
@@ -140,12 +140,7 @@ async function probeCapabilities(def, launchPath, env) {
140
140
  if (!def.helpArgs || !def.capabilityFlags)
141
141
  return null;
142
142
  try {
143
- const { stdout } = await execAgentFile(launchPath, def.helpArgs, { env, timeout: 5000, maxBuffer: 4 * 1024 * 1024 });
144
- const caps = {};
145
- for (const [flag, key] of Object.entries(def.capabilityFlags)) {
146
- caps[key] = String(stdout).includes(flag);
147
- }
148
- return caps;
143
+ return await readCapabilities(def.helpArgs, def.capabilityFlags, launchPath, env);
149
144
  }
150
145
  catch {
151
146
  // If --help fails, leave caps empty so buildArgs falls back to the
@@ -153,6 +148,51 @@ async function probeCapabilities(def, launchPath, env) {
153
148
  return {};
154
149
  }
155
150
  }
151
+ /** Runs the def's `--help` probe and maps each advertised flag to its capability key; throws on a failed probe. */
152
+ async function readCapabilities(helpArgs, capabilityFlags, launchPath, env) {
153
+ const { stdout } = await execAgentFile(launchPath, [...helpArgs], { env, timeout: 5000, maxBuffer: 4 * 1024 * 1024 });
154
+ const caps = {};
155
+ for (const [flag, key] of Object.entries(capabilityFlags)) {
156
+ caps[key] = String(stdout).includes(flag);
157
+ }
158
+ return caps;
159
+ }
160
+ /** One in-flight or settled `--help` probe per def id + launch path, so a run never re-spawns it. */
161
+ const capabilityProbes = new Map();
162
+ /**
163
+ * Makes sure `agentCapabilities` holds this def's `--help`-probed flags before its `buildArgs` runs.
164
+ *
165
+ * Why this exists: `agentCapabilities` used to be filled ONLY by {@link detectAgents}. A host whose
166
+ * run process never calls `detectAgents` (it lists agents with its own lighter probe, or not at
167
+ * all) left the map empty for every run, so every probe-gated flag stayed off for good — for
168
+ * `claude` that meant no `--include-partial-messages` (no streamed text) and no `--effort`, even on
169
+ * a CLI that supports both. The run path calls this with the exact launch path and env it is about
170
+ * to spawn, so the gate reflects the binary that actually runs.
171
+ *
172
+ * A no-op when the def declares no probe or the map already has an entry (a `detectAgents` result
173
+ * wins). Probes once per def id + launch path for the life of the process. A failed probe records
174
+ * nothing, which keeps the safe baseline (no optional flags), and is not retried on every run.
175
+ *
176
+ * @param def - The def about to be spawned.
177
+ * @param launchPath - The resolved executable the run will spawn.
178
+ * @param env - The env the run will spawn with.
179
+ * @complexity O(1) after the first call per def + path; the first call costs one `--help` spawn (5 s cap).
180
+ */
181
+ export function ensureAgentCapabilities(def, launchPath, env) {
182
+ const { helpArgs, capabilityFlags } = def;
183
+ if (!helpArgs || !capabilityFlags || agentCapabilities.has(def.id))
184
+ return Promise.resolve();
185
+ const key = `${def.id}\u0000${launchPath}`;
186
+ const existing = capabilityProbes.get(key);
187
+ if (existing)
188
+ return existing;
189
+ const probe = readCapabilities(helpArgs, capabilityFlags, launchPath, env).then((caps) => {
190
+ if (!agentCapabilities.has(def.id))
191
+ agentCapabilities.set(def.id, caps);
192
+ }, () => undefined);
193
+ capabilityProbes.set(key, probe);
194
+ return probe;
195
+ }
156
196
  /**
157
197
  * The effort-level override a live model catalog earns, if any.
158
198
  *
@@ -28,13 +28,19 @@ import { expandHomePath } from './paths.js';
28
28
  const AGENT_BIN_ENV_KEYS = new Map([
29
29
  ['amr', 'VELA_BIN'],
30
30
  ['aider', 'AIDER_BIN'],
31
+ ['auggie', 'AUGGIE_BIN'],
31
32
  ['claude', 'CLAUDE_BIN'],
33
+ ['cline', 'CLINE_BIN'],
32
34
  ['codebuddy', 'CODEBUDDY_BIN'],
33
35
  ['codex', 'CODEX_BIN'],
34
36
  ['copilot', 'COPILOT_BIN'],
37
+ ['crush', 'CRUSH_BIN'],
35
38
  ['cursor-agent', 'CURSOR_AGENT_BIN'],
36
39
  ['deepseek', 'DEEPSEEK_BIN'],
37
40
  ['devin', 'DEVIN_BIN'],
41
+ ['droid', 'DROID_BIN'],
42
+ ['gemini', 'GEMINI_BIN'],
43
+ ['goose', 'GOOSE_BIN'],
38
44
  ['hermes', 'HERMES_BIN'],
39
45
  ['kimi', 'KIMI_BIN'],
40
46
  ['kiro', 'KIRO_BIN'],
package/dist/metadata.js CHANGED
@@ -35,6 +35,10 @@ export const DEFAULT_AGENT_INSTALL_LINKS = {
35
35
  installUrl: 'https://cursor.com/docs/cli/overview',
36
36
  docsUrl: 'https://docs.cursor.com/en/cli/overview',
37
37
  },
38
+ gemini: {
39
+ installUrl: 'https://github.com/google-gemini/gemini-cli',
40
+ docsUrl: 'https://geminicli.com/docs/',
41
+ },
38
42
  qwen: {
39
43
  installUrl: 'https://github.com/QwenLM/qwen-code',
40
44
  docsUrl: 'https://qwenlm.github.io/qwen-code-docs/en/index',
@@ -74,6 +78,26 @@ export const DEFAULT_AGENT_INSTALL_LINKS = {
74
78
  installUrl: 'https://www.codebuddy.cn',
75
79
  docsUrl: 'https://www.codebuddy.cn/docs/workbuddy/Overview',
76
80
  },
81
+ cline: {
82
+ installUrl: 'https://cline.bot/cli',
83
+ docsUrl: 'https://docs.cline.bot/cline-cli/overview',
84
+ },
85
+ goose: {
86
+ installUrl: 'https://github.com/block/goose',
87
+ docsUrl: 'https://block.github.io/goose/',
88
+ },
89
+ auggie: {
90
+ installUrl: 'https://github.com/augmentcode/auggie',
91
+ docsUrl: 'https://docs.augmentcode.com/cli/overview',
92
+ },
93
+ crush: {
94
+ installUrl: 'https://github.com/charmbracelet/crush',
95
+ docsUrl: 'https://github.com/charmbracelet/crush',
96
+ },
97
+ droid: {
98
+ installUrl: 'https://factory.ai/product/cli',
99
+ docsUrl: 'https://docs.factory.ai/droid-exec/overview',
100
+ },
77
101
  };
78
102
  function sanitizeHttpsUrl(value) {
79
103
  if (!value)
@@ -7,8 +7,8 @@ export declare function getAgentDef(id: string): RuntimeAgentDef | null;
7
7
  * tools) into a session run by this
8
8
  * def, per its own `externalMcpInjection` declaration (`types.ts`'s own doc names the six wired
9
9
  * strategies and the defs that leave the field `undefined` because the CLI has no mechanism to
10
- * receive one — `aider`, `amp`, `copilot`, `cursor-agent`, `deepseek`, `grok-build`, `pi`,
11
- * `qoder`, and `qwen` today, each documenting why in its own def file).
10
+ * receive one — `aider`, `amp`, `copilot`, `crush`, `cursor-agent`, `deepseek`, `droid`,
11
+ * `gemini`, `grok-build`, `pi`, `qoder`, and `qwen` today, each documenting why in its own def file).
12
12
  *
13
13
  * This is the single seam a tool-availability UI (e.g. the chat runtime picker's "No tools" badge)
14
14
  * should read instead of hardcoding a runtime-id list: that list goes stale the moment a def gains
package/dist/registry.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @module registry
3
3
  *
4
- * The static `BASE_AGENT_DEFS` catalog (the 24 built-in CLI adapters), a
4
+ * The static `BASE_AGENT_DEFS` catalog (the built-in CLI adapters), a
5
5
  * dup-id guard, and `getAgentDef(id)` lookup.
6
6
  *
7
7
  * Ported from OD's `apps/daemon/src/runtimes/registry.ts`. Per the
@@ -17,7 +17,7 @@
17
17
  * can reintroduce a de-branded, sandbox-free local-profile loader as an
18
18
  * injected port if a consumer needs it. See `source-map.md`.
19
19
  */
20
- import { aiderAgentDef, ampAgentDef, amrAgentDef, antigravityAgentDef, claudeAgentDef, codebuddyAgentDef, codexAgentDef, copilotAgentDef, cursorAgentDef, deepseekAgentDef, devinAgentDef, grokBuildAgentDef, hermesAgentDef, kiloAgentDef, kimiAgentDef, kiroAgentDef, mimoAgentDef, opencodeAgentDef, piAgentDef, qoderAgentDef, qwenAgentDef, reasonixAgentDef, traeCliAgentDef, vibeAgentDef, } from './defs/index.js';
20
+ import { aiderAgentDef, ampAgentDef, amrAgentDef, antigravityAgentDef, auggieAgentDef, claudeAgentDef, clineAgentDef, codebuddyAgentDef, codexAgentDef, copilotAgentDef, crushAgentDef, cursorAgentDef, deepseekAgentDef, devinAgentDef, droidAgentDef, geminiAgentDef, gooseAgentDef, grokBuildAgentDef, hermesAgentDef, kiloAgentDef, kimiAgentDef, kiroAgentDef, mimoAgentDef, opencodeAgentDef, piAgentDef, qoderAgentDef, qwenAgentDef, reasonixAgentDef, traeCliAgentDef, vibeAgentDef, } from './defs/index.js';
21
21
  export const BASE_AGENT_DEFS = [
22
22
  amrAgentDef,
23
23
  claudeAgentDef,
@@ -30,6 +30,7 @@ export const BASE_AGENT_DEFS = [
30
30
  kimiAgentDef,
31
31
  cursorAgentDef,
32
32
  qwenAgentDef,
33
+ geminiAgentDef,
33
34
  qoderAgentDef,
34
35
  copilotAgentDef,
35
36
  ampAgentDef,
@@ -43,6 +44,11 @@ export const BASE_AGENT_DEFS = [
43
44
  reasonixAgentDef,
44
45
  codebuddyAgentDef,
45
46
  mimoAgentDef,
47
+ clineAgentDef,
48
+ gooseAgentDef,
49
+ auggieAgentDef,
50
+ crushAgentDef,
51
+ droidAgentDef,
46
52
  ];
47
53
  export const AGENT_DEFS = [...BASE_AGENT_DEFS];
48
54
  const ids = new Set();
@@ -60,8 +66,8 @@ export function getAgentDef(id) {
60
66
  * tools) into a session run by this
61
67
  * def, per its own `externalMcpInjection` declaration (`types.ts`'s own doc names the six wired
62
68
  * strategies and the defs that leave the field `undefined` because the CLI has no mechanism to
63
- * receive one — `aider`, `amp`, `copilot`, `cursor-agent`, `deepseek`, `grok-build`, `pi`,
64
- * `qoder`, and `qwen` today, each documenting why in its own def file).
69
+ * receive one — `aider`, `amp`, `copilot`, `crush`, `cursor-agent`, `deepseek`, `droid`,
70
+ * `gemini`, `grok-build`, `pi`, `qoder`, and `qwen` today, each documenting why in its own def file).
65
71
  *
66
72
  * This is the single seam a tool-availability UI (e.g. the chat runtime picker's "No tools" badge)
67
73
  * should read instead of hardcoding a runtime-id list: that list goes stale the moment a def gains
package/dist/types.d.ts CHANGED
@@ -95,6 +95,21 @@ export type RuntimeBuildOptions = {
95
95
  * `undefined`/empty means no restriction, same as today.
96
96
  */
97
97
  allowedTools?: readonly string[];
98
+ /**
99
+ * Which of the CLI's own settings layers to load — today `claude`'s `--setting-sources`
100
+ * (`user`, `project`, `local`). An EMPTY list loads none: no settings-file hooks, no plugins the
101
+ * operator enabled for themselves, no personal model/effort defaults. For a host that embeds the
102
+ * CLI as a product assistant, so the operator's personal setup (e.g. SessionStart hooks that
103
+ * inject their own instructions) never reaches the product's runs. Unlike staging a separate
104
+ * `CLAUDE_CONFIG_DIR`, this keeps the CLI's Keychain login. `undefined` = the CLI's default (all).
105
+ */
106
+ settingSources?: readonly string[];
107
+ /**
108
+ * Extra settings for this run — today `claude`'s `--settings <file-or-json>`, which the CLI applies
109
+ * on top of (and independently of) {@link settingSources}. Lets a host that loads no settings layers
110
+ * still hand the run the few it wants, e.g. one PreToolUse hook. `undefined`/empty = no flag.
111
+ */
112
+ settings?: string;
98
113
  };
99
114
  export type RuntimeContext = {
100
115
  cwd?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jini-ai/agent-runtime",
3
- "version": "0.3.8",
3
+ "version": "0.3.10",
4
4
  "description": "Coding-agent runtime adapters: runtime registry, detection, launch, stream parsers, and the ACP/pi-rpc subprocess transport.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -39,7 +39,7 @@
39
39
  },
40
40
  "dependencies": {
41
41
  "@jini-ai/platform": "0.3.0",
42
- "@jini-ai/protocol": "0.3.0"
42
+ "@jini-ai/protocol": "0.3.1"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@vitest/coverage-v8": "^2.1.9"