@covibes/zeroshot 5.4.0 → 5.4.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 (136) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +8 -465
  3. package/cli/index.js +101 -5231
  4. package/package.json +16 -130
  5. package/CHANGELOG.md +0 -537
  6. package/cli/commands/providers.js +0 -149
  7. package/cli/lib/first-run.js +0 -211
  8. package/cli/lib/update-checker.js +0 -281
  9. package/cli/message-formatter-utils.js +0 -75
  10. package/cli/message-formatters-normal.js +0 -275
  11. package/cli/message-formatters-watch.js +0 -181
  12. package/cluster-templates/base-templates/debug-workflow.json +0 -375
  13. package/cluster-templates/base-templates/full-workflow.json +0 -581
  14. package/cluster-templates/base-templates/single-worker.json +0 -63
  15. package/cluster-templates/base-templates/worker-validator.json +0 -208
  16. package/cluster-templates/conductor-bootstrap.json +0 -124
  17. package/docker/zeroshot-cluster/Dockerfile +0 -152
  18. package/docker/zeroshot-cluster/pre-baked-deps.json +0 -28
  19. package/lib/completion.js +0 -174
  20. package/lib/docker-config.js +0 -220
  21. package/lib/git-remote-utils.js +0 -165
  22. package/lib/id-detector.js +0 -56
  23. package/lib/provider-defaults.js +0 -62
  24. package/lib/provider-detection.js +0 -59
  25. package/lib/provider-names.js +0 -57
  26. package/lib/settings/claude-auth.js +0 -78
  27. package/lib/settings.js +0 -503
  28. package/lib/stream-json-parser.js +0 -10
  29. package/scripts/fix-node-pty-permissions.js +0 -75
  30. package/scripts/record-demo.sh +0 -279
  31. package/scripts/setup-merge-queue.sh +0 -170
  32. package/scripts/test-install.sh +0 -40
  33. package/scripts/validate-templates.js +0 -100
  34. package/src/agent/agent-config.js +0 -246
  35. package/src/agent/agent-context-builder.js +0 -444
  36. package/src/agent/agent-hook-executor.js +0 -599
  37. package/src/agent/agent-lifecycle.js +0 -743
  38. package/src/agent/agent-stuck-detector.js +0 -256
  39. package/src/agent/agent-task-executor.js +0 -1690
  40. package/src/agent/agent-trigger-evaluator.js +0 -67
  41. package/src/agent/output-extraction.js +0 -217
  42. package/src/agent/output-reformatter.js +0 -175
  43. package/src/agent/schema-utils.js +0 -146
  44. package/src/agent-wrapper.js +0 -579
  45. package/src/agents/git-pusher-template.js +0 -285
  46. package/src/attach/attach-client.js +0 -438
  47. package/src/attach/attach-server.js +0 -543
  48. package/src/attach/index.js +0 -35
  49. package/src/attach/protocol.js +0 -220
  50. package/src/attach/ring-buffer.js +0 -121
  51. package/src/attach/socket-discovery.js +0 -267
  52. package/src/claude-task-runner.js +0 -574
  53. package/src/config-router.js +0 -80
  54. package/src/config-validator.js +0 -1925
  55. package/src/copy-worker.js +0 -43
  56. package/src/input-helpers.js +0 -65
  57. package/src/isolation-manager.js +0 -1471
  58. package/src/issue-providers/README.md +0 -305
  59. package/src/issue-providers/azure-devops-provider.js +0 -273
  60. package/src/issue-providers/base-provider.js +0 -232
  61. package/src/issue-providers/github-provider.js +0 -179
  62. package/src/issue-providers/gitlab-provider.js +0 -241
  63. package/src/issue-providers/index.js +0 -196
  64. package/src/issue-providers/jira-provider.js +0 -239
  65. package/src/ledger.js +0 -631
  66. package/src/lib/safe-exec.js +0 -88
  67. package/src/logic-engine.js +0 -223
  68. package/src/message-bus-bridge.js +0 -139
  69. package/src/message-bus.js +0 -249
  70. package/src/name-generator.js +0 -232
  71. package/src/orchestrator.js +0 -2815
  72. package/src/preflight.js +0 -639
  73. package/src/process-metrics.js +0 -608
  74. package/src/providers/anthropic/cli-builder.js +0 -73
  75. package/src/providers/anthropic/index.js +0 -204
  76. package/src/providers/anthropic/models.js +0 -23
  77. package/src/providers/anthropic/output-parser.js +0 -177
  78. package/src/providers/base-provider.js +0 -251
  79. package/src/providers/capabilities.js +0 -60
  80. package/src/providers/google/cli-builder.js +0 -55
  81. package/src/providers/google/index.js +0 -116
  82. package/src/providers/google/models.js +0 -24
  83. package/src/providers/google/output-parser.js +0 -101
  84. package/src/providers/index.js +0 -91
  85. package/src/providers/openai/cli-builder.js +0 -133
  86. package/src/providers/openai/index.js +0 -136
  87. package/src/providers/openai/models.js +0 -21
  88. package/src/providers/openai/output-parser.js +0 -143
  89. package/src/providers/opencode/cli-builder.js +0 -42
  90. package/src/providers/opencode/index.js +0 -103
  91. package/src/providers/opencode/models.js +0 -55
  92. package/src/providers/opencode/output-parser.js +0 -122
  93. package/src/schemas/sub-cluster.js +0 -185
  94. package/src/status-footer.js +0 -1026
  95. package/src/sub-cluster-wrapper.js +0 -601
  96. package/src/task-runner.js +0 -30
  97. package/src/template-resolver.js +0 -372
  98. package/src/tui/CHANGES.txt +0 -133
  99. package/src/tui/LAYOUT.md +0 -261
  100. package/src/tui/README.txt +0 -192
  101. package/src/tui/TWO-LEVEL-NAVIGATION.md +0 -186
  102. package/src/tui/data-poller.js +0 -349
  103. package/src/tui/demo.js +0 -208
  104. package/src/tui/formatters.js +0 -129
  105. package/src/tui/index.js +0 -193
  106. package/src/tui/keybindings.js +0 -324
  107. package/src/tui/layout.js +0 -334
  108. package/src/tui/renderer.js +0 -184
  109. package/task-lib/attachable-watcher.js +0 -309
  110. package/task-lib/claude-recovery.js +0 -156
  111. package/task-lib/commands/clean.js +0 -50
  112. package/task-lib/commands/episodes.js +0 -105
  113. package/task-lib/commands/get-log-path.js +0 -23
  114. package/task-lib/commands/kill.js +0 -32
  115. package/task-lib/commands/list.js +0 -105
  116. package/task-lib/commands/logs.js +0 -453
  117. package/task-lib/commands/resume.js +0 -42
  118. package/task-lib/commands/run.js +0 -57
  119. package/task-lib/commands/schedule.js +0 -105
  120. package/task-lib/commands/scheduler-cmd.js +0 -96
  121. package/task-lib/commands/schedules.js +0 -148
  122. package/task-lib/commands/status.js +0 -44
  123. package/task-lib/commands/unschedule.js +0 -16
  124. package/task-lib/completion.js +0 -9
  125. package/task-lib/config.js +0 -8
  126. package/task-lib/name-generator.js +0 -230
  127. package/task-lib/package.json +0 -3
  128. package/task-lib/runner.js +0 -201
  129. package/task-lib/scheduler.js +0 -252
  130. package/task-lib/store.js +0 -529
  131. package/task-lib/tui/formatters.js +0 -215
  132. package/task-lib/tui/index.js +0 -197
  133. package/task-lib/tui/layout.js +0 -111
  134. package/task-lib/tui/renderer.js +0 -129
  135. package/task-lib/tui.js +0 -425
  136. package/task-lib/watcher.js +0 -226
