zelari-code 0.4.3 → 0.7.5

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 (127) hide show
  1. package/README.md +42 -0
  2. package/bin/zelari-code.js +1 -1
  3. package/dist/agents/councilApi.js +7 -7
  4. package/dist/agents/councilApi.js.map +1 -1
  5. package/dist/agents/councilDirectives.js +3 -3
  6. package/dist/agents/promoteMember.js +2 -2
  7. package/dist/agents/roles.js +50 -32
  8. package/dist/agents/roles.js.map +1 -1
  9. package/dist/agents/skills/builtin/debugging.js +4 -4
  10. package/dist/agents/skills/builtin/debugging.js.map +1 -1
  11. package/dist/agents/skills/builtin/docs.js +23 -13
  12. package/dist/agents/skills/builtin/docs.js.map +1 -1
  13. package/dist/agents/skills/builtin/git-ops.js +3 -3
  14. package/dist/agents/skills/builtin/git-ops.js.map +1 -1
  15. package/dist/agents/skills/builtin/planning.js +4 -4
  16. package/dist/agents/skills/builtin/planning.js.map +1 -1
  17. package/dist/agents/skills/builtin/refactoring.js +3 -3
  18. package/dist/agents/skills/builtin/refactoring.js.map +1 -1
  19. package/dist/agents/skills/builtin/review.js +9 -9
  20. package/dist/agents/skills/builtin/review.js.map +1 -1
  21. package/dist/agents/skills/builtin/testing.js +3 -3
  22. package/dist/agents/skills/builtin/testing.js.map +1 -1
  23. package/dist/agents/tools.js +2 -9
  24. package/dist/agents/tools.js.map +1 -1
  25. package/dist/cli/app.js +72 -33
  26. package/dist/cli/app.js.map +1 -1
  27. package/dist/cli/compaction.js.map +1 -1
  28. package/dist/cli/components/ChatStream.js +43 -82
  29. package/dist/cli/components/ChatStream.js.map +1 -1
  30. package/dist/cli/components/CollapsibleToolOutput.js +8 -21
  31. package/dist/cli/components/CollapsibleToolOutput.js.map +1 -1
  32. package/dist/cli/components/Header.js +6 -18
  33. package/dist/cli/components/Header.js.map +1 -1
  34. package/dist/cli/components/LiveRegion.js +54 -0
  35. package/dist/cli/components/LiveRegion.js.map +1 -0
  36. package/dist/cli/components/Sidebar.js +33 -31
  37. package/dist/cli/components/Sidebar.js.map +1 -1
  38. package/dist/cli/components/StatusBar.js +42 -0
  39. package/dist/cli/components/StatusBar.js.map +1 -0
  40. package/dist/cli/components/ToolOutput.js +68 -0
  41. package/dist/cli/components/ToolOutput.js.map +1 -0
  42. package/dist/cli/components/toolFormat.js +195 -0
  43. package/dist/cli/components/toolFormat.js.map +1 -0
  44. package/dist/cli/councilDispatcher.js +1 -1
  45. package/dist/cli/councilDispatcher.js.map +1 -1
  46. package/dist/cli/grokOAuth.js +93 -75
  47. package/dist/cli/grokOAuth.js.map +1 -1
  48. package/dist/cli/headless.js +137 -0
  49. package/dist/cli/headless.js.map +1 -0
  50. package/dist/cli/hooks/chatState.js +139 -0
  51. package/dist/cli/hooks/chatState.js.map +1 -0
  52. package/dist/cli/hooks/eventsToMessages.js +42 -11
  53. package/dist/cli/hooks/eventsToMessages.js.map +1 -1
  54. package/dist/cli/hooks/messageHelpers.js +72 -15
  55. package/dist/cli/hooks/messageHelpers.js.map +1 -1
  56. package/dist/cli/hooks/useBatchedMessages.js +71 -0
  57. package/dist/cli/hooks/useBatchedMessages.js.map +1 -0
  58. package/dist/cli/hooks/useChatTurn.js +453 -84
  59. package/dist/cli/hooks/useChatTurn.js.map +1 -1
  60. package/dist/cli/hooks/useSession.js +24 -3
  61. package/dist/cli/hooks/useSession.js.map +1 -1
  62. package/dist/cli/hooks/useSlashDispatch.js +13 -2
  63. package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
  64. package/dist/cli/main.bundled.js +10607 -7889
  65. package/dist/cli/main.bundled.js.map +4 -4
  66. package/dist/cli/main.js +120 -2
  67. package/dist/cli/main.js.map +1 -1
  68. package/dist/cli/mcp/mcpClient.js +152 -0
  69. package/dist/cli/mcp/mcpClient.js.map +1 -0
  70. package/dist/cli/mcp/mcpManager.js +139 -0
  71. package/dist/cli/mcp/mcpManager.js.map +1 -0
  72. package/dist/cli/provider/openai-compatible.js +9 -2
  73. package/dist/cli/provider/openai-compatible.js.map +1 -1
  74. package/dist/cli/refreshRegistry.js +9 -6
  75. package/dist/cli/refreshRegistry.js.map +1 -1
  76. package/dist/cli/runHeadless.js +160 -0
  77. package/dist/cli/runHeadless.js.map +1 -0
  78. package/dist/cli/sessionManager.js +1 -1
  79. package/dist/cli/sessionManager.js.map +1 -1
  80. package/dist/cli/skillSuggest.js +1 -1
  81. package/dist/cli/skillsMd.js +155 -0
  82. package/dist/cli/skillsMd.js.map +1 -0
  83. package/dist/cli/slashHandlers/branch.js +11 -2
  84. package/dist/cli/slashHandlers/branch.js.map +1 -1
  85. package/dist/cli/slashHandlers/git.js +0 -75
  86. package/dist/cli/slashHandlers/git.js.map +1 -1
  87. package/dist/cli/slashHandlers/promoteMember.js +25 -0
  88. package/dist/cli/slashHandlers/promoteMember.js.map +1 -0
  89. package/dist/cli/slashHandlers/skills.js +16 -0
  90. package/dist/cli/slashHandlers/skills.js.map +1 -1
  91. package/dist/cli/slashHandlers/transcript.js +13 -0
  92. package/dist/cli/slashHandlers/transcript.js.map +1 -0
  93. package/dist/cli/slashHandlers/updater.js +40 -0
  94. package/dist/cli/slashHandlers/updater.js.map +1 -0
  95. package/dist/cli/toolRegistry.js +37 -6
  96. package/dist/cli/toolRegistry.js.map +1 -1
  97. package/dist/cli/wizard/firstRun.js +63 -0
  98. package/dist/cli/wizard/firstRun.js.map +1 -0
  99. package/dist/cli/wizard/index.js +150 -0
  100. package/dist/cli/wizard/index.js.map +1 -0
  101. package/dist/cli/wizard/runWizard.js +137 -0
  102. package/dist/cli/wizard/runWizard.js.map +1 -0
  103. package/dist/cli/wizard/useWizardState.js +151 -0
  104. package/dist/cli/wizard/useWizardState.js.map +1 -0
  105. package/dist/cli/workspace/paths.js +20 -13
  106. package/dist/cli/workspace/paths.js.map +1 -1
  107. package/dist/cli/workspace/storage.js +7 -3
  108. package/dist/cli/workspace/storage.js.map +1 -1
  109. package/dist/cli/workspace/stubs.js +122 -44
  110. package/dist/cli/workspace/stubs.js.map +1 -1
  111. package/dist/cli/workspace/toolRegistry.js +2 -2
  112. package/dist/cli/workspace/toolRegistry.js.map +1 -1
  113. package/dist/cli/workspace/workspaceSummary.js +255 -0
  114. package/dist/cli/workspace/workspaceSummary.js.map +1 -0
  115. package/dist/main/core/AgentHarness.js +36 -7
  116. package/dist/main/core/AgentHarness.js.map +1 -1
  117. package/dist/main/core/tools/builtin/listFiles.js +43 -5
  118. package/dist/main/core/tools/builtin/listFiles.js.map +1 -1
  119. package/dist/main/core/tools/builtin/search.js +28 -120
  120. package/dist/main/core/tools/builtin/search.js.map +1 -1
  121. package/package.json +6 -1
  122. package/dist/cli/oauthCallbackServer.js +0 -207
  123. package/dist/cli/oauthCallbackServer.js.map +0 -1
  124. package/dist/main/core/tools/builtin/_walk.js +0 -129
  125. package/dist/main/core/tools/builtin/_walk.js.map +0 -1
  126. package/dist/main/core/tools/builtin/diff.js +0 -477
  127. package/dist/main/core/tools/builtin/diff.js.map +0 -1
