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,398 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Generates empirically-derived .agent.md files from execution history.
|
|
3
|
+
// Reads knowledge base patterns across runs, aggregates per-agent stats,
|
|
4
|
+
// and produces agent definitions enriched with learned conventions.
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
17
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
18
|
+
}) : function(o, v) {
|
|
19
|
+
o["default"] = v;
|
|
20
|
+
});
|
|
21
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
22
|
+
var ownKeys = function(o) {
|
|
23
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
24
|
+
var ar = [];
|
|
25
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
26
|
+
return ar;
|
|
27
|
+
};
|
|
28
|
+
return ownKeys(o);
|
|
29
|
+
};
|
|
30
|
+
return function (mod) {
|
|
31
|
+
if (mod && mod.__esModule) return mod;
|
|
32
|
+
var result = {};
|
|
33
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
34
|
+
__setModuleDefault(result, mod);
|
|
35
|
+
return result;
|
|
36
|
+
};
|
|
37
|
+
})();
|
|
38
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
39
|
+
exports.AgentsExporter = void 0;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const config_loader_1 = require("./config-loader");
|
|
43
|
+
// 30-day half-life for exponential decay weighting
|
|
44
|
+
const HALF_LIFE_DAYS = 30;
|
|
45
|
+
/**
|
|
46
|
+
* Reads knowledge base data from execution history and generates
|
|
47
|
+
* .agent.md files with learned conventions baked into the instructions.
|
|
48
|
+
*/
|
|
49
|
+
class AgentsExporter {
|
|
50
|
+
runsDir;
|
|
51
|
+
configLoader;
|
|
52
|
+
constructor(workingDir) {
|
|
53
|
+
const baseDir = workingDir || process.cwd();
|
|
54
|
+
this.runsDir = path.join(baseDir, 'runs');
|
|
55
|
+
this.configLoader = new config_loader_1.ConfigLoader();
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Export all agents as .agent.md files.
|
|
59
|
+
* If sufficient run data exists, enriches base definitions with learned patterns.
|
|
60
|
+
* Otherwise, generates from base definitions with a note about needing more data.
|
|
61
|
+
*/
|
|
62
|
+
export(options) {
|
|
63
|
+
if (!fs.existsSync(options.outputDir)) {
|
|
64
|
+
fs.mkdirSync(options.outputDir, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
const baseAgents = this.loadBaseAgents();
|
|
67
|
+
const knowledgeBases = this.loadAllKnowledgeBases();
|
|
68
|
+
const totalRuns = this.countDistinctRuns(knowledgeBases);
|
|
69
|
+
const fromData = totalRuns >= options.minRuns;
|
|
70
|
+
const agentStats = fromData
|
|
71
|
+
? this.aggregatePerAgent(knowledgeBases, baseAgents)
|
|
72
|
+
: new Map();
|
|
73
|
+
const diffs = [];
|
|
74
|
+
const agentsExported = [];
|
|
75
|
+
for (const agent of baseAgents) {
|
|
76
|
+
const stats = agentStats.get(agent.name);
|
|
77
|
+
const content = this.generateAgentMd(agent, stats, fromData, totalRuns);
|
|
78
|
+
const filename = agent.name.toLowerCase().replace(/[^a-z0-9]+/g, '_') + '.agent.md';
|
|
79
|
+
const outputPath = path.join(options.outputDir, filename);
|
|
80
|
+
// Compute diff if requested and a previous export exists
|
|
81
|
+
if (options.diff && fs.existsSync(outputPath)) {
|
|
82
|
+
const previous = fs.readFileSync(outputPath, 'utf8');
|
|
83
|
+
const entryDiffs = this.computeDiff(agent.name, previous, content);
|
|
84
|
+
diffs.push(...entryDiffs);
|
|
85
|
+
}
|
|
86
|
+
fs.writeFileSync(outputPath, content, 'utf8');
|
|
87
|
+
agentsExported.push(agent.name);
|
|
88
|
+
}
|
|
89
|
+
return { agentsExported, outputDir: options.outputDir, fromData, diffs };
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Load base agent profiles from config.
|
|
93
|
+
*/
|
|
94
|
+
loadBaseAgents() {
|
|
95
|
+
return this.configLoader.loadAllAgents();
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Scan the runs directory for knowledge-base.json files.
|
|
99
|
+
*/
|
|
100
|
+
loadAllKnowledgeBases() {
|
|
101
|
+
if (!fs.existsSync(this.runsDir))
|
|
102
|
+
return [];
|
|
103
|
+
const results = [];
|
|
104
|
+
let entries;
|
|
105
|
+
try {
|
|
106
|
+
entries = fs.readdirSync(this.runsDir, { withFileTypes: true });
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
for (const entry of entries) {
|
|
112
|
+
if (!entry.isDirectory())
|
|
113
|
+
continue;
|
|
114
|
+
const kbPath = path.join(this.runsDir, entry.name, 'knowledge-base.json');
|
|
115
|
+
if (fs.existsSync(kbPath)) {
|
|
116
|
+
try {
|
|
117
|
+
const content = fs.readFileSync(kbPath, 'utf8');
|
|
118
|
+
const kb = JSON.parse(content);
|
|
119
|
+
results.push(kb);
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// Skip malformed files without crashing the export
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return results;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Count distinct runs across all knowledge bases, weighting recent runs
|
|
130
|
+
* more heavily via exponential decay (30-day half-life).
|
|
131
|
+
*/
|
|
132
|
+
countDistinctRuns(bases) {
|
|
133
|
+
// Each knowledge base file represents one or more runs.
|
|
134
|
+
// totalRuns from the statistics field is the authoritative count per file.
|
|
135
|
+
return bases.reduce((sum, kb) => sum + (kb.statistics.totalRuns || 1), 0);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Aggregate knowledge patterns per agent with recency weighting.
|
|
139
|
+
*/
|
|
140
|
+
aggregatePerAgent(bases, agents) {
|
|
141
|
+
const statsMap = new Map();
|
|
142
|
+
// Initialize stats for each known agent
|
|
143
|
+
for (const agent of agents) {
|
|
144
|
+
statsMap.set(agent.name, {
|
|
145
|
+
agentName: agent.name,
|
|
146
|
+
totalMentions: 0,
|
|
147
|
+
failureModes: [],
|
|
148
|
+
successPatterns: [],
|
|
149
|
+
toolGuidance: [],
|
|
150
|
+
scopePatterns: [],
|
|
151
|
+
boundaryViolations: [],
|
|
152
|
+
avgDurationHint: undefined,
|
|
153
|
+
costHint: undefined
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
const now = Date.now();
|
|
157
|
+
for (const kb of bases) {
|
|
158
|
+
for (const pattern of kb.patterns) {
|
|
159
|
+
const weight = this.computeRecencyWeight(pattern.lastSeen, now);
|
|
160
|
+
// Only process patterns above minimum relevance weight
|
|
161
|
+
if (weight < 0.1)
|
|
162
|
+
continue;
|
|
163
|
+
// Find which agent(s) this pattern mentions
|
|
164
|
+
for (const agent of agents) {
|
|
165
|
+
const nameLower = agent.name.toLowerCase();
|
|
166
|
+
// Normalize for matching: strip underscores so "backend_master" matches "backendmaster" in KB text
|
|
167
|
+
const nameNormalized = nameLower.replace(/_/g, '');
|
|
168
|
+
const insightLower = pattern.insight.toLowerCase();
|
|
169
|
+
const evidenceStr = pattern.evidence.join(' ').toLowerCase();
|
|
170
|
+
const nameMatches = insightLower.includes(nameLower)
|
|
171
|
+
|| insightLower.includes(nameNormalized)
|
|
172
|
+
|| evidenceStr.includes(nameLower)
|
|
173
|
+
|| evidenceStr.includes(nameNormalized);
|
|
174
|
+
if (!nameMatches) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const stats = statsMap.get(agent.name);
|
|
178
|
+
if (!stats)
|
|
179
|
+
continue;
|
|
180
|
+
stats.totalMentions++;
|
|
181
|
+
this.classifyPattern(pattern, stats, weight);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return statsMap;
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Apply exponential decay weighting based on when the pattern was last seen.
|
|
189
|
+
*/
|
|
190
|
+
computeRecencyWeight(lastSeen, nowMs) {
|
|
191
|
+
const seenMs = new Date(lastSeen).getTime();
|
|
192
|
+
if (isNaN(seenMs))
|
|
193
|
+
return 0.5; // Unknown date gets neutral weight
|
|
194
|
+
const daysSince = (nowMs - seenMs) / (1000 * 60 * 60 * 24);
|
|
195
|
+
return Math.pow(0.5, daysSince / HALF_LIFE_DAYS);
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Classify a knowledge pattern into the appropriate stats bucket.
|
|
199
|
+
*/
|
|
200
|
+
classifyPattern(pattern, stats, _weight) {
|
|
201
|
+
switch (pattern.category) {
|
|
202
|
+
case 'failure_mode':
|
|
203
|
+
if (!stats.failureModes.includes(pattern.insight)) {
|
|
204
|
+
stats.failureModes.push(pattern.insight);
|
|
205
|
+
}
|
|
206
|
+
break;
|
|
207
|
+
case 'best_practice':
|
|
208
|
+
if (!stats.successPatterns.includes(pattern.insight)) {
|
|
209
|
+
stats.successPatterns.push(pattern.insight);
|
|
210
|
+
}
|
|
211
|
+
break;
|
|
212
|
+
case 'anti_pattern':
|
|
213
|
+
if (!stats.boundaryViolations.includes(pattern.insight)) {
|
|
214
|
+
stats.boundaryViolations.push(pattern.insight);
|
|
215
|
+
}
|
|
216
|
+
break;
|
|
217
|
+
case 'agent_behavior':
|
|
218
|
+
// Extract file path patterns from evidence
|
|
219
|
+
for (const ev of pattern.evidence) {
|
|
220
|
+
if (ev.includes('/') && !stats.scopePatterns.includes(ev)) {
|
|
221
|
+
stats.scopePatterns.push(ev);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
break;
|
|
225
|
+
case 'cost_history':
|
|
226
|
+
// Extract cost insights for the agent
|
|
227
|
+
if (pattern.insight.includes('premium request')) {
|
|
228
|
+
stats.costHint = pattern.insight;
|
|
229
|
+
}
|
|
230
|
+
break;
|
|
231
|
+
default:
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Generate .agent.md content for a single agent with optional learned data.
|
|
237
|
+
*/
|
|
238
|
+
generateAgentMd(agent, stats, fromData, totalRuns) {
|
|
239
|
+
const sections = [];
|
|
240
|
+
// YAML frontmatter
|
|
241
|
+
sections.push('---');
|
|
242
|
+
sections.push(`name: ${agent.name}`);
|
|
243
|
+
sections.push(`description: ${agent.purpose}`);
|
|
244
|
+
sections.push('tools:');
|
|
245
|
+
const tools = agent.tools || ['file_operations', 'terminal', 'git'];
|
|
246
|
+
for (const tool of tools) {
|
|
247
|
+
sections.push(` - ${tool}`);
|
|
248
|
+
}
|
|
249
|
+
sections.push('model: claude-sonnet-4');
|
|
250
|
+
sections.push('---');
|
|
251
|
+
sections.push('');
|
|
252
|
+
// Title
|
|
253
|
+
sections.push(`# ${agent.name}`);
|
|
254
|
+
sections.push('');
|
|
255
|
+
// Data notice
|
|
256
|
+
if (!fromData) {
|
|
257
|
+
sections.push('> **Note:** This agent definition is generated from base configuration.');
|
|
258
|
+
sections.push(`> Only ${totalRuns} run(s) recorded. Export again after 5+ runs for`);
|
|
259
|
+
sections.push('> data-driven recommendations.');
|
|
260
|
+
sections.push('');
|
|
261
|
+
}
|
|
262
|
+
// Purpose
|
|
263
|
+
sections.push('## Purpose');
|
|
264
|
+
sections.push('');
|
|
265
|
+
sections.push(agent.purpose + '.');
|
|
266
|
+
sections.push('');
|
|
267
|
+
// Scope
|
|
268
|
+
sections.push('## Scope');
|
|
269
|
+
sections.push('');
|
|
270
|
+
for (const item of agent.scope) {
|
|
271
|
+
sections.push(`- ${item}`);
|
|
272
|
+
}
|
|
273
|
+
sections.push('');
|
|
274
|
+
// Boundaries
|
|
275
|
+
sections.push('## Boundaries');
|
|
276
|
+
sections.push('');
|
|
277
|
+
for (const item of agent.boundaries) {
|
|
278
|
+
sections.push(`- ${item}`);
|
|
279
|
+
}
|
|
280
|
+
sections.push('');
|
|
281
|
+
// Done Definition
|
|
282
|
+
sections.push('## Done Definition');
|
|
283
|
+
sections.push('');
|
|
284
|
+
for (const item of agent.done_definition) {
|
|
285
|
+
sections.push(`- ${item}`);
|
|
286
|
+
}
|
|
287
|
+
sections.push('');
|
|
288
|
+
// Learned sections (only when sufficient data exists)
|
|
289
|
+
if (fromData && stats && stats.totalMentions > 0) {
|
|
290
|
+
// Failure prevention
|
|
291
|
+
if (stats.failureModes.length > 0) {
|
|
292
|
+
sections.push('## Failure Prevention (Learned)');
|
|
293
|
+
sections.push('');
|
|
294
|
+
sections.push('The following patterns have caused failures in past runs. Avoid them:');
|
|
295
|
+
sections.push('');
|
|
296
|
+
for (const mode of stats.failureModes.slice(0, 10)) {
|
|
297
|
+
sections.push(`- ${mode}`);
|
|
298
|
+
}
|
|
299
|
+
sections.push('');
|
|
300
|
+
}
|
|
301
|
+
// Success patterns
|
|
302
|
+
if (stats.successPatterns.length > 0) {
|
|
303
|
+
sections.push('## Proven Patterns');
|
|
304
|
+
sections.push('');
|
|
305
|
+
sections.push('These approaches have consistently succeeded:');
|
|
306
|
+
sections.push('');
|
|
307
|
+
for (const pattern of stats.successPatterns.slice(0, 10)) {
|
|
308
|
+
sections.push(`- ${pattern}`);
|
|
309
|
+
}
|
|
310
|
+
sections.push('');
|
|
311
|
+
}
|
|
312
|
+
// Scope insights from actual file paths
|
|
313
|
+
if (stats.scopePatterns.length > 0) {
|
|
314
|
+
sections.push('## Observed File Scope');
|
|
315
|
+
sections.push('');
|
|
316
|
+
sections.push('Files this agent typically modifies (based on execution history):');
|
|
317
|
+
sections.push('');
|
|
318
|
+
for (const sp of stats.scopePatterns.slice(0, 15)) {
|
|
319
|
+
sections.push(`- \`${sp}\``);
|
|
320
|
+
}
|
|
321
|
+
sections.push('');
|
|
322
|
+
}
|
|
323
|
+
// Boundary violations
|
|
324
|
+
if (stats.boundaryViolations.length > 0) {
|
|
325
|
+
sections.push('## Anti-Patterns (Do Not Repeat)');
|
|
326
|
+
sections.push('');
|
|
327
|
+
for (const violation of stats.boundaryViolations.slice(0, 10)) {
|
|
328
|
+
sections.push(`- ${violation}`);
|
|
329
|
+
}
|
|
330
|
+
sections.push('');
|
|
331
|
+
}
|
|
332
|
+
// Cost hints
|
|
333
|
+
if (stats.costHint) {
|
|
334
|
+
sections.push('## Performance Notes');
|
|
335
|
+
sections.push('');
|
|
336
|
+
sections.push(`- ${stats.costHint}`);
|
|
337
|
+
sections.push('');
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
// Refusal rules (always included)
|
|
341
|
+
sections.push('## Refusal Rules');
|
|
342
|
+
sections.push('');
|
|
343
|
+
for (const rule of agent.refusal_rules) {
|
|
344
|
+
sections.push(`- ${rule}`);
|
|
345
|
+
}
|
|
346
|
+
sections.push('');
|
|
347
|
+
return sections.join('\n');
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Compute a simple section-level diff between previous and current exports.
|
|
351
|
+
*/
|
|
352
|
+
computeDiff(agentName, previous, current) {
|
|
353
|
+
const diffs = [];
|
|
354
|
+
const prevSections = this.extractSections(previous);
|
|
355
|
+
const currSections = this.extractSections(current);
|
|
356
|
+
// Compare each section header
|
|
357
|
+
const allHeaders = new Set([...prevSections.keys(), ...currSections.keys()]);
|
|
358
|
+
for (const header of allHeaders) {
|
|
359
|
+
const prevContent = prevSections.get(header) || '';
|
|
360
|
+
const currContent = currSections.get(header) || '';
|
|
361
|
+
if (prevContent !== currContent) {
|
|
362
|
+
diffs.push({
|
|
363
|
+
agentName,
|
|
364
|
+
field: header,
|
|
365
|
+
previous: prevContent.slice(0, 200),
|
|
366
|
+
current: currContent.slice(0, 200)
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
return diffs;
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Extract markdown sections as header -> body map.
|
|
374
|
+
*/
|
|
375
|
+
extractSections(content) {
|
|
376
|
+
const sections = new Map();
|
|
377
|
+
const lines = content.split('\n');
|
|
378
|
+
let currentHeader = '_frontmatter';
|
|
379
|
+
let currentBody = [];
|
|
380
|
+
for (const line of lines) {
|
|
381
|
+
const match = line.match(/^##?\s+(.+)/);
|
|
382
|
+
if (match) {
|
|
383
|
+
// Save previous section
|
|
384
|
+
sections.set(currentHeader, currentBody.join('\n').trim());
|
|
385
|
+
currentHeader = match[1];
|
|
386
|
+
currentBody = [];
|
|
387
|
+
}
|
|
388
|
+
else {
|
|
389
|
+
currentBody.push(line);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// Save last section
|
|
393
|
+
sections.set(currentHeader, currentBody.join('\n').trim());
|
|
394
|
+
return sections;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
exports.AgentsExporter = AgentsExporter;
|
|
398
|
+
exports.default = AgentsExporter;
|
|
@@ -0,0 +1,161 @@
|
|
|
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
|
+
const fs = __importStar(require("fs"));
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const logger_1 = require("./logger");
|
|
39
|
+
const logger = (0, logger_1.getLogger)('analytics-log');
|
|
40
|
+
const ANALYTICS_SCHEMA_VERSION = 1;
|
|
41
|
+
/**
|
|
42
|
+
* Append-only analytics log for orchestrator runs
|
|
43
|
+
* Persists to runs/analytics.json
|
|
44
|
+
*/
|
|
45
|
+
class AnalyticsLog {
|
|
46
|
+
logPath;
|
|
47
|
+
constructor(runsDir = 'runs') {
|
|
48
|
+
this.logPath = path.join(runsDir, 'analytics.json');
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Append a run to the analytics log
|
|
52
|
+
*/
|
|
53
|
+
appendRun(metrics) {
|
|
54
|
+
const entry = {
|
|
55
|
+
schemaVersion: ANALYTICS_SCHEMA_VERSION,
|
|
56
|
+
timestamp: new Date().toISOString(),
|
|
57
|
+
metrics
|
|
58
|
+
};
|
|
59
|
+
let entries = [];
|
|
60
|
+
if (fs.existsSync(this.logPath)) {
|
|
61
|
+
try {
|
|
62
|
+
const content = fs.readFileSync(this.logPath, 'utf8');
|
|
63
|
+
entries = JSON.parse(content);
|
|
64
|
+
// Validate schema
|
|
65
|
+
if (!Array.isArray(entries)) {
|
|
66
|
+
logger.warn('Analytics log is not an array, resetting');
|
|
67
|
+
entries = [];
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
logger.warn('Failed to parse analytics log, resetting:', error instanceof Error ? error.message : error);
|
|
72
|
+
entries = [];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
entries.push(entry);
|
|
76
|
+
// Ensure directory exists
|
|
77
|
+
const dir = path.dirname(this.logPath);
|
|
78
|
+
if (!fs.existsSync(dir)) {
|
|
79
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
80
|
+
}
|
|
81
|
+
// Write atomically via temp file
|
|
82
|
+
const tmpPath = this.logPath + '.tmp';
|
|
83
|
+
fs.writeFileSync(tmpPath, JSON.stringify(entries, null, 2), 'utf8');
|
|
84
|
+
fs.renameSync(tmpPath, this.logPath);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get recent runs (default: last 10)
|
|
88
|
+
*/
|
|
89
|
+
getRecentRuns(count = 10) {
|
|
90
|
+
if (!fs.existsSync(this.logPath)) {
|
|
91
|
+
return [];
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
const content = fs.readFileSync(this.logPath, 'utf8');
|
|
95
|
+
const entries = JSON.parse(content);
|
|
96
|
+
if (!Array.isArray(entries)) {
|
|
97
|
+
return [];
|
|
98
|
+
}
|
|
99
|
+
// Return most recent entries
|
|
100
|
+
return entries.slice(-count).reverse();
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
logger.warn('Failed to read analytics log:', error instanceof Error ? error.message : error);
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get all runs
|
|
109
|
+
*/
|
|
110
|
+
getAllRuns() {
|
|
111
|
+
if (!fs.existsSync(this.logPath)) {
|
|
112
|
+
return [];
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
const content = fs.readFileSync(this.logPath, 'utf8');
|
|
116
|
+
const entries = JSON.parse(content);
|
|
117
|
+
if (!Array.isArray(entries)) {
|
|
118
|
+
return [];
|
|
119
|
+
}
|
|
120
|
+
return entries;
|
|
121
|
+
}
|
|
122
|
+
catch (error) {
|
|
123
|
+
logger.warn('Failed to read analytics log:', error instanceof Error ? error.message : error);
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Compare current run with historical average
|
|
129
|
+
*/
|
|
130
|
+
compareWithHistory(currentMetrics, historyCount = 5) {
|
|
131
|
+
const recent = this.getRecentRuns(historyCount + 1); // +1 to exclude current if already logged
|
|
132
|
+
// Filter out current run if it's already in the log
|
|
133
|
+
const historical = recent.filter(e => e.metrics.executionId !== currentMetrics.executionId);
|
|
134
|
+
if (historical.length === 0) {
|
|
135
|
+
return null; // No history to compare
|
|
136
|
+
}
|
|
137
|
+
// Calculate averages
|
|
138
|
+
const avgTime = historical.reduce((sum, e) => sum + e.metrics.totalTimeMs, 0) / historical.length;
|
|
139
|
+
const avgCommits = historical.reduce((sum, e) => sum + e.metrics.commitCount, 0) / historical.length;
|
|
140
|
+
const avgPassRate = historical.reduce((sum, e) => {
|
|
141
|
+
const total = e.metrics.verificationsPassed + e.metrics.verificationsFailed;
|
|
142
|
+
return sum + (total > 0 ? e.metrics.verificationsPassed / total : 0);
|
|
143
|
+
}, 0) / historical.length;
|
|
144
|
+
const currentTotal = currentMetrics.verificationsPassed + currentMetrics.verificationsFailed;
|
|
145
|
+
const currentPassRate = currentTotal > 0 ? currentMetrics.verificationsPassed / currentTotal : 0;
|
|
146
|
+
return {
|
|
147
|
+
current: currentMetrics,
|
|
148
|
+
averageHistorical: {
|
|
149
|
+
totalTimeMs: avgTime,
|
|
150
|
+
commitCount: avgCommits,
|
|
151
|
+
verificationPassRate: avgPassRate
|
|
152
|
+
},
|
|
153
|
+
delta: {
|
|
154
|
+
timePercent: avgTime > 0 ? ((currentMetrics.totalTimeMs - avgTime) / avgTime) * 100 : 0,
|
|
155
|
+
commitCountDiff: currentMetrics.commitCount - avgCommits,
|
|
156
|
+
passRateDiff: currentPassRate - avgPassRate
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
exports.default = AnalyticsLog;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Scans a git repo before execution to capture existing files.
|
|
3
|
+
// Feeds into shared instructions so agents know what not to break.
|
|
4
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5
|
+
exports.scanBaseline = scanBaseline;
|
|
6
|
+
exports.formatPreservationRules = formatPreservationRules;
|
|
7
|
+
const child_process_1 = require("child_process");
|
|
8
|
+
const TEST_PATTERN = /(?:^|\/)(?:test|tests|__tests__|spec)\/|\.(?:test|spec)\.\w+$/i;
|
|
9
|
+
// Vendored dependency directories whose test files are irrelevant to the project
|
|
10
|
+
const VENDORED_DIRS = /^(?:node_modules|venv|\.venv|env|\.env|\.tox|__pypackages__|bower_components|\.bundle)\//i;
|
|
11
|
+
const SITE_PACKAGES = /\/site-packages\//;
|
|
12
|
+
/**
|
|
13
|
+
* Run `git ls-files` and split results into test vs non-test.
|
|
14
|
+
* Returns empty lists if the directory isn't a git repo or has no commits.
|
|
15
|
+
*/
|
|
16
|
+
function scanBaseline(workingDir) {
|
|
17
|
+
let output;
|
|
18
|
+
try {
|
|
19
|
+
output = (0, child_process_1.execSync)('git ls-files', {
|
|
20
|
+
cwd: workingDir, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe']
|
|
21
|
+
}).trim();
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return { allFiles: [], testFiles: [], headCommit: '' };
|
|
25
|
+
}
|
|
26
|
+
// Capture HEAD so quality gates can scope checks to agent-changed files
|
|
27
|
+
let headCommit = '';
|
|
28
|
+
try {
|
|
29
|
+
headCommit = (0, child_process_1.execSync)('git rev-parse HEAD', {
|
|
30
|
+
cwd: workingDir, encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe']
|
|
31
|
+
}).trim();
|
|
32
|
+
}
|
|
33
|
+
catch { /* empty repo with no commits yet */ }
|
|
34
|
+
if (!output)
|
|
35
|
+
return { allFiles: [], testFiles: [], headCommit };
|
|
36
|
+
const allFiles = output.split('\n').filter(f => f.length > 0);
|
|
37
|
+
const testFiles = allFiles.filter(f => TEST_PATTERN.test(f) && !VENDORED_DIRS.test(f) && !SITE_PACKAGES.test(f));
|
|
38
|
+
return { allFiles, testFiles, headCommit };
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Build preservation rules for .copilot-instructions.md.
|
|
42
|
+
* Lists existing test files and tells agents not to break them.
|
|
43
|
+
*/
|
|
44
|
+
function formatPreservationRules(snapshot) {
|
|
45
|
+
if (snapshot.allFiles.length === 0)
|
|
46
|
+
return '';
|
|
47
|
+
const lines = [
|
|
48
|
+
'## Pre-existing Code',
|
|
49
|
+
`This repository has ${snapshot.allFiles.length} existing file(s).`,
|
|
50
|
+
'- Do NOT modify or delete files outside your assigned scope.',
|
|
51
|
+
'- Do NOT break existing tests. If they fail after your changes, fix the regression before finishing.',
|
|
52
|
+
'- When modifying shared files (e.g., package.json), make only the changes your task requires.',
|
|
53
|
+
'- Run the existing test suite after your changes to confirm nothing is broken.',
|
|
54
|
+
'',
|
|
55
|
+
];
|
|
56
|
+
if (snapshot.testFiles.length > 0) {
|
|
57
|
+
lines.push('### Protected Test Files');
|
|
58
|
+
lines.push('These tests must continue to pass:');
|
|
59
|
+
for (const f of snapshot.testFiles) {
|
|
60
|
+
lines.push(`- ${f}`);
|
|
61
|
+
}
|
|
62
|
+
lines.push('');
|
|
63
|
+
}
|
|
64
|
+
return lines.join('\n');
|
|
65
|
+
}
|