agentsys 5.0.0 → 5.0.2
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 +13 -13
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +19 -2
- package/README.md +1 -0
- package/adapters/README.md +1 -1
- package/adapters/codex/skills/consult/SKILL.md +3 -2
- package/adapters/codex/skills/next-task/SKILL.md +8 -8
- package/adapters/opencode/agents/consult-agent.md +1 -1
- package/adapters/opencode/agents/delivery-validator.md +1 -1
- package/adapters/opencode/agents/implementation-agent.md +1 -1
- package/adapters/opencode/agents/worktree-manager.md +3 -3
- package/adapters/opencode/commands/consult.md +3 -2
- package/adapters/opencode/commands/next-task.md +7 -7
- package/adapters/opencode/skills/agnix/SKILL.md +1 -1
- package/adapters/opencode/skills/consult/SKILL.md +16 -4
- package/adapters/opencode/skills/deslop/SKILL.md +1 -1
- package/adapters/opencode/skills/discover-tasks/SKILL.md +2 -2
- package/adapters/opencode/skills/drift-analysis/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-agent-prompts/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-claude-memory/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-cross-file/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-docs/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-hooks/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-orchestrator/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-plugins/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-prompts/SKILL.md +1 -1
- package/adapters/opencode/skills/enhance-skills/SKILL.md +1 -1
- package/adapters/opencode/skills/learn/SKILL.md +1 -1
- package/adapters/opencode/skills/orchestrate-review/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-analyzer/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-baseline-manager/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-benchmarker/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-code-paths/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-investigation-logger/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-profiler/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-theory-gatherer/SKILL.md +1 -1
- package/adapters/opencode/skills/perf-theory-tester/SKILL.md +1 -1
- package/adapters/opencode/skills/sync-docs/SKILL.md +1 -1
- package/adapters/opencode/skills/validate-delivery/SKILL.md +2 -2
- package/bin/cli.js +42 -8
- package/bin/dev-cli.js +16 -6
- package/lib/collectors/github.js +76 -12
- package/lib/perf/benchmark-runner.js +11 -6
- package/lib/perf/investigation-state.js +12 -13
- package/lib/perf/profiling-runner.js +23 -4
- package/lib/repo-map/concurrency.js +29 -0
- package/lib/repo-map/runner.js +218 -19
- package/lib/repo-map/updater.js +115 -27
- package/lib/state/workflow-state.js +31 -30
- package/lib/utils/command-parser.js +0 -0
- package/lib/utils/state-helpers.js +61 -0
- package/package.json +2 -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/collectors/github.js +76 -12
- package/plugins/audit-project/lib/perf/benchmark-runner.js +11 -6
- package/plugins/audit-project/lib/perf/investigation-state.js +12 -13
- package/plugins/audit-project/lib/perf/profiling-runner.js +23 -4
- package/plugins/audit-project/lib/repo-map/concurrency.js +29 -0
- package/plugins/audit-project/lib/repo-map/runner.js +218 -19
- package/plugins/audit-project/lib/repo-map/updater.js +115 -27
- package/plugins/audit-project/lib/state/workflow-state.js +31 -30
- package/plugins/audit-project/lib/utils/command-parser.js +0 -0
- package/plugins/audit-project/lib/utils/state-helpers.js +61 -0
- package/plugins/consult/.claude-plugin/plugin.json +1 -1
- package/plugins/consult/agents/consult-agent.md +1 -1
- package/plugins/consult/commands/consult.md +3 -2
- package/plugins/consult/skills/consult/SKILL.md +16 -4
- package/plugins/deslop/.claude-plugin/plugin.json +1 -1
- package/plugins/deslop/lib/collectors/github.js +76 -12
- package/plugins/deslop/lib/perf/benchmark-runner.js +11 -6
- package/plugins/deslop/lib/perf/investigation-state.js +12 -13
- package/plugins/deslop/lib/perf/profiling-runner.js +23 -4
- package/plugins/deslop/lib/repo-map/concurrency.js +29 -0
- package/plugins/deslop/lib/repo-map/runner.js +218 -19
- package/plugins/deslop/lib/repo-map/updater.js +115 -27
- package/plugins/deslop/lib/state/workflow-state.js +31 -30
- package/plugins/deslop/lib/utils/command-parser.js +0 -0
- package/plugins/deslop/lib/utils/state-helpers.js +61 -0
- package/plugins/deslop/skills/deslop/SKILL.md +1 -1
- package/plugins/drift-detect/.claude-plugin/plugin.json +1 -1
- package/plugins/drift-detect/lib/collectors/github.js +76 -12
- package/plugins/drift-detect/lib/perf/benchmark-runner.js +11 -6
- package/plugins/drift-detect/lib/perf/investigation-state.js +12 -13
- package/plugins/drift-detect/lib/perf/profiling-runner.js +23 -4
- package/plugins/drift-detect/lib/repo-map/concurrency.js +29 -0
- package/plugins/drift-detect/lib/repo-map/runner.js +218 -19
- package/plugins/drift-detect/lib/repo-map/updater.js +115 -27
- package/plugins/drift-detect/lib/state/workflow-state.js +31 -30
- package/plugins/drift-detect/lib/utils/command-parser.js +0 -0
- package/plugins/drift-detect/lib/utils/state-helpers.js +61 -0
- package/plugins/drift-detect/skills/drift-analysis/SKILL.md +1 -1
- package/plugins/enhance/.claude-plugin/plugin.json +1 -1
- package/plugins/enhance/lib/collectors/github.js +76 -12
- package/plugins/enhance/lib/perf/benchmark-runner.js +11 -6
- package/plugins/enhance/lib/perf/investigation-state.js +12 -13
- package/plugins/enhance/lib/perf/profiling-runner.js +23 -4
- package/plugins/enhance/lib/repo-map/concurrency.js +29 -0
- package/plugins/enhance/lib/repo-map/runner.js +218 -19
- package/plugins/enhance/lib/repo-map/updater.js +115 -27
- package/plugins/enhance/lib/state/workflow-state.js +31 -30
- package/plugins/enhance/lib/utils/command-parser.js +0 -0
- package/plugins/enhance/lib/utils/state-helpers.js +61 -0
- 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/lib/collectors/github.js +76 -12
- package/plugins/learn/lib/perf/benchmark-runner.js +11 -6
- package/plugins/learn/lib/perf/investigation-state.js +12 -13
- package/plugins/learn/lib/perf/profiling-runner.js +23 -4
- package/plugins/learn/lib/repo-map/concurrency.js +29 -0
- package/plugins/learn/lib/repo-map/runner.js +218 -19
- package/plugins/learn/lib/repo-map/updater.js +115 -27
- package/plugins/learn/lib/state/workflow-state.js +31 -30
- package/plugins/learn/lib/utils/command-parser.js +0 -0
- package/plugins/learn/lib/utils/state-helpers.js +61 -0
- package/plugins/learn/skills/learn/SKILL.md +1 -1
- package/plugins/next-task/.claude-plugin/plugin.json +1 -1
- package/plugins/next-task/agents/delivery-validator.md +1 -1
- package/plugins/next-task/agents/implementation-agent.md +2 -2
- package/plugins/next-task/agents/worktree-manager.md +3 -3
- package/plugins/next-task/commands/next-task.md +8 -8
- package/plugins/next-task/hooks/hooks.json +1 -1
- package/plugins/next-task/lib/collectors/github.js +76 -12
- package/plugins/next-task/lib/perf/benchmark-runner.js +11 -6
- package/plugins/next-task/lib/perf/investigation-state.js +12 -13
- package/plugins/next-task/lib/perf/profiling-runner.js +23 -4
- package/plugins/next-task/lib/repo-map/concurrency.js +29 -0
- package/plugins/next-task/lib/repo-map/runner.js +218 -19
- package/plugins/next-task/lib/repo-map/updater.js +115 -27
- package/plugins/next-task/lib/state/workflow-state.js +31 -30
- package/plugins/next-task/lib/utils/command-parser.js +0 -0
- package/plugins/next-task/lib/utils/state-helpers.js +61 -0
- package/plugins/next-task/skills/discover-tasks/SKILL.md +2 -2
- package/plugins/next-task/skills/orchestrate-review/SKILL.md +1 -1
- package/plugins/next-task/skills/validate-delivery/SKILL.md +2 -2
- package/plugins/perf/.claude-plugin/plugin.json +1 -1
- package/plugins/perf/lib/collectors/github.js +76 -12
- package/plugins/perf/lib/perf/benchmark-runner.js +11 -6
- package/plugins/perf/lib/perf/investigation-state.js +12 -13
- package/plugins/perf/lib/perf/profiling-runner.js +23 -4
- package/plugins/perf/lib/repo-map/concurrency.js +29 -0
- package/plugins/perf/lib/repo-map/runner.js +218 -19
- package/plugins/perf/lib/repo-map/updater.js +115 -27
- package/plugins/perf/lib/state/workflow-state.js +31 -30
- package/plugins/perf/lib/utils/command-parser.js +0 -0
- package/plugins/perf/lib/utils/state-helpers.js +61 -0
- 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/collectors/github.js +76 -12
- package/plugins/repo-map/lib/perf/benchmark-runner.js +11 -6
- package/plugins/repo-map/lib/perf/investigation-state.js +12 -13
- package/plugins/repo-map/lib/perf/profiling-runner.js +23 -4
- package/plugins/repo-map/lib/repo-map/concurrency.js +29 -0
- package/plugins/repo-map/lib/repo-map/runner.js +218 -19
- package/plugins/repo-map/lib/repo-map/updater.js +115 -27
- package/plugins/repo-map/lib/state/workflow-state.js +31 -30
- package/plugins/repo-map/lib/utils/command-parser.js +0 -0
- package/plugins/repo-map/lib/utils/state-helpers.js +61 -0
- package/plugins/ship/.claude-plugin/plugin.json +1 -1
- package/plugins/ship/lib/collectors/github.js +76 -12
- package/plugins/ship/lib/perf/benchmark-runner.js +11 -6
- package/plugins/ship/lib/perf/investigation-state.js +12 -13
- package/plugins/ship/lib/perf/profiling-runner.js +23 -4
- package/plugins/ship/lib/repo-map/concurrency.js +29 -0
- package/plugins/ship/lib/repo-map/runner.js +218 -19
- package/plugins/ship/lib/repo-map/updater.js +115 -27
- package/plugins/ship/lib/state/workflow-state.js +31 -30
- package/plugins/ship/lib/utils/command-parser.js +0 -0
- package/plugins/ship/lib/utils/state-helpers.js +61 -0
- package/plugins/sync-docs/.claude-plugin/plugin.json +1 -1
- package/plugins/sync-docs/lib/collectors/github.js +76 -12
- package/plugins/sync-docs/lib/perf/benchmark-runner.js +11 -6
- package/plugins/sync-docs/lib/perf/investigation-state.js +12 -13
- package/plugins/sync-docs/lib/perf/profiling-runner.js +23 -4
- package/plugins/sync-docs/lib/repo-map/concurrency.js +29 -0
- package/plugins/sync-docs/lib/repo-map/runner.js +218 -19
- package/plugins/sync-docs/lib/repo-map/updater.js +115 -27
- package/plugins/sync-docs/lib/state/workflow-state.js +31 -30
- package/plugins/sync-docs/lib/utils/command-parser.js +0 -0
- package/plugins/sync-docs/lib/utils/state-helpers.js +61 -0
- package/plugins/sync-docs/skills/sync-docs/SKILL.md +1 -1
- package/scripts/bump-version.js +4 -1
- package/scripts/dev-install.js +9 -0
- package/scripts/validate-opencode-install.js +17 -4
- package/site/content.json +1 -1
- package/site/index.html +1 -1
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
---
|
|
3
3
|
name: sync-docs
|
|
4
4
|
description: "Sync documentation with code. Use when user asks to update docs, check docs, fix stale documentation, update changelog, or after code changes."
|
|
5
|
-
version: 5.0.
|
|
5
|
+
version: 5.0.2
|
|
6
6
|
argument-hint: "[report|apply] [--scope=all|recent|before-pr] [--include-undocumented]"
|
|
7
7
|
allowed-tools: Bash(git:*), Read, Grep, Glob
|
|
8
8
|
---
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<!-- AUTO-GENERATED by scripts/gen-adapters.js - DO NOT EDIT -->
|
|
2
2
|
---
|
|
3
3
|
name: validate-delivery
|
|
4
|
-
description: "Use when
|
|
5
|
-
version: 5.0.
|
|
4
|
+
description: "Use when user asks to \"validate delivery\", \"check readiness\", or \"verify completion\". Runs tests, build, and requirement checks with pass/fail instructions."
|
|
5
|
+
version: 5.0.2
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# validate-delivery
|
package/bin/cli.js
CHANGED
|
@@ -214,10 +214,17 @@ function installForClaude() {
|
|
|
214
214
|
|
|
215
215
|
// Discover plugins from filesystem convention
|
|
216
216
|
const plugins = discovery.discoverPlugins(PACKAGE_DIR);
|
|
217
|
+
const failedPlugins = [];
|
|
217
218
|
for (const plugin of plugins) {
|
|
218
219
|
// Validate plugin name before shell use (prevents injection)
|
|
219
220
|
if (!/^[a-z0-9][a-z0-9-]*$/.test(plugin)) continue;
|
|
220
221
|
console.log(` Installing ${plugin}...`);
|
|
222
|
+
// Remove pre-rename plugin ID to prevent dual loading on upgrade
|
|
223
|
+
try {
|
|
224
|
+
execSync(`claude plugin uninstall ${plugin}@awesome-slash`, { stdio: 'pipe' });
|
|
225
|
+
} catch {
|
|
226
|
+
// Not installed under old name
|
|
227
|
+
}
|
|
221
228
|
try {
|
|
222
229
|
// Try install first
|
|
223
230
|
execSync(`claude plugin install ${plugin}@agentsys`, { stdio: 'pipe' });
|
|
@@ -226,11 +233,17 @@ function installForClaude() {
|
|
|
226
233
|
try {
|
|
227
234
|
execSync(`claude plugin update ${plugin}@agentsys`, { stdio: 'pipe' });
|
|
228
235
|
} catch {
|
|
229
|
-
|
|
236
|
+
failedPlugins.push(plugin);
|
|
230
237
|
}
|
|
231
238
|
}
|
|
232
239
|
}
|
|
233
240
|
|
|
241
|
+
if (failedPlugins.length > 0) {
|
|
242
|
+
console.log(`\n[ERROR] Failed to install/update ${failedPlugins.length} plugin(s): ${failedPlugins.join(', ')}`);
|
|
243
|
+
console.log('Retry with: /plugin install <plugin>@agentsys');
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
246
|
+
|
|
234
247
|
console.log('\n[OK] Claude Code installation complete!\n');
|
|
235
248
|
console.log('Commands: ' + plugins.map(p => '/' + p).join(', '));
|
|
236
249
|
return true;
|
|
@@ -328,9 +341,11 @@ function installForOpenCode(installDir, options = {}) {
|
|
|
328
341
|
// OpenCode global locations are under ~/.config/opencode (or $XDG_CONFIG_HOME/opencode).
|
|
329
342
|
const commandsDir = path.join(opencodeConfigDir, 'commands');
|
|
330
343
|
const pluginDir = path.join(opencodeConfigDir, 'plugins');
|
|
344
|
+
const agentsDir = path.join(opencodeConfigDir, 'agents');
|
|
331
345
|
|
|
332
346
|
fs.mkdirSync(commandsDir, { recursive: true });
|
|
333
347
|
fs.mkdirSync(pluginDir, { recursive: true });
|
|
348
|
+
fs.mkdirSync(agentsDir, { recursive: true });
|
|
334
349
|
|
|
335
350
|
// Install native OpenCode plugin (auto-thinking, workflow enforcement, compaction)
|
|
336
351
|
const pluginSrcDir = path.join(installDir, 'adapters', 'opencode-plugin');
|
|
@@ -384,10 +399,17 @@ function installForOpenCode(installDir, options = {}) {
|
|
|
384
399
|
}
|
|
385
400
|
}
|
|
386
401
|
|
|
402
|
+
// Remove legacy agent files from pre-rename installs.
|
|
403
|
+
const legacyAgentFiles = ['review.md', 'ship.md', 'workflow.md'];
|
|
404
|
+
for (const legacyFile of legacyAgentFiles) {
|
|
405
|
+
const legacyPath = path.join(agentsDir, legacyFile);
|
|
406
|
+
if (fs.existsSync(legacyPath)) {
|
|
407
|
+
fs.unlinkSync(legacyPath);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
387
411
|
// Install agents to global OpenCode location
|
|
388
412
|
// OpenCode looks for agents in ~/.config/opencode/agents/ (global) or .opencode/agents/ (per-project)
|
|
389
|
-
const agentsDir = path.join(opencodeConfigDir, 'agents');
|
|
390
|
-
fs.mkdirSync(agentsDir, { recursive: true });
|
|
391
413
|
|
|
392
414
|
console.log(' Installing agents for OpenCode...');
|
|
393
415
|
const pluginDirs = discovery.discoverPlugins(installDir);
|
|
@@ -681,24 +703,36 @@ async function main() {
|
|
|
681
703
|
}
|
|
682
704
|
|
|
683
705
|
// Install for each platform
|
|
706
|
+
const failedPlatforms = [];
|
|
684
707
|
for (const platform of selected) {
|
|
685
708
|
switch (platform) {
|
|
686
709
|
case 'claude':
|
|
687
|
-
if (args.development) {
|
|
688
|
-
|
|
710
|
+
if (args.development && !installForClaudeDevelopment()) {
|
|
711
|
+
failedPlatforms.push('claude');
|
|
689
712
|
} else {
|
|
690
|
-
installForClaude()
|
|
713
|
+
if (!args.development && !installForClaude()) {
|
|
714
|
+
failedPlatforms.push('claude');
|
|
715
|
+
}
|
|
691
716
|
}
|
|
692
717
|
break;
|
|
693
718
|
case 'opencode':
|
|
694
|
-
installForOpenCode(installDir, { stripModels: args.stripModels })
|
|
719
|
+
if (!installForOpenCode(installDir, { stripModels: args.stripModels })) {
|
|
720
|
+
failedPlatforms.push('opencode');
|
|
721
|
+
}
|
|
695
722
|
break;
|
|
696
723
|
case 'codex':
|
|
697
|
-
installForCodex(installDir)
|
|
724
|
+
if (!installForCodex(installDir)) {
|
|
725
|
+
failedPlatforms.push('codex');
|
|
726
|
+
}
|
|
698
727
|
break;
|
|
699
728
|
}
|
|
700
729
|
}
|
|
701
730
|
|
|
731
|
+
if (failedPlatforms.length > 0) {
|
|
732
|
+
console.log(`\n[ERROR] Installation failed for: ${failedPlatforms.join(', ')}`);
|
|
733
|
+
process.exitCode = 1;
|
|
734
|
+
}
|
|
735
|
+
|
|
702
736
|
console.log('─'.repeat(45));
|
|
703
737
|
if (installDir) {
|
|
704
738
|
console.log(`\nInstallation directory: ${installDir}`);
|
package/bin/dev-cli.js
CHANGED
|
@@ -13,7 +13,8 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
const path = require('path');
|
|
16
|
-
const { execSync } = require('child_process');
|
|
16
|
+
const { execSync, spawnSync } = require('child_process');
|
|
17
|
+
const { resolveExecutableForPlatform } = require('../lib/utils/command-parser');
|
|
17
18
|
|
|
18
19
|
const VERSION = require('../package.json').version;
|
|
19
20
|
const ROOT_DIR = path.join(__dirname, '..');
|
|
@@ -293,13 +294,22 @@ const COMMANDS = {
|
|
|
293
294
|
description: 'Run test suite',
|
|
294
295
|
handler: (args) => {
|
|
295
296
|
try {
|
|
296
|
-
const
|
|
297
|
+
const cmdArgs = ['test'];
|
|
297
298
|
if (args.length > 0) {
|
|
298
|
-
|
|
299
|
-
|
|
299
|
+
cmdArgs.push('--');
|
|
300
|
+
cmdArgs.push(...args);
|
|
300
301
|
}
|
|
301
|
-
|
|
302
|
-
|
|
302
|
+
const npmExecutable = resolveExecutableForPlatform('npm');
|
|
303
|
+
const result = spawnSync(npmExecutable, cmdArgs, {
|
|
304
|
+
cwd: ROOT_DIR,
|
|
305
|
+
stdio: 'inherit',
|
|
306
|
+
shell: false,
|
|
307
|
+
windowsHide: true
|
|
308
|
+
});
|
|
309
|
+
if (result.error) {
|
|
310
|
+
throw result.error;
|
|
311
|
+
}
|
|
312
|
+
return typeof result.status === 'number' ? result.status : 1;
|
|
303
313
|
} catch (err) {
|
|
304
314
|
return err.status || 1;
|
|
305
315
|
}
|
package/lib/collectors/github.js
CHANGED
|
@@ -14,6 +14,7 @@ const { execFileSync } = require('child_process');
|
|
|
14
14
|
const DEFAULT_OPTIONS = {
|
|
15
15
|
issueLimit: 100,
|
|
16
16
|
prLimit: 50,
|
|
17
|
+
milestoneLimit: 100,
|
|
17
18
|
timeout: 10000,
|
|
18
19
|
cwd: process.cwd()
|
|
19
20
|
};
|
|
@@ -25,16 +26,41 @@ const DEFAULT_OPTIONS = {
|
|
|
25
26
|
* @returns {Object|null} Parsed JSON result or null
|
|
26
27
|
*/
|
|
27
28
|
function execGh(args, options = {}) {
|
|
29
|
+
const result = execGhWithResult(args, options);
|
|
30
|
+
return result.ok ? result.data : null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function execGhWithResult(args, options = {}) {
|
|
28
34
|
try {
|
|
29
|
-
const
|
|
35
|
+
const output = execFileSync('gh', args, {
|
|
30
36
|
encoding: 'utf8',
|
|
31
37
|
stdio: 'pipe',
|
|
32
38
|
timeout: options.timeout || DEFAULT_OPTIONS.timeout,
|
|
33
39
|
cwd: options.cwd || DEFAULT_OPTIONS.cwd
|
|
34
40
|
});
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
return { ok: true, data: JSON.parse(output) };
|
|
44
|
+
} catch (error) {
|
|
45
|
+
return {
|
|
46
|
+
ok: false,
|
|
47
|
+
error: {
|
|
48
|
+
type: 'parse',
|
|
49
|
+
message: `Failed to parse gh output as JSON: ${error.message}`,
|
|
50
|
+
raw: output.slice(0, 500)
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
return {
|
|
56
|
+
ok: false,
|
|
57
|
+
error: {
|
|
58
|
+
type: error.killed ? 'timeout' : 'process',
|
|
59
|
+
message: error.message,
|
|
60
|
+
exitCode: error.status ?? null,
|
|
61
|
+
stderr: error.stderr ? String(error.stderr).trim() : ''
|
|
62
|
+
}
|
|
63
|
+
};
|
|
38
64
|
}
|
|
39
65
|
}
|
|
40
66
|
|
|
@@ -192,10 +218,18 @@ function scanGitHubState(options = {}) {
|
|
|
192
218
|
|
|
193
219
|
const result = {
|
|
194
220
|
available: false,
|
|
221
|
+
partial: false,
|
|
222
|
+
errors: [],
|
|
195
223
|
summary: { issueCount: 0, prCount: 0, milestoneCount: 0 },
|
|
196
224
|
issues: [],
|
|
197
225
|
prs: [],
|
|
198
226
|
milestones: [],
|
|
227
|
+
overdueMilestones: [],
|
|
228
|
+
pagination: {
|
|
229
|
+
issues: { requestedLimit: opts.issueLimit, fetchedCount: 0, hasMore: false },
|
|
230
|
+
prs: { requestedLimit: opts.prLimit, fetchedCount: 0, hasMore: false },
|
|
231
|
+
milestones: { requestedLimit: opts.milestoneLimit, fetchedCount: 0, hasMore: false }
|
|
232
|
+
},
|
|
199
233
|
categorized: { bugs: [], features: [], security: [], enhancements: [], other: [] },
|
|
200
234
|
stale: [],
|
|
201
235
|
themes: []
|
|
@@ -209,44 +243,74 @@ function scanGitHubState(options = {}) {
|
|
|
209
243
|
result.available = true;
|
|
210
244
|
|
|
211
245
|
// Fetch open issues
|
|
212
|
-
const
|
|
246
|
+
const issuesResult = execGhWithResult([
|
|
213
247
|
'issue', 'list',
|
|
214
248
|
'--state', 'open',
|
|
215
249
|
'--json', 'number,title,labels,milestone,createdAt,updatedAt,body',
|
|
216
250
|
'--limit', String(opts.issueLimit)
|
|
217
251
|
], opts);
|
|
218
252
|
|
|
219
|
-
if (
|
|
253
|
+
if (issuesResult.ok && Array.isArray(issuesResult.data)) {
|
|
254
|
+
const issues = issuesResult.data;
|
|
220
255
|
result.issues = issues.map(summarizeIssue);
|
|
221
256
|
result.summary.issueCount = issues.length;
|
|
257
|
+
result.pagination.issues.fetchedCount = issues.length;
|
|
258
|
+
result.pagination.issues.hasMore = opts.issueLimit > 0 && issues.length >= opts.issueLimit;
|
|
222
259
|
categorizeIssues(result, issues);
|
|
223
260
|
findStaleItems(result, issues, 90);
|
|
224
261
|
extractThemes(result, issues);
|
|
262
|
+
} else if (!issuesResult.ok) {
|
|
263
|
+
result.errors.push({ source: 'issues', ...issuesResult.error });
|
|
225
264
|
}
|
|
226
265
|
|
|
227
266
|
// Fetch open PRs with files changed
|
|
228
|
-
const
|
|
267
|
+
const prsResult = execGhWithResult([
|
|
229
268
|
'pr', 'list',
|
|
230
269
|
'--state', 'open',
|
|
231
270
|
'--json', 'number,title,labels,isDraft,createdAt,updatedAt,body,files',
|
|
232
271
|
'--limit', String(opts.prLimit)
|
|
233
272
|
], opts);
|
|
234
273
|
|
|
235
|
-
if (
|
|
274
|
+
if (prsResult.ok && Array.isArray(prsResult.data)) {
|
|
275
|
+
const prs = prsResult.data;
|
|
236
276
|
result.prs = prs.map(summarizePR);
|
|
237
277
|
result.summary.prCount = prs.length;
|
|
278
|
+
result.pagination.prs.fetchedCount = prs.length;
|
|
279
|
+
result.pagination.prs.hasMore = opts.prLimit > 0 && prs.length >= opts.prLimit;
|
|
280
|
+
} else if (!prsResult.ok) {
|
|
281
|
+
result.errors.push({ source: 'prs', ...prsResult.error });
|
|
238
282
|
}
|
|
239
283
|
|
|
240
284
|
// Fetch milestones
|
|
241
|
-
const
|
|
285
|
+
const milestonesResult = execGhWithResult([
|
|
242
286
|
'api', 'repos/{owner}/{repo}/milestones',
|
|
243
|
-
'--
|
|
287
|
+
'--paginate',
|
|
288
|
+
'--slurp'
|
|
244
289
|
], opts);
|
|
245
290
|
|
|
246
|
-
if (
|
|
247
|
-
|
|
291
|
+
if (milestonesResult.ok && Array.isArray(milestonesResult.data)) {
|
|
292
|
+
const pages = milestonesResult.data;
|
|
293
|
+
const allMilestones = pages.flatMap(page => Array.isArray(page) ? page : []);
|
|
294
|
+
const mappedMilestones = allMilestones.map((milestone) => ({
|
|
295
|
+
title: milestone.title,
|
|
296
|
+
state: milestone.state,
|
|
297
|
+
due_on: milestone.due_on,
|
|
298
|
+
open_issues: milestone.open_issues,
|
|
299
|
+
closed_issues: milestone.closed_issues
|
|
300
|
+
}));
|
|
301
|
+
|
|
302
|
+
result.pagination.milestones.fetchedCount = mappedMilestones.length;
|
|
303
|
+
result.pagination.milestones.hasMore = opts.milestoneLimit > 0 && mappedMilestones.length > opts.milestoneLimit;
|
|
304
|
+
result.milestones = mappedMilestones.slice(0, opts.milestoneLimit);
|
|
248
305
|
result.summary.milestoneCount = result.milestones.length;
|
|
249
306
|
findOverdueMilestones(result);
|
|
307
|
+
} else if (!milestonesResult.ok) {
|
|
308
|
+
result.errors.push({ source: 'milestones', ...milestonesResult.error });
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
result.partial = result.errors.length > 0;
|
|
312
|
+
if (result.partial && !result.error) {
|
|
313
|
+
result.error = 'Partial GitHub data collected';
|
|
250
314
|
}
|
|
251
315
|
|
|
252
316
|
return result;
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* @module lib/perf/benchmark-runner
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const {
|
|
7
|
+
const { execFileSync } = require('child_process');
|
|
8
8
|
const { validateBaseline } = require('./schemas');
|
|
9
|
+
const { parseCommand, resolveExecutableForPlatform } = require('../utils/command-parser');
|
|
9
10
|
|
|
10
11
|
const DEFAULT_MIN_DURATION = 60;
|
|
11
12
|
const BINARY_SEARCH_MIN_DURATION = 30;
|
|
@@ -55,6 +56,8 @@ function runBenchmark(command, options = {}) {
|
|
|
55
56
|
throw new Error('Benchmark command must be a non-empty string');
|
|
56
57
|
}
|
|
57
58
|
|
|
59
|
+
const parsedCommand = parseCommand(command, 'Benchmark command');
|
|
60
|
+
const executable = resolveExecutableForPlatform(parsedCommand.executable);
|
|
58
61
|
const normalized = normalizeBenchmarkOptions(options);
|
|
59
62
|
const setDurationEnv = options.setDurationEnv !== false;
|
|
60
63
|
const env = {
|
|
@@ -71,18 +74,20 @@ function runBenchmark(command, options = {}) {
|
|
|
71
74
|
const start = Date.now();
|
|
72
75
|
let output;
|
|
73
76
|
try {
|
|
74
|
-
output =
|
|
77
|
+
output = execFileSync(executable, parsedCommand.args, {
|
|
75
78
|
stdio: 'pipe',
|
|
76
79
|
encoding: 'utf8',
|
|
77
|
-
env
|
|
80
|
+
env,
|
|
81
|
+
windowsHide: true,
|
|
82
|
+
cwd: options.cwd || process.cwd()
|
|
78
83
|
});
|
|
79
84
|
} catch (error) {
|
|
80
|
-
const stderr = error.stderr ? error.stderr
|
|
81
|
-
const stdout = error.stdout ? error.stdout
|
|
85
|
+
const stderr = error.stderr ? String(error.stderr).trim() : '';
|
|
86
|
+
const stdout = error.stdout ? String(error.stdout).trim() : '';
|
|
82
87
|
const exitCode = error.status ?? 'unknown';
|
|
83
88
|
const details = stderr || stdout || error.message || 'No error details available';
|
|
84
89
|
throw new Error(
|
|
85
|
-
`Benchmark command failed (exit code ${exitCode}): ${
|
|
90
|
+
`Benchmark command failed (exit code ${exitCode}): ${parsedCommand.display}\n` +
|
|
86
91
|
`Details: ${details}`
|
|
87
92
|
);
|
|
88
93
|
}
|
|
@@ -14,12 +14,12 @@ const crypto = require('crypto');
|
|
|
14
14
|
const { getStateDir } = require('../platform/state-dir');
|
|
15
15
|
const { validateInvestigationState, assertValid } = require('./schemas');
|
|
16
16
|
const { writeJsonAtomic, writeFileAtomic } = require('../utils/atomic-write');
|
|
17
|
+
const { isPlainObject, updatesApplied, sleepForRetry } = require('../utils/state-helpers');
|
|
17
18
|
|
|
18
19
|
const SCHEMA_VERSION = 1;
|
|
19
20
|
const INVESTIGATION_FILE = 'investigation.json';
|
|
20
21
|
const LOG_DIR = 'investigations';
|
|
21
22
|
const BASELINE_DIR = 'baselines';
|
|
22
|
-
|
|
23
23
|
const PHASES = [
|
|
24
24
|
'setup',
|
|
25
25
|
'baseline',
|
|
@@ -196,10 +196,12 @@ function writeInvestigation(state, basePath = process.cwd()) {
|
|
|
196
196
|
* @returns {object|null}
|
|
197
197
|
*/
|
|
198
198
|
function updateInvestigation(updates, basePath = process.cwd()) {
|
|
199
|
-
const MAX_RETRIES =
|
|
199
|
+
const MAX_RETRIES = 5;
|
|
200
|
+
let fallbackState = null;
|
|
200
201
|
|
|
201
202
|
for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
|
|
202
203
|
const current = readInvestigation(basePath) || {};
|
|
204
|
+
fallbackState = current;
|
|
203
205
|
const initialVersion = current._version || 0;
|
|
204
206
|
const nextState = { ...current };
|
|
205
207
|
|
|
@@ -209,10 +211,7 @@ function updateInvestigation(updates, basePath = process.cwd()) {
|
|
|
209
211
|
|
|
210
212
|
if (value === null) {
|
|
211
213
|
nextState[key] = null;
|
|
212
|
-
} else if (
|
|
213
|
-
value && typeof value === 'object' && !Array.isArray(value) &&
|
|
214
|
-
nextState[key] && typeof nextState[key] === 'object' && !Array.isArray(nextState[key])
|
|
215
|
-
) {
|
|
214
|
+
} else if (isPlainObject(value) && isPlainObject(nextState[key])) {
|
|
216
215
|
nextState[key] = { ...nextState[key], ...value };
|
|
217
216
|
} else {
|
|
218
217
|
nextState[key] = value;
|
|
@@ -226,23 +225,23 @@ function updateInvestigation(updates, basePath = process.cwd()) {
|
|
|
226
225
|
|
|
227
226
|
// Re-read to verify our write succeeded
|
|
228
227
|
const afterWrite = readInvestigation(basePath);
|
|
229
|
-
if (afterWrite
|
|
228
|
+
if (afterWrite) {
|
|
229
|
+
fallbackState = afterWrite;
|
|
230
|
+
}
|
|
231
|
+
if (afterWrite && afterWrite._version >= initialVersion + 1 && updatesApplied(afterWrite, updates)) {
|
|
230
232
|
return afterWrite; // Success
|
|
231
233
|
}
|
|
232
234
|
|
|
233
235
|
// Version conflict - retry after brief delay
|
|
234
236
|
if (attempt < MAX_RETRIES - 1) {
|
|
235
237
|
const delay = Math.floor(Math.random() * 50) + 10;
|
|
236
|
-
|
|
237
|
-
while (Date.now() - start < delay) {
|
|
238
|
-
// Busy wait (synchronous delay)
|
|
239
|
-
}
|
|
238
|
+
sleepForRetry(delay);
|
|
240
239
|
}
|
|
241
240
|
}
|
|
242
241
|
|
|
243
242
|
// All retries exhausted
|
|
244
|
-
console.error('[
|
|
245
|
-
return readInvestigation(basePath);
|
|
243
|
+
console.error('[ERROR] updateInvestigation: failed to apply updates after max retries');
|
|
244
|
+
return readInvestigation(basePath) || fallbackState || { ...updates };
|
|
246
245
|
}
|
|
247
246
|
|
|
248
247
|
/**
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* @module lib/perf/profiling-runner
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const {
|
|
7
|
+
const { execFileSync } = require('child_process');
|
|
8
8
|
const profilers = require('./profilers');
|
|
9
|
+
const { parseCommand, resolveExecutableForPlatform } = require('../utils/command-parser');
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Run a profiling command and return artifacts/hotspots metadata.
|
|
@@ -16,6 +17,9 @@ const profilers = require('./profilers');
|
|
|
16
17
|
*/
|
|
17
18
|
function runProfiling(options = {}) {
|
|
18
19
|
const repoPath = options.repoPath || process.cwd();
|
|
20
|
+
const timeoutMs = Number.isFinite(options.timeoutMs)
|
|
21
|
+
? Math.max(1, Math.floor(options.timeoutMs))
|
|
22
|
+
: null;
|
|
19
23
|
const profiler = profilers.selectProfiler(repoPath);
|
|
20
24
|
|
|
21
25
|
if (!profiler || typeof profiler.buildCommand !== 'function') {
|
|
@@ -27,14 +31,29 @@ function runProfiling(options = {}) {
|
|
|
27
31
|
output: options.output,
|
|
28
32
|
...(options.profileOptions || {})
|
|
29
33
|
});
|
|
34
|
+
const parsedCommand = parseCommand(command, 'Profiling command');
|
|
35
|
+
const executable = resolveExecutableForPlatform(parsedCommand.executable);
|
|
30
36
|
const env = {
|
|
31
37
|
...process.env,
|
|
32
38
|
...(options.env || {})
|
|
33
39
|
};
|
|
34
40
|
try {
|
|
35
|
-
|
|
41
|
+
const execOptions = {
|
|
42
|
+
stdio: 'pipe',
|
|
43
|
+
env,
|
|
44
|
+
cwd: repoPath,
|
|
45
|
+
windowsHide: true
|
|
46
|
+
};
|
|
47
|
+
if (timeoutMs !== null) {
|
|
48
|
+
execOptions.timeout = timeoutMs;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
execFileSync(executable, parsedCommand.args, execOptions);
|
|
36
52
|
} catch (error) {
|
|
37
|
-
|
|
53
|
+
const stderr = error.stderr ? String(error.stderr).trim() : '';
|
|
54
|
+
const stdout = error.stdout ? String(error.stdout).trim() : '';
|
|
55
|
+
const details = stderr || stdout || error.message;
|
|
56
|
+
return { ok: false, error: `Profiling command failed: ${details}` };
|
|
38
57
|
}
|
|
39
58
|
|
|
40
59
|
const parsed = typeof profiler.parseOutput === 'function'
|
|
@@ -43,7 +62,7 @@ function runProfiling(options = {}) {
|
|
|
43
62
|
|
|
44
63
|
const result = {
|
|
45
64
|
tool: profiler.id,
|
|
46
|
-
command,
|
|
65
|
+
command: parsedCommand.display,
|
|
47
66
|
hotspots: parsed.hotspots || [],
|
|
48
67
|
artifacts: parsed.artifacts || []
|
|
49
68
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
async function runWithConcurrency(items, limit, worker) {
|
|
4
|
+
if (!Array.isArray(items) || items.length === 0) {
|
|
5
|
+
return [];
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const maxConcurrency = Math.max(1, Math.min(items.length, Math.floor(limit) || 1));
|
|
9
|
+
const results = new Array(items.length);
|
|
10
|
+
let cursor = 0;
|
|
11
|
+
|
|
12
|
+
async function runWorker() {
|
|
13
|
+
while (true) {
|
|
14
|
+
const index = cursor;
|
|
15
|
+
cursor += 1;
|
|
16
|
+
if (index >= items.length) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
results[index] = await worker(items[index], index);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
await Promise.all(Array.from({ length: maxConcurrency }, () => runWorker()));
|
|
24
|
+
return results;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
module.exports = {
|
|
28
|
+
runWithConcurrency
|
|
29
|
+
};
|