@cubis/foundry 0.3.79 → 0.3.81
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/cli/build/commands.js +1 -1
- package/dist/cli/build/commands.js.map +1 -1
- package/dist/cli/core.js +324 -149
- package/dist/cli/core.js.map +1 -1
- package/package.json +1 -1
- package/src/cli/build/commands.ts +1 -1
- package/src/cli/core.ts +368 -194
- package/workflows/workflows/agent-environment-setup/generated/route-manifest.json +2 -2
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/accessibility.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/architecture.toml +2 -2
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/backend.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/create.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/database.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/debug.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/devops.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/implement-track.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/migrate.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/mobile.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/onboard.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/orchestrate.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/plan.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/refactor.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/release.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/review.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/security.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/spec.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/test.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/vercel.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/workflows/architecture.md +22 -19
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/workflows/spec.md +2 -2
- package/workflows/workflows/agent-environment-setup/platforms/claude/workflows/architecture.md +22 -19
- package/workflows/workflows/agent-environment-setup/platforms/claude/workflows/spec.md +2 -2
- package/workflows/workflows/agent-environment-setup/platforms/codex/workflows/architecture.md +22 -19
- package/workflows/workflows/agent-environment-setup/platforms/codex/workflows/spec.md +2 -2
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-accessibility.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-architecture.prompt.md +2 -2
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-backend.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-create.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-database.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-debug.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-devops.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-implement-track.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-migrate.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-mobile.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-onboard.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-orchestrate.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-plan.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-refactor.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-release.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-review.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-security.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-spec.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-test.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-vercel.prompt.md +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/copilot/workflows/architecture.md +22 -19
- package/workflows/workflows/agent-environment-setup/platforms/copilot/workflows/spec.md +2 -2
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/accessibility.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/architecture.toml +2 -2
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/backend.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/create.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/database.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/debug.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/devops.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/implement-track.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/migrate.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/mobile.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/onboard.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/orchestrate.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/plan.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/refactor.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/release.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/review.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/security.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/spec.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/test.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/vercel.toml +1 -1
- package/workflows/workflows/agent-environment-setup/platforms/gemini/workflows/architecture.md +22 -19
- package/workflows/workflows/agent-environment-setup/platforms/gemini/workflows/spec.md +2 -2
- package/workflows/workflows/agent-environment-setup/shared/workflows/architecture.md +22 -19
- package/workflows/workflows/agent-environment-setup/shared/workflows/spec.md +2 -2
package/dist/cli/core.js
CHANGED
|
@@ -35,6 +35,8 @@ const TECH_ARCHITECTURE_BLOCK_START_RE = /<!--\s*cbx:architecture:tech:start[^>]
|
|
|
35
35
|
const TECH_ARCHITECTURE_BLOCK_END_RE = /<!--\s*cbx:architecture:tech:end\s*-->/g;
|
|
36
36
|
const ROADMAP_FOUNDATION_BLOCK_START_RE = /<!--\s*cbx:roadmap:foundation:start[^>]*-->/g;
|
|
37
37
|
const ROADMAP_FOUNDATION_BLOCK_END_RE = /<!--\s*cbx:roadmap:foundation:end\s*-->/g;
|
|
38
|
+
const FOUNDATION_DOCS_DIR = path.join("docs", "foundation");
|
|
39
|
+
const FOUNDATION_ADR_DIR = path.join(FOUNDATION_DOCS_DIR, "adr");
|
|
38
40
|
const COPILOT_ALLOWED_SKILL_FRONTMATTER_KEYS = new Set([
|
|
39
41
|
"compatibility",
|
|
40
42
|
"description",
|
|
@@ -1127,7 +1129,7 @@ function buildEngineeringArchitectureSection(snapshot) {
|
|
|
1127
1129
|
...profile.testingStrategy.map((rule) => ` - ${rule}`),
|
|
1128
1130
|
"- Doc refresh policy:",
|
|
1129
1131
|
" - Update these managed sections when architecture, scale, boundaries, design-system rules, or testing strategy changes.",
|
|
1130
|
-
|
|
1132
|
+
` - For non-trivial work, read ${FOUNDATION_DOCS_DIR}/PRODUCT.md, ENGINEERING_RULES.md, ${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md, and ${FOUNDATION_DOCS_DIR}/TECH.md in that order when they exist.`,
|
|
1131
1133
|
"<!-- cbx:architecture:rules:end -->",
|
|
1132
1134
|
"",
|
|
1133
1135
|
].join("\n");
|
|
@@ -1239,7 +1241,7 @@ function buildRoadmapFoundationSection(snapshot, specRoots = []) {
|
|
|
1239
1241
|
"- Use this section for medium-term scaling themes, major migrations, or cross-team architecture investments.",
|
|
1240
1242
|
"",
|
|
1241
1243
|
"### Backbone Maintenance",
|
|
1242
|
-
|
|
1244
|
+
`- Keep ${FOUNDATION_DOCS_DIR}/PRODUCT.md, ${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md, ENGINEERING_RULES.md, and ${FOUNDATION_DOCS_DIR}/TECH.md aligned when direction or structure changes.`,
|
|
1243
1245
|
"- Link major roadmap themes back to specs and ADRs instead of burying them in chat-only planning.",
|
|
1244
1246
|
"<!-- cbx:roadmap:foundation:end -->",
|
|
1245
1247
|
"",
|
|
@@ -1376,6 +1378,42 @@ function buildRoadmapTemplate(snapshot, specRoots = []) {
|
|
|
1376
1378
|
"",
|
|
1377
1379
|
].join("\n");
|
|
1378
1380
|
}
|
|
1381
|
+
function buildProductBuildSkeleton() {
|
|
1382
|
+
return [
|
|
1383
|
+
"# Product",
|
|
1384
|
+
"",
|
|
1385
|
+
"This file is managed by `cbx build architecture`.",
|
|
1386
|
+
"",
|
|
1387
|
+
"<!-- cbx:product:foundation:start version=1 profile=uninitialized -->",
|
|
1388
|
+
"Replace this managed section by running `cbx build architecture --platform <codex|claude|gemini|copilot>`.",
|
|
1389
|
+
"<!-- cbx:product:foundation:end -->",
|
|
1390
|
+
"",
|
|
1391
|
+
].join("\n");
|
|
1392
|
+
}
|
|
1393
|
+
function buildArchitectureBuildSkeleton() {
|
|
1394
|
+
return [
|
|
1395
|
+
"# Architecture",
|
|
1396
|
+
"",
|
|
1397
|
+
"This file is managed by `cbx build architecture`.",
|
|
1398
|
+
"",
|
|
1399
|
+
"<!-- cbx:architecture:doc:start version=1 profile=uninitialized -->",
|
|
1400
|
+
"Replace this managed section by running `cbx build architecture --platform <codex|claude|gemini|copilot>`.",
|
|
1401
|
+
"<!-- cbx:architecture:doc:end -->",
|
|
1402
|
+
"",
|
|
1403
|
+
].join("\n");
|
|
1404
|
+
}
|
|
1405
|
+
function buildTechBuildSkeleton() {
|
|
1406
|
+
return [
|
|
1407
|
+
"# TECH.md",
|
|
1408
|
+
"",
|
|
1409
|
+
"This file is managed by `cbx build architecture`.",
|
|
1410
|
+
"",
|
|
1411
|
+
"<!-- cbx:architecture:tech:start version=1 snapshot=uninitialized -->",
|
|
1412
|
+
"Replace this managed section by running `cbx build architecture --platform <codex|claude|gemini|copilot>`.",
|
|
1413
|
+
"<!-- cbx:architecture:tech:end -->",
|
|
1414
|
+
"",
|
|
1415
|
+
].join("\n");
|
|
1416
|
+
}
|
|
1379
1417
|
function buildAdrReadme() {
|
|
1380
1418
|
return [
|
|
1381
1419
|
"# Architecture Decision Records",
|
|
@@ -1450,7 +1488,7 @@ function buildEngineeringRulesManagedBlock({ platform, productFilePath, architec
|
|
|
1450
1488
|
"2. Keep architecture simple (KISS) and avoid speculative work (YAGNI).",
|
|
1451
1489
|
"3. Apply SOLID pragmatically to reduce change risk, not add ceremony.",
|
|
1452
1490
|
"4. Use clear naming with focused responsibilities and explicit boundaries.",
|
|
1453
|
-
|
|
1491
|
+
`5. For non-trivial work, read ${FOUNDATION_DOCS_DIR}/PRODUCT.md, ENGINEERING_RULES.md, ${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md, and ${FOUNDATION_DOCS_DIR}/TECH.md in that order when they exist before planning or implementation.`,
|
|
1454
1492
|
"6. Require validation evidence (lint/types/tests) before merge.",
|
|
1455
1493
|
"7. Use Decision Log response style.",
|
|
1456
1494
|
"8. Every Decision Log must include a `Skills Used` section listing skill, workflow, or agent names.",
|
|
@@ -1617,6 +1655,16 @@ async function upsertTaggedSectionInFile({ targetPath, initialContent, block, st
|
|
|
1617
1655
|
nextContent =
|
|
1618
1656
|
trimmed.length > 0 ? `${trimmed}\n\n${block}\n` : `${block}\n`;
|
|
1619
1657
|
}
|
|
1658
|
+
if (!exists) {
|
|
1659
|
+
if (!dryRun) {
|
|
1660
|
+
await mkdir(path.dirname(targetPath), { recursive: true });
|
|
1661
|
+
await writeFile(targetPath, nextContent, "utf8");
|
|
1662
|
+
}
|
|
1663
|
+
return {
|
|
1664
|
+
action: dryRun ? "would-create" : "created",
|
|
1665
|
+
filePath: targetPath,
|
|
1666
|
+
};
|
|
1667
|
+
}
|
|
1620
1668
|
if (nextContent === original) {
|
|
1621
1669
|
return {
|
|
1622
1670
|
action: "unchanged",
|
|
@@ -1638,18 +1686,14 @@ async function upsertTaggedSectionInFile({ targetPath, initialContent, block, st
|
|
|
1638
1686
|
filePath: targetPath,
|
|
1639
1687
|
};
|
|
1640
1688
|
}
|
|
1641
|
-
function buildArchitectureBuildMetadata({ platform, researchMode,
|
|
1689
|
+
function buildArchitectureBuildMetadata({ platform, researchMode, managedDocs, }) {
|
|
1642
1690
|
return {
|
|
1643
|
-
schemaVersion:
|
|
1691
|
+
schemaVersion: 3,
|
|
1644
1692
|
generatedBy: "cbx build architecture",
|
|
1645
1693
|
generatedAt: new Date().toISOString(),
|
|
1646
1694
|
platform,
|
|
1647
1695
|
researchMode,
|
|
1648
|
-
|
|
1649
|
-
architectureDocHash,
|
|
1650
|
-
rulesProfileHash,
|
|
1651
|
-
techSnapshotHash,
|
|
1652
|
-
roadmapProfileHash,
|
|
1696
|
+
managedDocs,
|
|
1653
1697
|
};
|
|
1654
1698
|
}
|
|
1655
1699
|
async function ensureArchitectureDocScaffold({ workspaceRoot, snapshot, specRoots = [], overwrite = false, dryRun = false, }) {
|
|
@@ -1746,6 +1790,78 @@ async function ensureArchitectureDocScaffold({ workspaceRoot, snapshot, specRoot
|
|
|
1746
1790
|
adrTemplateResult,
|
|
1747
1791
|
};
|
|
1748
1792
|
}
|
|
1793
|
+
async function ensureArchitectureBuildScaffold({ workspaceRoot, dryRun = false, }) {
|
|
1794
|
+
const foundationRoot = path.join(workspaceRoot, FOUNDATION_DOCS_DIR);
|
|
1795
|
+
const productPath = path.join(foundationRoot, "PRODUCT.md");
|
|
1796
|
+
const architectureDocPath = path.join(foundationRoot, "ARCHITECTURE.md");
|
|
1797
|
+
const techMdPath = path.join(foundationRoot, "TECH.md");
|
|
1798
|
+
const adrDir = path.join(workspaceRoot, FOUNDATION_ADR_DIR);
|
|
1799
|
+
const adrReadmePath = path.join(adrDir, "README.md");
|
|
1800
|
+
const adrTemplatePath = path.join(adrDir, "0000-template.md");
|
|
1801
|
+
const productResult = await upsertTaggedSectionInFile({
|
|
1802
|
+
targetPath: productPath,
|
|
1803
|
+
initialContent: `${buildProductBuildSkeleton()}\n`,
|
|
1804
|
+
block: [
|
|
1805
|
+
"<!-- cbx:product:foundation:start version=1 profile=uninitialized -->",
|
|
1806
|
+
"Replace this managed section by running `cbx build architecture --platform <codex|claude|gemini|copilot>`.",
|
|
1807
|
+
"<!-- cbx:product:foundation:end -->",
|
|
1808
|
+
"",
|
|
1809
|
+
].join("\n"),
|
|
1810
|
+
startPattern: PRODUCT_FOUNDATION_BLOCK_START_RE,
|
|
1811
|
+
endPattern: PRODUCT_FOUNDATION_BLOCK_END_RE,
|
|
1812
|
+
dryRun,
|
|
1813
|
+
});
|
|
1814
|
+
const architectureDocResult = await upsertTaggedSectionInFile({
|
|
1815
|
+
targetPath: architectureDocPath,
|
|
1816
|
+
initialContent: `${buildArchitectureBuildSkeleton()}\n`,
|
|
1817
|
+
block: [
|
|
1818
|
+
"<!-- cbx:architecture:doc:start version=1 profile=uninitialized -->",
|
|
1819
|
+
"Replace this managed section by running `cbx build architecture --platform <codex|claude|gemini|copilot>`.",
|
|
1820
|
+
"<!-- cbx:architecture:doc:end -->",
|
|
1821
|
+
"",
|
|
1822
|
+
].join("\n"),
|
|
1823
|
+
startPattern: ARCHITECTURE_DOC_BLOCK_START_RE,
|
|
1824
|
+
endPattern: ARCHITECTURE_DOC_BLOCK_END_RE,
|
|
1825
|
+
dryRun,
|
|
1826
|
+
});
|
|
1827
|
+
const techResult = await upsertTaggedSectionInFile({
|
|
1828
|
+
targetPath: techMdPath,
|
|
1829
|
+
initialContent: `${buildTechBuildSkeleton()}\n`,
|
|
1830
|
+
block: [
|
|
1831
|
+
"<!-- cbx:architecture:tech:start version=1 snapshot=uninitialized -->",
|
|
1832
|
+
"Replace this managed section by running `cbx build architecture --platform <codex|claude|gemini|copilot>`.",
|
|
1833
|
+
"<!-- cbx:architecture:tech:end -->",
|
|
1834
|
+
"",
|
|
1835
|
+
].join("\n"),
|
|
1836
|
+
startPattern: TECH_ARCHITECTURE_BLOCK_START_RE,
|
|
1837
|
+
endPattern: TECH_ARCHITECTURE_BLOCK_END_RE,
|
|
1838
|
+
dryRun,
|
|
1839
|
+
});
|
|
1840
|
+
const adrReadmeResult = await writeTextFile({
|
|
1841
|
+
targetPath: adrReadmePath,
|
|
1842
|
+
content: `${buildAdrReadme()}\n`,
|
|
1843
|
+
overwrite: false,
|
|
1844
|
+
dryRun,
|
|
1845
|
+
});
|
|
1846
|
+
const adrTemplateResult = await writeTextFile({
|
|
1847
|
+
targetPath: adrTemplatePath,
|
|
1848
|
+
content: `${buildAdrTemplate()}\n`,
|
|
1849
|
+
overwrite: false,
|
|
1850
|
+
dryRun,
|
|
1851
|
+
});
|
|
1852
|
+
return {
|
|
1853
|
+
productPath,
|
|
1854
|
+
architectureDocPath,
|
|
1855
|
+
techMdPath,
|
|
1856
|
+
adrReadmePath,
|
|
1857
|
+
adrTemplatePath,
|
|
1858
|
+
productResult,
|
|
1859
|
+
architectureDocResult,
|
|
1860
|
+
techResult,
|
|
1861
|
+
adrReadmeResult,
|
|
1862
|
+
adrTemplateResult,
|
|
1863
|
+
};
|
|
1864
|
+
}
|
|
1749
1865
|
function normalizeTechPackageName(value) {
|
|
1750
1866
|
if (value === undefined || value === null)
|
|
1751
1867
|
return null;
|
|
@@ -10248,7 +10364,7 @@ function printInstallEngineeringSummary({ engineeringResults, techResult }) {
|
|
|
10248
10364
|
function printInstallDocumentationNotice() {
|
|
10249
10365
|
console.log("\nProject backbone docs:");
|
|
10250
10366
|
console.log("- Install only wires the rule references and workflow assets.");
|
|
10251
|
-
console.log(
|
|
10367
|
+
console.log(`- Use \`cbx rules init\` to scaffold ENGINEERING_RULES.md and TECH.md, or \`cbx build architecture --platform <codex|claude|gemini|copilot>\` to generate ${FOUNDATION_DOCS_DIR}/PRODUCT.md, ${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md, ${FOUNDATION_DOCS_DIR}/TECH.md, and ADR scaffolds.`);
|
|
10252
10368
|
}
|
|
10253
10369
|
async function upsertEngineeringArtifacts({ platform, scope, overwrite = false, skipTech = false, dryRun = false, cwd = process.cwd(), }) {
|
|
10254
10370
|
const ruleFilePath = await resolveRuleFilePath(platform, scope, cwd);
|
|
@@ -10399,6 +10515,61 @@ async function listSpecPackRoots(workspaceRoot) {
|
|
|
10399
10515
|
.sort((a, b) => a.localeCompare(b))
|
|
10400
10516
|
.slice(0, 8);
|
|
10401
10517
|
}
|
|
10518
|
+
async function resolveArchitectureInspectionAnchors(workspaceRoot, snapshot, specRoots) {
|
|
10519
|
+
const seen = new Set();
|
|
10520
|
+
const ordered = [];
|
|
10521
|
+
const pushCandidate = async (relativePath) => {
|
|
10522
|
+
const normalized = toPosixPath(relativePath);
|
|
10523
|
+
if (!normalized || seen.has(normalized))
|
|
10524
|
+
return;
|
|
10525
|
+
if (!(await pathExists(path.join(workspaceRoot, relativePath))))
|
|
10526
|
+
return;
|
|
10527
|
+
seen.add(normalized);
|
|
10528
|
+
ordered.push(normalized);
|
|
10529
|
+
};
|
|
10530
|
+
for (const candidate of [
|
|
10531
|
+
"README.md",
|
|
10532
|
+
"package.json",
|
|
10533
|
+
"pubspec.yaml",
|
|
10534
|
+
"go.mod",
|
|
10535
|
+
"pyproject.toml",
|
|
10536
|
+
"Cargo.toml",
|
|
10537
|
+
"Dockerfile",
|
|
10538
|
+
"docker-compose.yml",
|
|
10539
|
+
"docker-compose.yaml",
|
|
10540
|
+
"compose.yaml",
|
|
10541
|
+
"cbx_config.json",
|
|
10542
|
+
".vscode/mcp.json",
|
|
10543
|
+
".gemini/settings.json",
|
|
10544
|
+
]) {
|
|
10545
|
+
await pushCandidate(candidate);
|
|
10546
|
+
}
|
|
10547
|
+
for (const specRoot of specRoots.slice(0, 4)) {
|
|
10548
|
+
await pushCandidate(specRoot);
|
|
10549
|
+
}
|
|
10550
|
+
for (const app of snapshot.architectureByApp || []) {
|
|
10551
|
+
if (!app?.rootPath || app.rootPath === ".")
|
|
10552
|
+
continue;
|
|
10553
|
+
await pushCandidate(app.rootPath);
|
|
10554
|
+
for (const child of [
|
|
10555
|
+
"README.md",
|
|
10556
|
+
"src",
|
|
10557
|
+
"lib",
|
|
10558
|
+
"app",
|
|
10559
|
+
"prisma",
|
|
10560
|
+
"migrations",
|
|
10561
|
+
"test",
|
|
10562
|
+
"tests",
|
|
10563
|
+
"docs",
|
|
10564
|
+
]) {
|
|
10565
|
+
await pushCandidate(path.join(app.rootPath, child));
|
|
10566
|
+
}
|
|
10567
|
+
}
|
|
10568
|
+
for (const dir of snapshot.topDirs || []) {
|
|
10569
|
+
await pushCandidate(dir);
|
|
10570
|
+
}
|
|
10571
|
+
return ordered.slice(0, 18);
|
|
10572
|
+
}
|
|
10402
10573
|
function resolveArchitectureConditionalSkills(snapshot, specRoots, researchMode) {
|
|
10403
10574
|
const conditional = [];
|
|
10404
10575
|
const frameworks = new Set(snapshot.frameworks || []);
|
|
@@ -10443,13 +10614,12 @@ async function resolveArchitectureSkillPathHints(platform, cwd, skillIds) {
|
|
|
10443
10614
|
.map((skillId) => path.join(skillsDir, skillId, "SKILL.md"))
|
|
10444
10615
|
.map((filePath) => toPosixPath(path.relative(findWorkspaceRoot(cwd), filePath)));
|
|
10445
10616
|
}
|
|
10446
|
-
function buildArchitecturePrompt({ platform, workspaceRoot, snapshot, specRoots, researchMode, coreSkills, conditionalSkills, skillPathHints, }) {
|
|
10447
|
-
const productPath =
|
|
10448
|
-
const architecturePath =
|
|
10449
|
-
const
|
|
10450
|
-
const
|
|
10451
|
-
const
|
|
10452
|
-
const adrReadmePath = "docs/adr/README.md";
|
|
10617
|
+
function buildArchitecturePrompt({ platform, workspaceRoot, snapshot, specRoots, inspectionAnchors, researchMode, coreSkills, conditionalSkills, skillPathHints, }) {
|
|
10618
|
+
const productPath = `${FOUNDATION_DOCS_DIR}/PRODUCT.md`;
|
|
10619
|
+
const architecturePath = `${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md`;
|
|
10620
|
+
const techPath = `${FOUNDATION_DOCS_DIR}/TECH.md`;
|
|
10621
|
+
const adrReadmePath = `${FOUNDATION_ADR_DIR}/README.md`;
|
|
10622
|
+
const adrTemplatePath = `${FOUNDATION_ADR_DIR}/0000-template.md`;
|
|
10453
10623
|
const architectureSignals = snapshot.architectureByApp
|
|
10454
10624
|
.filter((item) => (item.architectureSignals || []).length > 0)
|
|
10455
10625
|
.map((item) => {
|
|
@@ -10460,8 +10630,8 @@ function buildArchitecturePrompt({ platform, workspaceRoot, snapshot, specRoots,
|
|
|
10460
10630
|
`You are running inside ${platform}.`,
|
|
10461
10631
|
"",
|
|
10462
10632
|
"Objective:",
|
|
10463
|
-
`- Inspect the repository at ${toPosixPath(workspaceRoot)} and refresh the
|
|
10464
|
-
"-
|
|
10633
|
+
`- Inspect the repository at ${toPosixPath(workspaceRoot)} and author or refresh the core foundation docs in ${productPath}, ${architecturePath}, ${techPath}, ${adrReadmePath}, and ${adrTemplatePath}.`,
|
|
10634
|
+
"- The content should be primarily AI-authored from repository inspection, not copied from placeholder scaffolding.",
|
|
10465
10635
|
"- Preserve manual content outside the managed `cbx:*` markers.",
|
|
10466
10636
|
"",
|
|
10467
10637
|
"Required skill bundle:",
|
|
@@ -10481,27 +10651,38 @@ function buildArchitecturePrompt({ platform, workspaceRoot, snapshot, specRoots,
|
|
|
10481
10651
|
architectureSignals.length > 0
|
|
10482
10652
|
? `- Architecture signals: ${architectureSignals.join(" | ")}`
|
|
10483
10653
|
: "- Architecture signals: none confidently inferred from the repo scan",
|
|
10654
|
+
`- Entry points: ${snapshot.entryPoints.length > 0 ? snapshot.entryPoints.slice(0, 8).join(" | ") : "none detected"}`,
|
|
10655
|
+
`- Key scripts: ${snapshot.keyScripts.length > 0 ? snapshot.keyScripts.slice(0, 8).map((item) => `${item.name}=${item.command}`).join(" | ") : "none detected"}`,
|
|
10656
|
+
`- Inspection anchors: ${inspectionAnchors.length > 0 ? inspectionAnchors.join(", ") : "no concrete anchors detected; inspect the repo root, main source trees, and manifest files manually"}`,
|
|
10484
10657
|
"",
|
|
10485
10658
|
"Execution contract:",
|
|
10486
|
-
|
|
10487
|
-
"2.
|
|
10488
|
-
"3.
|
|
10489
|
-
|
|
10490
|
-
|
|
10491
|
-
|
|
10492
|
-
|
|
10493
|
-
|
|
10659
|
+
"1. Inspect the repository first before writing any backbone doc content. Derive structure, product surfaces, runtime boundaries, and technical constraints from the actual codebase.",
|
|
10660
|
+
"2. Complete a real inspection pass before drafting. At minimum, inspect the concrete anchors listed above, plus any adjacent directories needed to understand the main execution paths, data boundaries, and integration surfaces.",
|
|
10661
|
+
"3. Do not infer architecture from filenames alone when you can open representative files. Read enough source to validate the main app boundaries, runtime flows, and persistence/integration patterns.",
|
|
10662
|
+
`4. Then read ${productPath}, ${architecturePath}, and ${techPath} in that order when they exist so you can preserve useful manual context and update existing managed sections cleanly.`,
|
|
10663
|
+
`5. Replace or update only the content between the existing managed markers in ${productPath}, ${architecturePath}, and ${techPath}. Do not append a second marker block.`,
|
|
10664
|
+
`6. In ${productPath}, write a concrete product foundation: product purpose, primary users/operators, main journeys, business capabilities, operational constraints, and what future contributors must preserve.`,
|
|
10665
|
+
`7. In ${architecturePath}, write a lean but detailed architecture backbone in a pragmatic arc42/C4 style: system purpose and constraints, explicit architecture classification, bounded contexts, major building blocks, dependency rules, data and integration boundaries, runtime flows, deployment/operability notes, testing/debugging strategy, and only the diagram levels that add real value.`,
|
|
10666
|
+
`8. ${architecturePath} must include a dedicated folder-structure guide that lists the important apps/packages/directories, what each owns, and how contributors should treat those boundaries when editing code.`,
|
|
10667
|
+
`9. In ${techPath}, write the developer-facing technical map: stack, repo layout, key commands, entrypoints, data stores, external services, environment/config surfaces, MCP/tooling footprint, and change hotspots future agents should inspect before editing code.`,
|
|
10668
|
+
`10. ${techPath} should complement ${architecturePath}; do not repeat the same structure prose unless it helps a developer act faster.`,
|
|
10669
|
+
`11. Use exact required headings in ${productPath}: \`## Product Scope\`, \`## Product Purpose\`, \`## Primary Users And Operators\`, \`## Main Journeys\`, \`## Business Capabilities That Matter\`, \`## Operational Constraints\`, \`## Preservation Rules For Future Contributors\`.`,
|
|
10670
|
+
`12. Use exact required headings in ${architecturePath}: \`## Architecture Type\`, \`## System Purpose\`, \`## Constraints And Architectural Drivers\`, \`## Repository Structure Guide\`, \`## Bounded Contexts\`, \`## Major Building Blocks\`, \`## Dependency Rules\`, \`## Data Boundaries\`, \`## Integration Boundaries\`, \`## Runtime Flows\`, \`## Deployment And Operability\`, \`## Testing And Debugging Strategy\`, \`## Architectural Guidance\`.`,
|
|
10671
|
+
`13. Use exact required headings in ${techPath}: \`## Stack Snapshot\`, \`## Repository Layout\`, \`## Entrypoints\`, \`## Key Commands\`, \`## Runtime Data Stores\`, \`## External Services And Integration Surfaces\`, \`## Environment And Config Surfaces\`, \`## Generated Artifacts To Respect\`, \`## Change Hotspots\`, \`## Practical Editing Notes\`.`,
|
|
10672
|
+
"14. Every major claim should be grounded in repository evidence. Mention concrete repo paths in the docs when a structural claim would otherwise be ambiguous.",
|
|
10673
|
+
"15. Avoid placeholder filler, generic checklists, and duplicated content across files. Each doc should have a clear job.",
|
|
10674
|
+
"16. Do not create ROADMAP.md, ENGINEERING_RULES.md, or other extra docs unless the prompt explicitly asks for them.",
|
|
10494
10675
|
researchMode === "never"
|
|
10495
|
-
? "
|
|
10496
|
-
: "
|
|
10676
|
+
? "17. Stay repo-only. Do not use outside research."
|
|
10677
|
+
: "17. Use repo evidence first. Use official docs when needed. Treat Reddit or community sources only as labeled secondary evidence.",
|
|
10497
10678
|
researchMode === "always"
|
|
10498
|
-
?
|
|
10499
|
-
: "
|
|
10500
|
-
|
|
10501
|
-
`
|
|
10679
|
+
? `18. Include an external research evidence subsection in ${techPath} with clearly labeled primary and secondary evidence.`
|
|
10680
|
+
: "18. Include external research notes only if they materially informed the architecture update.",
|
|
10681
|
+
`19. If the project clearly follows Clean Architecture, feature-first modules, DDD, modular monolith, or another stable structure, make that explicit in ${architecturePath} with evidence from the repo.`,
|
|
10682
|
+
`20. Ensure ${adrReadmePath} and ${adrTemplatePath} exist as ADR entrypoints, but keep them lean.`,
|
|
10502
10683
|
"",
|
|
10503
10684
|
"Return one JSON object on the last line with this shape:",
|
|
10504
|
-
|
|
10685
|
+
`{"files_written":["${productPath}","${architecturePath}","${techPath}","${adrReadmePath}","${adrTemplatePath}"],"research_used":false,"gaps":[],"next_actions":[]}`,
|
|
10505
10686
|
"",
|
|
10506
10687
|
"Do not emit placeholder TODOs in the managed sections.",
|
|
10507
10688
|
].join("\n");
|
|
@@ -10722,108 +10903,117 @@ async function captureFileContents(filePaths) {
|
|
|
10722
10903
|
}
|
|
10723
10904
|
return snapshot;
|
|
10724
10905
|
}
|
|
10906
|
+
function collectTaggedBlocks(content, startPattern, endPattern) {
|
|
10907
|
+
const blocks = [];
|
|
10908
|
+
let cursor = 0;
|
|
10909
|
+
const startMatcher = new RegExp(startPattern.source, startPattern.flags.replace(/g/g, ""));
|
|
10910
|
+
const endMatcher = new RegExp(endPattern.source, endPattern.flags.replace(/g/g, ""));
|
|
10911
|
+
while (cursor < content.length) {
|
|
10912
|
+
const remaining = content.slice(cursor);
|
|
10913
|
+
const startMatch = remaining.match(startMatcher);
|
|
10914
|
+
if (!startMatch || startMatch.index == null)
|
|
10915
|
+
break;
|
|
10916
|
+
const startIndex = cursor + startMatch.index;
|
|
10917
|
+
const afterStart = content.slice(startIndex + startMatch[0].length);
|
|
10918
|
+
const endMatch = afterStart.match(endMatcher);
|
|
10919
|
+
if (!endMatch || endMatch.index == null)
|
|
10920
|
+
break;
|
|
10921
|
+
const endIndex = startIndex + startMatch[0].length + endMatch.index + endMatch[0].length;
|
|
10922
|
+
const block = content.slice(startIndex, endIndex);
|
|
10923
|
+
const inner = content
|
|
10924
|
+
.slice(startIndex + startMatch[0].length, endIndex - endMatch[0].length)
|
|
10925
|
+
.trim();
|
|
10926
|
+
blocks.push({
|
|
10927
|
+
startIndex,
|
|
10928
|
+
endIndex,
|
|
10929
|
+
block,
|
|
10930
|
+
score: inner.length,
|
|
10931
|
+
});
|
|
10932
|
+
cursor = endIndex;
|
|
10933
|
+
}
|
|
10934
|
+
return blocks;
|
|
10935
|
+
}
|
|
10936
|
+
async function collapseDuplicateTaggedBlocks({ targetPath, startPattern, endPattern, }) {
|
|
10937
|
+
if (!(await pathExists(targetPath)))
|
|
10938
|
+
return { changed: false };
|
|
10939
|
+
const content = await readFile(targetPath, "utf8");
|
|
10940
|
+
const blocks = collectTaggedBlocks(content, startPattern, endPattern);
|
|
10941
|
+
if (blocks.length <= 1)
|
|
10942
|
+
return { changed: false };
|
|
10943
|
+
const bestBlock = [...blocks].sort((a, b) => b.score - a.score)[0];
|
|
10944
|
+
const first = blocks[0];
|
|
10945
|
+
const last = blocks[blocks.length - 1];
|
|
10946
|
+
const normalized = content.slice(0, first.startIndex) +
|
|
10947
|
+
bestBlock.block +
|
|
10948
|
+
content.slice(last.endIndex);
|
|
10949
|
+
if (normalized === content)
|
|
10950
|
+
return { changed: false };
|
|
10951
|
+
await writeFile(targetPath, normalized, "utf8");
|
|
10952
|
+
return { changed: true };
|
|
10953
|
+
}
|
|
10954
|
+
async function normalizeArchitectureBuildOutputs(scaffold) {
|
|
10955
|
+
await collapseDuplicateTaggedBlocks({
|
|
10956
|
+
targetPath: scaffold.productPath,
|
|
10957
|
+
startPattern: PRODUCT_FOUNDATION_BLOCK_START_RE,
|
|
10958
|
+
endPattern: PRODUCT_FOUNDATION_BLOCK_END_RE,
|
|
10959
|
+
});
|
|
10960
|
+
await collapseDuplicateTaggedBlocks({
|
|
10961
|
+
targetPath: scaffold.architectureDocPath,
|
|
10962
|
+
startPattern: ARCHITECTURE_DOC_BLOCK_START_RE,
|
|
10963
|
+
endPattern: ARCHITECTURE_DOC_BLOCK_END_RE,
|
|
10964
|
+
});
|
|
10965
|
+
await collapseDuplicateTaggedBlocks({
|
|
10966
|
+
targetPath: scaffold.techMdPath,
|
|
10967
|
+
startPattern: TECH_ARCHITECTURE_BLOCK_START_RE,
|
|
10968
|
+
endPattern: TECH_ARCHITECTURE_BLOCK_END_RE,
|
|
10969
|
+
});
|
|
10970
|
+
}
|
|
10725
10971
|
async function readArchitectureDriftStatus(workspaceRoot, snapshot) {
|
|
10726
|
-
const
|
|
10727
|
-
const
|
|
10728
|
-
const
|
|
10729
|
-
const
|
|
10730
|
-
const techPath = path.join(workspaceRoot, "TECH.md");
|
|
10731
|
-
const roadmapPath = path.join(workspaceRoot, "ROADMAP.md");
|
|
10732
|
-
const adrReadmePath = path.join(workspaceRoot, "docs", "adr", "README.md");
|
|
10972
|
+
const productPath = path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "PRODUCT.md");
|
|
10973
|
+
const architecturePath = path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "ARCHITECTURE.md");
|
|
10974
|
+
const techPath = path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "TECH.md");
|
|
10975
|
+
const adrReadmePath = path.join(workspaceRoot, FOUNDATION_ADR_DIR, "README.md");
|
|
10733
10976
|
const metadataPath = path.join(workspaceRoot, ".cbx", ARCHITECTURE_BUILD_METADATA_FILENAME);
|
|
10734
10977
|
const productExists = await pathExists(productPath);
|
|
10735
10978
|
const architectureExists = await pathExists(architecturePath);
|
|
10736
|
-
const rulesExists = await pathExists(rulesPath);
|
|
10737
10979
|
const techExists = await pathExists(techPath);
|
|
10738
|
-
const roadmapExists = await pathExists(roadmapPath);
|
|
10739
10980
|
const adrReadmeExists = await pathExists(adrReadmePath);
|
|
10740
|
-
const expectedProductHash = hashStableObject(inferProductFoundationProfile(snapshot, specRoots));
|
|
10741
|
-
const expectedArchitectureHash = hashStableObject(inferArchitectureDocProfile(snapshot, specRoots));
|
|
10742
|
-
const expectedRulesHash = hashStableObject(inferArchitectureContractProfile(snapshot));
|
|
10743
|
-
const expectedTechHash = hashStableObject({
|
|
10744
|
-
style: inferArchitectureContractProfile(snapshot).style,
|
|
10745
|
-
topDirs: snapshot.topDirs,
|
|
10746
|
-
frameworks: snapshot.frameworks,
|
|
10747
|
-
architectureByApp: snapshot.architectureByApp,
|
|
10748
|
-
});
|
|
10749
|
-
const expectedRoadmapHash = hashStableObject({
|
|
10750
|
-
topDirs: snapshot.topDirs,
|
|
10751
|
-
frameworks: snapshot.frameworks,
|
|
10752
|
-
specRoots,
|
|
10753
|
-
});
|
|
10754
10981
|
const findings = [];
|
|
10755
10982
|
let actualProductHash = null;
|
|
10756
10983
|
let actualArchitectureHash = null;
|
|
10757
|
-
let actualRulesHash = null;
|
|
10758
10984
|
let actualTechHash = null;
|
|
10759
|
-
let actualRoadmapHash = null;
|
|
10760
10985
|
if (!productExists) {
|
|
10761
|
-
findings.push(
|
|
10986
|
+
findings.push(`${FOUNDATION_DOCS_DIR}/PRODUCT.md is missing.`);
|
|
10762
10987
|
}
|
|
10763
10988
|
else {
|
|
10764
10989
|
const content = await readFile(productPath, "utf8");
|
|
10765
10990
|
actualProductHash = extractTaggedMarkerAttribute(content, PRODUCT_FOUNDATION_BLOCK_START_RE, "profile");
|
|
10766
10991
|
if (!actualProductHash) {
|
|
10767
|
-
findings.push(
|
|
10768
|
-
}
|
|
10769
|
-
else if (actualProductHash !== expectedProductHash) {
|
|
10770
|
-
findings.push(`PRODUCT.md foundation is stale (expected ${expectedProductHash}, found ${actualProductHash}).`);
|
|
10992
|
+
findings.push(`${FOUNDATION_DOCS_DIR}/PRODUCT.md is missing the managed product foundation block.`);
|
|
10771
10993
|
}
|
|
10772
10994
|
}
|
|
10773
10995
|
if (!architectureExists) {
|
|
10774
|
-
findings.push(
|
|
10996
|
+
findings.push(`${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md is missing.`);
|
|
10775
10997
|
}
|
|
10776
10998
|
else {
|
|
10777
10999
|
const content = await readFile(architecturePath, "utf8");
|
|
10778
11000
|
actualArchitectureHash = extractTaggedMarkerAttribute(content, ARCHITECTURE_DOC_BLOCK_START_RE, "profile");
|
|
10779
11001
|
if (!actualArchitectureHash) {
|
|
10780
|
-
findings.push(
|
|
10781
|
-
}
|
|
10782
|
-
else if (actualArchitectureHash !== expectedArchitectureHash) {
|
|
10783
|
-
findings.push(`ARCHITECTURE.md backbone is stale (expected ${expectedArchitectureHash}, found ${actualArchitectureHash}).`);
|
|
10784
|
-
}
|
|
10785
|
-
}
|
|
10786
|
-
if (!rulesExists) {
|
|
10787
|
-
findings.push("ENGINEERING_RULES.md is missing.");
|
|
10788
|
-
}
|
|
10789
|
-
else {
|
|
10790
|
-
const content = await readFile(rulesPath, "utf8");
|
|
10791
|
-
actualRulesHash = extractTaggedMarkerAttribute(content, ENGINEERING_ARCHITECTURE_BLOCK_START_RE, "profile");
|
|
10792
|
-
if (!actualRulesHash) {
|
|
10793
|
-
findings.push("ENGINEERING_RULES.md is missing the managed architecture contract block.");
|
|
10794
|
-
}
|
|
10795
|
-
else if (actualRulesHash !== expectedRulesHash) {
|
|
10796
|
-
findings.push(`ENGINEERING_RULES.md architecture profile is stale (expected ${expectedRulesHash}, found ${actualRulesHash}).`);
|
|
11002
|
+
findings.push(`${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md is missing the managed architecture backbone block.`);
|
|
10797
11003
|
}
|
|
10798
11004
|
}
|
|
10799
11005
|
if (!techExists) {
|
|
10800
|
-
findings.push(
|
|
11006
|
+
findings.push(`${FOUNDATION_DOCS_DIR}/TECH.md is missing.`);
|
|
10801
11007
|
}
|
|
10802
11008
|
else {
|
|
10803
11009
|
const content = await readFile(techPath, "utf8");
|
|
10804
11010
|
actualTechHash = extractTaggedMarkerAttribute(content, TECH_ARCHITECTURE_BLOCK_START_RE, "snapshot");
|
|
10805
11011
|
if (!actualTechHash) {
|
|
10806
|
-
findings.push(
|
|
10807
|
-
}
|
|
10808
|
-
else if (actualTechHash !== expectedTechHash) {
|
|
10809
|
-
findings.push(`TECH.md architecture snapshot is stale (expected ${expectedTechHash}, found ${actualTechHash}).`);
|
|
10810
|
-
}
|
|
10811
|
-
}
|
|
10812
|
-
if (!roadmapExists) {
|
|
10813
|
-
findings.push("ROADMAP.md is missing.");
|
|
10814
|
-
}
|
|
10815
|
-
else {
|
|
10816
|
-
const content = await readFile(roadmapPath, "utf8");
|
|
10817
|
-
actualRoadmapHash = extractTaggedMarkerAttribute(content, ROADMAP_FOUNDATION_BLOCK_START_RE, "profile");
|
|
10818
|
-
if (!actualRoadmapHash) {
|
|
10819
|
-
findings.push("ROADMAP.md is missing the managed roadmap foundation block.");
|
|
10820
|
-
}
|
|
10821
|
-
else if (actualRoadmapHash !== expectedRoadmapHash) {
|
|
10822
|
-
findings.push(`ROADMAP.md backbone is stale (expected ${expectedRoadmapHash}, found ${actualRoadmapHash}).`);
|
|
11012
|
+
findings.push(`${FOUNDATION_DOCS_DIR}/TECH.md is missing the managed architecture snapshot block.`);
|
|
10823
11013
|
}
|
|
10824
11014
|
}
|
|
10825
11015
|
if (!adrReadmeExists) {
|
|
10826
|
-
findings.push(
|
|
11016
|
+
findings.push(`${FOUNDATION_ADR_DIR}/README.md is missing.`);
|
|
10827
11017
|
}
|
|
10828
11018
|
const metadata = await readJsonFileIfExists(metadataPath);
|
|
10829
11019
|
if (!metadata.exists) {
|
|
@@ -10834,21 +11024,12 @@ async function readArchitectureDriftStatus(workspaceRoot, snapshot) {
|
|
|
10834
11024
|
findings,
|
|
10835
11025
|
productPath,
|
|
10836
11026
|
architecturePath,
|
|
10837
|
-
rulesPath,
|
|
10838
11027
|
techPath,
|
|
10839
|
-
roadmapPath,
|
|
10840
11028
|
adrReadmePath,
|
|
10841
11029
|
metadataPath,
|
|
10842
|
-
expectedProductHash,
|
|
10843
|
-
expectedArchitectureHash,
|
|
10844
|
-
expectedRulesHash,
|
|
10845
|
-
expectedTechHash,
|
|
10846
|
-
expectedRoadmapHash,
|
|
10847
11030
|
actualProductHash,
|
|
10848
11031
|
actualArchitectureHash,
|
|
10849
|
-
actualRulesHash,
|
|
10850
11032
|
actualTechHash,
|
|
10851
|
-
actualRoadmapHash,
|
|
10852
11033
|
};
|
|
10853
11034
|
}
|
|
10854
11035
|
async function runBuildArchitecture(options) {
|
|
@@ -10872,7 +11053,7 @@ async function runBuildArchitecture(options) {
|
|
|
10872
11053
|
console.log(`Platform: ${platform}`);
|
|
10873
11054
|
console.log(`Workspace: ${toPosixPath(workspaceRoot)}`);
|
|
10874
11055
|
console.log(`Status: ${drift.stale ? "stale" : "fresh"}`);
|
|
10875
|
-
console.log(
|
|
11056
|
+
console.log(`Backbone docs: ${FOUNDATION_DOCS_DIR}/PRODUCT.md, ${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md, ${FOUNDATION_DOCS_DIR}/TECH.md, ${FOUNDATION_ADR_DIR}/README.md`);
|
|
10876
11057
|
if (drift.findings.length > 0) {
|
|
10877
11058
|
console.log("Findings:");
|
|
10878
11059
|
for (const finding of drift.findings) {
|
|
@@ -10885,24 +11066,12 @@ async function runBuildArchitecture(options) {
|
|
|
10885
11066
|
return;
|
|
10886
11067
|
}
|
|
10887
11068
|
const managedFilePaths = [
|
|
10888
|
-
path.join(workspaceRoot, "PRODUCT.md"),
|
|
10889
|
-
path.join(workspaceRoot, "ARCHITECTURE.md"),
|
|
10890
|
-
path.join(workspaceRoot, "
|
|
10891
|
-
path.join(workspaceRoot, "
|
|
10892
|
-
path.join(workspaceRoot, "
|
|
10893
|
-
path.join(workspaceRoot, "docs", "adr", "README.md"),
|
|
10894
|
-
path.join(workspaceRoot, "docs", "adr", "0000-template.md"),
|
|
11069
|
+
path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "PRODUCT.md"),
|
|
11070
|
+
path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "ARCHITECTURE.md"),
|
|
11071
|
+
path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "TECH.md"),
|
|
11072
|
+
path.join(workspaceRoot, FOUNDATION_ADR_DIR, "README.md"),
|
|
11073
|
+
path.join(workspaceRoot, FOUNDATION_ADR_DIR, "0000-template.md"),
|
|
10895
11074
|
];
|
|
10896
|
-
const filesBefore = dryRun
|
|
10897
|
-
? Object.fromEntries(managedFilePaths.map((filePath) => [filePath, null]))
|
|
10898
|
-
: await captureFileContents(managedFilePaths);
|
|
10899
|
-
const scaffold = await ensureArchitectureDocScaffold({
|
|
10900
|
-
workspaceRoot,
|
|
10901
|
-
snapshot,
|
|
10902
|
-
specRoots,
|
|
10903
|
-
overwrite,
|
|
10904
|
-
dryRun,
|
|
10905
|
-
});
|
|
10906
11075
|
const coreSkills = [
|
|
10907
11076
|
"architecture-doc",
|
|
10908
11077
|
"system-design",
|
|
@@ -10912,11 +11081,13 @@ async function runBuildArchitecture(options) {
|
|
|
10912
11081
|
const conditionalSkills = resolveArchitectureConditionalSkills(snapshot, specRoots, researchMode);
|
|
10913
11082
|
const skillBundle = [...coreSkills, ...conditionalSkills];
|
|
10914
11083
|
const skillPathHints = await resolveArchitectureSkillPathHints(platform, cwd, skillBundle);
|
|
11084
|
+
const inspectionAnchors = await resolveArchitectureInspectionAnchors(workspaceRoot, snapshot, specRoots);
|
|
10915
11085
|
const prompt = buildArchitecturePrompt({
|
|
10916
11086
|
platform,
|
|
10917
11087
|
workspaceRoot,
|
|
10918
11088
|
snapshot,
|
|
10919
11089
|
specRoots,
|
|
11090
|
+
inspectionAnchors,
|
|
10920
11091
|
researchMode,
|
|
10921
11092
|
coreSkills,
|
|
10922
11093
|
conditionalSkills,
|
|
@@ -10924,6 +11095,13 @@ async function runBuildArchitecture(options) {
|
|
|
10924
11095
|
});
|
|
10925
11096
|
const adapter = await probeArchitectureAdapter(platform, workspaceRoot);
|
|
10926
11097
|
const args = adapter.buildInvocation(prompt);
|
|
11098
|
+
const managedTargets = [
|
|
11099
|
+
path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "PRODUCT.md"),
|
|
11100
|
+
path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "ARCHITECTURE.md"),
|
|
11101
|
+
path.join(workspaceRoot, FOUNDATION_DOCS_DIR, "TECH.md"),
|
|
11102
|
+
path.join(workspaceRoot, FOUNDATION_ADR_DIR, "README.md"),
|
|
11103
|
+
path.join(workspaceRoot, FOUNDATION_ADR_DIR, "0000-template.md"),
|
|
11104
|
+
].map((filePath) => toPosixPath(filePath));
|
|
10927
11105
|
if (dryRun) {
|
|
10928
11106
|
const summary = {
|
|
10929
11107
|
platform,
|
|
@@ -10931,15 +11109,7 @@ async function runBuildArchitecture(options) {
|
|
|
10931
11109
|
adapter: adapter.binary,
|
|
10932
11110
|
invocation: [adapter.binary, ...args],
|
|
10933
11111
|
researchMode,
|
|
10934
|
-
managedTargets
|
|
10935
|
-
toPosixPath(scaffold.productPath),
|
|
10936
|
-
toPosixPath(scaffold.architectureDocPath),
|
|
10937
|
-
toPosixPath(scaffold.engineeringRulesPath),
|
|
10938
|
-
toPosixPath(scaffold.techMdPath),
|
|
10939
|
-
toPosixPath(scaffold.roadmapPath),
|
|
10940
|
-
toPosixPath(scaffold.adrReadmePath),
|
|
10941
|
-
toPosixPath(scaffold.adrTemplatePath),
|
|
10942
|
-
],
|
|
11112
|
+
managedTargets,
|
|
10943
11113
|
skillBundle,
|
|
10944
11114
|
};
|
|
10945
11115
|
if (emitJson) {
|
|
@@ -10950,12 +11120,17 @@ async function runBuildArchitecture(options) {
|
|
|
10950
11120
|
console.log(`Workspace: ${toPosixPath(workspaceRoot)}`);
|
|
10951
11121
|
console.log(`Adapter: ${adapter.binary}`);
|
|
10952
11122
|
console.log(`Research mode: ${researchMode}`);
|
|
10953
|
-
console.log(`Managed targets: ${
|
|
11123
|
+
console.log(`Managed targets: ${summary.managedTargets.join(", ")}`);
|
|
10954
11124
|
console.log(`Skill bundle: ${skillBundle.join(", ")}`);
|
|
10955
11125
|
console.log(`Invocation: ${[adapter.binary, ...args].join(" ")}`);
|
|
10956
11126
|
}
|
|
10957
11127
|
return;
|
|
10958
11128
|
}
|
|
11129
|
+
const filesBefore = await captureFileContents(managedFilePaths);
|
|
11130
|
+
const scaffold = await ensureArchitectureBuildScaffold({
|
|
11131
|
+
workspaceRoot,
|
|
11132
|
+
dryRun,
|
|
11133
|
+
});
|
|
10959
11134
|
if (!emitJson) {
|
|
10960
11135
|
console.log(`Streaming ${adapter.binary} output...`);
|
|
10961
11136
|
}
|
|
@@ -10967,26 +11142,26 @@ async function runBuildArchitecture(options) {
|
|
|
10967
11142
|
if (!execution.ok) {
|
|
10968
11143
|
throw new Error(explainArchitectureBuildFailure(platform, execution));
|
|
10969
11144
|
}
|
|
11145
|
+
await normalizeArchitectureBuildOutputs(scaffold);
|
|
10970
11146
|
const filesAfter = await captureFileContents(managedFilePaths);
|
|
10971
11147
|
const changedFiles = managedFilePaths
|
|
10972
11148
|
.filter((filePath) => filesBefore[filePath] !== filesAfter[filePath])
|
|
10973
11149
|
.map((filePath) => toPosixPath(path.relative(workspaceRoot, filePath)));
|
|
10974
|
-
const rulesContent = filesAfter[scaffold.engineeringRulesPath] ??
|
|
10975
|
-
(await readFile(scaffold.engineeringRulesPath, "utf8"));
|
|
10976
11150
|
const techContent = filesAfter[scaffold.techMdPath] ?? (await readFile(scaffold.techMdPath, "utf8"));
|
|
10977
11151
|
const productContent = filesAfter[scaffold.productPath] ?? (await readFile(scaffold.productPath, "utf8"));
|
|
10978
11152
|
const architectureContent = filesAfter[scaffold.architectureDocPath] ??
|
|
10979
11153
|
(await readFile(scaffold.architectureDocPath, "utf8"));
|
|
10980
|
-
const roadmapContent = filesAfter[scaffold.roadmapPath] ?? (await readFile(scaffold.roadmapPath, "utf8"));
|
|
10981
11154
|
const metadataPath = path.join(workspaceRoot, ".cbx", ARCHITECTURE_BUILD_METADATA_FILENAME);
|
|
10982
11155
|
const metadata = buildArchitectureBuildMetadata({
|
|
10983
11156
|
platform,
|
|
10984
11157
|
researchMode,
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
|
|
11158
|
+
managedDocs: [
|
|
11159
|
+
`${FOUNDATION_DOCS_DIR}/PRODUCT.md`,
|
|
11160
|
+
`${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md`,
|
|
11161
|
+
`${FOUNDATION_DOCS_DIR}/TECH.md`,
|
|
11162
|
+
`${FOUNDATION_ADR_DIR}/README.md`,
|
|
11163
|
+
`${FOUNDATION_ADR_DIR}/0000-template.md`,
|
|
11164
|
+
],
|
|
10990
11165
|
});
|
|
10991
11166
|
await mkdir(path.dirname(metadataPath), { recursive: true });
|
|
10992
11167
|
await writeFile(metadataPath, `${JSON.stringify(metadata, null, 2)}\n`, "utf8");
|
|
@@ -11008,8 +11183,8 @@ async function runBuildArchitecture(options) {
|
|
|
11008
11183
|
console.log(`Platform: ${platform}`);
|
|
11009
11184
|
console.log(`Adapter: ${adapter.binary}`);
|
|
11010
11185
|
console.log(`Workspace: ${toPosixPath(workspaceRoot)}`);
|
|
11011
|
-
console.log(
|
|
11012
|
-
console.log(
|
|
11186
|
+
console.log(`Managed docs: ${FOUNDATION_DOCS_DIR}/PRODUCT.md, ${FOUNDATION_DOCS_DIR}/ARCHITECTURE.md, ${FOUNDATION_DOCS_DIR}/TECH.md`);
|
|
11187
|
+
console.log(`ADR scaffold: ${FOUNDATION_ADR_DIR}/README.md, ${FOUNDATION_ADR_DIR}/0000-template.md`);
|
|
11013
11188
|
console.log(`Skill bundle: ${skillBundle.join(", ")}`);
|
|
11014
11189
|
console.log(`Files written: ${(result.filesWritten || []).join(", ") || "(none reported)"}`);
|
|
11015
11190
|
console.log(`Research used: ${result.researchUsed ? "yes" : "no"}`);
|