swarm-orchestrator 7.0.0-alpha.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 (174) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +199 -0
  3. package/agents/reviewer.agent.md +50 -0
  4. package/agents/worker.agent.md +41 -0
  5. package/config/default-agents.yaml +56 -0
  6. package/config/pm-agent.yaml +36 -0
  7. package/config/quality-gates.yaml +88 -0
  8. package/config/repair-agent.yaml +34 -0
  9. package/config/semgrep-rules/complexity-mismatch.yaml +6 -0
  10. package/config/semgrep-rules/exception-swallowing.yaml +13 -0
  11. package/config/semgrep-rules/hardcoded-answer.yaml +6 -0
  12. package/config/semgrep-rules/mock-mutation.yaml +6 -0
  13. package/config/semgrep-rules/test-modification.yaml +6 -0
  14. package/config/user-agents.yaml +23 -0
  15. package/dist/src/adapters/adapter-factory.js +29 -0
  16. package/dist/src/adapters/agent-adapter.js +32 -0
  17. package/dist/src/adapters/claude-code-adapter.js +126 -0
  18. package/dist/src/adapters/claude-code-teams.js +119 -0
  19. package/dist/src/adapters/codex-adapter.js +118 -0
  20. package/dist/src/adapters/copilot-adapter.js +224 -0
  21. package/dist/src/adapters/fatal-error-classifier.js +88 -0
  22. package/dist/src/adapters/index.js +44 -0
  23. package/dist/src/adapters/persistent-session.js +204 -0
  24. package/dist/src/adapters/process-supervisor.js +199 -0
  25. package/dist/src/agents-exporter.js +398 -0
  26. package/dist/src/analytics-log.js +161 -0
  27. package/dist/src/baseline-scanner.js +65 -0
  28. package/dist/src/bootstrap-evidence.js +88 -0
  29. package/dist/src/bootstrap-orchestrator.js +205 -0
  30. package/dist/src/bootstrap-types.js +5 -0
  31. package/dist/src/branch-merger.js +427 -0
  32. package/dist/src/cli/attest-handlers.js +44 -0
  33. package/dist/src/cli/cost-prompt.js +51 -0
  34. package/dist/src/cli/demo-handlers.js +274 -0
  35. package/dist/src/cli/flags.js +152 -0
  36. package/dist/src/cli/index.js +57 -0
  37. package/dist/src/cli/live-status.js +186 -0
  38. package/dist/src/cli/misc-handlers.js +242 -0
  39. package/dist/src/cli/plan-handlers.js +350 -0
  40. package/dist/src/cli/share-handlers.js +163 -0
  41. package/dist/src/cli/status-handlers.js +457 -0
  42. package/dist/src/cli/swarm-handlers.js +638 -0
  43. package/dist/src/cli/usage.js +72 -0
  44. package/dist/src/cli.js +217 -0
  45. package/dist/src/commit-pattern-detector.js +143 -0
  46. package/dist/src/commit-quality-analyzer.js +38 -0
  47. package/dist/src/config-loader.js +339 -0
  48. package/dist/src/context-broker.js +358 -0
  49. package/dist/src/copilot-cli-wrapper.js +258 -0
  50. package/dist/src/cost-estimator.js +241 -0
  51. package/dist/src/defaults.js +18 -0
  52. package/dist/src/demo-mode.js +180 -0
  53. package/dist/src/deployment-handler.js +78 -0
  54. package/dist/src/deployment-manager.js +228 -0
  55. package/dist/src/execution-queue.js +196 -0
  56. package/dist/src/external-tool-manager.js +184 -0
  57. package/dist/src/gate-prompt-builder.js +117 -0
  58. package/dist/src/gate-remediation.js +173 -0
  59. package/dist/src/github-issues-ingester.js +152 -0
  60. package/dist/src/github-mcp-integrator.js +164 -0
  61. package/dist/src/hook-generator.js +229 -0
  62. package/dist/src/index.js +48 -0
  63. package/dist/src/knowledge-base.js +300 -0
  64. package/dist/src/logger.js +111 -0
  65. package/dist/src/meta-analyzer.js +208 -0
  66. package/dist/src/metrics-collector.js +209 -0
  67. package/dist/src/metrics-types.js +5 -0
  68. package/dist/src/multi-repo-coordinator.js +179 -0
  69. package/dist/src/orchestrator/async-meta-analysis.js +84 -0
  70. package/dist/src/orchestrator/fatal-run-error.js +43 -0
  71. package/dist/src/orchestrator/final-gates-remediation.js +258 -0
  72. package/dist/src/orchestrator/git-state-utils.js +119 -0
  73. package/dist/src/orchestrator/pause-controller.js +55 -0
  74. package/dist/src/orchestrator/replan-runner.js +258 -0
  75. package/dist/src/orchestrator/step-executor.js +391 -0
  76. package/dist/src/orchestrator/wave-scheduler-loop.js +204 -0
  77. package/dist/src/owasp-mapper.js +153 -0
  78. package/dist/src/owasp-report-renderer.js +39 -0
  79. package/dist/src/plan-files.js +142 -0
  80. package/dist/src/plan-generator.js +1207 -0
  81. package/dist/src/pm-agent.js +296 -0
  82. package/dist/src/post-run-reporter.js +203 -0
  83. package/dist/src/pr-automation.js +103 -0
  84. package/dist/src/pr-manager.js +318 -0
  85. package/dist/src/presenter/index.js +209 -0
  86. package/dist/src/prompt-builder.js +173 -0
  87. package/dist/src/quality-gates/config-loader.js +196 -0
  88. package/dist/src/quality-gates/default-config.js +243 -0
  89. package/dist/src/quality-gates/file-utils.js +152 -0
  90. package/dist/src/quality-gates/gate-runner.js +171 -0
  91. package/dist/src/quality-gates/gates/accessibility.js +355 -0
  92. package/dist/src/quality-gates/gates/duplicate-blocks.js +144 -0
  93. package/dist/src/quality-gates/gates/hardcoded-config.js +52 -0
  94. package/dist/src/quality-gates/gates/readme-claims.js +62 -0
  95. package/dist/src/quality-gates/gates/runtime-checks.js +265 -0
  96. package/dist/src/quality-gates/gates/scaffold-defaults.js +108 -0
  97. package/dist/src/quality-gates/gates/test-coverage.js +240 -0
  98. package/dist/src/quality-gates/gates/test-file-protection.js +85 -0
  99. package/dist/src/quality-gates/gates/test-isolation.js +74 -0
  100. package/dist/src/quality-gates/index.js +17 -0
  101. package/dist/src/quality-gates/registry.js +205 -0
  102. package/dist/src/quality-gates/types.js +2 -0
  103. package/dist/src/quick-fix-mode.js +302 -0
  104. package/dist/src/recipe-loader.js +122 -0
  105. package/dist/src/repair-agent.js +396 -0
  106. package/dist/src/repo-analyzer.js +342 -0
  107. package/dist/src/report-generator.js +146 -0
  108. package/dist/src/report-renderer.js +90 -0
  109. package/dist/src/requirement-filter.js +52 -0
  110. package/dist/src/sarif-formatter.js +140 -0
  111. package/dist/src/scheduling/dependency-analyzer.js +178 -0
  112. package/dist/src/scheduling/work-stealing-queue.js +123 -0
  113. package/dist/src/secret-redactor.js +90 -0
  114. package/dist/src/session-executor.js +587 -0
  115. package/dist/src/session-manager.js +221 -0
  116. package/dist/src/share/transcript-verification.js +128 -0
  117. package/dist/src/share-parser.js +477 -0
  118. package/dist/src/spinner.js +146 -0
  119. package/dist/src/step-runner.js +365 -0
  120. package/dist/src/swarm-orchestrator.js +686 -0
  121. package/dist/src/task-classifier.js +134 -0
  122. package/dist/src/test-command-discovery.js +123 -0
  123. package/dist/src/text-similarity.js +24 -0
  124. package/dist/src/tier-maps.js +158 -0
  125. package/dist/src/types.js +5 -0
  126. package/dist/src/url-shortener.js +135 -0
  127. package/dist/src/verification/attestation.js +166 -0
  128. package/dist/src/verification/cheat-detector.js +240 -0
  129. package/dist/src/verification/command-runner.js +70 -0
  130. package/dist/src/verification/composite-score.js +157 -0
  131. package/dist/src/verification/cosign-attestation.js +137 -0
  132. package/dist/src/verification/diff-analysis.js +89 -0
  133. package/dist/src/verification/differential-gate.js +173 -0
  134. package/dist/src/verification/index.js +41 -0
  135. package/dist/src/verification/mutation-gate.js +242 -0
  136. package/dist/src/verification/property-gate.js +201 -0
  137. package/dist/src/verification/test-synthesizer.js +243 -0
  138. package/dist/src/verifier/outcome-checks.js +396 -0
  139. package/dist/src/verifier/transcript-checks.js +207 -0
  140. package/dist/src/verifier/verification-reporters.js +148 -0
  141. package/dist/src/verifier-engine.js +491 -0
  142. package/dist/src/wave-resizer.js +131 -0
  143. package/dist/src/wave-scheduler.js +44 -0
  144. package/dist/src/worktree-manager.js +368 -0
  145. package/dist/src/worktree-reserved-paths.js +97 -0
  146. package/package.json +80 -0
  147. package/plugin/agents/.gitkeep +0 -0
  148. package/plugin/agents/backend_master.agent.md +72 -0
  149. package/plugin/agents/devops_pro.agent.md +45 -0
  150. package/plugin/agents/frontend_expert.agent.md +59 -0
  151. package/plugin/agents/integrator_finalizer.agent.md +44 -0
  152. package/plugin/agents/meta_reviewer.agent.md +44 -0
  153. package/plugin/agents/security_auditor.agent.md +43 -0
  154. package/plugin/agents/tester_elite.agent.md +43 -0
  155. package/plugin/hooks/hooks.json +19 -0
  156. package/plugin/hooks/post-tool-use.json +9 -0
  157. package/plugin/hooks/pre-tool-use.json +9 -0
  158. package/plugin/plugin.json +47 -0
  159. package/plugin/skills/swarm-gates/SKILL.md +53 -0
  160. package/plugin/skills/swarm-orchestrate/SKILL.md +34 -0
  161. package/plugin/skills/swarm-verify/SKILL.md +44 -0
  162. package/templates/README.md +35 -0
  163. package/templates/cli-tool.json +31 -0
  164. package/templates/fullstack.json +52 -0
  165. package/templates/library.json +38 -0
  166. package/templates/react-app.json +45 -0
  167. package/templates/recipes/add-api-docs.json +35 -0
  168. package/templates/recipes/add-auth.json +47 -0
  169. package/templates/recipes/add-ci.json +39 -0
  170. package/templates/recipes/add-tests.json +39 -0
  171. package/templates/recipes/migrate-to-ts.json +42 -0
  172. package/templates/recipes/refactor-modularize.json +44 -0
  173. package/templates/recipes/security-audit.json +35 -0
  174. package/templates/rest-api.json +38 -0
