@ybotok/loam 0.1.0-beta.3 → 0.2.0-alpha.1
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 +2548 -86
- package/COMPARISON.md +80 -63
- package/CONTRIBUTING.md +84 -0
- package/MIGRATING-from-OpenSpec.md +213 -54
- package/QUICKSTART.md +125 -0
- package/README.md +450 -150
- package/ROADMAP.md +494 -0
- package/SCHEMA.md +2355 -256
- package/SECURITY.md +21 -3
- package/WORKFLOW.md +701 -0
- package/dist/cli.js +113 -19
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +209 -0
- package/dist/commands/adopt/adopt.js.map +1 -0
- package/dist/commands/adopt/render.js +268 -0
- package/dist/commands/adopt/render.js.map +1 -0
- package/dist/commands/archive/archive.js +77 -0
- package/dist/commands/archive/archive.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +159 -0
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +317 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +161 -0
- package/dist/commands/archive/plan/landscape.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +111 -0
- package/dist/commands/archive/plan/refusal.js.map +1 -0
- package/dist/commands/archive/plan/specs.js +237 -0
- package/dist/commands/archive/plan/specs.js.map +1 -0
- package/dist/commands/archive/plan/state.js +27 -0
- package/dist/commands/archive/plan/state.js.map +1 -0
- package/dist/commands/archive/run.js +251 -0
- package/dist/commands/archive/run.js.map +1 -0
- package/dist/commands/context/context.js +99 -0
- package/dist/commands/context/context.js.map +1 -0
- package/dist/commands/context/print.js +283 -0
- package/dist/commands/context/print.js.map +1 -0
- package/dist/commands/delta/delta.js +279 -0
- package/dist/commands/delta/delta.js.map +1 -0
- package/dist/commands/delta/print.js +205 -0
- package/dist/commands/delta/print.js.map +1 -0
- package/dist/commands/dependencies.js +9 -7
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +93 -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 +5 -4
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +151 -0
- package/dist/commands/explain/explain.js.map +1 -0
- package/dist/commands/explore.js +29 -24
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +115 -0
- package/dist/commands/gate/gate.js.map +1 -0
- package/dist/commands/gate/print.js +54 -0
- package/dist/commands/gate/print.js.map +1 -0
- package/dist/commands/gherkin/commit.js +146 -0
- package/dist/commands/gherkin/commit.js.map +1 -0
- package/dist/commands/gherkin/gherkin.js +246 -0
- package/dist/commands/gherkin/gherkin.js.map +1 -0
- package/dist/commands/gherkin/reconcile.js +149 -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 +28 -0
- package/dist/commands/init/first-hour.js.map +1 -0
- package/dist/commands/{init.js → init/init.js} +146 -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 +65 -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 +157 -0
- package/dist/commands/list/json.js.map +1 -0
- package/dist/commands/list/list.js +343 -0
- package/dist/commands/list/list.js.map +1 -0
- package/dist/commands/list/print.js +301 -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/views.js +105 -0
- package/dist/commands/list/views.js.map +1 -0
- package/dist/commands/mcp/dispatch.js +183 -0
- package/dist/commands/mcp/dispatch.js.map +1 -0
- package/dist/commands/mcp/mcp.js +34 -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 +170 -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 +142 -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 +91 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/error.js +19 -0
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/paths.js +43 -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/commit.js +76 -0
- package/dist/commands/new/commit.js.map +1 -0
- package/dist/commands/new/new.js +283 -0
- package/dist/commands/new/new.js.map +1 -0
- package/dist/commands/new/templates.js +355 -0
- package/dist/commands/new/templates.js.map +1 -0
- package/dist/commands/open.js +203 -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} +11 -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 +275 -0
- package/dist/commands/rebase/rebase.js.map +1 -0
- package/dist/commands/seed/commit.js +192 -0
- package/dist/commands/seed/commit.js.map +1 -0
- package/dist/commands/seed/plan.js +133 -0
- package/dist/commands/seed/plan.js.map +1 -0
- package/dist/commands/seed/seed.js +172 -0
- package/dist/commands/seed/seed.js.map +1 -0
- package/dist/commands/show/feature.js +178 -0
- package/dist/commands/show/feature.js.map +1 -0
- package/dist/commands/show/marks.js +24 -0
- package/dist/commands/show/marks.js.map +1 -0
- package/dist/commands/{show.js → show/service.js} +63 -152
- package/dist/commands/show/service.js.map +1 -0
- package/dist/commands/show/show.js +77 -0
- package/dist/commands/show/show.js.map +1 -0
- package/dist/commands/status/json.js +45 -0
- package/dist/commands/status/json.js.map +1 -0
- package/dist/commands/status/print.js +157 -0
- package/dist/commands/status/print.js.map +1 -0
- package/dist/commands/status/status.js +119 -0
- package/dist/commands/status/status.js.map +1 -0
- package/dist/commands/steps/steps.js +189 -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 +265 -0
- package/dist/commands/subsystem/move.js.map +1 -0
- package/dist/commands/subsystem/query.js +115 -0
- package/dist/commands/subsystem/query.js.map +1 -0
- package/dist/commands/subsystem/subsystem.js +101 -0
- package/dist/commands/subsystem/subsystem.js.map +1 -0
- package/dist/commands/subsystem/sync.js +103 -0
- package/dist/commands/subsystem/sync.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +94 -0
- package/dist/commands/subsystem/txn/txn.js.map +1 -0
- package/dist/commands/subsystem/txn/views.js +70 -0
- package/dist/commands/subsystem/txn/views.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +160 -0
- package/dist/commands/unarchive/manifest.js.map +1 -0
- package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
- package/dist/commands/unarchive/restore.js.map +1 -0
- package/dist/commands/unarchive/unarchive.js +67 -0
- package/dist/commands/unarchive/unarchive.js.map +1 -0
- package/dist/commands/validate/arch-coverage.js +194 -0
- package/dist/commands/validate/arch-coverage.js.map +1 -0
- package/dist/commands/validate/checks/fleet-shape.js +296 -0
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
- package/dist/commands/validate/checks/health-deps.js +55 -0
- package/dist/commands/validate/checks/health-deps.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +254 -0
- package/dist/commands/validate/checks/requirements.js.map +1 -0
- package/dist/commands/validate/checks/sources.js +76 -0
- package/dist/commands/validate/checks/sources.js.map +1 -0
- package/dist/commands/validate/checks/vocabulary.js +31 -0
- package/dist/commands/validate/checks/vocabulary.js.map +1 -0
- package/dist/commands/validate/feature.js +216 -0
- package/dist/commands/validate/feature.js.map +1 -0
- package/dist/commands/validate/fleet/census.js +69 -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 +353 -0
- package/dist/commands/validate/fleet/landscape.js.map +1 -0
- package/dist/commands/validate/fleet/load.js +52 -0
- package/dist/commands/validate/fleet/load.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +236 -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 +63 -0
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
- package/dist/commands/validate/fleet/usecases/capability-tag.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/usecases/requirement-tag.js +95 -0
- package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/steps.js +197 -0
- package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
- package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +40 -0
- package/dist/commands/validate/fleet/views/ids.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +59 -0
- package/dist/commands/validate/fleet/views/stale.js.map +1 -0
- package/dist/commands/validate/links/corpus.js +92 -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/report.js +269 -0
- package/dist/commands/validate/report.js.map +1 -0
- package/dist/commands/validate/service/api.js +338 -0
- package/dist/commands/validate/service/api.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +219 -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 +131 -0
- package/dist/commands/validate/service/evidence-pins.js.map +1 -0
- package/dist/commands/validate/service/service.js +250 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +219 -0
- package/dist/commands/validate/service/specs.js.map +1 -0
- package/dist/commands/validate/service/spine.js +113 -0
- package/dist/commands/validate/service/spine.js.map +1 -0
- package/dist/commands/validate/validate.js +338 -0
- package/dist/commands/validate/validate.js.map +1 -0
- package/dist/commands/verify/cross/diff.js +182 -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 +72 -0
- package/dist/commands/verify/evidence/read.js.map +1 -0
- package/dist/commands/verify/frozen.js +241 -0
- package/dist/commands/verify/frozen.js.map +1 -0
- package/dist/commands/verify/record.js +226 -0
- package/dist/commands/verify/record.js.map +1 -0
- package/dist/commands/verify/report.js +223 -0
- package/dist/commands/verify/report.js.map +1 -0
- package/dist/commands/verify/results.js +246 -0
- package/dist/commands/verify/results.js.map +1 -0
- package/dist/commands/verify/verify.js +217 -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 +271 -0
- package/dist/commands/vouch/pack/print.js.map +1 -0
- package/dist/commands/vouch/pack/sections.js +142 -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 +285 -0
- package/dist/commands/vouch/run.js.map +1 -0
- package/dist/commands/vouch/sample/plan.js +125 -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 +123 -0
- package/dist/commands/vouch/vet/verify.js.map +1 -0
- package/dist/commands/vouch/vouch.js +176 -0
- package/dist/commands/vouch/vouch.js.map +1 -0
- package/dist/core/agent/agents-md/artifacts.js +220 -0
- package/dist/core/agent/agents-md/artifacts.js.map +1 -0
- package/dist/core/agent/agents-md/command-map.js +324 -0
- package/dist/core/agent/agents-md/command-map.js.map +1 -0
- package/dist/core/agent/agents-md/cycle.js +165 -0
- package/dist/core/agent/agents-md/cycle.js.map +1 -0
- package/dist/core/agent/agents-md/map/explain.js +34 -0
- package/dist/core/agent/agents-md/map/explain.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
- package/dist/core/agent/agents-md/map/mcp.js +41 -0
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
- package/dist/core/agent/agents-md/map/status.js +62 -0
- package/dist/core/agent/agents-md/map/status.js.map +1 -0
- package/dist/core/agent/agents-md/map/subsystem.js +32 -0
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
- package/dist/core/agent/agents-md/map/usecases.js +60 -0
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
- package/dist/core/agent/agents-md/refusals.js +246 -0
- package/dist/core/agent/agents-md/refusals.js.map +1 -0
- package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
- package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
- package/dist/core/agent/agents-md/spine.js +40 -0
- package/dist/core/agent/agents-md/spine.js.map +1 -0
- package/dist/core/agent/agents-md.js +170 -0
- package/dist/core/agent/agents-md.js.map +1 -0
- package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +50 -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 +259 -0
- package/dist/core/agent/scaffold.js.map +1 -0
- package/dist/core/agent/support/report.js +103 -0
- package/dist/core/agent/support/report.js.map +1 -0
- package/dist/core/agent/tools/dialects.js +150 -0
- package/dist/core/agent/tools/dialects.js.map +1 -0
- package/dist/core/agent/tools/registry.js +228 -0
- package/dist/core/agent/tools/registry.js.map +1 -0
- package/dist/core/agent/workflows/adopt.js +133 -0
- package/dist/core/agent/workflows/adopt.js.map +1 -0
- package/dist/core/agent/workflows/check.js +334 -0
- package/dist/core/agent/workflows/check.js.map +1 -0
- package/dist/core/agent/workflows/closing.js +262 -0
- package/dist/core/agent/workflows/closing.js.map +1 -0
- package/dist/core/agent/workflows/feature.js +105 -0
- package/dist/core/agent/workflows/feature.js.map +1 -0
- package/dist/core/agent/workflows/implement.js +105 -0
- package/dist/core/agent/workflows/implement.js.map +1 -0
- package/dist/core/agent/workflows/reference/authoring.js +209 -0
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
- package/dist/core/agent/workflows/reference/codes.js +65 -0
- package/dist/core/agent/workflows/reference/codes.js.map +1 -0
- package/dist/core/agent/workflows/reference/done-check.js +188 -0
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +16 -0
- package/dist/core/agent/workflows/reference/reference.js.map +1 -0
- package/dist/core/agent/workflows/reference/spine.js +297 -0
- package/dist/core/agent/workflows/reference/spine.js.map +1 -0
- package/dist/core/asyncapi/baseline/plan.js +110 -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 +141 -0
- package/dist/core/asyncapi/digest.js.map +1 -0
- package/dist/core/asyncapi/merge/components.js +91 -0
- package/dist/core/asyncapi/merge/components.js.map +1 -0
- package/dist/core/asyncapi/merge/error.js +33 -0
- package/dist/core/asyncapi/merge/error.js.map +1 -0
- package/dist/core/asyncapi/merge/markers.js +308 -0
- package/dist/core/asyncapi/merge/markers.js.map +1 -0
- package/dist/core/asyncapi/merge/merge.js +215 -0
- package/dist/core/asyncapi/merge/merge.js.map +1 -0
- package/dist/core/asyncapi/merge/pin.js +107 -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.js → asyncapi/read.js} +95 -109
- package/dist/core/asyncapi/read.js.map +1 -0
- package/dist/core/brief/brief.js +225 -0
- package/dist/core/brief/brief.js.map +1 -0
- package/dist/core/brief/checks.js +250 -0
- package/dist/core/brief/checks.js.map +1 -0
- package/dist/core/brief/landscape.js +194 -0
- package/dist/core/brief/landscape.js.map +1 -0
- package/dist/core/brief/targets.js +226 -0
- package/dist/core/brief/targets.js.map +1 -0
- package/dist/core/brief/unchecked.js +47 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +282 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/likec4.js +88 -0
- package/dist/core/c4/likec4.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 +57 -0
- package/dist/core/c4/parsed/values.js.map +1 -0
- package/dist/core/c4/parsed/view-ids.js +75 -0
- package/dist/core/c4/parsed/view-ids.js.map +1 -0
- package/dist/core/c4/project/architecture.js +45 -0
- package/dist/core/c4/project/architecture.js.map +1 -0
- package/dist/core/c4/project/documents.js +58 -0
- package/dist/core/c4/project/documents.js.map +1 -0
- package/dist/core/c4/project/load.js +183 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/resolve/service.js +113 -0
- package/dist/core/c4/resolve/service.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 +109 -0
- package/dist/core/c4/seed/template.js.map +1 -0
- package/dist/core/c4/source-mask.js +82 -0
- package/dist/core/c4/source-mask.js.map +1 -0
- package/dist/core/c4/source-scan.js +227 -0
- package/dist/core/c4/source-scan.js.map +1 -0
- package/dist/core/c4/splice/authored-source.js +101 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -0
- package/dist/core/c4/splice/contract.js +10 -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/edges.js +36 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +269 -0
- package/dist/core/c4/splice/landscape-merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +194 -0
- package/dist/core/c4/splice/placement.js.map +1 -0
- package/dist/core/c4/workspace.js +172 -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 +50 -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 +342 -0
- package/dist/core/capabilities/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/findings.js +181 -0
- package/dist/core/capabilities/realizes/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/join.js +143 -0
- package/dist/core/capabilities/realizes/join.js.map +1 -0
- package/dist/core/capabilities/rollup.js +199 -0
- package/dist/core/capabilities/rollup.js.map +1 -0
- package/dist/core/capabilities/tree.js +126 -0
- package/dist/core/capabilities/tree.js.map +1 -0
- package/dist/core/capabilities/usecase-join.js +277 -0
- package/dist/core/capabilities/usecase-join.js.map +1 -0
- package/dist/core/coherence/authoring/scaffold.js +177 -0
- package/dist/core/coherence/authoring/scaffold.js.map +1 -0
- package/dist/core/coherence/authoring/sentinels.js +74 -0
- package/dist/core/coherence/authoring/sentinels.js.map +1 -0
- package/dist/core/coherence/coherence.js +251 -0
- package/dist/core/coherence/coherence.js.map +1 -0
- package/dist/core/coherence/declared.js +269 -0
- package/dist/core/coherence/declared.js.map +1 -0
- package/dist/core/coherence/events/declared.js +206 -0
- package/dist/core/coherence/events/declared.js.map +1 -0
- package/dist/core/coherence/events/events.js +204 -0
- package/dist/core/coherence/events/events.js.map +1 -0
- package/dist/core/coherence/events/grades.js +166 -0
- package/dist/core/coherence/events/grades.js.map +1 -0
- package/dist/core/coherence/events/lookups.js +122 -0
- package/dist/core/coherence/events/lookups.js.map +1 -0
- package/dist/core/coherence/events/merged.js +40 -0
- package/dist/core/coherence/events/merged.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 +155 -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/conflict-markers.js +60 -0
- package/dist/core/conflict-markers.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 +296 -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/diff/base-git.js +148 -0
- package/dist/core/diff/base-git.js.map +1 -0
- package/dist/core/diff/base-state.js +209 -0
- package/dist/core/diff/base-state.js.map +1 -0
- package/dist/core/diff/current-state.js +96 -0
- package/dist/core/diff/current-state.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +188 -0
- package/dist/core/diff/scope/changed-paths.js.map +1 -0
- package/dist/core/diff/semantic.js +243 -0
- package/dist/core/diff/semantic.js.map +1 -0
- package/dist/core/diff/victims.js +247 -0
- package/dist/core/diff/victims.js.map +1 -0
- package/dist/core/docs.js +7 -64
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +222 -0
- package/dist/core/doctor/agents.js.map +1 -0
- package/dist/core/doctor/config.js +135 -0
- package/dist/core/doctor/config.js.map +1 -0
- package/dist/core/doctor/doctor.js +275 -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/residue.js +110 -0
- package/dist/core/doctor/residue.js.map +1 -0
- package/dist/core/document/apply.js +77 -0
- package/dist/core/document/apply.js.map +1 -0
- package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -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 +263 -0
- package/dist/core/document/parse.js.map +1 -0
- package/dist/core/document/scenarios.js +221 -0
- package/dist/core/document/scenarios.js.map +1 -0
- package/dist/core/document/spec.js +241 -0
- package/dist/core/document/spec.js.map +1 -0
- package/dist/core/{config.js → envelope/config.js} +79 -18
- package/dist/core/envelope/config.js.map +1 -0
- package/dist/core/envelope/json.js +175 -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 +175 -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 +181 -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.js +144 -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.js → explore/explore.js} +50 -101
- package/dist/core/explore/explore.js.map +1 -0
- package/dist/core/fleet-context.js +120 -78
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +201 -0
- package/dist/core/gate/checks.js.map +1 -0
- package/dist/core/gate/partners.js +205 -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 +113 -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 +234 -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 +106 -0
- package/dist/core/glossary/delta.js.map +1 -0
- package/dist/core/glossary/tree.js +86 -0
- package/dist/core/glossary/tree.js.map +1 -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/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} +18 -4
- package/dist/core/kernel/path-safety.js.map +1 -0
- package/dist/core/kernel/records.js.map +1 -0
- package/dist/core/links/backlinks.js +68 -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 +104 -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 +236 -0
- package/dist/core/links/parse.js.map +1 -0
- package/dist/core/mcp/argv.js +111 -0
- package/dist/core/mcp/argv.js.map +1 -0
- package/dist/core/mcp/author-tools.js +72 -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 +314 -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 +166 -0
- package/dist/core/openapi/baseline/gate.js.map +1 -0
- package/dist/core/openapi/baseline/plan.js +112 -0
- package/dist/core/openapi/baseline/plan.js.map +1 -0
- package/dist/core/openapi/baseline/record.js +175 -0
- package/dist/core/openapi/baseline/record.js.map +1 -0
- package/dist/core/openapi/depth.js +122 -0
- package/dist/core/openapi/depth.js.map +1 -0
- package/dist/core/openapi/digest.js +189 -0
- package/dist/core/openapi/digest.js.map +1 -0
- package/dist/core/{openapi.js → openapi/doc.js} +44 -106
- package/dist/core/openapi/doc.js.map +1 -0
- package/dist/core/openapi/merge/components.js +234 -0
- package/dist/core/openapi/merge/components.js.map +1 -0
- package/dist/core/openapi/merge/error.js +26 -0
- package/dist/core/openapi/merge/error.js.map +1 -0
- package/dist/core/openapi/merge/markers.js +208 -0
- package/dist/core/openapi/merge/markers.js.map +1 -0
- package/dist/core/openapi/merge/merge.js +256 -0
- package/dist/core/openapi/merge/merge.js.map +1 -0
- package/dist/core/openapi/merge/pin.js +128 -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 +221 -0
- package/dist/core/openspec/inventory.js.map +1 -0
- package/dist/core/openspec/model/mapping.js +76 -0
- package/dist/core/openspec/model/mapping.js.map +1 -0
- package/dist/core/openspec/model/model.js +65 -0
- package/dist/core/openspec/model/model.js.map +1 -0
- package/dist/core/openspec/scan/changes.js +235 -0
- package/dist/core/openspec/scan/changes.js.map +1 -0
- package/dist/core/openspec/scan/config.js +200 -0
- package/dist/core/openspec/scan/config.js.map +1 -0
- package/dist/core/openspec/scan/shape.js +260 -0
- package/dist/core/openspec/scan/shape.js.map +1 -0
- package/dist/core/openspec/scan/walk.js +133 -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 +118 -0
- package/dist/core/pack/living.js.map +1 -0
- package/dist/core/pack/pack.js +76 -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/provenance/findings.js +208 -0
- package/dist/core/provenance/findings.js.map +1 -0
- package/dist/core/provenance/git.js +225 -0
- package/dist/core/provenance/git.js.map +1 -0
- package/dist/core/provenance/gitq/moves.js +182 -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 +263 -0
- package/dist/core/provenance/sources.js.map +1 -0
- package/dist/core/provenance/stamp.js +232 -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 +192 -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 +236 -0
- package/dist/core/repo/paths.js.map +1 -0
- package/dist/core/repo/repo.js +248 -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 +52 -0
- package/dist/core/repo/tree/find.js.map +1 -0
- package/dist/core/repo/tree/fs.js +64 -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/views.js +172 -0
- package/dist/core/repo/tree/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +234 -0
- package/dist/core/repo/tree/walk.js.map +1 -0
- package/dist/core/results.js +99 -2
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +131 -0
- package/dist/core/scaffold/landscape.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 +241 -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 +206 -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 +98 -0
- package/dist/core/staging/recovery/intent.js.map +1 -0
- package/dist/core/staging/recovery/recover.js +126 -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.js +202 -0
- package/dist/core/staging/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +171 -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 +49 -0
- package/dist/core/status/actions/execution.js.map +1 -0
- package/dist/core/status/contracts.js +102 -0
- package/dist/core/status/contracts.js.map +1 -0
- package/dist/core/status/feature/artifacts.js +171 -0
- package/dist/core/status/feature/artifacts.js.map +1 -0
- package/dist/core/status/feature/feature.js +207 -0
- package/dist/core/status/feature/feature.js.map +1 -0
- package/dist/core/status/feature/next.js +150 -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/fleet/fleet.js +187 -0
- package/dist/core/status/fleet/fleet.js.map +1 -0
- package/dist/core/status/fleet/next.js +207 -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 +201 -0
- package/dist/core/status/verification.js.map +1 -0
- package/dist/core/usecases/capability.js +169 -0
- package/dist/core/usecases/capability.js.map +1 -0
- package/dist/core/usecases/delta/claims.js +116 -0
- package/dist/core/usecases/delta/claims.js.map +1 -0
- package/dist/core/usecases/delta/flows.js +103 -0
- package/dist/core/usecases/delta/flows.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +235 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -0
- package/dist/core/usecases/fleet.js +137 -0
- package/dist/core/usecases/fleet.js.map +1 -0
- package/dist/core/usecases/operations.js +111 -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/touch.js +101 -0
- package/dist/core/usecases/touch.js.map +1 -0
- package/dist/core/verify/answers.js +173 -0
- package/dist/core/verify/answers.js.map +1 -0
- package/dist/core/verify/build.js +150 -0
- package/dist/core/verify/build.js.map +1 -0
- package/dist/core/verify/checklist.js +201 -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/file.js +257 -0
- package/dist/core/verify/file.js.map +1 -0
- package/dist/core/verify/pins/lint.js +157 -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/record.js +142 -0
- package/dist/core/verify/record.js.map +1 -0
- package/dist/core/verify/store/commit.js +89 -0
- package/dist/core/verify/store/commit.js.map +1 -0
- package/dist/core/verify/store/render.js +57 -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 +55 -0
- package/dist/core/vocabulary/issue.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +145 -0
- package/dist/core/vocabulary/maturity.js.map +1 -0
- package/dist/core/{report.js → vocabulary/report.js} +30 -2
- 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 +189 -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 +280 -0
- package/examples/docs/architecture/obligations.yaml +23 -0
- package/examples/docs/architecture/permissions.yaml +50 -0
- package/examples/docs/architecture/subsystems.likec4 +11 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +65 -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 +129 -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 +28 -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 +70 -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 +9 -0
- package/examples/docs/loam.json +3 -0
- package/examples/docs/services/checkout-web/model.likec4 +109 -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 +127 -0
- package/examples/docs/services/order-service/asyncapi.yaml +108 -0
- package/examples/docs/services/order-service/health.yaml +57 -0
- package/examples/docs/services/order-service/model.likec4 +138 -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 +73 -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 +67 -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 +117 -0
- package/examples/docs/services/platform/identity-service/health.yaml +70 -0
- package/examples/docs/services/platform/identity-service/model.likec4 +83 -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 +199 -0
- package/examples/docs/services/platform/notification-service/health.yaml +35 -0
- package/examples/docs/services/platform/notification-service/model.likec4 +118 -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.map +0 -1
- package/dist/commands/status.js +0 -262
- package/dist/commands/status.js.map +0 -1
- 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.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.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.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
- /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
- /package/dist/core/{records.js → kernel/records.js} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components.js","sourceRoot":"","sources":["../../../../src/core/asyncapi/merge/components.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE9C,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAuB,MAAM,kCAAkC,CAAC;AAC5F,OAAO,EAAE,uBAAuB,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACvG,6EAA6E;AAC7E,+EAA+E;AAC/E,6EAA6E;AAC7E,qEAAqE;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AACtE,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AA+B/C;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAA8B;IACpE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IAClE,MAAM,kBAAkB,GAAa,EAAE,CAAC;IACxC,MAAM,gBAAgB,GAAa,EAAE,CAAC;IACtC,MAAM,eAAe,GAAa,EAAE,CAAC;IACrC,MAAM,MAAM,GAA0D,EAAE,CAAC;IAEzE,yEAAyE;IACzE,wEAAwE;IACxE,yEAAyE;IACzE,KAAK,MAAM,OAAO,IAAI,gBAAgB,CAAC,SAAS,CAAC,EAAE,CAAC;QAClD,2EAA2E;QAC3E,iDAAiD;QACjD,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,QAAQ,GAAG,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QACjD,MAAM,OAAO,GAAG,uBAAuB,CACrC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,EACzB,WAAW,CAAC,OAAO,CAAC,KAAK,CAAC,EAC1B,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CACzD,CAAC;QACF,yEAAyE;QACzE,mEAAmE;QACnE,oEAAoE;QACpE,oDAAoD;QACpD,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YACxB,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;YAClC,SAAS;QACX,CAAC;QACD,IAAI,OAAO,KAAK,OAAO;YAAE,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC1D,MAAM,OAAO,GAAG,sBAAsB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;QACtD,IAAI,QAAQ,CAAC,KAAK,IAAI,iBAAiB,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;YAAE,SAAS;QAC3E,IAAI,QAAQ,CAAC,KAAK;YAAE,kBAAkB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QACxD,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC;IACnG,CAAC;IAED,KAAK,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,MAAM,EAAE,CAAC;QAC3C,qEAAqE;QACrE,0EAA0E;QAC1E,yEAAyE;QACzE,oCAAoC;QACpC,eAAe,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC,YAAY,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;QACpE,iBAAiB,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;IAED,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;AAC9F,CAAC","sourcesContent":["/**\n * The SURFACE half of the event merge: every `components/<kind>/<name>` the\n * feature declares outside `messages`, folded into the living contract by the\n * same verdict the slot loop takes.\n *\n * Verdict-driven and nothing else. A surface is classified against its\n * `x-loam-baselines` entry exactly as a slot is classified against its\n * in-value pin, so a QUOTE is skipped whatever landed on the living value\n * since, and an EDIT is written. There is deliberately no reachability\n * machinery here — the OpenAPI closure parks a genuinely new component until\n * something written reaches it, because on that axis a quoted OPERATION can\n * drag its authoring-time component copy along. This axis has no such carrier:\n * a surface is only ever copied because the delta declares it, and the ref\n * discipline is the post-hoc `danglingRefs` diff the merge runs over the whole\n * merged tree (../depth.ts) rather than the closure's queued `{ref, from}`.\n * Borrowing the parked set would mean a schema the author wrote on purpose\n * silently not merging, which is the defect this module closes.\n */\nimport { isDeepStrictEqual } from \"node:util\";\nimport type { Document } from \"yaml\";\nimport { entryFor, surfaceIn, type BaselineRecord } from \"../../openapi/baseline/record.js\";\nimport { classifyBaselineDigests, valueDigest, withoutFeatureKeysDeep } from \"../../openapi/digest.js\";\n// The OpenAPI axis's component writer, imported rather than respelled: it is\n// path-agnostic and string-key-matched, so a numeric component name (`404:` is\n// the YAML number) is REPLACED rather than appended a second time — the same\n// hazard every slot writer on this axis goes through `slotPair` for.\nimport { setComponentValue } from \"../../openapi/merge/components.js\";\nimport { asyncapiSurfaces } from \"../baseline/surfaces.js\";\nimport { writableSection } from \"./markers.js\";\n\n/** Everything the surface merge needs; one object because the merge is its only caller. */\nexport interface AsyncapiComponentsInput {\n /** The living document the copies are written into. */\n living: Document;\n featPlain: unknown;\n livingPlain: unknown;\n /** The feature's `x-loam-baselines` record, read once by the merge. */\n record: BaselineRecord;\n service: string;\n}\n\n/** What the surface merge computed. */\nexport interface AsyncapiComponentsOutcome {\n /** `<kind>/<name>` of living surfaces overwritten with different content. */\n componentsModified: string[];\n /** Surfaces the delta QUOTED — not copied, living's copy kept. */\n componentsQuoted: string[];\n /** Surfaces written on a stale record entry — under `--approve`, like the slots. */\n componentsStale: string[];\n /**\n * Whether anything was actually written. The merge turns this into `edited`:\n * without it the surface verdicts would be computed, reported, and then\n * dropped on the floor by the `!edited` early return that keeps an all-quote\n * delta byte-identical — the defect surviving in a new shape, with the plan\n * naming components it never wrote.\n */\n copied: boolean;\n}\n\n/**\n * Merge the feature's component surfaces into the living document by verdict:\n *\n * - quote → skipped; the living copy stays, whatever landed on it since.\n * - edit, or stale (under `--approve`) → copied, and reported.\n * - unpinned and living-equal → skipped: there is nothing to write, and a\n * never-rebased delta that merely restates the contract must not churn its\n * bytes (the slot loop's rule, at surface depth).\n * - unpinned and differing → copied, the old upsert kept for never-rebased\n * deltas, and reported as a modification like any other overwrite.\n * - unfounded (pinned, living gone — the gate refused; `--approve`) and NEW\n * (unpinned, living-absent) → copied. Both write a surface the living\n * contract does not have, which is the ordinary shape of a delta that adds\n * a schema.\n *\n * Every write goes through the deep strip first: a component's value can nest\n * loam's keys anywhere (a schema `properties` entry, a `$ref` sibling), and\n * publishing one into a living contract is the failure `--approve` already\n * caused once on the OpenAPI axis.\n */\nexport function mergeAsyncapiComponents(input: AsyncapiComponentsInput): AsyncapiComponentsOutcome {\n const { living, featPlain, livingPlain, record, service } = input;\n const componentsModified: string[] = [];\n const componentsQuoted: string[] = [];\n const componentsStale: string[] = [];\n const copies: Array<{ kind: string; name: string; value: unknown }> = [];\n\n // ONE enumeration (../baseline/surfaces.ts) with the rebase plan and the\n // gate, and ONE living lookup (surfaceIn), so \"which surfaces does this\n // delta declare, and does living have this one\" cannot have two answers.\n for (const surface of asyncapiSurfaces(featPlain)) {\n // The first `/` is the kind boundary, exactly as `surfaceIn` reads it back\n // — a component name cannot legally contain one.\n const cut = surface.id.indexOf(\"/\");\n const inLiving = surfaceIn(livingPlain, surface);\n const verdict = classifyBaselineDigests(\n entryFor(record, surface),\n valueDigest(surface.value),\n inLiving.found ? valueDigest(inLiving.value) : undefined,\n );\n // A QUOTE is not a merge input, on this axis for the slot loop's reason:\n // the author wrote the surface down because an AsyncAPI delta is a\n // COMPLETE document, not because they changed it. Mechanical, not a\n // judgement — `--approve` does not turn it back on.\n if (verdict === \"quote\") {\n componentsQuoted.push(surface.id);\n continue;\n }\n if (verdict === \"stale\") componentsStale.push(surface.id);\n const publish = withoutFeatureKeysDeep(surface.value);\n if (inLiving.found && isDeepStrictEqual(inLiving.value, publish)) continue;\n if (inLiving.found) componentsModified.push(surface.id);\n copies.push({ kind: surface.id.slice(0, cut), name: surface.id.slice(cut + 1), value: publish });\n }\n\n for (const { kind, name, value } of copies) {\n // Guarded at the write, like every slot write: a living `components:\n // *alias` (or an aliased `components.schemas`) is one shared value behind\n // every use of the anchor, so writing a surface through it would rewrite\n // every other node that aliases it.\n writableSection(living, livingPlain, [\"components\", kind], service);\n setComponentValue(living, kind, name, value);\n }\n\n return { componentsModified, componentsQuoted, componentsStale, copied: copies.length > 0 };\n}\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one refusal every stage of the event-contract delta path raises: a
|
|
3
|
+
* document the planner cannot read, named by which side it came from.
|
|
4
|
+
*
|
|
5
|
+
* The mirror of ../../openapi/merge/error.ts, and the package's leaf for the
|
|
6
|
+
* same reason: whichever sibling fails — the pin, the markers or the merge —
|
|
7
|
+
* the command above has to map one domain error onto its own envelope, and a
|
|
8
|
+
* module that owned the error would be imported by its siblings for that
|
|
9
|
+
* reason alone.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* A document the merge machinery cannot use. Commands map this domain error
|
|
13
|
+
* to their own envelope. `problem` is the verb phrase between the document's
|
|
14
|
+
* name and the detail — "is not valid YAML" for the parse failures that are
|
|
15
|
+
* the common case, overridden where the document parses fine and the refusal
|
|
16
|
+
* is about what it says (a section spelling one slot key twice is legal YAML,
|
|
17
|
+
* and calling it invalid would send the author to a linter that agrees with
|
|
18
|
+
* the file).
|
|
19
|
+
*/
|
|
20
|
+
export class AsyncapiMergeError extends Error {
|
|
21
|
+
source;
|
|
22
|
+
service;
|
|
23
|
+
name = "AsyncapiMergeError";
|
|
24
|
+
constructor(source, service, detail, problem = "is not valid YAML") {
|
|
25
|
+
super(`${source} asyncapi for ${service} ${problem}: ${detail}`);
|
|
26
|
+
this.source = source;
|
|
27
|
+
this.service = service;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export function errorMessage(error) {
|
|
31
|
+
return error instanceof Error ? error.message : String(error);
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=error.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error.js","sourceRoot":"","sources":["../../../../src/core/asyncapi/merge/error.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH;;;;;;;;GAQG;AACH,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAIhC,MAAM;IACN,OAAO;IAJA,IAAI,GAAG,oBAAoB,CAAC;IAE9C,YACW,MAA2B,EAC3B,OAAe,EACxB,MAAc,EACd,OAAO,GAAW,mBAAmB;QAErC,KAAK,CAAC,GAAG,MAAM,iBAAiB,OAAO,IAAI,OAAO,KAAK,MAAM,EAAE,CAAC,CAAC;sBALxD,MAAM;uBACN,OAAO;IAKlB,CAAC;CACF;AAED,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC","sourcesContent":["/**\n * The one refusal every stage of the event-contract delta path raises: a\n * document the planner cannot read, named by which side it came from.\n *\n * The mirror of ../../openapi/merge/error.ts, and the package's leaf for the\n * same reason: whichever sibling fails — the pin, the markers or the merge —\n * the command above has to map one domain error onto its own envelope, and a\n * module that owned the error would be imported by its siblings for that\n * reason alone.\n */\n\nexport type AsyncapiMergeSource = \"feature\" | \"living\";\n\n/**\n * A document the merge machinery cannot use. Commands map this domain error\n * to their own envelope. `problem` is the verb phrase between the document's\n * name and the detail — \"is not valid YAML\" for the parse failures that are\n * the common case, overridden where the document parses fine and the refusal\n * is about what it says (a section spelling one slot key twice is legal YAML,\n * and calling it invalid would send the author to a linter that agrees with\n * the file).\n */\nexport class AsyncapiMergeError extends Error {\n override readonly name = \"AsyncapiMergeError\";\n\n constructor(\n readonly source: AsyncapiMergeSource,\n readonly service: string,\n detail: string,\n problem: string = \"is not valid YAML\",\n ) {\n super(`${source} asyncapi for ${service} ${problem}: ${detail}`);\n }\n}\n\nexport function errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"]}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The keys loam adds to a feature's event contract that must never reach the
|
|
3
|
+
* living one: `x-loam-based-on`, `x-loam-remove`, and the root
|
|
4
|
+
* `x-loam-baselines` record — the same three spellings the OpenAPI axis
|
|
5
|
+
* strips, gathered here for the same reason its markers
|
|
6
|
+
* module exists: `stripAsyncapiMarkers` takes them out for the create branch
|
|
7
|
+
* that publishes a feature document verbatim, and the merge takes them out
|
|
8
|
+
* again on the way into a living document. Two spellings of "which keys are
|
|
9
|
+
* feature-only" is how one of the two starts leaking a marker.
|
|
10
|
+
*
|
|
11
|
+
* The strip is DEEP, and it covers the WHOLE document. Deep by the format
|
|
12
|
+
* spec's own decision: an inline channel message (`channels.<ck>.messages.<mk>`)
|
|
13
|
+
* is channel-slot interior, so a pin or marker nested on it is part of the
|
|
14
|
+
* channel's VALUE — the slot walker never visits it, and a slot-level strip
|
|
15
|
+
* would publish it into the fleet's living contract exactly the way
|
|
16
|
+
* `--approve` once published `x-loam-remove: true` inside a living OpenAPI
|
|
17
|
+
* component. Whole-document because the create branch publishes this text
|
|
18
|
+
* VERBATIM: a marker at the document root or a pin under `info` sits outside
|
|
19
|
+
* every section, and a strip that walked only the three sections shipped
|
|
20
|
+
* both into a living contract, unseen even by validate's marker sweep.
|
|
21
|
+
*/
|
|
22
|
+
import { isMap, isScalar, parseDocument } from "yaml";
|
|
23
|
+
// Every `isRecord` below asks one question of a resolved plain tree: is this a
|
|
24
|
+
// node that can hold AsyncAPI keys — an object, not an array?
|
|
25
|
+
import { isRecord } from "../../kernel/records.js";
|
|
26
|
+
// One spelling of the deep strip for both axes: the feature-only keys are the
|
|
27
|
+
// SAME two strings on either (core/asyncapi/digest.ts aliases the constants
|
|
28
|
+
// outright), so a drift between the strips would be two definitions of one
|
|
29
|
+
// rule (the openapi digest module's own failure mode).
|
|
30
|
+
import { FEATURE_ONLY_KEYS, withoutFeatureKeysDeep } from "../../openapi/digest.js";
|
|
31
|
+
import { ASYNCAPI_BASELINES_KEY, isSlotRemoval } from "../digest.js";
|
|
32
|
+
import { errorMessage, AsyncapiMergeError } from "./error.js";
|
|
33
|
+
/** The three slot sections, in document order — every whole-document walk here goes over them. */
|
|
34
|
+
const SECTIONS = ["channels", "operations", "components.messages"];
|
|
35
|
+
/**
|
|
36
|
+
* A slot's PUBLISHABLE value: every feature-only key removed, at any depth —
|
|
37
|
+
* the top-level pin, a nested pin or marker on an inline channel message, and
|
|
38
|
+
* anything an author buried deeper. What the merge writes and what the create
|
|
39
|
+
* branch keeps; a removal-marker slot is never published at all (the merge
|
|
40
|
+
* deletes its target, the strip drops it), so this is only ever asked of a
|
|
41
|
+
* slot that survives.
|
|
42
|
+
*/
|
|
43
|
+
export function withoutFeatureMarkers(node) {
|
|
44
|
+
return withoutFeatureKeysDeep(node);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The AST path of a section's own mapping — `slotPath` (../digest.ts) minus
|
|
48
|
+
* the slot key, spelled beside the writers so the strip and the merge cannot
|
|
49
|
+
* disagree about which node a section name addresses.
|
|
50
|
+
*/
|
|
51
|
+
export function sectionAstPath(section) {
|
|
52
|
+
return section === "components.messages" ? ["components", "messages"] : [section];
|
|
53
|
+
}
|
|
54
|
+
/** One mapping node's pair for a key, matched AS A STRING — `slotPair`'s find, reusable at any depth. */
|
|
55
|
+
function pairAt(node, key) {
|
|
56
|
+
return isMap(node) ? node.items.find((it) => isScalar(it.key) && String(it.key.value) === key) : undefined;
|
|
57
|
+
}
|
|
58
|
+
/** Delete one pair from a mapping node, string-key-matched. Returns whether a pair actually went. */
|
|
59
|
+
function deleteKeyIn(node, key) {
|
|
60
|
+
if (!isMap(node))
|
|
61
|
+
return false;
|
|
62
|
+
const at = node.items.findIndex((it) => isScalar(it.key) && String(it.key.value) === key);
|
|
63
|
+
if (at < 0)
|
|
64
|
+
return false;
|
|
65
|
+
node.items.splice(at, 1);
|
|
66
|
+
return true;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Find one slot's key/value pair, matching the existing key AS A STRING: a
|
|
70
|
+
* channel named `404:` is the YAML number 404, and a plain `getIn`/`setIn`
|
|
71
|
+
* with the string "404" misses it and APPENDS a second pair — the living
|
|
72
|
+
* contract then declares the slot twice, forever, with the pre-merge copy
|
|
73
|
+
* first in reading order. The openapi component write's lesson, applied to
|
|
74
|
+
* every slot access on this axis: the merge's writers below go through it,
|
|
75
|
+
* and so does the pin (./pin.ts), whose raw `getIn` used to grade every
|
|
76
|
+
* non-string-keyed slot `unwritable` with an alias diagnosis nothing in the
|
|
77
|
+
* document backed.
|
|
78
|
+
*/
|
|
79
|
+
export function slotPair(doc, section, key) {
|
|
80
|
+
return pairAt(doc.getIn(sectionAstPath(section)), key);
|
|
81
|
+
}
|
|
82
|
+
/** Write one slot's value, string-key-matched — the merge's one upsert door. */
|
|
83
|
+
export function setSlotValue(doc, section, key, value) {
|
|
84
|
+
const existing = slotPair(doc, section, key);
|
|
85
|
+
if (existing !== undefined)
|
|
86
|
+
existing.value = doc.createNode(value);
|
|
87
|
+
else
|
|
88
|
+
doc.setIn([...sectionAstPath(section), key], value);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Delete one slot's pair, string-key-matched for the numeric-key reason above
|
|
92
|
+
* (`deleteIn` with "404" reports nothing deleted and the slot survives in
|
|
93
|
+
* silence). Returns whether a pair actually went.
|
|
94
|
+
*/
|
|
95
|
+
export function deleteSlot(doc, section, key) {
|
|
96
|
+
return deleteKeyIn(doc.getIn(sectionAstPath(section)), key);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Refuse a living container the merge cannot write into: a container spelled
|
|
100
|
+
* as something other than a mapping is a document loam cannot merge, and one
|
|
101
|
+
* spelled as a YAML alias would take the write into every node that shares
|
|
102
|
+
* the anchor. Asked at the WRITE, because reading is safe and writing is not
|
|
103
|
+
* — an absent container is fine, the writers above create it.
|
|
104
|
+
*
|
|
105
|
+
* Takes a raw path rather than an `AsyncapiSection`, because the merge writes
|
|
106
|
+
* outside the three slot sections too: a component surface lands at
|
|
107
|
+
* `["components", <kind>]`, and a section-typed guard simply could not be
|
|
108
|
+
* asked about it. Skipping the question there would let a living
|
|
109
|
+
* `components: *alias` take a surface write into every node sharing the
|
|
110
|
+
* anchor — the exact corruption this function exists to refuse, at the one
|
|
111
|
+
* depth it could not see. Lives beside the writers rather than in the merge
|
|
112
|
+
* so the guard and the write cannot disagree about which node a path names.
|
|
113
|
+
*/
|
|
114
|
+
export function writableSection(living, livingPlain, path, service) {
|
|
115
|
+
for (let depth = 1; depth <= path.length; depth += 1) {
|
|
116
|
+
const prefix = path.slice(0, depth);
|
|
117
|
+
const plain = prefix.reduce((node, step) => (isRecord(node) ? node[step] : undefined), livingPlain);
|
|
118
|
+
if (plain === undefined || plain === null)
|
|
119
|
+
return;
|
|
120
|
+
const label = prefix.join(".");
|
|
121
|
+
if (!isRecord(plain)) {
|
|
122
|
+
throw new AsyncapiMergeError("living", service, `'${label}' is not a mapping`);
|
|
123
|
+
}
|
|
124
|
+
if (!isMap(living.getIn(prefix))) {
|
|
125
|
+
throw new AsyncapiMergeError("living", service, `'${label}' is written as a YAML alias — one shared value backs every use, so merging into it would rewrite every other node that aliases it. Expand it before archiving.`);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
/** One slot's human label: `channels.<key>` — with the message's join name where it has one. */
|
|
130
|
+
export function slotLabel(section, key, name) {
|
|
131
|
+
const at = `${section}.${key}`;
|
|
132
|
+
return name !== undefined && name !== key ? `'${name}' (${at})` : at;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Refuse a document whose section spells one slot key twice — `channels:
|
|
136
|
+
* {404: …, "404": …}` is legal YAML (a number and a string are distinct
|
|
137
|
+
* keys), but the resolved walk (`asyncapiSlots` reads `Object.entries` of
|
|
138
|
+
* `toJS()`) keeps the LAST pair while every string-matched AST access above
|
|
139
|
+
* finds the FIRST: the walker would grade one pair and the writer replace
|
|
140
|
+
* the other, and no single read discipline can make the two agree about
|
|
141
|
+
* which node the (section, key) names. Every entry point that walks slots —
|
|
142
|
+
* the pin, the strip, the merge — refuses it by name instead of writing
|
|
143
|
+
* through the wrong pair.
|
|
144
|
+
*/
|
|
145
|
+
export function refuseAmbiguousSlotKeys(doc, source, service) {
|
|
146
|
+
for (const section of SECTIONS) {
|
|
147
|
+
const node = doc.getIn(sectionAstPath(section));
|
|
148
|
+
if (!isMap(node))
|
|
149
|
+
continue;
|
|
150
|
+
const seen = new Set();
|
|
151
|
+
for (const it of node.items) {
|
|
152
|
+
if (!isScalar(it.key))
|
|
153
|
+
continue;
|
|
154
|
+
const key = String(it.key.value);
|
|
155
|
+
if (seen.has(key)) {
|
|
156
|
+
throw new AsyncapiMergeError(source, service, `'${section}' spells the key '${key}' in two pairs (two YAML scalars that stringify identically, e.g. 404 and "404") — loam cannot tell which pair a slot access should read or write; merge them into one entry`, "is ambiguous");
|
|
157
|
+
}
|
|
158
|
+
seen.add(key);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Remove feature-only markers — removal-marker slots, the pins on the slots
|
|
164
|
+
* that survive, and both loam keys at every nested depth of the whole
|
|
165
|
+
* document — before a feature contract is used to create a brand-new living
|
|
166
|
+
* document. Normally coherence refuses the removal shape because there cannot
|
|
167
|
+
* be a removal target; this guard also keeps `--approve` from ever persisting
|
|
168
|
+
* a marker into living docs.
|
|
169
|
+
*
|
|
170
|
+
* Edit the AST in place when every node the strip touches IS a node — the
|
|
171
|
+
* author's comments, key order and formatting are theirs to keep. An alias
|
|
172
|
+
* cannot be edited in place (there is one shared value behind it, and editing
|
|
173
|
+
* a slot through it would change every use), and a slot whose KEY is not a
|
|
174
|
+
* scalar is not findable by name at all — so a section holding either gets
|
|
175
|
+
* rewritten from the resolved tree instead: losing formatting is a cost,
|
|
176
|
+
* shipping the marker is a corruption. The openapi strip's two-branch
|
|
177
|
+
* discipline, per section.
|
|
178
|
+
*/
|
|
179
|
+
export function stripAsyncapiMarkers(featureText, service) {
|
|
180
|
+
const feature = parseDocument(featureText);
|
|
181
|
+
if (feature.errors.length > 0) {
|
|
182
|
+
throw new AsyncapiMergeError("feature", service, feature.errors[0].message);
|
|
183
|
+
}
|
|
184
|
+
refuseAmbiguousSlotKeys(feature, "feature", service);
|
|
185
|
+
let plain;
|
|
186
|
+
try {
|
|
187
|
+
// Resolve aliases once with the document's own anchor context — an
|
|
188
|
+
// individual node's toJSON() loses it (the openapi merge's lesson).
|
|
189
|
+
plain = feature.toJS() ?? {};
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
throw new AsyncapiMergeError("feature", service, errorMessage(error));
|
|
193
|
+
}
|
|
194
|
+
let stripped = false;
|
|
195
|
+
for (const section of SECTIONS) {
|
|
196
|
+
// Shape from the RESOLVED tree, for the same reason the merge reads it
|
|
197
|
+
// there: an aliased section is not a map node, and treating it as
|
|
198
|
+
// "nothing to strip" is how a feature-only marker reached a living
|
|
199
|
+
// contract on the OpenAPI axis.
|
|
200
|
+
const sectionPlain = sectionAstPath(section).reduce((node, step) => (isRecord(node) ? node[step] : undefined), plain);
|
|
201
|
+
if (!isRecord(sectionPlain))
|
|
202
|
+
continue;
|
|
203
|
+
const cleaned = {};
|
|
204
|
+
// `kept: undefined` means the slot goes — a resolved YAML value is never
|
|
205
|
+
// undefined itself (`~` reads as null), so the sentinel is unambiguous.
|
|
206
|
+
const edits = [];
|
|
207
|
+
for (const [key, value] of Object.entries(sectionPlain)) {
|
|
208
|
+
// A removal marker asserts a slot rather than declaring content; the
|
|
209
|
+
// create branch has no target to delete, so the slot itself goes.
|
|
210
|
+
const kept = isSlotRemoval(value) ? undefined : withoutFeatureKeysDeep(value);
|
|
211
|
+
if (kept !== value)
|
|
212
|
+
edits.push({ key, kept });
|
|
213
|
+
if (kept !== undefined)
|
|
214
|
+
cleaned[key] = kept;
|
|
215
|
+
}
|
|
216
|
+
if (edits.length === 0)
|
|
217
|
+
continue;
|
|
218
|
+
stripped = true;
|
|
219
|
+
// In place only when every touched node is reachable: the section is a
|
|
220
|
+
// real map and each edited slot's pair is findable by string key.
|
|
221
|
+
const editable = isMap(feature.getIn(sectionAstPath(section))) &&
|
|
222
|
+
edits.every(({ key }) => slotPair(feature, section, key) !== undefined);
|
|
223
|
+
if (!editable) {
|
|
224
|
+
feature.setIn(sectionAstPath(section), cleaned);
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
for (const { key, kept } of edits) {
|
|
228
|
+
if (kept === undefined)
|
|
229
|
+
deleteSlot(feature, section, key);
|
|
230
|
+
// The surviving slot's value is replaced wholesale with the deep-strip:
|
|
231
|
+
// a pin at slot depth could be deleted key-by-key, but a marker nested
|
|
232
|
+
// on an inline channel message sits where no fixed path reaches — the
|
|
233
|
+
// resolved copy is the one branch both depths share.
|
|
234
|
+
else
|
|
235
|
+
setSlotValue(feature, section, key, kept);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
if (isRecord(plain))
|
|
239
|
+
stripped = stripBeyondSections(feature, plain) || stripped;
|
|
240
|
+
// The root `x-loam-baselines` record, on EVERY branch — including the
|
|
241
|
+
// verbatim early return below. `stripBeyondSections` cannot do it: it
|
|
242
|
+
// filters on FEATURE_ONLY_KEYS, which holds the two IN-VALUE keys and not
|
|
243
|
+
// this one, so the record's own subtree (16-hex digests) carries no loam key
|
|
244
|
+
// for the deep strip to find and the whole entry rides out untouched. That
|
|
245
|
+
// is the create branch publishing loam's bookkeeping into a living
|
|
246
|
+
// asyncapi.yaml, where nothing catches it: `removalMarkerPaths` — validate's
|
|
247
|
+
// marker sweep on this axis — only ever looks for `x-loam-remove`.
|
|
248
|
+
if (isRecord(plain) && ASYNCAPI_BASELINES_KEY in plain) {
|
|
249
|
+
feature.deleteIn([ASYNCAPI_BASELINES_KEY]);
|
|
250
|
+
stripped = true;
|
|
251
|
+
}
|
|
252
|
+
if (!stripped)
|
|
253
|
+
return featureText;
|
|
254
|
+
try {
|
|
255
|
+
return feature.toString();
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
throw new AsyncapiMergeError("feature", service, errorMessage(error));
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* The strip's reach OUTSIDE the three sections: the document root's own
|
|
263
|
+
* keys, `info`, `servers`, and the `components` siblings of `messages` —
|
|
264
|
+
* everything the section loop above deliberately does not touch. A loam key
|
|
265
|
+
* here is feature-only exactly as it is inside a slot, and the create branch
|
|
266
|
+
* used to publish it (an `x-loam-remove: true` at the root reached a living
|
|
267
|
+
* contract with zero diagnosis). A loam key at this depth is deleted; any
|
|
268
|
+
* other entry whose subtree carries one is replaced with its deep-strip,
|
|
269
|
+
* through the same string-matched pair access the slot writers use.
|
|
270
|
+
*/
|
|
271
|
+
function stripBeyondSections(feature, plain) {
|
|
272
|
+
let stripped = false;
|
|
273
|
+
const strip = (path, key, value) => {
|
|
274
|
+
const parent = path.length === 0 ? feature.contents : feature.getIn(path);
|
|
275
|
+
if (FEATURE_ONLY_KEYS.has(key)) {
|
|
276
|
+
stripped = deleteKeyIn(parent, key) || stripped;
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
const kept = withoutFeatureKeysDeep(value);
|
|
280
|
+
if (kept === value)
|
|
281
|
+
return;
|
|
282
|
+
stripped = true;
|
|
283
|
+
const pair = pairAt(parent, key);
|
|
284
|
+
// The section loop's fallback, one entry wide: a pair no string can find
|
|
285
|
+
// is rewritten from the resolved tree rather than left carrying markers.
|
|
286
|
+
if (pair !== undefined)
|
|
287
|
+
pair.value = feature.createNode(kept);
|
|
288
|
+
else
|
|
289
|
+
feature.setIn([...path, key], kept);
|
|
290
|
+
};
|
|
291
|
+
for (const [key, value] of Object.entries(plain)) {
|
|
292
|
+
if (key === "channels" || key === "operations")
|
|
293
|
+
continue;
|
|
294
|
+
if (key === "components") {
|
|
295
|
+
// `components.messages` is the section loop's; the siblings are ours.
|
|
296
|
+
if (!isRecord(value))
|
|
297
|
+
continue;
|
|
298
|
+
for (const [ck, cv] of Object.entries(value)) {
|
|
299
|
+
if (ck !== "messages")
|
|
300
|
+
strip(["components"], ck, cv);
|
|
301
|
+
}
|
|
302
|
+
continue;
|
|
303
|
+
}
|
|
304
|
+
strip([], key, value);
|
|
305
|
+
}
|
|
306
|
+
return stripped;
|
|
307
|
+
}
|
|
308
|
+
//# sourceMappingURL=markers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markers.js","sourceRoot":"","sources":["../../../../src/core/asyncapi/merge/markers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,aAAa,EAA4B,MAAM,MAAM,CAAC;AAChF,+EAA+E;AAC/E,8DAA8D;AAC9D,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AACnD,8EAA8E;AAC9E,4EAA4E;AAC5E,2EAA2E;AAC3E,uDAAuD;AACvD,OAAO,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACpF,OAAO,EAAE,sBAAsB,EAAE,aAAa,EAAwB,MAAM,cAAc,CAAC;AAC3F,OAAO,EAAE,YAAY,EAAE,kBAAkB,EAA4B,MAAM,YAAY,CAAC;AAExF,kGAAkG;AAClG,MAAM,QAAQ,GAAsB,CAAC,UAAU,EAAE,YAAY,EAAE,qBAAqB,CAAC,CAAC;AAEtF;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAa;IACjD,OAAO,sBAAsB,CAAC,IAAI,CAAC,CAAC;AACtC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,OAAwB;IACrD,OAAO,OAAO,KAAK,qBAAqB,CAAC,CAAC,CAAC,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;AACpF,CAAC;AAED,yGAAyG;AACzG,SAAS,MAAM,CAAC,IAAa,EAAE,GAAW;IACxC,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7G,CAAC;AAED,qGAAqG;AACrG,SAAS,WAAW,CAAC,IAAa,EAAE,GAAW;IAC7C,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAC/B,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;IAC1F,IAAI,EAAE,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACzB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;IACzB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,QAAQ,CAAC,GAAa,EAAE,OAAwB,EAAE,GAAW;IAC3E,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACzD,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,YAAY,CAAC,GAAa,EAAE,OAAwB,EAAE,GAAW,EAAE,KAAc;IAC/F,MAAM,QAAQ,GAAG,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;IAC7C,IAAI,QAAQ,KAAK,SAAS;QAAE,QAAQ,CAAC,KAAK,GAAG,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;;QAC9D,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;AAC3D,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,GAAa,EAAE,OAAwB,EAAE,GAAW;IAC7E,OAAO,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC9D,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAC7B,MAAgB,EAChB,WAAoB,EACpB,IAAc,EACd,OAAe;IAEf,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;QACpC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAU,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,WAAW,CAAC,CAAC;QAC7G,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO;QAClD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACrB,MAAM,IAAI,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,KAAK,oBAAoB,CAAC,CAAC;QACjF,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,kBAAkB,CAC1B,QAAQ,EACR,OAAO,EACP,IAAI,KAAK,iKAAiK,CAC3K,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,gGAAgG;AAChG,MAAM,UAAU,SAAS,CAAC,OAAwB,EAAE,GAAW,EAAE,IAAa;IAC5E,MAAM,EAAE,GAAG,GAAG,OAAO,IAAI,GAAG,EAAE,CAAC;IAC/B,OAAO,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;AACvE,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAa,EAAE,MAA2B,EAAE,OAAe;IACjG,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;QAChD,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAS;QAC3B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;QAC/B,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC5B,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC;gBAAE,SAAS;YAChC,MAAM,GAAG,GAAG,MAAM,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACjC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBAClB,MAAM,IAAI,kBAAkB,CAC1B,MAAM,EACN,OAAO,EACP,IAAI,OAAO,qBAAqB,GAAG,8KAA8K,EACjN,cAAc,CACf,CAAC;YACJ,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChB,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,oBAAoB,CAAC,WAAmB,EAAE,OAAe;IACvE,MAAM,OAAO,GAAG,aAAa,CAAC,WAAW,CAAC,CAAC;IAC3C,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,kBAAkB,CAAC,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,CAAC;IAC/E,CAAC;IACD,uBAAuB,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IACrD,IAAI,KAAc,CAAC;IACnB,IAAI,CAAC;QACH,mEAAmE;QACnE,oEAAoE;QACpE,KAAK,GAAG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC;IAC/B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,kBAAkB,CAAC,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IACxE,CAAC;IAED,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,uEAAuE;QACvE,kEAAkE;QAClE,mEAAmE;QACnE,gCAAgC;QAChC,MAAM,YAAY,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC,MAAM,CACjD,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EACzD,KAAK,CACN,CAAC;QACF,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;YAAE,SAAS;QAEtC,MAAM,OAAO,GAA4B,EAAE,CAAC;QAC5C,yEAAyE;QACzE,wEAAwE;QACxE,MAAM,KAAK,GAA0C,EAAE,CAAC;QACxD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;YACxD,qEAAqE;YACrE,kEAAkE;YAClE,MAAM,IAAI,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC;YAC9E,IAAI,IAAI,KAAK,KAAK;gBAAE,KAAK,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9C,IAAI,IAAI,KAAK,SAAS;gBAAE,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC;QAC9C,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,SAAS;QACjC,QAAQ,GAAG,IAAI,CAAC;QAEhB,uEAAuE;QACvE,kEAAkE;QAClE,MAAM,QAAQ,GACZ,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;YAC7C,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,KAAK,SAAS,CAAC,CAAC;QAC1E,IAAI,CAAC,QAAQ,EAAE,CAAC;YACd,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,CAAC;YAChD,SAAS;QACX,CAAC;QACD,KAAK,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,KAAK,EAAE,CAAC;YAClC,IAAI,IAAI,KAAK,SAAS;gBAAE,UAAU,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;YAC1D,wEAAwE;YACxE,uEAAuE;YACvE,sEAAsE;YACtE,qDAAqD;;gBAChD,YAAY,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAED,IAAI,QAAQ,CAAC,KAAK,CAAC;QAAE,QAAQ,GAAG,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,QAAQ,CAAC;IAEhF,sEAAsE;IACtE,sEAAsE;IACtE,0EAA0E;IAC1E,6EAA6E;IAC7E,2EAA2E;IAC3E,mEAAmE;IACnE,6EAA6E;IAC7E,mEAAmE;IACnE,IAAI,QAAQ,CAAC,KAAK,CAAC,IAAI,sBAAsB,IAAI,KAAK,EAAE,CAAC;QACvD,OAAO,CAAC,QAAQ,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC;QAC3C,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC;IAED,IAAI,CAAC,QAAQ;QAAE,OAAO,WAAW,CAAC;IAClC,IAAI,CAAC;QACH,OAAO,OAAO,CAAC,QAAQ,EAAE,CAAC;IAC5B,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,kBAAkB,CAAC,SAAS,EAAE,OAAO,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IACxE,CAAC;AACH,CAAC;AAED;;;;;;;;;GASG;AACH,SAAS,mBAAmB,CAAC,OAAiB,EAAE,KAA8B;IAC5E,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,MAAM,KAAK,GAAG,CAAC,IAAc,EAAE,GAAW,EAAE,KAAc,EAAQ,EAAE;QAClE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1E,IAAI,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,QAAQ,GAAG,WAAW,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,QAAQ,CAAC;YAChD,OAAO;QACT,CAAC;QACD,MAAM,IAAI,GAAG,sBAAsB,CAAC,KAAK,CAAC,CAAC;QAC3C,IAAI,IAAI,KAAK,KAAK;YAAE,OAAO;QAC3B,QAAQ,GAAG,IAAI,CAAC;QAChB,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACjC,yEAAyE;QACzE,yEAAyE;QACzE,IAAI,IAAI,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;;YACzD,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,IAAI,EAAE,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3C,CAAC,CAAC;IACF,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,IAAI,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,YAAY;YAAE,SAAS;QACzD,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;YACzB,sEAAsE;YACtE,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;gBAAE,SAAS;YAC/B,KAAK,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC7C,IAAI,EAAE,KAAK,UAAU;oBAAE,KAAK,CAAC,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;YACvD,CAAC;YACD,SAAS;QACX,CAAC;QACD,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC","sourcesContent":["/**\n * The keys loam adds to a feature's event contract that must never reach the\n * living one: `x-loam-based-on`, `x-loam-remove`, and the root\n * `x-loam-baselines` record — the same three spellings the OpenAPI axis\n * strips, gathered here for the same reason its markers\n * module exists: `stripAsyncapiMarkers` takes them out for the create branch\n * that publishes a feature document verbatim, and the merge takes them out\n * again on the way into a living document. Two spellings of \"which keys are\n * feature-only\" is how one of the two starts leaking a marker.\n *\n * The strip is DEEP, and it covers the WHOLE document. Deep by the format\n * spec's own decision: an inline channel message (`channels.<ck>.messages.<mk>`)\n * is channel-slot interior, so a pin or marker nested on it is part of the\n * channel's VALUE — the slot walker never visits it, and a slot-level strip\n * would publish it into the fleet's living contract exactly the way\n * `--approve` once published `x-loam-remove: true` inside a living OpenAPI\n * component. Whole-document because the create branch publishes this text\n * VERBATIM: a marker at the document root or a pin under `info` sits outside\n * every section, and a strip that walked only the three sections shipped\n * both into a living contract, unseen even by validate's marker sweep.\n */\nimport { isMap, isScalar, parseDocument, type Document, type Pair } from \"yaml\";\n// Every `isRecord` below asks one question of a resolved plain tree: is this a\n// node that can hold AsyncAPI keys — an object, not an array?\nimport { isRecord } from \"../../kernel/records.js\";\n// One spelling of the deep strip for both axes: the feature-only keys are the\n// SAME two strings on either (core/asyncapi/digest.ts aliases the constants\n// outright), so a drift between the strips would be two definitions of one\n// rule (the openapi digest module's own failure mode).\nimport { FEATURE_ONLY_KEYS, withoutFeatureKeysDeep } from \"../../openapi/digest.js\";\nimport { ASYNCAPI_BASELINES_KEY, isSlotRemoval, type AsyncapiSection } from \"../digest.js\";\nimport { errorMessage, AsyncapiMergeError, type AsyncapiMergeSource } from \"./error.js\";\n\n/** The three slot sections, in document order — every whole-document walk here goes over them. */\nconst SECTIONS: AsyncapiSection[] = [\"channels\", \"operations\", \"components.messages\"];\n\n/**\n * A slot's PUBLISHABLE value: every feature-only key removed, at any depth —\n * the top-level pin, a nested pin or marker on an inline channel message, and\n * anything an author buried deeper. What the merge writes and what the create\n * branch keeps; a removal-marker slot is never published at all (the merge\n * deletes its target, the strip drops it), so this is only ever asked of a\n * slot that survives.\n */\nexport function withoutFeatureMarkers(node: unknown): unknown {\n return withoutFeatureKeysDeep(node);\n}\n\n/**\n * The AST path of a section's own mapping — `slotPath` (../digest.ts) minus\n * the slot key, spelled beside the writers so the strip and the merge cannot\n * disagree about which node a section name addresses.\n */\nexport function sectionAstPath(section: AsyncapiSection): string[] {\n return section === \"components.messages\" ? [\"components\", \"messages\"] : [section];\n}\n\n/** One mapping node's pair for a key, matched AS A STRING — `slotPair`'s find, reusable at any depth. */\nfunction pairAt(node: unknown, key: string): Pair | undefined {\n return isMap(node) ? node.items.find((it) => isScalar(it.key) && String(it.key.value) === key) : undefined;\n}\n\n/** Delete one pair from a mapping node, string-key-matched. Returns whether a pair actually went. */\nfunction deleteKeyIn(node: unknown, key: string): boolean {\n if (!isMap(node)) return false;\n const at = node.items.findIndex((it) => isScalar(it.key) && String(it.key.value) === key);\n if (at < 0) return false;\n node.items.splice(at, 1);\n return true;\n}\n\n/**\n * Find one slot's key/value pair, matching the existing key AS A STRING: a\n * channel named `404:` is the YAML number 404, and a plain `getIn`/`setIn`\n * with the string \"404\" misses it and APPENDS a second pair — the living\n * contract then declares the slot twice, forever, with the pre-merge copy\n * first in reading order. The openapi component write's lesson, applied to\n * every slot access on this axis: the merge's writers below go through it,\n * and so does the pin (./pin.ts), whose raw `getIn` used to grade every\n * non-string-keyed slot `unwritable` with an alias diagnosis nothing in the\n * document backed.\n */\nexport function slotPair(doc: Document, section: AsyncapiSection, key: string): Pair | undefined {\n return pairAt(doc.getIn(sectionAstPath(section)), key);\n}\n\n/** Write one slot's value, string-key-matched — the merge's one upsert door. */\nexport function setSlotValue(doc: Document, section: AsyncapiSection, key: string, value: unknown): void {\n const existing = slotPair(doc, section, key);\n if (existing !== undefined) existing.value = doc.createNode(value);\n else doc.setIn([...sectionAstPath(section), key], value);\n}\n\n/**\n * Delete one slot's pair, string-key-matched for the numeric-key reason above\n * (`deleteIn` with \"404\" reports nothing deleted and the slot survives in\n * silence). Returns whether a pair actually went.\n */\nexport function deleteSlot(doc: Document, section: AsyncapiSection, key: string): boolean {\n return deleteKeyIn(doc.getIn(sectionAstPath(section)), key);\n}\n\n/**\n * Refuse a living container the merge cannot write into: a container spelled\n * as something other than a mapping is a document loam cannot merge, and one\n * spelled as a YAML alias would take the write into every node that shares\n * the anchor. Asked at the WRITE, because reading is safe and writing is not\n * — an absent container is fine, the writers above create it.\n *\n * Takes a raw path rather than an `AsyncapiSection`, because the merge writes\n * outside the three slot sections too: a component surface lands at\n * `[\"components\", <kind>]`, and a section-typed guard simply could not be\n * asked about it. Skipping the question there would let a living\n * `components: *alias` take a surface write into every node sharing the\n * anchor — the exact corruption this function exists to refuse, at the one\n * depth it could not see. Lives beside the writers rather than in the merge\n * so the guard and the write cannot disagree about which node a path names.\n */\nexport function writableSection(\n living: Document,\n livingPlain: unknown,\n path: string[],\n service: string,\n): void {\n for (let depth = 1; depth <= path.length; depth += 1) {\n const prefix = path.slice(0, depth);\n const plain = prefix.reduce<unknown>((node, step) => (isRecord(node) ? node[step] : undefined), livingPlain);\n if (plain === undefined || plain === null) return;\n const label = prefix.join(\".\");\n if (!isRecord(plain)) {\n throw new AsyncapiMergeError(\"living\", service, `'${label}' is not a mapping`);\n }\n if (!isMap(living.getIn(prefix))) {\n throw new AsyncapiMergeError(\n \"living\",\n service,\n `'${label}' is written as a YAML alias — one shared value backs every use, so merging into it would rewrite every other node that aliases it. Expand it before archiving.`,\n );\n }\n }\n}\n\n/** One slot's human label: `channels.<key>` — with the message's join name where it has one. */\nexport function slotLabel(section: AsyncapiSection, key: string, name?: string): string {\n const at = `${section}.${key}`;\n return name !== undefined && name !== key ? `'${name}' (${at})` : at;\n}\n\n/**\n * Refuse a document whose section spells one slot key twice — `channels:\n * {404: …, \"404\": …}` is legal YAML (a number and a string are distinct\n * keys), but the resolved walk (`asyncapiSlots` reads `Object.entries` of\n * `toJS()`) keeps the LAST pair while every string-matched AST access above\n * finds the FIRST: the walker would grade one pair and the writer replace\n * the other, and no single read discipline can make the two agree about\n * which node the (section, key) names. Every entry point that walks slots —\n * the pin, the strip, the merge — refuses it by name instead of writing\n * through the wrong pair.\n */\nexport function refuseAmbiguousSlotKeys(doc: Document, source: AsyncapiMergeSource, service: string): void {\n for (const section of SECTIONS) {\n const node = doc.getIn(sectionAstPath(section));\n if (!isMap(node)) continue;\n const seen = new Set<string>();\n for (const it of node.items) {\n if (!isScalar(it.key)) continue;\n const key = String(it.key.value);\n if (seen.has(key)) {\n throw new AsyncapiMergeError(\n source,\n service,\n `'${section}' spells the key '${key}' in two pairs (two YAML scalars that stringify identically, e.g. 404 and \"404\") — loam cannot tell which pair a slot access should read or write; merge them into one entry`,\n \"is ambiguous\",\n );\n }\n seen.add(key);\n }\n }\n}\n\n/**\n * Remove feature-only markers — removal-marker slots, the pins on the slots\n * that survive, and both loam keys at every nested depth of the whole\n * document — before a feature contract is used to create a brand-new living\n * document. Normally coherence refuses the removal shape because there cannot\n * be a removal target; this guard also keeps `--approve` from ever persisting\n * a marker into living docs.\n *\n * Edit the AST in place when every node the strip touches IS a node — the\n * author's comments, key order and formatting are theirs to keep. An alias\n * cannot be edited in place (there is one shared value behind it, and editing\n * a slot through it would change every use), and a slot whose KEY is not a\n * scalar is not findable by name at all — so a section holding either gets\n * rewritten from the resolved tree instead: losing formatting is a cost,\n * shipping the marker is a corruption. The openapi strip's two-branch\n * discipline, per section.\n */\nexport function stripAsyncapiMarkers(featureText: string, service: string): string {\n const feature = parseDocument(featureText);\n if (feature.errors.length > 0) {\n throw new AsyncapiMergeError(\"feature\", service, feature.errors[0]!.message);\n }\n refuseAmbiguousSlotKeys(feature, \"feature\", service);\n let plain: unknown;\n try {\n // Resolve aliases once with the document's own anchor context — an\n // individual node's toJSON() loses it (the openapi merge's lesson).\n plain = feature.toJS() ?? {};\n } catch (error) {\n throw new AsyncapiMergeError(\"feature\", service, errorMessage(error));\n }\n\n let stripped = false;\n for (const section of SECTIONS) {\n // Shape from the RESOLVED tree, for the same reason the merge reads it\n // there: an aliased section is not a map node, and treating it as\n // \"nothing to strip\" is how a feature-only marker reached a living\n // contract on the OpenAPI axis.\n const sectionPlain = sectionAstPath(section).reduce<unknown>(\n (node, step) => (isRecord(node) ? node[step] : undefined),\n plain,\n );\n if (!isRecord(sectionPlain)) continue;\n\n const cleaned: Record<string, unknown> = {};\n // `kept: undefined` means the slot goes — a resolved YAML value is never\n // undefined itself (`~` reads as null), so the sentinel is unambiguous.\n const edits: Array<{ key: string; kept: unknown }> = [];\n for (const [key, value] of Object.entries(sectionPlain)) {\n // A removal marker asserts a slot rather than declaring content; the\n // create branch has no target to delete, so the slot itself goes.\n const kept = isSlotRemoval(value) ? undefined : withoutFeatureKeysDeep(value);\n if (kept !== value) edits.push({ key, kept });\n if (kept !== undefined) cleaned[key] = kept;\n }\n if (edits.length === 0) continue;\n stripped = true;\n\n // In place only when every touched node is reachable: the section is a\n // real map and each edited slot's pair is findable by string key.\n const editable =\n isMap(feature.getIn(sectionAstPath(section))) &&\n edits.every(({ key }) => slotPair(feature, section, key) !== undefined);\n if (!editable) {\n feature.setIn(sectionAstPath(section), cleaned);\n continue;\n }\n for (const { key, kept } of edits) {\n if (kept === undefined) deleteSlot(feature, section, key);\n // The surviving slot's value is replaced wholesale with the deep-strip:\n // a pin at slot depth could be deleted key-by-key, but a marker nested\n // on an inline channel message sits where no fixed path reaches — the\n // resolved copy is the one branch both depths share.\n else setSlotValue(feature, section, key, kept);\n }\n }\n\n if (isRecord(plain)) stripped = stripBeyondSections(feature, plain) || stripped;\n\n // The root `x-loam-baselines` record, on EVERY branch — including the\n // verbatim early return below. `stripBeyondSections` cannot do it: it\n // filters on FEATURE_ONLY_KEYS, which holds the two IN-VALUE keys and not\n // this one, so the record's own subtree (16-hex digests) carries no loam key\n // for the deep strip to find and the whole entry rides out untouched. That\n // is the create branch publishing loam's bookkeeping into a living\n // asyncapi.yaml, where nothing catches it: `removalMarkerPaths` — validate's\n // marker sweep on this axis — only ever looks for `x-loam-remove`.\n if (isRecord(plain) && ASYNCAPI_BASELINES_KEY in plain) {\n feature.deleteIn([ASYNCAPI_BASELINES_KEY]);\n stripped = true;\n }\n\n if (!stripped) return featureText;\n try {\n return feature.toString();\n } catch (error) {\n throw new AsyncapiMergeError(\"feature\", service, errorMessage(error));\n }\n}\n\n/**\n * The strip's reach OUTSIDE the three sections: the document root's own\n * keys, `info`, `servers`, and the `components` siblings of `messages` —\n * everything the section loop above deliberately does not touch. A loam key\n * here is feature-only exactly as it is inside a slot, and the create branch\n * used to publish it (an `x-loam-remove: true` at the root reached a living\n * contract with zero diagnosis). A loam key at this depth is deleted; any\n * other entry whose subtree carries one is replaced with its deep-strip,\n * through the same string-matched pair access the slot writers use.\n */\nfunction stripBeyondSections(feature: Document, plain: Record<string, unknown>): boolean {\n let stripped = false;\n const strip = (path: string[], key: string, value: unknown): void => {\n const parent = path.length === 0 ? feature.contents : feature.getIn(path);\n if (FEATURE_ONLY_KEYS.has(key)) {\n stripped = deleteKeyIn(parent, key) || stripped;\n return;\n }\n const kept = withoutFeatureKeysDeep(value);\n if (kept === value) return;\n stripped = true;\n const pair = pairAt(parent, key);\n // The section loop's fallback, one entry wide: a pair no string can find\n // is rewritten from the resolved tree rather than left carrying markers.\n if (pair !== undefined) pair.value = feature.createNode(kept);\n else feature.setIn([...path, key], kept);\n };\n for (const [key, value] of Object.entries(plain)) {\n if (key === \"channels\" || key === \"operations\") continue;\n if (key === \"components\") {\n // `components.messages` is the section loop's; the siblings are ours.\n if (!isRecord(value)) continue;\n for (const [ck, cv] of Object.entries(value)) {\n if (ck !== \"messages\") strip([\"components\"], ck, cv);\n }\n continue;\n }\n strip([], key, value);\n }\n return stripped;\n}\n"]}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The archive-time merge on the event axis: a feature's asyncapi delta folded
|
|
3
|
+
* into the living contract, and every condition the caller has to surface
|
|
4
|
+
* afterwards — the OpenAPI merge's shape, slot-keyed instead of path-keyed.
|
|
5
|
+
*
|
|
6
|
+
* The result type carries far more than the merged text on purpose. A merge
|
|
7
|
+
* that quietly overwrote a slot, deleted a message, or ran against a stale
|
|
8
|
+
* baseline is not an error — it is a fact the archiving human has to be told,
|
|
9
|
+
* and a return value nobody can forget to read is the only place that
|
|
10
|
+
* survives a refactor.
|
|
11
|
+
*
|
|
12
|
+
* Every SHAPE question — which slots does the feature declare, what does the
|
|
13
|
+
* living contract hold at a (section, key) — is answered from the RESOLVED
|
|
14
|
+
* plain trees, never from the AST node: an alias node is not a map even when
|
|
15
|
+
* it resolves to one, and reading it as absent is how the OpenAPI merge once
|
|
16
|
+
* dropped whole contract deltas. The WRITES walk the AST, string-key-matched,
|
|
17
|
+
* and refuse aliases — one shared value backs every use of an anchor, so
|
|
18
|
+
* writing through one would rewrite every other node that aliases it.
|
|
19
|
+
*/
|
|
20
|
+
import { isDeepStrictEqual } from "node:util";
|
|
21
|
+
import { isMap, parseDocument } from "yaml";
|
|
22
|
+
import { classifyBaselineDigests } from "../../openapi/digest.js";
|
|
23
|
+
import { asyncapiSlots, slotDigest } from "../digest.js";
|
|
24
|
+
import { danglingRefs } from "../depth.js";
|
|
25
|
+
import { messageName } from "../read.js";
|
|
26
|
+
import { readBaselineRecord } from "../../openapi/baseline/record.js";
|
|
27
|
+
import { asyncapiSurfaces } from "../baseline/surfaces.js";
|
|
28
|
+
import { errorMessage, AsyncapiMergeError } from "./error.js";
|
|
29
|
+
import { mergeAsyncapiComponents } from "./components.js";
|
|
30
|
+
import { deleteSlot, refuseAmbiguousSlotKeys, sectionAstPath, setSlotValue, slotLabel, withoutFeatureMarkers, writableSection, } from "./markers.js";
|
|
31
|
+
/**
|
|
32
|
+
* Merge the feature's slots into the living AsyncAPI structurally (YAML AST,
|
|
33
|
+
* not text splicing). A feature document restating NOTHING — neither a slot
|
|
34
|
+
* nor a component surface — is a successful no-op; one whose whole delta is a
|
|
35
|
+
* `components.schemas` entry is merged like any other, through
|
|
36
|
+
* `mergeAsyncapiComponents` at the end of this function. Per slot, the pin
|
|
37
|
+
* decides: a QUOTE is never a merge input — not even
|
|
38
|
+
* under `--approve`, because overriding a gate is a decision and reverting a
|
|
39
|
+
* slot nobody edited is a bug — while `stale` still writes, since reaching
|
|
40
|
+
* the merge at all means `--approve` said to. A removal marker deletes its
|
|
41
|
+
* exact target and the section key when the section empties; everything
|
|
42
|
+
* published goes through the deep marker strip.
|
|
43
|
+
*/
|
|
44
|
+
export function mergeAsyncapiSlots(livingText, featureText, service) {
|
|
45
|
+
const feature = parseDocument(featureText);
|
|
46
|
+
if (feature.errors.length > 0) {
|
|
47
|
+
throw new AsyncapiMergeError("feature", service, feature.errors[0].message);
|
|
48
|
+
}
|
|
49
|
+
// Two pairs whose keys stringify identically (404 and "404") would make
|
|
50
|
+
// the resolved walk and the string-matched writers disagree about which
|
|
51
|
+
// node a slot names — refused on either side, before any verdict is taken.
|
|
52
|
+
refuseAmbiguousSlotKeys(feature, "feature", service);
|
|
53
|
+
let featPlain;
|
|
54
|
+
try {
|
|
55
|
+
// Resolve aliases once with the document's own anchor context. Calling an
|
|
56
|
+
// individual AST node's toJSON() loses that context and can silently turn
|
|
57
|
+
// an aliased slot into the wrong value.
|
|
58
|
+
featPlain = feature.toJS() ?? {};
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw new AsyncapiMergeError("feature", service, errorMessage(error));
|
|
62
|
+
}
|
|
63
|
+
const featSlots = asyncapiSlots(featPlain);
|
|
64
|
+
// "Is there anything to merge?" is a question about the WHOLE delta, and it
|
|
65
|
+
// was asked of the three slot sections alone — an absence test standing in
|
|
66
|
+
// for the decision. It returned before the living document was even parsed,
|
|
67
|
+
// so `mergeAsyncapiComponents` (the last thing this function does, and the
|
|
68
|
+
// only thing that writes a component surface) never ran: a feature whose
|
|
69
|
+
// entire change was a `components.schemas` entry passed the gate and
|
|
70
|
+
// archived at exit 0 having merged NOTHING. The surfaces answer it too now,
|
|
71
|
+
// over the ONE enumeration the gate and the rebase plan already grade the
|
|
72
|
+
// delta with. Deleting the early return alone would have changed nothing:
|
|
73
|
+
// there was no writer outside the slot loop to fall through to.
|
|
74
|
+
if (featSlots.length === 0 && asyncapiSurfaces(featPlain).length === 0)
|
|
75
|
+
return noop();
|
|
76
|
+
const living = parseDocument(livingText);
|
|
77
|
+
if (living.errors.length > 0) {
|
|
78
|
+
throw new AsyncapiMergeError("living", service, living.errors[0].message);
|
|
79
|
+
}
|
|
80
|
+
refuseAmbiguousSlotKeys(living, "living", service);
|
|
81
|
+
let livingPlain;
|
|
82
|
+
try {
|
|
83
|
+
livingPlain = living.toJS() ?? {};
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
throw new AsyncapiMergeError("living", service, errorMessage(error));
|
|
87
|
+
}
|
|
88
|
+
const livingBySlot = new Map(asyncapiSlots(livingPlain).map((slot) => [`${slot.section}\0${slot.key}`, slot]));
|
|
89
|
+
// Read ONCE here, not per surface: `problems` are deliberately ignored — a
|
|
90
|
+
// malformed record is the gate's diagnosis (`asyncapi.baseline-invalid`) and
|
|
91
|
+
// a parser never prints, so what reaches the surface merge is whatever read
|
|
92
|
+
// back cleanly, and an entry that did not is simply absent (= unpinned).
|
|
93
|
+
const { record } = readBaselineRecord(featPlain);
|
|
94
|
+
const modified = [];
|
|
95
|
+
const removed = [];
|
|
96
|
+
const quoted = [];
|
|
97
|
+
const baselineStale = [];
|
|
98
|
+
const touched = new Set();
|
|
99
|
+
let edited = false;
|
|
100
|
+
for (const slot of featSlots) {
|
|
101
|
+
const before = livingBySlot.get(`${slot.section}\0${slot.key}`);
|
|
102
|
+
const name = slot.section === "components.messages" ? messageName(slot.node, slot.key) : undefined;
|
|
103
|
+
const at = { section: slot.section, label: slotLabel(slot.section, slot.key, name) };
|
|
104
|
+
if (slot.remove) {
|
|
105
|
+
// Coherence validates the marker and gates absent/mismatched targets.
|
|
106
|
+
// The merge remains defensive under --approve: never delete a different
|
|
107
|
+
// message merely because it occupies the requested slot. Channel and
|
|
108
|
+
// operation identity IS the key, so presence is the whole match there.
|
|
109
|
+
if (before === undefined)
|
|
110
|
+
continue;
|
|
111
|
+
if (slot.section === "components.messages" && messageName(before.node, slot.key) !== name)
|
|
112
|
+
continue;
|
|
113
|
+
writableSection(living, livingPlain, sectionAstPath(slot.section), service);
|
|
114
|
+
if (deleteSlot(living, slot.section, slot.key)) {
|
|
115
|
+
removed.push(at);
|
|
116
|
+
touched.add(slot.section);
|
|
117
|
+
edited = true;
|
|
118
|
+
}
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const verdict = classifyBaselineDigests(slot.basedOn, slot.digest, before === undefined ? undefined : slotDigest(before.node));
|
|
122
|
+
// A QUOTE is not a merge input. The author wrote this slot down because
|
|
123
|
+
// the document is complete, not because they changed it, so the living
|
|
124
|
+
// contract keeps whatever it holds — including a change that landed after
|
|
125
|
+
// this delta was written. Mechanical, not a judgement: `--approve` does
|
|
126
|
+
// not turn it back on.
|
|
127
|
+
if (verdict === "quote") {
|
|
128
|
+
quoted.push(at);
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (verdict === "stale")
|
|
132
|
+
baselineStale.push(at);
|
|
133
|
+
const publish = withoutFeatureMarkers(slot.node);
|
|
134
|
+
// An unpinned restatement equal to the living slot has nothing to write —
|
|
135
|
+
// the component closure's rule, kept here so a never-rebased delta that
|
|
136
|
+
// merely restates the contract does not churn its bytes.
|
|
137
|
+
if (before !== undefined && isDeepStrictEqual(before.node, publish))
|
|
138
|
+
continue;
|
|
139
|
+
if (before !== undefined)
|
|
140
|
+
modified.push(at);
|
|
141
|
+
writableSection(living, livingPlain, sectionAstPath(slot.section), service);
|
|
142
|
+
// Without the strip the living contract would grow a pin to a version of
|
|
143
|
+
// itself — and, on this axis, a marker nested on an inline channel
|
|
144
|
+
// message, invisible to the slot walker (SCHEMA.md's channel-interior
|
|
145
|
+
// decision: the strip works at that nested depth exactly as at slot depth).
|
|
146
|
+
setSlotValue(living, slot.section, slot.key, publish);
|
|
147
|
+
edited = true;
|
|
148
|
+
}
|
|
149
|
+
// Removing the last slot leaves a section the contract still spells and
|
|
150
|
+
// nothing declares — delete the emptied mapping, and `components` too when
|
|
151
|
+
// the messages were all it held. After the whole loop, so a removal and an
|
|
152
|
+
// upsert into one section never race the cleanup.
|
|
153
|
+
for (const section of touched) {
|
|
154
|
+
const node = living.getIn(sectionAstPath(section));
|
|
155
|
+
if (!isMap(node) || node.items.length > 0)
|
|
156
|
+
continue;
|
|
157
|
+
living.deleteIn(sectionAstPath(section));
|
|
158
|
+
if (section === "components.messages") {
|
|
159
|
+
const components = living.getIn(["components"]);
|
|
160
|
+
if (isMap(components) && components.items.length === 0)
|
|
161
|
+
living.deleteIn(["components"]);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// The surface half, after the slot loop and its section cleanup so a write
|
|
165
|
+
// outside the three sections can never race them. `edited` has to take the
|
|
166
|
+
// closure's answer: without it the verdicts below would be computed and
|
|
167
|
+
// reported while the `!edited` return discarded the document they were
|
|
168
|
+
// computed over — the defect surviving in a new shape, with the plan naming
|
|
169
|
+
// a schema that never reached the living contract.
|
|
170
|
+
const surfaces = mergeAsyncapiComponents({ living, featPlain, livingPlain, record, service });
|
|
171
|
+
const { componentsModified, componentsQuoted, componentsStale } = surfaces;
|
|
172
|
+
if (surfaces.copied)
|
|
173
|
+
edited = true;
|
|
174
|
+
// Nothing written: the living document must not even be re-serialized —
|
|
175
|
+
// byte-identity under an all-quote delta is the whole point of the pin.
|
|
176
|
+
if (!edited) {
|
|
177
|
+
return {
|
|
178
|
+
text: null, modified, removed, quoted, baselineStale,
|
|
179
|
+
componentsModified, componentsQuoted, componentsStale, unresolved: [],
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
let mergedPlain;
|
|
183
|
+
let text;
|
|
184
|
+
try {
|
|
185
|
+
mergedPlain = living.toJS() ?? {};
|
|
186
|
+
text = living.toString();
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
throw new AsyncapiMergeError("living", service, errorMessage(error));
|
|
190
|
+
}
|
|
191
|
+
// The ref sweep grades what the MERGE would leave dangling: a merged slot
|
|
192
|
+
// pointing at something neither document defines, or a removal that took a
|
|
193
|
+
// target the living document still references. Refs already dangling in the
|
|
194
|
+
// living contract are validate's finding (asyncapi.ref-unresolved, warn),
|
|
195
|
+
// not this feature's doing — gating the archive on pre-existing rot would
|
|
196
|
+
// block every delta over an already-rotten contract.
|
|
197
|
+
const preexisting = new Set(danglingRefs(livingPlain));
|
|
198
|
+
const unresolved = danglingRefs(mergedPlain).filter((ref) => !preexisting.has(ref));
|
|
199
|
+
return {
|
|
200
|
+
text, modified, removed, quoted, baselineStale,
|
|
201
|
+
componentsModified, componentsQuoted, componentsStale, unresolved,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* The successful "the feature document restates nothing at all" answer. Every
|
|
206
|
+
* key of the result is spelled here, empty, rather than left off — the reason
|
|
207
|
+
* `AsyncapiMergeResult` gives for the three surface fields.
|
|
208
|
+
*/
|
|
209
|
+
function noop() {
|
|
210
|
+
return {
|
|
211
|
+
text: null, modified: [], removed: [], quoted: [], baselineStale: [],
|
|
212
|
+
componentsModified: [], componentsQuoted: [], componentsStale: [], unresolved: [],
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
//# sourceMappingURL=merge.js.map
|