zelari-code 0.7.5 → 0.7.9

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 (44) hide show
  1. package/README.md +27 -1
  2. package/dist/cli/app.js +50 -18
  3. package/dist/cli/app.js.map +1 -1
  4. package/dist/cli/components/Sidebar.js +86 -39
  5. package/dist/cli/components/Sidebar.js.map +1 -1
  6. package/dist/cli/components/SplashScreen.js +204 -0
  7. package/dist/cli/components/SplashScreen.js.map +1 -0
  8. package/dist/cli/components/StatusBar.js +22 -18
  9. package/dist/cli/components/StatusBar.js.map +1 -1
  10. package/dist/cli/councilConfig.js +38 -0
  11. package/dist/cli/councilConfig.js.map +1 -0
  12. package/dist/cli/councilDispatcher.js +38 -32
  13. package/dist/cli/councilDispatcher.js.map +1 -1
  14. package/dist/cli/hooks/useChatTurn.js +80 -61
  15. package/dist/cli/hooks/useChatTurn.js.map +1 -1
  16. package/dist/cli/hooks/useExecutionTimer.js +25 -0
  17. package/dist/cli/hooks/useExecutionTimer.js.map +1 -0
  18. package/dist/cli/hooks/useGitChanges.js +142 -0
  19. package/dist/cli/hooks/useGitChanges.js.map +1 -0
  20. package/dist/cli/hooks/useSlashDispatch.js +9 -2
  21. package/dist/cli/hooks/useSlashDispatch.js.map +1 -1
  22. package/dist/cli/main.bundled.js +2560 -1231
  23. package/dist/cli/main.bundled.js.map +4 -4
  24. package/dist/cli/main.js +9 -2
  25. package/dist/cli/main.js.map +1 -1
  26. package/dist/cli/mcp/mcpClient.js +14 -6
  27. package/dist/cli/mcp/mcpClient.js.map +1 -1
  28. package/dist/cli/updater.js +8 -5
  29. package/dist/cli/updater.js.map +1 -1
  30. package/dist/cli/utils/cmdline.js +26 -0
  31. package/dist/cli/utils/cmdline.js.map +1 -0
  32. package/dist/cli/utils/paths.js +20 -0
  33. package/dist/cli/utils/paths.js.map +1 -0
  34. package/dist/cli/wizard/index.js +1 -1
  35. package/dist/cli/wizard/index.js.map +1 -1
  36. package/dist/cli/workspace/completeDesign.js +128 -0
  37. package/dist/cli/workspace/completeDesign.js.map +1 -0
  38. package/dist/cli/workspace/planDetect.js +17 -0
  39. package/dist/cli/workspace/planDetect.js.map +1 -0
  40. package/dist/cli/workspace/postCouncilHook.js +157 -20
  41. package/dist/cli/workspace/postCouncilHook.js.map +1 -1
  42. package/dist/cli/workspace/stubs.js +406 -225
  43. package/dist/cli/workspace/stubs.js.map +1 -1
  44. package/package.json +71 -71
package/README.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Zelari Code
2
2
 
3
+ ```
4
+ -#%=
5
+ .*%%%@#:
6
+ =%%%%%%%@*
7
+ +%%%%%%%%%%#.
8
+ +%%%@@@@@@@%@#.
9
+ .*%@@@@@@@@@@@@@%-
10
+ .#%@@@@@@@@@@@@@@@@-
11
+ *%@@@@@@@@@@@@@@@@@%.
12
+ :@%%@@@@@@%:+%@@@@@%@=
13
+ =@%%@@@@@%.=-+%@%%@*
14
+ .=@@%@@@@%.*@*-+@@*.
15
+ -*%@@@@@@@@%.*@@@+:#@@#=.
16
+ *%%%%%%@@@@@@.*#%#=-:+@@@%
17
+ :@%%%%%%@@@@@@.:=.*:*@@@@@@=
18
+ *@%%@%%@@@@@@@*%@*:-:%@@@@@%.
19
+ :@@@%@@@@@@@@@@@@@@#%@@@@@@@@=
20
+ *%%%%%%%%%%%%%%%%%%%%%%%%%%%%#
21
+
22
+ Z E L A R I C O D E
23
+ N-THEM Studio
24
+ ```
25
+
3
26
  > AI Council coding agent CLI — multi-agent orchestration with slash commands, provider-agnostic LLM streaming, and self-update.
4
27
 
