aicodeman 1.2.1 → 1.3.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 (232) hide show
  1. package/README.md +264 -90
  2. package/dist/attachment-magic.d.ts +13 -0
  3. package/dist/attachment-magic.d.ts.map +1 -1
  4. package/dist/attachment-magic.js +47 -0
  5. package/dist/attachment-magic.js.map +1 -1
  6. package/dist/attachment-registry.d.ts.map +1 -1
  7. package/dist/attachment-registry.js +13 -2
  8. package/dist/attachment-registry.js.map +1 -1
  9. package/dist/config/buffer-limits.d.ts +2 -3
  10. package/dist/config/buffer-limits.d.ts.map +1 -1
  11. package/dist/config/buffer-limits.js +5 -5
  12. package/dist/config/buffer-limits.js.map +1 -1
  13. package/dist/config/map-limits.d.ts +11 -0
  14. package/dist/config/map-limits.d.ts.map +1 -1
  15. package/dist/config/map-limits.js +11 -0
  16. package/dist/config/map-limits.js.map +1 -1
  17. package/dist/config/server-timing.d.ts +6 -0
  18. package/dist/config/server-timing.d.ts.map +1 -1
  19. package/dist/config/server-timing.js +9 -0
  20. package/dist/config/server-timing.js.map +1 -1
  21. package/dist/config/terminal-history.d.ts +30 -0
  22. package/dist/config/terminal-history.d.ts.map +1 -0
  23. package/dist/config/terminal-history.js +43 -0
  24. package/dist/config/terminal-history.js.map +1 -0
  25. package/dist/cron/cron-input.d.ts +30 -0
  26. package/dist/cron/cron-input.d.ts.map +1 -0
  27. package/dist/cron/cron-input.js +7 -0
  28. package/dist/cron/cron-input.js.map +1 -0
  29. package/dist/cron/cron-service.d.ts +92 -0
  30. package/dist/cron/cron-service.d.ts.map +1 -0
  31. package/dist/cron/cron-service.js +606 -0
  32. package/dist/cron/cron-service.js.map +1 -0
  33. package/dist/cron/cron-time.d.ts +29 -0
  34. package/dist/cron/cron-time.d.ts.map +1 -0
  35. package/dist/cron/cron-time.js +87 -0
  36. package/dist/cron/cron-time.js.map +1 -0
  37. package/dist/document-thumbnailer.d.ts +1 -1
  38. package/dist/document-thumbnailer.d.ts.map +1 -1
  39. package/dist/document-thumbnailer.js +11 -2
  40. package/dist/document-thumbnailer.js.map +1 -1
  41. package/dist/generated-artifact-attachments.d.ts +26 -0
  42. package/dist/generated-artifact-attachments.d.ts.map +1 -0
  43. package/dist/generated-artifact-attachments.js +61 -0
  44. package/dist/generated-artifact-attachments.js.map +1 -0
  45. package/dist/index.js +11 -0
  46. package/dist/index.js.map +1 -1
  47. package/dist/mux-interface.d.ts +37 -5
  48. package/dist/mux-interface.d.ts.map +1 -1
  49. package/dist/remote-hosts.d.ts +66 -0
  50. package/dist/remote-hosts.d.ts.map +1 -0
  51. package/dist/remote-hosts.js +198 -0
  52. package/dist/remote-hosts.js.map +1 -0
  53. package/dist/services/unified-session-service.d.ts +115 -0
  54. package/dist/services/unified-session-service.d.ts.map +1 -0
  55. package/dist/services/unified-session-service.js +173 -0
  56. package/dist/services/unified-session-service.js.map +1 -0
  57. package/dist/session-cli-builder.d.ts +3 -1
  58. package/dist/session-cli-builder.d.ts.map +1 -1
  59. package/dist/session-cli-builder.js +26 -7
  60. package/dist/session-cli-builder.js.map +1 -1
  61. package/dist/session-pty-exit-breaker.d.ts +66 -0
  62. package/dist/session-pty-exit-breaker.d.ts.map +1 -0
  63. package/dist/session-pty-exit-breaker.js +77 -0
  64. package/dist/session-pty-exit-breaker.js.map +1 -0
  65. package/dist/session.d.ts +27 -1
  66. package/dist/session.d.ts.map +1 -1
  67. package/dist/session.js +102 -11
  68. package/dist/session.js.map +1 -1
  69. package/dist/state-store.d.ts +14 -0
  70. package/dist/state-store.d.ts.map +1 -1
  71. package/dist/state-store.js +49 -0
  72. package/dist/state-store.js.map +1 -1
  73. package/dist/tmux-manager.d.ts +100 -8
  74. package/dist/tmux-manager.d.ts.map +1 -1
  75. package/dist/tmux-manager.js +249 -26
  76. package/dist/tmux-manager.js.map +1 -1
  77. package/dist/types/api.d.ts +11 -0
  78. package/dist/types/api.d.ts.map +1 -1
  79. package/dist/types/api.js.map +1 -1
  80. package/dist/types/app-state.d.ts +5 -0
  81. package/dist/types/app-state.d.ts.map +1 -1
  82. package/dist/types/app-state.js.map +1 -1
  83. package/dist/types/cron.d.ts +88 -0
  84. package/dist/types/cron.d.ts.map +1 -0
  85. package/dist/types/cron.js +13 -0
  86. package/dist/types/cron.js.map +1 -0
  87. package/dist/types/session.d.ts +57 -0
  88. package/dist/types/session.d.ts.map +1 -1
  89. package/dist/types/session.js.map +1 -1
  90. package/dist/web/heic-jpeg-converter.d.ts +24 -0
  91. package/dist/web/heic-jpeg-converter.d.ts.map +1 -0
  92. package/dist/web/heic-jpeg-converter.js +76 -0
  93. package/dist/web/heic-jpeg-converter.js.map +1 -0
  94. package/dist/web/heic-jpeg-worker.d.ts +44 -0
  95. package/dist/web/heic-jpeg-worker.d.ts.map +1 -0
  96. package/dist/web/heic-jpeg-worker.js +78 -0
  97. package/dist/web/heic-jpeg-worker.js.map +1 -0
  98. package/dist/web/ports/config-port.d.ts +2 -0
  99. package/dist/web/ports/config-port.d.ts.map +1 -1
  100. package/dist/web/ports/cron-port.d.ts +9 -0
  101. package/dist/web/ports/cron-port.d.ts.map +1 -0
  102. package/dist/web/ports/cron-port.js +6 -0
  103. package/dist/web/ports/cron-port.js.map +1 -0
  104. package/dist/web/ports/index.d.ts +1 -0
  105. package/dist/web/ports/index.d.ts.map +1 -1
  106. package/dist/web/public/api-client.c9b1cddc.js.gz +0 -0
  107. package/dist/web/public/app.b0534652.js +38 -0
  108. package/dist/web/public/app.b0534652.js.br +0 -0
  109. package/dist/web/public/app.b0534652.js.gz +0 -0
  110. package/dist/web/public/{constants.1c779517.js → constants.5b18ed64.js} +65 -0
  111. package/dist/web/public/constants.5b18ed64.js.br +0 -0
  112. package/dist/web/public/constants.5b18ed64.js.gz +0 -0
  113. package/dist/web/public/cron-ui.js +328 -0
  114. package/dist/web/public/cron-ui.js.br +0 -0
  115. package/dist/web/public/cron-ui.js.gz +0 -0
  116. package/dist/web/public/image-input.ee16ad88.js.gz +0 -0
  117. package/dist/web/public/index.html +296 -25
  118. package/dist/web/public/index.html.br +0 -0
  119. package/dist/web/public/index.html.gz +0 -0
  120. package/dist/web/public/input-cjk.63794d0b.js +1 -0
  121. package/dist/web/public/input-cjk.63794d0b.js.br +0 -0
  122. package/dist/web/public/input-cjk.63794d0b.js.gz +0 -0
  123. package/dist/web/public/keyboard-accessory.3f91acef.js.gz +0 -0
  124. package/dist/web/public/mobile-handlers.b5a667ef.js.gz +0 -0
  125. package/dist/web/public/mobile.0644e3ac.css +1 -0
  126. package/dist/web/public/mobile.0644e3ac.css.br +0 -0
  127. package/dist/web/public/mobile.0644e3ac.css.gz +0 -0
  128. package/dist/web/public/notification-manager.ca9dc40d.js.gz +0 -0
  129. package/dist/web/public/orchestrator-panel.js.gz +0 -0
  130. package/dist/web/public/{panels-ui.772e92c9.js → panels-ui.ca03853f.js} +25 -17
  131. package/dist/web/public/panels-ui.ca03853f.js.br +0 -0
  132. package/dist/web/public/panels-ui.ca03853f.js.gz +0 -0
  133. package/dist/web/public/ralph-panel.6de2d0f8.js.gz +0 -0
  134. package/dist/web/public/ralph-wizard.13a1831e.js.gz +0 -0
  135. package/dist/web/public/respawn-ui.2d249da9.js.gz +0 -0
  136. package/dist/web/public/sanitize-html.bc7078d6.js.gz +0 -0
  137. package/dist/web/public/session-ui.b51814ef.js +49 -0
  138. package/dist/web/public/session-ui.b51814ef.js.br +0 -0
  139. package/dist/web/public/session-ui.b51814ef.js.gz +0 -0
  140. package/dist/web/public/settings-ui.6c67c125.js +67 -0
  141. package/dist/web/public/settings-ui.6c67c125.js.br +0 -0
  142. package/dist/web/public/settings-ui.6c67c125.js.gz +0 -0
  143. package/dist/web/public/styles.e1ba7849.css +1 -0
  144. package/dist/web/public/styles.e1ba7849.css.br +0 -0
  145. package/dist/web/public/styles.e1ba7849.css.gz +0 -0
  146. package/dist/web/public/subagent-windows.69b60c35.js.gz +0 -0
  147. package/dist/web/public/sw.js.gz +0 -0
  148. package/dist/web/public/terminal-ui.dbf141fa.js +3 -0
  149. package/dist/web/public/terminal-ui.dbf141fa.js.br +0 -0
  150. package/dist/web/public/terminal-ui.dbf141fa.js.gz +0 -0
  151. package/dist/web/public/ultracode-panel.js.gz +0 -0
  152. package/dist/web/public/ultracode-windows.js.gz +0 -0
  153. package/dist/web/public/upload.html.gz +0 -0
  154. package/dist/web/public/vendor/dompurify.min.js.gz +0 -0
  155. package/dist/web/public/vendor/marked.min.js.gz +0 -0
  156. package/dist/web/public/vendor/xterm-addon-fit.min.js.gz +0 -0
  157. package/dist/web/public/vendor/xterm-addon-serialize.min.js.gz +0 -0
  158. package/dist/web/public/vendor/xterm-addon-unicode11.min.js.gz +0 -0
  159. package/dist/web/public/vendor/xterm-addon-webgl.min.js.gz +0 -0
  160. package/dist/web/public/vendor/xterm-zerolag-input.137ad9f0.js.gz +0 -0
  161. package/dist/web/public/vendor/xterm.css.gz +0 -0
  162. package/dist/web/public/vendor/xterm.min.js.gz +0 -0
  163. package/dist/web/public/voice-input.085e9e73.js.gz +0 -0
  164. package/dist/web/routes/case-routes.d.ts.map +1 -1
  165. package/dist/web/routes/case-routes.js +115 -1
  166. package/dist/web/routes/case-routes.js.map +1 -1
  167. package/dist/web/routes/cron-routes.d.ts +11 -0
  168. package/dist/web/routes/cron-routes.d.ts.map +1 -0
  169. package/dist/web/routes/cron-routes.js +70 -0
  170. package/dist/web/routes/cron-routes.js.map +1 -0
  171. package/dist/web/routes/index.d.ts +1 -0
  172. package/dist/web/routes/index.d.ts.map +1 -1
  173. package/dist/web/routes/index.js +1 -0
  174. package/dist/web/routes/index.js.map +1 -1
  175. package/dist/web/routes/respawn-routes.d.ts.map +1 -1
  176. package/dist/web/routes/respawn-routes.js +3 -0
  177. package/dist/web/routes/respawn-routes.js.map +1 -1
  178. package/dist/web/routes/session-routes.d.ts.map +1 -1
  179. package/dist/web/routes/session-routes.js +614 -68
  180. package/dist/web/routes/session-routes.js.map +1 -1
  181. package/dist/web/routes/system-routes.d.ts.map +1 -1
  182. package/dist/web/routes/system-routes.js +5 -0
  183. package/dist/web/routes/system-routes.js.map +1 -1
  184. package/dist/web/routes/ws-routes.d.ts.map +1 -1
  185. package/dist/web/routes/ws-routes.js +56 -17
  186. package/dist/web/routes/ws-routes.js.map +1 -1
  187. package/dist/web/schemas.d.ts +117 -0
  188. package/dist/web/schemas.d.ts.map +1 -1
  189. package/dist/web/schemas.js +168 -1
  190. package/dist/web/schemas.js.map +1 -1
  191. package/dist/web/server.d.ts +9 -2
  192. package/dist/web/server.d.ts.map +1 -1
  193. package/dist/web/server.js +82 -13
  194. package/dist/web/server.js.map +1 -1
  195. package/dist/web/session-listener-wiring.d.ts +5 -1
  196. package/dist/web/session-listener-wiring.d.ts.map +1 -1
  197. package/dist/web/session-listener-wiring.js +23 -1
  198. package/dist/web/session-listener-wiring.js.map +1 -1
  199. package/dist/web/sse-events.d.ts +15 -0
  200. package/dist/web/sse-events.d.ts.map +1 -1
  201. package/dist/web/sse-events.js +17 -0
  202. package/dist/web/sse-events.js.map +1 -1
  203. package/dist/web/ws-connection-registry.d.ts +77 -0
  204. package/dist/web/ws-connection-registry.d.ts.map +1 -0
  205. package/dist/web/ws-connection-registry.js +99 -0
  206. package/dist/web/ws-connection-registry.js.map +1 -0
  207. package/package.json +3 -1
  208. package/dist/web/public/app.a8d73c32.js +0 -38
  209. package/dist/web/public/app.a8d73c32.js.br +0 -0
  210. package/dist/web/public/app.a8d73c32.js.gz +0 -0
  211. package/dist/web/public/constants.1c779517.js.br +0 -0
  212. package/dist/web/public/constants.1c779517.js.gz +0 -0
  213. package/dist/web/public/input-cjk.4e950e0a.js +0 -1
  214. package/dist/web/public/input-cjk.4e950e0a.js.br +0 -0
  215. package/dist/web/public/input-cjk.4e950e0a.js.gz +0 -0
  216. package/dist/web/public/mobile.8a9aff7a.css +0 -1
  217. package/dist/web/public/mobile.8a9aff7a.css.br +0 -0
  218. package/dist/web/public/mobile.8a9aff7a.css.gz +0 -0
  219. package/dist/web/public/panels-ui.772e92c9.js.br +0 -0
  220. package/dist/web/public/panels-ui.772e92c9.js.gz +0 -0
  221. package/dist/web/public/session-ui.da3e53f2.js +0 -36
  222. package/dist/web/public/session-ui.da3e53f2.js.br +0 -0
  223. package/dist/web/public/session-ui.da3e53f2.js.gz +0 -0
  224. package/dist/web/public/settings-ui.38feb956.js +0 -61
  225. package/dist/web/public/settings-ui.38feb956.js.br +0 -0
  226. package/dist/web/public/settings-ui.38feb956.js.gz +0 -0
  227. package/dist/web/public/styles.1b3e6147.css +0 -1
  228. package/dist/web/public/styles.1b3e6147.css.br +0 -0
  229. package/dist/web/public/styles.1b3e6147.css.gz +0 -0
  230. package/dist/web/public/terminal-ui.865f21f6.js +0 -3
  231. package/dist/web/public/terminal-ui.865f21f6.js.br +0 -0
  232. package/dist/web/public/terminal-ui.865f21f6.js.gz +0 -0
