mason-context 0.16.1 → 0.16.3

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 CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.16.3 — 2026-09-09
4
+
5
+ - Coordinate overlapping hooks without holding the shared state lock during audit analysis. Reuse analysis for identical inputs, let changed inputs proceed independently, and revalidate before publishing results so older work cannot overwrite newer evidence.
6
+ - Retain independent execution receipts during parallel calls. Report repeated, durably recorded failures once per session until recovery; keep failures without receipts visible and preserve pre-edit evidence for shell and unknown tools.
7
+ - Accept decision bodies up to 2,500 characters, with a warning above the recommended 1,500. Preserve the full body, report precise validation limits, and shorten generated IDs at word boundaries where possible.
8
+ - Cover slow checks, overlapping CLI processes, failure recovery, and changing inputs with concurrency regressions. Simplify README badges for consistent rendering.
9
+
10
+ Run `mason upgrade` for standalone installations, then restart running assistants. Existing PATH-based project integrations do not need setup again for this release.
11
+
12
+ ## 0.16.2 — 2026-09-09
13
+
14
+ - Guard generated hooks when Mason is absent, and keep a checkout without local host setup quiet. Preserve active failure diagnostics and strict MCP startup; setup/status/teardown recognize the generated guard variants without project wrapper scripts.
15
+ - Observe known read-only tools without rescanning audit inputs or advancing verification. Keep before/after capture for shell and unknown tools. Add a reproducible full-CLI hook benchmark and publish its measured scope and limits.
16
+ - Document hook inputs, retained data, local versus optional networked features, MCP installation, and company mirrors. Require an explicit version with a custom release mirror to avoid public version discovery.
17
+ - Exercise core CLI/MCP and hook paths with denied network operations, raw-input retention markers, inactive/invalid setup, and changed evidence before potentially mutating tools. On macOS, apply OS network denial to the tested process tree too.
18
+
3
19
  ## 0.16.1 — 2026-09-08
4
20
 
5
21
  - Resolve references using literal import paths and declared Kotlin/Java package symbols. Separate explicit path mentions and uncertain name candidates; suppress config/document-name collisions and keep weak candidates out of compact task context with an omission count.
package/README.md CHANGED
@@ -1,16 +1,22 @@
1
+ <div align="center">
2
+
1
3
  # Mason
2
4
 
