jinzd-ai-cli 0.4.287 → 0.4.288

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.
Files changed (32) hide show
  1. package/dist/{batch-6OH7D5YU.js → batch-YAEXKK2C.js} +2 -2
  2. package/dist/{chunk-AXSWLNCU.js → chunk-37WBQV3E.js} +90 -127
  3. package/dist/{chunk-HEUB5PV6.js → chunk-5G6HX57U.js} +1 -1
  4. package/dist/{chunk-L7RAEUUN.js → chunk-6NEEFOVF.js} +1 -1
  5. package/dist/{chunk-5F7BGV72.js → chunk-7RC7AN6V.js} +1 -1
  6. package/dist/{chunk-EU6NMK7G.js → chunk-C5UAM4X7.js} +3 -3
  7. package/dist/{chunk-3BHJKMPQ.js → chunk-E66SCDTD.js} +1 -1
  8. package/dist/{chunk-L625B2XV.js → chunk-EYA4IXQJ.js} +1 -1
  9. package/dist/{chunk-3Y5BCGD2.js → chunk-G5QZS5TN.js} +1 -1
  10. package/dist/{chunk-ERDFOXYK.js → chunk-JBNNJ32H.js} +1 -1
  11. package/dist/{chunk-HNUT4STJ.js → chunk-NJDQCQ7P.js} +7 -7
  12. package/dist/{chunk-UDFK5Q52.js → chunk-O4CZPTPU.js} +1 -1
  13. package/dist/{chunk-CYUAHF6X.js → chunk-U4NQ2IRE.js} +1 -1
  14. package/dist/{chunk-RZVGR3KD.js → chunk-WQ2YQ5YC.js} +3 -3
  15. package/dist/{ci-WXCMI4ND.js → ci-RO2NLIRH.js} +4 -4
  16. package/dist/{ci-format-JXD2BQM6.js → ci-format-GBSRK2J4.js} +2 -2
  17. package/dist/{constants-SRRV3K5Y.js → constants-JQP6BENR.js} +1 -1
  18. package/dist/{constants-2B7CN2ER.js → constants-T2B3SBMR.js} +1 -1
  19. package/dist/{doctor-cli-LQYTDJ74.js → doctor-cli-CVOE7FAE.js} +4 -4
  20. package/dist/electron-server.js +117 -235
  21. package/dist/{hub-Y62P5MIA.js → hub-LFWL5PGH.js} +1 -1
  22. package/dist/index.js +17 -17
  23. package/dist/{persistent-memory-46JSUEYV.js → persistent-memory-4UR27ACM.js} +2 -2
  24. package/dist/{persistent-memory-3N2XQKJK.js → persistent-memory-LFE3YHZO.js} +2 -2
  25. package/dist/{pr-L7Y3XHGL.js → pr-3QAG7XO7.js} +4 -4
  26. package/dist/{run-tests-WC644BHH.js → run-tests-GGNFI7CL.js} +2 -2
  27. package/dist/{run-tests-3ZOMRFIX.js → run-tests-R3JB4UEI.js} +2 -2
  28. package/dist/{server-XWURZCAF.js → server-I6DXVJRO.js} +39 -114
  29. package/dist/{server-L4QHJT2I.js → server-THHSJRNI.js} +5 -5
  30. package/dist/{task-orchestrator-6TVKJYKC.js → task-orchestrator-6HH3KQUQ.js} +5 -5
  31. package/dist/{usage-L2PSI2KH.js → usage-UB4ZT5PE.js} +2 -2
  32. package/package.json +1 -1
@@ -50,7 +50,7 @@ import {
50
50
  touchMemoryReferences,
51
51
  updateMemoryApproval,
52
52
  updateMemoryEntry
53
- } from "./chunk-L625B2XV.js";
53
+ } from "./chunk-EYA4IXQJ.js";
54
54
  import {
55
55
  DEFAULT_PATTERNS,
56
56
  redactJson,
@@ -66,7 +66,7 @@ import {
66
66
  } from "./chunk-CGLYJRFA.js";
67
67
  import {
68
68
  runTestsTool
69
- } from "./chunk-3BHJKMPQ.js";
69
+ } from "./chunk-E66SCDTD.js";
70
70
  import {
71
71
  AGENTIC_BEHAVIOR_GUIDELINE,
72
72
  APP_NAME,
@@ -100,7 +100,7 @@ import {
100
100
  SUBAGENT_MAX_ROUNDS_LIMIT,
101
101
  VERSION,
102
102
  buildUserIdentityPrompt
103
- } from "./chunk-CYUAHF6X.js";
103
+ } from "./chunk-U4NQ2IRE.js";
104
104
 
105
105
  // src/web/server.ts
106
106
  import express from "express";
@@ -7262,6 +7262,63 @@ function runHook(template, vars) {
7262
7262
  }
7263
7263
  }
7264
7264
 
