agentsys 5.0.3 → 5.1.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/.claude-plugin/marketplace.json +21 -14
- package/.claude-plugin/plugin.json +1 -1
- package/AGENTS.md +2 -1
- package/CHANGELOG.md +18 -0
- package/README.md +7 -6
- package/adapters/codex/skills/agnix/SKILL.md +0 -1
- package/adapters/codex/skills/audit-project/SKILL.md +0 -1
- package/adapters/codex/skills/audit-project-agents/SKILL.md +0 -1
- package/adapters/codex/skills/audit-project-github/SKILL.md +0 -1
- package/adapters/codex/skills/consult/SKILL.md +132 -57
- package/adapters/codex/skills/debate/SKILL.md +214 -0
- package/adapters/codex/skills/delivery-approval/SKILL.md +0 -1
- package/adapters/codex/skills/deslop/SKILL.md +0 -1
- package/adapters/codex/skills/drift-detect/SKILL.md +0 -1
- package/adapters/codex/skills/enhance/SKILL.md +0 -1
- package/adapters/codex/skills/learn/SKILL.md +0 -1
- package/adapters/codex/skills/next-task/SKILL.md +0 -1
- package/adapters/codex/skills/perf/SKILL.md +0 -1
- package/adapters/codex/skills/repo-map/SKILL.md +0 -1
- package/adapters/codex/skills/ship/SKILL.md +0 -1
- package/adapters/codex/skills/ship-ci-review-loop/SKILL.md +0 -1
- package/adapters/codex/skills/ship-deployment/SKILL.md +0 -1
- package/adapters/codex/skills/ship-error-handling/SKILL.md +0 -1
- package/adapters/codex/skills/sync-docs/SKILL.md +0 -1
- package/adapters/opencode/agents/agent-enhancer.md +0 -1
- package/adapters/opencode/agents/agnix-agent.md +0 -1
- package/adapters/opencode/agents/ci-fixer.md +0 -1
- package/adapters/opencode/agents/ci-monitor.md +0 -1
- package/adapters/opencode/agents/claudemd-enhancer.md +0 -1
- package/adapters/opencode/agents/consult-agent.md +122 -30
- package/adapters/opencode/agents/cross-file-enhancer.md +0 -1
- package/adapters/opencode/agents/debate-orchestrator.md +169 -0
- package/adapters/opencode/agents/delivery-validator.md +0 -1
- package/adapters/opencode/agents/deslop-agent.md +0 -1
- package/adapters/opencode/agents/docs-enhancer.md +0 -1
- package/adapters/opencode/agents/exploration-agent.md +0 -1
- package/adapters/opencode/agents/hooks-enhancer.md +0 -1
- package/adapters/opencode/agents/implementation-agent.md +0 -1
- package/adapters/opencode/agents/learn-agent.md +0 -1
- package/adapters/opencode/agents/map-validator.md +0 -1
- package/adapters/opencode/agents/perf-analyzer.md +0 -1
- package/adapters/opencode/agents/perf-code-paths.md +0 -1
- package/adapters/opencode/agents/perf-investigation-logger.md +0 -1
- package/adapters/opencode/agents/perf-orchestrator.md +0 -1
- package/adapters/opencode/agents/perf-theory-gatherer.md +0 -1
- package/adapters/opencode/agents/perf-theory-tester.md +0 -1
- package/adapters/opencode/agents/plan-synthesizer.md +0 -1
- package/adapters/opencode/agents/planning-agent.md +0 -1
- package/adapters/opencode/agents/plugin-enhancer.md +0 -1
- package/adapters/opencode/agents/prompt-enhancer.md +0 -1
- package/adapters/opencode/agents/simple-fixer.md +0 -1
- package/adapters/opencode/agents/skills-enhancer.md +0 -1
- package/adapters/opencode/agents/sync-docs-agent.md +0 -1
- package/adapters/opencode/agents/task-discoverer.md +0 -1
- package/adapters/opencode/agents/test-coverage-checker.md +0 -1
- package/adapters/opencode/agents/worktree-manager.md +0 -1
- package/adapters/opencode/commands/agnix.md +0 -1
- package/adapters/opencode/commands/audit-project-agents.md +0 -1
- package/adapters/opencode/commands/audit-project-github.md +0 -1
- package/adapters/opencode/commands/audit-project.md +0 -1
- package/adapters/opencode/commands/consult.md +133 -57
- package/adapters/opencode/commands/debate.md +224 -0
- package/adapters/opencode/commands/delivery-approval.md +0 -1
- package/adapters/opencode/commands/deslop.md +0 -1
- package/adapters/opencode/commands/drift-detect.md +0 -1
- package/adapters/opencode/commands/enhance.md +0 -1
- package/adapters/opencode/commands/learn.md +0 -1
- package/adapters/opencode/commands/next-task.md +0 -1
- package/adapters/opencode/commands/perf.md +0 -1
- package/adapters/opencode/commands/repo-map.md +0 -1
- package/adapters/opencode/commands/ship-ci-review-loop.md +0 -1
- package/adapters/opencode/commands/ship-deployment.md +0 -1
- package/adapters/opencode/commands/ship-error-handling.md +0 -1
- package/adapters/opencode/commands/ship.md +0 -1
- package/adapters/opencode/commands/sync-docs.md +0 -1
- package/adapters/opencode/skills/agnix/SKILL.md +1 -2
- package/adapters/opencode/skills/consult/SKILL.md +33 -23
- package/adapters/opencode/skills/debate/SKILL.md +245 -0
- package/adapters/opencode/skills/deslop/SKILL.md +1 -2
- package/adapters/opencode/skills/discover-tasks/SKILL.md +1 -2
- package/adapters/opencode/skills/drift-analysis/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-agent-prompts/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-claude-memory/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-cross-file/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-docs/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-hooks/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-orchestrator/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-plugins/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-prompts/SKILL.md +1 -2
- package/adapters/opencode/skills/enhance-skills/SKILL.md +1 -2
- package/adapters/opencode/skills/learn/SKILL.md +1 -2
- package/adapters/opencode/skills/orchestrate-review/SKILL.md +0 -1
- package/adapters/opencode/skills/perf-analyzer/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-baseline-manager/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-benchmarker/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-code-paths/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-investigation-logger/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-profiler/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-theory-gatherer/SKILL.md +1 -2
- package/adapters/opencode/skills/perf-theory-tester/SKILL.md +1 -2
- package/adapters/opencode/skills/repo-mapping/SKILL.md +1 -2
- package/adapters/opencode/skills/sync-docs/SKILL.md +1 -2
- package/adapters/opencode/skills/validate-delivery/SKILL.md +1 -2
- package/lib/adapter-transforms.js +24 -4
- package/package.json +1 -1
- package/plugins/agnix/.claude-plugin/plugin.json +1 -1
- package/plugins/agnix/skills/agnix/SKILL.md +1 -1
- package/plugins/audit-project/.claude-plugin/plugin.json +1 -1
- package/plugins/audit-project/lib/adapter-transforms.js +24 -4
- package/plugins/consult/.claude-plugin/plugin.json +1 -1
- package/plugins/consult/agents/consult-agent.md +122 -29
- package/plugins/consult/commands/consult.md +135 -58
- package/plugins/consult/skills/consult/SKILL.md +31 -20
- package/plugins/debate/.claude-plugin/plugin.json +21 -0
- package/plugins/debate/agents/debate-orchestrator.md +175 -0
- package/plugins/debate/commands/debate.md +221 -0
- package/plugins/debate/lib/adapter-transforms.js +298 -0
- package/plugins/debate/lib/collectors/codebase.js +392 -0
- package/plugins/debate/lib/collectors/docs-patterns.js +713 -0
- package/plugins/debate/lib/collectors/documentation.js +219 -0
- package/plugins/debate/lib/collectors/github.js +330 -0
- package/plugins/debate/lib/collectors/index.js +126 -0
- package/plugins/debate/lib/config/index.js +14 -0
- package/plugins/debate/lib/cross-platform/index.js +539 -0
- package/plugins/debate/lib/discovery/index.js +352 -0
- package/plugins/debate/lib/drift-detect/collectors.js +37 -0
- package/plugins/debate/lib/enhance/agent-analyzer.js +421 -0
- package/plugins/debate/lib/enhance/agent-patterns.js +571 -0
- package/plugins/debate/lib/enhance/auto-suppression.js +622 -0
- package/plugins/debate/lib/enhance/benchmark.js +417 -0
- package/plugins/debate/lib/enhance/cross-file-analyzer.js +930 -0
- package/plugins/debate/lib/enhance/cross-file-patterns.js +370 -0
- package/plugins/debate/lib/enhance/docs-analyzer.js +325 -0
- package/plugins/debate/lib/enhance/docs-patterns.js +671 -0
- package/plugins/debate/lib/enhance/fixer.js +721 -0
- package/plugins/debate/lib/enhance/hook-analyzer.js +135 -0
- package/plugins/debate/lib/enhance/hook-patterns.js +40 -0
- package/plugins/debate/lib/enhance/index.js +127 -0
- package/plugins/debate/lib/enhance/plugin-analyzer.js +402 -0
- package/plugins/debate/lib/enhance/plugin-patterns.js +326 -0
- package/plugins/debate/lib/enhance/projectmemory-analyzer.js +551 -0
- package/plugins/debate/lib/enhance/projectmemory-patterns.js +617 -0
- package/plugins/debate/lib/enhance/prompt-analyzer.js +457 -0
- package/plugins/debate/lib/enhance/prompt-patterns.js +1484 -0
- package/plugins/debate/lib/enhance/reporter.js +1348 -0
- package/plugins/debate/lib/enhance/security-patterns.js +284 -0
- package/plugins/debate/lib/enhance/skill-analyzer.js +182 -0
- package/plugins/debate/lib/enhance/skill-patterns.js +147 -0
- package/plugins/debate/lib/enhance/suppression.js +352 -0
- package/plugins/debate/lib/enhance/tool-patterns.js +373 -0
- package/plugins/debate/lib/index.js +270 -0
- package/plugins/debate/lib/patterns/cli-enhancers.js +611 -0
- package/plugins/debate/lib/patterns/pipeline.js +948 -0
- package/plugins/debate/lib/patterns/review-patterns.js +558 -0
- package/plugins/debate/lib/patterns/slop-analyzers.js +2305 -0
- package/plugins/debate/lib/patterns/slop-patterns.js +1187 -0
- package/plugins/debate/lib/perf/analyzer/index.js +22 -0
- package/plugins/debate/lib/perf/argument-parser.js +105 -0
- package/plugins/debate/lib/perf/baseline-comparator.js +50 -0
- package/plugins/debate/lib/perf/baseline-store.js +127 -0
- package/plugins/debate/lib/perf/benchmark-runner.js +404 -0
- package/plugins/debate/lib/perf/breaking-point-finder.js +52 -0
- package/plugins/debate/lib/perf/breaking-point-runner.js +60 -0
- package/plugins/debate/lib/perf/checkpoint.js +123 -0
- package/plugins/debate/lib/perf/code-paths.js +86 -0
- package/plugins/debate/lib/perf/consolidation.js +37 -0
- package/plugins/debate/lib/perf/constraint-runner.js +71 -0
- package/plugins/debate/lib/perf/experiment-runner.js +32 -0
- package/plugins/debate/lib/perf/index.js +41 -0
- package/plugins/debate/lib/perf/investigation-state.js +874 -0
- package/plugins/debate/lib/perf/optimization-runner.js +79 -0
- package/plugins/debate/lib/perf/profilers/go.js +22 -0
- package/plugins/debate/lib/perf/profilers/index.js +46 -0
- package/plugins/debate/lib/perf/profilers/java.js +23 -0
- package/plugins/debate/lib/perf/profilers/node.js +27 -0
- package/plugins/debate/lib/perf/profilers/python.js +23 -0
- package/plugins/debate/lib/perf/profilers/rust.js +23 -0
- package/plugins/debate/lib/perf/profiling-runner.js +75 -0
- package/plugins/debate/lib/perf/schemas.js +140 -0
- package/plugins/debate/lib/platform/detect-platform.js +413 -0
- package/plugins/debate/lib/platform/detection-configs.js +93 -0
- package/plugins/debate/lib/platform/state-dir.js +132 -0
- package/plugins/debate/lib/platform/verify-tools.js +182 -0
- package/plugins/debate/lib/repo-map/cache.js +152 -0
- package/plugins/debate/lib/repo-map/concurrency.js +29 -0
- package/plugins/debate/lib/repo-map/index.js +222 -0
- package/plugins/debate/lib/repo-map/installer.js +212 -0
- package/plugins/debate/lib/repo-map/queries/go.js +27 -0
- package/plugins/debate/lib/repo-map/queries/index.js +100 -0
- package/plugins/debate/lib/repo-map/queries/java.js +38 -0
- package/plugins/debate/lib/repo-map/queries/javascript.js +55 -0
- package/plugins/debate/lib/repo-map/queries/python.js +24 -0
- package/plugins/debate/lib/repo-map/queries/rust.js +73 -0
- package/plugins/debate/lib/repo-map/queries/typescript.js +38 -0
- package/plugins/debate/lib/repo-map/runner.js +1364 -0
- package/plugins/debate/lib/repo-map/updater.js +562 -0
- package/plugins/debate/lib/repo-map/usage-analyzer.js +407 -0
- package/plugins/debate/lib/schemas/plugin-manifest.schema.json +57 -0
- package/plugins/debate/lib/schemas/validator.js +247 -0
- package/plugins/debate/lib/sources/custom-handler.js +199 -0
- package/plugins/debate/lib/sources/policy-questions.js +246 -0
- package/plugins/debate/lib/sources/source-cache.js +165 -0
- package/plugins/debate/lib/state/workflow-state.js +576 -0
- package/plugins/debate/lib/types/agent-frontmatter.d.ts +134 -0
- package/plugins/debate/lib/types/command-frontmatter.d.ts +107 -0
- package/plugins/debate/lib/types/hook-frontmatter.d.ts +115 -0
- package/plugins/debate/lib/types/index.d.ts +84 -0
- package/plugins/debate/lib/types/plugin-manifest.d.ts +102 -0
- package/plugins/debate/lib/types/skill-frontmatter.d.ts +89 -0
- package/plugins/debate/lib/utils/atomic-write.js +94 -0
- package/plugins/debate/lib/utils/cache-manager.js +159 -0
- package/plugins/debate/lib/utils/command-parser.js +0 -0
- package/plugins/debate/lib/utils/context-optimizer.js +300 -0
- package/plugins/debate/lib/utils/deprecation.js +37 -0
- package/plugins/debate/lib/utils/shell-escape.js +88 -0
- package/plugins/debate/lib/utils/state-helpers.js +61 -0
- package/plugins/debate/skills/debate/SKILL.md +264 -0
- package/plugins/deslop/.claude-plugin/plugin.json +1 -1
- package/plugins/deslop/lib/adapter-transforms.js +24 -4
- package/plugins/deslop/skills/deslop/SKILL.md +1 -1
- package/plugins/drift-detect/.claude-plugin/plugin.json +1 -1
- package/plugins/drift-detect/lib/adapter-transforms.js +24 -4
- package/plugins/drift-detect/skills/drift-analysis/SKILL.md +1 -1
- package/plugins/enhance/.claude-plugin/plugin.json +1 -1
- package/plugins/enhance/lib/adapter-transforms.js +24 -4
- package/plugins/enhance/skills/enhance-agent-prompts/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-claude-memory/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-cross-file/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-docs/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-hooks/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-orchestrator/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-plugins/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-prompts/SKILL.md +1 -1
- package/plugins/enhance/skills/enhance-skills/SKILL.md +1 -1
- package/plugins/learn/.claude-plugin/plugin.json +1 -1
- package/plugins/learn/agents/learn-agent.md +1 -1
- package/plugins/learn/lib/adapter-transforms.js +24 -4
- package/plugins/learn/skills/learn/SKILL.md +1 -1
- package/plugins/next-task/.claude-plugin/plugin.json +1 -1
- package/plugins/next-task/agents/exploration-agent.md +1 -1
- package/plugins/next-task/lib/adapter-transforms.js +24 -4
- package/plugins/next-task/skills/discover-tasks/SKILL.md +1 -1
- package/plugins/next-task/skills/validate-delivery/SKILL.md +1 -1
- package/plugins/perf/.claude-plugin/plugin.json +1 -1
- package/plugins/perf/lib/adapter-transforms.js +24 -4
- package/plugins/perf/skills/perf-analyzer/SKILL.md +1 -1
- package/plugins/perf/skills/perf-baseline-manager/SKILL.md +1 -1
- package/plugins/perf/skills/perf-benchmarker/SKILL.md +1 -1
- package/plugins/perf/skills/perf-code-paths/SKILL.md +1 -1
- package/plugins/perf/skills/perf-investigation-logger/SKILL.md +1 -1
- package/plugins/perf/skills/perf-profiler/SKILL.md +1 -1
- package/plugins/perf/skills/perf-theory-gatherer/SKILL.md +1 -1
- package/plugins/perf/skills/perf-theory-tester/SKILL.md +1 -1
- package/plugins/repo-map/.claude-plugin/plugin.json +1 -1
- package/plugins/repo-map/lib/adapter-transforms.js +24 -4
- package/plugins/ship/.claude-plugin/plugin.json +1 -1
- package/plugins/ship/lib/adapter-transforms.js +24 -4
- package/plugins/sync-docs/.claude-plugin/plugin.json +1 -1
- package/plugins/sync-docs/lib/adapter-transforms.js +24 -4
- package/plugins/sync-docs/skills/sync-docs/SKILL.md +1 -1
- package/scripts/gen-adapters.js +6 -7
- package/scripts/generate-docs.js +4 -2
- package/scripts/plugins.txt +1 -0
- package/site/content.json +6 -6
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Binary search helper for breaking point discovery.
|
|
3
|
+
*
|
|
4
|
+
* @module lib/perf/breaking-point-finder
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Find breaking point using binary search.
|
|
9
|
+
* The runner should return { ok: boolean, data?: any }.
|
|
10
|
+
*
|
|
11
|
+
* @param {object} options
|
|
12
|
+
* @param {number} options.min
|
|
13
|
+
* @param {number} options.max
|
|
14
|
+
* @param {(value:number)=>Promise<{ok:boolean,data?:any}>} options.runner
|
|
15
|
+
* @returns {Promise<{breakingPoint:number|null, attempts:number, history:Array}>}
|
|
16
|
+
*/
|
|
17
|
+
async function findBreakingPoint({ min, max, runner }) {
|
|
18
|
+
if (typeof min !== 'number' || typeof max !== 'number') {
|
|
19
|
+
throw new Error('min and max must be numbers');
|
|
20
|
+
}
|
|
21
|
+
if (typeof runner !== 'function') {
|
|
22
|
+
throw new Error('runner must be a function');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let low = min;
|
|
26
|
+
let high = max;
|
|
27
|
+
let breakingPoint = null;
|
|
28
|
+
const history = [];
|
|
29
|
+
|
|
30
|
+
while (low <= high) {
|
|
31
|
+
const mid = Math.floor((low + high) / 2);
|
|
32
|
+
const result = await runner(mid);
|
|
33
|
+
history.push({ value: mid, ok: result.ok });
|
|
34
|
+
|
|
35
|
+
if (result.ok) {
|
|
36
|
+
low = mid + 1;
|
|
37
|
+
} else {
|
|
38
|
+
breakingPoint = mid;
|
|
39
|
+
high = mid - 1;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
breakingPoint,
|
|
45
|
+
attempts: history.length,
|
|
46
|
+
history
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = {
|
|
51
|
+
findBreakingPoint
|
|
52
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Breaking point runner wrapper for /perf.
|
|
3
|
+
*
|
|
4
|
+
* @module lib/perf/breaking-point-runner
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { runBenchmark, parseMetrics, BINARY_SEARCH_MIN_DURATION } = require('./benchmark-runner');
|
|
8
|
+
const { findBreakingPoint } = require('./breaking-point-finder');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Run a binary search to find the breaking point for a numeric parameter.
|
|
12
|
+
* The benchmark command should accept the value via an env var.
|
|
13
|
+
*
|
|
14
|
+
* @param {object} options
|
|
15
|
+
* @param {string} options.command
|
|
16
|
+
* @param {string} options.paramEnv
|
|
17
|
+
* @param {number} options.min
|
|
18
|
+
* @param {number} options.max
|
|
19
|
+
* @returns {Promise<{breakingPoint:number|null, attempts:number, history:Array}>}
|
|
20
|
+
*/
|
|
21
|
+
async function runBreakingPointSearch(options) {
|
|
22
|
+
const { command, paramEnv, min, max } = options || {};
|
|
23
|
+
|
|
24
|
+
if (!command || typeof command !== 'string') {
|
|
25
|
+
throw new Error('command must be a non-empty string');
|
|
26
|
+
}
|
|
27
|
+
if (!paramEnv || typeof paramEnv !== 'string') {
|
|
28
|
+
throw new Error('paramEnv must be a non-empty string');
|
|
29
|
+
}
|
|
30
|
+
if (typeof min !== 'number' || typeof max !== 'number') {
|
|
31
|
+
throw new Error('min and max must be numbers');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const runner = async (value) => {
|
|
35
|
+
try {
|
|
36
|
+
const result = runBenchmark(command, {
|
|
37
|
+
mode: 'binary-search',
|
|
38
|
+
duration: BINARY_SEARCH_MIN_DURATION,
|
|
39
|
+
env: {
|
|
40
|
+
[paramEnv]: String(value)
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const parsed = parseMetrics(result.output);
|
|
45
|
+
if (!parsed.ok) {
|
|
46
|
+
return { ok: false, data: { error: parsed.error } };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return { ok: true, data: { metrics: parsed.metrics } };
|
|
50
|
+
} catch (error) {
|
|
51
|
+
return { ok: false, data: { error: error.message } };
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
return findBreakingPoint({ min, max, runner });
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
module.exports = {
|
|
59
|
+
runBreakingPointSearch
|
|
60
|
+
};
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Git checkpoint helper for /perf phases.
|
|
3
|
+
*
|
|
4
|
+
* @module lib/perf/checkpoint
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { execFileSync } = require('child_process');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const { getStateDir } = require('../platform/state-dir');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Check if git repo is clean.
|
|
13
|
+
* @returns {boolean}
|
|
14
|
+
*/
|
|
15
|
+
function isWorkingTreeClean() {
|
|
16
|
+
const output = execFileSync('git', ['status', '--porcelain'], { encoding: 'utf8' }).trim();
|
|
17
|
+
return output.length === 0;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Build checkpoint commit message.
|
|
22
|
+
* @param {object} input
|
|
23
|
+
* @param {string} input.phase
|
|
24
|
+
* @param {string} input.id
|
|
25
|
+
* @param {string} [input.baselineVersion]
|
|
26
|
+
* @param {string} [input.deltaSummary]
|
|
27
|
+
* @returns {string}
|
|
28
|
+
*/
|
|
29
|
+
function buildCheckpointMessage(input) {
|
|
30
|
+
if (!input || typeof input !== 'object') {
|
|
31
|
+
throw new Error('Checkpoint input must be an object');
|
|
32
|
+
}
|
|
33
|
+
const { phase, id, baselineVersion, deltaSummary } = input;
|
|
34
|
+
|
|
35
|
+
if (!phase || typeof phase !== 'string') {
|
|
36
|
+
throw new Error('phase is required');
|
|
37
|
+
}
|
|
38
|
+
if (!id || typeof id !== 'string') {
|
|
39
|
+
throw new Error('id is required');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const baseline = baselineVersion || 'n/a';
|
|
43
|
+
const delta = deltaSummary || 'n/a';
|
|
44
|
+
return `perf: phase ${phase} [${id}] baseline=${baseline} delta=${delta}`;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Get the most recent git commit message.
|
|
49
|
+
* @returns {string|null}
|
|
50
|
+
*/
|
|
51
|
+
function getLastCommitMessage() {
|
|
52
|
+
try {
|
|
53
|
+
return execFileSync('git', ['log', '-1', '--pretty=%B'], { encoding: 'utf8' }).trim();
|
|
54
|
+
} catch {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Get recent git commit summaries.
|
|
61
|
+
* @param {number} [limit=5]
|
|
62
|
+
* @returns {string[]}
|
|
63
|
+
*/
|
|
64
|
+
function getRecentCommits(limit = 5) {
|
|
65
|
+
try {
|
|
66
|
+
const count = Number.isFinite(limit) ? Math.max(1, Math.floor(limit)) : 5;
|
|
67
|
+
const output = execFileSync('git', ['log', `-${count}`, '--pretty=format:%h %s'], { encoding: 'utf8' }).trim();
|
|
68
|
+
if (!output) return [];
|
|
69
|
+
return output.split(/\r?\n/).map(line => line.trim()).filter(Boolean);
|
|
70
|
+
} catch {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Check if the next checkpoint would duplicate the last commit.
|
|
77
|
+
* @param {string} message
|
|
78
|
+
* @returns {boolean}
|
|
79
|
+
*/
|
|
80
|
+
function isDuplicateCheckpoint(message) {
|
|
81
|
+
const last = getLastCommitMessage();
|
|
82
|
+
if (!last) return false;
|
|
83
|
+
return last.trim() === String(message || '').trim();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Commit a checkpoint for a perf phase.
|
|
88
|
+
* @param {object} input
|
|
89
|
+
* @returns {{ ok: boolean, message?: string, reason?: string }}
|
|
90
|
+
*/
|
|
91
|
+
function commitCheckpoint(input) {
|
|
92
|
+
try {
|
|
93
|
+
execFileSync('git', ['rev-parse', '--is-inside-work-tree'], { stdio: 'ignore' });
|
|
94
|
+
} catch {
|
|
95
|
+
return { ok: false, reason: 'not a git repo' };
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (isWorkingTreeClean()) {
|
|
99
|
+
return { ok: false, reason: 'nothing to commit' };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const message = buildCheckpointMessage(input);
|
|
103
|
+
if (isDuplicateCheckpoint(message)) {
|
|
104
|
+
return { ok: false, reason: 'duplicate checkpoint' };
|
|
105
|
+
}
|
|
106
|
+
const perfDir = path.join(getStateDir(), 'perf');
|
|
107
|
+
try {
|
|
108
|
+
execFileSync('git', ['add', '-A', '--', perfDir], { stdio: 'ignore' });
|
|
109
|
+
} catch {
|
|
110
|
+
execFileSync('git', ['add', '-A'], { stdio: 'ignore' });
|
|
111
|
+
}
|
|
112
|
+
execFileSync('git', ['commit', '-m', message], { stdio: 'ignore' });
|
|
113
|
+
return { ok: true, message };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = {
|
|
117
|
+
isWorkingTreeClean,
|
|
118
|
+
buildCheckpointMessage,
|
|
119
|
+
getLastCommitMessage,
|
|
120
|
+
getRecentCommits,
|
|
121
|
+
isDuplicateCheckpoint,
|
|
122
|
+
commitCheckpoint
|
|
123
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code-path discovery helpers for /perf.
|
|
3
|
+
*
|
|
4
|
+
* @module lib/perf/code-paths
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const DEFAULT_STOPWORDS = new Set([
|
|
8
|
+
'the', 'and', 'for', 'with', 'from', 'that', 'this', 'these', 'those',
|
|
9
|
+
'into', 'over', 'under', 'than', 'then', 'when', 'where', 'what', 'which',
|
|
10
|
+
'your', 'you', 'our', 'their', 'there', 'have', 'has', 'had', 'will',
|
|
11
|
+
'would', 'should', 'could', 'about', 'across', 'after', 'before', 'while',
|
|
12
|
+
'perf', 'performance', 'investigation', 'baseline', 'benchmark', 'scenario'
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
function normalizeKeywords(text) {
|
|
16
|
+
if (!text || typeof text !== 'string') return [];
|
|
17
|
+
const tokens = text
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.split(/[^a-z0-9]+/g)
|
|
20
|
+
.filter(Boolean)
|
|
21
|
+
.filter(token => token.length > 2)
|
|
22
|
+
.filter(token => !DEFAULT_STOPWORDS.has(token));
|
|
23
|
+
|
|
24
|
+
return Array.from(new Set(tokens));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function scoreEntry(entry, keywords) {
|
|
28
|
+
let score = 0;
|
|
29
|
+
if (!entry || keywords.length === 0) return score;
|
|
30
|
+
|
|
31
|
+
const haystack = [
|
|
32
|
+
entry.file || '',
|
|
33
|
+
...(entry.symbols || [])
|
|
34
|
+
].join(' ').toLowerCase();
|
|
35
|
+
|
|
36
|
+
for (const keyword of keywords) {
|
|
37
|
+
if (haystack.includes(keyword)) score += 1;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return score;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function extractSymbols(fileData) {
|
|
44
|
+
if (!fileData || !fileData.symbols) return [];
|
|
45
|
+
const symbols = [];
|
|
46
|
+
for (const group of Object.values(fileData.symbols)) {
|
|
47
|
+
if (!Array.isArray(group)) continue;
|
|
48
|
+
for (const symbol of group) {
|
|
49
|
+
if (symbol && symbol.name) symbols.push(symbol.name);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return symbols;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function collectCodePaths(repoMap, scenario, limit = 12) {
|
|
56
|
+
if (!repoMap || !repoMap.files) {
|
|
57
|
+
return { keywords: normalizeKeywords(scenario), paths: [] };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const keywords = normalizeKeywords(scenario);
|
|
61
|
+
const candidates = [];
|
|
62
|
+
|
|
63
|
+
for (const [file, data] of Object.entries(repoMap.files)) {
|
|
64
|
+
const symbols = extractSymbols(data);
|
|
65
|
+
const entry = { file, symbols };
|
|
66
|
+
const score = scoreEntry(entry, keywords);
|
|
67
|
+
if (score <= 0) continue;
|
|
68
|
+
candidates.push({ ...entry, score });
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
candidates.sort((a, b) => b.score - a.score || a.file.localeCompare(b.file));
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
keywords,
|
|
75
|
+
paths: candidates.slice(0, limit).map(item => ({
|
|
76
|
+
file: item.file,
|
|
77
|
+
score: item.score,
|
|
78
|
+
symbols: item.symbols.slice(0, 8)
|
|
79
|
+
}))
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = {
|
|
84
|
+
normalizeKeywords,
|
|
85
|
+
collectCodePaths
|
|
86
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Baseline consolidation helper.
|
|
3
|
+
*
|
|
4
|
+
* @module lib/perf/consolidation
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const baselineStore = require('./baseline-store');
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Consolidate a baseline for a version (overwrite existing).
|
|
11
|
+
* @param {object} input
|
|
12
|
+
* @param {string} input.version
|
|
13
|
+
* @param {object} input.baseline
|
|
14
|
+
* @param {string} [basePath]
|
|
15
|
+
* @returns {{ version: string, path: string }}
|
|
16
|
+
*/
|
|
17
|
+
function consolidateBaseline(input, basePath = process.cwd()) {
|
|
18
|
+
if (!input || typeof input !== 'object') {
|
|
19
|
+
throw new Error('consolidateBaseline requires an input object');
|
|
20
|
+
}
|
|
21
|
+
const { version, baseline } = input;
|
|
22
|
+
|
|
23
|
+
if (!version || typeof version !== 'string') {
|
|
24
|
+
throw new Error('version is required');
|
|
25
|
+
}
|
|
26
|
+
if (!baseline || typeof baseline !== 'object') {
|
|
27
|
+
throw new Error('baseline is required');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
baselineStore.writeBaseline(version, baseline, basePath);
|
|
31
|
+
const path = baselineStore.getBaselinePath(version, basePath);
|
|
32
|
+
return { version, path };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
consolidateBaseline
|
|
37
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Constraint testing runner for /perf.
|
|
3
|
+
*
|
|
4
|
+
* @module lib/perf/constraint-runner
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { runBenchmarkSeries, DEFAULT_MIN_DURATION } = require('./benchmark-runner');
|
|
8
|
+
const { compareBaselines } = require('./baseline-comparator');
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Run baseline and constrained benchmarks sequentially.
|
|
12
|
+
* Constraints are provided via env vars to keep it cross-platform.
|
|
13
|
+
*
|
|
14
|
+
* @param {object} options
|
|
15
|
+
* @param {string} options.command
|
|
16
|
+
* @param {object} options.constraints
|
|
17
|
+
* @param {number} [options.duration]
|
|
18
|
+
* @param {number} [options.minDuration]
|
|
19
|
+
* @param {number} [options.runs]
|
|
20
|
+
* @param {string} [options.aggregate]
|
|
21
|
+
* @param {object} [options.env]
|
|
22
|
+
* @returns {{ constraints: object, baseline: object, constrained: object, delta: object }}
|
|
23
|
+
*/
|
|
24
|
+
function runConstraintTest(options) {
|
|
25
|
+
const { command, constraints, duration, minDuration, runs, aggregate, env } = options || {};
|
|
26
|
+
|
|
27
|
+
if (!command || typeof command !== 'string') {
|
|
28
|
+
throw new Error('command must be a non-empty string');
|
|
29
|
+
}
|
|
30
|
+
if (!constraints || typeof constraints !== 'object' || Array.isArray(constraints)) {
|
|
31
|
+
throw new Error('constraints must be an object');
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const baselineResult = runBenchmarkSeries(command, {
|
|
35
|
+
duration: duration ?? DEFAULT_MIN_DURATION,
|
|
36
|
+
minDuration,
|
|
37
|
+
runs,
|
|
38
|
+
aggregate,
|
|
39
|
+
env: {
|
|
40
|
+
...env
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const constrainedResult = runBenchmarkSeries(command, {
|
|
45
|
+
duration: duration ?? DEFAULT_MIN_DURATION,
|
|
46
|
+
minDuration,
|
|
47
|
+
runs,
|
|
48
|
+
aggregate,
|
|
49
|
+
env: {
|
|
50
|
+
...env,
|
|
51
|
+
PERF_CPU_LIMIT: constraints.cpu,
|
|
52
|
+
PERF_MEMORY_LIMIT: constraints.memory
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
const delta = compareBaselines(
|
|
57
|
+
{ metrics: baselineResult.metrics },
|
|
58
|
+
{ metrics: constrainedResult.metrics }
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
constraints,
|
|
63
|
+
baseline: { metrics: baselineResult.metrics },
|
|
64
|
+
constrained: { metrics: constrainedResult.metrics },
|
|
65
|
+
delta
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
module.exports = {
|
|
70
|
+
runConstraintTest
|
|
71
|
+
};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Experiment runner utilities.
|
|
3
|
+
*
|
|
4
|
+
* @module lib/perf/experiment-runner
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Run experiments sequentially (never parallel).
|
|
9
|
+
* @param {Array<object>} experiments
|
|
10
|
+
* @param {(experiment:object)=>Promise<object>} runner
|
|
11
|
+
* @returns {Promise<{results:Array<object>}>}
|
|
12
|
+
*/
|
|
13
|
+
async function runExperiments(experiments, runner) {
|
|
14
|
+
if (!Array.isArray(experiments)) {
|
|
15
|
+
throw new Error('experiments must be an array');
|
|
16
|
+
}
|
|
17
|
+
if (typeof runner !== 'function') {
|
|
18
|
+
throw new Error('runner must be a function');
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const results = [];
|
|
22
|
+
for (const experiment of experiments) {
|
|
23
|
+
const result = await runner(experiment);
|
|
24
|
+
results.push(result);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return { results };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = {
|
|
31
|
+
runExperiments
|
|
32
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performance investigation utilities
|
|
3
|
+
*
|
|
4
|
+
* @module lib/perf
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const investigationState = require('./investigation-state');
|
|
8
|
+
const baselineStore = require('./baseline-store');
|
|
9
|
+
const baselineComparator = require('./baseline-comparator');
|
|
10
|
+
const benchmarkRunner = require('./benchmark-runner');
|
|
11
|
+
const breakingPointFinder = require('./breaking-point-finder');
|
|
12
|
+
const breakingPointRunner = require('./breaking-point-runner');
|
|
13
|
+
const experimentRunner = require('./experiment-runner');
|
|
14
|
+
const constraintRunner = require('./constraint-runner');
|
|
15
|
+
const checkpoint = require('./checkpoint');
|
|
16
|
+
const profilingRunner = require('./profiling-runner');
|
|
17
|
+
const optimizationRunner = require('./optimization-runner');
|
|
18
|
+
const consolidation = require('./consolidation');
|
|
19
|
+
const profilers = require('./profilers');
|
|
20
|
+
const analyzer = require('./analyzer');
|
|
21
|
+
const argumentParser = require('./argument-parser');
|
|
22
|
+
const codePaths = require('./code-paths');
|
|
23
|
+
|
|
24
|
+
module.exports = {
|
|
25
|
+
investigationState,
|
|
26
|
+
baselineStore,
|
|
27
|
+
baselineComparator,
|
|
28
|
+
benchmarkRunner,
|
|
29
|
+
breakingPointFinder,
|
|
30
|
+
breakingPointRunner,
|
|
31
|
+
experimentRunner,
|
|
32
|
+
constraintRunner,
|
|
33
|
+
checkpoint,
|
|
34
|
+
profilingRunner,
|
|
35
|
+
optimizationRunner,
|
|
36
|
+
consolidation,
|
|
37
|
+
profilers,
|
|
38
|
+
analyzer,
|
|
39
|
+
argumentParser,
|
|
40
|
+
codePaths
|
|
41
|
+
};
|