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,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.showUsage = showUsage;
4
+ function showUsage() {
5
+ console.log(`
6
+ Swarm Orchestrator - Falsification and Audit-Ready Orchestration for AI Coding Agents
7
+
8
+ Usage:
9
+ swarm bootstrap <path(s)> "Goal" Deep analysis and plan generation (multi-repo)
10
+ swarm plan <goal> Generate intelligent plan
11
+ swarm plan --copilot <goal> Generate Copilot CLI prompt for planning
12
+ swarm plan import <runid> <transcript> Parse plan from Copilot /share transcript
13
+ swarm execute <planfile> Execute a saved plan step-by-step
14
+ swarm swarm <planfile> Execute plan with verified branch/worktree workflow (analyzer-gated concurrency)
15
+ swarm run --goal "description" Plan + execute in one step (convenience)
16
+ swarm quick "task" Quick-fix mode for simple single-agent tasks
17
+ swarm demo <scenario> Run pre-configured demo scenario
18
+ swarm demo-fast Fast 2-step demo (alias for: swarm demo demo-fast)
19
+ swarm demo list List available demo scenarios
20
+ swarm gates [path] Run quality gates on a repo (default: cwd)
21
+ swarm status <execid> Show execution status
22
+ swarm templates List available plan templates
23
+ swarm share import <runid> <step> <agent> <path>
24
+ Import /share transcript for a step
25
+ swarm share context <runid> <step> Show prior context for a step
26
+ swarm audit <session-id> Generate Markdown audit report for a session
27
+ swarm metrics <session-id> Show metrics summary for a session
28
+ swarm agents export [--output-dir dir] Export agents as .agent.md from execution history
29
+ swarm use <recipe> [--param k=v ...] Execute a pre-built recipe (see: swarm recipes)
30
+ swarm recipes List available recipes
31
+ swarm recipe-info <name> Show recipe details and parameters
32
+ swarm report <run-id> Generate structured run report from artifacts
33
+ swarm attest verify <commit> Verify swarm attestation git note
34
+ swarm --help Show this help message
35
+
36
+ Flags:
37
+ --delegate Instruct agents to use /delegate for PR creation
38
+ --mcp Require MCP evidence from GitHub context in verification
39
+ --model Specify model for sessions (e.g., claude-sonnet-4.5)
40
+ --resume <id> Resume a previously paused/failed swarm session
41
+ --agent Specify agent for quick-fix mode
42
+ --skip-verify Skip verification in quick-fix mode (faster)
43
+ --confirm-deploy Enable opt-in deployment for deployment steps (vercel, netlify)
44
+ --no-quality-gates Disable quality gates (swarm mode)
45
+ --pm Run PM agent plan review before swarm execution
46
+ --strict-isolation Force per-task branch isolation, transcript-only context
47
+ --lean Enable Delta Context Engine (reuse prior KB patterns)
48
+ --useInnerFleet Prefix prompts with /fleet for inner sub-agent dispatch
49
+ --wrap-fleet Enable /fleet prefix on all step prompts (alias for --useInnerFleet)
50
+ --cost-estimate-only Run plan generation and cost estimation, print result, exit
51
+ --max-premium-requests <n> Abort if estimated premium requests exceed budget
52
+ --max-retries <n> Max retry attempts for queued and repair retries (default 3)
53
+ --quality-gates-config <path> Path to quality gates YAML (default: config/quality-gates.yaml)
54
+ --quality-gates-out <dir> Where to write gate reports (default: <runDir>/quality-gates)
55
+ --pr <auto|review> Create PRs instead of direct merge (auto: merge on pass, review: wait for approval)
56
+ --owasp-report Generate OWASP ASI compliance report after verification
57
+ --tool <name> Agent tool: copilot, claude-code, codex, claude-code-teams
58
+ --target <dir> Run execution in specified directory instead of cwd (alias: --dir)
59
+ --hooks Enable per-step hook injection for scope enforcement (default: on)
60
+ --no-hooks Disable hook injection for debugging
61
+ --verbose Enable debug-level logging
62
+ --output json Print machine-readable JSON for supported commands
63
+ --yes, -y Skip cost confirmation prompt (auto-approve)
64
+
65
+ Examples:
66
+ swarm demo-fast
67
+ swarm plan "Build a REST API for user management"
68
+ swarm plan --output json "Build a REST API for user management"
69
+ swarm swarm plan.json --model claude-opus-4.5 --verbose
70
+ swarm metrics <session-id> --output json
71
+ `);
72
+ }
@@ -0,0 +1,217 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ Object.defineProperty(exports, "__esModule", { value: true });
37
+ exports.generatePlan = void 0;
38
+ exports.main = main;
39
+ const fs = __importStar(require("fs"));
40
+ const path = __importStar(require("path"));
41
+ const flags_1 = require("./cli/flags");
42
+ const logger_1 = require("./logger");
43
+ const presenter_1 = require("./presenter");
44
+ const startupArgs = process.argv.slice(2);
45
+ // User-facing commands enable a clean presenter surface by default:
46
+ // pretty-mode hides `[scope]` prefixes, diagnostic logger output is routed to
47
+ // stderr, and --quiet suppresses everything except errors and the result line.
48
+ // `--verbose` keeps the legacy diagnostic-on-stdout shape for developers.
49
+ const USER_FACING_COMMANDS = new Set(['run', 'swarm', 'quick', 'demo', 'demo-fast', 'bootstrap']);
50
+ const firstNonFlag = startupArgs.find((a) => !a.startsWith('-'));
51
+ const isUserFacingCommand = firstNonFlag ? USER_FACING_COMMANDS.has(firstNonFlag) : false;
52
+ const isVerbose = startupArgs.includes('--verbose');
53
+ const isQuiet = startupArgs.includes('--quiet') || startupArgs.includes('-q');
54
+ (0, logger_1.configureLogger)({
55
+ level: isQuiet ? 'warn' : (isVerbose ? 'debug' : 'info'),
56
+ outputFormat: (0, flags_1.parseOutputFormat)(startupArgs),
57
+ // Diagnostic output (info/debug/trace) routes to stderr when the presenter
58
+ // owns stdout. Without pretty mode (developer / non-user-facing commands),
59
+ // diagnostics keep flowing to stdout so tooling that scrapes stdout works.
60
+ diagnosticsToStderr: isUserFacingCommand && !isVerbose,
61
+ });
62
+ if (isUserFacingCommand && !isVerbose) {
63
+ (0, logger_1.setPrettyMode)(true);
64
+ }
65
+ (0, presenter_1.configurePresenter)({ quiet: isQuiet });
66
+ const logger = (0, logger_1.getLogger)('cli');
67
+ /**
68
+ * Parse a single .env file and set any variables not already in process.env.
69
+ * Supports KEY=value, KEY="value", KEY='value', and `export KEY=value`.
70
+ * Skips blank lines and comments. No external dependencies.
71
+ */
72
+ function parseDotenvFile(filePath) {
73
+ if (!fs.existsSync(filePath))
74
+ return;
75
+ const content = fs.readFileSync(filePath, 'utf-8');
76
+ logger.debug(`loading env file ${filePath}`);
77
+ for (const raw of content.split('\n')) {
78
+ const line = raw.trim();
79
+ if (!line || line.startsWith('#'))
80
+ continue;
81
+ const stripped = line.startsWith('export ') ? line.slice(7) : line;
82
+ const eqIndex = stripped.indexOf('=');
83
+ if (eqIndex === -1)
84
+ continue;
85
+ const key = stripped.slice(0, eqIndex).trim();
86
+ let value = stripped.slice(eqIndex + 1).trim();
87
+ if ((value.startsWith('"') && value.endsWith('"')) ||
88
+ (value.startsWith("'") && value.endsWith("'"))) {
89
+ value = value.slice(1, -1);
90
+ }
91
+ if (process.env[key] === undefined) {
92
+ process.env[key] = value;
93
+ }
94
+ }
95
+ }
96
+ /**
97
+ * Load .env from multiple locations so API keys are found regardless
98
+ * of which target repo the user runs the command from.
99
+ *
100
+ * Search order (first match for a given key wins):
101
+ * 1. cwd (the target project directory)
102
+ * 2. The orchestrator's own install directory (where cli.js lives)
103
+ * 3. The user's home directory (~/.env) as a last-resort fallback
104
+ */
105
+ function loadDotenv() {
106
+ const candidates = [
107
+ path.resolve(process.cwd(), '.env'),
108
+ ];
109
+ // __dirname at runtime is dist/src/, so two levels up reaches the
110
+ // project root where .env and package.json live.
111
+ const orchestratorRoot = path.resolve(__dirname, '..', '..');
112
+ const orchestratorEnv = path.join(orchestratorRoot, '.env');
113
+ if (orchestratorEnv !== candidates[0]) {
114
+ candidates.push(orchestratorEnv);
115
+ }
116
+ const homeEnv = path.join(process.env.HOME || process.env.USERPROFILE || '', '.env');
117
+ if (homeEnv && !candidates.includes(homeEnv)) {
118
+ candidates.push(homeEnv);
119
+ }
120
+ for (const envPath of candidates) {
121
+ parseDotenvFile(envPath);
122
+ }
123
+ }
124
+ loadDotenv();
125
+ const index_1 = require("./cli/index");
126
+ Object.defineProperty(exports, "generatePlan", { enumerable: true, get: function () { return index_1.generatePlan; } });
127
+ async function main() {
128
+ const args = (0, flags_1.normalizeLeadingGlobalFlags)(process.argv.slice(2));
129
+ if (args.length === 0) {
130
+ (0, index_1.showUsage)();
131
+ return;
132
+ }
133
+ const command = args[0];
134
+ let exitCode = 0;
135
+ try {
136
+ switch (command) {
137
+ case 'demo-fast':
138
+ exitCode = await (0, index_1.handleDemoCommand)(['demo', 'demo-fast', ...args.slice(1)]);
139
+ break;
140
+ case 'gates':
141
+ exitCode = await (0, index_1.handleGatesCommand)(args.slice(1));
142
+ break;
143
+ case 'quick':
144
+ exitCode = await (0, index_1.handleQuickCommand)(args);
145
+ break;
146
+ case 'bootstrap':
147
+ exitCode = await (0, index_1.handleBootstrapCommand)(args);
148
+ break;
149
+ case 'plan':
150
+ exitCode = await (0, index_1.handlePlanCommand)(args);
151
+ break;
152
+ case 'execute':
153
+ exitCode = await (0, index_1.handleExecuteCommand)(args);
154
+ break;
155
+ case 'status':
156
+ exitCode = await (0, index_1.handleStatusCommand)(args);
157
+ break;
158
+ case 'swarm':
159
+ exitCode = await (0, index_1.handleSwarmCommand)(args);
160
+ break;
161
+ case 'demo':
162
+ exitCode = await (0, index_1.handleDemoCommand)(args);
163
+ break;
164
+ case 'templates':
165
+ exitCode = await (0, index_1.handleTemplatesCommand)();
166
+ break;
167
+ case '--help':
168
+ case '-h':
169
+ (0, index_1.showUsage)();
170
+ break;
171
+ case 'share':
172
+ exitCode = await (0, index_1.handleShareCommand)(args);
173
+ break;
174
+ case 'audit':
175
+ exitCode = await (0, index_1.handleAuditCommand)(args);
176
+ break;
177
+ case 'metrics':
178
+ exitCode = await (0, index_1.handleMetricsCommand)(args);
179
+ break;
180
+ case 'run':
181
+ exitCode = await (0, index_1.handleRunCommand)(args);
182
+ break;
183
+ case 'report':
184
+ exitCode = await (0, index_1.handleReportCommand)(args);
185
+ break;
186
+ case 'agents':
187
+ exitCode = await (0, index_1.handleAgentsCommand)(args);
188
+ break;
189
+ case 'attest':
190
+ exitCode = await (0, index_1.handleAttestCommand)(args);
191
+ break;
192
+ case 'use':
193
+ exitCode = await (0, index_1.handleUseCommand)(args);
194
+ break;
195
+ case 'recipes':
196
+ exitCode = (0, index_1.handleRecipesCommand)();
197
+ break;
198
+ case 'recipe-info':
199
+ exitCode = (0, index_1.handleRecipeInfoCommand)(args);
200
+ break;
201
+ default:
202
+ logger.error(`Unknown command: ${command}\n`);
203
+ (0, index_1.showUsage)();
204
+ exitCode = 1;
205
+ }
206
+ }
207
+ catch (error) {
208
+ logger.error('Fatal error:', error instanceof Error ? error.message : String(error));
209
+ exitCode = 1;
210
+ }
211
+ if (exitCode !== 0) {
212
+ process.exit(exitCode);
213
+ }
214
+ }
215
+ if (require.main === module) {
216
+ main();
217
+ }
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ /**
3
+ * Commit Pattern Detector
4
+ *
5
+ * Analyzes git commit patterns to detect anti-patterns like:
6
+ * - Generic/vague messages
7
+ * - Repetitive patterns
8
+ * - Single-commit dumps
9
+ * - Non-incremental commits
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.CommitPatternDetector = void 0;
13
+ /**
14
+ * Generic/vague message patterns that indicate low quality
15
+ */
16
+ const GENERIC_PATTERNS = [
17
+ /^update/i,
18
+ /^fix$/i,
19
+ /^fix bug/i,
20
+ /^changes$/i,
21
+ /^wip$/i,
22
+ /^work in progress/i,
23
+ /^temp$/i,
24
+ /^temporary/i,
25
+ /^misc/i,
26
+ /^various/i,
27
+ /^stuff$/i,
28
+ /^code$/i,
29
+ /^update code/i,
30
+ /^fix code/i,
31
+ /^fix issue/i,
32
+ /^address.*feedback/i,
33
+ /^pr feedback/i,
34
+ /^refactor$/i,
35
+ /^cleanup$/i,
36
+ /^done$/i,
37
+ /^complete$/i
38
+ ];
39
+ /**
40
+ * Detects commit anti-patterns in a branch's history
41
+ */
42
+ class CommitPatternDetector {
43
+ /**
44
+ * Analyze commit patterns for quality
45
+ */
46
+ analyzeCommits(commits) {
47
+ if (commits.length === 0) {
48
+ return {
49
+ hasAntiPatterns: false,
50
+ warnings: [],
51
+ score: 100,
52
+ details: {
53
+ genericMessages: 0,
54
+ repetitivePatterns: 0,
55
+ singleCommitDump: false,
56
+ averageFilesPerCommit: 0,
57
+ commitCount: 0
58
+ }
59
+ };
60
+ }
61
+ const warnings = [];
62
+ let score = 100;
63
+ // Check for generic messages
64
+ const genericCount = commits.filter(c => GENERIC_PATTERNS.some(pattern => pattern.test(c.message))).length;
65
+ if (genericCount > 0) {
66
+ warnings.push(`Found ${genericCount} generic/vague commit message(s)`);
67
+ score -= genericCount * 15;
68
+ }
69
+ // Check for repetitive patterns (same message multiple times)
70
+ const messageFrequency = new Map();
71
+ for (const commit of commits) {
72
+ const normalized = commit.message.toLowerCase().trim();
73
+ messageFrequency.set(normalized, (messageFrequency.get(normalized) || 0) + 1);
74
+ }
75
+ const repetitiveCount = Array.from(messageFrequency.values()).filter(count => count > 2).length;
76
+ if (repetitiveCount > 0) {
77
+ warnings.push(`Found ${repetitiveCount} repetitive commit message pattern(s)`);
78
+ score -= repetitiveCount * 20;
79
+ }
80
+ // Check for single-commit dump (one commit with many files)
81
+ const singleCommitDump = commits.length === 1 && commits[0].files.length > 5;
82
+ if (singleCommitDump) {
83
+ warnings.push('Single-commit dump detected (one commit with many files)');
84
+ score -= 30;
85
+ }
86
+ // Check for non-incremental work (too many files per commit on average)
87
+ const totalFiles = commits.reduce((sum, c) => sum + c.files.length, 0);
88
+ const avgFilesPerCommit = totalFiles / commits.length;
89
+ if (avgFilesPerCommit > 8 && commits.length > 1) {
90
+ warnings.push(`High files-per-commit average (${avgFilesPerCommit.toFixed(1)}), suggests non-incremental work`);
91
+ score -= 15;
92
+ }
93
+ // Check for too few commits given file count
94
+ if (commits.length === 1 && totalFiles > 3) {
95
+ warnings.push('Too few commits for amount of work (should break into logical chunks)');
96
+ score -= 20;
97
+ }
98
+ // Ensure score stays in 0-100 range
99
+ score = Math.max(0, Math.min(100, score));
100
+ return {
101
+ hasAntiPatterns: warnings.length > 0,
102
+ warnings,
103
+ score,
104
+ details: {
105
+ genericMessages: genericCount,
106
+ repetitivePatterns: repetitiveCount,
107
+ singleCommitDump,
108
+ averageFilesPerCommit: parseFloat(avgFilesPerCommit.toFixed(1)),
109
+ commitCount: commits.length
110
+ }
111
+ };
112
+ }
113
+ /**
114
+ * Check if a single commit message is problematic
115
+ */
116
+ isGenericMessage(message) {
117
+ return GENERIC_PATTERNS.some(pattern => pattern.test(message));
118
+ }
119
+ /**
120
+ * Get suggestions for improving commit quality
121
+ */
122
+ getSuggestions(result) {
123
+ const suggestions = [];
124
+ if (result.details.genericMessages > 0) {
125
+ suggestions.push('Use specific, descriptive commit messages (e.g., "add user authentication API" not "update code")');
126
+ }
127
+ if (result.details.repetitivePatterns > 0) {
128
+ suggestions.push('Vary commit messages to reflect different work done');
129
+ }
130
+ if (result.details.singleCommitDump) {
131
+ suggestions.push('Break work into multiple logical commits (e.g., separate commits for API, tests, docs)');
132
+ }
133
+ if (result.details.averageFilesPerCommit > 8) {
134
+ suggestions.push('Make smaller, more focused commits (aim for 2-5 files per commit)');
135
+ }
136
+ if (result.score < 70) {
137
+ suggestions.push('Review git commit guidelines in your agent instructions for examples');
138
+ }
139
+ return suggestions;
140
+ }
141
+ }
142
+ exports.CommitPatternDetector = CommitPatternDetector;
143
+ exports.default = CommitPatternDetector;
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.analyzeCommitQuality = analyzeCommitQuality;
4
+ const commit_pattern_detector_1 = require("./commit-pattern-detector");
5
+ const logger_1 = require("./logger");
6
+ const logger = (0, logger_1.getLogger)('commit-quality');
7
+ async function analyzeCommitQuality(commits, stepNumber, agentName) {
8
+ if (commits.length === 0)
9
+ return;
10
+ const detector = new commit_pattern_detector_1.CommitPatternDetector();
11
+ // Convert to CommitMessage format; parsed commits may carry extra
12
+ // fields (timestamp, files) beyond the ShareIndex schema
13
+ const commitMessages = commits.map(c => {
14
+ const extra = c;
15
+ return {
16
+ hash: c.sha || 'unknown',
17
+ message: c.message || '',
18
+ timestamp: extra.timestamp ? new Date(extra.timestamp) : new Date(),
19
+ files: extra.files || []
20
+ };
21
+ });
22
+ const result = detector.analyzeCommits(commitMessages);
23
+ // Surface anti-patterns; suppress the "all good" announcement so passing
24
+ // steps stay quiet and the live status block carries the success signal.
25
+ if (result.hasAntiPatterns) {
26
+ logger.warn(` commit-quality warnings · step ${stepNumber} (${agentName}) · score ${result.score}/100`);
27
+ result.warnings.forEach(warning => {
28
+ logger.warn(` - ${warning}`);
29
+ });
30
+ const suggestions = detector.getSuggestions(result);
31
+ if (suggestions.length > 0) {
32
+ logger.warn(` suggestions:`);
33
+ suggestions.forEach(suggestion => {
34
+ logger.warn(` - ${suggestion}`);
35
+ });
36
+ }
37
+ }
38
+ }