@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.
Files changed (80) hide show
  1. package/dist/cli/build/commands.js +1 -1
  2. package/dist/cli/build/commands.js.map +1 -1
  3. package/dist/cli/core.js +324 -149
  4. package/dist/cli/core.js.map +1 -1
  5. package/package.json +1 -1
  6. package/src/cli/build/commands.ts +1 -1
  7. package/src/cli/core.ts +368 -194
  8. package/workflows/workflows/agent-environment-setup/generated/route-manifest.json +2 -2
  9. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/accessibility.toml +1 -1
  10. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/architecture.toml +2 -2
  11. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/backend.toml +1 -1
  12. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/create.toml +1 -1
  13. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/database.toml +1 -1
  14. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/debug.toml +1 -1
  15. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/devops.toml +1 -1
  16. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/implement-track.toml +1 -1
  17. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/migrate.toml +1 -1
  18. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/mobile.toml +1 -1
  19. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/onboard.toml +1 -1
  20. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/orchestrate.toml +1 -1
  21. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/plan.toml +1 -1
  22. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/refactor.toml +1 -1
  23. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/release.toml +1 -1
  24. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/review.toml +1 -1
  25. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/security.toml +1 -1
  26. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/spec.toml +1 -1
  27. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/test.toml +1 -1
  28. package/workflows/workflows/agent-environment-setup/platforms/antigravity/commands/vercel.toml +1 -1
  29. package/workflows/workflows/agent-environment-setup/platforms/antigravity/workflows/architecture.md +22 -19
  30. package/workflows/workflows/agent-environment-setup/platforms/antigravity/workflows/spec.md +2 -2
  31. package/workflows/workflows/agent-environment-setup/platforms/claude/workflows/architecture.md +22 -19
  32. package/workflows/workflows/agent-environment-setup/platforms/claude/workflows/spec.md +2 -2
  33. package/workflows/workflows/agent-environment-setup/platforms/codex/workflows/architecture.md +22 -19
  34. package/workflows/workflows/agent-environment-setup/platforms/codex/workflows/spec.md +2 -2
  35. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-accessibility.prompt.md +1 -1
  36. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-architecture.prompt.md +2 -2
  37. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-backend.prompt.md +1 -1
  38. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-create.prompt.md +1 -1
  39. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-database.prompt.md +1 -1
  40. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-debug.prompt.md +1 -1
  41. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-devops.prompt.md +1 -1
  42. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-implement-track.prompt.md +1 -1
  43. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-migrate.prompt.md +1 -1
  44. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-mobile.prompt.md +1 -1
  45. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-onboard.prompt.md +1 -1
  46. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-orchestrate.prompt.md +1 -1
  47. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-plan.prompt.md +1 -1
  48. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-refactor.prompt.md +1 -1
  49. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-release.prompt.md +1 -1
  50. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-review.prompt.md +1 -1
  51. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-security.prompt.md +1 -1
  52. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-spec.prompt.md +1 -1
  53. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-test.prompt.md +1 -1
  54. package/workflows/workflows/agent-environment-setup/platforms/copilot/prompts/workflow-vercel.prompt.md +1 -1
  55. package/workflows/workflows/agent-environment-setup/platforms/copilot/workflows/architecture.md +22 -19
  56. package/workflows/workflows/agent-environment-setup/platforms/copilot/workflows/spec.md +2 -2
  57. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/accessibility.toml +1 -1
  58. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/architecture.toml +2 -2
  59. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/backend.toml +1 -1
  60. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/create.toml +1 -1
  61. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/database.toml +1 -1
  62. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/debug.toml +1 -1
  63. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/devops.toml +1 -1
  64. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/implement-track.toml +1 -1
  65. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/migrate.toml +1 -1
  66. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/mobile.toml +1 -1
  67. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/onboard.toml +1 -1
  68. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/orchestrate.toml +1 -1
  69. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/plan.toml +1 -1
  70. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/refactor.toml +1 -1
  71. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/release.toml +1 -1
  72. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/review.toml +1 -1
  73. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/security.toml +1 -1
  74. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/spec.toml +1 -1
  75. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/test.toml +1 -1
  76. package/workflows/workflows/agent-environment-setup/platforms/gemini/commands/vercel.toml +1 -1
  77. package/workflows/workflows/agent-environment-setup/platforms/gemini/workflows/architecture.md +22 -19
  78. package/workflows/workflows/agent-environment-setup/platforms/gemini/workflows/spec.md +2 -2
  79. package/workflows/workflows/agent-environment-setup/shared/workflows/architecture.md +22 -19
  80. 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
