@provos/ironcurtain 0.5.1 → 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.
Files changed (217) hide show
  1. package/README.md +85 -66
  2. package/dist/cli-help.d.ts +63 -0
  3. package/dist/cli-help.js +102 -0
  4. package/dist/cli-help.js.map +1 -0
  5. package/dist/cli.js +78 -52
  6. package/dist/cli.js.map +1 -1
  7. package/dist/config/config-command.js +136 -2
  8. package/dist/config/config-command.js.map +1 -1
  9. package/dist/config/generated/tool-annotations.json +487 -338
  10. package/dist/config/index.d.ts +21 -1
  11. package/dist/config/index.js +12 -4
  12. package/dist/config/index.js.map +1 -1
  13. package/dist/config/mcp-servers.json +2 -8
  14. package/dist/config/paths.d.ts +30 -0
  15. package/dist/config/paths.js +58 -0
  16. package/dist/config/paths.js.map +1 -1
  17. package/dist/config/tool-description-hints.json +15 -0
  18. package/dist/config/types.d.ts +13 -0
  19. package/dist/config/user-config.d.ts +21 -0
  20. package/dist/config/user-config.js +8 -0
  21. package/dist/config/user-config.js.map +1 -1
  22. package/dist/cron/compile-task-policy.d.ts +17 -0
  23. package/dist/cron/compile-task-policy.js +39 -0
  24. package/dist/cron/compile-task-policy.js.map +1 -0
  25. package/dist/cron/cron-scheduler.d.ts +65 -0
  26. package/dist/cron/cron-scheduler.js +184 -0
  27. package/dist/cron/cron-scheduler.js.map +1 -0
  28. package/dist/cron/file-lock.d.ts +41 -0
  29. package/dist/cron/file-lock.js +156 -0
  30. package/dist/cron/file-lock.js.map +1 -0
  31. package/dist/cron/format-utils.d.ts +18 -0
  32. package/dist/cron/format-utils.js +145 -0
  33. package/dist/cron/format-utils.js.map +1 -0
  34. package/dist/cron/git-sync.d.ts +22 -0
  35. package/dist/cron/git-sync.js +121 -0
  36. package/dist/cron/git-sync.js.map +1 -0
  37. package/dist/cron/headless-transport.d.ts +27 -0
  38. package/dist/cron/headless-transport.js +43 -0
  39. package/dist/cron/headless-transport.js.map +1 -0
  40. package/dist/cron/job-commands.d.ts +39 -0
  41. package/dist/cron/job-commands.js +522 -0
  42. package/dist/cron/job-commands.js.map +1 -0
  43. package/dist/cron/job-store.d.ts +35 -0
  44. package/dist/cron/job-store.js +111 -0
  45. package/dist/cron/job-store.js.map +1 -0
  46. package/dist/cron/types.d.ts +127 -0
  47. package/dist/cron/types.js +25 -0
  48. package/dist/cron/types.js.map +1 -0
  49. package/dist/daemon/control-socket.d.ts +127 -0
  50. package/dist/daemon/control-socket.js +261 -0
  51. package/dist/daemon/control-socket.js.map +1 -0
  52. package/dist/daemon/daemon-command.d.ts +13 -0
  53. package/dist/daemon/daemon-command.js +230 -0
  54. package/dist/daemon/daemon-command.js.map +1 -0
  55. package/dist/daemon/ironcurtain-daemon.d.ts +90 -0
  56. package/dist/daemon/ironcurtain-daemon.js +548 -0
  57. package/dist/daemon/ironcurtain-daemon.js.map +1 -0
  58. package/dist/docker/adapters/claude-code.js +8 -48
  59. package/dist/docker/adapters/claude-code.js.map +1 -1
  60. package/dist/docker/adapters/goose.d.ts +58 -0
  61. package/dist/docker/adapters/goose.js +250 -0
  62. package/dist/docker/adapters/goose.js.map +1 -0
  63. package/dist/docker/adapters/shared-scripts.d.ts +29 -0
  64. package/dist/docker/adapters/shared-scripts.js +80 -0
  65. package/dist/docker/adapters/shared-scripts.js.map +1 -0
  66. package/dist/docker/agent-adapter.d.ts +12 -0
  67. package/dist/docker/agent-adapter.js.map +1 -1
  68. package/dist/docker/agent-registry.d.ts +6 -1
  69. package/dist/docker/agent-registry.js +10 -1
  70. package/dist/docker/agent-registry.js.map +1 -1
  71. package/dist/docker/docker-agent-session.d.ts +2 -25
  72. package/dist/docker/docker-agent-session.js +7 -106
  73. package/dist/docker/docker-agent-session.js.map +1 -1
  74. package/dist/docker/docker-infrastructure.d.ts +8 -0
  75. package/dist/docker/docker-infrastructure.js +22 -14
  76. package/dist/docker/docker-infrastructure.js.map +1 -1
  77. package/dist/docker/mitm-proxy.d.ts +5 -2
  78. package/dist/docker/mitm-proxy.js +169 -46
  79. package/dist/docker/mitm-proxy.js.map +1 -1
  80. package/dist/docker/oauth-credentials.d.ts +15 -2
  81. package/dist/docker/oauth-credentials.js +92 -8
  82. package/dist/docker/oauth-credentials.js.map +1 -1
  83. package/dist/docker/oauth-token-manager.d.ts +80 -0
  84. package/dist/docker/oauth-token-manager.js +133 -0
  85. package/dist/docker/oauth-token-manager.js.map +1 -0
  86. package/dist/docker/pty-session.d.ts +2 -0
  87. package/dist/docker/pty-session.js +17 -8
  88. package/dist/docker/pty-session.js.map +1 -1
  89. package/dist/escalation/escalation-watcher.d.ts +2 -0
  90. package/dist/escalation/escalation-watcher.js +5 -0
  91. package/dist/escalation/escalation-watcher.js.map +1 -1
  92. package/dist/escalation/listener-command.js +9 -58
  93. package/dist/escalation/listener-command.js.map +1 -1
  94. package/dist/escalation/listener-lock.d.ts +20 -0
  95. package/dist/escalation/listener-lock.js +69 -0
  96. package/dist/escalation/listener-lock.js.map +1 -0
  97. package/dist/escalation/session-registry.js +1 -14
  98. package/dist/escalation/session-registry.js.map +1 -1
  99. package/dist/index.js +51 -2
  100. package/dist/index.js.map +1 -1
  101. package/dist/mux/mux-app.d.ts +24 -0
  102. package/dist/mux/mux-app.js +450 -0
  103. package/dist/mux/mux-app.js.map +1 -0
  104. package/dist/mux/mux-command.d.ts +7 -0
  105. package/dist/mux/mux-command.js +104 -0
  106. package/dist/mux/mux-command.js.map +1 -0
  107. package/dist/mux/mux-escalation-manager.d.ts +48 -0
  108. package/dist/mux/mux-escalation-manager.js +162 -0
  109. package/dist/mux/mux-escalation-manager.js.map +1 -0
  110. package/dist/mux/mux-input-handler.d.ts +54 -0
  111. package/dist/mux/mux-input-handler.js +512 -0
  112. package/dist/mux/mux-input-handler.js.map +1 -0
  113. package/dist/mux/mux-renderer.d.ts +106 -0
  114. package/dist/mux/mux-renderer.js +850 -0
  115. package/dist/mux/mux-renderer.js.map +1 -0
  116. package/dist/mux/mux-splash.d.ts +17 -0
  117. package/dist/mux/mux-splash.js +323 -0
  118. package/dist/mux/mux-splash.js.map +1 -0
  119. package/dist/mux/paste-interceptor.d.ts +22 -0
  120. package/dist/mux/paste-interceptor.js +143 -0
  121. package/dist/mux/paste-interceptor.js.map +1 -0
  122. package/dist/mux/pty-bridge.d.ts +79 -0
  123. package/dist/mux/pty-bridge.js +151 -0
  124. package/dist/mux/pty-bridge.js.map +1 -0
  125. package/dist/mux/trusted-input.d.ts +27 -0
  126. package/dist/mux/trusted-input.js +27 -0
  127. package/dist/mux/trusted-input.js.map +1 -0
  128. package/dist/mux/types.d.ts +99 -0
  129. package/dist/mux/types.js +57 -0
  130. package/dist/mux/types.js.map +1 -0
  131. package/dist/pipeline/annotate.js +2 -1
  132. package/dist/pipeline/annotate.js.map +1 -1
  133. package/dist/pipeline/compile.d.ts +4 -34
  134. package/dist/pipeline/compile.js +29 -568
  135. package/dist/pipeline/compile.js.map +1 -1
  136. package/dist/pipeline/constitution-compiler.js +1 -1
  137. package/dist/pipeline/mcp-connections.d.ts +16 -0
  138. package/dist/pipeline/mcp-connections.js +61 -0
  139. package/dist/pipeline/mcp-connections.js.map +1 -0
  140. package/dist/pipeline/pipeline-runner.d.ts +86 -0
  141. package/dist/pipeline/pipeline-runner.js +554 -0
  142. package/dist/pipeline/pipeline-runner.js.map +1 -0
  143. package/dist/pipeline/pipeline-shared.d.ts +29 -2
  144. package/dist/pipeline/pipeline-shared.js +68 -12
  145. package/dist/pipeline/pipeline-shared.js.map +1 -1
  146. package/dist/pipeline/refresh-lists.js +38 -12
  147. package/dist/pipeline/refresh-lists.js.map +1 -1
  148. package/dist/pipeline/scenario-generator.js +2 -1
  149. package/dist/pipeline/scenario-generator.js.map +1 -1
  150. package/dist/pipeline/tool-annotator.d.ts +3 -3
  151. package/dist/pipeline/tool-annotator.js +96 -4
  152. package/dist/pipeline/tool-annotator.js.map +1 -1
  153. package/dist/pipeline/types.d.ts +52 -0
  154. package/dist/sandbox/index.js +40 -1
  155. package/dist/sandbox/index.js.map +1 -1
  156. package/dist/session/agent-session.d.ts +3 -0
  157. package/dist/session/agent-session.js +13 -1
  158. package/dist/session/agent-session.js.map +1 -1
  159. package/dist/session/index.js +65 -9
  160. package/dist/session/index.js.map +1 -1
  161. package/dist/session/preflight.js +26 -6
  162. package/dist/session/preflight.js.map +1 -1
  163. package/dist/session/prompts.d.ts +14 -0
  164. package/dist/session/prompts.js +39 -2
  165. package/dist/session/prompts.js.map +1 -1
  166. package/dist/session/session-manager.d.ts +105 -0
  167. package/dist/session/session-manager.js +134 -0
  168. package/dist/session/session-manager.js.map +1 -0
  169. package/dist/session/types.d.ts +33 -0
  170. package/dist/session/workspace-validation.d.ts +19 -0
  171. package/dist/session/workspace-validation.js +66 -0
  172. package/dist/session/workspace-validation.js.map +1 -0
  173. package/dist/signal/bot-command.d.ts +2 -0
  174. package/dist/signal/bot-command.js +8 -0
  175. package/dist/signal/bot-command.js.map +1 -1
  176. package/dist/signal/format.d.ts +27 -0
  177. package/dist/signal/format.js +59 -0
  178. package/dist/signal/format.js.map +1 -1
  179. package/dist/signal/signal-bot-daemon.d.ts +27 -25
  180. package/dist/signal/signal-bot-daemon.js +145 -130
  181. package/dist/signal/signal-bot-daemon.js.map +1 -1
  182. package/dist/signal/signal-container.js +63 -19
  183. package/dist/signal/signal-container.js.map +1 -1
  184. package/dist/signal/signal-transport.js +3 -8
  185. package/dist/signal/signal-transport.js.map +1 -1
  186. package/dist/trusted-process/auto-approver.d.ts +13 -4
  187. package/dist/trusted-process/auto-approver.js +12 -5
  188. package/dist/trusted-process/auto-approver.js.map +1 -1
  189. package/dist/trusted-process/domain-utils.d.ts +38 -4
  190. package/dist/trusted-process/domain-utils.js +118 -11
  191. package/dist/trusted-process/domain-utils.js.map +1 -1
  192. package/dist/trusted-process/escalation.js +5 -0
  193. package/dist/trusted-process/escalation.js.map +1 -1
  194. package/dist/trusted-process/index.js +6 -2
  195. package/dist/trusted-process/index.js.map +1 -1
  196. package/dist/trusted-process/mcp-client-manager.js +11 -5
  197. package/dist/trusted-process/mcp-client-manager.js.map +1 -1
  198. package/dist/trusted-process/mcp-proxy-server.d.ts +2 -0
  199. package/dist/trusted-process/mcp-proxy-server.js +98 -32
  200. package/dist/trusted-process/mcp-proxy-server.js.map +1 -1
  201. package/dist/trusted-process/permissive-output-validator.d.ts +23 -0
  202. package/dist/trusted-process/permissive-output-validator.js +10 -0
  203. package/dist/trusted-process/permissive-output-validator.js.map +1 -0
  204. package/dist/trusted-process/policy-engine.d.ts +27 -4
  205. package/dist/trusted-process/policy-engine.js +152 -57
  206. package/dist/trusted-process/policy-engine.js.map +1 -1
  207. package/dist/trusted-process/tool-description-hints.d.ts +19 -0
  208. package/dist/trusted-process/tool-description-hints.js +53 -0
  209. package/dist/trusted-process/tool-description-hints.js.map +1 -0
  210. package/dist/types/argument-roles.d.ts +33 -1
  211. package/dist/types/argument-roles.js +129 -1
  212. package/dist/types/argument-roles.js.map +1 -1
  213. package/docker/Dockerfile.goose +34 -0
  214. package/docker/entrypoint-goose.sh +30 -0
  215. package/package.json +6 -1
  216. package/src/config/generated/tool-annotations.json +487 -338
  217. package/src/config/mcp-servers.json +2 -8
