@livx.cc/agentx 0.99.126 → 0.99.128
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/cli.d.ts +2 -1
- package/dist/cli.js +47 -10
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +40 -6
- package/dist/index.js.map +1 -1
- package/dist/{secondChannel-B76KLrf7.d.ts → secondChannel-D-8AGmAT.d.ts} +7 -1
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
|
-
import { w as RouterState, H as Hooks, c as AgentOptions, x as RunResult, f as ChatUsage, R as ReasoningEffort, d as ChannelMode, b as Agent } from './secondChannel-
|
|
2
|
+
import { w as RouterState, H as Hooks, c as AgentOptions, x as RunResult, f as ChatUsage, R as ReasoningEffort, d as ChannelMode, b as Agent } from './secondChannel-D-8AGmAT.js';
|
|
3
3
|
import { IFilesystem } from '@livx.cc/wcli/core';
|
|
4
4
|
import { M as Message, U as UserQuestion, H as HostBridge, c as ContentPart, o as MessageContent } from './tools-DwfeF8VQ.js';
|
|
5
5
|
|
|
@@ -170,6 +170,7 @@ interface Args {
|
|
|
170
170
|
inputFormat?: 'stream-json';
|
|
171
171
|
allowedTools?: string[];
|
|
172
172
|
disallowedTools?: string[];
|
|
173
|
+
onlyTools?: string[];
|
|
173
174
|
appendSystemPrompt?: string;
|
|
174
175
|
voiceSystemPrompt?: string;
|
|
175
176
|
addDirs?: string[];
|
package/dist/cli.js
CHANGED
|
@@ -4160,16 +4160,19 @@ import { join as join4 } from "path";
|
|
|
4160
4160
|
|
|
4161
4161
|
// src/permissions.ts
|
|
4162
4162
|
init_tools_structured();
|
|
4163
|
+
import { posix } from "path";
|
|
4163
4164
|
function commandMatches(glob, cmd) {
|
|
4164
4165
|
const pattern = glob.split("*").map((s) => s.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*");
|
|
4165
4166
|
return new RegExp("^" + pattern + "$").test(cmd);
|
|
4166
4167
|
}
|
|
4168
|
+
var SHELL_CONTROL = /[;&|`$<>\n\r]/;
|
|
4167
4169
|
function toolMatches(rule, name) {
|
|
4168
4170
|
return rule.includes("*") ? commandMatches(rule, name) : rule === name;
|
|
4169
4171
|
}
|
|
4170
4172
|
var PermissionOptions = class {
|
|
4171
4173
|
rules = [];
|
|
4172
|
-
/** decision when no rule matches.
|
|
4174
|
+
/** decision when no rule matches. 'deny' = an allow-list run (`--onlyTools`): only the allow rules run, an allowed
|
|
4175
|
+
* command glob never matches shell control syntax, and claude-code enforces it by a PreToolUse hook (ccHooks). */
|
|
4173
4176
|
default = "allow";
|
|
4174
4177
|
/** host channel for `ask` (confirm). If absent, `ask` is treated as `deny` (fail-closed). */
|
|
4175
4178
|
host;
|
|
@@ -4182,15 +4185,17 @@ var PermissionPolicy = class {
|
|
|
4182
4185
|
/** Resolve the decision for a tool call (first matching rule, else default). */
|
|
4183
4186
|
decide(call) {
|
|
4184
4187
|
const names = call.name === "McpCall" && typeof call.args?.name === "string" ? [call.name, call.args.name] : [call.name];
|
|
4188
|
+
if (CC_TOOL_ALIAS[call.name]) names.push(CC_TOOL_ALIAS[call.name]);
|
|
4189
|
+
const strict = this.options.default === "deny";
|
|
4185
4190
|
for (const r of this.options.rules) {
|
|
4186
4191
|
if (r.tool && !names.some((n) => toolMatches(r.tool, n))) continue;
|
|
4187
4192
|
if (r.pathGlob) {
|
|
4188
4193
|
const path = typeof call.args?.path === "string" ? call.args.path : null;
|
|
4189
4194
|
const cmd = typeof call.args?.command === "string" ? call.args.command : null;
|
|
4190
4195
|
if (path != null) {
|
|
4191
|
-
if (!globToRegExp(r.pathGlob).test(path.startsWith("/") ? path : `/${path}`)) continue;
|
|
4196
|
+
if (!globToRegExp(r.pathGlob).test(posix.normalize(path.startsWith("/") ? path : `/${path}`))) continue;
|
|
4192
4197
|
} else if (cmd != null) {
|
|
4193
|
-
if (!commandMatches(r.pathGlob, cmd)) continue;
|
|
4198
|
+
if (!commandMatches(r.pathGlob, cmd) || strict && r.decision === "allow" && SHELL_CONTROL.test(cmd)) continue;
|
|
4194
4199
|
} else continue;
|
|
4195
4200
|
}
|
|
4196
4201
|
return r.decision;
|
|
@@ -4202,6 +4207,18 @@ var PermissionPolicy = class {
|
|
|
4202
4207
|
denyRules(explicitOnly = false) {
|
|
4203
4208
|
return this.options.rules.filter((r) => r.decision === "deny" && (!explicitOnly || r.explicit)).map((r) => `${r.tool ?? "*"}${r.pathGlob ? `(${r.pathGlob})` : ""}`);
|
|
4204
4209
|
}
|
|
4210
|
+
/** An allow-list policy (default 'deny') as Claude Code SDK hooks: claude-code runs its own tools, which never reach
|
|
4211
|
+
* {@link hooks}, and `disallowedTools` can't say "everything else". Every tool call (native and MCP) goes through
|
|
4212
|
+
* decide(); `ask` has no host there → deny. undefined for a default-allow policy (its deny rules travel as disallowedTools). */
|
|
4213
|
+
ccHooks() {
|
|
4214
|
+
if (this.options.default !== "deny") return void 0;
|
|
4215
|
+
const gate = async (input) => {
|
|
4216
|
+
const t = input?.tool_input ?? {}, path = t.file_path ?? t.notebook_path ?? t.path;
|
|
4217
|
+
const d = this.decide({ name: String(input?.tool_name ?? ""), args: { ...t, ...typeof path === "string" ? { path } : {} } });
|
|
4218
|
+
return d === "allow" ? {} : { hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: `not on this run's tool allow-list (${input?.tool_name})` } };
|
|
4219
|
+
};
|
|
4220
|
+
return { PreToolUse: [{ hooks: [gate] }] };
|
|
4221
|
+
}
|
|
4205
4222
|
/** A preToolUse hook enforcing this policy (deny/ask → block; allow → proceed). */
|
|
4206
4223
|
hooks() {
|
|
4207
4224
|
return {
|
|
@@ -5290,6 +5307,11 @@ var Agent = class _Agent {
|
|
|
5290
5307
|
}
|
|
5291
5308
|
const denyTools = [...claudeCodeDisallowedTools(o.permissions), ...mode.disallow];
|
|
5292
5309
|
if (mode.hooks) po.hooks = mode.hooks;
|
|
5310
|
+
const allowOnly = o.permissions?.ccHooks();
|
|
5311
|
+
if (allowOnly) {
|
|
5312
|
+
const h = po.hooks ?? o.providerOptions?.hooks ?? {};
|
|
5313
|
+
po.hooks = { ...h, PreToolUse: [...h.PreToolUse ?? [], ...allowOnly.PreToolUse] };
|
|
5314
|
+
}
|
|
5293
5315
|
if (this.modeKind && o.providerOptions?.claudeCodeSession) po.claudeCodeSession = `${o.providerOptions.claudeCodeSession}:${this.modeKind}`;
|
|
5294
5316
|
if (denyTools.length) {
|
|
5295
5317
|
const prior = o.providerOptions?.disallowedTools ?? [];
|
|
@@ -5326,6 +5348,7 @@ var Agent = class _Agent {
|
|
|
5326
5348
|
return texts;
|
|
5327
5349
|
}
|
|
5328
5350
|
/** Fold any host-injected messages into the transcript as user turns. Returns true if any landed. */
|
|
5351
|
+
reopen = () => this.drainInjections();
|
|
5329
5352
|
drainInjections() {
|
|
5330
5353
|
if (!this.pendingInjections.length) return false;
|
|
5331
5354
|
for (const content of this.pendingInjections.splice(0)) this.transcript.push({ role: "user", content });
|
|
@@ -5596,6 +5619,14 @@ var Agent = class _Agent {
|
|
|
5596
5619
|
};
|
|
5597
5620
|
const overBudget = () => !!o.maxTokens && spent >= o.maxTokens;
|
|
5598
5621
|
const canNudge = () => steps < o.maxSteps && !overBudget();
|
|
5622
|
+
this.reopen = () => {
|
|
5623
|
+
if (!this.pendingInjections.length) return false;
|
|
5624
|
+
if (steps >= o.maxSteps || overBudget()) {
|
|
5625
|
+
log9.warn(`answer finished with ${this.pendingInjections.length} injection(s) pending and no step/budget left \u2014 they wait for the next run`);
|
|
5626
|
+
return false;
|
|
5627
|
+
}
|
|
5628
|
+
return this.drainInjections();
|
|
5629
|
+
};
|
|
5599
5630
|
while (true) {
|
|
5600
5631
|
if (o.signal?.aborted) return kill("aborted");
|
|
5601
5632
|
if (steps >= o.maxSteps) return kill("max_steps");
|
|
@@ -5638,6 +5669,8 @@ var Agent = class _Agent {
|
|
|
5638
5669
|
const claudeSteerPo = this.claudeCodePo();
|
|
5639
5670
|
if (this.ccServer) this.ccExec = hostExec;
|
|
5640
5671
|
const cursorDeny = o.model.startsWith("cursor/") ? o.permissions?.denyRules(true) ?? [] : [];
|
|
5672
|
+
if (o.model.startsWith("cursor/") && o.permissions?.options.default === "deny")
|
|
5673
|
+
throw new Error("cursor/* cannot enforce --onlyTools: its native tools bypass it. Refusing to run \u2014 use a claude-code/* or API model.");
|
|
5641
5674
|
if (cursorDeny.length)
|
|
5642
5675
|
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.`);
|
|
5643
5676
|
const reasonOpts = {
|
|
@@ -5740,6 +5773,7 @@ var Agent = class _Agent {
|
|
|
5740
5773
|
usage.cacheCreationTokens += res.usage.cacheCreationTokens ?? 0;
|
|
5741
5774
|
usage.cacheReadTokens += res.usage.cacheReadTokens ?? 0;
|
|
5742
5775
|
const prompt = res.usage.promptTokens ?? 0, cacheRead = res.usage.cacheReadTokens ?? 0;
|
|
5776
|
+
const ctxTokens = res.usage.contextTokens ?? prompt;
|
|
5743
5777
|
usage.contextTokens = res.usage.contextTokens ?? prompt;
|
|
5744
5778
|
usage.contextWindow = res.usage.contextWindow || _Agent.contextCap(o);
|
|
5745
5779
|
if (prevPrompt < 0) {
|
|
@@ -5748,7 +5782,7 @@ var Agent = class _Agent {
|
|
|
5748
5782
|
}
|
|
5749
5783
|
const reused = Math.min(prompt, Math.max(cacheRead, prevPrompt));
|
|
5750
5784
|
spent += (res.usage.totalTokens ?? 0) - 0.9 * reused;
|
|
5751
|
-
prevPrompt = stepPrompt =
|
|
5785
|
+
prevPrompt = stepPrompt = ctxTokens;
|
|
5752
5786
|
}
|
|
5753
5787
|
const delegatedTools = res.delegatedTools ?? [];
|
|
5754
5788
|
if (delegatedTools.length) {
|
|
@@ -5788,7 +5822,7 @@ var Agent = class _Agent {
|
|
|
5788
5822
|
});
|
|
5789
5823
|
}
|
|
5790
5824
|
if (toolCalls.length === 0) {
|
|
5791
|
-
if (this.
|
|
5825
|
+
if (this.reopen()) continue;
|
|
5792
5826
|
if (emptyTurn && o.failEmptyTurns) {
|
|
5793
5827
|
if (!emptyNudged && canNudge()) {
|
|
5794
5828
|
emptyNudged = true;
|
|
@@ -5826,7 +5860,7 @@ var Agent = class _Agent {
|
|
|
5826
5860
|
const drained = await this.jobs.drain(o.signal);
|
|
5827
5861
|
if (o.signal?.aborted) return kill("aborted");
|
|
5828
5862
|
if (drained.length) lastProgressAt = Date.now();
|
|
5829
|
-
if (this.
|
|
5863
|
+
if (this.reopen()) continue;
|
|
5830
5864
|
this.releaseStaleImages();
|
|
5831
5865
|
await this.activeHooks?.onStop?.(res.content ?? "");
|
|
5832
5866
|
const claims = this.survivingClaims();
|
|
@@ -19493,6 +19527,7 @@ function parseArgs(argv) {
|
|
|
19493
19527
|
} else if (x === "--think-model") a.thinkModel = val(++i, x);
|
|
19494
19528
|
else if (x === "--no-think") a.thinkModel = false;
|
|
19495
19529
|
else if (x === "--allowedTools" || x === "--allowed-tools") a.allowedTools = val(++i, x).split(",").map((s) => s.trim()).filter(Boolean);
|
|
19530
|
+
else if (x === "--onlyTools" || x === "--only-tools") a.onlyTools = val(++i, x).split(",").map((s) => s.trim()).filter(Boolean);
|
|
19496
19531
|
else if (x === "--disallowedTools" || x === "--disallowed-tools") a.disallowedTools = val(++i, x).split(",").map((s) => s.trim()).filter(Boolean);
|
|
19497
19532
|
else if (x === "--append-system-prompt") a.appendSystemPrompt = val(++i, x);
|
|
19498
19533
|
else if (x === "--voice-system-prompt") a.voiceSystemPrompt = val(++i, x);
|
|
@@ -19578,6 +19613,8 @@ Flags:
|
|
|
19578
19613
|
--verbose, --debug verbose logs (sets DEBUG=* \u2014 tool args, hook decisions, retries)
|
|
19579
19614
|
--allowedTools <l> comma-list of tools to allow w/o asking, e.g. "Edit,Shell(git *)"
|
|
19580
19615
|
--disallowedTools <l> comma-list of tools to deny outright (wins over allow), e.g. "Shell(rm *)"
|
|
19616
|
+
--onlyTools <l> allow-list: ONLY these run, all else is denied (a command glob never matches shell chaining, pipes, $ or redirects),
|
|
19617
|
+
e.g. "Read(/job/**),Write(/job/**),Bash(bun /skill/cli.ts *)" \u2014 cursor/* refuses it
|
|
19581
19618
|
--append-system-prompt <t> extra instructions appended to the system prompt for this run
|
|
19582
19619
|
--call voice call (duplex v3): the main agent (-m, full tools) answers every turn; a fast model
|
|
19583
19620
|
(--voice-model, default Claude Haiku) only fills the wait \u2014 backchannels, fillers, bridges,
|
|
@@ -20359,9 +20396,9 @@ function optsFor(args, ai, cfg = {}, extraTools = []) {
|
|
|
20359
20396
|
const perm = resolvePermMode(args, canPrompt);
|
|
20360
20397
|
if (perm.notice) err(dim(` \u26A0 ${perm.notice}
|
|
20361
20398
|
`));
|
|
20362
|
-
const configRules = parsePermRules(cfg.permissions);
|
|
20363
|
-
const flagRules = [...parsePermRules({ deny: args.disallowedTools }, true), ...parsePermRules({ allow: args.allowedTools }, true)];
|
|
20364
|
-
const askRules = perm.gate === "ask" ? ASK_MUTATING.map((t) => ({ tool: t, decision: "ask" })) : [];
|
|
20399
|
+
const configRules = parsePermRules(cfg.permissions).filter((r) => !args.onlyTools || r.decision !== "allow");
|
|
20400
|
+
const flagRules = [...parsePermRules({ deny: args.disallowedTools }, true), ...parsePermRules({ allow: args.onlyTools ?? args.allowedTools }, true)];
|
|
20401
|
+
const askRules = perm.gate === "ask" && !args.onlyTools ? ASK_MUTATING.map((t) => ({ tool: t, decision: "ask" })) : [];
|
|
20365
20402
|
const rules = [...flagRules, ...configRules, ...askRules];
|
|
20366
20403
|
if (configRules.length) err(dim(` \u2295 ${configRules.length} permission rule(s) from config
|
|
20367
20404
|
`));
|
|
@@ -20387,7 +20424,7 @@ function optsFor(args, ai, cfg = {}, extraTools = []) {
|
|
|
20387
20424
|
stream: args.stream,
|
|
20388
20425
|
host: makeHost(args.outputFormat, { stream: true }),
|
|
20389
20426
|
planMode: args.plan || cfg.planMode || false,
|
|
20390
|
-
permissions: rules.length ? new PermissionPolicy({ rules, default: "allow", host: makeHost(), ask: makeAskResolver(resolve5(args.cwd ?? process.cwd())) }) : void 0,
|
|
20427
|
+
permissions: rules.length || args.onlyTools ? new PermissionPolicy({ rules, default: args.onlyTools ? "deny" : "allow", host: makeHost(), ask: makeAskResolver(resolve5(args.cwd ?? process.cwd())) }) : void 0,
|
|
20391
20428
|
subagents: args.subagents || cfg.subagents || false,
|
|
20392
20429
|
maxSteps: args.maxSteps ?? cfg.maxSteps,
|
|
20393
20430
|
reasoning: args.reasoning ?? cfg.reasoning,
|