@oharness/engine 0.1.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 (256) hide show
  1. package/dist/agent/agent.d.ts +196 -0
  2. package/dist/agent/agent.js +758 -0
  3. package/dist/agent/agent.js.map +1 -0
  4. package/dist/agent/compaction.d.ts +68 -0
  5. package/dist/agent/compaction.js +179 -0
  6. package/dist/agent/compaction.js.map +1 -0
  7. package/dist/agent/hooks.d.ts +77 -0
  8. package/dist/agent/hooks.js +152 -0
  9. package/dist/agent/hooks.js.map +1 -0
  10. package/dist/agent/memory.d.ts +45 -0
  11. package/dist/agent/memory.js +147 -0
  12. package/dist/agent/memory.js.map +1 -0
  13. package/dist/agent/overflow.d.ts +35 -0
  14. package/dist/agent/overflow.js +69 -0
  15. package/dist/agent/overflow.js.map +1 -0
  16. package/dist/agent/permissions.d.ts +181 -0
  17. package/dist/agent/permissions.js +289 -0
  18. package/dist/agent/permissions.js.map +1 -0
  19. package/dist/agent/prompt.d.ts +25 -0
  20. package/dist/agent/prompt.js +63 -0
  21. package/dist/agent/prompt.js.map +1 -0
  22. package/dist/agent/session.d.ts +108 -0
  23. package/dist/agent/session.js +231 -0
  24. package/dist/agent/session.js.map +1 -0
  25. package/dist/agent/settings.d.ts +37 -0
  26. package/dist/agent/settings.js +113 -0
  27. package/dist/agent/settings.js.map +1 -0
  28. package/dist/agent/skills.d.ts +58 -0
  29. package/dist/agent/skills.js +225 -0
  30. package/dist/agent/skills.js.map +1 -0
  31. package/dist/agent/store.d.ts +308 -0
  32. package/dist/agent/store.js +596 -0
  33. package/dist/agent/store.js.map +1 -0
  34. package/dist/agent/subagent.d.ts +44 -0
  35. package/dist/agent/subagent.js +138 -0
  36. package/dist/agent/subagent.js.map +1 -0
  37. package/dist/agent/titles.d.ts +8 -0
  38. package/dist/agent/titles.js +23 -0
  39. package/dist/agent/titles.js.map +1 -0
  40. package/dist/agent/workspace.d.ts +60 -0
  41. package/dist/agent/workspace.js +156 -0
  42. package/dist/agent/workspace.js.map +1 -0
  43. package/dist/artifacts/publish.d.ts +94 -0
  44. package/dist/artifacts/publish.js +104 -0
  45. package/dist/artifacts/publish.js.map +1 -0
  46. package/dist/artifacts/store.d.ts +324 -0
  47. package/dist/artifacts/store.js +500 -0
  48. package/dist/artifacts/store.js.map +1 -0
  49. package/dist/auth/index.d.ts +13 -0
  50. package/dist/auth/index.js +10 -0
  51. package/dist/auth/index.js.map +1 -0
  52. package/dist/auth/manager.d.ts +83 -0
  53. package/dist/auth/manager.js +266 -0
  54. package/dist/auth/manager.js.map +1 -0
  55. package/dist/auth/oauth.d.ts +83 -0
  56. package/dist/auth/oauth.js +327 -0
  57. package/dist/auth/oauth.js.map +1 -0
  58. package/dist/auth/providers/account.d.ts +59 -0
  59. package/dist/auth/providers/account.js +282 -0
  60. package/dist/auth/providers/account.js.map +1 -0
  61. package/dist/auth/providers/anthropic.d.ts +24 -0
  62. package/dist/auth/providers/anthropic.js +209 -0
  63. package/dist/auth/providers/anthropic.js.map +1 -0
  64. package/dist/auth/providers/generic.d.ts +57 -0
  65. package/dist/auth/providers/generic.js +155 -0
  66. package/dist/auth/providers/generic.js.map +1 -0
  67. package/dist/auth/providers/official.d.ts +3 -0
  68. package/dist/auth/providers/official.js +90 -0
  69. package/dist/auth/providers/official.js.map +1 -0
  70. package/dist/auth/providers/ottoport.d.ts +3 -0
  71. package/dist/auth/providers/ottoport.js +60 -0
  72. package/dist/auth/providers/ottoport.js.map +1 -0
  73. package/dist/auth/store.d.ts +22 -0
  74. package/dist/auth/store.js +138 -0
  75. package/dist/auth/store.js.map +1 -0
  76. package/dist/auth/types.d.ts +167 -0
  77. package/dist/auth/types.js +16 -0
  78. package/dist/auth/types.js.map +1 -0
  79. package/dist/config.d.ts +197 -0
  80. package/dist/config.js +195 -0
  81. package/dist/config.js.map +1 -0
  82. package/dist/core/errors.d.ts +46 -0
  83. package/dist/core/errors.js +83 -0
  84. package/dist/core/errors.js.map +1 -0
  85. package/dist/core/tokens.d.ts +12 -0
  86. package/dist/core/tokens.js +56 -0
  87. package/dist/core/tokens.js.map +1 -0
  88. package/dist/core/types.d.ts +91 -0
  89. package/dist/core/types.js +49 -0
  90. package/dist/core/types.js.map +1 -0
  91. package/dist/harness.d.ts +302 -0
  92. package/dist/harness.js +695 -0
  93. package/dist/harness.js.map +1 -0
  94. package/dist/index.d.ts +32 -0
  95. package/dist/index.js +21 -0
  96. package/dist/index.js.map +1 -0
  97. package/dist/mcp/client.d.ts +55 -0
  98. package/dist/mcp/client.js +199 -0
  99. package/dist/mcp/client.js.map +1 -0
  100. package/dist/mcp/index.d.ts +13 -0
  101. package/dist/mcp/index.js +8 -0
  102. package/dist/mcp/index.js.map +1 -0
  103. package/dist/mcp/manager.d.ts +77 -0
  104. package/dist/mcp/manager.js +325 -0
  105. package/dist/mcp/manager.js.map +1 -0
  106. package/dist/mcp/oauth.d.ts +63 -0
  107. package/dist/mcp/oauth.js +302 -0
  108. package/dist/mcp/oauth.js.map +1 -0
  109. package/dist/mcp/protocol.d.ts +130 -0
  110. package/dist/mcp/protocol.js +14 -0
  111. package/dist/mcp/protocol.js.map +1 -0
  112. package/dist/mcp/registry.d.ts +52 -0
  113. package/dist/mcp/registry.js +100 -0
  114. package/dist/mcp/registry.js.map +1 -0
  115. package/dist/mcp/registry.json +293 -0
  116. package/dist/mcp/secrets.d.ts +20 -0
  117. package/dist/mcp/secrets.js +75 -0
  118. package/dist/mcp/secrets.js.map +1 -0
  119. package/dist/mcp/transport.d.ts +51 -0
  120. package/dist/mcp/transport.js +158 -0
  121. package/dist/mcp/transport.js.map +1 -0
  122. package/dist/paths.d.ts +37 -0
  123. package/dist/paths.js +63 -0
  124. package/dist/paths.js.map +1 -0
  125. package/dist/plugins.d.ts +55 -0
  126. package/dist/plugins.js +201 -0
  127. package/dist/plugins.js.map +1 -0
  128. package/dist/providers/builtin.d.ts +23 -0
  129. package/dist/providers/builtin.js +141 -0
  130. package/dist/providers/builtin.js.map +1 -0
  131. package/dist/providers/catalog.d.ts +129 -0
  132. package/dist/providers/catalog.js +254 -0
  133. package/dist/providers/catalog.js.map +1 -0
  134. package/dist/providers/catalog.json +472 -0
  135. package/dist/providers/discovery.d.ts +16 -0
  136. package/dist/providers/discovery.js +161 -0
  137. package/dist/providers/discovery.js.map +1 -0
  138. package/dist/providers/http.d.ts +24 -0
  139. package/dist/providers/http.js +139 -0
  140. package/dist/providers/http.js.map +1 -0
  141. package/dist/providers/index.d.ts +10 -0
  142. package/dist/providers/index.js +8 -0
  143. package/dist/providers/index.js.map +1 -0
  144. package/dist/providers/piai.d.ts +124 -0
  145. package/dist/providers/piai.js +551 -0
  146. package/dist/providers/piai.js.map +1 -0
  147. package/dist/providers/registry.d.ts +65 -0
  148. package/dist/providers/registry.js +195 -0
  149. package/dist/providers/registry.js.map +1 -0
  150. package/dist/providers/resilient.d.ts +46 -0
  151. package/dist/providers/resilient.js +117 -0
  152. package/dist/providers/resilient.js.map +1 -0
  153. package/dist/providers/types.d.ts +182 -0
  154. package/dist/providers/types.js +50 -0
  155. package/dist/providers/types.js.map +1 -0
  156. package/dist/schedule/cron.d.ts +35 -0
  157. package/dist/schedule/cron.js +125 -0
  158. package/dist/schedule/cron.js.map +1 -0
  159. package/dist/schedule/scheduler.d.ts +87 -0
  160. package/dist/schedule/scheduler.js +237 -0
  161. package/dist/schedule/scheduler.js.map +1 -0
  162. package/dist/storage/kv.d.ts +56 -0
  163. package/dist/storage/kv.js +173 -0
  164. package/dist/storage/kv.js.map +1 -0
  165. package/dist/storage/migrate.d.ts +11 -0
  166. package/dist/storage/migrate.js +93 -0
  167. package/dist/storage/migrate.js.map +1 -0
  168. package/dist/storage/project.d.ts +9 -0
  169. package/dist/storage/project.js +57 -0
  170. package/dist/storage/project.js.map +1 -0
  171. package/dist/storage/records.d.ts +32 -0
  172. package/dist/storage/records.js +48 -0
  173. package/dist/storage/records.js.map +1 -0
  174. package/dist/sync/client.d.ts +79 -0
  175. package/dist/sync/client.js +118 -0
  176. package/dist/sync/client.js.map +1 -0
  177. package/dist/sync/mirror.d.ts +85 -0
  178. package/dist/sync/mirror.js +389 -0
  179. package/dist/sync/mirror.js.map +1 -0
  180. package/dist/sync/protocol.d.ts +67 -0
  181. package/dist/sync/protocol.js +16 -0
  182. package/dist/sync/protocol.js.map +1 -0
  183. package/dist/sync/settings.d.ts +56 -0
  184. package/dist/sync/settings.js +60 -0
  185. package/dist/sync/settings.js.map +1 -0
  186. package/dist/tools/builtin/artifact.d.ts +16 -0
  187. package/dist/tools/builtin/artifact.js +134 -0
  188. package/dist/tools/builtin/artifact.js.map +1 -0
  189. package/dist/tools/builtin/bash.d.ts +3 -0
  190. package/dist/tools/builtin/bash.js +142 -0
  191. package/dist/tools/builtin/bash.js.map +1 -0
  192. package/dist/tools/builtin/fs.d.ts +19 -0
  193. package/dist/tools/builtin/fs.js +280 -0
  194. package/dist/tools/builtin/fs.js.map +1 -0
  195. package/dist/tools/builtin/index.d.ts +22 -0
  196. package/dist/tools/builtin/index.js +42 -0
  197. package/dist/tools/builtin/index.js.map +1 -0
  198. package/dist/tools/builtin/mcp-resource.d.ts +3 -0
  199. package/dist/tools/builtin/mcp-resource.js +220 -0
  200. package/dist/tools/builtin/mcp-resource.js.map +1 -0
  201. package/dist/tools/builtin/memory.d.ts +10 -0
  202. package/dist/tools/builtin/memory.js +76 -0
  203. package/dist/tools/builtin/memory.js.map +1 -0
  204. package/dist/tools/builtin/recall.d.ts +13 -0
  205. package/dist/tools/builtin/recall.js +163 -0
  206. package/dist/tools/builtin/recall.js.map +1 -0
  207. package/dist/tools/builtin/search.d.ts +3 -0
  208. package/dist/tools/builtin/search.js +240 -0
  209. package/dist/tools/builtin/search.js.map +1 -0
  210. package/dist/tools/builtin/skill.d.ts +10 -0
  211. package/dist/tools/builtin/skill.js +46 -0
  212. package/dist/tools/builtin/skill.js.map +1 -0
  213. package/dist/tools/builtin/task.d.ts +9 -0
  214. package/dist/tools/builtin/task.js +68 -0
  215. package/dist/tools/builtin/task.js.map +1 -0
  216. package/dist/tools/builtin/todo.d.ts +20 -0
  217. package/dist/tools/builtin/todo.js +63 -0
  218. package/dist/tools/builtin/todo.js.map +1 -0
  219. package/dist/tools/define.d.ts +19 -0
  220. package/dist/tools/define.js +39 -0
  221. package/dist/tools/define.js.map +1 -0
  222. package/dist/tools/index.d.ts +7 -0
  223. package/dist/tools/index.js +5 -0
  224. package/dist/tools/index.js.map +1 -0
  225. package/dist/tools/registry.d.ts +39 -0
  226. package/dist/tools/registry.js +101 -0
  227. package/dist/tools/registry.js.map +1 -0
  228. package/dist/tools/types.d.ts +112 -0
  229. package/dist/tools/types.js +22 -0
  230. package/dist/tools/types.js.map +1 -0
  231. package/dist/util/id.d.ts +9 -0
  232. package/dist/util/id.js +19 -0
  233. package/dist/util/id.js.map +1 -0
  234. package/dist/util/json.d.ts +25 -0
  235. package/dist/util/json.js +100 -0
  236. package/dist/util/json.js.map +1 -0
  237. package/dist/util/jwt.d.ts +74 -0
  238. package/dist/util/jwt.js +177 -0
  239. package/dist/util/jwt.js.map +1 -0
  240. package/dist/util/logger.d.ts +13 -0
  241. package/dist/util/logger.js +59 -0
  242. package/dist/util/logger.js.map +1 -0
  243. package/dist/util/queue.d.ts +26 -0
  244. package/dist/util/queue.js +106 -0
  245. package/dist/util/queue.js.map +1 -0
  246. package/dist/util/schema.d.ts +17 -0
  247. package/dist/util/schema.js +98 -0
  248. package/dist/util/schema.js.map +1 -0
  249. package/dist/util/shell.d.ts +20 -0
  250. package/dist/util/shell.js +24 -0
  251. package/dist/util/shell.js.map +1 -0
  252. package/official.json +4 -0
  253. package/package.json +38 -0
  254. package/skills/artifact-authoring/SKILL.md +81 -0
  255. package/skills/canvas/SKILL.md +85 -0
  256. package/skills/skill-authoring/SKILL.md +85 -0