3
- [![npm version](https://img.shields.io/npm/v/mason-context)](https://www.npmjs.com/package/mason-context)
4
- [![CI](https://img.shields.io/github/actions/workflow/status/adrianczuczka/mason/ci.yml?branch=main)](https://github.com/adrianczuczka/mason/actions/workflows/ci.yml)
5
- [![npm downloads](https://img.shields.io/npm/dm/mason-context)](https://www.npmjs.com/package/mason-context)
6
- [![license](https://img.shields.io/github/license/adrianczuczka/mason)](https://github.com/adrianczuczka/mason/blob/main/LICENSE)
7
- [![issues](https://img.shields.io/github/issues/adrianczuczka/mason)](https://github.com/adrianczuczka/mason/issues)
5
+ ### Your agents are creating tech debt. Mason helps you prevent it.
6
+
7
+ **Remember why decisions were made · Catch outdated guidance · Find what else needs updating**
8
8
 
9
- ## Your AI agent is creating tech debt.
9
+ [![npm version](https://img.shields.io/npm/v/mason-context?style=flat-square&labelColor=334155&color=2563eb)](https://www.npmjs.com/package/mason-context)
10
+ [![CI](https://img.shields.io/github/actions/workflow/status/adrianczuczka/mason/ci.yml?branch=main&style=flat-square&labelColor=334155&label=CI)](https://github.com/adrianczuczka/mason/actions/workflows/ci.yml)
11
+ [![Monthly downloads](https://img.shields.io/npm/dm/mason-context?style=flat-square&labelColor=334155&color=2563eb)](https://www.npmjs.com/package/mason-context)
12
+ [![License](https://img.shields.io/github/license/adrianczuczka/mason?style=flat-square&labelColor=334155&color=64748b)](https://github.com/adrianczuczka/mason/blob/main/LICENSE)
10
13
 
11
- **Mason helps your coding agent catch what a patch leaves behind:** stale instructions, missed companion updates, and engineering decisions that need another look.
14
+ [![Works with Codex](https://img.shields.io/badge/Codex-supported-64748b?style=flat-square&labelColor=334155)](https://github.com/adrianczuczka/mason/blob/main/docs/setup.md)
15
+ [![Works with Claude Code](https://img.shields.io/badge/Claude%20Code-supported-64748b?style=flat-square&labelColor=334155)](https://github.com/adrianczuczka/mason/blob/main/docs/setup.md)
16
+ [![MCP compatible](https://img.shields.io/badge/MCP-compatible-64748b?style=flat-square&labelColor=334155)](https://github.com/adrianczuczka/mason/blob/main/docs/setup.md#other-clients)
17
+ [![Supported platforms](https://img.shields.io/badge/platforms-macOS%20%7C%20Linux%20%7C%20Windows-64748b?style=flat-square&labelColor=334155)](https://github.com/adrianczuczka/mason/blob/main/docs/distribution.md)
12
18
 
13
- Works through MCP, with automatic documentation checks for **Codex** and **Claude Code**. No concept map required.
19
+ </div>
14
20
 
15
21
  ## Get started
16
22
 
@@ -74,6 +80,7 @@ Earlier read-only decision-retrieval evaluations scored **9.0/10 with Mason vs 7
74
80
  ## Documentation
75
81
 
76
82
  - [Setup, hooks, and upgrades](docs/setup.md)
83
+ - [Data and network behavior](docs/data-and-network.md) · [Hook performance](docs/hook-performance.md)
77
84
  - [Audits, repair verification, and CI evidence](docs/checks.md)
78
85
  - [Decisions, tools, and optional architecture maps](docs/reference.md)
79
86
  - [Roadmap](ROADMAP.md) · [Changelog](CHANGELOG.md) · [MIT license](LICENSE)
@@ -1337,6 +1337,7 @@ import path14 from "path";
1337
1337
  import fs8 from "fs/promises";
1338
1338
  import path13 from "path";
1339
1339
  import { createHash } from "crypto";
1340
+ import { z as z3 } from "zod";
1340
1341
 
1341
1342
  // src/context/lexical.ts
1342
1343
  import path12 from "path";
@@ -1479,6 +1480,18 @@ function decisionProvenance(record, freshness = "unknown") {
1479
1480
  }
1480
1481
 
1481
1482
  // src/decisions/decisions.ts
1483
+ var TITLE_MAX_CHARS = 80;
1484
+ var BODY_RECOMMENDED_CHARS = 1500;
1485
+ var BODY_MAX_CHARS = 2500;
1486
+ var boundedText = (field, max, hint) => z3.string({
1487
+ errorMap: (issue, ctx) => ({ message: issue.code === "too_big" ? `${field} has ${ctx.data.length} characters; maximum is ${max} (${ctx.data.length - max} over). ${hint}` : ctx.defaultError })
1488
+ }).trim().min(1, `${field} must be non-empty`).max(max);
1489
+ var decisionTitleSchema = boundedText("title", TITLE_MAX_CHARS, "Tighten it to a specific headline.");
1490
+ var decisionBodySchema = boundedText(
1491
+ "body",
1492
+ BODY_MAX_CHARS,
1493
+ `Aim for ${BODY_RECOMMENDED_CHARS} characters or fewer. Preserve the rule, reason, and exceptions; put supporting references in sources.`
1494
+ );
1482
1495
  async function loadDecisionStore(rootDir) {
1483
1496
  const records = [];
1484
1497
  const diagnostics = [];
@@ -1654,96 +1667,103 @@ async function computeAudit(rootDir, options = {}) {
1654
1667
  import fs10 from "fs/promises";
1655
1668
  import path16 from "path";
1656
1669
  import { createHash as createHash2, randomUUID as randomUUID2 } from "crypto";
1657
- import { z as z3 } from "zod";
1658
- var checkSchema = z3.enum(["deleted-reference", "new-module", "stale-count", "dead-command", "deps-changed", "decision-anchor-drift"]);
1659
- var commitSchema = z3.object({ hash: z3.string().regex(/^[a-f0-9]{40,64}$/), date: z3.string(), subject: z3.string() });
1660
- var anchorSchema = z3.object({ doc: z3.string(), line: z3.number().int().positive().nullable(), excerpt: z3.string().nullable() });
1661
- var count = z3.number().int().nonnegative();
1662
- var evidenceSchema = z3.discriminatedUnion("kind", [
1663
- z3.object({
1664
- kind: z3.literal("missing-path"),
1665
- claimed: z3.string(),
1666
- renamedTo: z3.string().nullable(),
1670
+ import { z as z4 } from "zod";
1671
+ var checkSchema = z4.enum(["deleted-reference", "new-module", "stale-count", "dead-command", "deps-changed", "decision-anchor-drift"]);
1672
+ var commitSchema = z4.object({ hash: z4.string().regex(/^[a-f0-9]{40,64}$/), date: z4.string(), subject: z4.string() });
1673
+ var anchorSchema = z4.object({ doc: z4.string(), line: z4.number().int().positive().nullable(), excerpt: z4.string().nullable() });
1674
+ var count = z4.number().int().nonnegative();
1675
+ var evidenceSchema = z4.discriminatedUnion("kind", [
1676
+ z4.object({
1677
+ kind: z4.literal("missing-path"),
1678
+ claimed: z4.string(),
1679
+ renamedTo: z4.string().nullable(),
1667
1680
  deletedInCommit: commitSchema.nullable(),
1668
- everTracked: z3.boolean(),
1669
- parentDirExists: z3.boolean()
1681
+ everTracked: z4.boolean(),
1682
+ parentDirExists: z4.boolean()
1670
1683
  }),
1671
- z3.object({
1672
- kind: z3.literal("unmentioned-dir"),
1673
- dir: z3.string(),
1684
+ z4.object({
1685
+ kind: z4.literal("unmentioned-dir"),
1686
+ dir: z4.string(),
1674
1687
  sourceFileCount: count,
1675
1688
  firstCommit: commitSchema.nullable(),
1676
- checkedDocs: z3.array(z3.string())
1689
+ checkedDocs: z4.array(z4.string())
1677
1690
  }),
1678
- z3.object({
1679
- kind: z3.literal("count-mismatch"),
1691
+ z4.object({
1692
+ kind: z4.literal("count-mismatch"),
1680
1693
  claimed: count,
1681
1694
  actual: count,
1682
- unit: z3.string(),
1683
- countedFrom: z3.string(),
1684
- members: z3.array(z3.string())
1695
+ unit: z4.string(),
1696
+ countedFrom: z4.string(),
1697
+ members: z4.array(z4.string())
1685
1698
  }),
1686
- z3.object({
1687
- kind: z3.literal("missing-script"),
1688
- scriptName: z3.string(),
1689
- invocation: z3.string(),
1690
- manifestsChecked: z3.array(z3.string()),
1691
- availableScripts: z3.array(z3.string())
1699
+ z4.object({
1700
+ kind: z4.literal("missing-script"),
1701
+ scriptName: z4.string(),
1702
+ invocation: z4.string(),
1703
+ manifestsChecked: z4.array(z4.string()),
1704
+ availableScripts: z4.array(z4.string())
1692
1705
  }),
1693
- z3.object({
1694
- kind: z3.literal("doc-behind-manifests"),
1706
+ z4.object({
1707
+ kind: z4.literal("doc-behind-manifests"),
1695
1708
  docLastCommit: commitSchema,
1696
- manifestCommits: z3.array(commitSchema.extend({ files: z3.array(z3.string()) })),
1709
+ manifestCommits: z4.array(commitSchema.extend({ files: z4.array(z4.string()) })),
1697
1710
  totalCommits: count
1698
1711
  }),
1699
- z3.object({
1700
- kind: z3.literal("decision-anchor"),
1701
- decisionId: z3.string(),
1702
- title: z3.string(),
1703
- changedFiles: z3.array(z3.string()),
1704
- refreshedHash: z3.string(),
1705
- provenance: z3.object({}).passthrough().optional()
1712
+ z4.object({
1713
+ kind: z4.literal("decision-anchor"),
1714
+ decisionId: z4.string(),
1715
+ title: z4.string(),
1716
+ changedFiles: z4.array(z4.string()),
1717
+ refreshedHash: z4.string(),
1718
+ provenance: z4.object({}).passthrough().optional()
1706
1719
  })
1707
1720
  ]);
1708
- var findingSchema = z3.object({ message: z3.string(), anchor: anchorSchema, evidence: evidenceSchema });
1721
+ var findingSchema = z4.object({ message: z4.string(), anchor: anchorSchema, evidence: evidenceSchema });
1709
1722
  var issueSchema = findingSchema.extend({
1710
- type: z3.enum(["deleted-reference", "new-module", "stale-count", "dead-command"]),
1711
- confidence: z3.enum(["certain", "likely"])
1723
+ type: z4.enum(["deleted-reference", "new-module", "stale-count", "dead-command"]),
1724
+ confidence: z4.enum(["certain", "likely"])
1712
1725
  });
1713
- var advisorySchema = findingSchema.extend({ type: z3.enum(["deps-changed", "decision-anchor-drift"]) });
1714
- var checkResultSchema = z3.object({
1715
- issues: z3.array(issueSchema),
1716
- advisories: z3.array(advisorySchema),
1717
- suppressedAdvisories: z3.array(advisorySchema).optional(),
1718
- skipped: z3.array(z3.object({ check: z3.string(), reason: z3.string(), doc: z3.string().optional() }))
1726
+ var advisorySchema = findingSchema.extend({ type: z4.enum(["deps-changed", "decision-anchor-drift"]) });
1727
+ var checkResultSchema = z4.object({
1728
+ issues: z4.array(issueSchema),
1729
+ advisories: z4.array(advisorySchema),
1730
+ suppressedAdvisories: z4.array(advisorySchema).optional(),
1731
+ skipped: z4.array(z4.object({ check: z4.string(), reason: z4.string(), doc: z4.string().optional() }))
1719
1732
  });
1720
- var reportSchema = z3.object({
1721
- version: z3.literal(1),
1722
- root: z3.string(),
1723
- gitAvailable: z3.literal(true),
1733
+ var reportSchema = z4.object({
1734
+ version: z4.literal(1),
1735
+ root: z4.string(),
1736
+ gitAvailable: z4.literal(true),
1724
1737
  headHash: commitSchema.shape.hash,
1725
- checksRun: z3.array(checkSchema).nonempty(),
1726
- docs: z3.array(z3.object({
1727
- path: z3.enum(DOC_CANDIDATES),
1738
+ checksRun: z4.array(checkSchema).nonempty(),
1739
+ docs: z4.array(z4.object({
1740
+ path: z4.enum(DOC_CANDIDATES),
1728
1741
  lastCommit: commitSchema.nullable(),
1729
- dirty: z3.boolean(),
1742
+ dirty: z4.boolean(),
1730
1743
  lineCount: count
1731
1744
  })).nonempty(),
1732
- decisionsChecked: z3.boolean(),
1733
- clean: z3.boolean(),
1734
- issues: z3.array(issueSchema),
1735
- advisories: z3.array(advisorySchema),
1736
- suppressedAdvisories: z3.array(advisorySchema).optional(),
1737
- skippedChecks: z3.array(z3.object({ check: z3.string(), reason: z3.string(), doc: z3.string().optional() }))
1745
+ decisionsChecked: z4.boolean(),
1746
+ clean: z4.boolean(),
1747
+ issues: z4.array(issueSchema),
1748
+ advisories: z4.array(advisorySchema),
1749
+ suppressedAdvisories: z4.array(advisorySchema).optional(),
1750
+ skippedChecks: z4.array(z4.object({ check: z4.string(), reason: z4.string(), doc: z4.string().optional() }))
1738
1751
  });
1739
- var baselineSchema = z3.object({
1740
- kind: z3.literal("mason-audit-repair"),
1741
- version: z3.literal(1),
1742
- createdAt: z3.string().datetime(),
1752
+ var baselineSchema = z4.object({
1753
+ kind: z4.literal("mason-audit-repair"),
1754
+ version: z4.literal(1),
1755
+ createdAt: z4.string().datetime(),
1743
1756
  report: reportSchema,
1744
- digest: z3.string().regex(/^[a-f0-9]{64}$/)
1757
+ digest: z4.string().regex(/^[a-f0-9]{64}$/)
1745
1758
  });
1746
1759
  var digest = (value) => createHash2("sha256").update(JSON.stringify(value)).digest("hex");
1760
+ var repairFindingSchema = z4.object({
1761
+ id: z4.string(),
1762
+ original: z4.union([issueSchema, advisorySchema]),
1763
+ status: z4.enum(["resolved", "unresolved", "review-required", "unverified"]),
1764
+ reason: z4.string(),
1765
+ current: z4.union([issueSchema, advisorySchema]).optional()
1766
+ });
1747
1767
  function findingId(finding) {
1748
1768
  const e = finding.evidence;
1749
1769
  let key;
@@ -1797,7 +1817,7 @@ async function stableAudit(root, checks, options = {}) {
1797
1817
  }
1798
1818
  async function prepareRepair(rootDir, checks = ALL_CHECKS, options = {}) {
1799
1819
  const root = await fs10.realpath(rootDir);
1800
- const selected = z3.array(checkSchema).nonempty().parse(checks);
1820
+ const selected = z4.array(checkSchema).nonempty().parse(checks);
1801
1821
  const report = await stableAudit(root, selected, options);
1802
1822
  if (!report) throw new Error("No context files found to prepare a repair.");
1803
1823
  if (!report.gitAvailable) throw new Error("Readable Git history is required to prepare a repair.");