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
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  CONFIG_DIR_NAME,
4
4
  VERSION
5
- } from "./chunk-D62BVFP7.js";
5
+ } from "./chunk-B3LFGPU2.js";
6
6
 
7
7
  // src/diagnostics/crash-log.ts
8
8
  import {
@@ -5,10 +5,10 @@ import {
5
5
  } from "./chunk-HDSKW7Q3.js";
6
6
  import {
7
7
  runTestsTool
8
- } from "./chunk-OT2HLGSO.js";
8
+ } from "./chunk-JOJRBV2K.js";
9
9
  import {
10
10
  runTool
11
- } from "./chunk-EYJQJZJ6.js";
11
+ } from "./chunk-NFRTSL3N.js";
12
12
  import {
13
13
  getDangerLevel,
14
14
  isFileWriteTool
@@ -25,14 +25,14 @@ import {
25
25
  SUBAGENT_ALLOWED_TOOLS,
26
26
  SUBAGENT_DEFAULT_MAX_ROUNDS,
27
27
  SUBAGENT_MAX_ROUNDS_LIMIT
28
- } from "./chunk-D62BVFP7.js";
28
+ } from "./chunk-B3LFGPU2.js";
29
29
  import {
30
30
  fileCheckpoints
31
31
  } from "./chunk-4BKXL7SM.js";
32
32
  import {
33
33
  loadChatIndex,
34
34
  searchChatMemory
35
- } from "./chunk-RXM76HB7.js";
35
+ } from "./chunk-U5MY24UZ.js";
36
36
  import {
37
37
  indexProject
38
38
  } from "./chunk-VNNYHW6N.js";
@@ -8,7 +8,7 @@ import {
8
8
  CONFIG_FILE_NAME,
9
9
  HISTORY_DIR_NAME,
10
10
  PLUGINS_DIR_NAME
11
- } from "./chunk-D62BVFP7.js";
11
+ } from "./chunk-B3LFGPU2.js";
12
12
 
13
13
  // src/config/config-manager.ts
14
14
  import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  TEST_TIMEOUT
4
- } from "./chunk-D62BVFP7.js";
4
+ } from "./chunk-B3LFGPU2.js";
5
5
 
6
6
  // src/tools/builtin/run-tests.ts
7
7
  import { execSync, spawnSync } from "child_process";
@@ -6,7 +6,7 @@ import { platform } from "os";
6
6
  import chalk from "chalk";
7
7
 
8
8
  // src/core/constants.ts
9
- var VERSION = "0.4.153";
9
+ var VERSION = "0.4.155";
10
10
  var APP_NAME = "ai-cli";
11
11
  var CONFIG_DIR_NAME = ".aicli";
12
12
  var CONFIG_FILE_NAME = "config.json";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  CONFIG_DIR_NAME
4
- } from "./chunk-D62BVFP7.js";
4
+ } from "./chunk-B3LFGPU2.js";
5
5
 
6
6
  // src/diagnostics/tool-stats.ts
7
7
  import { existsSync, readFileSync, writeFileSync, mkdirSync, renameSync } from "fs";
@@ -1,7 +1,33 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ // src/hub/convergence.ts
4
+ function convergenceThreshold(total) {
5
+ if (total <= 0) return Infinity;
6
+ return Math.ceil(total * 2 / 3);
7
+ }
8
+ function isConverged(convergedCount, total) {
9
+ if (convergedCount <= 0) return false;
10
+ return convergedCount >= convergenceThreshold(total);
11
+ }
12
+ var CONVERGED_MARKER = /\[CONVERGED\]/i;
13
+ function hasConvergedMarker(content) {
14
+ return CONVERGED_MARKER.test(content);
15
+ }
16
+ function stripConvergedMarker(content) {
17
+ return content.replace(/\s*\[CONVERGED\]\s*/gi, " ").trim();
18
+ }
19
+
3
20
  // src/hub/agent.ts
4
21
  var PASS_MARKER = "[PASS]";
