@pellux/goodvibes-agent 1.4.4 → 1.5.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.
Files changed (230) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +52 -7
  3. package/dist/package/main.js +7491 -12253
  4. package/docs/README.md +2 -2
  5. package/docs/channels-remote-and-api.md +1 -1
  6. package/docs/getting-started.md +2 -2
  7. package/docs/release-and-publishing.md +1 -1
  8. package/docs/tools-and-commands.md +5 -5
  9. package/package.json +4 -2
  10. package/release/live-verification/live-verification.json +13 -13
  11. package/release/live-verification/live-verification.md +15 -15
  12. package/release/performance-snapshot.json +2 -2
  13. package/release/release-notes.md +5 -7
  14. package/release/release-readiness.json +6 -6
  15. package/src/agent/behavior-discovery-summary.ts +4 -18
  16. package/src/agent/calendar-registry.ts +322 -0
  17. package/src/agent/competitive-feature-inventory.ts +268 -130
  18. package/src/agent/document-registry.ts +5 -1
  19. package/src/agent/email/email-service.ts +350 -0
  20. package/src/agent/email/imap-client.ts +596 -0
  21. package/src/agent/email/smtp-client.ts +453 -0
  22. package/src/agent/ics-calendar.ts +662 -0
  23. package/src/agent/ics-timezone.ts +172 -0
  24. package/src/agent/markdown-frontmatter.ts +31 -0
  25. package/src/agent/memory-safety.ts +1 -1
  26. package/src/agent/note-registry.ts +3 -9
  27. package/src/agent/persona-discovery.ts +3 -15
  28. package/src/agent/persona-registry.ts +1 -10
  29. package/src/agent/research-source-registry.ts +5 -1
  30. package/src/agent/routine-discovery.ts +3 -15
  31. package/src/agent/runtime-profile.ts +3 -0
  32. package/src/agent/skill-discovery.ts +3 -15
  33. package/src/agent/skill-draft-proposer.ts +203 -0
  34. package/src/agent/skill-draft-runner.ts +201 -0
  35. package/src/agent/skill-registry.ts +36 -1
  36. package/src/agent/skill-standard.ts +99 -0
  37. package/src/agent/vibe-file.ts +7 -22
  38. package/src/cli/completion.ts +1 -1
  39. package/src/cli/config-overrides.ts +10 -1
  40. package/src/cli/redaction.ts +17 -5
  41. package/src/config/provider-model.ts +2 -1
  42. package/src/config/secret-config.ts +13 -6
  43. package/src/core/activity-feed.ts +97 -0
  44. package/src/core/away-digest.ts +161 -0
  45. package/src/core/conversation-rendering.ts +7 -3
  46. package/src/core/conversation.ts +22 -15
  47. package/src/core/hardware-profile.ts +362 -0
  48. package/src/core/last-seen-store.ts +78 -0
  49. package/src/core/plain-language.ts +52 -0
  50. package/src/core/setup-incomplete-hint.ts +90 -0
  51. package/src/core/system-message-router.ts +38 -87
  52. package/src/input/agent-workspace-basic-command-editor-submission.ts +60 -220
  53. package/src/input/agent-workspace-basic-command-editors.ts +39 -141
  54. package/src/input/agent-workspace-categories.ts +40 -125
  55. package/src/input/agent-workspace-command-editor.ts +4 -0
  56. package/src/input/agent-workspace-host-category.ts +0 -5
  57. package/src/input/agent-workspace-local-editor-submission.ts +3 -1
  58. package/src/input/agent-workspace-navigation.ts +10 -3
  59. package/src/input/agent-workspace-onboarding-actions.ts +132 -0
  60. package/src/input/agent-workspace-onboarding-categories.ts +29 -26
  61. package/src/input/agent-workspace-onboarding-finish.ts +11 -4
  62. package/src/input/agent-workspace-onboarding-state.ts +111 -0
  63. package/src/input/agent-workspace-profile-editor-submission.ts +260 -0
  64. package/src/input/agent-workspace-profile-editors.ts +155 -0
  65. package/src/input/agent-workspace-subscription-editor.ts +7 -0
  66. package/src/input/agent-workspace-types.ts +5 -1
  67. package/src/input/agent-workspace.ts +65 -39
  68. package/src/input/command-registry.ts +18 -5
  69. package/src/input/commands/agent-runtime-profile-runtime.ts +2 -1
  70. package/src/input/commands/agent-skills-runtime.ts +60 -3
  71. package/src/input/commands/calendar-runtime.ts +209 -0
  72. package/src/input/commands/channels-runtime.ts +1 -0
  73. package/src/input/commands/command-error.ts +9 -0
  74. package/src/input/commands/compat-runtime.ts +1 -0
  75. package/src/input/commands/config.ts +1 -0
  76. package/src/input/commands/conversation-runtime.ts +1 -1
  77. package/src/input/commands/delegation-runtime.ts +5 -6
  78. package/src/input/commands/email-runtime.ts +387 -0
  79. package/src/input/commands/experience-runtime.ts +17 -4
  80. package/src/input/commands/guidance-runtime.ts +1 -1
  81. package/src/input/commands/health-runtime.ts +6 -1
  82. package/src/input/commands/knowledge-format.ts +73 -0
  83. package/src/input/commands/knowledge.ts +9 -74
  84. package/src/input/commands/local-provider-runtime.ts +2 -1
  85. package/src/input/commands/local-runtime.ts +10 -4
  86. package/src/input/commands/mcp-runtime.ts +7 -0
  87. package/src/input/commands/notify-runtime.ts +17 -1
  88. package/src/input/commands/onboarding-runtime.ts +1 -0
  89. package/src/input/commands/operator-actions-runtime.ts +1 -0
  90. package/src/input/commands/operator-runtime.ts +3 -0
  91. package/src/input/commands/personas-runtime.ts +1 -0
  92. package/src/input/commands/platform-access-runtime.ts +40 -17
  93. package/src/input/commands/product-runtime.ts +6 -1
  94. package/src/input/commands/provider-accounts-runtime.ts +3 -2
  95. package/src/input/commands/qrcode-runtime.ts +1 -0
  96. package/src/input/commands/routines-runtime.ts +1 -0
  97. package/src/input/commands/runtime-services.ts +0 -13
  98. package/src/input/commands/security-runtime.ts +1 -0
  99. package/src/input/commands/session-content.ts +1 -0
  100. package/src/input/commands/shell-core.ts +5 -2
  101. package/src/input/commands/subscription-runtime.ts +33 -9
  102. package/src/input/commands/support-bundle-runtime.ts +8 -1
  103. package/src/input/commands/tasks-runtime.ts +1 -0
  104. package/src/input/commands/tts-runtime.ts +1 -0
  105. package/src/input/commands/vibe-runtime.ts +1 -0
  106. package/src/input/commands.ts +4 -0
  107. package/src/input/feed-context-factory.ts +3 -12
  108. package/src/input/handler-command-route.ts +7 -60
  109. package/src/input/handler-feed-routes.ts +0 -194
  110. package/src/input/handler-feed.ts +2 -54
  111. package/src/input/handler-interactions.ts +0 -2
  112. package/src/input/handler-modal-stack.ts +0 -9
  113. package/src/input/handler-picker-routes.ts +24 -1
  114. package/src/input/handler-shortcuts.ts +11 -40
  115. package/src/input/handler-ui-state.ts +13 -0
  116. package/src/input/handler.ts +8 -35
  117. package/src/input/keybindings.ts +40 -17
  118. package/src/input/model-picker-local-fit.ts +130 -0
  119. package/src/input/shell-passthrough.ts +58 -0
  120. package/src/input/submission-router.ts +0 -5
  121. package/src/main.ts +129 -90
  122. package/src/renderer/activity-sidebar.ts +186 -0
  123. package/src/renderer/agent-workspace-context-lines.ts +5 -48
  124. package/src/renderer/agent-workspace-style.ts +1 -1
  125. package/src/renderer/agent-workspace.ts +14 -2
  126. package/src/renderer/compositor.ts +37 -125
  127. package/src/renderer/conversation-overlays.ts +3 -3
  128. package/src/renderer/help-overlay.ts +7 -5
  129. package/src/renderer/model-workspace.ts +101 -86
  130. package/src/{panels → renderer}/polish.ts +3 -3
  131. package/src/renderer/shell-surface.ts +4 -5
  132. package/src/renderer/status-token.ts +31 -11
  133. package/src/renderer/tab-strip.ts +1 -1
  134. package/src/renderer/tool-call.ts +7 -8
  135. package/src/renderer/tool-labels.ts +92 -0
  136. package/src/renderer/ui-factory.ts +48 -96
  137. package/src/runtime/bootstrap-command-context.ts +0 -5
  138. package/src/runtime/bootstrap-command-parts.ts +6 -15
  139. package/src/runtime/bootstrap-core.ts +34 -13
  140. package/src/runtime/bootstrap-hook-bridge.ts +3 -1
  141. package/src/runtime/bootstrap-shell.ts +3 -50
  142. package/src/runtime/bootstrap.ts +3 -4
  143. package/src/runtime/context.ts +1 -1
  144. package/src/runtime/diagnostics/panels/index.ts +0 -1
  145. package/src/runtime/diagnostics/panels/policy.ts +1 -1
  146. package/src/runtime/execution-ledger.ts +16 -1
  147. package/src/runtime/index.ts +6 -1
  148. package/src/runtime/onboarding/index.ts +1 -0
  149. package/src/runtime/onboarding/onboarding-state.ts +200 -0
  150. package/src/{panels → runtime}/provider-account-snapshot.ts +5 -2
  151. package/src/runtime/services.ts +16 -4
  152. package/src/runtime/terminal-output-guard.ts +7 -0
  153. package/src/runtime/tool-permission-safety.ts +1 -1
  154. package/src/runtime/ui/model-picker/data-provider.ts +1 -1
  155. package/src/runtime/ui/model-picker/health-enrichment.ts +2 -2
  156. package/src/runtime/ui/model-picker/types.ts +2 -2
  157. package/src/runtime/ui/provider-health/data-provider.ts +3 -3
  158. package/src/runtime/ui/provider-health/types.ts +2 -2
  159. package/src/runtime/ui-services.ts +0 -2
  160. package/src/shell/agent-workspace-fullscreen.ts +0 -1
  161. package/src/shell/autonomy-surfacing.ts +272 -0
  162. package/src/shell/session-continuity-hints.ts +0 -6
  163. package/src/shell/startup-wiring.ts +221 -0
  164. package/src/shell/ui-openers.ts +18 -29
  165. package/src/tools/agent-context-policy.ts +1 -1
  166. package/src/tools/agent-harness-background-processes.ts +4 -4
  167. package/src/tools/agent-harness-browser-cockpit-route.ts +3 -3
  168. package/src/tools/agent-harness-command-runner.ts +6 -1
  169. package/src/tools/agent-harness-document-ops.ts +26 -53
  170. package/src/tools/agent-harness-execution-history.ts +1 -13
  171. package/src/tools/agent-harness-execution-posture.ts +0 -15
  172. package/src/tools/agent-harness-keybinding-metadata.ts +28 -29
  173. package/src/tools/agent-harness-local-model-cookbook.ts +24 -1
  174. package/src/tools/agent-harness-metadata.ts +16 -0
  175. package/src/tools/agent-harness-mode-catalog.ts +2 -9
  176. package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
  177. package/src/tools/agent-harness-setup-posture-utils.ts +1 -1
  178. package/src/tools/agent-harness-tool-schema.ts +13 -14
  179. package/src/tools/agent-harness-tool.ts +27 -23
  180. package/src/tools/agent-harness-ui-surface-metadata.ts +10 -20
  181. package/src/tools/agent-harness-workspace-action-runner.ts +3 -4
  182. package/src/tools/agent-workspace-tool.ts +2 -33
  183. package/src/utils/terminal-width.ts +9 -3
  184. package/src/version.ts +1 -1
  185. package/src/input/agent-workspace-panel-route.ts +0 -44
  186. package/src/input/panel-integration-actions.ts +0 -26
  187. package/src/panels/approval-panel.ts +0 -149
  188. package/src/panels/automation-control-panel.ts +0 -212
  189. package/src/panels/base-panel.ts +0 -254
  190. package/src/panels/builtin/agent.ts +0 -58
  191. package/src/panels/builtin/knowledge.ts +0 -26
  192. package/src/panels/builtin/operations.ts +0 -121
  193. package/src/panels/builtin/session.ts +0 -138
  194. package/src/panels/builtin/shared.ts +0 -275
  195. package/src/panels/builtin/usage.ts +0 -21
  196. package/src/panels/builtin-panels.ts +0 -23
  197. package/src/panels/confirm-state.ts +0 -61
  198. package/src/panels/context-visualizer-panel.ts +0 -204
  199. package/src/panels/cost-tracker-panel.ts +0 -444
  200. package/src/panels/docs-panel.ts +0 -285
  201. package/src/panels/index.ts +0 -25
  202. package/src/panels/knowledge-panel.ts +0 -417
  203. package/src/panels/memory-panel.ts +0 -226
  204. package/src/panels/panel-list-panel.ts +0 -464
  205. package/src/panels/panel-manager.ts +0 -570
  206. package/src/panels/provider-accounts-panel.ts +0 -233
  207. package/src/panels/provider-health-domains.ts +0 -208
  208. package/src/panels/provider-health-panel.ts +0 -720
  209. package/src/panels/provider-health-tracker.ts +0 -115
  210. package/src/panels/provider-stats-panel.ts +0 -366
  211. package/src/panels/qr-panel.ts +0 -207
  212. package/src/panels/schedule-panel.ts +0 -321
  213. package/src/panels/scrollable-list-panel.ts +0 -491
  214. package/src/panels/search-focus.ts +0 -32
  215. package/src/panels/security-panel.ts +0 -295
  216. package/src/panels/session-browser-panel.ts +0 -395
  217. package/src/panels/session-maintenance.ts +0 -125
  218. package/src/panels/subscription-panel.ts +0 -263
  219. package/src/panels/system-messages-panel.ts +0 -230
  220. package/src/panels/tasks-panel.ts +0 -344
  221. package/src/panels/thinking-panel.ts +0 -304
  222. package/src/panels/token-budget-panel.ts +0 -475
  223. package/src/panels/tool-inspector-panel.ts +0 -436
  224. package/src/panels/types.ts +0 -54
  225. package/src/renderer/panel-composite.ts +0 -158
  226. package/src/renderer/panel-tab-bar.ts +0 -69
  227. package/src/renderer/panel-workspace-bar.ts +0 -42
  228. package/src/runtime/diagnostics/panels/panel-resources.ts +0 -118
  229. package/src/tools/agent-harness-panel-metadata.ts +0 -211
  230. /package/src/runtime/perf/{panel-health-monitor.ts → component-health.ts} +0 -0
