@livx.cc/agentx 0.99.63 → 0.99.65
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/{Agent-DbqXQy5q.d.ts → Agent-BpCqDWFG.d.ts} +13 -2
- package/dist/cli.d.ts +2 -2
- package/dist/cli.js +167 -134
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +8 -6
- package/dist/index.js +162 -128
- package/dist/index.js.map +1 -1
- package/dist/{mcp-CSLRyvEp.d.ts → mcp-DGd2If0Z.d.ts} +1 -1
- package/dist/mcp.client.d.ts +2 -2
- package/dist/{tools-HsbxgqjF.d.ts → tools-DV4SkkQs.d.ts} +6 -0
- package/dist/tools.shell.d.ts +1 -1
- package/dist/tools.shell.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IFilesystem } from '@livx.cc/wcli/core';
|
|
2
|
-
import { M as Message, o as MessageContent, H as HostBridge, A as AgentTool, C as ChatLike, k as JobRegistry, U as UserQuestion } from './tools-
|
|
2
|
+
import { M as Message, o as MessageContent, H as HostBridge, A as AgentTool, C as ChatLike, k as JobRegistry, U as UserQuestion } from './tools-DV4SkkQs.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* `--model auto`: per-turn model routing. A classifier (Jev by default — injected, so a regex or
|
|
@@ -209,6 +209,8 @@ interface PermissionRule {
|
|
|
209
209
|
/** glob on the call's `path` arg to match (omit = any/none). */
|
|
210
210
|
pathGlob?: string;
|
|
211
211
|
decision: Decision;
|
|
212
|
+
/** Set by the caller for per-run rules (CLI `--disallowedTools`/`--allowedTools`), vs rules loaded from config files. */
|
|
213
|
+
explicit?: boolean;
|
|
212
214
|
}
|
|
213
215
|
declare class PermissionOptions {
|
|
214
216
|
rules: PermissionRule[];
|
|
@@ -229,9 +231,18 @@ declare class PermissionPolicy {
|
|
|
229
231
|
constructor(options?: Partial<PermissionOptions>);
|
|
230
232
|
/** Resolve the decision for a tool call (first matching rule, else default). */
|
|
231
233
|
decide(call: ToolUse): Decision;
|
|
234
|
+
/** The policy's `deny` rules as rule strings (`Tool` / `Tool(glob)`) — for delegated runtimes that run
|
|
235
|
+
* their OWN tools (claude-code/cursor) and never pass through {@link hooks}. */
|
|
236
|
+
denyRules(explicitOnly?: boolean): string[];
|
|
232
237
|
/** A preToolUse hook enforcing this policy (deny/ask → block; allow → proceed). */
|
|
233
238
|
hooks(): Hooks;
|
|
234
239
|
}
|
|
240
|
+
/**
|
|
241
|
+
* A policy's deny rules as Claude Code `disallowedTools` entries (deduped; agentx shell names mapped to
|
|
242
|
+
* `Bash`). The Claude Agent SDK removes these from the model's context and refuses them even under
|
|
243
|
+
* `bypassPermissions`. A bare `*` (deny everything) has no CC spelling, so it throws — fail closed.
|
|
244
|
+
*/
|
|
245
|
+
declare function claudeCodeDisallowedTools(policy?: PermissionPolicy): string[];
|
|
235
246
|
/** Tools the agent must not run before the plan is approved (sensible default). */
|
|
236
247
|
declare const DEFAULT_MUTATING: string[];
|
|
237
248
|
/**
|
|
@@ -732,4 +743,4 @@ declare class Agent {
|
|
|
732
743
|
* stub made `/compact` chase a target it could never reach and drop-oldest the conversation away. */
|
|
733
744
|
declare function estimateTokens(m: Message[], keepRecentImages?: number): number;
|
|
734
745
|
|
|
735
|
-
export { Agent as A, type ChatFragment as C, DEFAULT_MUTATING as D, type Hooks as H, ModelRouter as M, PermissionOptions as P, type ReasoningEffort as R, type Tier as T, AgentOptions as a, type Classification as b, type Classifier as c, type CompactResult as d, type Decision as e, ModelRouterOptions as f, PermissionPolicy as g, type PermissionRule as h, type PreToolUseDecision as i, RecordingHooks as j, RecordingLifecycle as k, type RouteDecision as l, type RouterState as m, type RunResult as n, type ToolUse as o, type ToolUseMeta as p,
|
|
746
|
+
export { Agent as A, type ChatFragment as C, DEFAULT_MUTATING as D, type Hooks as H, ModelRouter as M, PermissionOptions as P, type ReasoningEffort as R, type Tier as T, AgentOptions as a, type Classification as b, type Classifier as c, type CompactResult as d, type Decision as e, ModelRouterOptions as f, PermissionPolicy as g, type PermissionRule as h, type PreToolUseDecision as i, RecordingHooks as j, RecordingLifecycle as k, type RouteDecision as l, type RouterState as m, type RunResult as n, type ToolUse as o, type ToolUseMeta as p, claudeCodeDisallowedTools as q, composeHooks as r, estimateTokens as s, jevAvailable as t, jevClassifier as u, pickTier as v, planMode as w, reasoningToChatFragment as x };
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { m as RouterState, H as Hooks, n as RunResult, R as ReasoningEffort, A as Agent } from './Agent-
|
|
2
|
+
import { m as RouterState, H as Hooks, n as RunResult, R as ReasoningEffort, A as Agent } from './Agent-BpCqDWFG.js';
|
|
3
3
|
import { IFilesystem } from '@livx.cc/wcli/core';
|
|
4
|
-
import { M as Message, U as UserQuestion, H as HostBridge, c as ContentPart, o as MessageContent } from './tools-
|
|
4
|
+
import { M as Message, U as UserQuestion, H as HostBridge, c as ContentPart, o as MessageContent } from './tools-DV4SkkQs.js';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* On-disk session store for the CLI: each conversation is one JSON file at
|
package/dist/cli.js
CHANGED
|
@@ -3581,6 +3581,149 @@ function modelProvider(model) {
|
|
|
3581
3581
|
return `?${model}`;
|
|
3582
3582
|
}
|
|
3583
3583
|
|
|
3584
|
+
// src/permissions.ts
|
|
3585
|
+
init_tools_structured();
|
|
3586
|
+
function commandMatches(glob, cmd) {
|
|
3587
|
+
const pattern = glob.split("*").map((s) => s.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*");
|
|
3588
|
+
return new RegExp("^" + pattern + "$").test(cmd);
|
|
3589
|
+
}
|
|
3590
|
+
function toolMatches(rule, name) {
|
|
3591
|
+
return rule.includes("*") ? commandMatches(rule, name) : rule === name;
|
|
3592
|
+
}
|
|
3593
|
+
var PermissionOptions = class {
|
|
3594
|
+
rules = [];
|
|
3595
|
+
/** decision when no rule matches. */
|
|
3596
|
+
default = "allow";
|
|
3597
|
+
/** host channel for `ask` (confirm). If absent, `ask` is treated as `deny` (fail-closed). */
|
|
3598
|
+
host;
|
|
3599
|
+
};
|
|
3600
|
+
var PermissionPolicy = class {
|
|
3601
|
+
options;
|
|
3602
|
+
constructor(options) {
|
|
3603
|
+
this.options = { ...new PermissionOptions(), ...options };
|
|
3604
|
+
}
|
|
3605
|
+
/** Resolve the decision for a tool call (first matching rule, else default). */
|
|
3606
|
+
decide(call) {
|
|
3607
|
+
const names = call.name === "McpCall" && typeof call.args?.name === "string" ? [call.name, call.args.name] : [call.name];
|
|
3608
|
+
for (const r of this.options.rules) {
|
|
3609
|
+
if (r.tool && !names.some((n) => toolMatches(r.tool, n))) continue;
|
|
3610
|
+
if (r.pathGlob) {
|
|
3611
|
+
const path = typeof call.args?.path === "string" ? call.args.path : null;
|
|
3612
|
+
const cmd = typeof call.args?.command === "string" ? call.args.command : null;
|
|
3613
|
+
if (path != null) {
|
|
3614
|
+
if (!globToRegExp(r.pathGlob).test(path.startsWith("/") ? path : `/${path}`)) continue;
|
|
3615
|
+
} else if (cmd != null) {
|
|
3616
|
+
if (!commandMatches(r.pathGlob, cmd)) continue;
|
|
3617
|
+
} else continue;
|
|
3618
|
+
}
|
|
3619
|
+
return r.decision;
|
|
3620
|
+
}
|
|
3621
|
+
return this.options.default;
|
|
3622
|
+
}
|
|
3623
|
+
/** The policy's `deny` rules as rule strings (`Tool` / `Tool(glob)`) — for delegated runtimes that run
|
|
3624
|
+
* their OWN tools (claude-code/cursor) and never pass through {@link hooks}. */
|
|
3625
|
+
denyRules(explicitOnly = false) {
|
|
3626
|
+
return this.options.rules.filter((r) => r.decision === "deny" && (!explicitOnly || r.explicit)).map((r) => `${r.tool ?? "*"}${r.pathGlob ? `(${r.pathGlob})` : ""}`);
|
|
3627
|
+
}
|
|
3628
|
+
/** A preToolUse hook enforcing this policy (deny/ask → block; allow → proceed). */
|
|
3629
|
+
hooks() {
|
|
3630
|
+
return {
|
|
3631
|
+
preToolUse: async (call) => {
|
|
3632
|
+
const d = this.decide(call);
|
|
3633
|
+
if (d === "allow") return;
|
|
3634
|
+
if (d === "deny") return { block: true, reason: `denied by permission policy (${call.name})` };
|
|
3635
|
+
if (this.options.ask) {
|
|
3636
|
+
const r = await this.options.ask(call);
|
|
3637
|
+
const decision = r?.decision ?? "deny";
|
|
3638
|
+
const rememberTool2 = call.name === "McpCall" && typeof call.args?.name === "string" ? call.args.name : call.name;
|
|
3639
|
+
if (r?.remember) this.options.rules.unshift({ tool: rememberTool2, decision });
|
|
3640
|
+
return decision === "allow" ? void 0 : { block: true, reason: `not approved (${call.name})` };
|
|
3641
|
+
}
|
|
3642
|
+
const ok = await this.options.host?.confirm?.(`Allow ${call.name}${call.args?.path ? " on " + call.args.path : ""}?`);
|
|
3643
|
+
return ok ? void 0 : { block: true, reason: `not approved (${call.name})` };
|
|
3644
|
+
}
|
|
3645
|
+
};
|
|
3646
|
+
}
|
|
3647
|
+
};
|
|
3648
|
+
var CC_TOOL_ALIAS = { Shell: "Bash", bash: "Bash" };
|
|
3649
|
+
function claudeCodeDisallowedTools(policy) {
|
|
3650
|
+
const out = /* @__PURE__ */ new Set();
|
|
3651
|
+
for (const rule of policy?.denyRules() ?? []) {
|
|
3652
|
+
const m = /^([^(]+)(\(.*\))?$/.exec(rule);
|
|
3653
|
+
if (m[1] === "*") throw new Error("permission policy denies every tool (`*`) \u2014 claude-code cannot express that; refusing to run.");
|
|
3654
|
+
out.add((CC_TOOL_ALIAS[m[1]] ?? m[1]) + (m[2] ?? ""));
|
|
3655
|
+
}
|
|
3656
|
+
return [...out];
|
|
3657
|
+
}
|
|
3658
|
+
var DEFAULT_MUTATING = ["Write", "Edit", "MultiEdit", "deleteFile", "bash"];
|
|
3659
|
+
function planMode(opts) {
|
|
3660
|
+
const mutating = new Set(opts?.mutating ?? DEFAULT_MUTATING);
|
|
3661
|
+
let approved = false;
|
|
3662
|
+
const tool = {
|
|
3663
|
+
name: "ExitPlanMode",
|
|
3664
|
+
description: "Call when your plan is ready and you want to start making changes. Provide the `plan`. Until this is approved, edits/writes are blocked.",
|
|
3665
|
+
parameters: { type: "object", required: ["plan"], properties: { plan: { type: "string", description: "the concrete steps you will take" } } },
|
|
3666
|
+
async run({ plan }, _ctx) {
|
|
3667
|
+
if (opts?.host?.confirm) {
|
|
3668
|
+
const confirm = opts.host.confirm(`Approve this plan?
|
|
3669
|
+
|
|
3670
|
+
${String(plan ?? "")}`);
|
|
3671
|
+
const ok = await (_ctx?.parkHuman ? _ctx.parkHuman(confirm) : confirm);
|
|
3672
|
+
if (!ok) return "Plan not approved. Revise it and call ExitPlanMode again.";
|
|
3673
|
+
}
|
|
3674
|
+
approved = true;
|
|
3675
|
+
return "Plan approved \u2014 you may now make changes.";
|
|
3676
|
+
}
|
|
3677
|
+
};
|
|
3678
|
+
const hooks = {
|
|
3679
|
+
preToolUse: (call) => !approved && mutating.has(call.name) ? { block: true, reason: "plan mode: present a plan and call ExitPlanMode (approved) before editing." } : void 0
|
|
3680
|
+
};
|
|
3681
|
+
return { hooks, tool };
|
|
3682
|
+
}
|
|
3683
|
+
function composeHooks(...list) {
|
|
3684
|
+
const hooks = list.filter(Boolean);
|
|
3685
|
+
return {
|
|
3686
|
+
async preToolUse(call, meta) {
|
|
3687
|
+
for (const h of hooks) {
|
|
3688
|
+
const d = await h.preToolUse?.(call, meta);
|
|
3689
|
+
if (d?.block) return d;
|
|
3690
|
+
}
|
|
3691
|
+
},
|
|
3692
|
+
async postToolUse(call, result, meta) {
|
|
3693
|
+
for (const h of hooks) await h.postToolUse?.(call, result, meta);
|
|
3694
|
+
},
|
|
3695
|
+
onToolOutput(call, chunk, meta) {
|
|
3696
|
+
for (const h of hooks) h.onToolOutput?.(call, chunk, meta);
|
|
3697
|
+
},
|
|
3698
|
+
onStop(text) {
|
|
3699
|
+
for (const h of hooks) h.onStop?.(text);
|
|
3700
|
+
},
|
|
3701
|
+
// lifecycle: concatenate session-start context; chain prompt-submit transforms; fan out pre-compact.
|
|
3702
|
+
async onSessionStart() {
|
|
3703
|
+
let ctx = "";
|
|
3704
|
+
for (const h of hooks) {
|
|
3705
|
+
const r = await h.onSessionStart?.();
|
|
3706
|
+
if (r) ctx += (ctx ? "\n\n" : "") + r;
|
|
3707
|
+
}
|
|
3708
|
+
return ctx || void 0;
|
|
3709
|
+
},
|
|
3710
|
+
async onUserPromptSubmit(text) {
|
|
3711
|
+
let t = text;
|
|
3712
|
+
for (const h of hooks) {
|
|
3713
|
+
const r = await h.onUserPromptSubmit?.(t);
|
|
3714
|
+
if (typeof r === "string") t = r;
|
|
3715
|
+
}
|
|
3716
|
+
return t;
|
|
3717
|
+
},
|
|
3718
|
+
async onPreCompact(messages) {
|
|
3719
|
+
for (const h of hooks) await h.onPreCompact?.(messages);
|
|
3720
|
+
},
|
|
3721
|
+
async onSubagentStop(summary, info) {
|
|
3722
|
+
for (const h of hooks) await h.onSubagentStop?.(summary, info);
|
|
3723
|
+
}
|
|
3724
|
+
};
|
|
3725
|
+
}
|
|
3726
|
+
|
|
3584
3727
|
// src/subagent.ts
|
|
3585
3728
|
init_OverlayFilesystem();
|
|
3586
3729
|
init_worktree();
|
|
@@ -3738,6 +3881,8 @@ function childOptionsFor(opts, fs, depth, maxDepth, agentType, model, root) {
|
|
|
3738
3881
|
}
|
|
3739
3882
|
const po = opts.providerOptionsFor?.(childModel);
|
|
3740
3883
|
if (po) childOpts.providerOptions = po;
|
|
3884
|
+
const deny = opts.permissions?.options.rules.filter((r) => r.decision === "deny") ?? [];
|
|
3885
|
+
if (deny.length) childOpts.permissions = new PermissionPolicy({ rules: deny, default: "allow" });
|
|
3741
3886
|
if (opts.hooks?.preToolUse) childOpts.hooks = { preToolUse: opts.hooks.preToolUse.bind(opts.hooks) };
|
|
3742
3887
|
return childOpts;
|
|
3743
3888
|
}
|
|
@@ -3957,133 +4102,6 @@ async function loadAgents(fs, dir) {
|
|
|
3957
4102
|
|
|
3958
4103
|
// src/Agent.ts
|
|
3959
4104
|
init_OverlayFilesystem();
|
|
3960
|
-
|
|
3961
|
-
// src/permissions.ts
|
|
3962
|
-
init_tools_structured();
|
|
3963
|
-
function commandMatches(glob, cmd) {
|
|
3964
|
-
const pattern = glob.split("*").map((s) => s.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*");
|
|
3965
|
-
return new RegExp("^" + pattern + "$").test(cmd);
|
|
3966
|
-
}
|
|
3967
|
-
var PermissionOptions = class {
|
|
3968
|
-
rules = [];
|
|
3969
|
-
/** decision when no rule matches. */
|
|
3970
|
-
default = "allow";
|
|
3971
|
-
/** host channel for `ask` (confirm). If absent, `ask` is treated as `deny` (fail-closed). */
|
|
3972
|
-
host;
|
|
3973
|
-
};
|
|
3974
|
-
var PermissionPolicy = class {
|
|
3975
|
-
options;
|
|
3976
|
-
constructor(options) {
|
|
3977
|
-
this.options = { ...new PermissionOptions(), ...options };
|
|
3978
|
-
}
|
|
3979
|
-
/** Resolve the decision for a tool call (first matching rule, else default). */
|
|
3980
|
-
decide(call) {
|
|
3981
|
-
const names = call.name === "McpCall" && typeof call.args?.name === "string" ? [call.name, call.args.name] : [call.name];
|
|
3982
|
-
for (const r of this.options.rules) {
|
|
3983
|
-
if (r.tool && !names.includes(r.tool)) continue;
|
|
3984
|
-
if (r.pathGlob) {
|
|
3985
|
-
const path = typeof call.args?.path === "string" ? call.args.path : null;
|
|
3986
|
-
const cmd = typeof call.args?.command === "string" ? call.args.command : null;
|
|
3987
|
-
if (path != null) {
|
|
3988
|
-
if (!globToRegExp(r.pathGlob).test(path.startsWith("/") ? path : `/${path}`)) continue;
|
|
3989
|
-
} else if (cmd != null) {
|
|
3990
|
-
if (!commandMatches(r.pathGlob, cmd)) continue;
|
|
3991
|
-
} else continue;
|
|
3992
|
-
}
|
|
3993
|
-
return r.decision;
|
|
3994
|
-
}
|
|
3995
|
-
return this.options.default;
|
|
3996
|
-
}
|
|
3997
|
-
/** A preToolUse hook enforcing this policy (deny/ask → block; allow → proceed). */
|
|
3998
|
-
hooks() {
|
|
3999
|
-
return {
|
|
4000
|
-
preToolUse: async (call) => {
|
|
4001
|
-
const d = this.decide(call);
|
|
4002
|
-
if (d === "allow") return;
|
|
4003
|
-
if (d === "deny") return { block: true, reason: `denied by permission policy (${call.name})` };
|
|
4004
|
-
if (this.options.ask) {
|
|
4005
|
-
const r = await this.options.ask(call);
|
|
4006
|
-
const decision = r?.decision ?? "deny";
|
|
4007
|
-
const rememberTool2 = call.name === "McpCall" && typeof call.args?.name === "string" ? call.args.name : call.name;
|
|
4008
|
-
if (r?.remember) this.options.rules.unshift({ tool: rememberTool2, decision });
|
|
4009
|
-
return decision === "allow" ? void 0 : { block: true, reason: `not approved (${call.name})` };
|
|
4010
|
-
}
|
|
4011
|
-
const ok = await this.options.host?.confirm?.(`Allow ${call.name}${call.args?.path ? " on " + call.args.path : ""}?`);
|
|
4012
|
-
return ok ? void 0 : { block: true, reason: `not approved (${call.name})` };
|
|
4013
|
-
}
|
|
4014
|
-
};
|
|
4015
|
-
}
|
|
4016
|
-
};
|
|
4017
|
-
var DEFAULT_MUTATING = ["Write", "Edit", "MultiEdit", "deleteFile", "bash"];
|
|
4018
|
-
function planMode(opts) {
|
|
4019
|
-
const mutating = new Set(opts?.mutating ?? DEFAULT_MUTATING);
|
|
4020
|
-
let approved = false;
|
|
4021
|
-
const tool = {
|
|
4022
|
-
name: "ExitPlanMode",
|
|
4023
|
-
description: "Call when your plan is ready and you want to start making changes. Provide the `plan`. Until this is approved, edits/writes are blocked.",
|
|
4024
|
-
parameters: { type: "object", required: ["plan"], properties: { plan: { type: "string", description: "the concrete steps you will take" } } },
|
|
4025
|
-
async run({ plan }, _ctx) {
|
|
4026
|
-
if (opts?.host?.confirm) {
|
|
4027
|
-
const confirm = opts.host.confirm(`Approve this plan?
|
|
4028
|
-
|
|
4029
|
-
${String(plan ?? "")}`);
|
|
4030
|
-
const ok = await (_ctx?.parkHuman ? _ctx.parkHuman(confirm) : confirm);
|
|
4031
|
-
if (!ok) return "Plan not approved. Revise it and call ExitPlanMode again.";
|
|
4032
|
-
}
|
|
4033
|
-
approved = true;
|
|
4034
|
-
return "Plan approved \u2014 you may now make changes.";
|
|
4035
|
-
}
|
|
4036
|
-
};
|
|
4037
|
-
const hooks = {
|
|
4038
|
-
preToolUse: (call) => !approved && mutating.has(call.name) ? { block: true, reason: "plan mode: present a plan and call ExitPlanMode (approved) before editing." } : void 0
|
|
4039
|
-
};
|
|
4040
|
-
return { hooks, tool };
|
|
4041
|
-
}
|
|
4042
|
-
function composeHooks(...list) {
|
|
4043
|
-
const hooks = list.filter(Boolean);
|
|
4044
|
-
return {
|
|
4045
|
-
async preToolUse(call, meta) {
|
|
4046
|
-
for (const h of hooks) {
|
|
4047
|
-
const d = await h.preToolUse?.(call, meta);
|
|
4048
|
-
if (d?.block) return d;
|
|
4049
|
-
}
|
|
4050
|
-
},
|
|
4051
|
-
async postToolUse(call, result, meta) {
|
|
4052
|
-
for (const h of hooks) await h.postToolUse?.(call, result, meta);
|
|
4053
|
-
},
|
|
4054
|
-
onToolOutput(call, chunk, meta) {
|
|
4055
|
-
for (const h of hooks) h.onToolOutput?.(call, chunk, meta);
|
|
4056
|
-
},
|
|
4057
|
-
onStop(text) {
|
|
4058
|
-
for (const h of hooks) h.onStop?.(text);
|
|
4059
|
-
},
|
|
4060
|
-
// lifecycle: concatenate session-start context; chain prompt-submit transforms; fan out pre-compact.
|
|
4061
|
-
async onSessionStart() {
|
|
4062
|
-
let ctx = "";
|
|
4063
|
-
for (const h of hooks) {
|
|
4064
|
-
const r = await h.onSessionStart?.();
|
|
4065
|
-
if (r) ctx += (ctx ? "\n\n" : "") + r;
|
|
4066
|
-
}
|
|
4067
|
-
return ctx || void 0;
|
|
4068
|
-
},
|
|
4069
|
-
async onUserPromptSubmit(text) {
|
|
4070
|
-
let t = text;
|
|
4071
|
-
for (const h of hooks) {
|
|
4072
|
-
const r = await h.onUserPromptSubmit?.(t);
|
|
4073
|
-
if (typeof r === "string") t = r;
|
|
4074
|
-
}
|
|
4075
|
-
return t;
|
|
4076
|
-
},
|
|
4077
|
-
async onPreCompact(messages) {
|
|
4078
|
-
for (const h of hooks) await h.onPreCompact?.(messages);
|
|
4079
|
-
},
|
|
4080
|
-
async onSubagentStop(summary, info) {
|
|
4081
|
-
for (const h of hooks) await h.onSubagentStop?.(summary, info);
|
|
4082
|
-
}
|
|
4083
|
-
};
|
|
4084
|
-
}
|
|
4085
|
-
|
|
4086
|
-
// src/Agent.ts
|
|
4087
4105
|
init_logging();
|
|
4088
4106
|
|
|
4089
4107
|
// src/lint.ts
|
|
@@ -4603,6 +4621,8 @@ var Agent = class _Agent {
|
|
|
4603
4621
|
agents,
|
|
4604
4622
|
hooks: o.hooks,
|
|
4605
4623
|
traceDir: o.traceDir,
|
|
4624
|
+
permissions: o.permissions,
|
|
4625
|
+
// a child obeys the parent's allow/deny rules (else Task is a one-call bypass)
|
|
4606
4626
|
tools: [...o.tools, ...this.injectedTools],
|
|
4607
4627
|
systemPrompt: o.systemPrompt,
|
|
4608
4628
|
providerOptionsFor: o.providerOptionsFor ?? ((m) => modelProvider(m) === modelProvider(o.model) ? o.providerOptions : void 0)
|
|
@@ -4775,6 +4795,14 @@ var Agent = class _Agent {
|
|
|
4775
4795
|
}
|
|
4776
4796
|
} : void 0;
|
|
4777
4797
|
const claudeSteerPo = o.model.startsWith("claude-code/") ? { steer: () => this.drainPendingSteers() } : void 0;
|
|
4798
|
+
const denyTools = o.model.startsWith("claude-code/") ? claudeCodeDisallowedTools(o.permissions) : [];
|
|
4799
|
+
if (denyTools.length) {
|
|
4800
|
+
const prior = o.providerOptions?.disallowedTools ?? [];
|
|
4801
|
+
claudeSteerPo.disallowedTools = [.../* @__PURE__ */ new Set([...prior, ...denyTools])];
|
|
4802
|
+
}
|
|
4803
|
+
const cursorDeny = o.model.startsWith("cursor/") ? o.permissions?.denyRules(true) ?? [] : [];
|
|
4804
|
+
if (cursorDeny.length)
|
|
4805
|
+
throw new Error(`cursor/* cannot enforce --disallowedTools (${cursorDeny.join(", ")}): its native tools bypass them. Refusing to run \u2014 use a claude-code/* or API model, or drop --disallowedTools.`);
|
|
4778
4806
|
const reasonOpts = {
|
|
4779
4807
|
...frag,
|
|
4780
4808
|
...o.promptCache ? { promptCache: true } : {},
|
|
@@ -4891,6 +4919,9 @@ var Agent = class _Agent {
|
|
|
4891
4919
|
this.transcript.push({
|
|
4892
4920
|
role: "assistant",
|
|
4893
4921
|
content: res.content ?? "",
|
|
4922
|
+
// Record the model the adapter actually ran: aliases (`claude-code/opus`) resolve to a concrete
|
|
4923
|
+
// id (e.g. `claude-opus-5-5`); fall back to the requested model if the adapter didn't report one.
|
|
4924
|
+
model: res.model ?? o.model,
|
|
4894
4925
|
...toolCalls.length ? { tool_calls: toolCalls } : {},
|
|
4895
4926
|
...res.reasoningContent && passesBackReasoning(o.model) ? { reasoning_content: res.reasoningContent } : {}
|
|
4896
4927
|
});
|
|
@@ -5053,7 +5084,9 @@ var Agent = class _Agent {
|
|
|
5053
5084
|
let sawTool = false;
|
|
5054
5085
|
let trailing = "";
|
|
5055
5086
|
let reasoning = "";
|
|
5087
|
+
let resolvedModel;
|
|
5056
5088
|
for await (const chunk of stream) {
|
|
5089
|
+
if (chunk.model) resolvedModel = chunk.model;
|
|
5057
5090
|
poke?.();
|
|
5058
5091
|
if (this.options.signal?.aborted) break;
|
|
5059
5092
|
if (chunk.reasoningContent) {
|
|
@@ -5102,7 +5135,7 @@ var Agent = class _Agent {
|
|
|
5102
5135
|
}
|
|
5103
5136
|
const delegatedTools = delegatedOrder.map((k) => delegated.get(k));
|
|
5104
5137
|
const endedWithoutClosing = sawTool && (!trailing.trim() || endsOnAnnouncedAction(trailing));
|
|
5105
|
-
return { content, ...reasoning ? { reasoningContent: reasoning } : {}, ...finishReason ? { finishReason } : {}, ...toolCalls ? { toolCalls } : {}, ...usage ? { usage } : {}, ...delegatedTools.length ? { delegatedTools } : {}, ...endedWithoutClosing ? { endedWithoutClosing: true } : {} };
|
|
5138
|
+
return { content, ...resolvedModel ? { model: resolvedModel } : {}, ...reasoning ? { reasoningContent: reasoning } : {}, ...finishReason ? { finishReason } : {}, ...toolCalls ? { toolCalls } : {}, ...usage ? { usage } : {}, ...delegatedTools.length ? { delegatedTools } : {}, ...endedWithoutClosing ? { endedWithoutClosing: true } : {} };
|
|
5106
5139
|
}
|
|
5107
5140
|
/**
|
|
5108
5141
|
* FABRICATED TOOL USE — the failure no call-reactive layer can see, because there IS no call.
|
|
@@ -13462,20 +13495,20 @@ var GitCheckpointsOptions = class {
|
|
|
13462
13495
|
import { writeFileSync as writeFileSync6, mkdirSync as mkdirSync9 } from "fs";
|
|
13463
13496
|
import { homedir as homedir7 } from "os";
|
|
13464
13497
|
import { join as join10 } from "path";
|
|
13465
|
-
var RULE_RE = /^(\w
|
|
13498
|
+
var RULE_RE = /^(\w[\w*-]*)(?:\((.+)\))?$/;
|
|
13466
13499
|
function parseOne(raw, decision) {
|
|
13467
13500
|
const m = RULE_RE.exec(raw.trim());
|
|
13468
13501
|
if (!m) return null;
|
|
13469
13502
|
const [, tool, pathGlob] = m;
|
|
13470
13503
|
return pathGlob ? { tool, pathGlob, decision } : { tool, decision };
|
|
13471
13504
|
}
|
|
13472
|
-
function parsePermRules(perms) {
|
|
13505
|
+
function parsePermRules(perms, explicit = false) {
|
|
13473
13506
|
if (!perms) return [];
|
|
13474
13507
|
const out = [];
|
|
13475
13508
|
for (const [decision, list] of [["deny", perms.deny], ["allow", perms.allow], ["ask", perms.ask]]) {
|
|
13476
13509
|
for (const raw of list ?? []) {
|
|
13477
13510
|
const r = parseOne(raw, decision);
|
|
13478
|
-
if (r) out.push(r);
|
|
13511
|
+
if (r) out.push(explicit ? { ...r, explicit } : r);
|
|
13479
13512
|
}
|
|
13480
13513
|
}
|
|
13481
13514
|
return out;
|
|
@@ -16513,7 +16546,7 @@ function optsFor(args, ai, cfg = {}, extraTools = []) {
|
|
|
16513
16546
|
if (perm.notice) err(dim(` \u26A0 ${perm.notice}
|
|
16514
16547
|
`));
|
|
16515
16548
|
const configRules = parsePermRules(cfg.permissions);
|
|
16516
|
-
const flagRules = [...parsePermRules({ deny: args.disallowedTools }), ...parsePermRules({ allow: args.allowedTools })];
|
|
16549
|
+
const flagRules = [...parsePermRules({ deny: args.disallowedTools }, true), ...parsePermRules({ allow: args.allowedTools }, true)];
|
|
16517
16550
|
const askRules = perm.gate === "ask" ? ASK_MUTATING.map((t) => ({ tool: t, decision: "ask" })) : [];
|
|
16518
16551
|
const rules = [...flagRules, ...configRules, ...askRules];
|
|
16519
16552
|
if (configRules.length) err(dim(` \u2295 ${configRules.length} permission rule(s) from config
|
|
@@ -17232,8 +17265,8 @@ async function repl(args, ai, cfg, cwd) {
|
|
|
17232
17265
|
const sendVia = dx ? (c, o) => dx.send(c, o) : void 0;
|
|
17233
17266
|
const routeVia = autoRouteSend(args, agent, () => session, (m) => providerOptionsFor(m, cwd, cfg.mcpServers, mounted.map((x) => x.name)));
|
|
17234
17267
|
const baseRules = () => [
|
|
17235
|
-
...parsePermRules({ deny: args.disallowedTools }),
|
|
17236
|
-
...parsePermRules({ allow: args.allowedTools }),
|
|
17268
|
+
...parsePermRules({ deny: args.disallowedTools }, true),
|
|
17269
|
+
...parsePermRules({ allow: args.allowedTools }, true),
|
|
17237
17270
|
...parsePermRules(mergePerms(loadPersistedRules(cwd), cfg.permissions))
|
|
17238
17271
|
];
|
|
17239
17272
|
const askFor = (tools) => tools.map((t) => ({ tool: t, decision: "ask" }));
|