naive-framework 0.0.0-stage → 0.2.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 (549) hide show
  1. package/AGENTS.md +62 -0
  2. package/LICENSE +21 -0
  3. package/README.md +37 -2
  4. package/docs/decisions/decisions.json +888 -0
  5. package/docs/ontology.json +796 -0
  6. package/docs/ontology.md +163 -0
  7. package/docs/reference/ROUTES.md +124 -0
  8. package/evidence/benchmarks/2026-10-27-golden.jev.after-catalog-fix.json +558 -0
  9. package/evidence/benchmarks/2026-10-27-golden.jev.json +501 -0
  10. package/evidence/benchmarks/2026-10-27-golden.reasoning-answers.json +177 -0
  11. package/evidence/benchmarks/JEV_VS_REASONING_MODEL_2026-10-27.md +68 -0
  12. package/evidence/capabilities/agent-capabilities.json +86 -0
  13. package/evidence/design-documents.registry.json +2896 -0
  14. package/evidence/evals/evals.json +25 -0
  15. package/evidence/evals/harness-evals.json +140 -0
  16. package/evidence/layer.json +51 -0
  17. package/evidence/skills/agent-capabilities/SKILL.md +35 -0
  18. package/evidence/skills/design-coverage/SKILL.md +57 -0
  19. package/evidence/skills/design-coverage/check.mjs +192 -0
  20. package/evidence/skills/design-coverage/scan.mjs +45 -0
  21. package/evidence/skills/fidelity-ladder-audit/SKILL.md +121 -0
  22. package/evidence/skills/fidelity-ladder-audit/ladder-census.mjs +180 -0
  23. package/evidence/skills/findability/SKILL.md +32 -0
  24. package/evidence/skills/findability/inventory.rb +41 -0
  25. package/evidence/skills/foreshadowing-audit/SKILL.md +183 -0
  26. package/evidence/skills/metrics-review/SKILL.md +177 -0
  27. package/evidence/tooling/integrations.json +153 -0
  28. package/governance/layer.json +102 -0
  29. package/governance/references/references.json +26 -0
  30. package/governance/skills/board-design/SKILL.md +68 -0
  31. package/governance/skills/brand-pillar/SKILL.md +90 -0
  32. package/governance/skills/business-pillar/SKILL.md +96 -0
  33. package/governance/skills/chief-of-staff/SKILL.md +45 -0
  34. package/governance/skills/cofounder-structure/SKILL.md +64 -0
  35. package/governance/skills/cross-pillar-tradeoff/SKILL.md +168 -0
  36. package/governance/skills/equity-and-share-classes/SKILL.md +68 -0
  37. package/governance/skills/executive-roles/SKILL.md +95 -0
  38. package/governance/skills/exit-planning/SKILL.md +66 -0
  39. package/governance/skills/financing-and-investor-rights/SKILL.md +73 -0
  40. package/governance/skills/office-hours-mode/SKILL.md +113 -0
  41. package/governance/skills/product-pillar/SKILL.md +81 -0
  42. package/governance/skills/publication-policy/SKILL.md +63 -0
  43. package/governance/skills/role-and-candidate-authoring/SKILL.md +198 -0
  44. package/governance/skills/stakeholder-update/SKILL.md +177 -0
  45. package/governance/tooling/integrations.json +37 -0
  46. package/governance/venture-template/AGENT_ROLES_AND_DECISION_RIGHTS.md +58 -0
  47. package/governance/venture-template/COMPANY_VAULT_DEFINITION_2026-10-25.md +204 -0
  48. package/governance/venture-template/README.md +74 -0
  49. package/governance/venture-template/decision-rights.json +186 -0
  50. package/governance/venture-template/index.md +151 -0
  51. package/governance/venture-template/pillars/brand.md +209 -0
  52. package/governance/venture-template/pillars/business.md +255 -0
  53. package/governance/venture-template/pillars/product.md +254 -0
  54. package/governance/venture-template/render-roles.py +11 -0
  55. package/governance/venture-template/roles/README.md +85 -0
  56. package/governance/venture-template/roles/agent-roles.json +202 -0
  57. package/governance/venture-template/roles/ceo.md +163 -0
  58. package/governance/venture-template/roles/chief-of-staff.md +153 -0
  59. package/governance/venture-template/roles/cmo.md +165 -0
  60. package/governance/venture-template/roles/coo.md +189 -0
  61. package/governance/venture-template/roles/cto.md +158 -0
  62. package/governance/venture-template/roles/department-head.md +47 -0
  63. package/governance/venture-template/roles/forward-deployed-engineer.md +51 -0
  64. package/governance/venture-template/roles/founder.md +173 -0
  65. package/governance/venture-template/roles/hr-manager.md +49 -0
  66. package/governance/venture-template/roles/talent-acquisition-manager.md +50 -0
  67. package/governance/venture-template/roles/venture-roles.json +62 -0
  68. package/interface/acting.mjs +83 -0
  69. package/interface/adapters/claude-code.json +16 -0
  70. package/interface/adapters/codex.json +14 -0
  71. package/interface/adapters/cursor.json +16 -0
  72. package/interface/adapters.mjs +182 -0
  73. package/interface/api/server.mjs +71 -0
  74. package/interface/boundaries.mjs +218 -0
  75. package/interface/brand.mjs +214 -0
  76. package/interface/cli/find-venture.mjs +15 -0
  77. package/interface/cli/freshness.mjs +59 -0
  78. package/interface/cli/guard.mjs +6 -0
  79. package/interface/cli/mentura.mjs +341 -0
  80. package/interface/cli/naive.mjs +194 -0
  81. package/interface/context.mjs +524 -0
  82. package/interface/demo/board.mjs +581 -0
  83. package/interface/demo/decision-harness.mjs +91 -0
  84. package/interface/demo/live-agent.mjs +47 -0
  85. package/interface/dev/setup.mjs +84 -0
  86. package/interface/gate-hooks.mjs +36 -0
  87. package/interface/harness/evals.mjs +90 -0
  88. package/interface/harness/examples/pt-no-shows.dump.md +19 -0
  89. package/interface/harness/run.mjs +313 -0
  90. package/interface/harness/site.mjs +59 -0
  91. package/interface/instrumentation.mjs +86 -0
  92. package/interface/kit-boundary.mjs +73 -0
  93. package/interface/layer.json +37 -0
  94. package/interface/mcp/server.mjs +162 -0
  95. package/interface/operator-console/README.md +58 -0
  96. package/interface/package-routes.mjs +196 -0
  97. package/interface/provenance.mjs +65 -0
  98. package/interface/reads.mjs +173 -0
  99. package/interface/references/references.json +28 -0
  100. package/interface/release-card.mjs +42 -0
  101. package/interface/route-aliases.json +32 -0
  102. package/interface/router.mjs +653 -0
  103. package/interface/skills/install-mentura/SKILL.md +88 -0
  104. package/interface/skills/naive-setup/SKILL.md +71 -0
  105. package/interface/skills/naive-setup/artifact.html +83 -0
  106. package/interface/tooling/integrations.json +112 -0
  107. package/interface/vitals.mjs +115 -0
  108. package/interface/writes.mjs +190 -0
  109. package/knowledge/connectors/README.md +54 -0
  110. package/knowledge/connectors/catalog.mjs +118 -0
  111. package/knowledge/connectors/contract.mjs +56 -0
  112. package/knowledge/connectors/eval.mjs +176 -0
  113. package/knowledge/connectors/filesystem.mjs +79 -0
  114. package/knowledge/connectors/index.mjs +102 -0
  115. package/knowledge/connectors/resolve.mjs +44 -0
  116. package/knowledge/connectors/suite.mjs +80 -0
  117. package/knowledge/freshness.json +85 -0
  118. package/knowledge/layer.json +50 -0
  119. package/knowledge/skills/find-reference/SKILL.md +38 -0
  120. package/knowledge/skills/industry-awareness/SKILL.md +277 -0
  121. package/knowledge/templates/glossary.md +23 -0
  122. package/knowledge/tooling/integrations.json +127 -0
  123. package/knowledge/tooling/questions.md +46 -0
  124. package/operations/FOUNDER_OPERATING_MODEL_CAMPAIGN_2026-10-14.md +16 -0
  125. package/operations/departments.json +162 -0
  126. package/operations/handoff-v2.md +93 -0
  127. package/operations/layer.json +67 -0
  128. package/operations/marketing/check-public.mjs +68 -0
  129. package/operations/marketing/site/README.md +86 -0
  130. package/operations/marketing/site/matrix.json +731 -0
  131. package/operations/marketing/site/plan.mjs +117 -0
  132. package/operations/marketing/site/presence.mjs +252 -0
  133. package/operations/references/references.json +45 -0
  134. package/operations/skills/recruiting/SKILL.md +32 -0
  135. package/operations/skills/team-design/SKILL.md +36 -0
  136. package/operations/skills/tool-selection/SKILL.md +46 -0
  137. package/operations/templates/marketing-brand.md +46 -0
  138. package/operations/templates/public-assets.md +39 -0
  139. package/operations/templates/recruiting-brief.md +35 -0
  140. package/operations/tooling/integrations.json +158 -0
  141. package/package.json +59 -4
  142. package/packages/catalog.json +280 -0
  143. package/packages/cofounder/package.json +42 -0
  144. package/packages/counsel/package.json +47 -0
  145. package/packages/customers/package.json +41 -0
  146. package/packages/deals/package.json +27 -0
  147. package/packages/decisions/package.json +28 -0
  148. package/packages/engineering/package.json +41 -0
  149. package/packages/evidence/package.json +17 -0
  150. package/packages/finance/frames/fund-without-ceding-control.frame.json +177 -0
  151. package/packages/finance/package.json +48 -0
  152. package/packages/foundation/package.json +59 -0
  153. package/packages/fund/package.json +48 -0
  154. package/packages/investor/package.json +57 -0
  155. package/packages/investors/package.json +21 -0
  156. package/packages/legal/package.json +73 -0
  157. package/packages/marketing/package.json +63 -0
  158. package/packages/money/package.json +42 -0
  159. package/packages/operations/package.json +74 -0
  160. package/packages/partner/package.json +38 -0
  161. package/packages/people/package.json +64 -0
  162. package/packages/product/package.json +49 -0
  163. package/packages/raw/package.json +19 -0
  164. package/packages/relationships/package.json +52 -0
  165. package/packages/validation/package.json +112 -0
  166. package/platform/README.md +51 -0
  167. package/platform/adapter.json +15 -0
  168. package/platform/connectors/eval.mjs +154 -0
  169. package/platform/connectors/fake-github.mjs +91 -0
  170. package/platform/connectors/github.mjs +105 -0
  171. package/platform/integrations/jev.mjs +30 -0
  172. package/platform/integrations/langsmith-docket.mjs +53 -0
  173. package/platform/integrations/langsmith-setup.mjs +115 -0
  174. package/platform/integrations/langsmith.mjs +47 -0
  175. package/platform/integrations/remote-image.mjs +79 -0
  176. package/platform/integrations/rho.mjs +146 -0
  177. package/platform/integrations/site.mjs +75 -0
  178. package/platform/kits/README.md +14 -0
  179. package/platform/kits/agent-upgrade/kit.json +15 -0
  180. package/platform/kits/agent-upgrade/run.mjs +82 -0
  181. package/platform/kits/agent-upgrade/stand-in-agent.mjs +32 -0
  182. package/platform/kits/validation-kickoff/kit.json +29 -0
  183. package/platform/mcp/research.mjs +64 -0
  184. package/platform/webhooks/server.mjs +70 -0
  185. package/purpose/checklists/vault-and-tooling-consultancy-setup.md +216 -0
  186. package/purpose/frameworks/business-discovery-framework-amendments-2026-05-20.md +181 -0
  187. package/purpose/frameworks/business-discovery-framework.html +938 -0
  188. package/purpose/frameworks/business-discovery-framework.md +326 -0
  189. package/purpose/frameworks/idea-map/README.md +74 -0
  190. package/purpose/frameworks/idea-map/conventions.json +146 -0
  191. package/purpose/frameworks/idea-map/graph.mjs +182 -0
  192. package/purpose/frameworks/idea-map/ideamap.mjs +181 -0
  193. package/purpose/frameworks/idea-map/route.mjs +140 -0
  194. package/purpose/frameworks/onboarding-handoff-framework.md +269 -0
  195. package/purpose/frameworks/post-discovery-deliverable-playbook.md +274 -0
  196. package/purpose/frameworks/product-anatomy/README.md +63 -0
  197. package/purpose/frameworks/product-anatomy/anatomy.mjs +195 -0
  198. package/purpose/frameworks/product-anatomy/examples/polity.answers.reasoned.json +11 -0
  199. package/purpose/frameworks/product-anatomy/examples/polity.json +89 -0
  200. package/purpose/frameworks/product-anatomy/phases.json +107 -0
  201. package/purpose/frameworks/product-anatomy/questions.json +74 -0
  202. package/purpose/kits/validation/README.md +14 -0
  203. package/purpose/kits/validation/references/references.json +122 -0
  204. package/purpose/kits/validation/skills/problem-validation/SKILL.md +43 -0
  205. package/purpose/kits/validation/skills/validation-score/SKILL.md +35 -0
  206. package/purpose/kits/validation/templates/go-to-market.md +19 -0
  207. package/purpose/kits/validation/templates/operations-readiness.md +20 -0
  208. package/purpose/kits/validation/templates/pricing.md +22 -0
  209. package/purpose/kits/validation/templates/problem-interview.md +36 -0
  210. package/purpose/kits/validation/templates/problem.md +45 -0
  211. package/purpose/kits/validation/templates/product-market-fit.md +23 -0
  212. package/purpose/kits/validation/templates/solution.md +18 -0
  213. package/purpose/kits/validation/templates/team.md +19 -0
  214. package/purpose/kits/validation/weights.json +22 -0
  215. package/purpose/layer.json +53 -0
  216. package/purpose/references/references.json +324 -0
  217. package/purpose/skills/ambition-tier/SKILL.md +205 -0
  218. package/purpose/skills/telos/SKILL.md +52 -0
  219. package/purpose/strategic-foundation.json +133 -0
  220. package/purpose/templates/telos-based-smart.md +39 -0
  221. package/purpose/tooling/integrations.json +48 -0
  222. package/schema/README.md +62 -0
  223. package/schema/VERSION +1 -0
  224. package/schema/access.mjs +57 -0
  225. package/schema/account.schema.json +79 -0
  226. package/schema/adapter.schema.json +33 -0
  227. package/schema/add-department.mjs +41 -0
  228. package/schema/agent-capability.schema.json +94 -0
  229. package/schema/alignment.schema.json +61 -0
  230. package/schema/assess-problem.mjs +131 -0
  231. package/schema/assets.mjs +212 -0
  232. package/schema/bdd.mjs +56 -0
  233. package/schema/board.schema.json +101 -0
  234. package/schema/brand.mjs +373 -0
  235. package/schema/build-release.mjs +61 -0
  236. package/schema/caching.mjs +505 -0
  237. package/schema/check-assets.mjs +24 -0
  238. package/schema/check-boundary.mjs +54 -0
  239. package/schema/check-brand.mjs +24 -0
  240. package/schema/check-config.mjs +110 -0
  241. package/schema/check-data-model.mjs +170 -0
  242. package/schema/check-data-packages.mjs +83 -0
  243. package/schema/check-departments.mjs +45 -0
  244. package/schema/check-execution.mjs +85 -0
  245. package/schema/check-governance.mjs +98 -0
  246. package/schema/check-integrations.mjs +33 -0
  247. package/schema/check-nextjs-status.mjs +79 -0
  248. package/schema/check-nouns.mjs +49 -0
  249. package/schema/check-people.mjs +70 -0
  250. package/schema/check-private.mjs +61 -0
  251. package/schema/check-provenance.mjs +55 -0
  252. package/schema/check-publication.mjs +96 -0
  253. package/schema/check-ready.mjs +89 -0
  254. package/schema/check-sources.mjs +74 -0
  255. package/schema/check-team.mjs +94 -0
  256. package/schema/check-telos.mjs +59 -0
  257. package/schema/check-validation.mjs +165 -0
  258. package/schema/check-ventures.mjs +81 -0
  259. package/schema/check-where-used.mjs +58 -0
  260. package/schema/data-master.schema.json +14 -0
  261. package/schema/data-model.json +1584 -0
  262. package/schema/data-model.schema.json +152 -0
  263. package/schema/deal.schema.json +80 -0
  264. package/schema/decision-analytics.mjs +77 -0
  265. package/schema/decision-record.schema.json +290 -0
  266. package/schema/decision-rights.schema.json +34 -0
  267. package/schema/decision.schema.json +30 -0
  268. package/schema/decisions.mjs +327 -0
  269. package/schema/department-catalog.schema.json +55 -0
  270. package/schema/department.schema.json +15 -0
  271. package/schema/departments.mjs +32 -0
  272. package/schema/docket-eval.mjs +89 -0
  273. package/schema/docket.mjs +135 -0
  274. package/schema/eval-suite.schema.json +45 -0
  275. package/schema/evidence.schema.json +110 -0
  276. package/schema/examples/frames/judge.mjs +10 -0
  277. package/schema/examples/migrate/agent.mjs +12 -0
  278. package/schema/examples/venture-type/jev.mjs +12 -0
  279. package/schema/examples/workspace/ventures/acme-labs/AGENTS.md +17 -0
  280. package/schema/examples/workspace/ventures/acme-labs/accounts/.gitkeep +0 -0
  281. package/schema/examples/workspace/ventures/acme-labs/decisions/discovery-goal.decision.json +23 -0
  282. package/schema/examples/workspace/ventures/acme-labs/decisions/statement-icp.decision.json +22 -0
  283. package/schema/examples/workspace/ventures/acme-labs/decisions/statement-problem.decision.json +22 -0
  284. package/schema/examples/workspace/ventures/acme-labs/decisions/venture.team.decision.json +37 -0
  285. package/schema/examples/workspace/ventures/acme-labs/knowledge/README.md +3 -0
  286. package/schema/examples/workspace/ventures/acme-labs/knowledge/sources.json +46 -0
  287. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000001.json +12 -0
  288. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000002.json +12 -0
  289. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000003.json +12 -0
  290. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000004.json +12 -0
  291. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000005.json +12 -0
  292. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000006.json +12 -0
  293. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000007.json +12 -0
  294. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000008.json +12 -0
  295. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000009.json +12 -0
  296. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000010.json +12 -0
  297. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000011.json +12 -0
  298. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000012.json +12 -0
  299. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000013.json +12 -0
  300. package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000014.json +12 -0
  301. package/schema/examples/workspace/ventures/acme-labs/money/_streams/transactions/stream.json +5 -0
  302. package/schema/examples/workspace/ventures/acme-labs/money/_summary.json +30 -0
  303. package/schema/examples/workspace/ventures/acme-labs/operations/departments/customer-service/README.md +5 -0
  304. package/schema/examples/workspace/ventures/acme-labs/operations/departments/customer-service/department.json +5 -0
  305. package/schema/examples/workspace/ventures/acme-labs/operations/departments/finance/README.md +5 -0
  306. package/schema/examples/workspace/ventures/acme-labs/operations/departments/finance/department.json +5 -0
  307. package/schema/examples/workspace/ventures/acme-labs/operations/departments/human-capital/README.md +5 -0
  308. package/schema/examples/workspace/ventures/acme-labs/operations/departments/human-capital/department.json +5 -0
  309. package/schema/examples/workspace/ventures/acme-labs/operations/departments/it/README.md +5 -0
  310. package/schema/examples/workspace/ventures/acme-labs/operations/departments/it/department.json +5 -0
  311. package/schema/examples/workspace/ventures/acme-labs/operations/departments/marketing-and-sales/README.md +5 -0
  312. package/schema/examples/workspace/ventures/acme-labs/operations/departments/marketing-and-sales/department.json +5 -0
  313. package/schema/examples/workspace/ventures/acme-labs/operations/departments/products/README.md +5 -0
  314. package/schema/examples/workspace/ventures/acme-labs/operations/departments/products/department.json +5 -0
  315. package/schema/examples/workspace/ventures/acme-labs/operations/departments/strategy/README.md +5 -0
  316. package/schema/examples/workspace/ventures/acme-labs/operations/departments/strategy/department.json +5 -0
  317. package/schema/examples/workspace/ventures/acme-labs/people/founders/maya-chen.json +15 -0
  318. package/schema/examples/workspace/ventures/acme-labs/people/people.json +22 -0
  319. package/schema/examples/workspace/ventures/acme-labs/pillars/brand.md +5 -0
  320. package/schema/examples/workspace/ventures/acme-labs/pillars/business.md +5 -0
  321. package/schema/examples/workspace/ventures/acme-labs/pillars/product.md +5 -0
  322. package/schema/examples/workspace/ventures/acme-labs/products/.gitkeep +0 -0
  323. package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.core-product.decision.json +28 -0
  324. package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.exists.decision.json +38 -0
  325. package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.flagship.decision.json +27 -0
  326. package/schema/examples/workspace/ventures/acme-labs/profile.md +12 -0
  327. package/schema/examples/workspace/ventures/acme-labs/provenance.jsonl +12 -0
  328. package/schema/examples/workspace/ventures/acme-labs/raw/dump.md +6 -0
  329. package/schema/examples/workspace/ventures/acme-labs/venture.json +27 -0
  330. package/schema/examples/workspace/ventures/northstar/AGENTS.md +17 -0
  331. package/schema/examples/workspace/ventures/northstar/accounts/.gitkeep +0 -0
  332. package/schema/examples/workspace/ventures/northstar/deals/ductline.json +8 -0
  333. package/schema/examples/workspace/ventures/northstar/deals/kilnworks.json +14 -0
  334. package/schema/examples/workspace/ventures/northstar/decisions/venture.team.decision.json +31 -0
  335. package/schema/examples/workspace/ventures/northstar/evidence/README.md +3 -0
  336. package/schema/examples/workspace/ventures/northstar/fund/decisions/terms.decision.json +27 -0
  337. package/schema/examples/workspace/ventures/northstar/fund/decisions/terms.first-close.decision.json +27 -0
  338. package/schema/examples/workspace/ventures/northstar/fund/decisions/thesis.decision.json +26 -0
  339. package/schema/examples/workspace/ventures/northstar/fund/terms.json +22 -0
  340. package/schema/examples/workspace/ventures/northstar/fund/thesis.json +22 -0
  341. package/schema/examples/workspace/ventures/northstar/governance/README.md +3 -0
  342. package/schema/examples/workspace/ventures/northstar/governance/departments/external-relationships/charter.md +5 -0
  343. package/schema/examples/workspace/ventures/northstar/governance/departments/external-relationships/department.json +5 -0
  344. package/schema/examples/workspace/ventures/northstar/governance/departments/finance/charter.md +5 -0
  345. package/schema/examples/workspace/ventures/northstar/governance/departments/finance/department.json +5 -0
  346. package/schema/examples/workspace/ventures/northstar/governance/departments/human-capital/charter.md +5 -0
  347. package/schema/examples/workspace/ventures/northstar/governance/departments/human-capital/department.json +5 -0
  348. package/schema/examples/workspace/ventures/northstar/governance/departments/risk-and-compliance/charter.md +5 -0
  349. package/schema/examples/workspace/ventures/northstar/governance/departments/risk-and-compliance/department.json +5 -0
  350. package/schema/examples/workspace/ventures/northstar/governance/departments/strategy/charter.md +5 -0
  351. package/schema/examples/workspace/ventures/northstar/governance/departments/strategy/department.json +5 -0
  352. package/schema/examples/workspace/ventures/northstar/knowledge/README.md +3 -0
  353. package/schema/examples/workspace/ventures/northstar/operations/README.md +3 -0
  354. package/schema/examples/workspace/ventures/northstar/operations/departments/external-relationships/README.md +5 -0
  355. package/schema/examples/workspace/ventures/northstar/operations/departments/external-relationships/department.json +5 -0
  356. package/schema/examples/workspace/ventures/northstar/operations/departments/finance/README.md +5 -0
  357. package/schema/examples/workspace/ventures/northstar/operations/departments/finance/department.json +5 -0
  358. package/schema/examples/workspace/ventures/northstar/operations/departments/human-capital/README.md +5 -0
  359. package/schema/examples/workspace/ventures/northstar/operations/departments/human-capital/department.json +5 -0
  360. package/schema/examples/workspace/ventures/northstar/operations/departments/risk-and-compliance/README.md +5 -0
  361. package/schema/examples/workspace/ventures/northstar/operations/departments/risk-and-compliance/department.json +5 -0
  362. package/schema/examples/workspace/ventures/northstar/operations/departments/strategy/README.md +5 -0
  363. package/schema/examples/workspace/ventures/northstar/operations/departments/strategy/department.json +5 -0
  364. package/schema/examples/workspace/ventures/northstar/people/founders/ana-ruiz.json +13 -0
  365. package/schema/examples/workspace/ventures/northstar/people/founders/ben-okafor.json +7 -0
  366. package/schema/examples/workspace/ventures/northstar/people/people.json +27 -0
  367. package/schema/examples/workspace/ventures/northstar/pillars/brand.md +5 -0
  368. package/schema/examples/workspace/ventures/northstar/pillars/business.md +5 -0
  369. package/schema/examples/workspace/ventures/northstar/pillars/product.md +5 -0
  370. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/AGENTS.md +17 -0
  371. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/accounts/.gitkeep +0 -0
  372. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/decisions/venture.team.decision.json +31 -0
  373. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/knowledge/README.md +3 -0
  374. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/customer-service/README.md +5 -0
  375. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/customer-service/department.json +5 -0
  376. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/finance/README.md +5 -0
  377. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/finance/department.json +5 -0
  378. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/human-capital/README.md +5 -0
  379. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/human-capital/department.json +5 -0
  380. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/it/README.md +5 -0
  381. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/it/department.json +5 -0
  382. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/marketing-and-sales/README.md +5 -0
  383. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/marketing-and-sales/department.json +5 -0
  384. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/products/README.md +5 -0
  385. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/products/department.json +5 -0
  386. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/strategy/README.md +5 -0
  387. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/strategy/department.json +5 -0
  388. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/brand.md +5 -0
  389. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/business.md +5 -0
  390. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/product.md +5 -0
  391. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/.gitkeep +0 -0
  392. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.core-product.decision.json +28 -0
  393. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.exists.decision.json +32 -0
  394. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.flagship.decision.json +27 -0
  395. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/profile.md +5 -0
  396. package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/venture.json +27 -0
  397. package/schema/examples/workspace/ventures/northstar/products/.gitkeep +0 -0
  398. package/schema/examples/workspace/ventures/northstar/profile.md +5 -0
  399. package/schema/examples/workspace/ventures/northstar/provenance.jsonl +3 -0
  400. package/schema/examples/workspace/ventures/northstar/purpose/README.md +3 -0
  401. package/schema/examples/workspace/ventures/northstar/venture.json +49 -0
  402. package/schema/examples/workspace/ventures/studio/accounts/bakery/account.json +18 -0
  403. package/schema/examples/workspace/ventures/studio/evidence/.gitkeep +0 -0
  404. package/schema/examples/workspace/ventures/studio/governance/.gitkeep +0 -0
  405. package/schema/examples/workspace/ventures/studio/knowledge/.gitkeep +0 -0
  406. package/schema/examples/workspace/ventures/studio/operations/.gitkeep +0 -0
  407. package/schema/examples/workspace/ventures/studio/print/knowledge/.gitkeep +0 -0
  408. package/schema/examples/workspace/ventures/studio/print/purpose/.gitkeep +0 -0
  409. package/schema/examples/workspace/ventures/studio/print/venture.json +37 -0
  410. package/schema/examples/workspace/ventures/studio/products/brand-care.json +19 -0
  411. package/schema/examples/workspace/ventures/studio/products/brand-kit.json +23 -0
  412. package/schema/examples/workspace/ventures/studio/provenance.jsonl +3 -0
  413. package/schema/examples/workspace/ventures/studio/purpose/.gitkeep +0 -0
  414. package/schema/examples/workspace/ventures/studio/venture.json +43 -0
  415. package/schema/examples/workspace/ventures/tandem/accounts/.gitkeep +0 -0
  416. package/schema/examples/workspace/ventures/tandem/evidence/README.md +3 -0
  417. package/schema/examples/workspace/ventures/tandem/governance/README.md +3 -0
  418. package/schema/examples/workspace/ventures/tandem/governance/agreements/dee-fast.md +3 -0
  419. package/schema/examples/workspace/ventures/tandem/governance/board.json +51 -0
  420. package/schema/examples/workspace/ventures/tandem/governance/departments/finance/charter.md +5 -0
  421. package/schema/examples/workspace/ventures/tandem/governance/departments/finance/department.json +5 -0
  422. package/schema/examples/workspace/ventures/tandem/governance/departments/primary/marketing-and-sales/charter.md +5 -0
  423. package/schema/examples/workspace/ventures/tandem/governance/departments/primary/marketing-and-sales/department.json +5 -0
  424. package/schema/examples/workspace/ventures/tandem/governance/exit.json +33 -0
  425. package/schema/examples/workspace/ventures/tandem/governance/founder-agreement.json +24 -0
  426. package/schema/examples/workspace/ventures/tandem/governance/founder-agreement.md +3 -0
  427. package/schema/examples/workspace/ventures/tandem/governance/ownership.json +131 -0
  428. package/schema/examples/workspace/ventures/tandem/governance/publication-policy.json +171 -0
  429. package/schema/examples/workspace/ventures/tandem/knowledge/README.md +3 -0
  430. package/schema/examples/workspace/ventures/tandem/knowledge/research/friends-feedback-2026-08.md +3 -0
  431. package/schema/examples/workspace/ventures/tandem/knowledge/research/pilot-2026-10.md +3 -0
  432. package/schema/examples/workspace/ventures/tandem/knowledge/research/problem-interviews-2026-09.md +20 -0
  433. package/schema/examples/workspace/ventures/tandem/knowledge/sources.json +8 -0
  434. package/schema/examples/workspace/ventures/tandem/knowledge/where-used.json +13 -0
  435. package/schema/examples/workspace/ventures/tandem/operations/README.md +3 -0
  436. package/schema/examples/workspace/ventures/tandem/operations/departments/finance/README.md +5 -0
  437. package/schema/examples/workspace/ventures/tandem/operations/departments/finance/department.json +5 -0
  438. package/schema/examples/workspace/ventures/tandem/operations/departments/primary/marketing-and-sales/README.md +5 -0
  439. package/schema/examples/workspace/ventures/tandem/operations/departments/primary/marketing-and-sales/department.json +5 -0
  440. package/schema/examples/workspace/ventures/tandem/pillars/brand.md +5 -0
  441. package/schema/examples/workspace/ventures/tandem/pillars/business.md +5 -0
  442. package/schema/examples/workspace/ventures/tandem/pillars/product.md +5 -0
  443. package/schema/examples/workspace/ventures/tandem/products/.gitkeep +0 -0
  444. package/schema/examples/workspace/ventures/tandem/products/shop-app.json +22 -0
  445. package/schema/examples/workspace/ventures/tandem/profile.md +5 -0
  446. package/schema/examples/workspace/ventures/tandem/provenance.jsonl +13 -0
  447. package/schema/examples/workspace/ventures/tandem/purpose/README.md +3 -0
  448. package/schema/examples/workspace/ventures/tandem/purpose/telos.json +78 -0
  449. package/schema/examples/workspace/ventures/tandem/purpose/validation/go-to-market.json +35 -0
  450. package/schema/examples/workspace/ventures/tandem/purpose/validation/pricing.json +37 -0
  451. package/schema/examples/workspace/ventures/tandem/purpose/validation/problem.json +74 -0
  452. package/schema/examples/workspace/ventures/tandem/purpose/validation/product-market-fit.json +66 -0
  453. package/schema/examples/workspace/ventures/tandem/purpose/validation/solution.json +33 -0
  454. package/schema/examples/workspace/ventures/tandem/purpose/validation/team.json +52 -0
  455. package/schema/examples/workspace/ventures/tandem/venture.json +79 -0
  456. package/schema/examples/workspace/ventures/woodworking/knowledge/.gitkeep +0 -0
  457. package/schema/examples/workspace/ventures/woodworking/venture.json +21 -0
  458. package/schema/examples/workspace/workspace.json +8 -0
  459. package/schema/exit.schema.json +74 -0
  460. package/schema/foundation.mjs +118 -0
  461. package/schema/founder-agreement.schema.json +83 -0
  462. package/schema/founder.schema.json +72 -0
  463. package/schema/frame.schema.json +240 -0
  464. package/schema/frames.mjs +228 -0
  465. package/schema/freshness-log.schema.json +40 -0
  466. package/schema/freshness-profiles.schema.json +44 -0
  467. package/schema/freshness.mjs +473 -0
  468. package/schema/fund-terms.schema.json +107 -0
  469. package/schema/fund-thesis.schema.json +87 -0
  470. package/schema/gate-drafts.mjs +130 -0
  471. package/schema/gate.mjs +133 -0
  472. package/schema/glossary.schema.json +25 -0
  473. package/schema/handoff.schema.json +239 -0
  474. package/schema/icp.schema.json +136 -0
  475. package/schema/idea-graph.schema.json +61 -0
  476. package/schema/init-venture.mjs +128 -0
  477. package/schema/integration.schema.json +143 -0
  478. package/schema/judgment.schema.json +38 -0
  479. package/schema/kit.schema.json +47 -0
  480. package/schema/kits.mjs +24 -0
  481. package/schema/knowledge-sources.schema.json +260 -0
  482. package/schema/layer.json +59 -0
  483. package/schema/layer.schema.json +119 -0
  484. package/schema/load-packages.mjs +26 -0
  485. package/schema/marketing-brand.schema.json +116 -0
  486. package/schema/marketing-sitemap.schema.json +232 -0
  487. package/schema/migrate-venture.mjs +192 -0
  488. package/schema/migrations/kit-to-package.mjs +94 -0
  489. package/schema/migrations/package-layout.mjs +86 -0
  490. package/schema/model-steps.mjs +717 -0
  491. package/schema/money-summary.schema.json +138 -0
  492. package/schema/naive-config.mjs +165 -0
  493. package/schema/naive-config.schema.json +268 -0
  494. package/schema/need-now.json +772 -0
  495. package/schema/need-now.mjs +108 -0
  496. package/schema/nextjs-status.schema.json +29 -0
  497. package/schema/ownership.schema.json +282 -0
  498. package/schema/packages.json +4 -0
  499. package/schema/packages.mjs +252 -0
  500. package/schema/payouts.mjs +91 -0
  501. package/schema/people.schema.json +86 -0
  502. package/schema/port-venture.mjs +161 -0
  503. package/schema/product.schema.json +223 -0
  504. package/schema/provenance-entry.schema.json +154 -0
  505. package/schema/public-assets.schema.json +76 -0
  506. package/schema/publication-policy.schema.json +293 -0
  507. package/schema/raw-source.schema.json +15 -0
  508. package/schema/reference.schema.json +115 -0
  509. package/schema/release-read.mjs +111 -0
  510. package/schema/releases.mjs +497 -0
  511. package/schema/route-aliases.schema.json +25 -0
  512. package/schema/run-handoff.mjs +51 -0
  513. package/schema/scaffold/defaults.json +54 -0
  514. package/schema/setup.mjs +164 -0
  515. package/schema/site-presence.schema.json +337 -0
  516. package/schema/stale.mjs +111 -0
  517. package/schema/start-release.mjs +41 -0
  518. package/schema/strategic-foundation.schema.json +74 -0
  519. package/schema/stream.schema.json +14 -0
  520. package/schema/structure.mjs +186 -0
  521. package/schema/systems-catalog.json +126 -0
  522. package/schema/systems-catalog.schema.json +78 -0
  523. package/schema/team-plan.schema.json +157 -0
  524. package/schema/telos.schema.json +197 -0
  525. package/schema/time-to-ready.mjs +93 -0
  526. package/schema/trigger.schema.json +44 -0
  527. package/schema/triggers.mjs +237 -0
  528. package/schema/upgrade-registry.schema.json +60 -0
  529. package/schema/upgrade-venture.mjs +107 -0
  530. package/schema/upgrades.json +69 -0
  531. package/schema/upgrades.mjs +385 -0
  532. package/schema/use-model.mjs +10 -0
  533. package/schema/validate.py +58 -0
  534. package/schema/validation-evidence.schema.json +123 -0
  535. package/schema/validation-go-to-market.schema.json +110 -0
  536. package/schema/validation-operations-readiness.schema.json +91 -0
  537. package/schema/validation-pricing.schema.json +114 -0
  538. package/schema/validation-problem.schema.json +118 -0
  539. package/schema/validation-product-market-fit.schema.json +135 -0
  540. package/schema/validation-solution.schema.json +79 -0
  541. package/schema/validation-team.schema.json +116 -0
  542. package/schema/venture-role.schema.json +64 -0
  543. package/schema/venture-type.mjs +62 -0
  544. package/schema/venture-types.json +346 -0
  545. package/schema/venture-types.schema.json +129 -0
  546. package/schema/venture.schema.json +460 -0
  547. package/schema/vocab/business-models.json +298 -0
  548. package/schema/where-used.schema.json +56 -0
  549. package/schema/workspace.schema.json +38 -0
