jinzd-ai-cli 0.4.154 → 0.4.155

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 (26) hide show
  1. package/dist/{batch-W57MV5OT.js → batch-LS3IJVBK.js} +2 -2
  2. package/dist/{chat-index-LUQWWLKO.js → chat-index-IF4EINLQ.js} +2 -1
  3. package/dist/{chunk-UE26B3RO.js → chunk-B3LFGPU2.js} +1 -1
  4. package/dist/{chunk-ZAYDVWY4.js → chunk-CIZQZ7CC.js} +23 -787
  5. package/dist/{chunk-SH7NTECG.js → chunk-D6GJTJQH.js} +1 -1
  6. package/dist/{chunk-XWYWASPT.js → chunk-E5ICQT3P.js} +4 -4
  7. package/dist/{chunk-OSTMMSOV.js → chunk-IBBYW6PM.js} +1 -1
  8. package/dist/{chunk-NP7WOVIH.js → chunk-JOJRBV2K.js} +1 -1
  9. package/dist/{chunk-2IODI5TI.js → chunk-JXSWY54M.js} +1 -1
  10. package/dist/{chunk-HVNEBTSF.js → chunk-NFRTSL3N.js} +1 -1
  11. package/dist/chunk-SLSWPBK3.js +120 -0
  12. package/dist/chunk-TOTEUETI.js +768 -0
  13. package/dist/{chunk-RXM76HB7.js → chunk-U5MY24UZ.js} +3 -117
  14. package/dist/{ci-JYZGZSMP.js → ci-34ZQH43L.js} +2 -2
  15. package/dist/{constants-S4Y6A25E.js → constants-DQ5VJOGS.js} +1 -1
  16. package/dist/{doctor-cli-FMTMDO2Z.js → doctor-cli-TSCI4ORL.js} +4 -4
  17. package/dist/electron-server.js +2 -2
  18. package/dist/{hub-OP7EWTQQ.js → hub-ZILVZWI2.js} +19 -3
  19. package/dist/index.js +28 -22
  20. package/dist/persist-3EBOLHFZ.js +52 -0
  21. package/dist/{run-tests-4XNY7QB4.js → run-tests-5CJRMOMI.js} +1 -1
  22. package/dist/{run-tests-3QAZGHP2.js → run-tests-5KWCHBQS.js} +2 -2
  23. package/dist/{server-UL42EXOA.js → server-35OQV62B.js} +16 -13
  24. package/dist/{server-W4TBZN6I.js → server-DVIP7NLW.js} +6 -5
  25. package/dist/{task-orchestrator-RLAZK5EB.js → task-orchestrator-AXSS7ROD.js} +6 -5
  26. package/package.json +1 -1
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ redactString
4
+ } from "./chunk-SLSWPBK3.js";
2
5
  import {
3
6
  EMBEDDING_DIM,
4
7
  embed,
@@ -10,120 +13,6 @@ import fs from "fs";
10
13
  import path from "path";
11
14
  import os from "os";
12
15
  import crypto from "crypto";
13
-
14
- // src/security/redactor.ts
15
- var DEFAULT_PATTERNS = [
16
- // password: xxx / password = xxx / password="xxx"
17
- // Covers YAML / JSON / shell-ish / env-file forms.
18
- { kind: "password", regex: /\b(password|passwd|pwd)\s*[:=]\s*["']?([^\s"',;{}]{4,200})["']?/gi },
19
- // PGPASSWORD=xxx (explicit bash env-var form, separate rule because no quotes usually)
20
- { kind: "pgpassword-env", regex: /\b(PGPASSWORD)=([^\s"']{4,200})/g },
21
- // JDBC/PG/MySQL/Mongo connection strings with inline credentials
22
- // postgresql://user:pass@host/db → redact pass
23
- { kind: "db-uri-password", regex: /(\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp|mssql):\/\/[^:\s]+:)([^@\s]+)(@)/gi },
24
- // Anthropic API keys
25
- { kind: "anthropic-key", regex: /(sk-ant-[a-zA-Z0-9_-]{90,})/g },
26
- // L6 (v0.4.108): Zhipu / GLM API keys — `<24+ hex/base64-ish>.<32+>`
27
- // Two segments separated by a dot, each safely identifiable by length
28
- // and char class. Conservative on the lower bound so we don't eat
29
- // version strings like `1.0.0` or filenames.
30
- { kind: "zhipu-key", regex: /\b([a-zA-Z0-9]{24,}\.[a-zA-Z0-9]{32,})\b/g },
31
- // OpenAI / generic sk- keys — requires length ≥32 to avoid eating short identifiers
32
- { kind: "openai-key", regex: /(sk-(?:proj-)?[a-zA-Z0-9_-]{32,})/g },
33
- // GitHub personal access tokens
34
- { kind: "github-pat", regex: /\b(ghp_[a-zA-Z0-9]{36})\b/g },
35
- { kind: "github-oauth", regex: /\b(gho_[a-zA-Z0-9]{36})\b/g },
36
- { kind: "github-install", regex: /\b(ghs_[a-zA-Z0-9]{36})\b/g },
37
- // Slack tokens
38
- { kind: "slack-bot", regex: /\b(xoxb-\d+-\d+-[a-zA-Z0-9]+)\b/g },
39
- { kind: "slack-user", regex: /\b(xoxp-\d+-\d+-\d+-[a-zA-Z0-9]+)\b/g },
40
- // AWS access key IDs (AKIA...) and secret access keys are context-dependent;
41
- // we only catch the ID because secret key alone is indistinguishable from random base64.
42
- { kind: "aws-access-key-id", regex: /\b(AKIA[0-9A-Z]{16})\b/g },
43
- // Google API keys
44
- { kind: "google-api-key", regex: /\b(AIza[0-9A-Za-z_-]{35})\b/g },
45
- // Generic "api_key": "..." / "apiKey": "..." / api-key=xxx
46
- { kind: "api-key", regex: /\b(api[_-]?key)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{16,200})["']?/gi },
47
- // Generic token: xxx (only when value looks token-shaped; avoids eating human prose)
48
- { kind: "token", regex: /\b(token|access[_-]?token|bearer[_-]?token)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{20,300})["']?/gi },
49
- // Bearer <token> in Authorization headers
50
- { kind: "bearer", regex: /\b(Authorization:\s*Bearer\s+)([a-zA-Z0-9_\-.=]{20,500})/g },
51
- // Private key PEM blocks — catch the header+footer together
52
- { kind: "private-key", regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g }
53
- ];
54
- var MAX_CUSTOM = 32;
55
- var MAX_PATTERN_LEN = 500;
56
- var SUSPICIOUS_REDOS = /\([^)]*[+*][^)]*\)\s*[+*{]/;
57
- function render(placeholder, kind) {
58
- return placeholder.replace("{kind}", kind);
59
- }
60
- function redactString(input, options) {
61
- if (!options.enabled || !input) return { redacted: input, hits: [] };
62
- const placeholder = options.placeholder ?? "[REDACTED:{kind}]";
63
- const customSrcs = (options.customRegexes ?? []).slice(0, MAX_CUSTOM);
64
- const patterns = [
65
- ...options.patterns ?? DEFAULT_PATTERNS,
66
- ...customSrcs.flatMap((src, i) => {
67
- if (typeof src !== "string" || src.length === 0 || src.length > MAX_PATTERN_LEN) return [];
68
- try {
69
- const flags = src.match(/^\/.*\/([gimsuy]*)$/)?.[1] ?? "";
70
- const body = src.replace(/^\/(.*)\/[gimsuy]*$/, "$1");
71
- if (SUSPICIOUS_REDOS.test(body)) return [];
72
- const regex = new RegExp(body, flags.includes("g") ? flags : flags + "g");
73
- return [{ kind: `custom-${i}`, regex }];
74
- } catch {
75
- return [];
76
- }
77
- })
78
- ];
79
- let redacted = input;
80
- const hits = [];
81
- for (const { kind, regex } of patterns) {
82
- const rx = new RegExp(regex.source, regex.flags);
83
- const captureCount = new RegExp(rx.source + "|").exec("").length - 1;
84
- redacted = redacted.replace(rx, (...args) => {
85
- const match = args[0];
86
- const g1 = captureCount >= 1 ? args[1] : void 0;
87
- const g2 = captureCount >= 2 ? args[2] : void 0;
88
- const offset = args[1 + captureCount];
89
- if (captureCount >= 2 && typeof g2 === "string") {
90
- hits.push({ kind, start: offset + (g1?.length ?? 0), length: g2.length, secret: g2 });
91
- return `${g1}${render(placeholder, kind)}`;
92
- }
93
- hits.push({ kind, start: offset, length: match.length, secret: g1 ?? match });
94
- return render(placeholder, kind);
95
- });
96
- }
97
- return { redacted, hits };
98
- }
99
- function redactJson(value, options) {
100
- if (!options.enabled) return { value, hits: [] };
101
- const allHits = [];
102
- function walk(v) {
103
- if (typeof v === "string") {
104
- const r = redactString(v, options);
105
- allHits.push(...r.hits);
106
- return r.redacted;
107
- }
108
- if (Array.isArray(v)) return v.map(walk);
109
- if (v && typeof v === "object") {
110
- const out = {};
111
- for (const [k, vv] of Object.entries(v)) {
112
- out[k] = walk(vv);
113
- }
114
- return out;
115
- }
116
- return v;
117
- }
118
- const redacted = walk(value);
119
- return { value: redacted, hits: allHits };
120
- }
121
- function scanString(input, options) {
122
- const { hits } = redactString(input, { ...options, enabled: true });
123
- return hits;
124
- }
125
-
126
- // src/memory/chat-index.ts
127
16
  var MEMORY_DIR_NAME = "memory-index";
128
17
  var CHUNKS_FILE = "chunks.json";
129
18
  var VECTORS_FILE = "vectors.vec";
@@ -458,9 +347,6 @@ function getChatIndexStatus() {
458
347
  }
459
348
 
460
349
  export {
461
- DEFAULT_PATTERNS,
462
- redactJson,
463
- scanString,
464
350
  chunkSession,
465
351
  loadChatIndex,
466
352
  clearChatIndex,
@@ -9,12 +9,12 @@ import {
9
9
  } from "./chunk-AIZOARZY.js";
10
10
  import {
11
11
  ConfigManager
12
- } from "./chunk-OSTMMSOV.js";
12
+ } from "./chunk-IBBYW6PM.js";
13
13
  import "./chunk-NXXNLLSG.js";
14
14
  import "./chunk-2ZD3YTVM.js";
15
15
  import {
16
16
  VERSION
17
- } from "./chunk-UE26B3RO.js";
17
+ } from "./chunk-B3LFGPU2.js";
18
18
  import "./chunk-PDX44BCA.js";
19
19
 
20
20
  // src/cli/ci.ts
@@ -36,7 +36,7 @@ import {
36
36
  TEST_TIMEOUT,
37
37
  VERSION,
38
38
  buildUserIdentityPrompt
39
- } from "./chunk-UE26B3RO.js";
39
+ } from "./chunk-B3LFGPU2.js";
40
40
  import "./chunk-PDX44BCA.js";
41
41
  export {
42
42
  AGENTIC_BEHAVIOR_GUIDELINE,
@@ -2,26 +2,26 @@
2
2
  import {
3
3
  getConfigDirUsage,
4
4
  listRecentCrashes
5
- } from "./chunk-SH7NTECG.js";
5
+ } from "./chunk-D6GJTJQH.js";
6
6
  import {
7
7
  ProviderRegistry
8
8
  } from "./chunk-AIZOARZY.js";
9
9
  import {
10
10
  ConfigManager
11
- } from "./chunk-OSTMMSOV.js";
11
+ } from "./chunk-IBBYW6PM.js";
12
12
  import {
13
13
  getStatsSnapshot,
14
14
  getTopFailingTools,
15
15
  getTopUsedTools,
16
16
  resetStats
17
- } from "./chunk-HVNEBTSF.js";
17
+ } from "./chunk-NFRTSL3N.js";
18
18
  import "./chunk-NXXNLLSG.js";
