@canonical/pragma-cli 0.38.0 → 0.40.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 +1 -1
- package/dist/package.json +14 -14
- 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/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.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 +2 -2
- package/dist/src/capabilities/create/create.verb.js +14 -4
- package/dist/src/capabilities/create/create.verb.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/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/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/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/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/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/renderers.js +3 -3
- package/dist/src/kernel/render/turtle.js +21 -4
- package/dist/src/kernel/render/turtle.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/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 +14 -14
- 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 +2 -2
- package/src/capabilities/create/create.verb.ts +16 -0
- package/src/capabilities/create/createGrammar.test.ts +1 -1
- 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 +2 -2
- 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/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/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
|
@@ -12,6 +12,7 @@ import { RECOVERY_CLI_PREFIX } from "../../constants.js";
|
|
|
12
12
|
import { buildFixtureRuntime } from "../../testing/helpers/packRuntime.js";
|
|
13
13
|
import { PragmaError } from "../error/index.js";
|
|
14
14
|
import type { PragmaRuntime } from "../runtime/types.js";
|
|
15
|
+
import { declareVerbs } from "../spec/call.js";
|
|
15
16
|
import { kebabCase } from "../spec/emitSurface.js";
|
|
16
17
|
import type { VerbSpec } from "../spec/types.js";
|
|
17
18
|
import { compileListable, compilePack, compileStoryModule } from "./compile.js";
|
|
@@ -362,19 +363,28 @@ describe("the grammar rejects what the compiler cannot build (PROTECTED)", () =>
|
|
|
362
363
|
);
|
|
363
364
|
});
|
|
364
365
|
|
|
365
|
-
it("rejects
|
|
366
|
-
//
|
|
367
|
-
//
|
|
368
|
-
//
|
|
369
|
-
//
|
|
370
|
-
const
|
|
366
|
+
it("rejects the retired emptyRecovery.cli and a call that is a command line, naming the change", () => {
|
|
367
|
+
// A recovery names a CALL — a verb path and a param bag — and the consuming
|
|
368
|
+
// distribution spells it per surface. Third-party packs are third-party
|
|
369
|
+
// DATA: the old `cli` string gets an error that names the grammar change,
|
|
370
|
+
// and a command line in `verb` would render `pragma pragma sources update`.
|
|
371
|
+
const withRecovery = (recovery: Record<string, unknown>) => ({
|
|
371
372
|
noun: "widget",
|
|
372
|
-
list: { ...listShape, emptyRecovery: { message: "None.",
|
|
373
|
+
list: { ...listShape, emptyRecovery: { message: "None.", ...recovery } },
|
|
373
374
|
});
|
|
374
|
-
expect(parse(
|
|
375
|
-
/
|
|
375
|
+
expect(parse(withRecovery({ cli: "sources update" }))).toThrow(
|
|
376
|
+
/emptyRecovery\.cli is now emptyRecovery\.call/,
|
|
376
377
|
);
|
|
377
|
-
expect(
|
|
378
|
+
expect(
|
|
379
|
+
parse(
|
|
380
|
+
withRecovery({
|
|
381
|
+
call: { verb: `${RECOVERY_CLI_PREFIX}sources update` },
|
|
382
|
+
}),
|
|
383
|
+
),
|
|
384
|
+
).toThrow(/a call names a verb path/);
|
|
385
|
+
expect(
|
|
386
|
+
parse(withRecovery({ call: { verb: "sources update" } })),
|
|
387
|
+
).not.toThrow();
|
|
378
388
|
});
|
|
379
389
|
});
|
|
380
390
|
|
|
@@ -387,6 +397,11 @@ describe("pack compiler — SPARQL fetch path (PROTECTED)", () => {
|
|
|
387
397
|
prefixes: PREFIXES,
|
|
388
398
|
detail: "detailed",
|
|
389
399
|
}));
|
|
400
|
+
// A miss recovers to `widget list`; the suite checks every call it renders
|
|
401
|
+
// against the declared verbs, and a fixture's are not the distribution's.
|
|
402
|
+
declareVerbs(
|
|
403
|
+
compilePack(WIDGET_PACK, distributionSource("bundled:widget"), PREFIXES),
|
|
404
|
+
);
|
|
390
405
|
});
|
|
391
406
|
|
|
392
407
|
afterAll(async () => {
|
|
@@ -563,6 +578,88 @@ describe("pack compiler — SPARQL fetch path (PROTECTED)", () => {
|
|
|
563
578
|
* once, for the name resolve, and the resource listing reads that same
|
|
564
579
|
* declaration. Nothing to keep in sync because there is nothing written twice.
|
|
565
580
|
*/
|
|
581
|
+
describe("a lookup that declares no disclosure can still be asked for less", () => {
|
|
582
|
+
/** The widget lookup with every trace of disclosure removed. */
|
|
583
|
+
const BARE_PACK: PackDefinition = {
|
|
584
|
+
noun: "widget",
|
|
585
|
+
lookup: {
|
|
586
|
+
source: "sparql",
|
|
587
|
+
by: "ex:name",
|
|
588
|
+
type: "ex:Widget",
|
|
589
|
+
fields: [{ name: "description", property: "ex:description" }],
|
|
590
|
+
expand: [
|
|
591
|
+
{
|
|
592
|
+
name: "parts",
|
|
593
|
+
relation: "ex:hasPart",
|
|
594
|
+
select: [{ name: "name", property: "ex:name" }],
|
|
595
|
+
},
|
|
596
|
+
],
|
|
597
|
+
},
|
|
598
|
+
};
|
|
599
|
+
const lookupVerb = compilePack(
|
|
600
|
+
BARE_PACK,
|
|
601
|
+
distributionSource("bundled:widget"),
|
|
602
|
+
PREFIXES,
|
|
603
|
+
).find((v) => verbKey(v.path) === "widget lookup") as VerbSpec;
|
|
604
|
+
|
|
605
|
+
const lookupAt = async (options: {
|
|
606
|
+
detail?: "summary" | "standard" | "detailed";
|
|
607
|
+
configDetail?: "summary";
|
|
608
|
+
}) => {
|
|
609
|
+
const { rt } = await buildFixtureRuntime({
|
|
610
|
+
ttl: TTL,
|
|
611
|
+
prefixes: PREFIXES,
|
|
612
|
+
...(options.detail ? { detail: options.detail } : {}),
|
|
613
|
+
...(options.configDetail
|
|
614
|
+
? { configDetail: options.configDetail, detailOrigin: "project" }
|
|
615
|
+
: {}),
|
|
616
|
+
});
|
|
617
|
+
try {
|
|
618
|
+
const out = (await lookupVerb.run(
|
|
619
|
+
{ name: ["Button"] },
|
|
620
|
+
rt,
|
|
621
|
+
)) as LookupOutput;
|
|
622
|
+
return out.results.at(0);
|
|
623
|
+
} finally {
|
|
624
|
+
(await rt.store.get()).store.dispose();
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
it("advertises the canonical levels, defaulting to the fullest", () => {
|
|
629
|
+
expect(lookupVerb.disclosure).toEqual({
|
|
630
|
+
levels: ["summary", "standard", "detailed"],
|
|
631
|
+
default: "detailed",
|
|
632
|
+
});
|
|
633
|
+
});
|
|
634
|
+
|
|
635
|
+
it("answers exactly as before when nothing is asked for", async () => {
|
|
636
|
+
expect(await lookupAt({})).toEqual(await lookupAt({ detail: "detailed" }));
|
|
637
|
+
expect((await lookupAt({}))?.parts).toEqual([{ name: "Label" }]);
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
it("is the fields alone at summary, and everything from standard", async () => {
|
|
641
|
+
const summary = await lookupAt({ detail: "summary" });
|
|
642
|
+
expect(summary).toMatchObject({ description: "A button." });
|
|
643
|
+
expect(summary).not.toHaveProperty("parts");
|
|
644
|
+
expect(await lookupAt({ detail: "standard" })).toHaveProperty("parts");
|
|
645
|
+
});
|
|
646
|
+
|
|
647
|
+
it("follows a configured detail, as a declared disclosure always did", async () => {
|
|
648
|
+
expect(await lookupAt({ configDetail: "summary" })).not.toHaveProperty(
|
|
649
|
+
"parts",
|
|
650
|
+
);
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
it("leaves a declared disclosure exactly as its author wrote it", () => {
|
|
654
|
+
const declared = compilePack(
|
|
655
|
+
WIDGET_PACK,
|
|
656
|
+
distributionSource("bundled:widget"),
|
|
657
|
+
PREFIXES,
|
|
658
|
+
).find((v) => verbKey(v.path) === "widget lookup");
|
|
659
|
+
expect(declared?.disclosure?.default).toBe("summary");
|
|
660
|
+
});
|
|
661
|
+
});
|
|
662
|
+
|
|
566
663
|
describe("declared listing (derived from the lookup's types)", () => {
|
|
567
664
|
it("derives one collection per declared type, unweighted types at 1", () => {
|
|
568
665
|
expect(
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* facade).
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import { BIN_NAME } from "../../constants.js";
|
|
17
|
+
import { BIN_NAME, DETAIL_LEVELS } from "../../constants.js";
|
|
18
18
|
import { PragmaError } from "../error/index.js";
|
|
19
19
|
import { compactUri, DEFAULT_PREFIX_MAP } from "../render/index.js";
|
|
20
20
|
import type { PragmaRuntime } from "../runtime/index.js";
|
|
@@ -42,8 +42,10 @@ import {
|
|
|
42
42
|
import { storyIssues } from "./storyRules.js";
|
|
43
43
|
import {
|
|
44
44
|
EVERY_TIER,
|
|
45
|
+
type NounLookups,
|
|
45
46
|
type PackDefinition,
|
|
46
47
|
type PackFilter,
|
|
48
|
+
type PackGuidance,
|
|
47
49
|
type PackList,
|
|
48
50
|
type PackLookup,
|
|
49
51
|
type PackPage,
|
|
@@ -74,17 +76,22 @@ const READ_CAPABILITY = {
|
|
|
74
76
|
* @param definition - A validated pack definition.
|
|
75
77
|
* @param source - Where the definition came from, for diagnostics.
|
|
76
78
|
* @param prefixes - The merged prefix map used for display compaction.
|
|
79
|
+
* @param nouns - The other stories' lookups, which a filter naming a noun
|
|
80
|
+
* resolves its values through. Read at run time only.
|
|
77
81
|
* @returns The compiled verbs (list, extra verbs, lookup, sample), in order.
|
|
78
82
|
*/
|
|
79
83
|
export function compilePack(
|
|
80
84
|
definition: PackDefinition,
|
|
81
85
|
source: StorySource,
|
|
82
86
|
prefixes: Readonly<Record<string, string>>,
|
|
87
|
+
nouns?: NounLookups,
|
|
83
88
|
): VerbSpec[] {
|
|
84
89
|
const { noun } = definition;
|
|
85
90
|
const verbs: VerbSpec[] = [];
|
|
86
91
|
|
|
87
92
|
const tierScope = definition.tierScope;
|
|
93
|
+
// A story may declare a lookup alone; a miss must not point at a `list` it lacks.
|
|
94
|
+
const hasList = definition.list !== undefined;
|
|
88
95
|
|
|
89
96
|
if (definition.list) {
|
|
90
97
|
verbs.push(
|
|
@@ -93,8 +100,10 @@ export function compilePack(
|
|
|
93
100
|
verb: "list",
|
|
94
101
|
summary: definition.description ?? `List ${noun} entries.`,
|
|
95
102
|
doc: definition.toolDescription,
|
|
103
|
+
...guidanceOf(definition),
|
|
96
104
|
source,
|
|
97
105
|
prefixes,
|
|
106
|
+
...(nouns ? { nouns } : {}),
|
|
98
107
|
...(tierScope ? { tierScope } : {}),
|
|
99
108
|
}),
|
|
100
109
|
);
|
|
@@ -107,19 +116,24 @@ export function compilePack(
|
|
|
107
116
|
verb: verb.verb,
|
|
108
117
|
summary: verb.description ?? `List ${noun} ${verb.verb}.`,
|
|
109
118
|
doc: verb.toolDescription,
|
|
119
|
+
...guidanceOf(verb),
|
|
110
120
|
source,
|
|
111
121
|
prefixes,
|
|
122
|
+
...(nouns ? { nouns } : {}),
|
|
112
123
|
...(tierScope ? { tierScope } : {}),
|
|
113
124
|
}),
|
|
114
125
|
);
|
|
115
126
|
}
|
|
116
127
|
|
|
117
128
|
if (definition.lookup) {
|
|
129
|
+
// Normalised ONCE, here, so the lookup verb, its run body, both fetch lanes
|
|
130
|
+
// and the sample all read the same declaration.
|
|
131
|
+
const lookup = withDisclosure(definition.lookup);
|
|
118
132
|
verbs.push(
|
|
119
|
-
compileLookupVerb(
|
|
133
|
+
compileLookupVerb(lookup, noun, source, prefixes, hasList, tierScope),
|
|
120
134
|
);
|
|
121
|
-
if (
|
|
122
|
-
verbs.push(compileSampleVerb(
|
|
135
|
+
if (lookup.sample) {
|
|
136
|
+
verbs.push(compileSampleVerb(lookup, noun, source, prefixes, hasList));
|
|
123
137
|
}
|
|
124
138
|
}
|
|
125
139
|
|
|
@@ -195,6 +209,7 @@ export function compileListable(
|
|
|
195
209
|
* @param definition - A validated pack definition.
|
|
196
210
|
* @param source - Where the definition came from, for diagnostics.
|
|
197
211
|
* @param prefixes - The merged prefix map used for display compaction.
|
|
212
|
+
* @param nouns - As {@link compilePack}.
|
|
198
213
|
* @returns The module: the compiled verbs plus the story's module-level data.
|
|
199
214
|
* @throws PragmaError CONFIG_ERROR when the definition cannot be compiled,
|
|
200
215
|
* naming the field and the rule.
|
|
@@ -203,6 +218,7 @@ export function compileStoryModule(
|
|
|
203
218
|
definition: PackDefinition,
|
|
204
219
|
source: StorySource,
|
|
205
220
|
prefixes: Readonly<Record<string, string>>,
|
|
221
|
+
nouns?: NounLookups,
|
|
206
222
|
): CapabilityModule {
|
|
207
223
|
const issue = storyIssues(definition)[0];
|
|
208
224
|
if (issue) {
|
|
@@ -211,17 +227,47 @@ export function compileStoryModule(
|
|
|
211
227
|
);
|
|
212
228
|
}
|
|
213
229
|
const listable = compileListable(definition);
|
|
214
|
-
|
|
230
|
+
const module: CapabilityModule = {
|
|
215
231
|
name: definition.noun,
|
|
216
232
|
story: true,
|
|
217
|
-
verbs: compilePack(definition, source, prefixes),
|
|
233
|
+
verbs: compilePack(definition, source, prefixes, nouns),
|
|
218
234
|
colophon: definition.colophon,
|
|
219
235
|
...(listable ? { mcpListable: listable } : {}),
|
|
220
236
|
};
|
|
237
|
+
compiledFrom.set(module, { definition, source, prefixes });
|
|
238
|
+
return module;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** What each story module was compiled from. */
|
|
242
|
+
const compiledFrom = new WeakMap<
|
|
243
|
+
CapabilityModule,
|
|
244
|
+
{
|
|
245
|
+
readonly definition: PackDefinition;
|
|
246
|
+
readonly source: StorySource;
|
|
247
|
+
readonly prefixes: Readonly<Record<string, string>>;
|
|
248
|
+
}
|
|
249
|
+
>();
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* The story a module was compiled from by {@link compileStoryModule}, with the
|
|
253
|
+
* source and prefixes it was compiled under; `undefined` for any other module.
|
|
254
|
+
*/
|
|
255
|
+
export function storyOf(
|
|
256
|
+
module: CapabilityModule,
|
|
257
|
+
): ReturnType<(typeof compiledFrom)["get"]> {
|
|
258
|
+
return compiledFrom.get(module);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/** Carry a story half's declared guidance onto its verb, omitting what is absent. */
|
|
262
|
+
function guidanceOf(half: PackGuidance): Pick<VerbSpec, "useWhen" | "example"> {
|
|
263
|
+
return {
|
|
264
|
+
...(half.useWhen ? { useWhen: half.useWhen } : {}),
|
|
265
|
+
...(half.example ? { example: half.example } : {}),
|
|
266
|
+
};
|
|
221
267
|
}
|
|
222
268
|
|
|
223
269
|
/** Presentation facts for one compiled list-shaped verb. */
|
|
224
|
-
interface ListVerbMeta {
|
|
270
|
+
interface ListVerbMeta extends PackGuidance {
|
|
225
271
|
readonly noun: string;
|
|
226
272
|
readonly verb: string;
|
|
227
273
|
readonly summary: string;
|
|
@@ -229,6 +275,8 @@ interface ListVerbMeta {
|
|
|
229
275
|
readonly doc?: string;
|
|
230
276
|
readonly source: StorySource;
|
|
231
277
|
readonly prefixes: Readonly<Record<string, string>>;
|
|
278
|
+
/** The other stories' lookups, for a filter that names a noun. */
|
|
279
|
+
readonly nouns?: NounLookups;
|
|
232
280
|
/** The noun's declared tier hierarchy, when its entities are tiered. */
|
|
233
281
|
readonly tierScope?: PackTierScope;
|
|
234
282
|
}
|
|
@@ -246,6 +294,7 @@ function compileListVerb(shape: PackList, meta: ListVerbMeta): VerbSpec {
|
|
|
246
294
|
path: [meta.noun, meta.verb],
|
|
247
295
|
summary: meta.summary,
|
|
248
296
|
...(meta.doc ? { doc: meta.doc } : {}),
|
|
297
|
+
...guidanceOf(meta),
|
|
249
298
|
params,
|
|
250
299
|
output: {
|
|
251
300
|
formatters: listFormatters(shape, {
|
|
@@ -272,6 +321,8 @@ function compileListVerb(shape: PackList, meta: ListVerbMeta): VerbSpec {
|
|
|
272
321
|
runBodies().then((m) =>
|
|
273
322
|
m.makeListRun(shape, {
|
|
274
323
|
source: meta.source,
|
|
324
|
+
prefixes: meta.prefixes,
|
|
325
|
+
...(meta.nouns ? { nouns: meta.nouns } : {}),
|
|
275
326
|
...(meta.tierScope ? { tierScope: meta.tierScope } : {}),
|
|
276
327
|
})(params, rt),
|
|
277
328
|
),
|
|
@@ -285,6 +336,7 @@ function compileLookupVerb(
|
|
|
285
336
|
noun: string,
|
|
286
337
|
source: StorySource,
|
|
287
338
|
prefixes: Readonly<Record<string, string>>,
|
|
339
|
+
hasList: boolean,
|
|
288
340
|
tierScope?: PackTierScope,
|
|
289
341
|
): VerbSpec {
|
|
290
342
|
// Derive-by-default: every lookup completes its `<name>` from the pack index
|
|
@@ -319,6 +371,7 @@ function compileLookupVerb(
|
|
|
319
371
|
summary:
|
|
320
372
|
lookup.description ?? `Look up ${noun} details by name, IRI, or glob.`,
|
|
321
373
|
...(lookup.toolDescription ? { doc: lookup.toolDescription } : {}),
|
|
374
|
+
...guidanceOf(lookup),
|
|
322
375
|
params: [nameParam, ...tierParams(tierScope)],
|
|
323
376
|
output: { formatters: lookupFormatters(lookup, prefixes) },
|
|
324
377
|
examples: [
|
|
@@ -332,13 +385,18 @@ function compileLookupVerb(
|
|
|
332
385
|
]
|
|
333
386
|
: []),
|
|
334
387
|
],
|
|
335
|
-
|
|
336
|
-
? { disclosure: disclosureSpec(lookup.disclosure) }
|
|
337
|
-
: {}),
|
|
388
|
+
disclosure: disclosureSpec(lookup.disclosure),
|
|
338
389
|
capability: READ_CAPABILITY,
|
|
339
390
|
run: (params: Record<string, unknown>, rt: PragmaRuntime) =>
|
|
340
391
|
runBodies().then((m) =>
|
|
341
|
-
m.makeLookupRun(
|
|
392
|
+
m.makeLookupRun(
|
|
393
|
+
lookup,
|
|
394
|
+
noun,
|
|
395
|
+
source,
|
|
396
|
+
prefixes,
|
|
397
|
+
hasList,
|
|
398
|
+
tierScope,
|
|
399
|
+
)(params, rt),
|
|
342
400
|
),
|
|
343
401
|
};
|
|
344
402
|
return asVerb(verb);
|
|
@@ -374,6 +432,7 @@ function compileSampleVerb(
|
|
|
374
432
|
noun: string,
|
|
375
433
|
source: StorySource,
|
|
376
434
|
prefixes: Readonly<Record<string, string>>,
|
|
435
|
+
hasList: boolean,
|
|
377
436
|
): VerbSpec {
|
|
378
437
|
const defaultCount = sampleDefaultCount(lookup);
|
|
379
438
|
const config = lookup.sample === true ? undefined : lookup.sample;
|
|
@@ -396,6 +455,7 @@ function compileSampleVerb(
|
|
|
396
455
|
config?.description ??
|
|
397
456
|
`Return randomly selected complete ${noun} entries as exemplars.`,
|
|
398
457
|
...(config?.toolDescription ? { doc: config.toolDescription } : {}),
|
|
458
|
+
...guidanceOf(config ?? {}),
|
|
399
459
|
params: countParam,
|
|
400
460
|
output: { formatters: sampleFormatters(lookup, noun, prefixes) },
|
|
401
461
|
examples: [
|
|
@@ -411,12 +471,41 @@ function compileSampleVerb(
|
|
|
411
471
|
source,
|
|
412
472
|
prefixes,
|
|
413
473
|
defaultCount,
|
|
474
|
+
hasList,
|
|
414
475
|
)(params, rt),
|
|
415
476
|
),
|
|
416
477
|
};
|
|
417
478
|
return asVerb(verb);
|
|
418
479
|
}
|
|
419
480
|
|
|
481
|
+
/**
|
|
482
|
+
* Give a lookup that declares no disclosure the canonical ladder: default
|
|
483
|
+
* `detailed` (so its default answer is unchanged) and untagged expands from
|
|
484
|
+
* `standard` (so `summary` is the fields alone, and `standard` equals
|
|
485
|
+
* `detailed`). A declared disclosure is returned as written.
|
|
486
|
+
*/
|
|
487
|
+
function withDisclosure(lookup: PackLookup): PackLookup {
|
|
488
|
+
if (lookup.disclosure) return lookup;
|
|
489
|
+
return {
|
|
490
|
+
...lookup,
|
|
491
|
+
disclosure: { levels: [...DETAIL_LEVELS], default: IMPUTED_DEFAULT_LEVEL },
|
|
492
|
+
...(lookup.expand
|
|
493
|
+
? {
|
|
494
|
+
expand: lookup.expand.map((expand) => ({
|
|
495
|
+
...expand,
|
|
496
|
+
level: expand.level ?? IMPUTED_EXPAND_LEVEL,
|
|
497
|
+
})),
|
|
498
|
+
}
|
|
499
|
+
: {}),
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/** The level an imputed disclosure answers at when none is asked for: all of it. */
|
|
504
|
+
const IMPUTED_DEFAULT_LEVEL = "detailed";
|
|
505
|
+
|
|
506
|
+
/** The level from which an imputed disclosure shows an untagged expand. */
|
|
507
|
+
const IMPUTED_EXPAND_LEVEL = "standard";
|
|
508
|
+
|
|
420
509
|
/** Normalize a pack disclosure into a {@link DisclosureSpec} (default → base). */
|
|
421
510
|
function disclosureSpec(disclosure: PackLookup["disclosure"]): DisclosureSpec {
|
|
422
511
|
const levels = disclosure?.levels ?? [];
|
|
@@ -58,7 +58,7 @@ ex:slider a ex:Widget ; ex:name "Slider" ; ex:kind "input" .
|
|
|
58
58
|
const EMPTY_RECOVERY = {
|
|
59
59
|
message:
|
|
60
60
|
"Widgets are recorded by the catalogue build, and a store built before it ran records none.",
|
|
61
|
-
|
|
61
|
+
call: { verb: "sources update" },
|
|
62
62
|
} as const;
|
|
63
63
|
|
|
64
64
|
const listShape = (uriClass: string) => ({
|
|
@@ -133,10 +133,12 @@ describe("a zero-row answer names the filter and keeps the recovery", () => {
|
|
|
133
133
|
expect(outcome.exitCode).toBe(0);
|
|
134
134
|
const said = `${outcome.stdout ?? ""}${outcome.stderr ?? ""}`;
|
|
135
135
|
expect(said).toContain("No widget matches `--search zzzznotreal`.");
|
|
136
|
-
// The filter is the news; the story's account of where
|
|
137
|
-
//
|
|
136
|
+
// The filter is the news, with how to widen; the story's account of where
|
|
137
|
+
// widgets come from is kept — and the rebuild is not advised, because a
|
|
138
|
+
// filter that missed says nothing about the store.
|
|
139
|
+
expect(said).toContain("drop the argument, or loosen it");
|
|
138
140
|
expect(said).toContain("recorded by the catalogue build");
|
|
139
|
-
expect(said).toContain("
|
|
141
|
+
expect(said).not.toContain("sources update");
|
|
140
142
|
});
|
|
141
143
|
|
|
142
144
|
it("every filter in force is named", async () => {
|
|
@@ -195,7 +197,7 @@ describe("a zero-row answer names the filter and keeps the recovery", () => {
|
|
|
195
197
|
const said = `${outcome.stderr ?? ""}`;
|
|
196
198
|
expect(said).toContain("No gadget matches `--kind input`.");
|
|
197
199
|
expect(said).toContain("recorded by the catalogue build");
|
|
198
|
-
expect(said).toContain("
|
|
200
|
+
expect(said).not.toContain("sources update");
|
|
199
201
|
});
|
|
200
202
|
|
|
201
203
|
it("an EMPTY POPULATION unfiltered gets the kernel's own sentence", async () => {
|
|
@@ -210,4 +212,19 @@ describe("a zero-row answer names the filter and keeps the recovery", () => {
|
|
|
210
212
|
expect(outcome.stderr).toContain("recorded by the catalogue build");
|
|
211
213
|
expect(outcome.stderr).toContain("pragma sources update");
|
|
212
214
|
});
|
|
215
|
+
|
|
216
|
+
it("a story with no recovery of its own: rebuild unfiltered, never when filtered", async () => {
|
|
217
|
+
const bare: PackDefinition = {
|
|
218
|
+
...GADGET_PACK,
|
|
219
|
+
list: { ...listShape("ex:Gadget") },
|
|
220
|
+
};
|
|
221
|
+
const said = async (params: Record<string, unknown>): Promise<string> =>
|
|
222
|
+
(await executeVerb(listVerb(bare), params, REAL, as(PLAIN))).stderr ?? "";
|
|
223
|
+
|
|
224
|
+
expect(await said({})).toContain("pragma sources update");
|
|
225
|
+
const filtered = await said({ kind: "input" });
|
|
226
|
+
expect(filtered).toContain("drop the argument, or loosen it");
|
|
227
|
+
expect(filtered).not.toContain("sources update");
|
|
228
|
+
expect(filtered).not.toContain("needs building");
|
|
229
|
+
});
|
|
213
230
|
});
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* composed only from validated pack terms and compiled schema names.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import { callRecovery, PragmaError } from "../../error/index.js";
|
|
18
18
|
import type { PragmaRuntime } from "../../runtime/index.js";
|
|
19
19
|
import type { PackChildRow, PackEntity, PackLookup } from "../types.js";
|
|
20
20
|
import {
|
|
@@ -56,10 +56,9 @@ export async function fetchGraphqlLookup(
|
|
|
56
56
|
.join("; ");
|
|
57
57
|
throw PragmaError.storeUnavailable(`GraphQL lookup failed: ${messages}`, {
|
|
58
58
|
// `graph inspect` needs a <uri>; `ontology list` is runnable as-is.
|
|
59
|
-
recovery:
|
|
60
|
-
"ontology list",
|
|
59
|
+
recovery: callRecovery(
|
|
60
|
+
{ verb: "ontology list" },
|
|
61
61
|
"Check the loaded ontology and namespaces.",
|
|
62
|
-
{ tool: "ontology_list" },
|
|
63
62
|
),
|
|
64
63
|
});
|
|
65
64
|
}
|
|
@@ -72,8 +71,8 @@ export async function fetchGraphqlLookup(
|
|
|
72
71
|
throw new PragmaError({
|
|
73
72
|
code: "ENTITY_NOT_FOUND",
|
|
74
73
|
message: `Cannot resolve <${entityUri}> — its rdf:type may be missing from the ontology.`,
|
|
75
|
-
recovery:
|
|
76
|
-
|
|
74
|
+
recovery: callRecovery(
|
|
75
|
+
{ verb: "graph inspect", params: { uri: entityUri } },
|
|
77
76
|
"Inspect the entity's triples to check its rdf:type.",
|
|
78
77
|
),
|
|
79
78
|
});
|
|
@@ -14,6 +14,7 @@ import { buildFixtureRuntime } from "../../testing/helpers/packRuntime.js";
|
|
|
14
14
|
import type { PragmaRuntime, StoreSession } from "../runtime/types.js";
|
|
15
15
|
import { compilePack } from "./compile.js";
|
|
16
16
|
import { buildLookupDocument } from "./graphql/buildLookupDocument.js";
|
|
17
|
+
import { fetchGraphqlLookup } from "./graphql/fetchGraphqlLookup.js";
|
|
17
18
|
import type { LookupOutput } from "./resolveEntity.js";
|
|
18
19
|
import { parsePackDefinition } from "./schema.js";
|
|
19
20
|
import type { PackDefinition, PackLookup } from "./types.js";
|
|
@@ -320,6 +321,47 @@ describe("GraphQL engine — against the compiled fixture schema (PROTECTED)", (
|
|
|
320
321
|
|
|
321
322
|
const lookup = GBLOCK.lookup as PackLookup;
|
|
322
323
|
|
|
324
|
+
/** The fixture runtime with its GraphQL executor replaced by a canned answer. */
|
|
325
|
+
const answering = (answer: unknown): PragmaRuntime =>
|
|
326
|
+
({
|
|
327
|
+
...rt,
|
|
328
|
+
query: { ...rt.query, graphql: async () => answer },
|
|
329
|
+
}) as PragmaRuntime;
|
|
330
|
+
const fetchWith = (answer: unknown) =>
|
|
331
|
+
fetchGraphqlLookup(
|
|
332
|
+
answering(answer),
|
|
333
|
+
lookup,
|
|
334
|
+
"https://ds.canonical.com/x",
|
|
335
|
+
"X",
|
|
336
|
+
"t",
|
|
337
|
+
BLOCK_PREFIXES,
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
it("an execution error recovers to the namespace list, in both spellings", async () => {
|
|
341
|
+
await expect(
|
|
342
|
+
fetchWith({ errors: [{ message: "boom" }] }),
|
|
343
|
+
).rejects.toMatchObject({
|
|
344
|
+
code: "STORE_UNAVAILABLE",
|
|
345
|
+
recovery: {
|
|
346
|
+
cli: "pragma ontology list",
|
|
347
|
+
mcp: { tool: "ontology_list", params: {} },
|
|
348
|
+
},
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it("a resolved IRI with no typed node recovers to inspecting THAT entity", async () => {
|
|
353
|
+
await expect(fetchWith({ data: { node: null } })).rejects.toMatchObject({
|
|
354
|
+
code: "ENTITY_NOT_FOUND",
|
|
355
|
+
recovery: {
|
|
356
|
+
cli: "pragma graph inspect https://ds.canonical.com/x",
|
|
357
|
+
mcp: {
|
|
358
|
+
tool: "graph_inspect",
|
|
359
|
+
params: { uri: "https://ds.canonical.com/x" },
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
});
|
|
363
|
+
});
|
|
364
|
+
|
|
323
365
|
it("generates one document with derived names, Relay envelopes, subtype scoping", () => {
|
|
324
366
|
const plan = buildLookupDocument(lookup, schema, "t");
|
|
325
367
|
expect(plan.source).toContain("query PackLookup($uri: ID!)");
|
package/src/kernel/packs/iri.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* before it can be interpolated into a generated `<iri>` query token.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { callRecovery, PragmaError } from "../error/index.js";
|
|
11
11
|
|
|
12
12
|
/** Characters not allowed inside a SPARQL `<IRI>`. */
|
|
13
13
|
const UNSAFE_IRI_PATTERN = /[<>"{}|\\^`\s]/;
|
|
@@ -86,9 +86,10 @@ function tryResolveUri(
|
|
|
86
86
|
|
|
87
87
|
return PragmaError.invalidInput("prefix", prefix, {
|
|
88
88
|
validOptions: Object.keys(prefixes),
|
|
89
|
-
recovery:
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
recovery: callRecovery(
|
|
90
|
+
{ verb: "ontology list" },
|
|
91
|
+
"List known ontology prefixes.",
|
|
92
|
+
),
|
|
92
93
|
});
|
|
93
94
|
}
|
|
94
95
|
|
|
@@ -46,7 +46,7 @@ ex:slider a ex:Widget ; ex:name "Slider" ; ex:kind "input" .
|
|
|
46
46
|
/** The recovery a story authors for an EMPTY POPULATION — never for a filter. */
|
|
47
47
|
const EMPTY_RECOVERY = {
|
|
48
48
|
message: "No widgets in the store.",
|
|
49
|
-
|
|
49
|
+
call: { verb: "sources update" },
|
|
50
50
|
} as const;
|
|
51
51
|
|
|
52
52
|
const WIDGET_LIST = {
|