5
28
  ![Version](https://img.shields.io/npm/v/zelari-code)
@@ -143,7 +166,10 @@ Disable auto-check: `ZELARI_DEV=1 zelari-code`
143
166
  ## Features
144
167
 
145
168
  - 🤖 **Multi-agent council** — 6 roles (Caronte, Nettuno, Gerione, Plutone, Minosse, Lucifero) with feedback loops and member promotion
146
- - 🎨 **Rich TUI** — Ink + React multi-panel interface (header, chat stream, sidebar, input bar)
169
+ - ⇧⇥ **Agent/council mode switch** — `shift+tab` toggles free-form prompts between the single agent and the full council pipeline (mode shown in the status line)
170
+ - 🎨 **Rich TUI** — Ink + React: native-scrollback chat stream, input bar with status line below it (mode · provider · model · session · cwd · execution timer)
171
+ - 🗂️ **Live git sidebar** — right-hand panel with the N-THEM emblem and the working-tree changes (`+added`/`-removed` per file, refreshed every 4s; auto-hidden on narrow terminals)
172
+ - ⏱️ **Execution timer** — elapsed time of the in-flight turn in the status line (`⏱ 12s`), frozen as `last 34s` when the run completes
147
173
  - 🧠 **Provider-agnostic** — OpenAI-compatible APIs (OpenAI, Together, Groq, custom), xAI Grok with OAuth refresh, GLM/Z.AI
148
174
  - 🛠️ **Built-in tools** — filesystem (read/write/edit), shell (bash), search (grep), git operations
149
175
  - 📚 **7 coding skills** — refactoring, testing, debugging, review, planning, docs, git-ops
package/dist/cli/app.js CHANGED
@@ -3,13 +3,16 @@
3
3
  // hook signatures and remove this annotation. The split is documented in
4
4
  // `docs/plans/2026-07-01-app-split.md`.
5
5
  import React, { useState, useMemo, useCallback } from 'react';
6
- import { Box, Static } from 'ink';
6
+ import { Box, Static, useInput, useStdin } from 'ink';
7
7
  import { InputBar } from './components/InputBar.js';
8
8
  import { LiveRegion } from './components/LiveRegion.js';
9
9
  import { StatusBar } from './components/StatusBar.js';
10
+ import { Sidebar, shouldShowSidebar } from './components/Sidebar.js';
10
11
  import { renderMessage } from './components/ChatStream.js';
11
- import { formatSkillList } from './slashCommands.js';
12
12
  import { listCodingSkills } from '@zelari/core/skills';
13
+ import { useGitChanges } from './hooks/useGitChanges.js';
14
+ import { useExecutionTimer } from './hooks/useExecutionTimer.js';
15
+ import { shortenCwd } from './utils/paths.js';
13
16
  import '@zelari/core/skills/builtin/debugging';
14
17
  import '@zelari/core/skills/builtin/docs';
15
18
  import '@zelari/core/skills/builtin/git-ops';
@@ -19,6 +22,7 @@ import '@zelari/core/skills/builtin/review';
19
22
  import '@zelari/core/skills/builtin/testing';
20
23
  import { getProviderConfig, getActiveProvider as getActiveProviderSpec, } from './providerConfig.js';
21
24
  import { SessionJsonlWriter } from '@zelari/core/harness';
25
+ import { VERSION } from './main.js';
22
26
  import { useSession } from './hooks/useSession.js';
23
27
  import { useChatTurn } from './hooks/useChatTurn.js';
24
28
  import { useSlashDispatch } from './hooks/useSlashDispatch.js';
@@ -60,10 +64,26 @@ export function App() {
60
64
  // printed" index so the ANSI-cleared scrollback stays in sync). Also bumped
61
65
  // implicitly by a sessionId change (/new).
62
66
  const [clearEpoch, setClearEpoch] = useState(0);
67
+ // v0.7.9: dispatch mode for free-form prompts — 'agent' (single harness
68
+ // turn) or 'council' (6-member pipeline). Toggled with shift+tab.
69
+ const [mode, setMode] = useState('agent');
63
70
  const activeProviderSpec = getActiveProviderSpec();
64
71
  const activeModel = providerConfig.modelByProvider[activeProviderSpec.id];
65
72
  const session = useSession();
66
73
  const size = useTerminalSize();
74
+ const gitChanges = useGitChanges();
75
+ const cwd = useMemo(() => shortenCwd(process.cwd(), 32), []);
76
+ // v0.7.9: execution timer — elapsed time of the in-flight turn (shown in
77
+ // the StatusBar as `⏱ 12s`, then frozen as `last 34s` when the run ends).
78
+ const timer = useExecutionTimer(busy);
79
+ // shift+tab → toggle agent/council. ink-text-input ignores tab keys, so
80
+ // this never fights the InputBar. Guarded: useInput needs raw mode.
81
+ const { isRawModeSupported } = useStdin();
82
+ useInput((_input, key) => {
83
+ if (key.tab && key.shift) {
84
+ setMode((m) => (m === 'agent' ? 'council' : 'agent'));
85
+ }
86
+ }, { isActive: isRawModeSupported === true });
67
87
  // Throttle layer for the `live` region — coalesces per-token streaming
68
88
  // updates (~50-200/sec) into ≤60 renders/sec. The finalized array uses the
69
89
  // raw setter (its appends are rare and user-facing).
@@ -114,38 +134,50 @@ export function App() {
114
134
  setQueueCount: chatTurn.setQueueCount,
115
135
  dispatchPrompt: chatTurn.dispatchPrompt,
116
136
  dispatchCouncilPrompt: chatTurn.dispatchCouncilPrompt,
137
+ mode,
117
138
  onNewSession,
118
139
  onExit,
119
140
  onClear,
120
141
  });
121
- const skills = useMemo(() => listCodingSkills(), []);
122
- // The one-shot banner: printed once as the first Static item. Replaces the
123
- // persistent Header. Includes the skill list summary so the user can see
124
- // what's available without the 40-col Sidebar (which can't coexist with
125
- // native scrollback — a fixed right column would be printed into every
126
- // scrollback line).
142
+ // The one-shot banner: printed once as the first Static item. v0.7.9: the
143
+ // skill list is gone (it doubled the banner height and duplicated /help);
144
+ // the banner is now just the wordmark line + cwd + a hint.
127
145
  const banner = useMemo(() => {
128
- const skillList = formatSkillList(skills);
129
146
  return {
130
147
  id: 'banner-once',
131
148
  role: 'system',
132
149
  ts: 0,
133
- content: `zelari-code v0.7.3 — ${activeProviderSpec.id}/${activeModel}\n` +
134
- `${skills.length} skills available. Type /help for the list, or /skill <name>.\n` +
135
- `── skills ──\n${skillList}`,
150
+ content: `zelari-code v${VERSION} — ${activeProviderSpec.id}/${activeModel}\n` +
151
+ `cwd: ${cwd}\n` +
152
+ `/help for commands · /skill <name> · shift+tab toggles agent/council`,
136
153
  };
137
- }, [skills, activeProviderSpec.id, activeModel]);
154
+ }, [activeProviderSpec.id, activeModel, cwd]);
138
155
  // The Static feed: banner first, then finalized messages. `key` lets /clear
