agent-merge-broker 0.14.2 → 0.15.1

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.
Files changed (147) hide show
  1. package/README.md +57 -30
  2. package/dist/bootstrap.d.ts +0 -1
  3. package/dist/bootstrap.js +0 -1
  4. package/dist/broker.d.ts +0 -1
  5. package/dist/broker.js +12 -1
  6. package/dist/candidate-lifecycle.d.ts +0 -1
  7. package/dist/candidate-lifecycle.js +0 -1
  8. package/dist/cli.d.ts +0 -1
  9. package/dist/cli.js +47 -1
  10. package/dist/config.d.ts +0 -1
  11. package/dist/config.js +0 -1
  12. package/dist/core.d.ts +19 -0
  13. package/dist/core.js +18 -0
  14. package/dist/errors.d.ts +0 -1
  15. package/dist/errors.js +0 -1
  16. package/dist/gate-authority.d.ts +0 -1
  17. package/dist/gate-authority.js +0 -1
  18. package/dist/git-locators.d.ts +0 -1
  19. package/dist/git-locators.js +0 -1
  20. package/dist/git.d.ts +0 -1
  21. package/dist/git.js +30 -7
  22. package/dist/hooks.d.ts +0 -1
  23. package/dist/hooks.js +0 -1
  24. package/dist/index.d.ts +1 -19
  25. package/dist/index.js +2 -18
  26. package/dist/mcp-cli.d.ts +0 -1
  27. package/dist/mcp-cli.js +0 -1
  28. package/dist/mcp.d.ts +5 -1
  29. package/dist/mcp.js +29 -8
  30. package/dist/patterns.d.ts +0 -1
  31. package/dist/patterns.js +0 -1
  32. package/dist/process.d.ts +8 -1
  33. package/dist/process.js +46 -9
  34. package/dist/provenance.d.ts +0 -1
  35. package/dist/provenance.js +0 -1
  36. package/dist/publisher.d.ts +0 -1
  37. package/dist/publisher.js +0 -1
  38. package/dist/scheduler.d.ts +0 -1
  39. package/dist/scheduler.js +0 -1
  40. package/dist/schema-identity.d.ts +0 -1
  41. package/dist/schema-identity.js +0 -1
  42. package/dist/serve-log.d.ts +0 -1
  43. package/dist/serve-log.js +0 -1
  44. package/dist/service.d.ts +0 -1
  45. package/dist/service.js +0 -1
  46. package/dist/state-codec.d.ts +0 -1
  47. package/dist/state-codec.js +0 -1
  48. package/dist/status.d.ts +0 -1
  49. package/dist/status.js +0 -1
  50. package/dist/storage.d.ts +54 -0
  51. package/dist/storage.js +310 -0
  52. package/dist/store.d.ts +7 -1
  53. package/dist/store.js +190 -46
  54. package/dist/submission-attestation.d.ts +0 -1
  55. package/dist/submission-attestation.js +0 -1
  56. package/dist/submission-retention.d.ts +0 -1
  57. package/dist/submission-retention.js +0 -1
  58. package/dist/submission.d.ts +0 -1
  59. package/dist/submission.js +0 -1
  60. package/dist/support.d.ts +0 -1
  61. package/dist/support.js +0 -1
  62. package/dist/types.d.ts +0 -1
  63. package/dist/types.js +0 -1
  64. package/dist/validation.d.ts +0 -1
  65. package/dist/validation.js +10 -6
  66. package/dist/verify.d.ts +5 -1
  67. package/dist/verify.js +59 -31
  68. package/package.json +4 -9
  69. package/CHANGELOG.md +0 -575
  70. package/CODE_OF_CONDUCT.md +0 -28
  71. package/CONTRIBUTING.md +0 -50
  72. package/ROADMAP.md +0 -121
  73. package/SUPPORT.md +0 -31
  74. package/VISION.md +0 -143
  75. package/dist/bootstrap.d.ts.map +0 -1
  76. package/dist/bootstrap.js.map +0 -1
  77. package/dist/broker.d.ts.map +0 -1
  78. package/dist/broker.js.map +0 -1
  79. package/dist/candidate-lifecycle.d.ts.map +0 -1
  80. package/dist/candidate-lifecycle.js.map +0 -1
  81. package/dist/cli.d.ts.map +0 -1
  82. package/dist/cli.js.map +0 -1
  83. package/dist/config.d.ts.map +0 -1
  84. package/dist/config.js.map +0 -1
  85. package/dist/errors.d.ts.map +0 -1
  86. package/dist/errors.js.map +0 -1
  87. package/dist/gate-authority.d.ts.map +0 -1
  88. package/dist/gate-authority.js.map +0 -1
  89. package/dist/git-locators.d.ts.map +0 -1
  90. package/dist/git-locators.js.map +0 -1
  91. package/dist/git.d.ts.map +0 -1
  92. package/dist/git.js.map +0 -1
  93. package/dist/hooks.d.ts.map +0 -1
  94. package/dist/hooks.js.map +0 -1
  95. package/dist/index.d.ts.map +0 -1
  96. package/dist/index.js.map +0 -1
  97. package/dist/mcp-cli.d.ts.map +0 -1
  98. package/dist/mcp-cli.js.map +0 -1
  99. package/dist/mcp.d.ts.map +0 -1
  100. package/dist/mcp.js.map +0 -1
  101. package/dist/patterns.d.ts.map +0 -1
  102. package/dist/patterns.js.map +0 -1
  103. package/dist/process.d.ts.map +0 -1
  104. package/dist/process.js.map +0 -1
  105. package/dist/provenance.d.ts.map +0 -1
  106. package/dist/provenance.js.map +0 -1
  107. package/dist/publisher.d.ts.map +0 -1
  108. package/dist/publisher.js.map +0 -1
  109. package/dist/scheduler.d.ts.map +0 -1
  110. package/dist/scheduler.js.map +0 -1
  111. package/dist/schema-identity.d.ts.map +0 -1
  112. package/dist/schema-identity.js.map +0 -1
  113. package/dist/serve-log.d.ts.map +0 -1
  114. package/dist/serve-log.js.map +0 -1
  115. package/dist/service.d.ts.map +0 -1
  116. package/dist/service.js.map +0 -1
  117. package/dist/state-codec.d.ts.map +0 -1
  118. package/dist/state-codec.js.map +0 -1
  119. package/dist/status.d.ts.map +0 -1
  120. package/dist/status.js.map +0 -1
  121. package/dist/store.d.ts.map +0 -1
  122. package/dist/store.js.map +0 -1
  123. package/dist/submission-attestation.d.ts.map +0 -1
  124. package/dist/submission-attestation.js.map +0 -1
  125. package/dist/submission-retention.d.ts.map +0 -1
  126. package/dist/submission-retention.js.map +0 -1
  127. package/dist/submission.d.ts.map +0 -1
  128. package/dist/submission.js.map +0 -1
  129. package/dist/support.d.ts.map +0 -1
  130. package/dist/support.js.map +0 -1
  131. package/dist/types.d.ts.map +0 -1
  132. package/dist/types.js.map +0 -1
  133. package/dist/validation.d.ts.map +0 -1
  134. package/dist/validation.js.map +0 -1
  135. package/dist/verify.d.ts.map +0 -1
  136. package/dist/verify.js.map +0 -1
  137. package/docs/ARCHITECTURE.md +0 -552
  138. package/docs/COMPATIBILITY.md +0 -369
  139. package/docs/GETTING_STARTED.md +0 -595
  140. package/docs/PROTOCOL.md +0 -624
  141. package/docs/RELEASING.md +0 -75
  142. package/docs/SECURITY.md +0 -347
  143. package/examples/local-gate/README.md +0 -25
  144. package/examples/local-gate/run.mjs +0 -137
  145. package/examples/two-agents/README.md +0 -42
  146. package/examples/two-agents/run.mjs +0 -146
  147. package/examples/two-agents/run.sh +0 -143
