mason-context 0.20.2 → 0.21.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 +7 -1
- package/README.md +14 -0
- package/dist/mason-audit.js +1690 -649
- package/dist/mason-audit.js.map +1 -1
- package/dist/mason-drift.js +630 -175
- package/dist/mason-drift.js.map +1 -1
- package/dist/mason-hook.js +828 -194
- package/dist/mason-hook.js.map +1 -1
- package/dist/mason-mcp.js +6413 -3828
- package/dist/mason-mcp.js.map +1 -1
- package/dist/mason-review.js +990 -312
- package/dist/mason-review.js.map +1 -1
- package/dist/mason-runtime.js +296 -148
- package/dist/mason-runtime.js.map +1 -1
- package/dist/mason.js +4520 -2211
- package/dist/mason.js.map +1 -1
- package/package.json +11 -1
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,192 @@ 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(),
|
|
329
452
|
notifications: notificationStateSchema.optional(),
|
|
330
453
|
agentNotifications: notificationStateSchema.optional(),
|
|
331
|
-
analysis:
|
|
454
|
+
analysis: z6.object({ id: z6.string(), fingerprint: z6.string(), completedAt: z6.number(), path: z6.string() }).optional()
|
|
332
455
|
});
|
|
333
456
|
function withLock(root, directory, run, waitMs = 5e3) {
|
|
334
457
|
return withStoreLock(root, directory, run, waitMs, "Automation");
|
|
@@ -336,83 +459,100 @@ function withLock(root, directory, run, waitMs = 5e3) {
|
|
|
336
459
|
|
|
337
460
|
// src/distribution/state.ts
|
|
338
461
|
import os3 from "os";
|
|
339
|
-
import
|
|
462
|
+
import path6 from "path";
|
|
340
463
|
import { fileURLToPath } from "url";
|
|
341
|
-
import
|
|
342
|
-
import { z as
|
|
464
|
+
import fs6 from "fs/promises";
|
|
465
|
+
import { z as z8 } from "zod";
|
|
343
466
|
|
|
344
467
|
// src/distribution/path.ts
|
|
345
|
-
import
|
|
468
|
+
import fs5 from "fs/promises";
|
|
346
469
|
import os2 from "os";
|
|
347
|
-
import
|
|
470
|
+
import path5 from "path";
|
|
348
471
|
import { execFile as execFile2 } from "child_process";
|
|
349
472
|
import { promisify as promisify2 } from "util";
|
|
350
|
-
import { createHash as
|
|
351
|
-
import { z as
|
|
473
|
+
import { createHash as createHash3, randomUUID as randomUUID2 } from "crypto";
|
|
474
|
+
import { z as z7 } from "zod";
|
|
352
475
|
var execute2 = promisify2(execFile2);
|
|
353
|
-
var pathChangeSchema =
|
|
354
|
-
|
|
355
|
-
|
|
476
|
+
var pathChangeSchema = z7.discriminatedUnion("kind", [
|
|
477
|
+
z7.object({
|
|
478
|
+
kind: z7.literal("profile"),
|
|
479
|
+
file: z7.string(),
|
|
480
|
+
block: z7.string(),
|
|
481
|
+
created: z7.boolean()
|
|
482
|
+
}),
|
|
483
|
+
z7.object({ kind: z7.literal("windows"), entry: z7.string(), created: z7.boolean() })
|
|
356
484
|
]);
|
|
357
485
|
|
|
358
486
|
// src/distribution/state.ts
|
|
359
|
-
var releaseVersion =
|
|
360
|
-
var bundleId =
|
|
361
|
-
var updatePolicySchema =
|
|
362
|
-
enabled:
|
|
363
|
-
revision:
|
|
487
|
+
var releaseVersion = z8.string().regex(/^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/);
|
|
488
|
+
var bundleId = z8.string().regex(/^[a-f0-9]{24}$/);
|
|
489
|
+
var updatePolicySchema = z8.object({
|
|
490
|
+
enabled: z8.boolean(),
|
|
491
|
+
revision: z8.string(),
|
|
364
492
|
pinnedVersion: releaseVersion.optional(),
|
|
365
|
-
mirror:
|
|
493
|
+
mirror: z8.string().optional()
|
|
366
494
|
});
|
|
367
|
-
var recordSchema =
|
|
368
|
-
format:
|
|
369
|
-
home:
|
|
370
|
-
bin:
|
|
495
|
+
var recordSchema = z8.object({
|
|
496
|
+
format: z8.literal(1),
|
|
497
|
+
home: z8.string(),
|
|
498
|
+
bin: z8.string(),
|
|
371
499
|
current: bundleId,
|
|
372
500
|
version: releaseVersion,
|
|
373
|
-
launchers:
|
|
374
|
-
previousLaunchers:
|
|
375
|
-
pathChanges:
|
|
501
|
+
launchers: z8.record(z8.string()),
|
|
502
|
+
previousLaunchers: z8.record(z8.string()).optional(),
|
|
503
|
+
pathChanges: z8.array(pathChangeSchema).optional(),
|
|
376
504
|
updates: updatePolicySchema.optional(),
|
|
377
|
-
previous:
|
|
378
|
-
pending:
|
|
505
|
+
previous: z8.object({ id: bundleId, version: releaseVersion }).optional(),
|
|
506
|
+
pending: z8.object({ id: bundleId, version: releaseVersion, policyRevision: z8.string() }).optional()
|
|
379
507
|
});
|
|
380
508
|
async function readInstallation(home) {
|
|
381
509
|
const raw = await readStoreJson(home, "install.json");
|
|
382
|
-
if (!raw)
|
|
510
|
+
if (!raw)
|
|
511
|
+
throw new Error(
|
|
512
|
+
"Run this command from a standalone installation. npm users can upgrade with npm."
|
|
513
|
+
);
|
|
383
514
|
const record = recordSchema.parse(raw);
|
|
384
|
-
if (record.home !== await
|
|
515
|
+
if (record.home !== await fs6.realpath(home))
|
|
516
|
+
throw new Error("Invalid standalone installation receipt.");
|
|
385
517
|
return record;
|
|
386
518
|
}
|
|
387
519
|
function standaloneLocation() {
|
|
388
|
-
const bundle =
|
|
389
|
-
const home =
|
|
390
|
-
if (
|
|
520
|
+
const bundle = path6.resolve(path6.dirname(fileURLToPath(import.meta.url)), "../..");
|
|
521
|
+
const home = path6.dirname(path6.dirname(bundle));
|
|
522
|
+
if (path6.dirname(bundle) !== path6.join(home, "versions") || !/^[a-f0-9]{24}$/.test(path6.basename(bundle))) {
|
|
391
523
|
return null;
|
|
392
524
|
}
|
|
393
525
|
return { home, bundle };
|
|
394
526
|
}
|
|
395
527
|
|
|
396
528
|
// 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
|
-
|
|
529
|
+
import fs7 from "fs/promises";
|
|
530
|
+
import path7 from "path";
|
|
531
|
+
import { createHash as createHash4 } from "crypto";
|
|
532
|
+
import { z as z9 } from "zod";
|
|
533
|
+
var targets = [
|
|
534
|
+
"darwin-arm64",
|
|
535
|
+
"darwin-x64",
|
|
536
|
+
"linux-arm64",
|
|
537
|
+
"linux-x64",
|
|
538
|
+
"win32-arm64",
|
|
539
|
+
"win32-x64"
|
|
540
|
+
];
|
|
541
|
+
var digest2 = z9.string().regex(/^[a-f0-9]{64}$/);
|
|
542
|
+
var bundleSchema = z9.object({
|
|
543
|
+
format: z9.literal(1),
|
|
544
|
+
version: z9.string().regex(/^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/),
|
|
545
|
+
target: z9.enum(targets),
|
|
546
|
+
nodeVersion: z9.string(),
|
|
547
|
+
files: z9.record(digest2)
|
|
409
548
|
}).strict();
|
|
410
549
|
|
|
411
550
|
// src/distribution/trust.ts
|
|
412
551
|
import tls from "tls";
|
|
413
552
|
function configureSystemTrust() {
|
|
414
553
|
if (process.env.NODE_USE_SYSTEM_CA === "0") return;
|
|
415
|
-
if (typeof tls.getCACertificates !== "function" || typeof tls.setDefaultCACertificates !== "function")
|
|
554
|
+
if (typeof tls.getCACertificates !== "function" || typeof tls.setDefaultCACertificates !== "function")
|
|
555
|
+
return;
|
|
416
556
|
tls.setDefaultCACertificates([
|
|
417
557
|
...tls.getCACertificates("default"),
|
|
418
558
|
...tls.getCACertificates("system")
|
|
@@ -420,7 +560,11 @@ function configureSystemTrust() {
|
|
|
420
560
|
}
|
|
421
561
|
|
|
422
562
|
// src/distribution/runtime.ts
|
|
423
|
-
var leaseSchema =
|
|
563
|
+
var leaseSchema = z10.object({
|
|
564
|
+
pid: z10.number().int().positive(),
|
|
565
|
+
host: z10.string(),
|
|
566
|
+
bundle: z10.string().regex(/^[a-f0-9]{24}$/)
|
|
567
|
+
});
|
|
424
568
|
async function registerRuntime() {
|
|
425
569
|
const location = standaloneLocation();
|
|
426
570
|
if (!location) return;
|
|
@@ -429,8 +573,12 @@ async function registerRuntime() {
|
|
|
429
573
|
const name = `runtimes/${randomUUID3()}.json`;
|
|
430
574
|
await withLock(home, ".install-lock", async () => {
|
|
431
575
|
await readInstallation(home);
|
|
432
|
-
await
|
|
433
|
-
await writeStoreJson(home, name, {
|
|
576
|
+
await fs8.access(bundle);
|
|
577
|
+
await writeStoreJson(home, name, {
|
|
578
|
+
pid: process.pid,
|
|
579
|
+
host: os4.hostname(),
|
|
580
|
+
bundle: path8.basename(bundle)
|
|
581
|
+
});
|
|
434
582
|
});
|
|
435
583
|
const file = await storePath(home, name);
|
|
436
584
|
process.once("exit", () => {
|