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.
- package/LICENSE +15 -0
- package/README.md +199 -0
- package/agents/reviewer.agent.md +50 -0
- package/agents/worker.agent.md +41 -0
- package/config/default-agents.yaml +56 -0
- package/config/pm-agent.yaml +36 -0
- package/config/quality-gates.yaml +88 -0
- package/config/repair-agent.yaml +34 -0
- package/config/semgrep-rules/complexity-mismatch.yaml +6 -0
- package/config/semgrep-rules/exception-swallowing.yaml +13 -0
- package/config/semgrep-rules/hardcoded-answer.yaml +6 -0
- package/config/semgrep-rules/mock-mutation.yaml +6 -0
- package/config/semgrep-rules/test-modification.yaml +6 -0
- package/config/user-agents.yaml +23 -0
- package/dist/src/adapters/adapter-factory.js +29 -0
- package/dist/src/adapters/agent-adapter.js +32 -0
- package/dist/src/adapters/claude-code-adapter.js +126 -0
- package/dist/src/adapters/claude-code-teams.js +119 -0
- package/dist/src/adapters/codex-adapter.js +118 -0
- package/dist/src/adapters/copilot-adapter.js +224 -0
- package/dist/src/adapters/fatal-error-classifier.js +88 -0
- package/dist/src/adapters/index.js +44 -0
- package/dist/src/adapters/persistent-session.js +204 -0
- package/dist/src/adapters/process-supervisor.js +199 -0
- package/dist/src/agents-exporter.js +398 -0
- package/dist/src/analytics-log.js +161 -0
- package/dist/src/baseline-scanner.js +65 -0
- package/dist/src/bootstrap-evidence.js +88 -0
- package/dist/src/bootstrap-orchestrator.js +205 -0
- package/dist/src/bootstrap-types.js +5 -0
- package/dist/src/branch-merger.js +427 -0
- package/dist/src/cli/attest-handlers.js +44 -0
- package/dist/src/cli/cost-prompt.js +51 -0
- package/dist/src/cli/demo-handlers.js +274 -0
- package/dist/src/cli/flags.js +152 -0
- package/dist/src/cli/index.js +57 -0
- package/dist/src/cli/live-status.js +186 -0
- package/dist/src/cli/misc-handlers.js +242 -0
- package/dist/src/cli/plan-handlers.js +350 -0
- package/dist/src/cli/share-handlers.js +163 -0
- package/dist/src/cli/status-handlers.js +457 -0
- package/dist/src/cli/swarm-handlers.js +638 -0
- package/dist/src/cli/usage.js +72 -0
- package/dist/src/cli.js +217 -0
- package/dist/src/commit-pattern-detector.js +143 -0
- package/dist/src/commit-quality-analyzer.js +38 -0
- package/dist/src/config-loader.js +339 -0
- package/dist/src/context-broker.js +358 -0
- package/dist/src/copilot-cli-wrapper.js +258 -0
- package/dist/src/cost-estimator.js +241 -0
- package/dist/src/defaults.js +18 -0
- package/dist/src/demo-mode.js +180 -0
- package/dist/src/deployment-handler.js +78 -0
- package/dist/src/deployment-manager.js +228 -0
- package/dist/src/execution-queue.js +196 -0
- package/dist/src/external-tool-manager.js +184 -0
- package/dist/src/gate-prompt-builder.js +117 -0
- package/dist/src/gate-remediation.js +173 -0
- package/dist/src/github-issues-ingester.js +152 -0
- package/dist/src/github-mcp-integrator.js +164 -0
- package/dist/src/hook-generator.js +229 -0
- package/dist/src/index.js +48 -0
- package/dist/src/knowledge-base.js +300 -0
- package/dist/src/logger.js +111 -0
- package/dist/src/meta-analyzer.js +208 -0
- package/dist/src/metrics-collector.js +209 -0
- package/dist/src/metrics-types.js +5 -0
- package/dist/src/multi-repo-coordinator.js +179 -0
- package/dist/src/orchestrator/async-meta-analysis.js +84 -0
- package/dist/src/orchestrator/fatal-run-error.js +43 -0
- package/dist/src/orchestrator/final-gates-remediation.js +258 -0
- package/dist/src/orchestrator/git-state-utils.js +119 -0
- package/dist/src/orchestrator/pause-controller.js +55 -0
- package/dist/src/orchestrator/replan-runner.js +258 -0
- package/dist/src/orchestrator/step-executor.js +391 -0
- package/dist/src/orchestrator/wave-scheduler-loop.js +204 -0
- package/dist/src/owasp-mapper.js +153 -0
- package/dist/src/owasp-report-renderer.js +39 -0
- package/dist/src/plan-files.js +142 -0
- package/dist/src/plan-generator.js +1207 -0
- package/dist/src/pm-agent.js +296 -0
- package/dist/src/post-run-reporter.js +203 -0
- package/dist/src/pr-automation.js +103 -0
- package/dist/src/pr-manager.js +318 -0
- package/dist/src/presenter/index.js +209 -0
- package/dist/src/prompt-builder.js +173 -0
- package/dist/src/quality-gates/config-loader.js +196 -0
- package/dist/src/quality-gates/default-config.js +243 -0
- package/dist/src/quality-gates/file-utils.js +152 -0
- package/dist/src/quality-gates/gate-runner.js +171 -0
- package/dist/src/quality-gates/gates/accessibility.js +355 -0
- package/dist/src/quality-gates/gates/duplicate-blocks.js +144 -0
- package/dist/src/quality-gates/gates/hardcoded-config.js +52 -0
- package/dist/src/quality-gates/gates/readme-claims.js +62 -0
- package/dist/src/quality-gates/gates/runtime-checks.js +265 -0
- package/dist/src/quality-gates/gates/scaffold-defaults.js +108 -0
- package/dist/src/quality-gates/gates/test-coverage.js +240 -0
- package/dist/src/quality-gates/gates/test-file-protection.js +85 -0
- package/dist/src/quality-gates/gates/test-isolation.js +74 -0
- package/dist/src/quality-gates/index.js +17 -0
- package/dist/src/quality-gates/registry.js +205 -0
- package/dist/src/quality-gates/types.js +2 -0
- package/dist/src/quick-fix-mode.js +302 -0
- package/dist/src/recipe-loader.js +122 -0
- package/dist/src/repair-agent.js +396 -0
- package/dist/src/repo-analyzer.js +342 -0
- package/dist/src/report-generator.js +146 -0
- package/dist/src/report-renderer.js +90 -0
- package/dist/src/requirement-filter.js +52 -0
- package/dist/src/sarif-formatter.js +140 -0
- package/dist/src/scheduling/dependency-analyzer.js +178 -0
- package/dist/src/scheduling/work-stealing-queue.js +123 -0
- package/dist/src/secret-redactor.js +90 -0
- package/dist/src/session-executor.js +587 -0
- package/dist/src/session-manager.js +221 -0
- package/dist/src/share/transcript-verification.js +128 -0
- package/dist/src/share-parser.js +477 -0
- package/dist/src/spinner.js +146 -0
- package/dist/src/step-runner.js +365 -0
- package/dist/src/swarm-orchestrator.js +686 -0
- package/dist/src/task-classifier.js +134 -0
- package/dist/src/test-command-discovery.js +123 -0
- package/dist/src/text-similarity.js +24 -0
- package/dist/src/tier-maps.js +158 -0
- package/dist/src/types.js +5 -0
- package/dist/src/url-shortener.js +135 -0
- package/dist/src/verification/attestation.js +166 -0
- package/dist/src/verification/cheat-detector.js +240 -0
- package/dist/src/verification/command-runner.js +70 -0
- package/dist/src/verification/composite-score.js +157 -0
- package/dist/src/verification/cosign-attestation.js +137 -0
- package/dist/src/verification/diff-analysis.js +89 -0
- package/dist/src/verification/differential-gate.js +173 -0
- package/dist/src/verification/index.js +41 -0
- package/dist/src/verification/mutation-gate.js +242 -0
- package/dist/src/verification/property-gate.js +201 -0
- package/dist/src/verification/test-synthesizer.js +243 -0
- package/dist/src/verifier/outcome-checks.js +396 -0
- package/dist/src/verifier/transcript-checks.js +207 -0
- package/dist/src/verifier/verification-reporters.js +148 -0
- package/dist/src/verifier-engine.js +491 -0
- package/dist/src/wave-resizer.js +131 -0
- package/dist/src/wave-scheduler.js +44 -0
- package/dist/src/worktree-manager.js +368 -0
- package/dist/src/worktree-reserved-paths.js +97 -0
- package/package.json +80 -0
- package/plugin/agents/.gitkeep +0 -0
- package/plugin/agents/backend_master.agent.md +72 -0
- package/plugin/agents/devops_pro.agent.md +45 -0
- package/plugin/agents/frontend_expert.agent.md +59 -0
- package/plugin/agents/integrator_finalizer.agent.md +44 -0
- package/plugin/agents/meta_reviewer.agent.md +44 -0
- package/plugin/agents/security_auditor.agent.md +43 -0
- package/plugin/agents/tester_elite.agent.md +43 -0
- package/plugin/hooks/hooks.json +19 -0
- package/plugin/hooks/post-tool-use.json +9 -0
- package/plugin/hooks/pre-tool-use.json +9 -0
- package/plugin/plugin.json +47 -0
- package/plugin/skills/swarm-gates/SKILL.md +53 -0
- package/plugin/skills/swarm-orchestrate/SKILL.md +34 -0
- package/plugin/skills/swarm-verify/SKILL.md +44 -0
- package/templates/README.md +35 -0
- package/templates/cli-tool.json +31 -0
- package/templates/fullstack.json +52 -0
- package/templates/library.json +38 -0
- package/templates/react-app.json +45 -0
- package/templates/recipes/add-api-docs.json +35 -0
- package/templates/recipes/add-auth.json +47 -0
- package/templates/recipes/add-ci.json +39 -0
- package/templates/recipes/add-tests.json +39 -0
- package/templates/recipes/migrate-to-ts.json +42 -0
- package/templates/recipes/refactor-modularize.json +44 -0
- package/templates/recipes/security-audit.json +35 -0
- package/templates/rest-api.json +38 -0
|
@@ -0,0 +1,342 @@
|
|
|
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.RepoAnalyzer = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
/**
|
|
40
|
+
* Repo Analyzer - deep static analysis of repository structure
|
|
41
|
+
* NO GUESSING - only provable signals from actual files
|
|
42
|
+
*/
|
|
43
|
+
class RepoAnalyzer {
|
|
44
|
+
/**
|
|
45
|
+
* Analyze a single repository
|
|
46
|
+
*/
|
|
47
|
+
async analyzeRepo(repoPath) {
|
|
48
|
+
if (!fs.existsSync(repoPath)) {
|
|
49
|
+
throw new Error(`Repository path does not exist: ${repoPath}`);
|
|
50
|
+
}
|
|
51
|
+
const repoName = path.basename(repoPath);
|
|
52
|
+
const gitRemote = this.getGitRemote(repoPath);
|
|
53
|
+
const analysis = {
|
|
54
|
+
repoPath,
|
|
55
|
+
repoName,
|
|
56
|
+
languages: await this.detectLanguages(repoPath),
|
|
57
|
+
buildScripts: await this.findBuildScripts(repoPath),
|
|
58
|
+
testScripts: await this.findTestScripts(repoPath),
|
|
59
|
+
dependencies: await this.extractDependencies(repoPath),
|
|
60
|
+
techDebtMarkers: await this.findTechDebtMarkers(repoPath),
|
|
61
|
+
baselineConcerns: await this.identifyBaselineConcerns(repoPath),
|
|
62
|
+
...(gitRemote && { gitRemote })
|
|
63
|
+
};
|
|
64
|
+
return analysis;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Detect languages from file extensions (no guessing)
|
|
68
|
+
*/
|
|
69
|
+
async detectLanguages(repoPath) {
|
|
70
|
+
const extensionMap = {
|
|
71
|
+
'.ts': 'TypeScript',
|
|
72
|
+
'.js': 'JavaScript',
|
|
73
|
+
'.tsx': 'TypeScript',
|
|
74
|
+
'.jsx': 'JavaScript',
|
|
75
|
+
'.py': 'Python',
|
|
76
|
+
'.go': 'Go',
|
|
77
|
+
'.java': 'Java',
|
|
78
|
+
'.rb': 'Ruby',
|
|
79
|
+
'.rs': 'Rust',
|
|
80
|
+
'.c': 'C',
|
|
81
|
+
'.cpp': 'C++',
|
|
82
|
+
'.cs': 'C#'
|
|
83
|
+
};
|
|
84
|
+
const languages = new Set();
|
|
85
|
+
// Scan src/ directory if exists
|
|
86
|
+
const srcDir = path.join(repoPath, 'src');
|
|
87
|
+
if (fs.existsSync(srcDir)) {
|
|
88
|
+
this.scanDirectoryForExtensions(srcDir, extensionMap, languages);
|
|
89
|
+
}
|
|
90
|
+
// Scan root level too
|
|
91
|
+
const rootFiles = fs.readdirSync(repoPath);
|
|
92
|
+
for (const file of rootFiles) {
|
|
93
|
+
const ext = path.extname(file);
|
|
94
|
+
if (extensionMap[ext]) {
|
|
95
|
+
languages.add(extensionMap[ext]);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return Array.from(languages).sort();
|
|
99
|
+
}
|
|
100
|
+
scanDirectoryForExtensions(dir, extensionMap, languages) {
|
|
101
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
102
|
+
for (const entry of entries) {
|
|
103
|
+
if (entry.name.startsWith('.'))
|
|
104
|
+
continue;
|
|
105
|
+
if (entry.name === 'node_modules')
|
|
106
|
+
continue;
|
|
107
|
+
const fullPath = path.join(dir, entry.name);
|
|
108
|
+
if (entry.isDirectory()) {
|
|
109
|
+
this.scanDirectoryForExtensions(fullPath, extensionMap, languages);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
const ext = path.extname(entry.name);
|
|
113
|
+
if (extensionMap[ext]) {
|
|
114
|
+
languages.add(extensionMap[ext]);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Find build scripts from package.json, Makefile, etc.
|
|
121
|
+
*/
|
|
122
|
+
async findBuildScripts(repoPath) {
|
|
123
|
+
const scripts = [];
|
|
124
|
+
// Check package.json
|
|
125
|
+
const packageJsonPath = path.join(repoPath, 'package.json');
|
|
126
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
127
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
128
|
+
if (pkg.scripts) {
|
|
129
|
+
const buildLikeScripts = ['build', 'compile', 'dist', 'bundle'];
|
|
130
|
+
for (const scriptName of buildLikeScripts) {
|
|
131
|
+
if (pkg.scripts[scriptName]) {
|
|
132
|
+
scripts.push({
|
|
133
|
+
name: scriptName,
|
|
134
|
+
command: pkg.scripts[scriptName],
|
|
135
|
+
source: `package.json:scripts.${scriptName}`
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// Check Makefile
|
|
142
|
+
const makefilePath = path.join(repoPath, 'Makefile');
|
|
143
|
+
if (fs.existsSync(makefilePath)) {
|
|
144
|
+
const content = fs.readFileSync(makefilePath, 'utf8');
|
|
145
|
+
const buildTarget = content.match(/^build:/m);
|
|
146
|
+
if (buildTarget) {
|
|
147
|
+
scripts.push({
|
|
148
|
+
name: 'build',
|
|
149
|
+
command: 'make build',
|
|
150
|
+
source: 'Makefile:build'
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return scripts;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Find test scripts
|
|
158
|
+
*/
|
|
159
|
+
async findTestScripts(repoPath) {
|
|
160
|
+
const scripts = [];
|
|
161
|
+
// Check package.json
|
|
162
|
+
const packageJsonPath = path.join(repoPath, 'package.json');
|
|
163
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
164
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
165
|
+
if (pkg.scripts?.test) {
|
|
166
|
+
let framework;
|
|
167
|
+
// Detect test framework from command
|
|
168
|
+
if (pkg.scripts.test.includes('mocha'))
|
|
169
|
+
framework = 'mocha';
|
|
170
|
+
else if (pkg.scripts.test.includes('jest'))
|
|
171
|
+
framework = 'jest';
|
|
172
|
+
else if (pkg.scripts.test.includes('vitest'))
|
|
173
|
+
framework = 'vitest';
|
|
174
|
+
else if (pkg.scripts.test.includes('ava'))
|
|
175
|
+
framework = 'ava';
|
|
176
|
+
scripts.push({
|
|
177
|
+
name: 'test',
|
|
178
|
+
command: pkg.scripts.test,
|
|
179
|
+
source: 'package.json:scripts.test',
|
|
180
|
+
...(framework && { framework })
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return scripts;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Extract dependencies from package.json, go.mod, requirements.txt, etc.
|
|
188
|
+
*/
|
|
189
|
+
async extractDependencies(repoPath) {
|
|
190
|
+
const deps = [];
|
|
191
|
+
// package.json
|
|
192
|
+
const packageJsonPath = path.join(repoPath, 'package.json');
|
|
193
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
194
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
195
|
+
if (pkg.dependencies) {
|
|
196
|
+
for (const [name, version] of Object.entries(pkg.dependencies)) {
|
|
197
|
+
deps.push({
|
|
198
|
+
name,
|
|
199
|
+
version: version,
|
|
200
|
+
type: 'production',
|
|
201
|
+
source: 'package.json:dependencies'
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (pkg.devDependencies) {
|
|
206
|
+
for (const [name, version] of Object.entries(pkg.devDependencies)) {
|
|
207
|
+
deps.push({
|
|
208
|
+
name,
|
|
209
|
+
version: version,
|
|
210
|
+
type: 'development',
|
|
211
|
+
source: 'package.json:devDependencies'
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return deps;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Find tech debt markers
|
|
220
|
+
*/
|
|
221
|
+
async findTechDebtMarkers(repoPath) {
|
|
222
|
+
const markers = [];
|
|
223
|
+
// Look for .skip() in test files
|
|
224
|
+
const testDir = path.join(repoPath, 'test');
|
|
225
|
+
if (fs.existsSync(testDir)) {
|
|
226
|
+
this.findSkippedTests(testDir, markers);
|
|
227
|
+
}
|
|
228
|
+
// Look for TODO comments in src/
|
|
229
|
+
const srcDir = path.join(repoPath, 'src');
|
|
230
|
+
if (fs.existsSync(srcDir)) {
|
|
231
|
+
this.findTodoComments(srcDir, markers);
|
|
232
|
+
}
|
|
233
|
+
return markers;
|
|
234
|
+
}
|
|
235
|
+
findSkippedTests(dir, markers) {
|
|
236
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
237
|
+
for (const entry of entries) {
|
|
238
|
+
if (entry.name.startsWith('.'))
|
|
239
|
+
continue;
|
|
240
|
+
const fullPath = path.join(dir, entry.name);
|
|
241
|
+
if (entry.isDirectory()) {
|
|
242
|
+
this.findSkippedTests(fullPath, markers);
|
|
243
|
+
}
|
|
244
|
+
else if (entry.name.endsWith('.test.ts') || entry.name.endsWith('.test.js')) {
|
|
245
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
246
|
+
const lines = content.split('\n');
|
|
247
|
+
lines.forEach((line, idx) => {
|
|
248
|
+
if (line.includes('.skip(') || line.includes('it.skip(') || line.includes('describe.skip(')) {
|
|
249
|
+
markers.push({
|
|
250
|
+
type: 'skipped_test',
|
|
251
|
+
location: `${fullPath}:${idx + 1}`,
|
|
252
|
+
evidence: line.trim(),
|
|
253
|
+
severity: 'medium'
|
|
254
|
+
});
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
findTodoComments(dir, markers) {
|
|
261
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
262
|
+
for (const entry of entries) {
|
|
263
|
+
if (entry.name.startsWith('.'))
|
|
264
|
+
continue;
|
|
265
|
+
if (entry.name === 'node_modules')
|
|
266
|
+
continue;
|
|
267
|
+
const fullPath = path.join(dir, entry.name);
|
|
268
|
+
if (entry.isDirectory()) {
|
|
269
|
+
this.findTodoComments(fullPath, markers);
|
|
270
|
+
}
|
|
271
|
+
else if (entry.name.endsWith('.ts') || entry.name.endsWith('.js')) {
|
|
272
|
+
const content = fs.readFileSync(fullPath, 'utf8');
|
|
273
|
+
const lines = content.split('\n');
|
|
274
|
+
lines.forEach((line, idx) => {
|
|
275
|
+
if (line.includes('TODO') || line.includes('FIXME')) {
|
|
276
|
+
markers.push({
|
|
277
|
+
type: 'todo_comment',
|
|
278
|
+
location: `${fullPath}:${idx + 1}`,
|
|
279
|
+
evidence: line.trim(),
|
|
280
|
+
severity: 'low'
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Identify missing baseline concerns
|
|
289
|
+
*/
|
|
290
|
+
async identifyBaselineConcerns(repoPath) {
|
|
291
|
+
const concerns = [];
|
|
292
|
+
// Check for CI config
|
|
293
|
+
const ciPaths = [
|
|
294
|
+
'.github/workflows',
|
|
295
|
+
'.gitlab-ci.yml',
|
|
296
|
+
'.circleci/config.yml',
|
|
297
|
+
'Jenkinsfile'
|
|
298
|
+
];
|
|
299
|
+
const hasCi = ciPaths.some(p => fs.existsSync(path.join(repoPath, p)));
|
|
300
|
+
if (!hasCi) {
|
|
301
|
+
concerns.push({
|
|
302
|
+
type: 'missing_ci',
|
|
303
|
+
reason: 'No CI configuration detected',
|
|
304
|
+
evidence: `Checked: ${ciPaths.join(', ')}`
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
// Check for config management (only if src/ exists)
|
|
308
|
+
const srcDir = path.join(repoPath, 'src');
|
|
309
|
+
if (fs.existsSync(srcDir)) {
|
|
310
|
+
const hasConfigFile = ['config.ts', 'config.js', '.env.example', 'config.json']
|
|
311
|
+
.some(f => fs.existsSync(path.join(repoPath, f)) || fs.existsSync(path.join(srcDir, f)));
|
|
312
|
+
if (!hasConfigFile) {
|
|
313
|
+
concerns.push({
|
|
314
|
+
type: 'missing_config',
|
|
315
|
+
reason: 'No config management detected',
|
|
316
|
+
evidence: 'Checked: config.ts, config.js, .env.example, config.json'
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
return concerns;
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Get git remote URL
|
|
324
|
+
*/
|
|
325
|
+
getGitRemote(repoPath) {
|
|
326
|
+
const gitConfigPath = path.join(repoPath, '.git', 'config');
|
|
327
|
+
if (!fs.existsSync(gitConfigPath)) {
|
|
328
|
+
return undefined;
|
|
329
|
+
}
|
|
330
|
+
try {
|
|
331
|
+
const content = fs.readFileSync(gitConfigPath, 'utf8');
|
|
332
|
+
const match = content.match(/url\s*=\s*(.+)/);
|
|
333
|
+
return match ? match[1].trim() : undefined;
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
// .git/config unreadable; remote URL is optional metadata
|
|
337
|
+
return undefined;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
exports.RepoAnalyzer = RepoAnalyzer;
|
|
342
|
+
exports.default = RepoAnalyzer;
|
|
@@ -0,0 +1,146 @@
|
|
|
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.ReportGenerator = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
function readJsonSafe(filePath) {
|
|
40
|
+
try {
|
|
41
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
42
|
+
return JSON.parse(raw);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function readJsonRequired(filePath, label) {
|
|
49
|
+
if (!fs.existsSync(filePath)) {
|
|
50
|
+
throw new Error(`${label} not found at ${filePath}`);
|
|
51
|
+
}
|
|
52
|
+
const raw = fs.readFileSync(filePath, 'utf8');
|
|
53
|
+
return JSON.parse(raw);
|
|
54
|
+
}
|
|
55
|
+
class ReportGenerator {
|
|
56
|
+
generate(runDir) {
|
|
57
|
+
if (!fs.existsSync(runDir)) {
|
|
58
|
+
throw new Error(`Run directory not found: ${runDir}`);
|
|
59
|
+
}
|
|
60
|
+
const sessionState = readJsonRequired(path.join(runDir, 'session-state.json'), 'session-state.json');
|
|
61
|
+
const metrics = readJsonRequired(path.join(runDir, 'metrics.json'), 'metrics.json');
|
|
62
|
+
const costAttribution = readJsonSafe(path.join(runDir, 'cost-attribution.json'));
|
|
63
|
+
const owaspRaw = readJsonSafe(path.join(runDir, 'owasp-compliance.json'));
|
|
64
|
+
const falsificationBattery = readJsonSafe(path.join(runDir, 'falsification-battery.json'));
|
|
65
|
+
// Build a lookup for per-step cost data
|
|
66
|
+
const costByStep = new Map();
|
|
67
|
+
if (costAttribution?.perStep) {
|
|
68
|
+
for (const record of costAttribution.perStep) {
|
|
69
|
+
costByStep.set(record.stepNumber, record);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Identify repaired steps from recovery events
|
|
73
|
+
const repairedSteps = new Set();
|
|
74
|
+
if (metrics.recoveryEvents) {
|
|
75
|
+
for (const event of metrics.recoveryEvents) {
|
|
76
|
+
repairedSteps.add(event.stepNumber);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
const steps = sessionState.graph.steps.map(step => {
|
|
80
|
+
const costRecord = costByStep.get(step.stepNumber);
|
|
81
|
+
const wasRepaired = repairedSteps.has(step.stepNumber);
|
|
82
|
+
// Determine verification status from session state
|
|
83
|
+
let verificationStatus = 'passed';
|
|
84
|
+
if (wasRepaired) {
|
|
85
|
+
verificationStatus = 'repaired';
|
|
86
|
+
}
|
|
87
|
+
else if (sessionState.status === 'failed' && step.stepNumber > sessionState.lastCompletedStep) {
|
|
88
|
+
verificationStatus = 'failed';
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
stepNumber: step.stepNumber,
|
|
92
|
+
agentName: step.agent,
|
|
93
|
+
task: step.task,
|
|
94
|
+
verificationStatus,
|
|
95
|
+
checksPassed: [],
|
|
96
|
+
checksFailed: [],
|
|
97
|
+
repairAttempts: wasRepaired ? 1 : 0,
|
|
98
|
+
estimatedCost: costRecord?.estimatedPremiumRequests ?? null,
|
|
99
|
+
actualCost: costRecord?.actualPremiumRequests ?? null,
|
|
100
|
+
durationMs: costRecord?.durationMs ?? 0
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
const failedCount = steps.filter(s => s.verificationStatus === 'failed').length;
|
|
104
|
+
const repairedCount = steps.filter(s => s.verificationStatus === 'repaired').length;
|
|
105
|
+
const passedCount = steps.length - failedCount - repairedCount;
|
|
106
|
+
return {
|
|
107
|
+
executionId: path.basename(runDir),
|
|
108
|
+
goal: sessionState.graph.goal,
|
|
109
|
+
tool: 'swarm-orchestrator',
|
|
110
|
+
model: costAttribution?.modelUsed ?? 'unknown',
|
|
111
|
+
startedAt: metrics.startTime,
|
|
112
|
+
completedAt: metrics.endTime,
|
|
113
|
+
durationMs: metrics.totalTimeMs,
|
|
114
|
+
steps,
|
|
115
|
+
results: {
|
|
116
|
+
attempted: steps.length,
|
|
117
|
+
passed: passedCount,
|
|
118
|
+
failed: failedCount,
|
|
119
|
+
repaired: repairedCount
|
|
120
|
+
},
|
|
121
|
+
waves: {
|
|
122
|
+
count: metrics.waveCount
|
|
123
|
+
},
|
|
124
|
+
cost: costAttribution ? {
|
|
125
|
+
estimatedPremiumRequests: costAttribution.totalEstimatedPremiumRequests,
|
|
126
|
+
actualPremiumRequests: costAttribution.totalActualPremiumRequests,
|
|
127
|
+
accuracy: costAttribution.estimateAccuracy,
|
|
128
|
+
modelMultiplier: costAttribution.modelMultiplier,
|
|
129
|
+
overageTriggered: costAttribution.overageTriggered
|
|
130
|
+
} : null,
|
|
131
|
+
owaspSummary: owaspRaw ? {
|
|
132
|
+
applicableRisks: owaspRaw.applicableRisks,
|
|
133
|
+
mitigatedRisks: owaspRaw.mitigatedRisks,
|
|
134
|
+
partialRisks: owaspRaw.partialRisks
|
|
135
|
+
} : null,
|
|
136
|
+
verification: {
|
|
137
|
+
totalGitDiffs: metrics.commitCount,
|
|
138
|
+
buildPasses: metrics.verificationsPassed,
|
|
139
|
+
testPasses: metrics.verificationsPassed,
|
|
140
|
+
transcriptMatches: 0
|
|
141
|
+
},
|
|
142
|
+
falsificationBattery
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
exports.ReportGenerator = ReportGenerator;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ReportRenderer = void 0;
|
|
4
|
+
function formatDuration(ms) {
|
|
5
|
+
const seconds = Math.floor(ms / 1000);
|
|
6
|
+
const minutes = Math.floor(seconds / 60);
|
|
7
|
+
const remainingSeconds = seconds % 60;
|
|
8
|
+
if (minutes === 0)
|
|
9
|
+
return `${seconds}s`;
|
|
10
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
11
|
+
}
|
|
12
|
+
class ReportRenderer {
|
|
13
|
+
static toMarkdown(report) {
|
|
14
|
+
const lines = [
|
|
15
|
+
'# Swarm Orchestrator Run Report',
|
|
16
|
+
'',
|
|
17
|
+
`**Run:** ${report.executionId}`,
|
|
18
|
+
`**Goal:** ${report.goal}`,
|
|
19
|
+
`**Tool:** ${report.tool} | **Model:** ${report.model}`,
|
|
20
|
+
`**Duration:** ${formatDuration(report.durationMs)}`,
|
|
21
|
+
`**Date:** ${report.startedAt}`,
|
|
22
|
+
'',
|
|
23
|
+
'## Results',
|
|
24
|
+
'',
|
|
25
|
+
`Steps: ${report.results.attempted} attempted, ${report.results.passed} passed, ${report.results.failed} failed, ${report.results.repaired} repaired`,
|
|
26
|
+
`Waves: ${report.waves.count} waves`,
|
|
27
|
+
'',
|
|
28
|
+
'## Per-Step Detail',
|
|
29
|
+
'',
|
|
30
|
+
'| Step | Agent | Task | Status | Checks Passed | Repairs | Cost (est/actual) |',
|
|
31
|
+
'|------|-------|------|--------|---------------|---------|-------------------|'
|
|
32
|
+
];
|
|
33
|
+
for (const step of report.steps) {
|
|
34
|
+
const checks = step.checksPassed.length > 0 ? step.checksPassed.join(', ') : 'none';
|
|
35
|
+
const costStr = step.estimatedCost !== null && step.actualCost !== null
|
|
36
|
+
? `${step.estimatedCost} / ${step.actualCost}`
|
|
37
|
+
: 'n/a';
|
|
38
|
+
lines.push(`| ${step.stepNumber} | ${step.agentName} | ${step.task} | ${step.verificationStatus} | ${checks} | ${step.repairAttempts} | ${costStr} |`);
|
|
39
|
+
}
|
|
40
|
+
lines.push('');
|
|
41
|
+
if (report.cost) {
|
|
42
|
+
const accuracyPct = (report.cost.accuracy * 100).toFixed(1);
|
|
43
|
+
lines.push('## Cost Attribution');
|
|
44
|
+
lines.push('');
|
|
45
|
+
lines.push(`Estimated: ${report.cost.estimatedPremiumRequests} premium requests | Actual: ${report.cost.actualPremiumRequests} | Accuracy: ${accuracyPct}%`);
|
|
46
|
+
lines.push(`Model: ${report.model} (${report.cost.modelMultiplier}x multiplier)`);
|
|
47
|
+
lines.push(`Overage: ${report.cost.overageTriggered ? 'yes' : 'no'}`);
|
|
48
|
+
lines.push('');
|
|
49
|
+
}
|
|
50
|
+
lines.push('## Verification Evidence');
|
|
51
|
+
lines.push('');
|
|
52
|
+
lines.push(`Git diffs: ${report.verification.totalGitDiffs} | Build passes: ${report.verification.buildPasses} | Test passes: ${report.verification.testPasses} | Transcript matches: ${report.verification.transcriptMatches}`);
|
|
53
|
+
lines.push('');
|
|
54
|
+
if (report.falsificationBattery) {
|
|
55
|
+
lines.push('## Falsification Battery');
|
|
56
|
+
lines.push('');
|
|
57
|
+
lines.push(`Composite score: ${report.falsificationBattery.compositeScore}`);
|
|
58
|
+
lines.push(`Human review: ${report.falsificationBattery.humanReviewRequired ? 'yes' : 'no'}`);
|
|
59
|
+
for (const layer of report.falsificationBattery.layers) {
|
|
60
|
+
lines.push(`- ${layer.layer}: ${layer.status} (${layer.durationMs}ms) ${layer.evidenceSummary}`);
|
|
61
|
+
}
|
|
62
|
+
lines.push('');
|
|
63
|
+
}
|
|
64
|
+
if (report.owaspSummary) {
|
|
65
|
+
lines.push('## OWASP Compliance');
|
|
66
|
+
lines.push('');
|
|
67
|
+
lines.push(`Applicable risks: ${report.owaspSummary.applicableRisks}/10 | Mitigated: ${report.owaspSummary.mitigatedRisks} | Partial: ${report.owaspSummary.partialRisks}`);
|
|
68
|
+
lines.push('');
|
|
69
|
+
}
|
|
70
|
+
return lines.join('\n');
|
|
71
|
+
}
|
|
72
|
+
static toJson(report) {
|
|
73
|
+
return JSON.stringify(report, null, 2);
|
|
74
|
+
}
|
|
75
|
+
static toSummaryLine(report) {
|
|
76
|
+
const parts = [
|
|
77
|
+
`Run ${report.executionId}:`,
|
|
78
|
+
`${report.results.passed}/${report.results.attempted} steps passed`,
|
|
79
|
+
`| ${report.waves.count} waves`
|
|
80
|
+
];
|
|
81
|
+
if (report.cost) {
|
|
82
|
+
parts.push(`| ${report.cost.actualPremiumRequests} premium requests (est ${report.cost.estimatedPremiumRequests})`);
|
|
83
|
+
}
|
|
84
|
+
if (report.owaspSummary) {
|
|
85
|
+
parts.push(`| OWASP ${report.owaspSummary.mitigatedRisks}/${report.owaspSummary.applicableRisks} mitigated`);
|
|
86
|
+
}
|
|
87
|
+
return parts.join(' ');
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
exports.ReportRenderer = ReportRenderer;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Connects task classification to tier maps and produces
|
|
3
|
+
// filtered requirements for agent prompt injection.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.RequirementFilter = void 0;
|
|
6
|
+
class RequirementFilter {
|
|
7
|
+
tierMaps;
|
|
8
|
+
constructor(tierMaps) {
|
|
9
|
+
this.tierMaps = tierMaps;
|
|
10
|
+
}
|
|
11
|
+
filter(classification) {
|
|
12
|
+
const requirements = this.tierMaps[classification.taskType] || [];
|
|
13
|
+
const enforced = [];
|
|
14
|
+
const recommended = [];
|
|
15
|
+
const skipped = [];
|
|
16
|
+
for (const req of requirements) {
|
|
17
|
+
switch (req.tier) {
|
|
18
|
+
case 'enforce':
|
|
19
|
+
enforced.push(req);
|
|
20
|
+
break;
|
|
21
|
+
case 'recommend':
|
|
22
|
+
recommended.push(req);
|
|
23
|
+
break;
|
|
24
|
+
case 'skip':
|
|
25
|
+
skipped.push(req);
|
|
26
|
+
break;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return { taskType: classification.taskType, enforced, recommended, skipped };
|
|
30
|
+
}
|
|
31
|
+
toPromptInjection(filtered) {
|
|
32
|
+
const sections = [];
|
|
33
|
+
if (filtered.enforced.length > 0) {
|
|
34
|
+
sections.push('## Required (these are mandatory, your code will be rejected if missing):');
|
|
35
|
+
for (const req of filtered.enforced) {
|
|
36
|
+
sections.push(`- ${req.description}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (filtered.recommended.length > 0) {
|
|
40
|
+
if (sections.length > 0)
|
|
41
|
+
sections.push('');
|
|
42
|
+
sections.push('## Recommended (include where applicable):');
|
|
43
|
+
for (const req of filtered.recommended) {
|
|
44
|
+
sections.push(`- ${req.description}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
// Tier 3 (skip) items are intentionally absent from the prompt.
|
|
48
|
+
// Not mentioned, not suggested, not hinted at.
|
|
49
|
+
return sections.join('\n');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
exports.RequirementFilter = RequirementFilter;
|