@@ -0,0 +1,137 @@
1
+ /**
2
+ * headless — non-interactive CLI mode for CI/CD and scripting.
3
+ *
4
+ * Bypasses Ink entirely. Reads `--task <prompt>`, runs the prompt
5
+ * through the same dispatch path the TUI uses, and serializes the
6
+ * resulting events as one JSON object per line (NDJSON) on stdout.
7
+ *
8
+ * Exit codes:
9
+ * 0 — task completed successfully (last `agent_end.reason === 'completed'`)
10
+ * 1 — user error (missing task, missing API key, invalid flag)
11
+ * 2 — runtime error (provider failure, council exception)
12
+ * 3 — task errored (the agent run itself emitted `agent_end.reason === 'error'`)
13
+ *
14
+ * @public
15
+ * @since 0.5.0
16
+ */
17
+ import { PROVIDERS, resolveApiKeyWithMeta } from './keyStore.js';
18
+ import { getActiveProvider, getModelForProvider } from './providerConfig.js';
19
+ import { openaiCompatibleProvider } from './provider/openai-compatible.js';
20
+ const HELP_TEXT = `zelari-code --headless --task <prompt> [--output json|plain] [--council] [--provider <id>] [--model <name>]
21
+
22
+ Non-interactive mode. Streams BrainEvents as NDJSON to stdout (one JSON
23
+ object per line) or as plain text (just the assistant message text).
24
+
25
+ Exit codes:
26
+ 0 completed
27
+ 1 user error (bad flags, missing API key, ...)
28
+ 2 runtime error (provider failure, council exception)
29
+ 3 agent run errored
30
+ `;
31
+ /**
32
+ * Parse argv for --headless options. Returns null options when
33
+ * --headless is not present (caller should fall through to TUI mode).
34
+ */
35
+ export function parseHeadlessFlags(argv) {
36
+ if (!argv.includes('--headless')) {
37
+ return { options: null };
38
+ }
39
+ let task;
40
+ let output = 'json';
41
+ let useCouncil = false;
42
+ let provider;
43
+ let model;
44
+ for (let i = 0; i < argv.length; i++) {
45
+ const arg = argv[i];
46
+ if (arg === '--headless')
47
+ continue;
48
+ if (arg === '--output') {
49
+ const next = argv[i + 1];
50
+ if (next === 'json' || next === 'plain') {
51
+ output = next;
52
+ i++;
53
+ }
54
+ else {
55
+ return {
56
+ options: null,
57
+ error: `--output requires 'json' or 'plain', got '${next ?? '(missing)'}'`,
58
+ };
59
+ }
60
+ }
61
+ else if (arg === '--task') {
62
+ task = argv[i + 1];
63
+ i++;
64
+ }
65
+ else if (arg === '--council') {
66
+ useCouncil = true;
67
+ }
68
+ else if (arg === '--provider') {
69
+ provider = argv[i + 1];
70
+ i++;
71
+ }
72
+ else if (arg === '--model') {
73
+ model = argv[i + 1];
74
+ i++;
75
+ }
76
+ }
77
+ if (!task || task.trim().length === 0) {
78
+ return { options: null, error: '--headless requires --task <prompt>' };
79
+ }
80
+ return {
81
+ options: { task, output, useCouncil, provider, model },
82
+ };
83
+ }
84
+ /**
85
+ * Print the headless help text to stdout (caller prints to stderr for errors).
86
+ */
87
+ export function printHeadlessHelp() {
88
+ // eslint-disable-next-line no-console
89
+ console.log(HELP_TEXT);
90
+ }
91
+ /**
92
+ * Resolve the API key for a provider; returns null with a reason
93
+ * when the key is missing. Used to fail fast with a clear error
94
+ * instead of failing mid-stream.
95
+ */
96
+ export async function resolveHeadlessKey(providerId) {
97
+ const spec = PROVIDERS.find((p) => p.id === providerId);
98
+ if (!spec) {
99
+ return { error: `unknown provider: '${providerId}'` };
100
+ }
101
+ const resolved = await resolveApiKeyWithMeta(providerId);
102
+ if (!resolved || !resolved.apiKey) {
103
+ return {
104
+ error: `no API key for provider '${providerId}'.\n` +
105
+ `Set the env var ${spec.envVar} or save a key via /login.`,
106
+ };
107
+ }
108
+ // baseUrl lives in providerConfig (customEndpoints) not on StoredKey.
109
+ // Imported lazily to avoid a circular dep at module load.
110
+ const { getCustomEndpoint } = await import('./providerConfig.js');
111
+ const customBase = getCustomEndpoint(providerId);
112
+ return {
113
+ apiKey: resolved.apiKey,
114
+ ...(customBase ? { baseUrl: customBase } : {}),
115
+ };
116
+ }
117
+ /**
118
+ * Determine the effective provider + model for a headless run.
119
+ * Prefers explicit --provider/--model flags, then the active
120
+ * provider from provider.json, then 'openai-compatible' as a
121
+ * last resort.
122
+ */
123
+ export function resolveHeadlessProvider(opts) {
124
+ const provider = opts.provider ?? getActiveProvider().id;
125
+ const model = opts.model ?? getModelForProvider(provider);
126
+ return { provider, model };
127
+ }
128
+ /**
129
+ * Emit one NDJSON line to stdout. Use process.stdout.write directly
130
+ * to avoid the console.log trailing newline (NDJSON convention is
131
+ * one JSON object per line, no extra whitespace).
132
+ */
133
+ export function emitEvent(event) {
134
+ process.stdout.write(JSON.stringify(event) + '\n');
135
+ }
136
+ export { openaiCompatibleProvider };
137
+ //# sourceMappingURL=headless.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"headless.js","sourceRoot":"","sources":["../../src/cli/headless.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,139 @@
1
+ import { formatToolSummary } from '../components/toolFormat.js';
2
+ export const EMPTY_LIVE = { streaming: null, runningTools: [] };
3
+ /**
4
+ * Append a finalized message (system/user/sealed-assistant/completed-tool).
5
+ * Pure helper — callers pass the setter they want to target (the
6
+ * `finalized` setter in production, a plain array setter in tests).
7
+ */
8
+ export function pushFinalized(setFinalized, message) {
9
+ setFinalized((prev) => [...prev, message]);
10
+ }
11
+ /**
12
+ * Update or start the streaming assistant bubble in `live`.
13
+ *
14
+ * - If `live.streaming` exists and (for council) belongs to the same member,
15
+ * replace its content with `fullContent` (the streaming caller always
16
+ * passes full accumulated content, not a delta).
17
+ * - Otherwise create a new streaming bubble stamped with the member context.
18
+ *
19
+ * `setLive` accepts a functional updater so the throttle layer
20
+ * (`useBatchedMessages`-style) can compose multiple updates without reading
21
+ * stale state.
22
+ */
23
+ export function setStreaming(setLive, fullContent, ts, memberContext) {
24
+ setLive((prev) => {
25
+ const cur = prev.streaming;
26
+ if (cur &&
27
+ cur.role === 'assistant' &&
28
+ (cur.memberId ?? null) === (memberContext?.memberId ?? null)) {
29
+ return { ...prev, streaming: { ...cur, content: fullContent, ts } };
30
+ }
31
+ return {
32
+ ...prev,
33
+ streaming: {
34
+ id: `streaming-${crypto.randomUUID()}`,
35
+ role: 'assistant',
36
+ content: fullContent,
37
+ ts,
38
+ ...(memberContext?.memberId ? { memberId: memberContext.memberId } : {}),
39
+ ...(memberContext?.memberName ? { memberName: memberContext.memberName } : {}),
40
+ },
41
+ };
42
+ });
43
+ }
44
+ /**
45
+ * Move `live.streaming` (if any) into `finalized`, sealing it. Drops the
46
+ * `streaming-` id prefix so the next bubble starts fresh. Idempotent: a no-op
47
+ * when nothing is streaming.
48
+ *
49
+ * This is the seal point fired on `message_end` and before a tool call: the
50
+ * bubble is complete and can be printed once into scrollback.
51
+ */
52
+ export function finalizeStreaming(setFinalized, setLive) {
53
+ setLive((prev) => {
54
+ const cur = prev.streaming;
55
+ if (!cur || !cur.id.startsWith('streaming-'))
56
+ return prev;
57
+ const sealed = { ...cur, id: cur.id.slice('streaming-'.length) };
58
+ setFinalized((fin) => [...fin, sealed]);
59
+ return { ...prev, streaming: null };
60
+ });
61
+ }
62
+ /**
63
+ * Max chars of tool result kept in memory for the printed body.
64
+ *
65
+ * v0.7.3: raised from 600 to 8000. The 600-char cut happened BEFORE
66
+ * formatToolResult could parse the JSON envelope — truncated JSON no longer
67
+ * parses, so every long bash/read_file result fell back to the raw escaped
68
+ * envelope (the ugly boxes in the 2026-07-02 live test). Display truncation
69
+ * is line-based in the formatter (ZELARI_TOOL_OUTPUT_LINES); this constant is
70
+ * only a memory bound.
71
+ */
72
+ export const TOOL_RESULT_PREVIEW_CHARS = 8000;
73
+ /** Max chars of the JSON args preview shown on the tool summary line. */
74
+ export const TOOL_ARGS_PREVIEW_CHARS = 120;
75
+ /**
76
+ * Register a tool invocation in `live.runningTools`. The summary (args
77
+ * preview) is computed once; the result body is filled in by
78
+ * {@link completeTool} on `tool_execution_end`.
79
+ */
80
+ export function startTool(setLive, toolName, toolCallId, args, ts) {
81
+ // v0.7.1 (B2): human-readable summary instead of raw-JSON args.
82
+ const argsPreview = formatToolSummary(toolName, args);
83
+ setLive((prev) => ({
84
+ ...prev,
85
+ runningTools: [
86
+ ...prev.runningTools,
87
+ {
88
+ id: crypto.randomUUID(),
89
+ role: 'tool',
90
+ content: argsPreview,
91
+ ts,
92
+ toolName,
93
+ toolCallId,
94
+ toolOk: undefined,
95
+ toolDurationMs: undefined,
96
+ },
97
+ ],
98
+ }));
99
+ }
100
+ /**
101
+ * Mark a running tool as done and move it into `finalized`. Removes it from
102
+ * `live.runningTools` (by `toolCallId`) and appends the completed message —
103
+ * with its result body — to `finalized`.
104
+ *
105
+ * v0.7.3: the previous signature took a `live` snapshot (from `liveRef`) and
106
+ * removed by INDEX inside the functional updater. `liveRef` only updates on
107
+ * render, so for fast tools (start+end within one frame) the snapshot missed
108
+ * the just-started tool (end event dropped → tool stuck in the live region)
109
+ * or, with two ends in one frame, removed the WRONG element. The lookup now
110
+ * happens inside the `setLive` updater against the CURRENT state, keyed by
111
+ * toolCallId — same cross-setter pattern as {@link finalizeStreaming}.
112
+ *
113
+ * No-op if the toolCallId is unknown (defensive against duplicate end events).
114
+ */
115
+ export function completeTool(setFinalized, setLive, toolCallId, isError, durationMs, result) {
116
+ setLive((prev) => {
117
+ const tool = prev.runningTools.find((t) => t.toolCallId === toolCallId && t.toolDurationMs === undefined);
118
+ if (!tool)
119
+ return prev;
120
+ const completed = {
121
+ ...tool,
122
+ toolOk: !isError,
123
+ toolDurationMs: durationMs,
124
+ ...(result !== undefined
125
+ ? {
126
+ toolResult: result.length > TOOL_RESULT_PREVIEW_CHARS
127
+ ? `${result.slice(0, TOOL_RESULT_PREVIEW_CHARS)}…`
128
+ : result,
129
+ }
130
+ : {}),
131
+ };
132
+ setFinalized((fin) => [...fin, completed]);
133
+ return {
134
+ ...prev,
135
+ runningTools: prev.runningTools.filter((t) => t !== tool),
136
+ };
137
+ });
138
+ }
139
+ //# sourceMappingURL=chatState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chatState.js","sourceRoot":"","sources":["../../../src/cli/hooks/chatState.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AA6DhE,MAAM,CAAC,MAAM,UAAU,GAAc,EAAE,SAAS,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC;AAE3E;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,YAAiE,EACjE,OAAoB;IAEpB,YAAY,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAwD,EACxD,WAAmB,EACnB,EAAU,EACV,aAA0D;IAE1D,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACf,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC;QAC3B,IACE,GAAG;YACH,GAAG,CAAC,IAAI,KAAK,WAAW;YACxB,CAAC,GAAG,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE,QAAQ,IAAI,IAAI,CAAC,EAC5D,CAAC;YACD,OAAO,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,EAAE,GAAG,GAAG,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,EAAE,EAAE,CAAC;QACtE,CAAC;QACD,OAAO;YACL,GAAG,IAAI;YACP,SAAS,EAAE;gBACT,EAAE,EAAE,aAAa,MAAM,CAAC,UAAU,EAAE,EAAE;gBACtC,IAAI,EAAE,WAAW;gBACjB,OAAO,EAAE,WAAW;gBACpB,EAAE;gBACF,GAAG,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,aAAa,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACxE,GAAG,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,aAAa,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/E;SACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,YAAiE,EACjE,OAAwD;IAExD,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACf,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC;QAC3B,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1D,MAAM,MAAM,GAAG,EAAE,GAAG,GAAG,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC;QACjE,YAAY,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;QACxC,OAAO,EAAE,GAAG,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,IAAI,CAAC;AAE9C,yEAAyE;AACzE,MAAM,CAAC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAE3C;;;;GAIG;AACH,MAAM,UAAU,SAAS,CACvB,OAAwD,EACxD,QAAgB,EAChB,UAAkB,EAClB,IAAa,EACb,EAAU;IAEV,gEAAgE;IAChE,MAAM,WAAW,GAAG,iBAAiB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACtD,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QACjB,GAAG,IAAI;QACP,YAAY,EAAE;YACZ,GAAG,IAAI,CAAC,YAAY;YACpB;gBACE,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;gBACvB,IAAI,EAAE,MAAM;gBACZ,OAAO,EAAE,WAAW;gBACpB,EAAE;gBACF,QAAQ;gBACR,UAAU;gBACV,MAAM,EAAE,SAAS;gBACjB,cAAc,EAAE,SAAS;aAC1B;SACF;KACF,CAAC,CAAC,CAAC;AACN,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,YAAY,CAC1B,YAAiE,EACjE,OAAwD,EACxD,UAAkB,EAClB,OAAgB,EAChB,UAAkB,EAClB,MAAe;IAEf,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;QACf,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CACjC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,KAAK,UAAU,IAAI,CAAC,CAAC,cAAc,KAAK,SAAS,CACrE,CAAC;QACF,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QACvB,MAAM,SAAS,GAAgB;YAC7B,GAAG,IAAI;YACP,MAAM,EAAE,CAAC,OAAO;YAChB,cAAc,EAAE,UAAU;YAC1B,GAAG,CAAC,MAAM,KAAK,SAAS;gBACtB,CAAC,CAAC;oBACE,UAAU,EACR,MAAM,CAAC,MAAM,GAAG,yBAAyB;wBACvC,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,yBAAyB,CAAC,GAAG;wBAClD,CAAC,CAAC,MAAM;iBACb;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,CAAC;QACF,YAAY,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC;QAC3C,OAAO;YACL,GAAG,IAAI;YACP,YAAY,EAAE,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC;SAC1D,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -26,29 +26,60 @@ export function eventsToMessages(events) {
26
26
  out.push({ id: assistantId, role: 'assistant', content: assistantBuffer, ts: e.ts });
