@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,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `dynamic view`s a document DECLARES, read off LikeC4's parsed model.
|
|
3
|
+
*
|
|
4
|
+
* This is the only module in loam permitted to touch `$data`, and
|
|
5
|
+
* `scripts/arch-check.mjs` enforces that rather than trusting it (docs/DESIGN.md
|
|
6
|
+
* rule 26). The confinement is the point: `$data` is public and typed but thinly
|
|
7
|
+
* documented for this use, so an upstream shape change has a blast radius of one
|
|
8
|
+
* file, and `test/likec4-view-shape.test.ts` is the tripwire that fires before
|
|
9
|
+
* the change reaches a check.
|
|
10
|
+
*
|
|
11
|
+
* It takes the WHOLE model as `unknown` rather than a `$data` slice handed in by
|
|
12
|
+
* its caller, and that is not squeamishness — naming `$data` in `../likec4.ts`
|
|
13
|
+
* would violate the containment scan this module exists behind. Callers pass the
|
|
14
|
+
* model; every assumption about LikeC4's record shape lives here.
|
|
15
|
+
*
|
|
16
|
+
* Everything is defensive, in the same posture as `./specification.ts`: a shape
|
|
17
|
+
* this reader cannot make sense of degrades to ZERO views, never to a wrong one
|
|
18
|
+
* and never to a throw inside a validate run. That asymmetry is deliberate and
|
|
19
|
+
* is loam's standing rule for a suspended axis — a check with no views to grade
|
|
20
|
+
* reports could-not-look, while a check fed a half-read view would report
|
|
21
|
+
* nothing-wrong about a flow it never saw.
|
|
22
|
+
*/
|
|
23
|
+
import { descText } from "./values.js";
|
|
24
|
+
/** A record, or nothing — `v` is `unknown` off an untyped parse. */
|
|
25
|
+
function record(v) {
|
|
26
|
+
return v && typeof v === "object" && !Array.isArray(v) ? v : undefined;
|
|
27
|
+
}
|
|
28
|
+
/** The value at `key`, when it is a non-empty string. */
|
|
29
|
+
function str(rec, key) {
|
|
30
|
+
const v = rec[key];
|
|
31
|
+
return typeof v === "string" && v.length > 0 ? v : undefined;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Every leaf step under `entries`, depth-first in author order.
|
|
35
|
+
*
|
|
36
|
+
* Steps NEST: a `loop 'until accepted' { ... }` arrives as an entry with
|
|
37
|
+
* `_type: "loop"`, a title, its own `steps[]`, and NO endpoints and NO `astPath`
|
|
38
|
+
* of its own (measured). A walk that treated every entry as a hop would read the
|
|
39
|
+
* bracket as a step and then fail to find a relationship backing it — inventing
|
|
40
|
+
* a finding out of a grouping the author drew for legibility.
|
|
41
|
+
*
|
|
42
|
+
* The test is structural rather than a list of group keywords (`loop`, `par`,
|
|
43
|
+
* ...): an entry with a nested `steps` array is a group whatever LikeC4 calls
|
|
44
|
+
* it, and an entry with two string endpoints is a hop. A future group kind
|
|
45
|
+
* therefore flattens correctly on the day it ships instead of on the day
|
|
46
|
+
* somebody notices.
|
|
47
|
+
*/
|
|
48
|
+
function leaves(entries, out) {
|
|
49
|
+
if (!Array.isArray(entries))
|
|
50
|
+
return;
|
|
51
|
+
for (const entry of entries) {
|
|
52
|
+
const rec = record(entry);
|
|
53
|
+
if (!rec)
|
|
54
|
+
continue;
|
|
55
|
+
if (Array.isArray(rec["steps"])) {
|
|
56
|
+
leaves(rec["steps"], out);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (typeof rec["source"] === "string" && typeof rec["target"] === "string")
|
|
60
|
+
out.push(rec);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/** One leaf entry as a `ParsedStep`. Every leaf yields one; nothing is dropped. */
|
|
64
|
+
function step(rec, ordinal) {
|
|
65
|
+
const astPath = str(rec, "astPath");
|
|
66
|
+
const title = str(rec, "title");
|
|
67
|
+
const notes = descText(rec["notes"]);
|
|
68
|
+
return {
|
|
69
|
+
ordinal,
|
|
70
|
+
source: rec["source"],
|
|
71
|
+
target: rec["target"],
|
|
72
|
+
...(title === undefined ? {} : { title }),
|
|
73
|
+
...(notes === undefined ? {} : { notes }),
|
|
74
|
+
// Present-and-true is the only truthy form LikeC4 emits; absent means
|
|
75
|
+
// forward. Read as a boolean rather than carried as `true | undefined` so a
|
|
76
|
+
// caller cannot accidentally test `=== false` against a key that is never
|
|
77
|
+
// written.
|
|
78
|
+
isBackward: rec["isBackward"] === true,
|
|
79
|
+
...(astPath === undefined ? {} : { astPath }),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The dynamic views one parsed document declares, in the record's own order.
|
|
84
|
+
*
|
|
85
|
+
* `model` is the awaited `parsedModel()` result. The `await` matters and is the
|
|
86
|
+
* mistake every draft of this made: `$data` is `undefined` on the unresolved
|
|
87
|
+
* promise, so a reader handed the promise reports a document with views as
|
|
88
|
+
* having none — a silent zero, which is the one wrong answer this module is
|
|
89
|
+
* written to avoid.
|
|
90
|
+
*
|
|
91
|
+
* Two entries are dropped on the way out, for different reasons:
|
|
92
|
+
*
|
|
93
|
+
* - Anything whose `_type` is not `"dynamic"`. LikeC4 synthesises an `index`
|
|
94
|
+
* view into EVERY document, including one with no `views` block at all
|
|
95
|
+
* (measured), so reporting element views would be reporting a fiction the
|
|
96
|
+
* author never wrote. A census that must see authored element views wants the
|
|
97
|
+
* other filter rule 26 states — `sourcePath !== undefined` — and must not
|
|
98
|
+
* reuse this function to get it.
|
|
99
|
+
* - Anything with no `id`. There is nothing to name in a finding, and a view
|
|
100
|
+
* loam cannot name is a view it cannot ask anybody to fix.
|
|
101
|
+
*/
|
|
102
|
+
export function readDynamicViews(model) {
|
|
103
|
+
const data = record(record(model)?.["$data"]);
|
|
104
|
+
const views = record(data?.["views"]);
|
|
105
|
+
if (!views)
|
|
106
|
+
return [];
|
|
107
|
+
const out = [];
|
|
108
|
+
for (const raw of Object.values(views)) {
|
|
109
|
+
const rec = record(raw);
|
|
110
|
+
if (!rec || rec["_type"] !== "dynamic")
|
|
111
|
+
continue;
|
|
112
|
+
const id = str(rec, "id");
|
|
113
|
+
if (id === undefined)
|
|
114
|
+
continue;
|
|
115
|
+
const found = [];
|
|
116
|
+
leaves(rec["steps"], found);
|
|
117
|
+
const steps = found.map((leaf, i) => step(leaf, i + 1));
|
|
118
|
+
const title = str(rec, "title");
|
|
119
|
+
const description = descText(rec["description"]);
|
|
120
|
+
const sourcePath = str(rec, "sourcePath");
|
|
121
|
+
out.push({
|
|
122
|
+
id,
|
|
123
|
+
...(sourcePath === undefined ? {} : { sourcePath }),
|
|
124
|
+
tags: Array.isArray(rec["tags"]) ? rec["tags"].filter((t) => typeof t === "string") : [],
|
|
125
|
+
...(title === undefined ? {} : { title }),
|
|
126
|
+
...(description === undefined ? {} : { description }),
|
|
127
|
+
steps,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=dynamic-views.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dynamic-views.js","sourceRoot":"","sources":["../../../../src/core/c4/parsed/dynamic-views.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAsFvC,oEAAoE;AACpE,SAAS,MAAM,CAAC,CAAU;IACxB,OAAO,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAA6B,CAAC,CAAC,CAAC,SAAS,CAAC;AACtG,CAAC;AAED,yDAAyD;AACzD,SAAS,GAAG,CAAC,GAA4B,EAAE,GAAW;IACpD,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/D,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAS,MAAM,CAAC,OAAgB,EAAE,GAA8B;IAC9D,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO;IACpC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1B,IAAI,CAAC,GAAG;YAAE,SAAS;QACnB,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;YAChC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,CAAC;YAC1B,SAAS;QACX,CAAC;QACD,IAAI,OAAO,GAAG,CAAC,QAAQ,CAAC,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,QAAQ,CAAC,KAAK,QAAQ;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5F,CAAC;AACH,CAAC;AAED,mFAAmF;AACnF,SAAS,IAAI,CAAC,GAA4B,EAAE,OAAe;IACzD,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACpC,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;IACrC,OAAO;QACL,OAAO;QACP,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAW;QAC/B,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAW;QAC/B,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;QACzC,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;QACzC,sEAAsE;QACtE,4EAA4E;QAC5E,0EAA0E;QAC1E,WAAW;QACX,UAAU,EAAE,GAAG,CAAC,YAAY,CAAC,KAAK,IAAI;QACtC,GAAG,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC;KAC9C,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,gBAAgB,CAAC,KAAc;IAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9C,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IACtC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IAEtB,MAAM,GAAG,GAAiB,EAAE,CAAC;IAC7B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACxB,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,SAAS;YAAE,SAAS;QACjD,MAAM,EAAE,GAAG,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAC1B,IAAI,EAAE,KAAK,SAAS;YAAE,SAAS;QAE/B,MAAM,KAAK,GAA8B,EAAE,CAAC;QAC5C,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC;QAC5B,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QAExD,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAChC,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC;QACjD,MAAM,UAAU,GAAG,GAAG,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QAC1C,GAAG,CAAC,IAAI,CAAC;YACP,EAAE;YACF,GAAG,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC;YACnD,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE;YACrG,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC;YACzC,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC;YACrD,KAAK;SACN,CAAC,CAAC;IACL,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["/**\n * The `dynamic view`s a document DECLARES, read off LikeC4's parsed model.\n *\n * This is the only module in loam permitted to touch `$data`, and\n * `scripts/arch-check.mjs` enforces that rather than trusting it (docs/DESIGN.md\n * rule 26). The confinement is the point: `$data` is public and typed but thinly\n * documented for this use, so an upstream shape change has a blast radius of one\n * file, and `test/likec4-view-shape.test.ts` is the tripwire that fires before\n * the change reaches a check.\n *\n * It takes the WHOLE model as `unknown` rather than a `$data` slice handed in by\n * its caller, and that is not squeamishness — naming `$data` in `../likec4.ts`\n * would violate the containment scan this module exists behind. Callers pass the\n * model; every assumption about LikeC4's record shape lives here.\n *\n * Everything is defensive, in the same posture as `./specification.ts`: a shape\n * this reader cannot make sense of degrades to ZERO views, never to a wrong one\n * and never to a throw inside a validate run. That asymmetry is deliberate and\n * is loam's standing rule for a suspended axis — a check with no views to grade\n * reports could-not-look, while a check fed a half-read view would report\n * nothing-wrong about a flow it never saw.\n */\nimport { descText } from \"./values.js\";\n\n/** One hop of a declared use case: an ordered edge between two elements. */\nexport interface ParsedStep {\n /**\n * 1-based pre-order position among the view's LEAF steps — what lets a finding\n * say \"step 4 of Checkout\". Group wrappers do not consume an ordinal: a\n * `loop` is a bracket around hops, not a hop, and counting it would shift\n * every number after it away from what the author sees on the diagram.\n */\n ordinal: number;\n /**\n * The step's endpoints, ALREADY ORIENTED — see `isBackward`. Dotted FQN\n * strings naming elements, never relationship ids: a step says who talks to\n * whom, and which relationship backs that is a join loam performs later.\n */\n source: string;\n target: string;\n /** The step's label, absent when the author wrote none. */\n title?: string;\n /** A `notes '...'` block on the step, decoded from LikeC4's rich-text shape. */\n notes?: string;\n /**\n * True when the author wrote the hop as a reply — `a <- b` rather than\n * `b -> a`. LOAD-BEARING, and measured: LikeC4 records `a <- b 'reply'` as\n * `{source: b, target: a, isBackward: true}` — already reversed AND flagged —\n * while a forward step carries no such key at all. `source`/`target` above are\n * therefore correct as they stand and need no flipping; the flag is carried so\n * a check can tell a return hop from a call, and so a message naming the\n * failing step can suggest the `<-` spelling to an author who wrote the arrow\n * the long way round.\n */\n isBackward: boolean;\n /**\n * LikeC4's own path to the step inside the view (`/steps@1/steps@0`), carried\n * verbatim. It is the only stable handle on a nested step — two hops between\n * the same pair inside different `loop` blocks are otherwise indistinguishable\n * — and it is message text, never identity: nothing joins on it.\n *\n * OPTIONAL, and that is a deliberate refusal to make it load-bearing. Every\n * leaf carries one at the 1.59.2 pin, so requiring it would look free — and\n * would mean that an upstream release which stopped emitting it turned every\n * use case in the fleet into a view with zero steps. That is the silent wrong\n * answer this module exists to avoid: a hop loam cannot cite is still a hop it\n * must grade.\n */\n astPath?: string;\n}\n\n/** One declared `dynamic view`, flattened to what rule 26 permits reading. */\nexport interface ParsedView {\n id: string;\n /**\n * The name LikeC4 knows the document by, and it is only a PATH under\n * `loadProject`: there it is relative to the project root, so\n * `usecases/checkout.likec4` inside `architecture/`. Under the per-file\n * loaders it is whatever that loader called the document — `source.c4` for\n * `loadSource`, the basename for `loadBatch` — because there is no project\n * for it to be relative to.\n *\n * So: name a file with it only when the views came from `loadProject`. That\n * is the only reader that has one, which is also the only reader that needs\n * one — a use case lives in a file of its own now, and a finding that cannot\n * name that file sends its reader to the landscape to look for something\n * that is not there.\n *\n * Absent for anything LikeC4 synthesized rather than read off a file, which\n * is how the census reader tells the two apart.\n */\n sourcePath?: string;\n /**\n * The view's declared tags, `[]` when it declares none. Normalized here\n * because LikeC4 reads an untagged view's tags as `null`, and a caller\n * testing `.length` on that would throw inside a validate run.\n *\n * Tags live on the VIEW and nowhere else: a step cannot carry tags, and\n * `metadata` on a step is a hard parse error. That is measured, and it is why\n * a use case is opted in as a whole rather than hop by hop.\n */\n tags: string[];\n title?: string;\n description?: string;\n /** The declared hops, in author order, groups flattened away. */\n steps: ParsedStep[];\n}\n\n/** A record, or nothing — `v` is `unknown` off an untyped parse. */\nfunction record(v: unknown): Record<string, unknown> | undefined {\n return v && typeof v === \"object\" && !Array.isArray(v) ? (v as Record<string, unknown>) : undefined;\n}\n\n/** The value at `key`, when it is a non-empty string. */\nfunction str(rec: Record<string, unknown>, key: string): string | undefined {\n const v = rec[key];\n return typeof v === \"string\" && v.length > 0 ? v : undefined;\n}\n\n/**\n * Every leaf step under `entries`, depth-first in author order.\n *\n * Steps NEST: a `loop 'until accepted' { ... }` arrives as an entry with\n * `_type: \"loop\"`, a title, its own `steps[]`, and NO endpoints and NO `astPath`\n * of its own (measured). A walk that treated every entry as a hop would read the\n * bracket as a step and then fail to find a relationship backing it — inventing\n * a finding out of a grouping the author drew for legibility.\n *\n * The test is structural rather than a list of group keywords (`loop`, `par`,\n * ...): an entry with a nested `steps` array is a group whatever LikeC4 calls\n * it, and an entry with two string endpoints is a hop. A future group kind\n * therefore flattens correctly on the day it ships instead of on the day\n * somebody notices.\n */\nfunction leaves(entries: unknown, out: Record<string, unknown>[]): void {\n if (!Array.isArray(entries)) return;\n for (const entry of entries) {\n const rec = record(entry);\n if (!rec) continue;\n if (Array.isArray(rec[\"steps\"])) {\n leaves(rec[\"steps\"], out);\n continue;\n }\n if (typeof rec[\"source\"] === \"string\" && typeof rec[\"target\"] === \"string\") out.push(rec);\n }\n}\n\n/** One leaf entry as a `ParsedStep`. Every leaf yields one; nothing is dropped. */\nfunction step(rec: Record<string, unknown>, ordinal: number): ParsedStep {\n const astPath = str(rec, \"astPath\");\n const title = str(rec, \"title\");\n const notes = descText(rec[\"notes\"]);\n return {\n ordinal,\n source: rec[\"source\"] as string,\n target: rec[\"target\"] as string,\n ...(title === undefined ? {} : { title }),\n ...(notes === undefined ? {} : { notes }),\n // Present-and-true is the only truthy form LikeC4 emits; absent means\n // forward. Read as a boolean rather than carried as `true | undefined` so a\n // caller cannot accidentally test `=== false` against a key that is never\n // written.\n isBackward: rec[\"isBackward\"] === true,\n ...(astPath === undefined ? {} : { astPath }),\n };\n}\n\n/**\n * The dynamic views one parsed document declares, in the record's own order.\n *\n * `model` is the awaited `parsedModel()` result. The `await` matters and is the\n * mistake every draft of this made: `$data` is `undefined` on the unresolved\n * promise, so a reader handed the promise reports a document with views as\n * having none — a silent zero, which is the one wrong answer this module is\n * written to avoid.\n *\n * Two entries are dropped on the way out, for different reasons:\n *\n * - Anything whose `_type` is not `\"dynamic\"`. LikeC4 synthesises an `index`\n * view into EVERY document, including one with no `views` block at all\n * (measured), so reporting element views would be reporting a fiction the\n * author never wrote. A census that must see authored element views wants the\n * other filter rule 26 states — `sourcePath !== undefined` — and must not\n * reuse this function to get it.\n * - Anything with no `id`. There is nothing to name in a finding, and a view\n * loam cannot name is a view it cannot ask anybody to fix.\n */\nexport function readDynamicViews(model: unknown): ParsedView[] {\n const data = record(record(model)?.[\"$data\"]);\n const views = record(data?.[\"views\"]);\n if (!views) return [];\n\n const out: ParsedView[] = [];\n for (const raw of Object.values(views)) {\n const rec = record(raw);\n if (!rec || rec[\"_type\"] !== \"dynamic\") continue;\n const id = str(rec, \"id\");\n if (id === undefined) continue;\n\n const found: Record<string, unknown>[] = [];\n leaves(rec[\"steps\"], found);\n const steps = found.map((leaf, i) => step(leaf, i + 1));\n\n const title = str(rec, \"title\");\n const description = descText(rec[\"description\"]);\n const sourcePath = str(rec, \"sourcePath\");\n out.push({\n id,\n ...(sourcePath === undefined ? {} : { sourcePath }),\n tags: Array.isArray(rec[\"tags\"]) ? rec[\"tags\"].filter((t): t is string => typeof t === \"string\") : [],\n ...(title === undefined ? {} : { title }),\n ...(description === undefined ? {} : { description }),\n steps,\n });\n }\n return out;\n}\n"]}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `specification { ... }` block, read off LikeC4's parsed model.
|
|
3
|
+
*
|
|
4
|
+
* loam reads a model for what it MEANS, and until LikeC4 1.59.0 the
|
|
5
|
+
* specification carried nothing loam had to mean anything by: it declared which
|
|
6
|
+
* kinds and tags exist, and LikeC4 itself enforced that every use was declared.
|
|
7
|
+
* 1.59.0 added **tags on kinds** — `specification { element softwareSystem {
|
|
8
|
+
* #external } }` — and LikeC4 applies those tags to every element of the kind
|
|
9
|
+
* before loam ever sees it. So `Elem.tags` stopped answering the question loam
|
|
10
|
+
* was actually asking of it.
|
|
11
|
+
*
|
|
12
|
+
* That distinction is what this module exists for. loam does not need the
|
|
13
|
+
* specification to SEE an inherited tag — the tag is already on the element, and
|
|
14
|
+
* `flattenModel` has always copied it faithfully. It needs the specification to
|
|
15
|
+
* tell an inherited tag from one somebody wrote on the element, because loam
|
|
16
|
+
* gives two tags grading meaning (`#external` exempts an element from the
|
|
17
|
+
* landscape↔services reconciliation, `#platform` silences a hub warning) and a
|
|
18
|
+
* kind-wide declaration of either switches that grading off for every element of
|
|
19
|
+
* the kind at once. Six words in the specification block turned a fleet gate
|
|
20
|
+
* green over a fleet it had stopped checking; `kindTagFindings`
|
|
21
|
+
* (commands/validate/fleet/kind-tags.ts) is the check that refuses that, and this
|
|
22
|
+
* is the reader it is built on.
|
|
23
|
+
*
|
|
24
|
+
* Everything here is defensive. The specification is not part of the model API
|
|
25
|
+
* loam's `ReadableModel` slice pins, and 1.59.2 already spells the two kind
|
|
26
|
+
* tables differently — element kinds carry `tags` at the top of the kind record,
|
|
27
|
+
* relationship kinds carry theirs under `style` — which is exactly the kind of
|
|
28
|
+
* internal detail that moves between releases. Both positions are read for both
|
|
29
|
+
* tables, so a shape that swaps degrades to "no kind tags" (the pre-1.59.0
|
|
30
|
+
* answer) rather than throwing inside a validate run.
|
|
31
|
+
*/
|
|
32
|
+
/** Every string in `v`, or `[]` — `v` is `unknown` off an untyped parse. */
|
|
33
|
+
function stringList(v) {
|
|
34
|
+
return Array.isArray(v) ? v.filter((x) => typeof x === "string") : [];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The tags one kind record declares. 1.59.2 puts an element kind's under `tags`
|
|
38
|
+
* and a relationship kind's under `style.tags`; both are read for both, because
|
|
39
|
+
* which one a given kind table uses is LikeC4's internal business and a check
|
|
40
|
+
* that silently stopped seeing tags would fail OPEN — the exact failure this
|
|
41
|
+
* module was added to close.
|
|
42
|
+
*/
|
|
43
|
+
function kindTags(kind) {
|
|
44
|
+
if (!kind || typeof kind !== "object")
|
|
45
|
+
return [];
|
|
46
|
+
const rec = kind;
|
|
47
|
+
const style = rec["style"];
|
|
48
|
+
const nested = style && typeof style === "object" ? style["tags"] : undefined;
|
|
49
|
+
return [...new Set([...stringList(rec["tags"]), ...stringList(nested)])];
|
|
50
|
+
}
|
|
51
|
+
/** `{ kind: [tag, ...] }` for every kind in one of the specification's kind tables. */
|
|
52
|
+
function tagTable(table) {
|
|
53
|
+
if (!table || typeof table !== "object")
|
|
54
|
+
return {};
|
|
55
|
+
const out = {};
|
|
56
|
+
for (const [name, kind] of Object.entries(table)) {
|
|
57
|
+
const tags = kindTags(kind);
|
|
58
|
+
if (tags.length > 0)
|
|
59
|
+
out[name] = tags;
|
|
60
|
+
}
|
|
61
|
+
return out;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Normalize the `specification` LikeC4 hangs off its parsed model. Takes the
|
|
65
|
+
* whole untyped value so every shape assumption lives in this file: callers get
|
|
66
|
+
* `DocSpecification` or nothing, and never touch `unknown`.
|
|
67
|
+
*/
|
|
68
|
+
export function readSpecification(spec) {
|
|
69
|
+
if (!spec || typeof spec !== "object")
|
|
70
|
+
return undefined;
|
|
71
|
+
const rec = spec;
|
|
72
|
+
return {
|
|
73
|
+
elementKindTags: tagTable(rec["elements"]),
|
|
74
|
+
relationshipKindTags: tagTable(rec["relationships"]),
|
|
75
|
+
metadataKeys: stringList(rec["metadataKeys"]),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=specification.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"specification.js","sourceRoot":"","sources":["../../../../src/core/c4/parsed/specification.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAwBH,4EAA4E;AAC5E,SAAS,UAAU,CAAC,CAAU;IAC5B,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACrF,CAAC;AAED;;;;;;GAMG;AACH,SAAS,QAAQ,CAAC,IAAa;IAC7B,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACjD,MAAM,GAAG,GAAG,IAA+B,CAAC;IAC5C,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC;IAC3B,MAAM,MAAM,GAAG,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAE,KAAiC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3G,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,uFAAuF;AACvF,SAAS,QAAQ,CAAC,KAAc;IAC9B,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACnD,MAAM,GAAG,GAA6B,EAAE,CAAC;IACzC,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAgC,CAAC,EAAE,CAAC;QAC5E,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC5B,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IACxC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAa;IAC7C,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IACxD,MAAM,GAAG,GAAG,IAA+B,CAAC;IAC5C,OAAO;QACL,eAAe,EAAE,QAAQ,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC1C,oBAAoB,EAAE,QAAQ,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;QACpD,YAAY,EAAE,UAAU,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;KAC9C,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The `specification { ... }` block, read off LikeC4's parsed model.\n *\n * loam reads a model for what it MEANS, and until LikeC4 1.59.0 the\n * specification carried nothing loam had to mean anything by: it declared which\n * kinds and tags exist, and LikeC4 itself enforced that every use was declared.\n * 1.59.0 added **tags on kinds** — `specification { element softwareSystem {\n * #external } }` — and LikeC4 applies those tags to every element of the kind\n * before loam ever sees it. So `Elem.tags` stopped answering the question loam\n * was actually asking of it.\n *\n * That distinction is what this module exists for. loam does not need the\n * specification to SEE an inherited tag — the tag is already on the element, and\n * `flattenModel` has always copied it faithfully. It needs the specification to\n * tell an inherited tag from one somebody wrote on the element, because loam\n * gives two tags grading meaning (`#external` exempts an element from the\n * landscape↔services reconciliation, `#platform` silences a hub warning) and a\n * kind-wide declaration of either switches that grading off for every element of\n * the kind at once. Six words in the specification block turned a fleet gate\n * green over a fleet it had stopped checking; `kindTagFindings`\n * (commands/validate/fleet/kind-tags.ts) is the check that refuses that, and this\n * is the reader it is built on.\n *\n * Everything here is defensive. The specification is not part of the model API\n * loam's `ReadableModel` slice pins, and 1.59.2 already spells the two kind\n * tables differently — element kinds carry `tags` at the top of the kind record,\n * relationship kinds carry theirs under `style` — which is exactly the kind of\n * internal detail that moves between releases. Both positions are read for both\n * tables, so a shape that swaps degrades to \"no kind tags\" (the pre-1.59.0\n * answer) rather than throwing inside a validate run.\n */\n\n/** The slice of a LikeC4 `specification { ... }` block loam reads, normalized. */\nexport interface DocSpecification {\n /** Tag names each ELEMENT kind declares, by kind name. Kinds declaring none are absent. */\n elementKindTags: Record<string, string[]>;\n /**\n * Tag names each RELATIONSHIP kind declares, by kind name.\n *\n * Read and carried even though no check grades relationship tags today: the\n * feature tag on an edge is what `loam archive` splices on, and a kind-wide\n * declaration of one is the same defect on the write path. Dropping the table\n * here would make that a second reader's problem to rediscover.\n */\n relationshipKindTags: Record<string, string[]>;\n /**\n * The sorted union of every `metadata { }` key used anywhere in the document,\n * computed by LikeC4 for free. loam's own binding vocabulary is four keys —\n * `service`, `op`, `publishes`, `consumes` — and a near miss (`ops`,\n * `serviceId`) parses clean, binds nothing, and reports nothing.\n */\n metadataKeys: string[];\n}\n\n/** Every string in `v`, or `[]` — `v` is `unknown` off an untyped parse. */\nfunction stringList(v: unknown): string[] {\n return Array.isArray(v) ? v.filter((x): x is string => typeof x === \"string\") : [];\n}\n\n/**\n * The tags one kind record declares. 1.59.2 puts an element kind's under `tags`\n * and a relationship kind's under `style.tags`; both are read for both, because\n * which one a given kind table uses is LikeC4's internal business and a check\n * that silently stopped seeing tags would fail OPEN — the exact failure this\n * module was added to close.\n */\nfunction kindTags(kind: unknown): string[] {\n if (!kind || typeof kind !== \"object\") return [];\n const rec = kind as Record<string, unknown>;\n const style = rec[\"style\"];\n const nested = style && typeof style === \"object\" ? (style as Record<string, unknown>)[\"tags\"] : undefined;\n return [...new Set([...stringList(rec[\"tags\"]), ...stringList(nested)])];\n}\n\n/** `{ kind: [tag, ...] }` for every kind in one of the specification's kind tables. */\nfunction tagTable(table: unknown): Record<string, string[]> {\n if (!table || typeof table !== \"object\") return {};\n const out: Record<string, string[]> = {};\n for (const [name, kind] of Object.entries(table as Record<string, unknown>)) {\n const tags = kindTags(kind);\n if (tags.length > 0) out[name] = tags;\n }\n return out;\n}\n\n/**\n * Normalize the `specification` LikeC4 hangs off its parsed model. Takes the\n * whole untyped value so every shape assumption lives in this file: callers get\n * `DocSpecification` or nothing, and never touch `unknown`.\n */\nexport function readSpecification(spec: unknown): DocSpecification | undefined {\n if (!spec || typeof spec !== \"object\") return undefined;\n const rec = spec as Record<string, unknown>;\n return {\n elementKindTags: tagTable(rec[\"elements\"]),\n relationshipKindTags: tagTable(rec[\"relationships\"]),\n metadataKeys: stringList(rec[\"metadataKeys\"]),\n };\n}\n"]}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The corners of LikeC4's parse output that are typed `unknown`, decoded.
|
|
3
|
+
*
|
|
4
|
+
* LikeC4 models `metadata { ... }` values and a `description` as open shapes —
|
|
5
|
+
* a value may be a string, an array, or a rich-text object, and the declared
|
|
6
|
+
* type says none of that. Every one of those crossings needs a defensive read
|
|
7
|
+
* that answers "not present" rather than throwing, and each read encodes a
|
|
8
|
+
* defect somebody hit. They live together here, one module below the adapter
|
|
9
|
+
* (`../likec4.ts`) that calls them, because the adapter is at its line limit and
|
|
10
|
+
* because "decode a value LikeC4 left untyped" is a subject of its own: the
|
|
11
|
+
* specification reader beside this file is the same subject on a different
|
|
12
|
+
* corner of the same object.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Read one string key out of a LikeC4 `metadata { ... }` block. Four keys carry
|
|
16
|
+
* loam's spines: `op` on a relationship (the OpenAPI operationId it calls),
|
|
17
|
+
* `publishes`/`consumes` on a relationship (the AsyncAPI message it produces or
|
|
18
|
+
* receives), and `service` on an element (the services/<id> directory it stands
|
|
19
|
+
* for). Every one of them is read by BOTH model readers — the parsed one
|
|
20
|
+
* (`flattenModel` in `../likec4.ts`, which calls this) and the text scanner
|
|
21
|
+
* `scanModel` uses for archive's splice map — because a key only one of them
|
|
22
|
+
* sees is a key the merge silently drops. Elements with no metadata come back as
|
|
23
|
+
* `{}`, so a missing key is indistinguishable from a missing block — both mean
|
|
24
|
+
* "not bound".
|
|
25
|
+
*/
|
|
26
|
+
export function metaKey(m, key) {
|
|
27
|
+
if (m && typeof m === "object") {
|
|
28
|
+
const v = m[key];
|
|
29
|
+
if (typeof v === "string")
|
|
30
|
+
return v;
|
|
31
|
+
// A key written TWICE in one block comes back as an array, accepted with no
|
|
32
|
+
// error, and reading only the string form dropped every value — so an edge
|
|
33
|
+
// naming two operations reported as naming none, `c4.op-link-missing` telling
|
|
34
|
+
// the author the opposite of what they wrote. First wins, matching the text
|
|
35
|
+
// scanner's `keyedLiteral`: the two readers disagreeing about a binding is
|
|
36
|
+
// exactly what the paragraph above exists to prevent. Later values stay
|
|
37
|
+
// dropped — one id per key per edge is the model.
|
|
38
|
+
if (Array.isArray(v) && typeof v[0] === "string")
|
|
39
|
+
return v[0];
|
|
40
|
+
}
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
/** LikeC4 descriptions can be a string or a rich-text object ({ txt } / { text } / { md }). */
|
|
44
|
+
export function descText(d) {
|
|
45
|
+
if (typeof d === "string")
|
|
46
|
+
return d;
|
|
47
|
+
if (d && typeof d === "object") {
|
|
48
|
+
const o = d;
|
|
49
|
+
for (const key of ["txt", "text", "md", "value"]) {
|
|
50
|
+
const v = o[key];
|
|
51
|
+
if (typeof v === "string")
|
|
52
|
+
return v;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=values.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"values.js","sourceRoot":"","sources":["../../../../src/core/c4/parsed/values.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,OAAO,CAAC,CAAU,EAAE,GAAW;IAC7C,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAI,CAA6B,CAAC,GAAG,CAAC,CAAC;QAC9C,IAAI,OAAO,CAAC,KAAK,QAAQ;YAAE,OAAO,CAAC,CAAC;QACpC,4EAA4E;QAC5E,2EAA2E;QAC3E,8EAA8E;QAC9E,4EAA4E;QAC5E,2EAA2E;QAC3E,wEAAwE;QACxE,kDAAkD;QAClD,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,QAAQ;YAAE,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAChE,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,QAAQ,CAAC,CAAU;IACjC,IAAI,OAAO,CAAC,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC;IACpC,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,CAA4B,CAAC;QACvC,KAAK,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;YACjD,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC;YACjB,IAAI,OAAO,CAAC,KAAK,QAAQ;gBAAE,OAAO,CAAC,CAAC;QACtC,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["/**\n * The corners of LikeC4's parse output that are typed `unknown`, decoded.\n *\n * LikeC4 models `metadata { ... }` values and a `description` as open shapes —\n * a value may be a string, an array, or a rich-text object, and the declared\n * type says none of that. Every one of those crossings needs a defensive read\n * that answers \"not present\" rather than throwing, and each read encodes a\n * defect somebody hit. They live together here, one module below the adapter\n * (`../likec4.ts`) that calls them, because the adapter is at its line limit and\n * because \"decode a value LikeC4 left untyped\" is a subject of its own: the\n * specification reader beside this file is the same subject on a different\n * corner of the same object.\n */\n\n/**\n * Read one string key out of a LikeC4 `metadata { ... }` block. Four keys carry\n * loam's spines: `op` on a relationship (the OpenAPI operationId it calls),\n * `publishes`/`consumes` on a relationship (the AsyncAPI message it produces or\n * receives), and `service` on an element (the services/<id> directory it stands\n * for). Every one of them is read by BOTH model readers — the parsed one\n * (`flattenModel` in `../likec4.ts`, which calls this) and the text scanner\n * `scanModel` uses for archive's splice map — because a key only one of them\n * sees is a key the merge silently drops. Elements with no metadata come back as\n * `{}`, so a missing key is indistinguishable from a missing block — both mean\n * \"not bound\".\n */\nexport function metaKey(m: unknown, key: string): string | undefined {\n if (m && typeof m === \"object\") {\n const v = (m as Record<string, unknown>)[key];\n if (typeof v === \"string\") return v;\n // A key written TWICE in one block comes back as an array, accepted with no\n // error, and reading only the string form dropped every value — so an edge\n // naming two operations reported as naming none, `c4.op-link-missing` telling\n // the author the opposite of what they wrote. First wins, matching the text\n // scanner's `keyedLiteral`: the two readers disagreeing about a binding is\n // exactly what the paragraph above exists to prevent. Later values stay\n // dropped — one id per key per edge is the model.\n if (Array.isArray(v) && typeof v[0] === \"string\") return v[0];\n }\n return undefined;\n}\n\n/** LikeC4 descriptions can be a string or a rich-text object ({ txt } / { text } / { md }). */\nexport function descText(d: unknown): string | undefined {\n if (typeof d === \"string\") return d;\n if (d && typeof d === \"object\") {\n const o = d as Record<string, unknown>;\n for (const key of [\"txt\", \"text\", \"md\", \"value\"]) {\n const v = o[key];\n if (typeof v === \"string\") return v;\n }\n }\n return undefined;\n}\n"]}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ids of every view a document AUTHORS — the census read, as distinct from
|
|
3
|
+
* `./dynamic-views.ts`'s use-case read.
|
|
4
|
+
*
|
|
5
|
+
* Two readers over one record, because docs/DESIGN.md rule 26 states two
|
|
6
|
+
* filters and they are not interchangeable. A use-case reader wants dynamic
|
|
7
|
+
* views and filters on `_type === "dynamic"`. A census must see authored
|
|
8
|
+
* ELEMENT views too — a `view fleet { include * }` claims an id exactly as
|
|
9
|
+
* firmly as a dynamic one does — so it filters on `sourcePath !== undefined`
|
|
10
|
+
* instead. Measured: the `index` view LikeC4 synthesizes into every document is
|
|
11
|
+
* `_type: "element"` AND carries no `sourcePath`, so each filter drops it, and a
|
|
12
|
+
* reader that learned only the other one would report a fiction.
|
|
13
|
+
*
|
|
14
|
+
* Kept as its own module rather than a second export beside the use-case reader:
|
|
15
|
+
* the two share nothing but the reach into `$data`, and a defensive adapter is
|
|
16
|
+
* safer when each one owns its shape assumptions outright — the same reason
|
|
17
|
+
* `./specification.ts` states.
|
|
18
|
+
*
|
|
19
|
+
* Ids only, each with the file that claims it. What the view SHOWS stays
|
|
20
|
+
* unread, in any document, forever.
|
|
21
|
+
*/
|
|
22
|
+
/**
|
|
23
|
+
* The shape LikeC4 mints for a view its author never named — `view of svc { }`
|
|
24
|
+
* becomes `view_1yu7e9n`.
|
|
25
|
+
*
|
|
26
|
+
* Excluded from the census, and this is a correctness rule rather than
|
|
27
|
+
* tidiness: such an id is not a claim anybody wrote, and MEASURED at the
|
|
28
|
+
* 1.59.2 pin it is not even stable across loam's own two loaders — the same
|
|
29
|
+
* document yields `view_1yu7e9n` through `loadFile` and `view_zmkx82` through
|
|
30
|
+
* `loadBatch`, because the mint hashes the document URI and the batch stages
|
|
31
|
+
* into a temp workspace. Reporting it would put a value in `LoadedDoc` that
|
|
32
|
+
* depends on which loader ran, which is the one thing
|
|
33
|
+
* test/fleet-context-parity.test.ts exists to forbid; it also cannot collide
|
|
34
|
+
* with anything loam generates, since every generated id loam mints carries a
|
|
35
|
+
* prefix of its own.
|
|
36
|
+
*
|
|
37
|
+
* The cost is exact and small: an author who literally writes
|
|
38
|
+
* `view view_abc { }` loses that id from the census. It is a name nobody
|
|
39
|
+
* chooses, and no check reads the census for anything but collisions against
|
|
40
|
+
* loam's own generated prefixes, which this shape can never match.
|
|
41
|
+
*/
|
|
42
|
+
const MINTED_ID = /^view_[0-9a-z]+$/;
|
|
43
|
+
/** A record, or nothing — `v` is `unknown` off an untyped parse. */
|
|
44
|
+
function record(v) {
|
|
45
|
+
return v && typeof v === "object" && !Array.isArray(v) ? v : undefined;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Every view id the document declares, in the record's own order.
|
|
49
|
+
*
|
|
50
|
+
* `model` is the AWAITED `parsedModel()` result; `$data` is undefined on the
|
|
51
|
+
* unresolved promise, so a caller that forgets the await gets an empty census
|
|
52
|
+
* rather than a throw. Empty is also what a malformed record yields — this runs
|
|
53
|
+
* inside `validate --all` over every C4 document a fleet has, and the one
|
|
54
|
+
* behaviour it may never have is failing the run it was added to.
|
|
55
|
+
*/
|
|
56
|
+
export function readViewIds(model) {
|
|
57
|
+
const views = record(record(record(model)?.["$data"])?.["views"]);
|
|
58
|
+
if (!views)
|
|
59
|
+
return [];
|
|
60
|
+
const out = [];
|
|
61
|
+
for (const raw of Object.values(views)) {
|
|
62
|
+
const rec = record(raw);
|
|
63
|
+
// Authored, which is what `sourcePath` means here. The synthesized entry
|
|
64
|
+
// has none, and reporting a collision against a view nobody wrote would be
|
|
65
|
+
// a false error on every fleet in existence.
|
|
66
|
+
const sourcePath = rec?.["sourcePath"];
|
|
67
|
+
if (!rec || typeof sourcePath !== "string")
|
|
68
|
+
continue;
|
|
69
|
+
const id = rec["id"];
|
|
70
|
+
if (typeof id === "string" && id.length > 0 && !MINTED_ID.test(id))
|
|
71
|
+
out.push({ id, sourcePath });
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=view-ids.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view-ids.js","sourceRoot":"","sources":["../../../../src/core/c4/parsed/view-ids.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AASH;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,SAAS,GAAG,kBAAkB,CAAC;AAErC,oEAAoE;AACpE,SAAS,MAAM,CAAC,CAAU;IACxB,OAAO,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAA6B,CAAC,CAAC,CAAC,SAAS,CAAC;AACtG,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAClE,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,CAAC;IACtB,MAAM,GAAG,GAAkB,EAAE,CAAC;IAC9B,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACvC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QACxB,yEAAyE;QACzE,2EAA2E;QAC3E,6CAA6C;QAC7C,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC;QACvC,IAAI,CAAC,GAAG,IAAI,OAAO,UAAU,KAAK,QAAQ;YAAE,SAAS;QACrD,MAAM,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC;QACrB,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;IACnG,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["/**\n * The ids of every view a document AUTHORS — the census read, as distinct from\n * `./dynamic-views.ts`'s use-case read.\n *\n * Two readers over one record, because docs/DESIGN.md rule 26 states two\n * filters and they are not interchangeable. A use-case reader wants dynamic\n * views and filters on `_type === \"dynamic\"`. A census must see authored\n * ELEMENT views too — a `view fleet { include * }` claims an id exactly as\n * firmly as a dynamic one does — so it filters on `sourcePath !== undefined`\n * instead. Measured: the `index` view LikeC4 synthesizes into every document is\n * `_type: \"element\"` AND carries no `sourcePath`, so each filter drops it, and a\n * reader that learned only the other one would report a fiction.\n *\n * Kept as its own module rather than a second export beside the use-case reader:\n * the two share nothing but the reach into `$data`, and a defensive adapter is\n * safer when each one owns its shape assumptions outright — the same reason\n * `./specification.ts` states.\n *\n * Ids only, each with the file that claims it. What the view SHOWS stays\n * unread, in any document, forever.\n */\n\n/** One authored view id, and the document that claims it. */\nexport interface ViewIdClaim {\n id: string;\n /** As LikeC4 spells it: relative to the project root. */\n sourcePath: string;\n}\n\n/**\n * The shape LikeC4 mints for a view its author never named — `view of svc { }`\n * becomes `view_1yu7e9n`.\n *\n * Excluded from the census, and this is a correctness rule rather than\n * tidiness: such an id is not a claim anybody wrote, and MEASURED at the\n * 1.59.2 pin it is not even stable across loam's own two loaders — the same\n * document yields `view_1yu7e9n` through `loadFile` and `view_zmkx82` through\n * `loadBatch`, because the mint hashes the document URI and the batch stages\n * into a temp workspace. Reporting it would put a value in `LoadedDoc` that\n * depends on which loader ran, which is the one thing\n * test/fleet-context-parity.test.ts exists to forbid; it also cannot collide\n * with anything loam generates, since every generated id loam mints carries a\n * prefix of its own.\n *\n * The cost is exact and small: an author who literally writes\n * `view view_abc { }` loses that id from the census. It is a name nobody\n * chooses, and no check reads the census for anything but collisions against\n * loam's own generated prefixes, which this shape can never match.\n */\nconst MINTED_ID = /^view_[0-9a-z]+$/;\n\n/** A record, or nothing — `v` is `unknown` off an untyped parse. */\nfunction record(v: unknown): Record<string, unknown> | undefined {\n return v && typeof v === \"object\" && !Array.isArray(v) ? (v as Record<string, unknown>) : undefined;\n}\n\n/**\n * Every view id the document declares, in the record's own order.\n *\n * `model` is the AWAITED `parsedModel()` result; `$data` is undefined on the\n * unresolved promise, so a caller that forgets the await gets an empty census\n * rather than a throw. Empty is also what a malformed record yields — this runs\n * inside `validate --all` over every C4 document a fleet has, and the one\n * behaviour it may never have is failing the run it was added to.\n */\nexport function readViewIds(model: unknown): ViewIdClaim[] {\n const views = record(record(record(model)?.[\"$data\"])?.[\"views\"]);\n if (!views) return [];\n const out: ViewIdClaim[] = [];\n for (const raw of Object.values(views)) {\n const rec = record(raw);\n // Authored, which is what `sourcePath` means here. The synthesized entry\n // has none, and reporting a collision against a view nobody wrote would be\n // a false error on every fleet in existence.\n const sourcePath = rec?.[\"sourcePath\"];\n if (!rec || typeof sourcePath !== \"string\") continue;\n const id = rec[\"id\"];\n if (typeof id === \"string\" && id.length > 0 && !MINTED_ID.test(id)) out.push({ id, sourcePath });\n }\n return out;\n}\n"]}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `architecture/` as ONE LikeC4 project — the docsDir-aware wrapper over the two
|
|
3
|
+
* modules beside it.
|
|
4
|
+
*
|
|
5
|
+
* It lived in `commands/validate/fleet/load.ts` until the use-case axis grew a
|
|
6
|
+
* second reader. That was the right home while `validate --all` was the only
|
|
7
|
+
* caller: the command layer is where a `DocsDir` becomes paths. It stopped being
|
|
8
|
+
* the right home the moment `core/usecases/fleet.ts` needed the same load —
|
|
9
|
+
* `core/` may not import from `commands/` (AGENTS.md), so the choice was a second
|
|
10
|
+
* copy of the two-line composition or one copy one level down. A second copy is
|
|
11
|
+
* the copy that drifts, and the thing that would drift is which documents are in
|
|
12
|
+
* the project: the generated `architecture/subsystems.likec4` exclusion is a
|
|
13
|
+
* correctness rule (see `./documents.ts`), not a preference, and a reader that
|
|
14
|
+
* forgot it would blank a fleet's whole map over a stale generated file.
|
|
15
|
+
*
|
|
16
|
+
* So the wrapper moved here and `validate`'s own module kept the landscape
|
|
17
|
+
* CONTAINMENT — `readLandscape` / `unreadableLandscape` — which is genuinely
|
|
18
|
+
* command-layer business: it is about which validate target a failed read is
|
|
19
|
+
* filed against.
|
|
20
|
+
*/
|
|
21
|
+
import { join } from "node:path";
|
|
22
|
+
import { architectureDocuments } from "./documents.js";
|
|
23
|
+
import { asLoadedDoc, loadProject } from "./load.js";
|
|
24
|
+
import { subsystemViewsPath } from "../../repo/paths.js";
|
|
25
|
+
/** `<docsDir>/architecture` — the LikeC4 project root, spelled once. */
|
|
26
|
+
export function architectureDir(docsDir) {
|
|
27
|
+
return join(docsDir, "architecture");
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The fleet map, read as the PROJECT it actually is.
|
|
31
|
+
*
|
|
32
|
+
* `architecture/landscape.likec4` plus every `architecture/usecases/*.likec4`,
|
|
33
|
+
* merged the way the renderer merges them — because a use case declares views
|
|
34
|
+
* over the landscape's elements and does not parse standalone (measured: five
|
|
35
|
+
* errors). `architectureDocuments` owns which files are in and why the
|
|
36
|
+
* generated one is not.
|
|
37
|
+
*
|
|
38
|
+
* A fleet with no use cases loads exactly the landscape and behaves as it
|
|
39
|
+
* always did, which is what keeps this a widening rather than a change.
|
|
40
|
+
*/
|
|
41
|
+
export async function loadArchitecture(docsDir) {
|
|
42
|
+
const dir = architectureDir(docsDir);
|
|
43
|
+
return asLoadedDoc(await loadProject(dir, await architectureDocuments(dir, [subsystemViewsPath(docsDir)])));
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=architecture.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"architecture.js","sourceRoot":"","sources":["../../../../src/core/c4/project/architecture.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAErD,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEzD,wEAAwE;AACxE,MAAM,UAAU,eAAe,CAAC,OAAgB;IAC9C,OAAO,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,OAAgB;IACrD,MAAM,GAAG,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IACrC,OAAO,WAAW,CAAC,MAAM,WAAW,CAAC,GAAG,EAAE,MAAM,qBAAqB,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9G,CAAC","sourcesContent":["/**\n * `architecture/` as ONE LikeC4 project — the docsDir-aware wrapper over the two\n * modules beside it.\n *\n * It lived in `commands/validate/fleet/load.ts` until the use-case axis grew a\n * second reader. That was the right home while `validate --all` was the only\n * caller: the command layer is where a `DocsDir` becomes paths. It stopped being\n * the right home the moment `core/usecases/fleet.ts` needed the same load —\n * `core/` may not import from `commands/` (AGENTS.md), so the choice was a second\n * copy of the two-line composition or one copy one level down. A second copy is\n * the copy that drifts, and the thing that would drift is which documents are in\n * the project: the generated `architecture/subsystems.likec4` exclusion is a\n * correctness rule (see `./documents.ts`), not a preference, and a reader that\n * forgot it would blank a fleet's whole map over a stale generated file.\n *\n * So the wrapper moved here and `validate`'s own module kept the landscape\n * CONTAINMENT — `readLandscape` / `unreadableLandscape` — which is genuinely\n * command-layer business: it is about which validate target a failed read is\n * filed against.\n */\nimport { join } from \"node:path\";\nimport type { LoadedDoc } from \"../likec4.js\";\nimport { architectureDocuments } from \"./documents.js\";\nimport { asLoadedDoc, loadProject } from \"./load.js\";\nimport type { DocsDir } from \"../../kernel/ids/dirs.js\";\nimport { subsystemViewsPath } from \"../../repo/paths.js\";\n\n/** `<docsDir>/architecture` — the LikeC4 project root, spelled once. */\nexport function architectureDir(docsDir: DocsDir): string {\n return join(docsDir, \"architecture\");\n}\n\n/**\n * The fleet map, read as the PROJECT it actually is.\n *\n * `architecture/landscape.likec4` plus every `architecture/usecases/*.likec4`,\n * merged the way the renderer merges them — because a use case declares views\n * over the landscape's elements and does not parse standalone (measured: five\n * errors). `architectureDocuments` owns which files are in and why the\n * generated one is not.\n *\n * A fleet with no use cases loads exactly the landscape and behaves as it\n * always did, which is what keeps this a widening rather than a change.\n */\nexport async function loadArchitecture(docsDir: DocsDir): Promise<LoadedDoc> {\n const dir = architectureDir(docsDir);\n return asLoadedDoc(await loadProject(dir, await architectureDocuments(dir, [subsystemViewsPath(docsDir)])));\n}\n"]}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which `.likec4` documents in a docs repo's `architecture/` loam loads as one
|
|
3
|
+
* project.
|
|
4
|
+
*
|
|
5
|
+
* The renderer's answer is "all of them" — `likec4.config.json` scopes the root
|
|
6
|
+
* LikeC4 project to everything but `services/**` and `features/**`. loam's
|
|
7
|
+
* answer is all of them EXCEPT the generated `architecture/subsystems.likec4`,
|
|
8
|
+
* and that exception is not an optimisation:
|
|
9
|
+
*
|
|
10
|
+
* - docs/DESIGN.md rule 26 excludes the generated file from every read loam
|
|
11
|
+
* performs. Its staleness is a byte compare (`subsystem.views-stale`) and
|
|
12
|
+
* nothing anywhere reads its contents.
|
|
13
|
+
* - Including it would invent a failure mode. Its `include` lines name
|
|
14
|
+
* landscape element ids, so a file that has drifted — a service removed
|
|
15
|
+
* since the last `loam subsystem sync` — would be a parse error, and a parse
|
|
16
|
+
* error in one project document blanks the model for all of them. A fleet
|
|
17
|
+
* whose only problem is a stale generated file would lose its whole map
|
|
18
|
+
* instead of getting the one finding that names the repair.
|
|
19
|
+
*
|
|
20
|
+
* The skip is passed in by the caller rather than spelled here, so the filename
|
|
21
|
+
* stays written in `repo/paths.ts` alone.
|
|
22
|
+
*/
|
|
23
|
+
import { readdir } from "node:fs/promises";
|
|
24
|
+
import { join, resolve } from "node:path";
|
|
25
|
+
/**
|
|
26
|
+
* Every `.likec4` file under `dir`, recursively, minus `skip`, in a stable
|
|
27
|
+
* order.
|
|
28
|
+
*
|
|
29
|
+
* Sorted because it decides the staging order and therefore nothing at all —
|
|
30
|
+
* LikeC4 merges a project regardless — but a stable list makes a failure
|
|
31
|
+
* reproducible and a diff of one readable. A directory that does not exist is
|
|
32
|
+
* an empty list, never a throw: a fleet with no `architecture/` is a fleet with
|
|
33
|
+
* nothing to load, which is already `landscape.missing`'s question, not this
|
|
34
|
+
* function's.
|
|
35
|
+
*/
|
|
36
|
+
export async function architectureDocuments(dir, skip = []) {
|
|
37
|
+
const excluded = new Set(skip.map((path) => resolve(path)));
|
|
38
|
+
const found = [];
|
|
39
|
+
const walk = async (at) => {
|
|
40
|
+
let entries;
|
|
41
|
+
try {
|
|
42
|
+
entries = await readdir(at, { withFileTypes: true });
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
for (const entry of entries) {
|
|
48
|
+
const path = join(at, entry.name);
|
|
49
|
+
if (entry.isDirectory())
|
|
50
|
+
await walk(path);
|
|
51
|
+
else if (entry.name.endsWith(".likec4") && !excluded.has(resolve(path)))
|
|
52
|
+
found.push(path);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
await walk(resolve(dir));
|
|
56
|
+
return found.sort();
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=documents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"documents.js","sourceRoot":"","sources":["../../../../src/core/c4/project/documents.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAE1C;;;;;;;;;;GAUG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,GAAW,EAAE,IAAI,GAAa,EAAE;IAC1E,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,IAAI,GAAG,KAAK,EAAE,EAAU,EAAiB,EAAE;QAC/C,IAAI,OAAO,CAAC;QACZ,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,OAAO,CAAC,EAAE,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO;QACT,CAAC;QACD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;YAC5B,MAAM,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YAClC,IAAI,KAAK,CAAC,WAAW,EAAE;gBAAE,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;iBACrC,IAAI,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5F,CAAC;IACH,CAAC,CAAC;IACF,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACzB,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC","sourcesContent":["/**\n * Which `.likec4` documents in a docs repo's `architecture/` loam loads as one\n * project.\n *\n * The renderer's answer is \"all of them\" — `likec4.config.json` scopes the root\n * LikeC4 project to everything but `services/**` and `features/**`. loam's\n * answer is all of them EXCEPT the generated `architecture/subsystems.likec4`,\n * and that exception is not an optimisation:\n *\n * - docs/DESIGN.md rule 26 excludes the generated file from every read loam\n * performs. Its staleness is a byte compare (`subsystem.views-stale`) and\n * nothing anywhere reads its contents.\n * - Including it would invent a failure mode. Its `include` lines name\n * landscape element ids, so a file that has drifted — a service removed\n * since the last `loam subsystem sync` — would be a parse error, and a parse\n * error in one project document blanks the model for all of them. A fleet\n * whose only problem is a stale generated file would lose its whole map\n * instead of getting the one finding that names the repair.\n *\n * The skip is passed in by the caller rather than spelled here, so the filename\n * stays written in `repo/paths.ts` alone.\n */\nimport { readdir } from \"node:fs/promises\";\nimport { join, resolve } from \"node:path\";\n\n/**\n * Every `.likec4` file under `dir`, recursively, minus `skip`, in a stable\n * order.\n *\n * Sorted because it decides the staging order and therefore nothing at all —\n * LikeC4 merges a project regardless — but a stable list makes a failure\n * reproducible and a diff of one readable. A directory that does not exist is\n * an empty list, never a throw: a fleet with no `architecture/` is a fleet with\n * nothing to load, which is already `landscape.missing`'s question, not this\n * function's.\n */\nexport async function architectureDocuments(dir: string, skip: string[] = []): Promise<string[]> {\n const excluded = new Set(skip.map((path) => resolve(path)));\n const found: string[] = [];\n const walk = async (at: string): Promise<void> => {\n let entries;\n try {\n entries = await readdir(at, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const path = join(at, entry.name);\n if (entry.isDirectory()) await walk(path);\n else if (entry.name.endsWith(\".likec4\") && !excluded.has(resolve(path))) found.push(path);\n }\n };\n await walk(resolve(dir));\n return found.sort();\n}\n"]}
|