mason-context 0.19.1 → 0.19.2
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 +12 -0
- package/dist/mason-audit.js +99 -78
- package/dist/mason-audit.js.map +1 -1
- package/dist/mason-auto.js +651 -458
- package/dist/mason-auto.js.map +1 -1
- package/dist/mason-mcp.js +630 -431
- package/dist/mason-mcp.js.map +1 -1
- package/dist/mason-runtime.js +157 -54
- package/dist/mason-runtime.js.map +1 -1
- package/dist/mason.js +714 -501
- package/dist/mason.js.map +1 -1
- package/package.json +1 -1
package/dist/mason-mcp.js
CHANGED
|
@@ -3182,8 +3182,121 @@ var init_findings = __esm({
|
|
|
3182
3182
|
}
|
|
3183
3183
|
});
|
|
3184
3184
|
|
|
3185
|
-
// src/automation/
|
|
3185
|
+
// src/automation/notifications.ts
|
|
3186
3186
|
import { z as z5 } from "zod";
|
|
3187
|
+
function condition(finding) {
|
|
3188
|
+
const source = finding.current ?? finding.original;
|
|
3189
|
+
const e = source.evidence;
|
|
3190
|
+
const id = e.kind === "decision-anchor" ? digest([source.type, source.anchor.doc, e.decisionId]) : finding.id;
|
|
3191
|
+
const result = { level: "confidence" in source ? 2 : 1, facts: [] };
|
|
3192
|
+
switch (e.kind) {
|
|
3193
|
+
case "count-mismatch":
|
|
3194
|
+
result.magnitude = Math.abs(e.actual - e.claimed);
|
|
3195
|
+
break;
|
|
3196
|
+
case "unmentioned-dir":
|
|
3197
|
+
result.magnitude = e.sourceFileCount;
|
|
3198
|
+
break;
|
|
3199
|
+
case "decision-anchor":
|
|
3200
|
+
result.facts = [...e.changedFiles].sort();
|
|
3201
|
+
break;
|
|
3202
|
+
case "doc-behind-manifests":
|
|
3203
|
+
result.facts = (e.matches ?? []).map((m) => JSON.stringify([m.manifest, m.dependency, m.after])).sort();
|
|
3204
|
+
break;
|
|
3205
|
+
}
|
|
3206
|
+
return { id, condition: result };
|
|
3207
|
+
}
|
|
3208
|
+
function notificationConditions(findings) {
|
|
3209
|
+
const active = findings.filter((f) => f.status !== "resolved");
|
|
3210
|
+
const currentIds = new Set(active.filter((f) => f.current).map((f) => condition(f).id));
|
|
3211
|
+
const result = {};
|
|
3212
|
+
for (const f of active) {
|
|
3213
|
+
const value = condition(f);
|
|
3214
|
+
if (!f.current && currentIds.has(value.id)) continue;
|
|
3215
|
+
const previous = result[value.id];
|
|
3216
|
+
result[value.id] = previous ? {
|
|
3217
|
+
level: Math.max(previous.level, value.condition.level),
|
|
3218
|
+
facts: [.../* @__PURE__ */ new Set([...previous.facts, ...value.condition.facts])].sort(),
|
|
3219
|
+
...previous.magnitude !== void 0 || value.condition.magnitude !== void 0 ? { magnitude: Math.max(previous.magnitude ?? 0, value.condition.magnitude ?? 0) } : {}
|
|
3220
|
+
} : value.condition;
|
|
3221
|
+
}
|
|
3222
|
+
return result;
|
|
3223
|
+
}
|
|
3224
|
+
function createNotificationState(findings, head) {
|
|
3225
|
+
return { version: 1, baselineHead: head, baseline: notificationConditions(findings), delivered: {}, cleared: [] };
|
|
3226
|
+
}
|
|
3227
|
+
function worsened(current, previous) {
|
|
3228
|
+
return !previous || current.level > previous.level || (current.magnitude ?? 0) > (previous.magnitude ?? 0) || current.facts.some((fact) => !previous.facts.includes(fact));
|
|
3229
|
+
}
|
|
3230
|
+
function completionFindings(state, findings) {
|
|
3231
|
+
const current = notificationConditions(findings);
|
|
3232
|
+
const cleared = new Set(state.cleared);
|
|
3233
|
+
const resolvedIds = new Set(findings.filter((f) => f.status === "resolved").map((f) => condition(f).id));
|
|
3234
|
+
for (const id of Object.keys(state.baseline)) if (resolvedIds.has(id) && !current[id]) cleared.add(id);
|
|
3235
|
+
state.cleared = [...cleared];
|
|
3236
|
+
const selected = [];
|
|
3237
|
+
const selectedIds = /* @__PURE__ */ new Set();
|
|
3238
|
+
const delivered = { ...state.delivered };
|
|
3239
|
+
for (const finding of findings) {
|
|
3240
|
+
const value = condition(finding);
|
|
3241
|
+
const previous = state.delivered[value.id];
|
|
3242
|
+
value.condition = current[value.id] ?? value.condition;
|
|
3243
|
+
if (finding.status === "unverified" || !finding.current && finding.status !== "resolved") {
|
|
3244
|
+
continue;
|
|
3245
|
+
}
|
|
3246
|
+
if (finding.status === "resolved") {
|
|
3247
|
+
if (!current[value.id]) delete delivered[value.id];
|
|
3248
|
+
continue;
|
|
3249
|
+
}
|
|
3250
|
+
const eligible = cleared.has(value.id) || worsened(value.condition, state.baseline[value.id]);
|
|
3251
|
+
if (!eligible) continue;
|
|
3252
|
+
if (!selectedIds.has(value.id) && worsened(value.condition, previous)) {
|
|
3253
|
+
selectedIds.add(value.id);
|
|
3254
|
+
const source = finding.current;
|
|
3255
|
+
selected.push(source.evidence.kind === "decision-anchor" ? { ...finding, current: { ...source, evidence: { ...source.evidence, changedFiles: value.condition.facts } } } : finding);
|
|
3256
|
+
if (selected.length <= MAX_COMPLETION_FINDINGS) delivered[value.id] = value.condition;
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
state.delivered = delivered;
|
|
3260
|
+
return selected;
|
|
3261
|
+
}
|
|
3262
|
+
function completionSummary(findings, reportPath) {
|
|
3263
|
+
if (!findings.length) return null;
|
|
3264
|
+
const safe = (value) => value.replace(/[\u0000-\u001f\u007f-\u009f]/g, " ").slice(0, 250);
|
|
3265
|
+
return [
|
|
3266
|
+
`Mason: ${findings.length} new or worsened finding(s) since the retained baseline.`,
|
|
3267
|
+
...findings.slice(0, MAX_COMPLETION_FINDINGS).map((f) => {
|
|
3268
|
+
const source = f.current ?? f.original;
|
|
3269
|
+
const detail = source.evidence.kind === "decision-anchor" ? `Changes to ${source.evidence.changedFiles.join(", ")} may affect decision "${source.evidence.title}". Inspect the diff if relevant; acceptance is not required.` : source.message;
|
|
3270
|
+
return `[${f.status === "unresolved" ? "issue" : "advisory"}] ${safe(source.anchor.doc)}: ${safe(detail)}`;
|
|
3271
|
+
}),
|
|
3272
|
+
...findings.length > MAX_COMPLETION_FINDINGS ? [`${findings.length - MAX_COMPLETION_FINDINGS} more in the report; pending later feedback.`] : [],
|
|
3273
|
+
`Evidence: ${reportPath}. Explicit audit: mason_automation(action: "check").`,
|
|
3274
|
+
"Inspect findings within the authorized work. Concurrent changes may also contribute; this summary does not establish who introduced them."
|
|
3275
|
+
].join("\n");
|
|
3276
|
+
}
|
|
3277
|
+
var conditionSchema, MAX_COMPLETION_FINDINGS, notificationStateSchema;
|
|
3278
|
+
var init_notifications = __esm({
|
|
3279
|
+
"src/automation/notifications.ts"() {
|
|
3280
|
+
"use strict";
|
|
3281
|
+
init_findings();
|
|
3282
|
+
conditionSchema = z5.object({
|
|
3283
|
+
level: z5.number(),
|
|
3284
|
+
facts: z5.array(z5.string()),
|
|
3285
|
+
magnitude: z5.number().optional()
|
|
3286
|
+
});
|
|
3287
|
+
MAX_COMPLETION_FINDINGS = 4;
|
|
3288
|
+
notificationStateSchema = z5.object({
|
|
3289
|
+
version: z5.literal(1),
|
|
3290
|
+
baselineHead: z5.string(),
|
|
3291
|
+
baseline: z5.record(conditionSchema),
|
|
3292
|
+
delivered: z5.record(conditionSchema),
|
|
3293
|
+
cleared: z5.array(z5.string())
|
|
3294
|
+
});
|
|
3295
|
+
}
|
|
3296
|
+
});
|
|
3297
|
+
|
|
3298
|
+
// src/automation/store.ts
|
|
3299
|
+
import { z as z6 } from "zod";
|
|
3187
3300
|
function parseState(raw) {
|
|
3188
3301
|
try {
|
|
3189
3302
|
return stateSchema.parse(raw);
|
|
@@ -3199,37 +3312,36 @@ var init_store = __esm({
|
|
|
3199
3312
|
"src/automation/store.ts"() {
|
|
3200
3313
|
"use strict";
|
|
3201
3314
|
init_store_lock();
|
|
3202
|
-
|
|
3315
|
+
init_notifications();
|
|
3316
|
+
hostSchema = z6.enum(["claude", "codex"]);
|
|
3203
3317
|
events = ["session_start", "turn_start", "before_tool", "after_tool", "task_end"];
|
|
3204
|
-
stateSchema =
|
|
3205
|
-
version:
|
|
3206
|
-
root:
|
|
3207
|
-
gitDir:
|
|
3208
|
-
branch:
|
|
3209
|
-
baselines:
|
|
3210
|
-
sessions:
|
|
3318
|
+
stateSchema = z6.object({
|
|
3319
|
+
version: z6.literal(1),
|
|
3320
|
+
root: z6.string(),
|
|
3321
|
+
gitDir: z6.string(),
|
|
3322
|
+
branch: z6.string(),
|
|
3323
|
+
baselines: z6.array(z6.object({ path: z6.string(), at: z6.string(), event: z6.string(), fingerprint: z6.string() })).max(128),
|
|
3324
|
+
sessions: z6.record(z6.object({
|
|
3211
3325
|
host: hostSchema,
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
mutationObserved: z5.boolean(),
|
|
3218
|
-
pending: z5.record(z5.string()),
|
|
3219
|
-
coverageGaps: z5.array(z5.string()),
|
|
3220
|
-
events: z5.record(z5.object({ at: z5.string(), count: z5.number().int().positive() }))
|
|
3326
|
+
lastUsed: z6.string(),
|
|
3327
|
+
notifiedDiagnostics: z6.array(z6.string()).default([]),
|
|
3328
|
+
pending: z6.record(z6.string()),
|
|
3329
|
+
coverageGaps: z6.array(z6.string()),
|
|
3330
|
+
events: z6.record(z6.object({ at: z6.string(), count: z6.number().int().positive() }))
|
|
3221
3331
|
})),
|
|
3222
|
-
updatedAt:
|
|
3223
|
-
fingerprint:
|
|
3224
|
-
latest:
|
|
3225
|
-
|
|
3332
|
+
updatedAt: z6.string(),
|
|
3333
|
+
fingerprint: z6.string().nullable(),
|
|
3334
|
+
latest: z6.string().nullable(),
|
|
3335
|
+
notifications: notificationStateSchema.optional(),
|
|
3336
|
+
agentNotifications: notificationStateSchema.optional(),
|
|
3337
|
+
analysis: z6.object({ id: z6.string(), fingerprint: z6.string(), completedAt: z6.number(), path: z6.string() }).optional()
|
|
3226
3338
|
});
|
|
3227
3339
|
}
|
|
3228
3340
|
});
|
|
3229
3341
|
|
|
3230
3342
|
// src/audit/advisory-review.ts
|
|
3231
3343
|
import fs10 from "fs/promises";
|
|
3232
|
-
import { z as
|
|
3344
|
+
import { z as z7 } from "zod";
|
|
3233
3345
|
async function readRecord(root, id) {
|
|
3234
3346
|
const raw = await readStoreJson(root, recordPath(id));
|
|
3235
3347
|
if (raw === null) return null;
|
|
@@ -3448,41 +3560,41 @@ var init_advisory_review = __esm({
|
|
|
3448
3560
|
init_decisions();
|
|
3449
3561
|
init_drift2();
|
|
3450
3562
|
git2 = async (root, ...args) => (await (["log", "ls-tree", "ls-files", "merge-base"].includes(args[0]) ? inspectionGit : execGit)(args, { cwd: root, timeout: 1e4, maxBuffer: 8 * 1024 * 1024 })).stdout;
|
|
3451
|
-
hashSchema =
|
|
3452
|
-
commitSchema2 =
|
|
3453
|
-
evidenceSchema2 =
|
|
3563
|
+
hashSchema = z7.string().regex(/^[a-f0-9]{64}$/);
|
|
3564
|
+
commitSchema2 = z7.string().regex(/^[a-f0-9]{40,64}$/);
|
|
3565
|
+
evidenceSchema2 = z7.object({
|
|
3454
3566
|
head: commitSchema2,
|
|
3455
3567
|
fingerprint: hashSchema,
|
|
3456
|
-
scope:
|
|
3457
|
-
tree:
|
|
3568
|
+
scope: z7.array(z7.string()).min(1).max(1e3),
|
|
3569
|
+
tree: z7.string().max(2 * 1024 * 1024),
|
|
3458
3570
|
lastScopeCommit: commitSchema2,
|
|
3459
|
-
paths:
|
|
3571
|
+
paths: z7.array(z7.object({ path: z7.string(), exists: z7.boolean() })).max(1e3)
|
|
3460
3572
|
});
|
|
3461
|
-
dismissalReasonSchema =
|
|
3462
|
-
eventSchema2 =
|
|
3463
|
-
at:
|
|
3464
|
-
reviewer:
|
|
3465
|
-
note:
|
|
3466
|
-
outcome:
|
|
3573
|
+
dismissalReasonSchema = z7.enum(["no-dependency-claims", "unrelated-manifest-change"]);
|
|
3574
|
+
eventSchema2 = z7.object({
|
|
3575
|
+
at: z7.string().datetime(),
|
|
3576
|
+
reviewer: z7.string().trim().min(1).max(200).optional(),
|
|
3577
|
+
note: z7.string().trim().min(1).max(2500),
|
|
3578
|
+
outcome: z7.enum(["addressed", "inapplicable", "deferred", "dismissed"]),
|
|
3467
3579
|
reasonCode: dismissalReasonSchema.optional(),
|
|
3468
3580
|
finding: advisorySchema.refine((finding) => finding.evidence.kind !== "decision-anchor", "Decision findings use decision reviews"),
|
|
3469
3581
|
evidence: evidenceSchema2
|
|
3470
3582
|
});
|
|
3471
|
-
recordSchema =
|
|
3472
|
-
reviewSummarySchema =
|
|
3583
|
+
recordSchema = z7.object({ version: z7.literal(1), id: hashSchema, events: z7.array(eventSchema2).min(1).max(200), digest: hashSchema });
|
|
3584
|
+
reviewSummarySchema = z7.object({
|
|
3473
3585
|
id: hashSchema,
|
|
3474
|
-
status:
|
|
3475
|
-
reason:
|
|
3476
|
-
recordPath:
|
|
3477
|
-
reviewer:
|
|
3478
|
-
note:
|
|
3479
|
-
outcome:
|
|
3480
|
-
reviewedHead:
|
|
3586
|
+
status: z7.enum(["current", "reopened", "deferred", "unverified"]),
|
|
3587
|
+
reason: z7.string(),
|
|
3588
|
+
recordPath: z7.string().optional(),
|
|
3589
|
+
reviewer: z7.string().optional(),
|
|
3590
|
+
note: z7.string().optional(),
|
|
3591
|
+
outcome: z7.enum(["addressed", "inapplicable", "deferred", "accepted", "reaffirmed", "retired", "dismissed"]).optional(),
|
|
3592
|
+
reviewedHead: z7.string().optional()
|
|
3481
3593
|
});
|
|
3482
|
-
advisoryReviewRequest =
|
|
3483
|
-
baselinePath:
|
|
3594
|
+
advisoryReviewRequest = z7.object({
|
|
3595
|
+
baselinePath: z7.string().min(1),
|
|
3484
3596
|
findingId: hashSchema,
|
|
3485
|
-
action:
|
|
3597
|
+
action: z7.enum(["prepare", "addressed", "inapplicable", "deferred", "dismiss"]).default("prepare"),
|
|
3486
3598
|
reasonCode: dismissalReasonSchema.optional(),
|
|
3487
3599
|
reviewer: eventSchema2.shape.reviewer.optional(),
|
|
3488
3600
|
note: eventSchema2.shape.note.optional(),
|
|
@@ -3600,7 +3712,7 @@ __export(repair_exports, {
|
|
|
3600
3712
|
import fs12 from "fs/promises";
|
|
3601
3713
|
import path21 from "path";
|
|
3602
3714
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
3603
|
-
import { z as
|
|
3715
|
+
import { z as z8 } from "zod";
|
|
3604
3716
|
function recheckable(finding) {
|
|
3605
3717
|
return !("confidence" in finding) && finding.resolution === "recheck" && ["deleted-reference", "dead-command", "new-module"].includes(finding.type) && ["missing-path", "missing-script", "unmentioned-dir"].includes(finding.evidence.kind);
|
|
3606
3718
|
}
|
|
@@ -3671,7 +3783,7 @@ async function withRepairSession(root, options, run, validate, cachedAudit) {
|
|
|
3671
3783
|
}
|
|
3672
3784
|
async function prepareOriginal(rootDir, checks, options, session) {
|
|
3673
3785
|
const root = await fs12.realpath(rootDir);
|
|
3674
|
-
const selected =
|
|
3786
|
+
const selected = z8.array(checkSchema).nonempty().parse(checks);
|
|
3675
3787
|
const report = await (session ? session.audit(selected) : stableAudit(root, selected, options));
|
|
3676
3788
|
if (!report) throw new Error("No context files found to prepare a repair.");
|
|
3677
3789
|
if (!report.gitAvailable) throw new Error("Readable Git history is required to prepare a repair.");
|
|
@@ -3828,42 +3940,42 @@ var init_repair = __esm({
|
|
|
3828
3940
|
init_findings();
|
|
3829
3941
|
init_advisory_review();
|
|
3830
3942
|
init_findings();
|
|
3831
|
-
count2 =
|
|
3832
|
-
reportSchema =
|
|
3833
|
-
version:
|
|
3834
|
-
root:
|
|
3835
|
-
gitAvailable:
|
|
3943
|
+
count2 = z8.number().int().nonnegative();
|
|
3944
|
+
reportSchema = z8.object({
|
|
3945
|
+
version: z8.literal(1),
|
|
3946
|
+
root: z8.string(),
|
|
3947
|
+
gitAvailable: z8.literal(true),
|
|
3836
3948
|
headHash: commitSchema.shape.hash,
|
|
3837
|
-
checksRun:
|
|
3838
|
-
docs:
|
|
3839
|
-
path:
|
|
3840
|
-
scope:
|
|
3841
|
-
kind:
|
|
3949
|
+
checksRun: z8.array(checkSchema).nonempty(),
|
|
3950
|
+
docs: z8.array(z8.object({
|
|
3951
|
+
path: z8.string().refine((value) => normalizeRepoPath(value) === value),
|
|
3952
|
+
scope: z8.string().optional(),
|
|
3953
|
+
kind: z8.enum(["instructions", "readme", "guide"]).optional(),
|
|
3842
3954
|
lastCommit: commitSchema.nullable(),
|
|
3843
|
-
dirty:
|
|
3955
|
+
dirty: z8.boolean(),
|
|
3844
3956
|
lineCount: count2
|
|
3845
3957
|
})).nonempty(),
|
|
3846
|
-
decisionsChecked:
|
|
3847
|
-
clean:
|
|
3848
|
-
excludedChecks:
|
|
3849
|
-
issues:
|
|
3850
|
-
advisories:
|
|
3851
|
-
suppressedAdvisories:
|
|
3852
|
-
skippedChecks:
|
|
3958
|
+
decisionsChecked: z8.boolean(),
|
|
3959
|
+
clean: z8.boolean(),
|
|
3960
|
+
excludedChecks: z8.array(z8.object({ check: checkSchema, doc: z8.string() })).optional(),
|
|
3961
|
+
issues: z8.array(issueSchema),
|
|
3962
|
+
advisories: z8.array(advisorySchema),
|
|
3963
|
+
suppressedAdvisories: z8.array(advisorySchema).optional(),
|
|
3964
|
+
skippedChecks: z8.array(z8.object({ check: z8.string(), reason: z8.string(), doc: z8.string().optional() }))
|
|
3853
3965
|
});
|
|
3854
|
-
baselineSchema =
|
|
3855
|
-
kind:
|
|
3856
|
-
version:
|
|
3857
|
-
createdAt:
|
|
3966
|
+
baselineSchema = z8.object({
|
|
3967
|
+
kind: z8.literal("mason-audit-repair"),
|
|
3968
|
+
version: z8.literal(1),
|
|
3969
|
+
createdAt: z8.string().datetime(),
|
|
3858
3970
|
report: reportSchema,
|
|
3859
|
-
digest:
|
|
3971
|
+
digest: z8.string().regex(/^[a-f0-9]{64}$/)
|
|
3860
3972
|
});
|
|
3861
|
-
repairFindingSchema =
|
|
3862
|
-
id:
|
|
3863
|
-
original:
|
|
3864
|
-
status:
|
|
3865
|
-
reason:
|
|
3866
|
-
current:
|
|
3973
|
+
repairFindingSchema = z8.object({
|
|
3974
|
+
id: z8.string(),
|
|
3975
|
+
original: z8.union([issueSchema, advisorySchema]),
|
|
3976
|
+
status: z8.enum(["resolved", "unresolved", "review-required", "unverified"]),
|
|
3977
|
+
reason: z8.string(),
|
|
3978
|
+
current: z8.union([issueSchema, advisorySchema]).optional(),
|
|
3867
3979
|
review: reviewSummarySchema.optional()
|
|
3868
3980
|
});
|
|
3869
3981
|
}
|
|
@@ -3874,7 +3986,7 @@ import fs13 from "fs/promises";
|
|
|
3874
3986
|
import path22 from "path";
|
|
3875
3987
|
import { createHash as createHash3 } from "crypto";
|
|
3876
3988
|
import fg7 from "fast-glob";
|
|
3877
|
-
import { z as
|
|
3989
|
+
import { z as z9 } from "zod";
|
|
3878
3990
|
async function git3(root, ...args) {
|
|
3879
3991
|
return profilePhase("automation.git", async () => (await execGit(args, { cwd: root, maxBuffer: 16 * 1024 * 1024, timeout: 1e4 })).stdout);
|
|
3880
3992
|
}
|
|
@@ -4017,10 +4129,10 @@ var init_evidence = __esm({
|
|
|
4017
4129
|
init_dead_command();
|
|
4018
4130
|
init_storage();
|
|
4019
4131
|
init_advisory_review();
|
|
4020
|
-
engineVersion = true ? "0.19.
|
|
4132
|
+
engineVersion = true ? "0.19.2" : "development";
|
|
4021
4133
|
hash = (value) => createHash3("sha256").update(JSON.stringify(value)).digest("hex");
|
|
4022
4134
|
content = readAuditInput;
|
|
4023
|
-
cacheSchema =
|
|
4135
|
+
cacheSchema = z9.object({ version: z9.literal(1), entries: z9.record(z9.object({ key: z9.string(), result: checkResultSchema })), digest: z9.string() });
|
|
4024
4136
|
}
|
|
4025
4137
|
});
|
|
4026
4138
|
|
|
@@ -4036,7 +4148,7 @@ __export(model_exports, {
|
|
|
4036
4148
|
setupHostSchema: () => setupHostSchema,
|
|
4037
4149
|
setupSchema: () => setupSchema
|
|
4038
4150
|
});
|
|
4039
|
-
import { z as
|
|
4151
|
+
import { z as z10 } from "zod";
|
|
4040
4152
|
import fs14 from "fs/promises";
|
|
4041
4153
|
import path23 from "path";
|
|
4042
4154
|
async function loadSetup(root) {
|
|
@@ -4083,29 +4195,29 @@ var init_model = __esm({
|
|
|
4083
4195
|
"use strict";
|
|
4084
4196
|
init_evidence();
|
|
4085
4197
|
init_storage();
|
|
4086
|
-
setupHostSchema =
|
|
4087
|
-
configuredVersion:
|
|
4088
|
-
revision:
|
|
4089
|
-
fingerprint:
|
|
4090
|
-
mcpFingerprint:
|
|
4091
|
-
instructions:
|
|
4198
|
+
setupHostSchema = z10.object({
|
|
4199
|
+
configuredVersion: z10.string(),
|
|
4200
|
+
revision: z10.string().uuid(),
|
|
4201
|
+
fingerprint: z10.string(),
|
|
4202
|
+
mcpFingerprint: z10.string(),
|
|
4203
|
+
instructions: z10.array(z10.string())
|
|
4092
4204
|
});
|
|
4093
|
-
setupSchema =
|
|
4205
|
+
setupSchema = z10.object({ version: z10.literal(2), hosts: z10.object({
|
|
4094
4206
|
codex: setupHostSchema.optional(),
|
|
4095
4207
|
claude: setupHostSchema.optional()
|
|
4096
4208
|
}) });
|
|
4097
4209
|
SETUP_PATH = ".mason/local/setup.json";
|
|
4098
4210
|
INACTIVE_HOSTS_PATH = ".mason/local/inactive-hosts.json";
|
|
4099
|
-
inactiveHostsSchema =
|
|
4100
|
-
receiptSchema =
|
|
4101
|
-
version:
|
|
4102
|
-
host:
|
|
4103
|
-
status:
|
|
4104
|
-
initialReportPath:
|
|
4105
|
-
initialBaselinePaths:
|
|
4106
|
-
root:
|
|
4107
|
-
revision:
|
|
4108
|
-
configuredAt:
|
|
4211
|
+
inactiveHostsSchema = z10.object({ version: z10.literal(1), hosts: z10.array(z10.enum(["claude", "codex"])) });
|
|
4212
|
+
receiptSchema = z10.object({
|
|
4213
|
+
version: z10.literal(1),
|
|
4214
|
+
host: z10.enum(["codex", "claude"]),
|
|
4215
|
+
status: z10.enum(["installing", "configured"]),
|
|
4216
|
+
initialReportPath: z10.string(),
|
|
4217
|
+
initialBaselinePaths: z10.array(z10.string()),
|
|
4218
|
+
root: z10.string(),
|
|
4219
|
+
revision: z10.string().uuid(),
|
|
4220
|
+
configuredAt: z10.string().optional()
|
|
4109
4221
|
});
|
|
4110
4222
|
}
|
|
4111
4223
|
});
|
|
@@ -4143,7 +4255,7 @@ var init_launcher = __esm({
|
|
|
4143
4255
|
"use strict";
|
|
4144
4256
|
init_evidence();
|
|
4145
4257
|
init_model();
|
|
4146
|
-
executingVersion = () => true ? "0.19.
|
|
4258
|
+
executingVersion = () => true ? "0.19.2" : "development";
|
|
4147
4259
|
mcpCommand = (host) => globalCommand(["--setup-host", host, "mcp"]);
|
|
4148
4260
|
hookCommand = (host) => `mason --setup-host ${host} auto`;
|
|
4149
4261
|
}
|
|
@@ -4340,7 +4452,7 @@ __export(execution_exports, {
|
|
|
4340
4452
|
import os2 from "os";
|
|
4341
4453
|
import fs19 from "fs/promises";
|
|
4342
4454
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
4343
|
-
import { z as
|
|
4455
|
+
import { z as z13 } from "zod";
|
|
4344
4456
|
function parseExecution(raw) {
|
|
4345
4457
|
try {
|
|
4346
4458
|
return executionSchema.parse(raw);
|
|
@@ -4358,7 +4470,7 @@ function automationFailure(error) {
|
|
|
4358
4470
|
codes.add(String(cause.code));
|
|
4359
4471
|
cause = cause.cause;
|
|
4360
4472
|
}
|
|
4361
|
-
const code = codes.has("ENOSPC") || codes.has("EDQUOT") ? "storage-full" : /changed during|changed while|changed between/.test(message2) ? "inputs-changed" : /Automation is busy/.test(message2) ? "busy" : /not a git repository|unknown revision|bad revision|different history|unreachable/.test(message2) ? "history-unavailable" : error instanceof
|
|
4473
|
+
const code = codes.has("ENOSPC") || codes.has("EDQUOT") ? "storage-full" : /changed during|changed while|changed between/.test(message2) ? "inputs-changed" : /Automation is busy/.test(message2) ? "busy" : /not a git repository|unknown revision|bad revision|different history|unreachable/.test(message2) ? "history-unavailable" : error instanceof z13.ZodError || error instanceof SyntaxError || /Hook input|Expected one command|Unknown automation command|--host/.test(message2) ? "invalid-input" : /store|baseline|modified|symbolic link|Symlink|automation state|state belongs/.test(message2) ? "invalid-evidence" : [...codes].some((c) => /^E[A-Z]+$/.test(c)) ? "io-error" : "internal";
|
|
4362
4474
|
return { code, message: message2, retryable: ["inputs-changed", "storage-full", "busy", "io-error"].includes(code), receiptRecorded: false };
|
|
4363
4475
|
}
|
|
4364
4476
|
function failureMessage(error) {
|
|
@@ -4487,38 +4599,100 @@ var init_execution = __esm({
|
|
|
4487
4599
|
init_store();
|
|
4488
4600
|
init_evidence();
|
|
4489
4601
|
init_storage();
|
|
4490
|
-
failureSchema =
|
|
4491
|
-
code:
|
|
4492
|
-
message:
|
|
4493
|
-
retryable:
|
|
4494
|
-
receiptRecorded:
|
|
4602
|
+
failureSchema = z13.object({
|
|
4603
|
+
code: z13.enum(["inputs-changed", "storage-full", "busy", "invalid-input", "history-unavailable", "invalid-evidence", "io-error", "internal"]),
|
|
4604
|
+
message: z13.string(),
|
|
4605
|
+
retryable: z13.boolean(),
|
|
4606
|
+
receiptRecorded: z13.boolean()
|
|
4495
4607
|
});
|
|
4496
|
-
attemptSchema =
|
|
4497
|
-
id:
|
|
4498
|
-
lease:
|
|
4499
|
-
event:
|
|
4500
|
-
startedAt:
|
|
4501
|
-
finishedAt:
|
|
4502
|
-
durationMs:
|
|
4503
|
-
pid:
|
|
4504
|
-
host:
|
|
4505
|
-
status:
|
|
4506
|
-
verificationStatus:
|
|
4507
|
-
reportPath:
|
|
4608
|
+
attemptSchema = z13.object({
|
|
4609
|
+
id: z13.string().regex(/^[a-zA-Z0-9_-]+$/),
|
|
4610
|
+
lease: z13.literal(true).optional(),
|
|
4611
|
+
event: z13.string(),
|
|
4612
|
+
startedAt: z13.string(),
|
|
4613
|
+
finishedAt: z13.string().optional(),
|
|
4614
|
+
durationMs: z13.number().nonnegative().optional(),
|
|
4615
|
+
pid: z13.number().int().positive(),
|
|
4616
|
+
host: z13.string(),
|
|
4617
|
+
status: z13.enum(["running", "completed", "failed", "unknown"]),
|
|
4618
|
+
verificationStatus: z13.string().optional(),
|
|
4619
|
+
reportPath: z13.string().optional(),
|
|
4508
4620
|
failure: failureSchema.optional()
|
|
4509
4621
|
});
|
|
4510
|
-
executionSchema =
|
|
4511
|
-
notificationsSchema =
|
|
4512
|
-
signature:
|
|
4622
|
+
executionSchema = z13.object({ version: z13.literal(1), attempts: z13.array(attemptSchema).max(160), discardedAttempts: z13.number().int().nonnegative().default(0) });
|
|
4623
|
+
notificationsSchema = z13.object({ version: z13.literal(1), sessions: z13.record(z13.object({
|
|
4624
|
+
signature: z13.string(),
|
|
4513
4625
|
code: failureSchema.shape.code,
|
|
4514
|
-
message:
|
|
4515
|
-
count:
|
|
4516
|
-
lastAt:
|
|
4626
|
+
message: z13.string(),
|
|
4627
|
+
count: z13.number().int().positive(),
|
|
4628
|
+
lastAt: z13.string()
|
|
4517
4629
|
})) });
|
|
4518
4630
|
leasePath = (directory, id) => `${directory}/executions/${id}.json`;
|
|
4519
4631
|
}
|
|
4520
4632
|
});
|
|
4521
4633
|
|
|
4634
|
+
// src/decisions/pending.ts
|
|
4635
|
+
var pending_exports = {};
|
|
4636
|
+
__export(pending_exports, {
|
|
4637
|
+
pendingKnowledge: () => pendingKnowledge
|
|
4638
|
+
});
|
|
4639
|
+
async function pendingKnowledge(root, now = Date.now()) {
|
|
4640
|
+
try {
|
|
4641
|
+
const [store, status] = await Promise.all([
|
|
4642
|
+
loadDecisionStore(root),
|
|
4643
|
+
execGit(
|
|
4644
|
+
["status", "--porcelain=v1", "-z", "--untracked-files=all", "--", ".mason/decisions"],
|
|
4645
|
+
{ cwd: root, timeout: 1e4, maxBuffer: 1024 * 1024 }
|
|
4646
|
+
)
|
|
4647
|
+
]);
|
|
4648
|
+
const changed = /* @__PURE__ */ new Set();
|
|
4649
|
+
const entries = status.stdout.split("\0");
|
|
4650
|
+
for (let i = 0; i < entries.length; i++) {
|
|
4651
|
+
const entry = entries[i];
|
|
4652
|
+
if (!entry) continue;
|
|
4653
|
+
const file = entry.slice(3);
|
|
4654
|
+
if (/^\.mason\/decisions\/[^/]+\.json$/.test(file)) changed.add(file);
|
|
4655
|
+
if (/[RC]/.test(entry.slice(0, 2))) i++;
|
|
4656
|
+
}
|
|
4657
|
+
const records = new Map(store.records.map((record) => [`.mason/decisions/${record.id}.json`, record]));
|
|
4658
|
+
const age = (at) => {
|
|
4659
|
+
const time = at ? Date.parse(at) : NaN;
|
|
4660
|
+
return Number.isFinite(time) ? `${Math.max(0, Math.floor((now - time) / 864e5))} days` : "unknown age";
|
|
4661
|
+
};
|
|
4662
|
+
const safe = (value) => value.replace(/[\u0000-\u001f\u007f-\u009f]/g, " ");
|
|
4663
|
+
const list = (items) => items.slice(0, 5).map(safe).join("; ") + (items.length > 5 ? `; ${items.length - 5} more` : "");
|
|
4664
|
+
const proposals = store.records.filter((record) => record.status === "active" && decisionApproval(record) === "proposed").map((record) => {
|
|
4665
|
+
const history = record.version === 2 ? record.history : [];
|
|
4666
|
+
let lastReview = -1;
|
|
4667
|
+
history.forEach((event, index2) => {
|
|
4668
|
+
if (event.kind === "accepted" || event.kind === "reaffirmed") lastReview = index2;
|
|
4669
|
+
});
|
|
4670
|
+
const since = history.slice(lastReview + 1).find((event) => event.kind === "created" || event.kind === "revised")?.at ?? record.createdAt;
|
|
4671
|
+
return { record, since };
|
|
4672
|
+
}).sort((a, b) => {
|
|
4673
|
+
const timestamp = (value) => Number.isFinite(Date.parse(value)) ? Date.parse(value) : Infinity;
|
|
4674
|
+
return timestamp(a.since) - timestamp(b.since) || a.record.id.localeCompare(b.record.id);
|
|
4675
|
+
});
|
|
4676
|
+
const lines = [];
|
|
4677
|
+
if (changed.size) lines.push(`${changed.size} uncommitted decision record(s): ${list([...changed].sort().map((file) => `${file} (saved-record age: ${age(records.get(file)?.updatedAt)})`))}.`);
|
|
4678
|
+
if (proposals.length) lines.push(`${proposals.length} proposal(s) awaiting review (oldest first): ${list(proposals.map(({ record, since }) => `.mason/decisions/${record.id}.json (${age(since)})`))}.`);
|
|
4679
|
+
if (store.diagnostics.length) lines.push(`${store.diagnostics.length} decision record(s) could not be read; pending knowledge summary is incomplete.`);
|
|
4680
|
+
return lines.length ? `Mason pending knowledge:
|
|
4681
|
+
${lines.join("\n")}
|
|
4682
|
+
Informational only; review and commit through the normal project workflow. No approval is implied.` : null;
|
|
4683
|
+
} catch {
|
|
4684
|
+
return "Mason pending knowledge: unavailable; decision records or Git status could not be read.";
|
|
4685
|
+
}
|
|
4686
|
+
}
|
|
4687
|
+
var init_pending = __esm({
|
|
4688
|
+
"src/decisions/pending.ts"() {
|
|
4689
|
+
"use strict";
|
|
4690
|
+
init_git_read();
|
|
4691
|
+
init_decisions();
|
|
4692
|
+
init_provenance();
|
|
4693
|
+
}
|
|
4694
|
+
});
|
|
4695
|
+
|
|
4522
4696
|
// src/automation/runtime.ts
|
|
4523
4697
|
var runtime_exports = {};
|
|
4524
4698
|
__export(runtime_exports, {
|
|
@@ -4528,7 +4702,7 @@ __export(runtime_exports, {
|
|
|
4528
4702
|
summarize: () => summarize
|
|
4529
4703
|
});
|
|
4530
4704
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
4531
|
-
import { z as
|
|
4705
|
+
import { z as z14 } from "zod";
|
|
4532
4706
|
async function observeReadOnlyTool(dir, event) {
|
|
4533
4707
|
const ws = await profilePhase("automation.workspace", () => workspace(dir));
|
|
4534
4708
|
await withLock(ws.root, ws.directory, async () => {
|
|
@@ -4750,6 +4924,19 @@ async function automate(dir, event) {
|
|
|
4750
4924
|
const state = await loadState(ws);
|
|
4751
4925
|
if (state.analysis?.id !== result.analysis.id) throw new Error("Automation evidence changed during publication; retry against the current inputs.");
|
|
4752
4926
|
const report = structuredClone(result.analysis.report);
|
|
4927
|
+
if (!state.notifications) {
|
|
4928
|
+
let baseline = { findings: report.findings, head: report.head };
|
|
4929
|
+
if (state.latest) {
|
|
4930
|
+
try {
|
|
4931
|
+
const previous = z14.object({ findings: z14.array(repairFindingSchema), head: z14.string() }).safeParse(await readStoreJson(ws.root, state.latest));
|
|
4932
|
+
if (!previous.success) throw new Error("Unsupported saved report");
|
|
4933
|
+
baseline = previous.data;
|
|
4934
|
+
} catch {
|
|
4935
|
+
report.diagnostics.push("The saved notification baseline could not be read; initialized from the current audit. Original repair evidence is retained. Run an explicit check for all outstanding findings.");
|
|
4936
|
+
}
|
|
4937
|
+
}
|
|
4938
|
+
state.notifications = createNotificationState(baseline.findings, baseline.head);
|
|
4939
|
+
}
|
|
4753
4940
|
if (result.shared) report.checks = { ...report.checks, ran: [], reused: [.../* @__PURE__ */ new Set([...report.checks.ran, ...report.checks.reused])], shared: true };
|
|
4754
4941
|
report.reportPath = ws.directory + "/checks/" + randomUUID5() + ".json";
|
|
4755
4942
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -4762,12 +4949,8 @@ async function automate(dir, event) {
|
|
|
4762
4949
|
if (Object.keys(state.sessions).length >= 128) throw new Error("Too many sessions with unfinished tool calls; original evidence was retained.");
|
|
4763
4950
|
state.sessions[key] = {
|
|
4764
4951
|
host: event.host,
|
|
4765
|
-
|
|
4766
|
-
continued: false,
|
|
4767
|
-
initialIssues: report.findings.filter((f) => f.status === "unresolved").map((f) => f.id),
|
|
4768
|
-
initialDocs: inputs.docs,
|
|
4952
|
+
notifiedDiagnostics: [],
|
|
4769
4953
|
lastUsed: now,
|
|
4770
|
-
mutationObserved: false,
|
|
4771
4954
|
pending: {},
|
|
4772
4955
|
coverageGaps: [],
|
|
4773
4956
|
events: {}
|
|
@@ -4782,7 +4965,6 @@ async function automate(dir, event) {
|
|
|
4782
4965
|
session.pending[event.toolId] = inputs.fingerprint;
|
|
4783
4966
|
}
|
|
4784
4967
|
if (event.event === "after_tool" && event.mutating) {
|
|
4785
|
-
session.mutationObserved = true;
|
|
4786
4968
|
if (!event.toolId || !session.pending[event.toolId]) {
|
|
4787
4969
|
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.";
|
|
4788
4970
|
if (!session.coverageGaps.includes(gap)) session.coverageGaps.push(gap);
|
|
@@ -4793,31 +4975,39 @@ async function automate(dir, event) {
|
|
|
4793
4975
|
if (session.coverageGaps.length && report.status !== "unavailable") report.status = "incomplete";
|
|
4794
4976
|
report.capture = report.status !== "unavailable" && !session.coverageGaps.length && (session.events.session_start || session.events.before_tool) ? "observed" : "unknown";
|
|
4795
4977
|
}
|
|
4796
|
-
const
|
|
4797
|
-
|
|
4798
|
-
const
|
|
4799
|
-
const
|
|
4800
|
-
if (session)
|
|
4801
|
-
session.
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
const
|
|
4978
|
+
const selected = session && event.event === "task_end" ? completionFindings(state.notifications, report.findings) : [];
|
|
4979
|
+
state.agentNotifications ??= { ...structuredClone(state.notifications), delivered: {} };
|
|
4980
|
+
const feedback = session && ["turn_start", "after_tool"].includes(event.event) ? completionFindings(state.agentNotifications, report.findings) : [];
|
|
4981
|
+
const diagnostics = session ? report.diagnostics.filter((d) => !session.notifiedDiagnostics.includes(d)).slice(0, 2) : [];
|
|
4982
|
+
if (session) session.notifiedDiagnostics = [.../* @__PURE__ */ new Set([
|
|
4983
|
+
...session.notifiedDiagnostics.filter((d) => report.diagnostics.includes(d)),
|
|
4984
|
+
...diagnostics
|
|
4985
|
+
])];
|
|
4986
|
+
const message2 = !session ? summarize(report) : [
|
|
4987
|
+
completionSummary(selected, report.reportPath),
|
|
4988
|
+
completionSummary(feedback, report.reportPath),
|
|
4989
|
+
...diagnostics.length ? [`Mason: verification limited. ${diagnostics.slice(0, 2).map(cleanText).join(" ")} Evidence: ${report.reportPath}.`] : []
|
|
4990
|
+
].filter(Boolean).join("\n") || null;
|
|
4991
|
+
const notify = message2 !== null;
|
|
4992
|
+
const persistReport = !state.latest || state.fingerprint !== inputs.fingerprint || notify || newSession || event.event === "task_end";
|
|
4805
4993
|
if (!persistReport) report.reportPath = state.latest;
|
|
4806
4994
|
state.updatedAt = now;
|
|
4807
4995
|
state.fingerprint = inputs.fingerprint;
|
|
4808
4996
|
state.latest = report.reportPath;
|
|
4809
4997
|
if (persistReport) await writeStoreJson(ws.root, report.reportPath, report);
|
|
4810
4998
|
await writeStoreJson(ws.root, ws.directory + "/state.json", state);
|
|
4811
|
-
return { report, message:
|
|
4999
|
+
return { report, message: message2 };
|
|
4812
5000
|
}));
|
|
4813
5001
|
}));
|
|
4814
5002
|
}
|
|
4815
5003
|
async function automationStatus(dir) {
|
|
5004
|
+
const { pendingKnowledge: pendingKnowledge2 } = await Promise.resolve().then(() => (init_pending(), pending_exports));
|
|
4816
5005
|
const ws = await profilePhase("automation.workspace", () => workspace(dir));
|
|
5006
|
+
const knowledge = await pendingKnowledge2(ws.root);
|
|
4817
5007
|
const execution = await executionStatus(ws.root, ws.directory);
|
|
4818
5008
|
const notifications = await failureNotifications(ws.root, ws.directory);
|
|
4819
5009
|
const raw = await readStoreJson(ws.root, ws.directory + "/state.json");
|
|
4820
|
-
if (raw === null) return { version: 1, status: execution.status === "not-observed" ? "not-observed" : "unavailable", root: ws.root, branch: ws.branch, baselinePaths: [], hosts: {}, execution, notifications };
|
|
5010
|
+
if (raw === null) return { version: 1, status: execution.status === "not-observed" ? "not-observed" : "unavailable", root: ws.root, branch: ws.branch, baselinePaths: [], hosts: {}, execution, notifications, knowledge };
|
|
4821
5011
|
const state = parseState(raw);
|
|
4822
5012
|
if (state.root !== ws.root || state.gitDir !== ws.gitDir || state.branch !== ws.branch) throw new Error("Automation state belongs to another workspace.");
|
|
4823
5013
|
const inputs = await readInputs(ws.root);
|
|
@@ -4840,6 +5030,8 @@ async function automationStatus(dir) {
|
|
|
4840
5030
|
hosts,
|
|
4841
5031
|
execution,
|
|
4842
5032
|
notifications,
|
|
5033
|
+
knowledge,
|
|
5034
|
+
notificationBaselineHead: state.notifications?.baselineHead ?? null,
|
|
4843
5035
|
note: "Observed events do not prove all tool paths are intercepted. Run check to verify the retained evidence."
|
|
4844
5036
|
};
|
|
4845
5037
|
}
|
|
@@ -4847,6 +5039,7 @@ var SCOPE, priority, cleanText, analysisSchema, sharedSchema, baselineDigest;
|
|
|
4847
5039
|
var init_runtime = __esm({
|
|
4848
5040
|
"src/automation/runtime.ts"() {
|
|
4849
5041
|
"use strict";
|
|
5042
|
+
init_notifications();
|
|
4850
5043
|
init_profile();
|
|
4851
5044
|
init_inspection();
|
|
4852
5045
|
init_execution();
|
|
@@ -4858,34 +5051,34 @@ var init_runtime = __esm({
|
|
|
4858
5051
|
SCOPE = "Documentation audit evidence only. Hook receipts show observed events, not complete interception. Resolved findings no longer fail their checks or have a recorded assessment covering current evidence. Repair and review only within the user's task authorization.";
|
|
4859
5052
|
priority = { resolved: 0, "review-required": 1, unresolved: 2, unverified: 3 };
|
|
4860
5053
|
cleanText = (text2) => text2.replace(/[\u0000-\u001f\u007f-\u009f]/g, " ").slice(0, 250);
|
|
4861
|
-
analysisSchema =
|
|
4862
|
-
id:
|
|
4863
|
-
fingerprint:
|
|
4864
|
-
completedAt:
|
|
4865
|
-
baselineDigest:
|
|
5054
|
+
analysisSchema = z14.object({
|
|
5055
|
+
id: z14.string(),
|
|
5056
|
+
fingerprint: z14.string(),
|
|
5057
|
+
completedAt: z14.number(),
|
|
5058
|
+
baselineDigest: z14.string(),
|
|
4866
5059
|
currentAudit: reportSchema.nullable().optional(),
|
|
4867
|
-
report:
|
|
4868
|
-
version:
|
|
4869
|
-
status:
|
|
4870
|
-
root:
|
|
4871
|
-
branch:
|
|
4872
|
-
head:
|
|
4873
|
-
baselinePaths:
|
|
4874
|
-
reportPath:
|
|
4875
|
-
findings:
|
|
4876
|
-
diagnostics:
|
|
4877
|
-
checks:
|
|
4878
|
-
ran:
|
|
4879
|
-
reused:
|
|
4880
|
-
skipped:
|
|
4881
|
-
auditReused:
|
|
5060
|
+
report: z14.object({
|
|
5061
|
+
version: z14.literal(1),
|
|
5062
|
+
status: z14.enum(["verified", "issues-remain", "incomplete", "unavailable"]),
|
|
5063
|
+
root: z14.string(),
|
|
5064
|
+
branch: z14.string(),
|
|
5065
|
+
head: z14.string(),
|
|
5066
|
+
baselinePaths: z14.array(z14.string()),
|
|
5067
|
+
reportPath: z14.string(),
|
|
5068
|
+
findings: z14.array(repairFindingSchema),
|
|
5069
|
+
diagnostics: z14.array(z14.string()),
|
|
5070
|
+
checks: z14.object({
|
|
5071
|
+
ran: z14.array(z14.string()),
|
|
5072
|
+
reused: z14.array(z14.string()),
|
|
5073
|
+
skipped: z14.array(z14.object({ check: z14.string(), reason: z14.string(), doc: z14.string().optional() })),
|
|
5074
|
+
auditReused: z14.boolean().optional()
|
|
4882
5075
|
}),
|
|
4883
|
-
counts:
|
|
4884
|
-
capture:
|
|
4885
|
-
scope:
|
|
5076
|
+
counts: z14.object({ resolved: z14.number(), unresolved: z14.number(), "review-required": z14.number(), unverified: z14.number() }),
|
|
5077
|
+
capture: z14.enum(["observed", "unknown"]),
|
|
5078
|
+
scope: z14.string()
|
|
4886
5079
|
})
|
|
4887
5080
|
});
|
|
4888
|
-
sharedSchema =
|
|
5081
|
+
sharedSchema = z14.object({ analysis: analysisSchema, digest: z14.string() });
|
|
4889
5082
|
baselineDigest = async (ws, state) => profilePhase("automation.baselines", async () => hash(await Promise.all(
|
|
4890
5083
|
state.baselines.map(async (b) => [b.path, await readStoreJson(ws.root, b.path)])
|
|
4891
5084
|
)));
|
|
@@ -4903,7 +5096,7 @@ var init_hook_root = __esm({
|
|
|
4903
5096
|
});
|
|
4904
5097
|
|
|
4905
5098
|
// src/automation/adapters.ts
|
|
4906
|
-
import { z as
|
|
5099
|
+
import { z as z15 } from "zod";
|
|
4907
5100
|
function managedHookCommand(host, platform = process.platform) {
|
|
4908
5101
|
const command = `mason --setup-host ${host} auto hook --host ${host}`;
|
|
4909
5102
|
return platform === "win32" ? `cmd.exe /d /s /c "where mason >nul 2>nul & if errorlevel 1 (exit /b 0) else (${command})"` : `if command -v mason >/dev/null 2>&1; then ${command}; fi`;
|
|
@@ -4929,15 +5122,15 @@ var init_adapters = __esm({
|
|
|
4929
5122
|
init_runtime();
|
|
4930
5123
|
init_store();
|
|
4931
5124
|
init_hook_root();
|
|
4932
|
-
inputSchema =
|
|
4933
|
-
cwd:
|
|
4934
|
-
session_id:
|
|
4935
|
-
hook_event_name:
|
|
4936
|
-
tool_name:
|
|
4937
|
-
tool_use_id:
|
|
4938
|
-
tool_input:
|
|
4939
|
-
stop_hook_active:
|
|
4940
|
-
permission_mode:
|
|
5125
|
+
inputSchema = z15.object({
|
|
5126
|
+
cwd: z15.string().min(1),
|
|
5127
|
+
session_id: z15.string().min(1).max(500),
|
|
5128
|
+
hook_event_name: z15.enum(["SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "Stop"]),
|
|
5129
|
+
tool_name: z15.string().optional(),
|
|
5130
|
+
tool_use_id: z15.string().max(500).optional(),
|
|
5131
|
+
tool_input: z15.unknown().optional(),
|
|
5132
|
+
stop_hook_active: z15.boolean().optional(),
|
|
5133
|
+
permission_mode: z15.string().optional()
|
|
4941
5134
|
});
|
|
4942
5135
|
HOOK_EVENTS = ["SessionStart", "UserPromptSubmit", "PreToolUse", "PostToolUse", "Stop"];
|
|
4943
5136
|
}
|
|
@@ -4953,7 +5146,7 @@ __export(ownership_exports, {
|
|
|
4953
5146
|
ownershipEdit: () => ownershipEdit,
|
|
4954
5147
|
ownershipSchema: () => ownershipSchema
|
|
4955
5148
|
});
|
|
4956
|
-
import { z as
|
|
5149
|
+
import { z as z16 } from "zod";
|
|
4957
5150
|
import { parse } from "smol-toml";
|
|
4958
5151
|
function blockSpan(text2, start, end) {
|
|
4959
5152
|
const starts = text2.split(start).length - 1, ends = text2.split(end).length - 1;
|
|
@@ -5004,15 +5197,15 @@ var init_ownership = __esm({
|
|
|
5004
5197
|
["<!-- mason:agents:start -->", "<!-- mason:agents:end -->"],
|
|
5005
5198
|
["# mason:mcp:start", "# mason:mcp:end"]
|
|
5006
5199
|
];
|
|
5007
|
-
fileSchema =
|
|
5008
|
-
created:
|
|
5009
|
-
initialHash:
|
|
5010
|
-
blocks:
|
|
5011
|
-
mcpHash:
|
|
5012
|
-
hookCommands:
|
|
5013
|
-
hooks:
|
|
5200
|
+
fileSchema = z16.object({
|
|
5201
|
+
created: z16.boolean(),
|
|
5202
|
+
initialHash: z16.string(),
|
|
5203
|
+
blocks: z16.record(z16.string()),
|
|
5204
|
+
mcpHash: z16.string().optional(),
|
|
5205
|
+
hookCommands: z16.array(z16.string()).optional(),
|
|
5206
|
+
hooks: z16.record(z16.array(z16.string())).optional()
|
|
5014
5207
|
});
|
|
5015
|
-
ownershipSchema =
|
|
5208
|
+
ownershipSchema = z16.object({ version: z16.literal(1), files: z16.record(fileSchema) });
|
|
5016
5209
|
}
|
|
5017
5210
|
});
|
|
5018
5211
|
|
|
@@ -5027,7 +5220,7 @@ __export(install_exports, {
|
|
|
5027
5220
|
planAutomationInstall: () => planAutomationInstall,
|
|
5028
5221
|
recordSchema: () => recordSchema2
|
|
5029
5222
|
});
|
|
5030
|
-
import { z as
|
|
5223
|
+
import { z as z17 } from "zod";
|
|
5031
5224
|
async function installationRecord(root) {
|
|
5032
5225
|
return recordSchema2.parse(await readStoreJson(root, AUTOMATION_PATH) ?? { version: 1, hosts: {} });
|
|
5033
5226
|
}
|
|
@@ -5108,9 +5301,9 @@ var init_install = __esm({
|
|
|
5108
5301
|
init_store();
|
|
5109
5302
|
init_files2();
|
|
5110
5303
|
init_ownership();
|
|
5111
|
-
groupSchema =
|
|
5112
|
-
automationConfigSchema =
|
|
5113
|
-
recordSchema2 =
|
|
5304
|
+
groupSchema = z17.object({ hooks: z17.array(z17.object({ type: z17.string(), command: z17.string().optional() }).passthrough()) }).passthrough();
|
|
5305
|
+
automationConfigSchema = z17.object({ hooks: z17.record(z17.array(groupSchema)).optional() }).passthrough();
|
|
5306
|
+
recordSchema2 = z17.object({ version: z17.literal(1), hosts: z17.record(z17.object({ command: z17.string() })) });
|
|
5114
5307
|
AUTOMATION_PATH = ".mason/local/automation.json";
|
|
5115
5308
|
configPath = (host) => host === "claude" ? ".claude/settings.json" : ".codex/hooks.json";
|
|
5116
5309
|
}
|
|
@@ -5128,7 +5321,7 @@ __export(config_exports, {
|
|
|
5128
5321
|
});
|
|
5129
5322
|
import { isDeepStrictEqual } from "util";
|
|
5130
5323
|
import { parse as parse2, stringify } from "smol-toml";
|
|
5131
|
-
import { z as
|
|
5324
|
+
import { z as z18 } from "zod";
|
|
5132
5325
|
async function instructionEdits(root, host) {
|
|
5133
5326
|
const found = await Promise.all(DOC_CANDIDATES.map(async (file) => ({ path: file, text: await readText(root, file) })));
|
|
5134
5327
|
const existing = found.find((f) => f.text !== null);
|
|
@@ -5239,7 +5432,7 @@ var init_config = __esm({
|
|
|
5239
5432
|
init_install();
|
|
5240
5433
|
init_files2();
|
|
5241
5434
|
init_launcher();
|
|
5242
|
-
object =
|
|
5435
|
+
object = z18.record(z18.unknown());
|
|
5243
5436
|
mcpPath = (host) => host === "codex" ? ".codex/config.toml" : ".mcp.json";
|
|
5244
5437
|
TOML_START = "# mason:mcp:start";
|
|
5245
5438
|
TOML_END = "# mason:mcp:end";
|
|
@@ -5249,7 +5442,7 @@ var init_config = __esm({
|
|
|
5249
5442
|
});
|
|
5250
5443
|
|
|
5251
5444
|
// src/mcp/init.ts
|
|
5252
|
-
import { z as
|
|
5445
|
+
import { z as z19 } from "zod";
|
|
5253
5446
|
async function loadProjectMarker(rootDir) {
|
|
5254
5447
|
const raw = await readStoreJson(rootDir, ".mason/local/project.json");
|
|
5255
5448
|
if (raw === null) return null;
|
|
@@ -5257,8 +5450,8 @@ async function loadProjectMarker(rootDir) {
|
|
|
5257
5450
|
return { ...marker, features: await loadProjectFeatures(rootDir) };
|
|
5258
5451
|
}
|
|
5259
5452
|
async function loadProjectFeatures(rootDir) {
|
|
5260
|
-
const config =
|
|
5261
|
-
return
|
|
5453
|
+
const config = z19.record(z19.unknown()).parse(await readStoreJson(rootDir, ".mason/config.json") ?? {});
|
|
5454
|
+
return z19.object({ confluence: z19.boolean().optional() }).passthrough().parse(config.features ?? {});
|
|
5262
5455
|
}
|
|
5263
5456
|
async function saveProjectMarker(rootDir, marker) {
|
|
5264
5457
|
const { ancillaryEdits: ancillaryEdits2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
@@ -5270,8 +5463,8 @@ async function projectMarkerEdits(rootDir, marker) {
|
|
|
5270
5463
|
const edits = [{ path: file, before: await readText(rootDir, file), after: JSON.stringify(local, null, 2) + "\n" }];
|
|
5271
5464
|
if (features && Object.keys(features).length) {
|
|
5272
5465
|
const configPath2 = ".mason/config.json", before = await readText(rootDir, configPath2);
|
|
5273
|
-
const config =
|
|
5274
|
-
config.features = { ...
|
|
5466
|
+
const config = z19.record(z19.unknown()).parse(JSON.parse(before ?? "{}"));
|
|
5467
|
+
config.features = { ...z19.record(z19.unknown()).parse(config.features ?? {}), ...features };
|
|
5275
5468
|
edits.push({ path: configPath2, before, after: JSON.stringify(config, null, 2) + "\n" });
|
|
5276
5469
|
}
|
|
5277
5470
|
return edits;
|
|
@@ -5285,10 +5478,10 @@ var init_init = __esm({
|
|
|
5285
5478
|
"use strict";
|
|
5286
5479
|
init_storage();
|
|
5287
5480
|
init_files2();
|
|
5288
|
-
markerSchema =
|
|
5289
|
-
version:
|
|
5290
|
-
initializedAt:
|
|
5291
|
-
features:
|
|
5481
|
+
markerSchema = z19.object({
|
|
5482
|
+
version: z19.literal(1),
|
|
5483
|
+
initializedAt: z19.string(),
|
|
5484
|
+
features: z19.object({ confluence: z19.boolean().optional() }).passthrough().optional()
|
|
5292
5485
|
}).passthrough();
|
|
5293
5486
|
CLAUDE_MD_SECTION = `<!-- mason:start -->
|
|
5294
5487
|
## Mason project knowledge
|
|
@@ -5297,9 +5490,10 @@ Mason provides recorded decisions and file impact over MCP. A concept map is opt
|
|
|
5297
5490
|
|
|
5298
5491
|
- Task, bug, change request, or investigation of why the project works this way \u2192 \`get_context\` with the task text and known files: matching decisions, related tests, impact, and any available map entries.
|
|
5299
5492
|
- Before editing a file \u2192 \`get_impact\` to check references, tests, and historical change partners.
|
|
5300
|
-
- Investigation or correction reveals a reusable project lesson \u2192 \`save_decision\`
|
|
5493
|
+
- Investigation or correction reveals a reusable project lesson \u2192 \`save_decision\` as soon as the lesson is supported by evidence; do not wait for implementation, task completion, or merge. Record the established observation now and identify unimplemented remedies as tentative. Capture only the lasting constraint and reason, with anchors and known sources, owner, and recorder. This creates a proposal; never infer approval. Preserve uncertain causes and unknown attribution. Route project lessons here; keep personal preferences in agent memory. Skip code summaries, current checkout status, temporary task permissions, session trivia, and secrets. No qualifying lesson means no record.
|
|
5301
5494
|
- Before saving, compare the lesson with matching \`get_context\` records and any pending proposal. If new evidence changes the same lesson's assumptions, scope, or recommended action, revise it with \`save_decision(id: existingId)\`, including when it is accepted. Preserve supported rationale and sources, replace obsolete instructions, and add the new evidence. Create a separate record for a genuinely distinct lesson; skip unchanged restatements. Revision preserves history and leaves the accepted version operative until authorized review.
|
|
5302
5495
|
- Consult trust metadata before relying on entries: unknown or changed freshness requires inspection, stale or unknown map verification requires a fresh evidence review, and a recorded failed verdict means the description must be corrected. Check approval too: proposals are suggestions, legacy records are unreviewed, and accepted decisions are recorded constraints subject to freshness checks. An accepted revision remains operative while a pending proposal is reviewed; keep both versions and their freshness distinct.
|
|
5496
|
+
- Asked to review pending project knowledge \u2192 \`mason_automation(action: "status")\` lists pending proposals and uncommitted records. For ordinary tasks, inspect matching proposals through \`get_context\`; do not request acceptance merely because a proposal exists.
|
|
5303
5497
|
- Asked to review or re-verify a decision \u2192 \`review_decision\` first to inspect content, sources, history, and code changes. Record acceptance, reaffirmation, or retirement only when authorized by the user or a cited team review, with the actual reviewer and reason. Never infer approval from unchanged code. Review and commit the local record through the normal project workflow.
|
|
5304
5498
|
- For an architectural overview, use \`get_snapshot\` if a map is available. If \`map.status\` is missing or invalid, use available decisions and source evidence; do not start building a map unless requested.
|
|
5305
5499
|
- \`mason_init\` returns documentation audit and committed-diff review results, plus a short setup guide. Pass \`evidence\` with local CI manifest paths to include test and analysis results; the CLI equivalent is \`mason-review --evidence <manifest>\`. State skipped, unavailable, stale, or unknown checks explicitly. Related accepted decisions identify review context, not proven violations.
|
|
@@ -5323,7 +5517,7 @@ ${CLAUDE_MD_SECTION}`;
|
|
|
5323
5517
|
|
|
5324
5518
|
1. Explain the actionable findings with their source evidence. Separate audit issues, advisories, and skipped checks. The review covers committed changes from the merge base to HEAD; workingTree paths are not included in that review. An unavailable or empty check is not proof that the project is correct. Use the CLI for full output if a summary is truncated.
|
|
5325
5519
|
2. Address findings within the user's requested scope. Setup alone authorizes Mason host configuration, hooks, instructions, and ignore rules; rewriting existing project claims requires repair scope. If repair is authorized, call \`mason_repair(dir, action: "prepare")\` before editing; it saves the full original findings even when this summary is truncated. Inspect relevant source, make grounded edits, then call \`mason_repair(dir, action: "verify", baselinePath)\` with that same baseline, including after any final doc commit. Report resolved, unresolved, review-required, unverified, and new findings. Keep suppressed advisories visible even when setup has already dirtied a doc. Do not invent a decision just to populate the store.
|
|
5326
|
-
3. When the task reveals a real lesson or constraint, compare matching \`get_context\` records first. If its assumptions, scope, or recommended action changed, revise that record using \`save_decision(id: existingId)\`; create a separate record for a genuinely distinct lesson and skip unchanged restatements. Include title, body, category, anchors, and known owner/source/actor information. Preserve supported rationale and sources, replace obsolete instructions, and add new evidence. Missing attribution can be added later. The tool writes a local proposal; editing it preserves revision history and requires a new acceptance, while any earlier accepted revision remains operative. An unchanged save never refreshes its evidence. When decision review is requested, \`review_decision\` prepares the record and code evidence before any authorized verdict. Review and commit records through the normal workflow. Retrieve it on the next relevant task with \`get_context(dir, task, files)\`.
|
|
5520
|
+
3. Capture a supported lesson as soon as it is established; do not wait for implementation, task completion, or merge. Keep unimplemented remedies tentative. When the task reveals a real lesson or constraint, compare matching \`get_context\` records first. If its assumptions, scope, or recommended action changed, revise that record using \`save_decision(id: existingId)\`; create a separate record for a genuinely distinct lesson and skip unchanged restatements. Include title, body, category, anchors, and known owner/source/actor information. Preserve supported rationale and sources, replace obsolete instructions, and add new evidence. Missing attribution can be added later. The tool writes a local proposal; editing it preserves revision history and requires a new acceptance, while any earlier accepted revision remains operative. An unchanged save never refreshes its evidence. When decision review is requested, \`review_decision\` prepares the record and code evidence before any authorized verdict. Review and commit records through the normal workflow. Retrieve it on the next relevant task with \`get_context(dir, task, files)\`.
|
|
5327
5521
|
|
|
5328
5522
|
${ASSISTANT_SETUP}
|
|
5329
5523
|
|
|
@@ -5486,7 +5680,7 @@ var init_types2 = __esm({
|
|
|
5486
5680
|
});
|
|
5487
5681
|
|
|
5488
5682
|
// src/review/evidence/vitest.ts
|
|
5489
|
-
import { z as
|
|
5683
|
+
import { z as z20 } from "zod";
|
|
5490
5684
|
function parseVitest(raw, sourceRoot) {
|
|
5491
5685
|
const report = schema.parse(raw);
|
|
5492
5686
|
const findings = [], diagnostics = [];
|
|
@@ -5535,24 +5729,24 @@ var init_vitest = __esm({
|
|
|
5535
5729
|
"use strict";
|
|
5536
5730
|
init_paths2();
|
|
5537
5731
|
init_types2();
|
|
5538
|
-
count3 =
|
|
5539
|
-
schema =
|
|
5540
|
-
success:
|
|
5732
|
+
count3 = z20.number().int().nonnegative();
|
|
5733
|
+
schema = z20.object({
|
|
5734
|
+
success: z20.boolean(),
|
|
5541
5735
|
numTotalTests: count3,
|
|
5542
5736
|
numPassedTests: count3,
|
|
5543
5737
|
numFailedTests: count3,
|
|
5544
5738
|
numPendingTests: count3,
|
|
5545
5739
|
numTodoTests: count3,
|
|
5546
5740
|
numFailedTestSuites: count3,
|
|
5547
|
-
testResults:
|
|
5548
|
-
name:
|
|
5549
|
-
status:
|
|
5550
|
-
message:
|
|
5551
|
-
assertionResults:
|
|
5552
|
-
fullName:
|
|
5553
|
-
status:
|
|
5554
|
-
failureMessages:
|
|
5555
|
-
location:
|
|
5741
|
+
testResults: z20.array(z20.object({
|
|
5742
|
+
name: z20.string().min(1),
|
|
5743
|
+
status: z20.enum(["passed", "failed"]),
|
|
5744
|
+
message: z20.string().optional(),
|
|
5745
|
+
assertionResults: z20.array(z20.object({
|
|
5746
|
+
fullName: z20.string(),
|
|
5747
|
+
status: z20.enum(["passed", "failed", "pending", "skipped", "todo", "disabled"]),
|
|
5748
|
+
failureMessages: z20.array(z20.string()).nullable().optional(),
|
|
5749
|
+
location: z20.object({ line: count3, column: count3 }).nullable().optional()
|
|
5556
5750
|
}))
|
|
5557
5751
|
}))
|
|
5558
5752
|
});
|
|
@@ -5560,7 +5754,7 @@ var init_vitest = __esm({
|
|
|
5560
5754
|
});
|
|
5561
5755
|
|
|
5562
5756
|
// src/review/evidence/sarif.ts
|
|
5563
|
-
import { z as
|
|
5757
|
+
import { z as z21 } from "zod";
|
|
5564
5758
|
function parseSarif(raw, sourceRoot) {
|
|
5565
5759
|
const report = schema2.parse(raw), findings = [], diagnostics = [];
|
|
5566
5760
|
let active = 0, suppressed = 0, absent = 0, unresolved = 0;
|
|
@@ -5651,29 +5845,29 @@ var init_sarif = __esm({
|
|
|
5651
5845
|
"use strict";
|
|
5652
5846
|
init_paths2();
|
|
5653
5847
|
init_types2();
|
|
5654
|
-
index =
|
|
5655
|
-
artifact =
|
|
5656
|
-
message =
|
|
5657
|
-
level =
|
|
5658
|
-
location =
|
|
5659
|
-
schema2 =
|
|
5660
|
-
version:
|
|
5661
|
-
runs:
|
|
5662
|
-
tool:
|
|
5663
|
-
invocations:
|
|
5664
|
-
versionControlProvenance:
|
|
5665
|
-
originalUriBaseIds:
|
|
5666
|
-
artifacts:
|
|
5667
|
-
results:
|
|
5668
|
-
ruleId:
|
|
5848
|
+
index = z21.number().int().nonnegative();
|
|
5849
|
+
artifact = z21.object({ uri: z21.string().optional(), uriBaseId: z21.string().optional(), index: index.optional() });
|
|
5850
|
+
message = z21.object({ text: z21.string().optional(), markdown: z21.string().optional(), id: z21.string().optional(), arguments: z21.array(z21.string()).optional() });
|
|
5851
|
+
level = z21.enum(["error", "warning", "note", "none"]);
|
|
5852
|
+
location = z21.object({ physicalLocation: z21.object({ artifactLocation: artifact.optional(), region: z21.object({ startLine: index.optional(), startColumn: index.optional() }).optional() }).optional() });
|
|
5853
|
+
schema2 = z21.object({
|
|
5854
|
+
version: z21.literal("2.1.0"),
|
|
5855
|
+
runs: z21.array(z21.object({
|
|
5856
|
+
tool: z21.object({ driver: z21.object({ name: z21.string().min(1), rules: z21.array(z21.object({ id: z21.string(), defaultConfiguration: z21.object({ level: level.optional() }).optional(), messageStrings: z21.record(message).optional() })).optional(), globalMessageStrings: z21.record(message).optional() }) }),
|
|
5857
|
+
invocations: z21.array(z21.object({ executionSuccessful: z21.boolean(), commandLine: z21.string().optional(), toolExecutionNotifications: z21.array(z21.object({ level: level.optional(), message })).optional() })).optional(),
|
|
5858
|
+
versionControlProvenance: z21.array(z21.object({ revisionId: z21.string().optional() })).optional(),
|
|
5859
|
+
originalUriBaseIds: z21.record(artifact).optional(),
|
|
5860
|
+
artifacts: z21.array(z21.object({ location: artifact.optional() })).optional(),
|
|
5861
|
+
results: z21.array(z21.object({
|
|
5862
|
+
ruleId: z21.string().optional(),
|
|
5669
5863
|
ruleIndex: index.optional(),
|
|
5670
5864
|
message,
|
|
5671
5865
|
level: level.optional(),
|
|
5672
|
-
kind:
|
|
5673
|
-
baselineState:
|
|
5674
|
-
suppressions:
|
|
5675
|
-
locations:
|
|
5676
|
-
relatedLocations:
|
|
5866
|
+
kind: z21.enum(["fail", "pass", "open", "informational", "notApplicable", "review"]).optional(),
|
|
5867
|
+
baselineState: z21.enum(["new", "unchanged", "updated", "absent"]).optional(),
|
|
5868
|
+
suppressions: z21.array(z21.object({ kind: z21.enum(["inSource", "external"]), status: z21.enum(["accepted", "underReview", "rejected"]).optional() })).nullable().optional(),
|
|
5869
|
+
locations: z21.array(location).optional(),
|
|
5870
|
+
relatedLocations: z21.array(location).optional()
|
|
5677
5871
|
})).optional()
|
|
5678
5872
|
}))
|
|
5679
5873
|
});
|
|
@@ -5681,7 +5875,7 @@ var init_sarif = __esm({
|
|
|
5681
5875
|
});
|
|
5682
5876
|
|
|
5683
5877
|
// src/review/evidence/check.ts
|
|
5684
|
-
import { z as
|
|
5878
|
+
import { z as z22 } from "zod";
|
|
5685
5879
|
function parseCheck(raw, sourceRoot) {
|
|
5686
5880
|
const report = schema3.parse(raw);
|
|
5687
5881
|
const diagnostics = [], findings = [];
|
|
@@ -5721,17 +5915,17 @@ var init_check = __esm({
|
|
|
5721
5915
|
"use strict";
|
|
5722
5916
|
init_paths2();
|
|
5723
5917
|
init_types2();
|
|
5724
|
-
schema3 =
|
|
5725
|
-
version:
|
|
5726
|
-
commit:
|
|
5727
|
-
results:
|
|
5728
|
-
name:
|
|
5729
|
-
status:
|
|
5730
|
-
message:
|
|
5731
|
-
locations:
|
|
5732
|
-
file:
|
|
5733
|
-
line:
|
|
5734
|
-
column:
|
|
5918
|
+
schema3 = z22.object({
|
|
5919
|
+
version: z22.literal(1),
|
|
5920
|
+
commit: z22.string().regex(/^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/).optional(),
|
|
5921
|
+
results: z22.array(z22.object({
|
|
5922
|
+
name: z22.string().min(1).max(1e3),
|
|
5923
|
+
status: z22.enum(["passed", "failed", "skipped"]),
|
|
5924
|
+
message: z22.string().max(1e5).optional(),
|
|
5925
|
+
locations: z22.array(z22.object({
|
|
5926
|
+
file: z22.string().min(1).max(4e3),
|
|
5927
|
+
line: z22.number().int().positive().optional(),
|
|
5928
|
+
column: z22.number().int().positive().optional()
|
|
5735
5929
|
})).max(100).default([])
|
|
5736
5930
|
})).max(1e5)
|
|
5737
5931
|
});
|
|
@@ -5740,7 +5934,7 @@ var init_check = __esm({
|
|
|
5740
5934
|
|
|
5741
5935
|
// src/review/evidence.ts
|
|
5742
5936
|
import path29 from "path";
|
|
5743
|
-
import { z as
|
|
5937
|
+
import { z as z23 } from "zod";
|
|
5744
5938
|
function relativeArtifact(root, file) {
|
|
5745
5939
|
const relative = path29.isAbsolute(file) ? path29.relative(root, file) : file;
|
|
5746
5940
|
const normalized = normalizeRepoPath(relative);
|
|
@@ -5781,7 +5975,7 @@ async function collectReviewEvidence(root, manifests, changedFiles, decisions, d
|
|
|
5781
5975
|
let manifest, raw;
|
|
5782
5976
|
try {
|
|
5783
5977
|
manifest = relativeArtifact(root, supplied);
|
|
5784
|
-
raw =
|
|
5978
|
+
raw = z23.object({ version: z23.literal(1), checks: z23.array(z23.unknown()) }).parse(await readStoreJson(root, manifest));
|
|
5785
5979
|
} catch (error) {
|
|
5786
5980
|
output.diagnostics.push(`${supplied}: ${String(error)}`);
|
|
5787
5981
|
continue;
|
|
@@ -5936,25 +6130,25 @@ var init_evidence2 = __esm({
|
|
|
5936
6130
|
init_sarif();
|
|
5937
6131
|
init_check();
|
|
5938
6132
|
init_types2();
|
|
5939
|
-
checkSchema2 =
|
|
5940
|
-
id:
|
|
5941
|
-
kind:
|
|
5942
|
-
tool:
|
|
5943
|
-
command:
|
|
5944
|
-
commit:
|
|
5945
|
-
workingTreeClean:
|
|
5946
|
-
source:
|
|
5947
|
-
sourceRoot:
|
|
5948
|
-
status:
|
|
5949
|
-
reason:
|
|
5950
|
-
exitCode:
|
|
5951
|
-
environment:
|
|
5952
|
-
toolVersion:
|
|
5953
|
-
runtime:
|
|
5954
|
-
platform:
|
|
5955
|
-
configuration:
|
|
6133
|
+
checkSchema2 = z23.object({
|
|
6134
|
+
id: z23.string().min(1).max(100),
|
|
6135
|
+
kind: z23.enum(["tests", "static-analysis", "security", "complexity", "duplication", "documentation"]),
|
|
6136
|
+
tool: z23.string().min(1).max(200),
|
|
6137
|
+
command: z23.string().min(1).max(2e3),
|
|
6138
|
+
commit: z23.string().regex(/^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/).nullable().optional(),
|
|
6139
|
+
workingTreeClean: z23.boolean().optional(),
|
|
6140
|
+
source: z23.string().max(2e3).optional(),
|
|
6141
|
+
sourceRoot: z23.string().min(1).max(4e3).optional(),
|
|
6142
|
+
status: z23.enum(["completed", "skipped", "unavailable"]).default("completed"),
|
|
6143
|
+
reason: z23.string().min(1).max(2e3).optional(),
|
|
6144
|
+
exitCode: z23.number().int().nullable().optional(),
|
|
6145
|
+
environment: z23.object({
|
|
6146
|
+
toolVersion: z23.string().min(1).max(200),
|
|
6147
|
+
runtime: z23.string().min(1).max(200).optional(),
|
|
6148
|
+
platform: z23.string().min(1).max(200).optional(),
|
|
6149
|
+
configuration: z23.array(z23.string().min(1).max(4e3)).max(100).optional()
|
|
5956
6150
|
}).optional(),
|
|
5957
|
-
report:
|
|
6151
|
+
report: z23.object({ format: z23.enum(["vitest-json", "sarif", "mason-check-json"]), path: z23.string().min(1).max(4e3) }).optional()
|
|
5958
6152
|
});
|
|
5959
6153
|
}
|
|
5960
6154
|
});
|
|
@@ -6744,7 +6938,7 @@ __export(observations_exports, {
|
|
|
6744
6938
|
readObservation: () => readObservation
|
|
6745
6939
|
});
|
|
6746
6940
|
import fs23 from "fs/promises";
|
|
6747
|
-
import { z as
|
|
6941
|
+
import { z as z24 } from "zod";
|
|
6748
6942
|
function observationPath(directory, host, revision, version = executingVersion()) {
|
|
6749
6943
|
return `${directory}/activation/${host}-${revision}-${hash(version).slice(0, 12)}.json`;
|
|
6750
6944
|
}
|
|
@@ -6815,19 +7009,19 @@ var init_observations = __esm({
|
|
|
6815
7009
|
init_storage();
|
|
6816
7010
|
init_model();
|
|
6817
7011
|
init_launcher();
|
|
6818
|
-
observationSchema =
|
|
6819
|
-
version:
|
|
6820
|
-
masonVersion:
|
|
6821
|
-
root:
|
|
6822
|
-
revision:
|
|
6823
|
-
host:
|
|
6824
|
-
contextCalls:
|
|
6825
|
-
lastContextAt:
|
|
6826
|
-
sessions:
|
|
6827
|
-
events:
|
|
6828
|
-
at:
|
|
6829
|
-
verificationStatus:
|
|
6830
|
-
reportPath:
|
|
7012
|
+
observationSchema = z24.object({
|
|
7013
|
+
version: z24.literal(1),
|
|
7014
|
+
masonVersion: z24.string(),
|
|
7015
|
+
root: z24.string(),
|
|
7016
|
+
revision: z24.string(),
|
|
7017
|
+
host: z24.enum(["codex", "claude"]),
|
|
7018
|
+
contextCalls: z24.number().int().nonnegative(),
|
|
7019
|
+
lastContextAt: z24.string().optional(),
|
|
7020
|
+
sessions: z24.record(z24.object({
|
|
7021
|
+
events: z24.array(z24.enum(events)),
|
|
7022
|
+
at: z24.string(),
|
|
7023
|
+
verificationStatus: z24.string().optional(),
|
|
7024
|
+
reportPath: z24.string().optional()
|
|
6831
7025
|
}))
|
|
6832
7026
|
});
|
|
6833
7027
|
}
|
|
@@ -7962,7 +8156,7 @@ init_advisory_review();
|
|
|
7962
8156
|
init_decisions();
|
|
7963
8157
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7964
8158
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
7965
|
-
import { z as
|
|
8159
|
+
import { z as z25 } from "zod";
|
|
7966
8160
|
|
|
7967
8161
|
// src/mcp/tools.ts
|
|
7968
8162
|
init_repair();
|
|
@@ -8591,14 +8785,14 @@ init_files();
|
|
|
8591
8785
|
import { createHash as createHash4 } from "crypto";
|
|
8592
8786
|
import { execFile as execFile5 } from "child_process";
|
|
8593
8787
|
import { promisify as promisify5 } from "util";
|
|
8594
|
-
import { z as
|
|
8788
|
+
import { z as z11 } from "zod";
|
|
8595
8789
|
var exec3 = promisify5(execFile5);
|
|
8596
|
-
var requestSchema =
|
|
8597
|
-
id:
|
|
8598
|
-
action:
|
|
8599
|
-
reviewer:
|
|
8600
|
-
note:
|
|
8601
|
-
reviewToken:
|
|
8790
|
+
var requestSchema = z11.object({
|
|
8791
|
+
id: z11.string().regex(/^[a-zA-Z0-9_-]+$/),
|
|
8792
|
+
action: z11.enum(["prepare", "accept", "reaffirm", "retire"]).default("prepare"),
|
|
8793
|
+
reviewer: z11.string().trim().min(1).max(200).optional(),
|
|
8794
|
+
note: z11.string().trim().min(1).max(1500).optional(),
|
|
8795
|
+
reviewToken: z11.string().regex(/^[a-f0-9]{64}$/).optional()
|
|
8602
8796
|
});
|
|
8603
8797
|
async function reviewState(root, record) {
|
|
8604
8798
|
const [headHash, workingTree, changes] = await Promise.all([
|
|
@@ -8825,16 +9019,16 @@ init_lock();
|
|
|
8825
9019
|
init_storage();
|
|
8826
9020
|
init_snapshot();
|
|
8827
9021
|
import fs17 from "fs/promises";
|
|
8828
|
-
import { z as
|
|
9022
|
+
import { z as z12 } from "zod";
|
|
8829
9023
|
var DIRECTORY = ".mason/partial-snapshots";
|
|
8830
|
-
var partialSchema =
|
|
8831
|
-
batchId:
|
|
8832
|
-
offset:
|
|
8833
|
-
features:
|
|
8834
|
-
flows:
|
|
8835
|
-
savedAt:
|
|
9024
|
+
var partialSchema = z12.object({
|
|
9025
|
+
batchId: z12.string().regex(/^[a-zA-Z0-9_-]+$/),
|
|
9026
|
+
offset: z12.number().int().nonnegative(),
|
|
9027
|
+
features: z12.record(featureSchema),
|
|
9028
|
+
flows: z12.record(flowSchema),
|
|
9029
|
+
savedAt: z12.string()
|
|
8836
9030
|
});
|
|
8837
|
-
var scopeSchema2 =
|
|
9031
|
+
var scopeSchema2 = z12.object({ files: z12.array(z12.string()), savedAt: z12.string() });
|
|
8838
9032
|
async function savePartial(rootDir, partial) {
|
|
8839
9033
|
if (!/^[a-zA-Z0-9_-]+$/.test(partial.batchId)) throw new Error(`Invalid batchId: ${partial.batchId}`);
|
|
8840
9034
|
await withSnapshotWrite(rootDir, () => writeStoreJson(rootDir, `${DIRECTORY}/${partial.batchId}.json`, partialSchema.parse(partial)));
|
|
@@ -9833,21 +10027,21 @@ function createMcpServer() {
|
|
|
9833
10027
|
const server = new McpServer(
|
|
9834
10028
|
{
|
|
9835
10029
|
name: "mason",
|
|
9836
|
-
version: "0.19.
|
|
10030
|
+
version: "0.19.2"
|
|
9837
10031
|
},
|
|
9838
10032
|
{
|
|
9839
|
-
instructions: (setupNotice ? setupNotice + "\n\n" : "") + 'Mason retrieves recorded decisions, file impact, and optional feature/flow maps. Use get_context with the task and known files, and get_impact before editing. Save learned rationale and constraints with save_decision; review and commit the local records through the project workflow. These tools work without initialization or a concept map. Consult trust and diagnostics: changed or unknown freshness needs source inspection, stale or unknown map verification needs a fresh review, recorded failed verdicts need correction, and proposals are suggestions and legacy records are unreviewed. Accepted decisions are recorded team constraints, still subject to freshness checks. Use review_decision to prepare code evidence and record only authorized acceptance, reaffirmation, or retirement. Never invent a reviewer or treat these recorded identities as authenticated approval. mason_init returns documentation audit and committed-diff review findings with a quickstart guide. Use mode: "map" only when a full architecture map is requested. A missing map is not a setup failure; use decisions and source evidence. get_snapshot provides architecture navigation when a map is available. The mason-audit and mason-review CLIs also work without setup.'
|
|
10033
|
+
instructions: (setupNotice ? setupNotice + "\n\n" : "") + 'Mason retrieves recorded decisions, file impact, and optional feature/flow maps. Use get_context with the task and known files, and get_impact before editing. Save learned rationale and constraints with save_decision as soon as evidence supports them, without waiting for implementation or merge; review and commit the local records through the project workflow. These tools work without initialization or a concept map. Consult trust and diagnostics: changed or unknown freshness needs source inspection, stale or unknown map verification needs a fresh review, recorded failed verdicts need correction, and proposals are suggestions and legacy records are unreviewed. Accepted decisions are recorded team constraints, still subject to freshness checks. Use review_decision to prepare code evidence and record only authorized acceptance, reaffirmation, or retirement. Never invent a reviewer or treat these recorded identities as authenticated approval. mason_init returns documentation audit and committed-diff review findings with a quickstart guide. Use mode: "map" only when a full architecture map is requested. A missing map is not a setup failure; use decisions and source evidence. get_snapshot provides architecture navigation when a map is available. The mason-audit and mason-review CLIs also work without setup.'
|
|
9840
10034
|
}
|
|
9841
10035
|
);
|
|
9842
10036
|
server.tool(
|
|
9843
10037
|
"mason_init",
|
|
9844
10038
|
"Inspect this project now: returns documentation audit findings, committed-diff review findings, decision/map status, and a quickstart playbook. Quickstart and map modes are read-only and deterministic. Explicit mode: setup configures MCP, instructions and lifecycle hooks to use mason on PATH while retaining original audit evidence; use it only when the user requests setup. Optional host selects codex or claude. Optional base selects the review comparison; evidence imports CI manifests with check outcomes, commit freshness, and links to changed files and accepted decisions. mode: map returns the full Map-Reduce build workflow. Repeat calls refresh findings even after setup.",
|
|
9845
10039
|
{
|
|
9846
|
-
dir:
|
|
9847
|
-
mode:
|
|
9848
|
-
host:
|
|
9849
|
-
base:
|
|
9850
|
-
evidence:
|
|
10040
|
+
dir: z25.string().describe("Absolute path to the project root directory"),
|
|
10041
|
+
mode: z25.enum(["quickstart", "map", "setup"]).optional().default("quickstart").describe("Quickstart inspects without edits; map requests an architecture build; setup installs the shared onboarding flow."),
|
|
10042
|
+
host: z25.enum(["codex", "claude"]).optional().describe("Assistant to configure in setup mode; inferred only when unambiguous."),
|
|
10043
|
+
base: z25.string().optional().describe("Git ref for committed-diff review. Defaults to the first available main branch ref."),
|
|
10044
|
+
evidence: z25.array(z25.string()).max(10).optional().describe("Repository-local CI evidence manifests to include in the review. Imports Vitest JSON, SARIF, and native-validator mason-check-json results without executing check commands.")
|
|
9851
10045
|
},
|
|
9852
10046
|
async ({ dir, mode, host, base, evidence }) => {
|
|
9853
10047
|
const result = await masonInit(dir, { mode, host, base, evidence });
|
|
@@ -9856,10 +10050,10 @@ function createMcpServer() {
|
|
|
9856
10050
|
);
|
|
9857
10051
|
server.tool(
|
|
9858
10052
|
"mason_automation",
|
|
9859
|
-
"Inspect installed automation
|
|
10053
|
+
"Inspect installed automation, observed host events, pending decision records and the notification baseline, or check all retained documentation findings across sessions. status is read-only; check saves local baselines and verification reports without editing source, approving advisories or consuming pending completion notices. Returns concise results with a full report path. Works without a map.",
|
|
9860
10054
|
{
|
|
9861
|
-
dir:
|
|
9862
|
-
action:
|
|
10055
|
+
dir: z25.string().describe("Absolute path to the project directory"),
|
|
10056
|
+
action: z25.enum(["status", "check"]).describe("Inspect configuration and receipts, or capture/resume and verify original audit evidence.")
|
|
9863
10057
|
},
|
|
9864
10058
|
async ({ dir, action }) => ({ content: [{ type: "text", text: await masonAutomation(dir, action) }] })
|
|
9865
10059
|
);
|
|
@@ -9867,10 +10061,10 @@ function createMcpServer() {
|
|
|
9867
10061
|
"mason_repair",
|
|
9868
10062
|
"Track documentation repairs against original audit evidence. prepare saves a local baseline and returns a scoped work order; verify reads that baseline and reports resolved, unresolved, review-required, unverified, and new findings. Suppressed advisories remain unresolved. Does not edit documentation or approve decisions. No map required.",
|
|
9869
10063
|
{
|
|
9870
|
-
dir:
|
|
9871
|
-
action:
|
|
9872
|
-
baselinePath:
|
|
9873
|
-
checks:
|
|
10064
|
+
dir: z25.string().describe("Absolute path to the project root directory"),
|
|
10065
|
+
action: z25.enum(["prepare", "verify"]),
|
|
10066
|
+
baselinePath: z25.string().optional().describe("Original baseline path returned by prepare; required for verify."),
|
|
10067
|
+
checks: z25.array(z25.enum(["deleted-reference", "new-module", "stale-count", "dead-command", "deps-changed", "decision-anchor-drift"])).min(1).optional().describe("Optional audit check subset for prepare. Verification always uses the original checks.")
|
|
9874
10068
|
},
|
|
9875
10069
|
async ({ dir, action, baselinePath, checks }) => {
|
|
9876
10070
|
const result = await masonRepair(dir, { action, baselinePath, checks });
|
|
@@ -9880,15 +10074,15 @@ function createMcpServer() {
|
|
|
9880
10074
|
server.tool(
|
|
9881
10075
|
"review_advisory",
|
|
9882
10076
|
"Prepare an assessment of an original repair advisory and its exact repository scope, then record authorized addressed, inapplicable or deferred outcomes with reviewToken, reviewer and note. Relevant changes reopen reviews; unrelated commits preserve them. Records belong in Git. Decision findings route to review_decision; this tool never approves decisions. Recorded identities are assertions, not authenticated approvals. For dependency advisories, action dismiss with reasonCode and note records a one-step dismissal without a token or reviewer. no-dependency-claims reopens only on document content changes; unrelated-manifest-change also tracks scoped manifests.",
|
|
9883
|
-
{ dir:
|
|
10077
|
+
{ dir: z25.string().describe("Absolute path to the project root"), ...advisoryReviewRequest.shape },
|
|
9884
10078
|
async ({ dir, ...request }) => ({ content: [{ type: "text", text: await masonReviewAdvisory(dir, request) }] })
|
|
9885
10079
|
);
|
|
9886
10080
|
server.tool(
|
|
9887
10081
|
"mason_complete_init",
|
|
9888
10082
|
"Record assistant instruction setup locally in ignored .mason/local/project.json, with feature settings in shared .mason/config.json. Other tools work without this marker. Repeated calls preserve the original setup time and existing settings; pass confluenceConfigured only to change that setting.",
|
|
9889
10083
|
{
|
|
9890
|
-
dir:
|
|
9891
|
-
confluenceConfigured:
|
|
10084
|
+
dir: z25.string().describe("Absolute path to the project root directory"),
|
|
10085
|
+
confluenceConfigured: z25.boolean().optional().describe("Set the Confluence setup status; omit to preserve the existing value")
|
|
9892
10086
|
},
|
|
9893
10087
|
async ({ dir, confluenceConfigured }) => {
|
|
9894
10088
|
const result = await masonCompleteInit(dir, { confluenceConfigured });
|
|
@@ -9899,11 +10093,11 @@ function createMcpServer() {
|
|
|
9899
10093
|
"mason_set_confluence",
|
|
9900
10094
|
"Configure Confluence credentials. Two-step flow: (1) call without `spaceKey` to validate the credentials and receive a list of available spaces \u2014 relay them to the user. (2) call again with the same `baseUrl`/`email`/`apiToken` plus the chosen `spaceKey` to persist. Credentials are stored in `~/.mason/config.json`. Warn the user that the API token will be visible in chat history before they paste it.",
|
|
9901
10095
|
{
|
|
9902
|
-
baseUrl:
|
|
9903
|
-
email:
|
|
9904
|
-
apiToken:
|
|
9905
|
-
spaceKey:
|
|
9906
|
-
parentPageId:
|
|
10096
|
+
baseUrl: z25.string().describe("Confluence base URL. Accepts `acme`, `acme.atlassian.net`, or `https://acme.atlassian.net` (normalized automatically)."),
|
|
10097
|
+
email: z25.string().describe("User's Atlassian account email"),
|
|
10098
|
+
apiToken: z25.string().describe("API token from id.atlassian.com/manage-profile/security/api-tokens"),
|
|
10099
|
+
spaceKey: z25.string().optional().describe("Confluence space key. Omit on the first call to list available spaces."),
|
|
10100
|
+
parentPageId: z25.string().optional().describe("Optional parent page ID under which Mason's index page is created")
|
|
9907
10101
|
},
|
|
9908
10102
|
async ({ baseUrl, email, apiToken, spaceKey, parentPageId }) => {
|
|
9909
10103
|
const result = await masonSetConfluence({
|
|
@@ -9920,7 +10114,7 @@ function createMcpServer() {
|
|
|
9920
10114
|
"full_analysis",
|
|
9921
10115
|
"One-shot orientation for a project WITHOUT a concept map (get_snapshot returned exists:false). Returns git history stats, project structure with file counts, curated code sample previews (~60 lines each), and test-to-source mapping. On a mapped project, prefer get_snapshot \u2014 it is cheaper and answers feature/architecture questions directly.",
|
|
9922
10116
|
{
|
|
9923
|
-
dir:
|
|
10117
|
+
dir: z25.string().describe("Absolute path to the project root directory")
|
|
9924
10118
|
},
|
|
9925
10119
|
async ({ dir }) => {
|
|
9926
10120
|
const result = await fullAnalysis(dir);
|
|
@@ -9933,7 +10127,7 @@ function createMcpServer() {
|
|
|
9933
10127
|
"analyze_project",
|
|
9934
10128
|
"Run git history analysis on a codebase. Returns commit convention patterns, stale directories, and frequently changed files. These are aggregate stats across hundreds of commits that would be expensive to compute manually.",
|
|
9935
10129
|
{
|
|
9936
|
-
dir:
|
|
10130
|
+
dir: z25.string().describe("Absolute path to the project root directory")
|
|
9937
10131
|
},
|
|
9938
10132
|
async ({ dir }) => {
|
|
9939
10133
|
const result = await analyzeProject(dir);
|
|
@@ -9946,8 +10140,8 @@ function createMcpServer() {
|
|
|
9946
10140
|
"get_code_samples",
|
|
9947
10141
|
"Get previews (first ~60 lines) of representative source files from the codebase. Includes entry points, config files, hot files (frequently changed), test examples, and one file per directory for breadth. Read files natively for full content.",
|
|
9948
10142
|
{
|
|
9949
|
-
dir:
|
|
9950
|
-
count:
|
|
10143
|
+
dir: z25.string().describe("Absolute path to the project root directory"),
|
|
10144
|
+
count: z25.number().optional().default(15).describe("Maximum number of files to sample (default: 15)")
|
|
9951
10145
|
},
|
|
9952
10146
|
async ({ dir, count: count4 }) => {
|
|
9953
10147
|
const result = await getCodeSamples(dir, count4);
|
|
@@ -9960,7 +10154,7 @@ function createMcpServer() {
|
|
|
9960
10154
|
"get_snapshot",
|
|
9961
10155
|
"Return the optional feature-to-file architecture map with drift and trust evidence. Map verification is rechecked against sampled source contents; stale or unknown verification requires a fresh review, and recordedVerdict preserves the historical verdict. If no map exists, returns exists:false plus project structure, Git signals, and test pairs. Decision capture, get_context, and get_impact still work. No initialization required.",
|
|
9962
10156
|
{
|
|
9963
|
-
dir:
|
|
10157
|
+
dir: z25.string().describe("Absolute path to the project root directory")
|
|
9964
10158
|
},
|
|
9965
10159
|
async ({ dir }) => {
|
|
9966
10160
|
const result = await getSnapshot(dir);
|
|
@@ -9973,9 +10167,9 @@ function createMcpServer() {
|
|
|
9973
10167
|
"get_context",
|
|
9974
10168
|
"Assemble task context: matching decisions with rationale, approval, owner, sources, last review, and freshness, plus related tests, file impact, and any available map entries. Map verification is rechecked against sampled source contents; stale or unknown verification requires a fresh review, and recordedVerdict preserves the historical verdict. Proposals are suggestions; legacy records are unreviewed; accepted decisions are constraints subject to freshness. No initialization or map required. Pass task and optional files. map.status and diagnostics preserve missing or invalid knowledge. Impact covers up to three unique files, expanding directory anchors.",
|
|
9975
10169
|
{
|
|
9976
|
-
dir:
|
|
9977
|
-
task:
|
|
9978
|
-
files:
|
|
10170
|
+
dir: z25.string().describe("Absolute path to the project root directory"),
|
|
10171
|
+
task: z25.string().describe("The task, bug, or change request in natural language \u2014 e.g. 'add rate limiting to the API client' or a ticket description"),
|
|
10172
|
+
files: z25.array(z25.string()).optional().describe("Optional file paths already known to be involved (e.g. from a diff or stack trace). Entries containing them are boosted above pure text matches.")
|
|
9979
10173
|
},
|
|
9980
10174
|
async ({ dir, task, files }) => {
|
|
9981
10175
|
const result = await getContext(dir, task, files);
|
|
@@ -9991,10 +10185,10 @@ function createMcpServer() {
|
|
|
9991
10185
|
"generate_snapshot_batch",
|
|
9992
10186
|
"Map step of the concept-map build. Returns one batch of source files (skeletons of every file in the batch plus a few deeper-read bodies for grounding), along with a system prompt instructing you to derive features and flows for ONLY this batch. Call repeatedly with the returned `nextOffset` until it is null, calling `save_partial_snapshot` between each call. Use product-natural feature names so partials merge cleanly in the reduce step.",
|
|
9993
10187
|
{
|
|
9994
|
-
dir:
|
|
9995
|
-
offset:
|
|
9996
|
-
batchSize:
|
|
9997
|
-
files:
|
|
10188
|
+
dir: z25.string().describe("Absolute path to the project root directory"),
|
|
10189
|
+
offset: z25.number().int().optional().describe("0-indexed file offset to start the batch at. Omit on the first call; pass the `nextOffset` from the previous response for subsequent calls."),
|
|
10190
|
+
batchSize: z25.number().int().optional().describe("Files per batch. Defaults to 50."),
|
|
10191
|
+
files: z25.array(z25.string()).optional().describe("Scope the batch walk to this explicit file list \u2014 e.g. the drift set from mason_check_drift (changedFiles + unmappedFiles). Pass the SAME list on every batch call of one refresh run. Triggers refresh mode: reduce_snapshot will merge the partials into the existing map instead of rebuilding it.")
|
|
9998
10192
|
},
|
|
9999
10193
|
async ({ dir, offset, batchSize, files }) => {
|
|
10000
10194
|
const result = await generateSnapshotBatch(dir, offset, batchSize, files);
|
|
@@ -10007,23 +10201,23 @@ function createMcpServer() {
|
|
|
10007
10201
|
"save_partial_snapshot",
|
|
10008
10202
|
"Persist the partial concept map you derived for one batch. Call this once per batch, with the `batchId` from the `generate_snapshot_batch` response. Partials accumulate in `.mason/partial-snapshots/` and are merged in the reduce step.",
|
|
10009
10203
|
{
|
|
10010
|
-
dir:
|
|
10011
|
-
batchId:
|
|
10012
|
-
offset:
|
|
10013
|
-
features:
|
|
10014
|
-
|
|
10015
|
-
description:
|
|
10016
|
-
files:
|
|
10017
|
-
tests:
|
|
10018
|
-
type:
|
|
10204
|
+
dir: z25.string().describe("Absolute path to the project root directory"),
|
|
10205
|
+
batchId: z25.string().describe("The `batchId` returned by `generate_snapshot_batch`."),
|
|
10206
|
+
offset: z25.number().int().describe("The `offset` returned by `generate_snapshot_batch`. Used to order partials in the reduce step."),
|
|
10207
|
+
features: z25.record(
|
|
10208
|
+
z25.object({
|
|
10209
|
+
description: z25.string(),
|
|
10210
|
+
files: z25.array(z25.string()),
|
|
10211
|
+
tests: z25.array(z25.string()).optional(),
|
|
10212
|
+
type: z25.enum(["capability", "infrastructure"]).optional().describe(
|
|
10019
10213
|
'"capability" (user-facing functionality) or "infrastructure" (internal plumbing with no end user \u2014 DI/service wiring, config, logging, adapters). Defaults to "capability".'
|
|
10020
10214
|
)
|
|
10021
10215
|
})
|
|
10022
10216
|
).describe("Partial features for this batch only \u2014 files outside the batch will be added by other partials."),
|
|
10023
|
-
flows:
|
|
10024
|
-
|
|
10025
|
-
description:
|
|
10026
|
-
chain:
|
|
10217
|
+
flows: z25.record(
|
|
10218
|
+
z25.object({
|
|
10219
|
+
description: z25.string(),
|
|
10220
|
+
chain: z25.array(z25.string())
|
|
10027
10221
|
})
|
|
10028
10222
|
).describe("Partial flows whose entire chain is in this batch. Cross-batch flows are reconstructed in reduce.")
|
|
10029
10223
|
},
|
|
@@ -10038,7 +10232,7 @@ function createMcpServer() {
|
|
|
10038
10232
|
"reduce_snapshot",
|
|
10039
10233
|
"Reduce step of the concept-map build. Returns every partial snapshot plus a system prompt asking you to merge them into one coherent project-wide map. Resolve platform variants into single product features, dedupe near-duplicates, and ensure no file is dropped. After producing the unified map, call `save_snapshot` to persist it (this also clears the partials).",
|
|
10040
10234
|
{
|
|
10041
|
-
dir:
|
|
10235
|
+
dir: z25.string().describe("Absolute path to the project root directory")
|
|
10042
10236
|
},
|
|
10043
10237
|
async ({ dir }) => {
|
|
10044
10238
|
const result = await reduceSnapshot(dir);
|
|
@@ -10051,25 +10245,25 @@ function createMcpServer() {
|
|
|
10051
10245
|
"save_snapshot",
|
|
10052
10246
|
"Save a concept-to-files map as a persistent project snapshot. Maps feature names and data flows to the files that implement them. Persists across conversations \u2014 future sessions can call get_snapshot to instantly find relevant files. No API key needed \u2014 you are the LLM generating the map.",
|
|
10053
10247
|
{
|
|
10054
|
-
dir:
|
|
10055
|
-
features:
|
|
10056
|
-
|
|
10057
|
-
description:
|
|
10058
|
-
files:
|
|
10059
|
-
tests:
|
|
10060
|
-
type:
|
|
10248
|
+
dir: z25.string().describe("Absolute path to the project root directory"),
|
|
10249
|
+
features: z25.record(
|
|
10250
|
+
z25.object({
|
|
10251
|
+
description: z25.string().describe("One-line description of the feature"),
|
|
10252
|
+
files: z25.array(z25.string()).describe("File paths that implement this feature"),
|
|
10253
|
+
tests: z25.array(z25.string()).optional().describe("Test file paths for this feature"),
|
|
10254
|
+
type: z25.enum(["capability", "infrastructure"]).optional().describe(
|
|
10061
10255
|
'Classification: "capability" for user-facing functionality, "infrastructure" for internal plumbing with no end user (DI/service wiring, config, logging, adapters). Capabilities are published to Confluence; infrastructure stays in the AI concept map only. Defaults to "capability".'
|
|
10062
10256
|
)
|
|
10063
10257
|
})
|
|
10064
10258
|
).describe("Map of feature names to their implementing files"),
|
|
10065
|
-
flows:
|
|
10066
|
-
|
|
10067
|
-
description:
|
|
10068
|
-
chain:
|
|
10259
|
+
flows: z25.record(
|
|
10260
|
+
z25.object({
|
|
10261
|
+
description: z25.string().describe("One-line description of the flow"),
|
|
10262
|
+
chain: z25.array(z25.string()).describe("Ordered list of file paths showing data/call flow")
|
|
10069
10263
|
})
|
|
10070
10264
|
).describe("Map of flow names to ordered file chains"),
|
|
10071
|
-
removeFeatures:
|
|
10072
|
-
removeFlows:
|
|
10265
|
+
removeFeatures: z25.array(z25.string()).optional().describe("Feature names to delete from the existing map \u2014 for features that were renamed or no longer exist. Applied before merging; only meaningful on incremental saves."),
|
|
10266
|
+
removeFlows: z25.array(z25.string()).optional().describe("Flow names to delete from the existing map. Applied before merging; only meaningful on incremental saves.")
|
|
10073
10267
|
},
|
|
10074
10268
|
async ({ dir, features, flows, removeFeatures, removeFlows }) => {
|
|
10075
10269
|
const result = await saveSnapshotData(
|
|
@@ -10086,19 +10280,19 @@ function createMcpServer() {
|
|
|
10086
10280
|
);
|
|
10087
10281
|
server.tool(
|
|
10088
10282
|
"save_decision",
|
|
10089
|
-
"Capture or revise a decision proposal
|
|
10283
|
+
"Capture or revise a decision proposal as soon as the lesson is supported by evidence, without waiting for implementation or merge. Keep unimplemented remedies tentative. Include rationale, anchors, optional owner, sources, and a known actor. Compare matching get_context records and pending proposals before saving. When new evidence changes the same lesson's assumptions, scope, or recommended action, pass its existing id, including for accepted records. Preserve supported rationale and sources and replace obsolete instructions. Create a new record for a genuinely distinct lesson; skip unchanged restatements. No setup or map required. Writes a local record and preserves content history. Changes create a pending proposal while the last accepted revision remains operative; unchanged content does not re-verify or refresh it. Use review_decision for authorized acceptance or reaffirmation. A proposal cannot supersede a record with an operative accepted revision; review its replacement and retire the original separately.",
|
|
10090
10284
|
{
|
|
10091
|
-
dir:
|
|
10285
|
+
dir: z25.string().describe("Absolute path to the project root directory"),
|
|
10092
10286
|
title: decisionTitleSchema.describe(`Short, specific headline (max ${TITLE_MAX_CHARS} characters). Generates a stable id on creation; revising the title keeps the existing id.`),
|
|
10093
10287
|
body: decisionBodySchema.describe(`The knowledge itself: what was tried/decided, why, and what to avoid. Must contain information NOT derivable by reading the code. Aim for ${BODY_RECOMMENDED_CHARS} characters or fewer; up to ${BODY_MAX_CHARS} is accepted with a warning above the target. Matching context and hooks include the full body. Preserve exceptions; use sources for supporting references.`),
|
|
10094
|
-
category:
|
|
10095
|
-
files:
|
|
10096
|
-
id:
|
|
10097
|
-
supersedes:
|
|
10288
|
+
category: z25.enum(["decision", "gotcha", "deprecation", "convention"]),
|
|
10289
|
+
files: z25.array(z25.string()).optional().describe("Repo-relative files or directory prefixes this applies to. Matching is shared by retrieval, hooks, review, and drift checking; changes flag the decision for re-verification."),
|
|
10290
|
+
id: z25.string().optional().describe("Pass the matching record's existing id when evidence changes that lesson's assumptions, scope, or recommended action, including for accepted records. Changed content becomes a proposal while the accepted version remains operative; unchanged content leaves review and freshness untouched."),
|
|
10291
|
+
supersedes: z25.string().optional().describe("Id of an unreviewed record or proposal with no accepted revision to replace. Operative accepted decisions require separate review and retirement."),
|
|
10098
10292
|
owner: attributionSchema.shape.owner.describe("Responsible person or team, when known. Null clears it. Required for acceptance."),
|
|
10099
10293
|
sources: attributionSchema.shape.sources.describe("Known PR, issue, incident, discussion, or document references. Omit to preserve; [] clears. At least one is required for acceptance."),
|
|
10100
10294
|
actor: attributionSchema.shape.actor.describe("Known person or agent recording this revision. Omit if unknown; do not infer from Git identity."),
|
|
10101
|
-
force:
|
|
10295
|
+
force: z25.boolean().optional().describe("Save even when a near-duplicate was detected")
|
|
10102
10296
|
},
|
|
10103
10297
|
async ({ dir, title, body, category, files, id, supersedes, force, owner, sources, actor }) => {
|
|
10104
10298
|
const result = await saveDecision(dir, {
|
|
@@ -10120,12 +10314,12 @@ function createMcpServer() {
|
|
|
10120
10314
|
"review_decision",
|
|
10121
10315
|
"Prepare a decision review: returns the full record and history, any operative accepted revision, provenance, changes and previews for both sets of anchors, and a reviewToken. Then record accept, reaffirm, or retire with that token, the authorized reviewer, and a reason. Acceptance replaces the operative revision; retirement withdraws the entire record including its proposal. Acceptance requires owner, source, readable Git HEAD, and committed anchor changes. Changed records or code invalidate the token. Identities and approvals are recorded assertions for normal PR review, not authenticated proof.",
|
|
10122
10316
|
{
|
|
10123
|
-
dir:
|
|
10124
|
-
id:
|
|
10125
|
-
action:
|
|
10126
|
-
reviewer:
|
|
10127
|
-
note:
|
|
10128
|
-
reviewToken:
|
|
10317
|
+
dir: z25.string().describe("Absolute path to the project root directory"),
|
|
10318
|
+
id: z25.string().regex(/^[a-zA-Z0-9_-]+$/).describe("Decision id from get_context or save_decision"),
|
|
10319
|
+
action: z25.enum(["prepare", "accept", "reaffirm", "retire"]).optional().default("prepare").describe("Prepare is read-only. Other actions record an explicitly authorized review."),
|
|
10320
|
+
reviewer: z25.string().trim().min(1).max(200).optional().describe("Identity of the actual reviewer; required for a verdict. Never invent one."),
|
|
10321
|
+
note: z25.string().trim().min(1).max(1500).optional().describe("Review rationale; required for a verdict. Cite evidence for the decision."),
|
|
10322
|
+
reviewToken: z25.string().regex(/^[a-f0-9]{64}$/).optional().describe("Token from the prepared review; rejects stale record or code revisions")
|
|
10129
10323
|
},
|
|
10130
10324
|
async ({ dir, ...input }) => {
|
|
10131
10325
|
const result = await reviewDecision2(dir, input);
|
|
@@ -10136,7 +10330,7 @@ function createMcpServer() {
|
|
|
10136
10330
|
"mason_check_drift",
|
|
10137
10331
|
"Check how far the concept map has drifted from HEAD. Deterministic (git + filesystem, no LLM). Returns which features/flows are stale and the changed files behind them, new source files not yet mapped, ghost files (mapped but deleted), renames, and a `recommendation`: `up-to-date` (nothing to do), `incremental` (update just the stale entries via save_snapshot), or `full-rebuild` (re-run the Map-Reduce build). Call this before trusting the map in a long session, or periodically to keep the map and any synced wikis fresh.",
|
|
10138
10332
|
{
|
|
10139
|
-
dir:
|
|
10333
|
+
dir: z25.string().describe("Absolute path to the project root directory")
|
|
10140
10334
|
},
|
|
10141
10335
|
async ({ dir }) => {
|
|
10142
10336
|
const result = await checkDrift(dir);
|
|
@@ -10149,8 +10343,8 @@ function createMcpServer() {
|
|
|
10149
10343
|
"verify_snapshot",
|
|
10150
10344
|
"Spot-check the concept map's CORRECTNESS (drift checks freshness; this checks entries were right to begin with). Returns a sample of entries \u2014 always the never-verified and least-recently-verified first \u2014 with skeletons of their claimed files, for you to judge whether the files actually implement what the entry claims. Report verdicts back via save_verification with each entry\u2019s kind and reviewToken. Tokens bind the entry and bounded source evidence; changed evidence requires a fresh review. Run periodically, or after an automated refresh wrote entries no human reviewed.",
|
|
10151
10345
|
{
|
|
10152
|
-
dir:
|
|
10153
|
-
sample:
|
|
10346
|
+
dir: z25.string().describe("Absolute path to the project root directory"),
|
|
10347
|
+
sample: z25.number().int().optional().describe("Entries to sample (default 5)")
|
|
10154
10348
|
},
|
|
10155
10349
|
async ({ dir, sample }) => {
|
|
10156
10350
|
const result = await verifySnapshot(dir, sample);
|
|
@@ -10161,13 +10355,13 @@ function createMcpServer() {
|
|
|
10161
10355
|
"save_verification",
|
|
10162
10356
|
"Record verify_snapshot verdicts using each entry\u2019s kind and reviewToken. Missing tokens request a fresh review; changed or deleted entries return conflicts without being stamped. Entries judged ok are stamped verifiedAt; failures are flagged verificationFailed with your note and surface in get_context, get_snapshot, and mason_check_drift until corrected. Verdict notes are required for failures.",
|
|
10163
10357
|
{
|
|
10164
|
-
dir:
|
|
10165
|
-
verdicts:
|
|
10166
|
-
|
|
10167
|
-
kind:
|
|
10168
|
-
reviewToken:
|
|
10169
|
-
ok:
|
|
10170
|
-
note:
|
|
10358
|
+
dir: z25.string().describe("Absolute path to the project root directory"),
|
|
10359
|
+
verdicts: z25.record(
|
|
10360
|
+
z25.object({
|
|
10361
|
+
kind: z25.enum(["feature", "flow"]).optional().describe("Entry kind returned by verify_snapshot; required to record a verdict"),
|
|
10362
|
+
reviewToken: z25.string().optional().describe("Copy the reviewToken from verify_snapshot after inspecting its evidence; required to record a verdict"),
|
|
10363
|
+
ok: z25.boolean(),
|
|
10364
|
+
note: z25.string().optional().describe("One line on what's wrong \u2014 required when ok is false")
|
|
10171
10365
|
})
|
|
10172
10366
|
).describe("Entry name \u2192 verdict, exactly as returned by verify_snapshot")
|
|
10173
10367
|
},
|
|
@@ -10180,8 +10374,8 @@ function createMcpServer() {
|
|
|
10180
10374
|
"get_impact",
|
|
10181
10375
|
"Trace historical co-change partners, related tests, and references with evidence: resolved imports, explicit paths, or uncertain name candidates. Candidates are not proven dependencies. Deterministic and read-only; no initialization or concept map required.",
|
|
10182
10376
|
{
|
|
10183
|
-
dir:
|
|
10184
|
-
files:
|
|
10377
|
+
dir: z25.string().describe("Absolute path to the project root directory"),
|
|
10378
|
+
files: z25.array(z25.string()).describe("File paths or names to analyze (e.g., ['WeatherRepository.kt'] or ['src/services/auth.ts'])")
|
|
10185
10379
|
},
|
|
10186
10380
|
async ({ dir, files }) => {
|
|
10187
10381
|
const result = await getImpact(dir, files);
|
|
@@ -10194,12 +10388,12 @@ function createMcpServer() {
|
|
|
10194
10388
|
"export_to_confluence",
|
|
10195
10389
|
"Sync the project's concept map to Confluence as product-readable wiki pages: an index page, one page per feature (PM-language descriptions, no file paths), and a changelog page. Mason replaces managed page bodies; manual edits to those bodies are overwritten. Requires `mason_set_confluence` to have been called first.",
|
|
10196
10390
|
{
|
|
10197
|
-
dir:
|
|
10198
|
-
spaceKey:
|
|
10199
|
-
parentPageId:
|
|
10200
|
-
indexPageTitle:
|
|
10201
|
-
changelogPageTitle:
|
|
10202
|
-
featurePagePrefix:
|
|
10391
|
+
dir: z25.string().describe("Absolute path to the project root directory"),
|
|
10392
|
+
spaceKey: z25.string().optional().describe("Override the configured space key"),
|
|
10393
|
+
parentPageId: z25.string().optional().describe("Override the configured parent page ID"),
|
|
10394
|
+
indexPageTitle: z25.string().optional().describe("Title of the index page (default: 'Mason \u2014 System Map')"),
|
|
10395
|
+
changelogPageTitle: z25.string().optional().describe("Title of the changelog page (default: 'Mason \u2014 Changelog')"),
|
|
10396
|
+
featurePagePrefix: z25.string().optional().describe("Prefix for each feature page title (default: 'Feature: ')")
|
|
10203
10397
|
},
|
|
10204
10398
|
async ({ dir, spaceKey, parentPageId, indexPageTitle, changelogPageTitle, featurePagePrefix }) => {
|
|
10205
10399
|
const result = await exportToConfluenceTool(dir, {
|
|
@@ -10228,7 +10422,7 @@ import fs33 from "fs/promises";
|
|
|
10228
10422
|
import path42 from "path";
|
|
10229
10423
|
import { spawn as spawn3 } from "child_process";
|
|
10230
10424
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
10231
|
-
import { z as
|
|
10425
|
+
import { z as z31 } from "zod";
|
|
10232
10426
|
|
|
10233
10427
|
// src/distribution/state.ts
|
|
10234
10428
|
init_storage();
|
|
@@ -10236,7 +10430,7 @@ import os5 from "os";
|
|
|
10236
10430
|
import path38 from "path";
|
|
10237
10431
|
import { fileURLToPath } from "url";
|
|
10238
10432
|
import fs28 from "fs/promises";
|
|
10239
|
-
import { z as
|
|
10433
|
+
import { z as z27 } from "zod";
|
|
10240
10434
|
|
|
10241
10435
|
// src/distribution/path.ts
|
|
10242
10436
|
import fs27 from "fs/promises";
|
|
@@ -10245,11 +10439,11 @@ import path37 from "path";
|
|
|
10245
10439
|
import { execFile as execFile12 } from "child_process";
|
|
10246
10440
|
import { promisify as promisify12 } from "util";
|
|
10247
10441
|
import { createHash as createHash7, randomUUID as randomUUID7 } from "crypto";
|
|
10248
|
-
import { z as
|
|
10442
|
+
import { z as z26 } from "zod";
|
|
10249
10443
|
var execute2 = promisify12(execFile12);
|
|
10250
|
-
var pathChangeSchema =
|
|
10251
|
-
|
|
10252
|
-
|
|
10444
|
+
var pathChangeSchema = z26.discriminatedUnion("kind", [
|
|
10445
|
+
z26.object({ kind: z26.literal("profile"), file: z26.string(), block: z26.string(), created: z26.boolean() }),
|
|
10446
|
+
z26.object({ kind: z26.literal("windows"), entry: z26.string(), created: z26.boolean() })
|
|
10253
10447
|
]);
|
|
10254
10448
|
var quote = (s) => "'" + s.replace(/'/g, "'\\''") + "'";
|
|
10255
10449
|
async function configurePath(bin, previous, save, options = {}) {
|
|
@@ -10369,26 +10563,26 @@ try {
|
|
|
10369
10563
|
}
|
|
10370
10564
|
|
|
10371
10565
|
// src/distribution/state.ts
|
|
10372
|
-
var releaseVersion =
|
|
10373
|
-
var bundleId =
|
|
10374
|
-
var updatePolicySchema =
|
|
10375
|
-
enabled:
|
|
10376
|
-
revision:
|
|
10566
|
+
var releaseVersion = z27.string().regex(/^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/);
|
|
10567
|
+
var bundleId = z27.string().regex(/^[a-f0-9]{24}$/);
|
|
10568
|
+
var updatePolicySchema = z27.object({
|
|
10569
|
+
enabled: z27.boolean(),
|
|
10570
|
+
revision: z27.string(),
|
|
10377
10571
|
pinnedVersion: releaseVersion.optional(),
|
|
10378
|
-
mirror:
|
|
10572
|
+
mirror: z27.string().optional()
|
|
10379
10573
|
});
|
|
10380
|
-
var recordSchema3 =
|
|
10381
|
-
format:
|
|
10382
|
-
home:
|
|
10383
|
-
bin:
|
|
10574
|
+
var recordSchema3 = z27.object({
|
|
10575
|
+
format: z27.literal(1),
|
|
10576
|
+
home: z27.string(),
|
|
10577
|
+
bin: z27.string(),
|
|
10384
10578
|
current: bundleId,
|
|
10385
10579
|
version: releaseVersion,
|
|
10386
|
-
launchers:
|
|
10387
|
-
previousLaunchers:
|
|
10388
|
-
pathChanges:
|
|
10580
|
+
launchers: z27.record(z27.string()),
|
|
10581
|
+
previousLaunchers: z27.record(z27.string()).optional(),
|
|
10582
|
+
pathChanges: z27.array(pathChangeSchema).optional(),
|
|
10389
10583
|
updates: updatePolicySchema.optional(),
|
|
10390
|
-
previous:
|
|
10391
|
-
pending:
|
|
10584
|
+
previous: z27.object({ id: bundleId, version: releaseVersion }).optional(),
|
|
10585
|
+
pending: z27.object({ id: bundleId, version: releaseVersion, policyRevision: z27.string() }).optional()
|
|
10392
10586
|
});
|
|
10393
10587
|
async function readInstallation(home) {
|
|
10394
10588
|
const raw = await readStoreJson(home, "install.json");
|
|
@@ -10429,15 +10623,15 @@ init_storage();
|
|
|
10429
10623
|
import fs29 from "fs/promises";
|
|
10430
10624
|
import path39 from "path";
|
|
10431
10625
|
import { createHash as createHash8 } from "crypto";
|
|
10432
|
-
import { z as
|
|
10626
|
+
import { z as z28 } from "zod";
|
|
10433
10627
|
var targets = ["darwin-arm64", "darwin-x64", "linux-arm64", "linux-x64", "win32-arm64", "win32-x64"];
|
|
10434
|
-
var digest2 =
|
|
10435
|
-
var bundleSchema =
|
|
10436
|
-
format:
|
|
10437
|
-
version:
|
|
10438
|
-
target:
|
|
10439
|
-
nodeVersion:
|
|
10440
|
-
files:
|
|
10628
|
+
var digest2 = z28.string().regex(/^[a-f0-9]{64}$/);
|
|
10629
|
+
var bundleSchema = z28.object({
|
|
10630
|
+
format: z28.literal(1),
|
|
10631
|
+
version: z28.string().regex(/^\d+\.\d+\.\d+(?:-[A-Za-z0-9.-]+)?$/),
|
|
10632
|
+
target: z28.enum(targets),
|
|
10633
|
+
nodeVersion: z28.string(),
|
|
10634
|
+
files: z28.record(digest2)
|
|
10441
10635
|
}).strict();
|
|
10442
10636
|
var sha256 = (bytes) => createHash8("sha256").update(bytes).digest("hex");
|
|
10443
10637
|
async function readBundle(root) {
|
|
@@ -10473,8 +10667,13 @@ import { unlinkSync } from "fs";
|
|
|
10473
10667
|
import os6 from "os";
|
|
10474
10668
|
import path40 from "path";
|
|
10475
10669
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
10476
|
-
import { z as
|
|
10477
|
-
|
|
10670
|
+
import { z as z29 } from "zod";
|
|
10671
|
+
|
|
10672
|
+
// src/distribution/trust.ts
|
|
10673
|
+
import tls from "tls";
|
|
10674
|
+
|
|
10675
|
+
// src/distribution/runtime.ts
|
|
10676
|
+
var leaseSchema = z29.object({ pid: z29.number().int().positive(), host: z29.string(), bundle: z29.string().regex(/^[a-f0-9]{24}$/) });
|
|
10478
10677
|
|
|
10479
10678
|
// src/distribution/install.ts
|
|
10480
10679
|
import fs32 from "fs/promises";
|
|
@@ -10491,8 +10690,8 @@ init_storage();
|
|
|
10491
10690
|
import fs31 from "fs/promises";
|
|
10492
10691
|
import os7 from "os";
|
|
10493
10692
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
10494
|
-
import { z as
|
|
10495
|
-
var leaseSchema2 =
|
|
10693
|
+
import { z as z30 } from "zod";
|
|
10694
|
+
var leaseSchema2 = z30.object({ pid: z30.number().int().positive(), host: z30.string() });
|
|
10496
10695
|
async function hasRunningMcp(home) {
|
|
10497
10696
|
const directory = await storePath(home, "sessions");
|
|
10498
10697
|
const files = await fs31.readdir(directory).catch((error) => {
|
|
@@ -10722,14 +10921,14 @@ async function prepareStandaloneMcp(home) {
|
|
|
10722
10921
|
// src/distribution/updates.ts
|
|
10723
10922
|
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
10724
10923
|
var RELEASE_AGE_MS = 24 * 60 * 60 * 1e3;
|
|
10725
|
-
var releaseListSchema =
|
|
10726
|
-
var updateManifestSchema =
|
|
10727
|
-
format:
|
|
10728
|
-
version:
|
|
10729
|
-
publishedAt:
|
|
10730
|
-
assets:
|
|
10924
|
+
var releaseListSchema = z31.array(z31.object({ tag_name: z31.string(), draft: z31.boolean(), prerelease: z31.boolean(), published_at: z31.string().nullable() }));
|
|
10925
|
+
var updateManifestSchema = z31.object({
|
|
10926
|
+
format: z31.literal(1),
|
|
10927
|
+
version: z31.string().regex(/^\d+\.\d+\.\d+$/),
|
|
10928
|
+
publishedAt: z31.string().datetime(),
|
|
10929
|
+
assets: z31.record(z31.string().regex(/^[a-f0-9]{64}$/))
|
|
10731
10930
|
}).strict();
|
|
10732
|
-
var statusSchema2 =
|
|
10931
|
+
var statusSchema2 = z31.object({ lastAttempt: z31.number(), availableVersion: z31.string().optional(), error: z31.string().optional() });
|
|
10733
10932
|
async function scheduleAutomaticUpdate() {
|
|
10734
10933
|
try {
|
|
10735
10934
|
const { home, record } = await currentInstallation();
|