mason-context 0.20.2 → 0.22.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.
- package/CHANGELOG.md +25 -0
- package/README.md +24 -5
- package/dist/mason-audit.js +1755 -698
- package/dist/mason-audit.js.map +1 -1
- package/dist/mason-drift.js +662 -193
- package/dist/mason-drift.js.map +1 -1
- package/dist/mason-hook.js +862 -198
- package/dist/mason-hook.js.map +1 -1
- package/dist/mason-mcp.js +8713 -8484
- package/dist/mason-mcp.js.map +1 -1
- package/dist/mason-review.js +1088 -380
- package/dist/mason-review.js.map +1 -1
- package/dist/mason-runtime.js +297 -148
- package/dist/mason-runtime.js.map +1 -1
- package/dist/mason.js +7566 -5905
- package/dist/mason.js.map +1 -1
- package/package.json +11 -4
package/dist/mason-runtime.js
CHANGED
|
@@ -2,17 +2,18 @@
|
|
|
2
2
|
if (!import.meta.url.endsWith("/mason-runtime.js")) await import("./mason-runtime.js").then(m => m.registerRuntime());
|
|
3
3
|
|
|
4
4
|
// src/distribution/runtime.ts
|
|
5
|
-
import
|
|
5
|
+
import fs8 from "fs/promises";
|
|
6
6
|
import { unlinkSync } from "fs";
|
|
7
7
|
import os4 from "os";
|
|
8
|
-
import
|
|
8
|
+
import path8 from "path";
|
|
9
9
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
10
|
-
import { z as
|
|
10
|
+
import { z as z10 } from "zod";
|
|
11
11
|
|
|
12
12
|
// src/automation/store.ts
|
|
13
|
-
import { z as
|
|
13
|
+
import { z as z6 } from "zod";
|
|
14
14
|
|
|
15
15
|
// src/utils/store-lock.ts
|
|
16
|
+
import { z } from "zod";
|
|
16
17
|
import fs3 from "fs/promises";
|
|
17
18
|
import os from "os";
|
|
18
19
|
|
|
@@ -25,11 +26,22 @@ import { randomUUID } from "crypto";
|
|
|
25
26
|
import path from "path";
|
|
26
27
|
function normalizeRepoPath(value) {
|
|
27
28
|
const slash = value.replace(/\\/g, "/");
|
|
28
|
-
if (!slash || slash.includes("\0") || path.posix.isAbsolute(slash) || /^[A-Za-z]:/.test(slash))
|
|
29
|
+
if (!slash || slash.includes("\0") || path.posix.isAbsolute(slash) || /^[A-Za-z]:/.test(slash))
|
|
30
|
+
return null;
|
|
29
31
|
if (slash.split("/").includes("..")) return null;
|
|
30
32
|
const normalized = path.posix.normalize(slash).replace(/\/$/, "");
|
|
31
33
|
return normalized === "." ? null : normalized;
|
|
32
34
|
}
|
|
35
|
+
function anchorMatches(anchor, file) {
|
|
36
|
+
const a = normalizeRepoPath(anchor);
|
|
37
|
+
const f = normalizeRepoPath(file);
|
|
38
|
+
return a !== null && f !== null && (a === f || f.startsWith(`${a}/`));
|
|
39
|
+
}
|
|
40
|
+
function matchingPaths(anchors, files) {
|
|
41
|
+
return [...new Set(files)].filter(
|
|
42
|
+
(file) => anchors.some((anchor) => anchorMatches(anchor, file))
|
|
43
|
+
);
|
|
44
|
+
}
|
|
33
45
|
|
|
34
46
|
// src/utils/git-read.ts
|
|
35
47
|
import { execFile } from "child_process";
|
|
@@ -47,11 +59,40 @@ import fs from "fs/promises";
|
|
|
47
59
|
import { constants } from "fs";
|
|
48
60
|
import path2 from "path";
|
|
49
61
|
import fg from "fast-glob";
|
|
50
|
-
var SOURCE_EXTENSIONS = [
|
|
62
|
+
var SOURCE_EXTENSIONS = [
|
|
63
|
+
"ts",
|
|
64
|
+
"tsx",
|
|
65
|
+
"js",
|
|
66
|
+
"jsx",
|
|
67
|
+
"mts",
|
|
68
|
+
"cts",
|
|
69
|
+
"mjs",
|
|
70
|
+
"cjs",
|
|
71
|
+
"vue",
|
|
72
|
+
"svelte",
|
|
73
|
+
"kt",
|
|
74
|
+
"kts",
|
|
75
|
+
"java",
|
|
76
|
+
"py",
|
|
77
|
+
"go",
|
|
78
|
+
"rs",
|
|
79
|
+
"swift",
|
|
80
|
+
"rb",
|
|
81
|
+
"cs",
|
|
82
|
+
"cpp",
|
|
83
|
+
"c",
|
|
84
|
+
"h",
|
|
85
|
+
"hpp",
|
|
86
|
+
"dart",
|
|
87
|
+
"php"
|
|
88
|
+
];
|
|
51
89
|
var SOURCE_GLOB = `**/*.{${SOURCE_EXTENSIONS.join(",")}}`;
|
|
52
90
|
var MAX_SOURCE_BYTES = 1024 * 1024;
|
|
53
91
|
async function readBoundedFile(file, maxBytes) {
|
|
54
|
-
const handle = await fs.open(
|
|
92
|
+
const handle = await fs.open(
|
|
93
|
+
file,
|
|
94
|
+
constants.O_RDONLY | constants.O_NONBLOCK | constants.O_NOFOLLOW
|
|
95
|
+
);
|
|
55
96
|
try {
|
|
56
97
|
const stat = await handle.stat();
|
|
57
98
|
if (!stat.isFile() || stat.size > maxBytes) return null;
|
|
@@ -104,7 +145,10 @@ async function readStoreJson(root, relative) {
|
|
|
104
145
|
return parsed;
|
|
105
146
|
} catch (error) {
|
|
106
147
|
if (error.code === "ENOENT") return null;
|
|
107
|
-
throw new Error(
|
|
148
|
+
throw new Error(
|
|
149
|
+
`Invalid Mason store ${relative}: ${error instanceof Error ? error.message : String(error)}`,
|
|
150
|
+
{ cause: error }
|
|
151
|
+
);
|
|
108
152
|
}
|
|
109
153
|
}
|
|
110
154
|
async function writeStoreJson(root, relative, value) {
|
|
@@ -129,26 +173,30 @@ async function writeStoreJson(root, relative, value) {
|
|
|
129
173
|
}
|
|
130
174
|
|
|
131
175
|
// src/utils/store-lock.ts
|
|
176
|
+
var lockOwnerSchema = z.object({ host: z.string(), pid: z.number().int().positive() });
|
|
132
177
|
async function lockDiagnostic(file) {
|
|
133
178
|
let reason;
|
|
134
179
|
try {
|
|
135
|
-
const owner = JSON.parse(await fs3.readFile(file, "utf8"));
|
|
136
|
-
if (!owner
|
|
180
|
+
const owner = lockOwnerSchema.safeParse(JSON.parse(await fs3.readFile(file, "utf8")));
|
|
181
|
+
if (!owner.success) {
|
|
137
182
|
reason = "Lock owner data is incomplete or malformed.";
|
|
138
|
-
} else if (owner.host !== os.hostname()) {
|
|
183
|
+
} else if (owner.data.host !== os.hostname()) {
|
|
139
184
|
reason = "The lock belongs to another host; its process cannot be checked locally.";
|
|
140
185
|
} else {
|
|
141
186
|
try {
|
|
142
|
-
process.kill(owner.pid, 0);
|
|
143
|
-
reason = `Local owner PID ${owner.pid} is still running.`;
|
|
187
|
+
process.kill(owner.data.pid, 0);
|
|
188
|
+
reason = `Local owner PID ${owner.data.pid} is still running.`;
|
|
144
189
|
} catch (error) {
|
|
145
|
-
reason = error.code === "ESRCH" ? `Local owner PID ${owner.pid} has exited, but lock recovery has not completed.` : `Local owner PID ${owner.pid} could not be checked.`;
|
|
190
|
+
reason = error.code === "ESRCH" ? `Local owner PID ${owner.data.pid} has exited, but lock recovery has not completed.` : `Local owner PID ${owner.data.pid} could not be checked.`;
|
|
146
191
|
}
|
|
147
192
|
}
|
|
148
193
|
} catch (error) {
|
|
149
194
|
reason = error instanceof SyntaxError ? "Lock owner data is incomplete or malformed." : "Lock owner data could not be read; the lock may have changed.";
|
|
150
195
|
}
|
|
151
|
-
if (await fs3.lstat(file + ".reclaim").then(
|
|
196
|
+
if (await fs3.lstat(file + ".reclaim").then(
|
|
197
|
+
() => true,
|
|
198
|
+
() => false
|
|
199
|
+
)) {
|
|
152
200
|
reason += " A recovery guard also needs inspection: " + file + ".reclaim.";
|
|
153
201
|
}
|
|
154
202
|
return reason + " Retry if a writer is active. For manual recovery, stop all Mason writers for this checkout, confirm they have exited (including other hosts), then remove only confirmed abandoned lock and lock.reclaim files. See docs/reference.md#snapshot-repairs-and-verification.";
|
|
@@ -168,7 +216,7 @@ async function withStoreLock(root, directory, run, waitMs = 5e3, label = "Mason
|
|
|
168
216
|
}
|
|
169
217
|
if (error.code !== "EEXIST") throw error;
|
|
170
218
|
try {
|
|
171
|
-
const owner = JSON.parse(await fs3.readFile(file, "utf8"));
|
|
219
|
+
const owner = lockOwnerSchema.parse(JSON.parse(await fs3.readFile(file, "utf8")));
|
|
172
220
|
if (owner.host === os.hostname() && Number.isInteger(owner.pid) && owner.pid > 0) {
|
|
173
221
|
try {
|
|
174
222
|
process.kill(owner.pid, 0);
|
|
@@ -178,7 +226,7 @@ async function withStoreLock(root, directory, run, waitMs = 5e3, label = "Mason
|
|
|
178
226
|
let guard;
|
|
179
227
|
try {
|
|
180
228
|
guard = await fs3.open(reclaim, "wx", 384);
|
|
181
|
-
const current = JSON.parse(await fs3.readFile(file, "utf8"));
|
|
229
|
+
const current = lockOwnerSchema.parse(JSON.parse(await fs3.readFile(file, "utf8")));
|
|
182
230
|
if (current.pid === owner.pid && current.host === owner.host) await fs3.unlink(file);
|
|
183
231
|
} finally {
|
|
184
232
|
if (guard) {
|
|
@@ -191,7 +239,11 @@ async function withStoreLock(root, directory, run, waitMs = 5e3, label = "Mason
|
|
|
191
239
|
}
|
|
192
240
|
} catch {
|
|
193
241
|
}
|
|
194
|
-
if (Date.now() >= deadline)
|
|
242
|
+
if (Date.now() >= deadline)
|
|
243
|
+
throw new Error(
|
|
244
|
+
label + " is busy or its lock needs inspection: " + file + ". " + await lockDiagnostic(file),
|
|
245
|
+
{ cause: error }
|
|
246
|
+
);
|
|
195
247
|
await new Promise((resolve) => setTimeout(resolve, 40));
|
|
196
248
|
}
|
|
197
249
|
if (handle) {
|
|
@@ -214,121 +266,193 @@ async function withStoreLock(root, directory, run, waitMs = 5e3, label = "Mason
|
|
|
214
266
|
}
|
|
215
267
|
}
|
|
216
268
|
|
|
217
|
-
// src/automation/
|
|
269
|
+
// src/automation/stop-review.ts
|
|
270
|
+
import { z as z4 } from "zod";
|
|
271
|
+
|
|
272
|
+
// src/decisions/anchors.ts
|
|
273
|
+
import { createHash } from "crypto";
|
|
274
|
+
import fs4 from "fs/promises";
|
|
275
|
+
import { constants as constants2 } from "fs";
|
|
218
276
|
import { z as z2 } from "zod";
|
|
277
|
+
import fg3 from "fast-glob";
|
|
278
|
+
|
|
279
|
+
// src/audit/inspection.ts
|
|
280
|
+
import fg2 from "fast-glob";
|
|
281
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
282
|
+
import path4 from "path";
|
|
283
|
+
var inspections = new AsyncLocalStorage2();
|
|
284
|
+
var sourceSpecs = SOURCE_EXTENSIONS.map((extension) => `:(glob)**/*.${extension}`);
|
|
285
|
+
var sourceSuffixes = new Set(SOURCE_EXTENSIONS.map((extension) => "." + extension));
|
|
286
|
+
|
|
287
|
+
// src/decisions/anchors.ts
|
|
288
|
+
var repoPath = z2.string().refine((p) => normalizeRepoPath(p) === p);
|
|
289
|
+
var anchorCaptureSchema = z2.object({
|
|
290
|
+
anchors: z2.array(repoPath),
|
|
291
|
+
files: z2.record(repoPath, z2.string().regex(/^[a-f0-9]{64}$/)),
|
|
292
|
+
complete: z2.boolean()
|
|
293
|
+
}).refine(
|
|
294
|
+
(capture) => JSON.stringify(capture.anchors) === JSON.stringify([...new Set(capture.anchors)].sort()) && matchingPaths(capture.anchors, Object.keys(capture.files)).length === Object.keys(capture.files).length,
|
|
295
|
+
"Capture paths must belong to its normalized, sorted anchor scope"
|
|
296
|
+
);
|
|
219
297
|
|
|
220
298
|
// src/audit/findings.ts
|
|
221
|
-
import { createHash } from "crypto";
|
|
222
|
-
import { z } from "zod";
|
|
223
|
-
var checkSchema =
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
299
|
+
import { createHash as createHash2 } from "crypto";
|
|
300
|
+
import { z as z3 } from "zod";
|
|
301
|
+
var checkSchema = z3.enum([
|
|
302
|
+
"deleted-reference",
|
|
303
|
+
"new-module",
|
|
304
|
+
"stale-count",
|
|
305
|
+
"dead-command",
|
|
306
|
+
"deps-changed",
|
|
307
|
+
"decision-anchor-drift"
|
|
308
|
+
]);
|
|
309
|
+
var commitSchema = z3.object({
|
|
310
|
+
hash: z3.string().regex(/^[a-f0-9]{40,64}$/),
|
|
311
|
+
date: z3.string(),
|
|
312
|
+
subject: z3.string()
|
|
313
|
+
});
|
|
314
|
+
var anchorSchema = z3.object({
|
|
315
|
+
doc: z3.string(),
|
|
316
|
+
line: z3.number().int().positive().nullable(),
|
|
317
|
+
excerpt: z3.string().nullable()
|
|
318
|
+
});
|
|
319
|
+
var count = z3.number().int().nonnegative();
|
|
320
|
+
var scopeSchema = z3.object({
|
|
321
|
+
basis: z3.enum(["repository", "document", "document-link", "explicit"]),
|
|
322
|
+
directory: z3.string(),
|
|
323
|
+
candidates: z3.array(z3.string())
|
|
231
324
|
});
|
|
232
|
-
var evidenceSchema =
|
|
233
|
-
|
|
234
|
-
kind:
|
|
235
|
-
claimed:
|
|
236
|
-
renamedTo:
|
|
325
|
+
var evidenceSchema = z3.discriminatedUnion("kind", [
|
|
326
|
+
z3.object({
|
|
327
|
+
kind: z3.literal("missing-path"),
|
|
328
|
+
claimed: z3.string(),
|
|
329
|
+
renamedTo: z3.string().nullable(),
|
|
237
330
|
deletedInCommit: commitSchema.nullable(),
|
|
238
|
-
everTracked:
|
|
239
|
-
parentDirExists:
|
|
240
|
-
resolvedPath:
|
|
331
|
+
everTracked: z3.boolean(),
|
|
332
|
+
parentDirExists: z3.boolean(),
|
|
333
|
+
resolvedPath: z3.string().optional(),
|
|
241
334
|
scope: scopeSchema.optional()
|
|
242
335
|
}),
|
|
243
|
-
|
|
244
|
-
kind:
|
|
245
|
-
dir:
|
|
336
|
+
z3.object({
|
|
337
|
+
kind: z3.literal("unmentioned-dir"),
|
|
338
|
+
dir: z3.string(),
|
|
246
339
|
sourceFileCount: count,
|
|
247
340
|
firstCommit: commitSchema.nullable(),
|
|
248
|
-
checkedDocs:
|
|
341
|
+
checkedDocs: z3.array(z3.string())
|
|
249
342
|
}),
|
|
250
|
-
|
|
251
|
-
kind:
|
|
343
|
+
z3.object({
|
|
344
|
+
kind: z3.literal("count-mismatch"),
|
|
252
345
|
claimed: count,
|
|
253
346
|
actual: count,
|
|
254
|
-
unit:
|
|
255
|
-
countedFrom:
|
|
256
|
-
members:
|
|
347
|
+
unit: z3.string(),
|
|
348
|
+
countedFrom: z3.string(),
|
|
349
|
+
members: z3.array(z3.string())
|
|
257
350
|
}),
|
|
258
|
-
|
|
259
|
-
kind:
|
|
260
|
-
scriptName:
|
|
261
|
-
invocation:
|
|
262
|
-
manifestsChecked:
|
|
263
|
-
availableScripts:
|
|
351
|
+
z3.object({
|
|
352
|
+
kind: z3.literal("missing-script"),
|
|
353
|
+
scriptName: z3.string(),
|
|
354
|
+
invocation: z3.string(),
|
|
355
|
+
manifestsChecked: z3.array(z3.string()),
|
|
356
|
+
availableScripts: z3.array(z3.string()),
|
|
264
357
|
scope: scopeSchema.optional()
|
|
265
358
|
}),
|
|
266
|
-
|
|
267
|
-
kind:
|
|
359
|
+
z3.object({
|
|
360
|
+
kind: z3.literal("doc-behind-manifests"),
|
|
268
361
|
docLastCommit: commitSchema,
|
|
269
|
-
manifestCommits:
|
|
362
|
+
manifestCommits: z3.array(commitSchema.extend({ files: z3.array(z3.string()) })),
|
|
270
363
|
totalCommits: count,
|
|
271
|
-
matches:
|
|
272
|
-
|
|
364
|
+
matches: z3.array(
|
|
365
|
+
z3.object({
|
|
366
|
+
dependency: z3.string(),
|
|
367
|
+
manifest: z3.string(),
|
|
368
|
+
before: z3.string().nullable(),
|
|
369
|
+
after: z3.string().nullable(),
|
|
370
|
+
line: z3.number().int().positive(),
|
|
371
|
+
excerpt: z3.string()
|
|
372
|
+
})
|
|
373
|
+
).optional(),
|
|
374
|
+
matchingIncomplete: z3.boolean().optional()
|
|
273
375
|
}),
|
|
274
|
-
|
|
275
|
-
kind:
|
|
276
|
-
decisionId:
|
|
277
|
-
title:
|
|
278
|
-
changedFiles:
|
|
279
|
-
refreshedHash:
|
|
280
|
-
provenance:
|
|
376
|
+
z3.object({
|
|
377
|
+
kind: z3.literal("decision-anchor"),
|
|
378
|
+
decisionId: z3.string(),
|
|
379
|
+
title: z3.string(),
|
|
380
|
+
changedFiles: z3.array(z3.string()),
|
|
381
|
+
refreshedHash: z3.string(),
|
|
382
|
+
provenance: z3.object({}).passthrough().optional()
|
|
281
383
|
})
|
|
282
384
|
]);
|
|
283
|
-
var findingSchema =
|
|
385
|
+
var findingSchema = z3.object({
|
|
386
|
+
message: z3.string(),
|
|
387
|
+
anchor: anchorSchema,
|
|
388
|
+
evidence: evidenceSchema
|
|
389
|
+
});
|
|
284
390
|
var issueSchema = findingSchema.extend({
|
|
285
|
-
type:
|
|
286
|
-
confidence:
|
|
391
|
+
type: z3.enum(["deleted-reference", "new-module", "stale-count", "dead-command"]),
|
|
392
|
+
confidence: z3.enum(["certain", "likely"])
|
|
393
|
+
});
|
|
394
|
+
var advisorySchema = findingSchema.extend({
|
|
395
|
+
type: checkSchema,
|
|
396
|
+
resolution: z3.enum(["recheck", "informational"]).optional()
|
|
397
|
+
});
|
|
398
|
+
var checkResultSchema = z3.object({
|
|
399
|
+
issues: z3.array(issueSchema),
|
|
400
|
+
advisories: z3.array(advisorySchema),
|
|
401
|
+
suppressedAdvisories: z3.array(advisorySchema).optional(),
|
|
402
|
+
skipped: z3.array(z3.object({ check: z3.string(), reason: z3.string(), doc: z3.string().optional() }))
|
|
287
403
|
});
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
404
|
+
|
|
405
|
+
// src/automation/stop-review.ts
|
|
406
|
+
var evidenceSchema2 = z4.record(z4.object({ digest: z4.string(), capture: anchorCaptureSchema }));
|
|
407
|
+
var stopReviewSchema = z4.object({
|
|
408
|
+
pending: z4.record(z4.object({ head: z4.string(), evidence: evidenceSchema2 })),
|
|
409
|
+
edited: z4.record(z4.record(z4.string().nullable())),
|
|
410
|
+
delivered: z4.record(z4.object({ digest: z4.string(), files: z4.record(z4.string().nullable()) }))
|
|
294
411
|
});
|
|
295
412
|
|
|
296
413
|
// src/automation/notifications.ts
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
414
|
+
import { z as z5 } from "zod";
|
|
415
|
+
var conditionSchema = z5.object({
|
|
416
|
+
level: z5.number(),
|
|
417
|
+
facts: z5.array(z5.string()),
|
|
418
|
+
magnitude: z5.number().optional()
|
|
301
419
|
});
|
|
302
|
-
var notificationStateSchema =
|
|
303
|
-
version:
|
|
304
|
-
baselineHead:
|
|
305
|
-
baseline:
|
|
306
|
-
delivered:
|
|
307
|
-
cleared:
|
|
420
|
+
var notificationStateSchema = z5.object({
|
|
421
|
+
version: z5.literal(1),
|
|
422
|
+
baselineHead: z5.string(),
|
|
423
|
+
baseline: z5.record(conditionSchema),
|
|
424
|
+
delivered: z5.record(conditionSchema),
|
|
425
|
+
cleared: z5.array(z5.string())
|
|
308
426
|
});
|
|
309
427
|
|
|
310
428
|
// src/automation/store.ts
|
|
311
|
-
var hostSchema =
|
|
312
|
-
var stateSchema =
|
|
313
|
-
version:
|
|
314
|
-
root:
|
|
315
|
-
gitDir:
|
|
316
|
-
branch:
|
|
317
|
-
baselines:
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
429
|
+
var hostSchema = z6.enum(["claude", "codex"]);
|
|
430
|
+
var stateSchema = z6.object({
|
|
431
|
+
version: z6.literal(1),
|
|
432
|
+
root: z6.string(),
|
|
433
|
+
gitDir: z6.string(),
|
|
434
|
+
branch: z6.string(),
|
|
435
|
+
baselines: z6.array(
|
|
436
|
+
z6.object({ path: z6.string(), at: z6.string(), event: z6.string(), fingerprint: z6.string() })
|
|
437
|
+
).max(128),
|
|
438
|
+
sessions: z6.record(
|
|
439
|
+
z6.object({
|
|
440
|
+
host: hostSchema,
|
|
441
|
+
lastUsed: z6.string(),
|
|
442
|
+
notifiedDiagnostics: z6.array(z6.string()).default([]),
|
|
443
|
+
pending: z6.record(z6.string()),
|
|
444
|
+
stopReview: stopReviewSchema.optional(),
|
|
445
|
+
coverageGaps: z6.array(z6.string()),
|
|
446
|
+
events: z6.record(z6.object({ at: z6.string(), count: z6.number().int().positive() }))
|
|
447
|
+
})
|
|
448
|
+
),
|
|
449
|
+
updatedAt: z6.string(),
|
|
450
|
+
fingerprint: z6.string().nullable(),
|
|
451
|
+
latest: z6.string().nullable(),
|
|
452
|
+
guidance: z6.object({ fingerprint: z6.string(), path: z6.string() }).optional(),
|
|
329
453
|
notifications: notificationStateSchema.optional(),
|
|
330
454
|
agentNotifications: notificationStateSchema.optional(),
|
|
331
|
-
analysis:
|
|
455
|
+
analysis: z6.object({ id: z6.string(), fingerprint: z6.string(), completedAt: z6.number(), path: z6.string() }).optional()
|
|
332
456
|
});
|
|
333
457
|
function withLock(root, directory, run, waitMs = 5e3) {
|
|
334
458
|
return withStoreLock(root, directory, run, waitMs, "Automation");
|
|
@@ -336,83 +460,100 @@ function withLock(root, directory, run, waitMs = 5e3) {
|
|
|
336
460
|
|
|
337
461
|
// src/distribution/state.ts
|
|
338
462
|
import os3 from "os";
|
|
339
|
-
import
|
|
463
|
+
import path6 from "path";
|
|
340
464
|
import { fileURLToPath } from "url";
|
|
341
|
-
import
|
|
342
|
-
import { z as
|
|
465
|
+
import fs6 from "fs/promises";
|
|
466
|
+
import { z as z8 } from "zod";
|
|
343
467
|
|
|
344
468
|
// src/distribution/path.ts
|
|
345
|
-
import
|
|
469
|
+
import fs5 from "fs/promises";
|
|
346
470
|
import os2 from "os";
|
|
347
|
-
import
|
|
471
|
+
import path5 from "path";
|
|
348
472
|
import { execFile as execFile2 } from "child_process";
|
|
349
473
|
import { promisify as promisify2 } from "util";
|
|
350
|
-
import { createHash as
|
|
351
|
-
import { z as
|
|
474
|
+
import { createHash as createHash3, randomUUID as randomUUID2 } from "crypto";
|
|
475
|
+
import { z as z7 } from "zod";
|
|
352
476
|
var execute2 = promisify2(execFile2);
|
|
353
|
-
var pathChangeSchema =
|
|
354
|
-
|
|
355
|
-
|
|
477
|
+
var pathChangeSchema = z7.discriminatedUnion("kind", [
|
|
478
|
+
z7.object({
|
|
479
|
+
kind: z7.literal("profile"),
|
|
480
|
+
file: z7.string(),
|
|
481
|
+
block: z7.string(),
|
|
482
|
+
created: z7.boolean()
|
|
483
|
+
}),
|
|
484
|
+
z7.object({ kind: z7.literal("windows"), entry: z7.string(), created: z7.boolean() })
|
|
356
485
|
]);
|
|
357
486
|
|
|
358
487
|
// src/distribution/state.ts
|
|
359
|
-
var releaseVersion =
|
|
360
|
-
var bundleId =
|
|
361
|
-
var updatePolicySchema =
|
|
362
|
-
enabled:
|
|
363
|
-
revision:
|
|
488
|
+
var releaseVersion = z8.string().regex(/^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/);
|
|
489
|
+
var bundleId = z8.string().regex(/^[a-f0-9]{24}$/);
|
|
490
|
+
var updatePolicySchema = z8.object({
|
|
491
|
+
enabled: z8.boolean(),
|
|
492
|
+
revision: z8.string(),
|
|
364
493
|
pinnedVersion: releaseVersion.optional(),
|
|
365
|
-
mirror:
|
|
494
|
+
mirror: z8.string().optional()
|
|
366
495
|
});
|
|
367
|
-
var recordSchema =
|
|
368
|
-
format:
|
|
369
|
-
home:
|
|
370
|
-
bin:
|
|
496
|
+
var recordSchema = z8.object({
|
|
497
|
+
format: z8.literal(1),
|
|
498
|
+
home: z8.string(),
|
|
499
|
+
bin: z8.string(),
|
|
371
500
|
current: bundleId,
|
|
372
501
|
version: releaseVersion,
|
|
373
|
-
launchers:
|
|
374
|
-
previousLaunchers:
|
|
375
|
-
pathChanges:
|
|
502
|
+
launchers: z8.record(z8.string()),
|
|
503
|
+
previousLaunchers: z8.record(z8.string()).optional(),
|
|
504
|
+
pathChanges: z8.array(pathChangeSchema).optional(),
|
|
376
505
|
updates: updatePolicySchema.optional(),
|
|
377
|
-
previous:
|
|
378
|
-
pending:
|
|
506
|
+
previous: z8.object({ id: bundleId, version: releaseVersion }).optional(),
|
|
507
|
+
pending: z8.object({ id: bundleId, version: releaseVersion, policyRevision: z8.string() }).optional()
|
|
379
508
|
});
|
|
380
509
|
async function readInstallation(home) {
|
|
381
510
|
const raw = await readStoreJson(home, "install.json");
|
|
382
|
-
if (!raw)
|
|
511
|
+
if (!raw)
|
|
512
|
+
throw new Error(
|
|
513
|
+
"Run this command from a standalone installation. npm users can upgrade with npm."
|
|
514
|
+
);
|
|
383
515
|
const record = recordSchema.parse(raw);
|
|
384
|
-
if (record.home !== await
|
|
516
|
+
if (record.home !== await fs6.realpath(home))
|
|
517
|
+
throw new Error("Invalid standalone installation receipt.");
|
|
385
518
|
return record;
|
|
386
519
|
}
|
|
387
520
|
function standaloneLocation() {
|
|
388
|
-
const bundle =
|
|
389
|
-
const home =
|
|
390
|
-
if (
|
|
521
|
+
const bundle = path6.resolve(path6.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
522
|
+
const home = path6.dirname(path6.dirname(bundle));
|
|
523
|
+
if (path6.dirname(bundle) !== path6.join(home, "versions") || !/^[a-f0-9]{24}$/.test(path6.basename(bundle))) {
|
|
391
524
|
return null;
|
|
392
525
|
}
|
|
393
526
|
return { home, bundle };
|
|
394
527
|
}
|
|
395
528
|
|
|
396
529
|
// src/distribution/bundle.ts
|
|
397
|
-
import
|
|
398
|
-
import
|
|
399
|
-
import { createHash as
|
|
400
|
-
import { z as
|
|
401
|
-
var targets = [
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
530
|
+
import fs7 from "fs/promises";
|
|
531
|
+
import path7 from "path";
|
|
532
|
+
import { createHash as createHash4 } from "crypto";
|
|
533
|
+
import { z as z9 } from "zod";
|
|
534
|
+
var targets = [
|
|
535
|
+
"darwin-arm64",
|
|
536
|
+
"darwin-x64",
|
|
537
|
+
"linux-arm64",
|
|
538
|
+
"linux-x64",
|
|
539
|
+
"win32-arm64",
|
|
540
|
+
"win32-x64"
|
|
541
|
+
];
|
|
542
|
+
var digest2 = z9.string().regex(/^[a-f0-9]{64}$/);
|
|
543
|
+
var bundleSchema = z9.object({
|
|
544
|
+
format: z9.literal(1),
|
|
545
|
+
version: z9.string().regex(/^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/),
|
|
546
|
+
target: z9.enum(targets),
|
|
547
|
+
nodeVersion: z9.string(),
|
|
548
|
+
files: z9.record(digest2)
|
|
409
549
|
}).strict();
|
|
410
550
|
|
|
411
551
|
// src/distribution/trust.ts
|
|
412
552
|
import tls from "tls";
|
|
413
553
|
function configureSystemTrust() {
|
|
414
554
|
if (process.env.NODE_USE_SYSTEM_CA === "0") return;
|
|
415
|
-
if (typeof tls.getCACertificates !== "function" || typeof tls.setDefaultCACertificates !== "function")
|
|
555
|
+
if (typeof tls.getCACertificates !== "function" || typeof tls.setDefaultCACertificates !== "function")
|
|
556
|
+
return;
|
|
416
557
|
tls.setDefaultCACertificates([
|
|
417
558
|
...tls.getCACertificates("default"),
|
|
418
559
|
...tls.getCACertificates("system")
|
|
@@ -420,7 +561,11 @@ function configureSystemTrust() {
|
|
|
420
561
|
}
|
|
421
562
|
|
|
422
563
|
// src/distribution/runtime.ts
|
|
423
|
-
var leaseSchema =
|
|
564
|
+
var leaseSchema = z10.object({
|
|
565
|
+
pid: z10.number().int().positive(),
|
|
566
|
+
host: z10.string(),
|
|
567
|
+
bundle: z10.string().regex(/^[a-f0-9]{24}$/)
|
|
568
|
+
});
|
|
424
569
|
async function registerRuntime() {
|
|
425
570
|
const location = standaloneLocation();
|
|
426
571
|
if (!location) return;
|
|
@@ -429,8 +574,12 @@ async function registerRuntime() {
|
|
|
429
574
|
const name = `runtimes/${randomUUID3()}.json`;
|
|
430
575
|
await withLock(home, ".install-lock", async () => {
|
|
431
576
|
await readInstallation(home);
|
|
432
|
-
await
|
|
433
|
-
await writeStoreJson(home, name, {
|
|
577
|
+
await fs8.access(bundle);
|
|
578
|
+
await writeStoreJson(home, name, {
|
|
579
|
+
pid: process.pid,
|
|
580
|
+
host: os4.hostname(),
|
|
581
|
+
bundle: path8.basename(bundle)
|
|
582
|
+
});
|
|
434
583
|
});
|
|
435
584
|
const file = await storePath(home, name);
|
|
436
585
|
process.once("exit", () => {
|