- " - For non-trivial work, read PRODUCT.md, ENGINEERING_RULES.md, ARCHITECTURE.md, and TECH.md in that order when they exist.",
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
- "- Keep PRODUCT.md, ARCHITECTURE.md, ENGINEERING_RULES.md, and TECH.md aligned when direction or structure changes.",
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
- "5. For non-trivial work, read PRODUCT.md, ENGINEERING_RULES.md, ARCHITECTURE.md, and TECH.md in that order when they exist before planning or implementation.",
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, productProfileHash, architectureDocHash, rulesProfileHash, techSnapshotHash, roadmapProfileHash, }) {
1689
+ function buildArchitectureBuildMetadata({ platform, researchMode, managedDocs, }) {
1642
1690
  return {
1643
- schemaVersion: 2,
1691
+ schemaVersion: 3,
1644
1692
  generatedBy: "cbx build architecture",
1645
1693
  generatedAt: new Date().toISOString(),
1646
1694
  platform,
1647
1695
  researchMode,
1648
- productProfileHash,
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("- Use `cbx rules init` to scaffold ENGINEERING_RULES.md and TECH.md, or `cbx build architecture --platform <codex|claude|gemini|copilot>` to generate PRODUCT.md, ARCHITECTURE.md, ENGINEERING_RULES.md, TECH.md, ROADMAP.md, and ADR scaffolds.");
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 = "PRODUCT.md";
10448
- const architecturePath = "ARCHITECTURE.md";
10449
- const rulesPath = "ENGINEERING_RULES.md";
10450
- const techPath = "TECH.md";
10451
- const roadmapPath = "ROADMAP.md";
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 scalable project backbone in ${productPath}, ${architecturePath}, ${rulesPath}, ${techPath}, and ${roadmapPath}.`,
10464
- "- Keep PRODUCT.md focused on intent, ARCHITECTURE.md on accepted structure, ENGINEERING_RULES.md on normative rules, TECH.md on current-state evidence, and ROADMAP.md on delivery themes.",
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
- `1. Read ${productPath}, ${rulesPath}, ${architecturePath}, and ${techPath} in that order when they exist.`,
10487
- "2. Inspect the repo before making architecture claims.",
10488
- "3. Update only the content between the existing managed markers in the backbone docs and preserve the marker lines themselves, including their hash metadata.",
10489
- "4. In PRODUCT.md, state product scope, primary surfaces, users or operators, core journeys, success signals, and product guardrails.",
10490
- "5. In ARCHITECTURE.md, state accepted architecture style, bounded contexts, stable decision areas, ADR linkage, and add at least one Mermaid architecture diagram if the repo is non-trivial.",
10491
- "6. In ENGINEERING_RULES.md, state architecture style, dependency rules, feature or module structure rules, design-system source of truth, testability expectations, and doc refresh policy.",
10492
- "7. In TECH.md, update architecture snapshot, module or app topology, flow narratives, Mermaid diagrams, and scaling or deployment notes.",
10493
- "8. In ROADMAP.md, capture current delivery themes, active spec-driven work, and major architecture follow-ups without turning it into a speculative wishlist.",
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
- ? "9. Stay repo-only. Do not use outside research."
10496
- : "9. Use repo evidence first. Use official docs when needed. Treat Reddit or community sources only as labeled secondary evidence.",
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
- ? "10. Include an external research evidence subsection in TECH.md with clearly labeled primary and secondary evidence."
10499
- : "10. Include external research notes only if they materially informed the architecture update.",
10500
- "11. If the project clearly follows Clean Architecture, feature-first modules, or another stable structure, make that explicit so future implementation stays consistent.",
10501
- `12. Ensure ${adrReadmePath} exists as the ADR entrypoint and mention ADR follow-up when the repo lacks decision history.`,
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
- '{"files_written":["PRODUCT.md","ARCHITECTURE.md","ENGINEERING_RULES.md","TECH.md","ROADMAP.md","docs/adr/README.md"],"research_used":false,"gaps":[],"next_actions":[]}',
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 specRoots = await listSpecPackRoots(workspaceRoot);
10727
- const productPath = path.join(workspaceRoot, "PRODUCT.md");
10728
- const architecturePath = path.join(workspaceRoot, "ARCHITECTURE.md");
10729
- const rulesPath = path.join(workspaceRoot, "ENGINEERING_RULES.md");
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("PRODUCT.md is missing.");
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("PRODUCT.md is missing the managed product foundation block.");
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("ARCHITECTURE.md is missing.");
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("ARCHITECTURE.md is missing the managed architecture backbone block.");
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("TECH.md is missing.");
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("TECH.md is missing the managed architecture snapshot block.");
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("docs/adr/README.md is missing.");
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("Backbone docs: PRODUCT.md, ARCHITECTURE.md, ENGINEERING_RULES.md, TECH.md, ROADMAP.md, docs/adr/README.md");
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, "ENGINEERING_RULES.md"),
10891
- path.join(workspaceRoot, "TECH.md"),
10892
- path.join(workspaceRoot, "ROADMAP.md"),
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: ${toPosixPath(scaffold.engineeringRulesPath)}, ${toPosixPath(scaffold.techMdPath)}`);
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
- productProfileHash: extractTaggedMarkerAttribute(productContent, PRODUCT_FOUNDATION_BLOCK_START_RE, "profile") || "unknown",
10986
- architectureDocHash: extractTaggedMarkerAttribute(architectureContent, ARCHITECTURE_DOC_BLOCK_START_RE, "profile") || "unknown",
10987
- rulesProfileHash: extractTaggedMarkerAttribute(rulesContent, ENGINEERING_ARCHITECTURE_BLOCK_START_RE, "profile") || "unknown",
10988
- techSnapshotHash: extractTaggedMarkerAttribute(techContent, TECH_ARCHITECTURE_BLOCK_START_RE, "snapshot") || "unknown",
10989
- roadmapProfileHash: extractTaggedMarkerAttribute(roadmapContent, ROADMAP_FOUNDATION_BLOCK_START_RE, "profile") || "unknown",
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("Managed docs: PRODUCT.md, ARCHITECTURE.md, ENGINEERING_RULES.md, TECH.md, ROADMAP.md");
11012
- console.log("ADR scaffold: docs/adr/README.md, docs/adr/0000-template.md");
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"}`);