jinzd-ai-cli 0.4.212 → 0.4.214

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.
@@ -154,7 +154,7 @@ ${content}`);
154
154
  }
155
155
  }
156
156
  async function runTaskMode(config, providers, configManager, topic) {
157
- const { TaskOrchestrator } = await import("./task-orchestrator-AL2E642M.js");
157
+ const { TaskOrchestrator } = await import("./task-orchestrator-6AZD5WSR.js");
158
158
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
159
159
  let interrupted = false;
160
160
  const onSigint = () => {
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  scanProject,
16
16
  sessionHasMeaningfulContent,
17
17
  setupProxy
18
- } from "./chunk-HW2ALWQJ.js";
18
+ } from "./chunk-5FG7PSVM.js";
19
19
  import {
20
20
  buildReviewPrompt,
21
21
  buildSecurityReviewPrompt
@@ -25,9 +25,11 @@ import {
25
25
  ToolRegistry,
26
26
  askUserContext,
27
27
  cleanupRejectedTeeFile,
28
+ clearRecentlyDeniedAutoActions,
28
29
  estimateTokens,
29
30
  formatPermissionProfileWarning,
30
31
  getPendingHookTrust,
32
+ getRecentlyDeniedAutoActions,
31
33
  googleSearchContext,
32
34
  initTheme,
33
35
  isInterrupted,
@@ -45,10 +47,10 @@ import {
45
47
  trustHook,
46
48
  undoStack,
47
49
  untrustHook
48
- } from "./chunk-N5LB3PPL.js";
50
+ } from "./chunk-R5CJD2AB.js";
49
51
  import "./chunk-T2NL5ZIA.js";
50
52
  import "./chunk-BXP6YZ2P.js";
51
- import "./chunk-HX6N6QEY.js";
53
+ import "./chunk-TR6MSPSS.js";
52
54
  import {
53
55
  SessionManager,
54
56
  getContentText
@@ -65,7 +67,7 @@ import {
65
67
  getConfigDirUsage,
66
68
  listRecentCrashes,
67
69
  writeCrashLog
68
- } from "./chunk-LU6FBJQ5.js";
70
+ } from "./chunk-JQC7IATA.js";
69
71
  import {
70
72
  ProviderRegistry
71
73
  } from "./chunk-QMXC327F.js";
@@ -74,7 +76,7 @@ import {
74
76
  getTopFailingTools,
75
77
  getTopUsedTools,
76
78
  installFlushOnExit
77
- } from "./chunk-IFZX26K7.js";
79
+ } from "./chunk-YMFGGCUP.js";
78
80
  import {
79
81
  CONTENT_ONLY_STREAM_REMINDER,
80
82
  TEE_FINAL_USER_NUDGE,
@@ -96,7 +98,7 @@ import {
96
98
  } from "./chunk-XPBEJB27.js";
97
99
  import {
98
100
  ConfigManager
99
- } from "./chunk-NYCBOVNF.js";
101
+ } from "./chunk-YFHF3PVB.js";
100
102
  import {
101
103
  AuthError,
102
104
  ProviderError,
@@ -122,7 +124,7 @@ import {
122
124
  SKILLS_DIR_NAME,
123
125
  VERSION,
124
126
  buildUserIdentityPrompt
125
- } from "./chunk-GBBVCZ4W.js";
127
+ } from "./chunk-DBYMX2ZC.js";
126
128
  import {
127
129
  formatGitContextForPrompt,
128
130
  getGitContext,
@@ -879,7 +881,9 @@ function createDefaultCommands() {
879
881
  ["/route [on|off|show|test <msg>]", "Smart model routing rules"],
880
882
  ["/think [on|off|status]", "Toggle Extended Thinking (deep reasoning)"],
881
883
  ["/plan [execute|exit|status]", "Enter/manage Plan Mode (read-only)"],
882
- ["/yolo [on|off]", "Toggle session auto-approve (skip confirmations)"]
884
+ ["/auto [on|off|status]", "Rule-based low-risk auto approval"],
885
+ ["/permissions recently-denied|clear-denied", "Inspect permission and Auto Mode decisions"],
886
+ ["/yolo [on|off]", "Toggle write auto-approve (destructive still confirms)"]
883
887
  ]
884
888
  },
885
889
  {
@@ -1362,6 +1366,7 @@ No commands match "${filter}".
1362
1366
  console.log(` Ctx Win : ${ctxStr}`);
1363
1367
  console.log(" PermProf : " + (ctx.config.get("defaultPermissionProfile") ?? "legacy"));
1364
1368
  console.log(" Network : " + (ctx.config.get("networkPolicy")?.enabled ?? false ? "on" : "off"));
1369
+ console.log(" AutoMode : " + (ctx.getToolExecutor().sessionAutoMode ? "on" : "off"));
1365
1370
  console.log(" Hooks : " + getPendingHookTrust(ctx.config.get("hooks") ?? void 0, ctx.config.getConfigDir()).length + " pending trust");
1366
1371
  console.log(` Messages : ${session?.messages.length ?? 0}`);
1367
1372
  console.log(` Session : ${session?.id.slice(0, 8) ?? "none"}`);
@@ -1656,7 +1661,7 @@ No tools match "${filter}".
1656
1661
  const { join: join5 } = await import("path");
1657
1662
  const { existsSync: existsSync5 } = await import("fs");
1658
1663
  const { getGitRoot: getGitRoot2 } = await import("./git-context-EXOEHQSF.js");
1659
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-KDWG4KR4.js");
1664
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-BKR7T3QH.js");
1660
1665
  const { approveProject, hashMcpFile } = await import("./project-trust-NKYHL3VZ.js");
1661
1666
  const cwd = process.cwd();
1662
1667
  const projectRoot = getGitRoot2(cwd) ?? cwd;
@@ -2715,7 +2720,7 @@ ${hint}` : "")
2715
2720
  usage: "/test [command|filter]",
