@ybotok/loam 0.2.0-alpha.1 → 0.2.0-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +3448 -0
- package/COMPARISON.md +91 -3
- package/CONTRIBUTING.md +37 -0
- package/MIGRATING-from-OpenSpec.md +47 -23
- package/QUICKSTART.md +189 -12
- package/README.md +274 -65
- package/ROADMAP.md +572 -31
- package/SCHEMA.md +1709 -155
- package/WORKFLOW.md +298 -72
- package/dist/cli.js +26 -8
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +5 -10
- package/dist/commands/adopt/adopt.js.map +1 -1
- package/dist/commands/adopt/render.js +50 -9
- package/dist/commands/adopt/render.js.map +1 -1
- package/dist/commands/archive/archive.js +16 -19
- package/dist/commands/archive/archive.js.map +1 -1
- package/dist/commands/archive/closing.js +42 -0
- package/dist/commands/archive/closing.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +36 -42
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
- package/dist/commands/archive/plan/contracts/consumers.js +56 -0
- package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +77 -43
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
- package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
- package/dist/commands/archive/plan/document/head.js +151 -0
- package/dist/commands/archive/plan/document/head.js.map +1 -0
- package/dist/commands/archive/plan/document/links.js +284 -0
- package/dist/commands/archive/plan/document/links.js.map +1 -0
- package/dist/commands/archive/plan/document/run.js +136 -0
- package/dist/commands/archive/plan/document/run.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +21 -19
- package/dist/commands/archive/plan/gate.js.map +1 -1
- package/dist/commands/archive/plan/landscape.js +167 -30
- package/dist/commands/archive/plan/landscape.js.map +1 -1
- package/dist/commands/archive/plan/model/extending.js +85 -0
- package/dist/commands/archive/plan/model/extending.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +14 -19
- package/dist/commands/archive/plan/refusal.js.map +1 -1
- package/dist/commands/archive/plan/specs.js +137 -56
- package/dist/commands/archive/plan/specs.js.map +1 -1
- package/dist/commands/archive/plan/state.js +3 -0
- package/dist/commands/archive/plan/state.js.map +1 -1
- package/dist/commands/archive/run.js +134 -30
- package/dist/commands/archive/run.js.map +1 -1
- package/dist/commands/archive/shipped.js +49 -0
- package/dist/commands/archive/shipped.js.map +1 -0
- package/dist/commands/context/context.js +85 -18
- package/dist/commands/context/context.js.map +1 -1
- package/dist/commands/context/print.js +29 -7
- package/dist/commands/context/print.js.map +1 -1
- package/dist/commands/delta/delta.js +102 -14
- package/dist/commands/delta/delta.js.map +1 -1
- package/dist/commands/delta/print.js +17 -1
- package/dist/commands/delta/print.js.map +1 -1
- package/dist/commands/dependencies.js +3 -7
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +20 -27
- package/dist/commands/diff/diff.js.map +1 -1
- package/dist/commands/doctor.js +60 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +89 -13
- package/dist/commands/explain/explain.js.map +1 -1
- package/dist/commands/explore.js +16 -10
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +45 -8
- package/dist/commands/gate/gate.js.map +1 -1
- package/dist/commands/gate/print.js +15 -3
- package/dist/commands/gate/print.js.map +1 -1
- package/dist/commands/gherkin/commit.js +13 -54
- package/dist/commands/gherkin/commit.js.map +1 -1
- package/dist/commands/gherkin/gherkin.js +36 -20
- package/dist/commands/gherkin/gherkin.js.map +1 -1
- package/dist/commands/gherkin/reconcile.js +10 -13
- package/dist/commands/gherkin/reconcile.js.map +1 -1
- package/dist/commands/init/first-hour.js +44 -0
- package/dist/commands/init/first-hour.js.map +1 -1
- package/dist/commands/init/init.js +18 -22
- package/dist/commands/init/init.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +4 -6
- package/dist/commands/list/campaign/campaign.js.map +1 -1
- package/dist/commands/list/json.js +5 -7
- package/dist/commands/list/json.js.map +1 -1
- package/dist/commands/list/list.js +44 -29
- package/dist/commands/list/list.js.map +1 -1
- package/dist/commands/list/print.js +52 -9
- package/dist/commands/list/print.js.map +1 -1
- package/dist/commands/list/suites/suites.js +140 -0
- package/dist/commands/list/suites/suites.js.map +1 -0
- package/dist/commands/list/views.js +37 -34
- package/dist/commands/list/views.js.map +1 -1
- package/dist/commands/mcp/dispatch.js +91 -36
- package/dist/commands/mcp/dispatch.js.map +1 -1
- package/dist/commands/mcp/mcp.js +56 -15
- package/dist/commands/mcp/mcp.js.map +1 -1
- package/dist/commands/mcp/serve.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/active.js +27 -22
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/target.js +2 -2
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/error.js +7 -8
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
- package/dist/commands/new/capability-template.js +118 -0
- package/dist/commands/new/capability-template.js.map +1 -0
- package/dist/commands/new/commit.js +8 -22
- package/dist/commands/new/commit.js.map +1 -1
- package/dist/commands/new/modifies.js +206 -0
- package/dist/commands/new/modifies.js.map +1 -0
- package/dist/commands/new/new.js +59 -14
- package/dist/commands/new/new.js.map +1 -1
- package/dist/commands/new/templates.js +48 -124
- package/dist/commands/new/templates.js.map +1 -1
- package/dist/commands/open.js +3 -7
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/policy/gate.js +27 -0
- package/dist/commands/policy/gate.js.map +1 -1
- package/dist/commands/rebase/plan.js +2 -2
- package/dist/commands/rebase/plan.js.map +1 -1
- package/dist/commands/rebase/rebase.js +60 -35
- package/dist/commands/rebase/rebase.js.map +1 -1
- package/dist/commands/seed/commit.js +55 -26
- package/dist/commands/seed/commit.js.map +1 -1
- package/dist/commands/seed/plan.js +158 -13
- package/dist/commands/seed/plan.js.map +1 -1
- package/dist/commands/seed/seed.js +13 -11
- package/dist/commands/seed/seed.js.map +1 -1
- package/dist/commands/show/feature.js +9 -5
- package/dist/commands/show/feature.js.map +1 -1
- package/dist/commands/show/introduced.js +157 -0
- package/dist/commands/show/introduced.js.map +1 -0
- package/dist/commands/show/marks.js +35 -6
- package/dist/commands/show/marks.js.map +1 -1
- package/dist/commands/show/service.js +41 -33
- package/dist/commands/show/service.js.map +1 -1
- package/dist/commands/show/show.js +17 -7
- package/dist/commands/show/show.js.map +1 -1
- package/dist/commands/status/fleet-next.js +90 -0
- package/dist/commands/status/fleet-next.js.map +1 -0
- package/dist/commands/status/json.js +2 -0
- package/dist/commands/status/json.js.map +1 -1
- package/dist/commands/status/print.js +89 -37
- package/dist/commands/status/print.js.map +1 -1
- package/dist/commands/status/status.js +3 -7
- package/dist/commands/status/status.js.map +1 -1
- package/dist/commands/steps/steps.js +103 -23
- package/dist/commands/steps/steps.js.map +1 -1
- package/dist/commands/subsystem/edit.js +7 -7
- package/dist/commands/subsystem/edit.js.map +1 -1
- package/dist/commands/subsystem/move.js +106 -46
- package/dist/commands/subsystem/move.js.map +1 -1
- package/dist/commands/subsystem/query.js +2 -4
- package/dist/commands/subsystem/query.js.map +1 -1
- package/dist/commands/subsystem/subsystem.js +4 -7
- package/dist/commands/subsystem/subsystem.js.map +1 -1
- package/dist/commands/subsystem/sync.js +289 -74
- package/dist/commands/subsystem/sync.js.map +1 -1
- package/dist/commands/subsystem/txn/exclude.js +132 -0
- package/dist/commands/subsystem/txn/exclude.js.map +1 -0
- package/dist/commands/subsystem/txn/links.js +128 -0
- package/dist/commands/subsystem/txn/links.js.map +1 -0
- package/dist/commands/subsystem/txn/report.js +174 -0
- package/dist/commands/subsystem/txn/report.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +147 -45
- package/dist/commands/subsystem/txn/txn.js.map +1 -1
- package/dist/commands/subsystem/txn/views.js +200 -21
- package/dist/commands/subsystem/txn/views.js.map +1 -1
- package/dist/commands/tasks/actions.js +107 -0
- package/dist/commands/tasks/actions.js.map +1 -0
- package/dist/commands/tasks/render.js +253 -0
- package/dist/commands/tasks/render.js.map +1 -0
- package/dist/commands/tasks/tasks.js +119 -0
- package/dist/commands/tasks/tasks.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +42 -26
- package/dist/commands/unarchive/manifest.js.map +1 -1
- package/dist/commands/unarchive/restore.js +83 -33
- package/dist/commands/unarchive/restore.js.map +1 -1
- package/dist/commands/unarchive/unarchive.js +22 -30
- package/dist/commands/unarchive/unarchive.js.map +1 -1
- package/dist/commands/validate/arch-coverage.js +78 -27
- package/dist/commands/validate/arch-coverage.js.map +1 -1
- package/dist/commands/validate/checks/fleet-shape.js +34 -126
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
- package/dist/commands/validate/checks/health-deps.js +9 -6
- package/dist/commands/validate/checks/health-deps.js.map +1 -1
- package/dist/commands/validate/checks/introduced.js +102 -0
- package/dist/commands/validate/checks/introduced.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +18 -8
- package/dist/commands/validate/checks/requirements.js.map +1 -1
- package/dist/commands/validate/checks/sources.js +11 -2
- package/dist/commands/validate/checks/sources.js.map +1 -1
- package/dist/commands/validate/coverage/covers-after.js +105 -0
- package/dist/commands/validate/coverage/covers-after.js.map +1 -0
- package/dist/commands/validate/feature.js +26 -20
- package/dist/commands/validate/feature.js.map +1 -1
- package/dist/commands/validate/fleet/census.js +37 -13
- package/dist/commands/validate/fleet/census.js.map +1 -1
- package/dist/commands/validate/fleet/landscape.js +144 -126
- package/dist/commands/validate/fleet/landscape.js.map +1 -1
- package/dist/commands/validate/fleet/load.js +66 -0
- package/dist/commands/validate/fleet/load.js.map +1 -1
- package/dist/commands/validate/fleet/map/attest.js +98 -0
- package/dist/commands/validate/fleet/map/attest.js.map +1 -0
- package/dist/commands/validate/fleet/map/bindings.js +107 -0
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
- package/dist/commands/validate/fleet/map/consumers.js +244 -0
- package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
- package/dist/commands/validate/fleet/map/isolation.js +116 -0
- package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
- package/dist/commands/validate/fleet/map/usecases.js +54 -0
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +44 -14
- package/dist/commands/validate/fleet/obligations.js.map +1 -1
- package/dist/commands/validate/fleet/scorecard/print.js +10 -2
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
- package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -1
- package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +50 -15
- package/dist/commands/validate/fleet/views/ids.js.map +1 -1
- package/dist/commands/validate/fleet/views/projects.js +278 -0
- package/dist/commands/validate/fleet/views/projects.js.map +1 -0
- package/dist/commands/validate/fleet/views/root-documents.js +83 -0
- package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +40 -47
- package/dist/commands/validate/fleet/views/stale.js.map +1 -1
- package/dist/commands/validate/links/corpus.js +1 -4
- package/dist/commands/validate/links/corpus.js.map +1 -1
- package/dist/commands/validate/links/glossary.js.map +1 -1
- package/dist/commands/validate/render/repeats.js +63 -0
- package/dist/commands/validate/render/repeats.js.map +1 -0
- package/dist/commands/validate/render/rollups.js +115 -0
- package/dist/commands/validate/render/rollups.js.map +1 -0
- package/dist/commands/validate/render/text.js +199 -0
- package/dist/commands/validate/render/text.js.map +1 -0
- package/dist/commands/validate/report.js +36 -160
- package/dist/commands/validate/report.js.map +1 -1
- package/dist/commands/validate/scope.js +113 -0
- package/dist/commands/validate/scope.js.map +1 -0
- package/dist/commands/validate/service/api.js +21 -107
- package/dist/commands/validate/service/api.js.map +1 -1
- package/dist/commands/validate/service/contracts/generated.js +134 -0
- package/dist/commands/validate/service/contracts/generated.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +36 -14
- package/dist/commands/validate/service/events/events.js.map +1 -1
- package/dist/commands/validate/service/events/message-producers.js +1 -1
- package/dist/commands/validate/service/events/message-producers.js.map +1 -1
- package/dist/commands/validate/service/evidence-pins.js +56 -10
- package/dist/commands/validate/service/evidence-pins.js.map +1 -1
- package/dist/commands/validate/service/model/diverged.js +226 -0
- package/dist/commands/validate/service/model/diverged.js.map +1 -0
- package/dist/commands/validate/service/model/grade.js +163 -0
- package/dist/commands/validate/service/model/grade.js.map +1 -0
- package/dist/commands/validate/service/service.js +121 -61
- package/dist/commands/validate/service/service.js.map +1 -1
- package/dist/commands/validate/service/specs.js +88 -28
- package/dist/commands/validate/service/specs.js.map +1 -1
- package/dist/commands/validate/service/spine.js +38 -3
- package/dist/commands/validate/service/spine.js.map +1 -1
- package/dist/commands/validate/service/usecases/tags.js +113 -0
- package/dist/commands/validate/service/usecases/tags.js.map +1 -0
- package/dist/commands/validate/service/usecases/usecases.js +209 -0
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/validate.js +85 -60
- package/dist/commands/validate/validate.js.map +1 -1
- package/dist/commands/verify/cross/diff.js +2 -6
- package/dist/commands/verify/cross/diff.js.map +1 -1
- package/dist/commands/verify/evidence/contract.js +1 -1
- package/dist/commands/verify/evidence/contract.js.map +1 -1
- package/dist/commands/verify/evidence/read.js +12 -3
- package/dist/commands/verify/evidence/read.js.map +1 -1
- package/dist/commands/verify/frozen.js +45 -23
- package/dist/commands/verify/frozen.js.map +1 -1
- package/dist/commands/verify/record.js +69 -17
- package/dist/commands/verify/record.js.map +1 -1
- package/dist/commands/verify/report.js +27 -44
- package/dist/commands/verify/report.js.map +1 -1
- package/dist/commands/verify/results.js +112 -30
- package/dist/commands/verify/results.js.map +1 -1
- package/dist/commands/verify/verify.js +55 -52
- package/dist/commands/verify/verify.js.map +1 -1
- package/dist/commands/vouch/pack/pack.js +2 -2
- package/dist/commands/vouch/pack/pack.js.map +1 -1
- package/dist/commands/vouch/pack/print.js +1 -6
- package/dist/commands/vouch/pack/print.js.map +1 -1
- package/dist/commands/vouch/pack/sections.js +1 -2
- package/dist/commands/vouch/pack/sections.js.map +1 -1
- package/dist/commands/vouch/run.js +26 -81
- package/dist/commands/vouch/run.js.map +1 -1
- package/dist/commands/vouch/sample/plan.js +20 -34
- package/dist/commands/vouch/sample/plan.js.map +1 -1
- package/dist/commands/vouch/vet/verify.js +39 -7
- package/dist/commands/vouch/vet/verify.js.map +1 -1
- package/dist/commands/vouch/vouch.js +10 -17
- package/dist/commands/vouch/vouch.js.map +1 -1
- package/dist/core/agent/agents-md/command-map.js +81 -106
- package/dist/core/agent/agents-md/command-map.js.map +1 -1
- package/dist/core/agent/agents-md/map/explain.js +21 -9
- package/dist/core/agent/agents-md/map/explain.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/context.js +17 -8
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
- package/dist/core/agent/agents-md/map/mcp.js +10 -7
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
- package/dist/core/agent/agents-md/map/status.js +24 -8
- package/dist/core/agent/agents-md/map/status.js.map +1 -1
- package/dist/core/agent/agents-md/map/subsystem.js +80 -8
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
- package/dist/core/agent/agents-md/map/usecases.js +88 -10
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
- package/dist/core/agent/agents-md/refusals.js +49 -22
- package/dist/core/agent/agents-md/refusals.js.map +1 -1
- package/dist/core/agent/agents-md.js +39 -6
- package/dist/core/agent/agents-md.js.map +1 -1
- package/dist/core/agent/agents-stamp.js +10 -0
- package/dist/core/agent/agents-stamp.js.map +1 -1
- package/dist/core/agent/protocol.js +1 -1
- package/dist/core/agent/protocol.js.map +1 -1
- package/dist/core/agent/scaffold.js +10 -15
- package/dist/core/agent/scaffold.js.map +1 -1
- package/dist/core/agent/support/report.js +46 -5
- package/dist/core/agent/support/report.js.map +1 -1
- package/dist/core/agent/tools/dialects.js +1 -0
- package/dist/core/agent/tools/dialects.js.map +1 -1
- package/dist/core/agent/tools/registry.js +41 -76
- package/dist/core/agent/tools/registry.js.map +1 -1
- package/dist/core/agent/workflows/adopt.js +158 -11
- package/dist/core/agent/workflows/adopt.js.map +1 -1
- package/dist/core/agent/workflows/check.js +78 -39
- package/dist/core/agent/workflows/check.js.map +1 -1
- package/dist/core/agent/workflows/closing.js +88 -27
- package/dist/core/agent/workflows/closing.js.map +1 -1
- package/dist/core/agent/workflows/feature.js +128 -13
- package/dist/core/agent/workflows/feature.js.map +1 -1
- package/dist/core/agent/workflows/implement.js +96 -13
- package/dist/core/agent/workflows/implement.js.map +1 -1
- package/dist/core/agent/workflows/reference/authoring.js +106 -4
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
- package/dist/core/agent/workflows/reference/codes.js +8 -6
- package/dist/core/agent/workflows/reference/codes.js.map +1 -1
- package/dist/core/agent/workflows/reference/done-check.js +37 -15
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
- package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +6 -3
- package/dist/core/agent/workflows/reference/reference.js.map +1 -1
- package/dist/core/agent/workflows/reference/spine.js +68 -27
- package/dist/core/agent/workflows/reference/spine.js.map +1 -1
- package/dist/core/asyncapi/baseline/plan.js +14 -81
- package/dist/core/asyncapi/baseline/plan.js.map +1 -1
- package/dist/core/asyncapi/digest.js +30 -25
- package/dist/core/asyncapi/digest.js.map +1 -1
- package/dist/core/asyncapi/merge/components.js +5 -4
- package/dist/core/asyncapi/merge/components.js.map +1 -1
- package/dist/core/asyncapi/merge/error.js +7 -2
- package/dist/core/asyncapi/merge/error.js.map +1 -1
- package/dist/core/asyncapi/merge/markers.js +32 -50
- package/dist/core/asyncapi/merge/markers.js.map +1 -1
- package/dist/core/asyncapi/merge/merge.js +33 -53
- package/dist/core/asyncapi/merge/merge.js.map +1 -1
- package/dist/core/asyncapi/merge/pin.js +12 -36
- package/dist/core/asyncapi/merge/pin.js.map +1 -1
- package/dist/core/asyncapi/model.js.map +1 -1
- package/dist/core/asyncapi/read.js +36 -12
- package/dist/core/asyncapi/read.js.map +1 -1
- package/dist/core/brief/brief.js +96 -36
- package/dist/core/brief/brief.js.map +1 -1
- package/dist/core/brief/checks.js +138 -3
- package/dist/core/brief/checks.js.map +1 -1
- package/dist/core/brief/landscape.js +209 -130
- package/dist/core/brief/landscape.js.map +1 -1
- package/dist/core/brief/map/extend.js +84 -0
- package/dist/core/brief/map/extend.js.map +1 -0
- package/dist/core/brief/map/owed.js +266 -0
- package/dist/core/brief/map/owed.js.map +1 -0
- package/dist/core/brief/targets.js +109 -31
- package/dist/core/brief/targets.js.map +1 -1
- package/dist/core/brief/unchecked.js +14 -3
- package/dist/core/brief/unchecked.js.map +1 -1
- package/dist/core/c4/arch.js +90 -182
- package/dist/core/c4/arch.js.map +1 -1
- package/dist/core/c4/direction/direction.js +114 -0
- package/dist/core/c4/direction/direction.js.map +1 -0
- package/dist/core/c4/likec4.js +169 -14
- package/dist/core/c4/likec4.js.map +1 -1
- package/dist/core/c4/locate/unlocated.js +150 -0
- package/dist/core/c4/locate/unlocated.js.map +1 -0
- package/dist/core/c4/parsed/deployment.js +160 -0
- package/dist/core/c4/parsed/deployment.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -1
- package/dist/core/c4/parsed/values.js +54 -1
- package/dist/core/c4/parsed/values.js.map +1 -1
- package/dist/core/c4/parsed/view-ids.js +39 -1
- package/dist/core/c4/parsed/view-ids.js.map +1 -1
- package/dist/core/c4/prefetch/fleet.js +134 -0
- package/dist/core/c4/prefetch/fleet.js.map +1 -0
- package/dist/core/c4/project/architecture.js +123 -7
- package/dist/core/c4/project/architecture.js.map +1 -1
- package/dist/core/c4/project/batch.js +140 -0
- package/dist/core/c4/project/batch.js.map +1 -0
- package/dist/core/c4/project/documents.js +43 -12
- package/dist/core/c4/project/documents.js.map +1 -1
- package/dist/core/c4/project/load.js +79 -43
- package/dist/core/c4/project/load.js.map +1 -1
- package/dist/core/c4/project/staged.js +277 -0
- package/dist/core/c4/project/staged.js.map +1 -0
- package/dist/core/c4/resolve/attested.js +0 -0
- package/dist/core/c4/resolve/attested.js.map +1 -0
- package/dist/core/c4/resolve/external.js +51 -0
- package/dist/core/c4/resolve/external.js.map +1 -0
- package/dist/core/c4/resolve/service.js +78 -17
- package/dist/core/c4/resolve/service.js.map +1 -1
- package/dist/core/c4/resolve/steps.js +290 -0
- package/dist/core/c4/resolve/steps.js.map +1 -0
- package/dist/core/c4/resolve/systems.js +154 -0
- package/dist/core/c4/resolve/systems.js.map +1 -0
- package/dist/core/c4/root-project/exclude.js +352 -0
- package/dist/core/c4/root-project/exclude.js.map +1 -0
- package/dist/core/c4/seed/template.js +65 -1
- package/dist/core/c4/seed/template.js.map +1 -1
- package/dist/core/c4/service-model/created/models.js +96 -0
- package/dist/core/c4/service-model/created/models.js.map +1 -0
- package/dist/core/c4/service-model/documents.js +47 -0
- package/dist/core/c4/service-model/documents.js.map +1 -0
- package/dist/core/c4/service-model/fleet/extending.js +82 -0
- package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
- package/dist/core/c4/service-model/load.js +165 -0
- package/dist/core/c4/service-model/load.js.map +1 -0
- package/dist/core/c4/service-model/renderer.js +128 -0
- package/dist/core/c4/service-model/renderer.js.map +1 -0
- package/dist/core/c4/service-model/shape.js +106 -0
- package/dist/core/c4/service-model/shape.js.map +1 -0
- package/dist/core/c4/service-model/slice.js +188 -0
- package/dist/core/c4/service-model/slice.js.map +1 -0
- package/dist/core/c4/source-mask.js +297 -10
- package/dist/core/c4/source-mask.js.map +1 -1
- package/dist/core/c4/source-scan.js +222 -141
- package/dist/core/c4/source-scan.js.map +1 -1
- package/dist/core/c4/splice/authored-source.js +79 -13
- package/dist/core/c4/splice/authored-source.js.map +1 -1
- package/dist/core/c4/splice/contract.js +20 -0
- package/dist/core/c4/splice/contract.js.map +1 -1
- package/dist/core/c4/splice/delta-blocks.js +20 -20
- package/dist/core/c4/splice/delta-blocks.js.map +1 -1
- package/dist/core/c4/splice/identity/declared.js +87 -0
- package/dist/core/c4/splice/identity/declared.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +37 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -1
- package/dist/core/c4/splice/identity/existing.js +80 -0
- package/dist/core/c4/splice/identity/existing.js.map +1 -0
- package/dist/core/c4/splice/identity/interior.js +80 -0
- package/dist/core/c4/splice/identity/interior.js.map +1 -0
- package/dist/core/c4/splice/identity/owner.js +50 -0
- package/dist/core/c4/splice/identity/owner.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +182 -114
- package/dist/core/c4/splice/landscape-merge.js.map +1 -1
- package/dist/core/c4/splice/model/merge.js +151 -0
- package/dist/core/c4/splice/model/merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +160 -56
- package/dist/core/c4/splice/placement.js.map +1 -1
- package/dist/core/c4/splice/text/spot.js +131 -0
- package/dist/core/c4/splice/text/spot.js.map +1 -0
- package/dist/core/c4/workspace.js +13 -19
- package/dist/core/c4/workspace.js.map +1 -1
- package/dist/core/capabilities/capabilities.js +6 -6
- package/dist/core/capabilities/capabilities.js.map +1 -1
- package/dist/core/capabilities/delta/doc.js +7 -10
- package/dist/core/capabilities/delta/doc.js.map +1 -1
- package/dist/core/capabilities/delta/uncovered.js +2 -2
- package/dist/core/capabilities/delta/uncovered.js.map +1 -1
- package/dist/core/capabilities/findings.js +18 -22
- package/dist/core/capabilities/findings.js.map +1 -1
- package/dist/core/capabilities/realizes/findings.js +12 -19
- package/dist/core/capabilities/realizes/findings.js.map +1 -1
- package/dist/core/capabilities/realizes/join.js +0 -20
- package/dist/core/capabilities/realizes/join.js.map +1 -1
- package/dist/core/capabilities/rollup.js +6 -0
- package/dist/core/capabilities/rollup.js.map +1 -1
- package/dist/core/capabilities/tree.js +6 -28
- package/dist/core/capabilities/tree.js.map +1 -1
- package/dist/core/capabilities/usecase-join.js +3 -13
- package/dist/core/capabilities/usecase-join.js.map +1 -1
- package/dist/core/coherence/authoring/scaffold.js +11 -3
- package/dist/core/coherence/authoring/scaffold.js.map +1 -1
- package/dist/core/coherence/authoring/sentinels.js +2 -1
- package/dist/core/coherence/authoring/sentinels.js.map +1 -1
- package/dist/core/coherence/calls/called.js +52 -0
- package/dist/core/coherence/calls/called.js.map +1 -0
- package/dist/core/coherence/coherence.js +103 -22
- package/dist/core/coherence/coherence.js.map +1 -1
- package/dist/core/coherence/consumed/operations.js +70 -0
- package/dist/core/coherence/consumed/operations.js.map +1 -0
- package/dist/core/coherence/consumed/refusal.js +38 -0
- package/dist/core/coherence/consumed/refusal.js.map +1 -0
- package/dist/core/coherence/covers/health.js +85 -0
- package/dist/core/coherence/covers/health.js.map +1 -0
- package/dist/core/coherence/declared.js +60 -34
- package/dist/core/coherence/declared.js.map +1 -1
- package/dist/core/coherence/events/declared.js +44 -59
- package/dist/core/coherence/events/declared.js.map +1 -1
- package/dist/core/coherence/events/events.js +147 -16
- package/dist/core/coherence/events/events.js.map +1 -1
- package/dist/core/coherence/events/grades.js +31 -8
- package/dist/core/coherence/events/grades.js.map +1 -1
- package/dist/core/coherence/events/lookups.js +28 -87
- package/dist/core/coherence/events/lookups.js.map +1 -1
- package/dist/core/coherence/events/produced.js +100 -0
- package/dist/core/coherence/events/produced.js.map +1 -0
- package/dist/core/coherence/lookups.js +18 -78
- package/dist/core/coherence/lookups.js.map +1 -1
- package/dist/core/coherence/retired/archived.js +285 -0
- package/dist/core/coherence/retired/archived.js.map +1 -0
- package/dist/core/coherence/retired/event-pair.js +62 -0
- package/dist/core/coherence/retired/event-pair.js.map +1 -0
- package/dist/core/coherence/retired/merged.js +79 -0
- package/dist/core/coherence/retired/merged.js.map +1 -0
- package/dist/core/coherence/retired/retirement.js +49 -0
- package/dist/core/coherence/retired/retirement.js.map +1 -0
- package/dist/core/coherence/retired/revival/arrivals.js +131 -0
- package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
- package/dist/core/coherence/retired/revival/revived.js +297 -0
- package/dist/core/coherence/retired/revival/revived.js.map +1 -0
- package/dist/core/consumers/after.js +113 -0
- package/dist/core/consumers/after.js.map +1 -0
- package/dist/core/consumers/consumers.js +296 -0
- package/dist/core/consumers/consumers.js.map +1 -0
- package/dist/core/consumers/current.js +211 -0
- package/dist/core/consumers/current.js.map +1 -0
- package/dist/core/consumers/scan.js +46 -0
- package/dist/core/consumers/scan.js.map +1 -0
- package/dist/core/consumers/state.js +27 -0
- package/dist/core/consumers/state.js.map +1 -0
- package/dist/core/delta/delta.js +51 -6
- package/dist/core/delta/delta.js.map +1 -1
- package/dist/core/dependencies/fanin.js +2 -2
- package/dist/core/dependencies/fanin.js.map +1 -1
- package/dist/core/deployment/delta.js +191 -0
- package/dist/core/deployment/delta.js.map +1 -0
- package/dist/core/deployment/objects.js +145 -0
- package/dist/core/deployment/objects.js.map +1 -0
- package/dist/core/diff/base-git.js +94 -12
- package/dist/core/diff/base-git.js.map +1 -1
- package/dist/core/diff/base-state.js +49 -21
- package/dist/core/diff/base-state.js.map +1 -1
- package/dist/core/diff/joins.js +136 -0
- package/dist/core/diff/joins.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +22 -6
- package/dist/core/diff/scope/changed-paths.js.map +1 -1
- package/dist/core/diff/scope/edges.js +82 -0
- package/dist/core/diff/scope/edges.js.map +1 -0
- package/dist/core/diff/semantic.js +100 -31
- package/dist/core/diff/semantic.js.map +1 -1
- package/dist/core/docs.js +31 -22
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +34 -18
- package/dist/core/doctor/agents.js.map +1 -1
- package/dist/core/doctor/config.js +7 -3
- package/dist/core/doctor/config.js.map +1 -1
- package/dist/core/doctor/doctor.js +91 -11
- package/dist/core/doctor/doctor.js.map +1 -1
- package/dist/core/doctor/report.js.map +1 -1
- package/dist/core/doctor/reports/scan.js +242 -0
- package/dist/core/doctor/reports/scan.js.map +1 -0
- package/dist/core/document/apply.js +158 -11
- package/dist/core/document/apply.js.map +1 -1
- package/dist/core/document/frontmatter.js +55 -0
- package/dist/core/document/frontmatter.js.map +1 -1
- package/dist/core/document/parse.js +29 -6
- package/dist/core/document/parse.js.map +1 -1
- package/dist/core/document/scenarios.js +17 -0
- package/dist/core/document/scenarios.js.map +1 -1
- package/dist/core/document/spec.js +4 -11
- package/dist/core/document/spec.js.map +1 -1
- package/dist/core/envelope/config.js +10 -0
- package/dist/core/envelope/config.js.map +1 -1
- package/dist/core/envelope/json.js +34 -0
- package/dist/core/envelope/json.js.map +1 -1
- package/dist/core/explain/families.js +26 -21
- package/dist/core/explain/families.js.map +1 -1
- package/dist/core/explain/lookup.js +14 -1
- package/dist/core/explain/lookup.js.map +1 -1
- package/dist/core/explain/refusals.js +5 -5
- package/dist/core/explain/refusals.js.map +1 -1
- package/dist/core/explain/terms/documents.js +227 -0
- package/dist/core/explain/terms/documents.js.map +1 -0
- package/dist/core/explain/terms/done-check.js +144 -0
- package/dist/core/explain/terms/done-check.js.map +1 -0
- package/dist/core/explain/terms/entry.js +14 -0
- package/dist/core/explain/terms/entry.js.map +1 -0
- package/dist/core/explain/terms/stages.js +71 -0
- package/dist/core/explain/terms/stages.js.map +1 -0
- package/dist/core/explain/terms/tasks.js +97 -0
- package/dist/core/explain/terms/tasks.js.map +1 -0
- package/dist/core/explain/terms.js +68 -109
- package/dist/core/explain/terms.js.map +1 -1
- package/dist/core/explore/explore.js +40 -10
- package/dist/core/explore/explore.js.map +1 -1
- package/dist/core/fleet-context.js +81 -95
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +11 -4
- package/dist/core/gate/checks.js.map +1 -1
- package/dist/core/gate/partners.js +69 -28
- package/dist/core/gate/partners.js.map +1 -1
- package/dist/core/gate/report.js.map +1 -1
- package/dist/core/gate/verification.js +75 -12
- package/dist/core/gate/verification.js.map +1 -1
- package/dist/core/gherkin/stale.js +13 -37
- package/dist/core/gherkin/stale.js.map +1 -1
- package/dist/core/glossary/delta.js +10 -7
- package/dist/core/glossary/delta.js.map +1 -1
- package/dist/core/glossary/tree.js +6 -19
- package/dist/core/glossary/tree.js.map +1 -1
- package/dist/core/kernel/concurrency.js +19 -0
- package/dist/core/kernel/concurrency.js.map +1 -1
- package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
- package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
- package/dist/core/kernel/path-safety.js +38 -0
- package/dist/core/kernel/path-safety.js.map +1 -1
- package/dist/core/kernel/records.js +11 -0
- package/dist/core/kernel/records.js.map +1 -1
- package/dist/core/links/backlinks.js +1 -3
- package/dist/core/links/backlinks.js.map +1 -1
- package/dist/core/links/corpus.js +51 -37
- package/dist/core/links/corpus.js.map +1 -1
- package/dist/core/links/findings.js.map +1 -1
- package/dist/core/links/parse.js +38 -9
- package/dist/core/links/parse.js.map +1 -1
- package/dist/core/mcp/argv.js +101 -0
- package/dist/core/mcp/argv.js.map +1 -1
- package/dist/core/mcp/author-tools.js +2 -1
- package/dist/core/mcp/author-tools.js.map +1 -1
- package/dist/core/mcp/protocol.js +2 -2
- package/dist/core/mcp/protocol.js.map +1 -1
- package/dist/core/mcp/tools.js +43 -33
- package/dist/core/mcp/tools.js.map +1 -1
- package/dist/core/openapi/baseline/gate.js +53 -12
- package/dist/core/openapi/baseline/gate.js.map +1 -1
- package/dist/core/openapi/baseline/plan.js +40 -10
- package/dist/core/openapi/baseline/plan.js.map +1 -1
- package/dist/core/openapi/baseline/record.js +0 -1
- package/dist/core/openapi/baseline/record.js.map +1 -1
- package/dist/core/openapi/contract-text.js +33 -0
- package/dist/core/openapi/contract-text.js.map +1 -0
- package/dist/core/openapi/contract-tree.js +301 -0
- package/dist/core/openapi/contract-tree.js.map +1 -0
- package/dist/core/openapi/depth.js +38 -24
- package/dist/core/openapi/depth.js.map +1 -1
- package/dist/core/openapi/digest.js +52 -2
- package/dist/core/openapi/digest.js.map +1 -1
- package/dist/core/openapi/doc.js +12 -4
- package/dist/core/openapi/doc.js.map +1 -1
- package/dist/core/openapi/merge/components.js +25 -60
- package/dist/core/openapi/merge/components.js.map +1 -1
- package/dist/core/openapi/merge/error.js +3 -13
- package/dist/core/openapi/merge/error.js.map +1 -1
- package/dist/core/openapi/merge/markers.js +26 -30
- package/dist/core/openapi/merge/markers.js.map +1 -1
- package/dist/core/openapi/merge/merge.js +28 -52
- package/dist/core/openapi/merge/merge.js.map +1 -1
- package/dist/core/openapi/merge/pin.js +17 -35
- package/dist/core/openapi/merge/pin.js.map +1 -1
- package/dist/core/openspec/decide/verdict.js.map +1 -1
- package/dist/core/openspec/inventory.js +4 -5
- package/dist/core/openspec/inventory.js.map +1 -1
- package/dist/core/openspec/model/mapping.js +30 -28
- package/dist/core/openspec/model/mapping.js.map +1 -1
- package/dist/core/openspec/model/model.js +12 -7
- package/dist/core/openspec/model/model.js.map +1 -1
- package/dist/core/openspec/scan/changes.js +10 -4
- package/dist/core/openspec/scan/changes.js.map +1 -1
- package/dist/core/openspec/scan/config.js +7 -16
- package/dist/core/openspec/scan/config.js.map +1 -1
- package/dist/core/openspec/scan/shape.js +63 -19
- package/dist/core/openspec/scan/shape.js.map +1 -1
- package/dist/core/openspec/scan/walk.js +21 -38
- package/dist/core/openspec/scan/walk.js.map +1 -1
- package/dist/core/pack/living.js +43 -4
- package/dist/core/pack/living.js.map +1 -1
- package/dist/core/pack/pack.js +50 -6
- package/dist/core/pack/pack.js.map +1 -1
- package/dist/core/projection/arch-slice.js +2 -2
- package/dist/core/projection/arch-slice.js.map +1 -1
- package/dist/core/projection/introduced.js +14 -0
- package/dist/core/projection/introduced.js.map +1 -0
- package/dist/core/provenance/findings.js +48 -12
- package/dist/core/provenance/findings.js.map +1 -1
- package/dist/core/provenance/git.js +33 -57
- package/dist/core/provenance/git.js.map +1 -1
- package/dist/core/provenance/gitq/moves.js +71 -114
- package/dist/core/provenance/gitq/moves.js.map +1 -1
- package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
- package/dist/core/provenance/sources.js +23 -6
- package/dist/core/provenance/sources.js.map +1 -1
- package/dist/core/provenance/stamp.js +5 -17
- package/dist/core/provenance/stamp.js.map +1 -1
- package/dist/core/repo/authored/paths.js +18 -0
- package/dist/core/repo/authored/paths.js.map +1 -1
- package/dist/core/repo/entries.js.map +1 -1
- package/dist/core/repo/paths.js +92 -6
- package/dist/core/repo/paths.js.map +1 -1
- package/dist/core/repo/repo.js +74 -14
- package/dist/core/repo/repo.js.map +1 -1
- package/dist/core/repo/tree/find.js +12 -3
- package/dist/core/repo/tree/find.js.map +1 -1
- package/dist/core/repo/tree/fs.js +27 -1
- package/dist/core/repo/tree/fs.js.map +1 -1
- package/dist/core/repo/tree/render/body.js +258 -0
- package/dist/core/repo/tree/render/body.js.map +1 -0
- package/dist/core/repo/tree/render/projects.js +182 -0
- package/dist/core/repo/tree/render/projects.js.map +1 -0
- package/dist/core/repo/tree/render/service/header.js +125 -0
- package/dist/core/repo/tree/render/service/header.js.map +1 -0
- package/dist/core/repo/tree/render/service/peers.js +28 -0
- package/dist/core/repo/tree/render/service/peers.js.map +1 -0
- package/dist/core/repo/tree/render/service/view-id.js +67 -0
- package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
- package/dist/core/repo/tree/render/service/views.js +78 -0
- package/dist/core/repo/tree/render/service/views.js.map +1 -0
- package/dist/core/repo/tree/render/stale.js +42 -0
- package/dist/core/repo/tree/render/stale.js.map +1 -0
- package/dist/core/repo/tree/render/text.js +84 -0
- package/dist/core/repo/tree/render/text.js.map +1 -0
- package/dist/core/repo/tree/render/views.js +293 -0
- package/dist/core/repo/tree/render/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +53 -32
- package/dist/core/repo/tree/walk.js.map +1 -1
- package/dist/core/results.js +47 -12
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +121 -13
- package/dist/core/scaffold/landscape.js.map +1 -1
- package/dist/core/scaffold/legacy.js +271 -0
- package/dist/core/scaffold/legacy.js.map +1 -0
- package/dist/core/staging/commit.js +26 -15
- package/dist/core/staging/commit.js.map +1 -1
- package/dist/core/staging/lock.js +74 -12
- package/dist/core/staging/lock.js.map +1 -1
- package/dist/core/staging/recovery/intent.js +2 -5
- package/dist/core/staging/recovery/intent.js.map +1 -1
- package/dist/core/staging/recovery/recover.js +84 -6
- package/dist/core/staging/recovery/recover.js.map +1 -1
- package/dist/core/staging/snapshot/manifest.js +188 -0
- package/dist/core/staging/snapshot/manifest.js.map +1 -0
- package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +39 -45
- package/dist/core/staging/snapshot/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +24 -14
- package/dist/core/staging/txn/forward.js.map +1 -1
- package/dist/core/staging/writes.js.map +1 -1
- package/dist/core/status/actions/execution.js +11 -0
- package/dist/core/status/actions/execution.js.map +1 -1
- package/dist/core/status/contracts.js +39 -15
- package/dist/core/status/contracts.js.map +1 -1
- package/dist/core/status/feature/artifacts.js +33 -8
- package/dist/core/status/feature/artifacts.js.map +1 -1
- package/dist/core/status/feature/feature.js +24 -17
- package/dist/core/status/feature/feature.js.map +1 -1
- package/dist/core/status/feature/next.js +20 -7
- package/dist/core/status/feature/next.js.map +1 -1
- package/dist/core/status/feature/words.js +96 -0
- package/dist/core/status/feature/words.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +43 -14
- package/dist/core/status/fleet/fleet.js.map +1 -1
- package/dist/core/status/fleet/next.js +153 -58
- package/dist/core/status/fleet/next.js.map +1 -1
- package/dist/core/status/report.js.map +1 -1
- package/dist/core/status/scan.js.map +1 -1
- package/dist/core/status/verification.js +30 -15
- package/dist/core/status/verification.js.map +1 -1
- package/dist/core/tasks/packet.js +199 -0
- package/dist/core/tasks/packet.js.map +1 -0
- package/dist/core/tasks/record.js +43 -0
- package/dist/core/tasks/record.js.map +1 -0
- package/dist/core/tasks/sources.js +181 -0
- package/dist/core/tasks/sources.js.map +1 -0
- package/dist/core/tasks/stamps.js +76 -0
- package/dist/core/tasks/stamps.js.map +1 -0
- package/dist/core/tasks/unit.js +0 -0
- package/dist/core/tasks/unit.js.map +1 -0
- package/dist/core/usecases/capability.js +11 -14
- package/dist/core/usecases/capability.js.map +1 -1
- package/dist/core/usecases/delta/claims.js +31 -7
- package/dist/core/usecases/delta/claims.js.map +1 -1
- package/dist/core/usecases/delta/flows.js +5 -7
- package/dist/core/usecases/delta/flows.js.map +1 -1
- package/dist/core/usecases/delta/modified.js +315 -0
- package/dist/core/usecases/delta/modified.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +32 -191
- package/dist/core/usecases/delta/overlay.js.map +1 -1
- package/dist/core/usecases/fleet.js +195 -36
- package/dist/core/usecases/fleet.js.map +1 -1
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/capability-tag.js +8 -9
- package/dist/core/usecases/grade/capability-tag.js.map +1 -0
- package/dist/core/usecases/grade/feature.js +88 -0
- package/dist/core/usecases/grade/feature.js.map +1 -0
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/requirement-tag.js +3 -4
- package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/steps.js +102 -33
- package/dist/core/usecases/grade/steps.js.map +1 -0
- package/dist/{commands/validate/fleet/usecases → core/usecases/grade}/usecases.js +23 -10
- package/dist/core/usecases/grade/usecases.js.map +1 -0
- package/dist/core/usecases/operations.js +26 -14
- package/dist/core/usecases/operations.js.map +1 -1
- package/dist/core/usecases/place.js.map +1 -1
- package/dist/core/usecases/service/exclude.js +119 -0
- package/dist/core/usecases/service/exclude.js.map +1 -0
- package/dist/core/usecases/service/flows.js +164 -0
- package/dist/core/usecases/service/flows.js.map +1 -0
- package/dist/core/usecases/suites/participants.js +83 -0
- package/dist/core/usecases/suites/participants.js.map +1 -0
- package/dist/core/usecases/suites/suites.js +45 -0
- package/dist/core/usecases/suites/suites.js.map +1 -0
- package/dist/core/verify/answers.js +12 -5
- package/dist/core/verify/answers.js.map +1 -1
- package/dist/core/verify/build.js +102 -82
- package/dist/core/verify/build.js.map +1 -1
- package/dist/core/verify/checklist.js +70 -12
- package/dist/core/verify/checklist.js.map +1 -1
- package/dist/core/verify/location.js +67 -0
- package/dist/core/verify/location.js.map +1 -0
- package/dist/core/verify/pins/lint.js +3 -2
- package/dist/core/verify/pins/lint.js.map +1 -1
- package/dist/core/verify/pins/pin.js +1 -1
- package/dist/core/verify/pins/pin.js.map +1 -1
- package/dist/core/verify/read/file.js +224 -0
- package/dist/core/verify/read/file.js.map +1 -0
- package/dist/core/verify/{file.js → read/shape.js} +16 -104
- package/dist/core/verify/read/shape.js.map +1 -0
- package/dist/core/verify/read/union.js +105 -0
- package/dist/core/verify/read/union.js.map +1 -0
- package/dist/core/verify/record.js +35 -12
- package/dist/core/verify/record.js.map +1 -1
- package/dist/core/verify/store/commit.js +40 -30
- package/dist/core/verify/store/commit.js.map +1 -1
- package/dist/core/verify/store/render.js +8 -4
- package/dist/core/verify/store/render.js.map +1 -1
- package/dist/core/vocabulary/issue.js +4 -0
- package/dist/core/vocabulary/issue.js.map +1 -1
- package/dist/core/vocabulary/maturity.js +75 -4
- package/dist/core/vocabulary/maturity.js.map +1 -1
- package/dist/core/vocabulary/report.js +16 -1
- package/dist/core/vocabulary/report.js.map +1 -1
- package/examples/README.md +54 -11
- package/examples/docs/architecture/landscape.likec4 +62 -6
- package/examples/docs/architecture/services.likec4 +70 -0
- package/examples/docs/architecture/subsystems.likec4 +7 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +16 -7
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +4 -1
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
- package/examples/docs/likec4.config.json +0 -1
- package/examples/docs/services/checkout-web/model.likec4 +39 -56
- package/examples/docs/services/order-service/arch.spec.md +13 -6
- package/examples/docs/services/order-service/asyncapi.yaml +3 -2
- package/examples/docs/services/order-service/model.likec4 +58 -70
- package/examples/docs/services/payment-service/arch.spec.md +7 -4
- package/examples/docs/services/payment-service/model.likec4 +38 -37
- package/examples/docs/services/platform/identity-service/arch.spec.md +7 -4
- package/examples/docs/services/platform/identity-service/model.likec4 +35 -37
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
- package/examples/docs/services/platform/notification-service/health.yaml +8 -3
- package/examples/docs/services/platform/notification-service/model.likec4 +43 -64
- package/package.json +1 -1
- package/dist/commands/validate/checks/vocabulary.js +0 -31
- package/dist/commands/validate/checks/vocabulary.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/capability-tag.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/requirement-tag.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/steps.js.map +0 -1
- package/dist/commands/validate/fleet/usecases/usecases.js.map +0 -1
- package/dist/core/agent/agents-md/artifacts.js +0 -220
- package/dist/core/agent/agents-md/artifacts.js.map +0 -1
- package/dist/core/agent/agents-md/cycle.js +0 -165
- package/dist/core/agent/agents-md/cycle.js.map +0 -1
- package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
- package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
- package/dist/core/agent/agents-md/spine.js +0 -40
- package/dist/core/agent/agents-md/spine.js.map +0 -1
- package/dist/core/coherence/events/merged.js +0 -40
- package/dist/core/coherence/events/merged.js.map +0 -1
- package/dist/core/diff/current-state.js +0 -96
- package/dist/core/diff/current-state.js.map +0 -1
- package/dist/core/diff/victims.js +0 -247
- package/dist/core/diff/victims.js.map +0 -1
- package/dist/core/repo/tree/views.js +0 -172
- package/dist/core/repo/tree/views.js.map +0 -1
- package/dist/core/staging/snapshot.js.map +0 -1
- package/dist/core/verify/file.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"landscape-merge.js","sourceRoot":"","sources":["../../../../src/core/c4/splice/landscape-merge.ts"],"names":[],"mappings":"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","sourcesContent":["\nimport { loadSource, type Elem, type Rel } from \"../likec4.js\";\nimport { elementService, serviceOf } from \"../resolve/service.js\";\nimport { scanModel, type ScannedElement, type ScannedModel, type ScannedRel } from \"../source-scan.js\";\nimport { spliceSource } from \"./authored-source.js\";\nimport { LandscapeSpliceError, type LandscapeMergeRequest, type LandscapePlan } from \"./contract.js\";\nimport { assertMergeableDelta } from \"./delta-blocks.js\";\nimport { relKey, relSortKey } from \"./identity/edges.js\";\nimport {\n elementSpot,\n nestedInsert,\n relSpot,\n topStatements,\n type ModelRegion,\n type Spot,\n} from \"./placement.js\";\n\n/* ------------------------------------------------------------------ */\n/* Merging */\n/* ------------------------------------------------------------------ */\n\n/**\n * Plan the merge of the feature's new elements + relationships into the living\n * landscape's `model { ... }` block (preserving the rest of the file).\n *\n * The additions are SPLICED from delta.likec4 as authored — byte for byte,\n * technology, style, icons, links, metadata, nested children and all — never\n * re-serialized from the parsed model: a rebuild keeps only the fields loam\n * models, and every field it forgets is authored detail destroyed. The one\n * edit on the way over is dropping the feature's own tag — the additions are\n * baseline now (SCHEMA.md documents the drop as why unarchive restores bytes\n * instead of recomputing) — and a construct the strip empties goes with it.\n *\n * Placement is deterministic and SERVICE-GROUPED (the spot* helpers in\n * placement.ts):\n * a top-level addition lands beside what already belongs to its service, so\n * two concurrent archives touching different services usually splice on\n * different lines and git merges their PRs — the single shared append point\n * every archive used to hit made two concurrent archives conflict BY\n * CONSTRUCTION. A NESTED element lands inside its parent's block — inside the\n * living parent when the landscape already has it, riding verbatim inside the\n * spliced parent when the parent is new from the same delta — never as a flat\n * dotted id at top level, which LikeC4 rejects. The additions carry no marker\n * comment: which archive added what is the git history's to say.\n *\n * Existence is checked semantically against the parsed landscape (by element\n * id/title and by edge identity), so re-archiving is idempotent and title\n * strings appearing elsewhere in the source cause no false skips. Assumes the\n * delta reuses the landscape's element identifiers for existing services. A\n * title match whose two sides are BOTH bound to different services is not an\n * existence hit but a collision, and refuses the archive (see the guard).\n *\n * Splicing is text surgery, so the computed result is PARSED before it is\n * returned: a merged landscape LikeC4 rejects refuses the archive at plan time\n * (merge-failed, nothing written — the unparseable-delta discipline) instead\n * of landing in the living docs.\n */\nexport async function planLandscapeMerge(merge: LandscapeMergeRequest): Promise<LandscapePlan> {\n const { landscapeText: text, deltaText, deltaElements, newEls, newRels, featureId } = merge;\n // First, and before the early return for \"nothing to add\": a block this merge\n // cannot carry is lost whether or not the delta also has tagged elements to\n // splice. See delta-blocks.ts.\n assertMergeableDelta(deltaText);\n const land = await loadSource(text);\n if (land.errors.length > 0) {\n throw new LandscapeSpliceError(`landscape.likec4 has ${land.errors.length} error(s) — fix it before archiving`);\n }\n const haveIds = new Set(land.elements.map((e) => e.id));\n // The title join needs the matched element back, not just membership: the\n // cross-service guard below compares service BINDINGS across the join.\n const byTitle = new Map<string, Elem[]>();\n const seeTitle = (el: Elem): void => {\n byTitle.set(el.title, [...(byTitle.get(el.title) ?? []), el]);\n };\n for (const el of land.elements) seeTitle(el);\n const addedEls: Elem[] = [];\n for (const e of newEls) {\n if (haveIds.has(e.id)) continue;\n const sameTitle = byTitle.get(e.title);\n if (sameTitle !== undefined) {\n // A title match is the id-less fallback join, and skipping on it is only\n // safe when the two sides could be the same box. When both sides carry an\n // explicit `metadata { service }` binding and every binding disagrees,\n // they are provably DIFFERENT services' boxes sharing a title ('API',\n // 'Database') — the skip would silently drop the addition, and any delta\n // edge into it would then refuse the whole archive at the parse net\n // below with a message about nothing. Refuse here instead, at plan time,\n // naming both sides.\n if (e.service !== undefined && sameTitle.every((m) => m.service !== undefined && m.service !== e.service)) {\n const m = sameTitle[0]!;\n throw new LandscapeSpliceError(\n `the delta's '${e.id}' (bound to service '${e.service}') shares the title '${e.title}' with '${m.id}' (bound to service '${m.service}') — a title join across services would silently drop the addition; ` +\n `retitle one of them, or reuse the id '${m.id}' if they really are the same element`,\n );\n }\n // KNOWN (narrowed by the guard above): with EITHER side unbound the title\n // join stays trusting — the unbound title-fallback is the legal legacy\n // pattern — so a cross-service collision hiding behind an unbound element\n // is still silently skipped here. Scoping titles per service is backlog.\n continue;\n }\n haveIds.add(e.id);\n seeTitle(e);\n addedEls.push(e);\n }\n\n // Edges are matched by COUNT, not by membership: two edges the model cannot tell\n // apart are still two edges, and dropping the second one silently loses a call\n // the author drew. An edge already in the landscape consumes one delta edge of\n // the same identity, which is what keeps re-archiving idempotent.\n const have = new Map<string, number>();\n for (const r of land.relationships) {\n const k = relKey(land.elements, r);\n have.set(k, (have.get(k) ?? 0) + 1);\n }\n const addedRels: Rel[] = [];\n for (const r of newRels) {\n const k = relKey(deltaElements, r);\n const n = have.get(k) ?? 0;\n if (n > 0) {\n have.set(k, n - 1);\n continue;\n }\n addedRels.push(r);\n }\n\n if (addedEls.length === 0 && addedRels.length === 0) return { content: null, addedEls, addedRels };\n\n const scan = scanModel(deltaText);\n if (scan === null) {\n throw new LandscapeSpliceError(\"delta.likec4 has no model block — nothing to splice the additions from\");\n }\n\n // Everything below either locates a declaration's authored bytes or refuses.\n // `spliced` remembers the delta ranges already carried over, so a child whose\n // parent is itself new is recognised as riding inside the parent's text and\n // is never inserted twice.\n const byId = new Map(scan.elements.map((e) => [e.id, e]));\n const spliced: Array<{ start: number; end: number }> = [];\n const rides = (start: number, end: number): boolean =>\n spliced.some((r) => start >= r.start && end <= r.end);\n\n // The living model, scanned on MASKED source (scanModel) and RE-SCANNED\n // after every splice: each addition lands in the text exactly as the\n // previous one left it, so an archive of N additions produces the same\n // bytes as N single-addition archives run back to back. Placement then\n // composes per statement — the unit the order-independence argument below\n // is stated in — instead of per archive, where a batch computed against a\n // stale layout could interleave with itself. Masking matters — a `model {`\n // spelled inside a comment or string above the real block must not capture\n // the match, or every top-level addition lands inside the comment (legal\n // LikeC4, so the parse net below would pass a landscape containing none of\n // the architecture).\n let content = text;\n // Service binding for placement: living elements first (they win a shared\n // id), the delta's after — a spliced statement's id resolves to its service\n // the moment its bytes land in the scan.\n const bindEls = [...land.elements, ...deltaElements.filter((d) => !land.elements.some((l) => l.id === d.id))];\n let livingScan = scanModel(content);\n let stmts = livingScan === null ? [] : topStatements(livingScan, bindEls);\n const rescan = (): void => {\n livingScan = scanModel(content);\n stmts = livingScan === null ? [] : topStatements(livingScan, bindEls);\n };\n const requireModel = (): ScannedModel => {\n if (livingScan === null) throw new LandscapeSpliceError(\"landscape.likec4 has no model block\");\n return livingScan;\n };\n // Built fresh at every use, never captured: `content` and `stmts` are rebound\n // by each rescan, and a region assembled before a splice describes a document\n // that no longer exists.\n const modelRegion = (): ModelRegion => ({ text: content, stmts, close: requireModel().close });\n const applyAt = (at: number, insert: string): void => {\n content = content.slice(0, at) + insert + content.slice(at);\n rescan();\n };\n const applyTop = (spot: Spot, block: string): void => {\n // A bare spot shares its line with other text (the closing brace, or a\n // statement the block displaces) — it brings its own newlines; a\n // line-start spot slots between lines.\n applyAt(spot.at, spot.bare ? `\\n${block}\\n` : `${block}\\n`);\n };\n\n // Placement walks the scanned statement layout, so a declaration the scan\n // cannot see is one placement would blindly splice around — LikeC4 accepts\n // two declarations on one line, but scanModel's statement head runs to the\n // end of the line, so the second rides invisibly inside the first: an\n // element bound to its service would miss its neighborhood, and a bodyless\n // parent gaining a body could wrap the wrong declaration. Refuse\n // mechanically (the parse-net discipline) instead of splicing blind.\n if (livingScan !== null) {\n const seen = new Set(livingScan.elements.map((e) => e.id));\n const invisible = land.elements.find((e) => !seen.has(e.id));\n if (invisible !== undefined) {\n throw new LandscapeSpliceError(\n `landscape.likec4 declares '${invisible.id}' in a form placement cannot locate — most often two declarations sharing one line; give each its own line, then re-run`,\n );\n }\n if (livingScan.rels.length < land.relationships.length) {\n throw new LandscapeSpliceError(\n `landscape.likec4 declares ${land.relationships.length} relationship(s) but placement can locate only ${livingScan.rels.length} — most often two statements sharing one line; give each its own line, then re-run`,\n );\n }\n }\n\n const livingParentOf = (parentId: string): ScannedElement | null => {\n if (livingScan === null) return null;\n const direct = livingScan.elements.find((e) => e.id === parentId);\n if (direct !== undefined) return direct;\n // The delta may spell an existing element under its own id; the title is\n // the stable cross-namespace name (the same rule the existence check uses).\n const title = deltaElements.find((e) => e.id === parentId)?.title;\n const livingId = title === undefined ? undefined : land.elements.find((e) => e.title === title)?.id;\n if (livingId === undefined) return null;\n return livingScan.elements.find((e) => e.id === livingId) ?? null;\n };\n\n // Ancestors first: a spliced parent covers its children before they are seen.\n const depth = (id: string): number => id.split(\".\").length;\n const sortedEls = [...addedEls].sort(\n (a, b) => depth(a.id) - depth(b.id) || (byId.get(a.id)?.start ?? 0) - (byId.get(b.id)?.start ?? 0),\n );\n for (const e of sortedEls) {\n const src = byId.get(e.id);\n if (src === undefined) {\n throw new LandscapeSpliceError(\n `cannot locate '${e.id}' in delta.likec4 — the landscape merge splices authored source, and this declaration was not found`,\n );\n }\n if (rides(src.start, src.end)) continue;\n const dot = e.id.lastIndexOf(\".\");\n if (dot === -1) {\n const spot = elementSpot(modelRegion(), e.id, elementService(e));\n applyTop(spot, spliceSource(deltaText, src, featureId, \" \"));\n spliced.push({ start: src.start, end: src.end });\n continue;\n }\n const parentId = e.id.slice(0, dot);\n const parent = livingParentOf(parentId);\n if (parent === null) {\n throw new LandscapeSpliceError(\n `'${e.id}' nests under '${parentId}', which is neither in the living landscape nor added by this delta — there is nowhere to insert it`,\n );\n }\n const nested = nestedInsert(content, parent, spliceSource(deltaText, src, featureId, parent.indent + \" \"));\n applyAt(nested.at, nested.insert);\n spliced.push({ start: src.start, end: src.end });\n }\n\n // Relationships: match each parsed addition back to its statement in the\n // delta source — full identity (endpoints, title, all three spine keys,\n // tags), consumed one statement per addition so duplicates stay duplicates.\n // The spine keys earn their place here the same way they do in `relKey`:\n // without them two additions differing only by `publishes` share one pool\n // entry, and `shift()` hands the second one the first one's authored bytes.\n const relKeyOf = (r: Rel | ScannedRel): string =>\n JSON.stringify([r.source, r.target, r.title ?? \"\", r.op ?? \"\", r.publishes ?? \"\", r.consumes ?? \"\", [...r.tags].sort()]);\n const pool = new Map<string, ScannedRel[]>();\n for (const s of scan.rels) {\n const k = relKeyOf(s);\n pool.set(k, [...(pool.get(k) ?? []), s]);\n }\n for (const r of addedRels) {\n const s = pool.get(relKeyOf(r))?.shift();\n if (s === undefined) {\n throw new LandscapeSpliceError(\n `cannot locate the '${r.source} -> ${r.target}' relationship in delta.likec4 — the landscape merge splices authored source, and no matching declaration was found`,\n );\n }\n if (rides(s.start, s.end)) continue;\n const key = relSortKey(deltaElements, r);\n // Deliberately no `known` fleet set: this resolves only the anchor a new\n // relationship lands after (placement.ts's reason — cosmetic grouping,\n // safety-netted by the re-parse below), never which service a check\n // grades.\n const spot = relSpot(modelRegion(), serviceOf(deltaElements, r.source), key);\n applyTop(spot, spliceSource(deltaText, s, featureId, \" \"));\n }\n\n // The safety net: prove the computed landscape parses before anything is\n // written. Splice bugs — and legal inputs the living document cannot absorb,\n // like a kind its specification never declares — refuse here, at plan time,\n // instead of corrupting the one file the whole fleet reads.\n const check = await loadSource(content);\n if (check.errors.length > 0) {\n const detail = check.errors\n .slice(0, 3)\n .map((e) => (typeof e.line === \"number\" ? `L${e.line}: ${e.message}` : e.message))\n .join(\"; \");\n throw new LandscapeSpliceError(\n `the merged landscape would not parse (${check.errors.length} error(s): ${detail}) — nothing was written. ` +\n `The delta's additions do not fit the living landscape as authored — most often an element kind or tag ` +\n `its specification block does not declare; fix the landscape's specification or the delta, then re-run`,\n );\n }\n\n return { content, addedEls, addedRels };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"landscape-merge.js","sourceRoot":"","sources":["../../../../src/core/c4/splice/landscape-merge.ts"],"names":[],"mappings":"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","sourcesContent":["\nimport { parentIdOf } from \"../../kernel/ids/fqn/ancestors.js\";\nimport { errorText, loadSource, type Elem, type Rel } from \"../likec4.js\";\nimport { firstUnlocated, unlocatedReason } from \"../locate/unlocated.js\";\nimport { elementService, serviceOf } from \"../resolve/service.js\";\nimport { kindsDeclared, scanModel, type ScannedElement, type ScannedModel, type ScannedRel } from \"../source-scan.js\";\nimport { matchLineEndings, spliceSource } from \"./authored-source.js\";\nimport {\n assertSpliceVisible,\n LandscapeSpliceError,\n type ExtendingModel,\n type LandscapeMergeRequest,\n type LandscapePlan,\n type ModelAdditions,\n} from \"./contract.js\";\nimport { assertMergeableDelta } from \"./delta-blocks.js\";\nimport { relSortKey, relStatementKey, scannedStatementKey } from \"./identity/edges.js\";\nimport { newAdditions } from \"./identity/existing.js\";\nimport { planInteriors } from \"./identity/interior.js\";\nimport { ownerOf } from \"./identity/owner.js\";\nimport { elementSpot, relSpot, topStatements, type ModelRegion } from \"./placement.js\";\nimport { nestedInsert, type Spot } from \"./text/spot.js\";\n\n/* ------------------------------------------------------------------ */\n/* Merging */\n/* ------------------------------------------------------------------ */\n\n/**\n * Plan the merge of the feature's new elements + relationships into the living\n * landscape's `model { ... }` block (preserving the rest of the file).\n *\n * The additions are SPLICED from delta.likec4 as authored — byte for byte,\n * technology, style, icons, links, metadata, nested children and all — never\n * re-serialized from the parsed model: a rebuild keeps only the fields loam\n * models, and every field it forgets is authored detail destroyed. The one\n * edit on the way over is dropping the feature's own tag — the additions are\n * baseline now (SCHEMA.md documents the drop as why unarchive restores bytes\n * instead of recomputing) — and a construct the strip empties goes with it.\n *\n * Placement is deterministic and SERVICE-GROUPED (the spot* helpers in\n * placement.ts):\n * a top-level addition lands beside what already belongs to its service, so\n * two concurrent archives touching different services usually splice on\n * different lines and git merges their PRs — the single shared append point\n * every archive used to hit made two concurrent archives conflict BY\n * CONSTRUCTION. A NESTED element lands inside its parent's block — inside the\n * living parent when the landscape already has it, riding verbatim inside the\n * spliced parent when the parent is new from the same delta — never as a flat\n * dotted id at top level, which LikeC4 rejects. The additions carry no marker\n * comment: which archive added what is the git history's to say.\n *\n * Existence is checked semantically against the parsed landscape AND against\n * every extending model the request carries (by element id/title and by edge\n * identity), so re-archiving is idempotent whichever document the additions\n * landed in — `./identity/existing.ts` holds that phase and its two joins, and\n * this function only turns the collision it reports into the refusal.\n *\n * Splicing is text surgery, so the computed result is PARSED before it is\n * returned: a merged landscape LikeC4 rejects refuses the archive at plan time\n * (merge-failed, nothing written — the unparseable-delta discipline) instead\n * of landing in the living docs.\n *\n * NOT EVERYTHING LANDS HERE. A service whose model EXTENDS this map owns its\n * own interior, and an addition nested under such a service is ROUTED to that\n * model instead (`./identity/owner.ts` decides, `./model/merge.ts` splices).\n * Until it was, a delta's container landed in the map and the service was\n * `c4.invalid` — a duplicate declaration — the moment its model wrote the same\n * container, which is exactly what the adopt brief tells it to do\n * (verification 2026-09-04, E1). With no extending models in the request this\n * function behaves as it always did.\n *\n * Routing per ADDITION is not the whole of it, because a service the feature\n * INTRODUCES carries its interior in one element's authored bytes and those\n * children carry no feature tag of their own. `./identity/interior.ts` decides, once\n * per such block, whether it hands that interior to the model — cut out of what\n * lands on the map — or rides whole; the routing below DEFERS to that decision\n * for everything written inside the block, which is what keeps the two from\n * placing the same child twice.\n */\nexport async function planLandscapeMerge(merge: LandscapeMergeRequest): Promise<LandscapePlan> {\n const { landscapeText: text, deltaText, deltaElements, newEls, newRels, featureId } = merge;\n const models = merge.models ?? [];\n // What every extending model borrows from this map: its kinds, without which\n // a model's scan reads `container outbox` and `a .delivers b` as property lines.\n const borrowed = kindsDeclared(text);\n // First, and before the early return for \"nothing to add\": a block this merge\n // cannot carry is lost whether or not the delta also has tagged elements to\n // splice. See delta-blocks.ts.\n assertMergeableDelta(deltaText);\n const land = await loadSource(text);\n if (land.errors.length > 0) {\n throw new LandscapeSpliceError(`landscape.likec4 has ${land.errors.length} error(s) — fix it before archiving`);\n }\n // Service binding for the existence joins AND for routing and placement:\n // living elements first (they win a shared id), the delta's after — a spliced\n // statement's id resolves to its service the moment its bytes land in the scan.\n const bindEls = [...land.elements, ...deltaElements.filter((d) => !land.elements.some((l) => l.id === d.id))];\n // What the living fleet already has — the map AND every extending model, by id\n // and by title. `./identity/existing.ts` holds both joins and their asymmetry.\n const added = newAdditions({\n livingEls: land.elements,\n livingRels: land.relationships,\n bindEls,\n deltaElements,\n candidates: { els: newEls, rels: newRels },\n models,\n borrowed,\n });\n if (added.collision !== undefined) {\n const { addition: e, living: m } = added.collision;\n throw new LandscapeSpliceError(\n `the delta's '${e.id}' (bound to service '${e.service}') shares the title '${e.title}' with '${m.id}' (bound to service '${m.service}') — a title join across services would silently drop the addition; ` +\n `retitle one of them, or reuse the id '${m.id}' if they really are the same element`,\n );\n }\n const addedEls = added.els;\n const addedRels = added.rels;\n\n const owner = ownerOf({\n bindEls,\n living: new Set(land.elements.map((e) => e.id)),\n declared: added.declaredIds,\n added: new Set(addedEls.map((e) => e.id)),\n models,\n });\n // Nothing to add: the same shape the merge returned before routing existed,\n // and the reason it is decided HERE rather than after the loops below — a\n // no-op archive must not have to scan the delta, nor answer the landscape\n // guards further down, which refuse documents this merge is not touching.\n // Equivalent to the old \"nothing reached the map and nothing was routed\":\n // every addition ends up in one of those two, so an empty pair means both.\n if (addedEls.length === 0 && addedRels.length === 0) {\n return { content: null, addedEls: [], addedRels: [], models: [] };\n }\n\n const scan = scanModel(deltaText);\n if (scan === null) {\n throw new LandscapeSpliceError(\"delta.likec4 has no model block — nothing to splice the additions from\");\n }\n\n // Everything below either locates a declaration's authored bytes or refuses.\n // `spliced` remembers the delta ranges already carried over, so a child whose\n // parent is itself new is recognised as riding inside the parent's text and\n // is never inserted twice.\n const byId = new Map(scan.elements.map((e) => [e.id, e]));\n // Relationships: match each parsed addition back to its statement in the\n // delta source — full identity (`relStatementKey`), consumed one statement\n // per addition so duplicates stay duplicates. Built before the routing\n // because routing has to know WHERE an edge was written: one drawn inside a\n // block that rides whole is already on the map. A statement is keyed with the\n // tags its kind gives it, which the parsed addition carries and its text does not.\n const pool = new Map<string, ScannedRel[]>();\n for (const s of scan.rels) {\n const k = scannedStatementKey(s, merge.deltaKindTags ?? {});\n pool.set(k, [...(pool.get(k) ?? []), s]);\n }\n\n const interiors = planInteriors({ scan, deltaElements, owner, addedEls });\n const routed = new Map<string, ModelAdditions>();\n const into = (model: ExtendingModel): ModelAdditions => {\n const existing = routed.get(model.path);\n if (existing !== undefined) return existing;\n const fresh: ModelAdditions = { model, els: [], rels: [], borrowed };\n routed.set(model.path, fresh);\n return fresh;\n };\n for (const share of interiors.routed) into(share.model).els.push(...share.els);\n\n const mapEls: Elem[] = [];\n for (const e of addedEls) {\n const src = byId.get(e.id);\n // Written inside a block that has already decided: a split block handed it\n // to the model with its siblings, and a whole one carries it onto the map\n // in the parent's own bytes, where the splice loop's `rides` finds it. Both\n // are placed exactly once, which is the point of asking the block first.\n const fate = src === undefined ? null : interiors.covering(src);\n if (fate === \"split\") continue;\n const model = fate === \"whole\" ? undefined : owner(parentIdOf(e.id));\n if (model === undefined) mapEls.push(e);\n else into(model).els.push(e);\n }\n const mapRels: Rel[] = [];\n for (const r of addedRels) {\n // An edge written inside a block that rides whole names its endpoints by\n // their LOCAL names and reads only there; it stays with its block.\n const stmts = pool.get(relStatementKey(r)) ?? [];\n const inBlock = stmts.length > 0 && stmts.every((s) => interiors.covering(s) !== null);\n // Otherwise the SOURCE decides: a call is drawn where the caller draws its\n // calls, and only when the source is not itself interior does the target's\n // owner get the edge. A service-level edge belongs to neither and stays on\n // the map.\n const model = inBlock ? undefined : owner(parentIdOf(r.source)) ?? owner(parentIdOf(r.target));\n if (model === undefined) mapRels.push(r);\n else into(model).rels.push(r);\n }\n const touchesMap = mapEls.length > 0 || mapRels.length > 0;\n\n const spliced: Array<{ start: number; end: number }> = [];\n const rides = (start: number, end: number): boolean =>\n spliced.some((r) => start >= r.start && end <= r.end);\n\n // The living model, scanned on MASKED source (scanModel) and RE-SCANNED\n // after every splice: each addition lands in the text exactly as the\n // previous one left it, so an archive of N additions produces the same\n // bytes as N single-addition archives run back to back. Placement then\n // composes per statement — the unit the order-independence argument below\n // is stated in — instead of per archive, where a batch computed against a\n // stale layout could interleave with itself. Masking matters — a `model {`\n // spelled inside a comment or string above the real block must not capture\n // the match, or every top-level addition lands inside the comment (legal\n // LikeC4, so the parse net below would pass a landscape containing none of\n // the architecture).\n let content = text;\n let livingScan = scanModel(content);\n let stmts = livingScan === null ? [] : topStatements(livingScan, bindEls);\n const rescan = (): void => {\n livingScan = scanModel(content);\n stmts = livingScan === null ? [] : topStatements(livingScan, bindEls);\n };\n const requireModel = (): ScannedModel => {\n if (livingScan === null) throw new LandscapeSpliceError(\"landscape.likec4 has no model block\");\n return livingScan;\n };\n // Built fresh at every use, never captured: `content` and `stmts` are rebound\n // by each rescan, and a region assembled before a splice describes a document\n // that no longer exists.\n const modelRegion = (): ModelRegion => ({ text: content, stmts, blocks: requireModel().blocks });\n // Every insert must be one the next scan sees (`assertSpliceVisible`).\n const applyAt = (at: number, insert: string, what: string): void => {\n const before = livingScan;\n content = content.slice(0, at) + insert + content.slice(at);\n rescan();\n assertSpliceVisible(before, livingScan, what);\n };\n const applyTop = (spot: Spot, block: string, what: string): void => {\n // A bare spot shares its line with other text (the closing brace, or a\n // statement the block displaces) — it brings its own newlines; a\n // line-start spot slots between lines.\n applyAt(spot.at, spot.bare ? `\\n${block}\\n` : `${block}\\n`, what);\n };\n\n // Placement walks the scanned statement layout, so a declaration the scan\n // cannot see is one placement would blindly splice around — LikeC4 accepts\n // two declarations on one line, but scanModel's statement head runs to the\n // end of the line, so the second rides invisibly inside the first: an\n // element bound to its service would miss its neighborhood, and a bodyless\n // parent gaining a body could wrap the wrong declaration. Refuse\n // mechanically (the parse-net discipline) instead of splicing blind.\n //\n // THAT something is unlocated is decided here, from the parse already in\n // hand; WHAT and why is `firstUnlocated`'s, at the price of a second parse on\n // this path alone. The message used to guess \"most often two declarations\n // sharing one line\" whatever the map held, and a fleet read it over a\n // declaration on a line of its own in a second `model { }` block the scan\n // did not read then (2026-10): it names LikeC4's line now, and a shared line\n // only when that line shows one.\n if (livingScan !== null) {\n const seen = new Set(livingScan.elements.map((e) => e.id));\n const blind = land.elements.some((e) => !seen.has(e.id)) || livingScan.rels.length < land.relationships.length;\n if (blind) throw new LandscapeSpliceError(unlocatedReason(\"landscape.likec4\", await firstUnlocated(text, livingScan)));\n }\n\n const livingParentOf = (parentId: string): ScannedElement | null => {\n if (livingScan === null) return null;\n const direct = livingScan.elements.find((e) => e.id === parentId);\n if (direct !== undefined) return direct;\n // The delta may spell an existing element under its own id; the title is\n // the stable cross-namespace name (the same rule the existence check uses).\n const title = deltaElements.find((e) => e.id === parentId)?.title;\n const livingId = title === undefined ? undefined : land.elements.find((e) => e.title === title)?.id;\n if (livingId === undefined) return null;\n return livingScan.elements.find((e) => e.id === livingId) ?? null;\n };\n\n // Ancestors first: a spliced parent covers its children before they are seen.\n const depth = (id: string): number => id.split(\".\").length;\n const sortedEls = [...mapEls].sort(\n (a, b) => depth(a.id) - depth(b.id) || (byId.get(a.id)?.start ?? 0) - (byId.get(b.id)?.start ?? 0),\n );\n for (const e of sortedEls) {\n const src = byId.get(e.id);\n if (src === undefined) {\n throw new LandscapeSpliceError(\n `cannot locate '${e.id}' in delta.likec4 — the landscape merge splices authored source, and this declaration was not found`,\n );\n }\n if (rides(src.start, src.end)) continue;\n // Every split block's children, whichever block they belong to:\n // `spliceSource` keeps only the ranges that fall inside the bytes it is\n // carrying, so a block riding inside ANOTHER new block still loses its own\n // interior on the way to the map.\n const omit = interiors.omit;\n const dot = e.id.lastIndexOf(\".\");\n if (dot === -1) {\n const spot = elementSpot(modelRegion(), e.id, elementService(e));\n applyTop(spot, spliceSource(deltaText, src, { featureId, indent: \" \", omit }), e.id);\n spliced.push({ start: src.start, end: src.end });\n continue;\n }\n const parentId = e.id.slice(0, dot);\n const parent = livingParentOf(parentId);\n if (parent === null) {\n throw new LandscapeSpliceError(\n `'${e.id}' nests under '${parentId}', which is neither in the living landscape nor added by this delta — there is nowhere to insert it`,\n );\n }\n const nested = nestedInsert(\n content,\n parent,\n spliceSource(deltaText, src, { featureId, indent: parent.indent + \" \", omit }),\n );\n applyAt(nested.at, nested.insert, e.id);\n spliced.push({ start: src.start, end: src.end });\n }\n\n // Each map-bound addition takes its statement out of the pool built above:\n // one statement per addition, so duplicates stay duplicates.\n for (const r of mapRels) {\n const s = pool.get(relStatementKey(r))?.shift();\n if (s === undefined) {\n throw new LandscapeSpliceError(\n `cannot locate the '${r.source} -> ${r.target}' relationship in delta.likec4 — the landscape merge splices authored source, and no matching declaration was found`,\n );\n }\n if (rides(s.start, s.end)) continue;\n const key = relSortKey(deltaElements, r);\n // Deliberately no `known` fleet set: this resolves only the anchor a new\n // relationship lands after (placement.ts's reason — cosmetic grouping,\n // safety-netted by the re-parse below), never which service a check\n // grades.\n const spot = relSpot(modelRegion(), serviceOf(deltaElements, r.source), key);\n applyTop(spot, spliceSource(deltaText, s, { featureId, indent: \" \" }), `${r.source} -> ${r.target}`);\n }\n\n // The safety net: prove the computed landscape parses before anything is\n // written. Splice bugs — and legal inputs the living document cannot absorb,\n // like a kind its specification never declares — refuse here, at plan time,\n // instead of corrupting the one file the whole fleet reads. Skipped when\n // every addition was routed away: the text is the one already parsed above,\n // and the models get their own net from the caller, which is the only side\n // that can stage a model beside the map it extends.\n // The splice composed bytes from two documents, and the delta's newlines are\n // not necessarily the map's. Corrected before the net, so what is proven is\n // what would be written.\n content = matchLineEndings(text, content);\n if (touchesMap) {\n const check = await loadSource(content);\n if (check.errors.length > 0) {\n const detail = check.errors\n .slice(0, 3)\n .map(errorText)\n .join(\"; \");\n throw new LandscapeSpliceError(\n `the merged landscape would not parse (${check.errors.length} error(s): ${detail}) — nothing was written. ` +\n `The delta's additions do not fit the living landscape as authored — most often an element kind or tag ` +\n `its specification block does not declare; fix the landscape's specification or the delta, then re-run`,\n );\n }\n }\n\n return { content: touchesMap ? content : null, addedEls: mapEls, addedRels: mapRels, models: [...routed.values()] };\n}\n"]}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { scanModel } from "../../source-scan.js";
|
|
2
|
+
import { matchLineEndings, spliceSource } from "../authored-source.js";
|
|
3
|
+
import { assertSpliceVisible, LandscapeSpliceError } from "../contract.js";
|
|
4
|
+
import { relStatementKey, scannedStatementKey } from "../identity/edges.js";
|
|
5
|
+
import { HOME_BLOCK } from "../placement.js";
|
|
6
|
+
import { closeSpot, nestedInsert, spotAfter } from "../text/spot.js";
|
|
7
|
+
/** The merged model source. Refuses (never guesses) when the delta or the model cannot be read. */
|
|
8
|
+
export function spliceModel(req) {
|
|
9
|
+
const { additions, deltaText, featureId } = req;
|
|
10
|
+
const { model, borrowed } = additions;
|
|
11
|
+
const scan = scanModel(deltaText);
|
|
12
|
+
if (scan === null) {
|
|
13
|
+
throw new LandscapeSpliceError("delta.likec4 has no model block — nothing to splice the additions from");
|
|
14
|
+
}
|
|
15
|
+
const byId = new Map(scan.elements.map((e) => [e.id, e]));
|
|
16
|
+
const pool = new Map();
|
|
17
|
+
for (const s of scan.rels) {
|
|
18
|
+
const k = scannedStatementKey(s, req.deltaKindTags ?? {});
|
|
19
|
+
pool.set(k, [...(pool.get(k) ?? []), s]);
|
|
20
|
+
}
|
|
21
|
+
// Read with the map's kinds: the model declares none, and a `container
|
|
22
|
+
// outbox` frame or an `a .delivers b` edge it cannot see is a parent with
|
|
23
|
+
// nowhere to nest into, or an anchor the next edge lands above.
|
|
24
|
+
let content = withModelBlock(model.text, borrowed);
|
|
25
|
+
let live = read(content, model.path, borrowed);
|
|
26
|
+
// The delta ranges already carried over, so a child whose parent is itself
|
|
27
|
+
// new is recognised as riding inside the parent's text — the same rule the
|
|
28
|
+
// landscape merge states, and the reason `node` inside a new `cache` is never
|
|
29
|
+
// spliced twice.
|
|
30
|
+
const spliced = [];
|
|
31
|
+
const rides = (start, end) => spliced.some((r) => start >= r.start && end <= r.end);
|
|
32
|
+
// Every insert must be one the next scan sees — the landscape merge's backstop.
|
|
33
|
+
const applyAt = (at, insert, what) => {
|
|
34
|
+
const before = live;
|
|
35
|
+
content = content.slice(0, at) + insert + content.slice(at);
|
|
36
|
+
live = read(content, model.path, borrowed);
|
|
37
|
+
assertSpliceVisible(before, live, what);
|
|
38
|
+
};
|
|
39
|
+
// Ancestors first, exactly as the landscape merge orders them: a spliced
|
|
40
|
+
// parent covers its children before they are seen.
|
|
41
|
+
const depth = (id) => id.split(".").length;
|
|
42
|
+
const ordered = [...additions.els].sort((a, b) => depth(a.id) - depth(b.id) || (byId.get(a.id)?.start ?? 0) - (byId.get(b.id)?.start ?? 0));
|
|
43
|
+
for (const e of ordered) {
|
|
44
|
+
const src = byId.get(e.id);
|
|
45
|
+
if (src === undefined) {
|
|
46
|
+
throw new LandscapeSpliceError(`cannot locate '${e.id}' in delta.likec4 — the model merge splices authored source, and this declaration was not found`);
|
|
47
|
+
}
|
|
48
|
+
if (rides(src.start, src.end))
|
|
49
|
+
continue;
|
|
50
|
+
const [at, insert] = elementInsert({
|
|
51
|
+
content,
|
|
52
|
+
live,
|
|
53
|
+
block: (indent) => spliceSource(deltaText, src, { featureId, indent }),
|
|
54
|
+
parent: parentIdOf(e),
|
|
55
|
+
});
|
|
56
|
+
applyAt(at, insert, e.id);
|
|
57
|
+
spliced.push({ start: src.start, end: src.end });
|
|
58
|
+
}
|
|
59
|
+
for (const r of additions.rels) {
|
|
60
|
+
const s = pool.get(relStatementKey(r))?.shift();
|
|
61
|
+
if (s === undefined) {
|
|
62
|
+
throw new LandscapeSpliceError(`cannot locate the '${r.source} -> ${r.target}' relationship in delta.likec4 — the model merge splices authored source, and no matching declaration was found`);
|
|
63
|
+
}
|
|
64
|
+
if (rides(s.start, s.end))
|
|
65
|
+
continue;
|
|
66
|
+
const { close } = live.blocks[HOME_BLOCK];
|
|
67
|
+
const base = blockIndent(content, close);
|
|
68
|
+
// Top-level in the model block: an edge written inside an `extend` block is
|
|
69
|
+
// that block's, and anchoring after it would splice into someone's body.
|
|
70
|
+
// And in the HOME block: the anchor's own close is what `spotAfter` clamps
|
|
71
|
+
// to, and an edge last in a later block would otherwise pull this one there.
|
|
72
|
+
const top = live.rels.filter((x) => x.block === HOME_BLOCK && !live.elements.some((el) => x.start > el.start && x.start < el.end));
|
|
73
|
+
const anchor = top.at(-1);
|
|
74
|
+
const spot = anchor === undefined ? closeSpot(content, close) : spotAfter(content, close, anchor.end);
|
|
75
|
+
const block = spliceSource(deltaText, s, { featureId, indent: `${base} ` });
|
|
76
|
+
applyAt(spot.at, spot.bare ? `\n${block}\n` : `${block}\n`, `${r.source} -> ${r.target}`);
|
|
77
|
+
}
|
|
78
|
+
// The delta's newlines are not necessarily this model's, and a merge that left
|
|
79
|
+
// both conventions in one file is noise in every editor and every diff — the
|
|
80
|
+
// same correction the landscape merge makes, from the same helper
|
|
81
|
+
// (verification 2026-09-04, W-CRLF).
|
|
82
|
+
return matchLineEndings(model.text, content);
|
|
83
|
+
}
|
|
84
|
+
/** The parent an addition nests under. Routing only ever sends nested ids here. */
|
|
85
|
+
function parentIdOf(e) {
|
|
86
|
+
return e.id.slice(0, e.id.lastIndexOf("."));
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Where one element's block goes, as `(offset, text)`.
|
|
90
|
+
*
|
|
91
|
+
* Two arms, and the second is the one that makes a freshly adopted service
|
|
92
|
+
* work: a model that has never named this container's parent has no `extend`
|
|
93
|
+
* block for it, so the merge writes one rather than refusing. A parent the
|
|
94
|
+
* merged project will not resolve is caught by the caller's parse net, which is
|
|
95
|
+
* the only reader that can see the map and the model together.
|
|
96
|
+
*/
|
|
97
|
+
function elementInsert(req) {
|
|
98
|
+
const { content, live, block, parent } = req;
|
|
99
|
+
const declared = live.elements.find((x) => x.id === parent);
|
|
100
|
+
if (declared !== undefined) {
|
|
101
|
+
const nested = nestedInsert(content, declared, block(`${declared.indent} `));
|
|
102
|
+
return [nested.at, nested.insert];
|
|
103
|
+
}
|
|
104
|
+
const { close } = live.blocks[HOME_BLOCK];
|
|
105
|
+
const base = blockIndent(content, close);
|
|
106
|
+
const body = `${base} extend ${parent} {\n${block(`${base} `)}\n${base} }`;
|
|
107
|
+
const spot = closeSpot(content, close);
|
|
108
|
+
return [spot.at, spot.bare ? `\n${body}\n` : `${body}\n`];
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The model, with a `model { }` block appended when the file has none.
|
|
112
|
+
*
|
|
113
|
+
* `../../service-model/shape.ts` answers `extending` for an empty file, a
|
|
114
|
+
* views-only file and a tags-only `specification { }` — three shapes it calls
|
|
115
|
+
* legal on purpose — so routing hands those models a nested addition, and
|
|
116
|
+
* refusing there took a whole legal shape away from `loam archive` for a
|
|
117
|
+
* document the merge is perfectly able to author (review of E1: before the
|
|
118
|
+
* routing existed, the same delta merged onto the map). It is the call
|
|
119
|
+
* `elementInsert` already makes one level down — a model that has never named
|
|
120
|
+
* the parent gains the `extend` block rather than refusing — and the caller's
|
|
121
|
+
* parse net proves the result either way.
|
|
122
|
+
*/
|
|
123
|
+
function withModelBlock(text, borrowed) {
|
|
124
|
+
if (scanModel(text, borrowed) !== null)
|
|
125
|
+
return text;
|
|
126
|
+
const pad = text === "" || text.endsWith("\n") ? "" : "\n";
|
|
127
|
+
return `${text}${pad}model {\n}\n`;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* The model's `model { }` block, re-scanned after every splice so each addition
|
|
131
|
+
* lands in the text the previous one left — the landscape merge's rule, for the
|
|
132
|
+
* same reason: placement composes per statement, not per archive.
|
|
133
|
+
*
|
|
134
|
+
* `withModelBlock` guarantees the FIRST read finds one, so a null here means a
|
|
135
|
+
* splice destroyed the block it was writing into: mechanical, so it refuses at
|
|
136
|
+
* plan time with nothing written, exactly as the parse nets do.
|
|
137
|
+
*/
|
|
138
|
+
function read(content, path, borrowed) {
|
|
139
|
+
const scan = scanModel(content, borrowed);
|
|
140
|
+
if (scan === null) {
|
|
141
|
+
throw new LandscapeSpliceError(`merging this feature's additions left ${path} without a model block — nothing was written; re-run after reporting it`);
|
|
142
|
+
}
|
|
143
|
+
return scan;
|
|
144
|
+
}
|
|
145
|
+
/** The indentation of the line the model block's closing brace sits on, or "" when it shares one. */
|
|
146
|
+
function blockIndent(text, close) {
|
|
147
|
+
const lineStart = text.lastIndexOf("\n", close - 1) + 1;
|
|
148
|
+
const before = text.slice(lineStart, close);
|
|
149
|
+
return /^[ \t]*$/.test(before) ? before : "";
|
|
150
|
+
}
|
|
151
|
+
//# sourceMappingURL=merge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../../../../src/core/c4/splice/model/merge.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The other half of the archive's C4 merge: what a feature adds INSIDE a\n * service, spliced into the service's own extending `model.likec4`.\n *\n * `../landscape-merge.ts` routes the additions (`../identity/owner.ts` states\n * the rule) and this carries them over, by the same discipline: authored source,\n * byte for byte,\n * with the feature's own tag stripped and the indentation rebased — never a\n * re-serialization of the parsed model, which keeps only the fields loam models.\n *\n * PLACEMENT IS SIMPLER HERE, and deliberately so. The map groups additions by\n * service because every service writes into it and concurrent archives must\n * merge in git; a service model has ONE service in it, so there is no\n * neighborhood to join. An element lands inside the `extend <fqn> { … }` block\n * that owns its parent — or inside its parent's own block when the model\n * already declares that container — and a model with no `extend` block for the\n * fqn gains one at the end of its `model { }` block, as a model with no `model\n * { }` block at all gains that. A relationship lands after the last top-level\n * relationship of that block, or last in it. A model written in SEVERAL\n * `model { }` blocks is read whole — a parent's `extend` frame is found in\n * whichever block holds it — and \"its block\" for everything else is\n * `HOME_BLOCK`, the first, for the reasons `../placement.ts` gives the map.\n *\n * WHAT THIS DOES NOT DO IS PROVE THE RESULT. The landscape merge parses its own\n * output because a landscape is a self-contained document; an extending model\n * is not — it is read beside the `architecture/` project, and staging that set\n * means touching the docs repo. So the parse net lives with the caller\n * (`commands/archive/plan/model/extending.ts`), which is also the side that\n * holds the merged MAP the model must be proven against.\n */\nimport type { Elem } from \"../../likec4.js\";\nimport { scanModel, type ScanKinds, type ScannedModel, type ScannedRel } from \"../../source-scan.js\";\nimport { matchLineEndings, spliceSource } from \"../authored-source.js\";\nimport { assertSpliceVisible, LandscapeSpliceError, type KindTags, type ModelAdditions } from \"../contract.js\";\nimport { relStatementKey, scannedStatementKey } from \"../identity/edges.js\";\nimport { HOME_BLOCK } from \"../placement.js\";\nimport { closeSpot, nestedInsert, spotAfter } from \"../text/spot.js\";\n\nexport interface ModelMergeRequest {\n /** One model's share of the merge, as `planLandscapeMerge` routed it. */\n additions: ModelAdditions;\n /** delta.likec4 as authored — the bytes the additions are spliced from. */\n deltaText: string;\n featureId: string;\n /** The delta's relationship kinds' tags — the landscape merge's own reason (`../identity/edges.ts`). */\n deltaKindTags?: KindTags;\n}\n\n/** The merged model source. Refuses (never guesses) when the delta or the model cannot be read. */\nexport function spliceModel(req: ModelMergeRequest): string {\n const { additions, deltaText, featureId } = req;\n const { model, borrowed } = additions;\n const scan = scanModel(deltaText);\n if (scan === null) {\n throw new LandscapeSpliceError(\"delta.likec4 has no model block — nothing to splice the additions from\");\n }\n const byId = new Map(scan.elements.map((e) => [e.id, e]));\n const pool = new Map<string, ScannedRel[]>();\n for (const s of scan.rels) {\n const k = scannedStatementKey(s, req.deltaKindTags ?? {});\n pool.set(k, [...(pool.get(k) ?? []), s]);\n }\n\n // Read with the map's kinds: the model declares none, and a `container\n // outbox` frame or an `a .delivers b` edge it cannot see is a parent with\n // nowhere to nest into, or an anchor the next edge lands above.\n let content = withModelBlock(model.text, borrowed);\n let live = read(content, model.path, borrowed);\n // The delta ranges already carried over, so a child whose parent is itself\n // new is recognised as riding inside the parent's text — the same rule the\n // landscape merge states, and the reason `node` inside a new `cache` is never\n // spliced twice.\n const spliced: Array<{ start: number; end: number }> = [];\n const rides = (start: number, end: number): boolean =>\n spliced.some((r) => start >= r.start && end <= r.end);\n // Every insert must be one the next scan sees — the landscape merge's backstop.\n const applyAt = (at: number, insert: string, what: string): void => {\n const before = live;\n content = content.slice(0, at) + insert + content.slice(at);\n live = read(content, model.path, borrowed);\n assertSpliceVisible(before, live, what);\n };\n\n // Ancestors first, exactly as the landscape merge orders them: a spliced\n // parent covers its children before they are seen.\n const depth = (id: string): number => id.split(\".\").length;\n const ordered = [...additions.els].sort(\n (a, b) => depth(a.id) - depth(b.id) || (byId.get(a.id)?.start ?? 0) - (byId.get(b.id)?.start ?? 0),\n );\n for (const e of ordered) {\n const src = byId.get(e.id);\n if (src === undefined) {\n throw new LandscapeSpliceError(\n `cannot locate '${e.id}' in delta.likec4 — the model merge splices authored source, and this declaration was not found`,\n );\n }\n if (rides(src.start, src.end)) continue;\n const [at, insert] = elementInsert({\n content,\n live,\n block: (indent) => spliceSource(deltaText, src, { featureId, indent }),\n parent: parentIdOf(e),\n });\n applyAt(at, insert, e.id);\n spliced.push({ start: src.start, end: src.end });\n }\n\n for (const r of additions.rels) {\n const s = pool.get(relStatementKey(r))?.shift();\n if (s === undefined) {\n throw new LandscapeSpliceError(\n `cannot locate the '${r.source} -> ${r.target}' relationship in delta.likec4 — the model merge splices authored source, and no matching declaration was found`,\n );\n }\n if (rides(s.start, s.end)) continue;\n const { close } = live.blocks[HOME_BLOCK]!;\n const base = blockIndent(content, close);\n // Top-level in the model block: an edge written inside an `extend` block is\n // that block's, and anchoring after it would splice into someone's body.\n // And in the HOME block: the anchor's own close is what `spotAfter` clamps\n // to, and an edge last in a later block would otherwise pull this one there.\n const top = live.rels.filter(\n (x) => x.block === HOME_BLOCK && !live.elements.some((el) => x.start > el.start && x.start < el.end),\n );\n const anchor = top.at(-1);\n const spot = anchor === undefined ? closeSpot(content, close) : spotAfter(content, close, anchor.end);\n const block = spliceSource(deltaText, s, { featureId, indent: `${base} ` });\n applyAt(spot.at, spot.bare ? `\\n${block}\\n` : `${block}\\n`, `${r.source} -> ${r.target}`);\n }\n // The delta's newlines are not necessarily this model's, and a merge that left\n // both conventions in one file is noise in every editor and every diff — the\n // same correction the landscape merge makes, from the same helper\n // (verification 2026-09-04, W-CRLF).\n return matchLineEndings(model.text, content);\n}\n\n/** The parent an addition nests under. Routing only ever sends nested ids here. */\nfunction parentIdOf(e: Elem): string {\n return e.id.slice(0, e.id.lastIndexOf(\".\"));\n}\n\ninterface ElementInsert {\n content: string;\n live: ScannedModel;\n /** The authored block at a given indent — computed late, because the indent depends on where it lands. */\n block: (indent: string) => string;\n parent: string;\n}\n\n/**\n * Where one element's block goes, as `(offset, text)`.\n *\n * Two arms, and the second is the one that makes a freshly adopted service\n * work: a model that has never named this container's parent has no `extend`\n * block for it, so the merge writes one rather than refusing. A parent the\n * merged project will not resolve is caught by the caller's parse net, which is\n * the only reader that can see the map and the model together.\n */\nfunction elementInsert(req: ElementInsert): [number, string] {\n const { content, live, block, parent } = req;\n const declared = live.elements.find((x) => x.id === parent);\n if (declared !== undefined) {\n const nested = nestedInsert(content, declared, block(`${declared.indent} `));\n return [nested.at, nested.insert];\n }\n const { close } = live.blocks[HOME_BLOCK]!;\n const base = blockIndent(content, close);\n const body = `${base} extend ${parent} {\\n${block(`${base} `)}\\n${base} }`;\n const spot = closeSpot(content, close);\n return [spot.at, spot.bare ? `\\n${body}\\n` : `${body}\\n`];\n}\n\n/**\n * The model, with a `model { }` block appended when the file has none.\n *\n * `../../service-model/shape.ts` answers `extending` for an empty file, a\n * views-only file and a tags-only `specification { }` — three shapes it calls\n * legal on purpose — so routing hands those models a nested addition, and\n * refusing there took a whole legal shape away from `loam archive` for a\n * document the merge is perfectly able to author (review of E1: before the\n * routing existed, the same delta merged onto the map). It is the call\n * `elementInsert` already makes one level down — a model that has never named\n * the parent gains the `extend` block rather than refusing — and the caller's\n * parse net proves the result either way.\n */\nfunction withModelBlock(text: string, borrowed: ScanKinds): string {\n if (scanModel(text, borrowed) !== null) return text;\n const pad = text === \"\" || text.endsWith(\"\\n\") ? \"\" : \"\\n\";\n return `${text}${pad}model {\\n}\\n`;\n}\n\n/**\n * The model's `model { }` block, re-scanned after every splice so each addition\n * lands in the text the previous one left — the landscape merge's rule, for the\n * same reason: placement composes per statement, not per archive.\n *\n * `withModelBlock` guarantees the FIRST read finds one, so a null here means a\n * splice destroyed the block it was writing into: mechanical, so it refuses at\n * plan time with nothing written, exactly as the parse nets do.\n */\nfunction read(content: string, path: string, borrowed: ScanKinds): ScannedModel {\n const scan = scanModel(content, borrowed);\n if (scan === null) {\n throw new LandscapeSpliceError(\n `merging this feature's additions left ${path} without a model block — nothing was written; re-run after reporting it`,\n );\n }\n return scan;\n}\n\n/** The indentation of the line the model block's closing brace sits on, or \"\" when it shares one. */\nfunction blockIndent(text: string, close: number): string {\n const lineStart = text.lastIndexOf(\"\\n\", close - 1) + 1;\n const before = text.slice(lineStart, close);\n return /^[ \\t]*$/.test(before) ? before : \"\";\n}\n"]}
|
|
@@ -1,9 +1,89 @@
|
|
|
1
1
|
import {} from "../likec4.js";
|
|
2
2
|
import { elementService, serviceOf } from "../resolve/service.js";
|
|
3
3
|
import { relSortKey } from "./identity/edges.js";
|
|
4
|
+
import { aboveComments, closeSpot, lineStartAt, spotAfter } from "./text/spot.js";
|
|
5
|
+
/* ------------------------------------------------------------------ */
|
|
6
|
+
/* Landscape placement — where a top-level addition lands */
|
|
7
|
+
/* ------------------------------------------------------------------ */
|
|
8
|
+
/**
|
|
9
|
+
* The placement scheme, in full. It never moves an authored byte — placement
|
|
10
|
+
* only chooses where NEW spliced blocks go — and it is deterministic in a
|
|
11
|
+
* stronger sense: archiving feature A then feature B (touching different
|
|
12
|
+
* services) yields the SAME final bytes as B then A, which is what lets two
|
|
13
|
+
* concurrent archive PRs merge in git instead of colliding on one shared
|
|
14
|
+
* append point.
|
|
15
|
+
*
|
|
16
|
+
* - An ELEMENT whose service already has top-level elements in the model
|
|
17
|
+
* (the elementService join — binding first, title as the fallback) lands
|
|
18
|
+
* immediately after the last of them: it joins its service's neighborhood.
|
|
19
|
+
* Two features touching the SAME service therefore land adjacently, and
|
|
20
|
+
* their concurrent PRs still conflict — expected, and documented
|
|
21
|
+
* (SCHEMA.md sends that conflict to the PR flow).
|
|
22
|
+
* - An element opening a NEW service lands in the trailing region before the
|
|
23
|
+
* model's closing brace: skip the trailing relationship run, then walk left
|
|
24
|
+
* per same-service RUN, past every run whose leading id is
|
|
25
|
+
* lexicographically greater — an insertion sort of neighborhood heads
|
|
26
|
+
* against whatever is already there, which is what makes the region's
|
|
27
|
+
* final order independent of archive order (see the note on elementSpot:
|
|
28
|
+
* per-statement comparison was order-dependent).
|
|
29
|
+
* - A RELATIONSHIP lands after the last top-level relationship touching its
|
|
30
|
+
* SOURCE's service (either endpoint counts), then past the anchor's own
|
|
31
|
+
* CLUSTER members with a smaller sort key — two edges anchored to the same
|
|
32
|
+
* statement must order by key, not by which archived first. With no such
|
|
33
|
+
* neighborhood it falls to the trailing region, cluster-head-key-sorted
|
|
34
|
+
* the same insertion-sort way, after the trailing elements.
|
|
35
|
+
* - The relationship walk sorts only within the region's ASCENDING TAIL — the
|
|
36
|
+
* run loam's own insertions keep sorted — and stops where the existing order
|
|
37
|
+
* descends (`relSpot` has the case and the order-independence argument). A
|
|
38
|
+
* hand-written region is sorted by nobody, so walking into it made the spot
|
|
39
|
+
* depend on how unrelated edges happened to be drawn. The element walk is
|
|
40
|
+
* left unbounded: the map's top-level elements are few, a new service among
|
|
41
|
+
* them misfiles nothing, and its bytes are pinned as they always were.
|
|
42
|
+
* - A walk that stops BEFORE a statement, or at the closing brace, lands above
|
|
43
|
+
* the comment written directly over it (`aboveComments` in `./text/spot.ts`):
|
|
44
|
+
* a comment is about what follows it, and an addition between the two
|
|
45
|
+
* misfiles under it.
|
|
46
|
+
*
|
|
47
|
+
* A landscape may hold SEVERAL top-level `model { }` blocks, and LikeC4 reads
|
|
48
|
+
* them as one model. Placement keeps every rule above and adds one: an
|
|
49
|
+
* ANCHORED addition lands in its anchor's block (after the neighbor, clamped
|
|
50
|
+
* to that block's closing brace), and an UNANCHORED one — the trailing-region
|
|
51
|
+
* walks — lands in `HOME_BLOCK`, never crossing a block boundary. A same-service
|
|
52
|
+
* run and a relationship cluster are contiguous statements of ONE block: the
|
|
53
|
+
* views or the specification between two blocks are not a neighborhood.
|
|
54
|
+
*
|
|
55
|
+
* LikeC4 reference resolution is not order-dependent, so a relationship
|
|
56
|
+
* placed before an element it names still parses; the in-memory parse net in
|
|
57
|
+
* landscape-merge.ts's planLandscapeMerge stays as the backstop regardless.
|
|
58
|
+
*/
|
|
59
|
+
/**
|
|
60
|
+
* The block an addition with no anchor lands in: the document's FIRST
|
|
61
|
+
* `model { }` block.
|
|
62
|
+
*
|
|
63
|
+
* First, because it is the block every unanchored addition already landed in
|
|
64
|
+
* before the scan could see a second one — the scan stopped at the first
|
|
65
|
+
* match — so a single-block map places byte-identically, and a map that grew
|
|
66
|
+
* a second block keeps receiving new services where its older ones went. It
|
|
67
|
+
* is also invariant under every addition this merge can make (an archive never
|
|
68
|
+
* creates or reorders a block), which is what order-independence needs of it:
|
|
69
|
+
* a block chosen by size or content would move as the archives landed, and the
|
|
70
|
+
* same two features would compose to different bytes by archive order. The
|
|
71
|
+
* service-model splice (`./model/merge.ts`) uses the same block for the same
|
|
72
|
+
* reasons.
|
|
73
|
+
*/
|
|
74
|
+
export const HOME_BLOCK = 0;
|
|
75
|
+
/** The statements of one block, in document order — what a trailing walk may step over. */
|
|
76
|
+
function inBlock(stmts, block) {
|
|
77
|
+
return stmts.filter((s) => s.block === block);
|
|
78
|
+
}
|
|
4
79
|
/** The model's top-level statements in document order, joined to the parsed elements for services. */
|
|
5
80
|
export function topStatements(scan, els) {
|
|
6
|
-
|
|
81
|
+
// An `extend <fqn>` frame is never a top-level declaration of THIS document —
|
|
82
|
+
// it reopens one another document owns — so it anchors nothing and displaces
|
|
83
|
+
// nothing. Undotted fqns are the reason the tag is checked rather than the
|
|
84
|
+
// dot: `extend paymentService { }` would otherwise read as a declaration of
|
|
85
|
+
// `paymentService` here.
|
|
86
|
+
const topEls = scan.elements.filter((e) => e.extend !== true && !e.id.includes("."));
|
|
7
87
|
const bound = new Map(els.map((e) => [e.id, elementService(e)]));
|
|
8
88
|
const stmts = topEls.map((e) => ({
|
|
9
89
|
kind: "element",
|
|
@@ -12,11 +92,20 @@ export function topStatements(scan, els) {
|
|
|
12
92
|
services: [bound.get(e.id) ?? e.id],
|
|
13
93
|
start: e.start,
|
|
14
94
|
end: e.end,
|
|
95
|
+
block: e.block,
|
|
15
96
|
}));
|
|
97
|
+
// Every top-level FRAME a statement can sit inside: the elements, and the
|
|
98
|
+
// `extend` frames, which hold edges as well as children.
|
|
99
|
+
const frames = scan.elements.filter((e) => e.extend === true || !e.id.includes("."));
|
|
16
100
|
for (const r of scan.rels) {
|
|
17
101
|
// A rel declared inside an element's body is not a top-level statement —
|
|
18
|
-
// anchoring after it would splice into the parent's block.
|
|
19
|
-
|
|
102
|
+
// anchoring after it would splice into the parent's block. Inside an
|
|
103
|
+
// `extend` frame it is worse than misplaced: the frame is a SCOPE, so an
|
|
104
|
+
// edge spliced in after it re-resolves there, and the delta's `zulu ->
|
|
105
|
+
// beta` landed inside `extend alpha { beta = … }` as an edge into
|
|
106
|
+
// `alpha.beta` — a merge that parses, written at exit 0 (probed
|
|
107
|
+
// 2026-10-20). Only the extend frames' edges are new to this filter.
|
|
108
|
+
if (frames.some((e) => r.start > e.start && r.start < e.end))
|
|
20
109
|
continue;
|
|
21
110
|
stmts.push({
|
|
22
111
|
kind: "rel",
|
|
@@ -30,6 +119,7 @@ export function topStatements(scan, els) {
|
|
|
30
119
|
services: [serviceOf(els, r.source), serviceOf(els, r.target)],
|
|
31
120
|
start: r.start,
|
|
32
121
|
end: r.end,
|
|
122
|
+
block: r.block,
|
|
33
123
|
});
|
|
34
124
|
}
|
|
35
125
|
return stmts.sort((a, b) => a.start - b.start);
|
|
@@ -49,14 +139,16 @@ export function topStatements(scan, els) {
|
|
|
49
139
|
* exact regime the scheme guarantees.
|
|
50
140
|
*/
|
|
51
141
|
export function elementSpot(region, id, service) {
|
|
52
|
-
const { text,
|
|
142
|
+
const { text, blocks } = region;
|
|
53
143
|
let anchor;
|
|
54
|
-
for (const s of stmts) {
|
|
144
|
+
for (const s of region.stmts) {
|
|
55
145
|
if (s.kind === "element" && s.services.includes(service))
|
|
56
146
|
anchor = s;
|
|
57
147
|
}
|
|
58
148
|
if (anchor !== undefined)
|
|
59
|
-
return spotAfter(text, close, anchor.end);
|
|
149
|
+
return spotAfter(text, blocks[anchor.block].close, anchor.end);
|
|
150
|
+
const stmts = inBlock(region.stmts, HOME_BLOCK);
|
|
151
|
+
const close = blocks[HOME_BLOCK].close;
|
|
60
152
|
let i = stmts.length - 1;
|
|
61
153
|
let before;
|
|
62
154
|
while (i >= 0 && stmts[i].kind === "rel") {
|
|
@@ -94,6 +186,12 @@ function relClusterHeads(stmts) {
|
|
|
94
186
|
let services = null;
|
|
95
187
|
for (let i = 0; i < stmts.length; i += 1) {
|
|
96
188
|
const s = stmts[i];
|
|
189
|
+
// A block boundary ends a cluster exactly as an element does: the first
|
|
190
|
+
// edge of the next block is not contiguous with the last of this one.
|
|
191
|
+
if (i > 0 && stmts[i - 1].block !== s.block) {
|
|
192
|
+
head = -1;
|
|
193
|
+
services = null;
|
|
194
|
+
}
|
|
97
195
|
if (s.kind !== "rel") {
|
|
98
196
|
head = -1;
|
|
99
197
|
services = null;
|
|
@@ -111,8 +209,49 @@ function relClusterHeads(stmts) {
|
|
|
111
209
|
}
|
|
112
210
|
return heads;
|
|
113
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
* Where a relationship lands: after its source's neighborhood, or — with none —
|
|
214
|
+
* in the trailing region, insertion-sorted among the cluster heads.
|
|
215
|
+
*
|
|
216
|
+
* The trailing walk sorts only within the region's ASCENDING TAIL: it steps left
|
|
217
|
+
* past a cluster whose head sorts above the new key only while that head also
|
|
218
|
+
* sorts at or below the head of the cluster after it. The insertions loam makes
|
|
219
|
+
* keep that tail sorted, so on a region loam wrote the walk is the plain
|
|
220
|
+
* insertion sort it always was; a hand-written region is sorted by nobody, and
|
|
221
|
+
* walking into it made the landing spot a function of unrelated edges — an edge
|
|
222
|
+
* drawn `svc -> kafka` let a new edge walk past it, the same edge turned round
|
|
223
|
+
* (`kafka -[delivers]-> svc`, a head that sorts lower) stopped the walk, and the
|
|
224
|
+
* addition landed sixty lines away under a comment about something else
|
|
225
|
+
* (2026-10). Order-independence survives the bound: the statements before the
|
|
226
|
+
* tail never change, because an addition sorting below the tail's first head
|
|
227
|
+
* becomes its new first head, and that still sorts below the statement the tail
|
|
228
|
+
* broke from — so every archive inserts into the same sorted run, whatever
|
|
229
|
+
* order they land in.
|
|
230
|
+
*/
|
|
114
231
|
export function relSpot(region, sourceService, key) {
|
|
115
|
-
const
|
|
232
|
+
const anchored = anchoredRelSpot(region, sourceService, key);
|
|
233
|
+
if (anchored !== null)
|
|
234
|
+
return anchored;
|
|
235
|
+
const { text, blocks } = region;
|
|
236
|
+
const stmts = inBlock(region.stmts, HOME_BLOCK);
|
|
237
|
+
const close = blocks[HOME_BLOCK].close;
|
|
238
|
+
const heads = relClusterHeads(stmts);
|
|
239
|
+
let i = stmts.length - 1;
|
|
240
|
+
let before;
|
|
241
|
+
while (i >= 0 && stmts[i].kind === "rel") {
|
|
242
|
+
const j = heads[i];
|
|
243
|
+
if (!(stmts[j].key > key))
|
|
244
|
+
break;
|
|
245
|
+
if (before !== undefined && stmts[j].key > before.key)
|
|
246
|
+
break;
|
|
247
|
+
before = stmts[j];
|
|
248
|
+
i = j - 1;
|
|
249
|
+
}
|
|
250
|
+
return before !== undefined ? beforeSpot(text, before) : closeSpot(text, close);
|
|
251
|
+
}
|
|
252
|
+
/** After the last relationship touching the source's service, in that relationship's block — null when none does. */
|
|
253
|
+
function anchoredRelSpot(region, sourceService, key) {
|
|
254
|
+
const { text, stmts, blocks } = region;
|
|
116
255
|
const heads = relClusterHeads(stmts);
|
|
117
256
|
let anchorAt = -1;
|
|
118
257
|
for (let i = 0; i < stmts.length; i += 1) {
|
|
@@ -133,62 +272,27 @@ export function relSpot(region, sourceService, key) {
|
|
|
133
272
|
break;
|
|
134
273
|
last = s;
|
|
135
274
|
}
|
|
136
|
-
return spotAfter(text, close, last.end);
|
|
137
|
-
}
|
|
138
|
-
let i = stmts.length - 1;
|
|
139
|
-
let before;
|
|
140
|
-
while (i >= 0 && stmts[i].kind === "rel") {
|
|
141
|
-
const j = heads[i];
|
|
142
|
-
if (!(stmts[j].key > key))
|
|
143
|
-
break;
|
|
144
|
-
before = stmts[j];
|
|
145
|
-
i = j - 1;
|
|
275
|
+
return spotAfter(text, blocks[last.block].close, last.end);
|
|
146
276
|
}
|
|
147
|
-
return
|
|
277
|
+
return null;
|
|
148
278
|
}
|
|
149
279
|
/**
|
|
150
|
-
* Insertion before an existing statement:
|
|
151
|
-
* whitespace precedes it
|
|
152
|
-
* onto a fresh line — when other text shares the line (a
|
|
153
|
-
* the `model {` line, say). The unguarded line start
|
|
154
|
-
* the model keyword, and the parse net refused a
|
|
280
|
+
* Insertion before an existing statement: above the comment written directly
|
|
281
|
+
* over it when only whitespace precedes it on its line, at the statement itself
|
|
282
|
+
* — bare, displacing it onto a fresh line — when other text shares the line (a
|
|
283
|
+
* statement written on the `model {` line, say). The unguarded line start
|
|
284
|
+
* spliced the block BEFORE the model keyword, and the parse net refused a
|
|
285
|
+
* perfectly legal landscape.
|
|
286
|
+
*
|
|
287
|
+
* Above the comment, because a comment written over a statement is about that
|
|
288
|
+
* statement, or heads the section it opens: inserted at the statement's own
|
|
289
|
+
* line, an addition landed between a six-line explanation and the edge it
|
|
290
|
+
* explains (2026-10). `aboveComments` says which lines count.
|
|
155
291
|
*/
|
|
156
292
|
function beforeSpot(text, before) {
|
|
157
293
|
const ls = lineStartAt(text, before.start);
|
|
158
294
|
if (/^[ \t]*$/.test(text.slice(ls, before.start)))
|
|
159
|
-
return { at: ls, bare: false };
|
|
295
|
+
return { at: aboveComments(text, ls), bare: false };
|
|
160
296
|
return { at: before.start, bare: true };
|
|
161
297
|
}
|
|
162
|
-
/** The line following the statement that ends at `end` — clamped to the closing brace's own spot. */
|
|
163
|
-
function spotAfter(text, close, end) {
|
|
164
|
-
const nl = text.indexOf("\n", end);
|
|
165
|
-
const at = nl === -1 ? text.length : nl + 1;
|
|
166
|
-
return at > close ? closeSpot(text, close) : { at, bare: false };
|
|
167
|
-
}
|
|
168
|
-
/** The last resort: directly before the model's closing brace. */
|
|
169
|
-
function closeSpot(text, close) {
|
|
170
|
-
const ls = lineStartAt(text, close);
|
|
171
|
-
if (/^[ \t]*$/.test(text.slice(ls, close)))
|
|
172
|
-
return { at: ls, bare: false };
|
|
173
|
-
return { at: close, bare: true };
|
|
174
|
-
}
|
|
175
|
-
function lineStartAt(text, at) {
|
|
176
|
-
return text.lastIndexOf("\n", at - 1) + 1;
|
|
177
|
-
}
|
|
178
|
-
/**
|
|
179
|
-
* Where a child block enters an existing living parent: before the closing
|
|
180
|
-
* brace of the parent's body, on its own line at the parent's inner indent —
|
|
181
|
-
* and a parent that never had a body gains one around the child.
|
|
182
|
-
*/
|
|
183
|
-
export function nestedInsert(text, parent, block) {
|
|
184
|
-
if (parent.bodyOpen === -1) {
|
|
185
|
-
return { at: parent.end, insert: ` {\n${block}\n${parent.indent}}` };
|
|
186
|
-
}
|
|
187
|
-
const lineStart = text.lastIndexOf("\n", parent.bodyClose - 1) + 1;
|
|
188
|
-
if (/^[ \t]*$/.test(text.slice(lineStart, parent.bodyClose))) {
|
|
189
|
-
return { at: lineStart, insert: `${block}\n` };
|
|
190
|
-
}
|
|
191
|
-
// `{ ... }` on one line — break the brace onto its own line to make room.
|
|
192
|
-
return { at: parent.bodyClose, insert: `\n${block}\n${parent.indent}` };
|
|
193
|
-
}
|
|
194
298
|
//# sourceMappingURL=placement.js.map
|