jinzd-ai-cli 0.4.155 → 0.4.156

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 (31) hide show
  1. package/dist/{batch-LS3IJVBK.js → batch-DBOCPVH5.js} +2 -2
  2. package/dist/{chat-index-IF4EINLQ.js → chat-index-2I7ZHRE5.js} +2 -2
  3. package/dist/{chunk-D6GJTJQH.js → chunk-3DCAQKVZ.js} +1 -1
  4. package/dist/{chunk-NFRTSL3N.js → chunk-3SQMKA4I.js} +1 -1
  5. package/dist/{chunk-B3LFGPU2.js → chunk-3WLEDKOW.js} +1 -1
  6. package/dist/{chunk-JXSWY54M.js → chunk-7OCOFVQP.js} +1 -1
  7. package/dist/{chunk-JOJRBV2K.js → chunk-AACNCJMD.js} +1 -1
  8. package/dist/{chunk-CIZQZ7CC.js → chunk-GQ647SF3.js} +2 -2
  9. package/dist/chunk-NZ4X6GUC.js +230 -0
  10. package/dist/{chunk-O6MLS5QO.js → chunk-OJL3PY36.js} +0 -226
  11. package/dist/{hub-ZILVZWI2.js → chunk-Q3ZUDA6S.js} +6 -249
  12. package/dist/{persist-3EBOLHFZ.js → chunk-RUJQ5OUB.js} +1 -2
  13. package/dist/{chunk-IBBYW6PM.js → chunk-UAPNBQLU.js} +1 -1
  14. package/dist/{chunk-E5ICQT3P.js → chunk-Z2UJDFJK.js} +4 -4
  15. package/dist/{ci-34ZQH43L.js → ci-AWA6KC3X.js} +3 -3
  16. package/dist/{constants-DQ5VJOGS.js → constants-QDTWBWWC.js} +1 -1
  17. package/dist/{doctor-cli-TSCI4ORL.js → doctor-cli-4MTG6SFH.js} +6 -6
  18. package/dist/electron-server.js +740 -44
  19. package/dist/hub-QRDXG527.js +260 -0
  20. package/dist/{hub-server-OH7AYQIW.js → hub-server-GSTG5MNE.js} +4 -2
  21. package/dist/index.js +40 -40
  22. package/dist/persist-UI6WRBGB.js +12 -0
  23. package/dist/{run-tests-5KWCHBQS.js → run-tests-CNURD2ST.js} +2 -2
  24. package/dist/{run-tests-5CJRMOMI.js → run-tests-NPWSCWP5.js} +1 -1
  25. package/dist/{server-DVIP7NLW.js → server-HFG2SM3Y.js} +6 -6
  26. package/dist/{server-35OQV62B.js → server-RRUCZMMM.js} +124 -32
  27. package/dist/{task-orchestrator-AXSS7ROD.js → task-orchestrator-GF6ZMNUK.js} +6 -6
  28. package/dist/web/client/app.js +138 -0
  29. package/dist/web/client/index.html +28 -0
  30. package/package.json +1 -1
  31. package/dist/{chunk-U5MY24UZ.js → chunk-MM3F43H6.js} +3 -3
