@pellux/goodvibes-agent 0.1.117 → 1.0.1
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 +20 -4
- package/README.md +35 -14
- package/bin/goodvibes-agent.ts +16 -2
- package/dist/package/main.js +176093 -171065
- package/docs/README.md +11 -5
- package/docs/channels-remote-and-api.md +50 -0
- package/docs/connected-host.md +3 -3
- package/docs/getting-started.md +29 -15
- package/docs/knowledge-artifacts-and-multimodal.md +91 -0
- package/docs/project-planning.md +79 -0
- package/docs/providers-and-routing.md +46 -0
- package/docs/release-and-publishing.md +44 -9
- package/docs/tools-and-commands.md +123 -0
- package/docs/voice-and-live-tts.md +51 -0
- package/package.json +2 -5
- package/src/agent/channel-delivery.ts +201 -0
- package/src/agent/media-generation.ts +159 -0
- package/src/agent/memory-prompt.ts +0 -1
- package/src/agent/note-registry.ts +329 -0
- package/src/agent/operator-actions.ts +343 -0
- package/src/agent/persona-registry.ts +15 -14
- package/src/agent/record-labels.ts +107 -0
- package/src/agent/reminder-schedule-format.ts +33 -24
- package/src/agent/reminder-schedule.ts +26 -25
- package/src/agent/routine-registry.ts +13 -12
- package/src/agent/routine-schedule-args.ts +2 -1
- package/src/agent/routine-schedule-format.ts +77 -53
- package/src/agent/routine-schedule-promotion.ts +34 -32
- package/src/agent/routine-schedule-receipts.ts +28 -26
- package/src/agent/runtime-profile-starters.ts +2 -2
- package/src/agent/runtime-profile.ts +18 -17
- package/src/agent/skill-registry.ts +25 -24
- package/src/cli/agent-knowledge-args.ts +5 -1
- package/src/cli/agent-knowledge-command.ts +39 -33
- package/src/cli/agent-knowledge-format.ts +80 -67
- package/src/cli/agent-knowledge-methods.ts +1 -1
- package/src/cli/agent-knowledge-runtime.ts +32 -26
- package/src/cli/bundle-command.ts +13 -8
- package/src/cli/config-overrides.ts +37 -36
- package/src/cli/external-runtime.ts +10 -4
- package/src/cli/help.ts +29 -11
- package/src/cli/local-library-command.ts +159 -73
- package/src/cli/management-commands.ts +98 -62
- package/src/cli/management.ts +52 -26
- package/src/cli/memory-command.ts +66 -32
- package/src/cli/parser.ts +37 -24
- package/src/cli/profiles-command.ts +52 -35
- package/src/cli/provider-auth-routes.ts +2 -1
- package/src/cli/routines-command.ts +59 -39
- package/src/cli/service-posture.ts +6 -6
- package/src/cli/status.ts +46 -121
- package/src/core/conversation-message-snapshot.ts +131 -0
- package/src/input/agent-workspace-activation.ts +33 -7
- package/src/input/agent-workspace-basic-command-editor-submission.ts +7 -3
- package/src/input/agent-workspace-basic-command-editors.ts +30 -10
- package/src/input/agent-workspace-categories.ts +276 -64
- package/src/input/agent-workspace-channel-command-editor-submission.ts +34 -0
- package/src/input/agent-workspace-channel-command-editors.ts +23 -5
- package/src/input/agent-workspace-channels.ts +35 -2
- package/src/input/agent-workspace-command-editor.ts +18 -2
- package/src/input/agent-workspace-config-reader.ts +16 -0
- package/src/input/agent-workspace-delegation-editor-submission.ts +1 -1
- package/src/input/agent-workspace-editors.ts +140 -2
- package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
- package/src/input/agent-workspace-knowledge-url-editor.ts +4 -11
- package/src/input/agent-workspace-learned-behavior.ts +2 -2
- package/src/input/agent-workspace-library-command-editor-submission.ts +1 -1
- package/src/input/agent-workspace-library-command-editors.ts +2 -2
- package/src/input/agent-workspace-local-operations.ts +218 -0
- package/src/input/agent-workspace-local-selection.ts +75 -0
- package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
- package/src/input/agent-workspace-media-command-editors.ts +27 -0
- package/src/input/agent-workspace-memory-command-editors.ts +1 -1
- package/src/input/agent-workspace-memory-editor.ts +2 -2
- package/src/input/agent-workspace-navigation.ts +38 -2
- package/src/input/agent-workspace-notify-editor-submission.ts +16 -2
- package/src/input/agent-workspace-operations-command-editor-submission.ts +63 -1
- package/src/input/agent-workspace-operations-command-editors.ts +80 -3
- package/src/input/agent-workspace-panel-route.ts +43 -0
- package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
- package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
- package/src/input/agent-workspace-search.ts +169 -0
- package/src/input/agent-workspace-setup.ts +22 -11
- package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +6 -6
- package/src/input/agent-workspace-skill-bundle-command-editors.ts +10 -10
- package/src/input/agent-workspace-snapshot.ts +112 -13
- package/src/input/agent-workspace-task-command-editors.ts +4 -4
- package/src/input/agent-workspace-token.ts +18 -2
- package/src/input/agent-workspace-types.ts +92 -4
- package/src/input/agent-workspace-voice-media.ts +3 -6
- package/src/input/agent-workspace-web-research-editor.ts +104 -0
- package/src/input/agent-workspace.ts +136 -208
- package/src/input/command-registry.ts +4 -1
- package/src/input/commands/agent-local-library-args.ts +52 -0
- package/src/input/commands/agent-runtime-profile-runtime.ts +45 -41
- package/src/input/commands/agent-skills-runtime.ts +87 -99
- package/src/input/commands/agent-workspace-runtime.ts +23 -7
- package/src/input/commands/brief-runtime.ts +25 -24
- package/src/input/commands/channels-runtime.ts +145 -31
- package/src/input/commands/delegation-runtime.ts +29 -23
- package/src/input/commands/experience-runtime.ts +6 -4
- package/src/input/commands/guidance-runtime.ts +4 -4
- package/src/input/commands/health-runtime.ts +140 -115
- package/src/input/commands/knowledge.ts +57 -56
- package/src/input/commands/local-provider-runtime.ts +36 -18
- package/src/input/commands/local-runtime.ts +138 -16
- package/src/input/commands/local-setup-review.ts +7 -7
- package/src/input/commands/mcp-runtime.ts +118 -50
- package/src/input/commands/notify-runtime.ts +38 -9
- package/src/input/commands/operator-actions-runtime.ts +138 -0
- package/src/input/commands/operator-runtime.ts +6 -17
- package/src/input/commands/personas-runtime.ts +49 -59
- package/src/input/commands/planning-runtime.ts +1 -1
- package/src/input/commands/platform-access-runtime.ts +29 -29
- package/src/input/commands/provider-accounts-runtime.ts +60 -39
- package/src/input/commands/qrcode-runtime.ts +45 -6
- package/src/input/commands/recall-bundle.ts +11 -11
- package/src/input/commands/recall-capture.ts +13 -11
- package/src/input/commands/recall-query.ts +29 -21
- package/src/input/commands/recall-review.ts +2 -1
- package/src/input/commands/routines-runtime.ts +63 -72
- package/src/input/commands/schedule-runtime.ts +33 -20
- package/src/input/commands/security-runtime.ts +4 -4
- package/src/input/commands/session-content.ts +80 -78
- package/src/input/commands/session-workflow.ts +132 -93
- package/src/input/commands/session.ts +3 -174
- package/src/input/commands/shell-core.ts +32 -17
- package/src/input/commands/subscription-runtime.ts +53 -179
- package/src/input/commands/tasks-runtime.ts +20 -20
- package/src/input/commands/work-plan-runtime.ts +33 -8
- package/src/input/commands.ts +2 -2
- package/src/input/feed-context-factory.ts +2 -1
- package/src/input/file-picker.ts +3 -2
- package/src/input/handler-command-route.ts +4 -7
- package/src/input/handler-content-actions.ts +89 -1
- package/src/input/handler-feed-routes.ts +19 -12
- package/src/input/handler-feed.ts +6 -3
- package/src/input/handler-interactions.ts +7 -5
- package/src/input/handler-modal-stack.ts +3 -3
- package/src/input/handler-onboarding.ts +24 -80
- package/src/input/handler-shortcuts.ts +15 -4
- package/src/input/handler.ts +47 -17
- package/src/input/input-history.ts +5 -6
- package/src/input/keybindings.ts +22 -11
- package/src/input/onboarding/onboarding-wizard-apply.ts +13 -0
- package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
- package/src/input/onboarding/onboarding-wizard-operator-steps.ts +147 -57
- package/src/input/onboarding/onboarding-wizard-steps.ts +46 -29
- package/src/input/onboarding/onboarding-wizard-types.ts +3 -1
- package/src/input/onboarding/onboarding-wizard.ts +68 -0
- package/src/input/profile-picker-modal.ts +31 -12
- package/src/input/session-picker-modal.ts +22 -4
- package/src/input/settings-modal-behavior.ts +0 -3
- package/src/input/settings-modal-subscriptions.ts +3 -3
- package/src/input/settings-modal-types.ts +2 -13
- package/src/input/settings-modal.ts +6 -52
- package/src/input/submission-intent.ts +0 -1
- package/src/input/submission-router.ts +3 -3
- package/src/main.ts +18 -8
- package/src/panels/approval-panel.ts +8 -8
- package/src/panels/automation-control-panel.ts +2 -2
- package/src/panels/base-panel.ts +1 -1
- package/src/panels/builtin/agent.ts +1 -1
- package/src/panels/builtin/operations.ts +1 -10
- package/src/panels/builtin/session.ts +9 -9
- package/src/panels/builtin/shared.ts +2 -2
- package/src/panels/cost-tracker-panel.ts +1 -1
- package/src/panels/docs-panel.ts +5 -3
- package/src/panels/index.ts +0 -1
- package/src/panels/knowledge-panel.ts +6 -5
- package/src/panels/memory-panel.ts +7 -6
- package/src/panels/panel-list-panel.ts +36 -80
- package/src/panels/project-planning-panel.ts +18 -11
- package/src/panels/provider-account-snapshot.ts +51 -25
- package/src/panels/provider-accounts-panel.ts +33 -18
- package/src/panels/provider-health-domains.ts +45 -4
- package/src/panels/provider-health-panel.ts +5 -4
- package/src/panels/qr-panel.ts +1 -1
- package/src/panels/schedule-panel.ts +9 -17
- package/src/panels/security-panel.ts +8 -8
- package/src/panels/session-browser-panel.ts +10 -10
- package/src/panels/subscription-panel.ts +3 -3
- package/src/panels/system-messages-panel.ts +1 -1
- package/src/panels/tasks-panel.ts +20 -13
- package/src/panels/tool-inspector-panel.ts +19 -12
- package/src/panels/work-plan-panel.ts +5 -5
- package/src/planning/project-planning-coordinator.ts +1 -1
- package/src/provider-auth-route-display.ts +9 -0
- package/src/renderer/agent-workspace-style.ts +34 -0
- package/src/renderer/agent-workspace.ts +228 -52
- package/src/renderer/autocomplete-overlay.ts +25 -6
- package/src/renderer/bookmark-modal.ts +19 -4
- package/src/renderer/buffer.ts +4 -2
- package/src/renderer/context-inspector.ts +50 -13
- package/src/renderer/diff.ts +1 -1
- package/src/renderer/file-picker-overlay.ts +19 -6
- package/src/renderer/help-overlay.ts +106 -33
- package/src/renderer/history-search-overlay.ts +19 -4
- package/src/renderer/live-tail-modal.ts +27 -5
- package/src/renderer/mcp-workspace.ts +164 -50
- package/src/renderer/model-picker-overlay.ts +58 -2
- package/src/renderer/model-workspace.ts +104 -20
- package/src/renderer/process-modal.ts +27 -6
- package/src/renderer/profile-picker-modal.ts +20 -4
- package/src/renderer/search-overlay.ts +25 -5
- package/src/renderer/selection-modal-overlay.ts +46 -14
- package/src/renderer/session-picker-modal.ts +18 -1
- package/src/renderer/settings-modal-helpers.ts +2 -40
- package/src/renderer/settings-modal.ts +83 -50
- package/src/renderer/tool-call.ts +20 -11
- package/src/runtime/agent-runtime-events.ts +6 -6
- package/src/runtime/bootstrap-command-context.ts +7 -1
- package/src/runtime/bootstrap-command-parts.ts +9 -7
- package/src/runtime/bootstrap-core.ts +19 -1
- package/src/runtime/bootstrap-hook-bridge.ts +7 -18
- package/src/runtime/bootstrap-shell.ts +4 -4
- package/src/runtime/bootstrap.ts +31 -22
- package/src/runtime/connected-host-auth.ts +7 -2
- package/src/runtime/diagnostics/panels/index.ts +2 -2
- package/src/runtime/diagnostics/panels/policy.ts +7 -7
- package/src/runtime/index.ts +2 -1
- package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
- package/src/runtime/onboarding/apply.ts +80 -79
- package/src/runtime/onboarding/derivation.ts +5 -8
- package/src/runtime/onboarding/snapshot.ts +0 -15
- package/src/runtime/onboarding/types.ts +8 -19
- package/src/runtime/onboarding/verify.ts +32 -10
- package/src/runtime/operator-token-cleanup.ts +1 -1
- package/src/runtime/services.ts +91 -22
- package/src/runtime/store/selectors/index.ts +3 -3
- package/src/runtime/store/state.ts +1 -4
- package/src/runtime/surface-feature-flags.ts +41 -6
- package/src/runtime/ui-read-models.ts +3 -4
- package/src/runtime/ui-services.ts +6 -6
- package/src/shell/blocking-input.ts +2 -1
- package/src/shell/ui-openers.ts +3 -13
- package/src/tools/agent-analysis-registry-policy.ts +0 -1
- package/src/tools/agent-channel-send-tool.ts +133 -0
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
- package/src/tools/agent-knowledge-tool.ts +170 -0
- package/src/tools/agent-local-registry-tool.ts +269 -69
- package/src/tools/agent-media-generate-tool.ts +133 -0
- package/src/tools/agent-notify-tool.ts +143 -0
- package/src/tools/agent-operator-action-tool.ts +137 -0
- package/src/tools/agent-operator-briefing-tool.ts +217 -0
- package/src/tools/agent-reminder-schedule-tool.ts +237 -0
- package/src/tools/agent-tool-policy-guard.ts +8 -8
- package/src/tools/agent-work-plan-tool.ts +256 -0
- package/src/version.ts +1 -1
- package/src/input/commands/policy-dispatch.ts +0 -339
- package/src/input/commands/policy.ts +0 -13
- package/src/panels/panel-picker.ts +0 -105
- package/src/panels/policy-panel.ts +0 -308
- package/src/renderer/panel-picker-overlay.ts +0 -202
|
@@ -1,308 +0,0 @@
|
|
|
1
|
-
import type { Line } from '../types/grid.ts';
|
|
2
|
-
import { createEmptyLine } from '../types/grid.ts';
|
|
3
|
-
import { BasePanel } from './base-panel.ts';
|
|
4
|
-
import type { PolicyRuntimeState } from '@/runtime/index.ts';
|
|
5
|
-
import type { PolicyPanelSnapshot } from '../runtime/diagnostics/panels/policy.ts';
|
|
6
|
-
import {
|
|
7
|
-
buildPanelLine,
|
|
8
|
-
buildPanelWorkspace,
|
|
9
|
-
resolveScrollablePanelSection,
|
|
10
|
-
DEFAULT_PANEL_PALETTE,
|
|
11
|
-
} from './polish.ts';
|
|
12
|
-
|
|
13
|
-
const C = {
|
|
14
|
-
...DEFAULT_PANEL_PALETTE,
|
|
15
|
-
header: '#94a3b8',
|
|
16
|
-
headerBg: '#1e293b',
|
|
17
|
-
label: '#64748b',
|
|
18
|
-
value: '#e2e8f0',
|
|
19
|
-
dim: '#475569',
|
|
20
|
-
ok: '#22c55e',
|
|
21
|
-
warn: '#eab308',
|
|
22
|
-
error: '#ef4444',
|
|
23
|
-
info: '#38bdf8',
|
|
24
|
-
empty: '#334155',
|
|
25
|
-
} as const;
|
|
26
|
-
|
|
27
|
-
function fmtTime(value: string | undefined): string {
|
|
28
|
-
if (!value) return 'n/a';
|
|
29
|
-
return value.replace('T', ' ').slice(0, 19);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function fmtRate(value: number | undefined): string {
|
|
33
|
-
if (value === undefined) return 'n/a';
|
|
34
|
-
return `${(value * 100).toFixed(1)}%`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function gateColor(status: string | undefined): string {
|
|
38
|
-
switch (status) {
|
|
39
|
-
case 'allowed':
|
|
40
|
-
return C.ok;
|
|
41
|
-
case 'blocked':
|
|
42
|
-
return C.error;
|
|
43
|
-
case 'no_data':
|
|
44
|
-
return C.warn;
|
|
45
|
-
default:
|
|
46
|
-
return C.dim;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export class PolicyPanel extends BasePanel {
|
|
51
|
-
private readonly _state: PolicyRuntimeState;
|
|
52
|
-
private readonly _unsub: (() => void) | null;
|
|
53
|
-
private _scrollOffset = 0;
|
|
54
|
-
|
|
55
|
-
public constructor(state: PolicyRuntimeState) {
|
|
56
|
-
super('policy', 'Policy', 'U', 'monitoring');
|
|
57
|
-
this._state = state;
|
|
58
|
-
this._unsub = state.subscribe(() => this.markDirty());
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
public override onActivate(): void {
|
|
62
|
-
super.onActivate();
|
|
63
|
-
this._scrollOffset = 0;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
public override onDestroy(): void {
|
|
67
|
-
this._unsub?.();
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
public handleInput(key: string): boolean {
|
|
71
|
-
if (key === 'up' || key === 'k') {
|
|
72
|
-
this._scrollOffset = Math.max(0, this._scrollOffset - 1);
|
|
73
|
-
this.markDirty();
|
|
74
|
-
return true;
|
|
75
|
-
}
|
|
76
|
-
if (key === 'down' || key === 'j') {
|
|
77
|
-
this._scrollOffset++;
|
|
78
|
-
this.markDirty();
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
if (key === 'r') {
|
|
82
|
-
this._state.recordTrendEntry();
|
|
83
|
-
this.markDirty();
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
return false;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
public render(width: number, height: number): Line[] {
|
|
90
|
-
this.needsRender = false;
|
|
91
|
-
const snapshot = this._state.getSnapshot();
|
|
92
|
-
const content = this._buildContent(width, snapshot);
|
|
93
|
-
const governanceSection = resolveScrollablePanelSection(width, height, {
|
|
94
|
-
footerLines: [buildPanelLine(width, [[' Up/Down scroll r record divergence trend snapshot', C.dim]])],
|
|
95
|
-
palette: C,
|
|
96
|
-
section: {
|
|
97
|
-
title: 'Governance',
|
|
98
|
-
scrollableLines: content,
|
|
99
|
-
scrollOffset: this._scrollOffset,
|
|
100
|
-
minRows: 4,
|
|
101
|
-
},
|
|
102
|
-
});
|
|
103
|
-
this._scrollOffset = governanceSection.scrollOffset;
|
|
104
|
-
const lines = buildPanelWorkspace(width, height, {
|
|
105
|
-
title: 'Policy And Governance',
|
|
106
|
-
sections: [governanceSection.section],
|
|
107
|
-
footerLines: [buildPanelLine(width, [[' Up/Down scroll r record divergence trend snapshot', C.dim]])],
|
|
108
|
-
palette: C,
|
|
109
|
-
});
|
|
110
|
-
while (lines.length < height) {
|
|
111
|
-
lines.push(createEmptyLine(width));
|
|
112
|
-
}
|
|
113
|
-
return lines.slice(0, height);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
private _buildContent(width: number, snapshot: PolicyPanelSnapshot): Line[] {
|
|
117
|
-
const lines: Line[] = [];
|
|
118
|
-
const current = snapshot.current;
|
|
119
|
-
const candidate = snapshot.candidate;
|
|
120
|
-
const divergence = snapshot.divergence;
|
|
121
|
-
const permissionAudit = snapshot.recentPermissionAudit;
|
|
122
|
-
const lintFindings = snapshot.lintFindings;
|
|
123
|
-
const simulationSummary = snapshot.lastSimulationSummary;
|
|
124
|
-
const preflightReview = snapshot.lastPreflightReview;
|
|
125
|
-
|
|
126
|
-
if (!current && !candidate) {
|
|
127
|
-
lines.push(buildPanelLine(width, [[' No policy bundles loaded. Use /policy load to begin.', C.empty]]));
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (current) {
|
|
131
|
-
lines.push(buildPanelLine(width, [[' Current', C.label]]));
|
|
132
|
-
lines.push(buildPanelLine(width, [
|
|
133
|
-
[' Bundle: ', C.label],
|
|
134
|
-
[current.bundle.bundleId, C.value],
|
|
135
|
-
[' State: ', C.label],
|
|
136
|
-
[current.state, C.info],
|
|
137
|
-
]));
|
|
138
|
-
lines.push(buildPanelLine(width, [
|
|
139
|
-
[' Loaded: ', C.label],
|
|
140
|
-
[fmtTime(current.loadedAt), C.dim],
|
|
141
|
-
[' Active: ', C.label],
|
|
142
|
-
[fmtTime(current.activatedAt), C.dim],
|
|
143
|
-
]));
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (candidate) {
|
|
147
|
-
lines.push(buildPanelLine(width, [[' Candidate', C.label]]));
|
|
148
|
-
lines.push(buildPanelLine(width, [
|
|
149
|
-
[' Bundle: ', C.label],
|
|
150
|
-
[candidate.bundle.bundleId, C.value],
|
|
151
|
-
[' State: ', C.label],
|
|
152
|
-
[candidate.state, C.info],
|
|
153
|
-
]));
|
|
154
|
-
lines.push(buildPanelLine(width, [
|
|
155
|
-
[' Loaded: ', C.label],
|
|
156
|
-
[fmtTime(candidate.loadedAt), C.dim],
|
|
157
|
-
[' Rules: ', C.label],
|
|
158
|
-
[String(candidate.rules.length), C.value],
|
|
159
|
-
]));
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (snapshot.diff) {
|
|
163
|
-
lines.push(buildPanelLine(width, [[' Diff', C.label]]));
|
|
164
|
-
lines.push(buildPanelLine(width, [
|
|
165
|
-
[' Changes: ', C.label],
|
|
166
|
-
[String(snapshot.diff.totalChanges), C.value],
|
|
167
|
-
[' Added: ', C.label],
|
|
168
|
-
[String(snapshot.diff.added.length), C.ok],
|
|
169
|
-
[' Removed: ', C.label],
|
|
170
|
-
[String(snapshot.diff.removed.length), C.error],
|
|
171
|
-
[' Changed: ', C.label],
|
|
172
|
-
[String(snapshot.diff.changed.length), C.warn],
|
|
173
|
-
]));
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (divergence) {
|
|
177
|
-
lines.push(buildPanelLine(width, [[' Governance Gate', C.label]]));
|
|
178
|
-
lines.push(buildPanelLine(width, [
|
|
179
|
-
[' Mode: ', C.label],
|
|
180
|
-
[divergence.mode, C.info],
|
|
181
|
-
[' Gate: ', C.label],
|
|
182
|
-
[divergence.gate.status, gateColor(divergence.gate.status)],
|
|
183
|
-
[' Divergence: ', C.label],
|
|
184
|
-
[fmtRate(divergence.gate.divergenceRate ?? divergence.report.overall.divergenceRate), C.value],
|
|
185
|
-
]));
|
|
186
|
-
lines.push(buildPanelLine(width, [
|
|
187
|
-
[' Evaluations: ', C.label],
|
|
188
|
-
[String(divergence.report.overall.totalEvaluations), C.value],
|
|
189
|
-
[' Trend points: ', C.label],
|
|
190
|
-
[String(divergence.trend.length), C.value],
|
|
191
|
-
]));
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if (snapshot.history.length > 0) {
|
|
195
|
-
lines.push(buildPanelLine(width, [[' History', C.label]]));
|
|
196
|
-
for (const version of snapshot.history.slice(0, 5)) {
|
|
197
|
-
lines.push(buildPanelLine(width, [
|
|
198
|
-
[' ', C.label],
|
|
199
|
-
[version.bundle.bundleId, C.value],
|
|
200
|
-
[' ', C.label],
|
|
201
|
-
[version.state, C.dim],
|
|
202
|
-
[' ', C.label],
|
|
203
|
-
[fmtTime(version.activatedAt ?? version.loadedAt), C.dim],
|
|
204
|
-
]));
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (permissionAudit.length > 0) {
|
|
209
|
-
lines.push(buildPanelLine(width, [[' Permission Audit', C.label]]));
|
|
210
|
-
for (const entry of permissionAudit.slice(0, 5)) {
|
|
211
|
-
const outcome = entry.approved === undefined ? 'pending' : entry.approved ? 'approved' : 'denied';
|
|
212
|
-
const outcomeColor = entry.approved === undefined ? C.warn : entry.approved ? C.ok : C.error;
|
|
213
|
-
lines.push(buildPanelLine(width, [
|
|
214
|
-
[' ', C.label],
|
|
215
|
-
[entry.tool, C.value],
|
|
216
|
-
[' ', C.label],
|
|
217
|
-
[entry.riskLevel.toUpperCase(), outcomeColor],
|
|
218
|
-
[' ', C.label],
|
|
219
|
-
[outcome, outcomeColor],
|
|
220
|
-
]));
|
|
221
|
-
lines.push(buildPanelLine(width, [
|
|
222
|
-
[' ', C.label],
|
|
223
|
-
[entry.summary.slice(0, Math.max(0, width - 6)), C.dim],
|
|
224
|
-
]));
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
if (lintFindings.length > 0) {
|
|
229
|
-
lines.push(buildPanelLine(width, [[' Policy Lint', C.label]]));
|
|
230
|
-
for (const finding of lintFindings.slice(0, 5)) {
|
|
231
|
-
const color = finding.severity === 'error' ? C.error : finding.severity === 'warn' ? C.warn : C.info;
|
|
232
|
-
lines.push(buildPanelLine(width, [
|
|
233
|
-
[' ', C.label],
|
|
234
|
-
[finding.severity.toUpperCase(), color],
|
|
235
|
-
[' ', C.label],
|
|
236
|
-
[finding.message.slice(0, Math.max(0, width - 14)), color],
|
|
237
|
-
]));
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
if (!preflightReview) {
|
|
242
|
-
if (!current && !candidate && !divergence && snapshot.history.length === 0 && permissionAudit.length === 0 && lintFindings.length === 0 && !simulationSummary) {
|
|
243
|
-
lines.push(buildPanelLine(width, [[' Preflight Review', C.label]]));
|
|
244
|
-
lines.push(buildPanelLine(width, [[' No proactive preflight review recorded yet.', C.empty]]));
|
|
245
|
-
}
|
|
246
|
-
} else {
|
|
247
|
-
lines.push(buildPanelLine(width, [[' Preflight Review', C.label]]));
|
|
248
|
-
const statusColor =
|
|
249
|
-
preflightReview.status === 'pass'
|
|
250
|
-
? C.ok
|
|
251
|
-
: preflightReview.status === 'warn'
|
|
252
|
-
? C.warn
|
|
253
|
-
: C.error;
|
|
254
|
-
lines.push(buildPanelLine(width, [
|
|
255
|
-
[' Status: ', C.label],
|
|
256
|
-
[preflightReview.status.toUpperCase(), statusColor],
|
|
257
|
-
[' Issues: ', C.label],
|
|
258
|
-
[String(preflightReview.issueCount), C.value],
|
|
259
|
-
[' Generated: ', C.label],
|
|
260
|
-
[fmtTime(preflightReview.generatedAt), C.dim],
|
|
261
|
-
]));
|
|
262
|
-
lines.push(buildPanelLine(width, [
|
|
263
|
-
[' ', C.label],
|
|
264
|
-
[preflightReview.summary.slice(0, Math.max(0, width - 2)), C.dim],
|
|
265
|
-
]));
|
|
266
|
-
for (const issue of preflightReview.issues.slice(0, 4)) {
|
|
267
|
-
const issueColor = issue.severity === 'error' ? C.error : issue.severity === 'warn' ? C.warn : C.info;
|
|
268
|
-
lines.push(buildPanelLine(width, [
|
|
269
|
-
[' ', C.label],
|
|
270
|
-
[issue.severity.toUpperCase(), issueColor],
|
|
271
|
-
[' ', C.label],
|
|
272
|
-
[issue.message.slice(0, Math.max(0, width - 14)), issueColor],
|
|
273
|
-
]));
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
if (!simulationSummary) {
|
|
278
|
-
if (!current && !candidate && !divergence && snapshot.history.length === 0 && permissionAudit.length === 0 && lintFindings.length === 0 && !preflightReview) {
|
|
279
|
-
lines.push(buildPanelLine(width, [[' Simulation Samples', C.label]]));
|
|
280
|
-
lines.push(buildPanelLine(width, [[' No concrete simulation samples recorded yet.', C.empty]]));
|
|
281
|
-
}
|
|
282
|
-
} else {
|
|
283
|
-
lines.push(buildPanelLine(width, [[' Simulation Samples', C.label]]));
|
|
284
|
-
lines.push(buildPanelLine(width, [
|
|
285
|
-
[' Mode: ', C.label],
|
|
286
|
-
[simulationSummary.mode, C.info],
|
|
287
|
-
[' Diverged: ', C.label],
|
|
288
|
-
[`${simulationSummary.divergentScenarios}/${simulationSummary.totalScenarios}`, simulationSummary.divergentScenarios > 0 ? C.warn : C.ok],
|
|
289
|
-
[' Allowed(actual/sim): ', C.label],
|
|
290
|
-
[`${simulationSummary.allowedByActual}/${simulationSummary.allowedBySimulated}`, C.value],
|
|
291
|
-
]));
|
|
292
|
-
for (const result of simulationSummary.results.slice(0, 4)) {
|
|
293
|
-
const color = result.diverged ? C.warn : (result.authoritativeDecision.allowed ? C.ok : C.error);
|
|
294
|
-
lines.push(buildPanelLine(width, [
|
|
295
|
-
[' ', C.label],
|
|
296
|
-
[result.scenario.label.slice(0, Math.max(0, width - 40)), C.value],
|
|
297
|
-
[' ', C.label],
|
|
298
|
-
[(result.authoritativeDecision.allowed ? 'allow' : 'deny').toUpperCase(), color],
|
|
299
|
-
[' ', C.label],
|
|
300
|
-
[result.diverged ? (result.divergenceType ?? 'diverged') : 'aligned', color],
|
|
301
|
-
]));
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
lines.push(buildPanelLine(width, [[' /policy opens this panel. Press r to record a divergence trend snapshot.', C.dim]]));
|
|
306
|
-
return lines;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
@@ -1,202 +0,0 @@
|
|
|
1
|
-
import { type Line } from '../types/grid.ts';
|
|
2
|
-
import { fitDisplay, getDisplayWidth, truncateDisplay } from '../utils/terminal-width.ts';
|
|
3
|
-
import type { PanelPicker } from '../panels/panel-picker.ts';
|
|
4
|
-
import { CATEGORY_LABELS, CATEGORY_ORDER } from '../panels/panel-picker.ts';
|
|
5
|
-
import type { PanelCategory, PanelRegistration } from '../panels/types.ts';
|
|
6
|
-
import {
|
|
7
|
-
createOverlayBorderLine,
|
|
8
|
-
createOverlayBoxLayout,
|
|
9
|
-
createOverlayContentLine,
|
|
10
|
-
DEFAULT_OVERLAY_PALETTE,
|
|
11
|
-
putOverlayText,
|
|
12
|
-
} from './overlay-box.ts';
|
|
13
|
-
import { getOverlaySurfaceMetrics } from './overlay-viewport.ts';
|
|
14
|
-
|
|
15
|
-
const TITLE_FG = '#cbd5e1';
|
|
16
|
-
const CATEGORY_FG = '#94a3b8';
|
|
17
|
-
const SELECTED_FG = '#e2e8f0';
|
|
18
|
-
const SELECTED_BG = '#1e293b';
|
|
19
|
-
const BODY_FG = '252';
|
|
20
|
-
const BORDER_FG = DEFAULT_OVERLAY_PALETTE.borderFg;
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Render the panel picker modal as Line[] for overlay in the viewport.
|
|
24
|
-
* Panels are grouped by category. Category headers are inserted between groups.
|
|
25
|
-
* When a search query is active a search-bar row is shown beneath the title.
|
|
26
|
-
*/
|
|
27
|
-
export function renderPanelPickerOverlay(
|
|
28
|
-
picker: PanelPicker,
|
|
29
|
-
width: number,
|
|
30
|
-
viewportHeight = 24,
|
|
31
|
-
): Line[] {
|
|
32
|
-
if (!picker.active) return [];
|
|
33
|
-
|
|
34
|
-
const lines: Line[] = [];
|
|
35
|
-
const metrics = getOverlaySurfaceMetrics(width, viewportHeight, {
|
|
36
|
-
margin: 4,
|
|
37
|
-
maxWidth: 72,
|
|
38
|
-
chromeRows: picker.searchQuery.length > 0 ? 7 : 6,
|
|
39
|
-
minContentRows: 6,
|
|
40
|
-
maxContentRows: 10,
|
|
41
|
-
});
|
|
42
|
-
const layout = createOverlayBoxLayout(width, metrics.margin, metrics.boxWidth);
|
|
43
|
-
const contentW = layout.innerWidth;
|
|
44
|
-
const titleFg = TITLE_FG;
|
|
45
|
-
const borderFg = BORDER_FG;
|
|
46
|
-
|
|
47
|
-
// ── Title bar ──────────────────────────────────────────────────────────────
|
|
48
|
-
const titleLine = createOverlayBorderLine(width, layout, '┌', '─', '┐', borderFg);
|
|
49
|
-
putOverlayText(titleLine, layout.margin + 2, layout.width - 4, 'Deferred Workspace Picker', { fg: titleFg, bold: true });
|
|
50
|
-
lines.push(titleLine);
|
|
51
|
-
|
|
52
|
-
// ── Search bar (shown when query is non-empty) ──────────────────────────────
|
|
53
|
-
if (picker.searchQuery.length > 0) {
|
|
54
|
-
const searchLine = createOverlayContentLine(width, layout, borderFg);
|
|
55
|
-
const searchLabel = '\u2315 ';
|
|
56
|
-
const queryAvail = contentW - getDisplayWidth(searchLabel);
|
|
57
|
-
const queryText = fitDisplay(picker.searchQuery, queryAvail);
|
|
58
|
-
putOverlayText(searchLine, layout.margin + 2, getDisplayWidth(searchLabel), searchLabel, { fg: titleFg });
|
|
59
|
-
putOverlayText(searchLine, layout.margin + 2 + getDisplayWidth(searchLabel), queryAvail, queryText, { fg: titleFg });
|
|
60
|
-
lines.push(searchLine);
|
|
61
|
-
|
|
62
|
-
lines.push(createOverlayBorderLine(width, layout, '├', '─', '┤', borderFg));
|
|
63
|
-
} else {
|
|
64
|
-
const placeholder = ' Browse by category or start typing to filter by panel name, purpose, or category.';
|
|
65
|
-
const row = createOverlayContentLine(width, layout, borderFg);
|
|
66
|
-
putOverlayText(row, layout.margin + 2, contentW, fitDisplay(placeholder, contentW), { fg: '244', dim: true });
|
|
67
|
-
lines.push(row);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const visible = picker.getVisible();
|
|
71
|
-
|
|
72
|
-
if (visible.length === 0) {
|
|
73
|
-
const noResults = 'No panels match your search';
|
|
74
|
-
const noRow = createOverlayContentLine(width, layout, borderFg);
|
|
75
|
-
putOverlayText(noRow, layout.margin + 2, contentW, fitDisplay(noResults, contentW), { fg: '244', dim: true });
|
|
76
|
-
lines.push(noRow);
|
|
77
|
-
} else {
|
|
78
|
-
// Build a flat render list of { type: 'header' | 'item', ... } entries
|
|
79
|
-
// so we can compute the correct scroll window over all rows.
|
|
80
|
-
type HeaderEntry = { type: 'header'; category: PanelCategory };
|
|
81
|
-
type ItemEntry = { type: 'item'; reg: PanelRegistration; flatIndex: number };
|
|
82
|
-
type RenderEntry = HeaderEntry | ItemEntry;
|
|
83
|
-
|
|
84
|
-
const renderEntries: RenderEntry[] = [];
|
|
85
|
-
|
|
86
|
-
// When no search query, group by category; when searching, show flat list
|
|
87
|
-
// with a single "Results" header.
|
|
88
|
-
if (picker.searchQuery.length === 0) {
|
|
89
|
-
const byCategory = new Map<PanelCategory, PanelRegistration[]>();
|
|
90
|
-
for (const reg of visible) {
|
|
91
|
-
const group = byCategory.get(reg.category) ?? [];
|
|
92
|
-
group.push(reg);
|
|
93
|
-
byCategory.set(reg.category, group);
|
|
94
|
-
}
|
|
95
|
-
let flatIndex = 0;
|
|
96
|
-
for (const cat of CATEGORY_ORDER) {
|
|
97
|
-
const group = byCategory.get(cat);
|
|
98
|
-
if (!group || group.length === 0) continue;
|
|
99
|
-
renderEntries.push({ type: 'header', category: cat });
|
|
100
|
-
for (const reg of group) {
|
|
101
|
-
renderEntries.push({ type: 'item', reg, flatIndex });
|
|
102
|
-
flatIndex++;
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
} else {
|
|
106
|
-
for (let i = 0; i < visible.length; i++) {
|
|
107
|
-
renderEntries.push({ type: 'item', reg: visible[i], flatIndex: i });
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Compute scroll window: ensure the selected item row stays visible.
|
|
112
|
-
// Find the render-entry index of the selected item.
|
|
113
|
-
const selectedEntryIdx = renderEntries.findIndex(
|
|
114
|
-
e => e.type === 'item' && e.flatIndex === picker.selectedIndex,
|
|
115
|
-
);
|
|
116
|
-
const total = renderEntries.length;
|
|
117
|
-
const maxVisible = metrics.contentRows;
|
|
118
|
-
let startEntry = 0;
|
|
119
|
-
if (total > maxVisible && selectedEntryIdx >= 0) {
|
|
120
|
-
startEntry = Math.max(
|
|
121
|
-
0,
|
|
122
|
-
Math.min(
|
|
123
|
-
selectedEntryIdx - Math.floor(maxVisible / 2),
|
|
124
|
-
total - maxVisible,
|
|
125
|
-
),
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
const endEntry = Math.min(startEntry + maxVisible, total);
|
|
129
|
-
|
|
130
|
-
for (let i = startEntry; i < endEntry; i++) {
|
|
131
|
-
const entry = renderEntries[i];
|
|
132
|
-
|
|
133
|
-
if (entry.type === 'header') {
|
|
134
|
-
// Category header row
|
|
135
|
-
const label = CATEGORY_LABELS[entry.category].toUpperCase();
|
|
136
|
-
const headerRow = createOverlayContentLine(width, layout, borderFg);
|
|
137
|
-
putOverlayText(headerRow, layout.margin + 2, contentW, fitDisplay(` ${label}`, contentW), { fg: CATEGORY_FG, dim: true });
|
|
138
|
-
lines.push(headerRow);
|
|
139
|
-
} else {
|
|
140
|
-
const { reg, flatIndex } = entry;
|
|
141
|
-
const isSelected = flatIndex === picker.selectedIndex;
|
|
142
|
-
const indicator = isSelected ? '\u25b6 ' : ' ';
|
|
143
|
-
|
|
144
|
-
// icon (1 char) + 2 spaces + name
|
|
145
|
-
const iconStr = reg.icon + ' ';
|
|
146
|
-
const iconW = getDisplayWidth(iconStr);
|
|
147
|
-
|
|
148
|
-
// separator between name and description: ' \u2014 '
|
|
149
|
-
const sep = ' \u2014 ';
|
|
150
|
-
const sepW = getDisplayWidth(sep);
|
|
151
|
-
|
|
152
|
-
// Allocate space: indicator(2) + icon(iconW) + name + sep + desc fills contentW
|
|
153
|
-
const nameMaxW = Math.max(8, Math.floor((contentW - 2 - iconW - sepW) * 0.35));
|
|
154
|
-
const descMaxW = contentW - 2 - iconW - nameMaxW - sepW;
|
|
155
|
-
|
|
156
|
-
const nameRaw = reg.name;
|
|
157
|
-
const nameStr = fitDisplay(nameRaw, nameMaxW);
|
|
158
|
-
|
|
159
|
-
const descRaw = reg.description;
|
|
160
|
-
const descStr = fitDisplay(descRaw, descMaxW);
|
|
161
|
-
|
|
162
|
-
const row = createOverlayContentLine(width, layout, borderFg, isSelected ? SELECTED_BG : '');
|
|
163
|
-
const rowText = indicator + iconStr + nameStr + sep + descStr;
|
|
164
|
-
putOverlayText(row, layout.margin + 2, contentW, fitDisplay(truncateDisplay(rowText, contentW), contentW), {
|
|
165
|
-
fg: isSelected ? SELECTED_FG : BODY_FG,
|
|
166
|
-
bg: isSelected ? SELECTED_BG : '',
|
|
167
|
-
bold: isSelected,
|
|
168
|
-
});
|
|
169
|
-
lines.push(row);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const selected = picker.getSelected();
|
|
174
|
-
if (selected) {
|
|
175
|
-
lines.push(createOverlayBorderLine(width, layout, '├', '─', '┤', borderFg));
|
|
176
|
-
const categoryLabel = CATEGORY_LABELS[selected.category].toUpperCase();
|
|
177
|
-
const selectedLine = createOverlayContentLine(width, layout, borderFg);
|
|
178
|
-
putOverlayText(selectedLine, layout.margin + 2, contentW, fitDisplay(`${selected.icon} ${selected.name} [${categoryLabel}]`, contentW), { fg: SELECTED_FG });
|
|
179
|
-
lines.push(selectedLine);
|
|
180
|
-
const desc = fitDisplay(truncateDisplay(selected.description, contentW), contentW);
|
|
181
|
-
const descRow = createOverlayContentLine(width, layout, borderFg);
|
|
182
|
-
putOverlayText(descRow, layout.margin + 2, contentW, desc, { fg: '244', dim: true });
|
|
183
|
-
lines.push(descRow);
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
// ── Scroll indicator ───────────────────────────────────────────────────
|
|
187
|
-
if (total > maxVisible) {
|
|
188
|
-
const scrollInfo = `${picker.selectedIndex + 1}/${visible.length}`;
|
|
189
|
-
const scrollRow = createOverlayContentLine(width, layout, borderFg);
|
|
190
|
-
putOverlayText(scrollRow, layout.margin + 2 + Math.max(0, contentW - getDisplayWidth(scrollInfo)), getDisplayWidth(scrollInfo), scrollInfo, { fg: '240', dim: true });
|
|
191
|
-
lines.push(scrollRow);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// ── Bottom border with hints ───────────────────────────────────────────────
|
|
196
|
-
const hints = '[Up/Down] Navigate [Enter] Open [/] Filter [Esc] Cancel';
|
|
197
|
-
const bottomLine = createOverlayBorderLine(width, layout, '└', '─', '┘', borderFg);
|
|
198
|
-
putOverlayText(bottomLine, layout.margin + 2, layout.width - 4, truncateDisplay(hints, layout.width - 4), { fg: '240', dim: true });
|
|
199
|
-
lines.push(bottomLine);
|
|
200
|
-
|
|
201
|
-
return lines;
|
|
202
|
-
}
|