2716
2721
  async execute(args, ctx) {
2717
2722
  try {
2718
- const { executeTests } = await import("./run-tests-H4Q2PRX6.js");
2723
+ const { executeTests } = await import("./run-tests-F44JA2YW.js");
2719
2724
  const argStr = args.join(" ").trim();
2720
2725
  let testArgs = {};
2721
2726
  if (argStr) {
@@ -3378,6 +3383,7 @@ Summary: ${fileMap.size} file(s) \u2014 ${newFiles} new, ${modifiedFiles} modifi
3378
3383
  console.log(` mode : ${security.mode}`);
3379
3384
  console.log(" profile : " + (ctx.config.get("defaultPermissionProfile") ?? "legacy"));
3380
3385
  console.log(" network : " + (ctx.config.get("networkPolicy")?.enabled ?? false ? "on" : "off"));
3386
+ console.log(" autoMode : " + (ctx.getToolExecutor().sessionAutoMode ? "on" : "off"));
3381
3387
  console.log(" hooks : " + getPendingHookTrust(ctx.config.get("hooks") ?? void 0, ctx.config.getConfigDir()).length + " pending trust");
3382
3388
  console.log(` patterns : ${DEFAULT_PATTERNS.length} built-in + ${security.customPatterns?.length ?? 0} custom`);
3383
3389
  console.log(` last save : ${ctx.sessions.lastRedactionHits} hit(s) redacted`);
@@ -3450,9 +3456,64 @@ Summary: ${fileMap.size} file(s) \u2014 ${newFiles} new, ${modifiedFiles} modifi
3450
3456
  console.log();
3451
3457
  }
3452
3458
  },
3459
+ {
3460
+ name: "auto",
3461
+ description: "Toggle rule-based Auto Mode for low-risk actions",
3462
+ usage: "/auto [on|off|status]",
3463
+ execute(args, ctx) {
3464
+ const sub = args[0]?.toLowerCase() ?? "status";
3465
+ const executor = ctx.getToolExecutor();
3466
+ if (sub === "on") {
3467
+ executor.sessionAutoMode = true;
3468
+ console.log(theme.warning(" \u26A1 Auto Mode ON \u2014 low-risk actions may auto-run; high-risk actions still confirm or deny."));
3469
+ console.log(theme.dim(" Auto Mode is session-scoped and is not enabled by project config."));
3470
+ } else if (sub === "off") {
3471
+ executor.sessionAutoMode = false;
3472
+ console.log(theme.info(" Auto Mode disabled."));
3473
+ } else if (sub === "status") {
3474
+ console.log(` Auto Mode : ${executor.sessionAutoMode ? theme.warning("on") : theme.dim("off")}`);
3475
+ console.log(theme.dim(" Scope : current session only"));
3476
+ console.log(theme.dim(" Denied : /permissions recently-denied"));
3477
+ } else {
3478
+ console.log(theme.warning(" Usage: /auto [on|off|status]"));
3479
+ }
3480
+ console.log();
3481
+ }
3482
+ },
3483
+ {
3484
+ name: "permissions",
3485
+ description: "Inspect permission and Auto Mode decisions",
3486
+ usage: "/permissions recently-denied|clear-denied",
3487
+ execute(args) {
3488
+ const sub = args[0]?.toLowerCase() ?? "recently-denied";
3489
+ if (sub === "recently-denied") {
3490
+ const rows = getRecentlyDeniedAutoActions();
3491
+ if (rows.length === 0) {
3492
+ console.log(theme.success(" No recently denied Auto Mode actions."));
3493
+ } else {
3494
+ console.log(theme.warning(` Recently denied Auto Mode actions (${rows.length})`));
3495
+ for (const r of rows.slice(0, 20)) {
3496
+ console.log(` - ${r.timestamp} ${theme.error(r.tool)} ${theme.dim(r.ruleId)}`);
3497
+ console.log(` ${r.reason}`);
3498
+ console.log(theme.dim(` ${r.argsPreview}`));
3499
+ }
3500
+ }
3501
+ console.log();
3502
+ return;
3503
+ }
3504
+ if (sub === "clear-denied") {
3505
+ clearRecentlyDeniedAutoActions();
3506
+ console.log(theme.info(" Cleared recently denied Auto Mode actions."));
3507
+ console.log();
3508
+ return;
3509
+ }
3510
+ console.log(theme.warning(" Usage: /permissions recently-denied|clear-denied"));
3511
+ console.log();
3512
+ }
3513
+ },
3453
3514
  {
3454
3515
  name: "yolo",
3455
- description: "Toggle session auto-approve (skip all confirmations)",
3516
+ description: "Toggle session auto-approve for write tools (/yolo)",
3456
3517
  usage: "/yolo [on|off]",
3457
3518
  execute(args, ctx) {
3458
3519
  const sub = args[0]?.toLowerCase();
@@ -6399,6 +6460,7 @@ ${systemPromptVolatile}` : systemPrompt;
6399
6460
  ${systemPromptVolatile}` : systemPrompt;
6400
6461
  spawnAgentContext.modelParams = modelParams;
6401
6462
  spawnAgentContext.configManager = this.config;
6463
+ spawnAgentContext.providers = this.providers;
6402
6464
  ToolExecutor.currentMessageIndex = session.messages.length;
6403
6465
  return this.toolExecutor.executeAll(toolCalls);
6404
6466
  },
@@ -7145,7 +7207,7 @@ program.command("web").description("Start Web UI server with browser-based chat
7145
7207
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
7146
7208
  process.exit(1);
7147
7209
  }
7148
- const { startWebServer } = await import("./server-VNCN7AY5.js");
7210
+ const { startWebServer } = await import("./server-FXWCSCDZ.js");
7149
7211
  await startWebServer({ port, host: options.host });
7150
7212
  });