27
27
  }
28
28
  }
29
+ else if (e.type === 'message_end') {
30
+ // Message boundary: the next streamed message gets its own bubble,
31
+ // matching the live UI (which finalizes on message_end).
32
+ assistantBuffer = '';
33
+ assistantId = '';
34
+ }
29
35
  else if (e.type === 'tool_execution_start') {
30
36
  // v0.4.3 audit fix: the v3-W event schema renamed `tool_call` →
31
37
  // `tool_execution_start` and added the `args` field. The old branches
32
38
  // here silently dropped every tool invocation during session resume.
39
+ // v0.6.2: restored as a `role: 'tool'` message so the resumed
40
+ // transcript renders the tool box, same as the live UI.
33
41
  assistantBuffer = '';
34
42
  assistantId = '';
35
- const argsPreview = JSON.stringify(e.args).slice(0, 80);
43
+ const argsPreview = JSON.stringify(e.args)?.slice(0, 120) ?? '';
36
44
  out.push({
37
45
  id: crypto.randomUUID(),
38
- role: 'system',
39
- content: `[tool_call] ${e.toolName}(${argsPreview})`,
46
+ role: 'tool',
47
+ content: argsPreview,
40
48
  ts: e.ts,
49
+ toolName: e.toolName,
50
+ toolCallId: e.toolCallId,
41
51
  });
42
52
  }
