@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,601 +0,0 @@
1
- /**
2
- * SubClusterWrapper - Manages nested cluster lifecycle
3
- *
4
- * Implements same interface as AgentWrapper but spawns a child Orchestrator
5
- * instead of a Claude task. Enables recursive cluster composition.
6
- *
7
- * Lifecycle:
8
- * - On trigger match: spawns nested Orchestrator with child cluster config
9
- * - Passes parent context to child via ISSUE_OPENED equivalent
10
- * - Listens for child CLUSTER_COMPLETE → executes onComplete hook
11
- * - Listens for child CLUSTER_FAILED → executes onError hook
12
- * - Supports maxIterations at subcluster level (restart child on failure)
13
- */
14
-
15
- const LogicEngine = require('./logic-engine');
16
- const MessageBusBridge = require('./message-bus-bridge');
17
- const { DEFAULT_MAX_ITERATIONS } = require('./agent/agent-config');
18
-
19
- class SubClusterWrapper {
20
- constructor(config, messageBus, parentCluster, options = {}) {
21
- this.id = config.id;
22
- this.role = config.role || 'orchestrator';
23
- this.config = config;
24
- this.messageBus = messageBus; // Parent message bus
25
- this.parentCluster = parentCluster;
26
- this.logicEngine = new LogicEngine(messageBus, parentCluster);
27
-
28
- this.state = 'idle';
29
- this.iteration = 0;
30
- this.maxIterations = config.maxIterations || DEFAULT_MAX_ITERATIONS;
31
- this.running = false;
32
- this.unsubscribe = null;
33
-
34
- // Child cluster state
35
- this.childCluster = null; // { id, orchestrator, messageBus, bridge }
36
- this.childClusterId = null;
37
-
38
- this.quiet = options.quiet || false;
39
- this.modelOverride = options.modelOverride || null;
40
- }
41
-
42
- /**
43
- * Log message (respects quiet mode)
44
- * @private
45
- */
46
- _log(...args) {
47
- if (!this.quiet) {
48
- console.log(...args);
49
- }
50
- }
51
-
52
- /**
53
- * Publish lifecycle event to parent message bus
54
- * @private
55
- */
56
- _publishLifecycle(event, details = {}) {
57
- this.messageBus.publish({
58
- cluster_id: this.parentCluster.id,
59
- topic: 'AGENT_LIFECYCLE',
60
- sender: this.id,
61
- receiver: 'system',
62
- content: {
63
- text: `${this.id}: ${event}`,
64
- data: {
65
- event,
66
- agent: this.id,
67
- role: this.role,
68
- state: this.state,
69
- type: 'subcluster',
70
- ...details,
71
- },
72
- },
73
- });
74
- }
75
-
76
- /**
77
- * Start the sub-cluster wrapper (begin listening for triggers)
78
- */
79
- start() {
80
- if (this.running) {
81
- throw new Error(`SubCluster ${this.id} is already running`);
82
- }
83
-
84
- this.running = true;
85
- this.state = 'idle';
86
-
87
- // Subscribe to parent cluster messages
88
- this.unsubscribe = this.messageBus.subscribe((message) => {
89
- if (message.cluster_id === this.parentCluster.id) {
90
- this._handleMessage(message).catch((error) => {
91
- console.error(`\n${'='.repeat(80)}`);
92
- console.error(`🔴 FATAL: SubCluster ${this.id} message handler crashed`);
93
- console.error(`${'='.repeat(80)}`);
94
- console.error(`Topic: ${message.topic}`);
95
- console.error(`Error: ${error.message}`);
96
- console.error(`Stack: ${error.stack}`);
97
- console.error(`${'='.repeat(80)}\n`);
98
- throw error;
99
- });
100
- }
101
- });
102
-
103
- this._log(`SubCluster ${this.id} started (role: ${this.role})`);
104
- this._publishLifecycle('STARTED', {
105
- triggers: this.config.triggers?.map((t) => t.topic) || [],
106
- });
107
- }
108
-
109
- /**
110
- * Stop the sub-cluster wrapper
111
- */
112
- async stop() {
113
- if (!this.running) {
114
- return;
115
- }
116
-
117
- this.running = false;
118
- this.state = 'stopped';
119
-
120
- if (this.unsubscribe) {
121
- this.unsubscribe();
122
- this.unsubscribe = null;
123
- }
124
-
125
- // Stop child cluster if running
126
- if (this.childCluster) {
127
- await this._stopChildCluster();
128
- }
129
-
130
- this._log(`SubCluster ${this.id} stopped`);
131
- }
132
-
133
- /**
134
- * Handle incoming message from parent cluster
135
- * @private
136
- */
137
- async _handleMessage(message) {
138
- // Check if any trigger matches
139
- const matchingTrigger = this._findMatchingTrigger(message);
140
- if (!matchingTrigger) {
141
- return;
142
- }
143
-
144
- // Check state
145
- if (!this.running) {
146
- console.warn(`[${this.id}] ⚠️ DROPPING message (not running): ${message.topic}`);
147
- return;
148
- }
149
- if (this.state !== 'idle') {
150
- console.warn(
151
- `[${this.id}] ⚠️ DROPPING message (busy, state=${this.state}): ${message.topic}`
152
- );
153
- return;
154
- }
155
-
156
- // Evaluate trigger logic
157
- this.state = 'evaluating_logic';
158
- const shouldExecute = this._evaluateTrigger(matchingTrigger, message);
159
-
160
- if (!shouldExecute) {
161
- this.state = 'idle';
162
- return;
163
- }
164
-
165
- // Execute trigger action (spawn child cluster)
166
- await this._handleTrigger(message);
167
- }
168
-
169
- /**
170
- * Find trigger matching the message topic
171
- * @private
172
- */
173
- _findMatchingTrigger(message) {
174
- if (!this.config.triggers) {
175
- return null;
176
- }
177
-
178
- return this.config.triggers.find((trigger) => {
179
- if (trigger.topic === '*' || trigger.topic === message.topic) {
180
- return true;
181
- }
182
- if (trigger.topic.endsWith('*')) {
183
- const prefix = trigger.topic.slice(0, -1);
184
- return message.topic.startsWith(prefix);
185
- }
186
- return false;
187
- });
188
- }
189
-
190
- /**
191
- * Evaluate trigger logic
192
- * @private
193
- */
194
- _evaluateTrigger(trigger, message) {
195
- if (!trigger.logic || !trigger.logic.script) {
196
- return true;
197
- }
198
-
199
- const agent = {
200
- id: this.id,
201
- role: this.role,
202
- iteration: this.iteration,
203
- cluster_id: this.parentCluster.id,
204
- };
205
-
206
- return this.logicEngine.evaluate(trigger.logic.script, agent, message);
207
- }
208
-
209
- /**
210
- * Handle trigger: spawn child cluster
211
- * @private
212
- */
213
- async _handleTrigger(triggeringMessage) {
214
- // Check max iterations
215
- if (this.iteration >= this.maxIterations) {
216
- this._log(`[SubCluster ${this.id}] Hit max iterations (${this.maxIterations}), failing`);
217
- this._publishLifecycle('MAX_ITERATIONS_REACHED', {
218
- iteration: this.iteration,
219
- maxIterations: this.maxIterations,
220
- });
221
-
222
- this.messageBus.publish({
223
- cluster_id: this.parentCluster.id,
224
- topic: 'CLUSTER_FAILED',
225
- sender: this.id,
226
- receiver: 'system',
227
- content: {
228
- text: `SubCluster ${this.id} hit max iterations limit (${this.maxIterations})`,
229
- data: {
230
- reason: 'max_iterations',
231
- iteration: this.iteration,
232
- maxIterations: this.maxIterations,
233
- },
234
- },
235
- });
236
-
237
- this.state = 'failed';
238
- return;
239
- }
240
-
241
- this.iteration++;
242
- this.state = 'spawning_child';
243
-
244
- this._publishLifecycle('SPAWNING_CHILD', {
245
- iteration: this.iteration,
246
- triggeredBy: triggeringMessage.topic,
247
- });
248
-
249
- try {
250
- // Build child cluster context from parent messages
251
- const context = this._buildChildContext(triggeringMessage);
252
-
253
- // Spawn child cluster
254
- await this._spawnChildCluster(context);
255
-
256
- this._publishLifecycle('CHILD_SPAWNED', {
257
- childClusterId: this.childClusterId,
258
- iteration: this.iteration,
259
- });
260
-
261
- this.state = 'monitoring_child';
262
- } catch (error) {
263
- console.error(`\n${'='.repeat(80)}`);
264
- console.error(`🔴 CHILD CLUSTER SPAWN FAILED - ${this.id}`);
265
- console.error(`${'='.repeat(80)}`);
266
- console.error(`Error: ${error.message}`);
267
- console.error(`Stack: ${error.stack}`);
268
- console.error(`${'='.repeat(80)}\n`);
269
-
270
- this.state = 'error';
271
-
272
- // Execute onError hook
273
- await this._executeHook('onError', { error, triggeringMessage });
274
-
275
- // Return to idle if we haven't hit max iterations
276
- if (this.iteration < this.maxIterations) {
277
- this.state = 'idle';
278
- }
279
- }
280
- }
281
-
282
- /**
283
- * Build context for child cluster from parent messages
284
- * @private
285
- */
286
- _buildChildContext(triggeringMessage) {
287
- const parentTopics = this.config.contextStrategy?.parentTopics || [];
288
-
289
- const lines = [
290
- '# Child Cluster Context',
291
- '',
292
- `Parent Cluster: ${this.parentCluster.id}`,
293
- `SubCluster ID: ${this.id}`,
294
- `Iteration: ${this.iteration}`,
295
- '',
296
- ];
297
-
298
- this._appendParentTopicContext(lines, parentTopics);
299
- this._appendTriggeringMessageContext(lines, triggeringMessage);
300
-
301
- return lines.join('\n');
302
- }
303
-
304
- _appendParentTopicContext(lines, parentTopics) {
305
- if (parentTopics.length === 0) {
306
- return;
307
- }
308
-
309
- lines.push('## Parent Cluster Messages', '');
310
-
311
- for (const topic of parentTopics) {
312
- const topicLines = this._buildTopicContextLines(topic);
313
- if (topicLines.length === 0) {
314
- continue;
315
- }
316
-
317
- lines.push(...topicLines);
318
- }
319
- }
320
-
321
- _buildTopicContextLines(topic) {
322
- const messages = this.messageBus.query({
323
- cluster_id: this.parentCluster.id,
324
- topic,
325
- limit: 10,
326
- });
327
-
328
- if (messages.length === 0) {
329
- return [];
330
- }
331
-
332
- const lines = [`### Topic: ${topic}`, ''];
333
-
334
- for (const message of messages) {
335
- lines.push(...this._buildMessageContextLines(message));
336
- lines.push('');
337
- }
338
-
339
- return lines;
340
- }
341
-
342
- _buildMessageContextLines(message) {
343
- const lines = [`[${new Date(message.timestamp).toISOString()}] ${message.sender}:`];
344
- const text = message.content?.text;
345
- const data = message.content?.data;
346
-
347
- if (text) {
348
- lines.push(text);
349
- }
350
-
351
- if (data) {
352
- lines.push(`Data: ${JSON.stringify(data, null, 2)}`);
353
- }
354
-
355
- return lines;
356
- }
357
-
358
- _appendTriggeringMessageContext(lines, triggeringMessage) {
359
- lines.push(
360
- '',
361
- '## Triggering Message',
362
- '',
363
- `Topic: ${triggeringMessage.topic}`,
364
- `Sender: ${triggeringMessage.sender}`
365
- );
366
-
367
- const text = triggeringMessage.content?.text;
368
- if (text) {
369
- lines.push('', text);
370
- }
371
- }
372
-
373
- /**
374
- * Spawn child cluster with nested Orchestrator
375
- * @private
376
- */
377
- async _spawnChildCluster(context) {
378
- const Orchestrator = require('./orchestrator');
379
- const path = require('path');
380
-
381
- // Generate child cluster ID (namespaced under parent)
382
- const childId = `${this.parentCluster.id}.${this.id}`;
383
- this.childClusterId = childId;
384
-
385
- // Create child orchestrator with separate database
386
- const childOrchestrator = await Orchestrator.create({
387
- quiet: this.quiet,
388
- skipLoad: true,
389
- storageDir: path.join(this.parentCluster.ledger.dbPath, '..', 'subclusters', childId),
390
- });
391
-
392
- const childConfig = JSON.parse(JSON.stringify(this.config.config));
393
- const parentConfig = this.parentCluster?.config || {};
394
-
395
- if (parentConfig.forceProvider) {
396
- childConfig.forceProvider = parentConfig.forceProvider;
397
- childConfig.defaultProvider = parentConfig.forceProvider;
398
- if (parentConfig.forceLevel) {
399
- childConfig.forceLevel = parentConfig.forceLevel;
400
- childConfig.defaultLevel = parentConfig.forceLevel;
401
- }
402
- } else if (parentConfig.defaultProvider && !childConfig.defaultProvider) {
403
- childConfig.defaultProvider = parentConfig.defaultProvider;
404
- }
405
-
406
- // Start child cluster with text input (context from parent)
407
- const childCluster = await childOrchestrator.start(
408
- childConfig, // Child cluster config
409
- { text: context },
410
- { testMode: false, modelOverride: this.modelOverride || undefined }
411
- );
412
-
413
- // Create message bridge
414
- const bridge = new MessageBusBridge(this.messageBus, childCluster.messageBus, {
415
- parentClusterId: this.parentCluster.id,
416
- childClusterId: childId,
417
- parentTopics: this.config.contextStrategy?.parentTopics || [],
418
- });
419
-
420
- // Store child cluster state
421
- this.childCluster = {
422
- id: childId,
423
- orchestrator: childOrchestrator,
424
- messageBus: childCluster.messageBus,
425
- bridge,
426
- };
427
-
428
- // Listen for child cluster completion
429
- childCluster.messageBus.subscribe((message) => {
430
- if (message.topic === 'CLUSTER_COMPLETE' && message.cluster_id === childId) {
431
- this._onChildComplete(message).catch((err) => {
432
- console.error(`Failed to handle child completion: ${err.message}`);
433
- });
434
- }
435
- });
436
-
437
- // Listen for child cluster failure
438
- childCluster.messageBus.subscribe((message) => {
439
- if (message.topic === 'CLUSTER_FAILED' && message.cluster_id === childId) {
440
- this._onChildFailed(message).catch((err) => {
441
- console.error(`Failed to handle child failure: ${err.message}`);
442
- });
443
- }
444
- });
445
- }
446
-
447
- /**
448
- * Handle child cluster completion
449
- * @private
450
- */
451
- async _onChildComplete(message) {
452
- this._log(`[SubCluster ${this.id}] Child cluster completed`);
453
-
454
- this._publishLifecycle('CHILD_COMPLETE', {
455
- childClusterId: this.childClusterId,
456
- iteration: this.iteration,
457
- });
458
-
459
- // Execute onComplete hook
460
- await this._executeHook('onComplete', {
461
- result: message,
462
- triggeringMessage: null,
463
- });
464
-
465
- // Clean up child cluster
466
- await this._stopChildCluster();
467
-
468
- this.state = 'idle';
469
- }
470
-
471
- /**
472
- * Handle child cluster failure
473
- * @private
474
- */
475
- async _onChildFailed(message) {
476
- this._log(`[SubCluster ${this.id}] Child cluster failed`);
477
-
478
- this._publishLifecycle('CHILD_FAILED', {
479
- childClusterId: this.childClusterId,
480
- iteration: this.iteration,
481
- error: message.content?.data?.reason,
482
- });
483
-
484
- // Execute onError hook
485
- const error = new Error(message.content?.data?.reason || 'Child cluster failed');
486
- await this._executeHook('onError', { error, triggeringMessage: null });
487
-
488
- // Clean up child cluster
489
- await this._stopChildCluster();
490
-
491
- // Retry if within max iterations
492
- if (this.iteration < this.maxIterations) {
493
- this.state = 'idle';
494
- } else {
495
- this.state = 'failed';
496
- }
497
- }
498
-
499
- /**
500
- * Stop child cluster
501
- * @private
502
- */
503
- async _stopChildCluster() {
504
- if (!this.childCluster) {
505
- return;
506
- }
507
-
508
- // Close message bridge
509
- if (this.childCluster.bridge) {
510
- this.childCluster.bridge.close();
511
- }
512
-
513
- // Stop child orchestrator
514
- try {
515
- await this.childCluster.orchestrator.stop(this.childCluster.id);
516
- } catch (err) {
517
- console.warn(`Warning: Failed to stop child cluster ${this.childCluster.id}: ${err.message}`);
518
- }
519
-
520
- this.childCluster = null;
521
- this.childClusterId = null;
522
- }
523
-
524
- /**
525
- * Execute a hook
526
- * @private
527
- */
528
- _executeHook(hookName, context) {
529
- const hook = this.config.hooks?.[hookName];
530
- if (!hook) {
531
- return;
532
- }
533
-
534
- if (hook.action === 'publish_message') {
535
- const message = this._substituteTemplate(hook.config, context);
536
- this.messageBus.publish({
537
- cluster_id: this.parentCluster.id,
538
- sender: this.id,
539
- ...message,
540
- });
541
- } else {
542
- throw new Error(`Unknown hook action: ${hook.action}`);
543
- }
544
- }
545
-
546
- /**
547
- * Substitute template variables in hook config
548
- * @private
549
- */
550
- _substituteTemplate(config, context) {
551
- if (!config) {
552
- throw new Error('_substituteTemplate: config is required');
553
- }
554
-
555
- const json = JSON.stringify(config);
556
-
557
- let substituted = json
558
- .replace(/\{\{cluster\.id\}\}/g, this.parentCluster.id)
559
- .replace(/\{\{subcluster\.id\}\}/g, this.id)
560
- .replace(/\{\{child\.id\}\}/g, this.childClusterId || '')
561
- .replace(/\{\{iteration\}\}/g, String(this.iteration))
562
- .replace(/\{\{error\.message\}\}/g, context.error?.message || '');
563
-
564
- // Parse and validate
565
- let result;
566
- try {
567
- result = JSON.parse(substituted);
568
- } catch (e) {
569
- console.error('JSON parse failed. Substituted string:');
570
- console.error(substituted);
571
- throw new Error(`Template substitution produced invalid JSON: ${e.message}`);
572
- }
573
-
574
- return result;
575
- }
576
-
577
- /**
578
- * Resume sub-cluster task (not implemented for subclusters)
579
- */
580
- resume(_resumeContext) {
581
- throw new Error('Resume not implemented for subclusters');
582
- }
583
-
584
- /**
585
- * Get current sub-cluster state
586
- */
587
- getState() {
588
- return {
589
- id: this.id,
590
- role: this.role,
591
- state: this.state,
592
- iteration: this.iteration,
593
- maxIterations: this.maxIterations,
594
- type: 'subcluster',
595
- childClusterId: this.childClusterId,
596
- childRunning: this.childCluster !== null,
597
- };
598
- }
599
- }
600
-
601
- module.exports = SubClusterWrapper;
@@ -1,30 +0,0 @@
1
- /**
2
- * TaskRunner - Strategy Pattern interface for executing provider tasks
3
- *
4
- * Implementations must provide a `run()` method that executes a task
5
- * with the given context and options. Different runners can implement various
6
- * execution strategies (CLI, mock responses, etc).
7
- */
8
- class TaskRunner {
9
- /**
10
- * Execute a provider task with the given context and options
11
- *
12
- * @param {string} _context - Full prompt/context for the provider to process
13
- * @param {Object} _options - Execution options
14
- * @param {string} _options.agentId - Identifier for this agent/task
15
- * @param {string} _options.model - Model to use (provider-specific model id)
16
- * @param {string} [_options.provider] - Provider to use (claude|codex|gemini)
17
- * @param {object} [_options.modelSpec] - Resolved model spec (level/model/reasoningEffort)
18
- * @param {string} [_options.outputFormat] - Output format ('text', 'json', 'stream-json')
19
- * @param {Object} [_options.jsonSchema] - JSON schema for structured output validation
20
- * @param {string} [_options.cwd] - Working directory for task execution
21
- * @param {boolean} [_options.isolation] - Whether to run in isolated container
22
- *
23
- * @returns {Promise<{success: boolean, output: string, error: string|null, taskId?: string}>} Result object with success status, output, error message, and optional taskId
24
- */
25
- run(_context, _options) {
26
- throw new Error('TaskRunner.run() not implemented');
27
- }
28
- }
29
-
30
- module.exports = TaskRunner;