@thebackstoryis/engineering-with-ai 0.2.9

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 (334) hide show
  1. package/Docs/README.md +50 -0
  2. package/Docs/adoption/consultancy-and-multi-project-rollout.md +135 -0
  3. package/Docs/adoption/non-technical-team-guide.md +126 -0
  4. package/Docs/archaeology-technology-and-hosting-discovery.md +212 -0
  5. package/Docs/blast-radius-and-impact-routing-guide.md +325 -0
  6. package/Docs/blueprints/internal-blueprint-catalogue.md +146 -0
  7. package/Docs/blueprints/maintaining-organisation-blueprints.md +154 -0
  8. package/Docs/blueprints/validation-and-troubleshooting.md +168 -0
  9. package/Docs/cli-reference.md +113 -0
  10. package/Docs/completed-phase-evidence-amendments.md +74 -0
  11. package/Docs/consultancy-network-rollout-control-plane-guide.md +202 -0
  12. package/Docs/context-aware-delivery-companion-guide.md +198 -0
  13. package/Docs/context-aware-delivery-companion-user-guide.md +184 -0
  14. package/Docs/context-management-and-token-efficiency.md +113 -0
  15. package/Docs/design-systems/design-system-implementation-guide.md +85 -0
  16. package/Docs/design-systems/design-system-pack-authoring-guide.md +95 -0
  17. package/Docs/design-systems/design-system-review-guide.md +51 -0
  18. package/Docs/design-systems/design-system-user-guide.md +96 -0
  19. package/Docs/design-systems/product-owner-guide.md +49 -0
  20. package/Docs/designing-organisation-blueprint-packs.md +384 -0
  21. package/Docs/developer-delivery-guide.md +224 -0
  22. package/Docs/error-reporting-guide.md +110 -0
  23. package/Docs/error-reporting-provider-guide.md +49 -0
  24. package/Docs/examples/error-report-adapter.md +70 -0
  25. package/Docs/examples/meeting-review.md +76 -0
  26. package/Docs/examples/minimal-design-system.md +67 -0
  27. package/Docs/examples/prototype-review-inputs.md +175 -0
  28. package/Docs/examples/reproducible-archaeology-depth-example.md +144 -0
  29. package/Docs/examples/test-scenario-input.md +68 -0
  30. package/Docs/examples/worked-examples.md +147 -0
  31. package/Docs/existing-project-onboarding-guide.md +214 -0
  32. package/Docs/explanation/core-concepts.md +26 -0
  33. package/Docs/explanation/delivery-workflow.md +48 -0
  34. package/Docs/governance/governance-team-guide.md +139 -0
  35. package/Docs/governed-starter-project-materialisation-guide.md +284 -0
  36. package/Docs/guide-catalogue.md +117 -0
  37. package/Docs/guided-discovery-facilitator-guide.md +172 -0
  38. package/Docs/guided-intent-workspace-guide.md +109 -0
  39. package/Docs/guided-phase-evidence-drafting-guide.md +119 -0
  40. package/Docs/human-approval-and-assurance-guide.md +146 -0
  41. package/Docs/knowledge-proposals-implementer-guide.md +106 -0
  42. package/Docs/knowledge-proposals-user-guide.md +247 -0
  43. package/Docs/maintainers/context-benchmarks.md +29 -0
  44. package/Docs/maintainers/contributing.md +58 -0
  45. package/Docs/maintainers/evidence-depth-acceptance.md +72 -0
  46. package/Docs/maintainers/verification-walkthroughs.md +104 -0
  47. package/Docs/meeting-evidence-implementer-guide.md +132 -0
  48. package/Docs/meeting-evidence-user-guide.md +200 -0
  49. package/Docs/operations/dashboard-and-delivery-state.md +153 -0
  50. package/Docs/operations/dashboard-configuration.md +87 -0
  51. package/Docs/operations/installation-updating-and-entitlements.md +135 -0
  52. package/Docs/operations/premium-personas-setup.md +76 -0
  53. package/Docs/operations/troubleshooting-and-recovery.md +205 -0
  54. package/Docs/organisation-rollout-guide.md +142 -0
  55. package/Docs/persona-entitlement-provider-guide.md +199 -0
  56. package/Docs/persona-guided-prototype-iteration.md +129 -0
  57. package/Docs/personas/organisation-specific-personas.md +103 -0
  58. package/Docs/personas/persona-authoring-cookbook.md +176 -0
  59. package/Docs/personas/persona-engagement-ui.md +133 -0
  60. package/Docs/personas/persona-governance.md +118 -0
  61. package/Docs/platform-export-analysis-guide.md +336 -0
  62. package/Docs/policies/governance-owner-guide.md +36 -0
  63. package/Docs/policies/implementation-guide.md +42 -0
  64. package/Docs/policies/organisation-policy-design-gates.md +58 -0
  65. package/Docs/policies/policy-pack-authoring-guide.md +108 -0
  66. package/Docs/policies/product-owner-guide.md +43 -0
  67. package/Docs/policies/technical-owner-guide.md +37 -0
  68. package/Docs/product-owner-guide.md +327 -0
  69. package/Docs/project-portfolio-orchestration-guide.md +199 -0
  70. package/Docs/quality/manual-qa-and-acceptance.md +162 -0
  71. package/Docs/quality/persona-driven-test-scenarios.md +172 -0
  72. package/Docs/quality/reproducible-archaeology-depth-review-checklist.md +89 -0
  73. package/Docs/reference/capabilities-and-project-layout.md +678 -0
  74. package/Docs/reference/cli-and-configuration.md +398 -0
  75. package/Docs/reference/contributions-api.md +23 -0
  76. package/Docs/reference/security-adapter-authoring.md +81 -0
  77. package/Docs/reference/starter-adapter-authoring.md +74 -0
  78. package/Docs/repository-source-map-guide.md +381 -0
  79. package/Docs/reproducible-archaeology-and-discovery-depth.md +292 -0
  80. package/Docs/screen-prototype-creation-guide.md +324 -0
  81. package/Docs/security-validation-guide.md +353 -0
  82. package/Docs/solution-readiness-review-guide.md +123 -0
  83. package/Docs/standards/project-standards-authoring.md +157 -0
  84. package/Docs/team-hub-guide.md +162 -0
  85. package/Docs/team-hub-resource-registry-guide.md +167 -0
  86. package/Docs/tutorials/first-delivery.md +83 -0
  87. package/Docs/tutorials/first-session.md +62 -0
  88. package/Docs/using-lifecycle-hooks.md +381 -0
  89. package/Docs/working-with-personas.md +274 -0
  90. package/LICENSE +165 -0
  91. package/README.md +96 -0
  92. package/agents-src/claude/ewai-security-reviewer.md +15 -0
  93. package/bin/ewai +5 -0
  94. package/config/archaeology-record-families.yaml +59 -0
  95. package/config/delivery-artifacts.yaml +121 -0
  96. package/config/delivery-stages.yaml +77 -0
  97. package/config/design-system.schema.json +46 -0
  98. package/config/error-reporting.schema.json +79 -0
  99. package/config/evidence-depth.schema.json +53 -0
  100. package/config/intent.schema.json +90 -0
  101. package/config/knowledge-proposals-proposal.schema.json +34 -0
  102. package/config/lifecycle-event.schema.json +68 -0
  103. package/config/lifecycle-handler.schema.json +45 -0
  104. package/config/lifecycle-hook-ack.schema.json +19 -0
  105. package/config/meeting-evidence-candidate.schema.json +102 -0
  106. package/config/organisation-policy.schema.json +137 -0
  107. package/config/pack.schema.json +250 -0
  108. package/config/persona-pack.schema.json +21 -0
  109. package/config/persona.schema.json +17 -0
  110. package/config/policy-evaluation.schema.json +77 -0
  111. package/config/policy-facts.schema.json +140 -0
  112. package/config/portfolio.schema.json +68 -0
  113. package/config/project.schema.json +313 -0
  114. package/config/prototype-iteration.schema.json +128 -0
  115. package/config/rollout.schema.json +87 -0
  116. package/config/security-adapter.schema.json +31 -0
  117. package/config/security-scan-request.schema.json +64 -0
  118. package/config/security-scan-response.schema.json +52 -0
  119. package/config/security-validation-policy.schema.json +74 -0
  120. package/config/starter-source-acknowledgement.schema.json +13 -0
  121. package/config/starter-source-adapter.schema.json +38 -0
  122. package/config/starter-source-request.schema.json +61 -0
  123. package/package.json +77 -0
  124. package/packs/core/pack.yaml +7 -0
  125. package/packs/design-systems/default/experience-promise.md +9 -0
  126. package/packs/design-systems/default/intentional-review.md +10 -0
  127. package/packs/design-systems/default/interaction-and-entry.md +9 -0
  128. package/packs/design-systems/default/meaningful-content-and-states.md +9 -0
  129. package/packs/design-systems/default/pack.yaml +44 -0
  130. package/packs/design-systems/default/principles.md +10 -0
  131. package/packs/personas/core/pack.yaml +7 -0
  132. package/packs/personas/core/personas/archaeologist.md +37 -0
  133. package/packs/personas/core/personas/end-user.md +17 -0
  134. package/packs/personas/core/personas/maintainer.md +17 -0
  135. package/packs/personas/core/personas/operator.md +17 -0
  136. package/packs/personas/core/personas/specs-knowledge-curator.md +35 -0
  137. package/packs/technologies/laravel/pack.yaml +30 -0
  138. package/packs/technologies/laravel-nuxt/pack.yaml +30 -0
  139. package/packs/technologies/nuxt/pack.yaml +30 -0
  140. package/packs/technologies/power-platform/pack.yaml +31 -0
  141. package/packs/technologies/salesforce/pack.yaml +25 -0
  142. package/public/app.js +4896 -0
  143. package/public/apple-touch-icon.png +0 -0
  144. package/public/assets/backstory-icon.png +0 -0
  145. package/public/dashboard-navigation.js +98 -0
  146. package/public/favicon-16.png +0 -0
  147. package/public/favicon-32.png +0 -0
  148. package/public/favicon.ico +0 -0
  149. package/public/index.html +789 -0
  150. package/public/styles.css +2693 -0
  151. package/public/team-hub/app.js +202 -0
  152. package/public/team-hub/index.html +79 -0
  153. package/public/team-hub/styles.css +90 -0
  154. package/scripts/publication-check.mjs +140 -0
  155. package/scripts/setup.mjs +21 -0
  156. package/skills-src/ewai-archaeology/SKILL.md +334 -0
  157. package/skills-src/ewai-archaeology/agents/openai.yaml +4 -0
  158. package/skills-src/ewai-archaeology/references/archaeology-contract.md +201 -0
  159. package/skills-src/ewai-archaeology/references/lifecycle-reconstruction.md +177 -0
  160. package/skills-src/ewai-archaeology/references/maximum-detail-reconstruction.md +97 -0
  161. package/skills-src/ewai-archaeology/references/model-routing.md +26 -0
  162. package/skills-src/ewai-architecture/SKILL.md +108 -0
  163. package/skills-src/ewai-architecture/agents/openai.yaml +4 -0
  164. package/skills-src/ewai-architecture/references/architecture-contract.md +176 -0
  165. package/skills-src/ewai-context/SKILL.md +68 -0
  166. package/skills-src/ewai-context/agents/openai.yaml +4 -0
  167. package/skills-src/ewai-context-import/SKILL.md +118 -0
  168. package/skills-src/ewai-context-import/agents/openai.yaml +4 -0
  169. package/skills-src/ewai-context-import/references/context-import-contract.md +106 -0
  170. package/skills-src/ewai-dashboard-configuration/SKILL.md +20 -0
  171. package/skills-src/ewai-deliver/SKILL.md +122 -0
  172. package/skills-src/ewai-deliver/references/delivery-evidence.md +92 -0
  173. package/skills-src/ewai-deliver/references/phase-routing.md +31 -0
  174. package/skills-src/ewai-design-system-apply/SKILL.md +27 -0
  175. package/skills-src/ewai-design-system-apply/agents/openai.yaml +4 -0
  176. package/skills-src/ewai-design-system-apply/references/application-contract.md +36 -0
  177. package/skills-src/ewai-design-system-author/SKILL.md +28 -0
  178. package/skills-src/ewai-design-system-author/agents/openai.yaml +4 -0
  179. package/skills-src/ewai-design-system-author/references/authoring-contract.md +38 -0
  180. package/skills-src/ewai-design-system-review/SKILL.md +26 -0
  181. package/skills-src/ewai-design-system-review/agents/openai.yaml +4 -0
  182. package/skills-src/ewai-design-system-review/references/review-contract.md +40 -0
  183. package/skills-src/ewai-error-reporting/SKILL.md +46 -0
  184. package/skills-src/ewai-error-reporting/agents/openai.yaml +4 -0
  185. package/skills-src/ewai-error-reporting/references/provider-contract.md +74 -0
  186. package/skills-src/ewai-evidence-depth/SKILL.md +72 -0
  187. package/skills-src/ewai-evidence-depth/agents/openai.yaml +4 -0
  188. package/skills-src/ewai-evidence-depth/references/evidence-depth-contract.md +127 -0
  189. package/skills-src/ewai-intent/SKILL.md +68 -0
  190. package/skills-src/ewai-intent/agents/openai.yaml +4 -0
  191. package/skills-src/ewai-intent/references/intent-contract.md +42 -0
  192. package/skills-src/ewai-knowledge-proposals/SKILL.md +105 -0
  193. package/skills-src/ewai-knowledge-proposals/agents/openai.yaml +4 -0
  194. package/skills-src/ewai-knowledge-proposals/references/proposal-contract.md +59 -0
  195. package/skills-src/ewai-meeting-evidence/SKILL.md +106 -0
  196. package/skills-src/ewai-meeting-evidence/agents/openai.yaml +4 -0
  197. package/skills-src/ewai-meeting-evidence/references/candidate-contract.md +64 -0
  198. package/skills-src/ewai-organisation-policy/SKILL.md +62 -0
  199. package/skills-src/ewai-organisation-policy/agents/openai.yaml +4 -0
  200. package/skills-src/ewai-organisation-policy/references/policy-contract.md +94 -0
  201. package/skills-src/ewai-palace-housekeeping/SKILL.md +55 -0
  202. package/skills-src/ewai-palace-housekeeping/agents/openai.yaml +4 -0
  203. package/skills-src/ewai-persona-entitlement/SKILL.md +60 -0
  204. package/skills-src/ewai-persona-entitlement/agents/openai.yaml +4 -0
  205. package/skills-src/ewai-phase-evidence/SKILL.md +79 -0
  206. package/skills-src/ewai-phase-evidence/agents/openai.yaml +4 -0
  207. package/skills-src/ewai-pipeline/SKILL.md +130 -0
  208. package/skills-src/ewai-pipeline/agents/openai.yaml +4 -0
  209. package/skills-src/ewai-pipeline/references/cli.md +86 -0
  210. package/skills-src/ewai-pipeline/references/specs-contract.md +16 -0
  211. package/skills-src/ewai-portfolio/SKILL.md +70 -0
  212. package/skills-src/ewai-portfolio/agents/openai.yaml +4 -0
  213. package/skills-src/ewai-portfolio/references/portfolio-contract.md +67 -0
  214. package/skills-src/ewai-project-discovery/SKILL.md +95 -0
  215. package/skills-src/ewai-project-discovery/agents/openai.yaml +4 -0
  216. package/skills-src/ewai-project-discovery/references/discovery-contract.md +34 -0
  217. package/skills-src/ewai-prototype-iteration/SKILL.md +30 -0
  218. package/skills-src/ewai-prototype-iteration/agents/openai.yaml +4 -0
  219. package/skills-src/ewai-prototype-iteration/references/review-contract.md +49 -0
  220. package/skills-src/ewai-retro/SKILL.md +48 -0
  221. package/skills-src/ewai-retro/agents/openai.yaml +4 -0
  222. package/skills-src/ewai-retro/references/asset-routing.md +14 -0
  223. package/skills-src/ewai-rollout/SKILL.md +74 -0
  224. package/skills-src/ewai-rollout/agents/openai.yaml +4 -0
  225. package/skills-src/ewai-rollout/references/rollout-contract.md +74 -0
  226. package/skills-src/ewai-shape-intents/SKILL.md +84 -0
  227. package/skills-src/ewai-shape-intents/agents/openai.yaml +4 -0
  228. package/skills-src/ewai-shape-intents/references/intent-mapping-contract.md +109 -0
  229. package/skills-src/ewai-solution-readiness/SKILL.md +55 -0
  230. package/skills-src/ewai-solution-readiness/agents/openai.yaml +4 -0
  231. package/skills-src/ewai-standards-check/SKILL.md +93 -0
  232. package/skills-src/ewai-standards-check/agents/openai.yaml +4 -0
  233. package/skills-src/ewai-standards-check/references/report-contract.md +116 -0
  234. package/skills-src/ewai-test-scenarios/SKILL.md +94 -0
  235. package/skills-src/ewai-test-scenarios/agents/openai.yaml +4 -0
  236. package/skills-src/ewai-test-scenarios/references/scenario-contract.md +88 -0
  237. package/src/afk-worker.mjs +16 -0
  238. package/src/archaeology.mjs +1333 -0
  239. package/src/checkin.mjs +261 -0
  240. package/src/cli.mjs +2427 -0
  241. package/src/companion-guidance.mjs +257 -0
  242. package/src/companion-opening.mjs +62 -0
  243. package/src/companion.mjs +256 -0
  244. package/src/context.mjs +210 -0
  245. package/src/dashboard-preferences.mjs +80 -0
  246. package/src/delivery-artifacts.mjs +204 -0
  247. package/src/delivery-documents.mjs +248 -0
  248. package/src/delivery-gates.mjs +317 -0
  249. package/src/delivery.mjs +1433 -0
  250. package/src/design-system-application.mjs +291 -0
  251. package/src/design-system-authoring.mjs +101 -0
  252. package/src/design-systems.mjs +466 -0
  253. package/src/discovery.mjs +1314 -0
  254. package/src/error-reporting.mjs +323 -0
  255. package/src/evidence-depth.mjs +543 -0
  256. package/src/execution-state.mjs +243 -0
  257. package/src/install.mjs +166 -0
  258. package/src/intent-dependencies.mjs +117 -0
  259. package/src/intent-maps.mjs +402 -0
  260. package/src/intents.mjs +747 -0
  261. package/src/knowledge-proposals.mjs +717 -0
  262. package/src/launcher.mjs +51 -0
  263. package/src/meeting-evidence.mjs +703 -0
  264. package/src/network-rollout.mjs +386 -0
  265. package/src/organisation-blueprints.mjs +438 -0
  266. package/src/organisation-policies.mjs +448 -0
  267. package/src/packs.mjs +44 -0
  268. package/src/paths.mjs +62 -0
  269. package/src/persona-entitlements.mjs +438 -0
  270. package/src/persona-licence-config.mjs +98 -0
  271. package/src/persona-website-provider.mjs +134 -0
  272. package/src/persona-zip.mjs +87 -0
  273. package/src/personas.mjs +159 -0
  274. package/src/platform-metadata-analysis.mjs +314 -0
  275. package/src/policy-design-gates.mjs +623 -0
  276. package/src/policy-gate-integration.mjs +318 -0
  277. package/src/portfolio.mjs +509 -0
  278. package/src/power-platform-source-map.mjs +190 -0
  279. package/src/project.mjs +449 -0
  280. package/src/prototype-iterations.mjs +730 -0
  281. package/src/repository-source-map.mjs +603 -0
  282. package/src/runtime/afk-conductor.mjs +973 -0
  283. package/src/runtime/context-assembly.mjs +457 -0
  284. package/src/runtime/context-benchmarks.mjs +115 -0
  285. package/src/runtime/dashboard-actions.mjs +109 -0
  286. package/src/runtime/dashboard-handoffs.mjs +149 -0
  287. package/src/runtime/dashboard-server.mjs +1272 -0
  288. package/src/runtime/dashboard.mjs +197 -0
  289. package/src/runtime/database.mjs +789 -0
  290. package/src/runtime/error-reporting.mjs +581 -0
  291. package/src/runtime/evidence-depth-workspace.mjs +412 -0
  292. package/src/runtime/execution-leases.mjs +299 -0
  293. package/src/runtime/guided-discovery.mjs +350 -0
  294. package/src/runtime/guided-intents.mjs +517 -0
  295. package/src/runtime/impact-analysis.mjs +535 -0
  296. package/src/runtime/intents.mjs +222 -0
  297. package/src/runtime/knowledge.mjs +86 -0
  298. package/src/runtime/lifecycle-hooks.mjs +1239 -0
  299. package/src/runtime/mcp-config.mjs +110 -0
  300. package/src/runtime/mcp-server.mjs +1885 -0
  301. package/src/runtime/palace.mjs +362 -0
  302. package/src/runtime/paths.mjs +58 -0
  303. package/src/runtime/persona-engagement.mjs +255 -0
  304. package/src/runtime/phase-contributions.mjs +594 -0
  305. package/src/runtime/policy-workspace.mjs +170 -0
  306. package/src/runtime/prototype-iterations.mjs +235 -0
  307. package/src/runtime/provider-adapters.mjs +163 -0
  308. package/src/runtime/repository-index.mjs +838 -0
  309. package/src/runtime/runs.mjs +185 -0
  310. package/src/runtime/security-validation.mjs +1230 -0
  311. package/src/runtime/starter-materialisation.mjs +1155 -0
  312. package/src/runtime/team-hub-client.mjs +479 -0
  313. package/src/runtime/team-hub-database.mjs +288 -0
  314. package/src/runtime/team-hub-server.mjs +191 -0
  315. package/src/runtime/team-hub.mjs +110 -0
  316. package/src/runtime/tree-sitter-index.mjs +390 -0
  317. package/src/runtime/version.mjs +1 -0
  318. package/src/runtime/work.mjs +633 -0
  319. package/src/salesforce-source-map.mjs +212 -0
  320. package/src/security-validation-config.mjs +224 -0
  321. package/src/solution-readiness.mjs +620 -0
  322. package/src/starter-materialisation-contract.mjs +407 -0
  323. package/src/task-graph.mjs +544 -0
  324. package/src/team-hub-resources.mjs +239 -0
  325. package/src/team-hub.mjs +242 -0
  326. package/src/test-scenarios.mjs +622 -0
  327. package/src/validation-config.mjs +289 -0
  328. package/templates/SPECS/1.Scope/personas/registry.yaml +12 -0
  329. package/templates/SPECS/5.Strategy/patterns/context-packet.md +119 -0
  330. package/templates/SPECS/6.Build/_tracker-template.md +16 -0
  331. package/templates/SPECS/pipeline.yaml +62 -0
  332. package/templates/discovery-answers.yaml +86 -0
  333. package/templates/intent-body.md +21 -0
  334. package/tests/fixtures/context-benchmarks.json +9 -0