package/src/tui/index.js DELETED
@@ -1,193 +0,0 @@
1
- /**
2
- * TUI - Main interactive dashboard
3
- *
4
- * Coordinates:
5
- * - Screen and layout
6
- * - Data polling
7
- * - Rendering
8
- * - Keybindings
9
- * - State management
10
- */
11
-
12
- const blessed = require('blessed');
13
- const { createLayout } = require('./layout');
14
- const DataPoller = require('./data-poller');
15
- const Renderer = require('./renderer');
16
- const { setupKeybindings } = require('./keybindings');
17
-
18
- class TUI {
19
- constructor(options) {
20
- this.orchestrator = options.orchestrator;
21
- this.filter = options.filter || 'running';
22
- this.refreshRate = options.refreshRate || 1000;
23
-
24
- // State
25
- this.clusters = [];
26
- this.resourceStats = new Map();
27
- this.messages = [];
28
- this.selectedIndex = 0;
29
- this.poller = null;
30
- this.renderer = null;
31
- this.widgets = null;
32
- this.screen = null;
33
-
34
- // View mode: 'overview' or 'detail'
35
- this.viewMode = 'overview';
36
- this.detailClusterId = null;
37
- }
38
-
39
- start() {
40
- // Create screen
41
- this.screen = blessed.screen({
42
- smartCSR: true,
43
- title: 'Vibe Cluster Watch',
44
- dockBorders: true,
45
- fullUnicode: true,
46
- });
47
-
48
- // Create layout
49
- this.widgets = createLayout(this.screen);
50
-
51
- // Show immediate loading message
52
- this.widgets.statsBox.setContent('{center}{bold}Loading...{/bold}{/center}');
53
- this.screen.render();
54
-
55
- // Create renderer
56
- this.renderer = new Renderer(this.widgets, this.screen);
57
-
58
- // Setup keybindings (pass TUI instance for state management)
59
- setupKeybindings(this.screen, this.widgets, this, this.orchestrator);
60
-
61
- // Create data poller
62
- this.poller = new DataPoller(this.orchestrator, {
63
- refreshRate: this.refreshRate,
64
- onUpdate: (update) => this._handleUpdate(update),
65
- });
66
-
67
- // Initial message
68
- this.messages.push({
69
- timestamp: new Date().toISOString(),
70
- text: 'TUI started. Press ? for help.',
71
- level: 'info',
72
- });
73
- this.renderer.renderLogs(this.messages.slice(-20));
74
-
75
- // Start polling
76
- this.poller.start();
77
-
78
- // Initial render
79
- this.screen.render();
80
- }
81
-
82
- _handleUpdate(update) {
83
- // Update state based on update.type
84
- switch (update.type) {
85
- case 'cluster_state':
86
- // Update cluster list
87
- this.clusters = update.clusters;
88
-
89
- // Apply filter
90
- let filteredClusters = this.clusters;
91
- if (this.filter === 'running') {
92
- // For "running" filter, only show truly active (running) clusters
93
- // Exclude initializing, stopped, failed, etc.
94
- filteredClusters = this.clusters.filter((c) => c.state === 'running');
95
- } else if (this.filter !== 'all') {
96
- // For other specific filters, match exact state
97
- filteredClusters = this.clusters.filter((c) => c.state === this.filter);
98
- }
99
-
100
- // Ensure selectedIndex is valid
101
- if (this.selectedIndex >= filteredClusters.length) {
102
- this.selectedIndex = Math.max(0, filteredClusters.length - 1);
103
- }
104
-
105
- // Render clusters table
106
- this.renderer.renderClustersTable(filteredClusters, this.selectedIndex);
107
-
108
- // Render system stats
109
- this.renderer.renderSystemStats(this.clusters, this.resourceStats);
110
-
111
- // Update agent table for selected cluster (ONLY in detail view)
112
- if (this.viewMode === 'detail' && this.detailClusterId) {
113
- // In detail view, show agents for the detail cluster
114
- try {
115
- const status = this.orchestrator.getStatus(this.detailClusterId);
116
- this.renderer.renderAgentTable(status.agents, this.resourceStats);
117
- } catch {
118
- // Cluster might have been stopped/killed
119
- this.renderer.renderAgentTable([], this.resourceStats);
120
- }
121
- } else if (this.viewMode === 'overview') {
122
- // In overview view, don't show agents (or show empty)
123
- this.renderer.renderAgentTable([], this.resourceStats);
124
- }
125
- break;
126
-
127
- case 'resource_stats':
128
- // Update resource stats
129
- this.resourceStats = update.stats;
130
-
131
- // Re-render system stats
132
- this.renderer.renderSystemStats(this.clusters, this.resourceStats);
133
-
134
- // Update agent table with new resource stats (ONLY in detail view)
135
- if (this.viewMode === 'detail' && this.detailClusterId) {
136
- try {
137
- const status = this.orchestrator.getStatus(this.detailClusterId);
138
- this.renderer.renderAgentTable(status.agents, this.resourceStats);
139
- } catch {
140
- this.renderer.renderAgentTable([], this.resourceStats);
141
- }
142
- }
143
- break;
144
-
145
- case 'new_message':
146
- // Only add messages from the selected cluster
147
- const selectedClusterId = this.renderer.selectedClusterId;
148
- if (selectedClusterId && update.clusterId === selectedClusterId) {
149
- // Add new message to log
150
- this.messages.push(update.message);
151
-
152
- // Keep only last 100 messages in memory
153
- if (this.messages.length > 100) {
154
- this.messages = this.messages.slice(-100);
155
- }
156
-
157
- // Render last 20 messages
158
- this.renderer.renderLogs(this.messages.slice(-20));
159
- }
160
- break;
161
-
162
- case 'error':
163
- // Add error to log
164
- this.messages.push({
165
- timestamp: new Date().toISOString(),
166
- text: `✗ ${update.error}`,
167
- level: 'error',
168
- });
169
-
170
- if (this.messages.length > 100) {
171
- this.messages = this.messages.slice(-100);
172
- }
173
-
174
- this.renderer.renderLogs(this.messages.slice(-20));
175
- break;
176
- }
177
-
178
- // Render screen
179
- this.screen.render();
180
- }
181
-
182
- exit() {
183
- if (this.poller) {
184
- this.poller.stop();
185
- }
186
- if (this.screen) {
187
- this.screen.destroy();
188
- }
189
- process.exit(0);
190
- }
191
- }
192
-
193
- module.exports = TUI;
@@ -1,324 +0,0 @@
1
- /**
2
- * Keybindings for TUI
3
- *
4
- * Handles:
5
- * - Navigation (up/down, j/k)
6
- * - Actions (kill, stop, export, logs)
7
- * - Confirmations for destructive actions
8
- */
9
-
10
- const blessed = require('blessed');
11
- const fs = require('fs');
12
- const { spawn } = require('child_process');
13
- const { execSync } = require('../lib/safe-exec'); // Enforces timeouts
14
-
15
- const HELP_TEXT_DETAIL =
16
- '{cyan-fg}[Esc]{/} Back {cyan-fg}[k]{/} Kill {cyan-fg}[s]{/} Stop {cyan-fg}[e]{/} Export {cyan-fg}[l]{/} Logs {cyan-fg}[r]{/} Refresh {cyan-fg}[q]{/} Quit';
17
- const HELP_TEXT_OVERVIEW =
18
- '{cyan-fg}[Enter]{/} View {cyan-fg}[↑/↓]{/} Navigate {cyan-fg}[k]{/} Kill {cyan-fg}[s]{/} Stop {cyan-fg}[l]{/} Logs {cyan-fg}[r]{/} Refresh {cyan-fg}[q]{/} Quit';
19
-
20
- function getSelectedCluster(tui) {
21
- if (tui.clusters.length === 0) {
22
- return null;
23
- }
24
-
25
- return tui.clusters[tui.selectedIndex] || null;
26
- }
27
-
28
- function pushLogMessage(tui, text, level) {
29
- tui.messages.push({
30
- timestamp: new Date().toISOString(),
31
- text,
32
- level,
33
- });
34
- tui.renderer.renderLogs(tui.messages.slice(-20));
35
- }
36
-
37
- function enterDetailView(screen, widgets, tui) {
38
- if (tui.viewMode !== 'overview') {
39
- return;
40
- }
41
-
42
- const selectedCluster = getSelectedCluster(tui);
43
- if (!selectedCluster) {
44
- return;
45
- }
46
-
47
- tui.viewMode = 'detail';
48
- tui.detailClusterId = selectedCluster.id;
49
- tui.renderer.setSelectedCluster(selectedCluster.id);
50
- tui.messages = [];
51
-
52
- widgets.helpBar.setContent(HELP_TEXT_DETAIL);
53
- widgets.clustersTable.hide();
54
- widgets.statsBox.hide();
55
- widgets.agentTable.show();
56
- widgets.logsBox.show();
57
- screen.render();
58
- }
59
-
60
- function exitDetailView(screen, widgets, tui) {
61
- if (tui.viewMode !== 'detail') {
62
- return;
63
- }
64
-
65
- tui.viewMode = 'overview';
66
- tui.detailClusterId = null;
67
- tui.renderer.setSelectedCluster(null);
68
- tui.messages = [];
69
-
70
- widgets.helpBar.setContent(HELP_TEXT_OVERVIEW);
71
- widgets.clustersTable.show();
72
- widgets.statsBox.show();
73
- widgets.agentTable.hide();
74
- widgets.logsBox.hide();
75
- screen.render();
76
- }
77
-
78
- function moveSelection(screen, tui, orchestrator, delta) {
79
- if (tui.clusters.length === 0) {
80
- return;
81
- }
82
-
83
- tui.selectedIndex = Math.min(tui.clusters.length - 1, Math.max(0, tui.selectedIndex + delta));
84
- tui.renderer.renderClustersTable(tui.clusters, tui.selectedIndex);
85
-
86
- const selectedCluster = tui.clusters[tui.selectedIndex];
87
- if (selectedCluster) {
88
- tui.renderer.setSelectedCluster(selectedCluster.id);
89
- tui.messages = [];
90
-
91
- const status = orchestrator.getStatus(selectedCluster.id);
92
- tui.renderer.renderAgentTable(status.agents, tui.resourceStats);
93
- }
94
-
95
- screen.render();
96
- }
97
-
98
- function createConfirmationDialog(screen, label, color) {
99
- const labelText = color
100
- ? ` {bold}{${color}-fg}${label}{/${color}-fg}{/bold} `
101
- : ` {bold}${label}{/bold} `;
102
-
103
- return blessed.question({
104
- parent: screen,
105
- border: 'line',
106
- height: 'shrink',
107
- width: 'half',
108
- top: 'center',
109
- left: 'center',
110
- label: labelText,
111
- tags: true,
112
- keys: true,
113
- vi: true,
114
- });
115
- }
116
-
117
- function confirmClusterAction(options) {
118
- const { screen, tui, selectedCluster, label, color, prompt, action, successText, failureText } =
119
- options;
120
- const question = createConfirmationDialog(screen, label, color);
121
-
122
- question.ask(prompt, async (err, value) => {
123
- if (err || !value) {
124
- return;
125
- }
126
-
127
- try {
128
- await action(selectedCluster);
129
- pushLogMessage(tui, successText(selectedCluster), 'success');
130
- } catch (error) {
131
- pushLogMessage(tui, failureText(error), 'error');
132
- }
133
-
134
- screen.render();
135
- });
136
- }
137
-
138
- function handleKillCluster(screen, tui, orchestrator) {
139
- const selectedCluster = getSelectedCluster(tui);
140
- if (!selectedCluster) {
141
- return;
142
- }
143
-
144
- confirmClusterAction({
145
- screen,
146
- tui,
147
- selectedCluster,
148
- label: 'Confirm Kill',
149
- color: 'red',
150
- prompt: `Kill cluster ${selectedCluster.id}?\n\n(This will force-stop all agents)`,
151
- action: (cluster) => orchestrator.kill(cluster.id),
152
- successText: (cluster) => `✓ Killed cluster ${cluster.id}`,
153
- failureText: (error) => `✗ Failed to kill cluster: ${error.message}`,
154
- });
155
- }
156
-
157
- function handleStopCluster(screen, tui, orchestrator) {
158
- const selectedCluster = getSelectedCluster(tui);
159
- if (!selectedCluster) {
160
- return;
161
- }
162
-
163
- confirmClusterAction({
164
- screen,
165
- tui,
166
- selectedCluster,
167
- label: 'Confirm Stop',
168
- color: 'yellow',
169
- prompt: `Stop cluster ${selectedCluster.id}?\n\n(This will gracefully stop all agents)`,
170
- action: (cluster) => orchestrator.stop(cluster.id),
171
- successText: (cluster) => `✓ Stopped cluster ${cluster.id}`,
172
- failureText: (error) => `✗ Failed to stop cluster: ${error.message}`,
173
- });
174
- }
175
-
176
- function handleExportCluster(screen, tui, orchestrator) {
177
- const selectedCluster = getSelectedCluster(tui);
178
- if (!selectedCluster) {
179
- return;
180
- }
181
-
182
- try {
183
- const markdown = orchestrator.export(selectedCluster.id, 'markdown');
184
- const filename = `${selectedCluster.id}-export.md`;
185
- fs.writeFileSync(filename, markdown);
186
- pushLogMessage(tui, `✓ Exported cluster to ${filename}`, 'success');
187
- } catch (error) {
188
- pushLogMessage(tui, `✗ Failed to export cluster: ${error.message}`, 'error');
189
- }
190
-
191
- screen.render();
192
- }
193
-
194
- function findTerminalCommand() {
195
- const terminals = ['gnome-terminal', 'konsole', 'xterm', 'urxvt', 'alacritty', 'kitty'];
196
-
197
- for (const terminal of terminals) {
198
- try {
199
- execSync(`which ${terminal}`, { stdio: 'ignore' });
200
- return terminal;
201
- } catch {
202
- // Ignore missing terminal
203
- }
204
- }
205
-
206
- return 'xterm';
207
- }
208
-
209
- function buildLogCommand(clusterId) {
210
- const term =
211
- process.env.TERM_PROGRAM || (process.env.COLORTERM ? 'gnome-terminal' : null) || 'xterm';
212
-
213
- if (term === 'iTerm.app' || term === 'Apple_Terminal') {
214
- return {
215
- cmd: 'osascript',
216
- args: ['-e', `tell application "Terminal" to do script "zeroshot logs ${clusterId} -f"`],
217
- };
218
- }
219
-
220
- const cmd = findTerminalCommand();
221
- const logCommand = `zeroshot logs ${clusterId} -f; read -p "Press enter to close..."`;
222
-
223
- if (cmd === 'gnome-terminal' || cmd === 'konsole') {
224
- return { cmd, args: ['--', 'bash', '-c', logCommand] };
225
- }
226
-
227
- return { cmd, args: ['-e', 'bash', '-c', logCommand] };
228
- }
229
-
230
- function handleOpenLogs(screen, tui) {
231
- const selectedCluster = getSelectedCluster(tui);
232
- if (!selectedCluster) {
233
- return;
234
- }
235
-
236
- try {
237
- const { cmd, args } = buildLogCommand(selectedCluster.id);
238
- spawn(cmd, args, { detached: true, stdio: 'ignore' });
239
- pushLogMessage(tui, `✓ Opened logs for ${selectedCluster.id} in new terminal`, 'success');
240
- } catch (error) {
241
- pushLogMessage(tui, `✗ Failed to open logs: ${error.message}`, 'error');
242
- }
243
-
244
- screen.render();
245
- }
246
-
247
- function handleRefresh(screen, tui) {
248
- pushLogMessage(tui, '↻ Refreshing...', 'info');
249
- screen.render();
250
-
251
- if (tui.poller) {
252
- tui.poller.poll();
253
- }
254
- }
255
-
256
- function handleExit(screen, tui) {
257
- const question = createConfirmationDialog(screen, 'Confirm Exit');
258
-
259
- question.ask('Exit TUI?\n\n(Clusters will continue running)', (err, value) => {
260
- if (err || !value) {
261
- return;
262
- }
263
-
264
- tui.exit();
265
- });
266
- }
267
-
268
- function handleHelp(screen) {
269
- const helpBox = blessed.box({
270
- parent: screen,
271
- border: 'line',
272
- height: '80%',
273
- width: '60%',
274
- top: 'center',
275
- left: 'center',
276
- label: ' {bold}Keybindings{/bold} ',
277
- tags: true,
278
- keys: true,
279
- vi: true,
280
- scrollable: true,
281
- alwaysScroll: true,
282
- content: `
283
- {bold}Navigation:{/bold}
284
- ↑/k Move selection up
285
- ↓/j Move selection down
286
-
287
- {bold}Actions:{/bold}
288
- K Kill selected cluster (force stop)
289
- s Stop selected cluster (graceful)
290
- e Export selected cluster to markdown
291
- l Show full logs in new terminal
292
- r Force refresh
293
-
294
- {bold}Other:{/bold}
295
- ?/h Show this help
296
- q/Ctrl-C Exit TUI
297
-
298
- Press any key to close...
299
- `.trim(),
300
- });
301
-
302
- helpBox.key(['escape', 'q', 'enter', 'space'], () => {
303
- helpBox.destroy();
304
- screen.render();
305
- });
306
-
307
- screen.render();
308
- }
309
-
310
- function setupKeybindings(screen, widgets, tui, orchestrator) {
311
- screen.key(['enter'], () => enterDetailView(screen, widgets, tui));
312
- screen.key(['escape'], () => exitDetailView(screen, widgets, tui));
313
- screen.key(['up', 'k'], () => moveSelection(screen, tui, orchestrator, -1));
314
- screen.key(['down', 'j'], () => moveSelection(screen, tui, orchestrator, 1));
315
- screen.key(['K'], () => handleKillCluster(screen, tui, orchestrator));
316
- screen.key(['s'], () => handleStopCluster(screen, tui, orchestrator));
317
- screen.key(['e'], () => handleExportCluster(screen, tui, orchestrator));
318
- screen.key(['l'], () => handleOpenLogs(screen, tui));
319
- screen.key(['r'], () => handleRefresh(screen, tui));
320
- screen.key(['q', 'C-c'], () => handleExit(screen, tui));
321
- screen.key(['?', 'h'], () => handleHelp(screen));
322
- }
323
-
324
- module.exports = { setupKeybindings };