killeros 2.0.19 → 2.0.21

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.
@@ -0,0 +1,407 @@
1
+ import { createHash } from "node:crypto";
2
+ import type { Stats } from "node:fs";
3
+ import { lstat, open, type FileHandle } from "node:fs/promises";
4
+ import path from "node:path";
5
+ import type { GoalBlockerAudit, GoalFileBaseline, GoalFileVerification, GoalState, GoalStateCommon, GoalStatus } from "./runtime.ts";
6
+
7
+ export const GOAL_OBJECTIVE_LIMIT = 4_000;
8
+ export const GOAL_VERSION = 1;
9
+ const FILE_HASH_CHUNK_SIZE = 64 * 1024;
10
+ export const FILE_HASH_LIMIT = 64 * 1024 * 1024;
11
+ type OpenGoalFile = (filePath: string) => Promise<FileHandle>;
12
+ const openGoalFile: OpenGoalFile = (filePath) => open(filePath, "r");
13
+
14
+ export interface GoalTransitionOptions {
15
+ resetBlockedAudit?: boolean;
16
+ resumeAfterManualCompaction?: true;
17
+ blockerAudit?: GoalBlockerAudit;
18
+ }
19
+
20
+ function isGoalStatus(value: unknown): value is GoalStatus {
21
+ return value === "active" || value === "paused" || value === "blocked" || value === "complete";
22
+ }
23
+
24
+ function finiteNonNegative(value: unknown): value is number {
25
+ return typeof value === "number" && Number.isFinite(value) && value >= 0;
26
+ }
27
+
28
+ function isUnknownRecord(value: unknown): value is Record<string, unknown> {
29
+ return typeof value === "object" && value !== null && !Array.isArray(value);
30
+ }
31
+
32
+ function isGoalFileBaseline(value: unknown): value is GoalFileBaseline {
33
+ if (!isUnknownRecord(value)) return false;
34
+ if (value.exists === false) {
35
+ return value.size === undefined && value.mtimeMs === undefined && value.contentHash === undefined;
36
+ }
37
+ return value.exists === true
38
+ && finiteNonNegative(value.size)
39
+ && finiteNonNegative(value.mtimeMs)
40
+ && (value.contentHash === undefined
41
+ || value.contentHash === null
42
+ || typeof value.contentHash === "string" && /^[a-f0-9]{64}$/u.test(value.contentHash));
43
+ }
44
+
45
+ function isAbsoluteFilePath(value: string): boolean {
46
+ if (!value || /^(?:https?|file):\/\//iu.test(value) || /[\\\/]$/u.test(value)) return false;
47
+ return path.isAbsolute(value) || path.win32.isAbsolute(value);
48
+ }
49
+
50
+ function isGoalFileVerification(value: unknown): value is GoalFileVerification {
51
+ return isUnknownRecord(value)
52
+ && value.kind === "file"
53
+ && typeof value.path === "string"
54
+ && value.path === value.path.trim()
55
+ && isAbsoluteFilePath(value.path)
56
+ && isGoalFileBaseline(value.baseline);
57
+ }
58
+
59
+ function isGoalBlockerAudit(value: unknown, turns: number, status: GoalStatus): value is GoalBlockerAudit {
60
+ if (!isUnknownRecord(value)
61
+ || typeof value.key !== "string"
62
+ || !/^[a-z0-9][a-z0-9._-]{0,119}$/u.test(value.key)
63
+ || typeof value.streak !== "number" || !Number.isInteger(value.streak) || value.streak < 1 || value.streak > 3
64
+ || typeof value.lastTurn !== "number" || !Number.isInteger(value.lastTurn) || value.lastTurn < 1 || value.lastTurn > turns) {
65
+ return false;
66
+ }
67
+ if (status === "complete") return false;
68
+ return status === "blocked" ? value.streak === 3 : value.streak < 3;
69
+ }
70
+
71
+ export function parseGoalState(value: unknown): GoalState | undefined {
72
+ if (!isUnknownRecord(value)) return undefined;
73
+ const {
74
+ version,
75
+ revision,
76
+ objective,
77
+ status,
78
+ createdAt,
79
+ updatedAt,
80
+ activeMilliseconds,
81
+ activeStartedAt,
82
+ turns,
83
+ blockedAuditStartTurn,
84
+ baselineTokens,
85
+ result,
86
+ resumeAfterManualCompaction,
87
+ blockerAudit,
88
+ verification,
89
+ } = value;
90
+ if (version !== GOAL_VERSION
91
+ || typeof revision !== "number" || !Number.isInteger(revision) || revision < 1
92
+ || typeof objective !== "string" || !objective.trim() || [...objective].length > GOAL_OBJECTIVE_LIMIT
93
+ || !isGoalStatus(status)
94
+ || !finiteNonNegative(createdAt)
95
+ || !finiteNonNegative(updatedAt)
96
+ || !finiteNonNegative(activeMilliseconds)
97
+ || typeof turns !== "number" || !Number.isInteger(turns) || turns < 0
98
+ || blockedAuditStartTurn !== undefined
99
+ && (typeof blockedAuditStartTurn !== "number" || !Number.isInteger(blockedAuditStartTurn)
100
+ || blockedAuditStartTurn < 0 || blockedAuditStartTurn > turns)
101
+ || !finiteNonNegative(baselineTokens)
102
+ || result !== undefined && typeof result !== "string"
103
+ || verification !== undefined && !isGoalFileVerification(verification)
104
+ || resumeAfterManualCompaction !== undefined && resumeAfterManualCompaction !== true
105
+ || blockerAudit !== undefined && !isGoalBlockerAudit(blockerAudit, turns, status)) {
106
+ return undefined;
107
+ }
108
+
109
+ const common: GoalStateCommon = {
110
+ version: GOAL_VERSION,
111
+ revision,
112
+ objective: objective.trim(),
113
+ createdAt,
114
+ updatedAt,
115
+ activeMilliseconds,
116
+ turns,
117
+ blockedAuditStartTurn: blockedAuditStartTurn ?? 0,
118
+ baselineTokens,
119
+ ...(verification === undefined ? {} : { verification }),
120
+ };
121
+ switch (status) {
122
+ case "active":
123
+ if (!finiteNonNegative(activeStartedAt) || resumeAfterManualCompaction !== undefined) return undefined;
124
+ return {
125
+ ...common,
126
+ status,
127
+ activeStartedAt,
128
+ ...(result === undefined ? {} : { result }),
129
+ ...(blockerAudit === undefined ? {} : { blockerAudit }),
130
+ };
131
+ case "paused":
132
+ if (activeStartedAt !== undefined) return undefined;
133
+ return {
134
+ ...common,
135
+ status,
136
+ ...(result === undefined ? {} : { result }),
137
+ ...(blockerAudit === undefined ? {} : { blockerAudit }),
138
+ ...(resumeAfterManualCompaction === undefined ? {} : { resumeAfterManualCompaction }),
139
+ };
140
+ case "blocked":
141
+ if (activeStartedAt !== undefined || resumeAfterManualCompaction !== undefined || typeof result !== "string") return undefined;
142
+ return { ...common, status, result, ...(blockerAudit === undefined ? {} : { blockerAudit }) };
143
+ case "complete":
144
+ if (activeStartedAt !== undefined || resumeAfterManualCompaction !== undefined
145
+ || typeof result !== "string" || blockerAudit !== undefined) return undefined;
146
+ return { ...common, status, result };
147
+ }
148
+ }
149
+
150
+ function sameFile(left: Stats, right: Stats): boolean {
151
+ return left.dev === right.dev
152
+ && left.ino === right.ino
153
+ && left.size === right.size
154
+ && left.mtimeMs === right.mtimeMs;
155
+ }
156
+
157
+ async function hashFile(handle: FileHandle, inspected: Stats): Promise<string> {
158
+ const hash = createHash("sha256");
159
+ const buffer = Buffer.allocUnsafe(FILE_HASH_CHUNK_SIZE);
160
+ let position = 0;
161
+ while (position < inspected.size) {
162
+ const length = Math.min(buffer.length, inspected.size - position);
163
+ const { bytesRead } = await handle.read(buffer, 0, length, position);
164
+ if (bytesRead === 0) throw new Error("Goal deliverable changed while it was being inspected");
165
+ hash.update(buffer.subarray(0, bytesRead));
166
+ position += bytesRead;
167
+ }
168
+ if (!sameFile(inspected, await handle.stat())) {
169
+ throw new Error("Goal deliverable changed while it was being inspected");
170
+ }
171
+ return hash.digest("hex");
172
+ }
173
+
174
+ /** Captures a file baseline with bounded asynchronous I/O and descriptor identity checks. */
175
+ export async function captureGoalFileBaseline(
176
+ filePath: string,
177
+ openFile: OpenGoalFile = openGoalFile,
178
+ ): Promise<GoalFileBaseline> {
179
+ let inspected: Stats;
180
+ try {
181
+ inspected = await lstat(filePath);
182
+ } catch (error) {
183
+ if (isUnknownRecord(error) && error.code === "ENOENT") return { exists: false };
184
+ throw error;
185
+ }
186
+ const baseline = { exists: true as const, size: inspected.size, mtimeMs: inspected.mtimeMs };
187
+ if (!inspected.isFile() || inspected.size > FILE_HASH_LIMIT) return baseline;
188
+
189
+ let handle: FileHandle | undefined;
190
+ try {
191
+ handle = await openFile(filePath);
192
+ if (!sameFile(inspected, await handle.stat())) {
193
+ throw new Error("Goal deliverable changed while it was being inspected");
194
+ }
195
+ return { ...baseline, contentHash: await hashFile(handle, inspected) };
196
+ } catch (error) {
197
+ if (error instanceof Error && error.message === "Goal deliverable changed while it was being inspected") throw error;
198
+ return { ...baseline, contentHash: null };
199
+ } finally {
200
+ await handle?.close();
201
+ }
202
+ }
203
+
204
+ /** Captures one explicit absolute output path so goal completion can verify its creation or modification. */
205
+ export async function inferGoalVerification(objective: string): Promise<GoalFileVerification | undefined> {
206
+ const destination = /\b(?:create|write|save|generate)\b[^\r\n]{0,160}?\b(?:file|document|markdown|report|spreadsheet|presentation|image)\b\s+(?:to|at|as|destination(?:\s+is)?|output(?:\s+(?:to|at))?)\b\s*(?:`([^`\r\n]+)`|"([^"\r\n]+)"|'([^'\r\n]+)'|([A-Za-z]:\\[^\s,;]+|\/[^\s,;]+))/giu;
207
+ const paths = [...objective.matchAll(destination)]
208
+ .map((match) => (match[1] ?? match[2] ?? match[3] ?? match[4] ?? "").trim())
209
+ .filter(isAbsoluteFilePath);
210
+ const unique = [...new Set(paths)];
211
+ const filePath = unique.length === 1 ? unique[0] : undefined;
212
+ return filePath ? { kind: "file", path: filePath, baseline: await captureGoalFileBaseline(filePath) } : undefined;
213
+ }
214
+
215
+ export async function verifyGoalDeliverable(verification: GoalFileVerification): Promise<void> {
216
+ let artifact: Stats;
217
+ try {
218
+ artifact = await lstat(verification.path);
219
+ } catch {
220
+ throw new Error(`Goal deliverable is not a regular file at the required path: ${verification.path}`);
221
+ }
222
+ if (!artifact.isFile()) {
223
+ throw new Error(`Goal deliverable is not a regular file at the required path: ${verification.path}`);
224
+ }
225
+ if (!verification.baseline.exists) return;
226
+ if (verification.baseline.contentHash === null) {
227
+ throw new Error(`Goal deliverable content cannot be verified: ${verification.path}`);
228
+ }
229
+ if (verification.baseline.contentHash !== undefined) {
230
+ const current = await captureGoalFileBaseline(verification.path);
231
+ if (!current.exists || current.contentHash === null) {
232
+ throw new Error(`Goal deliverable content cannot be verified: ${verification.path}`);
233
+ }
234
+ if (current.contentHash === verification.baseline.contentHash) {
235
+ throw new Error(`Goal deliverable has not changed since the goal started: ${verification.path}`);
236
+ }
237
+ }
238
+ if (verification.baseline.contentHash === undefined
239
+ && artifact.size === verification.baseline.size
240
+ && artifact.mtimeMs === verification.baseline.mtimeMs) {
241
+ throw new Error(`Goal deliverable has not changed since the goal started: ${verification.path}`);
242
+ }
243
+ }
244
+
245
+ export function validateGoalObjective(input: string): string | undefined {
246
+ const objective = input.trim();
247
+ if (!objective) return undefined;
248
+ return [...objective].length <= GOAL_OBJECTIVE_LIMIT ? objective : undefined;
249
+ }
250
+
251
+ export function goalElapsedMilliseconds(state: GoalState, now: number): number {
252
+ const activeInterval = state.status === "active" ? Math.max(0, now - state.activeStartedAt) : 0;
253
+ return state.activeMilliseconds + activeInterval;
254
+ }
255
+
256
+ export function commonGoalState(state: GoalState): GoalStateCommon {
257
+ return {
258
+ version: state.version,
259
+ revision: state.revision,
260
+ objective: state.objective,
261
+ createdAt: state.createdAt,
262
+ updatedAt: state.updatedAt,
263
+ activeMilliseconds: state.activeMilliseconds,
264
+ turns: state.turns,
265
+ blockedAuditStartTurn: state.blockedAuditStartTurn,
266
+ baselineTokens: state.baselineTokens,
267
+ ...(state.verification === undefined ? {} : { verification: state.verification }),
268
+ };
269
+ }
270
+
271
+ export function stopGoalClock(state: GoalState, now: number): GoalStateCommon {
272
+ const common = commonGoalState(state);
273
+ return state.status === "active"
274
+ ? { ...common, activeMilliseconds: common.activeMilliseconds + Math.max(0, now - state.activeStartedAt) }
275
+ : common;
276
+ }
277
+
278
+ export function createNewGoalState(
279
+ objective: string,
280
+ baselineTokens: number,
281
+ verification: GoalFileVerification | undefined,
282
+ now: number,
283
+ ): GoalState {
284
+ return {
285
+ version: GOAL_VERSION,
286
+ revision: 1,
287
+ objective,
288
+ status: "active",
289
+ createdAt: now,
290
+ updatedAt: now,
291
+ activeMilliseconds: 0,
292
+ activeStartedAt: now,
293
+ turns: 0,
294
+ blockedAuditStartTurn: 0,
295
+ baselineTokens,
296
+ ...(verification === undefined ? {} : { verification }),
297
+ };
298
+ }
299
+
300
+ export function editGoalState(
301
+ state: GoalState,
302
+ objective: string,
303
+ verification: GoalFileVerification | undefined,
304
+ now: number,
305
+ ): GoalState {
306
+ const current = stopGoalClock(state, now);
307
+ const { verification: _previousVerification, ...common } = current;
308
+ return {
309
+ ...common,
310
+ revision: current.revision + 1,
311
+ objective,
312
+ status: "active",
313
+ updatedAt: now,
314
+ activeStartedAt: now,
315
+ blockedAuditStartTurn: current.turns,
316
+ ...(verification === undefined ? {} : { verification }),
317
+ };
318
+ }
319
+
320
+ export function beginGoalTurnState(
321
+ current: Extract<GoalState, { status: "active" }>,
322
+ now: number,
323
+ ): GoalState {
324
+ return { ...current, revision: current.revision + 1, turns: current.turns + 1, updatedAt: now };
325
+ }
326
+
327
+ export function checkpointActiveGoalState(
328
+ current: Extract<GoalState, { status: "active" }>,
329
+ now: number,
330
+ ): GoalState {
331
+ return {
332
+ ...stopGoalClock(current, now),
333
+ revision: current.revision + 1,
334
+ status: "active",
335
+ updatedAt: now,
336
+ activeStartedAt: now,
337
+ ...(current.result === undefined ? {} : { result: current.result }),
338
+ ...(current.blockerAudit === undefined ? {} : { blockerAudit: current.blockerAudit }),
339
+ };
340
+ }
341
+
342
+ export function pauseGoalState(
343
+ current: GoalState,
344
+ result: string | undefined,
345
+ now: number,
346
+ resumeAfterManualCompaction = false,
347
+ ): GoalState {
348
+ const common = stopGoalClock(current, now);
349
+ return {
350
+ ...common,
351
+ status: "paused",
352
+ ...(result === undefined ? {} : { result }),
353
+ ...(current.blockerAudit === undefined ? {} : { blockerAudit: current.blockerAudit }),
354
+ ...(resumeAfterManualCompaction ? { resumeAfterManualCompaction: true as const } : {}),
355
+ };
356
+ }
357
+
358
+ export function checkpointPausedGoalState(
359
+ current: Extract<GoalState, { status: "paused" }>,
360
+ now: number,
361
+ ): GoalState {
362
+ const { resumeAfterManualCompaction: _resume, ...paused } = current;
363
+ return { ...paused, revision: paused.revision + 1, updatedAt: now };
364
+ }
365
+
366
+ export function recordGoalBlockerAudit(
367
+ state: Extract<GoalState, { status: "active" }>,
368
+ blockerAudit: GoalBlockerAudit,
369
+ now: number,
370
+ ): GoalState {
371
+ return { ...state, revision: state.revision + 1, updatedAt: now, blockerAudit };
372
+ }
373
+
374
+ export function transitionGoalState(
375
+ current: GoalState,
376
+ status: GoalStatus,
377
+ result: string | undefined,
378
+ options: GoalTransitionOptions,
379
+ now: number,
380
+ ): GoalState {
381
+ const stopped = stopGoalClock(current, now);
382
+ const common: GoalStateCommon = {
383
+ ...stopped,
384
+ revision: stopped.revision + 1,
385
+ updatedAt: now,
386
+ blockedAuditStartTurn: options.resetBlockedAudit ? stopped.turns : stopped.blockedAuditStartTurn,
387
+ };
388
+ const blockerAudit = options.resetBlockedAudit ? undefined : options.blockerAudit ?? current.blockerAudit;
389
+ switch (status) {
390
+ case "active":
391
+ return { ...common, status, activeStartedAt: now, ...(blockerAudit === undefined ? {} : { blockerAudit }) };
392
+ case "paused":
393
+ return {
394
+ ...common,
395
+ status,
396
+ ...(result === undefined ? {} : { result }),
397
+ ...(blockerAudit === undefined ? {} : { blockerAudit }),
398
+ ...(options.resumeAfterManualCompaction === undefined ? {} : { resumeAfterManualCompaction: true }),
399
+ };
400
+ case "blocked":
401
+ if (result === undefined) throw new Error("A blocked goal requires a result");
402
+ return { ...common, status, result, ...(blockerAudit === undefined ? {} : { blockerAudit }) };
403
+ case "complete":
404
+ if (result === undefined) throw new Error("A complete goal requires a result");
405
+ return { ...common, status, result };
406
+ }
407
+ }