@@ -0,0 +1,125 @@
1
+ import { ConfigError } from "../core/errors.js";
2
+ const ALIASES = {
3
+ "@yearly": "0 0 1 1 *",
4
+ "@annually": "0 0 1 1 *",
5
+ "@monthly": "0 0 1 * *",
6
+ "@weekly": "0 0 * * 0",
7
+ "@daily": "0 0 * * *",
8
+ "@midnight": "0 0 * * *",
9
+ "@hourly": "0 * * * *",
10
+ };
11
+ const MONTH_NAMES = ["jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec"];
12
+ const DAY_NAMES = ["sun", "mon", "tue", "wed", "thu", "fri", "sat"];
13
+ const SPECS = [
14
+ { min: 0, max: 59 },
15
+ { min: 0, max: 23 },
16
+ { min: 1, max: 31 },
17
+ { min: 1, max: 12, names: MONTH_NAMES },
18
+ { min: 0, max: 7, names: DAY_NAMES },
19
+ ];
20
+ export function parseCron(expression) {
21
+ const normalized = ALIASES[expression.trim().toLowerCase()] ?? expression.trim();
22
+ const parts = normalized.split(/\s+/);
23
+ if (parts.length !== 5) {
24
+ throw new ConfigError(`cron expression must have 5 fields (minute hour day-of-month month day-of-week), got ${parts.length}: "${expression}"`);
25
+ }
26
+ const sets = parts.map((part, index) => parseField(part, SPECS[index], expression));
27
+ // Cron writes Sunday as either 0 or 7; normalize so lookups only check 0.
28
+ const dayOfWeek = sets[4];
29
+ if (dayOfWeek.has(7)) {
30
+ dayOfWeek.delete(7);
31
+ dayOfWeek.add(0);
32
+ }
33
+ return {
34
+ minute: sets[0],
35
+ hour: sets[1],
36
+ dayOfMonth: sets[2],
37
+ month: sets[3],
38
+ dayOfWeek,
39
+ dayFieldsAreOr: parts[2] !== "*" && parts[4] !== "*",
40
+ };
41
+ }
42
+ function parseField(raw, spec, expression) {
43
+ const out = new Set();
44
+ for (const term of raw.split(",")) {
45
+ const [rangePart, stepPart] = term.split("/");
46
+ const step = stepPart === undefined ? 1 : Number(stepPart);
47
+ if (!Number.isInteger(step) || step < 1) {
48
+ throw new ConfigError(`invalid step "${stepPart}" in cron expression "${expression}"`);
49
+ }
50
+ let from;
51
+ let to;
52
+ if (rangePart === "*" || rangePart === "?") {
53
+ from = spec.min;
54
+ to = spec.max;
55
+ }
56
+ else if (rangePart.includes("-")) {
57
+ const [a, b] = rangePart.split("-");
58
+ from = toNumber(a, spec, expression);
59
+ to = toNumber(b, spec, expression);
60
+ }
61
+ else {
62
+ from = toNumber(rangePart, spec, expression);
63
+ // A bare value with a step means "from here to the end", per crontab(5).
64
+ to = stepPart === undefined ? from : spec.max;
65
+ }
66
+ if (from > to) {
67
+ throw new ConfigError(`range ${from}-${to} is inverted in cron expression "${expression}"`);
68
+ }
69
+ for (let value = from; value <= to; value += step)
70
+ out.add(value);
71
+ }
72
+ if (out.size === 0) {
73
+ throw new ConfigError(`field "${raw}" matches nothing in cron expression "${expression}"`);
74
+ }
75
+ return out;
76
+ }
77
+ function toNumber(token, spec, expression) {
78
+ const named = spec.names?.indexOf(token.toLowerCase());
79
+ const value = named !== undefined && named >= 0 ? named + (spec.min === 1 ? 1 : 0) : Number(token);
80
+ if (!Number.isInteger(value) || value < spec.min || value > spec.max) {
81
+ throw new ConfigError(`"${token}" is out of range ${spec.min}-${spec.max} in cron expression "${expression}"`);
82
+ }
83
+ return value;
84
+ }
85
+ /** Whether a wall-clock instant matches, to the minute. */
86
+ export function matches(fields, date) {
87
+ if (!fields.minute.has(date.getMinutes()))
88
+ return false;
89
+ if (!fields.hour.has(date.getHours()))
90
+ return false;
91
+ if (!fields.month.has(date.getMonth() + 1))
92
+ return false;
93
+ const domMatch = fields.dayOfMonth.has(date.getDate());
94
+ const dowMatch = fields.dayOfWeek.has(date.getDay());
95
+ // The OR rule: with both fields restricted, either one firing is enough.
96
+ return fields.dayFieldsAreOr ? domMatch || dowMatch : domMatch && dowMatch;
97
+ }
98
+ /**
99
+ * The next instant at or after `from` that matches.
100
+ *
101
+ * Steps a minute at a time rather than solving the fields analytically: it is
102
+ * a few thousand iterations at worst, and it stays correct across DST shifts
103
+ * because it asks the platform's calendar rather than doing date arithmetic.
104
+ * Returns undefined if nothing matches within four years (e.g. Feb 30).
105
+ */
106
+ export function nextRun(fields, from = new Date()) {
107
+ const cursor = new Date(from.getTime());
108
+ cursor.setSeconds(0, 0);
109
+ cursor.setMinutes(cursor.getMinutes() + 1);
110
+ const limit = 4 * 366 * 24 * 60;
111
+ for (let i = 0; i < limit; i++) {
112
+ if (matches(fields, cursor))
113
+ return cursor;
114
+ cursor.setMinutes(cursor.getMinutes() + 1);
115
+ }
116
+ return undefined;
117
+ }
118
+ /** Describe a schedule in words, for `schedule list`. */
119
+ export function describeCron(expression) {
120
+ const alias = Object.entries(ALIASES).find(([name]) => name === expression.trim().toLowerCase());
121
+ if (alias)
122
+ return `${alias[0].slice(1)} (${alias[1]})`;
123
+ return expression.trim();
124
+ }
125
+ //# sourceMappingURL=cron.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cron.js","sourceRoot":"","sources":["../../src/schedule/cron.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,87 @@
1
+ import type { Harness } from "../harness.ts";
2
+ import type { PermissionMode } from "../agent/permissions.ts";
3
+ export interface ScheduleDefinition {
4
+ name: string;
5
+ /** Five-field cron, or an `@daily`-style alias. */
6
+ cron: string;
7
+ /** The prompt each firing runs. */
8
+ prompt: string;
9
+ model?: string;
10
+ /**
11
+ * Defaults to `bypassPermissions`: a scheduled run has nobody to ask, so
12
+ * anything else silently blocks on the first approval and looks like a hang.
13
+ * Constrain it with `permissions` rules instead of an interactive mode.
14
+ */
15
+ permissionMode?: PermissionMode;
16
+ maxTurns?: number;
17
+ enabled?: boolean;
18
+ /** Working directory for the run; defaults to the harness cwd. */
19
+ cwd?: string;
20
+ }
21
+ export interface ScheduleRun {
22
+ schedule: string;
23
+ startedAt: number;
24
+ finishedAt: number;
25
+ sessionId: string;
26
+ ok: boolean;
27
+ turns: number;
28
+ costUsd: number;
29
+ /** Final assistant text, truncated. */
30
+ output: string;
31
+ error?: string;
32
+ }
33
+ export interface ScheduleStatus {
34
+ name: string;
35
+ cron: string;
36
+ enabled: boolean;
37
+ nextRunAt?: number;
38
+ lastRun?: ScheduleRun;
39
+ }
40
+ /**
41
+ * Runs prompts on a cron schedule.
42
+ *
43
+ * Each firing gets its own session rather than appending to a long-lived one:
44
+ * a nightly job that shares context with every previous night would compact
45
+ * itself into uselessness within a week, and a failure would poison every
46
+ * subsequent run.
47
+ */
48
+ export declare class Scheduler {
49
+ private readonly harness;
50
+ private readonly logger;
51
+ private readonly schedules;
52
+ private readonly runDir;
53
+ private timer?;
54
+ private running;
55
+ /** Names currently executing, so a slow job cannot overlap itself. */
56
+ private readonly inFlight;
57
+ constructor(harness: Harness, definitions?: ScheduleDefinition[], opts?: {
58
+ runDir?: string;
59
+ });
60
+ add(def: ScheduleDefinition): this;
61
+ remove(name: string): boolean;
62
+ list(): ScheduleDefinition[];
63
+ status(): Promise<ScheduleStatus[]>;
64
+ /**
65
+ * Run one schedule now, regardless of its cron.
66
+ *
67
+ * This is also how you test a schedule — waiting until midnight to discover
68
+ * the prompt was wrong is a poor development loop.
69
+ */
70
+ runNow(name: string): Promise<ScheduleRun>;
71
+ /**
72
+ * Start firing on schedule.
73
+ *
74
+ * Wakes every 30s and fires anything whose minute has arrived, rather than
75
+ * sleeping until the exact next occurrence: a laptop that suspends would
76
+ * otherwise wake with a timer scheduled for a moment that has passed.
77
+ */
78
+ start(): void;
79
+ stop(): void;
80
+ /** Resolves when every in-flight run has finished. */
81
+ drain(): Promise<void>;
82
+ private execute;
83
+ private recordRun;
84
+ private lastRun;
85
+ /** Past runs, newest first. */
86
+ history(name: string, limit?: number): Promise<ScheduleRun[]>;
87
+ }
@@ -0,0 +1,237 @@
1
+ import { userPath } from "../paths.js";
2
+ import { appendFile, mkdir, readFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { ConfigError, errorMessage } from "../core/errors.js";
5
+ import { messageText } from "../core/types.js";
6
+ import { createLogger } from "../util/logger.js";
7
+ import { parseJson } from "../util/json.js";
8
+ import { nextRun, parseCron } from "./cron.js";
9
+ const MAX_OUTPUT_CHARS = 4_000;
10
+ /**
11
+ * Runs prompts on a cron schedule.
12
+ *
13
+ * Each firing gets its own session rather than appending to a long-lived one:
14
+ * a nightly job that shares context with every previous night would compact
15
+ * itself into uselessness within a week, and a failure would poison every
16
+ * subsequent run.
17
+ */
18
+ export class Scheduler {
19
+ harness;
20
+ logger;
21
+ schedules = new Map();
22
+ runDir;
23
+ timer;
24
+ running = false;
25
+ /** Names currently executing, so a slow job cannot overlap itself. */
26
+ inFlight = new Set();
27
+ constructor(harness, definitions = [], opts = {}) {
28
+ this.harness = harness;
29
+ this.logger = harness.logger.child("scheduler");
30
+ this.runDir = opts.runDir ?? userPath("schedules");
31
+ for (const def of definitions)
32
+ this.add(def);
33
+ }
34
+ add(def) {
35
+ if (!def.name)
36
+ throw new ConfigError("a schedule needs a name");
37
+ if (!def.prompt)
38
+ throw new ConfigError(`schedule "${def.name}" has no prompt`);
39
+ // Parse eagerly: a bad expression should fail at load, not at 3am.
40
+ this.schedules.set(def.name, { def, fields: parseCron(def.cron) });
41
+ return this;
42
+ }
43
+ remove(name) {
44
+ return this.schedules.delete(name);
45
+ }
46
+ list() {
47
+ return [...this.schedules.values()].map((entry) => entry.def);
48
+ }
49
+ async status() {
50
+ const out = [];
51
+ for (const { def, fields } of this.schedules.values()) {
52
+ const enabled = def.enabled !== false;
53
+ out.push({
54
+ name: def.name,
55
+ cron: def.cron,
56
+ enabled,
57
+ nextRunAt: enabled ? nextRun(fields)?.getTime() : undefined,
58
+ lastRun: await this.lastRun(def.name),
59
+ });
60
+ }
61
+ return out;
62
+ }
63
+ /**
64
+ * Run one schedule now, regardless of its cron.
65
+ *
66
+ * This is also how you test a schedule — waiting until midnight to discover
67
+ * the prompt was wrong is a poor development loop.
68
+ */
69
+ async runNow(name) {
70
+ const entry = this.schedules.get(name);
71
+ if (!entry)
72
+ throw new ConfigError(`no schedule named "${name}"`);
73
+ return this.execute(entry.def);
74
+ }
75
+ /**
76
+ * Start firing on schedule.
77
+ *
78
+ * Wakes every 30s and fires anything whose minute has arrived, rather than
79
+ * sleeping until the exact next occurrence: a laptop that suspends would
80
+ * otherwise wake with a timer scheduled for a moment that has passed.
81
+ */
82
+ start() {
83
+ if (this.running)
84
+ return;
85
+ this.running = true;
86
+ let lastMinute = -1;
87
+ const tick = () => {
88
+ const now = new Date();
89
+ const minute = Math.floor(now.getTime() / 60_000);
90
+ // Only evaluate once per wall-clock minute, however often we wake.
91
+ if (minute === lastMinute)
92
+ return;
93
+ lastMinute = minute;
94
+ for (const { def, fields } of this.schedules.values()) {
95
+ if (def.enabled === false)
96
+ continue;
97
+ if (!matchesNow(fields, now))
98
+ continue;
99
+ if (this.inFlight.has(def.name)) {
100
+ // A run still going when the next occurrence arrives means the job
101
+ // is slower than its interval; skipping is safer than piling up.
102
+ this.logger.warn("skipping overlapping run", { schedule: def.name });
103
+ continue;
104
+ }
105
+ void this.execute(def);
106
+ }
107
+ };
108
+ this.timer = setInterval(tick, 30_000);
109
+ // Do not hold the process open on our account; the CLI daemon decides.
110
+ this.timer.unref?.();
111
+ tick();
112
+ }
113
+ stop() {
114
+ this.running = false;
115
+ if (this.timer)
116
+ clearInterval(this.timer);
117
+ this.timer = undefined;
118
+ }
119
+ /** Resolves when every in-flight run has finished. */
120
+ async drain() {
121
+ while (this.inFlight.size > 0) {
122
+ await new Promise((resolve) => setTimeout(resolve, 50));
123
+ }
124
+ }
125
+ async execute(def) {
126
+ this.inFlight.add(def.name);
127
+ const startedAt = Date.now();
128
+ this.logger.info("running schedule", { schedule: def.name });
129
+ const session = this.harness.createSession({
130
+ model: def.model,
131
+ title: `schedule: ${def.name}`,
132
+ });
133
+ const agent = this.harness.agent(session, {
134
+ // Nobody is at the keyboard to approve anything.
135
+ permissionPrompt: async () => false,
136
+ ...(def.maxTurns !== undefined ? { maxTurns: def.maxTurns } : {}),
137
+ });
138
+ session.permissions.setMode(def.permissionMode ?? "bypassPermissions");
139
+ let output = "";
140
+ let ok = true;
141
+ let error;
142
+ try {
143
+ for await (const event of agent.run(def.prompt)) {
144
+ if (event.type === "assistant_message")
145
+ output = messageText(event.message) || output;
146
+ if (event.type === "error" && event.fatal) {
147
+ ok = false;
148
+ error = event.error;
149
+ }
150
+ }
151
+ }
152
+ catch (err) {
153
+ ok = false;
154
+ error = errorMessage(err);
155
+ this.logger.error("schedule failed", { schedule: def.name, error });
156
+ }
157
+ finally {
158
+ await agent.end().catch(() => { });
159
+ this.inFlight.delete(def.name);
160
+ }
161
+ const run = {
162
+ schedule: def.name,
163
+ startedAt,
164
+ finishedAt: Date.now(),
165
+ sessionId: session.id,
166
+ ok,
167
+ turns: session.turns,
168
+ costUsd: session.costUsd,
169
+ output: output.slice(0, MAX_OUTPUT_CHARS),
170
+ ...(error ? { error } : {}),
171
+ };
172
+ await this.recordRun(run).catch((err) => this.logger.warn("could not record the run", { error: String(err) }));
173
+ return run;
174
+ }
175
+ async recordRun(run) {
176
+ await mkdir(this.runDir, { recursive: true });
177
+ await appendFile(path.join(this.runDir, `${safeName(run.schedule)}.jsonl`), `${JSON.stringify(run)}\n`, "utf8");
178
+ }
179
+ async lastRun(name) {
180
+ let raw;
181
+ try {
182
+ raw = await readFile(path.join(this.runDir, `${safeName(name)}.jsonl`), "utf8");
183
+ }
184
+ catch {
185
+ return undefined;
186
+ }
187
+ const lines = raw.split("\n").filter((line) => line.trim() !== "");
188
+ for (let i = lines.length - 1; i >= 0; i--) {
189
+ const parsed = parseJson(lines[i]);
190
+ if (parsed.ok)
191
+ return parsed.value;
192
+ }
193
+ return undefined;
194
+ }
195
+ /** Past runs, newest first. */
196
+ async history(name, limit = 20) {
197
+ let raw;
198
+ try {
199
+ raw = await readFile(path.join(this.runDir, `${safeName(name)}.jsonl`), "utf8");
200
+ }
201
+ catch {
202
+ return [];
203
+ }
204
+ const runs = [];
205
+ for (const line of raw.split("\n")) {
206
+ if (line.trim() === "")
207
+ continue;
208
+ const parsed = parseJson(line);
209
+ if (parsed.ok)
210
+ runs.push(parsed.value);
211
+ }
212
+ return runs.reverse().slice(0, limit);
213
+ }
214
+ }
215
+ /** A schedule name becomes a filename, so keep it to safe characters. */
216
+ function safeName(name) {
217
+ return name.replace(/[^A-Za-z0-9._-]/g, "_");
218
+ }
219
+ function matchesNow(fields, now) {
220
+ // `matches` is minute-granular and `now` carries seconds; zero them so a
221
+ // tick at 12:00:37 still counts as 12:00.
222
+ const minute = new Date(now.getTime());
223
+ minute.setSeconds(0, 0);
224
+ return matchesMinute(fields, minute);
225
+ }
226
+ function matchesMinute(fields, date) {
227
+ if (!fields.minute.has(date.getMinutes()))
228
+ return false;
229
+ if (!fields.hour.has(date.getHours()))
230
+ return false;
231
+ if (!fields.month.has(date.getMonth() + 1))
232
+ return false;
233
+ const dom = fields.dayOfMonth.has(date.getDate());
234
+ const dow = fields.dayOfWeek.has(date.getDay());
235
+ return fields.dayFieldsAreOr ? dom || dow : dom && dow;
236
+ }
237
+ //# sourceMappingURL=scheduler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scheduler.js","sourceRoot":"","sources":["../../src/schedule/scheduler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * A directory of JSON files, addressed by key.
3
+ *
4
+ * A key is a path: `["session", projectId, sessionId]` is one file. That is the
5
+ * whole abstraction, and it is deliberate — the store has to stay something a
6
+ * person can open in a file browser and read, because a transcript nobody can
7
+ * recover by hand is a transcript that can be lost by a bug in this file.
8
+ *
9
+ * Two shapes live here. Documents (`.json`) are read and written whole; logs
10
+ * (`.jsonl`) are appended a line at a time so a crashed process still leaves
11
+ * everything written before it, and so appending never rewrites what is
12
+ * already there.
13
+ */
14
+ export declare class JsonStore {
15
+ readonly root: string;
16
+ constructor(root: string);
17
+ /** Path of a document key. */
18
+ file(key: string[]): string;
19
+ /** Path of a log key. */
20
+ log(key: string[]): string;
21
+ read<T>(key: string[]): Promise<T | undefined>;
22
+ /**
23
+ * Write a document.
24
+ *
25
+ * Temp file plus rename: a process killed mid-write would otherwise leave a
26
+ * truncated file, and a half-written meta.json is a session that has
27
+ * disappeared as far as every reader is concerned.
28
+ */
29
+ write(key: string[], value: unknown): Promise<void>;
30
+ remove(key: string[]): Promise<void>;
31
+ removeLog(key: string[]): Promise<void>;
32
+ /** Every document key under a prefix, depth-first, sorted. */
33
+ list(prefix: string[]): Promise<string[][]>;
34
+ /**
35
+ * Every log key under a prefix, depth-first, sorted.
36
+ *
37
+ * The counterpart to `list`, and it exists for the same reason: something
38
+ * has to be able to answer "which sessions wrote artifacts" without opening
39
+ * a session to ask it. A readdir answers that; reading the logs to find out
40
+ * would be reading everything on the machine to decide what to read.
41
+ */
42
+ listLogs(prefix: string[]): Promise<string[][]>;
43
+ private keysUnder;
44
+ append(key: string[], lines: unknown[]): Promise<void>;
45
+ /** Rewrite a log wholesale. Only compaction does this; appends are the norm. */
46
+ replaceLog(key: string[], lines: unknown[]): Promise<void>;
47
+ /**
48
+ * Read a log.
49
+ *
50
+ * Corrupt lines are skipped rather than failing the read: a torn final line
51
+ * from a killed process should cost that one line, not the transcript.
52
+ * `maxBytes` reads the tail instead of the whole file, for logs that grow
53
+ * without bound.
54
+ */
55
+ readLog<T>(key: string[], maxBytes?: number): Promise<T[]>;
56
+ }