7265
+ // src/core/tool-gate.ts
7266
+ var gateMessages = {
7267
+ hookDenied: (toolName, reason) => `[Hook denied] ${reason ?? `PreToolUse blocked ${toolName}`}. Do not retry without asking.`,
7268
+ networkDenied: (toolName, reason) => `[Permission denied] Tool ${toolName} is blocked by networkPolicy${reason ? ` (${reason})` : ""}. Do not retry.`,
7269
+ profileDenied: (toolName, profileName, reason) => `[Permission denied] Tool ${toolName} is blocked by permission profile "${profileName}"${reason ? ` (${reason})` : ""}. Do not retry.`,
7270
+ autoDenied: (reason) => `[Auto denied] ${reason}. Do not retry without asking.`,
7271
+ permissionCancelled: (toolName) => `[User cancelled] The user declined permission for ${toolName}. Do not retry without asking.`,
7272
+ operationCancelled: (toolName, level) => `[User cancelled] The user declined the ${level === "destructive" ? "destructive " : ""}${toolName} operation. Do not retry without asking.`
7273
+ };
7274
+ function needsPermissionRequestHook(input) {
7275
+ return input.networkPermission?.action === "confirm" || input.permission.action === "confirm";
7276
+ }
7277
+ function decideToolGate(call, input) {
7278
+ const { dangerLevel, permission, networkPermission } = input;
7279
+ if (input.hookDeny) {
7280
+ return { kind: "denied", source: "hook", message: gateMessages.hookDenied(call.name, input.hookDeny.reason) };
7281
+ }
7282
+ if (networkPermission?.action === "deny") {
7283
+ return { kind: "denied", source: "network", message: gateMessages.networkDenied(call.name, networkPermission.reason) };
7284
+ }
7285
+ if (permission.action === "deny") {
7286
+ return {
7287
+ kind: "denied",
7288
+ source: "profile",
7289
+ message: gateMessages.profileDenied(call.name, permission.profileName ?? "default", permission.reason)
7290
+ };
7291
+ }
7292
+ if (permission.action === "auto-approve" && networkPermission?.action !== "confirm") {
7293
+ return { kind: "allow", source: "profile" };
7294
+ }
7295
+ const requiresHardConfirmation = permission.action === "confirm" && permission.hardBoundary === true;
7296
+ if ((networkPermission?.action === "confirm" || requiresHardConfirmation) && dangerLevel === "safe") {
7297
+ return { kind: "confirm", level: "write", source: "permission" };
7298
+ }
7299
+ if (input.sessionAutoMode && networkPermission?.action !== "confirm") {
7300
+ const classification = input.classify();
7301
+ if (classification.decision === "deny") {
7302
+ return {
7303
+ kind: "denied",
7304
+ source: "auto-mode",
7305
+ message: gateMessages.autoDenied(classification.reason),
7306
+ classification
7307
+ };
7308
+ }
7309
+ if (classification.decision === "auto-approve" && !requiresHardConfirmation) {
7310
+ return { kind: "allow", source: "auto-mode" };
7311
+ }
7312
+ }
7313
+ if (input.sessionAutoApprove && dangerLevel === "write" && !requiresHardConfirmation) {
7314
+ return { kind: "allow", source: "yolo" };
7315
+ }
7316
+ if (dangerLevel === "write" || dangerLevel === "destructive") {
7317
+ return { kind: "confirm", level: dangerLevel, source: "danger" };
7318
+ }
7319
+ return { kind: "allow", source: "safe" };
7320
+ }
7321
+
7265
7322
  // src/tools/permissions.ts
7266
7323
  import { existsSync as existsSync9, realpathSync } from "fs";
7267
7324
  import { basename as basename2, dirname as dirname3, isAbsolute, resolve as resolve3 } from "path";
@@ -8056,13 +8113,6 @@ var ToolExecutor = class {
8056
8113
  { configDir: this.hookConfigDir, onSummary: (msg) => console.log(theme.dim(` [hook] ${msg}`)) }
8057
8114
  );
8058
8115
  const preDeny = preToolDecisions.find((d) => d.action === "deny");
8059
- if (preDeny) {
8060
- return {
8061
- callId: call.id,
8062
- content: `[Hook denied] ${preDeny.reason ?? `PreToolUse blocked ${call.name}`}. Do not retry without asking.`,
8063
- isError: true
8064
- };
8065
- }
8066
8116
  for (const d of preToolDecisions) {
8067
8117
  const warnings = [d.warning, ...d.warnings ?? []].filter(Boolean);
8068
8118
  for (const w of warnings) console.log(theme.warning(` \u26A0 Hook warning: ${w}`));
@@ -8082,7 +8132,19 @@ var ToolExecutor = class {
8082
8132
  }
8083
8133
  );
8084
8134
  const networkPermission = checkNetworkPolicy(call.name, call.arguments, this.networkPolicy);
