@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,574 +0,0 @@
1
- /**
2
- * ClaudeTaskRunner - Production implementation of TaskRunner
3
- *
4
- * Executes provider tasks by spawning the `zeroshot task run` CLI command,
5
- * following logs, and assembling results.
6
- */
7
-
8
- const { spawn } = require('child_process');
9
- const { exec, execSync } = require('./lib/safe-exec'); // Enforces timeouts
10
- const fs = require('fs');
11
- const TaskRunner = require('./task-runner');
12
- const { loadSettings } = require('../lib/settings');
13
- const { normalizeProviderName } = require('../lib/provider-names');
14
- const { getProvider } = require('./providers');
15
-
16
- class ClaudeTaskRunner extends TaskRunner {
17
- /**
18
- * @param {Object} options
19
- * @param {Object} [options.messageBus] - MessageBus for streaming output
20
- * @param {boolean} [options.quiet] - Suppress console logging
21
- * @param {number} [options.timeout] - Task timeout in ms (default: 1 hour)
22
- * @param {Function} [options.onOutput] - Callback for output lines
23
- */
24
- constructor(options = {}) {
25
- super();
26
- this.messageBus = options.messageBus || null;
27
- this.quiet = options.quiet || false;
28
- this.timeout = options.timeout || 60 * 60 * 1000;
29
- this.onOutput = options.onOutput || null;
30
- }
31
-
32
- /**
33
- * @param {...any} args
34
- */
35
- _log(...args) {
36
- if (!this.quiet) {
37
- console.log(...args);
38
- }
39
- }
40
-
41
- /**
42
- * Execute a task via zeroshot CLI
43
- *
44
- * @param {string} context - Full prompt/context
45
- * @param {{agentId?: string, model?: string, outputFormat?: string, jsonSchema?: any, strictSchema?: boolean, cwd?: string, isolation?: any}} options - Execution options
46
- * @returns {Promise<{success: boolean, output: string, error: string|null, taskId?: string}>}
47
- */
48
- async run(context, options = {}) {
49
- const {
50
- agentId = 'unknown',
51
- provider,
52
- model = null,
53
- modelLevel = null,
54
- modelSpec: explicitModelSpec = null,
55
- reasoningEffort = null,
56
- outputFormat = 'stream-json',
57
- jsonSchema = null,
58
- strictSchema = false, // false = live streaming (default), true = CLI schema enforcement (no streaming)
59
- cwd = process.cwd(),
60
- isolation = null,
61
- } = options;
62
-
63
- const settings = loadSettings();
64
- const providerName = normalizeProviderName(provider || settings.defaultProvider || 'claude');
65
- const { providerModule, providerSettings, levelOverrides } = this._getProviderContext(
66
- providerName,
67
- settings
68
- );
69
- const resolvedModelSpec = this._resolveModelSpec({
70
- explicitModelSpec,
71
- model,
72
- reasoningEffort,
73
- modelLevel,
74
- providerModule,
75
- providerSettings,
76
- levelOverrides,
77
- });
78
-
79
- // Isolation mode delegates to separate method
80
- if (isolation?.enabled) {
81
- return this._runIsolated(context, {
82
- ...options,
83
- provider: providerName,
84
- modelSpec: resolvedModelSpec,
85
- });
86
- }
87
-
88
- const ctPath = 'zeroshot';
89
-
90
- const runOutputFormat = this._resolveOutputFormat({
91
- outputFormat,
92
- jsonSchema,
93
- strictSchema,
94
- });
95
- const args = this._buildRunArgs({
96
- context,
97
- providerName,
98
- runOutputFormat,
99
- resolvedModelSpec,
100
- jsonSchema,
101
- });
102
-
103
- // Spawn and get task ID
104
- const spawnEnv = this._buildSpawnEnv(providerName, resolvedModelSpec);
105
-
106
- const taskId = await this._spawnAndGetTaskId(ctPath, args, cwd, spawnEnv, agentId);
107
-
108
- this._log(`📋 [${agentId}]: Following zeroshot logs for ${taskId}`);
109
-
110
- // Wait for task registration
111
- await this._waitForTaskReady(ctPath, taskId);
112
-
113
- // Follow logs until completion
114
- return this._followLogs(ctPath, taskId, agentId);
115
- }
116
-
117
- _getProviderContext(providerName, settings) {
118
- const providerModule = getProvider(providerName);
119
- const providerSettings = settings.providerSettings?.[providerName] || {};
120
- const levelOverrides = providerSettings.levelOverrides || {};
121
- return { providerModule, providerSettings, levelOverrides };
122
- }
123
-
124
- _resolveModelSpec({
125
- explicitModelSpec,
126
- model,
127
- reasoningEffort,
128
- modelLevel,
129
- providerModule,
130
- providerSettings,
131
- levelOverrides,
132
- }) {
133
- if (explicitModelSpec) {
134
- return explicitModelSpec;
135
- }
136
-
137
- if (model) {
138
- return { model, reasoningEffort };
139
- }
140
-
141
- const level = modelLevel || providerSettings.defaultLevel || providerModule.getDefaultLevel();
142
- let resolvedModelSpec = providerModule.resolveModelSpec(level, levelOverrides);
143
- if (reasoningEffort) {
144
- resolvedModelSpec = { ...resolvedModelSpec, reasoningEffort };
145
- }
146
-
147
- return resolvedModelSpec;
148
- }
149
-
150
- _resolveOutputFormat({ outputFormat, jsonSchema, strictSchema }) {
151
- // json output does not stream; if a jsonSchema is configured we run stream-json
152
- // for live logs and validate/parse JSON after completion.
153
- // Set strictSchema=true to disable live streaming and use CLI's native schema enforcement.
154
- return jsonSchema && outputFormat === 'json' && !strictSchema ? 'stream-json' : outputFormat;
155
- }
156
-
157
- _buildRunArgs({ context, providerName, runOutputFormat, resolvedModelSpec, jsonSchema }) {
158
- const args = ['task', 'run', '--output-format', runOutputFormat, '--provider', providerName];
159
-
160
- if (resolvedModelSpec?.model) {
161
- args.push('--model', resolvedModelSpec.model);
162
- }
163
-
164
- if (resolvedModelSpec?.reasoningEffort) {
165
- args.push('--reasoning-effort', resolvedModelSpec.reasoningEffort);
166
- }
167
-
168
- // Pass schema to CLI only when using json output (strictSchema=true or no conflict)
169
- if (jsonSchema && runOutputFormat === 'json') {
170
- args.push('--json-schema', JSON.stringify(jsonSchema));
171
- }
172
-
173
- args.push(context);
174
-
175
- return args;
176
- }
177
-
178
- _buildSpawnEnv(providerName, resolvedModelSpec) {
179
- const spawnEnv = {
180
- ...process.env,
181
- };
182
- if (providerName === 'claude' && resolvedModelSpec?.model) {
183
- spawnEnv.ANTHROPIC_MODEL = resolvedModelSpec.model;
184
- }
185
-
186
- return spawnEnv;
187
- }
188
-
189
- /**
190
- * @param {string} ctPath
191
- * @param {string[]} args
192
- * @param {string} cwd
193
- * @param {Object} spawnEnv
194
- * @param {string} _agentId
195
- * @returns {Promise<string>}
196
- */
197
- _spawnAndGetTaskId(ctPath, args, cwd, spawnEnv, _agentId) {
198
- return new Promise((resolve, reject) => {
199
- const proc = spawn(ctPath, args, {
200
- cwd,
201
- stdio: ['ignore', 'pipe', 'pipe'],
202
- env: spawnEnv,
203
- });
204
-
205
- let stdout = '';
206
- let stderr = '';
207
-
208
- proc.stdout.on('data', (data) => {
209
- stdout += data.toString();
210
- });
211
-
212
- proc.stderr.on('data', (data) => {
213
- stderr += data.toString();
214
- });
215
-
216
- proc.on('close', (code) => {
217
- if (code === 0) {
218
- const match = stdout.match(/Task spawned: ((?:task-)?[a-z]+-[a-z]+-[a-z0-9]+)/);
219
- if (match) {
220
- resolve(match[1]);
221
- } else {
222
- reject(new Error(`Could not parse task ID from output: ${stdout}`));
223
- }
224
- } else {
225
- reject(new Error(`zeroshot task run failed with code ${code}: ${stderr}`));
226
- }
227
- });
228
-
229
- proc.on('error', (error) => {
230
- reject(error);
231
- });
232
- });
233
- }
234
-
235
- /**
236
- * @param {string} ctPath
237
- * @param {string} taskId
238
- * @param {number} maxRetries
239
- * @param {number} delayMs
240
- * @returns {Promise<void>}
241
- */
242
- async _waitForTaskReady(ctPath, taskId, maxRetries = 10, delayMs = 200) {
243
- for (let i = 0; i < maxRetries; i++) {
244
- const exists = await new Promise((resolve) => {
245
- exec(`${ctPath} status ${taskId}`, (error, stdout) => {
246
- resolve(!error && !stdout.includes('Task not found'));
247
- });
248
- });
249
-
250
- if (exists) return;
251
- await new Promise((r) => setTimeout(r, delayMs));
252
- }
253
- console.warn(
254
- `⚠️ Task ${taskId} not yet visible after ${maxRetries} retries, continuing anyway`
255
- );
256
- }
257
-
258
- /**
259
- * @param {string} ctPath
260
- * @param {string} taskId
261
- * @param {string} agentId
262
- * @returns {Promise<{success: boolean, output: string, error: string|null, taskId: string}>}
263
- */
264
- _followLogs(ctPath, taskId, agentId) {
265
- return new Promise((resolve, reject) => {
266
- let output = '';
267
- /** @type {string|null} */
268
- let logFilePath = null;
269
- let lastSize = 0;
270
- /** @type {NodeJS.Timeout|null} */
271
- let pollInterval = null;
272
- /** @type {NodeJS.Timeout|null} */
273
- let statusCheckInterval = null;
274
- let resolved = false;
275
- let lineBuffer = '';
276
-
277
- // Get log file path
278
- try {
279
- logFilePath = execSync(`${ctPath} get-log-path ${taskId}`, {
280
- encoding: 'utf-8',
281
- }).trim();
282
- } catch {
283
- this._log(`⏳ [${agentId}]: Waiting for log file...`);
284
- }
285
-
286
- /**
287
- * @param {string} line
288
- */
289
- const broadcastLine = (line) => {
290
- if (!line.trim()) return;
291
-
292
- let content = line;
293
- const timestampMatch = line.match(/^\[(\d{13})\](.*)$/);
294
- if (timestampMatch) {
295
- content = timestampMatch[2];
296
- }
297
-
298
- // Skip non-JSON patterns
299
- if (
300
- content.startsWith('===') ||
301
- content.startsWith('Finished:') ||
302
- content.startsWith('Exit code:') ||
303
- (content.includes('"type":"system"') && content.includes('"subtype":"init"'))
304
- ) {
305
- return;
306
- }
307
-
308
- if (!content.trim().startsWith('{')) return;
309
-
310
- try {
311
- JSON.parse(content);
312
- } catch {
313
- return;
314
- }
315
-
316
- output += content + '\n';
317
-
318
- // Callback for output streaming
319
- if (this.onOutput) {
320
- this.onOutput(content, agentId);
321
- }
322
- };
323
-
324
- /**
325
- * @param {string} content
326
- */
327
- const processNewContent = (content) => {
328
- lineBuffer += content;
329
- const lines = lineBuffer.split('\n');
330
-
331
- for (let i = 0; i < lines.length - 1; i++) {
332
- broadcastLine(lines[i]);
333
- }
334
- lineBuffer = lines[lines.length - 1];
335
- };
336
-
337
- const pollLogFile = () => {
338
- if (!logFilePath) {
339
- try {
340
- logFilePath = execSync(`${ctPath} get-log-path ${taskId}`, {
341
- encoding: 'utf-8',
342
- }).trim();
343
- } catch {
344
- return;
345
- }
346
- }
347
-
348
- if (!fs.existsSync(logFilePath)) return;
349
-
350
- try {
351
- const stats = fs.statSync(logFilePath);
352
- const currentSize = stats.size;
353
-
354
- if (currentSize > lastSize) {
355
- const fd = fs.openSync(logFilePath, 'r');
356
- const buffer = Buffer.alloc(currentSize - lastSize);
357
- fs.readSync(fd, buffer, 0, buffer.length, lastSize);
358
- fs.closeSync(fd);
359
-
360
- processNewContent(buffer.toString('utf-8'));
361
- lastSize = currentSize;
362
- }
363
- } catch (err) {
364
- const error = /** @type {Error} */ (err);
365
- console.warn(`⚠️ [${agentId}]: Error reading log: ${error.message}`);
366
- }
367
- };
368
-
369
- pollInterval = setInterval(pollLogFile, 300);
370
-
371
- /**
372
- * @param {boolean} success
373
- * @param {string} stdout
374
- * @returns {string|null}
375
- */
376
- const extractErrorContext = (success, stdout) => {
377
- if (success) return null;
378
-
379
- // Try to extract error from status output first
380
- const statusErrorMatch = stdout.match(/Error:\s*(.+)/);
381
- if (statusErrorMatch) {
382
- return statusErrorMatch[1].trim();
383
- }
384
-
385
- // Fall back to last 500 chars of output
386
- const lastOutput = output.slice(-500).trim();
387
- if (!lastOutput) {
388
- return 'Task failed with no output';
389
- }
390
-
391
- const errorPatterns = [
392
- /Error:\s*(.+)/i,
393
- /error:\s*(.+)/i,
394
- /failed:\s*(.+)/i,
395
- /Exception:\s*(.+)/i,
396
- ];
397
-
398
- for (const pattern of errorPatterns) {
399
- const match = lastOutput.match(pattern);
400
- if (match) {
401
- return match[1].slice(0, 200);
402
- }
403
- }
404
-
405
- return `Task failed. Last output: ${lastOutput.slice(-200)}`;
406
- };
407
-
408
- statusCheckInterval = setInterval(() => {
409
- exec(`${ctPath} status ${taskId}`, (error, stdout) => {
410
- if (resolved) return;
411
-
412
- if (
413
- !error &&
414
- (stdout.includes('Status: completed') || stdout.includes('Status: failed'))
415
- ) {
416
- const success = stdout.includes('Status: completed');
417
-
418
- pollLogFile();
419
-
420
- setTimeout(() => {
421
- if (resolved) return;
422
- resolved = true;
423
-
424
- if (pollInterval) clearInterval(pollInterval);
425
- if (statusCheckInterval) clearInterval(statusCheckInterval);
426
-
427
- const errorContext = extractErrorContext(success, stdout);
428
-
429
- resolve({
430
- success,
431
- output,
432
- error: errorContext,
433
- taskId,
434
- });
435
- }, 500);
436
- }
437
- });
438
- }, 1000);
439
-
440
- // Timeout
441
- setTimeout(() => {
442
- if (resolved) return;
443
- resolved = true;
444
-
445
- clearInterval(pollInterval);
446
- clearInterval(statusCheckInterval);
447
-
448
- const timeoutMinutes = Math.round(this.timeout / 60000);
449
- reject(new Error(`Task timed out after ${timeoutMinutes} minutes`));
450
- }, this.timeout);
451
- });
452
- }
453
-
454
- /**
455
- * Run task in isolated Docker container
456
- * @param {string} context
457
- * @param {{agentId?: string, model?: string, outputFormat?: string, jsonSchema?: any, strictSchema?: boolean, isolation?: any}} options
458
- * @returns {Promise<{success: boolean, output: string, error: string|null}>}
459
- */
460
- _runIsolated(context, options) {
461
- const {
462
- agentId = 'unknown',
463
- provider = 'claude',
464
- modelSpec = null,
465
- outputFormat = 'stream-json',
466
- jsonSchema = null,
467
- strictSchema = false,
468
- isolation,
469
- } = options;
470
- const { manager, clusterId } = isolation;
471
-
472
- this._log(`📦 [${agentId}]: Running task in isolated container...`);
473
-
474
- const desiredOutputFormat = outputFormat;
475
- const runOutputFormat =
476
- jsonSchema && desiredOutputFormat === 'json' && !strictSchema
477
- ? 'stream-json'
478
- : desiredOutputFormat;
479
-
480
- const command = [
481
- 'zeroshot',
482
- 'task',
483
- 'run',
484
- '--output-format',
485
- runOutputFormat,
486
- '--provider',
487
- provider,
488
- ];
489
-
490
- if (modelSpec?.model) {
491
- command.push('--model', modelSpec.model);
492
- }
493
-
494
- if (modelSpec?.reasoningEffort) {
495
- command.push('--reasoning-effort', modelSpec.reasoningEffort);
496
- }
497
-
498
- if (jsonSchema && runOutputFormat === 'json') {
499
- command.push('--json-schema', JSON.stringify(jsonSchema));
500
- }
501
-
502
- let finalContext = context;
503
- if (jsonSchema && desiredOutputFormat === 'json' && runOutputFormat === 'stream-json') {
504
- finalContext += `\n\n## Output Format (REQUIRED)\n\nReturn a JSON object that matches this schema exactly.\n\nSchema:\n\`\`\`json\n${JSON.stringify(
505
- jsonSchema,
506
- null,
507
- 2
508
- )}\n\`\`\`\n`;
509
- }
510
-
511
- command.push(finalContext);
512
-
513
- return new Promise((resolve, reject) => {
514
- let output = '';
515
- let resolved = false;
516
-
517
- const proc = manager.spawnInContainer(clusterId, command, {
518
- env:
519
- provider === 'claude' && modelSpec?.model
520
- ? { ANTHROPIC_MODEL: modelSpec.model, ZEROSHOT_BLOCK_ASK_USER: '1' }
521
- : {},
522
- });
523
-
524
- proc.stdout.on('data', (/** @type {Buffer} */ data) => {
525
- const chunk = data.toString();
526
- output += chunk;
527
-
528
- if (this.onOutput) {
529
- this.onOutput(chunk, agentId);
530
- }
531
- });
532
-
533
- proc.stderr.on('data', (/** @type {Buffer} */ data) => {
534
- const chunk = data.toString();
535
- if (!this.quiet) {
536
- console.error(`[${agentId}] stderr:`, chunk);
537
- }
538
- });
539
-
540
- proc.on('close', (/** @type {number|null} */ code) => {
541
- if (resolved) return;
542
- resolved = true;
543
-
544
- resolve({
545
- success: code === 0,
546
- output,
547
- error: code === 0 ? null : `Container exited with code ${code}`,
548
- });
549
- });
550
-
551
- proc.on('error', (/** @type {Error} */ error) => {
552
- if (resolved) return;
553
- resolved = true;
554
- reject(error);
555
- });
556
-
557
- setTimeout(() => {
558
- if (resolved) return;
559
- resolved = true;
560
-
561
- try {
562
- proc.kill('SIGKILL');
563
- } catch {
564
- // Ignore - process may already be dead
565
- }
566
-
567
- const timeoutMinutes = Math.round(this.timeout / 60000);
568
- reject(new Error(`Isolated task timed out after ${timeoutMinutes} minutes`));
569
- }, this.timeout);
570
- });
571
- }
572
- }
573
-
574
- module.exports = ClaudeTaskRunner;
@@ -1,80 +0,0 @@
1
- /**
2
- * Config Router - Maps 2D classification to parameterized templates
3
- *
4
- * Single source of truth for: Complexity × TaskType → { base, params }
5
- * Used by both logic-engine.js (trigger evaluation) and agent-wrapper.js (transform scripts)
6
- */
7
-
8
- const { DEFAULT_MAX_ITERATIONS } = require('./agent/agent-config');
9
-
10
- /**
11
- * Get cluster config based on complexity and task type
12
- * @param {string} complexity - TRIVIAL, SIMPLE, STANDARD, CRITICAL
13
- * @param {string} taskType - INQUIRY, TASK, DEBUG
14
- * @returns {{ base: string, params: object }}
15
- */
16
- function getConfig(complexity, taskType) {
17
- const getBase = () => {
18
- if (taskType === 'DEBUG' && complexity !== 'TRIVIAL') {
19
- return 'debug-workflow';
20
- }
21
- if (complexity === 'TRIVIAL') {
22
- return 'single-worker';
23
- }
24
- if (complexity === 'SIMPLE') {
25
- return 'worker-validator';
26
- }
27
- return 'full-workflow';
28
- };
29
-
30
- const getLevel = (role) => {
31
- if (complexity === 'CRITICAL' && role === 'planner') return 'level3';
32
- if (complexity === 'TRIVIAL') return 'level1';
33
- return 'level2';
34
- };
35
-
36
- const getValidatorCount = () => {
37
- if (complexity === 'TRIVIAL') return 0;
38
- if (complexity === 'SIMPLE') return 1;
39
- if (complexity === 'STANDARD') return 2;
40
- if (complexity === 'CRITICAL') return 4;
41
- return 1;
42
- };
43
-
44
- const getMaxTokens = () => {
45
- if (complexity === 'TRIVIAL') return 50000;
46
- if (complexity === 'SIMPLE') return 100000;
47
- if (complexity === 'STANDARD') return 100000;
48
- if (complexity === 'CRITICAL') return 150000;
49
- return 100000;
50
- };
51
-
52
- const base = getBase();
53
-
54
- const params = {
55
- task_type: taskType,
56
- complexity,
57
- max_tokens: getMaxTokens(),
58
- max_iterations: DEFAULT_MAX_ITERATIONS,
59
- };
60
-
61
- if (base === 'single-worker') {
62
- params.worker_level = getLevel('worker');
63
- } else if (base === 'worker-validator') {
64
- params.worker_level = getLevel('worker');
65
- params.validator_level = getLevel('validator');
66
- } else if (base === 'debug-workflow') {
67
- params.investigator_level = getLevel('planner');
68
- params.fixer_level = getLevel('worker');
69
- params.tester_level = getLevel('validator');
70
- } else if (base === 'full-workflow') {
71
- params.planner_level = getLevel('planner');
72
- params.worker_level = getLevel('worker');
73
- params.validator_level = getLevel('validator');
74
- params.validator_count = getValidatorCount();
75
- }
76
-
77
- return { base, params };
78
- }
79
-
80
- module.exports = { getConfig };