@ybotok/loam 0.1.0-beta.3 → 0.2.0-alpha.2
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 +2635 -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 +599 -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 +323 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +180 -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 +252 -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 +204 -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 +270 -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 +251 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +251 -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 +337 -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 +48 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +174 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/likec4.js +90 -0
- package/dist/core/c4/likec4.js.map +1 -0
- package/dist/core/c4/parsed/deployment.js +158 -0
- package/dist/core/c4/parsed/deployment.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js +132 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
- package/dist/core/c4/parsed/specification.js +78 -0
- package/dist/core/c4/parsed/specification.js.map +1 -0
- package/dist/core/c4/parsed/values.js +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 +187 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/project/staged.js +220 -0
- package/dist/core/c4/project/staged.js.map +1 -0
- package/dist/core/c4/resolve/service.js +159 -0
- package/dist/core/c4/resolve/service.js.map +1 -0
- package/dist/core/c4/resolve/steps.js +144 -0
- package/dist/core/c4/resolve/steps.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 +139 -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 +174 -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 +287 -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/deployment/delta.js +188 -0
- package/dist/core/deployment/delta.js.map +1 -0
- package/dist/core/deployment/objects.js +145 -0
- package/dist/core/deployment/objects.js.map +1 -0
- package/dist/core/diff/base-git.js +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 +137 -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 +210 -0
- package/dist/core/repo/authored/paths.js.map +1 -0
- package/dist/core/repo/entries.js +126 -0
- package/dist/core/repo/entries.js.map +1 -0
- package/dist/core/repo/paths.js +277 -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 +196 -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 +197 -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 +72 -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 +58 -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":"living.js","sourceRoot":"","sources":["../../../src/core/pack/living.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The living slice of one service's context pack: its requirements verbatim,\n * its two contracts, its provenance, its maturity, and the fleet edges around\n * it — everything the docs repo says about the service TODAY, before any\n * feature in flight is consulted.\n *\n * Split from `./pack.ts` because it answers about the LIVING documents while\n * `./features.ts` answers about the deltas over them — two phases of one\n * briefing, and the line limit is what asked the question.\n */\nimport { existsSync } from \"node:fs\";\nimport { FleetContext } from \"../fleet-context.js\";\nimport { serviceResolver } from \"../c4/resolve/service.js\";\nimport { repoPath } from \"../envelope/json.js\";\nimport { listField, parseFrontmatter, stringField, type Frontmatter } from \"../document/frontmatter.js\";\nimport { scopeText } from \"../provenance/sample/scope.js\";\nimport { type Requirement } from \"../document/spec.js\";\nimport {\n landscapeEvidence,\n maturityGaps,\n serviceMaturity,\n type LandscapeEdge,\n type Maturity,\n} from \"../vocabulary/maturity.js\";\nimport { type ServiceEntry } from \"../repo/entries.js\";\nimport { landscapePath, servicePathsAt } from \"../repo/paths.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\nimport { hasDeployment, NO_DEPLOYMENT } from \"../c4/parsed/deployment.js\";\nimport { loadArchitecture } from \"../c4/project/architecture.js\";\nimport { serviceTopology, type ServiceTopology } from \"../deployment/objects.js\";\n\n/**\n * A requirement as the pack carries it: the delta brief's `reqJson` shape plus\n * the four join lines (`Requires:`, `Capability:`, `Publishes:`, `Consumes:`)\n * the brief never needed. Verbatim on purpose — the pack is the briefing, and\n * a heading without its body is a table of contents for a file the reader then\n * has to open.\n */\nexport interface PackRequirement {\n kind: Requirement[\"kind\"];\n id?: string;\n name: string;\n text: string;\n operations: string[];\n covers: string[];\n requires: string[];\n capabilities: string[];\n publishes: string[];\n consumes: string[];\n /** Verbatim: the acceptance criteria, and the source for the tests whoever picks this up writes. */\n scenarios: Array<{ name: string; lines: string[] }>;\n}\n\nexport function packRequirement(r: Requirement): PackRequirement {\n return {\n kind: r.kind,\n ...(r.id === undefined ? {} : { id: r.id }),\n name: r.name,\n text: r.text.join(\"\\n\").trim(),\n operations: r.operations,\n covers: r.covers,\n requires: r.requires,\n capabilities: r.capabilities,\n publishes: r.publishes,\n consumes: r.consumes,\n scenarios: r.scenarios.map((s) => ({ name: s.name, lines: s.lines })),\n };\n}\n\nexport interface LivingSlice {\n maturity: Maturity;\n /** What stands between the service and `vouched` — `maturityGaps`, so it matches `list --needs-work`. */\n missing: string[];\n /**\n * `vouch_scope` rides beside `status` because this pack is read by an agent\n * about to work on the service, and a bare `status: verified` over a vouch\n * that read a recorded sample of the document would be read as the whole of\n * it having been checked. Verbatim, null when there is none.\n *\n * spec.md's header ALONE — arch.spec.md carries its own, below.\n */\n frontmatter: {\n status: string | null;\n owner: string | null;\n last_verified: string | null;\n vouch_scope: string | null;\n sources: string[];\n };\n /**\n * arch.spec.md's own `vouch_scope`, under `show --json`'s spelling\n * (`archSpec.vouch_scope`) so the two surfaces name one fact one way.\n *\n * The sample is per FILE: one `loam vouch --sample` run reads a short\n * spec.md in full and stamps a long arch.spec.md sampled, and the pack read\n * only the first header. Every other trust surface — list, show,\n * `vouch --pack`, `validate --all`, status — reported that service as\n * sampled; context printed `verified`, `vouch_scope: null`, and then all of\n * arch.spec.md's requirements verbatim, of which nobody had read half. It is\n * the one surface whose reader is an agent that will act on the licence, and\n * `loam_context` exposes it as an MCP tool besides.\n */\n archSpec: { vouch_scope: string | null };\n /**\n * `present`/`parses` ride beside the edges (explore's shape) so silence is\n * evidence, not absence: an empty edge list under `parses: false` says\n * \"nobody could look\", not \"nobody calls this\".\n */\n landscape: {\n present: boolean;\n parses: boolean;\n modelled: boolean;\n inbound: LandscapeEdge[];\n outbound: LandscapeEdge[];\n };\n /**\n * Where this service runs, off the landscape's `deployment { }` model, and\n * the deployment edges touching it — replication, failover, a network hop.\n *\n * Both ends, not only the outbound one: a replication edge is as often read\n * from the standby's side as from the primary's. Empty for a fleet that draws\n * no topology, and empty is not a finding here any more than it is anywhere\n * else on this axis.\n *\n * WHAT IT IS NOT. A green deployment axis means the documents agree with each\n * other — never that the second cluster exists, is reachable, or holds the\n * data a requirement claims. `core/brief/unchecked.ts` says so beside the\n * sixteen statements that say the same about the rest of the map, and an\n * agent reading this slice is exactly the reader that sentence is for.\n */\n deployment: ServiceTopology;\n requirements: PackRequirement[];\n archRequirements: PackRequirement[];\n /** Whether the living contract could be read at all — the vacuously-green guard every sibling carries. */\n openapi: { unreadable: boolean; error?: string };\n operations: Array<{ id: string; method: string; path: string; governedBy: string[] }>;\n asyncapi: { unreadable: boolean; error?: string };\n messages: Array<{ name: string; slot: string; direction: \"send\" | \"receive\" | null }>;\n /** Free-form prose stays a pointer: unbounded documents do not belong in a bounded pack. */\n pointers: {\n runbook: { present: boolean; path: string };\n health: { present: boolean; path: string };\n adrs: { count: number; path: string };\n };\n}\n\nexport interface LivingRequest {\n docsDir: DocsDir;\n entry: ServiceEntry;\n context: FleetContext;\n}\n\nexport async function buildLiving(req: LivingRequest): Promise<LivingSlice> {\n const { docsDir, entry, context } = req;\n const paths = servicePathsAt(entry.dir);\n\n // Independent reads, fanned out together; each is memoized on the shared\n // context, so anything `./joins.ts` or `./features.ts` re-asks is free.\n const [reqs, archReqs, api, events, specText, archText, land] = await Promise.all([\n entry.has.spec ? context.readRequirements(paths.spec) : [],\n existsSync(paths.archSpec) ? context.readRequirements(paths.archSpec) : [],\n context.readOpenapi(paths.openapi),\n context.readAsyncapi(paths.asyncapi),\n entry.has.spec ? context.readText(paths.spec) : null,\n // Both headers, exactly as `show` reads both (commands/show/service.ts):\n // a memo hit on the same read the requirements above already paid for.\n existsSync(paths.archSpec) ? context.readText(paths.archSpec) : null,\n existsSync(landscapePath(docsDir)) ? context.loadLikeC4(landscapePath(docsDir)) : null,\n ]);\n\n const present = land !== null;\n const parses = land !== null && land.errors.length === 0;\n const elements = parses ? land.elements : [];\n // Edges are filed under the service an element is BOUND to, with the\n // enumerated fleet riding in — the same resolution `show`, `explore` and\n // `validate` use, so no two commands can disagree about who calls whom.\n const known = new Set((await context.listServices(docsDir)).map((s) => s.id));\n const svcOf = serviceResolver(elements, known);\n // The partition, the modelled probe and the apiExpected rule are ONE shared\n // derivation (core/vocabulary/maturity.ts `landscapeEvidence`) — the same\n // one explore's describe uses, so the pack and explore cannot grade the\n // same service differently.\n const { inbound, outbound, modelled, apiExpected } = landscapeEvidence({\n id: entry.id,\n parses,\n relationships: parses ? land.relationships : [],\n elementIds: elements.map((e) => e.id),\n svcOf,\n });\n // Where this service RUNS, from the landscape's own deployment model. The\n // pack's reader is an agent about to write the implementation, and until this\n // slice existed it described a service's calls and contracts while saying\n // nothing whatever about its topology — so a failover got written against a\n // map nobody had read. Empty for every fleet that draws none, which is the\n // axis's opt-in and not a finding.\n //\n // Read through the PROJECT when the landscape file itself declares none, for\n // the reason `validate/service/specs.ts` pays the same load: `architecture/`\n // is one LikeC4 project and a fleet's `deployment { }` block is ordinarily a\n // file beside the landscape, not inside it. A single-file read would report\n // \"this service runs nowhere\" over a repo that draws it, which is the one\n // answer a briefing must never give.\n const topology = parses ? (land.deployment ?? NO_DEPLOYMENT) : NO_DEPLOYMENT;\n const deployment = serviceTopology(\n hasDeployment(topology) || !parses ? topology : ((await loadArchitecture(docsDir)).deployment ?? NO_DEPLOYMENT),\n elements,\n known,\n entry.id,\n );\n\n const input = { entry, archSpec: existsSync(paths.archSpec), apiExpected };\n\n const header = (text: string | null): Frontmatter =>\n text === null ? { present: false, malformed: false, data: {}, body: \"\" } : parseFrontmatter(text);\n const fm: Frontmatter = header(specText);\n\n const governs = (op: string): string[] =>\n reqs.filter((r) => r.operations.includes(op)).map((r) => r.name);\n const sent = new Set(events.sent);\n const received = new Set(events.received);\n\n return {\n maturity: serviceMaturity(input),\n missing: maturityGaps(input),\n frontmatter: {\n status: stringField(fm, \"status\") ?? null,\n owner: stringField(fm, \"owner\") ?? null,\n last_verified: stringField(fm, \"last_verified\") ?? null,\n // Through `scopeText`, not `stringField`: a scope whose value is not\n // text is still a stamped partial read, and this pack is read by an\n // agent that will otherwise take `status: verified` at face value.\n vouch_scope: scopeText(fm),\n sources: listField(fm, \"sources\"),\n },\n archSpec: { vouch_scope: scopeText(header(archText)) },\n landscape: { present, parses, modelled, inbound, outbound },\n deployment,\n requirements: reqs.map(packRequirement),\n archRequirements: archReqs.map(packRequirement),\n openapi: { unreadable: api.unreadable, ...(api.error === undefined ? {} : { error: api.error }) },\n // Document order — a fact of the file, hence of the state. `x-loam-remove`\n // markers are filtered exactly as `show` filters them: they are deletion\n // markers from a delta, not operations anybody can call.\n operations: api.ops\n .filter((o) => !o.remove)\n .map((o) => ({ id: o.id, method: o.method.toUpperCase(), path: o.path, governedBy: governs(o.id) })),\n asyncapi: { unreadable: events.unreadable, ...(events.error === undefined ? {} : { error: events.error }) },\n messages: events.messages\n .filter((m) => m.remove !== true)\n .map((m) => ({\n name: m.name,\n slot: m.slot,\n direction: sent.has(m.name) ? \"send\" : received.has(m.name) ? \"receive\" : null,\n })),\n pointers: {\n runbook: { present: entry.has.runbook, path: repoPath(docsDir, paths.runbook) },\n health: { present: entry.has.health, path: repoPath(docsDir, paths.health) },\n // The enumeration already counted the ADRs; a second readdir here could\n // only disagree with it.\n adrs: { count: entry.adrs, path: repoPath(docsDir, paths.adrsDir) },\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One service's context pack: the exact docs slice bound to a service —
|
|
3
|
+
* living requirements verbatim, both contracts, the fleet edges one hop out,
|
|
4
|
+
* the permission and capability joins, provenance, and every active feature's
|
|
5
|
+
* delta over it — assembled as one deterministic payload an agent loads before
|
|
6
|
+
* working in that service's repository.
|
|
7
|
+
*
|
|
8
|
+
* Core rather than the command, exactly as `core/explore/explore.ts` sits
|
|
9
|
+
* behind `loam explore`: a future facade (an MCP tool, a second renderer)
|
|
10
|
+
* reuses the assembly without the printing, and the command layer stays I/O.
|
|
11
|
+
* Deterministic by construction — identical state must yield identical bytes:
|
|
12
|
+
* no timestamps, repo-relative forward-slash paths only, every unioned set
|
|
13
|
+
* sorted with `compareIds`, contract entries in document order (a fact of the
|
|
14
|
+
* file, hence of the state).
|
|
15
|
+
*/
|
|
16
|
+
import { FleetContext } from "../fleet-context.js";
|
|
17
|
+
import { repoPath } from "../envelope/json.js";
|
|
18
|
+
import {} from "../repo/entries.js";
|
|
19
|
+
import { buildLiving } from "./living.js";
|
|
20
|
+
import { buildJoins } from "./joins.js";
|
|
21
|
+
import { buildFeatures } from "./features.js";
|
|
22
|
+
/**
|
|
23
|
+
* Assemble the pack. Reads only; writes nothing, and refuses nothing — every
|
|
24
|
+
* miss is a field, and an unreadable DOCUMENT is a flag the caller grades
|
|
25
|
+
* (`packHoles`). What does throw — an unreadable directory, bytes that are
|
|
26
|
+
* not UTF-8 — is the all-or-nothing class explore takes too: the honest
|
|
27
|
+
* answer is a refusal naming the path, not a pack with a silent hole.
|
|
28
|
+
*/
|
|
29
|
+
export async function assemblePack(req) {
|
|
30
|
+
const { docsDir, entry, feature, context } = req;
|
|
31
|
+
// The three sections are independent derivations over one shared read
|
|
32
|
+
// index; identical reads share their in-flight promise, so the fan-out
|
|
33
|
+
// costs no duplicate I/O and no section can see a different file version.
|
|
34
|
+
const [living, joins, features] = await Promise.all([
|
|
35
|
+
buildLiving({ docsDir, entry, context }),
|
|
36
|
+
buildJoins({ docsDir, entry, context }),
|
|
37
|
+
buildFeatures({ docsDir, entry, feature, context }),
|
|
38
|
+
]);
|
|
39
|
+
return {
|
|
40
|
+
service: entry.id,
|
|
41
|
+
path: repoPath(docsDir, entry.dir),
|
|
42
|
+
feature: feature === null ? null : feature.id,
|
|
43
|
+
...living,
|
|
44
|
+
...joins,
|
|
45
|
+
features,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Whether the pack has a silent hole: a document that exists but could not be
|
|
50
|
+
* read, so a section that LOOKS empty is really unanswered. The command maps
|
|
51
|
+
* this to exit 1 with `ok: true` — delta's precedent, same reasoning: the
|
|
52
|
+
* pack is consumed by agents that never ran validate, so the exit code must
|
|
53
|
+
* carry the failure itself. Set before the format fork; the guard is about
|
|
54
|
+
* the pack, not about how it is rendered.
|
|
55
|
+
*/
|
|
56
|
+
export function packHoles(pack) {
|
|
57
|
+
return ((pack.landscape.present && !pack.landscape.parses) ||
|
|
58
|
+
pack.openapi.unreadable ||
|
|
59
|
+
pack.asyncapi.unreadable ||
|
|
60
|
+
// The two fleet vocabularies and the rollup's fleet walk fail the same
|
|
61
|
+
// way the contracts do: an unreadable file EMPTIES a section (`declared:
|
|
62
|
+
// false` on every permission, "(none realized here)") while looking like
|
|
63
|
+
// an answer, so their health is part of the hole contract, not decoration.
|
|
64
|
+
pack.permissionsVocabulary.invalid !== undefined ||
|
|
65
|
+
pack.capabilitiesVocabulary.invalid !== undefined ||
|
|
66
|
+
pack.capabilitiesUnread.length > 0 ||
|
|
67
|
+
// The use-case axis fails the same way, and one step wider than
|
|
68
|
+
// `landscape.parses` above: that flag is about `architecture/landscape.likec4`
|
|
69
|
+
// alone, while a flow lives in `architecture/usecases/*.likec4` and the whole
|
|
70
|
+
// directory is read as ONE LikeC4 project. So a use-case file with an
|
|
71
|
+
// unresolved element leaves `landscape.parses` true and empties every flow
|
|
72
|
+
// in the pack — the exact silent hole this predicate exists to refuse.
|
|
73
|
+
pack.useCaseScan.unreadable ||
|
|
74
|
+
pack.features.some((f) => f.architecture.errors.length > 0 || f.openapi.unreadable || f.events.unreadable));
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=pack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pack.js","sourceRoot":"","sources":["../../../src/core/pack/pack.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAwC,MAAM,oBAAoB,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAoB,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAmB,MAAM,YAAY,CAAC;AACzD,OAAO,EAAE,aAAa,EAAoB,MAAM,eAAe,CAAC;AA0BhE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,GAAgB;IACjD,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC;IACjD,sEAAsE;IACtE,uEAAuE;IACvE,0EAA0E;IAC1E,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAClD,WAAW,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QACxC,UAAU,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QACvC,aAAa,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;KACpD,CAAC,CAAC;IACH,OAAO;QACL,OAAO,EAAE,KAAK,CAAC,EAAE;QACjB,IAAI,EAAE,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC;QAClC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE;QAC7C,GAAG,MAAM;QACT,GAAG,KAAK;QACR,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,IAAiB;IACzC,OAAO,CACL,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;QAClD,IAAI,CAAC,OAAO,CAAC,UAAU;QACvB,IAAI,CAAC,QAAQ,CAAC,UAAU;QACxB,uEAAuE;QACvE,yEAAyE;QACzE,yEAAyE;QACzE,2EAA2E;QAC3E,IAAI,CAAC,qBAAqB,CAAC,OAAO,KAAK,SAAS;QAChD,IAAI,CAAC,sBAAsB,CAAC,OAAO,KAAK,SAAS;QACjD,IAAI,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC;QAClC,gEAAgE;QAChE,+EAA+E;QAC/E,8EAA8E;QAC9E,sEAAsE;QACtE,2EAA2E;QAC3E,uEAAuE;QACvE,IAAI,CAAC,WAAW,CAAC,UAAU;QAC3B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAChB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,UAAU,IAAI,CAAC,CAAC,MAAM,CAAC,UAAU,CACvF,CACF,CAAC;AACJ,CAAC","sourcesContent":["/**\n * One service's context pack: the exact docs slice bound to a service —\n * living requirements verbatim, both contracts, the fleet edges one hop out,\n * the permission and capability joins, provenance, and every active feature's\n * delta over it — assembled as one deterministic payload an agent loads before\n * working in that service's repository.\n *\n * Core rather than the command, exactly as `core/explore/explore.ts` sits\n * behind `loam explore`: a future facade (an MCP tool, a second renderer)\n * reuses the assembly without the printing, and the command layer stays I/O.\n * Deterministic by construction — identical state must yield identical bytes:\n * no timestamps, repo-relative forward-slash paths only, every unioned set\n * sorted with `compareIds`, contract entries in document order (a fact of the\n * file, hence of the state).\n */\nimport { FleetContext } from \"../fleet-context.js\";\nimport { repoPath } from \"../envelope/json.js\";\nimport { type FeatureEntry, type ServiceEntry } from \"../repo/entries.js\";\nimport { buildLiving, type LivingSlice } from \"./living.js\";\nimport { buildJoins, type JoinsSlice } from \"./joins.js\";\nimport { buildFeatures, type PackFeature } from \"./features.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\n\nexport interface PackRequest {\n docsDir: DocsDir;\n /** The service, as the enumeration answered it — the entry, not an id and a dir (rule 17). */\n entry: ServiceEntry;\n /** The one feature `--feature` resolved, or null for every touching feature. */\n feature: FeatureEntry | null;\n context: FleetContext;\n}\n\nexport interface ContextPack extends LivingSlice, JoinsSlice {\n service: string;\n path: string;\n /**\n * The canonical id of the one feature `--feature` narrowed to, or null for\n * the everything-in-flight default. Echoed so a stored pack SAYS it is a\n * narrowed view: two packs of the same service can otherwise differ only by\n * what they silently left out, and an agent diffing them (or resuming from\n * one) has no way to tell a narrowed pack from a fleet gone quiet.\n */\n feature: string | null;\n features: PackFeature[];\n}\n\n/**\n * Assemble the pack. Reads only; writes nothing, and refuses nothing — every\n * miss is a field, and an unreadable DOCUMENT is a flag the caller grades\n * (`packHoles`). What does throw — an unreadable directory, bytes that are\n * not UTF-8 — is the all-or-nothing class explore takes too: the honest\n * answer is a refusal naming the path, not a pack with a silent hole.\n */\nexport async function assemblePack(req: PackRequest): Promise<ContextPack> {\n const { docsDir, entry, feature, context } = req;\n // The three sections are independent derivations over one shared read\n // index; identical reads share their in-flight promise, so the fan-out\n // costs no duplicate I/O and no section can see a different file version.\n const [living, joins, features] = await Promise.all([\n buildLiving({ docsDir, entry, context }),\n buildJoins({ docsDir, entry, context }),\n buildFeatures({ docsDir, entry, feature, context }),\n ]);\n return {\n service: entry.id,\n path: repoPath(docsDir, entry.dir),\n feature: feature === null ? null : feature.id,\n ...living,\n ...joins,\n features,\n };\n}\n\n/**\n * Whether the pack has a silent hole: a document that exists but could not be\n * read, so a section that LOOKS empty is really unanswered. The command maps\n * this to exit 1 with `ok: true` — delta's precedent, same reasoning: the\n * pack is consumed by agents that never ran validate, so the exit code must\n * carry the failure itself. Set before the format fork; the guard is about\n * the pack, not about how it is rendered.\n */\nexport function packHoles(pack: ContextPack): boolean {\n return (\n (pack.landscape.present && !pack.landscape.parses) ||\n pack.openapi.unreadable ||\n pack.asyncapi.unreadable ||\n // The two fleet vocabularies and the rollup's fleet walk fail the same\n // way the contracts do: an unreadable file EMPTIES a section (`declared:\n // false` on every permission, \"(none realized here)\") while looking like\n // an answer, so their health is part of the hole contract, not decoration.\n pack.permissionsVocabulary.invalid !== undefined ||\n pack.capabilitiesVocabulary.invalid !== undefined ||\n pack.capabilitiesUnread.length > 0 ||\n // The use-case axis fails the same way, and one step wider than\n // `landscape.parses` above: that flag is about `architecture/landscape.likec4`\n // alone, while a flow lives in `architecture/usecases/*.likec4` and the whole\n // directory is read as ONE LikeC4 project. So a use-case file with an\n // unresolved element leaves `landscape.parses` true and empties every flow\n // in the pack — the exact silent hole this predicate exists to refuse.\n pack.useCaseScan.unreadable ||\n pack.features.some(\n (f) => f.architecture.errors.length > 0 || f.openapi.unreadable || f.events.unreadable,\n )\n );\n}\n"]}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The fleet's authorization vocabulary: which permissions exist, and on which
|
|
3
|
+
* kind of subject each one is checked.
|
|
4
|
+
*
|
|
5
|
+
* It is a fleet document rather than a service one because permissions cross
|
|
6
|
+
* services in the shape that matters — a permission a profile holds is owned by
|
|
7
|
+
* whatever service owns profiles and enforced by every service that reads it,
|
|
8
|
+
* and a per-service copy would be N copies of one word. `architecture/` is
|
|
9
|
+
* where the fleet's shared documents already live.
|
|
10
|
+
*
|
|
11
|
+
* The unit is a PAIR, `<subject>/<permission>`, and that is the whole reason
|
|
12
|
+
* this file exists instead of a `Requires:` line joined against OpenAPI's
|
|
13
|
+
* `security`. OpenAPI carries permission NAMES only for oauth2 and
|
|
14
|
+
* openIdConnect — for `http bearer` and `apiKey` the spec requires the scope
|
|
15
|
+
* array to be empty — so a fleet on bearer tokens has nowhere in its contract
|
|
16
|
+
* to say what it checks. And `security` answers only for the CALLER, while a
|
|
17
|
+
* permission is as often checked on an entity inside the request.
|
|
18
|
+
*
|
|
19
|
+
* What this is NOT, deliberately: a domain model. Permissions are a flat list
|
|
20
|
+
* of names under a subject kind — no entities, no relations, no resources.
|
|
21
|
+
* Everything past that has no ground truth to check against, which is the same
|
|
22
|
+
* reason the capability axis stops at declared names
|
|
23
|
+
* (core/capabilities/capabilities.ts) and there is still no AUTHORED capability
|
|
24
|
+
* layer (SCHEMA.md) — a vocabulary loam cannot
|
|
25
|
+
* check is a vocabulary that drifts while looking authoritative. A permission
|
|
26
|
+
* that varies by resource is separate names (`channel:send:sms`,
|
|
27
|
+
* `channel:send:email`) or a column in a scenario's Examples table.
|
|
28
|
+
*/
|
|
29
|
+
import { readFile } from "node:fs/promises";
|
|
30
|
+
import { existsSync } from "node:fs";
|
|
31
|
+
import { parse as parseYaml } from "yaml";
|
|
32
|
+
import { isRecord } from "../kernel/records.js";
|
|
33
|
+
const EMPTY = { present: false, subjects: [], byId: new Map() };
|
|
34
|
+
/**
|
|
35
|
+
* Read the vocabulary. A missing file is not a finding — a fleet that gates
|
|
36
|
+
* nothing on permissions owes no vocabulary, and the checks that read this stay
|
|
37
|
+
* silent on an absent one exactly as the OpenAPI axis stays silent for a
|
|
38
|
+
* service the landscape shows nobody calls.
|
|
39
|
+
*/
|
|
40
|
+
export async function readVocabulary(path) {
|
|
41
|
+
if (!existsSync(path))
|
|
42
|
+
return EMPTY;
|
|
43
|
+
let doc;
|
|
44
|
+
try {
|
|
45
|
+
doc = parseYaml(await readFile(path, "utf8"));
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
return { ...EMPTY, present: true, invalid: e instanceof Error ? e.message : String(e) };
|
|
49
|
+
}
|
|
50
|
+
if (doc === null || doc === undefined)
|
|
51
|
+
return { ...EMPTY, present: true };
|
|
52
|
+
if (!isRecord(doc))
|
|
53
|
+
return { ...EMPTY, present: true, invalid: "the document is not a mapping" };
|
|
54
|
+
const subjects = isRecord(doc["subjects"]) ? Object.keys(doc["subjects"]) : [];
|
|
55
|
+
const permsBlock = doc["permissions"];
|
|
56
|
+
if (permsBlock === undefined)
|
|
57
|
+
return { present: true, subjects, byId: new Map() };
|
|
58
|
+
if (!isRecord(permsBlock))
|
|
59
|
+
return { ...EMPTY, present: true, invalid: "`permissions` is not a mapping of subject kind to permissions" };
|
|
60
|
+
const byId = new Map();
|
|
61
|
+
for (const [subject, block] of Object.entries(permsBlock)) {
|
|
62
|
+
// A permission under an undeclared subject is the typo this shape exists to
|
|
63
|
+
// make impossible: `Requires: profiles/channel:send` against a `profile`
|
|
64
|
+
// block resolves nowhere, and without this the vocabulary would simply grow
|
|
65
|
+
// a second subject kind nobody meant to declare.
|
|
66
|
+
if (!subjects.includes(subject)) {
|
|
67
|
+
return { ...EMPTY, present: true, invalid: `'${subject}' holds permissions but is not declared under \`subjects\`` };
|
|
68
|
+
}
|
|
69
|
+
if (!isRecord(block)) {
|
|
70
|
+
return { ...EMPTY, present: true, invalid: `\`permissions.${subject}\` is not a mapping of permission name to its declaration` };
|
|
71
|
+
}
|
|
72
|
+
for (const [name, body] of Object.entries(block)) {
|
|
73
|
+
const decl = isRecord(body) ? body : {};
|
|
74
|
+
const enforced = decl["enforced_by"];
|
|
75
|
+
byId.set(`${subject}/${name}`, {
|
|
76
|
+
subject,
|
|
77
|
+
name,
|
|
78
|
+
id: `${subject}/${name}`,
|
|
79
|
+
...(typeof decl["description"] === "string" ? { description: decl["description"] } : {}),
|
|
80
|
+
...(typeof decl["owned_by"] === "string" ? { ownedBy: decl["owned_by"] } : {}),
|
|
81
|
+
enforcedBy: Array.isArray(enforced) ? enforced.filter((s) => typeof s === "string") : [],
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return { present: true, subjects, byId };
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissions.js","sourceRoot":"","sources":["../../../src/core/permissions/permissions.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The fleet's authorization vocabulary: which permissions exist, and on which\n * kind of subject each one is checked.\n *\n * It is a fleet document rather than a service one because permissions cross\n * services in the shape that matters — a permission a profile holds is owned by\n * whatever service owns profiles and enforced by every service that reads it,\n * and a per-service copy would be N copies of one word. `architecture/` is\n * where the fleet's shared documents already live.\n *\n * The unit is a PAIR, `<subject>/<permission>`, and that is the whole reason\n * this file exists instead of a `Requires:` line joined against OpenAPI's\n * `security`. OpenAPI carries permission NAMES only for oauth2 and\n * openIdConnect — for `http bearer` and `apiKey` the spec requires the scope\n * array to be empty — so a fleet on bearer tokens has nowhere in its contract\n * to say what it checks. And `security` answers only for the CALLER, while a\n * permission is as often checked on an entity inside the request.\n *\n * What this is NOT, deliberately: a domain model. Permissions are a flat list\n * of names under a subject kind — no entities, no relations, no resources.\n * Everything past that has no ground truth to check against, which is the same\n * reason the capability axis stops at declared names\n * (core/capabilities/capabilities.ts) and there is still no AUTHORED capability\n * layer (SCHEMA.md) — a vocabulary loam cannot\n * check is a vocabulary that drifts while looking authoritative. A permission\n * that varies by resource is separate names (`channel:send:sms`,\n * `channel:send:email`) or a column in a scenario's Examples table.\n */\nimport { readFile } from \"node:fs/promises\";\nimport { existsSync } from \"node:fs\";\nimport { parse as parseYaml } from \"yaml\";\nimport { isRecord } from \"../kernel/records.js\";\n\n/** One declared permission, under the subject kind it is checked on. */\nexport interface Permission {\n /** The subject kind — `user`, `profile`, `service`. */\n subject: string;\n /** The permission name as `Requires:` spells it, without the subject. */\n name: string;\n /** `<subject>/<name>` — the token a requirement writes. */\n id: string;\n description?: string;\n /**\n * Where the permission is DEFINED — a service id, or `idp` for a vocabulary\n * some identity provider owns. Never resolved: see `UNCHECKED`. It is here\n * because \"who would change this\" is the first question a reader asks, and a\n * blank is a worse answer than an unverified one.\n */\n ownedBy?: string;\n /** Services that CHECK it. Never resolved, for the same reason. */\n enforcedBy: string[];\n}\n\nexport interface Vocabulary {\n /** False when `architecture/permissions.yaml` does not exist — not an error. */\n present: boolean;\n /** Why the file could not be read as a vocabulary, when it could not. */\n invalid?: string;\n /** Declared subject kinds, in declaration order. */\n subjects: string[];\n /** Declared permissions, keyed by `<subject>/<name>`. */\n byId: Map<string, Permission>;\n}\n\nconst EMPTY: Vocabulary = { present: false, subjects: [], byId: new Map() };\n\n/**\n * Read the vocabulary. A missing file is not a finding — a fleet that gates\n * nothing on permissions owes no vocabulary, and the checks that read this stay\n * silent on an absent one exactly as the OpenAPI axis stays silent for a\n * service the landscape shows nobody calls.\n */\nexport async function readVocabulary(path: string): Promise<Vocabulary> {\n if (!existsSync(path)) return EMPTY;\n let doc: unknown;\n try {\n doc = parseYaml(await readFile(path, \"utf8\"));\n } catch (e) {\n return { ...EMPTY, present: true, invalid: e instanceof Error ? e.message : String(e) };\n }\n if (doc === null || doc === undefined) return { ...EMPTY, present: true };\n if (!isRecord(doc)) return { ...EMPTY, present: true, invalid: \"the document is not a mapping\" };\n\n const subjects = isRecord(doc[\"subjects\"]) ? Object.keys(doc[\"subjects\"]) : [];\n const permsBlock = doc[\"permissions\"];\n if (permsBlock === undefined) return { present: true, subjects, byId: new Map() };\n if (!isRecord(permsBlock)) return { ...EMPTY, present: true, invalid: \"`permissions` is not a mapping of subject kind to permissions\" };\n\n const byId = new Map<string, Permission>();\n for (const [subject, block] of Object.entries(permsBlock)) {\n // A permission under an undeclared subject is the typo this shape exists to\n // make impossible: `Requires: profiles/channel:send` against a `profile`\n // block resolves nowhere, and without this the vocabulary would simply grow\n // a second subject kind nobody meant to declare.\n if (!subjects.includes(subject)) {\n return { ...EMPTY, present: true, invalid: `'${subject}' holds permissions but is not declared under \\`subjects\\`` };\n }\n if (!isRecord(block)) {\n return { ...EMPTY, present: true, invalid: `\\`permissions.${subject}\\` is not a mapping of permission name to its declaration` };\n }\n for (const [name, body] of Object.entries(block)) {\n const decl = isRecord(body) ? body : {};\n const enforced = decl[\"enforced_by\"];\n byId.set(`${subject}/${name}`, {\n subject,\n name,\n id: `${subject}/${name}`,\n ...(typeof decl[\"description\"] === \"string\" ? { description: decl[\"description\"] } : {}),\n ...(typeof decl[\"owned_by\"] === \"string\" ? { ownedBy: decl[\"owned_by\"] } : {}),\n enforcedBy: Array.isArray(enforced) ? enforced.filter((s): s is string => typeof s === \"string\") : [],\n });\n }\n }\n return { present: true, subjects, byId };\n}\n"]}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The OpenAPI half of projecting a feature onto one service: which operations
|
|
3
|
+
* its contract delta defines, as slots rather than names.
|
|
4
|
+
*
|
|
5
|
+
* Moved out of `commands/delta/slices.ts` (rule 8 in docs/DESIGN.md) when
|
|
6
|
+
* `loam context` became the second caller — a command may not import another
|
|
7
|
+
* command, and a second copy of a projection is a second chance for the brief
|
|
8
|
+
* and the pack to disagree about what a feature changes. The answers here are
|
|
9
|
+
* what `loam delta --json` serializes verbatim, so they are computed once and
|
|
10
|
+
* never re-derived while printing — a printed number that disagrees with the
|
|
11
|
+
* payload beside it is the failure this separation prevents.
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync } from "node:fs";
|
|
14
|
+
import { readFile } from "node:fs/promises";
|
|
15
|
+
import { parse as parseYaml } from "yaml";
|
|
16
|
+
import { readOpenapi } from "../openapi/doc.js";
|
|
17
|
+
import { isRecord } from "../kernel/records.js";
|
|
18
|
+
import { compareIds } from "../repo/entries.js";
|
|
19
|
+
/**
|
|
20
|
+
* The feature's OpenAPI delta for one service, as slots rather than names.
|
|
21
|
+
*
|
|
22
|
+
* The operation set comes from core/openapi/doc.ts — the same structure-aware reader
|
|
23
|
+
* every other check uses, so this view cannot see an operation validate does not.
|
|
24
|
+
* `summary` is the one field that reader does not carry, and it is the sentence
|
|
25
|
+
* an implementer most wants, so it is looked up by the path+method the reader
|
|
26
|
+
* already resolved: a second read of the same document, never a second opinion
|
|
27
|
+
* about what an operation IS.
|
|
28
|
+
*/
|
|
29
|
+
export async function apiChanges(openapiPath) {
|
|
30
|
+
if (!existsSync(openapiPath))
|
|
31
|
+
return { changes: [], unreadable: false };
|
|
32
|
+
// `readOpenapi`, not `operations`: the operation list alone cannot tell a
|
|
33
|
+
// contract that defines nothing from one that could not be read, and this is
|
|
34
|
+
// the command whose output IS the implementation task.
|
|
35
|
+
const api = await readOpenapi(openapiPath);
|
|
36
|
+
if (api.unreadable) {
|
|
37
|
+
return { changes: [], unreadable: true, ...(api.error === undefined ? {} : { error: api.error }) };
|
|
38
|
+
}
|
|
39
|
+
const ops = api.ops;
|
|
40
|
+
if (ops.length === 0)
|
|
41
|
+
return { changes: [], unreadable: false };
|
|
42
|
+
let doc;
|
|
43
|
+
try {
|
|
44
|
+
doc = parseYaml(await readFile(openapiPath, "utf8"));
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// Unreadable is impossible here (the reader above said otherwise), but a
|
|
48
|
+
// summary is decoration and must never be the reason a task brief fails to
|
|
49
|
+
// print.
|
|
50
|
+
doc = null;
|
|
51
|
+
}
|
|
52
|
+
// The summary walk below descends four levels into a document nobody has
|
|
53
|
+
// validated, and `isRecord` is what it asks at each step: a cast there would
|
|
54
|
+
// assert a shape the parser never promised, and a sequence or a scalar in any of
|
|
55
|
+
// those slots would be indexed as a mapping.
|
|
56
|
+
const summaryOf = (op) => {
|
|
57
|
+
if (!isRecord(doc))
|
|
58
|
+
return null;
|
|
59
|
+
const paths = doc["paths"];
|
|
60
|
+
if (!isRecord(paths))
|
|
61
|
+
return null;
|
|
62
|
+
const item = paths[op.path];
|
|
63
|
+
if (!isRecord(item))
|
|
64
|
+
return null;
|
|
65
|
+
const entry = item[op.method];
|
|
66
|
+
if (!isRecord(entry))
|
|
67
|
+
return null;
|
|
68
|
+
const summary = entry["summary"];
|
|
69
|
+
return typeof summary === "string" && summary.length > 0 ? summary : null;
|
|
70
|
+
};
|
|
71
|
+
return {
|
|
72
|
+
changes: ops
|
|
73
|
+
.map((op) => ({
|
|
74
|
+
path: op.path,
|
|
75
|
+
method: op.method.toUpperCase(),
|
|
76
|
+
operationId: op.id,
|
|
77
|
+
summary: summaryOf(op),
|
|
78
|
+
remove: op.remove,
|
|
79
|
+
}))
|
|
80
|
+
.sort((a, b) => compareIds(a.path, b.path) || compareIds(a.method, b.method)),
|
|
81
|
+
unreadable: false,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/core/projection/api.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The OpenAPI half of projecting a feature onto one service: which operations\n * its contract delta defines, as slots rather than names.\n *\n * Moved out of `commands/delta/slices.ts` (rule 8 in docs/DESIGN.md) when\n * `loam context` became the second caller — a command may not import another\n * command, and a second copy of a projection is a second chance for the brief\n * and the pack to disagree about what a feature changes. The answers here are\n * what `loam delta --json` serializes verbatim, so they are computed once and\n * never re-derived while printing — a printed number that disagrees with the\n * payload beside it is the failure this separation prevents.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { parse as parseYaml } from \"yaml\";\nimport { readOpenapi, type Operation } from \"../openapi/doc.js\";\nimport { isRecord } from \"../kernel/records.js\";\nimport { compareIds } from \"../repo/entries.js\";\n\n/**\n * One operation the feature's OpenAPI delta defines for this service. The\n * projection is a task brief, and \"implement createSplit\" without the path and\n * the method is not a task — it is a name to go look up in a file the reader\n * was not told about.\n */\nexport interface ApiChange {\n path: string;\n method: string;\n operationId: string;\n summary: string | null;\n /** `x-loam-remove: true` — this operation is being retired, not added. */\n remove: boolean;\n}\n\n/**\n * The contract axis of the brief: the operations, and whether the document they\n * came from could be read at all.\n *\n * The two have to travel together. A feature `openapi.yaml` that does not parse\n * yields zero operations, which is the same answer as a delta that genuinely\n * changes no endpoints — and this projection is a task brief, so \"no contract\n * work here\" over a YAML error is the vacuously-green trap the architecture\n * axis already guards against.\n */\nexport interface ApiSlice {\n changes: ApiChange[];\n unreadable: boolean;\n /** The parser's own message, when there is one to quote back. */\n error?: string;\n}\n\n/**\n * The feature's OpenAPI delta for one service, as slots rather than names.\n *\n * The operation set comes from core/openapi/doc.ts — the same structure-aware reader\n * every other check uses, so this view cannot see an operation validate does not.\n * `summary` is the one field that reader does not carry, and it is the sentence\n * an implementer most wants, so it is looked up by the path+method the reader\n * already resolved: a second read of the same document, never a second opinion\n * about what an operation IS.\n */\nexport async function apiChanges(openapiPath: string): Promise<ApiSlice> {\n if (!existsSync(openapiPath)) return { changes: [], unreadable: false };\n // `readOpenapi`, not `operations`: the operation list alone cannot tell a\n // contract that defines nothing from one that could not be read, and this is\n // the command whose output IS the implementation task.\n const api = await readOpenapi(openapiPath);\n if (api.unreadable) {\n return { changes: [], unreadable: true, ...(api.error === undefined ? {} : { error: api.error }) };\n }\n const ops = api.ops;\n if (ops.length === 0) return { changes: [], unreadable: false };\n let doc: unknown;\n try {\n doc = parseYaml(await readFile(openapiPath, \"utf8\"));\n } catch {\n // Unreadable is impossible here (the reader above said otherwise), but a\n // summary is decoration and must never be the reason a task brief fails to\n // print.\n doc = null;\n }\n // The summary walk below descends four levels into a document nobody has\n // validated, and `isRecord` is what it asks at each step: a cast there would\n // assert a shape the parser never promised, and a sequence or a scalar in any of\n // those slots would be indexed as a mapping.\n const summaryOf = (op: Operation): string | null => {\n if (!isRecord(doc)) return null;\n const paths = doc[\"paths\"];\n if (!isRecord(paths)) return null;\n const item = paths[op.path];\n if (!isRecord(item)) return null;\n const entry = item[op.method];\n if (!isRecord(entry)) return null;\n const summary = entry[\"summary\"];\n return typeof summary === \"string\" && summary.length > 0 ? summary : null;\n };\n return {\n changes: ops\n .map((op): ApiChange => ({\n path: op.path,\n method: op.method.toUpperCase(),\n operationId: op.id,\n summary: summaryOf(op),\n remove: op.remove,\n }))\n .sort((a, b) => compareIds(a.path, b.path) || compareIds(a.method, b.method)),\n unreadable: false,\n };\n}\n"]}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The C4 half of projecting a feature onto one service: which services exist,
|
|
3
|
+
* which the feature introduces, and what its tagged edges add around the one
|
|
4
|
+
* being projected onto. Moved out of `commands/delta/slices.ts` beside
|
|
5
|
+
* `./api.ts` and `./events.ts`; named `arch-slice.ts` rather than `arch.ts`
|
|
6
|
+
* because `core/c4/arch.ts` already exists and a twin name invites the wrong
|
|
7
|
+
* import.
|
|
8
|
+
*/
|
|
9
|
+
import {} from "../c4/likec4.js";
|
|
10
|
+
import { elementService, serviceResolver } from "../c4/resolve/service.js";
|
|
11
|
+
import { DocsRepoUnavailableError } from "../repo/state.js";
|
|
12
|
+
import { listServices } from "../repo/repo.js";
|
|
13
|
+
/** Every service in the docs repo, or none when there is no docs repo to ask. */
|
|
14
|
+
export async function livingServices(docsDir) {
|
|
15
|
+
try {
|
|
16
|
+
return (await listServices(docsDir)).map((s) => s.id);
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
// "There is no docs repo at all" is a different diagnosis with its own
|
|
20
|
+
// command (`loam doctor`); turning it into "unknown service" here would
|
|
21
|
+
// send the reader after a typo that is not there.
|
|
22
|
+
if (!(err instanceof DocsRepoUnavailableError))
|
|
23
|
+
throw err;
|
|
24
|
+
return [];
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/** Services the feature's C4 delta introduces — its own tagged top-level elements. */
|
|
28
|
+
export function introducedServices(doc, featureId) {
|
|
29
|
+
if (doc === null || doc.errors.length > 0)
|
|
30
|
+
return [];
|
|
31
|
+
return doc.elements.filter((e) => e.tags.includes(featureId)).map(elementService);
|
|
32
|
+
}
|
|
33
|
+
/** The feature's tagged edges around one service, plus whether the service is new. */
|
|
34
|
+
export function archSlice(doc, service, featureId, known) {
|
|
35
|
+
const empty = { isNew: false, inbound: [], outbound: [], errors: [] };
|
|
36
|
+
if (doc === null)
|
|
37
|
+
return empty;
|
|
38
|
+
const { errors, elements, relationships } = doc;
|
|
39
|
+
if (errors.length > 0) {
|
|
40
|
+
return { ...empty, errors: errors.map((e) => (typeof e.line === "number" ? `L${e.line}: ${e.message}` : e.message)) };
|
|
41
|
+
}
|
|
42
|
+
// Which service an element stands for is the binding's call, not the title's
|
|
43
|
+
// — and the enumerated fleet rides in so the slice agrees with `validate`
|
|
44
|
+
// about an edge drawn into a modelled container. Without it, this projection
|
|
45
|
+
// told the provider "no inbound calls" and the consumer "you call 'api'" for
|
|
46
|
+
// the same `checkoutWeb -> paymentService.api` edge the validator was
|
|
47
|
+
// grading against payment-service — and the brief an agent implements from
|
|
48
|
+
// must never disagree with the gate it will be checked by.
|
|
49
|
+
const svcOf = serviceResolver(elements, known);
|
|
50
|
+
const edge = (r, other) => ({
|
|
51
|
+
service: other,
|
|
52
|
+
op: r.op ?? null,
|
|
53
|
+
title: r.title ?? null,
|
|
54
|
+
});
|
|
55
|
+
const featRels = relationships.filter((r) => r.tags.includes(featureId));
|
|
56
|
+
return {
|
|
57
|
+
isNew: elements.some((e) => elementService(e) === service && e.tags.includes(featureId)),
|
|
58
|
+
inbound: featRels.filter((r) => svcOf(r.target) === service).map((r) => edge(r, svcOf(r.source))),
|
|
59
|
+
outbound: featRels.filter((r) => svcOf(r.source) === service).map((r) => edge(r, svcOf(r.target))),
|
|
60
|
+
errors: [],
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=arch-slice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"arch-slice.js","sourceRoot":"","sources":["../../../src/core/projection/arch-slice.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The C4 half of projecting a feature onto one service: which services exist,\n * which the feature introduces, and what its tagged edges add around the one\n * being projected onto. Moved out of `commands/delta/slices.ts` beside\n * `./api.ts` and `./events.ts`; named `arch-slice.ts` rather than `arch.ts`\n * because `core/c4/arch.ts` already exists and a twin name invites the wrong\n * import.\n */\nimport { type Elem, type LoadedDoc, type Rel } from \"../c4/likec4.js\";\nimport { elementService, serviceResolver } from \"../c4/resolve/service.js\";\nimport { DocsRepoUnavailableError } from \"../repo/state.js\";\nimport { listServices } from \"../repo/repo.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\n\n/** One end of a feature edge, as seen from the projected service. */\nexport interface Edge {\n service: string;\n op: string | null;\n title: string | null;\n}\n\nexport interface ArchSlice {\n isNew: boolean;\n inbound: Edge[];\n outbound: Edge[];\n errors: string[];\n}\n\n/** Every service in the docs repo, or none when there is no docs repo to ask. */\nexport async function livingServices(docsDir: DocsDir): Promise<string[]> {\n try {\n return (await listServices(docsDir)).map((s) => s.id);\n } catch (err) {\n // \"There is no docs repo at all\" is a different diagnosis with its own\n // command (`loam doctor`); turning it into \"unknown service\" here would\n // send the reader after a typo that is not there.\n if (!(err instanceof DocsRepoUnavailableError)) throw err;\n return [];\n }\n}\n\n/** Services the feature's C4 delta introduces — its own tagged top-level elements. */\nexport function introducedServices(doc: LoadedDoc | null, featureId: string): string[] {\n if (doc === null || doc.errors.length > 0) return [];\n return doc.elements.filter((e: Elem) => e.tags.includes(featureId)).map(elementService);\n}\n\n/** The feature's tagged edges around one service, plus whether the service is new. */\nexport function archSlice(\n doc: LoadedDoc | null,\n service: string,\n featureId: string,\n known?: ReadonlySet<string>,\n): ArchSlice {\n const empty: ArchSlice = { isNew: false, inbound: [], outbound: [], errors: [] };\n if (doc === null) return empty;\n\n const { errors, elements, relationships } = doc;\n if (errors.length > 0) {\n return { ...empty, errors: errors.map((e) => (typeof e.line === \"number\" ? `L${e.line}: ${e.message}` : e.message)) };\n }\n\n // Which service an element stands for is the binding's call, not the title's\n // — and the enumerated fleet rides in so the slice agrees with `validate`\n // about an edge drawn into a modelled container. Without it, this projection\n // told the provider \"no inbound calls\" and the consumer \"you call 'api'\" for\n // the same `checkoutWeb -> paymentService.api` edge the validator was\n // grading against payment-service — and the brief an agent implements from\n // must never disagree with the gate it will be checked by.\n const svcOf = serviceResolver(elements, known);\n const edge = (r: Rel, other: string): Edge => ({\n service: other,\n op: r.op ?? null,\n title: r.title ?? null,\n });\n const featRels = relationships.filter((r) => r.tags.includes(featureId));\n\n return {\n isNew: elements.some((e) => elementService(e) === service && e.tags.includes(featureId)),\n inbound: featRels.filter((r) => svcOf(r.target) === service).map((r) => edge(r, svcOf(r.source))),\n outbound: featRels.filter((r) => svcOf(r.source) === service).map((r) => edge(r, svcOf(r.target))),\n errors: [],\n };\n}\n"]}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The AsyncAPI half of projecting a feature onto one service — the event-axis
|
|
3
|
+
* mirror of `./api.ts`, moved out of `commands/delta/slices.ts` with it for
|
|
4
|
+
* the same second-caller reason.
|
|
5
|
+
*/
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
import { readAsyncapi } from "../asyncapi/read.js";
|
|
8
|
+
/**
|
|
9
|
+
* The feature's AsyncAPI delta for one service, as slots rather than names —
|
|
10
|
+
* the event-axis mirror of `apiChanges`, read through `core/asyncapi/read.ts`
|
|
11
|
+
* so this view cannot see a message validate does not. Like the API slice, it
|
|
12
|
+
* lists the WHOLE document, restated living slots included: the delta is a
|
|
13
|
+
* complete document, and which slots are new is `loam validate`'s question.
|
|
14
|
+
*/
|
|
15
|
+
export async function eventChanges(asyncapiPath) {
|
|
16
|
+
if (!existsSync(asyncapiPath))
|
|
17
|
+
return { changes: [], unreadable: false };
|
|
18
|
+
const doc = await readAsyncapi(asyncapiPath);
|
|
19
|
+
if (doc.unreadable) {
|
|
20
|
+
return { changes: [], unreadable: true, ...(doc.error === undefined ? {} : { error: doc.error }) };
|
|
21
|
+
}
|
|
22
|
+
const sent = new Set(doc.sent);
|
|
23
|
+
const received = new Set(doc.received);
|
|
24
|
+
return {
|
|
25
|
+
changes: doc.messages.map((m) => ({
|
|
26
|
+
slot: m.slot,
|
|
27
|
+
message: m.name,
|
|
28
|
+
direction: sent.has(m.name) ? "send" : received.has(m.name) ? "receive" : null,
|
|
29
|
+
remove: m.remove === true,
|
|
30
|
+
})),
|
|
31
|
+
unreadable: false,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/core/projection/events.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AA+BnD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,YAAoB;IACrD,IAAI,CAAC,UAAU,CAAC,YAAY,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;IACzE,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,YAAY,CAAC,CAAC;IAC7C,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;QACnB,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC;IACrG,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACvC,OAAO;QACL,OAAO,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAChC,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,OAAO,EAAE,CAAC,CAAC,IAAI;YACf,SAAS,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI;YAC9E,MAAM,EAAE,CAAC,CAAC,MAAM,KAAK,IAAI;SAC1B,CAAC,CAAC;QACH,UAAU,EAAE,KAAK;KAClB,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The AsyncAPI half of projecting a feature onto one service — the event-axis\n * mirror of `./api.ts`, moved out of `commands/delta/slices.ts` with it for\n * the same second-caller reason.\n */\nimport { existsSync } from \"node:fs\";\nimport { readAsyncapi } from \"../asyncapi/read.js\";\n\n/**\n * One message declaration the feature's AsyncAPI delta carries for this\n * service. `slot` is where it is declared — `components.messages.<key>`, or an\n * inline `channels.<ck>.messages.<mk>` — the same spelling the validate\n * findings use; `message` is the join token an edge's `metadata { publishes }`\n * and a requirement's `Publishes:` line name.\n */\nexport interface EventChange {\n slot: string;\n message: string;\n /**\n * What the document's own operations do with the message: `send`, `receive`,\n * or null when no operation reaches it (declared but not wired — and always\n * null for a removal, whose marker joins nothing). A name both sent and\n * received reports `send`: the producer's side owns the contract.\n */\n direction: \"send\" | \"receive\" | null;\n /** `x-loam-remove: true` — this declaration retires the slot, not adds it. */\n remove: boolean;\n}\n\n/** The event axis of the brief. Same discipline as ApiSlice: the changes and the document's readability travel together. */\nexport interface EventSlice {\n changes: EventChange[];\n unreadable: boolean;\n /** The parser's own message, when there is one to quote back. */\n error?: string;\n}\n\n/**\n * The feature's AsyncAPI delta for one service, as slots rather than names —\n * the event-axis mirror of `apiChanges`, read through `core/asyncapi/read.ts`\n * so this view cannot see a message validate does not. Like the API slice, it\n * lists the WHOLE document, restated living slots included: the delta is a\n * complete document, and which slots are new is `loam validate`'s question.\n */\nexport async function eventChanges(asyncapiPath: string): Promise<EventSlice> {\n if (!existsSync(asyncapiPath)) return { changes: [], unreadable: false };\n const doc = await readAsyncapi(asyncapiPath);\n if (doc.unreadable) {\n return { changes: [], unreadable: true, ...(doc.error === undefined ? {} : { error: doc.error }) };\n }\n const sent = new Set(doc.sent);\n const received = new Set(doc.received);\n return {\n changes: doc.messages.map((m) => ({\n slot: m.slot,\n message: m.name,\n direction: sent.has(m.name) ? \"send\" : received.has(m.name) ? \"receive\" : null,\n remove: m.remove === true,\n })),\n unreadable: false,\n };\n}\n"]}
|