@@ -0,0 +1,218 @@
1
+ #!/usr/bin/env node
2
+ // Error boundaries (Next.js translation P-15, E-5, E-6, E-8). Expected errors stay answers, never throws.
3
+ //
4
+ // global-error a broken venture.json, or a broken framework file (the data model, a layer or package
5
+ // manifest), answers with what is wrong and the recovery steps, instead of a stack trace.
6
+ // One broken venture never stops the router from finding the others.
7
+ // boundary a failing check in one package is contained there: the other packages proceed, and
8
+ // only a venture-level failure (venture.json, the folder structure) reaches the venture.
9
+ // per record one bad record (a file that does not parse or does not match its schema) does not fail
10
+ // its package's read or check: the others come back, and the bad one is named with its fix.
11
+ //
12
+ // node interface/boundaries.mjs check <venture dir> [--package <name>] [--json] the boundaries, exit 1 on a failure
13
+ // node interface/boundaries.mjs recover <venture dir> --confirm recover rebuild a broken venture.json
14
+ //
15
+ // The router calls these through interface/writes.mjs; `mentura venture check` and `mentura <package> check`
16
+ // run them. Never calls a model.
17
+
18
+ import { spawnSync } from "node:child_process";
19
+ import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync } from "node:fs";
20
+ import { basename, dirname, join } from "node:path";
21
+
22
+ const repo = new URL("..", import.meta.url).pathname;
23
+ const load = (f) => JSON.parse(readFileSync(f, "utf8"));
24
+
25
+ // Where a JSON parse failed: line and column from the position in the message, when it gives one.
26
+ function where(text, message) {
27
+ const m = message.match(/position (\d+)/);
28
+ if (!m && /end of JSON input/.test(message)) return ` (at the end of the file, line ${text.split("\n").length})`;
29
+ if (!m || /line \d+/.test(message)) return "";
30
+ const before = text.slice(0, Number(m[1]));
31
+ const line = before.split("\n").length, col = before.length - before.lastIndexOf("\n");
32
+ return ` (line ${line}, column ${col})`;
33
+ }
34
+
35
+ /** Why a JSON file is broken, or null. */
36
+ export function jsonProblem(file) {
37
+ if (!existsSync(file)) return "is missing";
38
+ const text = readFileSync(file, "utf8");
39
+ try { JSON.parse(text); return null; } catch (e) { return `does not parse: ${String(e.message).split("\n")[0]}${where(text, String(e.message))}`; }
40
+ }
41
+
42
+ const VENTURE_SCHEMA = () => load(join(repo, "schema/venture.schema.json"));
43
+
44
+ /** A minimal venture.json for a folder, from the schema's required fields: what recover writes. */
45
+ export function minimalVenture(dir) {
46
+ const id = basename(dir).toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "") || "venture";
47
+ return { id, name: id, parent: null, phase: "discovery", owner: "self", status: "active", profile: "profile.md",
48
+ layers: Object.fromEntries(["purpose", "knowledge", "operations", "evidence", "governance", "interface"].map((l) => [l, existsSync(join(dir, l)) ? { location: `${l}/` } : false])) };
49
+ }
50
+
51
+ /**
52
+ * The venture's global error (E-8, P-15): null when venture.json is sound, else what is wrong and
53
+ * how to recover. Checks what the router needs before anything else runs: it parses, its required
54
+ * fields are there, its id and phase are valid. The full schema check stays in schema/validate.py.
55
+ */
56
+ export function ventureHealth(dir) {
57
+ const file = join(dir, "venture.json");
58
+ let problem = jsonProblem(file);
59
+ if (!problem) {
60
+ const v = load(file), s = VENTURE_SCHEMA();
61
+ const missing = v && typeof v === "object" ? s.required.filter((k) => !(k in v)) : [];
62
+ if (!v || typeof v !== "object" || Array.isArray(v)) problem = "is not a JSON object";
63
+ else if (missing.length) problem = `is missing ${missing.join(", ")}`;
64
+ else if (!new RegExp(s.properties.id.pattern).test(String(v.id))) problem = `has id ${JSON.stringify(v.id)}, which is not lowercase letters, digits and hyphens`;
65
+ else if (!s.properties.phase.enum.includes(v.phase)) problem = `has phase ${JSON.stringify(v.phase)}, which is not one of ${s.properties.phase.enum.join(", ")}`;
66
+ else if (typeof v.layers !== "object" || v.layers === null) problem = "has layers that are not an object";
67
+ }
68
+ if (!problem) return null;
69
+ const git = spawnSync("git", ["-C", dir, "ls-files", "--error-unmatch", "venture.json"], { encoding: "utf8" }).status === 0;
70
+ return {
71
+ scope: "venture", file, problem: `venture.json ${problem}`,
72
+ recovery: [
73
+ ...(git ? [`Restore the last committed version: git -C ${dir} checkout -- venture.json`] : []),
74
+ `Fix it by hand: it must be a JSON object with ${VENTURE_SCHEMA().required.join(", ")}`,
75
+ `Or rebuild a minimal one, keeping the broken file in _private/: node interface/boundaries.mjs recover ${dir} --confirm recover`,
76
+ `Then check it: python3 schema/validate.py --schema venture.schema.json --file ${file}`,
77
+ ],
78
+ template: minimalVenture(dir),
79
+ };
80
+ }
81
+
82
+ // The framework files every route depends on. A broken one stops every route, so it is checked first.
83
+ function frameworkFiles() {
84
+ const fixed = ["schema/data-model.json", "schema/need-now.json", "schema/venture.schema.json", "packages/catalog.json", "purpose/frameworks/product-anatomy/phases.json", "purpose/strategic-foundation.json", "operations/departments.json"];
85
+ let layers = [];
86
+ try { layers = load(join(repo, "schema/data-model.json")).layers.map((l) => `${l}/layer.json`); } catch {}
87
+ const pkgs = existsSync(join(repo, "packages")) ? readdirSync(join(repo, "packages")).map((n) => `packages/${n}/package.json`).filter((f) => existsSync(join(repo, f))) : [];
88
+ return [...fixed, ...layers, "schema/layer.json", ...pkgs];
89
+ }
90
+
91
+ /** The framework's global error (E-8): null when the data model and manifests parse, else the file, the problem and how to recover. */
92
+ export function frameworkHealth() {
93
+ for (const f of frameworkFiles()) {
94
+ const problem = jsonProblem(join(repo, f));
95
+ if (!problem) continue;
96
+ return { scope: "framework", file: f, problem: `${f} ${problem}`, recovery: [
97
+ `Restore it: git -C ${repo} checkout -- ${f}`,
98
+ "Then check the data model and the manifests: node schema/check-data-model.mjs",
99
+ "No venture record was touched: every route stops until the framework file parses again.",
100
+ ] };
101
+ }
102
+ return null;
103
+ }
104
+
105
+ /** The answer a global error gives: an expected error with its recovery steps, never a throw. */
106
+ export function globalError(h, venture) {
107
+ const head = h.scope === "venture" ? `${venture ?? basename(dirname(h.file))}: ${h.problem}` : `the framework is broken: ${h.problem}`;
108
+ return { ok: false, outcome: "error", error: [head, "Recovery:", ...h.recovery.map((s, i) => ` ${i + 1}. ${s}`)].join("\n"), global_error: h };
109
+ }
110
+
111
+ /** Per-record containment (E-6): parses each item on its own; a bad one becomes an error beside the good ones. */
112
+ export function contain(items, parse, idOf = (x) => x.path) {
113
+ const values = [], errors = {};
114
+ for (const x of items) {
115
+ try { values.push([x, parse(x)]); } catch (e) { errors[idOf(x.path)] = { file: x.path, error: `${x.path} does not parse: ${String(e.message ?? e).split("\n")[0]}` }; }
116
+ }
117
+ return { values, errors };
118
+ }
119
+
120
+ function validateFile(file, schema) {
121
+ const p = spawnSync("python3", [join(repo, "schema/validate.py"), "--schema", schema.replace(/^schema\//, ""), "--file", file], { encoding: "utf8" });
122
+ return p.status === 0 ? null : (p.stdout + p.stderr).trim();
123
+ }
124
+
125
+ /**
126
+ * The boundaries of a venture (E-5): the venture level first (venture.json and its folder structure),
127
+ * then each package the venture uses, each contained. Inside a package each record is checked on its
128
+ * own (E-6), then the package's checks run. options.only limits it to some packages.
129
+ */
130
+ export async function boundaries(dir, { only = null } = {}) {
131
+ const { structure, checkManifest, manifest } = await import("../schema/structure.mjs");
132
+ const { routes, glob } = await import("./router.mjs");
133
+ const { routable } = await import("../schema/structure.mjs");
134
+ const h = ventureHealth(dir);
135
+ if (h) return { ok: false, reached: "venture", venture: { ok: false, error: h.problem, recovery: h.recovery }, packages: [], proceeds: [] };
136
+ const s = structure(dir);
137
+ const verrors = [...s.errors, ...checkManifest(dir)];
138
+ const venture = { ok: !verrors.length, ...(verrors.length ? { errors: verrors, fix: "node schema/structure.mjs " + dir } : {}), warnings: s.warnings };
139
+ const m = await manifest(dir);
140
+ // Asked for by name, a package is checked whether or not the venture lists it.
141
+ const names = only ? only.filter((n) => existsSync(join(repo, "packages", n, "package.json"))) : m.packages.list.filter((p) => p.known).map((p) => p.name);
142
+ const rs = routes().filter((r) => r.kind === "record" && r.collection !== "list");
143
+ const out = [];
144
+ for (const name of names) {
145
+ // A package's failure stays in its result: an exception here is caught and reported as that package's.
146
+ try {
147
+ const pkg = load(join(repo, "packages", name, "package.json"));
148
+ const types = [...new Set([...(pkg.required ?? []), ...(pkg.optional ?? []), ...(pkg.records ?? [])])];
149
+ const records = [], checks = new Set((pkg.checks ?? []).filter((c) => /^schema\/check-[a-z-]+\.mjs$/.test(c) && c !== "schema/check-data-model.mjs" && existsSync(join(repo, c))));
150
+ for (const t of types) {
151
+ const r = rs.find((x) => x.record === t);
152
+ if (!r) continue;
153
+ for (const c of r.checks ?? []) checks.add(c);
154
+ const pats = r.files;
155
+ const hits = files(dir).filter((f) => pats.some((g) => glob(g).test(f) && routable(f, g)));
156
+ for (const f of hits) {
157
+ const problem = f.endsWith(".json") ? jsonProblem(join(dir, f)) ?? (r.schema ? validateFile(join(dir, f), r.schema) : null) : null;
158
+ records.push({ record: t, route: r.collection === "item" ? r.route.replace("[id]", starOf(f, pats) ?? basename(f)) : r.route, file: f, ok: !problem,
159
+ ...(problem ? { error: problem, fix: { schema: r.schema, template: r.template, skills: pkg.skill?.path ? [pkg.skill.path] : [] } } : {}) });
160
+ }
161
+ }
162
+ const ran = [...checks].map((c) => { const p = spawnSync("node", [join(repo, c), dir], { encoding: "utf8" }); return { check: c, passed: p.status === 0, output: (p.stdout + p.stderr).trim().split("\n").slice(-5).join("\n") }; });
163
+ const ok = records.every((x) => x.ok) && ran.every((x) => x.passed);
164
+ out.push({ package: name, ok, records, checks: ran });
165
+ } catch (e) {
166
+ out.push({ package: name, ok: false, error: `uncaught in ${name}: ${String(e.message ?? e).split("\n")[0]}`, records: [], checks: [] });
167
+ }
168
+ }
169
+ const failed = out.filter((p) => !p.ok).map((p) => p.package);
170
+ return { ok: venture.ok && !failed.length, reached: !venture.ok ? "venture" : failed.length ? "package" : null, venture, packages: out, contained: failed, proceeds: out.filter((p) => p.ok).map((p) => p.package) };
171
+ }
172
+
173
+ // The id a collection pattern's one star matches in a file (customers/[id].json, accounts/[id]/account.json).
174
+ export function starOf(file, patterns) {
175
+ for (const g of patterns) {
176
+ if (!g.includes("*") || g.includes("**")) continue;
177
+ const m = file.match(new RegExp("^" + g.split("*").map((x) => x.replace(/[.+^${}()|[\]\\]/g, "\\$&")).join("([^/]*)") + "$"));
178
+ if (m) return m[1];
179
+ }
180
+ return null;
181
+ }
182
+
183
+ // A venture's files, skipping dot folders, nested ventures and the root's private folders (as the router does).
184
+ function files(d, base = d) {
185
+ return existsSync(d) ? readdirSync(d, { withFileTypes: true }).flatMap((e) => e.name.startsWith(".") ? [] : e.isDirectory()
186
+ ? (existsSync(join(d, e.name, "venture.json")) || (d === base && e.name.startsWith("_")) ? [] : files(join(d, e.name), base)) : [join(d, e.name).slice(base.length + 1)]) : [];
187
+ }
188
+
189
+ /** Rebuilds a broken venture.json (E-8): the broken file moves to _private/, and a minimal one takes its place. */
190
+ export function recover(dir) {
191
+ const h = ventureHealth(dir);
192
+ if (!h) return { ok: true, result: "venture.json is sound: nothing to recover" };
193
+ const kept = join("_private", `venture.json.broken-${new Date().toISOString().replace(/[:.]/g, "-")}`);
194
+ if (existsSync(join(dir, "venture.json"))) { mkdirSync(join(dir, "_private"), { recursive: true }); renameSync(join(dir, "venture.json"), join(dir, kept)); }
195
+ writeFileSync(join(dir, "venture.json"), JSON.stringify(minimalVenture(dir), null, 2) + "\n");
196
+ return { ok: true, result: { written: "venture.json", kept: existsSync(join(dir, kept)) ? kept : null, note: "a minimal venture.json: copy back what you need from the kept file, then check it" } };
197
+ }
198
+
199
+ if (import.meta.url === `file://${process.argv[1]}`) {
200
+ const [cmd, dir] = process.argv.slice(2);
201
+ const opt = (n) => { const i = process.argv.indexOf(`--${n}`); return i >= 0 ? process.argv[i + 1] : undefined; };
202
+ if (!["check", "recover"].includes(cmd) || !dir || !existsSync(dir)) { console.error("usage: node interface/boundaries.mjs check <venture dir> [--package <name>] [--json] | recover <venture dir> --confirm recover"); process.exit(2); }
203
+ if (cmd === "recover") {
204
+ if (opt("confirm") !== "recover") { console.error("recover rewrites venture.json: pass --confirm recover"); process.exit(1); }
205
+ const r = recover(dir);
206
+ console.log(typeof r.result === "string" ? r.result : JSON.stringify(r.result, null, 2));
207
+ process.exit(0);
208
+ }
209
+ const fw = frameworkHealth();
210
+ if (fw) { console.error(globalError(fw).error); process.exit(1); }
211
+ const b = await boundaries(dir, { only: opt("package") ? [opt("package")] : null });
212
+ if (process.argv.includes("--json")) console.log(JSON.stringify(b, null, 2));
213
+ else {
214
+ console.log(`venture: ${b.venture.ok ? "ok" : `failed: ${(b.venture.errors ?? [b.venture.error]).join("; ")}`}`);
215
+ for (const p of b.packages) console.log(`${p.package.padEnd(14)} ${p.ok ? "ok" : `contained: ${[p.error, ...p.records.filter((x) => !x.ok).map((x) => `${x.file} ${x.error.split("\n")[0]}`), ...p.checks.filter((x) => !x.passed).map((x) => `${x.check} failed`)].filter(Boolean).join("; ")}`}`);
216
+ }
217
+ process.exit(b.ok ? 0 : 1);
218
+ }
@@ -0,0 +1,214 @@
1
+ // The brand and asset verbs of the CLI (mentura brand ..., mentura assets ...). Every write goes
2
+ // through the router, so it is checked against its schema and logged in provenance; the logic lives
3
+ // in schema/brand.mjs and schema/assets.mjs.
4
+ //
5
+ // mentura assets add <public/file> --venture <id> --source <who or url> --license <id> --credit <who>
6
+ // [--alt <text>] [--decorative] [--as person]
7
+ // register a file in public/; code fills its facts (J-2, J-4)
8
+ // mentura assets fill --venture <id> refill every entry's facts from its file, by code (J-4)
9
+ // mentura assets alt <public/file> --text <alt> --venture <id> [--as person]
10
+ // write alt text; an agent's waits for a person to confirm it
11
+ // mentura assets confirm <public/file> --venture <id> --by <name> [--confirm <public/file>]
12
+ // a person confirms the alt text as it stands (J-4)
13
+ // mentura assets remote <url> --venture <id> --license <id> --credit <who> [--id <raw id>] [--alt <text>] [--note <text>]
14
+ // record a remote image as a link with a note in raw/ (J-3)
15
+ // mentura assets hosts <host,host> --venture <id> set the hosts an agent may fetch from (J-3)
16
+ // mentura assets check|facts --venture <id>
17
+ // mentura brand tokens|css|head|check|voice --venture <id> [--json]
18
+ // mentura brand resolve <route> --venture <id> the brand at a route, nearer context winning (Y-5, T-2)
19
+ // mentura brand terms <package> --venture <id> the terms a package sees (Y-2)
20
+ // mentura brand sitemap --venture <id> --base <url> [--out <file>] sitemap.xml from the marketing sitemap (P-26)
21
+
22
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
23
+ import { dirname, join, resolve as resolvePath } from "node:path";
24
+ import { call, ventureDir } from "./router.mjs";
25
+ import { agentFromEnv, record as prov } from "./provenance.mjs";
26
+ import { altStatement, checkAssets, facts as allFacts, factsOf, REGISTER, registerOf } from "../schema/assets.mjs";
27
+ import { brandOf, checkBrand, resolveBrand, sitemapOf, sitemapXml, termsFor, tokens, voice } from "../schema/brand.mjs";
28
+
29
+ const VERSION = "0.1.0";
30
+ const today = () => new Date().toISOString();
31
+
32
+ /** The facts code reads, in the register's shape. */
33
+ export const factsFor = (dir, path) => {
34
+ const f = factsOf(readFileSync(join(dir, path)));
35
+ return Object.fromEntries(Object.entries({ type: f.type, width: f.width, height: f.height, sizes: f.sizes, bytes: f.bytes, sha256: f.sha256, filled_at: today() }).filter(([, v]) => v !== undefined));
36
+ };
37
+
38
+ const emptyRegister = () => ({ version: VERSION, assets: [] });
39
+
40
+ /** Writes the register through the router: schema first, then provenance. */
41
+ export async function writeRegister(venture, workspace, reg, { actor = "agent", note } = {}) {
42
+ return call({ venture, route: "public/assets", action: "write", input: reg, actor, workspace, via: "cli", provenance: { note } });
43
+ }
44
+
45
+ /** Registers one file in public/ with its source, license and credit; code fills its facts. */
46
+ export async function addAsset({ venture, workspace, path, source, license, credit, alt, decorative, origin_url, design_system, actor = "agent" }) {
47
+ const dir = ventureDir(venture, workspace);
48
+ if (!dir) return { ok: false, error: `no venture ${venture}` };
49
+ if (!path?.startsWith("public/")) return { ok: false, error: `${path} is not in public/` };
50
+ if (!existsSync(join(dir, path))) return { ok: false, error: `${path} is not in ${venture}` };
51
+ const reg = registerOf(dir) ?? emptyRegister();
52
+ const entry = Object.fromEntries(Object.entries({ path, source, license, credit, alt: alt ? { text: alt, by: actor === "person" ? "person" : "agent" } : undefined, decorative: decorative || undefined, origin_url, design_system, facts: factsFor(dir, path) }).filter(([, v]) => v !== undefined));
53
+ reg.assets = [...reg.assets.filter((a) => a.path !== path), entry].sort((a, b) => a.path.localeCompare(b.path));
54
+ const w = await writeRegister(venture, workspace, reg, { actor, note: `registered ${path}; facts read by code` });
55
+ if (w.ok && alt && actor === "person") prov(dir, { entity: REGISTER, route: "public/assets", activity: "confirm", statement: altStatement(path, alt), agent: agentFromEnv("person", "cli"), note: `alt text of ${path} written by a person` });
56
+ return w.ok ? { ok: true, result: { registered: path, facts: entry.facts, alt: entry.alt ?? null } } : w;
57
+ }
58
+
59
+ /** Refills every entry's facts from its file. Only code writes facts. */
60
+ export async function fill({ venture, workspace }) {
61
+ const dir = ventureDir(venture, workspace);
62
+ if (!dir) return { ok: false, error: `no venture ${venture}` };
63
+ const reg = registerOf(dir);
64
+ if (!reg) return { ok: false, error: `${venture} has no ${REGISTER}; register a file first: mentura assets add public/<file> ...` };
65
+ const changed = [], missing = [];
66
+ for (const a of reg.assets) {
67
+ if (!existsSync(join(dir, a.path))) { missing.push(a.path); continue; }
68
+ const f = factsFor(dir, a.path);
69
+ if (!a.facts || ["type", "width", "height", "bytes", "sha256"].some((k) => (a.facts[k] ?? null) !== (f[k] ?? null))) { a.facts = f; changed.push(a.path); }
70
+ }
71
+ const listed = new Set(reg.assets.map((a) => a.path));
72
+ const unregistered = allFacts(dir).map((x) => x.path).filter((p) => !listed.has(p));
73
+ if (changed.length) { const w = await writeRegister(venture, workspace, reg, { note: `facts filled by code: ${changed.join(", ")}` }); if (!w.ok) return w; }
74
+ return { ok: true, result: { filled: changed, missing, unregistered } };
75
+ }
76
+
77
+ /** Writes alt text. An agent's carries agent provenance until a person confirms it; a person's is confirmed as written. */
78
+ export async function setAlt({ venture, workspace, path, text, actor = "agent" }) {
79
+ const dir = ventureDir(venture, workspace);
80
+ if (!dir) return { ok: false, error: `no venture ${venture}` };
81
+ const reg = registerOf(dir);
82
+ const a = reg?.assets.find((x) => x.path === path);
83
+ if (!a) return { ok: false, error: `${path} is not registered; mentura assets add ${path} first` };
84
+ a.alt = { text, by: actor === "person" ? "person" : "agent" };
85
+ const w = await writeRegister(venture, workspace, reg, { actor, note: `alt text of ${path} by ${a.alt.by}` });
86
+ if (!w.ok) return w;
87
+ if (actor === "person") prov(dir, { entity: REGISTER, route: "public/assets", activity: "confirm", statement: altStatement(path, text), agent: agentFromEnv("person", "cli"), note: `alt text of ${path} written by a person` });
88
+ return { ok: true, result: { path, alt: a.alt, confirmed: actor === "person" } };
89
+ }
90
+
91
+ /** A person confirms an alt text exactly as it stands. The confirmation is bound to the text: change it and it is pending again. */
92
+ export function confirmAlt({ venture, workspace, path, by }) {
93
+ const dir = ventureDir(venture, workspace);
94
+ if (!dir) return { ok: false, error: `no venture ${venture}` };
95
+ if (!by) return { ok: false, error: "say who is confirming: --by <name>" };
96
+ const a = registerOf(dir)?.assets.find((x) => x.path === path);
97
+ if (!a?.alt?.text) return { ok: false, error: `${path} has no alt text to confirm` };
98
+ const e = prov(dir, { entity: REGISTER, route: "public/assets", activity: "confirm", statement: altStatement(path, a.alt.text), agent: agentFromEnv("person", "cli", { id: by }), note: `${by} confirmed the alt text of ${path}: ${a.alt.text}` });
99
+ return { ok: true, result: { path, alt: a.alt.text, confirmed_by: by, provenance: e.hash } };
100
+ }
101
+
102
+ const rawId = (url) => {
103
+ const u = new URL(url);
104
+ const slug = `${u.host}-${u.pathname.split("/").filter(Boolean).pop() ?? "image"}`.toLowerCase().replace(/\.[a-z0-9]+$/, "").replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
105
+ return slug.slice(0, 60) || "remote-image";
106
+ };
107
+
108
+ /**
109
+ * A remote image as a link with a note in raw/ (J-3): raw/sources/<id>/source.json says where it is,
110
+ * text.md is the note, and the register lists it under remote. Nothing is fetched here. The platform
111
+ * fetcher passes `fetched` (facts of the private original) and `copy` when it kept a public copy.
112
+ */
113
+ export async function addRemote({ venture, workspace, url, license, credit, id, alt, note, fetched, copy, actor = "agent" }) {
114
+ const dir = ventureDir(venture, workspace);
115
+ if (!dir) return { ok: false, error: `no venture ${venture}` };
116
+ try { new URL(url); } catch { return { ok: false, error: `${url} is not a URL` }; }
117
+ const rid = id ?? rawId(url);
118
+ const reg = registerOf(dir) ?? emptyRegister();
119
+ if (!existsSync(join(dir, "raw/sources", rid, "source.json"))) {
120
+ const w = await call({ venture, route: `raw/sources/${rid}`, action: "write", input: { id: rid, origin: url, title: `Remote image at ${new URL(url).host}`, fetched: today().slice(0, 10) }, actor, workspace, via: "cli", provenance: { note: "a remote image, kept as a link (J-3)" } });
121
+ if (!w.ok) return w;
122
+ const text = [`# Remote image`, "", `- Link: ${url}`, `- Host: ${new URL(url).host}`, `- License: ${license}`, `- Credit: ${credit ?? "(missing)"}`, ...(fetched ? [`- Fetched: ${fetched.type}${fetched.width ? `, ${fetched.width}x${fetched.height}` : ""}, ${fetched.bytes} bytes, sha256 ${fetched.sha256}`] : []), "",
123
+ copy ? `A copy is kept at ${copy}: the license allows it.` : "The venture links to this image. A full copy stays private (raw/sources/<id>/original.*, out of git) unless the license allows one.", ...(note ? ["", note] : []), ""].join("\n");
124
+ writeFileSync(join(dir, "raw/sources", rid, "text.md"), text);
125
+ prov(dir, { entity: `raw/sources/${rid}/text.md`, route: `raw/sources/${rid}`, activity: "write", agent: agentFromEnv(actor === "person" ? "person" : "agent", "cli"), note: "the note beside a remote image (J-3)" });
126
+ }
127
+ const entry = Object.fromEntries(Object.entries({ id: rid, url, license, credit, alt: alt ? { text: alt, by: actor === "person" ? "person" : "agent" } : undefined, fetched, copy }).filter(([, v]) => v !== undefined));
128
+ reg.remote = [...(reg.remote ?? []).filter((r) => r.url !== url), entry];
129
+ const w = await writeRegister(venture, workspace, reg, { actor, note: `remote image ${url}` });
130
+ return w.ok ? { ok: true, result: { remote: url, raw: `raw/sources/${rid}/`, copy: copy ?? null } } : w;
131
+ }
132
+
133
+ /** The hosts an agent may fetch from, a setting the platform fetcher enforces (J-3). */
134
+ export async function setHosts({ venture, workspace, hosts, actor = "agent" }) {
135
+ const dir = ventureDir(venture, workspace);
136
+ if (!dir) return { ok: false, error: `no venture ${venture}` };
137
+ const reg = registerOf(dir) ?? emptyRegister();
138
+ reg.remote_hosts = hosts;
139
+ const w = await writeRegister(venture, workspace, reg, { actor, note: `hosts an agent may fetch from: ${hosts.join(", ") || "none"}` });
140
+ return w.ok ? { ok: true, result: { remote_hosts: hosts } } : w;
141
+ }
142
+
143
+ /** mentura brand ... and mentura assets ...: returns the exit code. */
144
+ export async function main(argv, { workspace } = {}) {
145
+ const opt = (n) => { const i = argv.indexOf(`--${n}`); return i >= 0 ? argv[i + 1] : undefined; };
146
+ const flag = (n) => argv.includes(`--${n}`);
147
+ const pos = argv.filter((a, i) => !a.startsWith("--") && !(i > 0 && argv[i - 1].startsWith("--") && !["json", "decorative"].includes(argv[i - 1].slice(2))));
148
+ const [group, verb, arg] = pos;
149
+ const venture = opt("venture");
150
+ const actor = opt("as") === "person" ? "person" : "agent";
151
+ const show = (r, text) => {
152
+ if (!r.ok) { console.error(r.error ?? JSON.stringify(r, null, 2)); return 1; }
153
+ console.log(flag("json") || text === undefined ? JSON.stringify(r.result, null, 2) : text);
154
+ return 0;
155
+ };
156
+ if (!venture) { console.error(`mentura ${group} ${verb ?? ""}: --venture <id> is required`); return 2; }
157
+ const dir = ventureDir(venture, workspace);
158
+ if (!dir) { console.error(`no venture ${venture}`); return 1; }
159
+
160
+ if (group === "assets") {
161
+ if (verb === "add") return show(await addAsset({ venture, workspace, path: arg, source: opt("source"), license: opt("license"), credit: opt("credit"), alt: opt("alt"), decorative: flag("decorative"), origin_url: opt("origin-url"), design_system: opt("design-system"), actor }), `registered: ${arg}`);
162
+ if (verb === "fill") { const r = await fill({ venture, workspace }); return show(r, r.ok ? `filled: ${r.result.filled.length ? r.result.filled.join(", ") : "nothing changed"}${r.result.unregistered.length ? `\nnot registered: ${r.result.unregistered.join(", ")}` : ""}` : undefined); }
163
+ if (verb === "alt") return show(await setAlt({ venture, workspace, path: arg, text: opt("text"), actor }), `alt text of ${arg} written by ${actor}${actor === "agent" ? "; a person confirms it with mentura assets confirm" : ""}`);
164
+ if (verb === "confirm") {
165
+ // The person types the path to confirm, as with foundation statements (EE-051).
166
+ if (opt("confirm") !== arg) { console.error(`not confirmed: pass --confirm ${arg} to confirm the alt text of ${arg} as it stands`); return 1; }
167
+ return show(confirmAlt({ venture, workspace, path: arg, by: opt("by") ?? process.env.MENTURA_PERSON }), `confirmed: alt text of ${arg}`);
168
+ }
169
+ if (verb === "remote") return show(await addRemote({ venture, workspace, url: arg, license: opt("license"), credit: opt("credit"), id: opt("id"), alt: opt("alt"), note: opt("note"), actor }), `linked: ${arg}`);
170
+ if (verb === "hosts") return show(await setHosts({ venture, workspace, hosts: (arg ?? "").split(",").map((h) => h.trim()).filter(Boolean), actor }), `remote_hosts: ${arg ?? "none"}`);
171
+ if (verb === "facts") return show({ ok: true, result: allFacts(dir) }, allFacts(dir).map((x) => `${x.path} ${x.type}${x.width ? ` ${x.width}x${x.height}` : ""} ${x.bytes} bytes`).join("\n") || "public/ is empty");
172
+ if (verb === "check") {
173
+ const r = checkAssets(dir);
174
+ if (flag("json")) console.log(JSON.stringify(r, null, 2));
175
+ else { for (const e of r.errors) console.log(`error ${e}`); for (const p of r.pending) console.log(`pending ${p.path}: alt text by ${p.by}, not confirmed by a person`); console.log(r.ok ? `assets: ${r.assets} files, ${r.remote} remote links, ${r.pending.length} alt texts pending` : `assets: ${r.errors.length} errors`); }
176
+ return r.ok ? 0 : 1;
177
+ }
178
+ }
179
+
180
+ if (group === "brand") {
181
+ const brand = brandOf(dir);
182
+ const need = () => { console.error(`${venture} has no brand yet: write marketing/brand.json (mentura marketing/brand template)`); return 1; };
183
+ if (verb === "tokens" || verb === "css" || verb === "head") {
184
+ if (!brand) return need();
185
+ const t = tokens(dir, brand);
186
+ return show({ ok: true, result: verb === "tokens" ? t.tokens : verb === "head" ? t.head : t.css }, verb === "css" ? t.css.trimEnd() : undefined);
187
+ }
188
+ if (verb === "resolve") { if (!brand) return need(); return show({ ok: true, result: resolveBrand(brand, arg ?? "") }); }
189
+ if (verb === "terms") { const t = termsFor(dir, arg); return show({ ok: true, result: t }, t.terms.map((x) => `${x.term} (${x.from}): ${x.meaning}`).join("\n") || `no terms reach ${arg}`); }
190
+ if (verb === "voice") {
191
+ const v = opt("text") !== undefined ? { violations: (await import("../schema/brand.mjs")).voiceCheck(opt("text"), brand ? resolveBrand(brand, opt("for") ?? "").voice.rules : []) } : voice(dir, brand);
192
+ const lines = v.violations.map((x) => `${x.file ? `${x.file}:` : "line "}${x.line} "${x.found}" breaks ${x.rule}${x.use ? `; use "${x.use}"` : ""}`);
193
+ if (flag("json")) console.log(JSON.stringify(v, null, 2)); else console.log(lines.join("\n") || "keeps to the voice rules");
194
+ return v.violations.length ? 1 : 0;
195
+ }
196
+ if (verb === "check") {
197
+ const r = checkBrand(dir);
198
+ if (flag("json")) console.log(JSON.stringify(r, null, 2));
199
+ else { for (const e of r.errors) console.log(`error ${e}`); for (const w of r.warnings) console.log(`warn ${w}`); console.log(r.ok ? "brand: ok" : `brand: ${r.errors.length} errors`); }
200
+ return r.ok ? 0 : 1;
201
+ }
202
+ if (verb === "sitemap") {
203
+ const s = sitemapOf(dir);
204
+ if (!s) { console.error(`${venture} has no marketing sitemap yet: mentura operations/marketing/sitemap run, then write it to marketing/sitemap`); return 1; }
205
+ let xml;
206
+ try { xml = sitemapXml(s.record, opt("base") ?? ""); } catch (e) { console.error(`${e.message}; pass --base https://<your site>`); return 1; }
207
+ if (opt("out")) { const f = resolvePath(opt("out")); mkdirSync(dirname(f), { recursive: true }); writeFileSync(f, xml); console.log(`wrote ${opt("out")}: ${s.record.pages.length} pages from ${s.file}`); return 0; }
208
+ process.stdout.write(xml);
209
+ return 0;
210
+ }
211
+ }
212
+ console.error(readFileSync(new URL(import.meta.url), "utf8").split("\n").filter((l) => l.startsWith("// mentura")).map((l) => l.slice(5)).join("\n"));
213
+ return 2;
214
+ }
@@ -0,0 +1,15 @@
1
+ // The venture a command runs on when none is named: the nearest venture.json in the current
2
+ // directory or its parents, the way next finds the project it runs in (I-2).
3
+
4
+ import { existsSync } from "node:fs";
5
+ import { basename, dirname, join, resolve } from "node:path";
6
+
7
+ export function findVenture(from = process.cwd()) {
8
+ for (let d = resolve(from); ; d = dirname(d)) {
9
+ if (existsSync(join(d, "venture.json"))) return d;
10
+ if (dirname(d) === d) return null;
11
+ }
12
+ }
13
+
14
+ /** The router's view of a venture directory: its workspace is the folder that holds it. */
15
+ export const asRouted = (dir) => ({ workspace: dirname(dir), venture: basename(dir) });
@@ -0,0 +1,59 @@
1
+ // The freshness commands of the mentura CLI (Revalidating, V-1 to V-8). mentura.mjs hands these
2
+ // commands here; the logic is schema/freshness.mjs.
3
+ //
4
+ // mentura revalidate <target> --venture <id> [--reason <text>] [--as person] [--json]
5
+ // target: tag:<route or file> (the record and what depends on it), path:<folder>,
6
+ // package:<name>, or a plain route or file (a tag); a plain folder is refused with the tags to use
7
+ // mentura revalidate --pivot --venture <id> [--reason <text>] every assumption in the validation package
8
+ // mentura verify <route|folder> --venture <id> [--reason <text>] [--as person]
9
+ // checked and still right, unchanged: its age starts again
10
+ // mentura phase <phase> --venture <id> --as person [--reason <text>]
11
+ // the venture changes phase; records with a per-phase profile go stale
12
+ // mentura freshness --venture <id> [--json] [--now <iso>] [--freeze <out dir>]
13
+ // what is fresh, stale, expired or a live hole; --freeze writes the static shell
14
+
15
+ import { resolve } from "node:path";
16
+ import { agentFromEnv } from "../provenance.mjs";
17
+ import { ventureDir } from "../router.mjs";
18
+ import { freeze, freshness, phase, revalidate, verify } from "../../schema/freshness.mjs";
19
+
20
+ export const COMMANDS = ["revalidate", "verify", "phase", "freshness"];
21
+
22
+ /** Runs one freshness command. Returns the exit code. */
23
+ export async function main(cmd, argv, workspace) {
24
+ const opt = (n) => { const i = argv.indexOf(`--${n}`); return i >= 0 ? argv[i + 1] : undefined; };
25
+ const flag = (n) => argv.includes(`--${n}`);
26
+ const target = argv[1] && !argv[1].startsWith("--") ? argv[1] : undefined;
27
+ const venture = opt("venture");
28
+ const dir = venture && ventureDir(venture, workspace);
29
+ const print = (x) => console.log(typeof x === "string" ? x : JSON.stringify(x, null, 2));
30
+ if (!dir) { console.error(venture ? `no venture ${venture}` : `usage: mentura ${cmd} ${cmd === "freshness" ? "" : "<target> "}--venture <id>`); return venture ? 1 : 2; }
31
+ const by = agentFromEnv(opt("as") === "person" ? "person" : "agent", "cli");
32
+ const now = opt("now");
33
+ let r;
34
+ if (cmd === "revalidate") {
35
+ if (!target && !flag("pivot")) { console.error("usage: mentura revalidate <tag:route|path:folder|package:name|route> --venture <id>, or --pivot"); return 2; }
36
+ r = await revalidate(dir, flag("pivot") ? "pivot" : target, { reason: opt("reason"), by, now });
37
+ } else if (cmd === "verify") {
38
+ if (!target) { console.error("usage: mentura verify <route|folder> --venture <id>"); return 2; }
39
+ r = verify(dir, target, { reason: opt("reason"), by, now });
40
+ } else if (cmd === "phase") {
41
+ if (!target) { console.error("usage: mentura phase <phase> --venture <id> --as person"); return 2; }
42
+ // A phase change is the founder's decision: an agent may suggest it, not make it.
43
+ if (opt("as") !== "person") { console.error(`a phase change is a person's: run mentura phase ${target} --venture ${venture} --as person`); return 1; }
44
+ r = phase(dir, target, { reason: opt("reason"), by, now });
45
+ } else if (cmd === "freshness") {
46
+ if (opt("freeze")) r = await freeze(dir, resolve(opt("freeze")), { now });
47
+ else { const f = await freshness(dir, { now }); print(flag("json") ? f : [`${f.venture} (${f.phase}): ${f.summary.fresh} fresh, ${f.summary.stale} stale, ${f.summary.expired} expired, ${f.summary.holes} live ${f.summary.holes === 1 ? "hole" : "holes"}, of ${f.summary.records} records.`,
48
+ ...f.items.filter((i) => i.state !== "fresh").map((i) => ` ${i.state.padEnd(7)} ${i.route}: ${i.reasons.map((x) => x.note).join("; ")}`),
49
+ ...f.copies.filter((c) => c.state !== "fresh").map((c) => ` ${c.state.padEnd(7)} ${c.path} (copy of ${c.parent}): ${c.note}`),
50
+ ...f.warnings.map((w) => `warning: ${w}`)].join("\n")); return 0; }
51
+ }
52
+ if (!r.ok) {
53
+ console.error(r.error);
54
+ if (r.suggest) console.error(` ${r.suggest.join("\n ")}\n or, for the whole folder: mentura revalidate ${r.or} --venture ${venture}`);
55
+ return 1;
56
+ }
57
+ print(flag("json") ? r.result : r.result.note ?? r.result);
58
+ return 0;
59
+ }
@@ -0,0 +1,6 @@
1
+ // The framework's global error for the command line (E-8, interface/boundaries.mjs). Imported first, so a
2
+ // broken data model or manifest answers with recovery steps before any module that reads it loads.
3
+ import { frameworkHealth, globalError } from "../boundaries.mjs";
4
+
5
+ const fw = frameworkHealth();
6
+ if (fw) { console.error(globalError(fw).error); process.exit(1); }