@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 @@
|
|
|
1
|
+
{"version":3,"file":"legacy.js","sourceRoot":"","sources":["../../../src/core/scaffold/legacy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAsB;IACvD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkCD;IACC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsCD;IACC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0ED;IACC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+ED;CACA,CAAC","sourcesContent":["/**\n * Every fleet map an earlier loam scaffolded, frozen, so `isLandscapeStub` in\n * ./landscape.ts can still tell an untouched old scaffold from a hand-drawn map.\n *\n * Moved out of ./landscape.ts when that file neared its line limit, along the\n * seam the two halves already had: ./landscape.ts holds the stub loam writes\n * NOW and the predicate that reads it, this module holds what loam wrote\n * before. The first changes whenever the advice to a new fleet improves; this\n * one only ever grows by one entry, when that happens.\n */\n\n/**\n * Stubs earlier versions of loam wrote, FROZEN — never re-derived from\n * `LANDSCAPE_STUB` in ./landscape.ts, or an edit to it would silently rewrite\n * history.\n *\n * `isLandscapeStub` is a suffix match on the exact bytes, and `loam seed`\n * refuses (`seed-landscape-edited`) on a map it judges authored. So editing\n * the stub reclassifies every untouched older scaffold as hand-edited, in\n * repositories nobody has touched — the teaching step disappears from `loam\n * status` and `seed` refuses a map its own scaffold wrote. Each entry is one\n * shipped generation of the file, OLDEST FIRST, appended when\n * `LANDSCAPE_STUB`'s text changes — every generation loam ever wrote is here,\n * not just the previous one, since a repository scaffolded two releases ago is\n * as untouched as one scaffolded yesterday.\n *\n * Generation 1 (v0.1.0-beta.1, .2): the stub lived in core/docs.ts, carried no\n * `views` block at all (\"on purpose: loam reads the model and never a view\")\n * and no `tag platform`.\n * Generation 2 (v0.1.0-beta.3): the same file with the render paragraph\n * rewritten — still no `views` block, still no `tag platform`.\n * Generation 3 (v0.2.0-alpha.1 through .5): the `views` paragraph taught the\n * retired shape — that a service model \"renders from its OWN directory\" and\n * \"each declares its own `specification` block\" — which was written before an\n * extending model belonged to the root project.\n * Generation 4 (v0.2.0-alpha.6 through .11): the extending shape's render\n * paragraph and the shared-broker advice, with no relationship kinds — every\n * edge a plain `->`, which is how a fleet drawn from deployment configuration\n * ended with every arrow pointing into its broker and its stores.\n */\nexport const LEGACY_LANDSCAPE_STUBS: readonly string[] = [\n `// The fleet map: every service in services/ appears here, and every call\n// between two of them is an edge. This file is written by hand — loam never\n// guesses it, because \"who calls whom\" is the one fact no generator can read\n// off a repository.\n//\n// After \\`loam adopt --service <id>\\`, add the service here:\n//\n// paymentService = softwareSystem 'payment-service' {\n// description 'Owns payment authorization/capture'\n// metadata { service 'payment-service' } // binds the box to services/<id>/\n// }\n//\n// and give each call the operationId it uses, so requirements, C4 and OpenAPI\n// can be cross-checked:\n//\n// checkoutWeb -> paymentService 'Authorizes' {\n// metadata { op 'authorizePayment' }\n// }\n//\n// There is no \\`views\\` block, on purpose: loam reads the model and never a\n// view, so it would draw nothing. Add views here if you want diagrams, and\n// render them with LikeC4's own tooling (\\`npx likec4 start\\`) — but scope them,\n// because computing a view is superlinear in the number of edges and an\n// \\`include *\\` over a whole fleet takes minutes.\n\nspecification {\n element person\n element softwareSystem\n element container\n element database\n}\n\nmodel {\n}\n`,\n `// The fleet map: every service in services/ appears here, and every call\n// between two of them is an edge. This file is written by hand — loam never\n// guesses it, because \"who calls whom\" is the one fact no generator can read\n// off a repository.\n//\n// After \\`loam adopt --service <id>\\`, add the service here:\n//\n// paymentService = softwareSystem 'payment-service' {\n// description 'Owns payment authorization/capture'\n// metadata { service 'payment-service' } // binds the box to services/<id>/\n// }\n//\n// and give each call the operationId it uses, so requirements, C4 and OpenAPI\n// can be cross-checked:\n//\n// checkoutWeb -> paymentService 'Authorizes' {\n// metadata { op 'authorizePayment' }\n// }\n//\n// There is no \\`views\\` block, on purpose: loam reads the model and never a\n// view, so it would draw nothing. Add views here if you want diagrams, and\n// render them with LikeC4's own tooling — \\`npx likec4 start\\` from the docs\n// repo root, which likec4.config.json scopes to this directory. (A service\n// model or a feature delta renders from its OWN directory, e.g.\n// \\`npx likec4 start services/<id>\\`: each declares its own \\`specification\\`\n// block, so the renderer can only be given one of them at a time.) Scope your\n// views, because computing one is superlinear in the number of edges and an\n// \\`include *\\` over a whole fleet takes minutes.\n\nspecification {\n element person\n element softwareSystem\n element container\n element database\n}\n\nmodel {\n}\n`,\n `// The fleet map: every service in services/ appears here, and every call\n// between two of them is an edge. This file is written by hand — loam never\n// guesses it, because \"who calls whom\" is the one fact no generator can read\n// off a repository.\n//\n// After \\`loam adopt --service <id>\\`, add the service here:\n//\n// paymentService = softwareSystem 'payment-service' {\n// description 'Owns payment authorization/capture'\n// metadata { service 'payment-service' } // binds the box to services/<id>/\n// }\n//\n// and give each call the operationId it uses, so requirements, C4 and OpenAPI\n// can be cross-checked:\n//\n// checkoutWeb -> paymentService 'Authorizes' {\n// metadata { op 'authorizePayment' }\n// }\n//\n// The \\`views\\` block at the bottom is for LikeC4's own tooling — loam reads\n// the model and never a view. Render with \\`npx likec4 start\\` from the docs\n// repo root, which likec4.config.json scopes to this directory. (A service\n// model or a feature delta renders from its OWN directory, e.g.\n// \\`npx likec4 start services/<id>\\`: each declares its own \\`specification\\`\n// block, so the renderer can only be given one of them at a time.) Keep views\n// scoped, because computing one is superlinear in the number of edges — the\n// \\`fleet\\` view below stays affordable precisely because it excludes the\n// platform hubs.\n//\n// One shape is worth getting right before the fleet is drawn: a shared broker.\n// Kafka as a single element becomes the node every service points at, and any\n// view over it is a star nobody can read. Model the TOPIC instead — a \\`topic\\`\n// nested inside the broker's element, edges pointing at \\`kafka.<topic>\\` — which\n// splits one hub of degree sixty into a dozen small ones and is the truer model\n// besides. Tag the KIND, not just the broker: LikeC4 does not inherit tags, so a\n// topic under an \\`#external\\` broker is not external itself and \\`validate\\` asks\n// for a services/ directory nobody owes.\n//\n// specification {\n// element topic {\n// #external\n// style { shape queue }\n// }\n// }\n\nspecification {\n element person\n element softwareSystem\n element container\n element database\n\n // Ubiquitous infrastructure — logging Kafka, auth, service discovery — takes\n // one inbound edge per service, and by the third service the fleet view is a\n // hairball. Tag those elements #platform: the fleet view excludes them\n // without losing \"who depends on the Identity Provider\", which the platform\n // view answers.\n tag platform\n}\n\nmodel {\n}\n\nviews {\n view fleet {\n include *\n exclude element.tag = #platform\n }\n // The obvious spelling — \\`include element.tag = #platform\\` — draws the\n // platform boxes with NO edges and no consumers. The predicate that works is\n // the relationship form below.\n view platform {\n include * -> element.tag = #platform\n }\n}\n`,\n `// The fleet map: every service in services/ appears here, and every call\n// between two of them is an edge. This file is written by hand — loam never\n// guesses it, because \"who calls whom\" is the one fact no generator can read\n// off a repository.\n//\n// After \\`loam adopt --service <id>\\`, add the service here:\n//\n// paymentService = softwareSystem 'payment-service' {\n// description 'Owns payment authorization/capture'\n// metadata { service 'payment-service' } // binds the box to services/<id>/\n// }\n//\n// and give each call the operationId it uses, so requirements, C4 and OpenAPI\n// can be cross-checked:\n//\n// checkoutWeb -> paymentService 'Authorizes' {\n// metadata { op 'authorizePayment' }\n// }\n//\n// The \\`views\\` block at the bottom is for LikeC4's own tooling — loam reads\n// the model and never a view. Render with \\`npx likec4 start\\` from the docs\n// repo root, which likec4.config.json scopes to this directory. A service's\n// \\`services/<id>/model.likec4\\` EXTENDS this map: it declares no\n// \\`specification\\` block of its own, so it belongs to THIS project and renders\n// with it, containers and all. A model that declares its own \\`specification\\`\n// stands alone instead — it renders only from its own directory\n// (\\`npx likec4 start services/<id>\\`), and the \\`exclude\\` list in the root\n// likec4.config.json has to cover that directory or its declarations collide\n// with this file's. \\`loam subsystem sync\\` maintains both, so neither is\n// hand-edited. Keep views\n// scoped, because computing one is superlinear in the number of edges — the\n// \\`fleet\\` view below stays affordable precisely because it excludes the\n// platform hubs.\n//\n// One shape is worth getting right before the fleet is drawn: a shared broker.\n// Kafka as a single element becomes the node every service points at, and any\n// view over it is a star nobody can read. Model the TOPIC instead — a \\`topic\\`\n// nested inside the broker's element, edges pointing at \\`kafka.<topic>\\` — which\n// splits one hub of degree sixty into a dozen small ones and is the truer model\n// besides. Tag the KIND, not just the broker: LikeC4 does not inherit tags, so a\n// topic under an \\`#external\\` broker is not external itself and \\`validate\\` asks\n// for a services/ directory nobody owes.\n//\n// specification {\n// element topic {\n// #external\n// style { shape queue }\n// }\n// }\n\nspecification {\n element person\n element softwareSystem\n element container\n element database\n\n // Ubiquitous infrastructure — logging Kafka, auth, service discovery — takes\n // one inbound edge per service, and by the third service the fleet view is a\n // hairball. Tag those elements #platform: the fleet view excludes them\n // without losing \"who depends on the Identity Provider\", which the platform\n // view answers.\n tag platform\n}\n\nmodel {\n}\n\nviews {\n view fleet {\n include *\n exclude element.tag = #platform\n }\n // The obvious spelling — \\`include element.tag = #platform\\` — draws the\n // platform boxes with NO edges and no consumers. The predicate that works is\n // the relationship form below.\n view platform {\n include * -> element.tag = #platform\n }\n}\n`,\n];\n"]}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The README a new docs repo starts with — the one file in it addressed to a
|
|
3
|
+
* person.
|
|
4
|
+
*
|
|
5
|
+
* Everything else the scaffold lays down is either a document about the
|
|
6
|
+
* governed system or `AGENTS.md`, which is 1500 lines written for a coding
|
|
7
|
+
* agent and named so that a human does not open it. A forge renders `README.md`
|
|
8
|
+
* as the repository's landing page and nothing else, so without this file a
|
|
9
|
+
* docs repo opens as a bare directory listing: four folders and two config
|
|
10
|
+
* files, and no sentence anywhere saying what any of it is.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately SHORT, and deliberately not a second copy of anything. The
|
|
13
|
+
* layout table and the cycle are AGENTS.md's, in full; this page says what the
|
|
14
|
+
* repo is, points at the three commands a person actually types, and hands off.
|
|
15
|
+
* A README that restated the contract would be a second thing to keep true, and
|
|
16
|
+
* the first one to go stale.
|
|
17
|
+
*/
|
|
18
|
+
export const README_FILENAME = "README.md";
|
|
19
|
+
export const README_MD = `# Architecture & specs
|
|
20
|
+
|
|
21
|
+
This repository is a governed system's **source of truth**: its architecture,
|
|
22
|
+
requirements, contracts, domain vocabulary and verification evidence, kept in
|
|
23
|
+
explicit agreement. It is plain files — Markdown, YAML and LikeC4 — reviewed like
|
|
24
|
+
code, in pull requests.
|
|
25
|
+
|
|
26
|
+
In paths and commands, loam calls one governed implementation boundary a
|
|
27
|
+
**service**. That boundary may be a modular monolith, a network service, a CLI or
|
|
28
|
+
a worker. Nested C4 elements remain modules or components unless they need their
|
|
29
|
+
own repository binding, contracts, evidence and deployment boundary.
|
|
30
|
+
|
|
31
|
+
It is read and written with [**loam**](https://github.com/ybotok/loam). Delete
|
|
32
|
+
loam and these documents still make sense; that is the point of keeping them this
|
|
33
|
+
way.
|
|
34
|
+
|
|
35
|
+
## What is where
|
|
36
|
+
|
|
37
|
+
| | |
|
|
38
|
+
|---|---|
|
|
39
|
+
| \`architecture/landscape.likec4\` | the system map — governed boundaries, nested structure and their relationships |
|
|
40
|
+
| \`services/<id>/\` | one directory per governed boundary: what it promises, exposes and verifies |
|
|
41
|
+
| \`features/<FEAT>/\` | a change in flight — why it exists, and the delta it makes to the documents above |
|
|
42
|
+
| \`features/archive/\` | changes that shipped; their deltas are already merged into the living documents |
|
|
43
|
+
|
|
44
|
+
A directory under \`services/\` that holds a \`subsystem.yaml\` is a **group**, not
|
|
45
|
+
a service — services can be filed inside one at any depth.
|
|
46
|
+
|
|
47
|
+
## If you are new here
|
|
48
|
+
|
|
49
|
+
\`\`\`bash
|
|
50
|
+
loam status
|
|
51
|
+
\`\`\`
|
|
52
|
+
|
|
53
|
+
It reads the files and tells you where things stand and what to do next, ordered
|
|
54
|
+
most-unblocking first, with the exact command for each step. Nothing in this
|
|
55
|
+
repository is generated from a database or a server — if \`loam status\` says
|
|
56
|
+
something, a file said it first.
|
|
57
|
+
|
|
58
|
+
To check the whole repository the way CI does:
|
|
59
|
+
|
|
60
|
+
\`\`\`bash
|
|
61
|
+
loam validate --all
|
|
62
|
+
\`\`\`
|
|
63
|
+
|
|
64
|
+
And when a finding's code means nothing to you:
|
|
65
|
+
|
|
66
|
+
\`\`\`bash
|
|
67
|
+
loam explain <code>
|
|
68
|
+
\`\`\`
|
|
69
|
+
|
|
70
|
+
## Changing something
|
|
71
|
+
|
|
72
|
+
Documents here are edited through a **feature**: \`loam new <FEAT>\` scaffolds one,
|
|
73
|
+
you write the intent and the deltas, \`loam validate --feature <FEAT>\` grades it,
|
|
74
|
+
and \`loam archive <FEAT>\` merges it into the living documents. Living documents
|
|
75
|
+
are not edited directly once a boundary is adopted — the feature is the
|
|
76
|
+
reviewable unit, and the archive is what makes the change traceable afterwards.
|
|
77
|
+
|
|
78
|
+
## For coding agents
|
|
79
|
+
|
|
80
|
+
\`AGENTS.md\` in this directory is the full contract: the layout in detail, the
|
|
81
|
+
authoring rules \`loam validate\` enforces, the ID spine, the cycle, and what every
|
|
82
|
+
finding code means. It is generated by loam and kept in step with the binary.
|
|
83
|
+
`;
|
|
84
|
+
//# sourceMappingURL=readme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readme.js","sourceRoot":"","sources":["../../../src/core/scaffold/readme.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,WAAW,CAAC;AAE3C,MAAM,CAAC,MAAM,SAAS,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgExB,CAAC","sourcesContent":["/**\n * The README a new docs repo starts with — the one file in it addressed to a\n * person.\n *\n * Everything else the scaffold lays down is either a document about the\n * governed system or `AGENTS.md`, which is 1500 lines written for a coding\n * agent and named so that a human does not open it. A forge renders `README.md`\n * as the repository's landing page and nothing else, so without this file a\n * docs repo opens as a bare directory listing: four folders and two config\n * files, and no sentence anywhere saying what any of it is.\n *\n * Deliberately SHORT, and deliberately not a second copy of anything. The\n * layout table and the cycle are AGENTS.md's, in full; this page says what the\n * repo is, points at the three commands a person actually types, and hands off.\n * A README that restated the contract would be a second thing to keep true, and\n * the first one to go stale.\n */\nexport const README_FILENAME = \"README.md\";\n\nexport const README_MD = `# Architecture & specs\n\nThis repository is a governed system's **source of truth**: its architecture,\nrequirements, contracts, domain vocabulary and verification evidence, kept in\nexplicit agreement. It is plain files — Markdown, YAML and LikeC4 — reviewed like\ncode, in pull requests.\n\nIn paths and commands, loam calls one governed implementation boundary a\n**service**. That boundary may be a modular monolith, a network service, a CLI or\na worker. Nested C4 elements remain modules or components unless they need their\nown repository binding, contracts, evidence and deployment boundary.\n\nIt is read and written with [**loam**](https://github.com/ybotok/loam). Delete\nloam and these documents still make sense; that is the point of keeping them this\nway.\n\n## What is where\n\n| | |\n|---|---|\n| \\`architecture/landscape.likec4\\` | the system map — governed boundaries, nested structure and their relationships |\n| \\`services/<id>/\\` | one directory per governed boundary: what it promises, exposes and verifies |\n| \\`features/<FEAT>/\\` | a change in flight — why it exists, and the delta it makes to the documents above |\n| \\`features/archive/\\` | changes that shipped; their deltas are already merged into the living documents |\n\nA directory under \\`services/\\` that holds a \\`subsystem.yaml\\` is a **group**, not\na service — services can be filed inside one at any depth.\n\n## If you are new here\n\n\\`\\`\\`bash\nloam status\n\\`\\`\\`\n\nIt reads the files and tells you where things stand and what to do next, ordered\nmost-unblocking first, with the exact command for each step. Nothing in this\nrepository is generated from a database or a server — if \\`loam status\\` says\nsomething, a file said it first.\n\nTo check the whole repository the way CI does:\n\n\\`\\`\\`bash\nloam validate --all\n\\`\\`\\`\n\nAnd when a finding's code means nothing to you:\n\n\\`\\`\\`bash\nloam explain <code>\n\\`\\`\\`\n\n## Changing something\n\nDocuments here are edited through a **feature**: \\`loam new <FEAT>\\` scaffolds one,\nyou write the intent and the deltas, \\`loam validate --feature <FEAT>\\` grades it,\nand \\`loam archive <FEAT>\\` merges it into the living documents. Living documents\nare not edited directly once a boundary is adopted — the feature is the\nreviewable unit, and the archive is what makes the change traceable afterwards.\n\n## For coding agents\n\n\\`AGENTS.md\\` in this directory is the full contract: the layout in detail, the\nauthoring rules \\`loam validate\\` enforces, the ID spine, the cycle, and what every\nfinding code means. It is generated by loam and kept in step with the binary.\n`;\n"]}
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The commit itself, in three steps: stage every new version beside its
|
|
3
|
+
* target, swap them in, roll back what already went in when a later step fails.
|
|
4
|
+
*
|
|
5
|
+
* This is what `archive` and `unarchive` share, and it moved out of archive.ts
|
|
6
|
+
* verbatim once unarchive became its second consumer. The MERGE computations
|
|
7
|
+
* stayed with archive, which is still their only caller — the split was about a
|
|
8
|
+
* second CONSUMER, never about archive being long.
|
|
9
|
+
*
|
|
10
|
+
* `StagingRaceError` belongs here rather than with the lock, though both are
|
|
11
|
+
* about a second writer: the lock is taken before a plan is computed, while
|
|
12
|
+
* this is the compare-and-set immediately before each rename — the second line
|
|
13
|
+
* of defence for exactly the window two racers who both broke the same stale
|
|
14
|
+
* lock would land in.
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync } from "node:fs";
|
|
17
|
+
import { link, mkdir, readFile, rename, rm, rmdir, unlink, writeFile } from "node:fs/promises";
|
|
18
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
19
|
+
import { isPathInside, withoutNamespacePrefix } from "../kernel/path-safety.js";
|
|
20
|
+
import { sameBytes, toBytes } from "./writes.js";
|
|
21
|
+
/**
|
|
22
|
+
* The target changed between the pre-image staging read and the swap.
|
|
23
|
+
*
|
|
24
|
+
* The pre-image is what a rollback restores and what `unarchive` is handed, so
|
|
25
|
+
* swapping over somebody else's newer bytes would both lose their work and
|
|
26
|
+
* arm a rollback that writes a third version nobody wrote. Commands map this to
|
|
27
|
+
* `merge-failed`: nothing of theirs went in, the docs are as the other writer
|
|
28
|
+
* left them, and re-running can work.
|
|
29
|
+
*/
|
|
30
|
+
export class StagingRaceError extends Error {
|
|
31
|
+
path;
|
|
32
|
+
name = "StagingRaceError";
|
|
33
|
+
constructor(path) {
|
|
34
|
+
super(`${path} changed while this command was planning its merge — nothing was written; re-run`);
|
|
35
|
+
this.path = path;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Write every new version to a temp file beside its target, remembering what the
|
|
40
|
+
* target said first. Nothing observable changes here: on failure the temp files
|
|
41
|
+
* are removed and the docs are exactly as they were.
|
|
42
|
+
*
|
|
43
|
+
* The pre-image is read eagerly and deliberately: it is what a rollback restores
|
|
44
|
+
* and what `unarchive` is given, so a file we cannot read is a file we cannot
|
|
45
|
+
* safely rewrite, and the merge must stop before it starts.
|
|
46
|
+
*/
|
|
47
|
+
export async function stageWrites(writes) {
|
|
48
|
+
const staged = [];
|
|
49
|
+
try {
|
|
50
|
+
for (const [i, write] of writes.entries()) {
|
|
51
|
+
const createdDir = await mkdirReportingCreated(dirname(write.path));
|
|
52
|
+
const before = existsSync(write.path) ? await readFile(write.path) : null;
|
|
53
|
+
const content = toBytes(write.content);
|
|
54
|
+
let tmp = null;
|
|
55
|
+
if (content !== null) {
|
|
56
|
+
tmp = tempPath(write.path, i);
|
|
57
|
+
await writeFile(tmp, content);
|
|
58
|
+
}
|
|
59
|
+
staged.push({ write, content, tmp, before, createdDir, swapped: false });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
catch (err) {
|
|
63
|
+
await discardStaged(staged);
|
|
64
|
+
throw err;
|
|
65
|
+
}
|
|
66
|
+
return staged;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Swap the staged versions in, one file at a time. Each swap is a rename(2)
|
|
70
|
+
* within a single directory, so a concurrent reader sees either the old bytes or
|
|
71
|
+
* the new ones — never a half-written file. Across files it is not atomic: the
|
|
72
|
+
* caller rolls back what has already gone in.
|
|
73
|
+
*
|
|
74
|
+
* Every swap re-reads its target first and compares it with the pre-image the
|
|
75
|
+
* plan was computed from — a compare-and-set on the file's whole content. It is
|
|
76
|
+
* half a CAS on purpose: read and rename cannot be one syscall, so a writer
|
|
77
|
+
* landing inside that window still wins. What it does buy is the window that
|
|
78
|
+
* actually matters — the seconds a plan spends parsing LikeC4 and merging YAML
|
|
79
|
+
* between the pre-image read and this swap — and it costs one read per file.
|
|
80
|
+
*/
|
|
81
|
+
export async function swapStaged(staged) {
|
|
82
|
+
for (const s of staged) {
|
|
83
|
+
const now = existsSync(s.write.path) ? await readFile(s.write.path) : null;
|
|
84
|
+
if (!sameBytes(now, s.before))
|
|
85
|
+
throw new StagingRaceError(s.write.path);
|
|
86
|
+
if (s.tmp === null) {
|
|
87
|
+
if (s.before !== null)
|
|
88
|
+
await unlink(s.write.path);
|
|
89
|
+
}
|
|
90
|
+
else if (s.write.exclusive === true) {
|
|
91
|
+
// link(2) is the same-filesystem, atomic no-clobber counterpart to rename:
|
|
92
|
+
// it fails with EEXIST instead of replacing a file created after planning.
|
|
93
|
+
await link(s.tmp, s.write.path);
|
|
94
|
+
s.swapped = true;
|
|
95
|
+
await unlink(s.tmp);
|
|
96
|
+
s.tmp = null;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
await rename(s.tmp, s.write.path);
|
|
101
|
+
}
|
|
102
|
+
s.swapped = true;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Put back every file that was already swapped, newest first, from the bytes read
|
|
107
|
+
* before the swap. Returns the paths it could NOT restore — the caller must say so
|
|
108
|
+
* out loud rather than report a clean failure over a half-merged repo.
|
|
109
|
+
*
|
|
110
|
+
* A rollback only ever un-does ITS OWN write: if the file no longer holds the
|
|
111
|
+
* bytes this run put there, somebody else has written it since, and restoring
|
|
112
|
+
* the pre-image would destroy their work while reporting a clean failure. That
|
|
113
|
+
* file is left exactly as found and named in the failures, which is what turns
|
|
114
|
+
* the caller's answer from `merge-failed` ("trust the repo") into
|
|
115
|
+
* `rollback-incomplete` ("look at it by hand") — the honest answer, because the
|
|
116
|
+
* repo now holds one run's writes half-reverted next to another's.
|
|
117
|
+
*/
|
|
118
|
+
export async function rollbackStaged(staged) {
|
|
119
|
+
const failures = [];
|
|
120
|
+
for (const s of [...staged].reverse()) {
|
|
121
|
+
if (!s.swapped)
|
|
122
|
+
continue;
|
|
123
|
+
try {
|
|
124
|
+
const now = existsSync(s.write.path) ? await readFile(s.write.path) : null;
|
|
125
|
+
if (!sameBytes(now, s.content)) {
|
|
126
|
+
failures.push(`${s.write.path} (changed by another writer after this run wrote it — left as found)`);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (s.before === null)
|
|
130
|
+
await rm(s.write.path, { force: true });
|
|
131
|
+
else
|
|
132
|
+
await atomicWrite(s.write.path, s.before);
|
|
133
|
+
s.swapped = false;
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
failures.push(`${s.write.path} (${message(err)})`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
await discardStaged(staged);
|
|
140
|
+
return failures;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* `mkdir -p`, reporting the topmost directory it had to create — the handle a
|
|
144
|
+
* rollback needs to put the tree back the way it found it — or null when every
|
|
145
|
+
* one already existed.
|
|
146
|
+
*
|
|
147
|
+
* The report is never handed on raw. On Windows, Node spells it with a `\\?\`
|
|
148
|
+
* prefix that no other path loam holds carries, and a rollback comparing the
|
|
149
|
+
* two spellings found nothing to prune (`withoutNamespacePrefix` has the
|
|
150
|
+
* measurement). Every caller that keeps a created directory for its rollback
|
|
151
|
+
* takes it from here, so the plain spelling is decided once.
|
|
152
|
+
*/
|
|
153
|
+
export async function mkdirReportingCreated(dir) {
|
|
154
|
+
const created = await mkdir(dir, { recursive: true });
|
|
155
|
+
return created === undefined ? null : withoutNamespacePrefix(created);
|
|
156
|
+
}
|
|
157
|
+
/** Write `content` to `path` through a temp file in the same directory. */
|
|
158
|
+
export async function atomicWrite(path, content) {
|
|
159
|
+
const tmp = tempPath(path, 0);
|
|
160
|
+
await writeFile(tmp, content);
|
|
161
|
+
await rename(tmp, path);
|
|
162
|
+
}
|
|
163
|
+
/** A hidden sibling of `path`: same directory, so the rename never crosses a filesystem. */
|
|
164
|
+
export function tempPath(path, n) {
|
|
165
|
+
return join(dirname(path), `.${basename(path)}.loam-${process.pid}-${n}-${Date.now()}.tmp`);
|
|
166
|
+
}
|
|
167
|
+
/** The shape `tempPath` writes — what a scan for leftovers of a killed run matches on. */
|
|
168
|
+
export const TEMP_FILE_RE = /^\..*\.loam-\d+-\d+-\d+\.tmp$/;
|
|
169
|
+
/**
|
|
170
|
+
* Everything staging left on disk: the temp files, and the directories it made
|
|
171
|
+
* for them.
|
|
172
|
+
*
|
|
173
|
+
* Directories go by rmdir, never by recursive remove, and the walk stops the
|
|
174
|
+
* moment one is not empty. The recursive form used to be reached for because
|
|
175
|
+
* "we created this directory, so it is ours" — but a directory created at plan
|
|
176
|
+
* time is shared by the time the rollback runs: a second archive can have put a
|
|
177
|
+
* whole feature inside `features/archive/` in between, and `rm -r` on our own
|
|
178
|
+
* created root took their work with it, silently, on OUR failure path.
|
|
179
|
+
*/
|
|
180
|
+
async function discardStaged(staged) {
|
|
181
|
+
for (const s of staged)
|
|
182
|
+
if (s.tmp !== null)
|
|
183
|
+
await quietRm(s.tmp);
|
|
184
|
+
const roots = staged.filter((s) => s.createdDir !== null).map((s) => resolve(s.createdDir));
|
|
185
|
+
for (const s of [...staged].reverse()) {
|
|
186
|
+
const root = roots.find((candidate) => isPathInside(candidate, s.write.path));
|
|
187
|
+
if (root !== undefined)
|
|
188
|
+
await quietPruneEmptyParents(dirname(s.write.path), root);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
/** Remove `dir` if it is empty. Best effort — a directory left standing is noise, not corruption. */
|
|
192
|
+
export async function quietRmdir(dir) {
|
|
193
|
+
try {
|
|
194
|
+
await rmdir(dir);
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// Not empty, or not ours.
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Undo the directories a write had to create, from `start` up to and including
|
|
202
|
+
* `boundary` — or, for unarchive, the ones a restore's deletes left empty.
|
|
203
|
+
* Remove only directories that are still EMPTY: anything else in there arrived
|
|
204
|
+
* after we made it, and belongs to whoever put it there.
|
|
205
|
+
*/
|
|
206
|
+
export async function quietPruneEmptyParents(start, boundary) {
|
|
207
|
+
let cursor = resolve(start);
|
|
208
|
+
const root = resolve(boundary);
|
|
209
|
+
while (isPathInside(root, cursor)) {
|
|
210
|
+
try {
|
|
211
|
+
await rmdir(cursor);
|
|
212
|
+
}
|
|
213
|
+
catch {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (cursor === root)
|
|
217
|
+
return;
|
|
218
|
+
const parent = dirname(cursor);
|
|
219
|
+
if (parent === cursor)
|
|
220
|
+
return;
|
|
221
|
+
cursor = parent;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
export async function quietRm(path) {
|
|
225
|
+
try {
|
|
226
|
+
await rm(path, { recursive: true, force: true });
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
// Best effort — a leftover temp file is noise, not corruption.
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* The one spelling of the sentence a rollback failure prints, parameterised
|
|
234
|
+
* only by the verb for what the files were mid-way through becoming. It
|
|
235
|
+
* existed in three near-copies (archive's "half-merged", vouch's
|
|
236
|
+
* "half-stamped", verify's "half-written") — the exact shape whose fix lands
|
|
237
|
+
* in one copy while an operator greps their logs for another.
|
|
238
|
+
*/
|
|
239
|
+
export function rollbackMessage(err, failures, what) {
|
|
240
|
+
return `${message(err)} — ROLLBACK INCOMPLETE, these files may be half-${what} and need checking by hand: ${failures.join(", ")}`;
|
|
241
|
+
}
|
|
242
|
+
/** Say what the failure cost: nothing, or a repo that needs looking at by hand. */
|
|
243
|
+
export function rollbackError(err, failures) {
|
|
244
|
+
if (failures.length === 0) {
|
|
245
|
+
return new Error(`${message(err)} — the living docs were rolled back, nothing was merged`);
|
|
246
|
+
}
|
|
247
|
+
return new Error(rollbackMessage(err, failures, "merged"));
|
|
248
|
+
}
|
|
249
|
+
export function message(err) {
|
|
250
|
+
return err instanceof Error ? err.message : String(err);
|
|
251
|
+
}
|
|
252
|
+
//# sourceMappingURL=commit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit.js","sourceRoot":"","sources":["../../../src/core/staging/commit.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The commit itself, in three steps: stage every new version beside its\n * target, swap them in, roll back what already went in when a later step fails.\n *\n * This is what `archive` and `unarchive` share, and it moved out of archive.ts\n * verbatim once unarchive became its second consumer. The MERGE computations\n * stayed with archive, which is still their only caller — the split was about a\n * second CONSUMER, never about archive being long.\n *\n * `StagingRaceError` belongs here rather than with the lock, though both are\n * about a second writer: the lock is taken before a plan is computed, while\n * this is the compare-and-set immediately before each rename — the second line\n * of defence for exactly the window two racers who both broke the same stale\n * lock would land in.\n */\nimport { existsSync } from \"node:fs\";\nimport { link, mkdir, readFile, rename, rm, rmdir, unlink, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, join, resolve } from \"node:path\";\nimport { isPathInside, withoutNamespacePrefix } from \"../kernel/path-safety.js\";\nimport { sameBytes, toBytes, type PlannedWrite, type StagedWrite } from \"./writes.js\";\n\n/**\n * The target changed between the pre-image staging read and the swap.\n *\n * The pre-image is what a rollback restores and what `unarchive` is handed, so\n * swapping over somebody else's newer bytes would both lose their work and\n * arm a rollback that writes a third version nobody wrote. Commands map this to\n * `merge-failed`: nothing of theirs went in, the docs are as the other writer\n * left them, and re-running can work.\n */\nexport class StagingRaceError extends Error {\n override readonly name = \"StagingRaceError\";\n\n constructor(readonly path: string) {\n super(`${path} changed while this command was planning its merge — nothing was written; re-run`);\n }\n}\n\n/**\n * Write every new version to a temp file beside its target, remembering what the\n * target said first. Nothing observable changes here: on failure the temp files\n * are removed and the docs are exactly as they were.\n *\n * The pre-image is read eagerly and deliberately: it is what a rollback restores\n * and what `unarchive` is given, so a file we cannot read is a file we cannot\n * safely rewrite, and the merge must stop before it starts.\n */\nexport async function stageWrites(writes: PlannedWrite[]): Promise<StagedWrite[]> {\n const staged: StagedWrite[] = [];\n try {\n for (const [i, write] of writes.entries()) {\n const createdDir = await mkdirReportingCreated(dirname(write.path));\n const before = existsSync(write.path) ? await readFile(write.path) : null;\n const content = toBytes(write.content);\n let tmp: string | null = null;\n if (content !== null) {\n tmp = tempPath(write.path, i);\n await writeFile(tmp, content);\n }\n staged.push({ write, content, tmp, before, createdDir, swapped: false });\n }\n } catch (err) {\n await discardStaged(staged);\n throw err;\n }\n return staged;\n}\n\n/**\n * Swap the staged versions in, one file at a time. Each swap is a rename(2)\n * within a single directory, so a concurrent reader sees either the old bytes or\n * the new ones — never a half-written file. Across files it is not atomic: the\n * caller rolls back what has already gone in.\n *\n * Every swap re-reads its target first and compares it with the pre-image the\n * plan was computed from — a compare-and-set on the file's whole content. It is\n * half a CAS on purpose: read and rename cannot be one syscall, so a writer\n * landing inside that window still wins. What it does buy is the window that\n * actually matters — the seconds a plan spends parsing LikeC4 and merging YAML\n * between the pre-image read and this swap — and it costs one read per file.\n */\nexport async function swapStaged(staged: StagedWrite[]): Promise<void> {\n for (const s of staged) {\n const now = existsSync(s.write.path) ? await readFile(s.write.path) : null;\n if (!sameBytes(now, s.before)) throw new StagingRaceError(s.write.path);\n if (s.tmp === null) {\n if (s.before !== null) await unlink(s.write.path);\n } else if (s.write.exclusive === true) {\n // link(2) is the same-filesystem, atomic no-clobber counterpart to rename:\n // it fails with EEXIST instead of replacing a file created after planning.\n await link(s.tmp, s.write.path);\n s.swapped = true;\n await unlink(s.tmp);\n s.tmp = null;\n continue;\n } else {\n await rename(s.tmp, s.write.path);\n }\n s.swapped = true;\n }\n}\n\n/**\n * Put back every file that was already swapped, newest first, from the bytes read\n * before the swap. Returns the paths it could NOT restore — the caller must say so\n * out loud rather than report a clean failure over a half-merged repo.\n *\n * A rollback only ever un-does ITS OWN write: if the file no longer holds the\n * bytes this run put there, somebody else has written it since, and restoring\n * the pre-image would destroy their work while reporting a clean failure. That\n * file is left exactly as found and named in the failures, which is what turns\n * the caller's answer from `merge-failed` (\"trust the repo\") into\n * `rollback-incomplete` (\"look at it by hand\") — the honest answer, because the\n * repo now holds one run's writes half-reverted next to another's.\n */\nexport async function rollbackStaged(staged: StagedWrite[]): Promise<string[]> {\n const failures: string[] = [];\n for (const s of [...staged].reverse()) {\n if (!s.swapped) continue;\n try {\n const now = existsSync(s.write.path) ? await readFile(s.write.path) : null;\n if (!sameBytes(now, s.content)) {\n failures.push(`${s.write.path} (changed by another writer after this run wrote it — left as found)`);\n continue;\n }\n if (s.before === null) await rm(s.write.path, { force: true });\n else await atomicWrite(s.write.path, s.before);\n s.swapped = false;\n } catch (err) {\n failures.push(`${s.write.path} (${message(err)})`);\n }\n }\n await discardStaged(staged);\n return failures;\n}\n\n/**\n * `mkdir -p`, reporting the topmost directory it had to create — the handle a\n * rollback needs to put the tree back the way it found it — or null when every\n * one already existed.\n *\n * The report is never handed on raw. On Windows, Node spells it with a `\\\\?\\`\n * prefix that no other path loam holds carries, and a rollback comparing the\n * two spellings found nothing to prune (`withoutNamespacePrefix` has the\n * measurement). Every caller that keeps a created directory for its rollback\n * takes it from here, so the plain spelling is decided once.\n */\nexport async function mkdirReportingCreated(dir: string): Promise<string | null> {\n const created = await mkdir(dir, { recursive: true });\n return created === undefined ? null : withoutNamespacePrefix(created);\n}\n\n/** Write `content` to `path` through a temp file in the same directory. */\nexport async function atomicWrite(path: string, content: Buffer): Promise<void> {\n const tmp = tempPath(path, 0);\n await writeFile(tmp, content);\n await rename(tmp, path);\n}\n\n/** A hidden sibling of `path`: same directory, so the rename never crosses a filesystem. */\nexport function tempPath(path: string, n: number): string {\n return join(dirname(path), `.${basename(path)}.loam-${process.pid}-${n}-${Date.now()}.tmp`);\n}\n\n/** The shape `tempPath` writes — what a scan for leftovers of a killed run matches on. */\nexport const TEMP_FILE_RE = /^\\..*\\.loam-\\d+-\\d+-\\d+\\.tmp$/;\n\n/**\n * Everything staging left on disk: the temp files, and the directories it made\n * for them.\n *\n * Directories go by rmdir, never by recursive remove, and the walk stops the\n * moment one is not empty. The recursive form used to be reached for because\n * \"we created this directory, so it is ours\" — but a directory created at plan\n * time is shared by the time the rollback runs: a second archive can have put a\n * whole feature inside `features/archive/` in between, and `rm -r` on our own\n * created root took their work with it, silently, on OUR failure path.\n */\nasync function discardStaged(staged: StagedWrite[]): Promise<void> {\n for (const s of staged) if (s.tmp !== null) await quietRm(s.tmp);\n const roots = staged.filter((s) => s.createdDir !== null).map((s) => resolve(s.createdDir!));\n for (const s of [...staged].reverse()) {\n const root = roots.find((candidate) => isPathInside(candidate, s.write.path));\n if (root !== undefined) await quietPruneEmptyParents(dirname(s.write.path), root);\n }\n}\n\n/** Remove `dir` if it is empty. Best effort — a directory left standing is noise, not corruption. */\nexport async function quietRmdir(dir: string): Promise<void> {\n try {\n await rmdir(dir);\n } catch {\n // Not empty, or not ours.\n }\n}\n\n/**\n * Undo the directories a write had to create, from `start` up to and including\n * `boundary` — or, for unarchive, the ones a restore's deletes left empty.\n * Remove only directories that are still EMPTY: anything else in there arrived\n * after we made it, and belongs to whoever put it there.\n */\nexport async function quietPruneEmptyParents(start: string, boundary: string): Promise<void> {\n let cursor = resolve(start);\n const root = resolve(boundary);\n while (isPathInside(root, cursor)) {\n try {\n await rmdir(cursor);\n } catch {\n return;\n }\n if (cursor === root) return;\n const parent = dirname(cursor);\n if (parent === cursor) return;\n cursor = parent;\n }\n}\n\nexport async function quietRm(path: string): Promise<void> {\n try {\n await rm(path, { recursive: true, force: true });\n } catch {\n // Best effort — a leftover temp file is noise, not corruption.\n }\n}\n\n/**\n * The one spelling of the sentence a rollback failure prints, parameterised\n * only by the verb for what the files were mid-way through becoming. It\n * existed in three near-copies (archive's \"half-merged\", vouch's\n * \"half-stamped\", verify's \"half-written\") — the exact shape whose fix lands\n * in one copy while an operator greps their logs for another.\n */\nexport function rollbackMessage(err: unknown, failures: string[], what: string): string {\n return `${message(err)} — ROLLBACK INCOMPLETE, these files may be half-${what} and need checking by hand: ${failures.join(\", \")}`;\n}\n\n/** Say what the failure cost: nothing, or a repo that needs looking at by hand. */\nexport function rollbackError(err: unknown, failures: string[]): Error {\n if (failures.length === 0) {\n return new Error(`${message(err)} — the living docs were rolled back, nothing was merged`);\n }\n return new Error(\n rollbackMessage(err, failures, \"merged\"),\n );\n}\n\nexport function message(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\n"]}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The vocabulary every journaled commit shares, whichever journal version
|
|
3
|
+
* wrote it: the record's filename, the refusal an interrupted commit raises,
|
|
4
|
+
* the recovery report a caller prints, and the two disk disciplines (durable
|
|
5
|
+
* write, pid-scoped temp sweep) that recovery rests on.
|
|
6
|
+
*
|
|
7
|
+
* A staging-ROOT module, deliberately: `recovery/` (the version-1 undo path)
|
|
8
|
+
* and `txn/` (the version-2 roll-forward path) both need these VALUES, and a
|
|
9
|
+
* value import between those two packages in either direction would be the
|
|
10
|
+
* repo's first package cycle — `recovery/` already imports the staging root,
|
|
11
|
+
* and `txn/` must too. Shared values live where both edges already point.
|
|
12
|
+
*/
|
|
13
|
+
import { readdir, open } from "node:fs/promises";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { quietRm, TEMP_FILE_RE } from "./commit.js";
|
|
16
|
+
/**
|
|
17
|
+
* The journal that makes an interrupted commit detectable.
|
|
18
|
+
*
|
|
19
|
+
* `swapStaged` is N renames, and only each ONE of them is atomic. A kill
|
|
20
|
+
* between two of them leaves the tree half-merged — and nothing could see it:
|
|
21
|
+
* `doctor` and `status` called the repo healthy, `validate --all` blamed the
|
|
22
|
+
* delta, and the next archive cleared the one snapshot that could have
|
|
23
|
+
* repaired it. So every commit's swap loop runs inside a record written and
|
|
24
|
+
* fsynced BEFORE the first rename and removed after the last step: its mere
|
|
25
|
+
* presence says a commit was in flight, and its per-path digests say, file by
|
|
26
|
+
* file, whether that file's rename landed.
|
|
27
|
+
*
|
|
28
|
+
* It is deliberately NOT a source of truth and never disagrees with the
|
|
29
|
+
* files: every judgement it supports is made by re-reading the bytes and
|
|
30
|
+
* comparing digests, and every byte a repair writes is verified against the
|
|
31
|
+
* digest recorded before the crash. Outside the commit window it does not
|
|
32
|
+
* exist — except after a rollback that could not finish, where it is kept on
|
|
33
|
+
* purpose as the one durable record of which files need a human. Version 1
|
|
34
|
+
* (archive/unarchive) restores from a snapshot; version 2 (the smaller
|
|
35
|
+
* transaction) rolls forward from the staged temps. Both wear this name so
|
|
36
|
+
* one `doctor` scan finds either.
|
|
37
|
+
*/
|
|
38
|
+
export const COMMIT_INTENT = ".loam-commit";
|
|
39
|
+
/** An interrupted commit this loam must not silently write over. */
|
|
40
|
+
export class InterruptedCommitError extends Error {
|
|
41
|
+
name = "InterruptedCommitError";
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Write `text` to `path` and get it onto the DISK, not just into the page
|
|
45
|
+
* cache: a journal that dies with the machine describes nothing. The
|
|
46
|
+
* directory entry is fsynced too where the platform allows opening a
|
|
47
|
+
* directory — without that the file's bytes can be durable while its name is
|
|
48
|
+
* not.
|
|
49
|
+
*/
|
|
50
|
+
export async function writeDurable(path, text) {
|
|
51
|
+
const handle = await open(path, "w");
|
|
52
|
+
try {
|
|
53
|
+
await handle.writeFile(text, "utf8");
|
|
54
|
+
await handle.sync();
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
await handle.close();
|
|
58
|
+
}
|
|
59
|
+
try {
|
|
60
|
+
const dir = await open(join(path, ".."), "r");
|
|
61
|
+
try {
|
|
62
|
+
await dir.sync();
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
await dir.close();
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Not every platform lets a directory be opened; the file's own bytes are
|
|
70
|
+
// flushed either way, which is the part that carries the digests.
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Drop the staged temp files a killed run could not remove — scoped to that
|
|
75
|
+
* run's own pid and its own target directories, both carried in the temp
|
|
76
|
+
* name, so a leftover belonging to anything else is left for `doctor` to
|
|
77
|
+
* name. Without this a repair that put every byte back still left the repo
|
|
78
|
+
* dirty, which is the one thing a caller checks to decide whether it worked.
|
|
79
|
+
*/
|
|
80
|
+
export async function sweepPidTemps(dirs, pid) {
|
|
81
|
+
for (const dir of new Set(dirs)) {
|
|
82
|
+
let entries;
|
|
83
|
+
try {
|
|
84
|
+
entries = await readdir(dir);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
for (const name of entries) {
|
|
90
|
+
if (!TEMP_FILE_RE.test(name) || !name.includes(`.loam-${pid}-`))
|
|
91
|
+
continue;
|
|
92
|
+
await quietRm(join(dir, name));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=interrupted.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interrupted.js","sourceRoot":"","sources":["../../../src/core/staging/interrupted.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,cAAc,CAAC;AAE5C,oEAAoE;AACpE,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC7B,IAAI,GAAG,wBAAwB,CAAC;CACnD;AAsBD;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY,EAAE,IAAY;IAC3D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IACrC,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACrC,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;YAAS,CAAC;QACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QAC9C,IAAI,CAAC;YACH,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;QACnB,CAAC;gBAAS,CAAC;YACT,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;QAC1E,kEAAkE;IACpE,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAsB,EAAE,GAAW;IACrE,KAAK,MAAM,GAAG,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;QAChC,IAAI,OAAiB,CAAC;QACtB,IAAI,CAAC;YACH,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC;QAC/B,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;YAC3B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,GAAG,GAAG,CAAC;gBAAE,SAAS;YAC1E,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;AACH,CAAC","sourcesContent":["/**\n * The vocabulary every journaled commit shares, whichever journal version\n * wrote it: the record's filename, the refusal an interrupted commit raises,\n * the recovery report a caller prints, and the two disk disciplines (durable\n * write, pid-scoped temp sweep) that recovery rests on.\n *\n * A staging-ROOT module, deliberately: `recovery/` (the version-1 undo path)\n * and `txn/` (the version-2 roll-forward path) both need these VALUES, and a\n * value import between those two packages in either direction would be the\n * repo's first package cycle — `recovery/` already imports the staging root,\n * and `txn/` must too. Shared values live where both edges already point.\n */\nimport { readdir, open } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { quietRm, TEMP_FILE_RE } from \"./commit.js\";\n\n/**\n * The journal that makes an interrupted commit detectable.\n *\n * `swapStaged` is N renames, and only each ONE of them is atomic. A kill\n * between two of them leaves the tree half-merged — and nothing could see it:\n * `doctor` and `status` called the repo healthy, `validate --all` blamed the\n * delta, and the next archive cleared the one snapshot that could have\n * repaired it. So every commit's swap loop runs inside a record written and\n * fsynced BEFORE the first rename and removed after the last step: its mere\n * presence says a commit was in flight, and its per-path digests say, file by\n * file, whether that file's rename landed.\n *\n * It is deliberately NOT a source of truth and never disagrees with the\n * files: every judgement it supports is made by re-reading the bytes and\n * comparing digests, and every byte a repair writes is verified against the\n * digest recorded before the crash. Outside the commit window it does not\n * exist — except after a rollback that could not finish, where it is kept on\n * purpose as the one durable record of which files need a human. Version 1\n * (archive/unarchive) restores from a snapshot; version 2 (the smaller\n * transaction) rolls forward from the staged temps. Both wear this name so\n * one `doctor` scan finds either.\n */\nexport const COMMIT_INTENT = \".loam-commit\";\n\n/** An interrupted commit this loam must not silently write over. */\nexport class InterruptedCommitError extends Error {\n override readonly name = \"InterruptedCommitError\";\n}\n\n/** What recovery did, for the caller to print and put in `--json`. */\nexport interface CommitRecovery {\n /** Which command's commit was recovered — a sentence a human reads, not a branch. */\n command: string;\n /**\n * What that command was committing FOR: a feature id for archive, unarchive\n * and rebase; a service for vouch and gherkin. The field keeps archive's\n * original name because its `--json` shape shipped first.\n */\n feature: string;\n /**\n * `completed` — every step but the record's own removal landed;\n * `consistent` — no file was left in the other state;\n * `repaired` — files were put back (v1) or carried forward (v2), byte for byte.\n */\n outcome: \"completed\" | \"consistent\" | \"repaired\";\n /** Repo-relative paths this recovery rewrote or removed. */\n repaired: string[];\n}\n\n/**\n * Write `text` to `path` and get it onto the DISK, not just into the page\n * cache: a journal that dies with the machine describes nothing. The\n * directory entry is fsynced too where the platform allows opening a\n * directory — without that the file's bytes can be durable while its name is\n * not.\n */\nexport async function writeDurable(path: string, text: string): Promise<void> {\n const handle = await open(path, \"w\");\n try {\n await handle.writeFile(text, \"utf8\");\n await handle.sync();\n } finally {\n await handle.close();\n }\n try {\n const dir = await open(join(path, \"..\"), \"r\");\n try {\n await dir.sync();\n } finally {\n await dir.close();\n }\n } catch {\n // Not every platform lets a directory be opened; the file's own bytes are\n // flushed either way, which is the part that carries the digests.\n }\n}\n\n/**\n * Drop the staged temp files a killed run could not remove — scoped to that\n * run's own pid and its own target directories, both carried in the temp\n * name, so a leftover belonging to anything else is left for `doctor` to\n * name. Without this a repair that put every byte back still left the repo\n * dirty, which is the one thing a caller checks to decide whether it worked.\n */\nexport async function sweepPidTemps(dirs: Iterable<string>, pid: number): Promise<void> {\n for (const dir of new Set(dirs)) {\n let entries: string[];\n try {\n entries = await readdir(dir);\n } catch {\n continue;\n }\n for (const name of entries) {\n if (!TEMP_FILE_RE.test(name) || !name.includes(`.loam-${pid}-`)) continue;\n await quietRm(join(dir, name));\n }\n }\n}\n"]}
|