139
156
  // remount Static so its internal "already printed" index resets. clearEpoch
140
157
  // is composed in so /clear forces a remount even within the same session.
158
+ //
159
+ // v0.7.9 duplicate-banner fix: before the session bootstraps, sessionId is
160
+ // '' — the first Static mount would print the banner, then the bootstrap
161
+ // sessionId change would remount Static (new key) and print it AGAIN into
162
+ // scrollback. Feed Static nothing until the session id exists, so the
163
+ // banner prints exactly once, after bootstrap.
141
164
  const staticKey = `${session.sessionId || 'pre-bootstrap'}-${clearEpoch}`;
142
- const staticItems = [banner, ...session.messages];
165
+ const staticItems = session.sessionId
166
+ ? [banner, ...session.messages]
167
+ : [];
168
+ // v0.7.9: right Sidebar (logo + git changes). It lives in the dynamic
169
+ // region — a full-height column can't coexist with the native-scrollback
170
+ // <Static> model — so it docks beside the live/status/input block. Hidden
171
+ // on narrow/short terminals to keep the dynamic region under one screen.
172
+ const showSidebar = shouldShowSidebar(size.columns, size.rows);
143
173
  return (React.createElement(React.Fragment, null,
144
174
  React.createElement(Static, { key: staticKey, items: staticItems }, (item) => renderMessage(item)),
145
- React.createElement(Box, { flexDirection: "column", borderTop: true, paddingX: 1 },
146
- React.createElement(LiveRegion, { live: session.live, busy: busy }),
147
- React.createElement(StatusBar, { model: activeModel, provider: activeProviderSpec.id, sessionId: session.sessionId ? session.sessionId.slice(0, 8) : '...', sessionActive: session.sessionActive, totalTokens: sessionStats.totalTokens, totalCostUsd: sessionStats.totalCostUsd, queueCount: chatTurn.queueCount, busy: busy }),
148
- React.createElement(InputBar, { value: input, onChange: setInput, onSubmit: handleSubmit, disabled: busy }))));
175
+ React.createElement(Box, { flexDirection: "row" },
176
+ React.createElement(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1 },
177
+ React.createElement(LiveRegion, { live: session.live, busy: busy }),
178
+ React.createElement(InputBar, { value: input, onChange: setInput, onSubmit: handleSubmit, disabled: busy }),
179
+ React.createElement(StatusBar, { model: activeModel, provider: activeProviderSpec.id, sessionId: session.sessionId ? session.sessionId.slice(0, 8) : '...', sessionActive: session.sessionActive, queueCount: chatTurn.queueCount, busy: busy, mode: mode, cwd: cwd, elapsedMs: timer.elapsedMs, lastMs: timer.lastMs })),
180
+ showSidebar && (React.createElement(Sidebar, { version: VERSION, changes: gitChanges, rows: size.rows })))));
149
181
  }
