@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
package/src/panels/diff-panel.ts
CHANGED
|
@@ -8,9 +8,8 @@ import { truncateDisplay, getDisplayWidth } from '../utils/terminal-width.ts';
|
|
|
8
8
|
import { GitService } from '@pellux/goodvibes-sdk/platform/git';
|
|
9
9
|
import { BasePanel } from './base-panel.ts';
|
|
10
10
|
import { UI_TONES, DIFF_TONES } from '../renderer/ui-primitives.ts';
|
|
11
|
-
import { FilePreviewPanel } from './file-preview-panel.ts';
|
|
12
|
-
import type { PanelIntegrationContext } from './types.ts';
|
|
13
11
|
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
12
|
+
import { PanelConfirmOverlay } from './panel-confirm-overlay.ts';
|
|
14
13
|
import {
|
|
15
14
|
buildBodyText,
|
|
16
15
|
buildEmptyState,
|
|
@@ -262,14 +261,12 @@ export class DiffPanel extends BasePanel {
|
|
|
262
261
|
private selectedFile = 0;
|
|
263
262
|
private scrollOffset = 0;
|
|
264
263
|
|
|
265
|
-
/** Set by the 'o' key; consumed by handlePanelIntegrationAction on the next dispatch. */
|
|
266
|
-
private pendingOpenPreview = false;
|
|
267
|
-
|
|
268
264
|
/** One-line confirmation for the 'w'/'h'/'s' self-load hotkeys — otherwise a
|
|
269
265
|
* reload that produces identical content is visually indistinguishable
|
|
270
266
|
* from the keypress doing nothing at all. */
|
|
271
267
|
private hotkeyStatus: string | null = null;
|
|
272
268
|
|
|
269
|
+
public readonly confirmOverlay = new PanelConfirmOverlay(() => this.markDirty()); // armed by a command handler (e.g. /rewind); see panel-confirm-overlay.ts
|
|
273
270
|
constructor(
|
|
274
271
|
workingDirectory: string,
|
|
275
272
|
private readonly requestRender: () => void = () => {},
|
|
@@ -502,6 +499,7 @@ export class DiffPanel extends BasePanel {
|
|
|
502
499
|
}
|
|
503
500
|
|
|
504
501
|
handleInput(key: string): boolean {
|
|
502
|
+
if (this.confirmOverlay.handleInput(key)) return true; // confirm takes priority (git-panel.ts:284-303 precedent)
|
|
505
503
|
switch (key) {
|
|
506
504
|
case 'up': this.scrollUp(); return true;
|
|
507
505
|
case 'down': this.scrollDown(); return true;
|
|
@@ -519,48 +517,17 @@ export class DiffPanel extends BasePanel {
|
|
|
519
517
|
case 'w': this.runHotkeyReload('working tree', () => this.showGitDiff()); return true;
|
|
520
518
|
case 'h': this.runHotkeyReload('HEAD', () => this.showGitDiff('HEAD')); return true;
|
|
521
519
|
case 's': this.runHotkeyReload('staged', () => this.showStagedDiff()); return true;
|
|
522
|
-
case 'o': {
|
|
523
|
-
if (!this.currentEntry()) return false;
|
|
524
|
-
this.pendingOpenPreview = true;
|
|
525
|
-
return true;
|
|
526
|
-
}
|
|
527
520
|
default: return false;
|
|
528
521
|
}
|
|
529
522
|
}
|
|
530
523
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
if (!this.pendingOpenPreview) return false;
|
|
539
|
-
this.pendingOpenPreview = false;
|
|
540
|
-
const entry = this.currentEntry();
|
|
541
|
-
if (!entry) return false;
|
|
542
|
-
|
|
543
|
-
const pm = ctx.panelManager;
|
|
544
|
-
let previewPanel = pm.getPanel('preview');
|
|
545
|
-
if (previewPanel instanceof FilePreviewPanel) {
|
|
546
|
-
const pane = pm.getPaneOf('preview');
|
|
547
|
-
pm.activateById('preview');
|
|
548
|
-
if (pane) pm.focusPane(pane);
|
|
549
|
-
} else {
|
|
550
|
-
const targetPane: 'top' | 'bottom' = pm.isBottomPaneVisible()
|
|
551
|
-
? (pm.getFocusedPane() === 'top' ? 'bottom' : 'top')
|
|
552
|
-
: 'bottom';
|
|
553
|
-
const opened = pm.open('preview', targetPane);
|
|
554
|
-
pm.show();
|
|
555
|
-
pm.focusPane(targetPane);
|
|
556
|
-
previewPanel = opened instanceof FilePreviewPanel ? opened : null;
|
|
557
|
-
}
|
|
558
|
-
if (previewPanel instanceof FilePreviewPanel) {
|
|
559
|
-
previewPanel.openFile(entry.filePath);
|
|
560
|
-
return true;
|
|
561
|
-
}
|
|
562
|
-
return false;
|
|
563
|
-
}
|
|
524
|
+
// W6.1 (the purge): 'o' used to open the currently selected file in the
|
|
525
|
+
// preview panel via a staged pendingOpenPreview flag + a
|
|
526
|
+
// handlePanelIntegrationAction cross-panel hook (the same bridge
|
|
527
|
+
// FileExplorerPanel used). 'preview' is DELETE-disposition with no
|
|
528
|
+
// successor surface (no file-picker-overlay preview to repoint to
|
|
529
|
+
// either — verified), so the key and the hook were removed rather than
|
|
530
|
+
// repointed; diff no longer has an 'o' action.
|
|
564
531
|
|
|
565
532
|
private scrollUp(): void {
|
|
566
533
|
if (this.scrollOffset > 0) {
|
|
@@ -618,6 +585,8 @@ export class DiffPanel extends BasePanel {
|
|
|
618
585
|
return this.trackedRender(() => {
|
|
619
586
|
if (height <= 0 || width <= 0) return [];
|
|
620
587
|
|
|
588
|
+
const confirmLines = this.confirmOverlay.renderLines(width);
|
|
589
|
+
if (confirmLines) return buildPanelWorkspace(width, height, { title: 'Diff Workspace', palette: COLOR, sections: [{ title: 'Confirmation', lines: confirmLines }] });
|
|
621
590
|
if (this.entries.length === 0) {
|
|
622
591
|
return buildPanelWorkspace(width, height, {
|
|
623
592
|
title: 'Diff Workspace',
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EvalRegistry — holds the latest evaluation harness run state.
|
|
3
|
+
*
|
|
4
|
+
* W6.1 (the purge): extracted out of eval-panel.ts. 'eval' was
|
|
5
|
+
* DELETE-disposition (no surviving human surface — the evaluation harness
|
|
6
|
+
* is driven and reviewed via the `/eval` CLI command, input/commands/eval.ts)
|
|
7
|
+
* but this registry is still a live consumer of `/eval run` output, so it
|
|
8
|
+
* survives as a standalone read-model rather than being deleted with the
|
|
9
|
+
* view. See .goodvibes/audit/2026-07-04-wave6-briefs.json (W6.1).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import type { EvalSuiteResult, EvalGateResult } from '@/runtime/index.ts';
|
|
13
|
+
|
|
14
|
+
export class EvalRegistry {
|
|
15
|
+
private _suiteResults: EvalSuiteResult[] = [];
|
|
16
|
+
private _gateResults: EvalGateResult[] = [];
|
|
17
|
+
private _running = false;
|
|
18
|
+
private _lastRunAt: number | null = null;
|
|
19
|
+
private readonly _subscribers = new Set<() => void>();
|
|
20
|
+
|
|
21
|
+
push(result: EvalSuiteResult): void {
|
|
22
|
+
const idx = this._suiteResults.findIndex((r) => r.suite === result.suite);
|
|
23
|
+
if (idx >= 0) {
|
|
24
|
+
this._suiteResults[idx] = result;
|
|
25
|
+
} else {
|
|
26
|
+
this._suiteResults.push(result);
|
|
27
|
+
}
|
|
28
|
+
this._lastRunAt = Date.now();
|
|
29
|
+
this._notify();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
pushGate(gate: EvalGateResult): void {
|
|
33
|
+
const idx = this._gateResults.findIndex((g) => g.suite === gate.suite);
|
|
34
|
+
if (idx >= 0) {
|
|
35
|
+
this._gateResults[idx] = gate;
|
|
36
|
+
} else {
|
|
37
|
+
this._gateResults.push(gate);
|
|
38
|
+
}
|
|
39
|
+
this._notify();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setRunning(running: boolean): void {
|
|
43
|
+
this._running = running;
|
|
44
|
+
this._notify();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
isRunning(): boolean { return this._running; }
|
|
48
|
+
getLastRunAt(): number | null { return this._lastRunAt; }
|
|
49
|
+
getSuiteResults(): EvalSuiteResult[] { return this._suiteResults; }
|
|
50
|
+
getGateResults(): EvalGateResult[] { return this._gateResults; }
|
|
51
|
+
|
|
52
|
+
subscribe(cb: () => void): () => void {
|
|
53
|
+
this._subscribers.add(cb);
|
|
54
|
+
return () => this._subscribers.delete(cb);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private _notify(): void {
|
|
58
|
+
for (const cb of this._subscribers) cb();
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// fleet-deep-link.ts — DEBT-5 item 4.
|
|
3
|
+
//
|
|
4
|
+
// PanelManager.open('fleet', pane, target) hands FleetPanel a
|
|
5
|
+
// PanelDeepLinkTarget (a process id + optional ProcessKind) so a cross-panel
|
|
6
|
+
// jump (the work-plan modal's 'i'/'w' agent/WRFC-chain jumps, the docs
|
|
7
|
+
// modal's tools-tab Enter) can select + reveal a SPECIFIC node instead of
|
|
8
|
+
// just opening Fleet generically. Extracted from fleet-panel.ts (already at
|
|
9
|
+
// the 800-line architecture cap) so the panel stays a thin caller.
|
|
10
|
+
//
|
|
11
|
+
// `kind`, when given, must also match: ProcessNode ids are unique per the
|
|
12
|
+
// SDK's own contract, so this is a cheap extra honesty check, not the
|
|
13
|
+
// primary lookup key. Reveal is "free" once selectedIndex is set —
|
|
14
|
+
// ScrollableListPanel's render-time scroll-window resolution keeps the
|
|
15
|
+
// selected row visible, so FleetPanel.receiveDeepLink does not need its own
|
|
16
|
+
// scroll math.
|
|
17
|
+
//
|
|
18
|
+
// A target that isn't found (pruned, killed, never existed, or a domain —
|
|
19
|
+
// like the docs Tools tab's static tool definitions — that has no
|
|
20
|
+
// corresponding fleet node at all) resolves to -1; the caller degrades
|
|
21
|
+
// honestly (FleetPanel.setError('node no longer present.')) rather than
|
|
22
|
+
// silently landing on an unrelated row.
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
import type { PanelDeepLinkTarget } from './types.ts';
|
|
26
|
+
import type { FleetTreeRow } from './fleet-read-model.ts';
|
|
27
|
+
|
|
28
|
+
/** The row index matching `target`'s id (+ kind, if given), or -1. Pure — no I/O, no mutation. */
|
|
29
|
+
export function resolveFleetDeepLinkIndex(rows: readonly FleetTreeRow[], target: PanelDeepLinkTarget): number {
|
|
30
|
+
return rows.findIndex((row) => row.node.id === target.id && (!target.kind || row.node.kind === target.kind));
|
|
31
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// fleet-panel-format.ts
|
|
3
|
+
//
|
|
4
|
+
// Pure column-layout + cell-formatting helpers for FleetPanel's tree rows.
|
|
5
|
+
// Extracted from fleet-panel.ts (S3b hygiene) to hold that file under the
|
|
6
|
+
// 800-line architecture cap; these are stateless functions the panel's
|
|
7
|
+
// renderItem/renderDetail call, with no `this` dependency.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
import type { ProcessCostState, ProcessUsage } from '@pellux/goodvibes-sdk/platform/runtime/fleet';
|
|
11
|
+
import { formatAgentCost } from './agent-inspector-shared.ts';
|
|
12
|
+
import { DEFAULT_PANEL_PALETTE, type ColumnSpec, type PanelPalette } from './polish.ts';
|
|
13
|
+
import { fleetUsageTokens, hasFleetCost, type FleetStateTone } from './fleet-read-model.ts';
|
|
14
|
+
|
|
15
|
+
// Column widths for the tree row layout. `label` absorbs whatever width is
|
|
16
|
+
// left over after the fixed columns + gaps; on hostile (narrow) widths the
|
|
17
|
+
// trailing columns simply clip (buildAlignedRow/buildSelectablePanelLine stop
|
|
18
|
+
// writing once a cell would overflow the row) rather than throwing or
|
|
19
|
+
// wrapping — the tree stays readable, just denser.
|
|
20
|
+
const KIND_W = 8;
|
|
21
|
+
const ELAPSED_W = 7;
|
|
22
|
+
const TOKENS_W = 7;
|
|
23
|
+
const COST_W = 8;
|
|
24
|
+
const ACTIVITY_W = 20;
|
|
25
|
+
const GAP = 1;
|
|
26
|
+
const FIXED_W = 1 /* glyph */ + KIND_W + ELAPSED_W + TOKENS_W + COST_W + ACTIVITY_W + GAP * 6;
|
|
27
|
+
|
|
28
|
+
export function planColumns(width: number): ColumnSpec[] {
|
|
29
|
+
const labelWidth = Math.max(10, width - FIXED_W);
|
|
30
|
+
return [
|
|
31
|
+
{ width: 1 },
|
|
32
|
+
{ width: KIND_W },
|
|
33
|
+
{ width: labelWidth },
|
|
34
|
+
{ width: ELAPSED_W, align: 'right' },
|
|
35
|
+
{ width: TOKENS_W, align: 'right' },
|
|
36
|
+
{ width: COST_W, align: 'right' },
|
|
37
|
+
{ width: ACTIVITY_W },
|
|
38
|
+
];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function toneColor(tone: FleetStateTone, palette: PanelPalette): string {
|
|
42
|
+
switch (tone) {
|
|
43
|
+
case 'active': return palette.info ?? DEFAULT_PANEL_PALETTE.info;
|
|
44
|
+
case 'success': return palette.good ?? DEFAULT_PANEL_PALETTE.good;
|
|
45
|
+
case 'failure': return palette.bad ?? DEFAULT_PANEL_PALETTE.bad;
|
|
46
|
+
case 'warn': return palette.warn ?? DEFAULT_PANEL_PALETTE.warn;
|
|
47
|
+
case 'muted': return palette.dim;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function formatFleetTokens(usage: ProcessUsage | undefined): string {
|
|
52
|
+
const total = fleetUsageTokens(usage);
|
|
53
|
+
if (total === null) return 'n/a';
|
|
54
|
+
return total >= 1000 ? `${(total / 1000).toFixed(1)}k` : String(total);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Honest cost display: never a fabricated $0.00 — 'unpriced' when costState says so. */
|
|
58
|
+
export function formatFleetCost(costUsd: number | null | undefined, costState: ProcessCostState): string {
|
|
59
|
+
if (!hasFleetCost(costUsd, costState)) return 'unpriced';
|
|
60
|
+
const formatted = formatAgentCost(costUsd as number);
|
|
61
|
+
return costState === 'estimated' ? `~${formatted}` : formatted;
|
|
62
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// fleet-panel-worktree-detail.ts
|
|
3
|
+
//
|
|
4
|
+
// NET-NEW helper (not moved code — it was authored here because fleet-panel.ts
|
|
5
|
+
// sits at the architecture check's 800-line cap, scripts/check-architecture.ts):
|
|
6
|
+
// a single pure helper for the Fleet panel's per-work-item detail view, so a
|
|
7
|
+
// new panel feature doesn't have to fight that cap inline.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
|
|
10
|
+
import type { WorkItem } from '@pellux/goodvibes-sdk/platform/orchestration';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Per-item worktree-isolation detail text for the Fleet panel's expanded
|
|
14
|
+
* node detail (fleet-panel.ts renderDetail), or null for a shared-isolation
|
|
15
|
+
* item (or any node that isn't a work item). Inferred from the item's OWN
|
|
16
|
+
* fields (worktreePath/worktreeBranch/mergeState) rather than a
|
|
17
|
+
* workstream-level flag — adaptWorkItem's ProcessNode.raw carries
|
|
18
|
+
* `{ item, workstreamId }`, not the full Workstream, and these fields are
|
|
19
|
+
* set ONLY when the owning workstream's isolation is 'worktree'
|
|
20
|
+
* (engine.ts/worktree-isolation.ts, SDK), so they are a reliable
|
|
21
|
+
* self-contained signal with no fleet-adapter change needed.
|
|
22
|
+
*/
|
|
23
|
+
export function formatWorkItemIsolationDetail(item: WorkItem): string | null {
|
|
24
|
+
const isolated = item.worktreePath !== undefined || item.worktreeBranch !== undefined || item.mergeState !== undefined;
|
|
25
|
+
if (!isolated) return null;
|
|
26
|
+
switch (item.mergeState) {
|
|
27
|
+
case 'merged':
|
|
28
|
+
// Papercut sweep item 3: worktree-isolation items whose integration had
|
|
29
|
+
// no changes to merge (mergeState 'merged', mergeHash undefined — a
|
|
30
|
+
// documented cosmetic case, not an error) used to read as a bare/awkward
|
|
31
|
+
// "merged (nothing to merge)". "merged (no changes)" says the same thing
|
|
32
|
+
// in the same shape as the other merge-state phrases below.
|
|
33
|
+
return item.mergeHash ? `worktree — merged ${item.mergeHash.slice(0, 12)}` : 'worktree — merged (no changes)';
|
|
34
|
+
case 'conflict':
|
|
35
|
+
return 'worktree — merge-conflict (kept for inspection)';
|
|
36
|
+
case 'pending':
|
|
37
|
+
return 'worktree — merge pending';
|
|
38
|
+
case 'n-a':
|
|
39
|
+
default:
|
|
40
|
+
return item.worktreeKept ? 'worktree — kept' : 'worktree — not yet integrated';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** `node.raw` for a 'work-item' ProcessNode is `{ item, workstreamId }` (unknown to the panel's own types) — this narrows without fleet-panel.ts needing its own WorkItem import at the call site. Non-work-item nodes (raw is undefined/some other shape) fall through to null. */
|
|
45
|
+
export function formatWorkItemIsolationDetailFromRaw(raw: unknown): string | null {
|
|
46
|
+
const item = (raw as { item?: WorkItem } | undefined)?.item;
|
|
47
|
+
return item ? formatWorkItemIsolationDetail(item) : null;
|
|
48
|
+
}
|