@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/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 };