@isparling/engram-cli 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.
@@ -0,0 +1,1493 @@
1
+ import { constants, realpathSync } from "node:fs";
2
+ import { chmod, lstat, link, mkdir, open, readFile, readdir, readlink, realpath, rename, rm, symlink, unlink, writeFile } from "node:fs/promises";
3
+ import { createHash, randomUUID } from "node:crypto";
4
+ import { homedir, hostname } from "node:os";
5
+ import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
6
+ import { gunzipSync } from "node:zlib";
7
+ import { fileURLToPath } from "node:url";
8
+
9
+ export const RELEASE_SCHEMA_VERSION = 0;
10
+ export const RELEASE_FORMAT_VERSION = 0;
11
+ export const PACKAGING_PROCEDURE_VERSION = "r0-source-ustar-v1";
12
+
13
+ export type ReleaseFileIntegrity = {
14
+ path: string;
15
+ byte_length: number;
16
+ sha256: string;
17
+ executable: boolean;
18
+ };
19
+
20
+ export type ReleaseArtifactIntegrity = {
21
+ filename: string;
22
+ byte_length: number;
23
+ sha256: string;
24
+ };
25
+
26
+ type ReleasePack = {
27
+ id: string;
28
+ version: string;
29
+ };
30
+
31
+ type ReleaseQmdCompatibility = {
32
+ contract: "scoped-cli";
33
+ version: string;
34
+ };
35
+
36
+ type ReleaseEnvironmentCompatibility = {
37
+ platform: "darwin";
38
+ architecture: "arm64";
39
+ node_version: string;
40
+ };
41
+
42
+ type ReleaseVerification = {
43
+ command: string;
44
+ outcome: "passed" | "not_applicable";
45
+ mode: "automated" | "manual";
46
+ artifact_sha256: string;
47
+ };
48
+
49
+ export type ReleaseManifest = {
50
+ schema_version: typeof RELEASE_SCHEMA_VERSION;
51
+ release_format: typeof RELEASE_FORMAT_VERSION;
52
+ version: string;
53
+ source_revision: string;
54
+ packaging_procedure_version: typeof PACKAGING_PROCEDURE_VERSION;
55
+ host_agent_compatibility: "host-neutral-cli-schema-0";
56
+ qmd_compatibility: ReleaseQmdCompatibility;
57
+ knowledge_schema_compatibility: ["0"];
58
+ pack_api_compatibility: 0;
59
+ environment_compatibility: ReleaseEnvironmentCompatibility;
60
+ included_packs: ReleasePack[];
61
+ files: ReleaseFileIntegrity[];
62
+ };
63
+
64
+ export type ReleaseRecord = {
65
+ schema_version: typeof RELEASE_SCHEMA_VERSION;
66
+ version: string;
67
+ source_revision: string;
68
+ packaging_procedure_version: typeof PACKAGING_PROCEDURE_VERSION;
69
+ host_agent_compatibility: "host-neutral-cli-schema-0";
70
+ qmd_compatibility: ReleaseQmdCompatibility;
71
+ knowledge_schema_compatibility: ["0"];
72
+ pack_api_compatibility: 0;
73
+ environment_compatibility: ReleaseEnvironmentCompatibility;
74
+ included_packs: ReleasePack[];
75
+ included_beads: string[];
76
+ verification_summary: ReleaseVerification[];
77
+ known_limitations: string[];
78
+ artifact_integrity: {
79
+ archive: ReleaseArtifactIntegrity;
80
+ bootstrap: ReleaseArtifactIntegrity;
81
+ };
82
+ published_at: string;
83
+ };
84
+
85
+ export type ReleaseErrorCode =
86
+ | "release_manifest_invalid"
87
+ | "release_record_invalid"
88
+ | "release_id_invalid"
89
+ | "host_agent_compatibility_invalid"
90
+ | "release_path_invalid"
91
+ | "release_path_duplicate"
92
+ | "files_order_invalid"
93
+ | "included_packs_order_invalid"
94
+ | "known_limitations_invalid"
95
+ | "verification_artifact_mismatch"
96
+ | "release_incompatible"
97
+ | "release_boundary_unsafe"
98
+ | "artifact_integrity_mismatch"
99
+ | "archive_unsafe"
100
+ | "archive_inventory_mismatch"
101
+ | "release_identity_mismatch"
102
+ | "release_exists"
103
+ | "install_lock_conflict"
104
+ | "install_lock_owner_unverifiable"
105
+ | "install_failed"
106
+ | "selection_target_unknown"
107
+ | "selection_target_linked"
108
+ | "selection_target_invalid"
109
+ | "selection_target_incompatible"
110
+ | "launcher_conflict"
111
+ | "current_absent";
112
+
113
+ export type ReleaseError = {
114
+ code: ReleaseErrorCode;
115
+ message: string;
116
+ field?: string;
117
+ detail?: string;
118
+ };
119
+
120
+ export type ReleaseResult<T> =
121
+ | { ok: true; value: T }
122
+ | { ok: false; errors: ReleaseError[] };
123
+
124
+ type ErrorList = ReleaseError[];
125
+
126
+ function isRecord(value: unknown): value is Record<string, unknown> {
127
+ return typeof value === "object" && value !== null && !Array.isArray(value);
128
+ }
129
+
130
+ function addError(errors: ErrorList, code: ReleaseErrorCode, field: string): void {
131
+ errors.push({ code, message: `${field} is invalid`, field });
132
+ }
133
+
134
+ function failed<T>(code: ReleaseErrorCode, field: string): ReleaseResult<T> {
135
+ return { ok: false, errors: [{ code, message: `${field} is invalid`, field }] };
136
+ }
137
+
138
+ function hasExactKeys(raw: Record<string, unknown>, keys: readonly string[], errors: ErrorList, code: ReleaseErrorCode): void {
139
+ const actualKeys = Object.keys(raw).sort();
140
+ const expectedKeys = [...keys].sort();
141
+ if (actualKeys.length !== expectedKeys.length || actualKeys.some((key, index) => key !== expectedKeys[index])) {
142
+ addError(errors, code, "top_level_keys");
143
+ }
144
+ }
145
+
146
+ function singleLineString(raw: unknown, field: string, errors: ErrorList, code: ReleaseErrorCode): string | undefined {
147
+ if (typeof raw !== "string" || raw.length === 0 || raw.includes("\n") || raw.includes("\r")) {
148
+ addError(errors, code, field);
149
+ return undefined;
150
+ }
151
+ return raw;
152
+ }
153
+
154
+ function nonNegativeInteger(raw: unknown, field: string, errors: ErrorList, code: ReleaseErrorCode): number | undefined {
155
+ if (typeof raw !== "number" || !Number.isSafeInteger(raw) || raw < 0) {
156
+ addError(errors, code, field);
157
+ return undefined;
158
+ }
159
+ return raw;
160
+ }
161
+
162
+ function sha256(raw: unknown, field: string, errors: ErrorList, code: ReleaseErrorCode): string | undefined {
163
+ const value = singleLineString(raw, field, errors, code);
164
+ if (value === undefined) return undefined;
165
+ if (!/^[a-f0-9]{64}$/.test(value)) {
166
+ addError(errors, code, field);
167
+ return undefined;
168
+ }
169
+ return value;
170
+ }
171
+
172
+ function safeRelativePath(raw: unknown, field: string, errors: ErrorList, code: ReleaseErrorCode): string | undefined {
173
+ const value = singleLineString(raw, field, errors, code);
174
+ if (value === undefined) return undefined;
175
+ const segments = value.split("/");
176
+ if (
177
+ isAbsolute(value) ||
178
+ value.includes("\\") ||
179
+ segments.some((segment) => segment.length === 0 || segment === "." || segment === "..")
180
+ ) {
181
+ addError(errors, "release_path_invalid", field);
182
+ return undefined;
183
+ }
184
+ return value;
185
+ }
186
+
187
+ function parseReleaseIdentity(raw: Record<string, unknown>, errors: ErrorList, code: ReleaseErrorCode): { version: string; source_revision: string } | undefined {
188
+ const sourceRevision = singleLineString(raw.source_revision, "source_revision", errors, code);
189
+ const version = singleLineString(raw.version, "version", errors, code);
190
+ if (sourceRevision === undefined || version === undefined) return undefined;
191
+ if (!/^[a-f0-9]{40}$/.test(sourceRevision) || version !== `r0-${sourceRevision}`) {
192
+ addError(errors, "release_id_invalid", "version");
193
+ return undefined;
194
+ }
195
+ return { version, source_revision: sourceRevision };
196
+ }
197
+
198
+ function parseQmdCompatibility(raw: unknown, errors: ErrorList, code: ReleaseErrorCode): ReleaseQmdCompatibility | undefined {
199
+ if (!isRecord(raw)) {
200
+ addError(errors, code, "qmd_compatibility");
201
+ return undefined;
202
+ }
203
+ hasExactKeys(raw, ["contract", "version"], errors, code);
204
+ const contract = singleLineString(raw.contract, "qmd_compatibility.contract", errors, code);
205
+ const version = singleLineString(raw.version, "qmd_compatibility.version", errors, code);
206
+ if (contract !== "scoped-cli") addError(errors, code, "qmd_compatibility.contract");
207
+ if (contract !== "scoped-cli" || version === undefined) return undefined;
208
+ return { contract, version };
209
+ }
210
+
211
+ function parseKnowledgeSchemaCompatibility(raw: unknown, errors: ErrorList, code: ReleaseErrorCode): ["0"] | undefined {
212
+ if (!Array.isArray(raw) || raw.length !== 1 || raw[0] !== "0") {
213
+ addError(errors, code, "knowledge_schema_compatibility");
214
+ return undefined;
215
+ }
216
+ return ["0"];
217
+ }
218
+
219
+ function parseEnvironmentCompatibility(raw: unknown, errors: ErrorList, code: ReleaseErrorCode): ReleaseEnvironmentCompatibility | undefined {
220
+ if (!isRecord(raw)) {
221
+ addError(errors, code, "environment_compatibility");
222
+ return undefined;
223
+ }
224
+ hasExactKeys(raw, ["platform", "architecture", "node_version"], errors, code);
225
+ const platform = singleLineString(raw.platform, "environment_compatibility.platform", errors, code);
226
+ const architecture = singleLineString(raw.architecture, "environment_compatibility.architecture", errors, code);
227
+ const nodeVersion = singleLineString(raw.node_version, "environment_compatibility.node_version", errors, code);
228
+ if (platform !== "darwin") addError(errors, code, "environment_compatibility.platform");
229
+ if (architecture !== "arm64") addError(errors, code, "environment_compatibility.architecture");
230
+ if (nodeVersion !== process.version) addError(errors, code, "environment_compatibility.node_version");
231
+ if (platform !== "darwin" || architecture !== "arm64" || nodeVersion !== process.version) return undefined;
232
+ return { platform, architecture, node_version: nodeVersion };
233
+ }
234
+
235
+ function parseIncludedPacks(raw: unknown, errors: ErrorList, code: ReleaseErrorCode): ReleasePack[] | undefined {
236
+ if (!Array.isArray(raw)) {
237
+ addError(errors, code, "included_packs");
238
+ return undefined;
239
+ }
240
+ const packs: ReleasePack[] = [];
241
+ let valid = true;
242
+ for (let index = 0; index < raw.length; index += 1) {
243
+ const entry = raw[index];
244
+ const field = `included_packs.${index}`;
245
+ if (!isRecord(entry)) {
246
+ addError(errors, code, field);
247
+ valid = false;
248
+ continue;
249
+ }
250
+ hasExactKeys(entry, ["id", "version"], errors, code);
251
+ const id = singleLineString(entry.id, `${field}.id`, errors, code);
252
+ const version = singleLineString(entry.version, `${field}.version`, errors, code);
253
+ if (id === undefined || version === undefined || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(id)) {
254
+ if (id !== undefined && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(id)) addError(errors, code, `${field}.id`);
255
+ valid = false;
256
+ continue;
257
+ }
258
+ packs.push({ id, version });
259
+ }
260
+ for (let index = 1; index < packs.length; index += 1) {
261
+ const previous = packs[index - 1];
262
+ const current = packs[index];
263
+ if (previous === undefined || current === undefined) continue;
264
+ if (previous.id >= current.id) {
265
+ addError(errors, "included_packs_order_invalid", "included_packs");
266
+ valid = false;
267
+ break;
268
+ }
269
+ }
270
+ return valid ? packs : undefined;
271
+ }
272
+
273
+ function parseFiles(raw: unknown, errors: ErrorList, code: ReleaseErrorCode): ReleaseFileIntegrity[] | undefined {
274
+ if (!Array.isArray(raw)) {
275
+ addError(errors, code, "files");
276
+ return undefined;
277
+ }
278
+ const files: ReleaseFileIntegrity[] = [];
279
+ let valid = true;
280
+ const seen = new Set<string>();
281
+ for (let index = 0; index < raw.length; index += 1) {
282
+ const entry = raw[index];
283
+ const field = `files.${index}`;
284
+ if (!isRecord(entry)) {
285
+ addError(errors, code, field);
286
+ valid = false;
287
+ continue;
288
+ }
289
+ hasExactKeys(entry, ["path", "byte_length", "sha256", "executable"], errors, code);
290
+ const path = safeRelativePath(entry.path, `${field}.path`, errors, code);
291
+ const byteLength = nonNegativeInteger(entry.byte_length, `${field}.byte_length`, errors, code);
292
+ const hash = sha256(entry.sha256, `${field}.sha256`, errors, code);
293
+ const executable = entry.executable;
294
+ if (typeof executable !== "boolean") addError(errors, code, `${field}.executable`);
295
+ if (path === undefined || byteLength === undefined || hash === undefined || typeof executable !== "boolean") {
296
+ valid = false;
297
+ continue;
298
+ }
299
+ if (seen.has(path)) {
300
+ addError(errors, "release_path_duplicate", path);
301
+ valid = false;
302
+ }
303
+ seen.add(path);
304
+ files.push({ path, byte_length: byteLength, sha256: hash, executable });
305
+ }
306
+ for (let index = 1; index < files.length; index += 1) {
307
+ const previous = files[index - 1];
308
+ const current = files[index];
309
+ if (previous === undefined || current === undefined) continue;
310
+ if (previous.path >= current.path) {
311
+ addError(errors, "files_order_invalid", "files");
312
+ valid = false;
313
+ break;
314
+ }
315
+ }
316
+ return valid ? files : undefined;
317
+ }
318
+
319
+ function parseArtifactIntegrity(raw: unknown, field: string, errors: ErrorList, code: ReleaseErrorCode): ReleaseArtifactIntegrity | undefined {
320
+ if (!isRecord(raw)) {
321
+ addError(errors, code, field);
322
+ return undefined;
323
+ }
324
+ hasExactKeys(raw, ["filename", "byte_length", "sha256"], errors, code);
325
+ const filename = safeRelativePath(raw.filename, `${field}.filename`, errors, code);
326
+ const byteLength = nonNegativeInteger(raw.byte_length, `${field}.byte_length`, errors, code);
327
+ const hash = sha256(raw.sha256, `${field}.sha256`, errors, code);
328
+ if (filename === undefined || byteLength === undefined || hash === undefined) return undefined;
329
+ return { filename, byte_length: byteLength, sha256: hash };
330
+ }
331
+
332
+ function parseStringArray(raw: unknown, field: string, errors: ErrorList, code: ReleaseErrorCode): string[] | undefined {
333
+ if (!Array.isArray(raw)) {
334
+ addError(errors, code, field);
335
+ return undefined;
336
+ }
337
+ const values: string[] = [];
338
+ let valid = true;
339
+ for (let index = 0; index < raw.length; index += 1) {
340
+ const value = singleLineString(raw[index], `${field}.${index}`, errors, code);
341
+ if (value === undefined) {
342
+ valid = false;
343
+ continue;
344
+ }
345
+ values.push(value);
346
+ }
347
+ return valid ? values : undefined;
348
+ }
349
+
350
+ function parseVerificationSummary(raw: unknown, archiveHash: string | undefined, errors: ErrorList, code: ReleaseErrorCode): ReleaseVerification[] | undefined {
351
+ if (!Array.isArray(raw)) {
352
+ addError(errors, code, "verification_summary");
353
+ return undefined;
354
+ }
355
+ const entries: ReleaseVerification[] = [];
356
+ let valid = true;
357
+ for (let index = 0; index < raw.length; index += 1) {
358
+ const entry = raw[index];
359
+ const field = `verification_summary.${index}`;
360
+ if (!isRecord(entry)) {
361
+ addError(errors, code, field);
362
+ valid = false;
363
+ continue;
364
+ }
365
+ hasExactKeys(entry, ["command", "outcome", "mode", "artifact_sha256"], errors, code);
366
+ const command = singleLineString(entry.command, `${field}.command`, errors, code);
367
+ const outcome = entry.outcome;
368
+ const mode = entry.mode;
369
+ const artifactHash = sha256(entry.artifact_sha256, `${field}.artifact_sha256`, errors, code);
370
+ if (outcome !== "passed" && outcome !== "not_applicable") addError(errors, code, `${field}.outcome`);
371
+ if (mode !== "automated" && mode !== "manual") addError(errors, code, `${field}.mode`);
372
+ if (artifactHash !== undefined && archiveHash !== undefined && artifactHash !== archiveHash) {
373
+ addError(errors, "verification_artifact_mismatch", `${field}.artifact_sha256`);
374
+ valid = false;
375
+ }
376
+ if (
377
+ command === undefined ||
378
+ artifactHash === undefined ||
379
+ (outcome !== "passed" && outcome !== "not_applicable") ||
380
+ (mode !== "automated" && mode !== "manual")
381
+ ) {
382
+ valid = false;
383
+ continue;
384
+ }
385
+ entries.push({ command, outcome, mode, artifact_sha256: artifactHash });
386
+ }
387
+ return valid ? entries : undefined;
388
+ }
389
+
390
+ function parseCommon(raw: Record<string, unknown>, errors: ErrorList, code: ReleaseErrorCode): {
391
+ identity: { version: string; source_revision: string } | undefined;
392
+ packagingProcedureVersion: typeof PACKAGING_PROCEDURE_VERSION | undefined;
393
+ hostAgentCompatibility: "host-neutral-cli-schema-0" | undefined;
394
+ qmdCompatibility: ReleaseQmdCompatibility | undefined;
395
+ knowledgeSchemaCompatibility: ["0"] | undefined;
396
+ packApiCompatibility: 0 | undefined;
397
+ environmentCompatibility: ReleaseEnvironmentCompatibility | undefined;
398
+ includedPacks: ReleasePack[] | undefined;
399
+ } {
400
+ const identity = parseReleaseIdentity(raw, errors, code);
401
+ const packagingProcedureVersion = raw.packaging_procedure_version === PACKAGING_PROCEDURE_VERSION
402
+ ? PACKAGING_PROCEDURE_VERSION
403
+ : undefined;
404
+ if (packagingProcedureVersion === undefined) addError(errors, code, "packaging_procedure_version");
405
+ const hostAgentCompatibility = raw.host_agent_compatibility === "host-neutral-cli-schema-0"
406
+ ? "host-neutral-cli-schema-0"
407
+ : undefined;
408
+ if (hostAgentCompatibility === undefined) addError(errors, "host_agent_compatibility_invalid", "host_agent_compatibility");
409
+ const qmdCompatibility = parseQmdCompatibility(raw.qmd_compatibility, errors, code);
410
+ const knowledgeSchemaCompatibility = parseKnowledgeSchemaCompatibility(raw.knowledge_schema_compatibility, errors, code);
411
+ const packApiCompatibility = raw.pack_api_compatibility === 0 ? 0 : undefined;
412
+ if (packApiCompatibility === undefined) addError(errors, code, "pack_api_compatibility");
413
+ const environmentCompatibility = parseEnvironmentCompatibility(raw.environment_compatibility, errors, code);
414
+ const includedPacks = parseIncludedPacks(raw.included_packs, errors, code);
415
+ return {
416
+ identity,
417
+ packagingProcedureVersion,
418
+ hostAgentCompatibility,
419
+ qmdCompatibility,
420
+ knowledgeSchemaCompatibility,
421
+ packApiCompatibility,
422
+ environmentCompatibility,
423
+ includedPacks,
424
+ };
425
+ }
426
+
427
+ export function parseReleaseManifest(raw: unknown): ReleaseResult<ReleaseManifest> {
428
+ if (!isRecord(raw)) return failed("release_manifest_invalid", "release_manifest");
429
+ const errors: ErrorList = [];
430
+ hasExactKeys(raw, [
431
+ "schema_version", "release_format", "version", "source_revision", "packaging_procedure_version",
432
+ "host_agent_compatibility", "qmd_compatibility", "knowledge_schema_compatibility", "pack_api_compatibility",
433
+ "environment_compatibility", "included_packs", "files",
434
+ ], errors, "release_manifest_invalid");
435
+ if (raw.schema_version !== RELEASE_SCHEMA_VERSION) addError(errors, "release_manifest_invalid", "schema_version");
436
+ if (raw.release_format !== RELEASE_FORMAT_VERSION) addError(errors, "release_manifest_invalid", "release_format");
437
+ const common = parseCommon(raw, errors, "release_manifest_invalid");
438
+ const files = parseFiles(raw.files, errors, "release_manifest_invalid");
439
+ if (
440
+ errors.length > 0 ||
441
+ common.identity === undefined ||
442
+ common.packagingProcedureVersion === undefined ||
443
+ common.hostAgentCompatibility === undefined ||
444
+ common.qmdCompatibility === undefined ||
445
+ common.knowledgeSchemaCompatibility === undefined ||
446
+ common.packApiCompatibility === undefined ||
447
+ common.environmentCompatibility === undefined ||
448
+ common.includedPacks === undefined ||
449
+ files === undefined
450
+ ) return { ok: false, errors };
451
+ return {
452
+ ok: true,
453
+ value: {
454
+ schema_version: RELEASE_SCHEMA_VERSION,
455
+ release_format: RELEASE_FORMAT_VERSION,
456
+ version: common.identity.version,
457
+ source_revision: common.identity.source_revision,
458
+ packaging_procedure_version: common.packagingProcedureVersion,
459
+ host_agent_compatibility: common.hostAgentCompatibility,
460
+ qmd_compatibility: common.qmdCompatibility,
461
+ knowledge_schema_compatibility: common.knowledgeSchemaCompatibility,
462
+ pack_api_compatibility: common.packApiCompatibility,
463
+ environment_compatibility: common.environmentCompatibility,
464
+ included_packs: common.includedPacks,
465
+ files,
466
+ },
467
+ };
468
+ }
469
+
470
+ export function parseReleaseRecord(raw: unknown): ReleaseResult<ReleaseRecord> {
471
+ if (!isRecord(raw)) return failed("release_record_invalid", "release_record");
472
+ const errors: ErrorList = [];
473
+ hasExactKeys(raw, [
474
+ "schema_version", "version", "source_revision", "packaging_procedure_version", "host_agent_compatibility",
475
+ "qmd_compatibility", "knowledge_schema_compatibility", "pack_api_compatibility", "environment_compatibility",
476
+ "included_packs", "included_beads", "verification_summary", "known_limitations", "artifact_integrity", "published_at",
477
+ ], errors, "release_record_invalid");
478
+ if (raw.schema_version !== RELEASE_SCHEMA_VERSION) addError(errors, "release_record_invalid", "schema_version");
479
+ const common = parseCommon(raw, errors, "release_record_invalid");
480
+ const includedBeads = parseStringArray(raw.included_beads, "included_beads", errors, "release_record_invalid");
481
+ const knownLimitations = parseStringArray(raw.known_limitations, "known_limitations", errors, "known_limitations_invalid");
482
+ let archive: ReleaseArtifactIntegrity | undefined;
483
+ let bootstrap: ReleaseArtifactIntegrity | undefined;
484
+ if (!isRecord(raw.artifact_integrity)) {
485
+ addError(errors, "release_record_invalid", "artifact_integrity");
486
+ } else {
487
+ hasExactKeys(raw.artifact_integrity, ["archive", "bootstrap"], errors, "release_record_invalid");
488
+ archive = parseArtifactIntegrity(raw.artifact_integrity.archive, "artifact_integrity.archive", errors, "release_record_invalid");
489
+ bootstrap = parseArtifactIntegrity(raw.artifact_integrity.bootstrap, "artifact_integrity.bootstrap", errors, "release_record_invalid");
490
+ }
491
+ const verificationSummary = parseVerificationSummary(raw.verification_summary, archive?.sha256, errors, "release_record_invalid");
492
+ const publishedAt = singleLineString(raw.published_at, "published_at", errors, "release_record_invalid");
493
+ if (publishedAt !== undefined && !/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(publishedAt)) {
494
+ addError(errors, "release_record_invalid", "published_at");
495
+ }
496
+ if (
497
+ errors.length > 0 ||
498
+ common.identity === undefined ||
499
+ common.packagingProcedureVersion === undefined ||
500
+ common.hostAgentCompatibility === undefined ||
501
+ common.qmdCompatibility === undefined ||
502
+ common.knowledgeSchemaCompatibility === undefined ||
503
+ common.packApiCompatibility === undefined ||
504
+ common.environmentCompatibility === undefined ||
505
+ common.includedPacks === undefined ||
506
+ includedBeads === undefined ||
507
+ verificationSummary === undefined ||
508
+ knownLimitations === undefined ||
509
+ archive === undefined ||
510
+ bootstrap === undefined ||
511
+ publishedAt === undefined
512
+ ) return { ok: false, errors };
513
+ return {
514
+ ok: true,
515
+ value: {
516
+ schema_version: RELEASE_SCHEMA_VERSION,
517
+ version: common.identity.version,
518
+ source_revision: common.identity.source_revision,
519
+ packaging_procedure_version: common.packagingProcedureVersion,
520
+ host_agent_compatibility: common.hostAgentCompatibility,
521
+ qmd_compatibility: common.qmdCompatibility,
522
+ knowledge_schema_compatibility: common.knowledgeSchemaCompatibility,
523
+ pack_api_compatibility: common.packApiCompatibility,
524
+ environment_compatibility: common.environmentCompatibility,
525
+ included_packs: common.includedPacks,
526
+ included_beads: includedBeads,
527
+ verification_summary: verificationSummary,
528
+ known_limitations: knownLimitations,
529
+ artifact_integrity: { archive, bootstrap },
530
+ published_at: publishedAt,
531
+ },
532
+ };
533
+ }
534
+
535
+ export async function readReleaseManifest(path: string): Promise<ReleaseResult<ReleaseManifest>> {
536
+ try {
537
+ return parseReleaseManifest(JSON.parse(await readFile(path, "utf8")));
538
+ } catch {
539
+ return failed("release_manifest_invalid", "release_manifest");
540
+ }
541
+ }
542
+
543
+ function canonicalValue(value: unknown): string {
544
+ if (value === null || typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
545
+ if (typeof value === "number") {
546
+ if (!Number.isFinite(value)) throw new TypeError("canonical_release_json is invalid");
547
+ return JSON.stringify(value);
548
+ }
549
+ if (Array.isArray(value)) return `[${value.map(canonicalValue).join(",")}]`;
550
+ if (isRecord(value)) return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalValue(value[key])}`).join(",")}}`;
551
+ throw new TypeError("canonical_release_json is invalid");
552
+ }
553
+
554
+ export function canonicalReleaseJson(value: unknown): string {
555
+ return `${canonicalValue(value)}\n`;
556
+ }
557
+
558
+ export type ReleaseManagerHooks = {
559
+ afterExistingOwnerRead?: () => Promise<void> | void;
560
+ afterLaunchersInstalled?: () => Promise<void> | void;
561
+ beforeSelectionRename?: () => Promise<void> | void;
562
+ };
563
+
564
+ export type ReleaseManagerOptions = {
565
+ releaseHome?: string;
566
+ binDir?: string;
567
+ executablePath?: string;
568
+ hooks?: ReleaseManagerHooks;
569
+ manifestPath?: string;
570
+ stdout?: (message: string) => void;
571
+ stderr?: (message: string) => void;
572
+ };
573
+
574
+ type ArchiveEntry = { path: string; bytes: Buffer; mode: number; directory: boolean };
575
+ type InspectedArchive = { manifest: ReleaseManifest; entries: ArchiveEntry[] };
576
+ type ReleasePaths = { home: string; releases: string };
577
+ type LockOwner = { schema_version: 0; pid: number; hostname: string; token: string; purpose?: "recovery" };
578
+ type InstallLock = { release: () => Promise<void> };
579
+ type InstalledLauncher = { path: string; ino: number; dev: number; content: string };
580
+
581
+ function managerFailure<T>(code: ReleaseErrorCode, message: string, field?: string, detail?: string): ReleaseResult<T> {
582
+ return { ok: false, errors: [{ code, message, ...(field === undefined ? {} : { field }), ...(detail === undefined ? {} : { detail }) }] };
583
+ }
584
+
585
+ function managerErrorMessage(code: ReleaseErrorCode): string {
586
+ const messages: Record<ReleaseErrorCode, string> = {
587
+ release_manifest_invalid: "release manifest is invalid",
588
+ release_record_invalid: "release record is invalid",
589
+ release_id_invalid: "release identifier is invalid",
590
+ host_agent_compatibility_invalid: "release compatibility is invalid",
591
+ release_path_invalid: "release path is invalid",
592
+ release_path_duplicate: "release path is duplicated",
593
+ files_order_invalid: "release file order is invalid",
594
+ included_packs_order_invalid: "release pack order is invalid",
595
+ known_limitations_invalid: "release limitations are invalid",
596
+ verification_artifact_mismatch: "release verification is invalid",
597
+ release_incompatible: "release is incompatible with this host",
598
+ release_boundary_unsafe: "release filesystem boundary is unsafe",
599
+ artifact_integrity_mismatch: "release artifact integrity does not match",
600
+ archive_unsafe: "release archive is unsafe",
601
+ archive_inventory_mismatch: "release archive inventory does not match",
602
+ release_identity_mismatch: "release identity does not match",
603
+ release_exists: "release already exists",
604
+ install_lock_conflict: "another release installation is active",
605
+ install_lock_owner_unverifiable: "release installation lock owner cannot be verified",
606
+ install_failed: "release installation failed",
607
+ selection_target_unknown: "selected release does not exist",
608
+ selection_target_linked: "selected release is linked",
609
+ selection_target_invalid: "selected release is invalid",
610
+ selection_target_incompatible: "selected release is incompatible",
611
+ launcher_conflict: "stable launcher conflicts with an existing file",
612
+ current_absent: "current release selection is invalid",
613
+ };
614
+ return messages[code];
615
+ }
616
+
617
+ function managerFailed<T>(code: ReleaseErrorCode, field?: string): ReleaseResult<T> {
618
+ return managerFailure(code, managerErrorMessage(code), field);
619
+ }
620
+
621
+ function isNotFound(error: unknown): boolean {
622
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ENOENT";
623
+ }
624
+
625
+ function isAlreadyExists(error: unknown): boolean {
626
+ return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
627
+ }
628
+
629
+ function sha256Bytes(bytes: Buffer): string {
630
+ return createHash("sha256").update(bytes).digest("hex");
631
+ }
632
+
633
+ function isDirectChild(parent: string, child: string): boolean {
634
+ return dirname(child) === parent && basename(child).length > 0;
635
+ }
636
+
637
+ function isWithin(parent: string, child: string): boolean {
638
+ const path = relative(parent, child);
639
+ return path === "" || (!path.startsWith(`..${sep}`) && path !== ".." && !isAbsolute(path));
640
+ }
641
+
642
+ function safeReleaseBoundary(parent: string, child: string, directory: boolean, symbolicLink: boolean): boolean {
643
+ if (!directory || symbolicLink) return false;
644
+ return isDirectChild(parent, child);
645
+ }
646
+
647
+ function safeArchivePath(path: string): boolean {
648
+ return path.length > 0 &&
649
+ !isAbsolute(path) &&
650
+ !path.includes("\\") &&
651
+ !path.split("/").some((part) => part.length === 0 || part === "." || part === "..");
652
+ }
653
+
654
+ function parentPaths(path: string): string[] {
655
+ const parts = path.split("/");
656
+ const parents: string[] = [];
657
+ for (let index = 1; index < parts.length; index++) parents.push(parts.slice(0, index).join("/"));
658
+ return parents;
659
+ }
660
+
661
+ function textField(header: Buffer, offset: number, length: number): string {
662
+ const raw = header.subarray(offset, offset + length);
663
+ const end = raw.indexOf(0);
664
+ const text = raw.subarray(0, end === -1 ? raw.length : end).toString("utf8");
665
+ if (text.includes("\0")) throw new Error("embedded null");
666
+ return text;
667
+ }
668
+
669
+ function octalField(header: Buffer, offset: number, length: number): number {
670
+ const text = textField(header, offset, length).trim();
671
+ if (!/^[0-7]+$/.test(text)) throw new Error("invalid octal field");
672
+ const value = Number.parseInt(text, 8);
673
+ if (!Number.isSafeInteger(value) || value < 0) throw new Error("invalid octal value");
674
+ return value;
675
+ }
676
+
677
+ function validChecksum(header: Buffer): boolean {
678
+ const expected = octalField(header, 148, 8);
679
+ let actual = 0;
680
+ for (let index = 0; index < 512; index++) actual += index >= 148 && index < 156 ? 32 : header[index] ?? 0;
681
+ return actual === expected;
682
+ }
683
+
684
+ function zeroBlock(bytes: Buffer, offset: number): boolean {
685
+ for (let index = offset; index < offset + 512; index++) if ((bytes[index] ?? 0) !== 0) return false;
686
+ return true;
687
+ }
688
+
689
+ function archiveResultError<T>(): ReleaseResult<T> {
690
+ return managerFailed("archive_unsafe");
691
+ }
692
+
693
+ export async function inspectArchive(input: string | Buffer): Promise<ReleaseResult<InspectedArchive>> {
694
+ let bytes: Buffer;
695
+ try {
696
+ bytes = typeof input === "string" ? await readFile(input) : input;
697
+ bytes = gunzipSync(bytes);
698
+ } catch {
699
+ return archiveResultError();
700
+ }
701
+ try {
702
+ const entries: ArchiveEntry[] = [];
703
+ const names = new Set<string>();
704
+ let offset = 0;
705
+ while (offset + 1024 <= bytes.length && !zeroBlock(bytes, offset)) {
706
+ const header = bytes.subarray(offset, offset + 512);
707
+ if (textField(header, 257, 6) !== "ustar" || !validChecksum(header)) throw new Error("invalid header");
708
+ const name = textField(header, 0, 100);
709
+ const prefix = textField(header, 345, 155);
710
+ const pathName = prefix.length === 0 ? name : `${prefix}/${name}`;
711
+ const type = header[156] ?? 0;
712
+ if (type !== 0 && type !== 48 && type !== 53) throw new Error("unsupported entry type");
713
+ const directory = type === 53;
714
+ if (!safeArchivePath(pathName) || names.has(pathName)) throw new Error("unsafe path");
715
+ const byteLength = octalField(header, 124, 12);
716
+ const dataStart = offset + 512;
717
+ const paddedLength = Math.ceil(byteLength / 512) * 512;
718
+ if (dataStart + paddedLength > bytes.length || (directory && byteLength !== 0)) throw new Error("truncated entry");
719
+ names.add(pathName);
720
+ entries.push({
721
+ path: pathName,
722
+ bytes: Buffer.from(bytes.subarray(dataStart, dataStart + byteLength)),
723
+ mode: octalField(header, 100, 8),
724
+ directory,
725
+ });
726
+ offset = dataStart + paddedLength;
727
+ }
728
+ if (offset + 1024 !== bytes.length || !zeroBlock(bytes, offset) || !zeroBlock(bytes, offset + 512)) throw new Error("invalid trailer");
729
+ const manifestEntry = entries.find((entry) => entry.path === "release-manifest.json" && !entry.directory);
730
+ if (manifestEntry === undefined) return managerFailed("archive_inventory_mismatch");
731
+ const parsedManifest = parseReleaseManifest(JSON.parse(manifestEntry.bytes.toString("utf8")));
732
+ if (!parsedManifest.ok || manifestEntry.bytes.toString("utf8") !== canonicalReleaseJson(parsedManifest.value)) {
733
+ return managerFailed("archive_inventory_mismatch");
734
+ }
735
+ const files = entries.filter((entry) => !entry.directory);
736
+ const expected = new Map(parsedManifest.value.files.map((file) => [file.path, file]));
737
+ if (files.length !== expected.size + 1) return managerFailed("archive_inventory_mismatch");
738
+ for (const entry of files) {
739
+ if (entry.path === "release-manifest.json") {
740
+ if (entry.mode !== 0o644) return managerFailed("archive_inventory_mismatch");
741
+ continue;
742
+ }
743
+ const file = expected.get(entry.path);
744
+ const expectedMode = file?.executable ? 0o755 : 0o644;
745
+ if (file === undefined || entry.mode !== expectedMode || file.byte_length !== entry.bytes.length || file.sha256 !== sha256Bytes(entry.bytes)) {
746
+ return managerFailed("archive_inventory_mismatch");
747
+ }
748
+ }
749
+ const expectedDirectories = new Set(files.flatMap((entry) => parentPaths(entry.path)));
750
+ const directories = entries.filter((entry) => entry.directory);
751
+ if (
752
+ directories.length !== expectedDirectories.size ||
753
+ directories.some((entry) => !expectedDirectories.has(entry.path) || entry.mode !== 0o755)
754
+ ) return managerFailed("archive_inventory_mismatch");
755
+ return { ok: true, value: { manifest: parsedManifest.value, entries } };
756
+ } catch {
757
+ return archiveResultError();
758
+ }
759
+ }
760
+
761
+ async function createSafeDirectory(path: string, mode: number): Promise<void> {
762
+ const missing: string[] = [];
763
+ let cursor = path;
764
+ for (;;) {
765
+ try {
766
+ const stat = await lstat(cursor);
767
+ if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error("linked boundary");
768
+ cursor = await realpath(cursor);
769
+ break;
770
+ } catch (error) {
771
+ if (!isNotFound(error)) throw error;
772
+ missing.push(cursor);
773
+ const parent = dirname(cursor);
774
+ if (parent === cursor) throw new Error("missing root");
775
+ cursor = parent;
776
+ }
777
+ }
778
+ while (missing.length > 0) {
779
+ const next = missing.pop();
780
+ if (next === undefined) throw new Error("missing directory");
781
+ await mkdir(next, { mode });
782
+ const stat = await lstat(next);
783
+ const canonicalNext = await realpath(next);
784
+ if (!stat.isDirectory() || stat.isSymbolicLink() || !isDirectChild(cursor, canonicalNext)) throw new Error("linked boundary");
785
+ cursor = canonicalNext;
786
+ }
787
+ }
788
+
789
+ async function physicalPaths(options: ReleaseManagerOptions, create: boolean): Promise<ReleaseResult<ReleasePaths>> {
790
+ const home = resolve(options.releaseHome ?? process.env.ENGRAM_RELEASE_HOME ?? join(homedir(), ".local", "share", "engram"));
791
+ const releases = join(home, "releases");
792
+ try {
793
+ if (create) {
794
+ // Prevalidate any already-existing requested root before creating a
795
+ // descendant beneath it: a linked/outside root must be refused before
796
+ // `<outside>/releases` (or any other descendant) is ever written, and
797
+ // an already-existing accepted root is never re-created.
798
+ const existingHome = await lstat(home).catch((error) => { if (isNotFound(error)) return undefined; throw error; });
799
+ if (existingHome === undefined) {
800
+ await createSafeDirectory(home, 0o755);
801
+ } else if (!safeReleaseBoundary(await realpath(dirname(home)), await realpath(home), existingHome.isDirectory(), existingHome.isSymbolicLink())) {
802
+ return managerFailed("release_boundary_unsafe");
803
+ }
804
+ const existingReleases = await lstat(releases).catch((error) => { if (isNotFound(error)) return undefined; throw error; });
805
+ if (existingReleases === undefined) {
806
+ await createSafeDirectory(releases, 0o755);
807
+ } else if (!safeReleaseBoundary(await realpath(home), await realpath(releases), existingReleases.isDirectory(), existingReleases.isSymbolicLink())) {
808
+ return managerFailed("release_boundary_unsafe");
809
+ }
810
+ }
811
+ const homeStat = await lstat(home);
812
+ const canonicalHome = await realpath(home);
813
+ const canonicalParent = await realpath(dirname(home));
814
+ if (!safeReleaseBoundary(canonicalParent, canonicalHome, homeStat.isDirectory(), homeStat.isSymbolicLink())) {
815
+ return managerFailed("release_boundary_unsafe");
816
+ }
817
+ let releasesStat;
818
+ try {
819
+ releasesStat = await lstat(releases);
820
+ } catch (error) {
821
+ if (isNotFound(error) && !create) return managerFailed("selection_target_unknown");
822
+ return managerFailed("release_boundary_unsafe");
823
+ }
824
+ const canonicalReleases = await realpath(releases);
825
+ if (!safeReleaseBoundary(canonicalHome, canonicalReleases, releasesStat.isDirectory(), releasesStat.isSymbolicLink())) {
826
+ return managerFailed("release_boundary_unsafe");
827
+ }
828
+ return { ok: true, value: { home: canonicalHome, releases: canonicalReleases } };
829
+ } catch (error) {
830
+ if (!create && isNotFound(error)) return managerFailed("selection_target_unknown");
831
+ return managerFailed("release_boundary_unsafe");
832
+ }
833
+ }
834
+
835
+ function compatible(manifest: ReleaseManifest): boolean {
836
+ return manifest.environment_compatibility.platform === process.platform &&
837
+ manifest.environment_compatibility.architecture === process.arch &&
838
+ manifest.environment_compatibility.node_version === `v${process.versions.node}`;
839
+ }
840
+
841
+ function validReleaseId(id: string): boolean {
842
+ return /^r0-[0-9a-f]{40}$/.test(id);
843
+ }
844
+
845
+ async function readCurrent(paths: ReleasePaths): Promise<ReleaseResult<string | null>> {
846
+ const path = join(paths.home, "current");
847
+ let stat;
848
+ try {
849
+ stat = await lstat(path);
850
+ } catch (error) {
851
+ if (isNotFound(error)) return { ok: true, value: null };
852
+ return managerFailed("current_absent");
853
+ }
854
+ if (!stat.isSymbolicLink()) return managerFailed("current_absent");
855
+ try {
856
+ const target = await readlink(path);
857
+ const match = /^releases\/(r0-[0-9a-f]{40})$/.exec(target);
858
+ const id = match?.[1];
859
+ if (id === undefined) return managerFailed("current_absent");
860
+ const selected = join(paths.releases, id);
861
+ const selectedStat = await lstat(selected);
862
+ if (!selectedStat.isDirectory() || selectedStat.isSymbolicLink() || !isDirectChild(paths.releases, await realpath(selected))) {
863
+ return managerFailed("current_absent");
864
+ }
865
+ return { ok: true, value: id };
866
+ } catch {
867
+ return managerFailed("current_absent");
868
+ }
869
+ }
870
+
871
+ async function validatedTarget(id: string, paths: ReleasePaths): Promise<ReleaseResult<ReleaseManifest>> {
872
+ if (!validReleaseId(id)) return managerFailed("release_id_invalid");
873
+ const target = join(paths.releases, id);
874
+ try {
875
+ const stat = await lstat(target);
876
+ if (stat.isSymbolicLink()) return managerFailed("selection_target_linked");
877
+ if (!stat.isDirectory() || !isDirectChild(paths.releases, await realpath(target))) return managerFailed("selection_target_invalid");
878
+ const parsed = await readReleaseManifest(join(target, "release-manifest.json"));
879
+ if (!parsed.ok || parsed.value.version !== id) return managerFailed("selection_target_invalid");
880
+ if (!compatible(parsed.value)) return managerFailed("selection_target_incompatible");
881
+ return parsed;
882
+ } catch (error) {
883
+ if (isNotFound(error)) return managerFailed("selection_target_unknown");
884
+ return managerFailed("selection_target_invalid");
885
+ }
886
+ }
887
+
888
+ async function syncDirectory(path: string): Promise<void> {
889
+ const handle = await open(path, constants.O_RDONLY);
890
+ try {
891
+ await handle.sync();
892
+ } finally {
893
+ await handle.close();
894
+ }
895
+ }
896
+
897
+ async function readLockOwner(path: string): Promise<ReleaseResult<LockOwner>> {
898
+ try {
899
+ const raw: unknown = JSON.parse(await readFile(path, "utf8"));
900
+ if (!isRecord(raw) || raw.schema_version !== 0 || typeof raw.pid !== "number" || !Number.isInteger(raw.pid) || raw.pid <= 0 || typeof raw.hostname !== "string" || raw.hostname.length === 0 || typeof raw.token !== "string" || raw.token.length === 0 || (raw.purpose !== undefined && raw.purpose !== "recovery")) {
901
+ return managerFailed("install_lock_owner_unverifiable");
902
+ }
903
+ if (raw.purpose === "recovery") return { ok: true, value: { schema_version: 0, pid: raw.pid, hostname: raw.hostname, token: raw.token, purpose: "recovery" } };
904
+ return { ok: true, value: { schema_version: 0, pid: raw.pid, hostname: raw.hostname, token: raw.token } };
905
+ } catch {
906
+ return managerFailed("install_lock_owner_unverifiable");
907
+ }
908
+ }
909
+
910
+ async function installExclusiveLockMetadata(path: string, owner: LockOwner): Promise<ReleaseResult<boolean>> {
911
+ const candidate = `${path}.candidate-${owner.token}`;
912
+ try {
913
+ await writeFile(candidate, JSON.stringify(owner), { flag: "wx", mode: 0o600 });
914
+ try {
915
+ await link(candidate, path);
916
+ return { ok: true, value: true };
917
+ } catch (error) {
918
+ if (isAlreadyExists(error)) return { ok: true, value: false };
919
+ return managerFailed("install_failed");
920
+ }
921
+ } catch {
922
+ return managerFailed("install_failed");
923
+ } finally {
924
+ await unlink(candidate).catch(() => {});
925
+ }
926
+ }
927
+
928
+ function lockProcessState(owner: LockOwner): "live" | "absent" | "unknown" {
929
+ if (owner.hostname !== hostname()) return "live";
930
+ try {
931
+ process.kill(owner.pid, 0);
932
+ return "live";
933
+ } catch (error) {
934
+ return typeof error === "object" && error !== null && "code" in error && error.code === "ESRCH" ? "absent" : "unknown";
935
+ }
936
+ }
937
+
938
+ async function removeOwnerlessLock(lockPath: string, ownerPath: string, recoveryPath: string, hooks: ReleaseManagerHooks | undefined): Promise<boolean> {
939
+ try {
940
+ const original = await lstat(lockPath);
941
+ if (!original.isDirectory() || original.isSymbolicLink()) return false;
942
+ try {
943
+ await lstat(ownerPath);
944
+ return false;
945
+ } catch (error) {
946
+ if (!isNotFound(error)) return false;
947
+ }
948
+ // Claim recovery of this ownerless lock exclusively, using the same
949
+ // hard-link publication as dead-owner recovery, so a fresh owner
950
+ // publisher racing on the same lock generation can observe our claim
951
+ // before or after it publishes and yield rather than being destroyed.
952
+ const recovery: LockOwner = { schema_version: 0, pid: process.pid, hostname: hostname(), token: randomUUID(), purpose: "recovery" };
953
+ const claimed = await installExclusiveLockMetadata(recoveryPath, recovery);
954
+ if (!claimed.ok || !claimed.value) return false;
955
+ try {
956
+ await hooks?.afterExistingOwnerRead?.();
957
+ let current;
958
+ try {
959
+ current = await lstat(lockPath);
960
+ } catch (error) {
961
+ return isNotFound(error);
962
+ }
963
+ if (current.ino !== original.ino || current.dev !== original.dev) return false;
964
+ try {
965
+ await lstat(ownerPath);
966
+ return false;
967
+ } catch (error) {
968
+ if (!isNotFound(error)) return false;
969
+ }
970
+ const claim = await readLockOwner(recoveryPath);
971
+ if (!claim.ok || claim.value.token !== recovery.token) return false;
972
+ await hooks?.afterExistingOwnerRead?.();
973
+ await rm(lockPath, { recursive: true, force: false });
974
+ return true;
975
+ } finally {
976
+ const marker = await readLockOwner(recoveryPath);
977
+ if (marker.ok && marker.value.token === recovery.token) await unlink(recoveryPath).catch(() => {});
978
+ }
979
+ } catch {
980
+ return false;
981
+ }
982
+ }
983
+
984
+ async function removeDeadRecoveryMarker(recoveryPath: string): Promise<ReleaseResult<boolean>> {
985
+ try {
986
+ await lstat(recoveryPath);
987
+ } catch (error) {
988
+ if (isNotFound(error)) return { ok: true, value: false };
989
+ return managerFailed("install_lock_owner_unverifiable");
990
+ }
991
+ const marker = await readLockOwner(recoveryPath);
992
+ if (!marker.ok) return marker;
993
+ const state = lockProcessState(marker.value);
994
+ if (state === "live") return { ok: true, value: false };
995
+ if (state === "unknown") return managerFailed("install_lock_owner_unverifiable");
996
+ try {
997
+ const original = await lstat(recoveryPath);
998
+ const current = await readLockOwner(recoveryPath);
999
+ const reread = await lstat(recoveryPath);
1000
+ if (
1001
+ !current.ok ||
1002
+ current.value.token !== marker.value.token ||
1003
+ reread.ino !== original.ino ||
1004
+ reread.dev !== original.dev ||
1005
+ lockProcessState(current.value) !== "absent"
1006
+ ) return { ok: true, value: false };
1007
+ await unlink(recoveryPath);
1008
+ return { ok: true, value: true };
1009
+ } catch {
1010
+ return managerFailed("install_lock_owner_unverifiable");
1011
+ }
1012
+ }
1013
+
1014
+ async function acquireInstallLock(paths: ReleasePaths, hooks: ReleaseManagerHooks | undefined): Promise<ReleaseResult<InstallLock>> {
1015
+ const lockPath = join(paths.releases, ".install-lock");
1016
+ const ownerPath = join(lockPath, "owner.json");
1017
+ const recoveryPath = `${lockPath}.recovery`;
1018
+ for (let attempt = 0; attempt < 4; attempt += 1) {
1019
+ try {
1020
+ await mkdir(lockPath, { mode: 0o700 });
1021
+ const lockStat = await lstat(lockPath);
1022
+ const recoveryBefore = await lstat(recoveryPath).catch(() => undefined);
1023
+ if (recoveryBefore !== undefined) {
1024
+ // A recoverer may claim this lock generation, or its marker may be a
1025
+ // dead orphan with no lock directory of its own to recover through
1026
+ // (since we just freshly created this one): reclaim a dead marker
1027
+ // outright, and otherwise yield instead of racing a hard-link
1028
+ // publish against a live recoverer's removal.
1029
+ await rm(lockPath, { recursive: true, force: false }).catch(() => {});
1030
+ const staleMarker = await removeDeadRecoveryMarker(recoveryPath);
1031
+ if (!staleMarker.ok) return staleMarker;
1032
+ continue;
1033
+ }
1034
+ await hooks?.afterExistingOwnerRead?.();
1035
+ const owner: LockOwner = { schema_version: 0, pid: process.pid, hostname: hostname(), token: randomUUID() };
1036
+ const installed = await installExclusiveLockMetadata(ownerPath, owner);
1037
+ if (!installed.ok || !installed.value) {
1038
+ await removeOwnerlessLock(lockPath, ownerPath, recoveryPath, hooks);
1039
+ return managerFailed("install_lock_owner_unverifiable");
1040
+ }
1041
+ await hooks?.afterExistingOwnerRead?.();
1042
+ const recoveryAfter = await lstat(recoveryPath).catch(() => undefined);
1043
+ if (recoveryAfter !== undefined) {
1044
+ // A recoverer claimed this lock generation around our publish;
1045
+ // token-clean our own owner/lock and never return acquired.
1046
+ const currentLock = await lstat(lockPath).catch(() => undefined);
1047
+ if (currentLock !== undefined && currentLock.ino === lockStat.ino && currentLock.dev === lockStat.dev) {
1048
+ const current = await readLockOwner(ownerPath);
1049
+ if (current.ok && current.value.token === owner.token) await unlink(ownerPath).catch(() => {});
1050
+ await rm(lockPath, { recursive: true, force: false }).catch(() => {});
1051
+ }
1052
+ continue;
1053
+ }
1054
+ // No recoverer claim is visible now, but a recoverer may already have
1055
+ // removed this lock generation (owner.json and all) and cleared its
1056
+ // marker before this read: require our own token plus the original
1057
+ // lock directory identity before ever reporting acquired.
1058
+ const publishedOwner = await readLockOwner(ownerPath);
1059
+ const publishedLock = await lstat(lockPath).catch(() => undefined);
1060
+ if (
1061
+ !publishedOwner.ok ||
1062
+ publishedOwner.value.token !== owner.token ||
1063
+ publishedLock === undefined ||
1064
+ publishedLock.ino !== lockStat.ino ||
1065
+ publishedLock.dev !== lockStat.dev
1066
+ ) continue;
1067
+ return { ok: true, value: { release: async () => {
1068
+ const current = await readLockOwner(ownerPath);
1069
+ const currentLock = await lstat(lockPath).catch(() => undefined);
1070
+ if (!current.ok || current.value.token !== owner.token || currentLock === undefined || currentLock.ino !== lockStat.ino || currentLock.dev !== lockStat.dev) return;
1071
+ await rm(lockPath, { recursive: true, force: false }).catch(() => {});
1072
+ } } };
1073
+ } catch (error) {
1074
+ if (!isAlreadyExists(error)) return managerFailed("install_failed");
1075
+ }
1076
+ const existing = await readLockOwner(ownerPath);
1077
+ if (!existing.ok) {
1078
+ const staleMarker = await removeDeadRecoveryMarker(recoveryPath);
1079
+ if (!staleMarker.ok) return staleMarker;
1080
+ if (staleMarker.value || await removeOwnerlessLock(lockPath, ownerPath, recoveryPath, hooks)) continue;
1081
+ return existing;
1082
+ }
1083
+ await hooks?.afterExistingOwnerRead?.();
1084
+ const state = lockProcessState(existing.value);
1085
+ if (state === "live") return managerFailed("install_lock_conflict");
1086
+ if (state === "unknown") return managerFailed("install_lock_owner_unverifiable");
1087
+ const recovery: LockOwner = { schema_version: 0, pid: process.pid, hostname: hostname(), token: randomUUID(), purpose: "recovery" };
1088
+ const marked = await installExclusiveLockMetadata(recoveryPath, recovery);
1089
+ if (!marked.ok) return marked;
1090
+ if (!marked.value) {
1091
+ const staleMarker = await removeDeadRecoveryMarker(recoveryPath);
1092
+ if (!staleMarker.ok) return staleMarker;
1093
+ if (staleMarker.value) continue;
1094
+ return managerFailed("install_lock_conflict");
1095
+ }
1096
+ try {
1097
+ const current = await readLockOwner(ownerPath);
1098
+ if (!current.ok) return current;
1099
+ if (current.value.token !== existing.value.token || lockProcessState(current.value) !== "absent") return managerFailed("install_lock_conflict");
1100
+ await rm(lockPath, { recursive: true, force: false });
1101
+ } catch {
1102
+ return managerFailed("install_lock_owner_unverifiable");
1103
+ } finally {
1104
+ const marker = await readLockOwner(recoveryPath);
1105
+ if (marker.ok && marker.value.token === recovery.token) await unlink(recoveryPath).catch(() => {});
1106
+ }
1107
+ }
1108
+ return managerFailed("install_lock_conflict");
1109
+ }
1110
+
1111
+ function quotedShellPath(path: string): string {
1112
+ return `'${path.replaceAll("'", "'\\''")}'`;
1113
+ }
1114
+
1115
+ async function installLaunchers(paths: ReleasePaths, options: ReleaseManagerOptions): Promise<ReleaseResult<InstalledLauncher[]>> {
1116
+ const binDir = resolve(options.binDir ?? process.env.ENGRAM_BIN_DIR ?? join(homedir(), ".local", "bin"));
1117
+ const installed: InstalledLauncher[] = [];
1118
+ try {
1119
+ await mkdir(binDir, { recursive: true, mode: 0o755 });
1120
+ const binStat = await lstat(binDir);
1121
+ if (!binStat.isDirectory() || binStat.isSymbolicLink()) return managerFailed("launcher_conflict");
1122
+ const canonicalBin = await realpath(binDir);
1123
+ const definitions = [
1124
+ { name: "engram", content: `#!/bin/sh\nexec ${quotedShellPath(join(paths.home, "current", "bin", "engram"))} "$@"\n` },
1125
+ { name: "engram-release", content: `#!/bin/sh\nexec node ${quotedShellPath(join(paths.home, "current", "release", "engram-release.ts"))} "$@"\n` },
1126
+ ];
1127
+ for (const definition of definitions) {
1128
+ const launcherPath = join(canonicalBin, definition.name);
1129
+ try {
1130
+ const stat = await lstat(launcherPath);
1131
+ if (!stat.isFile() || stat.isSymbolicLink() || (stat.mode & 0o111) === 0 || await readFile(launcherPath, "utf8") !== definition.content) {
1132
+ await cleanupLaunchers(installed);
1133
+ return managerFailed("launcher_conflict");
1134
+ }
1135
+ } catch (error) {
1136
+ if (!isNotFound(error)) {
1137
+ await cleanupLaunchers(installed);
1138
+ return managerFailed("launcher_conflict");
1139
+ }
1140
+ const temporary = join(canonicalBin, `.${definition.name}.${randomUUID()}.tmp`);
1141
+ try {
1142
+ const handle = await open(temporary, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 0o755);
1143
+ try {
1144
+ await handle.writeFile(definition.content, "utf8");
1145
+ await handle.sync();
1146
+ } finally {
1147
+ await handle.close();
1148
+ }
1149
+ await chmod(temporary, 0o755);
1150
+ const candidate = await lstat(temporary);
1151
+ if (!candidate.isFile() || candidate.isSymbolicLink() || (candidate.mode & 0o777) !== 0o755) throw new Error("launcher mode");
1152
+ await link(temporary, launcherPath);
1153
+ installed.push({ path: launcherPath, ino: candidate.ino, dev: candidate.dev, content: definition.content });
1154
+ const published = await lstat(launcherPath);
1155
+ if (!published.isFile() || published.isSymbolicLink() || published.ino !== candidate.ino || published.dev !== candidate.dev) {
1156
+ throw new Error("launcher publication");
1157
+ }
1158
+ await chmod(launcherPath, 0o755);
1159
+ if (((await lstat(launcherPath)).mode & 0o777) !== 0o755) throw new Error("launcher mode");
1160
+ await unlink(temporary);
1161
+ } catch {
1162
+ await rm(temporary, { force: true });
1163
+ await cleanupLaunchers(installed);
1164
+ return managerFailed("launcher_conflict");
1165
+ }
1166
+ }
1167
+ }
1168
+ await syncDirectory(canonicalBin);
1169
+ return { ok: true, value: installed };
1170
+ } catch {
1171
+ await cleanupLaunchers(installed);
1172
+ return managerFailed("launcher_conflict");
1173
+ }
1174
+ }
1175
+
1176
+ async function cleanupLaunchers(launchers: readonly InstalledLauncher[]): Promise<void> {
1177
+ for (const launcher of launchers) {
1178
+ try {
1179
+ const stat = await lstat(launcher.path);
1180
+
1181
+ if (stat.isFile() && !stat.isSymbolicLink() && stat.ino === launcher.ino && stat.dev === launcher.dev && await readFile(launcher.path, "utf8") === launcher.content) {
1182
+ await rm(launcher.path);
1183
+ }
1184
+ } catch {
1185
+ continue;
1186
+ }
1187
+ }
1188
+ }
1189
+ async function sealAndVerifyStagedTree(root: string, entries: readonly ArchiveEntry[]): Promise<boolean> {
1190
+ try {
1191
+ const actual: string[] = [];
1192
+ const walk = async (relativePath: string): Promise<void> => {
1193
+ const directory = join(root, relativePath);
1194
+ for (const entry of await readdir(directory, { withFileTypes: true })) {
1195
+ const child = relativePath.length === 0 ? entry.name : join(relativePath, entry.name);
1196
+ actual.push(child);
1197
+ if (entry.isDirectory()) await walk(child);
1198
+ }
1199
+ };
1200
+ await walk("");
1201
+ const expected = entries.map((entry) => entry.path).sort();
1202
+ actual.sort();
1203
+ if (actual.length !== expected.length || actual.some((path, index) => path !== expected[index])) return false;
1204
+ for (const entry of entries) {
1205
+ const path = join(root, entry.path);
1206
+ const stat = await lstat(path);
1207
+ const expectedMode = entry.directory ? 0o755 : entry.mode;
1208
+ if (stat.isSymbolicLink() || stat.isDirectory() !== entry.directory || (stat.mode & 0o7777) !== expectedMode) return false;
1209
+ if (!entry.directory) {
1210
+ const bytes = await readFile(path);
1211
+ if (bytes.length !== entry.bytes.length || sha256Bytes(bytes) !== sha256Bytes(entry.bytes)) return false;
1212
+ }
1213
+ }
1214
+ for (const entry of entries.filter((candidate) => !candidate.directory)) {
1215
+ const path = join(root, entry.path);
1216
+ await chmod(path, entry.mode === 0o755 ? 0o555 : 0o444);
1217
+ await syncDirectory(path);
1218
+ }
1219
+ for (const path of [...actual].sort((left, right) => right.length - left.length)) {
1220
+ const fullPath = join(root, path);
1221
+ const stat = await lstat(fullPath);
1222
+ if (stat.isDirectory()) {
1223
+ await chmod(fullPath, 0o555);
1224
+ await syncDirectory(fullPath);
1225
+ }
1226
+ }
1227
+ await syncDirectory(root);
1228
+ return true;
1229
+ } catch {
1230
+ return false;
1231
+ }
1232
+ }
1233
+
1234
+ async function makeTreeWritable(root: string): Promise<void> {
1235
+ try {
1236
+ const walk = async (path: string): Promise<void> => {
1237
+ const stat = await lstat(path);
1238
+ if (stat.isDirectory()) {
1239
+ await chmod(path, 0o755);
1240
+ for (const entry of await readdir(path)) await walk(join(path, entry));
1241
+ } else {
1242
+ await chmod(path, 0o644);
1243
+ }
1244
+ };
1245
+ await walk(root);
1246
+ } catch {
1247
+ return;
1248
+ }
1249
+ }
1250
+
1251
+ export async function installRelease(archivePath: string, recordPath: string, options: ReleaseManagerOptions = {}): Promise<ReleaseResult<{ release_id: string }>> {
1252
+ let record: ReleaseRecord;
1253
+ let archive: Buffer;
1254
+ try {
1255
+ const raw = JSON.parse(await readFile(recordPath, "utf8"));
1256
+ const parsed = parseReleaseRecord(raw);
1257
+ if (!parsed.ok) {
1258
+ const detail = isRecord(raw) && typeof raw.source_revision === "string" ? raw.source_revision : undefined;
1259
+ return managerFailure("release_record_invalid", managerErrorMessage("release_record_invalid"), undefined, detail);
1260
+ }
1261
+ record = parsed.value;
1262
+ archive = await readFile(archivePath);
1263
+ } catch {
1264
+ return managerFailed("release_record_invalid");
1265
+ }
1266
+ if (
1267
+ archive.length !== record.artifact_integrity.archive.byte_length ||
1268
+ sha256Bytes(archive) !== record.artifact_integrity.archive.sha256 ||
1269
+ basename(archivePath) !== record.artifact_integrity.archive.filename
1270
+ ) return managerFailed("artifact_integrity_mismatch");
1271
+ const inspected = await inspectArchive(archive);
1272
+ if (!inspected.ok) return inspected;
1273
+ const manager = inspected.value.entries.find((entry) => entry.path === "release/engram-release.ts" && !entry.directory);
1274
+ if (
1275
+ manager === undefined ||
1276
+ manager.bytes.length !== record.artifact_integrity.bootstrap.byte_length ||
1277
+ sha256Bytes(manager.bytes) !== record.artifact_integrity.bootstrap.sha256
1278
+ ) return managerFailed("artifact_integrity_mismatch");
1279
+ if (
1280
+ inspected.value.manifest.version !== record.version ||
1281
+ inspected.value.manifest.source_revision !== record.source_revision
1282
+ ) return managerFailed("release_identity_mismatch");
1283
+ if (!compatible(inspected.value.manifest)) return managerFailed("release_incompatible");
1284
+ const pathResult = await physicalPaths(options, true);
1285
+ if (!pathResult.ok) return pathResult;
1286
+ const paths = pathResult.value;
1287
+ const finalPath = join(paths.releases, record.version);
1288
+ try {
1289
+ await lstat(finalPath);
1290
+ return managerFailed("release_exists");
1291
+ } catch (error) {
1292
+ if (!isNotFound(error)) return managerFailed("install_failed");
1293
+ }
1294
+ const lock = await acquireInstallLock(paths, options.hooks);
1295
+ if (!lock.ok) return lock;
1296
+ let staging = "";
1297
+ let launchers: InstalledLauncher[] = [];
1298
+ let committed = false;
1299
+ try {
1300
+ staging = join(paths.releases, `.staging-${randomUUID()}`);
1301
+ await mkdir(staging, { mode: 0o700 });
1302
+ const canonicalStaging = await realpath(staging);
1303
+ if (!isDirectChild(paths.releases, canonicalStaging)) return managerFailed("release_boundary_unsafe");
1304
+ for (const entry of inspected.value.entries) {
1305
+ if (entry.directory) continue;
1306
+ const destination = join(canonicalStaging, entry.path);
1307
+ const parent = dirname(destination);
1308
+ await mkdir(parent, { recursive: true, mode: 0o755 });
1309
+ const canonicalParent = await realpath(parent);
1310
+ if (!isWithin(canonicalStaging, canonicalParent)) return managerFailed("release_boundary_unsafe");
1311
+ const handle = await open(destination, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, entry.mode);
1312
+ try {
1313
+ await handle.writeFile(entry.bytes);
1314
+ await handle.sync();
1315
+ } finally {
1316
+ await handle.close();
1317
+ }
1318
+ await chmod(destination, entry.mode);
1319
+ const written = await readFile(destination);
1320
+ if (written.length !== entry.bytes.length || sha256Bytes(written) !== sha256Bytes(entry.bytes)) return managerFailed("install_failed");
1321
+ await syncDirectory(canonicalParent);
1322
+ }
1323
+ for (const entry of inspected.value.entries) {
1324
+ if (!entry.directory) continue;
1325
+ const directory = join(canonicalStaging, entry.path);
1326
+ const stat = await lstat(directory);
1327
+ const canonicalDirectory = await realpath(directory);
1328
+ if (!stat.isDirectory() || stat.isSymbolicLink() || !isWithin(canonicalStaging, canonicalDirectory)) {
1329
+ return managerFailed("release_boundary_unsafe");
1330
+ }
1331
+ await chmod(directory, 0o755);
1332
+ }
1333
+ const launchResult = await installLaunchers(paths, options);
1334
+ if (!launchResult.ok) return launchResult;
1335
+ launchers = launchResult.value;
1336
+ await options.hooks?.afterLaunchersInstalled?.();
1337
+ if (!await sealAndVerifyStagedTree(canonicalStaging, inspected.value.entries)) return managerFailed("install_failed");
1338
+ try {
1339
+ await lstat(finalPath);
1340
+ return managerFailed("release_exists");
1341
+ } catch (error) {
1342
+ if (!isNotFound(error)) return managerFailed("install_failed");
1343
+ }
1344
+ await rename(canonicalStaging, finalPath);
1345
+ committed = true;
1346
+ await chmod(finalPath, 0o555);
1347
+ await syncDirectory(finalPath);
1348
+ await syncDirectory(paths.releases);
1349
+ const selected = await readCurrent(paths);
1350
+ if (!selected.ok) return selected;
1351
+ if (selected.value === null) {
1352
+ const selection = await selectRelease(record.version, options);
1353
+ if (!selection.ok) return selection;
1354
+ }
1355
+ return { ok: true, value: { release_id: record.version } };
1356
+ } catch {
1357
+ return managerFailed("install_failed");
1358
+ } finally {
1359
+ if (!committed) {
1360
+ if (staging.length > 0) {
1361
+ await makeTreeWritable(staging);
1362
+ await rm(staging, { recursive: true, force: true });
1363
+ }
1364
+ await cleanupLaunchers(launchers);
1365
+ }
1366
+ await lock.value.release();
1367
+ }
1368
+ }
1369
+ export async function selectRelease(releaseId: string, options: ReleaseManagerOptions = {}): Promise<ReleaseResult<{ release_id: string }>> {
1370
+ const pathResult = await physicalPaths(options, false);
1371
+ if (!pathResult.ok) return pathResult;
1372
+ const paths = pathResult.value;
1373
+ const target = await validatedTarget(releaseId, paths);
1374
+ if (!target.ok) return target;
1375
+ const temporary = join(paths.home, `.current-${randomUUID()}`);
1376
+ try {
1377
+ await symlink(join("releases", releaseId), temporary);
1378
+ await options.hooks?.beforeSelectionRename?.();
1379
+ const revalidated = await validatedTarget(releaseId, paths);
1380
+ if (!revalidated.ok) return revalidated;
1381
+ await rename(temporary, join(paths.home, "current"));
1382
+ await syncDirectory(paths.home);
1383
+ return { ok: true, value: { release_id: releaseId } };
1384
+ } catch {
1385
+ return managerFailed("install_failed");
1386
+ } finally {
1387
+ await unlink(temporary).catch(() => {});
1388
+ }
1389
+ }
1390
+
1391
+ export async function listReleases(options: ReleaseManagerOptions = {}): Promise<ReleaseResult<{ release_ids: string[]; selected_release_id: string | null }>> {
1392
+ const pathResult = await physicalPaths(options, false);
1393
+ if (!pathResult.ok) {
1394
+ if (pathResult.errors[0]?.code === "selection_target_unknown") return { ok: true, value: { release_ids: [], selected_release_id: null } };
1395
+ return pathResult;
1396
+ }
1397
+ const ids: string[] = [];
1398
+ try {
1399
+ for (const entry of await readdir(pathResult.value.releases, { withFileTypes: true })) {
1400
+ if (entry.name.startsWith(".staging-") || entry.name === ".install-lock") continue;
1401
+ if (!validReleaseId(entry.name)) {
1402
+ if (entry.isDirectory()) return managerFailed("selection_target_invalid");
1403
+ continue;
1404
+ }
1405
+ const target = await validatedTarget(entry.name, pathResult.value);
1406
+ if (!target.ok) return target;
1407
+ ids.push(entry.name);
1408
+ }
1409
+ ids.sort();
1410
+ const selected = await readCurrent(pathResult.value);
1411
+ if (!selected.ok) return selected;
1412
+ return { ok: true, value: { release_ids: ids, selected_release_id: selected.value } };
1413
+ } catch {
1414
+ return managerFailed("selection_target_invalid");
1415
+ }
1416
+ }
1417
+
1418
+ export async function currentRelease(options: ReleaseManagerOptions = {}): Promise<ReleaseResult<string | null>> {
1419
+ const pathResult = await physicalPaths(options, false);
1420
+ if (!pathResult.ok) {
1421
+ if (pathResult.errors[0]?.code === "selection_target_unknown") return { ok: true, value: null };
1422
+ return pathResult;
1423
+ }
1424
+ const selected = await readCurrent(pathResult.value);
1425
+ if (!selected.ok || selected.value === null) return selected;
1426
+ const target = await validatedTarget(selected.value, pathResult.value);
1427
+ if (!target.ok) return managerFailed("current_absent");
1428
+ return selected;
1429
+ }
1430
+
1431
+ function projectReleaseErrors(errors: readonly ReleaseError[]): { code: ReleaseErrorCode; message: string; field?: string }[] {
1432
+ return errors.map((error) => ({ code: error.code, message: error.message, ...(error.field === undefined ? {} : { field: error.field }) }));
1433
+ }
1434
+
1435
+ export async function runReleaseManager(argv: readonly string[], options: ReleaseManagerOptions = {}): Promise<number> {
1436
+ const writeStdout = options.stdout ?? ((message: string) => process.stdout.write(message));
1437
+ const writeStderr = options.stderr ?? ((message: string) => process.stderr.write(message));
1438
+ const output = (value: object): void => writeStdout(`${JSON.stringify(value)}\n`);
1439
+ const failure = (result: ReleaseResult<unknown>): number => {
1440
+ if (result.ok) return 0;
1441
+ output({ schema_version: 0, status: "failed", errors: projectReleaseErrors(result.errors) });
1442
+ return 1;
1443
+ };
1444
+ if (argv[0] === "install" && argv.length === 3) {
1445
+ const result = await installRelease(argv[1] ?? "", argv[2] ?? "", options);
1446
+ if (!result.ok) return failure(result);
1447
+ output({ schema_version: 0, status: "installed" });
1448
+ return 0;
1449
+ }
1450
+ if (argv[0] === "select" && argv.length === 2) {
1451
+ const result = await selectRelease(argv[1] ?? "", options);
1452
+ if (!result.ok) return failure(result);
1453
+ output({ schema_version: 0, status: "selected" });
1454
+ return 0;
1455
+ }
1456
+ if (argv[0] === "list" && argv.length === 1) {
1457
+ const result = await listReleases(options);
1458
+ if (!result.ok) return failure(result);
1459
+ output({ schema_version: 0, status: "listed", release_ids: result.value.release_ids, selected_release_id: result.value.selected_release_id });
1460
+ return 0;
1461
+ }
1462
+ if (argv[0] === "current" && argv.length === 1) {
1463
+ const result = await currentRelease(options);
1464
+ if (!result.ok) return failure(result);
1465
+ output({ schema_version: 0, status: "current", release_id: result.value });
1466
+ return 0;
1467
+ }
1468
+ writeStderr("release_manager_command_invalid\n");
1469
+ return 1;
1470
+ }
1471
+
1472
+ // `endsWith("/release/engram-release.ts")` would only match this file at
1473
+ // its development-tree path; a packaged release copies and renames this
1474
+ // exact file to a standalone bootstrap (e.g. `engram-release-r0-<rev>.ts`)
1475
+ // for install, so the entrypoint must recognize "this file is the one
1476
+ // actually being executed" regardless of what it is named or where it
1477
+ // lives, not one hardcoded path shape. The installed `engram-release`
1478
+ // launcher always execs through the `current` symlink, and Node's ESM
1479
+ // loader resolves `import.meta.url` to the symlink target's real path
1480
+ // while `process.argv[1]` keeps the literal (symlinked) invocation path
1481
+ // — so the comparison must realpath the invoked path too, or every
1482
+ // invocation through `current` would silently no-op.
1483
+ let invokedEntrypoint: string | undefined;
1484
+ try {
1485
+ invokedEntrypoint = process.argv[1] === undefined ? undefined : realpathSync(process.argv[1]);
1486
+ } catch {
1487
+ invokedEntrypoint = undefined;
1488
+ }
1489
+ if (invokedEntrypoint === fileURLToPath(import.meta.url)) {
1490
+ void runReleaseManager(process.argv.slice(2)).then((code) => {
1491
+ process.exitCode = code;
1492
+ });
1493
+ }