@juangcarmona/lighthouse 0.10.0 → 0.11.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 +2 -0
- package/package.json +2 -2
- package/src/create-dotnet.mjs +1 -27
- package/src/lighthouse.mjs +17 -33
package/README.md
CHANGED
|
@@ -16,6 +16,8 @@ Use `lighthouse reconcile` to preview missing Lighthouse-managed paths in an exi
|
|
|
16
16
|
|
|
17
17
|
Use `lighthouse upgrade` to preview a versioned foundation update. The command is dry-run by default, accepts `--scope harness`, `--scope sdlc` or `--scope all`, preserves customized projections and stops when ownership evidence is missing. Add `--apply` only after reviewing the plan, then run `lighthouse verify`.
|
|
18
18
|
|
|
19
|
+
Agent workflows are opt-in through the SDLC package installer. Initialization does not create an entire worker catalog. Upgrading an older adoption releases workflow ownership while preserving the existing files for explicit review and cleanup.
|
|
20
|
+
|
|
19
21
|
The harness package owns the baseline command and verification contract. The SDLC package owns lifecycle skills, commands, metacommands, routes and gates, and `lighthouse init` records its selected version in `.lighthouse/sdlc.json`. The UI package owns visual tokens, native recipes, `DESIGN.md` and its agent skill. Selecting `visual-theme` projects the guide and skill into the adopter and enables its deterministic guardrail. Stack profiles own their source templates, guidance and checks; the .NET creator is the packaged entry point for the selected backend profile.
|
|
20
22
|
|
|
21
23
|
ProductShape, ArcShape and OpenSpec keep their own files and commands. Add them through their supported integration routes when the project needs them, and keep their versions and managed paths visible in the project configuration. In an existing repository, run `lighthouse authorities --adopt-existing` to validate the current ProductShape and ArcShape surfaces without running either initializer; review the dry-run plan and add `--apply` only to record both exact versions in Lighthouse-owned configuration.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juangcarmona/lighthouse",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Lighthouse adoption and verification CLI",
|
|
6
6
|
"repository": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"@arcshape/cli": "0.1.6",
|
|
24
24
|
"@juangcarmona/lighthouse-ui": "0.2.0",
|
|
25
25
|
"@prodshape/cli": "0.23.0",
|
|
26
|
-
"@juangcarmona/lighthouse-sdlc": "0.
|
|
26
|
+
"@juangcarmona/lighthouse-sdlc": "0.12.0"
|
|
27
27
|
},
|
|
28
28
|
"files": [
|
|
29
29
|
"src/lighthouse.mjs",
|
package/src/create-dotnet.mjs
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { lstat, mkdir, mkdtemp, readFile, readdir, rename, rm, rmdir, writeFile } from 'node:fs/promises';
|
|
3
|
-
import { createHash } from 'node:crypto';
|
|
4
3
|
import { dirname, join, resolve } from 'node:path';
|
|
5
4
|
import { fileURLToPath } from 'node:url';
|
|
6
5
|
import { createRequire } from 'node:module';
|
|
@@ -10,23 +9,6 @@ const templateRoot = resolve(packageRoot, 'assets/dotnet-template');
|
|
|
10
9
|
const cliPackage = JSON.parse(await readFile(resolve(packageRoot, 'package.json'), 'utf8'));
|
|
11
10
|
const require = createRequire(import.meta.url);
|
|
12
11
|
const sdlcContract = JSON.parse(await readFile(require.resolve('@juangcarmona/lighthouse-sdlc/contract.json'), 'utf8'));
|
|
13
|
-
const sdlcPackageRoot = dirname(require.resolve('@juangcarmona/lighthouse-sdlc/contract.json'));
|
|
14
|
-
const sdlcWorkflowPaths = [
|
|
15
|
-
'.github/workflows/lighthouse-sdlc-router.yml',
|
|
16
|
-
'.github/workflows/lighthouse-sdlc-triage.md',
|
|
17
|
-
'.github/workflows/lighthouse-sdlc-triage.lock.yml',
|
|
18
|
-
'.github/workflows/lighthouse-sdlc-refine.md',
|
|
19
|
-
'.github/workflows/lighthouse-sdlc-refine.lock.yml',
|
|
20
|
-
'.github/workflows/lighthouse-sdlc-propose.md',
|
|
21
|
-
'.github/workflows/lighthouse-sdlc-propose.lock.yml',
|
|
22
|
-
'.github/workflows/lighthouse-sdlc-implement.md',
|
|
23
|
-
'.github/workflows/lighthouse-sdlc-implement.lock.yml',
|
|
24
|
-
'.github/workflows/lighthouse-sdlc-integrate.md',
|
|
25
|
-
'.github/workflows/lighthouse-sdlc-integrate.lock.yml',
|
|
26
|
-
'.github/workflows/lighthouse-sdlc-review.md',
|
|
27
|
-
'.github/workflows/lighthouse-sdlc-review.lock.yml',
|
|
28
|
-
'.github/workflows/shared/lighthouse-sdlc-stage.md',
|
|
29
|
-
];
|
|
30
12
|
const args = process.argv.slice(2);
|
|
31
13
|
const target = args[0] ? resolve(args[0]) : null;
|
|
32
14
|
const name = args.includes('--name') ? args[args.indexOf('--name') + 1] : null;
|
|
@@ -109,7 +91,7 @@ try {
|
|
|
109
91
|
product: name, application: { shape: 'backend', stacks: ['dotnet'] }, profiles: ['dotnet-backend'],
|
|
110
92
|
integrations: { productShape: null, arcShape: null },
|
|
111
93
|
packages: { sdlc: { name: '@juangcarmona/lighthouse-sdlc', version: sdlcContract.version } },
|
|
112
|
-
managed: ['LIGHTHOUSE.md', 'scripts/lighthouse-guard.mjs', '.husky/commit-msg', '.husky/pre-push', '.github/workflows/lighthouse.yml', '.lighthouse/sdlc.json',
|
|
94
|
+
managed: ['LIGHTHOUSE.md', 'scripts/lighthouse-guard.mjs', '.husky/commit-msg', '.husky/pre-push', '.github/workflows/lighthouse.yml', '.lighthouse/sdlc.json', '.agents/skills/lighthouse-init/SKILL.md', '.lighthouse/upgrade.json', '.lighthouse/commands.json', 'docs/profiles/dotnet/README.md', 'docs/profiles/dotnet/adoption.md', 'docs/profiles/dotnet/architecture.md', 'docs/profiles/dotnet/guardrails.md', 'docs/profiles/dotnet/practices.md', 'docs/profiles/dotnet/testing-and-development.md', 'docs/profiles/dotnet/use-cases.md', '.agents/skills/lighthouse-dotnet/SKILL.md'],
|
|
113
95
|
repository: {
|
|
114
96
|
layout: ['src', 'docs', 'infra', 'scripts'], publicSite: { enabled: true },
|
|
115
97
|
conventions: { commits: 'conventional', branchPattern: '^(feat|fix|docs|refactor|test|chore|build|ci|perf|revert)/[1-9]\\d*-[a-z0-9]+(?:-[a-z0-9]+)*$' },
|
|
@@ -126,14 +108,6 @@ try {
|
|
|
126
108
|
|
|
127
109
|
const initialized = (await import('node:child_process')).spawnSync(process.execPath, [resolve(stage, 'scripts/lighthouse.mjs'), 'init'], { cwd: stage, encoding: 'utf8' });
|
|
128
110
|
if (initialized.status !== 0) throw new Error(initialized.stderr || 'Projection generation failed.');
|
|
129
|
-
await copy(resolve(sdlcPackageRoot, 'workflows'), resolve(stage, '.github/workflows'));
|
|
130
|
-
const upgradePath = resolve(stage, '.lighthouse/upgrade.json');
|
|
131
|
-
const upgrade = JSON.parse(await readFile(upgradePath, 'utf8'));
|
|
132
|
-
for (const path of sdlcWorkflowPaths) {
|
|
133
|
-
const content = await readFile(resolve(stage, path), 'utf8');
|
|
134
|
-
upgrade.files[path] = { hash: createHash('sha256').update(content).digest('hex'), scope: 'sdlc' };
|
|
135
|
-
}
|
|
136
|
-
await writeFile(upgradePath, `${JSON.stringify(upgrade, null, 2)}\n`);
|
|
137
111
|
if (existing) await rmdir(target);
|
|
138
112
|
await rename(stage, target);
|
|
139
113
|
process.stdout.write(`Created ${name} in ${target}. Run dotnet restore ${name}.slnx, then npm run verify.\n`);
|
package/src/lighthouse.mjs
CHANGED
|
@@ -41,22 +41,6 @@ const upgradeStatePath = resolve(root, upgradeStateRelative);
|
|
|
41
41
|
const layout = ['src', 'docs', 'infra', 'scripts'];
|
|
42
42
|
const sdlcPackage = { name: '@juangcarmona/lighthouse-sdlc', version: installedPackageVersion('@juangcarmona/lighthouse-sdlc', 'contract.json') ?? '0.1.0' };
|
|
43
43
|
const uiPackage = { name: '@juangcarmona/lighthouse-ui', version: installedPackageVersion('@juangcarmona/lighthouse-ui', 'DESIGN.md') ?? '0.1.0' };
|
|
44
|
-
const sdlcWorkflowPaths = Object.freeze([
|
|
45
|
-
'.github/workflows/lighthouse-sdlc-router.yml',
|
|
46
|
-
'.github/workflows/lighthouse-sdlc-triage.md',
|
|
47
|
-
'.github/workflows/lighthouse-sdlc-triage.lock.yml',
|
|
48
|
-
'.github/workflows/lighthouse-sdlc-refine.md',
|
|
49
|
-
'.github/workflows/lighthouse-sdlc-refine.lock.yml',
|
|
50
|
-
'.github/workflows/lighthouse-sdlc-propose.md',
|
|
51
|
-
'.github/workflows/lighthouse-sdlc-propose.lock.yml',
|
|
52
|
-
'.github/workflows/lighthouse-sdlc-implement.md',
|
|
53
|
-
'.github/workflows/lighthouse-sdlc-implement.lock.yml',
|
|
54
|
-
'.github/workflows/lighthouse-sdlc-integrate.md',
|
|
55
|
-
'.github/workflows/lighthouse-sdlc-integrate.lock.yml',
|
|
56
|
-
'.github/workflows/lighthouse-sdlc-review.md',
|
|
57
|
-
'.github/workflows/lighthouse-sdlc-review.lock.yml',
|
|
58
|
-
'.github/workflows/shared/lighthouse-sdlc-stage.md',
|
|
59
|
-
]);
|
|
60
44
|
const managedPaths = [
|
|
61
45
|
projection,
|
|
62
46
|
'scripts/lighthouse-guard.mjs',
|
|
@@ -64,7 +48,6 @@ const managedPaths = [
|
|
|
64
48
|
'.husky/pre-push',
|
|
65
49
|
'.github/workflows/lighthouse.yml',
|
|
66
50
|
'.lighthouse/sdlc.json',
|
|
67
|
-
...sdlcWorkflowPaths,
|
|
68
51
|
'.agents/skills/lighthouse-init/SKILL.md',
|
|
69
52
|
upgradeStateRelative,
|
|
70
53
|
'.lighthouse/commands.json',
|
|
@@ -102,7 +85,7 @@ function managedPathsFor(manifest) {
|
|
|
102
85
|
function upgradeScopesFor(manifest) {
|
|
103
86
|
return {
|
|
104
87
|
harness: [projection, 'scripts/lighthouse-guard.mjs', '.husky/commit-msg', '.husky/pre-push', '.github/workflows/lighthouse.yml', '.agents/skills/lighthouse-init/SKILL.md', ...((manifest?.profiles ?? []).flatMap((profile) => profileManagedPaths[profile] ?? []))],
|
|
105
|
-
sdlc: ['.lighthouse/sdlc.json', '.lighthouse/commands.json'
|
|
88
|
+
sdlc: ['.lighthouse/sdlc.json', '.lighthouse/commands.json'],
|
|
106
89
|
};
|
|
107
90
|
}
|
|
108
91
|
|
|
@@ -111,18 +94,6 @@ function packageAsset(packageName, entry) {
|
|
|
111
94
|
return readFileSync(path, 'utf8');
|
|
112
95
|
}
|
|
113
96
|
|
|
114
|
-
function sdlcWorkflowFiles() {
|
|
115
|
-
const files = {};
|
|
116
|
-
for (const target of sdlcWorkflowPaths) {
|
|
117
|
-
try {
|
|
118
|
-
files[target] = packageAsset('@juangcarmona/lighthouse-sdlc', `workflows/${target.slice('.github/workflows/'.length)}`);
|
|
119
|
-
} catch {
|
|
120
|
-
return {};
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return files;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
97
|
function profileAssets(manifest) {
|
|
127
98
|
const assets = {};
|
|
128
99
|
if ((manifest?.profiles ?? []).includes('visual-theme')) {
|
|
@@ -457,7 +428,6 @@ function managedFiles(manifest) {
|
|
|
457
428
|
'.agents/skills/lighthouse-init/SKILL.md': readFileSync(new URL('../assets/skills/init/SKILL.md', import.meta.url), 'utf8'),
|
|
458
429
|
};
|
|
459
430
|
Object.assign(files, profileAssets(manifest));
|
|
460
|
-
Object.assign(files, sdlcWorkflowFiles());
|
|
461
431
|
const controlPlane = sdlcControlPlane(manifest);
|
|
462
432
|
if (controlPlane) files['.lighthouse/sdlc.json'] = controlPlane;
|
|
463
433
|
files['.lighthouse/commands.json'] = commandAliasProjectionText(commandAliasesProjection());
|
|
@@ -542,6 +512,10 @@ function classifyUpgradeFile(path, current, expected, recordedHash) {
|
|
|
542
512
|
return { classification: 'conflicting', action: 'review', reason: 'ownership is not recorded for this path' };
|
|
543
513
|
}
|
|
544
514
|
|
|
515
|
+
function isOptionalWorkflow(path) {
|
|
516
|
+
return /^\.github\/workflows\/lighthouse-sdlc-(router\.yml|(?:triage|refine|propose|implement|integrate|review)\.(?:md|lock\.yml))$/.test(path) || path === '.github/workflows/shared/lighthouse-sdlc-stage.md';
|
|
517
|
+
}
|
|
518
|
+
|
|
545
519
|
async function planUpgrade(manifest, scopes) {
|
|
546
520
|
const state = await readUpgradeState();
|
|
547
521
|
const problems = stateProblems(state);
|
|
@@ -557,6 +531,9 @@ async function planUpgrade(manifest, scopes) {
|
|
|
557
531
|
const result = classifyUpgradeFile(path, current, expected, recordedHash);
|
|
558
532
|
changes.push({ path, scope: Object.entries(upgradeScopes).find(([, values]) => values.includes(path))?.[0], ...result });
|
|
559
533
|
}
|
|
534
|
+
if (scopes.has('sdlc') && manifest.managed.some(isOptionalWorkflow)) {
|
|
535
|
+
changes.push({ path: 'lighthouse.json', scope: 'sdlc', classification: 'adoptable', action: 'update', reason: 'release optional workflow ownership; preserve all workflow files' });
|
|
536
|
+
}
|
|
560
537
|
if (state?.baseline && state.baseline !== manifest.baseline) {
|
|
561
538
|
changes.unshift({ path: 'baseline', scope: 'harness', classification: 'breaking', action: 'review', reason: `baseline ${state.baseline} is not compatible with ${manifest.baseline}` });
|
|
562
539
|
}
|
|
@@ -688,7 +665,11 @@ function validate(manifest) {
|
|
|
688
665
|
const preSemanticWithoutUpgrade = Array.isArray(manifest.managed)
|
|
689
666
|
&& manifest.managed.length === preSemanticWithoutUpgradePaths.length
|
|
690
667
|
&& manifest.managed.every((entry, index) => entry === preSemanticWithoutUpgradePaths[index]);
|
|
691
|
-
|
|
668
|
+
// Earlier foundations installed every workflow. Accept that ownership inventory during upgrade;
|
|
669
|
+
// the foundation now leaves those files to explicit workflow adoption and never deletes them.
|
|
670
|
+
const withoutOldWorkflows = Array.isArray(manifest.managed) ? manifest.managed.filter(path => !isOptionalWorkflow(path)) : [];
|
|
671
|
+
const previousWorkflowManaged = withoutOldWorkflows.length === expectedManagedPaths.length && withoutOldWorkflows.every((path, index) => path === expectedManagedPaths[index]);
|
|
672
|
+
if (!previousWorkflowManaged && !legacyManaged && !profilelessManaged && !previousCompleteManaged && !completeManaged && !preSemanticManaged && !preSemanticWithoutUpgrade) {
|
|
692
673
|
problems.push(`managed must be ${legacyManagedPaths.join(', ')}, the previous Lighthouse guardrail set or the selected profile set`);
|
|
693
674
|
}
|
|
694
675
|
if ('repository' in manifest) {
|
|
@@ -990,7 +971,10 @@ async function applyUpgrade(manifest, plan) {
|
|
|
990
971
|
for (const change of updates) {
|
|
991
972
|
const target = resolve(root, change.path);
|
|
992
973
|
await mkdir(dirname(target), { recursive: true });
|
|
993
|
-
|
|
974
|
+
const content = change.path === 'lighthouse.json'
|
|
975
|
+
? `${JSON.stringify({ ...manifest, managed: manifest.managed.filter(path => !isOptionalWorkflow(path)) }, null, 2)}\n`
|
|
976
|
+
: files[change.path];
|
|
977
|
+
await writeTextAtomically(target, content);
|
|
994
978
|
}
|
|
995
979
|
const next = upgradeState(manifest, files, { ...previous, lastAppliedMigration: `upgrade-${cliPackage.version}` });
|
|
996
980
|
for (const path of Object.keys(next.files)) {
|