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,477 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ShareParser = void 0;
4
+ const transcript_verification_1 = require("./share/transcript-verification");
5
+ class ShareParser {
6
+ /**
7
+ * parse /share transcript and extract key facts with comprehensive verification
8
+ */
9
+ parse(content) {
10
+ const index = {
11
+ changedFiles: [],
12
+ commandsExecuted: [],
13
+ testsRun: [],
14
+ prLinks: [],
15
+ gitCommits: [],
16
+ packageOperations: [],
17
+ buildOperations: [],
18
+ lintOperations: [],
19
+ mcpSections: [],
20
+ claims: []
21
+ };
22
+ const lines = content.split('\n');
23
+ // extract changed files
24
+ index.changedFiles = this.extractChangedFiles(lines);
25
+ // extract commands executed
26
+ index.commandsExecuted = this.extractCommands(lines);
27
+ // extract test runs
28
+ index.testsRun = this.extractTestRuns(lines, index.commandsExecuted);
29
+ // extract PR links
30
+ index.prLinks = this.extractPRLinks(lines);
31
+ // extract git commits
32
+ index.gitCommits = this.extractGitCommits(lines, index.commandsExecuted);
33
+ // extract package operations
34
+ index.packageOperations = this.extractPackageOperations(lines, index.commandsExecuted);
35
+ // extract build operations
36
+ index.buildOperations = this.extractBuildOperations(lines, index.commandsExecuted);
37
+ // extract lint operations
38
+ index.lintOperations = this.extractLintOperations(lines, index.commandsExecuted);
39
+ // extract MCP sections
40
+ index.mcpSections = this.extractMcpSections(lines);
41
+ // extract and verify claims
42
+ index.claims = (0, transcript_verification_1.extractClaims)(lines, index);
43
+ return index;
44
+ }
45
+ extractChangedFiles(lines) {
46
+ const files = new Set();
47
+ // look for git status output
48
+ let inGitStatus = false;
49
+ for (const line of lines) {
50
+ if (line.includes('git status') || line.includes('git diff')) {
51
+ inGitStatus = true;
52
+ continue;
53
+ }
54
+ if (inGitStatus) {
55
+ // match modified files
56
+ const modifiedMatch = line.match(/^\s*modified:\s+(.+)$/);
57
+ if (modifiedMatch && modifiedMatch[1]) {
58
+ files.add(modifiedMatch[1].trim());
59
+ }
60
+ // match new files
61
+ const newFileMatch = line.match(/^\s*new file:\s+(.+)$/);
62
+ if (newFileMatch && newFileMatch[1]) {
63
+ files.add(newFileMatch[1].trim());
64
+ }
65
+ // match deleted files
66
+ const deletedMatch = line.match(/^\s*deleted:\s+(.+)$/);
67
+ if (deletedMatch && deletedMatch[1]) {
68
+ files.add(deletedMatch[1].trim());
69
+ }
70
+ // end of git status block
71
+ if (line.trim() === '' || line.includes('$') || line.includes('>')) {
72
+ inGitStatus = false;
73
+ }
74
+ }
75
+ // also look for explicit file mentions in code blocks
76
+ const filePathMatch = line.match(/^[\s]*(?:edited|created|modified|deleted):\s+([^\s]+\.[a-z]+)/i);
77
+ if (filePathMatch && filePathMatch[1]) {
78
+ files.add(filePathMatch[1]);
79
+ }
80
+ }
81
+ return Array.from(files);
82
+ }
83
+ extractCommands(lines) {
84
+ const commands = [];
85
+ // Accumulator for multi-line Copilot CLI commands (continued with │ prefix)
86
+ let pendingCopilotCmd = '';
87
+ for (let i = 0; i < lines.length; i++) {
88
+ const line = lines[i];
89
+ if (!line) {
90
+ // Blank line ends any pending multi-line command
91
+ if (pendingCopilotCmd) {
92
+ commands.push(pendingCopilotCmd);
93
+ pendingCopilotCmd = '';
94
+ }
95
+ continue;
96
+ }
97
+ // Copilot CLI transcript format: commands prefixed with box-drawing │ (U+2502)
98
+ // e.g. " │ source venv/bin/activate && python -m pytest tests/ -v"
99
+ const copilotMatch = line.match(/^\s*\u2502\s+(.+)/);
100
+ if (copilotMatch) {
101
+ const fragment = copilotMatch[1].trim();
102
+ // └ lines are output summaries (e.g. "└ 86 lines..."), not commands
103
+ if (!fragment.startsWith('\u2514') && !fragment.match(/^\d+ lines/)) {
104
+ if (pendingCopilotCmd) {
105
+ // Continuation of a multi-line command (e.g. && on previous line)
106
+ pendingCopilotCmd += ' ' + fragment;
107
+ }
108
+ else {
109
+ pendingCopilotCmd = fragment;
110
+ }
111
+ }
112
+ else if (pendingCopilotCmd) {
113
+ // Output summary terminates the pending command
114
+ commands.push(pendingCopilotCmd);
115
+ pendingCopilotCmd = '';
116
+ }
117
+ continue;
118
+ }
119
+ // Non-│ line ends any pending multi-line Copilot command
120
+ if (pendingCopilotCmd) {
121
+ commands.push(pendingCopilotCmd);
122
+ pendingCopilotCmd = '';
123
+ }
124
+ // look for command prompts
125
+ if (line.match(/^[\$>]\s+/) || line.match(/^npm\s+/) || line.match(/^git\s+/)) {
126
+ const cmd = line.replace(/^[\$>]\s+/, '').trim();
127
+ if (cmd) {
128
+ commands.push(cmd);
129
+ }
130
+ }
131
+ // look for commands in code blocks
132
+ if (line.includes('```') && i + 1 < lines.length) {
133
+ const nextLine = lines[i + 1];
134
+ if (nextLine && (nextLine.startsWith('$') || nextLine.startsWith('npm') || nextLine.startsWith('git'))) {
135
+ const cmd = nextLine.replace(/^[\$>]\s+/, '').trim();
136
+ if (cmd) {
137
+ commands.push(cmd);
138
+ }
139
+ }
140
+ }
141
+ }
142
+ // Flush any trailing command
143
+ if (pendingCopilotCmd) {
144
+ commands.push(pendingCopilotCmd);
145
+ }
146
+ return commands;
147
+ }
148
+ extractTestRuns(lines, commands) {
149
+ const testRuns = [];
150
+ // find test commands
151
+ const testCommands = commands.filter(cmd => cmd.includes('test') ||
152
+ cmd.includes('jest') ||
153
+ cmd.includes('mocha') ||
154
+ cmd.includes('pytest') ||
155
+ cmd.includes('go test') ||
156
+ cmd.includes('cargo test'));
157
+ for (const cmd of testCommands) {
158
+ // verify test actually ran by looking for output
159
+ const hasOutput = this.hasTestOutput(lines, cmd);
160
+ if (hasOutput) {
161
+ testRuns.push({
162
+ command: cmd,
163
+ verified: true
164
+ });
165
+ }
166
+ else {
167
+ testRuns.push({
168
+ command: cmd,
169
+ verified: false,
170
+ reason: 'no test output found in transcript'
171
+ });
172
+ }
173
+ }
174
+ return testRuns;
175
+ }
176
+ hasTestOutput(lines, testCommand) {
177
+ // look for common test output patterns after the command
178
+ const cmdIndex = lines.findIndex(line => line.includes(testCommand));
179
+ if (cmdIndex === -1)
180
+ return false;
181
+ // check next 80 lines for test output (Node.js test runner can be verbose)
182
+ const outputLines = lines.slice(cmdIndex + 1, cmdIndex + 81);
183
+ for (const line of outputLines) {
184
+ // mocha/jest patterns
185
+ if (line.match(/\d+\s+passing/))
186
+ return true;
187
+ if (line.match(/\d+\s+tests?\s+passed/))
188
+ return true;
189
+ // pytest patterns
190
+ if (line.match(/\d+\s+passed/))
191
+ return true;
192
+ // go test patterns
193
+ if (line.match(/PASS/))
194
+ return true;
195
+ if (line.match(/ok\s+/))
196
+ return true;
197
+ // Node.js built-in test runner patterns (node --test)
198
+ if (line.match(/tests\s+\d+/))
199
+ return true; // "ℹ tests 10"
200
+ if (line.match(/pass\s+\d+/))
201
+ return true; // "ℹ pass 10"
202
+ if (line.match(/fail\s+0/))
203
+ return true; // "ℹ fail 0"
204
+ if (line.match(/duration_ms/))
205
+ return true; // "ℹ duration_ms 123"
206
+ // generic success patterns
207
+ if (line.match(/all tests passed/i))
208
+ return true;
209
+ if (line.match(/all\s+\d+\s+tests?\s+pass/i))
210
+ return true;
211
+ }
212
+ return false;
213
+ }
214
+ extractPRLinks(lines) {
215
+ const links = new Set();
216
+ for (const line of lines) {
217
+ // github PR URLs
218
+ const prMatch = line.match(/https:\/\/github\.com\/[^\/]+\/[^\/]+\/pull\/\d+/g);
219
+ if (prMatch) {
220
+ prMatch.forEach(url => links.add(url));
221
+ }
222
+ // shortened PR references
223
+ const shortMatch = line.match(/#(\d+)/g);
224
+ if (shortMatch) {
225
+ // note: we can't construct full URL without repo context
226
+ // so we just note the PR number
227
+ shortMatch.forEach(ref => links.add(ref));
228
+ }
229
+ }
230
+ return Array.from(links);
231
+ }
232
+ extractGitCommits(lines, commands) {
233
+ const commits = [];
234
+ const commitMap = new Map();
235
+ // look for git commit commands in extracted commands list
236
+ const commitCommands = commands.filter(cmd => cmd.match(/git\s+commit/));
237
+ for (const cmd of commitCommands) {
238
+ // try single-line quoted message first
239
+ const messageMatch = cmd.match(/git\s+commit\s+-m\s+["']([^"']+)["']/);
240
+ if (messageMatch && messageMatch[1]) {
241
+ const message = messageMatch[1];
242
+ commitMap.set(message, { message, verified: true });
243
+ }
244
+ else {
245
+ // message may span multiple lines or have an unclosed quote;
246
+ // grab everything after -m " as the first line of the message
247
+ const partialMatch = cmd.match(/git\s+commit\s+-m\s+["'](.+)/);
248
+ if (partialMatch && partialMatch[1]) {
249
+ const message = partialMatch[1].replace(/["']$/, '').trim();
250
+ if (message) {
251
+ commitMap.set(message, { message, verified: true });
252
+ }
253
+ }
254
+ }
255
+ }
256
+ // also scan raw lines for git commit commands that extractCommands may
257
+ // have missed (e.g. chained commands: cd ... && git commit -m "...")
258
+ for (const line of lines) {
259
+ const inlineMatch = line.match(/git\s+commit\s+-m\s+["']([^"'\n]+)/);
260
+ if (inlineMatch && inlineMatch[1]) {
261
+ const message = inlineMatch[1].trim();
262
+ if (message && !commitMap.has(message)) {
263
+ commitMap.set(message, { message, verified: true });
264
+ }
265
+ }
266
+ }
267
+ // look for commit SHAs in git output
268
+ // format: [branch-name sha] message (branch can contain / and -)
269
+ for (const line of lines) {
270
+ const shaMatch = line.match(/\[[\w/.:-]+\s+([a-f0-9]{7,40})\]\s+(.+)/);
271
+ if (shaMatch && shaMatch[1] && shaMatch[2]) {
272
+ const sha = shaMatch[1];
273
+ const messageAfterSha = shaMatch[2].trim();
274
+ // try to match with an already-known commit
275
+ let foundCommit = false;
276
+ for (const [message, commit] of commitMap.entries()) {
277
+ if (messageAfterSha.includes(message) || message.includes(messageAfterSha)) {
278
+ commit.sha = sha;
279
+ foundCommit = true;
280
+ break;
281
+ }
282
+ }
283
+ if (!foundCommit && messageAfterSha) {
284
+ commitMap.set(messageAfterSha, { message: messageAfterSha, sha, verified: true });
285
+ }
286
+ }
287
+ }
288
+ // convert map to array
289
+ for (const commit of commitMap.values()) {
290
+ const result = {
291
+ message: commit.message || 'commit detected',
292
+ verified: true
293
+ };
294
+ if (commit.sha) {
295
+ result.sha = commit.sha;
296
+ }
297
+ commits.push(result);
298
+ }
299
+ return commits;
300
+ }
301
+ extractPackageOperations(lines, commands) {
302
+ const operations = [];
303
+ const processedCommands = new Set();
304
+ // npm/yarn/pnpm patterns
305
+ const packageManagers = ['npm', 'yarn', 'pnpm', 'bun'];
306
+ for (const cmd of commands) {
307
+ // skip if already processed
308
+ if (processedCommands.has(cmd)) {
309
+ continue;
310
+ }
311
+ for (const pm of packageManagers) {
312
+ // install operations (install, add, i)
313
+ const installMatch = cmd.match(new RegExp(`^${pm}\\s+(?:add|install|i)\\s+(.+)`));
314
+ if (installMatch && installMatch[1]) {
315
+ const argString = installMatch[1];
316
+ // filter out flags and extract package names
317
+ const packages = argString
318
+ .split(/\s+/)
319
+ .filter(p => p.trim() !== '' && !p.startsWith('-'));
320
+ if (packages.length > 0) {
321
+ operations.push({
322
+ operation: 'install',
323
+ packages
324
+ });
325
+ processedCommands.add(cmd);
326
+ break; // found a match, move to next command
327
+ }
328
+ }
329
+ // uninstall operations
330
+ const uninstallMatch = cmd.match(new RegExp(`^${pm}\\s+(?:remove|uninstall|rm)\\s+(.+)`));
331
+ if (uninstallMatch && uninstallMatch[1]) {
332
+ const argString = uninstallMatch[1];
333
+ const packages = argString
334
+ .split(/\s+/)
335
+ .filter(p => p.trim() !== '' && !p.startsWith('-'));
336
+ if (packages.length > 0) {
337
+ operations.push({
338
+ operation: 'uninstall',
339
+ packages
340
+ });
341
+ processedCommands.add(cmd);
342
+ break;
343
+ }
344
+ }
345
+ // update operations
346
+ if (cmd.match(new RegExp(`^${pm}\\s+(?:update|upgrade)`))) {
347
+ operations.push({
348
+ operation: 'update',
349
+ packages: ['all packages']
350
+ });
351
+ processedCommands.add(cmd);
352
+ break;
353
+ }
354
+ }
355
+ }
356
+ return operations;
357
+ }
358
+ extractBuildOperations(lines, commands) {
359
+ const operations = [];
360
+ const buildTools = [
361
+ { tool: 'tsc', pattern: /\btsc\b/ },
362
+ { tool: 'webpack', pattern: /\bwebpack\b/ },
363
+ { tool: 'vite', pattern: /\bvite\s+build\b/ },
364
+ { tool: 'rollup', pattern: /\brollup\b/ },
365
+ { tool: 'esbuild', pattern: /\besbuild\b/ },
366
+ { tool: 'swc', pattern: /\bswc\b/ },
367
+ { tool: 'babel', pattern: /\bbabel\b/ },
368
+ { tool: 'next', pattern: /\bnext\s+build\b/ },
369
+ { tool: 'nuxt', pattern: /\bnuxt\s+build\b/ },
370
+ { tool: 'npm build', pattern: /\bnpm\s+run\s+build\b/ },
371
+ { tool: 'yarn build', pattern: /\byarn\s+build\b/ }
372
+ ];
373
+ for (const { tool, pattern } of buildTools) {
374
+ const buildCmd = commands.find(cmd => pattern.test(cmd));
375
+ if (buildCmd) {
376
+ // verify build succeeded by looking for output
377
+ const verified = this.hasBuildOutput(lines, buildCmd);
378
+ operations.push({ tool, verified });
379
+ }
380
+ }
381
+ return operations;
382
+ }
383
+ hasBuildOutput(lines, buildCommand) {
384
+ const cmdIndex = lines.findIndex(line => line.includes(buildCommand));
385
+ if (cmdIndex === -1)
386
+ return false;
387
+ // check next 100 lines for build success indicators
388
+ const outputLines = lines.slice(cmdIndex + 1, cmdIndex + 101);
389
+ for (const line of outputLines) {
390
+ // success patterns
391
+ if (line.match(/build\s+succe(ss|eded)/i))
392
+ return true;
393
+ if (line.match(/compiled successfully/i))
394
+ return true;
395
+ if (line.match(/built in \d+/i))
396
+ return true;
397
+ if (line.match(/✓.*built/i))
398
+ return true;
399
+ if (line.match(/done in \d+/i))
400
+ return true;
401
+ if (line.match(/successfully built/i))
402
+ return true;
403
+ }
404
+ return false;
405
+ }
406
+ extractLintOperations(lines, commands) {
407
+ const operations = [];
408
+ const lintTools = [
409
+ { tool: 'eslint', pattern: /\beslint\b/ },
410
+ { tool: 'prettier', pattern: /\bprettier\b/ },
411
+ { tool: 'biome', pattern: /\bbiome\s+(?:check|lint)\b/ },
412
+ { tool: 'tslint', pattern: /\btslint\b/ },
413
+ { tool: 'npm lint', pattern: /\bnpm\s+run\s+lint\b/ },
414
+ { tool: 'yarn lint', pattern: /\byarn\s+lint\b/ }
415
+ ];
416
+ for (const { tool, pattern } of lintTools) {
417
+ const lintCmd = commands.find(cmd => pattern.test(cmd));
418
+ if (lintCmd) {
419
+ // verify lint succeeded
420
+ const verified = this.hasLintOutput(lines, lintCmd);
421
+ operations.push({ tool, verified });
422
+ }
423
+ }
424
+ return operations;
425
+ }
426
+ hasLintOutput(lines, lintCommand) {
427
+ const cmdIndex = lines.findIndex(line => line.includes(lintCommand));
428
+ if (cmdIndex === -1)
429
+ return false;
430
+ // check next 50 lines for lint output
431
+ const outputLines = lines.slice(cmdIndex + 1, cmdIndex + 51);
432
+ for (const line of outputLines) {
433
+ // success patterns
434
+ if (line.match(/✓.*no.*(error|warning|problem)/i))
435
+ return true;
436
+ if (line.match(/0\s+errors/i))
437
+ return true;
438
+ if (line.match(/all.*passed/i))
439
+ return true;
440
+ if (line.match(/✨.*done/i))
441
+ return true;
442
+ }
443
+ return false;
444
+ }
445
+ extractMcpSections(lines) {
446
+ const sections = [];
447
+ // look for MCP Evidence headers
448
+ for (let i = 0; i < lines.length; i++) {
449
+ const line = lines[i];
450
+ if (!line)
451
+ continue;
452
+ if (line.match(/##\s+MCP\s+Evidence/i)) {
453
+ // extract section content (everything until next ## or end)
454
+ let content = '';
455
+ let j = i + 1;
456
+ while (j < lines.length && !lines[j]?.match(/^##\s+/)) {
457
+ content += (lines[j] || '') + '\n';
458
+ j++;
459
+ }
460
+ const trimmedContent = content.trim();
461
+ // verify MCP section has actual evidence
462
+ const hasIssueRef = /issue\s+#?\d+/i.test(trimmedContent);
463
+ const hasPrRef = /pr\s+#?\d+|pull request/i.test(trimmedContent);
464
+ const hasWorkflowRef = /workflow|\.github\/workflows|CI/i.test(trimmedContent);
465
+ const hasDecision = /decision|influenced|based on|considering/i.test(trimmedContent);
466
+ const verified = (hasIssueRef || hasPrRef || hasWorkflowRef) && hasDecision && trimmedContent.length >= 50;
467
+ sections.push({
468
+ content: trimmedContent,
469
+ verified
470
+ });
471
+ }
472
+ }
473
+ return sections;
474
+ }
475
+ }
476
+ exports.ShareParser = ShareParser;
477
+ exports.default = ShareParser;
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ // Author: Bradley R. Kinnard
3
+ // Terminal spinner for visual feedback during long operations
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.ProgressTracker = exports.Spinner = void 0;
6
+ const logger_1 = require("./logger");
7
+ const logger = (0, logger_1.getLogger)('spinner');
8
+ const SPINNER_FRAMES = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
9
+ const DOTS_FRAMES = ['⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'];
10
+ const BOUNCE_FRAMES = ['⠁', '⠂', '⠄', '⡀', '⢀', '⠠', '⠐', '⠈'];
11
+ const PULSE_FRAMES = ['🐝', '🐝 ', '🐝 ', '🐝 ', '🐝 ', '🐝 ', '🐝'];
12
+ const FRAME_SETS = {
13
+ dots: DOTS_FRAMES,
14
+ spinner: SPINNER_FRAMES,
15
+ bounce: BOUNCE_FRAMES,
16
+ pulse: PULSE_FRAMES
17
+ };
18
+ class Spinner {
19
+ frames;
20
+ frameIndex = 0;
21
+ interval = null;
22
+ message;
23
+ prefix;
24
+ isRunning = false;
25
+ constructor(message, options = {}) {
26
+ this.frames = FRAME_SETS[options.style || 'dots'];
27
+ this.message = message;
28
+ this.prefix = options.prefix || '';
29
+ }
30
+ start() {
31
+ if (this.isRunning)
32
+ return;
33
+ // When stdout is not a TTY (piped to a file, CI log, etc.) cursor-control
34
+ // escapes show up as literal bytes and corrupt the captured output.
35
+ if (!process.stdout.isTTY)
36
+ return;
37
+ this.isRunning = true;
38
+ this.frameIndex = 0;
39
+ // hide cursor
40
+ process.stdout.write('\x1B[?25l');
41
+ this.interval = setInterval(() => {
42
+ const frame = this.frames[this.frameIndex];
43
+ process.stdout.write(`\r${this.prefix}${frame} ${this.message}`);
44
+ this.frameIndex = (this.frameIndex + 1) % this.frames.length;
45
+ }, 80);
46
+ }
47
+ update(message) {
48
+ this.message = message;
49
+ }
50
+ stop(finalMessage) {
51
+ if (!this.isRunning) {
52
+ // Even when start() was skipped, emit the final message via logger.
53
+ if (finalMessage) {
54
+ logger.info(`${this.prefix}${finalMessage}`);
55
+ }
56
+ return;
57
+ }
58
+ this.isRunning = false;
59
+ if (this.interval) {
60
+ clearInterval(this.interval);
61
+ this.interval = null;
62
+ }
63
+ // clear line and show cursor
64
+ process.stdout.write('\r\x1B[K');
65
+ process.stdout.write('\x1B[?25h');
66
+ if (finalMessage) {
67
+ logger.info(`${this.prefix}${finalMessage}`);
68
+ }
69
+ }
70
+ succeed(message) {
71
+ this.stop(`${this.color('✓', '32', '39')} ${message || this.message}`);
72
+ }
73
+ fail(message) {
74
+ this.stop(`${this.color('✗', '31', '39')} ${message || this.message}`);
75
+ }
76
+ warn(message) {
77
+ this.stop(`${this.color('!', '33', '39')} ${message || this.message}`);
78
+ }
79
+ info(message) {
80
+ this.stop(`${this.color('·', '2', '22')} ${message || this.message}`);
81
+ }
82
+ /** Wrap a glyph in ANSI color/style codes when stdout supports them. */
83
+ color(ch, open, close) {
84
+ if (!process.stdout.isTTY || process.env.NO_COLOR)
85
+ return ch;
86
+ return `\x1b[${open}m${ch}\x1b[${close}m`;
87
+ }
88
+ }
89
+ exports.Spinner = Spinner;
90
+ /**
91
+ * Multi-step progress tracker with visual feedback
92
+ */
93
+ class ProgressTracker {
94
+ activeSpinners = new Map();
95
+ stepStatus = new Map();
96
+ startStep(stepId, message, prefix = ' ') {
97
+ const spinner = new Spinner(message, { style: 'dots', prefix });
98
+ this.activeSpinners.set(stepId, spinner);
99
+ this.stepStatus.set(stepId, 'running');
100
+ spinner.start();
101
+ }
102
+ updateStep(stepId, message) {
103
+ const spinner = this.activeSpinners.get(stepId);
104
+ if (spinner) {
105
+ spinner.update(message);
106
+ }
107
+ }
108
+ completeStep(stepId, message) {
109
+ const spinner = this.activeSpinners.get(stepId);
110
+ if (spinner) {
111
+ spinner.succeed(message);
112
+ this.activeSpinners.delete(stepId);
113
+ this.stepStatus.set(stepId, 'done');
114
+ }
115
+ }
116
+ failStep(stepId, message) {
117
+ const existing = this.activeSpinners.get(stepId);
118
+ if (existing) {
119
+ existing.fail(message);
120
+ this.activeSpinners.delete(stepId);
121
+ }
122
+ else {
123
+ const spinner = new Spinner(message, { style: 'dots', prefix: ' ' });
124
+ spinner.fail(message);
125
+ }
126
+ this.stepStatus.set(stepId, 'failed');
127
+ }
128
+ warnStep(stepId, message) {
129
+ const spinner = this.activeSpinners.get(stepId);
130
+ if (spinner) {
131
+ spinner.warn(message);
132
+ this.activeSpinners.delete(stepId);
133
+ }
134
+ }
135
+ stopAll() {
136
+ for (const spinner of this.activeSpinners.values()) {
137
+ spinner.stop();
138
+ }
139
+ this.activeSpinners.clear();
140
+ }
141
+ getRunningCount() {
142
+ return this.activeSpinners.size;
143
+ }
144
+ }
145
+ exports.ProgressTracker = ProgressTracker;
146
+ exports.default = Spinner;