7151
7213
  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) => {
@@ -7312,16 +7374,16 @@ program.command("sessions").description("List recent conversation sessions").opt
7312
7374
  console.log(footer + "\n");
7313
7375
  });
7314
7376
  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) => {
7315
- const { runUsageCli } = await import("./usage-LB6REWPO.js");
7377
+ const { runUsageCli } = await import("./usage-W7J2QA3G.js");
7316
7378
  await runUsageCli(options);
7317
7379
  });
7318
7380
  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) => {
7319
- const { runDoctorCli } = await import("./doctor-cli-TJTWIW7U.js");
7381
+ const { runDoctorCli } = await import("./doctor-cli-TGVSWKDB.js");
7320
7382
  await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
7321
7383
  });
7322
7384
  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) => {
7323
7385
  try {
7324
- const batch = await import("./batch-WIKFEOAZ.js");
7386
+ const batch = await import("./batch-NPUUDETK.js");
7325
7387
  switch (action) {
7326
7388
  case "submit":
7327
7389
  if (!arg) {
@@ -7364,7 +7426,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
7364
7426
  }
7365
7427
  });
7366
7428
  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) => {
7367
- const { startMcpServer } = await import("./server-OFKGDRYI.js");
7429
+ const { startMcpServer } = await import("./server-GQXC46R5.js");
7368
7430
  await startMcpServer({
7369
7431
  allowDestructive: !!options.allowDestructive,
7370
7432
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -7373,7 +7435,7 @@ program.command("mcp-serve").description("Start an MCP server over STDIO, exposi
7373
7435
  });
7374
7436
  });
