agent-merge-broker 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +352 -0
  3. package/dist/broker.d.ts +110 -0
  4. package/dist/broker.d.ts.map +1 -0
  5. package/dist/broker.js +1023 -0
  6. package/dist/broker.js.map +1 -0
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +558 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/config.d.ts +19 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +312 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/errors.d.ts +16 -0
  16. package/dist/errors.d.ts.map +1 -0
  17. package/dist/errors.js +36 -0
  18. package/dist/errors.js.map +1 -0
  19. package/dist/git.d.ts +46 -0
  20. package/dist/git.d.ts.map +1 -0
  21. package/dist/git.js +195 -0
  22. package/dist/git.js.map +1 -0
  23. package/dist/hooks.d.ts +22 -0
  24. package/dist/hooks.d.ts.map +1 -0
  25. package/dist/hooks.js +110 -0
  26. package/dist/hooks.js.map +1 -0
  27. package/dist/index.d.ts +11 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +10 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/patterns.d.ts +9 -0
  32. package/dist/patterns.d.ts.map +1 -0
  33. package/dist/patterns.js +66 -0
  34. package/dist/patterns.js.map +1 -0
  35. package/dist/process.d.ts +30 -0
  36. package/dist/process.d.ts.map +1 -0
  37. package/dist/process.js +91 -0
  38. package/dist/process.js.map +1 -0
  39. package/dist/provenance.d.ts +10 -0
  40. package/dist/provenance.d.ts.map +1 -0
  41. package/dist/provenance.js +36 -0
  42. package/dist/provenance.js.map +1 -0
  43. package/dist/publisher.d.ts +37 -0
  44. package/dist/publisher.d.ts.map +1 -0
  45. package/dist/publisher.js +144 -0
  46. package/dist/publisher.js.map +1 -0
  47. package/dist/scheduler.d.ts +6 -0
  48. package/dist/scheduler.d.ts.map +1 -0
  49. package/dist/scheduler.js +96 -0
  50. package/dist/scheduler.js.map +1 -0
  51. package/dist/store.d.ts +73 -0
  52. package/dist/store.d.ts.map +1 -0
  53. package/dist/store.js +323 -0
  54. package/dist/store.js.map +1 -0
  55. package/dist/types.d.ts +219 -0
  56. package/dist/types.d.ts.map +1 -0
  57. package/dist/types.js +3 -0
  58. package/dist/types.js.map +1 -0
  59. package/dist/validation.d.ts +13 -0
  60. package/dist/validation.d.ts.map +1 -0
  61. package/dist/validation.js +75 -0
  62. package/dist/validation.js.map +1 -0
  63. package/dist/verify.d.ts +40 -0
  64. package/dist/verify.d.ts.map +1 -0
  65. package/dist/verify.js +177 -0
  66. package/dist/verify.js.map +1 -0
  67. package/docs/ARCHITECTURE.md +144 -0
  68. package/docs/PROTOCOL.md +127 -0
  69. package/docs/RELEASING.md +23 -0
  70. package/docs/SECURITY.md +57 -0
  71. package/package.json +68 -0
  72. package/schemas/config.schema.json +149 -0
  73. package/schemas/provenance.schema.json +56 -0
  74. package/schemas/receipt.schema.json +39 -0
  75. package/templates/AGENTS.snippet.md +5 -0
