@ai-sdlc/orchestrator 0.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/dist/adapters.d.ts +60 -0
- package/dist/adapters.js +160 -0
- package/dist/admission.d.ts +49 -0
- package/dist/admission.js +90 -0
- package/dist/analysis/analyzer.d.ts +10 -0
- package/dist/analysis/analyzer.js +67 -0
- package/dist/analysis/complexity-scorer.d.ts +24 -0
- package/dist/analysis/complexity-scorer.js +39 -0
- package/dist/analysis/context-builder.d.ts +14 -0
- package/dist/analysis/context-builder.js +79 -0
- package/dist/analysis/convention-detector.d.ts +9 -0
- package/dist/analysis/convention-detector.js +177 -0
- package/dist/analysis/dependency-parser.d.ts +17 -0
- package/dist/analysis/dependency-parser.js +167 -0
- package/dist/analysis/file-walker.d.ts +18 -0
- package/dist/analysis/file-walker.js +158 -0
- package/dist/analysis/hotspot-analyzer.d.ts +28 -0
- package/dist/analysis/hotspot-analyzer.js +85 -0
- package/dist/analysis/index.d.ts +13 -0
- package/dist/analysis/index.js +12 -0
- package/dist/analysis/pattern-detector.d.ts +10 -0
- package/dist/analysis/pattern-detector.js +86 -0
- package/dist/analysis/types.d.ts +94 -0
- package/dist/analysis/types.js +5 -0
- package/dist/audit-archival.d.ts +48 -0
- package/dist/audit-archival.js +72 -0
- package/dist/audit-export.d.ts +45 -0
- package/dist/audit-export.js +100 -0
- package/dist/audit-extended.d.ts +28 -0
- package/dist/audit-extended.js +38 -0
- package/dist/audit-scheduler.d.ts +32 -0
- package/dist/audit-scheduler.js +52 -0
- package/dist/audit-sqlite-sink.d.ts +11 -0
- package/dist/audit-sqlite-sink.js +51 -0
- package/dist/autonomy-tracker.d.ts +76 -0
- package/dist/autonomy-tracker.js +277 -0
- package/dist/check-runs.d.ts +37 -0
- package/dist/check-runs.js +72 -0
- package/dist/cli/commands/agents.d.ts +6 -0
- package/dist/cli/commands/agents.js +33 -0
- package/dist/cli/commands/complexity.d.ts +6 -0
- package/dist/cli/commands/complexity.js +35 -0
- package/dist/cli/commands/cost.d.ts +6 -0
- package/dist/cli/commands/cost.js +53 -0
- package/dist/cli/commands/dashboard.d.ts +9 -0
- package/dist/cli/commands/dashboard.js +50 -0
- package/dist/cli/commands/health.d.ts +6 -0
- package/dist/cli/commands/health.js +33 -0
- package/dist/cli/commands/init.d.ts +6 -0
- package/dist/cli/commands/init.js +127 -0
- package/dist/cli/commands/routing.d.ts +6 -0
- package/dist/cli/commands/routing.js +46 -0
- package/dist/cli/commands/run.d.ts +6 -0
- package/dist/cli/commands/run.js +36 -0
- package/dist/cli/commands/start.d.ts +6 -0
- package/dist/cli/commands/start.js +26 -0
- package/dist/cli/commands/status.d.ts +6 -0
- package/dist/cli/commands/status.js +34 -0
- package/dist/cli/dashboard-renderer.d.ts +24 -0
- package/dist/cli/dashboard-renderer.js +129 -0
- package/dist/cli/formatters/index.d.ts +6 -0
- package/dist/cli/formatters/index.js +18 -0
- package/dist/cli/formatters/json.d.ts +5 -0
- package/dist/cli/formatters/json.js +7 -0
- package/dist/cli/formatters/minimal.d.ts +5 -0
- package/dist/cli/formatters/minimal.js +36 -0
- package/dist/cli/formatters/table.d.ts +5 -0
- package/dist/cli/formatters/table.js +184 -0
- package/dist/cli/index.d.ts +6 -0
- package/dist/cli/index.js +35 -0
- package/dist/compliance-extended.d.ts +41 -0
- package/dist/compliance-extended.js +58 -0
- package/dist/config.d.ts +26 -0
- package/dist/config.js +66 -0
- package/dist/context-enrichment.d.ts +33 -0
- package/dist/context-enrichment.js +125 -0
- package/dist/cost-governance.d.ts +22 -0
- package/dist/cost-governance.js +106 -0
- package/dist/cost-tracker.d.ts +75 -0
- package/dist/cost-tracker.js +177 -0
- package/dist/defaults.d.ts +140 -0
- package/dist/defaults.js +218 -0
- package/dist/deploy/flyio-target.d.ts +19 -0
- package/dist/deploy/flyio-target.js +114 -0
- package/dist/deploy/index.d.ts +15 -0
- package/dist/deploy/index.js +11 -0
- package/dist/deploy/kubernetes-target.d.ts +25 -0
- package/dist/deploy/kubernetes-target.js +124 -0
- package/dist/deploy/metrics-collector.d.ts +31 -0
- package/dist/deploy/metrics-collector.js +75 -0
- package/dist/deploy/rollout-controller.d.ts +42 -0
- package/dist/deploy/rollout-controller.js +192 -0
- package/dist/deploy/rollout-types.d.ts +86 -0
- package/dist/deploy/rollout-types.js +5 -0
- package/dist/deploy/types.d.ts +47 -0
- package/dist/deploy/types.js +5 -0
- package/dist/deploy/vercel-target.d.ts +16 -0
- package/dist/deploy/vercel-target.js +115 -0
- package/dist/discovery.d.ts +26 -0
- package/dist/discovery.js +46 -0
- package/dist/episodic-enhanced.d.ts +88 -0
- package/dist/episodic-enhanced.js +212 -0
- package/dist/execute.d.ts +81 -0
- package/dist/execute.js +703 -0
- package/dist/fix-ci.d.ts +61 -0
- package/dist/fix-ci.js +380 -0
- package/dist/handoff-executor.d.ts +61 -0
- package/dist/handoff-executor.js +119 -0
- package/dist/index.d.ts +70 -0
- package/dist/index.js +87 -0
- package/dist/instrumented.d.ts +27 -0
- package/dist/instrumented.js +34 -0
- package/dist/logger.d.ts +17 -0
- package/dist/logger.js +37 -0
- package/dist/multi-repo/impact-analyzer.d.ts +22 -0
- package/dist/multi-repo/impact-analyzer.js +95 -0
- package/dist/multi-repo/index.d.ts +5 -0
- package/dist/multi-repo/index.js +4 -0
- package/dist/multi-repo/monorepo-detector.d.ts +16 -0
- package/dist/multi-repo/monorepo-detector.js +246 -0
- package/dist/multi-repo/service-map-builder.d.ts +24 -0
- package/dist/multi-repo/service-map-builder.js +235 -0
- package/dist/multi-repo/types.d.ts +54 -0
- package/dist/multi-repo/types.js +5 -0
- package/dist/notifications/index.d.ts +4 -0
- package/dist/notifications/index.js +4 -0
- package/dist/notifications/notification-router.d.ts +62 -0
- package/dist/notifications/notification-router.js +206 -0
- package/dist/notifications/slack-messenger.d.ts +26 -0
- package/dist/notifications/slack-messenger.js +69 -0
- package/dist/notifications/teams-messenger.d.ts +21 -0
- package/dist/notifications/teams-messenger.js +85 -0
- package/dist/notifications.d.ts +13 -0
- package/dist/notifications.js +15 -0
- package/dist/orchestration.d.ts +20 -0
- package/dist/orchestration.js +53 -0
- package/dist/orchestrator.d.ts +160 -0
- package/dist/orchestrator.js +372 -0
- package/dist/otel-exporter.d.ts +37 -0
- package/dist/otel-exporter.js +128 -0
- package/dist/plugin.d.ts +45 -0
- package/dist/plugin.js +8 -0
- package/dist/policy-evaluators.d.ts +40 -0
- package/dist/policy-evaluators.js +57 -0
- package/dist/process-escalation.d.ts +38 -0
- package/dist/process-escalation.js +129 -0
- package/dist/progressive-gates.d.ts +54 -0
- package/dist/progressive-gates.js +135 -0
- package/dist/provenance.d.ts +29 -0
- package/dist/provenance.js +61 -0
- package/dist/reconcilers.d.ts +28 -0
- package/dist/reconcilers.js +37 -0
- package/dist/runners/claude-code.d.ts +17 -0
- package/dist/runners/claude-code.js +200 -0
- package/dist/runners/codex.d.ts +19 -0
- package/dist/runners/codex.js +153 -0
- package/dist/runners/copilot-stub.d.ts +9 -0
- package/dist/runners/copilot-stub.js +15 -0
- package/dist/runners/copilot.d.ts +15 -0
- package/dist/runners/copilot.js +119 -0
- package/dist/runners/cursor-stub.d.ts +9 -0
- package/dist/runners/cursor-stub.js +15 -0
- package/dist/runners/cursor.d.ts +20 -0
- package/dist/runners/cursor.js +140 -0
- package/dist/runners/devin-stub.d.ts +9 -0
- package/dist/runners/devin-stub.js +15 -0
- package/dist/runners/generic-llm.d.ts +51 -0
- package/dist/runners/generic-llm.js +125 -0
- package/dist/runners/index.d.ts +8 -0
- package/dist/runners/index.js +7 -0
- package/dist/runners/runner-registry.d.ts +50 -0
- package/dist/runners/runner-registry.js +156 -0
- package/dist/runners/types.d.ts +59 -0
- package/dist/runners/types.js +7 -0
- package/dist/security.d.ts +51 -0
- package/dist/security.js +70 -0
- package/dist/shared.d.ts +134 -0
- package/dist/shared.js +284 -0
- package/dist/state/index.d.ts +4 -0
- package/dist/state/index.js +3 -0
- package/dist/state/schema.d.ts +16 -0
- package/dist/state/schema.js +264 -0
- package/dist/state/store.d.ts +109 -0
- package/dist/state/store.js +644 -0
- package/dist/state/types.d.ts +190 -0
- package/dist/state/types.js +5 -0
- package/dist/structured-logger.d.ts +20 -0
- package/dist/structured-logger.js +64 -0
- package/dist/task-decomposer.d.ts +61 -0
- package/dist/task-decomposer.js +265 -0
- package/dist/telemetry-extended.d.ts +24 -0
- package/dist/telemetry-extended.js +31 -0
- package/dist/types.d.ts +9 -0
- package/dist/types.js +7 -0
- package/dist/validate-agent-output.d.ts +30 -0
- package/dist/validate-agent-output.js +81 -0
- package/dist/validate-issue.d.ts +25 -0
- package/dist/validate-issue.js +102 -0
- package/dist/watch.d.ts +43 -0
- package/dist/watch.js +99 -0
- package/dist/webhook-manager.d.ts +38 -0
- package/dist/webhook-manager.js +66 -0
- package/package.json +59 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ai-sdlc health — validate config, state store, and adapter connectivity.
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { Orchestrator } from '../../orchestrator.js';
|
|
6
|
+
import { formatOutput } from '../formatters/index.js';
|
|
7
|
+
export const healthCommand = new Command('health')
|
|
8
|
+
.description('Check orchestrator health')
|
|
9
|
+
.option('--state <path>', 'SQLite state database path')
|
|
10
|
+
.action(async (opts, cmd) => {
|
|
11
|
+
const globalOpts = cmd.parent?.opts() ?? {};
|
|
12
|
+
const format = globalOpts.format ?? 'table';
|
|
13
|
+
const orchestrator = new Orchestrator({
|
|
14
|
+
configDir: globalOpts.config,
|
|
15
|
+
statePath: opts.state,
|
|
16
|
+
});
|
|
17
|
+
try {
|
|
18
|
+
const result = await orchestrator.health();
|
|
19
|
+
console.log(formatOutput(format, {
|
|
20
|
+
type: 'health',
|
|
21
|
+
configValid: result.configValid,
|
|
22
|
+
stateStoreConnected: result.stateStoreConnected,
|
|
23
|
+
errors: result.errors,
|
|
24
|
+
}));
|
|
25
|
+
if (result.errors.length > 0) {
|
|
26
|
+
process.exitCode = 1;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
orchestrator.close();
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
//# sourceMappingURL=health.js.map
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ai-sdlc init — initialize a project with AI-SDLC config files.
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
|
6
|
+
import { join } from 'node:path';
|
|
7
|
+
const PIPELINE_YAML = `apiVersion: ai-sdlc.io/v1alpha1
|
|
8
|
+
kind: Pipeline
|
|
9
|
+
metadata:
|
|
10
|
+
name: default
|
|
11
|
+
spec:
|
|
12
|
+
stages:
|
|
13
|
+
- name: validate
|
|
14
|
+
type: gate
|
|
15
|
+
- name: code
|
|
16
|
+
type: agent
|
|
17
|
+
timeout: 30m
|
|
18
|
+
onFailure:
|
|
19
|
+
action: retry
|
|
20
|
+
maxRetries: 2
|
|
21
|
+
- name: review
|
|
22
|
+
type: gate
|
|
23
|
+
triggers:
|
|
24
|
+
- event: issue.labeled
|
|
25
|
+
filters:
|
|
26
|
+
- field: label
|
|
27
|
+
value: ai-sdlc
|
|
28
|
+
`;
|
|
29
|
+
const AGENT_ROLE_YAML = `apiVersion: ai-sdlc.io/v1alpha1
|
|
30
|
+
kind: AgentRole
|
|
31
|
+
metadata:
|
|
32
|
+
name: default-agent
|
|
33
|
+
spec:
|
|
34
|
+
role: developer
|
|
35
|
+
goal: Implement issue requirements with tests
|
|
36
|
+
tools:
|
|
37
|
+
- Edit
|
|
38
|
+
- Write
|
|
39
|
+
- Read
|
|
40
|
+
- Glob
|
|
41
|
+
- Grep
|
|
42
|
+
- Bash
|
|
43
|
+
constraints:
|
|
44
|
+
maxFilesPerChange: 15
|
|
45
|
+
requireTests: true
|
|
46
|
+
blockedPaths:
|
|
47
|
+
- .github/workflows/**
|
|
48
|
+
- .ai-sdlc/**
|
|
49
|
+
`;
|
|
50
|
+
const QUALITY_GATE_YAML = `apiVersion: ai-sdlc.io/v1alpha1
|
|
51
|
+
kind: QualityGate
|
|
52
|
+
metadata:
|
|
53
|
+
name: default-gates
|
|
54
|
+
spec:
|
|
55
|
+
gates:
|
|
56
|
+
- name: has-description
|
|
57
|
+
rule:
|
|
58
|
+
metric: description-length
|
|
59
|
+
operator: gt
|
|
60
|
+
threshold: 0
|
|
61
|
+
enforcement: mandatory
|
|
62
|
+
- name: has-acceptance-criteria
|
|
63
|
+
rule:
|
|
64
|
+
metric: has-acceptance-criteria
|
|
65
|
+
operator: gte
|
|
66
|
+
threshold: 1
|
|
67
|
+
enforcement: warning
|
|
68
|
+
`;
|
|
69
|
+
const AUTONOMY_POLICY_YAML = `apiVersion: ai-sdlc.io/v1alpha1
|
|
70
|
+
kind: AutonomyPolicy
|
|
71
|
+
metadata:
|
|
72
|
+
name: default-autonomy
|
|
73
|
+
spec:
|
|
74
|
+
levels:
|
|
75
|
+
- level: 0
|
|
76
|
+
name: supervised
|
|
77
|
+
permissions:
|
|
78
|
+
read: ["**"]
|
|
79
|
+
write: ["src/**", "test/**", "tests/**"]
|
|
80
|
+
execute: []
|
|
81
|
+
guardrails:
|
|
82
|
+
maxLinesPerPR: 300
|
|
83
|
+
blockedPaths:
|
|
84
|
+
- .github/workflows/**
|
|
85
|
+
- .ai-sdlc/**
|
|
86
|
+
promotionCriteria:
|
|
87
|
+
- metric: tasks-completed
|
|
88
|
+
threshold: 10
|
|
89
|
+
demotionTriggers:
|
|
90
|
+
- trigger: failed-test
|
|
91
|
+
threshold: 3
|
|
92
|
+
`;
|
|
93
|
+
export const initCommand = new Command('init')
|
|
94
|
+
.description('Initialize AI-SDLC configuration in the current project')
|
|
95
|
+
.option('--dry-run', 'Show what would be created without writing files')
|
|
96
|
+
.option('-d, --dir <path>', 'Config directory name', '.ai-sdlc')
|
|
97
|
+
.action(async (opts) => {
|
|
98
|
+
const configDir = join(process.cwd(), opts.dir ?? '.ai-sdlc');
|
|
99
|
+
const files = [
|
|
100
|
+
{ name: 'pipeline.yaml', content: PIPELINE_YAML },
|
|
101
|
+
{ name: 'agent-role.yaml', content: AGENT_ROLE_YAML },
|
|
102
|
+
{ name: 'quality-gate.yaml', content: QUALITY_GATE_YAML },
|
|
103
|
+
{ name: 'autonomy-policy.yaml', content: AUTONOMY_POLICY_YAML },
|
|
104
|
+
];
|
|
105
|
+
if (opts.dryRun) {
|
|
106
|
+
console.log(`Would create ${configDir}/`);
|
|
107
|
+
for (const f of files) {
|
|
108
|
+
console.log(` ${f.name}`);
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (!existsSync(configDir)) {
|
|
113
|
+
mkdirSync(configDir, { recursive: true });
|
|
114
|
+
}
|
|
115
|
+
for (const f of files) {
|
|
116
|
+
const path = join(configDir, f.name);
|
|
117
|
+
if (existsSync(path)) {
|
|
118
|
+
console.log(` skip ${f.name} (already exists)`);
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
writeFileSync(path, f.content, 'utf-8');
|
|
122
|
+
console.log(` created ${f.name}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
console.log(`\nAI-SDLC config initialized in ${configDir}/`);
|
|
126
|
+
});
|
|
127
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ai-sdlc routing [--last <duration>] — show routing distribution.
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { Orchestrator } from '../../orchestrator.js';
|
|
6
|
+
import { formatOutput } from '../formatters/index.js';
|
|
7
|
+
export const routingCommand = new Command('routing')
|
|
8
|
+
.description('Show routing decision distribution')
|
|
9
|
+
.option('--last <duration>', 'Time window (e.g. 7d, 30d)', '30d')
|
|
10
|
+
.option('--state <path>', 'SQLite state database path')
|
|
11
|
+
.action(async (opts, cmd) => {
|
|
12
|
+
const globalOpts = cmd.parent?.opts() ?? {};
|
|
13
|
+
const format = globalOpts.format ?? 'table';
|
|
14
|
+
const orchestrator = new Orchestrator({
|
|
15
|
+
configDir: globalOpts.config,
|
|
16
|
+
statePath: opts.state,
|
|
17
|
+
});
|
|
18
|
+
try {
|
|
19
|
+
const history = await orchestrator.routing({ limit: 200 });
|
|
20
|
+
// Parse --last duration
|
|
21
|
+
const durationMatch = opts.last?.match(/^(\d+)([dhm])$/);
|
|
22
|
+
let cutoff = 0;
|
|
23
|
+
if (durationMatch) {
|
|
24
|
+
const value = parseInt(durationMatch[1], 10);
|
|
25
|
+
const unit = durationMatch[2];
|
|
26
|
+
const ms = unit === 'd' ? value * 86400000 : unit === 'h' ? value * 3600000 : value * 60000;
|
|
27
|
+
cutoff = Date.now() - ms;
|
|
28
|
+
}
|
|
29
|
+
const filtered = cutoff > 0
|
|
30
|
+
? history.filter((h) => h.decidedAt && new Date(h.decidedAt).getTime() >= cutoff)
|
|
31
|
+
: history;
|
|
32
|
+
console.log(formatOutput(format, {
|
|
33
|
+
type: 'routing',
|
|
34
|
+
duration: opts.last,
|
|
35
|
+
history: filtered,
|
|
36
|
+
}));
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
40
|
+
process.exitCode = 1;
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
orchestrator.close();
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=routing.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ai-sdlc run --issue <N> — execute the pipeline for a single issue.
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { Orchestrator } from '../../orchestrator.js';
|
|
6
|
+
import { formatOutput } from '../formatters/index.js';
|
|
7
|
+
export const runCommand = new Command('run')
|
|
8
|
+
.description('Run the AI-SDLC pipeline for a specific issue')
|
|
9
|
+
.requiredOption('-i, --issue <number>', 'Issue number to process', parseInt)
|
|
10
|
+
.option('--state <path>', 'SQLite state database path')
|
|
11
|
+
.action(async (opts, cmd) => {
|
|
12
|
+
const globalOpts = cmd.parent?.opts() ?? {};
|
|
13
|
+
const format = globalOpts.format ?? 'table';
|
|
14
|
+
const orchestrator = new Orchestrator({
|
|
15
|
+
configDir: globalOpts.config,
|
|
16
|
+
statePath: opts.state,
|
|
17
|
+
});
|
|
18
|
+
try {
|
|
19
|
+
const result = await orchestrator.run(opts.issue);
|
|
20
|
+
console.log(formatOutput(format, {
|
|
21
|
+
type: 'run',
|
|
22
|
+
issueNumber: opts.issue,
|
|
23
|
+
prUrl: result.prUrl,
|
|
24
|
+
filesChanged: result.filesChanged.length,
|
|
25
|
+
promotionEligible: result.promotionEligible,
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
30
|
+
process.exitCode = 1;
|
|
31
|
+
}
|
|
32
|
+
finally {
|
|
33
|
+
orchestrator.close();
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ai-sdlc start — start watch mode with continuous reconciliation.
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { Orchestrator } from '../../orchestrator.js';
|
|
6
|
+
export const startCommand = new Command('start')
|
|
7
|
+
.description('Start the AI-SDLC watch mode (continuous reconciliation)')
|
|
8
|
+
.option('--state <path>', 'SQLite state database path')
|
|
9
|
+
.action(async (opts, cmd) => {
|
|
10
|
+
const globalOpts = cmd.parent?.opts() ?? {};
|
|
11
|
+
const orchestrator = new Orchestrator({
|
|
12
|
+
configDir: globalOpts.config,
|
|
13
|
+
statePath: opts.state,
|
|
14
|
+
});
|
|
15
|
+
const handle = await orchestrator.start();
|
|
16
|
+
console.log('[ai-sdlc] Watch mode started. Press Ctrl+C to stop.');
|
|
17
|
+
const shutdown = () => {
|
|
18
|
+
console.log('\n[ai-sdlc] Shutting down...');
|
|
19
|
+
handle.stop();
|
|
20
|
+
orchestrator.close();
|
|
21
|
+
process.exit(0);
|
|
22
|
+
};
|
|
23
|
+
process.on('SIGINT', shutdown);
|
|
24
|
+
process.on('SIGTERM', shutdown);
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=start.js.map
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ai-sdlc status [--issue <N>] — show pipeline status.
|
|
3
|
+
*/
|
|
4
|
+
import { Command } from 'commander';
|
|
5
|
+
import { Orchestrator } from '../../orchestrator.js';
|
|
6
|
+
import { formatOutput } from '../formatters/index.js';
|
|
7
|
+
export const statusCommand = new Command('status')
|
|
8
|
+
.description('Show pipeline status')
|
|
9
|
+
.option('-i, --issue <number>', 'Filter by issue number', parseInt)
|
|
10
|
+
.option('--state <path>', 'SQLite state database path')
|
|
11
|
+
.action(async (opts, cmd) => {
|
|
12
|
+
const globalOpts = cmd.parent?.opts() ?? {};
|
|
13
|
+
const format = globalOpts.format ?? 'table';
|
|
14
|
+
const orchestrator = new Orchestrator({
|
|
15
|
+
configDir: globalOpts.config,
|
|
16
|
+
statePath: opts.state,
|
|
17
|
+
});
|
|
18
|
+
try {
|
|
19
|
+
const result = await orchestrator.status(opts.issue);
|
|
20
|
+
console.log(formatOutput(format, {
|
|
21
|
+
type: 'status',
|
|
22
|
+
pipeline: result.config.pipeline?.metadata.name ?? 'none',
|
|
23
|
+
recentRuns: result.recentRuns,
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
28
|
+
process.exitCode = 1;
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
orchestrator.close();
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
//# sourceMappingURL=status.js.map
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard renderer — pure render functions per panel (no I/O).
|
|
3
|
+
* Composes ANSI box-drawing characters for a TUI monitoring view.
|
|
4
|
+
*
|
|
5
|
+
* D1: Zero dependencies, unit-testable pure functions.
|
|
6
|
+
*/
|
|
7
|
+
import type { AutonomyLedgerEntry } from '../state/types.js';
|
|
8
|
+
import type { CostSummary, BudgetStatus } from '../cost-tracker.js';
|
|
9
|
+
export interface DashboardData {
|
|
10
|
+
runs: Array<{
|
|
11
|
+
runId: string;
|
|
12
|
+
status: string;
|
|
13
|
+
startedAt?: string;
|
|
14
|
+
}>;
|
|
15
|
+
agents: AutonomyLedgerEntry[];
|
|
16
|
+
costSummary: CostSummary;
|
|
17
|
+
budgetStatus: BudgetStatus;
|
|
18
|
+
}
|
|
19
|
+
export declare function renderPipelinePanel(runs: DashboardData['runs'], width: number): string[];
|
|
20
|
+
export declare function renderAgentPanel(agents: DashboardData['agents'], width: number): string[];
|
|
21
|
+
export declare function renderCostPanel(summary: CostSummary, budget: BudgetStatus, width: number): string[];
|
|
22
|
+
export declare function renderHeaderPanel(width: number): string[];
|
|
23
|
+
export declare function renderDashboardFrame(data: DashboardData, width: number): string;
|
|
24
|
+
//# sourceMappingURL=dashboard-renderer.d.ts.map
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dashboard renderer — pure render functions per panel (no I/O).
|
|
3
|
+
* Composes ANSI box-drawing characters for a TUI monitoring view.
|
|
4
|
+
*
|
|
5
|
+
* D1: Zero dependencies, unit-testable pure functions.
|
|
6
|
+
*/
|
|
7
|
+
// ── Box drawing helpers ─────────────────────────────────────────
|
|
8
|
+
const BOX = {
|
|
9
|
+
topLeft: '\u250C',
|
|
10
|
+
topRight: '\u2510',
|
|
11
|
+
bottomLeft: '\u2514',
|
|
12
|
+
bottomRight: '\u2518',
|
|
13
|
+
horizontal: '\u2500',
|
|
14
|
+
vertical: '\u2502',
|
|
15
|
+
teeRight: '\u251C',
|
|
16
|
+
teeLeft: '\u2524',
|
|
17
|
+
};
|
|
18
|
+
function boxTop(width, title) {
|
|
19
|
+
if (title) {
|
|
20
|
+
const titleStr = ` ${title} `;
|
|
21
|
+
const remaining = width - 2 - titleStr.length;
|
|
22
|
+
return BOX.topLeft + titleStr + BOX.horizontal.repeat(Math.max(0, remaining)) + BOX.topRight;
|
|
23
|
+
}
|
|
24
|
+
return BOX.topLeft + BOX.horizontal.repeat(width - 2) + BOX.topRight;
|
|
25
|
+
}
|
|
26
|
+
function boxBottom(width) {
|
|
27
|
+
return BOX.bottomLeft + BOX.horizontal.repeat(width - 2) + BOX.bottomRight;
|
|
28
|
+
}
|
|
29
|
+
function boxLine(content, width) {
|
|
30
|
+
const padded = content.slice(0, width - 4).padEnd(width - 4);
|
|
31
|
+
return `${BOX.vertical} ${padded} ${BOX.vertical}`;
|
|
32
|
+
}
|
|
33
|
+
function boxSeparator(width) {
|
|
34
|
+
return BOX.teeRight + BOX.horizontal.repeat(width - 2) + BOX.teeLeft;
|
|
35
|
+
}
|
|
36
|
+
// ── Panel renderers ─────────────────────────────────────────────
|
|
37
|
+
export function renderPipelinePanel(runs, width) {
|
|
38
|
+
const lines = [];
|
|
39
|
+
lines.push(boxTop(width, 'Active Pipelines'));
|
|
40
|
+
if (runs.length === 0) {
|
|
41
|
+
lines.push(boxLine('No recent runs.', width));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
lines.push(boxLine('Run ID'.padEnd(24) + 'Status'.padEnd(12) + 'Started', width));
|
|
45
|
+
lines.push(boxSeparator(width));
|
|
46
|
+
for (const run of runs.slice(0, 5)) {
|
|
47
|
+
const started = run.startedAt?.split('T')[1]?.slice(0, 8) ?? '-';
|
|
48
|
+
lines.push(boxLine(run.runId.slice(0, 22).padEnd(24) + run.status.padEnd(12) + started, width));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
lines.push(boxBottom(width));
|
|
52
|
+
return lines;
|
|
53
|
+
}
|
|
54
|
+
export function renderAgentPanel(agents, width) {
|
|
55
|
+
const lines = [];
|
|
56
|
+
lines.push(boxTop(width, 'Agents'));
|
|
57
|
+
if (agents.length === 0) {
|
|
58
|
+
lines.push(boxLine('No agents registered.', width));
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
lines.push(boxLine('Agent'.padEnd(18) + 'Lvl'.padEnd(5) + 'Tasks'.padEnd(8) + 'Rate'.padEnd(8) + 'Last', width));
|
|
62
|
+
lines.push(boxSeparator(width));
|
|
63
|
+
for (const agent of agents.slice(0, 5)) {
|
|
64
|
+
const rate = agent.totalTasks > 0
|
|
65
|
+
? `${Math.round((agent.successCount / agent.totalTasks) * 100)}%`
|
|
66
|
+
: '-';
|
|
67
|
+
const last = agent.lastTaskAt?.split('T')[0] ?? '-';
|
|
68
|
+
lines.push(boxLine(agent.agentName.slice(0, 16).padEnd(18) +
|
|
69
|
+
String(agent.currentLevel).padEnd(5) +
|
|
70
|
+
String(agent.totalTasks).padEnd(8) +
|
|
71
|
+
rate.padEnd(8) +
|
|
72
|
+
last, width));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
lines.push(boxBottom(width));
|
|
76
|
+
return lines;
|
|
77
|
+
}
|
|
78
|
+
export function renderCostPanel(summary, budget, width) {
|
|
79
|
+
const lines = [];
|
|
80
|
+
lines.push(boxTop(width, 'Cost'));
|
|
81
|
+
lines.push(boxLine(`Total: $${summary.totalCostUsd.toFixed(2)} | Tokens: ${formatNumber(summary.totalTokens)} | Runs: ${summary.entryCount}`, width));
|
|
82
|
+
lines.push(boxLine(`Avg/run: $${summary.avgCostPerRun.toFixed(4)} | Budget: $${budget.budgetUsd} (${budget.utilizationPercent.toFixed(0)}% used)`, width));
|
|
83
|
+
// Budget bar
|
|
84
|
+
const barWidth = Math.max(10, width - 20);
|
|
85
|
+
const filled = Math.min(barWidth, Math.round((budget.utilizationPercent / 100) * barWidth));
|
|
86
|
+
const bar = '\u2588'.repeat(filled) + '\u2591'.repeat(barWidth - filled);
|
|
87
|
+
const budgetStatus = budget.overBudget ? ' OVER BUDGET!' : '';
|
|
88
|
+
lines.push(boxLine(`[${bar}]${budgetStatus}`, width));
|
|
89
|
+
// Cost by agent
|
|
90
|
+
if (Object.keys(summary.costByAgent).length > 0) {
|
|
91
|
+
lines.push(boxSeparator(width));
|
|
92
|
+
for (const [agent, cost] of Object.entries(summary.costByAgent).slice(0, 3)) {
|
|
93
|
+
lines.push(boxLine(` ${agent.padEnd(16)} $${cost.toFixed(4)}`, width));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
lines.push(boxBottom(width));
|
|
97
|
+
return lines;
|
|
98
|
+
}
|
|
99
|
+
export function renderHeaderPanel(width) {
|
|
100
|
+
const now = new Date().toLocaleString();
|
|
101
|
+
return [boxTop(width, 'AI-SDLC Dashboard'), boxLine(`Updated: ${now}`, width), boxBottom(width)];
|
|
102
|
+
}
|
|
103
|
+
// ── Composer ─────────────────────────────────────────────────────
|
|
104
|
+
export function renderDashboardFrame(data, width) {
|
|
105
|
+
const panelWidth = Math.max(40, width);
|
|
106
|
+
const allLines = [];
|
|
107
|
+
allLines.push(...renderHeaderPanel(panelWidth));
|
|
108
|
+
allLines.push('');
|
|
109
|
+
allLines.push(...renderPipelinePanel(data.runs, panelWidth));
|
|
110
|
+
allLines.push('');
|
|
111
|
+
allLines.push(...renderAgentPanel(data.agents, panelWidth));
|
|
112
|
+
allLines.push('');
|
|
113
|
+
allLines.push(...renderCostPanel(data.costSummary, data.budgetStatus, panelWidth));
|
|
114
|
+
// Pad to fill terminal height to avoid artifacts
|
|
115
|
+
const termHeight = process.stdout.rows || 40;
|
|
116
|
+
while (allLines.length < termHeight - 1) {
|
|
117
|
+
allLines.push('');
|
|
118
|
+
}
|
|
119
|
+
return allLines.join('\n');
|
|
120
|
+
}
|
|
121
|
+
// ── Utilities ───────────────────────────────────────────────────
|
|
122
|
+
function formatNumber(n) {
|
|
123
|
+
if (n >= 1_000_000)
|
|
124
|
+
return `${(n / 1_000_000).toFixed(1)}M`;
|
|
125
|
+
if (n >= 1_000)
|
|
126
|
+
return `${(n / 1_000).toFixed(1)}K`;
|
|
127
|
+
return String(n);
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=dashboard-renderer.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Output formatter factory — routes to table, json, or minimal.
|
|
3
|
+
*/
|
|
4
|
+
import { formatTable } from './table.js';
|
|
5
|
+
import { formatJson } from './json.js';
|
|
6
|
+
import { formatMinimal } from './minimal.js';
|
|
7
|
+
export function formatOutput(format, data) {
|
|
8
|
+
switch (format) {
|
|
9
|
+
case 'json':
|
|
10
|
+
return formatJson(data);
|
|
11
|
+
case 'minimal':
|
|
12
|
+
return formatMinimal(data);
|
|
13
|
+
case 'table':
|
|
14
|
+
default:
|
|
15
|
+
return formatTable(data);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal output formatter — single-line output for scripting.
|
|
3
|
+
*/
|
|
4
|
+
export function formatMinimal(data) {
|
|
5
|
+
const type = data.type;
|
|
6
|
+
switch (type) {
|
|
7
|
+
case 'run':
|
|
8
|
+
return `PR: ${data.prUrl} (${data.filesChanged} files)`;
|
|
9
|
+
case 'status':
|
|
10
|
+
return `Pipeline: ${data.pipeline} | Runs: ${data.recentRuns.length}`;
|
|
11
|
+
case 'health': {
|
|
12
|
+
const ok = data.configValid && data.errors.length === 0;
|
|
13
|
+
return ok ? 'OK' : `UNHEALTHY: ${data.errors.join('; ')}`;
|
|
14
|
+
}
|
|
15
|
+
case 'agents': {
|
|
16
|
+
const agents = data.agents;
|
|
17
|
+
return `Agents: ${agents.length}`;
|
|
18
|
+
}
|
|
19
|
+
case 'routing': {
|
|
20
|
+
const history = data.history;
|
|
21
|
+
return `Routing decisions: ${history.length} (last ${data.duration ?? '30d'})`;
|
|
22
|
+
}
|
|
23
|
+
case 'complexity': {
|
|
24
|
+
const profile = data.profile;
|
|
25
|
+
return `Complexity: ${profile.score}/10 | ${profile.filesCount} files | ${profile.modulesCount} modules`;
|
|
26
|
+
}
|
|
27
|
+
case 'cost': {
|
|
28
|
+
const summary = data.summary;
|
|
29
|
+
const budget = data.budget;
|
|
30
|
+
return `Cost: $${summary.totalCostUsd.toFixed(2)} | Budget: ${budget.utilizationPercent.toFixed(0)}% used | Runs: ${summary.entryCount}`;
|
|
31
|
+
}
|
|
32
|
+
default:
|
|
33
|
+
return JSON.stringify(data);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=minimal.js.map
|