@ybotok/loam 0.1.0-beta.3 → 0.2.0-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5992 -82
- package/COMPARISON.md +168 -63
- package/CONTRIBUTING.md +121 -0
- package/MIGRATING-from-OpenSpec.md +238 -55
- package/QUICKSTART.md +302 -0
- package/README.md +653 -144
- package/ROADMAP.md +1035 -0
- package/SCHEMA.md +3916 -263
- package/SECURITY.md +21 -3
- package/WORKFLOW.md +927 -0
- package/dist/cli.js +133 -21
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +204 -0
- package/dist/commands/adopt/adopt.js.map +1 -0
- package/dist/commands/adopt/render.js +309 -0
- package/dist/commands/adopt/render.js.map +1 -0
- package/dist/commands/archive/archive.js +74 -0
- package/dist/commands/archive/archive.js.map +1 -0
- package/dist/commands/archive/closing.js +42 -0
- package/dist/commands/archive/closing.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +172 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/consumers.js +56 -0
- package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +193 -0
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
- package/dist/commands/archive/plan/document/head.js +151 -0
- package/dist/commands/archive/plan/document/head.js.map +1 -0
- package/dist/commands/archive/plan/document/links.js +284 -0
- package/dist/commands/archive/plan/document/links.js.map +1 -0
- package/dist/commands/archive/plan/document/run.js +136 -0
- package/dist/commands/archive/plan/document/run.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +319 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +298 -0
- package/dist/commands/archive/plan/landscape.js.map +1 -0
- package/dist/commands/archive/plan/model/extending.js +85 -0
- package/dist/commands/archive/plan/model/extending.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +106 -0
- package/dist/commands/archive/plan/refusal.js.map +1 -0
- package/dist/commands/archive/plan/specs.js +318 -0
- package/dist/commands/archive/plan/specs.js.map +1 -0
- package/dist/commands/archive/plan/state.js +30 -0
- package/dist/commands/archive/plan/state.js.map +1 -0
- package/dist/commands/archive/run.js +355 -0
- package/dist/commands/archive/run.js.map +1 -0
- package/dist/commands/archive/shipped.js +49 -0
- package/dist/commands/archive/shipped.js.map +1 -0
- package/dist/commands/context/context.js +166 -0
- package/dist/commands/context/context.js.map +1 -0
- package/dist/commands/context/print.js +305 -0
- package/dist/commands/context/print.js.map +1 -0
- package/dist/commands/delta/delta.js +367 -0
- package/dist/commands/delta/delta.js.map +1 -0
- package/dist/commands/delta/print.js +221 -0
- package/dist/commands/delta/print.js.map +1 -0
- package/dist/commands/dependencies.js +6 -8
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +86 -0
- package/dist/commands/diff/diff.js.map +1 -0
- package/dist/commands/diff/print.js +38 -0
- package/dist/commands/diff/print.js.map +1 -0
- package/dist/commands/doctor.js +65 -5
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +227 -0
- package/dist/commands/explain/explain.js.map +1 -0
- package/dist/commands/explore.js +39 -28
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +152 -0
- package/dist/commands/gate/gate.js.map +1 -0
- package/dist/commands/gate/print.js +66 -0
- package/dist/commands/gate/print.js.map +1 -0
- package/dist/commands/gherkin/commit.js +105 -0
- package/dist/commands/gherkin/commit.js.map +1 -0
- package/dist/commands/gherkin/gherkin.js +262 -0
- package/dist/commands/gherkin/gherkin.js.map +1 -0
- package/dist/commands/gherkin/reconcile.js +146 -0
- package/dist/commands/gherkin/reconcile.js.map +1 -0
- package/dist/commands/gherkin/render.js +77 -0
- package/dist/commands/gherkin/render.js.map +1 -0
- package/dist/commands/init/example.js +204 -0
- package/dist/commands/init/example.js.map +1 -0
- package/dist/commands/init/first-hour.js +72 -0
- package/dist/commands/init/first-hour.js.map +1 -0
- package/dist/commands/{init.js → init/init.js} +142 -71
- package/dist/commands/init/init.js.map +1 -0
- package/dist/commands/init/mcp.js +131 -0
- package/dist/commands/init/mcp.js.map +1 -0
- package/dist/commands/init/options.js +78 -0
- package/dist/commands/init/options.js.map +1 -0
- package/dist/commands/instructions.js +72 -14
- package/dist/commands/instructions.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +63 -0
- package/dist/commands/list/campaign/campaign.js.map +1 -0
- package/dist/commands/list/campaign/owners.js +65 -0
- package/dist/commands/list/campaign/owners.js.map +1 -0
- package/dist/commands/list/json.js +155 -0
- package/dist/commands/list/json.js.map +1 -0
- package/dist/commands/list/list.js +358 -0
- package/dist/commands/list/list.js.map +1 -0
- package/dist/commands/list/print.js +344 -0
- package/dist/commands/list/print.js.map +1 -0
- package/dist/commands/list/review.js +120 -0
- package/dist/commands/list/review.js.map +1 -0
- package/dist/commands/list/suites/suites.js +140 -0
- package/dist/commands/list/suites/suites.js.map +1 -0
- package/dist/commands/list/views.js +108 -0
- package/dist/commands/list/views.js.map +1 -0
- package/dist/commands/mcp/dispatch.js +238 -0
- package/dist/commands/mcp/dispatch.js.map +1 -0
- package/dist/commands/mcp/mcp.js +75 -0
- package/dist/commands/mcp/mcp.js.map +1 -0
- package/dist/commands/mcp/serve.js +55 -0
- package/dist/commands/mcp/serve.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/active.js +175 -0
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
- package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/living.js +62 -0
- package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/stage.js +143 -0
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/target.js +219 -0
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js +86 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/error.js +18 -0
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js +162 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/paths.js +40 -0
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/read.js +49 -0
- package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
- package/dist/commands/migrate-openspec/print.js +89 -0
- package/dist/commands/migrate-openspec/print.js.map +1 -0
- package/dist/commands/new/capability-template.js +118 -0
- package/dist/commands/new/capability-template.js.map +1 -0
- package/dist/commands/new/commit.js +62 -0
- package/dist/commands/new/commit.js.map +1 -0
- package/dist/commands/new/modifies.js +206 -0
- package/dist/commands/new/modifies.js.map +1 -0
- package/dist/commands/new/new.js +328 -0
- package/dist/commands/new/new.js.map +1 -0
- package/dist/commands/new/templates.js +279 -0
- package/dist/commands/new/templates.js.map +1 -0
- package/dist/commands/open.js +199 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/policy/format.js +152 -0
- package/dist/commands/policy/format.js.map +1 -0
- package/dist/commands/{docs-repo-gate.js → policy/gate.js} +38 -11
- package/dist/commands/policy/gate.js.map +1 -0
- package/dist/commands/rebase/edit.js +106 -0
- package/dist/commands/rebase/edit.js.map +1 -0
- package/dist/commands/rebase/living.js +185 -0
- package/dist/commands/rebase/living.js.map +1 -0
- package/dist/commands/rebase/plan.js +245 -0
- package/dist/commands/rebase/plan.js.map +1 -0
- package/dist/commands/rebase/rebase.js +300 -0
- package/dist/commands/rebase/rebase.js.map +1 -0
- package/dist/commands/seed/commit.js +221 -0
- package/dist/commands/seed/commit.js.map +1 -0
- package/dist/commands/seed/plan.js +278 -0
- package/dist/commands/seed/plan.js.map +1 -0
- package/dist/commands/seed/seed.js +174 -0
- package/dist/commands/seed/seed.js.map +1 -0
- package/dist/commands/show/feature.js +182 -0
- package/dist/commands/show/feature.js.map +1 -0
- package/dist/commands/show/introduced.js +157 -0
- package/dist/commands/show/introduced.js.map +1 -0
- package/dist/commands/show/marks.js +53 -0
- package/dist/commands/show/marks.js.map +1 -0
- package/dist/commands/show/service.js +239 -0
- package/dist/commands/show/service.js.map +1 -0
- package/dist/commands/show/show.js +87 -0
- package/dist/commands/show/show.js.map +1 -0
- package/dist/commands/status/fleet-next.js +90 -0
- package/dist/commands/status/fleet-next.js.map +1 -0
- package/dist/commands/status/json.js +47 -0
- package/dist/commands/status/json.js.map +1 -0
- package/dist/commands/status/print.js +209 -0
- package/dist/commands/status/print.js.map +1 -0
- package/dist/commands/status/status.js +115 -0
- package/dist/commands/status/status.js.map +1 -0
- package/dist/commands/steps/steps.js +269 -0
- package/dist/commands/steps/steps.js.map +1 -0
- package/dist/commands/subsystem/edit.js +192 -0
- package/dist/commands/subsystem/edit.js.map +1 -0
- package/dist/commands/subsystem/move.js +325 -0
- package/dist/commands/subsystem/move.js.map +1 -0
- package/dist/commands/subsystem/query.js +113 -0
- package/dist/commands/subsystem/query.js.map +1 -0
- package/dist/commands/subsystem/subsystem.js +98 -0
- package/dist/commands/subsystem/subsystem.js.map +1 -0
- package/dist/commands/subsystem/sync.js +318 -0
- package/dist/commands/subsystem/sync.js.map +1 -0
- package/dist/commands/subsystem/txn/exclude.js +132 -0
- package/dist/commands/subsystem/txn/exclude.js.map +1 -0
- package/dist/commands/subsystem/txn/links.js +128 -0
- package/dist/commands/subsystem/txn/links.js.map +1 -0
- package/dist/commands/subsystem/txn/report.js +174 -0
- package/dist/commands/subsystem/txn/report.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +196 -0
- package/dist/commands/subsystem/txn/txn.js.map +1 -0
- package/dist/commands/subsystem/txn/views.js +249 -0
- package/dist/commands/subsystem/txn/views.js.map +1 -0
- package/dist/commands/tasks/actions.js +107 -0
- package/dist/commands/tasks/actions.js.map +1 -0
- package/dist/commands/tasks/render.js +253 -0
- package/dist/commands/tasks/render.js.map +1 -0
- package/dist/commands/tasks/tasks.js +119 -0
- package/dist/commands/tasks/tasks.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +176 -0
- package/dist/commands/unarchive/manifest.js.map +1 -0
- package/dist/commands/unarchive/restore.js +254 -0
- package/dist/commands/unarchive/restore.js.map +1 -0
- package/dist/commands/unarchive/unarchive.js +59 -0
- package/dist/commands/unarchive/unarchive.js.map +1 -0
- package/dist/commands/validate/arch-coverage.js +245 -0
- package/dist/commands/validate/arch-coverage.js.map +1 -0
- package/dist/commands/validate/checks/fleet-shape.js +204 -0
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
- package/dist/commands/validate/checks/health-deps.js +58 -0
- package/dist/commands/validate/checks/health-deps.js.map +1 -0
- package/dist/commands/validate/checks/introduced.js +102 -0
- package/dist/commands/validate/checks/introduced.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +264 -0
- package/dist/commands/validate/checks/requirements.js.map +1 -0
- package/dist/commands/validate/checks/sources.js +85 -0
- package/dist/commands/validate/checks/sources.js.map +1 -0
- package/dist/commands/validate/coverage/covers-after.js +105 -0
- package/dist/commands/validate/coverage/covers-after.js.map +1 -0
- package/dist/commands/validate/feature.js +222 -0
- package/dist/commands/validate/feature.js.map +1 -0
- package/dist/commands/validate/fleet/census.js +93 -0
- package/dist/commands/validate/fleet/census.js.map +1 -0
- package/dist/commands/validate/fleet/kind-tags.js +39 -0
- package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
- package/dist/commands/validate/fleet/landscape.js +371 -0
- package/dist/commands/validate/fleet/landscape.js.map +1 -0
- package/dist/commands/validate/fleet/load.js +118 -0
- package/dist/commands/validate/fleet/load.js.map +1 -0
- package/dist/commands/validate/fleet/map/attest.js +98 -0
- package/dist/commands/validate/fleet/map/attest.js.map +1 -0
- package/dist/commands/validate/fleet/map/bindings.js +107 -0
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
- package/dist/commands/validate/fleet/map/consumers.js +244 -0
- package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
- package/dist/commands/validate/fleet/map/isolation.js +116 -0
- package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
- package/dist/commands/validate/fleet/map/usecases.js +54 -0
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +266 -0
- package/dist/commands/validate/fleet/obligations.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/print.js +71 -0
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js +162 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/place.js +13 -0
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
- package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +75 -0
- package/dist/commands/validate/fleet/views/ids.js.map +1 -0
- package/dist/commands/validate/fleet/views/projects.js +278 -0
- package/dist/commands/validate/fleet/views/projects.js.map +1 -0
- package/dist/commands/validate/fleet/views/root-documents.js +83 -0
- package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +52 -0
- package/dist/commands/validate/fleet/views/stale.js.map +1 -0
- package/dist/commands/validate/links/corpus.js +89 -0
- package/dist/commands/validate/links/corpus.js.map +1 -0
- package/dist/commands/validate/links/glossary.js +75 -0
- package/dist/commands/validate/links/glossary.js.map +1 -0
- package/dist/commands/validate/render/repeats.js +63 -0
- package/dist/commands/validate/render/repeats.js.map +1 -0
- package/dist/commands/validate/render/rollups.js +115 -0
- package/dist/commands/validate/render/rollups.js.map +1 -0
- package/dist/commands/validate/render/text.js +199 -0
- package/dist/commands/validate/render/text.js.map +1 -0
- package/dist/commands/validate/report.js +145 -0
- package/dist/commands/validate/report.js.map +1 -0
- package/dist/commands/validate/scope.js +113 -0
- package/dist/commands/validate/scope.js.map +1 -0
- package/dist/commands/validate/service/api.js +252 -0
- package/dist/commands/validate/service/api.js.map +1 -0
- package/dist/commands/validate/service/contracts/generated.js +134 -0
- package/dist/commands/validate/service/contracts/generated.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +241 -0
- package/dist/commands/validate/service/events/events.js.map +1 -0
- package/dist/commands/validate/service/events/message-producers.js +77 -0
- package/dist/commands/validate/service/events/message-producers.js.map +1 -0
- package/dist/commands/validate/service/evidence-pins.js +177 -0
- package/dist/commands/validate/service/evidence-pins.js.map +1 -0
- package/dist/commands/validate/service/model/diverged.js +226 -0
- package/dist/commands/validate/service/model/diverged.js.map +1 -0
- package/dist/commands/validate/service/model/grade.js +163 -0
- package/dist/commands/validate/service/model/grade.js.map +1 -0
- package/dist/commands/validate/service/service.js +310 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +279 -0
- package/dist/commands/validate/service/specs.js.map +1 -0
- package/dist/commands/validate/service/spine.js +148 -0
- package/dist/commands/validate/service/spine.js.map +1 -0
- package/dist/commands/validate/service/usecases/tags.js +113 -0
- package/dist/commands/validate/service/usecases/tags.js.map +1 -0
- package/dist/commands/validate/service/usecases/usecases.js +209 -0
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/validate.js +363 -0
- package/dist/commands/validate/validate.js.map +1 -0
- package/dist/commands/verify/cross/diff.js +178 -0
- package/dist/commands/verify/cross/diff.js.map +1 -0
- package/dist/commands/verify/evidence/contract.js +32 -0
- package/dist/commands/verify/evidence/contract.js.map +1 -0
- package/dist/commands/verify/evidence/pins.js +52 -0
- package/dist/commands/verify/evidence/pins.js.map +1 -0
- package/dist/commands/verify/evidence/read.js +81 -0
- package/dist/commands/verify/evidence/read.js.map +1 -0
- package/dist/commands/verify/frozen.js +263 -0
- package/dist/commands/verify/frozen.js.map +1 -0
- package/dist/commands/verify/record.js +278 -0
- package/dist/commands/verify/record.js.map +1 -0
- package/dist/commands/verify/report.js +206 -0
- package/dist/commands/verify/report.js.map +1 -0
- package/dist/commands/verify/results.js +328 -0
- package/dist/commands/verify/results.js.map +1 -0
- package/dist/commands/verify/verify.js +220 -0
- package/dist/commands/verify/verify.js.map +1 -0
- package/dist/commands/vouch/contract.js +11 -0
- package/dist/commands/vouch/contract.js.map +1 -0
- package/dist/commands/vouch/pack/contract.js +2 -0
- package/dist/commands/vouch/pack/contract.js.map +1 -0
- package/dist/commands/vouch/pack/pack.js +266 -0
- package/dist/commands/vouch/pack/pack.js.map +1 -0
- package/dist/commands/vouch/pack/print.js +266 -0
- package/dist/commands/vouch/pack/print.js.map +1 -0
- package/dist/commands/vouch/pack/sections.js +141 -0
- package/dist/commands/vouch/pack/sections.js.map +1 -0
- package/dist/commands/vouch/prompt/confirm.js +46 -0
- package/dist/commands/vouch/prompt/confirm.js.map +1 -0
- package/dist/commands/vouch/report.js +101 -0
- package/dist/commands/vouch/report.js.map +1 -0
- package/dist/commands/vouch/run.js +230 -0
- package/dist/commands/vouch/run.js.map +1 -0
- package/dist/commands/vouch/sample/plan.js +111 -0
- package/dist/commands/vouch/sample/plan.js.map +1 -0
- package/dist/commands/vouch/sample/print.js +109 -0
- package/dist/commands/vouch/sample/print.js.map +1 -0
- package/dist/commands/vouch/vet/verify.js +155 -0
- package/dist/commands/vouch/vet/verify.js.map +1 -0
- package/dist/commands/vouch/vouch.js +169 -0
- package/dist/commands/vouch/vouch.js.map +1 -0
- package/dist/core/agent/agents-md/command-map.js +299 -0
- package/dist/core/agent/agents-md/command-map.js.map +1 -0
- package/dist/core/agent/agents-md/map/explain.js +46 -0
- package/dist/core/agent/agents-md/map/explain.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/context.js +50 -0
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js +59 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js +65 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
- package/dist/core/agent/agents-md/map/mcp.js +44 -0
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
- package/dist/core/agent/agents-md/map/status.js +78 -0
- package/dist/core/agent/agents-md/map/status.js.map +1 -0
- package/dist/core/agent/agents-md/map/subsystem.js +104 -0
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
- package/dist/core/agent/agents-md/map/usecases.js +138 -0
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
- package/dist/core/agent/agents-md/refusals.js +273 -0
- package/dist/core/agent/agents-md/refusals.js.map +1 -0
- package/dist/core/agent/agents-md.js +203 -0
- package/dist/core/agent/agents-md.js.map +1 -0
- package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +60 -0
- package/dist/core/agent/agents-stamp.js.map +1 -0
- package/dist/core/agent/contract.js +2 -0
- package/dist/core/agent/contract.js.map +1 -0
- package/dist/core/agent/protocol.js +193 -0
- package/dist/core/agent/protocol.js.map +1 -0
- package/dist/core/agent/scaffold.js +254 -0
- package/dist/core/agent/scaffold.js.map +1 -0
- package/dist/core/agent/support/report.js +144 -0
- package/dist/core/agent/support/report.js.map +1 -0
- package/dist/core/agent/tools/dialects.js +151 -0
- package/dist/core/agent/tools/dialects.js.map +1 -0
- package/dist/core/agent/tools/registry.js +193 -0
- package/dist/core/agent/tools/registry.js.map +1 -0
- package/dist/core/agent/workflows/adopt.js +280 -0
- package/dist/core/agent/workflows/adopt.js.map +1 -0
- package/dist/core/agent/workflows/check.js +373 -0
- package/dist/core/agent/workflows/check.js.map +1 -0
- package/dist/core/agent/workflows/closing.js +323 -0
- package/dist/core/agent/workflows/closing.js.map +1 -0
- package/dist/core/agent/workflows/feature.js +220 -0
- package/dist/core/agent/workflows/feature.js.map +1 -0
- package/dist/core/agent/workflows/implement.js +188 -0
- package/dist/core/agent/workflows/implement.js.map +1 -0
- package/dist/core/agent/workflows/reference/authoring.js +311 -0
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
- package/dist/core/agent/workflows/reference/codes.js +67 -0
- package/dist/core/agent/workflows/reference/codes.js.map +1 -0
- package/dist/core/agent/workflows/reference/done-check.js +210 -0
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +19 -0
- package/dist/core/agent/workflows/reference/reference.js.map +1 -0
- package/dist/core/agent/workflows/reference/spine.js +338 -0
- package/dist/core/agent/workflows/reference/spine.js.map +1 -0
- package/dist/core/asyncapi/baseline/plan.js +43 -0
- package/dist/core/asyncapi/baseline/plan.js.map +1 -0
- package/dist/core/asyncapi/baseline/surfaces.js +54 -0
- package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
- package/dist/core/asyncapi/depth.js +164 -0
- package/dist/core/asyncapi/depth.js.map +1 -0
- package/dist/core/asyncapi/digest.js +146 -0
- package/dist/core/asyncapi/digest.js.map +1 -0
- package/dist/core/asyncapi/merge/components.js +92 -0
- package/dist/core/asyncapi/merge/components.js.map +1 -0
- package/dist/core/asyncapi/merge/error.js +38 -0
- package/dist/core/asyncapi/merge/error.js.map +1 -0
- package/dist/core/asyncapi/merge/markers.js +290 -0
- package/dist/core/asyncapi/merge/markers.js.map +1 -0
- package/dist/core/asyncapi/merge/merge.js +195 -0
- package/dist/core/asyncapi/merge/merge.js.map +1 -0
- package/dist/core/asyncapi/merge/pin.js +83 -0
- package/dist/core/asyncapi/merge/pin.js.map +1 -0
- package/dist/core/asyncapi/model.js +11 -0
- package/dist/core/asyncapi/model.js.map +1 -0
- package/dist/core/asyncapi/producers.js +50 -0
- package/dist/core/asyncapi/producers.js.map +1 -0
- package/dist/core/asyncapi/read.js +263 -0
- package/dist/core/asyncapi/read.js.map +1 -0
- package/dist/core/brief/brief.js +285 -0
- package/dist/core/brief/brief.js.map +1 -0
- package/dist/core/brief/checks.js +385 -0
- package/dist/core/brief/checks.js.map +1 -0
- package/dist/core/brief/landscape.js +273 -0
- package/dist/core/brief/landscape.js.map +1 -0
- package/dist/core/brief/map/extend.js +84 -0
- package/dist/core/brief/map/extend.js.map +1 -0
- package/dist/core/brief/map/owed.js +266 -0
- package/dist/core/brief/map/owed.js.map +1 -0
- package/dist/core/brief/targets.js +304 -0
- package/dist/core/brief/targets.js.map +1 -0
- package/dist/core/brief/unchecked.js +58 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +190 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/direction/direction.js +114 -0
- package/dist/core/c4/direction/direction.js.map +1 -0
- package/dist/core/c4/likec4.js +243 -0
- package/dist/core/c4/likec4.js.map +1 -0
- package/dist/core/c4/locate/unlocated.js +150 -0
- package/dist/core/c4/locate/unlocated.js.map +1 -0
- package/dist/core/c4/parsed/deployment.js +160 -0
- package/dist/core/c4/parsed/deployment.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js +132 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
- package/dist/core/c4/parsed/specification.js +78 -0
- package/dist/core/c4/parsed/specification.js.map +1 -0
- package/dist/core/c4/parsed/values.js +110 -0
- package/dist/core/c4/parsed/values.js.map +1 -0
- package/dist/core/c4/parsed/view-ids.js +113 -0
- package/dist/core/c4/parsed/view-ids.js.map +1 -0
- package/dist/core/c4/prefetch/fleet.js +134 -0
- package/dist/core/c4/prefetch/fleet.js.map +1 -0
- package/dist/core/c4/project/architecture.js +161 -0
- package/dist/core/c4/project/architecture.js.map +1 -0
- package/dist/core/c4/project/batch.js +140 -0
- package/dist/core/c4/project/batch.js.map +1 -0
- package/dist/core/c4/project/documents.js +89 -0
- package/dist/core/c4/project/documents.js.map +1 -0
- package/dist/core/c4/project/load.js +219 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/project/staged.js +277 -0
- package/dist/core/c4/project/staged.js.map +1 -0
- package/dist/core/c4/resolve/attested.js +0 -0
- package/dist/core/c4/resolve/attested.js.map +1 -0
- package/dist/core/c4/resolve/external.js +51 -0
- package/dist/core/c4/resolve/external.js.map +1 -0
- package/dist/core/c4/resolve/service.js +174 -0
- package/dist/core/c4/resolve/service.js.map +1 -0
- package/dist/core/c4/resolve/steps.js +290 -0
- package/dist/core/c4/resolve/steps.js.map +1 -0
- package/dist/core/c4/resolve/systems.js +154 -0
- package/dist/core/c4/resolve/systems.js.map +1 -0
- package/dist/core/c4/root-project/exclude.js +352 -0
- package/dist/core/c4/root-project/exclude.js.map +1 -0
- package/dist/core/c4/seed/fleet-file.js +201 -0
- package/dist/core/c4/seed/fleet-file.js.map +1 -0
- package/dist/core/c4/seed/items.js +91 -0
- package/dist/core/c4/seed/items.js.map +1 -0
- package/dist/core/c4/seed/stamp.js +48 -0
- package/dist/core/c4/seed/stamp.js.map +1 -0
- package/dist/core/c4/seed/template.js +173 -0
- package/dist/core/c4/seed/template.js.map +1 -0
- package/dist/core/c4/service-model/created/models.js +96 -0
- package/dist/core/c4/service-model/created/models.js.map +1 -0
- package/dist/core/c4/service-model/documents.js +47 -0
- package/dist/core/c4/service-model/documents.js.map +1 -0
- package/dist/core/c4/service-model/fleet/extending.js +82 -0
- package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
- package/dist/core/c4/service-model/load.js +165 -0
- package/dist/core/c4/service-model/load.js.map +1 -0
- package/dist/core/c4/service-model/renderer.js +128 -0
- package/dist/core/c4/service-model/renderer.js.map +1 -0
- package/dist/core/c4/service-model/shape.js +106 -0
- package/dist/core/c4/service-model/shape.js.map +1 -0
- package/dist/core/c4/service-model/slice.js +188 -0
- package/dist/core/c4/service-model/slice.js.map +1 -0
- package/dist/core/c4/source-mask.js +369 -0
- package/dist/core/c4/source-mask.js.map +1 -0
- package/dist/core/c4/source-scan.js +308 -0
- package/dist/core/c4/source-scan.js.map +1 -0
- package/dist/core/c4/splice/authored-source.js +167 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -0
- package/dist/core/c4/splice/contract.js +30 -0
- package/dist/core/c4/splice/contract.js.map +1 -0
- package/dist/core/c4/splice/delta-blocks.js +126 -0
- package/dist/core/c4/splice/delta-blocks.js.map +1 -0
- package/dist/core/c4/splice/identity/declared.js +87 -0
- package/dist/core/c4/splice/identity/declared.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +73 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -0
- package/dist/core/c4/splice/identity/existing.js +80 -0
- package/dist/core/c4/splice/identity/existing.js.map +1 -0
- package/dist/core/c4/splice/identity/interior.js +80 -0
- package/dist/core/c4/splice/identity/interior.js.map +1 -0
- package/dist/core/c4/splice/identity/owner.js +50 -0
- package/dist/core/c4/splice/identity/owner.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +337 -0
- package/dist/core/c4/splice/landscape-merge.js.map +1 -0
- package/dist/core/c4/splice/model/merge.js +151 -0
- package/dist/core/c4/splice/model/merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +298 -0
- package/dist/core/c4/splice/placement.js.map +1 -0
- package/dist/core/c4/splice/text/spot.js +131 -0
- package/dist/core/c4/splice/text/spot.js.map +1 -0
- package/dist/core/c4/workspace.js +166 -0
- package/dist/core/c4/workspace.js.map +1 -0
- package/dist/core/capabilities/authoring/notes.js +141 -0
- package/dist/core/capabilities/authoring/notes.js.map +1 -0
- package/dist/core/capabilities/capabilities.js +124 -0
- package/dist/core/capabilities/capabilities.js.map +1 -0
- package/dist/core/capabilities/delta/doc.js +47 -0
- package/dist/core/capabilities/delta/doc.js.map +1 -0
- package/dist/core/capabilities/delta/overlay.js +129 -0
- package/dist/core/capabilities/delta/overlay.js.map +1 -0
- package/dist/core/capabilities/delta/summary.js +57 -0
- package/dist/core/capabilities/delta/summary.js.map +1 -0
- package/dist/core/capabilities/delta/tree.js +43 -0
- package/dist/core/capabilities/delta/tree.js.map +1 -0
- package/dist/core/capabilities/delta/uncovered.js +222 -0
- package/dist/core/capabilities/delta/uncovered.js.map +1 -0
- package/dist/core/capabilities/findings.js +338 -0
- package/dist/core/capabilities/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/findings.js +174 -0
- package/dist/core/capabilities/realizes/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/join.js +123 -0
- package/dist/core/capabilities/realizes/join.js.map +1 -0
- package/dist/core/capabilities/rollup.js +205 -0
- package/dist/core/capabilities/rollup.js.map +1 -0
- package/dist/core/capabilities/tree.js +104 -0
- package/dist/core/capabilities/tree.js.map +1 -0
- package/dist/core/capabilities/usecase-join.js +267 -0
- package/dist/core/capabilities/usecase-join.js.map +1 -0
- package/dist/core/coherence/authoring/scaffold.js +185 -0
- package/dist/core/coherence/authoring/scaffold.js.map +1 -0
- package/dist/core/coherence/authoring/sentinels.js +75 -0
- package/dist/core/coherence/authoring/sentinels.js.map +1 -0
- package/dist/core/coherence/calls/called.js +52 -0
- package/dist/core/coherence/calls/called.js.map +1 -0
- package/dist/core/coherence/coherence.js +332 -0
- package/dist/core/coherence/coherence.js.map +1 -0
- package/dist/core/coherence/consumed/operations.js +70 -0
- package/dist/core/coherence/consumed/operations.js.map +1 -0
- package/dist/core/coherence/consumed/refusal.js +38 -0
- package/dist/core/coherence/consumed/refusal.js.map +1 -0
- package/dist/core/coherence/covers/health.js +85 -0
- package/dist/core/coherence/covers/health.js.map +1 -0
- package/dist/core/coherence/declared.js +295 -0
- package/dist/core/coherence/declared.js.map +1 -0
- package/dist/core/coherence/events/declared.js +191 -0
- package/dist/core/coherence/events/declared.js.map +1 -0
- package/dist/core/coherence/events/events.js +335 -0
- package/dist/core/coherence/events/events.js.map +1 -0
- package/dist/core/coherence/events/grades.js +189 -0
- package/dist/core/coherence/events/grades.js.map +1 -0
- package/dist/core/coherence/events/lookups.js +63 -0
- package/dist/core/coherence/events/lookups.js.map +1 -0
- package/dist/core/coherence/events/produced.js +100 -0
- package/dist/core/coherence/events/produced.js.map +1 -0
- package/dist/core/coherence/living.js +198 -0
- package/dist/core/coherence/living.js.map +1 -0
- package/dist/core/coherence/lookups.js +95 -0
- package/dist/core/coherence/lookups.js.map +1 -0
- package/dist/core/coherence/pending.js +39 -0
- package/dist/core/coherence/pending.js.map +1 -0
- package/dist/core/coherence/retired/archived.js +285 -0
- package/dist/core/coherence/retired/archived.js.map +1 -0
- package/dist/core/coherence/retired/event-pair.js +62 -0
- package/dist/core/coherence/retired/event-pair.js.map +1 -0
- package/dist/core/coherence/retired/merged.js +79 -0
- package/dist/core/coherence/retired/merged.js.map +1 -0
- package/dist/core/coherence/retired/retirement.js +49 -0
- package/dist/core/coherence/retired/retirement.js.map +1 -0
- package/dist/core/coherence/retired/revival/arrivals.js +131 -0
- package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
- package/dist/core/coherence/retired/revival/revived.js +297 -0
- package/dist/core/coherence/retired/revival/revived.js.map +1 -0
- package/dist/core/conflict-markers.js +60 -0
- package/dist/core/conflict-markers.js.map +1 -0
- package/dist/core/consumers/after.js +113 -0
- package/dist/core/consumers/after.js.map +1 -0
- package/dist/core/consumers/consumers.js +296 -0
- package/dist/core/consumers/consumers.js.map +1 -0
- package/dist/core/consumers/current.js +211 -0
- package/dist/core/consumers/current.js.map +1 -0
- package/dist/core/consumers/scan.js +46 -0
- package/dist/core/consumers/scan.js.map +1 -0
- package/dist/core/consumers/state.js +27 -0
- package/dist/core/consumers/state.js.map +1 -0
- package/dist/core/delta/claims.js +73 -0
- package/dist/core/delta/claims.js.map +1 -0
- package/dist/core/delta/delta.js +341 -0
- package/dist/core/delta/delta.js.map +1 -0
- package/dist/core/delta/document.js +177 -0
- package/dist/core/delta/document.js.map +1 -0
- package/dist/core/delta/scope.js +48 -0
- package/dist/core/delta/scope.js.map +1 -0
- package/dist/core/delta/select.js +237 -0
- package/dist/core/delta/select.js.map +1 -0
- package/dist/core/dependencies/dependencies.js +141 -0
- package/dist/core/dependencies/dependencies.js.map +1 -0
- package/dist/core/dependencies/facts.js +165 -0
- package/dist/core/dependencies/facts.js.map +1 -0
- package/dist/core/dependencies/fanin.js +88 -0
- package/dist/core/dependencies/fanin.js.map +1 -0
- package/dist/core/dependencies/graph.js +106 -0
- package/dist/core/dependencies/graph.js.map +1 -0
- package/dist/core/deployment/delta.js +191 -0
- package/dist/core/deployment/delta.js.map +1 -0
- package/dist/core/deployment/objects.js +145 -0
- package/dist/core/deployment/objects.js.map +1 -0
- package/dist/core/diff/base-git.js +230 -0
- package/dist/core/diff/base-git.js.map +1 -0
- package/dist/core/diff/base-state.js +237 -0
- package/dist/core/diff/base-state.js.map +1 -0
- package/dist/core/diff/joins.js +136 -0
- package/dist/core/diff/joins.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +204 -0
- package/dist/core/diff/scope/changed-paths.js.map +1 -0
- package/dist/core/diff/scope/edges.js +82 -0
- package/dist/core/diff/scope/edges.js.map +1 -0
- package/dist/core/diff/semantic.js +312 -0
- package/dist/core/diff/semantic.js.map +1 -0
- package/dist/core/docs.js +37 -85
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +238 -0
- package/dist/core/doctor/agents.js.map +1 -0
- package/dist/core/doctor/config.js +139 -0
- package/dist/core/doctor/config.js.map +1 -0
- package/dist/core/doctor/doctor.js +355 -0
- package/dist/core/doctor/doctor.js.map +1 -0
- package/dist/core/doctor/report.js +13 -0
- package/dist/core/doctor/report.js.map +1 -0
- package/dist/core/doctor/reports/scan.js +242 -0
- package/dist/core/doctor/reports/scan.js.map +1 -0
- package/dist/core/doctor/residue.js +110 -0
- package/dist/core/doctor/residue.js.map +1 -0
- package/dist/core/document/apply.js +224 -0
- package/dist/core/document/apply.js.map +1 -0
- package/dist/core/{frontmatter.js → document/frontmatter.js} +103 -2
- package/dist/core/document/frontmatter.js.map +1 -0
- package/dist/core/document/grammar/directives.js +143 -0
- package/dist/core/document/grammar/directives.js.map +1 -0
- package/dist/core/document/parse.js +286 -0
- package/dist/core/document/parse.js.map +1 -0
- package/dist/core/document/scenarios.js +238 -0
- package/dist/core/document/scenarios.js.map +1 -0
- package/dist/core/document/spec.js +234 -0
- package/dist/core/document/spec.js.map +1 -0
- package/dist/core/{config.js → envelope/config.js} +89 -18
- package/dist/core/envelope/config.js.map +1 -0
- package/dist/core/envelope/json.js +209 -0
- package/dist/core/envelope/json.js.map +1 -0
- package/dist/core/{version.js → envelope/version.js} +3 -3
- package/dist/core/envelope/version.js.map +1 -0
- package/dist/core/explain/families.js +180 -0
- package/dist/core/explain/families.js.map +1 -0
- package/dist/core/explain/fix-tables.js +178 -0
- package/dist/core/explain/fix-tables.js.map +1 -0
- package/dist/core/explain/lookup.js +194 -0
- package/dist/core/explain/lookup.js.map +1 -0
- package/dist/core/explain/refusals.js +49 -0
- package/dist/core/explain/refusals.js.map +1 -0
- package/dist/core/explain/terms/documents.js +227 -0
- package/dist/core/explain/terms/documents.js.map +1 -0
- package/dist/core/explain/terms/done-check.js +144 -0
- package/dist/core/explain/terms/done-check.js.map +1 -0
- package/dist/core/explain/terms/entry.js +14 -0
- package/dist/core/explain/terms/entry.js.map +1 -0
- package/dist/core/explain/terms/stages.js +71 -0
- package/dist/core/explain/terms/stages.js.map +1 -0
- package/dist/core/explain/terms/tasks.js +97 -0
- package/dist/core/explain/terms/tasks.js.map +1 -0
- package/dist/core/explain/terms.js +103 -0
- package/dist/core/explain/terms.js.map +1 -0
- package/dist/core/explore/describe.js +105 -0
- package/dist/core/explore/describe.js.map +1 -0
- package/dist/core/explore/explore.js +204 -0
- package/dist/core/explore/explore.js.map +1 -0
- package/dist/core/fleet-context.js +174 -146
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +208 -0
- package/dist/core/gate/checks.js.map +1 -0
- package/dist/core/gate/partners.js +246 -0
- package/dist/core/gate/partners.js.map +1 -0
- package/dist/core/gate/report.js +47 -0
- package/dist/core/gate/report.js.map +1 -0
- package/dist/core/gate/verification.js +176 -0
- package/dist/core/gate/verification.js.map +1 -0
- package/dist/core/gherkin/digest.js +60 -0
- package/dist/core/gherkin/digest.js.map +1 -0
- package/dist/core/gherkin/emit.js +177 -0
- package/dist/core/gherkin/emit.js.map +1 -0
- package/dist/core/gherkin/read.js +76 -0
- package/dist/core/gherkin/read.js.map +1 -0
- package/dist/core/gherkin/stale.js +210 -0
- package/dist/core/gherkin/stale.js.map +1 -0
- package/dist/core/gherkin/stamp.js +77 -0
- package/dist/core/gherkin/stamp.js.map +1 -0
- package/dist/core/gherkin/steps/catalogue.js +154 -0
- package/dist/core/gherkin/steps/catalogue.js.map +1 -0
- package/dist/core/gherkin/steps/inventory.js +98 -0
- package/dist/core/gherkin/steps/inventory.js.map +1 -0
- package/dist/core/gherkin/steps/phrase.js +72 -0
- package/dist/core/gherkin/steps/phrase.js.map +1 -0
- package/dist/core/glossary/delta.js +109 -0
- package/dist/core/glossary/delta.js.map +1 -0
- package/dist/core/glossary/tree.js +73 -0
- package/dist/core/glossary/tree.js.map +1 -0
- package/dist/core/{concurrency.js → kernel/concurrency.js} +19 -0
- package/dist/core/kernel/concurrency.js.map +1 -0
- package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
- package/dist/core/kernel/document-bytes.js.map +1 -0
- package/dist/core/kernel/fences.js +42 -0
- package/dist/core/kernel/fences.js.map +1 -0
- package/dist/core/kernel/ids/capability.js +72 -0
- package/dist/core/kernel/ids/capability.js.map +1 -0
- package/dist/core/kernel/ids/dirs.js +33 -0
- package/dist/core/kernel/ids/dirs.js.map +1 -0
- package/dist/core/kernel/ids/feature.js +75 -0
- package/dist/core/kernel/ids/feature.js.map +1 -0
- package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
- package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
- package/dist/core/kernel/ids/service.js +156 -0
- package/dist/core/kernel/ids/service.js.map +1 -0
- package/dist/core/kernel/ids/subsystem.js +63 -0
- package/dist/core/kernel/ids/subsystem.js.map +1 -0
- package/dist/core/{path-safety.js → kernel/path-safety.js} +56 -4
- package/dist/core/kernel/path-safety.js.map +1 -0
- package/dist/core/{records.js → kernel/records.js} +11 -0
- package/dist/core/kernel/records.js.map +1 -0
- package/dist/core/links/backlinks.js +66 -0
- package/dist/core/links/backlinks.js.map +1 -0
- package/dist/core/links/case.js +74 -0
- package/dist/core/links/case.js.map +1 -0
- package/dist/core/links/corpus.js +118 -0
- package/dist/core/links/corpus.js.map +1 -0
- package/dist/core/links/findings.js +110 -0
- package/dist/core/links/findings.js.map +1 -0
- package/dist/core/links/parse.js +265 -0
- package/dist/core/links/parse.js.map +1 -0
- package/dist/core/mcp/argv.js +212 -0
- package/dist/core/mcp/argv.js.map +1 -0
- package/dist/core/mcp/author-tools.js +73 -0
- package/dist/core/mcp/author-tools.js.map +1 -0
- package/dist/core/mcp/framing.js +46 -0
- package/dist/core/mcp/framing.js.map +1 -0
- package/dist/core/mcp/protocol.js +280 -0
- package/dist/core/mcp/protocol.js.map +1 -0
- package/dist/core/mcp/tools.js +324 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/obligations/obligations.js +106 -0
- package/dist/core/obligations/obligations.js.map +1 -0
- package/dist/core/openapi/baseline/gate.js +207 -0
- package/dist/core/openapi/baseline/gate.js.map +1 -0
- package/dist/core/openapi/baseline/plan.js +142 -0
- package/dist/core/openapi/baseline/plan.js.map +1 -0
- package/dist/core/openapi/baseline/record.js +174 -0
- package/dist/core/openapi/baseline/record.js.map +1 -0
- package/dist/core/openapi/contract-text.js +33 -0
- package/dist/core/openapi/contract-text.js.map +1 -0
- package/dist/core/openapi/contract-tree.js +301 -0
- package/dist/core/openapi/contract-tree.js.map +1 -0
- package/dist/core/openapi/depth.js +136 -0
- package/dist/core/openapi/depth.js.map +1 -0
- package/dist/core/openapi/digest.js +239 -0
- package/dist/core/openapi/digest.js.map +1 -0
- package/dist/core/{openapi.js → openapi/doc.js} +54 -108
- package/dist/core/openapi/doc.js.map +1 -0
- package/dist/core/openapi/merge/components.js +199 -0
- package/dist/core/openapi/merge/components.js.map +1 -0
- package/dist/core/openapi/merge/error.js +16 -0
- package/dist/core/openapi/merge/error.js.map +1 -0
- package/dist/core/openapi/merge/markers.js +204 -0
- package/dist/core/openapi/merge/markers.js.map +1 -0
- package/dist/core/openapi/merge/merge.js +232 -0
- package/dist/core/openapi/merge/merge.js.map +1 -0
- package/dist/core/openapi/merge/pin.js +110 -0
- package/dist/core/openapi/merge/pin.js.map +1 -0
- package/dist/core/openspec/decide/capabilities.js +244 -0
- package/dist/core/openspec/decide/capabilities.js.map +1 -0
- package/dist/core/openspec/decide/dispositions.js +63 -0
- package/dist/core/openspec/decide/dispositions.js.map +1 -0
- package/dist/core/openspec/decide/renames.js +179 -0
- package/dist/core/openspec/decide/renames.js.map +1 -0
- package/dist/core/openspec/decide/verdict.js +84 -0
- package/dist/core/openspec/decide/verdict.js.map +1 -0
- package/dist/core/openspec/inventory.js +220 -0
- package/dist/core/openspec/inventory.js.map +1 -0
- package/dist/core/openspec/model/mapping.js +78 -0
- package/dist/core/openspec/model/mapping.js.map +1 -0
- package/dist/core/openspec/model/model.js +70 -0
- package/dist/core/openspec/model/model.js.map +1 -0
- package/dist/core/openspec/scan/changes.js +241 -0
- package/dist/core/openspec/scan/changes.js.map +1 -0
- package/dist/core/openspec/scan/config.js +191 -0
- package/dist/core/openspec/scan/config.js.map +1 -0
- package/dist/core/openspec/scan/shape.js +304 -0
- package/dist/core/openspec/scan/shape.js.map +1 -0
- package/dist/core/openspec/scan/walk.js +116 -0
- package/dist/core/openspec/scan/walk.js.map +1 -0
- package/dist/core/openspec/scan/workspace.js +71 -0
- package/dist/core/openspec/scan/workspace.js.map +1 -0
- package/dist/core/owners/codeowners.js +141 -0
- package/dist/core/owners/codeowners.js.map +1 -0
- package/dist/core/pack/features.js +120 -0
- package/dist/core/pack/features.js.map +1 -0
- package/dist/core/pack/joins.js +112 -0
- package/dist/core/pack/joins.js.map +1 -0
- package/dist/core/pack/living.js +157 -0
- package/dist/core/pack/living.js.map +1 -0
- package/dist/core/pack/pack.js +120 -0
- package/dist/core/pack/pack.js.map +1 -0
- package/dist/core/permissions/permissions.js +87 -0
- package/dist/core/permissions/permissions.js.map +1 -0
- package/dist/core/projection/api.js +84 -0
- package/dist/core/projection/api.js.map +1 -0
- package/dist/core/projection/arch-slice.js +63 -0
- package/dist/core/projection/arch-slice.js.map +1 -0
- package/dist/core/projection/events.js +34 -0
- package/dist/core/projection/events.js.map +1 -0
- package/dist/core/projection/introduced.js +14 -0
- package/dist/core/projection/introduced.js.map +1 -0
- package/dist/core/provenance/findings.js +244 -0
- package/dist/core/provenance/findings.js.map +1 -0
- package/dist/core/provenance/git.js +201 -0
- package/dist/core/provenance/git.js.map +1 -0
- package/dist/core/provenance/gitq/moves.js +139 -0
- package/dist/core/provenance/gitq/moves.js.map +1 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
- package/dist/core/provenance/sample/scope.js +238 -0
- package/dist/core/provenance/sample/scope.js.map +1 -0
- package/dist/core/provenance/sample/sections.js +61 -0
- package/dist/core/provenance/sample/sections.js.map +1 -0
- package/dist/core/provenance/sources.js +280 -0
- package/dist/core/provenance/sources.js.map +1 -0
- package/dist/core/provenance/stamp.js +220 -0
- package/dist/core/provenance/stamp.js.map +1 -0
- package/dist/core/provenance/walk.js +157 -0
- package/dist/core/provenance/walk.js.map +1 -0
- package/dist/core/repo/authored/paths.js +210 -0
- package/dist/core/repo/authored/paths.js.map +1 -0
- package/dist/core/repo/entries.js +126 -0
- package/dist/core/repo/entries.js.map +1 -0
- package/dist/core/repo/paths.js +322 -0
- package/dist/core/repo/paths.js.map +1 -0
- package/dist/core/repo/repo.js +308 -0
- package/dist/core/repo/repo.js.map +1 -0
- package/dist/core/repo/service-target.js +153 -0
- package/dist/core/repo/service-target.js.map +1 -0
- package/dist/core/repo/state.js +58 -0
- package/dist/core/repo/state.js.map +1 -0
- package/dist/core/repo/tree/find.js +61 -0
- package/dist/core/repo/tree/find.js.map +1 -0
- package/dist/core/repo/tree/fs.js +90 -0
- package/dist/core/repo/tree/fs.js.map +1 -0
- package/dist/core/repo/tree/marker.js +61 -0
- package/dist/core/repo/tree/marker.js.map +1 -0
- package/dist/core/repo/tree/render/body.js +258 -0
- package/dist/core/repo/tree/render/body.js.map +1 -0
- package/dist/core/repo/tree/render/projects.js +182 -0
- package/dist/core/repo/tree/render/projects.js.map +1 -0
- package/dist/core/repo/tree/render/service/header.js +125 -0
- package/dist/core/repo/tree/render/service/header.js.map +1 -0
- package/dist/core/repo/tree/render/service/peers.js +28 -0
- package/dist/core/repo/tree/render/service/peers.js.map +1 -0
- package/dist/core/repo/tree/render/service/view-id.js +67 -0
- package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
- package/dist/core/repo/tree/render/service/views.js +78 -0
- package/dist/core/repo/tree/render/service/views.js.map +1 -0
- package/dist/core/repo/tree/render/stale.js +42 -0
- package/dist/core/repo/tree/render/stale.js.map +1 -0
- package/dist/core/repo/tree/render/text.js +84 -0
- package/dist/core/repo/tree/render/text.js.map +1 -0
- package/dist/core/repo/tree/render/views.js +293 -0
- package/dist/core/repo/tree/render/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +255 -0
- package/dist/core/repo/tree/walk.js.map +1 -0
- package/dist/core/results.js +146 -14
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +239 -0
- package/dist/core/scaffold/landscape.js.map +1 -0
- package/dist/core/scaffold/legacy.js +271 -0
- package/dist/core/scaffold/legacy.js.map +1 -0
- package/dist/core/scaffold/readme.js +84 -0
- package/dist/core/scaffold/readme.js.map +1 -0
- package/dist/core/staging/commit.js +252 -0
- package/dist/core/staging/commit.js.map +1 -0
- package/dist/core/staging/interrupted.js +96 -0
- package/dist/core/staging/interrupted.js.map +1 -0
- package/dist/core/staging/lock.js +268 -0
- package/dist/core/staging/lock.js.map +1 -0
- package/dist/core/staging/recovery/finding.js +35 -0
- package/dist/core/staging/recovery/finding.js.map +1 -0
- package/dist/core/staging/recovery/intent.js +95 -0
- package/dist/core/staging/recovery/intent.js.map +1 -0
- package/dist/core/staging/recovery/recover.js +204 -0
- package/dist/core/staging/recovery/recover.js.map +1 -0
- package/dist/core/staging/recovery/residue.js +62 -0
- package/dist/core/staging/recovery/residue.js.map +1 -0
- package/dist/core/staging/snapshot/manifest.js +188 -0
- package/dist/core/staging/snapshot/manifest.js.map +1 -0
- package/dist/core/staging/snapshot/snapshot.js +196 -0
- package/dist/core/staging/snapshot/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +181 -0
- package/dist/core/staging/txn/forward.js.map +1 -0
- package/dist/core/staging/txn/journal.js +139 -0
- package/dist/core/staging/txn/journal.js.map +1 -0
- package/dist/core/staging/txn/transaction.js +75 -0
- package/dist/core/staging/txn/transaction.js.map +1 -0
- package/dist/core/staging/writes.js +113 -0
- package/dist/core/staging/writes.js.map +1 -0
- package/dist/core/status/actions/execution.js +60 -0
- package/dist/core/status/actions/execution.js.map +1 -0
- package/dist/core/status/contracts.js +126 -0
- package/dist/core/status/contracts.js.map +1 -0
- package/dist/core/status/feature/artifacts.js +196 -0
- package/dist/core/status/feature/artifacts.js.map +1 -0
- package/dist/core/status/feature/feature.js +214 -0
- package/dist/core/status/feature/feature.js.map +1 -0
- package/dist/core/status/feature/next.js +163 -0
- package/dist/core/status/feature/next.js.map +1 -0
- package/dist/core/status/feature/state.js +21 -0
- package/dist/core/status/feature/state.js.map +1 -0
- package/dist/core/status/feature/words.js +96 -0
- package/dist/core/status/feature/words.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +216 -0
- package/dist/core/status/fleet/fleet.js.map +1 -0
- package/dist/core/status/fleet/next.js +302 -0
- package/dist/core/status/fleet/next.js.map +1 -0
- package/dist/core/status/interrupted.js +97 -0
- package/dist/core/status/interrupted.js.map +1 -0
- package/dist/core/status/report.js +31 -0
- package/dist/core/status/report.js.map +1 -0
- package/dist/core/status/scan.js +41 -0
- package/dist/core/status/scan.js.map +1 -0
- package/dist/core/status/verification.js +216 -0
- package/dist/core/status/verification.js.map +1 -0
- package/dist/core/tasks/packet.js +199 -0
- package/dist/core/tasks/packet.js.map +1 -0
- package/dist/core/tasks/record.js +43 -0
- package/dist/core/tasks/record.js.map +1 -0
- package/dist/core/tasks/sources.js +181 -0
- package/dist/core/tasks/sources.js.map +1 -0
- package/dist/core/tasks/stamps.js +76 -0
- package/dist/core/tasks/stamps.js.map +1 -0
- package/dist/core/tasks/unit.js +0 -0
- package/dist/core/tasks/unit.js.map +1 -0
- package/dist/core/usecases/capability.js +166 -0
- package/dist/core/usecases/capability.js.map +1 -0
- package/dist/core/usecases/delta/claims.js +140 -0
- package/dist/core/usecases/delta/claims.js.map +1 -0
- package/dist/core/usecases/delta/flows.js +101 -0
- package/dist/core/usecases/delta/flows.js.map +1 -0
- package/dist/core/usecases/delta/modified.js +315 -0
- package/dist/core/usecases/delta/modified.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +76 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -0
- package/dist/core/usecases/fleet.js +296 -0
- package/dist/core/usecases/fleet.js.map +1 -0
- package/dist/core/usecases/grade/capability-tag.js +93 -0
- package/dist/core/usecases/grade/capability-tag.js.map +1 -0
- package/dist/core/usecases/grade/feature.js +88 -0
- package/dist/core/usecases/grade/feature.js.map +1 -0
- package/dist/core/usecases/grade/requirement-tag.js +94 -0
- package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
- package/dist/core/usecases/grade/steps.js +266 -0
- package/dist/core/usecases/grade/steps.js.map +1 -0
- package/dist/core/usecases/grade/usecases.js +112 -0
- package/dist/core/usecases/grade/usecases.js.map +1 -0
- package/dist/core/usecases/operations.js +123 -0
- package/dist/core/usecases/operations.js.map +1 -0
- package/dist/core/usecases/place.js +44 -0
- package/dist/core/usecases/place.js.map +1 -0
- package/dist/core/usecases/service/exclude.js +119 -0
- package/dist/core/usecases/service/exclude.js.map +1 -0
- package/dist/core/usecases/service/flows.js +164 -0
- package/dist/core/usecases/service/flows.js.map +1 -0
- package/dist/core/usecases/suites/participants.js +83 -0
- package/dist/core/usecases/suites/participants.js.map +1 -0
- package/dist/core/usecases/suites/suites.js +45 -0
- package/dist/core/usecases/suites/suites.js.map +1 -0
- package/dist/core/usecases/touch.js +101 -0
- package/dist/core/usecases/touch.js.map +1 -0
- package/dist/core/verify/answers.js +180 -0
- package/dist/core/verify/answers.js.map +1 -0
- package/dist/core/verify/build.js +170 -0
- package/dist/core/verify/build.js.map +1 -0
- package/dist/core/verify/checklist.js +259 -0
- package/dist/core/verify/checklist.js.map +1 -0
- package/dist/core/verify/claims/identity.js +61 -0
- package/dist/core/verify/claims/identity.js.map +1 -0
- package/dist/core/verify/cross/diff.js +97 -0
- package/dist/core/verify/cross/diff.js.map +1 -0
- package/dist/core/verify/evidence/contract.js +169 -0
- package/dist/core/verify/evidence/contract.js.map +1 -0
- package/dist/core/verify/location.js +67 -0
- package/dist/core/verify/location.js.map +1 -0
- package/dist/core/verify/pins/lint.js +158 -0
- package/dist/core/verify/pins/lint.js.map +1 -0
- package/dist/core/verify/pins/pin.js +95 -0
- package/dist/core/verify/pins/pin.js.map +1 -0
- package/dist/core/verify/read/file.js +224 -0
- package/dist/core/verify/read/file.js.map +1 -0
- package/dist/core/verify/read/shape.js +169 -0
- package/dist/core/verify/read/shape.js.map +1 -0
- package/dist/core/verify/read/union.js +105 -0
- package/dist/core/verify/read/union.js.map +1 -0
- package/dist/core/verify/record.js +165 -0
- package/dist/core/verify/record.js.map +1 -0
- package/dist/core/verify/store/commit.js +99 -0
- package/dist/core/verify/store/commit.js.map +1 -0
- package/dist/core/verify/store/render.js +61 -0
- package/dist/core/verify/store/render.js.map +1 -0
- package/dist/core/vocabulary/health.js +91 -0
- package/dist/core/vocabulary/health.js.map +1 -0
- package/dist/core/vocabulary/issue.js +59 -0
- package/dist/core/vocabulary/issue.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +216 -0
- package/dist/core/vocabulary/maturity.js.map +1 -0
- package/dist/core/vocabulary/report.js +90 -0
- package/dist/core/vocabulary/report.js.map +1 -0
- package/dist/core/vocabulary/steps.js +266 -0
- package/dist/core/vocabulary/steps.js.map +1 -0
- package/dist/core/workspace/discover.js +239 -0
- package/dist/core/workspace/discover.js.map +1 -0
- package/dist/core/workspace/render.js +52 -0
- package/dist/core/workspace/render.js.map +1 -0
- package/examples/README.md +232 -0
- package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
- package/examples/docs/architecture/capabilities.yaml +31 -0
- package/examples/docs/architecture/landscape.likec4 +336 -0
- package/examples/docs/architecture/obligations.yaml +23 -0
- package/examples/docs/architecture/permissions.yaml +50 -0
- package/examples/docs/architecture/services.likec4 +70 -0
- package/examples/docs/architecture/subsystems.likec4 +18 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +74 -0
- package/examples/docs/capabilities/checkout/spec.md +55 -0
- package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
- package/examples/docs/capabilities/order-notifications/spec.md +43 -0
- package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
- package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
- package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +132 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +31 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
- package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
- package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +73 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
- package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
- package/examples/docs/glossary/order.md +15 -0
- package/examples/docs/glossary/payments/authorization.md +14 -0
- package/examples/docs/likec4.config.json +8 -0
- package/examples/docs/loam.json +3 -0
- package/examples/docs/services/checkout-web/model.likec4 +92 -0
- package/examples/docs/services/checkout-web/spec.md +91 -0
- package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
- package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
- package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
- package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
- package/examples/docs/services/order-service/arch.spec.md +134 -0
- package/examples/docs/services/order-service/asyncapi.yaml +109 -0
- package/examples/docs/services/order-service/health.yaml +57 -0
- package/examples/docs/services/order-service/model.likec4 +126 -0
- package/examples/docs/services/order-service/openapi.yaml +257 -0
- package/examples/docs/services/order-service/runbook.md +62 -0
- package/examples/docs/services/order-service/spec.md +134 -0
- package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
- package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
- package/examples/docs/services/payment-service/arch.spec.md +76 -0
- package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
- package/examples/docs/services/payment-service/health.yaml +39 -0
- package/examples/docs/services/payment-service/model.likec4 +68 -0
- package/examples/docs/services/payment-service/openapi.yaml +151 -0
- package/examples/docs/services/payment-service/runbook.md +37 -0
- package/examples/docs/services/payment-service/spec.md +88 -0
- package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
- package/examples/docs/services/platform/identity-service/arch.spec.md +120 -0
- package/examples/docs/services/platform/identity-service/health.yaml +70 -0
- package/examples/docs/services/platform/identity-service/model.likec4 +81 -0
- package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
- package/examples/docs/services/platform/identity-service/runbook.md +95 -0
- package/examples/docs/services/platform/identity-service/spec.md +119 -0
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +200 -0
- package/examples/docs/services/platform/notification-service/health.yaml +40 -0
- package/examples/docs/services/platform/notification-service/model.likec4 +97 -0
- package/examples/docs/services/platform/notification-service/runbook.md +48 -0
- package/examples/docs/services/platform/notification-service/spec.md +112 -0
- package/examples/docs/services/platform/subsystem.yaml +2 -0
- package/examples/fleet.yaml +57 -0
- package/package.json +19 -6
- package/dist/commands/adopt.js +0 -240
- package/dist/commands/adopt.js.map +0 -1
- package/dist/commands/archive.js +0 -1313
- package/dist/commands/archive.js.map +0 -1
- package/dist/commands/delta.js +0 -388
- package/dist/commands/delta.js.map +0 -1
- package/dist/commands/docs-repo-gate.js.map +0 -1
- package/dist/commands/format.js +0 -17
- package/dist/commands/format.js.map +0 -1
- package/dist/commands/gherkin.js +0 -309
- package/dist/commands/gherkin.js.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/list.js +0 -295
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/migrate-openspec.js +0 -950
- package/dist/commands/migrate-openspec.js.map +0 -1
- package/dist/commands/new.js +0 -413
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/rebase.js +0 -356
- package/dist/commands/rebase.js.map +0 -1
- package/dist/commands/show.js +0 -320
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/status.js +0 -262
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/unarchive.js +0 -317
- package/dist/commands/unarchive.js.map +0 -1
- package/dist/commands/validate.js +0 -1773
- package/dist/commands/validate.js.map +0 -1
- package/dist/commands/verify.js +0 -775
- package/dist/commands/verify.js.map +0 -1
- package/dist/commands/vouch.js +0 -421
- package/dist/commands/vouch.js.map +0 -1
- package/dist/core/agent.js +0 -2173
- package/dist/core/agent.js.map +0 -1
- package/dist/core/agents-stamp.js.map +0 -1
- package/dist/core/arch.js +0 -130
- package/dist/core/arch.js.map +0 -1
- package/dist/core/asyncapi.js +0 -253
- package/dist/core/asyncapi.js.map +0 -1
- package/dist/core/brief.js +0 -755
- package/dist/core/brief.js.map +0 -1
- package/dist/core/coherence.js +0 -577
- package/dist/core/coherence.js.map +0 -1
- package/dist/core/concurrency.js.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/delta.js +0 -476
- package/dist/core/delta.js.map +0 -1
- package/dist/core/dependencies.js +0 -356
- package/dist/core/dependencies.js.map +0 -1
- package/dist/core/doctor.js +0 -596
- package/dist/core/doctor.js.map +0 -1
- package/dist/core/document-bytes.js.map +0 -1
- package/dist/core/explore.js +0 -225
- package/dist/core/explore.js.map +0 -1
- package/dist/core/frontmatter.js.map +0 -1
- package/dist/core/gherkin.js +0 -463
- package/dist/core/gherkin.js.map +0 -1
- package/dist/core/health.js +0 -67
- package/dist/core/health.js.map +0 -1
- package/dist/core/ids.js +0 -122
- package/dist/core/ids.js.map +0 -1
- package/dist/core/issue.js +0 -9
- package/dist/core/issue.js.map +0 -1
- package/dist/core/json.js +0 -74
- package/dist/core/json.js.map +0 -1
- package/dist/core/likec4.js +0 -489
- package/dist/core/likec4.js.map +0 -1
- package/dist/core/maturity.js +0 -66
- package/dist/core/maturity.js.map +0 -1
- package/dist/core/openapi-merge.js +0 -552
- package/dist/core/openapi-merge.js.map +0 -1
- package/dist/core/openapi.js.map +0 -1
- package/dist/core/openspec-inventory.js +0 -1440
- package/dist/core/openspec-inventory.js.map +0 -1
- package/dist/core/path-safety.js.map +0 -1
- package/dist/core/provenance.js +0 -787
- package/dist/core/provenance.js.map +0 -1
- package/dist/core/records.js.map +0 -1
- package/dist/core/repo.js +0 -438
- package/dist/core/repo.js.map +0 -1
- package/dist/core/report.js +0 -47
- package/dist/core/report.js.map +0 -1
- package/dist/core/spec.js +0 -505
- package/dist/core/spec.js.map +0 -1
- package/dist/core/staging.js +0 -890
- package/dist/core/staging.js.map +0 -1
- package/dist/core/status.js +0 -1132
- package/dist/core/status.js.map +0 -1
- package/dist/core/steps.js +0 -72
- package/dist/core/steps.js.map +0 -1
- package/dist/core/verify.js +0 -807
- package/dist/core/verify.js.map +0 -1
- package/dist/core/version.js.map +0 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The spelling rule for a capability id that ARRIVED FROM ARGV — the one
|
|
3
|
+
* provenance `repo/authored/paths.ts` says must never reach a path join unchecked.
|
|
4
|
+
*
|
|
5
|
+
* `livingCapabilityPaths` takes a plain `string`, and its comment states why: a
|
|
6
|
+
* capability id has no grammar of its own — it is a YAML key and a chain of
|
|
7
|
+
* directory names — so what holds that join is PROVENANCE. Every id it sees
|
|
8
|
+
* today came out of a `readCapabilityTree` walk, where each component is a
|
|
9
|
+
* `readdir` entry name and therefore demonstrably a directory that exists.
|
|
10
|
+
* (`featureCapabilityDeltasDir` beside it takes a branded `FeatureDir` and no
|
|
11
|
+
* capability id at all; the feature-side join is spelled by `loam new` itself.)
|
|
12
|
+
*
|
|
13
|
+
* `loam new --capability <id>` is the first caller with no such provenance. The
|
|
14
|
+
* string is whatever a person typed, and it is joined as
|
|
15
|
+
* `features/<dirName>/capabilities/<id>/spec.md` — so `--capability ../../evil`
|
|
16
|
+
* resolves to `features/evil/spec.md`, a directory `listFeatures` then
|
|
17
|
+
* enumerates as a feature, and one `..` further reaches the docs-repo root.
|
|
18
|
+
* `resolveInside` cannot refuse either: both are still inside the repo. That is
|
|
19
|
+
* the failure this module closes, and it is the same one
|
|
20
|
+
* `core/kernel/ids/service.ts` opens with one file over.
|
|
21
|
+
*
|
|
22
|
+
* IT IS THE DIRECTORY-NAME RULE, NOT A NEW ONE. Nesting is spelled by the tree
|
|
23
|
+
* (`payments/refunds` is two directories), so an id is legal exactly when every
|
|
24
|
+
* one of its `/`-separated segments is a legal directory name in the docs repo
|
|
25
|
+
* — `dirNameHazard`, the same check a service id and a subsystem name are held
|
|
26
|
+
* to, Windows device names and trailing dots included. A capability tree that
|
|
27
|
+
* only clones onto some of the machines that read it is the same defect there
|
|
28
|
+
* as it is under `services/`.
|
|
29
|
+
*
|
|
30
|
+
* NO BRAND, deliberately, and the reason is the provenance rule above rather
|
|
31
|
+
* than an omission: a brand is worth its annotations when a path builder can
|
|
32
|
+
* DEMAND it, and neither builder can — both are called with walk-derived ids
|
|
33
|
+
* that were never parsed here and must keep working. What this module gives is
|
|
34
|
+
* the check the argv path owes; the rule that walk-derived ids are safe stays
|
|
35
|
+
* where `repo/paths.ts` already writes it down.
|
|
36
|
+
*/
|
|
37
|
+
import { dirNameHazard } from "./service.js";
|
|
38
|
+
/** Prose form of the rule, shown verbatim in the refusal so the fix is obvious. */
|
|
39
|
+
const CAPABILITY_ID_RULE = "a capability id is one or more '/'-separated segments, each starting with a letter or digit and " +
|
|
40
|
+
"containing only letters, digits, '.', '_' or '-' (no '..', no spaces, no leading or trailing '/') — " +
|
|
41
|
+
"it becomes the capabilities/<id>/ directory chain, one directory per segment";
|
|
42
|
+
/**
|
|
43
|
+
* Why `id` cannot be a capability id, or null when it can.
|
|
44
|
+
*
|
|
45
|
+
* A sentence rather than a boolean, matching `serviceIdProblem`: a caller that
|
|
46
|
+
* is collecting findings prints exactly what a refusal would.
|
|
47
|
+
*/
|
|
48
|
+
export function capabilityIdProblem(id, label = "--capability") {
|
|
49
|
+
if (typeof id !== "string" || id === "") {
|
|
50
|
+
return `${label} must name a capability: ${CAPABILITY_ID_RULE}.`;
|
|
51
|
+
}
|
|
52
|
+
for (const segment of id.split("/")) {
|
|
53
|
+
const hazard = dirNameHazard(segment);
|
|
54
|
+
if (hazard === null)
|
|
55
|
+
continue;
|
|
56
|
+
switch (hazard.kind) {
|
|
57
|
+
case "grammar":
|
|
58
|
+
return `Invalid ${label} '${id}': ${CAPABILITY_ID_RULE}.`;
|
|
59
|
+
// Both Windows refusals keep their own sentence for `serviceIdProblem`'s
|
|
60
|
+
// reason: "does not match the grammar" is true and useless, because the
|
|
61
|
+
// id LOOKS fine and the problem is what the filesystem does with it.
|
|
62
|
+
case "windows-device":
|
|
63
|
+
return (`Invalid ${label} '${id}': '${hazard.stem}' is a reserved device name on Windows — ` +
|
|
64
|
+
`the capabilities/${id}/ directory cannot be created there at all, so the docs repo would only work on some of the machines that clone it.`);
|
|
65
|
+
case "windows-trailing":
|
|
66
|
+
return (`Invalid ${label} '${id}': no segment of a capability id may end with '.' or a space — ` +
|
|
67
|
+
"Windows strips both when creating a directory, so the id would silently name one directory there and another everywhere else.");
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=capability.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capability.js","sourceRoot":"","sources":["../../../../src/core/kernel/ids/capability.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,mFAAmF;AACnF,MAAM,kBAAkB,GACtB,kGAAkG;IAClG,sGAAsG;IACtG,8EAA8E,CAAC;AAEjF;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAW,EAAE,KAAK,GAAG,cAAc;IACrE,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACxC,OAAO,GAAG,KAAK,4BAA4B,kBAAkB,GAAG,CAAC;IACnE,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACpC,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,MAAM,KAAK,IAAI;YAAE,SAAS;QAC9B,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;YACpB,KAAK,SAAS;gBACZ,OAAO,WAAW,KAAK,KAAK,EAAE,MAAM,kBAAkB,GAAG,CAAC;YAC5D,yEAAyE;YACzE,wEAAwE;YACxE,qEAAqE;YACrE,KAAK,gBAAgB;gBACnB,OAAO,CACL,WAAW,KAAK,KAAK,EAAE,OAAO,MAAM,CAAC,IAAI,2CAA2C;oBACpF,oBAAoB,EAAE,qHAAqH,CAC5I,CAAC;YACJ,KAAK,kBAAkB;gBACrB,OAAO,CACL,WAAW,KAAK,KAAK,EAAE,iEAAiE;oBACxF,+HAA+H,CAChI,CAAC;QACN,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC","sourcesContent":["/**\n * The spelling rule for a capability id that ARRIVED FROM ARGV — the one\n * provenance `repo/authored/paths.ts` says must never reach a path join unchecked.\n *\n * `livingCapabilityPaths` takes a plain `string`, and its comment states why: a\n * capability id has no grammar of its own — it is a YAML key and a chain of\n * directory names — so what holds that join is PROVENANCE. Every id it sees\n * today came out of a `readCapabilityTree` walk, where each component is a\n * `readdir` entry name and therefore demonstrably a directory that exists.\n * (`featureCapabilityDeltasDir` beside it takes a branded `FeatureDir` and no\n * capability id at all; the feature-side join is spelled by `loam new` itself.)\n *\n * `loam new --capability <id>` is the first caller with no such provenance. The\n * string is whatever a person typed, and it is joined as\n * `features/<dirName>/capabilities/<id>/spec.md` — so `--capability ../../evil`\n * resolves to `features/evil/spec.md`, a directory `listFeatures` then\n * enumerates as a feature, and one `..` further reaches the docs-repo root.\n * `resolveInside` cannot refuse either: both are still inside the repo. That is\n * the failure this module closes, and it is the same one\n * `core/kernel/ids/service.ts` opens with one file over.\n *\n * IT IS THE DIRECTORY-NAME RULE, NOT A NEW ONE. Nesting is spelled by the tree\n * (`payments/refunds` is two directories), so an id is legal exactly when every\n * one of its `/`-separated segments is a legal directory name in the docs repo\n * — `dirNameHazard`, the same check a service id and a subsystem name are held\n * to, Windows device names and trailing dots included. A capability tree that\n * only clones onto some of the machines that read it is the same defect there\n * as it is under `services/`.\n *\n * NO BRAND, deliberately, and the reason is the provenance rule above rather\n * than an omission: a brand is worth its annotations when a path builder can\n * DEMAND it, and neither builder can — both are called with walk-derived ids\n * that were never parsed here and must keep working. What this module gives is\n * the check the argv path owes; the rule that walk-derived ids are safe stays\n * where `repo/paths.ts` already writes it down.\n */\nimport { dirNameHazard } from \"./service.js\";\n\n/** Prose form of the rule, shown verbatim in the refusal so the fix is obvious. */\nconst CAPABILITY_ID_RULE =\n \"a capability id is one or more '/'-separated segments, each starting with a letter or digit and \" +\n \"containing only letters, digits, '.', '_' or '-' (no '..', no spaces, no leading or trailing '/') — \" +\n \"it becomes the capabilities/<id>/ directory chain, one directory per segment\";\n\n/**\n * Why `id` cannot be a capability id, or null when it can.\n *\n * A sentence rather than a boolean, matching `serviceIdProblem`: a caller that\n * is collecting findings prints exactly what a refusal would.\n */\nexport function capabilityIdProblem(id: unknown, label = \"--capability\"): string | null {\n if (typeof id !== \"string\" || id === \"\") {\n return `${label} must name a capability: ${CAPABILITY_ID_RULE}.`;\n }\n for (const segment of id.split(\"/\")) {\n const hazard = dirNameHazard(segment);\n if (hazard === null) continue;\n switch (hazard.kind) {\n case \"grammar\":\n return `Invalid ${label} '${id}': ${CAPABILITY_ID_RULE}.`;\n // Both Windows refusals keep their own sentence for `serviceIdProblem`'s\n // reason: \"does not match the grammar\" is true and useless, because the\n // id LOOKS fine and the problem is what the filesystem does with it.\n case \"windows-device\":\n return (\n `Invalid ${label} '${id}': '${hazard.stem}' is a reserved device name on Windows — ` +\n `the capabilities/${id}/ directory cannot be created there at all, so the docs repo would only work on some of the machines that clone it.`\n );\n case \"windows-trailing\":\n return (\n `Invalid ${label} '${id}': no segment of a capability id may end with '.' or a space — ` +\n \"Windows strips both when creating a directory, so the id would silently name one directory there and another everywhere else.\"\n );\n }\n }\n return null;\n}\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** The only constructor. `resolved` must carry `DocsDir`'s provenance, above. */
|
|
2
|
+
export function docsDirOf(resolved) {
|
|
3
|
+
return resolved;
|
|
4
|
+
}
|
|
5
|
+
/** The only constructor. `abs` must carry `FeatureDir`'s provenance, above. */
|
|
6
|
+
export function featureDirOf(abs) {
|
|
7
|
+
return abs;
|
|
8
|
+
}
|
|
9
|
+
/** The only constructor. `abs` must carry one of `ServiceDir`'s two provenances, above. */
|
|
10
|
+
export function serviceDirOf(abs) {
|
|
11
|
+
return abs;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Where a service sits under `services/`, repo-relative and spelled from its
|
|
15
|
+
* own placement chain — `services/<subsystem>/…/<id>/` for a filed service,
|
|
16
|
+
* `services/<id>/` for an unfiled one.
|
|
17
|
+
*
|
|
18
|
+
* The join it replaces is `services/${id}`, which is right for an unfiled
|
|
19
|
+
* service and WRONG for every filed one, and the failure is the kind a reader
|
|
20
|
+
* cannot diagnose: the message names a directory that does not exist, so the
|
|
21
|
+
* fix goes to the wrong place, or a `cd` simply fails. Three findings already
|
|
22
|
+
* spelled it correctly by hand and `loam status` spelled it by id; this exists
|
|
23
|
+
* so the rule has one implementation rather than a convention.
|
|
24
|
+
*
|
|
25
|
+
* DISPLAY only, and not a `ServiceDir`: it is repo-relative text for a human
|
|
26
|
+
* to read, while `ServiceDir` is the absolute path artifacts resolve from. And
|
|
27
|
+
* `subsystem` is placement carrying no identity, so nothing here may be joined
|
|
28
|
+
* on — the id is the identity, at whatever depth it lives.
|
|
29
|
+
*/
|
|
30
|
+
export function serviceTreePath(s) {
|
|
31
|
+
return ["services", ...s.subsystem, s.id].join("/");
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=dirs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dirs.js","sourceRoot":"","sources":["../../../../src/core/kernel/ids/dirs.ts"],"names":[],"mappings":"AAwDA,iFAAiF;AACjF,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,OAAO,QAAmB,CAAC;AAC7B,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,GAAiB,CAAC;AAC3B,CAAC;AAED,2FAA2F;AAC3F,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,OAAO,GAAiB,CAAC;AAC3B,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,eAAe,CAAC,CAAsC;IACpE,OAAO,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC","sourcesContent":["/**\n * The two directory roots loam's path builders spell paths under, branded by\n * PROVENANCE — where the string came from — exactly as the id brands beside\n * this file are.\n *\n * `repo/paths.ts` interpolates caller-controlled ids into these roots, and its\n * guarantee is only as good as the root it starts from: an\n * `unfiledServicePaths(dir, id)` whose `dir` is whatever string happened to\n * be in scope spells paths\n * into whatever tree that string names. Honestly stated: these constructors\n * VALIDATE nothing — they RECORD a provenance the caller must already have\n * established, and what the gate contributes is that the cast appears in\n * exactly one place per brand (a cast anywhere else in `src/` is a finding,\n * not a shortcut). `init` brands its `--docs` resolution before its guards\n * run and refuses before any path is built — the provenance comment is the\n * contract those call sites are held to by review, not by the compiler.\n *\n * The two brands are deliberately disjoint: a docs repo root and a feature\n * directory are different trees, and `featurePaths(docsDir)` is precisely the\n * confusion the compiler should refuse.\n */\ndeclare const provenance: unique symbol;\n\n/**\n * The resolved absolute root of the shared docs repo. Provenance: resolved\n * through a loaded config (`parseConfig` resolves the stored spelling against\n * the config file's own directory) or an explicit `--docs` a command\n * validated. NOT the stored spelling — loam.json deliberately keeps the\n * relative form (`storedDocsDir`), and that spelling stays a plain `string`.\n */\nexport type DocsDir = string & { readonly [provenance]: \"docs-dir\" };\n\n/**\n * The absolute path of one feature's directory. Provenance: an enumeration\n * read this directory — `listFeatures` joined a name `readdir` returned onto\n * the features root it walked, so the directory demonstrably exists (or did,\n * one readdir ago).\n */\nexport type FeatureDir = string & { readonly [provenance]: \"feature-dir\" };\n\n/**\n * The absolute path of one service's directory — the value the artifact paths\n * in `repo/paths.ts` are spelled under. Two provenances, both stated because\n * both are load-bearing: the tree walk read it (`core/repo/tree/walk.ts`\n * joined a name `readdir` returned onto the directory it was listed under, at\n * whatever depth the service actually lives), or it is the canonical UNFILED\n * spelling `<docsDir>/services/<id>/` that `unfiledServicePaths` builds from a\n * validated id and a `DocsDir` — the one place creation lands, and the honest\n * fallback for a service the enumeration does not answer. A path from a\n * readdir is NARROWER than one built from a validated string: the directory\n * demonstrably exists where the path says. Nothing else may construct this —\n * in particular not a bare `join(docsDir, \"services\", name)` at a call site,\n * which is exactly the root-level assumption the subsystem tree retired.\n */\nexport type ServiceDir = string & { readonly [provenance]: \"service-dir\" };\n\n/** The only constructor. `resolved` must carry `DocsDir`'s provenance, above. */\nexport function docsDirOf(resolved: string): DocsDir {\n return resolved as DocsDir;\n}\n\n/** The only constructor. `abs` must carry `FeatureDir`'s provenance, above. */\nexport function featureDirOf(abs: string): FeatureDir {\n return abs as FeatureDir;\n}\n\n/** The only constructor. `abs` must carry one of `ServiceDir`'s two provenances, above. */\nexport function serviceDirOf(abs: string): ServiceDir {\n return abs as ServiceDir;\n}\n\n/**\n * Where a service sits under `services/`, repo-relative and spelled from its\n * own placement chain — `services/<subsystem>/…/<id>/` for a filed service,\n * `services/<id>/` for an unfiled one.\n *\n * The join it replaces is `services/${id}`, which is right for an unfiled\n * service and WRONG for every filed one, and the failure is the kind a reader\n * cannot diagnose: the message names a directory that does not exist, so the\n * fix goes to the wrong place, or a `cd` simply fails. Three findings already\n * spelled it correctly by hand and `loam status` spelled it by id; this exists\n * so the rule has one implementation rather than a convention.\n *\n * DISPLAY only, and not a `ServiceDir`: it is repo-relative text for a human\n * to read, while `ServiceDir` is the absolute path artifacts resolve from. And\n * `subsystem` is placement carrying no identity, so nothing here may be joined\n * on — the id is the identity, at whatever depth it lives.\n */\nexport function serviceTreePath(s: { id: string; subsystem: string[] }): string {\n return [\"services\", ...s.subsystem, s.id].join(\"/\");\n}\n"]}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The spelling rule for feature ids, and the brands that carry its provenance.
|
|
3
|
+
*
|
|
4
|
+
* Split out of `service.ts` when the feature grammar grew the same brand
|
|
5
|
+
* lattice the service grammar has: the two rules share a package because both
|
|
6
|
+
* become directory names in the shared docs repo, but a feature id is not a
|
|
7
|
+
* service id — the brands below are deliberately disjoint from `RawServiceId`
|
|
8
|
+
* and `ServiceId`, so one grammar's checked value cannot stand in where the
|
|
9
|
+
* other's is demanded.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* Feature ids are `<word>-<number>`: the id has to survive being read back off
|
|
13
|
+
* the directory name (`FEAT-101-payment-splitting` -> `FEAT-101`), or the
|
|
14
|
+
* feature would answer to a name it was never given.
|
|
15
|
+
*
|
|
16
|
+
* Here for the same reason the service grammar is — this was spelled twice,
|
|
17
|
+
* privately, in `commands/new.ts` and `core/openspec/`, and
|
|
18
|
+
* docs/DESIGN.md rule 7 recorded the pair as a hazard rather than a fact. The
|
|
19
|
+
* third caller is what made it one: `loam explore --as <FEAT>` interpolates its
|
|
20
|
+
* argument into a `loam new` line that loam PRINTS for an agent to run, so
|
|
21
|
+
* without this check `explore` cheerfully handed back a command `new` refuses.
|
|
22
|
+
* A guard test catches that class only for literal source strings — a command
|
|
23
|
+
* assembled at runtime from argv is invisible to it — which is exactly why the
|
|
24
|
+
* grammar has to be shared rather than re-derived by whoever needs it next.
|
|
25
|
+
*/
|
|
26
|
+
const FEATURE_ID = /^[A-Za-z][A-Za-z0-9]*-\d+$/;
|
|
27
|
+
/** Prose form, shown verbatim in every refusal so the fix is obvious. */
|
|
28
|
+
export const FEATURE_ID_RULE = "Expected <word>-<number>, e.g. FEAT-101 or BUG-42.";
|
|
29
|
+
export function isFeatureId(id) {
|
|
30
|
+
return typeof id === "string" && FEATURE_ID.test(id);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Why `id` is not a usable feature id, or null when it is — the `serviceIdProblem`
|
|
34
|
+
* shape, so a caller already collecting findings reports the sentence a refusal
|
|
35
|
+
* would print.
|
|
36
|
+
*/
|
|
37
|
+
export function featureIdProblem(id, label = "feature id") {
|
|
38
|
+
if (!isFeatureId(id)) {
|
|
39
|
+
const shown = typeof id === "string" ? `'${id}'` : String(id);
|
|
40
|
+
return `${shown} is not a usable ${label}. ${FEATURE_ID_RULE}`;
|
|
41
|
+
}
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
/* ---------------------------------------------------------------- */
|
|
45
|
+
/* The two constructors — the only place a brand is asserted */
|
|
46
|
+
/* ---------------------------------------------------------------- */
|
|
47
|
+
/**
|
|
48
|
+
* The one constructor that validates — `parseServiceId`'s shape, for the same
|
|
49
|
+
* reason: a discriminated pair rather than `FeatureId | string`, because that
|
|
50
|
+
* second shape compiles and is unusable, and the problem sentence is the one
|
|
51
|
+
* `featureIdProblem` already produces, so a caller that is collecting findings
|
|
52
|
+
* prints exactly what a refusal would.
|
|
53
|
+
*/
|
|
54
|
+
export function parseFeatureId(raw, label = "feature id") {
|
|
55
|
+
const problem = featureIdProblem(raw, label);
|
|
56
|
+
if (problem !== null)
|
|
57
|
+
return { ok: false, problem };
|
|
58
|
+
// The cast, on the line immediately after the check that earns it.
|
|
59
|
+
return { ok: true, id: raw };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* An id derived from a directory name a repository listed. Says nothing about
|
|
63
|
+
* whether it is a legal id — that is the point: the enumeration must be able to
|
|
64
|
+
* name the directory that is there, however it is spelled.
|
|
65
|
+
*
|
|
66
|
+
* This is a cast, and it has to be: the derivation in
|
|
67
|
+
* `core/repo/entries.ts`'s `featureIdFromDirName` starts from a plain `readdir`
|
|
68
|
+
* string, and a brand does not survive it. What the rule in
|
|
69
|
+
* `docs/CODE-STYLE.md` buys is that both of this file's casts live HERE and
|
|
70
|
+
* nowhere else — a third one somewhere in `src/` is a finding, not a shortcut.
|
|
71
|
+
*/
|
|
72
|
+
export function rawFeatureId(derived) {
|
|
73
|
+
return derived;
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=feature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature.js","sourceRoot":"","sources":["../../../../src/core/kernel/ids/feature.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA2BH;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,GAAG,4BAA4B,CAAC;AAEhD,yEAAyE;AACzE,MAAM,CAAC,MAAM,eAAe,GAAG,oDAAoD,CAAC;AAEpF,MAAM,UAAU,WAAW,CAAC,EAAW;IACrC,OAAO,OAAO,EAAE,KAAK,QAAQ,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAW,EAAE,KAAK,GAAG,YAAY;IAChE,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC9D,OAAO,GAAG,KAAK,oBAAoB,KAAK,KAAK,eAAe,EAAE,CAAC;IACjE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,sEAAsE;AACtE,uEAAuE;AACvE,sEAAsE;AAEtE;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAW,EACX,KAAK,GAAG,YAAY;IAEpB,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7C,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IACpD,mEAAmE;IACnE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,GAAgB,EAAE,CAAC;AAC5C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,OAAO,OAAuB,CAAC;AACjC,CAAC","sourcesContent":["/**\n * The spelling rule for feature ids, and the brands that carry its provenance.\n *\n * Split out of `service.ts` when the feature grammar grew the same brand\n * lattice the service grammar has: the two rules share a package because both\n * become directory names in the shared docs repo, but a feature id is not a\n * service id — the brands below are deliberately disjoint from `RawServiceId`\n * and `ServiceId`, so one grammar's checked value cannot stand in where the\n * other's is demanded.\n */\n\n/* ---------------------------------------------------------------- */\n/* The two provenances a feature name can have */\n/* ---------------------------------------------------------------- */\n\n/**\n * Same hierarchy as the service brands, for the same measured reason: the raw\n * form is the base — a name whose provenance is the repository — and the\n * checked form is a SUBTYPE, so `id === arg`, `Set<RawFeatureId>.has(id)` and\n * sorting a mixed list all stay the ordinary string business they are.\n */\ndeclare const provenance: unique symbol;\ndeclare const checked: unique symbol;\n\n/**\n * A feature id a repository listed this directory for: read back off a\n * `features/` directory name by the enumeration. It exists; it may still be an\n * illegal loam id — `core/repo/repo.ts`'s `listFeatures` deliberately returns\n * those, because `loam list` must show you the badly-named directory that is\n * there.\n */\nexport type RawFeatureId = string & { readonly [provenance]: \"loam\" };\n\n/** An id that passed `featureIdProblem`. The only form a caller may construct. */\nexport type FeatureId = RawFeatureId & { readonly [checked]: true };\n\n/**\n * Feature ids are `<word>-<number>`: the id has to survive being read back off\n * the directory name (`FEAT-101-payment-splitting` -> `FEAT-101`), or the\n * feature would answer to a name it was never given.\n *\n * Here for the same reason the service grammar is — this was spelled twice,\n * privately, in `commands/new.ts` and `core/openspec/`, and\n * docs/DESIGN.md rule 7 recorded the pair as a hazard rather than a fact. The\n * third caller is what made it one: `loam explore --as <FEAT>` interpolates its\n * argument into a `loam new` line that loam PRINTS for an agent to run, so\n * without this check `explore` cheerfully handed back a command `new` refuses.\n * A guard test catches that class only for literal source strings — a command\n * assembled at runtime from argv is invisible to it — which is exactly why the\n * grammar has to be shared rather than re-derived by whoever needs it next.\n */\nconst FEATURE_ID = /^[A-Za-z][A-Za-z0-9]*-\\d+$/;\n\n/** Prose form, shown verbatim in every refusal so the fix is obvious. */\nexport const FEATURE_ID_RULE = \"Expected <word>-<number>, e.g. FEAT-101 or BUG-42.\";\n\nexport function isFeatureId(id: unknown): id is string {\n return typeof id === \"string\" && FEATURE_ID.test(id);\n}\n\n/**\n * Why `id` is not a usable feature id, or null when it is — the `serviceIdProblem`\n * shape, so a caller already collecting findings reports the sentence a refusal\n * would print.\n */\nexport function featureIdProblem(id: unknown, label = \"feature id\"): string | null {\n if (!isFeatureId(id)) {\n const shown = typeof id === \"string\" ? `'${id}'` : String(id);\n return `${shown} is not a usable ${label}. ${FEATURE_ID_RULE}`;\n }\n return null;\n}\n\n/* ---------------------------------------------------------------- */\n/* The two constructors — the only place a brand is asserted */\n/* ---------------------------------------------------------------- */\n\n/**\n * The one constructor that validates — `parseServiceId`'s shape, for the same\n * reason: a discriminated pair rather than `FeatureId | string`, because that\n * second shape compiles and is unusable, and the problem sentence is the one\n * `featureIdProblem` already produces, so a caller that is collecting findings\n * prints exactly what a refusal would.\n */\nexport function parseFeatureId(\n raw: string,\n label = \"feature id\",\n): { ok: true; id: FeatureId } | { ok: false; problem: string } {\n const problem = featureIdProblem(raw, label);\n if (problem !== null) return { ok: false, problem };\n // The cast, on the line immediately after the check that earns it.\n return { ok: true, id: raw as FeatureId };\n}\n\n/**\n * An id derived from a directory name a repository listed. Says nothing about\n * whether it is a legal id — that is the point: the enumeration must be able to\n * name the directory that is there, however it is spelled.\n *\n * This is a cast, and it has to be: the derivation in\n * `core/repo/entries.ts`'s `featureIdFromDirName` starts from a plain `readdir`\n * string, and a brand does not survive it. What the rule in\n * `docs/CODE-STYLE.md` buys is that both of this file's casts live HERE and\n * nowhere else — a third one somewhere in `src/` is a finding, not a shortcut.\n */\nexport function rawFeatureId(derived: string): RawFeatureId {\n return derived as RawFeatureId;\n}\n"]}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ancestor chain of a dotted element id — `a.b.c` yields `a.b`, then `a`.
|
|
3
|
+
*
|
|
4
|
+
* A leaf of its own because five modules were each walking it privately, in two
|
|
5
|
+
* spellings, and the walk is not incidental to any of them: it is the rule that
|
|
6
|
+
* a landscape does not have to draw a service as one opaque box. The moment
|
|
7
|
+
* somebody models its containers — `paymentService.api`, `paymentService.worker`
|
|
8
|
+
* — an edge drawn INTO a container is still an edge into the service, and every
|
|
9
|
+
* join that groups by service has to know that. Resolving only the exact id is
|
|
10
|
+
* what made those edges invisible: the spine check silently skipped them, and
|
|
11
|
+
* the no-openapi grace treated a service with a dozen inbound container calls as
|
|
12
|
+
* one nobody calls at all.
|
|
13
|
+
*
|
|
14
|
+
* The same walk answers a second question one altitude down, which is why a
|
|
15
|
+
* fifth copy appeared. A service model draws an edge at `kafka.orderEvents`
|
|
16
|
+
* while the fleet's health.yaml names the dependency `kafka`, so the slice of a
|
|
17
|
+
* per-service project has to carry the ANCESTOR of a partner endpoint as well as
|
|
18
|
+
* the endpoint (`core/c4/service-model/slice.ts`). Dropping it would turn a
|
|
19
|
+
* fleet's dependency declarations into `health.dependency-unmodelled` findings
|
|
20
|
+
* on the day it migrated its models, with nothing in the docs having changed.
|
|
21
|
+
*
|
|
22
|
+
* TWO SPELLINGS, both exported, because both are real and picking one would make
|
|
23
|
+
* every second caller write `[id, ...properAncestorIds(id)]` or `.slice(1)` — a
|
|
24
|
+
* per-call-site adjustment is exactly how a shared walk drifts back into five.
|
|
25
|
+
* A resolver that also looks the element itself up wants `ancestorIds`; a walk
|
|
26
|
+
* that has already handled the element wants `properAncestorIds`.
|
|
27
|
+
*
|
|
28
|
+
* No brand and no validation: this is string arithmetic over an id a DOCUMENT
|
|
29
|
+
* spells, and `core/kernel/ids/service.ts`'s provenance rules are about names
|
|
30
|
+
* that have to answer for a directory. An id with no dot in it has no ancestors
|
|
31
|
+
* and yields the empty list, which is the correct answer rather than an edge
|
|
32
|
+
* case — a top-level element belongs to nothing above it.
|
|
33
|
+
*/
|
|
34
|
+
/** Every dotted ancestor of an id, NEAREST FIRST and excluding the id itself. */
|
|
35
|
+
export function properAncestorIds(id) {
|
|
36
|
+
const out = [];
|
|
37
|
+
// Walking right-to-left from the last dot rather than splitting and rejoining:
|
|
38
|
+
// the ids are already strings, the answer is a set of prefixes of one of them,
|
|
39
|
+
// and a split/join round trip would invent a rule about what a segment may
|
|
40
|
+
// contain that nothing else here has.
|
|
41
|
+
for (let dot = id.lastIndexOf("."); dot !== -1; dot = id.lastIndexOf(".", dot - 1)) {
|
|
42
|
+
out.push(id.slice(0, dot));
|
|
43
|
+
}
|
|
44
|
+
return out;
|
|
45
|
+
}
|
|
46
|
+
/** The id itself, then every dotted ancestor of it, nearest first. */
|
|
47
|
+
export function ancestorIds(id) {
|
|
48
|
+
return [id, ...properAncestorIds(id)];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* The id a declaration nests directly under — `""` for a top-level one, which
|
|
52
|
+
* nests under nothing.
|
|
53
|
+
*
|
|
54
|
+
* The nearest ancestor, named because that is the question the callers ask:
|
|
55
|
+
* `properAncestorIds(id)[0] ?? ""` is the same walk spelled as an array index,
|
|
56
|
+
* and every reader has to re-derive that the first entry is the parent. It is
|
|
57
|
+
* here rather than beside its callers for the reason the file exists at all —
|
|
58
|
+
* the archive's two merges had each grown a private copy, and a third was about
|
|
59
|
+
* to appear the moment the routing gained a module.
|
|
60
|
+
*/
|
|
61
|
+
export function parentIdOf(id) {
|
|
62
|
+
const dot = id.lastIndexOf(".");
|
|
63
|
+
return dot === -1 ? "" : id.slice(0, dot);
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=ancestors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ancestors.js","sourceRoot":"","sources":["../../../../../src/core/kernel/ids/fqn/ancestors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,iFAAiF;AACjF,MAAM,UAAU,iBAAiB,CAAC,EAAU;IAC1C,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,+EAA+E;IAC/E,+EAA+E;IAC/E,2EAA2E;IAC3E,sCAAsC;IACtC,KAAK,IAAI,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC;QACnF,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;IAC7B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,WAAW,CAAC,EAAU;IACpC,OAAO,CAAC,EAAE,EAAE,GAAG,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,UAAU,CAAC,EAAU;IACnC,MAAM,GAAG,GAAG,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IAChC,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC5C,CAAC","sourcesContent":["/**\n * The ancestor chain of a dotted element id — `a.b.c` yields `a.b`, then `a`.\n *\n * A leaf of its own because five modules were each walking it privately, in two\n * spellings, and the walk is not incidental to any of them: it is the rule that\n * a landscape does not have to draw a service as one opaque box. The moment\n * somebody models its containers — `paymentService.api`, `paymentService.worker`\n * — an edge drawn INTO a container is still an edge into the service, and every\n * join that groups by service has to know that. Resolving only the exact id is\n * what made those edges invisible: the spine check silently skipped them, and\n * the no-openapi grace treated a service with a dozen inbound container calls as\n * one nobody calls at all.\n *\n * The same walk answers a second question one altitude down, which is why a\n * fifth copy appeared. A service model draws an edge at `kafka.orderEvents`\n * while the fleet's health.yaml names the dependency `kafka`, so the slice of a\n * per-service project has to carry the ANCESTOR of a partner endpoint as well as\n * the endpoint (`core/c4/service-model/slice.ts`). Dropping it would turn a\n * fleet's dependency declarations into `health.dependency-unmodelled` findings\n * on the day it migrated its models, with nothing in the docs having changed.\n *\n * TWO SPELLINGS, both exported, because both are real and picking one would make\n * every second caller write `[id, ...properAncestorIds(id)]` or `.slice(1)` — a\n * per-call-site adjustment is exactly how a shared walk drifts back into five.\n * A resolver that also looks the element itself up wants `ancestorIds`; a walk\n * that has already handled the element wants `properAncestorIds`.\n *\n * No brand and no validation: this is string arithmetic over an id a DOCUMENT\n * spells, and `core/kernel/ids/service.ts`'s provenance rules are about names\n * that have to answer for a directory. An id with no dot in it has no ancestors\n * and yields the empty list, which is the correct answer rather than an edge\n * case — a top-level element belongs to nothing above it.\n */\n\n/** Every dotted ancestor of an id, NEAREST FIRST and excluding the id itself. */\nexport function properAncestorIds(id: string): string[] {\n const out: string[] = [];\n // Walking right-to-left from the last dot rather than splitting and rejoining:\n // the ids are already strings, the answer is a set of prefixes of one of them,\n // and a split/join round trip would invent a rule about what a segment may\n // contain that nothing else here has.\n for (let dot = id.lastIndexOf(\".\"); dot !== -1; dot = id.lastIndexOf(\".\", dot - 1)) {\n out.push(id.slice(0, dot));\n }\n return out;\n}\n\n/** The id itself, then every dotted ancestor of it, nearest first. */\nexport function ancestorIds(id: string): string[] {\n return [id, ...properAncestorIds(id)];\n}\n\n/**\n * The id a declaration nests directly under — `\"\"` for a top-level one, which\n * nests under nothing.\n *\n * The nearest ancestor, named because that is the question the callers ask:\n * `properAncestorIds(id)[0] ?? \"\"` is the same walk spelled as an array index,\n * and every reader has to re-derive that the first entry is the parent. It is\n * here rather than beside its callers for the reason the file exists at all —\n * the archive's two merges had each grown a private copy, and a third was about\n * to appear the moment the routing gained a module.\n */\nexport function parentIdOf(id: string): string {\n const dot = id.lastIndexOf(\".\");\n return dot === -1 ? \"\" : id.slice(0, dot);\n}\n"]}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The spelling rules for the ids loam turns into directory names.
|
|
3
|
+
*
|
|
4
|
+
* A service id is not a label: it becomes `services/<id>/` in the shared docs
|
|
5
|
+
* repo, and it is interpolated into paths by adopt, validate, vouch, gherkin and
|
|
6
|
+
* new. That makes it caller-controlled path input, so it is validated in exactly
|
|
7
|
+
* one place — here — rather than by each command inventing its own guard. The
|
|
8
|
+
* failure mode this closes is not theoretical: `--service ../../etc` would have
|
|
9
|
+
* had `unfiledServicePaths()` hand a writer a directory outside the docs repo, and
|
|
10
|
+
* `--service ''` would have made `services//spec.md` collapse to a file the
|
|
11
|
+
* enumeration in repo.ts can never see again.
|
|
12
|
+
*
|
|
13
|
+
* The rule is deliberately narrower than "a path segment that happens to work":
|
|
14
|
+
* ids are also compared, sorted and printed in tables, so shell metacharacters,
|
|
15
|
+
* spaces and leading dots are refused even where the filesystem would accept
|
|
16
|
+
* them. Widening the alphabet later is a compatible change; narrowing it is not.
|
|
17
|
+
*
|
|
18
|
+
* "Works" also means "works on Windows", which this project tests in CI: the
|
|
19
|
+
* two rules below are the ones POSIX accepts and Windows does not. They used to
|
|
20
|
+
* live in migrate-openspec.ts alone, as a second, stricter copy of this grammar
|
|
21
|
+
* — so the PRIMARY authoring path (`--service`, `--touches`, `adopt`) accepted
|
|
22
|
+
* ids the migration refused, and `services/CON/` or `services/payments./` got
|
|
23
|
+
* as far as a directory nobody can create or open. Narrowing is not a
|
|
24
|
+
* compatible change, which is exactly why it belongs here, once, rather than in
|
|
25
|
+
* whichever command happened to think of it.
|
|
26
|
+
*/
|
|
27
|
+
/** The one grammar: alphanumeric head, then alphanumerics, dot, underscore, hyphen. */
|
|
28
|
+
const SERVICE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
29
|
+
/**
|
|
30
|
+
* The MS-DOS device names Windows still reserves. Reserved with any extension
|
|
31
|
+
* and in any case (`nul`, `NUL.txt`), so the test is on the stem — the part
|
|
32
|
+
* before the first dot — uppercased.
|
|
33
|
+
*/
|
|
34
|
+
const WINDOWS_DEVICE = /^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/;
|
|
35
|
+
export function dirNameHazard(name) {
|
|
36
|
+
// `..` produces the same verdict the pattern would; it is not special-cased
|
|
37
|
+
// here — the CALLERS' prose is where "no '..'" gets its own words.
|
|
38
|
+
if (name.includes("..") || !SERVICE_ID.test(name))
|
|
39
|
+
return { kind: "grammar" };
|
|
40
|
+
const stem = name.split(".")[0];
|
|
41
|
+
if (WINDOWS_DEVICE.test(stem.toUpperCase()))
|
|
42
|
+
return { kind: "windows-device", stem };
|
|
43
|
+
if (/[. ]$/.test(name))
|
|
44
|
+
return { kind: "windows-trailing" };
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
/** Prose form of the rule, shown verbatim in every refusal so the fix is obvious. */
|
|
48
|
+
const SERVICE_ID_RULE = "a service id must start with a letter or digit and contain only letters, digits, '.', '_' or '-' " +
|
|
49
|
+
"(no slashes, no '..', no spaces) — it becomes the services/<id>/ directory name";
|
|
50
|
+
/** Refusal carrying the offending value, so a caller can quote it back. */
|
|
51
|
+
export class InvalidIdError extends Error {
|
|
52
|
+
value;
|
|
53
|
+
constructor(value, message) {
|
|
54
|
+
super(message);
|
|
55
|
+
this.value = value;
|
|
56
|
+
this.name = "InvalidIdError";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Why `id` is not a usable service id, or null when it is. Returning the reason
|
|
61
|
+
* instead of a boolean lets a caller that is already collecting findings report
|
|
62
|
+
* the same sentence a refusal would print.
|
|
63
|
+
*/
|
|
64
|
+
export function serviceIdProblem(id, label = "--service") {
|
|
65
|
+
if (typeof id !== "string" || id === "") {
|
|
66
|
+
return `${label} must name a service: ${SERVICE_ID_RULE}.`;
|
|
67
|
+
}
|
|
68
|
+
const hazard = dirNameHazard(id);
|
|
69
|
+
if (hazard === null)
|
|
70
|
+
return null;
|
|
71
|
+
switch (hazard.kind) {
|
|
72
|
+
case "grammar":
|
|
73
|
+
return `Invalid ${label} '${id}': ${SERVICE_ID_RULE}.`;
|
|
74
|
+
// Both refusals below are about Windows, and both get their own sentence:
|
|
75
|
+
// "does not match the id grammar" is true and useless, because the id
|
|
76
|
+
// LOOKS fine and the problem is what the filesystem does with it.
|
|
77
|
+
case "windows-device":
|
|
78
|
+
return (`Invalid ${label} '${id}': '${hazard.stem}' is a reserved device name on Windows — ` +
|
|
79
|
+
`services/${id}/ cannot be created there at all, so the docs repo would only work on some of the machines that clone it.`);
|
|
80
|
+
case "windows-trailing":
|
|
81
|
+
return (`Invalid ${label} '${id}': a service id may not end with '.' or a space — ` +
|
|
82
|
+
`Windows strips both when creating a directory, so '${id}' and '${id.replace(/[. ]+$/, "")}' would silently become one directory there and two everywhere else.`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Assert that `id` may be used as a `services/<id>/` directory name. Throws
|
|
87
|
+
* InvalidIdError; commands catch it and report `invalid-option`, because a bad
|
|
88
|
+
* id is always something the caller typed, never a state of the repository.
|
|
89
|
+
*/
|
|
90
|
+
export function assertServiceId(id, label = "--service") {
|
|
91
|
+
const problem = serviceIdProblem(id, label);
|
|
92
|
+
if (problem !== null)
|
|
93
|
+
throw new InvalidIdError(typeof id === "string" ? id : String(id), problem);
|
|
94
|
+
}
|
|
95
|
+
/* ---------------------------------------------------------------- */
|
|
96
|
+
/* The three constructors — the only place a brand is asserted */
|
|
97
|
+
/* ---------------------------------------------------------------- */
|
|
98
|
+
/**
|
|
99
|
+
* The one constructor that validates. It takes a plain `string`, so a
|
|
100
|
+
* `DeclaredService` flows straight in — a brand is still a string — which is
|
|
101
|
+
* what makes this the single bridge out of document text.
|
|
102
|
+
*
|
|
103
|
+
* The result is a discriminated pair rather than `ServiceId | string`: that
|
|
104
|
+
* second shape compiles and is unusable, because nothing can narrow it back.
|
|
105
|
+
* The problem sentence is the one `serviceIdProblem` already produces, so a
|
|
106
|
+
* caller that is collecting findings prints exactly what a refusal would.
|
|
107
|
+
*/
|
|
108
|
+
export function parseServiceId(raw, label = "--service") {
|
|
109
|
+
const problem = serviceIdProblem(raw, label);
|
|
110
|
+
if (problem !== null)
|
|
111
|
+
return { ok: false, problem };
|
|
112
|
+
// The cast, on the line immediately after the check that earns it.
|
|
113
|
+
return { ok: true, id: raw };
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The plural form, for the two commands that take a LIST of ids.
|
|
117
|
+
*
|
|
118
|
+
* It exists because `for (const id of ids) assertServiceId(id)` narrows the
|
|
119
|
+
* ELEMENT and not the array: the loop leaves `string[]`, so the value that
|
|
120
|
+
* reaches core is unbranded no matter how thoroughly each item was checked.
|
|
121
|
+
* That is invisible in review and the compiler is the only thing that sees it.
|
|
122
|
+
*
|
|
123
|
+
* Returns the offending value alongside the problem so the caller prints the
|
|
124
|
+
* same sentence, with the same code, that the element-wise loop printed.
|
|
125
|
+
*/
|
|
126
|
+
export function parseServiceIds(ids, label = "--service") {
|
|
127
|
+
const out = [];
|
|
128
|
+
for (const raw of ids) {
|
|
129
|
+
const parsed = parseServiceId(raw, label);
|
|
130
|
+
if (!parsed.ok)
|
|
131
|
+
return parsed;
|
|
132
|
+
out.push(parsed.id);
|
|
133
|
+
}
|
|
134
|
+
return { ok: true, ids: out };
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* A directory name off `readdir`. Says nothing about whether it is a legal id —
|
|
138
|
+
* that is the point, and `idProblem` is where the answer goes.
|
|
139
|
+
*
|
|
140
|
+
* This is a second cast, and it has to be: `readdir` and `basename` return plain
|
|
141
|
+
* `string`, and a brand does not survive them. What the rule in
|
|
142
|
+
* `docs/CODE-STYLE.md` actually buys is that all three casts live in THIS FILE
|
|
143
|
+
* and nowhere else. A fourth one somewhere in `src/` is a finding, not a shortcut.
|
|
144
|
+
*/
|
|
145
|
+
export function rawServiceId(dirName) {
|
|
146
|
+
return dirName;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* A name a document asserted. Third and last cast, for the crossing between
|
|
150
|
+
* LikeC4's parse output and loam's type system: `e.service ?? e.title` is a
|
|
151
|
+
* plain `string` and does not brand itself.
|
|
152
|
+
*/
|
|
153
|
+
export function declaredService(text) {
|
|
154
|
+
return text;
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../../src/core/kernel/ids/service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAyDH,uFAAuF;AACvF,MAAM,UAAU,GAAG,8BAA8B,CAAC;AAElD;;;;GAIG;AACH,MAAM,cAAc,GAAG,yCAAyC,CAAC;AAiBjE,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,4EAA4E;IAC5E,mEAAmE;IACnE,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC9E,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;IACjC,IAAI,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,CAAC;IACrF,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,CAAC;IAC5D,OAAO,IAAI,CAAC;AACd,CAAC;AAED,qFAAqF;AACrF,MAAM,eAAe,GACnB,mGAAmG;IACnG,iFAAiF,CAAC;AAEpF,2EAA2E;AAC3E,MAAM,OAAO,cAAe,SAAQ,KAAK;IAE5B,KAAK;IADhB,YACW,KAAa,EACtB,OAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;qBAHN,KAAK;QAId,IAAI,CAAC,IAAI,GAAG,gBAAgB,CAAC;IAC/B,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,EAAW,EAAE,KAAK,GAAG,WAAW;IAC/D,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACxC,OAAO,GAAG,KAAK,yBAAyB,eAAe,GAAG,CAAC;IAC7D,CAAC;IACD,MAAM,MAAM,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;IACjC,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,SAAS;YACZ,OAAO,WAAW,KAAK,KAAK,EAAE,MAAM,eAAe,GAAG,CAAC;QACzD,0EAA0E;QAC1E,sEAAsE;QACtE,kEAAkE;QAClE,KAAK,gBAAgB;YACnB,OAAO,CACL,WAAW,KAAK,KAAK,EAAE,OAAO,MAAM,CAAC,IAAI,2CAA2C;gBACpF,YAAY,EAAE,2GAA2G,CAC1H,CAAC;QACJ,KAAK,kBAAkB;YACrB,OAAO,CACL,WAAW,KAAK,KAAK,EAAE,oDAAoD;gBAC3E,sDAAsD,EAAE,UAAU,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,sEAAsE,CACjK,CAAC;IACN,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,EAAW,EAAE,KAAK,GAAG,WAAW;IAC9D,MAAM,OAAO,GAAG,gBAAgB,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC;IAC5C,IAAI,OAAO,KAAK,IAAI;QAAE,MAAM,IAAI,cAAc,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;AACpG,CAAC;AAED,sEAAsE;AACtE,uEAAuE;AACvE,sEAAsE;AAEtE;;;;;;;;;GASG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAW,EACX,KAAK,GAAG,WAAW;IAEnB,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7C,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IACpD,mEAAmE;IACnE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,GAAgB,EAAE,CAAC;AAC5C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAC7B,GAAsB,EACtB,KAAK,GAAG,WAAW;IAEnB,MAAM,GAAG,GAAgB,EAAE,CAAC;IAC5B,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;QACtB,MAAM,MAAM,GAAG,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC1C,IAAI,CAAC,MAAM,CAAC,EAAE;YAAE,OAAO,MAAM,CAAC;QAC9B,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;IACtB,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAChC,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,OAAO,OAAuB,CAAC;AACjC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,OAAO,IAAuB,CAAC;AACjC,CAAC","sourcesContent":["/**\n * The spelling rules for the ids loam turns into directory names.\n *\n * A service id is not a label: it becomes `services/<id>/` in the shared docs\n * repo, and it is interpolated into paths by adopt, validate, vouch, gherkin and\n * new. That makes it caller-controlled path input, so it is validated in exactly\n * one place — here — rather than by each command inventing its own guard. The\n * failure mode this closes is not theoretical: `--service ../../etc` would have\n * had `unfiledServicePaths()` hand a writer a directory outside the docs repo, and\n * `--service ''` would have made `services//spec.md` collapse to a file the\n * enumeration in repo.ts can never see again.\n *\n * The rule is deliberately narrower than \"a path segment that happens to work\":\n * ids are also compared, sorted and printed in tables, so shell metacharacters,\n * spaces and leading dots are refused even where the filesystem would accept\n * them. Widening the alphabet later is a compatible change; narrowing it is not.\n *\n * \"Works\" also means \"works on Windows\", which this project tests in CI: the\n * two rules below are the ones POSIX accepts and Windows does not. They used to\n * live in migrate-openspec.ts alone, as a second, stricter copy of this grammar\n * — so the PRIMARY authoring path (`--service`, `--touches`, `adopt`) accepted\n * ids the migration refused, and `services/CON/` or `services/payments./` got\n * as far as a directory nobody can create or open. Narrowing is not a\n * compatible change, which is exactly why it belongs here, once, rather than in\n * whichever command happened to think of it.\n */\n\n/* ---------------------------------------------------------------- */\n/* The three provenances a service name can have */\n/* ---------------------------------------------------------------- */\n\n/**\n * A service name is one of three things, and until now all three were `string`.\n *\n * The distinction that matters is not \"valid\" versus \"invalid\" — it is WHERE the\n * name came from, because that is what decides whether loam may join it into a\n * path. A directory name read off disk is safe to join whether or not it is a\n * legal id: it demonstrably exists, `readdir` just returned it. A name a\n * *document* asserts is not, because nothing has checked it and `metadata {\n * service '../../../etc' }` parses in LikeC4 without a single error.\n *\n * So `RawServiceId` is the base — a name whose provenance is the repository —\n * and `ServiceId` is that plus the grammar check, which makes it a SUBTYPE\n * rather than a sibling. That hierarchy is deliberate and was measured: with\n * three disjoint brands, `id === dirName`, `Set<RawServiceId>.has(id)` and\n * `[...ids, ...raws].sort()` all stop compiling, and none of them is a safety\n * question — they are the ordinary business of comparing a validated id with a\n * directory that exists. Only `DeclaredService` is disjoint, because only there\n * is the comparison a real crossing.\n *\n * `path.join` is NOT the enforcement point and cannot be made one: node types it\n * `join(...paths: string[])`, so every brand satisfies it. The guarantee lives\n * in `unfiledServicePaths`' own parameter type — `PathableService`, declared below and\n * demanded by that signature — so a `DeclaredService` at the call site is a\n * compile error, not a review finding. Code that spells `services/<svc>/` with\n * a bare join is outside the guarantee; `repo/paths.ts`'s banner names it.\n */\ndeclare const provenance: unique symbol;\ndeclare const checked: unique symbol;\n\n/**\n * A directory name read off `services/` or `features/<id>/specs/`. It exists;\n * it may still be an illegal loam id — `core/repo/repo.ts`'s `listServices`\n * deliberately returns those, reporting the failure as an `idProblem` field,\n * because `loam list` must show you the badly-named directory that is there.\n */\nexport type RawServiceId = string & { readonly [provenance]: \"loam\" };\n\n/** A name that passed `serviceIdProblem`. The only form a caller may construct. */\nexport type ServiceId = RawServiceId & { readonly [checked]: true };\n\n/**\n * A name a DOCUMENT asserts — `metadata { service '...' }` in a `.likec4` file,\n * an element title standing in for one, or an element id. Arbitrary unchecked\n * text, and disjoint from the two above on purpose: it must not reach a path\n * join without going through `parseServiceId` first.\n */\nexport type DeclaredService = string & { readonly [provenance]: \"document\" };\n\n/** What `unfiledServicePaths` accepts: a name whose provenance is the repository. */\nexport type PathableService = RawServiceId;\n\n/** The one grammar: alphanumeric head, then alphanumerics, dot, underscore, hyphen. */\nconst SERVICE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;\n\n/**\n * The MS-DOS device names Windows still reserves. Reserved with any extension\n * and in any case (`nul`, `NUL.txt`), so the test is on the stem — the part\n * before the first dot — uppercased.\n */\nconst WINDOWS_DEVICE = /^(?:CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$/;\n\n/**\n * Why `name` cannot be a directory name in the docs repo, as a discriminated\n * fact rather than a sentence. Split out of `serviceIdProblem` when subsystem\n * names arrived (`./subsystem.ts`): both kinds of name become directories in\n * the same tree and share one flat namespace, so they must share ONE grammar\n * and one set of Windows rules — a name legal as one and illegal as the other\n * would make the namespace-collision refusal incoherent. Each caller keeps its\n * own prose, because \"a service id\" and \"a subsystem name\" point the reader at\n * different fixes; the CHECKS are what may never fork.\n */\nexport type DirNameHazard =\n | { kind: \"grammar\" }\n | { kind: \"windows-device\"; stem: string }\n | { kind: \"windows-trailing\" };\n\nexport function dirNameHazard(name: string): DirNameHazard | null {\n // `..` produces the same verdict the pattern would; it is not special-cased\n // here — the CALLERS' prose is where \"no '..'\" gets its own words.\n if (name.includes(\"..\") || !SERVICE_ID.test(name)) return { kind: \"grammar\" };\n const stem = name.split(\".\")[0]!;\n if (WINDOWS_DEVICE.test(stem.toUpperCase())) return { kind: \"windows-device\", stem };\n if (/[. ]$/.test(name)) return { kind: \"windows-trailing\" };\n return null;\n}\n\n/** Prose form of the rule, shown verbatim in every refusal so the fix is obvious. */\nconst SERVICE_ID_RULE =\n \"a service id must start with a letter or digit and contain only letters, digits, '.', '_' or '-' \" +\n \"(no slashes, no '..', no spaces) — it becomes the services/<id>/ directory name\";\n\n/** Refusal carrying the offending value, so a caller can quote it back. */\nexport class InvalidIdError extends Error {\n constructor(\n readonly value: string,\n message: string,\n ) {\n super(message);\n this.name = \"InvalidIdError\";\n }\n}\n\n/**\n * Why `id` is not a usable service id, or null when it is. Returning the reason\n * instead of a boolean lets a caller that is already collecting findings report\n * the same sentence a refusal would print.\n */\nexport function serviceIdProblem(id: unknown, label = \"--service\"): string | null {\n if (typeof id !== \"string\" || id === \"\") {\n return `${label} must name a service: ${SERVICE_ID_RULE}.`;\n }\n const hazard = dirNameHazard(id);\n if (hazard === null) return null;\n switch (hazard.kind) {\n case \"grammar\":\n return `Invalid ${label} '${id}': ${SERVICE_ID_RULE}.`;\n // Both refusals below are about Windows, and both get their own sentence:\n // \"does not match the id grammar\" is true and useless, because the id\n // LOOKS fine and the problem is what the filesystem does with it.\n case \"windows-device\":\n return (\n `Invalid ${label} '${id}': '${hazard.stem}' is a reserved device name on Windows — ` +\n `services/${id}/ cannot be created there at all, so the docs repo would only work on some of the machines that clone it.`\n );\n case \"windows-trailing\":\n return (\n `Invalid ${label} '${id}': a service id may not end with '.' or a space — ` +\n `Windows strips both when creating a directory, so '${id}' and '${id.replace(/[. ]+$/, \"\")}' would silently become one directory there and two everywhere else.`\n );\n }\n}\n\n/**\n * Assert that `id` may be used as a `services/<id>/` directory name. Throws\n * InvalidIdError; commands catch it and report `invalid-option`, because a bad\n * id is always something the caller typed, never a state of the repository.\n */\nexport function assertServiceId(id: unknown, label = \"--service\"): asserts id is ServiceId {\n const problem = serviceIdProblem(id, label);\n if (problem !== null) throw new InvalidIdError(typeof id === \"string\" ? id : String(id), problem);\n}\n\n/* ---------------------------------------------------------------- */\n/* The three constructors — the only place a brand is asserted */\n/* ---------------------------------------------------------------- */\n\n/**\n * The one constructor that validates. It takes a plain `string`, so a\n * `DeclaredService` flows straight in — a brand is still a string — which is\n * what makes this the single bridge out of document text.\n *\n * The result is a discriminated pair rather than `ServiceId | string`: that\n * second shape compiles and is unusable, because nothing can narrow it back.\n * The problem sentence is the one `serviceIdProblem` already produces, so a\n * caller that is collecting findings prints exactly what a refusal would.\n */\nexport function parseServiceId(\n raw: string,\n label = \"--service\",\n): { ok: true; id: ServiceId } | { ok: false; problem: string } {\n const problem = serviceIdProblem(raw, label);\n if (problem !== null) return { ok: false, problem };\n // The cast, on the line immediately after the check that earns it.\n return { ok: true, id: raw as ServiceId };\n}\n\n/**\n * The plural form, for the two commands that take a LIST of ids.\n *\n * It exists because `for (const id of ids) assertServiceId(id)` narrows the\n * ELEMENT and not the array: the loop leaves `string[]`, so the value that\n * reaches core is unbranded no matter how thoroughly each item was checked.\n * That is invisible in review and the compiler is the only thing that sees it.\n *\n * Returns the offending value alongside the problem so the caller prints the\n * same sentence, with the same code, that the element-wise loop printed.\n */\nexport function parseServiceIds(\n ids: readonly string[],\n label = \"--service\",\n): { ok: true; ids: ServiceId[] } | { ok: false; problem: string } {\n const out: ServiceId[] = [];\n for (const raw of ids) {\n const parsed = parseServiceId(raw, label);\n if (!parsed.ok) return parsed;\n out.push(parsed.id);\n }\n return { ok: true, ids: out };\n}\n\n/**\n * A directory name off `readdir`. Says nothing about whether it is a legal id —\n * that is the point, and `idProblem` is where the answer goes.\n *\n * This is a second cast, and it has to be: `readdir` and `basename` return plain\n * `string`, and a brand does not survive them. What the rule in\n * `docs/CODE-STYLE.md` actually buys is that all three casts live in THIS FILE\n * and nowhere else. A fourth one somewhere in `src/` is a finding, not a shortcut.\n */\nexport function rawServiceId(dirName: string): RawServiceId {\n return dirName as RawServiceId;\n}\n\n/**\n * A name a document asserted. Third and last cast, for the crossing between\n * LikeC4's parse output and loam's type system: `e.service ?? e.title` is a\n * plain `string` and does not brand itself.\n */\nexport function declaredService(text: string): DeclaredService {\n return text as DeclaredService;\n}\n"]}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The spelling rule for subsystem names — the directories that GROUP services
|
|
3
|
+
* under `services/`, marked by a `subsystem.yaml` (the walk that classifies
|
|
4
|
+
* them lives in `core/repo/tree/`).
|
|
5
|
+
*
|
|
6
|
+
* A subsystem name takes the service-id grammar and the same Windows rules,
|
|
7
|
+
* through the shared `dirNameHazard` in `./service.ts`, because both kinds of
|
|
8
|
+
* name become directory names in the same tree and share ONE flat namespace —
|
|
9
|
+
* unique across the whole tree at any depth, services and subsystems together.
|
|
10
|
+
* If the two grammars could drift, a name legal as one and illegal as the
|
|
11
|
+
* other would make the namespace-collision refusal incoherent.
|
|
12
|
+
*
|
|
13
|
+
* The BRAND is distinct on purpose, and deliberately not a subtype of
|
|
14
|
+
* `ServiceId`: a subsystem is a place services live, never a thing a `--service`
|
|
15
|
+
* flag may name or a path a spec's frontmatter may claim — `--into <name>` and
|
|
16
|
+
* `--service <id>` must not be satisfiable by each other's values. Placement is
|
|
17
|
+
* never part of any identity, and the type system is where that stops being a
|
|
18
|
+
* review comment — `repo/paths.ts`'s `subsystemPathUnder` is the consumer that
|
|
19
|
+
* DEMANDS the brand, so the joins `subsystem new` and `rename` build cannot be
|
|
20
|
+
* fed a raw argv string: a brand no signature requires is a validator with
|
|
21
|
+
* good intentions, which is exactly what this one briefly was.
|
|
22
|
+
*/
|
|
23
|
+
import { dirNameHazard } from "./service.js";
|
|
24
|
+
/** Prose form of the rule, shown verbatim in every refusal so the fix is obvious. */
|
|
25
|
+
const SUBSYSTEM_NAME_RULE = "a subsystem name must start with a letter or digit and contain only letters, digits, '.', '_' or '-' " +
|
|
26
|
+
"(no slashes, no '..', no spaces) — it becomes a directory name under services/";
|
|
27
|
+
/**
|
|
28
|
+
* Why `name` is not a usable subsystem name, or null when it is. The same
|
|
29
|
+
* shape as `serviceIdProblem`, for the same reason: the tree walk reports the
|
|
30
|
+
* sentence as a finding (`subsystem.name-invalid`) while a command refusal
|
|
31
|
+
* prints it verbatim, and the two must not disagree.
|
|
32
|
+
*/
|
|
33
|
+
export function subsystemNameProblem(name, label = "subsystem name") {
|
|
34
|
+
if (typeof name !== "string" || name === "") {
|
|
35
|
+
return `${label} must name a subsystem: ${SUBSYSTEM_NAME_RULE}.`;
|
|
36
|
+
}
|
|
37
|
+
const hazard = dirNameHazard(name);
|
|
38
|
+
if (hazard === null)
|
|
39
|
+
return null;
|
|
40
|
+
switch (hazard.kind) {
|
|
41
|
+
case "grammar":
|
|
42
|
+
return `Invalid ${label} '${name}': ${SUBSYSTEM_NAME_RULE}.`;
|
|
43
|
+
case "windows-device":
|
|
44
|
+
return (`Invalid ${label} '${name}': '${hazard.stem}' is a reserved device name on Windows — ` +
|
|
45
|
+
`a '${name}/' directory cannot be created there at all, so the docs repo would only work on some of the machines that clone it.`);
|
|
46
|
+
case "windows-trailing":
|
|
47
|
+
return (`Invalid ${label} '${name}': a subsystem name may not end with '.' or a space — ` +
|
|
48
|
+
`Windows strips both when creating a directory, so '${name}' and '${name.replace(/[. ]+$/, "")}' would silently become one directory there and two everywhere else.`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* The one constructor that validates. Discriminated pair rather than
|
|
53
|
+
* `SubsystemName | string` for `parseServiceId`'s reason: the union shape
|
|
54
|
+
* compiles and is unusable, because nothing can narrow it back.
|
|
55
|
+
*/
|
|
56
|
+
export function parseSubsystemName(raw, label = "subsystem name") {
|
|
57
|
+
const problem = subsystemNameProblem(raw, label);
|
|
58
|
+
if (problem !== null)
|
|
59
|
+
return { ok: false, problem };
|
|
60
|
+
// The cast, on the line immediately after the check that earns it.
|
|
61
|
+
return { ok: true, name: raw };
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=subsystem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subsystem.js","sourceRoot":"","sources":["../../../../src/core/kernel/ids/subsystem.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAO7C,qFAAqF;AACrF,MAAM,mBAAmB,GACvB,uGAAuG;IACvG,gFAAgF,CAAC;AAEnF;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,IAAa,EAAE,KAAK,GAAG,gBAAgB;IAC1E,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAC5C,OAAO,GAAG,KAAK,2BAA2B,mBAAmB,GAAG,CAAC;IACnE,CAAC;IACD,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,SAAS;YACZ,OAAO,WAAW,KAAK,KAAK,IAAI,MAAM,mBAAmB,GAAG,CAAC;QAC/D,KAAK,gBAAgB;YACnB,OAAO,CACL,WAAW,KAAK,KAAK,IAAI,OAAO,MAAM,CAAC,IAAI,2CAA2C;gBACtF,MAAM,IAAI,sHAAsH,CACjI,CAAC;QACJ,KAAK,kBAAkB;YACrB,OAAO,CACL,WAAW,KAAK,KAAK,IAAI,wDAAwD;gBACjF,sDAAsD,IAAI,UAAU,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,sEAAsE,CACrK,CAAC;IACN,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,GAAW,EACX,KAAK,GAAG,gBAAgB;IAExB,MAAM,OAAO,GAAG,oBAAoB,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACjD,IAAI,OAAO,KAAK,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IACpD,mEAAmE;IACnE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,GAAoB,EAAE,CAAC;AAClD,CAAC","sourcesContent":["/**\n * The spelling rule for subsystem names — the directories that GROUP services\n * under `services/`, marked by a `subsystem.yaml` (the walk that classifies\n * them lives in `core/repo/tree/`).\n *\n * A subsystem name takes the service-id grammar and the same Windows rules,\n * through the shared `dirNameHazard` in `./service.ts`, because both kinds of\n * name become directory names in the same tree and share ONE flat namespace —\n * unique across the whole tree at any depth, services and subsystems together.\n * If the two grammars could drift, a name legal as one and illegal as the\n * other would make the namespace-collision refusal incoherent.\n *\n * The BRAND is distinct on purpose, and deliberately not a subtype of\n * `ServiceId`: a subsystem is a place services live, never a thing a `--service`\n * flag may name or a path a spec's frontmatter may claim — `--into <name>` and\n * `--service <id>` must not be satisfiable by each other's values. Placement is\n * never part of any identity, and the type system is where that stops being a\n * review comment — `repo/paths.ts`'s `subsystemPathUnder` is the consumer that\n * DEMANDS the brand, so the joins `subsystem new` and `rename` build cannot be\n * fed a raw argv string: a brand no signature requires is a validator with\n * good intentions, which is exactly what this one briefly was.\n */\nimport { dirNameHazard } from \"./service.js\";\n\ndeclare const checked: unique symbol;\n\n/** A name that passed `subsystemNameProblem`. The only form a caller may construct. */\nexport type SubsystemName = string & { readonly [checked]: \"subsystem\" };\n\n/** Prose form of the rule, shown verbatim in every refusal so the fix is obvious. */\nconst SUBSYSTEM_NAME_RULE =\n \"a subsystem name must start with a letter or digit and contain only letters, digits, '.', '_' or '-' \" +\n \"(no slashes, no '..', no spaces) — it becomes a directory name under services/\";\n\n/**\n * Why `name` is not a usable subsystem name, or null when it is. The same\n * shape as `serviceIdProblem`, for the same reason: the tree walk reports the\n * sentence as a finding (`subsystem.name-invalid`) while a command refusal\n * prints it verbatim, and the two must not disagree.\n */\nexport function subsystemNameProblem(name: unknown, label = \"subsystem name\"): string | null {\n if (typeof name !== \"string\" || name === \"\") {\n return `${label} must name a subsystem: ${SUBSYSTEM_NAME_RULE}.`;\n }\n const hazard = dirNameHazard(name);\n if (hazard === null) return null;\n switch (hazard.kind) {\n case \"grammar\":\n return `Invalid ${label} '${name}': ${SUBSYSTEM_NAME_RULE}.`;\n case \"windows-device\":\n return (\n `Invalid ${label} '${name}': '${hazard.stem}' is a reserved device name on Windows — ` +\n `a '${name}/' directory cannot be created there at all, so the docs repo would only work on some of the machines that clone it.`\n );\n case \"windows-trailing\":\n return (\n `Invalid ${label} '${name}': a subsystem name may not end with '.' or a space — ` +\n `Windows strips both when creating a directory, so '${name}' and '${name.replace(/[. ]+$/, \"\")}' would silently become one directory there and two everywhere else.`\n );\n }\n}\n\n/**\n * The one constructor that validates. Discriminated pair rather than\n * `SubsystemName | string` for `parseServiceId`'s reason: the union shape\n * compiles and is unusable, because nothing can narrow it back.\n */\nexport function parseSubsystemName(\n raw: string,\n label = \"subsystem name\",\n): { ok: true; name: SubsystemName } | { ok: false; problem: string } {\n const problem = subsystemNameProblem(raw, label);\n if (problem !== null) return { ok: false, problem };\n // The cast, on the line immediately after the check that earns it.\n return { ok: true, name: raw as SubsystemName };\n}\n"]}
|