jinzd-ai-cli 0.4.153 → 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 (28) hide show
  1. package/dist/{batch-DBRN4MCC.js → batch-LS3IJVBK.js} +2 -2
  2. package/dist/{chat-index-LUQWWLKO.js → chat-index-IF4EINLQ.js} +2 -1
  3. package/dist/{chunk-D62BVFP7.js → chunk-B3LFGPU2.js} +1 -1
  4. package/dist/{chunk-EIIMBVXN.js → chunk-CIZQZ7CC.js} +23 -787
  5. package/dist/{chunk-TURORFH2.js → chunk-D6GJTJQH.js} +1 -1
  6. package/dist/{chunk-OP3I24WL.js → chunk-E5ICQT3P.js} +4 -4
  7. package/dist/{chunk-UWW3EWER.js → chunk-IBBYW6PM.js} +1 -1
  8. package/dist/{chunk-OT2HLGSO.js → chunk-JOJRBV2K.js} +1 -1
  9. package/dist/{chunk-LJPB4ZER.js → chunk-JXSWY54M.js} +1 -1
  10. package/dist/{chunk-EYJQJZJ6.js → chunk-NFRTSL3N.js} +1 -1
  11. package/dist/{chunk-M4GJOBWN.js → chunk-O6MLS5QO.js} +63 -23
  12. package/dist/chunk-SLSWPBK3.js +120 -0
  13. package/dist/chunk-TOTEUETI.js +768 -0
  14. package/dist/{chunk-RXM76HB7.js → chunk-U5MY24UZ.js} +3 -117
  15. package/dist/{ci-UEEUSELV.js → ci-34ZQH43L.js} +2 -2
  16. package/dist/{constants-43EVHE2E.js → constants-DQ5VJOGS.js} +1 -1
  17. package/dist/{doctor-cli-ZT674MCQ.js → doctor-cli-TSCI4ORL.js} +4 -4
  18. package/dist/electron-server.js +2 -2
  19. package/dist/{hub-MDQNJOMV.js → hub-ZILVZWI2.js} +81 -7
  20. package/dist/{hub-server-VPXCBWLA.js → hub-server-OH7AYQIW.js} +1 -1
  21. package/dist/index.js +32 -22
  22. package/dist/persist-3EBOLHFZ.js +52 -0
  23. package/dist/{run-tests-DCT5LWBB.js → run-tests-5CJRMOMI.js} +1 -1
  24. package/dist/{run-tests-EYZ2JZ4X.js → run-tests-5KWCHBQS.js} +2 -2
  25. package/dist/{server-OIYBFKS2.js → server-35OQV62B.js} +16 -13
  26. package/dist/{server-MQWFO2GJ.js → server-DVIP7NLW.js} +6 -5
  27. package/dist/{task-orchestrator-BGQBNKAI.js → task-orchestrator-AXSS7ROD.js} +6 -5
  28. 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-UWW3EWER.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-D62BVFP7.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-D62BVFP7.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-TURORFH2.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-UWW3EWER.js";
11
+ } from "./chunk-IBBYW6PM.js";
12
12
  import {
13
13
  getStatsSnapshot,
14
14
  getTopFailingTools,
15
15
  getTopUsedTools,
16
16
  resetStats
17
- } from "./chunk-EYJQJZJ6.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-D62BVFP7.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-LJPB4ZER.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-DCT5LWBB.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) {
@@ -2,9 +2,10 @@
2
2
  import {
3
3
  HubAgent,
4
4
  assignRoleColors,
5
+ isConverged,
5
6
  renderHubBanner,
6
7
  renderHubEvent
7
- } from "./chunk-M4GJOBWN.js";
8
+ } from "./chunk-O6MLS5QO.js";
8
9
  import "./chunk-PDX44BCA.js";
9
10
 
10
11
  // src/hub/discuss.ts
