@canonical/pragma-cli 0.38.0 → 0.42.0
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/README.md +3 -3
- package/dist/package.json +16 -16
- package/dist/pragma.conf.js +273 -176
- package/dist/pragma.conf.js.map +1 -1
- package/dist/src/capabilities/capabilities/capabilities.verb.js +2 -0
- package/dist/src/capabilities/capabilities/capabilities.verb.js.map +1 -1
- package/dist/src/capabilities/capabilities/catalog.js +47 -51
- package/dist/src/capabilities/capabilities/catalog.js.map +1 -1
- package/dist/src/capabilities/capabilities/index.js +2 -0
- package/dist/src/capabilities/capabilities/index.js.map +1 -1
- package/dist/src/capabilities/capabilities/types.js +5 -5
- package/dist/src/capabilities/colophon/colophon.render.js +7 -4
- package/dist/src/capabilities/colophon/colophon.render.js.map +1 -1
- package/dist/src/capabilities/colophon/colophon.verb.js +1 -0
- package/dist/src/capabilities/colophon/colophon.verb.js.map +1 -1
- package/dist/src/capabilities/colophon/markdownTerminal.js.map +1 -1
- package/dist/src/capabilities/config/get.verb.js +2 -0
- package/dist/src/capabilities/config/get.verb.js.map +1 -1
- package/dist/src/capabilities/config/runField.js +2 -2
- package/dist/src/capabilities/config/runField.js.map +1 -1
- package/dist/src/capabilities/config/set.verb.js +2 -0
- package/dist/src/capabilities/config/set.verb.js.map +1 -1
- package/dist/src/capabilities/config/show.render.js.map +1 -1
- package/dist/src/capabilities/config/show.verb.js +1 -0
- package/dist/src/capabilities/config/show.verb.js.map +1 -1
- package/dist/src/capabilities/config/unset.verb.js +2 -0
- package/dist/src/capabilities/config/unset.verb.js.map +1 -1
- package/dist/src/capabilities/create/constants.js +8 -5
- package/dist/src/capabilities/create/constants.js.map +1 -1
- package/dist/src/capabilities/create/create.render.js.map +1 -1
- package/dist/src/capabilities/create/create.verb.js +36 -7
- package/dist/src/capabilities/create/create.verb.js.map +1 -1
- package/dist/src/capabilities/create/createSurface.generated.js +22 -0
- package/dist/src/capabilities/create/createSurface.generated.js.map +1 -1
- package/dist/src/capabilities/create/index.js +1 -1
- package/dist/src/capabilities/create/pickGenerator.js +1 -0
- package/dist/src/capabilities/create/pickGenerator.js.map +1 -1
- package/dist/src/capabilities/distribution.js +3 -1
- package/dist/src/capabilities/distribution.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/checkPackageRefs.js +10 -2
- package/dist/src/capabilities/doctor/checks/checkPackageRefs.js.map +1 -1
- package/dist/src/capabilities/doctor/checks/targetHealth.js.map +1 -1
- package/dist/src/capabilities/doctor/doctor.verb.js +2 -0
- package/dist/src/capabilities/doctor/doctor.verb.js.map +1 -1
- package/dist/src/capabilities/graph/connect.verb.js +2 -0
- package/dist/src/capabilities/graph/connect.verb.js.map +1 -1
- package/dist/src/capabilities/graph/inspect.render.js +7 -1
- package/dist/src/capabilities/graph/inspect.render.js.map +1 -1
- package/dist/src/capabilities/graph/inspect.verb.js +2 -0
- package/dist/src/capabilities/graph/inspect.verb.js.map +1 -1
- package/dist/src/capabilities/graph/query.render.js +37 -5
- package/dist/src/capabilities/graph/query.render.js.map +1 -1
- package/dist/src/capabilities/graph/query.verb.js +2 -0
- package/dist/src/capabilities/graph/query.verb.js.map +1 -1
- package/dist/src/capabilities/graph/queryText.js +28 -0
- package/dist/src/capabilities/graph/queryText.js.map +1 -1
- package/dist/src/capabilities/graph/runConnect.js +3 -3
- package/dist/src/capabilities/graph/runConnect.js.map +1 -1
- package/dist/src/capabilities/graph/runQuery.js +8 -6
- package/dist/src/capabilities/graph/runQuery.js.map +1 -1
- package/dist/src/capabilities/info/info.verb.js +2 -0
- package/dist/src/capabilities/info/info.verb.js.map +1 -1
- package/dist/src/capabilities/meta/mcp.verb.js +1 -0
- package/dist/src/capabilities/meta/mcp.verb.js.map +1 -1
- package/dist/src/capabilities/ontology/verbs.js +7 -10
- package/dist/src/capabilities/ontology/verbs.js.map +1 -1
- package/dist/src/capabilities/prompt/verbs.js +5 -4
- package/dist/src/capabilities/prompt/verbs.js.map +1 -1
- package/dist/src/capabilities/resources/provider.js +6 -3
- package/dist/src/capabilities/resources/provider.js.map +1 -1
- package/dist/src/capabilities/setup/operations/writability.js.map +1 -1
- package/dist/src/capabilities/setup/plan.render.js.map +1 -1
- package/dist/src/capabilities/setup/setup.verb.js +13 -5
- package/dist/src/capabilities/setup/setup.verb.js.map +1 -1
- package/dist/src/capabilities/shared/calls.js +16 -0
- package/dist/src/capabilities/shared/calls.js.map +1 -0
- package/dist/src/capabilities/shared/packageManager.js.map +1 -1
- package/dist/src/capabilities/skill/discover.js.map +1 -1
- package/dist/src/capabilities/skill/render.js +7 -5
- package/dist/src/capabilities/skill/render.js.map +1 -1
- package/dist/src/capabilities/skill/verbs.js +5 -4
- package/dist/src/capabilities/skill/verbs.js.map +1 -1
- package/dist/src/capabilities/sources/collectStatus.js +6 -1
- package/dist/src/capabilities/sources/collectStatus.js.map +1 -1
- package/dist/src/capabilities/sources/index.js +4 -3
- package/dist/src/capabilities/sources/index.js.map +1 -1
- package/dist/src/capabilities/sources/reset.render.js +37 -0
- package/dist/src/capabilities/sources/reset.render.js.map +1 -0
- package/dist/src/capabilities/sources/reset.verb.js +51 -0
- package/dist/src/capabilities/sources/reset.verb.js.map +1 -0
- package/dist/src/capabilities/sources/runReset.js +59 -0
- package/dist/src/capabilities/sources/runReset.js.map +1 -0
- package/dist/src/capabilities/sources/runUpdate.js +7 -6
- package/dist/src/capabilities/sources/runUpdate.js.map +1 -1
- package/dist/src/capabilities/sources/status.render.js +24 -8
- package/dist/src/capabilities/sources/status.render.js.map +1 -1
- package/dist/src/capabilities/sources/status.verb.js +1 -0
- package/dist/src/capabilities/sources/status.verb.js.map +1 -1
- package/dist/src/capabilities/sources/update.verb.js +2 -0
- package/dist/src/capabilities/sources/update.verb.js.map +1 -1
- package/dist/src/capabilities/upgrade/upgrade.verb.js +1 -0
- package/dist/src/capabilities/upgrade/upgrade.verb.js.map +1 -1
- package/dist/src/capabilities/version/version.verb.js +1 -0
- package/dist/src/capabilities/version/version.verb.js.map +1 -1
- package/dist/src/constants.js +4 -3
- package/dist/src/constants.js.map +1 -1
- package/dist/src/kernel/completion/complete.js.map +1 -1
- package/dist/src/kernel/completion/emitScripts.js.map +1 -1
- package/dist/src/kernel/completion/parse.js.map +1 -1
- package/dist/src/kernel/completion/rank.js.map +1 -1
- package/dist/src/kernel/completion/resolve.js.map +1 -1
- package/dist/src/kernel/config/readConfig.js.map +1 -1
- package/dist/src/kernel/error/PragmaError.js.map +1 -1
- package/dist/src/kernel/error/index.js +1 -1
- package/dist/src/kernel/error/index.js.map +1 -1
- package/dist/src/kernel/error/recovery.js +24 -42
- package/dist/src/kernel/error/recovery.js.map +1 -1
- package/dist/src/kernel/packs/collect.js +123 -9
- package/dist/src/kernel/packs/collect.js.map +1 -1
- package/dist/src/kernel/packs/compile.js +74 -15
- package/dist/src/kernel/packs/compile.js.map +1 -1
- package/dist/src/kernel/packs/graphql/fetchGraphqlLookup.js +3 -3
- package/dist/src/kernel/packs/graphql/fetchGraphqlLookup.js.map +1 -1
- package/dist/src/kernel/packs/iri.js +2 -4
- package/dist/src/kernel/packs/iri.js.map +1 -1
- package/dist/src/kernel/packs/renderPack.js +90 -50
- package/dist/src/kernel/packs/renderPack.js.map +1 -1
- package/dist/src/kernel/packs/resolveEntity.js +202 -90
- package/dist/src/kernel/packs/resolveEntity.js.map +1 -1
- package/dist/src/kernel/packs/runBodies.js +89 -30
- package/dist/src/kernel/packs/runBodies.js.map +1 -1
- package/dist/src/kernel/packs/schema.js +66 -12
- package/dist/src/kernel/packs/schema.js.map +1 -1
- package/dist/src/kernel/packs/sparql/buildListQuery.js +80 -13
- package/dist/src/kernel/packs/sparql/buildListQuery.js.map +1 -1
- package/dist/src/kernel/packs/sparql/buildLookupQuery.js +41 -13
- package/dist/src/kernel/packs/sparql/buildLookupQuery.js.map +1 -1
- package/dist/src/kernel/packs/sparql/filterValues.js +32 -23
- package/dist/src/kernel/packs/sparql/filterValues.js.map +1 -1
- package/dist/src/kernel/packs/sparql/runSelect.js +3 -5
- package/dist/src/kernel/packs/sparql/runSelect.js.map +1 -1
- package/dist/src/kernel/packs/storyRules.js +31 -4
- package/dist/src/kernel/packs/storyRules.js.map +1 -1
- package/dist/src/kernel/packs/tierScope.js +3 -3
- package/dist/src/kernel/packs/tierScope.js.map +1 -1
- package/dist/src/kernel/packs/types.js +4 -0
- package/dist/src/kernel/packs/types.js.map +1 -1
- package/dist/src/kernel/project/cli/buildProgram.js +4 -0
- package/dist/src/kernel/project/cli/buildProgram.js.map +1 -1
- package/dist/src/kernel/project/cli/dispatch.js +32 -8
- package/dist/src/kernel/project/cli/dispatch.js.map +1 -1
- package/dist/src/kernel/project/cli/globalFlags.js.map +1 -1
- package/dist/src/kernel/project/cli/suggestNames.js +44 -1
- package/dist/src/kernel/project/cli/suggestNames.js.map +1 -1
- package/dist/src/kernel/project/cli/verbHelp.js +17 -18
- package/dist/src/kernel/project/cli/verbHelp.js.map +1 -1
- package/dist/src/kernel/project/mcp/buildServer.js +11 -4
- package/dist/src/kernel/project/mcp/buildServer.js.map +1 -1
- package/dist/src/kernel/project/mcp/envelope.js +3 -2
- package/dist/src/kernel/project/mcp/envelope.js.map +1 -1
- package/dist/src/kernel/project/mcp/instructions.js +101 -31
- package/dist/src/kernel/project/mcp/instructions.js.map +1 -1
- package/dist/src/kernel/project/mcp/registerVerb.js +59 -23
- package/dist/src/kernel/project/mcp/registerVerb.js.map +1 -1
- package/dist/src/kernel/render/envelope.js.map +1 -1
- package/dist/src/kernel/render/renderers.js +3 -3
- package/dist/src/kernel/render/renderers.js.map +1 -1
- package/dist/src/kernel/render/turtle.js +21 -4
- package/dist/src/kernel/render/turtle.js.map +1 -1
- package/dist/src/kernel/runtime/boot.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/build.js +54 -1
- package/dist/src/kernel/runtime/graphpack/build.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/manifest.js +14 -0
- package/dist/src/kernel/runtime/graphpack/manifest.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/read.js +3 -5
- package/dist/src/kernel/runtime/graphpack/read.js.map +1 -1
- package/dist/src/kernel/runtime/graphpack/schemas.js +1 -0
- package/dist/src/kernel/runtime/graphpack/schemas.js.map +1 -1
- package/dist/src/kernel/runtime/loadSession.js +8 -1
- package/dist/src/kernel/runtime/loadSession.js.map +1 -1
- package/dist/src/kernel/runtime/packVersion.js +75 -0
- package/dist/src/kernel/runtime/packVersion.js.map +1 -0
- package/dist/src/kernel/runtime/readEntity.js +43 -4
- package/dist/src/kernel/runtime/readEntity.js.map +1 -1
- package/dist/src/kernel/runtime/refs/resolve.js.map +1 -1
- package/dist/src/kernel/runtime/resolveSources.js +61 -9
- package/dist/src/kernel/runtime/resolveSources.js.map +1 -1
- package/dist/src/kernel/runtime/storeReadiness.js +3 -2
- package/dist/src/kernel/runtime/storeReadiness.js.map +1 -1
- package/dist/src/kernel/spec/call.js +167 -0
- package/dist/src/kernel/spec/call.js.map +1 -0
- package/dist/src/kernel/spec/emitReference.js +9 -13
- package/dist/src/kernel/spec/emitReference.js.map +1 -1
- package/dist/src/kernel/spec/emitSurface.js +8 -1
- package/dist/src/kernel/spec/emitSurface.js.map +1 -1
- package/dist/src/kernel/spec/guidance.js +63 -0
- package/dist/src/kernel/spec/guidance.js.map +1 -0
- package/dist/src/kernel/spec/wireType.js +36 -0
- package/dist/src/kernel/spec/wireType.js.map +1 -0
- package/package.json +16 -16
- package/pragma.conf.ts +294 -177
- package/src/capabilities/block.parity.test.ts +1 -1
- package/src/capabilities/callRule.test.ts +147 -0
- package/src/capabilities/capabilities/capabilities.test.ts +47 -19
- package/src/capabilities/capabilities/capabilities.verb.ts +2 -0
- package/src/capabilities/capabilities/catalog.ts +60 -55
- package/src/capabilities/capabilities/index.ts +2 -0
- package/src/capabilities/capabilities/types.ts +16 -19
- package/src/capabilities/colophon/colophon.render.ts +9 -5
- package/src/capabilities/colophon/colophon.verb.ts +1 -0
- package/src/capabilities/config/get.verb.ts +2 -0
- package/src/capabilities/config/runField.ts +3 -3
- package/src/capabilities/config/set.verb.ts +3 -0
- package/src/capabilities/config/show.verb.ts +2 -0
- package/src/capabilities/config/unset.verb.ts +2 -0
- package/src/capabilities/create/constants.ts +8 -5
- package/src/capabilities/create/create.mcp.test.ts +173 -1
- package/src/capabilities/create/create.test.ts +4 -2
- package/src/capabilities/create/create.verb.ts +45 -3
- package/src/capabilities/create/createGrammar.test.ts +41 -5
- package/src/capabilities/create/createSurface.generated.ts +22 -0
- package/src/capabilities/create/crossCli.subprocess.test.ts +53 -14
- package/src/capabilities/create/index.ts +1 -1
- package/src/capabilities/create/pickGenerator.ts +1 -0
- package/src/capabilities/create/shippedCreate.subprocess.test.ts +28 -7
- package/src/capabilities/distribution.test.ts +6 -3
- package/src/capabilities/distribution.ts +6 -0
- package/src/capabilities/doctor/checks/checkPackageRefs.ts +14 -2
- package/src/capabilities/doctor/doctor.test.ts +38 -1
- package/src/capabilities/doctor/doctor.verb.ts +2 -0
- package/src/capabilities/emptyRecovery.test.ts +5 -0
- package/src/capabilities/graph/connect.verb.ts +2 -0
- package/src/capabilities/graph/inspect.render.ts +9 -1
- package/src/capabilities/graph/inspect.test.ts +73 -0
- package/src/capabilities/graph/inspect.verb.ts +2 -0
- package/src/capabilities/graph/query.render.test.ts +35 -0
- package/src/capabilities/graph/query.render.ts +45 -7
- package/src/capabilities/graph/query.shipped.exec.test.ts +44 -0
- package/src/capabilities/graph/query.verb.ts +2 -0
- package/src/capabilities/graph/queryText.test.ts +55 -1
- package/src/capabilities/graph/queryText.ts +47 -0
- package/src/capabilities/graph/runConnect.ts +4 -5
- package/src/capabilities/graph/runQuery.ts +23 -9
- package/src/capabilities/info/info.verb.ts +2 -0
- package/src/capabilities/links.shipped.exec.test.ts +398 -0
- package/src/capabilities/listBudget.shipped.exec.test.ts +2 -2
- package/src/capabilities/listLookup.shipped.exec.test.ts +122 -13
- package/src/capabilities/listQuery.shipped.exec.test.ts +39 -16
- package/src/capabilities/lookupBudget.shipped.exec.test.ts +208 -0
- package/src/capabilities/meta/mcp.verb.ts +2 -0
- package/src/capabilities/ontology/ontology.test.ts +24 -0
- package/src/capabilities/ontology/verbs.ts +16 -12
- package/src/capabilities/prompt/verbs.ts +10 -4
- package/src/capabilities/resources/provider.ts +7 -3
- package/src/capabilities/resources/resources.test.ts +2 -1
- package/src/capabilities/setup/setup.verb.ts +16 -0
- package/src/capabilities/shared/calls.ts +20 -0
- package/src/capabilities/skill/render.ts +9 -6
- package/src/capabilities/skill/verbs.ts +8 -4
- package/src/capabilities/sources/collectStatus.ts +6 -1
- package/src/capabilities/sources/index.ts +4 -3
- package/src/capabilities/sources/reset.render.test.ts +33 -0
- package/src/capabilities/sources/reset.render.ts +43 -0
- package/src/capabilities/sources/reset.verb.ts +59 -0
- package/src/capabilities/sources/runReset.ts +65 -0
- package/src/capabilities/sources/runUpdate.ts +12 -11
- package/src/capabilities/sources/sources.test.ts +158 -3
- package/src/capabilities/sources/status.render.test.ts +63 -1
- package/src/capabilities/sources/status.render.ts +25 -8
- package/src/capabilities/sources/status.verb.ts +2 -0
- package/src/capabilities/sources/types.ts +26 -0
- package/src/capabilities/sources/update.verb.ts +3 -0
- package/src/capabilities/surface.test.ts +29 -4
- package/src/capabilities/token.parity.test.ts +3 -2
- package/src/capabilities/tokenGraph.shipped.exec.test.ts +14 -2
- package/src/capabilities/upgrade/upgrade.verb.ts +1 -0
- package/src/capabilities/variable.parity.test.ts +2 -1
- package/src/capabilities/version/version.verb.ts +1 -0
- package/src/capabilities/wireContract.test.ts +110 -0
- package/src/constants.ts +4 -3
- package/src/kernel/completion/shellDrive.test.ts +2 -2
- package/src/kernel/copy.test.ts +1 -1
- package/src/kernel/error/PragmaError.test.ts +7 -3
- package/src/kernel/error/index.ts +1 -1
- package/src/kernel/error/recovery.test.ts +52 -18
- package/src/kernel/error/recovery.ts +25 -46
- package/src/kernel/error/types.ts +1 -1
- package/src/kernel/packs/collect.test.ts +79 -0
- package/src/kernel/packs/collect.ts +151 -11
- package/src/kernel/packs/compile.test.ts +107 -10
- package/src/kernel/packs/compile.ts +100 -11
- package/src/kernel/packs/filteredEmpty.test.ts +22 -5
- package/src/kernel/packs/graphql/fetchGraphqlLookup.ts +5 -6
- package/src/kernel/packs/graphqlSource.test.ts +42 -0
- package/src/kernel/packs/iri.ts +5 -4
- package/src/kernel/packs/listNotice.test.ts +1 -1
- package/src/kernel/packs/nounLink.test.ts +385 -0
- package/src/kernel/packs/renderPack.ts +137 -57
- package/src/kernel/packs/resolveEntity.test.ts +170 -1
- package/src/kernel/packs/resolveEntity.ts +281 -101
- package/src/kernel/packs/runBodies.ts +133 -31
- package/src/kernel/packs/schema.ts +77 -12
- package/src/kernel/packs/sparql/buildListQuery.test.ts +78 -1
- package/src/kernel/packs/sparql/buildListQuery.ts +106 -16
- package/src/kernel/packs/sparql/buildLookupQuery.ts +44 -13
- package/src/kernel/packs/sparql/filterValues.test.ts +36 -4
- package/src/kernel/packs/sparql/filterValues.ts +50 -31
- package/src/kernel/packs/sparql/runSelect.ts +4 -6
- package/src/kernel/packs/storyRules.ts +37 -4
- package/src/kernel/packs/tierScope.test.ts +120 -6
- package/src/kernel/packs/tierScope.ts +5 -7
- package/src/kernel/packs/toolDescription.test.ts +59 -74
- package/src/kernel/packs/types.ts +93 -11
- package/src/kernel/project/cli/buildProgram.ts +4 -0
- package/src/kernel/project/cli/dispatch.ts +34 -8
- package/src/kernel/project/cli/suggest.test.ts +77 -0
- package/src/kernel/project/cli/suggestNames.ts +47 -1
- package/src/kernel/project/cli/verbHelp.ts +16 -19
- package/src/kernel/project/mcp/buildServer.ts +15 -4
- package/src/kernel/project/mcp/envelope.ts +3 -2
- package/src/kernel/project/mcp/instructions.ts +123 -35
- package/src/kernel/project/mcp/prompts/prompts.test.ts +136 -20
- package/src/kernel/project/mcp/registerVerb.test.ts +28 -0
- package/src/kernel/project/mcp/registerVerb.ts +67 -29
- package/src/kernel/render/__snapshots__/renderers.test.ts.snap +1 -1
- package/src/kernel/render/renderers.test.ts +2 -2
- package/src/kernel/render/renderers.ts +3 -3
- package/src/kernel/render/turtle.ts +24 -4
- package/src/kernel/runtime/graphpack/build.ts +58 -1
- package/src/kernel/runtime/graphpack/graphpack.test.ts +20 -0
- package/src/kernel/runtime/graphpack/manifest.ts +15 -0
- package/src/kernel/runtime/graphpack/read.ts +4 -6
- package/src/kernel/runtime/graphpack/schemas.ts +1 -0
- package/src/kernel/runtime/graphpack/types.ts +13 -0
- package/src/kernel/runtime/loadSession.ts +8 -1
- package/src/kernel/runtime/packVersion.test.ts +61 -0
- package/src/kernel/runtime/packVersion.ts +84 -0
- package/src/kernel/runtime/readEntity.ts +61 -6
- package/src/kernel/runtime/resolveSources.test.ts +90 -7
- package/src/kernel/runtime/resolveSources.ts +91 -10
- package/src/kernel/runtime/storeReadiness.ts +4 -4
- package/src/kernel/runtime/types.ts +12 -0
- package/src/kernel/spec/call.test.ts +95 -0
- package/src/kernel/spec/call.ts +186 -0
- package/src/kernel/spec/emitReference.ts +9 -13
- package/src/kernel/spec/emitSurface.ts +9 -1
- package/src/kernel/spec/guidance.test.ts +49 -0
- package/src/kernel/spec/guidance.ts +68 -0
- package/src/kernel/spec/index.ts +4 -0
- package/src/kernel/spec/surfaceConformance.test.ts +2 -2
- package/src/kernel/spec/types.ts +64 -7
- package/src/kernel/spec/wireType.ts +53 -0
- package/src/testing/behavioral/README.md +1 -1
- package/src/testing/behavioral/errorMatrix.mcp.test.ts +2 -1
- package/src/testing/behavioral/journeys.firstInstall.test.ts +72 -2
- package/src/testing/behavioral/parity.test.ts +40 -0
- package/src/testing/eval/__snapshots__/eval.test.ts.snap +1 -1
- package/src/testing/eval/cases/assembly.ts +4 -3
- package/src/testing/eval/cases/stable.ts +2 -3
- package/src/testing/helpers/callSchema.ts +40 -0
- package/src/testing/helpers/parity.ts +35 -2
- package/src/testing/setupCallChecking.ts +30 -0
- package/dist/src/capabilities/capabilities/hints.js +0 -223
- package/dist/src/capabilities/capabilities/hints.js.map +0 -1
- package/src/capabilities/capabilities/hints.ts +0 -266
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire contract of list-valued parameters, derived from the registry.
|
|
3
|
+
*
|
|
4
|
+
* Two recorded failures are the reason this file exists. A weak model asked
|
|
5
|
+
* for twenty tokens' variables with twenty `variable_list` calls, because over
|
|
6
|
+
* MCP a filter took ONE value while the CLI took the flag repeated; a stronger
|
|
7
|
+
* one passed `name: "color.text"` to `token_lookup` and was refused by schema
|
|
8
|
+
* validation over a pair of brackets. So: every parameter that takes several
|
|
9
|
+
* values ADVERTISES an array, and accepts one bare value as a list of one.
|
|
10
|
+
*
|
|
11
|
+
* Derived rather than listed — a story declared tomorrow is held to the rule
|
|
12
|
+
* by the act of declaring it.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
16
|
+
import { z } from "zod";
|
|
17
|
+
import { buildToolShape } from "../kernel/project/mcp/registerVerb.js";
|
|
18
|
+
import { toolName } from "../kernel/spec/index.js";
|
|
19
|
+
import type { ParamSpec, VerbSpec } from "../kernel/spec/types.js";
|
|
20
|
+
import { type McpHarness, projectMcp } from "../testing/helpers/projectMcp.js";
|
|
21
|
+
import { capabilities } from "./index.js";
|
|
22
|
+
|
|
23
|
+
const exposed: readonly VerbSpec[] = capabilities
|
|
24
|
+
.flatMap((module) => module.verbs)
|
|
25
|
+
.filter((verb) => !verb.hidden && verb.capability.mcp.expose !== false);
|
|
26
|
+
|
|
27
|
+
/** Every `[tool, param]` pair whose param satisfies `test`. */
|
|
28
|
+
function paramsWhere(
|
|
29
|
+
test: (param: ParamSpec) => boolean,
|
|
30
|
+
): (readonly [string, string, VerbSpec, ParamSpec])[] {
|
|
31
|
+
return exposed.flatMap((verb) =>
|
|
32
|
+
verb.params
|
|
33
|
+
.filter(test)
|
|
34
|
+
.map((param) => [toolName(verb.path), param.name, verb, param] as const),
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** One admissible value for a param: its first enum value, else any word. */
|
|
39
|
+
const sample = (param: ParamSpec): string =>
|
|
40
|
+
param.kind === "enum" ? (param.values.at(0) ?? "") : "anything";
|
|
41
|
+
|
|
42
|
+
/** Parse ONE field of a tool's input shape, leaving its other params aside. */
|
|
43
|
+
function parseField(verb: VerbSpec, param: ParamSpec, value: unknown) {
|
|
44
|
+
const field = buildToolShape(verb)[param.name];
|
|
45
|
+
if (!field) throw new Error(`no "${param.name}" in the tool shape`);
|
|
46
|
+
return z.object({ [param.name]: field }).safeParse({ [param.name]: value });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const variadic = paramsWhere((param) => param.kind === "string[]");
|
|
50
|
+
const repeatable = paramsWhere(
|
|
51
|
+
(param) => param.kind !== "string[]" && param.repeatable === true,
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
describe("a parameter that takes several values takes one, too", () => {
|
|
55
|
+
it("the registry has both kinds (the derivation is not vacuous)", () => {
|
|
56
|
+
expect(variadic.length).toBeGreaterThan(0);
|
|
57
|
+
expect(repeatable.length).toBeGreaterThan(0);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it.each(variadic)(
|
|
61
|
+
"%s { %s }: a bare string is a list of one",
|
|
62
|
+
(_tool, name, verb, param) => {
|
|
63
|
+
expect(parseField(verb, param, "color.text")).toEqual({
|
|
64
|
+
success: true,
|
|
65
|
+
data: { [name]: ["color.text"] },
|
|
66
|
+
});
|
|
67
|
+
expect(parseField(verb, param, ["a", "b"]).success).toBe(true);
|
|
68
|
+
},
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
it.each(repeatable)(
|
|
72
|
+
"%s { %s }: an array and a bare string are both accepted",
|
|
73
|
+
(_tool, name, verb, param) => {
|
|
74
|
+
const value = sample(param);
|
|
75
|
+
expect(parseField(verb, param, [value, value]).success).toBe(true);
|
|
76
|
+
expect(parseField(verb, param, value)).toEqual({
|
|
77
|
+
success: true,
|
|
78
|
+
data: { [name]: [value] },
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe("what is advertised is a plain array", () => {
|
|
85
|
+
let harness: McpHarness;
|
|
86
|
+
let schemas: Map<string, Record<string, Record<string, unknown>>>;
|
|
87
|
+
beforeAll(async () => {
|
|
88
|
+
harness = await projectMcp(capabilities);
|
|
89
|
+
schemas = new Map(
|
|
90
|
+
(await harness.listTools()).map((tool) => [
|
|
91
|
+
tool.name,
|
|
92
|
+
((tool.inputSchema as { properties?: unknown }).properties ??
|
|
93
|
+
{}) as Record<string, Record<string, unknown>>,
|
|
94
|
+
]),
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
afterAll(() => harness.cleanup());
|
|
98
|
+
|
|
99
|
+
// `anyOf` is what a `string | string[]` union would emit, and it is the
|
|
100
|
+
// shape the weaker models read badly — so the coercion must not leak into
|
|
101
|
+
// the advertised schema.
|
|
102
|
+
it.each([...variadic, ...repeatable])(
|
|
103
|
+
"%s { %s } is `type: array`, never `anyOf`",
|
|
104
|
+
(tool, name) => {
|
|
105
|
+
const advertised = schemas.get(tool)?.[name];
|
|
106
|
+
expect(advertised?.type).toBe("array");
|
|
107
|
+
expect(advertised).not.toHaveProperty("anyOf");
|
|
108
|
+
},
|
|
109
|
+
);
|
|
110
|
+
});
|
package/src/constants.ts
CHANGED
|
@@ -61,9 +61,10 @@ const PROJECT_CONFIG_FILENAME = `${identity.name}.config.ts`;
|
|
|
61
61
|
/**
|
|
62
62
|
* The distribution's name plus a space: the prefix a `recovery.cli` hint carries
|
|
63
63
|
* so it quotes a command the installed binary answers to (D5). Kernel hints are
|
|
64
|
-
* authored through `
|
|
65
|
-
*
|
|
66
|
-
*
|
|
64
|
+
* authored through `callRecovery`, whose call renderer prepends it; a pack's
|
|
65
|
+
* `emptyRecovery.call` names a verb path and never a binary (`packs/schema.ts`
|
|
66
|
+
* rejects a command line there), because the CONSUMING distribution's renderer
|
|
67
|
+
* supplies its own. Use {@link BIN_NAME} for prose —
|
|
67
68
|
* this constant's trailing space belongs to the recovery invariant, not to
|
|
68
69
|
* sentences.
|
|
69
70
|
*/
|
|
@@ -339,7 +339,7 @@ const STRUCTURE = [
|
|
|
339
339
|
at: "pragma create <TAB>",
|
|
340
340
|
words: ["pragma", "create", ""],
|
|
341
341
|
cword: 2,
|
|
342
|
-
offers: ["application", "component", "package"],
|
|
342
|
+
offers: ["application", "component", "package", "page"],
|
|
343
343
|
},
|
|
344
344
|
{
|
|
345
345
|
at: "pragma --format <TAB>",
|
|
@@ -546,7 +546,7 @@ describe.skipIf(!hasShell("fish"))(
|
|
|
546
546
|
},
|
|
547
547
|
{
|
|
548
548
|
line: "pragma create ",
|
|
549
|
-
offers: ["application", "component", "package"],
|
|
549
|
+
offers: ["application", "component", "package", "page"],
|
|
550
550
|
},
|
|
551
551
|
// fish's own inline convention: it returns the whole `--flag=value` word,
|
|
552
552
|
// not the bare value bash offers. Assert what fish returns.
|
package/src/kernel/copy.test.ts
CHANGED
|
@@ -438,7 +438,7 @@ describe("capability commands (PROTECTED)", () => {
|
|
|
438
438
|
it("no command quoted in capability prose is a bare literal", () => {
|
|
439
439
|
// The other half of the same promise, and the half the position rule cannot
|
|
440
440
|
// reach: an empty-state hint, a recovery MESSAGE (the second argument to
|
|
441
|
-
// `
|
|
441
|
+
// `callRecovery`, beside a first argument the position rule already covers),
|
|
442
442
|
// a `sources status` headline, a wizard step's title. They reach the same
|
|
443
443
|
// user with the same instruction, and seven of them named this distribution
|
|
444
444
|
// while the rule above reported zero exemptions.
|
|
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
|
|
|
2
2
|
import { ISSUES_URL } from "../../constants.js";
|
|
3
3
|
import { errorEnvelope, successEnvelope } from "../render/envelope.js";
|
|
4
4
|
import { PragmaError } from "./PragmaError.js";
|
|
5
|
-
import {
|
|
5
|
+
import { callRecovery } from "./recovery.js";
|
|
6
6
|
import { serializeError } from "./serialize.js";
|
|
7
7
|
|
|
8
8
|
describe("PragmaError factories", () => {
|
|
@@ -76,13 +76,17 @@ describe("serializeError", () => {
|
|
|
76
76
|
it("includes suggestions, recovery, validOptions, and filters when present", () => {
|
|
77
77
|
const error = PragmaError.notFound("block", "Buton", {
|
|
78
78
|
suggestions: ["Button"],
|
|
79
|
-
recovery:
|
|
79
|
+
recovery: callRecovery({ verb: "block list" }, "List blocks."),
|
|
80
80
|
});
|
|
81
81
|
expect(serializeError(error)).toEqual({
|
|
82
82
|
code: "ENTITY_NOT_FOUND",
|
|
83
83
|
message: 'block "Buton" not found.',
|
|
84
84
|
suggestions: ["Button"],
|
|
85
|
-
recovery: {
|
|
85
|
+
recovery: {
|
|
86
|
+
cli: "pragma block list",
|
|
87
|
+
message: "List blocks.",
|
|
88
|
+
mcp: { tool: "block_list", params: {} },
|
|
89
|
+
},
|
|
86
90
|
});
|
|
87
91
|
});
|
|
88
92
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
import { RECOVERY_CLI_PREFIX } from "../../constants.js";
|
|
3
|
-
import {
|
|
3
|
+
import { callRecovery } from "./recovery.js";
|
|
4
4
|
|
|
5
5
|
describe("recovery.cli invariant (D5)", () => {
|
|
6
6
|
it("carries the shipped distribution's recovery prefix", () => {
|
|
@@ -11,27 +11,61 @@ describe("recovery.cli invariant (D5)", () => {
|
|
|
11
11
|
expect(RECOVERY_CLI_PREFIX).toBe("pragma ");
|
|
12
12
|
});
|
|
13
13
|
|
|
14
|
-
it("
|
|
15
|
-
// The caller
|
|
16
|
-
//
|
|
17
|
-
//
|
|
18
|
-
// the raw `cli:` literals that never
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
14
|
+
it("derives both spellings from the one call it is given", () => {
|
|
15
|
+
// The caller names a CALL, so a hint naming the wrong binary — or a CLI
|
|
16
|
+
// string and an MCP hint that disagree about an argument — is unwritable
|
|
17
|
+
// rather than merely asserted against. `kernel/copy.test.ts`'s position
|
|
18
|
+
// rule still sees the raw `cli:` literals that never reach this function.
|
|
19
|
+
expect(
|
|
20
|
+
callRecovery(
|
|
21
|
+
{ verb: "config unset", params: { key: "tier" } },
|
|
22
|
+
"Clear the field.",
|
|
23
|
+
),
|
|
24
|
+
).toEqual({
|
|
25
|
+
cli: "pragma config unset tier",
|
|
26
|
+
message: "Clear the field.",
|
|
27
|
+
// A mutating tool is plan-first: the recovery never carries `confirm`.
|
|
28
|
+
mcp: { tool: "config_unset", params: { key: "tier" } },
|
|
23
29
|
});
|
|
24
30
|
});
|
|
25
31
|
|
|
26
|
-
it("
|
|
32
|
+
it("spells a flag, quotes what a shell would split, and repeats a variadic positional", () => {
|
|
27
33
|
expect(
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
callRecovery(
|
|
35
|
+
{ verb: "token consumers", params: { symbol: "color.text" } },
|
|
36
|
+
"m",
|
|
37
|
+
).cli,
|
|
38
|
+
).toBe("pragma token consumers --symbol color.text");
|
|
39
|
+
expect(
|
|
40
|
+
callRecovery(
|
|
41
|
+
{ verb: "graph query", params: { sparql: "ASK { ?s ?p 'x' }" } },
|
|
42
|
+
"m",
|
|
43
|
+
).cli,
|
|
44
|
+
).toBe("pragma graph query 'ASK { ?s ?p '\\''x'\\'' }'");
|
|
45
|
+
expect(
|
|
46
|
+
callRecovery(
|
|
47
|
+
{ verb: "block lookup", params: { name: ["Button", "Card"] } },
|
|
48
|
+
"m",
|
|
49
|
+
).cli,
|
|
50
|
+
).toBe("pragma block lookup Button Card");
|
|
51
|
+
expect(
|
|
52
|
+
callRecovery(
|
|
53
|
+
{ verb: "sources update", params: { skipInvalid: true } },
|
|
54
|
+
"m",
|
|
55
|
+
).cli,
|
|
56
|
+
).toBe("pragma sources update --skip-invalid");
|
|
57
|
+
expect(
|
|
58
|
+
callRecovery(
|
|
59
|
+
{ verb: "sources update", params: { skipInvalid: false } },
|
|
60
|
+
"m",
|
|
61
|
+
).cli,
|
|
62
|
+
).toBe("pragma sources update");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("names no MCP tool for a verb withheld from MCP", () => {
|
|
66
|
+
expect(callRecovery({ verb: "version" }, "See the version.")).toEqual({
|
|
67
|
+
cli: "pragma version",
|
|
68
|
+
message: "See the version.",
|
|
35
69
|
});
|
|
36
70
|
});
|
|
37
71
|
});
|
|
@@ -1,58 +1,37 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The recovery
|
|
2
|
+
* The recovery invariant (D5): a `recovery.cli` hint quotes a command the
|
|
3
|
+
* installed binary answers to, so it begins with {@link RECOVERY_CLI_PREFIX}.
|
|
3
4
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* A THIRD authoring route is also legal and reached by NEITHER guard: a `cli`
|
|
14
|
-
* DERIVED from the program's own name at the call site. One site does this —
|
|
15
|
-
* the create mount (`capabilities/create/mount.ts`,
|
|
16
|
-
* `[...detail.chain, suggestion].join(" ")`), whose `chain[0]` is the root
|
|
17
|
-
* Commander program's name, `BIN_NAME` by wiring. It bypasses
|
|
18
|
-
* {@link cliRecovery}, and the position rule is structurally blind to it (it
|
|
19
|
-
* flags QUOTED literals containing the distribution's name, never a computed
|
|
20
|
-
* expression) — so D5 holds there by derivation, and the derivation is pinned
|
|
21
|
-
* where the value surfaces: `createGrammar.test.ts` COMPOSES its expected
|
|
22
|
-
* `cli` from {@link RECOVERY_CLI_PREFIX}, so a renamed root program reddens
|
|
23
|
-
* the cell naming the constant. (A separate `startsWith` assertion cannot
|
|
24
|
-
* pin it — behind an exact pin of the same value it has no reachable
|
|
25
|
-
* failing input.)
|
|
26
|
-
*
|
|
27
|
-
* `kernel/packs/schema.ts` holds a user-authored pack's `emptyRecovery.cli` to
|
|
28
|
-
* the same shape from the other side — it must NOT carry a prefix, because the
|
|
29
|
-
* consuming distribution's renderer supplies one.
|
|
5
|
+
* {@link callRecovery} takes a CALL and the one call renderer spells it, prefix
|
|
6
|
+
* included, so a hint naming the wrong binary — or a `cli` and an `mcp` that
|
|
7
|
+
* disagree — is unwritable. Two routes do not pass through here:
|
|
8
|
+
* raw `cli:` object literals (`kernel/copy.test.ts` polices those at the
|
|
9
|
+
* position), and the create mount, which DERIVES its `cli` from the root
|
|
10
|
+
* program's name (`capabilities/create/mount.ts`; pinned by
|
|
11
|
+
* `createGrammar.test.ts`, whose expectation is composed from the prefix).
|
|
12
|
+
* A pack's `emptyRecovery.call` is held to the same shape from the other side
|
|
13
|
+
* by `kernel/packs/schema.ts`: a verb path, never a binary name.
|
|
30
14
|
*/
|
|
31
15
|
|
|
32
|
-
import {
|
|
16
|
+
import { callTool, renderCall } from "../spec/call.js";
|
|
17
|
+
import type { Call } from "../spec/types.js";
|
|
33
18
|
import type { Recovery } from "./types.js";
|
|
34
19
|
|
|
35
20
|
/**
|
|
36
|
-
* Build a {@link Recovery}
|
|
37
|
-
* prefix, optionally pairing it with an MCP tool an agent can call.
|
|
21
|
+
* Build a {@link Recovery} from the call that recovers.
|
|
38
22
|
*
|
|
39
|
-
* A recovery
|
|
40
|
-
*
|
|
41
|
-
*
|
|
23
|
+
* A recovery speaks to BOTH surfaces: `cli` guides a person, while `mcp` names
|
|
24
|
+
* the tool an agent invokes (an agent cannot run a shell command). Both derive
|
|
25
|
+
* from the one call, so they cannot disagree about the verb or its arguments;
|
|
26
|
+
* `mcp` is absent only when the verb is withheld from MCP. Neither spelling
|
|
27
|
+
* ever carries `confirm`: a mutating tool is plan-first, and the plan it
|
|
28
|
+
* returns says how to proceed.
|
|
42
29
|
*
|
|
43
|
-
* @param
|
|
30
|
+
* @param call - The verb to run and the params to run it with.
|
|
44
31
|
* @param message - Human-readable guidance shown alongside the command.
|
|
45
|
-
* @
|
|
46
|
-
* @returns A recovery hint whose `cli` names this distribution's binary.
|
|
32
|
+
* @returns A recovery hint carrying the call in both spellings.
|
|
47
33
|
*/
|
|
48
|
-
export function
|
|
49
|
-
|
|
50
|
-
message:
|
|
51
|
-
mcp?: Recovery["mcp"],
|
|
52
|
-
): Recovery {
|
|
53
|
-
return {
|
|
54
|
-
message,
|
|
55
|
-
cli: `${RECOVERY_CLI_PREFIX}${command}`,
|
|
56
|
-
...(mcp ? { mcp } : {}),
|
|
57
|
-
};
|
|
34
|
+
export function callRecovery(call: Call, message: string): Recovery {
|
|
35
|
+
const mcp = callTool(call);
|
|
36
|
+
return { message, cli: renderCall(call, "cli"), ...(mcp ? { mcp } : {}) };
|
|
58
37
|
}
|
|
@@ -16,7 +16,7 @@ type ErrorCode = (typeof ERROR_CODES)[number];
|
|
|
16
16
|
*
|
|
17
17
|
* `cli` — when present — is the command as a user would type it: this
|
|
18
18
|
* distribution's own bin name (`RECOVERY_CLI_PREFIX`) plus a grammar path (D5).
|
|
19
|
-
* `
|
|
19
|
+
* `callRecovery` takes the path alone and prepends the prefix, so there is no
|
|
20
20
|
* assertion to make; the one COMPUTED producer (the create mount) derives
|
|
21
21
|
* the prefix from the program's own name, pinned by a test expectation
|
|
22
22
|
* COMPOSED from `RECOVERY_CLI_PREFIX` — the routes are enumerated in the
|
|
@@ -19,6 +19,7 @@ import type { CapabilityModule, VerbSpec } from "../spec/types.js";
|
|
|
19
19
|
import {
|
|
20
20
|
assembleEffectiveModules,
|
|
21
21
|
loadEffectiveModules,
|
|
22
|
+
migrateLegacyRecoveries,
|
|
22
23
|
validateStories,
|
|
23
24
|
} from "./collect.js";
|
|
24
25
|
import { assertUniqueVerbs } from "./uniqueness.js";
|
|
@@ -210,6 +211,84 @@ describe("validateStories — package stories NEVER throw (PROTECTED)", () => {
|
|
|
210
211
|
]);
|
|
211
212
|
});
|
|
212
213
|
|
|
214
|
+
it("carries a package story's retired emptyRecovery.cli forward instead of losing the noun", () => {
|
|
215
|
+
// A pack built before the grammar changed still has `cli` on disk. The
|
|
216
|
+
// project config gets a hard error for it (its author can rename the key);
|
|
217
|
+
// a package is third-party data, so the hint is migrated when it IS a verb
|
|
218
|
+
// path and otherwise only the hint is dropped — never the noun.
|
|
219
|
+
const withCli = (noun: string, cli: string) => ({
|
|
220
|
+
noun,
|
|
221
|
+
list: {
|
|
222
|
+
...validPack(noun).list,
|
|
223
|
+
emptyRecovery: { message: "None yet.", cli },
|
|
224
|
+
},
|
|
225
|
+
verbs: [
|
|
226
|
+
{
|
|
227
|
+
...validPack(noun).list,
|
|
228
|
+
verb: "extras",
|
|
229
|
+
emptyRecovery: { message: "None yet.", cli },
|
|
230
|
+
},
|
|
231
|
+
],
|
|
232
|
+
});
|
|
233
|
+
const result = validateStories(
|
|
234
|
+
[
|
|
235
|
+
record(
|
|
236
|
+
"pkg/stories/recipe.json",
|
|
237
|
+
JSON.stringify(withCli("recipe", "sources update")),
|
|
238
|
+
),
|
|
239
|
+
record(
|
|
240
|
+
"pkg/stories/menu.json",
|
|
241
|
+
JSON.stringify(withCli("menu", "acme sources update --all")),
|
|
242
|
+
),
|
|
243
|
+
],
|
|
244
|
+
STATIC,
|
|
245
|
+
);
|
|
246
|
+
const [recipe, menu] = result.entries.map((entry) => entry.definition);
|
|
247
|
+
expect(recipe?.list?.emptyRecovery).toEqual({
|
|
248
|
+
message: "None yet.",
|
|
249
|
+
call: { verb: "sources update" },
|
|
250
|
+
});
|
|
251
|
+
expect(recipe?.verbs?.at(0)?.emptyRecovery?.call).toEqual({
|
|
252
|
+
verb: "sources update",
|
|
253
|
+
});
|
|
254
|
+
// Not a verb path: the story survives, the hint does not, and doctor hears.
|
|
255
|
+
expect(menu?.noun).toBe("menu");
|
|
256
|
+
expect(menu?.list?.emptyRecovery).toEqual({ message: "None yet." });
|
|
257
|
+
expect(result.problems.map((problem) => problem.source)).toEqual([
|
|
258
|
+
"pkg/stories/menu.json",
|
|
259
|
+
"pkg/stories/menu.json",
|
|
260
|
+
]);
|
|
261
|
+
expect(result.problems.at(0)?.message).toMatch(
|
|
262
|
+
/story is kept.*emptyRecovery\.cli.*emptyRecovery\.call/,
|
|
263
|
+
);
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it("leaves a story with nothing to migrate, and a non-object, untouched", () => {
|
|
267
|
+
const story = validPack("recipe");
|
|
268
|
+
expect(migrateLegacyRecoveries(story)).toEqual({ raw: story, dropped: [] });
|
|
269
|
+
expect(migrateLegacyRecoveries("nope")).toEqual({
|
|
270
|
+
raw: "nope",
|
|
271
|
+
dropped: [],
|
|
272
|
+
});
|
|
273
|
+
// A half that already names a call keeps it; the stale `cli` beside it goes.
|
|
274
|
+
const both = {
|
|
275
|
+
message: "m",
|
|
276
|
+
cli: "doctor",
|
|
277
|
+
call: { verb: "sources update" },
|
|
278
|
+
};
|
|
279
|
+
expect(
|
|
280
|
+
migrateLegacyRecoveries({ noun: "x", verbs: [{ emptyRecovery: both }] }),
|
|
281
|
+
).toEqual({
|
|
282
|
+
raw: {
|
|
283
|
+
noun: "x",
|
|
284
|
+
verbs: [
|
|
285
|
+
{ emptyRecovery: { message: "m", call: { verb: "sources update" } } },
|
|
286
|
+
],
|
|
287
|
+
},
|
|
288
|
+
dropped: [],
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
213
292
|
it("last declaration wins for a noun, and the shadowed file is reported", () => {
|
|
214
293
|
const result = validateStories(
|
|
215
294
|
[
|