@provos/ironcurtain 0.6.0 → 0.7.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/README.md +21 -2
- package/dist/cli-help.d.ts +63 -0
- package/dist/cli-help.js +102 -0
- package/dist/cli-help.js.map +1 -0
- package/dist/cli.js +73 -56
- package/dist/cli.js.map +1 -1
- package/dist/config/config-command.js +136 -2
- package/dist/config/config-command.js.map +1 -1
- package/dist/config/generated/tool-annotations.json +487 -338
- package/dist/config/index.d.ts +21 -1
- package/dist/config/index.js +12 -4
- package/dist/config/index.js.map +1 -1
- package/dist/config/mcp-servers.json +2 -8
- package/dist/config/paths.d.ts +30 -0
- package/dist/config/paths.js +58 -0
- package/dist/config/paths.js.map +1 -1
- package/dist/config/tool-description-hints.json +15 -0
- package/dist/config/types.d.ts +7 -0
- package/dist/config/user-config.d.ts +21 -0
- package/dist/config/user-config.js +8 -0
- package/dist/config/user-config.js.map +1 -1
- package/dist/cron/compile-task-policy.d.ts +17 -0
- package/dist/cron/compile-task-policy.js +39 -0
- package/dist/cron/compile-task-policy.js.map +1 -0
- package/dist/cron/cron-scheduler.d.ts +65 -0
- package/dist/cron/cron-scheduler.js +184 -0
- package/dist/cron/cron-scheduler.js.map +1 -0
- package/dist/cron/file-lock.d.ts +41 -0
- package/dist/cron/file-lock.js +156 -0
- package/dist/cron/file-lock.js.map +1 -0
- package/dist/cron/format-utils.d.ts +18 -0
- package/dist/cron/format-utils.js +145 -0
- package/dist/cron/format-utils.js.map +1 -0
- package/dist/cron/git-sync.d.ts +22 -0
- package/dist/cron/git-sync.js +121 -0
- package/dist/cron/git-sync.js.map +1 -0
- package/dist/cron/headless-transport.d.ts +27 -0
- package/dist/cron/headless-transport.js +43 -0
- package/dist/cron/headless-transport.js.map +1 -0
- package/dist/cron/job-commands.d.ts +39 -0
- package/dist/cron/job-commands.js +522 -0
- package/dist/cron/job-commands.js.map +1 -0
- package/dist/cron/job-store.d.ts +35 -0
- package/dist/cron/job-store.js +111 -0
- package/dist/cron/job-store.js.map +1 -0
- package/dist/cron/types.d.ts +127 -0
- package/dist/cron/types.js +25 -0
- package/dist/cron/types.js.map +1 -0
- package/dist/daemon/control-socket.d.ts +127 -0
- package/dist/daemon/control-socket.js +261 -0
- package/dist/daemon/control-socket.js.map +1 -0
- package/dist/daemon/daemon-command.d.ts +13 -0
- package/dist/daemon/daemon-command.js +230 -0
- package/dist/daemon/daemon-command.js.map +1 -0
- package/dist/daemon/ironcurtain-daemon.d.ts +90 -0
- package/dist/daemon/ironcurtain-daemon.js +548 -0
- package/dist/daemon/ironcurtain-daemon.js.map +1 -0
- package/dist/docker/adapters/claude-code.js +7 -47
- package/dist/docker/adapters/claude-code.js.map +1 -1
- package/dist/docker/adapters/goose.d.ts +58 -0
- package/dist/docker/adapters/goose.js +250 -0
- package/dist/docker/adapters/goose.js.map +1 -0
- package/dist/docker/adapters/shared-scripts.d.ts +29 -0
- package/dist/docker/adapters/shared-scripts.js +80 -0
- package/dist/docker/adapters/shared-scripts.js.map +1 -0
- package/dist/docker/agent-adapter.d.ts +12 -0
- package/dist/docker/agent-adapter.js.map +1 -1
- package/dist/docker/agent-registry.d.ts +6 -1
- package/dist/docker/agent-registry.js +10 -1
- package/dist/docker/agent-registry.js.map +1 -1
- package/dist/docker/docker-agent-session.d.ts +2 -25
- package/dist/docker/docker-agent-session.js +7 -106
- package/dist/docker/docker-agent-session.js.map +1 -1
- package/dist/docker/docker-infrastructure.d.ts +8 -0
- package/dist/docker/docker-infrastructure.js +12 -11
- package/dist/docker/docker-infrastructure.js.map +1 -1
- package/dist/docker/pty-session.js +7 -4
- package/dist/docker/pty-session.js.map +1 -1
- package/dist/escalation/escalation-watcher.d.ts +2 -0
- package/dist/escalation/escalation-watcher.js +3 -0
- package/dist/escalation/escalation-watcher.js.map +1 -1
- package/dist/escalation/session-registry.js +1 -14
- package/dist/escalation/session-registry.js.map +1 -1
- package/dist/index.js +30 -1
- package/dist/index.js.map +1 -1
- package/dist/mux/mux-app.js +11 -6
- package/dist/mux/mux-app.js.map +1 -1
- package/dist/mux/mux-command.js +20 -9
- package/dist/mux/mux-command.js.map +1 -1
- package/dist/mux/mux-input-handler.d.ts +5 -0
- package/dist/mux/mux-input-handler.js +64 -9
- package/dist/mux/mux-input-handler.js.map +1 -1
- package/dist/mux/mux-renderer.d.ts +20 -0
- package/dist/mux/mux-renderer.js +127 -35
- package/dist/mux/mux-renderer.js.map +1 -1
- package/dist/mux/mux-splash.js +2 -1
- package/dist/mux/mux-splash.js.map +1 -1
- package/dist/mux/paste-interceptor.d.ts +22 -0
- package/dist/mux/paste-interceptor.js +143 -0
- package/dist/mux/paste-interceptor.js.map +1 -0
- package/dist/mux/pty-bridge.js +1 -1
- package/dist/mux/pty-bridge.js.map +1 -1
- package/dist/mux/types.d.ts +8 -1
- package/dist/mux/types.js +17 -5
- package/dist/mux/types.js.map +1 -1
- package/dist/pipeline/annotate.js +2 -1
- package/dist/pipeline/annotate.js.map +1 -1
- package/dist/pipeline/compile.d.ts +4 -34
- package/dist/pipeline/compile.js +29 -568
- package/dist/pipeline/compile.js.map +1 -1
- package/dist/pipeline/constitution-compiler.js +1 -1
- package/dist/pipeline/mcp-connections.d.ts +16 -0
- package/dist/pipeline/mcp-connections.js +61 -0
- package/dist/pipeline/mcp-connections.js.map +1 -0
- package/dist/pipeline/pipeline-runner.d.ts +86 -0
- package/dist/pipeline/pipeline-runner.js +554 -0
- package/dist/pipeline/pipeline-runner.js.map +1 -0
- package/dist/pipeline/pipeline-shared.d.ts +29 -2
- package/dist/pipeline/pipeline-shared.js +68 -12
- package/dist/pipeline/pipeline-shared.js.map +1 -1
- package/dist/pipeline/refresh-lists.js +38 -12
- package/dist/pipeline/refresh-lists.js.map +1 -1
- package/dist/pipeline/scenario-generator.js +2 -1
- package/dist/pipeline/scenario-generator.js.map +1 -1
- package/dist/pipeline/tool-annotator.d.ts +3 -3
- package/dist/pipeline/tool-annotator.js +96 -4
- package/dist/pipeline/tool-annotator.js.map +1 -1
- package/dist/pipeline/types.d.ts +52 -0
- package/dist/sandbox/index.js +36 -1
- package/dist/sandbox/index.js.map +1 -1
- package/dist/session/agent-session.d.ts +3 -0
- package/dist/session/agent-session.js +10 -1
- package/dist/session/agent-session.js.map +1 -1
- package/dist/session/index.js +54 -5
- package/dist/session/index.js.map +1 -1
- package/dist/session/preflight.js +26 -6
- package/dist/session/preflight.js.map +1 -1
- package/dist/session/prompts.d.ts +14 -0
- package/dist/session/prompts.js +39 -2
- package/dist/session/prompts.js.map +1 -1
- package/dist/session/session-manager.d.ts +105 -0
- package/dist/session/session-manager.js +134 -0
- package/dist/session/session-manager.js.map +1 -0
- package/dist/session/types.d.ts +27 -0
- package/dist/session/workspace-validation.d.ts +2 -0
- package/dist/session/workspace-validation.js +6 -5
- package/dist/session/workspace-validation.js.map +1 -1
- package/dist/signal/bot-command.d.ts +2 -0
- package/dist/signal/bot-command.js +8 -0
- package/dist/signal/bot-command.js.map +1 -1
- package/dist/signal/format.d.ts +27 -0
- package/dist/signal/format.js +59 -0
- package/dist/signal/format.js.map +1 -1
- package/dist/signal/signal-bot-daemon.d.ts +27 -25
- package/dist/signal/signal-bot-daemon.js +145 -130
- package/dist/signal/signal-bot-daemon.js.map +1 -1
- package/dist/signal/signal-container.js +63 -19
- package/dist/signal/signal-container.js.map +1 -1
- package/dist/signal/signal-transport.js +3 -8
- package/dist/signal/signal-transport.js.map +1 -1
- package/dist/trusted-process/domain-utils.d.ts +38 -4
- package/dist/trusted-process/domain-utils.js +118 -11
- package/dist/trusted-process/domain-utils.js.map +1 -1
- package/dist/trusted-process/index.js +6 -2
- package/dist/trusted-process/index.js.map +1 -1
- package/dist/trusted-process/mcp-client-manager.js +11 -5
- package/dist/trusted-process/mcp-client-manager.js.map +1 -1
- package/dist/trusted-process/mcp-proxy-server.d.ts +2 -0
- package/dist/trusted-process/mcp-proxy-server.js +59 -16
- package/dist/trusted-process/mcp-proxy-server.js.map +1 -1
- package/dist/trusted-process/permissive-output-validator.d.ts +23 -0
- package/dist/trusted-process/permissive-output-validator.js +10 -0
- package/dist/trusted-process/permissive-output-validator.js.map +1 -0
- package/dist/trusted-process/policy-engine.d.ts +27 -4
- package/dist/trusted-process/policy-engine.js +152 -57
- package/dist/trusted-process/policy-engine.js.map +1 -1
- package/dist/trusted-process/tool-description-hints.d.ts +19 -0
- package/dist/trusted-process/tool-description-hints.js +53 -0
- package/dist/trusted-process/tool-description-hints.js.map +1 -0
- package/dist/types/argument-roles.d.ts +33 -1
- package/dist/types/argument-roles.js +129 -1
- package/dist/types/argument-roles.js.map +1 -1
- package/docker/Dockerfile.goose +34 -0
- package/docker/entrypoint-goose.sh +30 -0
- package/package.json +1 -1
- package/src/config/generated/tool-annotations.json +487 -338
- package/src/config/mcp-servers.json +2 -8
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI subcommands for cron job management.
|
|
3
|
+
*
|
|
4
|
+
* These commands work without a running daemon -- they read/write
|
|
5
|
+
* job files directly from ~/.ironcurtain/jobs/. When a daemon is
|
|
6
|
+
* running, daemon-command.ts forwards commands via the control socket
|
|
7
|
+
* instead of calling these functions directly.
|
|
8
|
+
*/
|
|
9
|
+
import { mkdirSync, writeFileSync, readFileSync, unlinkSync } from 'node:fs';
|
|
10
|
+
import { tmpdir } from 'node:os';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import { spawnSync } from 'node:child_process';
|
|
13
|
+
import chalk from 'chalk';
|
|
14
|
+
import { loadAllJobs, loadJob, saveJob, deleteJob, loadRecentRuns } from './job-store.js';
|
|
15
|
+
import { createJobId } from './types.js';
|
|
16
|
+
import { getJobWorkspaceDir, getJobDir } from '../config/paths.js';
|
|
17
|
+
import { compileTaskPolicy } from './compile-task-policy.js';
|
|
18
|
+
import { parseCronExpression, getNextFireTime } from './cron-scheduler.js';
|
|
19
|
+
import { formatRelativeTime, describeCronExpression } from './format-utils.js';
|
|
20
|
+
import { syncGitRepo, validateGitUri } from './git-sync.js';
|
|
21
|
+
/**
|
|
22
|
+
* Opens the user's $VISUAL / $EDITOR with a temporary file and returns
|
|
23
|
+
* the edited content. Lines beginning with '#' are stripped (instructions).
|
|
24
|
+
* Returns undefined if the user saves an empty file.
|
|
25
|
+
*
|
|
26
|
+
* @param initialContent Pre-populate the file with existing content (for editing).
|
|
27
|
+
*/
|
|
28
|
+
function openEditorForMultiline(instructions, initialContent = '') {
|
|
29
|
+
const editor = process.env['VISUAL'] ?? process.env['EDITOR'] ?? 'nano';
|
|
30
|
+
const tmpFile = join(tmpdir(), `ironcurtain-task-${Date.now()}.txt`);
|
|
31
|
+
const header = instructions
|
|
32
|
+
.split('\n')
|
|
33
|
+
.map((l) => `# ${l}`)
|
|
34
|
+
.join('\n');
|
|
35
|
+
writeFileSync(tmpFile, `${header}\n\n${initialContent}`, 'utf-8');
|
|
36
|
+
try {
|
|
37
|
+
const result = spawnSync(editor, [tmpFile], { stdio: 'inherit' });
|
|
38
|
+
if (result.error)
|
|
39
|
+
throw result.error;
|
|
40
|
+
const raw = readFileSync(tmpFile, 'utf-8');
|
|
41
|
+
const content = raw
|
|
42
|
+
.split('\n')
|
|
43
|
+
.filter((line) => !line.startsWith('#'))
|
|
44
|
+
.join('\n')
|
|
45
|
+
.trim();
|
|
46
|
+
return content || undefined;
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
try {
|
|
50
|
+
unlinkSync(tmpFile);
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// ignore cleanup errors
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/** Generates a unique default JobDefinition with empty task fields. */
|
|
58
|
+
function generateDefaultJob() {
|
|
59
|
+
const suffix = Math.random().toString(36).slice(2, 8);
|
|
60
|
+
return {
|
|
61
|
+
id: createJobId(`job-${suffix}`),
|
|
62
|
+
name: '',
|
|
63
|
+
schedule: '0 9 * * *',
|
|
64
|
+
taskDescription: '',
|
|
65
|
+
taskConstitution: '',
|
|
66
|
+
gitRepo: undefined,
|
|
67
|
+
notifyOnEscalation: true,
|
|
68
|
+
notifyOnCompletion: true,
|
|
69
|
+
enabled: true,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const TASK_DESCRIPTION_INSTRUCTIONS = 'Enter the task description — what the agent should do each run.\n' +
|
|
73
|
+
'This is sent to the agent as its work prompt.\n' +
|
|
74
|
+
'Lines starting with # are ignored.';
|
|
75
|
+
const TASK_CONSTITUTION_INSTRUCTIONS = 'Enter the task constitution — what the agent is and is not permitted to do.\n' +
|
|
76
|
+
'This is the policy compilation input; be specific about allowed operations.\n' +
|
|
77
|
+
'Lines starting with # are ignored.';
|
|
78
|
+
/**
|
|
79
|
+
* Interactive review-and-edit loop shared by add-job and edit-job.
|
|
80
|
+
*
|
|
81
|
+
* Shows a summary of all fields and lets the user edit any of them
|
|
82
|
+
* before confirming. Confirm is blocked until task is non-empty.
|
|
83
|
+
* In add mode the ID is editable; in edit mode it is fixed.
|
|
84
|
+
*/
|
|
85
|
+
async function runJobReviewLoop(initial, isNew) {
|
|
86
|
+
const { text, confirm, select, note, isCancel, cancel, log } = await import('@clack/prompts');
|
|
87
|
+
let job = initial;
|
|
88
|
+
for (;;) {
|
|
89
|
+
const gitRepoDisplay = job.gitRepo ?? '(none)';
|
|
90
|
+
const descIsEmpty = !job.taskDescription.trim();
|
|
91
|
+
const constIsEmpty = !job.taskConstitution.trim();
|
|
92
|
+
const anyEmpty = descIsEmpty || constIsEmpty;
|
|
93
|
+
function fieldPreview(text, empty) {
|
|
94
|
+
if (empty)
|
|
95
|
+
return ' (not set — required)';
|
|
96
|
+
const lines = text.split('\n');
|
|
97
|
+
return [
|
|
98
|
+
...lines.slice(0, 3).map((l) => ` ${l}`),
|
|
99
|
+
...(lines.length > 3 ? [` … (${lines.length - 3} more lines)`] : []),
|
|
100
|
+
].join('\n');
|
|
101
|
+
}
|
|
102
|
+
const notifyParts = [job.notifyOnEscalation ? 'escalation' : '', job.notifyOnCompletion ? 'completion' : ''].filter(Boolean);
|
|
103
|
+
const notifyStr = notifyParts.length ? notifyParts.join(', ') : 'none';
|
|
104
|
+
const scheduleDesc = describeCronExpression(job.schedule);
|
|
105
|
+
note([
|
|
106
|
+
`ID: ${job.id}`,
|
|
107
|
+
`Name: ${job.name || '(not set)'}`,
|
|
108
|
+
`Schedule: ${job.schedule} (${scheduleDesc})`,
|
|
109
|
+
`Git repo: ${gitRepoDisplay}`,
|
|
110
|
+
`Notify: ${notifyStr}`,
|
|
111
|
+
``,
|
|
112
|
+
`Task description:`,
|
|
113
|
+
fieldPreview(job.taskDescription, descIsEmpty),
|
|
114
|
+
``,
|
|
115
|
+
`Task constitution:`,
|
|
116
|
+
fieldPreview(job.taskConstitution, constIsEmpty),
|
|
117
|
+
].join('\n'), isNew ? 'New job' : 'Edit job');
|
|
118
|
+
const confirmLabel = isNew ? 'Confirm — create this job' : 'Save changes';
|
|
119
|
+
const action = await select({
|
|
120
|
+
message: 'Confirm or edit a field',
|
|
121
|
+
options: [
|
|
122
|
+
{ value: 'confirm', label: anyEmpty ? `${confirmLabel} (required fields missing)` : confirmLabel },
|
|
123
|
+
...(isNew ? [{ value: 'id', label: `Edit ID ${job.id}` }] : []),
|
|
124
|
+
{ value: 'name', label: `Edit name ${job.name || '(not set)'}` },
|
|
125
|
+
{ value: 'schedule', label: `Edit schedule ${job.schedule}` },
|
|
126
|
+
{ value: 'gitRepo', label: `Edit git repo ${gitRepoDisplay}` },
|
|
127
|
+
{ value: 'taskDescription', label: `Edit task description${descIsEmpty ? ' ← required' : ''}` },
|
|
128
|
+
{ value: 'taskConstitution', label: `Edit task constitution${constIsEmpty ? ' ← required' : ''}` },
|
|
129
|
+
{ value: 'notify', label: `Edit notify ${notifyStr}` },
|
|
130
|
+
],
|
|
131
|
+
});
|
|
132
|
+
if (isCancel(action)) {
|
|
133
|
+
cancel('Cancelled.');
|
|
134
|
+
process.exit(0);
|
|
135
|
+
}
|
|
136
|
+
if (action === 'confirm') {
|
|
137
|
+
if (anyEmpty) {
|
|
138
|
+
log.warn('Task description and constitution are both required. Please set them before confirming.');
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (isNew && loadJob(job.id)) {
|
|
142
|
+
log.error(`Job "${job.id}" already exists. Please edit the ID.`);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
break;
|
|
146
|
+
}
|
|
147
|
+
switch (action) {
|
|
148
|
+
case 'id': {
|
|
149
|
+
const inp = await text({
|
|
150
|
+
message: 'Job ID (slug)',
|
|
151
|
+
initialValue: job.id,
|
|
152
|
+
validate: (v) => {
|
|
153
|
+
if (!v)
|
|
154
|
+
return 'Required';
|
|
155
|
+
try {
|
|
156
|
+
createJobId(v);
|
|
157
|
+
}
|
|
158
|
+
catch (err) {
|
|
159
|
+
return err instanceof Error ? err.message : String(err);
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
});
|
|
163
|
+
if (isCancel(inp)) {
|
|
164
|
+
cancel('Cancelled.');
|
|
165
|
+
process.exit(0);
|
|
166
|
+
}
|
|
167
|
+
job = { ...job, id: createJobId(inp) };
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
case 'name': {
|
|
171
|
+
const inp = await text({ message: 'Display name', initialValue: job.name });
|
|
172
|
+
if (isCancel(inp)) {
|
|
173
|
+
cancel('Cancelled.');
|
|
174
|
+
process.exit(0);
|
|
175
|
+
}
|
|
176
|
+
job = { ...job, name: inp };
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
case 'schedule': {
|
|
180
|
+
const inp = await text({
|
|
181
|
+
message: 'Schedule (cron expression)',
|
|
182
|
+
initialValue: job.schedule,
|
|
183
|
+
validate: (v) => {
|
|
184
|
+
if (!v)
|
|
185
|
+
return 'Required';
|
|
186
|
+
try {
|
|
187
|
+
parseCronExpression(v);
|
|
188
|
+
}
|
|
189
|
+
catch (err) {
|
|
190
|
+
return err instanceof Error ? err.message : String(err);
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
});
|
|
194
|
+
if (isCancel(inp)) {
|
|
195
|
+
cancel('Cancelled.');
|
|
196
|
+
process.exit(0);
|
|
197
|
+
}
|
|
198
|
+
job = { ...job, schedule: inp };
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
case 'gitRepo': {
|
|
202
|
+
const inp = await text({
|
|
203
|
+
message: 'Git repository URI (optional, leave empty to skip)',
|
|
204
|
+
placeholder: 'git@github.com:org/repo.git',
|
|
205
|
+
initialValue: job.gitRepo ?? '',
|
|
206
|
+
validate: (v) => {
|
|
207
|
+
if (!v)
|
|
208
|
+
return; // empty is valid (skip)
|
|
209
|
+
try {
|
|
210
|
+
validateGitUri(v);
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
return err instanceof Error ? err.message : String(err);
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
});
|
|
217
|
+
if (isCancel(inp)) {
|
|
218
|
+
cancel('Cancelled.');
|
|
219
|
+
process.exit(0);
|
|
220
|
+
}
|
|
221
|
+
job = { ...job, gitRepo: inp || undefined };
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
case 'taskDescription': {
|
|
225
|
+
log.step('Opening editor — save and close to continue');
|
|
226
|
+
const newDesc = openEditorForMultiline(TASK_DESCRIPTION_INSTRUCTIONS, job.taskDescription);
|
|
227
|
+
if (newDesc) {
|
|
228
|
+
job = { ...job, taskDescription: newDesc };
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
log.warn('Editor was empty — keeping existing task description.');
|
|
232
|
+
}
|
|
233
|
+
break;
|
|
234
|
+
}
|
|
235
|
+
case 'taskConstitution': {
|
|
236
|
+
log.step('Opening editor — save and close to continue');
|
|
237
|
+
const initialConstitution = job.taskConstitution || 'The agent is allowed ';
|
|
238
|
+
const newConst = openEditorForMultiline(TASK_CONSTITUTION_INSTRUCTIONS, initialConstitution);
|
|
239
|
+
if (newConst) {
|
|
240
|
+
job = { ...job, taskConstitution: newConst };
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
log.warn('Editor was empty — keeping existing task constitution.');
|
|
244
|
+
}
|
|
245
|
+
break;
|
|
246
|
+
}
|
|
247
|
+
case 'notify': {
|
|
248
|
+
const esc = await confirm({
|
|
249
|
+
message: 'Notify on escalation via Signal?',
|
|
250
|
+
initialValue: job.notifyOnEscalation,
|
|
251
|
+
});
|
|
252
|
+
if (isCancel(esc)) {
|
|
253
|
+
cancel('Cancelled.');
|
|
254
|
+
process.exit(0);
|
|
255
|
+
}
|
|
256
|
+
const comp = await confirm({
|
|
257
|
+
message: 'Notify on completion via Signal?',
|
|
258
|
+
initialValue: job.notifyOnCompletion,
|
|
259
|
+
});
|
|
260
|
+
if (isCancel(comp)) {
|
|
261
|
+
cancel('Cancelled.');
|
|
262
|
+
process.exit(0);
|
|
263
|
+
}
|
|
264
|
+
job = { ...job, notifyOnEscalation: esc, notifyOnCompletion: comp };
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return job;
|
|
270
|
+
}
|
|
271
|
+
/** Loads a job by ID string, exiting with an error if not found. */
|
|
272
|
+
function loadJobOrExit(jobIdStr) {
|
|
273
|
+
const jobId = createJobId(jobIdStr);
|
|
274
|
+
const job = loadJob(jobId);
|
|
275
|
+
if (!job) {
|
|
276
|
+
console.error(`Job not found: ${jobIdStr}`);
|
|
277
|
+
process.exit(1);
|
|
278
|
+
}
|
|
279
|
+
return job;
|
|
280
|
+
}
|
|
281
|
+
function formatRunOutcome(outcome, verbose = true) {
|
|
282
|
+
if (outcome.kind === 'success')
|
|
283
|
+
return chalk.green('success');
|
|
284
|
+
if (outcome.kind === 'budget_exhausted') {
|
|
285
|
+
return verbose ? chalk.yellow(`budget exhausted: ${outcome.dimension}`) : chalk.yellow('budget exhausted');
|
|
286
|
+
}
|
|
287
|
+
return verbose ? chalk.red(`error: ${outcome.message}`) : chalk.red('error');
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Clones a git repo into workspace with interactive retry on failure.
|
|
291
|
+
* Returns the final URI cloned, or undefined if the user skipped.
|
|
292
|
+
*/
|
|
293
|
+
async function cloneWithRetry(uri, workspace) {
|
|
294
|
+
const { text, isCancel, log } = await import('@clack/prompts');
|
|
295
|
+
let currentUri = uri;
|
|
296
|
+
for (;;) {
|
|
297
|
+
console.error('Cloning repository...');
|
|
298
|
+
try {
|
|
299
|
+
syncGitRepo(currentUri, workspace, /* verbose= */ true);
|
|
300
|
+
return currentUri;
|
|
301
|
+
}
|
|
302
|
+
catch (err) {
|
|
303
|
+
log.error(`Git clone failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
304
|
+
const retryInput = await text({
|
|
305
|
+
message: 'Enter a corrected repository URI, or leave empty to skip cloning',
|
|
306
|
+
placeholder: currentUri,
|
|
307
|
+
});
|
|
308
|
+
if (isCancel(retryInput) || !retryInput)
|
|
309
|
+
return undefined;
|
|
310
|
+
currentUri = retryInput;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
/** Creates a new scheduled job interactively. */
|
|
315
|
+
export async function runAddJobWizard() {
|
|
316
|
+
const { intro, outro } = await import('@clack/prompts');
|
|
317
|
+
intro('Add a new scheduled job');
|
|
318
|
+
let job = await runJobReviewLoop(generateDefaultJob(), true);
|
|
319
|
+
const workspace = getJobWorkspaceDir(job.id);
|
|
320
|
+
mkdirSync(workspace, { recursive: true });
|
|
321
|
+
if (job.gitRepo) {
|
|
322
|
+
const finalUri = await cloneWithRetry(job.gitRepo, workspace);
|
|
323
|
+
job = { ...job, gitRepo: finalUri };
|
|
324
|
+
}
|
|
325
|
+
// Save job first so it's not lost if policy compilation fails
|
|
326
|
+
await saveJob(job);
|
|
327
|
+
console.error('');
|
|
328
|
+
console.error('Compiling task policy...');
|
|
329
|
+
try {
|
|
330
|
+
await compileTaskPolicy(job.taskConstitution, getJobDir(job.id));
|
|
331
|
+
}
|
|
332
|
+
catch (err) {
|
|
333
|
+
console.error(chalk.red(`Policy compilation failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
334
|
+
console.error(chalk.yellow(`Job "${job.id}" was saved. Fix the issue then run: ironcurtain daemon recompile-job ${job.id}`));
|
|
335
|
+
process.exit(1);
|
|
336
|
+
}
|
|
337
|
+
const nextRun = getNextFireTime(parseCronExpression(job.schedule), new Date());
|
|
338
|
+
outro(`Job "${job.id}" created. Next run: ${nextRun.toLocaleString()}`);
|
|
339
|
+
}
|
|
340
|
+
/** Edits an existing job interactively. Re-compiles policy if task changed. */
|
|
341
|
+
export async function runEditJobWizard(jobIdStr) {
|
|
342
|
+
const { intro, outro } = await import('@clack/prompts');
|
|
343
|
+
const existing = loadJobOrExit(jobIdStr);
|
|
344
|
+
intro(`Edit job "${existing.name || existing.id}"`);
|
|
345
|
+
const originalConstitution = existing.taskConstitution;
|
|
346
|
+
const job = await runJobReviewLoop(existing, false);
|
|
347
|
+
// Save first so changes aren't lost if recompilation fails
|
|
348
|
+
await saveJob(job);
|
|
349
|
+
if (job.taskConstitution !== originalConstitution) {
|
|
350
|
+
console.error('Constitution changed — recompiling policy...');
|
|
351
|
+
try {
|
|
352
|
+
await compileTaskPolicy(job.taskConstitution, getJobDir(job.id));
|
|
353
|
+
}
|
|
354
|
+
catch (err) {
|
|
355
|
+
console.error(chalk.red(`Policy compilation failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
356
|
+
console.error(chalk.yellow(`Job "${job.id}" was saved. Fix the issue then run: ironcurtain daemon recompile-job ${job.id}`));
|
|
357
|
+
process.exit(1);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
// Notify running daemon to pick up changes (single round-trip, no pre-check)
|
|
361
|
+
try {
|
|
362
|
+
const { sendControlRequest } = await import('../daemon/control-socket.js');
|
|
363
|
+
const response = await sendControlRequest({ command: 'reload-job', jobId: job.id });
|
|
364
|
+
if (response?.ok) {
|
|
365
|
+
console.error('Daemon notified — job reloaded.');
|
|
366
|
+
}
|
|
367
|
+
else if (response) {
|
|
368
|
+
console.error(chalk.yellow(`Daemon reload failed: ${response.error}`));
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
catch {
|
|
372
|
+
// Daemon not reachable — changes will be picked up on next start
|
|
373
|
+
}
|
|
374
|
+
outro(`Job "${job.id}" updated.`);
|
|
375
|
+
}
|
|
376
|
+
/** Formats and prints a single job entry. */
|
|
377
|
+
function printJobEntry(entry) {
|
|
378
|
+
const statusLabel = entry.statusLabels.length > 0 ? ` ${entry.statusLabels.join(' ')}` : '';
|
|
379
|
+
const cronDesc = describeCronExpression(entry.job.schedule);
|
|
380
|
+
let lastRunStr = '';
|
|
381
|
+
if (entry.lastRun) {
|
|
382
|
+
const lastRunDate = new Date(entry.lastRun.startedAt);
|
|
383
|
+
const lastRunRelative = formatRelativeTime(lastRunDate);
|
|
384
|
+
lastRunStr = `Last run: ${lastRunRelative} -- ${formatRunOutcome(entry.lastRun.outcome)}`;
|
|
385
|
+
if (entry.lastRun.summary) {
|
|
386
|
+
lastRunStr += `\n${' '.repeat(20)}${entry.lastRun.summary.split('\n')[0].slice(0, 60)}`;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
console.error(` ${chalk.bold(entry.job.id.padEnd(20))} ${entry.job.name.padEnd(30)} ${cronDesc.padEnd(25)} ${entry.nextRunStr}${statusLabel}`);
|
|
390
|
+
if (lastRunStr) {
|
|
391
|
+
console.error(` ${' '.repeat(20)}${lastRunStr}`);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
export function runListJobs() {
|
|
395
|
+
const jobs = loadAllJobs();
|
|
396
|
+
if (jobs.length === 0) {
|
|
397
|
+
console.error('No jobs configured. Use "ironcurtain daemon add-job" to create one.');
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
console.error('Jobs:');
|
|
401
|
+
for (const job of jobs) {
|
|
402
|
+
let nextRunStr = '';
|
|
403
|
+
if (job.enabled) {
|
|
404
|
+
try {
|
|
405
|
+
const nextRun = getNextFireTime(parseCronExpression(job.schedule), new Date());
|
|
406
|
+
nextRunStr = `next: ${formatRelativeTime(nextRun)}`;
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
nextRunStr = chalk.red('invalid schedule');
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
const lastRuns = loadRecentRuns(job.id, 1);
|
|
413
|
+
printJobEntry({
|
|
414
|
+
job,
|
|
415
|
+
nextRunStr,
|
|
416
|
+
lastRun: lastRuns[0],
|
|
417
|
+
statusLabels: job.enabled ? [] : [chalk.yellow('DISABLED')],
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Formats job list data received from the daemon control socket.
|
|
423
|
+
* Used when list-jobs is forwarded to a running daemon, which provides
|
|
424
|
+
* live running status and next-run times from the scheduler.
|
|
425
|
+
*/
|
|
426
|
+
export function formatDaemonJobList(jobs) {
|
|
427
|
+
if (jobs.length === 0) {
|
|
428
|
+
console.error('No jobs configured. Use "ironcurtain daemon add-job" to create one.');
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
console.error('Jobs (from running daemon):');
|
|
432
|
+
for (const entry of jobs) {
|
|
433
|
+
const statusLabels = [];
|
|
434
|
+
if (!entry.job.enabled)
|
|
435
|
+
statusLabels.push(chalk.yellow('DISABLED'));
|
|
436
|
+
if (entry.isRunning)
|
|
437
|
+
statusLabels.push(chalk.cyan('RUNNING'));
|
|
438
|
+
printJobEntry({
|
|
439
|
+
job: entry.job,
|
|
440
|
+
nextRunStr: entry.nextRun ? `next: ${formatRelativeTime(new Date(entry.nextRun))}` : '',
|
|
441
|
+
lastRun: entry.lastRun,
|
|
442
|
+
statusLabels,
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
/** Manually triggers a job run. */
|
|
447
|
+
export async function runJobCommand(jobIdStr) {
|
|
448
|
+
const job = loadJobOrExit(jobIdStr);
|
|
449
|
+
console.error(`Running job "${job.name}"...`);
|
|
450
|
+
const { resolveSessionMode } = await import('../session/preflight.js');
|
|
451
|
+
const { loadConfig } = await import('../config/index.js');
|
|
452
|
+
const preflight = await resolveSessionMode({ config: loadConfig() });
|
|
453
|
+
console.error(`Mode: ${preflight.mode.kind} (${preflight.reason})`);
|
|
454
|
+
const { IronCurtainDaemon } = await import('../daemon/ironcurtain-daemon.js');
|
|
455
|
+
const daemon = new IronCurtainDaemon({ mode: preflight.mode, noSignal: true });
|
|
456
|
+
const record = await daemon.runJobNow(job.id);
|
|
457
|
+
console.error(` Outcome: ${formatRunOutcome(record.outcome)}`);
|
|
458
|
+
console.error(` Duration: ${record.budget.elapsedSeconds.toFixed(0)}s`);
|
|
459
|
+
console.error(` Cost: $${record.budget.estimatedCostUsd.toFixed(2)}`);
|
|
460
|
+
if (record.summary) {
|
|
461
|
+
console.error(` Summary: ${record.summary.split('\n')[0].slice(0, 100)}`);
|
|
462
|
+
}
|
|
463
|
+
// Clean up daemon resources (scheduler, logger file handles) and exit.
|
|
464
|
+
// Without this, lingering handles keep the Node.js event loop alive.
|
|
465
|
+
await daemon.shutdown();
|
|
466
|
+
process.exit(record.outcome.kind === 'success' ? 0 : 1);
|
|
467
|
+
}
|
|
468
|
+
/** Removes a job. Prompts for confirmation unless force is true. */
|
|
469
|
+
export async function runRemoveJob(jobIdStr, force = false) {
|
|
470
|
+
const job = loadJobOrExit(jobIdStr);
|
|
471
|
+
if (!force) {
|
|
472
|
+
const { confirm, isCancel } = await import('@clack/prompts');
|
|
473
|
+
const displayName = job.name || job.id;
|
|
474
|
+
const shouldDelete = await confirm({
|
|
475
|
+
message: `Remove "${displayName}"? This deletes the workspace, run history, and policy.`,
|
|
476
|
+
});
|
|
477
|
+
if (isCancel(shouldDelete) || !shouldDelete) {
|
|
478
|
+
console.error('Cancelled.');
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
deleteJob(job.id);
|
|
483
|
+
console.error(`Job "${jobIdStr}" removed.`);
|
|
484
|
+
}
|
|
485
|
+
/** Sets a job's enabled state. */
|
|
486
|
+
async function runSetJobEnabled(jobIdStr, enabled) {
|
|
487
|
+
const job = loadJobOrExit(jobIdStr);
|
|
488
|
+
await saveJob({ ...job, enabled });
|
|
489
|
+
console.error(`Job "${jobIdStr}" ${enabled ? 'enabled' : 'disabled'}.`);
|
|
490
|
+
}
|
|
491
|
+
/** Disables a job. */
|
|
492
|
+
export const runDisableJob = (jobIdStr) => runSetJobEnabled(jobIdStr, false);
|
|
493
|
+
/** Enables a job. */
|
|
494
|
+
export const runEnableJob = (jobIdStr) => runSetJobEnabled(jobIdStr, true);
|
|
495
|
+
/** Re-runs policy compilation for a job. */
|
|
496
|
+
export async function runRecompileJob(jobIdStr) {
|
|
497
|
+
const job = loadJobOrExit(jobIdStr);
|
|
498
|
+
console.error(`Recompiling policy for job "${jobIdStr}"...`);
|
|
499
|
+
await compileTaskPolicy(job.taskConstitution, getJobDir(job.id));
|
|
500
|
+
console.error('Done.');
|
|
501
|
+
}
|
|
502
|
+
/** Shows recent run logs for a job. */
|
|
503
|
+
export function runShowLogs(jobIdStr, limit) {
|
|
504
|
+
const job = loadJobOrExit(jobIdStr);
|
|
505
|
+
const runs = loadRecentRuns(job.id, limit);
|
|
506
|
+
if (runs.length === 0) {
|
|
507
|
+
console.error(`No run history for job "${jobIdStr}".`);
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
console.error(`Recent runs for "${job.name}" (last ${runs.length}):`);
|
|
511
|
+
console.error('');
|
|
512
|
+
for (const run of runs) {
|
|
513
|
+
const runDate = new Date(run.startedAt);
|
|
514
|
+
const runRelative = formatRelativeTime(runDate);
|
|
515
|
+
console.error(` ${runRelative} ${formatRunOutcome(run.outcome, false)} ${run.budget.elapsedSeconds.toFixed(0)}s $${run.budget.estimatedCostUsd.toFixed(2)}`);
|
|
516
|
+
if (run.summary) {
|
|
517
|
+
const firstLine = run.summary.split('\n').find((l) => l.trim()) ?? '';
|
|
518
|
+
console.error(` ${firstLine.slice(0, 80)}`);
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
//# sourceMappingURL=job-commands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"job-commands.js","sourceRoot":"","sources":["../../src/cron/job-commands.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem-backed store for job definitions and run records.
|
|
3
|
+
*
|
|
4
|
+
* Directory layout:
|
|
5
|
+
* ~/.ironcurtain/jobs/{jobId}/
|
|
6
|
+
* job.json -- JobDefinition
|
|
7
|
+
* generated/ -- per-job compiled policy artifacts
|
|
8
|
+
* compiled-policy.json
|
|
9
|
+
* dynamic-lists.json -- (optional)
|
|
10
|
+
* workspace/ -- persistent agent workspace
|
|
11
|
+
* runs/ -- run history
|
|
12
|
+
* 2026-03-04T09:00:00.000Z.json
|
|
13
|
+
*
|
|
14
|
+
* Tool annotations (tool-annotations.json) are always loaded from
|
|
15
|
+
* the global location, never stored per-job.
|
|
16
|
+
*/
|
|
17
|
+
import type { JobDefinition, JobId, RunRecord } from './types.js';
|
|
18
|
+
/** Loads a job definition from disk. Returns undefined if not found. */
|
|
19
|
+
export declare function loadJob(jobId: JobId): JobDefinition | undefined;
|
|
20
|
+
/** Loads all job definitions from disk. */
|
|
21
|
+
export declare function loadAllJobs(): JobDefinition[];
|
|
22
|
+
/**
|
|
23
|
+
* Saves a job definition to disk. Creates directories as needed.
|
|
24
|
+
* Acquires an advisory file lock to prevent concurrent write corruption.
|
|
25
|
+
*/
|
|
26
|
+
export declare function saveJob(job: JobDefinition): Promise<void>;
|
|
27
|
+
/** Deletes a job and all its artifacts (generated, workspace, runs). */
|
|
28
|
+
export declare function deleteJob(jobId: JobId): void;
|
|
29
|
+
/** Records a completed run. Filenames are unique (timestamp-based), so no lock needed. */
|
|
30
|
+
export declare function saveRunRecord(jobId: JobId, record: RunRecord): void;
|
|
31
|
+
/**
|
|
32
|
+
* Loads recent run records for a job, most recent first.
|
|
33
|
+
* @param limit Maximum number of records to return (default 10).
|
|
34
|
+
*/
|
|
35
|
+
export declare function loadRecentRuns(jobId: JobId, limit?: number): RunRecord[];
|