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.
- package/AGENTS.md +62 -0
- package/LICENSE +21 -0
- package/README.md +37 -2
- package/docs/decisions/decisions.json +888 -0
- package/docs/ontology.json +796 -0
- package/docs/ontology.md +163 -0
- package/docs/reference/ROUTES.md +124 -0
- package/evidence/benchmarks/2026-10-27-golden.jev.after-catalog-fix.json +558 -0
- package/evidence/benchmarks/2026-10-27-golden.jev.json +501 -0
- package/evidence/benchmarks/2026-10-27-golden.reasoning-answers.json +177 -0
- package/evidence/benchmarks/JEV_VS_REASONING_MODEL_2026-10-27.md +68 -0
- package/evidence/capabilities/agent-capabilities.json +86 -0
- package/evidence/design-documents.registry.json +2896 -0
- package/evidence/evals/evals.json +25 -0
- package/evidence/evals/harness-evals.json +140 -0
- package/evidence/layer.json +51 -0
- package/evidence/skills/agent-capabilities/SKILL.md +35 -0
- package/evidence/skills/design-coverage/SKILL.md +57 -0
- package/evidence/skills/design-coverage/check.mjs +192 -0
- package/evidence/skills/design-coverage/scan.mjs +45 -0
- package/evidence/skills/fidelity-ladder-audit/SKILL.md +121 -0
- package/evidence/skills/fidelity-ladder-audit/ladder-census.mjs +180 -0
- package/evidence/skills/findability/SKILL.md +32 -0
- package/evidence/skills/findability/inventory.rb +41 -0
- package/evidence/skills/foreshadowing-audit/SKILL.md +183 -0
- package/evidence/skills/metrics-review/SKILL.md +177 -0
- package/evidence/tooling/integrations.json +153 -0
- package/governance/layer.json +102 -0
- package/governance/references/references.json +26 -0
- package/governance/skills/board-design/SKILL.md +68 -0
- package/governance/skills/brand-pillar/SKILL.md +90 -0
- package/governance/skills/business-pillar/SKILL.md +96 -0
- package/governance/skills/chief-of-staff/SKILL.md +45 -0
- package/governance/skills/cofounder-structure/SKILL.md +64 -0
- package/governance/skills/cross-pillar-tradeoff/SKILL.md +168 -0
- package/governance/skills/equity-and-share-classes/SKILL.md +68 -0
- package/governance/skills/executive-roles/SKILL.md +95 -0
- package/governance/skills/exit-planning/SKILL.md +66 -0
- package/governance/skills/financing-and-investor-rights/SKILL.md +73 -0
- package/governance/skills/office-hours-mode/SKILL.md +113 -0
- package/governance/skills/product-pillar/SKILL.md +81 -0
- package/governance/skills/publication-policy/SKILL.md +63 -0
- package/governance/skills/role-and-candidate-authoring/SKILL.md +198 -0
- package/governance/skills/stakeholder-update/SKILL.md +177 -0
- package/governance/tooling/integrations.json +37 -0
- package/governance/venture-template/AGENT_ROLES_AND_DECISION_RIGHTS.md +58 -0
- package/governance/venture-template/COMPANY_VAULT_DEFINITION_2026-10-25.md +204 -0
- package/governance/venture-template/README.md +74 -0
- package/governance/venture-template/decision-rights.json +186 -0
- package/governance/venture-template/index.md +151 -0
- package/governance/venture-template/pillars/brand.md +209 -0
- package/governance/venture-template/pillars/business.md +255 -0
- package/governance/venture-template/pillars/product.md +254 -0
- package/governance/venture-template/render-roles.py +11 -0
- package/governance/venture-template/roles/README.md +85 -0
- package/governance/venture-template/roles/agent-roles.json +202 -0
- package/governance/venture-template/roles/ceo.md +163 -0
- package/governance/venture-template/roles/chief-of-staff.md +153 -0
- package/governance/venture-template/roles/cmo.md +165 -0
- package/governance/venture-template/roles/coo.md +189 -0
- package/governance/venture-template/roles/cto.md +158 -0
- package/governance/venture-template/roles/department-head.md +47 -0
- package/governance/venture-template/roles/forward-deployed-engineer.md +51 -0
- package/governance/venture-template/roles/founder.md +173 -0
- package/governance/venture-template/roles/hr-manager.md +49 -0
- package/governance/venture-template/roles/talent-acquisition-manager.md +50 -0
- package/governance/venture-template/roles/venture-roles.json +62 -0
- package/interface/acting.mjs +83 -0
- package/interface/adapters/claude-code.json +16 -0
- package/interface/adapters/codex.json +14 -0
- package/interface/adapters/cursor.json +16 -0
- package/interface/adapters.mjs +182 -0
- package/interface/api/server.mjs +71 -0
- package/interface/boundaries.mjs +218 -0
- package/interface/brand.mjs +214 -0
- package/interface/cli/find-venture.mjs +15 -0
- package/interface/cli/freshness.mjs +59 -0
- package/interface/cli/guard.mjs +6 -0
- package/interface/cli/mentura.mjs +341 -0
- package/interface/cli/naive.mjs +194 -0
- package/interface/context.mjs +524 -0
- package/interface/demo/board.mjs +581 -0
- package/interface/demo/decision-harness.mjs +91 -0
- package/interface/demo/live-agent.mjs +47 -0
- package/interface/dev/setup.mjs +84 -0
- package/interface/gate-hooks.mjs +36 -0
- package/interface/harness/evals.mjs +90 -0
- package/interface/harness/examples/pt-no-shows.dump.md +19 -0
- package/interface/harness/run.mjs +313 -0
- package/interface/harness/site.mjs +59 -0
- package/interface/instrumentation.mjs +86 -0
- package/interface/kit-boundary.mjs +73 -0
- package/interface/layer.json +37 -0
- package/interface/mcp/server.mjs +162 -0
- package/interface/operator-console/README.md +58 -0
- package/interface/package-routes.mjs +196 -0
- package/interface/provenance.mjs +65 -0
- package/interface/reads.mjs +173 -0
- package/interface/references/references.json +28 -0
- package/interface/release-card.mjs +42 -0
- package/interface/route-aliases.json +32 -0
- package/interface/router.mjs +653 -0
- package/interface/skills/install-mentura/SKILL.md +88 -0
- package/interface/skills/naive-setup/SKILL.md +71 -0
- package/interface/skills/naive-setup/artifact.html +83 -0
- package/interface/tooling/integrations.json +112 -0
- package/interface/vitals.mjs +115 -0
- package/interface/writes.mjs +190 -0
- package/knowledge/connectors/README.md +54 -0
- package/knowledge/connectors/catalog.mjs +118 -0
- package/knowledge/connectors/contract.mjs +56 -0
- package/knowledge/connectors/eval.mjs +176 -0
- package/knowledge/connectors/filesystem.mjs +79 -0
- package/knowledge/connectors/index.mjs +102 -0
- package/knowledge/connectors/resolve.mjs +44 -0
- package/knowledge/connectors/suite.mjs +80 -0
- package/knowledge/freshness.json +85 -0
- package/knowledge/layer.json +50 -0
- package/knowledge/skills/find-reference/SKILL.md +38 -0
- package/knowledge/skills/industry-awareness/SKILL.md +277 -0
- package/knowledge/templates/glossary.md +23 -0
- package/knowledge/tooling/integrations.json +127 -0
- package/knowledge/tooling/questions.md +46 -0
- package/operations/FOUNDER_OPERATING_MODEL_CAMPAIGN_2026-10-14.md +16 -0
- package/operations/departments.json +162 -0
- package/operations/handoff-v2.md +93 -0
- package/operations/layer.json +67 -0
- package/operations/marketing/check-public.mjs +68 -0
- package/operations/marketing/site/README.md +86 -0
- package/operations/marketing/site/matrix.json +731 -0
- package/operations/marketing/site/plan.mjs +117 -0
- package/operations/marketing/site/presence.mjs +252 -0
- package/operations/references/references.json +45 -0
- package/operations/skills/recruiting/SKILL.md +32 -0
- package/operations/skills/team-design/SKILL.md +36 -0
- package/operations/skills/tool-selection/SKILL.md +46 -0
- package/operations/templates/marketing-brand.md +46 -0
- package/operations/templates/public-assets.md +39 -0
- package/operations/templates/recruiting-brief.md +35 -0
- package/operations/tooling/integrations.json +158 -0
- package/package.json +59 -4
- package/packages/catalog.json +280 -0
- package/packages/cofounder/package.json +42 -0
- package/packages/counsel/package.json +47 -0
- package/packages/customers/package.json +41 -0
- package/packages/deals/package.json +27 -0
- package/packages/decisions/package.json +28 -0
- package/packages/engineering/package.json +41 -0
- package/packages/evidence/package.json +17 -0
- package/packages/finance/frames/fund-without-ceding-control.frame.json +177 -0
- package/packages/finance/package.json +48 -0
- package/packages/foundation/package.json +59 -0
- package/packages/fund/package.json +48 -0
- package/packages/investor/package.json +57 -0
- package/packages/investors/package.json +21 -0
- package/packages/legal/package.json +73 -0
- package/packages/marketing/package.json +63 -0
- package/packages/money/package.json +42 -0
- package/packages/operations/package.json +74 -0
- package/packages/partner/package.json +38 -0
- package/packages/people/package.json +64 -0
- package/packages/product/package.json +49 -0
- package/packages/raw/package.json +19 -0
- package/packages/relationships/package.json +52 -0
- package/packages/validation/package.json +112 -0
- package/platform/README.md +51 -0
- package/platform/adapter.json +15 -0
- package/platform/connectors/eval.mjs +154 -0
- package/platform/connectors/fake-github.mjs +91 -0
- package/platform/connectors/github.mjs +105 -0
- package/platform/integrations/jev.mjs +30 -0
- package/platform/integrations/langsmith-docket.mjs +53 -0
- package/platform/integrations/langsmith-setup.mjs +115 -0
- package/platform/integrations/langsmith.mjs +47 -0
- package/platform/integrations/remote-image.mjs +79 -0
- package/platform/integrations/rho.mjs +146 -0
- package/platform/integrations/site.mjs +75 -0
- package/platform/kits/README.md +14 -0
- package/platform/kits/agent-upgrade/kit.json +15 -0
- package/platform/kits/agent-upgrade/run.mjs +82 -0
- package/platform/kits/agent-upgrade/stand-in-agent.mjs +32 -0
- package/platform/kits/validation-kickoff/kit.json +29 -0
- package/platform/mcp/research.mjs +64 -0
- package/platform/webhooks/server.mjs +70 -0
- package/purpose/checklists/vault-and-tooling-consultancy-setup.md +216 -0
- package/purpose/frameworks/business-discovery-framework-amendments-2026-05-20.md +181 -0
- package/purpose/frameworks/business-discovery-framework.html +938 -0
- package/purpose/frameworks/business-discovery-framework.md +326 -0
- package/purpose/frameworks/idea-map/README.md +74 -0
- package/purpose/frameworks/idea-map/conventions.json +146 -0
- package/purpose/frameworks/idea-map/graph.mjs +182 -0
- package/purpose/frameworks/idea-map/ideamap.mjs +181 -0
- package/purpose/frameworks/idea-map/route.mjs +140 -0
- package/purpose/frameworks/onboarding-handoff-framework.md +269 -0
- package/purpose/frameworks/post-discovery-deliverable-playbook.md +274 -0
- package/purpose/frameworks/product-anatomy/README.md +63 -0
- package/purpose/frameworks/product-anatomy/anatomy.mjs +195 -0
- package/purpose/frameworks/product-anatomy/examples/polity.answers.reasoned.json +11 -0
- package/purpose/frameworks/product-anatomy/examples/polity.json +89 -0
- package/purpose/frameworks/product-anatomy/phases.json +107 -0
- package/purpose/frameworks/product-anatomy/questions.json +74 -0
- package/purpose/kits/validation/README.md +14 -0
- package/purpose/kits/validation/references/references.json +122 -0
- package/purpose/kits/validation/skills/problem-validation/SKILL.md +43 -0
- package/purpose/kits/validation/skills/validation-score/SKILL.md +35 -0
- package/purpose/kits/validation/templates/go-to-market.md +19 -0
- package/purpose/kits/validation/templates/operations-readiness.md +20 -0
- package/purpose/kits/validation/templates/pricing.md +22 -0
- package/purpose/kits/validation/templates/problem-interview.md +36 -0
- package/purpose/kits/validation/templates/problem.md +45 -0
- package/purpose/kits/validation/templates/product-market-fit.md +23 -0
- package/purpose/kits/validation/templates/solution.md +18 -0
- package/purpose/kits/validation/templates/team.md +19 -0
- package/purpose/kits/validation/weights.json +22 -0
- package/purpose/layer.json +53 -0
- package/purpose/references/references.json +324 -0
- package/purpose/skills/ambition-tier/SKILL.md +205 -0
- package/purpose/skills/telos/SKILL.md +52 -0
- package/purpose/strategic-foundation.json +133 -0
- package/purpose/templates/telos-based-smart.md +39 -0
- package/purpose/tooling/integrations.json +48 -0
- package/schema/README.md +62 -0
- package/schema/VERSION +1 -0
- package/schema/access.mjs +57 -0
- package/schema/account.schema.json +79 -0
- package/schema/adapter.schema.json +33 -0
- package/schema/add-department.mjs +41 -0
- package/schema/agent-capability.schema.json +94 -0
- package/schema/alignment.schema.json +61 -0
- package/schema/assess-problem.mjs +131 -0
- package/schema/assets.mjs +212 -0
- package/schema/bdd.mjs +56 -0
- package/schema/board.schema.json +101 -0
- package/schema/brand.mjs +373 -0
- package/schema/build-release.mjs +61 -0
- package/schema/caching.mjs +505 -0
- package/schema/check-assets.mjs +24 -0
- package/schema/check-boundary.mjs +54 -0
- package/schema/check-brand.mjs +24 -0
- package/schema/check-config.mjs +110 -0
- package/schema/check-data-model.mjs +170 -0
- package/schema/check-data-packages.mjs +83 -0
- package/schema/check-departments.mjs +45 -0
- package/schema/check-execution.mjs +85 -0
- package/schema/check-governance.mjs +98 -0
- package/schema/check-integrations.mjs +33 -0
- package/schema/check-nextjs-status.mjs +79 -0
- package/schema/check-nouns.mjs +49 -0
- package/schema/check-people.mjs +70 -0
- package/schema/check-private.mjs +61 -0
- package/schema/check-provenance.mjs +55 -0
- package/schema/check-publication.mjs +96 -0
- package/schema/check-ready.mjs +89 -0
- package/schema/check-sources.mjs +74 -0
- package/schema/check-team.mjs +94 -0
- package/schema/check-telos.mjs +59 -0
- package/schema/check-validation.mjs +165 -0
- package/schema/check-ventures.mjs +81 -0
- package/schema/check-where-used.mjs +58 -0
- package/schema/data-master.schema.json +14 -0
- package/schema/data-model.json +1584 -0
- package/schema/data-model.schema.json +152 -0
- package/schema/deal.schema.json +80 -0
- package/schema/decision-analytics.mjs +77 -0
- package/schema/decision-record.schema.json +290 -0
- package/schema/decision-rights.schema.json +34 -0
- package/schema/decision.schema.json +30 -0
- package/schema/decisions.mjs +327 -0
- package/schema/department-catalog.schema.json +55 -0
- package/schema/department.schema.json +15 -0
- package/schema/departments.mjs +32 -0
- package/schema/docket-eval.mjs +89 -0
- package/schema/docket.mjs +135 -0
- package/schema/eval-suite.schema.json +45 -0
- package/schema/evidence.schema.json +110 -0
- package/schema/examples/frames/judge.mjs +10 -0
- package/schema/examples/migrate/agent.mjs +12 -0
- package/schema/examples/venture-type/jev.mjs +12 -0
- package/schema/examples/workspace/ventures/acme-labs/AGENTS.md +17 -0
- package/schema/examples/workspace/ventures/acme-labs/accounts/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/acme-labs/decisions/discovery-goal.decision.json +23 -0
- package/schema/examples/workspace/ventures/acme-labs/decisions/statement-icp.decision.json +22 -0
- package/schema/examples/workspace/ventures/acme-labs/decisions/statement-problem.decision.json +22 -0
- package/schema/examples/workspace/ventures/acme-labs/decisions/venture.team.decision.json +37 -0
- package/schema/examples/workspace/ventures/acme-labs/knowledge/README.md +3 -0
- package/schema/examples/workspace/ventures/acme-labs/knowledge/sources.json +46 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000001.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000002.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000003.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000004.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000005.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000006.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000007.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000008.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000009.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000010.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000011.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000012.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000013.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/30000000-0000-4000-8000-000000000014.json +12 -0
- package/schema/examples/workspace/ventures/acme-labs/money/_streams/transactions/stream.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/money/_summary.json +30 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/customer-service/README.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/customer-service/department.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/finance/README.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/finance/department.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/human-capital/README.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/human-capital/department.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/it/README.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/it/department.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/marketing-and-sales/README.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/marketing-and-sales/department.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/products/README.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/products/department.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/strategy/README.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/operations/departments/strategy/department.json +5 -0
- package/schema/examples/workspace/ventures/acme-labs/people/founders/maya-chen.json +15 -0
- package/schema/examples/workspace/ventures/acme-labs/people/people.json +22 -0
- package/schema/examples/workspace/ventures/acme-labs/pillars/brand.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/pillars/business.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/pillars/product.md +5 -0
- package/schema/examples/workspace/ventures/acme-labs/products/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.core-product.decision.json +28 -0
- package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.exists.decision.json +38 -0
- package/schema/examples/workspace/ventures/acme-labs/products/decisions/product.flagship.decision.json +27 -0
- package/schema/examples/workspace/ventures/acme-labs/profile.md +12 -0
- package/schema/examples/workspace/ventures/acme-labs/provenance.jsonl +12 -0
- package/schema/examples/workspace/ventures/acme-labs/raw/dump.md +6 -0
- package/schema/examples/workspace/ventures/acme-labs/venture.json +27 -0
- package/schema/examples/workspace/ventures/northstar/AGENTS.md +17 -0
- package/schema/examples/workspace/ventures/northstar/accounts/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/northstar/deals/ductline.json +8 -0
- package/schema/examples/workspace/ventures/northstar/deals/kilnworks.json +14 -0
- package/schema/examples/workspace/ventures/northstar/decisions/venture.team.decision.json +31 -0
- package/schema/examples/workspace/ventures/northstar/evidence/README.md +3 -0
- package/schema/examples/workspace/ventures/northstar/fund/decisions/terms.decision.json +27 -0
- package/schema/examples/workspace/ventures/northstar/fund/decisions/terms.first-close.decision.json +27 -0
- package/schema/examples/workspace/ventures/northstar/fund/decisions/thesis.decision.json +26 -0
- package/schema/examples/workspace/ventures/northstar/fund/terms.json +22 -0
- package/schema/examples/workspace/ventures/northstar/fund/thesis.json +22 -0
- package/schema/examples/workspace/ventures/northstar/governance/README.md +3 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/external-relationships/charter.md +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/external-relationships/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/finance/charter.md +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/finance/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/human-capital/charter.md +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/human-capital/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/risk-and-compliance/charter.md +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/risk-and-compliance/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/strategy/charter.md +5 -0
- package/schema/examples/workspace/ventures/northstar/governance/departments/strategy/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/knowledge/README.md +3 -0
- package/schema/examples/workspace/ventures/northstar/operations/README.md +3 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/external-relationships/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/external-relationships/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/finance/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/finance/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/human-capital/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/human-capital/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/risk-and-compliance/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/risk-and-compliance/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/strategy/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/operations/departments/strategy/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/people/founders/ana-ruiz.json +13 -0
- package/schema/examples/workspace/ventures/northstar/people/founders/ben-okafor.json +7 -0
- package/schema/examples/workspace/ventures/northstar/people/people.json +27 -0
- package/schema/examples/workspace/ventures/northstar/pillars/brand.md +5 -0
- package/schema/examples/workspace/ventures/northstar/pillars/business.md +5 -0
- package/schema/examples/workspace/ventures/northstar/pillars/product.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/AGENTS.md +17 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/accounts/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/decisions/venture.team.decision.json +31 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/knowledge/README.md +3 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/customer-service/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/customer-service/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/finance/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/finance/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/human-capital/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/human-capital/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/it/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/it/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/marketing-and-sales/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/marketing-and-sales/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/products/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/products/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/strategy/README.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/operations/departments/strategy/department.json +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/brand.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/business.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/pillars/product.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.core-product.decision.json +28 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.exists.decision.json +32 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/products/decisions/product.flagship.decision.json +27 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/profile.md +5 -0
- package/schema/examples/workspace/ventures/northstar/portfolio/kilnworks/venture.json +27 -0
- package/schema/examples/workspace/ventures/northstar/products/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/northstar/profile.md +5 -0
- package/schema/examples/workspace/ventures/northstar/provenance.jsonl +3 -0
- package/schema/examples/workspace/ventures/northstar/purpose/README.md +3 -0
- package/schema/examples/workspace/ventures/northstar/venture.json +49 -0
- package/schema/examples/workspace/ventures/studio/accounts/bakery/account.json +18 -0
- package/schema/examples/workspace/ventures/studio/evidence/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/studio/governance/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/studio/knowledge/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/studio/operations/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/studio/print/knowledge/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/studio/print/purpose/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/studio/print/venture.json +37 -0
- package/schema/examples/workspace/ventures/studio/products/brand-care.json +19 -0
- package/schema/examples/workspace/ventures/studio/products/brand-kit.json +23 -0
- package/schema/examples/workspace/ventures/studio/provenance.jsonl +3 -0
- package/schema/examples/workspace/ventures/studio/purpose/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/studio/venture.json +43 -0
- package/schema/examples/workspace/ventures/tandem/accounts/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/tandem/evidence/README.md +3 -0
- package/schema/examples/workspace/ventures/tandem/governance/README.md +3 -0
- package/schema/examples/workspace/ventures/tandem/governance/agreements/dee-fast.md +3 -0
- package/schema/examples/workspace/ventures/tandem/governance/board.json +51 -0
- package/schema/examples/workspace/ventures/tandem/governance/departments/finance/charter.md +5 -0
- package/schema/examples/workspace/ventures/tandem/governance/departments/finance/department.json +5 -0
- package/schema/examples/workspace/ventures/tandem/governance/departments/primary/marketing-and-sales/charter.md +5 -0
- package/schema/examples/workspace/ventures/tandem/governance/departments/primary/marketing-and-sales/department.json +5 -0
- package/schema/examples/workspace/ventures/tandem/governance/exit.json +33 -0
- package/schema/examples/workspace/ventures/tandem/governance/founder-agreement.json +24 -0
- package/schema/examples/workspace/ventures/tandem/governance/founder-agreement.md +3 -0
- package/schema/examples/workspace/ventures/tandem/governance/ownership.json +131 -0
- package/schema/examples/workspace/ventures/tandem/governance/publication-policy.json +171 -0
- package/schema/examples/workspace/ventures/tandem/knowledge/README.md +3 -0
- package/schema/examples/workspace/ventures/tandem/knowledge/research/friends-feedback-2026-08.md +3 -0
- package/schema/examples/workspace/ventures/tandem/knowledge/research/pilot-2026-10.md +3 -0
- package/schema/examples/workspace/ventures/tandem/knowledge/research/problem-interviews-2026-09.md +20 -0
- package/schema/examples/workspace/ventures/tandem/knowledge/sources.json +8 -0
- package/schema/examples/workspace/ventures/tandem/knowledge/where-used.json +13 -0
- package/schema/examples/workspace/ventures/tandem/operations/README.md +3 -0
- package/schema/examples/workspace/ventures/tandem/operations/departments/finance/README.md +5 -0
- package/schema/examples/workspace/ventures/tandem/operations/departments/finance/department.json +5 -0
- package/schema/examples/workspace/ventures/tandem/operations/departments/primary/marketing-and-sales/README.md +5 -0
- package/schema/examples/workspace/ventures/tandem/operations/departments/primary/marketing-and-sales/department.json +5 -0
- package/schema/examples/workspace/ventures/tandem/pillars/brand.md +5 -0
- package/schema/examples/workspace/ventures/tandem/pillars/business.md +5 -0
- package/schema/examples/workspace/ventures/tandem/pillars/product.md +5 -0
- package/schema/examples/workspace/ventures/tandem/products/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/tandem/products/shop-app.json +22 -0
- package/schema/examples/workspace/ventures/tandem/profile.md +5 -0
- package/schema/examples/workspace/ventures/tandem/provenance.jsonl +13 -0
- package/schema/examples/workspace/ventures/tandem/purpose/README.md +3 -0
- package/schema/examples/workspace/ventures/tandem/purpose/telos.json +78 -0
- package/schema/examples/workspace/ventures/tandem/purpose/validation/go-to-market.json +35 -0
- package/schema/examples/workspace/ventures/tandem/purpose/validation/pricing.json +37 -0
- package/schema/examples/workspace/ventures/tandem/purpose/validation/problem.json +74 -0
- package/schema/examples/workspace/ventures/tandem/purpose/validation/product-market-fit.json +66 -0
- package/schema/examples/workspace/ventures/tandem/purpose/validation/solution.json +33 -0
- package/schema/examples/workspace/ventures/tandem/purpose/validation/team.json +52 -0
- package/schema/examples/workspace/ventures/tandem/venture.json +79 -0
- package/schema/examples/workspace/ventures/woodworking/knowledge/.gitkeep +0 -0
- package/schema/examples/workspace/ventures/woodworking/venture.json +21 -0
- package/schema/examples/workspace/workspace.json +8 -0
- package/schema/exit.schema.json +74 -0
- package/schema/foundation.mjs +118 -0
- package/schema/founder-agreement.schema.json +83 -0
- package/schema/founder.schema.json +72 -0
- package/schema/frame.schema.json +240 -0
- package/schema/frames.mjs +228 -0
- package/schema/freshness-log.schema.json +40 -0
- package/schema/freshness-profiles.schema.json +44 -0
- package/schema/freshness.mjs +473 -0
- package/schema/fund-terms.schema.json +107 -0
- package/schema/fund-thesis.schema.json +87 -0
- package/schema/gate-drafts.mjs +130 -0
- package/schema/gate.mjs +133 -0
- package/schema/glossary.schema.json +25 -0
- package/schema/handoff.schema.json +239 -0
- package/schema/icp.schema.json +136 -0
- package/schema/idea-graph.schema.json +61 -0
- package/schema/init-venture.mjs +128 -0
- package/schema/integration.schema.json +143 -0
- package/schema/judgment.schema.json +38 -0
- package/schema/kit.schema.json +47 -0
- package/schema/kits.mjs +24 -0
- package/schema/knowledge-sources.schema.json +260 -0
- package/schema/layer.json +59 -0
- package/schema/layer.schema.json +119 -0
- package/schema/load-packages.mjs +26 -0
- package/schema/marketing-brand.schema.json +116 -0
- package/schema/marketing-sitemap.schema.json +232 -0
- package/schema/migrate-venture.mjs +192 -0
- package/schema/migrations/kit-to-package.mjs +94 -0
- package/schema/migrations/package-layout.mjs +86 -0
- package/schema/model-steps.mjs +717 -0
- package/schema/money-summary.schema.json +138 -0
- package/schema/naive-config.mjs +165 -0
- package/schema/naive-config.schema.json +268 -0
- package/schema/need-now.json +772 -0
- package/schema/need-now.mjs +108 -0
- package/schema/nextjs-status.schema.json +29 -0
- package/schema/ownership.schema.json +282 -0
- package/schema/packages.json +4 -0
- package/schema/packages.mjs +252 -0
- package/schema/payouts.mjs +91 -0
- package/schema/people.schema.json +86 -0
- package/schema/port-venture.mjs +161 -0
- package/schema/product.schema.json +223 -0
- package/schema/provenance-entry.schema.json +154 -0
- package/schema/public-assets.schema.json +76 -0
- package/schema/publication-policy.schema.json +293 -0
- package/schema/raw-source.schema.json +15 -0
- package/schema/reference.schema.json +115 -0
- package/schema/release-read.mjs +111 -0
- package/schema/releases.mjs +497 -0
- package/schema/route-aliases.schema.json +25 -0
- package/schema/run-handoff.mjs +51 -0
- package/schema/scaffold/defaults.json +54 -0
- package/schema/setup.mjs +164 -0
- package/schema/site-presence.schema.json +337 -0
- package/schema/stale.mjs +111 -0
- package/schema/start-release.mjs +41 -0
- package/schema/strategic-foundation.schema.json +74 -0
- package/schema/stream.schema.json +14 -0
- package/schema/structure.mjs +186 -0
- package/schema/systems-catalog.json +126 -0
- package/schema/systems-catalog.schema.json +78 -0
- package/schema/team-plan.schema.json +157 -0
- package/schema/telos.schema.json +197 -0
- package/schema/time-to-ready.mjs +93 -0
- package/schema/trigger.schema.json +44 -0
- package/schema/triggers.mjs +237 -0
- package/schema/upgrade-registry.schema.json +60 -0
- package/schema/upgrade-venture.mjs +107 -0
- package/schema/upgrades.json +69 -0
- package/schema/upgrades.mjs +385 -0
- package/schema/use-model.mjs +10 -0
- package/schema/validate.py +58 -0
- package/schema/validation-evidence.schema.json +123 -0
- package/schema/validation-go-to-market.schema.json +110 -0
- package/schema/validation-operations-readiness.schema.json +91 -0
- package/schema/validation-pricing.schema.json +114 -0
- package/schema/validation-problem.schema.json +118 -0
- package/schema/validation-product-market-fit.schema.json +135 -0
- package/schema/validation-solution.schema.json +79 -0
- package/schema/validation-team.schema.json +116 -0
- package/schema/venture-role.schema.json +64 -0
- package/schema/venture-type.mjs +62 -0
- package/schema/venture-types.json +346 -0
- package/schema/venture-types.schema.json +129 -0
- package/schema/venture.schema.json +460 -0
- package/schema/vocab/business-models.json +298 -0
- package/schema/where-used.schema.json +56 -0
- package/schema/workspace.schema.json +38 -0
package/schema/brand.mjs
ADDED
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// The venture's brand (Next.js CSS, Fonts and file-based metadata, translated): brand tokens in the
|
|
3
|
+
// marketing package, read by every view and every agent. Styling itself stays with the interface;
|
|
4
|
+
// what converts is the brand.
|
|
5
|
+
//
|
|
6
|
+
// Y-3 brand tokens (colors, typefaces, voice rules) live in marketing/brand.json, the global
|
|
7
|
+
// stylesheet. Voice rules are the global stylesheet for words: every agent's layout carries
|
|
8
|
+
// them, and the voice check holds marketing content to them
|
|
9
|
+
// Y-5 nearer context wins. brand.json scopes override the venture brand for a route prefix,
|
|
10
|
+
// T-2 a package's scope under an item's; a typeface is defined once and assigned to a role at
|
|
11
|
+
// the root (everywhere) or in a scope (only there), like next/font
|
|
12
|
+
// T-1 typefaces are brand tokens recorded with their license, self-hosted from public/ so a
|
|
13
|
+
// browser makes no outside request
|
|
14
|
+
// Y-4 an outside design system is a reference: linked, with its version and license, not copied
|
|
15
|
+
// Y-2 a package's own terms stay local: glossary/<package>.json terms reach other packages
|
|
16
|
+
// only when the glossary exports them
|
|
17
|
+
// P-24 the venture's logo and marks (logo, icon, apple-icon, favicon) are brand marks pointing at
|
|
18
|
+
// registered assets in public/, checked for type and size
|
|
19
|
+
// P-26 the sitemap is a marketing record (marketing/sitemap.json); sitemap.xml is rendered from
|
|
20
|
+
// it for a release, never from the framework's routes
|
|
21
|
+
//
|
|
22
|
+
// No model is called and nothing here reaches the network.
|
|
23
|
+
//
|
|
24
|
+
// node schema/brand.mjs <venture dir> tokens [--json] DTCG tokens, CSS and head links for the venture
|
|
25
|
+
// node schema/brand.mjs <venture dir> --for <route> [--json] the brand resolved at a route (nearer wins)
|
|
26
|
+
// node schema/brand.mjs <venture dir> voice [--json] marketing content against the voice rules
|
|
27
|
+
// node schema/brand.mjs <venture dir> --package <id> [--json] the terms a package sees (its own and exported ones)
|
|
28
|
+
// node schema/brand.mjs <venture dir> --base <url> [--json] sitemap.xml from the marketing sitemap
|
|
29
|
+
// node schema/brand.mjs <venture dir> check [--json] the brand check (also schema/check-brand.mjs)
|
|
30
|
+
|
|
31
|
+
import { existsSync, readdirSync, readFileSync } from "node:fs";
|
|
32
|
+
import { join } from "node:path";
|
|
33
|
+
import { allowsCopy, factsOf, registerOf, REGISTER } from "./assets.mjs";
|
|
34
|
+
|
|
35
|
+
export const BRAND = "marketing/brand.json";
|
|
36
|
+
export const SITEMAPS = ["marketing/sitemap.json", "operations/marketing/sitemap.json"];
|
|
37
|
+
const load = (p) => JSON.parse(readFileSync(p, "utf8"));
|
|
38
|
+
export const brandOf = (dir) => dir && existsSync(join(dir, BRAND)) ? load(join(dir, BRAND)) : null;
|
|
39
|
+
|
|
40
|
+
// ---------------------------------------------------------------------------------------------
|
|
41
|
+
// Router hooks. interface/router.mjs spreads these into its tables; this module never imports the router.
|
|
42
|
+
|
|
43
|
+
/** Where the new record types route (package folder layout, EE-070). */
|
|
44
|
+
export const BRAND_ROUTES = { "marketing-brand": "marketing/brand", "public-assets": "public/assets", glossary: "glossary" };
|
|
45
|
+
|
|
46
|
+
/** The command routes this module adds, built with the router's own cmd(). */
|
|
47
|
+
export const brandCommands = (cmd) => [
|
|
48
|
+
cmd("marketing/brand/tokens", "schema/brand.mjs", "The venture's brand tokens (Y-3): colors and typefaces as W3C design tokens, the CSS custom properties and @font-face rules an interface loads, each scope as its own selector, and the head links for the venture's marks (P-24)", { args: ["tokens"] }),
|
|
49
|
+
cmd("marketing/brand/resolve", "schema/brand.mjs", "The brand at one route (Y-5, T-2): the venture brand with every scope that covers the route applied, nearer last, and which scope set each value; input value is the route", { value_flag: "--for" }),
|
|
50
|
+
cmd("marketing/voice", "schema/brand.mjs", "Marketing content held to the voice rules, the global stylesheet for words (Y-3): each phrase to avoid, where it is and what to use instead; and terms another package keeps local (Y-2)", { args: ["voice"] }),
|
|
51
|
+
cmd("glossary/terms", "schema/brand.mjs", "The terms one package sees (Y-2): its own glossary and the terms other packages export; their local terms stay with them. Input value is the package", { value_flag: "--package" }),
|
|
52
|
+
cmd("marketing/sitemap/xml", "schema/brand.mjs", "sitemap.xml rendered from the marketing sitemap record (P-26), for a release; input value is the site's base URL", { value_flag: "--base" }),
|
|
53
|
+
cmd("public/assets/facts", "schema/assets.mjs", "What code reads from each file in public/ (J-4): type from the bytes, width and height, icon sizes, bytes and sha256. Agents copy these, never guess them", { args: ["facts"] }),
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
/** What a layout adds for an agent: the brand and voice at this route, and the terms its package sees. */
|
|
57
|
+
export function brandLayout(dir, route) {
|
|
58
|
+
if (!dir) return null;
|
|
59
|
+
const brand = brandOf(dir);
|
|
60
|
+
const pkg = route.split("/")[0];
|
|
61
|
+
const terms = glossaries(dir).size ? termsFor(dir, pkg) : null;
|
|
62
|
+
if (!brand && !terms) return null;
|
|
63
|
+
const at = brand ? resolveBrand(brand, route) : null;
|
|
64
|
+
return {
|
|
65
|
+
...(at ? { name: at.name, tone: at.voice.tone, voice: at.voice.rules.map((r) => ({ id: r.id, avoid: r.avoid, use: r.use ?? null, why: r.why ?? null })), fonts: Object.fromEntries(Object.entries(at.fonts).map(([role, t]) => [role, t.family])), colors: at.colors, scopes: at.scopes } : {}),
|
|
66
|
+
...(terms ? { terms: terms.terms.map((t) => ({ term: t.term, meaning: t.meaning, from: t.from })) } : {}),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ---------------------------------------------------------------------------------------------
|
|
71
|
+
// Resolution: nearer context wins (Y-5, T-2).
|
|
72
|
+
|
|
73
|
+
const covers = (scope, route) => route === scope || route.startsWith(`${scope}/`);
|
|
74
|
+
const depth = (s) => s.split("/").filter(Boolean).length;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The brand at a route: the venture's colors, font roles and voice rules, then each scope whose
|
|
78
|
+
* `for` covers the route, shallowest first, so the nearest scope wins. set_by says which scope set
|
|
79
|
+
* each value (the venture brand is "venture").
|
|
80
|
+
*/
|
|
81
|
+
export function resolveBrand(brand, route = "") {
|
|
82
|
+
const faces = new Map((brand.typefaces ?? []).map((t) => [t.id, t]));
|
|
83
|
+
const colors = { ...(brand.colors ?? {}) };
|
|
84
|
+
const roles = { ...(brand.fonts ?? {}) };
|
|
85
|
+
const rules = new Map((brand.voice?.rules ?? []).map((r) => [r.id, r]));
|
|
86
|
+
let tone = brand.voice?.tone ?? [];
|
|
87
|
+
const set_by = {};
|
|
88
|
+
for (const k of Object.keys(colors)) set_by[`color.${k}`] = "venture";
|
|
89
|
+
for (const k of Object.keys(roles)) set_by[`font.${k}`] = "venture";
|
|
90
|
+
for (const k of rules.keys()) set_by[`voice.${k}`] = "venture";
|
|
91
|
+
const scopes = (brand.scopes ?? []).filter((s) => covers(s.for, route)).sort((a, b) => depth(a.for) - depth(b.for));
|
|
92
|
+
for (const s of scopes) {
|
|
93
|
+
for (const [k, v] of Object.entries(s.colors ?? {})) { colors[k] = v; set_by[`color.${k}`] = s.for; }
|
|
94
|
+
for (const [k, v] of Object.entries(s.fonts ?? {})) { roles[k] = v; set_by[`font.${k}`] = s.for; }
|
|
95
|
+
for (const r of s.voice?.rules ?? []) { rules.set(r.id, r); set_by[`voice.${r.id}`] = s.for; }
|
|
96
|
+
if (s.voice?.tone) tone = s.voice.tone;
|
|
97
|
+
}
|
|
98
|
+
const fonts = Object.fromEntries(Object.entries(roles).filter(([, id]) => faces.has(id)).map(([role, id]) => [role, faces.get(id)]));
|
|
99
|
+
return { route, name: brand.name ?? null, colors, fonts, voice: { tone, rules: [...rules.values()] }, scopes: scopes.map((s) => s.for), set_by };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ---------------------------------------------------------------------------------------------
|
|
103
|
+
// Tokens: W3C design tokens (DTCG), CSS custom properties and head links.
|
|
104
|
+
|
|
105
|
+
const cssName = (s) => String(s).toLowerCase().replace(/[^a-z0-9-]+/g, "-");
|
|
106
|
+
const familyList = (t) => [JSON.stringify(t.family), ...(t.fallback ?? [])].join(", ");
|
|
107
|
+
const FORMAT = { woff2: "woff2", woff: "woff", ttf: "truetype", otf: "opentype" };
|
|
108
|
+
const url = (path) => `/${path.replace(/^public\//, "")}`;
|
|
109
|
+
|
|
110
|
+
/** The marks as head links: the file-based icons Next.js turns into <link> tags. */
|
|
111
|
+
export function headLinks(dir, brand) {
|
|
112
|
+
const reg = registerOf(dir);
|
|
113
|
+
const factsFor = (p) => reg?.assets?.find((a) => a.path === p)?.facts ?? (existsSync(join(dir, p)) ? factsOf(readFileSync(join(dir, p))) : null);
|
|
114
|
+
const out = [];
|
|
115
|
+
for (const m of brand.marks ?? []) {
|
|
116
|
+
if (m.kind === "logo") continue;
|
|
117
|
+
const f = factsFor(m.asset);
|
|
118
|
+
const sizes = m.kind === "favicon" ? "any" : f?.width ? `${f.width}x${f.height}` : undefined;
|
|
119
|
+
const type = { png: "image/png", svg: "image/svg+xml", ico: "image/x-icon" }[f?.type];
|
|
120
|
+
out.push(Object.fromEntries(Object.entries({ rel: m.kind === "apple-icon" ? "apple-touch-icon" : "icon", href: url(m.asset), type, sizes }).filter(([, v]) => v)));
|
|
121
|
+
}
|
|
122
|
+
return out;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** DTCG tokens, CSS (custom properties, @font-face, one selector per scope) and head links. */
|
|
126
|
+
export function tokens(dir, brand = brandOf(dir)) {
|
|
127
|
+
if (!brand) return null;
|
|
128
|
+
const at = resolveBrand(brand, "");
|
|
129
|
+
const dtcg = { color: {}, font: {} };
|
|
130
|
+
for (const [k, v] of Object.entries(at.colors)) dtcg.color[k] = { $type: "color", $value: v };
|
|
131
|
+
for (const [role, t] of Object.entries(at.fonts)) dtcg.font[role] = { $type: "fontFamily", $value: [t.family, ...(t.fallback ?? [])], $description: `${t.family}, ${t.license}` };
|
|
132
|
+
const faces = (brand.typefaces ?? []).filter((t) => t.source === "self-hosted").flatMap((t) => (t.files ?? []).map((f) => {
|
|
133
|
+
const ext = f.split(".").pop().toLowerCase();
|
|
134
|
+
return `@font-face {\n font-family: ${JSON.stringify(t.family)};\n src: url("${url(f)}") format("${FORMAT[ext] ?? ext}");\n font-display: swap;\n}`;
|
|
135
|
+
}));
|
|
136
|
+
const decl = (colors, fonts) => [...Object.entries(colors).map(([k, v]) => ` --color-${cssName(k)}: ${v};`), ...Object.entries(fonts).map(([role, t]) => ` --font-${cssName(role)}: ${familyList(t)};`)].join("\n");
|
|
137
|
+
const blocks = [...faces, `:root {\n${decl(at.colors, at.fonts)}\n}`];
|
|
138
|
+
const faceById = new Map((brand.typefaces ?? []).map((t) => [t.id, t]));
|
|
139
|
+
for (const s of [...(brand.scopes ?? [])].sort((a, b) => depth(a.for) - depth(b.for))) {
|
|
140
|
+
const f = Object.fromEntries(Object.entries(s.fonts ?? {}).filter(([, id]) => faceById.has(id)).map(([role, id]) => [role, faceById.get(id)]));
|
|
141
|
+
const d = decl(s.colors ?? {}, f);
|
|
142
|
+
if (d) blocks.push(`[data-naive-scope="${s.for}"] {\n${d}\n}`);
|
|
143
|
+
}
|
|
144
|
+
return { name: brand.name ?? null, tokens: dtcg, css: blocks.join("\n\n") + "\n", head: headLinks(dir, brand), voice: brand.voice ?? null, design_systems: brand.design_systems ?? [] };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ---------------------------------------------------------------------------------------------
|
|
148
|
+
// Glossaries (Y-2): a package's terms stay local unless it exports them.
|
|
149
|
+
|
|
150
|
+
/** Every package glossary in the venture (glossary/<package>.json): package -> record. */
|
|
151
|
+
export function glossaries(dir) {
|
|
152
|
+
const out = new Map();
|
|
153
|
+
const g = dir ? join(dir, "glossary") : null;
|
|
154
|
+
if (!g || !existsSync(g)) return out;
|
|
155
|
+
for (const f of readdirSync(g).filter((n) => n.endsWith(".json")).sort()) out.set(f.slice(0, -5), load(join(g, f)));
|
|
156
|
+
return out;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** The terms a package sees: its own (all of them), then other packages' exported ones. Its own win. */
|
|
160
|
+
export function termsFor(dir, pkg) {
|
|
161
|
+
const all = glossaries(dir);
|
|
162
|
+
const own = (all.get(pkg)?.terms ?? []).map((t) => ({ ...t, from: pkg }));
|
|
163
|
+
const names = new Set(own.map((t) => t.term.toLowerCase()));
|
|
164
|
+
const imported = [], shadows = [];
|
|
165
|
+
let hidden = 0;
|
|
166
|
+
for (const [p, g] of all) {
|
|
167
|
+
if (p === pkg) continue;
|
|
168
|
+
for (const t of g.terms ?? []) {
|
|
169
|
+
if (!t.export) { hidden++; continue; }
|
|
170
|
+
if (names.has(t.term.toLowerCase())) { shadows.push({ term: t.term, from: p, kept: pkg }); continue; }
|
|
171
|
+
imported.push({ ...t, from: p });
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return { package: pkg, terms: [...own, ...imported], shadows, hidden };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function checkGlossaries(dir) {
|
|
178
|
+
const errors = [], warnings = [];
|
|
179
|
+
const exported = new Map();
|
|
180
|
+
for (const [p, g] of glossaries(dir)) {
|
|
181
|
+
if (g.package !== p) errors.push(`glossary/${p}.json: names package ${g.package}; the file for ${g.package} is glossary/${g.package}.json (Y-2)`);
|
|
182
|
+
const seen = new Set();
|
|
183
|
+
for (const t of g.terms ?? []) {
|
|
184
|
+
const k = t.term.toLowerCase();
|
|
185
|
+
if (seen.has(k)) errors.push(`glossary/${p}.json: ${t.term} is defined twice`);
|
|
186
|
+
seen.add(k);
|
|
187
|
+
if (!t.export) continue;
|
|
188
|
+
const prior = exported.get(k);
|
|
189
|
+
if (prior && prior.meaning !== t.meaning) errors.push(`${t.term}: exported by ${prior.from} and ${p} with different meanings; one of them keeps it local or they agree (Y-2)`);
|
|
190
|
+
else exported.set(k, { ...t, from: p });
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return { errors, warnings };
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ---------------------------------------------------------------------------------------------
|
|
197
|
+
// Voice (Y-3): the global stylesheet for words.
|
|
198
|
+
|
|
199
|
+
const escape = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
200
|
+
const phrase = (p) => new RegExp(`(^|[^\\p{L}\\p{N}])(${escape(p)})(?=$|[^\\p{L}\\p{N}])`, "giu");
|
|
201
|
+
|
|
202
|
+
/** Text held to voice rules: every phrase to avoid, by line, with what to use instead. Frontmatter and code are skipped. */
|
|
203
|
+
export function voiceCheck(text, rules) {
|
|
204
|
+
const out = [];
|
|
205
|
+
let fence = false, front = false;
|
|
206
|
+
text.split("\n").forEach((line, i) => {
|
|
207
|
+
if (i === 0 && line.trim() === "---") { front = true; return; }
|
|
208
|
+
if (front) { if (line.trim() === "---") front = false; return; }
|
|
209
|
+
if (/^\s*(```|~~~)/.test(line)) { fence = !fence; return; }
|
|
210
|
+
if (fence) return;
|
|
211
|
+
const plain = line.replace(/`[^`]*`/g, "");
|
|
212
|
+
for (const r of rules) for (const a of [].concat(r.avoid ?? [])) for (const m of plain.matchAll(phrase(a))) out.push({ rule: r.id, line: i + 1, found: m[2], use: r.use ?? null, why: r.why ?? null });
|
|
213
|
+
});
|
|
214
|
+
return out;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** The venture's marketing content files, venture-relative. */
|
|
218
|
+
export function contentFiles(dir) {
|
|
219
|
+
const walk = (d) => existsSync(d) ? readdirSync(d, { withFileTypes: true }).flatMap((e) => e.isDirectory() ? walk(join(d, e.name)) : /\.(mdx?|txt)$/.test(e.name) ? [join(d, e.name)] : []) : [];
|
|
220
|
+
return ["marketing/content", "operations/marketing/content"].flatMap((p) => walk(join(dir, p))).map((f) => f.slice(dir.length + 1)).sort();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/** Every marketing content file held to the voice rules in force at its path, and to other packages' local terms (warnings). */
|
|
224
|
+
export function voice(dir, brand = brandOf(dir)) {
|
|
225
|
+
const violations = [], leaks = [];
|
|
226
|
+
const local = [...glossaries(dir)].filter(([p]) => p !== "marketing").flatMap(([p, g]) => (g.terms ?? []).filter((t) => !t.export).map((t) => ({ ...t, from: p })));
|
|
227
|
+
for (const f of contentFiles(dir)) {
|
|
228
|
+
const text = readFileSync(join(dir, f), "utf8");
|
|
229
|
+
const route = f.replace(/^operations\//, "").replace(/\.(mdx?|txt)$/, "");
|
|
230
|
+
if (brand) for (const v of voiceCheck(text, resolveBrand(brand, route).voice.rules)) violations.push({ file: f, ...v });
|
|
231
|
+
for (const t of local) for (const v of voiceCheck(text, [{ id: t.term, avoid: t.term }])) leaks.push({ file: f, line: v.line, term: t.term, local_to: t.from });
|
|
232
|
+
}
|
|
233
|
+
return { ok: !violations.length, files: contentFiles(dir).length, violations, local_terms: leaks };
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ---------------------------------------------------------------------------------------------
|
|
237
|
+
// The brand check.
|
|
238
|
+
|
|
239
|
+
const HEX = /^#([0-9a-f]{3}|[0-9a-f]{4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;
|
|
240
|
+
|
|
241
|
+
export function checkBrand(dir) {
|
|
242
|
+
const errors = [], warnings = [];
|
|
243
|
+
const brand = brandOf(dir);
|
|
244
|
+
const g = checkGlossaries(dir);
|
|
245
|
+
errors.push(...g.errors); warnings.push(...g.warnings);
|
|
246
|
+
if (!brand) return { ok: !errors.length, errors, warnings, brand: false };
|
|
247
|
+
const reg = registerOf(dir);
|
|
248
|
+
const asset = (p) => reg?.assets?.find((a) => a.path === p);
|
|
249
|
+
const faces = new Map((brand.typefaces ?? []).map((t) => [t.id, t]));
|
|
250
|
+
// Colors (Y-3).
|
|
251
|
+
const colorsOk = (cs, where) => { for (const [k, v] of Object.entries(cs ?? {})) if (!HEX.test(v)) errors.push(`${where}: color ${k} is ${v}, not a hex color`); };
|
|
252
|
+
colorsOk(brand.colors, BRAND);
|
|
253
|
+
// Typefaces (T-1): licensed, self-hosted from registered files, never fetched from another host by the browser.
|
|
254
|
+
for (const t of brand.typefaces ?? []) {
|
|
255
|
+
if (t.source !== "system" && !String(t.license ?? "").trim()) errors.push(`typeface ${t.id}: no license (T-1)`);
|
|
256
|
+
if (t.source === "remote") errors.push(`typeface ${t.id}: served from ${t.url ?? "another host"}, so every reader's browser makes an outside request; self-host its files in public/ (T-1)`);
|
|
257
|
+
if (t.source === "self-hosted") {
|
|
258
|
+
if (!(t.files ?? []).length) errors.push(`typeface ${t.id}: self-hosted but names no files in public/ (T-1)`);
|
|
259
|
+
for (const f of t.files ?? []) {
|
|
260
|
+
if (!f.startsWith("public/")) { errors.push(`typeface ${t.id}: ${f} is not in public/ (T-1)`); continue; }
|
|
261
|
+
if (!existsSync(join(dir, f))) { errors.push(`typeface ${t.id}: ${f} is not there (T-1)`); continue; }
|
|
262
|
+
const a = asset(f);
|
|
263
|
+
if (!a) errors.push(`typeface ${t.id}: ${f} has no entry in ${REGISTER} (T-1, J-2)`);
|
|
264
|
+
else if (String(a.license).toLowerCase() !== String(t.license).toLowerCase()) errors.push(`typeface ${t.id}: licensed ${t.license}, but ${REGISTER} says ${f} is ${a.license} (T-1)`);
|
|
265
|
+
const type = factsOf(readFileSync(join(dir, f))).type;
|
|
266
|
+
if (!["woff2", "woff", "ttf", "otf"].includes(type)) errors.push(`typeface ${t.id}: ${f} is ${type}, not a font file (T-1)`);
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
// Font roles, at the root and in scopes (T-2).
|
|
271
|
+
for (const [role, id] of Object.entries(brand.fonts ?? {})) if (!faces.has(id)) errors.push(`fonts.${role}: no typeface ${id} (T-2)`);
|
|
272
|
+
for (const s of brand.scopes ?? []) {
|
|
273
|
+
colorsOk(s.colors, `scope ${s.for}`);
|
|
274
|
+
for (const [role, id] of Object.entries(s.fonts ?? {})) if (!faces.has(id)) errors.push(`scope ${s.for}: fonts.${role} names no typeface ${id} (T-2)`);
|
|
275
|
+
}
|
|
276
|
+
const fors = (brand.scopes ?? []).map((s) => s.for);
|
|
277
|
+
for (const f of new Set(fors.filter((x, i) => fors.indexOf(x) !== i))) errors.push(`scope ${f} is declared twice; merge them (Y-5)`);
|
|
278
|
+
// Voice rules (Y-3).
|
|
279
|
+
const ids = (brand.voice?.rules ?? []).map((r) => r.id);
|
|
280
|
+
for (const id of new Set(ids.filter((x, i) => ids.indexOf(x) !== i))) errors.push(`voice rule ${id} is declared twice`);
|
|
281
|
+
// Marks (P-24): registered assets of the right type and size.
|
|
282
|
+
const KINDS = { favicon: ["ico"], icon: ["png", "svg", "ico"], "apple-icon": ["png"], logo: ["png", "svg", "jpeg", "webp"] };
|
|
283
|
+
for (const m of brand.marks ?? []) {
|
|
284
|
+
if (!existsSync(join(dir, m.asset))) { errors.push(`mark ${m.kind}: ${m.asset} is not there (P-24)`); continue; }
|
|
285
|
+
if (!asset(m.asset)) errors.push(`mark ${m.kind}: ${m.asset} has no entry in ${REGISTER}, so its source and license are unknown (P-24, J-2)`);
|
|
286
|
+
const f = factsOf(readFileSync(join(dir, m.asset)));
|
|
287
|
+
if (!KINDS[m.kind].includes(f.type)) errors.push(`mark ${m.kind}: ${m.asset} is ${f.type}; a ${m.kind} is ${KINDS[m.kind].join(" or ")} (P-24)`);
|
|
288
|
+
if (m.kind === "apple-icon" && f.type === "png" && (f.width !== 180 || f.height !== 180)) errors.push(`mark apple-icon: ${m.asset} is ${f.width}x${f.height}; an apple-icon is 180x180 (P-24)`);
|
|
289
|
+
if (m.kind === "icon" && f.width && f.width !== f.height) errors.push(`mark icon: ${m.asset} is ${f.width}x${f.height}; an icon is square (P-24)`);
|
|
290
|
+
}
|
|
291
|
+
const kinds = (brand.marks ?? []).map((m) => m.kind).filter((k) => k !== "icon");
|
|
292
|
+
for (const k of new Set(kinds.filter((x, i) => kinds.indexOf(x) !== i))) errors.push(`mark ${k} is declared twice (P-24)`);
|
|
293
|
+
// Design systems (Y-4): linked, not copied.
|
|
294
|
+
const systems = new Map((brand.design_systems ?? []).map((d) => [d.id, d]));
|
|
295
|
+
for (const d of brand.design_systems ?? []) if (!/^https?:\/\//.test(d.url ?? "")) errors.push(`design system ${d.id}: ${d.url ?? "no url"} is not a link; a design system is referenced, not copied (Y-4)`);
|
|
296
|
+
for (const a of reg?.assets ?? []) if (a.design_system) {
|
|
297
|
+
const d = systems.get(a.design_system);
|
|
298
|
+
if (!d) errors.push(`${a.path}: from design system ${a.design_system}, which the brand does not reference (Y-4)`);
|
|
299
|
+
else if (!allowsCopy(d.license)) errors.push(`${a.path}: a copy from design system ${d.id} (license ${d.license}); link to it at ${d.url} instead (Y-4)`);
|
|
300
|
+
}
|
|
301
|
+
// Content held to the voice.
|
|
302
|
+
const v = voice(dir, brand);
|
|
303
|
+
for (const x of v.violations) errors.push(`${x.file}:${x.line}: "${x.found}" breaks voice rule ${x.rule}${x.use ? `; use "${x.use}"` : ""} (Y-3)`);
|
|
304
|
+
for (const x of v.local_terms) warnings.push(`${x.file}:${x.line}: "${x.term}" is a term local to ${x.local_to}; export it from glossary/${x.local_to}.json or say it plainly (Y-2)`);
|
|
305
|
+
return { ok: !errors.length, errors, warnings, brand: true };
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// ---------------------------------------------------------------------------------------------
|
|
309
|
+
// The sitemap (P-26): rendered from the marketing record, for a release.
|
|
310
|
+
|
|
311
|
+
const xmlEscape = (s) => String(s).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
312
|
+
|
|
313
|
+
export function sitemapOf(dir) {
|
|
314
|
+
const f = SITEMAPS.find((p) => existsSync(join(dir, p)));
|
|
315
|
+
return f ? { file: f, record: load(join(dir, f)) } : null;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
/** sitemaps.org XML from a marketing sitemap record: one <url> per planned page, home first. */
|
|
319
|
+
export function sitemapXml(record, base) {
|
|
320
|
+
let root;
|
|
321
|
+
try { root = new URL(base); } catch { throw new Error(`${base} is not a URL`); }
|
|
322
|
+
if (!/^https?:$/.test(root.protocol)) throw new Error(`${base} is not an http or https URL`);
|
|
323
|
+
const origin = base.replace(/\/+$/, "");
|
|
324
|
+
const lastmod = /^\d{4}-\d{2}-\d{2}/.test(record.planned_at ?? "") ? record.planned_at.slice(0, 10) : null;
|
|
325
|
+
const pages = [...record.pages].sort((a, b) => (a.level === "home" ? -1 : b.level === "home" ? 1 : 0));
|
|
326
|
+
const urls = pages.map((p) => {
|
|
327
|
+
const path = p.path.startsWith("/") ? p.path : `/${p.path}`;
|
|
328
|
+
return ` <url>\n <loc>${xmlEscape(origin + (path === "/" ? "/" : path))}</loc>${lastmod ? `\n <lastmod>${lastmod}</lastmod>` : ""}\n </url>`;
|
|
329
|
+
});
|
|
330
|
+
return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${urls.join("\n")}\n</urlset>\n`;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// ---------------------------------------------------------------------------------------------
|
|
334
|
+
|
|
335
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
336
|
+
const argv = process.argv.slice(2);
|
|
337
|
+
const opt = (n) => { const i = argv.indexOf(`--${n}`); return i >= 0 ? argv[i + 1] : undefined; };
|
|
338
|
+
const json = argv.includes("--json");
|
|
339
|
+
const dir = argv[0];
|
|
340
|
+
const mode = argv[1] && !argv[1].startsWith("--") ? argv[1] : null;
|
|
341
|
+
if (!dir || !existsSync(join(dir, "venture.json"))) { console.error("usage: node schema/brand.mjs <venture dir> tokens|voice|check | --for <route> | --package <id> | --base <url> [--json]"); process.exit(2); }
|
|
342
|
+
const print = (x, text) => console.log(json ? JSON.stringify(x, null, 2) : text ?? JSON.stringify(x, null, 2));
|
|
343
|
+
if (opt("for") !== undefined) {
|
|
344
|
+
const brand = brandOf(dir);
|
|
345
|
+
if (!brand) { console.error(`no brand yet: write ${BRAND} (mentura marketing/brand template)`); process.exit(1); }
|
|
346
|
+
print(resolveBrand(brand, opt("for")));
|
|
347
|
+
} else if (opt("package") !== undefined) {
|
|
348
|
+
const t = termsFor(dir, opt("package"));
|
|
349
|
+
print(t, t.terms.map((x) => `${x.term.padEnd(24)} ${x.from.padEnd(12)} ${x.meaning}`).join("\n") || `no terms reach ${opt("package")}`);
|
|
350
|
+
} else if (opt("base") !== undefined) {
|
|
351
|
+
const s = sitemapOf(dir);
|
|
352
|
+
if (!s) { console.error("no marketing sitemap yet: plan it (mentura operations/marketing/sitemap run) and write marketing/sitemap.json"); process.exit(1); }
|
|
353
|
+
let xml;
|
|
354
|
+
try { xml = sitemapXml(s.record, opt("base")); } catch (e) { console.error(e.message); process.exit(1); }
|
|
355
|
+
print({ from: s.file, pages: s.record.pages.length, xml }, xml);
|
|
356
|
+
} else if (mode === "tokens") {
|
|
357
|
+
const t = tokens(dir);
|
|
358
|
+
if (!t) { console.error(`no brand yet: write ${BRAND}`); process.exit(1); }
|
|
359
|
+
print(t, t.css);
|
|
360
|
+
} else if (mode === "voice") {
|
|
361
|
+
const v = voice(dir);
|
|
362
|
+
print(v, v.violations.map((x) => `${x.file}:${x.line} "${x.found}" (${x.rule})${x.use ? ` -> ${x.use}` : ""}`).join("\n") || `voice: ${v.files} files keep to the voice rules`);
|
|
363
|
+
} else {
|
|
364
|
+
const r = checkBrand(dir);
|
|
365
|
+
if (json) console.log(JSON.stringify(r, null, 2));
|
|
366
|
+
else {
|
|
367
|
+
for (const e of r.errors) console.log(`error ${e}`);
|
|
368
|
+
for (const w of r.warnings) console.log(`warn ${w}`);
|
|
369
|
+
console.log(r.ok ? `brand: ${r.brand ? "tokens, typefaces, marks, design systems and voice check out" : "no brand record yet; glossaries check out"}` : `brand: ${r.errors.length} errors`);
|
|
370
|
+
}
|
|
371
|
+
process.exit(r.ok ? 0 : 1);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// naive build (I-17, C-13): checks every open package can be released, then writes the release to
|
|
3
|
+
// <venture>/.release/: release.json (the manifest: confirmed records frozen in, named live holes, the
|
|
4
|
+
// route table as the release holds it), records/ (the frozen copies) and card.json (the release card).
|
|
5
|
+
// It refuses, exit 1, when a record in an open package is unconfirmed or a check fails, and names each
|
|
6
|
+
// one with the command that settles it. The rules are in schema/releases.mjs.
|
|
7
|
+
//
|
|
8
|
+
// node schema/build-release.mjs <venture dir> [--now <iso time>] [--json] [--dry-run]
|
|
9
|
+
// node schema/build-release.mjs <venture dir> --add <route> add one new item without rebuilding (C-18)
|
|
10
|
+
// node schema/build-release.mjs <venture dir> --export <out dir> the release as plain files, no holes (Z-3)
|
|
11
|
+
//
|
|
12
|
+
// --port is accepted and ignored, so naive build and naive start can pass the same arguments.
|
|
13
|
+
|
|
14
|
+
import { existsSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
import { add, build, exportRelease } from "./releases.mjs";
|
|
17
|
+
|
|
18
|
+
const args = process.argv.slice(2);
|
|
19
|
+
const opt = (n) => { const i = args.indexOf(`--${n}`); return i >= 0 ? args[i + 1] : undefined; };
|
|
20
|
+
const has = (n) => args.includes(`--${n}`);
|
|
21
|
+
const values = new Set(["now", "add", "export", "port"].flatMap((n) => (opt(n) !== undefined ? [opt(n)] : [])));
|
|
22
|
+
const dir = args.find((a) => !a.startsWith("--") && !values.has(a));
|
|
23
|
+
if (!dir || !existsSync(join(dir, "venture.json"))) {
|
|
24
|
+
console.error("usage: node schema/build-release.mjs <venture dir> [--now <iso>] [--json] [--dry-run] | --add <route> | --export <out dir>");
|
|
25
|
+
process.exit(2);
|
|
26
|
+
}
|
|
27
|
+
const actor = process.env.MENTURA_ACTOR === "agent" ? "agent" : "person";
|
|
28
|
+
const now = opt("now") ?? new Date().toISOString();
|
|
29
|
+
if (opt("now") && Number.isNaN(Date.parse(opt("now")))) { console.error(`--now ${opt("now")} is not a time`); process.exit(2); }
|
|
30
|
+
|
|
31
|
+
if (opt("export")) {
|
|
32
|
+
const r = exportRelease(dir, opt("export"));
|
|
33
|
+
if (!r.ok) { console.error(r.error); process.exit(1); }
|
|
34
|
+
console.log(has("json") ? JSON.stringify(r, null, 2) : `exported ${r.records} records to ${r.out}; ${r.left_out_live} live items left out`);
|
|
35
|
+
process.exit(0);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (opt("add")) {
|
|
39
|
+
const r = await add(dir, opt("add"), { now, actor });
|
|
40
|
+
if (!r.ok) { console.error(r.error + (r.fix ? `\n fix: ${r.fix}` : "")); process.exit(1); }
|
|
41
|
+
console.log(has("json") ? JSON.stringify(r.manifest, null, 2) : `added ${r.added.route} to release ${r.added.from}: now release ${r.manifest.release}; nothing else was rebuilt`);
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const r = await build(dir, { now, actor, dryRun: has("dry-run") });
|
|
46
|
+
if (!r.ok) {
|
|
47
|
+
if (r.error) { console.error(r.error); process.exit(1); }
|
|
48
|
+
if (has("json")) console.log(JSON.stringify(r, null, 2));
|
|
49
|
+
console.error("naive build: no release written.");
|
|
50
|
+
for (const p of r.packages.filter((x) => !x.releasable)) console.error(` package ${p.id} cannot be released:`);
|
|
51
|
+
for (const b of r.blockers) console.error(` ${b.file}: ${b.why}\n fix: ${b.fix}`);
|
|
52
|
+
for (const c of r.failed_checks) console.error(` check ${c.check} failed:\n ${c.output.replace(/\n/g, "\n ")}`);
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
const m = r.manifest;
|
|
56
|
+
if (has("json")) { console.log(JSON.stringify(m, null, 2)); process.exit(0); }
|
|
57
|
+
console.log(`${r.dry_run ? "would write" : "wrote"} release ${m.release} for ${m.venture} (${m.phase}) as of ${m.now}`);
|
|
58
|
+
console.log(` ${m.records.length} records frozen, ${m.holes.length} live holes, ${m.left_out.length} files left out`);
|
|
59
|
+
for (const p of m.packages) console.log(` package ${p.id.padEnd(12)} ${p.releasable ? "released" : "blocked"} shell ${p.shell ?? "empty"}${p.gaps.length ? ` not written yet: ${p.gaps.join(", ")}` : ""}`);
|
|
60
|
+
for (const h of m.holes) console.log(` hole ${h.kind.padEnd(9)} ${h.name}: ${h.why}`);
|
|
61
|
+
console.log(` cache: ${m.cache.hits} hits, ${m.cache.misses} misses${m.cache.fresh ? " (started fresh: new framework, packages or model)" : ""}`);
|