@ai-sdlc/orchestrator 0.6.0 → 0.10.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/dist/__test-helpers/git-env.d.ts +40 -0
- package/dist/__test-helpers/git-env.js +73 -0
- package/dist/admission-composite.d.ts +89 -0
- package/dist/admission-composite.js +241 -0
- package/dist/admission-enrichment.d.ts +142 -0
- package/dist/admission-enrichment.js +341 -0
- package/dist/admission-hc.d.ts +81 -0
- package/dist/admission-hc.js +94 -0
- package/dist/admission-score.d.ts +109 -5
- package/dist/admission-score.js +90 -11
- package/dist/analysis/analyzer.js +3 -2
- package/dist/analysis/convention-detector.d.ts +85 -2
- package/dist/analysis/convention-detector.js +375 -70
- package/dist/analysis/diff-analyzer.d.ts +33 -0
- package/dist/analysis/diff-analyzer.js +122 -0
- package/dist/analysis/hotspot-analyzer.js +3 -1
- package/dist/analysis/index.d.ts +2 -1
- package/dist/analysis/index.js +2 -1
- package/dist/artifacts/index.d.ts +65 -0
- package/dist/artifacts/index.js +142 -0
- package/dist/backlog-adapter.d.ts +121 -0
- package/dist/backlog-adapter.js +438 -0
- package/dist/calibration.d.ts +43 -0
- package/dist/calibration.js +76 -0
- package/dist/cli/commands/agents.d.ts +24 -0
- package/dist/cli/commands/agents.js +66 -1
- package/dist/cli/commands/git-remote.d.ts +74 -0
- package/dist/cli/commands/git-remote.js +170 -0
- package/dist/cli/commands/health.d.ts +4 -0
- package/dist/cli/commands/health.js +13 -1
- package/dist/cli/commands/init-features.d.ts +208 -0
- package/dist/cli/commands/init-features.js +473 -0
- package/dist/cli/commands/init-templates.d.ts +104 -0
- package/dist/cli/commands/init-templates.js +399 -0
- package/dist/cli/commands/init.d.ts +48 -0
- package/dist/cli/commands/init.js +322 -23
- package/dist/cli/commands/mcp-setup.d.ts +31 -0
- package/dist/cli/commands/mcp-setup.js +78 -8
- package/dist/cli/formatters/table.js +15 -2
- package/dist/cli/index.d.ts +14 -1
- package/dist/cli/index.js +81 -20
- package/dist/cli/versions.d.ts +57 -0
- package/dist/cli/versions.js +128 -0
- package/dist/code-area-classifier.d.ts +21 -0
- package/dist/code-area-classifier.js +48 -0
- package/dist/config.d.ts +33 -1
- package/dist/config.js +78 -8
- package/dist/database/adapters/external.d.ts +24 -0
- package/dist/database/adapters/external.js +80 -0
- package/dist/database/adapters/neon.d.ts +41 -0
- package/dist/database/adapters/neon.js +98 -0
- package/dist/database/adapters/pg-snapshot-restore.d.ts +28 -0
- package/dist/database/adapters/pg-snapshot-restore.js +68 -0
- package/dist/database/adapters/sqlite-copy.d.ts +32 -0
- package/dist/database/adapters/sqlite-copy.js +145 -0
- package/dist/database/connection-injection.d.ts +35 -0
- package/dist/database/connection-injection.js +93 -0
- package/dist/database/index.d.ts +12 -0
- package/dist/database/index.js +23 -0
- package/dist/database/registry.d.ts +13 -0
- package/dist/database/registry.js +27 -0
- package/dist/database/topology.d.ts +52 -0
- package/dist/database/topology.js +44 -0
- package/dist/database/types.d.ts +89 -0
- package/dist/database/types.js +26 -0
- package/dist/design-authority.d.ts +53 -0
- package/dist/design-authority.js +84 -0
- package/dist/design-lookahead.d.ts +64 -0
- package/dist/design-lookahead.js +86 -0
- package/dist/design-quality-trend.d.ts +87 -0
- package/dist/design-quality-trend.js +190 -0
- package/dist/design-system-context.d.ts +46 -0
- package/dist/design-system-context.js +80 -0
- package/dist/design-system-correction-loop.d.ts +64 -0
- package/dist/design-system-correction-loop.js +128 -0
- package/dist/design-system-metrics.d.ts +61 -0
- package/dist/design-system-metrics.js +104 -0
- package/dist/design-system-stewardship.d.ts +22 -0
- package/dist/design-system-stewardship.js +85 -0
- package/dist/design-system-validation.d.ts +37 -0
- package/dist/design-system-validation.js +88 -0
- package/dist/dispatch/index.d.ts +4 -0
- package/dist/dispatch/index.js +4 -0
- package/dist/dispatch/merge-gate.d.ts +46 -0
- package/dist/dispatch/merge-gate.js +90 -0
- package/dist/dispatch/requeue.d.ts +57 -0
- package/dist/dispatch/requeue.js +131 -0
- package/dist/dispatch/worker-pool.d.ts +62 -0
- package/dist/dispatch/worker-pool.js +60 -0
- package/dist/execute.d.ts +40 -0
- package/dist/execute.js +188 -15
- package/dist/fix-ci.js +8 -1
- package/dist/fix-review.js +8 -1
- package/dist/harness/adapters/claude-code.d.ts +29 -0
- package/dist/harness/adapters/claude-code.js +191 -0
- package/dist/harness/adapters/codex.d.ts +25 -0
- package/dist/harness/adapters/codex.js +61 -0
- package/dist/harness/independence.d.ts +51 -0
- package/dist/harness/independence.js +67 -0
- package/dist/harness/index.d.ts +14 -0
- package/dist/harness/index.js +20 -0
- package/dist/harness/registry.d.ts +17 -0
- package/dist/harness/registry.js +31 -0
- package/dist/harness/types.d.ts +123 -0
- package/dist/harness/types.js +8 -0
- package/dist/harness/version-probe.d.ts +14 -0
- package/dist/harness/version-probe.js +123 -0
- package/dist/index.d.ts +30 -4
- package/dist/index.js +35 -2
- package/dist/models/classifier.d.ts +78 -0
- package/dist/models/classifier.js +277 -0
- package/dist/models/index.d.ts +3 -0
- package/dist/models/index.js +3 -0
- package/dist/models/registry.d.ts +97 -0
- package/dist/models/registry.js +173 -0
- package/dist/pillar-breakdown.d.ts +85 -0
- package/dist/pillar-breakdown.js +162 -0
- package/dist/priority.d.ts +5 -0
- package/dist/priority.js +18 -5
- package/dist/review-meta.d.ts +65 -0
- package/dist/review-meta.js +149 -0
- package/dist/review.d.ts +4 -0
- package/dist/review.js +12 -2
- package/dist/runners/claude-code-sdk.d.ts +31 -0
- package/dist/runners/claude-code-sdk.js +238 -0
- package/dist/runners/claude-code.d.ts +3 -0
- package/dist/runners/claude-code.js +30 -66
- package/dist/runners/codex.js +4 -1
- package/dist/runners/copilot.js +4 -1
- package/dist/runners/cursor.js +4 -1
- package/dist/runners/git-utils.d.ts +81 -0
- package/dist/runners/git-utils.js +201 -0
- package/dist/runners/index.d.ts +3 -0
- package/dist/runners/index.js +3 -0
- package/dist/runners/review-agent.d.ts +20 -0
- package/dist/runners/review-agent.js +171 -41
- package/dist/runners/runner-registry.js +10 -0
- package/dist/runners/sdk-review-runner.d.ts +65 -0
- package/dist/runners/sdk-review-runner.js +185 -0
- package/dist/runners/security-triage.d.ts +20 -4
- package/dist/runners/security-triage.js +39 -15
- package/dist/runners/types.d.ts +6 -0
- package/dist/runtime/attestations.d.ts +766 -0
- package/dist/runtime/attestations.js +1195 -0
- package/dist/runtime/git-env.d.ts +53 -0
- package/dist/runtime/git-env.js +60 -0
- package/dist/runtime/index.d.ts +7 -0
- package/dist/runtime/index.js +7 -0
- package/dist/runtime/parallelism-flag.d.ts +28 -0
- package/dist/runtime/parallelism-flag.js +39 -0
- package/dist/runtime/port-allocator.d.ts +32 -0
- package/dist/runtime/port-allocator.js +96 -0
- package/dist/runtime/worktree-pool.d.ts +86 -0
- package/dist/runtime/worktree-pool.js +204 -0
- package/dist/runtime/worktree.d.ts +25 -0
- package/dist/runtime/worktree.js +111 -0
- package/dist/sa-scoring/auto-calibrate.d.ts +69 -0
- package/dist/sa-scoring/auto-calibrate.js +107 -0
- package/dist/sa-scoring/c1-sa2-computable.d.ts +42 -0
- package/dist/sa-scoring/c1-sa2-computable.js +59 -0
- package/dist/sa-scoring/composite.d.ts +107 -0
- package/dist/sa-scoring/composite.js +139 -0
- package/dist/sa-scoring/depparse-client.d.ts +79 -0
- package/dist/sa-scoring/depparse-client.js +187 -0
- package/dist/sa-scoring/did-compiler.d.ts +122 -0
- package/dist/sa-scoring/did-compiler.js +286 -0
- package/dist/sa-scoring/drift-monitor.d.ts +84 -0
- package/dist/sa-scoring/drift-monitor.js +186 -0
- package/dist/sa-scoring/exemplar-bank.d.ts +78 -0
- package/dist/sa-scoring/exemplar-bank.js +154 -0
- package/dist/sa-scoring/feedback-store.d.ts +100 -0
- package/dist/sa-scoring/feedback-store.js +156 -0
- package/dist/sa-scoring/index.d.ts +71 -0
- package/dist/sa-scoring/index.js +158 -0
- package/dist/sa-scoring/layer1-deterministic.d.ts +115 -0
- package/dist/sa-scoring/layer1-deterministic.js +298 -0
- package/dist/sa-scoring/layer2-structural.d.ts +71 -0
- package/dist/sa-scoring/layer2-structural.js +151 -0
- package/dist/sa-scoring/layer3-llm.d.ts +86 -0
- package/dist/sa-scoring/layer3-llm.js +282 -0
- package/dist/sa-scoring/rescore-orchestrator.d.ts +52 -0
- package/dist/sa-scoring/rescore-orchestrator.js +47 -0
- package/dist/scheduling/burn-down.d.ts +27 -0
- package/dist/scheduling/burn-down.js +43 -0
- package/dist/scheduling/calibration.d.ts +42 -0
- package/dist/scheduling/calibration.js +150 -0
- package/dist/scheduling/index.d.ts +8 -0
- package/dist/scheduling/index.js +8 -0
- package/dist/scheduling/ledger.d.ts +59 -0
- package/dist/scheduling/ledger.js +216 -0
- package/dist/scheduling/off-peak.d.ts +27 -0
- package/dist/scheduling/off-peak.js +112 -0
- package/dist/scheduling/schedule-decision.d.ts +39 -0
- package/dist/scheduling/schedule-decision.js +89 -0
- package/dist/scheduling/tier-analysis.d.ts +47 -0
- package/dist/scheduling/tier-analysis.js +81 -0
- package/dist/scheduling/types.d.ts +140 -0
- package/dist/scheduling/types.js +11 -0
- package/dist/shared.d.ts +13 -0
- package/dist/shared.js +32 -0
- package/dist/state/schema.d.ts +5 -1
- package/dist/state/schema.js +223 -1
- package/dist/state/store.d.ts +55 -1
- package/dist/state/store.js +342 -7
- package/dist/state/types.d.ts +139 -0
- package/dist/types.d.ts +1 -1
- package/dist/validate-agent-output.js +4 -1
- package/dist/watch.js +6 -0
- package/package.json +3 -2
package/dist/cli/index.d.ts
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* AI-SDLC CLI — entry point for the Commander-based CLI.
|
|
4
|
+
*
|
|
5
|
+
* AISDLC-78: replaces the literal `0.1.0` version with the real package
|
|
6
|
+
* version, prints a 3-line provenance block on `--version`, and adds an
|
|
7
|
+
* unknown-subcommand hint that points at the upgrade flow when version
|
|
8
|
+
* drift is detected.
|
|
4
9
|
*/
|
|
5
|
-
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
import { type VersionTriple } from './versions.js';
|
|
12
|
+
/**
|
|
13
|
+
* Build the Commander program. Exported so integration tests can drive
|
|
14
|
+
* the real argv pipeline (`--version`, unknown-subcommand) without
|
|
15
|
+
* invoking the bundled binary on disk. The bin shim below calls this
|
|
16
|
+
* exact factory at startup.
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildProgram(versions: VersionTriple): Command;
|
|
6
19
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/cli/index.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* AI-SDLC CLI — entry point for the Commander-based CLI.
|
|
4
|
+
*
|
|
5
|
+
* AISDLC-78: replaces the literal `0.1.0` version with the real package
|
|
6
|
+
* version, prints a 3-line provenance block on `--version`, and adds an
|
|
7
|
+
* unknown-subcommand hint that points at the upgrade flow when version
|
|
8
|
+
* drift is detected.
|
|
4
9
|
*/
|
|
5
10
|
import { Command } from 'commander';
|
|
6
11
|
import { initCommand } from './commands/init.js';
|
|
@@ -14,24 +19,80 @@ import { complexityCommand } from './commands/complexity.js';
|
|
|
14
19
|
import { costCommand } from './commands/cost.js';
|
|
15
20
|
import { dashboardCommand } from './commands/dashboard.js';
|
|
16
21
|
import { validateCommand } from './commands/validate.js';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
program
|
|
26
|
-
program
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
22
|
+
import { resolveVersions, formatVersionBlock, upgradeHint, } from './versions.js';
|
|
23
|
+
/**
|
|
24
|
+
* Build the Commander program. Exported so integration tests can drive
|
|
25
|
+
* the real argv pipeline (`--version`, unknown-subcommand) without
|
|
26
|
+
* invoking the bundled binary on disk. The bin shim below calls this
|
|
27
|
+
* exact factory at startup.
|
|
28
|
+
*/
|
|
29
|
+
export function buildProgram(versions) {
|
|
30
|
+
const program = new Command();
|
|
31
|
+
program
|
|
32
|
+
.name('ai-sdlc')
|
|
33
|
+
.description('AI-SDLC Orchestrator — drive issues through the SDLC with AI agents')
|
|
34
|
+
// Anchor commander's --version to the real package version so a user
|
|
35
|
+
// who just ran `npm i -g @ai-sdlc/orchestrator` sees the version they
|
|
36
|
+
// installed, not the literal that was hardcoded years ago.
|
|
37
|
+
.version(versions.cli, '-V, --version', 'Print the CLI version')
|
|
38
|
+
.option('-c, --config <dir>', 'Config directory path', '.ai-sdlc')
|
|
39
|
+
.option('-f, --format <type>', 'Output format: table, json, minimal', 'table')
|
|
40
|
+
.option('-v, --verbose', 'Enable verbose output');
|
|
41
|
+
// Override commander's default --version handler so we can emit the full
|
|
42
|
+
// 3-line block (CLI + orchestrator + plugin) instead of just the literal.
|
|
43
|
+
//
|
|
44
|
+
// IMPORTANT: commander 12's `.version()` registers its own
|
|
45
|
+
// `option:version` listener (in registration order) that writes the
|
|
46
|
+
// bare version string and calls `_exit`. Plain `.on()` would queue
|
|
47
|
+
// *after* commander's listener, so our 3-line block would never
|
|
48
|
+
// print. `prependListener` puts ours first; calling commander's own
|
|
49
|
+
// `_exit` here prevents the default listener from ever firing while
|
|
50
|
+
// still going through `exitOverride()` so tests can intercept.
|
|
51
|
+
// commander's Command extends EventEmitter; the .d.ts only re-exports
|
|
52
|
+
// .on/.once, so we reach for prependListener via the EventEmitter cast.
|
|
53
|
+
program.prependListener('option:version', () => {
|
|
54
|
+
const writeOut = program.configureOutput().writeOut ?? ((s) => process.stdout.write(s));
|
|
55
|
+
writeOut(`${formatVersionBlock(versions)}\n`);
|
|
56
|
+
program._exit(0, 'commander.version', versions.cli);
|
|
57
|
+
});
|
|
58
|
+
program.addCommand(initCommand);
|
|
59
|
+
program.addCommand(runCommand);
|
|
60
|
+
program.addCommand(startCommand);
|
|
61
|
+
program.addCommand(statusCommand);
|
|
62
|
+
program.addCommand(healthCommand);
|
|
63
|
+
program.addCommand(agentsCommand);
|
|
64
|
+
program.addCommand(routingCommand);
|
|
65
|
+
program.addCommand(complexityCommand);
|
|
66
|
+
program.addCommand(costCommand);
|
|
67
|
+
program.addCommand(dashboardCommand);
|
|
68
|
+
program.addCommand(validateCommand);
|
|
69
|
+
// Unknown-subcommand handler (AC #9): hint at version drift / upgrade so
|
|
70
|
+
// users who installed an outdated CLI find out fast.
|
|
71
|
+
program.on('command:*', (operands) => {
|
|
72
|
+
const unknown = operands[0] ?? '';
|
|
73
|
+
const writeErr = program.configureOutput().writeErr ?? ((s) => process.stderr.write(s));
|
|
74
|
+
writeErr(`Unknown subcommand: ${unknown}\n`);
|
|
75
|
+
writeErr('\n');
|
|
76
|
+
writeErr(`${upgradeHint(versions)}\n`);
|
|
77
|
+
writeErr('\n');
|
|
78
|
+
writeErr('Run `ai-sdlc --help` to see the available subcommands.\n');
|
|
79
|
+
program._exit(1, 'commander.unknownCommand', unknown);
|
|
80
|
+
});
|
|
81
|
+
return program;
|
|
82
|
+
}
|
|
83
|
+
// Bin entry: only run argv parsing when invoked as a script, not when the
|
|
84
|
+
// module is imported by tests.
|
|
85
|
+
//
|
|
86
|
+
// `process.argv[1]` is the path Node resolved for the entry script.
|
|
87
|
+
// When it ends with the compiled CLI bundle (`dist/cli/index.js`) we are
|
|
88
|
+
// the main entry. When imported (e.g. via Vitest) argv[1] points at the
|
|
89
|
+
// test runner, so we skip parsing.
|
|
90
|
+
const isMainEntry = (() => {
|
|
91
|
+
const entry = process.argv[1] ?? '';
|
|
92
|
+
return entry.endsWith('cli/index.js') || entry.endsWith('cli/index.ts');
|
|
93
|
+
})();
|
|
94
|
+
if (isMainEntry) {
|
|
95
|
+
const program = buildProgram(resolveVersions());
|
|
96
|
+
program.parse();
|
|
97
|
+
}
|
|
37
98
|
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version provenance — surface the running CLI, orchestrator runtime,
|
|
3
|
+
* and (optionally) plugin versions in one place so users can spot drift.
|
|
4
|
+
*
|
|
5
|
+
* Why this exists: the original CLI hardcoded `0.1.0` in commander while
|
|
6
|
+
* the published `@ai-sdlc/orchestrator` package was at 0.6.0+. Operators
|
|
7
|
+
* who ran `ai-sdlc --version` saw the stale literal and assumed the
|
|
8
|
+
* orchestrator itself was that old. AISDLC-78 anchors `--version` to
|
|
9
|
+
* the package.json that ships with the binary and warns when components
|
|
10
|
+
* disagree.
|
|
11
|
+
*/
|
|
12
|
+
export interface VersionTriple {
|
|
13
|
+
/** The CLI binary's reported version. Tracks the orchestrator package. */
|
|
14
|
+
cli: string;
|
|
15
|
+
/** The orchestrator runtime version (from @ai-sdlc/orchestrator/package.json). */
|
|
16
|
+
orchestrator: string;
|
|
17
|
+
/** The plugin version, if discoverable in the workspace. */
|
|
18
|
+
plugin?: string;
|
|
19
|
+
/** Whether any of the discoverable components disagree on version. */
|
|
20
|
+
drift: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface ResolveVersionsOptions {
|
|
23
|
+
/** Override the working directory used to discover the plugin. */
|
|
24
|
+
workDir?: string;
|
|
25
|
+
/** Inject an orchestrator package.json path (testing). */
|
|
26
|
+
orchestratorPackageJsonPath?: string;
|
|
27
|
+
/** Inject a plugin version (testing). */
|
|
28
|
+
pluginVersionOverride?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Compute the active CLI/orchestrator/plugin versions.
|
|
32
|
+
*
|
|
33
|
+
* Drift detection: when at least two known components disagree on
|
|
34
|
+
* version string (case-insensitive), `drift` is set. The plugin is
|
|
35
|
+
* compared only when discovered.
|
|
36
|
+
*/
|
|
37
|
+
export declare function resolveVersions(opts?: ResolveVersionsOptions): VersionTriple;
|
|
38
|
+
/**
|
|
39
|
+
* Render the canonical 3-line version block. Always emits a
|
|
40
|
+
* trailing newline. When drift is detected, appends a warning line
|
|
41
|
+
* pointing at the upgrade hint.
|
|
42
|
+
*
|
|
43
|
+
* The CLI and orchestrator rows are rendered separately even though
|
|
44
|
+
* today they always show the same number — both ship from the same
|
|
45
|
+
* `@ai-sdlc/orchestrator` package.json. The shape is intentionally
|
|
46
|
+
* future-proofed: when the CLI is split into a thinner veneer with
|
|
47
|
+
* its own version it will start to differ from the orchestrator
|
|
48
|
+
* runtime, and operators are then trained to read both rows. Until
|
|
49
|
+
* then a duplicate value is the honest answer.
|
|
50
|
+
*/
|
|
51
|
+
export declare function formatVersionBlock(versions: VersionTriple): string;
|
|
52
|
+
/**
|
|
53
|
+
* Return the upgrade hint shown by unknown-subcommand handler and by
|
|
54
|
+
* version drift warnings. Centralised so tests can assert one string.
|
|
55
|
+
*/
|
|
56
|
+
export declare function upgradeHint(versions: VersionTriple): string;
|
|
57
|
+
//# sourceMappingURL=versions.d.ts.map
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Version provenance — surface the running CLI, orchestrator runtime,
|
|
3
|
+
* and (optionally) plugin versions in one place so users can spot drift.
|
|
4
|
+
*
|
|
5
|
+
* Why this exists: the original CLI hardcoded `0.1.0` in commander while
|
|
6
|
+
* the published `@ai-sdlc/orchestrator` package was at 0.6.0+. Operators
|
|
7
|
+
* who ran `ai-sdlc --version` saw the stale literal and assumed the
|
|
8
|
+
* orchestrator itself was that old. AISDLC-78 anchors `--version` to
|
|
9
|
+
* the package.json that ships with the binary and warns when components
|
|
10
|
+
* disagree.
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
13
|
+
import { dirname, join, resolve } from 'node:path';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
15
|
+
const FALLBACK_VERSION = '0.0.0';
|
|
16
|
+
function readPackageVersion(pkgPath) {
|
|
17
|
+
try {
|
|
18
|
+
if (!existsSync(pkgPath))
|
|
19
|
+
return undefined;
|
|
20
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
21
|
+
return pkg.version;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return undefined;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolve the orchestrator package's own package.json. The CLI bundle
|
|
29
|
+
* lives at `dist/cli/index.js` so we walk up two levels.
|
|
30
|
+
*/
|
|
31
|
+
function findOrchestratorPackageJson() {
|
|
32
|
+
// import.meta.url points at the compiled CLI module location.
|
|
33
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
34
|
+
// Try ../package.json (when running from dist/cli/) and ../../package.json
|
|
35
|
+
// (when running from src/cli/ in tests via tsx).
|
|
36
|
+
const candidates = [
|
|
37
|
+
resolve(here, '..', 'package.json'),
|
|
38
|
+
resolve(here, '..', '..', 'package.json'),
|
|
39
|
+
];
|
|
40
|
+
for (const candidate of candidates) {
|
|
41
|
+
if (existsSync(candidate)) {
|
|
42
|
+
try {
|
|
43
|
+
const pkg = JSON.parse(readFileSync(candidate, 'utf-8'));
|
|
44
|
+
if (pkg.name === '@ai-sdlc/orchestrator')
|
|
45
|
+
return candidate;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// continue
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return candidates[0];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Best-effort search for the plugin manifest. We look in the project
|
|
56
|
+
* working directory first (the common case for a co-located checkout),
|
|
57
|
+
* then a few well-known parent paths. Returns undefined silently when
|
|
58
|
+
* not found — the plugin is optional metadata.
|
|
59
|
+
*/
|
|
60
|
+
function findPluginVersion(workDir) {
|
|
61
|
+
const tries = [
|
|
62
|
+
join(workDir, 'ai-sdlc-plugin', 'plugin.json'),
|
|
63
|
+
join(workDir, '..', 'ai-sdlc-plugin', 'plugin.json'),
|
|
64
|
+
join(workDir, '..', '..', 'ai-sdlc-plugin', 'plugin.json'),
|
|
65
|
+
];
|
|
66
|
+
for (const t of tries) {
|
|
67
|
+
const v = readPackageVersion(t);
|
|
68
|
+
if (v)
|
|
69
|
+
return v;
|
|
70
|
+
}
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Compute the active CLI/orchestrator/plugin versions.
|
|
75
|
+
*
|
|
76
|
+
* Drift detection: when at least two known components disagree on
|
|
77
|
+
* version string (case-insensitive), `drift` is set. The plugin is
|
|
78
|
+
* compared only when discovered.
|
|
79
|
+
*/
|
|
80
|
+
export function resolveVersions(opts = {}) {
|
|
81
|
+
const orchPath = opts.orchestratorPackageJsonPath ?? findOrchestratorPackageJson();
|
|
82
|
+
const orchestrator = readPackageVersion(orchPath) ?? FALLBACK_VERSION;
|
|
83
|
+
// The CLI ships from the same package.json today, so cli === orchestrator
|
|
84
|
+
// by construction. Drift detection between cli/orchestrator is therefore
|
|
85
|
+
// a no-op until the CLI is split out (planned: a thinner veneer that
|
|
86
|
+
// versions independently of the runtime). We keep them logically
|
|
87
|
+
// separate so callers and tests don't have to change shape on that day.
|
|
88
|
+
const cli = orchestrator;
|
|
89
|
+
const plugin = opts.pluginVersionOverride ?? findPluginVersion(opts.workDir ?? process.cwd());
|
|
90
|
+
const observed = [cli, orchestrator, plugin].filter((v) => Boolean(v));
|
|
91
|
+
const drift = new Set(observed.map((v) => v.toLowerCase())).size > 1;
|
|
92
|
+
return { cli, orchestrator, plugin, drift };
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Render the canonical 3-line version block. Always emits a
|
|
96
|
+
* trailing newline. When drift is detected, appends a warning line
|
|
97
|
+
* pointing at the upgrade hint.
|
|
98
|
+
*
|
|
99
|
+
* The CLI and orchestrator rows are rendered separately even though
|
|
100
|
+
* today they always show the same number — both ship from the same
|
|
101
|
+
* `@ai-sdlc/orchestrator` package.json. The shape is intentionally
|
|
102
|
+
* future-proofed: when the CLI is split into a thinner veneer with
|
|
103
|
+
* its own version it will start to differ from the orchestrator
|
|
104
|
+
* runtime, and operators are then trained to read both rows. Until
|
|
105
|
+
* then a duplicate value is the honest answer.
|
|
106
|
+
*/
|
|
107
|
+
export function formatVersionBlock(versions) {
|
|
108
|
+
const lines = [
|
|
109
|
+
`ai-sdlc CLI: ${versions.cli}`,
|
|
110
|
+
`orchestrator: ${versions.orchestrator}`,
|
|
111
|
+
`plugin: ${versions.plugin ?? '(not detected)'}`,
|
|
112
|
+
];
|
|
113
|
+
if (versions.drift) {
|
|
114
|
+
lines.push('', 'WARN versions out of sync — components disagree.', ' Run `npm install -g @ai-sdlc/orchestrator@latest` (or pnpm equivalent) to align.');
|
|
115
|
+
}
|
|
116
|
+
return lines.join('\n');
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Return the upgrade hint shown by unknown-subcommand handler and by
|
|
120
|
+
* version drift warnings. Centralised so tests can assert one string.
|
|
121
|
+
*/
|
|
122
|
+
export function upgradeHint(versions) {
|
|
123
|
+
if (versions.drift) {
|
|
124
|
+
return `Detected version drift (cli=${versions.cli}, orchestrator=${versions.orchestrator}${versions.plugin ? `, plugin=${versions.plugin}` : ''}). Run \`npm install -g @ai-sdlc/orchestrator@latest\` to align.`;
|
|
125
|
+
}
|
|
126
|
+
return `Run \`ai-sdlc --version\` to confirm you are on the latest @ai-sdlc/orchestrator (currently ${versions.orchestrator}).`;
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=versions.js.map
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classify a code area as frontend-bearing or not (RFC-0008 C3).
|
|
3
|
+
*
|
|
4
|
+
* `hasFrontendComponents` is the branch predicate in the §A.5 defect-risk
|
|
5
|
+
* blend: frontend-bearing areas blend code-quality signals with design-
|
|
6
|
+
* quality signals; pure-code areas use only code signals.
|
|
7
|
+
*
|
|
8
|
+
* Classification order:
|
|
9
|
+
* 1. If the state store has a recent `code_area_metrics` row for the
|
|
10
|
+
* area, trust that explicitly — operators can correct the default
|
|
11
|
+
* by writing the metric.
|
|
12
|
+
* 2. Otherwise, apply a path-string heuristic: common frontend
|
|
13
|
+
* directory/extension markers.
|
|
14
|
+
*
|
|
15
|
+
* The state-store path matters because this runs in the hot admission
|
|
16
|
+
* loop — we don't want to ship a filesystem crawl on every issue score.
|
|
17
|
+
*/
|
|
18
|
+
import type { StateStore } from './state/store.js';
|
|
19
|
+
export declare function checkHasFrontendComponents(codeArea: string, store?: StateStore): boolean;
|
|
20
|
+
export declare function matchesFrontendHeuristic(codeArea: string): boolean;
|
|
21
|
+
//# sourceMappingURL=code-area-classifier.d.ts.map
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classify a code area as frontend-bearing or not (RFC-0008 C3).
|
|
3
|
+
*
|
|
4
|
+
* `hasFrontendComponents` is the branch predicate in the §A.5 defect-risk
|
|
5
|
+
* blend: frontend-bearing areas blend code-quality signals with design-
|
|
6
|
+
* quality signals; pure-code areas use only code signals.
|
|
7
|
+
*
|
|
8
|
+
* Classification order:
|
|
9
|
+
* 1. If the state store has a recent `code_area_metrics` row for the
|
|
10
|
+
* area, trust that explicitly — operators can correct the default
|
|
11
|
+
* by writing the metric.
|
|
12
|
+
* 2. Otherwise, apply a path-string heuristic: common frontend
|
|
13
|
+
* directory/extension markers.
|
|
14
|
+
*
|
|
15
|
+
* The state-store path matters because this runs in the hot admission
|
|
16
|
+
* loop — we don't want to ship a filesystem crawl on every issue score.
|
|
17
|
+
*/
|
|
18
|
+
const FRONTEND_PATH_MARKERS = [
|
|
19
|
+
'components/',
|
|
20
|
+
'ui/',
|
|
21
|
+
'frontend/',
|
|
22
|
+
'web/',
|
|
23
|
+
'webapp/',
|
|
24
|
+
'src/app/', // Next.js app-dir convention
|
|
25
|
+
'pages/',
|
|
26
|
+
'routes/',
|
|
27
|
+
'views/',
|
|
28
|
+
];
|
|
29
|
+
const FRONTEND_EXTENSIONS = ['.tsx', '.jsx', '.vue', '.svelte', '.astro'];
|
|
30
|
+
export function checkHasFrontendComponents(codeArea, store) {
|
|
31
|
+
const authoritative = store?.getCodeAreaMetrics(codeArea);
|
|
32
|
+
if (authoritative)
|
|
33
|
+
return authoritative.hasFrontendComponents ?? false;
|
|
34
|
+
return matchesFrontendHeuristic(codeArea);
|
|
35
|
+
}
|
|
36
|
+
export function matchesFrontendHeuristic(codeArea) {
|
|
37
|
+
const lower = codeArea.toLowerCase();
|
|
38
|
+
for (const marker of FRONTEND_PATH_MARKERS) {
|
|
39
|
+
if (lower.includes(marker))
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
for (const ext of FRONTEND_EXTENSIONS) {
|
|
43
|
+
if (lower.endsWith(ext))
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=code-area-classifier.js.map
|
package/dist/config.d.ts
CHANGED
|
@@ -5,9 +5,17 @@
|
|
|
5
5
|
* Unlike the dogfood config loader, this version does NOT import builder
|
|
6
6
|
* functions — it performs pure YAML loading and validation only.
|
|
7
7
|
*/
|
|
8
|
-
import { type Pipeline, type AgentRole, type QualityGate, type AutonomyPolicy, type AdapterBinding, type AdapterRegistry } from '@ai-sdlc/reference';
|
|
8
|
+
import { type Pipeline, type AgentRole, type QualityGate, type AutonomyPolicy, type AdapterBinding, type DesignSystemBinding, type DesignIntentDocument, type AdapterRegistry } from '@ai-sdlc/reference';
|
|
9
9
|
export interface AiSdlcConfig {
|
|
10
|
+
/** Default pipeline (first Pipeline resource loaded; preserved for backward compat). */
|
|
10
11
|
pipeline?: Pipeline;
|
|
12
|
+
/**
|
|
13
|
+
* All Pipeline resources found in the config directory. The dual-workflow setup
|
|
14
|
+
* (RFC-0010 §11): one pipeline for the public GitHub-issue path (API-key billed),
|
|
15
|
+
* another for the internal backlog path (subscription-billed). cli-watch picks
|
|
16
|
+
* by name based on the issue ID prefix.
|
|
17
|
+
*/
|
|
18
|
+
pipelines?: Pipeline[];
|
|
11
19
|
agentRole?: AgentRole;
|
|
12
20
|
qualityGate?: QualityGate;
|
|
13
21
|
autonomyPolicy?: AutonomyPolicy;
|
|
@@ -15,13 +23,37 @@ export interface AiSdlcConfig {
|
|
|
15
23
|
adapterBinding?: AdapterBinding;
|
|
16
24
|
/** All AdapterBinding resources found in the config directory. */
|
|
17
25
|
adapterBindings?: AdapterBinding[];
|
|
26
|
+
/** All DesignSystemBinding resources found in the config directory (RFC-0006). */
|
|
27
|
+
designSystemBindings?: DesignSystemBinding[];
|
|
28
|
+
/** All DesignIntentDocument resources found in the config directory (RFC-0008). */
|
|
29
|
+
designIntentDocuments?: DesignIntentDocument[];
|
|
18
30
|
adapterRegistry?: AdapterRegistry;
|
|
31
|
+
/**
|
|
32
|
+
* Per-file load issues collected during a non-fatal load. Each entry
|
|
33
|
+
* is `{ file, error }` for a YAML file that failed to parse or
|
|
34
|
+
* validate. Non-resource YAMLs (no `apiVersion`/`kind`) and DID→DSB
|
|
35
|
+
* cross-reference failures are NOT recorded here — the former are
|
|
36
|
+
* silently skipped, the latter throw outright.
|
|
37
|
+
*/
|
|
38
|
+
warnings?: ConfigLoadWarning[];
|
|
39
|
+
}
|
|
40
|
+
export interface ConfigLoadWarning {
|
|
41
|
+
file: string;
|
|
42
|
+
error: string;
|
|
19
43
|
}
|
|
20
44
|
/**
|
|
21
45
|
* Load all YAML files from the given directory, validate each against
|
|
22
46
|
* the AI-SDLC JSON Schema, and return typed resources keyed by kind.
|
|
23
47
|
*/
|
|
24
48
|
export declare function loadConfig(configDir: string): AiSdlcConfig;
|
|
49
|
+
/**
|
|
50
|
+
* Validate that every DesignIntentDocument's `spec.designSystemRef.name`
|
|
51
|
+
* resolves to a loaded DesignSystemBinding. Namespace match is required
|
|
52
|
+
* only when both resources declare a namespace (RFC-0008 §4.5).
|
|
53
|
+
*
|
|
54
|
+
* Unidirectional: DID → DSB. DesignSystemBinding surface is not modified.
|
|
55
|
+
*/
|
|
56
|
+
export declare function validateDesignIntentDocumentReferences(config: AiSdlcConfig): void;
|
|
25
57
|
/**
|
|
26
58
|
* Async variant of loadConfig that also scans for local adapter plugins.
|
|
27
59
|
*/
|
package/dist/config.js
CHANGED
|
@@ -9,9 +9,8 @@ import { readFileSync, readdirSync, existsSync } from 'node:fs';
|
|
|
9
9
|
import { resolve, join } from 'node:path';
|
|
10
10
|
import { parse as parseYaml } from 'yaml';
|
|
11
11
|
import { validateResource, createAdapterRegistry, scanLocalAdapters, } from '@ai-sdlc/reference';
|
|
12
|
-
/** Resource kinds that allow only a single instance. */
|
|
12
|
+
/** Resource kinds that allow only a single instance. Multi-instance kinds are excluded. */
|
|
13
13
|
const KIND_KEY = {
|
|
14
|
-
Pipeline: 'pipeline',
|
|
15
14
|
AgentRole: 'agentRole',
|
|
16
15
|
QualityGate: 'qualityGate',
|
|
17
16
|
AutonomyPolicy: 'autonomyPolicy',
|
|
@@ -27,21 +26,54 @@ export function loadConfig(configDir) {
|
|
|
27
26
|
}
|
|
28
27
|
const files = readdirSync(dir).filter((f) => f.endsWith('.yaml') || f.endsWith('.yml'));
|
|
29
28
|
const config = {};
|
|
29
|
+
const warnings = [];
|
|
30
30
|
for (const file of files) {
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
let doc;
|
|
32
|
+
try {
|
|
33
|
+
const raw = readFileSync(resolve(dir, file), 'utf-8');
|
|
34
|
+
doc = parseYaml(raw);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
// Malformed YAML — record and continue. One bad file should not
|
|
38
|
+
// poison the rest of the config (forward-looking YAMLs in active
|
|
39
|
+
// adoption are common).
|
|
40
|
+
warnings.push({ file, error: `parse error: ${err.message}` });
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
// Skip non-resource YAML files (review-exemplars.yaml, manifest.yaml, etc.)
|
|
44
|
+
// AI-SDLC resources always have an apiVersion field.
|
|
45
|
+
if (!doc || typeof doc !== 'object' || !('apiVersion' in doc) || !('kind' in doc)) {
|
|
33
46
|
continue;
|
|
34
|
-
|
|
35
|
-
const doc = parseYaml(raw);
|
|
47
|
+
}
|
|
36
48
|
const result = validateResource(doc);
|
|
37
49
|
if (!result.valid) {
|
|
38
|
-
const msgs = (result.errors ?? []).map((e) =>
|
|
39
|
-
|
|
50
|
+
const msgs = (result.errors ?? []).map((e) => `${e.path}: ${e.message}`).join('; ');
|
|
51
|
+
// Forward-looking schemas are common during incremental adoption
|
|
52
|
+
// (RFC-0008 §A.4 readers landing in phases). Record + skip rather
|
|
53
|
+
// than throw — callers see the warning, the rest of the config
|
|
54
|
+
// (the parts that DO validate) continues to drive admission.
|
|
55
|
+
warnings.push({ file, error: `validation failed: ${msgs}` });
|
|
56
|
+
continue;
|
|
40
57
|
}
|
|
41
58
|
const resource = result.data;
|
|
42
59
|
if (resource.kind === 'AdapterBinding') {
|
|
43
60
|
(config.adapterBindings ??= []).push(resource);
|
|
44
61
|
}
|
|
62
|
+
else if (resource.kind === 'DesignSystemBinding') {
|
|
63
|
+
(config.designSystemBindings ??= []).push(resource);
|
|
64
|
+
}
|
|
65
|
+
else if (resource.kind === 'DesignIntentDocument') {
|
|
66
|
+
(config.designIntentDocuments ??= []).push(resource);
|
|
67
|
+
}
|
|
68
|
+
else if (resource.kind === 'Pipeline') {
|
|
69
|
+
(config.pipelines ??= []).push(resource);
|
|
70
|
+
// Backward-compat: `config.pipeline` (singular) = the canonical one.
|
|
71
|
+
// Prefer the file literally named `pipeline.yaml` (the default workflow).
|
|
72
|
+
// Fall back to the first loaded otherwise.
|
|
73
|
+
if (file === 'pipeline.yaml' || file === 'pipeline.yml' || !config.pipeline) {
|
|
74
|
+
config.pipeline = resource;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
45
77
|
else {
|
|
46
78
|
const key = KIND_KEY[resource.kind];
|
|
47
79
|
if (key) {
|
|
@@ -50,12 +82,50 @@ export function loadConfig(configDir) {
|
|
|
50
82
|
}
|
|
51
83
|
}
|
|
52
84
|
}
|
|
85
|
+
if (warnings.length > 0) {
|
|
86
|
+
config.warnings = warnings;
|
|
87
|
+
}
|
|
53
88
|
// Backward compat: set adapterBinding to the first binding
|
|
54
89
|
if (config.adapterBindings?.length) {
|
|
55
90
|
config.adapterBinding = config.adapterBindings[0];
|
|
56
91
|
}
|
|
92
|
+
// RFC-0008: validate DID → DSB cross-references
|
|
93
|
+
if (config.designIntentDocuments?.length) {
|
|
94
|
+
validateDesignIntentDocumentReferences(config);
|
|
95
|
+
}
|
|
57
96
|
return config;
|
|
58
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Validate that every DesignIntentDocument's `spec.designSystemRef.name`
|
|
100
|
+
* resolves to a loaded DesignSystemBinding. Namespace match is required
|
|
101
|
+
* only when both resources declare a namespace (RFC-0008 §4.5).
|
|
102
|
+
*
|
|
103
|
+
* Unidirectional: DID → DSB. DesignSystemBinding surface is not modified.
|
|
104
|
+
*/
|
|
105
|
+
export function validateDesignIntentDocumentReferences(config) {
|
|
106
|
+
const dids = config.designIntentDocuments ?? [];
|
|
107
|
+
const dsbs = config.designSystemBindings ?? [];
|
|
108
|
+
const unresolved = [];
|
|
109
|
+
for (const did of dids) {
|
|
110
|
+
const targetName = did.spec.designSystemRef.name;
|
|
111
|
+
const targetNamespace = did.spec.designSystemRef.namespace;
|
|
112
|
+
const match = dsbs.find((dsb) => {
|
|
113
|
+
if (dsb.metadata.name !== targetName)
|
|
114
|
+
return false;
|
|
115
|
+
if (targetNamespace && dsb.metadata.namespace && dsb.metadata.namespace !== targetNamespace) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
return true;
|
|
119
|
+
});
|
|
120
|
+
if (!match) {
|
|
121
|
+
const nsSuffix = targetNamespace ? `/${targetNamespace}` : '';
|
|
122
|
+
unresolved.push(` DesignIntentDocument "${did.metadata.name}" references "${targetName}${nsSuffix}" which does not resolve to any loaded DesignSystemBinding`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (unresolved.length > 0) {
|
|
126
|
+
throw new Error(`DID → DesignSystemBinding reference validation failed:\n${unresolved.join('\n')}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
59
129
|
/**
|
|
60
130
|
* Async variant of loadConfig that also scans for local adapter plugins.
|
|
61
131
|
*/
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ExternalAdapter per RFC §15.2. Operator-declared shell hooks for proprietary or
|
|
3
|
+
* custom branching mechanisms. Pipeline-load REQUIRES `acknowledgeUntrusted: true`
|
|
4
|
+
* because shell hooks execute with full credential scope.
|
|
5
|
+
*/
|
|
6
|
+
import { type DatabaseBranchAdapter, type DatabaseBranchCapabilities, type DatabaseBranchHandle, type DatabaseAdapterName, type ResolvedDatabaseBranchPool, type ValidationResult } from '../types.js';
|
|
7
|
+
export interface ExternalAdapterDeps {
|
|
8
|
+
exec?: (cmd: string, args: string[]) => Promise<{
|
|
9
|
+
stdout: string;
|
|
10
|
+
stderr: string;
|
|
11
|
+
}>;
|
|
12
|
+
}
|
|
13
|
+
export declare class ExternalAdapter implements DatabaseBranchAdapter {
|
|
14
|
+
private readonly deps;
|
|
15
|
+
readonly name: DatabaseAdapterName;
|
|
16
|
+
readonly capabilities: DatabaseBranchCapabilities;
|
|
17
|
+
constructor(deps?: ExternalAdapterDeps);
|
|
18
|
+
validate(pool: ResolvedDatabaseBranchPool): Promise<ValidationResult>;
|
|
19
|
+
allocate(pool: ResolvedDatabaseBranchPool, branchKey: string): Promise<DatabaseBranchHandle>;
|
|
20
|
+
reclaim(handle: DatabaseBranchHandle): Promise<void>;
|
|
21
|
+
list(_pool: ResolvedDatabaseBranchPool): Promise<DatabaseBranchHandle[]>;
|
|
22
|
+
isAvailable(pool: ResolvedDatabaseBranchPool): Promise<boolean>;
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=external.d.ts.map
|