@pellux/goodvibes-tui 1.1.0 → 1.9.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 +85 -21
- package/README.md +28 -18
- package/docs/foundation-artifacts/operator-contract.json +4045 -1763
- package/package.json +2 -2
- package/src/audio/spoken-turn-controller.ts +12 -2
- package/src/audio/spoken-turn-wiring.ts +2 -1
- package/src/cli/help.ts +8 -1
- package/src/cli/service-posture.ts +2 -1
- package/src/cli/status.ts +2 -1
- package/src/cli/surface-command.ts +2 -2
- package/src/core/alert-gating.ts +67 -0
- package/src/core/approval-alert.ts +72 -0
- package/src/core/budget-breach-notifier.ts +106 -0
- package/src/core/composer-state.ts +11 -3
- package/src/core/conversation-line-cache.ts +27 -3
- package/src/core/conversation-rendering.ts +90 -14
- package/src/core/conversation.ts +18 -0
- package/src/core/focus-tracker.ts +41 -0
- package/src/core/long-task-notifier.ts +33 -6
- package/src/core/stream-event-wiring.ts +20 -1
- package/src/core/system-message-noise.ts +87 -0
- package/src/core/system-message-router.ts +104 -51
- package/src/core/turn-cancellation.ts +25 -0
- package/src/core/turn-event-wiring.ts +72 -3
- package/src/daemon/cli.ts +29 -2
- package/src/daemon/handlers/register.ts +8 -1
- package/src/daemon/service-commands.ts +329 -0
- package/src/export/cost-utils.ts +36 -0
- package/src/input/autocomplete.ts +27 -1
- package/src/input/command-registry.ts +84 -5
- package/src/input/commands/checkpoint-runtime.ts +280 -0
- package/src/input/commands/codebase-runtime.ts +232 -0
- package/src/input/commands/config.ts +43 -3
- package/src/input/commands/eval.ts +1 -1
- package/src/input/commands/health-runtime.ts +10 -2
- package/src/input/commands/image-runtime.ts +112 -0
- package/src/input/commands/intelligence-runtime.ts +11 -1
- package/src/input/commands/local-auth-runtime.ts +4 -1
- package/src/input/commands/local-runtime.ts +9 -3
- package/src/input/commands/marketplace-runtime.ts +2 -2
- package/src/input/commands/memory.ts +73 -35
- package/src/input/commands/operator-panel-runtime.ts +71 -31
- package/src/input/commands/planning-runtime.ts +116 -4
- package/src/input/commands/platform-sandbox-runtime.ts +1 -6
- package/src/input/commands/plugin-runtime.ts +2 -2
- package/src/input/commands/policy-dispatch.ts +21 -0
- package/src/input/commands/provider-accounts-runtime.ts +1 -1
- package/src/input/commands/qrcode-runtime.ts +26 -6
- package/src/input/commands/recall-review.ts +35 -0
- package/src/input/commands/remote-runtime-setup.ts +5 -3
- package/src/input/commands/remote-runtime.ts +3 -3
- package/src/input/commands/runtime-services.ts +54 -13
- package/src/input/commands/services-runtime.ts +1 -1
- package/src/input/commands/session-content.ts +20 -9
- package/src/input/commands/session-workflow.ts +16 -1
- package/src/input/commands/settings-sync-runtime.ts +16 -4
- package/src/input/commands/shell-core.ts +25 -8
- package/src/input/commands/skills-runtime.ts +2 -8
- package/src/input/commands/subscription-runtime.ts +2 -2
- package/src/input/commands/test-runtime.ts +277 -0
- package/src/input/commands/websearch-runtime.ts +101 -0
- package/src/input/commands/work-plan-runtime.ts +36 -10
- package/src/input/commands/workstream-runtime.ts +488 -0
- package/src/input/commands.ts +12 -0
- package/src/input/config-modal-types.ts +175 -0
- package/src/input/config-modal.ts +592 -0
- package/src/input/feed-context-factory.ts +10 -8
- package/src/input/handler-command-route.ts +37 -20
- package/src/input/handler-content-actions.ts +17 -2
- package/src/input/handler-feed-routes.ts +74 -114
- package/src/input/handler-feed.ts +79 -27
- package/src/input/handler-interactions.ts +1 -3
- package/src/input/handler-modal-routes.ts +136 -6
- package/src/input/handler-modal-stack.ts +14 -7
- package/src/input/handler-modal-token-routes.ts +16 -49
- package/src/input/handler-onboarding-daemon-adopt.ts +149 -0
- package/src/input/handler-onboarding.ts +71 -59
- package/src/input/handler-picker-routes.ts +26 -102
- package/src/input/handler-shortcuts.ts +74 -14
- package/src/input/handler-types.ts +2 -6
- package/src/input/handler-ui-state.ts +10 -22
- package/src/input/handler.ts +12 -29
- package/src/input/keybindings.ts +23 -8
- package/src/input/model-picker-types.ts +24 -6
- package/src/input/model-picker.ts +77 -2
- package/src/input/onboarding/onboarding-runtime-status.ts +10 -1
- package/src/input/onboarding/onboarding-wizard-apply.ts +8 -1
- package/src/input/onboarding/onboarding-wizard-constants.ts +4 -1
- package/src/input/onboarding/onboarding-wizard-network-adopt.ts +136 -0
- package/src/input/onboarding/onboarding-wizard-steps.ts +9 -6
- package/src/input/onboarding/onboarding-wizard-types.ts +3 -1
- package/src/input/panel-integration-actions.ts +9 -170
- package/src/input/panel-mouse-geometry.ts +97 -0
- package/src/input/panel-paste-flood-guard.ts +86 -0
- package/src/input/selection-modal.ts +11 -0
- package/src/input/session-picker-modal.ts +44 -4
- package/src/input/settings-modal-data.ts +146 -2
- package/src/input/settings-modal-mutations.ts +6 -4
- package/src/input/settings-modal-types.ts +4 -2
- package/src/main.ts +49 -51
- package/src/panels/agent-inspector-shared.ts +2 -1
- package/src/panels/base-panel.ts +22 -1
- package/src/panels/builtin/agent.ts +21 -107
- package/src/panels/builtin/development.ts +15 -61
- package/src/panels/builtin/knowledge.ts +8 -32
- package/src/panels/builtin/operations.ts +84 -428
- package/src/panels/builtin/session.ts +21 -112
- package/src/panels/builtin/shared.ts +18 -46
- package/src/panels/builtin-modals.ts +218 -0
- package/src/panels/builtin-panels.ts +5 -0
- package/src/panels/cost-tracker-panel.ts +36 -10
- package/src/panels/diff-panel.ts +12 -43
- package/src/panels/eval-registry.ts +60 -0
- package/src/panels/fleet-deep-link.ts +31 -0
- package/src/panels/fleet-panel-format.ts +62 -0
- package/src/panels/fleet-panel-worktree-detail.ts +48 -0
- package/src/panels/fleet-panel.ts +758 -0
- package/src/panels/fleet-read-model.ts +520 -0
- package/src/panels/fleet-steer.ts +125 -0
- package/src/panels/fleet-stop.ts +153 -0
- package/src/panels/fleet-tabs.ts +230 -0
- package/src/panels/fleet-transcript.ts +356 -0
- package/src/panels/index.ts +7 -31
- package/src/panels/modals/hooks-modal.ts +187 -0
- package/src/panels/modals/keybindings-modal.ts +166 -0
- package/src/panels/modals/knowledge-modal.ts +158 -0
- package/src/panels/modals/local-auth-modal.ts +132 -0
- package/src/panels/modals/marketplace-modal.ts +218 -0
- package/src/panels/modals/memory-modal.ts +180 -0
- package/src/panels/modals/modal-surface-helpers.ts +54 -0
- package/src/panels/modals/modal-theme.ts +42 -0
- package/src/panels/modals/pairing-modal.ts +163 -0
- package/src/panels/modals/planning-modal.ts +304 -0
- package/src/panels/modals/plugins-modal.ts +174 -0
- package/src/panels/modals/policy-modal.ts +256 -0
- package/src/panels/modals/provider-health-modal.ts +136 -0
- package/src/panels/modals/remote-modal.ts +115 -0
- package/src/panels/modals/sandbox-modal.ts +150 -0
- package/src/panels/modals/security-modal.ts +217 -0
- package/src/panels/modals/services-modal.ts +179 -0
- package/src/panels/modals/settings-sync-modal.ts +142 -0
- package/src/panels/modals/skills-modal.ts +189 -0
- package/src/panels/modals/subscription-modal.ts +172 -0
- package/src/panels/modals/work-plan-modal.ts +177 -0
- package/src/panels/panel-confirm-overlay.ts +72 -0
- package/src/panels/panel-manager.ts +123 -9
- package/src/panels/polish-core.ts +38 -25
- package/src/panels/project-planning-answer-actions.ts +8 -11
- package/src/panels/skills-panel.ts +7 -51
- package/src/panels/types.ts +37 -0
- package/src/permissions/hunk-selection.ts +179 -0
- package/src/permissions/prompt.ts +216 -13
- package/src/renderer/autocomplete-overlay.ts +28 -2
- package/src/renderer/compaction-history-modal.ts +19 -3
- package/src/renderer/compaction-preview.ts +13 -2
- package/src/renderer/compaction-quality.ts +100 -0
- package/src/renderer/compositor.ts +2 -3
- package/src/renderer/config-modal.ts +95 -0
- package/src/renderer/conversation-overlays.ts +10 -17
- package/src/renderer/fleet-tab-strip.ts +56 -0
- package/src/renderer/footer-tips.ts +15 -3
- package/src/renderer/fullscreen-primitives.ts +32 -22
- package/src/renderer/git-status.ts +43 -1
- package/src/renderer/help-overlay.ts +2 -2
- package/src/renderer/layout.ts +0 -4
- package/src/renderer/markdown.ts +7 -3
- package/src/renderer/modal-factory.ts +25 -20
- package/src/renderer/model-workspace.ts +62 -4
- package/src/renderer/overlay-box.ts +21 -17
- package/src/renderer/panel-workspace-bar.ts +8 -2
- package/src/renderer/process-indicator.ts +14 -3
- package/src/renderer/selection-modal-overlay.ts +6 -1
- package/src/renderer/session-picker-modal.ts +196 -3
- package/src/renderer/settings-modal-helpers.ts +2 -0
- package/src/renderer/settings-modal.ts +7 -0
- package/src/renderer/shell-surface.ts +8 -1
- package/src/renderer/status-glyphs.ts +14 -15
- package/src/renderer/system-message.ts +15 -3
- package/src/renderer/terminal-bg-probe.ts +339 -0
- package/src/renderer/terminal-escapes.ts +20 -0
- package/src/renderer/theme-mode-config.ts +67 -0
- package/src/renderer/theme.ts +91 -1
- package/src/renderer/thinking.ts +11 -3
- package/src/renderer/tool-call.ts +15 -9
- package/src/renderer/tool-result-summary.ts +148 -0
- package/src/renderer/turn-injection.ts +133 -0
- package/src/renderer/ui-factory.ts +154 -85
- package/src/renderer/ui-primitives.ts +30 -129
- package/src/runtime/bootstrap-command-context.ts +27 -1
- package/src/runtime/bootstrap-command-parts.ts +41 -10
- package/src/runtime/bootstrap-core.ts +47 -15
- package/src/runtime/bootstrap-hook-bridge.ts +7 -0
- package/src/runtime/bootstrap-shell.ts +48 -17
- package/src/runtime/bootstrap.ts +129 -22
- package/src/runtime/code-index-services.ts +135 -0
- package/src/runtime/legacy-daemon-migration.ts +516 -0
- package/src/runtime/memory-fold.ts +26 -0
- package/src/runtime/onboarding/derivation.ts +7 -2
- package/src/runtime/onboarding/snapshot.ts +27 -1
- package/src/runtime/onboarding/types.ts +31 -1
- package/src/runtime/operator-token-cleanup.ts +82 -1
- package/src/runtime/orchestrator-core-services.ts +59 -0
- package/src/runtime/process-lifecycle.ts +3 -1
- package/src/runtime/resume-notice.ts +209 -0
- package/src/runtime/services.ts +98 -46
- package/src/runtime/session-inbound-inputs.ts +252 -0
- package/src/runtime/session-spine-transport.ts +64 -0
- package/src/runtime/terminal-output-guard.ts +15 -8
- package/src/runtime/ui-services.ts +27 -3
- package/src/runtime/workstream-services.ts +327 -0
- package/src/runtime/wrfc-persistence.ts +124 -17
- package/src/shell/blocking-input.ts +68 -4
- package/src/shell/recovery-input-helpers.ts +170 -1
- package/src/shell/ui-openers.ts +171 -26
- package/src/utils/format-duration.ts +8 -18
- package/src/utils/splash-lines.ts +1 -1
- package/src/utils/terminal-width.ts +52 -0
- package/src/version.ts +1 -1
- package/src/panels/agent-inspector-panel.ts +0 -786
- package/src/panels/approval-panel.ts +0 -252
- package/src/panels/automation-control-panel.ts +0 -479
- package/src/panels/cockpit-panel.ts +0 -481
- package/src/panels/cockpit-read-model.ts +0 -238
- package/src/panels/communication-panel.ts +0 -256
- package/src/panels/control-plane-panel.ts +0 -470
- package/src/panels/debug-panel.ts +0 -615
- package/src/panels/docs-panel.ts +0 -384
- package/src/panels/eval-panel.ts +0 -627
- package/src/panels/file-explorer-panel.ts +0 -673
- package/src/panels/file-preview-panel.ts +0 -517
- package/src/panels/hooks-panel.ts +0 -401
- package/src/panels/incident-review-panel.ts +0 -406
- package/src/panels/intelligence-panel.ts +0 -383
- package/src/panels/knowledge-graph-panel.ts +0 -515
- package/src/panels/marketplace-panel.ts +0 -399
- package/src/panels/memory-panel.ts +0 -558
- package/src/panels/ops-control-panel.ts +0 -329
- package/src/panels/ops-strategy-panel.ts +0 -321
- package/src/panels/orchestration-panel.ts +0 -465
- package/src/panels/panel-list-panel.ts +0 -566
- package/src/panels/plan-dashboard-panel.ts +0 -707
- package/src/panels/policy-panel.ts +0 -517
- package/src/panels/project-planning-panel.ts +0 -731
- package/src/panels/provider-health-panel.ts +0 -678
- package/src/panels/provider-health-tracker.ts +0 -310
- package/src/panels/provider-health-views.ts +0 -567
- package/src/panels/qr-panel.ts +0 -280
- package/src/panels/remote-panel.ts +0 -534
- package/src/panels/routes-panel.ts +0 -241
- package/src/panels/sandbox-panel.ts +0 -456
- package/src/panels/security-panel.ts +0 -447
- package/src/panels/services-panel.ts +0 -329
- package/src/panels/session-browser-panel.ts +0 -496
- package/src/panels/settings-sync-panel.ts +0 -398
- package/src/panels/subscription-panel.ts +0 -342
- package/src/panels/symbol-outline-panel.ts +0 -619
- package/src/panels/system-messages-panel.ts +0 -364
- package/src/panels/tasks-panel.ts +0 -608
- package/src/panels/thinking-panel.ts +0 -333
- package/src/panels/tool-inspector-panel.ts +0 -537
- package/src/panels/work-plan-panel.ts +0 -540
- package/src/panels/worktree-panel.ts +0 -360
- package/src/panels/wrfc-panel.ts +0 -790
- package/src/renderer/agent-detail-modal.ts +0 -466
- package/src/renderer/live-tail-modal.ts +0 -156
- package/src/renderer/process-modal.ts +0 -671
- package/src/renderer/qr-renderer.ts +0 -120
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
upsertEcosystemCatalogEntry,
|
|
14
14
|
uninstallEcosystemCatalogEntry,
|
|
15
15
|
} from '@/runtime/index.ts';
|
|
16
|
-
import { requireEcosystemCatalogPaths, requirePluginPathOptions } from './runtime-services.ts';
|
|
16
|
+
import { openModalCommand, requireEcosystemCatalogPaths, requirePluginPathOptions } from './runtime-services.ts';
|
|
17
17
|
|
|
18
18
|
export function registerPluginRuntimeCommands(registry: CommandRegistry): void {
|
|
19
19
|
registry.register({
|
|
@@ -33,7 +33,7 @@ export function registerPluginRuntimeCommands(registry: CommandRegistry): void {
|
|
|
33
33
|
const sub = args[0];
|
|
34
34
|
|
|
35
35
|
if (!sub || sub === 'open' || sub === 'panel') {
|
|
36
|
-
|
|
36
|
+
openModalCommand(ctx, 'plugins-modal');
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
|
|
@@ -301,6 +301,23 @@ export function renderPolicyUsage(): string {
|
|
|
301
301
|
].join('\n');
|
|
302
302
|
}
|
|
303
303
|
|
|
304
|
+
// W6 command-path parity: the policy modal dropped its 'r' (record a
|
|
305
|
+
// divergence-dashboard trend sample) action because the panel used to call
|
|
306
|
+
// this._state.recordTrendEntry() directly and /policy had no equivalent verb.
|
|
307
|
+
// This exposes it as a thin wrapper: recordTrendEntry() forwards to the attached
|
|
308
|
+
// DivergencePanel, so it only captures a sample while a simulation dashboard is
|
|
309
|
+
// active — reported honestly here rather than silently no-op'ing.
|
|
310
|
+
function handleRecordTrend(_args: string[], context: CommandContext): void {
|
|
311
|
+
const policyState = getPolicyState(context);
|
|
312
|
+
if (!policyState.getDashboard()) {
|
|
313
|
+
context.print('[policy] No active simulation dashboard — nothing to sample. Run `/policy simulate` first, then `/policy record-trend`.');
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
policyState.recordTrendEntry();
|
|
317
|
+
const snap = policyState.getSnapshot();
|
|
318
|
+
context.print(`[policy] Recorded a divergence trend sample (${snap.divergence?.trend.length ?? 0} point(s) total).`);
|
|
319
|
+
}
|
|
320
|
+
|
|
304
321
|
export async function dispatchPolicyCommand(args: string[], context: CommandContext): Promise<void> {
|
|
305
322
|
const [sub, ...rest] = args;
|
|
306
323
|
switch (sub) {
|
|
@@ -332,6 +349,10 @@ export async function dispatchPolicyCommand(args: string[], context: CommandCont
|
|
|
332
349
|
case 'st':
|
|
333
350
|
await handleStatus(rest, context);
|
|
334
351
|
break;
|
|
352
|
+
case 'record-trend':
|
|
353
|
+
case 'trend':
|
|
354
|
+
handleRecordTrend(rest, context);
|
|
355
|
+
break;
|
|
335
356
|
default:
|
|
336
357
|
context.print(renderPolicyUsage());
|
|
337
358
|
break;
|
|
@@ -29,7 +29,7 @@ export function registerProviderAccountsRuntimeCommands(registry: CommandRegistr
|
|
|
29
29
|
async handler(args, ctx) {
|
|
30
30
|
const sub = (args[0] ?? 'review').toLowerCase();
|
|
31
31
|
if (sub === 'panel' || sub === 'open') {
|
|
32
|
-
|
|
32
|
+
ctx.openModal?.('providers-modal'); // W6.1: accounts alias -> provider-health modal
|
|
33
33
|
return;
|
|
34
34
|
}
|
|
35
35
|
const snapshot = await loadProviderAccountSnapshot(ctx);
|
|
@@ -1,19 +1,39 @@
|
|
|
1
|
+
import { join } from 'node:path';
|
|
1
2
|
import type { CommandRegistry } from '../command-registry.ts';
|
|
2
|
-
import {
|
|
3
|
+
import { openModalCommand, requireShellPaths } from './runtime-services.ts';
|
|
4
|
+
import { regenerateCompanionToken } from '@pellux/goodvibes-sdk/platform/pairing';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* Register the /qrcode command.
|
|
6
8
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
+
* `/qrcode` (no args) opens the companion-app pairing modal (QR code + URL/
|
|
10
|
+
* token/username). `/qrcode regenerate` rotates the companion pairing token:
|
|
11
|
+
* it re-keys the shared operator-token store, so the previously-issued token is
|
|
12
|
+
* rejected on the next auth and a fresh QR must be scanned to reconnect.
|
|
9
13
|
*/
|
|
10
14
|
export function registerQrcodeRuntimeCommands(registry: CommandRegistry): void {
|
|
11
15
|
registry.register({
|
|
12
16
|
name: 'qrcode',
|
|
13
17
|
aliases: ['qr', 'pair'],
|
|
14
|
-
description: 'Open the QR code
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
description: 'Open the companion-app pairing modal (QR code), or regenerate the pairing token',
|
|
19
|
+
usage: '[regenerate]',
|
|
20
|
+
argsHint: '[regenerate]',
|
|
21
|
+
handler(args, ctx) {
|
|
22
|
+
if (args[0]?.toLowerCase() === 'regenerate') {
|
|
23
|
+
const shellPaths = requireShellPaths(ctx);
|
|
24
|
+
const daemonHomeDir = join(shellPaths.homeDirectory, '.goodvibes', 'daemon');
|
|
25
|
+
try {
|
|
26
|
+
const rotated = regenerateCompanionToken({ daemonHomeDir });
|
|
27
|
+
ctx.print(
|
|
28
|
+
'Pairing token rotated. The previous token is now rejected — ' +
|
|
29
|
+
`re-scan the QR (new peer ${rotated.peerId.slice(0, 8)}…) to reconnect the companion app.`,
|
|
30
|
+
);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
ctx.print(`Could not regenerate the pairing token: ${String(error)}`);
|
|
33
|
+
}
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
openModalCommand(ctx, 'pairing-modal');
|
|
17
37
|
},
|
|
18
38
|
});
|
|
19
39
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { CommandContext } from '../command-registry.ts';
|
|
2
2
|
import { VALID_REVIEW_STATES, VALID_SCOPES, isValidReviewState, isValidScope } from './recall-shared.ts';
|
|
3
3
|
import { getMemoryApi } from './recall-query.ts';
|
|
4
|
+
import { buildMainSessionTurnInjectionsText, buildTurnInjectionsText } from '../../renderer/turn-injection.ts';
|
|
4
5
|
|
|
5
6
|
export function handleRecallQueue(args: string[], context: CommandContext): void {
|
|
6
7
|
const memory = getMemoryApi(context);
|
|
@@ -102,6 +103,40 @@ export function handleRecallExplain(args: string[], context: CommandContext): vo
|
|
|
102
103
|
context.print(explanation.prompt ?? '[recall] No explainable project knowledge was selected.');
|
|
103
104
|
}
|
|
104
105
|
|
|
106
|
+
/**
|
|
107
|
+
* W5.2 (wo803) — per-turn passive knowledge injection inspectability.
|
|
108
|
+
*
|
|
109
|
+
* With an explicit agent id, reads `AgentRecord.turnInjections` (Wave-5 wo801)
|
|
110
|
+
* via `context.ops.agentManager.exportState()` — the CommandContext-exposed
|
|
111
|
+
* `ShellAgentManagerService` doesn't have a `getStatus`/`list` pair, but
|
|
112
|
+
* `exportState()` returns the same full `AgentRecord[]` (it's what
|
|
113
|
+
* compactConversation() already uses for the same reason).
|
|
114
|
+
*
|
|
115
|
+
* With NO agent id (wo805 wiring), renders the MAIN interactive session's own
|
|
116
|
+
* per-turn injection ring — `Orchestrator.getTurnInjections()`, threaded onto
|
|
117
|
+
* the command context as `session.getMainSessionTurnInjections`. As of wo805 the
|
|
118
|
+
* main session DOES route through the passive-injection engine, so this is the
|
|
119
|
+
* honest main-session default (previously there was no record source, so the
|
|
120
|
+
* no-id path could only print a usage hint). When the accessor isn't wired
|
|
121
|
+
* (headless/test contexts built without an orchestrator), the main-session
|
|
122
|
+
* renderer's honest empty state stands in.
|
|
123
|
+
*/
|
|
124
|
+
export function handleRecallInjections(args: string[], context: CommandContext): void {
|
|
125
|
+
const agentId = args[0];
|
|
126
|
+
if (!agentId) {
|
|
127
|
+
const mainSessionInjections = context.session.getMainSessionTurnInjections?.() ?? [];
|
|
128
|
+
context.print(buildMainSessionTurnInjectionsText(mainSessionInjections));
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const records = context.ops.agentManager?.exportState() ?? [];
|
|
132
|
+
const record = records.find((candidate) => candidate.id === agentId);
|
|
133
|
+
if (!record) {
|
|
134
|
+
context.print(`[recall] Agent not found: ${agentId}`);
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
context.print(buildTurnInjectionsText(agentId, record.turnInjections ?? []));
|
|
138
|
+
}
|
|
139
|
+
|
|
105
140
|
export function handleRecallPromote(args: string[], context: CommandContext): void {
|
|
106
141
|
const memory = getMemoryApi(context);
|
|
107
142
|
if (!memory) {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { dirname, resolve } from 'node:path';
|
|
3
3
|
import { getDefaultAcpAgentCommand } from '@pellux/goodvibes-sdk/platform/acp';
|
|
4
|
+
import { resolveDaemonEnabled } from '@pellux/goodvibes-sdk/platform/config';
|
|
4
5
|
import type { CommandContext, RemoteCommandService } from '../command-registry.ts';
|
|
5
6
|
import type { RemoteSessionBundle } from '@/runtime/index.ts';
|
|
6
7
|
import { requireShellPaths } from './runtime-services.ts';
|
|
@@ -37,10 +38,11 @@ export async function handleRemoteSetupCommand(
|
|
|
37
38
|
if (subcommand === 'setup') {
|
|
38
39
|
const command = getDefaultAcpAgentCommand();
|
|
39
40
|
const danger = ctx.platform.configManager.getCategory('danger');
|
|
41
|
+
const daemonEnabled = resolveDaemonEnabled(ctx.platform.configManager);
|
|
40
42
|
const lines = [
|
|
41
43
|
'Remote Setup Review',
|
|
42
44
|
` acp agent command: ${command.join(' ')}`,
|
|
43
|
-
` daemon enabled: ${
|
|
45
|
+
` daemon enabled: ${daemonEnabled ? 'yes' : 'no'}`,
|
|
44
46
|
` http listener enabled: ${danger.httpListener ? 'yes' : 'no'}`,
|
|
45
47
|
` remote runner contracts: ${remoteRegistry.listContracts().length}`,
|
|
46
48
|
` active acp connections: ${activeConnections.length}`,
|
|
@@ -48,7 +50,7 @@ export async function handleRemoteSetupCommand(
|
|
|
48
50
|
' guidance:',
|
|
49
51
|
' - set ACP_AGENT_CMD to override the spawned remote agent command',
|
|
50
52
|
' - use /remote env to export a reusable shell snippet',
|
|
51
|
-
' -
|
|
53
|
+
' - the daemon runs by default (daemon.enabled); enable danger.httpListener only when you actually need that remote surface',
|
|
52
54
|
];
|
|
53
55
|
if (args[1]?.toLowerCase() === 'export') {
|
|
54
56
|
const pathArg = args[2];
|
|
@@ -62,7 +64,7 @@ export async function handleRemoteSetupCommand(
|
|
|
62
64
|
writeFileSync(targetPath, `${JSON.stringify({
|
|
63
65
|
exportedAt: Date.now(),
|
|
64
66
|
acpAgentCommand: command,
|
|
65
|
-
daemonEnabled
|
|
67
|
+
daemonEnabled,
|
|
66
68
|
httpListenerEnabled: Boolean(danger.httpListener),
|
|
67
69
|
remoteRunnerContracts: remoteRegistry.listContracts().length,
|
|
68
70
|
}, null, 2)}\n`, 'utf-8');
|
|
@@ -47,11 +47,11 @@ export function registerRemoteRuntimeCommands(registry: CommandRegistry): void {
|
|
|
47
47
|
usage: '[list | show [agentId] | supervisor [runnerId] | capabilities [runnerId] | recover [runnerId] | setup [export <path>] | env [export <path>] | tunnel [review|export <path>] | bootstrap [export <path>|inspect <path>] | session <export|inspect|import> <path> | pool <list|show|create|assign|unassign> ... | dispatch [template] <description> | dispatch-pool <pool> [template] <description> | contract [agentId] | cancel <agentId> | export <agentId> [path] | artifact list | artifact show <id> | artifact export <id> [path] | review <id> | rerun-local <id> | import <path>]',
|
|
48
48
|
async handler(args, ctx) {
|
|
49
49
|
if (args.length === 0) {
|
|
50
|
-
if (ctx.
|
|
51
|
-
ctx.
|
|
50
|
+
if (ctx.openModal) {
|
|
51
|
+
ctx.openModal('remote-modal'); // W6.1: remote panel -> config modal
|
|
52
52
|
return;
|
|
53
53
|
}
|
|
54
|
-
ctx.print('Remote
|
|
54
|
+
ctx.print('Remote surface is not available in this runtime.');
|
|
55
55
|
return;
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -9,6 +9,8 @@ import type {
|
|
|
9
9
|
} from '../command-registry.ts';
|
|
10
10
|
import { compactSmallWindow, getLastCompactionEvent, SMALL_WINDOW_THRESHOLD } from '@pellux/goodvibes-sdk/platform/core';
|
|
11
11
|
import type { CompactionContext, CompactionEvent } from '@pellux/goodvibes-sdk/platform/core';
|
|
12
|
+
import { recordCompactionQualityScore, scoreCompactionRun } from '../../renderer/compaction-quality.ts';
|
|
13
|
+
import type { CompactionQualityScore } from '../../renderer/compaction-quality.ts';
|
|
12
14
|
import type { UiReadModels } from '../../runtime/ui-read-models.ts';
|
|
13
15
|
import type { ShellPathService } from '@/runtime/index.ts';
|
|
14
16
|
import type { EcosystemCatalogPathOptions } from '@/runtime/index.ts';
|
|
@@ -101,6 +103,21 @@ export function openCommandPanel(
|
|
|
101
103
|
showPanel(panelId, pane);
|
|
102
104
|
}
|
|
103
105
|
|
|
106
|
+
/**
|
|
107
|
+
* W6.1 (group-B migration): open a config-modal surface by name via the
|
|
108
|
+
* ctx.openModal seam (ui-openers wires it; the WO-A host replaces the interim
|
|
109
|
+
* "not available yet" implementation with real dispatch). Front-doors for
|
|
110
|
+
* panels that migrated to modals call this instead of openCommandPanel — the
|
|
111
|
+
* modal is the surface's new home. Stubbed in tests by setting ctx.openModal.
|
|
112
|
+
*/
|
|
113
|
+
export function openModalCommand(
|
|
114
|
+
context: Pick<CommandContext, 'openModal'>,
|
|
115
|
+
modalName: string,
|
|
116
|
+
): void {
|
|
117
|
+
const openModal = requireContextValue(context.openModal, 'openModal');
|
|
118
|
+
openModal(modalName);
|
|
119
|
+
}
|
|
120
|
+
|
|
104
121
|
export function openOnboardingWizard(
|
|
105
122
|
context: Pick<CommandContext, 'openOnboardingWizard'>,
|
|
106
123
|
modeOrOptions?: import('../onboarding/onboarding-wizard.ts').OnboardingWizardMode
|
|
@@ -238,12 +255,19 @@ export function requireProviderApi(context: CommandContext): ProviderApi {
|
|
|
238
255
|
return requireContextValue(context.clients?.providerApi, 'clients.providerApi');
|
|
239
256
|
}
|
|
240
257
|
|
|
258
|
+
/** Result of a manual /compact run: the SDK's CompactionEvent, plus an
|
|
259
|
+
* out-of-band quality score (W5.4/B28) when one could be computed. */
|
|
260
|
+
export interface CompactionRunResult {
|
|
261
|
+
readonly event: CompactionEvent;
|
|
262
|
+
readonly qualityScore: CompactionQualityScore | null;
|
|
263
|
+
}
|
|
264
|
+
|
|
241
265
|
/**
|
|
242
|
-
* Compact the conversation and return the CompactionEvent recorded by the SDK
|
|
243
|
-
* or null if no event was recorded (e.g.
|
|
244
|
-
* change).
|
|
266
|
+
* Compact the conversation and return the CompactionEvent recorded by the SDK
|
|
267
|
+
* (plus an out-of-band quality score), or null if no event was recorded (e.g.
|
|
268
|
+
* compaction was skipped or produced no change).
|
|
245
269
|
*/
|
|
246
|
-
export async function compactConversation(context: CommandContext): Promise<
|
|
270
|
+
export async function compactConversation(context: CommandContext): Promise<CompactionRunResult | null> {
|
|
247
271
|
const conversationManager = context.session.conversationManager;
|
|
248
272
|
const providerRegistry = context.provider.providerRegistry;
|
|
249
273
|
// Resolve the live context window for the current model so manual /compact
|
|
@@ -263,20 +287,20 @@ export async function compactConversation(context: CommandContext): Promise<Comp
|
|
|
263
287
|
}
|
|
264
288
|
|
|
265
289
|
const eventBefore = getLastCompactionEvent();
|
|
290
|
+
const messagesBefore = conversationManager.getMessagesForLLM();
|
|
266
291
|
const sessionMemories = context.session.sessionMemoryStore?.list() ?? [];
|
|
267
292
|
const lineageTracker = context.session.sessionLineageTracker;
|
|
268
293
|
const agentManager = context.ops.agentManager;
|
|
269
294
|
const planManager = context.ops.planManager;
|
|
270
295
|
const compactionCtx: CompactionContext = {
|
|
271
|
-
messages:
|
|
296
|
+
messages: messagesBefore,
|
|
272
297
|
sessionMemories,
|
|
273
|
-
// Mirror buildAutoCompactionContext: pass
|
|
274
|
-
//
|
|
275
|
-
//
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
.filter((agent) => agent.status === 'running' || agent.status === 'pending') ?? [],
|
|
298
|
+
// Mirror buildAutoCompactionContext: pass ALL agent records (not just
|
|
299
|
+
// running/pending) so completed/failed subagent work reaches the
|
|
300
|
+
// "Completed Agent Work" / "Currently Running" compaction sections, plus
|
|
301
|
+
// the active execution plan and the session-lineage log so the handoff
|
|
302
|
+
// summary and lineage section are populated correctly (not "compaction #0").
|
|
303
|
+
agents: agentManager?.exportState() ?? [],
|
|
280
304
|
// Mirror buildAutoCompactionContext: include the live WRFC chains (wired
|
|
281
305
|
// through context.session.wrfcController) so the handoff summary's
|
|
282
306
|
// orchestration section matches the SDK auto-compaction path.
|
|
@@ -284,6 +308,11 @@ export async function compactConversation(context: CommandContext): Promise<Comp
|
|
|
284
308
|
activePlan: planManager?.getActive(context.session.runtime.sessionId) ?? null,
|
|
285
309
|
lineageEntries: lineageTracker?.getEntries() ?? [],
|
|
286
310
|
compactionCount: lineageTracker?.getCompactionCount() ?? 0,
|
|
311
|
+
// Mirror buildAutoCompactionContext: pass the recorded original task so
|
|
312
|
+
// the "Original task" lineage line reflects the session's actual first
|
|
313
|
+
// task instead of falling back to the current message on every manual
|
|
314
|
+
// compaction after the first.
|
|
315
|
+
originalTask: lineageTracker?.getOriginalTask() ?? undefined,
|
|
287
316
|
contextWindow,
|
|
288
317
|
trigger: 'manual',
|
|
289
318
|
extractionModelId: context.session.runtime.model,
|
|
@@ -299,7 +328,19 @@ export async function compactConversation(context: CommandContext): Promise<Comp
|
|
|
299
328
|
const eventAfter = getLastCompactionEvent();
|
|
300
329
|
// Return the new event only if it differs from the one recorded before the call.
|
|
301
330
|
if (eventAfter !== null && eventAfter !== eventBefore) {
|
|
302
|
-
|
|
331
|
+
// W5.4/B28: score this run out-of-band (see compaction-quality.ts for why
|
|
332
|
+
// this can't just subscribe to the SDK's own CompactionManager pipeline)
|
|
333
|
+
// and keep the score keyed by this event's timestamp for /compact-history.
|
|
334
|
+
const qualityScore = scoreCompactionRun({
|
|
335
|
+
sessionId: context.session.runtime.sessionId,
|
|
336
|
+
contextWindow,
|
|
337
|
+
messagesBefore,
|
|
338
|
+
messagesAfter: conversationManager.getMessagesForLLM(),
|
|
339
|
+
tokensBefore: eventAfter.tokensBeforeEstimate,
|
|
340
|
+
tokensAfter: eventAfter.tokensAfterEstimate,
|
|
341
|
+
});
|
|
342
|
+
recordCompactionQualityScore(eventAfter.timestamp, qualityScore);
|
|
343
|
+
return { event: eventAfter, qualityScore };
|
|
303
344
|
}
|
|
304
345
|
return null;
|
|
305
346
|
}
|
|
@@ -16,7 +16,7 @@ export function registerServicesRuntimeCommands(registry: CommandRegistry): void
|
|
|
16
16
|
const sub = args[0] ?? 'open';
|
|
17
17
|
const shellPaths = requireShellPaths(ctx);
|
|
18
18
|
if (sub === 'open' || sub === 'panel') {
|
|
19
|
-
|
|
19
|
+
ctx.openModal?.('services-modal'); // W6.1: services panel -> config modal
|
|
20
20
|
return;
|
|
21
21
|
}
|
|
22
22
|
const svcRegistry = requireServiceRegistry(ctx);
|
|
@@ -384,9 +384,20 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
|
|
|
384
384
|
},
|
|
385
385
|
});
|
|
386
386
|
|
|
387
|
+
// W6-C3 (Wave 6 core-verb pass, MEMORY fragmentation — worst-class
|
|
388
|
+
// collision #2): this command used to be named /memory, colliding with
|
|
389
|
+
// the agent's /memory (an alias that forwards to /recall, the durable
|
|
390
|
+
// cross-session MemoryStore) — same command name, two unrelated features.
|
|
391
|
+
// Renamed to /note (this feature manages EPHEMERAL, session-scoped sticky
|
|
392
|
+
// notes pinned across context compaction — an entirely different resource
|
|
393
|
+
// from /recall's durable records). /memory is now registered as an alias
|
|
394
|
+
// of /recall below (memory.ts), matching the agent, so the word means the
|
|
395
|
+
// same thing on both surfaces. See
|
|
396
|
+
// docs/decisions/2026-07-06-core-verb-spec.md (in the SDK repo) for the
|
|
397
|
+
// full writeup.
|
|
387
398
|
registry.register({
|
|
388
|
-
name: '
|
|
389
|
-
description: 'Manage session
|
|
399
|
+
name: 'note',
|
|
400
|
+
description: 'Manage session notes (pinned across context compaction)',
|
|
390
401
|
usage: '[list|add <text>|remove <id>]',
|
|
391
402
|
argsHint: '[list|add|remove]',
|
|
392
403
|
handler(args, ctx) {
|
|
@@ -394,26 +405,26 @@ export function registerSessionContentCommands(registry: CommandRegistry): void
|
|
|
394
405
|
if (sub === 'list' || args.length === 0) {
|
|
395
406
|
const memories = requireSessionMemoryStore(ctx).list();
|
|
396
407
|
ctx.print(memories.length === 0
|
|
397
|
-
? 'No session
|
|
398
|
-
: [`Session
|
|
408
|
+
? 'No session notes. Use !# prefix or /note add <text> to create one.'
|
|
409
|
+
: [`Session Notes (${memories.length}):`, ...memories.map(m => ` [${m.id}] ${m.text}`)].join('\n'));
|
|
399
410
|
} else if (sub === 'add') {
|
|
400
411
|
const text = args.slice(1).join(' ').trim();
|
|
401
412
|
if (!text) {
|
|
402
|
-
ctx.print('Usage: /
|
|
413
|
+
ctx.print('Usage: /note add <text>');
|
|
403
414
|
return;
|
|
404
415
|
}
|
|
405
416
|
const id = requireSessionMemoryStore(ctx).add(text);
|
|
406
|
-
ctx.print(`
|
|
417
|
+
ctx.print(`Note added: [${id}] ${text}`);
|
|
407
418
|
} else if (sub === 'remove') {
|
|
408
419
|
const id = args[1];
|
|
409
420
|
if (!id) {
|
|
410
|
-
ctx.print('Usage: /
|
|
421
|
+
ctx.print('Usage: /note remove <id>');
|
|
411
422
|
return;
|
|
412
423
|
}
|
|
413
424
|
const store = requireSessionMemoryStore(ctx);
|
|
414
|
-
ctx.print(store.remove(id) ? `
|
|
425
|
+
ctx.print(store.remove(id) ? `Note removed: [${id}]` : `Note not found: ${id}`);
|
|
415
426
|
} else {
|
|
416
|
-
ctx.print('Usage: /
|
|
427
|
+
ctx.print('Usage: /note [list|add <text>|remove <id>]\n /note — list all session notes\n /note list — list all session notes\n /note add <text> — add a note without sending a message\n /note remove <id> — remove a specific note');
|
|
417
428
|
}
|
|
418
429
|
},
|
|
419
430
|
});
|
|
@@ -79,11 +79,23 @@ function buildTranscriptReviewLines(
|
|
|
79
79
|
];
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
// Exported (test-only concern) so the MIGRATE-TO-MODAL redirect-skip honesty
|
|
83
|
+
// (W6 review, finding 3: saved-layout restore with 'sessions' must not lie)
|
|
84
|
+
// can be unit-tested directly instead of through a full /resume harness.
|
|
85
|
+
export function reopenPanelsFromReturnContext(ctx: CommandContext, summary: SessionReturnContextSummary | undefined): string[] {
|
|
83
86
|
if (!summary?.openPanels || summary.openPanels.length === 0) return [];
|
|
84
87
|
const panelManager = requirePanelManager(ctx);
|
|
85
88
|
const reopened: string[] = [];
|
|
89
|
+
const movedToModal: string[] = [];
|
|
86
90
|
for (const panelId of summary.openPanels.slice(0, 4)) {
|
|
91
|
+
// W6.1 (the purge): a MIGRATE-TO-MODAL id has no panel to restore — a modal
|
|
92
|
+
// is not part of the saved panel layout. Skip it (don't pop a modal
|
|
93
|
+
// mid-resume) and note it once, rather than firing openModal + revealing an
|
|
94
|
+
// empty workspace during resume.
|
|
95
|
+
if (panelManager.getModalRedirect(panelId) !== undefined) {
|
|
96
|
+
movedToModal.push(panelId);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
87
99
|
try {
|
|
88
100
|
panelManager.open(panelId);
|
|
89
101
|
reopened.push(panelId);
|
|
@@ -92,6 +104,9 @@ function reopenPanelsFromReturnContext(ctx: CommandContext, summary: SessionRetu
|
|
|
92
104
|
}
|
|
93
105
|
}
|
|
94
106
|
if (reopened.length > 0) panelManager.show();
|
|
107
|
+
if (movedToModal.length > 0) {
|
|
108
|
+
ctx.print(`Note: ${movedToModal.join(', ')} moved to a modal — reopen via its command instead of as a panel.`);
|
|
109
|
+
}
|
|
95
110
|
return reopened;
|
|
96
111
|
}
|
|
97
112
|
|
|
@@ -26,14 +26,26 @@ export function registerSettingsSyncRuntimeCommands(registry: CommandRegistry):
|
|
|
26
26
|
registry.register({
|
|
27
27
|
name: 'settings-sync',
|
|
28
28
|
aliases: ['settingssync'],
|
|
29
|
-
description: '
|
|
30
|
-
usage: '[review|
|
|
29
|
+
description: 'Open the settings sync modal (bare); review posture, export/import bundles, or resolve conflicts by subcommand',
|
|
30
|
+
usage: '[panel|report|review|show <key>|staged|conflicts|resolve <key> <local|synced>|failures|rollback-history|export <path>|inspect <path>|pull <path>|push <path>|lock <key> <source> <reason...>|unlock <key>] — bare opens the modal',
|
|
31
31
|
handler(args, ctx) {
|
|
32
32
|
const shellPaths = requireShellPaths(ctx);
|
|
33
33
|
const controlPlaneConfigDir = ctx.platform.configManager.getControlPlaneConfigDir();
|
|
34
|
-
const sub = (args[0] ?? '
|
|
34
|
+
const sub = (args[0] ?? '').toLowerCase();
|
|
35
|
+
// DEBT-5 item 3 (report-vs-modal front doors): settings-sync has a full
|
|
36
|
+
// modal surface (settings-sync-modal), so the bare command now opens it
|
|
37
|
+
// — the old bare/`review` transcript report moved to an explicit
|
|
38
|
+
// `report` subcommand (scriptability preserved: /settings-sync report).
|
|
39
|
+
if (sub === '') {
|
|
40
|
+
ctx.openModal?.('settings-sync-modal');
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
35
43
|
if (sub === 'panel' || sub === 'open') {
|
|
36
|
-
|
|
44
|
+
ctx.openModal?.('settings-sync-modal'); // W6.1: settings-sync panel -> config modal
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (sub === 'report' || sub === 'review') {
|
|
48
|
+
ctx.print(formatSettingsControlPlaneReview(ctx.platform.configManager).join('\n'));
|
|
37
49
|
return;
|
|
38
50
|
}
|
|
39
51
|
if (sub === 'show') {
|
|
@@ -153,6 +153,8 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
153
153
|
{ id: '/template save', label: '/template save <name>', detail: 'Save prompt as template', category: 'Templates' },
|
|
154
154
|
{ id: '/template use', label: '/template use <name>', detail: 'Execute template', category: 'Templates' },
|
|
155
155
|
{ id: '/tools', label: '/tools', detail: 'List available tools', category: 'Tools & System' },
|
|
156
|
+
{ id: '/search', label: '/search <query> [--limit <n>]', detail: 'Search the web and show ranked results', category: 'Tools & System' },
|
|
157
|
+
{ id: '/imagine', label: '/imagine <prompt>', detail: 'Generate an image from a prompt', category: 'Tools & System' },
|
|
156
158
|
{ id: '/paste', label: '/paste', detail: 'Insert clipboard text or image into the prompt', category: 'Tools & System' },
|
|
157
159
|
{ id: '/shortcuts', label: '/shortcuts', detail: 'View keyboard shortcuts reference', category: 'Tools & System' },
|
|
158
160
|
{ id: '/commands', label: '/commands', detail: 'Browse all commands in a scrollable list', category: 'Tools & System' },
|
|
@@ -161,7 +163,10 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
161
163
|
{ id: '/quit', label: '/quit', detail: 'Exit', category: 'Tools & System' },
|
|
162
164
|
{ id: '/wq', label: '/wq', detail: 'Commit all git changes and then exit', category: 'Tools & System' },
|
|
163
165
|
];
|
|
164
|
-
|
|
166
|
+
// UX-C: every item here is a command, and picking one RUNS it — label
|
|
167
|
+
// the verb "Run" (matching the slash-command palette) instead of the
|
|
168
|
+
// generic "Select" default.
|
|
169
|
+
ctx.openSelection('Help — Commands', items, { allowSearch: true, primaryVerbLabel: 'Run' }, (result) => {
|
|
165
170
|
if (!result) return;
|
|
166
171
|
const command = result.item.id;
|
|
167
172
|
if (command.startsWith('/')) {
|
|
@@ -207,18 +212,24 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
207
212
|
description: 'Summarize conversation to free context window',
|
|
208
213
|
async handler(_args, ctx) {
|
|
209
214
|
const messages = ctx.session.conversationManager.getMessagesForLLM();
|
|
210
|
-
// contextWindow
|
|
211
|
-
//
|
|
212
|
-
|
|
215
|
+
// W5.4 (wo803): contextWindow IS reachable from CommandContext — the same
|
|
216
|
+
// call compactConversation() (runtime-services.ts) already makes to scale
|
|
217
|
+
// its own behaviour by window size. Previously hardcoded to 0 here, which
|
|
218
|
+
// silently suppressed buildCompactionPreview()'s capacity-% clause even
|
|
219
|
+
// though the builder has always supported it.
|
|
220
|
+
const contextWindow = ctx.provider.providerRegistry.getContextWindowForModel(
|
|
221
|
+
ctx.provider.providerRegistry.getCurrentModel(),
|
|
222
|
+
);
|
|
213
223
|
const memStore = ctx.session.sessionMemoryStore;
|
|
214
224
|
const pinnedMemoryCount = memStore ? memStore.list().length : 0;
|
|
215
225
|
// Pre-compact preview: honest estimate, clearly labelled.
|
|
216
226
|
const preview = buildCompactionPreview({ messages, contextWindow, pinnedMemoryCount, trigger: 'manual' });
|
|
217
227
|
ctx.print(preview);
|
|
218
|
-
const
|
|
219
|
-
if (
|
|
220
|
-
// Post-compact notice: uses real CompactionEvent figures
|
|
221
|
-
|
|
228
|
+
const result = await compactConversation(ctx);
|
|
229
|
+
if (result) {
|
|
230
|
+
// Post-compact notice: uses real CompactionEvent figures, plus an
|
|
231
|
+
// out-of-band quality-score grade line when one was computed (W5.4/B28).
|
|
232
|
+
ctx.print(buildCompactionAfterNotice({ event: result.event, pinnedMemoryCount, qualityScore: result.qualityScore }));
|
|
222
233
|
} else {
|
|
223
234
|
ctx.print('[Context] Compact complete.');
|
|
224
235
|
}
|
|
@@ -286,6 +297,12 @@ export function registerShellCoreCommands(registry: CommandRegistry): void {
|
|
|
286
297
|
handler(_args, ctx) {
|
|
287
298
|
ctx.session.runtime.debugMode = !ctx.session.runtime.debugMode;
|
|
288
299
|
ctx.print(`Debug mode: ${ctx.session.runtime.debugMode ? 'ON' : 'OFF'}`);
|
|
300
|
+
// Honest quiet counter for direct terminal writes the guard intercepted
|
|
301
|
+
// (routed here instead of spamming the transcript). (UX-B item 1a.)
|
|
302
|
+
const intercepted = ctx.session.runtime.terminalWritesIntercepted ?? 0;
|
|
303
|
+
if (intercepted > 0) {
|
|
304
|
+
ctx.print(`Terminal writes intercepted this session: ${intercepted} (details in the activity log)`);
|
|
305
|
+
}
|
|
289
306
|
},
|
|
290
307
|
});
|
|
291
308
|
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
updateInstalledEcosystemEntry,
|
|
12
12
|
upsertEcosystemCatalogEntry,
|
|
13
13
|
} from '@/runtime/index.ts';
|
|
14
|
-
import {
|
|
14
|
+
import { openModalCommand, requireEcosystemCatalogPaths, requireShellPaths } from './runtime-services.ts';
|
|
15
15
|
|
|
16
16
|
export function registerSkillsRuntimeCommands(registry: CommandRegistry): void {
|
|
17
17
|
registry.register({
|
|
@@ -22,13 +22,7 @@ export function registerSkillsRuntimeCommands(registry: CommandRegistry): void {
|
|
|
22
22
|
async handler(args, ctx) {
|
|
23
23
|
const sub = args[0] ?? 'open';
|
|
24
24
|
if (sub === 'open' || sub === 'panel') {
|
|
25
|
-
|
|
26
|
-
else {
|
|
27
|
-
const panelManager = requirePanelManager(ctx);
|
|
28
|
-
panelManager.open('skills');
|
|
29
|
-
panelManager.show();
|
|
30
|
-
ctx.renderRequest();
|
|
31
|
-
}
|
|
25
|
+
openModalCommand(ctx, 'skills-modal');
|
|
32
26
|
return;
|
|
33
27
|
}
|
|
34
28
|
const skills = await discoverSkills(requireShellPaths(ctx));
|
|
@@ -79,8 +79,8 @@ export function registerSubscriptionRuntimeCommands(registry: CommandRegistry):
|
|
|
79
79
|
usage: '[review|list|providers|inspect <provider>|login <provider> start [--no-browser] [--manual]|finish <code-or-url>|logout <provider>|bundle export <path>|bundle inspect <path>]',
|
|
80
80
|
async handler(args, ctx) {
|
|
81
81
|
const shellPaths = requireShellPaths(ctx);
|
|
82
|
-
if (args.length === 0 && ctx.
|
|
83
|
-
ctx.
|
|
82
|
+
if (args.length === 0 && ctx.openModal) {
|
|
83
|
+
ctx.openModal('subscription-modal'); // W6.1: subscription panel -> config modal
|
|
84
84
|
return;
|
|
85
85
|
}
|
|
86
86
|
const sub = (args[0] ?? 'review').toLowerCase();
|