@ashlr/hub 3.5.1 → 3.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 (110) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/README.md +3 -0
  3. package/dist/build-identity.json +2 -2
  4. package/dist/cli/activation.d.ts +41 -0
  5. package/dist/cli/activation.js +485 -0
  6. package/dist/cli/activation.js.map +1 -0
  7. package/dist/core/daemon/cutoff-checkpoint-scheduler.js +7 -0
  8. package/dist/core/daemon/cutoff-checkpoint-scheduler.js.map +1 -1
  9. package/dist/core/daemon/loop.d.ts +19 -0
  10. package/dist/core/daemon/loop.js +235 -5
  11. package/dist/core/daemon/loop.js.map +1 -1
  12. package/dist/core/daemon/overnight-status.d.ts +152 -0
  13. package/dist/core/daemon/overnight-status.js +275 -0
  14. package/dist/core/daemon/overnight-status.js.map +1 -0
  15. package/dist/core/daemon/post-merge-halt.d.ts +212 -0
  16. package/dist/core/daemon/post-merge-halt.js +503 -0
  17. package/dist/core/daemon/post-merge-halt.js.map +1 -0
  18. package/dist/core/daemon/run-window.d.ts +218 -0
  19. package/dist/core/daemon/run-window.js +420 -0
  20. package/dist/core/daemon/run-window.js.map +1 -0
  21. package/dist/core/fleet/generated-repair-resolution.d.ts +36 -0
  22. package/dist/core/fleet/generated-repair-resolution.js +245 -0
  23. package/dist/core/fleet/generated-repair-resolution.js.map +1 -0
  24. package/dist/core/local-runtime/llama/port.d.ts +17 -0
  25. package/dist/core/local-runtime/llama/port.js +47 -0
  26. package/dist/core/local-runtime/llama/port.js.map +1 -0
  27. package/dist/core/local-runtime/llama/proxy-host.d.ts +54 -0
  28. package/dist/core/local-runtime/llama/proxy-host.js +159 -0
  29. package/dist/core/local-runtime/llama/proxy-host.js.map +1 -0
  30. package/dist/core/local-runtime/llama/proxy-process.d.ts +148 -0
  31. package/dist/core/local-runtime/llama/proxy-process.js +250 -0
  32. package/dist/core/local-runtime/llama/proxy-process.js.map +1 -0
  33. package/dist/core/local-runtime/llama/proxy-record.d.ts +40 -0
  34. package/dist/core/local-runtime/llama/proxy-record.js +133 -0
  35. package/dist/core/local-runtime/llama/proxy-record.js.map +1 -0
  36. package/dist/core/local-runtime/llama/proxy-supervisor.d.ts +118 -0
  37. package/dist/core/local-runtime/llama/proxy-supervisor.js +511 -0
  38. package/dist/core/local-runtime/llama/proxy-supervisor.js.map +1 -0
  39. package/dist/core/web/public/next/assets/{App-BbVoUCIi.js → App-vtaHB9mp.js} +2 -2
  40. package/dist/core/web/public/next/assets/{App-BbVoUCIi.js.map → App-vtaHB9mp.js.map} +1 -1
  41. package/dist/core/web/public/next/assets/{ApprovalsSection-BW9iVjUa.js → ApprovalsSection-B-bFJ0I9.js} +2 -2
  42. package/dist/core/web/public/next/assets/{ApprovalsSection-BW9iVjUa.js.map → ApprovalsSection-B-bFJ0I9.js.map} +1 -1
  43. package/dist/core/web/public/next/assets/{AutonomySection-Cpk_oEhc.css → AutonomySection-CHjxJt2z.css} +1 -1
  44. package/dist/core/web/public/next/assets/AutonomySection-DoqmsCjw.js +2 -0
  45. package/dist/core/web/public/next/assets/AutonomySection-DoqmsCjw.js.map +1 -0
  46. package/dist/core/web/public/next/assets/ChatSection-BfnLe5dT.css +1 -0
  47. package/dist/core/web/public/next/assets/ChatSection-vNPIJffd.js +80 -0
  48. package/dist/core/web/public/next/assets/ChatSection-vNPIJffd.js.map +1 -0
  49. package/dist/core/web/public/next/assets/{ConfirmDialog-CXevY3Au.js → ConfirmDialog-Dd2APQhB.js} +2 -2
  50. package/dist/core/web/public/next/assets/{ConfirmDialog-CXevY3Au.js.map → ConfirmDialog-Dd2APQhB.js.map} +1 -1
  51. package/dist/core/web/public/next/assets/{Dialog-Bn0CgEGz.js → Dialog-CPM9JxBc.js} +2 -2
  52. package/dist/core/web/public/next/assets/{Dialog-Bn0CgEGz.js.map → Dialog-CPM9JxBc.js.map} +1 -1
  53. package/dist/core/web/public/next/assets/{DiffViewer-QKyisN2L.js → DiffViewer-B84qVef9.js} +2 -2
  54. package/dist/core/web/public/next/assets/{DiffViewer-QKyisN2L.js.map → DiffViewer-B84qVef9.js.map} +1 -1
  55. package/dist/core/web/public/next/assets/McpSection-CEUpV_5X.js +2 -0
  56. package/dist/core/web/public/next/assets/McpSection-CEUpV_5X.js.map +1 -0
  57. package/dist/core/web/public/next/assets/McpSection-D88QlDpG.css +1 -0
  58. package/dist/core/web/public/next/assets/Meter--h3MmZS-.js +2 -0
  59. package/dist/core/web/public/next/assets/Meter--h3MmZS-.js.map +1 -0
  60. package/dist/core/web/public/next/assets/Meter-CLcr-4wS.css +1 -0
  61. package/dist/core/web/public/next/assets/{MutationTokenDialog-DbSHPy3w.js → MutationTokenDialog-DA8t97XT.js} +2 -2
  62. package/dist/core/web/public/next/assets/{MutationTokenDialog-DbSHPy3w.js.map → MutationTokenDialog-DA8t97XT.js.map} +1 -1
  63. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-C-PCgCzo.js → ResourcePoolConsoleApp-Bq7Vyud0.js} +2 -2
  64. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-C-PCgCzo.js.map → ResourcePoolConsoleApp-Bq7Vyud0.js.map} +1 -1
  65. package/dist/core/web/public/next/assets/{RouteErrorBoundary-Dw8ZjmkS.js → RouteErrorBoundary-Badio_uO.js} +2 -2
  66. package/dist/core/web/public/next/assets/{RouteErrorBoundary-Dw8ZjmkS.js.map → RouteErrorBoundary-Badio_uO.js.map} +1 -1
  67. package/dist/core/web/public/next/assets/SettingsSection-BwrpQlpP.js +2 -0
  68. package/dist/core/web/public/next/assets/SettingsSection-BwrpQlpP.js.map +1 -0
  69. package/dist/core/web/public/next/assets/{UniverseConsoleApp-Bk5HipM0.js → UniverseConsoleApp-_FSohAdN.js} +2 -2
  70. package/dist/core/web/public/next/assets/{UniverseConsoleApp-Bk5HipM0.js.map → UniverseConsoleApp-_FSohAdN.js.map} +1 -1
  71. package/dist/core/web/public/next/assets/{UniverseView-D8k9q0ce.js → UniverseView-DqcXbed4.js} +2 -2
  72. package/dist/core/web/public/next/assets/{UniverseView-D8k9q0ce.js.map → UniverseView-DqcXbed4.js.map} +1 -1
  73. package/dist/core/web/public/next/assets/{UsageSection-B2E06ZH1.js → UsageSection-Bq6Daaby.js} +2 -2
  74. package/dist/core/web/public/next/assets/{UsageSection-B2E06ZH1.js.map → UsageSection-Bq6Daaby.js.map} +1 -1
  75. package/dist/core/web/public/next/assets/VerseConsoleApp-CMkCizvL.css +1 -0
  76. package/dist/core/web/public/next/assets/VerseConsoleApp-CsIQv9id.js +3 -0
  77. package/dist/core/web/public/next/assets/VerseConsoleApp-CsIQv9id.js.map +1 -0
  78. package/dist/core/web/public/next/assets/{charts-DSUpczxG.js → charts-CTZJ-JrH.js} +2 -2
  79. package/dist/core/web/public/next/assets/{charts-DSUpczxG.js.map → charts-CTZJ-JrH.js.map} +1 -1
  80. package/dist/core/web/public/next/assets/global-D6bTxIRn.js +2 -0
  81. package/dist/core/web/public/next/assets/global-D6bTxIRn.js.map +1 -0
  82. package/dist/core/web/public/next/assets/global-z-JfD3ow.css +1 -0
  83. package/dist/core/web/public/next/assets/{icons-BxOX8-XB.js → icons-D9vlf85u.js} +2 -2
  84. package/dist/core/web/public/next/assets/{icons-BxOX8-XB.js.map → icons-D9vlf85u.js.map} +1 -1
  85. package/dist/core/web/public/next/assets/{index-BMRIET7F.js → index-CZamKRUg.js} +3 -3
  86. package/dist/core/web/public/next/assets/{index-BMRIET7F.js.map → index-CZamKRUg.js.map} +1 -1
  87. package/dist/core/web/public/next/assets/{queries-AxnVa02h.js → queries-B8eBnFox.js} +2 -2
  88. package/dist/core/web/public/next/assets/{queries-AxnVa02h.js.map → queries-B8eBnFox.js.map} +1 -1
  89. package/dist/core/web/public/next/assets/{use-guarded-action-BO6c94Wp.js → use-guarded-action-bzrVVAYq.js} +2 -2
  90. package/dist/core/web/public/next/assets/{use-guarded-action-BO6c94Wp.js.map → use-guarded-action-bzrVVAYq.js.map} +1 -1
  91. package/dist/core/web/public/next/assets/workspace-model-v0a1gl-C.js +2 -0
  92. package/dist/core/web/public/next/assets/workspace-model-v0a1gl-C.js.map +1 -0
  93. package/dist/core/web/public/next/index.html +1 -1
  94. package/dist/release-dependency-inventory.json +1 -1
  95. package/package.json +1 -1
  96. package/dist/core/web/public/next/assets/AutonomySection-CRqHUhED.js +0 -2
  97. package/dist/core/web/public/next/assets/AutonomySection-CRqHUhED.js.map +0 -1
  98. package/dist/core/web/public/next/assets/ChatSection-5irrh6Jw.js +0 -80
  99. package/dist/core/web/public/next/assets/ChatSection-5irrh6Jw.js.map +0 -1
  100. package/dist/core/web/public/next/assets/ChatSection-LQiAn6Eu.css +0 -1
  101. package/dist/core/web/public/next/assets/SettingsSection-CWxtTNlD.js +0 -2
  102. package/dist/core/web/public/next/assets/SettingsSection-CWxtTNlD.js.map +0 -1
  103. package/dist/core/web/public/next/assets/VerseConsoleApp-CRfZUV-T.js +0 -3
  104. package/dist/core/web/public/next/assets/VerseConsoleApp-CRfZUV-T.js.map +0 -1
  105. package/dist/core/web/public/next/assets/VerseConsoleApp-D2E3mU9a.css +0 -1
  106. package/dist/core/web/public/next/assets/global-C4jfYHrj.js +0 -2
  107. package/dist/core/web/public/next/assets/global-C4jfYHrj.js.map +0 -1
  108. package/dist/core/web/public/next/assets/global-D463gG1X.css +0 -1
  109. package/dist/core/web/public/next/assets/workspace-model-cE4LkKpE.js +0 -2
  110. package/dist/core/web/public/next/assets/workspace-model-cE4LkKpE.js.map +0 -1