150
182
  // Re-export so legacy imports keep working (Task v0.4.2 audit split).
151
183
  // New code should import directly from src/cli/hooks/* instead.
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/cli/app.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../../src/cli/app.tsx"],"names":[],"mappings":"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"}
@@ -1,46 +1,93 @@
1
- import React, { memo, useId } from 'react';
1
+ import React from 'react';
2
2
  import { Box, Text } from 'ink';
3
3
  /**
4
- * Sidebar showing: formatted skill list (from formatSkillList), session count,
5
- * and an indicator when the user is typing a slash command.
6
- *
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.
4
+ * The N-THEM emblem as Braille art (v0.7.9). Each Braille cell packs a 2×4
5
+ * dot grid, so this reads ~4× denser than the ASCII `EMBLEM_MICRO` it
6
+ * replaces while using fewer rows (9 vs 12). Generated by thresholding the
7
+ * splash `EMBLEM_LARGE` glyph densities and resampling to 48×36 dots.
8
+ */
9
+ const EMBLEM_BRAILLE = `⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣿⣷⣆⡀
10
+ ⠀⠀⠀⠀⠀⠀⠀⢀⣶⣿⣿⣿⣿⣿⣿⣦⡀
11
+ ⠀⠀⠀⠀⠀⠀⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦
12
+ ⠀⠀⠀⠀⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡄
13
+ ⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⠙⠻⣿⣿⣿⣿⣿⣿⠆
14
+ ⠀⠀⠀⠀⣈⣿⣿⣿⣿⣿⣿⣿⠀⣷⣬⡛⢿⣿⣟⣁
15
+ ⠀⢀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⡿⢿⡿⢃⣈⣻⣿⣿⣶
16
+ ⠀⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣠⣴⣆⠻⠎⢿⣿⣿⣿⣿⣧
17
+ ⣰⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇`;
18
+ /** Column width of the sidebar (border + padding included). */
19
+ export const SIDEBAR_WIDTH = 28;
20
+ /** Sidebar only renders on terminals at least this wide. */
21
+ export const SIDEBAR_MIN_COLUMNS = 96;
22
+ /** The Braille emblem is added only when the terminal is at least this tall. */
23
+ const EMBLEM_MIN_ROWS = 26;
24
+ /** Max file rows before collapsing to "+N more". */
25
+ const MAX_FILES_SHORT = 6;
26
+ const MAX_FILES_TALL = 10;
27
+ /**
28
+ * Pure helper: should the sidebar render at all? It lives in the dynamic
29
+ * region (Ink repaints it), so it must never make that region taller than
30
+ * the terminal — narrow or tiny panes skip it entirely.
14
31
  */
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 },
28
- React.createElement(Text, { bold: true, color: "cyan" }, "Skills & sessions"),
29
- React.createElement(Text, { dimColor: true },
30
- "Sessions: ",
31
- sessionCount),
32
- isSlashMode && React.createElement(Text, { color: "yellow" }, "\u2328 slash command mode"),
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))))));
32
+ export function shouldShowSidebar(columns, rows) {
33
+ return columns >= SIDEBAR_MIN_COLUMNS && rows >= 16;
34
+ }
35
+ /** Truncate a repo-relative path to `max` chars keeping the tail (filename). */
36
+ export function truncatePath(p, max) {
37
+ if (p.length <= max)
38
+ return p;
39
+ return `…${p.slice(-(max - 1))}`;
40
40
  }
41
41
  /**
42
- * B11memoized export. Custom equality is shallow; props are primitives
43
- * (strings + numbers + booleans) so React's default shallow compare is fine.
42
+ * Sidebarright-hand column of the dynamic region (v0.7.9).
43
+ *
44
+ * Shows the Braille N-THEM emblem (on tall terminals), the wordmark + version, and
45
+ * the current git working-tree changes with +added/-removed line counts
46
+ * (from `useGitChanges`). It CANNOT span the scrollback area — finalized
47
+ * messages are printed natively via <Static> — so it docks next to the
48
+ * live/status/input block at the bottom, which Ink owns and repaints.
44
49
  */
