mason-context 0.17.3 → 0.18.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 +21 -0
- package/dist/mason-audit.js +304 -222
- package/dist/mason-audit.js.map +1 -1
- package/dist/mason-auto.js +339 -253
- package/dist/mason-auto.js.map +1 -1
- package/dist/mason-drift.js +54 -22
- package/dist/mason-drift.js.map +1 -1
- package/dist/mason-hook.js +55 -22
- package/dist/mason-hook.js.map +1 -1
- package/dist/mason-mcp.js +831 -603
- package/dist/mason-mcp.js.map +1 -1
- package/dist/mason-review.js +63 -30
- package/dist/mason-review.js.map +1 -1
- package/dist/mason.js +372 -286
- package/dist/mason.js.map +1 -1
- package/package.json +1 -1
package/dist/mason-hook.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/hook/hook.ts
|
|
4
|
-
import
|
|
4
|
+
import fs6 from "fs/promises";
|
|
5
5
|
import path10 from "path";
|
|
6
|
-
import
|
|
6
|
+
import os2 from "os";
|
|
7
7
|
|
|
8
8
|
// src/decisions/decisions.ts
|
|
9
|
-
import
|
|
9
|
+
import fs4 from "fs/promises";
|
|
10
10
|
import path7 from "path";
|
|
11
11
|
import { createHash } from "crypto";
|
|
12
12
|
import { z as z3 } from "zod";
|
|
@@ -34,14 +34,48 @@ function matchingPaths(anchors, files) {
|
|
|
34
34
|
return [...new Set(files)].filter((file) => anchors.some((anchor) => anchorMatches(anchor, file)));
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
+
// src/utils/git-read.ts
|
|
38
|
+
import { execFile } from "child_process";
|
|
39
|
+
import { promisify } from "util";
|
|
40
|
+
|
|
41
|
+
// src/utils/profile.ts
|
|
42
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
43
|
+
var profiles = new AsyncLocalStorage();
|
|
44
|
+
async function profilePhase(label, run) {
|
|
45
|
+
const phases = profiles.getStore();
|
|
46
|
+
if (!phases) return run();
|
|
47
|
+
const start = performance.now();
|
|
48
|
+
try {
|
|
49
|
+
return await run();
|
|
50
|
+
} finally {
|
|
51
|
+
const timing = phases[label] ??= { calls: 0, totalMs: 0 };
|
|
52
|
+
timing.calls++;
|
|
53
|
+
timing.totalMs += performance.now() - start;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// src/utils/git-read.ts
|
|
58
|
+
var execute = promisify(execFile);
|
|
59
|
+
var commands = /* @__PURE__ */ new Set(["rev-parse", "symbolic-ref", "for-each-ref", "ls-files", "check-ignore", "status", "log", "diff", "ls-tree", "show", "merge-base"]);
|
|
60
|
+
function execGit(args, options) {
|
|
61
|
+
const command = args.find((arg) => !arg.startsWith("-")) ?? "other";
|
|
62
|
+
return profilePhase("git." + (commands.has(command) ? command : "other"), async () => {
|
|
63
|
+
const { input, ...processOptions } = options;
|
|
64
|
+
const operation = execute("git", args, processOptions);
|
|
65
|
+
if (input !== void 0) {
|
|
66
|
+
operation.child.stdin.on("error", () => {
|
|
67
|
+
});
|
|
68
|
+
operation.child.stdin.end(input);
|
|
69
|
+
}
|
|
70
|
+
return operation;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
37
74
|
// src/utils/files.ts
|
|
38
75
|
import fs from "fs/promises";
|
|
39
76
|
import { constants } from "fs";
|
|
40
77
|
import path2 from "path";
|
|
41
|
-
import { execFile } from "child_process";
|
|
42
|
-
import { promisify } from "util";
|
|
43
78
|
import fg from "fast-glob";
|
|
44
|
-
var exec = promisify(execFile);
|
|
45
79
|
var SOURCE_EXTENSIONS = ["ts", "tsx", "js", "jsx", "mts", "cts", "mjs", "cjs", "vue", "svelte", "kt", "kts", "java", "py", "go", "rs", "swift", "rb", "cs", "cpp", "c", "h", "hpp", "dart", "php"];
|
|
46
80
|
var SOURCE_GLOB = `**/*.{${SOURCE_EXTENSIONS.join(",")}}`;
|
|
47
81
|
var MAX_SOURCE_BYTES = 1024 * 1024;
|
|
@@ -105,20 +139,22 @@ async function readStoreJson(root, relative) {
|
|
|
105
139
|
|
|
106
140
|
// src/snapshot/snapshot.ts
|
|
107
141
|
import path5 from "path";
|
|
108
|
-
import { execFile as execFile2 } from "child_process";
|
|
109
|
-
import { promisify as promisify2 } from "util";
|
|
110
142
|
import { z } from "zod";
|
|
111
143
|
|
|
144
|
+
// src/utils/store-lock.ts
|
|
145
|
+
import fs3 from "fs/promises";
|
|
146
|
+
import os from "os";
|
|
147
|
+
|
|
112
148
|
// src/test-map.ts
|
|
113
149
|
import path4 from "path";
|
|
114
150
|
|
|
115
151
|
// src/snapshot/snapshot.ts
|
|
116
|
-
var exec2 = promisify2(execFile2);
|
|
117
152
|
var repoPath = z.string().refine((value) => normalizeRepoPath(value) !== null, "Expected a relative repository path");
|
|
118
153
|
var verificationFields = {
|
|
119
154
|
refreshedHash: z.string().optional(),
|
|
120
155
|
verifiedAt: z.string().optional(),
|
|
121
156
|
verifiedHash: z.string().optional(),
|
|
157
|
+
verificationToken: z.string().optional(),
|
|
122
158
|
verificationFailed: z.boolean().optional(),
|
|
123
159
|
verificationNote: z.string().optional()
|
|
124
160
|
};
|
|
@@ -140,7 +176,7 @@ var snapshotSchema = z.object({
|
|
|
140
176
|
}).passthrough();
|
|
141
177
|
async function getCurrentGitHash(rootDir) {
|
|
142
178
|
try {
|
|
143
|
-
const { stdout } = await
|
|
179
|
+
const { stdout } = await execGit(["rev-parse", "HEAD"], {
|
|
144
180
|
cwd: rootDir
|
|
145
181
|
});
|
|
146
182
|
return stdout.trim();
|
|
@@ -338,7 +374,7 @@ async function loadDecisionStore(rootDir) {
|
|
|
338
374
|
const diagnostics = [];
|
|
339
375
|
let entries;
|
|
340
376
|
try {
|
|
341
|
-
entries = await
|
|
377
|
+
entries = await fs4.readdir(await storePath(rootDir, ".mason/decisions"));
|
|
342
378
|
} catch (error) {
|
|
343
379
|
if (error.code !== "ENOENT") diagnostics.push({ path: ".mason/decisions", message: String(error) });
|
|
344
380
|
return { records, diagnostics };
|
|
@@ -364,11 +400,8 @@ import { createHash as createHash2 } from "crypto";
|
|
|
364
400
|
import path9 from "path";
|
|
365
401
|
|
|
366
402
|
// src/drift/drift.ts
|
|
367
|
-
import
|
|
403
|
+
import fs5 from "fs/promises";
|
|
368
404
|
import path8 from "path";
|
|
369
|
-
import { execFile as execFile3 } from "child_process";
|
|
370
|
-
import { promisify as promisify3 } from "util";
|
|
371
|
-
var exec3 = promisify3(execFile3);
|
|
372
405
|
function parseChanges(output) {
|
|
373
406
|
const fields = output.split("\0");
|
|
374
407
|
const changes = [];
|
|
@@ -389,7 +422,7 @@ function touchedPaths(changes) {
|
|
|
389
422
|
async function getChangesWithStatus(resolvedRoot, fromHash, toHash = "HEAD") {
|
|
390
423
|
if (!fromHash || fromHash === "unknown" || fromHash.startsWith("-") || !toHash || toHash === "unknown" || toHash.startsWith("-")) return null;
|
|
391
424
|
try {
|
|
392
|
-
const { stdout } = await
|
|
425
|
+
const { stdout } = await execGit(["diff", "--name-status", "-z", "-M", fromHash, toHash, "--"], { cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 });
|
|
393
426
|
return parseChanges(stdout);
|
|
394
427
|
} catch {
|
|
395
428
|
return null;
|
|
@@ -398,8 +431,8 @@ async function getChangesWithStatus(resolvedRoot, fromHash, toHash = "HEAD") {
|
|
|
398
431
|
async function getWorkingTree(resolvedRoot) {
|
|
399
432
|
try {
|
|
400
433
|
const [diff, untracked] = await Promise.all([
|
|
401
|
-
|
|
402
|
-
|
|
434
|
+
execGit(["diff", "--name-status", "-z", "-M", "HEAD", "--"], { cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 }),
|
|
435
|
+
execGit(["ls-files", "-z", "--others", "--exclude-standard"], { cwd: resolvedRoot, maxBuffer: 10 * 1024 * 1024 })
|
|
403
436
|
]);
|
|
404
437
|
const untrackedFiles = untracked.stdout.split("\0").filter((f) => f && !f.startsWith(".mason/"));
|
|
405
438
|
return { available: true, changedFiles: [.../* @__PURE__ */ new Set([...touchedPaths(parseChanges(diff.stdout)), ...untrackedFiles])].sort(), untrackedFiles };
|
|
@@ -445,7 +478,7 @@ var MAX_WALK_UP = 30;
|
|
|
445
478
|
var SUPPORTED_TOOLS = /* @__PURE__ */ new Set(["Read", "Edit", "Write"]);
|
|
446
479
|
async function exists(p) {
|
|
447
480
|
try {
|
|
448
|
-
await
|
|
481
|
+
await fs6.access(p);
|
|
449
482
|
return true;
|
|
450
483
|
} catch {
|
|
451
484
|
return false;
|
|
@@ -474,7 +507,7 @@ function stateKey(input) {
|
|
|
474
507
|
}
|
|
475
508
|
async function loadInjected(stateFile) {
|
|
476
509
|
try {
|
|
477
|
-
const parsed = JSON.parse(await
|
|
510
|
+
const parsed = JSON.parse(await fs6.readFile(stateFile, "utf-8"));
|
|
478
511
|
return new Set(Array.isArray(parsed) ? parsed.filter((x) => typeof x === "string") : []);
|
|
479
512
|
} catch {
|
|
480
513
|
return /* @__PURE__ */ new Set();
|
|
@@ -515,7 +548,7 @@ async function runHook(stdinText, env = {}) {
|
|
|
515
548
|
const relPath = path10.relative(root, absPath).split(path10.sep).join("/");
|
|
516
549
|
if (relPath.startsWith("..")) return null;
|
|
517
550
|
const { records } = await loadDecisionStore(root);
|
|
518
|
-
const stateDir = env.stateDir ??
|
|
551
|
+
const stateDir = env.stateDir ?? os2.tmpdir();
|
|
519
552
|
const stateFile = path10.join(stateDir, `mason-hook-${createHash2("sha256").update(root).digest("hex").slice(0, 12)}-${stateKey(input)}.json`);
|
|
520
553
|
const injected = await loadInjected(stateFile);
|
|
521
554
|
const recordKey = (record) => `${record.id}:${createHash2("sha256").update(JSON.stringify(record)).digest("hex")}`;
|
|
@@ -533,7 +566,7 @@ async function runHook(stdinText, env = {}) {
|
|
|
533
566
|
const drift = await computeDecisionDrift(root, selected);
|
|
534
567
|
for (const record of selected) injected.add(recordKey(record));
|
|
535
568
|
try {
|
|
536
|
-
await
|
|
569
|
+
await fs6.writeFile(stateFile, JSON.stringify([...injected]), "utf-8");
|
|
537
570
|
} catch {
|
|
538
571
|
}
|
|
539
572
|
return JSON.stringify({
|