@@ -1,4 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ DiscussionOrchestrator,
4
+ getPreset,
5
+ resolveRoleProviders
6
+ } from "./chunk-Q3ZUDA6S.js";
7
+ import "./chunk-NZ4X6GUC.js";
8
+ import {
9
+ persistDiscussion
10
+ } from "./chunk-RUJQ5OUB.js";
2
11
  import {
3
12
  AuthManager,
4
13
  TOKEN_EXPIRY_MS
@@ -12,28 +21,7 @@ import {
12
21
  loadDevState,
13
22
  persistToolRound,
14
23
  setupProxy
15
- } from "./chunk-CIZQZ7CC.js";
16
- import {
17
- SessionManager,
18
- getContentText
19
- } from "./chunk-TOTEUETI.js";
20
- import {
21
- CONTENT_ONLY_STREAM_REMINDER,
22
- HALLUCINATION_CORRECTION_MESSAGE,
23
- ProviderRegistry,
24
- TEE_FINAL_USER_NUDGE,
25
- TOOL_CALL_REMINDER,
26
- detectMetaNarration,
27
- detectPseudoToolCalls,
28
- detectsHallucinatedFileOp,
29
- hadPreviousWriteToolCalls,
30
- looksLikeDocumentBody,
31
- stripPseudoToolCalls,
32
- stripToolCallReminder
33
- } from "./chunk-AIZOARZY.js";
34
- import {
35
- ConfigManager
36
- } from "./chunk-IBBYW6PM.js";
24
+ } from "./chunk-GQ647SF3.js";
37
25
  import {
38
26
  ToolExecutor,
39
27
  ToolRegistry,
@@ -51,16 +39,37 @@ import {
51
39
  spawnAgentContext,
52
40
  truncateOutput,
53
41
  undoStack
54
- } from "./chunk-E5ICQT3P.js";
42
+ } from "./chunk-Z2UJDFJK.js";
55
43
  import "./chunk-HDSKW7Q3.js";
56
44
  import "./chunk-ZWVIDFGY.js";
57
- import "./chunk-JOJRBV2K.js";
45
+ import "./chunk-AACNCJMD.js";
46
+ import {
47
+ SessionManager,
48
+ getContentText
49
+ } from "./chunk-TOTEUETI.js";
50
+ import {
51
+ CONTENT_ONLY_STREAM_REMINDER,
52
+ HALLUCINATION_CORRECTION_MESSAGE,
53
+ ProviderRegistry,
54
+ TEE_FINAL_USER_NUDGE,
55
+ TOOL_CALL_REMINDER,
56
+ detectMetaNarration,
57
+ detectPseudoToolCalls,
58
+ detectsHallucinatedFileOp,
59
+ hadPreviousWriteToolCalls,
60
+ looksLikeDocumentBody,
61
+ stripPseudoToolCalls,
62
+ stripToolCallReminder
63
+ } from "./chunk-AIZOARZY.js";
58
64
  import {
59
65
  runTool
60
- } from "./chunk-NFRTSL3N.js";
66
+ } from "./chunk-3SQMKA4I.js";
61
67
  import {
62
68
  getDangerLevel
63
69
  } from "./chunk-NXXNLLSG.js";
70
+ import {
71
+ ConfigManager
72
+ } from "./chunk-UAPNBQLU.js";
64
73
  import "./chunk-2ZD3YTVM.js";
65
74
  import {
66
75
  AGENTIC_BEHAVIOR_GUIDELINE,
@@ -80,16 +89,16 @@ import {
80
89
  SKILLS_DIR_NAME,
81
90
  VERSION,
82
91
  buildUserIdentityPrompt
83
- } from "./chunk-B3LFGPU2.js";
92
+ } from "./chunk-3WLEDKOW.js";
84
93
  import {
85
94
  formatGitContextForPrompt,
86
95
  getGitContext,
87
96
  getGitRoot
88
97
  } from "./chunk-HOSJZMQS.js";
89
98
  import "./chunk-4BKXL7SM.js";
90
- import "./chunk-U5MY24UZ.js";
91
- import "./chunk-SLSWPBK3.js";
99
+ import "./chunk-MM3F43H6.js";
92
100
  import "./chunk-KHYD3WXE.js";
101
+ import "./chunk-SLSWPBK3.js";
93
102
  import "./chunk-VNNYHW6N.js";
94
103
  import "./chunk-OVWE4E46.js";
95
104
  import "./chunk-PDX44BCA.js";