@@ -12,12 +13,22 @@ var DiscussionOrchestrator = class {
12
13
  agents = [];
13
14
  state;
14
15
  aborted = false;
16
+ humanSteer;
17
+ voteConverge;
15
18
  /** Callback for rendering events */
16
19
  onEvent;
20
+ /**
21
+ * P2: human-in-the-loop. When `config.humanSteer` is on, the orchestrator
22
+ * awaits this between rounds so a person can inject guidance or stop. The
23
+ * CLI layer supplies the actual prompt; the orchestrator stays UI-agnostic.
24
+ */
25
+ onRoundReview;
17
26
  constructor(config, providers) {
18
27
  this.agents = config.roles.map(
19
28
  (role) => new HubAgent(role, providers, config.defaultProvider, config.defaultModel, config.context)
20
29
  );
30
+ this.humanSteer = config.humanSteer ?? false;
31
+ this.voteConverge = config.voteConverge ?? false;
21
32
  this.state = {
22
33
  topic: "",
23
34
  messages: [],
@@ -30,6 +41,10 @@ var DiscussionOrchestrator = class {
30
41
  getAgents() {
31
42
  return this.agents;
32
43
  }
44
+ /** Current discussion state (used to persist even after an error). */
45
+ getState() {
46
+ return this.state;
47
+ }
33
48
  /** Signal the orchestrator to stop after current turn */
34
49
  abort() {
35
50
  this.aborted = true;
@@ -52,6 +67,7 @@ var DiscussionOrchestrator = class {
52
67
  this.state.round = round;
53
68
  this.emit({ type: "round_start", round, maxRounds: this.state.maxRounds });
54
69
  let allPassed = true;
70
+ let convergedCount = 0;
55
71
  for (const agent of this.agents) {
56
72
  if (this.aborted) break;
57
73
  this.emit({ type: "agent_speaking", roleId: agent.role.id, roleName: agent.role.name });
@@ -61,9 +77,11 @@ var DiscussionOrchestrator = class {
61
77
  this.state.messages,
62
78
  round,
63
79
  this.state.maxRounds,
64
- (token) => this.emit({ type: "agent_token", roleId: agent.role.id, token })
80
+ (token) => this.emit({ type: "agent_token", roleId: agent.role.id, token }),
81
+ { voteConverge: this.voteConverge }
65
82
  );
66
83
  this.state.messages.push(message);
84
+ if (message.converged) convergedCount++;
67
85
  if (message.passed) {
68
86
  this.emit({ type: "agent_passed", roleId: agent.role.id });
69
87
  this.emit({ type: "agent_spoke", roleId: agent.role.id, message });
@@ -87,8 +105,33 @@ var DiscussionOrchestrator = class {
87
105
  this.emit({ type: "discussion_end", reason: "consensus" });
88
106
  break;
89
107
  }
108
+ if (this.voteConverge && convergedCount > 0) {
109
+ this.emit({ type: "converge_vote", converged: convergedCount, total: this.agents.length });
110
+ if (isConverged(convergedCount, this.agents.length)) {
111
+ this.emit({ type: "discussion_end", reason: "vote_converged" });
112
+ break;
113
+ }
114
+ }
90
115
  if (round === this.state.maxRounds) {
91
116
  this.emit({ type: "discussion_end", reason: "max_rounds", maxRounds: this.state.maxRounds });
117
+ break;
118
+ }
119
+ if (this.humanSteer && this.onRoundReview && !this.aborted) {
120
+ const steer = await this.onRoundReview({ round, maxRounds: this.state.maxRounds, state: this.state });
121
+ if (steer.action === "stop") {
122
+ this.emit({ type: "discussion_end", reason: "human_stop" });
123
+ break;
124
+ }
125
+ const guidance = steer.message?.trim();
126
+ if (guidance) {
127
+ this.state.messages.push({
128
+ speaker: "human",
129
+ speakerName: "\u4E3B\u6301\u4EBA (You)",
130
+ content: guidance,
131
+ timestamp: /* @__PURE__ */ new Date()
132
+ });
133
+ this.emit({ type: "human_steer", message: guidance });
134
+ }
92
135
  }
93
136
  }
94
137
  } catch (err) {
@@ -431,20 +474,33 @@ ${content}`);
431
474
  enableTools: mode === "task",
432
475
  maxToolRoundsPerTurn: mode === "task" ? options.taskRounds ?? 30 : void 0,
433
476
  context,
434
- contextFiles: contextFileNames.length > 0 ? contextFileNames : void 0
477
+ contextFiles: contextFileNames.length > 0 ? contextFileNames : void 0,
478
+ humanSteer: options.steer === true,
479
+ voteConverge: options.vote === true
435
480
  };
436
481
  if (mode === "discuss") {
437
482
  if (options.distributed) {
438
483
  await runDistributedDiscussion(config, providers, options.topic, options.port ?? 9527);
439
484
  } else {
440
- 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
+ }
441
497
  }
442
498
  } else if (mode === "task") {
443
499
  await runTaskMode(config, providers, configManager, options.topic);
444
500
  }
445
501
  }
446
502
  async function runTaskMode(config, providers, configManager, topic) {
447
- const { TaskOrchestrator } = await import("./task-orchestrator-BGQBNKAI.js");
503
+ const { TaskOrchestrator } = await import("./task-orchestrator-AXSS7ROD.js");
448
504
  const orchestrator = new TaskOrchestrator(config, providers, configManager);
449
505
  let interrupted = false;
450
506
  const onSigint = () => {
@@ -480,7 +536,7 @@ async function runTaskMode(config, providers, configManager, topic) {
480
536
  }
481
537
  }
482
538
  async function runDistributedDiscussion(config, providers, topic, port) {
483
- const { HubServer } = await import("./hub-server-VPXCBWLA.js");
539
+ const { HubServer } = await import("./hub-server-OH7AYQIW.js");
484
540
  const hub = new HubServer(config, providers, port);
485
541
  let interrupted = false;
486
542
  const onSigint = () => {
@@ -506,6 +562,23 @@ async function runDiscussion(config, providers, topic) {
506
562
  assignRoleColors(config.roles);
507
563
  const orchestrator = new DiscussionOrchestrator(config, providers);
508
564
  orchestrator.onEvent = renderHubEvent;
565
+ if (config.humanSteer) {
566
+ const { createInterface } = await import("readline");
567
+ orchestrator.onRoundReview = async ({ round, maxRounds }) => {
568
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
569
+ const answer = await new Promise((resolve) => {
570
+ rl.question(
571
+ chalk.cyan(`
572
+ \u{1F9ED} Round ${round}/${maxRounds} done. Steer next round? `) + chalk.dim("[Enter=continue \xB7 type guidance \xB7 /stop=end] "),
573
+ resolve
574
+ );
575
+ });
576
+ rl.close();
577
+ const t = answer.trim();
578
+ if (t === "/stop" || t.toLowerCase() === "stop") return { action: "stop" };
579
+ return { action: "continue", message: t || void 0 };
580
+ };
581
+ }
509
582
  let interrupted = false;
510
583
  const onSigint = () => {
511
584
  if (interrupted) {
@@ -518,10 +591,11 @@ async function runDiscussion(config, providers, topic) {
518
591
  process.on("SIGINT", onSigint);
519
592
  renderHubBanner(topic, config.roles, config.maxRounds ?? 10, config.contextFiles);
520
593
  try {
521
- await orchestrator.run(topic);
594
+ return await orchestrator.run(topic);
522
595
  } catch (err) {
523
596
  console.error(`
524
597
  \u2717 Hub error: ${err.message}`);
598
+ return orchestrator.getState();
525
599
  } finally {
526
600
  process.removeListener("SIGINT", onSigint);
527
601
  }
@@ -11,7 +11,7 @@ import {
11
11
  renderRoundHeader,
12
12
  renderSummary,
13
13
  renderUserInterrupt
14
- } from "./chunk-M4GJOBWN.js";
14
+ } from "./chunk-O6MLS5QO.js";
15
15
  import "./chunk-PDX44BCA.js";
16
16
 
17
17
  // src/hub/hub-server.ts
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-EIIMBVXN.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-TURORFH2.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-UWW3EWER.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-OP3I24WL.js";
70
+ } from "./chunk-E5ICQT3P.js";
69
71
  import "./chunk-HDSKW7Q3.js";
70
72
  import "./chunk-ZWVIDFGY.js";
71
- import "./chunk-OT2HLGSO.js";
73
+ import "./chunk-JOJRBV2K.js";
72
74
  import {
73
75
  getStatsSnapshot,
74
76
  getTopFailingTools,
75
77
  getTopUsedTools,
76
78
  installFlushOnExit
77
- } from "./chunk-EYJQJZJ6.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-D62BVFP7.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-43EVHE2E.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-EYZ2JZ4X.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-OIYBFKS2.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-ZT674MCQ.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-DBRN4MCC.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-MQWFO2GJ.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-UEEUSELV.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,
@@ -7828,6 +7832,9 @@ program.command("help").description("Show a comprehensive guide to all aicli fea
7828
7832
  ` ${Y}--preset <name>${R} Role preset (tech-review/brainstorm/code-review/debate)`,
7829
7833
  ` ${Y}--roles <file>${R} Custom roles JSON file`,
7830
7834
  ` ${Y}--mix [providers]${R} Mixed multi-model: spread providers across roles (e.g. claude,openai,deepseek)`,
7835
+ ` ${Y}--steer${R} Human-in-the-loop: steer/stop between rounds`,
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)`,
7831
7838
  ` ${Y}-c, --context <file>${R} Inject context doc (repeatable: -c a.md -c b.md)`,
7832
7839
  ` ${Y}--task${R} Task mode: agents plan & write code with tools`,
7833
7840
  ` ${Y}--distributed${R} Distributed mode (WebSocket, multi-process)`,
@@ -7885,7 +7892,7 @@ program.command("help").description("Show a comprehensive guide to all aicli fea
7885
7892
  ];
7886
7893
  console.log(lines.join("\n"));
7887
7894
  });
7888
- 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("--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) => {
7889
7896
  const config = new ConfigManager();
7890
7897
  const registry = new ProviderRegistry();
7891
7898
  await registry.initialize(
@@ -7896,7 +7903,7 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
7896
7903
  }),
7897
7904
  config.get("customProviders")
7898
7905
  );
7899
- const { startHub } = await import("./hub-MDQNJOMV.js");
7906
+ const { startHub } = await import("./hub-ZILVZWI2.js");
7900
7907
  await startHub(
7901
7908
  {
7902
7909
  topic: topic ?? "",
@@ -7905,6 +7912,9 @@ program.command("hub [topic]").description("Start multi-agent hub (discuss / bra
7905
7912
  provider: options.provider,
7906
7913
  model: options.model,
7907
7914
  mix: options.mix,
7915
+ steer: options.steer === true,
7916
+ vote: options.vote === true,
7917
+ save: options.save !== false,
7908
7918
  mode: options.task === true ? "task" : void 0,
7909
7919
  maxRounds: options.maxRounds ? parseInt(options.maxRounds, 10) : void 0,
7910
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-LJPB4ZER.js";
4
+ } from "./chunk-JXSWY54M.js";
5
5
  import "./chunk-3RG5ZIWI.js";
6
6
  export {
7
7
  executeTests,