8085
- if (networkPermission?.action === "confirm" || permission.action === "confirm") {
8135
+ const gate = decideToolGate(call, {
8136
+ dangerLevel,
8137
+ permission,
8138
+ networkPermission,
8139
+ hookDeny: preDeny ? { reason: preDeny.reason } : void 0,
8140
+ sessionAutoMode: this.sessionAutoMode,
8141
+ sessionAutoApprove: this.sessionAutoApprove,
8142
+ classify: () => defaultActionClassifier.classify(call, dangerLevel, {
8143
+ workspaceRoot: this.workspaceRoot,
8144
+ tempDirs: [tmpdir()]
8145
+ })
8146
+ });
8147
+ if (needsPermissionRequestHook({ permission, networkPermission })) {
8086
8148
  runLifecycleHooks(
8087
8149
  this.hookConfig,
8088
8150
  "PermissionRequest",
@@ -8090,131 +8152,29 @@ var ToolExecutor = class {
8090
8152
  { configDir: this.hookConfigDir, onSummary: (msg) => console.log(theme.dim(" [hook] " + msg)) }
8091
8153
  );
8092
8154
  }
8093
- if (networkPermission?.action === "deny") {
8094
- const reason = networkPermission.reason ? ` (${networkPermission.reason})` : "";
8095
- return {
8096
- callId: call.id,
8097
- content: `[Permission denied] Tool ${call.name} is blocked by networkPolicy${reason}. Do not retry.`,
8098
- isError: true
8099
- };
8100
- }
8101
- if (permission.action === "deny") {
8102
- const reason = permission.reason ? ` (${permission.reason})` : "";
8103
- return {
8104
- callId: call.id,
8105
- content: `[Permission denied] Tool ${call.name} is blocked by permission profile "${permission.profileName}"${reason}. Do not retry.`,
8106
- isError: true
8107
- };
8108
- }
8109
- if (permission.action === "auto-approve" && networkPermission?.action !== "confirm") {
8110
- if (!toolCallAlreadyPrinted) this.printToolCall(call);
8111
- try {
8112
- const rawContent = await runTool(tool, call.arguments, call.name);
8113
- const content = truncateOutput(rawContent, call.name);
8114
- const wasTruncated = content !== rawContent;
8115
- this.printToolResult(call.name, rawContent, false, wasTruncated);
8116
- runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "ok" });
8117
- runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
8118
- return { callId: call.id, content, isError: false };
8119
- } catch (err) {
8120
- const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
8121
- this.printToolResult(call.name, message, true, false);
8122
- runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
8123
- runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
8124
- return { callId: call.id, content: message, isError: true };
8125
- }
8126
- }
8127
- const requiresHardConfirmation = permission.action === "confirm" && permission.hardBoundary === true;
8128
- if ((networkPermission?.action === "confirm" || requiresHardConfirmation) && dangerLevel === "safe") {
8129
- this.printToolCall(call);
8130
- toolCallAlreadyPrinted = true;
8131
- const confirmed = await this.confirm(call, "write");
8132
- if (!confirmed) {
8133
- return {
8134
- callId: call.id,
8135
- content: `[User cancelled] The user declined permission for ${call.name}. Do not retry without asking.`,
8136
- isError: true
8137
- };
8138
- }
8155
+ if (gate.kind === "denied") {
8156
+ if (gate.source === "auto-mode") recordRecentlyDeniedAutoAction(call, gate.classification);
8157
+ return { callId: call.id, content: gate.message, isError: true };
8139
8158
  }
8140
- if (this.sessionAutoMode && networkPermission?.action !== "confirm") {
8141
- const classification = defaultActionClassifier.classify(call, dangerLevel, {
8142
- workspaceRoot: this.workspaceRoot,
8143
- tempDirs: [tmpdir()]
8144
- });
8145
- if (classification.decision === "deny") {
8146
- recordRecentlyDeniedAutoAction(call, classification);
8147
- return {
8148
- callId: call.id,
8149
- content: `[Auto denied] ${classification.reason}. Do not retry without asking.`,
8150
- isError: true
8151
- };
8152
- }
8153
- if (classification.decision === "auto-approve" && !requiresHardConfirmation) {
8159
+ if (gate.kind === "confirm") {
8160
+ if (gate.source === "danger" && gate.level === "write") {
8154
8161
  this.printToolCall(call);
8155
- if (dangerLevel === "write") this.printDiffPreview(call);
8156
- console.log(theme.warning(` \u26A1 Auto-approved (/auto: ${classification.ruleId})`));
8157
- try {
8158
- const rawContent = await runTool(tool, call.arguments, call.name);
8159
- const content = truncateOutput(rawContent, call.name);
8160
- const wasTruncated = content !== rawContent;
8161
- this.printToolResult(call.name, rawContent, false, wasTruncated);
8162
- runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "ok" });
8163
- runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
8164
- return { callId: call.id, content, isError: false };
8165
- } catch (err) {
8166
- const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
8167
- this.printToolResult(call.name, message, true, false);
8168
- runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
8169
- runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
8170
- return { callId: call.id, content: message, isError: true };
8171
- }
8172
- }
8173
- }
8174
- if (this.sessionAutoApprove && dangerLevel === "write" && !requiresHardConfirmation) {
8175
- this.printToolCall(call);
8176
- if (dangerLevel === "write") this.printDiffPreview(call);
8177
- console.log(theme.warning(" \u26A1 Auto-approved (session /yolo mode)"));
8178
- try {
8179
- const rawContent = await runTool(tool, call.arguments, call.name);
8180
- const content = truncateOutput(rawContent, call.name);
8181
- const wasTruncated = content !== rawContent;
8182
- this.printToolResult(call.name, rawContent, false, wasTruncated);
8183
- runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "ok" });
8184
- runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
8185
- return { callId: call.id, content, isError: false };
8186
- } catch (err) {
8187
- const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
8188
- this.printToolResult(call.name, message, true, false);
8189
- runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
8190
- runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
8191
- return { callId: call.id, content: message, isError: true };
8192
- }
8193
- }
8194
- if (dangerLevel === "write") {
8195
- this.printToolCall(call);
8196
- this.printDiffPreview(call);
8197
- const confirmed = await this.confirm(call, dangerLevel);
8198
- if (!confirmed) {
8199
- return {
8200
- callId: call.id,
8201
- content: `[User cancelled] The user declined the ${call.name} operation. Do not retry without asking.`,
8202
- isError: true
8203
- };
8162
+ this.printDiffPreview(call);
8163
+ toolCallAlreadyPrinted = true;
8164
+ } else if (gate.source === "permission") {
8165
+ this.printToolCall(call);
8166
+ toolCallAlreadyPrinted = true;
8204
8167
  }
8205
- } else if (dangerLevel === "destructive") {
8206
- const confirmed = await this.confirm(call, dangerLevel);
8168
+ const confirmed = await this.confirm(call, gate.level);
8207
8169
  if (!confirmed) {
8208
8170
  return {
8209
8171
  callId: call.id,
8210
- content: `[User cancelled] The user declined the destructive ${call.name} operation. Do not retry without asking.`,
8172
+ content: gate.source === "permission" ? gateMessages.permissionCancelled(call.name) : gateMessages.operationCancelled(call.name, gate.level),
8211
8173
  isError: true
8212
8174
  };
8213
8175
  }
8214
- this.printToolCall(call);
8215
- } else {
8216
- this.printToolCall(call);
8217
8176
  }
