@pellux/goodvibes-tui 1.13.1 → 1.15.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 +104 -0
- package/README.md +6 -6
- package/bin/goodvibes +6 -0
- package/bin/goodvibes-daemon +6 -0
- package/bin/launcher-support.js +34 -1
- package/docs/foundation-artifacts/operator-contract.json +8076 -2047
- package/package.json +15 -11
- package/scripts/postinstall.js +73 -48
- package/src/cli/bundle-command.ts +5 -5
- package/src/cli/completion.ts +1 -1
- package/src/cli/completions/generate.ts +15 -3
- package/src/cli/doctor.ts +385 -0
- package/src/cli/entrypoint.ts +72 -1
- package/src/cli/help.ts +29 -9
- package/src/cli/hooks-command.ts +74 -0
- package/src/cli/hooks-report.ts +167 -0
- package/src/cli/index.ts +3 -0
- package/src/cli/management.ts +13 -1
- package/src/cli/parser.ts +10 -2
- package/src/cli/plugin-bundles-command.ts +228 -0
- package/src/cli/plugin-command.ts +179 -0
- package/src/cli/service-posture.ts +10 -0
- package/src/cli/status.ts +275 -2
- package/src/cli/tui-startup.ts +119 -1
- package/src/cli/types.ts +3 -1
- package/src/config/index.ts +16 -0
- package/src/config/tui-extension-settings.ts +169 -0
- package/src/core/approval-alert.ts +15 -2
- package/src/core/compaction-receipt.ts +127 -0
- package/src/core/model-routing-chip.ts +82 -0
- package/src/core/permission-mode.ts +89 -0
- package/src/core/rewind-receipt.ts +83 -0
- package/src/core/rewind-turn-anchors.ts +160 -0
- package/src/core/scriptable-statusline.ts +141 -0
- package/src/core/session-auto-titler.ts +110 -0
- package/src/core/stream-event-wiring.ts +20 -0
- package/src/core/system-message-router.ts +1 -1
- package/src/core/terminal-notifier.ts +102 -0
- package/src/core/turn-event-wiring.ts +80 -1
- package/src/input/command-reference.ts +96 -0
- package/src/input/command-registry.ts +25 -0
- package/src/input/commands/channel-pairing.ts +245 -0
- package/src/input/commands/channel-runtime.ts +152 -6
- package/src/input/commands/checkin-runtime.ts +89 -0
- package/src/input/commands/checkpoint-runtime.ts +7 -179
- package/src/input/commands/ci-runtime.ts +207 -0
- package/src/input/commands/cost-attribution-format.ts +52 -0
- package/src/input/commands/cost-runtime.ts +44 -4
- package/src/input/commands/editor-runtime.ts +22 -0
- package/src/input/commands/flags-runtime.ts +328 -0
- package/src/input/commands/health-metrics-format.ts +67 -0
- package/src/input/commands/health-runtime.ts +55 -1
- package/src/input/commands/memory.ts +23 -0
- package/src/input/commands/operator-rpc.ts +95 -0
- package/src/input/commands/palette-runtime.ts +22 -0
- package/src/input/commands/permissions-provenance.ts +264 -0
- package/src/input/commands/permissions-runtime.ts +21 -0
- package/src/input/commands/planning-runtime.ts +28 -1
- package/src/input/commands/platform-access-runtime.ts +2 -97
- package/src/input/commands/principals-runtime.ts +212 -0
- package/src/input/commands/product-runtime.ts +43 -3
- package/src/input/commands/recall-files-config.ts +54 -0
- package/src/input/commands/recall-files-git.ts +57 -0
- package/src/input/commands/recall-files.ts +185 -0
- package/src/input/commands/recall-query.ts +8 -3
- package/src/input/commands/recall-review.ts +2 -2
- package/src/input/commands/recall-shared.ts +13 -0
- package/src/input/commands/relay-runtime.ts +86 -0
- package/src/input/commands/review-runtime.ts +160 -0
- package/src/input/commands/rewind-runtime.ts +362 -0
- package/src/input/commands/schedule-nl.ts +147 -0
- package/src/input/commands/schedule-runtime.ts +29 -10
- package/src/input/commands/secret-runtime.ts +55 -0
- package/src/input/commands/session-content.ts +19 -8
- package/src/input/commands/session-workflow.ts +10 -0
- package/src/input/commands/update-runtime.ts +412 -0
- package/src/input/commands/workstream-attempt-dependents.ts +103 -0
- package/src/input/commands/workstream-attempts.ts +244 -0
- package/src/input/commands/workstream-runtime.ts +164 -26
- package/src/input/commands/worktree-runtime.ts +56 -2
- package/src/input/commands.ts +135 -80
- package/src/input/composer-capture.ts +67 -0
- package/src/input/composer-editor.ts +134 -0
- package/src/input/concealed-input.ts +94 -0
- package/src/input/exec-env-scrub-config.ts +84 -0
- package/src/input/feature-unit-layout.ts +142 -0
- package/src/input/feed-context-factory.ts +2 -0
- package/src/input/handler-feed-routes.ts +17 -0
- package/src/input/handler-feed.ts +3 -0
- package/src/input/handler-modal-routes.ts +5 -2
- package/src/input/handler-shortcuts.ts +37 -0
- package/src/input/handler.ts +24 -2
- package/src/input/keybindings.ts +11 -2
- package/src/input/onboarding/onboarding-feature-units.ts +536 -0
- package/src/input/onboarding/onboarding-wizard-apply.ts +40 -6
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +324 -629
- package/src/input/onboarding/onboarding-wizard-steps.ts +5 -5
- package/src/input/onboarding/onboarding-wizard-types.ts +6 -0
- package/src/input/relay-settings-descriptions.ts +35 -0
- package/src/input/sandbox-exec-config.ts +107 -0
- package/src/input/settings-modal-adjustment.ts +4 -7
- package/src/input/settings-modal-data.ts +178 -8
- package/src/input/settings-modal-mutations.ts +41 -13
- package/src/input/settings-modal-types.ts +42 -5
- package/src/input/settings-modal.ts +67 -15
- package/src/input/submission-router.ts +4 -1
- package/src/input/worktree-setup-config.ts +93 -0
- package/src/main.ts +43 -43
- package/src/panels/builtin/development.ts +14 -0
- package/src/panels/diff-review-model.ts +189 -0
- package/src/panels/diff-review-panel.ts +395 -0
- package/src/panels/fleet-panel-format.ts +114 -2
- package/src/panels/fleet-panel.ts +65 -78
- package/src/panels/fleet-read-model.ts +91 -11
- package/src/panels/fleet-stop.ts +19 -4
- package/src/panels/modals/memory-modal.ts +11 -2
- package/src/permissions/hunk-selection.ts +86 -5
- package/src/permissions/prompt.ts +108 -7
- package/src/permissions/sandbox-exec-gate.ts +162 -0
- package/src/renderer/settings-modal-helpers.ts +21 -1
- package/src/renderer/settings-modal.ts +70 -44
- package/src/renderer/shell-surface.ts +23 -1
- package/src/renderer/system-message.ts +4 -0
- package/src/renderer/tool-result-summary.ts +95 -5
- package/src/renderer/ui-factory.ts +22 -0
- package/src/runtime/bootstrap-command-context.ts +15 -1
- package/src/runtime/bootstrap-command-parts.ts +14 -2
- package/src/runtime/bootstrap-core.ts +38 -38
- package/src/runtime/bootstrap-notifier-sync.ts +41 -0
- package/src/runtime/bootstrap-shell.ts +8 -0
- package/src/runtime/bootstrap.ts +21 -23
- package/src/runtime/context-accounting-source.ts +103 -0
- package/src/runtime/conversation-rewind-port.ts +130 -0
- package/src/runtime/fleet-needs-input-push.ts +70 -0
- package/src/runtime/install-self-check-startup.ts +36 -0
- package/src/runtime/install-self-check.ts +149 -0
- package/src/runtime/onboarding/fast-path.ts +93 -0
- package/src/runtime/process-lifecycle.ts +32 -24
- package/src/runtime/relay-reachability-bridge.ts +53 -0
- package/src/runtime/release-artifacts.ts +109 -0
- package/src/runtime/services.ts +33 -33
- package/src/runtime/trust/workspace-registration.ts +184 -0
- package/src/runtime/trust/workspace-trust.ts +202 -0
- package/src/runtime/ui-services.ts +2 -1
- package/src/runtime/update-check.ts +113 -0
- package/src/runtime/workspace-checkpointing.ts +32 -0
- package/src/runtime/workstream-attempts-validation.ts +77 -0
- package/src/runtime/workstream-draft-edits.ts +95 -0
- package/src/runtime/workstream-draft-store.ts +101 -0
- package/src/runtime/workstream-draft-types.ts +42 -0
- package/src/runtime/workstream-services.ts +70 -39
- package/src/shell/blocking-input.ts +29 -0
- package/src/shell/ui-openers.ts +65 -0
- package/src/verification/verification-ledger.ts +56 -2
- package/src/version.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +0 -130
- package/src/runtime/gateway-verbs.ts +0 -47
- package/src/runtime/render-scheduler.ts +0 -90
|
@@ -36,11 +36,23 @@ export interface ShellFooterBuildOptions {
|
|
|
36
36
|
readonly composerStatus?: string;
|
|
37
37
|
readonly composerFlags?: readonly string[];
|
|
38
38
|
readonly composerPendingRisk?: 'none' | 'approval-wait' | 'shell' | 'command' | 'remote';
|
|
39
|
+
/**
|
|
40
|
+
* Current session permission mode (config value: 'prompt' | 'allow-all' |
|
|
41
|
+
* 'custom' | 'plan' | 'accept-edits'). Rendered as a pill in the composer
|
|
42
|
+
* posture block. Cycled by Shift+Tab and toggled by /plan.
|
|
43
|
+
*/
|
|
44
|
+
readonly permissionMode?: string;
|
|
39
45
|
/**
|
|
40
46
|
* Passive context pressure hint from buildContextStatusHint.
|
|
41
47
|
* Rendered as a dim informational line above the prompt when non-null.
|
|
42
48
|
*/
|
|
43
49
|
readonly contextStatusHint?: string | null;
|
|
50
|
+
/**
|
|
51
|
+
* Output of the user's scriptable status line (`statusline.command`).
|
|
52
|
+
* Rendered as a dim informational line above the prompt when non-null,
|
|
53
|
+
* below the context pressure hint.
|
|
54
|
+
*/
|
|
55
|
+
readonly scriptableStatusLine?: string | null;
|
|
44
56
|
/**
|
|
45
57
|
* Compact footer posture for short terminals (~<30 rows). Collapses the
|
|
46
58
|
* footer to its essentials (prompt box + token/cost line + help) and drops
|
|
@@ -72,6 +84,10 @@ const PROCESS_INDICATOR_ROWS = 1;
|
|
|
72
84
|
// border, token-usage line, and the help/exit line.
|
|
73
85
|
const COMPACT_FOOTER_BASE_ROWS = 4;
|
|
74
86
|
|
|
87
|
+
// Dim slate foreground shared by the passive footer status lines (context
|
|
88
|
+
// pressure hint and the scriptable status line).
|
|
89
|
+
const DIM_STATUS_FG = '#64748b';
|
|
90
|
+
|
|
75
91
|
/**
|
|
76
92
|
* Real height of the most recently rendered footer, tagged with the compact
|
|
77
93
|
* posture it was rendered under. estimateShellFooterHeight prefers this so
|
|
@@ -127,6 +143,7 @@ export function buildShellFooter(
|
|
|
127
143
|
options.composerPendingRisk,
|
|
128
144
|
options.compact ?? false,
|
|
129
145
|
options.sessionSpineStatus,
|
|
146
|
+
options.permissionMode,
|
|
130
147
|
);
|
|
131
148
|
// Compact posture drops the process indicator and context hint entirely so
|
|
132
149
|
// the footer fits within ~5 rows on short terminals.
|
|
@@ -140,9 +157,14 @@ export function buildShellFooter(
|
|
|
140
157
|
);
|
|
141
158
|
const inputBoxRows = Math.max(1, options.promptLineCount) + 2;
|
|
142
159
|
lines.splice(inputBoxRows, 0, ...processIndicator);
|
|
160
|
+
// Scriptable status line — dim informational line above the prompt. Unshifted
|
|
161
|
+
// before the context hint so the context hint (if any) sits above it.
|
|
162
|
+
if (options.scriptableStatusLine) {
|
|
163
|
+
lines.unshift(UIFactory.stringToLine(options.scriptableStatusLine, options.width, { fg: DIM_STATUS_FG }));
|
|
164
|
+
}
|
|
143
165
|
// Passive context status hint — rendered as a dim informational line before the prompt.
|
|
144
166
|
if (options.contextStatusHint) {
|
|
145
|
-
const hintLine = UIFactory.stringToLine(options.contextStatusHint, options.width, { fg:
|
|
167
|
+
const hintLine = UIFactory.stringToLine(options.contextStatusHint, options.width, { fg: DIM_STATUS_FG });
|
|
146
168
|
lines.unshift(hintLine);
|
|
147
169
|
}
|
|
148
170
|
}
|
|
@@ -46,6 +46,10 @@ export function classifySystemMessage(content: string): SystemMessageType {
|
|
|
46
46
|
return 'info';
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// [Routing] chip — a mid-session model change is informational (the [Failover]
|
|
50
|
+
// line, not this, carries the alarming transport-error cases).
|
|
51
|
+
if (/^\[Routing\]/.test(content)) return 'info';
|
|
52
|
+
|
|
49
53
|
// [Local] and [Recovery] messages
|
|
50
54
|
if (/^\[Local\]/.test(content)) return 'info';
|
|
51
55
|
if (/^\[Recovery\]/.test(content)) {
|
|
@@ -93,20 +93,65 @@ function summarizeEdit(obj: Record<string, unknown>): string | null {
|
|
|
93
93
|
return `${verb} ${applied} edit${applied === 1 ? '' : 's'}${target}${failText}`;
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
+
/** Credential-bearing env-var names withheld from the spawn (never values). Empty when the field is absent/empty. */
|
|
97
|
+
function withheldEnvNames(obj: Record<string, unknown>): string[] {
|
|
98
|
+
const raw = obj.withheld_env;
|
|
99
|
+
if (!Array.isArray(raw)) return [];
|
|
100
|
+
return raw.filter((n): n is string => typeof n === 'string' && n.length > 0);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Compact "withheld: NAME, NAME, …" suffix, capped so a long scrub list doesn't dominate the collapsed line. */
|
|
104
|
+
function withheldEnvSuffix(names: readonly string[]): string {
|
|
105
|
+
if (names.length === 0) return '';
|
|
106
|
+
const MAX_SHOWN = 3;
|
|
107
|
+
const shown = names.slice(0, MAX_SHOWN).join(', ');
|
|
108
|
+
const more = names.length > MAX_SHOWN ? `, +${names.length - MAX_SHOWN} more` : '';
|
|
109
|
+
return ` · withheld: ${shown}${more}`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Compact per-command exec-sandbox suffix: `sandboxed` fields are present
|
|
114
|
+
* only when the sandbox was active for the run (SDK's attachSandboxMeta stays
|
|
115
|
+
* quiet otherwise), so absence here means "ran unsandboxed" and the suffix is
|
|
116
|
+
* empty — never a fabricated claim either way.
|
|
117
|
+
*
|
|
118
|
+
* sandboxed, network disabled -> " · sandboxed (net off)"
|
|
119
|
+
* sandboxed, network enabled, escalation -> " · sandboxed (net on, +1 escalation)"
|
|
120
|
+
* requested but host couldn't provide it -> " · sandbox unavailable (<reason>)"
|
|
121
|
+
*/
|
|
122
|
+
function sandboxSuffix(obj: Record<string, unknown>): string {
|
|
123
|
+
const sandboxed = obj.sandboxed;
|
|
124
|
+
if (sandboxed === undefined) return '';
|
|
125
|
+
if (sandboxed === false) {
|
|
126
|
+
const reason = typeof obj.sandbox_boundary === 'string' ? obj.sandbox_boundary : undefined;
|
|
127
|
+
return reason ? ` · sandbox unavailable (${reason})` : ' · sandbox unavailable';
|
|
128
|
+
}
|
|
129
|
+
const network = typeof obj.sandbox_network === 'string' ? obj.sandbox_network : undefined;
|
|
130
|
+
const escalations = Array.isArray(obj.sandbox_escalations)
|
|
131
|
+
? obj.sandbox_escalations.filter((e): e is string => typeof e === 'string')
|
|
132
|
+
: [];
|
|
133
|
+
const netText = network ? `net ${network}` : undefined;
|
|
134
|
+
const escText = escalations.length > 0 ? `+${escalations.length} escalation${escalations.length === 1 ? '' : 's'}` : undefined;
|
|
135
|
+
const detail = [netText, escText].filter((s): s is string => s !== undefined).join(', ');
|
|
136
|
+
return detail ? ` · sandboxed (${detail})` : ' · sandboxed';
|
|
137
|
+
}
|
|
138
|
+
|
|
96
139
|
/** A single exec command result. */
|
|
97
140
|
function summarizeExecOne(obj: Record<string, unknown>): string | null {
|
|
98
141
|
const exit = obj.exit_code;
|
|
99
142
|
const dur = asNumber(obj.duration_ms);
|
|
100
143
|
const durText = dur !== undefined ? ` · ${formatDuration(dur)}` : '';
|
|
101
|
-
|
|
102
|
-
|
|
144
|
+
const withheldText = withheldEnvSuffix(withheldEnvNames(obj));
|
|
145
|
+
const sandboxText = sandboxSuffix(obj);
|
|
146
|
+
if (obj.timed_out === true) return `timed out${durText}${withheldText}${sandboxText}`;
|
|
147
|
+
if (obj.cancelled === true) return `cancelled${durText}${withheldText}${sandboxText}`;
|
|
103
148
|
const stdout = typeof obj.stdout === 'string' ? obj.stdout : '';
|
|
104
149
|
const lineCount = stdout.length === 0
|
|
105
150
|
? 0
|
|
106
151
|
: stdout.replace(/\n$/, '').split('\n').length;
|
|
107
152
|
const lineText = lineCount > 0 ? ` · ${lineCount} line${lineCount === 1 ? '' : 's'}` : '';
|
|
108
153
|
const code = typeof exit === 'number' ? String(exit) : '?';
|
|
109
|
-
return `exit ${code}${durText}${lineText}`;
|
|
154
|
+
return `exit ${code}${durText}${lineText}${withheldText}${sandboxText}`;
|
|
110
155
|
}
|
|
111
156
|
|
|
112
157
|
/** exec: single { cmd, exit_code, ... } or multi { commands: [...], total }. */
|
|
@@ -116,9 +161,24 @@ function summarizeExec(obj: Record<string, unknown>): string | null {
|
|
|
116
161
|
const failed = obj.commands.filter(
|
|
117
162
|
(c) => c && typeof c === 'object' && (c as Record<string, unknown>).success === false,
|
|
118
163
|
).length;
|
|
164
|
+
// Union of withheld names across every command in the batch — the scrub
|
|
165
|
+
// runs per-spawn, so different commands can withhold different names.
|
|
166
|
+
const withheldAcrossCommands = new Set<string>();
|
|
167
|
+
for (const c of obj.commands) {
|
|
168
|
+
if (c && typeof c === 'object') {
|
|
169
|
+
for (const name of withheldEnvNames(c as Record<string, unknown>)) withheldAcrossCommands.add(name);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
const withheldText = withheldEnvSuffix([...withheldAcrossCommands]);
|
|
173
|
+
// Count sandboxed commands across the batch — a compact "N sandboxed" beats
|
|
174
|
+
// repeating each command's full boundary detail on the collapsed line.
|
|
175
|
+
const sandboxedCount = obj.commands.filter(
|
|
176
|
+
(c) => c && typeof c === 'object' && (c as Record<string, unknown>).sandboxed === true,
|
|
177
|
+
).length;
|
|
178
|
+
const sandboxText = sandboxedCount > 0 ? ` · ${sandboxedCount} sandboxed` : '';
|
|
119
179
|
return failed > 0
|
|
120
|
-
? `${total} commands · ${failed} failed`
|
|
121
|
-
: `${total} commands · all ok`;
|
|
180
|
+
? `${total} commands · ${failed} failed${withheldText}${sandboxText}`
|
|
181
|
+
: `${total} commands · all ok${withheldText}${sandboxText}`;
|
|
122
182
|
}
|
|
123
183
|
if ('exit_code' in obj || 'timed_out' in obj || 'cancelled' in obj) {
|
|
124
184
|
return summarizeExecOne(obj);
|
|
@@ -126,6 +186,35 @@ function summarizeExec(obj: Record<string, unknown>): string | null {
|
|
|
126
186
|
return null;
|
|
127
187
|
}
|
|
128
188
|
|
|
189
|
+
/**
|
|
190
|
+
* agent status/get/wait: an optional `failure` field (ChildFailureEnvelope,
|
|
191
|
+
* see the SDK's tools/agent/child-failure-envelope.ts) is present once the
|
|
192
|
+
* child agent terminated abnormally (max_turns, circuit_breaker,
|
|
193
|
+
* watchdog_timeout, budget_exhausted, claim_unverified, api_error, killed,
|
|
194
|
+
* interrupted, error). Renders it compactly on the collapsed preview line so
|
|
195
|
+
* a failed child is visible without expanding the full result; absent
|
|
196
|
+
* `failure` (the common, successful case) falls through to the raw preview.
|
|
197
|
+
*/
|
|
198
|
+
function summarizeAgentFailure(obj: Record<string, unknown>): string | null {
|
|
199
|
+
const failure = obj.failure;
|
|
200
|
+
if (!failure || typeof failure !== 'object') return null;
|
|
201
|
+
const f = failure as Record<string, unknown>;
|
|
202
|
+
const agentId = typeof f.agentId === 'string' ? f.agentId : '?';
|
|
203
|
+
const phase = typeof f.phase === 'string' ? f.phase : undefined;
|
|
204
|
+
const reason = f.reason && typeof f.reason === 'object' ? f.reason as Record<string, unknown> : undefined;
|
|
205
|
+
const code = reason && typeof reason.code === 'string' ? reason.code : 'error';
|
|
206
|
+
const message = reason && typeof reason.message === 'string' ? reason.message : '';
|
|
207
|
+
const partialOutputs = f.partialOutputs && typeof f.partialOutputs === 'object' ? f.partialOutputs as Record<string, unknown> : undefined;
|
|
208
|
+
const turnsCompleted = asNumber(partialOutputs?.turnsCompleted);
|
|
209
|
+
|
|
210
|
+
const MAX_MSG_LEN = 80;
|
|
211
|
+
const truncatedMessage = message.length > MAX_MSG_LEN ? `${message.slice(0, MAX_MSG_LEN - 3)}...` : message;
|
|
212
|
+
const phaseText = phase ? ` at ${phase}` : '';
|
|
213
|
+
const turnsText = turnsCompleted !== undefined ? ` (${turnsCompleted} turn${turnsCompleted === 1 ? '' : 's'} completed)` : '';
|
|
214
|
+
const msgText = truncatedMessage.length > 0 ? `: ${truncatedMessage}` : '';
|
|
215
|
+
return `agent ${agentId} failed [${code}]${phaseText}${msgText}${turnsText}`;
|
|
216
|
+
}
|
|
217
|
+
|
|
129
218
|
export function summarizeToolResult(toolName: string | undefined, content: string): string | null {
|
|
130
219
|
if (!toolName) return null;
|
|
131
220
|
const family = toolName.includes('__') ? toolName.split('__').pop()! : toolName;
|
|
@@ -143,6 +232,7 @@ export function summarizeToolResult(toolName: string | undefined, content: strin
|
|
|
143
232
|
case 'read': return summarizeRead(obj);
|
|
144
233
|
case 'edit': return summarizeEdit(obj);
|
|
145
234
|
case 'exec': return summarizeExec(obj);
|
|
235
|
+
case 'agent': return summarizeAgentFailure(obj);
|
|
146
236
|
default: return null;
|
|
147
237
|
}
|
|
148
238
|
}
|
|
@@ -9,6 +9,7 @@ import { activeUiTones } from './theme.ts';
|
|
|
9
9
|
import { formatElapsed } from '../utils/format-elapsed.ts';
|
|
10
10
|
import { abbreviateCount } from '../utils/format-number.ts';
|
|
11
11
|
import { computeContextUsage } from '../core/context-usage.ts';
|
|
12
|
+
import { permissionModeLabel, permissionModeTone } from '../core/permission-mode.ts';
|
|
12
13
|
import { calcSessionCost, isModelPriced } from '../export/cost-utils.ts';
|
|
13
14
|
import { buildFooterTip, isAgentActive } from './footer-tips.ts';
|
|
14
15
|
import type { StreamMetrics } from '../core/stream-event-wiring.ts';
|
|
@@ -198,6 +199,9 @@ export class UIFactory {
|
|
|
198
199
|
// Honest cross-surface spine posture. Defined ONLY in adopted-daemon
|
|
199
200
|
// mode (undefined in embedded/local), so the segment is absent otherwise.
|
|
200
201
|
sessionSpineStatus?: 'online' | 'offline',
|
|
202
|
+
// Session permission mode (config value). Rendered as a leading pill in the
|
|
203
|
+
// posture block; undefined suppresses the pill (e.g. bare test callers).
|
|
204
|
+
permissionMode?: string,
|
|
201
205
|
): Line[] {
|
|
202
206
|
const lines: Line[] = [];
|
|
203
207
|
const promptLines = prompt.split('\n');
|
|
@@ -332,6 +336,24 @@ export class UIFactory {
|
|
|
332
336
|
// (light-terminal-aware); state.info reads on both light and dark terminals.
|
|
333
337
|
const t = activeUiTones();
|
|
334
338
|
const composerTokens: Array<{ text: string; fg: string; bold?: boolean; dim?: boolean }> = [];
|
|
339
|
+
// Permission-mode pill — always shown so the active session posture (normal
|
|
340
|
+
// / plan / accept-edits / auto) is visible at a glance. Tone: normal reads
|
|
341
|
+
// dim/neutral, plan reads info (read-only, safe), accept-edits and auto read
|
|
342
|
+
// as caution (raised autonomy). Cycled by Shift+Tab, toggled by /plan.
|
|
343
|
+
if (permissionMode) {
|
|
344
|
+
const modeTone = permissionModeTone(permissionMode);
|
|
345
|
+
const modeFg = modeTone === 'caution' ? t.chrome.warn : modeTone === 'info' ? t.state.info : '244';
|
|
346
|
+
composerTokens.push({ text: ` mode:${permissionModeLabel(permissionMode)} `, fg: modeFg, bold: modeTone !== 'neutral', dim: modeTone === 'neutral' });
|
|
347
|
+
}
|
|
348
|
+
// Context-usage chip — always-visible compaction-pressure indicator so the
|
|
349
|
+
// user sees compaction approaching before it happens. Colored by proximity
|
|
350
|
+
// to the auto-compact threshold (fraction; falls back to 0.85 when unset).
|
|
351
|
+
if (contextWindow && contextWindow > 0) {
|
|
352
|
+
const ctxUsage = computeContextUsage(lastInputTokens ?? 0, contextWindow);
|
|
353
|
+
const ctxThr = compactThreshold && compactThreshold > 0 ? compactThreshold : 0.85;
|
|
354
|
+
const ctxFg = ctxUsage.clampedRatio >= ctxThr ? t.chrome.bad : ctxUsage.clampedRatio >= ctxThr * 0.85 ? t.chrome.warn : '244';
|
|
355
|
+
composerTokens.push({ text: ` ctx:${ctxUsage.pct}% `, fg: ctxFg, bold: ctxUsage.clampedRatio >= ctxThr, dim: ctxUsage.clampedRatio < ctxThr * 0.85 });
|
|
356
|
+
}
|
|
335
357
|
if (composerMode) composerTokens.push({ text: ` ${GLYPHS.status.active} ${composerMode} `, fg: t.state.info, bold: true });
|
|
336
358
|
if (composerPendingRisk && composerPendingRisk !== 'none') {
|
|
337
359
|
const riskColor = composerPendingRisk === 'approval-wait'
|
|
@@ -18,6 +18,9 @@ import type { ForensicsRegistry } from '@/runtime/index.ts';
|
|
|
18
18
|
import type { PolicyRuntimeState } from '@/runtime/index.ts';
|
|
19
19
|
import type { FileUndoManager } from '@pellux/goodvibes-sdk/platform/state';
|
|
20
20
|
import type { WorkspaceCheckpointManager } from '@pellux/goodvibes-sdk/platform/workspace';
|
|
21
|
+
import type { GatewayMethodCatalog } from '@pellux/goodvibes-sdk/platform/control-plane';
|
|
22
|
+
import type { WorkspaceTrustManager } from './trust/workspace-trust.ts';
|
|
23
|
+
import type { WorkspaceRegistrationManager } from './trust/workspace-registration.ts';
|
|
21
24
|
import type { McpRegistry } from '@pellux/goodvibes-sdk/platform/mcp';
|
|
22
25
|
import type { MemoryRegistry } from '@pellux/goodvibes-sdk/platform/state';
|
|
23
26
|
import type { IntegrationHelperService } from '@/runtime/index.ts';
|
|
@@ -53,6 +56,7 @@ import {
|
|
|
53
56
|
|
|
54
57
|
export type CreateBootstrapCommandContextOptions = {
|
|
55
58
|
configManager: ConfigManager;
|
|
59
|
+
featureFlagManager?: import('@/runtime/index.ts').FeatureFlagManager;
|
|
56
60
|
providerRegistry: ProviderRegistry;
|
|
57
61
|
conversation: ConversationManager;
|
|
58
62
|
runtime: MutableRuntimeState;
|
|
@@ -75,6 +79,9 @@ export type CreateBootstrapCommandContextOptions = {
|
|
|
75
79
|
planRuntime?: PlanRuntimeService;
|
|
76
80
|
fileUndoManager: FileUndoManager;
|
|
77
81
|
workspaceCheckpointManager?: WorkspaceCheckpointManager;
|
|
82
|
+
gatewayMethods?: GatewayMethodCatalog;
|
|
83
|
+
workspaceTrustManager?: WorkspaceTrustManager;
|
|
84
|
+
workspaceRegistrationManager?: WorkspaceRegistrationManager;
|
|
78
85
|
memoryRegistry?: MemoryRegistry;
|
|
79
86
|
integrationHelpers?: IntegrationHelperService;
|
|
80
87
|
automationManager?: ShellAutomationManagerRuntimeService;
|
|
@@ -136,6 +143,7 @@ export function createBootstrapCommandContext(
|
|
|
136
143
|
const {
|
|
137
144
|
providerRegistry,
|
|
138
145
|
configManager,
|
|
146
|
+
featureFlagManager,
|
|
139
147
|
conversation,
|
|
140
148
|
runtime,
|
|
141
149
|
requestRender,
|
|
@@ -156,6 +164,9 @@ export function createBootstrapCommandContext(
|
|
|
156
164
|
planRuntime,
|
|
157
165
|
fileUndoManager,
|
|
158
166
|
workspaceCheckpointManager,
|
|
167
|
+
gatewayMethods,
|
|
168
|
+
workspaceTrustManager,
|
|
169
|
+
workspaceRegistrationManager,
|
|
159
170
|
memoryRegistry,
|
|
160
171
|
integrationHelpers,
|
|
161
172
|
automationManager,
|
|
@@ -265,6 +276,9 @@ export function createBootstrapCommandContext(
|
|
|
265
276
|
keybindingsManager,
|
|
266
277
|
fileUndoManager,
|
|
267
278
|
workspaceCheckpointManager,
|
|
279
|
+
gatewayMethods,
|
|
280
|
+
workspaceTrustManager,
|
|
281
|
+
workspaceRegistrationManager,
|
|
268
282
|
panelManager,
|
|
269
283
|
profileManager,
|
|
270
284
|
bookmarkManager,
|
|
@@ -272,7 +286,7 @@ export function createBootstrapCommandContext(
|
|
|
272
286
|
projectPlanningProjectId,
|
|
273
287
|
workPlanStore,
|
|
274
288
|
}, shellServices);
|
|
275
|
-
const platform = createBootstrapCommandPlatformSection({ configManager, voiceProviderRegistry, voiceService, webSearchService, mediaProviders, artifactStore }, shellServices);
|
|
289
|
+
const platform = createBootstrapCommandPlatformSection({ configManager, featureFlagManager, voiceProviderRegistry, voiceService, webSearchService, mediaProviders, artifactStore }, shellServices);
|
|
276
290
|
const extensions = createBootstrapCommandExtensionsSection({
|
|
277
291
|
toolRegistry,
|
|
278
292
|
mcpRegistry,
|
|
@@ -9,6 +9,7 @@ import type { McpApi } from '@pellux/goodvibes-sdk/platform/mcp';
|
|
|
9
9
|
import type { PanelManager, PanelDeepLinkTarget } from '../panels/panel-manager.ts';
|
|
10
10
|
import type { ProviderApi } from '@pellux/goodvibes-sdk/platform/providers';
|
|
11
11
|
import type { OpsApi } from '@/runtime/index.ts';
|
|
12
|
+
import type { FeatureFlagManager } from '@/runtime/index.ts';
|
|
12
13
|
import type { MutableRuntimeState } from '@/runtime/index.ts';
|
|
13
14
|
import type { ProviderRegistry } from '@pellux/goodvibes-sdk/platform/providers';
|
|
14
15
|
import type { CommandContext } from '../input/command-registry.ts';
|
|
@@ -19,6 +20,9 @@ import type { ForensicsRegistry } from '@/runtime/index.ts';
|
|
|
19
20
|
import type { PolicyRuntimeState } from '@/runtime/index.ts';
|
|
20
21
|
import type { CodeIndexStore, FileUndoManager } from '@pellux/goodvibes-sdk/platform/state';
|
|
21
22
|
import type { WorkspaceCheckpointManager } from '@pellux/goodvibes-sdk/platform/workspace';
|
|
23
|
+
import type { GatewayMethodCatalog } from '@pellux/goodvibes-sdk/platform/control-plane';
|
|
24
|
+
import type { WorkspaceTrustManager } from './trust/workspace-trust.ts';
|
|
25
|
+
import type { WorkspaceRegistrationManager } from './trust/workspace-registration.ts';
|
|
22
26
|
import type { McpRegistry } from '@pellux/goodvibes-sdk/platform/mcp';
|
|
23
27
|
import type { MemoryRegistry } from '@pellux/goodvibes-sdk/platform/state';
|
|
24
28
|
import type { IntegrationHelperService } from '@/runtime/index.ts';
|
|
@@ -70,6 +74,7 @@ export interface BootstrapCommandActionOptions {
|
|
|
70
74
|
|
|
71
75
|
export interface BootstrapCommandSectionOptions {
|
|
72
76
|
readonly configManager: ConfigManager;
|
|
77
|
+
readonly featureFlagManager?: FeatureFlagManager;
|
|
73
78
|
readonly providerRegistry: ProviderRegistry;
|
|
74
79
|
readonly conversation: ConversationManager;
|
|
75
80
|
readonly runtime: MutableRuntimeState;
|
|
@@ -91,6 +96,9 @@ export interface BootstrapCommandSectionOptions {
|
|
|
91
96
|
readonly shellPaths: ShellPathService;
|
|
92
97
|
readonly fileUndoManager: FileUndoManager;
|
|
93
98
|
readonly workspaceCheckpointManager?: WorkspaceCheckpointManager;
|
|
99
|
+
readonly gatewayMethods?: GatewayMethodCatalog;
|
|
100
|
+
readonly workspaceTrustManager?: WorkspaceTrustManager;
|
|
101
|
+
readonly workspaceRegistrationManager?: WorkspaceRegistrationManager;
|
|
94
102
|
readonly memoryRegistry?: MemoryRegistry;
|
|
95
103
|
readonly integrationHelpers?: IntegrationHelperService;
|
|
96
104
|
readonly knowledgeService?: KnowledgeService;
|
|
@@ -362,7 +370,7 @@ export function createBootstrapCommandProviderSection(
|
|
|
362
370
|
export function createBootstrapCommandWorkspaceSection(
|
|
363
371
|
options: Pick<
|
|
364
372
|
BootstrapCommandSectionOptions,
|
|
365
|
-
'keybindingsManager' | 'fileUndoManager' | 'workspaceCheckpointManager' | 'panelManager' | 'profileManager' | 'bookmarkManager'
|
|
373
|
+
'keybindingsManager' | 'fileUndoManager' | 'workspaceCheckpointManager' | 'gatewayMethods' | 'workspaceTrustManager' | 'workspaceRegistrationManager' | 'panelManager' | 'profileManager' | 'bookmarkManager'
|
|
366
374
|
| 'projectPlanningService' | 'projectPlanningProjectId' | 'workPlanStore'
|
|
367
375
|
>,
|
|
368
376
|
shellServices: BootstrapCommandShellServices,
|
|
@@ -371,6 +379,9 @@ export function createBootstrapCommandWorkspaceSection(
|
|
|
371
379
|
keybindingsManager: options.keybindingsManager,
|
|
372
380
|
fileUndoManager: options.fileUndoManager,
|
|
373
381
|
workspaceCheckpointManager: options.workspaceCheckpointManager,
|
|
382
|
+
gatewayMethods: options.gatewayMethods,
|
|
383
|
+
workspaceTrustManager: options.workspaceTrustManager,
|
|
384
|
+
workspaceRegistrationManager: options.workspaceRegistrationManager,
|
|
374
385
|
panelManager: options.panelManager,
|
|
375
386
|
profileManager: options.profileManager,
|
|
376
387
|
bookmarkManager: options.bookmarkManager,
|
|
@@ -384,13 +395,14 @@ export function createBootstrapCommandWorkspaceSection(
|
|
|
384
395
|
export function createBootstrapCommandPlatformSection(
|
|
385
396
|
options: Pick<
|
|
386
397
|
BootstrapCommandSectionOptions,
|
|
387
|
-
'configManager' | 'voiceProviderRegistry' | 'voiceService' | 'webSearchService' | 'mediaProviders' | 'artifactStore'
|
|
398
|
+
'configManager' | 'featureFlagManager' | 'voiceProviderRegistry' | 'voiceService' | 'webSearchService' | 'mediaProviders' | 'artifactStore'
|
|
388
399
|
>,
|
|
389
400
|
shellServices: BootstrapCommandShellServices,
|
|
390
401
|
): BootstrapCommandPlatformSection {
|
|
391
402
|
return {
|
|
392
403
|
config: getConfigSnapshot(options.configManager),
|
|
393
404
|
configManager: options.configManager,
|
|
405
|
+
featureFlagManager: options.featureFlagManager,
|
|
394
406
|
voiceProviderRegistry: options.voiceProviderRegistry,
|
|
395
407
|
voiceService: options.voiceService,
|
|
396
408
|
webSearchService: options.webSearchService,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ConversationManager } from '../core/conversation';
|
|
2
|
+
import { registerSessionConversation } from './conversation-rewind-port.ts';
|
|
2
3
|
import { SelectionManager } from '../input/selection.ts';
|
|
3
4
|
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
4
5
|
import { ConfigManager, getConfiguredSystemPrompt } from '../config/index.ts';
|
|
@@ -13,19 +14,15 @@ import type { SystemMessageRouter } from '../core/system-message-router.ts';
|
|
|
13
14
|
import type { ConversationFollowUpItem } from '@pellux/goodvibes-sdk/platform/core';
|
|
14
15
|
import type { OrchestratorUserInputOptions } from '../core/orchestrator.ts';
|
|
15
16
|
import type { ControlPlaneRecentEvent } from '@pellux/goodvibes-sdk/platform/control-plane';
|
|
16
|
-
import type { MutableRuntimeState } from '@/runtime/index.ts';
|
|
17
17
|
import type { BootstrapOptions } from './context.ts';
|
|
18
|
-
import { createFeatureFlagManager } from '@/runtime/index.ts';
|
|
19
|
-
import { RuntimeEventBus } from '@/runtime/index.ts';
|
|
20
|
-
import type { SessionEvent } from '@/runtime/index.ts';
|
|
21
18
|
import { createRuntimeStore, createDomainDispatch, type RuntimeStore } from './store/index.ts';
|
|
22
|
-
import { ForensicsCollector, ForensicsRegistry } from '@/runtime/index.ts';
|
|
23
19
|
import {
|
|
24
|
-
|
|
20
|
+
type MutableRuntimeState, type SessionEvent, createFeatureFlagManager, RuntimeEventBus, ForensicsCollector,
|
|
21
|
+
ForensicsRegistry, generateUserSessionId, loadBootstrapSystemPrompt, syncConfiguredServices,
|
|
22
|
+
registerBootstrapHookBridge, registerBootstrapRuntimeEvents,
|
|
25
23
|
} from '@/runtime/index.ts';
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
import { registerBootstrapRuntimeEvents } from '@/runtime/index.ts';
|
|
24
|
+
import { readExecEnvScrubAllowlist } from '../input/exec-env-scrub-config.ts';
|
|
25
|
+
import { createSandboxExecAsk, sandboxExecAskDepsFromRuntime } from '../permissions/sandbox-exec-gate.ts';
|
|
29
26
|
import { createRuntimeServices, type RuntimeServices } from './services.ts';
|
|
30
27
|
import { runBootMemoryFold } from './memory-fold.ts';
|
|
31
28
|
import { setPricingSource } from '../export/cost-utils.ts';
|
|
@@ -36,6 +33,8 @@ import { createWrfcPersistence, type WrfcPersistence } from './wrfc-persistence.
|
|
|
36
33
|
import type { SystemMessagePriority } from '../core/system-message-router.ts';
|
|
37
34
|
import { SessionSpineClient, SessionUnionCache, TUI_SPINE_PARTICIPANT } from '@pellux/goodvibes-sdk/platform/runtime/session-spine';
|
|
38
35
|
import { SessionInboundInputPoller, createBootstrapInboundInputPoller } from './session-inbound-inputs.ts';
|
|
36
|
+
import { detectPriorWorkspaceState, trustGatedAsk } from './trust/workspace-trust.ts';
|
|
37
|
+
import { syncNotifierQueueIntegrations } from './bootstrap-notifier-sync.ts';
|
|
39
38
|
|
|
40
39
|
// ---------------------------------------------------------------------------
|
|
41
40
|
// Pre-router buffer
|
|
@@ -250,7 +249,10 @@ export async function initializeBootstrapCore(
|
|
|
250
249
|
getConversationTitle: () => getConversationTitle(),
|
|
251
250
|
workingDir,
|
|
252
251
|
homeDirectory,
|
|
252
|
+
// Sampled BEFORE any service writes to <cwd>/.goodvibes so a new workspace isn't misread as used.
|
|
253
|
+
workspaceHadPriorState: detectPriorWorkspaceState(workingDir),
|
|
253
254
|
});
|
|
255
|
+
await services.workspaceTrustManager.load(); // settle trust (+ grandfathering) before any tool runs
|
|
254
256
|
const providerRegistry = services.providerRegistry;
|
|
255
257
|
providerRegistry.initModelLimits();
|
|
256
258
|
services.benchmarkStore.initBenchmarks();
|
|
@@ -371,6 +373,15 @@ export async function initializeBootstrapCore(
|
|
|
371
373
|
serviceRegistry: services.serviceRegistry,
|
|
372
374
|
overflowHandler: services.overflowHandler,
|
|
373
375
|
changeTracker: services.sessionChangeTracker,
|
|
376
|
+
// Master switch stays on (SDK default); this only widens the allowlist of
|
|
377
|
+
// variable NAMES kept even though they look credential-bearing. See
|
|
378
|
+
// exec-env-scrub-config.ts (permissions.execEnvScrubAllowlist).
|
|
379
|
+
credentialEnvScrub: { allowlist: readExecEnvScrubAllowlist(configManager) },
|
|
380
|
+
// Registers the context_accounting tool on this (the real, interactive)
|
|
381
|
+
// registry against OUR holder rather than a fresh internal one, so the
|
|
382
|
+
// Orchestrator-backed source bound at bootstrap.ts is what the tool
|
|
383
|
+
// actually reads from. See runtime/context-accounting-source.ts.
|
|
384
|
+
contextAccountingHolder: services.contextAccountingHolder,
|
|
374
385
|
});
|
|
375
386
|
// Note: installWrfcAgentToolGuard is called after routeOrBuffer is defined
|
|
376
387
|
// (further below) so the onTrace callback can route guard decisions through
|
|
@@ -400,6 +411,7 @@ export async function initializeBootstrapCore(
|
|
|
400
411
|
memoryRegistry: services.memoryRegistry,
|
|
401
412
|
sandboxSessionRegistry: services.sandboxSessionRegistry,
|
|
402
413
|
workflowServices: services.workflow,
|
|
414
|
+
contextAccountingHolder: services.contextAccountingHolder,
|
|
403
415
|
});
|
|
404
416
|
|
|
405
417
|
const bootstrapUnsubs: Array<() => void> = [];
|
|
@@ -679,39 +691,24 @@ export async function initializeBootstrapCore(
|
|
|
679
691
|
services.webhookNotifier.attachToRuntimeBus(runtimeBus);
|
|
680
692
|
|
|
681
693
|
const notifier = await Notifier.fromConfig(services.serviceRegistry);
|
|
682
|
-
|
|
683
|
-
if (queueStatuses.length > 0) {
|
|
684
|
-
notifier.attachToRuntimeBus(runtimeBus);
|
|
685
|
-
for (const queueStatus of queueStatuses) {
|
|
686
|
-
domainDispatch.syncIntegration({
|
|
687
|
-
id: queueStatus.channel,
|
|
688
|
-
displayName: queueStatus.channel[0]!.toUpperCase() + queueStatus.channel.slice(1),
|
|
689
|
-
category: 'communication',
|
|
690
|
-
status: queueStatus.metrics.deadLettered > 0 ? 'degraded' : 'healthy',
|
|
691
|
-
enabled: true,
|
|
692
|
-
successCount: queueStatus.metrics.delivered,
|
|
693
|
-
errorCount: queueStatus.metrics.deadLettered,
|
|
694
|
-
...(queueStatus.dlqEntries[0]?.deadAt ? { lastErrorAt: queueStatus.dlqEntries[0].deadAt } : {}),
|
|
695
|
-
...(queueStatus.dlqEntries[0]?.finalError ? { lastError: queueStatus.dlqEntries[0].finalError } : {}),
|
|
696
|
-
meta: {
|
|
697
|
-
attempts: queueStatus.metrics.totalAttempts,
|
|
698
|
-
retrying: queueStatus.metrics.retrying,
|
|
699
|
-
deadLetters: queueStatus.metrics.deadLettered,
|
|
700
|
-
dlqSize: queueStatus.metrics.dlqSize,
|
|
701
|
-
sloEnforced: queueStatus.sloEnforced,
|
|
702
|
-
},
|
|
703
|
-
}, 'bootstrap.notifier');
|
|
704
|
-
}
|
|
705
|
-
}
|
|
694
|
+
syncNotifierQueueIntegrations(notifier, runtimeBus, domainDispatch);
|
|
706
695
|
|
|
707
696
|
await syncConfiguredServices(domainDispatch.syncIntegration, services.serviceRegistry);
|
|
708
697
|
|
|
709
698
|
const permissionManager = new PermissionManager(
|
|
710
|
-
(
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
699
|
+
// Composed ask layer: the workspace trust gate (outer) wraps the sandbox-aware
|
|
700
|
+
// exec gate (inner); see sandbox-exec-gate.ts. The catastrophic block is untouched.
|
|
701
|
+
trustGatedAsk(
|
|
702
|
+
services.workspaceTrustManager,
|
|
703
|
+
createSandboxExecAsk(
|
|
704
|
+
sandboxExecAskDepsFromRuntime(configManager, featureFlags),
|
|
705
|
+
(request) => approvalBroker.requestApproval({
|
|
706
|
+
request,
|
|
707
|
+
sessionId: runtimeSessionIdRef.value,
|
|
708
|
+
localPrompt: permissionPromptRef.requestPermission,
|
|
709
|
+
}),
|
|
710
|
+
),
|
|
711
|
+
),
|
|
715
712
|
createPermissionConfigReader(configManager),
|
|
716
713
|
policyRuntimeState,
|
|
717
714
|
services.hookDispatcher,
|
|
@@ -728,6 +725,9 @@ export async function initializeBootstrapCore(
|
|
|
728
725
|
sessionId: userSessionId,
|
|
729
726
|
};
|
|
730
727
|
runtimeSessionIdRef.value = runtime.sessionId;
|
|
728
|
+
// Register the live conversation so the composed daemon's rewind.plan/apply verbs
|
|
729
|
+
// can serve conversation scope for this session (see conversation-rewind-port.ts).
|
|
730
|
+
registerSessionConversation(runtime.sessionId, conversation);
|
|
731
731
|
void sharedSessionBroker.createSession({
|
|
732
732
|
id: runtime.sessionId,
|
|
733
733
|
title: 'Terminal UI session',
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Notifier } from '@pellux/goodvibes-sdk/platform/integrations';
|
|
2
|
+
import type { RuntimeEventBus } from '@/runtime/index.ts';
|
|
3
|
+
import type { createDomainDispatch } from './store/index.ts';
|
|
4
|
+
|
|
5
|
+
type DomainDispatch = ReturnType<typeof createDomainDispatch>;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Reflect the notifier's outbound delivery queues into the integrations domain
|
|
9
|
+
* (so the UI shows per-channel health) and attach the notifier to the runtime
|
|
10
|
+
* bus when any queue exists. Extracted from bootstrap-core to keep that file
|
|
11
|
+
* within the module size budget.
|
|
12
|
+
*/
|
|
13
|
+
export function syncNotifierQueueIntegrations(
|
|
14
|
+
notifier: Notifier,
|
|
15
|
+
runtimeBus: RuntimeEventBus,
|
|
16
|
+
domainDispatch: DomainDispatch,
|
|
17
|
+
): void {
|
|
18
|
+
const queueStatuses = notifier.getQueueStatus();
|
|
19
|
+
if (queueStatuses.length === 0) return;
|
|
20
|
+
notifier.attachToRuntimeBus(runtimeBus);
|
|
21
|
+
for (const queueStatus of queueStatuses) {
|
|
22
|
+
domainDispatch.syncIntegration({
|
|
23
|
+
id: queueStatus.channel,
|
|
24
|
+
displayName: queueStatus.channel[0]!.toUpperCase() + queueStatus.channel.slice(1),
|
|
25
|
+
category: 'communication',
|
|
26
|
+
status: queueStatus.metrics.deadLettered > 0 ? 'degraded' : 'healthy',
|
|
27
|
+
enabled: true,
|
|
28
|
+
successCount: queueStatus.metrics.delivered,
|
|
29
|
+
errorCount: queueStatus.metrics.deadLettered,
|
|
30
|
+
...(queueStatus.dlqEntries[0]?.deadAt ? { lastErrorAt: queueStatus.dlqEntries[0].deadAt } : {}),
|
|
31
|
+
...(queueStatus.dlqEntries[0]?.finalError ? { lastError: queueStatus.dlqEntries[0].finalError } : {}),
|
|
32
|
+
meta: {
|
|
33
|
+
attempts: queueStatus.metrics.totalAttempts,
|
|
34
|
+
retrying: queueStatus.metrics.retrying,
|
|
35
|
+
deadLetters: queueStatus.metrics.deadLettered,
|
|
36
|
+
dlqSize: queueStatus.metrics.dlqSize,
|
|
37
|
+
sloEnforced: queueStatus.sloEnforced,
|
|
38
|
+
},
|
|
39
|
+
}, 'bootstrap.notifier');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -17,6 +17,7 @@ import { GitStatusProvider } from '../renderer/git-status.ts';
|
|
|
17
17
|
import type { GitHeaderInfo } from '../renderer/git-status.ts';
|
|
18
18
|
import type { PermissionRequestHandler } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
19
19
|
import { registerBuiltinPanels } from '../panels/builtin-panels.ts';
|
|
20
|
+
import { WorkspaceRegistrationManager } from './trust/workspace-registration.ts';
|
|
20
21
|
import { createSystemMessageRouter, type SystemMessageRouter } from '../core/system-message-router.ts';
|
|
21
22
|
import { getConfigSnapshot } from '../config/index.ts';
|
|
22
23
|
import { createBootstrapCommandContext } from './bootstrap-command-context.ts';
|
|
@@ -259,6 +260,12 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
259
260
|
planRuntime,
|
|
260
261
|
fileUndoManager: services.fileUndoManager,
|
|
261
262
|
workspaceCheckpointManager: services.workspaceCheckpointManager,
|
|
263
|
+
gatewayMethods: services.gatewayMethods,
|
|
264
|
+
workspaceTrustManager: services.workspaceTrustManager,
|
|
265
|
+
// Registration half is stateless (reads the shared registry on demand), so
|
|
266
|
+
// it is constructed here for the command context rather than threaded through
|
|
267
|
+
// RuntimeServices — no early-load requirement like the trust gate has.
|
|
268
|
+
workspaceRegistrationManager: new WorkspaceRegistrationManager({ shellPaths: services.shellPaths }),
|
|
262
269
|
memoryRegistry: services.memoryRegistry,
|
|
263
270
|
integrationHelpers: services.integrationHelpers,
|
|
264
271
|
automationManager: services.automationManager,
|
|
@@ -291,6 +298,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
|
|
|
291
298
|
codeIndexStore: services.codeIndexStore,
|
|
292
299
|
codeIndexReindexScheduler: services.codeIndexReindexScheduler,
|
|
293
300
|
isPassiveCodeInjectionFlagEnabled: () => services.featureFlags.isEnabled('agent-passive-code-injection'),
|
|
301
|
+
featureFlagManager: services.featureFlags,
|
|
294
302
|
// Expose the MAIN session's per-turn passive-injection ring
|
|
295
303
|
// so `/recall injections` (no agent id) renders it — see recall-review.ts.
|
|
296
304
|
getMainSessionTurnInjections: () => orchestrator.getTurnInjections(),
|