@ybotok/loam 0.1.0-beta.3 → 0.2.0-alpha.13
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/CHANGELOG.md +5992 -82
- package/COMPARISON.md +168 -63
- package/CONTRIBUTING.md +121 -0
- package/MIGRATING-from-OpenSpec.md +238 -55
- package/QUICKSTART.md +302 -0
- package/README.md +653 -144
- package/ROADMAP.md +1035 -0
- package/SCHEMA.md +3916 -263
- package/SECURITY.md +21 -3
- package/WORKFLOW.md +927 -0
- package/dist/cli.js +133 -21
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +204 -0
- package/dist/commands/adopt/adopt.js.map +1 -0
- package/dist/commands/adopt/render.js +309 -0
- package/dist/commands/adopt/render.js.map +1 -0
- package/dist/commands/archive/archive.js +74 -0
- package/dist/commands/archive/archive.js.map +1 -0
- package/dist/commands/archive/closing.js +42 -0
- package/dist/commands/archive/closing.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +172 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/consumers.js +56 -0
- package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +193 -0
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
- package/dist/commands/archive/plan/document/head.js +151 -0
- package/dist/commands/archive/plan/document/head.js.map +1 -0
- package/dist/commands/archive/plan/document/links.js +284 -0
- package/dist/commands/archive/plan/document/links.js.map +1 -0
- package/dist/commands/archive/plan/document/run.js +136 -0
- package/dist/commands/archive/plan/document/run.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +319 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +298 -0
- package/dist/commands/archive/plan/landscape.js.map +1 -0
- package/dist/commands/archive/plan/model/extending.js +85 -0
- package/dist/commands/archive/plan/model/extending.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +106 -0
- package/dist/commands/archive/plan/refusal.js.map +1 -0
- package/dist/commands/archive/plan/specs.js +318 -0
- package/dist/commands/archive/plan/specs.js.map +1 -0
- package/dist/commands/archive/plan/state.js +30 -0
- package/dist/commands/archive/plan/state.js.map +1 -0
- package/dist/commands/archive/run.js +355 -0
- package/dist/commands/archive/run.js.map +1 -0
- package/dist/commands/archive/shipped.js +49 -0
- package/dist/commands/archive/shipped.js.map +1 -0
- package/dist/commands/context/context.js +166 -0
- package/dist/commands/context/context.js.map +1 -0
- package/dist/commands/context/print.js +305 -0
- package/dist/commands/context/print.js.map +1 -0
- package/dist/commands/delta/delta.js +367 -0
- package/dist/commands/delta/delta.js.map +1 -0
- package/dist/commands/delta/print.js +221 -0
- package/dist/commands/delta/print.js.map +1 -0
- package/dist/commands/dependencies.js +6 -8
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +86 -0
- package/dist/commands/diff/diff.js.map +1 -0
- package/dist/commands/diff/print.js +38 -0
- package/dist/commands/diff/print.js.map +1 -0
- package/dist/commands/doctor.js +65 -5
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +227 -0
- package/dist/commands/explain/explain.js.map +1 -0
- package/dist/commands/explore.js +39 -28
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +152 -0
- package/dist/commands/gate/gate.js.map +1 -0
- package/dist/commands/gate/print.js +66 -0
- package/dist/commands/gate/print.js.map +1 -0
- package/dist/commands/gherkin/commit.js +105 -0
- package/dist/commands/gherkin/commit.js.map +1 -0
- package/dist/commands/gherkin/gherkin.js +262 -0
- package/dist/commands/gherkin/gherkin.js.map +1 -0
- package/dist/commands/gherkin/reconcile.js +146 -0
- package/dist/commands/gherkin/reconcile.js.map +1 -0
- package/dist/commands/gherkin/render.js +77 -0
- package/dist/commands/gherkin/render.js.map +1 -0
- package/dist/commands/init/example.js +204 -0
- package/dist/commands/init/example.js.map +1 -0
- package/dist/commands/init/first-hour.js +72 -0
- package/dist/commands/init/first-hour.js.map +1 -0
- package/dist/commands/{init.js → init/init.js} +142 -71
- package/dist/commands/init/init.js.map +1 -0
- package/dist/commands/init/mcp.js +131 -0
- package/dist/commands/init/mcp.js.map +1 -0
- package/dist/commands/init/options.js +78 -0
- package/dist/commands/init/options.js.map +1 -0
- package/dist/commands/instructions.js +72 -14
- package/dist/commands/instructions.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +63 -0
- package/dist/commands/list/campaign/campaign.js.map +1 -0
- package/dist/commands/list/campaign/owners.js +65 -0
- package/dist/commands/list/campaign/owners.js.map +1 -0
- package/dist/commands/list/json.js +155 -0
- package/dist/commands/list/json.js.map +1 -0
- package/dist/commands/list/list.js +358 -0
- package/dist/commands/list/list.js.map +1 -0
- package/dist/commands/list/print.js +344 -0
- package/dist/commands/list/print.js.map +1 -0
- package/dist/commands/list/review.js +120 -0
- package/dist/commands/list/review.js.map +1 -0
- package/dist/commands/list/suites/suites.js +140 -0
- package/dist/commands/list/suites/suites.js.map +1 -0
- package/dist/commands/list/views.js +108 -0
- package/dist/commands/list/views.js.map +1 -0
- package/dist/commands/mcp/dispatch.js +238 -0
- package/dist/commands/mcp/dispatch.js.map +1 -0
- package/dist/commands/mcp/mcp.js +75 -0
- package/dist/commands/mcp/mcp.js.map +1 -0
- package/dist/commands/mcp/serve.js +55 -0
- package/dist/commands/mcp/serve.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/active.js +175 -0
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
- package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/living.js +62 -0
- package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/stage.js +143 -0
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/target.js +219 -0
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js +86 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/error.js +18 -0
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js +162 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/paths.js +40 -0
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/read.js +49 -0
- package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
- package/dist/commands/migrate-openspec/print.js +89 -0
- package/dist/commands/migrate-openspec/print.js.map +1 -0
- package/dist/commands/new/capability-template.js +118 -0
- package/dist/commands/new/capability-template.js.map +1 -0
- package/dist/commands/new/commit.js +62 -0
- package/dist/commands/new/commit.js.map +1 -0
- package/dist/commands/new/modifies.js +206 -0
- package/dist/commands/new/modifies.js.map +1 -0
- package/dist/commands/new/new.js +328 -0
- package/dist/commands/new/new.js.map +1 -0
- package/dist/commands/new/templates.js +279 -0
- package/dist/commands/new/templates.js.map +1 -0
- package/dist/commands/open.js +199 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/policy/format.js +152 -0
- package/dist/commands/policy/format.js.map +1 -0
- package/dist/commands/{docs-repo-gate.js → policy/gate.js} +38 -11
- package/dist/commands/policy/gate.js.map +1 -0
- package/dist/commands/rebase/edit.js +106 -0
- package/dist/commands/rebase/edit.js.map +1 -0
- package/dist/commands/rebase/living.js +185 -0
- package/dist/commands/rebase/living.js.map +1 -0
- package/dist/commands/rebase/plan.js +245 -0
- package/dist/commands/rebase/plan.js.map +1 -0
- package/dist/commands/rebase/rebase.js +300 -0
- package/dist/commands/rebase/rebase.js.map +1 -0
- package/dist/commands/seed/commit.js +221 -0
- package/dist/commands/seed/commit.js.map +1 -0
- package/dist/commands/seed/plan.js +278 -0
- package/dist/commands/seed/plan.js.map +1 -0
- package/dist/commands/seed/seed.js +174 -0
- package/dist/commands/seed/seed.js.map +1 -0
- package/dist/commands/show/feature.js +182 -0
- package/dist/commands/show/feature.js.map +1 -0
- package/dist/commands/show/introduced.js +157 -0
- package/dist/commands/show/introduced.js.map +1 -0
- package/dist/commands/show/marks.js +53 -0
- package/dist/commands/show/marks.js.map +1 -0
- package/dist/commands/show/service.js +239 -0
- package/dist/commands/show/service.js.map +1 -0
- package/dist/commands/show/show.js +87 -0
- package/dist/commands/show/show.js.map +1 -0
- package/dist/commands/status/fleet-next.js +90 -0
- package/dist/commands/status/fleet-next.js.map +1 -0
- package/dist/commands/status/json.js +47 -0
- package/dist/commands/status/json.js.map +1 -0
- package/dist/commands/status/print.js +209 -0
- package/dist/commands/status/print.js.map +1 -0
- package/dist/commands/status/status.js +115 -0
- package/dist/commands/status/status.js.map +1 -0
- package/dist/commands/steps/steps.js +269 -0
- package/dist/commands/steps/steps.js.map +1 -0
- package/dist/commands/subsystem/edit.js +192 -0
- package/dist/commands/subsystem/edit.js.map +1 -0
- package/dist/commands/subsystem/move.js +325 -0
- package/dist/commands/subsystem/move.js.map +1 -0
- package/dist/commands/subsystem/query.js +113 -0
- package/dist/commands/subsystem/query.js.map +1 -0
- package/dist/commands/subsystem/subsystem.js +98 -0
- package/dist/commands/subsystem/subsystem.js.map +1 -0
- package/dist/commands/subsystem/sync.js +318 -0
- package/dist/commands/subsystem/sync.js.map +1 -0
- package/dist/commands/subsystem/txn/exclude.js +132 -0
- package/dist/commands/subsystem/txn/exclude.js.map +1 -0
- package/dist/commands/subsystem/txn/links.js +128 -0
- package/dist/commands/subsystem/txn/links.js.map +1 -0
- package/dist/commands/subsystem/txn/report.js +174 -0
- package/dist/commands/subsystem/txn/report.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +196 -0
- package/dist/commands/subsystem/txn/txn.js.map +1 -0
- package/dist/commands/subsystem/txn/views.js +249 -0
- package/dist/commands/subsystem/txn/views.js.map +1 -0
- package/dist/commands/tasks/actions.js +107 -0
- package/dist/commands/tasks/actions.js.map +1 -0
- package/dist/commands/tasks/render.js +253 -0
- package/dist/commands/tasks/render.js.map +1 -0
- package/dist/commands/tasks/tasks.js +119 -0
- package/dist/commands/tasks/tasks.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +176 -0
- package/dist/commands/unarchive/manifest.js.map +1 -0
- package/dist/commands/unarchive/restore.js +254 -0
- package/dist/commands/unarchive/restore.js.map +1 -0
- package/dist/commands/unarchive/unarchive.js +59 -0
- package/dist/commands/unarchive/unarchive.js.map +1 -0
- package/dist/commands/validate/arch-coverage.js +245 -0
- package/dist/commands/validate/arch-coverage.js.map +1 -0
- package/dist/commands/validate/checks/fleet-shape.js +204 -0
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
- package/dist/commands/validate/checks/health-deps.js +58 -0
- package/dist/commands/validate/checks/health-deps.js.map +1 -0
- package/dist/commands/validate/checks/introduced.js +102 -0
- package/dist/commands/validate/checks/introduced.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +264 -0
- package/dist/commands/validate/checks/requirements.js.map +1 -0
- package/dist/commands/validate/checks/sources.js +85 -0
- package/dist/commands/validate/checks/sources.js.map +1 -0
- package/dist/commands/validate/coverage/covers-after.js +105 -0
- package/dist/commands/validate/coverage/covers-after.js.map +1 -0
- package/dist/commands/validate/feature.js +222 -0
- package/dist/commands/validate/feature.js.map +1 -0
- package/dist/commands/validate/fleet/census.js +93 -0
- package/dist/commands/validate/fleet/census.js.map +1 -0
- package/dist/commands/validate/fleet/kind-tags.js +39 -0
- package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
- package/dist/commands/validate/fleet/landscape.js +371 -0
- package/dist/commands/validate/fleet/landscape.js.map +1 -0
- package/dist/commands/validate/fleet/load.js +118 -0
- package/dist/commands/validate/fleet/load.js.map +1 -0
- package/dist/commands/validate/fleet/map/attest.js +98 -0
- package/dist/commands/validate/fleet/map/attest.js.map +1 -0
- package/dist/commands/validate/fleet/map/bindings.js +107 -0
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
- package/dist/commands/validate/fleet/map/consumers.js +244 -0
- package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
- package/dist/commands/validate/fleet/map/isolation.js +116 -0
- package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
- package/dist/commands/validate/fleet/map/usecases.js +54 -0
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +266 -0
- package/dist/commands/validate/fleet/obligations.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/print.js +71 -0
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js +162 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/place.js +13 -0
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
- package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +75 -0
- package/dist/commands/validate/fleet/views/ids.js.map +1 -0
- package/dist/commands/validate/fleet/views/projects.js +278 -0
- package/dist/commands/validate/fleet/views/projects.js.map +1 -0
- package/dist/commands/validate/fleet/views/root-documents.js +83 -0
- package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +52 -0
- package/dist/commands/validate/fleet/views/stale.js.map +1 -0
- package/dist/commands/validate/links/corpus.js +89 -0
- package/dist/commands/validate/links/corpus.js.map +1 -0
- package/dist/commands/validate/links/glossary.js +75 -0
- package/dist/commands/validate/links/glossary.js.map +1 -0
- package/dist/commands/validate/render/repeats.js +63 -0
- package/dist/commands/validate/render/repeats.js.map +1 -0
- package/dist/commands/validate/render/rollups.js +115 -0
- package/dist/commands/validate/render/rollups.js.map +1 -0
- package/dist/commands/validate/render/text.js +199 -0
- package/dist/commands/validate/render/text.js.map +1 -0
- package/dist/commands/validate/report.js +145 -0
- package/dist/commands/validate/report.js.map +1 -0
- package/dist/commands/validate/scope.js +113 -0
- package/dist/commands/validate/scope.js.map +1 -0
- package/dist/commands/validate/service/api.js +252 -0
- package/dist/commands/validate/service/api.js.map +1 -0
- package/dist/commands/validate/service/contracts/generated.js +134 -0
- package/dist/commands/validate/service/contracts/generated.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +241 -0
- package/dist/commands/validate/service/events/events.js.map +1 -0
- package/dist/commands/validate/service/events/message-producers.js +77 -0
- package/dist/commands/validate/service/events/message-producers.js.map +1 -0
- package/dist/commands/validate/service/evidence-pins.js +177 -0
- package/dist/commands/validate/service/evidence-pins.js.map +1 -0
- package/dist/commands/validate/service/model/diverged.js +226 -0
- package/dist/commands/validate/service/model/diverged.js.map +1 -0
- package/dist/commands/validate/service/model/grade.js +163 -0
- package/dist/commands/validate/service/model/grade.js.map +1 -0
- package/dist/commands/validate/service/service.js +310 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +279 -0
- package/dist/commands/validate/service/specs.js.map +1 -0
- package/dist/commands/validate/service/spine.js +148 -0
- package/dist/commands/validate/service/spine.js.map +1 -0
- package/dist/commands/validate/service/usecases/tags.js +113 -0
- package/dist/commands/validate/service/usecases/tags.js.map +1 -0
- package/dist/commands/validate/service/usecases/usecases.js +209 -0
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/validate.js +363 -0
- package/dist/commands/validate/validate.js.map +1 -0
- package/dist/commands/verify/cross/diff.js +178 -0
- package/dist/commands/verify/cross/diff.js.map +1 -0
- package/dist/commands/verify/evidence/contract.js +32 -0
- package/dist/commands/verify/evidence/contract.js.map +1 -0
- package/dist/commands/verify/evidence/pins.js +52 -0
- package/dist/commands/verify/evidence/pins.js.map +1 -0
- package/dist/commands/verify/evidence/read.js +81 -0
- package/dist/commands/verify/evidence/read.js.map +1 -0
- package/dist/commands/verify/frozen.js +263 -0
- package/dist/commands/verify/frozen.js.map +1 -0
- package/dist/commands/verify/record.js +278 -0
- package/dist/commands/verify/record.js.map +1 -0
- package/dist/commands/verify/report.js +206 -0
- package/dist/commands/verify/report.js.map +1 -0
- package/dist/commands/verify/results.js +328 -0
- package/dist/commands/verify/results.js.map +1 -0
- package/dist/commands/verify/verify.js +220 -0
- package/dist/commands/verify/verify.js.map +1 -0
- package/dist/commands/vouch/contract.js +11 -0
- package/dist/commands/vouch/contract.js.map +1 -0
- package/dist/commands/vouch/pack/contract.js +2 -0
- package/dist/commands/vouch/pack/contract.js.map +1 -0
- package/dist/commands/vouch/pack/pack.js +266 -0
- package/dist/commands/vouch/pack/pack.js.map +1 -0
- package/dist/commands/vouch/pack/print.js +266 -0
- package/dist/commands/vouch/pack/print.js.map +1 -0
- package/dist/commands/vouch/pack/sections.js +141 -0
- package/dist/commands/vouch/pack/sections.js.map +1 -0
- package/dist/commands/vouch/prompt/confirm.js +46 -0
- package/dist/commands/vouch/prompt/confirm.js.map +1 -0
- package/dist/commands/vouch/report.js +101 -0
- package/dist/commands/vouch/report.js.map +1 -0
- package/dist/commands/vouch/run.js +230 -0
- package/dist/commands/vouch/run.js.map +1 -0
- package/dist/commands/vouch/sample/plan.js +111 -0
- package/dist/commands/vouch/sample/plan.js.map +1 -0
- package/dist/commands/vouch/sample/print.js +109 -0
- package/dist/commands/vouch/sample/print.js.map +1 -0
- package/dist/commands/vouch/vet/verify.js +155 -0
- package/dist/commands/vouch/vet/verify.js.map +1 -0
- package/dist/commands/vouch/vouch.js +169 -0
- package/dist/commands/vouch/vouch.js.map +1 -0
- package/dist/core/agent/agents-md/command-map.js +299 -0
- package/dist/core/agent/agents-md/command-map.js.map +1 -0
- package/dist/core/agent/agents-md/map/explain.js +46 -0
- package/dist/core/agent/agents-md/map/explain.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/context.js +50 -0
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js +59 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js +65 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
- package/dist/core/agent/agents-md/map/mcp.js +44 -0
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
- package/dist/core/agent/agents-md/map/status.js +78 -0
- package/dist/core/agent/agents-md/map/status.js.map +1 -0
- package/dist/core/agent/agents-md/map/subsystem.js +104 -0
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
- package/dist/core/agent/agents-md/map/usecases.js +138 -0
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
- package/dist/core/agent/agents-md/refusals.js +273 -0
- package/dist/core/agent/agents-md/refusals.js.map +1 -0
- package/dist/core/agent/agents-md.js +203 -0
- package/dist/core/agent/agents-md.js.map +1 -0
- package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +60 -0
- package/dist/core/agent/agents-stamp.js.map +1 -0
- package/dist/core/agent/contract.js +2 -0
- package/dist/core/agent/contract.js.map +1 -0
- package/dist/core/agent/protocol.js +193 -0
- package/dist/core/agent/protocol.js.map +1 -0
- package/dist/core/agent/scaffold.js +254 -0
- package/dist/core/agent/scaffold.js.map +1 -0
- package/dist/core/agent/support/report.js +144 -0
- package/dist/core/agent/support/report.js.map +1 -0
- package/dist/core/agent/tools/dialects.js +151 -0
- package/dist/core/agent/tools/dialects.js.map +1 -0
- package/dist/core/agent/tools/registry.js +193 -0
- package/dist/core/agent/tools/registry.js.map +1 -0
- package/dist/core/agent/workflows/adopt.js +280 -0
- package/dist/core/agent/workflows/adopt.js.map +1 -0
- package/dist/core/agent/workflows/check.js +373 -0
- package/dist/core/agent/workflows/check.js.map +1 -0
- package/dist/core/agent/workflows/closing.js +323 -0
- package/dist/core/agent/workflows/closing.js.map +1 -0
- package/dist/core/agent/workflows/feature.js +220 -0
- package/dist/core/agent/workflows/feature.js.map +1 -0
- package/dist/core/agent/workflows/implement.js +188 -0
- package/dist/core/agent/workflows/implement.js.map +1 -0
- package/dist/core/agent/workflows/reference/authoring.js +311 -0
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
- package/dist/core/agent/workflows/reference/codes.js +67 -0
- package/dist/core/agent/workflows/reference/codes.js.map +1 -0
- package/dist/core/agent/workflows/reference/done-check.js +210 -0
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +19 -0
- package/dist/core/agent/workflows/reference/reference.js.map +1 -0
- package/dist/core/agent/workflows/reference/spine.js +338 -0
- package/dist/core/agent/workflows/reference/spine.js.map +1 -0
- package/dist/core/asyncapi/baseline/plan.js +43 -0
- package/dist/core/asyncapi/baseline/plan.js.map +1 -0
- package/dist/core/asyncapi/baseline/surfaces.js +54 -0
- package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
- package/dist/core/asyncapi/depth.js +164 -0
- package/dist/core/asyncapi/depth.js.map +1 -0
- package/dist/core/asyncapi/digest.js +146 -0
- package/dist/core/asyncapi/digest.js.map +1 -0
- package/dist/core/asyncapi/merge/components.js +92 -0
- package/dist/core/asyncapi/merge/components.js.map +1 -0
- package/dist/core/asyncapi/merge/error.js +38 -0
- package/dist/core/asyncapi/merge/error.js.map +1 -0
- package/dist/core/asyncapi/merge/markers.js +290 -0
- package/dist/core/asyncapi/merge/markers.js.map +1 -0
- package/dist/core/asyncapi/merge/merge.js +195 -0
- package/dist/core/asyncapi/merge/merge.js.map +1 -0
- package/dist/core/asyncapi/merge/pin.js +83 -0
- package/dist/core/asyncapi/merge/pin.js.map +1 -0
- package/dist/core/asyncapi/model.js +11 -0
- package/dist/core/asyncapi/model.js.map +1 -0
- package/dist/core/asyncapi/producers.js +50 -0
- package/dist/core/asyncapi/producers.js.map +1 -0
- package/dist/core/asyncapi/read.js +263 -0
- package/dist/core/asyncapi/read.js.map +1 -0
- package/dist/core/brief/brief.js +285 -0
- package/dist/core/brief/brief.js.map +1 -0
- package/dist/core/brief/checks.js +385 -0
- package/dist/core/brief/checks.js.map +1 -0
- package/dist/core/brief/landscape.js +273 -0
- package/dist/core/brief/landscape.js.map +1 -0
- package/dist/core/brief/map/extend.js +84 -0
- package/dist/core/brief/map/extend.js.map +1 -0
- package/dist/core/brief/map/owed.js +266 -0
- package/dist/core/brief/map/owed.js.map +1 -0
- package/dist/core/brief/targets.js +304 -0
- package/dist/core/brief/targets.js.map +1 -0
- package/dist/core/brief/unchecked.js +58 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +190 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/direction/direction.js +114 -0
- package/dist/core/c4/direction/direction.js.map +1 -0
- package/dist/core/c4/likec4.js +243 -0
- package/dist/core/c4/likec4.js.map +1 -0
- package/dist/core/c4/locate/unlocated.js +150 -0
- package/dist/core/c4/locate/unlocated.js.map +1 -0
- package/dist/core/c4/parsed/deployment.js +160 -0
- package/dist/core/c4/parsed/deployment.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js +132 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
- package/dist/core/c4/parsed/specification.js +78 -0
- package/dist/core/c4/parsed/specification.js.map +1 -0
- package/dist/core/c4/parsed/values.js +110 -0
- package/dist/core/c4/parsed/values.js.map +1 -0
- package/dist/core/c4/parsed/view-ids.js +113 -0
- package/dist/core/c4/parsed/view-ids.js.map +1 -0
- package/dist/core/c4/prefetch/fleet.js +134 -0
- package/dist/core/c4/prefetch/fleet.js.map +1 -0
- package/dist/core/c4/project/architecture.js +161 -0
- package/dist/core/c4/project/architecture.js.map +1 -0
- package/dist/core/c4/project/batch.js +140 -0
- package/dist/core/c4/project/batch.js.map +1 -0
- package/dist/core/c4/project/documents.js +89 -0
- package/dist/core/c4/project/documents.js.map +1 -0
- package/dist/core/c4/project/load.js +219 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/project/staged.js +277 -0
- package/dist/core/c4/project/staged.js.map +1 -0
- package/dist/core/c4/resolve/attested.js +0 -0
- package/dist/core/c4/resolve/attested.js.map +1 -0
- package/dist/core/c4/resolve/external.js +51 -0
- package/dist/core/c4/resolve/external.js.map +1 -0
- package/dist/core/c4/resolve/service.js +174 -0
- package/dist/core/c4/resolve/service.js.map +1 -0
- package/dist/core/c4/resolve/steps.js +290 -0
- package/dist/core/c4/resolve/steps.js.map +1 -0
- package/dist/core/c4/resolve/systems.js +154 -0
- package/dist/core/c4/resolve/systems.js.map +1 -0
- package/dist/core/c4/root-project/exclude.js +352 -0
- package/dist/core/c4/root-project/exclude.js.map +1 -0
- package/dist/core/c4/seed/fleet-file.js +201 -0
- package/dist/core/c4/seed/fleet-file.js.map +1 -0
- package/dist/core/c4/seed/items.js +91 -0
- package/dist/core/c4/seed/items.js.map +1 -0
- package/dist/core/c4/seed/stamp.js +48 -0
- package/dist/core/c4/seed/stamp.js.map +1 -0
- package/dist/core/c4/seed/template.js +173 -0
- package/dist/core/c4/seed/template.js.map +1 -0
- package/dist/core/c4/service-model/created/models.js +96 -0
- package/dist/core/c4/service-model/created/models.js.map +1 -0
- package/dist/core/c4/service-model/documents.js +47 -0
- package/dist/core/c4/service-model/documents.js.map +1 -0
- package/dist/core/c4/service-model/fleet/extending.js +82 -0
- package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
- package/dist/core/c4/service-model/load.js +165 -0
- package/dist/core/c4/service-model/load.js.map +1 -0
- package/dist/core/c4/service-model/renderer.js +128 -0
- package/dist/core/c4/service-model/renderer.js.map +1 -0
- package/dist/core/c4/service-model/shape.js +106 -0
- package/dist/core/c4/service-model/shape.js.map +1 -0
- package/dist/core/c4/service-model/slice.js +188 -0
- package/dist/core/c4/service-model/slice.js.map +1 -0
- package/dist/core/c4/source-mask.js +369 -0
- package/dist/core/c4/source-mask.js.map +1 -0
- package/dist/core/c4/source-scan.js +308 -0
- package/dist/core/c4/source-scan.js.map +1 -0
- package/dist/core/c4/splice/authored-source.js +167 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -0
- package/dist/core/c4/splice/contract.js +30 -0
- package/dist/core/c4/splice/contract.js.map +1 -0
- package/dist/core/c4/splice/delta-blocks.js +126 -0
- package/dist/core/c4/splice/delta-blocks.js.map +1 -0
- package/dist/core/c4/splice/identity/declared.js +87 -0
- package/dist/core/c4/splice/identity/declared.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +73 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -0
- package/dist/core/c4/splice/identity/existing.js +80 -0
- package/dist/core/c4/splice/identity/existing.js.map +1 -0
- package/dist/core/c4/splice/identity/interior.js +80 -0
- package/dist/core/c4/splice/identity/interior.js.map +1 -0
- package/dist/core/c4/splice/identity/owner.js +50 -0
- package/dist/core/c4/splice/identity/owner.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +337 -0
- package/dist/core/c4/splice/landscape-merge.js.map +1 -0
- package/dist/core/c4/splice/model/merge.js +151 -0
- package/dist/core/c4/splice/model/merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +298 -0
- package/dist/core/c4/splice/placement.js.map +1 -0
- package/dist/core/c4/splice/text/spot.js +131 -0
- package/dist/core/c4/splice/text/spot.js.map +1 -0
- package/dist/core/c4/workspace.js +166 -0
- package/dist/core/c4/workspace.js.map +1 -0
- package/dist/core/capabilities/authoring/notes.js +141 -0
- package/dist/core/capabilities/authoring/notes.js.map +1 -0
- package/dist/core/capabilities/capabilities.js +124 -0
- package/dist/core/capabilities/capabilities.js.map +1 -0
- package/dist/core/capabilities/delta/doc.js +47 -0
- package/dist/core/capabilities/delta/doc.js.map +1 -0
- package/dist/core/capabilities/delta/overlay.js +129 -0
- package/dist/core/capabilities/delta/overlay.js.map +1 -0
- package/dist/core/capabilities/delta/summary.js +57 -0
- package/dist/core/capabilities/delta/summary.js.map +1 -0
- package/dist/core/capabilities/delta/tree.js +43 -0
- package/dist/core/capabilities/delta/tree.js.map +1 -0
- package/dist/core/capabilities/delta/uncovered.js +222 -0
- package/dist/core/capabilities/delta/uncovered.js.map +1 -0
- package/dist/core/capabilities/findings.js +338 -0
- package/dist/core/capabilities/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/findings.js +174 -0
- package/dist/core/capabilities/realizes/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/join.js +123 -0
- package/dist/core/capabilities/realizes/join.js.map +1 -0
- package/dist/core/capabilities/rollup.js +205 -0
- package/dist/core/capabilities/rollup.js.map +1 -0
- package/dist/core/capabilities/tree.js +104 -0
- package/dist/core/capabilities/tree.js.map +1 -0
- package/dist/core/capabilities/usecase-join.js +267 -0
- package/dist/core/capabilities/usecase-join.js.map +1 -0
- package/dist/core/coherence/authoring/scaffold.js +185 -0
- package/dist/core/coherence/authoring/scaffold.js.map +1 -0
- package/dist/core/coherence/authoring/sentinels.js +75 -0
- package/dist/core/coherence/authoring/sentinels.js.map +1 -0
- package/dist/core/coherence/calls/called.js +52 -0
- package/dist/core/coherence/calls/called.js.map +1 -0
- package/dist/core/coherence/coherence.js +332 -0
- package/dist/core/coherence/coherence.js.map +1 -0
- package/dist/core/coherence/consumed/operations.js +70 -0
- package/dist/core/coherence/consumed/operations.js.map +1 -0
- package/dist/core/coherence/consumed/refusal.js +38 -0
- package/dist/core/coherence/consumed/refusal.js.map +1 -0
- package/dist/core/coherence/covers/health.js +85 -0
- package/dist/core/coherence/covers/health.js.map +1 -0
- package/dist/core/coherence/declared.js +295 -0
- package/dist/core/coherence/declared.js.map +1 -0
- package/dist/core/coherence/events/declared.js +191 -0
- package/dist/core/coherence/events/declared.js.map +1 -0
- package/dist/core/coherence/events/events.js +335 -0
- package/dist/core/coherence/events/events.js.map +1 -0
- package/dist/core/coherence/events/grades.js +189 -0
- package/dist/core/coherence/events/grades.js.map +1 -0
- package/dist/core/coherence/events/lookups.js +63 -0
- package/dist/core/coherence/events/lookups.js.map +1 -0
- package/dist/core/coherence/events/produced.js +100 -0
- package/dist/core/coherence/events/produced.js.map +1 -0
- package/dist/core/coherence/living.js +198 -0
- package/dist/core/coherence/living.js.map +1 -0
- package/dist/core/coherence/lookups.js +95 -0
- package/dist/core/coherence/lookups.js.map +1 -0
- package/dist/core/coherence/pending.js +39 -0
- package/dist/core/coherence/pending.js.map +1 -0
- package/dist/core/coherence/retired/archived.js +285 -0
- package/dist/core/coherence/retired/archived.js.map +1 -0
- package/dist/core/coherence/retired/event-pair.js +62 -0
- package/dist/core/coherence/retired/event-pair.js.map +1 -0
- package/dist/core/coherence/retired/merged.js +79 -0
- package/dist/core/coherence/retired/merged.js.map +1 -0
- package/dist/core/coherence/retired/retirement.js +49 -0
- package/dist/core/coherence/retired/retirement.js.map +1 -0
- package/dist/core/coherence/retired/revival/arrivals.js +131 -0
- package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
- package/dist/core/coherence/retired/revival/revived.js +297 -0
- package/dist/core/coherence/retired/revival/revived.js.map +1 -0
- package/dist/core/conflict-markers.js +60 -0
- package/dist/core/conflict-markers.js.map +1 -0
- package/dist/core/consumers/after.js +113 -0
- package/dist/core/consumers/after.js.map +1 -0
- package/dist/core/consumers/consumers.js +296 -0
- package/dist/core/consumers/consumers.js.map +1 -0
- package/dist/core/consumers/current.js +211 -0
- package/dist/core/consumers/current.js.map +1 -0
- package/dist/core/consumers/scan.js +46 -0
- package/dist/core/consumers/scan.js.map +1 -0
- package/dist/core/consumers/state.js +27 -0
- package/dist/core/consumers/state.js.map +1 -0
- package/dist/core/delta/claims.js +73 -0
- package/dist/core/delta/claims.js.map +1 -0
- package/dist/core/delta/delta.js +341 -0
- package/dist/core/delta/delta.js.map +1 -0
- package/dist/core/delta/document.js +177 -0
- package/dist/core/delta/document.js.map +1 -0
- package/dist/core/delta/scope.js +48 -0
- package/dist/core/delta/scope.js.map +1 -0
- package/dist/core/delta/select.js +237 -0
- package/dist/core/delta/select.js.map +1 -0
- package/dist/core/dependencies/dependencies.js +141 -0
- package/dist/core/dependencies/dependencies.js.map +1 -0
- package/dist/core/dependencies/facts.js +165 -0
- package/dist/core/dependencies/facts.js.map +1 -0
- package/dist/core/dependencies/fanin.js +88 -0
- package/dist/core/dependencies/fanin.js.map +1 -0
- package/dist/core/dependencies/graph.js +106 -0
- package/dist/core/dependencies/graph.js.map +1 -0
- package/dist/core/deployment/delta.js +191 -0
- package/dist/core/deployment/delta.js.map +1 -0
- package/dist/core/deployment/objects.js +145 -0
- package/dist/core/deployment/objects.js.map +1 -0
- package/dist/core/diff/base-git.js +230 -0
- package/dist/core/diff/base-git.js.map +1 -0
- package/dist/core/diff/base-state.js +237 -0
- package/dist/core/diff/base-state.js.map +1 -0
- package/dist/core/diff/joins.js +136 -0
- package/dist/core/diff/joins.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +204 -0
- package/dist/core/diff/scope/changed-paths.js.map +1 -0
- package/dist/core/diff/scope/edges.js +82 -0
- package/dist/core/diff/scope/edges.js.map +1 -0
- package/dist/core/diff/semantic.js +312 -0
- package/dist/core/diff/semantic.js.map +1 -0
- package/dist/core/docs.js +37 -85
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +238 -0
- package/dist/core/doctor/agents.js.map +1 -0
- package/dist/core/doctor/config.js +139 -0
- package/dist/core/doctor/config.js.map +1 -0
- package/dist/core/doctor/doctor.js +355 -0
- package/dist/core/doctor/doctor.js.map +1 -0
- package/dist/core/doctor/report.js +13 -0
- package/dist/core/doctor/report.js.map +1 -0
- package/dist/core/doctor/reports/scan.js +242 -0
- package/dist/core/doctor/reports/scan.js.map +1 -0
- package/dist/core/doctor/residue.js +110 -0
- package/dist/core/doctor/residue.js.map +1 -0
- package/dist/core/document/apply.js +224 -0
- package/dist/core/document/apply.js.map +1 -0
- package/dist/core/{frontmatter.js → document/frontmatter.js} +103 -2
- package/dist/core/document/frontmatter.js.map +1 -0
- package/dist/core/document/grammar/directives.js +143 -0
- package/dist/core/document/grammar/directives.js.map +1 -0
- package/dist/core/document/parse.js +286 -0
- package/dist/core/document/parse.js.map +1 -0
- package/dist/core/document/scenarios.js +238 -0
- package/dist/core/document/scenarios.js.map +1 -0
- package/dist/core/document/spec.js +234 -0
- package/dist/core/document/spec.js.map +1 -0
- package/dist/core/{config.js → envelope/config.js} +89 -18
- package/dist/core/envelope/config.js.map +1 -0
- package/dist/core/envelope/json.js +209 -0
- package/dist/core/envelope/json.js.map +1 -0
- package/dist/core/{version.js → envelope/version.js} +3 -3
- package/dist/core/envelope/version.js.map +1 -0
- package/dist/core/explain/families.js +180 -0
- package/dist/core/explain/families.js.map +1 -0
- package/dist/core/explain/fix-tables.js +178 -0
- package/dist/core/explain/fix-tables.js.map +1 -0
- package/dist/core/explain/lookup.js +194 -0
- package/dist/core/explain/lookup.js.map +1 -0
- package/dist/core/explain/refusals.js +49 -0
- package/dist/core/explain/refusals.js.map +1 -0
- package/dist/core/explain/terms/documents.js +227 -0
- package/dist/core/explain/terms/documents.js.map +1 -0
- package/dist/core/explain/terms/done-check.js +144 -0
- package/dist/core/explain/terms/done-check.js.map +1 -0
- package/dist/core/explain/terms/entry.js +14 -0
- package/dist/core/explain/terms/entry.js.map +1 -0
- package/dist/core/explain/terms/stages.js +71 -0
- package/dist/core/explain/terms/stages.js.map +1 -0
- package/dist/core/explain/terms/tasks.js +97 -0
- package/dist/core/explain/terms/tasks.js.map +1 -0
- package/dist/core/explain/terms.js +103 -0
- package/dist/core/explain/terms.js.map +1 -0
- package/dist/core/explore/describe.js +105 -0
- package/dist/core/explore/describe.js.map +1 -0
- package/dist/core/explore/explore.js +204 -0
- package/dist/core/explore/explore.js.map +1 -0
- package/dist/core/fleet-context.js +174 -146
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +208 -0
- package/dist/core/gate/checks.js.map +1 -0
- package/dist/core/gate/partners.js +246 -0
- package/dist/core/gate/partners.js.map +1 -0
- package/dist/core/gate/report.js +47 -0
- package/dist/core/gate/report.js.map +1 -0
- package/dist/core/gate/verification.js +176 -0
- package/dist/core/gate/verification.js.map +1 -0
- package/dist/core/gherkin/digest.js +60 -0
- package/dist/core/gherkin/digest.js.map +1 -0
- package/dist/core/gherkin/emit.js +177 -0
- package/dist/core/gherkin/emit.js.map +1 -0
- package/dist/core/gherkin/read.js +76 -0
- package/dist/core/gherkin/read.js.map +1 -0
- package/dist/core/gherkin/stale.js +210 -0
- package/dist/core/gherkin/stale.js.map +1 -0
- package/dist/core/gherkin/stamp.js +77 -0
- package/dist/core/gherkin/stamp.js.map +1 -0
- package/dist/core/gherkin/steps/catalogue.js +154 -0
- package/dist/core/gherkin/steps/catalogue.js.map +1 -0
- package/dist/core/gherkin/steps/inventory.js +98 -0
- package/dist/core/gherkin/steps/inventory.js.map +1 -0
- package/dist/core/gherkin/steps/phrase.js +72 -0
- package/dist/core/gherkin/steps/phrase.js.map +1 -0
- package/dist/core/glossary/delta.js +109 -0
- package/dist/core/glossary/delta.js.map +1 -0
- package/dist/core/glossary/tree.js +73 -0
- package/dist/core/glossary/tree.js.map +1 -0
- package/dist/core/{concurrency.js → kernel/concurrency.js} +19 -0
- package/dist/core/kernel/concurrency.js.map +1 -0
- package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
- package/dist/core/kernel/document-bytes.js.map +1 -0
- package/dist/core/kernel/fences.js +42 -0
- package/dist/core/kernel/fences.js.map +1 -0
- package/dist/core/kernel/ids/capability.js +72 -0
- package/dist/core/kernel/ids/capability.js.map +1 -0
- package/dist/core/kernel/ids/dirs.js +33 -0
- package/dist/core/kernel/ids/dirs.js.map +1 -0
- package/dist/core/kernel/ids/feature.js +75 -0
- package/dist/core/kernel/ids/feature.js.map +1 -0
- package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
- package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
- package/dist/core/kernel/ids/service.js +156 -0
- package/dist/core/kernel/ids/service.js.map +1 -0
- package/dist/core/kernel/ids/subsystem.js +63 -0
- package/dist/core/kernel/ids/subsystem.js.map +1 -0
- package/dist/core/{path-safety.js → kernel/path-safety.js} +56 -4
- package/dist/core/kernel/path-safety.js.map +1 -0
- package/dist/core/{records.js → kernel/records.js} +11 -0
- package/dist/core/kernel/records.js.map +1 -0
- package/dist/core/links/backlinks.js +66 -0
- package/dist/core/links/backlinks.js.map +1 -0
- package/dist/core/links/case.js +74 -0
- package/dist/core/links/case.js.map +1 -0
- package/dist/core/links/corpus.js +118 -0
- package/dist/core/links/corpus.js.map +1 -0
- package/dist/core/links/findings.js +110 -0
- package/dist/core/links/findings.js.map +1 -0
- package/dist/core/links/parse.js +265 -0
- package/dist/core/links/parse.js.map +1 -0
- package/dist/core/mcp/argv.js +212 -0
- package/dist/core/mcp/argv.js.map +1 -0
- package/dist/core/mcp/author-tools.js +73 -0
- package/dist/core/mcp/author-tools.js.map +1 -0
- package/dist/core/mcp/framing.js +46 -0
- package/dist/core/mcp/framing.js.map +1 -0
- package/dist/core/mcp/protocol.js +280 -0
- package/dist/core/mcp/protocol.js.map +1 -0
- package/dist/core/mcp/tools.js +324 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/obligations/obligations.js +106 -0
- package/dist/core/obligations/obligations.js.map +1 -0
- package/dist/core/openapi/baseline/gate.js +207 -0
- package/dist/core/openapi/baseline/gate.js.map +1 -0
- package/dist/core/openapi/baseline/plan.js +142 -0
- package/dist/core/openapi/baseline/plan.js.map +1 -0
- package/dist/core/openapi/baseline/record.js +174 -0
- package/dist/core/openapi/baseline/record.js.map +1 -0
- package/dist/core/openapi/contract-text.js +33 -0
- package/dist/core/openapi/contract-text.js.map +1 -0
- package/dist/core/openapi/contract-tree.js +301 -0
- package/dist/core/openapi/contract-tree.js.map +1 -0
- package/dist/core/openapi/depth.js +136 -0
- package/dist/core/openapi/depth.js.map +1 -0
- package/dist/core/openapi/digest.js +239 -0
- package/dist/core/openapi/digest.js.map +1 -0
- package/dist/core/{openapi.js → openapi/doc.js} +54 -108
- package/dist/core/openapi/doc.js.map +1 -0
- package/dist/core/openapi/merge/components.js +199 -0
- package/dist/core/openapi/merge/components.js.map +1 -0
- package/dist/core/openapi/merge/error.js +16 -0
- package/dist/core/openapi/merge/error.js.map +1 -0
- package/dist/core/openapi/merge/markers.js +204 -0
- package/dist/core/openapi/merge/markers.js.map +1 -0
- package/dist/core/openapi/merge/merge.js +232 -0
- package/dist/core/openapi/merge/merge.js.map +1 -0
- package/dist/core/openapi/merge/pin.js +110 -0
- package/dist/core/openapi/merge/pin.js.map +1 -0
- package/dist/core/openspec/decide/capabilities.js +244 -0
- package/dist/core/openspec/decide/capabilities.js.map +1 -0
- package/dist/core/openspec/decide/dispositions.js +63 -0
- package/dist/core/openspec/decide/dispositions.js.map +1 -0
- package/dist/core/openspec/decide/renames.js +179 -0
- package/dist/core/openspec/decide/renames.js.map +1 -0
- package/dist/core/openspec/decide/verdict.js +84 -0
- package/dist/core/openspec/decide/verdict.js.map +1 -0
- package/dist/core/openspec/inventory.js +220 -0
- package/dist/core/openspec/inventory.js.map +1 -0
- package/dist/core/openspec/model/mapping.js +78 -0
- package/dist/core/openspec/model/mapping.js.map +1 -0
- package/dist/core/openspec/model/model.js +70 -0
- package/dist/core/openspec/model/model.js.map +1 -0
- package/dist/core/openspec/scan/changes.js +241 -0
- package/dist/core/openspec/scan/changes.js.map +1 -0
- package/dist/core/openspec/scan/config.js +191 -0
- package/dist/core/openspec/scan/config.js.map +1 -0
- package/dist/core/openspec/scan/shape.js +304 -0
- package/dist/core/openspec/scan/shape.js.map +1 -0
- package/dist/core/openspec/scan/walk.js +116 -0
- package/dist/core/openspec/scan/walk.js.map +1 -0
- package/dist/core/openspec/scan/workspace.js +71 -0
- package/dist/core/openspec/scan/workspace.js.map +1 -0
- package/dist/core/owners/codeowners.js +141 -0
- package/dist/core/owners/codeowners.js.map +1 -0
- package/dist/core/pack/features.js +120 -0
- package/dist/core/pack/features.js.map +1 -0
- package/dist/core/pack/joins.js +112 -0
- package/dist/core/pack/joins.js.map +1 -0
- package/dist/core/pack/living.js +157 -0
- package/dist/core/pack/living.js.map +1 -0
- package/dist/core/pack/pack.js +120 -0
- package/dist/core/pack/pack.js.map +1 -0
- package/dist/core/permissions/permissions.js +87 -0
- package/dist/core/permissions/permissions.js.map +1 -0
- package/dist/core/projection/api.js +84 -0
- package/dist/core/projection/api.js.map +1 -0
- package/dist/core/projection/arch-slice.js +63 -0
- package/dist/core/projection/arch-slice.js.map +1 -0
- package/dist/core/projection/events.js +34 -0
- package/dist/core/projection/events.js.map +1 -0
- package/dist/core/projection/introduced.js +14 -0
- package/dist/core/projection/introduced.js.map +1 -0
- package/dist/core/provenance/findings.js +244 -0
- package/dist/core/provenance/findings.js.map +1 -0
- package/dist/core/provenance/git.js +201 -0
- package/dist/core/provenance/git.js.map +1 -0
- package/dist/core/provenance/gitq/moves.js +139 -0
- package/dist/core/provenance/gitq/moves.js.map +1 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
- package/dist/core/provenance/sample/scope.js +238 -0
- package/dist/core/provenance/sample/scope.js.map +1 -0
- package/dist/core/provenance/sample/sections.js +61 -0
- package/dist/core/provenance/sample/sections.js.map +1 -0
- package/dist/core/provenance/sources.js +280 -0
- package/dist/core/provenance/sources.js.map +1 -0
- package/dist/core/provenance/stamp.js +220 -0
- package/dist/core/provenance/stamp.js.map +1 -0
- package/dist/core/provenance/walk.js +157 -0
- package/dist/core/provenance/walk.js.map +1 -0
- package/dist/core/repo/authored/paths.js +210 -0
- package/dist/core/repo/authored/paths.js.map +1 -0
- package/dist/core/repo/entries.js +126 -0
- package/dist/core/repo/entries.js.map +1 -0
- package/dist/core/repo/paths.js +322 -0
- package/dist/core/repo/paths.js.map +1 -0
- package/dist/core/repo/repo.js +308 -0
- package/dist/core/repo/repo.js.map +1 -0
- package/dist/core/repo/service-target.js +153 -0
- package/dist/core/repo/service-target.js.map +1 -0
- package/dist/core/repo/state.js +58 -0
- package/dist/core/repo/state.js.map +1 -0
- package/dist/core/repo/tree/find.js +61 -0
- package/dist/core/repo/tree/find.js.map +1 -0
- package/dist/core/repo/tree/fs.js +90 -0
- package/dist/core/repo/tree/fs.js.map +1 -0
- package/dist/core/repo/tree/marker.js +61 -0
- package/dist/core/repo/tree/marker.js.map +1 -0
- package/dist/core/repo/tree/render/body.js +258 -0
- package/dist/core/repo/tree/render/body.js.map +1 -0
- package/dist/core/repo/tree/render/projects.js +182 -0
- package/dist/core/repo/tree/render/projects.js.map +1 -0
- package/dist/core/repo/tree/render/service/header.js +125 -0
- package/dist/core/repo/tree/render/service/header.js.map +1 -0
- package/dist/core/repo/tree/render/service/peers.js +28 -0
- package/dist/core/repo/tree/render/service/peers.js.map +1 -0
- package/dist/core/repo/tree/render/service/view-id.js +67 -0
- package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
- package/dist/core/repo/tree/render/service/views.js +78 -0
- package/dist/core/repo/tree/render/service/views.js.map +1 -0
- package/dist/core/repo/tree/render/stale.js +42 -0
- package/dist/core/repo/tree/render/stale.js.map +1 -0
- package/dist/core/repo/tree/render/text.js +84 -0
- package/dist/core/repo/tree/render/text.js.map +1 -0
- package/dist/core/repo/tree/render/views.js +293 -0
- package/dist/core/repo/tree/render/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +255 -0
- package/dist/core/repo/tree/walk.js.map +1 -0
- package/dist/core/results.js +146 -14
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +239 -0
- package/dist/core/scaffold/landscape.js.map +1 -0
- package/dist/core/scaffold/legacy.js +271 -0
- package/dist/core/scaffold/legacy.js.map +1 -0
- package/dist/core/scaffold/readme.js +84 -0
- package/dist/core/scaffold/readme.js.map +1 -0
- package/dist/core/staging/commit.js +252 -0
- package/dist/core/staging/commit.js.map +1 -0
- package/dist/core/staging/interrupted.js +96 -0
- package/dist/core/staging/interrupted.js.map +1 -0
- package/dist/core/staging/lock.js +268 -0
- package/dist/core/staging/lock.js.map +1 -0
- package/dist/core/staging/recovery/finding.js +35 -0
- package/dist/core/staging/recovery/finding.js.map +1 -0
- package/dist/core/staging/recovery/intent.js +95 -0
- package/dist/core/staging/recovery/intent.js.map +1 -0
- package/dist/core/staging/recovery/recover.js +204 -0
- package/dist/core/staging/recovery/recover.js.map +1 -0
- package/dist/core/staging/recovery/residue.js +62 -0
- package/dist/core/staging/recovery/residue.js.map +1 -0
- package/dist/core/staging/snapshot/manifest.js +188 -0
- package/dist/core/staging/snapshot/manifest.js.map +1 -0
- package/dist/core/staging/snapshot/snapshot.js +196 -0
- package/dist/core/staging/snapshot/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +181 -0
- package/dist/core/staging/txn/forward.js.map +1 -0
- package/dist/core/staging/txn/journal.js +139 -0
- package/dist/core/staging/txn/journal.js.map +1 -0
- package/dist/core/staging/txn/transaction.js +75 -0
- package/dist/core/staging/txn/transaction.js.map +1 -0
- package/dist/core/staging/writes.js +113 -0
- package/dist/core/staging/writes.js.map +1 -0
- package/dist/core/status/actions/execution.js +60 -0
- package/dist/core/status/actions/execution.js.map +1 -0
- package/dist/core/status/contracts.js +126 -0
- package/dist/core/status/contracts.js.map +1 -0
- package/dist/core/status/feature/artifacts.js +196 -0
- package/dist/core/status/feature/artifacts.js.map +1 -0
- package/dist/core/status/feature/feature.js +214 -0
- package/dist/core/status/feature/feature.js.map +1 -0
- package/dist/core/status/feature/next.js +163 -0
- package/dist/core/status/feature/next.js.map +1 -0
- package/dist/core/status/feature/state.js +21 -0
- package/dist/core/status/feature/state.js.map +1 -0
- package/dist/core/status/feature/words.js +96 -0
- package/dist/core/status/feature/words.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +216 -0
- package/dist/core/status/fleet/fleet.js.map +1 -0
- package/dist/core/status/fleet/next.js +302 -0
- package/dist/core/status/fleet/next.js.map +1 -0
- package/dist/core/status/interrupted.js +97 -0
- package/dist/core/status/interrupted.js.map +1 -0
- package/dist/core/status/report.js +31 -0
- package/dist/core/status/report.js.map +1 -0
- package/dist/core/status/scan.js +41 -0
- package/dist/core/status/scan.js.map +1 -0
- package/dist/core/status/verification.js +216 -0
- package/dist/core/status/verification.js.map +1 -0
- package/dist/core/tasks/packet.js +199 -0
- package/dist/core/tasks/packet.js.map +1 -0
- package/dist/core/tasks/record.js +43 -0
- package/dist/core/tasks/record.js.map +1 -0
- package/dist/core/tasks/sources.js +181 -0
- package/dist/core/tasks/sources.js.map +1 -0
- package/dist/core/tasks/stamps.js +76 -0
- package/dist/core/tasks/stamps.js.map +1 -0
- package/dist/core/tasks/unit.js +0 -0
- package/dist/core/tasks/unit.js.map +1 -0
- package/dist/core/usecases/capability.js +166 -0
- package/dist/core/usecases/capability.js.map +1 -0
- package/dist/core/usecases/delta/claims.js +140 -0
- package/dist/core/usecases/delta/claims.js.map +1 -0
- package/dist/core/usecases/delta/flows.js +101 -0
- package/dist/core/usecases/delta/flows.js.map +1 -0
- package/dist/core/usecases/delta/modified.js +315 -0
- package/dist/core/usecases/delta/modified.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +76 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -0
- package/dist/core/usecases/fleet.js +296 -0
- package/dist/core/usecases/fleet.js.map +1 -0
- package/dist/core/usecases/grade/capability-tag.js +93 -0
- package/dist/core/usecases/grade/capability-tag.js.map +1 -0
- package/dist/core/usecases/grade/feature.js +88 -0
- package/dist/core/usecases/grade/feature.js.map +1 -0
- package/dist/core/usecases/grade/requirement-tag.js +94 -0
- package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
- package/dist/core/usecases/grade/steps.js +266 -0
- package/dist/core/usecases/grade/steps.js.map +1 -0
- package/dist/core/usecases/grade/usecases.js +112 -0
- package/dist/core/usecases/grade/usecases.js.map +1 -0
- package/dist/core/usecases/operations.js +123 -0
- package/dist/core/usecases/operations.js.map +1 -0
- package/dist/core/usecases/place.js +44 -0
- package/dist/core/usecases/place.js.map +1 -0
- package/dist/core/usecases/service/exclude.js +119 -0
- package/dist/core/usecases/service/exclude.js.map +1 -0
- package/dist/core/usecases/service/flows.js +164 -0
- package/dist/core/usecases/service/flows.js.map +1 -0
- package/dist/core/usecases/suites/participants.js +83 -0
- package/dist/core/usecases/suites/participants.js.map +1 -0
- package/dist/core/usecases/suites/suites.js +45 -0
- package/dist/core/usecases/suites/suites.js.map +1 -0
- package/dist/core/usecases/touch.js +101 -0
- package/dist/core/usecases/touch.js.map +1 -0
- package/dist/core/verify/answers.js +180 -0
- package/dist/core/verify/answers.js.map +1 -0
- package/dist/core/verify/build.js +170 -0
- package/dist/core/verify/build.js.map +1 -0
- package/dist/core/verify/checklist.js +259 -0
- package/dist/core/verify/checklist.js.map +1 -0
- package/dist/core/verify/claims/identity.js +61 -0
- package/dist/core/verify/claims/identity.js.map +1 -0
- package/dist/core/verify/cross/diff.js +97 -0
- package/dist/core/verify/cross/diff.js.map +1 -0
- package/dist/core/verify/evidence/contract.js +169 -0
- package/dist/core/verify/evidence/contract.js.map +1 -0
- package/dist/core/verify/location.js +67 -0
- package/dist/core/verify/location.js.map +1 -0
- package/dist/core/verify/pins/lint.js +158 -0
- package/dist/core/verify/pins/lint.js.map +1 -0
- package/dist/core/verify/pins/pin.js +95 -0
- package/dist/core/verify/pins/pin.js.map +1 -0
- package/dist/core/verify/read/file.js +224 -0
- package/dist/core/verify/read/file.js.map +1 -0
- package/dist/core/verify/read/shape.js +169 -0
- package/dist/core/verify/read/shape.js.map +1 -0
- package/dist/core/verify/read/union.js +105 -0
- package/dist/core/verify/read/union.js.map +1 -0
- package/dist/core/verify/record.js +165 -0
- package/dist/core/verify/record.js.map +1 -0
- package/dist/core/verify/store/commit.js +99 -0
- package/dist/core/verify/store/commit.js.map +1 -0
- package/dist/core/verify/store/render.js +61 -0
- package/dist/core/verify/store/render.js.map +1 -0
- package/dist/core/vocabulary/health.js +91 -0
- package/dist/core/vocabulary/health.js.map +1 -0
- package/dist/core/vocabulary/issue.js +59 -0
- package/dist/core/vocabulary/issue.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +216 -0
- package/dist/core/vocabulary/maturity.js.map +1 -0
- package/dist/core/vocabulary/report.js +90 -0
- package/dist/core/vocabulary/report.js.map +1 -0
- package/dist/core/vocabulary/steps.js +266 -0
- package/dist/core/vocabulary/steps.js.map +1 -0
- package/dist/core/workspace/discover.js +239 -0
- package/dist/core/workspace/discover.js.map +1 -0
- package/dist/core/workspace/render.js +52 -0
- package/dist/core/workspace/render.js.map +1 -0
- package/examples/README.md +232 -0
- package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
- package/examples/docs/architecture/capabilities.yaml +31 -0
- package/examples/docs/architecture/landscape.likec4 +336 -0
- package/examples/docs/architecture/obligations.yaml +23 -0
- package/examples/docs/architecture/permissions.yaml +50 -0
- package/examples/docs/architecture/services.likec4 +70 -0
- package/examples/docs/architecture/subsystems.likec4 +18 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +74 -0
- package/examples/docs/capabilities/checkout/spec.md +55 -0
- package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
- package/examples/docs/capabilities/order-notifications/spec.md +43 -0
- package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
- package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
- package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +132 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +31 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
- package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
- package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +73 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
- package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
- package/examples/docs/glossary/order.md +15 -0
- package/examples/docs/glossary/payments/authorization.md +14 -0
- package/examples/docs/likec4.config.json +8 -0
- package/examples/docs/loam.json +3 -0
- package/examples/docs/services/checkout-web/model.likec4 +92 -0
- package/examples/docs/services/checkout-web/spec.md +91 -0
- package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
- package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
- package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
- package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
- package/examples/docs/services/order-service/arch.spec.md +134 -0
- package/examples/docs/services/order-service/asyncapi.yaml +109 -0
- package/examples/docs/services/order-service/health.yaml +57 -0
- package/examples/docs/services/order-service/model.likec4 +126 -0
- package/examples/docs/services/order-service/openapi.yaml +257 -0
- package/examples/docs/services/order-service/runbook.md +62 -0
- package/examples/docs/services/order-service/spec.md +134 -0
- package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
- package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
- package/examples/docs/services/payment-service/arch.spec.md +76 -0
- package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
- package/examples/docs/services/payment-service/health.yaml +39 -0
- package/examples/docs/services/payment-service/model.likec4 +68 -0
- package/examples/docs/services/payment-service/openapi.yaml +151 -0
- package/examples/docs/services/payment-service/runbook.md +37 -0
- package/examples/docs/services/payment-service/spec.md +88 -0
- package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
- package/examples/docs/services/platform/identity-service/arch.spec.md +120 -0
- package/examples/docs/services/platform/identity-service/health.yaml +70 -0
- package/examples/docs/services/platform/identity-service/model.likec4 +81 -0
- package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
- package/examples/docs/services/platform/identity-service/runbook.md +95 -0
- package/examples/docs/services/platform/identity-service/spec.md +119 -0
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +200 -0
- package/examples/docs/services/platform/notification-service/health.yaml +40 -0
- package/examples/docs/services/platform/notification-service/model.likec4 +97 -0
- package/examples/docs/services/platform/notification-service/runbook.md +48 -0
- package/examples/docs/services/platform/notification-service/spec.md +112 -0
- package/examples/docs/services/platform/subsystem.yaml +2 -0
- package/examples/fleet.yaml +57 -0
- package/package.json +19 -6
- package/dist/commands/adopt.js +0 -240
- package/dist/commands/adopt.js.map +0 -1
- package/dist/commands/archive.js +0 -1313
- package/dist/commands/archive.js.map +0 -1
- package/dist/commands/delta.js +0 -388
- package/dist/commands/delta.js.map +0 -1
- package/dist/commands/docs-repo-gate.js.map +0 -1
- package/dist/commands/format.js +0 -17
- package/dist/commands/format.js.map +0 -1
- package/dist/commands/gherkin.js +0 -309
- package/dist/commands/gherkin.js.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/list.js +0 -295
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/migrate-openspec.js +0 -950
- package/dist/commands/migrate-openspec.js.map +0 -1
- package/dist/commands/new.js +0 -413
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/rebase.js +0 -356
- package/dist/commands/rebase.js.map +0 -1
- package/dist/commands/show.js +0 -320
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/status.js +0 -262
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/unarchive.js +0 -317
- package/dist/commands/unarchive.js.map +0 -1
- package/dist/commands/validate.js +0 -1773
- package/dist/commands/validate.js.map +0 -1
- package/dist/commands/verify.js +0 -775
- package/dist/commands/verify.js.map +0 -1
- package/dist/commands/vouch.js +0 -421
- package/dist/commands/vouch.js.map +0 -1
- package/dist/core/agent.js +0 -2173
- package/dist/core/agent.js.map +0 -1
- package/dist/core/agents-stamp.js.map +0 -1
- package/dist/core/arch.js +0 -130
- package/dist/core/arch.js.map +0 -1
- package/dist/core/asyncapi.js +0 -253
- package/dist/core/asyncapi.js.map +0 -1
- package/dist/core/brief.js +0 -755
- package/dist/core/brief.js.map +0 -1
- package/dist/core/coherence.js +0 -577
- package/dist/core/coherence.js.map +0 -1
- package/dist/core/concurrency.js.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/delta.js +0 -476
- package/dist/core/delta.js.map +0 -1
- package/dist/core/dependencies.js +0 -356
- package/dist/core/dependencies.js.map +0 -1
- package/dist/core/doctor.js +0 -596
- package/dist/core/doctor.js.map +0 -1
- package/dist/core/document-bytes.js.map +0 -1
- package/dist/core/explore.js +0 -225
- package/dist/core/explore.js.map +0 -1
- package/dist/core/frontmatter.js.map +0 -1
- package/dist/core/gherkin.js +0 -463
- package/dist/core/gherkin.js.map +0 -1
- package/dist/core/health.js +0 -67
- package/dist/core/health.js.map +0 -1
- package/dist/core/ids.js +0 -122
- package/dist/core/ids.js.map +0 -1
- package/dist/core/issue.js +0 -9
- package/dist/core/issue.js.map +0 -1
- package/dist/core/json.js +0 -74
- package/dist/core/json.js.map +0 -1
- package/dist/core/likec4.js +0 -489
- package/dist/core/likec4.js.map +0 -1
- package/dist/core/maturity.js +0 -66
- package/dist/core/maturity.js.map +0 -1
- package/dist/core/openapi-merge.js +0 -552
- package/dist/core/openapi-merge.js.map +0 -1
- package/dist/core/openapi.js.map +0 -1
- package/dist/core/openspec-inventory.js +0 -1440
- package/dist/core/openspec-inventory.js.map +0 -1
- package/dist/core/path-safety.js.map +0 -1
- package/dist/core/provenance.js +0 -787
- package/dist/core/provenance.js.map +0 -1
- package/dist/core/records.js.map +0 -1
- package/dist/core/repo.js +0 -438
- package/dist/core/repo.js.map +0 -1
- package/dist/core/report.js +0 -47
- package/dist/core/report.js.map +0 -1
- package/dist/core/spec.js +0 -505
- package/dist/core/spec.js.map +0 -1
- package/dist/core/staging.js +0 -890
- package/dist/core/staging.js.map +0 -1
- package/dist/core/status.js +0 -1132
- package/dist/core/status.js.map +0 -1
- package/dist/core/steps.js +0 -72
- package/dist/core/steps.js.map +0 -1
- package/dist/core/verify.js +0 -807
- package/dist/core/verify.js.map +0 -1
- package/dist/core/version.js.map +0 -1
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read model of the docs repo — enumeration, and only by the filesystem.
|
|
3
|
+
*
|
|
4
|
+
* Files are the source of truth, so `services/` IS the list of services and
|
|
5
|
+
* there is no manifest that can disagree with it. The shapes this hands back
|
|
6
|
+
* live in `entries.ts`, the layout it walks in `paths.ts`, and whether there is
|
|
7
|
+
* a repo to walk at all in `state.ts`.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync } from "node:fs";
|
|
10
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
import { contentStamp, listField, movedUnderVouch, readFrontmatter, stringField, } from "../document/frontmatter.js";
|
|
13
|
+
import { featureDirOf } from "../kernel/ids/dirs.js";
|
|
14
|
+
import { rawServiceId, serviceIdProblem } from "../kernel/ids/service.js";
|
|
15
|
+
import { readVouchScope } from "../provenance/sample/scope.js";
|
|
16
|
+
import { compareIds, featureIdFromDirName } from "./entries.js";
|
|
17
|
+
import { ARCHIVE_DIR, featurePaths, featuresDir, fleetAdrsDir, isServiceArtifactName, servicePathsAt, SPEC_AXES, } from "./paths.js";
|
|
18
|
+
import { requireDocsRepo } from "./state.js";
|
|
19
|
+
import { countMarkdown, entryIs } from "./tree/fs.js";
|
|
20
|
+
import { walkServicesTree } from "./tree/walk.js";
|
|
21
|
+
/* ------------------------------------------------------------------ */
|
|
22
|
+
/* Enumeration */
|
|
23
|
+
/* ------------------------------------------------------------------ */
|
|
24
|
+
/**
|
|
25
|
+
* Sorted names of the real subdirectories of `dir` (dot-dirs and files skipped).
|
|
26
|
+
* A missing `dir` is an empty list — the swallow is deliberate but narrow: it
|
|
27
|
+
* only ever runs INSIDE a docs repo that `requireDocsRepo` has already
|
|
28
|
+
* confirmed, where an absent `features/` or `specs/` means "none yet" and
|
|
29
|
+
* nothing else.
|
|
30
|
+
*/
|
|
31
|
+
async function subdirs(dir) {
|
|
32
|
+
if (!existsSync(dir))
|
|
33
|
+
return [];
|
|
34
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
35
|
+
return entries
|
|
36
|
+
.filter((e) => !e.name.startsWith(".") && entryIs(dir, e, "dir"))
|
|
37
|
+
.map((e) => e.name)
|
|
38
|
+
.sort(compareIds);
|
|
39
|
+
}
|
|
40
|
+
/** Services a feature carries a delta for, ordered — the subdirs of its specs/. */
|
|
41
|
+
export async function featureSpecServices(featureDir, context) {
|
|
42
|
+
if (context !== undefined)
|
|
43
|
+
return context.featureSpecServices(featureDir);
|
|
44
|
+
return (await subdirs(featurePaths(featureDir).specsDir)).map(rawServiceId);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The classified `services/` tree — services at any depth, the subsystems
|
|
48
|
+
* grouping them, and the walk's own findings (`subsystem.*`). The walk itself
|
|
49
|
+
* lives in `./tree/walk.ts` and never imports back into this package; this
|
|
50
|
+
* function is where its two injected dependencies are built — the docs-repo
|
|
51
|
+
* precondition and the artifact-name table `paths.ts` owns.
|
|
52
|
+
*/
|
|
53
|
+
export async function listFleetTree(docsDir, context) {
|
|
54
|
+
if (context !== undefined)
|
|
55
|
+
return context.fleetTree(docsDir);
|
|
56
|
+
requireDocsRepo(docsDir, ["ok"]);
|
|
57
|
+
return walkServicesTree({ docsDir, isServiceArtifact: isServiceArtifactName });
|
|
58
|
+
}
|
|
59
|
+
/** Every service in the docs repo, at any depth of the tree, ordered by id. */
|
|
60
|
+
export async function listServices(docsDir, context) {
|
|
61
|
+
if (context !== undefined)
|
|
62
|
+
return context.listServices(docsDir);
|
|
63
|
+
return serviceEntries(await listFleetTree(docsDir));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* The full entries for a walked tree — frontmatter, artifact presence, ADR
|
|
67
|
+
* count. Split from `listServices` so `FleetContext` can derive its services
|
|
68
|
+
* memo from its tree memo: one walk per invocation answers both questions.
|
|
69
|
+
* Ordering is `compareIds` over the id wherever the service sits — placement
|
|
70
|
+
* is never part of any identity, and `--json` consumers diff this order — with
|
|
71
|
+
* the directory as the tiebreak so a duplicated id (its own error finding)
|
|
72
|
+
* still lists deterministically.
|
|
73
|
+
*/
|
|
74
|
+
/**
|
|
75
|
+
* The second spec axis's header, or an empty one when nobody could read it.
|
|
76
|
+
*
|
|
77
|
+
* `readFrontmatter` folds a decode failure into a flag but still THROWS when
|
|
78
|
+
* the path exists and cannot be read as a file at all — a directory named
|
|
79
|
+
* `arch.spec.md`, which test/gate-command.test.ts builds on purpose. This is
|
|
80
|
+
* the fleet ENUMERATION, where one service's bad byte must cost one subject
|
|
81
|
+
* and not the listing of the other 119, so the throw stops here.
|
|
82
|
+
*
|
|
83
|
+
* The distinction between "no scope" and "nobody could look" is not lost by
|
|
84
|
+
* swallowing it: a path that exists and cannot be read is `service.unreadable`
|
|
85
|
+
* — an ERROR that fails `loam validate` and `loam gate` — which is a louder
|
|
86
|
+
* signal than any row of a listing, and it names the file this cannot.
|
|
87
|
+
*/
|
|
88
|
+
async function archHeader(path) {
|
|
89
|
+
try {
|
|
90
|
+
return await readFrontmatter(path);
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return { present: false, malformed: false, data: {}, body: "" };
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* The spec files whose body moved under their vouch — `content.stale`'s
|
|
98
|
+
* question, asked through the one predicate `loam validate` grades with
|
|
99
|
+
* (`movedUnderVouch`) so the fleet listing and the finding cannot disagree
|
|
100
|
+
* about one file. Only a header that carries a stamp (`contentStamp`) costs the
|
|
101
|
+
* second read: the frontmatter read already answered whether there is anything
|
|
102
|
+
* to compare, and on a fleet mid-adoption most headers do not. The body is
|
|
103
|
+
* read exactly as the finding reads it, as UTF-8 text, because the stamp is
|
|
104
|
+
* byte-exact.
|
|
105
|
+
*/
|
|
106
|
+
async function filesMovedUnderVouch(axes) {
|
|
107
|
+
const moved = await Promise.all(axes.map(async ({ file, path, header }) => contentStamp(header) !== undefined && movedUnderVouch(header, await readFile(path, "utf8")) ? [file] : []));
|
|
108
|
+
return moved.flat();
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* `ServiceEntry.adoption`, read off one living spec.md's frontmatter — the one
|
|
112
|
+
* spelling of the marker's test, for the enumeration below and for the adopt
|
|
113
|
+
* brief, which must not call a partial adoption finished. Any value but
|
|
114
|
+
* `partial` reads as absent (SCHEMA.md).
|
|
115
|
+
*/
|
|
116
|
+
export function adoptionOf(fm) {
|
|
117
|
+
return stringField(fm, "adoption") === "partial" ? "partial" : null;
|
|
118
|
+
}
|
|
119
|
+
/** `adoptionOf` for a spec.md by path; an absent file is no marker. */
|
|
120
|
+
export async function specAdoption(specPath) {
|
|
121
|
+
return adoptionOf(await readFrontmatter(specPath));
|
|
122
|
+
}
|
|
123
|
+
export async function serviceEntries(tree) {
|
|
124
|
+
const entries = await Promise.all(tree.services.map(async (svc) => {
|
|
125
|
+
const p = servicePathsAt(svc.dir);
|
|
126
|
+
// Both spec axes, because a sample is per FILE: one `--sample 3` run can
|
|
127
|
+
// read a short spec.md in full and stamp a scope on a long arch.spec.md
|
|
128
|
+
// beside it, and a fleet row that reported only spec.md's header would
|
|
129
|
+
// print that service as fully vouched while `loam validate` reported it
|
|
130
|
+
// sampled. `readFrontmatter` answers "absent" for a file that is not
|
|
131
|
+
// there, so a service without the second axis pays one existsSync.
|
|
132
|
+
const [fm, archFm] = await Promise.all([readFrontmatter(p.spec), archHeader(p.archSpec)]);
|
|
133
|
+
const headers = { spec: fm, archSpec: archFm };
|
|
134
|
+
const idProblem = serviceIdProblem(svc.id, "directory name");
|
|
135
|
+
return {
|
|
136
|
+
id: svc.id,
|
|
137
|
+
dir: svc.dir,
|
|
138
|
+
subsystem: svc.subsystem,
|
|
139
|
+
...(idProblem === null ? {} : { idProblem }),
|
|
140
|
+
has: {
|
|
141
|
+
model: existsSync(p.model),
|
|
142
|
+
spec: existsSync(p.spec),
|
|
143
|
+
openapi: existsSync(p.openapi),
|
|
144
|
+
asyncapi: existsSync(p.asyncapi),
|
|
145
|
+
runbook: existsSync(p.runbook),
|
|
146
|
+
health: existsSync(p.health),
|
|
147
|
+
},
|
|
148
|
+
adrs: await countMarkdown(p.adrsDir),
|
|
149
|
+
status: stringField(fm, "status") ?? null,
|
|
150
|
+
adoption: adoptionOf(fm),
|
|
151
|
+
sources: {
|
|
152
|
+
declared: listField(fm, "sources").length > 0,
|
|
153
|
+
stamped: stringField(fm, "sources_digest") !== undefined,
|
|
154
|
+
},
|
|
155
|
+
// Either axis makes the SERVICE sampled, and presence is the test, not
|
|
156
|
+
// decodability: an unreadable scope is still a stamped partial read
|
|
157
|
+
// (core/provenance/sample/scope.ts's `readVouchScope`), and the fleet
|
|
158
|
+
// listing is the last place a mangled field should be able to buy
|
|
159
|
+
// itself a full-trust row.
|
|
160
|
+
vouchScope: [fm, archFm].some((header) => readVouchScope(header).kind !== "none") ? "sampled" : null,
|
|
161
|
+
// Both axes again, for the scope's reason: a stamp is per FILE, and an
|
|
162
|
+
// arch.spec.md edited under its vouch is a service part of whose
|
|
163
|
+
// documentation nobody has re-read.
|
|
164
|
+
contentStale: await filesMovedUnderVouch(SPEC_AXES.map((axis) => ({ file: axis.file, path: p[axis.key], header: headers[axis.key] }))),
|
|
165
|
+
};
|
|
166
|
+
}));
|
|
167
|
+
return entries.sort((a, b) => compareIds(a.id, b.id) || compareIds(a.dir, b.dir));
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* How many fleet-level ADRs `architecture/adrs/` holds — the same number, by the
|
|
171
|
+
* same rule (`countMarkdown`), that `ServiceEntry.adrs` carries one altitude
|
|
172
|
+
* down. One shape for one question: a second spelling of "count the decisions"
|
|
173
|
+
* is how `list` and `show` once reported different ADR counts for one service.
|
|
174
|
+
*
|
|
175
|
+
* A count and never a finding. The directory is optional, an absent one is 0,
|
|
176
|
+
* and nothing in loam grades either — see `fleetAdrsDir` for why that is the
|
|
177
|
+
* whole design rather than an unfinished half of it. No `FleetContext` overload:
|
|
178
|
+
* one caller asks this once per invocation, and a memo whose key is the docsDir
|
|
179
|
+
* would be a cache nobody reads twice.
|
|
180
|
+
*/
|
|
181
|
+
export async function fleetAdrCount(docsDir) {
|
|
182
|
+
return countMarkdown(fleetAdrsDir(docsDir));
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* What a feature is CALLED, for a person: intent.md's `title:`, else its first
|
|
186
|
+
* `# ` heading with the feature id peeled off the front, else null.
|
|
187
|
+
*
|
|
188
|
+
* Every row that names a feature used to print the id alone, and an id is a
|
|
189
|
+
* key, not a name — a newcomer looking at `ready FEAT-101` could not tell
|
|
190
|
+
* which change it was without opening the directory. Read on demand rather
|
|
191
|
+
* than carried on `FeatureEntry`, because the enumeration runs under every
|
|
192
|
+
* command and only the views a person reads need the words. A missing or
|
|
193
|
+
* unreadable intent.md is simply no title: the row still prints its id, and
|
|
194
|
+
* whether intent.md is owed is `status`'s question, not this one's.
|
|
195
|
+
*/
|
|
196
|
+
export async function featureTitle(feature) {
|
|
197
|
+
let fm;
|
|
198
|
+
try {
|
|
199
|
+
fm = await readFrontmatter(featurePaths(feature.dir).intent);
|
|
200
|
+
}
|
|
201
|
+
catch {
|
|
202
|
+
// A directory in intent.md's place, a permission: unreadable is no title.
|
|
203
|
+
// `readFrontmatter` folds only the encoding failure into a flag, and before
|
|
204
|
+
// this read the views that print a title never opened intent.md at all —
|
|
205
|
+
// so letting the error escape would hand `loam status` and `loam list`
|
|
206
|
+
// whole to `repository-unavailable` over a label. Whether intent.md is
|
|
207
|
+
// fine is the intent row's and `validate`'s question.
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
const declared = stringField(fm, "title")?.trim();
|
|
211
|
+
if (declared !== undefined && declared !== "")
|
|
212
|
+
return declared;
|
|
213
|
+
const heading = fm.body.split(/\r?\n/).find((l) => l.startsWith("# "));
|
|
214
|
+
if (heading === undefined)
|
|
215
|
+
return null;
|
|
216
|
+
const words = heading.slice(2).trim();
|
|
217
|
+
const bare = words.startsWith(feature.id) ? words.slice(feature.id.length).replace(/^[\s:—–-]+/, "") : words;
|
|
218
|
+
return bare === "" ? null : bare;
|
|
219
|
+
}
|
|
220
|
+
async function readFeature(dir, dirName, archived) {
|
|
221
|
+
const p = featurePaths(dir);
|
|
222
|
+
return {
|
|
223
|
+
id: featureIdFromDirName(dirName),
|
|
224
|
+
dirName,
|
|
225
|
+
dir,
|
|
226
|
+
archived,
|
|
227
|
+
services: (await subdirs(p.specsDir)).map(rawServiceId),
|
|
228
|
+
has: { intent: existsSync(p.intent), delta: existsSync(p.delta) },
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Features in the docs repo, ordered by id (active and archived interleaved when
|
|
233
|
+
* both are asked for). `features/archive/` is the archive, never a feature.
|
|
234
|
+
*/
|
|
235
|
+
export async function listFeatures(docsDir, opts = {}, context) {
|
|
236
|
+
if (context !== undefined)
|
|
237
|
+
return context.listFeatures(docsDir, opts);
|
|
238
|
+
// "no-services" is tolerated here on purpose: a docs repo whose services/ is
|
|
239
|
+
// gone is broken, but it is `listServices` (and `loam doctor`) that says so.
|
|
240
|
+
// Refusing here too would turn one diagnosis into two contradictory ones.
|
|
241
|
+
requireDocsRepo(docsDir, ["ok", "no-services"]);
|
|
242
|
+
const root = featuresDir(docsDir);
|
|
243
|
+
const active = (await subdirs(root)).filter((n) => n !== ARCHIVE_DIR);
|
|
244
|
+
// Branded at the join: the name came off this readdir, onto the features
|
|
245
|
+
// root it was listed under — the provenance `FeatureDir` records.
|
|
246
|
+
const out = await Promise.all(active.map((n) => readFeature(featureDirOf(join(root, n)), n, false)));
|
|
247
|
+
if (opts.includeArchived) {
|
|
248
|
+
const archiveRoot = join(root, ARCHIVE_DIR);
|
|
249
|
+
const archived = await subdirs(archiveRoot);
|
|
250
|
+
out.push(...(await Promise.all(archived.map((n) => readFeature(featureDirOf(join(archiveRoot, n)), n, true)))));
|
|
251
|
+
}
|
|
252
|
+
return out.sort((a, b) => compareIds(a.id, b.id) || compareIds(a.dirName, b.dirName));
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Resolve a feature argument — a canonical id (`FEAT-5`) or an exact directory
|
|
256
|
+
* name (`FEAT-5-slug`) — to its entry. The entry's `id` is the canonical
|
|
257
|
+
* spelling, and it is the only name a caller may use from here on: tag filters,
|
|
258
|
+
* coherence, and the cross-feature self-exclusion scans all compare against
|
|
259
|
+
* `feature.id`, never against the raw argument.
|
|
260
|
+
*
|
|
261
|
+
* Matching is EXACT, on one of two spellings: the directory name as it is on
|
|
262
|
+
* disk, or the canonical id derived from it. It used to also match any dirName
|
|
263
|
+
* starting with `arg + "-"`, which made the argument a prefix query in
|
|
264
|
+
* disguise: with FEAT-401 and FEAT-402 in flight, `loam archive FEAT` archived
|
|
265
|
+
* whichever sorted first, and `loam delta billing` reached into
|
|
266
|
+
* `billing-7-rewrite`. A destructive command must never pick a target the
|
|
267
|
+
* caller did not name, so a prefix now resolves to nothing at all.
|
|
268
|
+
*
|
|
269
|
+
* An exact directory name still wins over the id spelling (`FEAT-5` the
|
|
270
|
+
* directory over `FEAT-5-slug`, whose id is also `FEAT-5`), and under "include"
|
|
271
|
+
* an active feature wins over an archived one. Ties among equally-exact
|
|
272
|
+
* candidates go to the first by name — deterministic, unlike the raw readdir
|
|
273
|
+
* order this replaces; `featureCandidates` returns every one of them, for a
|
|
274
|
+
* caller that must see the tie (`loam status` names the colliding directories).
|
|
275
|
+
*/
|
|
276
|
+
export async function resolveFeature(docsDir, arg, archived, context) {
|
|
277
|
+
return (await featureCandidates(docsDir, arg, archived, context))[0] ?? null;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Every feature the argument names exactly, best first. Split out of
|
|
281
|
+
* `resolveFeature` so a caller that wants to REFUSE an ambiguous argument can
|
|
282
|
+
* see the tie instead of inheriting the winner.
|
|
283
|
+
*/
|
|
284
|
+
export async function featureCandidates(docsDir, arg, archived, context) {
|
|
285
|
+
const all = await listFeatures(docsDir, { includeArchived: archived !== "exclude" }, context);
|
|
286
|
+
return all
|
|
287
|
+
.filter((f) => archived === "include" || f.archived === (archived === "only"))
|
|
288
|
+
.filter((f) => f.dirName === arg || f.id === arg)
|
|
289
|
+
.sort((a, b) => Number(b.dirName === arg) - Number(a.dirName === arg) ||
|
|
290
|
+
Number(a.archived) - Number(b.archived) ||
|
|
291
|
+
compareIds(a.dirName, b.dirName));
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* The message for an exclude-mode miss. When the feature exists under
|
|
295
|
+
* `features/archive/`, "no feature" is a lie the caller would have to debug —
|
|
296
|
+
* the honest answer is "already archived", plus how to look at it. The `--json`
|
|
297
|
+
* code stays `unknown-target` either way: the target is unknown to the command
|
|
298
|
+
* that asked, and the prose carries the diagnosis.
|
|
299
|
+
*/
|
|
300
|
+
export async function missingFeatureMessage(docsDir, arg, context) {
|
|
301
|
+
const shipped = await resolveFeature(docsDir, arg, "only", context);
|
|
302
|
+
if (shipped !== null) {
|
|
303
|
+
return (`Feature '${shipped.id}' is already archived (features/archive/${shipped.dirName}) — ` +
|
|
304
|
+
`\`loam show ${shipped.id}\` reads it, \`loam unarchive ${shipped.id}\` re-opens it.`);
|
|
305
|
+
}
|
|
306
|
+
return `No feature '${arg}' under ${featuresDir(docsDir)}.`;
|
|
307
|
+
}
|
|
308
|
+
//# sourceMappingURL=repo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repo.js","sourceRoot":"","sources":["../../../src/core/repo/repo.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Read model of the docs repo — enumeration, and only by the filesystem.\n *\n * Files are the source of truth, so `services/` IS the list of services and\n * there is no manifest that can disagree with it. The shapes this hands back\n * live in `entries.ts`, the layout it walks in `paths.ts`, and whether there is\n * a repo to walk at all in `state.ts`.\n */\nimport { existsSync } from \"node:fs\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n contentStamp,\n listField,\n movedUnderVouch,\n readFrontmatter,\n stringField,\n type Frontmatter,\n} from \"../document/frontmatter.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\nimport { featureDirOf, type DocsDir, type FeatureDir } from \"../kernel/ids/dirs.js\";\nimport { rawServiceId, serviceIdProblem, type RawServiceId } from \"../kernel/ids/service.js\";\nimport { readVouchScope } from \"../provenance/sample/scope.js\";\nimport { compareIds, featureIdFromDirName, type FeatureEntry, type ServiceEntry } from \"./entries.js\";\nimport {\n ARCHIVE_DIR,\n featurePaths,\n featuresDir,\n fleetAdrsDir,\n isServiceArtifactName,\n servicePathsAt,\n SPEC_AXES,\n} from \"./paths.js\";\nimport { requireDocsRepo } from \"./state.js\";\nimport { countMarkdown, entryIs } from \"./tree/fs.js\";\nimport { walkServicesTree, type FleetTree } from \"./tree/walk.js\";\n\n/* ------------------------------------------------------------------ */\n/* Enumeration */\n/* ------------------------------------------------------------------ */\n\n/**\n * Sorted names of the real subdirectories of `dir` (dot-dirs and files skipped).\n * A missing `dir` is an empty list — the swallow is deliberate but narrow: it\n * only ever runs INSIDE a docs repo that `requireDocsRepo` has already\n * confirmed, where an absent `features/` or `specs/` means \"none yet\" and\n * nothing else.\n */\nasync function subdirs(dir: string): Promise<string[]> {\n if (!existsSync(dir)) return [];\n const entries = await readdir(dir, { withFileTypes: true });\n return entries\n .filter((e) => !e.name.startsWith(\".\") && entryIs(dir, e, \"dir\"))\n .map((e) => e.name)\n .sort(compareIds);\n}\n\n/** Services a feature carries a delta for, ordered — the subdirs of its specs/. */\nexport async function featureSpecServices(\n featureDir: FeatureDir,\n context?: FleetContext,\n): Promise<RawServiceId[]> {\n if (context !== undefined) return context.featureSpecServices(featureDir);\n return (await subdirs(featurePaths(featureDir).specsDir)).map(rawServiceId);\n}\n\n/**\n * The classified `services/` tree — services at any depth, the subsystems\n * grouping them, and the walk's own findings (`subsystem.*`). The walk itself\n * lives in `./tree/walk.ts` and never imports back into this package; this\n * function is where its two injected dependencies are built — the docs-repo\n * precondition and the artifact-name table `paths.ts` owns.\n */\nexport async function listFleetTree(docsDir: DocsDir, context?: FleetContext): Promise<FleetTree> {\n if (context !== undefined) return context.fleetTree(docsDir);\n requireDocsRepo(docsDir, [\"ok\"]);\n return walkServicesTree({ docsDir, isServiceArtifact: isServiceArtifactName });\n}\n\n/** Every service in the docs repo, at any depth of the tree, ordered by id. */\nexport async function listServices(docsDir: DocsDir, context?: FleetContext): Promise<ServiceEntry[]> {\n if (context !== undefined) return context.listServices(docsDir);\n return serviceEntries(await listFleetTree(docsDir));\n}\n\n/**\n * The full entries for a walked tree — frontmatter, artifact presence, ADR\n * count. Split from `listServices` so `FleetContext` can derive its services\n * memo from its tree memo: one walk per invocation answers both questions.\n * Ordering is `compareIds` over the id wherever the service sits — placement\n * is never part of any identity, and `--json` consumers diff this order — with\n * the directory as the tiebreak so a duplicated id (its own error finding)\n * still lists deterministically.\n */\n/**\n * The second spec axis's header, or an empty one when nobody could read it.\n *\n * `readFrontmatter` folds a decode failure into a flag but still THROWS when\n * the path exists and cannot be read as a file at all — a directory named\n * `arch.spec.md`, which test/gate-command.test.ts builds on purpose. This is\n * the fleet ENUMERATION, where one service's bad byte must cost one subject\n * and not the listing of the other 119, so the throw stops here.\n *\n * The distinction between \"no scope\" and \"nobody could look\" is not lost by\n * swallowing it: a path that exists and cannot be read is `service.unreadable`\n * — an ERROR that fails `loam validate` and `loam gate` — which is a louder\n * signal than any row of a listing, and it names the file this cannot.\n */\nasync function archHeader(path: string): Promise<Frontmatter> {\n try {\n return await readFrontmatter(path);\n } catch {\n return { present: false, malformed: false, data: {}, body: \"\" };\n }\n}\n\n/**\n * The spec files whose body moved under their vouch — `content.stale`'s\n * question, asked through the one predicate `loam validate` grades with\n * (`movedUnderVouch`) so the fleet listing and the finding cannot disagree\n * about one file. Only a header that carries a stamp (`contentStamp`) costs the\n * second read: the frontmatter read already answered whether there is anything\n * to compare, and on a fleet mid-adoption most headers do not. The body is\n * read exactly as the finding reads it, as UTF-8 text, because the stamp is\n * byte-exact.\n */\nasync function filesMovedUnderVouch(\n axes: readonly { file: string; path: string; header: Frontmatter }[],\n): Promise<string[]> {\n const moved = await Promise.all(\n axes.map(async ({ file, path, header }) =>\n contentStamp(header) !== undefined && movedUnderVouch(header, await readFile(path, \"utf8\")) ? [file] : [],\n ),\n );\n return moved.flat();\n}\n\n/**\n * `ServiceEntry.adoption`, read off one living spec.md's frontmatter — the one\n * spelling of the marker's test, for the enumeration below and for the adopt\n * brief, which must not call a partial adoption finished. Any value but\n * `partial` reads as absent (SCHEMA.md).\n */\nexport function adoptionOf(fm: Frontmatter): \"partial\" | null {\n return stringField(fm, \"adoption\") === \"partial\" ? \"partial\" : null;\n}\n\n/** `adoptionOf` for a spec.md by path; an absent file is no marker. */\nexport async function specAdoption(specPath: string): Promise<\"partial\" | null> {\n return adoptionOf(await readFrontmatter(specPath));\n}\n\nexport async function serviceEntries(tree: FleetTree): Promise<ServiceEntry[]> {\n const entries = await Promise.all(\n tree.services.map(async (svc): Promise<ServiceEntry> => {\n const p = servicePathsAt(svc.dir);\n // Both spec axes, because a sample is per FILE: one `--sample 3` run can\n // read a short spec.md in full and stamp a scope on a long arch.spec.md\n // beside it, and a fleet row that reported only spec.md's header would\n // print that service as fully vouched while `loam validate` reported it\n // sampled. `readFrontmatter` answers \"absent\" for a file that is not\n // there, so a service without the second axis pays one existsSync.\n const [fm, archFm] = await Promise.all([readFrontmatter(p.spec), archHeader(p.archSpec)]);\n const headers = { spec: fm, archSpec: archFm };\n const idProblem = serviceIdProblem(svc.id, \"directory name\");\n return {\n id: svc.id,\n dir: svc.dir,\n subsystem: svc.subsystem,\n ...(idProblem === null ? {} : { idProblem }),\n has: {\n model: existsSync(p.model),\n spec: existsSync(p.spec),\n openapi: existsSync(p.openapi),\n asyncapi: existsSync(p.asyncapi),\n runbook: existsSync(p.runbook),\n health: existsSync(p.health),\n },\n adrs: await countMarkdown(p.adrsDir),\n status: stringField(fm, \"status\") ?? null,\n adoption: adoptionOf(fm),\n sources: {\n declared: listField(fm, \"sources\").length > 0,\n stamped: stringField(fm, \"sources_digest\") !== undefined,\n },\n // Either axis makes the SERVICE sampled, and presence is the test, not\n // decodability: an unreadable scope is still a stamped partial read\n // (core/provenance/sample/scope.ts's `readVouchScope`), and the fleet\n // listing is the last place a mangled field should be able to buy\n // itself a full-trust row.\n vouchScope: [fm, archFm].some((header) => readVouchScope(header).kind !== \"none\") ? \"sampled\" : null,\n // Both axes again, for the scope's reason: a stamp is per FILE, and an\n // arch.spec.md edited under its vouch is a service part of whose\n // documentation nobody has re-read.\n contentStale: await filesMovedUnderVouch(\n SPEC_AXES.map((axis) => ({ file: axis.file, path: p[axis.key], header: headers[axis.key] })),\n ),\n };\n }),\n );\n return entries.sort((a, b) => compareIds(a.id, b.id) || compareIds(a.dir, b.dir));\n}\n\n/**\n * How many fleet-level ADRs `architecture/adrs/` holds — the same number, by the\n * same rule (`countMarkdown`), that `ServiceEntry.adrs` carries one altitude\n * down. One shape for one question: a second spelling of \"count the decisions\"\n * is how `list` and `show` once reported different ADR counts for one service.\n *\n * A count and never a finding. The directory is optional, an absent one is 0,\n * and nothing in loam grades either — see `fleetAdrsDir` for why that is the\n * whole design rather than an unfinished half of it. No `FleetContext` overload:\n * one caller asks this once per invocation, and a memo whose key is the docsDir\n * would be a cache nobody reads twice.\n */\nexport async function fleetAdrCount(docsDir: DocsDir): Promise<number> {\n return countMarkdown(fleetAdrsDir(docsDir));\n}\n\n/**\n * What a feature is CALLED, for a person: intent.md's `title:`, else its first\n * `# ` heading with the feature id peeled off the front, else null.\n *\n * Every row that names a feature used to print the id alone, and an id is a\n * key, not a name — a newcomer looking at `ready FEAT-101` could not tell\n * which change it was without opening the directory. Read on demand rather\n * than carried on `FeatureEntry`, because the enumeration runs under every\n * command and only the views a person reads need the words. A missing or\n * unreadable intent.md is simply no title: the row still prints its id, and\n * whether intent.md is owed is `status`'s question, not this one's.\n */\nexport async function featureTitle(feature: FeatureEntry): Promise<string | null> {\n let fm: Frontmatter;\n try {\n fm = await readFrontmatter(featurePaths(feature.dir).intent);\n } catch {\n // A directory in intent.md's place, a permission: unreadable is no title.\n // `readFrontmatter` folds only the encoding failure into a flag, and before\n // this read the views that print a title never opened intent.md at all —\n // so letting the error escape would hand `loam status` and `loam list`\n // whole to `repository-unavailable` over a label. Whether intent.md is\n // fine is the intent row's and `validate`'s question.\n return null;\n }\n const declared = stringField(fm, \"title\")?.trim();\n if (declared !== undefined && declared !== \"\") return declared;\n const heading = fm.body.split(/\\r?\\n/).find((l) => l.startsWith(\"# \"));\n if (heading === undefined) return null;\n const words = heading.slice(2).trim();\n const bare = words.startsWith(feature.id) ? words.slice(feature.id.length).replace(/^[\\s:—–-]+/, \"\") : words;\n return bare === \"\" ? null : bare;\n}\n\nasync function readFeature(dir: FeatureDir, dirName: string, archived: boolean): Promise<FeatureEntry> {\n const p = featurePaths(dir);\n return {\n id: featureIdFromDirName(dirName),\n dirName,\n dir,\n archived,\n services: (await subdirs(p.specsDir)).map(rawServiceId),\n has: { intent: existsSync(p.intent), delta: existsSync(p.delta) },\n };\n}\n\n/**\n * Features in the docs repo, ordered by id (active and archived interleaved when\n * both are asked for). `features/archive/` is the archive, never a feature.\n */\nexport async function listFeatures(\n docsDir: DocsDir,\n opts: { includeArchived?: boolean } = {},\n context?: FleetContext,\n): Promise<FeatureEntry[]> {\n if (context !== undefined) return context.listFeatures(docsDir, opts);\n // \"no-services\" is tolerated here on purpose: a docs repo whose services/ is\n // gone is broken, but it is `listServices` (and `loam doctor`) that says so.\n // Refusing here too would turn one diagnosis into two contradictory ones.\n requireDocsRepo(docsDir, [\"ok\", \"no-services\"]);\n const root = featuresDir(docsDir);\n const active = (await subdirs(root)).filter((n) => n !== ARCHIVE_DIR);\n // Branded at the join: the name came off this readdir, onto the features\n // root it was listed under — the provenance `FeatureDir` records.\n const out = await Promise.all(active.map((n) => readFeature(featureDirOf(join(root, n)), n, false)));\n\n if (opts.includeArchived) {\n const archiveRoot = join(root, ARCHIVE_DIR);\n const archived = await subdirs(archiveRoot);\n out.push(...(await Promise.all(archived.map((n) => readFeature(featureDirOf(join(archiveRoot, n)), n, true)))));\n }\n\n return out.sort((a, b) => compareIds(a.id, b.id) || compareIds(a.dirName, b.dirName));\n}\n\n/**\n * Which side of `features/archive/` a lookup may land on. The policy is an\n * argument, not a default, so every command's stance on shipped features is\n * visible at its call site: delta/validate/archive work on in-flight features\n * (\"exclude\"), show/verify/new read shipped ones too (\"include\"), unarchive\n * takes back nothing else (\"only\").\n */\nexport type ArchivedPolicy = \"exclude\" | \"include\" | \"only\";\n\n/**\n * Resolve a feature argument — a canonical id (`FEAT-5`) or an exact directory\n * name (`FEAT-5-slug`) — to its entry. The entry's `id` is the canonical\n * spelling, and it is the only name a caller may use from here on: tag filters,\n * coherence, and the cross-feature self-exclusion scans all compare against\n * `feature.id`, never against the raw argument.\n *\n * Matching is EXACT, on one of two spellings: the directory name as it is on\n * disk, or the canonical id derived from it. It used to also match any dirName\n * starting with `arg + \"-\"`, which made the argument a prefix query in\n * disguise: with FEAT-401 and FEAT-402 in flight, `loam archive FEAT` archived\n * whichever sorted first, and `loam delta billing` reached into\n * `billing-7-rewrite`. A destructive command must never pick a target the\n * caller did not name, so a prefix now resolves to nothing at all.\n *\n * An exact directory name still wins over the id spelling (`FEAT-5` the\n * directory over `FEAT-5-slug`, whose id is also `FEAT-5`), and under \"include\"\n * an active feature wins over an archived one. Ties among equally-exact\n * candidates go to the first by name — deterministic, unlike the raw readdir\n * order this replaces; `featureCandidates` returns every one of them, for a\n * caller that must see the tie (`loam status` names the colliding directories).\n */\nexport async function resolveFeature(\n docsDir: DocsDir,\n arg: string,\n archived: ArchivedPolicy,\n context?: FleetContext,\n): Promise<FeatureEntry | null> {\n return (await featureCandidates(docsDir, arg, archived, context))[0] ?? null;\n}\n\n/**\n * Every feature the argument names exactly, best first. Split out of\n * `resolveFeature` so a caller that wants to REFUSE an ambiguous argument can\n * see the tie instead of inheriting the winner.\n */\nexport async function featureCandidates(\n docsDir: DocsDir,\n arg: string,\n archived: ArchivedPolicy,\n context?: FleetContext,\n): Promise<FeatureEntry[]> {\n const all = await listFeatures(docsDir, { includeArchived: archived !== \"exclude\" }, context);\n return all\n .filter((f) => archived === \"include\" || f.archived === (archived === \"only\"))\n .filter((f) => f.dirName === arg || f.id === arg)\n .sort(\n (a, b) =>\n Number(b.dirName === arg) - Number(a.dirName === arg) ||\n Number(a.archived) - Number(b.archived) ||\n compareIds(a.dirName, b.dirName),\n );\n}\n\n/**\n * The message for an exclude-mode miss. When the feature exists under\n * `features/archive/`, \"no feature\" is a lie the caller would have to debug —\n * the honest answer is \"already archived\", plus how to look at it. The `--json`\n * code stays `unknown-target` either way: the target is unknown to the command\n * that asked, and the prose carries the diagnosis.\n */\nexport async function missingFeatureMessage(\n docsDir: DocsDir,\n arg: string,\n context?: FleetContext,\n): Promise<string> {\n const shipped = await resolveFeature(docsDir, arg, \"only\", context);\n if (shipped !== null) {\n return (\n `Feature '${shipped.id}' is already archived (features/archive/${shipped.dirName}) — ` +\n `\\`loam show ${shipped.id}\\` reads it, \\`loam unarchive ${shipped.id}\\` re-opens it.`\n );\n }\n return `No feature '${arg}' under ${featuresDir(docsDir)}.`;\n}\n"]}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Turning a name a caller typed into a name loam may join into a path.
|
|
3
|
+
*
|
|
4
|
+
* `unfiledServicePaths(docsDir, name)` spells `<docsDir>/services/<name>/`,
|
|
5
|
+
* and its parameter is `PathableService`: an unchecked name at that call site
|
|
6
|
+
* no longer compiles, and this module is where a name a caller typed EARNS the
|
|
7
|
+
* type. The history is why it exists. Six commands guard their argument with
|
|
8
|
+
* `assertServiceId` at the boundary; `validate` never did, and both of its
|
|
9
|
+
* entry points — `--service <id>` and the positional `<target>` — reached
|
|
10
|
+
* the path builder with whatever argv held. `--service ../../outside/services/x`
|
|
11
|
+
* resolved ABOVE the docs repo, and where a `spec.md` happened to sit there
|
|
12
|
+
* loam opened it, graded it, and reported its frontmatter through `--json`.
|
|
13
|
+
*
|
|
14
|
+
* The grammar alone is not the answer, and this is the whole reason this module
|
|
15
|
+
* exists rather than a call to `assertServiceId`. `services/Payment Service/`
|
|
16
|
+
* is a directory `loam list` shows, `validate --all` grades, and
|
|
17
|
+
* `service.id-invalid` calls an error nobody can fix without a rename — so it
|
|
18
|
+
* is exactly the directory somebody points `validate --service` at. Refusing on
|
|
19
|
+
* the grammar would make the one service loam complains about the one service
|
|
20
|
+
* loam cannot look at.
|
|
21
|
+
*
|
|
22
|
+
* So the enumeration answers first and the grammar answers second:
|
|
23
|
+
*
|
|
24
|
+
* in `services/` → the enumeration's OWN id, which is a name loam
|
|
25
|
+
* already reads off disk every time it lists the fleet.
|
|
26
|
+
* Legal or not, it exists, and joining it lands where
|
|
27
|
+
* the directory is.
|
|
28
|
+
* not there, legal → the caller's name. Nothing exists yet; the run
|
|
29
|
+
* continues and grades it `service.unknown`, with the
|
|
30
|
+
* near-miss hints that make a typo diagnosable.
|
|
31
|
+
* not there, illegal → refused, before any path is built.
|
|
32
|
+
*
|
|
33
|
+
* `show` and `status` already resolve against the enumeration this way. What
|
|
34
|
+
* they do not do is fall through to the grammar, which is why they answer
|
|
35
|
+
* "no such service" to a name that could never BE a service — a worse sentence
|
|
36
|
+
* for the same input.
|
|
37
|
+
*/
|
|
38
|
+
import { listServices } from "./repo.js";
|
|
39
|
+
import { parseServiceId } from "../kernel/ids/service.js";
|
|
40
|
+
import { serviceTreePath } from "../kernel/ids/dirs.js";
|
|
41
|
+
import { servicePathsAt, unfiledServicePaths } from "./paths.js";
|
|
42
|
+
/**
|
|
43
|
+
* The enumerated services, or the empty list when `services/` cannot be
|
|
44
|
+
* enumerated at all. The swallow is deliberate and spelled ONCE: every
|
|
45
|
+
* repository-aware resolver wants "which services exist" as context, and an
|
|
46
|
+
* unenumerable `services/` is that repository's own diagnosis
|
|
47
|
+
* (`services-missing`), never the asking check's. Six call sites each carried
|
|
48
|
+
* this try/catch in their own spelling before it lived here — which is exactly
|
|
49
|
+
* the shape docs/CODE-STYLE.md warns about: an errno fix lands in one copy and
|
|
50
|
+
* the other five keep the old behaviour. The existence probes that used to ask
|
|
51
|
+
* `existsSync(services/<id>/)` ask membership HERE for the same tolerance:
|
|
52
|
+
* `validate --feature` must run in a docs repo with no `services/` at all,
|
|
53
|
+
* where enumerating is a refusal but "does this service exist" still has the
|
|
54
|
+
* honest answer no.
|
|
55
|
+
*/
|
|
56
|
+
export async function enumeratedServices(docsDir, fleet) {
|
|
57
|
+
try {
|
|
58
|
+
return await listServices(docsDir, fleet);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
/** The id projection of `enumeratedServices` — most membership asks want only the names. */
|
|
65
|
+
export async function enumeratedServiceIds(docsDir, fleet) {
|
|
66
|
+
return (await enumeratedServices(docsDir, fleet)).map((s) => s.id);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* The artifact paths of a service wherever it lives: the enumeration's own
|
|
70
|
+
* directory when the id exists anywhere in the tree, the unfiled root
|
|
71
|
+
* spelling otherwise — so an absent service still probes, grades
|
|
72
|
+
* (`service.unknown`) and CREATES exactly as it did when the tree was flat.
|
|
73
|
+
* This is the one bridge the ~40 former `servicePaths` call sites resolve
|
|
74
|
+
* through — and it is NOT free: without a `fleet` context every call is a
|
|
75
|
+
* fresh fleet enumeration (one readdir per directory walked plus a
|
|
76
|
+
* frontmatter read and several existence probes per service), which measured
|
|
77
|
+
* ~13 ms per call on a 120-service fleet. A call site inside a loop must
|
|
78
|
+
* thread the command's `FleetContext`; a caller that already holds a
|
|
79
|
+
* `ServiceEntry` should spell `servicePathsAt(entry.dir)` directly and pay
|
|
80
|
+
* nothing.
|
|
81
|
+
*/
|
|
82
|
+
/**
|
|
83
|
+
* Where a service sits under `services/`, repo-relative and WITHOUT a trailing
|
|
84
|
+
* slash — for a message that names an existing directory to a reader.
|
|
85
|
+
*
|
|
86
|
+
* The join it replaces is `services/${id}`, which is right for an unfiled
|
|
87
|
+
* service and wrong for every filed one; `paths.ts` states the same rule for
|
|
88
|
+
* artifact paths and this is its display sibling. A name the enumeration does
|
|
89
|
+
* not answer to falls back to the unfiled spelling, which is the only honest
|
|
90
|
+
* answer: there is no directory to point at, and that is usually what the
|
|
91
|
+
* message is about.
|
|
92
|
+
*/
|
|
93
|
+
export async function serviceTreePathOf(docsDir, service, fleet) {
|
|
94
|
+
const entry = (await enumeratedServices(docsDir, fleet)).find((s) => s.id === service);
|
|
95
|
+
return entry === undefined ? `services/${service}` : serviceTreePath(entry);
|
|
96
|
+
}
|
|
97
|
+
export async function locateServicePaths(docsDir, service, fleet) {
|
|
98
|
+
const entry = (await enumeratedServices(docsDir, fleet)).find((s) => s.id === service);
|
|
99
|
+
return entry === undefined ? unfiledServicePaths(docsDir, service) : servicePathsAt(entry.dir);
|
|
100
|
+
}
|
|
101
|
+
export async function resolveServiceTarget(docsDir, name, label, fleet) {
|
|
102
|
+
// The enumeration is asked first, and its answer is the value that travels
|
|
103
|
+
// on: `entry.id` rather than `name`. They are equal as strings, and only one
|
|
104
|
+
// of them carries the fact that a `readdir` produced it. The resolved `dir`
|
|
105
|
+
// travels too, so a caller that goes on to read artifacts can spell
|
|
106
|
+
// `servicePathsAt(dir)` without a second enumeration; it is absent exactly
|
|
107
|
+
// when the name resolved by grammar alone — nothing exists to point at.
|
|
108
|
+
const entry = (await listServices(docsDir, fleet)).find((s) => s.id === name);
|
|
109
|
+
if (entry !== undefined)
|
|
110
|
+
return { ok: true, id: entry.id, dir: entry.dir };
|
|
111
|
+
return parseServiceId(name, label);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The same resolution for a name a DOCUMENT declared — an edge target's
|
|
115
|
+
* `metadata { service '…' }` binding, or its title standing in for one — where
|
|
116
|
+
* the caller needs an answer instead of a refusal: which enumerated directory,
|
|
117
|
+
* if any, does this text name?
|
|
118
|
+
*
|
|
119
|
+
* The enumeration is the fleet's `services/` plus whatever directory names the
|
|
120
|
+
* caller has already read for itself — a feature's own `specs/<svc>/`, the only
|
|
121
|
+
* place a service the feature INTRODUCES has a directory at all. There is
|
|
122
|
+
* deliberately no grammar arm here, in either direction: `services/Payment
|
|
123
|
+
* Service/` keeps resolving for the banner's reason, and a legal-looking name
|
|
124
|
+
* that matches no directory has no living file anywhere, so the caller's
|
|
125
|
+
* business is to grade it absent — never to build a path from it.
|
|
126
|
+
*
|
|
127
|
+
* The index is built on the first ask, not at construction: coherence asks per
|
|
128
|
+
* op-edge and features routinely carry none, so the enumeration only runs once
|
|
129
|
+
* an answer matters. A repo whose `services/` cannot be enumerated resolves
|
|
130
|
+
* only the caller's own names — every living probe would have found nothing
|
|
131
|
+
* there anyway, and `services-missing` is that repository's diagnosis, not
|
|
132
|
+
* this document's.
|
|
133
|
+
*/
|
|
134
|
+
export function enumeratedServiceIndex(docsDir, known, fleet) {
|
|
135
|
+
let index;
|
|
136
|
+
return async (name) => {
|
|
137
|
+
if (index === undefined) {
|
|
138
|
+
index = new Map();
|
|
139
|
+
for (const id of known)
|
|
140
|
+
index.set(id, id);
|
|
141
|
+
try {
|
|
142
|
+
for (const s of await listServices(docsDir, fleet))
|
|
143
|
+
index.set(s.id, s.id);
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// The docblock's last paragraph: no enumerable services/ means the
|
|
147
|
+
// fleet half of the index is empty, not that the question is an error.
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return index.get(name);
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=service-target.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-target.js","sourceRoot":"","sources":["../../../src/core/repo/service-target.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Turning a name a caller typed into a name loam may join into a path.\n *\n * `unfiledServicePaths(docsDir, name)` spells `<docsDir>/services/<name>/`,\n * and its parameter is `PathableService`: an unchecked name at that call site\n * no longer compiles, and this module is where a name a caller typed EARNS the\n * type. The history is why it exists. Six commands guard their argument with\n * `assertServiceId` at the boundary; `validate` never did, and both of its\n * entry points — `--service <id>` and the positional `<target>` — reached\n * the path builder with whatever argv held. `--service ../../outside/services/x`\n * resolved ABOVE the docs repo, and where a `spec.md` happened to sit there\n * loam opened it, graded it, and reported its frontmatter through `--json`.\n *\n * The grammar alone is not the answer, and this is the whole reason this module\n * exists rather than a call to `assertServiceId`. `services/Payment Service/`\n * is a directory `loam list` shows, `validate --all` grades, and\n * `service.id-invalid` calls an error nobody can fix without a rename — so it\n * is exactly the directory somebody points `validate --service` at. Refusing on\n * the grammar would make the one service loam complains about the one service\n * loam cannot look at.\n *\n * So the enumeration answers first and the grammar answers second:\n *\n * in `services/` → the enumeration's OWN id, which is a name loam\n * already reads off disk every time it lists the fleet.\n * Legal or not, it exists, and joining it lands where\n * the directory is.\n * not there, legal → the caller's name. Nothing exists yet; the run\n * continues and grades it `service.unknown`, with the\n * near-miss hints that make a typo diagnosable.\n * not there, illegal → refused, before any path is built.\n *\n * `show` and `status` already resolve against the enumeration this way. What\n * they do not do is fall through to the grammar, which is why they answer\n * \"no such service\" to a name that could never BE a service — a worse sentence\n * for the same input.\n */\nimport { listServices } from \"./repo.js\";\nimport { parseServiceId, type PathableService, type RawServiceId } from \"../kernel/ids/service.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\nimport { serviceTreePath, type DocsDir, type ServiceDir } from \"../kernel/ids/dirs.js\";\nimport { servicePathsAt, unfiledServicePaths, type ServicePaths } from \"./paths.js\";\nimport type { ServiceEntry } from \"./entries.js\";\n\nexport type ServiceTarget =\n | { readonly ok: true; readonly id: RawServiceId; readonly dir?: ServiceDir }\n | { readonly ok: false; readonly problem: string };\n\n/**\n * The enumerated services, or the empty list when `services/` cannot be\n * enumerated at all. The swallow is deliberate and spelled ONCE: every\n * repository-aware resolver wants \"which services exist\" as context, and an\n * unenumerable `services/` is that repository's own diagnosis\n * (`services-missing`), never the asking check's. Six call sites each carried\n * this try/catch in their own spelling before it lived here — which is exactly\n * the shape docs/CODE-STYLE.md warns about: an errno fix lands in one copy and\n * the other five keep the old behaviour. The existence probes that used to ask\n * `existsSync(services/<id>/)` ask membership HERE for the same tolerance:\n * `validate --feature` must run in a docs repo with no `services/` at all,\n * where enumerating is a refusal but \"does this service exist\" still has the\n * honest answer no.\n */\nexport async function enumeratedServices(\n docsDir: DocsDir,\n fleet?: FleetContext,\n): Promise<ServiceEntry[]> {\n try {\n return await listServices(docsDir, fleet);\n } catch {\n return [];\n }\n}\n\n/** The id projection of `enumeratedServices` — most membership asks want only the names. */\nexport async function enumeratedServiceIds(\n docsDir: DocsDir,\n fleet?: FleetContext,\n): Promise<RawServiceId[]> {\n return (await enumeratedServices(docsDir, fleet)).map((s) => s.id);\n}\n\n/**\n * The artifact paths of a service wherever it lives: the enumeration's own\n * directory when the id exists anywhere in the tree, the unfiled root\n * spelling otherwise — so an absent service still probes, grades\n * (`service.unknown`) and CREATES exactly as it did when the tree was flat.\n * This is the one bridge the ~40 former `servicePaths` call sites resolve\n * through — and it is NOT free: without a `fleet` context every call is a\n * fresh fleet enumeration (one readdir per directory walked plus a\n * frontmatter read and several existence probes per service), which measured\n * ~13 ms per call on a 120-service fleet. A call site inside a loop must\n * thread the command's `FleetContext`; a caller that already holds a\n * `ServiceEntry` should spell `servicePathsAt(entry.dir)` directly and pay\n * nothing.\n */\n/**\n * Where a service sits under `services/`, repo-relative and WITHOUT a trailing\n * slash — for a message that names an existing directory to a reader.\n *\n * The join it replaces is `services/${id}`, which is right for an unfiled\n * service and wrong for every filed one; `paths.ts` states the same rule for\n * artifact paths and this is its display sibling. A name the enumeration does\n * not answer to falls back to the unfiled spelling, which is the only honest\n * answer: there is no directory to point at, and that is usually what the\n * message is about.\n */\nexport async function serviceTreePathOf(\n docsDir: DocsDir,\n service: string,\n fleet?: FleetContext,\n): Promise<string> {\n const entry = (await enumeratedServices(docsDir, fleet)).find((s) => s.id === service);\n return entry === undefined ? `services/${service}` : serviceTreePath(entry);\n}\n\nexport async function locateServicePaths(\n docsDir: DocsDir,\n service: PathableService,\n fleet?: FleetContext,\n): Promise<ServicePaths> {\n const entry = (await enumeratedServices(docsDir, fleet)).find((s) => s.id === service);\n return entry === undefined ? unfiledServicePaths(docsDir, service) : servicePathsAt(entry.dir);\n}\n\nexport async function resolveServiceTarget(\n docsDir: DocsDir,\n name: string,\n label: string,\n fleet?: FleetContext,\n): Promise<ServiceTarget> {\n // The enumeration is asked first, and its answer is the value that travels\n // on: `entry.id` rather than `name`. They are equal as strings, and only one\n // of them carries the fact that a `readdir` produced it. The resolved `dir`\n // travels too, so a caller that goes on to read artifacts can spell\n // `servicePathsAt(dir)` without a second enumeration; it is absent exactly\n // when the name resolved by grammar alone — nothing exists to point at.\n const entry = (await listServices(docsDir, fleet)).find((s) => s.id === name);\n if (entry !== undefined) return { ok: true, id: entry.id, dir: entry.dir };\n return parseServiceId(name, label);\n}\n\n/**\n * The same resolution for a name a DOCUMENT declared — an edge target's\n * `metadata { service '…' }` binding, or its title standing in for one — where\n * the caller needs an answer instead of a refusal: which enumerated directory,\n * if any, does this text name?\n *\n * The enumeration is the fleet's `services/` plus whatever directory names the\n * caller has already read for itself — a feature's own `specs/<svc>/`, the only\n * place a service the feature INTRODUCES has a directory at all. There is\n * deliberately no grammar arm here, in either direction: `services/Payment\n * Service/` keeps resolving for the banner's reason, and a legal-looking name\n * that matches no directory has no living file anywhere, so the caller's\n * business is to grade it absent — never to build a path from it.\n *\n * The index is built on the first ask, not at construction: coherence asks per\n * op-edge and features routinely carry none, so the enumeration only runs once\n * an answer matters. A repo whose `services/` cannot be enumerated resolves\n * only the caller's own names — every living probe would have found nothing\n * there anyway, and `services-missing` is that repository's diagnosis, not\n * this document's.\n */\nexport function enumeratedServiceIndex(\n docsDir: DocsDir,\n known: readonly RawServiceId[],\n fleet?: FleetContext,\n): (name: string) => Promise<RawServiceId | undefined> {\n let index: Map<string, RawServiceId> | undefined;\n return async (name: string): Promise<RawServiceId | undefined> => {\n if (index === undefined) {\n index = new Map<string, RawServiceId>();\n for (const id of known) index.set(id, id);\n try {\n for (const s of await listServices(docsDir, fleet)) index.set(s.id, s.id);\n } catch {\n // The docblock's last paragraph: no enumerable services/ means the\n // fleet half of the index is empty, not that the question is an error.\n }\n }\n return index.get(name);\n };\n}\n"]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is there a docs repo there at all?
|
|
3
|
+
*
|
|
4
|
+
* Three answers, not two: missing, present-but-empty, and ok. The middle one
|
|
5
|
+
* exists because a freshly cloned docs repo whose `services/` git never tracked
|
|
6
|
+
* looks identical to a directory nobody wired — and the fix differs.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync, statSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
export function docsRepoState(docsDir) {
|
|
11
|
+
const path = docsDir;
|
|
12
|
+
let isDir = false;
|
|
13
|
+
try {
|
|
14
|
+
isDir = statSync(path).isDirectory();
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
isDir = false;
|
|
18
|
+
}
|
|
19
|
+
if (!isDir)
|
|
20
|
+
return { kind: "missing", path };
|
|
21
|
+
return { kind: existsSync(join(path, "services")) ? "ok" : "no-services", path };
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The docs repo is not there. Thrown rather than returned because every caller
|
|
25
|
+
* of the enumeration wants the same thing — to stop — and a `[]` return is the
|
|
26
|
+
* bug this closes. `message` is written for a human at a terminal: the CLI's
|
|
27
|
+
* top-level handler prints it verbatim, and commands that catch it report
|
|
28
|
+
* `repository-unavailable`.
|
|
29
|
+
*/
|
|
30
|
+
export class DocsRepoUnavailableError extends Error {
|
|
31
|
+
state;
|
|
32
|
+
constructor(state, message) {
|
|
33
|
+
super(message);
|
|
34
|
+
this.state = state;
|
|
35
|
+
this.name = "DocsRepoUnavailableError";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Refuse to enumerate a docs repo that is not one. `allow` names the states the
|
|
40
|
+
* caller can honestly survive: features/ may be absent from a real docs repo
|
|
41
|
+
* (nothing is in flight yet), so feature enumeration only insists the docs repo
|
|
42
|
+
* EXISTS, while service enumeration insists it is shaped like a docs repo — a
|
|
43
|
+
* `services/` directory is what makes it one.
|
|
44
|
+
*/
|
|
45
|
+
export function requireDocsRepo(docsDir, allow) {
|
|
46
|
+
const state = docsRepoState(docsDir);
|
|
47
|
+
if (allow.includes(state.kind))
|
|
48
|
+
return;
|
|
49
|
+
if (state.kind === "missing") {
|
|
50
|
+
throw new DocsRepoUnavailableError(state, `The configured docs repo does not exist: ${state.path}. ` +
|
|
51
|
+
"Fix `docsDir` in loam.json, clone the docs repo there, " +
|
|
52
|
+
"or run `loam init --docs <dir> --create` to make a new one.");
|
|
53
|
+
}
|
|
54
|
+
throw new DocsRepoUnavailableError(state, `${state.path} is not a docs repo — it has no services/ directory. ` +
|
|
55
|
+
"Point `docsDir` in loam.json at the shared docs repo, " +
|
|
56
|
+
"or run `loam init --docs <dir> --create` to make one.");
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.js","sourceRoot":"","sources":["../../../src/core/repo/state.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AA8BjC,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,MAAM,IAAI,GAAG,OAAO,CAAC;IACrB,IAAI,KAAK,GAAG,KAAK,CAAC;IAClB,IAAI,CAAC;QACH,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,KAAK,GAAG,KAAK,CAAC;IAChB,CAAC;IACD,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC7C,OAAO,EAAE,IAAI,EAAE,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,aAAa,EAAE,IAAI,EAAE,CAAC;AACnF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAEtC,KAAK;IADhB,YACW,KAAoB,EAC7B,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;qBAHN,KAAK;QAId,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACzC,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,KAAqB;IACpE,MAAM,KAAK,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;IACrC,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO;IACvC,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,IAAI,wBAAwB,CAChC,KAAK,EACL,4CAA4C,KAAK,CAAC,IAAI,IAAI;YACxD,yDAAyD;YACzD,6DAA6D,CAChE,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,wBAAwB,CAChC,KAAK,EACL,GAAG,KAAK,CAAC,IAAI,uDAAuD;QAClE,wDAAwD;QACxD,uDAAuD,CAC1D,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Is there a docs repo there at all?\n *\n * Three answers, not two: missing, present-but-empty, and ok. The middle one\n * exists because a freshly cloned docs repo whose `services/` git never tracked\n * looks identical to a directory nobody wired — and the fix differs.\n */\nimport { existsSync, statSync } from \"node:fs\";\nimport { join } from \"node:path\";\n\n/* ------------------------------------------------------------------ */\n/* Is there a docs repo there at all? */\n/* ------------------------------------------------------------------ */\n\n/**\n * What is actually at `docsDir`. Three answers, because they point at three\n * different fixes and the enumeration below used to give all of them the same\n * one — an empty list:\n *\n * - `missing` — nothing there (or not a directory): `docsDir` in loam.json\n * is wrong, or the docs repo was never cloned;\n * - `no-services` — a directory, but with no `services/`: it is some other\n * directory, most often the service repo itself after a typo;\n * - `ok` — a docs repo. `services/` may still be EMPTY, and that is a\n * legitimate state: a docs repo before the first `loam adopt`.\n *\n * \"Empty fleet\" and \"wrong path\" are the same output only if nobody asks this\n * question, and a green `loam list` over a docsDir that does not exist is worse\n * than a red one: it says the fleet is fine.\n */\nexport type DocsRepoKind = \"missing\" | \"no-services\" | \"ok\";\n\nexport interface DocsRepoState {\n kind: DocsRepoKind;\n /** The path examined, so a caller can quote it without re-deriving it. */\n path: string;\n}\n\nexport function docsRepoState(docsDir: string): DocsRepoState {\n const path = docsDir;\n let isDir = false;\n try {\n isDir = statSync(path).isDirectory();\n } catch {\n isDir = false;\n }\n if (!isDir) return { kind: \"missing\", path };\n return { kind: existsSync(join(path, \"services\")) ? \"ok\" : \"no-services\", path };\n}\n\n/**\n * The docs repo is not there. Thrown rather than returned because every caller\n * of the enumeration wants the same thing — to stop — and a `[]` return is the\n * bug this closes. `message` is written for a human at a terminal: the CLI's\n * top-level handler prints it verbatim, and commands that catch it report\n * `repository-unavailable`.\n */\nexport class DocsRepoUnavailableError extends Error {\n constructor(\n readonly state: DocsRepoState,\n message: string,\n ) {\n super(message);\n this.name = \"DocsRepoUnavailableError\";\n }\n}\n\n/**\n * Refuse to enumerate a docs repo that is not one. `allow` names the states the\n * caller can honestly survive: features/ may be absent from a real docs repo\n * (nothing is in flight yet), so feature enumeration only insists the docs repo\n * EXISTS, while service enumeration insists it is shaped like a docs repo — a\n * `services/` directory is what makes it one.\n */\nexport function requireDocsRepo(docsDir: string, allow: DocsRepoKind[]): void {\n const state = docsRepoState(docsDir);\n if (allow.includes(state.kind)) return;\n if (state.kind === \"missing\") {\n throw new DocsRepoUnavailableError(\n state,\n `The configured docs repo does not exist: ${state.path}. ` +\n \"Fix `docsDir` in loam.json, clone the docs repo there, \" +\n \"or run `loam init --docs <dir> --create` to make a new one.\",\n );\n }\n throw new DocsRepoUnavailableError(\n state,\n `${state.path} is not a docs repo — it has no services/ directory. ` +\n \"Point `docsDir` in loam.json at the shared docs repo, \" +\n \"or run `loam init --docs <dir> --create` to make one.\",\n );\n}\n"]}
|