@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/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { c as AgentOptions, H as Hooks, x as RunResult, k as Decider, b as Agent, q as PermissionPolicy, G as Gender, L as LineKind, d as ChannelMode, y as SecondChannelOptions, S as SecondChannel } from './secondChannel-B76KLrf7.js';
2
- export { A as ADVISE_LIMIT, a as AdvisorSetup, C as CC_WRITE_TOOLS, e as ChatFragment, f as ChatUsage, g as Classification, h as Classifier, i as CompactResult, j as ContextFileSpec, D as DEFAULT_MUTATING, l as Decision, M as ModelRouter, m as ModelRouterOptions, P as PLANNER_BLOCKED, n as PLANNER_REFUSAL, o as PLAN_FIRST, p as PermissionOptions, r as PermissionRule, s as PreToolUseDecision, R as ReasoningEffort, t as RecordingHooks, u as RecordingLifecycle, v as RouteDecision, w as RouterState, T as Tier, z as ToolUse, B as ToolUseMeta, W as WRITE_TOOLS, E as advisorFor, F as advisorPrompt, I as ccModeOptions, J as claudeCodeDisallowedTools, K as composeHooks, N as delegatePrompt, O as delegateTools, Q as delegateWorkerFor, U as estimateTokens, V as jevAvailable, X as jevClassifier, Y as loadContextFiles, Z as loadInstructions, _ as makeAdvisor, $ as meterWorkers, a0 as pickTier, a1 as planMode, a2 as plannerBlocks, a3 as reasoningToChatFragment } from './secondChannel-B76KLrf7.js';
1
+ import { c as AgentOptions, H as Hooks, x as RunResult, k as Decider, b as Agent, q as PermissionPolicy, G as Gender, L as LineKind, d as ChannelMode, y as SecondChannelOptions, S as SecondChannel } from './secondChannel-D-8AGmAT.js';
2
+ export { A as ADVISE_LIMIT, a as AdvisorSetup, C as CC_WRITE_TOOLS, e as ChatFragment, f as ChatUsage, g as Classification, h as Classifier, i as CompactResult, j as ContextFileSpec, D as DEFAULT_MUTATING, l as Decision, M as ModelRouter, m as ModelRouterOptions, P as PLANNER_BLOCKED, n as PLANNER_REFUSAL, o as PLAN_FIRST, p as PermissionOptions, r as PermissionRule, s as PreToolUseDecision, R as ReasoningEffort, t as RecordingHooks, u as RecordingLifecycle, v as RouteDecision, w as RouterState, T as Tier, z as ToolUse, B as ToolUseMeta, W as WRITE_TOOLS, E as advisorFor, F as advisorPrompt, I as ccModeOptions, J as claudeCodeDisallowedTools, K as composeHooks, N as delegatePrompt, O as delegateTools, Q as delegateWorkerFor, U as estimateTokens, V as jevAvailable, X as jevClassifier, Y as loadContextFiles, Z as loadInstructions, _ as makeAdvisor, $ as meterWorkers, a0 as pickTier, a1 as planMode, a2 as plannerBlocks, a3 as reasoningToChatFragment } from './secondChannel-D-8AGmAT.js';
3
3
  export { MODEL_ALIASES, ModelSwitch, ResolveModelSwitchOpts, latestClaude, modelShortLabel, resolveModelAlias, resolveModelSwitch } from './models.js';
4
4
  import { IFilesystem, FileMetadata } from '@livx.cc/wcli/core';
5
5
  export { CommandExecutor, FileMetadata, IFilesystem, IndexedDbFilesystem, MemFilesystem, registerHeadlessCommands } from '@livx.cc/wcli/core';
package/dist/index.js CHANGED
@@ -3901,16 +3901,19 @@ import { join as join3 } from "path";
3901
3901
 
3902
3902
  // src/permissions.ts
3903
3903
  init_tools_structured();
