@schneiderjoseph/devia 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (435) hide show
  1. package/AGENTS.md +149 -0
  2. package/CHANGELOG.md +78 -0
  3. package/GOVERNANCE.md +51 -0
  4. package/LEVELS.md +78 -0
  5. package/LICENSE +21 -0
  6. package/MATURITY.md +79 -0
  7. package/MEMORY.md +122 -0
  8. package/MIGRATION.md +62 -0
  9. package/PRINCIPLES.md +110 -0
  10. package/README.md +125 -0
  11. package/REFERENCES.md +30 -0
  12. package/VERSION +5 -0
  13. package/bin/devia.mjs +13 -0
  14. package/checklists/README.md +39 -0
  15. package/checklists/design/accessibility-review.md +11 -0
  16. package/checklists/design/design-to-code-review.md +10 -0
  17. package/checklists/design/responsive-review.md +7 -0
  18. package/checklists/design/ui-review.md +8 -0
  19. package/checklists/design/ux-review.md +10 -0
  20. package/checklists/engineering/accessibility.md +8 -0
  21. package/checklists/engineering/api.md +12 -0
  22. package/checklists/engineering/architecture.md +8 -0
  23. package/checklists/engineering/database.md +11 -0
  24. package/checklists/engineering/devops.md +9 -0
  25. package/checklists/engineering/disaster-recovery.md +9 -0
  26. package/checklists/engineering/frontend.md +9 -0
  27. package/checklists/engineering/incident.md +9 -0
  28. package/checklists/engineering/performance.md +7 -0
  29. package/checklists/engineering/production.md +26 -0
  30. package/checklists/engineering/release.md +17 -0
  31. package/checklists/engineering/security.md +33 -0
  32. package/checklists/engineering/testing.md +8 -0
  33. package/compliance/COVERAGE.md +46 -0
  34. package/compliance/REQUIREMENTS.md +8 -0
  35. package/compliance/TRACEABILITY.md +160 -0
  36. package/compliance/WAIVERS.md +13 -0
  37. package/package.json +74 -0
  38. package/rules/LIFECYCLE.md +16 -0
  39. package/rules/README.md +166 -0
  40. package/rules/accessibility/A11Y-001.md +42 -0
  41. package/rules/accessibility/A11Y-002.md +41 -0
  42. package/rules/accessibility/A11Y-003.md +40 -0
  43. package/rules/accessibility/A11Y-004.md +40 -0
  44. package/rules/accessibility/A11Y-005.md +39 -0
  45. package/rules/accessibility/A11Y-006.md +42 -0
  46. package/rules/accessibility/A11Y-007.md +39 -0
  47. package/rules/accessibility/A11Y-008.md +40 -0
  48. package/rules/accessibility/A11Y-009.md +41 -0
  49. package/rules/accessibility/A11Y-010.md +40 -0
  50. package/rules/accessibility/A11Y-011.md +39 -0
  51. package/rules/accessibility/A11Y-012.md +39 -0
  52. package/rules/agent/AGT-001.md +42 -0
  53. package/rules/agent/AGT-002.md +39 -0
  54. package/rules/agent/AGT-003.md +38 -0
  55. package/rules/agent/AGT-004.md +39 -0
  56. package/rules/agent/AGT-005.md +38 -0
  57. package/rules/agent/AGT-006.md +38 -0
  58. package/rules/agent/AGT-007.md +38 -0
  59. package/rules/agent/AGT-008.md +38 -0
  60. package/rules/agent/AGT-009.md +39 -0
  61. package/rules/agent/AGT-010.md +38 -0
  62. package/rules/agent/AGT-011.md +38 -0
  63. package/rules/ai/AI-001.md +44 -0
  64. package/rules/ai/AI-002.md +39 -0
  65. package/rules/ai/AI-003.md +40 -0
  66. package/rules/ai/AI-004.md +39 -0
  67. package/rules/ai/AI-005.md +38 -0
  68. package/rules/api/API-001.md +39 -0
  69. package/rules/api/API-002.md +39 -0
  70. package/rules/api/API-003.md +39 -0
  71. package/rules/api/API-004.md +38 -0
  72. package/rules/api/API-005.md +39 -0
  73. package/rules/api/API-006.md +40 -0
  74. package/rules/architecture/ARC-001.md +41 -0
  75. package/rules/architecture/ARC-002.md +43 -0
  76. package/rules/architecture/ARC-003.md +43 -0
  77. package/rules/architecture/ARC-004.md +40 -0
  78. package/rules/architecture/ARC-005.md +39 -0
  79. package/rules/architecture/ARC-006.md +39 -0
  80. package/rules/components/CMP-001.md +39 -0
  81. package/rules/components/CMP-002.md +38 -0
  82. package/rules/components/CMP-003.md +39 -0
  83. package/rules/components/CMP-004.md +40 -0
  84. package/rules/components/CMP-005.md +39 -0
  85. package/rules/content/CNT-001.md +39 -0
  86. package/rules/data-display/DATA-001.md +39 -0
  87. package/rules/data-display/DATA-002.md +39 -0
  88. package/rules/data-display/DATA-003.md +40 -0
  89. package/rules/data-display/DATA-004.md +40 -0
  90. package/rules/database/DB-001.md +43 -0
  91. package/rules/database/DB-002.md +38 -0
  92. package/rules/database/DB-003.md +40 -0
  93. package/rules/database/DB-004.md +44 -0
  94. package/rules/database/DB-005.md +39 -0
  95. package/rules/database/DB-006.md +38 -0
  96. package/rules/database/DB-007.md +40 -0
  97. package/rules/database/DB-008.md +40 -0
  98. package/rules/design-system/DS-001.md +39 -0
  99. package/rules/design-system/DS-002.md +40 -0
  100. package/rules/design-system/DS-003.md +38 -0
  101. package/rules/devops/OPS-001.md +43 -0
  102. package/rules/devops/OPS-002.md +39 -0
  103. package/rules/devops/OPS-003.md +38 -0
  104. package/rules/devops/OPS-004.md +40 -0
  105. package/rules/devops/OPS-005.md +43 -0
  106. package/rules/devops/OPS-006.md +38 -0
  107. package/rules/devops/OPS-007.md +40 -0
  108. package/rules/interaction/INT-001.md +39 -0
  109. package/rules/interaction/INT-002.md +39 -0
  110. package/rules/localization/I18N-001.md +38 -0
  111. package/rules/localization/I18N-002.md +40 -0
  112. package/rules/localization/I18N-003.md +39 -0
  113. package/rules/memory/MEM-001.md +44 -0
  114. package/rules/memory/MEM-002.md +39 -0
  115. package/rules/memory/MEM-003.md +38 -0
  116. package/rules/memory/MEM-004.md +38 -0
  117. package/rules/memory/MEM-005.md +38 -0
  118. package/rules/memory/MEM-006.md +38 -0
  119. package/rules/memory/MEM-007.md +38 -0
  120. package/rules/memory/MEM-008.md +38 -0
  121. package/rules/memory/MEM-009.md +39 -0
  122. package/rules/memory/MEM-010.md +38 -0
  123. package/rules/memory/MEM-011.md +38 -0
  124. package/rules/motion/MOT-001.md +38 -0
  125. package/rules/observability/OBS-001.md +40 -0
  126. package/rules/observability/OBS-002.md +40 -0
  127. package/rules/observability/OBS-003.md +38 -0
  128. package/rules/observability/OBS-004.md +38 -0
  129. package/rules/privacy/PRIV-001.md +38 -0
  130. package/rules/privacy/PRIV-002.md +44 -0
  131. package/rules/privacy/PRIV-003.md +40 -0
  132. package/rules/privacy/PRIV-004.md +41 -0
  133. package/rules/responsive/RWD-001.md +40 -0
  134. package/rules/responsive/RWD-002.md +39 -0
  135. package/rules/responsive/RWD-003.md +39 -0
  136. package/rules/security/SEC-001.md +44 -0
  137. package/rules/security/SEC-002.md +44 -0
  138. package/rules/security/SEC-003.md +41 -0
  139. package/rules/security/SEC-004.md +40 -0
  140. package/rules/security/SEC-005.md +42 -0
  141. package/rules/security/SEC-006.md +40 -0
  142. package/rules/security/SEC-007.md +44 -0
  143. package/rules/security/SEC-008.md +39 -0
  144. package/rules/security/SEC-009.md +40 -0
  145. package/rules/security/SEC-010.md +40 -0
  146. package/rules/security/SEC-011.md +40 -0
  147. package/rules/security/SEC-012.md +40 -0
  148. package/rules/states/STATE-001.md +38 -0
  149. package/rules/states/STATE-002.md +39 -0
  150. package/rules/states/STATE-003.md +39 -0
  151. package/rules/states/STATE-004.md +38 -0
  152. package/rules/testing/TST-001.md +39 -0
  153. package/rules/testing/TST-002.md +39 -0
  154. package/rules/testing/TST-003.md +39 -0
  155. package/rules/testing/TST-004.md +38 -0
  156. package/rules/testing/TST-005.md +40 -0
  157. package/rules/testing/TST-006.md +39 -0
  158. package/rules/ui/UI-001.md +40 -0
  159. package/rules/ui/UI-002.md +38 -0
  160. package/rules/ui/UI-003.md +41 -0
  161. package/rules/ui/UI-004.md +41 -0
  162. package/rules/ui/UI-005.md +41 -0
  163. package/rules/ui/UI-006.md +40 -0
  164. package/rules/ui/UI-007.md +41 -0
  165. package/rules/ux/UX-001.md +41 -0
  166. package/rules/ux/UX-002.md +41 -0
  167. package/rules/ux/UX-003.md +39 -0
  168. package/rules/ux/UX-004.md +39 -0
  169. package/rules/ux/UX-005.md +40 -0
  170. package/rules/ux/UX-006.md +40 -0
  171. package/rules/ux/UX-007.md +44 -0
  172. package/rules/ux/UX-008.md +41 -0
  173. package/rules/ux/UX-009.md +39 -0
  174. package/rules/ux/UX-010.md +40 -0
  175. package/rules/ux/UX-011.md +40 -0
  176. package/rules/ux/UX-012.md +40 -0
  177. package/rules/ux/UX-013.md +39 -0
  178. package/schema/README.md +19 -0
  179. package/schema/checklist.schema.json +34 -0
  180. package/schema/component.schema.json +37 -0
  181. package/schema/project-config.schema.json +70 -0
  182. package/schema/rule.schema.json +104 -0
  183. package/schema/token.schema.json +15 -0
  184. package/schema/waiver.schema.json +33 -0
  185. package/scripts/build-index.mjs +178 -0
  186. package/scripts/validate-links.mjs +43 -0
  187. package/scripts/validate-rules.mjs +42 -0
  188. package/skills/devia/SKILL.md +114 -0
  189. package/src/cli.mjs +107 -0
  190. package/src/commands/check.mjs +483 -0
  191. package/src/commands/doctor.mjs +139 -0
  192. package/src/commands/init.mjs +186 -0
  193. package/src/commands/registry.mjs +154 -0
  194. package/src/commands/rules.mjs +101 -0
  195. package/src/commands/skills.mjs +97 -0
  196. package/src/commands/sync.mjs +83 -0
  197. package/src/commands/validate.mjs +194 -0
  198. package/src/lib/fs.mjs +89 -0
  199. package/src/lib/git.mjs +31 -0
  200. package/src/lib/rules.mjs +85 -0
  201. package/src/lib/ui.mjs +52 -0
  202. package/src/lib/vendor.mjs +74 -0
  203. package/src/lib/version.mjs +19 -0
  204. package/src/lib/yaml.mjs +152 -0
  205. package/standard/README.md +31 -0
  206. package/standard/design/README.md +51 -0
  207. package/standard/design/REFERENCES.md +39 -0
  208. package/standard/design/accessibility/aria.md +7 -0
  209. package/standard/design/accessibility/contrast.md +6 -0
  210. package/standard/design/accessibility/focus.md +6 -0
  211. package/standard/design/accessibility/forms.md +3 -0
  212. package/standard/design/accessibility/keyboard.md +6 -0
  213. package/standard/design/accessibility/reduced-motion.md +3 -0
  214. package/standard/design/accessibility/reflow.md +3 -0
  215. package/standard/design/accessibility/screen-readers.md +3 -0
  216. package/standard/design/accessibility/target-size.md +3 -0
  217. package/standard/design/accessibility/testing.md +3 -0
  218. package/standard/design/accessibility/wcag-2.2.md +16 -0
  219. package/standard/design/accessibility/zoom.md +3 -0
  220. package/standard/design/ai/ai-design-rules.md +8 -0
  221. package/standard/design/ai/anti-patterns.md +1 -0
  222. package/standard/design/ai/compliance-format.md +22 -0
  223. package/standard/design/ai/design-review.md +10 -0
  224. package/standard/design/ai/evals/README.md +1 -0
  225. package/standard/design/ai/instructions.md +7 -0
  226. package/standard/design/ai/prompts/accessibility-review.md +5 -0
  227. package/standard/design/ai/prompts/design-system-review.md +5 -0
  228. package/standard/design/ai/prompts/ui-review.md +5 -0
  229. package/standard/design/ai/prompts/ux-review.md +5 -0
  230. package/standard/design/ai/review-protocol.md +11 -0
  231. package/standard/design/anti-patterns/accessibility.md +7 -0
  232. package/standard/design/anti-patterns/ai-generated.md +6 -0
  233. package/standard/design/anti-patterns/dashboards.md +5 -0
  234. package/standard/design/anti-patterns/forms.md +5 -0
  235. package/standard/design/anti-patterns/responsive.md +5 -0
  236. package/standard/design/anti-patterns/ui.md +6 -0
  237. package/standard/design/anti-patterns/ux.md +5 -0
  238. package/standard/design/components/buttons.md +6 -0
  239. package/standard/design/components/dialogs.md +5 -0
  240. package/standard/design/components/feedback.md +3 -0
  241. package/standard/design/components/forms.md +3 -0
  242. package/standard/design/components/navigation.md +3 -0
  243. package/standard/design/components/tables.md +6 -0
  244. package/standard/design/content/error-messages.md +4 -0
  245. package/standard/design/content/ux-writing.md +5 -0
  246. package/standard/design/data-display/README.md +5 -0
  247. package/standard/design/data-display/currency.md +3 -0
  248. package/standard/design/data-display/dates.md +3 -0
  249. package/standard/design/data-display/density.md +3 -0
  250. package/standard/design/data-display/filtering.md +3 -0
  251. package/standard/design/data-display/localization.md +3 -0
  252. package/standard/design/data-display/numbers.md +3 -0
  253. package/standard/design/data-display/pagination.md +3 -0
  254. package/standard/design/data-display/percentages.md +3 -0
  255. package/standard/design/data-display/sorting.md +3 -0
  256. package/standard/design/data-display/tables.md +3 -0
  257. package/standard/design/data-display/time.md +3 -0
  258. package/standard/design/decisions/ADR-001-token-naming.md +13 -0
  259. package/standard/design/decisions/ADR-002-radius-scale.md +9 -0
  260. package/standard/design/decisions/ADR-003-color-system.md +9 -0
  261. package/standard/design/decisions/ADR-004-component-versioning.md +9 -0
  262. package/standard/design/decisions/README.md +3 -0
  263. package/standard/design/design-system/components.md +9 -0
  264. package/standard/design/design-system/naming.md +19 -0
  265. package/standard/design/design-system/tokens.md +7 -0
  266. package/standard/design/design-system/variants.md +5 -0
  267. package/standard/design/design-system/versioning.md +5 -0
  268. package/standard/design/health/coverage.md +1 -0
  269. package/standard/design/health/dashboard.md +14 -0
  270. package/standard/design/health/maturity-model.md +9 -0
  271. package/standard/design/health/score.md +14 -0
  272. package/standard/design/interaction/README.md +10 -0
  273. package/standard/design/interaction/keyboard.md +3 -0
  274. package/standard/design/interaction/mouse.md +2 -0
  275. package/standard/design/interaction/pen.md +1 -0
  276. package/standard/design/interaction/touch.md +3 -0
  277. package/standard/design/interaction/touchscreen.md +6 -0
  278. package/standard/design/interaction/voice.md +2 -0
  279. package/standard/design/localization/README.md +5 -0
  280. package/standard/design/localization/currency.md +3 -0
  281. package/standard/design/localization/date-time.md +3 -0
  282. package/standard/design/localization/i18n.md +3 -0
  283. package/standard/design/localization/locale-testing.md +3 -0
  284. package/standard/design/localization/number-formatting.md +3 -0
  285. package/standard/design/localization/pluralization.md +3 -0
  286. package/standard/design/localization/rtl.md +3 -0
  287. package/standard/design/localization/text-expansion.md +3 -0
  288. package/standard/design/motion/animation.md +6 -0
  289. package/standard/design/penpot/WORKFLOW.md +27 -0
  290. package/standard/design/platforms/README.md +12 -0
  291. package/standard/design/platforms/desktop/README.md +5 -0
  292. package/standard/design/platforms/mobile/android.md +5 -0
  293. package/standard/design/platforms/mobile/ios.md +5 -0
  294. package/standard/design/platforms/tablet/README.md +5 -0
  295. package/standard/design/platforms/web/README.md +1 -0
  296. package/standard/design/principles/design-principles.md +9 -0
  297. package/standard/design/principles/ui-principles.md +7 -0
  298. package/standard/design/principles/ux-principles.md +14 -0
  299. package/standard/design/references/atlassian.md +3 -0
  300. package/standard/design/references/carbon.md +3 -0
  301. package/standard/design/references/figma-sds.md +5 -0
  302. package/standard/design/references/govuk.md +3 -0
  303. package/standard/design/references/material.md +3 -0
  304. package/standard/design/references/nng.md +3 -0
  305. package/standard/design/references/openui.md +3 -0
  306. package/standard/design/references/primer.md +5 -0
  307. package/standard/design/references/storybook.md +3 -0
  308. package/standard/design/references/uswds.md +3 -0
  309. package/standard/design/references/w3c.md +3 -0
  310. package/standard/design/responsive/desktop.md +4 -0
  311. package/standard/design/responsive/mobile.md +6 -0
  312. package/standard/design/responsive/tablet.md +3 -0
  313. package/standard/design/states/async.md +3 -0
  314. package/standard/design/states/conflict.md +3 -0
  315. package/standard/design/states/empty.md +3 -0
  316. package/standard/design/states/error.md +3 -0
  317. package/standard/design/states/interaction.md +5 -0
  318. package/standard/design/states/loading.md +3 -0
  319. package/standard/design/states/offline.md +3 -0
  320. package/standard/design/states/optimistic.md +3 -0
  321. package/standard/design/states/partial.md +3 -0
  322. package/standard/design/states/permission-denied.md +3 -0
  323. package/standard/design/states/rate-limited.md +3 -0
  324. package/standard/design/states/read-only.md +3 -0
  325. package/standard/design/states/retry.md +3 -0
  326. package/standard/design/states/skeleton.md +3 -0
  327. package/standard/design/states/stale.md +3 -0
  328. package/standard/design/states/success.md +3 -0
  329. package/standard/design/states/timeout.md +3 -0
  330. package/standard/design/states/unsaved-changes.md +3 -0
  331. package/standard/design/ui/color.md +6 -0
  332. package/standard/design/ui/grids.md +5 -0
  333. package/standard/design/ui/icons.md +5 -0
  334. package/standard/design/ui/imagery.md +5 -0
  335. package/standard/design/ui/layout.md +5 -0
  336. package/standard/design/ui/spacing.md +5 -0
  337. package/standard/design/ui/typography.md +6 -0
  338. package/standard/design/ui/visual-design.md +7 -0
  339. package/standard/design/ux/cognitive-load.md +5 -0
  340. package/standard/design/ux/errors.md +6 -0
  341. package/standard/design/ux/feedback.md +5 -0
  342. package/standard/design/ux/forms.md +7 -0
  343. package/standard/design/ux/heuristics.md +14 -0
  344. package/standard/design/ux/information-architecture.md +6 -0
  345. package/standard/design/ux/navigation.md +6 -0
  346. package/standard/design/ux/usability.md +6 -0
  347. package/standard/engineering/README.md +29 -0
  348. package/standard/engineering/REFERENCES.md +42 -0
  349. package/standard/engineering/ai/AI_SECURITY.md +15 -0
  350. package/standard/engineering/ai/PROMPT_SECURITY.md +6 -0
  351. package/standard/engineering/architecture/ADR.md +11 -0
  352. package/standard/engineering/architecture/ARCHITECTURE.md +25 -0
  353. package/standard/engineering/architecture/PRINCIPLES.md +17 -0
  354. package/standard/engineering/architecture/THREAT_MODEL.md +14 -0
  355. package/standard/engineering/backend/API.md +29 -0
  356. package/standard/engineering/backend/BACKGROUND_JOBS.md +12 -0
  357. package/standard/engineering/backend/ERROR_HANDLING.md +26 -0
  358. package/standard/engineering/backend/LOGGING.md +12 -0
  359. package/standard/engineering/compliance/DATA_RETENTION.md +10 -0
  360. package/standard/engineering/compliance/PRIVACY.md +11 -0
  361. package/standard/engineering/database/BACKUPS.md +19 -0
  362. package/standard/engineering/database/DATABASE.md +30 -0
  363. package/standard/engineering/database/MIGRATIONS.md +12 -0
  364. package/standard/engineering/devops/BRANCH_PROTECTION.md +17 -0
  365. package/standard/engineering/devops/CI_CD.md +48 -0
  366. package/standard/engineering/devops/DEPLOYMENT.md +12 -0
  367. package/standard/engineering/devops/DOCKER.md +9 -0
  368. package/standard/engineering/devops/ENVIRONMENTS.md +12 -0
  369. package/standard/engineering/devops/RELEASE.md +6 -0
  370. package/standard/engineering/devops/ROLLBACK.md +9 -0
  371. package/standard/engineering/frontend/ACCESSIBILITY.md +16 -0
  372. package/standard/engineering/frontend/DESIGN_SYSTEM.md +10 -0
  373. package/standard/engineering/frontend/FRONTEND.md +17 -0
  374. package/standard/engineering/frontend/UX.md +15 -0
  375. package/standard/engineering/observability/ALERTING.md +11 -0
  376. package/standard/engineering/observability/INCIDENTS.md +10 -0
  377. package/standard/engineering/observability/MONITORING.md +17 -0
  378. package/standard/engineering/payments/PAYMENTS.md +15 -0
  379. package/standard/engineering/performance/PERFORMANCE.md +19 -0
  380. package/standard/engineering/security/API_SECURITY.md +22 -0
  381. package/standard/engineering/security/ASVS_5.0/V10_MALICIOUS_CODE.md +31 -0
  382. package/standard/engineering/security/ASVS_5.0/V11_BUSINESS_LOGIC.md +31 -0
  383. package/standard/engineering/security/ASVS_5.0/V12_FILES.md +31 -0
  384. package/standard/engineering/security/ASVS_5.0/V13_API.md +31 -0
  385. package/standard/engineering/security/ASVS_5.0/V14_CONFIGURATION.md +31 -0
  386. package/standard/engineering/security/ASVS_5.0/V1_ARCHITECTURE.md +31 -0
  387. package/standard/engineering/security/ASVS_5.0/V2_AUTHENTICATION.md +31 -0
  388. package/standard/engineering/security/ASVS_5.0/V3_SESSION.md +31 -0
  389. package/standard/engineering/security/ASVS_5.0/V4_ACCESS_CONTROL.md +31 -0
  390. package/standard/engineering/security/ASVS_5.0/V5_VALIDATION.md +31 -0
  391. package/standard/engineering/security/ASVS_5.0/V6_CRYPTOGRAPHY.md +31 -0
  392. package/standard/engineering/security/ASVS_5.0/V7_ERROR_HANDLING.md +31 -0
  393. package/standard/engineering/security/ASVS_5.0/V8_DATA_PROTECTION.md +31 -0
  394. package/standard/engineering/security/ASVS_5.0/V9_COMMUNICATION.md +31 -0
  395. package/standard/engineering/security/ASVS_REGISTRY.md +31 -0
  396. package/standard/engineering/security/AUTHENTICATION.md +28 -0
  397. package/standard/engineering/security/AUTHORIZATION.md +27 -0
  398. package/standard/engineering/security/DATA_SECURITY.md +14 -0
  399. package/standard/engineering/security/OWASP_ASVS.md +31 -0
  400. package/standard/engineering/security/SECRETS.md +28 -0
  401. package/standard/engineering/security/SECURITY.md +28 -0
  402. package/standard/engineering/testing/TESTING.md +27 -0
  403. package/templates/agents/AGENTS.md +34 -0
  404. package/templates/agents/CLAUDE.md +33 -0
  405. package/templates/agents/copilot-instructions.md +15 -0
  406. package/templates/agents/cursor.mdc +27 -0
  407. package/templates/agents/windsurfrules.md +17 -0
  408. package/templates/docs/ADR.md +16 -0
  409. package/templates/docs/FEATURE.md +19 -0
  410. package/templates/docs/SECURITY_REPORT.md +15 -0
  411. package/templates/docs/accessibility-review.md +9 -0
  412. package/templates/docs/component.md +9 -0
  413. package/templates/docs/decision-record.md +9 -0
  414. package/templates/docs/design-review.md +9 -0
  415. package/templates/docs/exception.md +9 -0
  416. package/templates/docs/page.md +9 -0
  417. package/templates/docs/pattern.md +9 -0
  418. package/templates/docs/user-flow.md +9 -0
  419. package/templates/github/workflows/app-ci.yml +91 -0
  420. package/templates/project/00_OVERVIEW.md +51 -0
  421. package/templates/project/01_ARCHITECTURE.md +37 -0
  422. package/templates/project/02_SURFACES.md +30 -0
  423. package/templates/project/03_DATA_MODEL.md +31 -0
  424. package/templates/project/04_PERMISSIONS.md +32 -0
  425. package/templates/project/05_FLOWS.md +20 -0
  426. package/templates/project/06_INTEGRATIONS.md +21 -0
  427. package/templates/project/07_DESIGN.md +33 -0
  428. package/templates/project/10_NEVER_ALWAYS.md +26 -0
  429. package/templates/project/11_GAPS.md +18 -0
  430. package/templates/project/12_DEBT.md +19 -0
  431. package/templates/project/13_RECIPES.md +35 -0
  432. package/templates/project/14_INDEX.md +50 -0
  433. package/templates/project/AGENTS.md +51 -0
  434. package/templates/project/README.md +49 -0
  435. package/templates/project/impact-map.yaml +41 -0