@@ -0,0 +1,111 @@
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 { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
18
+ import { resolve } from 'node:path';
19
+ import { getJobsDir, getJobDir, getJobRunsDir } from '../config/paths.js';
20
+ import { createJobId } from './types.js';
21
+ import { withFileLock, getJobLockDir } from './file-lock.js';
22
+ /** Loads a job definition from disk. Returns undefined if not found. */
23
+ export function loadJob(jobId) {
24
+ const jobFile = resolve(getJobDir(jobId), 'job.json');
25
+ if (!existsSync(jobFile))
26
+ return undefined;
27
+ try {
28
+ return JSON.parse(readFileSync(jobFile, 'utf-8'));
29
+ }
30
+ catch {
31
+ return undefined;
32
+ }
33
+ }
34
+ /** Loads all job definitions from disk. */
35
+ export function loadAllJobs() {
36
+ const jobsDir = getJobsDir();
37
+ if (!existsSync(jobsDir))
38
+ return [];
39
+ const jobs = [];
40
+ let entries;
41
+ try {
42
+ entries = readdirSync(jobsDir);
43
+ }
44
+ catch {
45
+ return [];
46
+ }
47
+ for (const entry of entries) {
48
+ try {
49
+ const jobId = createJobId(entry);
50
+ const job = loadJob(jobId);
51
+ if (job)
52
+ jobs.push(job);
53
+ }
54
+ catch {
55
+ // Skip invalid directory names or malformed job files
56
+ }
57
+ }
58
+ return jobs;
59
+ }
60
+ /**
61
+ * Saves a job definition to disk. Creates directories as needed.
62
+ * Acquires an advisory file lock to prevent concurrent write corruption.
63
+ */
64
+ export async function saveJob(job) {
65
+ const jobDir = getJobDir(job.id);
66
+ mkdirSync(jobDir, { recursive: true });
67
+ await withFileLock(getJobLockDir(jobDir), () => {
68
+ writeFileSync(resolve(jobDir, 'job.json'), JSON.stringify(job, null, 2) + '\n');
69
+ });
70
+ }
71
+ /** Deletes a job and all its artifacts (generated, workspace, runs). */
72
+ export function deleteJob(jobId) {
73
+ rmSync(getJobDir(jobId), { recursive: true, force: true });
74
+ }
75
+ /** Records a completed run. Filenames are unique (timestamp-based), so no lock needed. */
76
+ export function saveRunRecord(jobId, record) {
77
+ const runsDir = getJobRunsDir(jobId);
78
+ mkdirSync(runsDir, { recursive: true });
79
+ const filename = record.startedAt.replace(/:/g, '-') + '.json';
80
+ writeFileSync(resolve(runsDir, filename), JSON.stringify(record, null, 2) + '\n');
81
+ }
82
+ /**
83
+ * Loads recent run records for a job, most recent first.
84
+ * @param limit Maximum number of records to return (default 10).
85
+ */
86
+ export function loadRecentRuns(jobId, limit = 10) {
87
+ const runsDir = getJobRunsDir(jobId);
88
+ if (!existsSync(runsDir))
89
+ return [];
90
+ let files;
91
+ try {
92
+ files = readdirSync(runsDir).filter((f) => f.endsWith('.json'));
93
+ }
94
+ catch {
95
+ return [];
96
+ }
97
+ // Sort by filename (ISO timestamp-based) descending
98
+ files.sort((a, b) => b.localeCompare(a));
99
+ const records = [];
100
+ for (const file of files.slice(0, limit)) {
101
+ try {
102
+ const record = JSON.parse(readFileSync(resolve(runsDir, file), 'utf-8'));
103
+ records.push(record);
104
+ }
105
+ catch {
106
+ // Skip malformed run records
107
+ }
108
+ }
109
+ return records;
110
+ }
111
+ //# sourceMappingURL=job-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-store.js","sourceRoot":"","sources":["../../src/cron/job-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,127 @@
1
+ /**
2
+ * Cron Mode types -- job definitions, run records, and budget overrides.
3
+ *
4
+ * These types are used by the job store, cron scheduler, daemon,
5
+ * and CLI commands.
6
+ */
7
+ /**
8
+ * Stable, user-chosen identifier for a cron job.
9
+ * Must be a valid slug: lowercase alphanumeric, hyphens, underscores.
10
+ * Branded to prevent mixing with other string identifiers.
11
+ */
12
+ export type JobId = string & {
13
+ readonly __brand: 'JobId';
14
+ };
15
+ /** Regex for valid job IDs: 1-63 chars, lowercase alphanumeric, hyphens, or underscores. */
16
+ export declare const JOB_ID_PATTERN: RegExp;
17
+ /** Validates and creates a JobId from a user-provided string. */
18
+ export declare function createJobId(raw: string): JobId;
19
+ /**
20
+ * Persisted job definition. Stored as JSON at
21
+ * ~/.ironcurtain/jobs/{jobId}/job.json.
22
+ *
23
+ * Invariant: the `task` field is the "constitution" input for
24
+ * per-job policy compilation. Changing it invalidates the
25
+ * compiled policy (detected via content hash comparison).
26
+ */
27
+ export interface JobDefinition {
28
+ /** Stable user-chosen slug. Matches the directory name. */
29
+ readonly id: JobId;
30
+ /** Human-friendly display name. */
31
+ readonly name: string;
32
+ /** Standard cron expression (5 fields: min hour dom mon dow). */
33
+ readonly schedule: string;
34
+ /**
35
+ * English task description sent to the agent as its work prompt.
36
+ */
37
+ readonly taskDescription: string;
38
+ /**
39
+ * English constitution text used as the policy compilation input.
40
+ * Describes what the agent is and is not permitted to do.
41
+ */
42
+ readonly taskConstitution: string;
43
+ /**
44
+ * Working directory for this job. Persists across runs.
45
+ * Default: ~/.ironcurtain/jobs/{jobId}/workspace/
46
+ */
47
+ readonly workspace?: string;
48
+ /**
49
+ * Optional git repository URI to clone into the workspace.
50
+ * On first run, the repo is cloned. On subsequent runs,
51
+ * tracked files are reset to remote HEAD (untracked files preserved).
52
+ */
53
+ readonly gitRepo?: string;
54
+ /**
55
+ * When true and Signal is configured, the daemon sends a Signal
56
+ * message on escalation and waits for approval. When false or
57
+ * Signal is not configured, escalations are auto-denied.
58
+ */
59
+ readonly notifyOnEscalation: boolean;
60
+ /**
61
+ * When true and Signal is configured, the daemon sends a Signal
62
+ * message with the run summary on completion.
63
+ */
64
+ readonly notifyOnCompletion: boolean;
65
+ /**
66
+ * Per-job resource budget overrides. Null fields inherit from
67
+ * the cron-specific defaults.
68
+ */
69
+ readonly budgetOverrides?: Partial<JobBudgetOverrides>;
70
+ /** Whether this job is active. Disabled jobs are not scheduled. */
71
+ readonly enabled: boolean;
72
+ }
73
+ /**
74
+ * Budget fields that can be overridden per-job.
75
+ * All fields are nullable: null means "disable this limit".
76
+ */
77
+ export interface JobBudgetOverrides {
78
+ readonly maxTotalTokens: number | null;
79
+ readonly maxSteps: number | null;
80
+ readonly maxSessionSeconds: number | null;
81
+ readonly maxEstimatedCostUsd: number | null;
82
+ }
83
+ /**
84
+ * Outcome status for a completed run.
85
+ */
86
+ export type RunOutcome = {
87
+ readonly kind: 'success';
88
+ } | {
89
+ readonly kind: 'budget_exhausted';
90
+ readonly dimension: string;
91
+ } | {
92
+ readonly kind: 'error';
93
+ readonly message: string;
94
+ };
95
+ /**
96
+ * Persisted run record. Written to
97
+ * ~/.ironcurtain/jobs/{jobId}/runs/{timestamp}.json
98
+ * after each run completes.
99
+ */
100
+ export interface RunRecord {
101
+ /** ISO 8601 start time. Also used as the filename. */
102
+ readonly startedAt: string;
103
+ /** ISO 8601 end time. */
104
+ readonly completedAt: string;
105
+ /** How the run ended. */
106
+ readonly outcome: RunOutcome;
107
+ /** Resource consumption snapshot. */
108
+ readonly budget: {
109
+ readonly totalTokens: number;
110
+ readonly stepCount: number;
111
+ readonly elapsedSeconds: number;
112
+ readonly estimatedCostUsd: number;
113
+ };
114
+ /**
115
+ * Brief summary extracted from workspace/last-run.md, if it exists.
116
+ * Truncated to 2000 chars. Null if the file was not written.
117
+ */
118
+ readonly summary: string | null;
119
+ /** Whether any escalations were surfaced during this run. */
120
+ readonly escalationsEncountered: number;
121
+ /** Whether any escalations were approved (vs. denied or timed out). */
122
+ readonly escalationsApproved: number;
123
+ /** git diff --stat of tracked-file changes discarded during pre-run sync. */
124
+ readonly discardedChanges: string | null;
125
+ }
126
+ /** Cron-specific budget defaults (differ from interactive defaults). */
127
+ export declare const CRON_BUDGET_DEFAULTS: Required<JobBudgetOverrides>;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Cron Mode types -- job definitions, run records, and budget overrides.
3
+ *
4
+ * These types are used by the job store, cron scheduler, daemon,
5
+ * and CLI commands.
6
+ */
7
+ /** Regex for valid job IDs: 1-63 chars, lowercase alphanumeric, hyphens, or underscores. */
8
+ export const JOB_ID_PATTERN = /^[a-z0-9][a-z0-9_-]{0,62}$/;
9
+ /** Validates and creates a JobId from a user-provided string. */
10
+ export function createJobId(raw) {
11
+ if (!JOB_ID_PATTERN.test(raw)) {
12
+ throw new Error(`Invalid job ID "${raw}": must be 1-63 chars, ` +
13
+ `lowercase alphanumeric, hyphens, or underscores, ` +
14
+ `starting with a letter or digit`);
15
+ }
16
+ return raw;
17
+ }
18
+ /** Cron-specific budget defaults (differ from interactive defaults). */
19
+ export const CRON_BUDGET_DEFAULTS = {
20
+ maxTotalTokens: 500_000,
21
+ maxSteps: 100,
22
+ maxSessionSeconds: 3_600,
23
+ maxEstimatedCostUsd: 2.0,
24
+ };
25
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/cron/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,4FAA4F;AAC5F,MAAM,CAAC,MAAM,cAAc,GAAG,4BAA4B,CAAC;AAE3D,iEAAiE;AACjE,MAAM,UAAU,WAAW,CAAC,GAAW;IACrC,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CACb,mBAAmB,GAAG,yBAAyB;YAC7C,mDAAmD;YACnD,iCAAiC,CACpC,CAAC;IACJ,CAAC;IACD,OAAO,GAAY,CAAC;AACtB,CAAC;AA6HD,wEAAwE;AACxE,MAAM,CAAC,MAAM,oBAAoB,GAAiC;IAChE,cAAc,EAAE,OAAO;IACvB,QAAQ,EAAE,GAAG;IACb,iBAAiB,EAAE,KAAK;IACxB,mBAAmB,EAAE,GAAG;CACzB,CAAC"}
@@ -0,0 +1,127 @@
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 type { JobDefinition, RunRecord } from '../cron/types.js';
13
+ /** Commands the CLI can send to the daemon. */
14
+ export type ControlRequest = {
15
+ readonly command: 'ping';
16
+ } | {
17
+ readonly command: 'status';
18
+ } | {
19
+ readonly command: 'add-job';
20
+ readonly job: JobDefinition;
21
+ } | {
22
+ readonly command: 'remove-job';
23
+ readonly jobId: string;
24
+ } | {
25
+ readonly command: 'enable-job';
26
+ readonly jobId: string;
27
+ } | {
28
+ readonly command: 'disable-job';
29
+ readonly jobId: string;
30
+ } | {
31
+ readonly command: 'recompile-job';
32
+ readonly jobId: string;
33
+ } | {
34
+ readonly command: 'reload-job';
35
+ readonly jobId: string;
36
+ } | {
37
+ readonly command: 'run-job';
38
+ readonly jobId: string;
39
+ } | {
40
+ readonly command: 'list-jobs';
41
+ };
42
+ /** Successful response from the daemon. */
43
+ export interface ControlResponseOk {
44
+ readonly ok: true;
45
+ readonly data?: unknown;
46
+ }
47
+ /** Error response from the daemon. */
48
+ export interface ControlResponseError {
49
+ readonly ok: false;
50
+ readonly error: string;
51
+ }
52
+ export type ControlResponse = ControlResponseOk | ControlResponseError;
53
+ /** Status snapshot returned by the daemon. */
54
+ export interface DaemonStatus {
55
+ readonly uptimeSeconds: number;
56
+ readonly jobs: {
57
+ total: number;
58
+ enabled: number;
59
+ running: number;
60
+ };
61
+ readonly signalConnected: boolean;
62
+ readonly nextFireTime: Date | null;
63
+ }
64
+ /** JSON-serialized form of DaemonStatus (Date → ISO string). */
65
+ export interface DaemonStatusDto {
66
+ readonly uptimeSeconds: number;
67
+ readonly jobs: {
68
+ total: number;
69
+ enabled: number;
70
+ running: number;
71
+ };
72
+ readonly signalConnected: boolean;
73
+ readonly nextFireTime: string | null;
74
+ }
75
+ export interface ControlRequestHandler {
76
+ getStatus(): DaemonStatus;
77
+ addJob(job: JobDefinition): Promise<void>;
78
+ removeJob(jobId: string): Promise<void>;
79
+ enableJob(jobId: string): Promise<void>;
80
+ disableJob(jobId: string): Promise<void>;
81
+ recompileJob(jobId: string): Promise<void>;
82
+ reloadJob(jobId: string): Promise<void>;
83
+ runJobNow(jobId: string): Promise<RunRecord>;
84
+ listJobs(): Array<{
85
+ job: JobDefinition;
86
+ nextRun: Date | undefined;
87
+ lastRun: RunRecord | undefined;
88
+ isRunning: boolean;
89
+ }>;
90
+ }
91
+ export declare class ControlSocketServer {
92
+ private server;
93
+ private readonly socketPath;
94
+ private readonly handler;
95
+ constructor(handler: ControlRequestHandler, socketPath?: string);
96
+ /** Starts listening on the Unix domain socket. */
97
+ start(): Promise<void>;
98
+ /** Stops the server and removes the socket file. */
99
+ stop(): Promise<void>;
100
+ /**
101
+ * Removes a stale socket file left behind by a crashed daemon.
102
+ * Attempts to connect first — only unlinks when the socket is
103
+ * confirmed stale (ECONNREFUSED) or absent (ENOENT). If the
104
+ * socket is live, throws so the caller knows another daemon is running.
105
+ */
106
+ private removeStaleSocket;
107
+ /**
108
+ * Probes whether the socket is actively accepting connections.
109
+ * Returns true if a daemon is listening, false if stale/absent.
110
+ */
111
+ private isSocketAlive;
112
+ private cleanupSocketFile;
113
+ private onConnection;
114
+ private handleRequest;
115
+ private dispatch;
116
+ private sendResponse;
117
+ }
118
+ /**
119
+ * Sends a request to the running daemon via the control socket.
120
+ * Returns the parsed response, or null if the daemon is not reachable.
121
+ */
122
+ export declare function sendControlRequest(request: ControlRequest, socketPath?: string): Promise<ControlResponse | null>;
123
+ /**
124
+ * Checks if a daemon is currently running and responsive.
125
+ * Returns true if the daemon responds to a ping.
126
+ */
127
+ export declare function isDaemonRunning(socketPath?: string): Promise<boolean>;
@@ -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":"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"}