3904
+ import { posix } from "path";
3904
3905
  function commandMatches(glob, cmd) {
3905
3906
  const pattern = glob.split("*").map((s) => s.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*");
3906
3907
  return new RegExp("^" + pattern + "$").test(cmd);
3907
3908
  }
3909
+ var SHELL_CONTROL = /[;&|`$<>\n\r]/;
3908
3910
  function toolMatches(rule, name) {
3909
3911
  return rule.includes("*") ? commandMatches(rule, name) : rule === name;
3910
3912
  }
3911
3913
  var PermissionOptions = class {
3912
3914
  rules = [];
3913
- /** decision when no rule matches. */
3915
+ /** decision when no rule matches. 'deny' = an allow-list run (`--onlyTools`): only the allow rules run, an allowed
3916
+ * command glob never matches shell control syntax, and claude-code enforces it by a PreToolUse hook (ccHooks). */
3914
3917
  default = "allow";
3915
3918
  /** host channel for `ask` (confirm). If absent, `ask` is treated as `deny` (fail-closed). */
3916
3919
  host;
@@ -3923,15 +3926,17 @@ var PermissionPolicy = class {
3923
3926
  /** Resolve the decision for a tool call (first matching rule, else default). */
3924
3927
  decide(call) {
3925
3928
  const names = call.name === "McpCall" && typeof call.args?.name === "string" ? [call.name, call.args.name] : [call.name];
3929
+ if (CC_TOOL_ALIAS[call.name]) names.push(CC_TOOL_ALIAS[call.name]);
3930
+ const strict = this.options.default === "deny";
3926
3931
  for (const r of this.options.rules) {
3927
3932
  if (r.tool && !names.some((n) => toolMatches(r.tool, n))) continue;
3928
3933
  if (r.pathGlob) {
3929
3934
  const path = typeof call.args?.path === "string" ? call.args.path : null;
3930
3935
  const cmd = typeof call.args?.command === "string" ? call.args.command : null;
3931
3936
  if (path != null) {
3932
- if (!globToRegExp(r.pathGlob).test(path.startsWith("/") ? path : `/${path}`)) continue;
3937
+ if (!globToRegExp(r.pathGlob).test(posix.normalize(path.startsWith("/") ? path : `/${path}`))) continue;
3933
3938
  } else if (cmd != null) {
3934
- if (!commandMatches(r.pathGlob, cmd)) continue;
3939
+ if (!commandMatches(r.pathGlob, cmd) || strict && r.decision === "allow" && SHELL_CONTROL.test(cmd)) continue;
3935
3940
  } else continue;
3936
3941
  }
3937
3942
  return r.decision;
@@ -3943,6 +3948,18 @@ var PermissionPolicy = class {
3943
3948
  denyRules(explicitOnly = false) {
3944
3949
  return this.options.rules.filter((r) => r.decision === "deny" && (!explicitOnly || r.explicit)).map((r) => `${r.tool ?? "*"}${r.pathGlob ? `(${r.pathGlob})` : ""}`);
3945
3950
  }
3951
+ /** An allow-list policy (default 'deny') as Claude Code SDK hooks: claude-code runs its own tools, which never reach
3952
+ * {@link hooks}, and `disallowedTools` can't say "everything else". Every tool call (native and MCP) goes through
3953
+ * decide(); `ask` has no host there → deny. undefined for a default-allow policy (its deny rules travel as disallowedTools). */
3954
+ ccHooks() {
3955
+ if (this.options.default !== "deny") return void 0;
3956
+ const gate = async (input) => {
3957
+ const t = input?.tool_input ?? {}, path = t.file_path ?? t.notebook_path ?? t.path;
3958
+ const d = this.decide({ name: String(input?.tool_name ?? ""), args: { ...t, ...typeof path === "string" ? { path } : {} } });
3959
+ return d === "allow" ? {} : { hookSpecificOutput: { hookEventName: "PreToolUse", permissionDecision: "deny", permissionDecisionReason: `not on this run's tool allow-list (${input?.tool_name})` } };
3960
+ };
3961
+ return { PreToolUse: [{ hooks: [gate] }] };
3962
+ }
3946
3963
  /** A preToolUse hook enforcing this policy (deny/ask → block; allow → proceed). */