43
53
  else if (e.type === 'tool_execution_end') {
44
- // v0.4.3 audit fix: same `tool_result` `tool_execution_end` with
45
- // `isError` / `durationMs` instead of `ok`.
46
- out.push({
47
- id: crypto.randomUUID(),
48
- role: 'system',
49
- content: `[tool_result] ${e.toolName} → ${e.isError ? 'error' : 'ok'}`,
50
- ts: e.ts,
51
- });
54
+ // v0.6.2: update the matching start message in place (the event does
55
+ // NOT carry toolName the old code rendered "[tool_result] undefined").
56
+ const end = e;
57
+ let matched = false;
58
+ for (let i = out.length - 1; i >= 0; i--) {
59
+ const m = out[i];
60
+ if (m.role === 'tool' && m.toolCallId === end.toolCallId && m.toolDurationMs === undefined) {
61
+ // v0.6.2 audit LOW-5: append `…` on truncation to match the
62
+ // live path (messageHelpers.appendToolEnd behavior).
63
+ const raw = typeof end.result === 'string' ? end.result : '';
64
+ const truncated = raw.length > 600 ? `${raw.slice(0, 600)}…` : raw;
65
+ out[i] = {
66
+ ...m,
67
+ toolOk: !end.isError,
68
+ toolDurationMs: end.durationMs,
69
+ ...(raw.length > 0 ? { toolResult: truncated } : {}),
70
+ };
71
+ matched = true;
72
+ break;
73
+ }
74
+ }
75
+ if (!matched) {
76
+ out.push({
77
+ id: crypto.randomUUID(),
78
+ role: 'system',
79
+ content: `[tool_result] ${end.toolCallId} → ${end.isError ? 'error' : 'ok'}`,
80
+ ts: e.ts,
81
+ });
82
+ }
52
83
  }
