@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
@@ -1,75 +0,0 @@
1
- /**
2
- * Message formatting utilities for CLI output
3
- * Extracted from index.js to reduce complexity
4
- */
5
-
6
- const chalk = require('chalk');
7
-
8
- /**
9
- * Get color for sender based on consistent hashing
10
- * @param {string} sender - Sender name
11
- * @returns {Function} Chalk color function
12
- */
13
- function getColorForSender(sender) {
14
- const colors = [chalk.cyan, chalk.magenta, chalk.yellow, chalk.green, chalk.blue];
15
- let hash = 0;
16
- for (let i = 0; i < sender.length; i++) {
17
- hash = (hash << 5) - hash + sender.charCodeAt(i);
18
- hash = hash & hash;
19
- }
20
- return colors[Math.abs(hash) % colors.length];
21
- }
22
-
23
- /**
24
- * Build message prefix with timestamp, sender, and optional cluster ID
25
- * @param {Object} msg - Message object
26
- * @param {boolean} showClusterId - Whether to show cluster ID
27
- * @param {boolean} isActive - Whether cluster is active
28
- * @returns {string} Formatted prefix
29
- */
30
- function buildMessagePrefix(msg, showClusterId, isActive) {
31
- const color = isActive ? getColorForSender(msg.sender) : chalk.dim;
32
-
33
- let senderLabel = msg.sender;
34
- if (showClusterId && msg.cluster_id) {
35
- senderLabel = `${msg.cluster_id}/${msg.sender}`;
36
- }
37
-
38
- const modelSuffix = msg.sender_model ? chalk.dim(` [${msg.sender_model}]`) : '';
39
- return color(`${senderLabel.padEnd(showClusterId ? 25 : 15)} |`) + modelSuffix;
40
- }
41
-
42
- /**
43
- * Build cluster prefix for watch mode
44
- * @param {string} clusterId - Cluster ID
45
- * @param {boolean} isActive - Whether cluster is active
46
- * @returns {string} Formatted prefix
47
- */
48
- function buildClusterPrefix(clusterId, isActive) {
49
- return isActive
50
- ? chalk.white(`${clusterId.padEnd(20)} |`)
51
- : chalk.dim(`${clusterId.padEnd(20)} |`);
52
- }
53
-
54
- /**
55
- * Parse and normalize data fields (handles string JSON)
56
- * @param {string|Array} data - Data to parse
57
- * @returns {Array} Parsed array
58
- */
59
- function parseDataField(data) {
60
- if (typeof data === 'string') {
61
- try {
62
- return JSON.parse(data);
63
- } catch {
64
- return [];
65
- }
66
- }
67
- return Array.isArray(data) ? data : [];
68
- }
69
-
70
- module.exports = {
71
- getColorForSender,
72
- buildMessagePrefix,
73
- buildClusterPrefix,
74
- parseDataField,
75
- };
@@ -1,275 +0,0 @@
1
- /**
2
- * Normal mode message formatters
3
- * Full-detail message display for non-watch mode
4
- *
5
- * All functions accept an optional `print` parameter for output routing.
6
- * When StatusFooter is active, pass safePrint to avoid terminal garbling.
7
- */
8
-
9
- const chalk = require('chalk');
10
-
11
- /**
12
- * Format AGENT_LIFECYCLE events
13
- * @param {Object} msg - Message object
14
- * @param {string} prefix - Formatted message prefix
15
- * @param {Function} [print=console.log] - Print function for output
16
- * @returns {boolean} True if message was handled
17
- */
18
- function formatAgentLifecycle(msg, prefix, print = console.log) {
19
- const data = msg.content?.data;
20
- const event = data?.event;
21
-
22
- let icon, eventText;
23
- switch (event) {
24
- case 'STARTED':
25
- icon = chalk.green('▶');
26
- const triggers = data.triggers?.join(', ') || 'none';
27
- eventText = `started (listening for: ${chalk.dim(triggers)})`;
28
- break;
29
- case 'TASK_STARTED':
30
- icon = chalk.yellow('⚡');
31
- eventText = `${chalk.cyan(data.triggeredBy)} → task #${data.iteration} (${chalk.dim(data.model)})`;
32
- break;
33
- case 'TASK_COMPLETED':
34
- icon = chalk.green('✓');
35
- eventText = `task #${data.iteration} completed`;
36
- break;
37
- default:
38
- icon = chalk.dim('•');
39
- eventText = event || 'unknown event';
40
- }
41
-
42
- print(`${prefix} ${icon} ${eventText}`);
43
- return true;
44
- }
45
-
46
- /**
47
- * Format AGENT_ERROR events
48
- * @param {Object} msg - Message object
49
- * @param {string} prefix - Formatted message prefix
50
- * @param {string} timestamp - Formatted timestamp
51
- * @param {Function} [print=console.log] - Print function for output
52
- * @returns {boolean} True if message was handled
53
- */
54
- function formatAgentError(msg, prefix, timestamp, print = console.log) {
55
- print(''); // Blank line before error
56
- print(chalk.bold.red(`${'─'.repeat(60)}`));
57
- print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.red('🔴 AGENT ERROR')}`);
58
-
59
- if (msg.content?.text) {
60
- print(`${prefix} ${chalk.red(msg.content.text)}`);
61
- }
62
-
63
- if (msg.content?.data?.stack) {
64
- const stackLines = msg.content.data.stack.split('\n').slice(0, 5);
65
- for (const line of stackLines) {
66
- if (line.trim()) {
67
- print(`${prefix} ${chalk.dim(line)}`);
68
- }
69
- }
70
- }
71
-
72
- print(chalk.bold.red(`${'─'.repeat(60)}`));
73
- return true;
74
- }
75
-
76
- /**
77
- * Format ISSUE_OPENED events
78
- * @param {Object} msg - Message object
79
- * @param {string} prefix - Formatted message prefix
80
- * @param {string} timestamp - Formatted timestamp
81
- * @param {Set} shownNewTaskForCluster - Set tracking shown tasks
82
- * @param {Function} [print=console.log] - Print function for output
83
- * @returns {boolean} True if message was handled
84
- */
85
- function formatIssueOpened(msg, prefix, timestamp, shownNewTaskForCluster, print = console.log) {
86
- // Skip duplicate - conductor re-publishes after spawning agents
87
- if (shownNewTaskForCluster.has(msg.cluster_id)) {
88
- return true;
89
- }
90
- shownNewTaskForCluster.add(msg.cluster_id);
91
-
92
- print(''); // Blank line before new task
93
- print(chalk.bold.blue(`${'─'.repeat(60)}`));
94
- print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.blue('📋 NEW TASK')}`);
95
-
96
- if (msg.content?.text) {
97
- const lines = msg.content.text.split('\n').slice(0, 3);
98
- for (const line of lines) {
99
- if (line.trim() && line.trim() !== '# Manual Input') {
100
- print(`${prefix} ${chalk.white(line)}`);
101
- }
102
- }
103
- }
104
-
105
- print(chalk.bold.blue(`${'─'.repeat(60)}`));
106
- return true;
107
- }
108
-
109
- /**
110
- * Format IMPLEMENTATION_READY events
111
- * @param {Object} msg - Message object
112
- * @param {string} prefix - Formatted message prefix
113
- * @param {string} timestamp - Formatted timestamp
114
- * @param {Function} [print=console.log] - Print function for output
115
- * @returns {boolean} True if message was handled
116
- */
117
- function formatImplementationReady(msg, prefix, timestamp, print = console.log) {
118
- print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.yellow('✅ IMPLEMENTATION READY')}`);
119
-
120
- if (msg.content?.data?.commit) {
121
- print(
122
- `${prefix} ${chalk.gray('Commit:')} ${chalk.cyan(msg.content.data.commit.substring(0, 8))}`
123
- );
124
- }
125
-
126
- return true;
127
- }
128
-
129
- /**
130
- * Format VALIDATION_RESULT events
131
- * @param {Object} msg - Message object
132
- * @param {string} prefix - Formatted message prefix
133
- * @param {string} timestamp - Formatted timestamp
134
- * @param {Function} [print=console.log] - Print function for output
135
- * @returns {boolean} True if message was handled
136
- */
137
- function formatValidationResult(msg, prefix, timestamp, print = console.log) {
138
- const data = msg.content?.data || {};
139
- const approved = data.approved === true || data.approved === 'true';
140
- const status = approved ? chalk.bold.green('✓ APPROVED') : chalk.bold.red('✗ REJECTED');
141
-
142
- print(`${prefix} ${chalk.gray(timestamp)} ${status}`);
143
-
144
- // Show summary if present and not a template variable
145
- if (msg.content?.text && !msg.content.text.includes('{{')) {
146
- print(`${prefix} ${msg.content.text.substring(0, 100)}`);
147
- }
148
-
149
- // Show CANNOT_VALIDATE (permanent) as warnings, CANNOT_VALIDATE_YET (temporary) as errors
150
- const criteriaResults = data.criteriaResults;
151
- if (Array.isArray(criteriaResults)) {
152
- // CANNOT_VALIDATE_YET = temporary, treated as FAIL (work incomplete)
153
- const cannotValidateYet = criteriaResults.filter((c) => c.status === 'CANNOT_VALIDATE_YET');
154
- if (cannotValidateYet.length > 0) {
155
- print(
156
- `${prefix} ${chalk.red('❌ Cannot validate yet')} (${cannotValidateYet.length} criteria - work incomplete):`
157
- );
158
- for (const cv of cannotValidateYet) {
159
- print(`${prefix} ${chalk.red('•')} ${cv.id}: ${cv.reason || 'No reason provided'}`);
160
- }
161
- }
162
-
163
- // CANNOT_VALIDATE = permanent, treated as PASS (environmental limitation)
164
- const cannotValidate = criteriaResults.filter((c) => c.status === 'CANNOT_VALIDATE');
165
- if (cannotValidate.length > 0) {
166
- print(
167
- `${prefix} ${chalk.yellow('⚠️ Could not validate')} (${cannotValidate.length} criteria - permanent):`
168
- );
169
- for (const cv of cannotValidate) {
170
- print(`${prefix} ${chalk.yellow('•')} ${cv.id}: ${cv.reason || 'No reason provided'}`);
171
- }
172
- }
173
- }
174
-
175
- // Show full JSON data structure
176
- print(`${prefix} ${chalk.dim(JSON.stringify(data, null, 2).split('\n').join(`\n${prefix} `))}`);
177
-
178
- return true;
179
- }
180
-
181
- /**
182
- * Format CLUSTER_COMPLETE events
183
- * @param {Object} msg - Message object
184
- * @param {string} prefix - Formatted message prefix
185
- * @param {string} timestamp - Formatted timestamp
186
- * @param {Function} [print=console.log] - Print function for output
187
- * @returns {boolean} True if message was handled
188
- */
189
- function formatClusterComplete(msg, prefix, timestamp, print = console.log) {
190
- print(''); // Blank line
191
- print(chalk.bold.green(`${'═'.repeat(60)}`));
192
- print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.green('🎉 CLUSTER COMPLETE')}`);
193
- if (msg.content?.data?.reason) {
194
- print(`${prefix} ${chalk.green(msg.content.data.reason)}`);
195
- }
196
- print(chalk.bold.green(`${'═'.repeat(60)}`));
197
- return true;
198
- }
199
-
200
- /**
201
- * Format CLUSTER_FAILED events
202
- * @param {Object} msg - Message object
203
- * @param {string} prefix - Formatted message prefix
204
- * @param {string} timestamp - Formatted timestamp
205
- * @param {Function} [print=console.log] - Print function for output
206
- * @returns {boolean} True if message was handled
207
- */
208
- function formatClusterFailed(msg, prefix, timestamp, print = console.log) {
209
- print(''); // Blank line
210
- print(chalk.bold.red(`${'═'.repeat(60)}`));
211
- print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.red('❌ CLUSTER FAILED')}`);
212
- if (msg.content?.text) {
213
- print(`${prefix} ${chalk.red(msg.content.text)}`);
214
- }
215
- if (msg.content?.data?.reason) {
216
- print(`${prefix} ${chalk.red(msg.content.data.reason)}`);
217
- }
218
- print(chalk.bold.red(`${'═'.repeat(60)}`));
219
- return true;
220
- }
221
-
222
- /**
223
- * Format PR_CREATED events
224
- * @param {Object} msg - Message object
225
- * @param {string} prefix - Formatted message prefix
226
- * @param {string} timestamp - Formatted timestamp
227
- * @param {Function} [print=console.log] - Print function for output
228
- * @returns {boolean} True if message was handled
229
- */
230
- function formatPrCreated(msg, prefix, timestamp, print = console.log) {
231
- const prNumber = msg.content?.data?.pr_number || '';
232
- const prUrl = msg.content?.data?.pr_url || '';
233
-
234
- print(''); // Blank line before PR notification
235
- print(chalk.bold.green(`${'─'.repeat(60)}`));
236
- print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold.green('🎉 PULL REQUEST CREATED')}`);
237
-
238
- if (prNumber) {
239
- print(`${prefix} ${chalk.gray('PR:')} ${chalk.cyan(`#${prNumber}`)}`);
240
- }
241
- if (prUrl) {
242
- print(`${prefix} ${chalk.gray('URL:')} ${chalk.blue(prUrl)}`);
243
- }
244
-
245
- print(chalk.bold.green(`${'─'.repeat(60)}`));
246
- return true;
247
- }
248
-
249
- /**
250
- * Format generic messages (fallback)
251
- * @param {Object} msg - Message object
252
- * @param {string} prefix - Formatted message prefix
253
- * @param {string} timestamp - Formatted timestamp
254
- * @param {Function} [print=console.log] - Print function for output
255
- * @returns {boolean} True if message was handled
256
- */
257
- function formatGenericMessage(msg, prefix, timestamp, print = console.log) {
258
- print(`${prefix} ${chalk.gray(timestamp)} ${chalk.bold(msg.topic)}`);
259
- if (msg.content?.text) {
260
- print(`${prefix} ${msg.content.text}`);
261
- }
262
- return true;
263
- }
264
-
265
- module.exports = {
266
- formatAgentLifecycle,
267
- formatAgentError,
268
- formatIssueOpened,
269
- formatImplementationReady,
270
- formatValidationResult,
271
- formatPrCreated,
272
- formatClusterComplete,
273
- formatClusterFailed,
274
- formatGenericMessage,
275
- };
@@ -1,181 +0,0 @@
1
- /**
2
- * Watch mode message formatters
3
- * Simplified, high-level event display for zeroshot watch command
4
- */
5
-
6
- const chalk = require('chalk');
7
- const { buildClusterPrefix, getColorForSender, parseDataField } = require('./message-formatter-utils');
8
-
9
- /**
10
- * Format AGENT_ERROR for watch mode
11
- * @param {Object} msg - Message object
12
- * @param {string} clusterPrefix - Formatted cluster prefix
13
- */
14
- function formatAgentError(msg, clusterPrefix) {
15
- const errorMsg = `${msg.sender} ${chalk.bold.red('ERROR')}`;
16
- console.log(`${clusterPrefix} ${errorMsg}`);
17
- if (msg.content?.text) {
18
- console.log(`${clusterPrefix} ${chalk.red(msg.content.text)}`);
19
- }
20
- }
21
-
22
- /**
23
- * Format ISSUE_OPENED for watch mode
24
- * @param {Object} msg - Message object
25
- * @param {string} clusterPrefix - Formatted cluster prefix
26
- */
27
- function formatIssueOpened(msg, clusterPrefix) {
28
- const issueNum = msg.content?.data?.issue_number || '';
29
- const title = msg.content?.data?.title || '';
30
- const prompt = msg.content?.data?.prompt || msg.content?.text || '';
31
-
32
- const taskDesc = title === 'Manual Input' && prompt ? prompt : title;
33
- const truncatedDesc =
34
- taskDesc && taskDesc.length > 60 ? taskDesc.substring(0, 60) + '...' : taskDesc;
35
-
36
- const eventText = `Started ${issueNum ? `#${issueNum}` : 'task'}${truncatedDesc ? chalk.dim(` - ${truncatedDesc}`) : ''}`;
37
- console.log(`${clusterPrefix} ${eventText}`);
38
- }
39
-
40
- /**
41
- * Format IMPLEMENTATION_READY for watch mode
42
- * @param {Object} msg - Message object
43
- * @param {string} clusterPrefix - Formatted cluster prefix
44
- */
45
- function formatImplementationReady(msg, clusterPrefix) {
46
- const agentColor = getColorForSender(msg.sender);
47
- const agentName = agentColor(msg.sender);
48
- const eventText = `${agentName} completed implementation`;
49
- console.log(`${clusterPrefix} ${eventText}`);
50
- }
51
-
52
- /**
53
- * Format VALIDATION_RESULT for watch mode
54
- * @param {Object} msg - Message object
55
- * @param {string} clusterPrefix - Formatted cluster prefix
56
- */
57
- function formatValidationResult(msg, clusterPrefix) {
58
- const agentColor = getColorForSender(msg.sender);
59
- const agentName = agentColor(msg.sender);
60
- const data = msg.content?.data;
61
- const approved = data?.approved === 'true' || data?.approved === true;
62
- const status = approved ? chalk.green('APPROVED') : chalk.red('REJECTED');
63
-
64
- let eventText = `${agentName} ${status}`;
65
- if (data?.summary && !approved) {
66
- eventText += chalk.dim(` - ${data.summary}`);
67
- }
68
- console.log(`${clusterPrefix} ${eventText}`);
69
-
70
- if (!approved) {
71
- printRejectionDetails(data, clusterPrefix);
72
- }
73
- }
74
-
75
- /**
76
- * Print rejection details (errors/issues)
77
- * @param {Object} data - Validation data
78
- * @param {string} clusterPrefix - Formatted cluster prefix
79
- */
80
- function printRejectionDetails(data, clusterPrefix) {
81
- const errors = parseDataField(data.errors);
82
- const issues = parseDataField(data.issues);
83
-
84
- if (errors.length > 0) {
85
- const errorsCharCount = JSON.stringify(errors).length;
86
- console.log(
87
- `${clusterPrefix} ${chalk.red('•')} ${errors.length} error${errors.length > 1 ? 's' : ''} (${errorsCharCount} chars)`
88
- );
89
- }
90
-
91
- if (issues.length > 0) {
92
- const issuesCharCount = JSON.stringify(issues).length;
93
- console.log(
94
- `${clusterPrefix} ${chalk.yellow('•')} ${issues.length} issue${issues.length > 1 ? 's' : ''} (${issuesCharCount} chars)`
95
- );
96
- }
97
- }
98
-
99
- /**
100
- * Format PR_CREATED for watch mode
101
- * @param {Object} msg - Message object
102
- * @param {string} clusterPrefix - Formatted cluster prefix
103
- */
104
- function formatPrCreated(msg, clusterPrefix) {
105
- const agentColor = getColorForSender(msg.sender);
106
- const agentName = agentColor(msg.sender);
107
- const prNum = msg.content?.data?.pr_number || '';
108
- const eventText = `${agentName} created PR${prNum ? ` #${prNum}` : ''}`;
109
- console.log(`${clusterPrefix} ${eventText}`);
110
- }
111
-
112
- /**
113
- * Format PR_MERGED for watch mode
114
- * @param {Object} msg - Message object
115
- * @param {string} clusterPrefix - Formatted cluster prefix
116
- */
117
- function formatPrMerged(msg, clusterPrefix) {
118
- const agentColor = getColorForSender(msg.sender);
119
- const agentName = agentColor(msg.sender);
120
- const eventText = `${agentName} merged PR`;
121
- console.log(`${clusterPrefix} ${eventText}`);
122
- }
123
-
124
- /**
125
- * Format unknown topic for watch mode (fallback)
126
- * @param {Object} msg - Message object
127
- * @param {string} clusterPrefix - Formatted cluster prefix
128
- */
129
- function formatUnknownTopic(msg, clusterPrefix) {
130
- const agentColor = getColorForSender(msg.sender);
131
- const agentName = agentColor(msg.sender);
132
- const eventText = `${agentName} ${msg.topic.toLowerCase().replace(/_/g, ' ')}`;
133
- console.log(`${clusterPrefix} ${eventText}`);
134
- }
135
-
136
- /**
137
- * Main watch mode formatter
138
- * @param {Object} msg - Message object
139
- * @param {boolean} isActive - Whether cluster is active
140
- * @returns {boolean} True if message was handled
141
- */
142
- function formatWatchMode(msg, isActive) {
143
- // Skip low-level topics (too noisy for watch mode)
144
- if (msg.topic === 'AGENT_OUTPUT' || msg.topic === 'AGENT_LIFECYCLE') {
145
- return true;
146
- }
147
-
148
- // Clear status line, print message, will be redrawn by status interval
149
- process.stdout.write('\r' + ' '.repeat(120) + '\r');
150
-
151
- const clusterPrefix = buildClusterPrefix(msg.cluster_id, isActive);
152
-
153
- switch (msg.topic) {
154
- case 'AGENT_ERROR':
155
- formatAgentError(msg, clusterPrefix);
156
- break;
157
- case 'ISSUE_OPENED':
158
- formatIssueOpened(msg, clusterPrefix);
159
- break;
160
- case 'IMPLEMENTATION_READY':
161
- formatImplementationReady(msg, clusterPrefix);
162
- break;
163
- case 'VALIDATION_RESULT':
164
- formatValidationResult(msg, clusterPrefix);
165
- break;
166
- case 'PR_CREATED':
167
- formatPrCreated(msg, clusterPrefix);
168
- break;
169
- case 'PR_MERGED':
170
- formatPrMerged(msg, clusterPrefix);
171
- break;
172
- default:
173
- formatUnknownTopic(msg, clusterPrefix);
174
- }
175
-
176
- return true;
177
- }
178
-
179
- module.exports = {
180
- formatWatchMode,
181
- };