@ybotok/loam 0.1.0-beta.2 → 0.2.0-alpha.1
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 +2570 -61
- package/COMPARISON.md +80 -63
- package/CONTRIBUTING.md +84 -0
- package/MIGRATING-from-OpenSpec.md +213 -54
- package/QUICKSTART.md +125 -0
- package/README.md +450 -150
- package/ROADMAP.md +494 -0
- package/SCHEMA.md +2362 -245
- package/SECURITY.md +21 -3
- package/WORKFLOW.md +701 -0
- package/dist/cli.js +113 -19
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +209 -0
- package/dist/commands/adopt/adopt.js.map +1 -0
- package/dist/commands/adopt/render.js +268 -0
- package/dist/commands/adopt/render.js.map +1 -0
- package/dist/commands/archive/archive.js +77 -0
- package/dist/commands/archive/archive.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +178 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +159 -0
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +317 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +161 -0
- package/dist/commands/archive/plan/landscape.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +111 -0
- package/dist/commands/archive/plan/refusal.js.map +1 -0
- package/dist/commands/archive/plan/specs.js +237 -0
- package/dist/commands/archive/plan/specs.js.map +1 -0
- package/dist/commands/archive/plan/state.js +27 -0
- package/dist/commands/archive/plan/state.js.map +1 -0
- package/dist/commands/archive/run.js +251 -0
- package/dist/commands/archive/run.js.map +1 -0
- package/dist/commands/context/context.js +99 -0
- package/dist/commands/context/context.js.map +1 -0
- package/dist/commands/context/print.js +283 -0
- package/dist/commands/context/print.js.map +1 -0
- package/dist/commands/delta/delta.js +279 -0
- package/dist/commands/delta/delta.js.map +1 -0
- package/dist/commands/delta/print.js +205 -0
- package/dist/commands/delta/print.js.map +1 -0
- package/dist/commands/dependencies.js +9 -7
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +93 -0
- package/dist/commands/diff/diff.js.map +1 -0
- package/dist/commands/diff/print.js +38 -0
- package/dist/commands/diff/print.js.map +1 -0
- package/dist/commands/doctor.js +5 -4
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +151 -0
- package/dist/commands/explain/explain.js.map +1 -0
- package/dist/commands/explore.js +29 -24
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +115 -0
- package/dist/commands/gate/gate.js.map +1 -0
- package/dist/commands/gate/print.js +54 -0
- package/dist/commands/gate/print.js.map +1 -0
- package/dist/commands/gherkin/commit.js +146 -0
- package/dist/commands/gherkin/commit.js.map +1 -0
- package/dist/commands/gherkin/gherkin.js +246 -0
- package/dist/commands/gherkin/gherkin.js.map +1 -0
- package/dist/commands/gherkin/reconcile.js +149 -0
- package/dist/commands/gherkin/reconcile.js.map +1 -0
- package/dist/commands/gherkin/render.js +77 -0
- package/dist/commands/gherkin/render.js.map +1 -0
- package/dist/commands/init/example.js +204 -0
- package/dist/commands/init/example.js.map +1 -0
- package/dist/commands/init/first-hour.js +28 -0
- package/dist/commands/init/first-hour.js.map +1 -0
- package/dist/commands/{init.js → init/init.js} +146 -71
- package/dist/commands/init/init.js.map +1 -0
- package/dist/commands/init/mcp.js +131 -0
- package/dist/commands/init/mcp.js.map +1 -0
- package/dist/commands/init/options.js +78 -0
- package/dist/commands/init/options.js.map +1 -0
- package/dist/commands/instructions.js +82 -14
- package/dist/commands/instructions.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +65 -0
- package/dist/commands/list/campaign/campaign.js.map +1 -0
- package/dist/commands/list/campaign/owners.js +65 -0
- package/dist/commands/list/campaign/owners.js.map +1 -0
- package/dist/commands/list/json.js +157 -0
- package/dist/commands/list/json.js.map +1 -0
- package/dist/commands/list/list.js +343 -0
- package/dist/commands/list/list.js.map +1 -0
- package/dist/commands/list/print.js +301 -0
- package/dist/commands/list/print.js.map +1 -0
- package/dist/commands/list/review.js +120 -0
- package/dist/commands/list/review.js.map +1 -0
- package/dist/commands/list/views.js +105 -0
- package/dist/commands/list/views.js.map +1 -0
- package/dist/commands/mcp/dispatch.js +183 -0
- package/dist/commands/mcp/dispatch.js.map +1 -0
- package/dist/commands/mcp/mcp.js +34 -0
- package/dist/commands/mcp/mcp.js.map +1 -0
- package/dist/commands/mcp/serve.js +55 -0
- package/dist/commands/mcp/serve.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/active.js +170 -0
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
- package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/living.js +62 -0
- package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/stage.js +142 -0
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/target.js +219 -0
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js +91 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/error.js +19 -0
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js +170 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/paths.js +43 -0
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/read.js +49 -0
- package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
- package/dist/commands/migrate-openspec/print.js +89 -0
- package/dist/commands/migrate-openspec/print.js.map +1 -0
- package/dist/commands/new/commit.js +76 -0
- package/dist/commands/new/commit.js.map +1 -0
- package/dist/commands/new/new.js +283 -0
- package/dist/commands/new/new.js.map +1 -0
- package/dist/commands/new/templates.js +355 -0
- package/dist/commands/new/templates.js.map +1 -0
- package/dist/commands/open.js +203 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/policy/format.js +152 -0
- package/dist/commands/policy/format.js.map +1 -0
- package/dist/commands/{docs-repo-gate.js → policy/gate.js} +11 -11
- package/dist/commands/policy/gate.js.map +1 -0
- package/dist/commands/rebase/edit.js +106 -0
- package/dist/commands/rebase/edit.js.map +1 -0
- package/dist/commands/rebase/living.js +185 -0
- package/dist/commands/rebase/living.js.map +1 -0
- package/dist/commands/rebase/plan.js +245 -0
- package/dist/commands/rebase/plan.js.map +1 -0
- package/dist/commands/rebase/rebase.js +275 -0
- package/dist/commands/rebase/rebase.js.map +1 -0
- package/dist/commands/seed/commit.js +192 -0
- package/dist/commands/seed/commit.js.map +1 -0
- package/dist/commands/seed/plan.js +133 -0
- package/dist/commands/seed/plan.js.map +1 -0
- package/dist/commands/seed/seed.js +172 -0
- package/dist/commands/seed/seed.js.map +1 -0
- package/dist/commands/show/feature.js +178 -0
- package/dist/commands/show/feature.js.map +1 -0
- package/dist/commands/show/marks.js +24 -0
- package/dist/commands/show/marks.js.map +1 -0
- package/dist/commands/{show.js → show/service.js} +63 -152
- package/dist/commands/show/service.js.map +1 -0
- package/dist/commands/show/show.js +77 -0
- package/dist/commands/show/show.js.map +1 -0
- package/dist/commands/status/json.js +45 -0
- package/dist/commands/status/json.js.map +1 -0
- package/dist/commands/status/print.js +157 -0
- package/dist/commands/status/print.js.map +1 -0
- package/dist/commands/status/status.js +119 -0
- package/dist/commands/status/status.js.map +1 -0
- package/dist/commands/steps/steps.js +189 -0
- package/dist/commands/steps/steps.js.map +1 -0
- package/dist/commands/subsystem/edit.js +192 -0
- package/dist/commands/subsystem/edit.js.map +1 -0
- package/dist/commands/subsystem/move.js +265 -0
- package/dist/commands/subsystem/move.js.map +1 -0
- package/dist/commands/subsystem/query.js +115 -0
- package/dist/commands/subsystem/query.js.map +1 -0
- package/dist/commands/subsystem/subsystem.js +101 -0
- package/dist/commands/subsystem/subsystem.js.map +1 -0
- package/dist/commands/subsystem/sync.js +103 -0
- package/dist/commands/subsystem/sync.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +94 -0
- package/dist/commands/subsystem/txn/txn.js.map +1 -0
- package/dist/commands/subsystem/txn/views.js +70 -0
- package/dist/commands/subsystem/txn/views.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +160 -0
- package/dist/commands/unarchive/manifest.js.map +1 -0
- package/dist/commands/{unarchive.js → unarchive/restore.js} +47 -160
- package/dist/commands/unarchive/restore.js.map +1 -0
- package/dist/commands/unarchive/unarchive.js +67 -0
- package/dist/commands/unarchive/unarchive.js.map +1 -0
- package/dist/commands/validate/arch-coverage.js +194 -0
- package/dist/commands/validate/arch-coverage.js.map +1 -0
- package/dist/commands/validate/checks/fleet-shape.js +296 -0
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
- package/dist/commands/validate/checks/health-deps.js +55 -0
- package/dist/commands/validate/checks/health-deps.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +254 -0
- package/dist/commands/validate/checks/requirements.js.map +1 -0
- package/dist/commands/validate/checks/sources.js +76 -0
- package/dist/commands/validate/checks/sources.js.map +1 -0
- package/dist/commands/validate/checks/vocabulary.js +31 -0
- package/dist/commands/validate/checks/vocabulary.js.map +1 -0
- package/dist/commands/validate/feature.js +216 -0
- package/dist/commands/validate/feature.js.map +1 -0
- package/dist/commands/validate/fleet/census.js +69 -0
- package/dist/commands/validate/fleet/census.js.map +1 -0
- package/dist/commands/validate/fleet/kind-tags.js +39 -0
- package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
- package/dist/commands/validate/fleet/landscape.js +353 -0
- package/dist/commands/validate/fleet/landscape.js.map +1 -0
- package/dist/commands/validate/fleet/load.js +52 -0
- package/dist/commands/validate/fleet/load.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +236 -0
- package/dist/commands/validate/fleet/obligations.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/print.js +63 -0
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js +156 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/capability-tag.js +94 -0
- package/dist/commands/validate/fleet/usecases/capability-tag.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/place.js +13 -0
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/requirement-tag.js +95 -0
- package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/steps.js +197 -0
- package/dist/commands/validate/fleet/usecases/steps.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/usecases.js +99 -0
- package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +40 -0
- package/dist/commands/validate/fleet/views/ids.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +59 -0
- package/dist/commands/validate/fleet/views/stale.js.map +1 -0
- package/dist/commands/validate/links/corpus.js +92 -0
- package/dist/commands/validate/links/corpus.js.map +1 -0
- package/dist/commands/validate/links/glossary.js +75 -0
- package/dist/commands/validate/links/glossary.js.map +1 -0
- package/dist/commands/validate/report.js +269 -0
- package/dist/commands/validate/report.js.map +1 -0
- package/dist/commands/validate/service/api.js +338 -0
- package/dist/commands/validate/service/api.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +219 -0
- package/dist/commands/validate/service/events/events.js.map +1 -0
- package/dist/commands/validate/service/events/message-producers.js +77 -0
- package/dist/commands/validate/service/events/message-producers.js.map +1 -0
- package/dist/commands/validate/service/evidence-pins.js +131 -0
- package/dist/commands/validate/service/evidence-pins.js.map +1 -0
- package/dist/commands/validate/service/service.js +250 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +219 -0
- package/dist/commands/validate/service/specs.js.map +1 -0
- package/dist/commands/validate/service/spine.js +113 -0
- package/dist/commands/validate/service/spine.js.map +1 -0
- package/dist/commands/validate/validate.js +338 -0
- package/dist/commands/validate/validate.js.map +1 -0
- package/dist/commands/verify/cross/diff.js +182 -0
- package/dist/commands/verify/cross/diff.js.map +1 -0
- package/dist/commands/verify/evidence/contract.js +32 -0
- package/dist/commands/verify/evidence/contract.js.map +1 -0
- package/dist/commands/verify/evidence/pins.js +52 -0
- package/dist/commands/verify/evidence/pins.js.map +1 -0
- package/dist/commands/verify/evidence/read.js +72 -0
- package/dist/commands/verify/evidence/read.js.map +1 -0
- package/dist/commands/verify/frozen.js +241 -0
- package/dist/commands/verify/frozen.js.map +1 -0
- package/dist/commands/verify/record.js +226 -0
- package/dist/commands/verify/record.js.map +1 -0
- package/dist/commands/verify/report.js +223 -0
- package/dist/commands/verify/report.js.map +1 -0
- package/dist/commands/verify/results.js +246 -0
- package/dist/commands/verify/results.js.map +1 -0
- package/dist/commands/verify/verify.js +217 -0
- package/dist/commands/verify/verify.js.map +1 -0
- package/dist/commands/vouch/contract.js +11 -0
- package/dist/commands/vouch/contract.js.map +1 -0
- package/dist/commands/vouch/pack/contract.js +2 -0
- package/dist/commands/vouch/pack/contract.js.map +1 -0
- package/dist/commands/vouch/pack/pack.js +266 -0
- package/dist/commands/vouch/pack/pack.js.map +1 -0
- package/dist/commands/vouch/pack/print.js +271 -0
- package/dist/commands/vouch/pack/print.js.map +1 -0
- package/dist/commands/vouch/pack/sections.js +142 -0
- package/dist/commands/vouch/pack/sections.js.map +1 -0
- package/dist/commands/vouch/prompt/confirm.js +46 -0
- package/dist/commands/vouch/prompt/confirm.js.map +1 -0
- package/dist/commands/vouch/report.js +101 -0
- package/dist/commands/vouch/report.js.map +1 -0
- package/dist/commands/vouch/run.js +285 -0
- package/dist/commands/vouch/run.js.map +1 -0
- package/dist/commands/vouch/sample/plan.js +125 -0
- package/dist/commands/vouch/sample/plan.js.map +1 -0
- package/dist/commands/vouch/sample/print.js +109 -0
- package/dist/commands/vouch/sample/print.js.map +1 -0
- package/dist/commands/vouch/vet/verify.js +123 -0
- package/dist/commands/vouch/vet/verify.js.map +1 -0
- package/dist/commands/vouch/vouch.js +176 -0
- package/dist/commands/vouch/vouch.js.map +1 -0
- package/dist/core/agent/agents-md/artifacts.js +220 -0
- package/dist/core/agent/agents-md/artifacts.js.map +1 -0
- package/dist/core/agent/agents-md/command-map.js +324 -0
- package/dist/core/agent/agents-md/command-map.js.map +1 -0
- package/dist/core/agent/agents-md/cycle.js +165 -0
- package/dist/core/agent/agents-md/cycle.js.map +1 -0
- package/dist/core/agent/agents-md/map/explain.js +34 -0
- package/dist/core/agent/agents-md/map/explain.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/context.js +41 -0
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js +46 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js +57 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
- package/dist/core/agent/agents-md/map/mcp.js +41 -0
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
- package/dist/core/agent/agents-md/map/status.js +62 -0
- package/dist/core/agent/agents-md/map/status.js.map +1 -0
- package/dist/core/agent/agents-md/map/subsystem.js +32 -0
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
- package/dist/core/agent/agents-md/map/usecases.js +60 -0
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
- package/dist/core/agent/agents-md/refusals.js +246 -0
- package/dist/core/agent/agents-md/refusals.js.map +1 -0
- package/dist/core/agent/agents-md/shipped/archive-gate.js +98 -0
- package/dist/core/agent/agents-md/shipped/archive-gate.js.map +1 -0
- package/dist/core/agent/agents-md/spine.js +40 -0
- package/dist/core/agent/agents-md/spine.js.map +1 -0
- package/dist/core/agent/agents-md.js +170 -0
- package/dist/core/agent/agents-md.js.map +1 -0
- package/dist/core/agent/agents-stamp.js +155 -0
- package/dist/core/agent/agents-stamp.js.map +1 -0
- package/dist/core/agent/contract.js +2 -0
- package/dist/core/agent/contract.js.map +1 -0
- package/dist/core/agent/protocol.js +193 -0
- package/dist/core/agent/protocol.js.map +1 -0
- package/dist/core/agent/scaffold.js +259 -0
- package/dist/core/agent/scaffold.js.map +1 -0
- package/dist/core/agent/support/report.js +103 -0
- package/dist/core/agent/support/report.js.map +1 -0
- package/dist/core/agent/tools/dialects.js +150 -0
- package/dist/core/agent/tools/dialects.js.map +1 -0
- package/dist/core/agent/tools/registry.js +228 -0
- package/dist/core/agent/tools/registry.js.map +1 -0
- package/dist/core/agent/workflows/adopt.js +133 -0
- package/dist/core/agent/workflows/adopt.js.map +1 -0
- package/dist/core/agent/workflows/check.js +334 -0
- package/dist/core/agent/workflows/check.js.map +1 -0
- package/dist/core/agent/workflows/closing.js +262 -0
- package/dist/core/agent/workflows/closing.js.map +1 -0
- package/dist/core/agent/workflows/feature.js +105 -0
- package/dist/core/agent/workflows/feature.js.map +1 -0
- package/dist/core/agent/workflows/implement.js +105 -0
- package/dist/core/agent/workflows/implement.js.map +1 -0
- package/dist/core/agent/workflows/reference/authoring.js +209 -0
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
- package/dist/core/agent/workflows/reference/codes.js +65 -0
- package/dist/core/agent/workflows/reference/codes.js.map +1 -0
- package/dist/core/agent/workflows/reference/done-check.js +188 -0
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +16 -0
- package/dist/core/agent/workflows/reference/reference.js.map +1 -0
- package/dist/core/agent/workflows/reference/spine.js +297 -0
- package/dist/core/agent/workflows/reference/spine.js.map +1 -0
- package/dist/core/asyncapi/baseline/plan.js +110 -0
- package/dist/core/asyncapi/baseline/plan.js.map +1 -0
- package/dist/core/asyncapi/baseline/surfaces.js +54 -0
- package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
- package/dist/core/asyncapi/depth.js +164 -0
- package/dist/core/asyncapi/depth.js.map +1 -0
- package/dist/core/asyncapi/digest.js +141 -0
- package/dist/core/asyncapi/digest.js.map +1 -0
- package/dist/core/asyncapi/merge/components.js +91 -0
- package/dist/core/asyncapi/merge/components.js.map +1 -0
- package/dist/core/asyncapi/merge/error.js +33 -0
- package/dist/core/asyncapi/merge/error.js.map +1 -0
- package/dist/core/asyncapi/merge/markers.js +308 -0
- package/dist/core/asyncapi/merge/markers.js.map +1 -0
- package/dist/core/asyncapi/merge/merge.js +215 -0
- package/dist/core/asyncapi/merge/merge.js.map +1 -0
- package/dist/core/asyncapi/merge/pin.js +107 -0
- package/dist/core/asyncapi/merge/pin.js.map +1 -0
- package/dist/core/asyncapi/model.js +11 -0
- package/dist/core/asyncapi/model.js.map +1 -0
- package/dist/core/asyncapi/producers.js +50 -0
- package/dist/core/asyncapi/producers.js.map +1 -0
- package/dist/core/asyncapi/read.js +239 -0
- package/dist/core/asyncapi/read.js.map +1 -0
- package/dist/core/brief/brief.js +225 -0
- package/dist/core/brief/brief.js.map +1 -0
- package/dist/core/brief/checks.js +250 -0
- package/dist/core/brief/checks.js.map +1 -0
- package/dist/core/brief/landscape.js +194 -0
- package/dist/core/brief/landscape.js.map +1 -0
- package/dist/core/brief/targets.js +226 -0
- package/dist/core/brief/targets.js.map +1 -0
- package/dist/core/brief/unchecked.js +47 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +282 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/likec4.js +88 -0
- package/dist/core/c4/likec4.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js +132 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
- package/dist/core/c4/parsed/specification.js +78 -0
- package/dist/core/c4/parsed/specification.js.map +1 -0
- package/dist/core/c4/parsed/values.js +57 -0
- package/dist/core/c4/parsed/values.js.map +1 -0
- package/dist/core/c4/parsed/view-ids.js +75 -0
- package/dist/core/c4/parsed/view-ids.js.map +1 -0
- package/dist/core/c4/project/architecture.js +45 -0
- package/dist/core/c4/project/architecture.js.map +1 -0
- package/dist/core/c4/project/documents.js +58 -0
- package/dist/core/c4/project/documents.js.map +1 -0
- package/dist/core/c4/project/load.js +183 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/resolve/service.js +113 -0
- package/dist/core/c4/resolve/service.js.map +1 -0
- package/dist/core/c4/seed/fleet-file.js +201 -0
- package/dist/core/c4/seed/fleet-file.js.map +1 -0
- package/dist/core/c4/seed/items.js +91 -0
- package/dist/core/c4/seed/items.js.map +1 -0
- package/dist/core/c4/seed/stamp.js +48 -0
- package/dist/core/c4/seed/stamp.js.map +1 -0
- package/dist/core/c4/seed/template.js +109 -0
- package/dist/core/c4/seed/template.js.map +1 -0
- package/dist/core/c4/source-mask.js +82 -0
- package/dist/core/c4/source-mask.js.map +1 -0
- package/dist/core/c4/source-scan.js +227 -0
- package/dist/core/c4/source-scan.js.map +1 -0
- package/dist/core/c4/splice/authored-source.js +101 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -0
- package/dist/core/c4/splice/contract.js +10 -0
- package/dist/core/c4/splice/contract.js.map +1 -0
- package/dist/core/c4/splice/delta-blocks.js +126 -0
- package/dist/core/c4/splice/delta-blocks.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +36 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +269 -0
- package/dist/core/c4/splice/landscape-merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +194 -0
- package/dist/core/c4/splice/placement.js.map +1 -0
- package/dist/core/c4/workspace.js +172 -0
- package/dist/core/c4/workspace.js.map +1 -0
- package/dist/core/capabilities/authoring/notes.js +141 -0
- package/dist/core/capabilities/authoring/notes.js.map +1 -0
- package/dist/core/capabilities/capabilities.js +124 -0
- package/dist/core/capabilities/capabilities.js.map +1 -0
- package/dist/core/capabilities/delta/doc.js +50 -0
- package/dist/core/capabilities/delta/doc.js.map +1 -0
- package/dist/core/capabilities/delta/overlay.js +129 -0
- package/dist/core/capabilities/delta/overlay.js.map +1 -0
- package/dist/core/capabilities/delta/summary.js +57 -0
- package/dist/core/capabilities/delta/summary.js.map +1 -0
- package/dist/core/capabilities/delta/tree.js +43 -0
- package/dist/core/capabilities/delta/tree.js.map +1 -0
- package/dist/core/capabilities/delta/uncovered.js +222 -0
- package/dist/core/capabilities/delta/uncovered.js.map +1 -0
- package/dist/core/capabilities/findings.js +342 -0
- package/dist/core/capabilities/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/findings.js +181 -0
- package/dist/core/capabilities/realizes/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/join.js +143 -0
- package/dist/core/capabilities/realizes/join.js.map +1 -0
- package/dist/core/capabilities/rollup.js +199 -0
- package/dist/core/capabilities/rollup.js.map +1 -0
- package/dist/core/capabilities/tree.js +126 -0
- package/dist/core/capabilities/tree.js.map +1 -0
- package/dist/core/capabilities/usecase-join.js +277 -0
- package/dist/core/capabilities/usecase-join.js.map +1 -0
- package/dist/core/coherence/authoring/scaffold.js +177 -0
- package/dist/core/coherence/authoring/scaffold.js.map +1 -0
- package/dist/core/coherence/authoring/sentinels.js +74 -0
- package/dist/core/coherence/authoring/sentinels.js.map +1 -0
- package/dist/core/coherence/coherence.js +251 -0
- package/dist/core/coherence/coherence.js.map +1 -0
- package/dist/core/coherence/declared.js +269 -0
- package/dist/core/coherence/declared.js.map +1 -0
- package/dist/core/coherence/events/declared.js +206 -0
- package/dist/core/coherence/events/declared.js.map +1 -0
- package/dist/core/coherence/events/events.js +204 -0
- package/dist/core/coherence/events/events.js.map +1 -0
- package/dist/core/coherence/events/grades.js +166 -0
- package/dist/core/coherence/events/grades.js.map +1 -0
- package/dist/core/coherence/events/lookups.js +122 -0
- package/dist/core/coherence/events/lookups.js.map +1 -0
- package/dist/core/coherence/events/merged.js +40 -0
- package/dist/core/coherence/events/merged.js.map +1 -0
- package/dist/core/coherence/living.js +198 -0
- package/dist/core/coherence/living.js.map +1 -0
- package/dist/core/coherence/lookups.js +155 -0
- package/dist/core/coherence/lookups.js.map +1 -0
- package/dist/core/coherence/pending.js +39 -0
- package/dist/core/coherence/pending.js.map +1 -0
- package/dist/core/conflict-markers.js +60 -0
- package/dist/core/conflict-markers.js.map +1 -0
- package/dist/core/delta/claims.js +73 -0
- package/dist/core/delta/claims.js.map +1 -0
- package/dist/core/delta/delta.js +296 -0
- package/dist/core/delta/delta.js.map +1 -0
- package/dist/core/delta/document.js +177 -0
- package/dist/core/delta/document.js.map +1 -0
- package/dist/core/delta/scope.js +48 -0
- package/dist/core/delta/scope.js.map +1 -0
- package/dist/core/delta/select.js +237 -0
- package/dist/core/delta/select.js.map +1 -0
- package/dist/core/dependencies/dependencies.js +141 -0
- package/dist/core/dependencies/dependencies.js.map +1 -0
- package/dist/core/dependencies/facts.js +165 -0
- package/dist/core/dependencies/facts.js.map +1 -0
- package/dist/core/dependencies/fanin.js +88 -0
- package/dist/core/dependencies/fanin.js.map +1 -0
- package/dist/core/dependencies/graph.js +106 -0
- package/dist/core/dependencies/graph.js.map +1 -0
- package/dist/core/diff/base-git.js +148 -0
- package/dist/core/diff/base-git.js.map +1 -0
- package/dist/core/diff/base-state.js +209 -0
- package/dist/core/diff/base-state.js.map +1 -0
- package/dist/core/diff/current-state.js +96 -0
- package/dist/core/diff/current-state.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +188 -0
- package/dist/core/diff/scope/changed-paths.js.map +1 -0
- package/dist/core/diff/semantic.js +243 -0
- package/dist/core/diff/semantic.js.map +1 -0
- package/dist/core/diff/victims.js +247 -0
- package/dist/core/diff/victims.js.map +1 -0
- package/dist/core/docs.js +59 -55
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +222 -0
- package/dist/core/doctor/agents.js.map +1 -0
- package/dist/core/doctor/config.js +135 -0
- package/dist/core/doctor/config.js.map +1 -0
- package/dist/core/doctor/doctor.js +275 -0
- package/dist/core/doctor/doctor.js.map +1 -0
- package/dist/core/doctor/report.js +13 -0
- package/dist/core/doctor/report.js.map +1 -0
- package/dist/core/doctor/residue.js +110 -0
- package/dist/core/doctor/residue.js.map +1 -0
- package/dist/core/document/apply.js +77 -0
- package/dist/core/document/apply.js.map +1 -0
- package/dist/core/{frontmatter.js → document/frontmatter.js} +48 -2
- package/dist/core/document/frontmatter.js.map +1 -0
- package/dist/core/document/grammar/directives.js +143 -0
- package/dist/core/document/grammar/directives.js.map +1 -0
- package/dist/core/document/parse.js +263 -0
- package/dist/core/document/parse.js.map +1 -0
- package/dist/core/document/scenarios.js +221 -0
- package/dist/core/document/scenarios.js.map +1 -0
- package/dist/core/document/spec.js +241 -0
- package/dist/core/document/spec.js.map +1 -0
- package/dist/core/{config.js → envelope/config.js} +79 -18
- package/dist/core/envelope/config.js.map +1 -0
- package/dist/core/envelope/json.js +175 -0
- package/dist/core/envelope/json.js.map +1 -0
- package/dist/core/{version.js → envelope/version.js} +3 -3
- package/dist/core/envelope/version.js.map +1 -0
- package/dist/core/explain/families.js +175 -0
- package/dist/core/explain/families.js.map +1 -0
- package/dist/core/explain/fix-tables.js +178 -0
- package/dist/core/explain/fix-tables.js.map +1 -0
- package/dist/core/explain/lookup.js +181 -0
- package/dist/core/explain/lookup.js.map +1 -0
- package/dist/core/explain/refusals.js +49 -0
- package/dist/core/explain/refusals.js.map +1 -0
- package/dist/core/explain/terms.js +144 -0
- package/dist/core/explain/terms.js.map +1 -0
- package/dist/core/explore/describe.js +105 -0
- package/dist/core/explore/describe.js.map +1 -0
- package/dist/core/{explore.js → explore/explore.js} +50 -101
- package/dist/core/explore/explore.js.map +1 -0
- package/dist/core/fleet-context.js +132 -77
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +201 -0
- package/dist/core/gate/checks.js.map +1 -0
- package/dist/core/gate/partners.js +205 -0
- package/dist/core/gate/partners.js.map +1 -0
- package/dist/core/gate/report.js +47 -0
- package/dist/core/gate/report.js.map +1 -0
- package/dist/core/gate/verification.js +113 -0
- package/dist/core/gate/verification.js.map +1 -0
- package/dist/core/gherkin/digest.js +60 -0
- package/dist/core/gherkin/digest.js.map +1 -0
- package/dist/core/gherkin/emit.js +177 -0
- package/dist/core/gherkin/emit.js.map +1 -0
- package/dist/core/gherkin/read.js +76 -0
- package/dist/core/gherkin/read.js.map +1 -0
- package/dist/core/gherkin/stale.js +234 -0
- package/dist/core/gherkin/stale.js.map +1 -0
- package/dist/core/gherkin/stamp.js +77 -0
- package/dist/core/gherkin/stamp.js.map +1 -0
- package/dist/core/gherkin/steps/catalogue.js +154 -0
- package/dist/core/gherkin/steps/catalogue.js.map +1 -0
- package/dist/core/gherkin/steps/inventory.js +98 -0
- package/dist/core/gherkin/steps/inventory.js.map +1 -0
- package/dist/core/gherkin/steps/phrase.js +72 -0
- package/dist/core/gherkin/steps/phrase.js.map +1 -0
- package/dist/core/glossary/delta.js +106 -0
- package/dist/core/glossary/delta.js.map +1 -0
- package/dist/core/glossary/tree.js +86 -0
- package/dist/core/glossary/tree.js.map +1 -0
- package/dist/core/kernel/concurrency.js.map +1 -0
- package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
- package/dist/core/kernel/document-bytes.js.map +1 -0
- package/dist/core/kernel/fences.js +42 -0
- package/dist/core/kernel/fences.js.map +1 -0
- package/dist/core/kernel/ids/capability.js +72 -0
- package/dist/core/kernel/ids/capability.js.map +1 -0
- package/dist/core/kernel/ids/dirs.js +33 -0
- package/dist/core/kernel/ids/dirs.js.map +1 -0
- package/dist/core/kernel/ids/feature.js +75 -0
- package/dist/core/kernel/ids/feature.js.map +1 -0
- package/dist/core/kernel/ids/service.js +156 -0
- package/dist/core/kernel/ids/service.js.map +1 -0
- package/dist/core/kernel/ids/subsystem.js +63 -0
- package/dist/core/kernel/ids/subsystem.js.map +1 -0
- package/dist/core/{path-safety.js → kernel/path-safety.js} +18 -4
- package/dist/core/kernel/path-safety.js.map +1 -0
- package/dist/core/kernel/records.js.map +1 -0
- package/dist/core/links/backlinks.js +68 -0
- package/dist/core/links/backlinks.js.map +1 -0
- package/dist/core/links/case.js +74 -0
- package/dist/core/links/case.js.map +1 -0
- package/dist/core/links/corpus.js +104 -0
- package/dist/core/links/corpus.js.map +1 -0
- package/dist/core/links/findings.js +110 -0
- package/dist/core/links/findings.js.map +1 -0
- package/dist/core/links/parse.js +236 -0
- package/dist/core/links/parse.js.map +1 -0
- package/dist/core/mcp/argv.js +111 -0
- package/dist/core/mcp/argv.js.map +1 -0
- package/dist/core/mcp/author-tools.js +72 -0
- package/dist/core/mcp/author-tools.js.map +1 -0
- package/dist/core/mcp/framing.js +46 -0
- package/dist/core/mcp/framing.js.map +1 -0
- package/dist/core/mcp/protocol.js +280 -0
- package/dist/core/mcp/protocol.js.map +1 -0
- package/dist/core/mcp/tools.js +314 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/obligations/obligations.js +106 -0
- package/dist/core/obligations/obligations.js.map +1 -0
- package/dist/core/openapi/baseline/gate.js +166 -0
- package/dist/core/openapi/baseline/gate.js.map +1 -0
- package/dist/core/openapi/baseline/plan.js +112 -0
- package/dist/core/openapi/baseline/plan.js.map +1 -0
- package/dist/core/openapi/baseline/record.js +175 -0
- package/dist/core/openapi/baseline/record.js.map +1 -0
- package/dist/core/openapi/depth.js +122 -0
- package/dist/core/openapi/depth.js.map +1 -0
- package/dist/core/openapi/digest.js +189 -0
- package/dist/core/openapi/digest.js.map +1 -0
- package/dist/core/{openapi.js → openapi/doc.js} +44 -106
- package/dist/core/openapi/doc.js.map +1 -0
- package/dist/core/openapi/merge/components.js +234 -0
- package/dist/core/openapi/merge/components.js.map +1 -0
- package/dist/core/openapi/merge/error.js +26 -0
- package/dist/core/openapi/merge/error.js.map +1 -0
- package/dist/core/openapi/merge/markers.js +208 -0
- package/dist/core/openapi/merge/markers.js.map +1 -0
- package/dist/core/openapi/merge/merge.js +256 -0
- package/dist/core/openapi/merge/merge.js.map +1 -0
- package/dist/core/openapi/merge/pin.js +128 -0
- package/dist/core/openapi/merge/pin.js.map +1 -0
- package/dist/core/openspec/decide/capabilities.js +244 -0
- package/dist/core/openspec/decide/capabilities.js.map +1 -0
- package/dist/core/openspec/decide/dispositions.js +63 -0
- package/dist/core/openspec/decide/dispositions.js.map +1 -0
- package/dist/core/openspec/decide/renames.js +179 -0
- package/dist/core/openspec/decide/renames.js.map +1 -0
- package/dist/core/openspec/decide/verdict.js +84 -0
- package/dist/core/openspec/decide/verdict.js.map +1 -0
- package/dist/core/openspec/inventory.js +221 -0
- package/dist/core/openspec/inventory.js.map +1 -0
- package/dist/core/openspec/model/mapping.js +76 -0
- package/dist/core/openspec/model/mapping.js.map +1 -0
- package/dist/core/openspec/model/model.js +65 -0
- package/dist/core/openspec/model/model.js.map +1 -0
- package/dist/core/openspec/scan/changes.js +235 -0
- package/dist/core/openspec/scan/changes.js.map +1 -0
- package/dist/core/openspec/scan/config.js +200 -0
- package/dist/core/openspec/scan/config.js.map +1 -0
- package/dist/core/openspec/scan/shape.js +260 -0
- package/dist/core/openspec/scan/shape.js.map +1 -0
- package/dist/core/openspec/scan/walk.js +133 -0
- package/dist/core/openspec/scan/walk.js.map +1 -0
- package/dist/core/openspec/scan/workspace.js +71 -0
- package/dist/core/openspec/scan/workspace.js.map +1 -0
- package/dist/core/owners/codeowners.js +141 -0
- package/dist/core/owners/codeowners.js.map +1 -0
- package/dist/core/pack/features.js +120 -0
- package/dist/core/pack/features.js.map +1 -0
- package/dist/core/pack/joins.js +112 -0
- package/dist/core/pack/joins.js.map +1 -0
- package/dist/core/pack/living.js +118 -0
- package/dist/core/pack/living.js.map +1 -0
- package/dist/core/pack/pack.js +76 -0
- package/dist/core/pack/pack.js.map +1 -0
- package/dist/core/permissions/permissions.js +87 -0
- package/dist/core/permissions/permissions.js.map +1 -0
- package/dist/core/projection/api.js +84 -0
- package/dist/core/projection/api.js.map +1 -0
- package/dist/core/projection/arch-slice.js +63 -0
- package/dist/core/projection/arch-slice.js.map +1 -0
- package/dist/core/projection/events.js +34 -0
- package/dist/core/projection/events.js.map +1 -0
- package/dist/core/provenance/findings.js +208 -0
- package/dist/core/provenance/findings.js.map +1 -0
- package/dist/core/provenance/git.js +225 -0
- package/dist/core/provenance/git.js.map +1 -0
- package/dist/core/provenance/gitq/moves.js +182 -0
- package/dist/core/provenance/gitq/moves.js.map +1 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
- package/dist/core/provenance/sample/scope.js +238 -0
- package/dist/core/provenance/sample/scope.js.map +1 -0
- package/dist/core/provenance/sample/sections.js +61 -0
- package/dist/core/provenance/sample/sections.js.map +1 -0
- package/dist/core/provenance/sources.js +263 -0
- package/dist/core/provenance/sources.js.map +1 -0
- package/dist/core/provenance/stamp.js +232 -0
- package/dist/core/provenance/stamp.js.map +1 -0
- package/dist/core/provenance/walk.js +157 -0
- package/dist/core/provenance/walk.js.map +1 -0
- package/dist/core/repo/authored/paths.js +192 -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 +236 -0
- package/dist/core/repo/paths.js.map +1 -0
- package/dist/core/repo/repo.js +248 -0
- package/dist/core/repo/repo.js.map +1 -0
- package/dist/core/repo/service-target.js +153 -0
- package/dist/core/repo/service-target.js.map +1 -0
- package/dist/core/repo/state.js +58 -0
- package/dist/core/repo/state.js.map +1 -0
- package/dist/core/repo/tree/find.js +52 -0
- package/dist/core/repo/tree/find.js.map +1 -0
- package/dist/core/repo/tree/fs.js +64 -0
- package/dist/core/repo/tree/fs.js.map +1 -0
- package/dist/core/repo/tree/marker.js +61 -0
- package/dist/core/repo/tree/marker.js.map +1 -0
- package/dist/core/repo/tree/views.js +172 -0
- package/dist/core/repo/tree/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +234 -0
- package/dist/core/repo/tree/walk.js.map +1 -0
- package/dist/core/results.js +99 -2
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +131 -0
- package/dist/core/scaffold/landscape.js.map +1 -0
- package/dist/core/scaffold/readme.js +84 -0
- package/dist/core/scaffold/readme.js.map +1 -0
- package/dist/core/staging/commit.js +241 -0
- package/dist/core/staging/commit.js.map +1 -0
- package/dist/core/staging/interrupted.js +96 -0
- package/dist/core/staging/interrupted.js.map +1 -0
- package/dist/core/staging/lock.js +206 -0
- package/dist/core/staging/lock.js.map +1 -0
- package/dist/core/staging/recovery/finding.js +35 -0
- package/dist/core/staging/recovery/finding.js.map +1 -0
- package/dist/core/staging/recovery/intent.js +98 -0
- package/dist/core/staging/recovery/intent.js.map +1 -0
- package/dist/core/staging/recovery/recover.js +126 -0
- package/dist/core/staging/recovery/recover.js.map +1 -0
- package/dist/core/staging/recovery/residue.js +62 -0
- package/dist/core/staging/recovery/residue.js.map +1 -0
- package/dist/core/staging/snapshot.js +202 -0
- package/dist/core/staging/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +171 -0
- package/dist/core/staging/txn/forward.js.map +1 -0
- package/dist/core/staging/txn/journal.js +139 -0
- package/dist/core/staging/txn/journal.js.map +1 -0
- package/dist/core/staging/txn/transaction.js +75 -0
- package/dist/core/staging/txn/transaction.js.map +1 -0
- package/dist/core/staging/writes.js +113 -0
- package/dist/core/staging/writes.js.map +1 -0
- package/dist/core/status/actions/execution.js +49 -0
- package/dist/core/status/actions/execution.js.map +1 -0
- package/dist/core/status/contracts.js +102 -0
- package/dist/core/status/contracts.js.map +1 -0
- package/dist/core/status/feature/artifacts.js +171 -0
- package/dist/core/status/feature/artifacts.js.map +1 -0
- package/dist/core/status/feature/feature.js +207 -0
- package/dist/core/status/feature/feature.js.map +1 -0
- package/dist/core/status/feature/next.js +150 -0
- package/dist/core/status/feature/next.js.map +1 -0
- package/dist/core/status/feature/state.js +21 -0
- package/dist/core/status/feature/state.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +187 -0
- package/dist/core/status/fleet/fleet.js.map +1 -0
- package/dist/core/status/fleet/next.js +207 -0
- package/dist/core/status/fleet/next.js.map +1 -0
- package/dist/core/status/interrupted.js +97 -0
- package/dist/core/status/interrupted.js.map +1 -0
- package/dist/core/status/report.js +31 -0
- package/dist/core/status/report.js.map +1 -0
- package/dist/core/status/scan.js +41 -0
- package/dist/core/status/scan.js.map +1 -0
- package/dist/core/status/verification.js +201 -0
- package/dist/core/status/verification.js.map +1 -0
- package/dist/core/usecases/capability.js +169 -0
- package/dist/core/usecases/capability.js.map +1 -0
- package/dist/core/usecases/delta/claims.js +116 -0
- package/dist/core/usecases/delta/claims.js.map +1 -0
- package/dist/core/usecases/delta/flows.js +103 -0
- package/dist/core/usecases/delta/flows.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +235 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -0
- package/dist/core/usecases/fleet.js +137 -0
- package/dist/core/usecases/fleet.js.map +1 -0
- package/dist/core/usecases/operations.js +111 -0
- package/dist/core/usecases/operations.js.map +1 -0
- package/dist/core/usecases/place.js +44 -0
- package/dist/core/usecases/place.js.map +1 -0
- package/dist/core/usecases/touch.js +101 -0
- package/dist/core/usecases/touch.js.map +1 -0
- package/dist/core/verify/answers.js +173 -0
- package/dist/core/verify/answers.js.map +1 -0
- package/dist/core/verify/build.js +150 -0
- package/dist/core/verify/build.js.map +1 -0
- package/dist/core/verify/checklist.js +201 -0
- package/dist/core/verify/checklist.js.map +1 -0
- package/dist/core/verify/claims/identity.js +61 -0
- package/dist/core/verify/claims/identity.js.map +1 -0
- package/dist/core/verify/cross/diff.js +97 -0
- package/dist/core/verify/cross/diff.js.map +1 -0
- package/dist/core/verify/evidence/contract.js +169 -0
- package/dist/core/verify/evidence/contract.js.map +1 -0
- package/dist/core/verify/file.js +257 -0
- package/dist/core/verify/file.js.map +1 -0
- package/dist/core/verify/pins/lint.js +157 -0
- package/dist/core/verify/pins/lint.js.map +1 -0
- package/dist/core/verify/pins/pin.js +95 -0
- package/dist/core/verify/pins/pin.js.map +1 -0
- package/dist/core/verify/record.js +142 -0
- package/dist/core/verify/record.js.map +1 -0
- package/dist/core/verify/store/commit.js +89 -0
- package/dist/core/verify/store/commit.js.map +1 -0
- package/dist/core/verify/store/render.js +57 -0
- package/dist/core/verify/store/render.js.map +1 -0
- package/dist/core/vocabulary/health.js +91 -0
- package/dist/core/vocabulary/health.js.map +1 -0
- package/dist/core/vocabulary/issue.js +55 -0
- package/dist/core/vocabulary/issue.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +145 -0
- package/dist/core/vocabulary/maturity.js.map +1 -0
- package/dist/core/{report.js → vocabulary/report.js} +30 -2
- package/dist/core/vocabulary/report.js.map +1 -0
- package/dist/core/vocabulary/steps.js +266 -0
- package/dist/core/vocabulary/steps.js.map +1 -0
- package/dist/core/workspace/discover.js +239 -0
- package/dist/core/workspace/discover.js.map +1 -0
- package/dist/core/workspace/render.js +52 -0
- package/dist/core/workspace/render.js.map +1 -0
- package/examples/README.md +189 -0
- package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
- package/examples/docs/architecture/capabilities.yaml +31 -0
- package/examples/docs/architecture/landscape.likec4 +280 -0
- package/examples/docs/architecture/obligations.yaml +23 -0
- package/examples/docs/architecture/permissions.yaml +50 -0
- package/examples/docs/architecture/subsystems.likec4 +11 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +65 -0
- package/examples/docs/capabilities/checkout/spec.md +55 -0
- package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
- package/examples/docs/capabilities/order-notifications/spec.md +43 -0
- package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
- package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
- package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +129 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +28 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
- package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
- package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +70 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
- package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
- package/examples/docs/glossary/order.md +15 -0
- package/examples/docs/glossary/payments/authorization.md +14 -0
- package/examples/docs/likec4.config.json +9 -0
- package/examples/docs/loam.json +3 -0
- package/examples/docs/services/checkout-web/model.likec4 +109 -0
- package/examples/docs/services/checkout-web/spec.md +91 -0
- package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
- package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
- package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
- package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
- package/examples/docs/services/order-service/arch.spec.md +127 -0
- package/examples/docs/services/order-service/asyncapi.yaml +108 -0
- package/examples/docs/services/order-service/health.yaml +57 -0
- package/examples/docs/services/order-service/model.likec4 +138 -0
- package/examples/docs/services/order-service/openapi.yaml +257 -0
- package/examples/docs/services/order-service/runbook.md +62 -0
- package/examples/docs/services/order-service/spec.md +134 -0
- package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
- package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
- package/examples/docs/services/payment-service/arch.spec.md +73 -0
- package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
- package/examples/docs/services/payment-service/health.yaml +39 -0
- package/examples/docs/services/payment-service/model.likec4 +67 -0
- package/examples/docs/services/payment-service/openapi.yaml +151 -0
- package/examples/docs/services/payment-service/runbook.md +37 -0
- package/examples/docs/services/payment-service/spec.md +88 -0
- package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
- package/examples/docs/services/platform/identity-service/arch.spec.md +117 -0
- package/examples/docs/services/platform/identity-service/health.yaml +70 -0
- package/examples/docs/services/platform/identity-service/model.likec4 +83 -0
- package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
- package/examples/docs/services/platform/identity-service/runbook.md +95 -0
- package/examples/docs/services/platform/identity-service/spec.md +119 -0
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +199 -0
- package/examples/docs/services/platform/notification-service/health.yaml +35 -0
- package/examples/docs/services/platform/notification-service/model.likec4 +118 -0
- package/examples/docs/services/platform/notification-service/runbook.md +48 -0
- package/examples/docs/services/platform/notification-service/spec.md +112 -0
- package/examples/docs/services/platform/subsystem.yaml +2 -0
- package/examples/fleet.yaml +57 -0
- package/package.json +19 -6
- package/dist/commands/adopt.js +0 -240
- package/dist/commands/adopt.js.map +0 -1
- package/dist/commands/archive.js +0 -1313
- package/dist/commands/archive.js.map +0 -1
- package/dist/commands/delta.js +0 -388
- package/dist/commands/delta.js.map +0 -1
- package/dist/commands/docs-repo-gate.js.map +0 -1
- package/dist/commands/format.js +0 -17
- package/dist/commands/format.js.map +0 -1
- package/dist/commands/gherkin.js +0 -309
- package/dist/commands/gherkin.js.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/list.js +0 -291
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/migrate-openspec.js +0 -950
- package/dist/commands/migrate-openspec.js.map +0 -1
- package/dist/commands/new.js +0 -413
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/rebase.js +0 -356
- package/dist/commands/rebase.js.map +0 -1
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/status.js +0 -254
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/unarchive.js.map +0 -1
- package/dist/commands/validate.js +0 -1591
- 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 -343
- package/dist/commands/vouch.js.map +0 -1
- package/dist/core/agent.js +0 -2065
- package/dist/core/agent.js.map +0 -1
- package/dist/core/agents-stamp.js +0 -68
- 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/brief.js +0 -733
- 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 -559
- package/dist/core/doctor.js.map +0 -1
- package/dist/core/document-bytes.js.map +0 -1
- package/dist/core/explore.js.map +0 -1
- package/dist/core/frontmatter.js.map +0 -1
- package/dist/core/gherkin.js +0 -463
- package/dist/core/gherkin.js.map +0 -1
- package/dist/core/health.js +0 -67
- package/dist/core/health.js.map +0 -1
- package/dist/core/ids.js +0 -122
- package/dist/core/ids.js.map +0 -1
- package/dist/core/issue.js +0 -9
- package/dist/core/issue.js.map +0 -1
- package/dist/core/json.js +0 -74
- package/dist/core/json.js.map +0 -1
- package/dist/core/likec4.js +0 -479
- 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 -720
- package/dist/core/provenance.js.map +0 -1
- package/dist/core/records.js.map +0 -1
- package/dist/core/repo.js +0 -436
- package/dist/core/repo.js.map +0 -1
- package/dist/core/report.js.map +0 -1
- package/dist/core/spec.js +0 -481
- 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 -1104
- package/dist/core/status.js.map +0 -1
- package/dist/core/steps.js +0 -72
- package/dist/core/steps.js.map +0 -1
- package/dist/core/verify.js +0 -807
- package/dist/core/verify.js.map +0 -1
- package/dist/core/version.js.map +0 -1
- /package/dist/core/{concurrency.js → kernel/concurrency.js} +0 -0
- /package/dist/core/{records.js → kernel/records.js} +0 -0
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `subsystem move` and `subsystem rename` — ONE transaction over N directory
|
|
3
|
+
* renames plus the generated views file, the first real consumer of the
|
|
4
|
+
* journaled txn's moves half (`core/staging/txn/`). The planning lives in
|
|
5
|
+
* this module; the commit window itself is `./txn/txn.ts`, shared with
|
|
6
|
+
* `new` and `rm`.
|
|
7
|
+
*
|
|
8
|
+
* The ONLY move-specific refusal is `move-uncommitted` — git reports
|
|
9
|
+
* uncommitted changes under a directory being moved — and only on positive
|
|
10
|
+
* evidence: where git will not say, the move proceeds. After a landed move
|
|
11
|
+
* loam performs the roadmap's one blessed git write, a best-effort `git add`
|
|
12
|
+
* of the rename pairs and the regenerated views file, so git records the
|
|
13
|
+
* renames as renames and `subsystem history` stays answerable once the user
|
|
14
|
+
* commits. Nothing is ever committed.
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync } from "node:fs";
|
|
17
|
+
import { readFile } from "node:fs/promises";
|
|
18
|
+
import { dirname, join, sep } from "node:path";
|
|
19
|
+
import { parseSubsystemName } from "../../core/kernel/ids/subsystem.js";
|
|
20
|
+
import { isRecord } from "../../core/kernel/records.js";
|
|
21
|
+
import { emitJson, fail, repoPath } from "../../core/envelope/json.js";
|
|
22
|
+
import { gitDirtyPaths, gitStageRenames } from "../../core/provenance/gitq/moves.js";
|
|
23
|
+
import { servicesDir, subsystemPathUnder, subsystemViewsPath } from "../../core/repo/paths.js";
|
|
24
|
+
import { listFeatures } from "../../core/repo/repo.js";
|
|
25
|
+
import { findInTree, nearestTreeNames, treeNames, withinSubsystem } from "../../core/repo/tree/find.js";
|
|
26
|
+
import { SNAPSHOT_COMPAT_VERSION, SNAPSHOT_MANIFEST, snapshotDir } from "../../core/staging/snapshot.js";
|
|
27
|
+
import { commitWindow, reportViews } from "./txn/txn.js";
|
|
28
|
+
import { movedTree } from "./txn/views.js";
|
|
29
|
+
/** `subsystem move <name>... --into <sub|.>` — services and whole subtrees alike. */
|
|
30
|
+
export async function runMove(docsDir, names, into, json) {
|
|
31
|
+
await commitWindow(docsDir, json, async (tree) => {
|
|
32
|
+
const seen = new Set();
|
|
33
|
+
for (const name of names) {
|
|
34
|
+
if (seen.has(name)) {
|
|
35
|
+
fail(json, "invalid-option", `'${name}' is named twice — each service or subsystem moves once.`);
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
seen.add(name);
|
|
39
|
+
}
|
|
40
|
+
const target = resolveTarget(tree, into, { docsDir, json });
|
|
41
|
+
if (target === null)
|
|
42
|
+
return null;
|
|
43
|
+
const moved = [];
|
|
44
|
+
for (const name of names) {
|
|
45
|
+
const hit = findInTree(tree, name);
|
|
46
|
+
if (hit === null) {
|
|
47
|
+
const close = nearestTreeNames(name, treeNames(tree));
|
|
48
|
+
fail(json, "unknown-target", `No service or subsystem '${name}' in the tree.` +
|
|
49
|
+
(close.length > 0 ? ` Close names: ${close.join(", ")}.` : " `loam subsystem list` shows what exists."));
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
moved.push(hit.kind === "service"
|
|
53
|
+
? { name, kind: "service", dir: hit.service.dir, parent: hit.service.subsystem }
|
|
54
|
+
: { name, kind: "subsystem", dir: hit.subsystem.dir, parent: hit.subsystem.path.slice(0, -1) });
|
|
55
|
+
}
|
|
56
|
+
for (const m of moved) {
|
|
57
|
+
if (m.kind === "subsystem" && withinSubsystem([...m.parent, m.name], target.path)) {
|
|
58
|
+
fail(json, "invalid-option", `'${m.name}' cannot move into itself or its own subtree.`);
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
if (m.parent.join("/") === target.path.join("/")) {
|
|
62
|
+
fail(json, "invalid-option", `'${m.name}' is already directly in ${into === "." ? "the services/ root" : `'${into}'`} — nothing to move.`);
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
const inside = moved.find((other) => other.kind === "subsystem" && other !== m && (m.dir + sep).startsWith(other.dir + sep));
|
|
66
|
+
if (inside !== undefined) {
|
|
67
|
+
fail(json, "invalid-option", `'${m.name}' sits inside '${inside.name}', which is also being moved — name only the subtree root.`);
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
if (existsSync(join(target.dir, m.name))) {
|
|
71
|
+
// Unreachable in a healthy flat namespace; a tree already carrying
|
|
72
|
+
// name collisions can produce it, and refusing beats stacking a
|
|
73
|
+
// second directory of the same name.
|
|
74
|
+
fail(json, "already-exists", `${repoPath(docsDir, join(target.dir, m.name))} already exists — fix the name collision first.`);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (await refuseUncommitted(docsDir, moved.map((m) => m.dir), json))
|
|
79
|
+
return null;
|
|
80
|
+
const notices = await v2SnapshotNotices(docsDir, moved.map((m) => m.dir));
|
|
81
|
+
const renames = moved.map((m) => ({ from: m.dir, to: join(target.dir, m.name) }));
|
|
82
|
+
return {
|
|
83
|
+
target: names.join(", "),
|
|
84
|
+
writes: [],
|
|
85
|
+
tree: movedTree(tree, renames, servicesDir(docsDir)),
|
|
86
|
+
moves: renames,
|
|
87
|
+
failedCode: "move-failed",
|
|
88
|
+
what: "moved",
|
|
89
|
+
report: async (views, recovered) => {
|
|
90
|
+
await stageInGit(docsDir, renames);
|
|
91
|
+
const rows = moved.map((m, i) => ({
|
|
92
|
+
name: m.name,
|
|
93
|
+
kind: m.kind,
|
|
94
|
+
from: repoPath(docsDir, renames[i].from),
|
|
95
|
+
to: repoPath(docsDir, renames[i].to),
|
|
96
|
+
}));
|
|
97
|
+
if (json) {
|
|
98
|
+
emitJson({
|
|
99
|
+
command: "subsystem",
|
|
100
|
+
into,
|
|
101
|
+
moved: rows,
|
|
102
|
+
views,
|
|
103
|
+
...(notices.length === 0 ? {} : { warnings: notices }),
|
|
104
|
+
...(recovered === null ? {} : { recovered }),
|
|
105
|
+
});
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
for (const row of rows)
|
|
109
|
+
console.log(`moved ${row.from} -> ${row.to}`);
|
|
110
|
+
for (const n of notices)
|
|
111
|
+
console.log(`note: ${n}`);
|
|
112
|
+
console.log(`Renames staged where git answers; nothing committed${reportViews(views)}.`);
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/** `subsystem rename <old> <new>` — one rename through the same transaction. */
|
|
118
|
+
export async function runRename(docsDir, names, json) {
|
|
119
|
+
const [from, to] = names;
|
|
120
|
+
await commitWindow(docsDir, json, async (tree) => {
|
|
121
|
+
const hit = findInTree(tree, from);
|
|
122
|
+
if (hit === null) {
|
|
123
|
+
const close = nearestTreeNames(from, tree.subsystems.map((s) => s.name));
|
|
124
|
+
fail(json, "unknown-target", `No subsystem '${from}' in the tree.` + (close.length > 0 ? ` Close names: ${close.join(", ")}.` : ""));
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
if (hit.kind === "service") {
|
|
128
|
+
fail(json, "invalid-option", `'${from}' is a service — a service's id IS its identity (loam.json, frontmatter, feature specs all join on it), so loam never renames one.`);
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
const parsed = parseSubsystemName(to, "subsystem name");
|
|
132
|
+
if (!parsed.ok) {
|
|
133
|
+
fail(json, "invalid-option", parsed.problem);
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
const taken = findInTree(tree, to);
|
|
137
|
+
if (taken !== null) {
|
|
138
|
+
const where = taken.kind === "service" ? taken.service.dir : taken.subsystem.dir;
|
|
139
|
+
fail(json, "already-exists", `'${to}' is already a ${taken.kind} (${repoPath(docsDir, where)}) — the namespace is flat at any depth.`);
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
if (await refuseUncommitted(docsDir, [hit.subsystem.dir], json))
|
|
143
|
+
return null;
|
|
144
|
+
const notices = await v2SnapshotNotices(docsDir, [hit.subsystem.dir]);
|
|
145
|
+
const rename = { from: hit.subsystem.dir, to: subsystemPathUnder(dirname(hit.subsystem.dir), parsed.name) };
|
|
146
|
+
return {
|
|
147
|
+
target: `${from} -> ${to}`,
|
|
148
|
+
writes: [],
|
|
149
|
+
tree: movedTree(tree, [rename], servicesDir(docsDir)),
|
|
150
|
+
moves: [rename],
|
|
151
|
+
failedCode: "move-failed",
|
|
152
|
+
what: "renamed",
|
|
153
|
+
report: async (views, recovered) => {
|
|
154
|
+
await stageInGit(docsDir, [rename]);
|
|
155
|
+
if (json) {
|
|
156
|
+
emitJson({
|
|
157
|
+
command: "subsystem",
|
|
158
|
+
renamed: from,
|
|
159
|
+
to,
|
|
160
|
+
path: repoPath(docsDir, rename.to),
|
|
161
|
+
views,
|
|
162
|
+
...(notices.length === 0 ? {} : { warnings: notices }),
|
|
163
|
+
...(recovered === null ? {} : { recovered }),
|
|
164
|
+
});
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
console.log(`renamed subsystem '${from}' -> '${to}' (${repoPath(docsDir, rename.to)}/)${reportViews(views)}`);
|
|
168
|
+
for (const n of notices)
|
|
169
|
+
console.log(`note: ${n}`);
|
|
170
|
+
},
|
|
171
|
+
};
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
/** Where `--into` points: the services/ root for `.`, an existing subsystem otherwise. */
|
|
175
|
+
function resolveTarget(tree, into, at) {
|
|
176
|
+
if (into === ".")
|
|
177
|
+
return { dir: servicesDir(at.docsDir), path: [] };
|
|
178
|
+
const hit = findInTree(tree, into);
|
|
179
|
+
if (hit === null) {
|
|
180
|
+
const close = nearestTreeNames(into, tree.subsystems.map((s) => s.name));
|
|
181
|
+
fail(at.json, "unknown-target", `No subsystem '${into}' to move into.` +
|
|
182
|
+
(close.length > 0 ? ` Close names: ${close.join(", ")}.` : " `--into .` unfiles; `loam subsystem new` creates."));
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
if (hit.kind === "service") {
|
|
186
|
+
fail(at.json, "invalid-option", `--into names the service '${into}' — a service never contains other services.`);
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
return { dir: hit.subsystem.dir, path: hit.subsystem.path };
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* The one move-specific refusal, on positive evidence only: git names
|
|
193
|
+
* uncommitted work under a directory about to be renamed. Null (git will not
|
|
194
|
+
* say) proceeds — a fleet that does not use git must not be refused over it.
|
|
195
|
+
*/
|
|
196
|
+
async function refuseUncommitted(docsDir, dirs, json) {
|
|
197
|
+
const dirty = await gitDirtyPaths(docsDir, dirs.map((d) => repoPath(docsDir, d)));
|
|
198
|
+
if (dirty === null || dirty.length === 0)
|
|
199
|
+
return false;
|
|
200
|
+
fail(json, "move-uncommitted",
|
|
201
|
+
// "or untracked", and `git stash -u` by name: the check fires on ANY
|
|
202
|
+
// porcelain entry, untracked files included, and plain `git stash` does
|
|
203
|
+
// not stash those — advice that said "stash" sent the user in a loop,
|
|
204
|
+
// refused again with the same sentence after doing what it asked.
|
|
205
|
+
`git reports ${dirty.length} uncommitted or untracked path(s) under the directory(ies) being moved: ${dirty.join(", ")}. ` +
|
|
206
|
+
"Renaming now would sweep them into a move nobody reviewed — commit them, `git stash -u`, or remove them, then re-run. " +
|
|
207
|
+
"Nothing was moved.");
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Stage the move's whole delta, silently: the rename pairs (both ends — the
|
|
212
|
+
* delete side and the add side) AND the regenerated views file. The views
|
|
213
|
+
* file rides along for the same reason the transaction writes it in the same
|
|
214
|
+
* commit: a user whose next `git commit` captured the renames without it
|
|
215
|
+
* would commit a tree `validate --all` fails (`subsystem.views-stale`) — the
|
|
216
|
+
* exact "failing between two commits" state the roadmap forbids.
|
|
217
|
+
*/
|
|
218
|
+
async function stageInGit(docsDir, renames) {
|
|
219
|
+
await gitStageRenames(docsDir, [
|
|
220
|
+
...renames.flatMap((r) => [repoPath(docsDir, r.from), repoPath(docsDir, r.to)]),
|
|
221
|
+
repoPath(docsDir, subsystemViewsPath(docsDir)),
|
|
222
|
+
]);
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Which archived features hold a VERSION-2 snapshot addressing a path under
|
|
226
|
+
* one of these directories — the notice, never a refusal, a move prints
|
|
227
|
+
* before it proceeds. A version-2 manifest predates the tree and records
|
|
228
|
+
* literal `services/<id>/…` paths, so after this move an `unarchive --force`
|
|
229
|
+
* of that feature restores into the OLD path, resurrecting the pre-move
|
|
230
|
+
* directory beside the moved one (two claimants, `subsystem.name-collision`
|
|
231
|
+
* — loud, but avoidable by being told now). Version-3 manifests key rows by
|
|
232
|
+
* service id and follow the enumeration, so they are not named. Every
|
|
233
|
+
* failure to read reads as "nothing to warn about": a warning needs positive
|
|
234
|
+
* evidence exactly as the move's one refusal does.
|
|
235
|
+
*/
|
|
236
|
+
async function v2SnapshotNotices(docsDir, dirs) {
|
|
237
|
+
const rels = dirs.map((d) => repoPath(docsDir, d));
|
|
238
|
+
const notices = [];
|
|
239
|
+
let features;
|
|
240
|
+
try {
|
|
241
|
+
features = await listFeatures(docsDir, { includeArchived: true });
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
return notices;
|
|
245
|
+
}
|
|
246
|
+
for (const f of features.filter((entry) => entry.archived)) {
|
|
247
|
+
let manifest;
|
|
248
|
+
try {
|
|
249
|
+
manifest = JSON.parse(await readFile(join(snapshotDir(f.dir), SNAPSHOT_MANIFEST), "utf8"));
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (!isRecord(manifest) || manifest.version !== SNAPSHOT_COMPAT_VERSION || !Array.isArray(manifest.files))
|
|
255
|
+
continue;
|
|
256
|
+
const addressed = rels.filter((rel) => manifest.files.some((row) => isRecord(row) && typeof row.path === "string" && row.path.startsWith(`${rel}/`)));
|
|
257
|
+
if (addressed.length > 0) {
|
|
258
|
+
notices.push(`${f.id}'s archived snapshot is version 2 and addresses ${addressed.join(", ")} by literal path — ` +
|
|
259
|
+
`\`loam unarchive ${f.id} --force\` after this move would restore into the old location, ` +
|
|
260
|
+
`resurrecting the pre-move directory beside the moved one.`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return notices;
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=move.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"move.js","sourceRoot":"","sources":["../../../src/commands/subsystem/move.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `subsystem move` and `subsystem rename` — ONE transaction over N directory\n * renames plus the generated views file, the first real consumer of the\n * journaled txn's moves half (`core/staging/txn/`). The planning lives in\n * this module; the commit window itself is `./txn/txn.ts`, shared with\n * `new` and `rm`.\n *\n * The ONLY move-specific refusal is `move-uncommitted` — git reports\n * uncommitted changes under a directory being moved — and only on positive\n * evidence: where git will not say, the move proceeds. After a landed move\n * loam performs the roadmap's one blessed git write, a best-effort `git add`\n * of the rename pairs and the regenerated views file, so git records the\n * renames as renames and `subsystem history` stays answerable once the user\n * commits. Nothing is ever committed.\n */\nimport { existsSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { dirname, join, sep } from \"node:path\";\nimport type { DocsDir } from \"../../core/kernel/ids/dirs.js\";\nimport { parseSubsystemName } from \"../../core/kernel/ids/subsystem.js\";\nimport { isRecord } from \"../../core/kernel/records.js\";\nimport { emitJson, fail, repoPath } from \"../../core/envelope/json.js\";\nimport { gitDirtyPaths, gitStageRenames } from \"../../core/provenance/gitq/moves.js\";\nimport type { FeatureEntry } from \"../../core/repo/entries.js\";\nimport { servicesDir, subsystemPathUnder, subsystemViewsPath } from \"../../core/repo/paths.js\";\nimport { listFeatures } from \"../../core/repo/repo.js\";\nimport { findInTree, nearestTreeNames, treeNames, withinSubsystem } from \"../../core/repo/tree/find.js\";\nimport type { FleetTree } from \"../../core/repo/tree/walk.js\";\nimport { SNAPSHOT_COMPAT_VERSION, SNAPSHOT_MANIFEST, snapshotDir } from \"../../core/staging/snapshot.js\";\nimport { commitWindow, reportViews, type SubsystemTxn } from \"./txn/txn.js\";\nimport { movedTree } from \"./txn/views.js\";\n\n/** What one name resolved to for a move: where it is, and where it goes. */\ninterface Moved {\n name: string;\n kind: \"service\" | \"subsystem\";\n dir: string;\n /** Path of the CONTAINING directory, as names from services/ down. */\n parent: string[];\n}\n\n/** `subsystem move <name>... --into <sub|.>` — services and whole subtrees alike. */\nexport async function runMove(docsDir: DocsDir, names: string[], into: string, json: boolean): Promise<void> {\n await commitWindow(docsDir, json, async (tree): Promise<SubsystemTxn | null> => {\n const seen = new Set<string>();\n for (const name of names) {\n if (seen.has(name)) {\n fail(json, \"invalid-option\", `'${name}' is named twice — each service or subsystem moves once.`);\n return null;\n }\n seen.add(name);\n }\n const target = resolveTarget(tree, into, { docsDir, json });\n if (target === null) return null;\n const moved: Moved[] = [];\n for (const name of names) {\n const hit = findInTree(tree, name);\n if (hit === null) {\n const close = nearestTreeNames(name, treeNames(tree));\n fail(\n json,\n \"unknown-target\",\n `No service or subsystem '${name}' in the tree.` +\n (close.length > 0 ? ` Close names: ${close.join(\", \")}.` : \" `loam subsystem list` shows what exists.\"),\n );\n return null;\n }\n moved.push(\n hit.kind === \"service\"\n ? { name, kind: \"service\", dir: hit.service.dir, parent: hit.service.subsystem }\n : { name, kind: \"subsystem\", dir: hit.subsystem.dir, parent: hit.subsystem.path.slice(0, -1) },\n );\n }\n for (const m of moved) {\n if (m.kind === \"subsystem\" && withinSubsystem([...m.parent, m.name], target.path)) {\n fail(json, \"invalid-option\", `'${m.name}' cannot move into itself or its own subtree.`);\n return null;\n }\n if (m.parent.join(\"/\") === target.path.join(\"/\")) {\n fail(json, \"invalid-option\", `'${m.name}' is already directly in ${into === \".\" ? \"the services/ root\" : `'${into}'`} — nothing to move.`);\n return null;\n }\n const inside = moved.find(\n (other) => other.kind === \"subsystem\" && other !== m && (m.dir + sep).startsWith(other.dir + sep),\n );\n if (inside !== undefined) {\n fail(json, \"invalid-option\", `'${m.name}' sits inside '${inside.name}', which is also being moved — name only the subtree root.`);\n return null;\n }\n if (existsSync(join(target.dir, m.name))) {\n // Unreachable in a healthy flat namespace; a tree already carrying\n // name collisions can produce it, and refusing beats stacking a\n // second directory of the same name.\n fail(json, \"already-exists\", `${repoPath(docsDir, join(target.dir, m.name))} already exists — fix the name collision first.`);\n return null;\n }\n }\n if (await refuseUncommitted(docsDir, moved.map((m) => m.dir), json)) return null;\n const notices = await v2SnapshotNotices(docsDir, moved.map((m) => m.dir));\n const renames = moved.map((m) => ({ from: m.dir, to: join(target.dir, m.name) }));\n return {\n target: names.join(\", \"),\n writes: [],\n tree: movedTree(tree, renames, servicesDir(docsDir)),\n moves: renames,\n failedCode: \"move-failed\",\n what: \"moved\",\n report: async (views, recovered) => {\n await stageInGit(docsDir, renames);\n const rows = moved.map((m, i) => ({\n name: m.name,\n kind: m.kind,\n from: repoPath(docsDir, renames[i]!.from),\n to: repoPath(docsDir, renames[i]!.to),\n }));\n if (json) {\n emitJson({\n command: \"subsystem\",\n into,\n moved: rows,\n views,\n ...(notices.length === 0 ? {} : { warnings: notices }),\n ...(recovered === null ? {} : { recovered }),\n });\n return;\n }\n for (const row of rows) console.log(`moved ${row.from} -> ${row.to}`);\n for (const n of notices) console.log(`note: ${n}`);\n console.log(`Renames staged where git answers; nothing committed${reportViews(views)}.`);\n },\n };\n });\n}\n\n/** `subsystem rename <old> <new>` — one rename through the same transaction. */\nexport async function runRename(docsDir: DocsDir, names: [string, string], json: boolean): Promise<void> {\n const [from, to] = names;\n await commitWindow(docsDir, json, async (tree): Promise<SubsystemTxn | null> => {\n const hit = findInTree(tree, from);\n if (hit === null) {\n const close = nearestTreeNames(from, tree.subsystems.map((s) => s.name));\n fail(\n json,\n \"unknown-target\",\n `No subsystem '${from}' in the tree.` + (close.length > 0 ? ` Close names: ${close.join(\", \")}.` : \"\"),\n );\n return null;\n }\n if (hit.kind === \"service\") {\n fail(\n json,\n \"invalid-option\",\n `'${from}' is a service — a service's id IS its identity (loam.json, frontmatter, feature specs all join on it), so loam never renames one.`,\n );\n return null;\n }\n const parsed = parseSubsystemName(to, \"subsystem name\");\n if (!parsed.ok) {\n fail(json, \"invalid-option\", parsed.problem);\n return null;\n }\n const taken = findInTree(tree, to);\n if (taken !== null) {\n const where = taken.kind === \"service\" ? taken.service.dir : taken.subsystem.dir;\n fail(json, \"already-exists\", `'${to}' is already a ${taken.kind} (${repoPath(docsDir, where)}) — the namespace is flat at any depth.`);\n return null;\n }\n if (await refuseUncommitted(docsDir, [hit.subsystem.dir], json)) return null;\n const notices = await v2SnapshotNotices(docsDir, [hit.subsystem.dir]);\n const rename = { from: hit.subsystem.dir, to: subsystemPathUnder(dirname(hit.subsystem.dir), parsed.name) };\n return {\n target: `${from} -> ${to}`,\n writes: [],\n tree: movedTree(tree, [rename], servicesDir(docsDir)),\n moves: [rename],\n failedCode: \"move-failed\",\n what: \"renamed\",\n report: async (views, recovered) => {\n await stageInGit(docsDir, [rename]);\n if (json) {\n emitJson({\n command: \"subsystem\",\n renamed: from,\n to,\n path: repoPath(docsDir, rename.to),\n views,\n ...(notices.length === 0 ? {} : { warnings: notices }),\n ...(recovered === null ? {} : { recovered }),\n });\n return;\n }\n console.log(`renamed subsystem '${from}' -> '${to}' (${repoPath(docsDir, rename.to)}/)${reportViews(views)}`);\n for (const n of notices) console.log(`note: ${n}`);\n },\n };\n });\n}\n\n/** Where `--into` points: the services/ root for `.`, an existing subsystem otherwise. */\nfunction resolveTarget(tree: FleetTree, into: string, at: { docsDir: DocsDir; json: boolean }): { dir: string; path: string[] } | null {\n if (into === \".\") return { dir: servicesDir(at.docsDir), path: [] };\n const hit = findInTree(tree, into);\n if (hit === null) {\n const close = nearestTreeNames(into, tree.subsystems.map((s) => s.name));\n fail(\n at.json,\n \"unknown-target\",\n `No subsystem '${into}' to move into.` +\n (close.length > 0 ? ` Close names: ${close.join(\", \")}.` : \" `--into .` unfiles; `loam subsystem new` creates.\"),\n );\n return null;\n }\n if (hit.kind === \"service\") {\n fail(at.json, \"invalid-option\", `--into names the service '${into}' — a service never contains other services.`);\n return null;\n }\n return { dir: hit.subsystem.dir, path: hit.subsystem.path };\n}\n\n/**\n * The one move-specific refusal, on positive evidence only: git names\n * uncommitted work under a directory about to be renamed. Null (git will not\n * say) proceeds — a fleet that does not use git must not be refused over it.\n */\nasync function refuseUncommitted(docsDir: DocsDir, dirs: string[], json: boolean): Promise<boolean> {\n const dirty = await gitDirtyPaths(docsDir, dirs.map((d) => repoPath(docsDir, d)));\n if (dirty === null || dirty.length === 0) return false;\n fail(\n json,\n \"move-uncommitted\",\n // \"or untracked\", and `git stash -u` by name: the check fires on ANY\n // porcelain entry, untracked files included, and plain `git stash` does\n // not stash those — advice that said \"stash\" sent the user in a loop,\n // refused again with the same sentence after doing what it asked.\n `git reports ${dirty.length} uncommitted or untracked path(s) under the directory(ies) being moved: ${dirty.join(\", \")}. ` +\n \"Renaming now would sweep them into a move nobody reviewed — commit them, `git stash -u`, or remove them, then re-run. \" +\n \"Nothing was moved.\",\n );\n return true;\n}\n\n/**\n * Stage the move's whole delta, silently: the rename pairs (both ends — the\n * delete side and the add side) AND the regenerated views file. The views\n * file rides along for the same reason the transaction writes it in the same\n * commit: a user whose next `git commit` captured the renames without it\n * would commit a tree `validate --all` fails (`subsystem.views-stale`) — the\n * exact \"failing between two commits\" state the roadmap forbids.\n */\nasync function stageInGit(docsDir: DocsDir, renames: { from: string; to: string }[]): Promise<void> {\n await gitStageRenames(docsDir, [\n ...renames.flatMap((r) => [repoPath(docsDir, r.from), repoPath(docsDir, r.to)]),\n repoPath(docsDir, subsystemViewsPath(docsDir)),\n ]);\n}\n\n/**\n * Which archived features hold a VERSION-2 snapshot addressing a path under\n * one of these directories — the notice, never a refusal, a move prints\n * before it proceeds. A version-2 manifest predates the tree and records\n * literal `services/<id>/…` paths, so after this move an `unarchive --force`\n * of that feature restores into the OLD path, resurrecting the pre-move\n * directory beside the moved one (two claimants, `subsystem.name-collision`\n * — loud, but avoidable by being told now). Version-3 manifests key rows by\n * service id and follow the enumeration, so they are not named. Every\n * failure to read reads as \"nothing to warn about\": a warning needs positive\n * evidence exactly as the move's one refusal does.\n */\nasync function v2SnapshotNotices(docsDir: DocsDir, dirs: string[]): Promise<string[]> {\n const rels = dirs.map((d) => repoPath(docsDir, d));\n const notices: string[] = [];\n let features: FeatureEntry[];\n try {\n features = await listFeatures(docsDir, { includeArchived: true });\n } catch {\n return notices;\n }\n for (const f of features.filter((entry) => entry.archived)) {\n let manifest: unknown;\n try {\n manifest = JSON.parse(await readFile(join(snapshotDir(f.dir), SNAPSHOT_MANIFEST), \"utf8\"));\n } catch {\n continue;\n }\n if (!isRecord(manifest) || manifest.version !== SNAPSHOT_COMPAT_VERSION || !Array.isArray(manifest.files)) continue;\n const addressed = rels.filter((rel) =>\n (manifest.files as unknown[]).some(\n (row) => isRecord(row) && typeof row.path === \"string\" && row.path.startsWith(`${rel}/`),\n ),\n );\n if (addressed.length > 0) {\n notices.push(\n `${f.id}'s archived snapshot is version 2 and addresses ${addressed.join(\", \")} by literal path — ` +\n `\\`loam unarchive ${f.id} --force\\` after this move would restore into the old location, ` +\n `resurrecting the pre-move directory beside the moved one.`,\n );\n }\n }\n return notices;\n}\n"]}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The read verbs: `subsystem list` (the tree with member and unfiled counts)
|
|
3
|
+
* and `subsystem history` (how a service or subsystem moved, asked of git).
|
|
4
|
+
*
|
|
5
|
+
* `history` stays inside the provenance doctrine (`core/provenance/git.ts`):
|
|
6
|
+
* loam asks git and never tells it, and every way git declines reads as "git
|
|
7
|
+
* will not say" — nothing to answer, exit 0, no finding. The question
|
|
8
|
+
* follows a representative FILE (a service's first surviving artifact, a
|
|
9
|
+
* subsystem's marker), because `git log --follow` is defined for one file
|
|
10
|
+
* and prints nothing at all for a directory path; each hop's directories are
|
|
11
|
+
* read off the file's own rename record.
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync } from "node:fs";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { emitJson, fail, repoPath } from "../../core/envelope/json.js";
|
|
16
|
+
import { gitRenameHops, gitRenamePairingAmbiguous } from "../../core/provenance/gitq/moves.js";
|
|
17
|
+
import { servicePathsAt } from "../../core/repo/paths.js";
|
|
18
|
+
import { listFleetTree } from "../../core/repo/repo.js";
|
|
19
|
+
import { findInTree, nearestTreeNames, servicesUnder, treeNames } from "../../core/repo/tree/find.js";
|
|
20
|
+
import { SUBSYSTEM_MARKER } from "../../core/repo/tree/marker.js";
|
|
21
|
+
export async function runList(docsDir, json) {
|
|
22
|
+
const tree = await listFleetTree(docsDir);
|
|
23
|
+
const sorted = [...tree.subsystems].sort((a, b) => (a.path.join("/") < b.path.join("/") ? -1 : 1));
|
|
24
|
+
const unfiled = tree.services.filter((s) => s.subsystem.length === 0).length;
|
|
25
|
+
const memberCount = (sub) => servicesUnder(tree, sub).length;
|
|
26
|
+
if (json) {
|
|
27
|
+
emitJson({
|
|
28
|
+
command: "subsystem",
|
|
29
|
+
subsystems: sorted.map((sub) => ({
|
|
30
|
+
name: sub.name,
|
|
31
|
+
path: repoPath(docsDir, sub.dir),
|
|
32
|
+
title: sub.meta.title ?? null,
|
|
33
|
+
memberCount: memberCount(sub),
|
|
34
|
+
})),
|
|
35
|
+
unfiledServices: unfiled,
|
|
36
|
+
services: tree.services.length,
|
|
37
|
+
});
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (sorted.length === 0) {
|
|
41
|
+
console.log(`no subsystems — the fleet is flat (${tree.services.length} service(s), all unfiled).`);
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
console.log(`subsystems (${sorted.length})`);
|
|
45
|
+
for (const sub of sorted) {
|
|
46
|
+
const indent = " ".repeat(sub.path.length);
|
|
47
|
+
const title = sub.meta.title === undefined ? "" : ` ${sub.meta.title}`;
|
|
48
|
+
console.log(`${indent}${sub.name}${title} — ${memberCount(sub)} service(s)`);
|
|
49
|
+
}
|
|
50
|
+
console.log(`unfiled: ${unfiled} of ${tree.services.length} service(s)`);
|
|
51
|
+
}
|
|
52
|
+
export async function runHistory(docsDir, name, json) {
|
|
53
|
+
const tree = await listFleetTree(docsDir);
|
|
54
|
+
const hit = findInTree(tree, name);
|
|
55
|
+
if (hit === null) {
|
|
56
|
+
const close = nearestTreeNames(name, treeNames(tree));
|
|
57
|
+
fail(json, "unknown-target", `No service or subsystem '${name}' in the tree.` +
|
|
58
|
+
(close.length > 0 ? ` Close names: ${close.join(", ")}.` : ""));
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const kind = hit.kind;
|
|
62
|
+
const file = representativeFile(hit);
|
|
63
|
+
const followed = file === null ? null : await gitRenameHops(docsDir, repoPath(docsDir, file));
|
|
64
|
+
// Every hop is cross-checked against its own commit before it is repeated:
|
|
65
|
+
// `--follow` pairs paths by content, and identical files moved together
|
|
66
|
+
// (empty markers above all) make that pairing a guess — a hop from a
|
|
67
|
+
// directory this subsystem never inhabited. A guessed hop, or a commit the
|
|
68
|
+
// check cannot read, poisons the whole answer, because the hops chain: one
|
|
69
|
+
// untrusted link makes every earlier "from" untrustworthy too.
|
|
70
|
+
let ambiguous = false;
|
|
71
|
+
for (const h of followed ?? []) {
|
|
72
|
+
if ((await gitRenamePairingAmbiguous(docsDir, h.commit, h.to)) !== false) {
|
|
73
|
+
ambiguous = true;
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const hops = ambiguous ? null : followed;
|
|
78
|
+
const parent = (rel) => rel.slice(0, Math.max(0, rel.lastIndexOf("/")));
|
|
79
|
+
const moves = (hops ?? []).map((h) => ({ from: parent(h.from), to: parent(h.to), commit: h.commit }));
|
|
80
|
+
if (json) {
|
|
81
|
+
// Additive honesty key: `answered: false` is git DECLINING (or nothing to
|
|
82
|
+
// follow, or a rename record too ambiguous to trust), not git answering
|
|
83
|
+
// "never moved" — exit 0 either way, no finding.
|
|
84
|
+
emitJson({ command: "subsystem", name, kind, moves, answered: hops !== null });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
if (ambiguous) {
|
|
88
|
+
console.log(`git will not say — a commit in this file's history moved identical files together, ` +
|
|
89
|
+
`so \`git log --follow\` pairs them by guesswork and the hops cannot be trusted. No finding either way.`);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (hops === null) {
|
|
93
|
+
console.log(`git will not say — not a repository, git unavailable, or nothing here to follow. No finding either way.`);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
if (moves.length === 0) {
|
|
97
|
+
console.log(`no recorded moves for '${name}'.`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
for (const m of moves)
|
|
101
|
+
console.log(`${m.from} -> ${m.to} (${m.commit.slice(0, 7)})`);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* The file whose rename record carries the directory's history: a
|
|
105
|
+
* subsystem's own marker; for a service, the first artifact that exists
|
|
106
|
+
* today, in the fixed artifact order — deterministic, so two runs follow the
|
|
107
|
+
* same file. A service with no artifact on disk gives git nothing to follow.
|
|
108
|
+
*/
|
|
109
|
+
function representativeFile(hit) {
|
|
110
|
+
if (hit.kind === "subsystem")
|
|
111
|
+
return join(hit.subsystem.dir, SUBSYSTEM_MARKER);
|
|
112
|
+
const p = servicePathsAt(hit.service.dir);
|
|
113
|
+
return [p.spec, p.model, p.archSpec, p.openapi, p.asyncapi, p.runbook, p.health].find(existsSync) ?? null;
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../../src/commands/subsystem/query.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The read verbs: `subsystem list` (the tree with member and unfiled counts)\n * and `subsystem history` (how a service or subsystem moved, asked of git).\n *\n * `history` stays inside the provenance doctrine (`core/provenance/git.ts`):\n * loam asks git and never tells it, and every way git declines reads as \"git\n * will not say\" — nothing to answer, exit 0, no finding. The question\n * follows a representative FILE (a service's first surviving artifact, a\n * subsystem's marker), because `git log --follow` is defined for one file\n * and prints nothing at all for a directory path; each hop's directories are\n * read off the file's own rename record.\n */\nimport { existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { DocsDir } from \"../../core/kernel/ids/dirs.js\";\nimport { emitJson, fail, repoPath } from \"../../core/envelope/json.js\";\nimport { gitRenameHops, gitRenamePairingAmbiguous } from \"../../core/provenance/gitq/moves.js\";\nimport { servicePathsAt } from \"../../core/repo/paths.js\";\nimport { listFleetTree } from \"../../core/repo/repo.js\";\nimport { findInTree, nearestTreeNames, servicesUnder, treeNames } from \"../../core/repo/tree/find.js\";\nimport { SUBSYSTEM_MARKER } from \"../../core/repo/tree/marker.js\";\nimport type { SubsystemEntry } from \"../../core/repo/tree/walk.js\";\n\nexport async function runList(docsDir: DocsDir, json: boolean): Promise<void> {\n const tree = await listFleetTree(docsDir);\n const sorted = [...tree.subsystems].sort((a, b) => (a.path.join(\"/\") < b.path.join(\"/\") ? -1 : 1));\n const unfiled = tree.services.filter((s) => s.subsystem.length === 0).length;\n const memberCount = (sub: SubsystemEntry): number => servicesUnder(tree, sub).length;\n if (json) {\n emitJson({\n command: \"subsystem\",\n subsystems: sorted.map((sub) => ({\n name: sub.name,\n path: repoPath(docsDir, sub.dir),\n title: sub.meta.title ?? null,\n memberCount: memberCount(sub),\n })),\n unfiledServices: unfiled,\n services: tree.services.length,\n });\n return;\n }\n if (sorted.length === 0) {\n console.log(`no subsystems — the fleet is flat (${tree.services.length} service(s), all unfiled).`);\n return;\n }\n console.log(`subsystems (${sorted.length})`);\n for (const sub of sorted) {\n const indent = \" \".repeat(sub.path.length);\n const title = sub.meta.title === undefined ? \"\" : ` ${sub.meta.title}`;\n console.log(`${indent}${sub.name}${title} — ${memberCount(sub)} service(s)`);\n }\n console.log(`unfiled: ${unfiled} of ${tree.services.length} service(s)`);\n}\n\nexport async function runHistory(docsDir: DocsDir, name: string, json: boolean): Promise<void> {\n const tree = await listFleetTree(docsDir);\n const hit = findInTree(tree, name);\n if (hit === null) {\n const close = nearestTreeNames(name, treeNames(tree));\n fail(\n json,\n \"unknown-target\",\n `No service or subsystem '${name}' in the tree.` +\n (close.length > 0 ? ` Close names: ${close.join(\", \")}.` : \"\"),\n );\n return;\n }\n const kind = hit.kind;\n const file = representativeFile(hit);\n const followed = file === null ? null : await gitRenameHops(docsDir, repoPath(docsDir, file));\n // Every hop is cross-checked against its own commit before it is repeated:\n // `--follow` pairs paths by content, and identical files moved together\n // (empty markers above all) make that pairing a guess — a hop from a\n // directory this subsystem never inhabited. A guessed hop, or a commit the\n // check cannot read, poisons the whole answer, because the hops chain: one\n // untrusted link makes every earlier \"from\" untrustworthy too.\n let ambiguous = false;\n for (const h of followed ?? []) {\n if ((await gitRenamePairingAmbiguous(docsDir, h.commit, h.to)) !== false) {\n ambiguous = true;\n break;\n }\n }\n const hops = ambiguous ? null : followed;\n const parent = (rel: string): string => rel.slice(0, Math.max(0, rel.lastIndexOf(\"/\")));\n const moves = (hops ?? []).map((h) => ({ from: parent(h.from), to: parent(h.to), commit: h.commit }));\n if (json) {\n // Additive honesty key: `answered: false` is git DECLINING (or nothing to\n // follow, or a rename record too ambiguous to trust), not git answering\n // \"never moved\" — exit 0 either way, no finding.\n emitJson({ command: \"subsystem\", name, kind, moves, answered: hops !== null });\n return;\n }\n if (ambiguous) {\n console.log(\n `git will not say — a commit in this file's history moved identical files together, ` +\n `so \\`git log --follow\\` pairs them by guesswork and the hops cannot be trusted. No finding either way.`,\n );\n return;\n }\n if (hops === null) {\n console.log(`git will not say — not a repository, git unavailable, or nothing here to follow. No finding either way.`);\n return;\n }\n if (moves.length === 0) {\n console.log(`no recorded moves for '${name}'.`);\n return;\n }\n for (const m of moves) console.log(`${m.from} -> ${m.to} (${m.commit.slice(0, 7)})`);\n}\n\n/**\n * The file whose rename record carries the directory's history: a\n * subsystem's own marker; for a service, the first artifact that exists\n * today, in the fixed artifact order — deterministic, so two runs follow the\n * same file. A service with no artifact on disk gives git nothing to follow.\n */\nfunction representativeFile(hit: NonNullable<ReturnType<typeof findInTree>>): string | null {\n if (hit.kind === \"subsystem\") return join(hit.subsystem.dir, SUBSYSTEM_MARKER);\n const p = servicePathsAt(hit.service.dir);\n return [p.spec, p.model, p.archSpec, p.openapi, p.asyncapi, p.runbook, p.health].find(existsSync) ?? null;\n}\n"]}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { loadConfig } from "../../core/envelope/config.js";
|
|
2
|
+
import { fail, reportNoConfig } from "../../core/envelope/json.js";
|
|
3
|
+
import { DocsRepoUnavailableError } from "../../core/repo/state.js";
|
|
4
|
+
import { docsRepoReady, reportDocsRepoError } from "../policy/gate.js";
|
|
5
|
+
import { runNew, runRm } from "./edit.js";
|
|
6
|
+
import { runMove, runRename } from "./move.js";
|
|
7
|
+
import { runHistory, runList } from "./query.js";
|
|
8
|
+
import { runSync } from "./sync.js";
|
|
9
|
+
const VERBS = ["new", "move", "rename", "rm", "list", "history", "sync"];
|
|
10
|
+
/** How many names each verb takes, spelled once so the refusals agree with the dispatch. */
|
|
11
|
+
const NAMES = {
|
|
12
|
+
new: { min: 1, max: 1, usage: "subsystem new <name> [--under <sub>] [--title <text>] [--description <text>] [--owner <name>]" },
|
|
13
|
+
move: { min: 1, max: Infinity, usage: "subsystem move <name>... --into <sub|.>" },
|
|
14
|
+
rename: { min: 2, max: 2, usage: "subsystem rename <old> <new>" },
|
|
15
|
+
rm: { min: 1, max: 1, usage: "subsystem rm <name>" },
|
|
16
|
+
list: { min: 0, max: 0, usage: "subsystem list" },
|
|
17
|
+
history: { min: 1, max: 1, usage: "subsystem history <name>" },
|
|
18
|
+
sync: { min: 0, max: 0, usage: "subsystem sync" },
|
|
19
|
+
};
|
|
20
|
+
/** The flag/verb contradictions worth refusing: an ignored flag is a lie about what ran. */
|
|
21
|
+
function flagMisuse(verb, opts) {
|
|
22
|
+
if (opts.into !== undefined && verb !== "move")
|
|
23
|
+
return `--into belongs to 'move' (${NAMES.move.usage}).`;
|
|
24
|
+
if (opts.into === undefined && verb === "move")
|
|
25
|
+
return `'move' needs a destination: ${NAMES.move.usage} ('.' unfiles).`;
|
|
26
|
+
for (const [flag, value] of [
|
|
27
|
+
["--under", opts.under],
|
|
28
|
+
["--title", opts.title],
|
|
29
|
+
["--description", opts.description],
|
|
30
|
+
["--owner", opts.owner],
|
|
31
|
+
]) {
|
|
32
|
+
if (value !== undefined && verb !== "new")
|
|
33
|
+
return `${flag} belongs to 'new' (${NAMES.new.usage}).`;
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
export function registerSubsystem(program) {
|
|
38
|
+
program
|
|
39
|
+
.command("subsystem")
|
|
40
|
+
.description("Manage the subsystem tree under services/ — the grouping no identity depends on")
|
|
41
|
+
.argument("<verb>", VERBS.join(" | "))
|
|
42
|
+
.argument("[names...]", "the subsystem or service names the verb applies to")
|
|
43
|
+
.option("--into <name>", "move: the destination subsystem, or '.' for the services/ root (unfiled)")
|
|
44
|
+
.option("--under <name>", "new: the parent subsystem (default: the services/ root)")
|
|
45
|
+
.option("--title <text>", "new: the subsystem's human title, kept in subsystem.yaml")
|
|
46
|
+
.option("--description <text>", "new: what the group is, kept in subsystem.yaml")
|
|
47
|
+
.option("--owner <name>", "new: who answers for the group, kept in subsystem.yaml")
|
|
48
|
+
.option("--json", "emit the machine contract instead of the human view")
|
|
49
|
+
.action(async (verb, names, opts) => {
|
|
50
|
+
const json = opts.json === true;
|
|
51
|
+
if (!VERBS.includes(verb)) {
|
|
52
|
+
// The same code `list` gives a bad section: one mistake class, one code.
|
|
53
|
+
fail(json, "invalid-option", `Unknown verb '${verb}'. Expected: ${VERBS.join(" | ")}.`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const arity = NAMES[verb];
|
|
57
|
+
if (names.length < arity.min || names.length > arity.max) {
|
|
58
|
+
fail(json, "invalid-option", `'${verb}' takes ${arity.min === arity.max ? arity.min : `${arity.min}+`} name(s): ${arity.usage}`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
const misuse = flagMisuse(verb, opts);
|
|
62
|
+
if (misuse !== null) {
|
|
63
|
+
fail(json, "invalid-option", misuse);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const loaded = await loadConfig();
|
|
67
|
+
if (loaded.kind !== "loaded") {
|
|
68
|
+
reportNoConfig(json, loaded);
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const { docsDir } = loaded.config;
|
|
72
|
+
// "services": every verb reads or rewrites the tree that IS the fleet,
|
|
73
|
+
// so a docsDir with no services/ is a refusal, never an empty answer.
|
|
74
|
+
if (!docsRepoReady(json, docsDir, "services"))
|
|
75
|
+
return;
|
|
76
|
+
try {
|
|
77
|
+
switch (verb) {
|
|
78
|
+
case "new":
|
|
79
|
+
return await runNew(docsDir, names[0], opts, json);
|
|
80
|
+
case "move":
|
|
81
|
+
return await runMove(docsDir, names, opts.into, json);
|
|
82
|
+
case "rename":
|
|
83
|
+
return await runRename(docsDir, [names[0], names[1]], json);
|
|
84
|
+
case "rm":
|
|
85
|
+
return await runRm(docsDir, names[0], json);
|
|
86
|
+
case "list":
|
|
87
|
+
return await runList(docsDir, json);
|
|
88
|
+
case "history":
|
|
89
|
+
return await runHistory(docsDir, names[0], json);
|
|
90
|
+
case "sync":
|
|
91
|
+
return await runSync(docsDir, json);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
if (!(err instanceof DocsRepoUnavailableError))
|
|
96
|
+
throw err;
|
|
97
|
+
reportDocsRepoError(json, err);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=subsystem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subsystem.js","sourceRoot":"","sources":["../../../src/commands/subsystem/subsystem.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `loam subsystem <verb>` — the command surface over the tree under\n * `services/`.\n *\n * ONE registration with the verbs dispatched inside the action, deliberately\n * NOT Commander subcommands: test/agents.test.ts counts the literal\n * command-registration calls across src/commands/ and asserts the count\n * equals `buildProgram()`'s command list, so nested subcommands would\n * register as one command while counting as many literals — the guard would\n * fail in a way that reads as unrelated. (That same scan is why this comment\n * never spells the registration call with its parenthesis.) The option\n * superset is declared here once; the arity table below refuses a flag on a\n * verb that does not read it, because a silently ignored `--into` is a move\n * that did not happen.\n */\nimport type { Command } from \"commander\";\nimport { loadConfig } from \"../../core/envelope/config.js\";\nimport { fail, reportNoConfig } from \"../../core/envelope/json.js\";\nimport { DocsRepoUnavailableError } from \"../../core/repo/state.js\";\nimport { docsRepoReady, reportDocsRepoError } from \"../policy/gate.js\";\nimport { runNew, runRm } from \"./edit.js\";\nimport { runMove, runRename } from \"./move.js\";\nimport { runHistory, runList } from \"./query.js\";\nimport { runSync } from \"./sync.js\";\n\nexport interface SubsystemOptions {\n into?: string;\n under?: string;\n title?: string;\n description?: string;\n owner?: string;\n json?: boolean;\n}\n\nconst VERBS = [\"new\", \"move\", \"rename\", \"rm\", \"list\", \"history\", \"sync\"] as const;\ntype Verb = (typeof VERBS)[number];\n\n/** How many names each verb takes, spelled once so the refusals agree with the dispatch. */\nconst NAMES: Record<Verb, { min: number; max: number; usage: string }> = {\n new: { min: 1, max: 1, usage: \"subsystem new <name> [--under <sub>] [--title <text>] [--description <text>] [--owner <name>]\" },\n move: { min: 1, max: Infinity, usage: \"subsystem move <name>... --into <sub|.>\" },\n rename: { min: 2, max: 2, usage: \"subsystem rename <old> <new>\" },\n rm: { min: 1, max: 1, usage: \"subsystem rm <name>\" },\n list: { min: 0, max: 0, usage: \"subsystem list\" },\n history: { min: 1, max: 1, usage: \"subsystem history <name>\" },\n sync: { min: 0, max: 0, usage: \"subsystem sync\" },\n};\n\n/** The flag/verb contradictions worth refusing: an ignored flag is a lie about what ran. */\nfunction flagMisuse(verb: Verb, opts: SubsystemOptions): string | null {\n if (opts.into !== undefined && verb !== \"move\") return `--into belongs to 'move' (${NAMES.move.usage}).`;\n if (opts.into === undefined && verb === \"move\") return `'move' needs a destination: ${NAMES.move.usage} ('.' unfiles).`;\n for (const [flag, value] of [\n [\"--under\", opts.under],\n [\"--title\", opts.title],\n [\"--description\", opts.description],\n [\"--owner\", opts.owner],\n ] as const) {\n if (value !== undefined && verb !== \"new\") return `${flag} belongs to 'new' (${NAMES.new.usage}).`;\n }\n return null;\n}\n\nexport function registerSubsystem(program: Command): void {\n program\n .command(\"subsystem\")\n .description(\"Manage the subsystem tree under services/ — the grouping no identity depends on\")\n .argument(\"<verb>\", VERBS.join(\" | \"))\n .argument(\"[names...]\", \"the subsystem or service names the verb applies to\")\n .option(\"--into <name>\", \"move: the destination subsystem, or '.' for the services/ root (unfiled)\")\n .option(\"--under <name>\", \"new: the parent subsystem (default: the services/ root)\")\n .option(\"--title <text>\", \"new: the subsystem's human title, kept in subsystem.yaml\")\n .option(\"--description <text>\", \"new: what the group is, kept in subsystem.yaml\")\n .option(\"--owner <name>\", \"new: who answers for the group, kept in subsystem.yaml\")\n .option(\"--json\", \"emit the machine contract instead of the human view\")\n .action(async (verb: string, names: string[], opts: SubsystemOptions) => {\n const json = opts.json === true;\n if (!(VERBS as readonly string[]).includes(verb)) {\n // The same code `list` gives a bad section: one mistake class, one code.\n fail(json, \"invalid-option\", `Unknown verb '${verb}'. Expected: ${VERBS.join(\" | \")}.`);\n return;\n }\n const arity = NAMES[verb as Verb];\n if (names.length < arity.min || names.length > arity.max) {\n fail(json, \"invalid-option\", `'${verb}' takes ${arity.min === arity.max ? arity.min : `${arity.min}+`} name(s): ${arity.usage}`);\n return;\n }\n const misuse = flagMisuse(verb as Verb, opts);\n if (misuse !== null) {\n fail(json, \"invalid-option\", misuse);\n return;\n }\n const loaded = await loadConfig();\n if (loaded.kind !== \"loaded\") {\n reportNoConfig(json, loaded);\n return;\n }\n const { docsDir } = loaded.config;\n // \"services\": every verb reads or rewrites the tree that IS the fleet,\n // so a docsDir with no services/ is a refusal, never an empty answer.\n if (!docsRepoReady(json, docsDir, \"services\")) return;\n try {\n switch (verb as Verb) {\n case \"new\":\n return await runNew(docsDir, names[0]!, opts, json);\n case \"move\":\n return await runMove(docsDir, names, opts.into!, json);\n case \"rename\":\n return await runRename(docsDir, [names[0]!, names[1]!], json);\n case \"rm\":\n return await runRm(docsDir, names[0]!, json);\n case \"list\":\n return await runList(docsDir, json);\n case \"history\":\n return await runHistory(docsDir, names[0]!, json);\n case \"sync\":\n return await runSync(docsDir, json);\n }\n } catch (err) {\n if (!(err instanceof DocsRepoUnavailableError)) throw err;\n reportDocsRepoError(json, err);\n }\n });\n}\n"]}
|