package/README.md CHANGED
@@ -18,22 +18,26 @@ protection, or forge merge queue.
18
18
 
19
19
  ## Release status
20
20
 
21
- Version **0.14.2** includes the complete Coordinate workflow and trusted local-ref Gate validation,
21
+ Version **0.15.1** includes the complete Coordinate workflow and trusted local-ref Gate validation,
22
22
  with Gate diagnostics, abandonment and archival, detached signed validation evidence, offline
23
- verification, stricter state diagnostics, and release safeguards. The documentation tracks source;
23
+ verification, stricter state diagnostics, leaner packaging, storage maintenance, and release safeguards.
24
+ It is a security release: upgrade from 0.15.0, and see the
25
+ [changelog](https://github.com/WeSpitfire/agent-merge-broker/blob/main/CHANGELOG.md) for upgrade notes.
26
+ The documentation tracks source;
24
27
  check the [npm version history](https://www.npmjs.com/package/agent-merge-broker?activeTab=versions)
25
28
  for published availability.
26
29
 
27
30
  The `v0.14.0` and `v0.14.1` GitHub tags remain available, but neither version was published to npm.
28
- Version 0.14.2 is the corrected npm release target for these features; the registry confirms when it
29
- is available.
31
+ The companion core package is published separately; confirm its version in
32
+ [npm's core package history](https://www.npmjs.com/package/agent-merge-broker-core?activeTab=versions).
30
33
 
31
- Version 0.14.2 requires **Node.js 22 or newer**; version 0.13.0 supported Node.js 20.12 or newer.
34
+ Version 0.15.1 requires **Node.js 22 or newer**; version 0.13.0 supported Node.js 20.12 or newer.
32
35
  Git 2.31+ is required for Coordinate; Gate requires Git 2.46+. Linux, macOS, and Windows are
33
36
  supported. GitHub CLI is required only for GitHub pull-request publication.
34
37
 
35
- See [Compatibility](docs/COMPATIBILITY.md), [Changelog](CHANGELOG.md), and
36
- [Roadmap](ROADMAP.md) for the exact boundaries. Gate approval, publication, and merge authorization
38
+ See [Compatibility](https://github.com/WeSpitfire/agent-merge-broker/blob/main/docs/COMPATIBILITY.md),
39
+ [Changelog](https://github.com/WeSpitfire/agent-merge-broker/blob/main/CHANGELOG.md), and
40
+ [Roadmap](https://github.com/WeSpitfire/agent-merge-broker/blob/main/ROADMAP.md) for the exact boundaries. Gate approval, publication, and merge authorization
37
41
  remain planned.
38
42
 
39
43
  ## Try both routes locally
@@ -53,16 +57,31 @@ The Coordinate example combines four commits from two workers and rejects an ove
53
57
  The Gate example validates one candidate, rejects another, signs the accepted result, verifies it
54
58
  offline, and previews archival.
55
59
 
56
- ## Install and review repository policy
60
+ ## Install once, use across projects
61
+
62
+ Keep the tool outside your project's dependencies with a version-pinned global installation:
57
63
 
58
64
  ```bash
59
- npm install --save-dev agent-merge-broker
60
- npx merge-broker init --base main --base-ref origin/main --remote origin
65
+ npm install --global agent-merge-broker@0.15.1
66
+ # From the repository you want to coordinate:
67
+ merge-broker init --base main --base-ref origin/main --remote origin
61
68
  git add .merge-broker AGENTS.md
62
69
  git commit -m 'Configure Agent Merge Broker'
63
- npx merge-broker doctor
70
+ merge-broker doctor
64
71
  ```
65
72
 
73
+ This does not add the broker to your project's `package.json` or `node_modules`. Prefer a
74
+ project-local, lockfile-pinned dev dependency when a team or CI needs to reproduce the entire
75
+ dependency tree. For pinned execution through npm's cache, or local installation instructions, see
76
+ [Getting started](https://github.com/WeSpitfire/agent-merge-broker/blob/main/docs/GETTING_STARTED.md#2-install-and-initialize).
77
+
78
+ `agent-merge-broker-core` offers the same Coordinate/Gate CLI and core Node API
79
+ without the MCP server or SDK dependency. Keep `agent-merge-broker` for MCP support and existing
80
+ imports. Choose one package per installation because they share CLI aliases, and confirm the
81
+ desired version is published for that package. Since 0.15.0, tarballs omit debug maps and long guides/examples while keeping
82
+ runtime code, TypeScript definitions, schemas, templates, README, and license. Full source and
83
+ guides remain on GitHub.
84
+
66
85
  Initialization detects validation commands the repository already declares. Review
67
86
  `.merge-broker/config.json` before using it: configuration is executable policy, and validators run
68
87
  with the broker user's permissions. The public signing key belongs in committed policy; the private
@@ -76,18 +95,18 @@ protected-branch provenance verification load their applicable policy from the e
76
95
  In each worker's linked worktree:
77
96
 
78
97
  ```bash
79
- npx merge-broker task claim SEARCH-1 --holder worker/search --path 'src/search/**'
98
+ merge-broker task claim SEARCH-1 --holder worker/search --path 'src/search/**'
80
99
  # Edit and commit the change.
81
- npx merge-broker task candidate SEARCH-1 --since-base
100
+ merge-broker task candidate SEARCH-1 --since-base
82
101
  ```
83
102
 
84
103
  The integration owner then runs:
85
104
 
86
105
  ```bash
87
- npx merge-broker plan
88
- npx merge-broker integrate --dry-run
89
- npx merge-broker integrate
90
- npx merge-broker status
106
+ merge-broker plan
107
+ merge-broker integrate --dry-run
108
+ merge-broker integrate
109
+ merge-broker status
91
110
  ```
92
111
 
93
112
  Expiring leases reduce predictable collisions; commit receipts identify immutable work. The broker
@@ -97,8 +116,8 @@ branch, or GitHub pull request. Optional approval binds evidence and permission
97
116
  candidate, base, and policy revision. Durable intents allow interrupted publication and merge
98
117
  decisions to be reconciled.
99
118
 
100
- Use [Getting started](docs/GETTING_STARTED.md) for validation, publication, approval, service, and
101
- recovery recipes. The [worker protocol](docs/PROTOCOL.md) documents CLI/JSON, Node, and permission-
119
+ Use [Getting started](https://github.com/WeSpitfire/agent-merge-broker/blob/main/docs/GETTING_STARTED.md) for validation, publication, approval, service, and
120
+ recovery recipes. The [worker protocol](https://github.com/WeSpitfire/agent-merge-broker/blob/main/docs/PROTOCOL.md) documents CLI/JSON, Node, and permission-
102
121
  separated stdio MCP integration.
103
122
 
104
123
  ## Route 2: validate a trusted existing branch
@@ -106,9 +125,9 @@ separated stdio MCP integration.
106
125
  From a reviewed checkout whose protected base contains the committed broker policy:
107
126
 
108
127
  ```bash
109
- npx merge-broker candidate authority setup
110
- npx merge-broker candidate adopt --ref refs/heads/producer/candidate
111
- npx merge-broker candidate show <submission-id>
128
+ merge-broker candidate authority setup
129
+ merge-broker candidate adopt --ref refs/heads/producer/candidate
130
+ merge-broker candidate show <submission-id>
112
131
  ```
113
132
 
114
133
  The candidate must already exist locally and be a nonempty linear descendant of the registered
@@ -116,7 +135,7 @@ base. Gate derives its history and paths, materializes its raw Git bytes, and ru
116
135
  broker-authoritative validators. A `SubmissionRecord` reports `validated`, `rejected`, or `failed`
117
136
  without inventing tasks or leases. A rejected candidate exits nonzero.
118
137
 
119
- Version 0.14.2 includes these operational commands:
138
+ Version 0.15.0 includes these operational commands:
120
139
 
121
140
  ```bash
122
141
  merge-broker doctor --gate
@@ -130,11 +149,11 @@ merge-broker candidate list --all
130
149
  Detached attestations use Ed25519 DSSE and a versioned in-toto validation statement. Offline
131
150
  verification requires an independently trusted key and expected commit, tree, base, policy digest,
132
151
  and authority digest. A valid signature can describe a rejection; validation evidence never grants
133
- merge authorization. [Protocol](docs/PROTOCOL.md) includes the full verifier command, abandonment,
134
- retention options, and immutable [schema identities](schemas/identities.json).
152
+ merge authorization. [Protocol](https://github.com/WeSpitfire/agent-merge-broker/blob/main/docs/PROTOCOL.md) includes the full verifier command, abandonment,
153
+ retention options, and immutable [schema identities](https://github.com/WeSpitfire/agent-merge-broker/blob/main/schemas/identities.json).
135
154
 
136
155
  Gate accepts trusted local code. A disposable worktree is not an execution sandbox. Read the
137
- [security model](docs/SECURITY.md) before choosing the broker host and credentials.
156
+ [security model](https://github.com/WeSpitfire/agent-merge-broker/blob/main/docs/SECURITY.md) before choosing the broker host and credentials.
138
157
 
139
158
  ## Operate and contribute
140
159
 
@@ -143,14 +162,22 @@ replays local interrupted operations. Coordinate publication uses `batch publish
143
162
  and `batch refresh` to observe the forge before proceeding. Gate archival preserves audit records,
144
163
  and releasing a retained Git ref requires an explicit option.
145
164
 
165
+ `storage show` reports broker-managed file sizes without reading file contents.
166
+ `storage compact --older-than 30` previews lossless compression of closed audit-log rotations;
167
+ add `--apply` to perform it. It does not prune evidence, recovery state, keys, worktrees, or Git refs.
168
+ Upgrade all audit readers first: versions before 0.15.0 cannot read compressed rotations.
169
+ See the [storage recipe](https://github.com/WeSpitfire/agent-merge-broker/blob/main/docs/GETTING_STARTED.md#inspect-and-compact-storage).
170
+
146
171
  For protected-branch enforcement of Coordinate provenance, pin the composite action to the matching
147
- release tag: `WeSpitfire/agent-merge-broker/verify@v0.14.2`. Configuration examples are in
148
- [Getting started](docs/GETTING_STARTED.md) and the [release guide](docs/RELEASING.md).
172
+ release tag: `WeSpitfire/agent-merge-broker/verify@v0.15.1`. Configuration examples are in
173
+ [Getting started](https://github.com/WeSpitfire/agent-merge-broker/blob/main/docs/GETTING_STARTED.md) and the [release guide](https://github.com/WeSpitfire/agent-merge-broker/blob/main/docs/RELEASING.md).
149
174
 
150
175
  Source verification includes the full test suite, both examples, and installation of the actual npm
151
176
  tarball. Publication waits for the same immutable commit to pass Linux, macOS, and Windows checks
152
177
  and publishes the tested tarball through npm trusted publishing.
153
178
 
154
- See [Architecture](docs/ARCHITECTURE.md), [Vision](VISION.md), [Contributing](CONTRIBUTING.md), and
155
- [Support](SUPPORT.md). The project is licensed under [Apache-2.0](LICENSE). Pre-1.0 persisted formats
179
+ See [Architecture](https://github.com/WeSpitfire/agent-merge-broker/blob/main/docs/ARCHITECTURE.md),
180
+ [Vision](https://github.com/WeSpitfire/agent-merge-broker/blob/main/VISION.md),
181
+ [Contributing](https://github.com/WeSpitfire/agent-merge-broker/blob/main/CONTRIBUTING.md), and
182
+ [Support](https://github.com/WeSpitfire/agent-merge-broker/blob/main/SUPPORT.md). The project is licensed under [Apache-2.0](LICENSE). Pre-1.0 persisted formats
156
183
  are versioned, but compatibility changes may still require a documented migration.
@@ -14,4 +14,3 @@ export declare function detectBootstrapPlan(root: string): Promise<BootstrapPlan
14
14
  export declare function applyBootstrapPlan(config: BrokerConfig, plan: BootstrapPlan): boolean;
15
15
  export declare function installAgentContract(root: string): Promise<AgentContractResult>;
16
16
  export declare function hasAgentContract(root: string): Promise<boolean>;
17
- //# sourceMappingURL=bootstrap.d.ts.map
package/dist/bootstrap.js CHANGED
@@ -359,4 +359,3 @@ export async function hasAgentContract(root) {
359
359
  const contents = await readFile(target, "utf8");
360
360
  return contents.includes(AGENT_BLOCK_START) && contents.includes(AGENT_BLOCK_END);
361
361
  }
362
- //# sourceMappingURL=bootstrap.js.map
package/dist/broker.d.ts CHANGED
@@ -307,4 +307,3 @@ export declare class MergeBroker {
307
307
  gate?: boolean;
308
308
  }): Promise<Record<string, unknown>>;
309
309
  }
310
- //# sourceMappingURL=broker.d.ts.map
package/dist/broker.js CHANGED
@@ -853,6 +853,8 @@ export class MergeBroker {
853
853
  * claim on anything.
854
854
  */
855
855
  async validateWorkingTree(options = {}) {
856
+ if (options.taskId !== undefined)
857
+ assertTaskId(options.taskId);
856
858
  const scope = options.scope ?? "all";
857
859
  const cwd = options.cwd ? path.resolve(options.cwd) : this.repo.root;
858
860
  const baseRef = options.base ?? this.config.baseRef;
@@ -3848,6 +3850,15 @@ export class MergeBroker {
3848
3850
  }
3849
3851
  const validationReady = this.config.validation.authority === "required-ci"
3850
3852
  || this.config.validation.authoritative.length > 0;
3853
+ // Validators run as this OS user. Removing key variables from their environment does not stop
3854
+ // them from reading the key file or this process's memory, so a signature cannot distinguish a
3855
+ // real batch from one forged by code a worker contributed to a test, build script, or dependency.
3856
+ const signingKeyReachableByValidators = Boolean(signingKeyId
3857
+ && (this.config.validation.focused.length > 0
3858
+ || (this.config.validation.authority === "broker" && this.config.validation.authoritative.length > 0)));
3859
+ if (signingKeyReachableByValidators) {
3860
+ warnings.push("Local validators run as the broker's OS user and can read its provenance signing key. If workers can change code those validators execute, a worker can forge signed provenance. Integrate untrusted work only where no local validator runs worker code, for example required-ci authority without focused validators.");
3861
+ }
3851
3862
  if (!validationReady) {
3852
3863
  warnings.push("validation.authority is broker, but no authoritative validators are configured. Add validation.authoritative commands or explicitly delegate the complete decision to required CI.");
3853
3864
  }
@@ -3960,6 +3971,7 @@ export class MergeBroker {
3960
3971
  authoritativeValidators: this.config.validation.authoritative.map((validator) => validator.name),
3961
3972
  provenanceAuthenticated: Boolean(provenance?.enabled && provenance.requireSignature && signingKeyId),
3962
3973
  provenanceKeyId: signingKeyId,
3974
+ signingKeyReachableByValidators,
3963
3975
  runningBatches,
3964
3976
  pendingCandidateRevisions,
3965
3977
  policy: { configCommitted },
@@ -3973,4 +3985,3 @@ export class MergeBroker {
3973
3985
  };
3974
3986
  }
3975
3987
  }
3976
- //# sourceMappingURL=broker.js.map
@@ -16,4 +16,3 @@ export declare function assertCandidateBinding(candidate: CandidateRecord, bindi
16
16
  }): void;
17
17
  export declare function assertCurrentApprovalPolicy(config: BrokerConfig, candidate: CandidateRecord): void;
18
18
  export declare function upsertEvidence(candidate: CandidateRecord, evidence: VerificationEvidence): void;
19
- //# sourceMappingURL=candidate-lifecycle.d.ts.map
@@ -169,4 +169,3 @@ export function upsertEvidence(candidate, evidence) {
169
169
  candidate.state = candidateState(candidate);
170
170
  delete candidate.reason;
171
171
  }
172
- //# sourceMappingURL=candidate-lifecycle.js.map
package/dist/cli.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  #!/usr/bin/env node
2
2
  export {};
3
- //# sourceMappingURL=cli.d.ts.map
package/dist/cli.js CHANGED
@@ -9,6 +9,9 @@ import { BrokerError, CommandError } from "./errors.js";
9
9
  import { formatServeEvent, isErrorEvent, serveEventJson, shouldReportIdle, } from "./serve-log.js";
10
10
  import { MergeBroker } from "./broker.js";
11
11
  import { GitRepository } from "./git.js";
12
+ import { loadConfig } from "./config.js";
13
+ import { StateStore } from "./store.js";
14
+ import { compactAuditStorage, inspectStorage } from "./storage.js";
12
15
  import { prePushHook } from "./hooks.js";
13
16
  import { formatBrokerStatus } from "./status.js";
14
17
  import { createSupportBundle } from "./support.js";
@@ -1017,6 +1020,7 @@ program
1017
1020
  provenanceDirectory: options.provenanceDirectory ?? policy.provenanceDirectory ?? ".merge-broker/attestations",
1018
1021
  ...(policy.publicKey ? { publicKey: policy.publicKey } : {}),
1019
1022
  requireSignature: policy.requireSignature ?? false,
1023
+ ...(policy.validationAuthority ? { validationAuthority: policy.validationAuthority } : {}),
1020
1024
  });
1021
1025
  output(result, [
1022
1026
  `${result.authenticated ? "Authenticated" : "Structurally verified"} broker batch ${result.batchId}.`,
@@ -1048,6 +1052,49 @@ program
1048
1052
  ...(result.archivePath ? [`Archive: ${result.archivePath}`] : []),
1049
1053
  ].join("\n"));
1050
1054
  });
1055
+ const storage = program.command("storage").description("inspect broker storage and compact closed audit logs without deleting evidence");
1056
+ // Inspection/preview must not initialize absent state or create keys and lock directories.
1057
+ async function storageContext() {
1058
+ const repo = await GitRepository.discover(globalOptions().cwd);
1059
+ const config = await loadConfig(repo.root);
1060
+ const store = new StateStore(repo.commonGitDir, config.stateDirectory, config.leases.lockTimeoutSeconds);
1061
+ return { repo, config, store };
1062
+ }
1063
+ storage.command("show")
1064
+ .description("report logical bytes and file counts; never read stored secrets or follow symlinks")
1065
+ .action(async () => {
1066
+ const { repo, config, store } = await storageContext();
1067
+ const report = await inspectStorage(store, {
1068
+ repositoryRoot: repo.root,
1069
+ ...(config.integration.provenance?.directory ? { provenanceDirectory: config.integration.provenance.directory } : {}),
1070
+ });
1071
+ output(report, [
1072
+ `Broker storage: ${report.logicalBytes.toLocaleString("en-US")} logical bytes in ${report.files} files${report.complete ? "" : " (partial)"}.`,
1073
+ ...report.categories.map((item) => ` ${item.category}: ${item.logicalBytes.toLocaleString("en-US")} bytes, ${item.files} files`),
1074
+ "Excludes npm installations, general repository files, Git object history, and filesystem allocation overhead.",
1075
+ ...report.skipped.map((item) => `Skipped ${item.path}: ${item.reason}`),
1076
+ ].join("\n"));
1077
+ });
1078
+ storage.command("compact")
1079
+ .description("preview lossless compression of closed audit logs; active and recovery data stay untouched")
1080
+ .option("--older-than <days>", "minimum modification age of closed audit logs", "30")
1081
+ .option("--apply", "write verified gzip copies and remove only their redundant originals")
1082
+ .action(async (options) => {
1083
+ const { store } = await storageContext();
1084
+ const result = await compactAuditStorage(store, {
1085
+ olderThanDays: Number(options.olderThan),
1086
+ apply: options.apply ?? false,
1087
+ });
1088
+ output(result, [
1089
+ result.applied
1090
+ ? `Compressed ${result.compressedFiles} closed audit segments; saved ${result.savedBytes.toLocaleString("en-US")} bytes.`
1091
+ : `Eligible: ${result.eligibleFiles} closed audit segments (${result.eligibleBytes.toLocaleString("en-US")} bytes). Preview only; add --apply to compress.`,
1092
+ "Audit evidence is preserved. No active state, signing keys, worktrees, or retained Git refs are deleted.",
1093
+ "Compacted audit history requires a broker version with gzip archive support.",
1094
+ ...result.entries.map((item) => `${item.status}: ${item.path}${item.reason ? ` — ${item.reason}` : ""}`),
1095
+ ...result.skipped.map((item) => `Skipped ${item.path}: ${item.reason}`),
1096
+ ].join("\n"));
1097
+ });
1051
1098
  program
1052
1099
  .command("recover")
1053
1100
  .description("recover interrupted integrations and candidate validation submissions")
@@ -1325,4 +1372,3 @@ program.parseAsync().catch((error) => {
1325
1372
  }
1326
1373
  process.exitCode = 1;
1327
1374
  });
1328
- //# sourceMappingURL=cli.js.map
package/dist/config.d.ts CHANGED
@@ -19,4 +19,3 @@ export declare function isSafeStateDirectory(value: unknown): value is string;
19
19
  export declare function validateConfig(value: unknown): BrokerConfig;
20
20
  export declare function loadConfig(repoRoot: string): Promise<BrokerConfig>;
21
21
  export declare function writeConfig(repoRoot: string, config: BrokerConfig): Promise<string>;
22
- //# sourceMappingURL=config.d.ts.map
package/dist/config.js CHANGED
@@ -524,4 +524,3 @@ export async function writeConfig(repoRoot, config) {
524
524
  await writeFile(target, `${JSON.stringify(config, null, 2)}\n`, "utf8");
525
525
  return target;
526
526
  }
527
- //# sourceMappingURL=config.js.map
package/dist/core.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ export { MergeBroker, type AdoptCandidateInput, type ClaimTaskInput, type RegisterCandidateAuthorityOptions, type RegisterTaskInput, } from "./broker.js";
2
+ export { adoptedRef, GitRepository, type LinearCommitHistory, type PinnedGitCommit, type WorktreeInfo, } from "./git.js";
3
+ export { StateStore, type ArchivedStateSlice, type LockStatus } from "./store.js";
4
+ export { inspectStorage, compactAuditStorage, type StorageCategory, type StorageReport, type StorageCompactionOptions, type StorageCompactionResult, } from "./storage.js";
5
+ export { installHooks, prePushHook, uninstallHooks, type HookInstallation } from "./hooks.js";
6
+ export { describeServeEvent, formatServeEvent, serveEventJson, shouldReportIdle, type ServeEvent, } from "./serve-log.js";
7
+ export { currentServicePlatform, installService, launchdPlist, serviceFilePath, serviceName, systemdUnit, windowsTaskXml, quoteWindowsArgument, uninstallService, type ServiceDefinition, type ServiceInstallation, type ServiceOptions, type ServicePlatform, } from "./service.js";
8
+ export { defaultConfig, initializeConfig, loadConfig, validateConfig, writeConfig } from "./config.js";
9
+ export { applyBootstrapPlan, detectBootstrapPlan, hasAgentContract, installAgentContract, type AgentContractResult, type BootstrapPlan, } from "./bootstrap.js";
10
+ export { scheduleTasks } from "./scheduler.js";
11
+ export { formatBrokerStatus } from "./status.js";
12
+ export { createSupportBundle, sanitizeSupportData, type SupportBundle } from "./support.js";
13
+ export { githubCliPublisher, type ForgePublisher, type PublicationResult, type PullRequestState, } from "./publisher.js";
14
+ export { buildBatchProvenance, generateProvenanceSigningIdentity, provenanceKeyId, provenancePath, publicKeyFromPrivate, signBatchProvenance, validateProvenancePublicKey, verifyBatchProvenanceSignature, type ProvenanceSigningIdentity, } from "./provenance.js";
15
+ export { batchIdFromBranch, policyFromBase, verifyProvenance, type ProvenanceVerification, type VerifyProvenanceOptions, } from "./verify.js";
16
+ export { BrokerError, CommandError, ValidationError } from "./errors.js";
17
+ export { signSubmissionAttestation, verifySubmissionAttestation, submissionAttestationEnvelopeSchema, submissionAttestationStatementSchema, SUBMISSION_ATTESTATION_PAYLOAD_TYPE, SUBMISSION_ATTESTATION_PREDICATE_TYPE, type SubmissionAttestationEnvelope, type SubmissionAttestationStatement, type SubmissionAttestationVerificationOptions, type SubmissionAttestationVerificationResult, } from "./submission-attestation.js";
18
+ export { schemaFingerprint, schemaSnapshotIdentity } from "./schema-identity.js";
19
+ export type * from "./types.js";
package/dist/core.js ADDED
@@ -0,0 +1,18 @@
1
+ export { MergeBroker, } from "./broker.js";
2
+ export { adoptedRef, GitRepository, } from "./git.js";
3
+ export { StateStore } from "./store.js";
4
+ export { inspectStorage, compactAuditStorage, } from "./storage.js";
5
+ export { installHooks, prePushHook, uninstallHooks } from "./hooks.js";
6
+ export { describeServeEvent, formatServeEvent, serveEventJson, shouldReportIdle, } from "./serve-log.js";
7
+ export { currentServicePlatform, installService, launchdPlist, serviceFilePath, serviceName, systemdUnit, windowsTaskXml, quoteWindowsArgument, uninstallService, } from "./service.js";
8
+ export { defaultConfig, initializeConfig, loadConfig, validateConfig, writeConfig } from "./config.js";
9
+ export { applyBootstrapPlan, detectBootstrapPlan, hasAgentContract, installAgentContract, } from "./bootstrap.js";
10
+ export { scheduleTasks } from "./scheduler.js";
11
+ export { formatBrokerStatus } from "./status.js";
12
+ export { createSupportBundle, sanitizeSupportData } from "./support.js";
13
+ export { githubCliPublisher, } from "./publisher.js";
14
+ export { buildBatchProvenance, generateProvenanceSigningIdentity, provenanceKeyId, provenancePath, publicKeyFromPrivate, signBatchProvenance, validateProvenancePublicKey, verifyBatchProvenanceSignature, } from "./provenance.js";
15
+ export { batchIdFromBranch, policyFromBase, verifyProvenance, } from "./verify.js";
16
+ export { BrokerError, CommandError, ValidationError } from "./errors.js";
17
+ export { signSubmissionAttestation, verifySubmissionAttestation, submissionAttestationEnvelopeSchema, submissionAttestationStatementSchema, SUBMISSION_ATTESTATION_PAYLOAD_TYPE, SUBMISSION_ATTESTATION_PREDICATE_TYPE, } from "./submission-attestation.js";
18
+ export { schemaFingerprint, schemaSnapshotIdentity } from "./schema-identity.js";
package/dist/errors.d.ts CHANGED
@@ -13,4 +13,3 @@ export declare class CommandError extends BrokerError {
13
13
  export declare class ValidationError extends BrokerError {
14
14
  constructor(message: string, details?: Record<string, unknown>);
15
15
  }
16
- //# sourceMappingURL=errors.d.ts.map
package/dist/errors.js CHANGED
@@ -33,4 +33,3 @@ export class ValidationError extends BrokerError {
33
33
  this.name = "ValidationError";
34
34
  }
35
35
  }
36
- //# sourceMappingURL=errors.js.map
@@ -19,4 +19,3 @@ export declare class GateAuthorityStore {
19
19
  private atomicReplace;
20
20
  private writeTemporary;
21
21
  }
22
- //# sourceMappingURL=gate-authority.d.ts.map
@@ -285,4 +285,3 @@ export class GateAuthorityStore {
285
285
  return temporary;
286
286
  }
287
287
  }
288
- //# sourceMappingURL=gate-authority.js.map
@@ -5,4 +5,3 @@ export declare function canonicalRemoteUrl(value: string, repoRoot: string): str
5
5
  export declare function localFileRemotePath(value: string, remote: string, purpose: "fetch" | "publication"): string;
6
6
  /** Remove one command record terminator without changing legal whitespace in a local pathname. */
7
7
  export declare function singleGitOutputRecord(output: string): string | undefined;
8
- //# sourceMappingURL=git-locators.d.ts.map
@@ -107,4 +107,3 @@ export function singleGitOutputRecord(output) {
107
107
  // risk resolving the replacement-character spelling to a different repository on disk.
108
108
  return value.length > 0 && !/[\0\r\n\ufffd]/u.test(value) ? value : undefined;
109
109
  }
110
- //# sourceMappingURL=git-locators.js.map
package/dist/git.d.ts CHANGED
@@ -212,4 +212,3 @@ export declare class GitRepository {
212
212
  replaceLocalBranch(branch: string, nextHead: string): Promise<void>;
213
213
  listWorktrees(): Promise<WorktreeInfo[]>;
214
214
  }
215
- //# sourceMappingURL=git.d.ts.map
package/dist/git.js CHANGED
@@ -6,7 +6,7 @@ import { chmod, lchmod, lstat, mkdir, mkdtemp, opendir, readFile, readlink, real
6
6
  import { remoteUrlFingerprint, forgeRepositoryFromRemote, canonicalRemoteUrl, localFileRemotePath, singleGitOutputRecord, } from "./git-locators.js";
7
7
  export { remoteUrlFingerprint, isHostQualifiedForgeRepository } from "./git-locators.js";
8
8
  import { BrokerError } from "./errors.js";
9
- import { runCommand } from "./process.js";
9
+ import { runCommand, withoutCurrentDirectoryExecutableSearch } from "./process.js";
10
10
  const ADOPTED_REF_PREFIX = "refs/merge-broker/adopted";
11
11
  const GATE_MINIMUM_GIT = [2, 46];
12
12
  const GATE_MAX_COMMIT_BYTES = 1 * 1_024 * 1_024;
@@ -192,6 +192,12 @@ export class GitRepository {
192
192
  return new GitRepository(root, path.resolve(common.stdout.trim()));
193
193
  }
194
194
  async git(args, cwd = this.root, allowFailure = false) {
195
+ if (path.resolve(cwd) !== path.resolve(this.root)) {
196
+ // A relative core.hooksPath -- written by install-hooks, husky, and similar tools -- resolves
197
+ // against the worktree Git runs in. In an integration or worker worktree that directory is
198
+ // submitted content, and even read-mostly commands such as status can fire index hooks.
199
+ return await this.withIsolatedHooks(async (hooksDirectory) => await runCommand("git", ["-c", `core.hooksPath=${hooksDirectory}`, ...args], { cwd, allowFailure }));
200
+ }
195
201
  return await runCommand("git", args, { cwd, allowFailure });
196
202
  }
197
203
  /** Run Git without allowing a partial/promisor clone to fetch missing objects implicitly. */
@@ -436,13 +442,14 @@ export class GitRepository {
436
442
  /** Capture bounded binary Git output without text decoding or promisor lazy fetch. */
437
443
  async localObjectGitBuffer(args, cwd, input, maxOutputBytes) {
438
444
  return await new Promise((resolve, reject) => {
439
- const child = spawn("git", [...GATE_GIT_CONFIG_ARGUMENTS, ...args], {
445
+ const env = localGateGitEnvironment();
446
+ const child = withoutCurrentDirectoryExecutableSearch(() => spawn("git", [...GATE_GIT_CONFIG_ARGUMENTS, ...args], {
440
447
  cwd,
441
- env: localGateGitEnvironment(),
448
+ env,
442
449
  shell: false,
443
450
  stdio: "pipe",
444
451
  windowsHide: true,
445
- });
452
+ }));
446
453
  const chunks = [];
447
454
  const errors = [];
448
455
  let outputBytes = 0;
@@ -2273,10 +2280,27 @@ export class GitRepository {
2273
2280
  async commitGeneratedFile(cwd, relativePath, contents, message) {
2274
2281
  const target = path.resolve(cwd, relativePath);
2275
2282
  const relative = path.relative(cwd, target);
2276
- if (relative.startsWith("..") || path.isAbsolute(relative)) {
2283
+ if (relative === "" || relative.startsWith("..") || path.isAbsolute(relative)) {
2277
2284
  throw new BrokerError("UNSAFE_PATH", `Generated file escapes the integration worktree: ${relativePath}`);
2278
2285
  }
2279
- await mkdir(path.dirname(target), { recursive: true });
2286
+ // The containing directories come from submitted content. A committed symlink at any component
2287
+ // would otherwise redirect the write outside the worktree before `git add` refuses the path.
2288
+ let current = cwd;
2289
+ const components = relative.split(path.sep);
2290
+ for (const [index, component] of components.entries()) {
2291
+ current = path.join(current, component);
2292
+ const status = await lstat(current).catch((error) => {
2293
+ if (error.code === "ENOENT")
2294
+ return undefined;
2295
+ throw error;
2296
+ });
2297
+ const isFinal = index === components.length - 1;
2298
+ if (status?.isSymbolicLink() || (status && !isFinal && !status.isDirectory())) {
2299
+ throw new BrokerError("UNSAFE_PATH", `Generated file path passes through a link or non-directory in the integration worktree: ${relativePath}`);
2300
+ }
2301
+ if (!status && !isFinal)
2302
+ await mkdir(current);
2303
+ }
2280
2304
  await writeFile(target, contents, "utf8");
2281
2305
  await this.git(["add", "--", relativePath], cwd);
2282
2306
  await this.brokerCommitGit(["commit", "-m", message], cwd);
@@ -2366,4 +2390,3 @@ export class GitRepository {
2366
2390
  return records;
2367
2391
  }
2368
2392
  }
2369
- //# sourceMappingURL=git.js.map
package/dist/hooks.d.ts CHANGED
@@ -19,4 +19,3 @@ export declare function installHooks(options: {
19
19
  force?: boolean;
20
20
  }): Promise<HookInstallation>;
21
21
  export declare function uninstallHooks(repo: GitRepository): Promise<HookInstallation>;
22
- //# sourceMappingURL=hooks.d.ts.map
package/dist/hooks.js CHANGED
@@ -123,4 +123,3 @@ export async function uninstallHooks(repo) {
123
123
  }
124
124
  return { hooksPath, hookFile, installed: false };
125
125
  }
126
- //# sourceMappingURL=hooks.js.map
package/dist/index.d.ts CHANGED
@@ -1,20 +1,2 @@
1
- export { MergeBroker, type AdoptCandidateInput, type ClaimTaskInput, type RegisterCandidateAuthorityOptions, type RegisterTaskInput, } from "./broker.js";
2
- export { adoptedRef, GitRepository, type LinearCommitHistory, type PinnedGitCommit, type WorktreeInfo, } from "./git.js";
3
- export { StateStore, type ArchivedStateSlice, type LockStatus } from "./store.js";
4
- export { installHooks, prePushHook, uninstallHooks, type HookInstallation } from "./hooks.js";
5
- export { describeServeEvent, formatServeEvent, serveEventJson, shouldReportIdle, type ServeEvent, } from "./serve-log.js";
6
- export { currentServicePlatform, installService, launchdPlist, serviceFilePath, serviceName, systemdUnit, windowsTaskXml, quoteWindowsArgument, uninstallService, type ServiceDefinition, type ServiceInstallation, type ServiceOptions, type ServicePlatform, } from "./service.js";
7
- export { defaultConfig, initializeConfig, loadConfig, validateConfig, writeConfig } from "./config.js";
8
- export { applyBootstrapPlan, detectBootstrapPlan, hasAgentContract, installAgentContract, type AgentContractResult, type BootstrapPlan, } from "./bootstrap.js";
9
- export { scheduleTasks } from "./scheduler.js";
10
- export { formatBrokerStatus } from "./status.js";
11
- export { createSupportBundle, sanitizeSupportData, type SupportBundle } from "./support.js";
1
+ export * from "./core.js";
12
2
  export { createMcpServer, mcpToolNames, type McpProfile } from "./mcp.js";
13
- export { githubCliPublisher, type ForgePublisher, type PublicationResult, type PullRequestState, } from "./publisher.js";
14
- export { buildBatchProvenance, generateProvenanceSigningIdentity, provenanceKeyId, provenancePath, publicKeyFromPrivate, signBatchProvenance, validateProvenancePublicKey, verifyBatchProvenanceSignature, type ProvenanceSigningIdentity, } from "./provenance.js";
15
- export { batchIdFromBranch, policyFromBase, verifyProvenance, type ProvenanceVerification, type VerifyProvenanceOptions, } from "./verify.js";
16
- export { BrokerError, CommandError, ValidationError } from "./errors.js";
17
- export { signSubmissionAttestation, verifySubmissionAttestation, submissionAttestationEnvelopeSchema, submissionAttestationStatementSchema, SUBMISSION_ATTESTATION_PAYLOAD_TYPE, SUBMISSION_ATTESTATION_PREDICATE_TYPE, type SubmissionAttestationEnvelope, type SubmissionAttestationStatement, type SubmissionAttestationVerificationOptions, type SubmissionAttestationVerificationResult, } from "./submission-attestation.js";
18
- export { schemaFingerprint, schemaSnapshotIdentity } from "./schema-identity.js";
19
- export type * from "./types.js";
20
- //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -1,19 +1,3 @@
1
- export { MergeBroker, } from "./broker.js";
2
- export { adoptedRef, GitRepository, } from "./git.js";
3
- export { StateStore } from "./store.js";
4
- export { installHooks, prePushHook, uninstallHooks } from "./hooks.js";
5
- export { describeServeEvent, formatServeEvent, serveEventJson, shouldReportIdle, } from "./serve-log.js";
6
- export { currentServicePlatform, installService, launchdPlist, serviceFilePath, serviceName, systemdUnit, windowsTaskXml, quoteWindowsArgument, uninstallService, } from "./service.js";
7
- export { defaultConfig, initializeConfig, loadConfig, validateConfig, writeConfig } from "./config.js";
8
- export { applyBootstrapPlan, detectBootstrapPlan, hasAgentContract, installAgentContract, } from "./bootstrap.js";
9
- export { scheduleTasks } from "./scheduler.js";
10
- export { formatBrokerStatus } from "./status.js";
11
- export { createSupportBundle, sanitizeSupportData } from "./support.js";
1
+ // Preserve the full package's public API; CLI-only consumers use the shared core entry point.
2
+ export * from "./core.js";
12
3
  export { createMcpServer, mcpToolNames } from "./mcp.js";
13
- export { githubCliPublisher, } from "./publisher.js";
14
- export { buildBatchProvenance, generateProvenanceSigningIdentity, provenanceKeyId, provenancePath, publicKeyFromPrivate, signBatchProvenance, validateProvenancePublicKey, verifyBatchProvenanceSignature, } from "./provenance.js";
15
- export { batchIdFromBranch, policyFromBase, verifyProvenance, } from "./verify.js";
16
- export { BrokerError, CommandError, ValidationError } from "./errors.js";
17
- export { signSubmissionAttestation, verifySubmissionAttestation, submissionAttestationEnvelopeSchema, submissionAttestationStatementSchema, SUBMISSION_ATTESTATION_PAYLOAD_TYPE, SUBMISSION_ATTESTATION_PREDICATE_TYPE, } from "./submission-attestation.js";
18
- export { schemaFingerprint, schemaSnapshotIdentity } from "./schema-identity.js";
19
- //# sourceMappingURL=index.js.map
package/dist/mcp-cli.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  #!/usr/bin/env node
2
2
  export {};
3
- //# sourceMappingURL=mcp-cli.d.ts.map
package/dist/mcp-cli.js CHANGED
@@ -18,4 +18,3 @@ for (const signal of ["SIGINT", "SIGTERM"]) {
18
18
  void handle.close().finally(() => process.exit(0));
19
19
  });
20
20
  }
21
- //# sourceMappingURL=mcp-cli.js.map
package/dist/mcp.d.ts CHANGED
@@ -9,5 +9,9 @@ export declare function createMcpServer(options?: {
9
9
  cwd?: string;
10
10
  profile?: McpProfile;
11
11
  version?: string;
12
+ /**
13
+ * Stable worker identity for this server. Defaults to MERGE_BROKER_AGENT. When set, a restarted
14
+ * worker server may resume leases held under exactly this identity.
15
+ */
16
+ agent?: string;
12
17
  }): McpServer;
13
- //# sourceMappingURL=mcp.d.ts.map