@@ -535,6 +544,8 @@ var SessionHandler = class _SessionHandler {
535
544
  abortController = null;
536
545
  userInterjection = null;
537
546
  processing = false;
547
+ /** P4: active hub discussion orchestrator (web room), if any. */
548
+ hubOrchestrator = null;
538
549
  /** Pending ask_user promises */
539
550
  pendingAskUser = /* @__PURE__ */ new Map();
540
551
  /** Pending auto-pause promises */
@@ -673,6 +684,11 @@ var SessionHandler = class _SessionHandler {
673
684
  this.abortController.abort();
674
685
  }
675
686
  return;
687
+ case "hub_start":
688
+ return this.handleHubStart(msg);
689
+ case "hub_abort":
690
+ this.hubOrchestrator?.abort();
691
+ return;
676
692
  case "interjection":
677
693
  this.userInterjection = msg.content;
678
694
  return;
@@ -763,6 +779,82 @@ var SessionHandler = class _SessionHandler {
763
779
  }
764
780
  }
765
781
  // ── Chat handling ────────────────────────────────────────────────
782
+ /**
783
+ * P4: run a multi-agent hub discussion in the browser room. Bridges the
784
+ * UI-agnostic DiscussionOrchestrator (onEvent) to WebSocket hub_event
785
+ * messages, then persists the result (P3) so it can be replayed.
786
+ */
787
+ async handleHubStart(msg) {
788
+ if (this.processing || this.hubOrchestrator) {
789
+ this.send({ type: "error", message: "Already running a request. Abort first." });
790
+ return;
791
+ }
792
+ const topic = (msg.topic ?? "").trim();
793
+ if (!topic) {
794
+ this.send({ type: "error", message: "Hub topic is required." });
795
+ return;
796
+ }
797
+ const preset = getPreset(msg.preset ?? "brainstorm");
798
+ if (!preset) {
799
+ this.send({ type: "error", message: `Unknown preset "${msg.preset}".` });
800
+ return;
801
+ }
802
+ const defaultProvider = this.currentProvider;
803
+ const defaultModel = this.currentModel;
804
+ const resolution = resolveRoleProviders(
805
+ preset.roles,
806
+ {
807
+ has: (id) => this.providers.has(id),
808
+ defaultModelFor: (id) => this.providers.has(id) ? this.providers.get(id).info.defaultModel : void 0
809
+ },
810
+ defaultProvider,
811
+ defaultModel,
812
+ this.providers.listAvailable().map((p) => p.info.id),
813
+ msg.mix
814
+ );
815
+ const roles = resolution.roles;
816
+ for (const w of resolution.warnings) this.send({ type: "info", message: w });
817
+ const config = {
818
+ mode: "discuss",
819
+ roles,
820
+ defaultProvider,
821
+ defaultModel,
822
+ maxRounds: msg.maxRounds && msg.maxRounds > 0 ? Math.min(msg.maxRounds, 20) : 6,
823
+ voteConverge: msg.vote === true
824
+ };
825
+ this.send({
826
+ type: "hub_started",
827
+ topic,
828
+ maxRounds: config.maxRounds,
829
+ roles: roles.map((r) => ({ id: r.id, name: r.name, color: r.color, provider: r.provider, model: r.model }))
830
+ });
831
+ const orchestrator = new DiscussionOrchestrator(config, this.providers);
832
+ this.hubOrchestrator = orchestrator;
833
+ orchestrator.onEvent = (event) => this.send({ type: "hub_event", event });
834
+ this.processing = true;
835
+ try {
836
+ const state = await orchestrator.run(topic);
837
+ let sessionId;
838
+ let saved = false;
839
+ if (state.messages.length > 0) {
840
+ try {
841
+ const res = await persistDiscussion(state, this.config, defaultProvider, defaultModel);
842
+ sessionId = res.id;
843
+ saved = true;
844
+ } catch (err) {
845
+ this.send({ type: "info", message: `Could not save discussion: ${err.message}` });
846
+ }
847
+ }
848
+ this.send({ type: "hub_done", sessionId, saved });
849
+ if (saved) this.sendSessionList();
850
+ } catch (err) {
851
+ this.send({ type: "error", message: `Hub error: ${err.message}` });
852
+ this.send({ type: "hub_done", saved: false });
853
+ } finally {
854
+ this.processing = false;
855
+ this.hubOrchestrator = null;
856
+ }
857
+ }
766
858
  async handleChat(content, images) {
767
859
  if (this.processing) {
768
860
  this.send({ type: "error", message: "Already processing a request. Use abort first." });
@@ -2465,7 +2557,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
2465
2557
  case "test": {
2466
2558
  this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
2467
2559
  try {
2468
- const { executeTests } = await import("./run-tests-5KWCHBQS.js");
2560
+ const { executeTests } = await import("./run-tests-CNURD2ST.js");
2469
2561
  const argStr = args.join(" ").trim();
2470
2562
  let testArgs = {};
2471
2563
  if (argStr) {
@@ -2989,7 +3081,7 @@ Add .md files to create commands.` });
2989
3081
  return;
2990
3082
  }
2991
3083
  try {
2992
- const { searchChatMemory, loadChatIndex } = await import("./chat-index-IF4EINLQ.js");
3084
+ const { searchChatMemory, loadChatIndex } = await import("./chat-index-2I7ZHRE5.js");
2993
3085
  const loaded = loadChatIndex();
2994
3086
  if (!loaded || loaded.idx.chunks.length === 0) {
2995
3087
  this.send({ type: "memory_hits", query: q, hits: [], indexMissing: true });
@@ -3025,7 +3117,7 @@ Add .md files to create commands.` });
3025
3117
  }
3026
3118
  async handleMemoryStatus() {
3027
3119
  try {
3028
- const { getChatIndexStatus } = await import("./chat-index-IF4EINLQ.js");
3120
+ const { getChatIndexStatus } = await import("./chat-index-2I7ZHRE5.js");
3029
3121
  const s = getChatIndexStatus();
3030
3122
  this.send({
3031
3123
  type: "memory_status",
@@ -3050,7 +3142,7 @@ Add .md files to create commands.` });
3050
3142
  type: "info",
3051
3143
  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"
3052
3144
  });
3053
- const { buildChatIndex } = await import("./chat-index-IF4EINLQ.js");
3145
+ const { buildChatIndex } = await import("./chat-index-2I7ZHRE5.js");
3054
3146
  const stats = await buildChatIndex({
3055
3147
  full,
3056
3148
  onProgress: (p) => {
@@ -3,24 +3,24 @@ import {
3
3
  ToolRegistry,
4
4
  googleSearchContext,
5
5
  truncateOutput
6
- } from "./chunk-E5ICQT3P.js";
6
+ } from "./chunk-Z2UJDFJK.js";
7
7
  import "./chunk-HDSKW7Q3.js";
8
8
  import "./chunk-ZWVIDFGY.js";
9
- import "./chunk-JOJRBV2K.js";
9
+ import "./chunk-AACNCJMD.js";
10
10
  import {
11
11
  runTool
12
- } from "./chunk-NFRTSL3N.js";
12
+ } from "./chunk-3SQMKA4I.js";
13
13
  import {
14
14
  getDangerLevel
15
15
  } from "./chunk-NXXNLLSG.js";
16
16
  import "./chunk-2ZD3YTVM.js";
17
17
  import {
18
18
  SUBAGENT_ALLOWED_TOOLS
19
- } from "./chunk-B3LFGPU2.js";
19
+ } from "./chunk-3WLEDKOW.js";
20
20
  import "./chunk-4BKXL7SM.js";
21
- import "./chunk-U5MY24UZ.js";
22
- import "./chunk-SLSWPBK3.js";
21
+ import "./chunk-MM3F43H6.js";
23
22
  import "./chunk-KHYD3WXE.js";
23
+ import "./chunk-SLSWPBK3.js";
24
24
  import "./chunk-VNNYHW6N.js";
25
25
  import "./chunk-OVWE4E46.js";
26
26
  import "./chunk-PDX44BCA.js";
@@ -199,6 +199,9 @@ function handleServerMessage(msg) {
199
199
  case 'memory_rebuild_done': renderMemoryRebuildDone(msg); break;
200
200
  case 'auth_required': showAuthScreen(msg.hasUsers); break;
201
201
  case 'auth_result': handleAuthResult(msg); break;
202
+ case 'hub_started': hubStarted(msg); break;
203
+ case 'hub_event': hubEvent(msg.event); break;
204
+ case 'hub_done': hubDone(msg); break;
202
205
  case 'info': addInfoMessage(msg.message); break;
203
206
  case 'error': addErrorMessage(msg.message); hideRoundProgress(); clearAllToolTimers(); setProcessing(false); break;
204
207
  case 'round_progress': handleRoundProgress(msg); break;
@@ -3109,3 +3112,138 @@ document.querySelectorAll('.sidebar-tab').forEach(btn => {
3109
3112
  btn.addEventListener('click', () => initMemoryPanel());
3110
3113
  }
3111
3114
  });
3115
+
3116
+ // ── Hub multi-agent room (P4) ─────────────────────────────────────
3117
+ // DaisyUI semantic colors map for role legend dots / borders.
3118
+ const HUB_COLORS = { cyan: '#22d3ee', green: '#4ade80', red: '#f87171', magenta: '#e879f9', yellow: '#facc15', blue: '#60a5fa', white: '#e5e7eb' };
3119
+ let hubRoles = {}; // roleId → { name, color, provider, model }
3120
+ let hubStreamEl = null; // current streaming agent message element
3121
+ let hubStreamRoleId = null;
3122
+
3123
+ function hubColor(c) { return HUB_COLORS[c] || '#9ca3af'; }
3124
+
3125
+ window.startHub = function () {
3126
+ const topic = (document.getElementById('hub-topic').value || '').trim();
3127
+ if (!topic) { document.getElementById('hub-status').textContent = 'Enter a topic first.'; return; }
3128
+ send({
3129
+ type: 'hub_start',
3130
+ topic,
3131
+ preset: document.getElementById('hub-preset').value,
3132
+ maxRounds: parseInt(document.getElementById('hub-rounds').value, 10) || 6,
3133
+ mix: document.getElementById('hub-mix').checked,
3134
+ vote: document.getElementById('hub-vote').checked,
3135
+ });
3136
+ document.getElementById('hub-start-btn').classList.add('hidden');
3137
+ document.getElementById('hub-abort-btn').classList.remove('hidden');
3138
+ document.getElementById('hub-status').textContent = 'Starting…';
3139
+ };
3140
+
3141
+ window.abortHub = function () {
3142
+ send({ type: 'hub_abort' });
3143
+ document.getElementById('hub-status').textContent = 'Stopping after current turn…';
3144
+ };
3145
+
3146
+ function hubStarted(msg) {
3147
+ hubRoles = {};
3148
+ for (const r of msg.roles) hubRoles[r.id] = r;
3149
+ hubStreamEl = null; hubStreamRoleId = null;
3150
+
3151
+ const legend = msg.roles.map(r => {
3152
+ const backend = r.provider ? `${r.provider}${r.model ? ':' + r.model : ''}` : '';
3153
+ return `<span class="inline-flex items-center gap-1 mr-2">
3154
+ <span style="width:.6rem;height:.6rem;border-radius:9999px;background:${hubColor(r.color)};display:inline-block"></span>
3155
+ <b>${escapeHtml(r.name)}</b><span class="opacity-50">${backend ? ' · ' + escapeHtml(backend) : ''}</span></span>`;
3156
+ }).join('');
3157
+
3158
+ const el = document.createElement('div');
3159
+ el.className = 'hub-banner border border-base-content/10 rounded-lg p-3 my-2 bg-base-200';
3160
+ el.innerHTML = `<div class="font-bold mb-1">🏛 ${escapeHtml(msg.topic)}</div>
3161
+ <div class="text-xs opacity-70 mb-1">up to ${msg.maxRounds} rounds</div>
3162
+ <div class="text-xs">${legend}</div>`;
3163
+ messagesEl.appendChild(el);
3164
+ scrollToBottom();
3165
+ }
3166
+
3167
+ function hubEvent(ev) {
3168
+ switch (ev.type) {
3169
+ case 'round_start': {
3170
+ const el = document.createElement('div');
3171
+ el.className = 'hub-round text-xs opacity-50 text-center my-2';
3172
+ el.textContent = `── Round ${ev.round}/${ev.maxRounds} ──`;
3173
+ messagesEl.appendChild(el);
3174
+ scrollToBottom();
3175
+ break;
3176
+ }
3177
+ case 'agent_token': {
3178
+ if (hubStreamRoleId !== ev.roleId || !hubStreamEl) {
3179
+ const role = hubRoles[ev.roleId] || { name: ev.roleId, color: 'white' };
3180
+ hubStreamEl = document.createElement('div');
3181
+ hubStreamEl.className = 'hub-msg border-l-2 pl-2 my-2';
3182
+ hubStreamEl.style.borderColor = hubColor(role.color);
3183
+ hubStreamEl.innerHTML = `<div class="text-xs font-bold mb-1" style="color:${hubColor(role.color)}">${escapeHtml(role.name)}</div><div class="hub-body text-sm"></div>`;
3184
+ messagesEl.appendChild(hubStreamEl);
3185
+ hubStreamRoleId = ev.roleId;
3186
+ hubStreamEl._raw = '';
3187
+ }
3188
+ hubStreamEl._raw += ev.token;
3189
+ renderMarkdown(hubStreamEl.querySelector('.hub-body'), hubStreamEl._raw);
3190
+ scrollToBottom();
3191
+ break;
3192
+ }
3193
+ case 'agent_spoke':
3194
+ // Streaming already rendered the body; finalize the stream slot.
3195
+ hubStreamEl = null; hubStreamRoleId = null;
3196
+ break;
3197
+ case 'agent_passed': {
3198
+ const role = hubRoles[ev.roleId] || { name: ev.roleId };
3199
+ const el = document.createElement('div');
3200
+ el.className = 'text-xs opacity-40 italic pl-2 my-1';
3201
+ el.textContent = `${role.name} passed`;
3202
+ messagesEl.appendChild(el);
3203
+ hubStreamEl = null; hubStreamRoleId = null;
3204
+ break;
3205
+ }
3206
+ case 'converge_vote': {
3207
+ const el = document.createElement('div');
3208
+ el.className = 'text-xs text-center opacity-60 my-1';
3209
+ el.textContent = `🗳 Convergence vote: ${ev.converged}/${ev.total} marked [CONVERGED]`;
3210
+ messagesEl.appendChild(el);
3211
+ break;
3212
+ }
3213
+ case 'discussion_end': {
3214
+ const labels = { consensus: 'Consensus reached', vote_converged: '✓ Converged by vote', max_rounds: 'Max rounds reached', human_stop: 'Stopped', user_interrupt: 'Interrupted' };
3215
+ const el = document.createElement('div');
3216
+ el.className = 'text-xs text-center font-semibold my-2 text-success';
3217
+ el.textContent = labels[ev.reason] || ev.reason;
3218
+ messagesEl.appendChild(el);
3219
+ break;
3220
+ }
3221
+ case 'summary': {
3222
+ const el = document.createElement('div');
3223
+ el.className = 'hub-summary border border-success/40 rounded-lg p-3 my-2 bg-success/5';
3224
+ el.innerHTML = `<div class="font-bold mb-1">📋 Summary</div><div class="hub-body text-sm"></div>`;
3225
+ messagesEl.appendChild(el);
3226
+ renderMarkdown(el.querySelector('.hub-body'), ev.content);
3227
+ scrollToBottom();
3228
+ break;
3229
+ }
3230
+ case 'error': {
3231
+ addErrorMessage(`Hub${ev.roleId ? ' (' + ev.roleId + ')' : ''}: ${ev.message}`);
3232
+ hubStreamEl = null; hubStreamRoleId = null;
3233
+ break;
3234
+ }
3235
+ }
3236
+ }
3237
+
3238
+ function hubDone(msg) {
3239
+ document.getElementById('hub-start-btn').classList.remove('hidden');
3240
+ document.getElementById('hub-abort-btn').classList.add('hidden');
3241
+ const status = document.getElementById('hub-status');
3242
+ if (msg.saved && msg.sessionId) {
3243
+ status.innerHTML = `Saved. <a class="link link-primary" onclick="send({type:'command',name:'session',args:['load','${msg.sessionId}']})">Open session</a>`;
3244
+ } else {
3245
+ status.textContent = msg.saved ? 'Saved to history.' : 'Done (not saved).';
3246
+ }
3247
+ hubStreamEl = null; hubStreamRoleId = null;
3248
+ scrollToBottom();
3249
+ }
@@ -186,6 +186,34 @@
186
186
  <div class="text-xs opacity-40 text-center py-4">Type a query above to recall past chats.</div>
187
187
  </div>
188
188
  </div>
189
+
190
+ <!-- Hub tab (P4) — multi-agent brainstorm room -->
191
+ <div id="tab-hub" class="sidebar-tab-content flex flex-col flex-1 overflow-hidden hidden">
192
+ <div class="p-2 flex flex-col gap-2 overflow-y-auto">
193
+ <p class="text-xs opacity-60 leading-snug">Several AI agents discuss a topic in the chat area, then a structured summary is saved to history (open it and hit 🎬 to replay).</p>
194
+ <textarea id="hub-topic" class="textarea textarea-bordered textarea-sm w-full" rows="2" placeholder="Discussion topic…"></textarea>
195
+ <label class="text-xs opacity-70">Preset
196
+ <select id="hub-preset" class="select select-bordered select-xs w-full mt-1">
197
+ <option value="brainstorm">brainstorm — 创意者·分析师·执行者</option>
198
+ <option value="tech-review">tech-review — 架构师·开发者·安全</option>
199
+ <option value="code-review">code-review — 质量·性能·测试</option>
200
+ <option value="debate">debate — 正方·反方·主持人</option>
201
+ </select>
202
+ </label>
203
+ <label class="text-xs opacity-70">Max rounds
204
+ <input id="hub-rounds" type="number" min="1" max="20" value="6" class="input input-bordered input-xs w-full mt-1">
205
+ </label>
206
+ <label class="flex items-center gap-2 text-xs cursor-pointer">
207
+ <input id="hub-mix" type="checkbox" class="checkbox checkbox-xs"> Mix providers (Claude vs GPT vs DeepSeek…)
208
+ </label>
209
+ <label class="flex items-center gap-2 text-xs cursor-pointer">
210
+ <input id="hub-vote" type="checkbox" class="checkbox checkbox-xs" checked> Convergence voting (2/3 ends early)
211
+ </label>
212
+ <button id="hub-start-btn" class="btn btn-primary btn-sm w-full" onclick="startHub()">🏛 Start discussion</button>
213
+ <button id="hub-abort-btn" class="btn btn-error btn-outline btn-xs w-full hidden" onclick="abortHub()">⏹ Stop</button>
214
+ <div id="hub-status" class="text-xs opacity-60"></div>
215
+ </div>
216
+ </div>
189
217
  </aside>
190
218
  <!-- Sidebar resize handle -->
191
219
  <div id="sidebar-resize" class="sidebar-resize-handle" title="Drag to resize sidebar"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jinzd-ai-cli",
3
- "version": "0.4.155",
3
+ "version": "0.4.156",
4
4
  "description": "Cross-platform REPL-style AI CLI with multi-provider support",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import {
3
- redactString
4
- } from "./chunk-SLSWPBK3.js";
5
2
  import {
6
3
  EMBEDDING_DIM,
7
4
  embed,
8
5
  embedOne
9
6
  } from "./chunk-KHYD3WXE.js";
7
+ import {
8
+ redactString
9
+ } from "./chunk-SLSWPBK3.js";
10
10
 
11
11
  // src/memory/chat-index.ts
12
12
  import fs from "fs";