@@ -0,0 +1,427 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.BranchMerger = void 0;
37
+ const child_process_1 = require("child_process");
38
+ const fs = __importStar(require("fs"));
39
+ const path = __importStar(require("path"));
40
+ const spinner_1 = require("./spinner");
41
+ const logger_1 = require("./logger");
42
+ const logger = (0, logger_1.getLogger)('branch-merger');
43
+ /**
44
+ * Render a long swarm branch name as `step-N agent` so log lines stay readable.
45
+ * The full ref `swarm/<execId>/step-N-<agent>` is unwieldy; the user already
46
+ * knows which run they triggered, so the per-step segment is the meaningful
47
+ * part. Falls back to the raw name when the convention does not match.
48
+ */
49
+ function shortBranchLabel(branchName) {
50
+ const m = branchName.match(/\/step-(\d+)-(.+?)$/);
51
+ return m ? `step-${m[1]} ${m[2]}` : branchName;
52
+ }
53
+ /**
54
+ * Handles all git branch merging: wave merges, final merges, and conflict
55
+ * resolution strategies. Extracted from SwarmOrchestrator for cohesion.
56
+ */
57
+ class BranchMerger {
58
+ workingDir;
59
+ worktreeManager;
60
+ constructor(workingDir, worktreeManager) {
61
+ this.workingDir = workingDir;
62
+ this.worktreeManager = worktreeManager;
63
+ }
64
+ /**
65
+ * Clear residual unmerged index entries left by failed merges or stash pops.
66
+ * Aborts any in-progress merge, resets the index, and restores tracked files.
67
+ * Safe to call when the index is already clean.
68
+ */
69
+ resetUnmergedState() {
70
+ const opts = { cwd: this.workingDir, stdio: 'pipe', encoding: 'utf8' };
71
+ try {
72
+ (0, child_process_1.execSync)('git merge --abort', opts);
73
+ }
74
+ catch { /* no merge in progress */ }
75
+ try {
76
+ const status = (0, child_process_1.execSync)('git status --porcelain', opts).trim();
77
+ const hasConflicts = status.split('\n').some(line => /^(U.|.U|AA|DD)/.test(line));
78
+ if (hasConflicts) {
79
+ (0, child_process_1.execSync)('git reset HEAD', opts);
80
+ (0, child_process_1.execSync)('git checkout -- .', opts);
81
+ }
82
+ }
83
+ catch { /* not critical */ }
84
+ }
85
+ /**
86
+ * Merge completed wave branches back to main, with PR or direct merge.
87
+ * Records unmerged branches and returns them for caller tracking.
88
+ */
89
+ async mergeWaveBranches(completedResults, context, prMode, prUrls, stepCostRecords, plan) {
90
+ const unmerged = [];
91
+ const branches = completedResults
92
+ .filter(r => r.branchName)
93
+ .map(r => r.branchName);
94
+ if (branches.length === 0)
95
+ return unmerged;
96
+ if (context.prManager) {
97
+ for (const result of completedResults) {
98
+ if (!result.branchName)
99
+ continue;
100
+ const step = plan?.steps.find(s => s.stepNumber === result.stepNumber);
101
+ const taskDesc = step?.task || `Step ${result.stepNumber}`;
102
+ const costRecord = stepCostRecords?.find(r => r.stepNumber === result.stepNumber);
103
+ const prResult = context.prManager.createStepPR(result.branchName, context.mainBranch, result.stepNumber, result.agentName, taskDesc, { verification: result.verificationResult, costRecord });
104
+ if (prResult.success && prResult.url) {
105
+ prUrls?.set(result.stepNumber, prResult.url);
106
+ // PR URL goes into the final-summary footer; this debug line is the
107
+ // forensic record of when each PR was created.
108
+ logger.debug(`pr step-${result.stepNumber} ${prResult.url}`);
109
+ if (prMode === 'auto' && prResult.number) {
110
+ const merged = context.prManager.autoMergePR(prResult.number);
111
+ if (merged) {
112
+ logger.debug(`merged pr #${prResult.number}`);
113
+ }
114
+ else {
115
+ logger.warn(`auto-merge failed for pr #${prResult.number}; manual merge required`);
116
+ }
117
+ }
118
+ else if (prMode === 'review' && prResult.number) {
119
+ logger.info(`waiting on review for pr #${prResult.number}...`);
120
+ const status = await context.prManager.waitForApproval(prResult.number);
121
+ if (status.approved || status.state === 'MERGED') {
122
+ logger.debug(`approved pr #${prResult.number}`);
123
+ if (status.state !== 'MERGED') {
124
+ context.prManager.autoMergePR(prResult.number);
125
+ }
126
+ }
127
+ else {
128
+ logger.warn(`pr #${prResult.number} review timed out or was not approved`);
129
+ }
130
+ }
131
+ }
132
+ else {
133
+ logger.warn(`pr creation failed for ${shortBranchLabel(result.branchName)}: ${prResult.error}`);
134
+ try {
135
+ await this.mergeBranch(result.branchName, context);
136
+ logger.debug(`merged ${shortBranchLabel(result.branchName)} (fallback)`);
137
+ }
138
+ catch (error) {
139
+ const err = error;
140
+ logger.warn(`merge conflict on ${shortBranchLabel(result.branchName)}: ${err.message}`);
141
+ }
142
+ }
143
+ }
144
+ return unmerged;
145
+ }
146
+ try {
147
+ this.resetUnmergedState();
148
+ await this.worktreeManager.switchBranch(context.mainBranch);
149
+ // Stash all changes (including untracked files like .copilot-instructions.md)
150
+ // so they don't block incoming merges that introduce files with the same names.
151
+ let stashed = false;
152
+ try {
153
+ const stashResult = (0, child_process_1.execSync)('git stash push --include-untracked -m "pre-wave-merge stash"', {
154
+ cwd: this.workingDir, encoding: 'utf8', stdio: 'pipe'
155
+ });
156
+ stashed = !stashResult.includes('No local changes');
157
+ }
158
+ catch {
159
+ // Clean working tree; expected
160
+ }
161
+ for (const result of completedResults) {
162
+ if (result.branchName) {
163
+ const label = shortBranchLabel(result.branchName);
164
+ try {
165
+ await this.mergeBranch(result.branchName, context);
166
+ // Per-step merge confirmations are diagnostic; the final summary
167
+ // already reports completed/total. Keep them visible with --verbose.
168
+ logger.debug(`merged ${label}`);
169
+ }
170
+ catch (error) {
171
+ const err = error;
172
+ try {
173
+ (0, child_process_1.execSync)('git merge --abort', { cwd: this.workingDir, stdio: 'pipe' });
174
+ }
175
+ catch { /* no merge in progress */ }
176
+ logger.debug(`rebasing ${label} onto ${context.mainBranch}`);
177
+ const rebased = this.tryRebaseAndMerge(result.branchName, context);
178
+ if (rebased) {
179
+ logger.debug(`merged ${label} (rebased)`);
180
+ }
181
+ else {
182
+ logger.warn(` could not merge ${label} after rebase: ${err.message}`);
183
+ logger.warn(` step ${result.stepNumber} work preserved on ${result.branchName}`);
184
+ unmerged.push({
185
+ stepNumber: result.stepNumber,
186
+ branchName: result.branchName,
187
+ agentName: result.agentName,
188
+ reason: err.message,
189
+ });
190
+ }
191
+ }
192
+ }
193
+ }
194
+ if (stashed) {
195
+ try {
196
+ (0, child_process_1.execSync)('git stash pop', { cwd: this.workingDir, stdio: 'pipe' });
197
+ }
198
+ catch {
199
+ // Stash pop conflicted (common with binary .pyc files after merges).
200
+ // Reset the conflicted state and drop the stash; merged content takes priority.
201
+ this.resetUnmergedState();
202
+ try {
203
+ (0, child_process_1.execSync)('git stash drop', { cwd: this.workingDir, stdio: 'pipe' });
204
+ }
205
+ catch { /* already gone */ }
206
+ }
207
+ }
208
+ }
209
+ finally {
210
+ // switchBranch and mergeBranch pass cwd explicitly; no global state to restore
211
+ }
212
+ return unmerged;
213
+ }
214
+ /**
215
+ * Final merge phase: remove worktrees, merge all remaining branches to main,
216
+ * with stash/pop to preserve working directory state.
217
+ */
218
+ async mergeAllBranches(results, runDir, context) {
219
+ const unmerged = [];
220
+ // Remove all worktrees before branch operations
221
+ const worktreesDir = path.join(runDir, 'worktrees');
222
+ if (fs.existsSync(worktreesDir)) {
223
+ for (const result of results) {
224
+ if (result.branchName) {
225
+ const worktreePath = path.join(worktreesDir, `step-${result.stepNumber}`);
226
+ await this.worktreeManager.removeAgentWorktree(worktreePath);
227
+ }
228
+ }
229
+ }
230
+ this.resetUnmergedState();
231
+ await this.worktreeManager.switchBranch(context.mainBranch);
232
+ // Stash all changes including untracked files so they don't block
233
+ // incoming merges that introduce files with the same names.
234
+ let stashed = false;
235
+ try {
236
+ const stashResult = (0, child_process_1.execSync)('git stash push --include-untracked -m "pre-final-merge stash"', {
237
+ cwd: this.workingDir, encoding: 'utf8', stdio: 'pipe'
238
+ });
239
+ stashed = !stashResult.includes('No local changes');
240
+ }
241
+ catch {
242
+ // Clean working tree; expected
243
+ }
244
+ // Determine already-merged branches to avoid double-merge
245
+ let mergedBranches = [];
246
+ try {
247
+ const merged = (0, child_process_1.execSync)(`git branch --merged ${context.mainBranch}`, {
248
+ cwd: this.workingDir, encoding: 'utf8', stdio: 'pipe'
249
+ });
250
+ mergedBranches = merged.split('\n').map(b => b.trim().replace(/^\* /, ''));
251
+ }
252
+ catch {
253
+ // Shallow clones or empty repos; safe to attempt all merges
254
+ }
255
+ for (const result of results) {
256
+ if (result.status === 'completed' && result.branchName) {
257
+ const label = shortBranchLabel(result.branchName);
258
+ if (mergedBranches.includes(result.branchName)) {
259
+ // Skip silently. The wave loop already announced this merge; a
260
+ // second "(already merged)" line on top is just noise.
261
+ continue;
262
+ }
263
+ const mergeSpinner = new spinner_1.Spinner(`merging ${label}...`, { style: 'dots', prefix: ' ' });
264
+ mergeSpinner.start();
265
+ try {
266
+ await this.mergeBranch(result.branchName, context);
267
+ mergeSpinner.stop(`merged ${label}`);
268
+ }
269
+ catch (error) {
270
+ const err = error;
271
+ try {
272
+ (0, child_process_1.execSync)('git merge --abort', { cwd: this.workingDir, stdio: 'pipe' });
273
+ }
274
+ catch { /* no merge in progress */ }
275
+ const rebased = this.tryRebaseAndMerge(result.branchName, context);
276
+ if (rebased) {
277
+ mergeSpinner.stop(`merged ${label} (rebased)`);
278
+ }
279
+ else {
280
+ mergeSpinner.stop(`conflict on ${label}: ${err.message}`);
281
+ logger.error(` work preserved on ${result.branchName}`);
282
+ unmerged.push({
283
+ stepNumber: result.stepNumber,
284
+ branchName: result.branchName,
285
+ agentName: result.agentName,
286
+ reason: err.message,
287
+ });
288
+ }
289
+ }
290
+ }
291
+ }
292
+ if (stashed) {
293
+ try {
294
+ (0, child_process_1.execSync)('git stash pop', { cwd: this.workingDir, stdio: 'pipe' });
295
+ }
296
+ catch {
297
+ this.resetUnmergedState();
298
+ try {
299
+ (0, child_process_1.execSync)('git stash drop', { cwd: this.workingDir, stdio: 'pipe' });
300
+ }
301
+ catch { /* already gone */ }
302
+ }
303
+ }
304
+ return unmerged;
305
+ }
306
+ /**
307
+ * Three-strategy conflict resolution:
308
+ * 1. Rebase onto main, fast-forward merge
309
+ * 2. merge -X theirs (accept branch version of conflicting hunks)
310
+ * 3. Manual modify/delete conflict resolution
311
+ */
312
+ tryRebaseAndMerge(branchName, context) {
313
+ const gitEnv = { ...process.env, GIT_TERMINAL_PROMPT: '0' };
314
+ const mergeEnv = { ...gitEnv, GIT_MERGE_AUTOEDIT: 'no' };
315
+ // Strategy 1: rebase + fast-forward
316
+ try {
317
+ (0, child_process_1.execSync)(`git rebase ${context.mainBranch} "${branchName}"`, {
318
+ cwd: this.workingDir, stdio: 'pipe', timeout: 120000, env: gitEnv
319
+ });
320
+ (0, child_process_1.execSync)(`git checkout "${context.mainBranch}"`, {
321
+ cwd: this.workingDir, stdio: 'pipe', env: gitEnv
322
+ });
323
+ (0, child_process_1.execSync)(`git merge --no-ff "${branchName}" -m "Merge ${branchName} (rebased)"`, {
324
+ cwd: this.workingDir, stdio: 'pipe', timeout: 120000, env: mergeEnv
325
+ });
326
+ return true;
327
+ }
328
+ catch {
329
+ try {
330
+ (0, child_process_1.execSync)('git rebase --abort', { cwd: this.workingDir, stdio: 'pipe' });
331
+ }
332
+ catch { /* none in progress */ }
333
+ try {
334
+ (0, child_process_1.execSync)('git merge --abort', { cwd: this.workingDir, stdio: 'pipe' });
335
+ }
336
+ catch { /* none in progress */ }
337
+ try {
338
+ (0, child_process_1.execSync)(`git checkout "${context.mainBranch}"`, { cwd: this.workingDir, stdio: 'pipe', env: gitEnv });
339
+ }
340
+ catch { /* best-effort */ }
341
+ }
342
+ // Strategy 2: -X theirs auto-resolution
343
+ try {
344
+ logger.info(` \u{1F500} Retrying merge of ${branchName} with conflict auto-resolution...`);
345
+ (0, child_process_1.execSync)(`git merge -X theirs --no-ff "${branchName}" -m "Merge ${branchName} (auto-resolved)"`, {
346
+ cwd: this.workingDir, stdio: 'pipe', timeout: 120000, env: mergeEnv
347
+ });
348
+ return true;
349
+ }
350
+ catch {
351
+ // Handle modify/delete conflicts that -X theirs can't resolve
352
+ try {
353
+ const statusOutput = (0, child_process_1.execSync)('git status --porcelain', {
354
+ cwd: this.workingDir, encoding: 'utf8', stdio: 'pipe'
355
+ });
356
+ const conflictLines = statusOutput.split('\n').filter(l => l.startsWith('UD') || l.startsWith('DU') || l.startsWith('UU') || l.startsWith('AA'));
357
+ if (conflictLines.length > 0) {
358
+ for (const line of conflictLines) {
359
+ const filePath = line.slice(3).trim();
360
+ if (line.startsWith('UD')) {
361
+ // Ours modified, theirs deleted: accept deletion
362
+ (0, child_process_1.execSync)(`git rm -f "${filePath}"`, { cwd: this.workingDir, stdio: 'pipe' });
363
+ }
364
+ else {
365
+ // DU, UU, AA: accept theirs (binary .pyc, .db, or text conflicts)
366
+ (0, child_process_1.execSync)(`git checkout --theirs "${filePath}" && git add "${filePath}"`, {
367
+ cwd: this.workingDir, stdio: 'pipe', shell: '/bin/bash'
368
+ });
369
+ }
370
+ }
371
+ try {
372
+ (0, child_process_1.execSync)('git add -u', { cwd: this.workingDir, stdio: 'pipe' });
373
+ }
374
+ catch { /* ignore */ }
375
+ (0, child_process_1.execSync)(`git commit --no-edit -m "Merge ${branchName} (auto-resolved conflicts)"`, { cwd: this.workingDir, stdio: 'pipe', env: mergeEnv });
376
+ logger.info(` \u2705 Resolved merge conflicts for ${branchName}`);
377
+ return true;
378
+ }
379
+ }
380
+ catch {
381
+ // Manual resolution failed; fall through to abort
382
+ }
383
+ try {
384
+ (0, child_process_1.execSync)('git merge --abort', { cwd: this.workingDir, stdio: 'pipe' });
385
+ }
386
+ catch { /* none in progress */ }
387
+ try {
388
+ (0, child_process_1.execSync)(`git checkout "${context.mainBranch}"`, { cwd: this.workingDir, stdio: 'pipe', env: gitEnv });
389
+ }
390
+ catch { /* best-effort */ }
391
+ return false;
392
+ }
393
+ }
394
+ /**
395
+ * Merge a single branch via git merge --no-ff, with git lock coordination.
396
+ */
397
+ async mergeBranch(branchName, context) {
398
+ const lockId = await context.contextBroker.acquireGitLock('orchestrator', `merge ${branchName}`);
399
+ if (!lockId) {
400
+ throw new Error('Failed to acquire git lock for merge');
401
+ }
402
+ try {
403
+ (0, child_process_1.execSync)(`git merge --no-ff "${branchName}" -m "Merge ${branchName}"`, {
404
+ cwd: this.workingDir,
405
+ stdio: 'pipe',
406
+ timeout: 120000,
407
+ env: {
408
+ ...process.env,
409
+ GIT_TERMINAL_PROMPT: '0',
410
+ GIT_MERGE_AUTOEDIT: 'no'
411
+ }
412
+ });
413
+ }
414
+ catch (err) {
415
+ const e = err;
416
+ if (e.killed) {
417
+ throw new Error(`Timeout merging ${branchName}`, { cause: err });
418
+ }
419
+ throw new Error(`Merge conflict: ${e.stderr?.toString() || e.message || 'unknown error'}`, { cause: err });
420
+ }
421
+ finally {
422
+ context.contextBroker.releaseGitLock(lockId);
423
+ }
424
+ }
425
+ }
426
+ exports.BranchMerger = BranchMerger;
427
+ exports.default = BranchMerger;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.handleAttestCommand = handleAttestCommand;
4
+ const verification_1 = require("../verification");
5
+ /**
6
+ * Handle `swarm attest verify <commit>`.
7
+ *
8
+ * @param args - CLI argv segment beginning with `attest`.
9
+ * @returns Process exit code.
10
+ */
11
+ async function handleAttestCommand(args) {
12
+ const subcommand = args[1];
13
+ if (subcommand !== 'verify') {
14
+ console.error('Usage: swarm attest verify <commit>');
15
+ return 1;
16
+ }
17
+ const commit = args[2];
18
+ if (!commit) {
19
+ console.error('Usage: swarm attest verify <commit>');
20
+ return 1;
21
+ }
22
+ const result = await (0, verification_1.verifyAttestation)(process.cwd(), commit);
23
+ if (!result.found) {
24
+ console.error(`No attestation found for ${commit}`);
25
+ return 1;
26
+ }
27
+ const attestation = result.attestation;
28
+ if (!attestation) {
29
+ console.error(`No attestation found for ${commit}`);
30
+ return 1;
31
+ }
32
+ const metadata = attestation.envelope.predicate.metadata;
33
+ const agent = attestation.envelope.predicate.buildConfig;
34
+ console.log(`Commit: ${commit}`);
35
+ console.log(`Verified: ${result.verified ? 'yes' : 'no'}`);
36
+ console.log(`Reason: ${result.reason}`);
37
+ console.log(`Agent: ${agent.tool} ${agent.version} (${agent.model})`);
38
+ console.log(`Composite score: ${metadata.compositeScore}`);
39
+ console.log(`Timestamp: ${metadata.timestamp}`);
40
+ for (const layer of metadata.layerResults) {
41
+ console.log(`- ${layer.layer}: ${layer.status} (${layer.durationMs}ms) ${layer.evidenceSummary}`);
42
+ }
43
+ return result.verified ? 0 : 1;
44
+ }
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.confirmCostPrompt = confirmCostPrompt;
37
+ const readline = __importStar(require("readline"));
38
+ function confirmCostPrompt(estimateLow, estimateHigh, model, skipConfirm) {
39
+ if (skipConfirm)
40
+ return Promise.resolve(true);
41
+ if (!process.stdin.isTTY)
42
+ return Promise.resolve(true);
43
+ return new Promise((resolve) => {
44
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
45
+ rl.question(`\n⚡ This will use ${estimateLow}-${estimateHigh} premium requests (${model}). Proceed? [Y/n] `, (answer) => {
46
+ rl.close();
47
+ const normalized = (answer || 'y').trim().toLowerCase();
48
+ resolve(normalized === 'y' || normalized === 'yes' || normalized === '');
49
+ });
50
+ });
51
+ }