@pellux/goodvibes-agent 1.4.3 → 1.5.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 +24 -0
- package/README.md +7 -7
- package/dist/package/main.js +7450 -12285
- package/docs/README.md +2 -2
- package/docs/channels-remote-and-api.md +1 -1
- package/docs/getting-started.md +2 -2
- package/docs/release-and-publishing.md +1 -1
- package/docs/tools-and-commands.md +5 -5
- package/package.json +4 -2
- package/release/performance-snapshot.json +2 -2
- package/release/release-notes.md +11 -7
- package/release/release-readiness.json +6 -6
- package/src/agent/behavior-discovery-summary.ts +4 -18
- package/src/agent/calendar-registry.ts +322 -0
- package/src/agent/competitive-feature-inventory.ts +268 -130
- package/src/agent/document-registry.ts +5 -1
- package/src/agent/email/email-service.ts +350 -0
- package/src/agent/email/imap-client.ts +596 -0
- package/src/agent/email/smtp-client.ts +453 -0
- package/src/agent/ics-calendar.ts +662 -0
- package/src/agent/ics-timezone.ts +172 -0
- package/src/agent/markdown-frontmatter.ts +31 -0
- package/src/agent/memory-safety.ts +1 -1
- package/src/agent/note-registry.ts +3 -9
- package/src/agent/persona-discovery.ts +3 -15
- package/src/agent/persona-registry.ts +1 -10
- package/src/agent/research-source-registry.ts +5 -1
- package/src/agent/routine-discovery.ts +3 -15
- package/src/agent/runtime-profile.ts +3 -0
- package/src/agent/skill-discovery.ts +3 -15
- package/src/agent/skill-draft-proposer.ts +203 -0
- package/src/agent/skill-draft-runner.ts +201 -0
- package/src/agent/skill-registry.ts +36 -1
- package/src/agent/skill-standard.ts +99 -0
- package/src/agent/vibe-file.ts +7 -22
- package/src/cli/completion.ts +1 -1
- package/src/cli/config-overrides.ts +10 -1
- package/src/cli/redaction.ts +17 -5
- package/src/config/provider-model.ts +2 -1
- package/src/config/secret-config.ts +13 -6
- package/src/core/activity-feed.ts +97 -0
- package/src/core/away-digest.ts +161 -0
- package/src/core/conversation-rendering.ts +7 -3
- package/src/core/conversation.ts +22 -15
- package/src/core/hardware-profile.ts +362 -0
- package/src/core/last-seen-store.ts +78 -0
- package/src/core/plain-language.ts +52 -0
- package/src/core/setup-incomplete-hint.ts +90 -0
- package/src/core/system-message-router.ts +38 -87
- package/src/input/agent-workspace-basic-command-editor-submission.ts +60 -220
- package/src/input/agent-workspace-basic-command-editors.ts +39 -141
- package/src/input/agent-workspace-categories.ts +63 -158
- package/src/input/agent-workspace-command-editor.ts +4 -0
- package/src/input/agent-workspace-host-category.ts +0 -5
- package/src/input/agent-workspace-local-editor-submission.ts +3 -1
- package/src/input/agent-workspace-navigation.ts +10 -3
- package/src/input/agent-workspace-onboarding-actions.ts +132 -0
- package/src/input/agent-workspace-onboarding-categories.ts +29 -26
- package/src/input/agent-workspace-onboarding-finish.ts +11 -4
- package/src/input/agent-workspace-onboarding-state.ts +111 -0
- package/src/input/agent-workspace-profile-editor-submission.ts +260 -0
- package/src/input/agent-workspace-profile-editors.ts +155 -0
- package/src/input/agent-workspace-subscription-editor.ts +7 -0
- package/src/input/agent-workspace-types.ts +5 -1
- package/src/input/agent-workspace.ts +65 -39
- package/src/input/command-registry.ts +18 -5
- package/src/input/commands/agent-runtime-profile-runtime.ts +2 -1
- package/src/input/commands/agent-skills-runtime.ts +60 -3
- package/src/input/commands/calendar-runtime.ts +209 -0
- package/src/input/commands/channels-runtime.ts +1 -0
- package/src/input/commands/command-error.ts +9 -0
- package/src/input/commands/compat-runtime.ts +1 -0
- package/src/input/commands/config.ts +1 -0
- package/src/input/commands/conversation-runtime.ts +1 -1
- package/src/input/commands/delegation-runtime.ts +5 -6
- package/src/input/commands/email-runtime.ts +387 -0
- package/src/input/commands/experience-runtime.ts +17 -4
- package/src/input/commands/guidance-runtime.ts +1 -1
- package/src/input/commands/health-runtime.ts +6 -1
- package/src/input/commands/knowledge-format.ts +73 -0
- package/src/input/commands/knowledge.ts +9 -74
- package/src/input/commands/local-provider-runtime.ts +2 -1
- package/src/input/commands/local-runtime.ts +10 -4
- package/src/input/commands/mcp-runtime.ts +7 -0
- package/src/input/commands/notify-runtime.ts +17 -1
- package/src/input/commands/onboarding-runtime.ts +1 -0
- package/src/input/commands/operator-actions-runtime.ts +1 -0
- package/src/input/commands/operator-runtime.ts +3 -0
- package/src/input/commands/personas-runtime.ts +1 -0
- package/src/input/commands/platform-access-runtime.ts +40 -17
- package/src/input/commands/product-runtime.ts +6 -1
- package/src/input/commands/provider-accounts-runtime.ts +3 -2
- package/src/input/commands/qrcode-runtime.ts +1 -0
- package/src/input/commands/routines-runtime.ts +1 -0
- package/src/input/commands/runtime-services.ts +0 -13
- package/src/input/commands/security-runtime.ts +1 -0
- package/src/input/commands/session-content.ts +1 -0
- package/src/input/commands/shell-core.ts +5 -2
- package/src/input/commands/subscription-runtime.ts +33 -9
- package/src/input/commands/support-bundle-runtime.ts +8 -1
- package/src/input/commands/tasks-runtime.ts +1 -0
- package/src/input/commands/tts-runtime.ts +1 -0
- package/src/input/commands/vibe-runtime.ts +1 -0
- package/src/input/commands.ts +4 -0
- package/src/input/feed-context-factory.ts +3 -12
- package/src/input/handler-command-route.ts +7 -60
- package/src/input/handler-feed-routes.ts +0 -194
- package/src/input/handler-feed.ts +2 -54
- package/src/input/handler-interactions.ts +0 -2
- package/src/input/handler-modal-stack.ts +0 -9
- package/src/input/handler-picker-routes.ts +24 -1
- package/src/input/handler-shortcuts.ts +11 -40
- package/src/input/handler-ui-state.ts +13 -0
- package/src/input/handler.ts +8 -35
- package/src/input/keybindings.ts +40 -17
- package/src/input/model-picker-local-fit.ts +130 -0
- package/src/input/submission-router.ts +0 -5
- package/src/main.ts +111 -89
- package/src/renderer/activity-sidebar.ts +186 -0
- package/src/renderer/agent-workspace-context-lines.ts +5 -48
- package/src/renderer/agent-workspace-style.ts +1 -1
- package/src/renderer/agent-workspace.ts +14 -2
- package/src/renderer/compositor.ts +37 -125
- package/src/renderer/conversation-overlays.ts +3 -3
- package/src/renderer/help-overlay.ts +7 -5
- package/src/renderer/model-workspace.ts +101 -86
- package/src/{panels → renderer}/polish.ts +3 -3
- package/src/renderer/shell-surface.ts +4 -5
- package/src/renderer/status-token.ts +31 -11
- package/src/renderer/tab-strip.ts +1 -1
- package/src/renderer/tool-call.ts +7 -8
- package/src/renderer/tool-labels.ts +92 -0
- package/src/renderer/ui-factory.ts +48 -96
- package/src/runtime/bootstrap-command-context.ts +0 -5
- package/src/runtime/bootstrap-command-parts.ts +6 -15
- package/src/runtime/bootstrap-core.ts +34 -13
- package/src/runtime/bootstrap-hook-bridge.ts +3 -1
- package/src/runtime/bootstrap-shell.ts +3 -50
- package/src/runtime/bootstrap.ts +3 -4
- package/src/runtime/context.ts +1 -1
- package/src/runtime/diagnostics/panels/index.ts +0 -1
- package/src/runtime/diagnostics/panels/policy.ts +1 -1
- package/src/runtime/execution-ledger.ts +16 -1
- package/src/runtime/index.ts +6 -1
- package/src/runtime/onboarding/index.ts +1 -0
- package/src/runtime/onboarding/onboarding-state.ts +200 -0
- package/src/{panels → runtime}/provider-account-snapshot.ts +5 -2
- package/src/runtime/services.ts +16 -4
- package/src/runtime/terminal-output-guard.ts +7 -0
- package/src/runtime/tool-permission-safety.ts +1 -1
- package/src/runtime/ui/model-picker/data-provider.ts +1 -1
- package/src/runtime/ui/model-picker/health-enrichment.ts +2 -2
- package/src/runtime/ui/model-picker/types.ts +2 -2
- package/src/runtime/ui/provider-health/data-provider.ts +3 -3
- package/src/runtime/ui/provider-health/types.ts +2 -2
- package/src/runtime/ui-services.ts +0 -2
- package/src/shell/agent-workspace-fullscreen.ts +0 -1
- package/src/shell/autonomy-surfacing.ts +272 -0
- package/src/shell/session-continuity-hints.ts +0 -6
- package/src/shell/startup-wiring.ts +221 -0
- package/src/shell/ui-openers.ts +18 -29
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/agent-harness-background-processes.ts +4 -4
- package/src/tools/agent-harness-browser-cockpit-route.ts +3 -3
- package/src/tools/agent-harness-command-runner.ts +6 -1
- package/src/tools/agent-harness-document-ops.ts +26 -53
- package/src/tools/agent-harness-execution-history.ts +1 -13
- package/src/tools/agent-harness-execution-posture.ts +0 -15
- package/src/tools/agent-harness-keybinding-metadata.ts +28 -29
- package/src/tools/agent-harness-local-model-cookbook.ts +24 -1
- package/src/tools/agent-harness-metadata.ts +16 -0
- package/src/tools/agent-harness-mode-catalog.ts +2 -9
- package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
- package/src/tools/agent-harness-setup-posture-utils.ts +1 -1
- package/src/tools/agent-harness-tool-schema.ts +13 -14
- package/src/tools/agent-harness-tool.ts +27 -23
- package/src/tools/agent-harness-ui-surface-metadata.ts +10 -20
- package/src/tools/agent-harness-workspace-action-runner.ts +3 -4
- package/src/tools/agent-workspace-tool.ts +2 -33
- package/src/utils/terminal-width.ts +9 -3
- package/src/version.ts +1 -1
- package/src/input/agent-workspace-panel-route.ts +0 -44
- package/src/input/panel-integration-actions.ts +0 -26
- package/src/panels/approval-panel.ts +0 -149
- package/src/panels/automation-control-panel.ts +0 -212
- package/src/panels/base-panel.ts +0 -254
- package/src/panels/builtin/agent.ts +0 -58
- package/src/panels/builtin/knowledge.ts +0 -26
- package/src/panels/builtin/operations.ts +0 -121
- package/src/panels/builtin/session.ts +0 -138
- package/src/panels/builtin/shared.ts +0 -275
- package/src/panels/builtin/usage.ts +0 -21
- package/src/panels/builtin-panels.ts +0 -23
- package/src/panels/confirm-state.ts +0 -61
- package/src/panels/context-visualizer-panel.ts +0 -204
- package/src/panels/cost-tracker-panel.ts +0 -444
- package/src/panels/docs-panel.ts +0 -285
- package/src/panels/index.ts +0 -25
- package/src/panels/knowledge-panel.ts +0 -417
- package/src/panels/memory-panel.ts +0 -226
- package/src/panels/panel-list-panel.ts +0 -464
- package/src/panels/panel-manager.ts +0 -570
- package/src/panels/provider-accounts-panel.ts +0 -233
- package/src/panels/provider-health-domains.ts +0 -208
- package/src/panels/provider-health-panel.ts +0 -720
- package/src/panels/provider-health-tracker.ts +0 -115
- package/src/panels/provider-stats-panel.ts +0 -366
- package/src/panels/qr-panel.ts +0 -207
- package/src/panels/schedule-panel.ts +0 -321
- package/src/panels/scrollable-list-panel.ts +0 -491
- package/src/panels/search-focus.ts +0 -32
- package/src/panels/security-panel.ts +0 -295
- package/src/panels/session-browser-panel.ts +0 -395
- package/src/panels/session-maintenance.ts +0 -125
- package/src/panels/subscription-panel.ts +0 -263
- package/src/panels/system-messages-panel.ts +0 -230
- package/src/panels/tasks-panel.ts +0 -344
- package/src/panels/thinking-panel.ts +0 -304
- package/src/panels/token-budget-panel.ts +0 -475
- package/src/panels/tool-inspector-panel.ts +0 -436
- package/src/panels/types.ts +0 -54
- package/src/renderer/panel-composite.ts +0 -158
- package/src/renderer/panel-tab-bar.ts +0 -69
- package/src/renderer/panel-workspace-bar.ts +0 -42
- package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
- package/src/tools/agent-harness-panel-metadata.ts +0 -211
- /package/src/runtime/perf/{panel-health-monitor.ts → component-health.ts} +0 -0
|
@@ -11,9 +11,6 @@ type AgentWorkspaceToolAction =
|
|
|
11
11
|
| 'surfaces'
|
|
12
12
|
| 'surface'
|
|
13
13
|
| 'open'
|
|
14
|
-
| 'panels'
|
|
15
|
-
| 'panel'
|
|
16
|
-
| 'open_panel'
|
|
17
14
|
| 'shortcuts'
|
|
18
15
|
| 'keybindings'
|
|
19
16
|
| 'keybinding'
|
|
@@ -33,7 +30,6 @@ interface AgentWorkspaceToolArgs {
|
|
|
33
30
|
readonly actionId?: unknown;
|
|
34
31
|
readonly workspaceActionId?: unknown;
|
|
35
32
|
readonly surfaceId?: unknown;
|
|
36
|
-
readonly panelId?: unknown;
|
|
37
33
|
readonly command?: unknown;
|
|
38
34
|
readonly commandName?: unknown;
|
|
39
35
|
readonly args?: unknown;
|
|
@@ -47,7 +43,6 @@ interface AgentWorkspaceToolArgs {
|
|
|
47
43
|
readonly combos?: unknown;
|
|
48
44
|
readonly key?: unknown;
|
|
49
45
|
readonly value?: unknown;
|
|
50
|
-
readonly pane?: unknown;
|
|
51
46
|
readonly includeParameters?: unknown;
|
|
52
47
|
readonly limit?: unknown;
|
|
53
48
|
readonly confirm?: unknown;
|
|
@@ -79,9 +74,6 @@ function normalizeWorkspaceAction(value: unknown): AgentWorkspaceToolAction | nu
|
|
|
79
74
|
if (action === 'surfaces' || action === 'ui_surfaces' || action === 'screens' || action === 'views') return 'surfaces';
|
|
80
75
|
if (action === 'surface' || action === 'ui_surface' || action === 'screen' || action === 'view') return 'surface';
|
|
81
76
|
if (action === 'open' || action === 'navigate' || action === 'open_surface' || action === 'open_ui_surface') return 'open';
|
|
82
|
-
if (action === 'panels' || action === 'panes') return 'panels';
|
|
83
|
-
if (action === 'panel' || action === 'pane') return 'panel';
|
|
84
|
-
if (action === 'open_panel' || action === 'open_pane') return 'open_panel';
|
|
85
77
|
if (action === 'shortcuts' || action === 'shortcut_help' || action === 'help') return 'shortcuts';
|
|
86
78
|
if (action === 'keybindings' || action === 'bindings' || action === 'keys') return 'keybindings';
|
|
87
79
|
if (action === 'keybinding' || action === 'binding' || action === 'key') return 'keybinding';
|
|
@@ -100,7 +92,6 @@ function readAction(args: AgentWorkspaceToolArgs): AgentWorkspaceToolAction {
|
|
|
100
92
|
const explicit = normalizeWorkspaceAction(args.action) ?? normalizeWorkspaceAction(args.mode);
|
|
101
93
|
if (explicit) return explicit;
|
|
102
94
|
if (readString(args.surfaceId)) return 'surface';
|
|
103
|
-
if (readString(args.panelId)) return 'panel';
|
|
104
95
|
if (readString(args.actionId) || readString(args.workspaceActionId)) return 'action';
|
|
105
96
|
if (readString(args.command) || readString(args.commandName)) return 'command';
|
|
106
97
|
if (readString(args.key)) return 'keybinding';
|
|
@@ -120,10 +111,6 @@ function surfaceLookup(args: AgentWorkspaceToolArgs): string {
|
|
|
120
111
|
return readString(args.surfaceId) || readString(args.id);
|
|
121
112
|
}
|
|
122
113
|
|
|
123
|
-
function panelLookup(args: AgentWorkspaceToolArgs): string {
|
|
124
|
-
return readString(args.panelId) || readString(args.id);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
114
|
function confirmedArgs(args: AgentWorkspaceToolArgs): Record<string, unknown> {
|
|
128
115
|
return compactArgs({
|
|
129
116
|
confirm: args.confirm,
|
|
@@ -173,19 +160,6 @@ function surfaceArgs(mode: 'ui_surface' | 'open_ui_surface', args: AgentWorkspac
|
|
|
173
160
|
});
|
|
174
161
|
}
|
|
175
162
|
|
|
176
|
-
function panelArgs(mode: 'panel' | 'open_panel', args: AgentWorkspaceToolArgs): Record<string, unknown> {
|
|
177
|
-
const panelId = panelLookup(args);
|
|
178
|
-
return compactArgs({
|
|
179
|
-
mode,
|
|
180
|
-
panelId,
|
|
181
|
-
target: panelId ? undefined : args.target,
|
|
182
|
-
query: panelId ? undefined : args.query,
|
|
183
|
-
pane: args.pane,
|
|
184
|
-
includeParameters: mode === 'panel' ? args.includeParameters : undefined,
|
|
185
|
-
...(mode === 'open_panel' ? confirmedArgs(args) : {}),
|
|
186
|
-
});
|
|
187
|
-
}
|
|
188
|
-
|
|
189
163
|
function keybindingArgs(mode: 'keybinding' | 'run_keybinding' | 'set_keybinding' | 'reset_keybinding', args: AgentWorkspaceToolArgs): Record<string, unknown> {
|
|
190
164
|
const actionId = lookupId(args);
|
|
191
165
|
return compactArgs({
|
|
@@ -232,15 +206,14 @@ export function createAgentWorkspaceTool(deps: AgentWorkspaceToolDeps): Tool {
|
|
|
232
206
|
properties: {
|
|
233
207
|
action: {
|
|
234
208
|
type: 'string',
|
|
235
|
-
enum: ['status', 'actions', 'action', 'run', 'surfaces', 'surface', 'open', '
|
|
209
|
+
enum: ['status', 'actions', 'action', 'run', 'surfaces', 'surface', 'open', 'shortcuts', 'keybindings', 'keybinding', 'run_keybinding', 'set_keybinding', 'reset_keybinding', 'commands', 'command', 'run_command', 'cli_commands', 'cli_command'],
|
|
236
210
|
description: 'Inspect catalogs, open UI, or run approved workspace actions.',
|
|
237
211
|
},
|
|
238
212
|
mode: { type: 'string', description: 'Alias for action.' },
|
|
239
|
-
id: { type: 'string', description: 'Generic action, surface,
|
|
213
|
+
id: { type: 'string', description: 'Generic action, surface, or keybinding id.' },
|
|
240
214
|
actionId: { type: 'string', description: 'Workspace action or keybinding action id.' },
|
|
241
215
|
workspaceActionId: { type: 'string', description: 'Workspace action id alias.' },
|
|
242
216
|
surfaceId: { type: 'string', description: 'UI surface id.' },
|
|
243
|
-
panelId: { type: 'string', description: 'Panel id.' },
|
|
244
217
|
command: { type: 'string', description: 'Slash or CLI command string.' },
|
|
245
218
|
commandName: { type: 'string', description: 'Slash or CLI command name.' },
|
|
246
219
|
args: { type: 'array', items: { type: 'string' }, description: 'Command arguments when commandName is used.' },
|
|
@@ -254,7 +227,6 @@ export function createAgentWorkspaceTool(deps: AgentWorkspaceToolDeps): Tool {
|
|
|
254
227
|
combos: { type: 'array', items: { type: 'object' }, description: 'Multiple keybinding combos.' },
|
|
255
228
|
key: { type: 'string', description: 'Keybinding lookup key.' },
|
|
256
229
|
value: { anyOf: [{ type: 'string' }, { type: 'number' }, { type: 'boolean' }], description: 'Keybinding value such as Ctrl+G.' },
|
|
257
|
-
pane: { type: 'string', enum: ['top', 'bottom'], description: 'Preferred pane for panel open.' },
|
|
258
230
|
includeParameters: { type: 'boolean', description: 'Include detailed schemas or route metadata.' },
|
|
259
231
|
limit: { type: 'number', description: 'Maximum rows returned for catalog actions.' },
|
|
260
232
|
confirm: { type: 'boolean', description: 'Required true for UI opens and side-effecting actions.' },
|
|
@@ -276,9 +248,6 @@ export function createAgentWorkspaceTool(deps: AgentWorkspaceToolDeps): Tool {
|
|
|
276
248
|
if (action === 'surfaces') return harnessTool.execute(compactArgs({ mode: 'ui_surfaces', target: args.target, query: args.query, limit: args.limit, includeParameters: args.includeParameters }));
|
|
277
249
|
if (action === 'surface') return harnessTool.execute(surfaceArgs('ui_surface', args));
|
|
278
250
|
if (action === 'open') return harnessTool.execute(surfaceArgs('open_ui_surface', args));
|
|
279
|
-
if (action === 'panels') return harnessTool.execute(compactArgs({ mode: 'panels', target: args.target, query: args.query, limit: args.limit, includeParameters: args.includeParameters }));
|
|
280
|
-
if (action === 'panel') return harnessTool.execute(panelArgs('panel', args));
|
|
281
|
-
if (action === 'open_panel') return harnessTool.execute(panelArgs('open_panel', args));
|
|
282
251
|
if (action === 'shortcuts') return harnessTool.execute(compactArgs({ mode: 'shortcuts', target: args.target, query: args.query, limit: args.limit, includeParameters: args.includeParameters }));
|
|
283
252
|
if (action === 'keybindings') return harnessTool.execute(compactArgs({ mode: 'keybindings', target: args.target, query: args.query, limit: args.limit, includeParameters: args.includeParameters }));
|
|
284
253
|
if (action === 'keybinding') return harnessTool.execute(keybindingArgs('keybinding', args));
|
|
@@ -139,14 +139,20 @@ export function wrapText(text: string, width: number): string[] {
|
|
|
139
139
|
if (currentLine) lines.push(currentLine);
|
|
140
140
|
let remaining = word;
|
|
141
141
|
while (getDisplayWidth(remaining) > width) {
|
|
142
|
+
const codePoints = [...remaining];
|
|
142
143
|
let splitIdx = 0;
|
|
143
144
|
let currentWidth = 0;
|
|
144
|
-
for (
|
|
145
|
-
const charWidth = getDisplayWidth(
|
|
145
|
+
for (const cp of codePoints) {
|
|
146
|
+
const charWidth = getDisplayWidth(cp);
|
|
146
147
|
if (currentWidth + charWidth > width) break;
|
|
147
148
|
currentWidth += charWidth;
|
|
148
|
-
splitIdx
|
|
149
|
+
splitIdx += cp.length;
|
|
149
150
|
}
|
|
151
|
+
// Safety: guarantee at least one code point of progress even if a
|
|
152
|
+
// single grapheme is wider than the available width (e.g. CJK/emoji
|
|
153
|
+
// at width===1). Without this guard splitIdx stays 0, remaining
|
|
154
|
+
// never shrinks, and the while-loop hangs.
|
|
155
|
+
if (splitIdx === 0) splitIdx = codePoints[0]!.length;
|
|
150
156
|
lines.push(remaining.slice(0, splitIdx));
|
|
151
157
|
remaining = remaining.slice(splitIdx);
|
|
152
158
|
}
|
package/src/version.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { join } from 'node:path';
|
|
|
6
6
|
// The prebuild script updates the fallback value before compilation.
|
|
7
7
|
// Uses import.meta.dir (Bun) to locate package.json relative to this file,
|
|
8
8
|
// which is correct regardless of the process working directory.
|
|
9
|
-
let _version = '1.
|
|
9
|
+
let _version = '1.5.0';
|
|
10
10
|
try {
|
|
11
11
|
const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {
|
|
12
12
|
readonly version?: unknown;
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { AgentWorkspaceCategoryId } from './agent-workspace-types.ts';
|
|
2
|
-
|
|
3
|
-
const PANEL_CATEGORY_ROUTES = {
|
|
4
|
-
knowledge: 'knowledge',
|
|
5
|
-
memory: 'memory',
|
|
6
|
-
'work-plan': 'work',
|
|
7
|
-
'project-planning': 'work',
|
|
8
|
-
plan: 'work',
|
|
9
|
-
approval: 'work',
|
|
10
|
-
tasks: 'work',
|
|
11
|
-
'provider-health': 'setup',
|
|
12
|
-
automation: 'automation',
|
|
13
|
-
schedule: 'automation',
|
|
14
|
-
providers: 'setup',
|
|
15
|
-
accounts: 'setup',
|
|
16
|
-
subscription: 'setup',
|
|
17
|
-
cost: 'setup',
|
|
18
|
-
tokens: 'setup',
|
|
19
|
-
security: 'tools',
|
|
20
|
-
policy: 'tools',
|
|
21
|
-
tools: 'tools',
|
|
22
|
-
'qr-code': 'channels',
|
|
23
|
-
sessions: 'conversation',
|
|
24
|
-
context: 'conversation',
|
|
25
|
-
thinking: 'conversation',
|
|
26
|
-
'system-messages': 'conversation',
|
|
27
|
-
docs: 'home',
|
|
28
|
-
'panel-list': 'home',
|
|
29
|
-
} as const satisfies Readonly<Record<string, AgentWorkspaceCategoryId>>;
|
|
30
|
-
|
|
31
|
-
type AgentWorkspacePanelRouteId = keyof typeof PANEL_CATEGORY_ROUTES;
|
|
32
|
-
|
|
33
|
-
function hasPanelCategoryRoute(panelId: string): panelId is AgentWorkspacePanelRouteId {
|
|
34
|
-
return Object.prototype.hasOwnProperty.call(PANEL_CATEGORY_ROUTES, panelId);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
export function agentWorkspaceCategoryForPanel(panelId: string): AgentWorkspaceCategoryId {
|
|
38
|
-
return hasPanelCategoryRoute(panelId) ? PANEL_CATEGORY_ROUTES[panelId] : 'home';
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export function agentWorkspaceCommandForPanel(panelId: string): string {
|
|
42
|
-
const category = agentWorkspaceCategoryForPanel(panelId);
|
|
43
|
-
return category === 'setup' ? '/agent' : `/agent ${category}`;
|
|
44
|
-
}
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { CommandContext } from './command-registry.ts';
|
|
2
|
-
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
3
|
-
import type { Panel } from '../panels/types.ts';
|
|
4
|
-
import type { PanelManager } from '../panels/panel-manager.ts';
|
|
5
|
-
import { ApprovalPanel } from '../panels/approval-panel.ts';
|
|
6
|
-
|
|
7
|
-
export function handlePanelIntegrationAction(
|
|
8
|
-
panelManager: PanelManager,
|
|
9
|
-
activePanel: Panel | null,
|
|
10
|
-
key: string,
|
|
11
|
-
commandContext?: CommandContext,
|
|
12
|
-
): boolean {
|
|
13
|
-
if (!activePanel) return false;
|
|
14
|
-
|
|
15
|
-
if ((key === 'enter' || key === 'return') && activePanel instanceof ApprovalPanel) {
|
|
16
|
-
const command = activePanel.getSelectedCommand();
|
|
17
|
-
if (!command || !commandContext?.executeCommand) return false;
|
|
18
|
-
const parts = command.replace(/^\//, '').split(/\s+/).filter(Boolean);
|
|
19
|
-
const [name, ...args] = parts;
|
|
20
|
-
if (!name) return false;
|
|
21
|
-
void commandContext.executeCommand(name, args).catch((err) => { logger.debug('approval panel command dispatch failed', { err }); });
|
|
22
|
-
return true;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return false;
|
|
26
|
-
}
|
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
import type { Line } from '../types/grid.ts';
|
|
2
|
-
import { ScrollableListPanel } from './scrollable-list-panel.ts';
|
|
3
|
-
import {
|
|
4
|
-
buildGuidanceLine,
|
|
5
|
-
buildKeyValueLine,
|
|
6
|
-
buildPanelLine,
|
|
7
|
-
DEFAULT_PANEL_PALETTE,
|
|
8
|
-
} from './polish.ts';
|
|
9
|
-
import type { PolicyRuntimeState } from '@/runtime/index.ts';
|
|
10
|
-
import { buildPermissionRuleSuggestions } from '@/runtime/index.ts';
|
|
11
|
-
|
|
12
|
-
const C = {
|
|
13
|
-
...DEFAULT_PANEL_PALETTE,
|
|
14
|
-
headerBg: '#111827',
|
|
15
|
-
} as const;
|
|
16
|
-
|
|
17
|
-
const APPROVAL_ROWS = [
|
|
18
|
-
['shell', 'why prompted: side effects, destructive ops, secret exposure, escalation', 'review via /approval review shell'],
|
|
19
|
-
['file', 'why prompted: config mutation, notebook edits, secret-bearing paths', 'review via /approval review file'],
|
|
20
|
-
['network', 'why prompted: external hosts, fetch scope, egress policy', 'review via /approval review network'],
|
|
21
|
-
['delegate', 'why prompted: explicit TUI build handoff, write scope, result ownership', 'review via /approval review delegate'],
|
|
22
|
-
['mcp', 'why prompted: trust escalation, host scope, path scope, coherence mismatch', 'review via /approval review mcp'],
|
|
23
|
-
['remote', 'why prompted: build-host trust, remote write scope, artifact requirements', 'review via /approval review remote'],
|
|
24
|
-
['hook', 'why prompted: deny/mutate authority, blocking behavior, execution provenance', 'review via /approval review hook'],
|
|
25
|
-
['plugin', 'why prompted: install/update lifecycle, provenance, capability grants', 'review via /approval review plugin'],
|
|
26
|
-
] as const;
|
|
27
|
-
|
|
28
|
-
type ApprovalRow = (typeof APPROVAL_ROWS)[number];
|
|
29
|
-
|
|
30
|
-
export class ApprovalPanel extends ScrollableListPanel<ApprovalRow> {
|
|
31
|
-
private readonly policyRuntimeState: Pick<PolicyRuntimeState, 'getSnapshot'>;
|
|
32
|
-
|
|
33
|
-
public constructor(policyRuntimeState: Pick<PolicyRuntimeState, 'getSnapshot'>) {
|
|
34
|
-
super('approval', 'Approval', 'A', 'monitoring');
|
|
35
|
-
this.showSelectionGutter = true; // I5: non-color selection affordance
|
|
36
|
-
this.policyRuntimeState = policyRuntimeState;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
protected override getPalette() { return C; }
|
|
40
|
-
protected override getEmptyStateMessage() { return ' No approval lanes defined.'; }
|
|
41
|
-
|
|
42
|
-
protected getItems(): readonly ApprovalRow[] {
|
|
43
|
-
return APPROVAL_ROWS;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
protected renderItem(row: ApprovalRow, index: number, selected: boolean, width: number): Line {
|
|
47
|
-
const bg = selected ? C.selectBg : undefined;
|
|
48
|
-
return buildPanelLine(width, [
|
|
49
|
-
[' ', C.label],
|
|
50
|
-
[row[0].padEnd(10), C.info, bg],
|
|
51
|
-
[row[1].slice(0, Math.max(0, width - 18)), C.value, bg],
|
|
52
|
-
]);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
public handleInput(key: string): boolean {
|
|
56
|
-
if (key === 'home') {
|
|
57
|
-
this.selectedIndex = 0;
|
|
58
|
-
this.markDirty();
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
if (key === 'end') {
|
|
62
|
-
this.selectedIndex = APPROVAL_ROWS.length - 1;
|
|
63
|
-
this.markDirty();
|
|
64
|
-
return true;
|
|
65
|
-
}
|
|
66
|
-
if (key === 'enter' || key === 'return') {
|
|
67
|
-
return true;
|
|
68
|
-
}
|
|
69
|
-
return super.handleInput(key);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
public getSelectedCommand(): string | null {
|
|
73
|
-
const selected = APPROVAL_ROWS[this.selectedIndex] ?? null;
|
|
74
|
-
return selected ? selected[2].replace('review via ', '').trim() : null;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
public render(width: number, height: number): Line[] {
|
|
78
|
-
this.clampSelection();
|
|
79
|
-
const policySnapshot = this.policyRuntimeState.getSnapshot();
|
|
80
|
-
const approvalCount = policySnapshot.recentPermissionAudit.filter((e) => e.approved === true).length;
|
|
81
|
-
const denialCount = policySnapshot.recentPermissionAudit.filter((e) => e.approved === false).length;
|
|
82
|
-
const pendingCount = policySnapshot.recentPermissionAudit.filter((e) => e.approved === undefined).length;
|
|
83
|
-
|
|
84
|
-
const selected = APPROVAL_ROWS[this.selectedIndex] ?? null;
|
|
85
|
-
const detailLines: Line[] = [];
|
|
86
|
-
if (selected) {
|
|
87
|
-
detailLines.push(buildPanelLine(width, [[' Selected Lane', C.label]]));
|
|
88
|
-
detailLines.push(buildKeyValueLine(width, [
|
|
89
|
-
{ label: 'lane', value: selected[0], valueColor: C.info },
|
|
90
|
-
{ label: 'next review', value: selected[2], valueColor: C.dim },
|
|
91
|
-
], C));
|
|
92
|
-
detailLines.push(buildPanelLine(width, [[` ${selected[1]}`, C.value]]));
|
|
93
|
-
detailLines.push(buildGuidanceLine(width, selected[2].replace('review via ', ''), `open the ${selected[0]} review path`, C));
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const recentAuditLines: Line[] = [];
|
|
97
|
-
for (const entry of policySnapshot.recentPermissionAudit.slice(0, 5)) {
|
|
98
|
-
const decision = entry.approved === undefined ? 'pending' : entry.approved ? 'approved' : 'denied';
|
|
99
|
-
const decisionColor = entry.approved === undefined ? C.info : entry.approved ? C.good : C.bad;
|
|
100
|
-
recentAuditLines.push(buildPanelLine(width, [
|
|
101
|
-
[` ${decision.padEnd(8)}`, decisionColor],
|
|
102
|
-
[`${entry.tool}`.padEnd(14), C.label],
|
|
103
|
-
[entry.summary.slice(0, Math.max(0, width - 28)), C.value],
|
|
104
|
-
]));
|
|
105
|
-
if (entry.reasons[0]) {
|
|
106
|
-
recentAuditLines.push(buildPanelLine(width, [[` ${entry.reasons[0]}`, C.dim]]));
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
if (recentAuditLines.length === 0) {
|
|
110
|
-
recentAuditLines.push(buildPanelLine(width, [[` No recent approval pressure. Live requests and decisions will appear here.`, C.dim]]));
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const ruleSuggestionLines: Line[] = [];
|
|
114
|
-
for (const suggestion of buildPermissionRuleSuggestions(policySnapshot.recentPermissionAudit).slice(0, 3)) {
|
|
115
|
-
ruleSuggestionLines.push(buildPanelLine(width, [[` ${suggestion.summary}`, C.info]]));
|
|
116
|
-
ruleSuggestionLines.push(buildGuidanceLine(width, suggestion.command, suggestion.reason, C));
|
|
117
|
-
}
|
|
118
|
-
if (ruleSuggestionLines.length === 0) {
|
|
119
|
-
ruleSuggestionLines.push(buildPanelLine(width, [[` No repeated denials currently suggest a durable rule.`, C.dim]]));
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
const headerLines: Line[] = [
|
|
123
|
-
buildPanelLine(width, [[' Approval posture', C.label]]),
|
|
124
|
-
buildKeyValueLine(width, [
|
|
125
|
-
{ label: 'why prompted', value: 'risk summary', valueColor: C.value },
|
|
126
|
-
{ label: 'what-if', value: '/security review', valueColor: C.info },
|
|
127
|
-
{ label: 'operator', value: '/approval + /security', valueColor: C.good },
|
|
128
|
-
], C),
|
|
129
|
-
buildPanelLine(width, [
|
|
130
|
-
[' \u2713 ', C.good],
|
|
131
|
-
[`approvals (${approvalCount}) `, C.good],
|
|
132
|
-
['\u2715 ', C.bad],
|
|
133
|
-
[`denials (${denialCount}) `, C.bad],
|
|
134
|
-
['\u25cb ', C.info],
|
|
135
|
-
[`pending (${pendingCount})`, C.info],
|
|
136
|
-
]),
|
|
137
|
-
buildGuidanceLine(width, '/approval review shell', 'inspect the highest-risk approval lane and refine scoped review posture', C),
|
|
138
|
-
...detailLines,
|
|
139
|
-
...recentAuditLines,
|
|
140
|
-
...ruleSuggestionLines,
|
|
141
|
-
];
|
|
142
|
-
|
|
143
|
-
return this.renderList(width, height, {
|
|
144
|
-
title: 'Approval Control Room',
|
|
145
|
-
header: headerLines,
|
|
146
|
-
footer: [buildPanelLine(width, [[` Up/Down move Home/End jump selected lane opens the next command path`, C.dim]])],
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
}
|
|
@@ -1,212 +0,0 @@
|
|
|
1
|
-
import type { Line } from '../types/grid.ts';
|
|
2
|
-
import { createEmptyLine } from '../types/grid.ts';
|
|
3
|
-
import { ScrollableListPanel } from './scrollable-list-panel.ts';
|
|
4
|
-
import type { UiAutomationSnapshot, UiReadModel } from '../runtime/ui-read-models.ts';
|
|
5
|
-
import { truncateDisplay } from '../utils/terminal-width.ts';
|
|
6
|
-
import {
|
|
7
|
-
buildEmptyState,
|
|
8
|
-
buildGuidanceLine,
|
|
9
|
-
buildKeyValueLine,
|
|
10
|
-
buildPanelLine,
|
|
11
|
-
buildPanelWorkspace,
|
|
12
|
-
DEFAULT_PANEL_PALETTE,
|
|
13
|
-
type PanelPalette,
|
|
14
|
-
} from './polish.ts';
|
|
15
|
-
|
|
16
|
-
const C = {
|
|
17
|
-
...DEFAULT_PANEL_PALETTE,
|
|
18
|
-
header: '#94a3b8',
|
|
19
|
-
headerBg: '#1e293b',
|
|
20
|
-
ok: '#22c55e',
|
|
21
|
-
warn: '#eab308',
|
|
22
|
-
error: '#ef4444',
|
|
23
|
-
info: '#38bdf8',
|
|
24
|
-
selectBg: '#0f172a',
|
|
25
|
-
} as const;
|
|
26
|
-
|
|
27
|
-
function formatTime(value?: number): string {
|
|
28
|
-
if (!value) return 'n/a';
|
|
29
|
-
return new Date(value).toLocaleString();
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
function runStatusColor(status: string): string {
|
|
33
|
-
if (status === 'completed') return C.ok;
|
|
34
|
-
if (status === 'failed' || status === 'dead_lettered') return C.error;
|
|
35
|
-
if (status === 'cancelled') return C.warn;
|
|
36
|
-
return C.info;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
type AutomationRun = UiAutomationSnapshot['runs'][number];
|
|
40
|
-
type AutomationJob = UiAutomationSnapshot['jobs'][number];
|
|
41
|
-
|
|
42
|
-
export class AutomationControlPanel extends ScrollableListPanel<AutomationRun> {
|
|
43
|
-
private readonly readModel?: UiReadModel<UiAutomationSnapshot>;
|
|
44
|
-
private readonly unsub: (() => void) | null;
|
|
45
|
-
|
|
46
|
-
public constructor(readModel?: UiReadModel<UiAutomationSnapshot>) {
|
|
47
|
-
super('automation', 'Automation', 'M', 'monitoring');
|
|
48
|
-
this.showSelectionGutter = true; // I5: non-color selection affordance
|
|
49
|
-
this.readModel = readModel;
|
|
50
|
-
this.unsub = readModel ? readModel.subscribe(() => this.markDirty()) : null;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
public override onDestroy(): void {
|
|
54
|
-
this.unsub?.();
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
protected override getPalette(): PanelPalette {
|
|
58
|
-
return C;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
private getJobs(): readonly AutomationJob[] {
|
|
62
|
-
if (!this.readModel) return [];
|
|
63
|
-
return this.readModel.getSnapshot().jobs;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
protected getItems(): readonly AutomationRun[] {
|
|
67
|
-
if (!this.readModel) return [];
|
|
68
|
-
return this.readModel.getSnapshot().runs;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
protected renderItem(run: AutomationRun, _index: number, selected: boolean, width: number): Line {
|
|
72
|
-
const bg = selected ? C.selectBg : undefined;
|
|
73
|
-
const jobs = this.getJobs();
|
|
74
|
-
const name = jobs.find((job) => job.id === run.jobId)?.name ?? run.jobId;
|
|
75
|
-
return buildPanelLine(width, [
|
|
76
|
-
[' ', C.label, bg],
|
|
77
|
-
[run.status.padEnd(11), runStatusColor(run.status), bg],
|
|
78
|
-
[` ${truncateDisplay(name, 22).padEnd(22)}`, C.value, bg],
|
|
79
|
-
[` ${truncateDisplay(run.target.kind, 12).padEnd(12)}`, C.info, bg],
|
|
80
|
-
[` ${truncateDisplay(formatTime(run.queuedAt), Math.max(0, width - 49))}`, C.dim, bg],
|
|
81
|
-
]);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
protected override getEmptyStateMessage(): string {
|
|
85
|
-
return ' No automation activity recorded.';
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
protected override getEmptyStateActions(): Array<{ command: string; summary: string }> {
|
|
89
|
-
return [
|
|
90
|
-
{ command: '/schedule list', summary: 'inspect jobs and run history without mutating schedules' },
|
|
91
|
-
{ command: '/schedule receipts', summary: 'review Agent routine promotion receipts' },
|
|
92
|
-
];
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
public render(width: number, height: number): Line[] {
|
|
96
|
-
const intro = 'Automation jobs, active runs, deliveries, and failure posture across the shared runtime.';
|
|
97
|
-
|
|
98
|
-
if (!this.readModel) {
|
|
99
|
-
const workspace = buildPanelWorkspace(width, height, {
|
|
100
|
-
title: 'Automation Control',
|
|
101
|
-
intro,
|
|
102
|
-
sections: [{
|
|
103
|
-
lines: buildEmptyState(
|
|
104
|
-
width,
|
|
105
|
-
' Connected-host automation state is unavailable.',
|
|
106
|
-
'This operator view is read-only. Use /schedule list for compact transcript output; automation stays unchanged.',
|
|
107
|
-
[{ command: '/schedule list', summary: 'review automation without starting hidden work' }],
|
|
108
|
-
C,
|
|
109
|
-
),
|
|
110
|
-
}],
|
|
111
|
-
palette: C,
|
|
112
|
-
});
|
|
113
|
-
while (workspace.length < height) workspace.push(createEmptyLine(width));
|
|
114
|
-
return workspace;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
const snapshot = this.readModel.getSnapshot();
|
|
118
|
-
const jobs = [...snapshot.jobs];
|
|
119
|
-
const runs = this.getItems();
|
|
120
|
-
|
|
121
|
-
const headerLines: Line[] = [
|
|
122
|
-
buildKeyValueLine(width, [
|
|
123
|
-
{ label: 'jobs', value: String(snapshot.totalJobs), valueColor: snapshot.totalJobs > 0 ? C.info : C.dim },
|
|
124
|
-
{ label: 'runs', value: String(snapshot.totalRuns), valueColor: snapshot.totalRuns > 0 ? C.value : C.dim },
|
|
125
|
-
{ label: 'active', value: String(snapshot.activeRunIds.length), valueColor: snapshot.activeRunIds.length > 0 ? C.warn : C.dim },
|
|
126
|
-
{ label: 'failed', value: String(snapshot.totalFailed), valueColor: snapshot.totalFailed > 0 ? C.error : C.dim },
|
|
127
|
-
], C),
|
|
128
|
-
buildKeyValueLine(width, [
|
|
129
|
-
{ label: 'deliveries ok', value: String(snapshot.deliveryTotals.succeeded), valueColor: snapshot.deliveryTotals.succeeded > 0 ? C.ok : C.dim },
|
|
130
|
-
{ label: 'delivery fail', value: String(snapshot.deliveryTotals.failed), valueColor: snapshot.deliveryTotals.failed > 0 ? C.error : C.dim },
|
|
131
|
-
{ label: 'dead letters', value: String(snapshot.deliveryTotals.deadLettered), valueColor: snapshot.deliveryTotals.deadLettered > 0 ? C.warn : C.dim },
|
|
132
|
-
{ label: 'sources', value: String(snapshot.sourceCount), valueColor: snapshot.sourceCount > 0 ? C.info : C.dim },
|
|
133
|
-
], C),
|
|
134
|
-
buildGuidanceLine(width, '/schedule list', 'read-only in Agent; schedule mutation/run controls remain blocked here', C),
|
|
135
|
-
];
|
|
136
|
-
|
|
137
|
-
if (jobs.length === 0 && runs.length === 0) {
|
|
138
|
-
return this.renderList(width, height, {
|
|
139
|
-
title: 'Automation Control',
|
|
140
|
-
header: headerLines,
|
|
141
|
-
emptyMessage: ' No automation activity recorded.',
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
this.clampSelection();
|
|
146
|
-
const selectedRun = runs[this.selectedIndex];
|
|
147
|
-
const jobName = selectedRun ? (jobs.find((job) => job.id === selectedRun.jobId)?.name ?? selectedRun.jobId) : 'n/a';
|
|
148
|
-
|
|
149
|
-
const footerLines: Line[] = [];
|
|
150
|
-
if (selectedRun) {
|
|
151
|
-
footerLines.push(
|
|
152
|
-
buildPanelLine(width, [
|
|
153
|
-
[' Run: ', C.label],
|
|
154
|
-
[selectedRun.id, C.value],
|
|
155
|
-
[' Status: ', C.label],
|
|
156
|
-
[selectedRun.status, runStatusColor(selectedRun.status)],
|
|
157
|
-
]),
|
|
158
|
-
buildPanelLine(width, [
|
|
159
|
-
[' Job: ', C.label],
|
|
160
|
-
[jobName, C.value],
|
|
161
|
-
[' Agent: ', C.label],
|
|
162
|
-
[selectedRun.agentId ?? 'n/a', C.info],
|
|
163
|
-
]),
|
|
164
|
-
buildPanelLine(width, [
|
|
165
|
-
[' Queue: ', C.label],
|
|
166
|
-
[formatTime(selectedRun.queuedAt), C.dim],
|
|
167
|
-
[' End: ', C.label],
|
|
168
|
-
[formatTime(selectedRun.endedAt), C.dim],
|
|
169
|
-
]),
|
|
170
|
-
buildPanelLine(width, [
|
|
171
|
-
[' Trigger: ', C.label],
|
|
172
|
-
[selectedRun.triggeredBy.kind, C.info],
|
|
173
|
-
[' Target: ', C.label],
|
|
174
|
-
[selectedRun.target.kind, C.value],
|
|
175
|
-
]),
|
|
176
|
-
buildPanelLine(width, [
|
|
177
|
-
[' Deliveries: ', C.label],
|
|
178
|
-
[String(selectedRun.deliveryIds.length), selectedRun.deliveryIds.length > 0 ? C.info : C.dim],
|
|
179
|
-
[' Route: ', C.label],
|
|
180
|
-
[selectedRun.routeId ?? 'n/a', C.dim],
|
|
181
|
-
]),
|
|
182
|
-
);
|
|
183
|
-
if (selectedRun.error) {
|
|
184
|
-
footerLines.push(buildPanelLine(width, [
|
|
185
|
-
[' Error ', C.label],
|
|
186
|
-
[truncateDisplay(selectedRun.error, Math.max(0, width - 10)), C.error],
|
|
187
|
-
]));
|
|
188
|
-
}
|
|
189
|
-
} else {
|
|
190
|
-
footerLines.push(buildPanelLine(width, [[' No run selected.', C.dim]]));
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
// Jobs quick view
|
|
194
|
-
if (jobs.length > 0) {
|
|
195
|
-
footerLines.push(
|
|
196
|
-
...jobs.slice(0, 6).map((job) => buildPanelLine(width, [
|
|
197
|
-
[' ', C.label],
|
|
198
|
-
[job.enabled ? 'ENABLED ' : 'PAUSED ', job.enabled ? C.ok : C.warn],
|
|
199
|
-
[truncateDisplay(job.name, 24).padEnd(24), C.value],
|
|
200
|
-
[` next ${truncateDisplay(formatTime(job.nextRunAt), Math.max(0, width - 43))}`, C.dim],
|
|
201
|
-
])),
|
|
202
|
-
);
|
|
203
|
-
}
|
|
204
|
-
footerLines.push(buildPanelLine(width, [[' Up/Down move through runs', C.dim]]));
|
|
205
|
-
|
|
206
|
-
return this.renderList(width, height, {
|
|
207
|
-
title: 'Automation Control',
|
|
208
|
-
header: headerLines,
|
|
209
|
-
footer: footerLines,
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
}
|