@rasensio/aidlc 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/README.md +251 -0
- package/capabilities/claude-code.yaml +9 -0
- package/capabilities/codex.yaml +8 -0
- package/capabilities/cursor.yaml +8 -0
- package/capabilities/kiro.yaml +9 -0
- package/capabilities/windsurf.yaml +8 -0
- package/ci/aidlc-gate.yml +100 -0
- package/dist/cli.d.ts +11 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +39 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/add-action.d.ts +83 -0
- package/dist/commands/add-action.d.ts.map +1 -0
- package/dist/commands/add-action.js +437 -0
- package/dist/commands/add-action.js.map +1 -0
- package/dist/commands/continue.d.ts +23 -0
- package/dist/commands/continue.d.ts.map +1 -0
- package/dist/commands/continue.js +238 -0
- package/dist/commands/continue.js.map +1 -0
- package/dist/commands/discover.d.ts +19 -0
- package/dist/commands/discover.d.ts.map +1 -0
- package/dist/commands/discover.js +85 -0
- package/dist/commands/discover.js.map +1 -0
- package/dist/commands/docs.d.ts +25 -0
- package/dist/commands/docs.d.ts.map +1 -0
- package/dist/commands/docs.js +282 -0
- package/dist/commands/docs.js.map +1 -0
- package/dist/commands/gate.d.ts +25 -0
- package/dist/commands/gate.d.ts.map +1 -0
- package/dist/commands/gate.js +168 -0
- package/dist/commands/gate.js.map +1 -0
- package/dist/commands/init.d.ts +24 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +187 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/review.d.ts +60 -0
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/commands/review.js +264 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/setup.d.ts +24 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +206 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/start.d.ts +27 -0
- package/dist/commands/start.d.ts.map +1 -0
- package/dist/commands/start.js +243 -0
- package/dist/commands/start.js.map +1 -0
- package/dist/commands/status.d.ts +25 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +263 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/transition.d.ts +30 -0
- package/dist/commands/transition.d.ts.map +1 -0
- package/dist/commands/transition.js +353 -0
- package/dist/commands/transition.js.map +1 -0
- package/dist/compile/adapters/claude-code.d.ts +24 -0
- package/dist/compile/adapters/claude-code.d.ts.map +1 -0
- package/dist/compile/adapters/claude-code.js +271 -0
- package/dist/compile/adapters/claude-code.js.map +1 -0
- package/dist/compile/adapters/codex.d.ts +19 -0
- package/dist/compile/adapters/codex.d.ts.map +1 -0
- package/dist/compile/adapters/codex.js +157 -0
- package/dist/compile/adapters/codex.js.map +1 -0
- package/dist/compile/adapters/cursor.d.ts +21 -0
- package/dist/compile/adapters/cursor.d.ts.map +1 -0
- package/dist/compile/adapters/cursor.js +181 -0
- package/dist/compile/adapters/cursor.js.map +1 -0
- package/dist/compile/adapters/index.d.ts +16 -0
- package/dist/compile/adapters/index.d.ts.map +1 -0
- package/dist/compile/adapters/index.js +26 -0
- package/dist/compile/adapters/index.js.map +1 -0
- package/dist/compile/adapters/kiro.d.ts +24 -0
- package/dist/compile/adapters/kiro.d.ts.map +1 -0
- package/dist/compile/adapters/kiro.js +222 -0
- package/dist/compile/adapters/kiro.js.map +1 -0
- package/dist/compile/adapters/windsurf.d.ts +25 -0
- package/dist/compile/adapters/windsurf.d.ts.map +1 -0
- package/dist/compile/adapters/windsurf.js +242 -0
- package/dist/compile/adapters/windsurf.js.map +1 -0
- package/dist/compile/install-plan.d.ts +49 -0
- package/dist/compile/install-plan.d.ts.map +1 -0
- package/dist/compile/install-plan.js +112 -0
- package/dist/compile/install-plan.js.map +1 -0
- package/dist/compile/loaders.d.ts +81 -0
- package/dist/compile/loaders.d.ts.map +1 -0
- package/dist/compile/loaders.js +293 -0
- package/dist/compile/loaders.js.map +1 -0
- package/dist/compile/merger.d.ts +32 -0
- package/dist/compile/merger.d.ts.map +1 -0
- package/dist/compile/merger.js +60 -0
- package/dist/compile/merger.js.map +1 -0
- package/dist/core/gate.d.ts +36 -0
- package/dist/core/gate.d.ts.map +1 -0
- package/dist/core/gate.js +97 -0
- package/dist/core/gate.js.map +1 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +7 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/lifecycle.d.ts +89 -0
- package/dist/core/lifecycle.d.ts.map +1 -0
- package/dist/core/lifecycle.js +356 -0
- package/dist/core/lifecycle.js.map +1 -0
- package/dist/core/template-resolver.d.ts +56 -0
- package/dist/core/template-resolver.d.ts.map +1 -0
- package/dist/core/template-resolver.js +261 -0
- package/dist/core/template-resolver.js.map +1 -0
- package/dist/core/types.d.ts +527 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +8 -0
- package/dist/core/types.js.map +1 -0
- package/dist/discover/scanner.d.ts +58 -0
- package/dist/discover/scanner.d.ts.map +1 -0
- package/dist/discover/scanner.js +772 -0
- package/dist/discover/scanner.js.map +1 -0
- package/dist/events/event-bus.d.ts +53 -0
- package/dist/events/event-bus.d.ts.map +1 -0
- package/dist/events/event-bus.js +263 -0
- package/dist/events/event-bus.js.map +1 -0
- package/dist/events/plugin-hooks.d.ts +44 -0
- package/dist/events/plugin-hooks.d.ts.map +1 -0
- package/dist/events/plugin-hooks.js +225 -0
- package/dist/events/plugin-hooks.js.map +1 -0
- package/dist/orchestrator/budget-packer.d.ts +57 -0
- package/dist/orchestrator/budget-packer.d.ts.map +1 -0
- package/dist/orchestrator/budget-packer.js +70 -0
- package/dist/orchestrator/budget-packer.js.map +1 -0
- package/dist/orchestrator/config.d.ts +43 -0
- package/dist/orchestrator/config.d.ts.map +1 -0
- package/dist/orchestrator/config.js +109 -0
- package/dist/orchestrator/config.js.map +1 -0
- package/dist/orchestrator/endpoint-clients.d.ts +23 -0
- package/dist/orchestrator/endpoint-clients.d.ts.map +1 -0
- package/dist/orchestrator/endpoint-clients.js +129 -0
- package/dist/orchestrator/endpoint-clients.js.map +1 -0
- package/dist/orchestrator/orchestrator-loop.d.ts +93 -0
- package/dist/orchestrator/orchestrator-loop.d.ts.map +1 -0
- package/dist/orchestrator/orchestrator-loop.js +185 -0
- package/dist/orchestrator/orchestrator-loop.js.map +1 -0
- package/dist/security/confirmation.d.ts +90 -0
- package/dist/security/confirmation.d.ts.map +1 -0
- package/dist/security/confirmation.js +140 -0
- package/dist/security/confirmation.js.map +1 -0
- package/dist/setup/setup-compute.d.ts +54 -0
- package/dist/setup/setup-compute.d.ts.map +1 -0
- package/dist/setup/setup-compute.js +66 -0
- package/dist/setup/setup-compute.js.map +1 -0
- package/dist/state/snapshot-store.d.ts +79 -0
- package/dist/state/snapshot-store.d.ts.map +1 -0
- package/dist/state/snapshot-store.js +164 -0
- package/dist/state/snapshot-store.js.map +1 -0
- package/dist/state/state-recovery.d.ts +87 -0
- package/dist/state/state-recovery.d.ts.map +1 -0
- package/dist/state/state-recovery.js +274 -0
- package/dist/state/state-recovery.js.map +1 -0
- package/dist/state/transition-log.d.ts +40 -0
- package/dist/state/transition-log.d.ts.map +1 -0
- package/dist/state/transition-log.js +83 -0
- package/dist/state/transition-log.js.map +1 -0
- package/dist/state/yaml-helpers.d.ts +53 -0
- package/dist/state/yaml-helpers.d.ts.map +1 -0
- package/dist/state/yaml-helpers.js +110 -0
- package/dist/state/yaml-helpers.js.map +1 -0
- package/examples/.gitkeep +0 -0
- package/guidance/accessibility.md +67 -0
- package/guidance/api-conventions.md +124 -0
- package/guidance/index.yaml +7 -0
- package/guidance/secure-defaults.md +71 -0
- package/package.json +52 -0
- package/phases/.gitkeep +0 -0
- package/skills/00-overview.md +74 -0
- package/skills/10-ideation.md +45 -0
- package/skills/20-requirements.md +54 -0
- package/skills/30-design.md +57 -0
- package/skills/40-implementation.md +64 -0
- package/skills/50-testing.md +60 -0
- package/skills/60-deployment.md +63 -0
- package/skills/70-maintenance.md +56 -0
- package/skills/80-review.md +85 -0
- package/skills/81-continue.md +57 -0
- package/skills/82-add-action.md +71 -0
- package/templates/.gitkeep +0 -0
- package/templates/bugfix.yaml +14 -0
- package/templates/full-feature.yaml +44 -0
- package/templates/micro-task.yaml +11 -0
- package/templates/quick-feature.yaml +20 -0
- package/templates/spike.yaml +15 -0
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `aidlc transition <instance>` command — evaluate gates and advance phase.
|
|
3
|
+
*
|
|
4
|
+
* Behavior:
|
|
5
|
+
* - Load instance state, phase states, and resolve template.
|
|
6
|
+
* - Call `evaluateTransition(state, phaseStates, template, actor, findings, override)`.
|
|
7
|
+
* - Call `nextStep(state, phaseStates, template)` to determine the target phase.
|
|
8
|
+
* - If transition is allowed:
|
|
9
|
+
* - Update current_phase in instance.yaml to the next phase.
|
|
10
|
+
* - Update source phase status to 'complete'.
|
|
11
|
+
* - Update target phase status to 'in-progress'.
|
|
12
|
+
* - Append a TransitionRecord to transitions.log.
|
|
13
|
+
* - Fire on-phase-exit and on-phase-enter events.
|
|
14
|
+
* - Print success message.
|
|
15
|
+
* - If blocked: print all violations, exit code 1.
|
|
16
|
+
*
|
|
17
|
+
* Options:
|
|
18
|
+
* --override Override ownership gate
|
|
19
|
+
* --json Output result as JSON
|
|
20
|
+
*
|
|
21
|
+
* Requirements: 3.6, 6.6, 11.5, 5.5
|
|
22
|
+
*
|
|
23
|
+
* @module
|
|
24
|
+
*/
|
|
25
|
+
import { Command } from 'commander';
|
|
26
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
27
|
+
import { join, resolve } from 'node:path';
|
|
28
|
+
import { fileURLToPath } from 'node:url';
|
|
29
|
+
import { evaluateTransition, nextStep } from '../core/lifecycle.js';
|
|
30
|
+
import { loadSnapshot, saveSnapshot } from '../state/snapshot-store.js';
|
|
31
|
+
import { appendTransition } from '../state/transition-log.js';
|
|
32
|
+
import { loadTemplates, resolveTemplate } from '../core/template-resolver.js';
|
|
33
|
+
import { emit, loadActionsConfig } from '../events/event-bus.js';
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
// Helpers
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
/**
|
|
38
|
+
* Resolve the package root directory.
|
|
39
|
+
*/
|
|
40
|
+
function getPackageRoot() {
|
|
41
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
42
|
+
return resolve(thisFile, '..', '..', '..');
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Load all templates: built-in from the package + custom from the project.
|
|
46
|
+
*/
|
|
47
|
+
function loadAllTemplates(packageRoot, projectRoot) {
|
|
48
|
+
const builtInDir = join(packageRoot, 'templates');
|
|
49
|
+
const customDir = join(projectRoot, '.aidlc', 'templates');
|
|
50
|
+
const templates = loadTemplates(builtInDir);
|
|
51
|
+
if (existsSync(customDir)) {
|
|
52
|
+
const custom = loadTemplates(customDir);
|
|
53
|
+
for (const [name, tpl] of custom) {
|
|
54
|
+
templates.set(name, tpl);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return templates;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Load all phase state files for a given instance.
|
|
61
|
+
*/
|
|
62
|
+
function loadPhaseStates(stateDir, instanceName) {
|
|
63
|
+
const phases = new Map();
|
|
64
|
+
const instanceDir = join(stateDir, instanceName);
|
|
65
|
+
let entries;
|
|
66
|
+
try {
|
|
67
|
+
entries = readdirSync(instanceDir);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return phases;
|
|
71
|
+
}
|
|
72
|
+
const phaseFiles = entries.filter((f) => f.startsWith('phase-') && f.endsWith('.yaml'));
|
|
73
|
+
for (const file of phaseFiles) {
|
|
74
|
+
try {
|
|
75
|
+
const phaseState = loadSnapshot(stateDir, instanceName, file);
|
|
76
|
+
if (phaseState && phaseState.phase) {
|
|
77
|
+
phases.set(phaseState.phase, phaseState);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// Skip corrupt phase files
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return phases;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Determine the actor identity from environment variables.
|
|
88
|
+
* Uses USER, USERNAME, or falls back to 'unknown'.
|
|
89
|
+
*/
|
|
90
|
+
function getActorIdentity() {
|
|
91
|
+
return (process.env.USER ||
|
|
92
|
+
process.env.USERNAME ||
|
|
93
|
+
'unknown');
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Parse review findings from `<artifact>.review.md` files in the instance directory.
|
|
97
|
+
*
|
|
98
|
+
* Looks for files matching `*.review.md` and parses them into a FindingsIndex.
|
|
99
|
+
* Each finding is parsed from markdown heading format:
|
|
100
|
+
* ## <id>: <title> [<severity>] [<status>]
|
|
101
|
+
*/
|
|
102
|
+
function loadFindings(stateDir, instanceName) {
|
|
103
|
+
const findings = {};
|
|
104
|
+
const instanceDir = join(stateDir, instanceName);
|
|
105
|
+
let entries;
|
|
106
|
+
try {
|
|
107
|
+
entries = readdirSync(instanceDir);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return findings;
|
|
111
|
+
}
|
|
112
|
+
const reviewFiles = entries.filter((f) => f.endsWith('.review.md'));
|
|
113
|
+
for (const file of reviewFiles) {
|
|
114
|
+
const artifactName = file.replace('.review.md', '');
|
|
115
|
+
const filePath = join(instanceDir, file);
|
|
116
|
+
try {
|
|
117
|
+
const content = readFileSync(filePath, 'utf8');
|
|
118
|
+
const parsed = parseFindingsFromMarkdown(content);
|
|
119
|
+
if (parsed.length > 0) {
|
|
120
|
+
findings[artifactName] = parsed;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Skip unparseable review files
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return findings;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Parse findings from markdown content.
|
|
131
|
+
*
|
|
132
|
+
* Expected format:
|
|
133
|
+
* ## F1: Title [critical] [open]
|
|
134
|
+
* - Section: ...
|
|
135
|
+
* - Issue: ...
|
|
136
|
+
* - Suggested resolution: ...
|
|
137
|
+
*/
|
|
138
|
+
function parseFindingsFromMarkdown(content) {
|
|
139
|
+
const findings = [];
|
|
140
|
+
const headingPattern = /^## ([\w-]+): (.+?) \[(critical|major|minor|info)\] \[(open|resolved|accepted-risk|rejected)\]/gm;
|
|
141
|
+
let match;
|
|
142
|
+
while ((match = headingPattern.exec(content)) !== null) {
|
|
143
|
+
findings.push({
|
|
144
|
+
id: match[1],
|
|
145
|
+
title: match[2],
|
|
146
|
+
severity: match[3],
|
|
147
|
+
status: match[4],
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return findings;
|
|
151
|
+
}
|
|
152
|
+
// ---------------------------------------------------------------------------
|
|
153
|
+
// Command registration
|
|
154
|
+
// ---------------------------------------------------------------------------
|
|
155
|
+
/**
|
|
156
|
+
* Register the `aidlc transition` command on the given commander program.
|
|
157
|
+
*/
|
|
158
|
+
export function registerTransition(program) {
|
|
159
|
+
program
|
|
160
|
+
.command('transition')
|
|
161
|
+
.description('Evaluate gates and advance to the next phase')
|
|
162
|
+
.argument('<instance>', 'Lifecycle instance name')
|
|
163
|
+
.option('--override', 'Override ownership gate')
|
|
164
|
+
.option('--json', 'Output result as JSON')
|
|
165
|
+
.action((instance, opts) => {
|
|
166
|
+
runTransition(instance, opts);
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
// ---------------------------------------------------------------------------
|
|
170
|
+
// Core logic
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
function runTransition(instanceArg, opts) {
|
|
173
|
+
const packageRoot = getPackageRoot();
|
|
174
|
+
const projectRoot = process.cwd();
|
|
175
|
+
const stateDir = join(projectRoot, '.aidlc', 'state');
|
|
176
|
+
// Check instance exists
|
|
177
|
+
const instanceDir = join(stateDir, instanceArg);
|
|
178
|
+
if (!existsSync(instanceDir)) {
|
|
179
|
+
process.stderr.write(`Error: instance '${instanceArg}' not found.\n`);
|
|
180
|
+
process.exitCode = 1;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
// Load instance state
|
|
184
|
+
let instanceState;
|
|
185
|
+
try {
|
|
186
|
+
instanceState = loadSnapshot(stateDir, instanceArg, 'instance.yaml');
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
process.stderr.write(`Error: failed to load instance state: ${err.message}\n`);
|
|
190
|
+
process.exitCode = 1;
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
// Load phase states
|
|
194
|
+
const phaseStates = loadPhaseStates(stateDir, instanceArg);
|
|
195
|
+
// Resolve template
|
|
196
|
+
const allTemplates = loadAllTemplates(packageRoot, projectRoot);
|
|
197
|
+
const rawTemplate = allTemplates.get(instanceState.template);
|
|
198
|
+
if (!rawTemplate) {
|
|
199
|
+
process.stderr.write(`Error: template '${instanceState.template}' not found.\n`);
|
|
200
|
+
process.exitCode = 1;
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
let resolvedTemplate;
|
|
204
|
+
try {
|
|
205
|
+
resolvedTemplate = resolveTemplate(rawTemplate, allTemplates);
|
|
206
|
+
}
|
|
207
|
+
catch (err) {
|
|
208
|
+
process.stderr.write(`Error: failed to resolve template: ${err.message}\n`);
|
|
209
|
+
process.exitCode = 1;
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
// Determine actor identity
|
|
213
|
+
const actor = getActorIdentity();
|
|
214
|
+
// Load findings for review gate evaluation
|
|
215
|
+
const findings = loadFindings(stateDir, instanceArg);
|
|
216
|
+
// Evaluate transition gates
|
|
217
|
+
const result = evaluateTransition(instanceState, phaseStates, resolvedTemplate, actor, findings, opts.override);
|
|
218
|
+
if (!result.allowed) {
|
|
219
|
+
// Transition blocked — print violations
|
|
220
|
+
if (opts.json) {
|
|
221
|
+
process.stdout.write(JSON.stringify({ allowed: false, violations: result.violations }, null, 2) + '\n');
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
process.stdout.write(`✗ Transition blocked for instance "${instanceArg}"\n\n`);
|
|
225
|
+
process.stdout.write(` Violations:\n`);
|
|
226
|
+
for (const v of result.violations) {
|
|
227
|
+
process.stdout.write(` [${v.gate}] ${v.reason}\n`);
|
|
228
|
+
}
|
|
229
|
+
process.stdout.write('\n');
|
|
230
|
+
}
|
|
231
|
+
process.exitCode = 1;
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
// Transition allowed — determine the next phase
|
|
235
|
+
const next = nextStep(instanceState, phaseStates, resolvedTemplate);
|
|
236
|
+
if (next.kind === 'complete') {
|
|
237
|
+
// All phases are done — nothing to transition to
|
|
238
|
+
if (opts.json) {
|
|
239
|
+
process.stdout.write(JSON.stringify({ allowed: true, complete: true }, null, 2) + '\n');
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
process.stdout.write(`✓ Instance "${instanceArg}" is already complete — no further transitions.\n`);
|
|
243
|
+
}
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
// Determine the target phase
|
|
247
|
+
const sourcePhase = instanceState.current_phase;
|
|
248
|
+
const targetPhase = next.kind === 'phase' ? next.phase : sourcePhase;
|
|
249
|
+
// Only perform a phase transition if we're moving to a new phase
|
|
250
|
+
if (next.kind === 'artifact') {
|
|
251
|
+
// Still in the same phase — artifacts remain, not a phase-level transition
|
|
252
|
+
if (opts.json) {
|
|
253
|
+
process.stdout.write(JSON.stringify({
|
|
254
|
+
allowed: true,
|
|
255
|
+
transition: false,
|
|
256
|
+
reason: `phase "${sourcePhase}" still has incomplete artifacts`,
|
|
257
|
+
next_artifact: next.artifact,
|
|
258
|
+
}, null, 2) + '\n');
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
process.stdout.write(`✓ Gates passed for "${instanceArg}" but phase "${sourcePhase}" still has work remaining.\n` +
|
|
262
|
+
` Next artifact: ${next.artifact}\n`);
|
|
263
|
+
}
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
// Phase transition: source → target
|
|
267
|
+
const now = new Date().toISOString();
|
|
268
|
+
// Update source phase: mark as 'complete'
|
|
269
|
+
const sourcePhaseState = phaseStates.get(sourcePhase);
|
|
270
|
+
if (sourcePhaseState) {
|
|
271
|
+
sourcePhaseState.status = 'complete';
|
|
272
|
+
sourcePhaseState.completed_at = now;
|
|
273
|
+
sourcePhaseState.completed_by = actor;
|
|
274
|
+
saveSnapshot(stateDir, instanceArg, `phase-${sourcePhase}.yaml`, sourcePhaseState);
|
|
275
|
+
}
|
|
276
|
+
// Update target phase: mark as 'in-progress'
|
|
277
|
+
const targetPhaseState = phaseStates.get(targetPhase);
|
|
278
|
+
if (targetPhaseState) {
|
|
279
|
+
targetPhaseState.status = 'in-progress';
|
|
280
|
+
targetPhaseState.entered_at = now;
|
|
281
|
+
saveSnapshot(stateDir, instanceArg, `phase-${targetPhase}.yaml`, targetPhaseState);
|
|
282
|
+
}
|
|
283
|
+
// Update instance.yaml: advance current_phase
|
|
284
|
+
instanceState.current_phase = targetPhase;
|
|
285
|
+
saveSnapshot(stateDir, instanceArg, 'instance.yaml', instanceState);
|
|
286
|
+
// Append transition record to transitions.log
|
|
287
|
+
const transitionRecord = {
|
|
288
|
+
at: now,
|
|
289
|
+
by: actor,
|
|
290
|
+
from: sourcePhase,
|
|
291
|
+
to: targetPhase,
|
|
292
|
+
type: 'normal',
|
|
293
|
+
criteria: buildSatisfiedCriteria(sourcePhaseState),
|
|
294
|
+
};
|
|
295
|
+
const logPath = join(stateDir, instanceArg, 'transitions.log');
|
|
296
|
+
appendTransition(logPath, transitionRecord);
|
|
297
|
+
// Fire on-phase-exit and on-phase-enter events
|
|
298
|
+
const actionsPath = join(projectRoot, '.aidlc', 'actions.yaml');
|
|
299
|
+
let actionsConfig = null;
|
|
300
|
+
try {
|
|
301
|
+
actionsConfig = loadActionsConfig(actionsPath);
|
|
302
|
+
}
|
|
303
|
+
catch {
|
|
304
|
+
// Non-fatal: proceed without actions
|
|
305
|
+
}
|
|
306
|
+
const exitPayload = {
|
|
307
|
+
event: 'on-phase-exit',
|
|
308
|
+
instance: instanceArg,
|
|
309
|
+
phase: sourcePhase,
|
|
310
|
+
template: instanceState.template,
|
|
311
|
+
};
|
|
312
|
+
emit(exitPayload, actionsConfig);
|
|
313
|
+
const enterPayload = {
|
|
314
|
+
event: 'on-phase-enter',
|
|
315
|
+
instance: instanceArg,
|
|
316
|
+
phase: targetPhase,
|
|
317
|
+
template: instanceState.template,
|
|
318
|
+
};
|
|
319
|
+
emit(enterPayload, actionsConfig);
|
|
320
|
+
// Output success message
|
|
321
|
+
if (opts.json) {
|
|
322
|
+
process.stdout.write(JSON.stringify({
|
|
323
|
+
allowed: true,
|
|
324
|
+
transition: true,
|
|
325
|
+
from: sourcePhase,
|
|
326
|
+
to: targetPhase,
|
|
327
|
+
at: now,
|
|
328
|
+
by: actor,
|
|
329
|
+
}, null, 2) + '\n');
|
|
330
|
+
}
|
|
331
|
+
else {
|
|
332
|
+
process.stdout.write(`✓ Transitioned "${instanceArg}": ${sourcePhase} → ${targetPhase}\n`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Build a list of satisfied criteria descriptions from the completed phase state.
|
|
337
|
+
*/
|
|
338
|
+
function buildSatisfiedCriteria(phaseState) {
|
|
339
|
+
if (!phaseState)
|
|
340
|
+
return [];
|
|
341
|
+
const criteria = [];
|
|
342
|
+
// Record completed artifacts as satisfied criteria
|
|
343
|
+
for (const artifact of phaseState.artifacts) {
|
|
344
|
+
if (artifact.status === 'complete') {
|
|
345
|
+
criteria.push(`${artifact.name} complete`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (criteria.length === 0) {
|
|
349
|
+
criteria.push('all exit criteria satisfied');
|
|
350
|
+
}
|
|
351
|
+
return criteria;
|
|
352
|
+
}
|
|
353
|
+
//# sourceMappingURL=transition.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transition.js","sourceRoot":"","sources":["../../src/commands/transition.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code platform adapter.
|
|
3
|
+
*
|
|
4
|
+
* Generates an InstallPlan that installs AIDLC skills into Claude Code's native
|
|
5
|
+
* configuration structure:
|
|
6
|
+
*
|
|
7
|
+
* - Canonical skill bodies → `.aidlc/skills/<filename>`
|
|
8
|
+
* - Per-skill shims → `.claude/skills/aidlc-<name>/SKILL.md`
|
|
9
|
+
* - State protocol + context-doc references → `merge-block` into `CLAUDE.md`
|
|
10
|
+
*
|
|
11
|
+
* Capability map consumption follows the resolution precedence:
|
|
12
|
+
* 1. `skill.meta.native_mode_hint['claude-code']` → use it
|
|
13
|
+
* 2. Capability map entry covering the skill's phase → inject activation directive
|
|
14
|
+
* 3. Otherwise → full structured guidance, no native references
|
|
15
|
+
*
|
|
16
|
+
* Malformed/unknown-phase map → stderr warning + adapter proceeds capability-free (Req 18.7)
|
|
17
|
+
*
|
|
18
|
+
* Requirements: 1.1, 18.1, 18.7
|
|
19
|
+
*
|
|
20
|
+
* @module
|
|
21
|
+
*/
|
|
22
|
+
import type { PlatformAdapter } from '../../core/types.js';
|
|
23
|
+
export declare const claudeCodeAdapter: PlatformAdapter;
|
|
24
|
+
//# sourceMappingURL=claude-code.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-code.d.ts","sourceRoot":"","sources":["../../../src/compile/adapters/claude-code.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EACV,eAAe,EAShB,MAAM,qBAAqB,CAAC;AAoN7B,eAAO,MAAM,iBAAiB,EAAE,eA4G/B,CAAC"}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code platform adapter.
|
|
3
|
+
*
|
|
4
|
+
* Generates an InstallPlan that installs AIDLC skills into Claude Code's native
|
|
5
|
+
* configuration structure:
|
|
6
|
+
*
|
|
7
|
+
* - Canonical skill bodies → `.aidlc/skills/<filename>`
|
|
8
|
+
* - Per-skill shims → `.claude/skills/aidlc-<name>/SKILL.md`
|
|
9
|
+
* - State protocol + context-doc references → `merge-block` into `CLAUDE.md`
|
|
10
|
+
*
|
|
11
|
+
* Capability map consumption follows the resolution precedence:
|
|
12
|
+
* 1. `skill.meta.native_mode_hint['claude-code']` → use it
|
|
13
|
+
* 2. Capability map entry covering the skill's phase → inject activation directive
|
|
14
|
+
* 3. Otherwise → full structured guidance, no native references
|
|
15
|
+
*
|
|
16
|
+
* Malformed/unknown-phase map → stderr warning + adapter proceeds capability-free (Req 18.7)
|
|
17
|
+
*
|
|
18
|
+
* Requirements: 1.1, 18.1, 18.7
|
|
19
|
+
*
|
|
20
|
+
* @module
|
|
21
|
+
*/
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Constants
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
/** Valid lifecycle phase names for capability map validation. */
|
|
26
|
+
const VALID_PHASES = new Set([
|
|
27
|
+
'ideation',
|
|
28
|
+
'requirements',
|
|
29
|
+
'design',
|
|
30
|
+
'implementation',
|
|
31
|
+
'testing',
|
|
32
|
+
'deployment',
|
|
33
|
+
'maintenance',
|
|
34
|
+
]);
|
|
35
|
+
/** Maximum length for the skill name in Claude Code format. */
|
|
36
|
+
const MAX_SKILL_NAME_LENGTH = 64;
|
|
37
|
+
/** Pattern: lowercase, hyphens allowed, must match directory name. */
|
|
38
|
+
const SKILL_NAME_RE = /^[a-z][a-z0-9-]*$/;
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Helpers
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
/**
|
|
43
|
+
* Validate and sanitize a capability map. Returns a clean map with only valid
|
|
44
|
+
* entries, or null if the map is entirely unusable. Emits warnings for problems.
|
|
45
|
+
*/
|
|
46
|
+
function validateCapabilityMap(caps, warnings) {
|
|
47
|
+
const phaseMap = new Map();
|
|
48
|
+
if (!caps.capabilities || typeof caps.capabilities !== 'object') {
|
|
49
|
+
warnings.push(`capability map for '${caps.platform}': malformed capabilities object; proceeding capability-free`);
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
let hasValidEntry = false;
|
|
53
|
+
for (const [capName, entry] of Object.entries(caps.capabilities)) {
|
|
54
|
+
if (!entry || typeof entry !== 'object') {
|
|
55
|
+
warnings.push(`capability map '${caps.platform}': capability '${capName}' is malformed; skipping`);
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
if (!Array.isArray(entry.phases)) {
|
|
59
|
+
warnings.push(`capability map '${caps.platform}': capability '${capName}' has invalid phases; skipping`);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (!entry.activation || typeof entry.activation !== 'string') {
|
|
63
|
+
warnings.push(`capability map '${caps.platform}': capability '${capName}' missing activation text; skipping`);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
for (const phase of entry.phases) {
|
|
67
|
+
if (!VALID_PHASES.has(phase)) {
|
|
68
|
+
warnings.push(`capability map '${caps.platform}': unknown phase '${phase}' in capability '${capName}'; skipping phase`);
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
phaseMap.set(phase, entry);
|
|
72
|
+
hasValidEntry = true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return hasValidEntry ? phaseMap : null;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Derive the activation directive for a skill given the resolution precedence.
|
|
79
|
+
*/
|
|
80
|
+
function resolveActivation(skill, phaseMap) {
|
|
81
|
+
// 1. native_mode_hint for claude-code takes precedence
|
|
82
|
+
const hint = skill.meta.native_mode_hint?.['claude-code'];
|
|
83
|
+
if (hint) {
|
|
84
|
+
return hint;
|
|
85
|
+
}
|
|
86
|
+
// 2. Capability map entry covering the skill's phase
|
|
87
|
+
if (phaseMap) {
|
|
88
|
+
const entry = phaseMap.get(skill.meta.phase);
|
|
89
|
+
if (entry) {
|
|
90
|
+
return entry.activation;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// 3. No native reference — full structured guidance
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Normalize a skill name for the Claude Code directory convention.
|
|
98
|
+
* Must be lowercase, hyphens allowed, ≤ 64 chars, matching the dir name.
|
|
99
|
+
*/
|
|
100
|
+
function normalizeSkillName(name) {
|
|
101
|
+
// Strip aidlc- prefix if already present, then re-add
|
|
102
|
+
let normalized = name.toLowerCase().replace(/[^a-z0-9-]/g, '-');
|
|
103
|
+
// Remove consecutive hyphens
|
|
104
|
+
normalized = normalized.replace(/-+/g, '-').replace(/^-|-$/g, '');
|
|
105
|
+
// Ensure aidlc- prefix
|
|
106
|
+
if (!normalized.startsWith('aidlc-')) {
|
|
107
|
+
normalized = `aidlc-${normalized}`;
|
|
108
|
+
}
|
|
109
|
+
// Truncate to max length
|
|
110
|
+
if (normalized.length > MAX_SKILL_NAME_LENGTH) {
|
|
111
|
+
normalized = normalized.slice(0, MAX_SKILL_NAME_LENGTH);
|
|
112
|
+
}
|
|
113
|
+
return normalized;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Derive the canonical skill filename for `.aidlc/skills/`.
|
|
117
|
+
*/
|
|
118
|
+
function canonicalFilename(skill) {
|
|
119
|
+
// Use the skill name directly, kebab-case + .md
|
|
120
|
+
return `${skill.meta.name}.md`;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Generate the SKILL.md shim content for Claude Code.
|
|
124
|
+
*/
|
|
125
|
+
function generateShimContent(skill, dirName, activation, canonicalPath) {
|
|
126
|
+
const lines = [];
|
|
127
|
+
// Frontmatter
|
|
128
|
+
lines.push('---');
|
|
129
|
+
lines.push(`name: ${dirName}`);
|
|
130
|
+
lines.push(`description: ${skill.meta.description}`);
|
|
131
|
+
lines.push('---');
|
|
132
|
+
lines.push('');
|
|
133
|
+
// Activation directive (if any)
|
|
134
|
+
if (activation) {
|
|
135
|
+
lines.push(activation);
|
|
136
|
+
lines.push('');
|
|
137
|
+
}
|
|
138
|
+
// Pointer to canonical skill body
|
|
139
|
+
lines.push(`Read \`.aidlc/skills/${canonicalPath}\` and follow its instructions.`);
|
|
140
|
+
lines.push('');
|
|
141
|
+
return lines.join('\n');
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Generate the CLAUDE.md managed block content (state protocol + context refs).
|
|
145
|
+
*/
|
|
146
|
+
function generateClaudeMdBlock(ctx) {
|
|
147
|
+
const lines = [];
|
|
148
|
+
lines.push('# AIDLC Lifecycle');
|
|
149
|
+
lines.push('');
|
|
150
|
+
lines.push('## State Protocol');
|
|
151
|
+
lines.push('');
|
|
152
|
+
lines.push('- Lifecycle state lives in `.aidlc/state/<instance>/`');
|
|
153
|
+
lines.push('- Before mutating state, claim the instance (check `instance.yaml` claim field)');
|
|
154
|
+
lines.push('- After completing a phase, update `phase-<name>.yaml` and append to `transitions.log`');
|
|
155
|
+
lines.push('- Use `aidlc status` to see current progress across all instances');
|
|
156
|
+
lines.push('');
|
|
157
|
+
// Context doc references
|
|
158
|
+
const docNames = Object.keys(ctx.contextDocs);
|
|
159
|
+
if (docNames.length > 0) {
|
|
160
|
+
lines.push('## Context Documents');
|
|
161
|
+
lines.push('');
|
|
162
|
+
for (const name of docNames.sort()) {
|
|
163
|
+
lines.push(`- \`.aidlc/context/${ctx.contextDocs[name]}\` — ${name}`);
|
|
164
|
+
}
|
|
165
|
+
lines.push('');
|
|
166
|
+
}
|
|
167
|
+
// Guidance layer references
|
|
168
|
+
const layerNames = Object.keys(ctx.guidanceLayers);
|
|
169
|
+
if (layerNames.length > 0) {
|
|
170
|
+
lines.push('## Guidance Layers');
|
|
171
|
+
lines.push('');
|
|
172
|
+
for (const name of layerNames.sort()) {
|
|
173
|
+
lines.push(`- \`.aidlc/guidance/${ctx.guidanceLayers[name]}\` — ${name}`);
|
|
174
|
+
}
|
|
175
|
+
lines.push('');
|
|
176
|
+
}
|
|
177
|
+
return lines.join('\n');
|
|
178
|
+
}
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
// Adapter Implementation
|
|
181
|
+
// ---------------------------------------------------------------------------
|
|
182
|
+
export const claudeCodeAdapter = {
|
|
183
|
+
id: 'claude-code',
|
|
184
|
+
plan(skills, caps, ctx) {
|
|
185
|
+
const ops = [];
|
|
186
|
+
const warnings = [];
|
|
187
|
+
// Validate capability map
|
|
188
|
+
let phaseMap = null;
|
|
189
|
+
if (caps) {
|
|
190
|
+
phaseMap = validateCapabilityMap(caps, warnings);
|
|
191
|
+
}
|
|
192
|
+
// 1. Copy canonical skill bodies to .aidlc/skills/
|
|
193
|
+
for (const skill of skills) {
|
|
194
|
+
const filename = canonicalFilename(skill);
|
|
195
|
+
ops.push({
|
|
196
|
+
kind: 'create',
|
|
197
|
+
path: `.aidlc/skills/${filename}`,
|
|
198
|
+
content: skill.body,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
// 2. Generate .claude/skills/aidlc-<name>/SKILL.md per skill
|
|
202
|
+
for (const skill of skills) {
|
|
203
|
+
const dirName = normalizeSkillName(skill.meta.name);
|
|
204
|
+
const activation = resolveActivation(skill, phaseMap);
|
|
205
|
+
const canonicalPath = canonicalFilename(skill);
|
|
206
|
+
const shimContent = generateShimContent(skill, dirName, activation, canonicalPath);
|
|
207
|
+
ops.push({
|
|
208
|
+
kind: 'create',
|
|
209
|
+
path: `.claude/skills/${dirName}/SKILL.md`,
|
|
210
|
+
content: shimContent,
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
// 3. Generate merge-block into CLAUDE.md with state protocol + context refs
|
|
214
|
+
const claudeMdContent = generateClaudeMdBlock(ctx);
|
|
215
|
+
ops.push({
|
|
216
|
+
kind: 'merge-block',
|
|
217
|
+
path: 'CLAUDE.md',
|
|
218
|
+
blockId: 'aidlc-lifecycle',
|
|
219
|
+
content: claudeMdContent,
|
|
220
|
+
});
|
|
221
|
+
return { ops, warnings };
|
|
222
|
+
},
|
|
223
|
+
validate(op) {
|
|
224
|
+
const errors = [];
|
|
225
|
+
const resultWarnings = [];
|
|
226
|
+
if (op.kind === 'merge-block') {
|
|
227
|
+
// Merge-block into CLAUDE.md — always valid structurally
|
|
228
|
+
return { valid: true, errors: [], warnings: [] };
|
|
229
|
+
}
|
|
230
|
+
// Validate .claude/skills/*/SKILL.md files
|
|
231
|
+
if (op.path.startsWith('.claude/skills/') && op.path.endsWith('/SKILL.md')) {
|
|
232
|
+
// Extract directory name from path
|
|
233
|
+
const segments = op.path.split('/');
|
|
234
|
+
const dirName = segments[2]; // .claude/skills/<dirName>/SKILL.md
|
|
235
|
+
// Validate directory name format
|
|
236
|
+
if (!dirName || !SKILL_NAME_RE.test(dirName)) {
|
|
237
|
+
errors.push(`skill directory name '${dirName}' must be lowercase with hyphens only`);
|
|
238
|
+
}
|
|
239
|
+
if (dirName && dirName.length > MAX_SKILL_NAME_LENGTH) {
|
|
240
|
+
errors.push(`skill directory name '${dirName}' exceeds ${MAX_SKILL_NAME_LENGTH} character limit`);
|
|
241
|
+
}
|
|
242
|
+
// Validate frontmatter presence and required fields
|
|
243
|
+
const content = op.content;
|
|
244
|
+
if (!content.startsWith('---\n')) {
|
|
245
|
+
errors.push('SKILL.md must begin with YAML frontmatter (---)');
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
const endIdx = content.indexOf('\n---\n', 4);
|
|
249
|
+
if (endIdx === -1) {
|
|
250
|
+
errors.push('SKILL.md has unclosed frontmatter');
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
const frontmatter = content.slice(4, endIdx);
|
|
254
|
+
if (!frontmatter.includes('name:')) {
|
|
255
|
+
errors.push("SKILL.md frontmatter missing required field 'name'");
|
|
256
|
+
}
|
|
257
|
+
if (!frontmatter.includes('description:')) {
|
|
258
|
+
errors.push("SKILL.md frontmatter missing required field 'description'");
|
|
259
|
+
}
|
|
260
|
+
// Validate name matches directory name
|
|
261
|
+
const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
|
|
262
|
+
if (nameMatch && nameMatch[1].trim() !== dirName) {
|
|
263
|
+
errors.push(`SKILL.md frontmatter 'name' (${nameMatch[1].trim()}) must match directory name (${dirName})`);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return { valid: errors.length === 0, errors, warnings: resultWarnings };
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
//# sourceMappingURL=claude-code.js.map
|