19
19
  import "./chunk-2ZD3YTVM.js";
20
20
  import {
21
21
  DEV_STATE_FILE_NAME,
22
22
  MEMORY_FILE_NAME,
23
23
  VERSION
24
- } from "./chunk-UE26B3RO.js";
24
+ } from "./chunk-B3LFGPU2.js";
25
25
  import "./chunk-PDX44BCA.js";
26
26
 
27
27
  // src/diagnostics/doctor-cli.ts
@@ -36,7 +36,7 @@ import {
36
36
  VERSION,
37
37
  buildUserIdentityPrompt,
38
38
  runTestsTool
39
- } from "./chunk-2IODI5TI.js";
39
+ } from "./chunk-JXSWY54M.js";
40
40
  import {
41
41
  hasSemanticIndex,
42
42
  semanticSearch
@@ -12715,7 +12715,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
12715
12715
  case "test": {
12716
12716
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
12717
12717
  try {
12718
- const { executeTests } = await import("./run-tests-4XNY7QB4.js");
12718
+ const { executeTests } = await import("./run-tests-5CJRMOMI.js");
12719
12719
  const argStr = args.join(" ").trim();
12720
12720
  let testArgs = {};
12721
12721
  if (argStr) {
@@ -41,6 +41,10 @@ var DiscussionOrchestrator = class {
41
41
  getAgents() {
42
42
  return this.agents;
43
43
  }
44
+ /** Current discussion state (used to persist even after an error). */
45
+ getState() {
46
+ return this.state;
47
+ }
44
48
  /** Signal the orchestrator to stop after current turn */
45
49
  abort() {
46
50
  this.aborted = true;
@@ -478,14 +482,25 @@ ${content}`);
478
482
  if (options.distributed) {
479
483
  await runDistributedDiscussion(config, providers, options.topic, options.port ?? 9527);
480
484
  } else {
481
- await runDiscussion(config, providers, options.topic);
485
+ const state = await runDiscussion(config, providers, options.topic);
486
+ if (options.save !== false && state.messages.length > 0) {
487
+ try {
488
+ const { persistDiscussion } = await import("./persist-3EBOLHFZ.js");
489
+ const { path } = await persistDiscussion(state, configManager, defaultProvider, defaultModel);
490
+ console.log(chalk.dim(`
491
+ \u{1F4BE} Saved to history \u2014 open it in the Web UI and hit \u{1F3AC} to replay.
492
+ ${path}`));
493
+ } catch (err) {
494
+ console.error(chalk.yellow(` \u26A0 Could not save discussion: ${err.message}`));
495
+ }
496
+ }
482
497
  }
483
498
  } else if (mode === "task") {
484
499
  await runTaskMode(config, providers, configManager, options.topic);
485
500
  }
486
501
  }
487
502
  async function runTaskMode(config, providers, configManager, topic) {
488
- const { TaskOrchestrator } = await import("./task-orchestrator-RLAZK5EB.js");
503
+ const { TaskOrchestrator } = await import("./task-orchestrator-AXSS7ROD.js");
489
504
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
490
505
  let interrupted = false;
491
506
  const onSigint = () => {
@@ -576,10 +591,11 @@ async function runDiscussion(config, providers, topic) {
576
591
  process.on("SIGINT", onSigint);
577
592
  renderHubBanner(topic, config.roles, config.maxRounds ?? 10, config.contextFiles);
578
593
  try {
579
- await orchestrator.run(topic);
594
+ return await orchestrator.run(topic);
580
595
  } catch (err) {
581
596
  console.error(`
582
597
  \u2717 Hub error: ${err.message}`);
598
+ return orchestrator.getState();
583
599
  } finally {
584
600
  process.removeListener("SIGINT", onSigint);
585
601
  }
package/dist/index.js CHANGED
@@ -6,13 +6,11 @@ import {
6
6
  import {
7
7
  McpManager,
8
8
  SNAPSHOT_PROMPT,
9
- SessionManager,
10
9
  SkillManager,
11
10
  autoTrimSessionIfNeeded,
12
11
  clearDevState,
13
12
  computeCost,
14
13
  formatCost,
15
- getContentText,
16
14
  getPricing,
17
15
  loadDevState,
18
16
  parseSimpleYaml,
@@ -20,12 +18,16 @@ import {
20
18
  saveDevState,
21
19
  sessionHasMeaningfulContent,
22
20
  setupProxy
23
- } from "./chunk-ZAYDVWY4.js";
21
+ } from "./chunk-CIZQZ7CC.js";
22
+ import {
23
+ SessionManager,
24
+ getContentText
25
+ } from "./chunk-TOTEUETI.js";
24
26
  import {
25
27
  getConfigDirUsage,
26
28
  listRecentCrashes,
27
29
  writeCrashLog
28
- } from "./chunk-SH7NTECG.js";
30
+ } from "./chunk-D6GJTJQH.js";
29
31
  import {
30
32
  CONTENT_ONLY_STREAM_REMINDER,
31
33
  HALLUCINATION_CORRECTION_MESSAGE,
@@ -46,7 +48,7 @@ import {
46
48
  } from "./chunk-AIZOARZY.js";
47
49
  import {
48
50
  ConfigManager
49
- } from "./chunk-OSTMMSOV.js";
51
+ } from "./chunk-IBBYW6PM.js";
50
52
  import {
51
53
  ToolExecutor,
52
54
  ToolRegistry,
@@ -65,16 +67,16 @@ import {
65
67
  spawnAgentContext,
66
68
  theme,
67
69
  undoStack
68
- } from "./chunk-XWYWASPT.js";
70
+ } from "./chunk-E5ICQT3P.js";
69
71
  import "./chunk-HDSKW7Q3.js";
70
72
  import "./chunk-ZWVIDFGY.js";
71
- import "./chunk-NP7WOVIH.js";
73
+ import "./chunk-JOJRBV2K.js";
72
74
  import {
73
75
  getStatsSnapshot,
74
76
  getTopFailingTools,
75
77
  getTopUsedTools,
76
78
  installFlushOnExit
77
- } from "./chunk-HVNEBTSF.js";
79
+ } from "./chunk-NFRTSL3N.js";
78
80
  import "./chunk-NXXNLLSG.js";
79
81
  import {
80
82
  AuthError,
@@ -102,7 +104,7 @@ import {
102
104
  SKILLS_DIR_NAME,
103
105
  VERSION,
104
106
  buildUserIdentityPrompt
105
- } from "./chunk-UE26B3RO.js";
107
+ } from "./chunk-B3LFGPU2.js";
106
108
  import {
107
109
  formatGitContextForPrompt,
108
110
  getGitContext,
@@ -112,13 +114,15 @@ import {
112
114
  fileCheckpoints
113
115
  } from "./chunk-4BKXL7SM.js";
114
116
  import {
115
- DEFAULT_PATTERNS,
116
117
  buildChatIndex,
117
118
  clearChatIndex,
118
119
  getChatIndexStatus,
119
- scanString,
120
120
  searchChatMemory
121
- } from "./chunk-RXM76HB7.js";
121
+ } from "./chunk-U5MY24UZ.js";
122
+ import {
123
+ DEFAULT_PATTERNS,
124
+ scanString
125
+ } from "./chunk-SLSWPBK3.js";
122
126
  import "./chunk-KHYD3WXE.js";
123
127
  import "./chunk-VNNYHW6N.js";
124
128
  import "./chunk-OVWE4E46.js";
@@ -1769,7 +1773,7 @@ No tools match "${filter}".
1769
1773
  const { join: join6 } = await import("path");
1770
1774
  const { existsSync: existsSync6 } = await import("fs");
1771
1775
  const { getGitRoot: getGitRoot2 } = await import("./git-context-7KIP4X2V.js");
1772
- const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-S4Y6A25E.js");
1776
+ const { MCP_PROJECT_CONFIG_NAME: MCP_PROJECT_CONFIG_NAME2 } = await import("./constants-DQ5VJOGS.js");
1773
1777
  const { approveProject, hashMcpFile } = await import("./project-trust-IFM7FXEV.js");
1774
1778
  const cwd = process.cwd();
1775
1779
  const projectRoot = getGitRoot2(cwd) ?? cwd;
@@ -2830,7 +2834,7 @@ ${hint}` : "")
2830
2834
  usage: "/test [command|filter]",
2831
2835
  async execute(args, ctx) {
2832
2836
  try {
2833
- const { executeTests } = await import("./run-tests-3QAZGHP2.js");
2837
+ const { executeTests } = await import("./run-tests-5KWCHBQS.js");
2834
2838
  const argStr = args.join(" ").trim();
2835
2839
  let testArgs = {};
2836
2840
  if (argStr) {
@@ -5560,7 +5564,7 @@ Session '${this.resumeSessionId}' not found.
5560
5564
  })();
5561
5565
  void (async () => {
5562
5566
  try {
5563
- const { getChatIndexStatus: getChatIndexStatus2, buildChatIndex: buildChatIndex2 } = await import("./chat-index-LUQWWLKO.js");
5567
+ const { getChatIndexStatus: getChatIndexStatus2, buildChatIndex: buildChatIndex2 } = await import("./chat-index-IF4EINLQ.js");
5564
5568
  const initial = getChatIndexStatus2();
5565
5569
  this.chatMemoryStatus = {
5566
5570
  exists: initial.exists,
@@ -7530,7 +7534,7 @@ program.command("web").description("Start Web UI server with browser-based chat
7530
7534
  console.error("Error: Invalid port number. Must be between 1 and 65535.");
7531
7535
  process.exit(1);
7532
7536
  }
7533
- const { startWebServer } = await import("./server-UL42EXOA.js");
7537
+ const { startWebServer } = await import("./server-35OQV62B.js");
7534
7538
  await startWebServer({ port, host: options.host });
7535
7539
  });
7536
7540
  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) => {
@@ -7697,12 +7701,12 @@ program.command("sessions").description("List recent conversation sessions").opt
7697
7701
  console.log(footer + "\n");
7698
7702
  });
7699
7703
  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) => {
7700
- const { runDoctorCli } = await import("./doctor-cli-FMTMDO2Z.js");
7704
+ const { runDoctorCli } = await import("./doctor-cli-TSCI4ORL.js");
7701
7705
  await runDoctorCli({ json: !!options.json, resetStats: !!options.resetStats });
7702
7706
  });
7703
7707
  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) => {
7704
7708
  try {
7705
- const batch = await import("./batch-W57MV5OT.js");
7709
+ const batch = await import("./batch-LS3IJVBK.js");
7706
7710
  switch (action) {
7707
7711
  case "submit":
7708
7712
  if (!arg) {
@@ -7745,7 +7749,7 @@ program.command("batch <action> [arg] [arg2]").description("Anthropic Message Ba
7745
7749
  }
7746
7750
  });
7747
7751
  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) => {
7748
- const { startMcpServer } = await import("./server-W4TBZN6I.js");
7752
+ const { startMcpServer } = await import("./server-DVIP7NLW.js");
7749
7753
  await startMcpServer({
7750
7754
  allowDestructive: !!options.allowDestructive,
7751
7755
  allowOutsideCwd: !!options.allowOutsideCwd,
@@ -7754,7 +7758,7 @@ program.command("mcp-serve").description("Start an MCP server over STDIO, exposi
7754
7758
  });
7755
7759
  });
7756
7760
  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) => {
7757
- const { runCi } = await import("./ci-JYZGZSMP.js");
7761
+ const { runCi } = await import("./ci-34ZQH43L.js");
7758
7762
  const result = await runCi({
7759
7763
  pr: options.pr,
7760
7764
  base: options.base,
@@ -7830,6 +7834,7 @@ program.command("help").description("Show a comprehensive guide to all aicli fea
7830
7834
  ` ${Y}--mix [providers]${R} Mixed multi-model: spread providers across roles (e.g. claude,openai,deepseek)`,
7831
7835
  ` ${Y}--steer${R} Human-in-the-loop: steer/stop between rounds`,
7832
7836
  ` ${Y}--vote${R} Convergence voting: 2/3 [CONVERGED] majority ends early`,
7837
+ ` ${Y}--no-save${R} Don't persist discussion to history (saved + replayable by default)`,
7833
7838
  ` ${Y}-c, --context <file>${R} Inject context doc (repeatable: -c a.md -c b.md)`,
7834
7839
  ` ${Y}--task${R} Task mode: agents plan & write code with tools`,
7835
7840
  ` ${Y}--distributed${R} Distributed mode (WebSocket, multi-process)`,
@@ -7887,7 +7892,7 @@ program.command("help").description("Show a comprehensive guide to all aicli fea
7887
7892
  ];
7888
7893
  console.log(lines.join("\n"));
7889
7894
  });
7890
- program.command("hub [topic]").description("Start multi-agent hub (discuss / brainstorm with multiple AI roles)").option("--preset <name>", "Use a built-in role preset (default: tech-review)").option("--roles <file>", "Load roles from a JSON file").option("--provider <name>", "Override default AI provider").option("-m, --model <name>", "Override default model").option("--mix [providers]", "Mixed multi-model: spread configured providers across roles (or --mix claude,openai,deepseek)").option("--steer", "Human-in-the-loop: pause between rounds to inject guidance or stop (discuss mode)").option("--vote", "Convergence voting: agents may [CONVERGED]; 2/3 majority ends early (discuss mode)").option("--max-rounds <n>", "Max discussion rounds (default: 10)").option("--presets", "List available role presets").option("--task", "Task mode: plan \u2192 approve \uFFFD\uFFFD execute with tools (agents write code)").option("--task-rounds <n>", "Max tool-call rounds per task (default: 30)").option("-c, --context <file>", "Inject context document (repeatable: -c a.md -c b.md)", (val, prev) => prev.concat(val), []).option("--distributed", "Start WebSocket server so remote aicli instances can join as agents").option("--port <n>", "WebSocket port for distributed mode (default: 9527)", "9527").action(async (topic, options) => {
7895
+ program.command("hub [topic]").description("Start multi-agent hub (discuss / brainstorm with multiple AI roles)").option("--preset <name>", "Use a built-in role preset (default: tech-review)").option("--roles <file>", "Load roles from a JSON file").option("--provider <name>", "Override default AI provider").option("-m, --model <name>", "Override default model").option("--mix [providers]", "Mixed multi-model: spread configured providers across roles (or --mix claude,openai,deepseek)").option("--steer", "Human-in-the-loop: pause between rounds to inject guidance or stop (discuss mode)").option("--vote", "Convergence voting: agents may [CONVERGED]; 2/3 majority ends early (discuss mode)").option("--no-save", "Do not persist the discussion to ~/.aicli/history (discuss mode saves by default)").option("--max-rounds <n>", "Max discussion rounds (default: 10)").option("--presets", "List available role presets").option("--task", "Task mode: plan \u2192 approve \uFFFD\uFFFD execute with tools (agents write code)").option("--task-rounds <n>", "Max tool-call rounds per task (default: 30)").option("-c, --context <file>", "Inject context document (repeatable: -c a.md -c b.md)", (val, prev) => prev.concat(val), []).option("--distributed", "Start WebSocket server so remote aicli instances can join as agents").option("--port <n>", "WebSocket port for distributed mode (default: 9527)", "9527").action(async (topic, options) => {
7891
7896
  const config = new ConfigManager();
7892
7897
  const registry = new ProviderRegistry();
7893
7898
  await registry.initialize(
@@ -7898,7 +7903,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
7898
7903
  }),
7899
7904
  config.get("customProviders")
7900
7905
  );
7901
- const { startHub } = await import("./hub-OP7EWTQQ.js");
7906
+ const { startHub } = await import("./hub-ZILVZWI2.js");
7902
7907
  await startHub(
7903
7908
  {
7904
7909
  topic: topic ?? "",
@@ -7909,6 +7914,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
7909
7914
  mix: options.mix,
7910
7915
  steer: options.steer === true,
7911
7916
  vote: options.vote === true,
7917
+ save: options.save !== false,
7912
7918
  mode: options.task === true ? "task" : void 0,
7913
7919
  maxRounds: options.maxRounds ? parseInt(options.maxRounds, 10) : void 0,
7914
7920
  listPresets: options.presets === true,
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ SessionManager
4
+ } from "./chunk-TOTEUETI.js";
5
+ import "./chunk-SLSWPBK3.js";
6
+ import "./chunk-PDX44BCA.js";
7
+
8
+ // src/hub/persist.ts
9
+ import { join } from "path";
10
+ function discussionToMessages(state) {
11
+ const out = [];
12
+ const t0 = state.messages[0]?.timestamp ?? /* @__PURE__ */ new Date();
13
+ out.push({ role: "user", content: `\u{1F3DB} Topic: ${state.topic}`, timestamp: t0 });
14
+ for (const m of state.messages) {
15
+ if (m.speaker === "system") {
16
+ out.push({ role: "system", content: m.content, timestamp: m.timestamp });
17
+ continue;
18
+ }
19
+ if (m.speaker === "human") {
20
+ out.push({ role: "user", content: `\u{1F9ED} ${m.speakerName}: ${m.content}`, timestamp: m.timestamp });
21
+ continue;
22
+ }
23
+ if (m.passed || !m.content.trim()) continue;
24
+ const tag = m.converged ? " \u2713converged" : "";
25
+ out.push({
26
+ role: "assistant",
27
+ content: `**${m.speakerName}** (${m.speaker})${tag}
28
+
29
+ ${m.content}`,
30
+ timestamp: m.timestamp
31
+ });
32
+ }
33
+ if (state.summary && state.summary.trim()) {
34
+ out.push({ role: "assistant", content: `\u{1F4CB} **Summary**
35
+
36
+ ${state.summary}`, timestamp: /* @__PURE__ */ new Date() });
37
+ }
38
+ return out;
39
+ }
40
+ async function persistDiscussion(state, config, defaultProvider, defaultModel) {
41
+ const sm = new SessionManager(config);
42
+ const session = sm.createSession(defaultProvider, defaultModel);
43
+ session.messages = discussionToMessages(state);
44
+ session.title = `[Hub] ${state.topic.slice(0, 48)}`.replace(/\n/g, " ");
45
+ session.titleAiGenerated = true;
46
+ await sm.save();
47
+ return { id: session.id, path: join(config.getHistoryDir(), `${session.id}.json`) };
48
+ }
49
+ export {
50
+ discussionToMessages,
51
+ persistDiscussion
52
+ };
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  executeTests,
3
3
  runTestsTool
4
- } from "./chunk-2IODI5TI.js";
4
+ } from "./chunk-JXSWY54M.js";
5
5
  import "./chunk-3RG5ZIWI.js";
6
6
  export {
7
7
  executeTests,
@@ -2,8 +2,8 @@
2
2
  import {
3
3
  executeTests,
4
4
  runTestsTool
5
- } from "./chunk-NP7WOVIH.js";
6
- import "./chunk-UE26B3RO.js";
5
+ } from "./chunk-JOJRBV2K.js";
6
+ import "./chunk-B3LFGPU2.js";
7
7
  import "./chunk-PDX44BCA.js";
8
8
  export {
9
9
  executeTests,
@@ -5,16 +5,18 @@ import {
5
5
  } from "./chunk-GXB7YKF2.js";
6
6
  import {
7
7
  McpManager,
8
- SessionManager,
9
8
  SkillManager,
10
9
  autoTrimSessionIfNeeded,
11
10
  computeCost,
12
11
  formatCost,
13
- getContentText,
14
12
  loadDevState,
15
13
  persistToolRound,
16
14
  setupProxy
17
- } from "./chunk-ZAYDVWY4.js";
15
+ } from "./chunk-CIZQZ7CC.js";
16
+ import {
17
+ SessionManager,
18
+ getContentText
19
+ } from "./chunk-TOTEUETI.js";
18
20
  import {
19
21
  CONTENT_ONLY_STREAM_REMINDER,
20
22
  HALLUCINATION_CORRECTION_MESSAGE,
@@ -31,7 +33,7 @@ import {
31
33
  } from "./chunk-AIZOARZY.js";
32
34
  import {
33
35
  ConfigManager
34
- } from "./chunk-OSTMMSOV.js";
36
+ } from "./chunk-IBBYW6PM.js";
35
37
  import {
36
38
  ToolExecutor,
37
39
  ToolRegistry,
@@ -49,13 +51,13 @@ import {
49
51
  spawnAgentContext,
50
52
  truncateOutput,
51
53
  undoStack
52
- } from "./chunk-XWYWASPT.js";
54
+ } from "./chunk-E5ICQT3P.js";
53
55
  import "./chunk-HDSKW7Q3.js";
54
56
  import "./chunk-ZWVIDFGY.js";
55
- import "./chunk-NP7WOVIH.js";
57
+ import "./chunk-JOJRBV2K.js";
56
58
  import {
57
59
  runTool
58
- } from "./chunk-HVNEBTSF.js";
60
+ } from "./chunk-NFRTSL3N.js";
59
61
  import {
60
62
  getDangerLevel
61
63
  } from "./chunk-NXXNLLSG.js";
@@ -78,14 +80,15 @@ import {
78
80
  SKILLS_DIR_NAME,
79
81
  VERSION,
80
82
  buildUserIdentityPrompt
81
- } from "./chunk-UE26B3RO.js";
83
+ } from "./chunk-B3LFGPU2.js";
82
84
  import {
83
85
  formatGitContextForPrompt,
84
86
  getGitContext,
85
87
  getGitRoot
86
88
  } from "./chunk-HOSJZMQS.js";
87
89
  import "./chunk-4BKXL7SM.js";
88
- import "./chunk-RXM76HB7.js";
90
+ import "./chunk-U5MY24UZ.js";
91
+ import "./chunk-SLSWPBK3.js";
89
92
  import "./chunk-KHYD3WXE.js";
90
93
  import "./chunk-VNNYHW6N.js";
91
94
  import "./chunk-OVWE4E46.js";
@@ -2462,7 +2465,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
2462
2465
  case "test": {
2463
2466
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
2464
2467
  try {
2465
- const { executeTests } = await import("./run-tests-3QAZGHP2.js");
2468
+ const { executeTests } = await import("./run-tests-5KWCHBQS.js");
2466
2469
  const argStr = args.join(" ").trim();
2467
2470
  let testArgs = {};
2468
2471
  if (argStr) {
@@ -2986,7 +2989,7 @@ Add .md files to create commands.` });
2986
2989
  return;
2987
2990
  }
2988
2991
  try {
2989
- const { searchChatMemory, loadChatIndex } = await import("./chat-index-LUQWWLKO.js");
2992
+ const { searchChatMemory, loadChatIndex } = await import("./chat-index-IF4EINLQ.js");
2990
2993
  const loaded = loadChatIndex();
2991
2994
  if (!loaded || loaded.idx.chunks.length === 0) {
2992
2995
  this.send({ type: "memory_hits", query: q, hits: [], indexMissing: true });
@@ -3022,7 +3025,7 @@ Add .md files to create commands.` });
3022
3025
  }
3023
3026
  async handleMemoryStatus() {
3024
3027
  try {
3025
- const { getChatIndexStatus } = await import("./chat-index-LUQWWLKO.js");
3028
+ const { getChatIndexStatus } = await import("./chat-index-IF4EINLQ.js");
3026
3029
  const s = getChatIndexStatus();
3027
3030
  this.send({
3028
3031
  type: "memory_status",
@@ -3047,7 +3050,7 @@ Add .md files to create commands.` });
3047
3050
  type: "info",
3048
3051
  message: full ? "\u{1F9E0} Rebuilding chat memory index (this may take a while on first run \u2014 ~117 MB embedder)." : "\u{1F9E0} Refreshing chat memory index (incremental)\u2026"
3049
3052
  });
3050
- const { buildChatIndex } = await import("./chat-index-LUQWWLKO.js");
3053
+ const { buildChatIndex } = await import("./chat-index-IF4EINLQ.js");
3051
3054
  const stats = await buildChatIndex({
3052
3055
  full,
3053
3056
  onProgress: (p) => {
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  ToolRegistry
4
- } from "./chunk-XWYWASPT.js";
4
+ } from "./chunk-E5ICQT3P.js";
5
5
  import "./chunk-HDSKW7Q3.js";
6
6
  import "./chunk-ZWVIDFGY.js";
7
- import "./chunk-NP7WOVIH.js";
7
+ import "./chunk-JOJRBV2K.js";
8
8
  import {
9
9
  runTool
10
- } from "./chunk-HVNEBTSF.js";
10
+ } from "./chunk-NFRTSL3N.js";
11
11
  import {
12
12
  getDangerLevel,
13
13
  schemaToJsonSchema
@@ -15,9 +15,10 @@ import {
15
15
  import "./chunk-2ZD3YTVM.js";
16
16
  import {
17
17
  VERSION
18
- } from "./chunk-UE26B3RO.js";
18
+ } from "./chunk-B3LFGPU2.js";
19
19
  import "./chunk-4BKXL7SM.js";
20
- import "./chunk-RXM76HB7.js";
20
+ import "./chunk-U5MY24UZ.js";
21
+ import "./chunk-SLSWPBK3.js";
21
22
  import "./chunk-KHYD3WXE.js";
22
23
  import "./chunk-VNNYHW6N.js";
23
24
  import "./chunk-OVWE4E46.js";