@@ -0,0 +1,218 @@
1
+ /**
2
+ * run-window.ts — the BOUNDED RUN WINDOW. Pure maths, no I/O, never throws.
3
+ *
4
+ * ── WHY THIS EXISTS ────────────────────────────────────────────────────────
5
+ * Every scheduler in this repo is relative-elapsed: `Date.now()` deltas and
6
+ * `setTimeout`. Nothing parses a time of day, nothing knows a timezone, and
7
+ * `StartCalendarInterval` appears nowhere — the two launch-trigger allowlists
8
+ * (`daemon/runtime-activation-transaction.ts`, `daemon/resident-service-
9
+ * readiness.ts`) actively REJECT an extra OS trigger and their tests lock that.
10
+ * So an overnight run window cannot be an OS launch trigger. It is IN-PROCESS,
11
+ * and this module is the whole of its arithmetic.
12
+ *
13
+ * Three stop rules, chosen per run:
14
+ *
15
+ * { kind: 'until-paused' } run until the operator parks it
16
+ * { kind: 'until-clock', at: '07:00' } stop at a wall-clock local time
17
+ * { kind: 'iterations', max: 40 } stop after N loop iterations
18
+ *
19
+ * ── THE THINGS A NAIVE CLOCK GETS WRONG ────────────────────────────────────
20
+ *
21
+ * 1. THE MACHINE SLEEPS AND WAKES PAST THE END TIME.
22
+ * A window must NEVER be held as "remaining milliseconds" counted down by
23
+ * elapsed time, and must never be armed as one long `setTimeout`. A laptop
24
+ * suspended at 01:00 and opened at 09:00 fired no timers in between; a
25
+ * single `setTimeout(6h)` scheduled for 07:00 fires at 15:00 on macOS,
26
+ * eight hours of wall-clock too late, and a countdown of elapsed awake time
27
+ * never reaches zero at all. So the window is stored as an ABSOLUTE epoch
28
+ * instant (`endsAtMs`) and every check is `Date.now() >= endsAtMs`. A run
29
+ * that slept through its own end time is expired the first moment it looks,
30
+ * with `reason: 'clock-reached'` and a negative remaining — which is the
31
+ * correct answer, not an error. {@link runWindowParkMs} additionally caps
32
+ * every park at {@link RUN_WINDOW_MAX_PARK_MS} so a woken process re-checks
33
+ * within a minute instead of finishing a stale timer.
34
+ *
35
+ * 2. A STOP TIME THAT IS TOMORROW. The overnight case IS the case: a run
36
+ * started at 23:00 that stops at 07:00 must resolve to TOMORROW's 07:00,
37
+ * not to an instant eight hours in the past. {@link nextWallClockOccurrenceMs}
38
+ * always resolves strictly forward — when today's occurrence is already at
39
+ * or behind `now`, it advances one LOCAL CALENDAR DAY (not `+24h`, which is
40
+ * wrong across a DST transition by exactly the offset change).
41
+ *
42
+ * 3. THE LOCAL TIMEZONE, AND DST. '07:00' means 07:00 where the operator is.
43
+ * Offsets are resolved per-instant from the IANA zone via `Intl`, so a
44
+ * window spanning a DST boundary is 7 or 9 hours of real time as the clock
45
+ * requires, not a fixed 8. A local time that does not exist (the spring-
46
+ * forward gap) resolves to the instant the clock jumps to; a local time
47
+ * that happens twice (the autumn fall-back) resolves to the FIRST of the
48
+ * two. Both are documented choices, not accidents — see
49
+ * {@link wallClockToEpochMs}.
50
+ *
51
+ * This module decides nothing about stopping. It reports that the window is
52
+ * over; `loop.ts` parks the daemon by PAUSING (`~/.ashlr/daemon.paused`), never
53
+ * by `stopDaemon()`, which is `setKill(true)` and would also refuse the agent's
54
+ * own write tools. See `daemon/pause.ts`.
55
+ *
56
+ * No new runtime deps; `Intl` only. Never throws out of a public API.
57
+ */
58
+ /**
59
+ * The three stop rules. A run picks exactly one.
60
+ *
61
+ * This is the wire shape `POST /api/verse/overnight` sends, shared verbatim
62
+ * with the client's `overnight-contract.ts`.
63
+ *
64
+ * `at` is an ABSOLUTE ISO-8601 instant, deliberately NOT a time of day. The
65
+ * caller resolves the operator's wall-clock pick to the next occurrence in
66
+ * their own timezone BEFORE arming, which removes the ambiguity entirely: a
67
+ * 23:50 arming for "07:00" can never be read here as ten minutes ago. A caller
68
+ * with no browser (the CLI) resolves it with {@link resolveWallClockStopRule},
69
+ * which is the same arithmetic the browser does.
70
+ */
71
+ export type RunWindowStopRule = {
72
+ readonly kind: 'until-paused';
73
+ } | {
74
+ readonly kind: 'at-time';
75
+ readonly at: string;
76
+ } | {
77
+ readonly kind: 'after-iterations';
78
+ readonly iterations: number;
79
+ };
80
+ /** A stop rule resolved against a concrete `now` into absolute quantities. */
81
+ export interface ResolvedRunWindow {
82
+ readonly kind: RunWindowStopRule['kind'];
83
+ /** Epoch ms the window was armed at. */
84
+ readonly startedAtMs: number;
85
+ /**
86
+ * ABSOLUTE epoch ms the window ends, or null when the rule has no clock
87
+ * component. Never a duration — see note 1 in the file header.
88
+ */
89
+ readonly endsAtMs: number | null;
90
+ /** Iteration ceiling, or null when the rule has no iteration component. */
91
+ readonly maxIterations: number | null;
92
+ /** The absolute ISO instant for an `at-time` rule; null otherwise. */
93
+ readonly at: string | null;
94
+ /** One line, safe for an audit summary. Metadata only. */
95
+ readonly describe: string;
96
+ }
97
+ /** Why a window is over. `null` while it is still open. */
98
+ export type RunWindowExpiry = 'clock-reached' | 'iterations-reached';
99
+ export interface RunWindowEvaluation {
100
+ readonly expired: boolean;
101
+ readonly reason: RunWindowExpiry | null;
102
+ /**
103
+ * Signed ms until `endsAtMs` (NEGATIVE when the end time already passed,
104
+ * which is how a slept-through window reports itself), or null.
105
+ */
106
+ readonly remainingMs: number | null;
107
+ readonly remainingIterations: number | null;
108
+ readonly detail: string;
109
+ }
110
+ /** {@link resolveRunWindow}'s result. A refusal is a value, never a throw. */
111
+ export type ResolveRunWindowResult = {
112
+ readonly ok: true;
113
+ readonly window: ResolvedRunWindow;
114
+ } | {
115
+ readonly ok: false;
116
+ readonly reason: string;
117
+ };
118
+ /**
119
+ * The longest a caller may park in one go while a window is open. A machine
120
+ * that suspends mid-park wakes with a stale timer; capping the chunk bounds
121
+ * how long a woken process can run past its own end time to one minute.
122
+ * Matches `sleepUntilNextUtcBudgetDay`'s existing 60s chunking in loop.ts.
123
+ */
124
+ export declare const RUN_WINDOW_MAX_PARK_MS = 60000;
125
+ /** The host's IANA zone, or 'UTC' when the runtime cannot say. Never throws. */
126
+ export declare function hostTimeZone(): string;
127
+ /** True when `timeZone` is a zone this runtime can actually resolve. */
128
+ export declare function isResolvableTimeZone(timeZone: string): boolean;
129
+ /**
130
+ * The epoch instant at which `timeZone`'s clock reads the given local
131
+ * date-and-time. Returns null when the zone cannot be resolved.
132
+ *
133
+ * Two passes: guess with the offset in force at the naive-UTC instant, then
134
+ * re-read the offset at the corrected instant and correct again if it changed.
135
+ * That second pass is what makes DST boundaries land correctly.
136
+ *
137
+ * AMBIGUOUS AND NONEXISTENT LOCAL TIMES — both documented, neither an error:
138
+ * - Spring forward (02:30 does not exist): both passes agree on an instant
139
+ * whose clock reads 03:30, i.e. the moment the clock jumps past the request.
140
+ * A window asking to stop at a skipped time stops when that time would have
141
+ * arrived, which is the operator's intent.
142
+ * - Autumn fall-back (01:30 happens twice): resolves to the FIRST occurrence,
143
+ * the earlier instant, so a window never runs an extra hour by surprise.
144
+ * Erring short is the safe direction for a bound on autonomous work.
145
+ */
146
+ export declare function wallClockToEpochMs(year: number, month: number, day: number, hour: number, minute: number, timeZone: string): number | null;
147
+ /** Parse 'HH:MM' (24h). Returns null for anything else — no throw, no guess. */
148
+ export declare function parseWallClockTime(at: string): {
149
+ hour: number;
150
+ minute: number;
151
+ } | null;
152
+ /**
153
+ * The next instant at which `timeZone`'s clock reads `at`, STRICTLY AFTER
154
+ * `nowMs`. This is the overnight wrap: at 23:00 local, '07:00' is tomorrow's
155
+ * 07:00, because today's has already gone.
156
+ *
157
+ * Advances by one LOCAL CALENDAR DAY, never by `+24h` — across a DST boundary
158
+ * those differ by the offset change, and only the calendar-day advance keeps
159
+ * the clock reading the requested time.
160
+ */
161
+ export declare function nextWallClockOccurrenceMs(at: string, nowMs: number, timeZone: string): number | null;
162
+ /**
163
+ * The iteration ceiling, matching the client contract's documented 1..500.
164
+ * A bound a typo can turn into "forever" is not a bound.
165
+ */
166
+ export declare const RUN_WINDOW_MAX_ITERATIONS = 500;
167
+ /**
168
+ * The furthest ahead an `at-time` stop may be armed. A window is a NIGHT, not
169
+ * a standing instruction; an instant six weeks out is a mistake, not a plan.
170
+ */
171
+ export declare const RUN_WINDOW_MAX_HORIZON_MS: number;
172
+ /**
173
+ * Turn an operator's wall-clock pick into the contract's absolute `at-time`
174
+ * rule. This is the arithmetic the browser does before it POSTs; it lives here
175
+ * so the CLI, which has no browser to do it, resolves it identically instead
176
+ * of inventing a second, subtly different answer.
177
+ *
178
+ * Handles the overnight wrap and DST — see {@link nextWallClockOccurrenceMs}.
179
+ */
180
+ export declare function resolveWallClockStopRule(at: string, opts?: {
181
+ nowMs?: number;
182
+ timeZone?: string;
183
+ }): {
184
+ ok: true;
185
+ rule: RunWindowStopRule;
186
+ } | {
187
+ ok: false;
188
+ reason: string;
189
+ };
190
+ /**
191
+ * Resolve a stop rule against `nowMs` into absolute quantities. Never throws;
192
+ * every rejection is an `{ ok: false, reason }` value, and every reason is a
193
+ * SENTENCE, because it is rendered verbatim to the operator as the refusal
194
+ * `note` on `POST /api/verse/overnight`.
195
+ */
196
+ export declare function resolveRunWindow(rule: RunWindowStopRule, opts?: {
197
+ nowMs?: number;
198
+ }): ResolveRunWindowResult;
199
+ /**
200
+ * Is the window over? Compares an ABSOLUTE deadline against an ABSOLUTE now,
201
+ * so a process that was suspended across its own end time reports expired on
202
+ * its first look, with a negative `remainingMs`.
203
+ *
204
+ * `iterations` is the count of iterations ALREADY COMPLETED.
205
+ */
206
+ export declare function evaluateRunWindow(window: ResolvedRunWindow, state?: {
207
+ nowMs?: number;
208
+ iterations?: number;
209
+ }): RunWindowEvaluation;
210
+ /**
211
+ * How long a caller may park before it must look at the window again.
212
+ *
213
+ * Never longer than {@link RUN_WINDOW_MAX_PARK_MS}, so a suspended host that
214
+ * wakes past its end time notices within a minute instead of serving out a
215
+ * timer armed before the suspend. Never longer than the time actually left,
216
+ * so the window is not overshot by a park. Never negative.
217
+ */
218
+ export declare function runWindowParkMs(window: ResolvedRunWindow, requestedMs: number, nowMs?: number): number;
@@ -0,0 +1,420 @@
1
+ /**
2
+ * run-window.ts — the BOUNDED RUN WINDOW. Pure maths, no I/O, never throws.
3
+ *
4
+ * ── WHY THIS EXISTS ────────────────────────────────────────────────────────
5
+ * Every scheduler in this repo is relative-elapsed: `Date.now()` deltas and
6
+ * `setTimeout`. Nothing parses a time of day, nothing knows a timezone, and
7
+ * `StartCalendarInterval` appears nowhere — the two launch-trigger allowlists
8
+ * (`daemon/runtime-activation-transaction.ts`, `daemon/resident-service-
9
+ * readiness.ts`) actively REJECT an extra OS trigger and their tests lock that.
10
+ * So an overnight run window cannot be an OS launch trigger. It is IN-PROCESS,
11
+ * and this module is the whole of its arithmetic.
12
+ *
13
+ * Three stop rules, chosen per run:
14
+ *
15
+ * { kind: 'until-paused' } run until the operator parks it
16
+ * { kind: 'until-clock', at: '07:00' } stop at a wall-clock local time
17
+ * { kind: 'iterations', max: 40 } stop after N loop iterations
18
+ *
19
+ * ── THE THINGS A NAIVE CLOCK GETS WRONG ────────────────────────────────────
20
+ *
21
+ * 1. THE MACHINE SLEEPS AND WAKES PAST THE END TIME.
22
+ * A window must NEVER be held as "remaining milliseconds" counted down by
23
+ * elapsed time, and must never be armed as one long `setTimeout`. A laptop
24
+ * suspended at 01:00 and opened at 09:00 fired no timers in between; a
25
+ * single `setTimeout(6h)` scheduled for 07:00 fires at 15:00 on macOS,
26
+ * eight hours of wall-clock too late, and a countdown of elapsed awake time
27
+ * never reaches zero at all. So the window is stored as an ABSOLUTE epoch
28
+ * instant (`endsAtMs`) and every check is `Date.now() >= endsAtMs`. A run
29
+ * that slept through its own end time is expired the first moment it looks,
30
+ * with `reason: 'clock-reached'` and a negative remaining — which is the
31
+ * correct answer, not an error. {@link runWindowParkMs} additionally caps
32
+ * every park at {@link RUN_WINDOW_MAX_PARK_MS} so a woken process re-checks
33
+ * within a minute instead of finishing a stale timer.
34
+ *
35
+ * 2. A STOP TIME THAT IS TOMORROW. The overnight case IS the case: a run
36
+ * started at 23:00 that stops at 07:00 must resolve to TOMORROW's 07:00,
37
+ * not to an instant eight hours in the past. {@link nextWallClockOccurrenceMs}
38
+ * always resolves strictly forward — when today's occurrence is already at
39
+ * or behind `now`, it advances one LOCAL CALENDAR DAY (not `+24h`, which is
40
+ * wrong across a DST transition by exactly the offset change).
41
+ *
42
+ * 3. THE LOCAL TIMEZONE, AND DST. '07:00' means 07:00 where the operator is.
43
+ * Offsets are resolved per-instant from the IANA zone via `Intl`, so a
44
+ * window spanning a DST boundary is 7 or 9 hours of real time as the clock
45
+ * requires, not a fixed 8. A local time that does not exist (the spring-
46
+ * forward gap) resolves to the instant the clock jumps to; a local time
47
+ * that happens twice (the autumn fall-back) resolves to the FIRST of the
48
+ * two. Both are documented choices, not accidents — see
49
+ * {@link wallClockToEpochMs}.
50
+ *
51
+ * This module decides nothing about stopping. It reports that the window is
52
+ * over; `loop.ts` parks the daemon by PAUSING (`~/.ashlr/daemon.paused`), never
53
+ * by `stopDaemon()`, which is `setKill(true)` and would also refuse the agent's
54
+ * own write tools. See `daemon/pause.ts`.
55
+ *
56
+ * No new runtime deps; `Intl` only. Never throws out of a public API.
57
+ */
58
+ /**
59
+ * The longest a caller may park in one go while a window is open. A machine
60
+ * that suspends mid-park wakes with a stale timer; capping the chunk bounds
61
+ * how long a woken process can run past its own end time to one minute.
62
+ * Matches `sleepUntilNextUtcBudgetDay`'s existing 60s chunking in loop.ts.
63
+ */
64
+ export const RUN_WINDOW_MAX_PARK_MS = 60_000;
65
+ // ---------------------------------------------------------------------------
66
+ // Timezone arithmetic
67
+ // ---------------------------------------------------------------------------
68
+ /** The host's IANA zone, or 'UTC' when the runtime cannot say. Never throws. */
69
+ export function hostTimeZone() {
70
+ try {
71
+ const zone = Intl.DateTimeFormat().resolvedOptions().timeZone;
72
+ return typeof zone === 'string' && zone.length > 0 ? zone : 'UTC';
73
+ }
74
+ catch {
75
+ return 'UTC';
76
+ }
77
+ }
78
+ /** True when `timeZone` is a zone this runtime can actually resolve. */
79
+ export function isResolvableTimeZone(timeZone) {
80
+ try {
81
+ new Intl.DateTimeFormat('en-US', { timeZone });
82
+ return true;
83
+ }
84
+ catch {
85
+ return false;
86
+ }
87
+ }
88
+ /**
89
+ * The wall-clock components `instantMs` shows in `timeZone`.
90
+ * Returns null when the zone cannot be resolved.
91
+ */
92
+ function partsInZone(instantMs, timeZone) {
93
+ try {
94
+ const formatter = new Intl.DateTimeFormat('en-US', {
95
+ timeZone,
96
+ hour12: false,
97
+ year: 'numeric',
98
+ month: '2-digit',
99
+ day: '2-digit',
100
+ hour: '2-digit',
101
+ minute: '2-digit',
102
+ second: '2-digit',
103
+ });
104
+ const read = {};
105
+ for (const part of formatter.formatToParts(new Date(instantMs))) {
106
+ if (part.type === 'literal')
107
+ continue;
108
+ const value = Number(part.value);
109
+ if (!Number.isFinite(value))
110
+ continue;
111
+ read[part.type] = value;
112
+ }
113
+ const year = read['year'];
114
+ const month = read['month'];
115
+ const day = read['day'];
116
+ // `hour12: false` yields 24 rather than 0 for midnight in some ICU builds.
117
+ const hour = read['hour'] === 24 ? 0 : read['hour'];
118
+ const minute = read['minute'];
119
+ const second = read['second'];
120
+ if (year === undefined || month === undefined || day === undefined ||
121
+ hour === undefined || minute === undefined || second === undefined) {
122
+ return null;
123
+ }
124
+ return { year, month, day, hour, minute, second };
125
+ }
126
+ catch {
127
+ return null;
128
+ }
129
+ }
130
+ /**
131
+ * The zone's UTC offset (ms) AT a given instant. Positive east of Greenwich.
132
+ * Derived by reading the instant's wall clock in the zone and treating those
133
+ * components as if they were UTC — the difference is the offset in force then,
134
+ * which is what makes this DST-correct rather than fixed per zone.
135
+ */
136
+ function zoneOffsetMsAt(instantMs, timeZone) {
137
+ const parts = partsInZone(instantMs, timeZone);
138
+ if (!parts)
139
+ return null;
140
+ const asIfUtc = Date.UTC(parts.year, parts.month - 1, parts.day, parts.hour, parts.minute, parts.second);
141
+ // Second-truncate the probe so the sub-second remainder does not leak in.
142
+ return asIfUtc - Math.floor(instantMs / 1000) * 1000;
143
+ }
144
+ /**
145
+ * The epoch instant at which `timeZone`'s clock reads the given local
146
+ * date-and-time. Returns null when the zone cannot be resolved.
147
+ *
148
+ * Two passes: guess with the offset in force at the naive-UTC instant, then
149
+ * re-read the offset at the corrected instant and correct again if it changed.
150
+ * That second pass is what makes DST boundaries land correctly.
151
+ *
152
+ * AMBIGUOUS AND NONEXISTENT LOCAL TIMES — both documented, neither an error:
153
+ * - Spring forward (02:30 does not exist): both passes agree on an instant
154
+ * whose clock reads 03:30, i.e. the moment the clock jumps past the request.
155
+ * A window asking to stop at a skipped time stops when that time would have
156
+ * arrived, which is the operator's intent.
157
+ * - Autumn fall-back (01:30 happens twice): resolves to the FIRST occurrence,
158
+ * the earlier instant, so a window never runs an extra hour by surprise.
159
+ * Erring short is the safe direction for a bound on autonomous work.
160
+ */
161
+ export function wallClockToEpochMs(year, month, day, hour, minute, timeZone) {
162
+ const naive = Date.UTC(year, month - 1, day, hour, minute, 0, 0);
163
+ if (!Number.isFinite(naive))
164
+ return null;
165
+ const firstOffset = zoneOffsetMsAt(naive, timeZone);
166
+ if (firstOffset === null)
167
+ return null;
168
+ const firstGuess = naive - firstOffset;
169
+ const secondOffset = zoneOffsetMsAt(firstGuess, timeZone);
170
+ if (secondOffset === null)
171
+ return null;
172
+ if (secondOffset === firstOffset)
173
+ return firstGuess;
174
+ const secondGuess = naive - secondOffset;
175
+ // Fall-back hour: both candidates are real instants reading the requested
176
+ // clock time. Take the earlier one — a bound that errs short, never long.
177
+ const thirdOffset = zoneOffsetMsAt(secondGuess, timeZone);
178
+ if (thirdOffset === secondOffset)
179
+ return Math.min(firstGuess, secondGuess);
180
+ return firstGuess;
181
+ }
182
+ /** Parse 'HH:MM' (24h). Returns null for anything else — no throw, no guess. */
183
+ export function parseWallClockTime(at) {
184
+ if (typeof at !== 'string')
185
+ return null;
186
+ const match = /^([01]\d|2[0-3]):([0-5]\d)$/.exec(at.trim());
187
+ if (!match)
188
+ return null;
189
+ return { hour: Number(match[1]), minute: Number(match[2]) };
190
+ }
191
+ /**
192
+ * The next instant at which `timeZone`'s clock reads `at`, STRICTLY AFTER
193
+ * `nowMs`. This is the overnight wrap: at 23:00 local, '07:00' is tomorrow's
194
+ * 07:00, because today's has already gone.
195
+ *
196
+ * Advances by one LOCAL CALENDAR DAY, never by `+24h` — across a DST boundary
197
+ * those differ by the offset change, and only the calendar-day advance keeps
198
+ * the clock reading the requested time.
199
+ */
200
+ export function nextWallClockOccurrenceMs(at, nowMs, timeZone) {
201
+ const hhmm = parseWallClockTime(at);
202
+ if (!hhmm)
203
+ return null;
204
+ if (!Number.isFinite(nowMs))
205
+ return null;
206
+ const today = partsInZone(nowMs, timeZone);
207
+ if (!today)
208
+ return null;
209
+ const sameDay = wallClockToEpochMs(today.year, today.month, today.day, hhmm.hour, hhmm.minute, timeZone);
210
+ if (sameDay !== null && sameDay > nowMs)
211
+ return sameDay;
212
+ // Already gone today (or landed exactly on now) — take tomorrow's. Date.UTC
213
+ // normalises a day overflow (e.g. the 32nd) into the next month/year for us;
214
+ // we only use it to get the next calendar date, never as an instant.
215
+ const tomorrowProbe = new Date(Date.UTC(today.year, today.month - 1, today.day + 1));
216
+ const nextDay = wallClockToEpochMs(tomorrowProbe.getUTCFullYear(), tomorrowProbe.getUTCMonth() + 1, tomorrowProbe.getUTCDate(), hhmm.hour, hhmm.minute, timeZone);
217
+ if (nextDay !== null && nextDay > nowMs)
218
+ return nextDay;
219
+ return null;
220
+ }
221
+ // ---------------------------------------------------------------------------
222
+ // Resolve
223
+ // ---------------------------------------------------------------------------
224
+ /**
225
+ * The iteration ceiling, matching the client contract's documented 1..500.
226
+ * A bound a typo can turn into "forever" is not a bound.
227
+ */
228
+ export const RUN_WINDOW_MAX_ITERATIONS = 500;
229
+ /**
230
+ * The furthest ahead an `at-time` stop may be armed. A window is a NIGHT, not
231
+ * a standing instruction; an instant six weeks out is a mistake, not a plan.
232
+ */
233
+ export const RUN_WINDOW_MAX_HORIZON_MS = 7 * 24 * 3_600_000;
234
+ /**
235
+ * Turn an operator's wall-clock pick into the contract's absolute `at-time`
236
+ * rule. This is the arithmetic the browser does before it POSTs; it lives here
237
+ * so the CLI, which has no browser to do it, resolves it identically instead
238
+ * of inventing a second, subtly different answer.
239
+ *
240
+ * Handles the overnight wrap and DST — see {@link nextWallClockOccurrenceMs}.
241
+ */
242
+ export function resolveWallClockStopRule(at, opts = {}) {
243
+ const nowMs = opts.nowMs ?? Date.now();
244
+ if (!parseWallClockTime(at)) {
245
+ return { ok: false, reason: `A stop time must look like 'HH:MM' on a 24-hour clock. '${at}' does not.` };
246
+ }
247
+ const timeZone = opts.timeZone ?? hostTimeZone();
248
+ if (!isResolvableTimeZone(timeZone)) {
249
+ return { ok: false, reason: `This machine cannot resolve the timezone '${timeZone}', so '${at}' has no fixed meaning.` };
250
+ }
251
+ const endsAtMs = nextWallClockOccurrenceMs(at, nowMs, timeZone);
252
+ if (endsAtMs === null) {
253
+ return { ok: false, reason: `Could not work out when '${at}' next happens in ${timeZone}.` };
254
+ }
255
+ return { ok: true, rule: { kind: 'at-time', at: new Date(endsAtMs).toISOString() } };
256
+ }
257
+ /**
258
+ * Resolve a stop rule against `nowMs` into absolute quantities. Never throws;
259
+ * every rejection is an `{ ok: false, reason }` value, and every reason is a
260
+ * SENTENCE, because it is rendered verbatim to the operator as the refusal
261
+ * `note` on `POST /api/verse/overnight`.
262
+ */
263
+ export function resolveRunWindow(rule, opts = {}) {
264
+ const nowMs = opts.nowMs ?? Date.now();
265
+ if (!Number.isFinite(nowMs)) {
266
+ return { ok: false, reason: 'This machine could not read its own clock, so a timed run cannot be bounded.' };
267
+ }
268
+ if (rule === null || typeof rule !== 'object') {
269
+ return { ok: false, reason: 'A run needs exactly one stop rule, and none was given.' };
270
+ }
271
+ if (rule.kind === 'until-paused') {
272
+ return {
273
+ ok: true,
274
+ window: {
275
+ kind: 'until-paused',
276
+ startedAtMs: nowMs,
277
+ endsAtMs: null,
278
+ maxIterations: null,
279
+ at: null,
280
+ describe: 'run until paused (~/.ashlr/daemon.paused)',
281
+ },
282
+ };
283
+ }
284
+ if (rule.kind === 'after-iterations') {
285
+ const iterations = rule.iterations;
286
+ if (typeof iterations !== 'number' || !Number.isInteger(iterations) || iterations < 1) {
287
+ return { ok: false, reason: 'An iteration budget must be a whole number of at least 1.' };
288
+ }
289
+ if (iterations > RUN_WINDOW_MAX_ITERATIONS) {
290
+ return {
291
+ ok: false,
292
+ reason: `An iteration budget may be at most ${RUN_WINDOW_MAX_ITERATIONS}; ${iterations} was asked for.`,
293
+ };
294
+ }
295
+ return {
296
+ ok: true,
297
+ window: {
298
+ kind: 'after-iterations',
299
+ startedAtMs: nowMs,
300
+ endsAtMs: null,
301
+ maxIterations: iterations,
302
+ at: null,
303
+ describe: `stop after ${iterations} iteration${iterations === 1 ? '' : 's'}`,
304
+ },
305
+ };
306
+ }
307
+ if (rule.kind === 'at-time') {
308
+ if (typeof rule.at !== 'string' || rule.at.trim().length === 0) {
309
+ return { ok: false, reason: 'A timed run needs an absolute ISO-8601 instant to stop at, and none was given.' };
310
+ }
311
+ const endsAtMs = Date.parse(rule.at);
312
+ if (!Number.isFinite(endsAtMs)) {
313
+ return {
314
+ ok: false,
315
+ reason: `'${rule.at}' is not an ISO-8601 instant. A stop time must be absolute (for example ` +
316
+ `2026-09-24T07:00:00.000Z), not a time of day.`,
317
+ };
318
+ }
319
+ // The client resolves forward before sending, but a request can still
320
+ // arrive stale — a queued POST, a hand-written call, a host whose clock
321
+ // moved. A window that already ended must REFUSE, not run zero iterations
322
+ // and not silently become unbounded.
323
+ if (endsAtMs <= nowMs) {
324
+ const agoMin = ((nowMs - endsAtMs) / 60_000).toFixed(1);
325
+ return {
326
+ ok: false,
327
+ reason: `That stop time (${rule.at}) is ${agoMin} minutes in the past, so the run would end before ` +
328
+ `it began. Pick a time later than now.`,
329
+ };
330
+ }
331
+ if (endsAtMs - nowMs > RUN_WINDOW_MAX_HORIZON_MS) {
332
+ const days = ((endsAtMs - nowMs) / 86_400_000).toFixed(1);
333
+ return {
334
+ ok: false,
335
+ reason: `That stop time is ${days} days away. An unattended run is bounded to at most ` +
336
+ `${RUN_WINDOW_MAX_HORIZON_MS / 86_400_000} days.`,
337
+ };
338
+ }
339
+ const hours = (endsAtMs - nowMs) / 3_600_000;
340
+ return {
341
+ ok: true,
342
+ window: {
343
+ kind: 'at-time',
344
+ startedAtMs: nowMs,
345
+ endsAtMs,
346
+ maxIterations: null,
347
+ at: new Date(endsAtMs).toISOString(),
348
+ describe: `stop at ${new Date(endsAtMs).toISOString()} (in ${hours.toFixed(2)}h)`,
349
+ },
350
+ };
351
+ }
352
+ return {
353
+ ok: false,
354
+ reason: `'${String(rule.kind)}' is not a stop rule this engine knows.`,
355
+ };
356
+ }
357
+ // ---------------------------------------------------------------------------
358
+ // Evaluate
359
+ // ---------------------------------------------------------------------------
360
+ /**
361
+ * Is the window over? Compares an ABSOLUTE deadline against an ABSOLUTE now,
362
+ * so a process that was suspended across its own end time reports expired on
363
+ * its first look, with a negative `remainingMs`.
364
+ *
365
+ * `iterations` is the count of iterations ALREADY COMPLETED.
366
+ */
367
+ export function evaluateRunWindow(window, state = {}) {
368
+ const nowMs = state.nowMs ?? Date.now();
369
+ const iterations = state.iterations ?? 0;
370
+ const remainingIterations = window.maxIterations === null
371
+ ? null
372
+ : window.maxIterations - iterations;
373
+ const remainingMs = window.endsAtMs === null ? null : window.endsAtMs - nowMs;
374
+ if (window.endsAtMs !== null && Number.isFinite(nowMs) && nowMs >= window.endsAtMs) {
375
+ const overshootMs = nowMs - window.endsAtMs;
376
+ return {
377
+ expired: true,
378
+ reason: 'clock-reached',
379
+ remainingMs,
380
+ remainingIterations,
381
+ detail: overshootMs > RUN_WINDOW_MAX_PARK_MS
382
+ ? `run window ended at ${window.at}; ` +
383
+ `noticed ${(overshootMs / 60_000).toFixed(1)} min late (the host was likely asleep)`
384
+ : `run window ended at ${window.at}`,
385
+ };
386
+ }
387
+ if (remainingIterations !== null && remainingIterations <= 0) {
388
+ return {
389
+ expired: true,
390
+ reason: 'iterations-reached',
391
+ remainingMs,
392
+ remainingIterations,
393
+ detail: `run window completed its ${window.maxIterations}-iteration budget`,
394
+ };
395
+ }
396
+ return {
397
+ expired: false,
398
+ reason: null,
399
+ remainingMs,
400
+ remainingIterations,
401
+ detail: window.describe,
402
+ };
403
+ }
404
+ /**
405
+ * How long a caller may park before it must look at the window again.
406
+ *
407
+ * Never longer than {@link RUN_WINDOW_MAX_PARK_MS}, so a suspended host that
408
+ * wakes past its end time notices within a minute instead of serving out a
409
+ * timer armed before the suspend. Never longer than the time actually left,
410
+ * so the window is not overshot by a park. Never negative.
411
+ */
412
+ export function runWindowParkMs(window, requestedMs, nowMs = Date.now()) {
413
+ const requested = Number.isFinite(requestedMs) ? Math.max(0, requestedMs) : 0;
414
+ let park = Math.min(requested, RUN_WINDOW_MAX_PARK_MS);
415
+ if (window.endsAtMs !== null && Number.isFinite(nowMs)) {
416
+ park = Math.min(park, Math.max(0, window.endsAtMs - nowMs));
417
+ }
418
+ return park;
419
+ }
420
+ //# sourceMappingURL=run-window.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-window.js","sourceRoot":"","sources":["../../../src/core/daemon/run-window.ts"],"names":[],"mappings":"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"}