8177
+ if (!toolCallAlreadyPrinted) this.printToolCall(call);
8218
8178
  try {
8219
8179
  const rawContent = await runTool(tool, call.arguments, call.name);
8220
8180
  const content = truncateOutput(rawContent, call.name);
@@ -14048,15 +14008,6 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
14048
14008
  { configDir: this.hookConfigDir, onSummary: (message) => this.send({ type: "info", message: `[hook] ${message}` }) }
14049
14009
  );
14050
14010
  const preDeny = preToolDecisions.find((d) => d.action === "deny");
14051
- if (preDeny) {
14052
- const result = {
14053
- callId: call.id,
14054
- content: `[Hook denied] ${preDeny.reason ?? `PreToolUse blocked ${call.name}`}. Do not retry without asking.`,
14055
- isError: true
14056
- };
14057
- this.sendToolCallResult(call, result.content, true);
14058
- return result;
14059
- }
14060
14011
  for (const d of preToolDecisions) {
14061
14012
  const warnings = [d.warning, ...d.warnings ?? []].filter(Boolean);
14062
14013
  for (const warning of warnings) this.send({ type: "info", message: `[hook] ${warning}` });
@@ -14076,7 +14027,19 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
14076
14027
  }
14077
14028
  );
14078
14029
  const networkPermission = checkNetworkPolicy(call.name, call.arguments, this.networkPolicy);
