@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
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
* them (disclosure gates the fetch), never HOW it is laid out.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { BIN_NAME, RECOVERY_CLI_PREFIX } from "../../constants.js";
|
|
13
12
|
import type {
|
|
14
13
|
ColumnDef,
|
|
15
14
|
LookupField,
|
|
@@ -25,18 +24,25 @@ import {
|
|
|
25
24
|
renderLookupLlm,
|
|
26
25
|
renderLookupPlain,
|
|
27
26
|
} from "../render/renderers.js";
|
|
28
|
-
import
|
|
29
|
-
|
|
27
|
+
import {
|
|
28
|
+
BUILD_STORE_CALL,
|
|
29
|
+
quoteArgument,
|
|
30
|
+
renderNextStep,
|
|
31
|
+
} from "../spec/call.js";
|
|
32
|
+
import type { Formatters, Surface } from "../spec/index.js";
|
|
30
33
|
import type { LookupOutput } from "./resolveEntity.js";
|
|
31
34
|
import {
|
|
32
35
|
EVERY_TIER,
|
|
33
36
|
type PackAppliedFilter,
|
|
34
37
|
type PackChildRow,
|
|
38
|
+
type PackEmptyRecovery,
|
|
35
39
|
type PackEntity,
|
|
36
40
|
type PackList,
|
|
37
41
|
type PackLookup,
|
|
38
42
|
type PackPage,
|
|
39
43
|
type PackRow,
|
|
44
|
+
TIER_PARAM,
|
|
45
|
+
UNTIERED_KEY,
|
|
40
46
|
} from "./types.js";
|
|
41
47
|
|
|
42
48
|
/** Sample output: the drawn exemplars, the population size, and agent follow-ups. */
|
|
@@ -59,7 +65,15 @@ export interface RenderMeta {
|
|
|
59
65
|
* list on a BUILT store (a cold store would have failed with STORE_UNAVAILABLE
|
|
60
66
|
* first) means "nothing matched", so point at both possible fixes.
|
|
61
67
|
*/
|
|
62
|
-
const
|
|
68
|
+
export const DEFAULT_EMPTY_RECOVERY: PackEmptyRecovery = {
|
|
69
|
+
message:
|
|
70
|
+
"Either nothing matched — try a wider filter — or the store has nothing in it yet and needs building.",
|
|
71
|
+
call: BUILD_STORE_CALL,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/** What a filtered empty page says first: the store is fine, the filter missed. */
|
|
75
|
+
const FILTERED_EMPTY_HINT =
|
|
76
|
+
"The store answered and nothing carries that — drop the argument, or loosen it, to widen the read.";
|
|
63
77
|
|
|
64
78
|
/**
|
|
65
79
|
* Build the list formatters for a list-shaped verb (list or an extra verb).
|
|
@@ -93,42 +107,67 @@ export function listFormatters(
|
|
|
93
107
|
// Zero results is a calm success, not an error (see runBodies.makeListRun):
|
|
94
108
|
// render a non-blank message, exit 0, JSON stays []. A pack's authored
|
|
95
109
|
// `emptyRecovery` becomes the hint; otherwise the generic build/broaden hint.
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
110
|
+
// Built per call, not once: the hint ends in the next call to make, spelled
|
|
111
|
+
// for the surface that is about to print it.
|
|
112
|
+
const { message, call } = shape.emptyRecovery ?? DEFAULT_EMPTY_RECOVERY;
|
|
113
|
+
const hintFor = (surface: Surface): string =>
|
|
114
|
+
call ? `${message} ${renderNextStep(call, surface)}` : message;
|
|
115
|
+
// A FILTERED empty page is a miss, not an empty store: it says how to widen,
|
|
116
|
+
// keeps the story's own account of the emptiness, and drops the rebuild call
|
|
117
|
+
// (any other next step a story declares — listing the values — still helps).
|
|
118
|
+
const declared = shape.emptyRecovery;
|
|
119
|
+
const filteredHintFor = (surface: Surface): string =>
|
|
120
|
+
[
|
|
121
|
+
FILTERED_EMPTY_HINT,
|
|
122
|
+
declared?.message,
|
|
123
|
+
declared?.call && declared.call.verb !== BUILD_STORE_CALL.verb
|
|
124
|
+
? renderNextStep(declared.call, surface)
|
|
125
|
+
: undefined,
|
|
126
|
+
]
|
|
127
|
+
.filter(Boolean)
|
|
128
|
+
.join(" ");
|
|
129
|
+
const optionsFor = (surface: Surface): RenderListOptions<PackRow> => ({
|
|
104
130
|
heading: meta.heading,
|
|
105
131
|
columns,
|
|
106
132
|
prefixes: meta.prefixes,
|
|
107
133
|
emptyMessage: `No ${meta.noun} entries found.`,
|
|
108
|
-
emptyHint,
|
|
109
|
-
};
|
|
134
|
+
emptyHint: hintFor(surface),
|
|
135
|
+
});
|
|
110
136
|
return {
|
|
111
|
-
plain: (page, context) =>
|
|
137
|
+
plain: (page, context) =>
|
|
138
|
+
renderListPlain(page.rows, optionsFor("cli"), context),
|
|
112
139
|
llm: (page) => {
|
|
113
|
-
const body = renderListLlm(
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
:
|
|
118
|
-
|
|
119
|
-
|
|
140
|
+
const body = renderListLlm(
|
|
141
|
+
page.rows,
|
|
142
|
+
emptyCopy(page, meta, optionsFor("cli"), "cli", filteredHintFor("cli")),
|
|
143
|
+
{
|
|
144
|
+
more: page.nextAfter !== undefined,
|
|
145
|
+
...(scopeText(page) === undefined
|
|
146
|
+
? {}
|
|
147
|
+
: { scope: scopeText(page) as string }),
|
|
148
|
+
},
|
|
149
|
+
);
|
|
150
|
+
const notice = listNotice(page, meta, "cli");
|
|
120
151
|
return notice ? `${body}\n\n${notice}` : body;
|
|
121
152
|
},
|
|
122
153
|
json: (page) => JSON.stringify(page.rows, null, 2),
|
|
123
154
|
// Zero rows: the dispatcher routes this to stderr (exit 0) so the plain
|
|
124
155
|
// stdout stream stays pure data; llm/json keep their own empty shapes.
|
|
125
|
-
notice: (page) =>
|
|
156
|
+
notice: (page, surface = "cli") =>
|
|
126
157
|
page.rows.length === 0
|
|
127
158
|
? joinNotices([
|
|
128
|
-
renderListEmptyNotice(
|
|
129
|
-
|
|
159
|
+
renderListEmptyNotice(
|
|
160
|
+
emptyCopy(
|
|
161
|
+
page,
|
|
162
|
+
meta,
|
|
163
|
+
optionsFor(surface),
|
|
164
|
+
surface,
|
|
165
|
+
filteredHintFor(surface),
|
|
166
|
+
),
|
|
167
|
+
),
|
|
168
|
+
scopeNotice(page, surface),
|
|
130
169
|
])
|
|
131
|
-
: listNotice(page, meta),
|
|
170
|
+
: listNotice(page, meta, surface),
|
|
132
171
|
// The scope rides the envelope as DATA as well as prose: an agent deciding
|
|
133
172
|
// whether to widen the read should not have to parse a sentence to learn
|
|
134
173
|
// which tiers it got.
|
|
@@ -136,9 +175,22 @@ export function listFormatters(
|
|
|
136
175
|
};
|
|
137
176
|
}
|
|
138
177
|
|
|
139
|
-
/**
|
|
178
|
+
/**
|
|
179
|
+
* The tier scope in the words `--tier` accepts, each tier with its share of
|
|
180
|
+
* the whole filtered answer; an EMPTY page also names the tiers outside the
|
|
181
|
+
* scope that hold a match. Nothing when unscoped.
|
|
182
|
+
*/
|
|
140
183
|
function scopeText(page: PackPage): string | undefined {
|
|
141
|
-
|
|
184
|
+
if (!page.scope) return undefined;
|
|
185
|
+
const { tiers, counts } = page.scope;
|
|
186
|
+
if (!counts) return tiers.join(", ");
|
|
187
|
+
const held = (tier: string): string => `${tier} ${counts[tier] ?? 0}`;
|
|
188
|
+
const inside = [...tiers, ...(UNTIERED_KEY in counts ? [UNTIERED_KEY] : [])];
|
|
189
|
+
const outside = Object.keys(counts).filter((tier) => !inside.includes(tier));
|
|
190
|
+
const text = inside.map(held).join(", ");
|
|
191
|
+
return page.rows.length > 0 || outside.length === 0
|
|
192
|
+
? text
|
|
193
|
+
: `${text}; other tiers: ${outside.map(held).join(", ")}`;
|
|
142
194
|
}
|
|
143
195
|
|
|
144
196
|
/**
|
|
@@ -150,18 +202,25 @@ function scopeText(page: PackPage): string | undefined {
|
|
|
150
202
|
* the scope — and the notice seam is where this package already puts what the
|
|
151
203
|
* data cannot say about itself.
|
|
152
204
|
*/
|
|
153
|
-
function scopeNotice(page: PackPage): string | undefined {
|
|
205
|
+
function scopeNotice(page: PackPage, surface: Surface): string | undefined {
|
|
154
206
|
const scope = scopeText(page);
|
|
155
207
|
if (scope === undefined) return undefined;
|
|
156
208
|
return (
|
|
157
209
|
`Tier scope: ${scope}. ` +
|
|
158
|
-
`Pass
|
|
210
|
+
`Pass ${quoteArgument(TIER_PARAM, "<name>", surface)} for one tier and its ancestors, or ${quoteArgument(TIER_PARAM, EVERY_TIER, surface)} for every tier.`
|
|
159
211
|
);
|
|
160
212
|
}
|
|
161
213
|
|
|
162
214
|
/** The page's notices, in the order a reader needs them: scope, then paging. */
|
|
163
|
-
function listNotice(
|
|
164
|
-
|
|
215
|
+
function listNotice(
|
|
216
|
+
page: PackPage,
|
|
217
|
+
meta: RenderMeta,
|
|
218
|
+
surface: Surface,
|
|
219
|
+
): string | undefined {
|
|
220
|
+
return joinNotices([
|
|
221
|
+
scopeNotice(page, surface),
|
|
222
|
+
pageNotice(page, meta, surface),
|
|
223
|
+
]);
|
|
165
224
|
}
|
|
166
225
|
|
|
167
226
|
/** Join what a page has to say into one notice, dropping what it has not. */
|
|
@@ -175,46 +234,40 @@ function joinNotices(
|
|
|
175
234
|
/**
|
|
176
235
|
* The empty-state copy this page deserves.
|
|
177
236
|
*
|
|
178
|
-
* Two facts can empty a list
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
182
|
-
* it on the next line, exactly as it does on an unfiltered page.
|
|
183
|
-
*
|
|
184
|
-
* It did not, briefly: a filtered empty page reported only the narrowing,
|
|
185
|
-
* because the recoveries of the day asserted an empty store ("No token symbols
|
|
186
|
-
* in the store … run `pragma sources update`") and so told a reader with 745
|
|
187
|
-
* symbols in it to rebuild for nothing. That is a WORDING defect, and it is
|
|
188
|
-
* fixed where it lives — a story's recovery is now written to hold whether the
|
|
189
|
-
* population is empty or a filter missed a populated one, or the story declares
|
|
190
|
-
* none. Suppressing it here cost more than it saved: `token consumers --symbol
|
|
191
|
-
* color.text` narrows a table that records no bindings at all, and "No token
|
|
192
|
-
* matches `--symbol color.text`." on its own read as a mistyped symbol while
|
|
193
|
-
* withholding the one account of the emptiness that verb has.
|
|
237
|
+
* Two facts can empty a list: nothing was there, or a filter missed what was.
|
|
238
|
+
* An unfiltered empty page gets the story's `emptyRecovery` whole. A filtered
|
|
239
|
+
* one names the arguments the caller typed and takes `filteredHint` instead —
|
|
240
|
+
* see {@link listFormatters} for what that keeps and drops.
|
|
194
241
|
*
|
|
195
242
|
* @param page - The rendered page (its rows and the filters that cut them).
|
|
196
243
|
* @param meta - The noun, for the sentence.
|
|
197
244
|
* @param base - The story's own empty copy.
|
|
198
|
-
* @
|
|
199
|
-
*
|
|
245
|
+
* @param filteredHint - The hint a filtered empty page carries.
|
|
246
|
+
* @returns `base` unchanged, or `base` with the filter-shaped message and hint.
|
|
200
247
|
*/
|
|
201
248
|
function emptyCopy(
|
|
202
249
|
page: PackPage,
|
|
203
250
|
meta: RenderMeta,
|
|
204
251
|
base: RenderListOptions<PackRow>,
|
|
252
|
+
surface: Surface,
|
|
253
|
+
filteredHint: string,
|
|
205
254
|
): RenderListOptions<PackRow> {
|
|
206
255
|
const applied = page.filters ?? [];
|
|
207
256
|
if (page.rows.length > 0 || applied.length === 0) return base;
|
|
208
257
|
return {
|
|
209
258
|
...base,
|
|
210
|
-
emptyMessage: `No ${meta.noun} matches ${listFilters(applied)}.`,
|
|
259
|
+
emptyMessage: `No ${meta.noun} matches ${listFilters(applied, surface)}.`,
|
|
260
|
+
emptyHint: filteredHint,
|
|
211
261
|
};
|
|
212
262
|
}
|
|
213
263
|
|
|
214
264
|
/** The filters in force, as flags a reader can edit: `\`--kind input\`` … */
|
|
215
|
-
function listFilters(
|
|
216
|
-
|
|
217
|
-
|
|
265
|
+
function listFilters(
|
|
266
|
+
applied: readonly PackAppliedFilter[],
|
|
267
|
+
surface: Surface,
|
|
268
|
+
): string {
|
|
269
|
+
const flags = applied.map((filter) =>
|
|
270
|
+
quoteArgument(filter.param, filter.value, surface),
|
|
218
271
|
);
|
|
219
272
|
const last = flags.at(-1) as string;
|
|
220
273
|
return flags.length === 1
|
|
@@ -231,12 +284,16 @@ function listFilters(applied: readonly PackAppliedFilter[]): string {
|
|
|
231
284
|
* that carry this are read by agents — so the sentence contains the flag, the
|
|
232
285
|
* value, and the tool parameter, ready to copy.
|
|
233
286
|
*/
|
|
234
|
-
function pageNotice(
|
|
287
|
+
function pageNotice(
|
|
288
|
+
page: PackPage,
|
|
289
|
+
meta: RenderMeta,
|
|
290
|
+
surface: Surface,
|
|
291
|
+
): string | undefined {
|
|
235
292
|
if (page.nextAfter === undefined) return undefined;
|
|
236
293
|
return (
|
|
237
294
|
`Showing ${page.rows.length} ${meta.noun} entries, and more exist. ` +
|
|
238
|
-
`For the next page pass
|
|
239
|
-
`
|
|
295
|
+
`For the next page pass ${quoteArgument("after", page.nextAfter, surface)}, ` +
|
|
296
|
+
`or raise ${surface === "mcp" ? "`limit`" : "`--limit`"} (currently ${page.limit}).`
|
|
240
297
|
);
|
|
241
298
|
}
|
|
242
299
|
|
|
@@ -292,9 +349,29 @@ export function lookupFormatters(
|
|
|
292
349
|
llm: (output) =>
|
|
293
350
|
renderOutput(output, (entity) => renderLookupLlm(entity, options), "llm"),
|
|
294
351
|
json: (output) => JSON.stringify(output, null, 2),
|
|
352
|
+
notice: (output, surface = "cli") => truncationNotice(output, surface),
|
|
295
353
|
};
|
|
296
354
|
}
|
|
297
355
|
|
|
356
|
+
/** What a capped pattern says for itself, on the notice seam and in the llm body. */
|
|
357
|
+
function truncationNotice(
|
|
358
|
+
output: LookupOutput,
|
|
359
|
+
surface: Surface,
|
|
360
|
+
): string | undefined {
|
|
361
|
+
if (!output.truncated) return undefined;
|
|
362
|
+
const advice =
|
|
363
|
+
output.detail === "summary"
|
|
364
|
+
? ""
|
|
365
|
+
: `, or pass ${quoteArgument("detail", "summary", surface)} for smaller entries`;
|
|
366
|
+
const elsewhere = output.elsewhere
|
|
367
|
+
? `, and ${output.elsewhere} more in other tiers: pass ${quoteArgument(TIER_PARAM, EVERY_TIER, surface)}`
|
|
368
|
+
: "";
|
|
369
|
+
return (
|
|
370
|
+
`${output.results.length} of ${output.total} matches shown${elsewhere}. ` +
|
|
371
|
+
`Narrow the pattern to reach the rest${advice}.`
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
298
375
|
/** Build the sample formatters (renders each exemplar, then the follow-ups). */
|
|
299
376
|
export function sampleFormatters(
|
|
300
377
|
lookup: PackLookup,
|
|
@@ -366,6 +443,9 @@ function renderOutput(
|
|
|
366
443
|
`${mode === "llm" ? "### Not found" : "Not found:"}\n${lines.join("\n")}`,
|
|
367
444
|
);
|
|
368
445
|
}
|
|
446
|
+
const truncation =
|
|
447
|
+
mode === "llm" ? truncationNotice(output, "cli") : undefined;
|
|
448
|
+
if (truncation) bodies.push(truncation);
|
|
369
449
|
return bodies.join("\n\n").trimEnd();
|
|
370
450
|
}
|
|
371
451
|
|
|
@@ -32,7 +32,7 @@ import { buildFixtureRuntime } from "../../testing/helpers/packRuntime.js";
|
|
|
32
32
|
import type { PragmaRuntime } from "../runtime/types.js";
|
|
33
33
|
import { compilePack } from "./compile.js";
|
|
34
34
|
import { lookupFormatters, lookupOptions } from "./renderPack.js";
|
|
35
|
-
import type
|
|
35
|
+
import { GLOB_EXPANSION_CAP, type LookupOutput } from "./resolveEntity.js";
|
|
36
36
|
import type { PackDefinition, PackLookup } from "./types.js";
|
|
37
37
|
import { distributionSource } from "./types.js";
|
|
38
38
|
import { verbKey } from "./uniqueness.js";
|
|
@@ -259,6 +259,70 @@ describe("pack lookup addressing (PROTECTED)", () => {
|
|
|
259
259
|
});
|
|
260
260
|
});
|
|
261
261
|
|
|
262
|
+
describe("a glob with no prefix reads names AND IRI local names", () => {
|
|
263
|
+
it("reaches an entity through its local name", async () => {
|
|
264
|
+
// The recorded case: `*.component.meter` is a pattern over what every
|
|
265
|
+
// list prints, and it matched nothing while names were the only thing a
|
|
266
|
+
// prefix-less glob was tried against.
|
|
267
|
+
const out = await lookupVia(SPQ, "*.timeline");
|
|
268
|
+
expect(out.errors).toEqual([]);
|
|
269
|
+
expect(uris(out)).toEqual([`${DS}padded.timeline`]);
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
it("reaches an entity that carries no name at all", async () => {
|
|
273
|
+
expect(uris(await lookupVia(SPQ, "nameless.*"))).toEqual([
|
|
274
|
+
`${DS}nameless.widget`,
|
|
275
|
+
]);
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it("answers ONCE for an entity both its name and its local name match", async () => {
|
|
279
|
+
// `*chip` fits the name "Chip" and the local names `alpha.chip` and
|
|
280
|
+
// `zeta.chip`. The name match already reaches both, so neither is looked
|
|
281
|
+
// up a second time by IRI.
|
|
282
|
+
const out = await lookupVia(SPQ, "*chip");
|
|
283
|
+
expect(uris(out).sort()).toEqual([`${DS}alpha.chip`, `${DS}zeta.chip`]);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it("does not make a bare local name an address", async () => {
|
|
287
|
+
await expect(lookupVia(SPQ, "alpha.chip")).rejects.toMatchObject({
|
|
288
|
+
code: "ENTITY_NOT_FOUND",
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
describe("a miss suggests the real thing", () => {
|
|
294
|
+
const suggestionsFor = async (query: string): Promise<string[]> => {
|
|
295
|
+
const reason = await lookupVia(SPQ, query).catch(
|
|
296
|
+
(error: unknown) => error,
|
|
297
|
+
);
|
|
298
|
+
expect(reason).toMatchObject({ code: "ENTITY_NOT_FOUND" });
|
|
299
|
+
return (reason as { suggestions: string[] }).suggestions;
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
it("answers a pasted local name with its prefixed IRI, then the name inside it", async () => {
|
|
303
|
+
expect((await suggestionsFor("alpha.chip")).slice(0, 2)).toEqual([
|
|
304
|
+
"ds:alpha.chip",
|
|
305
|
+
"Chip",
|
|
306
|
+
]);
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
it("answers a mistyped local name with the prefixed IRI it was near", async () => {
|
|
310
|
+
expect(await suggestionsFor("nameless.widgit")).toContain(
|
|
311
|
+
"ds:nameless.widget",
|
|
312
|
+
);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it("every suggestion it prints resolves", async () => {
|
|
316
|
+
const suggestions = await suggestionsFor("alpha.chip");
|
|
317
|
+
const out = await lookupVia(SPQ, ...suggestions);
|
|
318
|
+
expect(out.errors).toEqual([]);
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it("keeps the five-suggestion cap", async () => {
|
|
322
|
+
expect((await suggestionsFor("a")).length).toBeLessThanOrEqual(5);
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
|
|
262
326
|
describe("an ambiguous name answers with EVERY entity it reaches", () => {
|
|
263
327
|
// `ds:zeta.chip` is declared BEFORE `ds:alpha.chip` in the fixture, so the
|
|
264
328
|
// store enumerates it first while IRI order puts `alpha` first. Neither of
|
|
@@ -331,3 +395,108 @@ describe("pack lookup addressing (PROTECTED)", () => {
|
|
|
331
395
|
});
|
|
332
396
|
});
|
|
333
397
|
});
|
|
398
|
+
|
|
399
|
+
describe("a glob says what it did", () => {
|
|
400
|
+
/** More same-family entities than one lookup's patterns may expand to. */
|
|
401
|
+
const FAMILY = GLOB_EXPANSION_CAP + 12;
|
|
402
|
+
const pad = (index: number): string => String(index).padStart(3, "0");
|
|
403
|
+
const FAMILY_TTL = Array.from(
|
|
404
|
+
{ length: FAMILY },
|
|
405
|
+
(_, index) =>
|
|
406
|
+
`ds:swatch.${pad(index)} a ds:Component ; ds:name "swatch.${pad(index)}" .`,
|
|
407
|
+
).join("\n");
|
|
408
|
+
|
|
409
|
+
let rt: PragmaRuntime;
|
|
410
|
+
beforeAll(async () => {
|
|
411
|
+
({ rt } = await buildFixtureRuntime({
|
|
412
|
+
ttl: BLOCK_TTL + AMBIGUOUS_TTL + FAMILY_TTL,
|
|
413
|
+
prefixes: BLOCK_PREFIXES,
|
|
414
|
+
detail: "detailed",
|
|
415
|
+
}));
|
|
416
|
+
});
|
|
417
|
+
afterAll(async () => {
|
|
418
|
+
(await rt.store.get()).store.dispose();
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
const lookup = (...name: string[]): Promise<LookupOutput> => {
|
|
422
|
+
const verb = compilePack(SPQ, distributionSource("t"), BLOCK_PREFIXES).find(
|
|
423
|
+
(v) => verbKey(v.path) === "sblock lookup",
|
|
424
|
+
);
|
|
425
|
+
if (!verb) throw new Error("no lookup verb");
|
|
426
|
+
return verb.run({ name }, rt) as Promise<LookupOutput>;
|
|
427
|
+
};
|
|
428
|
+
const formatters = lookupFormatters(SPQ.lookup as PackLookup, BLOCK_PREFIXES);
|
|
429
|
+
|
|
430
|
+
it("cuts a wide pattern at the cap and reports the true total", async () => {
|
|
431
|
+
const out = await lookup("swatch.*");
|
|
432
|
+
expect(out.results).toHaveLength(GLOB_EXPANSION_CAP);
|
|
433
|
+
expect(out).toMatchObject({ truncated: true, total: FAMILY });
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it("says so in each surface's own spelling, and in the condensed body", async () => {
|
|
437
|
+
const out = await lookup("swatch.*");
|
|
438
|
+
const counted = `${GLOB_EXPANSION_CAP} of ${FAMILY} matches shown.`;
|
|
439
|
+
expect(formatters.notice?.(out, "cli")).toContain(counted);
|
|
440
|
+
expect(formatters.notice?.(out, "cli")).toContain("`--detail summary`");
|
|
441
|
+
expect(formatters.notice?.(out, "mcp")).toContain('`detail: "summary"`');
|
|
442
|
+
expect(formatters.llm(out).split("\n").at(-1)).toContain(counted);
|
|
443
|
+
expect(JSON.parse(formatters.json(out)).total).toBe(FAMILY);
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
it("does not advise summary to a caller already there", () => {
|
|
447
|
+
const out: LookupOutput = {
|
|
448
|
+
results: [],
|
|
449
|
+
errors: [],
|
|
450
|
+
truncated: true,
|
|
451
|
+
total: FAMILY,
|
|
452
|
+
detail: "summary",
|
|
453
|
+
};
|
|
454
|
+
expect(formatters.notice?.(out, "mcp")).toBe(
|
|
455
|
+
`0 of ${FAMILY} matches shown. Narrow the pattern to reach the rest.`,
|
|
456
|
+
);
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
it("counts ENTITIES: a name route and an IRI route to the same ones are one total", async () => {
|
|
460
|
+
const out = await lookup("swatch.*", "ds:swatch.*");
|
|
461
|
+
expect(out.total).toBe(FAMILY);
|
|
462
|
+
expect(out.results).toHaveLength(GLOB_EXPANSION_CAP);
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
it("cuts the same fifty every time, in name order", async () => {
|
|
466
|
+
const names = (await lookup("swatch.*")).results.map((e) => e.name);
|
|
467
|
+
expect(names).toEqual(
|
|
468
|
+
Array.from({ length: GLOB_EXPANSION_CAP }, (_, i) => `swatch.${pad(i)}`),
|
|
469
|
+
);
|
|
470
|
+
expect(
|
|
471
|
+
(await lookup("*.0*", "swatch.*")).results.map((e) => e.name),
|
|
472
|
+
).toEqual(names);
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
it("says nothing about a pattern answered in full", async () => {
|
|
476
|
+
const out = await lookup("swatch.00*");
|
|
477
|
+
expect(out.results).toHaveLength(10);
|
|
478
|
+
expect(out.truncated).toBeUndefined();
|
|
479
|
+
expect(formatters.notice?.(out, "cli")).toBeUndefined();
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
it("counts an entry ONCE across overlapping patterns", async () => {
|
|
483
|
+
// Twenty-seven matches over twenty-five entries: `swatch.001` and
|
|
484
|
+
// `swatch.011` are each matched twice and answered once.
|
|
485
|
+
const out = await lookup("swatch.00*", "swatch.0*1", "swatch.01*");
|
|
486
|
+
expect(out.truncated).toBeUndefined();
|
|
487
|
+
expect(out.results.map((entity) => entity.name)).toHaveLength(25);
|
|
488
|
+
expect(new Set(out.results.map((entity) => entity.uri)).size).toBe(25);
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
it("answers once for an entity a name pattern and an IRI pattern both reach", async () => {
|
|
492
|
+
const out = await lookup("swatch.001", "ds:swatch.001", "ds:swatch.00*");
|
|
493
|
+
expect(out.results).toHaveLength(10);
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
it("never cuts a literal — not even one a cut pattern also matched", async () => {
|
|
497
|
+
const last = `swatch.${pad(FAMILY - 1)}`;
|
|
498
|
+
const out = await lookup("swatch.*", last);
|
|
499
|
+
expect(out.results.map((entity) => entity.name)).toContain(last);
|
|
500
|
+
expect(out.results).toHaveLength(GLOB_EXPANSION_CAP + 1);
|
|
501
|
+
});
|
|
502
|
+
});
|