3947
3964
  hooks() {
3948
3965
  return {
@@ -5181,6 +5198,11 @@ var Agent = class _Agent {
5181
5198
  }
5182
5199
  const denyTools = [...claudeCodeDisallowedTools(o.permissions), ...mode.disallow];
5183
5200
  if (mode.hooks) po.hooks = mode.hooks;
5201
+ const allowOnly = o.permissions?.ccHooks();
5202
+ if (allowOnly) {
5203
+ const h = po.hooks ?? o.providerOptions?.hooks ?? {};
5204
+ po.hooks = { ...h, PreToolUse: [...h.PreToolUse ?? [], ...allowOnly.PreToolUse] };
5205
+ }
5184
5206
  if (this.modeKind && o.providerOptions?.claudeCodeSession) po.claudeCodeSession = `${o.providerOptions.claudeCodeSession}:${this.modeKind}`;
5185
5207
  if (denyTools.length) {
5186
5208
  const prior = o.providerOptions?.disallowedTools ?? [];
@@ -5217,6 +5239,7 @@ var Agent = class _Agent {
5217
5239
  return texts;
5218
5240
  }
5219
5241
  /** Fold any host-injected messages into the transcript as user turns. Returns true if any landed. */
5242
+ reopen = () => this.drainInjections();
5220
5243
  drainInjections() {
5221
5244
  if (!this.pendingInjections.length) return false;
5222
5245
  for (const content of this.pendingInjections.splice(0)) this.transcript.push({ role: "user", content });
@@ -5487,6 +5510,14 @@ var Agent = class _Agent {
5487
5510
  };
5488
5511
  const overBudget = () => !!o.maxTokens && spent >= o.maxTokens;
5489
5512
  const canNudge = () => steps < o.maxSteps && !overBudget();
5513
+ this.reopen = () => {
5514
+ if (!this.pendingInjections.length) return false;
5515
+ if (steps >= o.maxSteps || overBudget()) {
5516
+ log9.warn(`answer finished with ${this.pendingInjections.length} injection(s) pending and no step/budget left \u2014 they wait for the next run`);
5517
+ return false;
5518
+ }
5519
+ return this.drainInjections();
5520
+ };
5490
5521
  while (true) {
5491
5522
  if (o.signal?.aborted) return kill("aborted");
5492
5523
  if (steps >= o.maxSteps) return kill("max_steps");
@@ -5529,6 +5560,8 @@ var Agent = class _Agent {
5529
5560
  const claudeSteerPo = this.claudeCodePo();
5530
5561
  if (this.ccServer) this.ccExec = hostExec;
5531
5562
  const cursorDeny = o.model.startsWith("cursor/") ? o.permissions?.denyRules(true) ?? [] : [];
5563
+ if (o.model.startsWith("cursor/") && o.permissions?.options.default === "deny")
5564
+ throw new Error("cursor/* cannot enforce --onlyTools: its native tools bypass it. Refusing to run \u2014 use a claude-code/* or API model.");
5532
5565
  if (cursorDeny.length)
5533
5566
  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.`);
5534
5567
  const reasonOpts = {
@@ -5631,6 +5664,7 @@ var Agent = class _Agent {
5631
5664
  usage.cacheCreationTokens += res.usage.cacheCreationTokens ?? 0;
5632
5665
  usage.cacheReadTokens += res.usage.cacheReadTokens ?? 0;
5633
5666
  const prompt = res.usage.promptTokens ?? 0, cacheRead = res.usage.cacheReadTokens ?? 0;
5667
+ const ctxTokens = res.usage.contextTokens ?? prompt;
5634
5668
  usage.contextTokens = res.usage.contextTokens ?? prompt;
5635
5669
  usage.contextWindow = res.usage.contextWindow || _Agent.contextCap(o);
5636
5670
  if (prevPrompt < 0) {
@@ -5639,7 +5673,7 @@ var Agent = class _Agent {
5639
5673
  }
5640
5674
  const reused = Math.min(prompt, Math.max(cacheRead, prevPrompt));
5641
5675
  spent += (res.usage.totalTokens ?? 0) - 0.9 * reused;
5642
- prevPrompt = stepPrompt = prompt;
5676
+ prevPrompt = stepPrompt = ctxTokens;
5643
5677
  }
5644
5678
  const delegatedTools = res.delegatedTools ?? [];
5645
5679
  if (delegatedTools.length) {
@@ -5679,7 +5713,7 @@ var Agent = class _Agent {
5679
5713
  });
5680
5714
  }
5681
5715
  if (toolCalls.length === 0) {
5682
- if (this.drainInjections()) continue;
5716
+ if (this.reopen()) continue;
5683
5717
  if (emptyTurn && o.failEmptyTurns) {
5684
5718
  if (!emptyNudged && canNudge()) {
5685
5719
  emptyNudged = true;
@@ -5717,7 +5751,7 @@ var Agent = class _Agent {
5717
5751
  const drained = await this.jobs.drain(o.signal);
5718
5752
  if (o.signal?.aborted) return kill("aborted");
5719
5753
  if (drained.length) lastProgressAt = Date.now();
5720
- if (this.drainInjections()) continue;
5754
+ if (this.reopen()) continue;
5721
5755
  this.releaseStaleImages();
5722
5756
  await this.activeHooks?.onStop?.(res.content ?? "");
5723
5757
  const claims = this.survivingClaims();