@@ -0,0 +1,606 @@
1
+ /**
2
+ * @fileoverview Cron service: CRUD for cron jobs, manual Run Now,
3
+ * the background due-job tick, and run-history recording.
4
+ *
5
+ * It does NOT own session/tmux logic — it reuses Codeman's existing session
6
+ * layer (create → addSession → setupSessionListeners → startInteractive/Shell →
7
+ * send prompt via writeViaMux/write), mirroring the "quick start" route flow.
8
+ */
9
+ import { v4 as uuidv4 } from 'uuid';
10
+ import { readFile } from 'node:fs/promises';
11
+ import { statSync, realpathSync } from 'node:fs';
12
+ import { Session } from '../session.js';
13
+ import { SseEvent } from '../web/sse-events.js';
14
+ import { CronJobSchema } from '../web/schemas.js';
15
+ import { getErrorMessage, createErrorResponse, ApiErrorCode } from '../types/api.js';
16
+ import { MAX_CONCURRENT_SESSIONS, MAX_CRON_JOBS, MAX_CRON_RUN_HISTORY } from '../config/map-limits.js';
17
+ import { CRON_READY_MAX_ATTEMPTS, CRON_READY_SETTLE_MS } from '../config/server-timing.js';
18
+ import { DEFAULT_BLOCKED_TREES, isBlockedAttachmentPath, loadAttachmentGuardConfig, } from '../config/attachment-guard.js';
19
+ import { validateSessionFilePath } from '../web/route-helpers.js';
20
+ import { computeNextRunAt, dueKeyFor } from './cron-time.js';
21
+ const delay = (ms) => new Promise((r) => setTimeout(r, ms));
22
+ /** Hard ceiling on a prompt-file read (defends against unbounded-read DoS). */
23
+ const MAX_PROMPT_FILE_BYTES = 1024 * 1024;
24
+ /**
25
+ * Pseudo-filesystem trees a cron job may never touch, ON TOP of the shared
26
+ * attachment blocklist. `/proc` in particular defeats the workingDir
27
+ * confinement trick (`workingDir: '/proc'` + `promptFilePath:
28
+ * '/proc/self/environ'` would read the SERVER's own environment).
29
+ */
30
+ const CRON_PSEUDO_FS_TREES = ['/proc', '/sys', '/dev'];
31
+ /** Sync blocklist for the create/update workingDir gate (no settings extras). */
32
+ const CRON_WORKING_DIR_BLOCKED_TREES = [...DEFAULT_BLOCKED_TREES, ...CRON_PSEUDO_FS_TREES];
33
+ /** Prompt delivery is single-line only (writeViaMux/Ink constraint). */
34
+ const HAS_NEWLINE = /[\r\n]/;
35
+ /** Order-insensitive equality for the weekly-days arrays. */
36
+ function sameDays(a, b) {
37
+ const x = [...(a ?? [])].sort((p, q) => p - q);
38
+ const y = [...(b ?? [])].sort((p, q) => p - q);
39
+ return x.length === y.length && x.every((v, i) => v === y[i]);
40
+ }
41
+ export class CronService {
42
+ deps;
43
+ constructor(deps) {
44
+ this.deps = deps;
45
+ }
46
+ get store() {
47
+ return this.deps.store;
48
+ }
49
+ // ───────────────────────────── Reads ─────────────────────────────
50
+ listJobs() {
51
+ return Object.values(this.store.getCronJobs());
52
+ }
53
+ getJob(id) {
54
+ return this.store.getCronJob(id);
55
+ }
56
+ listRuns(jobId) {
57
+ const all = Object.values(this.store.getCronJobRuns());
58
+ const filtered = jobId ? all.filter((r) => r.cronJobId === jobId) : all;
59
+ return filtered.sort((a, b) => b.startedAt - a.startedAt);
60
+ }
61
+ /**
62
+ * Number of LIVE sessions of a given agent type (for the multi-session
63
+ * warning and the skip_if_same_agent_running policy). Sessions whose CLI has
64
+ * exited (`stopped`/`error` — the tab is still open but nothing is running)
65
+ * don't count. When `excludeJobId` is given, sessions created by that job's
66
+ * own runs are also excluded — otherwise a recurring job with the skip
67
+ * policy would deadlock on its own previous (never-closed) session and fire
68
+ * exactly once, forever skipping after that.
69
+ */
70
+ countActiveAgents(agentType, excludeJobId) {
71
+ const ownSessionIds = excludeJobId
72
+ ? new Set(this.listRuns(excludeJobId)
73
+ .map((r) => r.sessionId)
74
+ .filter((id) => id !== null))
75
+ : null;
76
+ let n = 0;
77
+ for (const [id, s] of this.deps.sessions.entries()) {
78
+ if (s.mode !== agentType)
79
+ continue;
80
+ if (s.status === 'stopped' || s.status === 'error')
81
+ continue;
82
+ if (ownSessionIds?.has(id))
83
+ continue;
84
+ n++;
85
+ }
86
+ return n;
87
+ }
88
+ // ──────────────────────────── Mutations ───────────────────────────
89
+ createJob(input) {
90
+ if (Object.keys(this.store.getCronJobs()).length >= MAX_CRON_JOBS) {
91
+ throw this.badRequest(`Maximum number of cron jobs (${MAX_CRON_JOBS}) reached`);
92
+ }
93
+ this.assertValidWorkingDir(input.workingDir);
94
+ const now = Date.now();
95
+ const job = {
96
+ id: uuidv4(),
97
+ name: input.name,
98
+ agentType: input.agentType,
99
+ workingDir: input.workingDir,
100
+ launchCommand: input.launchCommand,
101
+ promptMode: input.promptMode,
102
+ promptText: input.promptText,
103
+ promptFilePath: input.promptFilePath,
104
+ inputMode: input.inputMode,
105
+ scheduleType: input.scheduleType,
106
+ runAt: input.runAt,
107
+ intervalMinutes: input.intervalMinutes,
108
+ dailyTime: input.dailyTime,
109
+ weeklyDays: input.weeklyDays,
110
+ weeklyTime: input.weeklyTime,
111
+ enabled: input.enabled,
112
+ notes: input.notes,
113
+ concurrencyPolicy: input.concurrencyPolicy,
114
+ autoClosePreviousSession: input.autoClosePreviousSession ?? true,
115
+ createdAt: now,
116
+ updatedAt: now,
117
+ lastRunAt: null,
118
+ nextRunAt: null,
119
+ lastStatus: null,
120
+ lastDueKey: null,
121
+ };
122
+ job.nextRunAt = job.enabled ? computeNextRunAt(job, now) : null;
123
+ this.store.setCronJob(job.id, job);
124
+ this.broadcastListChanged();
125
+ return job;
126
+ }
127
+ updateJob(id, patch) {
128
+ const existing = this.getJob(id);
129
+ if (!existing)
130
+ return null;
131
+ const now = Date.now();
132
+ // A completed one-time job is only re-armed when the SCHEDULE actually
133
+ // CHANGES — otherwise a cosmetic edit would silently resurrect a job that
134
+ // already fired. We compare VALUES, not field-presence: the edit form
135
+ // round-trips the full job (incl. unchanged scheduleType/runAt) on every
136
+ // save, so a presence check would always re-arm. Only a real schedule
137
+ // change re-arms.
138
+ const changed = (next, prev) => next !== undefined && next !== prev;
139
+ const scheduleChanged = changed(patch.scheduleType, existing.scheduleType) ||
140
+ changed(patch.runAt, existing.runAt) ||
141
+ changed(patch.intervalMinutes, existing.intervalMinutes) ||
142
+ changed(patch.dailyTime, existing.dailyTime) ||
143
+ changed(patch.weeklyTime, existing.weeklyTime) ||
144
+ (patch.weeklyDays !== undefined && !sameDays(patch.weeklyDays, existing.weeklyDays));
145
+ const reArm = existing.scheduleType !== 'once' || !existing.completedOnce || scheduleChanged;
146
+ const updated = {
147
+ ...existing,
148
+ ...patch,
149
+ id: existing.id,
150
+ createdAt: existing.createdAt,
151
+ updatedAt: now,
152
+ completedOnce: reArm ? false : existing.completedOnce,
153
+ lastDueKey: null,
154
+ };
155
+ // The PUT schema is `.partial()`, so its cross-field rules don't run on a
156
+ // partial body. Re-validate the MERGED job against the full schema so a
157
+ // partial edit can't leave an enabled job with an inconsistent schedule
158
+ // (e.g. switching to `once` without a `runAt` → a dead `nextRunAt:null`).
159
+ const check = CronJobSchema.safeParse(updated);
160
+ if (!check.success) {
161
+ throw this.badRequest(check.error.issues[0]?.message ?? 'Invalid cron job update');
162
+ }
163
+ if (patch.workingDir !== undefined)
164
+ this.assertValidWorkingDir(patch.workingDir);
165
+ updated.nextRunAt = updated.enabled ? computeNextRunAt(updated, now) : null;
166
+ this.store.setCronJob(updated.id, updated);
167
+ this.broadcastListChanged();
168
+ return updated;
169
+ }
170
+ setEnabled(id, enabled) {
171
+ const existing = this.getJob(id);
172
+ if (!existing)
173
+ return null;
174
+ const now = Date.now();
175
+ existing.enabled = enabled;
176
+ existing.updatedAt = now;
177
+ existing.nextRunAt = enabled ? computeNextRunAt(existing, now) : null;
178
+ this.store.setCronJob(existing.id, existing);
179
+ this.broadcastListChanged();
180
+ return existing;
181
+ }
182
+ deleteJob(id) {
183
+ if (!this.getJob(id))
184
+ return false;
185
+ this.store.removeCronJob(id);
186
+ for (const run of this.listRuns(id))
187
+ this.store.removeCronJobRun(run.id);
188
+ this.deps.broadcast(SseEvent.CronJobDeleted, { id });
189
+ this.broadcastListChanged();
190
+ return true;
191
+ }
192
+ // ──────────────────────────── Execution ───────────────────────────
193
+ /** Manual Run Now — always launches regardless of schedule/enabled state. */
194
+ async runNow(id) {
195
+ const job = this.getJob(id);
196
+ if (!job)
197
+ return null;
198
+ return this.launch(job, 'manual_run_now');
199
+ }
200
+ /**
201
+ * Background tick: launch every enabled job whose next run is due. Advances
202
+ * each job's schedule and guards against double-launching the same due time.
203
+ */
204
+ async tickDueJobs(now = Date.now()) {
205
+ for (const job of this.listJobs()) {
206
+ if (!job.enabled || job.nextRunAt == null || job.nextRunAt > now)
207
+ continue;
208
+ const key = dueKeyFor(job.id, job.nextRunAt);
209
+ if (job.lastDueKey === key) {
210
+ // This due time was already consumed (overlap/restart) — just advance.
211
+ this.advanceAfterFire(job, now);
212
+ continue;
213
+ }
214
+ // Optional concurrency policy for AUTOMATIC runs. Only LIVE sessions
215
+ // block, and this job's own previous sessions never do (see
216
+ // countActiveAgents) — otherwise a recurring job would deadlock on the
217
+ // session it created last time.
218
+ if (job.concurrencyPolicy === 'skip_if_same_agent_running' && this.countActiveAgents(job.agentType, job.id) > 0) {
219
+ // Record the skip so the job's run history isn't silently empty when it
220
+ // keeps getting skipped (otherwise it looks like the job never ran).
221
+ this.recordSkippedRun(job);
222
+ if (job.scheduleType === 'once') {
223
+ // A skipped one-time job is NOT consumed: leave nextRunAt armed (and
224
+ // the due key unconsumed) so the next tick retries once the blocking
225
+ // session goes away.
226
+ continue;
227
+ }
228
+ job.lastDueKey = key;
229
+ this.advanceAfterFire(job, now);
230
+ continue;
231
+ }
232
+ job.lastDueKey = key;
233
+ // Advance the schedule BEFORE launching so a slow launch can't be
234
+ // re-triggered by the next tick.
235
+ this.advanceAfterFire(job, now);
236
+ this.launch(job, 'scheduled').catch((err) => console.error(`[cron] launch failed for job ${job.id}:`, getErrorMessage(err)));
237
+ }
238
+ }
239
+ /** Recompute nextRunAt for loaded jobs on boot (e.g. after a restart). */
240
+ init() {
241
+ const now = Date.now();
242
+ for (const job of this.listJobs()) {
243
+ const isDeadOnce = job.scheduleType === 'once' && job.completedOnce;
244
+ if (job.enabled && job.nextRunAt == null && !isDeadOnce) {
245
+ job.nextRunAt = computeNextRunAt(job, now);
246
+ this.store.setCronJob(job.id, job);
247
+ }
248
+ }
249
+ }
250
+ // ──────────────────────────── Internals ───────────────────────────
251
+ advanceAfterFire(job, now) {
252
+ if (job.scheduleType === 'once') {
253
+ job.completedOnce = true;
254
+ job.enabled = false;
255
+ job.nextRunAt = null;
256
+ }
257
+ else {
258
+ job.nextRunAt = computeNextRunAt(job, now);
259
+ }
260
+ job.updatedAt = now;
261
+ this.store.setCronJob(job.id, job);
262
+ this.broadcastListChanged();
263
+ }
264
+ async launch(job, trigger) {
265
+ const run = {
266
+ id: uuidv4(),
267
+ cronJobId: job.id,
268
+ sessionId: null,
269
+ sessionName: null,
270
+ startedAt: Date.now(),
271
+ finishedAt: null,
272
+ status: 'created',
273
+ triggerType: trigger,
274
+ createdSessionUrl: null,
275
+ };
276
+ this.store.setCronJobRun(run.id, run);
277
+ this.pruneRunHistory();
278
+ this.deps.broadcast(SseEvent.CronRunCreated, run);
279
+ // Resolve the prompt.
280
+ let prompt;
281
+ try {
282
+ prompt = await this.resolvePrompt(job);
283
+ }
284
+ catch (err) {
285
+ return this.failRun(job, run, `Prompt error: ${getErrorMessage(err)}`);
286
+ }
287
+ // Validate working directory.
288
+ try {
289
+ if (!statSync(job.workingDir).isDirectory()) {
290
+ return this.failRun(job, run, 'workingDir is not a directory');
291
+ }
292
+ }
293
+ catch {
294
+ return this.failRun(job, run, 'workingDir does not exist');
295
+ }
296
+ // Recurring jobs: close the still-open session created by this job's
297
+ // previous run before launching the next (default ON, opt-out via
298
+ // autoClosePreviousSession:false) — otherwise an unattended interval/daily
299
+ // job accumulates a new tab per fire until the global session cap.
300
+ if (job.scheduleType !== 'once' && job.autoClosePreviousSession !== false) {
301
+ await this.closePreviousRunSessions(job, run.id);
302
+ }
303
+ // Respect the global session cap.
304
+ if (this.deps.sessions.size >= MAX_CONCURRENT_SESSIONS) {
305
+ return this.failRun(job, run, `Maximum concurrent sessions (${MAX_CONCURRENT_SESSIONS}) reached`);
306
+ }
307
+ // Create + start the session (mirrors the quick-start route flow).
308
+ let session;
309
+ try {
310
+ const mode = job.agentType;
311
+ const globalNice = await this.deps.getGlobalNiceConfig();
312
+ const modelConfig = await this.deps.getModelConfig();
313
+ const claudeModeConfig = await this.deps.getClaudeModeConfig();
314
+ const model = mode !== 'shell' ? modelConfig?.defaultModel || undefined : undefined;
315
+ session = new Session({
316
+ workingDir: job.workingDir,
317
+ mode,
318
+ name: job.name,
319
+ mux: this.deps.mux,
320
+ useMux: true,
321
+ niceConfig: globalNice,
322
+ model,
323
+ claudeMode: claudeModeConfig.claudeMode,
324
+ allowedTools: claudeModeConfig.allowedTools,
325
+ });
326
+ this.deps.addSession(session);
327
+ this.store.incrementSessionsCreated();
328
+ this.deps.persistSessionState(session);
329
+ await this.deps.setupSessionListeners(session);
330
+ this.deps.broadcast(SseEvent.SessionCreated, this.deps.getSessionStateWithRespawn(session));
331
+ if (mode === 'shell') {
332
+ await session.startShell();
333
+ }
334
+ else {
335
+ await session.startInteractive();
336
+ }
337
+ this.deps.broadcast(SseEvent.SessionInteractive, { id: session.id, mode });
338
+ }
339
+ catch (err) {
340
+ return this.failRun(job, run, `Session launch failed: ${getErrorMessage(err)}`);
341
+ }
342
+ run.sessionId = session.id;
343
+ run.sessionName = session.name;
344
+ run.createdSessionUrl = `/?session=${session.id}`;
345
+ run.status = 'session_started';
346
+ this.store.setCronJobRun(run.id, run);
347
+ this.deps.broadcast(SseEvent.CronRunUpdated, run);
348
+ this.updateJobLastStatus(job.id, 'session_started');
349
+ // Send the prompt once the CLI is ready (async; does not block the caller).
350
+ this.sendPromptWhenReady(session.id, prompt, job, run);
351
+ return run;
352
+ }
353
+ /**
354
+ * Resolves the prompt text and enforces the single-line constraint: prompt
355
+ * delivery rides writeViaMux/PTY writes where a newline is Enter, so a
356
+ * multi-line prompt would be silently corrupted (typed mode fuses lines,
357
+ * paste mode submits the first line and dribbles the rest in as separate
358
+ * messages). Rather than mangle an unattended agent's instructions, fail the
359
+ * run with a clear error. A prompt FILE may end with trailing newline(s)
360
+ * (every editor writes one) — those are stripped before the check.
361
+ */
362
+ async resolvePrompt(job) {
363
+ if (job.promptMode === 'prompt_file_path') {
364
+ if (!job.promptFilePath)
365
+ throw new Error('prompt file path is empty');
366
+ const safePath = await this.resolveSafePromptPath(job.promptFilePath, job.workingDir);
367
+ const content = (await readFile(safePath, 'utf-8')).replace(/[\r\n]+$/, '');
368
+ if (HAS_NEWLINE.test(content)) {
369
+ throw new Error('prompt file must contain a single line — multi-line prompts are not supported');
370
+ }
371
+ return content;
372
+ }
373
+ const text = job.promptText ?? '';
374
+ if (HAS_NEWLINE.test(text)) {
375
+ // Schema-rejected since this check was added; guards legacy persisted jobs.
376
+ throw new Error('promptText must be a single line — multi-line prompts are not supported');
377
+ }
378
+ return text;
379
+ }
380
+ /**
381
+ * Guards a prompt-file path before it is read. The path is user-supplied via
382
+ * the API and its contents are injected into an agent session (an exfil sink
383
+ * over SSE/terminal), so an unconfined read would let a hostile job config
384
+ * pull arbitrary host files — including the SERVER PROCESS'S OWN secrets via
385
+ * `/proc/self/environ` — into the session.
386
+ *
387
+ * A denylist is the wrong posture for an exfil sink (it kept missing `/proc`,
388
+ * `/dev`, other users' `~/.ssh`, modern cloud creds…). So the PRIMARY gate is
389
+ * an allowlist: the prompt file must resolve INSIDE the job's working
390
+ * directory. A symlink escaping the workspace fails this because we check the
391
+ * realpath-resolved target. We additionally require a regular file (rejects
392
+ * directories, FIFOs, and `/dev/*` character devices that would hang or OOM
393
+ * the unbounded read) within a sane size cap, and keep the shared blocklist as
394
+ * cheap defense-in-depth. Returns the symlink-resolved path to read.
395
+ */
396
+ async resolveSafePromptPath(rawPath, workingDir) {
397
+ let resolved;
398
+ try {
399
+ resolved = realpathSync(rawPath);
400
+ }
401
+ catch {
402
+ throw new Error('prompt file path could not be resolved');
403
+ }
404
+ // workingDir is USER-CONTROLLED, so it is not a trust boundary by itself:
405
+ // realpath-resolve it (a symlinked workspace must not defeat containment)
406
+ // and reject blocked/pseudo-fs trees — otherwise workingDir '/proc' would
407
+ // make '/proc/self/environ' pass the containment check below.
408
+ let realWorkingDir;
409
+ try {
410
+ realWorkingDir = realpathSync(workingDir);
411
+ }
412
+ catch {
413
+ throw new Error('job working directory could not be resolved');
414
+ }
415
+ const guard = await loadAttachmentGuardConfig();
416
+ const blockedTrees = [...guard.blockedTrees, ...CRON_PSEUDO_FS_TREES];
417
+ if (realWorkingDir === '/' || isBlockedAttachmentPath(realWorkingDir, blockedTrees)) {
418
+ throw new Error('job working directory is blocked');
419
+ }
420
+ // Defense-in-depth blocklist (secret locations, /etc, /root, pseudo-fs).
421
+ if (isBlockedAttachmentPath(resolved, blockedTrees)) {
422
+ throw new Error('prompt file path is blocked');
423
+ }
424
+ // Primary gate: the prompt file must live inside the job's workspace.
425
+ if (!validateSessionFilePath(realWorkingDir, resolved)) {
426
+ throw new Error('prompt file path must be inside the job working directory');
427
+ }
428
+ // Reject non-regular files and oversized files (DoS via unbounded read).
429
+ let info;
430
+ try {
431
+ info = statSync(resolved);
432
+ }
433
+ catch {
434
+ throw new Error('prompt file path could not be resolved');
435
+ }
436
+ if (!info.isFile())
437
+ throw new Error('prompt file path is not a regular file');
438
+ if (info.size > MAX_PROMPT_FILE_BYTES)
439
+ throw new Error('prompt file is too large');
440
+ return resolved;
441
+ }
442
+ sendPromptWhenReady(sessionId, prompt, job, run) {
443
+ setImmediate(() => {
444
+ const poll = async () => {
445
+ if (job.agentType !== 'shell') {
446
+ for (let attempt = 0; attempt < CRON_READY_MAX_ATTEMPTS; attempt++) {
447
+ await delay(500);
448
+ const s = this.deps.sessions.get(sessionId);
449
+ if (!s)
450
+ return; // session was removed
451
+ const buf = s.getTerminalBuffer().slice(-2048);
452
+ if (buf.includes('❯') || buf.includes('tokens'))
453
+ break;
454
+ }
455
+ await delay(CRON_READY_SETTLE_MS);
456
+ }
457
+ else {
458
+ await delay(1000);
459
+ // Shell mode: deliver the optional custom launch command as the
460
+ // first input line (single-line, schema-enforced), then give it a
461
+ // moment to start before the prompt follows.
462
+ if (job.launchCommand) {
463
+ const shell = this.deps.sessions.get(sessionId);
464
+ if (!shell)
465
+ return;
466
+ const sent = await shell.writeViaMux(`${job.launchCommand}\r`);
467
+ if (!sent) {
468
+ this.failRun(job, run, 'Failed to send launch command: mux write failed');
469
+ return;
470
+ }
471
+ await delay(1000);
472
+ }
473
+ }
474
+ const s = this.deps.sessions.get(sessionId);
475
+ if (!s)
476
+ return;
477
+ try {
478
+ const payload = prompt.endsWith('\r') ? prompt : `${prompt}\r`;
479
+ let delivered = true;
480
+ if (job.inputMode === 'paste') {
481
+ s.write(payload);
482
+ }
483
+ else {
484
+ delivered = await s.writeViaMux(payload);
485
+ }
486
+ if (!delivered) {
487
+ this.failRun(job, run, 'Failed to send prompt: mux write failed');
488
+ return;
489
+ }
490
+ run.status = 'prompt_sent';
491
+ run.finishedAt = Date.now();
492
+ this.store.setCronJobRun(run.id, run);
493
+ this.deps.broadcast(SseEvent.CronRunUpdated, run);
494
+ this.updateJobLastStatus(job.id, 'prompt_sent');
495
+ }
496
+ catch (err) {
497
+ this.failRun(job, run, `Failed to send prompt: ${getErrorMessage(err)}`);
498
+ }
499
+ };
500
+ poll().catch((err) => console.error('[cron] sendPromptWhenReady error:', getErrorMessage(err)));
501
+ });
502
+ }
503
+ /** 400-shaped error for route handlers (mirrors parseBody's error contract). */
504
+ badRequest(msg) {
505
+ return Object.assign(new Error(msg), {
506
+ statusCode: 400,
507
+ body: createErrorResponse(ApiErrorCode.INVALID_INPUT, msg),
508
+ });
509
+ }
510
+ /**
511
+ * Create/update gate for a job's workingDir: must exist, be a directory, and
512
+ * not resolve into a blocked or pseudo-filesystem tree (nor the fs root).
513
+ * The user-supplied workingDir doubles as the prompt-file confinement root,
514
+ * so an unrestricted value would defeat that boundary (e.g. '/proc').
515
+ */
516
+ assertValidWorkingDir(workingDir) {
517
+ let real;
518
+ try {
519
+ real = realpathSync(workingDir);
520
+ }
521
+ catch {
522
+ throw this.badRequest('workingDir does not exist');
523
+ }
524
+ if (!statSync(real).isDirectory())
525
+ throw this.badRequest('workingDir is not a directory');
526
+ if (real === '/' || isBlockedAttachmentPath(real, CRON_WORKING_DIR_BLOCKED_TREES)) {
527
+ throw this.badRequest('workingDir is not allowed (blocked or pseudo-filesystem tree)');
528
+ }
529
+ }
530
+ /** Close still-open sessions created by this job's previous runs (normal cleanup path). */
531
+ async closePreviousRunSessions(job, currentRunId) {
532
+ for (const prev of this.listRuns(job.id)) {
533
+ if (prev.id === currentRunId || !prev.sessionId)
534
+ continue;
535
+ if (!this.deps.sessions.has(prev.sessionId))
536
+ continue;
537
+ try {
538
+ await this.deps.cleanupSession(prev.sessionId, true, 'cron: superseded by the next run of this job');
539
+ }
540
+ catch (err) {
541
+ console.error(`[cron] failed to auto-close previous session ${prev.sessionId}:`, getErrorMessage(err));
542
+ }
543
+ }
544
+ }
545
+ failRun(job, run, message) {
546
+ run.status = 'failed';
547
+ run.errorMessage = message;
548
+ run.finishedAt = Date.now();
549
+ this.store.setCronJobRun(run.id, run);
550
+ this.deps.broadcast(SseEvent.CronRunUpdated, run);
551
+ this.updateJobLastStatus(job.id, 'failed');
552
+ return run;
553
+ }
554
+ recordSkippedRun(job) {
555
+ // Coalesce consecutive skips: if the job is already in a skip streak, don't
556
+ // record again — a perpetually-skipped interval job would otherwise write a
557
+ // run every tick forever and bloat state.json.
558
+ if (this.listRuns(job.id)[0]?.status === 'skipped')
559
+ return;
560
+ const now = Date.now();
561
+ const run = {
562
+ id: uuidv4(),
563
+ cronJobId: job.id,
564
+ sessionId: null,
565
+ sessionName: null,
566
+ startedAt: now,
567
+ finishedAt: now,
568
+ status: 'skipped',
569
+ errorMessage: `Skipped: a ${job.agentType} agent is already running (concurrency policy)`,
570
+ triggerType: 'scheduled',
571
+ createdSessionUrl: null,
572
+ };
573
+ this.store.setCronJobRun(run.id, run);
574
+ this.pruneRunHistory();
575
+ this.deps.broadcast(SseEvent.CronRunCreated, run);
576
+ // A skip is NOT a run: surface it as the lastStatus, but do NOT advance
577
+ // lastRunAt (no session was created).
578
+ this.updateJobLastStatus(job.id, 'skipped', { touchLastRun: false });
579
+ }
580
+ /** Prune the oldest run records (by startedAt) once the global cap is exceeded. */
581
+ pruneRunHistory() {
582
+ const runs = Object.values(this.store.getCronJobRuns());
583
+ if (runs.length <= MAX_CRON_RUN_HISTORY)
584
+ return;
585
+ runs.sort((a, b) => a.startedAt - b.startedAt);
586
+ for (const run of runs.slice(0, runs.length - MAX_CRON_RUN_HISTORY)) {
587
+ this.store.removeCronJobRun(run.id);
588
+ }
589
+ }
590
+ updateJobLastStatus(jobId, status, opts = {}) {
591
+ const fresh = this.store.getCronJob(jobId);
592
+ if (!fresh)
593
+ return;
594
+ const now = Date.now();
595
+ fresh.lastStatus = status;
596
+ if (opts.touchLastRun !== false)
597
+ fresh.lastRunAt = now;
598
+ fresh.updatedAt = now;
599
+ this.store.setCronJob(fresh.id, fresh);
600
+ this.broadcastListChanged();
601
+ }
602
+ broadcastListChanged() {
603
+ this.deps.broadcast(SseEvent.CronJobsChanged, { jobs: this.listJobs() });
604
+ }
605
+ }
606
+ //# sourceMappingURL=cron-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron-service.js","sourceRoot":"","sources":["../../src/cron/cron-service.ts"],"names":[],"mappings":"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"}