@ybotok/loam 0.1.0-beta.3 → 0.2.0-alpha.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5992 -82
- package/COMPARISON.md +168 -63
- package/CONTRIBUTING.md +121 -0
- package/MIGRATING-from-OpenSpec.md +238 -55
- package/QUICKSTART.md +302 -0
- package/README.md +653 -144
- package/ROADMAP.md +1035 -0
- package/SCHEMA.md +3916 -263
- package/SECURITY.md +21 -3
- package/WORKFLOW.md +927 -0
- package/dist/cli.js +133 -21
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +204 -0
- package/dist/commands/adopt/adopt.js.map +1 -0
- package/dist/commands/adopt/render.js +309 -0
- package/dist/commands/adopt/render.js.map +1 -0
- package/dist/commands/archive/archive.js +74 -0
- package/dist/commands/archive/archive.js.map +1 -0
- package/dist/commands/archive/closing.js +42 -0
- package/dist/commands/archive/closing.js.map +1 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js +172 -0
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/consumers.js +56 -0
- package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +193 -0
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js +103 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
- package/dist/commands/archive/plan/document/head.js +151 -0
- package/dist/commands/archive/plan/document/head.js.map +1 -0
- package/dist/commands/archive/plan/document/links.js +284 -0
- package/dist/commands/archive/plan/document/links.js.map +1 -0
- package/dist/commands/archive/plan/document/run.js +136 -0
- package/dist/commands/archive/plan/document/run.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +319 -0
- package/dist/commands/archive/plan/gate.js.map +1 -0
- package/dist/commands/archive/plan/landscape.js +298 -0
- package/dist/commands/archive/plan/landscape.js.map +1 -0
- package/dist/commands/archive/plan/model/extending.js +85 -0
- package/dist/commands/archive/plan/model/extending.js.map +1 -0
- package/dist/commands/archive/plan/refusal.js +106 -0
- package/dist/commands/archive/plan/refusal.js.map +1 -0
- package/dist/commands/archive/plan/specs.js +318 -0
- package/dist/commands/archive/plan/specs.js.map +1 -0
- package/dist/commands/archive/plan/state.js +30 -0
- package/dist/commands/archive/plan/state.js.map +1 -0
- package/dist/commands/archive/run.js +355 -0
- package/dist/commands/archive/run.js.map +1 -0
- package/dist/commands/archive/shipped.js +49 -0
- package/dist/commands/archive/shipped.js.map +1 -0
- package/dist/commands/context/context.js +166 -0
- package/dist/commands/context/context.js.map +1 -0
- package/dist/commands/context/print.js +305 -0
- package/dist/commands/context/print.js.map +1 -0
- package/dist/commands/delta/delta.js +367 -0
- package/dist/commands/delta/delta.js.map +1 -0
- package/dist/commands/delta/print.js +221 -0
- package/dist/commands/delta/print.js.map +1 -0
- package/dist/commands/dependencies.js +6 -8
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +86 -0
- package/dist/commands/diff/diff.js.map +1 -0
- package/dist/commands/diff/print.js +38 -0
- package/dist/commands/diff/print.js.map +1 -0
- package/dist/commands/doctor.js +65 -5
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/explain/explain.js +227 -0
- package/dist/commands/explain/explain.js.map +1 -0
- package/dist/commands/explore.js +39 -28
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +152 -0
- package/dist/commands/gate/gate.js.map +1 -0
- package/dist/commands/gate/print.js +66 -0
- package/dist/commands/gate/print.js.map +1 -0
- package/dist/commands/gherkin/commit.js +105 -0
- package/dist/commands/gherkin/commit.js.map +1 -0
- package/dist/commands/gherkin/gherkin.js +262 -0
- package/dist/commands/gherkin/gherkin.js.map +1 -0
- package/dist/commands/gherkin/reconcile.js +146 -0
- package/dist/commands/gherkin/reconcile.js.map +1 -0
- package/dist/commands/gherkin/render.js +77 -0
- package/dist/commands/gherkin/render.js.map +1 -0
- package/dist/commands/init/example.js +204 -0
- package/dist/commands/init/example.js.map +1 -0
- package/dist/commands/init/first-hour.js +72 -0
- package/dist/commands/init/first-hour.js.map +1 -0
- package/dist/commands/{init.js → init/init.js} +142 -71
- package/dist/commands/init/init.js.map +1 -0
- package/dist/commands/init/mcp.js +131 -0
- package/dist/commands/init/mcp.js.map +1 -0
- package/dist/commands/init/options.js +78 -0
- package/dist/commands/init/options.js.map +1 -0
- package/dist/commands/instructions.js +72 -14
- package/dist/commands/instructions.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +63 -0
- package/dist/commands/list/campaign/campaign.js.map +1 -0
- package/dist/commands/list/campaign/owners.js +65 -0
- package/dist/commands/list/campaign/owners.js.map +1 -0
- package/dist/commands/list/json.js +155 -0
- package/dist/commands/list/json.js.map +1 -0
- package/dist/commands/list/list.js +358 -0
- package/dist/commands/list/list.js.map +1 -0
- package/dist/commands/list/print.js +344 -0
- package/dist/commands/list/print.js.map +1 -0
- package/dist/commands/list/review.js +120 -0
- package/dist/commands/list/review.js.map +1 -0
- package/dist/commands/list/suites/suites.js +140 -0
- package/dist/commands/list/suites/suites.js.map +1 -0
- package/dist/commands/list/views.js +108 -0
- package/dist/commands/list/views.js.map +1 -0
- package/dist/commands/mcp/dispatch.js +238 -0
- package/dist/commands/mcp/dispatch.js.map +1 -0
- package/dist/commands/mcp/mcp.js +75 -0
- package/dist/commands/mcp/mcp.js.map +1 -0
- package/dist/commands/mcp/serve.js +55 -0
- package/dist/commands/mcp/serve.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/active.js +175 -0
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/feature.js +41 -0
- package/dist/commands/migrate-openspec/materialize/feature.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/living.js +62 -0
- package/dist/commands/migrate-openspec/materialize/living.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/stage.js +143 -0
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -0
- package/dist/commands/migrate-openspec/materialize/target.js +219 -0
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js +142 -0
- package/dist/commands/migrate-openspec/migrate-openspec.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js +86 -0
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/error.js +18 -0
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js +162 -0
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/paths.js +40 -0
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -0
- package/dist/commands/migrate-openspec/openspec/read.js +49 -0
- package/dist/commands/migrate-openspec/openspec/read.js.map +1 -0
- package/dist/commands/migrate-openspec/print.js +89 -0
- package/dist/commands/migrate-openspec/print.js.map +1 -0
- package/dist/commands/new/capability-template.js +118 -0
- package/dist/commands/new/capability-template.js.map +1 -0
- package/dist/commands/new/commit.js +62 -0
- package/dist/commands/new/commit.js.map +1 -0
- package/dist/commands/new/modifies.js +206 -0
- package/dist/commands/new/modifies.js.map +1 -0
- package/dist/commands/new/new.js +328 -0
- package/dist/commands/new/new.js.map +1 -0
- package/dist/commands/new/templates.js +279 -0
- package/dist/commands/new/templates.js.map +1 -0
- package/dist/commands/open.js +199 -0
- package/dist/commands/open.js.map +1 -0
- package/dist/commands/policy/format.js +152 -0
- package/dist/commands/policy/format.js.map +1 -0
- package/dist/commands/{docs-repo-gate.js → policy/gate.js} +38 -11
- package/dist/commands/policy/gate.js.map +1 -0
- package/dist/commands/rebase/edit.js +106 -0
- package/dist/commands/rebase/edit.js.map +1 -0
- package/dist/commands/rebase/living.js +185 -0
- package/dist/commands/rebase/living.js.map +1 -0
- package/dist/commands/rebase/plan.js +245 -0
- package/dist/commands/rebase/plan.js.map +1 -0
- package/dist/commands/rebase/rebase.js +300 -0
- package/dist/commands/rebase/rebase.js.map +1 -0
- package/dist/commands/seed/commit.js +221 -0
- package/dist/commands/seed/commit.js.map +1 -0
- package/dist/commands/seed/plan.js +278 -0
- package/dist/commands/seed/plan.js.map +1 -0
- package/dist/commands/seed/seed.js +174 -0
- package/dist/commands/seed/seed.js.map +1 -0
- package/dist/commands/show/feature.js +182 -0
- package/dist/commands/show/feature.js.map +1 -0
- package/dist/commands/show/introduced.js +157 -0
- package/dist/commands/show/introduced.js.map +1 -0
- package/dist/commands/show/marks.js +53 -0
- package/dist/commands/show/marks.js.map +1 -0
- package/dist/commands/show/service.js +239 -0
- package/dist/commands/show/service.js.map +1 -0
- package/dist/commands/show/show.js +87 -0
- package/dist/commands/show/show.js.map +1 -0
- package/dist/commands/status/fleet-next.js +90 -0
- package/dist/commands/status/fleet-next.js.map +1 -0
- package/dist/commands/status/json.js +47 -0
- package/dist/commands/status/json.js.map +1 -0
- package/dist/commands/status/print.js +209 -0
- package/dist/commands/status/print.js.map +1 -0
- package/dist/commands/status/status.js +115 -0
- package/dist/commands/status/status.js.map +1 -0
- package/dist/commands/steps/steps.js +269 -0
- package/dist/commands/steps/steps.js.map +1 -0
- package/dist/commands/subsystem/edit.js +192 -0
- package/dist/commands/subsystem/edit.js.map +1 -0
- package/dist/commands/subsystem/move.js +325 -0
- package/dist/commands/subsystem/move.js.map +1 -0
- package/dist/commands/subsystem/query.js +113 -0
- package/dist/commands/subsystem/query.js.map +1 -0
- package/dist/commands/subsystem/subsystem.js +98 -0
- package/dist/commands/subsystem/subsystem.js.map +1 -0
- package/dist/commands/subsystem/sync.js +318 -0
- package/dist/commands/subsystem/sync.js.map +1 -0
- package/dist/commands/subsystem/txn/exclude.js +132 -0
- package/dist/commands/subsystem/txn/exclude.js.map +1 -0
- package/dist/commands/subsystem/txn/links.js +128 -0
- package/dist/commands/subsystem/txn/links.js.map +1 -0
- package/dist/commands/subsystem/txn/report.js +174 -0
- package/dist/commands/subsystem/txn/report.js.map +1 -0
- package/dist/commands/subsystem/txn/txn.js +196 -0
- package/dist/commands/subsystem/txn/txn.js.map +1 -0
- package/dist/commands/subsystem/txn/views.js +249 -0
- package/dist/commands/subsystem/txn/views.js.map +1 -0
- package/dist/commands/tasks/actions.js +107 -0
- package/dist/commands/tasks/actions.js.map +1 -0
- package/dist/commands/tasks/render.js +253 -0
- package/dist/commands/tasks/render.js.map +1 -0
- package/dist/commands/tasks/tasks.js +119 -0
- package/dist/commands/tasks/tasks.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +176 -0
- package/dist/commands/unarchive/manifest.js.map +1 -0
- package/dist/commands/unarchive/restore.js +254 -0
- package/dist/commands/unarchive/restore.js.map +1 -0
- package/dist/commands/unarchive/unarchive.js +59 -0
- package/dist/commands/unarchive/unarchive.js.map +1 -0
- package/dist/commands/validate/arch-coverage.js +245 -0
- package/dist/commands/validate/arch-coverage.js.map +1 -0
- package/dist/commands/validate/checks/fleet-shape.js +204 -0
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -0
- package/dist/commands/validate/checks/health-deps.js +58 -0
- package/dist/commands/validate/checks/health-deps.js.map +1 -0
- package/dist/commands/validate/checks/introduced.js +102 -0
- package/dist/commands/validate/checks/introduced.js.map +1 -0
- package/dist/commands/validate/checks/requirements.js +264 -0
- package/dist/commands/validate/checks/requirements.js.map +1 -0
- package/dist/commands/validate/checks/sources.js +85 -0
- package/dist/commands/validate/checks/sources.js.map +1 -0
- package/dist/commands/validate/coverage/covers-after.js +105 -0
- package/dist/commands/validate/coverage/covers-after.js.map +1 -0
- package/dist/commands/validate/feature.js +222 -0
- package/dist/commands/validate/feature.js.map +1 -0
- package/dist/commands/validate/fleet/census.js +93 -0
- package/dist/commands/validate/fleet/census.js.map +1 -0
- package/dist/commands/validate/fleet/kind-tags.js +39 -0
- package/dist/commands/validate/fleet/kind-tags.js.map +1 -0
- package/dist/commands/validate/fleet/landscape.js +371 -0
- package/dist/commands/validate/fleet/landscape.js.map +1 -0
- package/dist/commands/validate/fleet/load.js +118 -0
- package/dist/commands/validate/fleet/load.js.map +1 -0
- package/dist/commands/validate/fleet/map/attest.js +98 -0
- package/dist/commands/validate/fleet/map/attest.js.map +1 -0
- package/dist/commands/validate/fleet/map/bindings.js +107 -0
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -0
- package/dist/commands/validate/fleet/map/consumers.js +244 -0
- package/dist/commands/validate/fleet/map/consumers.js.map +1 -0
- package/dist/commands/validate/fleet/map/isolation.js +116 -0
- package/dist/commands/validate/fleet/map/isolation.js.map +1 -0
- package/dist/commands/validate/fleet/map/usecases.js +54 -0
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -0
- package/dist/commands/validate/fleet/obligations.js +266 -0
- package/dist/commands/validate/fleet/obligations.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js +102 -0
- package/dist/commands/validate/fleet/scorecard/adoption.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js +98 -0
- package/dist/commands/validate/fleet/scorecard/contracts.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/print.js +71 -0
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js +162 -0
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -0
- package/dist/commands/validate/fleet/usecases/place.js +13 -0
- package/dist/commands/validate/fleet/usecases/place.js.map +1 -0
- package/dist/commands/validate/fleet/views/fleet-project.js +217 -0
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -0
- package/dist/commands/validate/fleet/views/ids.js +75 -0
- package/dist/commands/validate/fleet/views/ids.js.map +1 -0
- package/dist/commands/validate/fleet/views/projects.js +278 -0
- package/dist/commands/validate/fleet/views/projects.js.map +1 -0
- package/dist/commands/validate/fleet/views/root-documents.js +83 -0
- package/dist/commands/validate/fleet/views/root-documents.js.map +1 -0
- package/dist/commands/validate/fleet/views/stale.js +52 -0
- package/dist/commands/validate/fleet/views/stale.js.map +1 -0
- package/dist/commands/validate/links/corpus.js +89 -0
- package/dist/commands/validate/links/corpus.js.map +1 -0
- package/dist/commands/validate/links/glossary.js +75 -0
- package/dist/commands/validate/links/glossary.js.map +1 -0
- package/dist/commands/validate/render/repeats.js +63 -0
- package/dist/commands/validate/render/repeats.js.map +1 -0
- package/dist/commands/validate/render/rollups.js +115 -0
- package/dist/commands/validate/render/rollups.js.map +1 -0
- package/dist/commands/validate/render/text.js +199 -0
- package/dist/commands/validate/render/text.js.map +1 -0
- package/dist/commands/validate/report.js +145 -0
- package/dist/commands/validate/report.js.map +1 -0
- package/dist/commands/validate/scope.js +113 -0
- package/dist/commands/validate/scope.js.map +1 -0
- package/dist/commands/validate/service/api.js +252 -0
- package/dist/commands/validate/service/api.js.map +1 -0
- package/dist/commands/validate/service/contracts/generated.js +134 -0
- package/dist/commands/validate/service/contracts/generated.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +241 -0
- package/dist/commands/validate/service/events/events.js.map +1 -0
- package/dist/commands/validate/service/events/message-producers.js +77 -0
- package/dist/commands/validate/service/events/message-producers.js.map +1 -0
- package/dist/commands/validate/service/evidence-pins.js +177 -0
- package/dist/commands/validate/service/evidence-pins.js.map +1 -0
- package/dist/commands/validate/service/model/diverged.js +226 -0
- package/dist/commands/validate/service/model/diverged.js.map +1 -0
- package/dist/commands/validate/service/model/grade.js +163 -0
- package/dist/commands/validate/service/model/grade.js.map +1 -0
- package/dist/commands/validate/service/service.js +310 -0
- package/dist/commands/validate/service/service.js.map +1 -0
- package/dist/commands/validate/service/specs.js +279 -0
- package/dist/commands/validate/service/specs.js.map +1 -0
- package/dist/commands/validate/service/spine.js +148 -0
- package/dist/commands/validate/service/spine.js.map +1 -0
- package/dist/commands/validate/service/usecases/tags.js +113 -0
- package/dist/commands/validate/service/usecases/tags.js.map +1 -0
- package/dist/commands/validate/service/usecases/usecases.js +209 -0
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -0
- package/dist/commands/validate/validate.js +363 -0
- package/dist/commands/validate/validate.js.map +1 -0
- package/dist/commands/verify/cross/diff.js +178 -0
- package/dist/commands/verify/cross/diff.js.map +1 -0
- package/dist/commands/verify/evidence/contract.js +32 -0
- package/dist/commands/verify/evidence/contract.js.map +1 -0
- package/dist/commands/verify/evidence/pins.js +52 -0
- package/dist/commands/verify/evidence/pins.js.map +1 -0
- package/dist/commands/verify/evidence/read.js +81 -0
- package/dist/commands/verify/evidence/read.js.map +1 -0
- package/dist/commands/verify/frozen.js +263 -0
- package/dist/commands/verify/frozen.js.map +1 -0
- package/dist/commands/verify/record.js +278 -0
- package/dist/commands/verify/record.js.map +1 -0
- package/dist/commands/verify/report.js +206 -0
- package/dist/commands/verify/report.js.map +1 -0
- package/dist/commands/verify/results.js +328 -0
- package/dist/commands/verify/results.js.map +1 -0
- package/dist/commands/verify/verify.js +220 -0
- package/dist/commands/verify/verify.js.map +1 -0
- package/dist/commands/vouch/contract.js +11 -0
- package/dist/commands/vouch/contract.js.map +1 -0
- package/dist/commands/vouch/pack/contract.js +2 -0
- package/dist/commands/vouch/pack/contract.js.map +1 -0
- package/dist/commands/vouch/pack/pack.js +266 -0
- package/dist/commands/vouch/pack/pack.js.map +1 -0
- package/dist/commands/vouch/pack/print.js +266 -0
- package/dist/commands/vouch/pack/print.js.map +1 -0
- package/dist/commands/vouch/pack/sections.js +141 -0
- package/dist/commands/vouch/pack/sections.js.map +1 -0
- package/dist/commands/vouch/prompt/confirm.js +46 -0
- package/dist/commands/vouch/prompt/confirm.js.map +1 -0
- package/dist/commands/vouch/report.js +101 -0
- package/dist/commands/vouch/report.js.map +1 -0
- package/dist/commands/vouch/run.js +230 -0
- package/dist/commands/vouch/run.js.map +1 -0
- package/dist/commands/vouch/sample/plan.js +111 -0
- package/dist/commands/vouch/sample/plan.js.map +1 -0
- package/dist/commands/vouch/sample/print.js +109 -0
- package/dist/commands/vouch/sample/print.js.map +1 -0
- package/dist/commands/vouch/vet/verify.js +155 -0
- package/dist/commands/vouch/vet/verify.js.map +1 -0
- package/dist/commands/vouch/vouch.js +169 -0
- package/dist/commands/vouch/vouch.js.map +1 -0
- package/dist/core/agent/agents-md/command-map.js +299 -0
- package/dist/core/agent/agents-md/command-map.js.map +1 -0
- package/dist/core/agent/agents-md/map/explain.js +46 -0
- package/dist/core/agent/agents-md/map/explain.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/context.js +50 -0
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js +59 -0
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js +65 -0
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -0
- package/dist/core/agent/agents-md/map/mcp.js +44 -0
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -0
- package/dist/core/agent/agents-md/map/status.js +78 -0
- package/dist/core/agent/agents-md/map/status.js.map +1 -0
- package/dist/core/agent/agents-md/map/subsystem.js +104 -0
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -0
- package/dist/core/agent/agents-md/map/usecases.js +138 -0
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -0
- package/dist/core/agent/agents-md/refusals.js +273 -0
- package/dist/core/agent/agents-md/refusals.js.map +1 -0
- package/dist/core/agent/agents-md.js +203 -0
- package/dist/core/agent/agents-md.js.map +1 -0
- package/dist/core/{agents-stamp.js → agent/agents-stamp.js} +60 -0
- package/dist/core/agent/agents-stamp.js.map +1 -0
- package/dist/core/agent/contract.js +2 -0
- package/dist/core/agent/contract.js.map +1 -0
- package/dist/core/agent/protocol.js +193 -0
- package/dist/core/agent/protocol.js.map +1 -0
- package/dist/core/agent/scaffold.js +254 -0
- package/dist/core/agent/scaffold.js.map +1 -0
- package/dist/core/agent/support/report.js +144 -0
- package/dist/core/agent/support/report.js.map +1 -0
- package/dist/core/agent/tools/dialects.js +151 -0
- package/dist/core/agent/tools/dialects.js.map +1 -0
- package/dist/core/agent/tools/registry.js +193 -0
- package/dist/core/agent/tools/registry.js.map +1 -0
- package/dist/core/agent/workflows/adopt.js +280 -0
- package/dist/core/agent/workflows/adopt.js.map +1 -0
- package/dist/core/agent/workflows/check.js +373 -0
- package/dist/core/agent/workflows/check.js.map +1 -0
- package/dist/core/agent/workflows/closing.js +323 -0
- package/dist/core/agent/workflows/closing.js.map +1 -0
- package/dist/core/agent/workflows/feature.js +220 -0
- package/dist/core/agent/workflows/feature.js.map +1 -0
- package/dist/core/agent/workflows/implement.js +188 -0
- package/dist/core/agent/workflows/implement.js.map +1 -0
- package/dist/core/agent/workflows/reference/authoring.js +311 -0
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -0
- package/dist/core/agent/workflows/reference/codes.js +67 -0
- package/dist/core/agent/workflows/reference/codes.js.map +1 -0
- package/dist/core/agent/workflows/reference/done-check.js +210 -0
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js +253 -0
- package/dist/core/agent/workflows/reference/drawing/drawing.js.map +1 -0
- package/dist/core/agent/workflows/reference/reference.js +19 -0
- package/dist/core/agent/workflows/reference/reference.js.map +1 -0
- package/dist/core/agent/workflows/reference/spine.js +338 -0
- package/dist/core/agent/workflows/reference/spine.js.map +1 -0
- package/dist/core/asyncapi/baseline/plan.js +43 -0
- package/dist/core/asyncapi/baseline/plan.js.map +1 -0
- package/dist/core/asyncapi/baseline/surfaces.js +54 -0
- package/dist/core/asyncapi/baseline/surfaces.js.map +1 -0
- package/dist/core/asyncapi/depth.js +164 -0
- package/dist/core/asyncapi/depth.js.map +1 -0
- package/dist/core/asyncapi/digest.js +146 -0
- package/dist/core/asyncapi/digest.js.map +1 -0
- package/dist/core/asyncapi/merge/components.js +92 -0
- package/dist/core/asyncapi/merge/components.js.map +1 -0
- package/dist/core/asyncapi/merge/error.js +38 -0
- package/dist/core/asyncapi/merge/error.js.map +1 -0
- package/dist/core/asyncapi/merge/markers.js +290 -0
- package/dist/core/asyncapi/merge/markers.js.map +1 -0
- package/dist/core/asyncapi/merge/merge.js +195 -0
- package/dist/core/asyncapi/merge/merge.js.map +1 -0
- package/dist/core/asyncapi/merge/pin.js +83 -0
- package/dist/core/asyncapi/merge/pin.js.map +1 -0
- package/dist/core/asyncapi/model.js +11 -0
- package/dist/core/asyncapi/model.js.map +1 -0
- package/dist/core/asyncapi/producers.js +50 -0
- package/dist/core/asyncapi/producers.js.map +1 -0
- package/dist/core/asyncapi/read.js +263 -0
- package/dist/core/asyncapi/read.js.map +1 -0
- package/dist/core/brief/brief.js +285 -0
- package/dist/core/brief/brief.js.map +1 -0
- package/dist/core/brief/checks.js +385 -0
- package/dist/core/brief/checks.js.map +1 -0
- package/dist/core/brief/landscape.js +273 -0
- package/dist/core/brief/landscape.js.map +1 -0
- package/dist/core/brief/map/extend.js +84 -0
- package/dist/core/brief/map/extend.js.map +1 -0
- package/dist/core/brief/map/owed.js +266 -0
- package/dist/core/brief/map/owed.js.map +1 -0
- package/dist/core/brief/targets.js +304 -0
- package/dist/core/brief/targets.js.map +1 -0
- package/dist/core/brief/unchecked.js +58 -0
- package/dist/core/brief/unchecked.js.map +1 -0
- package/dist/core/c4/arch.js +190 -0
- package/dist/core/c4/arch.js.map +1 -0
- package/dist/core/c4/direction/direction.js +114 -0
- package/dist/core/c4/direction/direction.js.map +1 -0
- package/dist/core/c4/likec4.js +243 -0
- package/dist/core/c4/likec4.js.map +1 -0
- package/dist/core/c4/locate/unlocated.js +150 -0
- package/dist/core/c4/locate/unlocated.js.map +1 -0
- package/dist/core/c4/parsed/deployment.js +160 -0
- package/dist/core/c4/parsed/deployment.js.map +1 -0
- package/dist/core/c4/parsed/dynamic-views.js +132 -0
- package/dist/core/c4/parsed/dynamic-views.js.map +1 -0
- package/dist/core/c4/parsed/specification.js +78 -0
- package/dist/core/c4/parsed/specification.js.map +1 -0
- package/dist/core/c4/parsed/values.js +110 -0
- package/dist/core/c4/parsed/values.js.map +1 -0
- package/dist/core/c4/parsed/view-ids.js +113 -0
- package/dist/core/c4/parsed/view-ids.js.map +1 -0
- package/dist/core/c4/prefetch/fleet.js +134 -0
- package/dist/core/c4/prefetch/fleet.js.map +1 -0
- package/dist/core/c4/project/architecture.js +161 -0
- package/dist/core/c4/project/architecture.js.map +1 -0
- package/dist/core/c4/project/batch.js +140 -0
- package/dist/core/c4/project/batch.js.map +1 -0
- package/dist/core/c4/project/documents.js +89 -0
- package/dist/core/c4/project/documents.js.map +1 -0
- package/dist/core/c4/project/load.js +219 -0
- package/dist/core/c4/project/load.js.map +1 -0
- package/dist/core/c4/project/staged.js +277 -0
- package/dist/core/c4/project/staged.js.map +1 -0
- package/dist/core/c4/resolve/attested.js +0 -0
- package/dist/core/c4/resolve/attested.js.map +1 -0
- package/dist/core/c4/resolve/external.js +51 -0
- package/dist/core/c4/resolve/external.js.map +1 -0
- package/dist/core/c4/resolve/service.js +174 -0
- package/dist/core/c4/resolve/service.js.map +1 -0
- package/dist/core/c4/resolve/steps.js +290 -0
- package/dist/core/c4/resolve/steps.js.map +1 -0
- package/dist/core/c4/resolve/systems.js +154 -0
- package/dist/core/c4/resolve/systems.js.map +1 -0
- package/dist/core/c4/root-project/exclude.js +352 -0
- package/dist/core/c4/root-project/exclude.js.map +1 -0
- package/dist/core/c4/seed/fleet-file.js +201 -0
- package/dist/core/c4/seed/fleet-file.js.map +1 -0
- package/dist/core/c4/seed/items.js +91 -0
- package/dist/core/c4/seed/items.js.map +1 -0
- package/dist/core/c4/seed/stamp.js +48 -0
- package/dist/core/c4/seed/stamp.js.map +1 -0
- package/dist/core/c4/seed/template.js +173 -0
- package/dist/core/c4/seed/template.js.map +1 -0
- package/dist/core/c4/service-model/created/models.js +96 -0
- package/dist/core/c4/service-model/created/models.js.map +1 -0
- package/dist/core/c4/service-model/documents.js +47 -0
- package/dist/core/c4/service-model/documents.js.map +1 -0
- package/dist/core/c4/service-model/fleet/extending.js +82 -0
- package/dist/core/c4/service-model/fleet/extending.js.map +1 -0
- package/dist/core/c4/service-model/load.js +165 -0
- package/dist/core/c4/service-model/load.js.map +1 -0
- package/dist/core/c4/service-model/renderer.js +128 -0
- package/dist/core/c4/service-model/renderer.js.map +1 -0
- package/dist/core/c4/service-model/shape.js +106 -0
- package/dist/core/c4/service-model/shape.js.map +1 -0
- package/dist/core/c4/service-model/slice.js +188 -0
- package/dist/core/c4/service-model/slice.js.map +1 -0
- package/dist/core/c4/source-mask.js +369 -0
- package/dist/core/c4/source-mask.js.map +1 -0
- package/dist/core/c4/source-scan.js +308 -0
- package/dist/core/c4/source-scan.js.map +1 -0
- package/dist/core/c4/splice/authored-source.js +167 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -0
- package/dist/core/c4/splice/contract.js +30 -0
- package/dist/core/c4/splice/contract.js.map +1 -0
- package/dist/core/c4/splice/delta-blocks.js +126 -0
- package/dist/core/c4/splice/delta-blocks.js.map +1 -0
- package/dist/core/c4/splice/identity/declared.js +87 -0
- package/dist/core/c4/splice/identity/declared.js.map +1 -0
- package/dist/core/c4/splice/identity/edges.js +73 -0
- package/dist/core/c4/splice/identity/edges.js.map +1 -0
- package/dist/core/c4/splice/identity/existing.js +80 -0
- package/dist/core/c4/splice/identity/existing.js.map +1 -0
- package/dist/core/c4/splice/identity/interior.js +80 -0
- package/dist/core/c4/splice/identity/interior.js.map +1 -0
- package/dist/core/c4/splice/identity/owner.js +50 -0
- package/dist/core/c4/splice/identity/owner.js.map +1 -0
- package/dist/core/c4/splice/landscape-merge.js +337 -0
- package/dist/core/c4/splice/landscape-merge.js.map +1 -0
- package/dist/core/c4/splice/model/merge.js +151 -0
- package/dist/core/c4/splice/model/merge.js.map +1 -0
- package/dist/core/c4/splice/placement.js +298 -0
- package/dist/core/c4/splice/placement.js.map +1 -0
- package/dist/core/c4/splice/text/spot.js +131 -0
- package/dist/core/c4/splice/text/spot.js.map +1 -0
- package/dist/core/c4/workspace.js +166 -0
- package/dist/core/c4/workspace.js.map +1 -0
- package/dist/core/capabilities/authoring/notes.js +141 -0
- package/dist/core/capabilities/authoring/notes.js.map +1 -0
- package/dist/core/capabilities/capabilities.js +124 -0
- package/dist/core/capabilities/capabilities.js.map +1 -0
- package/dist/core/capabilities/delta/doc.js +47 -0
- package/dist/core/capabilities/delta/doc.js.map +1 -0
- package/dist/core/capabilities/delta/overlay.js +129 -0
- package/dist/core/capabilities/delta/overlay.js.map +1 -0
- package/dist/core/capabilities/delta/summary.js +57 -0
- package/dist/core/capabilities/delta/summary.js.map +1 -0
- package/dist/core/capabilities/delta/tree.js +43 -0
- package/dist/core/capabilities/delta/tree.js.map +1 -0
- package/dist/core/capabilities/delta/uncovered.js +222 -0
- package/dist/core/capabilities/delta/uncovered.js.map +1 -0
- package/dist/core/capabilities/findings.js +338 -0
- package/dist/core/capabilities/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/findings.js +174 -0
- package/dist/core/capabilities/realizes/findings.js.map +1 -0
- package/dist/core/capabilities/realizes/join.js +123 -0
- package/dist/core/capabilities/realizes/join.js.map +1 -0
- package/dist/core/capabilities/rollup.js +205 -0
- package/dist/core/capabilities/rollup.js.map +1 -0
- package/dist/core/capabilities/tree.js +104 -0
- package/dist/core/capabilities/tree.js.map +1 -0
- package/dist/core/capabilities/usecase-join.js +267 -0
- package/dist/core/capabilities/usecase-join.js.map +1 -0
- package/dist/core/coherence/authoring/scaffold.js +185 -0
- package/dist/core/coherence/authoring/scaffold.js.map +1 -0
- package/dist/core/coherence/authoring/sentinels.js +75 -0
- package/dist/core/coherence/authoring/sentinels.js.map +1 -0
- package/dist/core/coherence/calls/called.js +52 -0
- package/dist/core/coherence/calls/called.js.map +1 -0
- package/dist/core/coherence/coherence.js +332 -0
- package/dist/core/coherence/coherence.js.map +1 -0
- package/dist/core/coherence/consumed/operations.js +70 -0
- package/dist/core/coherence/consumed/operations.js.map +1 -0
- package/dist/core/coherence/consumed/refusal.js +38 -0
- package/dist/core/coherence/consumed/refusal.js.map +1 -0
- package/dist/core/coherence/covers/health.js +85 -0
- package/dist/core/coherence/covers/health.js.map +1 -0
- package/dist/core/coherence/declared.js +295 -0
- package/dist/core/coherence/declared.js.map +1 -0
- package/dist/core/coherence/events/declared.js +191 -0
- package/dist/core/coherence/events/declared.js.map +1 -0
- package/dist/core/coherence/events/events.js +335 -0
- package/dist/core/coherence/events/events.js.map +1 -0
- package/dist/core/coherence/events/grades.js +189 -0
- package/dist/core/coherence/events/grades.js.map +1 -0
- package/dist/core/coherence/events/lookups.js +63 -0
- package/dist/core/coherence/events/lookups.js.map +1 -0
- package/dist/core/coherence/events/produced.js +100 -0
- package/dist/core/coherence/events/produced.js.map +1 -0
- package/dist/core/coherence/living.js +198 -0
- package/dist/core/coherence/living.js.map +1 -0
- package/dist/core/coherence/lookups.js +95 -0
- package/dist/core/coherence/lookups.js.map +1 -0
- package/dist/core/coherence/pending.js +39 -0
- package/dist/core/coherence/pending.js.map +1 -0
- package/dist/core/coherence/retired/archived.js +285 -0
- package/dist/core/coherence/retired/archived.js.map +1 -0
- package/dist/core/coherence/retired/event-pair.js +62 -0
- package/dist/core/coherence/retired/event-pair.js.map +1 -0
- package/dist/core/coherence/retired/merged.js +79 -0
- package/dist/core/coherence/retired/merged.js.map +1 -0
- package/dist/core/coherence/retired/retirement.js +49 -0
- package/dist/core/coherence/retired/retirement.js.map +1 -0
- package/dist/core/coherence/retired/revival/arrivals.js +131 -0
- package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
- package/dist/core/coherence/retired/revival/revived.js +297 -0
- package/dist/core/coherence/retired/revival/revived.js.map +1 -0
- package/dist/core/conflict-markers.js +60 -0
- package/dist/core/conflict-markers.js.map +1 -0
- package/dist/core/consumers/after.js +113 -0
- package/dist/core/consumers/after.js.map +1 -0
- package/dist/core/consumers/consumers.js +296 -0
- package/dist/core/consumers/consumers.js.map +1 -0
- package/dist/core/consumers/current.js +211 -0
- package/dist/core/consumers/current.js.map +1 -0
- package/dist/core/consumers/scan.js +46 -0
- package/dist/core/consumers/scan.js.map +1 -0
- package/dist/core/consumers/state.js +27 -0
- package/dist/core/consumers/state.js.map +1 -0
- package/dist/core/delta/claims.js +73 -0
- package/dist/core/delta/claims.js.map +1 -0
- package/dist/core/delta/delta.js +341 -0
- package/dist/core/delta/delta.js.map +1 -0
- package/dist/core/delta/document.js +177 -0
- package/dist/core/delta/document.js.map +1 -0
- package/dist/core/delta/scope.js +48 -0
- package/dist/core/delta/scope.js.map +1 -0
- package/dist/core/delta/select.js +237 -0
- package/dist/core/delta/select.js.map +1 -0
- package/dist/core/dependencies/dependencies.js +141 -0
- package/dist/core/dependencies/dependencies.js.map +1 -0
- package/dist/core/dependencies/facts.js +165 -0
- package/dist/core/dependencies/facts.js.map +1 -0
- package/dist/core/dependencies/fanin.js +88 -0
- package/dist/core/dependencies/fanin.js.map +1 -0
- package/dist/core/dependencies/graph.js +106 -0
- package/dist/core/dependencies/graph.js.map +1 -0
- package/dist/core/deployment/delta.js +191 -0
- package/dist/core/deployment/delta.js.map +1 -0
- package/dist/core/deployment/objects.js +145 -0
- package/dist/core/deployment/objects.js.map +1 -0
- package/dist/core/diff/base-git.js +230 -0
- package/dist/core/diff/base-git.js.map +1 -0
- package/dist/core/diff/base-state.js +237 -0
- package/dist/core/diff/base-state.js.map +1 -0
- package/dist/core/diff/joins.js +136 -0
- package/dist/core/diff/joins.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +204 -0
- package/dist/core/diff/scope/changed-paths.js.map +1 -0
- package/dist/core/diff/scope/edges.js +82 -0
- package/dist/core/diff/scope/edges.js.map +1 -0
- package/dist/core/diff/semantic.js +312 -0
- package/dist/core/diff/semantic.js.map +1 -0
- package/dist/core/docs.js +37 -85
- package/dist/core/docs.js.map +1 -1
- package/dist/core/doctor/agents.js +238 -0
- package/dist/core/doctor/agents.js.map +1 -0
- package/dist/core/doctor/config.js +139 -0
- package/dist/core/doctor/config.js.map +1 -0
- package/dist/core/doctor/doctor.js +355 -0
- package/dist/core/doctor/doctor.js.map +1 -0
- package/dist/core/doctor/report.js +13 -0
- package/dist/core/doctor/report.js.map +1 -0
- package/dist/core/doctor/reports/scan.js +242 -0
- package/dist/core/doctor/reports/scan.js.map +1 -0
- package/dist/core/doctor/residue.js +110 -0
- package/dist/core/doctor/residue.js.map +1 -0
- package/dist/core/document/apply.js +224 -0
- package/dist/core/document/apply.js.map +1 -0
- package/dist/core/{frontmatter.js → document/frontmatter.js} +103 -2
- package/dist/core/document/frontmatter.js.map +1 -0
- package/dist/core/document/grammar/directives.js +143 -0
- package/dist/core/document/grammar/directives.js.map +1 -0
- package/dist/core/document/parse.js +286 -0
- package/dist/core/document/parse.js.map +1 -0
- package/dist/core/document/scenarios.js +238 -0
- package/dist/core/document/scenarios.js.map +1 -0
- package/dist/core/document/spec.js +234 -0
- package/dist/core/document/spec.js.map +1 -0
- package/dist/core/{config.js → envelope/config.js} +89 -18
- package/dist/core/envelope/config.js.map +1 -0
- package/dist/core/envelope/json.js +209 -0
- package/dist/core/envelope/json.js.map +1 -0
- package/dist/core/{version.js → envelope/version.js} +3 -3
- package/dist/core/envelope/version.js.map +1 -0
- package/dist/core/explain/families.js +180 -0
- package/dist/core/explain/families.js.map +1 -0
- package/dist/core/explain/fix-tables.js +178 -0
- package/dist/core/explain/fix-tables.js.map +1 -0
- package/dist/core/explain/lookup.js +194 -0
- package/dist/core/explain/lookup.js.map +1 -0
- package/dist/core/explain/refusals.js +49 -0
- package/dist/core/explain/refusals.js.map +1 -0
- package/dist/core/explain/terms/documents.js +227 -0
- package/dist/core/explain/terms/documents.js.map +1 -0
- package/dist/core/explain/terms/done-check.js +144 -0
- package/dist/core/explain/terms/done-check.js.map +1 -0
- package/dist/core/explain/terms/entry.js +14 -0
- package/dist/core/explain/terms/entry.js.map +1 -0
- package/dist/core/explain/terms/stages.js +71 -0
- package/dist/core/explain/terms/stages.js.map +1 -0
- package/dist/core/explain/terms/tasks.js +97 -0
- package/dist/core/explain/terms/tasks.js.map +1 -0
- package/dist/core/explain/terms.js +103 -0
- package/dist/core/explain/terms.js.map +1 -0
- package/dist/core/explore/describe.js +105 -0
- package/dist/core/explore/describe.js.map +1 -0
- package/dist/core/explore/explore.js +204 -0
- package/dist/core/explore/explore.js.map +1 -0
- package/dist/core/fleet-context.js +174 -146
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +208 -0
- package/dist/core/gate/checks.js.map +1 -0
- package/dist/core/gate/partners.js +246 -0
- package/dist/core/gate/partners.js.map +1 -0
- package/dist/core/gate/report.js +47 -0
- package/dist/core/gate/report.js.map +1 -0
- package/dist/core/gate/verification.js +176 -0
- package/dist/core/gate/verification.js.map +1 -0
- package/dist/core/gherkin/digest.js +60 -0
- package/dist/core/gherkin/digest.js.map +1 -0
- package/dist/core/gherkin/emit.js +177 -0
- package/dist/core/gherkin/emit.js.map +1 -0
- package/dist/core/gherkin/read.js +76 -0
- package/dist/core/gherkin/read.js.map +1 -0
- package/dist/core/gherkin/stale.js +210 -0
- package/dist/core/gherkin/stale.js.map +1 -0
- package/dist/core/gherkin/stamp.js +77 -0
- package/dist/core/gherkin/stamp.js.map +1 -0
- package/dist/core/gherkin/steps/catalogue.js +154 -0
- package/dist/core/gherkin/steps/catalogue.js.map +1 -0
- package/dist/core/gherkin/steps/inventory.js +98 -0
- package/dist/core/gherkin/steps/inventory.js.map +1 -0
- package/dist/core/gherkin/steps/phrase.js +72 -0
- package/dist/core/gherkin/steps/phrase.js.map +1 -0
- package/dist/core/glossary/delta.js +109 -0
- package/dist/core/glossary/delta.js.map +1 -0
- package/dist/core/glossary/tree.js +73 -0
- package/dist/core/glossary/tree.js.map +1 -0
- package/dist/core/{concurrency.js → kernel/concurrency.js} +19 -0
- package/dist/core/kernel/concurrency.js.map +1 -0
- package/dist/core/{document-bytes.js → kernel/document-bytes.js} +1 -1
- package/dist/core/kernel/document-bytes.js.map +1 -0
- package/dist/core/kernel/fences.js +42 -0
- package/dist/core/kernel/fences.js.map +1 -0
- package/dist/core/kernel/ids/capability.js +72 -0
- package/dist/core/kernel/ids/capability.js.map +1 -0
- package/dist/core/kernel/ids/dirs.js +33 -0
- package/dist/core/kernel/ids/dirs.js.map +1 -0
- package/dist/core/kernel/ids/feature.js +75 -0
- package/dist/core/kernel/ids/feature.js.map +1 -0
- package/dist/core/kernel/ids/fqn/ancestors.js +65 -0
- package/dist/core/kernel/ids/fqn/ancestors.js.map +1 -0
- package/dist/core/kernel/ids/service.js +156 -0
- package/dist/core/kernel/ids/service.js.map +1 -0
- package/dist/core/kernel/ids/subsystem.js +63 -0
- package/dist/core/kernel/ids/subsystem.js.map +1 -0
- package/dist/core/{path-safety.js → kernel/path-safety.js} +56 -4
- package/dist/core/kernel/path-safety.js.map +1 -0
- package/dist/core/{records.js → kernel/records.js} +11 -0
- package/dist/core/kernel/records.js.map +1 -0
- package/dist/core/links/backlinks.js +66 -0
- package/dist/core/links/backlinks.js.map +1 -0
- package/dist/core/links/case.js +74 -0
- package/dist/core/links/case.js.map +1 -0
- package/dist/core/links/corpus.js +118 -0
- package/dist/core/links/corpus.js.map +1 -0
- package/dist/core/links/findings.js +110 -0
- package/dist/core/links/findings.js.map +1 -0
- package/dist/core/links/parse.js +265 -0
- package/dist/core/links/parse.js.map +1 -0
- package/dist/core/mcp/argv.js +212 -0
- package/dist/core/mcp/argv.js.map +1 -0
- package/dist/core/mcp/author-tools.js +73 -0
- package/dist/core/mcp/author-tools.js.map +1 -0
- package/dist/core/mcp/framing.js +46 -0
- package/dist/core/mcp/framing.js.map +1 -0
- package/dist/core/mcp/protocol.js +280 -0
- package/dist/core/mcp/protocol.js.map +1 -0
- package/dist/core/mcp/tools.js +324 -0
- package/dist/core/mcp/tools.js.map +1 -0
- package/dist/core/obligations/obligations.js +106 -0
- package/dist/core/obligations/obligations.js.map +1 -0
- package/dist/core/openapi/baseline/gate.js +207 -0
- package/dist/core/openapi/baseline/gate.js.map +1 -0
- package/dist/core/openapi/baseline/plan.js +142 -0
- package/dist/core/openapi/baseline/plan.js.map +1 -0
- package/dist/core/openapi/baseline/record.js +174 -0
- package/dist/core/openapi/baseline/record.js.map +1 -0
- package/dist/core/openapi/contract-text.js +33 -0
- package/dist/core/openapi/contract-text.js.map +1 -0
- package/dist/core/openapi/contract-tree.js +301 -0
- package/dist/core/openapi/contract-tree.js.map +1 -0
- package/dist/core/openapi/depth.js +136 -0
- package/dist/core/openapi/depth.js.map +1 -0
- package/dist/core/openapi/digest.js +239 -0
- package/dist/core/openapi/digest.js.map +1 -0
- package/dist/core/{openapi.js → openapi/doc.js} +54 -108
- package/dist/core/openapi/doc.js.map +1 -0
- package/dist/core/openapi/merge/components.js +199 -0
- package/dist/core/openapi/merge/components.js.map +1 -0
- package/dist/core/openapi/merge/error.js +16 -0
- package/dist/core/openapi/merge/error.js.map +1 -0
- package/dist/core/openapi/merge/markers.js +204 -0
- package/dist/core/openapi/merge/markers.js.map +1 -0
- package/dist/core/openapi/merge/merge.js +232 -0
- package/dist/core/openapi/merge/merge.js.map +1 -0
- package/dist/core/openapi/merge/pin.js +110 -0
- package/dist/core/openapi/merge/pin.js.map +1 -0
- package/dist/core/openspec/decide/capabilities.js +244 -0
- package/dist/core/openspec/decide/capabilities.js.map +1 -0
- package/dist/core/openspec/decide/dispositions.js +63 -0
- package/dist/core/openspec/decide/dispositions.js.map +1 -0
- package/dist/core/openspec/decide/renames.js +179 -0
- package/dist/core/openspec/decide/renames.js.map +1 -0
- package/dist/core/openspec/decide/verdict.js +84 -0
- package/dist/core/openspec/decide/verdict.js.map +1 -0
- package/dist/core/openspec/inventory.js +220 -0
- package/dist/core/openspec/inventory.js.map +1 -0
- package/dist/core/openspec/model/mapping.js +78 -0
- package/dist/core/openspec/model/mapping.js.map +1 -0
- package/dist/core/openspec/model/model.js +70 -0
- package/dist/core/openspec/model/model.js.map +1 -0
- package/dist/core/openspec/scan/changes.js +241 -0
- package/dist/core/openspec/scan/changes.js.map +1 -0
- package/dist/core/openspec/scan/config.js +191 -0
- package/dist/core/openspec/scan/config.js.map +1 -0
- package/dist/core/openspec/scan/shape.js +304 -0
- package/dist/core/openspec/scan/shape.js.map +1 -0
- package/dist/core/openspec/scan/walk.js +116 -0
- package/dist/core/openspec/scan/walk.js.map +1 -0
- package/dist/core/openspec/scan/workspace.js +71 -0
- package/dist/core/openspec/scan/workspace.js.map +1 -0
- package/dist/core/owners/codeowners.js +141 -0
- package/dist/core/owners/codeowners.js.map +1 -0
- package/dist/core/pack/features.js +120 -0
- package/dist/core/pack/features.js.map +1 -0
- package/dist/core/pack/joins.js +112 -0
- package/dist/core/pack/joins.js.map +1 -0
- package/dist/core/pack/living.js +157 -0
- package/dist/core/pack/living.js.map +1 -0
- package/dist/core/pack/pack.js +120 -0
- package/dist/core/pack/pack.js.map +1 -0
- package/dist/core/permissions/permissions.js +87 -0
- package/dist/core/permissions/permissions.js.map +1 -0
- package/dist/core/projection/api.js +84 -0
- package/dist/core/projection/api.js.map +1 -0
- package/dist/core/projection/arch-slice.js +63 -0
- package/dist/core/projection/arch-slice.js.map +1 -0
- package/dist/core/projection/events.js +34 -0
- package/dist/core/projection/events.js.map +1 -0
- package/dist/core/projection/introduced.js +14 -0
- package/dist/core/projection/introduced.js.map +1 -0
- package/dist/core/provenance/findings.js +244 -0
- package/dist/core/provenance/findings.js.map +1 -0
- package/dist/core/provenance/git.js +201 -0
- package/dist/core/provenance/git.js.map +1 -0
- package/dist/core/provenance/gitq/moves.js +139 -0
- package/dist/core/provenance/gitq/moves.js.map +1 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js +179 -0
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -0
- package/dist/core/provenance/sample/scope.js +238 -0
- package/dist/core/provenance/sample/scope.js.map +1 -0
- package/dist/core/provenance/sample/sections.js +61 -0
- package/dist/core/provenance/sample/sections.js.map +1 -0
- package/dist/core/provenance/sources.js +280 -0
- package/dist/core/provenance/sources.js.map +1 -0
- package/dist/core/provenance/stamp.js +220 -0
- package/dist/core/provenance/stamp.js.map +1 -0
- package/dist/core/provenance/walk.js +157 -0
- package/dist/core/provenance/walk.js.map +1 -0
- package/dist/core/repo/authored/paths.js +210 -0
- package/dist/core/repo/authored/paths.js.map +1 -0
- package/dist/core/repo/entries.js +126 -0
- package/dist/core/repo/entries.js.map +1 -0
- package/dist/core/repo/paths.js +322 -0
- package/dist/core/repo/paths.js.map +1 -0
- package/dist/core/repo/repo.js +308 -0
- package/dist/core/repo/repo.js.map +1 -0
- package/dist/core/repo/service-target.js +153 -0
- package/dist/core/repo/service-target.js.map +1 -0
- package/dist/core/repo/state.js +58 -0
- package/dist/core/repo/state.js.map +1 -0
- package/dist/core/repo/tree/find.js +61 -0
- package/dist/core/repo/tree/find.js.map +1 -0
- package/dist/core/repo/tree/fs.js +90 -0
- package/dist/core/repo/tree/fs.js.map +1 -0
- package/dist/core/repo/tree/marker.js +61 -0
- package/dist/core/repo/tree/marker.js.map +1 -0
- package/dist/core/repo/tree/render/body.js +258 -0
- package/dist/core/repo/tree/render/body.js.map +1 -0
- package/dist/core/repo/tree/render/projects.js +182 -0
- package/dist/core/repo/tree/render/projects.js.map +1 -0
- package/dist/core/repo/tree/render/service/header.js +125 -0
- package/dist/core/repo/tree/render/service/header.js.map +1 -0
- package/dist/core/repo/tree/render/service/peers.js +28 -0
- package/dist/core/repo/tree/render/service/peers.js.map +1 -0
- package/dist/core/repo/tree/render/service/view-id.js +67 -0
- package/dist/core/repo/tree/render/service/view-id.js.map +1 -0
- package/dist/core/repo/tree/render/service/views.js +78 -0
- package/dist/core/repo/tree/render/service/views.js.map +1 -0
- package/dist/core/repo/tree/render/stale.js +42 -0
- package/dist/core/repo/tree/render/stale.js.map +1 -0
- package/dist/core/repo/tree/render/text.js +84 -0
- package/dist/core/repo/tree/render/text.js.map +1 -0
- package/dist/core/repo/tree/render/views.js +293 -0
- package/dist/core/repo/tree/render/views.js.map +1 -0
- package/dist/core/repo/tree/walk.js +255 -0
- package/dist/core/repo/tree/walk.js.map +1 -0
- package/dist/core/results.js +146 -14
- package/dist/core/results.js.map +1 -1
- package/dist/core/scaffold/landscape.js +239 -0
- package/dist/core/scaffold/landscape.js.map +1 -0
- package/dist/core/scaffold/legacy.js +271 -0
- package/dist/core/scaffold/legacy.js.map +1 -0
- package/dist/core/scaffold/readme.js +84 -0
- package/dist/core/scaffold/readme.js.map +1 -0
- package/dist/core/staging/commit.js +252 -0
- package/dist/core/staging/commit.js.map +1 -0
- package/dist/core/staging/interrupted.js +96 -0
- package/dist/core/staging/interrupted.js.map +1 -0
- package/dist/core/staging/lock.js +268 -0
- package/dist/core/staging/lock.js.map +1 -0
- package/dist/core/staging/recovery/finding.js +35 -0
- package/dist/core/staging/recovery/finding.js.map +1 -0
- package/dist/core/staging/recovery/intent.js +95 -0
- package/dist/core/staging/recovery/intent.js.map +1 -0
- package/dist/core/staging/recovery/recover.js +204 -0
- package/dist/core/staging/recovery/recover.js.map +1 -0
- package/dist/core/staging/recovery/residue.js +62 -0
- package/dist/core/staging/recovery/residue.js.map +1 -0
- package/dist/core/staging/snapshot/manifest.js +188 -0
- package/dist/core/staging/snapshot/manifest.js.map +1 -0
- package/dist/core/staging/snapshot/snapshot.js +196 -0
- package/dist/core/staging/snapshot/snapshot.js.map +1 -0
- package/dist/core/staging/txn/forward.js +181 -0
- package/dist/core/staging/txn/forward.js.map +1 -0
- package/dist/core/staging/txn/journal.js +139 -0
- package/dist/core/staging/txn/journal.js.map +1 -0
- package/dist/core/staging/txn/transaction.js +75 -0
- package/dist/core/staging/txn/transaction.js.map +1 -0
- package/dist/core/staging/writes.js +113 -0
- package/dist/core/staging/writes.js.map +1 -0
- package/dist/core/status/actions/execution.js +60 -0
- package/dist/core/status/actions/execution.js.map +1 -0
- package/dist/core/status/contracts.js +126 -0
- package/dist/core/status/contracts.js.map +1 -0
- package/dist/core/status/feature/artifacts.js +196 -0
- package/dist/core/status/feature/artifacts.js.map +1 -0
- package/dist/core/status/feature/feature.js +214 -0
- package/dist/core/status/feature/feature.js.map +1 -0
- package/dist/core/status/feature/next.js +163 -0
- package/dist/core/status/feature/next.js.map +1 -0
- package/dist/core/status/feature/state.js +21 -0
- package/dist/core/status/feature/state.js.map +1 -0
- package/dist/core/status/feature/words.js +96 -0
- package/dist/core/status/feature/words.js.map +1 -0
- package/dist/core/status/fleet/fleet.js +216 -0
- package/dist/core/status/fleet/fleet.js.map +1 -0
- package/dist/core/status/fleet/next.js +302 -0
- package/dist/core/status/fleet/next.js.map +1 -0
- package/dist/core/status/interrupted.js +97 -0
- package/dist/core/status/interrupted.js.map +1 -0
- package/dist/core/status/report.js +31 -0
- package/dist/core/status/report.js.map +1 -0
- package/dist/core/status/scan.js +41 -0
- package/dist/core/status/scan.js.map +1 -0
- package/dist/core/status/verification.js +216 -0
- package/dist/core/status/verification.js.map +1 -0
- package/dist/core/tasks/packet.js +199 -0
- package/dist/core/tasks/packet.js.map +1 -0
- package/dist/core/tasks/record.js +43 -0
- package/dist/core/tasks/record.js.map +1 -0
- package/dist/core/tasks/sources.js +181 -0
- package/dist/core/tasks/sources.js.map +1 -0
- package/dist/core/tasks/stamps.js +76 -0
- package/dist/core/tasks/stamps.js.map +1 -0
- package/dist/core/tasks/unit.js +0 -0
- package/dist/core/tasks/unit.js.map +1 -0
- package/dist/core/usecases/capability.js +166 -0
- package/dist/core/usecases/capability.js.map +1 -0
- package/dist/core/usecases/delta/claims.js +140 -0
- package/dist/core/usecases/delta/claims.js.map +1 -0
- package/dist/core/usecases/delta/flows.js +101 -0
- package/dist/core/usecases/delta/flows.js.map +1 -0
- package/dist/core/usecases/delta/modified.js +315 -0
- package/dist/core/usecases/delta/modified.js.map +1 -0
- package/dist/core/usecases/delta/overlay.js +76 -0
- package/dist/core/usecases/delta/overlay.js.map +1 -0
- package/dist/core/usecases/fleet.js +296 -0
- package/dist/core/usecases/fleet.js.map +1 -0
- package/dist/core/usecases/grade/capability-tag.js +93 -0
- package/dist/core/usecases/grade/capability-tag.js.map +1 -0
- package/dist/core/usecases/grade/feature.js +88 -0
- package/dist/core/usecases/grade/feature.js.map +1 -0
- package/dist/core/usecases/grade/requirement-tag.js +94 -0
- package/dist/core/usecases/grade/requirement-tag.js.map +1 -0
- package/dist/core/usecases/grade/steps.js +266 -0
- package/dist/core/usecases/grade/steps.js.map +1 -0
- package/dist/core/usecases/grade/usecases.js +112 -0
- package/dist/core/usecases/grade/usecases.js.map +1 -0
- package/dist/core/usecases/operations.js +123 -0
- package/dist/core/usecases/operations.js.map +1 -0
- package/dist/core/usecases/place.js +44 -0
- package/dist/core/usecases/place.js.map +1 -0
- package/dist/core/usecases/service/exclude.js +119 -0
- package/dist/core/usecases/service/exclude.js.map +1 -0
- package/dist/core/usecases/service/flows.js +164 -0
- package/dist/core/usecases/service/flows.js.map +1 -0
- package/dist/core/usecases/suites/participants.js +83 -0
- package/dist/core/usecases/suites/participants.js.map +1 -0
- package/dist/core/usecases/suites/suites.js +45 -0
- package/dist/core/usecases/suites/suites.js.map +1 -0
- package/dist/core/usecases/touch.js +101 -0
- package/dist/core/usecases/touch.js.map +1 -0
- package/dist/core/verify/answers.js +180 -0
- package/dist/core/verify/answers.js.map +1 -0
- package/dist/core/verify/build.js +170 -0
- package/dist/core/verify/build.js.map +1 -0
- package/dist/core/verify/checklist.js +259 -0
- package/dist/core/verify/checklist.js.map +1 -0
- package/dist/core/verify/claims/identity.js +61 -0
- package/dist/core/verify/claims/identity.js.map +1 -0
- package/dist/core/verify/cross/diff.js +97 -0
- package/dist/core/verify/cross/diff.js.map +1 -0
- package/dist/core/verify/evidence/contract.js +169 -0
- package/dist/core/verify/evidence/contract.js.map +1 -0
- package/dist/core/verify/location.js +67 -0
- package/dist/core/verify/location.js.map +1 -0
- package/dist/core/verify/pins/lint.js +158 -0
- package/dist/core/verify/pins/lint.js.map +1 -0
- package/dist/core/verify/pins/pin.js +95 -0
- package/dist/core/verify/pins/pin.js.map +1 -0
- package/dist/core/verify/read/file.js +224 -0
- package/dist/core/verify/read/file.js.map +1 -0
- package/dist/core/verify/read/shape.js +169 -0
- package/dist/core/verify/read/shape.js.map +1 -0
- package/dist/core/verify/read/union.js +105 -0
- package/dist/core/verify/read/union.js.map +1 -0
- package/dist/core/verify/record.js +165 -0
- package/dist/core/verify/record.js.map +1 -0
- package/dist/core/verify/store/commit.js +99 -0
- package/dist/core/verify/store/commit.js.map +1 -0
- package/dist/core/verify/store/render.js +61 -0
- package/dist/core/verify/store/render.js.map +1 -0
- package/dist/core/vocabulary/health.js +91 -0
- package/dist/core/vocabulary/health.js.map +1 -0
- package/dist/core/vocabulary/issue.js +59 -0
- package/dist/core/vocabulary/issue.js.map +1 -0
- package/dist/core/vocabulary/maturity.js +216 -0
- package/dist/core/vocabulary/maturity.js.map +1 -0
- package/dist/core/vocabulary/report.js +90 -0
- package/dist/core/vocabulary/report.js.map +1 -0
- package/dist/core/vocabulary/steps.js +266 -0
- package/dist/core/vocabulary/steps.js.map +1 -0
- package/dist/core/workspace/discover.js +239 -0
- package/dist/core/workspace/discover.js.map +1 -0
- package/dist/core/workspace/render.js +52 -0
- package/dist/core/workspace/render.js.map +1 -0
- package/examples/README.md +232 -0
- package/examples/docs/architecture/adrs/0001-transactional-outbox.md +33 -0
- package/examples/docs/architecture/capabilities.yaml +31 -0
- package/examples/docs/architecture/landscape.likec4 +336 -0
- package/examples/docs/architecture/obligations.yaml +23 -0
- package/examples/docs/architecture/permissions.yaml +50 -0
- package/examples/docs/architecture/services.likec4 +70 -0
- package/examples/docs/architecture/subsystems.likec4 +18 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +74 -0
- package/examples/docs/capabilities/checkout/spec.md +55 -0
- package/examples/docs/capabilities/identity/tokens/spec.md +42 -0
- package/examples/docs/capabilities/order-notifications/spec.md +43 -0
- package/examples/docs/features/FEAT-101-payment-splitting/adrs/0001-dedicated-split-service.md +18 -0
- package/examples/docs/features/FEAT-101-payment-splitting/delta.likec4 +94 -0
- package/examples/docs/features/FEAT-101-payment-splitting/intent.md +44 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/checkout-web/spec.md +21 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +132 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/spec.md +36 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/arch.spec.md +40 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +116 -0
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/spec.md +55 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/intent.md +35 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/openapi.yaml +31 -0
- package/examples/docs/features/FEAT-112-retire-order-v1/specs/order-service/spec.md +17 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/architecture/landscape.likec4 +253 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/order-service/spec.md +121 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/openapi.yaml +111 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/files/services/payment-service/spec.md +58 -0
- package/examples/docs/features/archive/FEAT-088-refunds/.loam-before/manifest.json +32 -0
- package/examples/docs/features/archive/FEAT-088-refunds/adrs/0001-refunds-stay-in-payment-service.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/delta.likec4 +28 -0
- package/examples/docs/features/archive/FEAT-088-refunds/intent.md +26 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/order-service/spec.md +37 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +73 -0
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/spec.md +23 -0
- package/examples/docs/features/archive/FEAT-088-refunds/verification.yaml +76 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/architecture/landscape.likec4 +275 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/asyncapi.yaml +96 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/payment-service/spec.md +82 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/asyncapi.yaml +164 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/files/services/platform/notification-service/spec.md +91 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/.loam-before/manifest.json +46 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/delta.likec4 +36 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/intent.md +22 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/scenario-report.json +10 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/asyncapi.yaml +208 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/notification-service/spec.md +24 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/asyncapi.yaml +137 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/specs/payment-service/spec.md +31 -0
- package/examples/docs/features/archive/FEAT-120-refund-notification/verification.yaml +84 -0
- package/examples/docs/glossary/order.md +15 -0
- package/examples/docs/glossary/payments/authorization.md +14 -0
- package/examples/docs/likec4.config.json +8 -0
- package/examples/docs/loam.json +3 -0
- package/examples/docs/services/checkout-web/model.likec4 +92 -0
- package/examples/docs/services/checkout-web/spec.md +91 -0
- package/examples/docs/services/checkout-web/ui/pages/checkout.page.yaml +40 -0
- package/examples/docs/services/checkout-web/ui/pages/order-status.page.yaml +24 -0
- package/examples/docs/services/checkout-web/ui/pages/split-payment.page.yaml +26 -0
- package/examples/docs/services/order-service/adrs/0001-orchestrated-order-lifecycle.md +52 -0
- package/examples/docs/services/order-service/arch.spec.md +134 -0
- package/examples/docs/services/order-service/asyncapi.yaml +109 -0
- package/examples/docs/services/order-service/health.yaml +57 -0
- package/examples/docs/services/order-service/model.likec4 +126 -0
- package/examples/docs/services/order-service/openapi.yaml +257 -0
- package/examples/docs/services/order-service/runbook.md +62 -0
- package/examples/docs/services/order-service/spec.md +134 -0
- package/examples/docs/services/payment-service/adrs/0001-payments-outbox.md +18 -0
- package/examples/docs/services/payment-service/adrs/0002-idempotency-keys-on-authorization.md +27 -0
- package/examples/docs/services/payment-service/arch.spec.md +76 -0
- package/examples/docs/services/payment-service/asyncapi.yaml +130 -0
- package/examples/docs/services/payment-service/health.yaml +39 -0
- package/examples/docs/services/payment-service/model.likec4 +68 -0
- package/examples/docs/services/payment-service/openapi.yaml +151 -0
- package/examples/docs/services/payment-service/runbook.md +37 -0
- package/examples/docs/services/payment-service/spec.md +88 -0
- package/examples/docs/services/platform/identity-service/adrs/0001-token-introspection-over-local-validation.md +60 -0
- package/examples/docs/services/platform/identity-service/arch.spec.md +120 -0
- package/examples/docs/services/platform/identity-service/health.yaml +70 -0
- package/examples/docs/services/platform/identity-service/model.likec4 +81 -0
- package/examples/docs/services/platform/identity-service/openapi.yaml +197 -0
- package/examples/docs/services/platform/identity-service/runbook.md +95 -0
- package/examples/docs/services/platform/identity-service/spec.md +119 -0
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +200 -0
- package/examples/docs/services/platform/notification-service/health.yaml +40 -0
- package/examples/docs/services/platform/notification-service/model.likec4 +97 -0
- package/examples/docs/services/platform/notification-service/runbook.md +48 -0
- package/examples/docs/services/platform/notification-service/spec.md +112 -0
- package/examples/docs/services/platform/subsystem.yaml +2 -0
- package/examples/fleet.yaml +57 -0
- package/package.json +19 -6
- package/dist/commands/adopt.js +0 -240
- package/dist/commands/adopt.js.map +0 -1
- package/dist/commands/archive.js +0 -1313
- package/dist/commands/archive.js.map +0 -1
- package/dist/commands/delta.js +0 -388
- package/dist/commands/delta.js.map +0 -1
- package/dist/commands/docs-repo-gate.js.map +0 -1
- package/dist/commands/format.js +0 -17
- package/dist/commands/format.js.map +0 -1
- package/dist/commands/gherkin.js +0 -309
- package/dist/commands/gherkin.js.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/list.js +0 -295
- package/dist/commands/list.js.map +0 -1
- package/dist/commands/migrate-openspec.js +0 -950
- package/dist/commands/migrate-openspec.js.map +0 -1
- package/dist/commands/new.js +0 -413
- package/dist/commands/new.js.map +0 -1
- package/dist/commands/rebase.js +0 -356
- package/dist/commands/rebase.js.map +0 -1
- package/dist/commands/show.js +0 -320
- package/dist/commands/show.js.map +0 -1
- package/dist/commands/status.js +0 -262
- package/dist/commands/status.js.map +0 -1
- package/dist/commands/unarchive.js +0 -317
- package/dist/commands/unarchive.js.map +0 -1
- package/dist/commands/validate.js +0 -1773
- package/dist/commands/validate.js.map +0 -1
- package/dist/commands/verify.js +0 -775
- package/dist/commands/verify.js.map +0 -1
- package/dist/commands/vouch.js +0 -421
- package/dist/commands/vouch.js.map +0 -1
- package/dist/core/agent.js +0 -2173
- package/dist/core/agent.js.map +0 -1
- package/dist/core/agents-stamp.js.map +0 -1
- package/dist/core/arch.js +0 -130
- package/dist/core/arch.js.map +0 -1
- package/dist/core/asyncapi.js +0 -253
- package/dist/core/asyncapi.js.map +0 -1
- package/dist/core/brief.js +0 -755
- package/dist/core/brief.js.map +0 -1
- package/dist/core/coherence.js +0 -577
- package/dist/core/coherence.js.map +0 -1
- package/dist/core/concurrency.js.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/delta.js +0 -476
- package/dist/core/delta.js.map +0 -1
- package/dist/core/dependencies.js +0 -356
- package/dist/core/dependencies.js.map +0 -1
- package/dist/core/doctor.js +0 -596
- package/dist/core/doctor.js.map +0 -1
- package/dist/core/document-bytes.js.map +0 -1
- package/dist/core/explore.js +0 -225
- package/dist/core/explore.js.map +0 -1
- package/dist/core/frontmatter.js.map +0 -1
- package/dist/core/gherkin.js +0 -463
- package/dist/core/gherkin.js.map +0 -1
- package/dist/core/health.js +0 -67
- package/dist/core/health.js.map +0 -1
- package/dist/core/ids.js +0 -122
- package/dist/core/ids.js.map +0 -1
- package/dist/core/issue.js +0 -9
- package/dist/core/issue.js.map +0 -1
- package/dist/core/json.js +0 -74
- package/dist/core/json.js.map +0 -1
- package/dist/core/likec4.js +0 -489
- package/dist/core/likec4.js.map +0 -1
- package/dist/core/maturity.js +0 -66
- package/dist/core/maturity.js.map +0 -1
- package/dist/core/openapi-merge.js +0 -552
- package/dist/core/openapi-merge.js.map +0 -1
- package/dist/core/openapi.js.map +0 -1
- package/dist/core/openspec-inventory.js +0 -1440
- package/dist/core/openspec-inventory.js.map +0 -1
- package/dist/core/path-safety.js.map +0 -1
- package/dist/core/provenance.js +0 -787
- package/dist/core/provenance.js.map +0 -1
- package/dist/core/records.js.map +0 -1
- package/dist/core/repo.js +0 -438
- package/dist/core/repo.js.map +0 -1
- package/dist/core/report.js +0 -47
- package/dist/core/report.js.map +0 -1
- package/dist/core/spec.js +0 -505
- package/dist/core/spec.js.map +0 -1
- package/dist/core/staging.js +0 -890
- package/dist/core/staging.js.map +0 -1
- package/dist/core/status.js +0 -1132
- package/dist/core/status.js.map +0 -1
- package/dist/core/steps.js +0 -72
- package/dist/core/steps.js.map +0 -1
- package/dist/core/verify.js +0 -807
- package/dist/core/verify.js.map +0 -1
- package/dist/core/version.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agents-stamp.js","sourceRoot":"","sources":["../../../src/core/agent/agents-stamp.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The AGENTS.md version stamp: detection, never refresh.\n *\n * AGENTS.md is written once by `loam init` and never touched again — that is\n * the ownership contract (agent.ts): it is a starting point, and a team's edits\n * to it outrank ours. But the file tells agents to branch on flag and code\n * tables, and those tables describe the binary that wrote them. OpenSpec hit\n * the same wall and answered with auto-refresh, which teaches everyone the file\n * belongs to the tool after all; loam answers with the smallest honest thing —\n * a version stamp in the generated file, and one warning when the stamp is\n * missing or trails the running binary. Reviewing the file and bumping the\n * stamp is a human act, and a hand-curated file silences the warning the same\n * way: by saying, in the stamp, that someone has looked.\n */\nimport type { Finding } from \"../vocabulary/report.js\";\n\n/** The stamp `loam init` writes at the top of AGENTS.md. */\nexport function agentsStampLine(version: string): string {\n return `<!-- generated by loam v${version} -->`;\n}\n\n/** Matches a stamp line anywhere in the file; the capture is the version text. */\nconst STAMP_RE = /<!--\\s*generated by loam v(\\S+?)\\s*-->/;\n\n/**\n * `text` with its stamp, when it has one, rewritten to name `version` — every\n * other byte untouched. What lets a caller ask whether a generated file differs\n * from what a binary would write in anything BUT the stamp: the pointer files\n * carry this same line, and a release that changes nothing in their body still\n * changes it.\n */\nexport function restamped(text: string, version: string): string {\n return text.replace(STAMP_RE, agentsStampLine(version));\n}\n\n/**\n * The version the stamp names, or null when there is no stamp (or one whose\n * version does not read as numbers — unparseable is indistinguishable from\n * absent, and both get the same advice).\n */\nexport function agentsStampVersion(text: string): string | null {\n const m = STAMP_RE.exec(text);\n return m !== null && parseVersion(m[1]!) !== null ? m[1]! : null;\n}\n\n/** A version split the way precedence is decided: the triple, then the prerelease identifiers. */\ninterface ParsedVersion {\n release: [number, number, number];\n /**\n * The dot-separated identifiers of a `-beta.2` suffix, empty for a final\n * release. Build metadata (`+sha`) is dropped — semver excludes it from\n * precedence, and two builds of one version are the same instructions.\n */\n pre: string[];\n}\n\n/** `X.Y.Z[-pre][+build]`, or null when the leading triple does not read as numbers. */\nfunction parseVersion(v: string): ParsedVersion | null {\n const m = /^(\\d+)\\.(\\d+)\\.(\\d+)(?:-([0-9A-Za-z.-]+))?(?:\\+[0-9A-Za-z.-]+)?$/.exec(v);\n if (m === null) return null;\n return {\n release: [Number(m[1]), Number(m[2]), Number(m[3])],\n pre: m[4] === undefined ? [] : m[4].split(\".\"),\n };\n}\n\n/**\n * Semver identifier precedence: numeric identifiers compare numerically and\n * rank below alphanumeric ones, and a longer identifier list outranks a prefix\n * of itself. -1 / 0 / 1, so the caller reads like the triple comparison above.\n */\nfunction comparePre(a: string[], b: string[]): number {\n // No prerelease outranks any prerelease — `1.2.0` is newer than `1.2.0-beta.9`\n // — which is why this cannot be the plain lexicographic walk the identifiers get.\n if (a.length === 0 || b.length === 0) return a.length === b.length ? 0 : a.length === 0 ? 1 : -1;\n for (let i = 0; i < Math.min(a.length, b.length); i += 1) {\n const [x, y] = [a[i]!, b[i]!];\n if (x === y) continue;\n const [nx, ny] = [/^\\d+$/.test(x), /^\\d+$/.test(y)];\n if (nx && ny) return Number(x) < Number(y) ? -1 : 1;\n if (nx !== ny) return nx ? -1 : 1;\n return x < y ? -1 : 1;\n }\n return a.length === b.length ? 0 : a.length < b.length ? -1 : 1;\n}\n\n/**\n * Does `stamp` name an older version than `binary`? A stamp NEWER than the\n * binary does not trail: that is an old binary, not a stale file, and the fix\n * (upgrade loam) is not an AGENTS.md edit.\n *\n * Prerelease identifiers are compared, not ignored, and the difference is the\n * whole reason this check exists. Comparing the numeric triple alone made\n * `0.1.0-beta.1` and `0.1.0-beta.2` indistinguishable — and beta.2 is precisely\n * the release that changed the FORM of every generated file (embedded protocol\n * text became a pointer at `loam instructions`), with a CHANGELOG telling\n * readers to delete the files and re-run `loam init`. The one upgrade that most\n * needed the warning was the one bump shape that could not raise it. A\n * prerelease line is where a generated file's form actually moves, because that\n * is what a prerelease is for.\n */\nexport function versionTrails(stamp: string, binary: string): boolean {\n const s = parseVersion(stamp);\n const b = parseVersion(binary);\n if (s === null || b === null) return false;\n for (let i = 0; i < 3; i += 1) {\n if (s.release[i]! !== b.release[i]!) return s.release[i]! < b.release[i]!;\n }\n return comparePre(s.pre, b.pre) < 0;\n}\n\n/**\n * Does `stamp` name a version NEWER than the binary reading it? The mirror of\n * {@link versionTrails}, and a different subject rather than its negation:\n * equal versions are neither.\n */\nexport function versionAhead(stamp: string, binary: string): boolean {\n return versionTrails(binary, stamp);\n}\n\n/**\n * `docs.binary-behind` — this loam is OLDER than the loam that wrote the docs\n * repo it is reading.\n *\n * The false-green this closes is the sharpest one in the product, because it\n * inverts the meaning of a passing run rather than merely missing a defect.\n * loam's whole promise is that a token spelled here must be spelled there — so\n * every check is an existence constraint over a value the parser recognised.\n * A binary that predates a grammar addition does not FAIL on the newer\n * directive; it does not see it, produces no value, has nothing to join, and\n * reports green. The corpus is checked less than it looks, and nothing anywhere\n * says so. `agents.stale` is the opposite direction and explicitly declines\n * this case (\"that is an old binary, not a stale file\") — correctly, because\n * the fix is different: upgrade loam, do not edit the file.\n *\n * A WARNING, not an error, and the reasoning is the `sources.stale` doctrine.\n * A mixed-version fleet is ordinary — one engineer's global install trails a\n * release by a week — and failing every command in that repo would be a\n * refusal aimed at the wrong person on the wrong day. What the message must do\n * instead is say plainly that a green run from this binary is worth less than\n * it appears, which no other finding says. A fleet that wants it to gate has\n * `--strict`, which is exactly the lever that doctrine reserves for this.\n *\n * Silent when there is no file, no stamp, or the stamp is equal or older —\n * every one of those is somebody else's finding.\n */\nexport function binaryBehindFinding(text: string | null, binary: string): Finding | null {\n if (text === null) return null;\n const stamp = agentsStampVersion(text);\n if (stamp === null || !versionAhead(stamp, binary)) return null;\n return {\n severity: \"warn\",\n code: \"docs.binary-behind\",\n message:\n `This docs repo was written by loam v${stamp}; this binary is v${binary}. A newer loam may check ` +\n \"joins this one cannot parse — an unrecognised directive is read as prose, so it produces no \" +\n \"join to fail and this run reports green without having graded it. Treat a pass from this \" +\n `binary as incomplete rather than clean, and upgrade to v${stamp} or later (\\`npm i -g @ybotok/loam\\`). ` +\n \"Nothing here is wrong with the documents; the reader is behind them.\",\n };\n}\n\n/**\n * The one finding `loam validate --all` owes the agent contract. `text` is the\n * docs repo's AGENTS.md, or null when there is none — no file means no contract\n * to have drifted, and this check stays silent rather than inventing a second\n * meaning for its code. Returns null when the stamp is current (or newer).\n */\nexport function agentsStaleFinding(text: string | null, binary: string): Finding | null {\n if (text === null) return null;\n const stamp = agentsStampVersion(text);\n if (stamp === null) {\n return {\n severity: \"warn\",\n code: \"agents.stale\",\n message:\n \"AGENTS.md has no version stamp — it predates stamping or was hand-created, so nothing says \" +\n \"which loam its flag and code tables describe. Review it against the current `loam --help`, \" +\n `then add \\`${agentsStampLine(binary)}\\` near the top; a hand-curated file keeps the warning ` +\n \"off the same way, by keeping the stamp current.\",\n };\n }\n if (!versionTrails(stamp, binary)) return null;\n return {\n severity: \"warn\",\n code: \"agents.stale\",\n message:\n `AGENTS.md was written by loam v${stamp}; this binary is v${binary} — the flag and code tables ` +\n \"agents branch on may have moved. Review the file against the current `loam --help`, then \" +\n `update the stamp line to v${binary} (a hand-curated file silences this by bumping the stamp itself).`,\n };\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../../src/core/agent/contract.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * The shapes of the agent contract: what a workflow protocol is made of and\n * what a per-tool delivery adds around it. Types only, deliberately — a leaf\n * module the rest of the package `import type`s from. scripts/package-graph.mjs\n * counts only value imports, so keeping this file value-free is what lets\n * workflows/ and tools/ depend on the shapes without a package edge back into\n * the agent root, and what keeps that graph acyclic.\n */\n/**\n * One slash command, format-free. `body` is the whole protocol — the per-tool\n * emitters in AGENT_TOOLS add only a path and a wrapper (frontmatter fields, a\n * TOML shell), never their own prose: one source of truth, thin spellings.\n * Bodies keep Claude's positional `$1`/`$2` placeholder convention across\n * every tool — dialects differ (Gemini's {{args}}, Copilot's ${input}) and rewriting the\n * text per tool would be a second copy of the protocol in all but name; an\n * agent reading the file still sees which argument goes where.\n */\n/**\n * What a protocol's positional placeholder denotes. `free` is the one that\n * cannot be checked — `loam-feature`'s `$2` is a human title, and any string is\n * a legal one — and it is spelled rather than left implicit so a new\n * placeholder has to state which of the three it is.\n */\nexport type PlaceholderKind = \"service\" | \"feature\" | \"free\";\n\nexport interface CommandContent {\n /** Stable command name (`loam-check`) — also the flat file name everywhere. */\n name: string;\n description: string;\n /** What the user passes, in Claude's `argument-hint` spelling. */\n argumentHint: string;\n /** One or two sentences: what this workflow is for, and who does which half. */\n purpose: string;\n /**\n * The literal `loam instructions …` line the generated file tells an agent to\n * run, placeholders and all. Spelled per command rather than derived from\n * `argumentHint`, because the mapping from a hint to positional arguments is\n * exactly the kind of clever derivation that is right five times and wrong\n * once — and the once is a command an agent pastes.\n */\n invocation: string;\n /**\n * What `$1`, `$2`, … stand for in `body`, in order — so the substitution can\n * be checked instead of merely performed.\n *\n * `loam instructions loam-adopt \"$PWD\"` used to render a protocol reading\n * `services//Users/someone/work/svc/` and `--service /Users/someone/…`: the\n * placeholder is a service id, the value was an absolute path, and nothing\n * between the shell and the printed page knew the difference. The commands\n * downstream all refuse it — `assertServiceId` is one rule in one place, and\n * it says so well — so a bad brief could never become bad documentation. But\n * the refusal arrives one step late, after an agent has read a page of\n * confident instructions built around a value that cannot work, and the\n * cheapest place to say \"that is not a service id\" is the command that was\n * told the argument IS one.\n */\n placeholders: readonly PlaceholderKind[];\n /**\n * The verbs, in order, and nothing else. This is the half of the protocol\n * that does not move between releases: a reader with a stale file can still\n * tell whether a run went sideways, without the file claiming to know this\n * binary's flags or finding codes.\n */\n spine: string[];\n /** The protocol itself: markdown, ends with a newline. */\n body: string;\n}\n\n/**\n * One delivery of one command: where the file goes, and what goes in it. Both\n * halves are thin by construction — the protocol is `CommandContent.body` and\n * nothing here may restate it.\n */\nexport interface AgentFileEmitter {\n /** Repo-relative path segments of the file. */\n path(name: string): string[];\n /** The full file: this tool's wrapper around the shared body. */\n format(cmd: CommandContent): string;\n}\n\n/**\n * A tool the commands can be emitted for — the registry key is the `--tools`\n * id (OpenSpec's ids where the tool has one there). A path and a wrapper are\n * the WHOLE adapter: OpenSpec's per-tool command layer, minus everything loam\n * refuses on principle — no version stamps in command files, no\n * overwrite-on-update, no managed marker blocks in anyone else's file. Paths\n * and wrappers follow each tool's own documented convention, pinned in\n * test/agents.test.ts.\n */\nexport interface AgentTool {\n /**\n * Repo-relative path segments of one command's file. Absent — together with\n * `format` — for a tool that registers no command files at all: Codex reads\n * skills and nothing else, and inventing a command directory for it would\n * scatter files no agent ever loads.\n */\n path?(name: string): string[];\n /** The full command file: this tool's wrapper around the shared body. */\n format?(cmd: CommandContent): string;\n /** The skill delivery. Absent for a tool with no skills convention. */\n skill?: AgentFileEmitter;\n /**\n * Repo-relative paths whose presence means this tool is in use here — what\n * `loam init` scans when no `--tools` says otherwise. Usually just the tool's\n * own dot-directory; spelled per tool because the exceptions matter more than\n * the rule (see `github-copilot`, whose `.github/` says nothing at all).\n */\n detect: string[];\n}\n"]}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The protocol surface: six lifecycle workflows, the support protocol and the
|
|
3
|
+
* reference pages — what `loam instructions` prints (commands/instructions.ts)
|
|
4
|
+
* and the corpus every check over loam's agent-facing prose reads
|
|
5
|
+
* (test/codes-drift.test.ts, test/agent-contract.test.ts,
|
|
6
|
+
* test/agent-commands-runnable.test.ts).
|
|
7
|
+
*/
|
|
8
|
+
import { featureIdProblem } from "../kernel/ids/feature.js";
|
|
9
|
+
import { serviceIdProblem } from "../kernel/ids/service.js";
|
|
10
|
+
import { LOAM_ADOPT } from "./workflows/adopt.js";
|
|
11
|
+
import { LOAM_CHECK } from "./workflows/check.js";
|
|
12
|
+
import { LOAM_VERIFY, LOAM_SHIP } from "./workflows/closing.js";
|
|
13
|
+
import { LOAM_FEATURE } from "./workflows/feature.js";
|
|
14
|
+
import { LOAM_IMPLEMENT } from "./workflows/implement.js";
|
|
15
|
+
import { REFERENCES } from "./workflows/reference/reference.js";
|
|
16
|
+
import { LOAM_REPORT } from "./support/report.js";
|
|
17
|
+
/**
|
|
18
|
+
* The six protocols, in cycle order. One assembly, exported: scaffold.ts
|
|
19
|
+
* derives the generated files through this same list, so what
|
|
20
|
+
* `loam instructions` prints and what a fresh scaffold writes cannot drift
|
|
21
|
+
* apart.
|
|
22
|
+
*/
|
|
23
|
+
export const COMMANDS = [
|
|
24
|
+
LOAM_ADOPT,
|
|
25
|
+
LOAM_FEATURE,
|
|
26
|
+
LOAM_IMPLEMENT,
|
|
27
|
+
LOAM_CHECK,
|
|
28
|
+
LOAM_VERIFY,
|
|
29
|
+
LOAM_SHIP,
|
|
30
|
+
];
|
|
31
|
+
/**
|
|
32
|
+
* Support entry points generated beside the lifecycle, but not counted as
|
|
33
|
+
* lifecycle steps. Reporting a bad run must be discoverable in every profile;
|
|
34
|
+
* placing it in COMMANDS would make a consumer iterating that list try to run
|
|
35
|
+
* incident collection after every feature.
|
|
36
|
+
*/
|
|
37
|
+
export const SUPPORT = [LOAM_REPORT];
|
|
38
|
+
/** Every command/skill file init generates, regardless of category. */
|
|
39
|
+
export const AGENT_COMMANDS = [...COMMANDS, ...SUPPORT];
|
|
40
|
+
/**
|
|
41
|
+
* Everything `loam instructions <name>` can print: the six workflows, support
|
|
42
|
+
* protocol and five reference pages, in that order.
|
|
43
|
+
*
|
|
44
|
+
* The pages join the generated protocols HERE and nowhere else — not in
|
|
45
|
+
* {@link AGENT_COMMANDS}, which is what scaffold.ts derives `SLASH_COMMANDS`
|
|
46
|
+
* and `plannedCommandFiles` from. That is the whole mechanism, and the
|
|
47
|
+
* asymmetry is the point: a page is printable by name but `loam init` writes no
|
|
48
|
+
* file for it, so moving 44 KB out of AGENTS.md did not put 44 KB back as four
|
|
49
|
+
* new artifacts in every repository loam touches. The support protocol does
|
|
50
|
+
* belong in AGENT_COMMANDS because discovery is its purpose, while its separate
|
|
51
|
+
* menu category keeps it out of the lifecycle. test/agents.test.ts asserts the
|
|
52
|
+
* reference-page halves separately, because a future edit can break either
|
|
53
|
+
* alone.
|
|
54
|
+
*/
|
|
55
|
+
const PRINTABLE = [...AGENT_COMMANDS, ...REFERENCES];
|
|
56
|
+
/**
|
|
57
|
+
* The printable bodies, keyed by name — what `loam instructions <name>` prints,
|
|
58
|
+
* and the corpus every check over loam's agent-facing prose reads.
|
|
59
|
+
*
|
|
60
|
+
* Separate from SLASH_COMMANDS since the file became a pointer: the protocol is
|
|
61
|
+
* still the thing that must document every stable code (`codes-drift`) and
|
|
62
|
+
* every `loam …` line it teaches must still parse against the real CLI
|
|
63
|
+
* (`agent-commands-runnable`). Those two properties are about the INSTRUCTIONS,
|
|
64
|
+
* and they did not move just because the delivery did.
|
|
65
|
+
*
|
|
66
|
+
* The reference pages belong in this record for exactly that reason. Every code
|
|
67
|
+
* they carry LEFT AGENTS.md to get here, and `codes-drift` reads
|
|
68
|
+
* `AGENTS_MD + PROTOCOLS` — so the guard stays green by construction, because
|
|
69
|
+
* the codes moved from one half of that corpus into the other. If it goes red
|
|
70
|
+
* after a change here, something was deleted rather than moved.
|
|
71
|
+
*/
|
|
72
|
+
export const PROTOCOLS = Object.fromEntries(PRINTABLE.map((c) => [c.name, c.body]));
|
|
73
|
+
/**
|
|
74
|
+
* What each page's `$1`, `$2`, … denote — see {@link CommandContent.placeholders}.
|
|
75
|
+
* A reference page declares `[]`, which is not a formality: `placeholderProblems`
|
|
76
|
+
* keys off this record, and a name absent from it is treated as unknown rather
|
|
77
|
+
* than as taking no arguments.
|
|
78
|
+
*/
|
|
79
|
+
export const PLACEHOLDERS = Object.fromEntries(PRINTABLE.map((c) => [c.name, c.placeholders]));
|
|
80
|
+
/**
|
|
81
|
+
* Whether nothing was supplied for this position — the two shapes an absent
|
|
82
|
+
* argument actually arrives in, in one place because both call sites below owe
|
|
83
|
+
* the same answer.
|
|
84
|
+
*
|
|
85
|
+
* The first is empty; {@link protocolFor} says which dialects send that. The
|
|
86
|
+
* second is the placeholder ITSELF, arriving as data. One body serves twenty
|
|
87
|
+
* tool dialects (tools/registry.ts) and keeps Claude's positional `$1`/`$2`
|
|
88
|
+
* convention in all of them (see {@link CommandContent}), so every generated
|
|
89
|
+
* stub carries the spelling verbatim: `.gemini/commands/loam/adopt.toml`
|
|
90
|
+
* contains the literal line `loam instructions loam-adopt $1`. Gemini's own
|
|
91
|
+
* convention is `{{args}}` and Copilot's is `${input:…}`, and Cline, Kilo Code
|
|
92
|
+
* and Roo Code substitute nothing whatever — so on those three the `$1` reaches
|
|
93
|
+
* this command exactly as written, and loam refused the literal first
|
|
94
|
+
* instruction of its own workflow with `invalid-option`. (Unquoted in a POSIX
|
|
95
|
+
* shell the same line degrades the other way: `$1` expands to empty, and the
|
|
96
|
+
* agent receives a protocol addressed to nobody.) The same class already cost
|
|
97
|
+
* `loam-check` its placeholder — see the comment in workflows/check.ts; this is
|
|
98
|
+
* the general fix, made once in the RECEIVING command rather than per dialect.
|
|
99
|
+
*
|
|
100
|
+
* Scoped to `^\$[1-9]$` and no wider. `{{args}}` and `${input:…}` are
|
|
101
|
+
* deliberately NOT matched: the tools that spell placeholders that way
|
|
102
|
+
* substitute them before an agent ever reads the file, so they cannot arrive
|
|
103
|
+
* here, and loam emits neither. A value that merely CONTAINS a placeholder
|
|
104
|
+
* (`FEAT-$1`) is a real argument and is still checked as one.
|
|
105
|
+
*/
|
|
106
|
+
const unsupplied = (arg) => arg === undefined || arg === "" || /^\$[1-9]$/.test(arg);
|
|
107
|
+
/**
|
|
108
|
+
* Why the arguments given to `name` cannot be substituted into its protocol, or
|
|
109
|
+
* null when they can. One sentence per bad argument, already naming the
|
|
110
|
+
* placeholder it was meant to fill.
|
|
111
|
+
*
|
|
112
|
+
* The grammars are `core/kernel/ids/`'s, never a second copy: a value this accepts
|
|
113
|
+
* and `loam adopt` refuses would be worse than no check, because the protocol
|
|
114
|
+
* would still be wrong and now something had approved it. An argument nobody
|
|
115
|
+
* supplied is not an error — `protocolFor` leaves that placeholder standing on
|
|
116
|
+
* purpose, so the page reads as "the service id goes here" — and by
|
|
117
|
+
* {@link unsupplied} that covers the placeholder text arriving as the argument,
|
|
118
|
+
* which is what an untouched generated stub sends.
|
|
119
|
+
*/
|
|
120
|
+
export function placeholderProblems(name, args) {
|
|
121
|
+
const kinds = PLACEHOLDERS[name];
|
|
122
|
+
if (kinds === undefined)
|
|
123
|
+
return null;
|
|
124
|
+
const problems = kinds.flatMap((kind, i) => {
|
|
125
|
+
const arg = args[i];
|
|
126
|
+
// The `undefined` arm is `unsupplied`'s own; it is repeated here because
|
|
127
|
+
// that is what narrows `arg` to a string for the id grammars below.
|
|
128
|
+
if (arg === undefined || unsupplied(arg) || kind === "free")
|
|
129
|
+
return [];
|
|
130
|
+
const problem = kind === "service"
|
|
131
|
+
? serviceIdProblem(arg, `$${i + 1}`)
|
|
132
|
+
: featureIdProblem(arg, `feature id ($${i + 1})`);
|
|
133
|
+
return problem === null ? [] : [problem];
|
|
134
|
+
});
|
|
135
|
+
return problems.length === 0 ? null : problems;
|
|
136
|
+
}
|
|
137
|
+
const row = ({ name, description, argumentHint }) => ({ name, description, argumentHint });
|
|
138
|
+
/** The workflow names, in cycle order — `loam instructions` with no argument lists these. */
|
|
139
|
+
export const WORKFLOWS = COMMANDS.map(row);
|
|
140
|
+
/** Support protocols, listed separately so no caller mistakes one for a lifecycle step. */
|
|
141
|
+
export const SUPPORT_PAGES = SUPPORT.map(row);
|
|
142
|
+
/**
|
|
143
|
+
* The reference-page names, listed by the same bare `loam instructions` and
|
|
144
|
+
* kept a SEPARATE list rather than appended to {@link WORKFLOWS}.
|
|
145
|
+
*
|
|
146
|
+
* A page is not a workflow: it has no steps, it is not part of the cycle, and
|
|
147
|
+
* running one is not doing anything. A menu that ran the ten together would
|
|
148
|
+
* read as a ten-step process, which is the one thing the six-step cycle must
|
|
149
|
+
* not be confused with — so the command prints them under their own heading
|
|
150
|
+
* (commands/instructions.ts) and test/instructions.test.ts pins that they stay
|
|
151
|
+
* apart.
|
|
152
|
+
*/
|
|
153
|
+
export const REFERENCE_PAGES = REFERENCES.map(row);
|
|
154
|
+
/**
|
|
155
|
+
* One workflow's protocol with `$1`, `$2`, … replaced by the arguments given.
|
|
156
|
+
*
|
|
157
|
+
* An unsupplied placeholder is LEFT STANDING rather than blanked: the bodies
|
|
158
|
+
* are written so `$1` reads as "the feature id goes here", and a protocol that
|
|
159
|
+
* silently dropped it would hand an agent `loam validate --feature --json` — a
|
|
160
|
+
* command that parses, runs, and answers a different question. Extra arguments
|
|
161
|
+
* are ignored for the same reason: this substitutes, it does not validate.
|
|
162
|
+
*
|
|
163
|
+
* "Unsupplied" is {@link unsupplied}'s two shapes, not merely a missing
|
|
164
|
+
* element, and neither is pedantry — they are the two things a tool actually
|
|
165
|
+
* sends. An EMPTY argument is the first: several dialects expand an absent
|
|
166
|
+
* positional to the empty string, and `loam-feature`'s own invocation quotes
|
|
167
|
+
* its second one (`--title "$2"`), so `/loam-feature FEAT-101` with no title
|
|
168
|
+
* arrives here as `["FEAT-101", ""]`. Blanking it produced
|
|
169
|
+
* `loam new FEAT-101 --title ""` — which is exactly the failure the paragraph
|
|
170
|
+
* above describes, reached by the one path that paragraph did not cover: the
|
|
171
|
+
* command succeeds, and writes a feature whose title is the empty string and
|
|
172
|
+
* whose intent.md opens with a bare `#`.
|
|
173
|
+
*
|
|
174
|
+
* The LITERAL PLACEHOLDER is the second: the dialects that substitute nothing
|
|
175
|
+
* hand this command the `$1` their generated stub was written with, so
|
|
176
|
+
* `loam instructions loam-adopt $1` renders the same page as
|
|
177
|
+
* `loam instructions loam-adopt` — the placeholder standing, the protocol
|
|
178
|
+
* printed. Here the shape mostly falls out anyway (planting `$1` where `$1`
|
|
179
|
+
* stood is a no-op); it is spelled all the same, because a MISNUMBERED one
|
|
180
|
+
* would not be — `$3` given for `$1` would renumber the placeholder in the
|
|
181
|
+
* printed page — and because the check above and this render have to agree on
|
|
182
|
+
* one definition or a value can pass one and be rewritten by the other.
|
|
183
|
+
*/
|
|
184
|
+
export function protocolFor(name, args = []) {
|
|
185
|
+
const body = PROTOCOLS[name];
|
|
186
|
+
if (body === undefined)
|
|
187
|
+
return null;
|
|
188
|
+
return body.replace(/\$([1-9])/g, (whole, digit) => {
|
|
189
|
+
const arg = args[Number(digit) - 1];
|
|
190
|
+
return arg === undefined || unsupplied(arg) ? whole : arg;
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=protocol.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/core/agent/protocol.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The protocol surface: six lifecycle workflows, the support protocol and the\n * reference pages — what `loam instructions` prints (commands/instructions.ts)\n * and the corpus every check over loam's agent-facing prose reads\n * (test/codes-drift.test.ts, test/agent-contract.test.ts,\n * test/agent-commands-runnable.test.ts).\n */\nimport { featureIdProblem } from \"../kernel/ids/feature.js\";\nimport { serviceIdProblem } from \"../kernel/ids/service.js\";\nimport type { CommandContent, PlaceholderKind } from \"./contract.js\";\nimport { LOAM_ADOPT } from \"./workflows/adopt.js\";\nimport { LOAM_CHECK } from \"./workflows/check.js\";\nimport { LOAM_VERIFY, LOAM_SHIP } from \"./workflows/closing.js\";\nimport { LOAM_FEATURE } from \"./workflows/feature.js\";\nimport { LOAM_IMPLEMENT } from \"./workflows/implement.js\";\nimport { REFERENCES } from \"./workflows/reference/reference.js\";\nimport { LOAM_REPORT } from \"./support/report.js\";\n\n/**\n * The six protocols, in cycle order. One assembly, exported: scaffold.ts\n * derives the generated files through this same list, so what\n * `loam instructions` prints and what a fresh scaffold writes cannot drift\n * apart.\n */\nexport const COMMANDS: CommandContent[] = [\n LOAM_ADOPT,\n LOAM_FEATURE,\n LOAM_IMPLEMENT,\n LOAM_CHECK,\n LOAM_VERIFY,\n LOAM_SHIP,\n];\n\n/**\n * Support entry points generated beside the lifecycle, but not counted as\n * lifecycle steps. Reporting a bad run must be discoverable in every profile;\n * placing it in COMMANDS would make a consumer iterating that list try to run\n * incident collection after every feature.\n */\nexport const SUPPORT: CommandContent[] = [LOAM_REPORT];\n\n/** Every command/skill file init generates, regardless of category. */\nexport const AGENT_COMMANDS: CommandContent[] = [...COMMANDS, ...SUPPORT];\n\n/**\n * Everything `loam instructions <name>` can print: the six workflows, support\n * protocol and five reference pages, in that order.\n *\n * The pages join the generated protocols HERE and nowhere else — not in\n * {@link AGENT_COMMANDS}, which is what scaffold.ts derives `SLASH_COMMANDS`\n * and `plannedCommandFiles` from. That is the whole mechanism, and the\n * asymmetry is the point: a page is printable by name but `loam init` writes no\n * file for it, so moving 44 KB out of AGENTS.md did not put 44 KB back as four\n * new artifacts in every repository loam touches. The support protocol does\n * belong in AGENT_COMMANDS because discovery is its purpose, while its separate\n * menu category keeps it out of the lifecycle. test/agents.test.ts asserts the\n * reference-page halves separately, because a future edit can break either\n * alone.\n */\nconst PRINTABLE: CommandContent[] = [...AGENT_COMMANDS, ...REFERENCES];\n\n/**\n * The printable bodies, keyed by name — what `loam instructions <name>` prints,\n * and the corpus every check over loam's agent-facing prose reads.\n *\n * Separate from SLASH_COMMANDS since the file became a pointer: the protocol is\n * still the thing that must document every stable code (`codes-drift`) and\n * every `loam …` line it teaches must still parse against the real CLI\n * (`agent-commands-runnable`). Those two properties are about the INSTRUCTIONS,\n * and they did not move just because the delivery did.\n *\n * The reference pages belong in this record for exactly that reason. Every code\n * they carry LEFT AGENTS.md to get here, and `codes-drift` reads\n * `AGENTS_MD + PROTOCOLS` — so the guard stays green by construction, because\n * the codes moved from one half of that corpus into the other. If it goes red\n * after a change here, something was deleted rather than moved.\n */\nexport const PROTOCOLS: Record<string, string> = Object.fromEntries(\n PRINTABLE.map((c) => [c.name, c.body]),\n);\n\n/**\n * What each page's `$1`, `$2`, … denote — see {@link CommandContent.placeholders}.\n * A reference page declares `[]`, which is not a formality: `placeholderProblems`\n * keys off this record, and a name absent from it is treated as unknown rather\n * than as taking no arguments.\n */\nexport const PLACEHOLDERS: Record<string, readonly PlaceholderKind[]> = Object.fromEntries(\n PRINTABLE.map((c) => [c.name, c.placeholders]),\n);\n\n/**\n * Whether nothing was supplied for this position — the two shapes an absent\n * argument actually arrives in, in one place because both call sites below owe\n * the same answer.\n *\n * The first is empty; {@link protocolFor} says which dialects send that. The\n * second is the placeholder ITSELF, arriving as data. One body serves twenty\n * tool dialects (tools/registry.ts) and keeps Claude's positional `$1`/`$2`\n * convention in all of them (see {@link CommandContent}), so every generated\n * stub carries the spelling verbatim: `.gemini/commands/loam/adopt.toml`\n * contains the literal line `loam instructions loam-adopt $1`. Gemini's own\n * convention is `{{args}}` and Copilot's is `${input:…}`, and Cline, Kilo Code\n * and Roo Code substitute nothing whatever — so on those three the `$1` reaches\n * this command exactly as written, and loam refused the literal first\n * instruction of its own workflow with `invalid-option`. (Unquoted in a POSIX\n * shell the same line degrades the other way: `$1` expands to empty, and the\n * agent receives a protocol addressed to nobody.) The same class already cost\n * `loam-check` its placeholder — see the comment in workflows/check.ts; this is\n * the general fix, made once in the RECEIVING command rather than per dialect.\n *\n * Scoped to `^\\$[1-9]$` and no wider. `{{args}}` and `${input:…}` are\n * deliberately NOT matched: the tools that spell placeholders that way\n * substitute them before an agent ever reads the file, so they cannot arrive\n * here, and loam emits neither. A value that merely CONTAINS a placeholder\n * (`FEAT-$1`) is a real argument and is still checked as one.\n */\nconst unsupplied = (arg: string | undefined): boolean =>\n arg === undefined || arg === \"\" || /^\\$[1-9]$/.test(arg);\n\n/**\n * Why the arguments given to `name` cannot be substituted into its protocol, or\n * null when they can. One sentence per bad argument, already naming the\n * placeholder it was meant to fill.\n *\n * The grammars are `core/kernel/ids/`'s, never a second copy: a value this accepts\n * and `loam adopt` refuses would be worse than no check, because the protocol\n * would still be wrong and now something had approved it. An argument nobody\n * supplied is not an error — `protocolFor` leaves that placeholder standing on\n * purpose, so the page reads as \"the service id goes here\" — and by\n * {@link unsupplied} that covers the placeholder text arriving as the argument,\n * which is what an untouched generated stub sends.\n */\nexport function placeholderProblems(name: string, args: readonly string[]): string[] | null {\n const kinds = PLACEHOLDERS[name];\n if (kinds === undefined) return null;\n const problems = kinds.flatMap((kind, i) => {\n const arg = args[i];\n // The `undefined` arm is `unsupplied`'s own; it is repeated here because\n // that is what narrows `arg` to a string for the id grammars below.\n if (arg === undefined || unsupplied(arg) || kind === \"free\") return [];\n const problem = kind === \"service\"\n ? serviceIdProblem(arg, `$${i + 1}`)\n : featureIdProblem(arg, `feature id ($${i + 1})`);\n return problem === null ? [] : [problem];\n });\n return problems.length === 0 ? null : problems;\n}\n\n/** One row of the `loam instructions` menu: enough to choose, and nothing more. */\ntype MenuRow = Pick<CommandContent, \"name\" | \"description\" | \"argumentHint\">;\n\nconst row = ({ name, description, argumentHint }: CommandContent): MenuRow =>\n ({ name, description, argumentHint });\n\n/** The workflow names, in cycle order — `loam instructions` with no argument lists these. */\nexport const WORKFLOWS: readonly MenuRow[] = COMMANDS.map(row);\n\n/** Support protocols, listed separately so no caller mistakes one for a lifecycle step. */\nexport const SUPPORT_PAGES: readonly MenuRow[] = SUPPORT.map(row);\n\n/**\n * The reference-page names, listed by the same bare `loam instructions` and\n * kept a SEPARATE list rather than appended to {@link WORKFLOWS}.\n *\n * A page is not a workflow: it has no steps, it is not part of the cycle, and\n * running one is not doing anything. A menu that ran the ten together would\n * read as a ten-step process, which is the one thing the six-step cycle must\n * not be confused with — so the command prints them under their own heading\n * (commands/instructions.ts) and test/instructions.test.ts pins that they stay\n * apart.\n */\nexport const REFERENCE_PAGES: readonly MenuRow[] = REFERENCES.map(row);\n\n/**\n * One workflow's protocol with `$1`, `$2`, … replaced by the arguments given.\n *\n * An unsupplied placeholder is LEFT STANDING rather than blanked: the bodies\n * are written so `$1` reads as \"the feature id goes here\", and a protocol that\n * silently dropped it would hand an agent `loam validate --feature --json` — a\n * command that parses, runs, and answers a different question. Extra arguments\n * are ignored for the same reason: this substitutes, it does not validate.\n *\n * \"Unsupplied\" is {@link unsupplied}'s two shapes, not merely a missing\n * element, and neither is pedantry — they are the two things a tool actually\n * sends. An EMPTY argument is the first: several dialects expand an absent\n * positional to the empty string, and `loam-feature`'s own invocation quotes\n * its second one (`--title \"$2\"`), so `/loam-feature FEAT-101` with no title\n * arrives here as `[\"FEAT-101\", \"\"]`. Blanking it produced\n * `loam new FEAT-101 --title \"\"` — which is exactly the failure the paragraph\n * above describes, reached by the one path that paragraph did not cover: the\n * command succeeds, and writes a feature whose title is the empty string and\n * whose intent.md opens with a bare `#`.\n *\n * The LITERAL PLACEHOLDER is the second: the dialects that substitute nothing\n * hand this command the `$1` their generated stub was written with, so\n * `loam instructions loam-adopt $1` renders the same page as\n * `loam instructions loam-adopt` — the placeholder standing, the protocol\n * printed. Here the shape mostly falls out anyway (planting `$1` where `$1`\n * stood is a no-op); it is spelled all the same, because a MISNUMBERED one\n * would not be — `$3` given for `$1` would renumber the placeholder in the\n * printed page — and because the check above and this render have to agree on\n * one definition or a value can pass one and be rewritten by the other.\n */\nexport function protocolFor(name: string, args: readonly string[] = []): string | null {\n const body = PROTOCOLS[name];\n if (body === undefined) return null;\n return body.replace(/\\$([1-9])/g, (whole, digit: string) => {\n const arg = args[Number(digit) - 1];\n return arg === undefined || unsupplied(arg) ? whole : arg;\n });\n}\n"]}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The generated FILES: what a pointer file contains (the stub), what this
|
|
3
|
+
* binary would write (SLASH_COMMANDS, plannedCommandFiles), and how the files
|
|
4
|
+
* land and are detected on disk.
|
|
5
|
+
*
|
|
6
|
+
* The command and skill files go into the repo `init` runs in, because that is
|
|
7
|
+
* where the agent is invoked — for whichever tools the repo shows signs of, via
|
|
8
|
+
* the AGENT_TOOLS registry (tools/registry.ts): one shared body, a per-tool
|
|
9
|
+
* path and wrapper. A delivery is refreshed only while its bytes still match
|
|
10
|
+
* the digest loam recorded when it wrote them; a team's edits revoke that
|
|
11
|
+
* authority and outrank ours.
|
|
12
|
+
*
|
|
13
|
+
* Two deliveries, one body. A slash command has to be TYPED, so it only ever
|
|
14
|
+
* reaches an agent whose operator already knows loam exists. A skill is loaded
|
|
15
|
+
* by the model itself when the task matches its `description`, which is how the
|
|
16
|
+
* protocol reaches an agent that was never told about it. That difference is
|
|
17
|
+
* the whole reason both are written by default.
|
|
18
|
+
*
|
|
19
|
+
* The per-tool command and skill files carry the same version stamp AGENTS.md
|
|
20
|
+
* does (agents-md.ts), for the same reason and with the same answer:
|
|
21
|
+
* `loam doctor` reports `doctor.agent-files-stale` without writing. A later
|
|
22
|
+
* `loam init` can refresh only a digest-matched pointer. Without the stamp,
|
|
23
|
+
* absence was the only drift doctor could see — a command file mangled to one
|
|
24
|
+
* line left it saying `healthy: true`, which across a hundred repositories is
|
|
25
|
+
* invisible rot with no repair path.
|
|
26
|
+
*/
|
|
27
|
+
import { createHash } from "node:crypto";
|
|
28
|
+
import { existsSync } from "node:fs";
|
|
29
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
30
|
+
import { dirname, join, relative } from "node:path";
|
|
31
|
+
import { agentsStampLine } from "./agents-stamp.js";
|
|
32
|
+
import { LOAM_VERSION } from "../envelope/version.js";
|
|
33
|
+
import { AGENT_COMMANDS } from "./protocol.js";
|
|
34
|
+
import { AGENT_TOOLS, CLAUDE } from "./tools/registry.js";
|
|
35
|
+
/**
|
|
36
|
+
* What a generated file actually contains: the purpose, the spine, and the
|
|
37
|
+
* command that prints the rest.
|
|
38
|
+
*
|
|
39
|
+
* The protocol itself stays in `body` and ships inside the binary, reachable as
|
|
40
|
+
* `loam instructions <name>`. The file on disk gets a pointer to it, because
|
|
41
|
+
* these two things go stale in opposite directions and only one of them can be
|
|
42
|
+
* fixed. A generated file is refreshed only while its bytes still match the
|
|
43
|
+
* digest loam recorded; any edit revokes that authority because your edits
|
|
44
|
+
* outrank the template. Without that distinction a repo scaffolded a year ago
|
|
45
|
+
* holds a year-old protocol: exact
|
|
46
|
+
* flags, exact finding codes, exact step order, all of it asserted with total
|
|
47
|
+
* confidence by a file whose reader has no way to know it is describing a
|
|
48
|
+
* different release. That is not a hypothetical failure mode. It is the one
|
|
49
|
+
* every project shipping generated agent instructions has had, and the fix
|
|
50
|
+
* everybody reaches for — regenerate on upgrade — trades it for silently
|
|
51
|
+
* overwriting what a human wrote.
|
|
52
|
+
*
|
|
53
|
+
* Thinning the file is the third option. What remains is what does not move
|
|
54
|
+
* between releases: what this workflow is for, and the verbs in order. What
|
|
55
|
+
* leaves is everything version-shaped. `doctor.agent-files-stale` still reports
|
|
56
|
+
* a file whose stamp has fallen behind — once its body, stamp aside, is no
|
|
57
|
+
* longer the one this binary writes — and now has almost nothing to be right
|
|
58
|
+
* about, which is the point.
|
|
59
|
+
*
|
|
60
|
+
* The trade is real and worth stating: an agent that cannot execute `loam` now
|
|
61
|
+
* has a spine instead of a protocol. That is the correct failure. The exact
|
|
62
|
+
* diagnostic and lifecycle invocations belong to the binary-owned page; an
|
|
63
|
+
* agent that cannot run loam cannot finish either kind from an embedded copy —
|
|
64
|
+
* it can only try using a year-old flag.
|
|
65
|
+
*
|
|
66
|
+
* The last clause of the pointer is the one sentence here that changes what an
|
|
67
|
+
* agent DOES rather than what it knows. `loam instructions loam-check` prints
|
|
68
|
+
* the largest page loam has — 109 KB measured 2026-10-10 (84 KB when this was
|
|
69
|
+
* first written), about a quarter of a 100k-token window, and hundreds of
|
|
70
|
+
* fix-table rows of which a run needs two or three — and every file written
|
|
71
|
+
* from this stub opens by telling the agent to run it. `--no-fix-tables`
|
|
72
|
+
* (commands/instructions.ts) drops the rows, and `loam explain <code>` answers
|
|
73
|
+
* the one row the run turned out to need on its own. The flag is what makes
|
|
74
|
+
* the lazy path payable; this sentence is what makes an agent take it.
|
|
75
|
+
*/
|
|
76
|
+
function stubBody(c) {
|
|
77
|
+
const steps = c.spine.map((s, i) => ` ${i + 1}. ${s}`).join("\n");
|
|
78
|
+
const entry = c.name === "loam-report"
|
|
79
|
+
? `This support protocol has two equivalent chat entry points: the explicit command a
|
|
80
|
+
user chooses, and the Agent Skill an unexpected-run request may load. Both reach
|
|
81
|
+
the same local, sanitized report; the agent owns the diagnostic steps.`
|
|
82
|
+
: `This workflow has two equivalent chat entry points: the explicit command a user
|
|
83
|
+
chooses, and the Agent Skill a natural-language request may load. Both reach this
|
|
84
|
+
same body and must produce the same status/edit/validate loop; do not make the
|
|
85
|
+
user type the internal loam commands one by one.`;
|
|
86
|
+
const output = c.name === "loam-report"
|
|
87
|
+
? `The runtime protocol decides which diagnostics are safe to run and what may enter the
|
|
88
|
+
report. Do not infer permission to retry a writer, repair files or send the result
|
|
89
|
+
from the broader lifecycle commands another generated skill may allow.`
|
|
90
|
+
: `Every step above is a \`loam\` invocation, and each command's own \`--json\` output
|
|
91
|
+
carries what to do next: findings have stable codes, and \`loam status --json\` puts
|
|
92
|
+
the ordered \`next[]\` — each entry a code and the literal command — in one place.
|
|
93
|
+
Branch on the codes, never on the prose. The check workflow starts with
|
|
94
|
+
\`--no-fix-tables\`; use \`loam explain <code>\` for each code the run actually
|
|
95
|
+
reports, and remove that flag only when you deliberately need the complete table.`;
|
|
96
|
+
return `${c.purpose}
|
|
97
|
+
|
|
98
|
+
${entry}
|
|
99
|
+
|
|
100
|
+
**Run this first.** It is the protocol, and it ships with the binary you are about
|
|
101
|
+
to call — so it names this loam's flags, its finding codes and its fix tables,
|
|
102
|
+
not the ones that were current when this repository was scaffolded:
|
|
103
|
+
|
|
104
|
+
${c.invocation}
|
|
105
|
+
|
|
106
|
+
The spine it fills in, so you can tell a run that went sideways from one that did not:
|
|
107
|
+
|
|
108
|
+
${steps}
|
|
109
|
+
|
|
110
|
+
${output}
|
|
111
|
+
|
|
112
|
+
This file is a pointer, not the protocol. loam may refresh it while its bytes still
|
|
113
|
+
match the digest recorded in loam.json. Editing it revokes that authority: your
|
|
114
|
+
changes outrank the template and stay untouched. Where this file and
|
|
115
|
+
\`loam instructions\` disagree, the command is right.
|
|
116
|
+
`;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* The command body a file actually gets: the pointer, under the same version
|
|
120
|
+
* stamp AGENTS.md carries.
|
|
121
|
+
*
|
|
122
|
+
* The stamp is applied once, here, rather than in twenty wrappers — it is a
|
|
123
|
+
* fact about loam, not about a tool's dialect, and a per-wrapper copy is twenty
|
|
124
|
+
* chances to forget it. It rides at the top of the BODY (not the file) because
|
|
125
|
+
* every dialect puts something of its own first: YAML frontmatter, a TOML key,
|
|
126
|
+
* a title line. An HTML comment is invisible in all of them, and
|
|
127
|
+
* `agentsStampVersion` matches it wherever in the file it lands.
|
|
128
|
+
*
|
|
129
|
+
* A repo initialized before stamping existed has unstamped files, which is
|
|
130
|
+
* exactly what `doctor.agent-files-stale` is for: nobody has confirmed that
|
|
131
|
+
* those instructions still describe this binary.
|
|
132
|
+
*/
|
|
133
|
+
const stubbed = (c) => ({
|
|
134
|
+
...c,
|
|
135
|
+
body: `${agentsStampLine(LOAM_VERSION)}\n\n${stubBody(c)}`,
|
|
136
|
+
});
|
|
137
|
+
/**
|
|
138
|
+
* The Claude-format files, keyed by command name: exactly what **this** binary
|
|
139
|
+
* would write, derived through the same adapter that writes them, so the export
|
|
140
|
+
* and a freshly scaffolded repo can never disagree.
|
|
141
|
+
*
|
|
142
|
+
* Read that scope literally. It used to be described as the on-disk contract of
|
|
143
|
+
* every repo initialized before `--tools` existed, and that is no longer true
|
|
144
|
+
* of anything but a fresh scaffold: a file holds the STUB now, every repo
|
|
145
|
+
* scaffolded before that holds the full protocol. A recorded, byte-identical
|
|
146
|
+
* pointer can refresh; an older unrecorded file or any customized file cannot,
|
|
147
|
+
* so an export cannot describe files this binary did not write.
|
|
148
|
+
*
|
|
149
|
+
* The protocol those older files carry is `PROTOCOLS`. Anything asserting on
|
|
150
|
+
* protocol content wants that one — this answers "what would loam write here",
|
|
151
|
+
* not "what does loam instruct".
|
|
152
|
+
*/
|
|
153
|
+
export const SLASH_COMMANDS = Object.fromEntries(AGENT_COMMANDS.map((c) => [c.name, CLAUDE.format(stubbed(c))]));
|
|
154
|
+
/** The two ways a command body reaches an agent. Both are on by default. */
|
|
155
|
+
export const DELIVERIES = ["commands", "skills"];
|
|
156
|
+
export const AGENT_PROFILES = ["full", "service", "docs"];
|
|
157
|
+
const PROFILE_COMMANDS = {
|
|
158
|
+
full: new Set(AGENT_COMMANDS.map((command) => command.name)),
|
|
159
|
+
service: new Set(["loam-adopt", "loam-implement", "loam-check", "loam-verify", "loam-report"]),
|
|
160
|
+
docs: new Set(["loam-feature", "loam-check", "loam-ship", "loam-report"]),
|
|
161
|
+
};
|
|
162
|
+
/**
|
|
163
|
+
* Every file the selected tools would lay down, in creation order — the same
|
|
164
|
+
* list `init` probes for `skipped` BEFORE the scaffold runs, so created +
|
|
165
|
+
* skipped is the same list on every repo.
|
|
166
|
+
*
|
|
167
|
+
* Called with two arguments it returns EVERYTHING the binary would write under
|
|
168
|
+
* default delivery: commands and skills both. That is the contract callers
|
|
169
|
+
* outside this module depend on — `loam doctor` asks "what should be here?"
|
|
170
|
+
* and a half-answer would report a fully-scaffolded repo as fully scaffolded
|
|
171
|
+
* while ignoring every skill file. The name predates the second delivery and is
|
|
172
|
+
* kept because it is imported elsewhere; `delivery` narrows it.
|
|
173
|
+
*/
|
|
174
|
+
export function plannedCommandFiles(cwd, toolIds, delivery = DELIVERIES, profile = "full") {
|
|
175
|
+
return toolIds.flatMap((id) => {
|
|
176
|
+
const tool = AGENT_TOOLS[id];
|
|
177
|
+
if (tool === undefined)
|
|
178
|
+
throw new Error(`unknown agent tool: ${id}`);
|
|
179
|
+
const emitters = [];
|
|
180
|
+
// A tool declares only the deliveries it actually reads, so an absent
|
|
181
|
+
// emitter is a fact about the tool, never a reason to fall back to some
|
|
182
|
+
// other tool's convention.
|
|
183
|
+
const { path, format, skill } = tool;
|
|
184
|
+
if (delivery.includes("commands") && path !== undefined && format !== undefined) {
|
|
185
|
+
emitters.push({ path, format });
|
|
186
|
+
}
|
|
187
|
+
if (delivery.includes("skills") && skill !== undefined)
|
|
188
|
+
emitters.push(skill);
|
|
189
|
+
return emitters.flatMap((e) => AGENT_COMMANDS.filter((command) => PROFILE_COMMANDS[profile].has(command.name)).map((c) => ({
|
|
190
|
+
path: join(cwd, ...e.path(c.name)),
|
|
191
|
+
content: e.format(stubbed(c)),
|
|
192
|
+
})));
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
function contentDigest(content) {
|
|
196
|
+
return createHash("sha256").update(content).digest("hex");
|
|
197
|
+
}
|
|
198
|
+
function manifestPath(cwd, path) {
|
|
199
|
+
return relative(cwd, path).replaceAll("\\", "/");
|
|
200
|
+
}
|
|
201
|
+
export function updatedAgentFileManifest(cwd, planned, existing, managed) {
|
|
202
|
+
const out = { ...existing };
|
|
203
|
+
for (const file of planned)
|
|
204
|
+
delete out[manifestPath(cwd, file.path)];
|
|
205
|
+
return Object.assign(out, managed);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Create missing files and refresh only files still byte-identical to the
|
|
209
|
+
* digest recorded when loam last wrote them. A human edit breaks that equality
|
|
210
|
+
* and therefore revokes loam's authority over the file without a marker block
|
|
211
|
+
* or a prompt.
|
|
212
|
+
*/
|
|
213
|
+
export async function syncAgentCommands(req) {
|
|
214
|
+
const { cwd, toolIds = ["claude"], delivery = DELIVERIES, profile = "full", known = {} } = req;
|
|
215
|
+
const out = { created: [], refreshed: [], managed: {} };
|
|
216
|
+
for (const { path, content } of plannedCommandFiles(cwd, toolIds, delivery, profile)) {
|
|
217
|
+
const key = manifestPath(cwd, path);
|
|
218
|
+
const desired = contentDigest(content);
|
|
219
|
+
if (!existsSync(path)) {
|
|
220
|
+
await mkdir(dirname(path), { recursive: true });
|
|
221
|
+
await writeFile(path, content, "utf8");
|
|
222
|
+
out.created.push(path);
|
|
223
|
+
out.managed[key] = desired;
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
const current = contentDigest(await readFile(path));
|
|
227
|
+
if (current === desired) {
|
|
228
|
+
out.managed[key] = desired;
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (known[key] !== current)
|
|
232
|
+
continue;
|
|
233
|
+
await writeFile(path, content, "utf8");
|
|
234
|
+
out.refreshed.push(path);
|
|
235
|
+
out.managed[key] = desired;
|
|
236
|
+
}
|
|
237
|
+
return out;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* The registry ids whose marker paths are present in `cwd` — what `loam init`
|
|
241
|
+
* writes for when nobody passed `--tools`.
|
|
242
|
+
*
|
|
243
|
+
* A repo with `.cursor/` and no Claude Code used to get `.claude/commands/`
|
|
244
|
+
* and nothing it could actually run. Presence is the whole test, and existence
|
|
245
|
+
* (not directory-ness) is what is asked, because a marker is as often a file as
|
|
246
|
+
* a directory — `.github/copilot-instructions.md` is the honest signal for
|
|
247
|
+
* Copilot where `.github/` itself is noise.
|
|
248
|
+
*/
|
|
249
|
+
export function detectAgentTools(cwd) {
|
|
250
|
+
return Object.entries(AGENT_TOOLS)
|
|
251
|
+
.filter(([, tool]) => tool.detect.some((marker) => existsSync(join(cwd, marker))))
|
|
252
|
+
.map(([id]) => id);
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=scaffold.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../../../src/core/agent/scaffold.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The generated FILES: what a pointer file contains (the stub), what this\n * binary would write (SLASH_COMMANDS, plannedCommandFiles), and how the files\n * land and are detected on disk.\n *\n * The command and skill files go into the repo `init` runs in, because that is\n * where the agent is invoked — for whichever tools the repo shows signs of, via\n * the AGENT_TOOLS registry (tools/registry.ts): one shared body, a per-tool\n * path and wrapper. A delivery is refreshed only while its bytes still match\n * the digest loam recorded when it wrote them; a team's edits revoke that\n * authority and outrank ours.\n *\n * Two deliveries, one body. A slash command has to be TYPED, so it only ever\n * reaches an agent whose operator already knows loam exists. A skill is loaded\n * by the model itself when the task matches its `description`, which is how the\n * protocol reaches an agent that was never told about it. That difference is\n * the whole reason both are written by default.\n *\n * The per-tool command and skill files carry the same version stamp AGENTS.md\n * does (agents-md.ts), for the same reason and with the same answer:\n * `loam doctor` reports `doctor.agent-files-stale` without writing. A later\n * `loam init` can refresh only a digest-matched pointer. Without the stamp,\n * absence was the only drift doctor could see — a command file mangled to one\n * line left it saying `healthy: true`, which across a hundred repositories is\n * invisible rot with no repair path.\n */\nimport { createHash } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { dirname, join, relative } from \"node:path\";\nimport { agentsStampLine } from \"./agents-stamp.js\";\nimport { LOAM_VERSION } from \"../envelope/version.js\";\nimport type { AgentFileEmitter, CommandContent } from \"./contract.js\";\nimport { AGENT_COMMANDS } from \"./protocol.js\";\nimport { AGENT_TOOLS, CLAUDE } from \"./tools/registry.js\";\n\n/**\n * What a generated file actually contains: the purpose, the spine, and the\n * command that prints the rest.\n *\n * The protocol itself stays in `body` and ships inside the binary, reachable as\n * `loam instructions <name>`. The file on disk gets a pointer to it, because\n * these two things go stale in opposite directions and only one of them can be\n * fixed. A generated file is refreshed only while its bytes still match the\n * digest loam recorded; any edit revokes that authority because your edits\n * outrank the template. Without that distinction a repo scaffolded a year ago\n * holds a year-old protocol: exact\n * flags, exact finding codes, exact step order, all of it asserted with total\n * confidence by a file whose reader has no way to know it is describing a\n * different release. That is not a hypothetical failure mode. It is the one\n * every project shipping generated agent instructions has had, and the fix\n * everybody reaches for — regenerate on upgrade — trades it for silently\n * overwriting what a human wrote.\n *\n * Thinning the file is the third option. What remains is what does not move\n * between releases: what this workflow is for, and the verbs in order. What\n * leaves is everything version-shaped. `doctor.agent-files-stale` still reports\n * a file whose stamp has fallen behind — once its body, stamp aside, is no\n * longer the one this binary writes — and now has almost nothing to be right\n * about, which is the point.\n *\n * The trade is real and worth stating: an agent that cannot execute `loam` now\n * has a spine instead of a protocol. That is the correct failure. The exact\n * diagnostic and lifecycle invocations belong to the binary-owned page; an\n * agent that cannot run loam cannot finish either kind from an embedded copy —\n * it can only try using a year-old flag.\n *\n * The last clause of the pointer is the one sentence here that changes what an\n * agent DOES rather than what it knows. `loam instructions loam-check` prints\n * the largest page loam has — 109 KB measured 2026-10-10 (84 KB when this was\n * first written), about a quarter of a 100k-token window, and hundreds of\n * fix-table rows of which a run needs two or three — and every file written\n * from this stub opens by telling the agent to run it. `--no-fix-tables`\n * (commands/instructions.ts) drops the rows, and `loam explain <code>` answers\n * the one row the run turned out to need on its own. The flag is what makes\n * the lazy path payable; this sentence is what makes an agent take it.\n */\nfunction stubBody(c: CommandContent): string {\n const steps = c.spine.map((s, i) => ` ${i + 1}. ${s}`).join(\"\\n\");\n const entry = c.name === \"loam-report\"\n ? `This support protocol has two equivalent chat entry points: the explicit command a\nuser chooses, and the Agent Skill an unexpected-run request may load. Both reach\nthe same local, sanitized report; the agent owns the diagnostic steps.`\n : `This workflow has two equivalent chat entry points: the explicit command a user\nchooses, and the Agent Skill a natural-language request may load. Both reach this\nsame body and must produce the same status/edit/validate loop; do not make the\nuser type the internal loam commands one by one.`;\n const output = c.name === \"loam-report\"\n ? `The runtime protocol decides which diagnostics are safe to run and what may enter the\nreport. Do not infer permission to retry a writer, repair files or send the result\nfrom the broader lifecycle commands another generated skill may allow.`\n : `Every step above is a \\`loam\\` invocation, and each command's own \\`--json\\` output\ncarries what to do next: findings have stable codes, and \\`loam status --json\\` puts\nthe ordered \\`next[]\\` — each entry a code and the literal command — in one place.\nBranch on the codes, never on the prose. The check workflow starts with\n\\`--no-fix-tables\\`; use \\`loam explain <code>\\` for each code the run actually\nreports, and remove that flag only when you deliberately need the complete table.`;\n return `${c.purpose}\n\n${entry}\n\n**Run this first.** It is the protocol, and it ships with the binary you are about\nto call — so it names this loam's flags, its finding codes and its fix tables,\nnot the ones that were current when this repository was scaffolded:\n\n ${c.invocation}\n\nThe spine it fills in, so you can tell a run that went sideways from one that did not:\n\n${steps}\n\n${output}\n\nThis file is a pointer, not the protocol. loam may refresh it while its bytes still\nmatch the digest recorded in loam.json. Editing it revokes that authority: your\nchanges outrank the template and stay untouched. Where this file and\n\\`loam instructions\\` disagree, the command is right.\n`;\n}\n\n/**\n * The command body a file actually gets: the pointer, under the same version\n * stamp AGENTS.md carries.\n *\n * The stamp is applied once, here, rather than in twenty wrappers — it is a\n * fact about loam, not about a tool's dialect, and a per-wrapper copy is twenty\n * chances to forget it. It rides at the top of the BODY (not the file) because\n * every dialect puts something of its own first: YAML frontmatter, a TOML key,\n * a title line. An HTML comment is invisible in all of them, and\n * `agentsStampVersion` matches it wherever in the file it lands.\n *\n * A repo initialized before stamping existed has unstamped files, which is\n * exactly what `doctor.agent-files-stale` is for: nobody has confirmed that\n * those instructions still describe this binary.\n */\nconst stubbed = (c: CommandContent): CommandContent => ({\n ...c,\n body: `${agentsStampLine(LOAM_VERSION)}\\n\\n${stubBody(c)}`,\n});\n\n/**\n * The Claude-format files, keyed by command name: exactly what **this** binary\n * would write, derived through the same adapter that writes them, so the export\n * and a freshly scaffolded repo can never disagree.\n *\n * Read that scope literally. It used to be described as the on-disk contract of\n * every repo initialized before `--tools` existed, and that is no longer true\n * of anything but a fresh scaffold: a file holds the STUB now, every repo\n * scaffolded before that holds the full protocol. A recorded, byte-identical\n * pointer can refresh; an older unrecorded file or any customized file cannot,\n * so an export cannot describe files this binary did not write.\n *\n * The protocol those older files carry is `PROTOCOLS`. Anything asserting on\n * protocol content wants that one — this answers \"what would loam write here\",\n * not \"what does loam instruct\".\n */\nexport const SLASH_COMMANDS: Record<string, string> = Object.fromEntries(\n AGENT_COMMANDS.map((c) => [c.name, CLAUDE.format(stubbed(c))]),\n);\n\n/** The two ways a command body reaches an agent. Both are on by default. */\nexport const DELIVERIES = [\"commands\", \"skills\"] as const;\nexport type Delivery = (typeof DELIVERIES)[number];\n\nexport const AGENT_PROFILES = [\"full\", \"service\", \"docs\"] as const;\nexport type AgentProfile = (typeof AGENT_PROFILES)[number];\n\nconst PROFILE_COMMANDS: Record<AgentProfile, ReadonlySet<string>> = {\n full: new Set(AGENT_COMMANDS.map((command) => command.name)),\n service: new Set([\"loam-adopt\", \"loam-implement\", \"loam-check\", \"loam-verify\", \"loam-report\"]),\n docs: new Set([\"loam-feature\", \"loam-check\", \"loam-ship\", \"loam-report\"]),\n};\n\n/**\n * Every file the selected tools would lay down, in creation order — the same\n * list `init` probes for `skipped` BEFORE the scaffold runs, so created +\n * skipped is the same list on every repo.\n *\n * Called with two arguments it returns EVERYTHING the binary would write under\n * default delivery: commands and skills both. That is the contract callers\n * outside this module depend on — `loam doctor` asks \"what should be here?\"\n * and a half-answer would report a fully-scaffolded repo as fully scaffolded\n * while ignoring every skill file. The name predates the second delivery and is\n * kept because it is imported elsewhere; `delivery` narrows it.\n */\nexport function plannedCommandFiles(\n cwd: string,\n toolIds: string[],\n delivery: readonly Delivery[] = DELIVERIES,\n profile: AgentProfile = \"full\",\n): Array<{ path: string; content: string }> {\n return toolIds.flatMap((id) => {\n const tool = AGENT_TOOLS[id];\n if (tool === undefined) throw new Error(`unknown agent tool: ${id}`);\n const emitters: AgentFileEmitter[] = [];\n // A tool declares only the deliveries it actually reads, so an absent\n // emitter is a fact about the tool, never a reason to fall back to some\n // other tool's convention.\n const { path, format, skill } = tool;\n if (delivery.includes(\"commands\") && path !== undefined && format !== undefined) {\n emitters.push({ path, format });\n }\n if (delivery.includes(\"skills\") && skill !== undefined) emitters.push(skill);\n return emitters.flatMap((e) =>\n AGENT_COMMANDS.filter((command) => PROFILE_COMMANDS[profile].has(command.name)).map((c) => ({\n path: join(cwd, ...e.path(c.name)),\n content: e.format(stubbed(c)),\n })),\n );\n });\n}\n\nfunction contentDigest(content: string | Buffer): string {\n return createHash(\"sha256\").update(content).digest(\"hex\");\n}\n\nfunction manifestPath(cwd: string, path: string): string {\n return relative(cwd, path).replaceAll(\"\\\\\", \"/\");\n}\n\nexport function updatedAgentFileManifest(\n cwd: string,\n planned: Array<{ path: string }>,\n existing: Readonly<Record<string, string>> | undefined,\n managed: Readonly<Record<string, string>>,\n): Record<string, string> {\n const out = { ...existing };\n for (const file of planned) delete out[manifestPath(cwd, file.path)];\n return Object.assign(out, managed);\n}\n\nexport interface AgentFileSync {\n created: string[];\n refreshed: string[];\n /** Repo-relative path -> digest of the bytes loam is allowed to refresh. */\n managed: Record<string, string>;\n}\n\n/**\n * Create missing files and refresh only files still byte-identical to the\n * digest recorded when loam last wrote them. A human edit breaks that equality\n * and therefore revokes loam's authority over the file without a marker block\n * or a prompt.\n */\nexport async function syncAgentCommands(req: {\n cwd: string;\n toolIds?: string[];\n delivery?: readonly Delivery[];\n profile?: AgentProfile;\n known?: Readonly<Record<string, string>>;\n}): Promise<AgentFileSync> {\n const { cwd, toolIds = [\"claude\"], delivery = DELIVERIES, profile = \"full\", known = {} } = req;\n const out: AgentFileSync = { created: [], refreshed: [], managed: {} };\n for (const { path, content } of plannedCommandFiles(cwd, toolIds, delivery, profile)) {\n const key = manifestPath(cwd, path);\n const desired = contentDigest(content);\n if (!existsSync(path)) {\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, content, \"utf8\");\n out.created.push(path);\n out.managed[key] = desired;\n continue;\n }\n const current = contentDigest(await readFile(path));\n if (current === desired) {\n out.managed[key] = desired;\n continue;\n }\n if (known[key] !== current) continue;\n await writeFile(path, content, \"utf8\");\n out.refreshed.push(path);\n out.managed[key] = desired;\n }\n return out;\n}\n\n/**\n * The registry ids whose marker paths are present in `cwd` — what `loam init`\n * writes for when nobody passed `--tools`.\n *\n * A repo with `.cursor/` and no Claude Code used to get `.claude/commands/`\n * and nothing it could actually run. Presence is the whole test, and existence\n * (not directory-ness) is what is asked, because a marker is as often a file as\n * a directory — `.github/copilot-instructions.md` is the honest signal for\n * Copilot where `.github/` itself is noise.\n */\nexport function detectAgentTools(cwd: string): string[] {\n return Object.entries(AGENT_TOOLS)\n .filter(([, tool]) => tool.detect.some((marker) => existsSync(join(cwd, marker))))\n .map(([id]) => id);\n}\n"]}
|