14079
- if (networkPermission?.action === "confirm" || permission.action === "confirm") {
14030
+ const gate = decideToolGate(call, {
14031
+ dangerLevel,
14032
+ permission,
14033
+ networkPermission,
14034
+ hookDeny: preDeny ? { reason: preDeny.reason } : void 0,
14035
+ sessionAutoMode: this.sessionAutoMode,
14036
+ sessionAutoApprove: this.sessionAutoApprove,
14037
+ classify: () => defaultActionClassifier.classify(call, dangerLevel, {
14038
+ workspaceRoot: this.workspaceRoot,
14039
+ tempDirs: [tmpdir2()]
14040
+ })
14041
+ });
14042
+ if (needsPermissionRequestHook({ permission, networkPermission })) {
14080
14043
  runLifecycleHooks(
14081
14044
  this.hookConfig,
14082
14045
  "PermissionRequest",
@@ -14084,105 +14047,24 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
14084
14047
  { configDir: this.hookConfigDir, onSummary: (message) => this.send({ type: "info", message: "[hook] " + message }) }
14085
14048
  );
14086
14049
  }
14087
- if (networkPermission?.action === "deny") {
14088
- const reason = networkPermission.reason ? ` (${networkPermission.reason})` : "";
14089
- return {
14090
- callId: call.id,
14091
- content: `[Permission denied] Tool ${call.name} is blocked by networkPolicy${reason}. Do not retry.`,
14092
- isError: true
14093
- };
14050
+ if (gate.kind === "denied") {
14051
+ if (gate.source === "auto-mode") recordRecentlyDeniedAutoAction(call, gate.classification);
14052
+ this.sendToolCallResult(call, gate.message, true);
14053
+ return { callId: call.id, content: gate.message, isError: true };
14094
14054
  }
14095
- if (permission.action === "deny") {
14096
- const reason = permission.reason ? ` (${permission.reason})` : "";
14097
- return {
14098
- callId: call.id,
14099
- content: `[Permission denied] Tool ${call.name} is blocked by permission profile "${permission.profileName}"${reason}. Do not retry.`,
14100
- isError: true
14101
- };
14102
- }
14103
- if (permission.action === "auto-approve" && networkPermission?.action !== "confirm") {
14104
- this.sendToolCallStart(call);
14105
- try {
14106
- const rawContent = await runTool(tool, call.arguments, call.name);
14107
- const content = truncateOutput(rawContent, call.name);
14108
- this.sendToolCallResult(call, rawContent, false);
14109
- runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "ok" });
14110
- runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
14111
- return { callId: call.id, content, isError: false };
14112
- } catch (err) {
14113
- const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
14114
- this.sendToolCallResult(call, message, true);
14115
- runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
14116
- runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
14117
- return { callId: call.id, content: message, isError: true };
14118
- }
14119
- }
14120
- const requiresHardConfirmation = permission.action === "confirm" && permission.hardBoundary === true;
14121
- if ((networkPermission?.action === "confirm" || requiresHardConfirmation) && dangerLevel === "safe") {
14122
- this.sendToolCallStart(call);
14123
- toolCallStarted = true;
14124
- const confirmed = await this.confirm(call, "write");
14125
- if (!confirmed) {
14126
- const rejectionMsg = `[User cancelled] The user declined permission for ${call.name}. Do not retry without asking.`;
14127
- this.sendToolCallResult(call, rejectionMsg, true);
14128
- return { callId: call.id, content: rejectionMsg, isError: true };
14129
- }
14130
- }
14131
- if (!toolCallStarted) this.sendToolCallStart(call);
14132
- if (this.sessionAutoMode && networkPermission?.action !== "confirm") {
14133
- const classification = defaultActionClassifier.classify(call, dangerLevel, {
14134
- workspaceRoot: this.workspaceRoot,
14135
- tempDirs: [tmpdir2()]
14136
- });
14137
- if (classification.decision === "deny") {
14138
- recordRecentlyDeniedAutoAction(call, classification);
14139
- const rejectionMsg = `[Auto denied] ${classification.reason}. Do not retry without asking.`;
14140
- this.sendToolCallResult(call, rejectionMsg, true);
14141
- return { callId: call.id, content: rejectionMsg, isError: true };
14055
+ if (gate.kind === "confirm") {
14056
+ if (!toolCallStarted) {
14057
+ this.sendToolCallStart(call);
14058
+ toolCallStarted = true;
14142
14059
  }
14143
- if (classification.decision === "auto-approve" && !requiresHardConfirmation) {
14144
- this.send({ type: "info", message: `\u26A1 Auto-approved (/auto: ${classification.ruleId})` });
14145
- try {
14146
- const rawContent = await runTool(tool, call.arguments, call.name);
14147
- const content = truncateOutput(rawContent, call.name);
14148
- this.sendToolCallResult(call, rawContent, false);
14149
- runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "ok" });
14150
- runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
14151
- return { callId: call.id, content, isError: false };
14152
- } catch (err) {
14153
- const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
14154
- this.sendToolCallResult(call, message, true);
14155
- runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
14156
- runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
14157
- return { callId: call.id, content: message, isError: true };
14158
- }
14159
- }
14160
- }
14161
- if (this.sessionAutoApprove && dangerLevel === "write" && !requiresHardConfirmation) {
14162
- try {
14163
- const rawContent = await runTool(tool, call.arguments, call.name);
14164
- const content = truncateOutput(rawContent, call.name);
14165
- this.sendToolCallResult(call, rawContent, false);
14166
- runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "ok" });
14167
- runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
14168
- return { callId: call.id, content, isError: false };
14169
- } catch (err) {
14170
- const message = err instanceof Error ? err.message : err && typeof err === "object" && "message" in err ? String(err.message) : String(err);
14171
- this.sendToolCallResult(call, message, true);
14172
- runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
14173
- runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
14174
- return { callId: call.id, content: message, isError: true };
14175
- }
14176
- }
14177
- if (dangerLevel === "write" || dangerLevel === "destructive") {
14178
- const confirmed = await this.confirm(call, dangerLevel);
14060
+ const confirmed = await this.confirm(call, gate.level);
14179
14061
  if (!confirmed) {
14180
- const label = dangerLevel === "destructive" ? "destructive " : "";
14181
- const rejectionMsg = `[User cancelled] The user declined the ${label}${call.name} operation. Do not retry without asking.`;
14062
+ const rejectionMsg = gate.source === "permission" ? gateMessages.permissionCancelled(call.name) : gateMessages.operationCancelled(call.name, gate.level);
14182
14063
  this.sendToolCallResult(call, rejectionMsg, true);
14183
14064
  return { callId: call.id, content: rejectionMsg, isError: true };
14184
14065
  }
14185
14066
  }
