@canonical/pragma-cli 0.33.0 → 0.34.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 +7 -7
- package/dist/pragma +0 -0
- package/package.json +18 -15
- package/pragma.conf.ts +664 -0
- package/src/bin.ts +13 -4
- package/src/capabilities/block.parity.test.ts +250 -0
- package/src/capabilities/capabilities/capabilities.render.ts +3 -2
- package/src/capabilities/capabilities/capabilities.verb.ts +31 -13
- package/src/capabilities/capabilities/catalog.ts +18 -10
- package/src/capabilities/capabilities/hints.ts +13 -19
- package/src/capabilities/colophon/collectColophon.ts +34 -19
- package/src/capabilities/colophon/colophon.verb.ts +8 -4
- package/src/capabilities/colophon/types.ts +16 -7
- package/src/capabilities/config/collectConfigShow.test.ts +57 -0
- package/src/capabilities/config/collectConfigShow.ts +41 -4
- package/src/capabilities/config/fields.ts +0 -27
- package/src/capabilities/config/set.verb.ts +7 -3
- package/src/capabilities/config/show.render.test.ts +77 -5
- package/src/capabilities/config/show.render.ts +7 -12
- package/src/capabilities/config/show.verb.ts +4 -3
- package/src/capabilities/config/types.ts +8 -0
- package/src/capabilities/create/byteEquality.test.ts +78 -100
- package/src/capabilities/create/compiledCreate.subprocess.test.ts +52 -15
- package/src/capabilities/create/constants.ts +75 -0
- package/src/capabilities/create/create.mcp.test.ts +2 -2
- package/src/capabilities/create/create.test.ts +162 -15
- package/src/capabilities/create/create.verb.ts +140 -69
- package/src/capabilities/create/index.ts +2 -10
- package/src/capabilities/create/pickGenerator.ts +34 -28
- package/src/capabilities/create/templates.embedded.generated.ts +4 -29
- package/src/capabilities/create/types.ts +10 -6
- package/src/capabilities/{standard/parity.test.ts → distribution.parity.test.ts} +24 -14
- package/src/capabilities/distribution.test.ts +120 -0
- package/src/capabilities/distribution.ts +59 -0
- package/src/capabilities/doctor/checks/checkConfigFile.ts +6 -5
- package/src/capabilities/doctor/checks/checkKeStore.ts +2 -2
- package/src/capabilities/doctor/checks/checkMcpConfigured.ts +7 -6
- package/src/capabilities/doctor/checks/checkPackageRefs.ts +79 -45
- package/src/capabilities/doctor/checks/checkPragmaVersion.ts +3 -2
- package/src/capabilities/doctor/checks/checkShellCompletions.test.ts +61 -11
- package/src/capabilities/doctor/checks/checkShellCompletions.ts +63 -23
- package/src/capabilities/doctor/checks/checkSkillsSymlinked.ts +3 -2
- package/src/capabilities/doctor/doctor.render.test.ts +6 -6
- package/src/capabilities/doctor/doctor.render.ts +2 -1
- package/src/capabilities/doctor/doctor.test.ts +37 -8
- package/src/capabilities/doctor/doctor.verb.ts +6 -2
- package/src/capabilities/doctor/runChecks.ts +5 -5
- package/src/capabilities/doctor/types.ts +1 -1
- package/src/capabilities/emptyRecovery.test.ts +32 -15
- package/src/capabilities/graph/inspect.verb.ts +3 -2
- package/src/capabilities/graph/query.verb.ts +3 -2
- package/src/capabilities/graph/runQuery.ts +8 -5
- package/src/capabilities/index.ts +22 -18
- package/src/capabilities/info/collectInfo.ts +10 -6
- package/src/capabilities/info/info.render.ts +3 -2
- package/src/capabilities/info/info.verb.ts +3 -2
- package/src/capabilities/lazy.test.ts +93 -2
- package/src/capabilities/ontology/verbs.ts +21 -21
- package/src/capabilities/prompt/prompt.test.ts +12 -6
- package/src/capabilities/prompt/verbs.ts +24 -11
- package/src/capabilities/resources/provider.ts +30 -11
- package/src/capabilities/resources/resources.test.ts +85 -29
- package/src/capabilities/setup/operations/setupGenerator.ts +16 -9
- package/src/capabilities/setup/operations/setupMcp.ts +2 -2
- package/src/capabilities/setup/operations/setupSkills.ts +3 -3
- package/src/capabilities/setup/setup.verb.ts +12 -5
- package/src/capabilities/setup/shell.ts +29 -3
- package/src/capabilities/skill/discover.ts +11 -5
- package/src/capabilities/skill/render.ts +4 -5
- package/src/capabilities/skill/verbs.ts +7 -7
- package/src/capabilities/sources/collectStatus.ts +55 -50
- package/src/capabilities/sources/index.ts +1 -1
- package/src/capabilities/sources/installSkills.ts +2 -2
- package/src/capabilities/sources/runUpdate.ts +113 -122
- package/src/capabilities/sources/sources.test.ts +111 -117
- package/src/capabilities/sources/status.render.test.ts +53 -24
- package/src/capabilities/sources/status.render.ts +24 -29
- package/src/capabilities/sources/status.verb.ts +15 -8
- package/src/capabilities/sources/types.ts +18 -25
- package/src/capabilities/sources/update.render.ts +9 -2
- package/src/capabilities/sources/update.verb.ts +12 -23
- package/src/capabilities/surface.test.ts +33 -10
- package/src/capabilities/tier.parity.test.ts +144 -0
- package/src/capabilities/upgrade/upgrade.verb.ts +7 -3
- package/src/constants.test.ts +8 -6
- package/src/constants.ts +47 -21
- package/src/identity.test.ts +333 -0
- package/src/index.ts +2 -2
- package/src/kernel/completion/__snapshots__/emitScripts.test.ts.snap +5 -2
- package/src/kernel/completion/emitScripts.test.ts +1 -1
- package/src/kernel/completion/emitScripts.ts +4 -2
- package/src/kernel/completion/entitySource.test.ts +185 -41
- package/src/kernel/completion/entitySource.ts +117 -107
- package/src/kernel/completion/model.test.ts +1 -1
- package/src/kernel/completion/model.ts +11 -0
- package/src/kernel/completion/safety.test.ts +82 -36
- package/src/kernel/completion/shellDrive.test.ts +592 -0
- package/src/kernel/completion/templates/fish.ts +28 -6
- package/src/kernel/completion/types.ts +3 -3
- package/src/kernel/config/__snapshots__/firstRun.test.ts.snap +1 -1
- package/src/kernel/config/defaults.test.ts +85 -0
- package/src/kernel/config/defaults.ts +12 -23
- package/src/kernel/config/evaluateProjectConfig.ts +2 -3
- package/src/kernel/config/findProjectConfig.ts +4 -3
- package/src/kernel/config/firstRun.ts +12 -5
- package/src/kernel/config/globalConfig.ts +2 -2
- package/src/kernel/config/index.ts +4 -5
- package/src/kernel/config/paths.ts +17 -17
- package/src/kernel/config/readConfig.test.ts +242 -6
- package/src/kernel/config/readConfig.ts +8 -8
- package/src/kernel/config/schema.test.ts +50 -0
- package/src/kernel/config/schema.ts +97 -10
- package/src/kernel/config/types.ts +73 -19
- package/src/kernel/copy.test.ts +453 -0
- package/src/kernel/error/PragmaError.test.ts +1 -1
- package/src/kernel/error/constants.ts +3 -2
- package/src/kernel/error/index.ts +1 -1
- package/src/kernel/error/recovery.test.ts +22 -45
- package/src/kernel/error/recovery.ts +22 -27
- package/src/kernel/error/types.ts +5 -4
- package/src/kernel/packs/collect.test.ts +195 -11
- package/src/kernel/packs/collect.ts +213 -58
- package/src/kernel/packs/compile.test.ts +163 -7
- package/src/kernel/packs/compile.ts +15 -12
- package/src/kernel/packs/disclosure.test.ts +5 -2
- package/src/kernel/packs/graphql/fetchGraphqlLookup.ts +11 -10
- package/src/kernel/packs/graphqlSource.test.ts +6 -3
- package/src/kernel/packs/iri.ts +5 -7
- package/src/kernel/packs/renderPack.ts +5 -3
- package/src/kernel/packs/resolveEntity.ts +21 -17
- package/src/kernel/packs/runBodies.ts +15 -14
- package/src/kernel/packs/schema.ts +96 -10
- package/src/kernel/packs/sparql/runSelect.test.ts +104 -10
- package/src/kernel/packs/sparql/runSelect.ts +73 -34
- package/src/kernel/packs/toolDescription.test.ts +10 -2
- package/src/kernel/packs/types.ts +39 -4
- package/src/kernel/packs/uniqueness.ts +4 -4
- package/src/kernel/project/cli/buildProgram.test.ts +9 -4
- package/src/kernel/project/cli/dispatch.test.ts +67 -0
- package/src/kernel/project/cli/dispatch.ts +34 -12
- package/src/kernel/project/cli/helpFormat.ts +1 -1
- package/src/kernel/project/cli/rootHelp.ts +105 -105
- package/src/kernel/project/mcp/buildServer.ts +11 -6
- package/src/kernel/project/mcp/instructions.ts +11 -6
- package/src/kernel/project/mcp/parity.test.ts +39 -1
- package/src/kernel/project/mcp/prompts/prompts.test.ts +120 -5
- package/src/kernel/project/mcp/prompts/provider.ts +22 -8
- package/src/kernel/project/mcp/prompts/source.ts +68 -67
- package/src/kernel/project/mcp/registerVerb.ts +25 -6
- package/src/kernel/project/mcp/serve.ts +11 -3
- package/src/kernel/project/mcp/toolDescriptions.test.ts +6 -2
- package/src/kernel/render/disclosure.ts +4 -2
- package/src/kernel/render/prefixes.test.ts +36 -0
- package/src/kernel/render/prefixes.ts +40 -13
- package/src/kernel/render/renderers.test.ts +1 -1
- package/src/kernel/runtime/graphpack/build.ts +29 -3
- package/src/kernel/runtime/graphpack/buildIndex.test.ts +46 -0
- package/src/kernel/runtime/graphpack/buildIndex.ts +52 -17
- package/src/kernel/runtime/graphpack/embedded/pack.generated.ts +5 -5
- package/src/kernel/runtime/graphpack/embedded/pack.index.generated.ts +3 -3
- package/src/kernel/runtime/graphpack/embedded/pack.stories.generated.ts +3 -0
- package/src/kernel/runtime/graphpack/embedded.ts +37 -11
- package/src/kernel/runtime/graphpack/graphpack.test.ts +205 -5
- package/src/kernel/runtime/graphpack/hash.ts +3 -2
- package/src/kernel/runtime/graphpack/index.ts +1 -1
- package/src/kernel/runtime/graphpack/manifest.ts +114 -12
- package/src/kernel/runtime/graphpack/read.ts +4 -9
- package/src/kernel/runtime/graphpack/schemas.ts +74 -0
- package/src/kernel/runtime/graphpack/stories.ts +84 -0
- package/src/kernel/runtime/graphpack/types.ts +61 -48
- package/src/kernel/runtime/paths.ts +64 -15
- package/src/kernel/runtime/probe.test.ts +8 -4
- package/src/kernel/runtime/readEntity.ts +6 -5
- package/src/kernel/runtime/refs/gitOps.ts +1 -19
- package/src/kernel/runtime/refs/parseRef.ts +7 -7
- package/src/kernel/runtime/refs/resolve.ts +78 -62
- package/src/kernel/runtime/resolveSources.test.ts +63 -24
- package/src/kernel/runtime/resolveSources.ts +36 -25
- package/src/kernel/runtime/storeReadiness.ts +9 -8
- package/src/kernel/runtime/storeless.test.ts +1 -1
- package/src/kernel/runtime/wasmEmbed.test.ts +22 -19
- package/src/kernel/spec/emitReference.test.ts +3 -3
- package/src/kernel/spec/emitReference.ts +144 -11
- package/src/kernel/spec/emitSurface.ts +9 -5
- package/src/kernel/spec/surfaceConformance.test.ts +2 -2
- package/src/kernel/spec/surfaceConformance.ts +8 -0
- package/src/kernel/spec/types.ts +29 -9
- package/src/kernel/spec/validate.ts +2 -1
- package/src/kernel/vocabulary.test.ts +164 -0
- package/src/kernel/vocabulary.ts +146 -0
- package/src/testing/PARITY_GAPS.ts +8 -2
- package/src/testing/behavioral/README.md +3 -3
- package/src/testing/behavioral/completion.test.ts +19 -6
- package/src/testing/behavioral/errorMatrix.mcp.test.ts +4 -3
- package/src/testing/behavioral/errorMatrix.storeless.test.ts +1 -1
- package/src/testing/behavioral/exitCodes.e2e.test.ts +6 -5
- package/src/testing/behavioral/harness.foundation.test.ts +14 -5
- package/src/testing/behavioral/journeys.cli.test.ts +116 -75
- package/src/testing/behavioral/journeys.defaultPack.test.ts +82 -176
- package/src/testing/behavioral/journeys.firstInstall.test.ts +167 -0
- package/src/testing/behavioral/journeys.mcpLifecycle.mcp.test.ts +9 -6
- package/src/testing/behavioral/journeys.packageStories.test.ts +188 -0
- package/src/testing/behavioral/liveReadSurface.ts +4 -3
- package/src/testing/behavioral/mcpSurface.test.ts +9 -4
- package/src/testing/behavioral/staleCommands.test.ts +10 -0
- package/src/testing/eval/__snapshots__/eval.test.ts.snap +7 -7
- package/src/testing/eval/cases/assembly.ts +13 -6
- package/src/testing/eval/cases/effectful.ts +25 -13
- package/src/testing/eval/cases/readNouns.ts +22 -20
- package/src/testing/eval/cases/stable.ts +5 -1
- package/src/testing/eval/eval.test.ts +7 -1
- package/src/testing/fixtures/fixtureCapability.ts +45 -1
- package/src/testing/fixtures/graph/canonical.ts +6 -3
- package/src/testing/fixtures/graph/defaultPack.ts +6 -5
- package/src/testing/fixtures/graph/owlExport.ts +7 -5
- package/src/testing/helpers/fixtureGraph.ts +33 -16
- package/src/testing/helpers/packRuntime.ts +2 -3
- package/src/testing/helpers/projectCli.ts +2 -1
- package/src/testing/helpers/projectMcp.ts +6 -0
- package/src/testing/perf/budgets.test.ts +4 -0
- package/src/testing/perf/budgets.ts +22 -7
- package/src/testing/perf/globalSetup.ts +121 -6
- package/src/types.ts +2 -2
- package/src/capabilities/block/blockList.test.ts +0 -79
- package/src/capabilities/block/blockList.verb.ts +0 -163
- package/src/capabilities/block/index.ts +0 -25
- package/src/capabilities/block/pack.ts +0 -166
- package/src/capabilities/block/parity.test.ts +0 -187
- package/src/capabilities/block/tierChain.ts +0 -78
- package/src/capabilities/colophon/pragmaColophon.ts +0 -66
- package/src/capabilities/modifier/index.ts +0 -15
- package/src/capabilities/modifier/pack.ts +0 -64
- package/src/capabilities/standard/index.ts +0 -18
- package/src/capabilities/standard/pack.ts +0 -128
- package/src/capabilities/tier/index.ts +0 -19
- package/src/capabilities/tier/lookup.render.test.ts +0 -72
- package/src/capabilities/tier/lookup.render.ts +0 -59
- package/src/capabilities/tier/lookup.test.ts +0 -83
- package/src/capabilities/tier/lookup.verb.ts +0 -44
- package/src/capabilities/tier/pack.ts +0 -28
- package/src/capabilities/tier/runLookup.ts +0 -87
- package/src/capabilities/token/addConfig.render.ts +0 -27
- package/src/capabilities/token/addConfig.test.ts +0 -62
- package/src/capabilities/token/addConfig.verb.ts +0 -40
- package/src/capabilities/token/index.ts +0 -19
- package/src/capabilities/token/pack.ts +0 -58
- package/src/capabilities/token/runAddConfig.ts +0 -95
- package/src/kernel/completion/bashDrive.test.ts +0 -73
- package/src/kernel/runtime/graphpack/embedded/sample.ttl +0 -39
- package/src/kernel/runtime/lock.ts +0 -90
|
@@ -2,27 +2,26 @@
|
|
|
2
2
|
* Resolve a {@link PackageRef} to its pinned revision and RDF source contents.
|
|
3
3
|
*
|
|
4
4
|
* `file` reads the local path in place; `npm` resolves the installed package
|
|
5
|
-
* from the project's `node_modules`; `git` clones/fetches into the ref cache
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* from the project's `node_modules`; `git` clones/fetches into the ref cache.
|
|
6
|
+
* A ref that is already a commit SHA resolves to exactly that commit, which is
|
|
7
|
+
* how a project pins a revision. Each package contributes its `definitions/**`
|
|
8
|
+
* and `data/**` TTL files plus any `stories/*.json` it ships, labelled by a
|
|
9
|
+
* stable `pkg/relative-path` so the pack's content hash is machine-independent.
|
|
10
|
+
* Reached only from the `sources update` Task body.
|
|
10
11
|
*/
|
|
11
12
|
|
|
12
13
|
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
13
14
|
import { createRequire } from "node:module";
|
|
14
15
|
import { dirname, join, relative } from "node:path";
|
|
15
|
-
import { RECOVERY_CLI_PREFIX } from "../../../constants.js";
|
|
16
16
|
import { PragmaError } from "../../error/PragmaError.js";
|
|
17
|
-
import { cliRecovery } from "../../error/recovery.js";
|
|
18
17
|
import { refsCacheDir } from "../paths.js";
|
|
19
|
-
import {
|
|
18
|
+
import { cloneRef, fetchRef, headCommit } from "./gitOps.js";
|
|
20
19
|
import { type PackageRef, redactUrl } from "./parseRef.js";
|
|
21
20
|
|
|
22
21
|
/** A resolved package: its pinned revision and labelled RDF sources. */
|
|
23
22
|
export interface ResolvedPackage {
|
|
24
23
|
readonly name: string;
|
|
25
|
-
/** The config `
|
|
24
|
+
/** The config `packs` source ref, verbatim. */
|
|
26
25
|
readonly source: string;
|
|
27
26
|
/** The resolved commit / version / absolute path. */
|
|
28
27
|
readonly resolved: string;
|
|
@@ -34,19 +33,26 @@ export interface ResolvedPackage {
|
|
|
34
33
|
readonly root: string;
|
|
35
34
|
/** The labelled RDF sources (path label + content). */
|
|
36
35
|
readonly sources: { readonly path: string; readonly content: string }[];
|
|
36
|
+
/**
|
|
37
|
+
* The package's `stories/*.json` files, as RAW TEXT — never parsed here. The
|
|
38
|
+
* pack carries the package's bytes verbatim so every interpretation failure
|
|
39
|
+
* (malformed JSON and schema-invalid JSON alike) is caught behind one guard
|
|
40
|
+
* at dispatch instead of two half-guards at two layers.
|
|
41
|
+
*/
|
|
42
|
+
readonly stories: { readonly path: string; readonly content: string }[];
|
|
37
43
|
}
|
|
38
44
|
|
|
39
|
-
/** Options for a resolution
|
|
45
|
+
/** Options for a resolution — the project directory an `npm` ref resolves from. */
|
|
40
46
|
export interface ResolveOptions {
|
|
41
47
|
readonly cwd: string;
|
|
42
|
-
readonly frozen: boolean;
|
|
43
|
-
/** The lock's pinned revision for this package (used under `--frozen`). */
|
|
44
|
-
readonly pinned?: string;
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
/** The package subdirectories scanned for `.ttl` sources. */
|
|
48
51
|
const TTL_DIRS = ["definitions", "data"];
|
|
49
52
|
|
|
53
|
+
/** The package subdirectory whose immediate `*.json` children are read stories. */
|
|
54
|
+
const STORIES_DIR = "stories";
|
|
55
|
+
|
|
50
56
|
/** Sanitize a ref for use as a cache path segment. */
|
|
51
57
|
const sanitize = (value: string): string => value.replace(/[/\\:*?"<>|]/g, "_");
|
|
52
58
|
|
|
@@ -127,6 +133,47 @@ function readTtlSources(
|
|
|
127
133
|
return sources;
|
|
128
134
|
}
|
|
129
135
|
|
|
136
|
+
/**
|
|
137
|
+
* Read a package's `stories/*.json` as raw text, with stable labels.
|
|
138
|
+
*
|
|
139
|
+
* IMMEDIATE children only — the same discipline `skills/` uses, and recursion
|
|
140
|
+
* buys nothing. Hidden entries are skipped and a symlinked FILE is followed but
|
|
141
|
+
* a symlinked DIRECTORY is never recursed into, exactly as {@link walkTtl}
|
|
142
|
+
* argues. Sorted so the pack's content hash does not depend on readdir order.
|
|
143
|
+
*
|
|
144
|
+
* @param rootDir - The package root.
|
|
145
|
+
* @param label - The package name, used as the label prefix.
|
|
146
|
+
* @returns The labelled story files (`pkg/stories/name.json` + raw content).
|
|
147
|
+
* @note Impure — reads from disk.
|
|
148
|
+
*/
|
|
149
|
+
function readStorySources(
|
|
150
|
+
rootDir: string,
|
|
151
|
+
label: string,
|
|
152
|
+
): { path: string; content: string }[] {
|
|
153
|
+
const dir = join(rootDir, STORIES_DIR);
|
|
154
|
+
if (!existsSync(dir)) return [];
|
|
155
|
+
const stories: { path: string; content: string }[] = [];
|
|
156
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
157
|
+
if (entry.name.startsWith(".") || !entry.name.endsWith(".json")) continue;
|
|
158
|
+
const full = join(dir, entry.name);
|
|
159
|
+
let isFile = entry.isFile();
|
|
160
|
+
if (entry.isSymbolicLink()) {
|
|
161
|
+
try {
|
|
162
|
+
isFile = statSync(full).isFile();
|
|
163
|
+
} catch {
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
if (!isFile) continue;
|
|
168
|
+
stories.push({
|
|
169
|
+
path: `${label}/${STORIES_DIR}/${entry.name}`,
|
|
170
|
+
content: readFileSync(full, "utf-8"),
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
stories.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
174
|
+
return stories;
|
|
175
|
+
}
|
|
176
|
+
|
|
130
177
|
/**
|
|
131
178
|
* A Turtle/SPARQL prefix prologue declaration: `@prefix ex: <iri> .` or the
|
|
132
179
|
* keyword-form `PREFIX ex: <iri>`. Both are legal in Turtle 1.1; the keyword is
|
|
@@ -254,31 +301,15 @@ export function resolvePackageJson(
|
|
|
254
301
|
* Resolve a package reference to its revision and RDF sources.
|
|
255
302
|
*
|
|
256
303
|
* @param ref - The parsed package reference.
|
|
257
|
-
* @param options - The
|
|
304
|
+
* @param options - The project directory an `npm` ref resolves from.
|
|
258
305
|
* @returns The resolved package.
|
|
259
306
|
* @throws PragmaError on a missing file path or unresolvable npm package.
|
|
260
|
-
* @throws PragmaError under `--frozen` when the package has no lock entry.
|
|
261
307
|
* @note Impure — may clone/fetch git, reads TTL from disk.
|
|
262
308
|
*/
|
|
263
309
|
export async function resolvePackage(
|
|
264
310
|
ref: PackageRef,
|
|
265
311
|
options: ResolveOptions,
|
|
266
312
|
): Promise<ResolvedPackage> {
|
|
267
|
-
// `--frozen` means "reproduce the locked state exactly". A configured package
|
|
268
|
-
// with no lock entry has nothing to reproduce, so refuse rather than silently
|
|
269
|
-
// resolving it fresh (which would advance the very state the lock pins).
|
|
270
|
-
if (options.frozen && options.pinned === undefined) {
|
|
271
|
-
throw PragmaError.configError(
|
|
272
|
-
`Cannot resolve "${ref.pkg}" under --frozen: it has no entry in the lock.`,
|
|
273
|
-
{
|
|
274
|
-
recovery: cliRecovery(
|
|
275
|
-
`${RECOVERY_CLI_PREFIX}sources update`,
|
|
276
|
-
"Update the lock without --frozen, then commit it.",
|
|
277
|
-
),
|
|
278
|
-
},
|
|
279
|
-
);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
313
|
switch (ref.kind) {
|
|
283
314
|
case "file": {
|
|
284
315
|
if (!existsSync(ref.path)) {
|
|
@@ -292,6 +323,7 @@ export async function resolvePackage(
|
|
|
292
323
|
resolved: ref.path,
|
|
293
324
|
root: ref.path,
|
|
294
325
|
sources: readTtlSources(ref.path, ref.pkg),
|
|
326
|
+
stories: readStorySources(ref.path, ref.pkg),
|
|
295
327
|
};
|
|
296
328
|
}
|
|
297
329
|
|
|
@@ -322,22 +354,15 @@ export async function resolvePackage(
|
|
|
322
354
|
resolved: version,
|
|
323
355
|
root: dir,
|
|
324
356
|
sources: readTtlSources(dir, ref.pkg),
|
|
357
|
+
stories: readStorySources(dir, ref.pkg),
|
|
325
358
|
};
|
|
326
359
|
}
|
|
327
360
|
|
|
328
361
|
case "git": {
|
|
329
|
-
const
|
|
330
|
-
const dir = join(
|
|
331
|
-
refsCacheDir(),
|
|
332
|
-
sanitize(ref.pkg),
|
|
333
|
-
sanitize(useCommit ? (options.pinned as string) : ref.ref),
|
|
334
|
-
);
|
|
362
|
+
const dir = join(refsCacheDir(), sanitize(ref.pkg), sanitize(ref.ref));
|
|
335
363
|
let resolved: string;
|
|
336
364
|
try {
|
|
337
|
-
if (
|
|
338
|
-
checkoutCommit(ref.url, options.pinned as string, dir);
|
|
339
|
-
resolved = options.pinned as string;
|
|
340
|
-
} else if (existsSync(dir)) {
|
|
365
|
+
if (existsSync(dir)) {
|
|
341
366
|
resolved = fetchRef(ref.url, ref.ref, dir);
|
|
342
367
|
} else {
|
|
343
368
|
cloneRef(ref.url, ref.ref, dir);
|
|
@@ -345,28 +370,18 @@ export async function resolvePackage(
|
|
|
345
370
|
}
|
|
346
371
|
} catch (error) {
|
|
347
372
|
// A git clone/fetch/checkout failed — an unreachable remote, a moved or
|
|
348
|
-
// deleted ref, an auth/credential problem, or
|
|
349
|
-
//
|
|
350
|
-
//
|
|
351
|
-
throw
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
)
|
|
361
|
-
: PragmaError.configError(
|
|
362
|
-
`Cannot resolve "${ref.pkg}" from ${redactUrl(ref.url)}#${ref.ref}: ${errorDetail(error)}`,
|
|
363
|
-
{
|
|
364
|
-
recovery: {
|
|
365
|
-
message:
|
|
366
|
-
"Check the git URL and ref, your network, and your git credentials, then re-run the update.",
|
|
367
|
-
},
|
|
368
|
-
},
|
|
369
|
-
);
|
|
373
|
+
// deleted ref, an auth/credential problem, or a pinned SHA that has been
|
|
374
|
+
// force-pushed away. Name the package + ref with git's own reason so it
|
|
375
|
+
// reads as a fixable data error, not INTERNAL_ERROR.
|
|
376
|
+
throw PragmaError.configError(
|
|
377
|
+
`Cannot resolve "${ref.pkg}" from ${redactUrl(ref.url)}#${ref.ref}: ${errorDetail(error)}`,
|
|
378
|
+
{
|
|
379
|
+
recovery: {
|
|
380
|
+
message:
|
|
381
|
+
"Check the git URL and ref, your network, and your git credentials, then re-run the update.",
|
|
382
|
+
},
|
|
383
|
+
},
|
|
384
|
+
);
|
|
370
385
|
}
|
|
371
386
|
return {
|
|
372
387
|
name: ref.pkg,
|
|
@@ -374,6 +389,7 @@ export async function resolvePackage(
|
|
|
374
389
|
resolved,
|
|
375
390
|
root: dir,
|
|
376
391
|
sources: readTtlSources(dir, ref.pkg),
|
|
392
|
+
stories: readStorySources(dir, ref.pkg),
|
|
377
393
|
};
|
|
378
394
|
}
|
|
379
395
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { tmpdir } from "node:os";
|
|
3
|
-
import { join } from "node:path";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
4
|
import { afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
5
5
|
import type { ConfigLayers } from "../config/types.js";
|
|
6
6
|
import { loadStoreSession } from "./loadSession.js";
|
|
7
|
-
import {
|
|
8
|
-
import { packDir } from "./paths.js";
|
|
7
|
+
import { activePackPath, packDir } from "./paths.js";
|
|
9
8
|
import { resolveSources } from "./resolveSources.js";
|
|
10
9
|
|
|
11
10
|
/**
|
|
@@ -21,24 +20,21 @@ const tmp = (): string => {
|
|
|
21
20
|
return dir;
|
|
22
21
|
};
|
|
23
22
|
|
|
24
|
-
/** Config layers whose only relevant knob is the `
|
|
25
|
-
function layersWith(
|
|
23
|
+
/** Config layers whose only relevant knob is the `packs` origin. */
|
|
24
|
+
function layersWith(packsOrigin: "default" | "project"): ConfigLayers {
|
|
26
25
|
return {
|
|
27
26
|
config: {
|
|
28
27
|
channel: "normal",
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
? [{ name: "x", source: "file:///x" }]
|
|
32
|
-
: [],
|
|
28
|
+
packs:
|
|
29
|
+
packsOrigin === "project" ? [{ name: "x", source: "file:///x" }] : [],
|
|
33
30
|
},
|
|
34
31
|
origins: {
|
|
35
32
|
tier: "default",
|
|
36
33
|
channel: "default",
|
|
37
34
|
detail: "default",
|
|
38
|
-
|
|
35
|
+
packs: packsOrigin,
|
|
39
36
|
stories: "default",
|
|
40
37
|
prefixes: "default",
|
|
41
|
-
prompts: "default",
|
|
42
38
|
},
|
|
43
39
|
global: { path: "/nonexistent", exists: false },
|
|
44
40
|
project: { exists: false },
|
|
@@ -67,10 +63,18 @@ function writeCompletePack(hash: string): string {
|
|
|
67
63
|
writeFileSync(join(dir, "data.nq"), "<urn:s> <urn:p> <urn:o> .\n");
|
|
68
64
|
writeFileSync(join(dir, "schema.json"), "{}");
|
|
69
65
|
writeFileSync(join(dir, "index.json"), "{}");
|
|
66
|
+
writeFileSync(join(dir, "stories.json"), "[]");
|
|
70
67
|
writeManifest(dir, hash);
|
|
71
68
|
return dir;
|
|
72
69
|
}
|
|
73
70
|
|
|
71
|
+
/** Plant the active-pack pointer a `sources update` would have written. */
|
|
72
|
+
function writePointer(cwd: string, content: string): void {
|
|
73
|
+
const path = activePackPath(cwd);
|
|
74
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
75
|
+
writeFileSync(path, content);
|
|
76
|
+
}
|
|
77
|
+
|
|
74
78
|
beforeEach(() => {
|
|
75
79
|
roots = [];
|
|
76
80
|
});
|
|
@@ -79,11 +83,11 @@ afterEach(() => {
|
|
|
79
83
|
});
|
|
80
84
|
|
|
81
85
|
describe("resolveSources decision table", () => {
|
|
82
|
-
it("
|
|
86
|
+
it("pointer present + pack cached → load the built pack", () => {
|
|
83
87
|
const cwd = tmp();
|
|
84
88
|
const hash = "a".repeat(64);
|
|
85
89
|
const dir = writeCompletePack(hash);
|
|
86
|
-
|
|
90
|
+
writePointer(cwd, hash);
|
|
87
91
|
|
|
88
92
|
expect(resolveSources(layersWith("default"), cwd)).toEqual({
|
|
89
93
|
kind: "pack",
|
|
@@ -92,46 +96,81 @@ describe("resolveSources decision table", () => {
|
|
|
92
96
|
});
|
|
93
97
|
});
|
|
94
98
|
|
|
95
|
-
it("
|
|
99
|
+
it("pointer present + pack evicted → STORE_UNAVAILABLE", () => {
|
|
96
100
|
const cwd = tmp();
|
|
97
|
-
// A
|
|
98
|
-
|
|
101
|
+
// A pointer whose content-addressed pack is absent from the cache.
|
|
102
|
+
writePointer(cwd, "b".repeat(64));
|
|
99
103
|
|
|
100
104
|
expect(resolveSources(layersWith("default"), cwd)).toEqual({
|
|
101
105
|
kind: "unavailable",
|
|
102
|
-
reason: "the
|
|
106
|
+
reason: "the built pack is missing from the cache",
|
|
103
107
|
});
|
|
104
108
|
});
|
|
105
109
|
|
|
106
|
-
it("
|
|
110
|
+
it("pointer present + pack with a torn schema/index → STORE_UNAVAILABLE", () => {
|
|
107
111
|
const cwd = tmp();
|
|
108
112
|
const hash = "c".repeat(64);
|
|
109
113
|
// manifest + non-empty dump present, but the extracted schema/index are
|
|
110
114
|
// missing (a torn or partially-evicted pack). This used to slip through
|
|
111
115
|
// `packIsComplete` and then crash at read time as an INTERNAL error; it must
|
|
112
|
-
// now be treated as not-built so the boot surfaces STORE_UNAVAILABLE
|
|
116
|
+
// now be treated as not-built so the boot surfaces STORE_UNAVAILABLE — and
|
|
117
|
+
// say INCOMPLETE, not "missing", because the directory is right there. This
|
|
118
|
+
// is also the shape every pack built before `stories.json` now takes.
|
|
113
119
|
const dir = packDir(hash);
|
|
114
120
|
mkdirSync(dir, { recursive: true });
|
|
115
121
|
writeFileSync(join(dir, "data.nq"), "<urn:s> <urn:p> <urn:o> .\n");
|
|
116
122
|
writeManifest(dir, hash);
|
|
117
|
-
|
|
123
|
+
writePointer(cwd, hash);
|
|
124
|
+
|
|
125
|
+
expect(resolveSources(layersWith("default"), cwd)).toEqual({
|
|
126
|
+
kind: "unavailable",
|
|
127
|
+
reason: "the built pack is incomplete — an older or torn build",
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it("pointer present + a pack whose stories.json is not an array → STORE_UNAVAILABLE", () => {
|
|
132
|
+
const cwd = tmp();
|
|
133
|
+
const hash = "d".repeat(64);
|
|
134
|
+
const dir = writeCompletePack(hash);
|
|
135
|
+
// Every file present and non-empty, but `stories.json` holds an object.
|
|
136
|
+
// Gated on size alone this passed, so `buildPack` REUSED the directory and
|
|
137
|
+
// every package-declared noun disappeared while `sources update` reported
|
|
138
|
+
// success. It is a torn build like any other, and says so.
|
|
139
|
+
writeFileSync(join(dir, "stories.json"), '{"noun":"recipe"}');
|
|
140
|
+
writePointer(cwd, hash);
|
|
118
141
|
|
|
119
142
|
expect(resolveSources(layersWith("default"), cwd)).toEqual({
|
|
120
143
|
kind: "unavailable",
|
|
121
|
-
reason: "the
|
|
144
|
+
reason: "the built pack is incomplete — an older or torn build",
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it("a malformed pointer is treated as absent, not as a pack name", () => {
|
|
149
|
+
// A truncated/garbage pointer must never name a cache directory. With
|
|
150
|
+
// default packs it falls through to the embedded row, exactly as no
|
|
151
|
+
// pointer at all would.
|
|
152
|
+
const cwd = tmp();
|
|
153
|
+
writePointer(cwd, "not-a-content-hash\n");
|
|
154
|
+
|
|
155
|
+
expect(resolveSources(layersWith("default"), cwd)).toEqual({
|
|
156
|
+
kind: "embedded",
|
|
157
|
+
});
|
|
158
|
+
expect(resolveSources(layersWith("project"), cwd)).toEqual({
|
|
159
|
+
kind: "unavailable",
|
|
160
|
+
reason: "packs are configured but the store has not been built",
|
|
122
161
|
});
|
|
123
162
|
});
|
|
124
163
|
|
|
125
|
-
it("no
|
|
164
|
+
it("no pointer + default packs → embedded fallback", () => {
|
|
126
165
|
expect(resolveSources(layersWith("default"), tmp())).toEqual({
|
|
127
166
|
kind: "embedded",
|
|
128
167
|
});
|
|
129
168
|
});
|
|
130
169
|
|
|
131
|
-
it("no
|
|
170
|
+
it("no pointer + packs configured → STORE_UNAVAILABLE", () => {
|
|
132
171
|
expect(resolveSources(layersWith("project"), tmp())).toEqual({
|
|
133
172
|
kind: "unavailable",
|
|
134
|
-
reason: "
|
|
173
|
+
reason: "packs are configured but the store has not been built",
|
|
135
174
|
});
|
|
136
175
|
});
|
|
137
176
|
});
|
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The store-boot decision table — storeless, and the single place the boot
|
|
3
|
-
* strategy is decided.
|
|
3
|
+
* strategy is decided. No other module re-derives it: `sources status`, `info`,
|
|
4
|
+
* `doctor`, and the native MCP prompt/resource surfaces all switch on what this
|
|
5
|
+
* returns (`readPackIndex` takes the decision rather than resolving a pack of
|
|
6
|
+
* its own). The one module that cannot is the shell-completion fast path, which
|
|
7
|
+
* is denied the config evaluator and so implements the pointer half only — it
|
|
8
|
+
* says so, and it answers with completion candidates, never content.
|
|
4
9
|
*
|
|
5
|
-
* Boot never touches the network. From the
|
|
10
|
+
* Boot never touches the network. From the project's active-pack pointer (the
|
|
11
|
+
* content hash `sources update` last built here) and the resolved config:
|
|
6
12
|
*
|
|
7
|
-
* |
|
|
8
|
-
*
|
|
9
|
-
* | yes
|
|
10
|
-
* | yes
|
|
11
|
-
* | no
|
|
12
|
-
* | no
|
|
13
|
+
* | pointer | pack complete | packs origin | → decision |
|
|
14
|
+
* |---------|---------------|--------------|-----------------------|
|
|
15
|
+
* | yes | yes | — | load the built pack |
|
|
16
|
+
* | yes | no | — | STORE_UNAVAILABLE |
|
|
17
|
+
* | no | — | default | embedded fallback |
|
|
18
|
+
* | no | — | configured | STORE_UNAVAILABLE |
|
|
13
19
|
*
|
|
14
|
-
* A configured-but-unbuilt store (or a
|
|
20
|
+
* A configured-but-unbuilt store (or a pointer whose pack the cache lost)
|
|
15
21
|
* surfaces STORE_UNAVAILABLE with a single recovery: `pragma sources update`.
|
|
16
|
-
* "
|
|
17
|
-
* a fresh install — so the embedded
|
|
22
|
+
* "packs origin default" means the user has not pinned their own packs —
|
|
23
|
+
* a fresh install — so the embedded pack answers reads offline. A project that
|
|
24
|
+
* DID configure its own packs is never quietly served the distribution's graph.
|
|
18
25
|
*/
|
|
19
26
|
|
|
27
|
+
import { existsSync } from "node:fs";
|
|
20
28
|
import type { ConfigLayers } from "../config/types.js";
|
|
21
29
|
import { packIsComplete } from "./graphpack/manifest.js";
|
|
22
|
-
import {
|
|
23
|
-
import { packDir } from "./paths.js";
|
|
30
|
+
import { packDir, readActivePack } from "./paths.js";
|
|
24
31
|
|
|
25
32
|
/** The resolved boot strategy. */
|
|
26
33
|
export type SourcesDecision =
|
|
@@ -35,32 +42,36 @@ export type SourcesDecision =
|
|
|
35
42
|
/**
|
|
36
43
|
* Decide how (or whether) to boot the store — without any network or store I/O.
|
|
37
44
|
*
|
|
38
|
-
* @param layers - The resolved config layers (for the `
|
|
39
|
-
* @param cwd - The project directory (for the
|
|
45
|
+
* @param layers - The resolved config layers (for the `packs` origin).
|
|
46
|
+
* @param cwd - The project directory (for the active-pack pointer).
|
|
40
47
|
* @returns The boot decision.
|
|
41
|
-
* @note Impure — reads the
|
|
48
|
+
* @note Impure — reads the pointer and probes the pack cache.
|
|
42
49
|
*/
|
|
43
50
|
export function resolveSources(
|
|
44
51
|
layers: ConfigLayers,
|
|
45
52
|
cwd: string,
|
|
46
53
|
): SourcesDecision {
|
|
47
|
-
const
|
|
48
|
-
if (
|
|
49
|
-
const dir = packDir(
|
|
50
|
-
if (packIsComplete(dir)) {
|
|
51
|
-
|
|
52
|
-
|
|
54
|
+
const contentHash = readActivePack(cwd);
|
|
55
|
+
if (contentHash !== undefined) {
|
|
56
|
+
const dir = packDir(contentHash);
|
|
57
|
+
if (packIsComplete(dir)) return { kind: "pack", dir, contentHash };
|
|
58
|
+
// Two different things, and the recovery text is the only thing a user has
|
|
59
|
+
// to go on: the cache evicted the pack, or the directory is there but does
|
|
60
|
+
// not hold a whole pack — the state EVERY install upgraded past the
|
|
61
|
+
// four-file pack lands in, where "missing" is plainly contradicted by `ls`.
|
|
53
62
|
return {
|
|
54
63
|
kind: "unavailable",
|
|
55
|
-
reason:
|
|
64
|
+
reason: existsSync(dir)
|
|
65
|
+
? "the built pack is incomplete — an older or torn build"
|
|
66
|
+
: "the built pack is missing from the cache",
|
|
56
67
|
};
|
|
57
68
|
}
|
|
58
69
|
|
|
59
|
-
if (layers.origins.
|
|
70
|
+
if (layers.origins.packs === "default") {
|
|
60
71
|
return { kind: "embedded" };
|
|
61
72
|
}
|
|
62
73
|
return {
|
|
63
74
|
kind: "unavailable",
|
|
64
|
-
reason: "
|
|
75
|
+
reason: "packs are configured but the store has not been built",
|
|
65
76
|
};
|
|
66
77
|
}
|
|
@@ -12,12 +12,11 @@
|
|
|
12
12
|
* and one silently-empty list. Centralizing the construction here is what keeps
|
|
13
13
|
* those surfaces from drifting apart.
|
|
14
14
|
*
|
|
15
|
-
* It reaches only {@link resolveSources} (a
|
|
16
|
-
* ke), so a caller on the storeless fast path can pre-check availability
|
|
17
|
-
* ever booting the store.
|
|
15
|
+
* It reaches only {@link resolveSources} (a pointer + config probe — no store,
|
|
16
|
+
* no ke), so a caller on the storeless fast path can pre-check availability
|
|
17
|
+
* without ever booting the store.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { RECOVERY_CLI_PREFIX } from "../../constants.js";
|
|
21
20
|
import type { ConfigLayers } from "../config/types.js";
|
|
22
21
|
import { PragmaError } from "../error/PragmaError.js";
|
|
23
22
|
import { cliRecovery } from "../error/recovery.js";
|
|
@@ -28,14 +27,15 @@ import { resolveSources } from "./resolveSources.js";
|
|
|
28
27
|
* single `pragma sources update` recovery that also names the `sources_update`
|
|
29
28
|
* tool an agent calls (then retries — PR9's C1 cold-store retry succeeds).
|
|
30
29
|
*
|
|
31
|
-
* @param reason - The boot decision's reason (e.g. "the
|
|
30
|
+
* @param reason - The boot decision's reason (e.g. "the built pack is missing
|
|
31
|
+
* from the cache").
|
|
32
32
|
* @returns The structured STORE_UNAVAILABLE error.
|
|
33
33
|
*/
|
|
34
34
|
export function storeUnavailable(reason: string): PragmaError {
|
|
35
35
|
return PragmaError.storeUnavailable(`${reason}.`, {
|
|
36
36
|
recovery: cliRecovery(
|
|
37
|
-
|
|
38
|
-
"Build the local store from the configured
|
|
37
|
+
"sources update",
|
|
38
|
+
"Build the local store from the configured packs.",
|
|
39
39
|
{ tool: "sources_update" },
|
|
40
40
|
),
|
|
41
41
|
});
|
|
@@ -43,7 +43,8 @@ export function storeUnavailable(reason: string): PragmaError {
|
|
|
43
43
|
|
|
44
44
|
/**
|
|
45
45
|
* The STORE_UNAVAILABLE error to surface when the store cannot boot from the
|
|
46
|
-
* current config
|
|
46
|
+
* current config and active-pack pointer, or `undefined` when a store read may
|
|
47
|
+
* proceed. STORELESS —
|
|
47
48
|
* probes the decision table only, never constructs the store.
|
|
48
49
|
*
|
|
49
50
|
* @param layers - The resolved config layers.
|
|
@@ -58,7 +58,7 @@ describe("storeless guarantee — the store never boots for storeless verbs (PRO
|
|
|
58
58
|
expect(runtime.store.booted).toBe(false);
|
|
59
59
|
});
|
|
60
60
|
|
|
61
|
-
it("sources status does not construct the store
|
|
61
|
+
it("sources status does not construct the store", async () => {
|
|
62
62
|
const runtime = bootRuntime(FLAGS, freshCwd());
|
|
63
63
|
const outcome = await executeVerb(sourcesStatusVerb, {}, NO_MUT, runtime);
|
|
64
64
|
expect(outcome.exitCode).toBe(0);
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
import { spawnSync } from "node:child_process";
|
|
2
|
-
import {
|
|
3
|
-
existsSync,
|
|
4
|
-
mkdirSync,
|
|
5
|
-
mkdtempSync,
|
|
6
|
-
rmSync,
|
|
7
|
-
writeFileSync,
|
|
8
|
-
} from "node:fs";
|
|
2
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
9
3
|
import { tmpdir } from "node:os";
|
|
10
4
|
import { join } from "node:path";
|
|
11
5
|
import { fileURLToPath } from "node:url";
|
|
12
6
|
import { afterAll, beforeAll, describe, expect, it } from "vitest";
|
|
7
|
+
import { embeddedManifest } from "./graphpack/embedded.js";
|
|
13
8
|
|
|
14
9
|
/**
|
|
15
10
|
* The store-boot path only fully lives in the standalone binary: this is the
|
|
@@ -74,8 +69,11 @@ describe("oxigraph WASM + embedded pack embed in the compiled binary (PROTECTED)
|
|
|
74
69
|
triples: string;
|
|
75
70
|
};
|
|
76
71
|
expect(out.ok).toBe(true);
|
|
77
|
-
|
|
78
|
-
|
|
72
|
+
// The compiled binary is the only place this is worth asserting: the store
|
|
73
|
+
// it booted from the inlined `data.nq` must hold exactly what the committed
|
|
74
|
+
// `manifest.json` claims was built into it.
|
|
75
|
+
expect(Number(out.triples)).toBe(embeddedManifest().tripleCount);
|
|
76
|
+
expect(out.entities).toBeGreaterThan(0);
|
|
79
77
|
});
|
|
80
78
|
|
|
81
79
|
it("dist binary runs storeless sources status", () => {
|
|
@@ -83,18 +81,17 @@ describe("oxigraph WASM + embedded pack embed in the compiled binary (PROTECTED)
|
|
|
83
81
|
expect(run.status, run.stderr).toBe(0);
|
|
84
82
|
const envelope = JSON.parse(run.stdout.trim()) as {
|
|
85
83
|
ok: boolean;
|
|
86
|
-
data: {
|
|
84
|
+
data: { store: string };
|
|
87
85
|
};
|
|
88
86
|
expect(envelope.ok).toBe(true);
|
|
89
|
-
// A fresh install:
|
|
90
|
-
expect(envelope.data.
|
|
91
|
-
expect(envelope.data.cached).toBe(false);
|
|
87
|
+
// A fresh install: nothing built here, so the embedded pack answers reads.
|
|
88
|
+
expect(envelope.data.store).toBe("embedded");
|
|
92
89
|
});
|
|
93
90
|
|
|
94
91
|
// Regression guard: `sources update` walks a package's TTL directories. The
|
|
95
92
|
// compiled binary's node:fs globSync mishandles `**` (returns bogus paths),
|
|
96
93
|
// which the in-process suite could not catch — so exercise the real binary.
|
|
97
|
-
it("dist binary runs sources update end-to-end (build +
|
|
94
|
+
it("dist binary runs sources update end-to-end (build + point + status)", () => {
|
|
98
95
|
const pkg = join(workdir, "pkg");
|
|
99
96
|
const proj = join(workdir, "proj");
|
|
100
97
|
mkdirSync(join(pkg, "definitions"), { recursive: true });
|
|
@@ -110,7 +107,7 @@ ex:one a ex:Widget ; rdfs:label "One" .
|
|
|
110
107
|
);
|
|
111
108
|
writeFileSync(
|
|
112
109
|
join(proj, "pragma.config.ts"),
|
|
113
|
-
`export default {
|
|
110
|
+
`export default { packs: [{ name: "pkg-a", source: "file://${pkg}" }] };\n`,
|
|
114
111
|
);
|
|
115
112
|
|
|
116
113
|
const env = {
|
|
@@ -129,14 +126,20 @@ ex:one a ex:Widget ; rdfs:label "One" .
|
|
|
129
126
|
|
|
130
127
|
const update = inProj(["sources", "update", "--yes", "--format", "json"]);
|
|
131
128
|
expect(update.status, update.stderr).toBe(0);
|
|
132
|
-
|
|
129
|
+
const built = (
|
|
130
|
+
JSON.parse(update.stdout.trim()) as {
|
|
131
|
+
data: { contentHash: string };
|
|
132
|
+
}
|
|
133
|
+
).data.contentHash;
|
|
134
|
+
expect(built).toMatch(/^[0-9a-f]{64}$/);
|
|
133
135
|
|
|
134
136
|
const status = inProj(["sources", "status", "--format", "json"]);
|
|
135
137
|
const envelope = JSON.parse(status.stdout.trim()) as {
|
|
136
|
-
data: {
|
|
138
|
+
data: { store: string; contentHash: string; entityCount: number };
|
|
137
139
|
};
|
|
138
|
-
|
|
139
|
-
expect(envelope.data.
|
|
140
|
+
// The project now reads its OWN pack — the one the update just built.
|
|
141
|
+
expect(envelope.data.store).toBe("built");
|
|
142
|
+
expect(envelope.data.contentHash).toBe(built);
|
|
140
143
|
// Distinct abox subjects: the one individual (ex:one). The ex:Widget class
|
|
141
144
|
// is tbox schema, not an entity — the raw entity count would double this (A1).
|
|
142
145
|
expect(envelope.data.entityCount).toBe(1);
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
import { ERROR_CODES } from "../error/constants.js";
|
|
7
7
|
import { emitReference } from "./emitReference.js";
|
|
8
8
|
|
|
9
|
-
/** The
|
|
10
|
-
const PAGES = ["index.md", "commands.md", "tools.md", "errors.md"];
|
|
9
|
+
/** The five pages every reference doc set carries. */
|
|
10
|
+
const PAGES = ["index.md", "commands.md", "tools.md", "errors.md", "config.md"];
|
|
11
11
|
|
|
12
12
|
describe("emitReference", () => {
|
|
13
13
|
const docs = emitReference([fixtureReferenceModule]);
|
|
@@ -16,7 +16,7 @@ describe("emitReference", () => {
|
|
|
16
16
|
const tools = docs.get("tools.md") ?? "";
|
|
17
17
|
const errors = docs.get("errors.md") ?? "";
|
|
18
18
|
|
|
19
|
-
it("emits exactly the
|
|
19
|
+
it("emits exactly the five reference pages", () => {
|
|
20
20
|
expect([...docs.keys()].sort()).toEqual([...PAGES].sort());
|
|
21
21
|
});
|
|
22
22
|
|