@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,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The problem reports a repository has collected: how many there are, what
|
|
3
|
+
* state each one is in, and which ordinal the next one takes.
|
|
4
|
+
*
|
|
5
|
+
* A sub-package because `doctor/` is at its five-file limit, and a scan of its
|
|
6
|
+
* own because this is the one directory loam reads that loam never writes. The
|
|
7
|
+
* `loam-report` protocol has always asked a repository to accumulate a corpus
|
|
8
|
+
* under `loam-reports/` and then never looked at it — eleven reports landed in
|
|
9
|
+
* this repository in two days, three of them already closed, and every bit of
|
|
10
|
+
* that state lived outside the files, in whoever remembered. The directory is
|
|
11
|
+
* loam's own convention and its contents are loam's own format, so counting
|
|
12
|
+
* them is a fact loam can read as cheaply as it reads `agentFiles`. Reading is
|
|
13
|
+
* the whole of it: nothing here transmits anything, which is the constraint the
|
|
14
|
+
* protocol is built around.
|
|
15
|
+
*
|
|
16
|
+
* Everything below is best-effort on purpose. A report is a hand-written
|
|
17
|
+
* Markdown file, so an absent directory, an unreadable one, a name written
|
|
18
|
+
* before the numbering existed and a file with no `Status:` line are all
|
|
19
|
+
* ordinary states of a healthy repository. None of them is a finding, and
|
|
20
|
+
* `doctor`'s `healthy` does not move for anything in here — a repo with eleven
|
|
21
|
+
* open reports is not broken, it is one that has been paying attention.
|
|
22
|
+
*/
|
|
23
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
24
|
+
import { join } from "node:path";
|
|
25
|
+
import {} from "../report.js";
|
|
26
|
+
/**
|
|
27
|
+
* The conventional NAME of the directory the `loam-report` protocol asks a
|
|
28
|
+
* repository to accumulate, spelled once — the segment `scanReports` joins onto
|
|
29
|
+
* the resolved root to reach it.
|
|
30
|
+
*
|
|
31
|
+
* A name rather than a path, because two readers want different things out of
|
|
32
|
+
* it and both are right: `ProblemReports.dir` carries the joined ABSOLUTE
|
|
33
|
+
* location, because the protocol tells an agent to write there and a relative
|
|
34
|
+
* spelling leaves it guessing which repository "relative" meant (`../report.ts`
|
|
35
|
+
* records that), while `commands/doctor.ts`'s human row prints this constant, so
|
|
36
|
+
* a person standing in the repository reads `loam-reports/` — what the protocol,
|
|
37
|
+
* the reports themselves and every page that mentions them say.
|
|
38
|
+
*/
|
|
39
|
+
export const REPORTS_DIR = "loam-reports";
|
|
40
|
+
/**
|
|
41
|
+
* The leading ordinal of `012-2026-09-03-slug.md`. Three digits or more, so the
|
|
42
|
+
* thousandth report widens the field instead of losing its number.
|
|
43
|
+
*/
|
|
44
|
+
const ORDINAL = /^(\d{3,})-/;
|
|
45
|
+
/**
|
|
46
|
+
* A name written before the numbering existed: `2026-09-03-slug.md`, the shape
|
|
47
|
+
* eleven reports in this repository already carry.
|
|
48
|
+
*
|
|
49
|
+
* Checked FIRST, and this is the whole reason it exists as its own pattern: a
|
|
50
|
+
* four-digit year satisfies `ORDINAL` perfectly, so a legacy name read as an
|
|
51
|
+
* ordinal is report number 2026 — and the next report loam hands out is then
|
|
52
|
+
* 2027, in a directory whose highest real ordinal is 3. A legacy name is still
|
|
53
|
+
* a report; it just has no number, and contributes none.
|
|
54
|
+
*/
|
|
55
|
+
const LEGACY_DATE_NAME = /^\d{4}-\d{2}-\d{2}-/;
|
|
56
|
+
/** The ordinal a report's file name claims, or null when the name predates numbering. */
|
|
57
|
+
function ordinalOf(file) {
|
|
58
|
+
if (LEGACY_DATE_NAME.test(file))
|
|
59
|
+
return null;
|
|
60
|
+
return ORDINAL.exec(file)?.[1] ?? null;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* The template's `- Status:` line, matched in the header FIELD BLOCK alone (see
|
|
64
|
+
* `headerFields`). Only the first word is captured: the vocabulary's two
|
|
65
|
+
* composite values carry prose after it (`fixed in 0.2.0-alpha.5`,
|
|
66
|
+
* `superseded by 010`) that an author writes for a reader, and parsing further
|
|
67
|
+
* would make loam an authority on a sentence it does not own.
|
|
68
|
+
*/
|
|
69
|
+
const STATUS_LINE = /^[ \t]*-[ \t]*Status:[ \t]*(\S+)/m;
|
|
70
|
+
/** A fenced block's delimiter line, either spelling. */
|
|
71
|
+
const FENCE = /^[ \t]*(`{3,}|~{3,})/;
|
|
72
|
+
/**
|
|
73
|
+
* An indented code block's line — the OTHER way markdown quotes code, and the
|
|
74
|
+
* way `loam instructions loam-report` prints its own template (the four-space
|
|
75
|
+
* block in ../../agent/support/report.ts). A fence-only reader counted such a
|
|
76
|
+
* report open off the template's `- Status: open`.
|
|
77
|
+
*/
|
|
78
|
+
const INDENTED = /^(?: {4}|\t)/;
|
|
79
|
+
/** A section heading — the line that ends the header field block. */
|
|
80
|
+
const SECTION = /^##[ \t]/;
|
|
81
|
+
/**
|
|
82
|
+
* The report's header field block: every line above the first `## ` heading,
|
|
83
|
+
* with quoted code — fenced or indented — dropped.
|
|
84
|
+
*
|
|
85
|
+
* Matched anywhere in the file, `- Status:` convicted the wrong reports twice
|
|
86
|
+
* over. A report that QUOTES the protocol template — which several do, because
|
|
87
|
+
* an agent reporting that the protocol is wrong pastes the protocol — carries a
|
|
88
|
+
* `- Status: open` inside a fence and was counted open however its own header
|
|
89
|
+
* read; and a report whose body discusses a status line later on was read the
|
|
90
|
+
* same way. The status a report claims is a header FIELD, written beside
|
|
91
|
+
* `- Classification:` above the first section, so that is the only place it is
|
|
92
|
+
* read from. An unterminated fence swallows the rest of the file rather than
|
|
93
|
+
* flipping back — the safe direction, since the alternative is reading code as
|
|
94
|
+
* a field.
|
|
95
|
+
*
|
|
96
|
+
* Two shapes defeated the first version of that, and both are the same quoting
|
|
97
|
+
* case: a NESTED fence, where the outer ```` opens and the inner ``` was taken
|
|
98
|
+
* for its close, leaving the quoted block read as fields; and an INDENTED
|
|
99
|
+
* block, which the protocol itself uses and whose indented `## Summary` never
|
|
100
|
+
* ends the header either. So a fence is closed only by a run of the same
|
|
101
|
+
* character at least as long as the one that opened it, and an indented block
|
|
102
|
+
* (four spaces after a blank line, through the blank lines inside it) is
|
|
103
|
+
* dropped whole.
|
|
104
|
+
*/
|
|
105
|
+
function headerFields(text) {
|
|
106
|
+
const kept = [];
|
|
107
|
+
let fence = null;
|
|
108
|
+
let indented = false;
|
|
109
|
+
let afterBlank = true;
|
|
110
|
+
for (const line of text.split(/\r?\n/)) {
|
|
111
|
+
if (fence !== null) {
|
|
112
|
+
const close = FENCE.exec(line)?.[1];
|
|
113
|
+
if (close !== undefined && close[0] === fence[0] && close.length >= fence.length)
|
|
114
|
+
fence = null;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
const blank = line.trim() === "";
|
|
118
|
+
if (indented) {
|
|
119
|
+
if (blank || INDENTED.test(line))
|
|
120
|
+
continue;
|
|
121
|
+
indented = false;
|
|
122
|
+
}
|
|
123
|
+
const open = FENCE.exec(line)?.[1];
|
|
124
|
+
if (open !== undefined) {
|
|
125
|
+
fence = open;
|
|
126
|
+
afterBlank = false;
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (afterBlank && INDENTED.test(line)) {
|
|
130
|
+
indented = true;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (SECTION.test(line))
|
|
134
|
+
break;
|
|
135
|
+
kept.push(line);
|
|
136
|
+
afterBlank = blank;
|
|
137
|
+
}
|
|
138
|
+
return kept.join("\n");
|
|
139
|
+
}
|
|
140
|
+
/** The words a `Status:` line may say that loam can count. */
|
|
141
|
+
const STATED = ["open", "sent", "fixed", "superseded"];
|
|
142
|
+
/**
|
|
143
|
+
* The ordinal the next report takes: one past the highest present, never one
|
|
144
|
+
* past the count.
|
|
145
|
+
*
|
|
146
|
+
* Those two differ exactly when the directory has a gap or a legacy name in it
|
|
147
|
+
* — which this directory does, since the numbering arrived after eleven
|
|
148
|
+
* reports had already been written — and counting instead of maximising is how
|
|
149
|
+
* a next ordinal starts handing out numbers that are already taken.
|
|
150
|
+
*/
|
|
151
|
+
function nextOrdinal(entries) {
|
|
152
|
+
let highest = 0;
|
|
153
|
+
for (const entry of entries) {
|
|
154
|
+
if (entry.ordinal === null)
|
|
155
|
+
continue;
|
|
156
|
+
const value = Number.parseInt(entry.ordinal, 10);
|
|
157
|
+
if (value > highest)
|
|
158
|
+
highest = value;
|
|
159
|
+
}
|
|
160
|
+
return String(highest + 1).padStart(3, "0");
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* What one report's own `Status:` line says, or `unstated`.
|
|
164
|
+
*
|
|
165
|
+
* Unreadable reads as unstated rather than throwing: a report saved as UTF-16,
|
|
166
|
+
* a file the process cannot open, or a directory somebody named `notes.md` are
|
|
167
|
+
* all things a diagnostic must survive. `doctor` is the command that has to be
|
|
168
|
+
* able to describe a broken repository without becoming the next thing that
|
|
169
|
+
* breaks in it.
|
|
170
|
+
*/
|
|
171
|
+
async function statusOf(path) {
|
|
172
|
+
let text;
|
|
173
|
+
try {
|
|
174
|
+
text = await readFile(path, "utf8");
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
// Unreadable is not a state the file claims — it is a state of the read.
|
|
178
|
+
return "unstated";
|
|
179
|
+
}
|
|
180
|
+
const word = STATUS_LINE.exec(headerFields(text))?.[1]?.toLowerCase();
|
|
181
|
+
return STATED.find((known) => known === word) ?? "unstated";
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Read `<root>/loam-reports/`, where `root` is the directory holding the
|
|
185
|
+
* `loam.json` that resolved — the repository the reports were written at the
|
|
186
|
+
* root of — falling back, when nothing parsed, to the directory of the
|
|
187
|
+
* `loam.json` loam FOUND (`doctor.ts` says why that and not the cwd), and to the
|
|
188
|
+
* run directory only when there is no config file anywhere above it.
|
|
189
|
+
*
|
|
190
|
+
* Every `*.md` in the directory is an entry, including a hand-written index
|
|
191
|
+
* page: which files in there are "really" reports is a second naming
|
|
192
|
+
* convention, and inventing one would make loam disagree with a directory
|
|
193
|
+
* listing about what the directory holds. An unnumbered entry contributes
|
|
194
|
+
* nothing to `next`, so an index costs the corpus nothing either.
|
|
195
|
+
*/
|
|
196
|
+
export async function scanReports(root) {
|
|
197
|
+
const dir = join(root, REPORTS_DIR);
|
|
198
|
+
let names;
|
|
199
|
+
try {
|
|
200
|
+
names = (await readdir(dir)).filter((name) => name.toLowerCase().endsWith(".md"));
|
|
201
|
+
}
|
|
202
|
+
catch (error) {
|
|
203
|
+
// Absent is the state of every repository that has never had to write a
|
|
204
|
+
// report, and it is the common one — `present: false`, nothing to say. Any
|
|
205
|
+
// other errno means the directory IS there and this process could not list
|
|
206
|
+
// it, which is a different sentence: the corpus exists and loam cannot see
|
|
207
|
+
// into it, so `present` stays true and the counts stay honestly empty.
|
|
208
|
+
const code = error.code;
|
|
209
|
+
const present = code !== "ENOENT" && code !== "ENOTDIR";
|
|
210
|
+
return { dir, present, total: 0, next: "001", entries: [] };
|
|
211
|
+
}
|
|
212
|
+
// Sorted here rather than left in readdir order, which is the filesystem's and
|
|
213
|
+
// differs between one machine and another — and sorted by the ORDINAL the name
|
|
214
|
+
// claims, numerically, because report order is what a reader scanning the list
|
|
215
|
+
// expects and byte order stops being it at exactly the point the widening rule
|
|
216
|
+
// was written for: `1000-…` sorts before `998-…`, so a directory that has
|
|
217
|
+
// passed its thousandth report reads 1000, 1001, 998, 999 (verification
|
|
218
|
+
// 2026-09-04, second pass). Unnumbered names — the shape reports carried before
|
|
219
|
+
// the numbering existed — contribute no ordinal, so they sort last among
|
|
220
|
+
// themselves by name, where a reader looking for "the next one" is not looking.
|
|
221
|
+
const rank = (file) => {
|
|
222
|
+
const ordinal = ordinalOf(file);
|
|
223
|
+
return ordinal === null ? Number.POSITIVE_INFINITY : Number.parseInt(ordinal, 10);
|
|
224
|
+
};
|
|
225
|
+
names.sort((a, b) => rank(a) - rank(b) || (a < b ? -1 : a > b ? 1 : 0));
|
|
226
|
+
// Read together, like `staleAgentFiles` does: a report corpus is a flat
|
|
227
|
+
// directory of small hand-written files, so there is nothing here worth a
|
|
228
|
+
// concurrency cap, and `Promise.all` preserves the order just established.
|
|
229
|
+
const entries = await Promise.all(names.map(async (file) => ({
|
|
230
|
+
file,
|
|
231
|
+
ordinal: ordinalOf(file),
|
|
232
|
+
status: await statusOf(join(dir, file)),
|
|
233
|
+
})));
|
|
234
|
+
return {
|
|
235
|
+
dir,
|
|
236
|
+
present: true,
|
|
237
|
+
total: entries.length,
|
|
238
|
+
next: nextOrdinal(entries),
|
|
239
|
+
entries,
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
//# sourceMappingURL=scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../../../src/core/doctor/reports/scan.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The problem reports a repository has collected: how many there are, what\n * state each one is in, and which ordinal the next one takes.\n *\n * A sub-package because `doctor/` is at its five-file limit, and a scan of its\n * own because this is the one directory loam reads that loam never writes. The\n * `loam-report` protocol has always asked a repository to accumulate a corpus\n * under `loam-reports/` and then never looked at it — eleven reports landed in\n * this repository in two days, three of them already closed, and every bit of\n * that state lived outside the files, in whoever remembered. The directory is\n * loam's own convention and its contents are loam's own format, so counting\n * them is a fact loam can read as cheaply as it reads `agentFiles`. Reading is\n * the whole of it: nothing here transmits anything, which is the constraint the\n * protocol is built around.\n *\n * Everything below is best-effort on purpose. A report is a hand-written\n * Markdown file, so an absent directory, an unreadable one, a name written\n * before the numbering existed and a file with no `Status:` line are all\n * ordinary states of a healthy repository. None of them is a finding, and\n * `doctor`'s `healthy` does not move for anything in here — a repo with eleven\n * open reports is not broken, it is one that has been paying attention.\n */\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport {\n type ProblemReportEntry,\n type ProblemReports,\n type ProblemReportStatus,\n} from \"../report.js\";\n\n/**\n * The conventional NAME of the directory the `loam-report` protocol asks a\n * repository to accumulate, spelled once — the segment `scanReports` joins onto\n * the resolved root to reach it.\n *\n * A name rather than a path, because two readers want different things out of\n * it and both are right: `ProblemReports.dir` carries the joined ABSOLUTE\n * location, because the protocol tells an agent to write there and a relative\n * spelling leaves it guessing which repository \"relative\" meant (`../report.ts`\n * records that), while `commands/doctor.ts`'s human row prints this constant, so\n * a person standing in the repository reads `loam-reports/` — what the protocol,\n * the reports themselves and every page that mentions them say.\n */\nexport const REPORTS_DIR = \"loam-reports\";\n\n/**\n * The leading ordinal of `012-2026-09-03-slug.md`. Three digits or more, so the\n * thousandth report widens the field instead of losing its number.\n */\nconst ORDINAL = /^(\\d{3,})-/;\n\n/**\n * A name written before the numbering existed: `2026-09-03-slug.md`, the shape\n * eleven reports in this repository already carry.\n *\n * Checked FIRST, and this is the whole reason it exists as its own pattern: a\n * four-digit year satisfies `ORDINAL` perfectly, so a legacy name read as an\n * ordinal is report number 2026 — and the next report loam hands out is then\n * 2027, in a directory whose highest real ordinal is 3. A legacy name is still\n * a report; it just has no number, and contributes none.\n */\nconst LEGACY_DATE_NAME = /^\\d{4}-\\d{2}-\\d{2}-/;\n\n/** The ordinal a report's file name claims, or null when the name predates numbering. */\nfunction ordinalOf(file: string): string | null {\n if (LEGACY_DATE_NAME.test(file)) return null;\n return ORDINAL.exec(file)?.[1] ?? null;\n}\n\n/**\n * The template's `- Status:` line, matched in the header FIELD BLOCK alone (see\n * `headerFields`). Only the first word is captured: the vocabulary's two\n * composite values carry prose after it (`fixed in 0.2.0-alpha.5`,\n * `superseded by 010`) that an author writes for a reader, and parsing further\n * would make loam an authority on a sentence it does not own.\n */\nconst STATUS_LINE = /^[ \\t]*-[ \\t]*Status:[ \\t]*(\\S+)/m;\n\n/** A fenced block's delimiter line, either spelling. */\nconst FENCE = /^[ \\t]*(`{3,}|~{3,})/;\n\n/**\n * An indented code block's line — the OTHER way markdown quotes code, and the\n * way `loam instructions loam-report` prints its own template (the four-space\n * block in ../../agent/support/report.ts). A fence-only reader counted such a\n * report open off the template's `- Status: open`.\n */\nconst INDENTED = /^(?: {4}|\\t)/;\n\n/** A section heading — the line that ends the header field block. */\nconst SECTION = /^##[ \\t]/;\n\n/**\n * The report's header field block: every line above the first `## ` heading,\n * with quoted code — fenced or indented — dropped.\n *\n * Matched anywhere in the file, `- Status:` convicted the wrong reports twice\n * over. A report that QUOTES the protocol template — which several do, because\n * an agent reporting that the protocol is wrong pastes the protocol — carries a\n * `- Status: open` inside a fence and was counted open however its own header\n * read; and a report whose body discusses a status line later on was read the\n * same way. The status a report claims is a header FIELD, written beside\n * `- Classification:` above the first section, so that is the only place it is\n * read from. An unterminated fence swallows the rest of the file rather than\n * flipping back — the safe direction, since the alternative is reading code as\n * a field.\n *\n * Two shapes defeated the first version of that, and both are the same quoting\n * case: a NESTED fence, where the outer ```` opens and the inner ``` was taken\n * for its close, leaving the quoted block read as fields; and an INDENTED\n * block, which the protocol itself uses and whose indented `## Summary` never\n * ends the header either. So a fence is closed only by a run of the same\n * character at least as long as the one that opened it, and an indented block\n * (four spaces after a blank line, through the blank lines inside it) is\n * dropped whole.\n */\nfunction headerFields(text: string): string {\n const kept: string[] = [];\n let fence: string | null = null;\n let indented = false;\n let afterBlank = true;\n for (const line of text.split(/\\r?\\n/)) {\n if (fence !== null) {\n const close = FENCE.exec(line)?.[1];\n if (close !== undefined && close[0] === fence[0] && close.length >= fence.length) fence = null;\n continue;\n }\n const blank = line.trim() === \"\";\n if (indented) {\n if (blank || INDENTED.test(line)) continue;\n indented = false;\n }\n const open = FENCE.exec(line)?.[1];\n if (open !== undefined) {\n fence = open;\n afterBlank = false;\n continue;\n }\n if (afterBlank && INDENTED.test(line)) {\n indented = true;\n continue;\n }\n if (SECTION.test(line)) break;\n kept.push(line);\n afterBlank = blank;\n }\n return kept.join(\"\\n\");\n}\n\n/** The words a `Status:` line may say that loam can count. */\nconst STATED: readonly ProblemReportStatus[] = [\"open\", \"sent\", \"fixed\", \"superseded\"];\n\n/**\n * The ordinal the next report takes: one past the highest present, never one\n * past the count.\n *\n * Those two differ exactly when the directory has a gap or a legacy name in it\n * — which this directory does, since the numbering arrived after eleven\n * reports had already been written — and counting instead of maximising is how\n * a next ordinal starts handing out numbers that are already taken.\n */\nfunction nextOrdinal(entries: readonly ProblemReportEntry[]): string {\n let highest = 0;\n for (const entry of entries) {\n if (entry.ordinal === null) continue;\n const value = Number.parseInt(entry.ordinal, 10);\n if (value > highest) highest = value;\n }\n return String(highest + 1).padStart(3, \"0\");\n}\n\n/**\n * What one report's own `Status:` line says, or `unstated`.\n *\n * Unreadable reads as unstated rather than throwing: a report saved as UTF-16,\n * a file the process cannot open, or a directory somebody named `notes.md` are\n * all things a diagnostic must survive. `doctor` is the command that has to be\n * able to describe a broken repository without becoming the next thing that\n * breaks in it.\n */\nasync function statusOf(path: string): Promise<ProblemReportStatus> {\n let text: string;\n try {\n text = await readFile(path, \"utf8\");\n } catch {\n // Unreadable is not a state the file claims — it is a state of the read.\n return \"unstated\";\n }\n const word = STATUS_LINE.exec(headerFields(text))?.[1]?.toLowerCase();\n return STATED.find((known) => known === word) ?? \"unstated\";\n}\n\n/**\n * Read `<root>/loam-reports/`, where `root` is the directory holding the\n * `loam.json` that resolved — the repository the reports were written at the\n * root of — falling back, when nothing parsed, to the directory of the\n * `loam.json` loam FOUND (`doctor.ts` says why that and not the cwd), and to the\n * run directory only when there is no config file anywhere above it.\n *\n * Every `*.md` in the directory is an entry, including a hand-written index\n * page: which files in there are \"really\" reports is a second naming\n * convention, and inventing one would make loam disagree with a directory\n * listing about what the directory holds. An unnumbered entry contributes\n * nothing to `next`, so an index costs the corpus nothing either.\n */\nexport async function scanReports(root: string): Promise<ProblemReports> {\n const dir = join(root, REPORTS_DIR);\n let names: string[];\n try {\n names = (await readdir(dir)).filter((name) => name.toLowerCase().endsWith(\".md\"));\n } catch (error) {\n // Absent is the state of every repository that has never had to write a\n // report, and it is the common one — `present: false`, nothing to say. Any\n // other errno means the directory IS there and this process could not list\n // it, which is a different sentence: the corpus exists and loam cannot see\n // into it, so `present` stays true and the counts stay honestly empty.\n const code = (error as NodeJS.ErrnoException).code;\n const present = code !== \"ENOENT\" && code !== \"ENOTDIR\";\n return { dir, present, total: 0, next: \"001\", entries: [] };\n }\n\n // Sorted here rather than left in readdir order, which is the filesystem's and\n // differs between one machine and another — and sorted by the ORDINAL the name\n // claims, numerically, because report order is what a reader scanning the list\n // expects and byte order stops being it at exactly the point the widening rule\n // was written for: `1000-…` sorts before `998-…`, so a directory that has\n // passed its thousandth report reads 1000, 1001, 998, 999 (verification\n // 2026-09-04, second pass). Unnumbered names — the shape reports carried before\n // the numbering existed — contribute no ordinal, so they sort last among\n // themselves by name, where a reader looking for \"the next one\" is not looking.\n const rank = (file: string): number => {\n const ordinal = ordinalOf(file);\n return ordinal === null ? Number.POSITIVE_INFINITY : Number.parseInt(ordinal, 10);\n };\n names.sort((a, b) => rank(a) - rank(b) || (a < b ? -1 : a > b ? 1 : 0));\n // Read together, like `staleAgentFiles` does: a report corpus is a flat\n // directory of small hand-written files, so there is nothing here worth a\n // concurrency cap, and `Promise.all` preserves the order just established.\n const entries = await Promise.all(names.map(async (file): Promise<ProblemReportEntry> => ({\n file,\n ordinal: ordinalOf(file),\n status: await statusOf(join(dir, file)),\n })));\n\n return {\n dir,\n present: true,\n total: entries.length,\n next: nextOrdinal(entries),\n entries,\n };\n}\n"]}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What an unfinished write means for the health of the repo.
|
|
3
|
+
*
|
|
4
|
+
* `core/staging/recovery/residue.ts` reports what is on disk; this decides how
|
|
5
|
+
* bad it is. A held lock and an interrupted commit are blockers because the docs
|
|
6
|
+
* are, or may be, half-merged: a SIGKILL between two of archive's renames once
|
|
7
|
+
* left `doctor: healthy: true` over a merged spec.md and an unmerged landscape,
|
|
8
|
+
* and the next `loam archive` reported loam's own half-merge as the author's
|
|
9
|
+
* bug. Temp files are the exception — a `.loam-*.tmp` was never linked into
|
|
10
|
+
* place, so nothing reads it. Litter, not damage.
|
|
11
|
+
*/
|
|
12
|
+
import { join } from "node:path";
|
|
13
|
+
import {} from "../staging/recovery/residue.js";
|
|
14
|
+
import {} from "./report.js";
|
|
15
|
+
export function gradeWritePathResidue(docsDir, residue, findings) {
|
|
16
|
+
if (residue.lock !== null) {
|
|
17
|
+
const lockFile = join(docsDir, residue.lock.path);
|
|
18
|
+
// Three grades of one file. Held by a live process is a fact about right
|
|
19
|
+
// now — wait and re-run. Held by a dead process is damage: nothing will
|
|
20
|
+
// ever release it. And a lock that cannot NAME a holder — empty bytes from
|
|
21
|
+
// a crash between create and flush, or JSON nothing understands — is the
|
|
22
|
+
// same damage wearing a live lock's face: `breakStaleLock` rightly refuses
|
|
23
|
+
// to guess about it, so "wait" is advice that can never work, while every
|
|
24
|
+
// writer (archive, unarchive, rebase, verify --record) refuses `docs-busy`
|
|
25
|
+
// forever.
|
|
26
|
+
const unbreakable = residue.lock.stale || residue.lock.unreadable;
|
|
27
|
+
findings.push({
|
|
28
|
+
severity: unbreakable ? "blocker" : "warning",
|
|
29
|
+
code: "doctor.docs-locked",
|
|
30
|
+
message: residue.lock.unreadable
|
|
31
|
+
? `${residue.lock.path} exists but cannot be read as a lock record — no process can be identified as its holder, so nothing is ever going to release it, and every writing command refuses with \`docs-busy\` while it is there.`
|
|
32
|
+
: residue.lock.stale
|
|
33
|
+
? `${residue.lock.path} is held by ${residue.lock.holder}, a process that no longer exists on this host — every command that writes through this root will refuse with \`docs-busy\` until it is gone.`
|
|
34
|
+
: `${residue.lock.path} is held by ${residue.lock.holder}; another loam command is writing through this root.`,
|
|
35
|
+
fix: unbreakable
|
|
36
|
+
? `Delete ${lockFile} — ${residue.lock.unreadable ? "it names no holder, so nothing is going to release it" : "its holder is dead, so nothing is going to release it"}. Check \`loam doctor\` again afterwards for an interrupted commit.`
|
|
37
|
+
: "Wait for it to finish and re-run; nothing is read or written while it is held.",
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (residue.intentUnreadable) {
|
|
41
|
+
findings.push({
|
|
42
|
+
severity: "blocker",
|
|
43
|
+
code: "doctor.commit-unreadable",
|
|
44
|
+
message: `${docsDir} holds a .loam-commit that cannot be read — a commit was interrupted and the one record of which files it had already written is unreadable.`,
|
|
45
|
+
fix: "Hand this to a human: compare this root's files against version control before running any loam command that writes here. Every journaled writer refuses with `commit-interrupted` while it is there.",
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
else if (residue.intent !== null && "rerun" in residue.intent) {
|
|
49
|
+
// Version 2 — the smaller journaled transaction (rebase, vouch, new,
|
|
50
|
+
// gherkin, and any writer after them). Its stored `rerun` IS the repair:
|
|
51
|
+
// that command recovers first, rolling the staged bytes forward. The
|
|
52
|
+
// string is journal data, so agent-commands-runnable cannot parse it here;
|
|
53
|
+
// test/staging-txn.test.ts parses every writer's rerun template against
|
|
54
|
+
// the real program instead.
|
|
55
|
+
const i = residue.intent;
|
|
56
|
+
// Both halves of the journal are named, because a version-3 record can be
|
|
57
|
+
// rename-only (`subsystem move` where the views bytes did not change): a
|
|
58
|
+
// blocker that said "0 file(s) may be half-written" and named nothing sent
|
|
59
|
+
// the operator hunting for files while the pending damage was directories.
|
|
60
|
+
const halves = [
|
|
61
|
+
...(i.files.length > 0 ? [`${i.files.length} file(s) may be half-written: ${i.files.map((f) => f.path).join(", ")}`] : []),
|
|
62
|
+
...(i.moves.length > 0
|
|
63
|
+
? [`${i.moves.length} directory move(s) pending: ${i.moves.map((m) => `${m.from} -> ${m.to}`).join(", ")}`]
|
|
64
|
+
: []),
|
|
65
|
+
];
|
|
66
|
+
findings.push({
|
|
67
|
+
severity: "blocker",
|
|
68
|
+
code: "doctor.commit-interrupted",
|
|
69
|
+
message: `A \`${i.rerun}\` was killed mid-commit (${i.host}, pid ${i.pid}, ${i.at}) — `
|
|
70
|
+
+ (halves.length > 0 ? halves.join("; ") : "its journal records no pending file or directory"),
|
|
71
|
+
fix: `Re-run \`${i.rerun}\` — it recovers first, rolling the staged bytes forward, and refuses with \`commit-interrupted\` rather than guessing if a file has been edited since.`,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else if (residue.intent !== null) {
|
|
75
|
+
const i = residue.intent;
|
|
76
|
+
// The command is spelled out per branch rather than interpolated into one
|
|
77
|
+
// sentence: `loam ${i.command} ${i.feature}` reads fine to a person and is
|
|
78
|
+
// opaque to test/agent-commands-runnable.test.ts, which parses the commands
|
|
79
|
+
// loam prints against the real program. Same discipline as spelling `code:`
|
|
80
|
+
// literally — be visible to your own guard.
|
|
81
|
+
const repair = i.command === "archive"
|
|
82
|
+
? `\`loam archive ${i.feature}\` — it recovers first, under the lock, putting the half-written files back from the snapshot`
|
|
83
|
+
: `\`loam unarchive ${i.feature}\` — it recovers first, under the lock, finishing the restore (an interrupted restore is FINISHED, never undone: the merged text it was replacing is written down nowhere)`;
|
|
84
|
+
findings.push({
|
|
85
|
+
severity: "blocker",
|
|
86
|
+
code: "doctor.commit-interrupted",
|
|
87
|
+
message: `A ${i.command === "archive" ? `\`loam archive ${i.feature}\`` : `\`loam unarchive ${i.feature}\``} `
|
|
88
|
+
+ `was killed mid-commit (${i.host}, pid ${i.pid}, ${i.at}) — `
|
|
89
|
+
+ `${i.files.length} file(s) may be half-written: ${i.files.map((f) => f.path).join(", ")}`,
|
|
90
|
+
fix: `Re-run ${repair}, and refuses with \`commit-interrupted\` rather than guessing if a file has been edited since.`,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
// A version-2 journal's recorded temps are NOT litter: they are the only
|
|
94
|
+
// durable copy of the after-bytes its roll-forward recovery renames in.
|
|
95
|
+
// Advising their deletion beside a blocker that says "re-run to recover"
|
|
96
|
+
// converted a one-command repair into a manual VCS restore.
|
|
97
|
+
const journalTemps = new Set(residue.intent !== null && "rerun" in residue.intent
|
|
98
|
+
? residue.intent.files.flatMap((f) => (f.tmp === null ? [] : [f.tmp]))
|
|
99
|
+
: []);
|
|
100
|
+
const litter = residue.temps.filter((t) => !journalTemps.has(t));
|
|
101
|
+
if (litter.length > 0) {
|
|
102
|
+
findings.push({
|
|
103
|
+
severity: "warning",
|
|
104
|
+
code: "doctor.staging-temps",
|
|
105
|
+
message: `${litter.length} orphaned staging file(s) under ${docsDir}: ${litter.join(", ")} — a killed writer's scratch, never linked into place.`,
|
|
106
|
+
fix: "The next journaled writer through this root removes its own; delete any that remain. Nothing reads them, so they cost disk and nothing else.",
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=residue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"residue.js","sourceRoot":"","sources":["../../../src/core/doctor/residue.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * What an unfinished write means for the health of the repo.\n *\n * `core/staging/recovery/residue.ts` reports what is on disk; this decides how\n * bad it is. A held lock and an interrupted commit are blockers because the docs\n * are, or may be, half-merged: a SIGKILL between two of archive's renames once\n * left `doctor: healthy: true` over a merged spec.md and an unmerged landscape,\n * and the next `loam archive` reported loam's own half-merge as the author's\n * bug. Temp files are the exception — a `.loam-*.tmp` was never linked into\n * place, so nothing reads it. Litter, not damage.\n */\nimport { join } from \"node:path\";\nimport { type WritePathResidue } from \"../staging/recovery/residue.js\";\nimport { type DoctorFinding } from \"./report.js\";\n\nexport function gradeWritePathResidue(\n docsDir: string,\n residue: WritePathResidue,\n findings: DoctorFinding[],\n): void {\n if (residue.lock !== null) {\n const lockFile = join(docsDir, residue.lock.path);\n // Three grades of one file. Held by a live process is a fact about right\n // now — wait and re-run. Held by a dead process is damage: nothing will\n // ever release it. And a lock that cannot NAME a holder — empty bytes from\n // a crash between create and flush, or JSON nothing understands — is the\n // same damage wearing a live lock's face: `breakStaleLock` rightly refuses\n // to guess about it, so \"wait\" is advice that can never work, while every\n // writer (archive, unarchive, rebase, verify --record) refuses `docs-busy`\n // forever.\n const unbreakable = residue.lock.stale || residue.lock.unreadable;\n findings.push({\n severity: unbreakable ? \"blocker\" : \"warning\",\n code: \"doctor.docs-locked\",\n message: residue.lock.unreadable\n ? `${residue.lock.path} exists but cannot be read as a lock record — no process can be identified as its holder, so nothing is ever going to release it, and every writing command refuses with \\`docs-busy\\` while it is there.`\n : residue.lock.stale\n ? `${residue.lock.path} is held by ${residue.lock.holder}, a process that no longer exists on this host — every command that writes through this root will refuse with \\`docs-busy\\` until it is gone.`\n : `${residue.lock.path} is held by ${residue.lock.holder}; another loam command is writing through this root.`,\n fix: unbreakable\n ? `Delete ${lockFile} — ${residue.lock.unreadable ? \"it names no holder, so nothing is going to release it\" : \"its holder is dead, so nothing is going to release it\"}. Check \\`loam doctor\\` again afterwards for an interrupted commit.`\n : \"Wait for it to finish and re-run; nothing is read or written while it is held.\",\n });\n }\n\n if (residue.intentUnreadable) {\n findings.push({\n severity: \"blocker\",\n code: \"doctor.commit-unreadable\",\n message: `${docsDir} holds a .loam-commit that cannot be read — a commit was interrupted and the one record of which files it had already written is unreadable.`,\n fix: \"Hand this to a human: compare this root's files against version control before running any loam command that writes here. Every journaled writer refuses with `commit-interrupted` while it is there.\",\n });\n } else if (residue.intent !== null && \"rerun\" in residue.intent) {\n // Version 2 — the smaller journaled transaction (rebase, vouch, new,\n // gherkin, and any writer after them). Its stored `rerun` IS the repair:\n // that command recovers first, rolling the staged bytes forward. The\n // string is journal data, so agent-commands-runnable cannot parse it here;\n // test/staging-txn.test.ts parses every writer's rerun template against\n // the real program instead.\n const i = residue.intent;\n // Both halves of the journal are named, because a version-3 record can be\n // rename-only (`subsystem move` where the views bytes did not change): a\n // blocker that said \"0 file(s) may be half-written\" and named nothing sent\n // the operator hunting for files while the pending damage was directories.\n const halves = [\n ...(i.files.length > 0 ? [`${i.files.length} file(s) may be half-written: ${i.files.map((f) => f.path).join(\", \")}`] : []),\n ...(i.moves.length > 0\n ? [`${i.moves.length} directory move(s) pending: ${i.moves.map((m) => `${m.from} -> ${m.to}`).join(\", \")}`]\n : []),\n ];\n findings.push({\n severity: \"blocker\",\n code: \"doctor.commit-interrupted\",\n message:\n `A \\`${i.rerun}\\` was killed mid-commit (${i.host}, pid ${i.pid}, ${i.at}) — `\n + (halves.length > 0 ? halves.join(\"; \") : \"its journal records no pending file or directory\"),\n fix: `Re-run \\`${i.rerun}\\` — it recovers first, rolling the staged bytes forward, and refuses with \\`commit-interrupted\\` rather than guessing if a file has been edited since.`,\n });\n } else if (residue.intent !== null) {\n const i = residue.intent;\n // The command is spelled out per branch rather than interpolated into one\n // sentence: `loam ${i.command} ${i.feature}` reads fine to a person and is\n // opaque to test/agent-commands-runnable.test.ts, which parses the commands\n // loam prints against the real program. Same discipline as spelling `code:`\n // literally — be visible to your own guard.\n const repair = i.command === \"archive\"\n ? `\\`loam archive ${i.feature}\\` — it recovers first, under the lock, putting the half-written files back from the snapshot`\n : `\\`loam unarchive ${i.feature}\\` — it recovers first, under the lock, finishing the restore (an interrupted restore is FINISHED, never undone: the merged text it was replacing is written down nowhere)`;\n findings.push({\n severity: \"blocker\",\n code: \"doctor.commit-interrupted\",\n message:\n `A ${i.command === \"archive\" ? `\\`loam archive ${i.feature}\\`` : `\\`loam unarchive ${i.feature}\\``} `\n + `was killed mid-commit (${i.host}, pid ${i.pid}, ${i.at}) — `\n + `${i.files.length} file(s) may be half-written: ${i.files.map((f) => f.path).join(\", \")}`,\n fix: `Re-run ${repair}, and refuses with \\`commit-interrupted\\` rather than guessing if a file has been edited since.`,\n });\n }\n\n // A version-2 journal's recorded temps are NOT litter: they are the only\n // durable copy of the after-bytes its roll-forward recovery renames in.\n // Advising their deletion beside a blocker that says \"re-run to recover\"\n // converted a one-command repair into a manual VCS restore.\n const journalTemps = new Set(\n residue.intent !== null && \"rerun\" in residue.intent\n ? residue.intent.files.flatMap((f) => (f.tmp === null ? [] : [f.tmp]))\n : [],\n );\n const litter = residue.temps.filter((t) => !journalTemps.has(t));\n if (litter.length > 0) {\n findings.push({\n severity: \"warning\",\n code: \"doctor.staging-temps\",\n message: `${litter.length} orphaned staging file(s) under ${docsDir}: ${litter.join(\", \")} — a killed writer's scratch, never linked into place.`,\n fix: \"The next journaled writer through this root removes its own; delete any that remain. Nothing reads them, so they cost disk and nothing else.\",\n });\n }\n}\n"]}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A feature's ADDED/MODIFIED/REMOVED requirements folded onto a living set.
|
|
3
|
+
*
|
|
4
|
+
* The one thing `loam archive` does to a spec, and a module of its own because
|
|
5
|
+
* it is where a requirement stops being a delta: `asLiving` drops the
|
|
6
|
+
* `Based-On:` pin, which is a claim about which living version this was written
|
|
7
|
+
* against — meaningless once it IS the living version, and poison for the next
|
|
8
|
+
* feature's baseline, which would otherwise hash the previous feature's pin.
|
|
9
|
+
*
|
|
10
|
+
* It is also where the merge says what it TAKES AWAY (`replacementsOf`,
|
|
11
|
+
* `droppedParts`), because only the algebra knows which living requirement a
|
|
12
|
+
* delta requirement selects: a MODIFIED carries its full new text and replaces
|
|
13
|
+
* the living requirement whole, so every scenario and every join line it does
|
|
14
|
+
* not restate is gone after the archive — and a second reading of "which one
|
|
15
|
+
* does this select" anywhere else would be a second answer free to disagree.
|
|
16
|
+
*/
|
|
17
|
+
import { requirementIdProblems, splitRealizesPin, withoutBaseline } from "./spec.js";
|
|
18
|
+
/**
|
|
19
|
+
* A delta requirement as it lands in the living document, with the bookkeeping
|
|
20
|
+
* that belongs to the DELTA left behind: the `Based-On:` pin (a claim about
|
|
21
|
+
* which living version this was written against — meaningless once it IS the
|
|
22
|
+
* living version, and poison for the next feature's baseline, which would then
|
|
23
|
+
* hash the previous feature's pin) and the line it was parsed from.
|
|
24
|
+
*/
|
|
25
|
+
function asLiving(d) {
|
|
26
|
+
const { line: _dropped, ...rest } = withoutBaseline(d);
|
|
27
|
+
return { ...rest, kind: "BASE" };
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Apply a feature's ADDED/MODIFIED/REMOVED requirements onto a living requirement set.
|
|
31
|
+
*
|
|
32
|
+
* A living requirement the delta does not touch comes back as the SAME object
|
|
33
|
+
* it went in as (a living spec's requirements are already BASE), and that
|
|
34
|
+
* identity is load-bearing: archive keys each requirement's raw bytes on it, so
|
|
35
|
+
* an untouched requirement is written back exactly as its author wrote it and
|
|
36
|
+
* only the ones this function replaced or added are serialized.
|
|
37
|
+
*/
|
|
38
|
+
export function applyRequirementDelta(living, delta) {
|
|
39
|
+
return foldDelta(living, delta).merged;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Every living requirement the delta replaces or removes, in delta order — the
|
|
43
|
+
* walk `applyRequirementDelta` takes, so the two cannot disagree about which
|
|
44
|
+
* requirement a MODIFIED selected. Throws exactly when the merge would.
|
|
45
|
+
*/
|
|
46
|
+
export function replacementsOf(living, delta) {
|
|
47
|
+
return foldDelta(living, delta).replaced;
|
|
48
|
+
}
|
|
49
|
+
function foldDelta(living, delta) {
|
|
50
|
+
const malformed = [...requirementIdProblems(living), ...requirementIdProblems(delta)];
|
|
51
|
+
if (malformed.length > 0) {
|
|
52
|
+
throw new Error("cannot merge requirements with invalid, repeated, or duplicate Requirement-ID declarations");
|
|
53
|
+
}
|
|
54
|
+
let result = living.map((r) => (r.kind === "BASE" ? r : { ...r, kind: "BASE" }));
|
|
55
|
+
const replaced = [];
|
|
56
|
+
// What each requirement the fold has PRODUCED stands for: the replacement
|
|
57
|
+
// record it belongs to, or null for one this delta added. A delta may select
|
|
58
|
+
// one requirement twice (nothing refuses a repeated heading in a delta), and
|
|
59
|
+
// without this the second step reported the first step's text as "living" —
|
|
60
|
+
// a drop the merge never makes. With it every record stays pre-merge to
|
|
61
|
+
// post-merge, so what `droppedParts` reads is the net change.
|
|
62
|
+
const born = new Map();
|
|
63
|
+
const record = (kind, previous, merged) => {
|
|
64
|
+
const earlier = born.get(previous);
|
|
65
|
+
if (earlier === undefined) {
|
|
66
|
+
const entry = { kind, living: previous, merged };
|
|
67
|
+
replaced.push(entry);
|
|
68
|
+
if (merged !== null)
|
|
69
|
+
born.set(merged, entry);
|
|
70
|
+
}
|
|
71
|
+
else if (earlier === null) {
|
|
72
|
+
// Added by this delta, so nothing living is replaced by rewriting it.
|
|
73
|
+
if (merged !== null)
|
|
74
|
+
born.set(merged, null);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
earlier.merged = merged;
|
|
78
|
+
if (merged === null)
|
|
79
|
+
earlier.kind = "REMOVED";
|
|
80
|
+
else
|
|
81
|
+
born.set(merged, earlier);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
const add = (merged) => {
|
|
85
|
+
born.set(merged, null);
|
|
86
|
+
result.push(merged);
|
|
87
|
+
};
|
|
88
|
+
for (const d of delta) {
|
|
89
|
+
// BASE is not a delta kind — a requirement outside an ADDED/MODIFIED/REMOVED
|
|
90
|
+
// section (e.g. quoted under ## Notes) is documentation, not a change.
|
|
91
|
+
if (d.kind === "BASE")
|
|
92
|
+
continue;
|
|
93
|
+
const kind = d.kind;
|
|
94
|
+
if (d.id !== undefined) {
|
|
95
|
+
const idMatches = result
|
|
96
|
+
.map((r, i) => (r.id === d.id ? i : -1))
|
|
97
|
+
.filter((i) => i >= 0);
|
|
98
|
+
const nameMatches = result
|
|
99
|
+
.map((r, i) => (r.name === d.name ? i : -1))
|
|
100
|
+
.filter((i) => i >= 0);
|
|
101
|
+
const otherNameMatches = nameMatches.filter((i) => !idMatches.includes(i));
|
|
102
|
+
if (idMatches.length > 1 || otherNameMatches.length > 0) {
|
|
103
|
+
throw new Error(`ambiguous requirement identity for '${d.name}' (${d.id}): Requirement-ID and heading select different living requirements`);
|
|
104
|
+
}
|
|
105
|
+
if (d.kind === "REMOVED") {
|
|
106
|
+
const selected = new Set(idMatches);
|
|
107
|
+
for (const i of idMatches)
|
|
108
|
+
record(kind, result[i], null);
|
|
109
|
+
result = result.filter((_, i) => !selected.has(i));
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
const merged = asLiving(d);
|
|
113
|
+
const at = idMatches[0];
|
|
114
|
+
if (at === undefined)
|
|
115
|
+
add(merged);
|
|
116
|
+
else {
|
|
117
|
+
record(kind, result[at], merged);
|
|
118
|
+
result[at] = merged;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else if (d.kind === "REMOVED") {
|
|
123
|
+
for (const r of result)
|
|
124
|
+
if (r.name === d.name)
|
|
125
|
+
record(kind, r, null);
|
|
126
|
+
result = result.filter((r) => r.name !== d.name);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
const i = result.findIndex((r) => r.name === d.name);
|
|
130
|
+
// A legacy delta may still modify an ID-bearing living requirement by
|
|
131
|
+
// its exact heading. Keep the identity while the repository migrates.
|
|
132
|
+
const inheritedId = i >= 0 ? result[i].id : undefined;
|
|
133
|
+
const merged = {
|
|
134
|
+
...asLiving(d),
|
|
135
|
+
...(inheritedId === undefined ? {} : { id: inheritedId }),
|
|
136
|
+
};
|
|
137
|
+
if (i < 0)
|
|
138
|
+
add(merged);
|
|
139
|
+
else {
|
|
140
|
+
record(kind, result[i], merged);
|
|
141
|
+
result[i] = merged;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return { merged: result, replaced };
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The join lines a requirement carries, keyed by `Requirement` field and
|
|
149
|
+
* spelled as the body line writes them — every list the parser reads out of a
|
|
150
|
+
* requirement's text, in one order, so the archive plan, `loam delta` and their
|
|
151
|
+
* `--json` rows name a dropped entry the same way.
|
|
152
|
+
*/
|
|
153
|
+
export const DIRECTIVE_LINES = {
|
|
154
|
+
operations: "Operations",
|
|
155
|
+
covers: "Covers",
|
|
156
|
+
requires: "Requires",
|
|
157
|
+
capabilities: "Capability",
|
|
158
|
+
realizes: "Realizes",
|
|
159
|
+
publishes: "Publishes",
|
|
160
|
+
consumes: "Consumes",
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* What a replacement drops: the living scenarios its new text does not carry,
|
|
164
|
+
* by name, and each join-line entry it does not restate, verbatim.
|
|
165
|
+
*
|
|
166
|
+
* VERBATIM AND BY NAME, and that is a reading, not a judgement — with one
|
|
167
|
+
* exception for bookkeeping: a `Realizes:` entry is compared, and reported, by
|
|
168
|
+
* the target it names, its `@<digest>` pin set aside. A scenario
|
|
169
|
+
* renamed is reported dropped, and a `Covers:` entry respelled from an element
|
|
170
|
+
* id to the service name is reported dropped too, though either may mean the
|
|
171
|
+
* same thing — this lists what the living text says that the merged text does
|
|
172
|
+
* not, and the author decides. What it must never be again is the old answer,
|
|
173
|
+
* which was nothing: a MODIFIED that restated one of two scenarios merged, and
|
|
174
|
+
* the second vanished under the archive's exit 0.
|
|
175
|
+
*/
|
|
176
|
+
export function droppedParts(replacement) {
|
|
177
|
+
const { living, merged } = replacement;
|
|
178
|
+
const keptScenarios = new Set((merged?.scenarios ?? []).map((s) => s.name));
|
|
179
|
+
const directives = {};
|
|
180
|
+
for (const key of Object.keys(DIRECTIVE_LINES)) {
|
|
181
|
+
// A `Realizes:` entry is compared by the target it names: the `@<digest>`
|
|
182
|
+
// pin `loam rebase --living` writes is bookkeeping, and a replacement that
|
|
183
|
+
// restates the target unpinned has kept the join, not dropped it.
|
|
184
|
+
const spell = key === "realizes" ? (entry) => splitRealizesPin(entry).target : (entry) => entry;
|
|
185
|
+
const kept = new Set((merged?.[key] ?? []).map(spell));
|
|
186
|
+
const gone = [...new Set(living[key].map(spell))].filter((entry) => !kept.has(entry));
|
|
187
|
+
if (gone.length > 0)
|
|
188
|
+
directives[key] = gone;
|
|
189
|
+
}
|
|
190
|
+
return { scenarios: living.scenarios.map((s) => s.name).filter((name) => !keptScenarios.has(name)), directives };
|
|
191
|
+
}
|
|
192
|
+
/** Does this replacement take anything away at all? */
|
|
193
|
+
export function dropsAnything(parts) {
|
|
194
|
+
return parts.scenarios.length > 0 || Object.keys(parts.directives).length > 0;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Every replacement that takes something away: a removal always (the
|
|
198
|
+
* requirement itself is what goes), a MODIFIED or a landing ADDED whenever its
|
|
199
|
+
* new text restates less than the living one held.
|
|
200
|
+
*/
|
|
201
|
+
export function droppedBy(living, delta) {
|
|
202
|
+
return replacementsOf(living, delta).flatMap((replacement) => {
|
|
203
|
+
const parts = droppedParts(replacement);
|
|
204
|
+
if (replacement.kind !== "REMOVED" && !dropsAnything(parts))
|
|
205
|
+
return [];
|
|
206
|
+
const { name, id } = replacement.living;
|
|
207
|
+
return [{ kind: replacement.kind, requirement: name, ...(id === undefined ? {} : { id }), ...parts }];
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
/** One dropped row in words — the line the archive plan and `loam delta` both print. */
|
|
211
|
+
export function droppedSentence(row) {
|
|
212
|
+
const who = row.id === undefined ? `'${row.requirement}'` : `${row.id} '${row.requirement}'`;
|
|
213
|
+
const lost = [
|
|
214
|
+
...(row.scenarios.length === 0 ? [] : [`scenario ${row.scenarios.map((s) => `'${s}'`).join(", ")}`]),
|
|
215
|
+
...Object.keys(DIRECTIVE_LINES).flatMap((key) => {
|
|
216
|
+
const gone = row.directives[key];
|
|
217
|
+
return gone === undefined ? [] : [`${DIRECTIVE_LINES[key]}: ${gone.join(", ")}`];
|
|
218
|
+
}),
|
|
219
|
+
];
|
|
220
|
+
if (row.kind === "REMOVED")
|
|
221
|
+
return lost.length === 0 ? `${who} is removed` : `${who} is removed, and with it ${lost.join("; ")}`;
|
|
222
|
+
return `${who} is replaced whole, and its new text does not carry ${lost.join("; ")}`;
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=apply.js.map
|