@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,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pin that tells a QUOTE from an EDIT, on the event axis.
|
|
3
|
+
*
|
|
4
|
+
* A feature's asyncapi.yaml is a complete document, so most of what it spells
|
|
5
|
+
* is quotation: the author restated the living contract around the slot they
|
|
6
|
+
* were changing. Without a pin the merge cannot tell the two apart and
|
|
7
|
+
* upserts both — the exact silent-revert the OpenAPI axis's pin closed, with
|
|
8
|
+
* no overlap between two features required, just two deltas over one service.
|
|
9
|
+
*
|
|
10
|
+
* Separate from `./merge.ts` because this is `loam rebase`'s half: it plans
|
|
11
|
+
* the pins a delta is missing, while the merge only ever reads pins already
|
|
12
|
+
* written. Slot-keyed over the three named sections exactly as the merge
|
|
13
|
+
* upserts (core/asyncapi/digest.ts owns the walker and the section→path
|
|
14
|
+
* spelling); an inline channel message is channel-slot interior and is never
|
|
15
|
+
* pinned on its own — SCHEMA.md's recorded decision.
|
|
16
|
+
*/
|
|
17
|
+
import { isMap } from "yaml";
|
|
18
|
+
import { writeTreeOver } from "../../openapi/contract-tree.js";
|
|
19
|
+
import { asyncapiRefusal } from "./error.js";
|
|
20
|
+
import { readEventTree, slotPair } from "./markers.js";
|
|
21
|
+
import { ASYNCAPI_BASELINE_KEY, asyncapiSlots, slotDigest, slotKey, slotsByKey, } from "../digest.js";
|
|
22
|
+
/**
|
|
23
|
+
* Pin every slot in a feature contract against the living one — what
|
|
24
|
+
* `loam rebase` writes on this axis.
|
|
25
|
+
*
|
|
26
|
+
* The pin is always `slotDigest` of the LIVING slot, never of the delta's
|
|
27
|
+
* own, and that single rule produces both merge verdicts by itself: a slot
|
|
28
|
+
* the author only QUOTED is byte-equal to living, so its pin equals its own
|
|
29
|
+
* content and classifies as a quote; one the author EDITED differs from its
|
|
30
|
+
* pin, so the merge writes it. A slot the living document lacks is
|
|
31
|
+
* `unresolved` and correct — there is no living version of a channel,
|
|
32
|
+
* operation or message the contract does not carry yet.
|
|
33
|
+
*/
|
|
34
|
+
export function pinAsyncapiSlots(featureText, livingText, service) {
|
|
35
|
+
const { doc, plain: featPlain } = readEventTree(featureText, "feature", service);
|
|
36
|
+
const { plain: livingPlain } = readEventTree(livingText, "living", service);
|
|
37
|
+
const livingBySlot = slotsByKey(asyncapiSlots(livingPlain));
|
|
38
|
+
const pins = [];
|
|
39
|
+
let edited = false;
|
|
40
|
+
for (const slot of asyncapiSlots(featPlain)) {
|
|
41
|
+
// A removal marker asserts a slot rather than restating it, so it has
|
|
42
|
+
// nothing to be based on; `asyncapi.remove-target-missing/-mismatch`
|
|
43
|
+
// are what guard it against a living slot that moved under it.
|
|
44
|
+
if (slot.remove)
|
|
45
|
+
continue;
|
|
46
|
+
const at = { section: slot.section, key: slot.key };
|
|
47
|
+
const from = slot.basedOn ?? null;
|
|
48
|
+
const living = livingBySlot.get(slotKey(slot));
|
|
49
|
+
if (living === undefined || living.node === null || typeof living.node !== "object" || Array.isArray(living.node)) {
|
|
50
|
+
pins.push({ ...at, status: "unresolved", from, to: null });
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
const digest = slotDigest(living.node);
|
|
54
|
+
if (from === digest) {
|
|
55
|
+
pins.push({ ...at, status: "unchanged", from: digest, to: digest });
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
// Located string-matched through the same door as every other slot
|
|
59
|
+
// access (markers.ts's slotPair): a channel written `404:` is the YAML
|
|
60
|
+
// number 404, which a raw `getIn("404")` misses — the miss used to grade
|
|
61
|
+
// every non-string-keyed slot `unwritable`, with an alias diagnosis
|
|
62
|
+
// nothing in the document backed, and the gate's own remedy was the
|
|
63
|
+
// command that had just refused. What stays refused: an aliased slot
|
|
64
|
+
// value (one shared value backs every use of an anchor, so stamping
|
|
65
|
+
// through it would pin every other use too — the OpenAPI pin's refusal,
|
|
66
|
+
// for the same data-loss reason) and a slot whose key is not a scalar,
|
|
67
|
+
// which no string can address.
|
|
68
|
+
const pair = slotPair(doc, slot.section, slot.key);
|
|
69
|
+
if (pair === undefined || !isMap(pair.value)) {
|
|
70
|
+
pins.push({ ...at, status: "unwritable", from, to: null });
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
pins.push({ ...at, status: from === null ? "pinned" : "repinned", from, to: digest });
|
|
74
|
+
pair.value.set(ASYNCAPI_BASELINE_KEY, digest);
|
|
75
|
+
edited = true;
|
|
76
|
+
}
|
|
77
|
+
if (!edited)
|
|
78
|
+
return { text: null, pins };
|
|
79
|
+
// Over the author's text, so the pins are the only lines this run changes
|
|
80
|
+
// (`writeTreeOver` says what re-serializing cost).
|
|
81
|
+
return { text: writeTreeOver(doc, featureText, asyncapiRefusal("feature", service)), pins };
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=pin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pin.js","sourceRoot":"","sources":["../../../../src/core/asyncapi/merge/pin.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The pin that tells a QUOTE from an EDIT, on the event axis.\n *\n * A feature's asyncapi.yaml is a complete document, so most of what it spells\n * is quotation: the author restated the living contract around the slot they\n * were changing. Without a pin the merge cannot tell the two apart and\n * upserts both — the exact silent-revert the OpenAPI axis's pin closed, with\n * no overlap between two features required, just two deltas over one service.\n *\n * Separate from `./merge.ts` because this is `loam rebase`'s half: it plans\n * the pins a delta is missing, while the merge only ever reads pins already\n * written. Slot-keyed over the three named sections exactly as the merge\n * upserts (core/asyncapi/digest.ts owns the walker and the section→path\n * spelling); an inline channel message is channel-slot interior and is never\n * pinned on its own — SCHEMA.md's recorded decision.\n */\nimport { isMap } from \"yaml\";\nimport { writeTreeOver } from \"../../openapi/contract-tree.js\";\nimport { asyncapiRefusal } from \"./error.js\";\nimport { readEventTree, slotPair } from \"./markers.js\";\nimport {\n ASYNCAPI_BASELINE_KEY,\n asyncapiSlots,\n slotDigest,\n slotKey,\n slotsByKey,\n type AsyncapiSection,\n} from \"../digest.js\";\n\n/** What happened to one slot's `x-loam-based-on`. */\nexport interface AsyncapiSlotPin {\n section: AsyncapiSection;\n key: string;\n status:\n /** It had no pin and now has one. */\n | \"pinned\"\n /** It named an older living version; it now names the current one. */\n | \"repinned\"\n /** It already named the current living version — no write. */\n | \"unchanged\"\n /** The living contract has no slot at this (section, key): this feature is adding it. */\n | \"unresolved\"\n /** Written as a YAML alias (one shared value backs every use) or under a key no string can address — loam will not stamp through either. */\n | \"unwritable\";\n from: string | null;\n to: string | null;\n}\n\nexport interface AsyncapiPinPlan {\n /** The rewritten contract, or null when no pin changes. */\n text: string | null;\n pins: AsyncapiSlotPin[];\n}\n\n/**\n * Pin every slot in a feature contract against the living one — what\n * `loam rebase` writes on this axis.\n *\n * The pin is always `slotDigest` of the LIVING slot, never of the delta's\n * own, and that single rule produces both merge verdicts by itself: a slot\n * the author only QUOTED is byte-equal to living, so its pin equals its own\n * content and classifies as a quote; one the author EDITED differs from its\n * pin, so the merge writes it. A slot the living document lacks is\n * `unresolved` and correct — there is no living version of a channel,\n * operation or message the contract does not carry yet.\n */\nexport function pinAsyncapiSlots(featureText: string, livingText: string, service: string): AsyncapiPinPlan {\n const { doc, plain: featPlain } = readEventTree(featureText, \"feature\", service);\n const { plain: livingPlain } = readEventTree(livingText, \"living\", service);\n\n const livingBySlot = slotsByKey(asyncapiSlots(livingPlain));\n const pins: AsyncapiSlotPin[] = [];\n let edited = false;\n for (const slot of asyncapiSlots(featPlain)) {\n // A removal marker asserts a slot rather than restating it, so it has\n // nothing to be based on; `asyncapi.remove-target-missing/-mismatch`\n // are what guard it against a living slot that moved under it.\n if (slot.remove) continue;\n\n const at = { section: slot.section, key: slot.key };\n const from = slot.basedOn ?? null;\n const living = livingBySlot.get(slotKey(slot));\n if (living === undefined || living.node === null || typeof living.node !== \"object\" || Array.isArray(living.node)) {\n pins.push({ ...at, status: \"unresolved\", from, to: null });\n continue;\n }\n const digest = slotDigest(living.node);\n if (from === digest) {\n pins.push({ ...at, status: \"unchanged\", from: digest, to: digest });\n continue;\n }\n // Located string-matched through the same door as every other slot\n // access (markers.ts's slotPair): a channel written `404:` is the YAML\n // number 404, which a raw `getIn(\"404\")` misses — the miss used to grade\n // every non-string-keyed slot `unwritable`, with an alias diagnosis\n // nothing in the document backed, and the gate's own remedy was the\n // command that had just refused. What stays refused: an aliased slot\n // value (one shared value backs every use of an anchor, so stamping\n // through it would pin every other use too — the OpenAPI pin's refusal,\n // for the same data-loss reason) and a slot whose key is not a scalar,\n // which no string can address.\n const pair = slotPair(doc, slot.section, slot.key);\n if (pair === undefined || !isMap(pair.value)) {\n pins.push({ ...at, status: \"unwritable\", from, to: null });\n continue;\n }\n pins.push({ ...at, status: from === null ? \"pinned\" : \"repinned\", from, to: digest });\n pair.value.set(ASYNCAPI_BASELINE_KEY, digest);\n edited = true;\n }\n\n if (!edited) return { text: null, pins };\n // Over the author's text, so the pins are the only lines this run changes\n // (`writeTreeOver` says what re-serializing cost).\n return { text: writeTreeOver(doc, featureText, asyncapiRefusal(\"feature\", service)), pins };\n}\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The read model of one AsyncAPI document — what `./read.ts`'s walk produces
|
|
3
|
+
* and every consumer of the axis branches on. Split from `read.ts` when the
|
|
4
|
+
* `asyncapiFromText` extraction pushed that module past the 300-line ceiling:
|
|
5
|
+
* the walk and its result are two subjects (`read.ts` says HOW a document is
|
|
6
|
+
* read, this file says WHAT a read answers), and the type block is the seam
|
|
7
|
+
* that already existed. The doctrine comments travel with the fields they
|
|
8
|
+
* explain — they are the documentation of the model, not of the walk.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../../src/core/asyncapi/model.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG","sourcesContent":["/**\n * The read model of one AsyncAPI document — what `./read.ts`'s walk produces\n * and every consumer of the axis branches on. Split from `read.ts` when the\n * `asyncapiFromText` extraction pushed that module past the 300-line ceiling:\n * the walk and its result are two subjects (`read.ts` says HOW a document is\n * read, this file says WHAT a read answers), and the type block is the seam\n * that already existed. The doctrine comments travel with the fields they\n * explain — they are the documentation of the model, not of the walk.\n */\n\n/** One message declaration, as the reader sees it. */\nexport interface EventMessage {\n /**\n * The join token — what a landscape edge's `metadata { publishes }` and a\n * requirement's `Publishes:` line name.\n *\n * The Message Object's own `name` when it has one, otherwise the key it is\n * declared under. Both are legal AsyncAPI, and the key is what an author who\n * never wrote a `name` would reasonably expect to reference; falling back to\n * it means a minimal hand-written contract still joins to the spine.\n */\n name: string;\n /**\n * Where it was declared — `components.messages.<key>` or\n * `channels.<key>.messages.<key>`. Carried so `asyncapi.duplicate-message` can\n * name both slots instead of only saying that a name repeats, the way\n * `openapi.duplicate-operationid` names both `METHOD /path` slots.\n */\n slot: string;\n /**\n * The declaration plus every internal `$ref` it reaches, transitively — the\n * OpenAPI axis's `closureDigester` (core/openapi/digest.ts), so a payload\n * schema factored into `components.schemas` still moves it. Content equality\n * only, and so inside the stance read.ts states: what `loam diff` compares to\n * say a message changed, never a join on a payload field. Absent on a removal\n * marker, which declares nothing to compare.\n */\n closureDigest?: string;\n /**\n * Present when the declaration's payload defines no shape a consumer could\n * code against (`payloadUndeclared`, depth.ts). Set only when true, and\n * never set for a payload declaring a non-JSON `schemaFormat`.\n */\n payloadEmpty?: true;\n /**\n * Present when the declaration carries `x-loam-remove: true` — a FEATURE\n * delta retiring it. A marker asserts a slot rather than declaring a\n * message, so it joins nothing: excluded from sent/received and from\n * duplicate counting, the discipline `core/openapi/doc.ts` set for\n * operation markers. Set only when true, like `payloadEmpty`.\n */\n remove?: true;\n}\n\n/** The parse of one AsyncAPI document: what it declares, and whether it could be read at all. */\nexport interface AsyncapiDoc {\n /** Every message declaration in the document, in document order. */\n messages: EventMessage[];\n /** Message names reachable from an `action: send` operation — what this service PRODUCES. */\n sent: string[];\n /** Message names reachable from an `action: receive` operation — what this service CONSUMES. */\n received: string[];\n /**\n * Names declared in more than one slot. Every join on this axis is by name, so\n * two slots claiming one name is the same ambiguity `openapi.duplicate-operationid`\n * grades: the join picks one arbitrarily and the other declaration is invisible.\n */\n duplicateNames: string[];\n /**\n * True when the file EXISTS but cannot be read as an AsyncAPI document —\n * broken YAML, non-UTF-8 bytes, or a document that is not a mapping. A missing\n * file is not unreadable (absence is `service.no-asyncapi`'s question), and an\n * empty one parses to null and honestly declares nothing.\n */\n unreadable: boolean;\n /** The parser's own message, when there is one to quote back. */\n error?: string;\n /** Internal `#/` refs that resolve to nothing in this document (depth.ts). */\n danglingRefs: string[];\n /**\n * Where `x-loam-remove: true` appears — at ANY depth (digest.ts's\n * `removalMarkerPaths`): the three slot depths the format spec gives the\n * key meaning at, inline channel messages (channel-slot interior the merge\n * strips at that nested depth), and every place the key means nothing —\n * the document root, `info`, a `components` sibling. Feature-only\n * bookkeeping wherever it sits: `validate` grades any of these in a LIVING\n * contract as `asyncapi.remove-marker-living`, and the sweep is as deep as\n * the strip so a leaked marker can never be invisible to it.\n */\n markers: string[];\n}\n"]}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Who produces what across the fleet, read one contract at a time.
|
|
3
|
+
*
|
|
4
|
+
* Separate from `./read.ts` because it asks a question no single document can
|
|
5
|
+
* answer: a message's producer is a claim about some OTHER service's contract,
|
|
6
|
+
* so this walk is the only part of the axis whose answer depends on how much of
|
|
7
|
+
* the fleet was readable. That incompleteness is a value it returns, not a
|
|
8
|
+
* failure it hides — a consumer check that treated an unreadable producer as
|
|
9
|
+
* "nobody sends this" would report a phantom orphan.
|
|
10
|
+
*/
|
|
11
|
+
import { readAsyncapi } from "./read.js";
|
|
12
|
+
import { locateServicePaths } from "../repo/service-target.js";
|
|
13
|
+
/**
|
|
14
|
+
* Which services in the fleet declare an `action: send` for each message name.
|
|
15
|
+
*
|
|
16
|
+
* The one question on this axis that no single repository can answer, and the
|
|
17
|
+
* reason `validate --service` reads more than its own service here: a consumer
|
|
18
|
+
* joins to a message the PRODUCER owns, so "does anybody publish this" is a
|
|
19
|
+
* fleet fact. Zero producers is `spine.message-unproduced`; two are
|
|
20
|
+
* `asyncapi.message-contested`, where every consumer's join picks one
|
|
21
|
+
* arbitrarily.
|
|
22
|
+
*
|
|
23
|
+
* The two answers rest on different evidence, and only one of them survives an
|
|
24
|
+
* unreadable contract. Finding two producers is POSITIVE evidence and stays
|
|
25
|
+
* true whatever else in the fleet fails to parse. Finding none is an argument
|
|
26
|
+
* from absence, and one broken file makes it worthless — skipping that service
|
|
27
|
+
* silently would turn its outage into one `spine.message-unproduced` per
|
|
28
|
+
* consuming edge across the whole fleet, every one of them pointing at the
|
|
29
|
+
* wrong repository. So the unreadable services are reported rather than
|
|
30
|
+
* skipped, and the caller suspends the negative answer while any exist.
|
|
31
|
+
*
|
|
32
|
+
* The cost is N small YAML parses, not N LikeC4 workspace spins — the latter is
|
|
33
|
+
* what makes `validate --all` expensive (SCHEMA.md, "Operating at fleet scale"),
|
|
34
|
+
* and a context memoizes these reads across the run.
|
|
35
|
+
*/
|
|
36
|
+
export async function producersByMessage(docsDir, services, context) {
|
|
37
|
+
const byMessage = new Map();
|
|
38
|
+
const unreadable = [];
|
|
39
|
+
for (const service of services) {
|
|
40
|
+
const doc = await readAsyncapi((await locateServicePaths(docsDir, service, context)).asyncapi, context);
|
|
41
|
+
if (doc.unreadable) {
|
|
42
|
+
unreadable.push(service);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
for (const name of doc.sent)
|
|
46
|
+
byMessage.set(name, [...(byMessage.get(name) ?? []), service]);
|
|
47
|
+
}
|
|
48
|
+
return { byMessage, unreadable };
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=producers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"producers.js","sourceRoot":"","sources":["../../../src/core/asyncapi/producers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAGzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAe/D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,OAAgB,EAChB,QAAoC,EACpC,OAAsB;IAEtB,MAAM,SAAS,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC9C,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,CAAC,MAAM,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACxG,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;YACnB,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACzB,SAAS;QACX,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,IAAI;YAAE,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC;IAC9F,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC;AACnC,CAAC","sourcesContent":["/**\n * Who produces what across the fleet, read one contract at a time.\n *\n * Separate from `./read.ts` because it asks a question no single document can\n * answer: a message's producer is a claim about some OTHER service's contract,\n * so this walk is the only part of the axis whose answer depends on how much of\n * the fleet was readable. That incompleteness is a value it returns, not a\n * failure it hides — a consumer check that treated an unreadable producer as\n * \"nobody sends this\" would report a phantom orphan.\n */\nimport { readAsyncapi } from \"./read.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\nimport type { PathableService } from \"../kernel/ids/service.js\";\nimport { locateServicePaths } from \"../repo/service-target.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\n\n/** Who produces what across the fleet, and whether that view is complete. */\nexport interface FleetProducers {\n /** Message name → the services declaring an `action: send` for it. */\n byMessage: Map<string, string[]>;\n /**\n * Services whose `asyncapi.yaml` exists and could not be read. Non-empty means\n * the ABSENCE of a producer proves nothing: one of these files may well\n * declare the message, and nobody can tell without fixing it first.\n */\n unreadable: string[];\n}\n\n/**\n * Which services in the fleet declare an `action: send` for each message name.\n *\n * The one question on this axis that no single repository can answer, and the\n * reason `validate --service` reads more than its own service here: a consumer\n * joins to a message the PRODUCER owns, so \"does anybody publish this\" is a\n * fleet fact. Zero producers is `spine.message-unproduced`; two are\n * `asyncapi.message-contested`, where every consumer's join picks one\n * arbitrarily.\n *\n * The two answers rest on different evidence, and only one of them survives an\n * unreadable contract. Finding two producers is POSITIVE evidence and stays\n * true whatever else in the fleet fails to parse. Finding none is an argument\n * from absence, and one broken file makes it worthless — skipping that service\n * silently would turn its outage into one `spine.message-unproduced` per\n * consuming edge across the whole fleet, every one of them pointing at the\n * wrong repository. So the unreadable services are reported rather than\n * skipped, and the caller suspends the negative answer while any exist.\n *\n * The cost is N small YAML parses, not N LikeC4 workspace spins — the latter is\n * what makes `validate --all` expensive (SCHEMA.md, \"Operating at fleet scale\"),\n * and a context memoizes these reads across the run.\n */\nexport async function producersByMessage(\n docsDir: DocsDir,\n services: readonly PathableService[],\n context?: FleetContext,\n): Promise<FleetProducers> {\n const byMessage = new Map<string, string[]>();\n const unreadable: string[] = [];\n for (const service of services) {\n const doc = await readAsyncapi((await locateServicePaths(docsDir, service, context)).asyncapi, context);\n if (doc.unreadable) {\n unreadable.push(service);\n continue;\n }\n for (const name of doc.sent) byMessage.set(name, [...(byMessage.get(name) ?? []), service]);\n }\n return { byMessage, unreadable };\n}\n\n"]}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { isUtf8 } from "node:buffer";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { parse } from "yaml";
|
|
5
|
+
import { danglingRefs, deref, payloadUndeclared } from "./depth.js";
|
|
6
|
+
import { entriesOf, isSlotRemoval, removalMarkerPaths } from "./digest.js";
|
|
7
|
+
import { closureDigester } from "../openapi/digest.js";
|
|
8
|
+
/**
|
|
9
|
+
* The async contract axis: AsyncAPI 3.0, read the way `core/openapi/doc.ts` reads
|
|
10
|
+
* OpenAPI — a shallow structural walk over the `yaml` parse, never a real
|
|
11
|
+
* AsyncAPI parser. `@asyncapi/parser` would be a fourth runtime dependency
|
|
12
|
+
* (AGENTS.md: adding one is a product decision), and loam needs a slice of the
|
|
13
|
+
* document so thin that the parser's whole model would be dead weight.
|
|
14
|
+
*
|
|
15
|
+
* 3.0 only, deliberately. Its operations are named top-level objects carrying
|
|
16
|
+
* `action: send|receive`, which is the exact analog of an `operationId`; 2.x
|
|
17
|
+
* spells the same thing as `publish`/`subscribe` nested under a channel, where
|
|
18
|
+
* the two words are notoriously ambiguous about whose perspective they take.
|
|
19
|
+
* Supporting one dialect is cheaper than supporting two. A 2.x (or 1.x)
|
|
20
|
+
* document declares no `operations` at all, and it used to read as a contract
|
|
21
|
+
* with no messages: one `asyncapi.yaml` copied in from an older service turned
|
|
22
|
+
* into a `spine.message-undefined` per landscape edge, a
|
|
23
|
+
* `spec-event.message-undefined` per requirement and a knock-on
|
|
24
|
+
* `spine.message-unproduced` on every consumer, none of them naming the
|
|
25
|
+
* version and every fix text saying "declare the operation" about a file that
|
|
26
|
+
* does declare it, as `publish`/`subscribe`. That is exactly the false
|
|
27
|
+
* diagnosis the unreadable policy below exists to prevent, so an older
|
|
28
|
+
* version now reads as UNREADABLE (`asyncapiDocOf`): one `asyncapi.invalid`
|
|
29
|
+
* naming the version and the upgrade command, and nothing graded against it.
|
|
30
|
+
* `loam diff` skips such a document when the base ref holds the same bytes
|
|
31
|
+
* (core/diff/semantic.ts's `UNTOUCHED_SKIPS`); without that, one unconverted
|
|
32
|
+
* file suspended the event axis on every run and failed every PR's diff.
|
|
33
|
+
*
|
|
34
|
+
* WHAT THIS READER MUST NEVER DO: join on anything inside a message's `payload`.
|
|
35
|
+
* The payload is JSON Schema today and may be Avro later, and that switch is
|
|
36
|
+
* meant to be a line in the document (`schemaFormat`) rather than a branch in
|
|
37
|
+
* loam. Every check on this axis joins on a message NAME; nothing joins on a
|
|
38
|
+
* field, and nothing under `payload` may ever contribute one. The day
|
|
39
|
+
* something here reads a `required` array or a `fields` list INTO A JOIN, the
|
|
40
|
+
* Avro migration stops being free. The one look the reader takes inside is
|
|
41
|
+
* `payloadUndeclared` (depth.ts) — a presence probe that checks whether any
|
|
42
|
+
* shape was declared at all, reads key existence and never a value, and skips
|
|
43
|
+
* any payload declaring a non-JSON `schemaFormat`, so the stance holds. The
|
|
44
|
+
* slot digests (./digest.ts) are COMPATIBLE with it, not an exception: they
|
|
45
|
+
* hash payload bytes as content equality — a changed payload moves the slot's
|
|
46
|
+
* identity — and content equality is not a join; nothing a digest reads ever
|
|
47
|
+
* contributes a name to the spine. The per-message `closureDigest` `loam diff`
|
|
48
|
+
* compares is the same kind of read followed through `$ref`s: it hashes what
|
|
49
|
+
* the payload points at, transitively, and still never names a field.
|
|
50
|
+
*/
|
|
51
|
+
/*
|
|
52
|
+
* The `EventMessage`/`AsyncapiDoc` read model lives in `./model.ts` — split
|
|
53
|
+
* there when the `asyncapiFromText` extraction pushed this module past the
|
|
54
|
+
* 300-line ceiling. This module keeps the walk; that one keeps what the walk
|
|
55
|
+
* answers.
|
|
56
|
+
*/
|
|
57
|
+
/**
|
|
58
|
+
* A message's join token: its `name`, or the key it is declared under.
|
|
59
|
+
* Exported for the merge (./merge/merge.ts), whose removal exactness compares
|
|
60
|
+
* this same spelling — a second definition of the fallback rule is how a
|
|
61
|
+
* marker would delete a message the reader joins under a different name.
|
|
62
|
+
*/
|
|
63
|
+
export function messageName(node, key) {
|
|
64
|
+
if (node !== null && typeof node === "object" && !Array.isArray(node)) {
|
|
65
|
+
const name = node["name"];
|
|
66
|
+
if (typeof name === "string" && name.trim().length > 0)
|
|
67
|
+
return name.trim();
|
|
68
|
+
}
|
|
69
|
+
return key;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Read an AsyncAPI 3.0 document into the slice loam joins on: the messages it
|
|
73
|
+
* declares, and which of them it sends and receives.
|
|
74
|
+
*
|
|
75
|
+
* The send/receive sets are what make the spine directional, and the direction
|
|
76
|
+
* is not decoration: on the HTTP axis the PROVIDER owns the contract and a
|
|
77
|
+
* consumer's edge is checked against it, while here the PRODUCER owns the
|
|
78
|
+
* message and a consumer joins to it from another repository entirely. That
|
|
79
|
+
* inversion is why `spine.message-unproduced` has no OpenAPI analog.
|
|
80
|
+
*
|
|
81
|
+
* An unreadable document yields empty sets PLUS the `unreadable` flag, the
|
|
82
|
+
* policy every reader here follows: parsers never diagnose. Swallowing the
|
|
83
|
+
* failure into empty sets would make a broken contract indistinguishable from
|
|
84
|
+
* one that declares nothing, and every inbound edge would be graded
|
|
85
|
+
* `spine.message-undefined` — a false diagnosis pointing at the landscape when
|
|
86
|
+
* the truth is this file.
|
|
87
|
+
*/
|
|
88
|
+
export async function readAsyncapi(asyncapiPath, context) {
|
|
89
|
+
if (context !== undefined)
|
|
90
|
+
return context.readAsyncapi(asyncapiPath);
|
|
91
|
+
if (!existsSync(asyncapiPath))
|
|
92
|
+
return empty();
|
|
93
|
+
const bytes = await readFile(asyncapiPath);
|
|
94
|
+
// Bytes that are not UTF-8 are as unreadable as broken YAML and for a worse
|
|
95
|
+
// reason: `toString("utf8")` substitutes U+FFFD and hands the parser a
|
|
96
|
+
// document nobody wrote. The openapi axis learned this the same way.
|
|
97
|
+
if (!isUtf8(bytes))
|
|
98
|
+
return { ...empty(), unreadable: true, error: "file is not valid UTF-8" };
|
|
99
|
+
return asyncapiFromText(bytes.toString("utf8"));
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* The same read over text already in hand — the parse half of `readAsyncapi`,
|
|
103
|
+
* split out so `loam diff` can read a contract fetched from a base git ref
|
|
104
|
+
* (core/diff/base-state.ts) without writing it to disk. The YAML-throw catch
|
|
105
|
+
* lives here and nowhere else; `asyncapiDocOf` below owns everything after
|
|
106
|
+
* the parse, and the byte concerns (existence, UTF-8) stay with the reader
|
|
107
|
+
* that holds the bytes.
|
|
108
|
+
*/
|
|
109
|
+
export function asyncapiFromText(text) {
|
|
110
|
+
let doc;
|
|
111
|
+
try {
|
|
112
|
+
doc = parse(text);
|
|
113
|
+
}
|
|
114
|
+
catch (e) {
|
|
115
|
+
return { ...empty(), unreadable: true, error: e instanceof Error ? e.message : String(e) };
|
|
116
|
+
}
|
|
117
|
+
return asyncapiDocOf(doc);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* The same read over an already-parsed root — what the coherence gate's
|
|
121
|
+
* merge simulation grades (core/coherence/events/), where the "file" is a
|
|
122
|
+
* document the merge computed and never wrote. One spelling of the walk for
|
|
123
|
+
* both entries, so a simulated contract can never read differently from the
|
|
124
|
+
* living file the archive would produce from it.
|
|
125
|
+
*/
|
|
126
|
+
export function asyncapiDocOf(doc) {
|
|
127
|
+
// A scalar or sequence document has no mapping to look `channels` up in, so
|
|
128
|
+
// nothing can be concluded from it. null (an empty file) stays readable — it
|
|
129
|
+
// declares nothing, and says so honestly.
|
|
130
|
+
if (doc !== null && (typeof doc !== "object" || Array.isArray(doc))) {
|
|
131
|
+
return { ...empty(), unreadable: true, error: "document is not a YAML mapping" };
|
|
132
|
+
}
|
|
133
|
+
if (doc === null)
|
|
134
|
+
return empty();
|
|
135
|
+
const root = doc;
|
|
136
|
+
// A pre-3.0 document is not a 3.0 document with nothing in it, so it takes
|
|
137
|
+
// the unreadable path rather than the empty one (see the module header).
|
|
138
|
+
// Only a version that SAYS 1.x or 2.x is refused: a file with no `asyncapi:`
|
|
139
|
+
// key at all (a hand-trimmed feature delta that restates slots and not the
|
|
140
|
+
// header) keeps reading as 3.0, and so does any later major, which is a
|
|
141
|
+
// question for the day it exists rather than a guess made now. A bare `2`
|
|
142
|
+
// or `2.6` parses as a YAML number, hence the String() and the `$`.
|
|
143
|
+
const version = root["asyncapi"];
|
|
144
|
+
if ((typeof version === "string" || typeof version === "number") && /^[12](\.|$)/.test(String(version))) {
|
|
145
|
+
return {
|
|
146
|
+
...empty(),
|
|
147
|
+
unreadable: true,
|
|
148
|
+
error: `AsyncAPI ${String(version)}: loam reads AsyncAPI 3.0 only; \`asyncapi convert --target-version=3.0.0\` upgrades it`,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
const messages = [];
|
|
152
|
+
const seen = new Map();
|
|
153
|
+
const closureDigest = closureDigester(root);
|
|
154
|
+
const declare = (name, slot, node) => {
|
|
155
|
+
// A declaration carrying the removal marker asserts a slot rather than
|
|
156
|
+
// declaring a message: it is listed (with `remove`) so the gate can see
|
|
157
|
+
// it, but it joins nothing — not sent/received, not the duplicate count.
|
|
158
|
+
if (isSlotRemoval(node)) {
|
|
159
|
+
messages.push({ name, slot, remove: true });
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
messages.push({ name, slot, closureDigest: closureDigest(node), ...(payloadUndeclared(root, node) ? { payloadEmpty: true } : {}) });
|
|
163
|
+
seen.set(name, [...(seen.get(name) ?? []), slot]);
|
|
164
|
+
};
|
|
165
|
+
// `components.messages` — the ordinary place a message is declared.
|
|
166
|
+
for (const [key, node] of entriesOf(root["components"]?.["messages"])) {
|
|
167
|
+
declare(messageName(node, key), `components.messages.${key}`, node);
|
|
168
|
+
}
|
|
169
|
+
// `channels.<ck>.messages.<mk>` — an entry here is either an ALIAS of a
|
|
170
|
+
// components declaration (a `$ref`) or an inline declaration of its own. Only
|
|
171
|
+
// the second is a new slot: counting an alias would report every properly
|
|
172
|
+
// factored document as declaring each message twice, which is the shape the
|
|
173
|
+
// spec's own examples use.
|
|
174
|
+
const channelMessages = new Map();
|
|
175
|
+
for (const [ck, channel] of entriesOf(root["channels"])) {
|
|
176
|
+
// A channel-slot removal retires the whole channel, inline interior
|
|
177
|
+
// included: nothing under it declares or joins anything any more.
|
|
178
|
+
if (isSlotRemoval(channel)) {
|
|
179
|
+
channelMessages.set(ck, []);
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const names = [];
|
|
183
|
+
for (const [mk, entry] of entriesOf(channel?.["messages"])) {
|
|
184
|
+
const isAlias = entry !== null && typeof entry === "object" && !Array.isArray(entry) && "$ref" in entry;
|
|
185
|
+
const { node, key } = deref(root, entry, mk);
|
|
186
|
+
const name = messageName(node, key);
|
|
187
|
+
// A name whose declaration is being retired stays off the channel's
|
|
188
|
+
// list, whether the marker sits on the aliased components entry or on
|
|
189
|
+
// the inline declaration itself — the operation fallback below must
|
|
190
|
+
// not join through a message the feature is removing.
|
|
191
|
+
if (!isSlotRemoval(node))
|
|
192
|
+
names.push(name);
|
|
193
|
+
if (!isAlias)
|
|
194
|
+
declare(name, `channels.${ck}.messages.${mk}`, node);
|
|
195
|
+
}
|
|
196
|
+
channelMessages.set(ck, names);
|
|
197
|
+
}
|
|
198
|
+
const sent = new Set();
|
|
199
|
+
const received = new Set();
|
|
200
|
+
for (const [, operation] of entriesOf(root["operations"])) {
|
|
201
|
+
const op = operation;
|
|
202
|
+
// An operation-slot removal retires the operation: it contributes no
|
|
203
|
+
// send/receive whatever its `action` says.
|
|
204
|
+
if (isSlotRemoval(op))
|
|
205
|
+
continue;
|
|
206
|
+
const action = op?.["action"];
|
|
207
|
+
if (action !== "send" && action !== "receive")
|
|
208
|
+
continue;
|
|
209
|
+
const into = action === "send" ? sent : received;
|
|
210
|
+
// The channel this operation acts on, by pointer — its key is what the
|
|
211
|
+
// fallback below indexes.
|
|
212
|
+
const channelRef = op?.["channel"]?.["$ref"];
|
|
213
|
+
const channelKey = typeof channelRef === "string" ? channelRef.slice(channelRef.lastIndexOf("/") + 1) : undefined;
|
|
214
|
+
const listed = op?.["messages"];
|
|
215
|
+
if (Array.isArray(listed) && listed.length > 0) {
|
|
216
|
+
for (const entry of listed) {
|
|
217
|
+
const { node, key } = deref(root, entry, "");
|
|
218
|
+
// A pointer that resolves nowhere contributes no name rather than an
|
|
219
|
+
// empty one: a phantom "" would join to nothing and read as a message
|
|
220
|
+
// the service produces.
|
|
221
|
+
if (node === undefined && key === "")
|
|
222
|
+
continue;
|
|
223
|
+
// A pointer into a declaration being retired joins nothing either —
|
|
224
|
+
// the marker means the message is leaving the contract.
|
|
225
|
+
if (isSlotRemoval(node))
|
|
226
|
+
continue;
|
|
227
|
+
const name = messageName(node, key);
|
|
228
|
+
if (name.length > 0)
|
|
229
|
+
into.add(name);
|
|
230
|
+
}
|
|
231
|
+
continue;
|
|
232
|
+
}
|
|
233
|
+
// AsyncAPI 3: an operation that lists no messages applies to every message
|
|
234
|
+
// of its channel. Omitting the list is the normal shape of a minimal
|
|
235
|
+
// hand-written contract — exactly what a fleet with no registry writes — so
|
|
236
|
+
// reading it as "produces nothing" would report the common case broken.
|
|
237
|
+
if (channelKey !== undefined)
|
|
238
|
+
for (const name of channelMessages.get(channelKey) ?? [])
|
|
239
|
+
into.add(name);
|
|
240
|
+
}
|
|
241
|
+
const duplicateNames = [...seen].filter(([, slots]) => slots.length > 1).map(([name]) => name);
|
|
242
|
+
return {
|
|
243
|
+
messages,
|
|
244
|
+
sent: [...sent],
|
|
245
|
+
received: [...received],
|
|
246
|
+
duplicateNames,
|
|
247
|
+
unreadable: false,
|
|
248
|
+
danglingRefs: danglingRefs(root),
|
|
249
|
+
// One deep scan rather than pushes scattered through the walk above: the
|
|
250
|
+
// walk only visits the depths that JOIN, and a marker leaked anywhere
|
|
251
|
+
// else (the root, `info`) was invisible to the living sweep while the
|
|
252
|
+
// strip still owed its removal.
|
|
253
|
+
markers: removalMarkerPaths(root, ""),
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
function empty() {
|
|
257
|
+
return { messages: [], sent: [], received: [], duplicateNames: [], unreadable: false, danglingRefs: [], markers: [] };
|
|
258
|
+
}
|
|
259
|
+
/** The slots one message name is declared in — what `asyncapi.duplicate-message` names. */
|
|
260
|
+
export function slotsOf(doc, name) {
|
|
261
|
+
return doc.messages.filter((m) => m.name === name).map((m) => m.slot);
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=read.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read.js","sourceRoot":"","sources":["../../../src/core/asyncapi/read.ts"],"names":[],"mappings":"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","sourcesContent":["import { isUtf8 } from \"node:buffer\";\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { parse } from \"yaml\";\nimport { danglingRefs, deref, payloadUndeclared } from \"./depth.js\";\nimport { entriesOf, isSlotRemoval, removalMarkerPaths } from \"./digest.js\";\nimport { closureDigester } from \"../openapi/digest.js\";\nimport type { AsyncapiDoc, EventMessage } from \"./model.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\n\n/**\n * The async contract axis: AsyncAPI 3.0, read the way `core/openapi/doc.ts` reads\n * OpenAPI — a shallow structural walk over the `yaml` parse, never a real\n * AsyncAPI parser. `@asyncapi/parser` would be a fourth runtime dependency\n * (AGENTS.md: adding one is a product decision), and loam needs a slice of the\n * document so thin that the parser's whole model would be dead weight.\n *\n * 3.0 only, deliberately. Its operations are named top-level objects carrying\n * `action: send|receive`, which is the exact analog of an `operationId`; 2.x\n * spells the same thing as `publish`/`subscribe` nested under a channel, where\n * the two words are notoriously ambiguous about whose perspective they take.\n * Supporting one dialect is cheaper than supporting two. A 2.x (or 1.x)\n * document declares no `operations` at all, and it used to read as a contract\n * with no messages: one `asyncapi.yaml` copied in from an older service turned\n * into a `spine.message-undefined` per landscape edge, a\n * `spec-event.message-undefined` per requirement and a knock-on\n * `spine.message-unproduced` on every consumer, none of them naming the\n * version and every fix text saying \"declare the operation\" about a file that\n * does declare it, as `publish`/`subscribe`. That is exactly the false\n * diagnosis the unreadable policy below exists to prevent, so an older\n * version now reads as UNREADABLE (`asyncapiDocOf`): one `asyncapi.invalid`\n * naming the version and the upgrade command, and nothing graded against it.\n * `loam diff` skips such a document when the base ref holds the same bytes\n * (core/diff/semantic.ts's `UNTOUCHED_SKIPS`); without that, one unconverted\n * file suspended the event axis on every run and failed every PR's diff.\n *\n * WHAT THIS READER MUST NEVER DO: join on anything inside a message's `payload`.\n * The payload is JSON Schema today and may be Avro later, and that switch is\n * meant to be a line in the document (`schemaFormat`) rather than a branch in\n * loam. Every check on this axis joins on a message NAME; nothing joins on a\n * field, and nothing under `payload` may ever contribute one. The day\n * something here reads a `required` array or a `fields` list INTO A JOIN, the\n * Avro migration stops being free. The one look the reader takes inside is\n * `payloadUndeclared` (depth.ts) — a presence probe that checks whether any\n * shape was declared at all, reads key existence and never a value, and skips\n * any payload declaring a non-JSON `schemaFormat`, so the stance holds. The\n * slot digests (./digest.ts) are COMPATIBLE with it, not an exception: they\n * hash payload bytes as content equality — a changed payload moves the slot's\n * identity — and content equality is not a join; nothing a digest reads ever\n * contributes a name to the spine. The per-message `closureDigest` `loam diff`\n * compares is the same kind of read followed through `$ref`s: it hashes what\n * the payload points at, transitively, and still never names a field.\n */\n\n/*\n * The `EventMessage`/`AsyncapiDoc` read model lives in `./model.ts` — split\n * there when the `asyncapiFromText` extraction pushed this module past the\n * 300-line ceiling. This module keeps the walk; that one keeps what the walk\n * answers.\n */\n\n/**\n * A message's join token: its `name`, or the key it is declared under.\n * Exported for the merge (./merge/merge.ts), whose removal exactness compares\n * this same spelling — a second definition of the fallback rule is how a\n * marker would delete a message the reader joins under a different name.\n */\nexport function messageName(node: unknown, key: string): string {\n if (node !== null && typeof node === \"object\" && !Array.isArray(node)) {\n const name = (node as Record<string, unknown>)[\"name\"];\n if (typeof name === \"string\" && name.trim().length > 0) return name.trim();\n }\n return key;\n}\n\n/**\n * Read an AsyncAPI 3.0 document into the slice loam joins on: the messages it\n * declares, and which of them it sends and receives.\n *\n * The send/receive sets are what make the spine directional, and the direction\n * is not decoration: on the HTTP axis the PROVIDER owns the contract and a\n * consumer's edge is checked against it, while here the PRODUCER owns the\n * message and a consumer joins to it from another repository entirely. That\n * inversion is why `spine.message-unproduced` has no OpenAPI analog.\n *\n * An unreadable document yields empty sets PLUS the `unreadable` flag, the\n * policy every reader here follows: parsers never diagnose. Swallowing the\n * failure into empty sets would make a broken contract indistinguishable from\n * one that declares nothing, and every inbound edge would be graded\n * `spine.message-undefined` — a false diagnosis pointing at the landscape when\n * the truth is this file.\n */\nexport async function readAsyncapi(asyncapiPath: string, context?: FleetContext): Promise<AsyncapiDoc> {\n if (context !== undefined) return context.readAsyncapi(asyncapiPath);\n if (!existsSync(asyncapiPath)) return empty();\n const bytes = await readFile(asyncapiPath);\n // Bytes that are not UTF-8 are as unreadable as broken YAML and for a worse\n // reason: `toString(\"utf8\")` substitutes U+FFFD and hands the parser a\n // document nobody wrote. The openapi axis learned this the same way.\n if (!isUtf8(bytes)) return { ...empty(), unreadable: true, error: \"file is not valid UTF-8\" };\n return asyncapiFromText(bytes.toString(\"utf8\"));\n}\n\n/**\n * The same read over text already in hand — the parse half of `readAsyncapi`,\n * split out so `loam diff` can read a contract fetched from a base git ref\n * (core/diff/base-state.ts) without writing it to disk. The YAML-throw catch\n * lives here and nowhere else; `asyncapiDocOf` below owns everything after\n * the parse, and the byte concerns (existence, UTF-8) stay with the reader\n * that holds the bytes.\n */\nexport function asyncapiFromText(text: string): AsyncapiDoc {\n let doc: unknown;\n try {\n doc = parse(text);\n } catch (e) {\n return { ...empty(), unreadable: true, error: e instanceof Error ? e.message : String(e) };\n }\n return asyncapiDocOf(doc);\n}\n\n/**\n * The same read over an already-parsed root — what the coherence gate's\n * merge simulation grades (core/coherence/events/), where the \"file\" is a\n * document the merge computed and never wrote. One spelling of the walk for\n * both entries, so a simulated contract can never read differently from the\n * living file the archive would produce from it.\n */\nexport function asyncapiDocOf(doc: unknown): AsyncapiDoc {\n // A scalar or sequence document has no mapping to look `channels` up in, so\n // nothing can be concluded from it. null (an empty file) stays readable — it\n // declares nothing, and says so honestly.\n if (doc !== null && (typeof doc !== \"object\" || Array.isArray(doc))) {\n return { ...empty(), unreadable: true, error: \"document is not a YAML mapping\" };\n }\n if (doc === null) return empty();\n\n const root = doc as Record<string, unknown>;\n // A pre-3.0 document is not a 3.0 document with nothing in it, so it takes\n // the unreadable path rather than the empty one (see the module header).\n // Only a version that SAYS 1.x or 2.x is refused: a file with no `asyncapi:`\n // key at all (a hand-trimmed feature delta that restates slots and not the\n // header) keeps reading as 3.0, and so does any later major, which is a\n // question for the day it exists rather than a guess made now. A bare `2`\n // or `2.6` parses as a YAML number, hence the String() and the `$`.\n const version = root[\"asyncapi\"];\n if ((typeof version === \"string\" || typeof version === \"number\") && /^[12](\\.|$)/.test(String(version))) {\n return {\n ...empty(),\n unreadable: true,\n error: `AsyncAPI ${String(version)}: loam reads AsyncAPI 3.0 only; \\`asyncapi convert --target-version=3.0.0\\` upgrades it`,\n };\n }\n const messages: EventMessage[] = [];\n const seen = new Map<string, string[]>();\n const closureDigest = closureDigester(root);\n const declare = (name: string, slot: string, node: unknown): void => {\n // A declaration carrying the removal marker asserts a slot rather than\n // declaring a message: it is listed (with `remove`) so the gate can see\n // it, but it joins nothing — not sent/received, not the duplicate count.\n if (isSlotRemoval(node)) {\n messages.push({ name, slot, remove: true as const });\n return;\n }\n messages.push({ name, slot, closureDigest: closureDigest(node), ...(payloadUndeclared(root, node) ? { payloadEmpty: true as const } : {}) });\n seen.set(name, [...(seen.get(name) ?? []), slot]);\n };\n\n // `components.messages` — the ordinary place a message is declared.\n for (const [key, node] of entriesOf((root[\"components\"] as Record<string, unknown> | undefined)?.[\"messages\"])) {\n declare(messageName(node, key), `components.messages.${key}`, node);\n }\n\n // `channels.<ck>.messages.<mk>` — an entry here is either an ALIAS of a\n // components declaration (a `$ref`) or an inline declaration of its own. Only\n // the second is a new slot: counting an alias would report every properly\n // factored document as declaring each message twice, which is the shape the\n // spec's own examples use.\n const channelMessages = new Map<string, string[]>();\n for (const [ck, channel] of entriesOf(root[\"channels\"])) {\n // A channel-slot removal retires the whole channel, inline interior\n // included: nothing under it declares or joins anything any more.\n if (isSlotRemoval(channel)) {\n channelMessages.set(ck, []);\n continue;\n }\n const names: string[] = [];\n for (const [mk, entry] of entriesOf((channel as Record<string, unknown> | null)?.[\"messages\"])) {\n const isAlias =\n entry !== null && typeof entry === \"object\" && !Array.isArray(entry) && \"$ref\" in (entry as object);\n const { node, key } = deref(root, entry, mk);\n const name = messageName(node, key);\n // A name whose declaration is being retired stays off the channel's\n // list, whether the marker sits on the aliased components entry or on\n // the inline declaration itself — the operation fallback below must\n // not join through a message the feature is removing.\n if (!isSlotRemoval(node)) names.push(name);\n if (!isAlias) declare(name, `channels.${ck}.messages.${mk}`, node);\n }\n channelMessages.set(ck, names);\n }\n\n const sent = new Set<string>();\n const received = new Set<string>();\n for (const [, operation] of entriesOf(root[\"operations\"])) {\n const op = operation as Record<string, unknown> | null;\n // An operation-slot removal retires the operation: it contributes no\n // send/receive whatever its `action` says.\n if (isSlotRemoval(op)) continue;\n const action = op?.[\"action\"];\n if (action !== \"send\" && action !== \"receive\") continue;\n const into = action === \"send\" ? sent : received;\n // The channel this operation acts on, by pointer — its key is what the\n // fallback below indexes.\n const channelRef = (op?.[\"channel\"] as Record<string, unknown> | undefined)?.[\"$ref\"];\n const channelKey = typeof channelRef === \"string\" ? channelRef.slice(channelRef.lastIndexOf(\"/\") + 1) : undefined;\n const listed = op?.[\"messages\"];\n if (Array.isArray(listed) && listed.length > 0) {\n for (const entry of listed) {\n const { node, key } = deref(root, entry, \"\");\n // A pointer that resolves nowhere contributes no name rather than an\n // empty one: a phantom \"\" would join to nothing and read as a message\n // the service produces.\n if (node === undefined && key === \"\") continue;\n // A pointer into a declaration being retired joins nothing either —\n // the marker means the message is leaving the contract.\n if (isSlotRemoval(node)) continue;\n const name = messageName(node, key);\n if (name.length > 0) into.add(name);\n }\n continue;\n }\n // AsyncAPI 3: an operation that lists no messages applies to every message\n // of its channel. Omitting the list is the normal shape of a minimal\n // hand-written contract — exactly what a fleet with no registry writes — so\n // reading it as \"produces nothing\" would report the common case broken.\n if (channelKey !== undefined) for (const name of channelMessages.get(channelKey) ?? []) into.add(name);\n }\n\n const duplicateNames = [...seen].filter(([, slots]) => slots.length > 1).map(([name]) => name);\n return {\n messages,\n sent: [...sent],\n received: [...received],\n duplicateNames,\n unreadable: false,\n danglingRefs: danglingRefs(root),\n // One deep scan rather than pushes scattered through the walk above: the\n // walk only visits the depths that JOIN, and a marker leaked anywhere\n // else (the root, `info`) was invisible to the living sweep while the\n // strip still owed its removal.\n markers: removalMarkerPaths(root, \"\"),\n };\n}\n\nfunction empty(): AsyncapiDoc {\n return { messages: [], sent: [], received: [], duplicateNames: [], unreadable: false, danglingRefs: [], markers: [] };\n}\n\n/** The slots one message name is declared in — what `asyncapi.duplicate-message` names. */\nexport function slotsOf(doc: AsyncapiDoc, name: string): string[] {\n return doc.messages.filter((m) => m.name === name).map((m) => m.slot);\n}\n\n"]}
|