ispbills-icli 8.7.7 → 8.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.
- package/package.json +1 -1
- package/src/commands.js +3 -3
- package/src/tui/app.js +36 -34
- package/src/tui/components.js +25 -15
- package/src/tui/composer.js +1 -1
- package/src/tui/run.js +3 -3
- package/src/tui/theme.js +2 -0
package/package.json
CHANGED
package/src/commands.js
CHANGED
|
@@ -88,7 +88,7 @@ export const SLASH_COMMANDS = [
|
|
|
88
88
|
{ cmd: '/list-dirs', hint: '', desc: 'Show all allowed directories', group: 'Permissions', local: true },
|
|
89
89
|
{ cmd: '/sandbox', hint: '[enable|disable]', desc: 'Enable/disable local sandboxing', group: 'Permissions', local: true },
|
|
90
90
|
{ cmd: '/experimental', hint: '[on|off|show]', desc: 'Toggle experimental features', group: 'Permissions', local: true },
|
|
91
|
-
{ cmd: '/init', hint: '', desc: 'Initialize
|
|
91
|
+
{ cmd: '/init', hint: '', desc: 'Initialize .github/copilot-instructions.md for this repo', group: 'Permissions', local: true },
|
|
92
92
|
|
|
93
93
|
// ── Agents & models ──
|
|
94
94
|
{ cmd: '/agent', hint: '', desc: 'Browse and select agents', group: 'Agents', local: true },
|
|
@@ -121,9 +121,9 @@ export const SLASH_COMMANDS = [
|
|
|
121
121
|
{ cmd: '/bug', hint: '', desc: 'Report a bug (alias for /feedback)', group: 'Help', local: true },
|
|
122
122
|
{ cmd: '/update', hint: '', desc: 'Update iCli to the latest version', group: 'Help', local: true },
|
|
123
123
|
{ cmd: '/downgrade', hint: 'VERSION', desc: 'Roll back to a specific CLI version', group: 'Help', local: true },
|
|
124
|
-
{ cmd: '/app', hint: '', desc: '
|
|
124
|
+
{ cmd: '/app', hint: '', desc: 'Show instructions to open the iPolot web app', group: 'Help', local: true },
|
|
125
125
|
{ cmd: '/user', hint: '', desc: 'Manage GitHub user list', group: 'Help', local: true },
|
|
126
|
-
{ cmd: '/login', hint: '', desc: 'Log in to
|
|
126
|
+
{ cmd: '/login', hint: '', desc: 'Log in to iPolot', group: 'Help', local: true },
|
|
127
127
|
{ cmd: '/whoami', hint: '', desc: 'Show current user info', group: 'Help', local: true },
|
|
128
128
|
{ cmd: '/clikit', hint: '[component]', desc: 'Preview CLI UI components', group: 'Help', local: true },
|
|
129
129
|
{ cmd: '/extensions', hint: '[manage|mode]', desc: 'Manage CLI extensions', group: 'Help', local: true },
|
package/src/tui/app.js
CHANGED
|
@@ -69,6 +69,8 @@ function approxTokens(messages) {
|
|
|
69
69
|
|
|
70
70
|
const TOKEN_LIMIT = 100000;
|
|
71
71
|
const SESSION_SORTS = ['relevance', 'created', 'name', 'last used'];
|
|
72
|
+
const TOOL_APPROVAL_ONCE = 'yes, proceed with this tool call';
|
|
73
|
+
const TOOL_APPROVAL_SESSION = '__session_allow__';
|
|
72
74
|
|
|
73
75
|
function sessionAutoName(messages = []) {
|
|
74
76
|
const firstUser = messages.find((m) => m?.role === 'user' && String(m.content || '').trim());
|
|
@@ -437,7 +439,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
437
439
|
const [deviceError, setDeviceError] = useState(null);
|
|
438
440
|
const chipsRows = (!busy && chips.length && !choice && !search && !sessionPicker && !diffState) ? 1 : 0;
|
|
439
441
|
const composerRows = 2;
|
|
440
|
-
const chromeRows = 2 + composerRows + 1 + chipsRows +
|
|
442
|
+
const chromeRows = 2 + composerRows + 1 + chipsRows + 1; // tabBar + composer + sep + chips + 1 footer row
|
|
441
443
|
const viewportRows = Math.max(3, rows - chromeRows);
|
|
442
444
|
const scrollPage = Math.max(4, viewportRows - 2);
|
|
443
445
|
|
|
@@ -899,9 +901,9 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
899
901
|
const toolArgs = reply.toolCall?.args || reply.toolCall?.command || '';
|
|
900
902
|
const toolDesc = toolArgs ? `${toolName}: ${toolArgs}` : (reply.note || toolName);
|
|
901
903
|
choiceActionRef.current = (value) => {
|
|
902
|
-
if (value ===
|
|
904
|
+
if (value === TOOL_APPROVAL_SESSION) {
|
|
903
905
|
cfg.allowedTools = [...(cfg.allowedTools || []), toolName];
|
|
904
|
-
runTurn(
|
|
906
|
+
runTurn(TOOL_APPROVAL_ONCE);
|
|
905
907
|
return;
|
|
906
908
|
}
|
|
907
909
|
if (value != null) runTurn(String(value));
|
|
@@ -912,9 +914,9 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
912
914
|
sel: 0, text: '', focusText: false, allowText: true,
|
|
913
915
|
isToolApproval: true,
|
|
914
916
|
options: [
|
|
915
|
-
{ label: '1. Yes', value:
|
|
916
|
-
{ label:
|
|
917
|
-
{ label: '3. No, and tell
|
|
917
|
+
{ label: '1. Yes', value: TOOL_APPROVAL_ONCE },
|
|
918
|
+
{ label: `2. Yes, and approve ${toolName} for the rest of the session`, value: TOOL_APPROVAL_SESSION },
|
|
919
|
+
{ label: '3. No, and tell iCopilot what to do differently (Esc)', value: null },
|
|
918
920
|
],
|
|
919
921
|
});
|
|
920
922
|
} else if (type === 'prompt' || type === 'choice') {
|
|
@@ -1449,7 +1451,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
1449
1451
|
if (q === '/init') {
|
|
1450
1452
|
const fp = resolve(process.cwd(), '.github/copilot-instructions.md');
|
|
1451
1453
|
if (existsSync(fp)) {
|
|
1452
|
-
pushNotice(
|
|
1454
|
+
pushNotice(`.github/copilot-instructions.md already exists at ${shortenPath(fp)}. Edit it directly.`);
|
|
1453
1455
|
} else {
|
|
1454
1456
|
runTurn('Create a .github/copilot-instructions.md file for this repository with sensible defaults for an ISP NOC tool.');
|
|
1455
1457
|
}
|
|
@@ -1774,7 +1776,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
1774
1776
|
if (value == null) {
|
|
1775
1777
|
if (currentChoice?.isToolApproval || /⚙ Tool request|tool request|approval|shell:/i.test(`${currentChoice?.title || ''} ${currentChoice?.note || ''}`)) {
|
|
1776
1778
|
setChoice({
|
|
1777
|
-
title: 'Tell
|
|
1779
|
+
title: 'Tell iCopilot what to do differently:',
|
|
1778
1780
|
note: '',
|
|
1779
1781
|
sel: 0,
|
|
1780
1782
|
text: '',
|
|
@@ -1836,6 +1838,13 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
1836
1838
|
if (!choice) return;
|
|
1837
1839
|
if (sessionPicker || diffState) return;
|
|
1838
1840
|
if (key.escape || (key.ctrl && input === 'c')) { setChoice(null); return; }
|
|
1841
|
+
if (choice.isToolApproval && !choice.focusText) {
|
|
1842
|
+
const yesValue = choice.options.find((o) => o?.value === TOOL_APPROVAL_ONCE)?.value;
|
|
1843
|
+
const alwaysValue = choice.options.find((o) => o?.value === TOOL_APPROVAL_SESSION)?.value;
|
|
1844
|
+
if (input === 'y') { pickChoice(yesValue); return; }
|
|
1845
|
+
if (input === 'a') { pickChoice(alwaysValue); return; }
|
|
1846
|
+
if (input === 'n') { pickChoice(null); return; }
|
|
1847
|
+
}
|
|
1839
1848
|
if (key.tab && choice.allowText) { setChoice((c) => ({ ...c, focusText: !c.focusText })); return; }
|
|
1840
1849
|
if (key.upArrow) { setChoice((c) => ({ ...c, focusText: false, sel: Math.max(0, c.sel - 1) })); return; }
|
|
1841
1850
|
if (key.downArrow) {
|
|
@@ -2124,23 +2133,23 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
2124
2133
|
const tokenCount = approxTokens(convo.current);
|
|
2125
2134
|
const tokenLabel = contextUsageLabel(tokenCount);
|
|
2126
2135
|
const modelLabel = streamerMode ? '' : shortModel(model || modelRef.current || 'server default');
|
|
2127
|
-
// §8:
|
|
2128
|
-
const
|
|
2136
|
+
// §8: single footer row (GH Copilot CLI style) — cwd·branch on left, mode·model·tokens on right
|
|
2137
|
+
const modeLabel = mode === 'autopilot' ? 'AUTOPILOT' : mode === 'plan' ? 'PLAN' : null;
|
|
2138
|
+
const footerRightEstLen = (modeLabel ? modeLabel.length + 3 : 0) + (modelLabel.length || 0) + (tokenLabel.length || 0) + 8;
|
|
2129
2139
|
const cwdMaxLen = Math.max(12, cols - footerRightEstLen - (branch ? branch.length + 6 : 0) - 4);
|
|
2130
2140
|
const cwd = shortenPath(process.cwd(), cwdMaxLen);
|
|
2131
|
-
const footerLeft =
|
|
2132
|
-
const footerInfoRight = streamerMode ? '' : [modelLabel, tokenLabel].filter(Boolean).join(midDot());
|
|
2133
|
-
// Status row: working indicator when busy, key hints when idle, hint message when set
|
|
2134
|
-
const footerStatusLeft = busy
|
|
2141
|
+
const footerLeft = busy
|
|
2135
2142
|
? `${glyphs.spinner} Working\u2026`
|
|
2136
2143
|
: hint
|
|
2137
2144
|
? hint
|
|
2138
|
-
:
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2145
|
+
: [cwd, branch ? `${glyphs.gitBranch}${branch}` : null].filter(Boolean).join(midDot());
|
|
2146
|
+
const footerLeftColor = busy ? C.warning : hint ? C.accent : C.muted;
|
|
2147
|
+
const footerRight = busy
|
|
2148
|
+
? `Ctrl+C cancel`
|
|
2149
|
+
: streamerMode
|
|
2150
|
+
? ''
|
|
2151
|
+
: [modeLabel, modelLabel, tokenLabel].filter(Boolean).join(midDot());
|
|
2152
|
+
const footerRightColor = busy ? C.warning : mode === 'autopilot' ? C.warning : mode === 'plan' ? C.accent : C.muted;
|
|
2144
2153
|
const composerMode = shellMode ? 'shell' : mode;
|
|
2145
2154
|
|
|
2146
2155
|
// ── Viewport slicing ───────────────────────────────────────────────────────
|
|
@@ -2156,7 +2165,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
2156
2165
|
|
|
2157
2166
|
const liveArea = live
|
|
2158
2167
|
? html`<${Box} flexDirection="column">
|
|
2159
|
-
<${StatusLines} lines=${live.status} busy=${busy} />
|
|
2168
|
+
<${StatusLines} lines=${live.status} busy=${busy} cols=${cols} />
|
|
2160
2169
|
${live.reasoning ? html`<${Reasoning} text=${live.reasoning} show=${showReasoning} />` : null}
|
|
2161
2170
|
${live.text ? html`<${AssistantMessage} text=${live.text} cols=${cols} ts=${startedAt || Date.now()} streaming=${true} />` : null}
|
|
2162
2171
|
${live.reply?.steps ? html`<${Plan} reply=${live.reply} live=${true} />` : null}
|
|
@@ -2166,9 +2175,8 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
2166
2175
|
|
|
2167
2176
|
const scrollPct = maxScrollRef.current > 0 ? Math.round((scrollOffset / maxScrollRef.current) * 100) : 100;
|
|
2168
2177
|
const scrollIndicator = hasAbove
|
|
2169
|
-
? html`<${Box} paddingX=${1} justifyContent="
|
|
2170
|
-
<${Text} color=${C.muted} dimColor>${glyphs.up} ${aboveCount} above ${midDot()}
|
|
2171
|
-
<${Text} color=${C.muted} dimColor>${scrollPct}%<//>
|
|
2178
|
+
? html`<${Box} paddingX=${1} justifyContent="flex-end" width=${cols}>
|
|
2179
|
+
<${Text} color=${C.muted} dimColor>${glyphs.up} ${aboveCount} above ${midDot()} ${scrollPct}%<//>
|
|
2172
2180
|
<//>`
|
|
2173
2181
|
: null;
|
|
2174
2182
|
|
|
@@ -2185,7 +2193,7 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
2185
2193
|
/>
|
|
2186
2194
|
${diffState.commentInput
|
|
2187
2195
|
? html`<${Choice}
|
|
2188
|
-
title=${`Tell
|
|
2196
|
+
title=${`Tell iCopilot what stands out about ${diffState.commentInput.file}:${diffState.commentInput.lineNumber || '?'}`}
|
|
2189
2197
|
note=${diffState.commentInput.content}
|
|
2190
2198
|
sel=${0}
|
|
2191
2199
|
allowText=${true}
|
|
@@ -2258,18 +2266,12 @@ export function App({ cfg, display = {}, onExternal, onExit, initialQuestion, sh
|
|
|
2258
2266
|
clearToken=${composerClearToken}
|
|
2259
2267
|
/>`}
|
|
2260
2268
|
|
|
2269
|
+
<${Text} color=${C.separator}>${'─'.repeat(Math.max(1, cols))}<//>
|
|
2261
2270
|
<${Box} paddingX=${1} width=${cols}>
|
|
2262
2271
|
<${Box} flexGrow=${1}>
|
|
2263
|
-
<${Text} color=${
|
|
2264
|
-
<//>
|
|
2265
|
-
<${Text} color=${footerStatusRightColor} bold wrap="truncate-end">${footerStatusRight}<//>
|
|
2266
|
-
<//>
|
|
2267
|
-
|
|
2268
|
-
<${Box} paddingX=${1} width=${cols}>
|
|
2269
|
-
<${Box} flexGrow=${1}>
|
|
2270
|
-
<${Text} color=${C.muted} dimColor wrap="truncate-end">${footerLeft}<//>
|
|
2272
|
+
<${Text} color=${footerLeftColor} bold=${busy} dimColor=${!busy && !hint} wrap="truncate-end">${footerLeft}<//>
|
|
2271
2273
|
<//>
|
|
2272
|
-
<${Text} color=${
|
|
2274
|
+
<${Text} color=${footerRightColor} bold=${mode === 'autopilot' || mode === 'plan'} dimColor=${!busy && !modeLabel} wrap="truncate-end">${footerRight}<//>
|
|
2273
2275
|
<//>
|
|
2274
2276
|
<//>
|
|
2275
2277
|
<//>`;
|
package/src/tui/components.js
CHANGED
|
@@ -124,7 +124,7 @@ export function TabBar({ active = 'session', cols = 80 }) {
|
|
|
124
124
|
const label = ` ${i + 1} ${tab.label} `.padEnd(TAB_W);
|
|
125
125
|
return html`
|
|
126
126
|
<${Box} key=${tab.id} width=${TAB_W}>
|
|
127
|
-
<${Text} bold=${on} color=${on ?
|
|
127
|
+
<${Text} bold=${on} color=${on ? C.brand : C.muted} dimColor=${!on} inverse=${on}>
|
|
128
128
|
${label}
|
|
129
129
|
<//>
|
|
130
130
|
<//>`;
|
|
@@ -229,8 +229,9 @@ export function UserMessage({ text, cols = 80, ts }) {
|
|
|
229
229
|
const stamp = ts ? new Date(ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }) : '';
|
|
230
230
|
return html`
|
|
231
231
|
<${Box} flexDirection="column" marginBottom=${1}>
|
|
232
|
+
<${Sep} cols=${cols} />
|
|
232
233
|
<${Box} flexDirection="row" justifyContent="space-between" width=${cols} paddingX=${1}>
|
|
233
|
-
<${Text} bold color
|
|
234
|
+
<${Text} bold color=${C.brand}>You<//>
|
|
234
235
|
<${Text} color=${C.muted}>${stamp}<//>
|
|
235
236
|
<//>
|
|
236
237
|
<${Box} paddingX=${1} marginLeft=${2} flexWrap="wrap">
|
|
@@ -264,12 +265,14 @@ function StreamingText({ text = '' }) {
|
|
|
264
265
|
|
|
265
266
|
export function AssistantMessage({ text, cols = 80, ts, label, streaming = false }) {
|
|
266
267
|
const stamp = ts ? new Date(ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }) : '';
|
|
267
|
-
const speakerLabel = streaming ? 'iCopilot ●' : 'iCopilot';
|
|
268
268
|
const bodyWidth = Math.min(cols, 100);
|
|
269
269
|
return html`
|
|
270
270
|
<${Box} flexDirection="column" marginBottom=${1}>
|
|
271
|
+
<${Sep} cols=${cols} />
|
|
271
272
|
<${Box} flexDirection="row" justifyContent="space-between" width=${cols} paddingX=${1}>
|
|
272
|
-
<${
|
|
273
|
+
<${Box}>
|
|
274
|
+
<${Text} color=${C.accent} bold>${glyphs.copilotDot} <//><${Text} bold>iCopilot${streaming ? ' ●' : ''}<//>
|
|
275
|
+
<//>
|
|
273
276
|
<${Text} color=${C.muted}>${stamp}<//>
|
|
274
277
|
<//>
|
|
275
278
|
<${Box} paddingX=${1} marginLeft=${2} flexDirection="column" width=${bodyWidth}>
|
|
@@ -279,18 +282,22 @@ export function AssistantMessage({ text, cols = 80, ts, label, streaming = false
|
|
|
279
282
|
}
|
|
280
283
|
|
|
281
284
|
export function ShellOutput({ command, output, cols = 80, ts, code = 0 }) {
|
|
285
|
+
const ok = code === 0;
|
|
286
|
+
const tone = ok ? C.success : C.error;
|
|
282
287
|
return html`
|
|
283
288
|
<${Box} flexDirection="column" marginTop=${1}>
|
|
289
|
+
<${Sep} cols=${cols} />
|
|
284
290
|
<${SpeakerLine}
|
|
285
291
|
label=${"$ Shell"}
|
|
286
|
-
color=${
|
|
292
|
+
color=${tone}
|
|
287
293
|
cols=${cols}
|
|
288
294
|
ts=${ts}
|
|
289
|
-
rightLabel=${
|
|
295
|
+
rightLabel=${ok ? '' : `exit ${code}`}
|
|
290
296
|
/>
|
|
291
297
|
<${Box} paddingX=${1} flexDirection="column">
|
|
292
298
|
<${Text} color=${C.warning}>$ ${command}<//>
|
|
293
|
-
<${Text}>${
|
|
299
|
+
<${Text} color=${tone}>${ok ? glyphs.check : `${glyphs.cross} exit ${code}` }<//>
|
|
300
|
+
<${Text} color=${ok ? C.white : tone}>${output || '(no output)'}<//>
|
|
294
301
|
<//>
|
|
295
302
|
<//>`;
|
|
296
303
|
}
|
|
@@ -386,6 +393,7 @@ export function StatusLines({ lines = [], busy = false, navigable = false }) {
|
|
|
386
393
|
if (!lines.length) return null;
|
|
387
394
|
const lastIdx = lines.length - 1;
|
|
388
395
|
|
|
396
|
+
|
|
389
397
|
return html`
|
|
390
398
|
<${Box} flexDirection="column" marginTop=${1}>
|
|
391
399
|
${lines.map((line, i) => {
|
|
@@ -654,15 +662,17 @@ export function Thinking({ label = 'Working', startedAt }) {
|
|
|
654
662
|
}
|
|
655
663
|
|
|
656
664
|
export function Choice({ title, note, options = [], sel = 0, allowText = false, text = '', focusText = false, isToolApproval = false, cols = 80 }) {
|
|
657
|
-
// §13: tool approval uses
|
|
665
|
+
// §13: tool approval uses separator-line style matching TUI.md spec exactly
|
|
658
666
|
if (isToolApproval) {
|
|
659
667
|
return html`
|
|
660
668
|
<${Box} flexDirection="column" marginTop=${1}>
|
|
661
|
-
<${
|
|
662
|
-
|
|
669
|
+
<${Sep} cols=${cols} />
|
|
670
|
+
<${Box} paddingX=${1} marginBottom=${1}>
|
|
671
|
+
<${Text} color=${C.accent} bold>${glyphs.settings} Tool request<//>
|
|
663
672
|
<//>
|
|
664
|
-
|
|
665
|
-
|
|
673
|
+
<${Sep} cols=${cols} />
|
|
674
|
+
${note ? html`<${Box} paddingX=${1} marginTop=${1} marginBottom=${1}><${Text} color=${C.white}>${note}<//><//>` : null}
|
|
675
|
+
<${Box} flexDirection="column" marginTop=${1} paddingX=${1}>
|
|
666
676
|
${options.map((o, i) => {
|
|
667
677
|
const on = !focusText && i === sel;
|
|
668
678
|
const label = o.label ?? o.value ?? String(o);
|
|
@@ -676,13 +686,13 @@ export function Choice({ title, note, options = [], sel = 0, allowText = false,
|
|
|
676
686
|
${allowText
|
|
677
687
|
? html`<${Box} key="freetext" marginTop=${1}>
|
|
678
688
|
<${Text} color=${focusText ? C.accent : C.muted}>${focusText ? glyphs.prompt + ' ' : ' '}<//>
|
|
679
|
-
<${Text} color=${C.muted}>Tell
|
|
689
|
+
<${Text} color=${C.muted}>Tell iCopilot what to do differently: <//>
|
|
680
690
|
<${Text} color=${C.white}>${text}<//>${focusText ? html`<${Text} inverse> <//>` : null}
|
|
681
691
|
<//>`
|
|
682
692
|
: null}
|
|
683
693
|
<//>
|
|
684
|
-
<${Box} marginTop=${1} paddingX=${
|
|
685
|
-
<${Text} color=${C.muted}
|
|
694
|
+
<${Box} marginTop=${1} paddingX=${1}>
|
|
695
|
+
<${Text} color=${C.muted}>y / a / n ${midDot()} ${glyphs.up}${glyphs.down} move ${midDot()} Enter confirm ${midDot()} Esc cancel<//>
|
|
686
696
|
<//>
|
|
687
697
|
<//>`;
|
|
688
698
|
}
|
package/src/tui/composer.js
CHANGED
|
@@ -512,7 +512,7 @@ export function Composer({
|
|
|
512
512
|
<//>`
|
|
513
513
|
: null}
|
|
514
514
|
|
|
515
|
-
<${Text} color=${C.
|
|
515
|
+
<${Text} color=${C.accent}>${'_'.repeat(Math.max(1, width))}<//>
|
|
516
516
|
|
|
517
517
|
<${Box} width=${width} paddingX=${1} justifyContent="space-between">
|
|
518
518
|
<${Box} flexGrow=${1}>
|
package/src/tui/run.js
CHANGED
|
@@ -93,7 +93,7 @@ function exitAltScreen() {
|
|
|
93
93
|
altScreenActive = false;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
//
|
|
96
|
+
// iPolot wordmark in block letters
|
|
97
97
|
const LOGO = [
|
|
98
98
|
' ██╗ ██████╗ ██████╗ ██████╗ ██╗██╗ ██████╗ ████████╗',
|
|
99
99
|
' ██║██╔════╝██╔═══██╗██╔══██╗██║██║ ██╔═══██╗╚══██╔══╝',
|
|
@@ -145,8 +145,8 @@ async function animateSplash(cfg = {}) {
|
|
|
145
145
|
const R = '\x1b[0m';
|
|
146
146
|
|
|
147
147
|
const hr = `${SEP}${'─'.repeat(cols)}${R}`;
|
|
148
|
-
const subtitle = `${ACC}◈
|
|
149
|
-
const subtitleLen =
|
|
148
|
+
const subtitle = `${ACC}◈ iPolot${R} ${DIM}IspBills network engineer in your terminal${R}`;
|
|
149
|
+
const subtitleLen = subtitle.replace(/\x1b\[[0-9;]*m/g, '').length;
|
|
150
150
|
const subPad = ' '.repeat(Math.max(0, Math.floor((cols - subtitleLen) / 2)));
|
|
151
151
|
|
|
152
152
|
process.stdout.write(`\n${hr}\n`);
|
package/src/tui/theme.js
CHANGED
|
@@ -46,6 +46,7 @@ const ASCII_EXTRA = {
|
|
|
46
46
|
chip: '|', // chip separator
|
|
47
47
|
expand: '+', // expand indicator
|
|
48
48
|
collapse: '-', // collapse indicator
|
|
49
|
+
settings: '#', // tool-approval header (ASCII safe)
|
|
49
50
|
};
|
|
50
51
|
const UNICODE_EXTRA = {
|
|
51
52
|
copilotDot: '◈', // spec §6: ◈ Copilot speaker label (◈ in accent/purple)
|
|
@@ -56,6 +57,7 @@ const UNICODE_EXTRA = {
|
|
|
56
57
|
chip: '·',
|
|
57
58
|
expand: '▸',
|
|
58
59
|
collapse: '▾',
|
|
60
|
+
settings: '⚙', // spec §13: tool request header glyph
|
|
59
61
|
};
|
|
60
62
|
|
|
61
63
|
// Merged glyph proxy: own extras first, then ui.js base glyphs.
|