@ybotok/loam 0.2.0-alpha.6 → 0.2.0-alpha.9
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 +1477 -1
- package/COMPARISON.md +91 -3
- package/CONTRIBUTING.md +37 -0
- package/MIGRATING-from-OpenSpec.md +40 -22
- package/QUICKSTART.md +181 -9
- package/README.md +256 -57
- package/ROADMAP.md +108 -11
- package/SCHEMA.md +721 -130
- package/WORKFLOW.md +272 -62
- package/dist/cli.js +26 -8
- package/dist/cli.js.map +1 -1
- package/dist/commands/adopt/adopt.js +5 -10
- package/dist/commands/adopt/adopt.js.map +1 -1
- package/dist/commands/archive/archive.js +15 -18
- package/dist/commands/archive/archive.js.map +1 -1
- package/dist/commands/archive/plan/contracts/asyncapi.js +27 -41
- package/dist/commands/archive/plan/contracts/asyncapi.js.map +1 -1
- package/dist/commands/archive/plan/contracts/consumers.js +56 -0
- package/dist/commands/archive/plan/contracts/consumers.js.map +1 -0
- package/dist/commands/archive/plan/contracts/openapi.js +25 -42
- package/dist/commands/archive/plan/contracts/openapi.js.map +1 -1
- package/dist/commands/archive/plan/contracts/verdict-lines.js +41 -0
- package/dist/commands/archive/plan/contracts/verdict-lines.js.map +1 -0
- package/dist/commands/archive/plan/gate.js +3 -7
- package/dist/commands/archive/plan/gate.js.map +1 -1
- package/dist/commands/archive/plan/landscape.js +4 -4
- package/dist/commands/archive/plan/landscape.js.map +1 -1
- package/dist/commands/archive/plan/refusal.js +8 -18
- package/dist/commands/archive/plan/refusal.js.map +1 -1
- package/dist/commands/archive/plan/specs.js +134 -25
- package/dist/commands/archive/plan/specs.js.map +1 -1
- package/dist/commands/archive/plan/state.js +1 -0
- package/dist/commands/archive/plan/state.js.map +1 -1
- package/dist/commands/archive/run.js +82 -33
- package/dist/commands/archive/run.js.map +1 -1
- package/dist/commands/archive/shipped.js +49 -0
- package/dist/commands/archive/shipped.js.map +1 -0
- package/dist/commands/context/context.js +4 -7
- package/dist/commands/context/context.js.map +1 -1
- package/dist/commands/context/print.js +2 -2
- package/dist/commands/context/print.js.map +1 -1
- package/dist/commands/delta/delta.js +44 -12
- package/dist/commands/delta/delta.js.map +1 -1
- package/dist/commands/delta/print.js +1 -1
- package/dist/commands/delta/print.js.map +1 -1
- package/dist/commands/dependencies.js +3 -7
- package/dist/commands/dependencies.js.map +1 -1
- package/dist/commands/diff/diff.js +20 -27
- package/dist/commands/diff/diff.js.map +1 -1
- package/dist/commands/explore.js +4 -8
- package/dist/commands/explore.js.map +1 -1
- package/dist/commands/gate/gate.js +45 -8
- package/dist/commands/gate/gate.js.map +1 -1
- package/dist/commands/gate/print.js +15 -3
- package/dist/commands/gate/print.js.map +1 -1
- package/dist/commands/gherkin/commit.js +13 -54
- package/dist/commands/gherkin/commit.js.map +1 -1
- package/dist/commands/gherkin/gherkin.js +36 -20
- package/dist/commands/gherkin/gherkin.js.map +1 -1
- package/dist/commands/gherkin/reconcile.js +10 -13
- package/dist/commands/gherkin/reconcile.js.map +1 -1
- package/dist/commands/init/first-hour.js +44 -0
- package/dist/commands/init/first-hour.js.map +1 -1
- package/dist/commands/init/init.js +18 -22
- package/dist/commands/init/init.js.map +1 -1
- package/dist/commands/list/campaign/campaign.js +4 -6
- package/dist/commands/list/campaign/campaign.js.map +1 -1
- package/dist/commands/list/json.js +0 -4
- package/dist/commands/list/json.js.map +1 -1
- package/dist/commands/list/list.js +38 -23
- package/dist/commands/list/list.js.map +1 -1
- package/dist/commands/list/print.js +38 -6
- package/dist/commands/list/print.js.map +1 -1
- package/dist/commands/list/suites/suites.js +140 -0
- package/dist/commands/list/suites/suites.js.map +1 -0
- package/dist/commands/list/views.js +28 -33
- package/dist/commands/list/views.js.map +1 -1
- package/dist/commands/mcp/dispatch.js +91 -36
- package/dist/commands/mcp/dispatch.js.map +1 -1
- package/dist/commands/mcp/mcp.js +56 -15
- package/dist/commands/mcp/mcp.js.map +1 -1
- package/dist/commands/mcp/serve.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/active.js +27 -22
- package/dist/commands/migrate-openspec/materialize/active.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/stage.js +4 -3
- package/dist/commands/migrate-openspec/materialize/stage.js.map +1 -1
- package/dist/commands/migrate-openspec/materialize/target.js +2 -2
- package/dist/commands/migrate-openspec/materialize/target.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/decisions.js +9 -14
- package/dist/commands/migrate-openspec/openspec/decisions.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/error.js +7 -8
- package/dist/commands/migrate-openspec/openspec/error.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/mapping.js +1 -9
- package/dist/commands/migrate-openspec/openspec/mapping.js.map +1 -1
- package/dist/commands/migrate-openspec/openspec/paths.js +3 -6
- package/dist/commands/migrate-openspec/openspec/paths.js.map +1 -1
- package/dist/commands/new/capability-template.js +118 -0
- package/dist/commands/new/capability-template.js.map +1 -0
- package/dist/commands/new/commit.js +8 -22
- package/dist/commands/new/commit.js.map +1 -1
- package/dist/commands/new/modifies.js +206 -0
- package/dist/commands/new/modifies.js.map +1 -0
- package/dist/commands/new/new.js +59 -14
- package/dist/commands/new/new.js.map +1 -1
- package/dist/commands/new/templates.js +48 -124
- package/dist/commands/new/templates.js.map +1 -1
- package/dist/commands/open.js +3 -7
- package/dist/commands/open.js.map +1 -1
- package/dist/commands/policy/gate.js +27 -0
- package/dist/commands/policy/gate.js.map +1 -1
- package/dist/commands/rebase/plan.js +2 -2
- package/dist/commands/rebase/plan.js.map +1 -1
- package/dist/commands/rebase/rebase.js +60 -35
- package/dist/commands/rebase/rebase.js.map +1 -1
- package/dist/commands/seed/commit.js +55 -26
- package/dist/commands/seed/commit.js.map +1 -1
- package/dist/commands/seed/plan.js +64 -13
- package/dist/commands/seed/plan.js.map +1 -1
- package/dist/commands/seed/seed.js +6 -9
- package/dist/commands/seed/seed.js.map +1 -1
- package/dist/commands/show/show.js +3 -7
- package/dist/commands/show/show.js.map +1 -1
- package/dist/commands/status/print.js +13 -4
- package/dist/commands/status/print.js.map +1 -1
- package/dist/commands/status/status.js +3 -7
- package/dist/commands/status/status.js.map +1 -1
- package/dist/commands/steps/steps.js +3 -7
- package/dist/commands/steps/steps.js.map +1 -1
- package/dist/commands/subsystem/edit.js +7 -7
- package/dist/commands/subsystem/edit.js.map +1 -1
- package/dist/commands/subsystem/move.js +60 -25
- package/dist/commands/subsystem/move.js.map +1 -1
- package/dist/commands/subsystem/query.js +2 -4
- package/dist/commands/subsystem/query.js.map +1 -1
- package/dist/commands/subsystem/subsystem.js +4 -7
- package/dist/commands/subsystem/subsystem.js.map +1 -1
- package/dist/commands/subsystem/sync.js +141 -71
- package/dist/commands/subsystem/sync.js.map +1 -1
- package/dist/commands/subsystem/txn/report.js +55 -5
- package/dist/commands/subsystem/txn/report.js.map +1 -1
- package/dist/commands/subsystem/txn/txn.js +121 -45
- package/dist/commands/subsystem/txn/txn.js.map +1 -1
- package/dist/commands/subsystem/txn/views.js +82 -12
- package/dist/commands/subsystem/txn/views.js.map +1 -1
- package/dist/commands/tasks/render.js +116 -0
- package/dist/commands/tasks/render.js.map +1 -0
- package/dist/commands/tasks/tasks.js +113 -0
- package/dist/commands/tasks/tasks.js.map +1 -0
- package/dist/commands/unarchive/manifest.js +6 -9
- package/dist/commands/unarchive/manifest.js.map +1 -1
- package/dist/commands/unarchive/restore.js +17 -28
- package/dist/commands/unarchive/restore.js.map +1 -1
- package/dist/commands/unarchive/unarchive.js +22 -30
- package/dist/commands/unarchive/unarchive.js.map +1 -1
- package/dist/commands/validate/arch-coverage.js +6 -15
- package/dist/commands/validate/arch-coverage.js.map +1 -1
- package/dist/commands/validate/checks/fleet-shape.js +4 -49
- package/dist/commands/validate/checks/fleet-shape.js.map +1 -1
- package/dist/commands/validate/checks/health-deps.js +9 -6
- package/dist/commands/validate/checks/health-deps.js.map +1 -1
- package/dist/commands/validate/checks/requirements.js +18 -8
- package/dist/commands/validate/checks/requirements.js.map +1 -1
- package/dist/commands/validate/checks/sources.js +6 -2
- package/dist/commands/validate/checks/sources.js.map +1 -1
- package/dist/commands/validate/feature.js +23 -19
- package/dist/commands/validate/feature.js.map +1 -1
- package/dist/commands/validate/fleet/census.js +26 -3
- package/dist/commands/validate/fleet/census.js.map +1 -1
- package/dist/commands/validate/fleet/landscape.js +35 -32
- package/dist/commands/validate/fleet/landscape.js.map +1 -1
- package/dist/commands/validate/fleet/map/attest.js +7 -12
- package/dist/commands/validate/fleet/map/attest.js.map +1 -1
- package/dist/commands/validate/fleet/map/bindings.js +16 -5
- package/dist/commands/validate/fleet/map/bindings.js.map +1 -1
- package/dist/commands/validate/fleet/map/consumers.js +43 -122
- package/dist/commands/validate/fleet/map/consumers.js.map +1 -1
- package/dist/commands/validate/fleet/map/usecases.js +5 -11
- package/dist/commands/validate/fleet/map/usecases.js.map +1 -1
- package/dist/commands/validate/fleet/obligations.js +1 -5
- package/dist/commands/validate/fleet/obligations.js.map +1 -1
- package/dist/commands/validate/fleet/scorecard/print.js +5 -1
- package/dist/commands/validate/fleet/scorecard/print.js.map +1 -1
- package/dist/commands/validate/fleet/scorecard/scorecard.js +17 -11
- package/dist/commands/validate/fleet/scorecard/scorecard.js.map +1 -1
- package/dist/commands/validate/fleet/usecases/usecases.js +6 -4
- package/dist/commands/validate/fleet/usecases/usecases.js.map +1 -1
- package/dist/commands/validate/fleet/views/fleet-project.js +1 -1
- package/dist/commands/validate/fleet/views/fleet-project.js.map +1 -1
- package/dist/commands/validate/fleet/views/ids.js +33 -7
- package/dist/commands/validate/fleet/views/ids.js.map +1 -1
- package/dist/commands/validate/fleet/views/root-documents.js +17 -35
- package/dist/commands/validate/fleet/views/root-documents.js.map +1 -1
- package/dist/commands/validate/fleet/views/stale.js +31 -14
- package/dist/commands/validate/fleet/views/stale.js.map +1 -1
- package/dist/commands/validate/links/corpus.js +1 -4
- package/dist/commands/validate/links/corpus.js.map +1 -1
- package/dist/commands/validate/links/glossary.js.map +1 -1
- package/dist/commands/validate/report.js +5 -4
- package/dist/commands/validate/report.js.map +1 -1
- package/dist/commands/validate/scope.js +113 -0
- package/dist/commands/validate/scope.js.map +1 -0
- package/dist/commands/validate/service/api.js +16 -104
- package/dist/commands/validate/service/api.js.map +1 -1
- package/dist/commands/validate/service/contracts/generated.js +134 -0
- package/dist/commands/validate/service/contracts/generated.js.map +1 -0
- package/dist/commands/validate/service/events/events.js +1 -1
- package/dist/commands/validate/service/events/events.js.map +1 -1
- package/dist/commands/validate/service/events/message-producers.js +1 -1
- package/dist/commands/validate/service/events/message-producers.js.map +1 -1
- package/dist/commands/validate/service/evidence-pins.js +56 -10
- package/dist/commands/validate/service/evidence-pins.js.map +1 -1
- package/dist/commands/validate/service/service.js +16 -26
- package/dist/commands/validate/service/service.js.map +1 -1
- package/dist/commands/validate/service/specs.js +31 -38
- package/dist/commands/validate/service/specs.js.map +1 -1
- package/dist/commands/validate/service/spine.js +8 -11
- package/dist/commands/validate/service/spine.js.map +1 -1
- package/dist/commands/validate/service/usecases/usecases.js +3 -3
- package/dist/commands/validate/service/usecases/usecases.js.map +1 -1
- package/dist/commands/validate/validate.js +44 -26
- package/dist/commands/validate/validate.js.map +1 -1
- package/dist/commands/verify/cross/diff.js +2 -6
- package/dist/commands/verify/cross/diff.js.map +1 -1
- package/dist/commands/verify/evidence/contract.js +1 -1
- package/dist/commands/verify/evidence/contract.js.map +1 -1
- package/dist/commands/verify/evidence/read.js +12 -3
- package/dist/commands/verify/evidence/read.js.map +1 -1
- package/dist/commands/verify/frozen.js +45 -23
- package/dist/commands/verify/frozen.js.map +1 -1
- package/dist/commands/verify/record.js +69 -17
- package/dist/commands/verify/record.js.map +1 -1
- package/dist/commands/verify/report.js +27 -44
- package/dist/commands/verify/report.js.map +1 -1
- package/dist/commands/verify/results.js +112 -30
- package/dist/commands/verify/results.js.map +1 -1
- package/dist/commands/verify/verify.js +54 -51
- package/dist/commands/verify/verify.js.map +1 -1
- package/dist/commands/vouch/pack/pack.js +2 -2
- package/dist/commands/vouch/pack/pack.js.map +1 -1
- package/dist/commands/vouch/pack/print.js +1 -6
- package/dist/commands/vouch/pack/print.js.map +1 -1
- package/dist/commands/vouch/pack/sections.js +1 -2
- package/dist/commands/vouch/pack/sections.js.map +1 -1
- package/dist/commands/vouch/run.js +26 -81
- package/dist/commands/vouch/run.js.map +1 -1
- package/dist/commands/vouch/sample/plan.js +20 -34
- package/dist/commands/vouch/sample/plan.js.map +1 -1
- package/dist/commands/vouch/vet/verify.js +39 -7
- package/dist/commands/vouch/vet/verify.js.map +1 -1
- package/dist/commands/vouch/vouch.js +10 -17
- package/dist/commands/vouch/vouch.js.map +1 -1
- package/dist/core/agent/agents-md/command-map.js +57 -102
- package/dist/core/agent/agents-md/command-map.js.map +1 -1
- package/dist/core/agent/agents-md/map/explain.js +4 -3
- package/dist/core/agent/agents-md/map/explain.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/context.js +4 -3
- package/dist/core/agent/agents-md/map/lenses/context.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/diff.js +33 -20
- package/dist/core/agent/agents-md/map/lenses/diff.js.map +1 -1
- package/dist/core/agent/agents-md/map/lenses/gate.js +13 -5
- package/dist/core/agent/agents-md/map/lenses/gate.js.map +1 -1
- package/dist/core/agent/agents-md/map/mcp.js +10 -7
- package/dist/core/agent/agents-md/map/mcp.js.map +1 -1
- package/dist/core/agent/agents-md/map/status.js +9 -3
- package/dist/core/agent/agents-md/map/status.js.map +1 -1
- package/dist/core/agent/agents-md/map/subsystem.js +31 -17
- package/dist/core/agent/agents-md/map/subsystem.js.map +1 -1
- package/dist/core/agent/agents-md/map/usecases.js +24 -6
- package/dist/core/agent/agents-md/map/usecases.js.map +1 -1
- package/dist/core/agent/agents-md/refusals.js +37 -21
- package/dist/core/agent/agents-md/refusals.js.map +1 -1
- package/dist/core/agent/agents-md.js +25 -10
- package/dist/core/agent/agents-md.js.map +1 -1
- package/dist/core/agent/agents-stamp.js +10 -0
- package/dist/core/agent/agents-stamp.js.map +1 -1
- package/dist/core/agent/scaffold.js +10 -15
- package/dist/core/agent/scaffold.js.map +1 -1
- package/dist/core/agent/tools/dialects.js +1 -0
- package/dist/core/agent/tools/dialects.js.map +1 -1
- package/dist/core/agent/tools/registry.js +41 -76
- package/dist/core/agent/tools/registry.js.map +1 -1
- package/dist/core/agent/workflows/adopt.js +5 -3
- package/dist/core/agent/workflows/adopt.js.map +1 -1
- package/dist/core/agent/workflows/check.js +25 -22
- package/dist/core/agent/workflows/check.js.map +1 -1
- package/dist/core/agent/workflows/closing.js +54 -21
- package/dist/core/agent/workflows/closing.js.map +1 -1
- package/dist/core/agent/workflows/feature.js +79 -11
- package/dist/core/agent/workflows/feature.js.map +1 -1
- package/dist/core/agent/workflows/implement.js +91 -13
- package/dist/core/agent/workflows/implement.js.map +1 -1
- package/dist/core/agent/workflows/reference/authoring.js +3 -1
- package/dist/core/agent/workflows/reference/authoring.js.map +1 -1
- package/dist/core/agent/workflows/reference/codes.js +8 -6
- package/dist/core/agent/workflows/reference/codes.js.map +1 -1
- package/dist/core/agent/workflows/reference/done-check.js +37 -15
- package/dist/core/agent/workflows/reference/done-check.js.map +1 -1
- package/dist/core/agent/workflows/reference/reference.js.map +1 -1
- package/dist/core/agent/workflows/reference/spine.js +62 -24
- package/dist/core/agent/workflows/reference/spine.js.map +1 -1
- package/dist/core/asyncapi/baseline/plan.js +14 -81
- package/dist/core/asyncapi/baseline/plan.js.map +1 -1
- package/dist/core/asyncapi/digest.js +30 -25
- package/dist/core/asyncapi/digest.js.map +1 -1
- package/dist/core/asyncapi/merge/components.js +5 -4
- package/dist/core/asyncapi/merge/components.js.map +1 -1
- package/dist/core/asyncapi/merge/error.js +7 -2
- package/dist/core/asyncapi/merge/error.js.map +1 -1
- package/dist/core/asyncapi/merge/markers.js +30 -50
- package/dist/core/asyncapi/merge/markers.js.map +1 -1
- package/dist/core/asyncapi/merge/merge.js +31 -53
- package/dist/core/asyncapi/merge/merge.js.map +1 -1
- package/dist/core/asyncapi/merge/pin.js +10 -36
- package/dist/core/asyncapi/merge/pin.js.map +1 -1
- package/dist/core/asyncapi/model.js.map +1 -1
- package/dist/core/asyncapi/read.js +36 -12
- package/dist/core/asyncapi/read.js.map +1 -1
- package/dist/core/brief/brief.js +30 -25
- package/dist/core/brief/brief.js.map +1 -1
- package/dist/core/brief/landscape.js +8 -12
- package/dist/core/brief/landscape.js.map +1 -1
- package/dist/core/brief/map/extend.js +8 -5
- package/dist/core/brief/map/extend.js.map +1 -1
- package/dist/core/brief/map/owed.js +8 -26
- package/dist/core/brief/map/owed.js.map +1 -1
- package/dist/core/brief/targets.js +79 -5
- package/dist/core/brief/targets.js.map +1 -1
- package/dist/core/brief/unchecked.js +1 -1
- package/dist/core/brief/unchecked.js.map +1 -1
- package/dist/core/c4/likec4.js +147 -16
- package/dist/core/c4/likec4.js.map +1 -1
- package/dist/core/c4/locate/unlocated.js +150 -0
- package/dist/core/c4/locate/unlocated.js.map +1 -0
- package/dist/core/c4/parsed/values.js +54 -1
- package/dist/core/c4/parsed/values.js.map +1 -1
- package/dist/core/c4/prefetch/fleet.js +1 -9
- package/dist/core/c4/prefetch/fleet.js.map +1 -1
- package/dist/core/c4/project/architecture.js +31 -9
- package/dist/core/c4/project/architecture.js.map +1 -1
- package/dist/core/c4/project/documents.js +36 -10
- package/dist/core/c4/project/documents.js.map +1 -1
- package/dist/core/c4/project/load.js +14 -21
- package/dist/core/c4/project/load.js.map +1 -1
- package/dist/core/c4/project/staged.js +7 -3
- package/dist/core/c4/project/staged.js.map +1 -1
- 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 +25 -1
- package/dist/core/c4/resolve/service.js.map +1 -1
- package/dist/core/c4/seed/template.js +15 -1
- package/dist/core/c4/seed/template.js.map +1 -1
- package/dist/core/c4/service-model/shape.js +2 -22
- package/dist/core/c4/service-model/shape.js.map +1 -1
- package/dist/core/c4/source-mask.js +288 -4
- package/dist/core/c4/source-mask.js.map +1 -1
- package/dist/core/c4/source-scan.js +203 -147
- package/dist/core/c4/source-scan.js.map +1 -1
- package/dist/core/c4/splice/authored-source.js +19 -0
- package/dist/core/c4/splice/authored-source.js.map +1 -1
- package/dist/core/c4/splice/delta-blocks.js +5 -18
- package/dist/core/c4/splice/delta-blocks.js.map +1 -1
- package/dist/core/c4/splice/landscape-merge.js +13 -8
- package/dist/core/c4/splice/landscape-merge.js.map +1 -1
- package/dist/core/c4/splice/model/merge.js +10 -6
- package/dist/core/c4/splice/model/merge.js.map +1 -1
- package/dist/core/c4/splice/placement.js +108 -18
- package/dist/core/c4/splice/placement.js.map +1 -1
- package/dist/core/c4/workspace.js +13 -22
- package/dist/core/c4/workspace.js.map +1 -1
- package/dist/core/capabilities/capabilities.js +6 -6
- package/dist/core/capabilities/capabilities.js.map +1 -1
- package/dist/core/capabilities/delta/doc.js +7 -10
- package/dist/core/capabilities/delta/doc.js.map +1 -1
- package/dist/core/capabilities/findings.js +15 -20
- package/dist/core/capabilities/findings.js.map +1 -1
- package/dist/core/capabilities/realizes/findings.js +12 -19
- package/dist/core/capabilities/realizes/findings.js.map +1 -1
- package/dist/core/capabilities/realizes/join.js +0 -20
- package/dist/core/capabilities/realizes/join.js.map +1 -1
- package/dist/core/capabilities/rollup.js +6 -0
- package/dist/core/capabilities/rollup.js.map +1 -1
- package/dist/core/capabilities/tree.js +6 -28
- package/dist/core/capabilities/tree.js.map +1 -1
- package/dist/core/capabilities/usecase-join.js +3 -13
- package/dist/core/capabilities/usecase-join.js.map +1 -1
- package/dist/core/coherence/authoring/scaffold.js +11 -3
- package/dist/core/coherence/authoring/scaffold.js.map +1 -1
- package/dist/core/coherence/authoring/sentinels.js +2 -1
- package/dist/core/coherence/authoring/sentinels.js.map +1 -1
- package/dist/core/coherence/coherence.js +30 -16
- package/dist/core/coherence/coherence.js.map +1 -1
- package/dist/core/coherence/consumed/operations.js +70 -0
- package/dist/core/coherence/consumed/operations.js.map +1 -0
- package/dist/core/coherence/consumed/refusal.js +38 -0
- package/dist/core/coherence/consumed/refusal.js.map +1 -0
- package/dist/core/coherence/declared.js +60 -34
- package/dist/core/coherence/declared.js.map +1 -1
- package/dist/core/coherence/events/declared.js +44 -59
- package/dist/core/coherence/events/declared.js.map +1 -1
- package/dist/core/coherence/events/events.js +119 -8
- package/dist/core/coherence/events/events.js.map +1 -1
- package/dist/core/coherence/events/grades.js +31 -8
- package/dist/core/coherence/events/grades.js.map +1 -1
- package/dist/core/coherence/events/lookups.js +14 -82
- package/dist/core/coherence/events/lookups.js.map +1 -1
- package/dist/core/coherence/lookups.js +18 -78
- package/dist/core/coherence/lookups.js.map +1 -1
- package/dist/core/coherence/retired/archived.js +285 -0
- package/dist/core/coherence/retired/archived.js.map +1 -0
- package/dist/core/coherence/retired/event-pair.js +62 -0
- package/dist/core/coherence/retired/event-pair.js.map +1 -0
- package/dist/core/coherence/retired/merged.js +79 -0
- package/dist/core/coherence/retired/merged.js.map +1 -0
- package/dist/core/coherence/retired/retirement.js +49 -0
- package/dist/core/coherence/retired/retirement.js.map +1 -0
- package/dist/core/coherence/retired/revival/arrivals.js +131 -0
- package/dist/core/coherence/retired/revival/arrivals.js.map +1 -0
- package/dist/core/coherence/retired/revival/revived.js +297 -0
- package/dist/core/coherence/retired/revival/revived.js.map +1 -0
- package/dist/core/consumers/after.js +113 -0
- package/dist/core/consumers/after.js.map +1 -0
- package/dist/core/consumers/consumers.js +296 -0
- package/dist/core/consumers/consumers.js.map +1 -0
- package/dist/core/consumers/current.js +211 -0
- package/dist/core/consumers/current.js.map +1 -0
- package/dist/core/consumers/scan.js +46 -0
- package/dist/core/consumers/scan.js.map +1 -0
- package/dist/core/consumers/state.js +27 -0
- package/dist/core/consumers/state.js.map +1 -0
- package/dist/core/delta/delta.js +1 -1
- package/dist/core/delta/delta.js.map +1 -1
- package/dist/core/deployment/delta.js +15 -16
- package/dist/core/deployment/delta.js.map +1 -1
- package/dist/core/diff/base-git.js +94 -12
- package/dist/core/diff/base-git.js.map +1 -1
- package/dist/core/diff/base-state.js +28 -16
- package/dist/core/diff/base-state.js.map +1 -1
- package/dist/core/diff/joins.js +136 -0
- package/dist/core/diff/joins.js.map +1 -0
- package/dist/core/diff/scope/changed-paths.js +22 -6
- package/dist/core/diff/scope/changed-paths.js.map +1 -1
- package/dist/core/diff/scope/edges.js +82 -0
- package/dist/core/diff/scope/edges.js.map +1 -0
- package/dist/core/diff/semantic.js +100 -31
- package/dist/core/diff/semantic.js.map +1 -1
- package/dist/core/doctor/agents.js +34 -18
- package/dist/core/doctor/agents.js.map +1 -1
- package/dist/core/doctor/report.js.map +1 -1
- package/dist/core/document/apply.js +10 -2
- package/dist/core/document/apply.js.map +1 -1
- package/dist/core/document/frontmatter.js +55 -0
- package/dist/core/document/frontmatter.js.map +1 -1
- package/dist/core/document/parse.js +29 -6
- package/dist/core/document/parse.js.map +1 -1
- package/dist/core/document/scenarios.js +17 -0
- package/dist/core/document/scenarios.js.map +1 -1
- package/dist/core/document/spec.js +4 -11
- package/dist/core/document/spec.js.map +1 -1
- package/dist/core/envelope/config.js +10 -0
- package/dist/core/envelope/config.js.map +1 -1
- package/dist/core/envelope/json.js +34 -0
- package/dist/core/envelope/json.js.map +1 -1
- package/dist/core/explain/families.js +17 -12
- package/dist/core/explain/families.js.map +1 -1
- package/dist/core/explain/refusals.js +3 -3
- package/dist/core/explain/refusals.js.map +1 -1
- package/dist/core/explain/terms.js +18 -9
- package/dist/core/explain/terms.js.map +1 -1
- package/dist/core/explore/explore.js +2 -7
- package/dist/core/explore/explore.js.map +1 -1
- package/dist/core/fleet-context.js +34 -95
- package/dist/core/fleet-context.js.map +1 -1
- package/dist/core/gate/checks.js +10 -3
- package/dist/core/gate/checks.js.map +1 -1
- package/dist/core/gate/partners.js +64 -19
- package/dist/core/gate/partners.js.map +1 -1
- package/dist/core/gate/report.js.map +1 -1
- package/dist/core/gate/verification.js +75 -12
- package/dist/core/gate/verification.js.map +1 -1
- package/dist/core/gherkin/stale.js +13 -37
- package/dist/core/gherkin/stale.js.map +1 -1
- package/dist/core/glossary/tree.js +6 -19
- package/dist/core/glossary/tree.js.map +1 -1
- package/dist/core/kernel/concurrency.js +19 -0
- package/dist/core/kernel/concurrency.js.map +1 -1
- package/dist/core/kernel/records.js +11 -0
- package/dist/core/kernel/records.js.map +1 -1
- package/dist/core/links/backlinks.js +1 -3
- package/dist/core/links/backlinks.js.map +1 -1
- package/dist/core/links/corpus.js +5 -36
- package/dist/core/links/corpus.js.map +1 -1
- package/dist/core/mcp/argv.js +101 -0
- package/dist/core/mcp/argv.js.map +1 -1
- package/dist/core/mcp/author-tools.js +2 -1
- package/dist/core/mcp/author-tools.js.map +1 -1
- package/dist/core/mcp/protocol.js +2 -2
- package/dist/core/mcp/protocol.js.map +1 -1
- package/dist/core/mcp/tools.js +43 -33
- package/dist/core/mcp/tools.js.map +1 -1
- package/dist/core/openapi/baseline/gate.js +53 -12
- package/dist/core/openapi/baseline/gate.js.map +1 -1
- package/dist/core/openapi/baseline/plan.js +22 -8
- package/dist/core/openapi/baseline/plan.js.map +1 -1
- package/dist/core/openapi/baseline/record.js +0 -1
- package/dist/core/openapi/baseline/record.js.map +1 -1
- package/dist/core/openapi/contract-text.js +33 -0
- package/dist/core/openapi/contract-text.js.map +1 -0
- package/dist/core/openapi/contract-tree.js +56 -0
- package/dist/core/openapi/contract-tree.js.map +1 -0
- package/dist/core/openapi/depth.js +38 -24
- package/dist/core/openapi/depth.js.map +1 -1
- package/dist/core/openapi/digest.js +52 -2
- package/dist/core/openapi/digest.js.map +1 -1
- package/dist/core/openapi/doc.js +12 -4
- package/dist/core/openapi/doc.js.map +1 -1
- package/dist/core/openapi/merge/components.js +25 -60
- package/dist/core/openapi/merge/components.js.map +1 -1
- package/dist/core/openapi/merge/error.js +3 -13
- package/dist/core/openapi/merge/error.js.map +1 -1
- package/dist/core/openapi/merge/markers.js +26 -30
- package/dist/core/openapi/merge/markers.js.map +1 -1
- package/dist/core/openapi/merge/merge.js +26 -52
- package/dist/core/openapi/merge/merge.js.map +1 -1
- package/dist/core/openapi/merge/pin.js +15 -35
- package/dist/core/openapi/merge/pin.js.map +1 -1
- package/dist/core/openspec/decide/verdict.js.map +1 -1
- package/dist/core/openspec/inventory.js +4 -5
- package/dist/core/openspec/inventory.js.map +1 -1
- package/dist/core/openspec/model/mapping.js +30 -28
- package/dist/core/openspec/model/mapping.js.map +1 -1
- package/dist/core/openspec/model/model.js +12 -7
- package/dist/core/openspec/model/model.js.map +1 -1
- package/dist/core/openspec/scan/changes.js +10 -4
- package/dist/core/openspec/scan/changes.js.map +1 -1
- package/dist/core/openspec/scan/config.js +7 -16
- package/dist/core/openspec/scan/config.js.map +1 -1
- package/dist/core/openspec/scan/shape.js +63 -19
- package/dist/core/openspec/scan/shape.js.map +1 -1
- package/dist/core/openspec/scan/walk.js +21 -38
- package/dist/core/openspec/scan/walk.js.map +1 -1
- package/dist/core/pack/living.js +2 -16
- package/dist/core/pack/living.js.map +1 -1
- package/dist/core/provenance/findings.js +48 -12
- package/dist/core/provenance/findings.js.map +1 -1
- package/dist/core/provenance/git.js +33 -57
- package/dist/core/provenance/git.js.map +1 -1
- package/dist/core/provenance/gitq/moves.js +71 -114
- package/dist/core/provenance/gitq/moves.js.map +1 -1
- package/dist/core/provenance/gitq/vouched-ancestor.js +2 -2
- package/dist/core/provenance/gitq/vouched-ancestor.js.map +1 -1
- package/dist/core/provenance/sources.js +23 -6
- package/dist/core/provenance/sources.js.map +1 -1
- package/dist/core/provenance/stamp.js +5 -17
- package/dist/core/provenance/stamp.js.map +1 -1
- package/dist/core/repo/entries.js.map +1 -1
- package/dist/core/repo/paths.js +34 -29
- package/dist/core/repo/paths.js.map +1 -1
- package/dist/core/repo/repo.js +24 -14
- package/dist/core/repo/repo.js.map +1 -1
- package/dist/core/repo/tree/find.js +12 -3
- package/dist/core/repo/tree/find.js.map +1 -1
- package/dist/core/repo/tree/fs.js +27 -1
- package/dist/core/repo/tree/fs.js.map +1 -1
- package/dist/core/repo/tree/render/body.js +45 -6
- package/dist/core/repo/tree/render/body.js.map +1 -1
- 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 +19 -2
- package/dist/core/repo/tree/render/stale.js.map +1 -1
- package/dist/core/repo/tree/render/views.js +102 -33
- package/dist/core/repo/tree/render/views.js.map +1 -1
- package/dist/core/repo/tree/walk.js +8 -30
- package/dist/core/repo/tree/walk.js.map +1 -1
- package/dist/core/results.js +47 -12
- package/dist/core/results.js.map +1 -1
- package/dist/core/staging/commit.js +10 -12
- package/dist/core/staging/commit.js.map +1 -1
- package/dist/core/staging/lock.js +74 -12
- package/dist/core/staging/lock.js.map +1 -1
- package/dist/core/staging/recovery/intent.js +2 -5
- package/dist/core/staging/recovery/intent.js.map +1 -1
- package/dist/core/staging/recovery/recover.js +60 -1
- package/dist/core/staging/recovery/recover.js.map +1 -1
- package/dist/core/staging/snapshot/manifest.js +152 -0
- package/dist/core/staging/snapshot/manifest.js.map +1 -0
- package/dist/core/staging/{snapshot.js → snapshot/snapshot.js} +10 -34
- package/dist/core/staging/snapshot/snapshot.js.map +1 -0
- package/dist/core/status/actions/execution.js +11 -0
- package/dist/core/status/actions/execution.js.map +1 -1
- package/dist/core/status/feature/artifacts.js +2 -2
- package/dist/core/status/feature/artifacts.js.map +1 -1
- package/dist/core/status/feature/feature.js +5 -11
- package/dist/core/status/feature/feature.js.map +1 -1
- package/dist/core/status/fleet/fleet.js +6 -2
- package/dist/core/status/fleet/fleet.js.map +1 -1
- package/dist/core/status/fleet/next.js +26 -3
- package/dist/core/status/fleet/next.js.map +1 -1
- package/dist/core/status/report.js.map +1 -1
- package/dist/core/status/verification.js +30 -15
- package/dist/core/status/verification.js.map +1 -1
- package/dist/core/tasks/packet.js +174 -0
- package/dist/core/tasks/packet.js.map +1 -0
- package/dist/core/tasks/record.js +43 -0
- package/dist/core/tasks/record.js.map +1 -0
- package/dist/core/tasks/sources.js +181 -0
- package/dist/core/tasks/sources.js.map +1 -0
- package/dist/core/tasks/stamps.js +76 -0
- package/dist/core/tasks/stamps.js.map +1 -0
- package/dist/core/tasks/unit.js +0 -0
- package/dist/core/tasks/unit.js.map +1 -0
- package/dist/core/usecases/capability.js +11 -14
- package/dist/core/usecases/capability.js.map +1 -1
- package/dist/core/usecases/delta/flows.js +5 -7
- package/dist/core/usecases/delta/flows.js.map +1 -1
- package/dist/core/usecases/fleet.js +178 -31
- package/dist/core/usecases/fleet.js.map +1 -1
- package/dist/core/usecases/operations.js +5 -4
- package/dist/core/usecases/operations.js.map +1 -1
- package/dist/core/usecases/service/flows.js +9 -6
- package/dist/core/usecases/service/flows.js.map +1 -1
- package/dist/core/usecases/suites/participants.js +83 -0
- package/dist/core/usecases/suites/participants.js.map +1 -0
- package/dist/core/usecases/suites/suites.js +45 -0
- package/dist/core/usecases/suites/suites.js.map +1 -0
- package/dist/core/verify/answers.js +12 -5
- package/dist/core/verify/answers.js.map +1 -1
- package/dist/core/verify/build.js +102 -82
- package/dist/core/verify/build.js.map +1 -1
- package/dist/core/verify/checklist.js +45 -10
- package/dist/core/verify/checklist.js.map +1 -1
- package/dist/core/verify/location.js +67 -0
- package/dist/core/verify/location.js.map +1 -0
- package/dist/core/verify/pins/lint.js +3 -2
- package/dist/core/verify/pins/lint.js.map +1 -1
- package/dist/core/verify/pins/pin.js +1 -1
- package/dist/core/verify/pins/pin.js.map +1 -1
- package/dist/core/verify/read/file.js +224 -0
- package/dist/core/verify/read/file.js.map +1 -0
- package/dist/core/verify/{file.js → read/shape.js} +16 -104
- package/dist/core/verify/read/shape.js.map +1 -0
- package/dist/core/verify/read/union.js +105 -0
- package/dist/core/verify/read/union.js.map +1 -0
- package/dist/core/verify/record.js +35 -12
- package/dist/core/verify/record.js.map +1 -1
- package/dist/core/verify/store/commit.js +40 -30
- package/dist/core/verify/store/commit.js.map +1 -1
- package/dist/core/verify/store/render.js +8 -4
- package/dist/core/verify/store/render.js.map +1 -1
- package/dist/core/vocabulary/issue.js +1 -0
- package/dist/core/vocabulary/issue.js.map +1 -1
- package/dist/core/vocabulary/maturity.js +53 -3
- package/dist/core/vocabulary/maturity.js.map +1 -1
- package/examples/README.md +28 -9
- package/examples/docs/architecture/landscape.likec4 +21 -7
- package/examples/docs/architecture/services.likec4 +70 -0
- package/examples/docs/architecture/subsystems.likec4 +3 -0
- package/examples/docs/architecture/usecases/order-notification.likec4 +6 -2
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-service/asyncapi.yaml +11 -8
- package/examples/docs/features/FEAT-101-payment-splitting/specs/payment-split-service/openapi.yaml +6 -6
- package/examples/docs/features/archive/FEAT-088-refunds/specs/payment-service/openapi.yaml +13 -10
- package/examples/docs/services/order-service/asyncapi.yaml +3 -2
- package/examples/docs/services/order-service/model.likec4 +10 -8
- package/examples/docs/services/payment-service/model.likec4 +6 -4
- package/examples/docs/services/platform/identity-service/model.likec4 +9 -7
- package/examples/docs/services/platform/notification-service/asyncapi.yaml +2 -1
- package/examples/docs/services/platform/notification-service/model.likec4 +4 -5
- package/package.json +1 -1
- package/dist/commands/validate/checks/vocabulary.js +0 -16
- package/dist/commands/validate/checks/vocabulary.js.map +0 -1
- package/dist/core/agent/agents-md/artifacts.js +0 -221
- package/dist/core/agent/agents-md/artifacts.js.map +0 -1
- package/dist/core/agent/agents-md/cycle.js +0 -180
- package/dist/core/agent/agents-md/cycle.js.map +0 -1
- package/dist/core/agent/agents-md/shipped/archive-gate.js +0 -98
- package/dist/core/agent/agents-md/shipped/archive-gate.js.map +0 -1
- package/dist/core/agent/agents-md/spine.js +0 -40
- package/dist/core/agent/agents-md/spine.js.map +0 -1
- package/dist/core/coherence/events/merged.js +0 -40
- package/dist/core/coherence/events/merged.js.map +0 -1
- package/dist/core/diff/current-state.js +0 -96
- package/dist/core/diff/current-state.js.map +0 -1
- package/dist/core/diff/victims.js +0 -256
- package/dist/core/diff/victims.js.map +0 -1
- package/dist/core/staging/snapshot.js.map +0 -1
- package/dist/core/verify/file.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree.js","sourceRoot":"","sources":["../../../src/core/glossary/tree.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,EAAE,UAAU,EAAE,
|
|
1
|
+
{"version":3,"file":"tree.js","sourceRoot":"","sources":["../../../src/core/glossary/tree.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * The glossary tree: `glossary/<term>.md`, and the rule that a markdown file\n * under it IS a declared term.\n *\n * WHY A TREE AND NOT A YAML VOCABULARY, at length in `repo/authored/paths.ts`'s\n * `glossaryDir`: a single vocabulary file at fleet scale is unworkable, and a\n * second list is the drift `loam init`'s removed service manifest was removed\n * for. A term is prose — that is what a definition is — so by this codebase's\n * own rule it gets a file.\n *\n * PRESENCE CLASSIFIES, one tree over from `capabilities/`: a `.md` file is a\n * term, a directory is a group the walk descends through. There is no\n * \"half-created term\" state to name, which is why this walk emits nothing like\n * `capability.doc-missing`: creating a term is writing one file, and an empty\n * grouping directory declares nothing and claims nothing.\n *\n * `README.md` IS NOT A TERM, and it is the one name excluded. A glossary big\n * enough to want an index page is normal, and reporting that page as a word\n * nobody uses would make the axis's only warning fire on the document that\n * explains the axis. Excluded by name rather than by a marker field: the\n * alternative is frontmatter nobody would remember to write.\n *\n * The walk reads directories only and never opens a file. What is IN a term\n * document is prose for a human, and the one thing loam reads from it — the\n * links it writes — is read by `core/links/`, where every other document's are.\n */\nimport { existsSync } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { compareIds } from \"../repo/entries.js\";\nimport { entryIs, markDescended } from \"../repo/tree/fs.js\";\n\n/** The one filename under `glossary/` that is not a term. */\nconst INDEX_PAGE = \"README.md\";\n\n/** One defined term: what it is called, and where its definition is. */\nexport interface GlossaryTerm {\n /** The path from `glossary/` to the file, without `.md` — `order`, or `payments/order`. */\n id: string;\n /** Absolute path of the definition. */\n path: string;\n}\n\nexport interface Glossary {\n /**\n * False when `glossary/` does not exist. The directory's existence is the\n * axis's opt-in, so a fleet without one produces nothing here — not an empty\n * glossary, which would read as \"the terms went missing\" to anything counting.\n */\n present: boolean;\n /** Every term found, at any depth, ordered by id. */\n terms: GlossaryTerm[];\n}\n\n/** One directory the walk is looking at: where it is, and how it was reached. */\ninterface Spot {\n dir: string;\n /** Directory names between `glossary/` and this one, outermost first. */\n chain: string[];\n}\n\ninterface WalkState {\n terms: GlossaryTerm[];\n /** Realpaths already descended into — the symlink-cycle guard. */\n visited: Set<string>;\n}\n\n/**\n * Read the tree under `root` (`glossaryDir(docsDir)`).\n *\n * A fleet is expected to hold tens to low hundreds of these — a domain's\n * vocabulary, not its data — so the cost is one `readdir` per directory and the\n * walk's expense is a non-question. The symlink-cycle guard is the one\n * `core/repo/tree/walk.ts` and the capability walk both carry\n * (`core/repo/tree/fs.ts`'s `markDescended`), and for the same reason:\n * `entryIs` follows symlinks on purpose, and a followed cycle without a\n * visited set recurses until the stack ends.\n */\nexport async function readGlossary(root: string): Promise<Glossary> {\n if (!existsSync(root)) return { present: false, terms: [] };\n const state: WalkState = { terms: [], visited: new Set() };\n await visit({ dir: root, chain: [] }, state);\n state.terms.sort((a, b) => compareIds(a.id, b.id));\n return { present: true, terms: state.terms };\n}\n\n/** Collect the terms in one directory and walk what is beneath it. */\nasync function visit(spot: Spot, state: WalkState): Promise<void> {\n if (!markDescended(spot.dir, state.visited)) return;\n const entries = (await readdir(spot.dir, { withFileTypes: true })).filter((e) => !e.name.startsWith(\".\"));\n for (const entry of entries.filter((e) => e.name.endsWith(\".md\")).sort((a, b) => compareIds(a.name, b.name))) {\n if (entry.name === INDEX_PAGE || !entryIs(spot.dir, entry, \"file\")) continue;\n state.terms.push({\n id: [...spot.chain, entry.name.slice(0, -\".md\".length)].join(\"/\"),\n path: join(spot.dir, entry.name),\n });\n }\n // Sequential, not Promise.all: the visited set is shared mutable state and\n // the walk's correctness under symlinks rests on a child being marked before\n // its sibling asks. These trees are tens of directories at most.\n for (const child of entries.filter((e) => entryIs(spot.dir, e, \"dir\")).map((e) => e.name).sort()) {\n await visit({ dir: join(spot.dir, child), chain: [...spot.chain, child] }, state);\n }\n}\n"]}
|
|
@@ -7,6 +7,16 @@
|
|
|
7
7
|
* either opens all of them — on a big fleet that is not a faster run, it is a
|
|
8
8
|
* bigger one. The cap and the ordering guarantee travel together because a
|
|
9
9
|
* caller that wants the first cannot afford to lose the second.
|
|
10
|
+
*
|
|
11
|
+
* The third answer to "how much may happen at once" is `memo`: the same read
|
|
12
|
+
* asked for twice in one invocation happens once, both askers sharing the one
|
|
13
|
+
* in-flight promise. It lives here, in a leaf, because both read indexes —
|
|
14
|
+
* `core/fleet-context.ts` and the service-model memos it owns
|
|
15
|
+
* (`core/c4/prefetch/fleet.ts`) — spell every cache they keep with it, and
|
|
16
|
+
* neither should own the other's idiom. The read index could borrow it from
|
|
17
|
+
* the package it already imports, but then a rule about caching in general
|
|
18
|
+
* would live inside the LikeC4 adapter, and the next memo outside `c4/` would
|
|
19
|
+
* have to import that adapter to obey it.
|
|
10
20
|
*/
|
|
11
21
|
import { cpus } from "node:os";
|
|
12
22
|
/**
|
|
@@ -48,4 +58,13 @@ export async function inOrder(items, work) {
|
|
|
48
58
|
}));
|
|
49
59
|
return out;
|
|
50
60
|
}
|
|
61
|
+
/** One in-flight promise per key, created on first ask — the memo idiom, once. */
|
|
62
|
+
export function memo(store, k, make) {
|
|
63
|
+
let pending = store.get(k);
|
|
64
|
+
if (pending === undefined) {
|
|
65
|
+
pending = make();
|
|
66
|
+
store.set(k, pending);
|
|
67
|
+
}
|
|
68
|
+
return pending;
|
|
69
|
+
}
|
|
51
70
|
//# sourceMappingURL=concurrency.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../../../src/core/kernel/concurrency.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"concurrency.js","sourceRoot":"","sources":["../../../src/core/kernel/concurrency.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;AAE1E;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,KAAmB,EACnB,IAA6B;IAE7B,MAAM,GAAG,GAAQ,EAAE,CAAC;IACpB,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,kBAAkB,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IAC3D,MAAM,OAAO,CAAC,GAAG,CACf,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,KAAK,IAAI,EAAE;QACzC,KAAK,IAAI,CAAC,GAAG,IAAI,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE;YAAE,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;IACpF,CAAC,CAAC,CACH,CAAC;IACF,OAAO,GAAG,CAAC;AACb,CAAC;AAED,kFAAkF;AAClF,MAAM,UAAU,IAAI,CAAI,KAA8B,EAAE,CAAS,EAAE,IAAsB;IACvF,IAAI,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IAC3B,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,GAAG,IAAI,EAAE,CAAC;QACjB,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["/**\n * How much of loam may happen at once, and in what order the answers come back.\n *\n * One rule, because there is one resource being rationed: a LikeC4/Langium\n * workspace. `validate --all` opens one per service and per feature, the\n * dependency graph opens one per feature, and an unbounded `Promise.all` over\n * either opens all of them — on a big fleet that is not a faster run, it is a\n * bigger one. The cap and the ordering guarantee travel together because a\n * caller that wants the first cannot afford to lose the second.\n *\n * The third answer to \"how much may happen at once\" is `memo`: the same read\n * asked for twice in one invocation happens once, both askers sharing the one\n * in-flight promise. It lives here, in a leaf, because both read indexes —\n * `core/fleet-context.ts` and the service-model memos it owns\n * (`core/c4/prefetch/fleet.ts`) — spell every cache they keep with it, and\n * neither should own the other's idiom. The read index could borrow it from\n * the package it already imports, but then a rule about caching in general\n * would live inside the LikeC4 adapter, and the next memo outside `c4/` would\n * have to import that adapter to obey it.\n */\nimport { cpus } from \"node:os\";\n\n/**\n * How many units of work may be in flight at once.\n *\n * Capped as well as scaled: each in-flight unit holds a whole LikeC4/Langium\n * workspace, so a 64-core box would open sixty-four of them at once and buy\n * memory pressure rather than throughput (peak RSS on an 80-service fleet:\n * 385 MB serial, ~500 MB pooled). That measurement is the entire justification\n * for the cap, and it is why the cap lives with the work rather than inside one\n * command: `loam dependencies` and the fleet form of `loam status` fan out over\n * the same workspaces `validate --all` does, and used to do it uncapped.\n *\n * Do not quote a speedup for this. The measured cost is CPU inside the Langium\n * parse, which one thread cannot divide however the loop is shaped; what the\n * pool overlaps is the I/O half — the spec, contract and health reads around\n * each parse. On an 80-service fleet it measures as a wash (11–13 s either way,\n * on a box that was itself loaded). The number that moves these commands is\n * workspaces per run, not awaits per loop.\n */\nexport const TARGET_CONCURRENCY = Math.max(1, Math.min(cpus().length, 8));\n\n/**\n * Run `work` over `items` with a bounded number in flight, returning the\n * results in INPUT order.\n *\n * The order is the contract, not an accident: the text report and the `--json`\n * envelope are diffed between runs and between machines, so a concurrent run\n * has to be byte-identical to the serial one for the same input. That is why\n * results are written by index — nothing is appended as it finishes, and a slow\n * item cannot reorder the fleet around it.\n */\nexport async function inOrder<T, R>(\n items: readonly T[],\n work: (item: T) => Promise<R>,\n): Promise<R[]> {\n const out: R[] = [];\n let next = 0;\n const workers = Math.min(TARGET_CONCURRENCY, items.length);\n await Promise.all(\n Array.from({ length: workers }, async () => {\n for (let i = next++; i < items.length; i = next++) out[i] = await work(items[i]!);\n }),\n );\n return out;\n}\n\n/** One in-flight promise per key, created on first ask — the memo idiom, once. */\nexport function memo<T>(store: Map<string, Promise<T>>, k: string, make: () => Promise<T>): Promise<T> {\n let pending = store.get(k);\n if (pending === undefined) {\n pending = make();\n store.set(k, pending);\n }\n return pending;\n}\n"]}
|
|
@@ -16,6 +16,17 @@ export function isRecord(value) {
|
|
|
16
16
|
export function asRecord(value) {
|
|
17
17
|
return isRecord(value) ? value : null;
|
|
18
18
|
}
|
|
19
|
+
/**
|
|
20
|
+
* A list of strings. `Array.isArray` narrows an `unknown` to `any[]`, so an
|
|
21
|
+
* element check written below it proved nothing to tsc and the elements had to
|
|
22
|
+
* be asserted back to `string` at the point of use — how a checked element
|
|
23
|
+
* type went on being asserted back in a line later. Deciding both halves in
|
|
24
|
+
* one predicate makes the narrowing carry the check. (It was written twice,
|
|
25
|
+
* once in the OpenSpec scan and once in the migration's mapping reader.)
|
|
26
|
+
*/
|
|
27
|
+
export function isStringArray(value) {
|
|
28
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
29
|
+
}
|
|
19
30
|
/**
|
|
20
31
|
* A map whose keys come from a document somebody else wrote.
|
|
21
32
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"records.js","sourceRoot":"","sources":["../../../src/core/kernel/records.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,+DAA+D;AAC/D,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAsB,CAAC;AAClD,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,QAAQ,CAAI,MAAyB,EAAE,GAAW;IAChE,OAAO,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACrF,CAAC","sourcesContent":["/**\n * The shapes an unknown parsed document is asked about, in one place.\n *\n * Every YAML and JSON file loam reads arrives as `unknown`, and every reader\n * has to answer the same first question before it can look at a key: is this an\n * object at all? Six modules each carried their own copy of the answer, two of\n * them spelled with a cast — and a cast is exactly what this test exists to\n * make unnecessary, since the predicate form hands the caller a narrowed type\n * that tsc keeps checking. A leaf with no imports, so any layer can ask.\n */\n\n/** An object with string keys — not null, and not an array. */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** The same question where the answer is used rather than branched on. */\nexport function asRecord(value: unknown): Record<string, unknown> | null {\n return isRecord(value) ? value : null;\n}\n\n/**\n * A map whose keys come from a document somebody else wrote.\n *\n * `Object.create(null)` rather than `{}` because a key read out of untrusted\n * YAML can be `__proto__` or `constructor`, and on a normal object those either\n * mutate the prototype or read back a function that was never in the file.\n */\nexport function dictionary<T>(): Record<string, T> {\n return Object.create(null) as Record<string, T>;\n}\n\n/** The value a record actually holds for `key`, never one it inherited. */\nexport function ownValue<T>(record: Record<string, T>, key: string): T | undefined {\n return Object.prototype.hasOwnProperty.call(record, key) ? record[key] : undefined;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"records.js","sourceRoot":"","sources":["../../../src/core/kernel/records.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,+DAA+D;AAC/D,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,0EAA0E;AAC1E,MAAM,UAAU,QAAQ,CAAC,KAAc;IACrC,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;AACxC,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC1C,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC;AACjF,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU;IACxB,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAsB,CAAC;AAClD,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,QAAQ,CAAI,MAAyB,EAAE,GAAW;IAChE,OAAO,MAAM,CAAC,SAAS,CAAC,cAAc,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACrF,CAAC","sourcesContent":["/**\n * The shapes an unknown parsed document is asked about, in one place.\n *\n * Every YAML and JSON file loam reads arrives as `unknown`, and every reader\n * has to answer the same first question before it can look at a key: is this an\n * object at all? Six modules each carried their own copy of the answer, two of\n * them spelled with a cast — and a cast is exactly what this test exists to\n * make unnecessary, since the predicate form hands the caller a narrowed type\n * that tsc keeps checking. A leaf with no imports, so any layer can ask.\n */\n\n/** An object with string keys — not null, and not an array. */\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/** The same question where the answer is used rather than branched on. */\nexport function asRecord(value: unknown): Record<string, unknown> | null {\n return isRecord(value) ? value : null;\n}\n\n/**\n * A list of strings. `Array.isArray` narrows an `unknown` to `any[]`, so an\n * element check written below it proved nothing to tsc and the elements had to\n * be asserted back to `string` at the point of use — how a checked element\n * type went on being asserted back in a line later. Deciding both halves in\n * one predicate makes the narrowing carry the check. (It was written twice,\n * once in the OpenSpec scan and once in the migration's mapping reader.)\n */\nexport function isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((item) => typeof item === \"string\");\n}\n\n/**\n * A map whose keys come from a document somebody else wrote.\n *\n * `Object.create(null)` rather than `{}` because a key read out of untrusted\n * YAML can be `__proto__` or `constructor`, and on a normal object those either\n * mutate the prototype or read back a function that was never in the file.\n */\nexport function dictionary<T>(): Record<string, T> {\n return Object.create(null) as Record<string, T>;\n}\n\n/** The value a record actually holds for `key`, never one it inherited. */\nexport function ownValue<T>(record: Record<string, T>, key: string): T | undefined {\n return Object.prototype.hasOwnProperty.call(record, key) ? record[key] : undefined;\n}\n"]}
|
|
@@ -20,11 +20,9 @@
|
|
|
20
20
|
* file already earns `link.unreadable`; `loam list` has no such finding, so it
|
|
21
21
|
* needs the list to say what it did not read.
|
|
22
22
|
*/
|
|
23
|
-
import { readFile } from "node:fs/promises";
|
|
24
23
|
import { existsSync } from "node:fs";
|
|
25
24
|
import { resolve } from "node:path";
|
|
26
25
|
import { repoPath } from "../envelope/json.js";
|
|
27
|
-
import { decodeDocument } from "../kernel/document-bytes.js";
|
|
28
26
|
import { pathCaseIndex } from "./case.js";
|
|
29
27
|
import { allAuthoredDocuments } from "./corpus.js";
|
|
30
28
|
import { resolveLinks } from "./findings.js";
|
|
@@ -44,7 +42,7 @@ export async function backlinkIndex(docsDir, fleet) {
|
|
|
44
42
|
continue;
|
|
45
43
|
let text;
|
|
46
44
|
try {
|
|
47
|
-
text =
|
|
45
|
+
text = await fleet.readText(path);
|
|
48
46
|
}
|
|
49
47
|
catch {
|
|
50
48
|
unreadable.push(repoPath(docsDir, path));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backlinks.js","sourceRoot":"","sources":["../../../src/core/links/backlinks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"backlinks.js","sourceRoot":"","sources":["../../../src/core/links/backlinks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAG/C,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAS7C;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAgB,EAAE,KAAmB;IACvE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAuB,CAAC;IAC/C,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,aAAa,EAAE,EAAE,CAAC;IAClD,KAAK,MAAM,IAAI,IAAI,MAAM,oBAAoB,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC;QAC9D,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QAChC,IAAI,IAAY,CAAC;QACjB,IAAI,CAAC;YACH,IAAI,GAAG,MAAM,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC;QAAC,MAAM,CAAC;YACP,UAAU,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;YACzC,SAAS;QACX,CAAC;QACD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACrC,KAAK,MAAM,EAAE,MAAM,EAAE,IAAI,YAAY,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC;YACtE,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;YAC5B,IAAI,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,OAAO,KAAK,SAAS;gBAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,OAAO,GAAG,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC;YACnE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IACD,UAAU,CAAC,IAAI,EAAE,CAAC;IAClB,OAAO;QACL,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE;QACvE,UAAU;KACX,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Who links to what, across the whole repository — the link graph read\n * backwards.\n *\n * `link.unresolved` asks each document about its own links. This asks the\n * opposite question, and it is the one the glossary is built on: \"which\n * documents use this term\" is exactly \"which documents link to `glossary/<term>.md`\",\n * and no single target can answer it. A term is cited from a service's spec, a\n * capability document and a feature's intent, so the index is fleet-scope by\n * construction.\n *\n * IT IS THE SAME WALK AS THE FINDING, deliberately — `resolveLinks` produces\n * both halves of one answer, and the corpus is `core/links/corpus.ts`'s single\n * definition. An index built from a second enumeration would report a term as\n * unused while the document citing it was being graded one target over.\n *\n * AN UNREADABLE DOCUMENT IS RETURNED, not swallowed. A term can only be shown as\n * cited by nobody if loam actually read everybody, and a UTF-16 spec.md would\n * otherwise turn into a silently missing citation. Under `validate` the same\n * file already earns `link.unreadable`; `loam list` has no such finding, so it\n * needs the list to say what it did not read.\n */\nimport { existsSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\nimport { repoPath } from \"../envelope/json.js\";\nimport type { FleetContext } from \"../fleet-context.js\";\nimport type { DocsDir } from \"../kernel/ids/dirs.js\";\nimport { pathCaseIndex } from \"./case.js\";\nimport { allAuthoredDocuments } from \"./corpus.js\";\nimport { resolveLinks } from \"./findings.js\";\n\nexport interface BacklinkIndex {\n /** Repo-relative paths of the documents linking to `target`, ordered, without duplicates. */\n linkersOf(target: string): string[];\n /** Repo-relative paths of documents whose links could not be read at all. */\n unreadable: string[];\n}\n\n/**\n * Build the index over every authored document in the repository.\n *\n * One `pathCaseIndex` for the whole walk, because this one really is fleet-wide\n * and the same directories are asked about hundreds of times. Still not a\n * module-level cache: it lives exactly as long as this call.\n */\nexport async function backlinkIndex(docsDir: DocsDir, fleet: FleetContext): Promise<BacklinkIndex> {\n const linkers = new Map<string, Set<string>>();\n const unreadable: string[] = [];\n const scope = { docsDir, cases: pathCaseIndex() };\n for (const path of await allAuthoredDocuments(docsDir, fleet)) {\n if (!existsSync(path)) continue;\n let text: string;\n try {\n text = await fleet.readText(path);\n } catch {\n unreadable.push(repoPath(docsDir, path));\n continue;\n }\n const from = repoPath(docsDir, path);\n for (const { target } of resolveLinks({ path, text }, scope).resolved) {\n const key = resolve(target);\n let sources = linkers.get(key);\n if (sources === undefined) linkers.set(key, (sources = new Set()));\n sources.add(from);\n }\n }\n unreadable.sort();\n return {\n linkersOf: (target) => [...(linkers.get(resolve(target)) ?? [])].sort(),\n unreadable,\n };\n}\n"]}
|
|
@@ -1,42 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* WHICH documents loam reads links out of — the corpus, spelled once.
|
|
3
|
-
*
|
|
4
|
-
* Two readers need it and must not disagree. `commands/validate/links/` grades
|
|
5
|
-
* each target's own documents for `link.unresolved`; `core/glossary/backlinks.ts`
|
|
6
|
-
* reads the WHOLE fleet's, because "which documents use this term" is a question
|
|
7
|
-
* no single target can answer. A corpus that differed between them would report
|
|
8
|
-
* a term as unused while the very document citing it was being graded one target
|
|
9
|
-
* over.
|
|
10
|
-
*
|
|
11
|
-
* THE CORPUS IS EVERY AUTHORED MARKDOWN DOCUMENT, and the word doing the work is
|
|
12
|
-
* authored. `AGENTS.md` and the scaffolded `README.md` are excluded because loam
|
|
13
|
-
* WRITES them: a finding against generated prose names a defect its reader
|
|
14
|
-
* cannot fix by editing, since the next `loam init` restores it. Their links are
|
|
15
|
-
* loam's own problem, held on this side of the boundary by
|
|
16
|
-
* `test/docs-facts.test.ts` and `test/package-docs.test.ts`.
|
|
17
|
-
*
|
|
18
|
-
* ADRs AND RUNBOOKS ARE IN IT, and they are the reason the convention was
|
|
19
|
-
* written down at all: an ADR that supersedes another says which, by linking to
|
|
20
|
-
* it. They are also the first documents loam reads that it previously only
|
|
21
|
-
* counted, which is what `link.unreadable` exists for.
|
|
22
|
-
*
|
|
23
|
-
* `delta.likec4` IS NOT, and neither is any YAML: this is a markdown question.
|
|
24
|
-
* The one thing a delta holds that addresses another file — `metadata { op }` —
|
|
25
|
-
* has its own resolution and its own findings.
|
|
26
|
-
*/
|
|
27
|
-
import { featureCapabilityDeltas } from "../capabilities/delta/tree.js";
|
|
28
|
-
import { readCapabilityTree } from "../capabilities/tree.js";
|
|
29
1
|
import { featureGlossary } from "../glossary/delta.js";
|
|
30
2
|
import { readGlossary } from "../glossary/tree.js";
|
|
31
3
|
import { featurePaths, featureSpecPaths, fleetAdrsDir, servicePathsAt } from "../repo/paths.js";
|
|
32
|
-
import {
|
|
4
|
+
import { glossaryDir } from "../repo/authored/paths.js";
|
|
33
5
|
import { featureSpecServices, listFeatures, listServices } from "../repo/repo.js";
|
|
34
6
|
import { markdownFiles } from "../repo/tree/fs.js";
|
|
35
7
|
/**
|
|
36
8
|
* One service's authored documents: the two requirement specs, the runbook, and
|
|
37
|
-
* every ADR. The specs cost nothing extra
|
|
38
|
-
*
|
|
39
|
-
* same text.
|
|
9
|
+
* every ADR. The specs cost nothing extra: the run's `FleetContext` has already
|
|
10
|
+
* read both to parse their requirements, and the memo hands back the same text.
|
|
40
11
|
*/
|
|
41
12
|
export async function serviceDocuments(paths) {
|
|
42
13
|
return [paths.spec, paths.archSpec, paths.runbook, ...(await markdownFiles(paths.adrsDir))];
|
|
@@ -52,7 +23,7 @@ export async function featureDocuments(featureDir, fleet) {
|
|
|
52
23
|
const spec = featureSpecPaths(featureDir, svc);
|
|
53
24
|
docs.push(spec.spec, spec.archSpec);
|
|
54
25
|
}
|
|
55
|
-
const capabilities =
|
|
26
|
+
const capabilities = await fleet.featureCapabilityDeltas(featureDir);
|
|
56
27
|
docs.push(...capabilities.docs.map((d) => d.spec));
|
|
57
28
|
// The definitions this feature introduces. Their own links are graded like
|
|
58
29
|
// any other document's — a term that cites a term the feature is not adding
|
|
@@ -70,9 +41,7 @@ export async function featureDocuments(featureDir, fleet) {
|
|
|
70
41
|
* the fleet repeated on every service target is the report.
|
|
71
42
|
*/
|
|
72
43
|
export async function fleetDocuments(docsDir, fleet) {
|
|
73
|
-
const capabilities = fleet
|
|
74
|
-
? await readCapabilityTree(capabilityDocsDir(docsDir))
|
|
75
|
-
: (await fleet.capabilities(docsDir)).tree;
|
|
44
|
+
const capabilities = (await fleet.capabilities(docsDir)).tree;
|
|
76
45
|
const glossary = await readGlossary(glossaryDir(docsDir));
|
|
77
46
|
return [
|
|
78
47
|
...(await markdownFiles(fleetAdrsDir(docsDir))),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"corpus.js","sourceRoot":"","sources":["../../../src/core/links/corpus.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"corpus.js","sourceRoot":"","sources":["../../../src/core/links/corpus.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * WHICH documents loam reads links out of — the corpus, spelled once.\n *\n * Two readers need it and must not disagree. `commands/validate/links/` grades\n * each target's own documents for `link.unresolved`; `core/glossary/backlinks.ts`\n * reads the WHOLE fleet's, because \"which documents use this term\" is a question\n * no single target can answer. A corpus that differed between them would report\n * a term as unused while the very document citing it was being graded one target\n * over.\n *\n * THE CORPUS IS EVERY AUTHORED MARKDOWN DOCUMENT, and the word doing the work is\n * authored. `AGENTS.md` and the scaffolded `README.md` are excluded because loam\n * WRITES them: a finding against generated prose names a defect its reader\n * cannot fix by editing, since the next `loam init` restores it. Their links are\n * loam's own problem, held on this side of the boundary by\n * `test/docs-facts.test.ts` and `test/package-docs.test.ts`.\n *\n * ADRs AND RUNBOOKS ARE IN IT, and they are the reason the convention was\n * written down at all: an ADR that supersedes another says which, by linking to\n * it. They are also the first documents loam reads that it previously only\n * counted, which is what `link.unreadable` exists for.\n *\n * `delta.likec4` IS NOT, and neither is any YAML: this is a markdown question.\n * The one thing a delta holds that addresses another file — `metadata { op }` —\n * has its own resolution and its own findings.\n */\nimport type { FleetContext } from \"../fleet-context.js\";\nimport { featureGlossary } from \"../glossary/delta.js\";\nimport { readGlossary } from \"../glossary/tree.js\";\nimport type { DocsDir, FeatureDir } from \"../kernel/ids/dirs.js\";\nimport { featurePaths, featureSpecPaths, fleetAdrsDir, servicePathsAt, type ServicePaths } from \"../repo/paths.js\";\nimport { glossaryDir } from \"../repo/authored/paths.js\";\nimport { featureSpecServices, listFeatures, listServices } from \"../repo/repo.js\";\nimport { markdownFiles } from \"../repo/tree/fs.js\";\n\n/**\n * One service's authored documents: the two requirement specs, the runbook, and\n * every ADR. The specs cost nothing extra: the run's `FleetContext` has already\n * read both to parse their requirements, and the memo hands back the same text.\n */\nexport async function serviceDocuments(paths: ServicePaths): Promise<string[]> {\n return [paths.spec, paths.archSpec, paths.runbook, ...(await markdownFiles(paths.adrsDir))];\n}\n\n/**\n * One feature's authored documents: the intent, each addressed service's two\n * spec deltas, every ADR, and each capability delta document.\n */\nexport async function featureDocuments(featureDir: FeatureDir, fleet: FleetContext): Promise<string[]> {\n const paths = featurePaths(featureDir);\n const docs = [paths.intent, ...(await markdownFiles(paths.adrsDir))];\n for (const svc of await featureSpecServices(featureDir, fleet)) {\n const spec = featureSpecPaths(featureDir, svc);\n docs.push(spec.spec, spec.archSpec);\n }\n const capabilities = await fleet.featureCapabilityDeltas(featureDir);\n docs.push(...capabilities.docs.map((d) => d.spec));\n // The definitions this feature introduces. Their own links are graded like\n // any other document's — a term that cites a term the feature is not adding\n // is a broken join whether or not it has shipped yet.\n docs.push(...(await featureGlossary(featureDir)).terms.map((t) => t.path));\n return docs;\n}\n\n/**\n * The documents that belong to no service and no feature: the fleet's own\n * decision records, the living capability tree, and the glossary.\n *\n * Graded at fleet scope, so `validate --all` reports them once. A single-target\n * run says nothing about them — the rule `permissions.unenforced` and\n * `capability.invalid` already follow, and for the same reason: a finding about\n * the fleet repeated on every service target is the report.\n */\nexport async function fleetDocuments(docsDir: DocsDir, fleet: FleetContext): Promise<string[]> {\n const capabilities = (await fleet.capabilities(docsDir)).tree;\n const glossary = await readGlossary(glossaryDir(docsDir));\n return [\n ...(await markdownFiles(fleetAdrsDir(docsDir))),\n ...capabilities.docs.map((d) => d.spec),\n ...glossary.terms.map((t) => t.path),\n ];\n}\n\n/**\n * Every authored document in the repository — the union of the three above over\n * every service and every in-flight feature.\n *\n * ARCHIVED FEATURES ARE OUT, and the omission is the point rather than an\n * oversight. `features/archive/<FEAT>/` is the evolution history: its documents\n * describe a change that already shipped, its links point at whatever the tree\n * looked like then, and grading them would make every directory rename a\n * retroactive error against a record nobody may edit. `listFeatures` excludes\n * them by default, which is the same judgement one enumeration up.\n */\nexport async function allAuthoredDocuments(docsDir: DocsDir, fleet: FleetContext): Promise<string[]> {\n const docs = await fleetDocuments(docsDir, fleet);\n for (const service of await listServices(docsDir, fleet)) {\n docs.push(...(await serviceDocuments(servicePathsAt(service.dir))));\n }\n for (const feature of await listFeatures(docsDir, {}, fleet)) {\n docs.push(...(await featureDocuments(feature.dir, fleet)));\n }\n return docs;\n}\n"]}
|
package/dist/core/mcp/argv.js
CHANGED
|
@@ -1,3 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The MCP inputSchema for one tool: a closed object, so a typo'd argument
|
|
3
|
+
* refuses instead of vanishing, with the required set and the positional order
|
|
4
|
+
* `toArgv` enforces declared beside it.
|
|
5
|
+
*/
|
|
6
|
+
export function toInputSchema(tool) {
|
|
7
|
+
const properties = {};
|
|
8
|
+
for (const positional of tool.positionals) {
|
|
9
|
+
properties[positional.property] = positional.variadic
|
|
10
|
+
? { type: "array", items: { type: "string" }, description: positional.description }
|
|
11
|
+
: { type: "string", description: positional.description };
|
|
12
|
+
}
|
|
13
|
+
for (const flag of tool.flags) {
|
|
14
|
+
properties[flag.property] =
|
|
15
|
+
flag.kind === "boolean"
|
|
16
|
+
? { type: "boolean", description: flag.description }
|
|
17
|
+
: flag.kind === "strings"
|
|
18
|
+
? { type: "array", items: { type: "string" }, description: flag.description }
|
|
19
|
+
: { type: "string", description: flag.description };
|
|
20
|
+
}
|
|
21
|
+
const required = [
|
|
22
|
+
...tool.positionals.filter((p) => p.required).map((p) => p.property),
|
|
23
|
+
...tool.flags.filter((f) => f.required === true).map((f) => f.property),
|
|
24
|
+
];
|
|
25
|
+
return {
|
|
26
|
+
type: "object",
|
|
27
|
+
properties,
|
|
28
|
+
...(required.length > 0 ? { required } : {}),
|
|
29
|
+
...orderRule(tool),
|
|
30
|
+
additionalProperties: false,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The rule `positionalTokens` enforces, declared: a positional after an
|
|
35
|
+
* optional one needs it, because positionals reach argv by position and the
|
|
36
|
+
* later value would otherwise be read in the earlier one's slot. Without it a
|
|
37
|
+
* client that validated `{name: "smoke"}` for `loam_list` against the schema
|
|
38
|
+
* it was given passed, and was then refused `-32602` by the server.
|
|
39
|
+
*
|
|
40
|
+
* Read off the declaration order rather than spelled per tool, so a tool that
|
|
41
|
+
* gains a positional after an optional one is declared the day it is refused.
|
|
42
|
+
* Each later positional needs every earlier OPTIONAL one; an earlier required
|
|
43
|
+
* one is in `required` already.
|
|
44
|
+
*
|
|
45
|
+
* Two keywords, because presence means two things. A scalar that is present
|
|
46
|
+
* always yields a token, so presence is the whole condition and
|
|
47
|
+
* `dependentRequired` says exactly that. A variadic yields tokens only when it
|
|
48
|
+
* has members: an empty one moves nothing into anybody's slot, and
|
|
49
|
+
* `positionalTokens` serves it — `{args: []}` with no `workflow` is the
|
|
50
|
+
* workflow list. `dependentRequired` there would forbid a call the server
|
|
51
|
+
* answers, the same disagreement turned the other way, so the variadic's rule
|
|
52
|
+
* sits under `dependentSchemas`: once it is present, either the earlier ones
|
|
53
|
+
* are too or it is empty. `anyOf` rather than `if`/`then`, which says the same
|
|
54
|
+
* but puts a `then` key on an object, and a thenable literal is one `await`
|
|
55
|
+
* away from being called.
|
|
56
|
+
*/
|
|
57
|
+
function orderRule(tool) {
|
|
58
|
+
const dependentRequired = {};
|
|
59
|
+
const dependentSchemas = {};
|
|
60
|
+
const earlier = [];
|
|
61
|
+
for (const positional of tool.positionals) {
|
|
62
|
+
if (earlier.length > 0 && positional.variadic) {
|
|
63
|
+
dependentSchemas[positional.property] = {
|
|
64
|
+
anyOf: [{ required: [...earlier] }, { properties: { [positional.property]: { maxItems: 0 } } }],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
else if (earlier.length > 0) {
|
|
68
|
+
dependentRequired[positional.property] = [...earlier];
|
|
69
|
+
}
|
|
70
|
+
if (!positional.required)
|
|
71
|
+
earlier.push(positional.property);
|
|
72
|
+
}
|
|
73
|
+
return {
|
|
74
|
+
...(Object.keys(dependentRequired).length > 0 ? { dependentRequired } : {}),
|
|
75
|
+
...(Object.keys(dependentSchemas).length > 0 ? { dependentSchemas } : {}),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
1
78
|
/**
|
|
2
79
|
* A string value that argv would read as a flag is refused before any command
|
|
3
80
|
* sees it: {"target": "--type"} must not become a parsed option. Commander
|
|
@@ -30,13 +107,30 @@ function checkedStrings(property, value) {
|
|
|
30
107
|
}
|
|
31
108
|
return { ok: true, tokens };
|
|
32
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* The positionals, in declaration order — and refused when one would land in
|
|
112
|
+
* another's slot.
|
|
113
|
+
*
|
|
114
|
+
* A positional reaches argv by POSITION, so an optional one left out leaves no
|
|
115
|
+
* gap: whatever follows it moves up into its place. `loam_list` with `{name:
|
|
116
|
+
* "services"}` built `list services` and answered ok:true with the services
|
|
117
|
+
* listing, a wrong answer with nothing in it saying so; `loam_instructions`
|
|
118
|
+
* with `{args: [...]}` and no `workflow` read the first arg as the workflow.
|
|
119
|
+
* Refused here instead, as the invalid-params problem a missing REQUIRED
|
|
120
|
+
* positional already is, naming the slot the caller left empty. A later
|
|
121
|
+
* positional that yields no token — an empty variadic — moves nothing up, so
|
|
122
|
+
* it passes. `orderRule` above declares the same rule in the advertised
|
|
123
|
+
* schema; the two change together.
|
|
124
|
+
*/
|
|
33
125
|
function positionalTokens(tool, args) {
|
|
34
126
|
const tokens = [];
|
|
127
|
+
let absent;
|
|
35
128
|
for (const positional of tool.positionals) {
|
|
36
129
|
const value = args[positional.property];
|
|
37
130
|
if (value === undefined) {
|
|
38
131
|
if (positional.required)
|
|
39
132
|
return { ok: false, problem: `required argument '${positional.property}' is missing` };
|
|
133
|
+
absent ??= positional.property;
|
|
40
134
|
continue;
|
|
41
135
|
}
|
|
42
136
|
const checked = positional.variadic
|
|
@@ -44,6 +138,13 @@ function positionalTokens(tool, args) {
|
|
|
44
138
|
: checkedString(positional.property, value);
|
|
45
139
|
if (!checked.ok)
|
|
46
140
|
return checked;
|
|
141
|
+
if (absent !== undefined && checked.tokens.length > 0) {
|
|
142
|
+
return {
|
|
143
|
+
ok: false,
|
|
144
|
+
problem: `argument '${positional.property}' requires '${absent}' — positionals are read in order, ` +
|
|
145
|
+
`so without '${absent}' this value would be read as '${absent}'`,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
47
148
|
tokens.push(...checked.tokens);
|
|
48
149
|
}
|
|
49
150
|
return { ok: true, tokens };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"argv.js","sourceRoot":"","sources":["../../../src/core/mcp/argv.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * How one MCP tool call's JSON arguments become an argv the CLI already\n * trusts — the boundary where an argument value could otherwise smuggle a\n * flag. The tool TABLE (what the tools are) lives in `./tools.ts`; this\n * module owns the crossing.\n */\nimport type { McpTool } from \"./tools.js\";\n\n/** One checked step of argv construction: the tokens it yields, or the invalid-params problem. */\ntype Checked =\n | { readonly ok: true; readonly tokens: readonly string[] }\n | { readonly ok: false; readonly problem: string };\n\nexport type ArgvOutcome =\n | { readonly ok: true; readonly argv: readonly string[] }\n | { readonly ok: false; readonly problem: string };\n\n/**\n * A string value that argv would read as a flag is refused before any command\n * sees it: {\"target\": \"--type\"} must not become a parsed option. Commander\n * cannot make this distinction after the fact — by then the token IS a flag —\n * so the boundary is here, on every string that crosses, array members\n * included. No shell is ever involved, so this is the only smuggling path.\n */\nfunction smuggled(property: string, value: string): string | null {\n return value.startsWith(\"-\")\n ? `argument '${property}' value '${value}' begins with '-' — a value argv would read as a flag is refused`\n : null;\n}\n\n/** One string value checked for type and smuggling. */\nfunction checkedString(property: string, value: unknown): Checked {\n if (typeof value !== \"string\") return { ok: false, problem: `argument '${property}' must be a string` };\n const bad = smuggled(property, value);\n return bad === null ? { ok: true, tokens: [value] } : { ok: false, problem: bad };\n}\n\n/** An array value checked member by member — rebuilt, not cast, so the claim is earned. */\nfunction checkedStrings(property: string, value: unknown): Checked {\n if (!Array.isArray(value)) return { ok: false, problem: `argument '${property}' must be an array of strings` };\n const tokens: string[] = [];\n for (const entry of value) {\n const checked = checkedString(property, entry);\n if (!checked.ok) return checked;\n tokens.push(...checked.tokens);\n }\n return { ok: true, tokens };\n}\n\nfunction positionalTokens(tool: McpTool, args: Record<string, unknown>): Checked {\n const tokens: string[] = [];\n for (const positional of tool.positionals) {\n const value = args[positional.property];\n if (value === undefined) {\n if (positional.required) return { ok: false, problem: `required argument '${positional.property}' is missing` };\n continue;\n }\n const checked = positional.variadic\n ? checkedStrings(positional.property, value)\n : checkedString(positional.property, value);\n if (!checked.ok) return checked;\n tokens.push(...checked.tokens);\n }\n return { ok: true, tokens };\n}\n\nfunction flagTokens(tool: McpTool, args: Record<string, unknown>): Checked {\n const tokens: string[] = [];\n for (const flag of tool.flags) {\n const value = args[flag.property];\n if (value === undefined) {\n // The same refusal absent required positionals get: the client learns\n // \"-32602 missing argument\", not an invalid-option envelope after the\n // command already refused.\n if (flag.required === true) return { ok: false, problem: `required argument '${flag.property}' is missing` };\n continue;\n }\n if (flag.kind === \"boolean\") {\n if (typeof value !== \"boolean\") return { ok: false, problem: `argument '${flag.property}' must be a boolean` };\n if (value) tokens.push(flag.flag);\n continue;\n }\n const checked = flag.kind === \"strings\"\n ? checkedStrings(flag.property, value)\n : checkedString(flag.property, value);\n if (!checked.ok) return checked;\n // A repeatable flag repeats per value; a single-valued one appears once.\n for (const token of checked.tokens) tokens.push(flag.flag, token);\n }\n return { ok: true, tokens };\n}\n\n/**\n * The argv for one tool call — or the invalid-params problem that stops it.\n * `--json` is always appended: the envelope is the tool-result contract, and\n * a client cannot opt out of it into the human rendering. Unknown argument\n * names refuse rather than vanish — the schema says additionalProperties\n * false, and a server that enforced that only in the schema would silently\n * drop the typo'd argument of any client that skipped validation.\n */\nexport function toArgv(tool: McpTool, args: Record<string, unknown>): ArgvOutcome {\n const known = new Set([\n ...tool.positionals.map((p) => p.property),\n ...tool.flags.map((f) => f.property),\n ]);\n for (const property of Object.keys(args)) {\n if (!known.has(property)) {\n const allowed = known.size === 0 ? \"no arguments\" : [...known].join(\", \");\n return { ok: false, problem: `unknown argument '${property}' for ${tool.name} — expected ${allowed}` };\n }\n }\n const positionals = positionalTokens(tool, args);\n if (!positionals.ok) return { ok: false, problem: positionals.problem };\n const flags = flagTokens(tool, args);\n if (!flags.ok) return { ok: false, problem: flags.problem };\n return {\n ok: true,\n argv: [tool.command, ...positionals.tokens, ...flags.tokens, ...(tool.fixed ?? []), \"--json\"],\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"argv.js","sourceRoot":"","sources":["../../../src/core/mcp/argv.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * How one MCP tool call's JSON arguments become an argv the CLI already\n * trusts — the boundary where an argument value could otherwise smuggle a\n * flag. The tool TABLE (what the tools are) lives in `./tools.ts`; this\n * module owns the crossing, and the inputSchema that declares it: the schema\n * a client validates against and the argv builder that refuses what it\n * forbids are one contract written twice, so they sit in one module.\n */\nimport type { McpTool } from \"./tools.js\";\n\n/**\n * The MCP inputSchema for one tool: a closed object, so a typo'd argument\n * refuses instead of vanishing, with the required set and the positional order\n * `toArgv` enforces declared beside it.\n */\nexport function toInputSchema(tool: McpTool): Record<string, unknown> {\n const properties: Record<string, unknown> = {};\n for (const positional of tool.positionals) {\n properties[positional.property] = positional.variadic\n ? { type: \"array\", items: { type: \"string\" }, description: positional.description }\n : { type: \"string\", description: positional.description };\n }\n for (const flag of tool.flags) {\n properties[flag.property] =\n flag.kind === \"boolean\"\n ? { type: \"boolean\", description: flag.description }\n : flag.kind === \"strings\"\n ? { type: \"array\", items: { type: \"string\" }, description: flag.description }\n : { type: \"string\", description: flag.description };\n }\n const required = [\n ...tool.positionals.filter((p) => p.required).map((p) => p.property),\n ...tool.flags.filter((f) => f.required === true).map((f) => f.property),\n ];\n return {\n type: \"object\",\n properties,\n ...(required.length > 0 ? { required } : {}),\n ...orderRule(tool),\n additionalProperties: false,\n };\n}\n\n/**\n * The rule `positionalTokens` enforces, declared: a positional after an\n * optional one needs it, because positionals reach argv by position and the\n * later value would otherwise be read in the earlier one's slot. Without it a\n * client that validated `{name: \"smoke\"}` for `loam_list` against the schema\n * it was given passed, and was then refused `-32602` by the server.\n *\n * Read off the declaration order rather than spelled per tool, so a tool that\n * gains a positional after an optional one is declared the day it is refused.\n * Each later positional needs every earlier OPTIONAL one; an earlier required\n * one is in `required` already.\n *\n * Two keywords, because presence means two things. A scalar that is present\n * always yields a token, so presence is the whole condition and\n * `dependentRequired` says exactly that. A variadic yields tokens only when it\n * has members: an empty one moves nothing into anybody's slot, and\n * `positionalTokens` serves it — `{args: []}` with no `workflow` is the\n * workflow list. `dependentRequired` there would forbid a call the server\n * answers, the same disagreement turned the other way, so the variadic's rule\n * sits under `dependentSchemas`: once it is present, either the earlier ones\n * are too or it is empty. `anyOf` rather than `if`/`then`, which says the same\n * but puts a `then` key on an object, and a thenable literal is one `await`\n * away from being called.\n */\nfunction orderRule(tool: McpTool): Record<string, unknown> {\n const dependentRequired: Record<string, string[]> = {};\n const dependentSchemas: Record<string, unknown> = {};\n const earlier: string[] = [];\n for (const positional of tool.positionals) {\n if (earlier.length > 0 && positional.variadic) {\n dependentSchemas[positional.property] = {\n anyOf: [{ required: [...earlier] }, { properties: { [positional.property]: { maxItems: 0 } } }],\n };\n } else if (earlier.length > 0) {\n dependentRequired[positional.property] = [...earlier];\n }\n if (!positional.required) earlier.push(positional.property);\n }\n return {\n ...(Object.keys(dependentRequired).length > 0 ? { dependentRequired } : {}),\n ...(Object.keys(dependentSchemas).length > 0 ? { dependentSchemas } : {}),\n };\n}\n\n/** One checked step of argv construction: the tokens it yields, or the invalid-params problem. */\ntype Checked =\n | { readonly ok: true; readonly tokens: readonly string[] }\n | { readonly ok: false; readonly problem: string };\n\nexport type ArgvOutcome =\n | { readonly ok: true; readonly argv: readonly string[] }\n | { readonly ok: false; readonly problem: string };\n\n/**\n * A string value that argv would read as a flag is refused before any command\n * sees it: {\"target\": \"--type\"} must not become a parsed option. Commander\n * cannot make this distinction after the fact — by then the token IS a flag —\n * so the boundary is here, on every string that crosses, array members\n * included. No shell is ever involved, so this is the only smuggling path.\n */\nfunction smuggled(property: string, value: string): string | null {\n return value.startsWith(\"-\")\n ? `argument '${property}' value '${value}' begins with '-' — a value argv would read as a flag is refused`\n : null;\n}\n\n/** One string value checked for type and smuggling. */\nfunction checkedString(property: string, value: unknown): Checked {\n if (typeof value !== \"string\") return { ok: false, problem: `argument '${property}' must be a string` };\n const bad = smuggled(property, value);\n return bad === null ? { ok: true, tokens: [value] } : { ok: false, problem: bad };\n}\n\n/** An array value checked member by member — rebuilt, not cast, so the claim is earned. */\nfunction checkedStrings(property: string, value: unknown): Checked {\n if (!Array.isArray(value)) return { ok: false, problem: `argument '${property}' must be an array of strings` };\n const tokens: string[] = [];\n for (const entry of value) {\n const checked = checkedString(property, entry);\n if (!checked.ok) return checked;\n tokens.push(...checked.tokens);\n }\n return { ok: true, tokens };\n}\n\n/**\n * The positionals, in declaration order — and refused when one would land in\n * another's slot.\n *\n * A positional reaches argv by POSITION, so an optional one left out leaves no\n * gap: whatever follows it moves up into its place. `loam_list` with `{name:\n * \"services\"}` built `list services` and answered ok:true with the services\n * listing, a wrong answer with nothing in it saying so; `loam_instructions`\n * with `{args: [...]}` and no `workflow` read the first arg as the workflow.\n * Refused here instead, as the invalid-params problem a missing REQUIRED\n * positional already is, naming the slot the caller left empty. A later\n * positional that yields no token — an empty variadic — moves nothing up, so\n * it passes. `orderRule` above declares the same rule in the advertised\n * schema; the two change together.\n */\nfunction positionalTokens(tool: McpTool, args: Record<string, unknown>): Checked {\n const tokens: string[] = [];\n let absent: string | undefined;\n for (const positional of tool.positionals) {\n const value = args[positional.property];\n if (value === undefined) {\n if (positional.required) return { ok: false, problem: `required argument '${positional.property}' is missing` };\n absent ??= positional.property;\n continue;\n }\n const checked = positional.variadic\n ? checkedStrings(positional.property, value)\n : checkedString(positional.property, value);\n if (!checked.ok) return checked;\n if (absent !== undefined && checked.tokens.length > 0) {\n return {\n ok: false,\n problem:\n `argument '${positional.property}' requires '${absent}' — positionals are read in order, ` +\n `so without '${absent}' this value would be read as '${absent}'`,\n };\n }\n tokens.push(...checked.tokens);\n }\n return { ok: true, tokens };\n}\n\nfunction flagTokens(tool: McpTool, args: Record<string, unknown>): Checked {\n const tokens: string[] = [];\n for (const flag of tool.flags) {\n const value = args[flag.property];\n if (value === undefined) {\n // The same refusal absent required positionals get: the client learns\n // \"-32602 missing argument\", not an invalid-option envelope after the\n // command already refused.\n if (flag.required === true) return { ok: false, problem: `required argument '${flag.property}' is missing` };\n continue;\n }\n if (flag.kind === \"boolean\") {\n if (typeof value !== \"boolean\") return { ok: false, problem: `argument '${flag.property}' must be a boolean` };\n if (value) tokens.push(flag.flag);\n continue;\n }\n const checked = flag.kind === \"strings\"\n ? checkedStrings(flag.property, value)\n : checkedString(flag.property, value);\n if (!checked.ok) return checked;\n // A repeatable flag repeats per value; a single-valued one appears once.\n for (const token of checked.tokens) tokens.push(flag.flag, token);\n }\n return { ok: true, tokens };\n}\n\n/**\n * The argv for one tool call — or the invalid-params problem that stops it.\n * `--json` is always appended: the envelope is the tool-result contract, and\n * a client cannot opt out of it into the human rendering. Unknown argument\n * names refuse rather than vanish — the schema says additionalProperties\n * false, and a server that enforced that only in the schema would silently\n * drop the typo'd argument of any client that skipped validation.\n */\nexport function toArgv(tool: McpTool, args: Record<string, unknown>): ArgvOutcome {\n const known = new Set([\n ...tool.positionals.map((p) => p.property),\n ...tool.flags.map((f) => f.property),\n ]);\n for (const property of Object.keys(args)) {\n if (!known.has(property)) {\n const allowed = known.size === 0 ? \"no arguments\" : [...known].join(\", \");\n return { ok: false, problem: `unknown argument '${property}' for ${tool.name} — expected ${allowed}` };\n }\n }\n const positionals = positionalTokens(tool, args);\n if (!positionals.ok) return { ok: false, problem: positionals.problem };\n const flags = flagTokens(tool, args);\n if (!flags.ok) return { ok: false, problem: flags.problem };\n return {\n ok: true,\n argv: [tool.command, ...positionals.tokens, ...flags.tokens, ...(tool.fixed ?? []), \"--json\"],\n };\n}\n"]}
|
|
@@ -13,7 +13,7 @@ export const MCP_AUTHOR_TOOLS = [
|
|
|
13
13
|
name: "loam_new",
|
|
14
14
|
command: "new",
|
|
15
15
|
description: "Scaffold a feature in the docs repo. Opt-in writer; refuses an existing feature. " +
|
|
16
|
-
"CLI equivalent: loam new <featureId> [--title <text>] [--touches <id>...] [--new-service <id>...] [--capability <id>...] --json",
|
|
16
|
+
"CLI equivalent: loam new <featureId> [--title <text>] [--touches <id>...] [--new-service <id>...] [--capability <id>...] [--modifies <Req-ID>...] --json",
|
|
17
17
|
positionals: [
|
|
18
18
|
{ property: "featureId", required: true, variadic: false, description: "new feature id, e.g. FEAT-101" },
|
|
19
19
|
],
|
|
@@ -22,6 +22,7 @@ export const MCP_AUTHOR_TOOLS = [
|
|
|
22
22
|
{ property: "touches", flag: "--touches", kind: "strings", description: "existing services changed; repeatable" },
|
|
23
23
|
{ property: "newServices", flag: "--new-service", kind: "strings", description: "services introduced; repeatable" },
|
|
24
24
|
{ property: "capabilities", flag: "--capability", kind: "strings", description: "business capabilities changed; repeatable" },
|
|
25
|
+
{ property: "modifies", flag: "--modifies", kind: "strings", description: "living Requirement-IDs of touched services this feature rewrites, scaffolded as pinned MODIFIED blocks; repeatable" },
|
|
25
26
|
],
|
|
26
27
|
annotations: WRITE_ANNOTATIONS,
|
|
27
28
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"author-tools.js","sourceRoot":"","sources":["../../../src/core/mcp/author-tools.ts"],"names":[],"mappings":"AAGA,MAAM,iBAAiB,GAAG;IACxB,YAAY,EAAE,KAAK;IACnB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,KAAK;IACrB,aAAa,EAAE,KAAK;CACZ,CAAC;AAEX,MAAM,sBAAsB,GAAG;IAC7B,GAAG,iBAAiB;IACpB,cAAc,EAAE,IAAI;CACZ,CAAC;AAEX,MAAM,CAAC,MAAM,gBAAgB,GAAuB;IAClD;QACE,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,KAAK;QACd,WAAW,EACT,mFAAmF;YACnF,
|
|
1
|
+
{"version":3,"file":"author-tools.js","sourceRoot":"","sources":["../../../src/core/mcp/author-tools.ts"],"names":[],"mappings":"AAGA,MAAM,iBAAiB,GAAG;IACxB,YAAY,EAAE,KAAK;IACnB,eAAe,EAAE,KAAK;IACtB,cAAc,EAAE,KAAK;IACrB,aAAa,EAAE,KAAK;CACZ,CAAC;AAEX,MAAM,sBAAsB,GAAG;IAC7B,GAAG,iBAAiB;IACpB,cAAc,EAAE,IAAI;CACZ,CAAC;AAEX,MAAM,CAAC,MAAM,gBAAgB,GAAuB;IAClD;QACE,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,KAAK;QACd,WAAW,EACT,mFAAmF;YACnF,0JAA0J;QAC5J,WAAW,EAAE;YACX,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,+BAA+B,EAAE;SACzG;QACD,KAAK,EAAE;YACL,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,gCAAgC,EAAE;YACrG,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,uCAAuC,EAAE;YACjH,EAAE,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,eAAe,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,iCAAiC,EAAE;YACnH,EAAE,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,2CAA2C,EAAE;YAC7H,EAAE,QAAQ,EAAE,UAAU,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,oHAAoH,EAAE;SACjM;QACD,WAAW,EAAE,iBAAiB;KAC/B;IACD;QACE,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,QAAQ;QACjB,WAAW,EACT,4GAA4G;YAC5G,iEAAiE;QACnE,yEAAyE;QACzE,sEAAsE;QACtE,2EAA2E;QAC3E,0EAA0E;QAC1E,gDAAgD;QAChD,WAAW,EAAE;YACX,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,0CAA0C,EAAE;SACrH;QACD,KAAK,EAAE;YACL,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,iCAAiC,EAAE;SAC3G;QACD,WAAW,EAAE,sBAAsB;KACpC;IACD;QACE,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,SAAS;QAClB,WAAW,EACT,2HAA2H;YAC3H,kEAAkE;QACpE,WAAW,EAAE;YACX,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,uCAAuC,EAAE;SAClH;QACD,KAAK,EAAE;YACL,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,qBAAqB,EAAE;SAC/F;QACD,WAAW,EAAE,sBAAsB;KACpC;IACD;QACE,IAAI,EAAE,mBAAmB;QACzB,OAAO,EAAE,SAAS;QAClB,WAAW,EACT,oFAAoF;YACpF,2DAA2D;QAC7D,WAAW,EAAE;YACX,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,sBAAsB,EAAE;SAChG;QACD,KAAK,EAAE,EAAE;QACT,KAAK,EAAE,CAAC,WAAW,CAAC;QACpB,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,aAAa,EAAE,KAAK,EAAE;KAC1D;CACF,CAAC","sourcesContent":["/** Opt-in MCP writers. Vouch and a committing archive are never exposed. */\nimport type { McpTool } from \"./tools.js\";\n\nconst WRITE_ANNOTATIONS = {\n readOnlyHint: false,\n destructiveHint: false,\n idempotentHint: false,\n openWorldHint: false,\n} as const;\n\nconst SAFE_WRITE_ANNOTATIONS = {\n ...WRITE_ANNOTATIONS,\n idempotentHint: true,\n} as const;\n\nexport const MCP_AUTHOR_TOOLS: readonly McpTool[] = [\n {\n name: \"loam_new\",\n command: \"new\",\n description:\n \"Scaffold a feature in the docs repo. Opt-in writer; refuses an existing feature. \" +\n \"CLI equivalent: loam new <featureId> [--title <text>] [--touches <id>...] [--new-service <id>...] [--capability <id>...] [--modifies <Req-ID>...] --json\",\n positionals: [\n { property: \"featureId\", required: true, variadic: false, description: \"new feature id, e.g. FEAT-101\" },\n ],\n flags: [\n { property: \"title\", flag: \"--title\", kind: \"string\", description: \"human title and directory slug\" },\n { property: \"touches\", flag: \"--touches\", kind: \"strings\", description: \"existing services changed; repeatable\" },\n { property: \"newServices\", flag: \"--new-service\", kind: \"strings\", description: \"services introduced; repeatable\" },\n { property: \"capabilities\", flag: \"--capability\", kind: \"strings\", description: \"business capabilities changed; repeatable\" },\n { property: \"modifies\", flag: \"--modifies\", kind: \"strings\", description: \"living Requirement-IDs of touched services this feature rewrites, scaffolded as pinned MODIFIED blocks; repeatable\" },\n ],\n annotations: WRITE_ANNOTATIONS,\n },\n {\n name: \"loam_rebase\",\n command: \"rebase\",\n description:\n \"Pin a feature delta to the living baselines after the agent has reconciled them. Opt-in journaled writer. \" +\n \"CLI equivalent: loam rebase [featureId] [--service <id>] --json\",\n // Optional because the REGISTERED argument is — `loam rebase` relaxed it\n // for `--living`, which names no feature — and the schema mirrors the\n // command it wraps rather than the subset this tool exposes. `--living` is\n // not offered here, so an omitted id reaches the CLI's own refusal, which\n // names the flag that makes the omission legal.\n positionals: [\n { property: \"featureId\", required: false, variadic: false, description: \"feature id whose baselines were reviewed\" },\n ],\n flags: [\n { property: \"service\", flag: \"--service\", kind: \"string\", description: \"restrict to one touched service\" },\n ],\n annotations: SAFE_WRITE_ANNOTATIONS,\n },\n {\n name: \"loam_gherkin\",\n command: \"gherkin\",\n description:\n \"Generate loam-owned Gherkin files in the bound service repository. Opt-in journaled writer; refuses ownership conflicts. \" +\n \"CLI equivalent: loam gherkin [featureId] [--service <id>] --json\",\n positionals: [\n { property: \"featureId\", required: false, variadic: false, description: \"feature id; omit for the living suite\" },\n ],\n flags: [\n { property: \"service\", flag: \"--service\", kind: \"string\", description: \"service to emit for\" },\n ],\n annotations: SAFE_WRITE_ANNOTATIONS,\n },\n {\n name: \"loam_archive_plan\",\n command: \"archive\",\n description:\n \"Compute the complete archive plan without writing. The server enforces --dry-run. \" +\n \"CLI equivalent: loam archive <featureId> --dry-run --json\",\n positionals: [\n { property: \"featureId\", required: true, variadic: false, description: \"feature id to review\" },\n ],\n flags: [],\n fixed: [\"--dry-run\"],\n annotations: { readOnlyHint: true, openWorldHint: false },\n },\n];\n"]}
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { isRecord } from "../kernel/records.js";
|
|
18
18
|
import { LOAM_VERSION } from "../envelope/version.js";
|
|
19
|
-
import { toArgv } from "./argv.js";
|
|
20
|
-
import { MCP_TOOLS, READ_ONLY_ANNOTATIONS,
|
|
19
|
+
import { toArgv, toInputSchema } from "./argv.js";
|
|
20
|
+
import { MCP_TOOLS, READ_ONLY_ANNOTATIONS, toolByName, } from "./tools.js";
|
|
21
21
|
import { AGENTS_MD } from "../agent/agents-md.js";
|
|
22
22
|
import { PROTOCOLS } from "../agent/protocol.js";
|
|
23
23
|
import { withoutFixTables } from "../explain/fix-tables.js";
|