@ybotok/loam 0.1.0-beta.3 → 0.2.0-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5992 -82
- package/COMPARISON.md +168 -63
- package/CONTRIBUTING.md +121 -0
- package/MIGRATING-from-OpenSpec.md +238 -55
- package/QUICKSTART.md +302 -0
- package/README.md +653 -144
- package/ROADMAP.md +1035 -0
- package/SCHEMA.md +3916 -263
- package/SECURITY.md +21 -3
- package/WORKFLOW.md +927 -0
- package/dist/cli.js +133 -21
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +204 -0
- package/dist/commands/adopt/adopt.js.map +1 -0
- package/dist/commands/adopt/render.js +309 -0
- package/dist/commands/adopt/render.js.map +1 -0
- package/dist/commands/archive/archive.js +74 -0
- package/dist/commands/archive/archive.js.map +1 -0
- package/dist/commands/archive/closing.js +42 -0
- package/dist/commands/archive/closing.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +172 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/consumers.js +56 -0
- package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +193 -0
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
- package/dist/commands/archive/plan/document/head.js +151 -0
- package/dist/commands/archive/plan/document/head.js.map +1 -0
- package/dist/commands/archive/plan/document/links.js +284 -0
- package/dist/commands/archive/plan/document/links.js.map +1 -0
- package/dist/commands/archive/plan/document/run.js +136 -0
- package/dist/commands/archive/plan/document/run.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +319 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +298 -0
- package/dist/commands/archive/plan/landscape.js.map +1 -0
- package/dist/commands/archive/plan/model/extending.js +85 -0
- package/dist/commands/archive/plan/model/extending.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +106 -0
- package/dist/commands/archive/plan/refusal.js.map +1 -0
- package/dist/commands/archive/plan/specs.js +318 -0
- package/dist/commands/archive/plan/specs.js.map +1 -0
- package/dist/commands/archive/plan/state.js +30 -0
- package/dist/commands/archive/plan/state.js.map +1 -0
- package/dist/commands/archive/run.js +355 -0
- package/dist/commands/archive/run.js.map +1 -0
- package/dist/commands/archive/shipped.js +49 -0
- package/dist/commands/archive/shipped.js.map +1 -0
- package/dist/commands/context/context.js +166 -0
- package/dist/commands/context/context.js.map +1 -0
- package/dist/commands/context/print.js +305 -0
- package/dist/commands/context/print.js.map +1 -0
- package/dist/commands/delta/delta.js +367 -0
- package/dist/commands/delta/delta.js.map +1 -0
- package/dist/commands/delta/print.js +221 -0
- package/dist/commands/delta/print.js.map +1 -0
- package/dist/commands/dependencies.js +6 -8
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +86 -0
- package/dist/commands/diff/diff.js.map +1 -0
- package/dist/commands/diff/print.js +38 -0
- package/dist/commands/diff/print.js.map +1 -0
- package/dist/commands/doctor.js +65 -5
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +227 -0
- package/dist/commands/explain/explain.js.map +1 -0
- package/dist/commands/explore.js +39 -28
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +152 -0
- package/dist/commands/gate/gate.js.map +1 -0
- package/dist/commands/gate/print.js +66 -0
- package/dist/commands/gate/print.js.map +1 -0
- package/dist/commands/gherkin/commit.js +105 -0
- package/dist/commands/gherkin/commit.js.map +1 -0
- package/dist/commands/gherkin/gherkin.js +262 -0
- package/dist/commands/gherkin/gherkin.js.map +1 -0
- package/dist/commands/gherkin/reconcile.js +146 -0
- package/dist/commands/gherkin/reconcile.js.map +1 -0
- package/dist/commands/gherkin/render.js +77 -0
- package/dist/commands/gherkin/render.js.map +1 -0
- package/dist/commands/init/example.js +204 -0
- package/dist/commands/init/example.js.map +1 -0
- package/dist/commands/init/first-hour.js +72 -0
- package/dist/commands/init/first-hour.js.map +1 -0
- package/dist/commands/{init.js → init/init.js} +142 -71
- package/dist/commands/init/init.js.map +1 -0
- package/dist/commands/init/mcp.js +131 -0
- package/dist/commands/init/mcp.js.map +1 -0
- package/dist/commands/init/options.js +78 -0
- package/dist/commands/init/options.js.map +1 -0
- package/dist/commands/instructions.js +72 -14
- package/dist/commands/instructions.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +63 -0
- package/dist/commands/list/campaign/campaign.js.map +1 -0
- package/dist/commands/list/campaign/owners.js +65 -0
- package/dist/commands/list/campaign/owners.js.map +1 -0
- package/dist/commands/list/json.js +155 -0
- package/dist/commands/list/json.js.map +1 -0
- package/dist/commands/list/list.js +358 -0
- package/dist/commands/list/list.js.map +1 -0
- package/dist/commands/list/print.js +344 -0
- package/dist/commands/list/print.js.map +1 -0
- package/dist/commands/list/review.js +120 -0
- package/dist/commands/list/review.js.map +1 -0
- package/dist/commands/list/suites/suites.js +140 -0
- package/dist/commands/list/suites/suites.js.map +1 -0
- package/dist/commands/list/views.js +108 -0
- package/dist/commands/list/views.js.map +1 -0
- package/dist/commands/mcp/dispatch.js +238 -0
- package/dist/commands/mcp/dispatch.js.map +1 -0
- package/dist/commands/mcp/mcp.js +75 -0
- package/dist/commands/mcp/mcp.js.map +1 -0
- package/dist/commands/mcp/serve.js +55 -0
- package/dist/commands/mcp/serve.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/active.js +175 -0
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
- package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/living.js +62 -0
- package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/stage.js +143 -0
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/target.js +219 -0
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js +86 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/error.js +18 -0
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js +162 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/paths.js +40 -0
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/read.js +49 -0
- package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
- package/dist/commands/migrate-openspec/print.js +89 -0
- package/dist/commands/migrate-openspec/print.js.map +1 -0
- package/dist/commands/new/capability-template.js +118 -0
- package/dist/commands/new/capability-template.js.map +1 -0
- package/dist/commands/new/commit.js +62 -0
- package/dist/commands/new/commit.js.map +1 -0
- package/dist/commands/new/modifies.js +206 -0
- package/dist/commands/new/modifies.js.map +1 -0
- package/dist/commands/new/new.js +328 -0
- package/dist/commands/new/new.js.map +1 -0
- package/dist/commands/new/templates.js +279 -0
- package/dist/commands/new/templates.js.map +1 -0
- package/dist/commands/open.js +199 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/policy/format.js +152 -0
- package/dist/commands/policy/format.js.map +1 -0
- package/dist/commands/{docs-repo-gate.js → policy/gate.js} +38 -11
- package/dist/commands/policy/gate.js.map +1 -0
- package/dist/commands/rebase/edit.js +106 -0
- package/dist/commands/rebase/edit.js.map +1 -0
- package/dist/commands/rebase/living.js +185 -0
- package/dist/commands/rebase/living.js.map +1 -0
- package/dist/commands/rebase/plan.js +245 -0
- package/dist/commands/rebase/plan.js.map +1 -0
- package/dist/commands/rebase/rebase.js +300 -0
- package/dist/commands/rebase/rebase.js.map +1 -0
- package/dist/commands/seed/commit.js +221 -0
- package/dist/commands/seed/commit.js.map +1 -0
- package/dist/commands/seed/plan.js +278 -0
- package/dist/commands/seed/plan.js.map +1 -0
- package/dist/commands/seed/seed.js +174 -0
- package/dist/commands/seed/seed.js.map +1 -0
- package/dist/commands/show/feature.js +182 -0
- package/dist/commands/show/feature.js.map +1 -0
- package/dist/commands/show/introduced.js +157 -0
- package/dist/commands/show/introduced.js.map +1 -0
- package/dist/commands/show/marks.js +53 -0
- package/dist/commands/show/marks.js.map +1 -0
- package/dist/commands/show/service.js +239 -0
- package/dist/commands/show/service.js.map +1 -0
- package/dist/commands/show/show.js +87 -0
- package/dist/commands/show/show.js.map +1 -0
- package/dist/commands/status/fleet-next.js +90 -0
- package/dist/commands/status/fleet-next.js.map +1 -0
- package/dist/commands/status/json.js +47 -0
- package/dist/commands/status/json.js.map +1 -0
- package/dist/commands/status/print.js +209 -0
- package/dist/commands/status/print.js.map +1 -0
- package/dist/commands/status/status.js +115 -0
- package/dist/commands/status/status.js.map +1 -0
- package/dist/commands/steps/steps.js +269 -0
- package/dist/commands/steps/steps.js.map +1 -0
- package/dist/commands/subsystem/edit.js +192 -0
- package/dist/commands/subsystem/edit.js.map +1 -0
- package/dist/commands/subsystem/move.js +325 -0
- package/dist/commands/subsystem/move.js.map +1 -0
- package/dist/commands/subsystem/query.js +113 -0
- package/dist/commands/subsystem/query.js.map +1 -0
- package/dist/commands/subsystem/subsystem.js +98 -0
- package/dist/commands/subsystem/subsystem.js.map +1 -0
- package/dist/commands/subsystem/sync.js +318 -0
- package/dist/commands/subsystem/sync.js.map +1 -0
- package/dist/commands/subsystem/txn/exclude.js +132 -0
- package/dist/commands/subsystem/txn/exclude.js.map +1 -0
- package/dist/commands/subsystem/txn/links.js +128 -0
- package/dist/commands/subsystem/txn/links.js.map +1 -0
- package/dist/commands/subsystem/txn/report.js +174 -0
- package/dist/commands/subsystem/txn/report.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +196 -0
- package/dist/commands/subsystem/txn/txn.js.map +1 -0
- package/dist/commands/subsystem/txn/views.js +249 -0
- package/dist/commands/subsystem/txn/views.js.map +1 -0
- package/dist/commands/tasks/actions.js +107 -0
- package/dist/commands/tasks/actions.js.map +1 -0
- package/dist/commands/tasks/render.js +253 -0
- package/dist/commands/tasks/render.js.map +1 -0
- package/dist/commands/tasks/tasks.js +119 -0
- package/dist/commands/tasks/tasks.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +176 -0
- package/dist/commands/unarchive/manifest.js.map +1 -0
- package/dist/commands/unarchive/restore.js +254 -0
- package/dist/commands/unarchive/restore.js.map +1 -0
- package/dist/commands/unarchive/unarchive.js +59 -0
- package/dist/commands/unarchive/unarchive.js.map +1 -0
- package/dist/commands/validate/arch-coverage.js +245 -0
- package/dist/commands/validate/arch-coverage.js.map +1 -0
- package/dist/commands/validate/checks/fleet-shape.js +204 -0
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
- package/dist/commands/validate/checks/health-deps.js +58 -0
- package/dist/commands/validate/checks/health-deps.js.map +1 -0
- package/dist/commands/validate/checks/introduced.js +102 -0
- package/dist/commands/validate/checks/introduced.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +264 -0
- package/dist/commands/validate/checks/requirements.js.map +1 -0
- package/dist/commands/validate/checks/sources.js +85 -0
- package/dist/commands/validate/checks/sources.js.map +1 -0
- package/dist/commands/validate/coverage/covers-after.js +105 -0
- package/dist/commands/validate/coverage/covers-after.js.map +1 -0
- package/dist/commands/validate/feature.js +222 -0
- package/dist/commands/validate/feature.js.map +1 -0
- package/dist/commands/validate/fleet/census.js +93 -0
- package/dist/commands/validate/fleet/census.js.map +1 -0
- package/dist/commands/validate/fleet/kind-tags.js +39 -0
- package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
- package/dist/commands/validate/fleet/landscape.js +371 -0
- package/dist/commands/validate/fleet/landscape.js.map +1 -0
- package/dist/commands/validate/fleet/load.js +118 -0
- package/dist/commands/validate/fleet/load.js.map +1 -0
- package/dist/commands/validate/fleet/map/attest.js +98 -0
- package/dist/commands/validate/fleet/map/attest.js.map +1 -0
- package/dist/commands/validate/fleet/map/bindings.js +107 -0
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
- package/dist/commands/validate/fleet/map/consumers.js +244 -0
- package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
- package/dist/commands/validate/fleet/map/isolation.js +116 -0
- package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
- package/dist/commands/validate/fleet/map/usecases.js +54 -0
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +266 -0
- package/dist/commands/validate/fleet/obligations.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/print.js +71 -0
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js +162 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/place.js +13 -0
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
- package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +75 -0
- package/dist/commands/validate/fleet/views/ids.js.map +1 -0
- package/dist/commands/validate/fleet/views/projects.js +278 -0
- package/dist/commands/validate/fleet/views/projects.js.map +1 -0
- package/dist/commands/validate/fleet/views/root-documents.js +83 -0
- package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +52 -0
- package/dist/commands/validate/fleet/views/stale.js.map +1 -0
- package/dist/commands/validate/links/corpus.js +89 -0
- package/dist/commands/validate/links/corpus.js.map +1 -0
- package/dist/commands/validate/links/glossary.js +75 -0
- package/dist/commands/validate/links/glossary.js.map +1 -0
- package/dist/commands/validate/render/repeats.js +63 -0
- package/dist/commands/validate/render/repeats.js.map +1 -0
- package/dist/commands/validate/render/rollups.js +115 -0
- package/dist/commands/validate/render/rollups.js.map +1 -0
- package/dist/commands/validate/render/text.js +199 -0
- package/dist/commands/validate/render/text.js.map +1 -0
- package/dist/commands/validate/report.js +145 -0
- package/dist/commands/validate/report.js.map +1 -0
- package/dist/commands/validate/scope.js +113 -0
- package/dist/commands/validate/scope.js.map +1 -0
- package/dist/commands/validate/service/api.js +252 -0
- package/dist/commands/validate/service/api.js.map +1 -0
- package/dist/commands/validate/service/contracts/generated.js +134 -0
- package/dist/commands/validate/service/contracts/generated.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +241 -0
- package/dist/commands/validate/service/events/events.js.map +1 -0
- package/dist/commands/validate/service/events/message-producers.js +77 -0
- package/dist/commands/validate/service/events/message-producers.js.map +1 -0
- package/dist/commands/validate/service/evidence-pins.js +177 -0
- package/dist/commands/validate/service/evidence-pins.js.map +1 -0
- package/dist/commands/validate/service/model/diverged.js +226 -0
- package/dist/commands/validate/service/model/diverged.js.map +1 -0
- package/dist/commands/validate/service/model/grade.js +163 -0
- package/dist/commands/validate/service/model/grade.js.map +1 -0
- package/dist/commands/validate/service/service.js +310 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +279 -0
- package/dist/commands/validate/service/specs.js.map +1 -0
- package/dist/commands/validate/service/spine.js +148 -0
- package/dist/commands/validate/service/spine.js.map +1 -0
- package/dist/commands/validate/service/usecases/tags.js +113 -0
- package/dist/commands/validate/service/usecases/tags.js.map +1 -0
- package/dist/commands/validate/service/usecases/usecases.js +209 -0
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/validate.js +363 -0
- package/dist/commands/validate/validate.js.map +1 -0
- package/dist/commands/verify/cross/diff.js +178 -0
- package/dist/commands/verify/cross/diff.js.map +1 -0
- package/dist/commands/verify/evidence/contract.js +32 -0
- package/dist/commands/verify/evidence/contract.js.map +1 -0
- package/dist/commands/verify/evidence/pins.js +52 -0
- package/dist/commands/verify/evidence/pins.js.map +1 -0
- package/dist/commands/verify/evidence/read.js +81 -0
- package/dist/commands/verify/evidence/read.js.map +1 -0
- package/dist/commands/verify/frozen.js +263 -0
- package/dist/commands/verify/frozen.js.map +1 -0
- package/dist/commands/verify/record.js +278 -0
- package/dist/commands/verify/record.js.map +1 -0
- package/dist/commands/verify/report.js +206 -0
- package/dist/commands/verify/report.js.map +1 -0
- package/dist/commands/verify/results.js +328 -0
- package/dist/commands/verify/results.js.map +1 -0
- package/dist/commands/verify/verify.js +220 -0
- package/dist/commands/verify/verify.js.map +1 -0
- package/dist/commands/vouch/contract.js +11 -0
- package/dist/commands/vouch/contract.js.map +1 -0
- package/dist/commands/vouch/pack/contract.js +2 -0
- package/dist/commands/vouch/pack/contract.js.map +1 -0
- package/dist/commands/vouch/pack/pack.js +266 -0
- package/dist/commands/vouch/pack/pack.js.map +1 -0
- package/dist/commands/vouch/pack/print.js +266 -0
- package/dist/commands/vouch/pack/print.js.map +1 -0
- package/dist/commands/vouch/pack/sections.js +141 -0
- package/dist/commands/vouch/pack/sections.js.map +1 -0
- package/dist/commands/vouch/prompt/confirm.js +46 -0
- package/dist/commands/vouch/prompt/confirm.js.map +1 -0
- package/dist/commands/vouch/report.js +101 -0
- package/dist/commands/vouch/report.js.map +1 -0
- package/dist/commands/vouch/run.js +230 -0
- package/dist/commands/vouch/run.js.map +1 -0
- package/dist/commands/vouch/sample/plan.js +111 -0
- package/dist/commands/vouch/sample/plan.js.map +1 -0
- package/dist/commands/vouch/sample/print.js +109 -0
- package/dist/commands/vouch/sample/print.js.map +1 -0
- package/dist/commands/vouch/vet/verify.js +155 -0
- package/dist/commands/vouch/vet/verify.js.map +1 -0
- package/dist/commands/vouch/vouch.js +169 -0
- package/dist/commands/vouch/vouch.js.map +1 -0
- package/dist/core/agent/agents-md/command-map.js +299 -0
- package/dist/core/agent/agents-md/command-map.js.map +1 -0
- package/dist/core/agent/agents-md/map/explain.js +46 -0
- package/dist/core/agent/agents-md/map/explain.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/context.js +50 -0
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js +59 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js +65 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
- package/dist/core/agent/agents-md/map/mcp.js +44 -0
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
- package/dist/core/agent/agents-md/map/status.js +78 -0
- package/dist/core/agent/agents-md/map/status.js.map +1 -0
- package/dist/core/agent/agents-md/map/subsystem.js +104 -0
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
- package/dist/core/agent/agents-md/map/usecases.js +138 -0
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
- package/dist/core/agent/agents-md/refusals.js +273 -0
- package/dist/core/agent/agents-md/refusals.js.map +1 -0
- package/dist/core/agent/agents-md.js +203 -0
- package/dist/core/agent/agents-md.js.map +1 -0
- package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +60 -0
- package/dist/core/agent/agents-stamp.js.map +1 -0
- package/dist/core/agent/contract.js +2 -0
- package/dist/core/agent/contract.js.map +1 -0
- package/dist/core/agent/protocol.js +193 -0
- package/dist/core/agent/protocol.js.map +1 -0
- package/dist/core/agent/scaffold.js +254 -0
- package/dist/core/agent/scaffold.js.map +1 -0
- package/dist/core/agent/support/report.js +144 -0
- package/dist/core/agent/support/report.js.map +1 -0
- package/dist/core/agent/tools/dialects.js +151 -0
- package/dist/core/agent/tools/dialects.js.map +1 -0
- package/dist/core/agent/tools/registry.js +193 -0
- package/dist/core/agent/tools/registry.js.map +1 -0
- package/dist/core/agent/workflows/adopt.js +280 -0
- package/dist/core/agent/workflows/adopt.js.map +1 -0
- package/dist/core/agent/workflows/check.js +373 -0
- package/dist/core/agent/workflows/check.js.map +1 -0
- package/dist/core/agent/workflows/closing.js +323 -0
- package/dist/core/agent/workflows/closing.js.map +1 -0
- package/dist/core/agent/workflows/feature.js +220 -0
- package/dist/core/agent/workflows/feature.js.map +1 -0
- package/dist/core/agent/workflows/implement.js +188 -0
- package/dist/core/agent/workflows/implement.js.map +1 -0
- package/dist/core/agent/workflows/reference/authoring.js +311 -0
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
- package/dist/core/agent/workflows/reference/codes.js +67 -0
- package/dist/core/agent/workflows/reference/codes.js.map +1 -0
- package/dist/core/agent/workflows/reference/done-check.js +210 -0
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +19 -0
- package/dist/core/agent/workflows/reference/reference.js.map +1 -0
- package/dist/core/agent/workflows/reference/spine.js +338 -0
- package/dist/core/agent/workflows/reference/spine.js.map +1 -0
- package/dist/core/asyncapi/baseline/plan.js +43 -0
- package/dist/core/asyncapi/baseline/plan.js.map +1 -0
- package/dist/core/asyncapi/baseline/surfaces.js +54 -0
- package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
- package/dist/core/asyncapi/depth.js +164 -0
- package/dist/core/asyncapi/depth.js.map +1 -0
- package/dist/core/asyncapi/digest.js +146 -0
- package/dist/core/asyncapi/digest.js.map +1 -0
- package/dist/core/asyncapi/merge/components.js +92 -0
- package/dist/core/asyncapi/merge/components.js.map +1 -0
- package/dist/core/asyncapi/merge/error.js +38 -0
- package/dist/core/asyncapi/merge/error.js.map +1 -0
- package/dist/core/asyncapi/merge/markers.js +290 -0
- package/dist/core/asyncapi/merge/markers.js.map +1 -0
- package/dist/core/asyncapi/merge/merge.js +195 -0
- package/dist/core/asyncapi/merge/merge.js.map +1 -0
- package/dist/core/asyncapi/merge/pin.js +83 -0
- package/dist/core/asyncapi/merge/pin.js.map +1 -0
- package/dist/core/asyncapi/model.js +11 -0
- package/dist/core/asyncapi/model.js.map +1 -0
- package/dist/core/asyncapi/producers.js +50 -0
- package/dist/core/asyncapi/producers.js.map +1 -0
- package/dist/core/asyncapi/read.js +263 -0
- package/dist/core/asyncapi/read.js.map +1 -0
- package/dist/core/brief/brief.js +285 -0
- package/dist/core/brief/brief.js.map +1 -0
- package/dist/core/brief/checks.js +385 -0
- package/dist/core/brief/checks.js.map +1 -0
- package/dist/core/brief/landscape.js +273 -0
- package/dist/core/brief/landscape.js.map +1 -0
- package/dist/core/brief/map/extend.js +84 -0
- package/dist/core/brief/map/extend.js.map +1 -0
- package/dist/core/brief/map/owed.js +266 -0
- package/dist/core/brief/map/owed.js.map +1 -0
- package/dist/core/brief/targets.js +304 -0
- package/dist/core/brief/targets.js.map +1 -0
- package/dist/core/brief/unchecked.js +58 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +190 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/direction/direction.js +114 -0
- package/dist/core/c4/direction/direction.js.map +1 -0
- package/dist/core/c4/likec4.js +243 -0
- package/dist/core/c4/likec4.js.map +1 -0
- package/dist/core/c4/locate/unlocated.js +150 -0
- package/dist/core/c4/locate/unlocated.js.map +1 -0
- package/dist/core/c4/parsed/deployment.js +160 -0
- package/dist/core/c4/parsed/deployment.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js +132 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
- package/dist/core/c4/parsed/specification.js +78 -0
- package/dist/core/c4/parsed/specification.js.map +1 -0
- package/dist/core/c4/parsed/values.js +110 -0
- package/dist/core/c4/parsed/values.js.map +1 -0
- package/dist/core/c4/parsed/view-ids.js +113 -0
- package/dist/core/c4/parsed/view-ids.js.map +1 -0
- package/dist/core/c4/prefetch/fleet.js +134 -0
- package/dist/core/c4/prefetch/fleet.js.map +1 -0
- package/dist/core/c4/project/architecture.js +161 -0
- package/dist/core/c4/project/architecture.js.map +1 -0
- package/dist/core/c4/project/batch.js +140 -0
- package/dist/core/c4/project/batch.js.map +1 -0
- package/dist/core/c4/project/documents.js +89 -0
- package/dist/core/c4/project/documents.js.map +1 -0
- package/dist/core/c4/project/load.js +219 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/project/staged.js +277 -0
- package/dist/core/c4/project/staged.js.map +1 -0
- package/dist/core/c4/resolve/attested.js +0 -0
- package/dist/core/c4/resolve/attested.js.map +1 -0
- package/dist/core/c4/resolve/external.js +51 -0
- package/dist/core/c4/resolve/external.js.map +1 -0
- package/dist/core/c4/resolve/service.js +174 -0
- package/dist/core/c4/resolve/service.js.map +1 -0
- package/dist/core/c4/resolve/steps.js +290 -0
- package/dist/core/c4/resolve/steps.js.map +1 -0
- package/dist/core/c4/resolve/systems.js +154 -0
- package/dist/core/c4/resolve/systems.js.map +1 -0
- package/dist/core/c4/root-project/exclude.js +352 -0
- package/dist/core/c4/root-project/exclude.js.map +1 -0
- package/dist/core/c4/seed/fleet-file.js +201 -0
- package/dist/core/c4/seed/fleet-file.js.map +1 -0
- package/dist/core/c4/seed/items.js +91 -0
- package/dist/core/c4/seed/items.js.map +1 -0
- package/dist/core/c4/seed/stamp.js +48 -0
- package/dist/core/c4/seed/stamp.js.map +1 -0
- package/dist/core/c4/seed/template.js +173 -0
- package/dist/core/c4/seed/template.js.map +1 -0
- package/dist/core/c4/service-model/created/models.js +96 -0
- package/dist/core/c4/service-model/created/models.js.map +1 -0
- package/dist/core/c4/service-model/documents.js +47 -0
- package/dist/core/c4/service-model/documents.js.map +1 -0
- package/dist/core/c4/service-model/fleet/extending.js +82 -0
- package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
- package/dist/core/c4/service-model/load.js +165 -0
- package/dist/core/c4/service-model/load.js.map +1 -0
- package/dist/core/c4/service-model/renderer.js +128 -0
- package/dist/core/c4/service-model/renderer.js.map +1 -0
- package/dist/core/c4/service-model/shape.js +106 -0
- package/dist/core/c4/service-model/shape.js.map +1 -0
- package/dist/core/c4/service-model/slice.js +188 -0
- package/dist/core/c4/service-model/slice.js.map +1 -0
- package/dist/core/c4/source-mask.js +369 -0
- package/dist/core/c4/source-mask.js.map +1 -0
- package/dist/core/c4/source-scan.js +308 -0
- package/dist/core/c4/source-scan.js.map +1 -0
- package/dist/core/c4/splice/authored-source.js +167 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -0
- package/dist/core/c4/splice/contract.js +30 -0
- package/dist/core/c4/splice/contract.js.map +1 -0
- package/dist/core/c4/splice/delta-blocks.js +126 -0
- package/dist/core/c4/splice/delta-blocks.js.map +1 -0
- package/dist/core/c4/splice/identity/declared.js +87 -0
- package/dist/core/c4/splice/identity/declared.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +73 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -0
- package/dist/core/c4/splice/identity/existing.js +80 -0
- package/dist/core/c4/splice/identity/existing.js.map +1 -0
- package/dist/core/c4/splice/identity/interior.js +80 -0
- package/dist/core/c4/splice/identity/interior.js.map +1 -0
- package/dist/core/c4/splice/identity/owner.js +50 -0
- package/dist/core/c4/splice/identity/owner.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +337 -0
- package/dist/core/c4/splice/landscape-merge.js.map +1 -0
- package/dist/core/c4/splice/model/merge.js +151 -0
- package/dist/core/c4/splice/model/merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +298 -0
- package/dist/core/c4/splice/placement.js.map +1 -0
- package/dist/core/c4/splice/text/spot.js +131 -0
- package/dist/core/c4/splice/text/spot.js.map +1 -0
- package/dist/core/c4/workspace.js +166 -0
- package/dist/core/c4/workspace.js.map +1 -0
- package/dist/core/capabilities/authoring/notes.js +141 -0
- package/dist/core/capabilities/authoring/notes.js.map +1 -0
- package/dist/core/capabilities/capabilities.js +124 -0
- package/dist/core/capabilities/capabilities.js.map +1 -0
- package/dist/core/capabilities/delta/doc.js +47 -0
- package/dist/core/capabilities/delta/doc.js.map +1 -0
- package/dist/core/capabilities/delta/overlay.js +129 -0
- package/dist/core/capabilities/delta/overlay.js.map +1 -0
- package/dist/core/capabilities/delta/summary.js +57 -0
- package/dist/core/capabilities/delta/summary.js.map +1 -0
- package/dist/core/capabilities/delta/tree.js +43 -0
- package/dist/core/capabilities/delta/tree.js.map +1 -0
- package/dist/core/capabilities/delta/uncovered.js +222 -0
- package/dist/core/capabilities/delta/uncovered.js.map +1 -0
- package/dist/core/capabilities/findings.js +338 -0
- package/dist/core/capabilities/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/findings.js +174 -0
- package/dist/core/capabilities/realizes/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/join.js +123 -0
- package/dist/core/capabilities/realizes/join.js.map +1 -0
- package/dist/core/capabilities/rollup.js +205 -0
- package/dist/core/capabilities/rollup.js.map +1 -0
- package/dist/core/capabilities/tree.js +104 -0
- package/dist/core/capabilities/tree.js.map +1 -0
- package/dist/core/capabilities/usecase-join.js +267 -0
- package/dist/core/capabilities/usecase-join.js.map +1 -0
- package/dist/core/coherence/authoring/scaffold.js +185 -0
- package/dist/core/coherence/authoring/scaffold.js.map +1 -0
- package/dist/core/coherence/authoring/sentinels.js +75 -0
- package/dist/core/coherence/authoring/sentinels.js.map +1 -0
- package/dist/core/coherence/calls/called.js +52 -0
- package/dist/core/coherence/calls/called.js.map +1 -0
- package/dist/core/coherence/coherence.js +332 -0
- package/dist/core/coherence/coherence.js.map +1 -0
- package/dist/core/coherence/consumed/operations.js +70 -0
- package/dist/core/coherence/consumed/operations.js.map +1 -0
- package/dist/core/coherence/consumed/refusal.js +38 -0
- package/dist/core/coherence/consumed/refusal.js.map +1 -0
- package/dist/core/coherence/covers/health.js +85 -0
- package/dist/core/coherence/covers/health.js.map +1 -0
- package/dist/core/coherence/declared.js +295 -0
- package/dist/core/coherence/declared.js.map +1 -0
- package/dist/core/coherence/events/declared.js +191 -0
- package/dist/core/coherence/events/declared.js.map +1 -0
- package/dist/core/coherence/events/events.js +335 -0
- package/dist/core/coherence/events/events.js.map +1 -0
- package/dist/core/coherence/events/grades.js +189 -0
- package/dist/core/coherence/events/grades.js.map +1 -0
- package/dist/core/coherence/events/lookups.js +63 -0
- package/dist/core/coherence/events/lookups.js.map +1 -0
- package/dist/core/coherence/events/produced.js +100 -0
- package/dist/core/coherence/events/produced.js.map +1 -0
- package/dist/core/coherence/living.js +198 -0
- package/dist/core/coherence/living.js.map +1 -0
- package/dist/core/coherence/lookups.js +95 -0
- package/dist/core/coherence/lookups.js.map +1 -0
- package/dist/core/coherence/pending.js +39 -0
- package/dist/core/coherence/pending.js.map +1 -0
- package/dist/core/coherence/retired/archived.js +285 -0
- package/dist/core/coherence/retired/archived.js.map +1 -0
- package/dist/core/coherence/retired/event-pair.js +62 -0
- package/dist/core/coherence/retired/event-pair.js.map +1 -0
- package/dist/core/coherence/retired/merged.js +79 -0
- package/dist/core/coherence/retired/merged.js.map +1 -0
- package/dist/core/coherence/retired/retirement.js +49 -0
- package/dist/core/coherence/retired/retirement.js.map +1 -0
- package/dist/core/coherence/retired/revival/arrivals.js +131 -0
- package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
- package/dist/core/coherence/retired/revival/revived.js +297 -0
- package/dist/core/coherence/retired/revival/revived.js.map +1 -0
- package/dist/core/conflict-markers.js +60 -0
- package/dist/core/conflict-markers.js.map +1 -0
- package/dist/core/consumers/after.js +113 -0
- package/dist/core/consumers/after.js.map +1 -0
- package/dist/core/consumers/consumers.js +296 -0
- package/dist/core/consumers/consumers.js.map +1 -0
- package/dist/core/consumers/current.js +211 -0
- package/dist/core/consumers/current.js.map +1 -0
- package/dist/core/consumers/scan.js +46 -0
- package/dist/core/consumers/scan.js.map +1 -0
- package/dist/core/consumers/state.js +27 -0
- package/dist/core/consumers/state.js.map +1 -0
- package/dist/core/delta/claims.js +73 -0
- package/dist/core/delta/claims.js.map +1 -0
- package/dist/core/delta/delta.js +341 -0
- package/dist/core/delta/delta.js.map +1 -0
- package/dist/core/delta/document.js +177 -0
- package/dist/core/delta/document.js.map +1 -0
- package/dist/core/delta/scope.js +48 -0
- package/dist/core/delta/scope.js.map +1 -0
- package/dist/core/delta/select.js +237 -0
- package/dist/core/delta/select.js.map +1 -0
- package/dist/core/dependencies/dependencies.js +141 -0
- package/dist/core/dependencies/dependencies.js.map +1 -0
- package/dist/core/dependencies/facts.js +165 -0
- package/dist/core/dependencies/facts.js.map +1 -0
- package/dist/core/dependencies/fanin.js +88 -0
- package/dist/core/dependencies/fanin.js.map +1 -0
- package/dist/core/dependencies/graph.js +106 -0
- package/dist/core/dependencies/graph.js.map +1 -0
- package/dist/core/deployment/delta.js +191 -0
- package/dist/core/deployment/delta.js.map +1 -0
- package/dist/core/deployment/objects.js +145 -0
- package/dist/core/deployment/objects.js.map +1 -0
- package/dist/core/diff/base-git.js +230 -0
- package/dist/core/diff/base-git.js.map +1 -0
- package/dist/core/diff/base-state.js +237 -0
- package/dist/core/diff/base-state.js.map +1 -0
- package/dist/core/diff/joins.js +136 -0
- package/dist/core/diff/joins.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +204 -0
- package/dist/core/diff/scope/changed-paths.js.map +1 -0
- package/dist/core/diff/scope/edges.js +82 -0
- package/dist/core/diff/scope/edges.js.map +1 -0
- package/dist/core/diff/semantic.js +312 -0
- package/dist/core/diff/semantic.js.map +1 -0
- package/dist/core/docs.js +37 -85
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +238 -0
- package/dist/core/doctor/agents.js.map +1 -0
- package/dist/core/doctor/config.js +139 -0
- package/dist/core/doctor/config.js.map +1 -0
- package/dist/core/doctor/doctor.js +355 -0
- package/dist/core/doctor/doctor.js.map +1 -0
- package/dist/core/doctor/report.js +13 -0
- package/dist/core/doctor/report.js.map +1 -0
- package/dist/core/doctor/reports/scan.js +242 -0
- package/dist/core/doctor/reports/scan.js.map +1 -0
- package/dist/core/doctor/residue.js +110 -0
- package/dist/core/doctor/residue.js.map +1 -0
- package/dist/core/document/apply.js +224 -0
- package/dist/core/document/apply.js.map +1 -0
- package/dist/core/{frontmatter.js → document/frontmatter.js} +103 -2
- package/dist/core/document/frontmatter.js.map +1 -0
- package/dist/core/document/grammar/directives.js +143 -0
- package/dist/core/document/grammar/directives.js.map +1 -0
- package/dist/core/document/parse.js +286 -0
- package/dist/core/document/parse.js.map +1 -0
- package/dist/core/document/scenarios.js +238 -0
- package/dist/core/document/scenarios.js.map +1 -0
- package/dist/core/document/spec.js +234 -0
- package/dist/core/document/spec.js.map +1 -0
- package/dist/core/{config.js → envelope/config.js} +89 -18
- package/dist/core/envelope/config.js.map +1 -0
- package/dist/core/envelope/json.js +209 -0
- package/dist/core/envelope/json.js.map +1 -0
- package/dist/core/{version.js → envelope/version.js} +3 -3
- package/dist/core/envelope/version.js.map +1 -0
- package/dist/core/explain/families.js +180 -0
- package/dist/core/explain/families.js.map +1 -0
- package/dist/core/explain/fix-tables.js +178 -0
- package/dist/core/explain/fix-tables.js.map +1 -0
- package/dist/core/explain/lookup.js +194 -0
- package/dist/core/explain/lookup.js.map +1 -0
- package/dist/core/explain/refusals.js +49 -0
- package/dist/core/explain/refusals.js.map +1 -0
- package/dist/core/explain/terms/documents.js +227 -0
- package/dist/core/explain/terms/documents.js.map +1 -0
- package/dist/core/explain/terms/done-check.js +144 -0
- package/dist/core/explain/terms/done-check.js.map +1 -0
- package/dist/core/explain/terms/entry.js +14 -0
- package/dist/core/explain/terms/entry.js.map +1 -0
- package/dist/core/explain/terms/stages.js +71 -0
- package/dist/core/explain/terms/stages.js.map +1 -0
- package/dist/core/explain/terms/tasks.js +97 -0
- package/dist/core/explain/terms/tasks.js.map +1 -0
- package/dist/core/explain/terms.js +103 -0
- package/dist/core/explain/terms.js.map +1 -0
- package/dist/core/explore/describe.js +105 -0
- package/dist/core/explore/describe.js.map +1 -0
- package/dist/core/explore/explore.js +204 -0
- package/dist/core/explore/explore.js.map +1 -0
- package/dist/core/fleet-context.js +174 -146
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +208 -0
- package/dist/core/gate/checks.js.map +1 -0
- package/dist/core/gate/partners.js +246 -0
- package/dist/core/gate/partners.js.map +1 -0
- package/dist/core/gate/report.js +47 -0
- package/dist/core/gate/report.js.map +1 -0
- package/dist/core/gate/verification.js +176 -0
- package/dist/core/gate/verification.js.map +1 -0
- package/dist/core/gherkin/digest.js +60 -0
- package/dist/core/gherkin/digest.js.map +1 -0
- package/dist/core/gherkin/emit.js +177 -0
- package/dist/core/gherkin/emit.js.map +1 -0
- package/dist/core/gherkin/read.js +76 -0
- package/dist/core/gherkin/read.js.map +1 -0
- package/dist/core/gherkin/stale.js +210 -0
- package/dist/core/gherkin/stale.js.map +1 -0
- package/dist/core/gherkin/stamp.js +77 -0
- package/dist/core/gherkin/stamp.js.map +1 -0
- package/dist/core/gherkin/steps/catalogue.js +154 -0
- package/dist/core/gherkin/steps/catalogue.js.map +1 -0
- package/dist/core/gherkin/steps/inventory.js +98 -0
- package/dist/core/gherkin/steps/inventory.js.map +1 -0
- package/dist/core/gherkin/steps/phrase.js +72 -0
- package/dist/core/gherkin/steps/phrase.js.map +1 -0
- package/dist/core/glossary/delta.js +109 -0
- package/dist/core/glossary/delta.js.map +1 -0
- package/dist/core/glossary/tree.js +73 -0
- package/dist/core/glossary/tree.js.map +1 -0
- package/dist/core/{concurrency.js → kernel/concurrency.js} +19 -0
- package/dist/core/kernel/concurrency.js.map +1 -0
- package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
- package/dist/core/kernel/document-bytes.js.map +1 -0
- package/dist/core/kernel/fences.js +42 -0
- package/dist/core/kernel/fences.js.map +1 -0
- package/dist/core/kernel/ids/capability.js +72 -0
- package/dist/core/kernel/ids/capability.js.map +1 -0
- package/dist/core/kernel/ids/dirs.js +33 -0
- package/dist/core/kernel/ids/dirs.js.map +1 -0
- package/dist/core/kernel/ids/feature.js +75 -0
- package/dist/core/kernel/ids/feature.js.map +1 -0
- package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
- package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
- package/dist/core/kernel/ids/service.js +156 -0
- package/dist/core/kernel/ids/service.js.map +1 -0
- package/dist/core/kernel/ids/subsystem.js +63 -0
- package/dist/core/kernel/ids/subsystem.js.map +1 -0
- package/dist/core/{path-safety.js → kernel/path-safety.js} +56 -4
- package/dist/core/kernel/path-safety.js.map +1 -0
- package/dist/core/{records.js → kernel/records.js} +11 -0
- package/dist/core/kernel/records.js.map +1 -0
- package/dist/core/links/backlinks.js +66 -0
- package/dist/core/links/backlinks.js.map +1 -0
- package/dist/core/links/case.js +74 -0
- package/dist/core/links/case.js.map +1 -0
- package/dist/core/links/corpus.js +118 -0
- package/dist/core/links/corpus.js.map +1 -0
- package/dist/core/links/findings.js +110 -0
- package/dist/core/links/findings.js.map +1 -0
- package/dist/core/links/parse.js +265 -0
- package/dist/core/links/parse.js.map +1 -0
- package/dist/core/mcp/argv.js +212 -0
- package/dist/core/mcp/argv.js.map +1 -0
- package/dist/core/mcp/author-tools.js +73 -0
- package/dist/core/mcp/author-tools.js.map +1 -0
- package/dist/core/mcp/framing.js +46 -0
- package/dist/core/mcp/framing.js.map +1 -0
- package/dist/core/mcp/protocol.js +280 -0
- package/dist/core/mcp/protocol.js.map +1 -0
- package/dist/core/mcp/tools.js +324 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/obligations/obligations.js +106 -0
- package/dist/core/obligations/obligations.js.map +1 -0
- package/dist/core/openapi/baseline/gate.js +207 -0
- package/dist/core/openapi/baseline/gate.js.map +1 -0
- package/dist/core/openapi/baseline/plan.js +142 -0
- package/dist/core/openapi/baseline/plan.js.map +1 -0
- package/dist/core/openapi/baseline/record.js +174 -0
- package/dist/core/openapi/baseline/record.js.map +1 -0
- package/dist/core/openapi/contract-text.js +33 -0
- package/dist/core/openapi/contract-text.js.map +1 -0
- package/dist/core/openapi/contract-tree.js +301 -0
- package/dist/core/openapi/contract-tree.js.map +1 -0
- package/dist/core/openapi/depth.js +136 -0
- package/dist/core/openapi/depth.js.map +1 -0
- package/dist/core/openapi/digest.js +239 -0
- package/dist/core/openapi/digest.js.map +1 -0
- package/dist/core/{openapi.js → openapi/doc.js} +54 -108
- package/dist/core/openapi/doc.js.map +1 -0
- package/dist/core/openapi/merge/components.js +199 -0
- package/dist/core/openapi/merge/components.js.map +1 -0
- package/dist/core/openapi/merge/error.js +16 -0
- package/dist/core/openapi/merge/error.js.map +1 -0
- package/dist/core/openapi/merge/markers.js +204 -0
- package/dist/core/openapi/merge/markers.js.map +1 -0
- package/dist/core/openapi/merge/merge.js +232 -0
- package/dist/core/openapi/merge/merge.js.map +1 -0
- package/dist/core/openapi/merge/pin.js +110 -0
- package/dist/core/openapi/merge/pin.js.map +1 -0
- package/dist/core/openspec/decide/capabilities.js +244 -0
- package/dist/core/openspec/decide/capabilities.js.map +1 -0
- package/dist/core/openspec/decide/dispositions.js +63 -0
- package/dist/core/openspec/decide/dispositions.js.map +1 -0
- package/dist/core/openspec/decide/renames.js +179 -0
- package/dist/core/openspec/decide/renames.js.map +1 -0
- package/dist/core/openspec/decide/verdict.js +84 -0
- package/dist/core/openspec/decide/verdict.js.map +1 -0
- package/dist/core/openspec/inventory.js +220 -0
- package/dist/core/openspec/inventory.js.map +1 -0
- package/dist/core/openspec/model/mapping.js +78 -0
- package/dist/core/openspec/model/mapping.js.map +1 -0
- package/dist/core/openspec/model/model.js +70 -0
- package/dist/core/openspec/model/model.js.map +1 -0
- package/dist/core/openspec/scan/changes.js +241 -0
- package/dist/core/openspec/scan/changes.js.map +1 -0
- package/dist/core/openspec/scan/config.js +191 -0
- package/dist/core/openspec/scan/config.js.map +1 -0
- package/dist/core/openspec/scan/shape.js +304 -0
- package/dist/core/openspec/scan/shape.js.map +1 -0
- package/dist/core/openspec/scan/walk.js +116 -0
- package/dist/core/openspec/scan/walk.js.map +1 -0
- package/dist/core/openspec/scan/workspace.js +71 -0
- package/dist/core/openspec/scan/workspace.js.map +1 -0
- package/dist/core/owners/codeowners.js +141 -0
- package/dist/core/owners/codeowners.js.map +1 -0
- package/dist/core/pack/features.js +120 -0
- package/dist/core/pack/features.js.map +1 -0
- package/dist/core/pack/joins.js +112 -0
- package/dist/core/pack/joins.js.map +1 -0
- package/dist/core/pack/living.js +157 -0
- package/dist/core/pack/living.js.map +1 -0
- package/dist/core/pack/pack.js +120 -0
- package/dist/core/pack/pack.js.map +1 -0
- package/dist/core/permissions/permissions.js +87 -0
- package/dist/core/permissions/permissions.js.map +1 -0
- package/dist/core/projection/api.js +84 -0
- package/dist/core/projection/api.js.map +1 -0
- package/dist/core/projection/arch-slice.js +63 -0
- package/dist/core/projection/arch-slice.js.map +1 -0
- package/dist/core/projection/events.js +34 -0
- package/dist/core/projection/events.js.map +1 -0
- package/dist/core/projection/introduced.js +14 -0
- package/dist/core/projection/introduced.js.map +1 -0
- package/dist/core/provenance/findings.js +244 -0
- package/dist/core/provenance/findings.js.map +1 -0
- package/dist/core/provenance/git.js +201 -0
- package/dist/core/provenance/git.js.map +1 -0
- package/dist/core/provenance/gitq/moves.js +139 -0
- package/dist/core/provenance/gitq/moves.js.map +1 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
- package/dist/core/provenance/sample/scope.js +238 -0
- package/dist/core/provenance/sample/scope.js.map +1 -0
- package/dist/core/provenance/sample/sections.js +61 -0
- package/dist/core/provenance/sample/sections.js.map +1 -0
- package/dist/core/provenance/sources.js +280 -0
- package/dist/core/provenance/sources.js.map +1 -0
- package/dist/core/provenance/stamp.js +220 -0
- package/dist/core/provenance/stamp.js.map +1 -0
- package/dist/core/provenance/walk.js +157 -0
- package/dist/core/provenance/walk.js.map +1 -0
- package/dist/core/repo/authored/paths.js +210 -0
- package/dist/core/repo/authored/paths.js.map +1 -0
- package/dist/core/repo/entries.js +126 -0
- package/dist/core/repo/entries.js.map +1 -0
- package/dist/core/repo/paths.js +322 -0
- package/dist/core/repo/paths.js.map +1 -0
- package/dist/core/repo/repo.js +308 -0
- package/dist/core/repo/repo.js.map +1 -0
- package/dist/core/repo/service-target.js +153 -0
- package/dist/core/repo/service-target.js.map +1 -0
- package/dist/core/repo/state.js +58 -0
- package/dist/core/repo/state.js.map +1 -0
- package/dist/core/repo/tree/find.js +61 -0
- package/dist/core/repo/tree/find.js.map +1 -0
- package/dist/core/repo/tree/fs.js +90 -0
- package/dist/core/repo/tree/fs.js.map +1 -0
- package/dist/core/repo/tree/marker.js +61 -0
- package/dist/core/repo/tree/marker.js.map +1 -0
- package/dist/core/repo/tree/render/body.js +258 -0
- package/dist/core/repo/tree/render/body.js.map +1 -0
- package/dist/core/repo/tree/render/projects.js +182 -0
- package/dist/core/repo/tree/render/projects.js.map +1 -0
- package/dist/core/repo/tree/render/service/header.js +125 -0
- package/dist/core/repo/tree/render/service/header.js.map +1 -0
- package/dist/core/repo/tree/render/service/peers.js +28 -0
- package/dist/core/repo/tree/render/service/peers.js.map +1 -0
- package/dist/core/repo/tree/render/service/view-id.js +67 -0
- package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
- package/dist/core/repo/tree/render/service/views.js +78 -0
- package/dist/core/repo/tree/render/service/views.js.map +1 -0
- package/dist/core/repo/tree/render/stale.js +42 -0
- package/dist/core/repo/tree/render/stale.js.map +1 -0
- package/dist/core/repo/tree/render/text.js +84 -0
- package/dist/core/repo/tree/render/text.js.map +1 -0
- package/dist/core/repo/tree/render/views.js +293 -0
- package/dist/core/repo/tree/render/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +255 -0
- package/dist/core/repo/tree/walk.js.map +1 -0
- package/dist/core/results.js +146 -14
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +239 -0
- package/dist/core/scaffold/landscape.js.map +1 -0
- package/dist/core/scaffold/legacy.js +271 -0
- package/dist/core/scaffold/legacy.js.map +1 -0
- package/dist/core/scaffold/readme.js +84 -0
- package/dist/core/scaffold/readme.js.map +1 -0
- package/dist/core/staging/commit.js +252 -0
- package/dist/core/staging/commit.js.map +1 -0
- package/dist/core/staging/interrupted.js +96 -0
- package/dist/core/staging/interrupted.js.map +1 -0
- package/dist/core/staging/lock.js +268 -0
- package/dist/core/staging/lock.js.map +1 -0
- package/dist/core/staging/recovery/finding.js +35 -0
- package/dist/core/staging/recovery/finding.js.map +1 -0
- package/dist/core/staging/recovery/intent.js +95 -0
- package/dist/core/staging/recovery/intent.js.map +1 -0
- package/dist/core/staging/recovery/recover.js +204 -0
- package/dist/core/staging/recovery/recover.js.map +1 -0
- package/dist/core/staging/recovery/residue.js +62 -0
- package/dist/core/staging/recovery/residue.js.map +1 -0
- package/dist/core/staging/snapshot/manifest.js +188 -0
- package/dist/core/staging/snapshot/manifest.js.map +1 -0
- package/dist/core/staging/snapshot/snapshot.js +196 -0
- package/dist/core/staging/snapshot/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +181 -0
- package/dist/core/staging/txn/forward.js.map +1 -0
- package/dist/core/staging/txn/journal.js +139 -0
- package/dist/core/staging/txn/journal.js.map +1 -0
- package/dist/core/staging/txn/transaction.js +75 -0
- package/dist/core/staging/txn/transaction.js.map +1 -0
- package/dist/core/staging/writes.js +113 -0
- package/dist/core/staging/writes.js.map +1 -0
- package/dist/core/status/actions/execution.js +60 -0
- package/dist/core/status/actions/execution.js.map +1 -0
- package/dist/core/status/contracts.js +126 -0
- package/dist/core/status/contracts.js.map +1 -0
- package/dist/core/status/feature/artifacts.js +196 -0
- package/dist/core/status/feature/artifacts.js.map +1 -0
- package/dist/core/status/feature/feature.js +214 -0
- package/dist/core/status/feature/feature.js.map +1 -0
- package/dist/core/status/feature/next.js +163 -0
- package/dist/core/status/feature/next.js.map +1 -0
- package/dist/core/status/feature/state.js +21 -0
- package/dist/core/status/feature/state.js.map +1 -0
- package/dist/core/status/feature/words.js +96 -0
- package/dist/core/status/feature/words.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +216 -0
- package/dist/core/status/fleet/fleet.js.map +1 -0
- package/dist/core/status/fleet/next.js +302 -0
- package/dist/core/status/fleet/next.js.map +1 -0
- package/dist/core/status/interrupted.js +97 -0
- package/dist/core/status/interrupted.js.map +1 -0
- package/dist/core/status/report.js +31 -0
- package/dist/core/status/report.js.map +1 -0
- package/dist/core/status/scan.js +41 -0
- package/dist/core/status/scan.js.map +1 -0
- package/dist/core/status/verification.js +216 -0
- package/dist/core/status/verification.js.map +1 -0
- package/dist/core/tasks/packet.js +199 -0
- package/dist/core/tasks/packet.js.map +1 -0
- package/dist/core/tasks/record.js +43 -0
- package/dist/core/tasks/record.js.map +1 -0
- package/dist/core/tasks/sources.js +181 -0
- package/dist/core/tasks/sources.js.map +1 -0
- package/dist/core/tasks/stamps.js +76 -0
- package/dist/core/tasks/stamps.js.map +1 -0
- package/dist/core/tasks/unit.js +0 -0
- package/dist/core/tasks/unit.js.map +1 -0
- package/dist/core/usecases/capability.js +166 -0
- package/dist/core/usecases/capability.js.map +1 -0
- package/dist/core/usecases/delta/claims.js +140 -0
- package/dist/core/usecases/delta/claims.js.map +1 -0
- package/dist/core/usecases/delta/flows.js +101 -0
- package/dist/core/usecases/delta/flows.js.map +1 -0
- package/dist/core/usecases/delta/modified.js +315 -0
- package/dist/core/usecases/delta/modified.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +76 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -0
- package/dist/core/usecases/fleet.js +296 -0
- package/dist/core/usecases/fleet.js.map +1 -0
- package/dist/core/usecases/grade/capability-tag.js +93 -0
- package/dist/core/usecases/grade/capability-tag.js.map +1 -0
- package/dist/core/usecases/grade/feature.js +88 -0
- package/dist/core/usecases/grade/feature.js.map +1 -0
- package/dist/core/usecases/grade/requirement-tag.js +94 -0
- package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
- package/dist/core/usecases/grade/steps.js +266 -0
- package/dist/core/usecases/grade/steps.js.map +1 -0
- package/dist/core/usecases/grade/usecases.js +112 -0
- package/dist/core/usecases/grade/usecases.js.map +1 -0
- package/dist/core/usecases/operations.js +123 -0
- package/dist/core/usecases/operations.js.map +1 -0
- package/dist/core/usecases/place.js +44 -0
- package/dist/core/usecases/place.js.map +1 -0
- package/dist/core/usecases/service/exclude.js +119 -0
- package/dist/core/usecases/service/exclude.js.map +1 -0
- package/dist/core/usecases/service/flows.js +164 -0
- package/dist/core/usecases/service/flows.js.map +1 -0
- package/dist/core/usecases/suites/participants.js +83 -0
- package/dist/core/usecases/suites/participants.js.map +1 -0
- package/dist/core/usecases/suites/suites.js +45 -0
- package/dist/core/usecases/suites/suites.js.map +1 -0
- package/dist/core/usecases/touch.js +101 -0
- package/dist/core/usecases/touch.js.map +1 -0
- package/dist/core/verify/answers.js +180 -0
- package/dist/core/verify/answers.js.map +1 -0
- package/dist/core/verify/build.js +170 -0
- package/dist/core/verify/build.js.map +1 -0
- package/dist/core/verify/checklist.js +259 -0
- package/dist/core/verify/checklist.js.map +1 -0
- package/dist/core/verify/claims/identity.js +61 -0
- package/dist/core/verify/claims/identity.js.map +1 -0
- package/dist/core/verify/cross/diff.js +97 -0
- package/dist/core/verify/cross/diff.js.map +1 -0
- package/dist/core/verify/evidence/contract.js +169 -0
- package/dist/core/verify/evidence/contract.js.map +1 -0
- package/dist/core/verify/location.js +67 -0
- package/dist/core/verify/location.js.map +1 -0
- package/dist/core/verify/pins/lint.js +158 -0
- package/dist/core/verify/pins/lint.js.map +1 -0
- package/dist/core/verify/pins/pin.js +95 -0
- package/dist/core/verify/pins/pin.js.map +1 -0
- package/dist/core/verify/read/file.js +224 -0
- package/dist/core/verify/read/file.js.map +1 -0
- package/dist/core/verify/read/shape.js +169 -0
- package/dist/core/verify/read/shape.js.map +1 -0
- package/dist/core/verify/read/union.js +105 -0
- package/dist/core/verify/read/union.js.map +1 -0
- package/dist/core/verify/record.js +165 -0
- package/dist/core/verify/record.js.map +1 -0
- package/dist/core/verify/store/commit.js +99 -0
- package/dist/core/verify/store/commit.js.map +1 -0
- package/dist/core/verify/store/render.js +61 -0
- package/dist/core/verify/store/render.js.map +1 -0
- package/dist/core/vocabulary/health.js +91 -0
- package/dist/core/vocabulary/health.js.map +1 -0
- package/dist/core/vocabulary/issue.js +59 -0
- package/dist/core/vocabulary/issue.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +216 -0
- package/dist/core/vocabulary/maturity.js.map +1 -0
- package/dist/core/vocabulary/report.js +90 -0
- package/dist/core/vocabulary/report.js.map +1 -0
- package/dist/core/vocabulary/steps.js +266 -0
- package/dist/core/vocabulary/steps.js.map +1 -0
- package/dist/core/workspace/discover.js +239 -0
- package/dist/core/workspace/discover.js.map +1 -0
- package/dist/core/workspace/render.js +52 -0
- package/dist/core/workspace/render.js.map +1 -0
- package/examples/README.md +232 -0
- package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
- package/examples/docs/architecture/capabilities.yaml +31 -0
- package/examples/docs/architecture/landscape.likec4 +336 -0
- package/examples/docs/architecture/obligations.yaml +23 -0
- package/examples/docs/architecture/permissions.yaml +50 -0
- package/examples/docs/architecture/services.likec4 +70 -0
- package/examples/docs/architecture/subsystems.likec4 +18 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +74 -0
- package/examples/docs/capabilities/checkout/spec.md +55 -0
- package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
- package/examples/docs/capabilities/order-notifications/spec.md +43 -0
- package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
- package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
- package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +132 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +31 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
- package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
- package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +73 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
- package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
- package/examples/docs/glossary/order.md +15 -0
- package/examples/docs/glossary/payments/authorization.md +14 -0
- package/examples/docs/likec4.config.json +8 -0
- package/examples/docs/loam.json +3 -0
- package/examples/docs/services/checkout-web/model.likec4 +92 -0
- package/examples/docs/services/checkout-web/spec.md +91 -0
- package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
- package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
- package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
- package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
- package/examples/docs/services/order-service/arch.spec.md +134 -0
- package/examples/docs/services/order-service/asyncapi.yaml +109 -0
- package/examples/docs/services/order-service/health.yaml +57 -0
- package/examples/docs/services/order-service/model.likec4 +126 -0
- package/examples/docs/services/order-service/openapi.yaml +257 -0
- package/examples/docs/services/order-service/runbook.md +62 -0
- package/examples/docs/services/order-service/spec.md +134 -0
- package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
- package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
- package/examples/docs/services/payment-service/arch.spec.md +76 -0
- package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
- package/examples/docs/services/payment-service/health.yaml +39 -0
- package/examples/docs/services/payment-service/model.likec4 +68 -0
- package/examples/docs/services/payment-service/openapi.yaml +151 -0
- package/examples/docs/services/payment-service/runbook.md +37 -0
- package/examples/docs/services/payment-service/spec.md +88 -0
- package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
- package/examples/docs/services/platform/identity-service/arch.spec.md +120 -0
- package/examples/docs/services/platform/identity-service/health.yaml +70 -0
- package/examples/docs/services/platform/identity-service/model.likec4 +81 -0
- package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
- package/examples/docs/services/platform/identity-service/runbook.md +95 -0
- package/examples/docs/services/platform/identity-service/spec.md +119 -0
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +200 -0
- package/examples/docs/services/platform/notification-service/health.yaml +40 -0
- package/examples/docs/services/platform/notification-service/model.likec4 +97 -0
- package/examples/docs/services/platform/notification-service/runbook.md +48 -0
- package/examples/docs/services/platform/notification-service/spec.md +112 -0
- package/examples/docs/services/platform/subsystem.yaml +2 -0
- package/examples/fleet.yaml +57 -0
- package/package.json +19 -6
- package/dist/commands/adopt.js +0 -240
- package/dist/commands/adopt.js.map +0 -1
- package/dist/commands/archive.js +0 -1313
- package/dist/commands/archive.js.map +0 -1
- package/dist/commands/delta.js +0 -388
- package/dist/commands/delta.js.map +0 -1
- package/dist/commands/docs-repo-gate.js.map +0 -1
- package/dist/commands/format.js +0 -17
- package/dist/commands/format.js.map +0 -1
- package/dist/commands/gherkin.js +0 -309
- package/dist/commands/gherkin.js.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/list.js +0 -295
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/migrate-openspec.js +0 -950
- package/dist/commands/migrate-openspec.js.map +0 -1
- package/dist/commands/new.js +0 -413
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/rebase.js +0 -356
- package/dist/commands/rebase.js.map +0 -1
- package/dist/commands/show.js +0 -320
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/status.js +0 -262
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/unarchive.js +0 -317
- package/dist/commands/unarchive.js.map +0 -1
- package/dist/commands/validate.js +0 -1773
- package/dist/commands/validate.js.map +0 -1
- package/dist/commands/verify.js +0 -775
- package/dist/commands/verify.js.map +0 -1
- package/dist/commands/vouch.js +0 -421
- package/dist/commands/vouch.js.map +0 -1
- package/dist/core/agent.js +0 -2173
- package/dist/core/agent.js.map +0 -1
- package/dist/core/agents-stamp.js.map +0 -1
- package/dist/core/arch.js +0 -130
- package/dist/core/arch.js.map +0 -1
- package/dist/core/asyncapi.js +0 -253
- package/dist/core/asyncapi.js.map +0 -1
- package/dist/core/brief.js +0 -755
- package/dist/core/brief.js.map +0 -1
- package/dist/core/coherence.js +0 -577
- package/dist/core/coherence.js.map +0 -1
- package/dist/core/concurrency.js.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/delta.js +0 -476
- package/dist/core/delta.js.map +0 -1
- package/dist/core/dependencies.js +0 -356
- package/dist/core/dependencies.js.map +0 -1
- package/dist/core/doctor.js +0 -596
- package/dist/core/doctor.js.map +0 -1
- package/dist/core/document-bytes.js.map +0 -1
- package/dist/core/explore.js +0 -225
- package/dist/core/explore.js.map +0 -1
- package/dist/core/frontmatter.js.map +0 -1
- package/dist/core/gherkin.js +0 -463
- package/dist/core/gherkin.js.map +0 -1
- package/dist/core/health.js +0 -67
- package/dist/core/health.js.map +0 -1
- package/dist/core/ids.js +0 -122
- package/dist/core/ids.js.map +0 -1
- package/dist/core/issue.js +0 -9
- package/dist/core/issue.js.map +0 -1
- package/dist/core/json.js +0 -74
- package/dist/core/json.js.map +0 -1
- package/dist/core/likec4.js +0 -489
- package/dist/core/likec4.js.map +0 -1
- package/dist/core/maturity.js +0 -66
- package/dist/core/maturity.js.map +0 -1
- package/dist/core/openapi-merge.js +0 -552
- package/dist/core/openapi-merge.js.map +0 -1
- package/dist/core/openapi.js.map +0 -1
- package/dist/core/openspec-inventory.js +0 -1440
- package/dist/core/openspec-inventory.js.map +0 -1
- package/dist/core/path-safety.js.map +0 -1
- package/dist/core/provenance.js +0 -787
- package/dist/core/provenance.js.map +0 -1
- package/dist/core/records.js.map +0 -1
- package/dist/core/repo.js +0 -438
- package/dist/core/repo.js.map +0 -1
- package/dist/core/report.js +0 -47
- package/dist/core/report.js.map +0 -1
- package/dist/core/spec.js +0 -505
- package/dist/core/spec.js.map +0 -1
- package/dist/core/staging.js +0 -890
- package/dist/core/staging.js.map +0 -1
- package/dist/core/status.js +0 -1132
- package/dist/core/status.js.map +0 -1
- package/dist/core/steps.js +0 -72
- package/dist/core/steps.js.map +0 -1
- package/dist/core/verify.js +0 -807
- package/dist/core/verify.js.map +0 -1
- package/dist/core/version.js.map +0 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Name resolution over a walked tree — the questions every `loam subsystem`
|
|
3
|
+
* verb asks before it acts: what does this name denote, what sits beneath a
|
|
4
|
+
* subsystem, and which names come close to a miss. One module so `move`,
|
|
5
|
+
* `rm`, `new` and `history` cannot grow four private spellings of "the flat
|
|
6
|
+
* namespace" — the walk already enforces one namespace, and resolution must
|
|
7
|
+
* read it the same way.
|
|
8
|
+
*/
|
|
9
|
+
import { closeIds } from "../../c4/arch.js";
|
|
10
|
+
/**
|
|
11
|
+
* Resolve one name against the flat namespace. Services win a tie on
|
|
12
|
+
* purpose: a tie IS `subsystem.name-collision`, already an error finding,
|
|
13
|
+
* and while it stands the service reading keeps every id-addressed command
|
|
14
|
+
* coherent.
|
|
15
|
+
*/
|
|
16
|
+
export function findInTree(tree, name) {
|
|
17
|
+
const service = tree.services.find((s) => s.id === name);
|
|
18
|
+
if (service !== undefined)
|
|
19
|
+
return { kind: "service", service };
|
|
20
|
+
const subsystem = tree.subsystems.find((s) => s.name === name);
|
|
21
|
+
if (subsystem !== undefined)
|
|
22
|
+
return { kind: "subsystem", subsystem };
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
/** Every name the flat namespace holds — service ids and subsystem names together. */
|
|
26
|
+
export function treeNames(tree) {
|
|
27
|
+
return [...tree.services.map((s) => s.id), ...tree.subsystems.map((s) => s.name)];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The near-miss tail a refusal appends to its "no such name" sentence, over
|
|
31
|
+
* whichever pool the verb resolves against: the close names when there are
|
|
32
|
+
* any, else `otherwise` — the verb's own pointer at what exists, or "" for
|
|
33
|
+
* none. Eight refusals across `subsystem`, `adopt --subsystem` and
|
|
34
|
+
* `list --subsystem` end this way, and each spelled the conditional itself;
|
|
35
|
+
* the lead sentence and the fallback stay theirs, because those are what
|
|
36
|
+
* differ.
|
|
37
|
+
*/
|
|
38
|
+
export function closeNamesHint(name, pool, otherwise) {
|
|
39
|
+
const close = closeIds(name, pool);
|
|
40
|
+
return close.length > 0 ? ` Close names: ${close.join(", ")}.` : otherwise;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Does the subsystem at `subPath` contain `path` — itself, or anywhere beneath
|
|
44
|
+
* it? The move-into-own-subtree refusal. The parameter is the name chain, not
|
|
45
|
+
* a `SubsystemEntry`, because a chain is all this comparison reads — the one
|
|
46
|
+
* caller outside this module (`move`) has a chain it just composed and no
|
|
47
|
+
* entry to hand, and a structural parameter it never reads would force a
|
|
48
|
+
* placeholder there.
|
|
49
|
+
*/
|
|
50
|
+
export function withinSubsystem(subPath, path) {
|
|
51
|
+
return subPath.length <= path.length && subPath.every((name, i) => path[i] === name);
|
|
52
|
+
}
|
|
53
|
+
/** Services anywhere beneath a subsystem — the transitive membership the views and counts share. */
|
|
54
|
+
export function servicesUnder(tree, sub) {
|
|
55
|
+
return tree.services.filter((s) => sub.path.every((name, i) => s.subsystem[i] === name));
|
|
56
|
+
}
|
|
57
|
+
/** Child subsystems anywhere beneath one — `rm`'s other half of "empty". */
|
|
58
|
+
export function subsystemsUnder(tree, sub) {
|
|
59
|
+
return tree.subsystems.filter((c) => c !== sub && withinSubsystem(sub.path, c.path));
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=find.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"find.js","sourceRoot":"","sources":["../../../../src/core/repo/tree/find.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAS5C;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,IAAe,EAAE,IAAY;IACtD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,IAAI,CAAC,CAAC;IACzD,IAAI,OAAO,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;IAC/D,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC/D,IAAI,SAAS,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC;IACrE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,SAAS,CAAC,IAAe;IACvC,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACpF,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,IAAc,EAAE,SAAiB;IAC5E,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACnC,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,iBAAiB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC;AAC7E,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAAC,OAAiB,EAAE,IAAc;IAC/D,OAAO,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC;AACvF,CAAC;AAED,oGAAoG;AACpG,MAAM,UAAU,aAAa,CAAC,IAAe,EAAE,GAAmB;IAChE,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;AAC3F,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,eAAe,CAAC,IAAe,EAAE,GAAmB;IAClE,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,GAAG,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AACvF,CAAC","sourcesContent":["/**\n * Name resolution over a walked tree — the questions every `loam subsystem`\n * verb asks before it acts: what does this name denote, what sits beneath a\n * subsystem, and which names come close to a miss. One module so `move`,\n * `rm`, `new` and `history` cannot grow four private spellings of \"the flat\n * namespace\" — the walk already enforces one namespace, and resolution must\n * read it the same way.\n */\nimport { closeIds } from \"../../c4/arch.js\";\nimport type { FleetTree, SubsystemEntry, WalkedService } from \"./walk.js\";\n\n/** What a name denotes in the tree — a service, a subsystem, or nothing. */\nexport type TreeHit =\n | { kind: \"service\"; service: WalkedService }\n | { kind: \"subsystem\"; subsystem: SubsystemEntry }\n | null;\n\n/**\n * Resolve one name against the flat namespace. Services win a tie on\n * purpose: a tie IS `subsystem.name-collision`, already an error finding,\n * and while it stands the service reading keeps every id-addressed command\n * coherent.\n */\nexport function findInTree(tree: FleetTree, name: string): TreeHit {\n const service = tree.services.find((s) => s.id === name);\n if (service !== undefined) return { kind: \"service\", service };\n const subsystem = tree.subsystems.find((s) => s.name === name);\n if (subsystem !== undefined) return { kind: \"subsystem\", subsystem };\n return null;\n}\n\n/** Every name the flat namespace holds — service ids and subsystem names together. */\nexport function treeNames(tree: FleetTree): string[] {\n return [...tree.services.map((s) => s.id), ...tree.subsystems.map((s) => s.name)];\n}\n\n/**\n * The near-miss tail a refusal appends to its \"no such name\" sentence, over\n * whichever pool the verb resolves against: the close names when there are\n * any, else `otherwise` — the verb's own pointer at what exists, or \"\" for\n * none. Eight refusals across `subsystem`, `adopt --subsystem` and\n * `list --subsystem` end this way, and each spelled the conditional itself;\n * the lead sentence and the fallback stay theirs, because those are what\n * differ.\n */\nexport function closeNamesHint(name: string, pool: string[], otherwise: string): string {\n const close = closeIds(name, pool);\n return close.length > 0 ? ` Close names: ${close.join(\", \")}.` : otherwise;\n}\n\n/**\n * Does the subsystem at `subPath` contain `path` — itself, or anywhere beneath\n * it? The move-into-own-subtree refusal. The parameter is the name chain, not\n * a `SubsystemEntry`, because a chain is all this comparison reads — the one\n * caller outside this module (`move`) has a chain it just composed and no\n * entry to hand, and a structural parameter it never reads would force a\n * placeholder there.\n */\nexport function withinSubsystem(subPath: string[], path: string[]): boolean {\n return subPath.length <= path.length && subPath.every((name, i) => path[i] === name);\n}\n\n/** Services anywhere beneath a subsystem — the transitive membership the views and counts share. */\nexport function servicesUnder(tree: FleetTree, sub: SubsystemEntry): WalkedService[] {\n return tree.services.filter((s) => sub.path.every((name, i) => s.subsystem[i] === name));\n}\n\n/** Child subsystems anywhere beneath one — `rm`'s other half of \"empty\". */\nexport function subsystemsUnder(tree: FleetTree, sub: SubsystemEntry): SubsystemEntry[] {\n return tree.subsystems.filter((c) => c !== sub && withinSubsystem(sub.path, c.path));\n}\n"]}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Directory-entry questions the enumerations share, symlinks followed.
|
|
3
|
+
*
|
|
4
|
+
* Moved here from `repo/repo.ts` when the tree walk arrived: the walk and the
|
|
5
|
+
* feature enumeration must answer "what IS this entry" identically, and the
|
|
6
|
+
* package direction is `repo → repo/tree` (never back — `walk.ts` says why),
|
|
7
|
+
* so the shared spelling lives on this side of the edge.
|
|
8
|
+
*/
|
|
9
|
+
import { existsSync, realpathSync, statSync } from "node:fs";
|
|
10
|
+
import { readdir } from "node:fs/promises";
|
|
11
|
+
import { join } from "node:path";
|
|
12
|
+
/**
|
|
13
|
+
* What a directory entry IS, following a symlink to find out.
|
|
14
|
+
*
|
|
15
|
+
* `readdir(withFileTypes)` does not follow symlinks: for a symlink `Dirent`
|
|
16
|
+
* every `isDirectory()`/`isFile()` is false, whatever it points at. That made a
|
|
17
|
+
* symlinked `services/<id>/` or `features/<id>/` vanish from every enumeration
|
|
18
|
+
* at once — `list`, `validate --all`, the fleet gate — with no diagnostic
|
|
19
|
+
* anywhere, which is the one outcome a shared docs repo cannot survive: the
|
|
20
|
+
* fleet gate reported a service that is not there as fine because it never saw
|
|
21
|
+
* it. Composing a docs repo out of symlinks (a worktree, a submodule, one
|
|
22
|
+
* service's directory shared between two checkouts) is legitimate, so they are
|
|
23
|
+
* FOLLOWED rather than refused. A dangling link stats as nothing and is skipped
|
|
24
|
+
* exactly as an absent directory is — it is not a service, and saying so would
|
|
25
|
+
* mean inventing an entry to hang the complaint on.
|
|
26
|
+
*/
|
|
27
|
+
export function entryIs(dir, e, want) {
|
|
28
|
+
if (!e.isSymbolicLink())
|
|
29
|
+
return want === "dir" ? e.isDirectory() : e.isFile();
|
|
30
|
+
try {
|
|
31
|
+
const s = statSync(join(dir, e.name));
|
|
32
|
+
return want === "dir" ? s.isDirectory() : s.isFile();
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Markdown files sitting directly in `dir`, sorted, as full paths — the ADR
|
|
40
|
+
* corpus, and the only place that rule is spelled. Symlinks are resolved
|
|
41
|
+
* through `entryIs`, which is the whole reason this is shared: `show` once kept
|
|
42
|
+
* a second copy that tested `Dirent.isFile()` itself — always false for a
|
|
43
|
+
* symlink, whatever it points at — so a docs repo composed of symlinks (the
|
|
44
|
+
* layout `entryIs` above exists to support) had `loam list` and `loam show`
|
|
45
|
+
* reporting different ADR counts for the same service. One rule, one answer.
|
|
46
|
+
*
|
|
47
|
+
* The list, not the count, is the primitive: the link check reads these same
|
|
48
|
+
* files, and a corpus that disagreed with the count would grade documents the
|
|
49
|
+
* fleet listing says are not there.
|
|
50
|
+
*/
|
|
51
|
+
export async function markdownFiles(dir) {
|
|
52
|
+
if (!existsSync(dir))
|
|
53
|
+
return [];
|
|
54
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
55
|
+
return entries
|
|
56
|
+
.filter((e) => e.name.endsWith(".md") && entryIs(dir, e, "file"))
|
|
57
|
+
.map((e) => join(dir, e.name))
|
|
58
|
+
.sort();
|
|
59
|
+
}
|
|
60
|
+
/** How many markdown files sit directly in `dir` — the ADR count, over the corpus above. */
|
|
61
|
+
export async function countMarkdown(dir) {
|
|
62
|
+
return (await markdownFiles(dir)).length;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Mark a directory as descended-into; false when it (or another name for it)
|
|
66
|
+
* already was. The symlink-cycle guard every walk that follows links through
|
|
67
|
+
* `entryIs` carries — the service tree (`./walk.ts`), the capability tree, the
|
|
68
|
+
* glossary, the generated-gherkin scan — and for one reason: a followed cycle
|
|
69
|
+
* without a visited set recurses until the stack ends. A path realpath cannot
|
|
70
|
+
* resolve is one whose children cannot be read either, so it is never entered.
|
|
71
|
+
*/
|
|
72
|
+
export function markDescended(dir, visited) {
|
|
73
|
+
let real;
|
|
74
|
+
try {
|
|
75
|
+
real = realpathSync(dir);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
if (visited.has(real))
|
|
81
|
+
return false;
|
|
82
|
+
visited.add(real);
|
|
83
|
+
return true;
|
|
84
|
+
}
|
|
85
|
+
/** Sorted non-dot subdirectory names, links followed — a tree walk's deterministic child order. */
|
|
86
|
+
export async function subdirNames(dir) {
|
|
87
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
88
|
+
return entries.filter((e) => !e.name.startsWith(".") && entryIs(dir, e, "dir")).map((e) => e.name).sort();
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../../../src/core/repo/tree/fs.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,QAAQ,EAAe,MAAM,SAAS,CAAC;AAC1E,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,OAAO,CAAC,GAAW,EAAE,CAAS,EAAE,IAAoB;IAClE,IAAI,CAAC,CAAC,CAAC,cAAc,EAAE;QAAE,OAAO,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC9E,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QACtC,OAAO,IAAI,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW;IAC7C,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,OAAO,OAAO;SACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC;SAChE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;SAC7B,IAAI,EAAE,CAAC;AACZ,CAAC;AAED,4FAA4F;AAC5F,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW;IAC7C,OAAO,CAAC,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC;AAC3C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,OAAoB;IAC7D,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClB,OAAO,IAAI,CAAC;AACd,CAAC;AAED,mGAAmG;AACnG,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,GAAW;IAC3C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5G,CAAC","sourcesContent":["/**\n * Directory-entry questions the enumerations share, symlinks followed.\n *\n * Moved here from `repo/repo.ts` when the tree walk arrived: the walk and the\n * feature enumeration must answer \"what IS this entry\" identically, and the\n * package direction is `repo → repo/tree` (never back — `walk.ts` says why),\n * so the shared spelling lives on this side of the edge.\n */\nimport { existsSync, realpathSync, statSync, type Dirent } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\n/**\n * What a directory entry IS, following a symlink to find out.\n *\n * `readdir(withFileTypes)` does not follow symlinks: for a symlink `Dirent`\n * every `isDirectory()`/`isFile()` is false, whatever it points at. That made a\n * symlinked `services/<id>/` or `features/<id>/` vanish from every enumeration\n * at once — `list`, `validate --all`, the fleet gate — with no diagnostic\n * anywhere, which is the one outcome a shared docs repo cannot survive: the\n * fleet gate reported a service that is not there as fine because it never saw\n * it. Composing a docs repo out of symlinks (a worktree, a submodule, one\n * service's directory shared between two checkouts) is legitimate, so they are\n * FOLLOWED rather than refused. A dangling link stats as nothing and is skipped\n * exactly as an absent directory is — it is not a service, and saying so would\n * mean inventing an entry to hang the complaint on.\n */\nexport function entryIs(dir: string, e: Dirent, want: \"dir\" | \"file\"): boolean {\n if (!e.isSymbolicLink()) return want === \"dir\" ? e.isDirectory() : e.isFile();\n try {\n const s = statSync(join(dir, e.name));\n return want === \"dir\" ? s.isDirectory() : s.isFile();\n } catch {\n return false;\n }\n}\n\n/**\n * Markdown files sitting directly in `dir`, sorted, as full paths — the ADR\n * corpus, and the only place that rule is spelled. Symlinks are resolved\n * through `entryIs`, which is the whole reason this is shared: `show` once kept\n * a second copy that tested `Dirent.isFile()` itself — always false for a\n * symlink, whatever it points at — so a docs repo composed of symlinks (the\n * layout `entryIs` above exists to support) had `loam list` and `loam show`\n * reporting different ADR counts for the same service. One rule, one answer.\n *\n * The list, not the count, is the primitive: the link check reads these same\n * files, and a corpus that disagreed with the count would grade documents the\n * fleet listing says are not there.\n */\nexport async function markdownFiles(dir: string): Promise<string[]> {\n if (!existsSync(dir)) return [];\n const entries = await readdir(dir, { withFileTypes: true });\n return entries\n .filter((e) => e.name.endsWith(\".md\") && entryIs(dir, e, \"file\"))\n .map((e) => join(dir, e.name))\n .sort();\n}\n\n/** How many markdown files sit directly in `dir` — the ADR count, over the corpus above. */\nexport async function countMarkdown(dir: string): Promise<number> {\n return (await markdownFiles(dir)).length;\n}\n\n/**\n * Mark a directory as descended-into; false when it (or another name for it)\n * already was. The symlink-cycle guard every walk that follows links through\n * `entryIs` carries — the service tree (`./walk.ts`), the capability tree, the\n * glossary, the generated-gherkin scan — and for one reason: a followed cycle\n * without a visited set recurses until the stack ends. A path realpath cannot\n * resolve is one whose children cannot be read either, so it is never entered.\n */\nexport function markDescended(dir: string, visited: Set<string>): boolean {\n let real: string;\n try {\n real = realpathSync(dir);\n } catch {\n return false;\n }\n if (visited.has(real)) return false;\n visited.add(real);\n return true;\n}\n\n/** Sorted non-dot subdirectory names, links followed — a tree walk's deterministic child order. */\nexport async function subdirNames(dir: string): Promise<string[]> {\n const entries = await readdir(dir, { withFileTypes: true });\n return entries.filter((e) => !e.name.startsWith(\".\") && entryIs(dir, e, \"dir\")).map((e) => e.name).sort();\n}\n"]}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The subsystem marker: `subsystem.yaml`, the one file that makes a directory
|
|
3
|
+
* under `services/` a GROUP rather than a service.
|
|
4
|
+
*
|
|
5
|
+
* Presence classifies; content is metadata. The walk decides what a directory
|
|
6
|
+
* IS from the marker's existence alone, so a marker that cannot be read still
|
|
7
|
+
* classifies its directory as a subsystem — anything else would let a corrupt
|
|
8
|
+
* byte reinterpret a whole subtree as a service and swallow the fleet beneath
|
|
9
|
+
* it, the exact silent-shrink the three-way classification exists to refuse.
|
|
10
|
+
* An unreadable marker is reported as exactly one `subsystem.invalid` finding
|
|
11
|
+
* instead (`walk.ts` emits it from the `invalid` field here).
|
|
12
|
+
*
|
|
13
|
+
* The defensive-read shape is `core/permissions/permissions.ts`'s: every wrong
|
|
14
|
+
* shape is an `invalid` sentence naming what is wrong, never a throw — this is
|
|
15
|
+
* a read model, and a marker somebody hand-edited badly must not take down the
|
|
16
|
+
* enumeration that would report it.
|
|
17
|
+
*/
|
|
18
|
+
import { readFile } from "node:fs/promises";
|
|
19
|
+
import { parse as parseYaml } from "yaml";
|
|
20
|
+
import { isRecord } from "../../kernel/records.js";
|
|
21
|
+
/** The marker's filename — spelled here and nowhere else. */
|
|
22
|
+
export const SUBSYSTEM_MARKER = "subsystem.yaml";
|
|
23
|
+
/**
|
|
24
|
+
* Read one marker. An EMPTY file is a valid marker with no metadata — the
|
|
25
|
+
* marker's job is done by existing, and `title`/`description`/`owner` are all
|
|
26
|
+
* optional. A `members` key is invalid on purpose: placement is recorded
|
|
27
|
+
* exactly once, in the directory itself, and a membership list would be a
|
|
28
|
+
* second copy that merges, drifts and lies (SCHEMA.md's marker-not-manifest
|
|
29
|
+
* rule).
|
|
30
|
+
*/
|
|
31
|
+
export async function readSubsystemMarker(path) {
|
|
32
|
+
let doc;
|
|
33
|
+
try {
|
|
34
|
+
doc = parseYaml(await readFile(path, "utf8"));
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
return { invalid: e instanceof Error ? e.message : String(e) };
|
|
38
|
+
}
|
|
39
|
+
if (doc === null || doc === undefined)
|
|
40
|
+
return {};
|
|
41
|
+
if (!isRecord(doc))
|
|
42
|
+
return { invalid: "the document is not a mapping" };
|
|
43
|
+
if (doc["members"] !== undefined) {
|
|
44
|
+
return {
|
|
45
|
+
invalid: "it declares `members` — a subsystem's members are the service directories inside it, " +
|
|
46
|
+
"recorded exactly once, in the directory itself; a list here would be a second copy that drifts",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
for (const field of ["title", "description", "owner"]) {
|
|
50
|
+
const value = doc[field];
|
|
51
|
+
if (value !== undefined && typeof value !== "string") {
|
|
52
|
+
return { invalid: `\`${field}\` is not a string` };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
...(typeof doc["title"] === "string" ? { title: doc["title"] } : {}),
|
|
57
|
+
...(typeof doc["description"] === "string" ? { description: doc["description"] } : {}),
|
|
58
|
+
...(typeof doc["owner"] === "string" ? { owner: doc["owner"] } : {}),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=marker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"marker.js","sourceRoot":"","sources":["../../../../src/core/repo/tree/marker.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,6DAA6D;AAC7D,MAAM,CAAC,MAAM,gBAAgB,GAAG,gBAAgB,CAAC;AAUjD;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAY;IACpD,IAAI,GAAY,CAAC;IACjB,IAAI,CAAC;QACH,GAAG,GAAG,SAAS,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAChD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,EAAE,OAAO,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACjE,CAAC;IACD,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,EAAE,CAAC;IACjD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,OAAO,EAAE,+BAA+B,EAAE,CAAC;IACxE,IAAI,GAAG,CAAC,SAAS,CAAC,KAAK,SAAS,EAAE,CAAC;QACjC,OAAO;YACL,OAAO,EACL,uFAAuF;gBACvF,gGAAgG;SACnG,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,CAAU,EAAE,CAAC;QAC/D,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;QACzB,IAAI,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,EAAE,OAAO,EAAE,KAAK,KAAK,oBAAoB,EAAE,CAAC;QACrD,CAAC;IACH,CAAC;IACD,OAAO;QACL,GAAG,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,GAAG,CAAC,OAAO,GAAG,CAAC,aAAa,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,GAAG,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrE,CAAC;AACJ,CAAC","sourcesContent":["/**\n * The subsystem marker: `subsystem.yaml`, the one file that makes a directory\n * under `services/` a GROUP rather than a service.\n *\n * Presence classifies; content is metadata. The walk decides what a directory\n * IS from the marker's existence alone, so a marker that cannot be read still\n * classifies its directory as a subsystem — anything else would let a corrupt\n * byte reinterpret a whole subtree as a service and swallow the fleet beneath\n * it, the exact silent-shrink the three-way classification exists to refuse.\n * An unreadable marker is reported as exactly one `subsystem.invalid` finding\n * instead (`walk.ts` emits it from the `invalid` field here).\n *\n * The defensive-read shape is `core/permissions/permissions.ts`'s: every wrong\n * shape is an `invalid` sentence naming what is wrong, never a throw — this is\n * a read model, and a marker somebody hand-edited badly must not take down the\n * enumeration that would report it.\n */\nimport { readFile } from \"node:fs/promises\";\nimport { parse as parseYaml } from \"yaml\";\nimport { isRecord } from \"../../kernel/records.js\";\n\n/** The marker's filename — spelled here and nowhere else. */\nexport const SUBSYSTEM_MARKER = \"subsystem.yaml\";\n\nexport interface SubsystemMeta {\n title?: string;\n description?: string;\n owner?: string;\n /** Why the file could not be read as subsystem metadata, when it could not. */\n invalid?: string;\n}\n\n/**\n * Read one marker. An EMPTY file is a valid marker with no metadata — the\n * marker's job is done by existing, and `title`/`description`/`owner` are all\n * optional. A `members` key is invalid on purpose: placement is recorded\n * exactly once, in the directory itself, and a membership list would be a\n * second copy that merges, drifts and lies (SCHEMA.md's marker-not-manifest\n * rule).\n */\nexport async function readSubsystemMarker(path: string): Promise<SubsystemMeta> {\n let doc: unknown;\n try {\n doc = parseYaml(await readFile(path, \"utf8\"));\n } catch (e) {\n return { invalid: e instanceof Error ? e.message : String(e) };\n }\n if (doc === null || doc === undefined) return {};\n if (!isRecord(doc)) return { invalid: \"the document is not a mapping\" };\n if (doc[\"members\"] !== undefined) {\n return {\n invalid:\n \"it declares `members` — a subsystem's members are the service directories inside it, \" +\n \"recorded exactly once, in the directory itself; a list here would be a second copy that drifts\",\n };\n }\n for (const field of [\"title\", \"description\", \"owner\"] as const) {\n const value = doc[field];\n if (value !== undefined && typeof value !== \"string\") {\n return { invalid: `\\`${field}\\` is not a string` };\n }\n }\n return {\n ...(typeof doc[\"title\"] === \"string\" ? { title: doc[\"title\"] } : {}),\n ...(typeof doc[\"description\"] === \"string\" ? { description: doc[\"description\"] } : {}),\n ...(typeof doc[\"owner\"] === \"string\" ? { owner: doc[\"owner\"] } : {}),\n };\n}\n"]}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What one subsystem's generated view SHOWS: which boxes it draws around the
|
|
3
|
+
* services beneath a directory, and the one thing it may say about the map.
|
|
4
|
+
*
|
|
5
|
+
* Split from `../views.ts` when that file crossed the 400-line limit: the file
|
|
6
|
+
* render (header, view ids, staleness comparison) and the body render (the
|
|
7
|
+
* boxes) are two subjects, and the seam is exactly where the second one
|
|
8
|
+
* consults the LANDSCAPE. Everything here reads element ids and nothing else —
|
|
9
|
+
* no view is ever parsed (docs/DESIGN.md rule 26), and the generated file
|
|
10
|
+
* stays a pure function of the tree plus the committed map.
|
|
11
|
+
*/
|
|
12
|
+
import {} from "../../../c4/likec4.js";
|
|
13
|
+
import { serviceResolver } from "../../../c4/resolve/service.js";
|
|
14
|
+
import { servicesUnder, withinSubsystem } from "../find.js";
|
|
15
|
+
import { subsystemLabel } from "./text.js";
|
|
16
|
+
export function renderContext(tree, elements) {
|
|
17
|
+
const known = new Set(tree.services.map((s) => s.id));
|
|
18
|
+
const resolve = serviceResolver(elements, known);
|
|
19
|
+
return {
|
|
20
|
+
tree,
|
|
21
|
+
elementOf: elementByService(tree, elements, resolve),
|
|
22
|
+
elementIds: new Set(elements.map((e) => e.id)),
|
|
23
|
+
isServiceElement: (id) => known.has(resolve(id)),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Three shapes, and which one applies is a fact about the landscape rather
|
|
28
|
+
* than a setting:
|
|
29
|
+
*
|
|
30
|
+
* 1. **The model draws this group.** Some ancestor element holds exactly this
|
|
31
|
+
* subsystem's members and nothing else, so the view includes it beside the
|
|
32
|
+
* leaves and the renderer nests them inside the box the AUTHOR drew, with
|
|
33
|
+
* the author's own title. Measured: including the ancestor alone renders
|
|
34
|
+
* one empty box and the leaves alone render flat — both lines are needed.
|
|
35
|
+
* 2. **The model is flat.** No member element is nested at all, so there is
|
|
36
|
+
* no authored box to agree with, and the view wraps the members in a
|
|
37
|
+
* `group '<title>'` of its own — a real named box in the renderer, derived
|
|
38
|
+
* from the DIRECTORY the services already sit in, mirroring the subtree so
|
|
39
|
+
* a parent subsystem shows its children as boxes rather than as one pile.
|
|
40
|
+
* Nothing is invented: the grouping is the tree, and the tree is what this
|
|
41
|
+
* file has always mirrored.
|
|
42
|
+
* 3. **The model nests them, differently.** The members ARE nested but no
|
|
43
|
+
* ancestor owns exactly them — the directory tree and the map disagree
|
|
44
|
+
* about this group. loam draws no box (a synthetic one would silently
|
|
45
|
+
* replace the author's boundary with the folder's, and the picture would
|
|
46
|
+
* look the same whether or not the two agree) and writes ONE comment line
|
|
47
|
+
* saying so, outside the view body. That comment is the whole of loam's
|
|
48
|
+
* answer to the drift: it grades nothing, it fails nothing, and it appears
|
|
49
|
+
* in the diff of the very commit that caused it — placement stays a fact
|
|
50
|
+
* nothing branches on.
|
|
51
|
+
*/
|
|
52
|
+
export function viewBody(ctx, sub) {
|
|
53
|
+
const members = memberElements(ctx, sub);
|
|
54
|
+
if (members.length === 0)
|
|
55
|
+
return { lines: [], disclosure: null, of: null };
|
|
56
|
+
if (members.every((id) => !id.includes("."))) {
|
|
57
|
+
return { lines: [...groupedBody(ctx, sub, " "), ...boundaryLines(members)], disclosure: null, of: null };
|
|
58
|
+
}
|
|
59
|
+
const includes = [...ownedAncestors(ctx, sub), ...members].map((id) => ` include ${id}`);
|
|
60
|
+
const lines = [...includes, ...boundaryLines(members)];
|
|
61
|
+
const owner = owningAncestor(ctx, sub);
|
|
62
|
+
if (owner !== null)
|
|
63
|
+
return { lines, disclosure: null, of: owner };
|
|
64
|
+
const shared = sharedAncestor(ctx, members);
|
|
65
|
+
return {
|
|
66
|
+
lines,
|
|
67
|
+
of: null,
|
|
68
|
+
disclosure: shared === null
|
|
69
|
+
? "model: no boundary — these members do not share a containing element."
|
|
70
|
+
: `model: no boundary — ${shared} also holds services outside this subsystem.`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* What this group TOUCHES: for each member, every edge it has in either
|
|
75
|
+
* direction, so the view answers "what does payments talk to" and not only
|
|
76
|
+
* "who is in payments".
|
|
77
|
+
*
|
|
78
|
+
* **The measured trap, and it is why these lines are appended by the caller of
|
|
79
|
+
* `groupedBody` rather than inside it:** placed INSIDE the `group { }` block of
|
|
80
|
+
* the flat-map body shape, this exact predicate parses and validates with ZERO
|
|
81
|
+
* errors and draws a false picture. Measured at likec4 1.59.2 on a flat map of
|
|
82
|
+
* `alpha, beta` grouped and `outsider, store` outside it: at view level the two
|
|
83
|
+
* neighbours are drawn with no parent, correctly outside the box; moved inside
|
|
84
|
+
* the `group { }`, both are drawn as CHILDREN of that group — the diagram then
|
|
85
|
+
* claims `outsider` and `store` are part of the subsystem. A maintainer tidying
|
|
86
|
+
* the body by moving these lines next to the includes they refer to would ship
|
|
87
|
+
* that, and nothing anywhere would report it. They belong at view level, always.
|
|
88
|
+
*
|
|
89
|
+
* The WILDCARD is correct here, and that is not an inconsistency with the
|
|
90
|
+
* per-service views, which measure it as a defect (`./service/peers.ts`): at
|
|
91
|
+
* subsystem altitude a counterpart collapsing to its own group box is exactly
|
|
92
|
+
* the sentence "payments touches identity", and — once those group boxes are
|
|
93
|
+
* themselves views' subjects (`of <ancestor>`) — it is a click-through into
|
|
94
|
+
* that subsystem. At service altitude the same collapse is a lie about who
|
|
95
|
+
* calls whom.
|
|
96
|
+
*
|
|
97
|
+
* MEMBERS only, never `ownedAncestors`: `-> *` on an authored container pulls
|
|
98
|
+
* in every edge any descendant of it has, and in the `// model: no boundary`
|
|
99
|
+
* shape that container also holds services outside this subsystem — the view
|
|
100
|
+
* would draw traffic that is nobody-here's. Measured at 58 services in 11
|
|
101
|
+
* groups: 13-15 nodes and 31-39 edges per subsystem view, of which 11-12 nodes
|
|
102
|
+
* carry drill-down — the members into their own service views, the neighbouring
|
|
103
|
+
* group boxes into THEIR subsystem views.
|
|
104
|
+
*/
|
|
105
|
+
function boundaryLines(members) {
|
|
106
|
+
return ["", ...members.map((id) => ` include ${id} -> *, * -> ${id}`)];
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* The flat-model body: this subsystem as a box, its child subsystems as boxes
|
|
110
|
+
* inside it, its own services as leaves. Recursive, and the recursion is the
|
|
111
|
+
* point — a parent subsystem's view is otherwise one undifferentiated pile of
|
|
112
|
+
* every service beneath it.
|
|
113
|
+
*
|
|
114
|
+
* An empty child renders an empty named box, which is what the tree says: the
|
|
115
|
+
* group exists and holds nothing yet.
|
|
116
|
+
*/
|
|
117
|
+
function groupedBody(ctx, sub, indent) {
|
|
118
|
+
const inner = `${indent} `;
|
|
119
|
+
const out = [`${indent}group '${subsystemLabel(sub)}' {`];
|
|
120
|
+
for (const child of childSubsystems(ctx, sub))
|
|
121
|
+
out.push(...groupedBody(ctx, child, inner));
|
|
122
|
+
for (const id of directMemberElements(ctx, sub))
|
|
123
|
+
out.push(`${inner}include ${id}`);
|
|
124
|
+
out.push(`${indent}}`);
|
|
125
|
+
return out;
|
|
126
|
+
}
|
|
127
|
+
/** The child subsystems one level down, ordered by name. */
|
|
128
|
+
function childSubsystems(ctx, sub) {
|
|
129
|
+
return ctx.tree.subsystems
|
|
130
|
+
.filter((c) => c.path.length === sub.path.length + 1 && withinSubsystem(sub.path, c.path))
|
|
131
|
+
.sort((a, b) => (a.name < b.name ? -1 : 1));
|
|
132
|
+
}
|
|
133
|
+
/** The drawn elements of the services filed in THIS directory, not in a child. */
|
|
134
|
+
function directMemberElements(ctx, sub) {
|
|
135
|
+
return drawnElements(ctx, membersOf(ctx.tree, sub).filter((s) => s.subsystem.length === sub.path.length));
|
|
136
|
+
}
|
|
137
|
+
/** The drawn elements of every service beneath this subsystem, ordered by service id. */
|
|
138
|
+
function memberElements(ctx, sub) {
|
|
139
|
+
return drawnElements(ctx, membersOf(ctx.tree, sub));
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The element ids these services resolve to. A service the map does not draw
|
|
143
|
+
* is omitted rather than invented: the omission is already an error
|
|
144
|
+
* (`landscape.service-unmodelled`), and rendering only what the committed
|
|
145
|
+
* documents resolve keeps the output a function of committed bytes alone.
|
|
146
|
+
*/
|
|
147
|
+
function drawnElements(ctx, services) {
|
|
148
|
+
return services.map((s) => ctx.elementOf.get(s.id)).filter((id) => id !== undefined);
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* The boxes a nested-model view draws: this subsystem's own owning ancestor
|
|
152
|
+
* when it has one, plus the owning ancestor of every subsystem beneath it — so
|
|
153
|
+
* a parent view keeps its children's boundaries instead of flattening them
|
|
154
|
+
* into one box. Sorted and de-duplicated, because two subsystems resolve to
|
|
155
|
+
* one element only in a tree that already reports a collision.
|
|
156
|
+
*/
|
|
157
|
+
function ownedAncestors(ctx, sub) {
|
|
158
|
+
const found = new Set();
|
|
159
|
+
for (const candidate of ctx.tree.subsystems) {
|
|
160
|
+
if (!withinSubsystem(sub.path, candidate.path))
|
|
161
|
+
continue;
|
|
162
|
+
const owner = owningAncestor(ctx, candidate);
|
|
163
|
+
if (owner !== null)
|
|
164
|
+
found.add(owner);
|
|
165
|
+
}
|
|
166
|
+
return [...found].sort();
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* The deepest ancestor element that holds exactly this subsystem's members —
|
|
170
|
+
* or null when no element does.
|
|
171
|
+
*
|
|
172
|
+
* "Exactly" is the whole guard, and dropping it was measured on loam's own
|
|
173
|
+
* `examples/docs`: the members' longest common ancestor there is a group of
|
|
174
|
+
* five services while the subsystem holds two, so an unguarded include would
|
|
175
|
+
* generate a box labelled for the group with two of its five children drawn
|
|
176
|
+
* inside it — a diagram asserting something false, in a file the reader is
|
|
177
|
+
* told not to edit. Tightness is judged over ELEMENTS rather than over
|
|
178
|
+
* documented services: mid-adoption a group commonly holds systems no
|
|
179
|
+
* `services/<id>/` exists for yet, and counting only the documented ones would
|
|
180
|
+
* draw that same false box for the whole of an adoption.
|
|
181
|
+
*
|
|
182
|
+
* An ancestor that is itself a service's element is refused separately: one
|
|
183
|
+
* service's box containing another's is a picture of nothing.
|
|
184
|
+
*/
|
|
185
|
+
function owningAncestor(ctx, sub) {
|
|
186
|
+
const members = memberElements(ctx, sub);
|
|
187
|
+
if (members.length === 0)
|
|
188
|
+
return null;
|
|
189
|
+
const owned = new Set(members);
|
|
190
|
+
for (const candidate of ancestorChain(members)) {
|
|
191
|
+
if (!ctx.elementIds.has(candidate) || ctx.isServiceElement(candidate))
|
|
192
|
+
continue;
|
|
193
|
+
if (ownsExactly(ctx, candidate, owned))
|
|
194
|
+
return candidate;
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
/** The deepest common ancestor the map declares at all — the disclosure's subject. */
|
|
199
|
+
function sharedAncestor(ctx, members) {
|
|
200
|
+
return ancestorChain(members).find((id) => ctx.elementIds.has(id)) ?? null;
|
|
201
|
+
}
|
|
202
|
+
/** The common proper ancestors of every member id, deepest first. */
|
|
203
|
+
function ancestorChain(members) {
|
|
204
|
+
const segments = members.map((id) => id.split("."));
|
|
205
|
+
let common = Math.min(...segments.map((s) => s.length - 1));
|
|
206
|
+
for (let i = 0; i < common; i++) {
|
|
207
|
+
if (!segments.every((s) => s[i] === segments[0][i])) {
|
|
208
|
+
common = i;
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
const out = [];
|
|
213
|
+
for (let depth = common; depth > 0; depth--)
|
|
214
|
+
out.push(segments[0].slice(0, depth).join("."));
|
|
215
|
+
return out;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Does every element beneath `ancestor` belong to this subsystem — as a
|
|
219
|
+
* member, as one of a member's own containers, or as a container of one?
|
|
220
|
+
*/
|
|
221
|
+
function ownsExactly(ctx, ancestor, members) {
|
|
222
|
+
const prefix = `${ancestor}.`;
|
|
223
|
+
for (const id of ctx.elementIds) {
|
|
224
|
+
if (!id.startsWith(prefix))
|
|
225
|
+
continue;
|
|
226
|
+
const claimed = [...members].some((m) => id === m || id.startsWith(`${m}.`) || m.startsWith(`${id}.`));
|
|
227
|
+
if (!claimed)
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
return true;
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* The landscape element standing for each service id: for every element,
|
|
234
|
+
* resolve it through the shared join, and let the SHALLOWEST element win
|
|
235
|
+
* (document order breaking ties). Shallowest, because `serviceResolver`
|
|
236
|
+
* resolves a service's own containers to the service too, and a view should
|
|
237
|
+
* include the service-level box, not whichever nested container happened to be
|
|
238
|
+
* declared first.
|
|
239
|
+
*/
|
|
240
|
+
function elementByService(tree, elements, resolve) {
|
|
241
|
+
const known = new Set(tree.services.map((s) => s.id));
|
|
242
|
+
const depth = (id) => id.split(".").length;
|
|
243
|
+
const out = new Map();
|
|
244
|
+
for (const e of elements) {
|
|
245
|
+
const service = resolve(e.id);
|
|
246
|
+
if (!known.has(service))
|
|
247
|
+
continue;
|
|
248
|
+
const held = out.get(service);
|
|
249
|
+
if (held === undefined || depth(e.id) < depth(held))
|
|
250
|
+
out.set(service, e.id);
|
|
251
|
+
}
|
|
252
|
+
return out;
|
|
253
|
+
}
|
|
254
|
+
/** Services beneath this subsystem at any depth, ordered by id — the transitive membership. */
|
|
255
|
+
function membersOf(tree, sub) {
|
|
256
|
+
return [...servicesUnder(tree, sub)].sort((a, b) => (a.id < b.id ? -1 : 1));
|
|
257
|
+
}
|
|
258
|
+
//# sourceMappingURL=body.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"body.js","sourceRoot":"","sources":["../../../../../src/core/repo/tree/render/body.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What one subsystem's generated view SHOWS: which boxes it draws around the\n * services beneath a directory, and the one thing it may say about the map.\n *\n * Split from `../views.ts` when that file crossed the 400-line limit: the file\n * render (header, view ids, staleness comparison) and the body render (the\n * boxes) are two subjects, and the seam is exactly where the second one\n * consults the LANDSCAPE. Everything here reads element ids and nothing else —\n * no view is ever parsed (docs/DESIGN.md rule 26), and the generated file\n * stays a pure function of the tree plus the committed map.\n */\nimport { type Elem } from \"../../../c4/likec4.js\";\nimport { serviceResolver } from \"../../../c4/resolve/service.js\";\nimport { servicesUnder, withinSubsystem } from \"../find.js\";\nimport type { FleetTree, SubsystemEntry, WalkedService } from \"../walk.js\";\nimport { subsystemLabel } from \"./text.js\";\n\n/**\n * Everything a view's body needs from the landscape, resolved ONCE: the\n * element standing for each service, every element id the map declares, and\n * whether an element is a service's own box. A record rather than four\n * threaded parameters because the body render recurses down the subsystem\n * subtree and would otherwise sit on the parameter limit at every hop\n * (`docs/CODE-STYLE.md`'s own prescription).\n */\nexport interface RenderContext {\n tree: FleetTree;\n elementOf: Map<string, string>;\n elementIds: ReadonlySet<string>;\n isServiceElement: (id: string) => boolean;\n}\n\nexport function renderContext(tree: FleetTree, elements: Elem[]): RenderContext {\n const known: ReadonlySet<string> = new Set(tree.services.map((s) => s.id));\n const resolve = serviceResolver(elements, known);\n return {\n tree,\n elementOf: elementByService(tree, elements, resolve),\n elementIds: new Set(elements.map((e) => e.id)),\n isServiceElement: (id: string): boolean => known.has(resolve(id)),\n };\n}\n\n/** A view's body lines, the one comment the render may write above it, and its subject. */\nexport interface ViewBody {\n lines: string[];\n disclosure: string | null;\n /**\n * The element this view is declared `of`, or null when the map holds none\n * that owns exactly this subsystem. It is computed here rather than by the\n * file render because `owningAncestor` below already decides it — the same\n * answer decides which of the three body shapes applies, and two callers\n * deriving it separately could draw the boundary of one element while\n * declaring the view of another.\n */\n of: string | null;\n}\n\n/**\n * Three shapes, and which one applies is a fact about the landscape rather\n * than a setting:\n *\n * 1. **The model draws this group.** Some ancestor element holds exactly this\n * subsystem's members and nothing else, so the view includes it beside the\n * leaves and the renderer nests them inside the box the AUTHOR drew, with\n * the author's own title. Measured: including the ancestor alone renders\n * one empty box and the leaves alone render flat — both lines are needed.\n * 2. **The model is flat.** No member element is nested at all, so there is\n * no authored box to agree with, and the view wraps the members in a\n * `group '<title>'` of its own — a real named box in the renderer, derived\n * from the DIRECTORY the services already sit in, mirroring the subtree so\n * a parent subsystem shows its children as boxes rather than as one pile.\n * Nothing is invented: the grouping is the tree, and the tree is what this\n * file has always mirrored.\n * 3. **The model nests them, differently.** The members ARE nested but no\n * ancestor owns exactly them — the directory tree and the map disagree\n * about this group. loam draws no box (a synthetic one would silently\n * replace the author's boundary with the folder's, and the picture would\n * look the same whether or not the two agree) and writes ONE comment line\n * saying so, outside the view body. That comment is the whole of loam's\n * answer to the drift: it grades nothing, it fails nothing, and it appears\n * in the diff of the very commit that caused it — placement stays a fact\n * nothing branches on.\n */\nexport function viewBody(ctx: RenderContext, sub: SubsystemEntry): ViewBody {\n const members = memberElements(ctx, sub);\n if (members.length === 0) return { lines: [], disclosure: null, of: null };\n if (members.every((id) => !id.includes(\".\"))) {\n return { lines: [...groupedBody(ctx, sub, \" \"), ...boundaryLines(members)], disclosure: null, of: null };\n }\n const includes = [...ownedAncestors(ctx, sub), ...members].map((id) => ` include ${id}`);\n const lines = [...includes, ...boundaryLines(members)];\n const owner = owningAncestor(ctx, sub);\n if (owner !== null) return { lines, disclosure: null, of: owner };\n const shared = sharedAncestor(ctx, members);\n return {\n lines,\n of: null,\n disclosure:\n shared === null\n ? \"model: no boundary — these members do not share a containing element.\"\n : `model: no boundary — ${shared} also holds services outside this subsystem.`,\n };\n}\n\n/**\n * What this group TOUCHES: for each member, every edge it has in either\n * direction, so the view answers \"what does payments talk to\" and not only\n * \"who is in payments\".\n *\n * **The measured trap, and it is why these lines are appended by the caller of\n * `groupedBody` rather than inside it:** placed INSIDE the `group { }` block of\n * the flat-map body shape, this exact predicate parses and validates with ZERO\n * errors and draws a false picture. Measured at likec4 1.59.2 on a flat map of\n * `alpha, beta` grouped and `outsider, store` outside it: at view level the two\n * neighbours are drawn with no parent, correctly outside the box; moved inside\n * the `group { }`, both are drawn as CHILDREN of that group — the diagram then\n * claims `outsider` and `store` are part of the subsystem. A maintainer tidying\n * the body by moving these lines next to the includes they refer to would ship\n * that, and nothing anywhere would report it. They belong at view level, always.\n *\n * The WILDCARD is correct here, and that is not an inconsistency with the\n * per-service views, which measure it as a defect (`./service/peers.ts`): at\n * subsystem altitude a counterpart collapsing to its own group box is exactly\n * the sentence \"payments touches identity\", and — once those group boxes are\n * themselves views' subjects (`of <ancestor>`) — it is a click-through into\n * that subsystem. At service altitude the same collapse is a lie about who\n * calls whom.\n *\n * MEMBERS only, never `ownedAncestors`: `-> *` on an authored container pulls\n * in every edge any descendant of it has, and in the `// model: no boundary`\n * shape that container also holds services outside this subsystem — the view\n * would draw traffic that is nobody-here's. Measured at 58 services in 11\n * groups: 13-15 nodes and 31-39 edges per subsystem view, of which 11-12 nodes\n * carry drill-down — the members into their own service views, the neighbouring\n * group boxes into THEIR subsystem views.\n */\nfunction boundaryLines(members: readonly string[]): string[] {\n return [\"\", ...members.map((id) => ` include ${id} -> *, * -> ${id}`)];\n}\n\n/**\n * The flat-model body: this subsystem as a box, its child subsystems as boxes\n * inside it, its own services as leaves. Recursive, and the recursion is the\n * point — a parent subsystem's view is otherwise one undifferentiated pile of\n * every service beneath it.\n *\n * An empty child renders an empty named box, which is what the tree says: the\n * group exists and holds nothing yet.\n */\nfunction groupedBody(ctx: RenderContext, sub: SubsystemEntry, indent: string): string[] {\n const inner = `${indent} `;\n const out = [`${indent}group '${subsystemLabel(sub)}' {`];\n for (const child of childSubsystems(ctx, sub)) out.push(...groupedBody(ctx, child, inner));\n for (const id of directMemberElements(ctx, sub)) out.push(`${inner}include ${id}`);\n out.push(`${indent}}`);\n return out;\n}\n\n/** The child subsystems one level down, ordered by name. */\nfunction childSubsystems(ctx: RenderContext, sub: SubsystemEntry): SubsystemEntry[] {\n return ctx.tree.subsystems\n .filter((c) => c.path.length === sub.path.length + 1 && withinSubsystem(sub.path, c.path))\n .sort((a, b) => (a.name < b.name ? -1 : 1));\n}\n\n/** The drawn elements of the services filed in THIS directory, not in a child. */\nfunction directMemberElements(ctx: RenderContext, sub: SubsystemEntry): string[] {\n return drawnElements(\n ctx,\n membersOf(ctx.tree, sub).filter((s) => s.subsystem.length === sub.path.length),\n );\n}\n\n/** The drawn elements of every service beneath this subsystem, ordered by service id. */\nfunction memberElements(ctx: RenderContext, sub: SubsystemEntry): string[] {\n return drawnElements(ctx, membersOf(ctx.tree, sub));\n}\n\n/**\n * The element ids these services resolve to. A service the map does not draw\n * is omitted rather than invented: the omission is already an error\n * (`landscape.service-unmodelled`), and rendering only what the committed\n * documents resolve keeps the output a function of committed bytes alone.\n */\nfunction drawnElements(ctx: RenderContext, services: WalkedService[]): string[] {\n return services.map((s) => ctx.elementOf.get(s.id)).filter((id): id is string => id !== undefined);\n}\n\n/**\n * The boxes a nested-model view draws: this subsystem's own owning ancestor\n * when it has one, plus the owning ancestor of every subsystem beneath it — so\n * a parent view keeps its children's boundaries instead of flattening them\n * into one box. Sorted and de-duplicated, because two subsystems resolve to\n * one element only in a tree that already reports a collision.\n */\nfunction ownedAncestors(ctx: RenderContext, sub: SubsystemEntry): string[] {\n const found = new Set<string>();\n for (const candidate of ctx.tree.subsystems) {\n if (!withinSubsystem(sub.path, candidate.path)) continue;\n const owner = owningAncestor(ctx, candidate);\n if (owner !== null) found.add(owner);\n }\n return [...found].sort();\n}\n\n/**\n * The deepest ancestor element that holds exactly this subsystem's members —\n * or null when no element does.\n *\n * \"Exactly\" is the whole guard, and dropping it was measured on loam's own\n * `examples/docs`: the members' longest common ancestor there is a group of\n * five services while the subsystem holds two, so an unguarded include would\n * generate a box labelled for the group with two of its five children drawn\n * inside it — a diagram asserting something false, in a file the reader is\n * told not to edit. Tightness is judged over ELEMENTS rather than over\n * documented services: mid-adoption a group commonly holds systems no\n * `services/<id>/` exists for yet, and counting only the documented ones would\n * draw that same false box for the whole of an adoption.\n *\n * An ancestor that is itself a service's element is refused separately: one\n * service's box containing another's is a picture of nothing.\n */\nfunction owningAncestor(ctx: RenderContext, sub: SubsystemEntry): string | null {\n const members = memberElements(ctx, sub);\n if (members.length === 0) return null;\n const owned = new Set(members);\n for (const candidate of ancestorChain(members)) {\n if (!ctx.elementIds.has(candidate) || ctx.isServiceElement(candidate)) continue;\n if (ownsExactly(ctx, candidate, owned)) return candidate;\n }\n return null;\n}\n\n/** The deepest common ancestor the map declares at all — the disclosure's subject. */\nfunction sharedAncestor(ctx: RenderContext, members: string[]): string | null {\n return ancestorChain(members).find((id) => ctx.elementIds.has(id)) ?? null;\n}\n\n/** The common proper ancestors of every member id, deepest first. */\nfunction ancestorChain(members: string[]): string[] {\n const segments = members.map((id) => id.split(\".\"));\n let common = Math.min(...segments.map((s) => s.length - 1));\n for (let i = 0; i < common; i++) {\n if (!segments.every((s) => s[i] === segments[0]![i])) {\n common = i;\n break;\n }\n }\n const out: string[] = [];\n for (let depth = common; depth > 0; depth--) out.push(segments[0]!.slice(0, depth).join(\".\"));\n return out;\n}\n\n/**\n * Does every element beneath `ancestor` belong to this subsystem — as a\n * member, as one of a member's own containers, or as a container of one?\n */\nfunction ownsExactly(ctx: RenderContext, ancestor: string, members: ReadonlySet<string>): boolean {\n const prefix = `${ancestor}.`;\n for (const id of ctx.elementIds) {\n if (!id.startsWith(prefix)) continue;\n const claimed = [...members].some((m) => id === m || id.startsWith(`${m}.`) || m.startsWith(`${id}.`));\n if (!claimed) return false;\n }\n return true;\n}\n\n/**\n * The landscape element standing for each service id: for every element,\n * resolve it through the shared join, and let the SHALLOWEST element win\n * (document order breaking ties). Shallowest, because `serviceResolver`\n * resolves a service's own containers to the service too, and a view should\n * include the service-level box, not whichever nested container happened to be\n * declared first.\n */\nfunction elementByService(\n tree: FleetTree,\n elements: Elem[],\n resolve: (id: string) => string,\n): Map<string, string> {\n const known: ReadonlySet<string> = new Set(tree.services.map((s) => s.id));\n const depth = (id: string): number => id.split(\".\").length;\n const out = new Map<string, string>();\n for (const e of elements) {\n const service = resolve(e.id);\n if (!known.has(service)) continue;\n const held = out.get(service);\n if (held === undefined || depth(e.id) < depth(held)) out.set(service, e.id);\n }\n return out;\n}\n\n/** Services beneath this subsystem at any depth, ordered by id — the transitive membership. */\nfunction membersOf(tree: FleetTree, sub: SubsystemEntry): WalkedService[] {\n return [...servicesUnder(tree, sub)].sort((a, b) => (a.id < b.id ? -1 : 1));\n}\n"]}
|