53
84
  else if (e.type === 'agent_start') {
54
85
  out.push({
@@ -1 +1 @@
1
- {"version":3,"file":"eventsToMessages.js","sourceRoot":"","sources":["../../../src/cli/hooks/eventsToMessages.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"eventsToMessages.js","sourceRoot":"","sources":["../../../src/cli/hooks/eventsToMessages.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,4 @@
1
+ import { formatToolSummary } from '../components/toolFormat.js';
1
2
  /**
2
3
  * Helpers for building ChatMessage instances in the most common shapes.
3
4
  *
@@ -29,8 +30,12 @@ export function appendUser(setMessages, content, ts = Date.now()) {
29
30
  * Append or extend the streaming assistant message. If the last message is
30
31
  * already a streaming assistant message, append `delta` to its content;
31
32
  * otherwise create a new one with a stable streaming id.
33
+ *
34
+ * When `memberName` is set (council-sourced messages), it's stamped on
35
+ * the message so the visible-reasoning UI can render `🜂 Caronte: …`
36
+ * headers above the streamed text.
32
37
  */
33
- export function appendOrExtendStreamingAssistant(setMessages, fullContent, ts) {
38
+ export function appendOrExtendStreamingAssistant(setMessages, fullContent, ts, memberContext) {
34
39
  setMessages((prev) => {
35
40
  const last = prev[prev.length - 1];
36
41
  if (last && last.role === 'assistant' && last.id.startsWith('streaming-')) {
@@ -38,23 +43,54 @@ export function appendOrExtendStreamingAssistant(setMessages, fullContent, ts) {
38
43
  }
39
44
  return [
40
45
  ...prev,
41
- { id: `streaming-${crypto.randomUUID()}`, role: 'assistant', content: fullContent, ts },
46
+ {
47
+ id: `streaming-${crypto.randomUUID()}`,
48
+ role: 'assistant',
49
+ content: fullContent,
50
+ ts,
51
+ ...(memberContext?.memberId ? { memberId: memberContext.memberId } : {}),
52
+ ...(memberContext?.memberName ? { memberName: memberContext.memberName } : {}),
53
+ },
42
54
  ];
43
55
  });
44
56
  }
45
- /** Append a tool invocation indicator (▶ name(args) or ✓/✗ result). */
46
- export function appendToolStart(setMessages, toolName, args, ts) {
47
- const argsPreview = JSON.stringify(args).slice(0, 120);
48
- appendSystem(setMessages, `▶ ${toolName}(${argsPreview})`, ts);
49
- }
50
- /** Append a tool result indicator. */
51
- export function appendToolEnd(setMessages, result, isError, durationMs, ts) {
52
- const preview = result.slice(0, 200);
53
- const icon = isError ? '✗' : '✓';
54
- appendSystem(setMessages, `${icon} ${preview}${result.length > 200 ? '…' : ''} (${durationMs}ms)`, ts);
57
+ /**
58
+ * Max chars of tool result kept for the body. v0.7.3: raised 600 → 8000 to
59
+ * match chatState.ts — the 600-char cut chopped the JSON envelope before
60
+ * formatToolResult could parse it, forcing the raw-escaped fallback.
61
+ */
62
+ export const TOOL_RESULT_PREVIEW_CHARS = 8000;
63
+ /** Max chars of the JSON args preview shown on the tool summary line. */
64
+ export const TOOL_ARGS_PREVIEW_CHARS = 120;
65
+ /**
66
+ * Append a tool invocation as a `role: 'tool'` message so ChatStream renders
67
+ * it via the live region's tool rendering (one status line per invocation, updated in
68
+ * place by {@link updateToolMessageEnd}) instead of loose system lines.
69
+ */
70
+ export function appendToolStart(setMessages, toolName, toolCallId, args, ts) {
71
+ // v0.7.1 (B2): human-readable summary instead of raw-JSON args (which cut
72
+ // mid-string like {"path":"…","content":"Scrivi una spiegazione estrema…").
73
+ const argsPreview = formatToolSummary(toolName, args);
74
+ setMessages((prev) => [
75
+ ...prev,
76
+ {
77
+ id: crypto.randomUUID(),
78
+ role: 'tool',
79
+ content: argsPreview,
80
+ ts,
81
+ toolName,
82
+ toolCallId,
83
+ toolOk: undefined,
84
+ toolDurationMs: undefined,
85
+ },
86
+ ]);
55
87
  }
56
- /** Update the matching `tool_execution_start` message with its end status. */
57
- export function updateToolMessageEnd(setMessages, toolCallId, isError, durationMs) {
88
+ /**
89
+ * Update the matching `tool_execution_start` message with its end status.
90
+ * The summary (args preview) is kept; the result is stored separately as the
91
+ * expandable body. Failed invocations auto-expand in ChatStream.
92
+ */
93
+ export function updateToolMessageEnd(setMessages, toolCallId, isError, durationMs, result) {
58
94
  setMessages((prev) => {
59
95
  for (let i = prev.length - 1; i >= 0; i--) {
60
96
  const m = prev[i];
@@ -64,7 +100,13 @@ export function updateToolMessageEnd(setMessages, toolCallId, isError, durationM
64
100
  ...m,
65
101
  toolOk: !isError,
66
102
  toolDurationMs: durationMs,
67
- content: `${m.toolName ?? 'tool'}${isError ? ' → error' : ' → ok'} (${durationMs}ms)`,
103
+ ...(result !== undefined
104
+ ? {
105
+ toolResult: result.length > TOOL_RESULT_PREVIEW_CHARS
106
+ ? `${result.slice(0, TOOL_RESULT_PREVIEW_CHARS)}…`
107
+ : result,
108
+ }
109
+ : {}),
68
110
  };
69
111
  return updated;
70
112
  }
@@ -72,4 +114,19 @@ export function updateToolMessageEnd(setMessages, toolCallId, isError, durationM
72
114
  return prev;
73
115
  });
74
116
  }
117
+ /**
118
+ * Seal the trailing streaming assistant message (if any) by dropping its
119
+ * `streaming-` id prefix. Called on `message_end` so the NEXT assistant
120
+ * message in the same turn (e.g. after a tool call) starts a fresh bubble
121
+ * instead of being merged into — or duplicated over — the previous one.
122
+ */
123
+ export function finalizeStreamingAssistant(setMessages) {
124
+ setMessages((prev) => {
125
+ const last = prev[prev.length - 1];
126
+ if (last && last.role === 'assistant' && last.id.startsWith('streaming-')) {
127
+ return [...prev.slice(0, -1), { ...last, id: last.id.slice('streaming-'.length) }];
128
+ }
129
+ return prev;
130
+ });
131
+ }
75
132
  //# sourceMappingURL=messageHelpers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"messageHelpers.js","sourceRoot":"","sources":["../../../src/cli/hooks/messageHelpers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"messageHelpers.js","sourceRoot":"","sources":["../../../src/cli/hooks/messageHelpers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import { useCallback, useEffect, useRef } from 'react';
2
+ export function useBatchedMessages(state, setState, cadenceMs = 16) {
3
+ // Composed pending updater, or `null` when nothing is buffered.
4
+ const pendingRef = useRef(null);
5
+ // Active throttle-window timer handle, or `null` when not throttling.
6
+ const timerRef = useRef(null);
7
+ /**
8
+ * Apply the current pending updater to state, ignoring/clearing the timer.
9
+ * Used as the synchronous public drain (stream end) and internally.
10
+ */
11
+ const flush = useCallback(() => {
12
+ if (timerRef.current !== null) {
13
+ clearTimeout(timerRef.current);
14
+ timerRef.current = null;
15
+ }
16
+ const pending = pendingRef.current;
17
+ pendingRef.current = null;
18
+ if (pending !== null) {
19
+ setState(pending);
20
+ }
21
+ }, [setState]);
22
+ const commit = useCallback((update) => {
23
+ // Type guard: SetStateAction<S> = S | ((prev: S) => S). Because a generic
24
+ // S may itself be a function type, `typeof x === 'function'` doesn't
25
+ // narrow; resolve via a guarded call helper instead.
26
+ const apply = (action, prev) => typeof action === 'function' ? action(prev) : action;
27
+ // Compose this update onto any pending one, preserving arrival order.
28
+ const head = pendingRef.current;
29
+ pendingRef.current =
30
+ head === null
31
+ ? update
32
+ : (s) => {
33
+ const intermediate = apply(head, s);
34
+ return apply(update, intermediate);
35
+ };
36
+ if (timerRef.current === null) {
37
+ // Leading edge: not currently throttling. Flush immediately so the
38
+ // first token renders with no latency, then open a throttle window.
39
+ const leading = pendingRef.current;
40
+ pendingRef.current = null;
41
+ if (leading !== null) {
42
+ setState(leading);
43
+ }
44
+ timerRef.current = setTimeout(() => {
45
+ timerRef.current = null;
46
+ // Trailing edge: flush anything that accumulated during the window
47
+ // as a single render. Do NOT re-arm — the next commit starts a new
48
+ // leading edge.
49
+ const tail = pendingRef.current;
50
+ pendingRef.current = null;
51
+ if (tail !== null) {
52
+ setState(tail);
53
+ }
54
+ }, cadenceMs);
55
+ }
56
+ // else: inside a throttle window — the trailing handler above will
57
+ // catch the buffered update when the window closes.
58
+ }, [cadenceMs, setState]);
59
+ // On unmount: cancel any pending timer. Do NOT flush — teardown means the
60
+ // display is going away, and persisted state lives in the JSONL writer.
61
+ useEffect(() => {
62
+ return () => {
63
+ if (timerRef.current !== null) {
64
+ clearTimeout(timerRef.current);
65
+ timerRef.current = null;
66
+ }
67
+ };
68
+ }, []);
69
+ return { state, commit, flush, setState };
70
+ }
71
+ //# sourceMappingURL=useBatchedMessages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBatchedMessages.js","sourceRoot":"","sources":["../../../src/cli/hooks/useBatchedMessages.ts"],"names":[],"mappings":"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"}