@pellux/goodvibes-agent 0.1.117 → 1.0.0
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 +13 -4
- package/README.md +35 -14
- package/bin/goodvibes-agent.ts +16 -2
- package/dist/package/main.js +176073 -170980
- package/docs/README.md +11 -5
- package/docs/channels-remote-and-api.md +50 -0
- package/docs/connected-host.md +3 -3
- package/docs/getting-started.md +29 -15
- package/docs/knowledge-artifacts-and-multimodal.md +91 -0
- package/docs/project-planning.md +79 -0
- package/docs/providers-and-routing.md +46 -0
- package/docs/release-and-publishing.md +44 -9
- package/docs/tools-and-commands.md +123 -0
- package/docs/voice-and-live-tts.md +51 -0
- package/package.json +2 -5
- package/src/agent/channel-delivery.ts +201 -0
- package/src/agent/media-generation.ts +159 -0
- package/src/agent/memory-prompt.ts +0 -1
- package/src/agent/note-registry.ts +329 -0
- package/src/agent/operator-actions.ts +343 -0
- package/src/agent/persona-registry.ts +15 -14
- package/src/agent/record-labels.ts +107 -0
- package/src/agent/reminder-schedule-format.ts +33 -24
- package/src/agent/reminder-schedule.ts +26 -25
- package/src/agent/routine-registry.ts +13 -12
- package/src/agent/routine-schedule-args.ts +2 -1
- package/src/agent/routine-schedule-format.ts +77 -53
- package/src/agent/routine-schedule-promotion.ts +34 -32
- package/src/agent/routine-schedule-receipts.ts +28 -26
- package/src/agent/runtime-profile-starters.ts +2 -2
- package/src/agent/runtime-profile.ts +18 -17
- package/src/agent/skill-registry.ts +25 -24
- package/src/cli/agent-knowledge-args.ts +5 -1
- package/src/cli/agent-knowledge-command.ts +39 -33
- package/src/cli/agent-knowledge-format.ts +80 -67
- package/src/cli/agent-knowledge-methods.ts +1 -1
- package/src/cli/agent-knowledge-runtime.ts +32 -26
- package/src/cli/bundle-command.ts +13 -8
- package/src/cli/config-overrides.ts +37 -36
- package/src/cli/external-runtime.ts +10 -4
- package/src/cli/help.ts +29 -11
- package/src/cli/local-library-command.ts +134 -68
- package/src/cli/management-commands.ts +98 -62
- package/src/cli/management.ts +52 -26
- package/src/cli/memory-command.ts +66 -32
- package/src/cli/parser.ts +37 -24
- package/src/cli/profiles-command.ts +52 -35
- package/src/cli/provider-auth-routes.ts +2 -1
- package/src/cli/routines-command.ts +44 -36
- package/src/cli/service-posture.ts +6 -6
- package/src/cli/status.ts +46 -121
- package/src/core/conversation-message-snapshot.ts +131 -0
- package/src/input/agent-workspace-activation.ts +33 -7
- package/src/input/agent-workspace-basic-command-editor-submission.ts +7 -3
- package/src/input/agent-workspace-basic-command-editors.ts +30 -10
- package/src/input/agent-workspace-categories.ts +276 -64
- package/src/input/agent-workspace-channel-command-editor-submission.ts +34 -0
- package/src/input/agent-workspace-channel-command-editors.ts +23 -5
- package/src/input/agent-workspace-channels.ts +35 -2
- package/src/input/agent-workspace-command-editor.ts +18 -2
- package/src/input/agent-workspace-config-reader.ts +16 -0
- package/src/input/agent-workspace-delegation-editor-submission.ts +1 -1
- package/src/input/agent-workspace-editors.ts +140 -2
- package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
- package/src/input/agent-workspace-learned-behavior.ts +2 -2
- package/src/input/agent-workspace-library-command-editor-submission.ts +1 -1
- package/src/input/agent-workspace-library-command-editors.ts +2 -2
- package/src/input/agent-workspace-local-operations.ts +218 -0
- package/src/input/agent-workspace-local-selection.ts +75 -0
- package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
- package/src/input/agent-workspace-media-command-editors.ts +27 -0
- package/src/input/agent-workspace-memory-command-editors.ts +1 -1
- package/src/input/agent-workspace-memory-editor.ts +2 -2
- package/src/input/agent-workspace-navigation.ts +38 -2
- package/src/input/agent-workspace-notify-editor-submission.ts +16 -2
- package/src/input/agent-workspace-operations-command-editor-submission.ts +63 -1
- package/src/input/agent-workspace-operations-command-editors.ts +80 -3
- package/src/input/agent-workspace-panel-route.ts +43 -0
- package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
- package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
- package/src/input/agent-workspace-search.ts +169 -0
- package/src/input/agent-workspace-setup.ts +22 -11
- package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +6 -6
- package/src/input/agent-workspace-skill-bundle-command-editors.ts +10 -10
- package/src/input/agent-workspace-snapshot.ts +112 -13
- package/src/input/agent-workspace-task-command-editors.ts +4 -4
- package/src/input/agent-workspace-token.ts +18 -2
- package/src/input/agent-workspace-types.ts +92 -4
- package/src/input/agent-workspace-voice-media.ts +3 -6
- package/src/input/agent-workspace-web-research-editor.ts +104 -0
- package/src/input/agent-workspace.ts +136 -208
- package/src/input/command-registry.ts +4 -1
- package/src/input/commands/agent-runtime-profile-runtime.ts +45 -41
- package/src/input/commands/agent-skills-runtime.ts +83 -70
- package/src/input/commands/agent-workspace-runtime.ts +23 -7
- package/src/input/commands/brief-runtime.ts +25 -24
- package/src/input/commands/channels-runtime.ts +145 -31
- package/src/input/commands/delegation-runtime.ts +29 -23
- package/src/input/commands/experience-runtime.ts +6 -4
- package/src/input/commands/guidance-runtime.ts +4 -4
- package/src/input/commands/health-runtime.ts +140 -115
- package/src/input/commands/knowledge.ts +57 -56
- package/src/input/commands/local-provider-runtime.ts +36 -18
- package/src/input/commands/local-runtime.ts +138 -16
- package/src/input/commands/local-setup-review.ts +7 -7
- package/src/input/commands/mcp-runtime.ts +56 -35
- package/src/input/commands/notify-runtime.ts +38 -9
- package/src/input/commands/operator-actions-runtime.ts +138 -0
- package/src/input/commands/operator-runtime.ts +6 -17
- package/src/input/commands/personas-runtime.ts +45 -30
- package/src/input/commands/planning-runtime.ts +1 -1
- package/src/input/commands/platform-access-runtime.ts +29 -29
- package/src/input/commands/provider-accounts-runtime.ts +60 -39
- package/src/input/commands/qrcode-runtime.ts +45 -6
- package/src/input/commands/recall-bundle.ts +11 -11
- package/src/input/commands/recall-capture.ts +13 -11
- package/src/input/commands/recall-query.ts +29 -21
- package/src/input/commands/recall-review.ts +2 -1
- package/src/input/commands/routines-runtime.ts +59 -43
- package/src/input/commands/schedule-runtime.ts +33 -20
- package/src/input/commands/security-runtime.ts +4 -4
- package/src/input/commands/session-content.ts +80 -78
- package/src/input/commands/session-workflow.ts +132 -93
- package/src/input/commands/session.ts +3 -174
- package/src/input/commands/shell-core.ts +32 -17
- package/src/input/commands/subscription-runtime.ts +53 -179
- package/src/input/commands/tasks-runtime.ts +20 -20
- package/src/input/commands/work-plan-runtime.ts +33 -8
- package/src/input/commands.ts +2 -2
- package/src/input/feed-context-factory.ts +2 -1
- package/src/input/file-picker.ts +3 -2
- package/src/input/handler-command-route.ts +4 -7
- package/src/input/handler-content-actions.ts +89 -1
- package/src/input/handler-feed-routes.ts +19 -12
- package/src/input/handler-feed.ts +6 -3
- package/src/input/handler-interactions.ts +7 -5
- package/src/input/handler-modal-stack.ts +3 -3
- package/src/input/handler-onboarding.ts +24 -80
- package/src/input/handler-shortcuts.ts +15 -4
- package/src/input/handler.ts +47 -17
- package/src/input/input-history.ts +5 -6
- package/src/input/keybindings.ts +22 -11
- package/src/input/onboarding/onboarding-wizard-apply.ts +13 -0
- package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
- package/src/input/onboarding/onboarding-wizard-operator-steps.ts +147 -57
- package/src/input/onboarding/onboarding-wizard-steps.ts +46 -29
- package/src/input/onboarding/onboarding-wizard-types.ts +3 -1
- package/src/input/onboarding/onboarding-wizard.ts +68 -0
- package/src/input/profile-picker-modal.ts +31 -12
- package/src/input/session-picker-modal.ts +21 -4
- package/src/input/settings-modal-behavior.ts +0 -3
- package/src/input/settings-modal-subscriptions.ts +3 -3
- package/src/input/settings-modal-types.ts +2 -13
- package/src/input/settings-modal.ts +6 -52
- package/src/input/submission-intent.ts +0 -1
- package/src/input/submission-router.ts +3 -3
- package/src/main.ts +18 -8
- package/src/panels/approval-panel.ts +8 -8
- package/src/panels/automation-control-panel.ts +2 -2
- package/src/panels/base-panel.ts +1 -1
- package/src/panels/builtin/agent.ts +1 -1
- package/src/panels/builtin/operations.ts +1 -10
- package/src/panels/builtin/session.ts +9 -9
- package/src/panels/builtin/shared.ts +2 -2
- package/src/panels/cost-tracker-panel.ts +1 -1
- package/src/panels/docs-panel.ts +5 -3
- package/src/panels/index.ts +0 -1
- package/src/panels/knowledge-panel.ts +6 -5
- package/src/panels/memory-panel.ts +7 -6
- package/src/panels/panel-list-panel.ts +36 -80
- package/src/panels/project-planning-panel.ts +18 -11
- package/src/panels/provider-account-snapshot.ts +51 -25
- package/src/panels/provider-accounts-panel.ts +33 -18
- package/src/panels/provider-health-domains.ts +45 -4
- package/src/panels/provider-health-panel.ts +5 -4
- package/src/panels/qr-panel.ts +1 -1
- package/src/panels/schedule-panel.ts +9 -17
- package/src/panels/security-panel.ts +8 -8
- package/src/panels/session-browser-panel.ts +10 -10
- package/src/panels/subscription-panel.ts +3 -3
- package/src/panels/system-messages-panel.ts +1 -1
- package/src/panels/tasks-panel.ts +20 -13
- package/src/panels/tool-inspector-panel.ts +19 -12
- package/src/panels/work-plan-panel.ts +5 -5
- package/src/planning/project-planning-coordinator.ts +1 -1
- package/src/provider-auth-route-display.ts +9 -0
- package/src/renderer/agent-workspace-style.ts +34 -0
- package/src/renderer/agent-workspace.ts +228 -52
- package/src/renderer/autocomplete-overlay.ts +25 -6
- package/src/renderer/bookmark-modal.ts +19 -4
- package/src/renderer/buffer.ts +4 -2
- package/src/renderer/context-inspector.ts +50 -13
- package/src/renderer/diff.ts +1 -1
- package/src/renderer/file-picker-overlay.ts +19 -6
- package/src/renderer/help-overlay.ts +106 -33
- package/src/renderer/history-search-overlay.ts +19 -4
- package/src/renderer/live-tail-modal.ts +27 -5
- package/src/renderer/mcp-workspace.ts +164 -50
- package/src/renderer/model-picker-overlay.ts +58 -2
- package/src/renderer/model-workspace.ts +104 -20
- package/src/renderer/process-modal.ts +27 -6
- package/src/renderer/profile-picker-modal.ts +20 -4
- package/src/renderer/search-overlay.ts +25 -5
- package/src/renderer/selection-modal-overlay.ts +46 -14
- package/src/renderer/session-picker-modal.ts +18 -1
- package/src/renderer/settings-modal-helpers.ts +2 -40
- package/src/renderer/settings-modal.ts +83 -50
- package/src/renderer/tool-call.ts +20 -11
- package/src/runtime/agent-runtime-events.ts +6 -6
- package/src/runtime/bootstrap-command-context.ts +7 -1
- package/src/runtime/bootstrap-command-parts.ts +9 -7
- package/src/runtime/bootstrap-core.ts +19 -1
- package/src/runtime/bootstrap-hook-bridge.ts +7 -18
- package/src/runtime/bootstrap-shell.ts +4 -4
- package/src/runtime/bootstrap.ts +31 -22
- package/src/runtime/connected-host-auth.ts +7 -2
- package/src/runtime/diagnostics/panels/index.ts +2 -2
- package/src/runtime/diagnostics/panels/policy.ts +7 -7
- package/src/runtime/index.ts +2 -1
- package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
- package/src/runtime/onboarding/apply.ts +80 -79
- package/src/runtime/onboarding/derivation.ts +5 -8
- package/src/runtime/onboarding/snapshot.ts +0 -15
- package/src/runtime/onboarding/types.ts +8 -19
- package/src/runtime/onboarding/verify.ts +32 -10
- package/src/runtime/operator-token-cleanup.ts +1 -1
- package/src/runtime/services.ts +91 -22
- package/src/runtime/store/selectors/index.ts +3 -3
- package/src/runtime/store/state.ts +1 -4
- package/src/runtime/surface-feature-flags.ts +41 -6
- package/src/runtime/ui-read-models.ts +3 -4
- package/src/runtime/ui-services.ts +6 -6
- package/src/shell/blocking-input.ts +2 -1
- package/src/shell/ui-openers.ts +3 -13
- package/src/tools/agent-analysis-registry-policy.ts +0 -1
- package/src/tools/agent-channel-send-tool.ts +133 -0
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
- package/src/tools/agent-knowledge-tool.ts +170 -0
- package/src/tools/agent-local-registry-tool.ts +269 -69
- package/src/tools/agent-media-generate-tool.ts +133 -0
- package/src/tools/agent-notify-tool.ts +143 -0
- package/src/tools/agent-operator-action-tool.ts +137 -0
- package/src/tools/agent-operator-briefing-tool.ts +217 -0
- package/src/tools/agent-reminder-schedule-tool.ts +237 -0
- package/src/tools/agent-tool-policy-guard.ts +8 -8
- package/src/tools/agent-work-plan-tool.ts +256 -0
- package/src/version.ts +1 -1
- package/src/input/commands/policy-dispatch.ts +0 -339
- package/src/input/commands/policy.ts +0 -13
- package/src/panels/panel-picker.ts +0 -105
- package/src/panels/policy-panel.ts +0 -308
- package/src/renderer/panel-picker-overlay.ts +0 -202
|
@@ -15,6 +15,11 @@ export interface ProcessEntry {
|
|
|
15
15
|
|
|
16
16
|
const MAX_LABEL_LENGTH = 80;
|
|
17
17
|
const MODAL_BORDER_WIDTH = 8;
|
|
18
|
+
const PROCESS_MODAL_TITLE = 'Runtime Activity';
|
|
19
|
+
const PROCESS_MODAL_EMPTY_MESSAGE = 'No running shell processes.';
|
|
20
|
+
const PROCESS_MODAL_EMPTY_HINTS = ['[Esc] Close'];
|
|
21
|
+
const PROCESS_MODAL_ACTIVE_HINTS = ['[Up/Down] Navigate', '[Enter] Output', '[k] Stop process', '[Esc] Close'];
|
|
22
|
+
const PROCESS_MODAL_TYPE_TAG = '[exec]';
|
|
18
23
|
|
|
19
24
|
export interface ProcessModalDeps {
|
|
20
25
|
readonly processManager: Pick<ProcessManager, 'list' | 'getStatus' | 'stop'>;
|
|
@@ -101,6 +106,22 @@ export class ProcessModal {
|
|
|
101
106
|
}
|
|
102
107
|
}
|
|
103
108
|
|
|
109
|
+
export function renderProcessModalPackageText(): string {
|
|
110
|
+
return [
|
|
111
|
+
PROCESS_MODAL_TITLE,
|
|
112
|
+
PROCESS_MODAL_EMPTY_MESSAGE,
|
|
113
|
+
PROCESS_MODAL_TYPE_TAG,
|
|
114
|
+
'*',
|
|
115
|
+
'!',
|
|
116
|
+
'-',
|
|
117
|
+
'running',
|
|
118
|
+
'failed',
|
|
119
|
+
'<duration>',
|
|
120
|
+
...PROCESS_MODAL_EMPTY_HINTS,
|
|
121
|
+
...PROCESS_MODAL_ACTIVE_HINTS,
|
|
122
|
+
].join('\n');
|
|
123
|
+
}
|
|
124
|
+
|
|
104
125
|
export function renderProcessModal(modal: ProcessModal, width: number, viewportHeight = 24): Line[] {
|
|
105
126
|
modal.refresh();
|
|
106
127
|
|
|
@@ -118,14 +139,14 @@ export function renderProcessModal(modal: ProcessModal, width: number, viewportH
|
|
|
118
139
|
|
|
119
140
|
if (modal.entries.length === 0) {
|
|
120
141
|
return ModalFactory.createModal({
|
|
121
|
-
title:
|
|
142
|
+
title: PROCESS_MODAL_TITLE,
|
|
122
143
|
width: boxW,
|
|
123
144
|
margin: boxMargin,
|
|
124
145
|
targetContentRows,
|
|
125
146
|
sections: [
|
|
126
|
-
{ type: 'text', content:
|
|
147
|
+
{ type: 'text', content: PROCESS_MODAL_EMPTY_MESSAGE },
|
|
127
148
|
],
|
|
128
|
-
hints:
|
|
149
|
+
hints: PROCESS_MODAL_EMPTY_HINTS,
|
|
129
150
|
}, width);
|
|
130
151
|
}
|
|
131
152
|
|
|
@@ -138,7 +159,7 @@ export function renderProcessModal(modal: ProcessModal, width: number, viewportH
|
|
|
138
159
|
const statusIcon = entry.status === 'running' ? '*' : entry.status === 'failed' ? '!' : '-';
|
|
139
160
|
const dur = formatDuration(entry.elapsedMs);
|
|
140
161
|
const suffix = ` ${entry.status} ${dur}`;
|
|
141
|
-
const typeTag =
|
|
162
|
+
const typeTag = PROCESS_MODAL_TYPE_TAG;
|
|
142
163
|
const maxDescW = Math.max(0, maxLabelW - typeTag.length - suffix.length - 4);
|
|
143
164
|
const desc = entry.label.length > maxDescW ? `${entry.label.slice(0, Math.max(0, maxDescW - 3))}...` : entry.label;
|
|
144
165
|
return {
|
|
@@ -150,7 +171,7 @@ export function renderProcessModal(modal: ProcessModal, width: number, viewportH
|
|
|
150
171
|
if (modal.entries.length > maxVisibleRows) sections.push({ type: 'separator' });
|
|
151
172
|
|
|
152
173
|
return ModalFactory.createModal({
|
|
153
|
-
title:
|
|
174
|
+
title: PROCESS_MODAL_TITLE,
|
|
154
175
|
width: boxW,
|
|
155
176
|
margin: boxMargin,
|
|
156
177
|
targetContentRows,
|
|
@@ -158,6 +179,6 @@ export function renderProcessModal(modal: ProcessModal, width: number, viewportH
|
|
|
158
179
|
helpers: modal.entries.length > maxVisibleRows
|
|
159
180
|
? [{ content: `[${window.start + 1}-${window.end} of ${modal.entries.length}]` }]
|
|
160
181
|
: undefined,
|
|
161
|
-
hints:
|
|
182
|
+
hints: PROCESS_MODAL_ACTIVE_HINTS,
|
|
162
183
|
}, width);
|
|
163
184
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* renderProfilePickerModal — renders the
|
|
2
|
+
* renderProfilePickerModal — renders the Agent profile picker modal as Line[]
|
|
3
3
|
* using ModalFactory.
|
|
4
4
|
*
|
|
5
5
|
* Shows a list of saved profiles with:
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import type { Line } from '../types/grid.ts';
|
|
11
11
|
import { ModalFactory } from './modal-factory.ts';
|
|
12
12
|
import type { ProfilePickerModal } from '../input/profile-picker-modal.ts';
|
|
13
|
+
import { renderProfilePickerStatePackageText } from '../input/profile-picker-modal.ts';
|
|
13
14
|
import { formatTimestamp } from './modal-utils.ts';
|
|
14
15
|
import { fitDisplay } from '../utils/terminal-width.ts';
|
|
15
16
|
import { getOverlaySurfaceMetrics, getStableOverlayContentRows } from './overlay-viewport.ts';
|
|
@@ -18,6 +19,23 @@ import { getOverlaySurfaceMetrics, getStableOverlayContentRows } from './overlay
|
|
|
18
19
|
// Renderer
|
|
19
20
|
// ---------------------------------------------------------------------------
|
|
20
21
|
|
|
22
|
+
export function renderProfilePickerPackageText(): string {
|
|
23
|
+
return [
|
|
24
|
+
'Profiles',
|
|
25
|
+
'No saved profiles.',
|
|
26
|
+
'Open Agent Workspace -> Profiles to create and manage isolated Agent profile homes.',
|
|
27
|
+
'Name',
|
|
28
|
+
'Saved',
|
|
29
|
+
'Settings',
|
|
30
|
+
'(display/provider/behavior)',
|
|
31
|
+
'[Up/Down] Navigate',
|
|
32
|
+
'[Enter] Load',
|
|
33
|
+
'Agent profiles: /agent profiles',
|
|
34
|
+
'[Esc] Close',
|
|
35
|
+
renderProfilePickerStatePackageText(),
|
|
36
|
+
].join('\n');
|
|
37
|
+
}
|
|
38
|
+
|
|
21
39
|
/**
|
|
22
40
|
* Render the profile picker modal as Line[] for overlay in the viewport.
|
|
23
41
|
*
|
|
@@ -51,7 +69,7 @@ export function renderProfilePickerModal(
|
|
|
51
69
|
});
|
|
52
70
|
sections.push({
|
|
53
71
|
type: 'text',
|
|
54
|
-
content: '
|
|
72
|
+
content: 'Open Agent Workspace -> Profiles to create and manage isolated Agent profile homes.',
|
|
55
73
|
style: { fg: '240', dim: true },
|
|
56
74
|
});
|
|
57
75
|
} else {
|
|
@@ -79,8 +97,6 @@ export function renderProfilePickerModal(
|
|
|
79
97
|
|
|
80
98
|
const tsStr = fitDisplay(formatTimestamp(prof.timestamp), tsW);
|
|
81
99
|
|
|
82
|
-
// Read the profile file to get a preview of settings
|
|
83
|
-
// (We only have name/timestamp in ProfileInfo, so show a placeholder)
|
|
84
100
|
const preview = fitDisplay('(display/provider/behavior)', previewW);
|
|
85
101
|
|
|
86
102
|
const label = `${nameStr} ${tsStr} ${preview}`;
|
|
@@ -3,6 +3,26 @@ import { fitDisplay, getDisplayWidth, truncateDisplay } from '../utils/terminal-
|
|
|
3
3
|
import type { SearchManager } from '../input/search.ts';
|
|
4
4
|
import { createBottomBarLine, writeBottomBarText } from './bottom-bar.ts';
|
|
5
5
|
|
|
6
|
+
const SEARCH_OVERLAY_LABEL = ' Find: ';
|
|
7
|
+
const SEARCH_OVERLAY_NO_MATCHES = 'No matches';
|
|
8
|
+
const SEARCH_OVERLAY_COUNT_SUFFIX = 'up/down';
|
|
9
|
+
const SEARCH_OVERLAY_LOCKED_HINTS = ' [Up/Down] or [jk] navigate [Bksp] edit [Esc] close';
|
|
10
|
+
const SEARCH_OVERLAY_UNLOCKED_HINTS = ' [Enter/Tab] lock [Esc] close';
|
|
11
|
+
|
|
12
|
+
function searchOverlayMatchCount(current: string | number, total: string | number): string {
|
|
13
|
+
return `${current}/${total} ${SEARCH_OVERLAY_COUNT_SUFFIX}`;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function renderSearchOverlayPackageText(): string {
|
|
17
|
+
return [
|
|
18
|
+
SEARCH_OVERLAY_LABEL.trim(),
|
|
19
|
+
searchOverlayMatchCount('<current>', '<total>'),
|
|
20
|
+
SEARCH_OVERLAY_NO_MATCHES,
|
|
21
|
+
SEARCH_OVERLAY_LOCKED_HINTS.trim(),
|
|
22
|
+
SEARCH_OVERLAY_UNLOCKED_HINTS.trim(),
|
|
23
|
+
].join('\n');
|
|
24
|
+
}
|
|
25
|
+
|
|
6
26
|
/**
|
|
7
27
|
* Render the search bar as a single Line[] overlay at the bottom of the viewport.
|
|
8
28
|
* Format: [ Find: <query> 3/17 up/down [n] next [N] prev [Esc] close ]
|
|
@@ -14,18 +34,18 @@ export function renderSearchOverlay(
|
|
|
14
34
|
): Line[] {
|
|
15
35
|
// Match count text — displayed in dim grey, right of query, left of hints
|
|
16
36
|
const matchCount = manager.matches?.length > 0
|
|
17
|
-
?
|
|
37
|
+
? searchOverlayMatchCount(manager.currentMatch + 1, manager.matches.length)
|
|
18
38
|
: manager.query.length > 0
|
|
19
|
-
?
|
|
39
|
+
? SEARCH_OVERLAY_NO_MATCHES
|
|
20
40
|
: '';
|
|
21
41
|
|
|
22
42
|
const locked = manager.locked;
|
|
23
43
|
const cursor = locked ? '' : '█';
|
|
24
44
|
const queryDisplay = manager.query + cursor;
|
|
25
45
|
const hints = locked
|
|
26
|
-
?
|
|
27
|
-
:
|
|
28
|
-
const label =
|
|
46
|
+
? SEARCH_OVERLAY_LOCKED_HINTS
|
|
47
|
+
: SEARCH_OVERLAY_UNLOCKED_HINTS;
|
|
48
|
+
const label = SEARCH_OVERLAY_LABEL;
|
|
29
49
|
const matchStr = matchCount ? ` ${matchCount}` : '';
|
|
30
50
|
|
|
31
51
|
// Build left portion: label + query (no match count — that gets separate styling)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type Line } from '../types/grid.ts';
|
|
2
2
|
import { fitDisplay, getDisplayWidth, truncateDisplay } from '../utils/terminal-width.ts';
|
|
3
|
-
import type { SelectionModal } from '../input/selection-modal.ts';
|
|
3
|
+
import type { SelectionAction, SelectionModal } from '../input/selection-modal.ts';
|
|
4
4
|
import {
|
|
5
5
|
createOverlayBoxLayout,
|
|
6
6
|
createOverlayContentLine,
|
|
@@ -18,6 +18,14 @@ const BODY_FG = DEFAULT_OVERLAY_PALETTE.bodyFg;
|
|
|
18
18
|
const MUTED_FG = DEFAULT_OVERLAY_PALETTE.mutedFg;
|
|
19
19
|
const CATEGORY_FG = '#4488cc';
|
|
20
20
|
const SELECTED_BG = DEFAULT_OVERLAY_PALETTE.selectedBg;
|
|
21
|
+
const SELECTION_MODAL_SEARCH_LABEL = ' Search';
|
|
22
|
+
const SELECTION_MODAL_RESULTS_LABEL = ' Results';
|
|
23
|
+
const SELECTION_MODAL_NO_MATCHING_ITEMS = 'No matching items';
|
|
24
|
+
const SELECTION_MODAL_NO_ITEMS = 'No items';
|
|
25
|
+
const SELECTION_MODAL_NAVIGATION_HINT = '[Up/Down] Navigate';
|
|
26
|
+
const SELECTION_MODAL_CLOSE_HINT = '[Esc] Close';
|
|
27
|
+
const SELECTION_MODAL_SEARCH_HINT = '[/] Search';
|
|
28
|
+
const SELECTION_MODAL_SPACE_TOGGLE_HINT = '[Space] Toggle';
|
|
21
29
|
|
|
22
30
|
interface CellStyle {
|
|
23
31
|
fg: string;
|
|
@@ -30,6 +38,36 @@ function putText(line: Line, startX: number, maxWidth: number, text: string, sty
|
|
|
30
38
|
putOverlayText(line, startX, maxWidth, text, style);
|
|
31
39
|
}
|
|
32
40
|
|
|
41
|
+
function primaryVerbForAction(primaryAction: SelectionAction | undefined): string {
|
|
42
|
+
return primaryAction === 'toggle'
|
|
43
|
+
? '[Enter] Toggle'
|
|
44
|
+
: primaryAction === 'edit'
|
|
45
|
+
? '[Enter] Edit'
|
|
46
|
+
: primaryAction === 'delete'
|
|
47
|
+
? '[Enter] Delete'
|
|
48
|
+
: '[Enter] Select';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function renderSelectionModalPackageText(): string {
|
|
52
|
+
return [
|
|
53
|
+
SELECTION_MODAL_SEARCH_LABEL.trim(),
|
|
54
|
+
SELECTION_MODAL_RESULTS_LABEL.trim(),
|
|
55
|
+
SELECTION_MODAL_NO_MATCHING_ITEMS,
|
|
56
|
+
SELECTION_MODAL_NO_ITEMS,
|
|
57
|
+
'(<above> above, <below> below)',
|
|
58
|
+
'(<below> below)',
|
|
59
|
+
'(<above> above)',
|
|
60
|
+
SELECTION_MODAL_NAVIGATION_HINT,
|
|
61
|
+
primaryVerbForAction(undefined),
|
|
62
|
+
primaryVerbForAction('toggle'),
|
|
63
|
+
primaryVerbForAction('edit'),
|
|
64
|
+
primaryVerbForAction('delete'),
|
|
65
|
+
SELECTION_MODAL_CLOSE_HINT,
|
|
66
|
+
SELECTION_MODAL_SEARCH_HINT,
|
|
67
|
+
SELECTION_MODAL_SPACE_TOGGLE_HINT,
|
|
68
|
+
].join('\n');
|
|
69
|
+
}
|
|
70
|
+
|
|
33
71
|
/**
|
|
34
72
|
* Render the selection modal as Line[] for overlay in the viewport.
|
|
35
73
|
*/
|
|
@@ -62,7 +100,7 @@ export function renderSelectionModalOverlay(
|
|
|
62
100
|
|
|
63
101
|
if (modal.allowSearch) {
|
|
64
102
|
const labelLine = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg);
|
|
65
|
-
putText(labelLine, layout.margin + 2, layout.innerWidth, fitDisplay(
|
|
103
|
+
putText(labelLine, layout.margin + 2, layout.innerWidth, fitDisplay(SELECTION_MODAL_SEARCH_LABEL, layout.innerWidth), {
|
|
66
104
|
fg: CATEGORY_FG,
|
|
67
105
|
dim: true,
|
|
68
106
|
});
|
|
@@ -86,7 +124,7 @@ export function renderSelectionModalOverlay(
|
|
|
86
124
|
}
|
|
87
125
|
|
|
88
126
|
const listTitle = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg);
|
|
89
|
-
putText(listTitle, layout.margin + 2, layout.innerWidth, fitDisplay(
|
|
127
|
+
putText(listTitle, layout.margin + 2, layout.innerWidth, fitDisplay(SELECTION_MODAL_RESULTS_LABEL, layout.innerWidth), {
|
|
90
128
|
fg: CATEGORY_FG,
|
|
91
129
|
dim: true,
|
|
92
130
|
});
|
|
@@ -95,7 +133,7 @@ export function renderSelectionModalOverlay(
|
|
|
95
133
|
const items = modal.filteredItems;
|
|
96
134
|
if (items.length === 0) {
|
|
97
135
|
const line = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.bodyBg);
|
|
98
|
-
const message = modal.query ?
|
|
136
|
+
const message = modal.query ? SELECTION_MODAL_NO_MATCHING_ITEMS : SELECTION_MODAL_NO_ITEMS;
|
|
99
137
|
putText(line, layout.margin + 2, layout.innerWidth, fitDisplay(message, layout.innerWidth), { fg: MUTED_FG, dim: true });
|
|
100
138
|
lines.push(line);
|
|
101
139
|
} else {
|
|
@@ -189,16 +227,10 @@ export function renderSelectionModalOverlay(
|
|
|
189
227
|
|
|
190
228
|
const footerLine = createOverlayContentLine(width, layout, BORDER_FG, DEFAULT_OVERLAY_PALETTE.sectionBg);
|
|
191
229
|
const selectedItem = modal.getSelected();
|
|
192
|
-
const primaryVerb = selectedItem?.primaryAction
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
: selectedItem?.primaryAction === 'delete'
|
|
197
|
-
? '[Enter] Delete'
|
|
198
|
-
: '[Enter] Select';
|
|
199
|
-
let hints = `[Up/Down] Navigate ${primaryVerb} [Esc] Close`;
|
|
200
|
-
if (modal.allowSearch) hints += ' [/] Search';
|
|
201
|
-
if (selectedItem?.primaryAction === 'toggle' && !selectedItem.actions) hints += ' [Space] Toggle';
|
|
230
|
+
const primaryVerb = primaryVerbForAction(selectedItem?.primaryAction);
|
|
231
|
+
let hints = `${SELECTION_MODAL_NAVIGATION_HINT} ${primaryVerb} ${SELECTION_MODAL_CLOSE_HINT}`;
|
|
232
|
+
if (modal.allowSearch) hints += ` ${SELECTION_MODAL_SEARCH_HINT}`;
|
|
233
|
+
if (selectedItem?.primaryAction === 'toggle' && !selectedItem.actions) hints += ` ${SELECTION_MODAL_SPACE_TOGGLE_HINT}`;
|
|
202
234
|
if (selectedItem?.actions) hints += ` ${selectedItem.actions}`;
|
|
203
235
|
putText(
|
|
204
236
|
footerLine,
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import type { Line } from '../types/grid.ts';
|
|
11
11
|
import { ModalFactory } from './modal-factory.ts';
|
|
12
12
|
import type { SessionPickerModal } from '../input/session-picker-modal.ts';
|
|
13
|
+
import { renderSessionPickerStatePackageText } from '../input/session-picker-modal.ts';
|
|
13
14
|
import { formatTimestamp } from './modal-utils.ts';
|
|
14
15
|
import { fitDisplay } from '../utils/terminal-width.ts';
|
|
15
16
|
import { getOverlaySurfaceMetrics, getStableOverlayContentRows } from './overlay-viewport.ts';
|
|
@@ -18,6 +19,22 @@ import { getOverlaySurfaceMetrics, getStableOverlayContentRows } from './overlay
|
|
|
18
19
|
// Renderer
|
|
19
20
|
// ---------------------------------------------------------------------------
|
|
20
21
|
|
|
22
|
+
export function renderSessionPickerPackageText(): string {
|
|
23
|
+
return [
|
|
24
|
+
'Sessions',
|
|
25
|
+
'No saved sessions.',
|
|
26
|
+
'Open Agent Workspace -> Conversation -> Save current session.',
|
|
27
|
+
'Name',
|
|
28
|
+
'Saved',
|
|
29
|
+
'Msgs',
|
|
30
|
+
'[\u2191\u2193] Navigate',
|
|
31
|
+
'[Enter] Load',
|
|
32
|
+
'Delete: /session delete <id> --yes',
|
|
33
|
+
'[Esc] Close',
|
|
34
|
+
renderSessionPickerStatePackageText(),
|
|
35
|
+
].join('\n');
|
|
36
|
+
}
|
|
37
|
+
|
|
21
38
|
/**
|
|
22
39
|
* Render the session picker modal as Line[] for overlay in the viewport.
|
|
23
40
|
*
|
|
@@ -51,7 +68,7 @@ export function renderSessionPickerModal(
|
|
|
51
68
|
});
|
|
52
69
|
sections.push({
|
|
53
70
|
type: 'text',
|
|
54
|
-
content: '
|
|
71
|
+
content: 'Open Agent Workspace -> Conversation -> Save current session.',
|
|
55
72
|
style: { fg: '240', dim: true },
|
|
56
73
|
});
|
|
57
74
|
} else {
|
|
@@ -82,33 +82,21 @@ export const CATEGORY_LABELS: Record<(typeof SETTINGS_CATEGORIES)[number], strin
|
|
|
82
82
|
behavior: 'Behavior',
|
|
83
83
|
storage: 'Storage',
|
|
84
84
|
permissions: 'Permissions',
|
|
85
|
-
orchestration: 'Orchestration',
|
|
86
|
-
wrfc: 'Build Delegation',
|
|
87
85
|
helper: 'Helper',
|
|
88
86
|
tts: 'TTS',
|
|
89
|
-
service: 'Connected Host',
|
|
90
|
-
controlPlane: 'Connected API',
|
|
91
|
-
httpListener: 'Inbound Delivery',
|
|
92
|
-
web: 'Browser Companion',
|
|
93
|
-
batch: 'Batch',
|
|
94
87
|
automation: 'Automation',
|
|
95
|
-
watchers: 'Watchers',
|
|
96
|
-
runtime: 'Runtime',
|
|
97
88
|
telemetry: 'Telemetry',
|
|
98
89
|
cache: 'Cache',
|
|
99
90
|
mcp: 'MCP',
|
|
100
91
|
surfaces: 'Channels',
|
|
101
|
-
release: '
|
|
102
|
-
danger: 'Danger',
|
|
92
|
+
release: 'Update Channel',
|
|
103
93
|
tools: 'Tools',
|
|
104
|
-
flags: 'Feature
|
|
105
|
-
network: 'Network',
|
|
94
|
+
flags: 'Feature Controls',
|
|
106
95
|
};
|
|
107
96
|
|
|
108
97
|
export const SETTING_LABELS: Partial<Record<string, string>> = {
|
|
109
98
|
'ui.systemMessages': 'System Message Target',
|
|
110
99
|
'ui.operationalMessages': 'Operational Message Target',
|
|
111
|
-
'ui.wrfcMessages': 'Delegated Build Message Target',
|
|
112
100
|
'ui.voiceEnabled': 'Voice Interaction',
|
|
113
101
|
'behavior.autoCompactThreshold': 'Auto-Compact %',
|
|
114
102
|
'behavior.staleContextWarnings': 'Context Warnings',
|
|
@@ -123,32 +111,6 @@ export const SETTING_LABELS: Partial<Record<string, string>> = {
|
|
|
123
111
|
'helper.enabled': 'Helper Enabled',
|
|
124
112
|
'helper.globalProvider': 'Helper Provider',
|
|
125
113
|
'helper.globalModel': 'Helper Model',
|
|
126
|
-
// Runtime API
|
|
127
|
-
'controlPlane.enabled': 'Connected API Enabled',
|
|
128
|
-
'controlPlane.hostMode': 'Connected API Host Mode',
|
|
129
|
-
'controlPlane.host': 'Connected API Host',
|
|
130
|
-
'controlPlane.port': 'Connected API Port',
|
|
131
|
-
'controlPlane.baseUrl': 'Connected API Base URL',
|
|
132
|
-
'controlPlane.streamMode': 'Connected API Stream Mode',
|
|
133
|
-
'controlPlane.allowRemote': 'Connected API Allow Remote',
|
|
134
|
-
'controlPlane.trustProxy': 'Connected API Trust Proxy',
|
|
135
|
-
'controlPlane.tls.mode': 'Connected API TLS Mode',
|
|
136
|
-
'controlPlane.tls.certFile': 'Connected API TLS Cert',
|
|
137
|
-
'controlPlane.tls.keyFile': 'Connected API TLS Key',
|
|
138
|
-
// Inbound delivery endpoint
|
|
139
|
-
'httpListener.hostMode': 'Inbound Delivery Host Mode',
|
|
140
|
-
'httpListener.host': 'Inbound Delivery Host',
|
|
141
|
-
'httpListener.port': 'Inbound Delivery Port',
|
|
142
|
-
'httpListener.trustProxy': 'Inbound Delivery Trust Proxy',
|
|
143
|
-
'httpListener.tls.mode': 'Inbound Delivery TLS Mode',
|
|
144
|
-
'httpListener.tls.certFile': 'Inbound Delivery TLS Cert',
|
|
145
|
-
// Browser companion
|
|
146
|
-
'web.enabled': 'Web Enabled',
|
|
147
|
-
'web.hostMode': 'Web Host Mode',
|
|
148
|
-
'web.host': 'Web Host',
|
|
149
|
-
'web.port': 'Web Port',
|
|
150
|
-
'web.publicBaseUrl': 'Web Public Base URL',
|
|
151
|
-
'web.staticAssetsDir': 'Web Static Assets Dir',
|
|
152
114
|
'surfaces.ntfy.enabled': 'ntfy Enabled',
|
|
153
115
|
'surfaces.ntfy.baseUrl': 'ntfy Base URL',
|
|
154
116
|
'surfaces.ntfy.topic': 'ntfy Default Delivery Topic',
|
|
@@ -11,6 +11,7 @@ import { isExternalHostOwnedSettingKey, SETTINGS_CATEGORIES, SETTINGS_CATEGORY_G
|
|
|
11
11
|
import { getDisplayWidth, wrapText } from '../utils/terminal-width.ts';
|
|
12
12
|
import { CATEGORY_LABELS, describeUiRouting, formatValue, getSettingLabel, inferSubscriptionRouteReason, valueColor } from './settings-modal-helpers.ts';
|
|
13
13
|
import { isSecretConfigKey } from '../config/secret-config.ts';
|
|
14
|
+
import { formatProviderAuthRouteId } from '../provider-auth-route-display.ts';
|
|
14
15
|
import { GLYPHS } from './ui-primitives.ts';
|
|
15
16
|
import {
|
|
16
17
|
clamp,
|
|
@@ -30,27 +31,16 @@ const CATEGORY_INFO: Record<SettingsCategory, string> = {
|
|
|
30
31
|
behavior: 'Day-to-day shell behavior: approval posture, compaction, history, guidance, notifications, stale-context warnings, return context, and Human-in-the-Loop mode.',
|
|
31
32
|
storage: 'Local storage posture, including secret storage policy and maximum artifact size for Agent Knowledge, artifacts, and document ingestion.',
|
|
32
33
|
permissions: 'Permission mode and tool-class policy. These settings decide whether the shell prompts before read/write/exec/network/agent actions.',
|
|
33
|
-
orchestration: 'Hidden compatibility settings. Normal Agent operation stays serial and does not expose local spawn fanout.',
|
|
34
|
-
wrfc: 'Build-review routing is external to normal Agent operation. Review these compatibility values only for explicit delegated build work.',
|
|
35
34
|
helper: 'Helper model defaults used by helper subsystems when they do not use the main chat route.',
|
|
36
35
|
tts: 'Text-to-speech provider, voice, and optional spoken-turn LLM overrides.',
|
|
37
|
-
service: 'Connected-host status posture. Agent inspects these values only and does not install, start, stop, restart, or autostart anything.',
|
|
38
|
-
controlPlane: 'Connected API settings. Agent uses these values for access and does not mutate bind posture.',
|
|
39
|
-
httpListener: 'Inbound delivery endpoint settings owned by the connected GoodVibes host. Agent inspects readiness and does not expose endpoints.',
|
|
40
|
-
web: 'External browser companion settings. Agent does not own browser hosting or network bind lifecycle.',
|
|
41
|
-
batch: 'Queued execution settings reported from the connected GoodVibes host. Agent does not own remote queue provisioning.',
|
|
42
36
|
automation: 'Scheduled and automated run settings, concurrency, timeout, catch-up, cooldown, and retention behavior.',
|
|
43
|
-
watchers: 'File/process watcher heartbeat, polling, and recovery-window behavior.',
|
|
44
|
-
runtime: 'Connected-host guardrails such as companion chat limits and event-stream caps.',
|
|
45
37
|
telemetry: 'Telemetry payload policy.',
|
|
46
38
|
cache: 'Provider and model cache behavior, TTL, and hit-rate monitoring.',
|
|
47
39
|
mcp: 'MCP server trust and scope review. Trust changes can expose local files, tools, databases, browsers, or remote automation depending on the server.',
|
|
48
40
|
surfaces: 'Messaging and notification channel accounts such as Slack, Discord, ntfy, Telegram, chat bridges, and delivery providers.',
|
|
49
|
-
release: '
|
|
50
|
-
danger: 'High-impact host switches. Agent renders host-owned switches read-only; change them outside Agent.',
|
|
41
|
+
release: 'Update-channel preference.',
|
|
51
42
|
tools: 'Tool LLM and helper model routing. Empty provider/model values inherit the active chat route unless a specific helper/tool route is set.',
|
|
52
|
-
flags: 'Feature
|
|
53
|
-
network: 'Read-only view of connected GoodVibes API, inbound delivery, and browser companion bind posture plus editable Agent network settings.',
|
|
43
|
+
flags: 'Feature controls for optional behavior that can be enabled or disabled separately from normal configuration.',
|
|
54
44
|
};
|
|
55
45
|
|
|
56
46
|
const ENUM_VALUE_DESCRIPTIONS: Record<string, Record<string, string>> = {
|
|
@@ -74,26 +64,6 @@ const ENUM_VALUE_DESCRIPTIONS: Record<string, Record<string, string>> = {
|
|
|
74
64
|
require_secure: 'Require secure secret storage and reject plaintext fallback.',
|
|
75
65
|
plaintext_allowed: 'Allow plaintext fallback when secure storage is unavailable.',
|
|
76
66
|
},
|
|
77
|
-
'batch.mode': {
|
|
78
|
-
off: 'Keep runtime work on the immediate local path.',
|
|
79
|
-
explicit: 'Use batch only when callers explicitly request batch execution.',
|
|
80
|
-
'eligible-by-default': 'Allow eligible runtime work to use the batch path unless callers opt out.',
|
|
81
|
-
},
|
|
82
|
-
'controlPlane.hostMode': {
|
|
83
|
-
localhost: 'Bind only to this computer.',
|
|
84
|
-
network: 'Bind for LAN access using the default network host.',
|
|
85
|
-
custom: 'Use the explicit host value in the related host setting.',
|
|
86
|
-
},
|
|
87
|
-
'httpListener.hostMode': {
|
|
88
|
-
localhost: 'Bind only to this computer.',
|
|
89
|
-
network: 'Bind for LAN event delivery using the default network host.',
|
|
90
|
-
custom: 'Use the explicit host value in the related host setting.',
|
|
91
|
-
},
|
|
92
|
-
'web.hostMode': {
|
|
93
|
-
localhost: 'Serve the browser UI only on this computer.',
|
|
94
|
-
network: 'Serve the browser UI on the LAN.',
|
|
95
|
-
custom: 'Use the explicit host value in the related host setting.',
|
|
96
|
-
},
|
|
97
67
|
'ui.systemMessages': {
|
|
98
68
|
panel: 'Show system messages in panels only.',
|
|
99
69
|
conversation: 'Show system messages inline in the transcript.',
|
|
@@ -104,11 +74,6 @@ const ENUM_VALUE_DESCRIPTIONS: Record<string, Record<string, string>> = {
|
|
|
104
74
|
conversation: 'Show operational messages inline in the transcript.',
|
|
105
75
|
both: 'Show operational messages in both panels and the transcript.',
|
|
106
76
|
},
|
|
107
|
-
'ui.wrfcMessages': {
|
|
108
|
-
panel: 'Show explicit delegated build messages in panels only.',
|
|
109
|
-
conversation: 'Show explicit delegated build messages inline in the transcript.',
|
|
110
|
-
both: 'Show explicit delegated build messages in both panels and the transcript.',
|
|
111
|
-
},
|
|
112
77
|
'surfaces.telegram.mode': {
|
|
113
78
|
webhook: 'Receive Telegram updates through externally hosted delivery.',
|
|
114
79
|
polling: 'Poll Telegram for updates from the configured account.',
|
|
@@ -155,7 +120,6 @@ function buildSettingContext(modal: SettingsModal, entry: SettingEntry): string[
|
|
|
155
120
|
if (
|
|
156
121
|
entry.setting.key === 'ui.systemMessages'
|
|
157
122
|
|| entry.setting.key === 'ui.operationalMessages'
|
|
158
|
-
|| entry.setting.key === 'ui.wrfcMessages'
|
|
159
123
|
) {
|
|
160
124
|
lines.push(`Routing meaning: ${describeUiRouting(String(entry.currentValue))}.`);
|
|
161
125
|
}
|
|
@@ -194,8 +158,12 @@ function buildSettingContext(modal: SettingsModal, entry: SettingEntry): string[
|
|
|
194
158
|
return lines;
|
|
195
159
|
}
|
|
196
160
|
|
|
161
|
+
function formatSubscriptionRoute(route: SubscriptionEntry['activeRoute'] | SubscriptionEntry['preferredRoute']): string {
|
|
162
|
+
return route ? formatProviderAuthRouteId(route) : 'n/a';
|
|
163
|
+
}
|
|
164
|
+
|
|
197
165
|
function buildFlagContext(entry: FlagEntry | null): string[] {
|
|
198
|
-
if (!entry) return ['Feature
|
|
166
|
+
if (!entry) return ['Feature Controls', 'No feature control is selected.'];
|
|
199
167
|
return [
|
|
200
168
|
entry.flag.name,
|
|
201
169
|
`ID: ${entry.flag.id}`,
|
|
@@ -209,7 +177,7 @@ function buildFlagContext(entry: FlagEntry | null): string[] {
|
|
|
209
177
|
'',
|
|
210
178
|
entry.flag.runtimeToggleable
|
|
211
179
|
? 'Impact: changes apply immediately and are also persisted as an override when they differ from the default.'
|
|
212
|
-
: 'Impact: this
|
|
180
|
+
: 'Impact: this override is saved for the next Agent launch or owning-host reload, depending on who owns the flag.',
|
|
213
181
|
];
|
|
214
182
|
}
|
|
215
183
|
|
|
@@ -248,14 +216,14 @@ function buildSubscriptionContext(modal: SettingsModal, entry: SubscriptionEntry
|
|
|
248
216
|
? modal.subscriptionLogoutConfirmationTarget === entry.provider
|
|
249
217
|
? `Press Enter again to sign out ${entry.provider}. Move selection or close config to cancel.`
|
|
250
218
|
: 'Press Enter to review sign-out for this provider session.'
|
|
251
|
-
: `Open
|
|
219
|
+
: `Open Agent Workspace -> Setup and choose Start subscription login for ${entry.provider}.`;
|
|
252
220
|
return [
|
|
253
221
|
entry.provider,
|
|
254
222
|
`State: ${entry.state}`,
|
|
255
223
|
...(routeReason ? [routeReason] : []),
|
|
256
224
|
logout,
|
|
257
|
-
`Active route: ${entry.activeRoute
|
|
258
|
-
`Preferred route: ${entry.preferredRoute
|
|
225
|
+
`Active route: ${formatSubscriptionRoute(entry.activeRoute)}`,
|
|
226
|
+
`Preferred route: ${formatSubscriptionRoute(entry.preferredRoute)}`,
|
|
259
227
|
`OAuth configured: ${entry.oauthConfigured ? 'yes' : 'no'}`,
|
|
260
228
|
`Freshness: ${entry.authFreshness ?? 'n/a'}`,
|
|
261
229
|
`Expires: ${expires}`,
|
|
@@ -390,10 +358,10 @@ function renderFlagRows(modal: SettingsModal, width: number, height: number): st
|
|
|
390
358
|
const nameWidth = clamp(Math.floor(width * 0.40), 24, 58);
|
|
391
359
|
const stateWidth = 10;
|
|
392
360
|
const tierWidth = 6;
|
|
393
|
-
const runtimeWidth =
|
|
361
|
+
const runtimeWidth = 10;
|
|
394
362
|
const defaultWidth = 9;
|
|
395
363
|
const idWidth = Math.max(12, width - nameWidth - stateWidth - tierWidth - runtimeWidth - defaultWidth - 14);
|
|
396
|
-
rows.push(` ${padDisplay('Feature Flag', nameWidth)} ${padDisplay('State', stateWidth)} ${padDisplay('Tier', tierWidth)} ${padDisplay('
|
|
364
|
+
rows.push(` ${padDisplay('Feature Flag', nameWidth)} ${padDisplay('State', stateWidth)} ${padDisplay('Tier', tierWidth)} ${padDisplay('Applies', runtimeWidth)} ${padDisplay('Default', defaultWidth)} ${padDisplay('ID', idWidth)}`);
|
|
397
365
|
const visibleCount = Math.max(1, height - 2);
|
|
398
366
|
const window = stableWindow(items.length, selectedIndex, visibleCount);
|
|
399
367
|
if (window.start > 0) rows.push(`${GLYPHS.navigation.moreAbove} ${window.start} more flag(s) above`);
|
|
@@ -401,7 +369,7 @@ function renderFlagRows(modal: SettingsModal, width: number, height: number): st
|
|
|
401
369
|
const entry = items[index]!;
|
|
402
370
|
const selected = index === selectedIndex;
|
|
403
371
|
const marker = selected ? (modal.focusPane === 'settings' ? GLYPHS.navigation.selected : '•') : ' ';
|
|
404
|
-
rows.push(`${marker} ${padDisplay(entry.flag.name, nameWidth)} ${padDisplay(entry.state, stateWidth)} ${padDisplay(String(entry.flag.tier), tierWidth)} ${padDisplay(entry.flag.runtimeToggleable ? '
|
|
372
|
+
rows.push(`${marker} ${padDisplay(entry.flag.name, nameWidth)} ${padDisplay(entry.state, stateWidth)} ${padDisplay(String(entry.flag.tier), tierWidth)} ${padDisplay(entry.flag.runtimeToggleable ? 'now' : 'next run', runtimeWidth)} ${padDisplay(entry.flag.defaultState, defaultWidth)} ${padDisplay(entry.flag.id, idWidth)}`);
|
|
405
373
|
}
|
|
406
374
|
if (window.end < items.length) rows.push(`${GLYPHS.navigation.moreBelow} ${items.length - window.end} more flag(s) below`);
|
|
407
375
|
return rows.slice(0, height);
|
|
@@ -450,7 +418,7 @@ function renderSubscriptionRows(modal: SettingsModal, width: number, height: num
|
|
|
450
418
|
const entry = items[index]!;
|
|
451
419
|
const selected = index === selectedIndex;
|
|
452
420
|
const marker = selected ? (modal.focusPane === 'settings' ? GLYPHS.navigation.selected : '•') : ' ';
|
|
453
|
-
rows.push(`${marker} ${padDisplay(entry.provider, providerWidth)} ${padDisplay(entry.state, stateWidth)} ${padDisplay(entry.activeRoute
|
|
421
|
+
rows.push(`${marker} ${padDisplay(entry.provider, providerWidth)} ${padDisplay(entry.state, stateWidth)} ${padDisplay(formatSubscriptionRoute(entry.activeRoute), routeWidth)} ${padDisplay(entry.authFreshness ?? 'n/a', freshnessWidth)} ${padDisplay(entry.oauthConfigured ? 'yes' : 'no', oauthWidth)} ${padDisplay(inferSubscriptionRouteReason(entry) ?? '', noteWidth)}`);
|
|
454
422
|
}
|
|
455
423
|
if (window.end < items.length) rows.push(`${GLYPHS.navigation.moreBelow} ${items.length - window.end} more subscription provider(s) below`);
|
|
456
424
|
return rows.slice(0, height);
|
|
@@ -464,7 +432,6 @@ function renderControlRows(modal: SettingsModal, width: number, height: number):
|
|
|
464
432
|
}
|
|
465
433
|
|
|
466
434
|
function rowColorForSetting(modal: SettingsModal, rowText: string): string {
|
|
467
|
-
if (modal.currentCategory === 'danger') return PALETTE.bad;
|
|
468
435
|
if (rowText.startsWith(GLYPHS.navigation.selected)) return PALETTE.text;
|
|
469
436
|
const selected = modal.getSelected();
|
|
470
437
|
if (!selected) return PALETTE.text;
|
|
@@ -484,13 +451,79 @@ function footerText(modal: SettingsModal): string {
|
|
|
484
451
|
return 'Focus settings · Up/Down setting · Left categories · Tab pane · Enter/Space edit/toggle · R reset · Esc close';
|
|
485
452
|
}
|
|
486
453
|
|
|
454
|
+
export function renderSettingsModalPackageText(): string {
|
|
455
|
+
const lines: string[] = [
|
|
456
|
+
'Configuration Workspace / Settings',
|
|
457
|
+
'Categories',
|
|
458
|
+
'Setting',
|
|
459
|
+
'Value',
|
|
460
|
+
'Type',
|
|
461
|
+
'Source',
|
|
462
|
+
'Default',
|
|
463
|
+
'Feature Flag',
|
|
464
|
+
'State',
|
|
465
|
+
'Tier',
|
|
466
|
+
'Applies',
|
|
467
|
+
'Server',
|
|
468
|
+
'Trust',
|
|
469
|
+
'Status',
|
|
470
|
+
'Scope',
|
|
471
|
+
'Provider',
|
|
472
|
+
'Route',
|
|
473
|
+
'Freshness',
|
|
474
|
+
'OAuth',
|
|
475
|
+
'Note',
|
|
476
|
+
'No settings in this category.',
|
|
477
|
+
'No feature flags registered.',
|
|
478
|
+
'No MCP servers registered.',
|
|
479
|
+
'No provider subscriptions available or configured.',
|
|
480
|
+
'No setting is selected in this category.',
|
|
481
|
+
'No feature control is selected.',
|
|
482
|
+
'No MCP server is selected.',
|
|
483
|
+
'No subscription provider is selected.',
|
|
484
|
+
'Trust meanings:',
|
|
485
|
+
'constrained: keep MCP activity inside declared paths/hosts and prompt on risk.',
|
|
486
|
+
'ask-on-risk: allow routine MCP operations but ask before risky behavior.',
|
|
487
|
+
'allow-all: allow unrestricted MCP operations for this server after explicit confirmation.',
|
|
488
|
+
'blocked: prevent this MCP server from being used.',
|
|
489
|
+
'Possible values:',
|
|
490
|
+
'true: enabled or allowed for this setting.',
|
|
491
|
+
'false: disabled or not allowed for this setting.',
|
|
492
|
+
'Secret handling: raw values entered here are stored through the secret manager and the config receives a goodvibes:// secret reference. Empty input clears the config value.',
|
|
493
|
+
'Editing: Enter opens inline edit, then type the value and press Enter to save. Arrow keys only navigate.',
|
|
494
|
+
'Editing: Enter opens inline edit. Delete the current text to save an empty value when that is valid for the setting.',
|
|
495
|
+
'Enter Confirm edit · Esc Cancel edit · text keys edit the selected field',
|
|
496
|
+
'Focus categories · Up/Down choose · Right/Enter settings · Tab pane · Esc close',
|
|
497
|
+
'Focus settings · Up/Down provider · Left categories · Tab pane · Enter review/sign out · Esc close',
|
|
498
|
+
'Focus settings · Up/Down server · Left categories · Tab pane · Enter edit trust · Esc close',
|
|
499
|
+
'Focus feature flags · Up/Down flag · Left categories · Tab pane · Enter/Space toggle · Esc close',
|
|
500
|
+
'Read-only connected-host setting · Change from GoodVibes TUI or the owning host · Esc close',
|
|
501
|
+
'Focus settings · Up/Down setting · Left categories · Tab pane · Enter/Space edit/toggle · R reset · Esc close',
|
|
502
|
+
];
|
|
503
|
+
|
|
504
|
+
for (const group of SETTINGS_CATEGORY_GROUPS) {
|
|
505
|
+
lines.push(group.label);
|
|
506
|
+
for (const category of group.categories) {
|
|
507
|
+
lines.push(category, CATEGORY_LABELS[category], CATEGORY_INFO[category]);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
for (const [key, values] of Object.entries(ENUM_VALUE_DESCRIPTIONS)) {
|
|
512
|
+
lines.push(key);
|
|
513
|
+
for (const [value, description] of Object.entries(values)) {
|
|
514
|
+
lines.push(value, description);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return lines.join('\n');
|
|
519
|
+
}
|
|
520
|
+
|
|
487
521
|
export function renderSettingsModal(
|
|
488
522
|
modal: SettingsModal,
|
|
489
523
|
width: number,
|
|
490
524
|
viewportHeight = 24,
|
|
491
525
|
): Line[] {
|
|
492
526
|
const notices = [
|
|
493
|
-
...(modal.lastSaveTriggeredRestart ? [`Owning host must restart ${modal.lastSaveTriggeredRestart}`] : []),
|
|
494
527
|
...(modal.lastSettingEffectMessage ? [modal.lastSettingEffectMessage] : []),
|
|
495
528
|
];
|
|
496
529
|
const metrics = getFullscreenWorkspaceMetrics({ width, height: viewportHeight });
|