@provos/ironcurtain 0.6.0 → 0.7.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.
- package/README.md +29 -86
- 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 +79 -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/constitution-readonly.md +21 -0
- package/dist/config/generated/tool-annotations.json +487 -338
- package/dist/config/generated-readonly/compiled-policy.json +468 -0
- 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 +47 -0
- package/dist/config/paths.js +81 -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/constitution-generator.d.ts +60 -0
- package/dist/cron/constitution-generator.js +217 -0
- package/dist/cron/constitution-generator.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 +585 -0
- package/dist/cron/job-commands.js.map +1 -0
- package/dist/cron/job-customizer.d.ts +22 -0
- package/dist/cron/job-customizer.js +47 -0
- package/dist/cron/job-customizer.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 +135 -0
- package/dist/cron/types.js +22 -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 +550 -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/mitm-proxy.js +10 -5
- package/dist/docker/mitm-proxy.js.map +1 -1
- package/dist/docker/oauth-credentials.js +2 -2
- package/dist/docker/oauth-credentials.js.map +1 -1
- package/dist/docker/pty-session.js +146 -39
- 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 +43 -5
- 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 +49 -10
- 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/persona/compile-persona-policy.d.ts +21 -0
- package/dist/persona/compile-persona-policy.js +50 -0
- package/dist/persona/compile-persona-policy.js.map +1 -0
- package/dist/persona/persona-command.d.ts +9 -0
- package/dist/persona/persona-command.js +479 -0
- package/dist/persona/persona-command.js.map +1 -0
- package/dist/persona/persona-customizer.d.ts +23 -0
- package/dist/persona/persona-customizer.js +52 -0
- package/dist/persona/persona-customizer.js.map +1 -0
- package/dist/persona/persona-prompt.d.ts +19 -0
- package/dist/persona/persona-prompt.js +42 -0
- package/dist/persona/persona-prompt.js.map +1 -0
- package/dist/persona/resolve.d.ts +46 -0
- package/dist/persona/resolve.js +108 -0
- package/dist/persona/resolve.js.map +1 -0
- package/dist/persona/types.d.ts +40 -0
- package/dist/persona/types.js +20 -0
- package/dist/persona/types.js.map +1 -0
- package/dist/pipeline/annotate.js +10 -4
- package/dist/pipeline/annotate.js.map +1 -1
- package/dist/pipeline/compile.d.ts +14 -31
- package/dist/pipeline/compile.js +50 -563
- package/dist/pipeline/compile.js.map +1 -1
- package/dist/pipeline/constitution-compiler.d.ts +6 -0
- package/dist/pipeline/constitution-compiler.js +42 -6
- package/dist/pipeline/constitution-compiler.js.map +1 -1
- package/dist/pipeline/constitution-customizer.d.ts +3 -0
- package/dist/pipeline/constitution-customizer.js +19 -5
- package/dist/pipeline/constitution-customizer.js.map +1 -1
- package/dist/pipeline/customizer-loop.d.ts +34 -0
- package/dist/pipeline/customizer-loop.js +167 -0
- package/dist/pipeline/customizer-loop.js.map +1 -0
- 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 +547 -0
- package/dist/pipeline/pipeline-runner.js.map +1 -0
- package/dist/pipeline/pipeline-shared.d.ts +37 -3
- package/dist/pipeline/pipeline-shared.js +77 -16
- 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 +114 -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.d.ts +10 -0
- package/dist/session/index.js +134 -12
- 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/session-metadata.d.ts +18 -0
- package/dist/session/session-metadata.js +34 -0
- package/dist/session/session-metadata.js.map +1 -0
- package/dist/session/types.d.ts +47 -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 +153 -135
- 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 +37 -4
- package/dist/trusted-process/domain-utils.js +130 -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 +21 -0
- package/dist/trusted-process/mcp-proxy-server.js +91 -28
- 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 +29 -7
- package/dist/trusted-process/policy-engine.js +149 -92
- 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/dist/types/slug.d.ts +7 -0
- package/dist/types/slug.js +14 -0
- package/dist/types/slug.js.map +1 -0
- package/dist/utils/editor.d.ts +24 -0
- package/dist/utils/editor.js +66 -0
- package/dist/utils/editor.js.map +1 -0
- 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,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Control socket for live daemon communication.
|
|
3
|
+
*
|
|
4
|
+
* The daemon listens on a Unix domain socket at ~/.ironcurtain/daemon.sock.
|
|
5
|
+
* CLI commands detect whether the daemon is running (socket exists and
|
|
6
|
+
* responds) and forward commands to it. If no daemon is running, CLI
|
|
7
|
+
* commands fall back to direct filesystem operations.
|
|
8
|
+
*
|
|
9
|
+
* Protocol: newline-delimited JSON. Each request is a single JSON line;
|
|
10
|
+
* the daemon writes a single JSON response line and closes the connection.
|
|
11
|
+
*/
|
|
12
|
+
import { createServer, createConnection } from 'node:net';
|
|
13
|
+
import { unlinkSync } from 'node:fs';
|
|
14
|
+
import { getDaemonSocketPath } from '../config/paths.js';
|
|
15
|
+
import * as logger from '../logger.js';
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Server (daemon-side)
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
export class ControlSocketServer {
|
|
20
|
+
server = null;
|
|
21
|
+
socketPath;
|
|
22
|
+
handler;
|
|
23
|
+
constructor(handler, socketPath) {
|
|
24
|
+
this.handler = handler;
|
|
25
|
+
this.socketPath = socketPath ?? getDaemonSocketPath();
|
|
26
|
+
}
|
|
27
|
+
/** Starts listening on the Unix domain socket. */
|
|
28
|
+
async start() {
|
|
29
|
+
await this.removeStaleSocket();
|
|
30
|
+
return new Promise((resolve, reject) => {
|
|
31
|
+
const server = createServer((socket) => this.onConnection(socket));
|
|
32
|
+
this.server = server;
|
|
33
|
+
server.on('error', (err) => {
|
|
34
|
+
logger.error(`[ControlSocket] Server error: ${err.message}`);
|
|
35
|
+
reject(err);
|
|
36
|
+
});
|
|
37
|
+
server.listen(this.socketPath, () => {
|
|
38
|
+
logger.info(`[ControlSocket] Listening on ${this.socketPath}`);
|
|
39
|
+
resolve();
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
/** Stops the server and removes the socket file. */
|
|
44
|
+
async stop() {
|
|
45
|
+
if (!this.server)
|
|
46
|
+
return;
|
|
47
|
+
const server = this.server;
|
|
48
|
+
return new Promise((resolve) => {
|
|
49
|
+
server.close(() => {
|
|
50
|
+
this.cleanupSocketFile();
|
|
51
|
+
this.server = null;
|
|
52
|
+
resolve();
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Removes a stale socket file left behind by a crashed daemon.
|
|
58
|
+
* Attempts to connect first — only unlinks when the socket is
|
|
59
|
+
* confirmed stale (ECONNREFUSED) or absent (ENOENT). If the
|
|
60
|
+
* socket is live, throws so the caller knows another daemon is running.
|
|
61
|
+
*/
|
|
62
|
+
async removeStaleSocket() {
|
|
63
|
+
const alive = await this.isSocketAlive();
|
|
64
|
+
if (alive) {
|
|
65
|
+
throw new Error(`Another daemon is already listening on ${this.socketPath}. ` + `Stop it first or remove the socket manually.`);
|
|
66
|
+
}
|
|
67
|
+
// Socket is stale or absent — safe to unlink
|
|
68
|
+
try {
|
|
69
|
+
unlinkSync(this.socketPath);
|
|
70
|
+
logger.info(`[ControlSocket] Removed stale socket file`);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// File doesn't exist — fine
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Probes whether the socket is actively accepting connections.
|
|
78
|
+
* Returns true if a daemon is listening, false if stale/absent.
|
|
79
|
+
*/
|
|
80
|
+
isSocketAlive() {
|
|
81
|
+
return new Promise((resolve) => {
|
|
82
|
+
const conn = createConnection(this.socketPath);
|
|
83
|
+
conn.once('connect', () => {
|
|
84
|
+
conn.destroy();
|
|
85
|
+
resolve(true);
|
|
86
|
+
});
|
|
87
|
+
conn.once('error', () => {
|
|
88
|
+
resolve(false);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
cleanupSocketFile() {
|
|
93
|
+
try {
|
|
94
|
+
unlinkSync(this.socketPath);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// Best-effort cleanup
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
onConnection(socket) {
|
|
101
|
+
let data = '';
|
|
102
|
+
let dispatched = false;
|
|
103
|
+
socket.on('data', (chunk) => {
|
|
104
|
+
if (dispatched)
|
|
105
|
+
return;
|
|
106
|
+
data += chunk.toString();
|
|
107
|
+
const newlineIndex = data.indexOf('\n');
|
|
108
|
+
if (newlineIndex === -1)
|
|
109
|
+
return;
|
|
110
|
+
dispatched = true;
|
|
111
|
+
const line = data.slice(0, newlineIndex);
|
|
112
|
+
void this.handleRequest(line, socket);
|
|
113
|
+
});
|
|
114
|
+
socket.on('error', (err) => {
|
|
115
|
+
logger.warn(`[ControlSocket] Connection error: ${err.message}`);
|
|
116
|
+
});
|
|
117
|
+
// Timeout idle connections after 30s
|
|
118
|
+
socket.setTimeout(30_000, () => {
|
|
119
|
+
socket.destroy();
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
async handleRequest(line, socket) {
|
|
123
|
+
let request;
|
|
124
|
+
try {
|
|
125
|
+
request = JSON.parse(line);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
this.sendResponse(socket, { ok: false, error: 'Invalid JSON' });
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
try {
|
|
132
|
+
const response = await this.dispatch(request);
|
|
133
|
+
this.sendResponse(socket, response);
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
137
|
+
this.sendResponse(socket, { ok: false, error: message });
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
async dispatch(request) {
|
|
141
|
+
switch (request.command) {
|
|
142
|
+
case 'ping':
|
|
143
|
+
return { ok: true, data: { status: 'running' } };
|
|
144
|
+
case 'status': {
|
|
145
|
+
const status = this.handler.getStatus();
|
|
146
|
+
return {
|
|
147
|
+
ok: true,
|
|
148
|
+
data: {
|
|
149
|
+
...status,
|
|
150
|
+
nextFireTime: status.nextFireTime?.toISOString() ?? null,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
case 'add-job':
|
|
155
|
+
await this.handler.addJob(request.job);
|
|
156
|
+
return { ok: true };
|
|
157
|
+
case 'remove-job':
|
|
158
|
+
await this.handler.removeJob(request.jobId);
|
|
159
|
+
return { ok: true };
|
|
160
|
+
case 'enable-job':
|
|
161
|
+
await this.handler.enableJob(request.jobId);
|
|
162
|
+
return { ok: true };
|
|
163
|
+
case 'disable-job':
|
|
164
|
+
await this.handler.disableJob(request.jobId);
|
|
165
|
+
return { ok: true };
|
|
166
|
+
case 'recompile-job':
|
|
167
|
+
await this.handler.recompileJob(request.jobId);
|
|
168
|
+
return { ok: true };
|
|
169
|
+
case 'reload-job':
|
|
170
|
+
await this.handler.reloadJob(request.jobId);
|
|
171
|
+
return { ok: true };
|
|
172
|
+
case 'run-job': {
|
|
173
|
+
const record = await this.handler.runJobNow(request.jobId);
|
|
174
|
+
return { ok: true, data: record };
|
|
175
|
+
}
|
|
176
|
+
case 'list-jobs': {
|
|
177
|
+
const jobs = this.handler.listJobs();
|
|
178
|
+
// Serialize dates for JSON transport
|
|
179
|
+
const serialized = jobs.map((j) => ({
|
|
180
|
+
...j,
|
|
181
|
+
nextRun: j.nextRun?.toISOString() ?? null,
|
|
182
|
+
}));
|
|
183
|
+
return { ok: true, data: serialized };
|
|
184
|
+
}
|
|
185
|
+
default:
|
|
186
|
+
return { ok: false, error: `Unknown command: ${request.command}` };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
sendResponse(socket, response) {
|
|
190
|
+
try {
|
|
191
|
+
socket.end(JSON.stringify(response) + '\n');
|
|
192
|
+
}
|
|
193
|
+
catch {
|
|
194
|
+
// Connection may have been closed
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
// ---------------------------------------------------------------------------
|
|
199
|
+
// Client (CLI-side)
|
|
200
|
+
// ---------------------------------------------------------------------------
|
|
201
|
+
/** Timeout for connecting to the daemon socket (ms). */
|
|
202
|
+
const CONNECT_TIMEOUT = 2_000;
|
|
203
|
+
/** Timeout for receiving a response from the daemon (ms). */
|
|
204
|
+
const RESPONSE_TIMEOUT = 300_000; // 5 minutes -- run-job can take a while
|
|
205
|
+
/**
|
|
206
|
+
* Sends a request to the running daemon via the control socket.
|
|
207
|
+
* Returns the parsed response, or null if the daemon is not reachable.
|
|
208
|
+
*/
|
|
209
|
+
export async function sendControlRequest(request, socketPath) {
|
|
210
|
+
const path = socketPath ?? getDaemonSocketPath();
|
|
211
|
+
return new Promise((resolve) => {
|
|
212
|
+
const socket = createConnection({ path });
|
|
213
|
+
let data = '';
|
|
214
|
+
let settled = false;
|
|
215
|
+
let connectTimer = null;
|
|
216
|
+
const finish = (result) => {
|
|
217
|
+
if (settled)
|
|
218
|
+
return;
|
|
219
|
+
settled = true;
|
|
220
|
+
if (connectTimer)
|
|
221
|
+
clearTimeout(connectTimer);
|
|
222
|
+
socket.destroy();
|
|
223
|
+
resolve(result);
|
|
224
|
+
};
|
|
225
|
+
socket.setTimeout(RESPONSE_TIMEOUT, () => {
|
|
226
|
+
finish(null);
|
|
227
|
+
});
|
|
228
|
+
socket.on('connect', () => {
|
|
229
|
+
socket.write(JSON.stringify(request) + '\n');
|
|
230
|
+
});
|
|
231
|
+
socket.on('data', (chunk) => {
|
|
232
|
+
data += chunk.toString();
|
|
233
|
+
const newlineIndex = data.indexOf('\n');
|
|
234
|
+
if (newlineIndex === -1)
|
|
235
|
+
return;
|
|
236
|
+
try {
|
|
237
|
+
const response = JSON.parse(data.slice(0, newlineIndex));
|
|
238
|
+
finish(response);
|
|
239
|
+
}
|
|
240
|
+
catch {
|
|
241
|
+
finish(null);
|
|
242
|
+
}
|
|
243
|
+
});
|
|
244
|
+
socket.on('error', () => {
|
|
245
|
+
finish(null);
|
|
246
|
+
});
|
|
247
|
+
// Connect timeout -- daemon not responding
|
|
248
|
+
connectTimer = setTimeout(() => {
|
|
249
|
+
finish(null);
|
|
250
|
+
}, CONNECT_TIMEOUT);
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Checks if a daemon is currently running and responsive.
|
|
255
|
+
* Returns true if the daemon responds to a ping.
|
|
256
|
+
*/
|
|
257
|
+
export async function isDaemonRunning(socketPath) {
|
|
258
|
+
const response = await sendControlRequest({ command: 'ping' }, socketPath);
|
|
259
|
+
return response !== null && response.ok;
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=control-socket.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"control-socket.js","sourceRoot":"","sources":["../../src/daemon/control-socket.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAA4B,MAAM,UAAU,CAAC;AACpF,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,KAAK,MAAM,MAAM,cAAc,CAAC;AAuEvC,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,MAAM,OAAO,mBAAmB;IACtB,MAAM,GAAkB,IAAI,CAAC;IACpB,UAAU,CAAS;IACnB,OAAO,CAAwB;IAEhD,YAAY,OAA8B,EAAE,UAAmB;QAC7D,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,UAAU,IAAI,mBAAmB,EAAE,CAAC;IACxD,CAAC;IAED,kDAAkD;IAClD,KAAK,CAAC,KAAK;QACT,MAAM,IAAI,CAAC,iBAAiB,EAAE,CAAC;QAE/B,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC3C,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;YACnE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;YAErB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBACzB,MAAM,CAAC,KAAK,CAAC,iCAAiC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC7D,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC,CAAC,CAAC;YAEH,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,GAAG,EAAE;gBAClC,MAAM,CAAC,IAAI,CAAC,gCAAgC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC;gBAC/D,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED,oDAAoD;IACpD,KAAK,CAAC,IAAI;QACR,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO;QAEzB,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,OAAO,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;YACnC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE;gBAChB,IAAI,CAAC,iBAAiB,EAAE,CAAC;gBACzB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;gBACnB,OAAO,EAAE,CAAC;YACZ,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;OAKG;IACK,KAAK,CAAC,iBAAiB;QAC7B,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QACzC,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CACb,0CAA0C,IAAI,CAAC,UAAU,IAAI,GAAG,8CAA8C,CAC/G,CAAC;QACJ,CAAC;QACD,6CAA6C;QAC7C,IAAI,CAAC;YACH,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QAC3D,CAAC;QAAC,MAAM,CAAC;YACP,4BAA4B;QAC9B,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,aAAa;QACnB,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;YACtC,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/C,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,EAAE;gBACxB,IAAI,CAAC,OAAO,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,CAAC;YAChB,CAAC,CAAC,CAAC;YACH,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;gBACtB,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,iBAAiB;QACvB,IAAI,CAAC;YACH,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC9B,CAAC;QAAC,MAAM,CAAC;YACP,sBAAsB;QACxB,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,MAAc;QACjC,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,UAAU,GAAG,KAAK,CAAC;QAEvB,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAC1B,IAAI,UAAU;gBAAE,OAAO;YACvB,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACzB,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,YAAY,KAAK,CAAC,CAAC;gBAAE,OAAO;YAEhC,UAAU,GAAG,IAAI,CAAC;YAClB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;YACzC,KAAK,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACzB,MAAM,CAAC,IAAI,CAAC,qCAAqC,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;QAClE,CAAC,CAAC,CAAC;QAEH,qCAAqC;QACrC,MAAM,CAAC,UAAU,CAAC,MAAM,EAAE,GAAG,EAAE;YAC7B,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,CAAC,CAAC,CAAC;IACL,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,IAAY,EAAE,MAAc;QACtD,IAAI,OAAuB,CAAC;QAC5B,IAAI,CAAC;YACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAmB,CAAC;QAC/C,CAAC;QAAC,MAAM,CAAC;YACP,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;YAChE,OAAO;QACT,CAAC;QAED,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;YAC9C,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;QACtC,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACjE,IAAI,CAAC,YAAY,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,QAAQ,CAAC,OAAuB;QAC5C,QAAQ,OAAO,CAAC,OAAO,EAAE,CAAC;YACxB,KAAK,MAAM;gBACT,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC;YAEnD,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;gBACxC,OAAO;oBACL,EAAE,EAAE,IAAI;oBACR,IAAI,EAAE;wBACJ,GAAG,MAAM;wBACT,YAAY,EAAE,MAAM,CAAC,YAAY,EAAE,WAAW,EAAE,IAAI,IAAI;qBACzD;iBACF,CAAC;YACJ,CAAC;YAED,KAAK,SAAS;gBACZ,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;gBACvC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;YAEtB,KAAK,YAAY;gBACf,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC5C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;YAEtB,KAAK,YAAY;gBACf,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC5C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;YAEtB,KAAK,aAAa;gBAChB,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC7C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;YAEtB,KAAK,eAAe;gBAClB,MAAM,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC/C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;YAEtB,KAAK,YAAY;gBACf,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC5C,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;YAEtB,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;gBAC3D,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YACpC,CAAC;YAED,KAAK,WAAW,CAAC,CAAC,CAAC;gBACjB,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrC,qCAAqC;gBACrC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAClC,GAAG,CAAC;oBACJ,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,IAAI;iBAC1C,CAAC,CAAC,CAAC;gBACJ,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC;YACxC,CAAC;YAED;gBACE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,oBAAqB,OAA0B,CAAC,OAAO,EAAE,EAAE,CAAC;QAC3F,CAAC;IACH,CAAC;IAEO,YAAY,CAAC,MAAc,EAAE,QAAyB;QAC5D,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,kCAAkC;QACpC,CAAC;IACH,CAAC;CACF;AAED,8EAA8E;AAC9E,oBAAoB;AACpB,8EAA8E;AAE9E,wDAAwD;AACxD,MAAM,eAAe,GAAG,KAAK,CAAC;AAE9B,6DAA6D;AAC7D,MAAM,gBAAgB,GAAG,OAAO,CAAC,CAAC,wCAAwC;AAE1E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAuB,EACvB,UAAmB;IAEnB,MAAM,IAAI,GAAG,UAAU,IAAI,mBAAmB,EAAE,CAAC;IAEjD,OAAO,IAAI,OAAO,CAAyB,CAAC,OAAO,EAAE,EAAE;QACrD,MAAM,MAAM,GAAG,gBAAgB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC1C,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,YAAY,GAAyC,IAAI,CAAC;QAE9D,MAAM,MAAM,GAAG,CAAC,MAA8B,EAAE,EAAE;YAChD,IAAI,OAAO;gBAAE,OAAO;YACpB,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,YAAY;gBAAE,YAAY,CAAC,YAAY,CAAC,CAAC;YAC7C,MAAM,CAAC,OAAO,EAAE,CAAC;YACjB,OAAO,CAAC,MAAM,CAAC,CAAC;QAClB,CAAC,CAAC;QAEF,MAAM,CAAC,UAAU,CAAC,gBAAgB,EAAE,GAAG,EAAE;YACvC,MAAM,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE;YACxB,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;QAC/C,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE;YAC1B,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;YACzB,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACxC,IAAI,YAAY,KAAK,CAAC,CAAC;gBAAE,OAAO;YAEhC,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAoB,CAAC;gBAC5E,MAAM,CAAC,QAAQ,CAAC,CAAC;YACnB,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,CAAC,IAAI,CAAC,CAAC;YACf,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACtB,MAAM,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,2CAA2C;QAC3C,YAAY,GAAG,UAAU,CAAC,GAAG,EAAE;YAC7B,MAAM,CAAC,IAAI,CAAC,CAAC;QACf,CAAC,EAAE,eAAe,CAAC,CAAC;IACtB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,UAAmB;IACvD,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,UAAU,CAAC,CAAC;IAC3E,OAAO,QAAQ,KAAK,IAAI,IAAI,QAAQ,CAAC,EAAE,CAAC;AAC1C,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI entry point for `ironcurtain daemon` and its subcommands.
|
|
3
|
+
*
|
|
4
|
+
* When no sub-subcommand is given, starts the unified daemon.
|
|
5
|
+
* Subcommands: add-job, list-jobs, run-job, remove-job,
|
|
6
|
+
* disable-job, enable-job, recompile-job, logs
|
|
7
|
+
*
|
|
8
|
+
* Commands that modify daemon state (remove-job, enable-job, disable-job,
|
|
9
|
+
* recompile-job, run-job) first check if a daemon is running via the
|
|
10
|
+
* control socket. If running, the command is forwarded to the daemon.
|
|
11
|
+
* Otherwise, the command operates directly on the filesystem.
|
|
12
|
+
*/
|
|
13
|
+
export declare function runDaemonCommand(argv: string[]): Promise<void>;
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI entry point for `ironcurtain daemon` and its subcommands.
|
|
3
|
+
*
|
|
4
|
+
* When no sub-subcommand is given, starts the unified daemon.
|
|
5
|
+
* Subcommands: add-job, list-jobs, run-job, remove-job,
|
|
6
|
+
* disable-job, enable-job, recompile-job, logs
|
|
7
|
+
*
|
|
8
|
+
* Commands that modify daemon state (remove-job, enable-job, disable-job,
|
|
9
|
+
* recompile-job, run-job) first check if a daemon is running via the
|
|
10
|
+
* control socket. If running, the command is forwarded to the daemon.
|
|
11
|
+
* Otherwise, the command operates directly on the filesystem.
|
|
12
|
+
*/
|
|
13
|
+
import { parseArgs } from 'node:util';
|
|
14
|
+
import { IronCurtainDaemon } from './ironcurtain-daemon.js';
|
|
15
|
+
import { sendControlRequest } from './control-socket.js';
|
|
16
|
+
import { formatDuration } from '../cron/format-utils.js';
|
|
17
|
+
import { checkHelp } from '../cli-help.js';
|
|
18
|
+
const daemonSpec = {
|
|
19
|
+
name: 'ironcurtain daemon',
|
|
20
|
+
description: 'Unified Signal + cron daemon',
|
|
21
|
+
usage: [
|
|
22
|
+
'ironcurtain daemon [options] Start the daemon',
|
|
23
|
+
'ironcurtain daemon <subcommand> [options] Manage jobs',
|
|
24
|
+
],
|
|
25
|
+
subcommands: [
|
|
26
|
+
{ name: 'add-job', description: 'Add a new scheduled job (interactive)' },
|
|
27
|
+
{ name: 'edit-job <id>', description: 'Edit an existing job (interactive)' },
|
|
28
|
+
{ name: 'list-jobs', description: 'List all jobs with schedule info' },
|
|
29
|
+
{ name: 'run-job <id>', description: 'Manually trigger a job run' },
|
|
30
|
+
{ name: 'status', description: 'Show daemon status' },
|
|
31
|
+
{ name: 'remove-job <id>', description: 'Delete a job and all artifacts' },
|
|
32
|
+
{ name: 'disable-job <id>', description: 'Stop scheduling a job' },
|
|
33
|
+
{ name: 'enable-job <id>', description: 'Resume scheduling a job' },
|
|
34
|
+
{ name: 'recompile-job <id>', description: 'Re-run policy compilation' },
|
|
35
|
+
{ name: 'logs <id>', description: 'Show recent run summaries' },
|
|
36
|
+
],
|
|
37
|
+
options: [
|
|
38
|
+
{ flag: 'agent', short: 'a', description: 'Agent mode (same as start)', placeholder: '<name>' },
|
|
39
|
+
{ flag: 'force', short: 'f', description: 'Skip confirmation prompts' },
|
|
40
|
+
{ flag: 'no-signal', description: 'Skip Signal transport (cron-only mode)' },
|
|
41
|
+
{ flag: 'runs', description: 'Number of recent runs to show (for logs)', placeholder: '<N>' },
|
|
42
|
+
],
|
|
43
|
+
};
|
|
44
|
+
/** Extracts a required job-id positional, exiting with usage if missing. */
|
|
45
|
+
function requireJobIdArg(positionals) {
|
|
46
|
+
const jobId = positionals[1];
|
|
47
|
+
if (!jobId) {
|
|
48
|
+
console.error('Usage: ironcurtain daemon <subcommand> <job-id>');
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
return jobId;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Attempts to forward a command to a running daemon.
|
|
55
|
+
* Returns the response if the daemon handled it, or null if no daemon
|
|
56
|
+
* is running (caller should fall back to local filesystem operations).
|
|
57
|
+
*/
|
|
58
|
+
async function tryForwardToDaemon(request) {
|
|
59
|
+
return sendControlRequest(request);
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Handles a forwarded response: prints success/error and exits.
|
|
63
|
+
* Returns true if the response was handled (caller should return).
|
|
64
|
+
*/
|
|
65
|
+
function handleForwardedResponse(response, successMessage) {
|
|
66
|
+
if (response === null)
|
|
67
|
+
return false;
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
console.error(`Error from daemon: ${response.error}`);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
72
|
+
if (successMessage) {
|
|
73
|
+
console.error(successMessage);
|
|
74
|
+
}
|
|
75
|
+
return true;
|
|
76
|
+
}
|
|
77
|
+
export async function runDaemonCommand(argv) {
|
|
78
|
+
const { values, positionals } = parseArgs({
|
|
79
|
+
args: argv,
|
|
80
|
+
options: {
|
|
81
|
+
agent: { type: 'string', short: 'a' },
|
|
82
|
+
'no-signal': { type: 'boolean' },
|
|
83
|
+
force: { type: 'boolean', short: 'f' },
|
|
84
|
+
runs: { type: 'string' },
|
|
85
|
+
help: { type: 'boolean', short: 'h' },
|
|
86
|
+
},
|
|
87
|
+
allowPositionals: true,
|
|
88
|
+
strict: false,
|
|
89
|
+
});
|
|
90
|
+
if (checkHelp(values, daemonSpec)) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const subcommand = positionals[0];
|
|
94
|
+
// Resolve session mode (same as `start` command)
|
|
95
|
+
const { resolveSessionMode } = await import('../session/preflight.js');
|
|
96
|
+
const { loadConfig } = await import('../config/index.js');
|
|
97
|
+
const preflight = await resolveSessionMode({
|
|
98
|
+
config: loadConfig(),
|
|
99
|
+
requestedAgent: values.agent ? values.agent : undefined,
|
|
100
|
+
});
|
|
101
|
+
const mode = preflight.mode;
|
|
102
|
+
console.error(`Mode: ${mode.kind} (${preflight.reason})`);
|
|
103
|
+
if (!subcommand) {
|
|
104
|
+
// Start the daemon
|
|
105
|
+
const daemon = new IronCurtainDaemon({
|
|
106
|
+
mode,
|
|
107
|
+
noSignal: values['no-signal'],
|
|
108
|
+
});
|
|
109
|
+
// Handle shutdown signals
|
|
110
|
+
const shutdownHandler = async () => {
|
|
111
|
+
await daemon.shutdown();
|
|
112
|
+
process.exit(0);
|
|
113
|
+
};
|
|
114
|
+
process.on('SIGINT', () => void shutdownHandler());
|
|
115
|
+
process.on('SIGTERM', () => void shutdownHandler());
|
|
116
|
+
await daemon.start();
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// Sub-subcommands that work without a running daemon
|
|
120
|
+
switch (subcommand) {
|
|
121
|
+
case 'add-job': {
|
|
122
|
+
const { runAddJobWizard } = await import('../cron/job-commands.js');
|
|
123
|
+
await runAddJobWizard();
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
case 'edit-job': {
|
|
127
|
+
const jobId = requireJobIdArg(positionals);
|
|
128
|
+
const { runEditJobWizard } = await import('../cron/job-commands.js');
|
|
129
|
+
await runEditJobWizard(jobId);
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
case 'status': {
|
|
133
|
+
const { sendControlRequest: sendReq } = await import('./control-socket.js');
|
|
134
|
+
const resp = await sendReq({ command: 'status' });
|
|
135
|
+
if (!resp || !resp.ok) {
|
|
136
|
+
console.error('Daemon is not running.');
|
|
137
|
+
break;
|
|
138
|
+
}
|
|
139
|
+
const status = resp.data;
|
|
140
|
+
const uptimeStr = formatDuration(status.uptimeSeconds);
|
|
141
|
+
console.error('Daemon is running.');
|
|
142
|
+
console.error(` Uptime: ${uptimeStr}`);
|
|
143
|
+
console.error(` Jobs: ${status.jobs.total} total, ${status.jobs.enabled} enabled, ${status.jobs.running} running`);
|
|
144
|
+
console.error(` Signal transport: ${status.signalConnected ? 'connected' : 'not configured'}`);
|
|
145
|
+
if (status.nextFireTime) {
|
|
146
|
+
const { formatRelativeTime } = await import('../cron/format-utils.js');
|
|
147
|
+
console.error(` Next scheduled run: ${formatRelativeTime(new Date(status.nextFireTime))}`);
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
console.error(' Next scheduled run: none');
|
|
151
|
+
}
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
case 'list-jobs': {
|
|
155
|
+
const resp = await tryForwardToDaemon({ command: 'list-jobs' });
|
|
156
|
+
if (handleForwardedResponse(resp)) {
|
|
157
|
+
const { formatDaemonJobList } = await import('../cron/job-commands.js');
|
|
158
|
+
formatDaemonJobList(resp.data);
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
const { runListJobs } = await import('../cron/job-commands.js');
|
|
162
|
+
runListJobs();
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
case 'run-job': {
|
|
166
|
+
const jobId = requireJobIdArg(positionals);
|
|
167
|
+
const resp = await tryForwardToDaemon({ command: 'run-job', jobId });
|
|
168
|
+
if (handleForwardedResponse(resp)) {
|
|
169
|
+
const record = resp.data;
|
|
170
|
+
console.error(`Job "${jobId}" completed via daemon.`);
|
|
171
|
+
console.error(` Outcome: ${record.outcome.kind}`);
|
|
172
|
+
console.error(` Duration: ${record.budget.elapsedSeconds.toFixed(0)}s`);
|
|
173
|
+
console.error(` Cost: $${record.budget.estimatedCostUsd.toFixed(2)}`);
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
const { runJobCommand } = await import('../cron/job-commands.js');
|
|
177
|
+
await runJobCommand(jobId);
|
|
178
|
+
break;
|
|
179
|
+
}
|
|
180
|
+
case 'remove-job': {
|
|
181
|
+
const jobId = requireJobIdArg(positionals);
|
|
182
|
+
// When forwarding to daemon via control socket, skip interactive prompt
|
|
183
|
+
const resp = await tryForwardToDaemon({ command: 'remove-job', jobId });
|
|
184
|
+
if (handleForwardedResponse(resp, `Job "${jobId}" removed (daemon notified).`))
|
|
185
|
+
break;
|
|
186
|
+
const { runRemoveJob } = await import('../cron/job-commands.js');
|
|
187
|
+
await runRemoveJob(jobId, values.force);
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
case 'disable-job': {
|
|
191
|
+
const jobId = requireJobIdArg(positionals);
|
|
192
|
+
const resp = await tryForwardToDaemon({ command: 'disable-job', jobId });
|
|
193
|
+
if (handleForwardedResponse(resp, `Job "${jobId}" disabled (daemon notified).`))
|
|
194
|
+
break;
|
|
195
|
+
const { runDisableJob } = await import('../cron/job-commands.js');
|
|
196
|
+
await runDisableJob(jobId);
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
case 'enable-job': {
|
|
200
|
+
const jobId = requireJobIdArg(positionals);
|
|
201
|
+
const resp = await tryForwardToDaemon({ command: 'enable-job', jobId });
|
|
202
|
+
if (handleForwardedResponse(resp, `Job "${jobId}" enabled (daemon notified).`))
|
|
203
|
+
break;
|
|
204
|
+
const { runEnableJob } = await import('../cron/job-commands.js');
|
|
205
|
+
await runEnableJob(jobId);
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
case 'recompile-job': {
|
|
209
|
+
const jobId = requireJobIdArg(positionals);
|
|
210
|
+
const resp = await tryForwardToDaemon({ command: 'recompile-job', jobId });
|
|
211
|
+
if (handleForwardedResponse(resp, `Job "${jobId}" policy recompiled (daemon notified).`))
|
|
212
|
+
break;
|
|
213
|
+
const { runRecompileJob } = await import('../cron/job-commands.js');
|
|
214
|
+
await runRecompileJob(jobId);
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
case 'logs': {
|
|
218
|
+
const jobId = requireJobIdArg(positionals);
|
|
219
|
+
const limit = values.runs ? parseInt(values.runs, 10) : 5;
|
|
220
|
+
const { runShowLogs } = await import('../cron/job-commands.js');
|
|
221
|
+
runShowLogs(jobId, limit);
|
|
222
|
+
break;
|
|
223
|
+
}
|
|
224
|
+
default:
|
|
225
|
+
console.error(`Unknown daemon subcommand: ${subcommand}\n`);
|
|
226
|
+
checkHelp({ help: true }, daemonSpec);
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=daemon-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon-command.js","sourceRoot":"","sources":["../../src/daemon/daemon-command.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IronCurtainDaemon -- Unified daemon managing both Signal-initiated
|
|
3
|
+
* interactive sessions and cron-scheduled headless sessions.
|
|
4
|
+
*
|
|
5
|
+
* Lifecycle:
|
|
6
|
+
* 1. start() -- loads jobs, starts Signal (if configured), schedules jobs
|
|
7
|
+
* 2. Runs indefinitely, processing Signal messages and cron triggers
|
|
8
|
+
* 3. shutdown() -- unschedules all jobs, ends all sessions, disconnects
|
|
9
|
+
*
|
|
10
|
+
* Both Signal and cron sessions are managed through a shared SessionManager
|
|
11
|
+
* instance. This enables unified escalation routing: `approve #N` from
|
|
12
|
+
* Signal works for both Signal-initiated and cron-initiated sessions.
|
|
13
|
+
*/
|
|
14
|
+
import type { SessionMode } from '../session/types.js';
|
|
15
|
+
import type { JobDefinition, JobId, RunRecord } from '../cron/types.js';
|
|
16
|
+
import { type DaemonStatus } from './control-socket.js';
|
|
17
|
+
export type { SessionSource, ManagedSession } from '../session/session-manager.js';
|
|
18
|
+
export interface IronCurtainDaemonOptions {
|
|
19
|
+
/** Session mode for both Signal and cron sessions. */
|
|
20
|
+
readonly mode: SessionMode;
|
|
21
|
+
/** When true, skip starting Signal transport. */
|
|
22
|
+
readonly noSignal?: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare class IronCurtainDaemon {
|
|
25
|
+
private readonly mode;
|
|
26
|
+
private readonly noSignal;
|
|
27
|
+
private readonly sessionManager;
|
|
28
|
+
private readonly scheduler;
|
|
29
|
+
/** Time the daemon was started (for uptime calculation). */
|
|
30
|
+
private startTime;
|
|
31
|
+
/** Tracks which jobs are currently running (jobId -> session label). */
|
|
32
|
+
private readonly activeJobRuns;
|
|
33
|
+
/** Control socket server for CLI communication. */
|
|
34
|
+
private controlSocket;
|
|
35
|
+
/** Signal daemon instance (null if Signal not configured). */
|
|
36
|
+
private signalDaemon;
|
|
37
|
+
/** Resolve to exit the daemon. */
|
|
38
|
+
private exitResolve;
|
|
39
|
+
constructor(options: IronCurtainDaemonOptions);
|
|
40
|
+
/**
|
|
41
|
+
* Starts the daemon. Loads all enabled jobs, schedules them,
|
|
42
|
+
* optionally starts the Signal transport.
|
|
43
|
+
*/
|
|
44
|
+
start(): Promise<void>;
|
|
45
|
+
/** Graceful shutdown. */
|
|
46
|
+
shutdown(): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Adds a new job. Runs the full policy compilation pipeline
|
|
49
|
+
* before confirming. Schedules the job if enabled.
|
|
50
|
+
*/
|
|
51
|
+
addJob(job: JobDefinition): Promise<void>;
|
|
52
|
+
/** Removes a job. Stops any active run, unschedules, deletes files. */
|
|
53
|
+
removeJob(jobId: JobId): Promise<void>;
|
|
54
|
+
/** Enables a previously disabled job. Schedules it. */
|
|
55
|
+
enableJob(jobId: JobId): Promise<void>;
|
|
56
|
+
/** Disables a job. Unschedules it but preserves files. */
|
|
57
|
+
disableJob(jobId: JobId): Promise<void>;
|
|
58
|
+
/** Reloads a job definition from disk and reschedules it. */
|
|
59
|
+
reloadJob(jobId: JobId): Promise<void>;
|
|
60
|
+
/** Re-runs policy compilation for an existing job. */
|
|
61
|
+
recompileJob(jobId: JobId): Promise<void>;
|
|
62
|
+
/**
|
|
63
|
+
* Manually triggers a job run (for testing).
|
|
64
|
+
* Does not affect the cron schedule.
|
|
65
|
+
*/
|
|
66
|
+
runJobNow(jobId: JobId): Promise<RunRecord>;
|
|
67
|
+
/** Lists all jobs with their schedules and last run status. */
|
|
68
|
+
listJobs(): Array<{
|
|
69
|
+
job: JobDefinition;
|
|
70
|
+
nextRun: Date | undefined;
|
|
71
|
+
lastRun: RunRecord | undefined;
|
|
72
|
+
isRunning: boolean;
|
|
73
|
+
}>;
|
|
74
|
+
/** Returns a status snapshot for the control socket. */
|
|
75
|
+
getStatus(): DaemonStatus;
|
|
76
|
+
/**
|
|
77
|
+
* Called when a scheduled job fires.
|
|
78
|
+
* Checks for overlap, creates a session, and runs the job.
|
|
79
|
+
*/
|
|
80
|
+
private onJobTrigger;
|
|
81
|
+
/**
|
|
82
|
+
* Executes a job: creates a session with the job's workspace and
|
|
83
|
+
* per-job policy, runs it to completion, and records the outcome.
|
|
84
|
+
*/
|
|
85
|
+
private executeJob;
|
|
86
|
+
private handleCronEscalation;
|
|
87
|
+
private startSignalDaemon;
|
|
88
|
+
private startControlSocket;
|
|
89
|
+
private readLastRunSummary;
|
|
90
|
+
}
|