@livx.cc/agentx 0.99.40 → 0.99.41
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/README.md +1 -0
- package/dist/{Agent-D4-CLnxC.d.ts → Agent-DydgLoT-.d.ts} +5 -1
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +98 -15
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +17 -5
- package/dist/index.js +119 -54
- package/dist/index.js.map +1 -1
- package/dist/{mcp-aONOXRNk.d.ts → mcp-D5eN0JyQ.d.ts} +1 -1
- package/dist/mcp.client.d.ts +2 -2
- package/dist/models.d.ts +15 -1
- package/dist/models.js +7 -0
- package/dist/models.js.map +1 -1
- package/dist/{tools-BWzPQVy0.d.ts → tools-S-ArIR3o.d.ts} +14 -2
- package/dist/tools.shell.d.ts +6 -2
- package/dist/tools.shell.js +22 -0
- package/dist/tools.shell.js.map +1 -1
- package/package.json +1 -1
package/dist/mcp.client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { e as McpToolSearchOptions, f as McpToolSpec } from './mcp-
|
|
2
|
-
import { A as AgentTool } from './tools-
|
|
1
|
+
import { e as McpToolSearchOptions, f as McpToolSpec } from './mcp-D5eN0JyQ.js';
|
|
2
|
+
import { A as AgentTool } from './tools-S-ArIR3o.js';
|
|
3
3
|
import '@livx.cc/wcli/core';
|
|
4
4
|
|
|
5
5
|
/** A JSON-RPC 2.0 transport: request (awaits a result), notify (fire-and-forget), close. */
|
package/dist/models.d.ts
CHANGED
|
@@ -10,6 +10,20 @@
|
|
|
10
10
|
declare const MODEL_ALIASES: Record<string, string>;
|
|
11
11
|
/** Resolve an alias to a concrete id. A provider prefix ("anthropic/") is preserved; unknown ids pass through. */
|
|
12
12
|
declare function resolveModelAlias(input: string): string;
|
|
13
|
+
/** The provider of a model id ("cursor/x" -> "cursor"). Provider-specific `providerOptions` are only
|
|
14
|
+
* portable within the same provider — leaking them across is a hard 400.
|
|
15
|
+
*
|
|
16
|
+
* A BARE id is the common case, not the exception: `resolveModelAlias('haiku')` yields
|
|
17
|
+
* `claude-haiku-4-5-20251001` with no prefix (ai.libx.js resolves it fuzzily downstream), so reading
|
|
18
|
+
* only the literal "/" made every aliased child look like a provider switch and silently dropped the
|
|
19
|
+
* parent's options. The fix belongs HERE — the alias table must keep emitting the ids ai.libx.js
|
|
20
|
+
* expects, and the comparison is provider identity, not string identity.
|
|
21
|
+
*
|
|
22
|
+
* A bare id we can't attribute is UNKNOWN, not a shared provider: it gets a per-id marker so two
|
|
23
|
+
* different unknown ids never compare equal (returning "" for both made them look like one provider
|
|
24
|
+
* and would have leaked one host's options onto the other's model). An unknown id still compares
|
|
25
|
+
* equal to ITSELF, so a child staying on the parent's exact model keeps the parent's options. */
|
|
26
|
+
declare function modelProvider(model: string): string;
|
|
13
27
|
/** Short, human-friendly name for a resolved model id (e.g. "anthropic/claude-opus-4-8" → "opus"). */
|
|
14
28
|
declare function modelShortLabel(model?: string): string;
|
|
15
29
|
interface ResolveModelSwitchOpts {
|
|
@@ -39,4 +53,4 @@ interface ModelSwitch {
|
|
|
39
53
|
*/
|
|
40
54
|
declare function resolveModelSwitch(opts: ResolveModelSwitchOpts): ModelSwitch;
|
|
41
55
|
|
|
42
|
-
export { MODEL_ALIASES, type ModelSwitch, type ResolveModelSwitchOpts, modelShortLabel, resolveModelAlias, resolveModelSwitch };
|
|
56
|
+
export { MODEL_ALIASES, type ModelSwitch, type ResolveModelSwitchOpts, modelProvider, modelShortLabel, resolveModelAlias, resolveModelSwitch };
|
package/dist/models.js
CHANGED
|
@@ -15,6 +15,12 @@ function resolveModelAlias(input) {
|
|
|
15
15
|
const rest = slash === -1 ? input : input.slice(slash + 1);
|
|
16
16
|
return prefix + (MODEL_ALIASES[rest.toLowerCase()] ?? rest);
|
|
17
17
|
}
|
|
18
|
+
function modelProvider(model) {
|
|
19
|
+
const i = model.indexOf("/");
|
|
20
|
+
if (i !== -1) return model.slice(0, i);
|
|
21
|
+
if (/^claude-/i.test(model)) return "anthropic";
|
|
22
|
+
return `?${model}`;
|
|
23
|
+
}
|
|
18
24
|
function modelShortLabel(model) {
|
|
19
25
|
if (!model) return "default";
|
|
20
26
|
const id = model.split("/").pop();
|
|
@@ -38,6 +44,7 @@ function resolveModelSwitch(opts) {
|
|
|
38
44
|
}
|
|
39
45
|
export {
|
|
40
46
|
MODEL_ALIASES,
|
|
47
|
+
modelProvider,
|
|
41
48
|
modelShortLabel,
|
|
42
49
|
resolveModelAlias,
|
|
43
50
|
resolveModelSwitch
|
package/dist/models.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/models.ts"],"sourcesContent":["/**\n * Model aliasing + mid-conversation switch resolution — pure, dependency-free.\n *\n * Harness-level so every agentx consumer (unclaw, para-chat, …) resolves `[opus]`-style\n * aliases, gates by an allow-list, and announces a switch the same way. Policy (which models\n * a caller may use) and session state (the prior model) stay with the consumer; this module\n * is the shared mechanism.\n */\n\n/** Canonical short aliases → concrete Anthropic model ids. */\nexport const MODEL_ALIASES: Record<string, string> = {\n fable: 'claude-fable-5',\n 'fable-5': 'claude-fable-5',\n opus: 'claude-opus-4-8',\n 'opus-4-8': 'claude-opus-4-8',\n 'opus-4-7': 'claude-opus-4-7',\n 'opus-4-6': 'claude-opus-4-6',\n sonnet: 'claude-sonnet-4-6',\n haiku: 'claude-haiku-4-5-20251001',\n};\n\n/** Resolve an alias to a concrete id. A provider prefix (\"anthropic/\") is preserved; unknown ids pass through. */\nexport function resolveModelAlias(input: string): string {\n const slash = input.indexOf('/');\n const prefix = slash === -1 ? '' : input.slice(0, slash + 1);\n const rest = slash === -1 ? input : input.slice(slash + 1);\n return prefix + (MODEL_ALIASES[rest.toLowerCase()] ?? rest);\n}\n\n/** Short, human-friendly name for a resolved model id (e.g. \"anthropic/claude-opus-4-8\" → \"opus\"). */\nexport function modelShortLabel(model?: string): string {\n if (!model) return 'default';\n const id = model.split('/').pop()!;\n return id.replace(/^claude-/, '').replace(/-\\d.*$/, '');\n}\n\nexport interface ResolveModelSwitchOpts {\n /** Model requested for this turn (e.g. from an inline directive). Undefined = keep `current`. */\n requested?: string;\n /** The turn's default/current model when nothing is requested. */\n current: string;\n /** The session's prior resolved model — drives change detection + the notice. */\n prior?: string;\n /** If set, `requested` must match one of these (by short label) or it's denied and `current` is kept. */\n allowed?: string[];\n /** Announcement formatter. Default: `_[switching from x to y]_\\n\\n`. */\n format?: (from: string, to: string) => string;\n}\n\nexport interface ModelSwitch {\n /** The model to run this turn. */\n model: string;\n /** True when `requested` was rejected by `allowed` and `model` fell back to `current`. */\n denied: boolean;\n /** Inline notice to surface when the model actually changed vs `prior`, else undefined. */\n notice?: string;\n}\n\n/**\n * Resolve which model a turn runs, given an optional request, an allow-list, and the prior model.\n * Comparisons are by short label so provider-prefixed and dated ids unify\n * (\"anthropic/claude-opus-4-8\" ≡ \"claude-opus-4-8\" ≡ \"opus\").\n */\nexport function resolveModelSwitch(opts: ResolveModelSwitchOpts): ModelSwitch {\n const { requested, current, prior, allowed } = opts;\n if (!requested) return { model: current, denied: false };\n if (allowed && !allowed.some((a) => modelShortLabel(a) === modelShortLabel(requested))) {\n return { model: current, denied: true };\n }\n const fmt = opts.format ?? ((from: string, to: string) => `_[switching from ${from} to ${to}]_\\n\\n`);\n const changed = prior !== undefined && modelShortLabel(prior) !== modelShortLabel(requested);\n return {\n model: requested,\n denied: false,\n notice: changed ? fmt(modelShortLabel(prior!), modelShortLabel(requested)) : undefined,\n };\n}\n"],"mappings":";AAUO,IAAM,gBAAwC;AAAA,EACnD,OAAO;AAAA,EACP,WAAW;AAAA,EACX,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,OAAO;AACT;AAGO,SAAS,kBAAkB,OAAuB;AACvD,QAAM,QAAQ,MAAM,QAAQ,GAAG;AAC/B,QAAM,SAAS,UAAU,KAAK,KAAK,MAAM,MAAM,GAAG,QAAQ,CAAC;AAC3D,QAAM,OAAO,UAAU,KAAK,QAAQ,MAAM,MAAM,QAAQ,CAAC;AACzD,SAAO,UAAU,cAAc,KAAK,YAAY,CAAC,KAAK;AACxD;AAGO,SAAS,gBAAgB,OAAwB;AACtD,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,KAAK,MAAM,MAAM,GAAG,EAAE,IAAI;AAChC,SAAO,GAAG,QAAQ,YAAY,EAAE,EAAE,QAAQ,UAAU,EAAE;AACxD;AA6BO,SAAS,mBAAmB,MAA2C;AAC5E,QAAM,EAAE,WAAW,SAAS,OAAO,QAAQ,IAAI;AAC/C,MAAI,CAAC,UAAW,QAAO,EAAE,OAAO,SAAS,QAAQ,MAAM;AACvD,MAAI,WAAW,CAAC,QAAQ,KAAK,CAAC,MAAM,gBAAgB,CAAC,MAAM,gBAAgB,SAAS,CAAC,GAAG;AACtF,WAAO,EAAE,OAAO,SAAS,QAAQ,KAAK;AAAA,EACxC;AACA,QAAM,MAAM,KAAK,WAAW,CAAC,MAAc,OAAe,oBAAoB,IAAI,OAAO,EAAE;AAAA;AAAA;AAC3F,QAAM,UAAU,UAAU,UAAa,gBAAgB,KAAK,MAAM,gBAAgB,SAAS;AAC3F,SAAO;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ,UAAU,IAAI,gBAAgB,KAAM,GAAG,gBAAgB,SAAS,CAAC,IAAI;AAAA,EAC/E;AACF;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/models.ts"],"sourcesContent":["/**\n * Model aliasing + mid-conversation switch resolution — pure, dependency-free.\n *\n * Harness-level so every agentx consumer (unclaw, para-chat, …) resolves `[opus]`-style\n * aliases, gates by an allow-list, and announces a switch the same way. Policy (which models\n * a caller may use) and session state (the prior model) stay with the consumer; this module\n * is the shared mechanism.\n */\n\n/** Canonical short aliases → concrete Anthropic model ids. */\nexport const MODEL_ALIASES: Record<string, string> = {\n fable: 'claude-fable-5',\n 'fable-5': 'claude-fable-5',\n opus: 'claude-opus-4-8',\n 'opus-4-8': 'claude-opus-4-8',\n 'opus-4-7': 'claude-opus-4-7',\n 'opus-4-6': 'claude-opus-4-6',\n sonnet: 'claude-sonnet-4-6',\n haiku: 'claude-haiku-4-5-20251001',\n};\n\n/** Resolve an alias to a concrete id. A provider prefix (\"anthropic/\") is preserved; unknown ids pass through. */\nexport function resolveModelAlias(input: string): string {\n const slash = input.indexOf('/');\n const prefix = slash === -1 ? '' : input.slice(0, slash + 1);\n const rest = slash === -1 ? input : input.slice(slash + 1);\n return prefix + (MODEL_ALIASES[rest.toLowerCase()] ?? rest);\n}\n\n/** The provider of a model id (\"cursor/x\" -> \"cursor\"). Provider-specific `providerOptions` are only\n * portable within the same provider — leaking them across is a hard 400.\n *\n * A BARE id is the common case, not the exception: `resolveModelAlias('haiku')` yields\n * `claude-haiku-4-5-20251001` with no prefix (ai.libx.js resolves it fuzzily downstream), so reading\n * only the literal \"/\" made every aliased child look like a provider switch and silently dropped the\n * parent's options. The fix belongs HERE — the alias table must keep emitting the ids ai.libx.js\n * expects, and the comparison is provider identity, not string identity.\n *\n * A bare id we can't attribute is UNKNOWN, not a shared provider: it gets a per-id marker so two\n * different unknown ids never compare equal (returning \"\" for both made them look like one provider\n * and would have leaked one host's options onto the other's model). An unknown id still compares\n * equal to ITSELF, so a child staying on the parent's exact model keeps the parent's options. */\nexport function modelProvider(model: string): string {\n const i = model.indexOf('/');\n if (i !== -1) return model.slice(0, i);\n if (/^claude-/i.test(model)) return 'anthropic';\n return `?${model}`; // unknown: identity-scoped, never equal to a different unknown id\n}\n\n/** Short, human-friendly name for a resolved model id (e.g. \"anthropic/claude-opus-4-8\" → \"opus\"). */\nexport function modelShortLabel(model?: string): string {\n if (!model) return 'default';\n const id = model.split('/').pop()!;\n return id.replace(/^claude-/, '').replace(/-\\d.*$/, '');\n}\n\nexport interface ResolveModelSwitchOpts {\n /** Model requested for this turn (e.g. from an inline directive). Undefined = keep `current`. */\n requested?: string;\n /** The turn's default/current model when nothing is requested. */\n current: string;\n /** The session's prior resolved model — drives change detection + the notice. */\n prior?: string;\n /** If set, `requested` must match one of these (by short label) or it's denied and `current` is kept. */\n allowed?: string[];\n /** Announcement formatter. Default: `_[switching from x to y]_\\n\\n`. */\n format?: (from: string, to: string) => string;\n}\n\nexport interface ModelSwitch {\n /** The model to run this turn. */\n model: string;\n /** True when `requested` was rejected by `allowed` and `model` fell back to `current`. */\n denied: boolean;\n /** Inline notice to surface when the model actually changed vs `prior`, else undefined. */\n notice?: string;\n}\n\n/**\n * Resolve which model a turn runs, given an optional request, an allow-list, and the prior model.\n * Comparisons are by short label so provider-prefixed and dated ids unify\n * (\"anthropic/claude-opus-4-8\" ≡ \"claude-opus-4-8\" ≡ \"opus\").\n */\nexport function resolveModelSwitch(opts: ResolveModelSwitchOpts): ModelSwitch {\n const { requested, current, prior, allowed } = opts;\n if (!requested) return { model: current, denied: false };\n if (allowed && !allowed.some((a) => modelShortLabel(a) === modelShortLabel(requested))) {\n return { model: current, denied: true };\n }\n const fmt = opts.format ?? ((from: string, to: string) => `_[switching from ${from} to ${to}]_\\n\\n`);\n const changed = prior !== undefined && modelShortLabel(prior) !== modelShortLabel(requested);\n return {\n model: requested,\n denied: false,\n notice: changed ? fmt(modelShortLabel(prior!), modelShortLabel(requested)) : undefined,\n };\n}\n"],"mappings":";AAUO,IAAM,gBAAwC;AAAA,EACnD,OAAO;AAAA,EACP,WAAW;AAAA,EACX,MAAM;AAAA,EACN,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,YAAY;AAAA,EACZ,QAAQ;AAAA,EACR,OAAO;AACT;AAGO,SAAS,kBAAkB,OAAuB;AACvD,QAAM,QAAQ,MAAM,QAAQ,GAAG;AAC/B,QAAM,SAAS,UAAU,KAAK,KAAK,MAAM,MAAM,GAAG,QAAQ,CAAC;AAC3D,QAAM,OAAO,UAAU,KAAK,QAAQ,MAAM,MAAM,QAAQ,CAAC;AACzD,SAAO,UAAU,cAAc,KAAK,YAAY,CAAC,KAAK;AACxD;AAeO,SAAS,cAAc,OAAuB;AACnD,QAAM,IAAI,MAAM,QAAQ,GAAG;AAC3B,MAAI,MAAM,GAAI,QAAO,MAAM,MAAM,GAAG,CAAC;AACrC,MAAI,YAAY,KAAK,KAAK,EAAG,QAAO;AACpC,SAAO,IAAI,KAAK;AAClB;AAGO,SAAS,gBAAgB,OAAwB;AACtD,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,KAAK,MAAM,MAAM,GAAG,EAAE,IAAI;AAChC,SAAO,GAAG,QAAQ,YAAY,EAAE,EAAE,QAAQ,UAAU,EAAE;AACxD;AA6BO,SAAS,mBAAmB,MAA2C;AAC5E,QAAM,EAAE,WAAW,SAAS,OAAO,QAAQ,IAAI;AAC/C,MAAI,CAAC,UAAW,QAAO,EAAE,OAAO,SAAS,QAAQ,MAAM;AACvD,MAAI,WAAW,CAAC,QAAQ,KAAK,CAAC,MAAM,gBAAgB,CAAC,MAAM,gBAAgB,SAAS,CAAC,GAAG;AACtF,WAAO,EAAE,OAAO,SAAS,QAAQ,KAAK;AAAA,EACxC;AACA,QAAM,MAAM,KAAK,WAAW,CAAC,MAAc,OAAe,oBAAoB,IAAI,OAAO,EAAE;AAAA;AAAA;AAC3F,QAAM,UAAU,UAAU,UAAa,gBAAgB,KAAK,MAAM,gBAAgB,SAAS;AAC3F,SAAO;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ,UAAU,IAAI,gBAAgB,KAAM,GAAG,gBAAgB,SAAS,CAAC,IAAI;AAAA,EAC/E;AACF;","names":[]}
|
|
@@ -407,6 +407,15 @@ interface AgentTool {
|
|
|
407
407
|
data: string;
|
|
408
408
|
}[];
|
|
409
409
|
}>;
|
|
410
|
+
/** Optional: return a copy of this tool bound to a different real-disk working directory.
|
|
411
|
+
* Implemented by tools that escape the VFS (the real `Shell`), which are cwd-bound at construction
|
|
412
|
+
* and would otherwise keep pointing at the PARENT's tree when the tool instance is inherited by an
|
|
413
|
+
* isolated child agent. `subagent.ts` calls this for a worktree child; tools without it pass through.
|
|
414
|
+
* Return `undefined` for a capability that CANNOT follow the child (the background-job companions,
|
|
415
|
+
* bound to the parent's job registry) — the tool is then dropped from the child's toolbelt.
|
|
416
|
+
* An implementation must carry over any post-construction mutation the host made to the instance
|
|
417
|
+
* (a renamed `name`/`description`) — rebuilding from the factory's options alone loses it. */
|
|
418
|
+
withCwd?(cwd: string): AgentTool | undefined;
|
|
410
419
|
}
|
|
411
420
|
/** Build a tool context bound to a filesystem backend (Mem / Disk / …) and an optional host. */
|
|
412
421
|
declare function makeContext(fs: IFilesystem, host?: HostBridge): ToolContext;
|
|
@@ -427,7 +436,10 @@ declare function defaultTools(): AgentTool[];
|
|
|
427
436
|
* surface picks from this registry; embedders can build a custom tool set by name.
|
|
428
437
|
*/
|
|
429
438
|
declare function toolRegistry(): Record<string, AgentTool>;
|
|
430
|
-
/** Resolve a list of tool names against
|
|
431
|
-
|
|
439
|
+
/** Resolve a list of tool names against `available` (host-supplied tools, e.g. a parent agent's
|
|
440
|
+
* toolbelt or mounted MCP tools) first, then the built-in registry. Unknown names throw.
|
|
441
|
+
* Without `available` an allowlist could only ever name a built-in — so a def could not scope a
|
|
442
|
+
* child to a tool its parent injected (`Bash`, `ToolSearch`, …). */
|
|
443
|
+
declare function toolsByName(names: string[], available?: AgentTool[]): AgentTool[];
|
|
432
444
|
|
|
433
445
|
export { type AgentTool as A, makeJobTools as B, type ChatLike as C, messageHasImage as D, messageHasImageRef as E, messageHasInlineImage as F, mintImageRef as G, type HostBridge as H, IMAGE_ELIDE_STUB as I, parseImageRef as J, readTool as K, remintImageRefs as L, type Message as M, sendBytes as N, sendBytesPer as O, toWireTools as P, todoWriteTool as Q, type Role as R, SandboxJobRegistry as S, type TodoItem as T, type UserQuestion as U, toolImageRef as V, toolRegistry as W, toolsByName as X, type ChatOptions as a, type ChatResponse as b, type ContentPart as c, type HostEvent as d, IMAGE_REF_SCHEME as e, type ImageRef as f, type MessageContent as g, type StreamChunk as h, type Tool as i, type ToolCall as j, type ToolContext as k, bashTool as l, clearImageRefs as m, contentBytes as n, contentText as o, defaultTools as p, editTool as q, elideImages as r, elideInlineImages as s, elideStaleImages as t, exitSessionTool as u, expandImagesForSend as v, imagePart as w, imageRefPart as x, imageRefResult as y, makeContext as z };
|
package/dist/tools.shell.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as AgentTool } from './tools-
|
|
1
|
+
import { A as AgentTool } from './tools-S-ArIR3o.js';
|
|
2
2
|
import '@livx.cc/wcli/core';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -146,7 +146,11 @@ declare class ShellJobRegistry {
|
|
|
146
146
|
}
|
|
147
147
|
/** Build an opt-in real-shell tool bound to `options.cwd`. */
|
|
148
148
|
declare function makeRealShellTool(options: RealShellOptions): AgentTool;
|
|
149
|
-
/** Build the background-job companion tools (ShellOutput / ShellStatus / ShellKill) over a registry.
|
|
149
|
+
/** Build the background-job companion tools (ShellOutput / ShellStatus / ShellKill) over a registry.
|
|
150
|
+
* Each closes over THIS registry, i.e. this agent's jobs in this agent's cwd, so none of them can be
|
|
151
|
+
* rebound to an isolated child's root: `withCwd` returns `undefined` and they are dropped from the
|
|
152
|
+
* child's toolbelt. That keeps the capability coherent — the child's `Shell` cannot START a background
|
|
153
|
+
* job (its registry is dropped), so it must not be able to inspect or SIGTERM the parent's either. */
|
|
150
154
|
declare function makeShellJobTools(registry: ShellJobRegistry): AgentTool[];
|
|
151
155
|
|
|
152
156
|
export { type JobExitHandler, type JobExitNotice, type JobStatus, type RealShellOptions, type ShellJobConfig, ShellJobRegistry, type SpawnFn, type SpawnedProcess, formatJobExit, makeRealShellTool, makeShellJobTools };
|
package/dist/tools.shell.js
CHANGED
|
@@ -679,6 +679,24 @@ function makeRealShellTool(options) {
|
|
|
679
679
|
};
|
|
680
680
|
return {
|
|
681
681
|
name: "Shell",
|
|
682
|
+
// Rebind for an isolated child agent (git worktree): same policy/env/timeouts, new cwd. The
|
|
683
|
+
// `registry` is deliberately dropped — it is bound to the PARENT's cwd (and, in hosts like
|
|
684
|
+
// shraga-ee, to the parent's session), so a background job started from the child would run
|
|
685
|
+
// outside the child's isolation and report into the parent. Background stays a parent capability
|
|
686
|
+
// (`makeShellJobTools`' companions drop out of an isolated child entirely — see their `withCwd`).
|
|
687
|
+
// Only `run` is rebuilt: everything else is carried over from THIS instance, because a host may
|
|
688
|
+
// have mutated the tool AFTER construction (shraga-ee renames `Shell` -> `Bash` and its system
|
|
689
|
+
// prompt says `Bash` everywhere). Rebuilding from `options` alone silently dropped that rename,
|
|
690
|
+
// so a worktree child advertised `Shell` while being told to call `Bash` — an unknown-tool error
|
|
691
|
+
// on its first call, and a hard failure for an agentType def whose allowlist names `Bash`.
|
|
692
|
+
// `description` is the ONE thing taken from the rebound tool instead: it is derived from the
|
|
693
|
+
// options and states whether `background:true` works — the rebind drops the registry, so carrying
|
|
694
|
+
// the parent's text over would advertise a background capability the child does not have. (The
|
|
695
|
+
// spread also collapses the getter below to a plain value, which is why this override is explicit.)
|
|
696
|
+
withCwd(cwd) {
|
|
697
|
+
const rebound = makeRealShellTool({ ...options, cwd, registry: void 0 });
|
|
698
|
+
return { ...this, description: rebound.description, run: rebound.run, withCwd: rebound.withCwd };
|
|
699
|
+
},
|
|
682
700
|
get description() {
|
|
683
701
|
return `Run a shell command via /bin/sh in the working directory. Executes any installed binary \u2014 ls, cat, grep, git, bun, node, curl, scripts, etc. Returns combined stdout+stderr; non-zero exits are prefixed \`[exit N]\`. Runs non-interactively with no terminal (stdin is /dev/null): commands that prompt for input fail fast rather than hang \u2014 for privileged actions use a non-interactive flag (e.g. \`sudo -n\`), or ask the user to run the command themselves. Each command is killed after ${defaultTimeoutMs}ms (result \`[exit 124]\` with whatever output it produced) \u2014 pass \`timeoutMs\` (max ${maxTimeoutMs}) for a legitimately slower command, and always bound network commands yourself (e.g. \`curl -m 10\`). ` + backgroundDoc();
|
|
684
702
|
},
|
|
@@ -793,8 +811,10 @@ ${body}` : head;
|
|
|
793
811
|
var NO_JOB = (id) => `Error: no background job '${id}'. Use ShellStatus with no id to list jobs, or start one with Shell({background:true}).`;
|
|
794
812
|
function makeShellJobTools(registry) {
|
|
795
813
|
const idParam = { type: "object", properties: { id: { type: "string", description: "the job id from Shell({background:true})" } } };
|
|
814
|
+
const dropOnRebind = { withCwd: () => void 0 };
|
|
796
815
|
return [
|
|
797
816
|
{
|
|
817
|
+
...dropOnRebind,
|
|
798
818
|
name: "ShellOutput",
|
|
799
819
|
description: "Read the accumulated output (tail) of a background Shell job by id.",
|
|
800
820
|
parameters: { type: "object", required: ["id"], properties: { id: { type: "string" } } },
|
|
@@ -807,6 +827,7 @@ ${clean(out) || "(no output yet)"}`;
|
|
|
807
827
|
}
|
|
808
828
|
},
|
|
809
829
|
{
|
|
830
|
+
...dropOnRebind,
|
|
810
831
|
name: "ShellStatus",
|
|
811
832
|
description: "Status of a background Shell job (running/exited/killed + exit code). Omit `id` to list all jobs.",
|
|
812
833
|
parameters: idParam,
|
|
@@ -820,6 +841,7 @@ ${clean(out) || "(no output yet)"}`;
|
|
|
820
841
|
}
|
|
821
842
|
},
|
|
822
843
|
{
|
|
844
|
+
...dropOnRebind,
|
|
823
845
|
name: "ShellKill",
|
|
824
846
|
description: "Stop a running background Shell job by id (SIGTERM).",
|
|
825
847
|
parameters: { type: "object", required: ["id"], properties: { id: { type: "string" } } },
|