@@ -0,0 +1,402 @@
1
+ import { existsSync, readFileSync, rmSync } from 'node:fs';
2
+ import { extname, relative, resolve } from 'node:path';
3
+ import YAML from 'yaml';
4
+ import { atomicJson, atomicText, now } from './delivery-documents.mjs';
5
+ import { createIntent, intentRelationshipTypes } from './intents.mjs';
6
+ import { loadProjectConfig } from './project.mjs';
7
+ import { validatePersonaRef } from './personas.mjs';
8
+ import { syncIntentIndex } from './runtime/intents.mjs';
9
+
10
+ const slugPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
11
+ const intentReferencePattern = /^[a-z0-9]+(?:-[a-z0-9]+)*\/[a-z0-9]+(?:-[a-z0-9]+)*$/;
12
+ const deliveryShapeRecommendations = ['single', 'split', 'decision-required'];
13
+
14
+ function text(value, fallback = '') {
15
+ if (value === undefined || value === null) return fallback;
16
+ return String(value).trim();
17
+ }
18
+
19
+ function list(value) {
20
+ if (Array.isArray(value)) return value.map((item) => text(item)).filter(Boolean);
21
+ const scalar = text(value);
22
+ return scalar ? [scalar] : [];
23
+ }
24
+
25
+ function requireText(value, label) {
26
+ const normalized = text(value);
27
+ if (!normalized) throw new Error(`Intent map requires ${label}`);
28
+ return normalized;
29
+ }
30
+
31
+ function requireSlug(value, label) {
32
+ const normalized = text(value);
33
+ if (!slugPattern.test(normalized)) throw new Error(`${label} must be lower kebab-case: ${normalized}`);
34
+ return normalized;
35
+ }
36
+
37
+ function normalizePersona(persona) {
38
+ if (typeof persona === 'string') {
39
+ return { ref: validatePersonaRef(persona), role: 'advisor', depth: 3 };
40
+ }
41
+ const ref = validatePersonaRef(persona?.ref);
42
+ const role = requireSlug(persona?.role ?? 'advisor', 'Persona role');
43
+ const depth = Number(persona?.depth ?? 3);
44
+ if (!Number.isInteger(depth) || depth < 1 || depth > 5) {
45
+ throw new Error('Persona depth must be an integer from 1 to 5');
46
+ }
47
+ return { ref, role, depth };
48
+ }
49
+
50
+ function normalizeRelationship(relationship) {
51
+ const type = text(relationship?.type);
52
+ const target = text(relationship?.target);
53
+ if (!intentRelationshipTypes.includes(type)) {
54
+ throw new Error(`Intent relationship type must be one of: ${intentRelationshipTypes.join(', ')}`);
55
+ }
56
+ if (!intentReferencePattern.test(target)) {
57
+ throw new Error(`Intent relationship target must be an exact domain/slug reference: ${target}`);
58
+ }
59
+ const rationale = text(relationship?.rationale);
60
+ const requiredBefore = text(relationship?.required_before);
61
+ const requiredState = text(relationship?.required_state);
62
+ if ((requiredBefore || requiredState) && type !== 'depends-on') {
63
+ throw new Error('required_before and required_state apply only to depends-on relationships');
64
+ }
65
+ if (requiredBefore && !['build', 'delivery'].includes(requiredBefore)) {
66
+ throw new Error('depends-on required_before must be build or delivery');
67
+ }
68
+ if (requiredState && !['plan-complete', 'delivered'].includes(requiredState)) {
69
+ throw new Error('depends-on required_state must be plan-complete or delivered');
70
+ }
71
+ return {
72
+ type,
73
+ target,
74
+ ...(rationale ? { rationale } : {}),
75
+ ...(requiredBefore ? { required_before: requiredBefore } : {}),
76
+ ...(requiredState ? { required_state: requiredState } : {}),
77
+ };
78
+ }
79
+
80
+ function normalizeDeliveryShape(value) {
81
+ if (value == null) return null;
82
+ const recommendation = text(value.recommendation);
83
+ if (!deliveryShapeRecommendations.includes(recommendation)) {
84
+ throw new Error(`Delivery-shape recommendation must be one of: ${deliveryShapeRecommendations.join(', ')}`);
85
+ }
86
+ const reason = text(value.reason);
87
+ if (!reason) throw new Error('Delivery-shape preview requires a reason');
88
+ const suggestedChildren = (value.suggested_children ?? value.suggestedChildren ?? []).map((child) => {
89
+ const slug = text(child?.slug);
90
+ if (slug && !slugPattern.test(slug)) throw new Error(`Suggested child slug must be lower kebab-case: ${slug}`);
91
+ const domain = text(child?.domain);
92
+ if (domain && !slugPattern.test(domain)) throw new Error(`Suggested child domain must be lower kebab-case: ${domain}`);
93
+ const title = text(child?.title);
94
+ const outcome = text(child?.outcome);
95
+ const dependsOn = list(child?.depends_on ?? child?.dependsOn);
96
+ return {
97
+ ...(domain ? { domain } : {}),
98
+ ...(slug ? { slug } : {}),
99
+ ...(title ? { title } : {}),
100
+ outcome,
101
+ ...(dependsOn.length ? { depends_on: dependsOn } : {}),
102
+ };
103
+ });
104
+ const reviewedDecision = text(value.reviewed_decision ?? value.reviewedDecision);
105
+ if (reviewedDecision && !['keep-as-one', 'split', 'refine-split', 'defer'].includes(reviewedDecision)) {
106
+ throw new Error('Delivery-shape reviewed_decision must be keep-as-one, split, refine-split, or defer');
107
+ }
108
+ return {
109
+ recommendation,
110
+ reason,
111
+ suggested_children: suggestedChildren,
112
+ blocking_questions: list(value.blocking_questions ?? value.blockingQuestions),
113
+ reviewed_decision: reviewedDecision || null,
114
+ };
115
+ }
116
+
117
+ function normalizeIntent(input) {
118
+ const slug = requireSlug(input?.slug, 'Intent slug');
119
+ const domain = requireSlug(input?.domain ?? 'general', 'Intent domain');
120
+ const reference = `${domain}/${slug}`;
121
+ const relationships = (input?.relationships ?? []).map(normalizeRelationship);
122
+ if (relationships.some((relationship) => relationship.target === reference)) {
123
+ throw new Error(`Intent cannot relate to itself: ${reference}`);
124
+ }
125
+ return {
126
+ reference,
127
+ slug,
128
+ domain,
129
+ title: requireText(input?.title, `title for ${reference}`),
130
+ problem: requireText(input?.problem, `problem for ${reference}`),
131
+ desiredOutcome: requireText(input?.desiredOutcome, `desired outcome for ${reference}`),
132
+ users: list(input?.users),
133
+ journeys: list(input?.journeys),
134
+ acceptanceCriteria: list(input?.acceptanceCriteria),
135
+ constraints: list(input?.constraints),
136
+ evidence: list(input?.evidence),
137
+ openDecisions: list(input?.openDecisions),
138
+ personas: (input?.personas ?? []).map(normalizePersona),
139
+ relationships,
140
+ deliveryShape: normalizeDeliveryShape(input?.deliveryShape ?? input?.delivery_shape ?? null),
141
+ };
142
+ }
143
+
144
+ export function normalizeIntentMapRequest(raw = {}) {
145
+ if (raw.schema && raw.schema !== 'ewai.intent-map-request/v1') {
146
+ throw new Error(`Unsupported intent map request schema: ${raw.schema}`);
147
+ }
148
+ const intents = (raw.intents ?? []).map(normalizeIntent);
149
+ if (!intents.length) throw new Error('Intent map requires at least one proposed intent');
150
+ const references = intents.map((intent) => intent.reference);
151
+ if (new Set(references).size !== references.length) {
152
+ throw new Error('Intent map contains duplicate domain/slug references');
153
+ }
154
+ return {
155
+ schema: 'ewai.intent-map-request/v1',
156
+ slug: requireSlug(raw.slug, 'Intent map slug'),
157
+ title: requireText(raw.title, 'an intent map title'),
158
+ idea: requireText(raw.idea, 'the originating idea'),
159
+ desiredOutcome: requireText(raw.desiredOutcome, 'the overall desired outcome'),
160
+ users: list(raw.users),
161
+ evidence: list(raw.evidence),
162
+ boundaries: list(raw.boundaries),
163
+ nonGoals: list(raw.nonGoals),
164
+ assumptions: list(raw.assumptions),
165
+ openQuestions: list(raw.openQuestions),
166
+ shapingPersonas: (raw.shapingPersonas ?? []).map(normalizePersona),
167
+ intents,
168
+ };
169
+ }
170
+
171
+ function assertAcyclicDependencies(intents) {
172
+ const local = new Set(intents.map((intent) => intent.reference));
173
+ const edges = new Map(intents.map((intent) => [
174
+ intent.reference,
175
+ intent.relationships
176
+ .filter((relationship) => relationship.type === 'depends-on' && local.has(relationship.target))
177
+ .map((relationship) => relationship.target),
178
+ ]));
179
+ const visiting = new Set();
180
+ const visited = new Set();
181
+
182
+ const visit = (reference, trail = []) => {
183
+ if (visiting.has(reference)) {
184
+ throw new Error(`Intent dependency cycle detected: ${[...trail, reference].join(' -> ')}`);
185
+ }
186
+ if (visited.has(reference)) return;
187
+ visiting.add(reference);
188
+ for (const target of edges.get(reference) ?? []) visit(target, [...trail, reference]);
189
+ visiting.delete(reference);
190
+ visited.add(reference);
191
+ };
192
+ for (const reference of edges.keys()) visit(reference);
193
+ }
194
+
195
+ function intentExists(paths, reference) {
196
+ const [domain, slug] = reference.split('/');
197
+ const base = resolve(paths.specsRoot, '2.Purpose/intents', domain, slug);
198
+ return existsSync(`${base}.md`) || existsSync(`${base}.json`);
199
+ }
200
+
201
+ function preflight(paths, request) {
202
+ const mapRoot = resolve(paths.specsRoot, '2.Purpose/explorations/intent-maps');
203
+ const markdownPath = resolve(mapRoot, `${request.slug}.md`);
204
+ const jsonPath = resolve(mapRoot, `${request.slug}.json`);
205
+ if (existsSync(markdownPath) || existsSync(jsonPath)) {
206
+ throw new Error(`Intent map already exists: ${relative(paths.projectRoot, markdownPath)}`);
207
+ }
208
+
209
+ const local = new Set(request.intents.map((intent) => intent.reference));
210
+ for (const intent of request.intents) {
211
+ if (intentExists(paths, intent.reference)) {
212
+ throw new Error(`Intent already exists: ${intent.reference}`);
213
+ }
214
+ for (const relationship of intent.relationships) {
215
+ if (!local.has(relationship.target) && !intentExists(paths, relationship.target)) {
216
+ throw new Error(
217
+ `Intent ${intent.reference} relates to missing intent ${relationship.target}`,
218
+ );
219
+ }
220
+ }
221
+ }
222
+ assertAcyclicDependencies(request.intents);
223
+ return { mapRoot, markdownPath, jsonPath };
224
+ }
225
+
226
+ function bullets(values, empty = 'None recorded') {
227
+ return values.length ? values.map((value) => `- ${value}`).join('\n') : `- ${empty}`;
228
+ }
229
+
230
+ function renderIntentMap(record) {
231
+ const intentRows = record.intents.map((intent, index) => (
232
+ `| ${index + 1} | \`${intent.reference}\` | ${intent.title.replaceAll('|', '\\|')} | ${intent.desiredOutcome.replaceAll('|', '\\|')} |`
233
+ )).join('\n');
234
+ const relationshipRows = record.intents.flatMap((intent) => (
235
+ intent.relationships.map((relationship) => (
236
+ `| \`${intent.reference}\` | ${relationship.type} | \`${relationship.target}\` | ${
237
+ (relationship.rationale || '').replaceAll('|', '\\|')
238
+ } |`
239
+ ))
240
+ ));
241
+ const shapingPersonas = record.shapingPersonas.map((persona) => (
242
+ `${persona.ref} (${persona.role}, depth ${persona.depth})`
243
+ ));
244
+ const deliveryRows = record.intents.map((intent) => (
245
+ `| \`${intent.reference}\` | ${intent.deliveryShape?.recommendation ?? 'single'} | ${
246
+ (intent.deliveryShape?.reason ?? 'No split concern recorded.').replaceAll('|', '\\|')
247
+ } |`
248
+ )).join('\n');
249
+
250
+ return `---
251
+ schema: ewai.intent-map/v1
252
+ slug: ${record.slug}
253
+ title: ${JSON.stringify(record.title)}
254
+ status: confirmed
255
+ created_at: ${record.createdAt}
256
+ approved_by: ${JSON.stringify(record.approvedBy)}
257
+ ---
258
+
259
+ # Intent Map: ${record.title}
260
+
261
+ ## Originating idea
262
+
263
+ ${record.idea}
264
+
265
+ ## Desired outcome
266
+
267
+ ${record.desiredOutcome}
268
+
269
+ ## Users and affected people
270
+
271
+ ${bullets(record.users)}
272
+
273
+ ## Evidence
274
+
275
+ ${bullets(record.evidence)}
276
+
277
+ ## Boundaries
278
+
279
+ ${bullets(record.boundaries)}
280
+
281
+ ## Non-goals
282
+
283
+ ${bullets(record.nonGoals)}
284
+
285
+ ## Assumptions
286
+
287
+ ${bullets(record.assumptions)}
288
+
289
+ ## Open questions
290
+
291
+ ${bullets(record.openQuestions)}
292
+
293
+ ## Shaping personas
294
+
295
+ ${bullets(shapingPersonas, 'No library persona was used')}
296
+
297
+ ## Proposed intents
298
+
299
+ | Sequence | Intent | Title | Outcome |
300
+ |---:|---|---|---|
301
+ ${intentRows}
302
+
303
+ ## Relationships
304
+
305
+ | Source | Relationship | Target | Rationale |
306
+ |---|---|---|---|
307
+ ${relationshipRows.length ? relationshipRows.join('\n') : '| — | — | — | No cross-intent relationship was required. |'}
308
+
309
+ ## Delivery shape preview
310
+
311
+ | Intent | Recommendation | Reason |
312
+ |---|---|---|
313
+ ${deliveryRows}
314
+
315
+ ## Review decision
316
+
317
+ The user reviewed and approved this intent map before EWAI created the linked draft intents. Each intent remains draft until it is individually refined through \`$ewai-intent\`.
318
+ `;
319
+ }
320
+
321
+ export function loadIntentMapRequest(path) {
322
+ const absolute = resolve(path);
323
+ if (!existsSync(absolute)) throw new Error(`Intent map request does not exist: ${absolute}`);
324
+ if (!['.json', '.yaml', '.yml'].includes(extname(absolute).toLowerCase())) {
325
+ throw new Error('Intent map request must be JSON or YAML');
326
+ }
327
+ return YAML.parse(readFileSync(absolute, 'utf8'));
328
+ }
329
+
330
+ export function createIntentMap(projectRoot, rawRequest, options = {}) {
331
+ if (!options.confirmed) {
332
+ throw new Error('Creating an intent map requires explicit user approval');
333
+ }
334
+ const { paths } = loadProjectConfig(projectRoot);
335
+ const request = normalizeIntentMapRequest(rawRequest);
336
+ const destinations = preflight(paths, request);
337
+ const createdAt = options.now ?? now();
338
+ const approvedBy = text(options.approvedBy, 'Project owner');
339
+ const record = {
340
+ ...request,
341
+ schema: 'ewai.intent-map/v1',
342
+ status: 'confirmed',
343
+ createdAt,
344
+ approvedBy,
345
+ };
346
+ const created = [];
347
+ const allowedRelationshipTargets = request.intents.map((intent) => intent.reference);
348
+
349
+ try {
350
+ atomicText(destinations.markdownPath, renderIntentMap(record));
351
+ created.push(destinations.markdownPath);
352
+ atomicJson(destinations.jsonPath, record);
353
+ created.push(destinations.jsonPath);
354
+
355
+ for (const intent of request.intents) {
356
+ const result = createIntent(paths.projectRoot, {
357
+ slug: intent.slug,
358
+ domain: intent.domain,
359
+ title: intent.title,
360
+ intentMap: request.slug,
361
+ personas: intent.personas,
362
+ relationships: intent.relationships,
363
+ allowedRelationshipTargets,
364
+ deliveryShape: intent.deliveryShape,
365
+ details: {
366
+ problem: intent.problem,
367
+ desiredOutcome: intent.desiredOutcome,
368
+ users: intent.users,
369
+ journeys: intent.journeys,
370
+ acceptanceCriteria: intent.acceptanceCriteria,
371
+ constraints: intent.constraints,
372
+ evidence: intent.evidence,
373
+ openDecisions: intent.openDecisions,
374
+ },
375
+ });
376
+ created.push(result.path, result.path.replace(/\.md$/, '.json'));
377
+ }
378
+ syncIntentIndex(paths.projectRoot);
379
+ } catch (error) {
380
+ for (const path of created.reverse()) rmSync(path, { force: true });
381
+ try {
382
+ syncIntentIndex(paths.projectRoot);
383
+ } catch {
384
+ // Preserve the original failure; the SQLite projection remains rebuildable.
385
+ }
386
+ throw error;
387
+ }
388
+
389
+ return {
390
+ schema: 'ewai.intent-map-result/v1',
391
+ slug: request.slug,
392
+ title: request.title,
393
+ mapPath: relative(paths.projectRoot, destinations.markdownPath).replaceAll('\\', '/'),
394
+ jsonPath: relative(paths.projectRoot, destinations.jsonPath).replaceAll('\\', '/'),
395
+ intents: request.intents.map((intent) => ({
396
+ reference: intent.reference,
397
+ title: intent.title,
398
+ status: 'draft',
399
+ })),
400
+ next: 'Refine one draft intent through $ewai-intent before starting delivery.',
401
+ };
402
+ }