7375
7437
  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; diff fetched via `gh pr diff <num>`", (v) => parseInt(v, 10)).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)").action(async (options) => {
7376
- const { runCi } = await import("./ci-X3LNUFZV.js");
7438
+ const { runCi } = await import("./ci-3TU7WCY4.js");
7377
7439
  const result = await runCi({
7378
7440
  pr: options.pr,
7379
7441
  base: options.base,
@@ -7519,7 +7581,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
7519
7581
  }),
7520
7582
  config.get("customProviders")
7521
7583
  );
7522
- const { startHub } = await import("./hub-JWSV4MKC.js");
7584
+ const { startHub } = await import("./hub-GURYEW6F.js");
7523
7585
  await startHub(
7524
7586
  {
7525
7587
  topic: topic ?? "",
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-HX6N6QEY.js";
6
- import "./chunk-GBBVCZ4W.js";
5
+ } from "./chunk-TR6MSPSS.js";
6
+ import "./chunk-DBYMX2ZC.js";
7
7
  export {
8
8
  executeTests,
9
9
  runTestsTool
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  executeTests,
3
3
  runTestsTool
4
- } from "./chunk-KE4B3NOQ.js";
4
+ } from "./chunk-JOJA35RK.js";
5
5
  export {
6
6
  executeTests,
7
7
  runTestsTool
@@ -24,7 +24,7 @@ import {
24
24
  scanDirTree,
25
25
  scanProject,
26
26
  setupProxy
27
- } from "./chunk-HW2ALWQJ.js";
27
+ } from "./chunk-5FG7PSVM.js";
28
28
  import {
29
29
  buildReviewPrompt,
30
30
  buildSecurityReviewPrompt
@@ -36,25 +36,35 @@ import {
36
36
  checkNetworkPolicy,
37
37
  checkPermissionWithProfile,
38
38
  cleanupRejectedTeeFile,
39
+ clearRecentlyDeniedAutoActions,
40
+ defaultActionClassifier,
39
41
  estimateTokens,
40
42
  formatPermissionProfileWarning,
41
43
  getPendingHookTrust,
44
+ getPreferredAgentName,
45
+ getRecentlyDeniedAutoActions,
42
46
  googleSearchContext,
43
47
  groupCallsByPhase,
48
+ listAgentConfigs,
49
+ listAgentRuns,
50
+ recordRecentlyDeniedAutoAction,
44
51
  renderDiff,
52
+ requestAgentStop,
53
+ resolveAgentConfig,
45
54
  runHook,
46
55
  runLifecycleHooks,
47
56
  runSafePhases,
48
57
  runWithSessionKey,
49
58
  setContextWindow,
50
59
  setMaxOutputCap,
60
+ setPreferredAgentName,
51
61
  spawnAgentContext,
52
62
  truncateOutput,
53
63
  undoStack
54
- } from "./chunk-N5LB3PPL.js";
64
+ } from "./chunk-R5CJD2AB.js";
55
65
  import "./chunk-T2NL5ZIA.js";
56
66
  import "./chunk-BXP6YZ2P.js";
57
- import "./chunk-HX6N6QEY.js";
67
+ import "./chunk-TR6MSPSS.js";
58
68
  import {
59
69
  SessionManager,
60
70
  getContentText
@@ -68,7 +78,7 @@ import {
68
78
  } from "./chunk-QMXC327F.js";
69
79
  import {
70
80
  runTool
71
- } from "./chunk-IFZX26K7.js";
81
+ } from "./chunk-YMFGGCUP.js";
72
82
  import {
73
83
  CONTENT_ONLY_STREAM_REMINDER,
74
84
  TEE_FINAL_USER_NUDGE,
@@ -87,7 +97,7 @@ import {
87
97
  } from "./chunk-XPBEJB27.js";
88
98
  import {
89
99
  ConfigManager
90
- } from "./chunk-NYCBOVNF.js";
100
+ } from "./chunk-YFHF3PVB.js";
91
101
  import "./chunk-TZQHYZKT.js";
92
102
  import {
93
103
  AGENTIC_BEHAVIOR_GUIDELINE,
@@ -106,7 +116,7 @@ import {
106
116
  SKILLS_DIR_NAME,
107
117
  VERSION,
108
118
  buildUserIdentityPrompt
109
- } from "./chunk-GBBVCZ4W.js";
119
+ } from "./chunk-DBYMX2ZC.js";
110
120
  import {
111
121
  formatGitContextForPrompt,
112
122
  getGitContext,
@@ -164,6 +174,8 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
164
174
  confirming = false;
165
175
  /** Session-level auto-approve toggle (/yolo command) */
166
176
  sessionAutoApprove = false;
177
+ /** Session-level Auto Mode: rule-based low-risk auto approval. */
178
+ sessionAutoMode = false;
167
179
  /** Track tool start times for duration calculation */
168
180
  toolStartTimes = /* @__PURE__ */ new Map();
169
181
  /**
@@ -441,6 +453,35 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
441
453
  }
442
454
  }
443
455
  this.sendToolCallStart(call);
456
+ if (this.sessionAutoMode && networkPermission?.action !== "confirm") {
457
+ const classification = defaultActionClassifier.classify(call, dangerLevel, {
458
+ workspaceRoot: this.workspaceRoot,
459
+ tempDirs: [tmpdir()]
460
+ });
461
+ if (classification.decision === "deny") {
462
+ recordRecentlyDeniedAutoAction(call, classification);
463
+ const rejectionMsg = `[Auto denied] ${classification.reason}. Do not retry without asking.`;
464
+ this.sendToolCallResult(call, rejectionMsg, true);
465
+ return { callId: call.id, content: rejectionMsg, isError: true };
466
+ }
467
+ if (classification.decision === "auto-approve") {
468
+ this.send({ type: "info", message: `\u26A1 Auto-approved (/auto: ${classification.ruleId})` });
469
+ try {
470
+ const rawContent = await runTool(tool, call.arguments, call.name);
471
+ const content = truncateOutput(rawContent, call.name);
472
+ this.sendToolCallResult(call, rawContent, false);
473
+ runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "ok" });
474
+ runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "ok" }, { configDir: this.hookConfigDir });
475
+ return { callId: call.id, content, isError: false };
476
+ } catch (err) {
477
+ const message = err instanceof Error ? err.message : String(err);
478
+ this.sendToolCallResult(call, message, true);
479
+ runHook(this.hookConfig?.postToolExecution, { tool: call.name, status: "error" });
480
+ runLifecycleHooks(this.hookConfig, "PostToolUse", { tool: call.name, status: "error", error: message }, { configDir: this.hookConfigDir });
481
+ return { callId: call.id, content: message, isError: true };
482
+ }
483
+ }
484
+ }
444
485
  if (this.sessionAutoApprove && dangerLevel === "write") {
445
486
  try {
446
487
  const rawContent = await runTool(tool, call.arguments, call.name);
@@ -777,7 +818,19 @@ var SessionHandler = class {
777
818
  costUsd,
778
819
  providers: providerList,
779
820
  branches,
780
- activeBranchId: sess?.activeBranchId ?? "main"
821
+ activeBranchId: sess?.activeBranchId ?? "main",
822
+ agents: listAgentRuns().slice(0, 20).map((run) => ({
823
+ id: run.id,
824
+ agentName: run.agentName,
825
+ task: run.task,
826
+ status: run.status,
827
+ startedAt: run.startedAt,
828
+ finishedAt: run.finishedAt,
829
+ summary: run.summary,
830
+ error: run.error,
831
+ toolNames: run.toolNames,
832
+ agentIndex: run.agentIndex
833
+ }))
781
834
  });
782
835
  }
783
836
  async handleMessage(raw) {
@@ -1254,6 +1307,7 @@ Details: ${errMsg.split("\n")[0]}
1254
1307
  ${systemPromptVolatile}` : systemPrompt;
1255
1308
  spawnAgentContext.modelParams = modelParams;
1256
1309
  spawnAgentContext.configManager = this.config;
1310
+ spawnAgentContext.providers = this.providers;
1257
1311
  ToolExecutor.currentMessageIndex = this.sessions.current?.messages.length ?? 0;
1258
1312
  return this.toolExecutor.executeAll(toolCalls);
1259
1313
  },
@@ -1848,6 +1902,7 @@ Tokens: in=${this.sessionTokenUsage.inputTokens} out=${this.sessionTokenUsage.ou
1848
1902
  " /export [md|json] \u2014 Export conversation",
1849
1903
  " /skill [name|off|list|reload] \u2014 Manage agent skills",
1850
1904
  " /memory [show|add|clear] \u2014 Persistent memory management",
1905
+ " /agent list|switch|stop|summary \u2014 Manage named sub-agents",
1851
1906
  " /yolo [on|off] \u2014 Toggle auto-approve (skip confirmations)",
1852
1907
  " /search <keyword> \u2014 Search across all session histories",
1853
1908
  " /undo [list|<n>] \u2014 Undo file operations",
@@ -1980,7 +2035,108 @@ ${activated.meta.description || ""}` });
1980
2035
  }
1981
2036
  break;
1982
2037
  }
2038
+ case "agent": {
2039
+ const sub = args[0]?.toLowerCase() ?? "summary";
2040
+ if (sub === "list") {
2041
+ const agents = listAgentConfigs(this.config.getConfigDir());
2042
+ const lines = [`Agents (${agents.length})`, ""];
2043
+ for (const agent of agents) {
2044
+ const active = agent.name === getPreferredAgentName() ? " *" : " ";
2045
+ const model = [agent.provider, agent.model].filter(Boolean).join("/") || "inherit";
2046
+ lines.push(`${active} ${agent.name} [${agent.source ?? "builtin"}] \u2014 ${agent.description ?? ""}`);
2047
+ lines.push(` model: ${model} \xB7 permission: ${agent.permissionProfile ?? "workspace-write"} \xB7 maxRounds: ${agent.maxToolRounds ?? "inherit"}`);
2048
+ }
2049
+ lines.push("", "Config dirs: ~/.aicli/agents/ and .aicli/agents/");
2050
+ this.send({ type: "info", message: lines.join("\n") });
2051
+ break;
2052
+ }
2053
+ if (sub === "switch") {
2054
+ const name2 = args[1];
2055
+ if (!name2) {
2056
+ this.send({ type: "error", message: "Usage: /agent switch <name>" });
2057
+ break;
2058
+ }
2059
+ const agent = resolveAgentConfig(name2, this.config.getConfigDir());
2060
+ if (!agent) {
2061
+ const available = listAgentConfigs(this.config.getConfigDir()).map((a) => a.name).join(", ");
2062
+ this.send({ type: "error", message: `Unknown agent: ${name2}
2063
+ Available: ${available}` });
2064
+ break;
2065
+ }
2066
+ setPreferredAgentName(agent.name);
2067
+ this.send({ type: "info", message: `Preferred spawn_agent role: ${agent.name}` });
2068
+ this.sendStatus();
2069
+ break;
2070
+ }
2071
+ if (sub === "stop") {
2072
+ const target = args[1] ?? "all";
2073
+ const count = requestAgentStop(target);
2074
+ this.send({ type: "info", message: count > 0 ? `Stop requested for ${count} running agent(s).` : "No matching running agents." });
2075
+ this.sendStatus();
2076
+ break;
2077
+ }
2078
+ if (sub === "summary") {
2079
+ const runs = listAgentRuns();
2080
+ if (runs.length === 0) {
2081
+ this.send({ type: "info", message: "No sub-agent runs yet." });
2082
+ break;
2083
+ }
2084
+ const lines = [`Recent agent runs (${runs.length})`, ""];
2085
+ for (const run of runs.slice(0, 20)) {
2086
+ lines.push(`${run.id} ${run.status} ${run.agentName} ${run.startedAt}`);
2087
+ lines.push(` task: ${run.task.slice(0, 120)}${run.task.length > 120 ? "..." : ""}`);
2088
+ if (run.toolNames.length > 0) lines.push(` tools: ${run.toolNames.join(", ")}`);
2089
+ if (run.summary) lines.push(` summary: ${run.summary.slice(0, 180)}${run.summary.length > 180 ? "..." : ""}`);
2090
+ if (run.error) lines.push(` error: ${run.error}`);
2091
+ }
2092
+ this.send({ type: "info", message: lines.join("\n") });
2093
+ break;
2094
+ }
2095
+ this.send({ type: "error", message: "Usage: /agent list|switch <name>|stop <id|all>|summary" });
2096
+ break;
2097
+ }
1983
2098
  // ── /yolo ──────────────────────────────────────────────────────
2099
+ case "auto": {
2100
+ const sub = args[0]?.toLowerCase() ?? "status";
2101
+ if (sub === "on") {
2102
+ this.toolExecutor.sessionAutoMode = true;
2103
+ this.send({ type: "info", message: "\u26A1 Auto Mode ON \u2014 low-risk actions may auto-run; high-risk actions still confirm or deny. Auto Mode is session-scoped." });
2104
+ } else if (sub === "off") {
2105
+ this.toolExecutor.sessionAutoMode = false;
2106
+ this.send({ type: "info", message: "Auto Mode disabled." });
2107
+ } else if (sub === "status") {
2108
+ this.send({ type: "info", message: `Auto Mode: ${this.toolExecutor.sessionAutoMode ? "on" : "off"}
2109
+ Scope: current session only
2110
+ Denied: /permissions recently-denied` });
2111
+ } else {
2112
+ this.send({ type: "error", message: "Usage: /auto [on|off|status]" });
2113
+ }
2114
+ this.sendStatus();
2115
+ break;
2116
+ }
2117
+ case "permissions": {
2118
+ const sub = args[0]?.toLowerCase() ?? "recently-denied";
2119
+ if (sub === "recently-denied") {
2120
+ const rows = getRecentlyDeniedAutoActions();
2121
+ if (rows.length === 0) {
2122
+ this.send({ type: "info", message: "No recently denied Auto Mode actions." });
2123
+ } else {
2124
+ const lines = [`Recently denied Auto Mode actions (${rows.length})`, ""];
2125
+ for (const r of rows.slice(0, 20)) {
2126
+ lines.push(`- ${r.timestamp} ${r.tool} ${r.ruleId}`);
2127
+ lines.push(` ${r.reason}`);
2128
+ lines.push(` ${r.argsPreview}`);
2129
+ }
2130
+ this.send({ type: "info", message: lines.join("\n") });
2131
+ }
2132
+ } else if (sub === "clear-denied") {
2133
+ clearRecentlyDeniedAutoActions();
2134
+ this.send({ type: "info", message: "Cleared recently denied Auto Mode actions." });
2135
+ } else {
2136
+ this.send({ type: "error", message: "Usage: /permissions recently-denied|clear-denied" });
2137
+ }
2138
+ break;
2139
+ }
1984
2140
  case "yolo": {
1985
2141
  const sub = args[0]?.toLowerCase();
1986
2142
  if (sub === "off") {
@@ -2599,7 +2755,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
2599
2755
  case "test": {
2600
2756
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
2601
2757
  try {
2602
- const { executeTests } = await import("./run-tests-H4Q2PRX6.js");
2758
+ const { executeTests } = await import("./run-tests-F44JA2YW.js");
2603
2759
  const argStr = args.join(" ").trim();
2604
2760
  let testArgs = {};
2605
2761
  if (argStr) {
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ToolRegistry
4
- } from "./chunk-N5LB3PPL.js";
4
+ } from "./chunk-R5CJD2AB.js";
5
5
  import "./chunk-T2NL5ZIA.js";
6
6
  import "./chunk-BXP6YZ2P.js";
7
- import "./chunk-HX6N6QEY.js";
7
+ import "./chunk-TR6MSPSS.js";
8
8
  import {
9
9
  runTool
10
- } from "./chunk-IFZX26K7.js";
10
+ } from "./chunk-YMFGGCUP.js";
11
11
  import {
12
12
  getDangerLevel,
13
13
  schemaToJsonSchema
@@ -15,7 +15,7 @@ import {
15
15
  import "./chunk-TZQHYZKT.js";
16
16
  import {
17
17
  VERSION
18
- } from "./chunk-GBBVCZ4W.js";
18
+ } from "./chunk-DBYMX2ZC.js";
19
19
  import "./chunk-4BKXL7SM.js";
20
20
  import "./chunk-TB4W4Y4T.js";
21
21
  import "./chunk-KHYD3WXE.js";
@@ -3,13 +3,13 @@ import {
3
3
  ToolRegistry,
4
4
  googleSearchContext,
5
5
  truncateOutput
6
- } from "./chunk-N5LB3PPL.js";
6
+ } from "./chunk-R5CJD2AB.js";
7
7
  import "./chunk-T2NL5ZIA.js";
8
8
  import "./chunk-BXP6YZ2P.js";
9
- import "./chunk-HX6N6QEY.js";
9
+ import "./chunk-TR6MSPSS.js";
10
10
  import {
11
11
  runTool
12
- } from "./chunk-IFZX26K7.js";
12
+ } from "./chunk-YMFGGCUP.js";
13
13
  import {
14
14
  getDangerLevel,
15
15
  runLeanAgentLoop
@@ -17,7 +17,7 @@ import {
17
17
  import "./chunk-TZQHYZKT.js";
18
18
  import {
19
19
  SUBAGENT_ALLOWED_TOOLS
20
- } from "./chunk-GBBVCZ4W.js";
20
+ } from "./chunk-DBYMX2ZC.js";
21
21
  import "./chunk-4BKXL7SM.js";
22
22
  import "./chunk-TB4W4Y4T.js";
23
23
  import "./chunk-KHYD3WXE.js";
@@ -8,9 +8,9 @@ import {
8
8
  } from "./chunk-E44DTERW.js";
9
9
  import {
10
10
  ConfigManager
11
- } from "./chunk-NYCBOVNF.js";
11
+ } from "./chunk-YFHF3PVB.js";
12
12
  import "./chunk-TZQHYZKT.js";
13
- import "./chunk-GBBVCZ4W.js";
13
+ import "./chunk-DBYMX2ZC.js";
14
14
  import "./chunk-IW3Q7AE5.js";
15
15
 
16
16
  // src/cli/usage.ts
@@ -548,7 +548,10 @@ function handleStatus(msg) {
548
548
  // Active tab: full UI reflection
549
549
  btnThink.classList.toggle('btn-active-toggle', msg.thinkingMode);
550
550
  btnPlan.classList.toggle('btn-active-toggle', msg.planMode);
551
- statusSession.textContent = '📋 ' + (msg.sessionId?.slice(0, 8) || '—') + ' (' + msg.messageCount + ' msgs) · ' + (msg.permissionProfile || 'legacy') + (msg.networkPolicyEnabled ? ' · net:on' : '') + (msg.pendingHookTrustCount ? ' · hooks:' + msg.pendingHookTrustCount : '');
551
+ const runningAgents = Array.isArray(msg.agents) ? msg.agents.filter(a => a.status === 'running').length : 0;
552
+ const failedAgents = Array.isArray(msg.agents) ? msg.agents.filter(a => a.status === 'error').length : 0;
553
+ const agentStatus = (runningAgents ? ' · agents:' + runningAgents : '') + (failedAgents ? ' · agent-errors:' + failedAgents : '');
554
+ statusSession.textContent = '📋 ' + (msg.sessionId?.slice(0, 8) || '—') + ' (' + msg.messageCount + ' msgs) · ' + (msg.permissionProfile || 'legacy') + (msg.networkPolicyEnabled ? ' · net:on' : '') + (msg.autoMode ? ' · auto:on' : '') + (msg.pendingHookTrustCount ? ' · hooks:' + msg.pendingHookTrustCount : '') + agentStatus;
552
555
  if (msg.tokenUsage) {
553
556
  const u = msg.tokenUsage;
554
557
  const cacheRead = u.cacheReadTokens || 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.4.212",
3
+ "version": "0.4.214",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",