@@ -0,0 +1,83 @@
1
+ import path from "node:path";
2
+ import { exists, read, readJSON, writeJSON, walk } from "../lib/fs.mjs";
3
+ import { cliVersion, standardVersion } from "../lib/version.mjs";
4
+ import { vendorStandard, vendorContents } from "../lib/vendor.mjs";
5
+ import { color, heading, status, line } from "../lib/ui.mjs";
6
+
7
+ export default async function sync(ctx) {
8
+ const { root, deviaDir, flags } = ctx;
9
+
10
+ if (flags.help) {
11
+ line(`
12
+ ${color.bold("devia sync")} — refresh the vendored standard in .devia/standard/
13
+
14
+ --root <dir> repository to sync
15
+ --dry-run report what would change, write nothing
16
+
17
+ The project memory is never touched: sync replaces the pinned copy of the standard only.
18
+ `.trim());
19
+ return 0;
20
+ }
21
+
22
+ if (!exists(deviaDir)) {
23
+ status("FAIL", "no .devia/", "run `devia init` first");
24
+ return 1;
25
+ }
26
+
27
+ const dest = path.join(deviaDir, "standard");
28
+ const installed = standardVersion();
29
+ const cli = cliVersion();
30
+ const config = readJSON(path.join(deviaDir, "devia.json")) || {};
31
+ const pinned = config.standardVersion;
32
+
33
+ heading("devia sync");
34
+ line(` ${color.dim("pinned")} ${pinned || "none"}`);
35
+ line(` ${color.dim("installed")} ${installed || "unknown"}`);
36
+
37
+ const before = new Map();
38
+ for (const rel of walk(dest)) before.set(rel, read(path.join(dest, rel)));
39
+
40
+ if (flags["dry-run"]) {
41
+ let changed = 0;
42
+ let added = 0;
43
+ const now = vendorContents();
44
+ for (const [rel, content] of now) {
45
+ if (!before.has(rel)) added++;
46
+ else if (before.get(rel) !== content) changed++;
47
+ }
48
+ const removed = [...before.keys()].filter((k) => !now.has(k) && k !== "PINNED.md").length;
49
+ status("INFO", `would write ${added} new, ${changed} changed, remove ${removed}`);
50
+ line("");
51
+ return 0;
52
+ }
53
+
54
+ const files = vendorStandard(dest, {
55
+ by: "devia sync",
56
+ cli,
57
+ standard: installed,
58
+ date: new Date().toISOString().slice(0, 10),
59
+ });
60
+
61
+ if (config.standardVersion !== installed || config.deviaVersion !== cli) {
62
+ config.standardVersion = installed;
63
+ config.deviaVersion = cli;
64
+ writeJSON(path.join(deviaDir, "devia.json"), config);
65
+ status("PASS", `pin updated to ${installed}`, `written by devia ${cli}`);
66
+ }
67
+
68
+ const after = new Map();
69
+ for (const rel of walk(dest)) after.set(rel, read(path.join(dest, rel)));
70
+ const changed = [...after.keys()].filter((k) => before.has(k) && before.get(k) !== after.get(k));
71
+ const added = [...after.keys()].filter((k) => !before.has(k));
72
+ const removed = [...before.keys()].filter((k) => !after.has(k));
73
+
74
+ status("PASS", `${files} files vendored`, `v${installed}`);
75
+ if (added.length) status("INFO", `${added.length} new`, added.slice(0, 5).join(", "));
76
+ if (changed.length) status("INFO", `${changed.length} changed`, changed.slice(0, 5).join(", "));
77
+ if (removed.length) status("WARN", `${removed.length} removed`, removed.slice(0, 5).join(", "));
78
+
79
+ line("");
80
+ line(color.dim(" Read CHANGELOG.md for what moved, then run `devia check`."));
81
+ line("");
82
+ return 0;
83
+ }
@@ -0,0 +1,194 @@
1
+ import path from "node:path";
2
+ import { exists, read, readJSON, packageRoot } from "../lib/fs.mjs";
3
+ import { parseYaml } from "../lib/yaml.mjs";
4
+ import { standardVersion } from "../lib/version.mjs";
5
+ import { color, heading, status, line, summary } from "../lib/ui.mjs";
6
+
7
+ export const REQUIRED_MEMORY = [
8
+ "AGENTS.md",
9
+ "00_OVERVIEW.md",
10
+ "01_ARCHITECTURE.md",
11
+ "02_SURFACES.md",
12
+ "03_DATA_MODEL.md",
13
+ "04_PERMISSIONS.md",
14
+ "05_FLOWS.md",
15
+ "06_INTEGRATIONS.md",
16
+ "07_DESIGN.md",
17
+ "10_NEVER_ALWAYS.md",
18
+ "11_GAPS.md",
19
+ "12_DEBT.md",
20
+ "13_RECIPES.md",
21
+ "14_INDEX.md",
22
+ "impact-map.yaml",
23
+ "devia.json",
24
+ ];
25
+
26
+ const PLACEHOLDER = /TODO\(devia\)/g;
27
+
28
+ /** Perishable facts do not belong in files that describe what the project is (MEM-007). */
29
+ const PERISHABLE = [
30
+ /\b\d+\s+tests?\s+(passing|green|failing)\b/i,
31
+ /\bcurrently\s+(working|building|on)\b/i,
32
+ /\bnext\s+(we|up|sprint|milestone)\b/i,
33
+ /\bas of (today|this week|yesterday)\b/i,
34
+ /\bin progress\b/i,
35
+ /\b(this|next) (sprint|week)\b/i,
36
+ ];
37
+ const PERISHABLE_FILES = ["00_OVERVIEW.md", "01_ARCHITECTURE.md", "14_INDEX.md"];
38
+
39
+ /** Registry ids look like `| G12 |` (gaps) or `| D7 |` (debt). */
40
+ export function registryIds(text, prefix) {
41
+ const re = new RegExp(`^\\|\\s*(${prefix}(\\d+))\\s*\\|`, "gm");
42
+ const out = [];
43
+ let m;
44
+ while ((m = re.exec(text))) out.push({ id: m[1], n: Number(m[2]) });
45
+ return out;
46
+ }
47
+
48
+ export function checkRegistry(text, prefix, name, add) {
49
+ const entries = registryIds(text, prefix);
50
+ const seen = new Map();
51
+ for (const { id, n } of entries) {
52
+ if (seen.has(id)) add("FAIL", `${name}: duplicate id ${id}`, "ids are never reused (MEM-004)");
53
+ else seen.set(id, n);
54
+ }
55
+ const nums = [...seen.values()];
56
+ if (nums.length && new Set(nums).size !== nums.length) {
57
+ add("FAIL", `${name}: repeated numbering`, "MEM-004");
58
+ }
59
+ return seen.size;
60
+ }
61
+
62
+ export default async function validate(ctx) {
63
+ const { root, deviaDir, flags } = ctx;
64
+ const results = [];
65
+ const add = (kind, label, detail = "") => results.push({ kind, label, detail });
66
+
67
+ if (flags.help) {
68
+ line(`
69
+ ${color.bold("devia validate")} — memory integrity
70
+
71
+ --root <dir> repository to validate
72
+ --strict treat unfilled placeholders as failures
73
+ --json machine-readable output
74
+ `.trim());
75
+ return 0;
76
+ }
77
+
78
+ if (!exists(deviaDir)) {
79
+ if (ctx.json) {
80
+ console.log(JSON.stringify({ ok: false, error: "no .devia directory", root }, null, 2));
81
+ } else {
82
+ heading("devia validate");
83
+ status("FAIL", "no .devia/ in this repository", "run `devia init` (AGT-002)");
84
+ line("");
85
+ }
86
+ return 1;
87
+ }
88
+
89
+ // 1. Structure
90
+ for (const file of REQUIRED_MEMORY) {
91
+ if (exists(path.join(deviaDir, file))) add("PASS", `memory file ${file}`);
92
+ else add("FAIL", `missing ${file}`, "run `devia init` to restore the template");
93
+ }
94
+
95
+ // 2. Configuration
96
+ const config = readJSON(path.join(deviaDir, "devia.json"));
97
+ if (!config) {
98
+ add("FAIL", "devia.json missing or invalid JSON");
99
+ } else {
100
+ for (const key of ["project", "maturity", "standardVersion"]) {
101
+ if (!config[key]) add("FAIL", `devia.json: missing ${key}`);
102
+ }
103
+ if (config.project && !config.project.name) add("FAIL", "devia.json: project.name is empty");
104
+ const installed = standardVersion();
105
+ if (installed && config.standardVersion && installed !== config.standardVersion) {
106
+ add(
107
+ "WARN",
108
+ `standard pinned at ${config.standardVersion}, installed is ${installed}`,
109
+ "run `devia sync`"
110
+ );
111
+ }
112
+ }
113
+
114
+ // 3. Impact map
115
+ const mapRaw = read(path.join(deviaDir, "impact-map.yaml"));
116
+ if (mapRaw) {
117
+ const map = parseYaml(mapRaw);
118
+ const impacts = map.impacts || {};
119
+ const keys = Object.keys(impacts);
120
+ if (!keys.length) add("FAIL", "impact-map.yaml has no impacts", "MEM-009 cannot be checked");
121
+ let missing = 0;
122
+ for (const [key, targets] of Object.entries(impacts)) {
123
+ for (const t of [].concat(targets || [])) {
124
+ const rel = String(t);
125
+ if (rel.startsWith(".") || rel.includes("/")) continue; // points outside .devia
126
+ if (!exists(path.join(deviaDir, rel))) {
127
+ add("FAIL", `impact-map: ${key} -> ${rel} does not exist`);
128
+ missing++;
129
+ }
130
+ }
131
+ }
132
+ if (!missing && keys.length) add("PASS", `impact map: ${keys.length} change types`);
133
+ }
134
+
135
+ // 4. Registries
136
+ const gaps = read(path.join(deviaDir, "11_GAPS.md")) || "";
137
+ const debt = read(path.join(deviaDir, "12_DEBT.md")) || "";
138
+ const nGaps = checkRegistry(gaps, "G", "11_GAPS.md", add);
139
+ const nDebt = checkRegistry(debt, "D", "12_DEBT.md", add);
140
+ add("PASS", `registries: ${nGaps} gap ids, ${nDebt} debt ids`);
141
+
142
+ // 5. Placeholders
143
+ const strict = Boolean(flags.strict);
144
+ const current = String(config?.maturity?.current || "bronze").toLowerCase();
145
+ let placeholders = 0;
146
+ for (const file of REQUIRED_MEMORY) {
147
+ const text = read(path.join(deviaDir, file));
148
+ if (!text) continue;
149
+ const n = (text.match(PLACEHOLDER) || []).length;
150
+ if (!n) continue;
151
+ placeholders += n;
152
+ const blocking = strict || (file === "00_OVERVIEW.md" && current !== "bronze");
153
+ add(blocking ? "FAIL" : "WARN", `${file}: ${n} unfilled placeholder${n > 1 ? "s" : ""}`);
154
+ }
155
+ if (!placeholders) add("PASS", "no unfilled placeholders");
156
+
157
+ // 6. Perishable facts (MEM-007)
158
+ for (const file of PERISHABLE_FILES) {
159
+ const text = read(path.join(deviaDir, file));
160
+ if (!text) continue;
161
+ for (const re of PERISHABLE) {
162
+ const m = text.match(re);
163
+ if (m) add("WARN", `${file}: perishable fact "${m[0].trim()}"`, "MEM-007");
164
+ }
165
+ }
166
+
167
+ // 7. Committed
168
+ if (exists(path.join(root, ".gitignore"))) {
169
+ const ignore = read(path.join(root, ".gitignore")) || "";
170
+ if (/^\s*\.devia\/?\s*$/m.test(ignore)) {
171
+ add("FAIL", ".devia/ is gitignored", "the memory is part of the repository");
172
+ }
173
+ }
174
+
175
+ const counts = results.reduce((a, r) => ((a[r.kind] = (a[r.kind] || 0) + 1), a), {});
176
+ const failed = counts.FAIL || 0;
177
+
178
+ if (ctx.json) {
179
+ console.log(JSON.stringify({ ok: failed === 0, counts, results }, null, 2));
180
+ return failed ? 1 : 0;
181
+ }
182
+
183
+ heading("devia validate");
184
+ const quiet = !flags.verbose;
185
+ for (const r of results) {
186
+ if (quiet && r.kind === "PASS") continue;
187
+ status(r.kind, r.label, r.detail);
188
+ }
189
+ if (quiet && !failed && !counts.WARN) status("PASS", `${results.length} checks passed`);
190
+ line("");
191
+ line(` ${failed ? color.red("FAILED") : color.green("OK")} ${summary(counts)}`);
192
+ line("");
193
+ return failed ? 1 : 0;
194
+ }
package/src/lib/fs.mjs ADDED
@@ -0,0 +1,89 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ /** Root of the installed devia package. */
6
+ export const packageRoot = path.resolve(
7
+ path.dirname(fileURLToPath(import.meta.url)),
8
+ "..",
9
+ ".."
10
+ );
11
+
12
+ export function exists(p) {
13
+ return fs.existsSync(p);
14
+ }
15
+
16
+ export function read(p) {
17
+ try {
18
+ return fs.readFileSync(p, "utf8");
19
+ } catch {
20
+ return null;
21
+ }
22
+ }
23
+
24
+ export function readJSON(p) {
25
+ const raw = read(p);
26
+ if (raw === null) return null;
27
+ try {
28
+ return JSON.parse(raw);
29
+ } catch {
30
+ return null;
31
+ }
32
+ }
33
+
34
+ export function writeFile(p, content) {
35
+ fs.mkdirSync(path.dirname(p), { recursive: true });
36
+ fs.writeFileSync(p, content.replace(/\r\n/g, "\n"), "utf8");
37
+ }
38
+
39
+ export function writeJSON(p, value) {
40
+ writeFile(p, JSON.stringify(value, null, 2) + "\n");
41
+ }
42
+
43
+ /** Recursively list files under dir, relative to dir. */
44
+ export function walk(dir, { filter = () => true, skip = () => false } = {}) {
45
+ const out = [];
46
+ if (!fs.existsSync(dir)) return out;
47
+ const stack = [""];
48
+ while (stack.length) {
49
+ const rel = stack.pop();
50
+ const abs = path.join(dir, rel);
51
+ for (const ent of fs.readdirSync(abs, { withFileTypes: true })) {
52
+ const childRel = rel ? path.join(rel, ent.name) : ent.name;
53
+ if (skip(childRel, ent)) continue;
54
+ if (ent.isDirectory()) stack.push(childRel);
55
+ else if (ent.isFile() && filter(childRel)) out.push(childRel);
56
+ }
57
+ }
58
+ return out.sort();
59
+ }
60
+
61
+ /** Copy a directory tree. Returns the number of files written. */
62
+ export function copyDir(from, to, { filter = () => true, overwrite = true } = {}) {
63
+ let n = 0;
64
+ for (const rel of walk(from, { filter })) {
65
+ const target = path.join(to, rel);
66
+ if (!overwrite && fs.existsSync(target)) continue;
67
+ fs.mkdirSync(path.dirname(target), { recursive: true });
68
+ fs.copyFileSync(path.join(from, rel), target);
69
+ n++;
70
+ }
71
+ return n;
72
+ }
73
+
74
+ /** Find the repository root by walking up for a marker, else return cwd. */
75
+ export function findProjectRoot(start = process.cwd()) {
76
+ let dir = path.resolve(start);
77
+ for (;;) {
78
+ if (
79
+ fs.existsSync(path.join(dir, ".devia")) ||
80
+ fs.existsSync(path.join(dir, ".git")) ||
81
+ fs.existsSync(path.join(dir, "package.json"))
82
+ ) {
83
+ return dir;
84
+ }
85
+ const parent = path.dirname(dir);
86
+ if (parent === dir) return path.resolve(start);
87
+ dir = parent;
88
+ }
89
+ }
@@ -0,0 +1,31 @@
1
+ import { execFileSync } from "node:child_process";
2
+
3
+ /** Run git in `root`. Returns trimmed stdout, or null when git is absent or the command fails. */
4
+ export function git(root, args) {
5
+ try {
6
+ return execFileSync("git", args, {
7
+ cwd: root,
8
+ encoding: "utf8",
9
+ stdio: ["ignore", "pipe", "ignore"],
10
+ maxBuffer: 64 * 1024 * 1024,
11
+ }).trim();
12
+ } catch {
13
+ return null;
14
+ }
15
+ }
16
+
17
+ export function isRepo(root) {
18
+ return git(root, ["rev-parse", "--is-inside-work-tree"]) === "true";
19
+ }
20
+
21
+ /**
22
+ * What the repository actually carries under `root`: tracked files plus untracked ones that are
23
+ * not ignored. Ignored paths are local artefacts, not the repository's content — scanning them
24
+ * turns a build cache into a P0 failure. Returns null when git cannot answer, so the caller
25
+ * falls back to walking the tree rather than scanning nothing.
26
+ */
27
+ export function trackedFiles(root) {
28
+ const out = git(root, ["ls-files", "-z", "--cached", "--others", "--exclude-standard"]);
29
+ if (out === null) return null;
30
+ return out.split("\0").filter(Boolean);
31
+ }
@@ -0,0 +1,85 @@
1
+ import path from "node:path";
2
+ import { parseFrontmatter } from "./yaml.mjs";
3
+ import { read, walk, packageRoot } from "./fs.mjs";
4
+
5
+ export const SEVERITIES = ["MUST", "MUST NOT", "SHOULD", "MAY"];
6
+ export const STATUSES = [
7
+ "draft",
8
+ "proposed",
9
+ "active",
10
+ "deprecated",
11
+ "superseded",
12
+ "removed",
13
+ ];
14
+ export const PRIORITIES = ["P0", "P1", "P2", "P3"];
15
+ export const ID_PATTERN = /^[A-Z][A-Z0-9]*(-[A-Z0-9]+)+$/;
16
+
17
+ const NOT_A_RULE = new Set(["README.md", "LIFECYCLE.md"]);
18
+
19
+ /**
20
+ * Load every rule under a `rules/` directory.
21
+ * Returns `{ rules, errors }`; a malformed file becomes an error, never a silent skip.
22
+ */
23
+ export function loadRules(rulesDir = path.join(packageRoot, "rules")) {
24
+ const files = walk(rulesDir, {
25
+ filter: (rel) => rel.endsWith(".md") && !NOT_A_RULE.has(path.basename(rel)),
26
+ });
27
+ const rules = [];
28
+ const errors = [];
29
+ const seen = new Map();
30
+
31
+ for (const rel of files) {
32
+ const abs = path.join(rulesDir, rel);
33
+ const text = read(abs);
34
+ const { data, error } = parseFrontmatter(text ?? "");
35
+ const where = rel.split(path.sep).join("/");
36
+
37
+ if (error || !data) {
38
+ errors.push(`${where}: ${error || "missing frontmatter"}`);
39
+ continue;
40
+ }
41
+ const rule = { ...data, file: where };
42
+ const id = rule.id;
43
+
44
+ if (!id || !ID_PATTERN.test(String(id))) errors.push(`${where}: invalid id ${id}`);
45
+ else if (seen.has(id)) errors.push(`${where}: duplicate id ${id} (also ${seen.get(id)})`);
46
+ else seen.set(id, where);
47
+
48
+ if (path.basename(where, ".md") !== id) errors.push(`${where}: filename must match id`);
49
+ if (!SEVERITIES.includes(rule.severity)) errors.push(`${where}: bad severity ${rule.severity}`);
50
+ if (!STATUSES.includes(rule.status)) errors.push(`${where}: bad status ${rule.status}`);
51
+ if (!PRIORITIES.includes(rule.priority)) errors.push(`${where}: bad priority ${rule.priority}`);
52
+ if (!rule.domain) errors.push(`${where}: missing domain`);
53
+ if (!Array.isArray(rule.source) || rule.source.length === 0)
54
+ errors.push(`${where}: at least one source is required`);
55
+ if (!rule.requirement || String(rule.requirement).length < 10)
56
+ errors.push(`${where}: requirement too short`);
57
+ if (
58
+ typeof rule.validation?.automated !== "boolean" ||
59
+ typeof rule.validation?.manual !== "boolean"
60
+ )
61
+ errors.push(`${where}: validation.automated and validation.manual are required`);
62
+
63
+ const dir = where.split("/")[0];
64
+ if (rule.domain && dir !== rule.domain)
65
+ errors.push(`${where}: lives in ${dir}/ but declares domain ${rule.domain}`);
66
+
67
+ rules.push(rule);
68
+ }
69
+
70
+ rules.sort((a, b) => String(a.id).localeCompare(String(b.id)));
71
+ return { rules, errors };
72
+ }
73
+
74
+ export function ruleStats(rules) {
75
+ const by = (key) =>
76
+ rules.reduce((acc, r) => ((acc[r[key]] = (acc[r[key]] || 0) + 1), acc), {});
77
+ return {
78
+ total: rules.length,
79
+ severity: by("severity"),
80
+ priority: by("priority"),
81
+ domain: by("domain"),
82
+ automatable: rules.filter((r) => r.validation?.automated).length,
83
+ active: rules.filter((r) => r.status === "active").length,
84
+ };
85
+ }
package/src/lib/ui.mjs ADDED
@@ -0,0 +1,52 @@
1
+ import process from "node:process";
2
+
3
+ const useColor =
4
+ process.stdout.isTTY && !process.env.NO_COLOR && process.env.TERM !== "dumb";
5
+
6
+ const ESC = String.fromCharCode(27);
7
+ const wrap = (code) => (s) =>
8
+ useColor ? `${ESC}[${code}m${s}${ESC}[0m` : String(s);
9
+
10
+ export const color = {
11
+ bold: wrap("1"),
12
+ dim: wrap("2"),
13
+ red: wrap("31"),
14
+ green: wrap("32"),
15
+ yellow: wrap("33"),
16
+ blue: wrap("34"),
17
+ gray: wrap("90"),
18
+ };
19
+
20
+ export function heading(text) {
21
+ console.log("\n" + color.bold(text));
22
+ }
23
+
24
+ export function line(text = "") {
25
+ console.log(text);
26
+ }
27
+
28
+ export const STATUS = {
29
+ PASS: color.green("PASS"),
30
+ WARN: color.yellow("WARN"),
31
+ FAIL: color.red("FAIL"),
32
+ SKIP: color.gray("SKIP"),
33
+ INFO: color.blue("INFO"),
34
+ };
35
+
36
+ export function status(kind, label, detail = "") {
37
+ const tag = STATUS[kind] ?? kind;
38
+ console.log(` ${tag} ${label}${detail ? color.dim(" — " + detail) : ""}`);
39
+ }
40
+
41
+ export function summary(counts) {
42
+ const parts = [];
43
+ for (const [k, v] of Object.entries(counts)) {
44
+ if (v) parts.push(`${v} ${k.toLowerCase()}`);
45
+ }
46
+ return parts.length ? parts.join(" · ") : "nothing to report";
47
+ }
48
+
49
+ export function fail(message) {
50
+ console.error(color.red("error: ") + message);
51
+ process.exitCode = 1;
52
+ }
@@ -0,0 +1,74 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { packageRoot, exists, read, writeFile, copyDir, walk } from "./fs.mjs";
4
+
5
+ /**
6
+ * What `.devia/standard/` receives.
7
+ *
8
+ * A file is vendored together with whatever it links to: a relative link that resolves in this
9
+ * repository and not in the adopter's copy is a broken link shipped to every project
10
+ * (`tests/cli.test.mjs` walks the materialised tree and fails on one).
11
+ *
12
+ * `templates/project/` and `templates/agents/` are deliberately absent: their links are written
13
+ * for a materialised `.devia/`, so they only resolve once `init` has expanded them.
14
+ */
15
+ export const VENDOR_FILES = [
16
+ "AGENTS.md",
17
+ "PRINCIPLES.md",
18
+ "MEMORY.md",
19
+ "LEVELS.md",
20
+ "MATURITY.md",
21
+ "GOVERNANCE.md",
22
+ "MIGRATION.md",
23
+ "REFERENCES.md",
24
+ "CHANGELOG.md",
25
+ "VERSION",
26
+ ];
27
+
28
+ export const VENDOR_DIRS = [
29
+ "rules",
30
+ "checklists",
31
+ "standard",
32
+ "compliance",
33
+ "schema",
34
+ path.join("templates", "docs"),
35
+ path.join("templates", "github"),
36
+ ];
37
+
38
+ /** Everything the vendor would write, as `relative path -> content`. */
39
+ export function vendorContents() {
40
+ const out = new Map();
41
+ for (const f of VENDOR_FILES) {
42
+ const src = path.join(packageRoot, f);
43
+ if (exists(src)) out.set(f, read(src));
44
+ }
45
+ for (const d of VENDOR_DIRS) {
46
+ const from = path.join(packageRoot, d);
47
+ for (const rel of walk(from)) out.set(path.join(d, rel), read(path.join(from, rel)));
48
+ }
49
+ return out;
50
+ }
51
+
52
+ /**
53
+ * Rewrite the pinned copy from scratch. Returns the number of files written, `PINNED.md`
54
+ * included.
55
+ */
56
+ export function vendorStandard(dest, { by, cli, standard, date }) {
57
+ fs.rmSync(dest, { recursive: true, force: true });
58
+ let files = 0;
59
+ for (const f of VENDOR_FILES) {
60
+ const src = path.join(packageRoot, f);
61
+ if (exists(src)) {
62
+ writeFile(path.join(dest, f), read(src));
63
+ files++;
64
+ }
65
+ }
66
+ for (const d of VENDOR_DIRS) files += copyDir(path.join(packageRoot, d), path.join(dest, d));
67
+ writeFile(
68
+ path.join(dest, "PINNED.md"),
69
+ `# Pinned standard\n\nVendored by \`${by}\` on ${date}.\n\n` +
70
+ `- devia version: ${cli}\n- standard version: ${standard}\n\n` +
71
+ "Do not edit these files. Change the standard upstream, then run `npx devia sync`.\n"
72
+ );
73
+ return files + 1;
74
+ }
@@ -0,0 +1,19 @@
1
+ import path from "node:path";
2
+ import { packageRoot, read, readJSON } from "./fs.mjs";
3
+ import { parseYaml } from "./yaml.mjs";
4
+
5
+ /**
6
+ * Two versions, deliberately separate: the CLI ships bug fixes without moving the standard, and
7
+ * the standard gains rules without a CLI change. An adopter pins the second and reports the
8
+ * first, so neither may stand in for the other.
9
+ */
10
+
11
+ /** Version of the installed devia CLI. */
12
+ export function cliVersion() {
13
+ return readJSON(path.join(packageRoot, "package.json"))?.version || "0.0.0";
14
+ }
15
+
16
+ /** Version of the standard corpus. */
17
+ export function standardVersion() {
18
+ return parseYaml(read(path.join(packageRoot, "VERSION")) || "").standard_version || "0.0.0";
19
+ }