@covibes/zeroshot 5.2.1 → 5.4.0
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.
- package/CHANGELOG.md +174 -189
- package/README.md +226 -195
- package/cli/commands/providers.js +149 -0
- package/cli/index.js +3145 -2366
- package/cli/lib/first-run.js +40 -3
- package/cli/message-formatters-normal.js +28 -6
- package/cluster-templates/base-templates/debug-workflow.json +24 -78
- package/cluster-templates/base-templates/full-workflow.json +99 -316
- package/cluster-templates/base-templates/single-worker.json +23 -15
- package/cluster-templates/base-templates/worker-validator.json +105 -36
- package/cluster-templates/conductor-bootstrap.json +9 -7
- package/lib/docker-config.js +14 -1
- package/lib/git-remote-utils.js +165 -0
- package/lib/id-detector.js +10 -7
- package/lib/provider-defaults.js +62 -0
- package/lib/provider-detection.js +59 -0
- package/lib/provider-names.js +57 -0
- package/lib/settings/claude-auth.js +78 -0
- package/lib/settings.js +298 -15
- package/lib/stream-json-parser.js +4 -238
- package/package.json +27 -6
- package/scripts/setup-merge-queue.sh +170 -0
- package/scripts/validate-templates.js +100 -0
- package/src/agent/agent-config.js +140 -63
- package/src/agent/agent-context-builder.js +336 -165
- package/src/agent/agent-hook-executor.js +337 -67
- package/src/agent/agent-lifecycle.js +386 -287
- package/src/agent/agent-stuck-detector.js +7 -7
- package/src/agent/agent-task-executor.js +944 -683
- package/src/agent/output-extraction.js +217 -0
- package/src/agent/output-reformatter.js +175 -0
- package/src/agent/schema-utils.js +146 -0
- package/src/agent-wrapper.js +112 -31
- package/src/agents/git-pusher-template.js +285 -0
- package/src/claude-task-runner.js +145 -44
- package/src/config-router.js +13 -13
- package/src/config-validator.js +1049 -563
- package/src/input-helpers.js +65 -0
- package/src/isolation-manager.js +499 -320
- package/src/issue-providers/README.md +305 -0
- package/src/issue-providers/azure-devops-provider.js +273 -0
- package/src/issue-providers/base-provider.js +232 -0
- package/src/issue-providers/github-provider.js +179 -0
- package/src/issue-providers/gitlab-provider.js +241 -0
- package/src/issue-providers/index.js +196 -0
- package/src/issue-providers/jira-provider.js +239 -0
- package/src/ledger.js +50 -11
- package/src/lib/safe-exec.js +88 -0
- package/src/orchestrator.js +1348 -757
- package/src/preflight.js +306 -149
- package/src/process-metrics.js +98 -56
- package/src/providers/anthropic/cli-builder.js +73 -0
- package/src/providers/anthropic/index.js +204 -0
- package/src/providers/anthropic/models.js +23 -0
- package/src/providers/anthropic/output-parser.js +177 -0
- package/src/providers/base-provider.js +251 -0
- package/src/providers/capabilities.js +60 -0
- package/src/providers/google/cli-builder.js +55 -0
- package/src/providers/google/index.js +116 -0
- package/src/providers/google/models.js +24 -0
- package/src/providers/google/output-parser.js +101 -0
- package/src/providers/index.js +91 -0
- package/src/providers/openai/cli-builder.js +133 -0
- package/src/providers/openai/index.js +136 -0
- package/src/providers/openai/models.js +21 -0
- package/src/providers/openai/output-parser.js +143 -0
- package/src/providers/opencode/cli-builder.js +42 -0
- package/src/providers/opencode/index.js +103 -0
- package/src/providers/opencode/models.js +55 -0
- package/src/providers/opencode/output-parser.js +122 -0
- package/src/schemas/sub-cluster.js +68 -39
- package/src/status-footer.js +94 -48
- package/src/sub-cluster-wrapper.js +92 -36
- package/src/task-runner.js +8 -6
- package/src/template-resolver.js +12 -9
- package/src/tui/data-poller.js +123 -99
- package/src/tui/formatters.js +4 -3
- package/src/tui/keybindings.js +259 -318
- package/src/tui/layout.js +20 -3
- package/src/tui/renderer.js +11 -21
- package/task-lib/attachable-watcher.js +150 -111
- package/task-lib/claude-recovery.js +156 -0
- package/task-lib/commands/episodes.js +105 -0
- package/task-lib/commands/list.js +3 -3
- package/task-lib/commands/logs.js +231 -189
- package/task-lib/commands/resume.js +3 -2
- package/task-lib/commands/run.js +12 -3
- package/task-lib/commands/schedules.js +111 -61
- package/task-lib/config.js +0 -2
- package/task-lib/runner.js +128 -50
- package/task-lib/scheduler.js +3 -3
- package/task-lib/store.js +464 -152
- package/task-lib/tui/formatters.js +94 -45
- package/task-lib/tui/renderer.js +13 -3
- package/task-lib/tui.js +73 -32
- package/task-lib/watcher.js +157 -100
- package/src/agents/git-pusher-agent.json +0 -20
- package/src/github.js +0 -103
|
@@ -10,14 +10,32 @@ export function listSchedules(_options = {}) {
|
|
|
10
10
|
const daemonStatus = getDaemonStatus();
|
|
11
11
|
|
|
12
12
|
if (scheduleList.length === 0) {
|
|
13
|
-
|
|
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 * * * *"'));
|
|
13
|
+
printNoSchedules();
|
|
17
14
|
return;
|
|
18
15
|
}
|
|
19
16
|
|
|
20
|
-
|
|
17
|
+
printDaemonStatus(daemonStatus);
|
|
18
|
+
|
|
19
|
+
// Sort by next run time
|
|
20
|
+
sortSchedulesByNextRun(scheduleList);
|
|
21
|
+
|
|
22
|
+
printScheduleHeader();
|
|
23
|
+
|
|
24
|
+
for (const schedule of scheduleList) {
|
|
25
|
+
printSchedule(schedule);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
console.log(chalk.dim(`Total: ${scheduleList.length} schedule(s)`));
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function printNoSchedules() {
|
|
32
|
+
console.log(chalk.dim('No schedules found.'));
|
|
33
|
+
console.log(chalk.dim('\nCreate a schedule:'));
|
|
34
|
+
console.log(chalk.dim(' zeroshot schedule "your prompt" --every 1h'));
|
|
35
|
+
console.log(chalk.dim(' zeroshot schedule "your prompt" --cron "0 * * * *"'));
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function printDaemonStatus(daemonStatus) {
|
|
21
39
|
if (daemonStatus.running) {
|
|
22
40
|
console.log(chalk.green(`Scheduler: running (PID: ${daemonStatus.pid})`));
|
|
23
41
|
} else if (daemonStatus.stale) {
|
|
@@ -27,72 +45,104 @@ export function listSchedules(_options = {}) {
|
|
|
27
45
|
console.log(chalk.dim(' Run: zeroshot scheduler start'));
|
|
28
46
|
}
|
|
29
47
|
console.log();
|
|
48
|
+
}
|
|
30
49
|
|
|
31
|
-
|
|
50
|
+
function sortSchedulesByNextRun(scheduleList) {
|
|
32
51
|
scheduleList.sort((a, b) => {
|
|
33
52
|
if (!a.nextRunAt) return 1;
|
|
34
53
|
if (!b.nextRunAt) return -1;
|
|
35
54
|
return new Date(a.nextRunAt) - new Date(b.nextRunAt);
|
|
36
55
|
});
|
|
56
|
+
}
|
|
37
57
|
|
|
58
|
+
function printScheduleHeader() {
|
|
38
59
|
console.log(chalk.bold('Scheduled Tasks:'));
|
|
39
60
|
console.log();
|
|
61
|
+
}
|
|
40
62
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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();
|
|
63
|
+
function printSchedule(schedule) {
|
|
64
|
+
printScheduleHeaderLine(schedule);
|
|
65
|
+
printSchedulePrompt(schedule);
|
|
66
|
+
printScheduleInterval(schedule);
|
|
67
|
+
printScheduleCron(schedule);
|
|
68
|
+
printScheduleNextRun(schedule);
|
|
69
|
+
printScheduleLastRun(schedule);
|
|
70
|
+
printScheduleVerify(schedule);
|
|
71
|
+
console.log();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function printScheduleHeaderLine(schedule) {
|
|
75
|
+
const statusColor = schedule.enabled ? chalk.green : chalk.red;
|
|
76
|
+
const statusText = schedule.enabled ? '●' : '○';
|
|
77
|
+
console.log(`${statusColor(statusText)} ${chalk.cyan(schedule.id)}`);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function printSchedulePrompt(schedule) {
|
|
81
|
+
console.log(chalk.dim(` Prompt: ${schedule.prompt}`));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function printScheduleInterval(schedule) {
|
|
85
|
+
if (!schedule.interval) {
|
|
86
|
+
return;
|
|
95
87
|
}
|
|
88
|
+
const human = formatInterval(schedule.interval);
|
|
89
|
+
console.log(chalk.dim(` Interval: every ${human}`));
|
|
90
|
+
}
|
|
96
91
|
|
|
97
|
-
|
|
92
|
+
function printScheduleCron(schedule) {
|
|
93
|
+
if (schedule.cron) {
|
|
94
|
+
console.log(chalk.dim(` Cron: ${schedule.cron}`));
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function printScheduleNextRun(schedule) {
|
|
99
|
+
if (!schedule.nextRunAt) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const nextRun = new Date(schedule.nextRunAt);
|
|
103
|
+
const timeUntil = formatTimeUntil(nextRun);
|
|
104
|
+
console.log(chalk.dim(` Next run: ${nextRun.toISOString()} (${timeUntil})`));
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function printScheduleLastRun(schedule) {
|
|
108
|
+
if (!schedule.lastRunAt) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
console.log(chalk.dim(` Last run: ${schedule.lastRunAt}`));
|
|
112
|
+
if (schedule.lastTaskId) {
|
|
113
|
+
console.log(chalk.dim(` Last task: ${schedule.lastTaskId}`));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function printScheduleVerify(schedule) {
|
|
118
|
+
if (schedule.verify) {
|
|
119
|
+
console.log(chalk.dim(` Verify: enabled`));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function formatInterval(ms) {
|
|
124
|
+
if (ms >= 7 * 24 * 60 * 60 * 1000) return `${ms / (7 * 24 * 60 * 60 * 1000)}w`;
|
|
125
|
+
if (ms >= 24 * 60 * 60 * 1000) return `${ms / (24 * 60 * 60 * 1000)}d`;
|
|
126
|
+
if (ms >= 60 * 60 * 1000) return `${ms / (60 * 60 * 1000)}h`;
|
|
127
|
+
if (ms >= 60 * 1000) return `${ms / (60 * 1000)}m`;
|
|
128
|
+
return `${ms / 1000}s`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function formatTimeUntil(nextRun) {
|
|
132
|
+
const now = new Date();
|
|
133
|
+
const diff = nextRun - now;
|
|
134
|
+
|
|
135
|
+
if (diff < 0) {
|
|
136
|
+
return 'overdue';
|
|
137
|
+
}
|
|
138
|
+
if (diff < 60000) {
|
|
139
|
+
return 'in < 1m';
|
|
140
|
+
}
|
|
141
|
+
if (diff < 3600000) {
|
|
142
|
+
return `in ${Math.round(diff / 60000)}m`;
|
|
143
|
+
}
|
|
144
|
+
if (diff < 86400000) {
|
|
145
|
+
return `in ${Math.round(diff / 3600000)}h`;
|
|
146
|
+
}
|
|
147
|
+
return `in ${Math.round(diff / 86400000)}d`;
|
|
98
148
|
}
|
package/task-lib/config.js
CHANGED
|
@@ -2,9 +2,7 @@ import { homedir } from 'os';
|
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
|
|
4
4
|
export const TASKS_DIR = join(homedir(), '.claude-zeroshot');
|
|
5
|
-
export const TASKS_FILE = join(TASKS_DIR, 'tasks.json');
|
|
6
5
|
export const LOGS_DIR = join(TASKS_DIR, 'logs');
|
|
7
|
-
export const SCHEDULES_FILE = join(TASKS_DIR, 'schedules.json');
|
|
8
6
|
export const SCHEDULER_PID_FILE = join(TASKS_DIR, 'scheduler.pid');
|
|
9
7
|
export const SCHEDULER_LOG = join(TASKS_DIR, 'scheduler.log');
|
|
10
8
|
export const DEFAULT_MODEL = 'sonnet';
|
package/task-lib/runner.js
CHANGED
|
@@ -1,56 +1,133 @@
|
|
|
1
1
|
import { fork } from 'child_process';
|
|
2
2
|
import { join, dirname } from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
|
-
import { LOGS_DIR
|
|
4
|
+
import { LOGS_DIR } from './config.js';
|
|
5
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');
|
|
6
12
|
|
|
7
13
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
14
|
|
|
9
|
-
export function spawnTask(prompt, options = {}) {
|
|
15
|
+
export async function spawnTask(prompt, options = {}) {
|
|
10
16
|
ensureDirs();
|
|
11
17
|
|
|
12
18
|
const id = generateId();
|
|
13
19
|
const logFile = join(LOGS_DIR, `${id}.log`);
|
|
14
20
|
const cwd = options.cwd || process.cwd();
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
21
|
+
|
|
22
|
+
const settings = loadSettings();
|
|
23
|
+
const { providerName, provider, providerSettings, levelOverrides } = resolveProviderContext(
|
|
24
|
+
options,
|
|
25
|
+
settings
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const outputFormat = resolveOutputFormat(options);
|
|
29
|
+
const jsonSchema = resolveJsonSchema(options, outputFormat);
|
|
30
|
+
const modelSpec = resolveModelSpec(options, provider, providerSettings, levelOverrides);
|
|
31
|
+
|
|
32
|
+
const cliFeatures = await provider.getCliFeatures();
|
|
33
|
+
const commandSpec = provider.buildCommand(prompt, {
|
|
34
|
+
modelSpec,
|
|
35
|
+
outputFormat,
|
|
36
|
+
jsonSchema,
|
|
37
|
+
cwd,
|
|
38
|
+
autoApprove: true,
|
|
39
|
+
cliFeatures,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const finalArgs = resolveFinalArgs(commandSpec, providerName, options);
|
|
43
|
+
const task = buildTaskRecord({
|
|
44
|
+
id,
|
|
45
|
+
prompt,
|
|
46
|
+
cwd,
|
|
47
|
+
options,
|
|
48
|
+
logFile,
|
|
49
|
+
providerName,
|
|
50
|
+
modelSpec,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
addTask(task);
|
|
54
|
+
|
|
55
|
+
const watcherConfig = buildWatcherConfig(
|
|
56
|
+
outputFormat,
|
|
57
|
+
jsonSchema,
|
|
58
|
+
options,
|
|
59
|
+
providerName,
|
|
60
|
+
commandSpec
|
|
61
|
+
);
|
|
62
|
+
const watcherScript = resolveWatcherScript(options);
|
|
63
|
+
spawnWatcher({
|
|
64
|
+
watcherScript,
|
|
65
|
+
id,
|
|
66
|
+
cwd,
|
|
67
|
+
logFile,
|
|
68
|
+
finalArgs,
|
|
69
|
+
watcherConfig,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
return task;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function resolveProviderContext(options, settings) {
|
|
76
|
+
const providerName = normalizeProviderName(
|
|
77
|
+
options.provider || settings.defaultProvider || 'claude'
|
|
78
|
+
);
|
|
79
|
+
const provider = getProvider(providerName);
|
|
80
|
+
const providerSettings = settings.providerSettings?.[providerName] || {};
|
|
81
|
+
const levelOverrides = providerSettings.levelOverrides || {};
|
|
82
|
+
return { providerName, provider, providerSettings, levelOverrides };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function resolveOutputFormat(options) {
|
|
86
|
+
return options.outputFormat || 'stream-json';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function resolveJsonSchema(options, outputFormat) {
|
|
90
|
+
let jsonSchema = options.jsonSchema || null;
|
|
91
|
+
if (jsonSchema && outputFormat !== 'json') {
|
|
92
|
+
console.warn('Warning: --json-schema requires --output-format json, ignoring schema');
|
|
93
|
+
jsonSchema = null;
|
|
29
94
|
}
|
|
95
|
+
return jsonSchema;
|
|
96
|
+
}
|
|
30
97
|
|
|
31
|
-
|
|
32
|
-
if (options.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const schemaString =
|
|
38
|
-
typeof options.jsonSchema === 'string'
|
|
39
|
-
? options.jsonSchema
|
|
40
|
-
: JSON.stringify(options.jsonSchema);
|
|
41
|
-
args.push('--json-schema', schemaString);
|
|
42
|
-
}
|
|
98
|
+
function resolveModelSpec(options, provider, providerSettings, levelOverrides) {
|
|
99
|
+
if (options.model) {
|
|
100
|
+
return {
|
|
101
|
+
model: options.model,
|
|
102
|
+
reasoningEffort: options.reasoningEffort,
|
|
103
|
+
};
|
|
43
104
|
}
|
|
44
105
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
106
|
+
const level = options.modelLevel || providerSettings.defaultLevel || provider.getDefaultLevel();
|
|
107
|
+
let modelSpec = provider.resolveModelSpec(level, levelOverrides);
|
|
108
|
+
if (options.reasoningEffort) {
|
|
109
|
+
modelSpec = { ...modelSpec, reasoningEffort: options.reasoningEffort };
|
|
49
110
|
}
|
|
111
|
+
return modelSpec;
|
|
112
|
+
}
|
|
50
113
|
|
|
51
|
-
|
|
114
|
+
function resolveFinalArgs(commandSpec, providerName, options) {
|
|
115
|
+
const finalArgs = [...commandSpec.args];
|
|
116
|
+
if (providerName === 'claude') {
|
|
117
|
+
const promptIndex = finalArgs.length - 1;
|
|
118
|
+
if (options.resume) {
|
|
119
|
+
finalArgs.splice(promptIndex, 0, '--resume', options.resume);
|
|
120
|
+
} else if (options.continue) {
|
|
121
|
+
finalArgs.splice(promptIndex, 0, '--continue');
|
|
122
|
+
}
|
|
123
|
+
} else if (options.resume || options.continue) {
|
|
124
|
+
console.warn('Warning: resume/continue is only supported for Claude CLI; ignoring.');
|
|
125
|
+
}
|
|
126
|
+
return finalArgs;
|
|
127
|
+
}
|
|
52
128
|
|
|
53
|
-
|
|
129
|
+
function buildTaskRecord({ id, prompt, cwd, options, logFile, providerName, modelSpec }) {
|
|
130
|
+
return {
|
|
54
131
|
id,
|
|
55
132
|
prompt: prompt.slice(0, 200) + (prompt.length > 200 ? '...' : ''),
|
|
56
133
|
fullPrompt: prompt,
|
|
@@ -63,33 +140,36 @@ export function spawnTask(prompt, options = {}) {
|
|
|
63
140
|
updatedAt: new Date().toISOString(),
|
|
64
141
|
exitCode: null,
|
|
65
142
|
error: null,
|
|
143
|
+
provider: providerName,
|
|
144
|
+
model: modelSpec?.model || null,
|
|
66
145
|
// Schedule reference (if spawned by scheduler)
|
|
67
146
|
scheduleId: options.scheduleId || null,
|
|
68
147
|
// Attach support
|
|
69
148
|
socketPath: null,
|
|
70
149
|
attachable: false,
|
|
71
150
|
};
|
|
151
|
+
}
|
|
72
152
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
// Fork a watcher process that will manage the claude process
|
|
76
|
-
const watcherConfig = {
|
|
153
|
+
function buildWatcherConfig(outputFormat, jsonSchema, options, providerName, commandSpec) {
|
|
154
|
+
return {
|
|
77
155
|
outputFormat,
|
|
78
|
-
jsonSchema
|
|
156
|
+
jsonSchema,
|
|
79
157
|
silentJsonOutput: options.silentJsonOutput || false,
|
|
80
|
-
|
|
158
|
+
provider: providerName,
|
|
159
|
+
command: commandSpec.binary,
|
|
160
|
+
env: commandSpec.env || {},
|
|
81
161
|
};
|
|
162
|
+
}
|
|
82
163
|
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
? join(__dirname, 'attachable-watcher.js')
|
|
88
|
-
: join(__dirname, 'watcher.js');
|
|
164
|
+
function resolveWatcherScript(options) {
|
|
165
|
+
const useAttachable = options.attachable !== false && !options.jsonSchema;
|
|
166
|
+
return useAttachable ? join(__dirname, 'attachable-watcher.js') : join(__dirname, 'watcher.js');
|
|
167
|
+
}
|
|
89
168
|
|
|
169
|
+
function spawnWatcher({ watcherScript, id, cwd, logFile, finalArgs, watcherConfig }) {
|
|
90
170
|
const watcher = fork(
|
|
91
171
|
watcherScript,
|
|
92
|
-
[id, cwd, logFile, JSON.stringify(
|
|
172
|
+
[id, cwd, logFile, JSON.stringify(finalArgs), JSON.stringify(watcherConfig)],
|
|
93
173
|
{
|
|
94
174
|
detached: true,
|
|
95
175
|
stdio: 'ignore',
|
|
@@ -97,9 +177,7 @@ export function spawnTask(prompt, options = {}) {
|
|
|
97
177
|
);
|
|
98
178
|
|
|
99
179
|
watcher.unref();
|
|
100
|
-
|
|
101
|
-
// Return task immediately - watcher will update PID async
|
|
102
|
-
return task;
|
|
180
|
+
watcher.disconnect(); // Close IPC channel so parent can exit
|
|
103
181
|
}
|
|
104
182
|
|
|
105
183
|
export function isProcessRunning(pid) {
|
package/task-lib/scheduler.js
CHANGED
|
@@ -17,7 +17,7 @@ const CHECK_INTERVAL = 60000; // 60 seconds
|
|
|
17
17
|
* Supports: 30s, 5m, 2h, 1d, 1w
|
|
18
18
|
*/
|
|
19
19
|
export function parseInterval(str) {
|
|
20
|
-
const match = str.match(/^(\d+)(
|
|
20
|
+
const match = str.match(/^(\d+)([smhdw])$/i);
|
|
21
21
|
if (!match) return null;
|
|
22
22
|
|
|
23
23
|
const value = parseInt(match[1], 10);
|
|
@@ -108,7 +108,7 @@ function log(msg) {
|
|
|
108
108
|
/**
|
|
109
109
|
* Check and run due schedules
|
|
110
110
|
*/
|
|
111
|
-
function checkSchedules() {
|
|
111
|
+
async function checkSchedules() {
|
|
112
112
|
const schedules = loadSchedules();
|
|
113
113
|
const now = new Date();
|
|
114
114
|
|
|
@@ -122,7 +122,7 @@ function checkSchedules() {
|
|
|
122
122
|
log(`Running scheduled task: ${schedule.id} - "${schedule.prompt.slice(0, 50)}..."`);
|
|
123
123
|
|
|
124
124
|
try {
|
|
125
|
-
const task = spawnTask(schedule.prompt, {
|
|
125
|
+
const task = await spawnTask(schedule.prompt, {
|
|
126
126
|
cwd: schedule.cwd,
|
|
127
127
|
scheduleId: schedule.id,
|
|
128
128
|
});
|