45
- export const Sidebar = memo(SidebarImpl);
50
+ export function Sidebar({ version, changes, rows }) {
51
+ const showEmblem = rows >= EMBLEM_MIN_ROWS;
52
+ const maxFiles = rows >= EMBLEM_MIN_ROWS + 8 ? MAX_FILES_TALL : MAX_FILES_SHORT;
53
+ const visible = changes.files.slice(0, maxFiles);
54
+ const hidden = changes.files.length - visible.length;
55
+ // Width available for the path inside the box: total − border(2) − padding(2)
56
+ // − the " +NNN -NNN" tail (~11 chars).
57
+ const innerWidth = SIDEBAR_WIDTH - 4;
58
+ return (React.createElement(Box, { flexDirection: "column", width: SIDEBAR_WIDTH, borderStyle: "single", borderColor: "gray", paddingX: 1, flexShrink: 0 },
59
+ showEmblem && (React.createElement(Box, { justifyContent: "center" },
60
+ React.createElement(Text, { color: "cyan" }, EMBLEM_BRAILLE))),
61
+ React.createElement(Box, { justifyContent: "center" },
62
+ React.createElement(Text, { bold: true, color: "white" }, "ZELARI CODE")),
63
+ React.createElement(Box, { justifyContent: "center" },
64
+ React.createElement(Text, { dimColor: true },
65
+ "v",
66
+ version,
67
+ changes.branch ? ` · ${truncatePath(changes.branch, 12)}` : '')),
68
+ React.createElement(Text, { dimColor: true }, '─'.repeat(innerWidth)),
69
+ !changes.isRepo ? (React.createElement(Text, { dimColor: true, italic: true }, "not a git repo")) : changes.files.length === 0 ? (React.createElement(Text, { dimColor: true, italic: true }, "no changes")) : (React.createElement(React.Fragment, null,
70
+ React.createElement(Text, { dimColor: true },
71
+ "changes (",
72
+ changes.files.length,
73
+ ")"),
74
+ visible.map((f) => (React.createElement(FileRow, { key: f.path, file: f, pathWidth: innerWidth - 10 }))),
75
+ hidden > 0 && React.createElement(Text, { dimColor: true },
76
+ " +",
77
+ hidden,
78
+ " more\u2026")))));
79
+ }
80
+ function FileRow({ file, pathWidth }) {
81
+ const name = truncatePath(file.path, Math.max(6, pathWidth));
82
+ return (React.createElement(Box, null,
83
+ React.createElement(Text, { wrap: "truncate" },
84
+ React.createElement(Text, { color: file.untracked ? 'yellow' : 'white' }, name),
85
+ file.untracked ? (React.createElement(Text, { color: "yellow" }, " new")) : (React.createElement(React.Fragment, null,
86
+ React.createElement(Text, { color: "green" },
87
+ " +",
88
+ file.added ?? '·'),
89
+ React.createElement(Text, { color: "red" },
90
+ " -",
91
+ file.removed ?? '·'))))));
92
+ }
46
93
  //# sourceMappingURL=Sidebar.js.map
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"Sidebar.js","sourceRoot":"","sources":["../../../src/cli/components/Sidebar.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,204 @@
1
+ /**
2
+ * SplashScreen — one-shot startup splash (v0.7.8).
3
+ *
4
+ * Shows the N-THEM / Zelari emblem (downscaled from the original 400-col
5
+ * ASCII art) centered in the terminal for ~2 seconds — or until any key is
6
+ * pressed — then unmounts and gives way to the normal App.
7
+ *
8
+ * Sizing: four pre-rendered variants (64/44/30/22 columns wide) are
9
+ * embedded as constants; `pickSplashArt` chooses the largest one that fits
10
+ * the current terminal (dropping the version/hint footer on short panes),
11
+ * or returns null when even the micro one doesn't fit (the splash is then
12
+ * skipped entirely).
13
+ *
14
+ * Skipped when stdout is not a TTY (pipes, CI) or `ZELARI_NO_SPLASH=1`.
15
+ */
16
+ // NOTE: no import from '../main.js' here — main.ts executes `main()` at
17
+ // module scope, so importing it from a component (or a unit test that
18
+ // imports this component) would boot the whole CLI. The version string is
19
+ // passed in as a prop instead.
20
+ import React, { useEffect, useState } from 'react';
21
+ import { Box, Text, useInput, useStdin } from 'ink';
22
+ /** How long the splash stays up before auto-dismissing (ms). */
23
+ export const SPLASH_DURATION_MS = 2000;
24
+ // Downscaled from the source emblem (142×79) by block-averaging glyph
25
+ // density — see docs/plans/2026-07-03-cli-splash-screen.md.
26
+ const EMBLEM_LARGE = ` =%@*-
27
+ =%@@@@@#:
28
+ *%%%%%%@@%-
29
+ :#%%%%%%%%%@@*
30
+ :*%%%%%%%%%%%%%@%*.
31
+ =%%%%%%%%%%%%%%%%@@%.
32
+ =%%%%%%%%%%%%%%%%%%%@%-
33
+ *%%%%%%%%%%%%%%%%%%%%%@@=
34
+ .#%%%%%%%%@@@@@@@@%%%%%%@@@+
35
+ :#%%%%%%@@@@@@@@@@@@@@@%%%%@@+
36
+ -%%%%%@@@@@@@@@@@@@@@@@@@@@%%@@#.
37
+ -%%%%%@@@@@@@@@@@@@@@@@@@@@@@%%@@%:
38
+ =%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@%@@%.
39
+ +%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%@@%:
40
+ =%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-
41
+ -%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%:
42
+ :%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%
43
+ #%%%%%@@@@@@@@@@@@@@@%--#%@@@@@@@@@@@@@%%@@@=
44
+ #@@%%%%@@@@@@@@@@@@@@%: -*@@@@@@@@@@@%%@@@@=
45
+ #@@%%%%@@@@@@@@@@@@@%: .. -#@@@@@@@%%%%@@@=
46
+ +@@@%%%@@@@@@@@@@@@%: :#= =%@@@@%%%@@@%-
47
+ =@@@@%%%@@@@@@@@@@%: -%%*: +%@@%%@@@#
48
+ +%@@@@%%@@@@@@@@@%: -%@@%*=.:+#@@@@#:
49
+ .+*@@@@@@@@@%%%@@@@@@%: -%@@@@@#- +@@@@@@*=
50
+ =*%%%%@@@@@@@@@@@%%@@@@%: -#@@@@@@@*: :*@@@@@@%+=
51
+ -*%%%%%%%%%%@@@@@@@@@@@@@@@: -%@@@@@@@@#- -#@@@@@@@@*
52
+ #%%%%%%%%%%%%%@@@@@@@@@@@@@: -#@@@@@%+-::. *@@@@@@@@=
53
+ =%%%%%%%%%%%%%%%@@@@@@@@@@@@: :*+--=%#. :+++++*@@@@@@@@%
54
+ #@%%%%%%%%%%%%%@@@@@@@@@@@@%: .. - -## *@@@@@@@@@@@@@@=
55
+ :@@%%%%%%%%%%%%@@@@@@@@@@@@@%: .**= *%= :%@@@@@@@@@@@@@%
56
+ #@@@%%%%%%%%%%%@@@@@@@@@@@@@@- =#@@%- :**: =%@@@@@@@@@@@@@+
57
+ =@@@@@%%%@@%%%%@@@@@@@@@@@@@@@@@@@@@@%- :: .-#@@@@@@@@@@@@@%.
58
+ :@@@@@@%%@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@%==*%%@@@@@@@@@@@@@@@@#
59
+ *@@@@@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:
60
+ :@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+
61
+ =##########*######**##**#*********##**#*#######################*`;
62
+ const EMBLEM_SMALL = ` =%%*:
63
+ :#%%@@@+
64
+ =%%%%%%%@#.
65
+ .*%%%%%%%%%@%-
66
+ =%%%%%%%%%%%%%@*.
67
+ +%%%%%%@@@@@%%%%@%:
68
+ *%%%%@@@@@@@@@@@%%@%:
69
+ *%%%@@@@@@@@@@@@@@@%@%-
70
+ :#%%@@@@@@@@@@@@@@@@@@@@@+
71
+ :%%%@@@@@@@@@@@@@@@@@@@@@@@+
72
+ #%%@@@@@@@@@@@@@@@@@@@@@@@@@-
73
+ +%%@@@@@@@@@@@@#@@@@@@@@@@@@@%:
74
+ %%%%@@@@@@@@@@%::*@@@@@@@@@%@@=
75
+ -%@%%@@@@@@@@@%:.::*@@@@@%%@@*.
76
+ :%@@%%@@@@@@@%.:%#::*@@%@@@-
77
+ :#@@@%@@@@@@%.:%@%+.-#@@@=
78
+ :+#@@@@@@@%@@@@%.:%@@@%=.+@@@%*-
79
+ .*#%%%%%%@@@@@@@@@@.:%@@@@@*:.+%@@@@#-
80
+ +%%%%%%%%%%@@@@@@@@::##*%* :----%@@@@%.
81
+ .@%%%%%%%%%@@@@@@@@@:.-..-#=:%@@@@@@@@@+
82
+ *@@%%%%%%%%@@@@@@@@@: =#+ +#.-@@@@@@@@@@.
83
+ -@@@%%%%%%%@@@@@@@@@@#%@@@- -.:*@@@@@@@@@*
84
+ %@@@@%@@%@@@@@@@@@@@@@@@@@%**%@@@@@@@@@@@@:
85
+ =@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*`;
86
+ const EMBLEM_TINY = ` -%%+
87
+ .*%%%@#:
88
+ =%%%%%%%@*
89
+ +%%%%%%%%%%#.
90
+ +%%%@@@@@@@%@#.
91
+ .*%@@@@@@@@@@@@@%-
92
+ .#%@@@@@@@@@@@@@@@@-
93
+ *%@@@@@@@@@@@@@@@@@%.
94
+ :@%%@@@@@@%:+%@@@@@%@=
95
+ =@%%@@@@@%.=-+%@%%@*
96
+ .=@@%@@@@%.*@*-+@@*.
97
+ -*%@@@@@@@@%.*@@@+:#@@#=.
98
+ *%%%%%%@@@@@@.*#%#=-:+@@@%
99
+ :@%%%%%%@@@@@@.:=.*:*@@@@@@=
100
+ *@%%@%%@@@@@@@*%@*:-:%@@@@@%.
101
+ :@@@%@@@@@@@@@@@@@@#%@@@@@@@@=
102
+ *%%%%%%%%%%%%%%%%%%%%%%%%%%%%#`;
103
+ const EMBLEM_MICRO = ` -#%=
104
+ +%%%%#.
105
+ :#%%%%%%%-
106
+ :%%@@@@@@@@=
107
+ -%@@@@@@@@@@@+
108
+ :%@@@@@@%@@@@@@=
109
+ -%%@@@@@.+%@@%@+
110
+ -@@@@@@:%++%@=
111
+ =*%@@@@@@:@@%=*@#+.
112
+ =%%%%%@@@@:+++-*%@@*
113
+ .%%%%%@@@@@+%+=:%@@@@:
114
+ *@@@@@@@@@@@@@%@@@@@@*`;
115
+ /** Rows the FULL footer (margin + wordmark + version + hint) needs below the art. */
116
+ const FOOTER_ROWS_FULL = 5;
117
+ /** Rows the COMPACT footer (margin + wordmark only) needs — used on short terminals. */
118
+ const FOOTER_ROWS_COMPACT = 2;
119
+ function measure(art) {
120
+ const lines = art.split('\n');
121
+ return {
122
+ art,
123
+ width: Math.max(...lines.map((l) => l.length)),
124
+ height: lines.length,
125
+ };
126
+ }
127
+ const VARIANTS = [
128
+ measure(EMBLEM_LARGE),
129
+ measure(EMBLEM_SMALL),
130
+ measure(EMBLEM_TINY),
131
+ measure(EMBLEM_MICRO),
132
+ ];
133
+ /**
134
+ * Pure helper: pick the largest emblem variant that fits `columns`×`rows`.
135
+ * Tries the full footer first (wordmark + version + hint); on short
136
+ * terminals falls back to the compact footer (wordmark only) so the
137
+ * splash still shows in low panes like VS Code's integrated terminal.
138
+ * Returns null only when even the micro variant doesn't fit.
139
+ */
140
+ export function pickSplashArt(columns, rows) {
141
+ // Largest art wins: a bigger emblem with the compact footer beats a
142
+ // smaller emblem with the full footer.
143
+ for (const v of VARIANTS) {
144
+ if (v.width > columns - 2)
145
+ continue;
146
+ if (v.height + FOOTER_ROWS_FULL <= rows)
147
+ return { ...v, compact: false };
148
+ if (v.height + FOOTER_ROWS_COMPACT <= rows)
149
+ return { ...v, compact: true };
150
+ }
151
+ return null;
152
+ }
153
+ /**
154
+ * Pure helper: should the splash be shown at all?
155
+ * Skipped for non-TTY stdout (pipes/CI), when ZELARI_NO_SPLASH=1, or when
156
+ * the terminal is too small for even the small variant.
157
+ */
158
+ export function shouldShowSplash(opts) {
159
+ if (!opts.isTTY)
160
+ return false;
161
+ if (opts.env['ZELARI_NO_SPLASH'] === '1')
162
+ return false;
163
+ return pickSplashArt(opts.columns, opts.rows) !== null;
164
+ }
165
+ function Splash({ onDone, version }) {
166
+ const { isRawModeSupported } = useStdin();
167
+ const columns = process.stdout.columns ?? 80;
168
+ const rows = process.stdout.rows ?? 24;
169
+ const picked = pickSplashArt(columns, rows);
170
+ useEffect(() => {
171
+ const t = setTimeout(onDone, SPLASH_DURATION_MS);
172
+ return () => clearTimeout(t);
173
+ }, [onDone]);
174
+ // Any key skips the splash. Guarded: useInput throws without raw mode.
175
+ useInput(() => {
176
+ onDone();
177
+ }, { isActive: isRawModeSupported === true });
178
+ if (!picked)
179
+ return null;
180
+ return (React.createElement(Box, { flexDirection: "column", alignItems: "center", justifyContent: "center", width: columns, height: rows - 1 },
181
+ React.createElement(Text, { color: "cyan" }, picked.art),
182
+ React.createElement(Box, { marginTop: 1 },
183
+ React.createElement(Text, { bold: true, color: "white" }, 'Z E L A R I C O D E')),
184
+ !picked.compact && (React.createElement(Text, { dimColor: true }, `${version ? `v${version} — ` : ''}N-THEM Studio`)),
185
+ !picked.compact && (React.createElement(Text, { dimColor: true, italic: true }, "press any key to skip"))));
186
+ }
187
+ /**
188
+ * SplashGate — renders the splash first, then swaps in `children` (the
189
+ * real App). The App therefore mounts only after the splash dismisses,
190
+ * so its <Static> banner and raw-mode input never fight the splash.
191
+ */
192
+ export function SplashGate({ children, version, }) {
193
+ const [show, setShow] = useState(() => shouldShowSplash({
194
+ isTTY: process.stdout.isTTY === true,
195
+ env: process.env,
196
+ columns: process.stdout.columns ?? 80,
197
+ rows: process.stdout.rows ?? 24,
198
+ }));
199
+ if (show) {
200
+ return React.createElement(Splash, { onDone: () => setShow(false), version: version });
201
+ }
202
+ return React.createElement(React.Fragment, null, children);
203
+ }
204
+ //# sourceMappingURL=SplashScreen.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SplashScreen.js","sourceRoot":"","sources":["../../../src/cli/components/SplashScreen.tsx"],"names":[],"mappings":"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"}
@@ -1,22 +1,23 @@
1
1
  import React from 'react';
2
2
  import { Box, Text } from 'ink';
3
- import { formatCost, formatTokens } from '../modelPricing.js';
3
+ import { formatDuration } from '../utils/duration.js';
4
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.
5
+ * StatusBar — single one-line status bar. v0.7.9: rendered BELOW the input
6
+ * box (the "top bar" position above it is gone), and the token/cost fields
7
+ * are replaced by an execution timer: `⏱ 12s` while a run is in flight,
8
+ * `last 34s` after it completes.
8
9
  *
9
10
  * Why one line: the static-scrollback model (v0.7.0) needs the dynamic
10
11
  * region as short as possible. A single status line + the input bar + the
11
12
  * streaming tail is always well under a screen, so no full repaint.
12
13
  */
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);
14
+ export function StatusBar({ model, provider, sessionId, sessionActive, queueCount = 0, busy = false, mode = 'agent', cwd, elapsedMs = null, lastMs = null, }) {
17
15
  return (React.createElement(Box, { paddingX: 1 },
18
16
  React.createElement(Text, { color: sessionActive ? 'green' : 'gray' }, sessionActive ? '●' : '○'),
19
17
  React.createElement(Text, { dimColor: true }, " "),
18
+ React.createElement(Text, { bold: true, color: mode === 'council' ? 'magenta' : 'cyan' }, mode === 'council' ? '⛬ council' : '⏵ agent'),
19
+ React.createElement(Text, { dimColor: true }, " (shift+tab)"),
20
+ React.createElement(Text, { dimColor: true }, " \u00B7 "),
20
21
  React.createElement(Text, { bold: true, color: "cyan" }, provider),
21
22
  React.createElement(Text, { dimColor: true }, " \u00B7 "),
22
23
  React.createElement(Text, null, model),
@@ -24,19 +25,22 @@ export function StatusBar({ model, provider, sessionId, sessionActive, totalToke
24
25
  React.createElement(Text, { dimColor: true },
25
26
  "session ",
26
27
  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),
28
+ cwd ? (React.createElement(React.Fragment, null,
29
+ React.createElement(Text, { dimColor: true }, " \u00B7 "),
30
+ React.createElement(Text, { color: "blue" }, cwd))) : null,
31
+ busy && elapsedMs !== null ? (React.createElement(React.Fragment, null,
32
+ React.createElement(Text, { dimColor: true }, " \u00B7 "),
33
+ React.createElement(Text, { color: "yellow" },
34
+ "\u23F1 ",
35
+ formatDuration(elapsedMs)))) : lastMs !== null ? (React.createElement(React.Fragment, null,
36
+ React.createElement(Text, { dimColor: true }, " \u00B7 "),
37
+ React.createElement(Text, { dimColor: true },
38
+ "last ",
39
+ formatDuration(lastMs)))) : null,
33
40
  queueCount > 0 ? (React.createElement(React.Fragment, null,
34
41
  React.createElement(Text, { dimColor: true }, " \u00B7 "),
35
42
  React.createElement(Text, { color: "magenta" },
36
43
  "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));
44
+ queueCount))) : null));
41
45
  }
42
46
  //# sourceMappingURL=StatusBar.js.map