@@ -1,321 +0,0 @@
1
- import { BasePanel } from './base-panel.ts';
2
- import { type Line } from '../types/grid.ts';
3
- import type { AutomationManager } from '@pellux/goodvibes-sdk/platform/automation';
4
- import type { AutomationJob } from '@pellux/goodvibes-sdk/platform/automation';
5
- import type { AutomationRun } from '@pellux/goodvibes-sdk/platform/automation';
6
- import type { AutomationScheduleDefinition } from '@pellux/goodvibes-sdk/platform/automation';
7
- import {
8
- buildEmptyState,
9
- buildPanelLine,
10
- buildPanelWorkspace,
11
- resolveScrollablePanelSection,
12
- DEFAULT_PANEL_PALETTE,
13
- type PanelWorkspaceSection,
14
- } from './polish.ts';
15
-
16
- // ---------------------------------------------------------------------------
17
- // Colors
18
- // ---------------------------------------------------------------------------
19
-
20
- const C = {
21
- header: '#00d7ff',
22
- sectionHeader: '244',
23
- enabled: '#5fd700',
24
- disabled: '#6c6c6c',
25
- selected: '#1c1c1c',
26
- selectedFg: '#ffffff',
27
- id: '238',
28
- cron: '#af87ff',
29
- prompt: '250',
30
- nextRun: '#87afff',
31
- lastRun: '244',
32
- runCount: '#ffaf00',
33
- statusRunning: '#5fd700',
34
- statusFailed: '#ff5f5f',
35
- hint: '240',
36
- } as const;
37
-
38
- // ---------------------------------------------------------------------------
39
- // View items
40
- // ---------------------------------------------------------------------------
41
-
42
- type ViewItem =
43
- | { kind: 'header' }
44
- | { kind: 'task'; task: AutomationJob; history: AutomationRun[] }
45
- | { kind: 'empty' };
46
-
47
- type ScheduleAutomationManager = Pick<
48
- AutomationManager,
49
- 'listJobs' | 'listRuns'
50
- >;
51
-
52
- function formatSchedule(schedule: AutomationScheduleDefinition): string {
53
- switch (schedule.kind) {
54
- case 'cron':
55
- return schedule.timezone ? `${schedule.expression} [${schedule.timezone}]` : schedule.expression;
56
- case 'every':
57
- return formatEveryInterval(schedule.intervalMs);
58
- case 'at':
59
- return new Date(schedule.at).toLocaleString();
60
- }
61
- }
62
-
63
- function formatEveryInterval(intervalMs: number): string {
64
- const units: ReadonlyArray<readonly [number, string]> = [
65
- [86_400_000, 'd'],
66
- [3_600_000, 'h'],
67
- [60_000, 'm'],
68
- [1_000, 's'],
69
- ];
70
- for (const [size, unit] of units) {
71
- if (intervalMs >= size && intervalMs % size === 0) {
72
- return `${intervalMs / size}${unit}`;
73
- }
74
- }
75
- return `${intervalMs}ms`;
76
- }
77
-
78
- // ---------------------------------------------------------------------------
79
- // SchedulePanel
80
- // ---------------------------------------------------------------------------
81
-
82
- /**
83
- * SchedulePanel — displays connected schedule posture with next run time and run history.
84
- * It does not create, enable, disable, or run schedules from panel keypresses.
85
- */
86
- export class SchedulePanel extends BasePanel {
87
- private items: ViewItem[] = [];
88
- private selectedIndex = 0;
89
- private scrollOffset = 0;
90
- private readonly automationManager: ScheduleAutomationManager;
91
-
92
- constructor(automationManager: ScheduleAutomationManager) {
93
- super('schedule', 'Schedule', 'Z', 'agent');
94
- this.automationManager = automationManager;
95
- }
96
-
97
- // -------------------------------------------------------------------------
98
- // Lifecycle
99
- // -------------------------------------------------------------------------
100
-
101
- override onActivate(): void {
102
- super.onActivate();
103
- this.rebuild();
104
- }
105
-
106
- override onDeactivate(): void {
107
- this.scrollOffset = 0;
108
- }
109
-
110
- override onDestroy(): void {
111
- this.onDeactivate();
112
- super.onDestroy();
113
- }
114
-
115
- // -------------------------------------------------------------------------
116
- // Data
117
- // -------------------------------------------------------------------------
118
-
119
- private rebuild(): void {
120
- const manager = this.automationManager;
121
- const tasks = manager.listJobs();
122
-
123
- const items: ViewItem[] = [{ kind: 'header' }];
124
- if (tasks.length === 0) {
125
- items.push({ kind: 'empty' });
126
- } else {
127
- for (const task of tasks) {
128
- items.push({
129
- kind: 'task',
130
- task,
131
- history: manager.listRuns(task.id),
132
- });
133
- }
134
- }
135
- this.items = items;
136
-
137
- if (this.selectedIndex >= this.items.length) {
138
- this.selectedIndex = Math.max(0, this.items.length - 1);
139
- }
140
- }
141
-
142
- // -------------------------------------------------------------------------
143
- // Input
144
- // -------------------------------------------------------------------------
145
-
146
- handleInput(key: string): boolean {
147
- switch (key) {
148
- case 'up':
149
- case 'k': {
150
- if (this.selectedIndex > 0) {
151
- this.selectedIndex--;
152
- this.markDirty();
153
- }
154
- return true;
155
- }
156
- case 'down':
157
- case 'j': {
158
- if (this.selectedIndex < this.items.length - 1) {
159
- this.selectedIndex++;
160
- this.markDirty();
161
- }
162
- return true;
163
- }
164
- case 'return':
165
- case ' ': {
166
- this.setError('Schedule mutation is read-only in GoodVibes Agent. Schedule changes require an exact command with --yes; panel keypresses never mutate connected schedules.');
167
- return true;
168
- }
169
- case 'r': {
170
- this.setError('Schedule run is blocked in GoodVibes Agent. Use /schedule run <schedule-id> --yes only when you explicitly want to run that connected schedule.');
171
- return true;
172
- }
173
- case 'R': {
174
- // Refresh the view
175
- this.rebuild();
176
- this.markDirty();
177
- return true;
178
- }
179
- default:
180
- return false;
181
- }
182
- }
183
-
184
- // -------------------------------------------------------------------------
185
- // Rendering
186
- // -------------------------------------------------------------------------
187
-
188
- override render(width: number, height: number): Line[] {
189
- const tasks = this.automationManager.listJobs();
190
- const enabled = tasks.filter((task: AutomationJob) => task.enabled).length;
191
- if (tasks.length === 0) {
192
- return buildPanelWorkspace(width, height, {
193
- title: ' Schedule',
194
- intro: 'Review recurring scheduled tasks, next run timing, recent history, and enablement state.',
195
- sections: [
196
- {
197
- lines: buildEmptyState(
198
- width,
199
- ' No scheduled tasks',
200
- 'Schedule mutation and run controls are blocked. Use /schedule list for read-only history, or exact --yes commands for connected schedule actions.',
201
- [],
202
- DEFAULT_PANEL_PALETTE,
203
- ),
204
- },
205
- ],
206
- footerLines: [
207
- ...(this.renderErrorLine(width) ? [this.renderErrorLine(width)!] : []),
208
- buildPanelLine(width, [[' Up/Down', DEFAULT_PANEL_PALETTE.info], [' navigate', DEFAULT_PANEL_PALETTE.dim], [' R', DEFAULT_PANEL_PALETTE.info], [' refresh', DEFAULT_PANEL_PALETTE.dim], [' no keypress mutations', DEFAULT_PANEL_PALETTE.warn]]),
209
- ],
210
- palette: DEFAULT_PANEL_PALETTE,
211
- });
212
- }
213
-
214
- const taskItems = this.items.filter((item): item is Extract<ViewItem, { kind: 'task' }> => item.kind === 'task');
215
- this.selectedIndex = Math.max(0, Math.min(this.selectedIndex, taskItems.length - 1));
216
- const summarySection: PanelWorkspaceSection = {
217
- title: 'Summary',
218
- lines: [
219
- buildPanelLine(width, [
220
- [' Tasks ', DEFAULT_PANEL_PALETTE.label],
221
- [String(tasks.length), DEFAULT_PANEL_PALETTE.value],
222
- [' Enabled ', DEFAULT_PANEL_PALETTE.label],
223
- [String(enabled), enabled > 0 ? DEFAULT_PANEL_PALETTE.good : DEFAULT_PANEL_PALETTE.dim],
224
- ]),
225
- ],
226
- };
227
- const scheduledTasksSection = resolveScrollablePanelSection(width, height, {
228
- intro: 'Review recurring scheduled tasks, next run timing, recent history, and enablement state.',
229
- footerLines: [
230
- ...(this.renderErrorLine(width) ? [this.renderErrorLine(width)!] : []),
231
- buildPanelLine(width, [[' Up/Down', DEFAULT_PANEL_PALETTE.info], [' navigate', DEFAULT_PANEL_PALETTE.dim], [' R', DEFAULT_PANEL_PALETTE.info], [' refresh', DEFAULT_PANEL_PALETTE.dim], [' no keypress mutations', DEFAULT_PANEL_PALETTE.warn]]),
232
- ],
233
- palette: DEFAULT_PANEL_PALETTE,
234
- beforeSections: [summarySection],
235
- section: {
236
- title: 'Scheduled Tasks',
237
- scrollableLines: taskItems.flatMap((item, index) => this.renderTask(item.task, item.history, index === this.selectedIndex, width)),
238
- selectedIndex: this.selectedIndex * 3,
239
- scrollOffset: this.scrollOffset,
240
- minRows: 6,
241
- },
242
- });
243
- this.scrollOffset = scheduledTasksSection.scrollOffset;
244
- const sections: PanelWorkspaceSection[] = [
245
- summarySection,
246
- scheduledTasksSection.section,
247
- ];
248
-
249
- return buildPanelWorkspace(width, height, {
250
- title: ' Schedule',
251
- intro: 'Review recurring scheduled tasks, next run timing, recent history, and enablement state.',
252
- sections,
253
- footerLines: [
254
- ...(this.renderErrorLine(width) ? [this.renderErrorLine(width)!] : []),
255
- buildPanelLine(width, [[' Up/Down', DEFAULT_PANEL_PALETTE.info], [' navigate', DEFAULT_PANEL_PALETTE.dim], [' R', DEFAULT_PANEL_PALETTE.info], [' refresh', DEFAULT_PANEL_PALETTE.dim], [' no keypress mutations', DEFAULT_PANEL_PALETTE.warn]]),
256
- ],
257
- palette: DEFAULT_PANEL_PALETTE,
258
- });
259
- }
260
-
261
- /**
262
- * Render a task as 3 rows:
263
- * Row 1: [status] id name schedule
264
- * Row 2: next: <date> last: <date> runs: N
265
- * Row 3: prompt preview [history]
266
- */
267
- private renderTask(task: AutomationJob, history: AutomationRun[], selected: boolean, width: number): Line[] {
268
- const bg = selected ? C.selected : undefined;
269
- const fgBase = selected ? C.selectedFg : undefined;
270
-
271
- const bullet = task.enabled ? '* ' : 'o ';
272
- const bulletFg = task.enabled ? C.enabled : C.disabled;
273
- const nameStr = task.name.length > 28 ? task.name.slice(0, 25) + '...' : task.name.padEnd(28);
274
- const scheduleText = formatSchedule(task.schedule);
275
- const row1 = buildPanelLine(width, [
276
- [bullet, bulletFg, bg],
277
- [task.id.slice(0, 12), fgBase ?? C.id, bg],
278
- [' ', fgBase ?? C.prompt, bg],
279
- [nameStr, fgBase ?? C.prompt, bg],
280
- [' ', fgBase ?? C.prompt, bg],
281
- [scheduleText, fgBase ?? C.cron, bg],
282
- ]);
283
-
284
- const indent = ' ';
285
- const nextStr = task.nextRunAt
286
- ? `next: ${new Date(task.nextRunAt).toLocaleString()}`
287
- : 'next: unknown';
288
- const lastStr = task.lastRunAt
289
- ? `last: ${new Date(task.lastRunAt).toLocaleString()}`
290
- : 'last: never';
291
- const row2 = buildPanelLine(width, [
292
- [indent, fgBase ?? C.prompt, bg],
293
- [nextStr.padEnd(36), fgBase ?? C.nextRun, bg],
294
- [lastStr.padEnd(32), fgBase ?? C.lastRun, bg],
295
- [`runs: ${task.runCount}`, fgBase ?? C.runCount, bg],
296
- ]);
297
-
298
- const maxPromptLen = Math.max(20, width - indent.length - 30);
299
- const prompt = task.execution.prompt ?? task.description ?? '';
300
- const promptPreview = prompt.length > maxPromptLen
301
- ? prompt.slice(0, maxPromptLen - 1) + '\u2026'
302
- : prompt;
303
-
304
- // Show last 3 run statuses as colored dots
305
- const recentRuns = history.slice(-3);
306
- const runSegments = recentRuns.flatMap((run) => {
307
- const dotFg = run.status === 'failed' ? C.statusFailed : C.statusRunning;
308
- return [['\u25cf', dotFg, bg] as [string, string, string?]];
309
- });
310
- const row3 = buildPanelLine(width, [
311
- [indent, fgBase ?? C.prompt, bg],
312
- [promptPreview, fgBase ?? C.prompt, bg],
313
- ...(runSegments.length > 0 ? [[' ', fgBase ?? C.prompt, bg] as [string, string, string?], ...runSegments] : []),
314
- ]);
315
-
316
- // spacer row between tasks
317
- const spacer = buildPanelLine(width, [['', fgBase ?? C.prompt, bg]]);
318
-
319
- return [row1, row2, row3, spacer];
320
- }
321
- }