14067
+ if (!toolCallStarted) this.sendToolCallStart(call);
14186
14068
  try {
14187
14069
  const rawContent = await runTool(tool, call.arguments, call.name);
14188
14070
  const content = truncateOutput(rawContent, call.name);
@@ -16997,7 +16879,7 @@ Cache: write=${cacheCreate} read=${cacheRead}` : "";
16997
16879
  Cost: ${formatCost(cost)}` : "";
16998
16880
  let memoryLine = "";
16999
16881
  try {
17000
- const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-3N2XQKJK.js");
16882
+ const { countPendingMemories: countPendingMemories2 } = await import("./persistent-memory-LFE3YHZO.js");
17001
16883
  const pending = countPendingMemories2(ctx.config.getConfigDir());
17002
16884
  if (pending > 0) memoryLine = `
17003
16885
  Memory: \u26A0 ${pending} pending approval \u2014 see the Memory panel or /memory`;
@@ -17980,7 +17862,7 @@ async function handleTest(args, ctx) {
17980
17862
  const isCommand = argStr.includes(" ") || /^(mvn|gradle|npm|pytest|cargo|go)\b/.test(argStr);
17981
17863
  testArgs = isCommand ? { command: argStr } : { filter: argStr };
17982
17864
  }
17983
- const runTests = ctx.runTests ?? (await import("./run-tests-3ZOMRFIX.js")).executeTests;
17865
+ const runTests = ctx.runTests ?? (await import("./run-tests-R3JB4UEI.js")).executeTests;
17984
17866
  const report = await runTests(testArgs);
17985
17867
  ctx.send({ type: "info", message: report });
17986
17868
  } catch (err) {
@@ -18370,7 +18252,7 @@ async function handleMemory(args, ctx) {
18370
18252
  }
18371
18253
  if (intent.kind === "status") {
18372
18254
  const { getChatIndexStatus: getChatIndexStatus2 } = await import("./chat-index-DGUOUUQW.js");
18373
- const { listMemoryEntries: listMemoryEntries2, isMemoryExpired: isMemoryExpired2, formatMemoryForPrompt: formatMemoryForPrompt2 } = await import("./persistent-memory-3N2XQKJK.js");
18255
+ const { listMemoryEntries: listMemoryEntries2, isMemoryExpired: isMemoryExpired2, formatMemoryForPrompt: formatMemoryForPrompt2 } = await import("./persistent-memory-LFE3YHZO.js");
18374
18256
  const memories = listMemoryEntries2(configDir, { includeExpired: true, includeRejected: true });
18375
18257
  const injected = formatMemoryForPrompt2(configDir, process.cwd(), ctx.config.get("memory")?.maxChars);
18376
18258
  const view = buildMemoryStatusView({
@@ -18393,7 +18275,7 @@ async function handleMemory(args, ctx) {
18393
18275
  return;
18394
18276
  }
18395
18277
  if (intent.kind === "recall") {
18396
- const { searchPersistentMemories: searchPersistentMemories2, touchMemoryReferences: touchMemoryReferences2 } = await import("./persistent-memory-3N2XQKJK.js");
18278
+ const { searchPersistentMemories: searchPersistentMemories2, touchMemoryReferences: touchMemoryReferences2 } = await import("./persistent-memory-LFE3YHZO.js");
18397
18279
  const { searchChatMemory: searchChatMemory2 } = await import("./chat-index-DGUOUUQW.js");
18398
18280
  const persistentHits = searchPersistentMemories2(configDir, intent.query, process.cwd(), 3);
18399
18281
  if (persistentHits.length > 0) {
@@ -18514,7 +18396,7 @@ async function handleMemory(args, ctx) {
18514
18396
  ctx.handleMemoryManage(intent.action, args[1], intent.action === "expire" ? args[2] : void 0);
18515
18397
  } else if (intent.kind === "export") {
18516
18398
  if (args[1] === "md") {
18517
- const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-3N2XQKJK.js");
18399
+ const { exportMemoryEntries: exportMemoryEntries2 } = await import("./persistent-memory-LFE3YHZO.js");
18518
18400
  ctx.send({
18519
18401
  type: "export_data",
18520
18402
  format: "md",
@@ -19519,7 +19401,7 @@ No tools match "${filter}".
19519
19401
  const { join: join29 } = await import("path");
19520
19402
  const { existsSync: existsSync33 } = await import("fs");
19521
19403
  const { getGitRoot: getGitRoot2 } = await import("./git-context-VNCA2GU7.js");
19522
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-SRRV3K5Y.js");
19404
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-JQP6BENR.js");
19523
19405
  const { approveProject, hashMcpFile } = await import("./project-trust-MUG325AW.js");
19524
19406
  const cwd = process.cwd();
19525
19407
  const projectRoot = getGitRoot2(cwd) ?? cwd;
@@ -20434,7 +20316,7 @@ function createReviewCommands() {
20434
20316
  usage: "/test [command|filter]",
20435
20317
  async execute(args, ctx) {
20436
20318
  try {
20437
- const { executeTests } = await import("./run-tests-3ZOMRFIX.js");
20319
+ const { executeTests } = await import("./run-tests-R3JB4UEI.js");
20438
20320
  const argStr = args.join(" ").trim();
20439
20321
  let testArgs = {};
20440
20322
  if (argStr) {
@@ -158,7 +158,7 @@ ${content}`);
158
158
  }
159
159
  }
160
160
  async function runTaskMode(config, providers, configManager, topic) {
161
- const { TaskOrchestrator } = await import("./task-orchestrator-6TVKJYKC.js");
161
+ const { TaskOrchestrator } = await import("./task-orchestrator-6HH3KQUQ.js");
162
162
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
163
163
  let interrupted = false;
164
164
  const onSigint = () => {
package/dist/index.js CHANGED
@@ -24,7 +24,7 @@ import {
24
24
  setupProxy,
25
25
  snapshotFile,
26
26
  stripRoutingTags
27
- } from "./chunk-HNUT4STJ.js";
27
+ } from "./chunk-NJDQCQ7P.js";
28
28
  import {
29
29
  CostTracker,
30
30
  getPricing,
@@ -49,7 +49,7 @@ import {
49
49
  setMaxOutputCap,
50
50
  spawnAgentContext,
51
51
  undoStack
52
- } from "./chunk-AXSWLNCU.js";
52
+ } from "./chunk-37WBQV3E.js";
53
53
  import "./chunk-HLWUDRBO.js";
54
54
  import {
55
55
  NO_THINKING,
@@ -62,7 +62,7 @@ import {
62
62
  countPendingMemories,
63
63
  detectStaleLegacyMarkdownEdit,
64
64
  formatMemoryForPrompt
65
- } from "./chunk-ERDFOXYK.js";
65
+ } from "./chunk-JBNNJ32H.js";
66
66
  import "./chunk-4DEMGCK4.js";
67
67
  import "./chunk-UUSRWSSX.js";
68
68
  import "./chunk-CKH4KQ4E.js";
@@ -83,14 +83,14 @@ import {
83
83
  import {
84
84
  loadContextFiles,
85
85
  writeCrashLog
86
- } from "./chunk-EU6NMK7G.js";
86
+ } from "./chunk-C5UAM4X7.js";
87
87
  import {
88
88
  getActivePluginAssets,
89
89
  getPendingHookTrust,
90
90
  installFlushOnExit,
91
91
  mergePluginHooks,
92
92
  runLifecycleHooks
93
- } from "./chunk-HEUB5PV6.js";
93
+ } from "./chunk-5G6HX57U.js";
94
94
  import "./chunk-RS7SKYTS.js";
95
95
  import {
96
96
  ProviderRegistry,
@@ -98,7 +98,7 @@ import {
98
98
  } from "./chunk-ALSSNFNK.js";
99
99
  import {
100
100
  ConfigManager
101
- } from "./chunk-5F7BGV72.js";
101
+ } from "./chunk-7RC7AN6V.js";
102
102
  import {
103
103
  CONTENT_ONLY_STREAM_REMINDER,
104
104
  TEE_FINAL_USER_NUDGE,
@@ -132,7 +132,7 @@ import {
132
132
  } from "./chunk-IW3Q7AE5.js";
133
133
  import "./chunk-XNFIYS7G.js";
134
134
  import "./chunk-4BKXL7SM.js";
135
- import "./chunk-L7RAEUUN.js";
135
+ import "./chunk-6NEEFOVF.js";
136
136
  import {
137
137
  AGENTIC_BEHAVIOR_GUIDELINE,
138
138
  AUTHOR,
@@ -149,7 +149,7 @@ import {
149
149
  SKILLS_DIR_NAME,
150
150
  VERSION,
151
151
  buildUserIdentityPrompt
152
- } from "./chunk-UDFK5Q52.js";
152
+ } from "./chunk-O4CZPTPU.js";
153
153
 
154
154
  // src/index.ts
155
155
  import { program } from "commander";
@@ -3990,7 +3990,7 @@ program.command("web").description("Start Web UI server with browser-based chat
3990
3990
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
3991
3991
  process.exit(1);
3992
3992
  }
3993
- const { startWebServer } = await import("./server-XWURZCAF.js");
3993
+ const { startWebServer } = await import("./server-I6DXVJRO.js");
3994
3994
  await startWebServer({ port, host: options.host });
3995
3995
  });
3996
3996
  program.command("user [action] [username]").description("Manage Web UI users (list | create <name> | delete <name> | reset-password <name> | logout-all <name> | migrate <name>)").action(async (action, username) => {
@@ -4157,11 +4157,11 @@ program.command("sessions").description("List recent conversation sessions").opt
4157
4157
  console.log(footer + "\n");
4158
4158
  });
4159
4159
  program.command("usage").description("Show token + cost usage grouped by provider/model (cross-session)").option("--days <n>", "Only the last N days (inclusive of today)").option("--month <ym>", "Only a specific month, format YYYY-MM (e.g. 2026-06)").option("--json", "Output as JSON (for scripting)").action(async (options) => {
4160
- const { runUsageCli } = await import("./usage-L2PSI2KH.js");
4160
+ const { runUsageCli } = await import("./usage-UB4ZT5PE.js");
4161
4161
  await runUsageCli(options);
4162
4162
  });
4163
4163
  program.command("doctor").description("Health check: API keys, config, MCP, recent crashes, tool usage, disk usage").option("--json", "Output as JSON (for scripting)").option("--reset-stats", "Reset accumulated tool usage statistics").action(async (options) => {
4164
- const { runDoctorCli } = await import("./doctor-cli-LQYTDJ74.js");
4164
+ const { runDoctorCli } = await import("./doctor-cli-CVOE7FAE.js");
4165
4165
  const argv = process.argv.slice(2);
4166
4166
  await runDoctorCli({
4167
4167
  json: !!options.json || argv.includes("--json"),
@@ -4170,7 +4170,7 @@ program.command("doctor").description("Health check: API keys, config, MCP, rece
4170
4170
  });
4171
4171
  program.command("batch <action> [arg] [arg2]").description("Anthropic Message Batches: submit | list | status <id> | results <id> [out] | cancel <id>").option("--dry-run", "Parse and validate input without submitting (submit only)").action(async (action, arg, arg2, options) => {
4172
4172
  try {
4173
- const batch = await import("./batch-6OH7D5YU.js");
4173
+ const batch = await import("./batch-YAEXKK2C.js");
4174
4174
  switch (action) {
4175
4175
  case "submit":
4176
4176
  if (!arg) {
@@ -4213,7 +4213,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
4213
4213
  }
4214
4214
  });
4215
4215
  program.command("mcp-serve").description("Start an MCP server over STDIO, exposing aicli's built-in tools to Claude Desktop / Cursor / other MCP clients").option("--allow-destructive", "Allow bash / run_interactive / task_create (always destructive in MCP mode)").option("--allow-outside-cwd", "Allow tool path arguments to escape the sandbox root \u2014 disabled by default").option("--tools <list>", "Comma-separated whitelist of tools to expose (default: all eligible tools)").option("--cwd <path>", "Working directory AND sandbox root (default: current directory)").action(async (options) => {
4216
- const { startMcpServer } = await import("./server-L4QHJT2I.js");
4216
+ const { startMcpServer } = await import("./server-THHSJRNI.js");
4217
4217
  await startMcpServer({
4218
4218
  allowDestructive: !!options.allowDestructive,
4219
4219
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -4226,7 +4226,7 @@ program.command("pr <action> [target]").description("PR review helpers: review |
4226
4226
  console.error(`Unknown pr action: ${action}. Use review | security-review | summarize.`);
4227
4227
  process.exit(1);
4228
4228
  }
4229
- const { runPrCli } = await import("./pr-L7Y3XHGL.js");
4229
+ const { runPrCli } = await import("./pr-3QAG7XO7.js");
4230
4230
  const result = await runPrCli({
4231
4231
  action,
4232
4232
  target,
@@ -4246,8 +4246,8 @@ program.command("pr <action> [target]").description("PR review helpers: review |
4246
4246
  process.exit(result.exitCode);
4247
4247
  });
4248
4248
  program.command("ci").description("Headless PR review (code + security) \u2014 reads git/gh diff, optionally posts to PR. Designed for GitHub Actions.").option("--pr <num>", "PR number or URL; diff fetched via gh pr diff <value>", (v) => /^#?\d+$/.test(v) ? parseInt(v.replace(/^#/, ""), 10) : v).option("--base <ref>", "Base ref for git diff <ref>...HEAD (ignored when --pr set)").option("--post", "Post review as a PR comment (requires gh CLI + GH_TOKEN, needs --pr)").option("--no-update", "Always create a new comment instead of updating the previous aicli review").option("--skip-code", "Skip the code review section").option("--skip-security", "Skip the security review section").option("--detailed", "Use the detailed code-review prompt").option("--max-diff <n>", "Max diff chars sent to the model (default 30000)", (v) => parseInt(v, 10)).option("--provider <id>", "Override provider (default: config.defaultProvider)").option("--model <id>", "Override model").option("--dry-run", "Print result to stdout instead of posting (overrides --post)").option("--json", "Output a structured JSON report").option("--markdown", "Output Markdown report (default)").option("--sarif", "Output SARIF 2.1.0 for code scanning artifacts").option("--fail-on-security-high", "Fail when the security review contains HIGH/CRITICAL findings (default)").option("--no-fail-on-security-high", "Do not fail on security HIGH/CRITICAL findings").option("--fail-on-test-failure", "Fail when the report mentions test failures (default)").option("--no-fail-on-test-failure", "Do not fail on test failure findings").option("--fail-on-lint-failure", "Fail when the report mentions lint/typecheck failures (default)").option("--no-fail-on-lint-failure", "Do not fail on lint/typecheck failure findings").action(async (options) => {
4249
- const { runCi } = await import("./ci-WXCMI4ND.js");
4250
- const { formatCiResult } = await import("./ci-format-JXD2BQM6.js");
4249
+ const { runCi } = await import("./ci-RO2NLIRH.js");
4250
+ const { formatCiResult } = await import("./ci-format-GBSRK2J4.js");
4251
4251
  const formats = [options.json, options.markdown, options.sarif].filter(Boolean).length;
4252
4252
  if (formats > 1) {
4253
4253
  console.error("Choose only one output format: --json, --markdown, or --sarif.");
@@ -4405,7 +4405,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
4405
4405
  config.get("customProviders"),
4406
4406
  config.getConfigDir()
4407
4407
  );
4408
- const { startHub } = await import("./hub-Y62P5MIA.js");
4408
+ const { startHub } = await import("./hub-LFWL5PGH.js");
4409
4409
  await startHub(
4410
4410
  {
4411
4411
  topic: topic ?? "",
@@ -28,11 +28,11 @@ import {
28
28
  touchMemoryReferences,
29
29
  updateMemoryApproval,
30
30
  updateMemoryEntry
31
- } from "./chunk-ERDFOXYK.js";
31
+ } from "./chunk-JBNNJ32H.js";
32
32
  import "./chunk-3FEZSLGI.js";
33
33
  import "./chunk-HOSJZMQS.js";
34
34
  import "./chunk-IW3Q7AE5.js";
35
- import "./chunk-UDFK5Q52.js";
35
+ import "./chunk-O4CZPTPU.js";
36
36
  export {
37
37
  addMemoryEntry,
38
38
  backupMemoryStore,