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
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// Context: what the router sends an agent, in what order, and what it costs. Naive's translation of
|
|
3
|
+
// Next.js Linking and Navigating, layouts that keep their state, prefetching, streaming and bundle
|
|
4
|
+
// size, for a client that is a model instead of a browser. Code decides everything here; no model
|
|
5
|
+
// is called.
|
|
6
|
+
//
|
|
7
|
+
// navigate read a route the AI-native way: header first, then the layout (once per session),
|
|
8
|
+
// the template (fresh every time), the record, and prefetched refs. Reached as the
|
|
9
|
+
// router actions navigate and head, the CLI and the MCP tool mentura_read.
|
|
10
|
+
// header first (O-4) a record's header (what it is, its state, its owner, its size) comes before
|
|
11
|
+
// its body; head stops there, so an agent can decide not to read on
|
|
12
|
+
// layout (L-2, N-7) the stable context, split into parts (the layer and package stack, each
|
|
13
|
+
// AGENTS.md, the merged instructions, the record's schema and gate). In a session each
|
|
14
|
+
// part is sent once and only again when it changes; a sibling route keeps the shared
|
|
15
|
+
// parts and swaps only the record's own
|
|
16
|
+
// template (P-12, F-6) what is recomputed on every action: the need-now ranking and the open
|
|
17
|
+
// decisions. It is never in the layout, and it runs with a time limit, so a slow
|
|
18
|
+
// computation never blocks the read
|
|
19
|
+
// prefetch (N-3, L-12) short summaries of the routes the agent is likely to need next: the
|
|
20
|
+
// record's refs and links, the records it reads first and the ones that wait on it
|
|
21
|
+
// (the after links in packages/catalog.json), and the need-now next step. Confirmed
|
|
22
|
+
// records come in full when small, changing ones send only their state (N-4); large
|
|
23
|
+
// collections send a count unless the task names them (N-12); every entry costs
|
|
24
|
+
// tokens from the prefetch budget (C-16)
|
|
25
|
+
// budget (N-13) each route has a context budget in tokens, measured like bundle size; every
|
|
26
|
+
// answer reports what it used, and budget() reports every route of a venture with its
|
|
27
|
+
// largest part and where to move it (S-14: give context as low in the tree as it is
|
|
28
|
+
// needed; F-6: keep computed values out of layouts)
|
|
29
|
+
// streaming (N-5, N-9) parts are handed to onPart as they are ready; a computed (command) route
|
|
30
|
+
// answers at once with its state and the last result, then the new one. runStreaming
|
|
31
|
+
// and batch report progress, which the MCP server sends as progress notifications
|
|
32
|
+
//
|
|
33
|
+
// Settings come from "context" in the venture's naive.config.json:
|
|
34
|
+
// { "context": { "budget": 6000, "routes": { "purpose/**": 4000 }, "prefetch_budget": 1500,
|
|
35
|
+
// "large_collection": 20, "full_max": 800, "template_ms": 3000 } }
|
|
36
|
+
// A scoped instruction applies only under its routes: a line "[purpose/validation/**] key: value" in
|
|
37
|
+
// any AGENTS.md (the router's plain layout ignores it, so other routes do not pay for it).
|
|
38
|
+
//
|
|
39
|
+
// node interface/context.mjs <venture dir> budget [--check] [--json]
|
|
40
|
+
|
|
41
|
+
import { execFile, spawn } from "node:child_process";
|
|
42
|
+
import { createHash } from "node:crypto";
|
|
43
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
|
|
44
|
+
import { tmpdir } from "node:os";
|
|
45
|
+
import { dirname, join, relative } from "node:path";
|
|
46
|
+
import { call, draftOf, gateOf, glob, layout as routerLayout, resolve, routes, ventureDir } from "./router.mjs";
|
|
47
|
+
import { entries as provEntries } from "./provenance.mjs";
|
|
48
|
+
import { tokens } from "./instrumentation.mjs";
|
|
49
|
+
|
|
50
|
+
const here = dirname(new URL(import.meta.url).pathname);
|
|
51
|
+
const repoRoot = join(here, "..");
|
|
52
|
+
const load = (p) => JSON.parse(readFileSync(p, "utf8"));
|
|
53
|
+
const sha = (x) => createHash("sha256").update(typeof x === "string" ? x : JSON.stringify(x)).digest("hex").slice(0, 16);
|
|
54
|
+
|
|
55
|
+
export const DEFAULTS = { budget: 6000, prefetch_budget: 1500, large_collection: 20, full_max: 800, template_ms: 3000 };
|
|
56
|
+
// Keys that hold computed values: they belong in the template, never in a layout (F-6).
|
|
57
|
+
export const COMPUTED = ["need_now", "need-now", "next", "ranking", "rank", "open_decisions", "decisions", "status", "todo", "due"];
|
|
58
|
+
|
|
59
|
+
/** The venture's context settings: the defaults, overridden by naive.config.json context. */
|
|
60
|
+
export function settings(dir) {
|
|
61
|
+
const f = dir && join(dir, "naive.config.json");
|
|
62
|
+
let c = {};
|
|
63
|
+
try { if (f && existsSync(f)) c = load(f).context ?? {}; } catch {}
|
|
64
|
+
return { ...DEFAULTS, ...c };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** A route's context budget in tokens: the first matching glob in context.routes, else the default. */
|
|
68
|
+
export function budgetFor(set, route) {
|
|
69
|
+
const hit = Object.entries(set.routes ?? {}).find(([g]) => glob(g).test(route));
|
|
70
|
+
return hit ? hit[1] : set.budget;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// ---------------------------------------------------------------------------------------------
|
|
74
|
+
// Header first (O-4)
|
|
75
|
+
|
|
76
|
+
/** The state of one venture file: missing, draft waiting, agent-written, confirmed, baseline or unlogged. */
|
|
77
|
+
export function stateOf(dir, file, draft) {
|
|
78
|
+
if (draft && existsSync(join(dir, draft))) return { state: "draft waiting", draft };
|
|
79
|
+
if (!file || !existsSync(join(dir, file))) return { state: "missing" };
|
|
80
|
+
let state = "unlogged", last = null;
|
|
81
|
+
for (const e of provEntries(dir).filter((x) => x.entity === file)) {
|
|
82
|
+
last = e;
|
|
83
|
+
if (e.activity === "baseline") state = "baseline";
|
|
84
|
+
else if (e.activity === "accept" || e.activity === "confirm" || e.agent?.kind === "person") state = "confirmed";
|
|
85
|
+
else if (e.agent?.kind === "agent") state = "agent-written";
|
|
86
|
+
}
|
|
87
|
+
return { state, ...(last ? { updated: last.at, by: `${last.agent?.kind ?? "unknown"}${last.agent?.id ? ` ${last.agent.id}` : ""}` } : {}) };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const TITLE = ["name", "title", "statement", "claim", "end", "question", "promise", "summary", "description", "id"];
|
|
91
|
+
/** A one-line summary of a record: its first naming field, cut to 140 characters. */
|
|
92
|
+
export function titleOf(rec) {
|
|
93
|
+
if (rec === null || rec === undefined) return null;
|
|
94
|
+
if (typeof rec === "string") return rec.split("\n").find((l) => l.trim())?.replace(/^#+\s*/, "").slice(0, 140) ?? null;
|
|
95
|
+
if (typeof rec !== "object" || Array.isArray(rec)) return null;
|
|
96
|
+
for (const k of TITLE) if (typeof rec[k] === "string" && rec[k].trim()) return rec[k].slice(0, 140);
|
|
97
|
+
for (const v of Object.values(rec)) if (v && typeof v === "object" && !Array.isArray(v)) { const t = titleOf(v); if (t) return t; }
|
|
98
|
+
const s = Object.values(rec).find((v) => typeof v === "string" && v.trim());
|
|
99
|
+
return s ? s.slice(0, 140) : null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function ownerOf(r, dir, route) {
|
|
103
|
+
const g = r.kind === "record" ? gateOf(r, dir) : null;
|
|
104
|
+
if (g?.owner) return g.owner;
|
|
105
|
+
const plan = [join(dir, "people/team-plan.json"), join(dir, "operations/team-plan.json")].find((p) => existsSync(p));
|
|
106
|
+
if (!plan) return null;
|
|
107
|
+
try { return load(plan).roles.find((x) => (x.routes?.write ?? []).some((gl) => glob(gl).test(route)))?.id ?? null; } catch { return null; }
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function fileOfRead(res) {
|
|
111
|
+
const a = res?.source?.address;
|
|
112
|
+
return a ? a.replace(/^[a-z0-9-]+:\/\//, "") : null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** The header of a read: what it is, its state, its owner and what reading it costs, without its body. */
|
|
116
|
+
export function headerOf({ r, route, dir, venture, workspace, res }) {
|
|
117
|
+
const h = { route, record: r.record ?? null, kind: r.kind, ...(r.collection ? { collection: r.collection } : {}) };
|
|
118
|
+
if (r.kind === "command") return { ...h, state: "computed", note: r.note };
|
|
119
|
+
if (r.collection === "list") {
|
|
120
|
+
const n = res?.result ? Object.keys(res.result).length : 0;
|
|
121
|
+
return { ...h, state: n ? "collection" : "missing", count: n, owner: ownerOf(r, dir, route), tokens: tokens(res?.result) };
|
|
122
|
+
}
|
|
123
|
+
const d = draftOf(route, venture, workspace);
|
|
124
|
+
const file = (res?.result !== null && res?.result !== undefined && (fileOfRead(res) ?? d?.file)) || d?.file;
|
|
125
|
+
const st = stateOf(dir, res?.result === null ? null : file, d?.draft);
|
|
126
|
+
if (st.state === "missing" && res?.result !== null && res?.result !== undefined) st.state = "present";
|
|
127
|
+
return { ...h, ...st, ...(st.state === "draft waiting" && res?.result ? { has_record: true } : {}), owner: ownerOf(r, dir, route), title: titleOf(res?.result), tokens: tokens(res?.result),
|
|
128
|
+
...(res?.source ? { source: res.source.source, version: res.source.version } : {}) };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// ---------------------------------------------------------------------------------------------
|
|
132
|
+
// Layout parts, sessions and scoped instructions (L-2, N-7, S-14)
|
|
133
|
+
|
|
134
|
+
/** Every AGENTS.md from the venture root down the route's segments, nearest last. */
|
|
135
|
+
export function chainOf(dir, route) {
|
|
136
|
+
const out = [];
|
|
137
|
+
const add = (rel) => { const f = join(dir, rel); if (existsSync(f)) out.push({ path: rel, text: readFileSync(f, "utf8") }); };
|
|
138
|
+
add("AGENTS.md");
|
|
139
|
+
let acc = "";
|
|
140
|
+
for (const p of route.split("/").filter(Boolean)) { acc = acc ? `${acc}/${p}` : p; add(`${acc}/AGENTS.md`); }
|
|
141
|
+
return out;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const PLAIN = /^([a-z][a-z0-9_-]*)\s*:\s*(.+)$/;
|
|
145
|
+
const SCOPED = /^\[([^\]]+)\]\s*([a-z][a-z0-9_-]*)\s*:\s*(.+)$/;
|
|
146
|
+
/** The merged key: value instructions for a route; a scoped line applies only where its glob matches. Nearest wins. */
|
|
147
|
+
export function instructionsFor(chain, route) {
|
|
148
|
+
const out = {};
|
|
149
|
+
for (const f of chain) for (const line of f.text.split("\n")) {
|
|
150
|
+
const s = line.match(SCOPED);
|
|
151
|
+
if (s) { if (s[1].split(",").map((x) => x.trim()).some((g) => glob(g).test(route))) out[s[2]] = s[3].trim(); continue; }
|
|
152
|
+
const m = line.match(PLAIN);
|
|
153
|
+
if (m) out[m[1]] = m[2].trim();
|
|
154
|
+
}
|
|
155
|
+
return out;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** The stable layout of a route, as named parts. Nothing computed is in it (F-6). */
|
|
159
|
+
export function layoutParts(r, dir) {
|
|
160
|
+
const base = routerLayout(r, null); // no venture: no need-now spawn, no chain; both come from here instead
|
|
161
|
+
const chain = chainOf(dir, r.route.replace(/\/\[id\]$/, ""));
|
|
162
|
+
// One part per layer or package in the stack, so routes in the same layer share theirs.
|
|
163
|
+
const parts = Object.fromEntries(base.stack.map((k) => [`stack:${k.path}`, k]));
|
|
164
|
+
for (const f of chain) parts[`chain:${f.path}`] = f.text;
|
|
165
|
+
parts.instructions = instructionsFor(chain, r.route);
|
|
166
|
+
parts[`record:${r.route}`] = r.kind === "record"
|
|
167
|
+
? { schema: r.schema, template: r.template, checks: r.checks, gate: gateOf(r, dir), package: base.package, groups: r.groups, note: r.note }
|
|
168
|
+
: { note: r.note, script: r.script ?? null };
|
|
169
|
+
return parts;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const sessionDir = () => process.env.NAIVE_SESSION_DIR ?? join(tmpdir(), "naive-sessions");
|
|
173
|
+
const sessionFile = (dir, session) => join(sessionDir(), `${sha(`${dir}\0${session}`)}.json`);
|
|
174
|
+
/** What a session has been sent: part key to hash, and the routes it visited. */
|
|
175
|
+
export function sessionOf(dir, session) {
|
|
176
|
+
try { return load(sessionFile(dir, session)); } catch { return { session, sent: {}, routes: [] }; }
|
|
177
|
+
}
|
|
178
|
+
function saveSession(dir, s) { mkdirSync(sessionDir(), { recursive: true }); writeFileSync(sessionFile(dir, s.session), JSON.stringify(s)); }
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* The layout to send: every part without a session; with one, only the parts this session has not
|
|
182
|
+
* seen or that changed since (L-2). A sibling route keeps the shared parts and swaps the record's (N-7).
|
|
183
|
+
*/
|
|
184
|
+
export function layoutFor(r, dir, session) {
|
|
185
|
+
const parts = layoutParts(r, dir);
|
|
186
|
+
if (!session) return { parts };
|
|
187
|
+
const s = sessionOf(dir, session);
|
|
188
|
+
const send = {}, kept = [], changed = [];
|
|
189
|
+
for (const [k, v] of Object.entries(parts)) {
|
|
190
|
+
const h = sha(v);
|
|
191
|
+
if (s.sent[k] === h) kept.push(k);
|
|
192
|
+
else { send[k] = v; if (s.sent[k]) changed.push(k); s.sent[k] = h; }
|
|
193
|
+
}
|
|
194
|
+
const first = s.routes.length === 0;
|
|
195
|
+
s.routes = [...s.routes.filter((x) => x !== r.route), r.route].slice(-50);
|
|
196
|
+
saveSession(dir, s);
|
|
197
|
+
return { session, first, parts: send, kept, ...(changed.length ? { changed } : {}) };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// ---------------------------------------------------------------------------------------------
|
|
201
|
+
// Template: recomputed on every action, with a time limit (P-12, F-6)
|
|
202
|
+
|
|
203
|
+
function runJson(script, args, ms) {
|
|
204
|
+
return new Promise((done) => {
|
|
205
|
+
const t0 = Date.now();
|
|
206
|
+
execFile(process.execPath, [join(repoRoot, script), ...args], { timeout: ms, maxBuffer: 64 * 1024 * 1024 }, (err, stdout) => {
|
|
207
|
+
if (err?.killed) return done({ ok: false, timed_out: true, ms: Date.now() - t0 });
|
|
208
|
+
try { done({ ok: true, json: JSON.parse(stdout), ms: Date.now() - t0 }); } catch { done({ ok: false, error: String(err?.message ?? "no JSON").split("\n")[0], ms: Date.now() - t0 }); }
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/** The template for a route: the need-now ranking and open decisions, computed now. Parts that run past template_ms come back pending. */
|
|
214
|
+
export async function templateFor(r, dir, set = settings(dir)) {
|
|
215
|
+
const [nn, ds] = await Promise.all([runJson("schema/need-now.mjs", [dir, "--json"], set.template_ms), runJson("schema/decisions.mjs", [dir, "--json"], set.template_ms)]);
|
|
216
|
+
const out = { computed_at: new Date().toISOString() };
|
|
217
|
+
const pending = [];
|
|
218
|
+
if (nn.ok) {
|
|
219
|
+
const row = nn.json.rows.find((x) => x.type === r.record);
|
|
220
|
+
out.need_now = { phase: nn.json.phase, ...(row ? { this: { status: row.status, now: row.now, why: row.why } } : {}),
|
|
221
|
+
suggest_now: nn.json.rows.filter((x) => x.status === "suggest now").sort((a, b) => b.now - a.now).slice(0, 5).map((x) => x.type) };
|
|
222
|
+
} else pending.push(`need_now (${nn.timed_out ? `over ${set.template_ms}ms` : nn.error})`);
|
|
223
|
+
if (ds.ok) {
|
|
224
|
+
const open = (ds.json.decisions ?? []).filter((d) => ["now", "overdue"].includes(d.render) && d.source !== "root");
|
|
225
|
+
out.decisions = { open: open.length, overdue: open.filter((d) => d.render === "overdue").map((d) => d.id), now: open.slice(0, 5).map((d) => ({ id: d.id, question: d.question })) };
|
|
226
|
+
} else pending.push(`decisions (${ds.timed_out ? `over ${set.template_ms}ms` : ds.error})`);
|
|
227
|
+
if (pending.length) Object.assign(out, { pending, note: "still computing: run system/need-now or governance/decisions for the rest; the read did not wait" });
|
|
228
|
+
return out;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// ---------------------------------------------------------------------------------------------
|
|
232
|
+
// Prefetch (N-3, N-4, N-12, L-12, C-16)
|
|
233
|
+
|
|
234
|
+
const MODEL = () => load(join(repoRoot, "schema/data-model.json"));
|
|
235
|
+
const AFTER = () => { try { return load(join(repoRoot, "packages/catalog.json")).records ?? {}; } catch { return {}; } };
|
|
236
|
+
const valuesAt = (o, path) => path.split(".").reduce((xs, k) => xs.flatMap((x) => (Array.isArray(x) ? x : [x]).flatMap((y) => (y && typeof y === "object" && y[k] !== undefined ? [y[k]] : []))), [o]).flat();
|
|
237
|
+
const ROUTEISH = /^[a-z][a-z0-9-]*(\/[a-z0-9.\-[\]]+)+$/;
|
|
238
|
+
function strings(o, out = [], depth = 0) {
|
|
239
|
+
if (out.length > 300 || depth > 6) return out;
|
|
240
|
+
if (typeof o === "string") out.push(o);
|
|
241
|
+
else if (Array.isArray(o)) for (const x of o) strings(x, out, depth + 1);
|
|
242
|
+
else if (o && typeof o === "object") for (const x of Object.values(o)) strings(x, out, depth + 1);
|
|
243
|
+
return out;
|
|
244
|
+
}
|
|
245
|
+
/** The route a record type is read at: its list route for a collection, else its one route. */
|
|
246
|
+
export function routeOfType(type, id) {
|
|
247
|
+
const rs = routes().filter((x) => x.kind === "record" && x.record === type);
|
|
248
|
+
const item = rs.find((x) => x.collection === "item"), list = rs.find((x) => x.collection === "list"), one = rs.find((x) => !x.collection);
|
|
249
|
+
if (item && typeof id === "string" && /^[a-z0-9][a-z0-9-]*$/.test(id)) return item.route.replace("[id]", id);
|
|
250
|
+
return (list ?? one)?.route ?? null;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** The routes an agent is likely to need after this one, most likely first, each with why. */
|
|
254
|
+
export function candidates(r, record, template, { hover = [] } = {}) {
|
|
255
|
+
const out = [];
|
|
256
|
+
const add = (route, why) => { if (route && route !== r.route && !out.some((x) => x.route === route)) out.push({ route, why }); };
|
|
257
|
+
for (const h of hover) add(h, "asked");
|
|
258
|
+
if (r.kind === "record" && record && typeof record === "object") {
|
|
259
|
+
const def = MODEL().records.find((x) => x.id === r.record);
|
|
260
|
+
for (const ref of def?.refs ?? []) {
|
|
261
|
+
const vals = valuesAt(record, ref.field).filter((v) => typeof v === "string");
|
|
262
|
+
for (const v of vals) add(routeOfType(ref.to, v), `ref ${ref.field}`);
|
|
263
|
+
}
|
|
264
|
+
// Links: a string in the record that is itself a route (foundation/icp), Naive's <Link>.
|
|
265
|
+
for (const s of strings(record).filter((x) => ROUTEISH.test(x))) { const { r: hit } = resolve(s); if (hit?.kind === "record") add(s, "link"); }
|
|
266
|
+
}
|
|
267
|
+
const after = AFTER();
|
|
268
|
+
for (const t of after[r.record]?.after ?? []) add(routeOfType(t), "reads first");
|
|
269
|
+
const next = template?.need_now?.suggest_now?.find((t) => t !== r.record);
|
|
270
|
+
if (next) add(routeOfType(next), "next step");
|
|
271
|
+
for (const [t, v] of Object.entries(after)) if ((v.after ?? []).includes(r.record)) add(routeOfType(t), "waits on this");
|
|
272
|
+
return out;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/** Prefetches the candidates within the prefetch budget: full, summary, state or count, by what each is and what is left. */
|
|
276
|
+
export async function prefetch({ r, record, template, venture, dir, workspace, actor_id, task = "", hover = [], set }) {
|
|
277
|
+
const cands = candidates(r, record, template, { hover });
|
|
278
|
+
const named = (route) => hover.includes(route) || (task && (task.includes(route) || task.includes(route.split("/").at(-1))));
|
|
279
|
+
const entries = [], dropped = [];
|
|
280
|
+
let spent = 0;
|
|
281
|
+
for (const c of cands) {
|
|
282
|
+
const { r: cr } = resolve(c.route);
|
|
283
|
+
if (!cr) continue;
|
|
284
|
+
const res = await safeCall({ venture, route: c.route, action: "read", workspace, actor_id, via: "prefetch" });
|
|
285
|
+
let options; // most to least, each an entry the agent could receive
|
|
286
|
+
if (!res.ok) options = [{ ...c, state: "unreadable" }];
|
|
287
|
+
else if (cr.collection === "list") {
|
|
288
|
+
const items = res.result ? Object.entries(res.result) : [];
|
|
289
|
+
const counted = { ...c, state: items.length ? "collection" : "missing", count: items.length };
|
|
290
|
+
if (items.length > set.large_collection && !named(c.route)) options = [counted];
|
|
291
|
+
else options = [{ ...counted, items: items.map(([id, v]) => ({ id, title: titleOf(v) })) }, counted];
|
|
292
|
+
} else {
|
|
293
|
+
const h = headerOf({ r: cr, route: c.route, dir, venture, workspace, res });
|
|
294
|
+
const st = { ...c, state: h.state };
|
|
295
|
+
const summary = { ...st, title: h.title, tokens: h.tokens };
|
|
296
|
+
const stable = h.state === "confirmed";
|
|
297
|
+
if (h.state === "missing") options = [st];
|
|
298
|
+
else if ((stable || named(c.route)) && h.tokens <= set.full_max) options = [{ ...summary, full: res.result }, summary, st];
|
|
299
|
+
else if (stable || named(c.route)) options = [summary, st];
|
|
300
|
+
else options = [st]; // changing (agent-written, a draft, unlogged): only its state (N-4)
|
|
301
|
+
}
|
|
302
|
+
const fit = options.find((o) => spent + tokens(o) <= set.prefetch_budget);
|
|
303
|
+
if (!fit) { dropped.push(c.route); continue; }
|
|
304
|
+
spent += tokens(fit);
|
|
305
|
+
entries.push({ ...fit, cost: tokens(fit) });
|
|
306
|
+
}
|
|
307
|
+
return { entries, spent, budget: set.prefetch_budget, ...(dropped.length ? { dropped } : {}) };
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// ---------------------------------------------------------------------------------------------
|
|
311
|
+
// Navigate: the whole answer, streamed part by part (N-5, N-9)
|
|
312
|
+
|
|
313
|
+
// A router call that answers a throw as an error, so one broken route never stops a navigation or a report.
|
|
314
|
+
const safeCall = async (args) => { try { return await call(args); } catch (e) { return { ok: false, error: String(e.message ?? e).split("\n")[0] }; } };
|
|
315
|
+
|
|
316
|
+
const runCacheFile = (dir, route) => join(sessionDir(), "runs", `${sha(`${dir}\0${route}`)}.json`);
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Reads a route the AI-native way. Options: session (layout once per session), task (what the agent
|
|
320
|
+
* is doing; a route it names is prefetched in full), prefetch (false to turn it off, or a list of
|
|
321
|
+
* routes to prefetch in full, like hover), header_only (stop after the header), onPart (called with
|
|
322
|
+
* { part, data } as each part is ready). Returns { ok, result: { header, budget, layout, template,
|
|
323
|
+
* result, prefetch } } in that order.
|
|
324
|
+
*/
|
|
325
|
+
export async function navigate({ venture, route, workspace, actor = "agent", actor_id, via = "router", session = process.env.MENTURA_SESSION, task, prefetch: pf = true, header_only = false, onPart, _template }) {
|
|
326
|
+
const { r, params } = resolve(route);
|
|
327
|
+
if (!r) return { ok: false, error: `no route ${route}` };
|
|
328
|
+
const dir = ventureDir(venture, workspace);
|
|
329
|
+
if (!dir) return { ok: false, error: `no venture ${venture}` };
|
|
330
|
+
const concrete = r.collection === "item" ? r.route.replace("[id]", params.id) : r.route;
|
|
331
|
+
const set = settings(dir);
|
|
332
|
+
const send = (part, data) => { try { onPart?.({ part, data: data === undefined ? data : JSON.parse(JSON.stringify(data)) }); } catch {} };
|
|
333
|
+
const out = {};
|
|
334
|
+
|
|
335
|
+
if (r.kind === "command") {
|
|
336
|
+
// A computed route answers at once with its state and the last result, then streams the new one (N-9).
|
|
337
|
+
let last = null;
|
|
338
|
+
try { last = load(runCacheFile(dir, concrete)); } catch {}
|
|
339
|
+
out.header = { ...headerOf({ r, route: concrete, dir, venture, workspace }), state: "computing", ...(last ? { last_at: last.at } : {}) };
|
|
340
|
+
send("header", out.header);
|
|
341
|
+
if (last) { out.stale_result = last.result; send("stale_result", { as_of: last.at, result: last.result }); }
|
|
342
|
+
if (header_only) return { ok: true, result: out };
|
|
343
|
+
out.layout = layoutFor(r, dir, session); send("layout", out.layout);
|
|
344
|
+
const res = await safeCall({ venture, route: concrete, action: "run", workspace, actor, actor_id, via });
|
|
345
|
+
if (!res.ok) return res;
|
|
346
|
+
out.header.state = res.needs_input ? "needs input" : "computed";
|
|
347
|
+
out.result = res.result ?? null;
|
|
348
|
+
if (res.needs_input) out.needs_input = res.needs_input;
|
|
349
|
+
else { mkdirSync(dirname(runCacheFile(dir, concrete)), { recursive: true }); writeFileSync(runCacheFile(dir, concrete), JSON.stringify({ at: new Date().toISOString(), result: res.result })); }
|
|
350
|
+
send("result", out.result);
|
|
351
|
+
out.budget = budgetOf(out, budgetFor(set, r.route));
|
|
352
|
+
send("budget", out.budget);
|
|
353
|
+
return { ok: true, result: order(out) };
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
// The template starts first, in other processes, so it runs while the record is read.
|
|
357
|
+
const templating = header_only ? null : _template ? Promise.resolve(_template) : templateFor(r, dir, set);
|
|
358
|
+
const res = await safeCall({ venture, route: concrete, action: "read", workspace, actor, actor_id, via });
|
|
359
|
+
if (!res.ok) return res;
|
|
360
|
+
out.header = headerOf({ r, route: concrete, dir, venture, workspace, res });
|
|
361
|
+
send("header", out.header);
|
|
362
|
+
if (header_only) { out.budget = budgetOf(out, budgetFor(set, r.route)); return { ok: true, result: order(out) }; }
|
|
363
|
+
out.layout = layoutFor(r, dir, session);
|
|
364
|
+
send("layout", out.layout);
|
|
365
|
+
out.template = await templating;
|
|
366
|
+
send("template", out.template);
|
|
367
|
+
out.result = res.result;
|
|
368
|
+
for (const k of ["not_found", "pending_draft", "pending_pull_requests", "source", "sources", "deprecated"]) if (res[k]) out[k] = res[k];
|
|
369
|
+
send("result", out.result);
|
|
370
|
+
if (pf !== false) {
|
|
371
|
+
out.prefetch = await prefetch({ r, record: res.result, template: out.template, venture, dir, workspace, actor_id, task, hover: Array.isArray(pf) ? pf : [], set });
|
|
372
|
+
// Over the route's budget: prefetch is the first thing given back (C-16).
|
|
373
|
+
const limit = budgetFor(set, r.route);
|
|
374
|
+
while (out.prefetch.entries.length && budgetOf(out, limit).over) out.prefetch.dropped = [...(out.prefetch.dropped ?? []), out.prefetch.entries.pop().route];
|
|
375
|
+
out.prefetch.spent = out.prefetch.entries.reduce((n, e) => n + e.cost, 0);
|
|
376
|
+
send("prefetch", out.prefetch);
|
|
377
|
+
}
|
|
378
|
+
out.budget = budgetOf(out, budgetFor(set, r.route));
|
|
379
|
+
send("budget", out.budget);
|
|
380
|
+
return { ok: true, result: order(out) };
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const PARTS = ["header", "layout", "template", "stale_result", "result", "prefetch"];
|
|
384
|
+
function budgetOf(out, limit) {
|
|
385
|
+
const parts = Object.fromEntries(PARTS.filter((k) => out[k] !== undefined).map((k) => [k, tokens(out[k])]));
|
|
386
|
+
const used = Object.values(parts).reduce((a, b) => a + b, 0);
|
|
387
|
+
return { limit, used, over: used > limit, parts };
|
|
388
|
+
}
|
|
389
|
+
// Header first, then the budget, then the rest in the order an agent needs it.
|
|
390
|
+
const order = (o) => Object.fromEntries(["header", "budget", "needs_input", "layout", "template", "stale_result", "result", "not_found", "pending_draft", "pending_pull_requests", "source", "sources", "deprecated", "prefetch"].filter((k) => o[k] !== undefined).map((k) => [k, o[k]]));
|
|
391
|
+
|
|
392
|
+
/** Runs a command route in a child process and reports progress while it runs (N-5). Gates apply: it goes through the router. */
|
|
393
|
+
export function runStreaming({ venture, route, input, workspace, actor_id }, onProgress = () => {}, every = 250) {
|
|
394
|
+
return new Promise((done) => {
|
|
395
|
+
const args = [join(repoRoot, "interface/cli/mentura.mjs"), route, "run", "--venture", venture, "--json",
|
|
396
|
+
...(input?.value !== undefined ? ["--value", String(input.value)] : []), ...(input?.as_is ? ["--as-is"] : []), ...(workspace ? ["--workspace", workspace] : [])];
|
|
397
|
+
const env = { ...process.env, ...(actor_id ? { MENTURA_ACTOR_ID: actor_id } : {}) };
|
|
398
|
+
const p = spawn(process.execPath, args, { env });
|
|
399
|
+
let stdout = "", stderr = "", n = 0;
|
|
400
|
+
const t0 = Date.now();
|
|
401
|
+
onProgress({ progress: 0, message: `started ${route}` });
|
|
402
|
+
const timer = setInterval(() => onProgress({ progress: ++n, message: `running ${route}: ${((Date.now() - t0) / 1000).toFixed(1)}s` }), every);
|
|
403
|
+
p.stdout.on("data", (d) => { stdout += d; });
|
|
404
|
+
p.stderr.on("data", (d) => {
|
|
405
|
+
stderr += d;
|
|
406
|
+
for (const line of String(d).split("\n")) { const m = line.match(/^progress\s+(\d+)\/(\d+)\s*(.*)$/); if (m) onProgress({ progress: Number(m[1]), total: Number(m[2]), message: m[3] }); }
|
|
407
|
+
});
|
|
408
|
+
p.on("close", (code) => {
|
|
409
|
+
clearInterval(timer);
|
|
410
|
+
onProgress({ progress: ++n, message: `finished ${route} in ${((Date.now() - t0) / 1000).toFixed(1)}s` });
|
|
411
|
+
if (code !== 0) return done({ ok: false, error: (stderr || stdout).trim() });
|
|
412
|
+
try { const j = JSON.parse(stdout); done(j.ok !== undefined ? j : { ok: true, result: j }); } catch { done({ ok: true, result: stdout.trim() }); }
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/** Runs calls one after another (a batch of reads, checks or runs) and reports each as it finishes (N-5). */
|
|
418
|
+
export async function batch({ venture, workspace, calls = [], actor_id, via = "router" }, onProgress = () => {}) {
|
|
419
|
+
const results = [];
|
|
420
|
+
for (const [i, c] of calls.entries()) {
|
|
421
|
+
const r = await safeCall({ venture, workspace, actor_id, via, ...c });
|
|
422
|
+
results.push({ route: c.route, action: c.action, ok: r.ok, ...(r.ok ? { result: r.result } : { error: r.error }) });
|
|
423
|
+
onProgress({ progress: i + 1, total: calls.length, message: `${c.action} ${c.route}: ${r.ok ? "ok" : "failed"}` });
|
|
424
|
+
}
|
|
425
|
+
return { ok: results.every((x) => x.ok), result: results };
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// ---------------------------------------------------------------------------------------------
|
|
429
|
+
// The context budget report (N-13, S-14, F-6)
|
|
430
|
+
|
|
431
|
+
const ADVICE = {
|
|
432
|
+
layout: "move procedural instructions out of AGENTS.md into the router's code or a check, and scope the rest to the routes that need them (S-14)",
|
|
433
|
+
template: "the template is computed every time: keep it to rankings and counts",
|
|
434
|
+
result: "the record is large: read its header first (head) and split it if agents rarely need all of it",
|
|
435
|
+
prefetch: "lower context.prefetch_budget for this route, or turn prefetch off where the refs are rarely followed",
|
|
436
|
+
header: "the header should be small: check the record's title field",
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
/** Every route of a venture against its context budget, with its largest part, plus the layout rules it breaks. */
|
|
440
|
+
export async function budget(dir) {
|
|
441
|
+
// The report's own reads are measurement, not an agent's work: they stay out of the events log and vitals.
|
|
442
|
+
const was = process.env.NAIVE_INSTRUMENT;
|
|
443
|
+
process.env.NAIVE_INSTRUMENT = "0";
|
|
444
|
+
try { return await measureBudget(dir); } finally { if (was === undefined) delete process.env.NAIVE_INSTRUMENT; else process.env.NAIVE_INSTRUMENT = was; }
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
async function measureBudget(dir) {
|
|
448
|
+
const v = load(join(dir, "venture.json"));
|
|
449
|
+
const workspace = dirname(dir);
|
|
450
|
+
const set = settings(dir);
|
|
451
|
+
const rows = [];
|
|
452
|
+
let tmpl = null;
|
|
453
|
+
for (const r of routes().filter((x) => x.kind === "record" && x.collection !== "item")) {
|
|
454
|
+
tmpl ??= await templateFor(r, dir, set);
|
|
455
|
+
const t = { ...tmpl, need_now: tmpl.need_now ? { ...tmpl.need_now, this: undefined } : undefined };
|
|
456
|
+
const n = await navigate({ venture: v.id, route: r.route, workspace, _template: t, via: "budget" });
|
|
457
|
+
if (!n.ok) { rows.push({ route: r.route, error: n.error }); continue; }
|
|
458
|
+
const b = n.result.budget;
|
|
459
|
+
const largest = Object.entries(b.parts).sort((a, c) => c[1] - a[1])[0]?.[0];
|
|
460
|
+
rows.push({ route: r.route, limit: b.limit, used: b.used, over: b.over, largest, ...(b.over ? { advice: ADVICE[largest] } : {}) });
|
|
461
|
+
}
|
|
462
|
+
// Layout rules, over every AGENTS.md in the venture.
|
|
463
|
+
const rules = [];
|
|
464
|
+
const agentsFiles = (d, rel = "") => readdirSync(join(d, rel), { withFileTypes: true }).flatMap((e) => e.name.startsWith(".") || e.name.startsWith("_") ? []
|
|
465
|
+
: e.isDirectory() ? (existsSync(join(d, rel, e.name, "venture.json")) ? [] : agentsFiles(d, rel ? `${rel}/${e.name}` : e.name)) : e.name === "AGENTS.md" ? [rel ? `${rel}/AGENTS.md` : "AGENTS.md"] : []);
|
|
466
|
+
for (const f of agentsFiles(dir)) {
|
|
467
|
+
const folder = dirname(f) === "." ? "" : dirname(f);
|
|
468
|
+
const text = readFileSync(join(dir, f), "utf8");
|
|
469
|
+
for (const line of text.split("\n")) {
|
|
470
|
+
const s = line.match(SCOPED), m = s ? [null, s[2], s[3]] : line.match(PLAIN);
|
|
471
|
+
if (!m) continue;
|
|
472
|
+
// F-6: a computed value in a layout blocks or goes stale; it belongs in the template.
|
|
473
|
+
if (COMPUTED.includes(m[1])) rules.push({ rule: "F-6", file: f, key: m[1], fix: `${m[1]} is computed: leave it to the template (need-now and decisions), not ${f}` });
|
|
474
|
+
// S-14: a scoped line whose routes all sit under one folder belongs in that folder's AGENTS.md.
|
|
475
|
+
if (s) {
|
|
476
|
+
const fixed = s[1].split(",").map((g) => g.trim().split("/").filter((x) => !x.includes("*")).join("/"));
|
|
477
|
+
const common = fixed.reduce((a, b) => { const x = a.split("/"), y = b.split("/"); let i = 0; while (i < x.length && x[i] === y[i]) i++; return x.slice(0, i).join("/"); });
|
|
478
|
+
if (common && common !== folder && common.startsWith(folder)) rules.push({ rule: "S-14", file: f, key: s[2], fix: `move "${line.trim()}" to ${common}/AGENTS.md, so routes outside ${common} do not pay ${tokens(line)} tokens for it` });
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
const t = tokens(text);
|
|
482
|
+
if (t > set.budget / 4) rules.push({ rule: "N-13", file: f, tokens: t, fix: `${f} is ${t} tokens, over a quarter of the ${set.budget}-token budget of every route under it: ${ADVICE.layout}` });
|
|
483
|
+
}
|
|
484
|
+
const over = rows.filter((x) => x.over);
|
|
485
|
+
return { venture: v.id, budget: set.budget, prefetch_budget: set.prefetch_budget, routes: rows, over: over.map((x) => x.route), rules, passed: !over.length && !rules.length };
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// ---------------------------------------------------------------------------------------------
|
|
489
|
+
// Command line: the router's command route system/context, and the CLI hook for navigate, head and batch.
|
|
490
|
+
|
|
491
|
+
/** mentura <route> navigate|head --venture <id> [--session s] [--task text] [--prefetch a,b | --no-prefetch] [--stream]; mentura batch --venture <id> --input calls.json [--stream]. */
|
|
492
|
+
export async function cli(argv, { workspace } = {}) {
|
|
493
|
+
const opt = (n) => { const i = argv.indexOf(`--${n}`); return i >= 0 ? argv[i + 1] : undefined; };
|
|
494
|
+
const flag = (n) => argv.includes(`--${n}`);
|
|
495
|
+
const [route, action] = argv.filter((a, i) => !a.startsWith("--") && !(i > 0 && argv[i - 1].startsWith("--") && !["json", "stream", "no-prefetch", "header", "as-is"].includes(argv[i - 1].slice(2))));
|
|
496
|
+
const venture = opt("venture");
|
|
497
|
+
const stream = flag("stream");
|
|
498
|
+
const line = (x) => process.stdout.write(JSON.stringify(x) + "\n");
|
|
499
|
+
if (route === "batch") {
|
|
500
|
+
const calls = JSON.parse(readFileSync(opt("input") === "-" ? 0 : opt("input"), "utf8"));
|
|
501
|
+
const r = await batch({ venture, workspace, calls: calls.calls ?? calls, via: "cli" }, stream ? (p) => line({ progress: p }) : undefined);
|
|
502
|
+
if (stream) line({ part: "result", data: r.result }); else console.log(JSON.stringify(r.result, null, 2));
|
|
503
|
+
return r.ok ? 0 : 1;
|
|
504
|
+
}
|
|
505
|
+
// Through the router, so the navigation is one instrumented call with its reads under it.
|
|
506
|
+
const r = await call({ venture, route, action, workspace, via: "cli", actor: opt("as") === "person" ? "person" : "agent", input: { session: opt("session") ?? process.env.MENTURA_SESSION, task: opt("task"),
|
|
507
|
+
prefetch: flag("no-prefetch") ? false : opt("prefetch") ? opt("prefetch").split(",").filter(Boolean) : true, onPart: stream ? line : undefined } });
|
|
508
|
+
if (!r.ok) { console.error(r.error); return 1; }
|
|
509
|
+
if (!stream) console.log(JSON.stringify(r.result, null, 2));
|
|
510
|
+
return 0;
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
514
|
+
const [dir, what] = process.argv.slice(2);
|
|
515
|
+
if (!dir || !existsSync(join(dir, "venture.json")) || what !== "budget") { console.error("usage: node interface/context.mjs <venture dir> budget [--check] [--json]"); process.exit(2); }
|
|
516
|
+
const r = await budget(dir);
|
|
517
|
+
if (process.argv.includes("--json")) console.log(JSON.stringify(r, null, 2));
|
|
518
|
+
else {
|
|
519
|
+
console.log(`${r.venture}: ${r.routes.length} routes, budget ${r.budget} tokens (prefetch ${r.prefetch_budget})`);
|
|
520
|
+
for (const x of r.routes) console.log(` ${x.error ? "err " : x.over ? "OVER" : "ok "} ${x.route.padEnd(40)} ${x.error ? `could not read: ${x.error}` : `${String(x.used).padStart(6)} / ${x.limit} largest ${x.largest}`}`);
|
|
521
|
+
for (const x of r.rules) console.log(` ${x.rule.padEnd(5)} ${x.file}: ${x.fix}`);
|
|
522
|
+
}
|
|
523
|
+
if (process.argv.includes("--check") && !r.passed) { console.error(`context budget failing: ${[...r.over, ...r.rules.map((x) => `${x.rule} ${x.file}`)].join(", ")}`); process.exit(1); }
|
|
524
|
+
}
|