package/dist/config.js ADDED
@@ -0,0 +1,312 @@
1
+ import path from "node:path";
2
+ import { access, mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import { constants } from "node:fs";
4
+ import { BrokerError } from "./errors.js";
5
+ import { CONFIG_VERSION } from "./types.js";
6
+ export const CONFIG_DIRECTORY = ".merge-broker";
7
+ export const CONFIG_FILENAME = "config.json";
8
+ export const AGENT_INSTRUCTIONS_FILENAME = "agent-instructions.md";
9
+ const AGENT_INSTRUCTIONS = `# Merge Broker agent contract
10
+
11
+ This repository coordinates parallel work with Agent Merge Broker.
12
+
13
+ 1. Claim a task and declare the smallest accurate path scope before editing:
14
+ \`merge-broker task claim <task-id> --holder <agent> --path 'src/area/**'\`
15
+ 2. Heartbeat long-running work with \`merge-broker task heartbeat <task-id>\`. The broker holds the
16
+ lease token for you; pass \`--token\` only when working from another machine.
17
+ 3. Work only inside the declared scope. Coordinate a new claim before expanding it.
18
+ 4. Commit the completed, focused change. Agents do not merge, rebase, push, or administer branches.
19
+ 5. Submit immutable commits to the broker:
20
+ \`merge-broker task submit <task-id> --since-base\`
21
+ 6. Report the task ID, commit SHA, changed paths, and validation performed.
22
+
23
+ The broker owns integration ordering, conflict resolution requests, validation, batching, and publication.
24
+ `;
25
+ export function defaultConfig(baseBranch = "main", remote = "origin", baseRef = baseBranch) {
26
+ return {
27
+ version: CONFIG_VERSION,
28
+ baseBranch,
29
+ baseRef,
30
+ remote,
31
+ stateDirectory: "merge-broker",
32
+ leases: {
33
+ ttlSeconds: 1_800,
34
+ lockTimeoutSeconds: 15,
35
+ serializedPatterns: [
36
+ "package-lock.json",
37
+ "pnpm-lock.yaml",
38
+ "yarn.lock",
39
+ ],
40
+ },
41
+ policies: {
42
+ unexpectedPaths: "error",
43
+ requireCleanWorktree: false,
44
+ requireDependencies: true,
45
+ },
46
+ scheduling: {
47
+ maxTasks: 6,
48
+ maxCommits: 12,
49
+ maxWaitSeconds: 600,
50
+ allowPathOverlap: false,
51
+ },
52
+ integration: {
53
+ branchPrefix: "merge-broker/",
54
+ history: "preserve",
55
+ keepFailedWorktrees: false,
56
+ refreshBase: true,
57
+ maxAttempts: 3,
58
+ provenance: {
59
+ enabled: true,
60
+ directory: ".merge-broker/attestations",
61
+ },
62
+ },
63
+ validation: {
64
+ focused: [],
65
+ authoritative: [],
66
+ },
67
+ publish: {
68
+ mode: "none",
69
+ draft: false,
70
+ autoMerge: true,
71
+ mergeMethod: "squash",
72
+ labels: [],
73
+ titleTemplate: "Integration batch {batchId}",
74
+ },
75
+ };
76
+ }
77
+ async function exists(file) {
78
+ try {
79
+ await access(file, constants.F_OK);
80
+ return true;
81
+ }
82
+ catch {
83
+ return false;
84
+ }
85
+ }
86
+ export function configPath(repoRoot) {
87
+ return path.join(repoRoot, CONFIG_DIRECTORY, CONFIG_FILENAME);
88
+ }
89
+ export async function initializeConfig(repoRoot, options = {}) {
90
+ const target = configPath(repoRoot);
91
+ if ((await exists(target)) && !options.force) {
92
+ const instructions = path.join(path.dirname(target), AGENT_INSTRUCTIONS_FILENAME);
93
+ if (!(await exists(instructions)))
94
+ await writeFile(instructions, AGENT_INSTRUCTIONS, "utf8");
95
+ return { path: target, config: await loadConfig(repoRoot), created: false };
96
+ }
97
+ const config = defaultConfig(options.baseBranch, options.remote, options.baseRef);
98
+ await mkdir(path.dirname(target), { recursive: true });
99
+ await writeFile(target, `${JSON.stringify(config, null, 2)}\n`, "utf8");
100
+ const instructions = path.join(path.dirname(target), AGENT_INSTRUCTIONS_FILENAME);
101
+ if (!(await exists(instructions)))
102
+ await writeFile(instructions, AGENT_INSTRUCTIONS, "utf8");
103
+ return { path: target, config, created: true };
104
+ }
105
+ function assertString(value, key) {
106
+ if (typeof value !== "string" || value.trim() === "") {
107
+ throw new BrokerError("INVALID_CONFIG", `Configuration field ${key} must be a non-empty string.`);
108
+ }
109
+ }
110
+ function assertPositiveInteger(value, key) {
111
+ if (!Number.isInteger(value) || value <= 0) {
112
+ throw new BrokerError("INVALID_CONFIG", `Configuration field ${key} must be a positive integer.`);
113
+ }
114
+ }
115
+ function assertBoolean(value, key) {
116
+ if (typeof value !== "boolean") {
117
+ throw new BrokerError("INVALID_CONFIG", `Configuration field ${key} must be a boolean.`);
118
+ }
119
+ }
120
+ function assertStringArray(value, key) {
121
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string" || item.trim() === "")) {
122
+ throw new BrokerError("INVALID_CONFIG", `Configuration field ${key} must be an array of non-empty strings.`);
123
+ }
124
+ }
125
+ function assertAllowedKeys(value, key, allowed) {
126
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
127
+ throw new BrokerError("INVALID_CONFIG", `Configuration field ${key} must be an object.`);
128
+ }
129
+ const unexpected = Object.keys(value).filter((item) => !allowed.includes(item));
130
+ if (unexpected.length > 0) {
131
+ throw new BrokerError("INVALID_CONFIG", `Unknown configuration field(s) in ${key}: ${unexpected.join(", ")}.`);
132
+ }
133
+ }
134
+ function assertSafeGitName(value, key, allowTrailingSlash = false) {
135
+ const candidate = allowTrailingSlash ? value.replace(/\/+$/u, "") : value;
136
+ if (!/^[a-zA-Z0-9][a-zA-Z0-9._/-]*$/u.test(candidate) ||
137
+ candidate.includes("..") ||
138
+ candidate.includes("//") ||
139
+ candidate.endsWith(".") ||
140
+ (!allowTrailingSlash && candidate.endsWith("/"))) {
141
+ throw new BrokerError("INVALID_CONFIG", `Configuration field ${key} is not a safe Git name.`);
142
+ }
143
+ }
144
+ export function validateConfig(value) {
145
+ if (!value || typeof value !== "object") {
146
+ throw new BrokerError("INVALID_CONFIG", "Configuration must be a JSON object.");
147
+ }
148
+ const config = value;
149
+ assertAllowedKeys(config, "root", [
150
+ "version",
151
+ "baseBranch",
152
+ "baseRef",
153
+ "remote",
154
+ "stateDirectory",
155
+ "leases",
156
+ "policies",
157
+ "scheduling",
158
+ "integration",
159
+ "validation",
160
+ "publish",
161
+ ]);
162
+ if (config.version !== CONFIG_VERSION) {
163
+ throw new BrokerError("INVALID_CONFIG", `Unsupported configuration version: ${String(config.version)}`);
164
+ }
165
+ assertString(config.baseBranch, "baseBranch");
166
+ assertString(config.baseRef, "baseRef");
167
+ assertString(config.remote, "remote");
168
+ assertSafeGitName(config.baseBranch, "baseBranch");
169
+ assertSafeGitName(config.baseRef, "baseRef");
170
+ assertSafeGitName(config.remote, "remote");
171
+ assertString(config.stateDirectory, "stateDirectory");
172
+ if (path.isAbsolute(config.stateDirectory) ||
173
+ config.stateDirectory === "." ||
174
+ config.stateDirectory.split(/[\\/]/u).some((part) => part === "..") ||
175
+ new Set(["branches", "hooks", "info", "logs", "objects", "refs", "worktrees"]).has(config.stateDirectory.split(/[\\/]/u)[0] ?? "")) {
176
+ throw new BrokerError("INVALID_CONFIG", "stateDirectory must stay inside Git's common directory.");
177
+ }
178
+ assertAllowedKeys(config.leases, "leases", ["ttlSeconds", "lockTimeoutSeconds", "serializedPatterns"]);
179
+ assertPositiveInteger(config.leases?.ttlSeconds, "leases.ttlSeconds");
180
+ assertPositiveInteger(config.leases?.lockTimeoutSeconds, "leases.lockTimeoutSeconds");
181
+ assertStringArray(config.leases?.serializedPatterns, "leases.serializedPatterns");
182
+ assertAllowedKeys(config.policies, "policies", [
183
+ "unexpectedPaths",
184
+ "requireCleanWorktree",
185
+ "requireDependencies",
186
+ ]);
187
+ if (config.policies?.unexpectedPaths !== "error" &&
188
+ config.policies?.unexpectedPaths !== "warn" &&
189
+ config.policies?.unexpectedPaths !== "allow") {
190
+ throw new BrokerError("INVALID_CONFIG", "policies.unexpectedPaths must be error, warn, or allow.");
191
+ }
192
+ assertBoolean(config.policies?.requireCleanWorktree, "policies.requireCleanWorktree");
193
+ assertBoolean(config.policies?.requireDependencies, "policies.requireDependencies");
194
+ assertAllowedKeys(config.scheduling, "scheduling", [
195
+ "maxTasks",
196
+ "maxCommits",
197
+ "maxWaitSeconds",
198
+ "allowPathOverlap",
199
+ ]);
200
+ assertPositiveInteger(config.scheduling?.maxTasks, "scheduling.maxTasks");
201
+ assertPositiveInteger(config.scheduling?.maxCommits, "scheduling.maxCommits");
202
+ assertPositiveInteger(config.scheduling?.maxWaitSeconds, "scheduling.maxWaitSeconds");
203
+ assertBoolean(config.scheduling?.allowPathOverlap, "scheduling.allowPathOverlap");
204
+ assertAllowedKeys(config.integration, "integration", [
205
+ "branchPrefix",
206
+ "history",
207
+ "keepFailedWorktrees",
208
+ "refreshBase",
209
+ "maxAttempts",
210
+ "provenance",
211
+ ]);
212
+ assertString(config.integration?.branchPrefix, "integration.branchPrefix");
213
+ assertSafeGitName(config.integration.branchPrefix, "integration.branchPrefix", true);
214
+ if (!["preserve", "squash"].includes(config.integration?.history)) {
215
+ throw new BrokerError("INVALID_CONFIG", "integration.history must be preserve or squash.");
216
+ }
217
+ assertBoolean(config.integration?.keepFailedWorktrees, "integration.keepFailedWorktrees");
218
+ config.integration.refreshBase ??= true;
219
+ config.integration.maxAttempts ??= 3;
220
+ assertBoolean(config.integration.refreshBase, "integration.refreshBase");
221
+ assertPositiveInteger(config.integration.maxAttempts, "integration.maxAttempts");
222
+ if (config.integration.provenance !== undefined) {
223
+ assertAllowedKeys(config.integration.provenance, "integration.provenance", ["enabled", "directory"]);
224
+ assertBoolean(config.integration.provenance.enabled, "integration.provenance.enabled");
225
+ assertString(config.integration.provenance.directory, "integration.provenance.directory");
226
+ const directory = config.integration.provenance.directory.replaceAll("\\", "/");
227
+ if (path.isAbsolute(directory) ||
228
+ directory === "." ||
229
+ directory.split("/").some((part) => part === ".." || part === ".git")) {
230
+ throw new BrokerError("INVALID_CONFIG", "integration.provenance.directory must be a safe repository-relative directory.");
231
+ }
232
+ }
233
+ assertAllowedKeys(config.validation, "validation", ["shell", "focused", "authoritative"]);
234
+ if (!Array.isArray(config.validation.focused) || !Array.isArray(config.validation.authoritative)) {
235
+ throw new BrokerError("INVALID_CONFIG", "validation.focused and validation.authoritative must be arrays.");
236
+ }
237
+ if (config.validation.shell !== undefined)
238
+ assertString(config.validation.shell, "validation.shell");
239
+ assertAllowedKeys(config.publish, "publish", [
240
+ "mode",
241
+ "draft",
242
+ "autoMerge",
243
+ "mergeMethod",
244
+ "labels",
245
+ "titleTemplate",
246
+ ]);
247
+ if (!["none", "branch", "pull-request"].includes(config.publish?.mode)) {
248
+ throw new BrokerError("INVALID_CONFIG", "publish.mode must be none, branch, or pull-request.");
249
+ }
250
+ assertBoolean(config.publish?.draft, "publish.draft");
251
+ // Absent on configurations written before auto-merge existed. Defaulting to false keeps an
252
+ // upgrade from silently starting to land agent work on the base branch.
253
+ config.publish.autoMerge ??= false;
254
+ config.publish.mergeMethod ??= "squash";
255
+ assertBoolean(config.publish.autoMerge, "publish.autoMerge");
256
+ if (!["squash", "merge", "rebase"].includes(config.publish.mergeMethod)) {
257
+ throw new BrokerError("INVALID_CONFIG", "publish.mergeMethod must be squash, merge, or rebase.");
258
+ }
259
+ if (config.publish.autoMerge && config.publish.draft) {
260
+ throw new BrokerError("INVALID_CONFIG", "publish.autoMerge cannot be combined with publish.draft: GitHub refuses to merge a draft pull request.");
261
+ }
262
+ // "none" is the generated default and simply means publishing is not enabled yet, so auto-merge
263
+ // is allowed to sit there as declared intent. "branch" mode has no pull request to merge.
264
+ if (config.publish.autoMerge && config.publish.mode === "branch") {
265
+ throw new BrokerError("INVALID_CONFIG", "publish.autoMerge has no effect in branch mode: set publish.mode to pull-request.");
266
+ }
267
+ assertStringArray(config.publish?.labels, "publish.labels");
268
+ assertString(config.publish?.titleTemplate, "publish.titleTemplate");
269
+ for (const [scope, validators] of Object.entries(config.validation ?? {})) {
270
+ if (scope === "shell")
271
+ continue;
272
+ if (!Array.isArray(validators)) {
273
+ throw new BrokerError("INVALID_CONFIG", `validation.${scope} must be an array.`);
274
+ }
275
+ for (const validator of validators) {
276
+ assertAllowedKeys(validator, `validation.${scope}[]`, ["name", "command", "paths", "timeoutSeconds", "env"]);
277
+ assertString(validator.name, `validation.${scope}.name`);
278
+ assertString(validator.command, `validation.${scope}.command`);
279
+ if (validator.paths !== undefined)
280
+ assertStringArray(validator.paths, `validation.${scope}.paths`);
281
+ if (validator.timeoutSeconds !== undefined) {
282
+ assertPositiveInteger(validator.timeoutSeconds, `validation.${scope}.timeoutSeconds`);
283
+ }
284
+ if (validator.env !== undefined &&
285
+ (typeof validator.env !== "object" ||
286
+ validator.env === null ||
287
+ Object.values(validator.env).some((item) => typeof item !== "string"))) {
288
+ throw new BrokerError("INVALID_CONFIG", `validation.${scope}.env must contain only string values.`);
289
+ }
290
+ }
291
+ }
292
+ return config;
293
+ }
294
+ export async function loadConfig(repoRoot) {
295
+ const target = configPath(repoRoot);
296
+ let source;
297
+ try {
298
+ source = await readFile(target, "utf8");
299
+ }
300
+ catch (error) {
301
+ throw new BrokerError("NOT_INITIALIZED", `Merge Broker is not initialized. Run \"merge-broker init\" in ${repoRoot}.`, { cause: error instanceof Error ? error.message : String(error) });
302
+ }
303
+ try {
304
+ return validateConfig(JSON.parse(source));
305
+ }
306
+ catch (error) {
307
+ if (error instanceof BrokerError)
308
+ throw error;
309
+ throw new BrokerError("INVALID_CONFIG", `Could not parse ${target}: ${String(error)}`);
310
+ }
311
+ }
312
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ export declare class BrokerError extends Error {
2
+ readonly code: string;
3
+ readonly details: Record<string, unknown> | undefined;
4
+ constructor(code: string, message: string, details?: Record<string, unknown>);
5
+ }
6
+ export declare class CommandError extends BrokerError {
7
+ readonly command: string;
8
+ readonly exitCode: number;
9
+ readonly stdout: string;
10
+ readonly stderr: string;
11
+ constructor(command: string, exitCode: number, stdout: string, stderr: string);
12
+ }
13
+ export declare class ValidationError extends BrokerError {
14
+ constructor(message: string, details?: Record<string, unknown>);
15
+ }
16
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,WAAY,SAAQ,KAAK;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;gBAE1C,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAM7E;AAED,qBAAa,YAAa,SAAQ,WAAW;IAC3C,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAa9E;AAED,qBAAa,eAAgB,SAAQ,WAAW;gBAClC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;CAI/D"}
package/dist/errors.js ADDED
@@ -0,0 +1,36 @@
1
+ export class BrokerError extends Error {
2
+ code;
3
+ details;
4
+ constructor(code, message, details) {
5
+ super(message);
6
+ this.name = "BrokerError";
7
+ this.code = code;
8
+ this.details = details;
9
+ }
10
+ }
11
+ export class CommandError extends BrokerError {
12
+ command;
13
+ exitCode;
14
+ stdout;
15
+ stderr;
16
+ constructor(command, exitCode, stdout, stderr) {
17
+ super("COMMAND_FAILED", `Command failed (${exitCode}): ${command}`, {
18
+ command,
19
+ exitCode,
20
+ stdout,
21
+ stderr,
22
+ });
23
+ this.name = "CommandError";
24
+ this.command = command;
25
+ this.exitCode = exitCode;
26
+ this.stdout = stdout;
27
+ this.stderr = stderr;
28
+ }
29
+ }
30
+ export class ValidationError extends BrokerError {
31
+ constructor(message, details) {
32
+ super("VALIDATION_FAILED", message, details);
33
+ this.name = "ValidationError";
34
+ }
35
+ }
36
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,WAAY,SAAQ,KAAK;IAC3B,IAAI,CAAS;IACb,OAAO,CAAsC;IAEtD,YAAY,IAAY,EAAE,OAAe,EAAE,OAAiC;QAC1E,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;QAC1B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;CACF;AAED,MAAM,OAAO,YAAa,SAAQ,WAAW;IAClC,OAAO,CAAS;IAChB,QAAQ,CAAS;IACjB,MAAM,CAAS;IACf,MAAM,CAAS;IAExB,YAAY,OAAe,EAAE,QAAgB,EAAE,MAAc,EAAE,MAAc;QAC3E,KAAK,CAAC,gBAAgB,EAAE,mBAAmB,QAAQ,MAAM,OAAO,EAAE,EAAE;YAClE,OAAO;YACP,QAAQ;YACR,MAAM;YACN,MAAM;SACP,CAAC,CAAC;QACH,IAAI,CAAC,IAAI,GAAG,cAAc,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,MAAM,OAAO,eAAgB,SAAQ,WAAW;IAC9C,YAAY,OAAe,EAAE,OAAiC;QAC5D,KAAK,CAAC,mBAAmB,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;QAC7C,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;IAChC,CAAC;CACF"}
package/dist/git.d.ts ADDED
@@ -0,0 +1,46 @@
1
+ import { type CommandResult } from "./process.js";
2
+ export interface WorktreeInfo {
3
+ path: string;
4
+ head: string;
5
+ branch?: string;
6
+ bare: boolean;
7
+ detached: boolean;
8
+ prunable: boolean;
9
+ }
10
+ export declare class GitRepository {
11
+ readonly root: string;
12
+ readonly commonGitDir: string;
13
+ private constructor();
14
+ static discover(cwd?: string): Promise<GitRepository>;
15
+ git(args: string[], cwd?: string, allowFailure?: boolean): Promise<CommandResult>;
16
+ resolveCommit(revision: string): Promise<string>;
17
+ currentHead(cwd?: string): Promise<string>;
18
+ resolveCommitAt(revision: string, cwd: string): Promise<string>;
19
+ changedFiles(commit: string): Promise<string[]>;
20
+ changedFilesForCommits(commits: string[]): Promise<string[]>;
21
+ changedFilesBetween(base: string, head: string): Promise<string[]>;
22
+ /**
23
+ * Linear commits on HEAD after `base`, oldest first. `git cherry` compares patch identities, so a
24
+ * change already contained in the base under a different SHA -- the ordinary result of a rebase --
25
+ * is not submitted a second time.
26
+ */
27
+ commitsSinceBase(cwd: string, base: string): Promise<string[]>;
28
+ parentCount(commit: string): Promise<number>;
29
+ isClean(cwd?: string): Promise<boolean>;
30
+ addDetachedWorktree(destination: string, startPoint: string): Promise<void>;
31
+ removeWorktree(destination: string): Promise<void>;
32
+ cherryPick(cwd: string, commit: string): Promise<CommandResult>;
33
+ abortCherryPick(cwd: string): Promise<void>;
34
+ createBranch(name: string, commit: string): Promise<void>;
35
+ deleteBranch(name: string): Promise<void>;
36
+ squash(cwd: string, baseSha: string, message: string): Promise<string>;
37
+ /**
38
+ * Best-effort refresh of the remote-tracking base. Integration must still work in a repository
39
+ * with no remote or no network, so a failed fetch is reported rather than thrown.
40
+ */
41
+ fetchBranch(remote: string, branch: string): Promise<boolean>;
42
+ commitGeneratedFile(cwd: string, relativePath: string, contents: string, message: string): Promise<string>;
43
+ push(remote: string, branch: string): Promise<void>;
44
+ listWorktrees(): Promise<WorktreeInfo[]>;
45
+ }
46
+ //# sourceMappingURL=git.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAE9D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAMD,qBAAa,aAAa;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAE9B,OAAO;WAKM,QAAQ,CAAC,GAAG,SAAgB,GAAG,OAAO,CAAC,aAAa,CAAC;IAS5D,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,SAAY,EAAE,YAAY,UAAQ,GAAG,OAAO,CAAC,aAAa,CAAC;IAIlF,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAehD,WAAW,CAAC,GAAG,SAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAI7C,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAY/D,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAO/C,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAQ5D,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAUxE;;;;OAIG;IACG,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAe9D,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAK5C,OAAO,CAAC,GAAG,SAAY,GAAG,OAAO,CAAC,OAAO,CAAC;IAK1C,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3E,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUlD,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAI/D,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzD,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIzC,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAM5E;;;OAGG;IACG,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK7D,mBAAmB,CACvB,GAAG,EAAE,MAAM,EACX,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,MAAM,CAAC;IAaZ,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOnD,aAAa,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;CAoC/C"}
package/dist/git.js ADDED
@@ -0,0 +1,195 @@
1
+ import path from "node:path";
2
+ import { mkdir, writeFile } from "node:fs/promises";
3
+ import { BrokerError } from "./errors.js";
4
+ import { runCommand } from "./process.js";
5
+ function splitNull(value) {
6
+ return value.split("\0").map((part) => part.trim()).filter(Boolean);
7
+ }
8
+ export class GitRepository {
9
+ root;
10
+ commonGitDir;
11
+ constructor(root, commonGitDir) {
12
+ this.root = root;
13
+ this.commonGitDir = commonGitDir;
14
+ }
15
+ static async discover(cwd = process.cwd()) {
16
+ const top = await runCommand("git", ["rev-parse", "--show-toplevel"], { cwd });
17
+ const root = path.resolve(top.stdout.trim());
18
+ const common = await runCommand("git", ["rev-parse", "--path-format=absolute", "--git-common-dir"], {
19
+ cwd: root,
20
+ });
21
+ return new GitRepository(root, path.resolve(common.stdout.trim()));
22
+ }
23
+ async git(args, cwd = this.root, allowFailure = false) {
24
+ return await runCommand("git", args, { cwd, allowFailure });
25
+ }
26
+ async resolveCommit(revision) {
27
+ const result = await this.git(["rev-parse", "--verify", "--end-of-options", `${revision}^{commit}`], this.root, true);
28
+ if (result.exitCode !== 0) {
29
+ throw new BrokerError("UNKNOWN_COMMIT", `Git revision is not a commit: ${revision}`, {
30
+ revision,
31
+ stderr: result.stderr,
32
+ });
33
+ }
34
+ return result.stdout.trim();
35
+ }
36
+ async currentHead(cwd = this.root) {
37
+ return await this.resolveCommitAt("HEAD", cwd);
38
+ }
39
+ async resolveCommitAt(revision, cwd) {
40
+ const result = await this.git(["rev-parse", "--verify", "--end-of-options", `${revision}^{commit}`], cwd, true);
41
+ if (result.exitCode !== 0) {
42
+ throw new BrokerError("UNKNOWN_COMMIT", `Git revision is not a commit: ${revision}`, {
43
+ revision,
44
+ cwd,
45
+ stderr: result.stderr,
46
+ });
47
+ }
48
+ return result.stdout.trim();
49
+ }
50
+ async changedFiles(commit) {
51
+ const result = await this.git(["diff-tree", "--root", "--no-commit-id", "--name-only", "-r", "-z", commit]);
52
+ return [...new Set(splitNull(result.stdout))].sort();
53
+ }
54
+ async changedFilesForCommits(commits) {
55
+ const files = new Set();
56
+ for (const commit of commits) {
57
+ for (const file of await this.changedFiles(commit))
58
+ files.add(file);
59
+ }
60
+ return [...files].sort();
61
+ }
62
+ async changedFilesBetween(base, head) {
63
+ const result = await this.git([
64
+ "diff",
65
+ "--name-only",
66
+ "-z",
67
+ `${base}..${head}`,
68
+ ]);
69
+ return [...new Set(splitNull(result.stdout))].sort();
70
+ }
71
+ /**
72
+ * Linear commits on HEAD after `base`, oldest first. `git cherry` compares patch identities, so a
73
+ * change already contained in the base under a different SHA -- the ordinary result of a rebase --
74
+ * is not submitted a second time.
75
+ */
76
+ async commitsSinceBase(cwd, base) {
77
+ const cherry = await this.git(["cherry", base, "HEAD"], cwd);
78
+ const notUpstream = new Set(cherry.stdout
79
+ .split("\n")
80
+ .filter((line) => line.startsWith("+ "))
81
+ .map((line) => line.slice(2).trim()));
82
+ const listed = await this.git(["rev-list", "--reverse", "--no-merges", `${base}..HEAD`], cwd);
83
+ return listed.stdout
84
+ .split("\n")
85
+ .map((line) => line.trim())
86
+ .filter((commit) => commit !== "" && notUpstream.has(commit));
87
+ }
88
+ async parentCount(commit) {
89
+ const result = await this.git(["rev-list", "--parents", "-n", "1", commit]);
90
+ return Math.max(0, result.stdout.trim().split(/\s+/u).length - 1);
91
+ }
92
+ async isClean(cwd = this.root) {
93
+ const result = await this.git(["status", "--porcelain=v1", "-z"], cwd);
94
+ return result.stdout.length === 0;
95
+ }
96
+ async addDetachedWorktree(destination, startPoint) {
97
+ await mkdir(path.dirname(destination), { recursive: true });
98
+ await this.git(["worktree", "add", "--detach", destination, startPoint]);
99
+ }
100
+ async removeWorktree(destination) {
101
+ const result = await this.git(["worktree", "remove", "--force", destination], this.root, true);
102
+ if (result.exitCode !== 0) {
103
+ await this.git(["worktree", "prune"], this.root, true);
104
+ throw new BrokerError("WORKTREE_REMOVE_FAILED", `Could not remove integration worktree: ${destination}`, {
105
+ stderr: result.stderr,
106
+ });
107
+ }
108
+ }
109
+ async cherryPick(cwd, commit) {
110
+ return await this.git(["cherry-pick", "-x", commit], cwd, true);
111
+ }
112
+ async abortCherryPick(cwd) {
113
+ await this.git(["cherry-pick", "--abort"], cwd, true);
114
+ }
115
+ async createBranch(name, commit) {
116
+ const exists = await this.git(["show-ref", "--verify", "--quiet", `refs/heads/${name}`], this.root, true);
117
+ if (exists.exitCode === 0) {
118
+ throw new BrokerError("BRANCH_EXISTS", `Integration branch already exists: ${name}`);
119
+ }
120
+ await this.git(["branch", "--", name, commit]);
121
+ }
122
+ async deleteBranch(name) {
123
+ await this.git(["branch", "-D", "--", name], this.root, true);
124
+ }
125
+ async squash(cwd, baseSha, message) {
126
+ await this.git(["reset", "--soft", baseSha], cwd);
127
+ await this.git(["commit", "-m", message], cwd);
128
+ return await this.currentHead(cwd);
129
+ }
130
+ /**
131
+ * Best-effort refresh of the remote-tracking base. Integration must still work in a repository
132
+ * with no remote or no network, so a failed fetch is reported rather than thrown.
133
+ */
134
+ async fetchBranch(remote, branch) {
135
+ const result = await this.git(["fetch", "--quiet", "--", remote, branch], this.root, true);
136
+ return result.exitCode === 0;
137
+ }
138
+ async commitGeneratedFile(cwd, relativePath, contents, message) {
139
+ const target = path.resolve(cwd, relativePath);
140
+ const relative = path.relative(cwd, target);
141
+ if (relative.startsWith("..") || path.isAbsolute(relative)) {
142
+ throw new BrokerError("UNSAFE_PATH", `Generated file escapes the integration worktree: ${relativePath}`);
143
+ }
144
+ await mkdir(path.dirname(target), { recursive: true });
145
+ await writeFile(target, contents, "utf8");
146
+ await this.git(["add", "--", relativePath], cwd);
147
+ await this.git(["commit", "-m", message], cwd);
148
+ return await this.currentHead(cwd);
149
+ }
150
+ async push(remote, branch) {
151
+ await this.git(["push", "--set-upstream", "--", remote, `refs/heads/${branch}:refs/heads/${branch}`], this.root);
152
+ }
153
+ async listWorktrees() {
154
+ const result = await this.git(["worktree", "list", "--porcelain"]);
155
+ const records = [];
156
+ let current = {};
157
+ const flush = () => {
158
+ if (current.path && current.head) {
159
+ records.push({
160
+ path: current.path,
161
+ head: current.head,
162
+ ...(current.branch ? { branch: current.branch } : {}),
163
+ bare: current.bare ?? false,
164
+ detached: current.detached ?? false,
165
+ prunable: current.prunable ?? false,
166
+ });
167
+ }
168
+ current = {};
169
+ };
170
+ for (const line of result.stdout.split("\n")) {
171
+ if (!line) {
172
+ flush();
173
+ continue;
174
+ }
175
+ const separator = line.indexOf(" ");
176
+ const key = separator === -1 ? line : line.slice(0, separator);
177
+ const value = separator === -1 ? "" : line.slice(separator + 1);
178
+ if (key === "worktree")
179
+ current.path = value;
180
+ else if (key === "HEAD")
181
+ current.head = value;
182
+ else if (key === "branch")
183
+ current.branch = value.replace(/^refs\/heads\//u, "");
184
+ else if (key === "bare")
185
+ current.bare = true;
186
+ else if (key === "detached")
187
+ current.detached = true;
188
+ else if (key === "prunable")
189
+ current.prunable = true;
190
+ }
191
+ flush();
192
+ return records;
193
+ }
194
+ }
195
+ //# sourceMappingURL=git.js.map