@pellux/goodvibes-agent 1.5.5 → 1.5.6
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/CHANGELOG.md +9 -0
- package/README.md +1 -1
- package/dist/package/main.js +94130 -79335
- package/docs/tools-and-commands.md +2 -1
- package/package.json +6 -3
- package/src/agent/autonomy-schedule-format.ts +1 -1
- package/src/agent/autonomy-schedule.ts +3 -3
- package/src/agent/calendar/calendar-oauth-service.ts +324 -0
- package/src/agent/calendar-subscription-registry.ts +497 -0
- package/src/agent/email/email-service.ts +57 -0
- package/src/agent/email/smtp-client.ts +30 -10
- package/src/agent/memory-prompt.ts +143 -12
- package/src/agent/operator-actions.ts +26 -22
- package/src/agent/prompt-context-receipts.ts +45 -18
- package/src/agent/reminder-schedule-format.ts +1 -1
- package/src/agent/reminder-schedule.ts +3 -3
- package/src/agent/routine-schedule-format.ts +2 -2
- package/src/agent/routine-schedule-promotion.ts +5 -5
- package/src/agent/routine-schedule-receipts.ts +2 -2
- package/src/agent/schedule-edit-format.ts +1 -1
- package/src/agent/schedule-edit.ts +5 -5
- package/src/agent/session-registration.ts +281 -0
- package/src/agent/vibe-file.ts +50 -0
- package/src/cli/local-library-command-shared.ts +146 -0
- package/src/cli/management.ts +2 -1
- package/src/cli/personas-command.ts +252 -0
- package/src/cli/resume-relaunch-notice.ts +151 -0
- package/src/cli/routines-command.ts +25 -2
- package/src/cli/service-posture.ts +3 -2
- package/src/cli/skill-bundle-command.ts +175 -0
- package/src/cli/skills-command.ts +309 -0
- package/src/cli/status.ts +43 -7
- package/src/cli/tui-startup.ts +24 -1
- package/src/config/agent-settings-policy.ts +0 -1
- package/src/config/secret-config.ts +4 -0
- package/src/core/conversation-rendering.ts +20 -11
- package/src/core/focus-tracker.ts +41 -0
- package/src/core/system-message-noise.ts +108 -0
- package/src/core/system-message-router.ts +54 -1
- package/src/core/thinking-overlay.ts +83 -0
- package/src/input/agent-workspace-access-command-editor-submission.ts +75 -108
- package/src/input/agent-workspace-access-command-editors.ts +108 -128
- package/src/input/agent-workspace-activation.ts +15 -0
- package/src/input/agent-workspace-basic-command-editor-submission.ts +292 -513
- package/src/input/agent-workspace-basic-command-editors.ts +433 -564
- package/src/input/agent-workspace-calendar-connect-editor.ts +116 -0
- package/src/input/agent-workspace-calendar-oauth-editor.ts +152 -0
- package/src/input/agent-workspace-calendar-subscribe-editor.ts +128 -0
- package/src/input/agent-workspace-categories.ts +7 -2
- package/src/input/agent-workspace-channel-command-editor-submission.ts +38 -52
- package/src/input/agent-workspace-channel-command-editors.ts +42 -46
- package/src/input/agent-workspace-command-editor-engine.ts +133 -0
- package/src/input/agent-workspace-command-editor.ts +4 -0
- package/src/input/agent-workspace-direct-editor-submission.ts +59 -0
- package/src/input/agent-workspace-email-connect-editor.ts +162 -0
- package/src/input/agent-workspace-knowledge-command-editor-submission.ts +52 -81
- package/src/input/agent-workspace-knowledge-command-editors.ts +71 -71
- package/src/input/agent-workspace-library-command-editor-submission.ts +10 -28
- package/src/input/agent-workspace-library-command-editors.ts +16 -2
- package/src/input/agent-workspace-live-counters.ts +55 -0
- package/src/input/agent-workspace-mcp-command-editor-submission.ts +60 -82
- package/src/input/agent-workspace-mcp-command-editors.ts +52 -0
- package/src/input/agent-workspace-media-command-editor-submission.ts +12 -39
- package/src/input/agent-workspace-media-command-editors.ts +10 -8
- package/src/input/agent-workspace-memory-command-editor-submission.ts +76 -151
- package/src/input/agent-workspace-memory-command-editors.ts +116 -141
- package/src/input/agent-workspace-operations-command-editor-submission.ts +131 -184
- package/src/input/agent-workspace-operations-command-editors.ts +150 -162
- package/src/input/agent-workspace-provider-command-editor-submission.ts +60 -106
- package/src/input/agent-workspace-provider-command-editors.ts +58 -68
- package/src/input/agent-workspace-search.ts +8 -1
- package/src/input/agent-workspace-session-command-editor-submission.ts +104 -132
- package/src/input/agent-workspace-session-command-editors.ts +160 -195
- package/src/input/agent-workspace-settings.ts +40 -1
- package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +55 -71
- package/src/input/agent-workspace-skill-bundle-command-editors.ts +65 -69
- package/src/input/agent-workspace-snapshot-builders.ts +431 -0
- package/src/input/agent-workspace-snapshot-config.ts +43 -0
- package/src/input/agent-workspace-snapshot.ts +198 -432
- package/src/input/agent-workspace-task-command-editor-submission.ts +34 -44
- package/src/input/agent-workspace-task-command-editors.ts +27 -28
- package/src/input/agent-workspace-types.ts +35 -1
- package/src/input/agent-workspace.ts +5 -14
- package/src/input/command-registry.ts +23 -1
- package/src/input/commands/calendar-connect-runtime.ts +226 -0
- package/src/input/commands/calendar-runtime.ts +110 -7
- package/src/input/commands/calendar-subscription-runtime.ts +225 -0
- package/src/input/commands/email-runtime.ts +100 -40
- package/src/input/commands/knowledge.ts +1 -1
- package/src/input/commands/network-scan-runtime.ts +75 -0
- package/src/input/commands/operator-actions-runtime.ts +9 -6
- package/src/input/commands/personas-runtime.ts +1 -1
- package/src/input/commands/schedule-runtime.ts +4 -4
- package/src/input/commands/session-content.ts +13 -1
- package/src/input/commands/session-workflow.ts +15 -20
- package/src/input/commands/session.ts +3 -1
- package/src/input/commands/shell-core.ts +20 -6
- package/src/input/commands.ts +2 -2
- package/src/input/delete-key-policy.ts +46 -0
- package/src/input/feed-context-factory.ts +10 -0
- package/src/input/handler-feed.ts +87 -0
- package/src/input/handler-modal-routes.ts +6 -1
- package/src/input/handler.ts +5 -0
- package/src/input/panel-paste-flood-guard.ts +94 -0
- package/src/input/settings-modal-types.ts +5 -3
- package/src/input/settings-modal.ts +21 -0
- package/src/main.ts +36 -36
- package/src/permissions/approval-posture.ts +141 -0
- package/src/renderer/agent-workspace-context-lines.ts +10 -2
- package/src/renderer/compositor.ts +27 -4
- package/src/renderer/diff.ts +61 -18
- package/src/renderer/fullscreen-primitives.ts +37 -18
- package/src/renderer/markdown.ts +20 -10
- package/src/renderer/modal-factory.ts +25 -15
- package/src/renderer/overlay-box.ts +23 -12
- package/src/renderer/process-indicator.ts +8 -3
- package/src/renderer/prompt-content-width.ts +16 -0
- package/src/renderer/settings-modal-helpers.ts +2 -0
- package/src/renderer/settings-modal.ts +2 -0
- package/src/renderer/startup-theme-probe.ts +35 -0
- package/src/renderer/status-glyphs.ts +11 -15
- package/src/renderer/system-message.ts +17 -2
- package/src/renderer/term-caps.ts +318 -0
- package/src/renderer/terminal-bg-probe.ts +373 -0
- package/src/renderer/terminal-escapes.ts +24 -0
- package/src/renderer/theme-mode-config.ts +87 -0
- package/src/renderer/theme.ts +241 -0
- package/src/renderer/thinking.ts +12 -3
- package/src/renderer/tool-call.ts +7 -3
- package/src/renderer/ui-factory.ts +92 -36
- package/src/renderer/ui-primitives.ts +33 -93
- package/src/runtime/bootstrap-core.ts +15 -0
- package/src/runtime/bootstrap-hook-bridge.ts +6 -0
- package/src/runtime/bootstrap-shell.ts +2 -0
- package/src/runtime/bootstrap.ts +68 -5
- package/src/runtime/calendar-boot-refresh.ts +105 -0
- package/src/runtime/lan-scan-consent.ts +253 -0
- package/src/runtime/services.ts +127 -2
- package/src/runtime/session-spine-rest-transport.ts +160 -0
- package/src/runtime/terminal-output-guard.ts +6 -1
- package/src/runtime/ui-services.ts +3 -0
- package/src/shell/agent-workspace-fullscreen.ts +5 -0
- package/src/shell/terminal-focus-mode.ts +120 -0
- package/src/shell/ui-openers.ts +13 -4
- package/src/tools/agent-harness-autonomy-intake.ts +5 -5
- package/src/tools/agent-harness-autonomy-queue.ts +1 -1
- package/src/tools/agent-harness-background-processes.ts +2 -1
- package/src/tools/agent-harness-metadata.ts +16 -8
- package/src/tools/agent-harness-operator-methods.ts +44 -8
- package/src/tools/agent-harness-personal-ops-discovery.ts +57 -10
- package/src/tools/agent-harness-personal-ops-lanes.ts +17 -5
- package/src/tools/agent-harness-personal-ops-operations.ts +7 -7
- package/src/tools/agent-harness-personal-ops-types.ts +6 -0
- package/src/tools/agent-harness-prompt-context.ts +26 -12
- package/src/tools/agent-harness-workspace-actions.ts +4 -0
- package/src/tools/agent-local-registry-args.ts +117 -0
- package/src/tools/agent-local-registry-memory.ts +227 -0
- package/src/tools/agent-local-registry-tool.ts +19 -237
- package/src/tools/agent-operator-briefing-tool.ts +2 -2
- package/src/tools/agent-operator-method-tool.ts +13 -0
- package/src/tools/agent-policy-explanation.ts +39 -4
- package/src/tools/agent-schedule-tool.ts +5 -5
- package/src/utils/terminal-width.ts +98 -1
- package/src/version.ts +1 -1
- package/src/cli/local-library-command.ts +0 -825
package/src/renderer/markdown.ts
CHANGED
|
@@ -3,6 +3,13 @@ import { UIFactory } from './ui-factory.ts';
|
|
|
3
3
|
import { renderCodeBlock } from './code-block.ts';
|
|
4
4
|
import { getDisplayWidth } from '../utils/terminal-width.ts';
|
|
5
5
|
import { LAYOUT } from './layout.ts';
|
|
6
|
+
import { activeTheme } from './theme.ts';
|
|
7
|
+
|
|
8
|
+
// Transcript tokens are read live per render (const T = activeTheme() at the top
|
|
9
|
+
// of each render function below) so a dark→light repaint re-resolves with no
|
|
10
|
+
// module reload. Dark values are byte-identical to the agent's prior static
|
|
11
|
+
// reads; the only dark change is inline code losing its dark background box (it
|
|
12
|
+
// gains bold instead — the near-black box was unreadable on a light terminal).
|
|
6
13
|
|
|
7
14
|
export interface MarkdownRenderOptions {
|
|
8
15
|
codeBlockLineNumbers?: boolean;
|
|
@@ -56,6 +63,7 @@ export function renderMarkdownTracked(
|
|
|
56
63
|
width: number,
|
|
57
64
|
options: MarkdownRenderOptions = {},
|
|
58
65
|
): { lines: ReturnType<typeof renderMarkdown>; codeBlocks: CodeBlockSpan[] } {
|
|
66
|
+
const T = activeTheme();
|
|
59
67
|
const lines: ReturnType<typeof renderMarkdown> = [];
|
|
60
68
|
const codeBlocks: CodeBlockSpan[] = [];
|
|
61
69
|
const rawLines = text.split('\n');
|
|
@@ -106,17 +114,17 @@ export function renderMarkdownTracked(
|
|
|
106
114
|
const h2 = raw.match(/^## (.+)/);
|
|
107
115
|
const h1 = raw.match(/^# (.+)/);
|
|
108
116
|
if (h1) {
|
|
109
|
-
lines.push(UIFactory.stringToLine(' '.repeat(indent) + h1[1].toUpperCase(), width, { fg:
|
|
117
|
+
lines.push(UIFactory.stringToLine(' '.repeat(indent) + h1[1].toUpperCase(), width, { fg: T.heading1, bold: true }));
|
|
110
118
|
lines.push(UIFactory.stringToLine(' '.repeat(indent) + '━'.repeat(Math.min(getDisplayWidth(h1[1]), contentWidth)), width, { fg: '244' }));
|
|
111
119
|
continue;
|
|
112
120
|
}
|
|
113
121
|
if (h2) {
|
|
114
|
-
lines.push(UIFactory.stringToLine(' '.repeat(indent) + h2[1], width, { fg:
|
|
122
|
+
lines.push(UIFactory.stringToLine(' '.repeat(indent) + h2[1], width, { fg: T.heading2, bold: true }));
|
|
115
123
|
lines.push(UIFactory.stringToLine(' '.repeat(indent) + '─'.repeat(Math.min(getDisplayWidth(h2[1]), contentWidth)), width, { fg: '240' }));
|
|
116
124
|
continue;
|
|
117
125
|
}
|
|
118
126
|
if (h3) {
|
|
119
|
-
lines.push(UIFactory.stringToLine(' '.repeat(indent) + h3[1], width, { fg:
|
|
127
|
+
lines.push(UIFactory.stringToLine(' '.repeat(indent) + h3[1], width, { fg: T.heading3, bold: true }));
|
|
120
128
|
continue;
|
|
121
129
|
}
|
|
122
130
|
|
|
@@ -130,7 +138,7 @@ export function renderMarkdownTracked(
|
|
|
130
138
|
const rendered = renderInlineMarkdown(taskMatch[3]);
|
|
131
139
|
const prefix = ' '.repeat(bulletX) + checkbox;
|
|
132
140
|
const style = checked ? { fg: '244', strikethrough: true } : {};
|
|
133
|
-
lines.push(...compositeInlineLine(prefix, rendered, width, { fg: checked ?
|
|
141
|
+
lines.push(...compositeInlineLine(prefix, rendered, width, { fg: checked ? T.checkboxChecked : '252', ...style }, textStartX));
|
|
134
142
|
continue;
|
|
135
143
|
}
|
|
136
144
|
|
|
@@ -220,6 +228,7 @@ function stripMarkdown(text: string): string {
|
|
|
220
228
|
* truncates long content, and renders with proper styling.
|
|
221
229
|
*/
|
|
222
230
|
function renderTable(rows: string[], width: number, indent: number): Line[] {
|
|
231
|
+
const T = activeTheme();
|
|
223
232
|
const lines: Line[] = [];
|
|
224
233
|
|
|
225
234
|
// Parse rows into cells, skip separator
|
|
@@ -300,14 +309,14 @@ function renderTable(rows: string[], width: number, indent: number): Line[] {
|
|
|
300
309
|
}
|
|
301
310
|
let style: Partial<Cell> = {};
|
|
302
311
|
if (token.type === 'code') {
|
|
303
|
-
style = { fg:
|
|
312
|
+
style = { fg: T.inlineCodeFg, bold: true };
|
|
304
313
|
} else if (token.type === 'link') {
|
|
305
|
-
style = { fg:
|
|
314
|
+
style = { fg: T.link, underline: true };
|
|
306
315
|
} else {
|
|
307
316
|
style = { ...token.style };
|
|
308
317
|
}
|
|
309
318
|
if (isHdr) {
|
|
310
|
-
style.fg = style.fg ||
|
|
319
|
+
style.fg = style.fg || T.heading1;
|
|
311
320
|
style.bold = true;
|
|
312
321
|
} else {
|
|
313
322
|
style.fg = style.fg || '252';
|
|
@@ -320,7 +329,7 @@ function renderTable(rows: string[], width: number, indent: number): Line[] {
|
|
|
320
329
|
|
|
321
330
|
// Pad remaining space
|
|
322
331
|
while (w < maxW) {
|
|
323
|
-
cells.push(createStyledCell(' ', isHdr ? { fg:
|
|
332
|
+
cells.push(createStyledCell(' ', isHdr ? { fg: T.heading1 } : { fg: '252' }));
|
|
324
333
|
w++;
|
|
325
334
|
}
|
|
326
335
|
return cells;
|
|
@@ -518,6 +527,7 @@ function compositeInlineLine(
|
|
|
518
527
|
prefixStyle: Partial<Cell>,
|
|
519
528
|
textStartX: number
|
|
520
529
|
): Line[] {
|
|
530
|
+
const T = activeTheme();
|
|
521
531
|
const lines: Line[] = [];
|
|
522
532
|
|
|
523
533
|
// Flatten tokens to [char, style] pairs
|
|
@@ -528,14 +538,14 @@ function compositeInlineLine(
|
|
|
528
538
|
if (token.type === 'text') {
|
|
529
539
|
for (const ch of token.text) chars.push({ char: ch, style: token.style });
|
|
530
540
|
} else if (token.type === 'code') {
|
|
531
|
-
for (const ch of token.text) chars.push({ char: ch, style: { fg:
|
|
541
|
+
for (const ch of token.text) chars.push({ char: ch, style: { fg: T.inlineCodeFg, bold: true } });
|
|
532
542
|
} else if (token.type === 'link') {
|
|
533
543
|
// Resolve URL: if url is empty or relative, treat as text; if it's a file path, use file:// protocol
|
|
534
544
|
let resolvedUrl = token.url;
|
|
535
545
|
if (resolvedUrl && !resolvedUrl.startsWith('http') && !resolvedUrl.startsWith('file://') && resolvedUrl.startsWith('/')) {
|
|
536
546
|
resolvedUrl = `file://${resolvedUrl}`;
|
|
537
547
|
}
|
|
538
|
-
for (const ch of token.text) chars.push({ char: ch, style: { fg:
|
|
548
|
+
for (const ch of token.text) chars.push({ char: ch, style: { fg: T.link, underline: true, link: resolvedUrl || undefined } });
|
|
539
549
|
}
|
|
540
550
|
}
|
|
541
551
|
|
|
@@ -8,7 +8,8 @@ import {
|
|
|
8
8
|
putOverlayText,
|
|
9
9
|
} from './overlay-box.ts';
|
|
10
10
|
import { getOverlayMaxWidth } from './overlay-viewport.ts';
|
|
11
|
-
import { GLYPHS
|
|
11
|
+
import { GLYPHS } from './ui-primitives.ts';
|
|
12
|
+
import { activeUiTones, registerThemeRefresh } from './theme.ts';
|
|
12
13
|
|
|
13
14
|
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
14
15
|
|
|
@@ -90,20 +91,29 @@ export interface ModalConfig {
|
|
|
90
91
|
|
|
91
92
|
// ── Defaults ─────────────────────────────────────────────────────────────────
|
|
92
93
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
94
|
+
// Built from the mode-resolved chrome tones (activeUiTones) and rebuilt IN PLACE
|
|
95
|
+
// on a mode flip via the registered refresher (read by reference across modal
|
|
96
|
+
// call sites). These paint the OPAQUE dark modal surface, so in the SDK light
|
|
97
|
+
// tones the fg/bg roles stay dark (only state.info flips) — dark is byte-identical.
|
|
98
|
+
function buildModalStyle(): Required<ModalStyle> {
|
|
99
|
+
const t = activeUiTones();
|
|
100
|
+
return {
|
|
101
|
+
titleFg: t.fg.primary,
|
|
102
|
+
borderFg: t.fg.dim,
|
|
103
|
+
hintFg: t.fg.muted,
|
|
104
|
+
selectedFg: t.fg.primary,
|
|
105
|
+
selectedBg: t.bg.selected,
|
|
106
|
+
textFg: t.fg.primary,
|
|
107
|
+
accentFg: t.state.info,
|
|
108
|
+
titleRowFg: t.fg.secondary,
|
|
109
|
+
titleBg: t.bg.title,
|
|
110
|
+
sectionBg: t.bg.section,
|
|
111
|
+
inputBg: t.bg.input,
|
|
112
|
+
surfaceBg: t.bg.surface,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
const DEFAULT_STYLE: Required<ModalStyle> = buildModalStyle();
|
|
116
|
+
registerThemeRefresh(() => Object.assign(DEFAULT_STYLE, buildModalStyle()));
|
|
107
117
|
|
|
108
118
|
// ── ModalFactory ─────────────────────────────────────────────────────────────
|
|
109
119
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createStyledCell, type Line } from '../types/grid.ts';
|
|
2
2
|
import { getOverlayMaxWidth } from './overlay-viewport.ts';
|
|
3
|
-
import { GLYPHS
|
|
3
|
+
import { GLYPHS } from './ui-primitives.ts';
|
|
4
|
+
import { activeUiTones, registerThemeRefresh } from './theme.ts';
|
|
4
5
|
import { fillWidth, makeLine, writeText } from './fullscreen-primitives.ts';
|
|
5
6
|
|
|
6
7
|
export interface OverlayBoxPalette {
|
|
@@ -15,17 +16,27 @@ export interface OverlayBoxPalette {
|
|
|
15
16
|
readonly bodyBg: string;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
// Built from the mode-resolved chrome tones (activeUiTones) and rebuilt IN PLACE
|
|
20
|
+
// on a mode flip via the registered refresher (read by reference across the
|
|
21
|
+
// overlay call sites). Opaque dark overlay surface → fg/bg roles stay dark in
|
|
22
|
+
// the SDK light tones; dark is byte-identical to the prior static reads.
|
|
23
|
+
function buildOverlayPalette(): OverlayBoxPalette {
|
|
24
|
+
const t = activeUiTones();
|
|
25
|
+
return {
|
|
26
|
+
borderFg: t.fg.secondary,
|
|
27
|
+
titleFg: t.fg.primary,
|
|
28
|
+
bodyFg: t.fg.primary,
|
|
29
|
+
mutedFg: t.fg.dim,
|
|
30
|
+
selectedBg: t.bg.selected,
|
|
31
|
+
titleBg: t.bg.title,
|
|
32
|
+
sectionBg: t.bg.section,
|
|
33
|
+
inputBg: t.bg.input,
|
|
34
|
+
bodyBg: t.bg.surface,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const DEFAULT_OVERLAY_PALETTE: Readonly<OverlayBoxPalette> = buildOverlayPalette();
|
|
39
|
+
registerThemeRefresh(() => Object.assign(DEFAULT_OVERLAY_PALETTE as OverlayBoxPalette, buildOverlayPalette()));
|
|
29
40
|
|
|
30
41
|
export interface OverlayBoxLayout {
|
|
31
42
|
readonly margin: number;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { type Line } from '../types/grid.ts';
|
|
2
2
|
import { UIFactory } from './ui-factory.ts';
|
|
3
3
|
import { getDisplayWidth } from '../utils/terminal-width.ts';
|
|
4
|
-
import { GLYPHS } from './ui-primitives.ts';
|
|
4
|
+
import { GLYPHS, UI_TONES } from './ui-primitives.ts';
|
|
5
|
+
import { activeUiTones } from './theme.ts';
|
|
5
6
|
|
|
6
7
|
/** Truncate a string to fit within maxWidth display columns. */
|
|
7
8
|
function truncateToWidth(text: string, maxWidth: number): string {
|
|
@@ -39,7 +40,9 @@ export function renderProcessIndicator(
|
|
|
39
40
|
const renderFocusedStatus = (text: string): Line[] => {
|
|
40
41
|
const bg = '#31506f';
|
|
41
42
|
const fg = '#eefaff';
|
|
42
|
-
|
|
43
|
+
// Opaque highlight bar (bg/fg fixed) — marker sourced from the shared
|
|
44
|
+
// browser accent token (dark == the prior browser-cyan marker).
|
|
45
|
+
const markerFg = UI_TONES.accent.browser;
|
|
43
46
|
const line = UIFactory.stringToLine(' '.repeat(width), width, { fg: '238' });
|
|
44
47
|
const prefix = `${GLYPHS.navigation.selected} `;
|
|
45
48
|
const body = truncateToWidth(text, Math.max(0, width - 8));
|
|
@@ -93,5 +96,7 @@ export function renderProcessIndicator(
|
|
|
93
96
|
: '';
|
|
94
97
|
const label = `${parts.join(` ${GLYPHS.navigation.pipeSeparator} `)}${progressSuffix}`;
|
|
95
98
|
const hint = ` ${GLYPHS.status.pending} Enter to view`;
|
|
96
|
-
|
|
99
|
+
// Active-status label paints on the transparent terminal bg → read the live
|
|
100
|
+
// brand accent so it flips to a legible value in light mode (dark == brand cyan).
|
|
101
|
+
return renderPlainStatus(`${label}${hint}`, { fg: activeUiTones().accent.brand, bold: true });
|
|
97
102
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* computePromptContentWidth — content width available for prompt text inside
|
|
3
|
+
* the footer input box, after the box margin, inner padding, and the ' > '
|
|
4
|
+
* prefix are subtracted.
|
|
5
|
+
*
|
|
6
|
+
* Floors at 1: on a hostile-narrow terminal the raw subtraction
|
|
7
|
+
* (boxWidth - 4 - 3) can go zero or negative, and a non-positive content
|
|
8
|
+
* width breaks downstream text-wrapping and cursor-position math (which
|
|
9
|
+
* assume at least one column to place a character in).
|
|
10
|
+
*/
|
|
11
|
+
export function computePromptContentWidth(terminalColumns: number): number {
|
|
12
|
+
const w = terminalColumns || 80;
|
|
13
|
+
const boxMargin = 2;
|
|
14
|
+
const boxWidth = w - (boxMargin * 2);
|
|
15
|
+
return Math.max(1, boxWidth - 4 - 3); // minus padding (4) minus prefix width (3: ' > ')
|
|
16
|
+
}
|
|
@@ -92,6 +92,8 @@ export const CATEGORY_LABELS: Record<(typeof SETTINGS_CATEGORIES)[number], strin
|
|
|
92
92
|
watchers: 'Watchers',
|
|
93
93
|
network: 'Network',
|
|
94
94
|
orchestration: 'Orchestration',
|
|
95
|
+
planner: 'Planner',
|
|
96
|
+
daemon: 'Daemon',
|
|
95
97
|
runtime: 'Runtime',
|
|
96
98
|
sandbox: 'Sandbox',
|
|
97
99
|
batch: 'Batch',
|
|
@@ -41,6 +41,8 @@ const CATEGORY_INFO: Record<SettingsCategory, string> = {
|
|
|
41
41
|
watchers: 'Polling watcher and heartbeat behavior for runtime recovery and periodic checks.',
|
|
42
42
|
network: 'Outbound TLS and remote fetch network policy.',
|
|
43
43
|
orchestration: 'Visible agent orchestration limits such as recursion and active-agent caps.',
|
|
44
|
+
planner: 'Planning-decomposition agent limits: decomposition strategy, max turns, token ceiling, and wall-clock timeout before falling back to the deterministic heuristic path.',
|
|
45
|
+
daemon: 'Whether the local session daemon runs, and whether it is embedded in this surface process instead of spawned as a detached background service.',
|
|
44
46
|
runtime: 'Runtime service limits and event bus settings.',
|
|
45
47
|
sandbox: 'Isolation settings for REPL, MCP, and VM-backed sessions.',
|
|
46
48
|
batch: 'Batch queue backend, limits, and provider batching behavior.',
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* startup-theme-probe.ts (W4-R4) — install the OSC-11 background probe at
|
|
3
|
+
* startup and wire its resolved mode to the ported theme system.
|
|
4
|
+
*
|
|
5
|
+
* Thin composition seam extracted from main.ts: it binds R2's
|
|
6
|
+
* installBackgroundThemeProbe to theme.ts's setActiveThemeMode (applyThemeMode)
|
|
7
|
+
* so forced dark/light applies before first paint and auto (TTY only) probes and
|
|
8
|
+
* repaints once if light wins. The returned handle's filterInput() must gate the
|
|
9
|
+
* stdin data handler so the OSC-11 reply never reaches the tokenizer.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { installBackgroundThemeProbe, type ThemeProbeHandle } from './terminal-bg-probe.ts';
|
|
13
|
+
import { setActiveThemeMode } from './theme.ts';
|
|
14
|
+
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
15
|
+
|
|
16
|
+
export interface StartupThemeProbeDeps {
|
|
17
|
+
readonly configManager: Pick<ConfigManager, 'get'>;
|
|
18
|
+
readonly stdout: NodeJS.WriteStream;
|
|
19
|
+
/** The caller's terminal-output guard wrapper (allowTerminalWrite). */
|
|
20
|
+
readonly writeAllowed: (write: () => void) => void;
|
|
21
|
+
/** Reset the compositor diff so the repaint after a light reply is full. */
|
|
22
|
+
readonly resetDiff: () => void;
|
|
23
|
+
readonly render: () => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function installStartupThemeProbe(deps: StartupThemeProbeDeps): ThemeProbeHandle {
|
|
27
|
+
return installBackgroundThemeProbe({
|
|
28
|
+
configManager: deps.configManager,
|
|
29
|
+
applyThemeMode: setActiveThemeMode,
|
|
30
|
+
isTTY: Boolean(deps.stdout.isTTY),
|
|
31
|
+
env: process.env,
|
|
32
|
+
writeQuery: (b) => deps.writeAllowed(() => deps.stdout.write(b)),
|
|
33
|
+
requestRepaint: () => { deps.resetDiff(); deps.render(); },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
// ---------------------------------------------------------------------------
|
|
2
2
|
// status-glyphs.ts — canonical glyph map for status states.
|
|
3
3
|
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
4
|
+
// W4-R4: STATE_GLYPHS is no longer hardcoded here. It is the SDK presentation
|
|
5
|
+
// contract (@pellux/goodvibes-sdk/platform/presentation, landed by W4-S1),
|
|
6
|
+
// aliased to GLYPHS.status so the four semantic glyphs are spelled out in
|
|
7
|
+
// exactly one place and can never drift from the registry again. Re-exported
|
|
8
|
+
// under the historical names so status-token.ts and polish.ts import unchanged.
|
|
6
9
|
//
|
|
7
|
-
// Glyphs:
|
|
8
|
-
// good ✓ (CHECK MARK U+2713)
|
|
9
|
-
// warn ⚠ (WARNING SIGN U+26A0)
|
|
10
|
-
// bad ✕ (MULTIPLICATION X U+2715)
|
|
11
|
-
// info ○ (WHITE CIRCLE U+25CB)
|
|
10
|
+
// Glyphs (the reconciled TUI-reference definitions):
|
|
11
|
+
// good ✓ (CHECK MARK U+2713) — GLYPHS.status.success
|
|
12
|
+
// warn ⚠ (WARNING SIGN U+26A0) — GLYPHS.status.warn
|
|
13
|
+
// bad ✕ (MULTIPLICATION X U+2715) — GLYPHS.status.failure
|
|
14
|
+
// info ○ (WHITE CIRCLE U+25CB) — GLYPHS.status.info
|
|
12
15
|
// ---------------------------------------------------------------------------
|
|
13
16
|
|
|
14
|
-
export type StatusState
|
|
15
|
-
|
|
16
|
-
export const STATE_GLYPHS: Record<StatusState, string> = {
|
|
17
|
-
good: '\u2713', // ✓
|
|
18
|
-
warn: '\u26a0', // ⚠
|
|
19
|
-
bad: '\u2715', // ✕
|
|
20
|
-
info: '\u25cb', // ○
|
|
21
|
-
};
|
|
17
|
+
export { STATE_GLYPHS, type StatusState } from '@pellux/goodvibes-sdk/platform/presentation';
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Line } from '../types/grid.ts';
|
|
2
2
|
import { BORDERS, COLORS } from './layout.ts';
|
|
3
3
|
import { renderConversationNotice } from './conversation-surface.ts';
|
|
4
|
+
import { activeUiTones, getActiveThemeMode } from './theme.ts';
|
|
4
5
|
|
|
5
6
|
/** Exported for use by typeOverride callers and tests. */
|
|
6
7
|
export type SystemMessageType = 'error' | 'warning' | 'info';
|
|
@@ -74,9 +75,23 @@ export function renderSystemMessage(
|
|
|
74
75
|
const border = msgType === 'error' ? BORDERS.ERROR
|
|
75
76
|
: msgType === 'warning' ? BORDERS.WARNING
|
|
76
77
|
: BORDERS.INFO;
|
|
77
|
-
|
|
78
|
+
// System-message notices paint the ▌ marker and body on the TRANSPARENT
|
|
79
|
+
// terminal background, so the accent/body must resolve per render to stay
|
|
80
|
+
// legible on a light terminal. Dark is byte-identical to today: the agent's
|
|
81
|
+
// BORDERS.* accents (which include a yellow/cyan that are unreadable on light)
|
|
82
|
+
// are preserved in dark and only swapped for the legible chrome/state tones in
|
|
83
|
+
// light mode. (chrome.bad dark == BORDERS.ERROR.color; only warn/info/faint
|
|
84
|
+
// differ, and only in light.)
|
|
85
|
+
const t = activeUiTones();
|
|
86
|
+
const light = getActiveThemeMode() === 'light';
|
|
87
|
+
const accent = light
|
|
88
|
+
? (msgType === 'error' ? t.chrome.bad : msgType === 'warning' ? t.chrome.warn : t.state.info)
|
|
89
|
+
: border.color;
|
|
90
|
+
const textColor = msgType === 'info'
|
|
91
|
+
? (light ? t.chrome.faint : COLORS.DIM_TEXT)
|
|
92
|
+
: accent;
|
|
78
93
|
return renderConversationNotice(content, width, {
|
|
79
|
-
accent
|
|
94
|
+
accent,
|
|
80
95
|
text: textColor,
|
|
81
96
|
dim: msgType === 'info',
|
|
82
97
|
}, border.char);
|