22
+ function parseTurn(raw) {
23
+ const trimmed = raw.trim();
24
+ const upper = trimmed.toUpperCase();
25
+ if (upper.startsWith(PASS_MARKER) || upper === PASS_MARKER) {
26
+ return { content: "", passed: true, converged: false };
27
+ }
28
+ const converged = hasConvergedMarker(trimmed);
29
+ return { content: converged ? stripConvergedMarker(trimmed) : trimmed, passed: false, converged };
30
+ }
5
31
  var HubAgent = class {
6
32
  role;
7
33
  providers;
@@ -27,12 +53,12 @@ var HubAgent = class {
27
53
  *
28
54
  * Returns a DiscussionMessage, with `passed: true` if the agent outputs [PASS].
29
55
  */
30
- async speak(topic, history, round, maxRounds) {
56
+ async speak(topic, history, round, maxRounds, opts) {
31
57
  const provider = this.providers.get(this.providerId);
32
58
  if (!provider) {
33
59
  throw new Error(`Provider "${this.providerId}" not available for agent "${this.role.id}"`);
34
60
  }
35
- const systemPrompt = this.buildSystemPrompt(topic, round, maxRounds);
61
+ const systemPrompt = this.buildSystemPrompt(topic, round, maxRounds, opts?.voteConverge);
36
62
  const messages = this.buildMessages(history);
37
63
  const response = await provider.chat({
38
64
  messages,
@@ -42,31 +68,31 @@ var HubAgent = class {
42
68
  temperature: 0.7,
43
69
  maxTokens: 4096
44
70
  });
45
- const content = response.content.trim();
46
- const passed = content.toUpperCase().startsWith(PASS_MARKER) || content.toUpperCase() === PASS_MARKER;
71
+ const { content, passed, converged } = parseTurn(response.content);
47
72
  return {
48
73
  speaker: this.role.id,
49
74
  speakerName: this.role.name,
50
- content: passed ? "" : content,
75
+ content,
51
76
  timestamp: /* @__PURE__ */ new Date(),
52
- passed
77
+ passed,
78
+ converged
53
79
  };
54
80
  }
55
81
  /**
56
82
  * Streaming version of speak() — yields tokens as they arrive.
57
83
  * Falls back to non-streaming speak() if the provider doesn't support chatStream.
58
84
  */
59
- async speakStream(topic, history, round, maxRounds, onToken) {
85
+ async speakStream(topic, history, round, maxRounds, onToken, opts) {
60
86
  const provider = this.providers.get(this.providerId);
61
87
  if (!provider) {
62
88
  throw new Error(`Provider "${this.providerId}" not available for agent "${this.role.id}"`);
63
89
  }
64
90
  if (!provider.chatStream) {
65
- return this.speak(topic, history, round, maxRounds);
91
+ return this.speak(topic, history, round, maxRounds, opts);
66
92
  }
67
- const systemPrompt = this.buildSystemPrompt(topic, round, maxRounds);
93
+ const systemPrompt = this.buildSystemPrompt(topic, round, maxRounds, opts?.voteConverge);
68
94
  const messages = this.buildMessages(history);
69
- let content = "";
95
+ let raw = "";
70
96
  const stream = provider.chatStream({
71
97
  messages,
72
98
  model: this.modelId,
@@ -77,18 +103,18 @@ var HubAgent = class {
77
103
  });
78
104
  for await (const chunk of stream) {
79
105
  if (chunk.delta) {
80
- content += chunk.delta;
106
+ raw += chunk.delta;
81
107
  onToken?.(chunk.delta);
82
108
  }
83
109
  }
84
- content = content.trim();
85
- const passed = content.toUpperCase().startsWith(PASS_MARKER) || content.toUpperCase() === PASS_MARKER;
110
+ const { content, passed, converged } = parseTurn(raw);
86
111
  return {
87
112
  speaker: this.role.id,
88
113
  speakerName: this.role.name,
89
- content: passed ? "" : content,
114
+ content,
90
115
  timestamp: /* @__PURE__ */ new Date(),
91
- passed
116
+ passed,
117
+ converged
92
118
  };
93
119
  }
94
120
  /**
@@ -116,11 +142,13 @@ var HubAgent = class {
116
142
  return response.content.trim();
117
143
  }
118
144
  // ── Private ──────────────────────────────────────────────────────
119
- buildSystemPrompt(topic, round, maxRounds) {
145
+ buildSystemPrompt(topic, round, maxRounds, voteConverge) {
120
146
  const contextSection = this.context ? `
121
147
 
122
148
  ## Reference Documents
123
149
  ${this.context}` : "";
150
+ const convergeRule = voteConverge ? `
151
+ - If you believe the group has reached a sufficient conclusion and further rounds would add little, append the marker [CONVERGED] at the very end of your message (you may still make your substantive point above it). When a 2/3 majority converges, the discussion ends.` : "";
124
152
  return `# Multi-Agent Discussion \u2014 Role: ${this.role.name}
125
153
 
126
154
  ${this.role.persona}
@@ -130,7 +158,7 @@ ${this.role.persona}
130
158
  - You can see what other participants have said. Build on their ideas, challenge them, or add your own perspective.
131
159
  - Stay in character as ${this.role.name}. Respond from your role's expertise and viewpoint.
132
160
  - Keep responses concise and focused (2-6 paragraphs). Do not repeat what others have already said.
133
- - If you have nothing meaningful to add (others have covered your points), respond with exactly: [PASS]
161
+ - If you have nothing meaningful to add (others have covered your points), respond with exactly: [PASS]${convergeRule}
134
162
  - This is round ${round} of ${maxRounds}. ${round >= maxRounds - 1 ? "This is one of the final rounds \u2014 try to converge on conclusions." : ""}
135
163
  - Use the language that the topic is written in (if the topic is in Chinese, respond in Chinese).
136
164
 
@@ -184,13 +212,15 @@ ${topic}
184
212
  ${transcript}
185
213
 
186
214
  ## Instructions
187
- Produce a summary that includes:
188
- 1. **Key Points of Agreement** \u2014 what all participants agreed on
189
- 2. **Points of Debate** \u2014 where participants disagreed and the different perspectives
190
- 3. **Conclusions & Recommendations** \u2014 actionable takeaways
191
- 4. **Open Questions** \u2014 unresolved issues that need further discussion
215
+ Produce a structured, decision-oriented synthesis with these exact sections:
216
+
217
+ 1. **Decision / Recommendation** \u2014 the single clearest recommendation the discussion points to. If the group genuinely did not converge, say so and give the leading option plus what would settle it.
218
+ 2. **Key Points of Agreement** \u2014 what participants agreed on.
219
+ 3. **Points of Debate** \u2014 where they disagreed, with the competing perspectives.
220
+ 4. **Action Items** \u2014 concrete next steps as a checklist. For each, suggest which role/expertise should own it, e.g. "- [ ] (\u67B6\u6784\u5E08) \u8BC4\u4F30\u670D\u52A1\u62C6\u5206\u8FB9\u754C".
221
+ 5. **Risks & Open Questions** \u2014 unresolved issues and what to watch.
192
222
 
193
- Keep the summary concise (within 500 words). Use the same language as the discussion.`;
223
+ Keep it tight (within ~600 words). Use the same language as the discussion.`;
194
224
  }
195
225
  };
196
226
 
@@ -358,9 +388,18 @@ function renderHubEvent(event) {
358
388
  clearSpeakingLine();
359
389
  streamHeaderPrinted = false;
360
390
  break;
391
+ case "converge_vote":
392
+ console.log(chalk.dim(` \u{1F5F3} Convergence vote: ${event.converged}/${event.total} agent(s) marked [CONVERGED]`));
393
+ break;
394
+ case "human_steer":
395
+ console.log(chalk.cyan(` \u{1F9ED} You steered: ${truncate(event.message, 80)}`));
396
+ console.log();
397
+ break;
361
398
  case "discussion_end":
362
399
  if (event.reason === "consensus") renderConsensus();
400
+ else if (event.reason === "vote_converged") console.log(chalk.bold.green("\n \u2713 Converged by vote (2/3 majority).\n"));
363
401
  else if (event.reason === "max_rounds") renderMaxRounds(event.maxRounds ?? 0);
402
+ else if (event.reason === "human_stop") console.log(chalk.bold.yellow("\n \u23F9 Stopped by you \u2014 generating summary.\n"));
364
403
  else renderUserInterrupt();
365
404
  break;
366
405
  case "summary":
@@ -379,6 +418,7 @@ function stripAnsi(s) {
379
418
  }
380
419
 
381
420
  export {
421
+ isConverged,
382
422
  HubAgent,
383
423
  assignRoleColors,
384
424
  renderHubBanner,
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/security/redactor.ts
4
+ var DEFAULT_PATTERNS = [
5
+ // password: xxx / password = xxx / password="xxx"
6
+ // Covers YAML / JSON / shell-ish / env-file forms.
7
+ { kind: "password", regex: /\b(password|passwd|pwd)\s*[:=]\s*["']?([^\s"',;{}]{4,200})["']?/gi },
8
+ // PGPASSWORD=xxx (explicit bash env-var form, separate rule because no quotes usually)
9
+ { kind: "pgpassword-env", regex: /\b(PGPASSWORD)=([^\s"']{4,200})/g },
10
+ // JDBC/PG/MySQL/Mongo connection strings with inline credentials
11
+ // postgresql://user:pass@host/db → redact pass
12
+ { kind: "db-uri-password", regex: /(\b(?:postgres(?:ql)?|mysql|mongodb(?:\+srv)?|redis|amqp|mssql):\/\/[^:\s]+:)([^@\s]+)(@)/gi },
13
+ // Anthropic API keys
14
+ { kind: "anthropic-key", regex: /(sk-ant-[a-zA-Z0-9_-]{90,})/g },
15
+ // L6 (v0.4.108): Zhipu / GLM API keys — `<24+ hex/base64-ish>.<32+>`
16
+ // Two segments separated by a dot, each safely identifiable by length
17
+ // and char class. Conservative on the lower bound so we don't eat
18
+ // version strings like `1.0.0` or filenames.
19
+ { kind: "zhipu-key", regex: /\b([a-zA-Z0-9]{24,}\.[a-zA-Z0-9]{32,})\b/g },
20
+ // OpenAI / generic sk- keys — requires length ≥32 to avoid eating short identifiers
21
+ { kind: "openai-key", regex: /(sk-(?:proj-)?[a-zA-Z0-9_-]{32,})/g },
22
+ // GitHub personal access tokens
23
+ { kind: "github-pat", regex: /\b(ghp_[a-zA-Z0-9]{36})\b/g },
24
+ { kind: "github-oauth", regex: /\b(gho_[a-zA-Z0-9]{36})\b/g },
25
+ { kind: "github-install", regex: /\b(ghs_[a-zA-Z0-9]{36})\b/g },
26
+ // Slack tokens
27
+ { kind: "slack-bot", regex: /\b(xoxb-\d+-\d+-[a-zA-Z0-9]+)\b/g },
28
+ { kind: "slack-user", regex: /\b(xoxp-\d+-\d+-\d+-[a-zA-Z0-9]+)\b/g },
29
+ // AWS access key IDs (AKIA...) and secret access keys are context-dependent;
30
+ // we only catch the ID because secret key alone is indistinguishable from random base64.
31
+ { kind: "aws-access-key-id", regex: /\b(AKIA[0-9A-Z]{16})\b/g },
32
+ // Google API keys
33
+ { kind: "google-api-key", regex: /\b(AIza[0-9A-Za-z_-]{35})\b/g },
34
+ // Generic "api_key": "..." / "apiKey": "..." / api-key=xxx
35
+ { kind: "api-key", regex: /\b(api[_-]?key)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{16,200})["']?/gi },
36
+ // Generic token: xxx (only when value looks token-shaped; avoids eating human prose)
37
+ { kind: "token", regex: /\b(token|access[_-]?token|bearer[_-]?token)\s*[:=]\s*["']?([a-zA-Z0-9_\-.]{20,300})["']?/gi },
38
+ // Bearer <token> in Authorization headers
39
+ { kind: "bearer", regex: /\b(Authorization:\s*Bearer\s+)([a-zA-Z0-9_\-.=]{20,500})/g },
40
+ // Private key PEM blocks — catch the header+footer together
41
+ { kind: "private-key", regex: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g }
42
+ ];
43
+ var MAX_CUSTOM = 32;
44
+ var MAX_PATTERN_LEN = 500;
45
+ var SUSPICIOUS_REDOS = /\([^)]*[+*][^)]*\)\s*[+*{]/;
46
+ function render(placeholder, kind) {
47
+ return placeholder.replace("{kind}", kind);
48
+ }
49
+ function redactString(input, options) {
50
+ if (!options.enabled || !input) return { redacted: input, hits: [] };
51
+ const placeholder = options.placeholder ?? "[REDACTED:{kind}]";
52
+ const customSrcs = (options.customRegexes ?? []).slice(0, MAX_CUSTOM);
53
+ const patterns = [
54
+ ...options.patterns ?? DEFAULT_PATTERNS,
55
+ ...customSrcs.flatMap((src, i) => {
56
+ if (typeof src !== "string" || src.length === 0 || src.length > MAX_PATTERN_LEN) return [];
57
+ try {
58
+ const flags = src.match(/^\/.*\/([gimsuy]*)$/)?.[1] ?? "";
59
+ const body = src.replace(/^\/(.*)\/[gimsuy]*$/, "$1");
60
+ if (SUSPICIOUS_REDOS.test(body)) return [];
61
+ const regex = new RegExp(body, flags.includes("g") ? flags : flags + "g");
62
+ return [{ kind: `custom-${i}`, regex }];
63
+ } catch {
64
+ return [];
65
+ }
66
+ })
67
+ ];
68
+ let redacted = input;
69
+ const hits = [];
70
+ for (const { kind, regex } of patterns) {
71
+ const rx = new RegExp(regex.source, regex.flags);
72
+ const captureCount = new RegExp(rx.source + "|").exec("").length - 1;
73
+ redacted = redacted.replace(rx, (...args) => {
74
+ const match = args[0];
75
+ const g1 = captureCount >= 1 ? args[1] : void 0;
76
+ const g2 = captureCount >= 2 ? args[2] : void 0;
77
+ const offset = args[1 + captureCount];
78
+ if (captureCount >= 2 && typeof g2 === "string") {
79
+ hits.push({ kind, start: offset + (g1?.length ?? 0), length: g2.length, secret: g2 });
80
+ return `${g1}${render(placeholder, kind)}`;
81
+ }
82
+ hits.push({ kind, start: offset, length: match.length, secret: g1 ?? match });
83
+ return render(placeholder, kind);
84
+ });
85
+ }
86
+ return { redacted, hits };
87
+ }
88
+ function redactJson(value, options) {
89
+ if (!options.enabled) return { value, hits: [] };
90
+ const allHits = [];
91
+ function walk(v) {
92
+ if (typeof v === "string") {
93
+ const r = redactString(v, options);
94
+ allHits.push(...r.hits);
95
+ return r.redacted;
96
+ }
97
+ if (Array.isArray(v)) return v.map(walk);
98
+ if (v && typeof v === "object") {
99
+ const out = {};
100
+ for (const [k, vv] of Object.entries(v)) {
101
+ out[k] = walk(vv);
102
+ }
103
+ return out;
104
+ }
105
+ return v;
106
+ }
107
+ const redacted = walk(value);
108
+ return { value: redacted, hits: allHits };
109
+ }
110
+ function scanString(input, options) {
111
+ const { hits } = redactString(input, { ...options, enabled: true });
112
+ return hits;
113
+ }
114
+
115
+ export {
116
+ DEFAULT_PATTERNS,
117
+ redactString,
118
+ redactJson,
119
+ scanString
120
+ };