@juangcarmona/lighthouse-sdlc 0.6.0 → 0.8.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 +14 -0
- package/command-aliases.json +20 -0
- package/commands/aliases.md +5 -0
- package/commands/evidence.md +9 -0
- package/contract.json +6 -2
- package/package.json +11 -2
- package/schemas/command-aliases.schema.json +35 -0
- package/schemas/evidence-index.schema.json +65 -0
- package/schemas/evidence-record.schema.json +67 -0
- package/schemas/sdlc-contract.schema.json +4 -2
- package/src/aliases.mjs +57 -0
- package/src/evidence.mjs +204 -0
- package/src/sdlc.mjs +68 -5
- package/workflows/lighthouse-sdlc-implement.lock.yml +2212 -0
- package/workflows/lighthouse-sdlc-implement.md +41 -0
- package/workflows/lighthouse-sdlc-integrate.lock.yml +2212 -0
- package/workflows/lighthouse-sdlc-integrate.md +41 -0
- package/workflows/lighthouse-sdlc-propose.lock.yml +2212 -0
- package/workflows/lighthouse-sdlc-propose.md +41 -0
- package/workflows/lighthouse-sdlc-refine.lock.yml +2212 -0
- package/workflows/lighthouse-sdlc-refine.md +41 -0
- package/workflows/lighthouse-sdlc-review.lock.yml +2212 -0
- package/workflows/lighthouse-sdlc-review.md +41 -0
- package/workflows/lighthouse-sdlc-router.yml +176 -0
- package/workflows/lighthouse-sdlc-triage.lock.yml +2212 -0
- package/workflows/lighthouse-sdlc-triage.md +41 -0
- package/workflows/shared/lighthouse-sdlc-stage.md +81 -0
package/src/sdlc.mjs
CHANGED
|
@@ -14,7 +14,9 @@ import { validateMemoryRecord } from './memory.mjs';
|
|
|
14
14
|
import { replayWorkflow } from './workflow.mjs';
|
|
15
15
|
import { validateStageResult } from './contracts.mjs';
|
|
16
16
|
import { browserEvidenceReport } from './browser-e2e.mjs';
|
|
17
|
+
import { buildEvidenceIndex, evidenceReport, validateEvidenceIndex, validateEvidenceRecord } from './evidence.mjs';
|
|
17
18
|
import { readCapabilityCatalog, validateCapabilityCatalog } from './capabilities.mjs';
|
|
19
|
+
import { readCommandAliases, validateCommandAliases, verifyCommandAliases } from './aliases.mjs';
|
|
18
20
|
|
|
19
21
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
|
20
22
|
const contractPath = resolve(packageRoot, 'contract.json');
|
|
@@ -40,10 +42,10 @@ async function verifyContract() {
|
|
|
40
42
|
for (const stage of stages) {
|
|
41
43
|
for (const asset of [stage.skill, stage.command]) if (!(await exists(resolve(packageRoot, asset)))) problems.push(`missing stage asset ${asset}`);
|
|
42
44
|
}
|
|
43
|
-
for (const asset of [contract.assets?.routes, contract.assets?.gates, contract.assets?.stages, contract.assets?.controlPlaneSchema, contract.assets?.triageSchema, contract.assets?.stageResultSchema, contract.assets?.stateSchema, contract.assets?.decompositionSchema, contract.assets?.capabilitiesSchema, contract.assets?.capabilityCatalog, contract.assets?.capabilityCatalogSchema, contract.assets?.browserE2eSchema]) {
|
|
45
|
+
for (const asset of [contract.assets?.routes, contract.assets?.gates, contract.assets?.stages, contract.assets?.controlPlaneSchema, contract.assets?.triageSchema, contract.assets?.stageResultSchema, contract.assets?.stateSchema, contract.assets?.decompositionSchema, contract.assets?.capabilitiesSchema, contract.assets?.capabilityCatalog, contract.assets?.capabilityCatalogSchema, contract.assets?.browserE2eSchema, contract.assets?.evidenceRecordSchema, contract.assets?.evidenceIndexSchema, contract.assets?.commandAliases, contract.assets?.commandAliasesSchema]) {
|
|
44
46
|
if (!asset || !(await exists(resolve(packageRoot, asset)))) problems.push(`missing contract asset ${asset ?? '(empty)'}`);
|
|
45
47
|
}
|
|
46
|
-
for (const asset of ['routes.json', 'gates.json', 'stages.json', 'schemas/routes.schema.json', 'schemas/gates.schema.json', 'schemas/stages.schema.json', 'schemas/control-plane.schema.json', 'schemas/triage.schema.json', 'schemas/stage-result.schema.json', 'schemas/workflow-state.schema.json', 'schemas/decomposition.schema.json', 'schemas/capabilities.schema.json', 'schemas/capability-catalog.schema.json', 'schemas/browser-e2e.schema.json', 'src/browser-e2e.mjs', 'src/capabilities.mjs', 'src/contracts.mjs', 'src/control-plane.mjs', 'src/decompose.mjs', 'src/github.mjs', 'src/memory.mjs', 'src/reconcile.mjs', 'src/routes.mjs', 'src/stacked.mjs', 'src/triage.mjs', 'src/workflow.mjs']) {
|
|
48
|
+
for (const asset of ['routes.json', 'gates.json', 'stages.json', 'command-aliases.json', 'schemas/routes.schema.json', 'schemas/gates.schema.json', 'schemas/stages.schema.json', 'schemas/control-plane.schema.json', 'schemas/triage.schema.json', 'schemas/stage-result.schema.json', 'schemas/workflow-state.schema.json', 'schemas/decomposition.schema.json', 'schemas/capabilities.schema.json', 'schemas/capability-catalog.schema.json', 'schemas/browser-e2e.schema.json', 'schemas/evidence-record.schema.json', 'schemas/evidence-index.schema.json', 'schemas/command-aliases.schema.json', 'src/aliases.mjs', 'src/browser-e2e.mjs', 'src/evidence.mjs', 'src/capabilities.mjs', 'src/contracts.mjs', 'src/control-plane.mjs', 'src/decompose.mjs', 'src/github.mjs', 'src/memory.mjs', 'src/reconcile.mjs', 'src/routes.mjs', 'src/stacked.mjs', 'src/triage.mjs', 'src/workflow.mjs']) {
|
|
47
49
|
if (!(await exists(resolve(packageRoot, asset)))) problems.push(`missing package asset ${asset}`);
|
|
48
50
|
}
|
|
49
51
|
try {
|
|
@@ -65,11 +67,30 @@ async function verifyContract() {
|
|
|
65
67
|
const catalog = await readCapabilityCatalog();
|
|
66
68
|
problems.push(...validateCapabilityCatalog(catalog).map((error) => `${error.code}: ${error.message}`));
|
|
67
69
|
} catch (error) { problems.push(`Cannot read capabilities.json: ${error.message}`); }
|
|
70
|
+
try {
|
|
71
|
+
const aliases = await readCommandAliases();
|
|
72
|
+
problems.push(...(await verifyCommandAliases(aliases)).map((error) => `${error.code}: ${error.message}`));
|
|
73
|
+
} catch (error) { problems.push(`Cannot read command-aliases.json: ${error.message}`); }
|
|
68
74
|
for (const command of ['status', ...expectedStages, ...(contract.utilities ?? []).filter((command) => command !== 'status')]) if (!(await exists(resolve(packageRoot, `commands/${command}.md`)))) problems.push(`missing command asset ${command}`);
|
|
69
75
|
for (const metaCommand of contract.metaCommands ?? []) if (!(await exists(resolve(packageRoot, `meta-commands/${metaCommand}.md`)))) problems.push(`missing meta-command asset ${metaCommand}`);
|
|
70
76
|
return problems;
|
|
71
77
|
}
|
|
72
78
|
|
|
79
|
+
async function runAliases(args) {
|
|
80
|
+
const format = option(args, '--format') ?? 'json';
|
|
81
|
+
if (!['json', 'text'].includes(format)) { console.error('Usage: lighthouse-sdlc aliases [--format <json|text>]'); process.exit(2); }
|
|
82
|
+
const contract = await readCommandAliases();
|
|
83
|
+
const errors = await verifyCommandAliases(contract);
|
|
84
|
+
const result = { schemaVersion: 1, status: errors.length ? 'invalid' : 'valid', valid: errors.length === 0, package: contract.package, contractVersion: contract.contractVersion, canonicalNamespace: contract.canonicalNamespace, aliasNamespace: contract.aliasNamespace, aliases: contract.aliases, errors };
|
|
85
|
+
if (format === 'json') console.log(JSON.stringify(result, null, 2));
|
|
86
|
+
else {
|
|
87
|
+
console.log(`SDLC command aliases: ${result.status}`);
|
|
88
|
+
for (const alias of result.aliases) console.log(` ${alias.alias} -> ${alias.canonical}`);
|
|
89
|
+
for (const error of result.errors) console.error(` ${error.code}: ${error.message}`);
|
|
90
|
+
}
|
|
91
|
+
if (errors.length) process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
|
|
73
94
|
function option(args, name) {
|
|
74
95
|
const index = args.indexOf(name);
|
|
75
96
|
if (index !== -1) return args[index + 1];
|
|
@@ -170,6 +191,44 @@ async function runBrowserE2e(args) {
|
|
|
170
191
|
if (!report.valid || report.status !== 'passed') process.exit(1);
|
|
171
192
|
}
|
|
172
193
|
|
|
194
|
+
async function runEvidence(args) {
|
|
195
|
+
const inputPath = option(args, '--input');
|
|
196
|
+
const outputPath = option(args, '--output');
|
|
197
|
+
const format = option(args, '--format') ?? 'json';
|
|
198
|
+
const build = args.includes('--build');
|
|
199
|
+
if (!inputPath || !['json', 'text'].includes(format) || (build && !outputPath)) {
|
|
200
|
+
console.error('Usage: lighthouse-sdlc evidence --input <record|index|records.json> [--build --output <index.json>] [--format <json|text>]');
|
|
201
|
+
process.exit(2);
|
|
202
|
+
}
|
|
203
|
+
const input = await readJson(resolve(process.cwd(), inputPath));
|
|
204
|
+
let report;
|
|
205
|
+
if (build) {
|
|
206
|
+
const result = buildEvidenceIndex(input.records, input);
|
|
207
|
+
report = { schemaVersion: 1, status: result.errors.length ? 'invalid' : 'valid', valid: result.errors.length === 0, index: result.index, errors: result.errors };
|
|
208
|
+
if (result.index) {
|
|
209
|
+
const output = resolve(process.cwd(), outputPath);
|
|
210
|
+
await mkdir(dirname(output), { recursive: true });
|
|
211
|
+
for (const reference of result.index.records) {
|
|
212
|
+
const record = input.records.find((item) => item.id === reference.id);
|
|
213
|
+
const recordPath = resolve(dirname(output), reference.path);
|
|
214
|
+
await mkdir(dirname(recordPath), { recursive: true });
|
|
215
|
+
await writeFile(recordPath, `${JSON.stringify(record, null, 2)}\n`);
|
|
216
|
+
}
|
|
217
|
+
await writeFile(output, `${JSON.stringify(result.index, null, 2)}\n`);
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
const errors = input?.kind ? validateEvidenceRecord(input) : validateEvidenceIndex(input);
|
|
221
|
+
report = { ...evidenceReport(input), errors };
|
|
222
|
+
}
|
|
223
|
+
if (format === 'json') output(report, format);
|
|
224
|
+
else {
|
|
225
|
+
console.log(`Evidence: ${report.status}`);
|
|
226
|
+
for (const error of report.errors) console.error(` ${error.code}: ${error.message}`);
|
|
227
|
+
if (report.index) console.log(` Coverage entries: ${report.index.coverage.length}`);
|
|
228
|
+
}
|
|
229
|
+
if (!report.valid) process.exit(1);
|
|
230
|
+
}
|
|
231
|
+
|
|
173
232
|
async function runMemory(args) {
|
|
174
233
|
const inputPath = option(args, '--input');
|
|
175
234
|
const policyPath = option(args, '--policy');
|
|
@@ -328,14 +387,16 @@ async function runGithubLabels(args) {
|
|
|
328
387
|
}
|
|
329
388
|
|
|
330
389
|
const command = process.argv[2] ?? 'verify';
|
|
331
|
-
if (!['contract', 'verify', 'triage', 'state', 'stage-result', 'browser-e2e', 'control-plane', 'memory', 'launch', 'decompose', 'stacked', 'route', 'github-triage', 'github-decompose', 'reconcile-labels', 'github-labels'].includes(command)) {
|
|
332
|
-
console.error('Usage: lighthouse-sdlc <contract|verify|triage|state|stage-result|browser-e2e|control-plane|memory|launch|decompose|stacked|route|github-triage|github-decompose|reconcile-labels|github-labels>');
|
|
390
|
+
if (!['contract', 'verify', 'aliases', 'triage', 'state', 'stage-result', 'browser-e2e', 'evidence', 'control-plane', 'memory', 'launch', 'decompose', 'stacked', 'route', 'github-triage', 'github-decompose', 'reconcile-labels', 'github-labels'].includes(command)) {
|
|
391
|
+
console.error('Usage: lighthouse-sdlc <contract|verify|aliases|triage|state|stage-result|browser-e2e|evidence|control-plane|memory|launch|decompose|stacked|route|github-triage|github-decompose|reconcile-labels|github-labels>');
|
|
333
392
|
process.exit(2);
|
|
334
393
|
}
|
|
335
394
|
if (command === 'contract') {
|
|
336
395
|
console.log(await readFile(contractPath, 'utf8'));
|
|
337
396
|
} else if (command === 'triage') {
|
|
338
397
|
await runTriage(process.argv.slice(3));
|
|
398
|
+
} else if (command === 'aliases') {
|
|
399
|
+
await runAliases(process.argv.slice(3));
|
|
339
400
|
} else if (command === 'state') {
|
|
340
401
|
await runState(process.argv.slice(3));
|
|
341
402
|
} else if (command === 'control-plane') {
|
|
@@ -344,6 +405,8 @@ if (command === 'contract') {
|
|
|
344
405
|
await runStageResult(process.argv.slice(3));
|
|
345
406
|
} else if (command === 'browser-e2e') {
|
|
346
407
|
await runBrowserE2e(process.argv.slice(3));
|
|
408
|
+
} else if (command === 'evidence') {
|
|
409
|
+
await runEvidence(process.argv.slice(3));
|
|
347
410
|
} else if (command === 'memory') {
|
|
348
411
|
await runMemory(process.argv.slice(3));
|
|
349
412
|
} else if (command === 'launch') {
|
|
@@ -371,4 +434,4 @@ if (command === 'contract') {
|
|
|
371
434
|
console.log('Lighthouse SDLC package contract is valid.');
|
|
372
435
|
}
|
|
373
436
|
|
|
374
|
-
export { contractPath, runTriage, verifyContract, runState, runStageResult, runBrowserE2e, runControlPlane, runMemory, runLaunch, runDecompose, runRoute, runStacked, runGithubTriage, runGithubDecompose, runReconcileLabels, runGithubLabels };
|
|
437
|
+
export { contractPath, runTriage, verifyContract, runAliases, runState, runStageResult, runBrowserE2e, runEvidence, runControlPlane, runMemory, runLaunch, runDecompose, runRoute, runStacked, runGithubTriage, runGithubDecompose, runReconcileLabels, runGithubLabels };
|