@cubis/foundry 0.3.78 → 0.3.79
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 +601 -54
- 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 +736 -54
- 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 +17 -12
- package/workflows/workflows/agent-environment-setup/platforms/antigravity/workflows/spec.md +2 -2
- package/workflows/workflows/agent-environment-setup/platforms/claude/workflows/architecture.md +17 -12
- package/workflows/workflows/agent-environment-setup/platforms/claude/workflows/spec.md +2 -2
- package/workflows/workflows/agent-environment-setup/platforms/codex/workflows/architecture.md +17 -12
- 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 +17 -12
- 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 +17 -12
- package/workflows/workflows/agent-environment-setup/platforms/gemini/workflows/spec.md +2 -2
- package/workflows/workflows/agent-environment-setup/shared/rules/STEERING.md +3 -3
- package/workflows/workflows/agent-environment-setup/shared/workflows/architecture.md +17 -12
- package/workflows/workflows/agent-environment-setup/shared/workflows/spec.md +2 -2
package/dist/cli/core.js
CHANGED
|
@@ -27,8 +27,14 @@ const ENGINEERING_RULES_FILE_BLOCK_START_RE = /<!--\s*cbx:engineering:rules:star
|
|
|
27
27
|
const ENGINEERING_RULES_FILE_BLOCK_END_RE = /<!--\s*cbx:engineering:rules:end\s*-->/g;
|
|
28
28
|
const ENGINEERING_ARCHITECTURE_BLOCK_START_RE = /<!--\s*cbx:architecture:rules:start[^>]*-->/g;
|
|
29
29
|
const ENGINEERING_ARCHITECTURE_BLOCK_END_RE = /<!--\s*cbx:architecture:rules:end\s*-->/g;
|
|
30
|
+
const PRODUCT_FOUNDATION_BLOCK_START_RE = /<!--\s*cbx:product:foundation:start[^>]*-->/g;
|
|
31
|
+
const PRODUCT_FOUNDATION_BLOCK_END_RE = /<!--\s*cbx:product:foundation:end\s*-->/g;
|
|
32
|
+
const ARCHITECTURE_DOC_BLOCK_START_RE = /<!--\s*cbx:architecture:doc:start[^>]*-->/g;
|
|
33
|
+
const ARCHITECTURE_DOC_BLOCK_END_RE = /<!--\s*cbx:architecture:doc:end\s*-->/g;
|
|
30
34
|
const TECH_ARCHITECTURE_BLOCK_START_RE = /<!--\s*cbx:architecture:tech:start[^>]*-->/g;
|
|
31
35
|
const TECH_ARCHITECTURE_BLOCK_END_RE = /<!--\s*cbx:architecture:tech:end\s*-->/g;
|
|
36
|
+
const ROADMAP_FOUNDATION_BLOCK_START_RE = /<!--\s*cbx:roadmap:foundation:start[^>]*-->/g;
|
|
37
|
+
const ROADMAP_FOUNDATION_BLOCK_END_RE = /<!--\s*cbx:roadmap:foundation:end\s*-->/g;
|
|
32
38
|
const COPILOT_ALLOWED_SKILL_FRONTMATTER_KEYS = new Set([
|
|
33
39
|
"compatibility",
|
|
34
40
|
"description",
|
|
@@ -954,6 +960,154 @@ function buildArchitectureMermaid(snapshot) {
|
|
|
954
960
|
}
|
|
955
961
|
return lines.join("\n");
|
|
956
962
|
}
|
|
963
|
+
function inferProductFoundationProfile(snapshot, specRoots = []) {
|
|
964
|
+
const appRoots = (snapshot.architectureByApp || [])
|
|
965
|
+
.map((item) => item.rootPath)
|
|
966
|
+
.filter((value) => value && value !== ".");
|
|
967
|
+
const primarySurfaces = appRoots.length > 0 ? appRoots : snapshot.topDirs.slice(0, 6);
|
|
968
|
+
const userPersonas = [];
|
|
969
|
+
if (snapshot.frameworks.includes("Flutter")) {
|
|
970
|
+
userPersonas.push("End users interacting through mobile or desktop app surfaces");
|
|
971
|
+
}
|
|
972
|
+
if (snapshot.frameworks.includes("Next.js") ||
|
|
973
|
+
snapshot.frameworks.includes("React") ||
|
|
974
|
+
snapshot.topDirs.includes("web")) {
|
|
975
|
+
userPersonas.push("Browser users and internal operators using web-facing flows");
|
|
976
|
+
}
|
|
977
|
+
if (snapshot.frameworks.includes("NestJS") || snapshot.topDirs.includes("api")) {
|
|
978
|
+
userPersonas.push("Internal services, operators, or partner systems consuming API boundaries");
|
|
979
|
+
}
|
|
980
|
+
if (userPersonas.length === 0) {
|
|
981
|
+
userPersonas.push("Project stakeholders are not obvious from the repo alone; refine personas from product context before major feature work.");
|
|
982
|
+
}
|
|
983
|
+
const coreJourneys = [];
|
|
984
|
+
if (specRoots.length > 0) {
|
|
985
|
+
coreJourneys.push(`Active implementation themes are reflected in current spec packs: ${specRoots.join(", ")}.`);
|
|
986
|
+
}
|
|
987
|
+
if (primarySurfaces.length > 0) {
|
|
988
|
+
coreJourneys.push(`Primary product surfaces currently live in: ${primarySurfaces.join(", ")}.`);
|
|
989
|
+
}
|
|
990
|
+
if (snapshot.isMcpServer || snapshot.mcpSignals.length > 0) {
|
|
991
|
+
coreJourneys.push("Tool-assisted and MCP-driven workflows are part of the operating model and should stay stable.");
|
|
992
|
+
}
|
|
993
|
+
if (coreJourneys.length === 0) {
|
|
994
|
+
coreJourneys.push("Repository evidence is thin; capture the primary user journeys here before scaling the codebase further.");
|
|
995
|
+
}
|
|
996
|
+
const successSignals = [
|
|
997
|
+
"Feature work should stay aligned to explicit user or operator value, not speculative abstractions.",
|
|
998
|
+
"Architecture changes should reduce onboarding, debugging, and testing cost over time.",
|
|
999
|
+
];
|
|
1000
|
+
if (snapshot.cicdSignals.length > 0) {
|
|
1001
|
+
successSignals.push(`Delivery flows already rely on ${snapshot.cicdSignals.join(", ")} signals; keep release friction low for that pipeline.`);
|
|
1002
|
+
}
|
|
1003
|
+
return {
|
|
1004
|
+
productScope: snapshot.readmeExcerpt ||
|
|
1005
|
+
"No explicit product summary was detected from repo docs. Replace this with a concise product statement when better context exists.",
|
|
1006
|
+
primarySurfaces,
|
|
1007
|
+
userPersonas,
|
|
1008
|
+
coreJourneys,
|
|
1009
|
+
successSignals,
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
function buildProductFoundationSection(snapshot, specRoots = []) {
|
|
1013
|
+
const profile = inferProductFoundationProfile(snapshot, specRoots);
|
|
1014
|
+
const hash = hashStableObject(profile);
|
|
1015
|
+
return [
|
|
1016
|
+
`<!-- cbx:product:foundation:start version=1 profile=${hash} -->`,
|
|
1017
|
+
"## Product Foundation (auto-managed)",
|
|
1018
|
+
"",
|
|
1019
|
+
"### Product Scope",
|
|
1020
|
+
profile.productScope,
|
|
1021
|
+
"",
|
|
1022
|
+
"### Primary Surfaces",
|
|
1023
|
+
...(profile.primarySurfaces.length > 0
|
|
1024
|
+
? profile.primarySurfaces.map((item) => `- ${item}`)
|
|
1025
|
+
: ["- No primary surfaces were detected automatically."]),
|
|
1026
|
+
"",
|
|
1027
|
+
"### Users and Operators",
|
|
1028
|
+
...profile.userPersonas.map((item) => `- ${item}`),
|
|
1029
|
+
"",
|
|
1030
|
+
"### Core Journeys",
|
|
1031
|
+
...profile.coreJourneys.map((item) => `- ${item}`),
|
|
1032
|
+
"",
|
|
1033
|
+
"### Success Signals",
|
|
1034
|
+
...profile.successSignals.map((item) => `- ${item}`),
|
|
1035
|
+
"",
|
|
1036
|
+
"### Product Guardrails",
|
|
1037
|
+
"- Keep product intent stable across future features so agents do not optimize for the wrong user outcome.",
|
|
1038
|
+
"- Refresh this managed section when scope, personas, operating model, or success metrics change materially.",
|
|
1039
|
+
"<!-- cbx:product:foundation:end -->",
|
|
1040
|
+
"",
|
|
1041
|
+
].join("\n");
|
|
1042
|
+
}
|
|
1043
|
+
function inferArchitectureDocProfile(snapshot, specRoots = []) {
|
|
1044
|
+
const contract = inferArchitectureContractProfile(snapshot);
|
|
1045
|
+
const architectureSignals = (snapshot.architectureByApp || []).map((item) => {
|
|
1046
|
+
const label = item.rootPath === "." ? "repo root" : item.rootPath;
|
|
1047
|
+
const signals = item.architectureSignals && item.architectureSignals.length > 0
|
|
1048
|
+
? item.architectureSignals.join(", ")
|
|
1049
|
+
: "not enough signals to classify";
|
|
1050
|
+
return `${label}: ${signals}`;
|
|
1051
|
+
});
|
|
1052
|
+
const decisionAreas = [
|
|
1053
|
+
"Module boundaries and dependency direction",
|
|
1054
|
+
"Design-system ownership and reusable primitives",
|
|
1055
|
+
"Testing and validation expectations by runtime boundary",
|
|
1056
|
+
];
|
|
1057
|
+
if (specRoots.length > 0) {
|
|
1058
|
+
decisionAreas.push(`Active specs that may influence upcoming architecture work: ${specRoots.join(", ")}.`);
|
|
1059
|
+
}
|
|
1060
|
+
return {
|
|
1061
|
+
style: contract.style,
|
|
1062
|
+
designSystemSource: contract.designSystemSource,
|
|
1063
|
+
moduleBoundaries: contract.moduleBoundaries,
|
|
1064
|
+
architectureSignals,
|
|
1065
|
+
decisionAreas,
|
|
1066
|
+
scalingConstraints: contract.scalingConstraints,
|
|
1067
|
+
testingStrategy: contract.testingStrategy,
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
function buildArchitectureDocSection(snapshot, specRoots = []) {
|
|
1071
|
+
const profile = inferArchitectureDocProfile(snapshot, specRoots);
|
|
1072
|
+
const hash = hashStableObject(profile);
|
|
1073
|
+
return [
|
|
1074
|
+
`<!-- cbx:architecture:doc:start version=1 profile=${hash} -->`,
|
|
1075
|
+
"## Accepted Architecture Backbone (auto-managed)",
|
|
1076
|
+
"",
|
|
1077
|
+
"### System Overview",
|
|
1078
|
+
`- Accepted style: ${profile.style}.`,
|
|
1079
|
+
`- Design-system source of truth: ${profile.designSystemSource}`,
|
|
1080
|
+
"",
|
|
1081
|
+
"### Bounded Contexts and Module Boundaries",
|
|
1082
|
+
...(profile.moduleBoundaries.length > 0
|
|
1083
|
+
? profile.moduleBoundaries.map((item) => `- ${item}`)
|
|
1084
|
+
: ["- No strong top-level module boundaries were detected automatically."]),
|
|
1085
|
+
"",
|
|
1086
|
+
"### Architecture Signals by Surface",
|
|
1087
|
+
...(profile.architectureSignals.length > 0
|
|
1088
|
+
? profile.architectureSignals.map((item) => `- ${item}`)
|
|
1089
|
+
: ["- No app-level architecture signals were inferred from the repo scan."]),
|
|
1090
|
+
"",
|
|
1091
|
+
"### Decision Areas to Preserve",
|
|
1092
|
+
...profile.decisionAreas.map((item) => `- ${item}`),
|
|
1093
|
+
"",
|
|
1094
|
+
"### Scalability and Reliability Notes",
|
|
1095
|
+
...profile.scalingConstraints.map((item) => `- ${item}`),
|
|
1096
|
+
"",
|
|
1097
|
+
"### Testing and Operability",
|
|
1098
|
+
...profile.testingStrategy.map((item) => `- ${item}`),
|
|
1099
|
+
"",
|
|
1100
|
+
"### ADR Linkage",
|
|
1101
|
+
"- Keep durable architecture decisions in `docs/adr/` and summarize the active decision set here.",
|
|
1102
|
+
"",
|
|
1103
|
+
"### Mermaid Diagram",
|
|
1104
|
+
"```mermaid",
|
|
1105
|
+
buildArchitectureDocMermaid(snapshot),
|
|
1106
|
+
"```",
|
|
1107
|
+
"<!-- cbx:architecture:doc:end -->",
|
|
1108
|
+
"",
|
|
1109
|
+
].join("\n");
|
|
1110
|
+
}
|
|
957
1111
|
function buildEngineeringArchitectureSection(snapshot) {
|
|
958
1112
|
const profile = inferArchitectureContractProfile(snapshot);
|
|
959
1113
|
const hash = hashStableObject(profile);
|
|
@@ -973,11 +1127,30 @@ function buildEngineeringArchitectureSection(snapshot) {
|
|
|
973
1127
|
...profile.testingStrategy.map((rule) => ` - ${rule}`),
|
|
974
1128
|
"- Doc refresh policy:",
|
|
975
1129
|
" - Update these managed sections when architecture, scale, boundaries, design-system rules, or testing strategy changes.",
|
|
976
|
-
" - For non-trivial work, read
|
|
1130
|
+
" - For non-trivial work, read PRODUCT.md, ENGINEERING_RULES.md, ARCHITECTURE.md, and TECH.md in that order when they exist.",
|
|
977
1131
|
"<!-- cbx:architecture:rules:end -->",
|
|
978
1132
|
"",
|
|
979
1133
|
].join("\n");
|
|
980
1134
|
}
|
|
1135
|
+
function buildArchitectureDocMermaid(snapshot) {
|
|
1136
|
+
const topDirs = snapshot.topDirs.slice(0, 5);
|
|
1137
|
+
const lines = [
|
|
1138
|
+
"flowchart LR",
|
|
1139
|
+
' product["Product Intent"] --> rules["Engineering Rules"]',
|
|
1140
|
+
' product --> arch["Architecture Backbone"]',
|
|
1141
|
+
' arch --> tech["Current Tech Snapshot"]',
|
|
1142
|
+
];
|
|
1143
|
+
if (topDirs.length > 0) {
|
|
1144
|
+
for (let index = 0; index < topDirs.length; index += 1) {
|
|
1145
|
+
const dir = topDirs[index];
|
|
1146
|
+
const nodeName = `D${index}`;
|
|
1147
|
+
lines.push(` arch --> ${nodeName}["${dir}/"]`);
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
lines.push(' arch --> adr["docs/adr"]');
|
|
1151
|
+
lines.push(' product --> specs["docs/specs"]');
|
|
1152
|
+
return lines.join("\n");
|
|
1153
|
+
}
|
|
981
1154
|
function buildTechArchitectureSection(snapshot) {
|
|
982
1155
|
const profile = inferArchitectureContractProfile(snapshot);
|
|
983
1156
|
const payload = {
|
|
@@ -1030,6 +1203,48 @@ function buildTechArchitectureSection(snapshot) {
|
|
|
1030
1203
|
"",
|
|
1031
1204
|
].join("\n");
|
|
1032
1205
|
}
|
|
1206
|
+
function buildRoadmapFoundationSection(snapshot, specRoots = []) {
|
|
1207
|
+
const payload = {
|
|
1208
|
+
topDirs: snapshot.topDirs,
|
|
1209
|
+
frameworks: snapshot.frameworks,
|
|
1210
|
+
specRoots,
|
|
1211
|
+
};
|
|
1212
|
+
const hash = hashStableObject(payload);
|
|
1213
|
+
const nowItems = specRoots.length > 0
|
|
1214
|
+
? specRoots.map((item) => `Track active change planning in \`${item}\`.`)
|
|
1215
|
+
: [
|
|
1216
|
+
"No active spec packs detected. Create a spec pack before starting the next non-trivial feature or migration.",
|
|
1217
|
+
];
|
|
1218
|
+
const nextItems = [];
|
|
1219
|
+
if (snapshot.frameworks.length > 0) {
|
|
1220
|
+
nextItems.push(`Keep shared conventions stable across the current stack: ${snapshot.frameworks.join(", ")}.`);
|
|
1221
|
+
}
|
|
1222
|
+
if (snapshot.cicdSignals.length > 0) {
|
|
1223
|
+
nextItems.push(`Preserve release compatibility with the detected delivery surfaces: ${snapshot.cicdSignals.join(", ")}.`);
|
|
1224
|
+
}
|
|
1225
|
+
if (nextItems.length === 0) {
|
|
1226
|
+
nextItems.push("Document the next scaling milestones here once product direction and architecture constraints are clearer.");
|
|
1227
|
+
}
|
|
1228
|
+
return [
|
|
1229
|
+
`<!-- cbx:roadmap:foundation:start version=1 profile=${hash} -->`,
|
|
1230
|
+
"## Delivery Backbone (auto-managed)",
|
|
1231
|
+
"",
|
|
1232
|
+
"### Now",
|
|
1233
|
+
...nowItems.map((item) => `- ${item}`),
|
|
1234
|
+
"",
|
|
1235
|
+
"### Next",
|
|
1236
|
+
...nextItems.map((item) => `- ${item}`),
|
|
1237
|
+
"",
|
|
1238
|
+
"### Later",
|
|
1239
|
+
"- Use this section for medium-term scaling themes, major migrations, or cross-team architecture investments.",
|
|
1240
|
+
"",
|
|
1241
|
+
"### Backbone Maintenance",
|
|
1242
|
+
"- Keep PRODUCT.md, ARCHITECTURE.md, ENGINEERING_RULES.md, and TECH.md aligned when direction or structure changes.",
|
|
1243
|
+
"- Link major roadmap themes back to specs and ADRs instead of burying them in chat-only planning.",
|
|
1244
|
+
"<!-- cbx:roadmap:foundation:end -->",
|
|
1245
|
+
"",
|
|
1246
|
+
].join("\n");
|
|
1247
|
+
}
|
|
1033
1248
|
function buildEngineeringRulesTemplate() {
|
|
1034
1249
|
return [
|
|
1035
1250
|
"# Engineering Rules",
|
|
@@ -1131,17 +1346,103 @@ function buildEngineeringRulesTemplate() {
|
|
|
1131
1346
|
"",
|
|
1132
1347
|
].join("\n");
|
|
1133
1348
|
}
|
|
1134
|
-
function
|
|
1349
|
+
function buildProductTemplate(snapshot, specRoots = []) {
|
|
1350
|
+
return [
|
|
1351
|
+
"# Product",
|
|
1352
|
+
"",
|
|
1353
|
+
"This file is the durable product backbone for the project.",
|
|
1354
|
+
"",
|
|
1355
|
+
buildProductFoundationSection(snapshot, specRoots).trimEnd(),
|
|
1356
|
+
"",
|
|
1357
|
+
].join("\n");
|
|
1358
|
+
}
|
|
1359
|
+
function buildArchitectureDocTemplate(snapshot, specRoots = []) {
|
|
1360
|
+
return [
|
|
1361
|
+
"# Architecture",
|
|
1362
|
+
"",
|
|
1363
|
+
"This file captures the accepted architecture backbone for the project.",
|
|
1364
|
+
"",
|
|
1365
|
+
buildArchitectureDocSection(snapshot, specRoots).trimEnd(),
|
|
1366
|
+
"",
|
|
1367
|
+
].join("\n");
|
|
1368
|
+
}
|
|
1369
|
+
function buildRoadmapTemplate(snapshot, specRoots = []) {
|
|
1370
|
+
return [
|
|
1371
|
+
"# Roadmap",
|
|
1372
|
+
"",
|
|
1373
|
+
"This file captures the living delivery backbone for medium-term product and architecture work.",
|
|
1374
|
+
"",
|
|
1375
|
+
buildRoadmapFoundationSection(snapshot, specRoots).trimEnd(),
|
|
1376
|
+
"",
|
|
1377
|
+
].join("\n");
|
|
1378
|
+
}
|
|
1379
|
+
function buildAdrReadme() {
|
|
1380
|
+
return [
|
|
1381
|
+
"# Architecture Decision Records",
|
|
1382
|
+
"",
|
|
1383
|
+
"Use this directory for durable decisions that future contributors and agents need to preserve.",
|
|
1384
|
+
"",
|
|
1385
|
+
"## When to add an ADR",
|
|
1386
|
+
"",
|
|
1387
|
+
"- Architecture style or boundary changes",
|
|
1388
|
+
"- Data model or persistence strategy changes",
|
|
1389
|
+
"- Deployment or scaling model changes",
|
|
1390
|
+
"- Design-system ownership or shared UX pattern changes",
|
|
1391
|
+
"",
|
|
1392
|
+
"## Suggested format",
|
|
1393
|
+
"",
|
|
1394
|
+
"1. Context",
|
|
1395
|
+
"2. Decision",
|
|
1396
|
+
"3. Consequences",
|
|
1397
|
+
"4. Validation",
|
|
1398
|
+
"",
|
|
1399
|
+
"Start with `0000-template.md` and create numbered follow-up ADRs for accepted decisions.",
|
|
1400
|
+
"",
|
|
1401
|
+
].join("\n");
|
|
1402
|
+
}
|
|
1403
|
+
function buildAdrTemplate() {
|
|
1404
|
+
return [
|
|
1405
|
+
"# ADR 0000: Title",
|
|
1406
|
+
"",
|
|
1407
|
+
"## Status",
|
|
1408
|
+
"",
|
|
1409
|
+
"Proposed",
|
|
1410
|
+
"",
|
|
1411
|
+
"## Context",
|
|
1412
|
+
"",
|
|
1413
|
+
"- What problem or pressure led to this decision?",
|
|
1414
|
+
"",
|
|
1415
|
+
"## Decision",
|
|
1416
|
+
"",
|
|
1417
|
+
"- What is the chosen direction?",
|
|
1418
|
+
"",
|
|
1419
|
+
"## Consequences",
|
|
1420
|
+
"",
|
|
1421
|
+
"- What tradeoffs, benefits, or costs follow from this choice?",
|
|
1422
|
+
"",
|
|
1423
|
+
"## Validation",
|
|
1424
|
+
"",
|
|
1425
|
+
"- How will the team know this decision is working?",
|
|
1426
|
+
"",
|
|
1427
|
+
].join("\n");
|
|
1428
|
+
}
|
|
1429
|
+
function buildEngineeringRulesManagedBlock({ platform, productFilePath, architectureFilePath, engineeringRulesFilePath, techMdFilePath, roadmapFilePath, ruleFilePath, }) {
|
|
1430
|
+
const productRef = toPosixPath(path.resolve(productFilePath));
|
|
1431
|
+
const architectureRef = toPosixPath(path.resolve(architectureFilePath));
|
|
1135
1432
|
const engineeringRef = toPosixPath(path.resolve(engineeringRulesFilePath));
|
|
1136
1433
|
const techRef = toPosixPath(path.resolve(techMdFilePath));
|
|
1434
|
+
const roadmapRef = toPosixPath(path.resolve(roadmapFilePath));
|
|
1137
1435
|
const ruleRef = toPosixPath(path.resolve(ruleFilePath));
|
|
1138
1436
|
return [
|
|
1139
1437
|
`<!-- cbx:engineering:auto:start platform=${platform} version=1 -->`,
|
|
1140
1438
|
"## Engineering Guardrails (auto-managed)",
|
|
1141
1439
|
"Apply these before planning, coding, review, and release:",
|
|
1142
1440
|
"",
|
|
1441
|
+
`- Product backbone: \`${productRef}\``,
|
|
1442
|
+
`- Accepted architecture: \`${architectureRef}\``,
|
|
1143
1443
|
`- Required baseline: \`${engineeringRef}\``,
|
|
1144
1444
|
`- Project tech map: \`${techRef}\``,
|
|
1445
|
+
`- Delivery roadmap: \`${roadmapRef}\``,
|
|
1145
1446
|
`- Active platform rule file: \`${ruleRef}\``,
|
|
1146
1447
|
"",
|
|
1147
1448
|
"Hard policy:",
|
|
@@ -1149,7 +1450,7 @@ function buildEngineeringRulesManagedBlock({ platform, engineeringRulesFilePath,
|
|
|
1149
1450
|
"2. Keep architecture simple (KISS) and avoid speculative work (YAGNI).",
|
|
1150
1451
|
"3. Apply SOLID pragmatically to reduce change risk, not add ceremony.",
|
|
1151
1452
|
"4. Use clear naming with focused responsibilities and explicit boundaries.",
|
|
1152
|
-
"5. For non-trivial work, read ENGINEERING_RULES.md
|
|
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.",
|
|
1153
1454
|
"6. Require validation evidence (lint/types/tests) before merge.",
|
|
1154
1455
|
"7. Use Decision Log response style.",
|
|
1155
1456
|
"8. Every Decision Log must include a `Skills Used` section listing skill, workflow, or agent names.",
|
|
@@ -1240,11 +1541,14 @@ async function upsertEngineeringRulesFile({ targetPath, template, overwrite = fa
|
|
|
1240
1541
|
filePath: targetPath,
|
|
1241
1542
|
};
|
|
1242
1543
|
}
|
|
1243
|
-
async function upsertEngineeringRulesBlock({ ruleFilePath, platform, engineeringRulesFilePath, techMdFilePath, dryRun = false, }) {
|
|
1544
|
+
async function upsertEngineeringRulesBlock({ ruleFilePath, platform, productFilePath, architectureFilePath, engineeringRulesFilePath, techMdFilePath, roadmapFilePath, dryRun = false, }) {
|
|
1244
1545
|
const block = buildEngineeringRulesManagedBlock({
|
|
1245
1546
|
platform,
|
|
1547
|
+
productFilePath,
|
|
1548
|
+
architectureFilePath,
|
|
1246
1549
|
engineeringRulesFilePath,
|
|
1247
1550
|
techMdFilePath,
|
|
1551
|
+
roadmapFilePath,
|
|
1248
1552
|
ruleFilePath,
|
|
1249
1553
|
});
|
|
1250
1554
|
const exists = await pathExists(ruleFilePath);
|
|
@@ -1334,20 +1638,45 @@ async function upsertTaggedSectionInFile({ targetPath, initialContent, block, st
|
|
|
1334
1638
|
filePath: targetPath,
|
|
1335
1639
|
};
|
|
1336
1640
|
}
|
|
1337
|
-
function buildArchitectureBuildMetadata({ platform, researchMode, rulesProfileHash, techSnapshotHash, }) {
|
|
1641
|
+
function buildArchitectureBuildMetadata({ platform, researchMode, productProfileHash, architectureDocHash, rulesProfileHash, techSnapshotHash, roadmapProfileHash, }) {
|
|
1338
1642
|
return {
|
|
1339
|
-
schemaVersion:
|
|
1643
|
+
schemaVersion: 2,
|
|
1340
1644
|
generatedBy: "cbx build architecture",
|
|
1341
1645
|
generatedAt: new Date().toISOString(),
|
|
1342
1646
|
platform,
|
|
1343
1647
|
researchMode,
|
|
1648
|
+
productProfileHash,
|
|
1649
|
+
architectureDocHash,
|
|
1344
1650
|
rulesProfileHash,
|
|
1345
1651
|
techSnapshotHash,
|
|
1652
|
+
roadmapProfileHash,
|
|
1346
1653
|
};
|
|
1347
1654
|
}
|
|
1348
|
-
async function ensureArchitectureDocScaffold({ workspaceRoot, snapshot, overwrite = false, dryRun = false, }) {
|
|
1655
|
+
async function ensureArchitectureDocScaffold({ workspaceRoot, snapshot, specRoots = [], overwrite = false, dryRun = false, }) {
|
|
1656
|
+
const productPath = path.join(workspaceRoot, "PRODUCT.md");
|
|
1657
|
+
const architectureDocPath = path.join(workspaceRoot, "ARCHITECTURE.md");
|
|
1349
1658
|
const engineeringRulesPath = path.join(workspaceRoot, "ENGINEERING_RULES.md");
|
|
1350
1659
|
const techMdPath = path.join(workspaceRoot, "TECH.md");
|
|
1660
|
+
const roadmapPath = path.join(workspaceRoot, "ROADMAP.md");
|
|
1661
|
+
const adrDir = path.join(workspaceRoot, "docs", "adr");
|
|
1662
|
+
const adrReadmePath = path.join(adrDir, "README.md");
|
|
1663
|
+
const adrTemplatePath = path.join(adrDir, "0000-template.md");
|
|
1664
|
+
const productResult = await upsertTaggedSectionInFile({
|
|
1665
|
+
targetPath: productPath,
|
|
1666
|
+
initialContent: `${buildProductTemplate(snapshot, specRoots)}\n`,
|
|
1667
|
+
block: buildProductFoundationSection(snapshot, specRoots),
|
|
1668
|
+
startPattern: PRODUCT_FOUNDATION_BLOCK_START_RE,
|
|
1669
|
+
endPattern: PRODUCT_FOUNDATION_BLOCK_END_RE,
|
|
1670
|
+
dryRun,
|
|
1671
|
+
});
|
|
1672
|
+
const architectureDocResult = await upsertTaggedSectionInFile({
|
|
1673
|
+
targetPath: architectureDocPath,
|
|
1674
|
+
initialContent: `${buildArchitectureDocTemplate(snapshot, specRoots)}\n`,
|
|
1675
|
+
block: buildArchitectureDocSection(snapshot, specRoots),
|
|
1676
|
+
startPattern: ARCHITECTURE_DOC_BLOCK_START_RE,
|
|
1677
|
+
endPattern: ARCHITECTURE_DOC_BLOCK_END_RE,
|
|
1678
|
+
dryRun,
|
|
1679
|
+
});
|
|
1351
1680
|
const rulesTemplate = buildEngineeringRulesTemplate();
|
|
1352
1681
|
const rulesFileResult = await upsertEngineeringRulesFile({
|
|
1353
1682
|
targetPath: engineeringRulesPath,
|
|
@@ -1378,13 +1707,43 @@ async function ensureArchitectureDocScaffold({ workspaceRoot, snapshot, overwrit
|
|
|
1378
1707
|
endPattern: TECH_ARCHITECTURE_BLOCK_END_RE,
|
|
1379
1708
|
dryRun,
|
|
1380
1709
|
});
|
|
1710
|
+
const roadmapResult = await upsertTaggedSectionInFile({
|
|
1711
|
+
targetPath: roadmapPath,
|
|
1712
|
+
initialContent: `${buildRoadmapTemplate(snapshot, specRoots)}\n`,
|
|
1713
|
+
block: buildRoadmapFoundationSection(snapshot, specRoots),
|
|
1714
|
+
startPattern: ROADMAP_FOUNDATION_BLOCK_START_RE,
|
|
1715
|
+
endPattern: ROADMAP_FOUNDATION_BLOCK_END_RE,
|
|
1716
|
+
dryRun,
|
|
1717
|
+
});
|
|
1718
|
+
const adrReadmeResult = await writeTextFile({
|
|
1719
|
+
targetPath: adrReadmePath,
|
|
1720
|
+
content: `${buildAdrReadme()}\n`,
|
|
1721
|
+
overwrite,
|
|
1722
|
+
dryRun,
|
|
1723
|
+
});
|
|
1724
|
+
const adrTemplateResult = await writeTextFile({
|
|
1725
|
+
targetPath: adrTemplatePath,
|
|
1726
|
+
content: `${buildAdrTemplate()}\n`,
|
|
1727
|
+
overwrite,
|
|
1728
|
+
dryRun,
|
|
1729
|
+
});
|
|
1381
1730
|
return {
|
|
1731
|
+
productPath,
|
|
1732
|
+
architectureDocPath,
|
|
1382
1733
|
engineeringRulesPath,
|
|
1383
1734
|
techMdPath,
|
|
1735
|
+
roadmapPath,
|
|
1736
|
+
adrReadmePath,
|
|
1737
|
+
adrTemplatePath,
|
|
1738
|
+
productResult,
|
|
1739
|
+
architectureDocResult,
|
|
1384
1740
|
rulesFileResult,
|
|
1385
1741
|
rulesArchitectureResult,
|
|
1386
1742
|
techResult,
|
|
1387
1743
|
techArchitectureResult,
|
|
1744
|
+
roadmapResult,
|
|
1745
|
+
adrReadmeResult,
|
|
1746
|
+
adrTemplateResult,
|
|
1388
1747
|
};
|
|
1389
1748
|
}
|
|
1390
1749
|
function normalizeTechPackageName(value) {
|
|
@@ -6958,14 +7317,6 @@ async function performWorkflowInstall(options, { postmanSelectionOverride = null
|
|
|
6958
7317
|
dryRun,
|
|
6959
7318
|
cwd,
|
|
6960
7319
|
});
|
|
6961
|
-
const engineeringArtifactsResult = await upsertEngineeringArtifacts({
|
|
6962
|
-
platform,
|
|
6963
|
-
scope: ruleScope,
|
|
6964
|
-
overwrite: false,
|
|
6965
|
-
dryRun,
|
|
6966
|
-
skipTech: false,
|
|
6967
|
-
cwd,
|
|
6968
|
-
});
|
|
6969
7320
|
const postmanSetupResult = await configurePostmanInstallArtifacts({
|
|
6970
7321
|
platform,
|
|
6971
7322
|
scope,
|
|
@@ -7007,7 +7358,7 @@ async function performWorkflowInstall(options, { postmanSelectionOverride = null
|
|
|
7007
7358
|
bundleId,
|
|
7008
7359
|
installResult,
|
|
7009
7360
|
syncResult,
|
|
7010
|
-
engineeringArtifactsResult,
|
|
7361
|
+
engineeringArtifactsResult: null,
|
|
7011
7362
|
postmanSetupResult,
|
|
7012
7363
|
terminalVerificationRuleResult,
|
|
7013
7364
|
};
|
|
@@ -7035,10 +7386,7 @@ async function runWorkflowInstall(options) {
|
|
|
7035
7386
|
dryRun: result.dryRun,
|
|
7036
7387
|
});
|
|
7037
7388
|
printRuleSyncResult(result.syncResult);
|
|
7038
|
-
|
|
7039
|
-
engineeringResults: result.engineeringArtifactsResult.engineeringResults,
|
|
7040
|
-
techResult: result.engineeringArtifactsResult.techResult,
|
|
7041
|
-
});
|
|
7389
|
+
printInstallDocumentationNotice();
|
|
7042
7390
|
printPostmanSetupSummary({
|
|
7043
7391
|
postmanSetup: result.postmanSetupResult,
|
|
7044
7392
|
});
|
|
@@ -9897,6 +10245,11 @@ function printInstallEngineeringSummary({ engineeringResults, techResult }) {
|
|
|
9897
10245
|
console.log(`- TECH scan files: ${techResult.snapshot.scannedFiles}`);
|
|
9898
10246
|
}
|
|
9899
10247
|
}
|
|
10248
|
+
function printInstallDocumentationNotice() {
|
|
10249
|
+
console.log("\nProject backbone docs:");
|
|
10250
|
+
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.");
|
|
10252
|
+
}
|
|
9900
10253
|
async function upsertEngineeringArtifacts({ platform, scope, overwrite = false, skipTech = false, dryRun = false, cwd = process.cwd(), }) {
|
|
9901
10254
|
const ruleFilePath = await resolveRuleFilePath(platform, scope, cwd);
|
|
9902
10255
|
if (!ruleFilePath)
|
|
@@ -9906,10 +10259,10 @@ async function upsertEngineeringArtifacts({ platform, scope, overwrite = false,
|
|
|
9906
10259
|
const scaffold = await ensureArchitectureDocScaffold({
|
|
9907
10260
|
workspaceRoot,
|
|
9908
10261
|
snapshot,
|
|
10262
|
+
specRoots: [],
|
|
9909
10263
|
overwrite,
|
|
9910
10264
|
dryRun,
|
|
9911
10265
|
});
|
|
9912
|
-
const techMdPath = path.join(workspaceRoot, "TECH.md");
|
|
9913
10266
|
const targets = [{ ruleFilePath }];
|
|
9914
10267
|
if (scope === "global") {
|
|
9915
10268
|
const workspaceRuleFile = await resolveWorkspaceRuleFileForGlobalScope(platform, cwd);
|
|
@@ -9924,8 +10277,11 @@ async function upsertEngineeringArtifacts({ platform, scope, overwrite = false,
|
|
|
9924
10277
|
const blockResult = await upsertEngineeringRulesBlock({
|
|
9925
10278
|
ruleFilePath: target.ruleFilePath,
|
|
9926
10279
|
platform,
|
|
10280
|
+
productFilePath: scaffold.productPath,
|
|
10281
|
+
architectureFilePath: scaffold.architectureDocPath,
|
|
9927
10282
|
engineeringRulesFilePath: scaffold.engineeringRulesPath,
|
|
9928
|
-
techMdFilePath: techMdPath,
|
|
10283
|
+
techMdFilePath: scaffold.techMdPath,
|
|
10284
|
+
roadmapFilePath: scaffold.roadmapPath,
|
|
9929
10285
|
dryRun,
|
|
9930
10286
|
});
|
|
9931
10287
|
engineeringResults.push({
|
|
@@ -10088,8 +10444,12 @@ async function resolveArchitectureSkillPathHints(platform, cwd, skillIds) {
|
|
|
10088
10444
|
.map((filePath) => toPosixPath(path.relative(findWorkspaceRoot(cwd), filePath)));
|
|
10089
10445
|
}
|
|
10090
10446
|
function buildArchitecturePrompt({ platform, workspaceRoot, snapshot, specRoots, researchMode, coreSkills, conditionalSkills, skillPathHints, }) {
|
|
10447
|
+
const productPath = "PRODUCT.md";
|
|
10448
|
+
const architecturePath = "ARCHITECTURE.md";
|
|
10091
10449
|
const rulesPath = "ENGINEERING_RULES.md";
|
|
10092
10450
|
const techPath = "TECH.md";
|
|
10451
|
+
const roadmapPath = "ROADMAP.md";
|
|
10452
|
+
const adrReadmePath = "docs/adr/README.md";
|
|
10093
10453
|
const architectureSignals = snapshot.architectureByApp
|
|
10094
10454
|
.filter((item) => (item.architectureSignals || []).length > 0)
|
|
10095
10455
|
.map((item) => {
|
|
@@ -10100,9 +10460,9 @@ function buildArchitecturePrompt({ platform, workspaceRoot, snapshot, specRoots,
|
|
|
10100
10460
|
`You are running inside ${platform}.`,
|
|
10101
10461
|
"",
|
|
10102
10462
|
"Objective:",
|
|
10103
|
-
`- Inspect the repository at ${toPosixPath(workspaceRoot)} and refresh the
|
|
10104
|
-
"- Keep ENGINEERING_RULES.md normative
|
|
10105
|
-
"- Preserve manual content outside the managed `cbx
|
|
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.",
|
|
10465
|
+
"- Preserve manual content outside the managed `cbx:*` markers.",
|
|
10106
10466
|
"",
|
|
10107
10467
|
"Required skill bundle:",
|
|
10108
10468
|
`- Load these exact skill IDs first: ${coreSkills.map((skillId) => `\`${skillId}\``).join(", ")}`,
|
|
@@ -10123,22 +10483,25 @@ function buildArchitecturePrompt({ platform, workspaceRoot, snapshot, specRoots,
|
|
|
10123
10483
|
: "- Architecture signals: none confidently inferred from the repo scan",
|
|
10124
10484
|
"",
|
|
10125
10485
|
"Execution contract:",
|
|
10126
|
-
|
|
10486
|
+
`1. Read ${productPath}, ${rulesPath}, ${architecturePath}, and ${techPath} in that order when they exist.`,
|
|
10127
10487
|
"2. Inspect the repo before making architecture claims.",
|
|
10128
|
-
"3. Update only the content between the existing
|
|
10129
|
-
"4.
|
|
10130
|
-
"5. In
|
|
10131
|
-
"6. In
|
|
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.",
|
|
10132
10494
|
researchMode === "never"
|
|
10133
|
-
? "
|
|
10134
|
-
: "
|
|
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.",
|
|
10135
10497
|
researchMode === "always"
|
|
10136
|
-
? "
|
|
10137
|
-
: "
|
|
10138
|
-
"
|
|
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.`,
|
|
10139
10502
|
"",
|
|
10140
10503
|
"Return one JSON object on the last line with this shape:",
|
|
10141
|
-
'{"files_written":["ENGINEERING_RULES.md","TECH.md"],"research_used":false,"gaps":[],"next_actions":[]}',
|
|
10504
|
+
'{"files_written":["PRODUCT.md","ARCHITECTURE.md","ENGINEERING_RULES.md","TECH.md","ROADMAP.md","docs/adr/README.md"],"research_used":false,"gaps":[],"next_actions":[]}',
|
|
10142
10505
|
"",
|
|
10143
10506
|
"Do not emit placeholder TODOs in the managed sections.",
|
|
10144
10507
|
].join("\n");
|
|
@@ -10167,6 +10530,73 @@ async function execFileCapture(command, args, options = {}) {
|
|
|
10167
10530
|
};
|
|
10168
10531
|
}
|
|
10169
10532
|
}
|
|
10533
|
+
async function spawnCapture(command, args, options = {}) {
|
|
10534
|
+
const { cwd, env, streamOutput = false } = options;
|
|
10535
|
+
return await new Promise((resolve, reject) => {
|
|
10536
|
+
let stdout = "";
|
|
10537
|
+
let stderr = "";
|
|
10538
|
+
const child = spawn(command, args, {
|
|
10539
|
+
cwd,
|
|
10540
|
+
env,
|
|
10541
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
10542
|
+
});
|
|
10543
|
+
child.stdout.on("data", (chunk) => {
|
|
10544
|
+
const text = chunk.toString();
|
|
10545
|
+
stdout += text;
|
|
10546
|
+
if (streamOutput)
|
|
10547
|
+
process.stdout.write(text);
|
|
10548
|
+
});
|
|
10549
|
+
child.stderr.on("data", (chunk) => {
|
|
10550
|
+
const text = chunk.toString();
|
|
10551
|
+
stderr += text;
|
|
10552
|
+
if (streamOutput)
|
|
10553
|
+
process.stderr.write(text);
|
|
10554
|
+
});
|
|
10555
|
+
child.on("error", (error) => {
|
|
10556
|
+
if (error?.code === "ENOENT") {
|
|
10557
|
+
reject(new Error(`Required CLI '${command}' is not installed or not on PATH.`));
|
|
10558
|
+
return;
|
|
10559
|
+
}
|
|
10560
|
+
reject(error);
|
|
10561
|
+
});
|
|
10562
|
+
child.on("close", (code) => {
|
|
10563
|
+
resolve({
|
|
10564
|
+
ok: code === 0,
|
|
10565
|
+
stdout,
|
|
10566
|
+
stderr,
|
|
10567
|
+
code: code ?? 1,
|
|
10568
|
+
});
|
|
10569
|
+
});
|
|
10570
|
+
});
|
|
10571
|
+
}
|
|
10572
|
+
function explainArchitectureBuildFailure(platform, execution) {
|
|
10573
|
+
const combined = String(`${execution.stderr || ""}\n${execution.stdout || ""}`.trim());
|
|
10574
|
+
const notes = [];
|
|
10575
|
+
if (platform === "gemini") {
|
|
10576
|
+
if (combined.includes("Error during discovery for MCP server") ||
|
|
10577
|
+
combined.includes("[MCP error]")) {
|
|
10578
|
+
notes.push("Gemini CLI is failing while loading MCP servers from your Gemini settings. Start the required MCP runtime(s) first or disable the broken server entries in `.gemini/settings.json` before retrying.");
|
|
10579
|
+
}
|
|
10580
|
+
if (combined.includes("cloudaicompanion.companions.generateChat") ||
|
|
10581
|
+
combined.includes("PERMISSION_DENIED") ||
|
|
10582
|
+
combined.includes("403")) {
|
|
10583
|
+
notes.push("Gemini CLI reached Google auth, but the active account or project cannot generate chat content. Re-authenticate Gemini CLI with a permitted account or configure a supported Gemini API credential and project before retrying.");
|
|
10584
|
+
}
|
|
10585
|
+
}
|
|
10586
|
+
if (platform === "claude" && combined.includes("permission")) {
|
|
10587
|
+
notes.push("Claude CLI appears to be blocked by its own permission model. Re-run in a Claude environment that allows non-interactive edits for this workspace.");
|
|
10588
|
+
}
|
|
10589
|
+
if (notes.length === 0) {
|
|
10590
|
+
return `Architecture build failed via ${platform}. ${combined}`.trim();
|
|
10591
|
+
}
|
|
10592
|
+
return [
|
|
10593
|
+
`Architecture build failed via ${platform}.`,
|
|
10594
|
+
...notes.map((note) => `- ${note}`),
|
|
10595
|
+
combined ? `Raw CLI output:\n${combined}` : "",
|
|
10596
|
+
]
|
|
10597
|
+
.filter(Boolean)
|
|
10598
|
+
.join("\n");
|
|
10599
|
+
}
|
|
10170
10600
|
async function probeArchitectureAdapter(platform, cwd) {
|
|
10171
10601
|
if (platform === "codex") {
|
|
10172
10602
|
const help = await execFileCapture("codex", ["exec", "--help"], { cwd });
|
|
@@ -10242,7 +10672,7 @@ async function probeArchitectureAdapter(platform, cwd) {
|
|
|
10242
10672
|
},
|
|
10243
10673
|
};
|
|
10244
10674
|
}
|
|
10245
|
-
function normalizeArchitectureResult({ stdout, workspaceRoot,
|
|
10675
|
+
function normalizeArchitectureResult({ stdout, workspaceRoot, researchMode, changedFiles = [], }) {
|
|
10246
10676
|
const trimmed = String(stdout || "").trim();
|
|
10247
10677
|
if (trimmed) {
|
|
10248
10678
|
const lastLine = trimmed.split(/\r?\n/).pop();
|
|
@@ -10251,9 +10681,11 @@ function normalizeArchitectureResult({ stdout, workspaceRoot, rulesPath, techPat
|
|
|
10251
10681
|
const parsed = JSON.parse(lastLine);
|
|
10252
10682
|
return {
|
|
10253
10683
|
outputRoot: workspaceRoot,
|
|
10254
|
-
filesWritten:
|
|
10255
|
-
?
|
|
10256
|
-
:
|
|
10684
|
+
filesWritten: changedFiles.length > 0
|
|
10685
|
+
? changedFiles
|
|
10686
|
+
: Array.isArray(parsed.files_written)
|
|
10687
|
+
? parsed.files_written
|
|
10688
|
+
: [],
|
|
10257
10689
|
researchUsed: typeof parsed.research_used === "boolean"
|
|
10258
10690
|
? parsed.research_used
|
|
10259
10691
|
: researchMode === "always",
|
|
@@ -10271,19 +10703,42 @@ function normalizeArchitectureResult({ stdout, workspaceRoot, rulesPath, techPat
|
|
|
10271
10703
|
}
|
|
10272
10704
|
return {
|
|
10273
10705
|
outputRoot: workspaceRoot,
|
|
10274
|
-
filesWritten:
|
|
10706
|
+
filesWritten: changedFiles,
|
|
10275
10707
|
researchUsed: researchMode === "always",
|
|
10276
10708
|
gaps: [],
|
|
10277
10709
|
nextActions: [],
|
|
10278
10710
|
rawOutput: trimmed,
|
|
10279
10711
|
};
|
|
10280
10712
|
}
|
|
10713
|
+
async function captureFileContents(filePaths) {
|
|
10714
|
+
const snapshot = {};
|
|
10715
|
+
for (const filePath of filePaths) {
|
|
10716
|
+
if (await pathExists(filePath)) {
|
|
10717
|
+
snapshot[filePath] = await readFile(filePath, "utf8");
|
|
10718
|
+
}
|
|
10719
|
+
else {
|
|
10720
|
+
snapshot[filePath] = null;
|
|
10721
|
+
}
|
|
10722
|
+
}
|
|
10723
|
+
return snapshot;
|
|
10724
|
+
}
|
|
10281
10725
|
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");
|
|
10282
10729
|
const rulesPath = path.join(workspaceRoot, "ENGINEERING_RULES.md");
|
|
10283
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");
|
|
10284
10733
|
const metadataPath = path.join(workspaceRoot, ".cbx", ARCHITECTURE_BUILD_METADATA_FILENAME);
|
|
10734
|
+
const productExists = await pathExists(productPath);
|
|
10735
|
+
const architectureExists = await pathExists(architecturePath);
|
|
10285
10736
|
const rulesExists = await pathExists(rulesPath);
|
|
10286
10737
|
const techExists = await pathExists(techPath);
|
|
10738
|
+
const roadmapExists = await pathExists(roadmapPath);
|
|
10739
|
+
const adrReadmeExists = await pathExists(adrReadmePath);
|
|
10740
|
+
const expectedProductHash = hashStableObject(inferProductFoundationProfile(snapshot, specRoots));
|
|
10741
|
+
const expectedArchitectureHash = hashStableObject(inferArchitectureDocProfile(snapshot, specRoots));
|
|
10287
10742
|
const expectedRulesHash = hashStableObject(inferArchitectureContractProfile(snapshot));
|
|
10288
10743
|
const expectedTechHash = hashStableObject({
|
|
10289
10744
|
style: inferArchitectureContractProfile(snapshot).style,
|
|
@@ -10291,9 +10746,43 @@ async function readArchitectureDriftStatus(workspaceRoot, snapshot) {
|
|
|
10291
10746
|
frameworks: snapshot.frameworks,
|
|
10292
10747
|
architectureByApp: snapshot.architectureByApp,
|
|
10293
10748
|
});
|
|
10749
|
+
const expectedRoadmapHash = hashStableObject({
|
|
10750
|
+
topDirs: snapshot.topDirs,
|
|
10751
|
+
frameworks: snapshot.frameworks,
|
|
10752
|
+
specRoots,
|
|
10753
|
+
});
|
|
10294
10754
|
const findings = [];
|
|
10755
|
+
let actualProductHash = null;
|
|
10756
|
+
let actualArchitectureHash = null;
|
|
10295
10757
|
let actualRulesHash = null;
|
|
10296
10758
|
let actualTechHash = null;
|
|
10759
|
+
let actualRoadmapHash = null;
|
|
10760
|
+
if (!productExists) {
|
|
10761
|
+
findings.push("PRODUCT.md is missing.");
|
|
10762
|
+
}
|
|
10763
|
+
else {
|
|
10764
|
+
const content = await readFile(productPath, "utf8");
|
|
10765
|
+
actualProductHash = extractTaggedMarkerAttribute(content, PRODUCT_FOUNDATION_BLOCK_START_RE, "profile");
|
|
10766
|
+
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}).`);
|
|
10771
|
+
}
|
|
10772
|
+
}
|
|
10773
|
+
if (!architectureExists) {
|
|
10774
|
+
findings.push("ARCHITECTURE.md is missing.");
|
|
10775
|
+
}
|
|
10776
|
+
else {
|
|
10777
|
+
const content = await readFile(architecturePath, "utf8");
|
|
10778
|
+
actualArchitectureHash = extractTaggedMarkerAttribute(content, ARCHITECTURE_DOC_BLOCK_START_RE, "profile");
|
|
10779
|
+
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
|
+
}
|
|
10297
10786
|
if (!rulesExists) {
|
|
10298
10787
|
findings.push("ENGINEERING_RULES.md is missing.");
|
|
10299
10788
|
}
|
|
@@ -10320,6 +10809,22 @@ async function readArchitectureDriftStatus(workspaceRoot, snapshot) {
|
|
|
10320
10809
|
findings.push(`TECH.md architecture snapshot is stale (expected ${expectedTechHash}, found ${actualTechHash}).`);
|
|
10321
10810
|
}
|
|
10322
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}).`);
|
|
10823
|
+
}
|
|
10824
|
+
}
|
|
10825
|
+
if (!adrReadmeExists) {
|
|
10826
|
+
findings.push("docs/adr/README.md is missing.");
|
|
10827
|
+
}
|
|
10323
10828
|
const metadata = await readJsonFileIfExists(metadataPath);
|
|
10324
10829
|
if (!metadata.exists) {
|
|
10325
10830
|
findings.push("Architecture build metadata is missing.");
|
|
@@ -10327,13 +10832,23 @@ async function readArchitectureDriftStatus(workspaceRoot, snapshot) {
|
|
|
10327
10832
|
return {
|
|
10328
10833
|
stale: findings.length > 0,
|
|
10329
10834
|
findings,
|
|
10835
|
+
productPath,
|
|
10836
|
+
architecturePath,
|
|
10330
10837
|
rulesPath,
|
|
10331
10838
|
techPath,
|
|
10839
|
+
roadmapPath,
|
|
10840
|
+
adrReadmePath,
|
|
10332
10841
|
metadataPath,
|
|
10842
|
+
expectedProductHash,
|
|
10843
|
+
expectedArchitectureHash,
|
|
10333
10844
|
expectedRulesHash,
|
|
10334
10845
|
expectedTechHash,
|
|
10846
|
+
expectedRoadmapHash,
|
|
10847
|
+
actualProductHash,
|
|
10848
|
+
actualArchitectureHash,
|
|
10335
10849
|
actualRulesHash,
|
|
10336
10850
|
actualTechHash,
|
|
10851
|
+
actualRoadmapHash,
|
|
10337
10852
|
};
|
|
10338
10853
|
}
|
|
10339
10854
|
async function runBuildArchitecture(options) {
|
|
@@ -10347,6 +10862,7 @@ async function runBuildArchitecture(options) {
|
|
|
10347
10862
|
const cwd = process.cwd();
|
|
10348
10863
|
const workspaceRoot = findWorkspaceRoot(cwd);
|
|
10349
10864
|
const snapshot = await collectTechSnapshot(workspaceRoot);
|
|
10865
|
+
const specRoots = await listSpecPackRoots(workspaceRoot);
|
|
10350
10866
|
if (checkOnly) {
|
|
10351
10867
|
const drift = await readArchitectureDriftStatus(workspaceRoot, snapshot);
|
|
10352
10868
|
if (emitJson) {
|
|
@@ -10356,6 +10872,7 @@ async function runBuildArchitecture(options) {
|
|
|
10356
10872
|
console.log(`Platform: ${platform}`);
|
|
10357
10873
|
console.log(`Workspace: ${toPosixPath(workspaceRoot)}`);
|
|
10358
10874
|
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");
|
|
10359
10876
|
if (drift.findings.length > 0) {
|
|
10360
10877
|
console.log("Findings:");
|
|
10361
10878
|
for (const finding of drift.findings) {
|
|
@@ -10367,13 +10884,25 @@ async function runBuildArchitecture(options) {
|
|
|
10367
10884
|
process.exit(1);
|
|
10368
10885
|
return;
|
|
10369
10886
|
}
|
|
10887
|
+
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"),
|
|
10895
|
+
];
|
|
10896
|
+
const filesBefore = dryRun
|
|
10897
|
+
? Object.fromEntries(managedFilePaths.map((filePath) => [filePath, null]))
|
|
10898
|
+
: await captureFileContents(managedFilePaths);
|
|
10370
10899
|
const scaffold = await ensureArchitectureDocScaffold({
|
|
10371
10900
|
workspaceRoot,
|
|
10372
10901
|
snapshot,
|
|
10902
|
+
specRoots,
|
|
10373
10903
|
overwrite,
|
|
10374
10904
|
dryRun,
|
|
10375
10905
|
});
|
|
10376
|
-
const specRoots = await listSpecPackRoots(workspaceRoot);
|
|
10377
10906
|
const coreSkills = [
|
|
10378
10907
|
"architecture-doc",
|
|
10379
10908
|
"system-design",
|
|
@@ -10403,8 +10932,13 @@ async function runBuildArchitecture(options) {
|
|
|
10403
10932
|
invocation: [adapter.binary, ...args],
|
|
10404
10933
|
researchMode,
|
|
10405
10934
|
managedTargets: [
|
|
10935
|
+
toPosixPath(scaffold.productPath),
|
|
10936
|
+
toPosixPath(scaffold.architectureDocPath),
|
|
10406
10937
|
toPosixPath(scaffold.engineeringRulesPath),
|
|
10407
10938
|
toPosixPath(scaffold.techMdPath),
|
|
10939
|
+
toPosixPath(scaffold.roadmapPath),
|
|
10940
|
+
toPosixPath(scaffold.adrReadmePath),
|
|
10941
|
+
toPosixPath(scaffold.adrTemplatePath),
|
|
10408
10942
|
],
|
|
10409
10943
|
skillBundle,
|
|
10410
10944
|
};
|
|
@@ -10422,30 +10956,45 @@ async function runBuildArchitecture(options) {
|
|
|
10422
10956
|
}
|
|
10423
10957
|
return;
|
|
10424
10958
|
}
|
|
10425
|
-
|
|
10959
|
+
if (!emitJson) {
|
|
10960
|
+
console.log(`Streaming ${adapter.binary} output...`);
|
|
10961
|
+
}
|
|
10962
|
+
const execution = await spawnCapture(adapter.binary, args, {
|
|
10426
10963
|
cwd: workspaceRoot,
|
|
10427
10964
|
env: process.env,
|
|
10965
|
+
streamOutput: !emitJson,
|
|
10428
10966
|
});
|
|
10429
10967
|
if (!execution.ok) {
|
|
10430
|
-
throw new Error(
|
|
10431
|
-
}
|
|
10432
|
-
const
|
|
10433
|
-
const
|
|
10968
|
+
throw new Error(explainArchitectureBuildFailure(platform, execution));
|
|
10969
|
+
}
|
|
10970
|
+
const filesAfter = await captureFileContents(managedFilePaths);
|
|
10971
|
+
const changedFiles = managedFilePaths
|
|
10972
|
+
.filter((filePath) => filesBefore[filePath] !== filesAfter[filePath])
|
|
10973
|
+
.map((filePath) => toPosixPath(path.relative(workspaceRoot, filePath)));
|
|
10974
|
+
const rulesContent = filesAfter[scaffold.engineeringRulesPath] ??
|
|
10975
|
+
(await readFile(scaffold.engineeringRulesPath, "utf8"));
|
|
10976
|
+
const techContent = filesAfter[scaffold.techMdPath] ?? (await readFile(scaffold.techMdPath, "utf8"));
|
|
10977
|
+
const productContent = filesAfter[scaffold.productPath] ?? (await readFile(scaffold.productPath, "utf8"));
|
|
10978
|
+
const architectureContent = filesAfter[scaffold.architectureDocPath] ??
|
|
10979
|
+
(await readFile(scaffold.architectureDocPath, "utf8"));
|
|
10980
|
+
const roadmapContent = filesAfter[scaffold.roadmapPath] ?? (await readFile(scaffold.roadmapPath, "utf8"));
|
|
10434
10981
|
const metadataPath = path.join(workspaceRoot, ".cbx", ARCHITECTURE_BUILD_METADATA_FILENAME);
|
|
10435
10982
|
const metadata = buildArchitectureBuildMetadata({
|
|
10436
10983
|
platform,
|
|
10437
10984
|
researchMode,
|
|
10985
|
+
productProfileHash: extractTaggedMarkerAttribute(productContent, PRODUCT_FOUNDATION_BLOCK_START_RE, "profile") || "unknown",
|
|
10986
|
+
architectureDocHash: extractTaggedMarkerAttribute(architectureContent, ARCHITECTURE_DOC_BLOCK_START_RE, "profile") || "unknown",
|
|
10438
10987
|
rulesProfileHash: extractTaggedMarkerAttribute(rulesContent, ENGINEERING_ARCHITECTURE_BLOCK_START_RE, "profile") || "unknown",
|
|
10439
10988
|
techSnapshotHash: extractTaggedMarkerAttribute(techContent, TECH_ARCHITECTURE_BLOCK_START_RE, "snapshot") || "unknown",
|
|
10989
|
+
roadmapProfileHash: extractTaggedMarkerAttribute(roadmapContent, ROADMAP_FOUNDATION_BLOCK_START_RE, "profile") || "unknown",
|
|
10440
10990
|
});
|
|
10441
10991
|
await mkdir(path.dirname(metadataPath), { recursive: true });
|
|
10442
10992
|
await writeFile(metadataPath, `${JSON.stringify(metadata, null, 2)}\n`, "utf8");
|
|
10443
10993
|
const result = normalizeArchitectureResult({
|
|
10444
10994
|
stdout: execution.stdout,
|
|
10445
10995
|
workspaceRoot: toPosixPath(workspaceRoot),
|
|
10446
|
-
rulesPath: "ENGINEERING_RULES.md",
|
|
10447
|
-
techPath: "TECH.md",
|
|
10448
10996
|
researchMode,
|
|
10997
|
+
changedFiles: [...new Set(changedFiles)],
|
|
10449
10998
|
});
|
|
10450
10999
|
if (emitJson) {
|
|
10451
11000
|
console.log(JSON.stringify({
|
|
@@ -10459,7 +11008,8 @@ async function runBuildArchitecture(options) {
|
|
|
10459
11008
|
console.log(`Platform: ${platform}`);
|
|
10460
11009
|
console.log(`Adapter: ${adapter.binary}`);
|
|
10461
11010
|
console.log(`Workspace: ${toPosixPath(workspaceRoot)}`);
|
|
10462
|
-
console.log(
|
|
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");
|
|
10463
11013
|
console.log(`Skill bundle: ${skillBundle.join(", ")}`);
|
|
10464
11014
|
console.log(`Files written: ${(result.filesWritten || []).join(", ") || "(none reported)"}`);
|
|
10465
11015
|
console.log(`Research used: ${result.researchUsed ? "yes" : "no"}`);
|
|
@@ -10680,10 +11230,7 @@ async function runInitWizard(options) {
|
|
|
10680
11230
|
dryRun: installOutcome.dryRun,
|
|
10681
11231
|
});
|
|
10682
11232
|
printRuleSyncResult(installOutcome.syncResult);
|
|
10683
|
-
|
|
10684
|
-
engineeringResults: installOutcome.engineeringArtifactsResult.engineeringResults,
|
|
10685
|
-
techResult: installOutcome.engineeringArtifactsResult.techResult,
|
|
10686
|
-
});
|
|
11233
|
+
printInstallDocumentationNotice();
|
|
10687
11234
|
printPostmanSetupSummary({
|
|
10688
11235
|
postmanSetup: installOutcome.postmanSetupResult,
|
|
10689
11236
|
});
|