@covibes/zeroshot 5.3.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 (119) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +8 -385
  3. package/cli/index.js +108 -4615
  4. package/package.json +16 -125
  5. package/CHANGELOG.md +0 -537
  6. package/cli/commands/providers.js +0 -150
  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 -253
  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 -697
  14. package/cluster-templates/base-templates/single-worker.json +0 -63
  15. package/cluster-templates/base-templates/worker-validator.json +0 -152
  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 -212
  21. package/lib/id-detector.js +0 -53
  22. package/lib/provider-detection.js +0 -59
  23. package/lib/provider-names.js +0 -56
  24. package/lib/settings.js +0 -405
  25. package/lib/stream-json-parser.js +0 -10
  26. package/scripts/fix-node-pty-permissions.js +0 -75
  27. package/scripts/record-demo.sh +0 -279
  28. package/scripts/test-install.sh +0 -40
  29. package/scripts/validate-templates.js +0 -100
  30. package/src/agent/agent-config.js +0 -193
  31. package/src/agent/agent-context-builder.js +0 -335
  32. package/src/agent/agent-hook-executor.js +0 -402
  33. package/src/agent/agent-lifecycle.js +0 -683
  34. package/src/agent/agent-stuck-detector.js +0 -256
  35. package/src/agent/agent-task-executor.js +0 -1431
  36. package/src/agent/agent-trigger-evaluator.js +0 -67
  37. package/src/agent/output-extraction.js +0 -200
  38. package/src/agent/output-reformatter.js +0 -175
  39. package/src/agent/schema-utils.js +0 -111
  40. package/src/agent-wrapper.js +0 -570
  41. package/src/agents/git-pusher-agent.json +0 -20
  42. package/src/attach/attach-client.js +0 -438
  43. package/src/attach/attach-server.js +0 -543
  44. package/src/attach/index.js +0 -35
  45. package/src/attach/protocol.js +0 -220
  46. package/src/attach/ring-buffer.js +0 -121
  47. package/src/attach/socket-discovery.js +0 -267
  48. package/src/claude-task-runner.js +0 -523
  49. package/src/config-router.js +0 -80
  50. package/src/config-validator.js +0 -1660
  51. package/src/copy-worker.js +0 -43
  52. package/src/github.js +0 -139
  53. package/src/isolation-manager.js +0 -1381
  54. package/src/ledger.js +0 -614
  55. package/src/logic-engine.js +0 -223
  56. package/src/message-bus-bridge.js +0 -139
  57. package/src/message-bus.js +0 -249
  58. package/src/name-generator.js +0 -232
  59. package/src/orchestrator.js +0 -2519
  60. package/src/preflight.js +0 -485
  61. package/src/process-metrics.js +0 -566
  62. package/src/providers/anthropic/cli-builder.js +0 -45
  63. package/src/providers/anthropic/index.js +0 -134
  64. package/src/providers/anthropic/models.js +0 -23
  65. package/src/providers/anthropic/output-parser.js +0 -159
  66. package/src/providers/base-provider.js +0 -181
  67. package/src/providers/capabilities.js +0 -51
  68. package/src/providers/google/cli-builder.js +0 -55
  69. package/src/providers/google/index.js +0 -116
  70. package/src/providers/google/models.js +0 -24
  71. package/src/providers/google/output-parser.js +0 -92
  72. package/src/providers/index.js +0 -75
  73. package/src/providers/openai/cli-builder.js +0 -122
  74. package/src/providers/openai/index.js +0 -135
  75. package/src/providers/openai/models.js +0 -21
  76. package/src/providers/openai/output-parser.js +0 -129
  77. package/src/schemas/sub-cluster.js +0 -156
  78. package/src/status-footer.js +0 -980
  79. package/src/sub-cluster-wrapper.js +0 -560
  80. package/src/task-runner.js +0 -30
  81. package/src/template-resolver.js +0 -369
  82. package/src/tui/CHANGES.txt +0 -133
  83. package/src/tui/LAYOUT.md +0 -261
  84. package/src/tui/README.txt +0 -192
  85. package/src/tui/TWO-LEVEL-NAVIGATION.md +0 -186
  86. package/src/tui/data-poller.js +0 -325
  87. package/src/tui/demo.js +0 -208
  88. package/src/tui/formatters.js +0 -128
  89. package/src/tui/index.js +0 -193
  90. package/src/tui/keybindings.js +0 -383
  91. package/src/tui/layout.js +0 -334
  92. package/src/tui/renderer.js +0 -194
  93. package/task-lib/attachable-watcher.js +0 -272
  94. package/task-lib/claude-recovery.js +0 -119
  95. package/task-lib/commands/clean.js +0 -50
  96. package/task-lib/commands/get-log-path.js +0 -23
  97. package/task-lib/commands/kill.js +0 -32
  98. package/task-lib/commands/list.js +0 -105
  99. package/task-lib/commands/logs.js +0 -411
  100. package/task-lib/commands/resume.js +0 -42
  101. package/task-lib/commands/run.js +0 -57
  102. package/task-lib/commands/schedule.js +0 -105
  103. package/task-lib/commands/scheduler-cmd.js +0 -96
  104. package/task-lib/commands/schedules.js +0 -98
  105. package/task-lib/commands/status.js +0 -44
  106. package/task-lib/commands/unschedule.js +0 -16
  107. package/task-lib/completion.js +0 -9
  108. package/task-lib/config.js +0 -10
  109. package/task-lib/name-generator.js +0 -230
  110. package/task-lib/package.json +0 -3
  111. package/task-lib/runner.js +0 -144
  112. package/task-lib/scheduler.js +0 -252
  113. package/task-lib/store.js +0 -230
  114. package/task-lib/tui/formatters.js +0 -166
  115. package/task-lib/tui/index.js +0 -197
  116. package/task-lib/tui/layout.js +0 -111
  117. package/task-lib/tui/renderer.js +0 -119
  118. package/task-lib/tui.js +0 -384
  119. package/task-lib/watcher.js +0 -188
