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.
- package/README.md +42 -0
- package/bin/zelari-code.js +1 -1
- package/dist/agents/councilApi.js +7 -7
- package/dist/agents/councilApi.js.map +1 -1
- package/dist/agents/councilDirectives.js +3 -3
- package/dist/agents/promoteMember.js +2 -2
- package/dist/agents/roles.js +50 -32
- package/dist/agents/roles.js.map +1 -1
- package/dist/agents/skills/builtin/debugging.js +4 -4
- package/dist/agents/skills/builtin/debugging.js.map +1 -1
- package/dist/agents/skills/builtin/docs.js +23 -13
- package/dist/agents/skills/builtin/docs.js.map +1 -1
- package/dist/agents/skills/builtin/git-ops.js +3 -3
- package/dist/agents/skills/builtin/git-ops.js.map +1 -1
- package/dist/agents/skills/builtin/planning.js +4 -4
- package/dist/agents/skills/builtin/planning.js.map +1 -1
- package/dist/agents/skills/builtin/refactoring.js +3 -3
- package/dist/agents/skills/builtin/refactoring.js.map +1 -1
- package/dist/agents/skills/builtin/review.js +9 -9
- package/dist/agents/skills/builtin/review.js.map +1 -1
- package/dist/agents/skills/builtin/testing.js +3 -3
- package/dist/agents/skills/builtin/testing.js.map +1 -1
- package/dist/agents/tools.js +2 -9
- package/dist/agents/tools.js.map +1 -1
- package/dist/cli/app.js +72 -33
- package/dist/cli/app.js.map +1 -1
- package/dist/cli/compaction.js.map +1 -1
- package/dist/cli/components/ChatStream.js +43 -82
- package/dist/cli/components/ChatStream.js.map +1 -1
- package/dist/cli/components/CollapsibleToolOutput.js +8 -21
- package/dist/cli/components/CollapsibleToolOutput.js.map +1 -1
- package/dist/cli/components/Header.js +6 -18
- package/dist/cli/components/Header.js.map +1 -1
- package/dist/cli/components/LiveRegion.js +54 -0
- package/dist/cli/components/LiveRegion.js.map +1 -0
- package/dist/cli/components/Sidebar.js +33 -31
- package/dist/cli/components/Sidebar.js.map +1 -1
- package/dist/cli/components/StatusBar.js +42 -0
- package/dist/cli/components/StatusBar.js.map +1 -0
- package/dist/cli/components/ToolOutput.js +68 -0
- package/dist/cli/components/ToolOutput.js.map +1 -0
- package/dist/cli/components/toolFormat.js +195 -0
- package/dist/cli/components/toolFormat.js.map +1 -0
- package/dist/cli/councilDispatcher.js +1 -1
- package/dist/cli/councilDispatcher.js.map +1 -1
- package/dist/cli/grokOAuth.js +93 -75
- package/dist/cli/grokOAuth.js.map +1 -1
- package/dist/cli/headless.js +137 -0
- package/dist/cli/headless.js.map +1 -0
- package/dist/cli/hooks/chatState.js +139 -0
- package/dist/cli/hooks/chatState.js.map +1 -0
- package/dist/cli/hooks/eventsToMessages.js +42 -11
- package/dist/cli/hooks/eventsToMessages.js.map +1 -1
- package/dist/cli/hooks/messageHelpers.js +72 -15
- package/dist/cli/hooks/messageHelpers.js.map +1 -1
- package/dist/cli/hooks/useBatchedMessages.js +71 -0
- package/dist/cli/hooks/useBatchedMessages.js.map +1 -0
- package/dist/cli/hooks/useChatTurn.js +453 -84
- package/dist/cli/hooks/useChatTurn.js.map +1 -1
- package/dist/cli/hooks/useSession.js +24 -3
- package/dist/cli/hooks/useSession.js.map +1 -1
- package/dist/cli/hooks/useSlashDispatch.js +13 -2
- package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
- package/dist/cli/main.bundled.js +10607 -7889
- package/dist/cli/main.bundled.js.map +4 -4
- package/dist/cli/main.js +120 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/mcp/mcpClient.js +152 -0
- package/dist/cli/mcp/mcpClient.js.map +1 -0
- package/dist/cli/mcp/mcpManager.js +139 -0
- package/dist/cli/mcp/mcpManager.js.map +1 -0
- package/dist/cli/provider/openai-compatible.js +9 -2
- package/dist/cli/provider/openai-compatible.js.map +1 -1
- package/dist/cli/refreshRegistry.js +9 -6
- package/dist/cli/refreshRegistry.js.map +1 -1
- package/dist/cli/runHeadless.js +160 -0
- package/dist/cli/runHeadless.js.map +1 -0
- package/dist/cli/sessionManager.js +1 -1
- package/dist/cli/sessionManager.js.map +1 -1
- package/dist/cli/skillSuggest.js +1 -1
- package/dist/cli/skillsMd.js +155 -0
- package/dist/cli/skillsMd.js.map +1 -0
- package/dist/cli/slashHandlers/branch.js +11 -2
- package/dist/cli/slashHandlers/branch.js.map +1 -1
- package/dist/cli/slashHandlers/git.js +0 -75
- package/dist/cli/slashHandlers/git.js.map +1 -1
- package/dist/cli/slashHandlers/promoteMember.js +25 -0
- package/dist/cli/slashHandlers/promoteMember.js.map +1 -0
- package/dist/cli/slashHandlers/skills.js +16 -0
- package/dist/cli/slashHandlers/skills.js.map +1 -1
- package/dist/cli/slashHandlers/transcript.js +13 -0
- package/dist/cli/slashHandlers/transcript.js.map +1 -0
- package/dist/cli/slashHandlers/updater.js +40 -0
- package/dist/cli/slashHandlers/updater.js.map +1 -0
- package/dist/cli/toolRegistry.js +37 -6
- package/dist/cli/toolRegistry.js.map +1 -1
- package/dist/cli/wizard/firstRun.js +63 -0
- package/dist/cli/wizard/firstRun.js.map +1 -0
- package/dist/cli/wizard/index.js +150 -0
- package/dist/cli/wizard/index.js.map +1 -0
- package/dist/cli/wizard/runWizard.js +137 -0
- package/dist/cli/wizard/runWizard.js.map +1 -0
- package/dist/cli/wizard/useWizardState.js +151 -0
- package/dist/cli/wizard/useWizardState.js.map +1 -0
- package/dist/cli/workspace/paths.js +20 -13
- package/dist/cli/workspace/paths.js.map +1 -1
- package/dist/cli/workspace/storage.js +7 -3
- package/dist/cli/workspace/storage.js.map +1 -1
- package/dist/cli/workspace/stubs.js +122 -44
- package/dist/cli/workspace/stubs.js.map +1 -1
- package/dist/cli/workspace/toolRegistry.js +2 -2
- package/dist/cli/workspace/toolRegistry.js.map +1 -1
- package/dist/cli/workspace/workspaceSummary.js +255 -0
- package/dist/cli/workspace/workspaceSummary.js.map +1 -0
- package/dist/main/core/AgentHarness.js +36 -7
- package/dist/main/core/AgentHarness.js.map +1 -1
- package/dist/main/core/tools/builtin/listFiles.js +43 -5
- package/dist/main/core/tools/builtin/listFiles.js.map +1 -1
- package/dist/main/core/tools/builtin/search.js +28 -120
- package/dist/main/core/tools/builtin/search.js.map +1 -1
- package/package.json +6 -1
- package/dist/cli/oauthCallbackServer.js +0 -207
- package/dist/cli/oauthCallbackServer.js.map +0 -1
- package/dist/main/core/tools/builtin/_walk.js +0 -129
- package/dist/main/core/tools/builtin/_walk.js.map +0 -1
- package/dist/main/core/tools/builtin/diff.js +0 -477
- package/dist/main/core/tools/builtin/diff.js.map +0 -1
|
@@ -1,92 +1,53 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
|
-
import {
|
|
4
|
-
/** Estimate the rendered row count for a single message. */
|
|
5
|
-
function estimateMessageHeight(m, width) {
|
|
6
|
-
if (m.role === 'tool') {
|
|
7
|
-
// Collapsed tool output takes 1 line of summary
|
|
8
|
-
return 1;
|
|
9
|
-
}
|
|
10
|
-
const lines = m.content.split('\n');
|
|
11
|
-
let textRows = 0;
|
|
12
|
-
for (const line of lines) {
|
|
13
|
-
textRows += Math.max(1, Math.ceil(line.length / width));
|
|
14
|
-
}
|
|
15
|
-
return 1 + textRows + 1; // header + textRows + margin-bottom
|
|
16
|
-
}
|
|
3
|
+
import { ToolOutput } from './ToolOutput.js';
|
|
17
4
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
5
|
+
* renderMessage — pure per-message renderer shared by `<Static>` (finalized
|
|
6
|
+
* items, printed once into native scrollback) and the live region (the
|
|
7
|
+
* streaming tail + pending tools, repainted by Ink).
|
|
8
|
+
*
|
|
9
|
+
* v0.7.0 static-scrollback refactor: this replaces the old `ChatStream`
|
|
10
|
+
* component, which combined rendering with visible-message picking
|
|
11
|
+
* (`pickVisibleMessages` / `estimateMessageHeight`). Those are gone —
|
|
12
|
+
* `<Static>` handles scrollback, and the live region guarantees a small
|
|
13
|
+
* dynamic footprint by construction. Each message renders identically
|
|
14
|
+
* whether it is printed once (Static) or repainted (live), so the UI is
|
|
15
|
+
* stable as a message crosses from live → finalized.
|
|
16
|
+
*
|
|
17
|
+
* `live` flag: when true, the tool summary shows a pending glyph and no
|
|
18
|
+
* duration (the invocation hasn't ended yet). Finalized tool messages
|
|
19
|
+
* render via the stateless `ToolOutput` policy (Phase 3).
|
|
21
20
|
*/
|
|
22
|
-
export function
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
26
|
-
const m = messages[i];
|
|
27
|
-
const mHeight = estimateMessageHeight(m, width);
|
|
28
|
-
if (remainingHeight - mHeight >= 0) {
|
|
29
|
-
visibleMessages.unshift(m);
|
|
30
|
-
remainingHeight -= mHeight;
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
// Truncate the top-most visible message if we have some space
|
|
34
|
-
if (remainingHeight > 2) {
|
|
35
|
-
const maxTextRows = remainingHeight - 2; // header + margin-bottom
|
|
36
|
-
const lines = m.content.split('\n');
|
|
37
|
-
const truncatedLines = [];
|
|
38
|
-
let currentRows = 0;
|
|
39
|
-
for (let j = lines.length - 1; j >= 0; j--) {
|
|
40
|
-
const line = lines[j];
|
|
41
|
-
const lineRows = Math.max(1, Math.ceil(line.length / width));
|
|
42
|
-
if (currentRows + lineRows <= maxTextRows) {
|
|
43
|
-
truncatedLines.unshift(line);
|
|
44
|
-
currentRows += lineRows;
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
truncatedLines.unshift('... [truncated]');
|
|
48
|
-
break;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
visibleMessages.unshift({
|
|
52
|
-
...m,
|
|
53
|
-
content: truncatedLines.join('\n'),
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
21
|
+
export function renderMessage(m, live = false) {
|
|
22
|
+
if (m.role === 'tool') {
|
|
23
|
+
return (React.createElement(ToolOutput, { key: m.id, toolName: m.toolName ?? 'tool', summary: m.content, body: m.toolResult ?? m.content, ok: m.toolOk, durationMs: m.toolDurationMs, live: live }));
|
|
58
24
|
}
|
|
59
|
-
return
|
|
25
|
+
return (React.createElement(Box, { key: m.id, flexDirection: "column", marginBottom: 1 },
|
|
26
|
+
React.createElement(Text, { color: m.role === 'user' ? 'cyan' : m.role === 'assistant' ? 'green' : 'yellow', bold: true },
|
|
27
|
+
m.role === 'user' ? '❯' : m.role === 'assistant' ? '◆' : 'ℹ',
|
|
28
|
+
" ",
|
|
29
|
+
m.role,
|
|
30
|
+
m.role === 'assistant' && m.memberName ? (React.createElement(Text, { color: "magenta" },
|
|
31
|
+
" \u00B7 ",
|
|
32
|
+
m.memberName)) : null),
|
|
33
|
+
React.createElement(Box, { marginLeft: 2 },
|
|
34
|
+
React.createElement(Text, null, m.content))));
|
|
35
|
+
}
|
|
36
|
+
function ChatStreamImpl({ messages }) {
|
|
37
|
+
return (React.createElement(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1 }, messages.length === 0 ? (React.createElement(Text, { dimColor: true }, "Ready. Type a prompt or /skill <name> to invoke a skill.")) : (messages.map((m) => renderMessage(m)))));
|
|
60
38
|
}
|
|
39
|
+
export const ChatStream = React.memo(ChatStreamImpl);
|
|
40
|
+
// ── Backward-compat exports for tests still importing the picking helpers ──
|
|
41
|
+
// The v0.6.2 `pickVisibleMessages` / `estimateMessageHeight` are removed in
|
|
42
|
+
// v0.7.0 (the fixed frame is gone). Re-exporting shims that delegate to a
|
|
43
|
+
// trivial implementation keeps older test imports resolving until those tests
|
|
44
|
+
// are migrated. See tests/unit/v4-ui-audit.test.ts + cli-toolDisplay.test.ts.
|
|
61
45
|
/**
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
65
|
-
*
|
|
66
|
-
* Performance: `visibleMessages` is computed via `React.useMemo` keyed on
|
|
67
|
-
* [messages, height, width]. Without this, every streaming token delta from
|
|
68
|
-
* the LLM (≈20-50/sec) would trigger:
|
|
69
|
-
* - O(N) `estimateMessageHeight` calls per render
|
|
70
|
-
* - O(N) `m.content.split('\n')` calls inside the truncation branch
|
|
71
|
-
* - A new `visibleMessages` array, which causes every child to re-render
|
|
72
|
-
*
|
|
73
|
-
* Wrapped in React.memo so the component re-renders only when its props
|
|
74
|
-
* actually change (messages array identity, height, width).
|
|
46
|
+
* @deprecated since v0.7.0 — visible-message picking is removed; `<Static>`
|
|
47
|
+
* handles scrollback. This shim returns the input unchanged so legacy tests
|
|
48
|
+
* that only assert on returned message identity/content still pass.
|
|
75
49
|
*/
|
|
76
|
-
function
|
|
77
|
-
|
|
78
|
-
return (React.createElement(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1, height: height }, visibleMessages.length === 0 ? (React.createElement(Text, { dimColor: true }, "Ready. Type a prompt or /skill <name> to invoke a skill.")) : (visibleMessages.map((m) => {
|
|
79
|
-
if (m.role === 'tool') {
|
|
80
|
-
return (React.createElement(CollapsibleToolOutput, { key: m.id, toolName: m.toolName ?? 'tool', summary: m.content, body: m.content, ok: m.toolOk, durationMs: m.toolDurationMs, defaultExpanded: false }));
|
|
81
|
-
}
|
|
82
|
-
return (React.createElement(Box, { key: m.id, flexDirection: "column", marginBottom: 1 },
|
|
83
|
-
React.createElement(Text, { color: m.role === 'user' ? 'cyan' : m.role === 'assistant' ? 'green' : 'yellow', bold: true },
|
|
84
|
-
m.role === 'user' ? '❯' : m.role === 'assistant' ? '◆' : 'ℹ',
|
|
85
|
-
" ",
|
|
86
|
-
m.role),
|
|
87
|
-
React.createElement(Box, { marginLeft: 2 },
|
|
88
|
-
React.createElement(Text, null, m.content))));
|
|
89
|
-
}))));
|
|
50
|
+
export function pickVisibleMessages(messages, _height, _width) {
|
|
51
|
+
return [...messages];
|
|
90
52
|
}
|
|
91
|
-
export const ChatStream = React.memo(ChatStreamImpl);
|
|
92
53
|
//# sourceMappingURL=ChatStream.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatStream.js","sourceRoot":"","sources":["../../../src/cli/components/ChatStream.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"ChatStream.js","sourceRoot":"","sources":["../../../src/cli/components/ChatStream.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAwC7C;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,aAAa,CAAC,CAAc,EAAE,IAAI,GAAG,KAAK;IACxD,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CACL,oBAAC,UAAU,IACT,GAAG,EAAE,CAAC,CAAC,EAAE,EACT,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,MAAM,EAC9B,OAAO,EAAE,CAAC,CAAC,OAAO,EAClB,IAAI,EAAE,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,OAAO,EAC/B,EAAE,EAAE,CAAC,CAAC,MAAM,EACZ,UAAU,EAAE,CAAC,CAAC,cAAc,EAC5B,IAAI,EAAE,IAAI,GACV,CACH,CAAC;IACJ,CAAC;IACD,OAAO,CACL,oBAAC,GAAG,IAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC;QACpD,oBAAC,IAAI,IAAC,KAAK,EAAE,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,IAAI;YACxF,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;;YAAG,CAAC,CAAC,IAAI;YACrE,CAAC,CAAC,IAAI,KAAK,WAAW,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CACxC,oBAAC,IAAI,IAAC,KAAK,EAAC,SAAS;;gBAAK,CAAC,CAAC,UAAU,CAAQ,CAC/C,CAAC,CAAC,CAAC,IAAI,CACH;QACP,oBAAC,GAAG,IAAC,UAAU,EAAE,CAAC;YAChB,oBAAC,IAAI,QAAE,CAAC,CAAC,OAAO,CAAQ,CACpB,CACF,CACP,CAAC;AACJ,CAAC;AAiBD,SAAS,cAAc,CAAC,EAAE,QAAQ,EAAmB;IACnD,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,IACjD,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CACvB,oBAAC,IAAI,IAAC,QAAQ,qEAAsE,CACrF,CAAC,CAAC,CAAC,CACF,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CACtC,CACG,CACP,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;AAErD,8EAA8E;AAC9E,4EAA4E;AAC5E,0EAA0E;AAC1E,8EAA8E;AAC9E,8EAA8E;AAE9E;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAgC,EAChC,OAAe,EACf,MAAc;IAEd,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
function borderColor(toolName, ok) {
|
|
4
4
|
if (ok === false)
|
|
@@ -12,18 +12,10 @@ function borderColor(toolName, ok) {
|
|
|
12
12
|
return 'red';
|
|
13
13
|
return 'cyan';
|
|
14
14
|
}
|
|
15
|
-
function
|
|
15
|
+
export function CollapsibleToolOutput(props) {
|
|
16
16
|
const { toolName, summary, body, durationMs, ok, defaultExpanded = false } = props;
|
|
17
17
|
const isControlled = typeof props.expanded === 'boolean';
|
|
18
18
|
const [localExpanded, setLocalExpanded] = useState(defaultExpanded);
|
|
19
|
-
// Sync uncontrolled state when the controlled prop is undefined and
|
|
20
|
-
// defaultExpanded changes post-mount (rare but possible on session
|
|
21
|
-
// resume, where the restored message carries defaultExpanded=true).
|
|
22
|
-
useEffect(() => {
|
|
23
|
-
if (!isControlled)
|
|
24
|
-
setLocalExpanded(defaultExpanded);
|
|
25
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
26
|
-
}, [defaultExpanded, isControlled]);
|
|
27
19
|
const expanded = isControlled ? props.expanded : localExpanded;
|
|
28
20
|
const color = borderColor(toolName, ok);
|
|
29
21
|
const summaryLine = [
|
|
@@ -35,18 +27,13 @@ function CollapsibleToolOutputImpl(props) {
|
|
|
35
27
|
return (React.createElement(Box, { flexDirection: "column", marginLeft: 2 },
|
|
36
28
|
React.createElement(Box, null,
|
|
37
29
|
React.createElement(Text, { color: color }, summaryLine)),
|
|
38
|
-
expanded && (React.createElement(Box, { flexDirection: "column", marginLeft: 2, borderStyle: "single", borderColor: color, paddingX: 1 },
|
|
39
|
-
|
|
30
|
+
expanded && (React.createElement(Box, { flexDirection: "column", marginLeft: 2, borderStyle: "single", borderColor: color, paddingX: 1 }, body.split('\n').map((line, idx) => (
|
|
31
|
+
// B12 fix — index keys caused "Encountered two children with the
|
|
32
|
+
// same key" warnings when adjacent lines were identical (e.g.
|
|
33
|
+
// empty separators in multi-line tool output). Use line content
|
|
34
|
+
// with an idx fallback for empty lines.
|
|
35
|
+
React.createElement(Text, { key: line || `__blank-${idx}`, dimColor: ok === false }, line)))))));
|
|
40
36
|
}
|
|
41
|
-
export const CollapsibleToolOutput = React.memo(CollapsibleToolOutputImpl, (prev, next) => {
|
|
42
|
-
return (prev.toolName === next.toolName &&
|
|
43
|
-
prev.summary === next.summary &&
|
|
44
|
-
prev.body === next.body &&
|
|
45
|
-
prev.durationMs === next.durationMs &&
|
|
46
|
-
prev.ok === next.ok &&
|
|
47
|
-
prev.expanded === next.expanded &&
|
|
48
|
-
prev.defaultExpanded === next.defaultExpanded);
|
|
49
|
-
});
|
|
50
37
|
/**
|
|
51
38
|
* Pure helper: classify tool color (exported for unit tests).
|
|
52
39
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CollapsibleToolOutput.js","sourceRoot":"","sources":["../../../src/cli/components/CollapsibleToolOutput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"CollapsibleToolOutput.js","sourceRoot":"","sources":["../../../src/cli/components/CollapsibleToolOutput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACxC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAqChC,SAAS,WAAW,CAAC,QAAgB,EAAE,EAAY;IACjD,IAAI,EAAE,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAC/B,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,OAAO,CAAC;IACpH,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,QAAQ,CAAC;IACvE,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IAC5E,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAiC;IACrE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,eAAe,GAAG,KAAK,EAAE,GAAG,KAAK,CAAC;IACnF,MAAM,YAAY,GAAG,OAAO,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC;IACzD,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,eAAe,CAAC,CAAC;IACpE,MAAM,QAAQ,GAAG,YAAY,CAAC,CAAC,CAAE,KAAK,CAAC,QAAoB,CAAC,CAAC,CAAC,aAAa,CAAC;IAC5E,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IAExC,MAAM,WAAW,GAAG;QAClB,IAAI,QAAQ,GAAG;QACf,OAAO;QACP,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,UAAU,KAAK,CAAC,CAAC,CAAC,EAAE;QACnD,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;KACrB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE5B,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,UAAU,EAAE,CAAC;QACvC,oBAAC,GAAG;YACF,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK,IAAG,WAAW,CAAQ,CACpC;QACL,QAAQ,IAAI,CACX,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,UAAU,EAAE,CAAC,EAAE,WAAW,EAAC,QAAQ,EAAC,WAAW,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,IAC5F,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;QACnC,iEAAiE;QACjE,8DAA8D;QAC9D,gEAAgE;QAChE,wCAAwC;QACxC,oBAAC,IAAI,IAAC,GAAG,EAAE,IAAI,IAAI,WAAW,GAAG,EAAE,EAAE,QAAQ,EAAE,EAAE,KAAK,KAAK,IAAG,IAAI,CAAQ,CAC3E,CAAC,CACE,CACP,CACG,CACP,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,EAAY;IAC9D,OAAO,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC"}
|
|
@@ -1,14 +1,10 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { memo } from 'react';
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
import { formatCost, formatTokens } from '../modelPricing.js';
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* re-renders only when one of its primitive props actually changes. This is
|
|
9
|
-
* critical because the parent App re-renders on EVERY streaming token delta
|
|
10
|
-
* (≈20-50/sec during LLM response); without memo the Header would redraw its
|
|
11
|
-
* border 50×/sec, causing visible flicker on the top edge of the terminal.
|
|
5
|
+
* B11 fix — wrapped in React.memo so the header doesn't re-render on every
|
|
6
|
+
* input keystroke or streaming delta. It only re-renders when its props
|
|
7
|
+
* (model, provider, cost, token count, etc.) actually change.
|
|
12
8
|
*/
|
|
13
9
|
function HeaderImpl({ model, provider, skillCount, sessionActive, sessionId, totalTokens, totalCostUsd }) {
|
|
14
10
|
const hasCost = typeof totalCostUsd === 'number' && totalCostUsd > 0;
|
|
@@ -37,14 +33,6 @@ function HeaderImpl({ model, provider, skillCount, sessionActive, sessionId, tot
|
|
|
37
33
|
tokStr,
|
|
38
34
|
" tok")));
|
|
39
35
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return (prev.model === next.model &&
|
|
43
|
-
prev.provider === next.provider &&
|
|
44
|
-
prev.skillCount === next.skillCount &&
|
|
45
|
-
prev.sessionActive === next.sessionActive &&
|
|
46
|
-
prev.sessionId === next.sessionId &&
|
|
47
|
-
prev.totalTokens === next.totalTokens &&
|
|
48
|
-
prev.totalCostUsd === next.totalCostUsd);
|
|
49
|
-
});
|
|
36
|
+
/** B11 — memoized export. Shallow equality suffices (all props are primitives). */
|
|
37
|
+
export const Header = memo(HeaderImpl);
|
|
50
38
|
//# sourceMappingURL=Header.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Header.js","sourceRoot":"","sources":["../../../src/cli/components/Header.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Header.js","sourceRoot":"","sources":["../../../src/cli/components/Header.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC;AACpC,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAc9D;;;;GAIG;AACH,SAAS,UAAU,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAe;IACnH,MAAM,OAAO,GAAG,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,GAAG,CAAC,CAAC;IACrE,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/D,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IAC9C,OAAO,CACL,oBAAC,GAAG,IAAC,WAAW,EAAC,OAAO,EAAC,WAAW,EAAC,MAAM,EAAC,QAAQ,EAAE,CAAC,EAAE,aAAa,EAAC,KAAK;QAC1E,oBAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,MAAM,kBAAmB;QAC1C,oBAAC,IAAI,IAAC,QAAQ,qBAAW;QACzB,oBAAC,IAAI,QAAE,KAAK,CAAQ;QACpB,oBAAC,IAAI,IAAC,QAAQ,qBAAW;QACzB,oBAAC,IAAI,QAAE,QAAQ,CAAQ;QACvB,oBAAC,IAAI,IAAC,QAAQ,qBAAW;QACzB,oBAAC,IAAI;YAAE,UAAU;sBAAe;QAChC,oBAAC,IAAI,IAAC,QAAQ,qBAAW;QACzB,oBAAC,IAAI,IAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,IAC1C,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,CACjC;QACP,oBAAC,IAAI,IAAC,QAAQ,qBAAW;QACzB,oBAAC,IAAI,IAAC,QAAQ;;YAAU,SAAS,CAAQ;QACzC,oBAAC,IAAI,IAAC,QAAQ,qBAAW;QACzB,oBAAC,IAAI,IAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,IAAG,OAAO,CAAQ;QAC1D,oBAAC,IAAI,IAAC,QAAQ,qBAAW;QACzB,oBAAC,IAAI,IAAC,KAAK,EAAC,MAAM;YAAE,MAAM;mBAAY,CAClC,CACP,CAAC;AACJ,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { renderMessage } from './ChatStream.js';
|
|
4
|
+
/**
|
|
5
|
+
* Max lines of the streaming bubble kept in the dynamic region. The full
|
|
6
|
+
* text is never lost — it lands complete in `<Static>` at finalize. This
|
|
7
|
+
* clamp only bounds the live repaint footprint so the dynamic region fits
|
|
8
|
+
* any terminal height, eliminating full-screen repaints by construction.
|
|
9
|
+
*/
|
|
10
|
+
const LIVE_STREAM_TAIL_LINES = 10;
|
|
11
|
+
/**
|
|
12
|
+
* LiveRegion — the small dynamic region Ink repaints every frame.
|
|
13
|
+
*
|
|
14
|
+
* Contains:
|
|
15
|
+
* - the currently-streaming assistant bubble (clamped to the last
|
|
16
|
+
* `LIVE_STREAM_TAIL_LINES` lines so the region stays short), and
|
|
17
|
+
* - one `⋯ [tool] summary` line per pending tool invocation.
|
|
18
|
+
*
|
|
19
|
+
* Because this region is always at most ~10 + N lines tall, it can never
|
|
20
|
+
* exceed the terminal height → Ink never falls back to clear-screen + full
|
|
21
|
+
* repaint → no flicker, by construction. Finalized messages live in the
|
|
22
|
+
* terminal's native scrollback via `<Static>` (printed exactly once).
|
|
23
|
+
*/
|
|
24
|
+
export function LiveRegion({ live, busy }) {
|
|
25
|
+
const { streaming, runningTools } = live;
|
|
26
|
+
if (!streaming && runningTools.length === 0)
|
|
27
|
+
return null;
|
|
28
|
+
return (React.createElement(Box, { flexDirection: "column", paddingX: 1 },
|
|
29
|
+
streaming && streaming.role === 'assistant' && (React.createElement(StreamingTail, { id: streaming.id, content: streaming.content, ts: streaming.ts, memberName: streaming.memberName, memberId: streaming.memberId })),
|
|
30
|
+
runningTools.map((t) => (React.createElement(Box, { key: t.id, flexDirection: "column" }, renderMessage(t, true)))),
|
|
31
|
+
busy && runningTools.length === 0 && !streaming && (React.createElement(Text, { dimColor: true }, " \u22EF working\u2026"))));
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Render the streaming bubble, clamped to the last N content lines. A leading
|
|
35
|
+
* `…` marker is shown when the content was truncated so the user knows there
|
|
36
|
+
* is more above (in the scrollback once finalized). The bubble uses the same
|
|
37
|
+
* header style as `renderMessage` so it is visually continuous when it
|
|
38
|
+
* crosses from live → finalized.
|
|
39
|
+
*/
|
|
40
|
+
function StreamingTail(m) {
|
|
41
|
+
const lines = m.content.split('\n');
|
|
42
|
+
const truncated = lines.length > LIVE_STREAM_TAIL_LINES;
|
|
43
|
+
const tail = truncated ? lines.slice(-LIVE_STREAM_TAIL_LINES) : lines;
|
|
44
|
+
return (React.createElement(Box, { key: m.id, flexDirection: "column", marginBottom: 1 },
|
|
45
|
+
React.createElement(Text, { color: "green", bold: true },
|
|
46
|
+
"\u25C6 assistant",
|
|
47
|
+
m.memberName ? React.createElement(Text, { color: "magenta" },
|
|
48
|
+
" \u00B7 ",
|
|
49
|
+
m.memberName) : null),
|
|
50
|
+
React.createElement(Box, { marginLeft: 2, flexDirection: "column" },
|
|
51
|
+
truncated && React.createElement(Text, { dimColor: true }, "\u2026"),
|
|
52
|
+
React.createElement(Text, null, tail.join('\n')))));
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=LiveRegion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LiveRegion.js","sourceRoot":"","sources":["../../../src/cli/components/LiveRegion.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD;;;;;GAKG;AACH,MAAM,sBAAsB,GAAG,EAAE,CAAC;AAOlC;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,IAAI,EAAE,IAAI,EAAmB;IACxD,MAAM,EAAE,SAAS,EAAE,YAAY,EAAE,GAAG,IAAI,CAAC;IAEzC,IAAI,CAAC,SAAS,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEzD,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,QAAQ,EAAE,CAAC;QACpC,SAAS,IAAI,SAAS,CAAC,IAAI,KAAK,WAAW,IAAI,CAC9C,oBAAC,aAAa,IACZ,EAAE,EAAE,SAAS,CAAC,EAAE,EAChB,OAAO,EAAE,SAAS,CAAC,OAAO,EAC1B,EAAE,EAAE,SAAS,CAAC,EAAE,EAChB,UAAU,EAAE,SAAS,CAAC,UAAU,EAChC,QAAQ,EAAE,SAAS,CAAC,QAAQ,GAC5B,CACH;QACA,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CACvB,oBAAC,GAAG,IAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,aAAa,EAAC,QAAQ,IACnC,aAAa,CAAC,CAAC,EAAE,IAAI,CAAC,CACnB,CACP,CAAC;QACD,IAAI,IAAI,YAAY,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,SAAS,IAAI,CAClD,oBAAC,IAAI,IAAC,QAAQ,kCAAmB,CAClC,CACG,CACP,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,SAAS,aAAa,CAAC,CAMtB;IACC,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,sBAAsB,CAAC;IACxD,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IACtE,OAAO,CACL,oBAAC,GAAG,IAAC,GAAG,EAAE,CAAC,CAAC,EAAE,EAAE,aAAa,EAAC,QAAQ,EAAC,YAAY,EAAE,CAAC;QACpD,oBAAC,IAAI,IAAC,KAAK,EAAC,OAAO,EAAC,IAAI;;YAErB,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,oBAAC,IAAI,IAAC,KAAK,EAAC,SAAS;;gBAAK,CAAC,CAAC,UAAU,CAAQ,CAAC,CAAC,CAAC,IAAI,CAChE;QACP,oBAAC,GAAG,IAAC,UAAU,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ;YACvC,SAAS,IAAI,oBAAC,IAAI,IAAC,QAAQ,mBAAS;YACrC,oBAAC,IAAI,QAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAQ,CAC1B,CACF,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -1,44 +1,46 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { memo, useId } from 'react';
|
|
2
2
|
import { Box, Text } from 'ink';
|
|
3
3
|
/**
|
|
4
4
|
* Sidebar showing: formatted skill list (from formatSkillList), session count,
|
|
5
5
|
* and an indicator when the user is typing a slash command.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
7
|
+
* B11 fix — wrapped in React.memo so the sidebar doesn't re-render on every
|
|
8
|
+
* App re-render (e.g. every input keystroke or streaming delta). It only
|
|
9
|
+
* re-renders when its props actually change.
|
|
10
|
+
*
|
|
11
|
+
* B20 fix — width is now a prop, scaled to the terminal columns instead of
|
|
12
|
+
* being hardcoded to 40. On narrow terminals the sidebar shrinks so it
|
|
13
|
+
* doesn't overlap the chat stream.
|
|
13
14
|
*/
|
|
14
|
-
function SidebarImpl({ skillList, sessionCount, isSlashMode, height }) {
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
26
|
-
return (React.createElement(Box, { flexDirection: "column", width:
|
|
15
|
+
function SidebarImpl({ skillList, sessionCount, isSlashMode, height, width }) {
|
|
16
|
+
// Stable per-instance prefix to guarantee unique keys across renders and
|
|
17
|
+
// across sibling Sidebar instances (shouldn't exist today, but defensive).
|
|
18
|
+
const uidPrefix = useId();
|
|
19
|
+
const lines = skillList.split('\n');
|
|
20
|
+
const headerLines = 3 + (isSlashMode ? 1 : 0);
|
|
21
|
+
const maxSkillLines = Math.max(2, height - headerLines - 3); // 3 for border + padding
|
|
22
|
+
const visibleSkillLines = lines.slice(0, maxSkillLines);
|
|
23
|
+
const showTruncatedIndicator = lines.length > maxSkillLines;
|
|
24
|
+
if (showTruncatedIndicator) {
|
|
25
|
+
visibleSkillLines.push(' ... (more in /skills)');
|
|
26
|
+
}
|
|
27
|
+
return (React.createElement(Box, { flexDirection: "column", width: width, height: height, borderStyle: "single", borderColor: "gray", paddingX: 1 },
|
|
27
28
|
React.createElement(Text, { bold: true, color: "cyan" }, "Skills & sessions"),
|
|
28
29
|
React.createElement(Text, { dimColor: true },
|
|
29
30
|
"Sessions: ",
|
|
30
31
|
sessionCount),
|
|
31
32
|
isSlashMode && React.createElement(Text, { color: "yellow" }, "\u2328 slash command mode"),
|
|
32
|
-
React.createElement(Box, { marginTop: 1, flexDirection: "column" },
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
React.createElement(Box, { marginTop: 1, flexDirection: "column" }, visibleSkillLines.map((line, idx) => (
|
|
34
|
+
// B12 fix — combine React's useId() with idx + line content for a
|
|
35
|
+
// guaranteed-unique key. formatSkillList can legitimately emit
|
|
36
|
+
// multiple blank lines or duplicate entries (e.g. the
|
|
37
|
+
// "... (more in /skills)" footer when the list is short), which
|
|
38
|
+
// would otherwise collide when used as a key directly.
|
|
39
|
+
React.createElement(Text, { key: `${uidPrefix}-${idx}:${line}` }, line))))));
|
|
37
40
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
});
|
|
41
|
+
/**
|
|
42
|
+
* B11 — memoized export. Custom equality is shallow; props are primitives
|
|
43
|
+
* (strings + numbers + booleans) so React's default shallow compare is fine.
|
|
44
|
+
*/
|
|
45
|
+
export const Sidebar = memo(SidebarImpl);
|
|
44
46
|
//# sourceMappingURL=Sidebar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Sidebar.js","sourceRoot":"","sources":["../../../src/cli/components/Sidebar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"Sidebar.js","sourceRoot":"","sources":["../../../src/cli/components/Sidebar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAUhC;;;;;;;;;;;GAWG;AACH,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAgB;IACxF,yEAAyE;IACzE,2EAA2E;IAC3E,MAAM,SAAS,GAAG,KAAK,EAAE,CAAC;IAC1B,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpC,MAAM,WAAW,GAAG,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC9C,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC,CAAC,yBAAyB;IACtF,MAAM,iBAAiB,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,aAAa,CAAC,CAAC;IACxD,MAAM,sBAAsB,GAAG,KAAK,CAAC,MAAM,GAAG,aAAa,CAAC;IAC5D,IAAI,sBAAsB,EAAE,CAAC;QAC3B,iBAAiB,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;IACpD,CAAC;IAED,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAC,QAAQ,EAAC,WAAW,EAAC,MAAM,EAAC,QAAQ,EAAE,CAAC;QAC3G,oBAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,MAAM,wBAA6B;QACpD,oBAAC,IAAI,IAAC,QAAQ;;YAAY,YAAY,CAAQ;QAC7C,WAAW,IAAI,oBAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,gCAA4B;QAChE,oBAAC,GAAG,IAAC,SAAS,EAAE,CAAC,EAAE,aAAa,EAAC,QAAQ,IACtC,iBAAiB,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC;QACpC,kEAAkE;QAClE,+DAA+D;QAC/D,sDAAsD;QACtD,gEAAgE;QAChE,uDAAuD;QACvD,oBAAC,IAAI,IAAC,GAAG,EAAE,GAAG,SAAS,IAAI,GAAG,IAAI,IAAI,EAAE,IAAG,IAAI,CAAQ,CACxD,CAAC,CACE,CACF,CACP,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { formatCost, formatTokens } from '../modelPricing.js';
|
|
4
|
+
/**
|
|
5
|
+
* StatusBar — single one-line status bar replacing the persistent v0.6
|
|
6
|
+
* `Header`. It lives in the dynamic region (repainted by Ink) and condenses:
|
|
7
|
+
* provider · model · session · tokens · cost · queue · busy.
|
|
8
|
+
*
|
|
9
|
+
* Why one line: the static-scrollback model (v0.7.0) needs the dynamic
|
|
10
|
+
* region as short as possible. A single status line + the input bar + the
|
|
11
|
+
* streaming tail is always well under a screen, so no full repaint.
|
|
12
|
+
*/
|
|
13
|
+
export function StatusBar({ model, provider, sessionId, sessionActive, totalTokens, totalCostUsd, queueCount = 0, busy = false, }) {
|
|
14
|
+
const hasCost = typeof totalCostUsd === 'number' && totalCostUsd > 0;
|
|
15
|
+
const costStr = hasCost ? formatCost(totalCostUsd) : '$0.0000';
|
|
16
|
+
const tokStr = formatTokens(totalTokens ?? 0);
|
|
17
|
+
return (React.createElement(Box, { paddingX: 1 },
|
|
18
|
+
React.createElement(Text, { color: sessionActive ? 'green' : 'gray' }, sessionActive ? '●' : '○'),
|
|
19
|
+
React.createElement(Text, { dimColor: true }, " "),
|
|
20
|
+
React.createElement(Text, { bold: true, color: "cyan" }, provider),
|
|
21
|
+
React.createElement(Text, { dimColor: true }, " \u00B7 "),
|
|
22
|
+
React.createElement(Text, null, model),
|
|
23
|
+
React.createElement(Text, { dimColor: true }, " \u00B7 "),
|
|
24
|
+
React.createElement(Text, { dimColor: true },
|
|
25
|
+
"session ",
|
|
26
|
+
sessionId),
|
|
27
|
+
React.createElement(Text, { dimColor: true }, " \u00B7 "),
|
|
28
|
+
React.createElement(Text, { color: "gray" },
|
|
29
|
+
tokStr,
|
|
30
|
+
" tok"),
|
|
31
|
+
React.createElement(Text, { dimColor: true }, " \u00B7 "),
|
|
32
|
+
React.createElement(Text, { color: hasCost ? 'yellow' : 'gray' }, costStr),
|
|
33
|
+
queueCount > 0 ? (React.createElement(React.Fragment, null,
|
|
34
|
+
React.createElement(Text, { dimColor: true }, " \u00B7 "),
|
|
35
|
+
React.createElement(Text, { color: "magenta" },
|
|
36
|
+
"queue ",
|
|
37
|
+
queueCount))) : null,
|
|
38
|
+
busy ? (React.createElement(React.Fragment, null,
|
|
39
|
+
React.createElement(Text, { dimColor: true }, " \u00B7 "),
|
|
40
|
+
React.createElement(Text, { color: "yellow" }, "working"))) : null));
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=StatusBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StatusBar.js","sourceRoot":"","sources":["../../../src/cli/components/StatusBar.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAa9D;;;;;;;;GAQG;AACH,MAAM,UAAU,SAAS,CAAC,EACxB,KAAK,EACL,QAAQ,EACR,SAAS,EACT,aAAa,EACb,WAAW,EACX,YAAY,EACZ,UAAU,GAAG,CAAC,EACd,IAAI,GAAG,KAAK,GACG;IACf,MAAM,OAAO,GAAG,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,GAAG,CAAC,CAAC;IACrE,MAAM,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/D,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,IAAI,CAAC,CAAC,CAAC;IAC9C,OAAO,CACL,oBAAC,GAAG,IAAC,QAAQ,EAAE,CAAC;QACd,oBAAC,IAAI,IAAC,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,IAC1C,aAAa,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CACrB;QACP,oBAAC,IAAI,IAAC,QAAQ,cAAS;QACvB,oBAAC,IAAI,IAAC,IAAI,QAAC,KAAK,EAAC,MAAM,IAAE,QAAQ,CAAQ;QACzC,oBAAC,IAAI,IAAC,QAAQ,qBAAW;QACzB,oBAAC,IAAI,QAAE,KAAK,CAAQ;QACpB,oBAAC,IAAI,IAAC,QAAQ,qBAAW;QACzB,oBAAC,IAAI,IAAC,QAAQ;;YAAU,SAAS,CAAQ;QACzC,oBAAC,IAAI,IAAC,QAAQ,qBAAW;QACzB,oBAAC,IAAI,IAAC,KAAK,EAAC,MAAM;YAAE,MAAM;mBAAY;QACtC,oBAAC,IAAI,IAAC,QAAQ,qBAAW;QACzB,oBAAC,IAAI,IAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,IAAG,OAAO,CAAQ;QACzD,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,CAChB;YACE,oBAAC,IAAI,IAAC,QAAQ,qBAAW;YACzB,oBAAC,IAAI,IAAC,KAAK,EAAC,SAAS;;gBAAQ,UAAU,CAAQ,CAC9C,CACJ,CAAC,CAAC,CAAC,IAAI;QACP,IAAI,CAAC,CAAC,CAAC,CACN;YACE,oBAAC,IAAI,IAAC,QAAQ,qBAAW;YACzB,oBAAC,IAAI,IAAC,KAAK,EAAC,QAAQ,cAAe,CAClC,CACJ,CAAC,CAAC,CAAC,IAAI,CACJ,CACP,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { useStdout } from 'ink';
|
|
4
|
+
import { formatToolResult } from './toolFormat.js';
|
|
5
|
+
function borderColor(toolName, ok) {
|
|
6
|
+
if (ok === false)
|
|
7
|
+
return 'red';
|
|
8
|
+
const lower = toolName.toLowerCase();
|
|
9
|
+
if (lower.includes('read') || lower === 'cat' || lower.includes('grep') || lower.includes('search'))
|
|
10
|
+
return 'green';
|
|
11
|
+
if (lower.includes('write') || lower.includes('edit'))
|
|
12
|
+
return 'yellow';
|
|
13
|
+
if (lower === 'bash' || lower === 'shell' || lower === 'exec')
|
|
14
|
+
return 'red';
|
|
15
|
+
return 'cyan';
|
|
16
|
+
}
|
|
17
|
+
function ToolOutputImpl(props) {
|
|
18
|
+
const { toolName, summary, body, ok, durationMs, live = false } = props;
|
|
19
|
+
const color = borderColor(toolName, ok);
|
|
20
|
+
const { stdout } = useStdout();
|
|
21
|
+
// B3: clamp bordered box width so boxes don't stretch to full terminal and
|
|
22
|
+
// produce the mixed-width wall seen in v0.7.0.
|
|
23
|
+
const termWidth = stdout?.columns ?? 80;
|
|
24
|
+
const boxWidth = Math.min(Math.max(40, termWidth - 6), 100);
|
|
25
|
+
// Pending (live region): single line, no body, no duration.
|
|
26
|
+
if (live || ok === undefined) {
|
|
27
|
+
const summaryLine = ['⋯', `[${toolName}]`, summary].filter(Boolean).join(' ');
|
|
28
|
+
return (React.createElement(Box, { flexDirection: "column", marginLeft: 2 },
|
|
29
|
+
React.createElement(Box, null,
|
|
30
|
+
React.createElement(Text, { color: color }, summaryLine))));
|
|
31
|
+
}
|
|
32
|
+
// Finalized — format the body per tool policy (B1).
|
|
33
|
+
const isError = ok === false;
|
|
34
|
+
const formatted = formatToolResult(toolName, body);
|
|
35
|
+
const status = ok ? '✓' : '✗';
|
|
36
|
+
const summaryLine = [
|
|
37
|
+
status,
|
|
38
|
+
`[${toolName}]`,
|
|
39
|
+
summary,
|
|
40
|
+
durationMs !== undefined ? `(${durationMs}ms)` : '',
|
|
41
|
+
].filter(Boolean).join(' ');
|
|
42
|
+
// B3: one-line results (write_file/edit_file success) print inline — no box.
|
|
43
|
+
if (formatted.oneLine && !isError) {
|
|
44
|
+
const inline = formatted.lines[0] ?? '';
|
|
45
|
+
return (React.createElement(Box, { flexDirection: "column", marginLeft: 2 },
|
|
46
|
+
React.createElement(Box, null,
|
|
47
|
+
React.createElement(Text, { color: color }, summaryLine)),
|
|
48
|
+
React.createElement(Box, { marginLeft: 2 },
|
|
49
|
+
React.createElement(Text, { dimColor: true }, inline))));
|
|
50
|
+
}
|
|
51
|
+
const bodyText = formatted.lines.join('\n');
|
|
52
|
+
const metaSuffix = formatted.meta ? `\n${formatted.meta}` : '';
|
|
53
|
+
return (React.createElement(Box, { flexDirection: "column", marginLeft: 2 },
|
|
54
|
+
React.createElement(Box, null,
|
|
55
|
+
React.createElement(Text, { color: color }, summaryLine)),
|
|
56
|
+
React.createElement(Box, { flexDirection: "column", marginLeft: 2, width: boxWidth, borderStyle: "single", borderColor: color, paddingX: 1 },
|
|
57
|
+
React.createElement(Text, { dimColor: isError },
|
|
58
|
+
bodyText,
|
|
59
|
+
metaSuffix))));
|
|
60
|
+
}
|
|
61
|
+
export const ToolOutput = React.memo(ToolOutputImpl);
|
|
62
|
+
/**
|
|
63
|
+
* Pure helper: classify tool color (exported for unit tests).
|
|
64
|
+
*/
|
|
65
|
+
export function classifyToolColor(toolName, ok) {
|
|
66
|
+
return borderColor(toolName, ok);
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=ToolOutput.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToolOutput.js","sourceRoot":"","sources":["../../../src/cli/components/ToolOutput.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,CAAC;AAChC,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AA4CnD,SAAS,WAAW,CAAC,QAAgB,EAAE,EAAY;IACjD,IAAI,EAAE,KAAK,KAAK;QAAE,OAAO,KAAK,CAAC;IAC/B,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,OAAO,CAAC;IACpH,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,QAAQ,CAAC;IACvE,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IAC5E,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,cAAc,CAAC,KAAsB;IAC5C,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,GAAG,KAAK,EAAE,GAAG,KAAK,CAAC;IACxE,MAAM,KAAK,GAAG,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,EAAE,CAAC;IAC/B,2EAA2E;IAC3E,+CAA+C;IAC/C,MAAM,SAAS,GAAG,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAE5D,4DAA4D;IAC5D,IAAI,IAAI,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,IAAI,QAAQ,GAAG,EAAE,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC9E,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,UAAU,EAAE,CAAC;YACvC,oBAAC,GAAG;gBACF,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK,IAAG,WAAW,CAAQ,CACpC,CACF,CACP,CAAC;IACJ,CAAC;IAED,oDAAoD;IACpD,MAAM,OAAO,GAAG,EAAE,KAAK,KAAK,CAAC;IAC7B,MAAM,SAAS,GAAG,gBAAgB,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IACnD,MAAM,MAAM,GAAG,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IAC9B,MAAM,WAAW,GAAG;QAClB,MAAM;QACN,IAAI,QAAQ,GAAG;QACf,OAAO;QACP,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,UAAU,KAAK,CAAC,CAAC,CAAC,EAAE;KACpD,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAE5B,6EAA6E;IAC7E,IAAI,SAAS,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QACxC,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,UAAU,EAAE,CAAC;YACvC,oBAAC,GAAG;gBACF,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK,IAAG,WAAW,CAAQ,CACpC;YACN,oBAAC,GAAG,IAAC,UAAU,EAAE,CAAC;gBAChB,oBAAC,IAAI,IAAC,QAAQ,UAAE,MAAM,CAAQ,CAC1B,CACF,CACP,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5C,MAAM,UAAU,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAE/D,OAAO,CACL,oBAAC,GAAG,IAAC,aAAa,EAAC,QAAQ,EAAC,UAAU,EAAE,CAAC;QACvC,oBAAC,GAAG;YACF,oBAAC,IAAI,IAAC,KAAK,EAAE,KAAK,IAAG,WAAW,CAAQ,CACpC;QACN,oBAAC,GAAG,IACF,aAAa,EAAC,QAAQ,EACtB,UAAU,EAAE,CAAC,EACb,KAAK,EAAE,QAAQ,EACf,WAAW,EAAC,QAAQ,EACpB,WAAW,EAAE,KAAK,EAClB,QAAQ,EAAE,CAAC;YAIX,oBAAC,IAAI,IAAC,QAAQ,EAAE,OAAO;gBAAG,QAAQ;gBAAE,UAAU,CAAQ,CAClD,CACF,CACP,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;AAErD;;GAEG;AACH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,EAAY;IAC9D,OAAO,WAAW,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC"}
|