@livx.cc/agentx 0.99.127 → 0.99.129

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-CYU9qqwr.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-CYU9qqwr.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 ?? [];
@@ -5538,6 +5560,8 @@ var Agent = class _Agent {
5538
5560
  const claudeSteerPo = this.claudeCodePo();
5539
5561
  if (this.ccServer) this.ccExec = hostExec;
5540
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.");
5541
5565
  if (cursorDeny.length)
5542
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.`);
5543
5567
  const reasonOpts = {
@@ -5799,7 +5823,7 @@ var Agent = class _Agent {
5799
5823
  e.code = "stall";
5800
5824
  return e;
5801
5825
  };
5802
- const poke = () => {
5826
+ const poke = (quietMs) => {
5803
5827
  if (!stallMs) return;
5804
5828
  if (timer) clearTimeout(timer);
5805
5829
  timer = setTimeout(() => {
@@ -5814,7 +5838,7 @@ var Agent = class _Agent {
5814
5838
  log9.warn(`stall watchdog: no stream output for ${stallMs}ms and no tool holding the stream \u2014 aborting the request` + (inFlight.length ? ` (${inFlight.length} detached job(s) running, not awaited by the stream: ${inFlight.map((j) => `${j.id}/${j.kind}`).join(", ")})` : ""));
5815
5839
  fired = true;
5816
5840
  ac.abort(stallError());
5817
- }, stallMs);
5841
+ }, Math.max(stallMs, quietMs ?? 0));
5818
5842
  };
5819
5843
  this.stallPoke = poke;
5820
5844
  poke();
@@ -5856,7 +5880,7 @@ var Agent = class _Agent {
5856
5880
  let resolvedModel;
5857
5881
  for await (const chunk of stream) {
5858
5882
  if (chunk.model) resolvedModel = chunk.model;
5859
- poke?.();
5883
+ poke?.(chunk.quietMs);
5860
5884
  if (this.options.signal?.aborted) break;
5861
5885
  if (chunk.reasoningContent) {
5862
5886
  reasoning += chunk.reasoningContent;