@@ -1,96 +0,0 @@
1
- import chalk from 'chalk';
2
- import { fork } from 'child_process';
3
- import { join, dirname } from 'path';
4
- import { fileURLToPath } from 'url';
5
- import { getDaemonStatus, stopDaemon } from '../scheduler.js';
6
- import { SCHEDULER_LOG } from '../config.js';
7
- import { existsSync, readFileSync } from 'fs';
8
-
9
- const __dirname = dirname(fileURLToPath(import.meta.url));
10
-
11
- export function schedulerCommand(action) {
12
- switch (action) {
13
- case 'start':
14
- startScheduler();
15
- break;
16
- case 'stop':
17
- stopScheduler();
18
- break;
19
- case 'status':
20
- showStatus();
21
- break;
22
- case 'logs':
23
- showLogs();
24
- break;
25
- default:
26
- console.log(chalk.red(`Unknown action: ${action}`));
27
- console.log(chalk.dim('Available actions: start, stop, status, logs'));
28
- process.exit(1);
29
- }
30
- }
31
-
32
- function startScheduler() {
33
- const status = getDaemonStatus();
34
-
35
- if (status.running) {
36
- console.log(chalk.yellow(`Scheduler already running (PID: ${status.pid})`));
37
- return;
38
- }
39
-
40
- if (status.stale) {
41
- console.log(chalk.dim('Cleaning up stale PID file...'));
42
- }
43
-
44
- console.log(chalk.dim('Starting scheduler daemon...'));
45
-
46
- const scheduler = fork(join(__dirname, '..', 'scheduler.js'), [], {
47
- detached: true,
48
- stdio: 'ignore',
49
- });
50
- scheduler.unref();
51
-
52
- // Give it a moment to start
53
- setTimeout(() => {
54
- const newStatus = getDaemonStatus();
55
- if (newStatus.running) {
56
- console.log(chalk.green(`✓ Scheduler started (PID: ${newStatus.pid})`));
57
- } else {
58
- console.log(chalk.red('Failed to start scheduler. Check logs:'));
59
- console.log(chalk.dim(` zeroshot scheduler logs`));
60
- }
61
- }, 500);
62
- }
63
-
64
- function stopScheduler() {
65
- const stopped = stopDaemon();
66
- if (!stopped) {
67
- process.exit(1);
68
- }
69
- }
70
-
71
- function showStatus() {
72
- const status = getDaemonStatus();
73
-
74
- if (status.running) {
75
- console.log(chalk.green(`Scheduler: running`));
76
- console.log(chalk.dim(` PID: ${status.pid}`));
77
- console.log(chalk.dim(` Log: ${SCHEDULER_LOG}`));
78
- } else if (status.stale) {
79
- console.log(chalk.yellow('Scheduler: not running (stale PID file)'));
80
- console.log(chalk.dim(' Run: zeroshot scheduler start'));
81
- } else {
82
- console.log(chalk.red('Scheduler: not running'));
83
- console.log(chalk.dim(' Run: zeroshot scheduler start'));
84
- }
85
- }
86
-
87
- function showLogs() {
88
- if (!existsSync(SCHEDULER_LOG)) {
89
- console.log(chalk.dim('No scheduler logs found.'));
90
- return;
91
- }
92
-
93
- const content = readFileSync(SCHEDULER_LOG, 'utf-8');
94
- const lines = content.split('\n').slice(-50); // Last 50 lines
95
- console.log(lines.join('\n'));
96
- }
@@ -1,98 +0,0 @@
1
- import chalk from 'chalk';
2
- import { loadSchedules } from '../store.js';
3
- import { getDaemonStatus } from '../scheduler.js';
4
-
5
- export function listSchedules(_options = {}) {
6
- const schedules = loadSchedules();
7
- const scheduleList = Object.values(schedules);
8
-
9
- // Check daemon status
10
- const daemonStatus = getDaemonStatus();
11
-
12
- if (scheduleList.length === 0) {
13
- console.log(chalk.dim('No schedules found.'));
14
- console.log(chalk.dim('\nCreate a schedule:'));
15
- console.log(chalk.dim(' zeroshot schedule "your prompt" --every 1h'));
16
- console.log(chalk.dim(' zeroshot schedule "your prompt" --cron "0 * * * *"'));
17
- return;
18
- }
19
-
20
- // Show daemon status
21
- if (daemonStatus.running) {
22
- console.log(chalk.green(`Scheduler: running (PID: ${daemonStatus.pid})`));
23
- } else if (daemonStatus.stale) {
24
- console.log(chalk.yellow('Scheduler: not running (stale PID file)'));
25
- } else {
26
- console.log(chalk.red('Scheduler: not running'));
27
- console.log(chalk.dim(' Run: zeroshot scheduler start'));
28
- }
29
- console.log();
30
-
31
- // Sort by next run time
32
- scheduleList.sort((a, b) => {
33
- if (!a.nextRunAt) return 1;
34
- if (!b.nextRunAt) return -1;
35
- return new Date(a.nextRunAt) - new Date(b.nextRunAt);
36
- });
37
-
38
- console.log(chalk.bold('Scheduled Tasks:'));
39
- console.log();
40
-
41
- for (const schedule of scheduleList) {
42
- const statusColor = schedule.enabled ? chalk.green : chalk.red;
43
- const statusText = schedule.enabled ? '●' : '○';
44
-
45
- console.log(`${statusColor(statusText)} ${chalk.cyan(schedule.id)}`);
46
- console.log(chalk.dim(` Prompt: ${schedule.prompt}`));
47
-
48
- if (schedule.interval) {
49
- const ms = schedule.interval;
50
- let human;
51
- if (ms >= 7 * 24 * 60 * 60 * 1000) human = `${ms / (7 * 24 * 60 * 60 * 1000)}w`;
52
- else if (ms >= 24 * 60 * 60 * 1000) human = `${ms / (24 * 60 * 60 * 1000)}d`;
53
- else if (ms >= 60 * 60 * 1000) human = `${ms / (60 * 60 * 1000)}h`;
54
- else if (ms >= 60 * 1000) human = `${ms / (60 * 1000)}m`;
55
- else human = `${ms / 1000}s`;
56
- console.log(chalk.dim(` Interval: every ${human}`));
57
- }
58
- if (schedule.cron) {
59
- console.log(chalk.dim(` Cron: ${schedule.cron}`));
60
- }
61
-
62
- if (schedule.nextRunAt) {
63
- const nextRun = new Date(schedule.nextRunAt);
64
- const now = new Date();
65
- const diff = nextRun - now;
66
-
67
- let timeUntil;
68
- if (diff < 0) {
69
- timeUntil = 'overdue';
70
- } else if (diff < 60000) {
71
- timeUntil = 'in < 1m';
72
- } else if (diff < 3600000) {
73
- timeUntil = `in ${Math.round(diff / 60000)}m`;
74
- } else if (diff < 86400000) {
75
- timeUntil = `in ${Math.round(diff / 3600000)}h`;
76
- } else {
77
- timeUntil = `in ${Math.round(diff / 86400000)}d`;
78
- }
79
-
80
- console.log(chalk.dim(` Next run: ${nextRun.toISOString()} (${timeUntil})`));
81
- }
82
-
83
- if (schedule.lastRunAt) {
84
- console.log(chalk.dim(` Last run: ${schedule.lastRunAt}`));
85
- if (schedule.lastTaskId) {
86
- console.log(chalk.dim(` Last task: ${schedule.lastTaskId}`));
87
- }
88
- }
89
-
90
- if (schedule.verify) {
91
- console.log(chalk.dim(` Verify: enabled`));
92
- }
93
-
94
- console.log();
95
- }
96
-
97
- console.log(chalk.dim(`Total: ${scheduleList.length} schedule(s)`));
98
- }
@@ -1,44 +0,0 @@
1
- import chalk from 'chalk';
2
- import { getTask } from '../store.js';
3
- import { isProcessRunning } from '../runner.js';
4
-
5
- export function showStatus(taskId) {
6
- const task = getTask(taskId);
7
-
8
- if (!task) {
9
- console.log(chalk.red(`Task not found: ${taskId}`));
10
- process.exit(1);
11
- }
12
-
13
- // Verify running status
14
- let status = task.status;
15
- if (status === 'running' && !isProcessRunning(task.pid)) {
16
- status = 'stale (process died)';
17
- }
18
-
19
- const statusColor =
20
- {
21
- running: chalk.green,
22
- completed: chalk.green,
23
- failed: chalk.red,
24
- }[task.status] || chalk.yellow;
25
-
26
- console.log(chalk.bold(`\nTask: ${task.id}\n`));
27
- console.log(`${chalk.dim('Status:')} ${statusColor(status)}`);
28
- console.log(`${chalk.dim('Created:')} ${task.createdAt}`);
29
- console.log(`${chalk.dim('Updated:')} ${task.updatedAt}`);
30
- console.log(`${chalk.dim('CWD:')} ${task.cwd}`);
31
- console.log(`${chalk.dim('PID:')} ${task.pid || 'N/A'}`);
32
- console.log(`${chalk.dim('Exit Code:')} ${task.exitCode ?? 'N/A'}`);
33
- console.log(`${chalk.dim('Session:')} ${task.sessionId || 'N/A'}`);
34
- console.log(`${chalk.dim('Log File:')} ${task.logFile}`);
35
-
36
- console.log(`\n${chalk.dim('Prompt:')}`);
37
- console.log(task.fullPrompt || task.prompt);
38
-
39
- if (task.error) {
40
- console.log(`\n${chalk.red('Error:')} ${task.error}`);
41
- }
42
-
43
- console.log();
44
- }
@@ -1,16 +0,0 @@
1
- import chalk from 'chalk';
2
- import { getSchedule, removeSchedule } from '../store.js';
3
-
4
- export function deleteSchedule(scheduleId) {
5
- const schedule = getSchedule(scheduleId);
6
-
7
- if (!schedule) {
8
- console.log(chalk.red(`Schedule not found: ${scheduleId}`));
9
- process.exit(1);
10
- }
11
-
12
- removeSchedule(scheduleId);
13
-
14
- console.log(chalk.green(`✓ Schedule removed: ${chalk.cyan(scheduleId)}`));
15
- console.log(chalk.dim(` Prompt: ${schedule.prompt}`));
16
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Shell completion setup for ct
3
- * Placeholder - completion not yet implemented
4
- */
5
-
6
- export function setupCompletion() {
7
- // TODO: Implement shell completion
8
- // For now, this is a no-op
9
- }
@@ -1,10 +0,0 @@
1
- import { homedir } from 'os';
2
- import { join } from 'path';
3
-
4
- export const TASKS_DIR = join(homedir(), '.claude-zeroshot');
5
- export const TASKS_FILE = join(TASKS_DIR, 'tasks.json');
6
- export const LOGS_DIR = join(TASKS_DIR, 'logs');
7
- export const SCHEDULES_FILE = join(TASKS_DIR, 'schedules.json');
8
- export const SCHEDULER_PID_FILE = join(TASKS_DIR, 'scheduler.pid');
9
- export const SCHEDULER_LOG = join(TASKS_DIR, 'scheduler.log');
10
- export const DEFAULT_MODEL = 'sonnet';
@@ -1,230 +0,0 @@
1
- /**
2
- * Human-readable name generator (like Weights & Biases)
3
- * Generates names like "wandering-forest-42" or "bright-star-17"
4
- *
5
- * No prefix - short forms used everywhere for simplicity
6
- */
7
-
8
- const ADJECTIVES = [
9
- // Colors
10
- 'amber',
11
- 'azure',
12
- 'crimson',
13
- 'emerald',
14
- 'golden',
15
- 'indigo',
16
- 'jade',
17
- 'ruby',
18
- 'sapphire',
19
- 'silver',
20
- 'violet',
21
- 'bronze',
22
- 'coral',
23
- 'ivory',
24
- 'pearl',
25
- 'platinum',
26
- 'scarlet',
27
- 'cobalt',
28
- 'copper',
29
- 'obsidian',
30
- 'onyx',
31
- 'opal',
32
- 'topaz',
33
- 'turquoise',
34
- // Nature
35
- 'wandering',
36
- 'bright',
37
- 'silent',
38
- 'ancient',
39
- 'swift',
40
- 'noble',
41
- 'bold',
42
- 'wild',
43
- 'gentle',
44
- 'hidden',
45
- 'fierce',
46
- 'calm',
47
- 'frozen',
48
- 'misty',
49
- 'stormy',
50
- 'sunny',
51
- // Cosmic
52
- 'cosmic',
53
- 'crystal',
54
- 'electric',
55
- 'lunar',
56
- 'solar',
57
- 'stellar',
58
- 'astral',
59
- 'orbital',
60
- 'mystic',
61
- 'quantum',
62
- 'radiant',
63
- 'twilight',
64
- 'vivid',
65
- 'zen',
66
- 'infinite',
67
- 'eternal',
68
- // Tech/Abstract
69
- 'clever',
70
- 'rapid',
71
- 'steady',
72
- 'agile',
73
- 'nimble',
74
- 'keen',
75
- 'sharp',
76
- 'quick',
77
- 'prime',
78
- 'binary',
79
- 'neural',
80
- 'atomic',
81
- 'sonic',
82
- 'hyper',
83
- 'mega',
84
- 'ultra',
85
- // Descriptive
86
- 'blazing',
87
- 'gleaming',
88
- 'glowing',
89
- 'shining',
90
- 'burning',
91
- 'flaming',
92
- 'sparkling',
93
- 'dazzling',
94
- 'roaring',
95
- 'rushing',
96
- 'soaring',
97
- 'flying',
98
- 'rising',
99
- 'falling',
100
- 'spinning',
101
- 'dancing',
102
- ];
103
-
104
- const NOUNS = [
105
- // Nature
106
- 'forest',
107
- 'river',
108
- 'mountain',
109
- 'ocean',
110
- 'thunder',
111
- 'canyon',
112
- 'summit',
113
- 'valley',
114
- 'cascade',
115
- 'glacier',
116
- 'volcano',
117
- 'desert',
118
- 'meadow',
119
- 'tundra',
120
- 'jungle',
121
- 'reef',
122
- // Space
123
- 'star',
124
- 'comet',
125
- 'nebula',
126
- 'galaxy',
127
- 'pulsar',
128
- 'quasar',
129
- 'aurora',
130
- 'eclipse',
131
- 'meteor',
132
- 'nova',
133
- 'cosmos',
134
- 'orbit',
135
- 'void',
136
- 'horizon',
137
- 'zenith',
138
- 'equinox',
139
- // Mythical
140
- 'phoenix',
141
- 'dragon',
142
- 'griffin',
143
- 'sphinx',
144
- 'hydra',
145
- 'kraken',
146
- 'titan',
147
- 'atlas',
148
- 'oracle',
149
- 'rune',
150
- 'sigil',
151
- 'glyph',
152
- 'totem',
153
- 'aegis',
154
- 'aether',
155
- 'flux',
156
- // Animals
157
- 'falcon',
158
- 'eagle',
159
- 'wolf',
160
- 'bear',
161
- 'tiger',
162
- 'hawk',
163
- 'lion',
164
- 'panther',
165
- 'raven',
166
- 'serpent',
167
- 'shark',
168
- 'owl',
169
- 'fox',
170
- 'lynx',
171
- 'viper',
172
- 'condor',
173
- // Architecture
174
- 'citadel',
175
- 'temple',
176
- 'spire',
177
- 'tower',
178
- 'fortress',
179
- 'bastion',
180
- 'vault',
181
- 'sanctum',
182
- 'beacon',
183
- 'arch',
184
- 'bridge',
185
- 'gate',
186
- 'hall',
187
- 'keep',
188
- 'dome',
189
- 'obelisk',
190
- // Abstract
191
- 'cipher',
192
- 'echo',
193
- 'nexus',
194
- 'prism',
195
- 'relic',
196
- 'vertex',
197
- 'vortex',
198
- 'pulse',
199
- 'surge',
200
- 'spark',
201
- 'flame',
202
- 'storm',
203
- 'wave',
204
- 'drift',
205
- 'shift',
206
- 'core',
207
- ];
208
-
209
- // 96 adjectives × 96 nouns × 100 numbers = 921,600 combinations
210
-
211
- /**
212
- * Generate a human-readable name
213
- * @param {string} _prefix - DEPRECATED: Ignored for backwards compat, short form always used
214
- * @returns {string} Human-readable name (e.g., 'wandering-forest-42')
215
- */
216
- export function generateName(_prefix = '') {
217
- const adjective = ADJECTIVES[Math.floor(Math.random() * ADJECTIVES.length)];
218
- const noun = NOUNS[Math.floor(Math.random() * NOUNS.length)];
219
- const number = Math.floor(Math.random() * 100);
220
-
221
- return `${adjective}-${noun}-${number}`;
222
- }
223
-
224
- /**
225
- * Generate a short unique suffix (for collision prevention)
226
- * @returns {string} Short random suffix (e.g., 'a3f9')
227
- */
228
- export function generateSuffix() {
229
- return Math.random().toString(36).slice(2, 6);
230
- }
@@ -1,3 +0,0 @@
1
- {
2
- "type": "module"
3
- }
@@ -1,144 +0,0 @@
1
- import { fork } from 'child_process';
2
- import { join, dirname } from 'path';
3
- import { fileURLToPath } from 'url';
4
- import { LOGS_DIR } from './config.js';
5
- import { addTask, generateId, ensureDirs } from './store.js';
6
- import { createRequire } from 'module';
7
-
8
- const require = createRequire(import.meta.url);
9
- const { loadSettings } = require('../lib/settings.js');
10
- const { normalizeProviderName } = require('../lib/provider-names');
11
- const { getProvider } = require('../src/providers');
12
-
13
- const __dirname = dirname(fileURLToPath(import.meta.url));
14
-
15
- export async function spawnTask(prompt, options = {}) {
16
- ensureDirs();
17
-
18
- const id = generateId();
19
- const logFile = join(LOGS_DIR, `${id}.log`);
20
- const cwd = options.cwd || process.cwd();
21
-
22
- const settings = loadSettings();
23
- const providerName = normalizeProviderName(
24
- options.provider || settings.defaultProvider || 'claude'
25
- );
26
- const provider = getProvider(providerName);
27
- const providerSettings = settings.providerSettings?.[providerName] || {};
28
- const levelOverrides = providerSettings.levelOverrides || {};
29
-
30
- const outputFormat = options.outputFormat || 'stream-json';
31
-
32
- let jsonSchema = options.jsonSchema || null;
33
- if (jsonSchema && outputFormat !== 'json') {
34
- console.warn('Warning: --json-schema requires --output-format json, ignoring schema');
35
- jsonSchema = null;
36
- }
37
-
38
- let modelSpec;
39
- if (options.model) {
40
- modelSpec = {
41
- model: options.model,
42
- reasoningEffort: options.reasoningEffort,
43
- };
44
- } else {
45
- const level = options.modelLevel || providerSettings.defaultLevel || provider.getDefaultLevel();
46
- modelSpec = provider.resolveModelSpec(level, levelOverrides);
47
- if (options.reasoningEffort) {
48
- modelSpec = { ...modelSpec, reasoningEffort: options.reasoningEffort };
49
- }
50
- }
51
-
52
- const cliFeatures = await provider.getCliFeatures();
53
- const commandSpec = provider.buildCommand(prompt, {
54
- modelSpec,
55
- outputFormat,
56
- jsonSchema,
57
- cwd,
58
- autoApprove: true,
59
- cliFeatures,
60
- });
61
-
62
- const finalArgs = [...commandSpec.args];
63
- if (providerName === 'claude') {
64
- const promptIndex = finalArgs.length - 1;
65
- if (options.resume) {
66
- finalArgs.splice(promptIndex, 0, '--resume', options.resume);
67
- } else if (options.continue) {
68
- finalArgs.splice(promptIndex, 0, '--continue');
69
- }
70
- } else if (options.resume || options.continue) {
71
- console.warn('Warning: resume/continue is only supported for Claude CLI; ignoring.');
72
- }
73
-
74
- const task = {
75
- id,
76
- prompt: prompt.slice(0, 200) + (prompt.length > 200 ? '...' : ''),
77
- fullPrompt: prompt,
78
- cwd,
79
- status: 'running',
80
- pid: null,
81
- sessionId: options.resume || options.sessionId || null,
82
- logFile,
83
- createdAt: new Date().toISOString(),
84
- updatedAt: new Date().toISOString(),
85
- exitCode: null,
86
- error: null,
87
- provider: providerName,
88
- model: modelSpec?.model || null,
89
- // Schedule reference (if spawned by scheduler)
90
- scheduleId: options.scheduleId || null,
91
- // Attach support
92
- socketPath: null,
93
- attachable: false,
94
- };
95
-
96
- addTask(task);
97
-
98
- const watcherConfig = {
99
- outputFormat,
100
- jsonSchema,
101
- silentJsonOutput: options.silentJsonOutput || false,
102
- provider: providerName,
103
- command: commandSpec.binary,
104
- env: commandSpec.env || {},
105
- };
106
-
107
- const useAttachable = options.attachable !== false && !options.jsonSchema;
108
- const watcherScript = useAttachable
109
- ? join(__dirname, 'attachable-watcher.js')
110
- : join(__dirname, 'watcher.js');
111
-
112
- const watcher = fork(
113
- watcherScript,
114
- [id, cwd, logFile, JSON.stringify(finalArgs), JSON.stringify(watcherConfig)],
115
- {
116
- detached: true,
117
- stdio: 'ignore',
118
- }
119
- );
120
-
121
- watcher.unref();
122
-
123
- return task;
124
- }
125
-
126
- export function isProcessRunning(pid) {
127
- if (!pid) return false;
128
- try {
129
- process.kill(pid, 0);
130
- return true;
131
- } catch {
132
- return false;
133
- }
134
- }
135
-
136
- export function killTask(pid) {
137
- if (!pid) return false;
138
- try {
139
- process.kill(pid, 'SIGTERM');
140
- return true;
141
- } catch {
142
- return false;
143
- }
144
- }