mason-context 0.18.0 → 0.19.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 +9 -0
- package/README.md +2 -0
- package/dist/mason-audit.js +20 -1
- package/dist/mason-audit.js.map +1 -1
- package/dist/mason-auto.js +111 -36
- package/dist/mason-auto.js.map +1 -1
- package/dist/mason-drift.js +1 -0
- package/dist/mason-drift.js.map +1 -1
- package/dist/mason-hook.js +1 -0
- package/dist/mason-hook.js.map +1 -1
- package/dist/mason-mcp.js +765 -125
- package/dist/mason-mcp.js.map +1 -1
- package/dist/mason-review.js +1 -0
- package/dist/mason-review.js.map +1 -1
- package/dist/mason-runtime.js +337 -0
- package/dist/mason-runtime.js.map +1 -0
- package/dist/mason.js +910 -229
- package/dist/mason.js.map +1 -1
- package/package.json +2 -1
package/dist/mason-auto.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
if (!import.meta.url.endsWith("/mason-runtime.js")) await import("./mason-runtime.js").then(m => m.registerRuntime());
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
5
|
var __esm = (fn, res) => function __init() {
|
|
@@ -1987,6 +1988,10 @@ var init_release_metadata = __esm({
|
|
|
1987
1988
|
});
|
|
1988
1989
|
|
|
1989
1990
|
// src/audit/checks/deps-changed.ts
|
|
1991
|
+
function hasDependencyContent(content2) {
|
|
1992
|
+
const text2 = content2.replace(/<!-- mason:start -->[\s\S]*?<!-- mason:end -->/g, "").replace(/<!--[\s\S]*?-->/g, "");
|
|
1993
|
+
return /\b(?:dependenc(?:y|ies)|librar(?:y|ies)|frameworks?|tech(?:nology)? stack|prerequisites|requirements)\b/i.test(text2) || /\b(?:package\.json|build\.gradle(?:\.kts)?|settings\.gradle(?:\.kts)?|libs\.versions\.toml|Cargo\.toml|go\.mod|pyproject\.toml|requirements\.txt|Gemfile|composer\.json)\b/i.test(text2) || /\b(?:node(?:\.js)?|npm|pnpm|yarn|bun|deno|python|ruby|rust|go|java|jdk|kotlin|gradle|swift|php|react|vue|angular|compose|ktor|room)\s*(?:version\s*)?[`*:=>~^v\s-]*\d+(?:\.\d+)*\b/i.test(text2) || /\b(?:npm|pnpm|yarn|pip3?|cargo|gem|composer)\s+(?:install|add|require)\b/i.test(text2);
|
|
1994
|
+
}
|
|
1990
1995
|
function manifestPathspecs(doc) {
|
|
1991
1996
|
const scope = documentScope(doc);
|
|
1992
1997
|
if (scope === ".") return MANIFEST_PATHSPECS;
|
|
@@ -2013,6 +2018,19 @@ async function checkDepsChanged(ctx) {
|
|
|
2013
2018
|
reason: `${doc.path} has uncommitted edits \u2013 suppressed while in flight`
|
|
2014
2019
|
});
|
|
2015
2020
|
}
|
|
2021
|
+
let content2 = doc.content;
|
|
2022
|
+
if (doc.dirty) {
|
|
2023
|
+
try {
|
|
2024
|
+
content2 = (await inspectionGit(
|
|
2025
|
+
["show", `${doc.lastCommit.hash}:${doc.path}`],
|
|
2026
|
+
{ cwd: ctx.root, maxBuffer: 10 * 1024 * 1024, timeout: 1e4 }
|
|
2027
|
+
)).stdout;
|
|
2028
|
+
} catch {
|
|
2029
|
+
result.skipped.push({ check: "deps-changed", doc: doc.path, reason: `${doc.path}: committed dependency content is unavailable` });
|
|
2030
|
+
continue;
|
|
2031
|
+
}
|
|
2032
|
+
}
|
|
2033
|
+
if (!hasDependencyContent(content2)) continue;
|
|
2016
2034
|
const range = await commitsTouchingSince(
|
|
2017
2035
|
ctx.root,
|
|
2018
2036
|
doc.lastCommit.hash,
|
|
@@ -2058,6 +2076,7 @@ var init_deps_changed = __esm({
|
|
|
2058
2076
|
init_docs();
|
|
2059
2077
|
init_release_metadata();
|
|
2060
2078
|
init_git();
|
|
2079
|
+
init_inspection();
|
|
2061
2080
|
init_checks();
|
|
2062
2081
|
MANIFEST_COMMITS_CAP = 10;
|
|
2063
2082
|
MANIFEST_PATHSPECS = [
|
|
@@ -2953,7 +2972,7 @@ async function verifyOriginal(rootDir, baselinePath, options, session) {
|
|
|
2953
2972
|
return {
|
|
2954
2973
|
...base,
|
|
2955
2974
|
status: "review-required",
|
|
2956
|
-
reason: "An audit cannot establish that this advisory was reviewed. Retain its original evidence and report a separate assessment; editing or committing the doc is not approval."
|
|
2975
|
+
reason: (now ? "The current check still reports this advisory. " : finding.type === "deps-changed" ? "The current check no longer reports this condition; the historical advisory remains awaiting assessment. " : "The current check no longer reports the original finding; retained evidence still requires assessment. ") + "An audit cannot establish that this advisory was reviewed. Retain its original evidence and report a separate assessment; editing or committing the doc is not approval."
|
|
2957
2976
|
};
|
|
2958
2977
|
}
|
|
2959
2978
|
return { ...base, status: "resolved", reason: "The original check ran and no longer reports this claim. Inspect the edit for semantic correctness." };
|
|
@@ -3131,7 +3150,7 @@ async function collectInputs(root) {
|
|
|
3131
3150
|
git3(root, "status", "--porcelain=v1", "-z", "--untracked-files=all", "--", ".", ":(exclude).mason/reports"),
|
|
3132
3151
|
git3(root, "ls-files", "--stage", "-z", "--", ".", ":(exclude).mason/reports")
|
|
3133
3152
|
]) : ["", ""];
|
|
3134
|
-
const common = [
|
|
3153
|
+
const common = [6, engineVersion, head, shallow, replacements, docContents];
|
|
3135
3154
|
const keys = {
|
|
3136
3155
|
"deleted-reference": hash([common, claims, docStatus]),
|
|
3137
3156
|
"new-module": hash([common, modules]),
|
|
@@ -3191,7 +3210,7 @@ var init_evidence = __esm({
|
|
|
3191
3210
|
init_dead_command();
|
|
3192
3211
|
init_storage();
|
|
3193
3212
|
init_advisory_review();
|
|
3194
|
-
engineVersion = true ? "0.
|
|
3213
|
+
engineVersion = true ? "0.19.0" : "development";
|
|
3195
3214
|
hash = (value) => createHash3("sha256").update(JSON.stringify(value)).digest("hex");
|
|
3196
3215
|
content = readAuditInput;
|
|
3197
3216
|
cacheSchema = z8.object({ version: z8.literal(1), entries: z8.record(z8.object({ key: z8.string(), result: checkResultSchema })), digest: z8.string() });
|
|
@@ -3405,13 +3424,17 @@ async function observeReadOnlyTool(dir, event) {
|
|
|
3405
3424
|
}
|
|
3406
3425
|
function summarize(report) {
|
|
3407
3426
|
const open = report.findings.filter((f) => f.status !== "resolved");
|
|
3427
|
+
const onlyReview = report.status === "incomplete" && !report.diagnostics.length && !report.counts.unresolved && !report.counts.unverified && report.counts["review-required"] > 0;
|
|
3408
3428
|
return [
|
|
3409
|
-
`Mason: ${report.status}; ${report.counts.unresolved} unresolved, ${report.counts["review-required"]} need review, ${report.counts.unverified} unverified.`,
|
|
3410
|
-
...open.slice(0, 4).map((f) =>
|
|
3429
|
+
onlyReview ? `Mason: ${report.counts["review-required"]} advisor${report.counts["review-required"] === 1 ? "y" : "ies"} awaiting review; no unresolved issues.` : `Mason: ${report.status}; ${report.counts.unresolved} unresolved, ${report.counts["review-required"]} need review, ${report.counts.unverified} unverified.`,
|
|
3430
|
+
...open.slice(0, 4).map((f) => {
|
|
3431
|
+
const detail = f.current ? f.current.message : f.status === "review-required" ? `${f.original.type}: current check no longer reports ${f.original.type === "deps-changed" ? "this condition" : "the original finding"}; historical evidence awaits assessment.` : `Original evidence: ${f.original.message}. ${f.reason}`;
|
|
3432
|
+
return `[${f.status}] ${cleanText(f.original.anchor.doc)}: ${cleanText(detail)}`;
|
|
3433
|
+
}),
|
|
3411
3434
|
...open.length > 4 ? [`${open.length - 4} more findings in the report.`] : [],
|
|
3412
3435
|
...report.diagnostics.slice(0, 2).map(cleanText),
|
|
3413
3436
|
`Evidence: ${report.reportPath}. Resume/check with mason_automation(action: "check") or mason-auto check.`,
|
|
3414
|
-
"Keep original evidence. Address findings relevant to the authorized task; report unrelated findings and
|
|
3437
|
+
"Keep original evidence. Address findings relevant to the authorized task; report unrelated findings with a brief scope reason and suggested follow-up. Use review_advisory for authorized assessments; otherwise leave advisories open without approving them."
|
|
3415
3438
|
].join("\n");
|
|
3416
3439
|
}
|
|
3417
3440
|
async function loadState(ws) {
|
|
@@ -3635,7 +3658,7 @@ async function automate(dir, event) {
|
|
|
3635
3658
|
if (event.event === "after_tool" && event.mutating) {
|
|
3636
3659
|
session.mutationObserved = true;
|
|
3637
3660
|
if (!event.toolId || !session.pending[event.toolId]) {
|
|
3638
|
-
const gap = "A tool completed without an observed matching pre-tool capture; pre-edit coverage is unknown.";
|
|
3661
|
+
const gap = "A tool completed without an observed matching pre-tool capture in this checkout; pre-edit coverage is unknown. The tool may have changed checkouts; captures are kept separately for each worktree.";
|
|
3639
3662
|
if (!session.coverageGaps.includes(gap)) session.coverageGaps.push(gap);
|
|
3640
3663
|
}
|
|
3641
3664
|
if (event.toolId) delete session.pending[event.toolId];
|
|
@@ -3778,11 +3801,39 @@ var init_hook_root = __esm({
|
|
|
3778
3801
|
|
|
3779
3802
|
// src/setup/model.ts
|
|
3780
3803
|
import { z as z11 } from "zod";
|
|
3804
|
+
import fs16 from "fs/promises";
|
|
3805
|
+
import path23 from "path";
|
|
3781
3806
|
async function loadSetup(root) {
|
|
3782
3807
|
const raw = await readStoreJson(root, SETUP_PATH);
|
|
3783
3808
|
if (raw === null) return null;
|
|
3784
3809
|
return setupSchema.parse(raw);
|
|
3785
3810
|
}
|
|
3811
|
+
async function effectiveSetup(root) {
|
|
3812
|
+
const local = await loadSetup(root);
|
|
3813
|
+
if (local) return { root, setup: local };
|
|
3814
|
+
const common = await fs16.realpath(path23.resolve(root, (await git3(root, "rev-parse", "--git-common-dir")).trim()));
|
|
3815
|
+
const own = await fs16.realpath((await git3(root, "rev-parse", "--absolute-git-dir")).trim());
|
|
3816
|
+
if (common === own) return { root, setup: null };
|
|
3817
|
+
const primary = (await git3(root, "worktree", "list", "--porcelain", "-z")).split("\0\0")[0].split("\0");
|
|
3818
|
+
const candidate = primary.find((field) => field.startsWith("worktree "))?.slice(9);
|
|
3819
|
+
if (!candidate || primary.includes("bare")) return { root, setup: null };
|
|
3820
|
+
let inheritedRoot;
|
|
3821
|
+
try {
|
|
3822
|
+
inheritedRoot = await fs16.realpath((await git3(candidate, "rev-parse", "--show-toplevel")).trim());
|
|
3823
|
+
} catch (error) {
|
|
3824
|
+
if (/must be run in a work tree/.test(String(error.stderr))) return { root, setup: null };
|
|
3825
|
+
throw error;
|
|
3826
|
+
}
|
|
3827
|
+
const inheritedCommon = await fs16.realpath(path23.resolve(
|
|
3828
|
+
inheritedRoot,
|
|
3829
|
+
(await git3(inheritedRoot, "rev-parse", "--git-common-dir")).trim()
|
|
3830
|
+
));
|
|
3831
|
+
if (inheritedCommon !== common) throw new Error("Linked worktree setup does not belong to the same Git repository.");
|
|
3832
|
+
const setup = await loadSetup(inheritedRoot);
|
|
3833
|
+
const inactive = await readStoreJson(root, INACTIVE_HOSTS_PATH);
|
|
3834
|
+
if (inactive && setup) for (const host of inactiveHostsSchema.parse(inactive).hosts) delete setup.hosts[host];
|
|
3835
|
+
return { root: inheritedRoot, setup };
|
|
3836
|
+
}
|
|
3786
3837
|
async function loadSetupReceipt(root, directory, host) {
|
|
3787
3838
|
const raw = await readStoreJson(root, directory + "/setup-" + host + ".json");
|
|
3788
3839
|
if (raw === null) return null;
|
|
@@ -3790,10 +3841,11 @@ async function loadSetupReceipt(root, directory, host) {
|
|
|
3790
3841
|
if (receipt.root !== root || receipt.host !== host) throw new Error("Setup receipt belongs to another installation.");
|
|
3791
3842
|
return receipt;
|
|
3792
3843
|
}
|
|
3793
|
-
var setupHostSchema, setupSchema, SETUP_PATH, receiptSchema;
|
|
3844
|
+
var setupHostSchema, setupSchema, SETUP_PATH, INACTIVE_HOSTS_PATH, inactiveHostsSchema, receiptSchema;
|
|
3794
3845
|
var init_model = __esm({
|
|
3795
3846
|
"src/setup/model.ts"() {
|
|
3796
3847
|
"use strict";
|
|
3848
|
+
init_evidence();
|
|
3797
3849
|
init_storage();
|
|
3798
3850
|
setupHostSchema = z11.object({
|
|
3799
3851
|
configuredVersion: z11.string(),
|
|
@@ -3807,6 +3859,8 @@ var init_model = __esm({
|
|
|
3807
3859
|
claude: setupHostSchema.optional()
|
|
3808
3860
|
}) });
|
|
3809
3861
|
SETUP_PATH = ".mason/local/setup.json";
|
|
3862
|
+
INACTIVE_HOSTS_PATH = ".mason/local/inactive-hosts.json";
|
|
3863
|
+
inactiveHostsSchema = z11.object({ version: z11.literal(1), hosts: z11.array(z11.enum(["claude", "codex"])) });
|
|
3810
3864
|
receiptSchema = z11.object({
|
|
3811
3865
|
version: z11.literal(1),
|
|
3812
3866
|
host: z11.enum(["codex", "claude"]),
|
|
@@ -3833,7 +3887,7 @@ __export(launcher_exports, {
|
|
|
3833
3887
|
});
|
|
3834
3888
|
import { execFile as execFile2 } from "child_process";
|
|
3835
3889
|
import { promisify as promisify2 } from "util";
|
|
3836
|
-
import
|
|
3890
|
+
import fs17 from "fs/promises";
|
|
3837
3891
|
function globalCommand(args, platform = process.platform) {
|
|
3838
3892
|
return platform === "win32" ? { command: "cmd.exe", args: ["/d", "/s", "/c", "mason", ...args] } : { command: "mason", args };
|
|
3839
3893
|
}
|
|
@@ -3853,8 +3907,8 @@ async function installedCommand() {
|
|
|
3853
3907
|
}
|
|
3854
3908
|
}
|
|
3855
3909
|
async function prepareLaunch(host, options = {}) {
|
|
3856
|
-
const root = await
|
|
3857
|
-
const entry = (await
|
|
3910
|
+
const root = await fs17.realpath((await git3(options.dir ?? process.cwd(), "rev-parse", "--show-toplevel")).trim());
|
|
3911
|
+
const entry = (await effectiveSetup(root)).setup?.hosts[host];
|
|
3858
3912
|
process.env.MASON_SETUP_ROOT = root;
|
|
3859
3913
|
process.env.MASON_SETUP_HOST = host;
|
|
3860
3914
|
delete process.env.MASON_SETUP_REVISION;
|
|
@@ -3876,7 +3930,7 @@ var init_launcher = __esm({
|
|
|
3876
3930
|
"use strict";
|
|
3877
3931
|
init_evidence();
|
|
3878
3932
|
init_model();
|
|
3879
|
-
executingVersion = () => true ? "0.
|
|
3933
|
+
executingVersion = () => true ? "0.19.0" : "development";
|
|
3880
3934
|
mcpCommand = (host) => globalCommand(["--setup-host", host, "mcp"]);
|
|
3881
3935
|
hookCommand = (host) => `mason --setup-host ${host} auto`;
|
|
3882
3936
|
}
|
|
@@ -3889,7 +3943,7 @@ __export(observations_exports, {
|
|
|
3889
3943
|
observeActivation: () => observeActivation,
|
|
3890
3944
|
readObservation: () => readObservation
|
|
3891
3945
|
});
|
|
3892
|
-
import
|
|
3946
|
+
import fs18 from "fs/promises";
|
|
3893
3947
|
import { z as z12 } from "zod";
|
|
3894
3948
|
function observationPath(directory, host, revision, version = executingVersion()) {
|
|
3895
3949
|
return `${directory}/activation/${host}-${revision}-${hash(version).slice(0, 12)}.json`;
|
|
@@ -3906,15 +3960,15 @@ async function observeActivation(dir, event, options = {}) {
|
|
|
3906
3960
|
if (host !== "codex" && host !== "claude" || !process.env.MASON_SETUP_ROOT) return null;
|
|
3907
3961
|
try {
|
|
3908
3962
|
if (!revision) {
|
|
3909
|
-
if ((await
|
|
3963
|
+
if ((await effectiveSetup(process.env.MASON_SETUP_ROOT)).setup?.hosts[host]) {
|
|
3910
3964
|
return "Mason setup is now present. Restart the assistant to connect this MCP session to the configured integration; activation has not been established by this session.";
|
|
3911
3965
|
}
|
|
3912
3966
|
return inactiveSetupMessage();
|
|
3913
3967
|
}
|
|
3914
3968
|
const capturedDirectory = options.directory?.match(/^\.mason\/reports\/automation\/[a-f0-9]{24}$/)?.[0] ?? options.reportPath?.match(/^(\.mason\/reports\/automation\/[a-f0-9]{24})\/checks\//)?.[1];
|
|
3915
|
-
const ws = capturedDirectory ? { root: await
|
|
3916
|
-
if (ws.root !== await
|
|
3917
|
-
const setup = await
|
|
3969
|
+
const ws = capturedDirectory ? { root: await fs18.realpath(dir), directory: capturedDirectory } : await workspace(dir);
|
|
3970
|
+
if (ws.root !== await fs18.realpath(process.env.MASON_SETUP_ROOT)) return null;
|
|
3971
|
+
const { setup } = await effectiveSetup(ws.root);
|
|
3918
3972
|
if (setup?.hosts[host]?.revision !== revision) return "Mason setup changed; restart the assistant to observe the current integration.";
|
|
3919
3973
|
const directory = ws.directory + "/activation";
|
|
3920
3974
|
await withLock(ws.root, directory, async () => {
|
|
@@ -4091,8 +4145,8 @@ __export(files_exports, {
|
|
|
4091
4145
|
managedBlock: () => managedBlock,
|
|
4092
4146
|
readText: () => readText
|
|
4093
4147
|
});
|
|
4094
|
-
import
|
|
4095
|
-
import
|
|
4148
|
+
import fs19 from "fs/promises";
|
|
4149
|
+
import path24 from "path";
|
|
4096
4150
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
4097
4151
|
async function readText(root, file) {
|
|
4098
4152
|
try {
|
|
@@ -4121,14 +4175,14 @@ async function applyEdit(root, edit) {
|
|
|
4121
4175
|
if (edit.after === null) {
|
|
4122
4176
|
const file2 = await storePath(root, edit.path);
|
|
4123
4177
|
if (await readText(root, edit.path) !== edit.before) throw new Error("Input changed during removal: " + edit.path);
|
|
4124
|
-
await
|
|
4178
|
+
await fs19.unlink(file2);
|
|
4125
4179
|
return true;
|
|
4126
4180
|
}
|
|
4127
4181
|
const file = await storePath(root, edit.path, true);
|
|
4128
|
-
const temporary =
|
|
4182
|
+
const temporary = path24.join(path24.dirname(file), ".mason-setup-" + randomUUID5() + ".tmp");
|
|
4129
4183
|
try {
|
|
4130
|
-
const mode = await
|
|
4131
|
-
const handle = await
|
|
4184
|
+
const mode = await fs19.stat(file).then((s) => s.mode & 511, () => 384);
|
|
4185
|
+
const handle = await fs19.open(temporary, "wx", mode);
|
|
4132
4186
|
try {
|
|
4133
4187
|
await handle.writeFile(edit.after, "utf8");
|
|
4134
4188
|
await handle.sync();
|
|
@@ -4136,10 +4190,10 @@ async function applyEdit(root, edit) {
|
|
|
4136
4190
|
await handle.close();
|
|
4137
4191
|
}
|
|
4138
4192
|
if (await readText(root, edit.path) !== edit.before) throw new Error("Integration input changed during update: " + edit.path);
|
|
4139
|
-
await
|
|
4193
|
+
await fs19.rename(temporary, file);
|
|
4140
4194
|
return true;
|
|
4141
4195
|
} finally {
|
|
4142
|
-
await
|
|
4196
|
+
await fs19.rm(temporary, { force: true });
|
|
4143
4197
|
}
|
|
4144
4198
|
}
|
|
4145
4199
|
var init_files2 = __esm({
|
|
@@ -4547,6 +4601,8 @@ __export(teardown_exports, {
|
|
|
4547
4601
|
teardownProject: () => teardownProject
|
|
4548
4602
|
});
|
|
4549
4603
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "util";
|
|
4604
|
+
import fs20 from "fs/promises";
|
|
4605
|
+
import path25 from "path";
|
|
4550
4606
|
import { parse as parse3, stringify as stringify2 } from "smol-toml";
|
|
4551
4607
|
import fg6 from "fast-glob";
|
|
4552
4608
|
import { z as z18 } from "zod";
|
|
@@ -4568,6 +4624,11 @@ async function planTeardown(root, selected) {
|
|
|
4568
4624
|
const ownership = ownershipBefore === null ? { version: 1, files: {} } : ownershipSchema.parse(JSON.parse(ownershipBefore));
|
|
4569
4625
|
const setupBefore = await read(SETUP_PATH);
|
|
4570
4626
|
const setup = setupBefore === null ? null : setupSchema.parse(JSON.parse(setupBefore));
|
|
4627
|
+
const linked = (await workspace(root)).gitDir !== await fs20.realpath(
|
|
4628
|
+
path25.resolve(root, (await git3(root, "rev-parse", "--git-common-dir")).trim())
|
|
4629
|
+
);
|
|
4630
|
+
const inactiveBefore = linked && !setup ? await read(INACTIVE_HOSTS_PATH) : null;
|
|
4631
|
+
const inactive = inactiveBefore === null ? { version: 1, hosts: [] } : inactiveHostsSchema.parse(JSON.parse(inactiveBefore));
|
|
4571
4632
|
const automationBefore = await read(AUTOMATION_PATH);
|
|
4572
4633
|
const automation = automationBefore === null ? null : recordSchema2.parse(JSON.parse(automationBefore));
|
|
4573
4634
|
const commands2 = (host) => new Set([
|
|
@@ -4711,7 +4772,16 @@ async function planTeardown(root, selected) {
|
|
|
4711
4772
|
delete ownership.files[configPath(host)];
|
|
4712
4773
|
}
|
|
4713
4774
|
if (!remainingHost) for (const file of DOC_CANDIDATES) delete ownership.files[file];
|
|
4714
|
-
if (setupBefore !== null) cleanup.push({
|
|
4775
|
+
if (setupBefore !== null) cleanup.push({
|
|
4776
|
+
path: SETUP_PATH,
|
|
4777
|
+
before: setupBefore,
|
|
4778
|
+
after: linked || Object.keys(setup.hosts).length ? json(setup) : null
|
|
4779
|
+
});
|
|
4780
|
+
else if (linked) cleanup.push({
|
|
4781
|
+
path: INACTIVE_HOSTS_PATH,
|
|
4782
|
+
before: inactiveBefore,
|
|
4783
|
+
after: json({ version: 1, hosts: [.../* @__PURE__ */ new Set([...inactive.hosts, ...selected])].sort() })
|
|
4784
|
+
});
|
|
4715
4785
|
if (automationBefore !== null) cleanup.push({ path: AUTOMATION_PATH, before: automationBefore, after: Object.keys(automation.hosts).length ? json(automation) : null });
|
|
4716
4786
|
if (ownershipBefore !== null) cleanup.push({ path: OWNERSHIP_PATH, before: ownershipBefore, after: Object.keys(ownership.files).length ? json(ownership) : null });
|
|
4717
4787
|
edits.push(...cleanup);
|
|
@@ -5152,10 +5222,10 @@ var init_check = __esm({
|
|
|
5152
5222
|
});
|
|
5153
5223
|
|
|
5154
5224
|
// src/review/evidence.ts
|
|
5155
|
-
import
|
|
5225
|
+
import path26 from "path";
|
|
5156
5226
|
import { z as z22 } from "zod";
|
|
5157
5227
|
function relativeArtifact(root, file) {
|
|
5158
|
-
const relative =
|
|
5228
|
+
const relative = path26.isAbsolute(file) ? path26.relative(root, file) : file;
|
|
5159
5229
|
const normalized = normalizeRepoPath(relative);
|
|
5160
5230
|
if (!normalized) throw new Error(`Evidence artifact must be inside the repository: ${file}`);
|
|
5161
5231
|
return normalized;
|
|
@@ -5252,7 +5322,7 @@ async function collectReviewEvidence(root, manifests, changedFiles, decisions, d
|
|
|
5252
5322
|
const report = await readStoreJson(root, file);
|
|
5253
5323
|
if (report === null) throw new Error(`Report artifact is missing: ${file}`);
|
|
5254
5324
|
const sourceRoot = check.sourceRoot ?? root;
|
|
5255
|
-
if (!
|
|
5325
|
+
if (!path26.posix.isAbsolute(sourceRoot) && !/^[A-Za-z]:[\\/]/.test(sourceRoot)) throw new Error("sourceRoot must identify the absolute checkout root on the check runner.");
|
|
5256
5326
|
const parsed = check.report.format === "vitest-json" ? parseVitest(report, sourceRoot) : check.report.format === "mason-check-json" ? parseCheck(report, sourceRoot) : parseSarif(report, sourceRoot);
|
|
5257
5327
|
result.outcome = parsed.outcome;
|
|
5258
5328
|
result.counts = parsed.counts;
|
|
@@ -5373,8 +5443,8 @@ var init_evidence2 = __esm({
|
|
|
5373
5443
|
});
|
|
5374
5444
|
|
|
5375
5445
|
// src/review/review.ts
|
|
5376
|
-
import
|
|
5377
|
-
import
|
|
5446
|
+
import fs21 from "fs/promises";
|
|
5447
|
+
import path27 from "path";
|
|
5378
5448
|
import { execFile as execFile4 } from "child_process";
|
|
5379
5449
|
import { promisify as promisify4 } from "util";
|
|
5380
5450
|
async function resolveMergeBase(resolvedRoot, base, head) {
|
|
@@ -5403,7 +5473,7 @@ function anchorsTouched(record, changedFiles) {
|
|
|
5403
5473
|
return matchingPaths(record.files, changedFiles);
|
|
5404
5474
|
}
|
|
5405
5475
|
async function computeReview(rootDir, base, options = {}) {
|
|
5406
|
-
const resolvedRoot =
|
|
5476
|
+
const resolvedRoot = path27.resolve(rootDir);
|
|
5407
5477
|
const head = await getCurrentGitHash(resolvedRoot);
|
|
5408
5478
|
if (head === "unknown") return null;
|
|
5409
5479
|
const mergeBase = await resolveMergeBase(resolvedRoot, base, head);
|
|
@@ -5453,7 +5523,7 @@ async function computeReview(rootDir, base, options = {}) {
|
|
|
5453
5523
|
analyzed,
|
|
5454
5524
|
async (relPath) => {
|
|
5455
5525
|
try {
|
|
5456
|
-
await
|
|
5526
|
+
await fs21.access(path27.join(resolvedRoot, relPath));
|
|
5457
5527
|
return true;
|
|
5458
5528
|
} catch {
|
|
5459
5529
|
return false;
|
|
@@ -5596,8 +5666,9 @@ __export(status_exports, {
|
|
|
5596
5666
|
import { isDeepStrictEqual as isDeepStrictEqual3 } from "util";
|
|
5597
5667
|
async function setupStatus(dir) {
|
|
5598
5668
|
const ws = await workspace(dir);
|
|
5599
|
-
const
|
|
5600
|
-
|
|
5669
|
+
const activation = await effectiveSetup(ws.root);
|
|
5670
|
+
const setup = activation.setup;
|
|
5671
|
+
if (!setup || !Object.keys(setup.hosts).length) {
|
|
5601
5672
|
const partial = await Promise.all(["codex", "claude"].map(async (host) => ({
|
|
5602
5673
|
host,
|
|
5603
5674
|
receipt: await loadSetupReceipt(ws.root, ws.directory, host)
|
|
@@ -5631,7 +5702,7 @@ async function setupStatus(dir) {
|
|
|
5631
5702
|
]));
|
|
5632
5703
|
const hooks = isDeepStrictEqual3(compatibleHooks, expectedHooks) && !config.disabled;
|
|
5633
5704
|
const local = await loadSetupReceipt(ws.root, ws.directory, host);
|
|
5634
|
-
const configured = local?.status === "configured" && local.root === ws.root && local.revision === entry.revision;
|
|
5705
|
+
const configured = activation.root !== ws.root || local?.status === "configured" && local.root === ws.root && local.revision === entry.revision;
|
|
5635
5706
|
const observation = await readObservation(ws.root, ws.directory, host, entry.revision, installed.version ?? "unavailable");
|
|
5636
5707
|
const sessions = Object.values(observation?.sessions ?? {}).sort((a, b) => b.at.localeCompare(a.at));
|
|
5637
5708
|
const complete = sessions.find((session) => events.every((event) => session.events.includes(event)));
|
|
@@ -5663,6 +5734,7 @@ async function setupStatus(dir) {
|
|
|
5663
5734
|
status: statuses.length && statuses.every((status) => status === "active") ? "active" : statuses.includes("attention") ? "attention" : "pending",
|
|
5664
5735
|
root: ws.root,
|
|
5665
5736
|
hosts: hosts2,
|
|
5737
|
+
activationRoot: activation.root,
|
|
5666
5738
|
decisionRecords: decisions.records.length,
|
|
5667
5739
|
diagnostics: decisions.diagnostics,
|
|
5668
5740
|
scope: "Activation receipts record observed use after setup, not complete interception, correct repairs, or measured usefulness. Host trust and higher-priority settings may prevent execution. Receipts are local to this worktree and branch."
|
|
@@ -5670,6 +5742,9 @@ async function setupStatus(dir) {
|
|
|
5670
5742
|
}
|
|
5671
5743
|
function summarizeActivation(status) {
|
|
5672
5744
|
const lines = ["Mason setup: " + status.status + "."];
|
|
5745
|
+
if (status.activationRoot && status.activationRoot !== status.root) {
|
|
5746
|
+
lines.push("Activation inherited from " + status.activationRoot + "; evidence belongs to this worktree.");
|
|
5747
|
+
}
|
|
5673
5748
|
for (const [host, state] of Object.entries(status.hosts)) {
|
|
5674
5749
|
lines.push(
|
|
5675
5750
|
`${host}: ${state.status}`,
|