@skill-map/cli 0.7.0 → 0.9.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.
@@ -0,0 +1,27 @@
1
+ # Default `.skill-mapignore` shipped by `sm init`. Anything matching is
2
+ # skipped during `sm scan`. Same syntax as `.gitignore` (kaelzhang/ignore).
3
+ # Edit freely after `sm init` — the file is owned by the user from then on.
4
+
5
+ # Version-control + dependency dirs
6
+ .git/
7
+ node_modules/
8
+
9
+ # Build output
10
+ dist/
11
+ build/
12
+ out/
13
+ .next/
14
+ .cache/
15
+
16
+ # Project-local transient artifacts
17
+ .tmp/
18
+ .skill-map/
19
+
20
+ # OS / editor noise
21
+ .DS_Store
22
+ Thumbs.db
23
+ *.swp
24
+ *~
25
+
26
+ # Logs
27
+ *.log
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Contract runner — executes the conformance cases shipped with
3
+ * `@skill-map/spec` against an installed binary and emits a pass/fail result
4
+ * per case.
5
+ *
6
+ * Implements the six assertion types from `spec/schemas/conformance-case.schema.json`.
7
+ * Provisions a clean tmp scope per case, optionally pre-populated with the
8
+ * referenced fixture corpus.
9
+ *
10
+ * Step 0b scope: single-case dispatch. Suite-level runner + reporter land
11
+ * alongside Step 2 extensions.
12
+ */
13
+ type IAssertionResult = {
14
+ ok: true;
15
+ type: string;
16
+ } | {
17
+ ok: false;
18
+ type: string;
19
+ reason: string;
20
+ };
21
+ interface IRunCaseResult {
22
+ caseId: string;
23
+ passed: boolean;
24
+ exitCode: number;
25
+ stdout: string;
26
+ stderr: string;
27
+ assertions: IAssertionResult[];
28
+ }
29
+ interface IRunCaseOptions {
30
+ /** Absolute path to the binary wrapper (e.g. `bin/sm.js`). */
31
+ binary: string;
32
+ /** Absolute path to the `@skill-map/spec` root. */
33
+ specRoot: string;
34
+ /** Absolute path to the case JSON under `<conformance-root>/cases/`. */
35
+ casePath: string;
36
+ /**
37
+ * Absolute path to the `<conformance-root>/fixtures/` directory backing
38
+ * this case (or the parent conformance suite).
39
+ *
40
+ * Phase 5 / A.13 introduced per-Provider conformance directories that
41
+ * live outside the spec tree (Claude-specific cases moved to
42
+ * `src/extensions/providers/claude/conformance/`). Cases reference
43
+ * fixtures by directory name; the runner resolves them under
44
+ * `fixturesRoot` so the spec-agnostic kernel-empty-boot case and the
45
+ * Claude `basic-scan` / `rename-high` / `orphan-detection` cases can
46
+ * coexist without colliding fixture namespaces. Defaults to
47
+ * `<specRoot>/conformance/fixtures` for the legacy spec layout.
48
+ */
49
+ fixturesRoot?: string;
50
+ /** Extra env vars passed to the child. */
51
+ env?: NodeJS.ProcessEnv;
52
+ }
53
+ type IAssertion = {
54
+ type: 'exit-code';
55
+ value: number;
56
+ } | {
57
+ type: 'json-path';
58
+ path: string;
59
+ equals?: unknown;
60
+ greaterThan?: number;
61
+ lessThan?: number;
62
+ matches?: string;
63
+ } | {
64
+ type: 'file-exists';
65
+ path: string;
66
+ } | {
67
+ type: 'file-contains-verbatim';
68
+ path: string;
69
+ fixture: string;
70
+ } | {
71
+ type: 'file-matches-schema';
72
+ path: string;
73
+ schema: string;
74
+ } | {
75
+ type: 'stderr-matches';
76
+ pattern: string;
77
+ };
78
+ declare function runConformanceCase(options: IRunCaseOptions): IRunCaseResult;
79
+ /** Verifies the spec root looks sane (contains `index.json`). */
80
+ declare function assertSpecRoot(specRoot: string): void;
81
+
82
+ export { type IAssertion, type IAssertionResult, type IRunCaseOptions, type IRunCaseResult, assertSpecRoot, runConformanceCase };
@@ -0,0 +1,357 @@
1
+ // conformance/index.ts
2
+ import { spawnSync } from "child_process";
3
+ import { cpSync, existsSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync } from "fs";
4
+ import { tmpdir } from "os";
5
+ import { isAbsolute, join, relative, resolve } from "path";
6
+
7
+ // kernel/util/tx.ts
8
+ var TOKEN_RE = /\{\{\s*([A-Za-z][A-Za-z0-9_]*)\s*\}\}/g;
9
+ function tx(template, vars = {}) {
10
+ return template.replace(TOKEN_RE, (_match, name) => {
11
+ if (!Object.prototype.hasOwnProperty.call(vars, name)) {
12
+ throw new Error(
13
+ `tx: missing variable "${name}" for template "${template.slice(0, 80)}${template.length > 80 ? "\u2026" : ""}"`
14
+ );
15
+ }
16
+ const value = vars[name];
17
+ if (value === null || value === void 0) {
18
+ throw new Error(
19
+ `tx: variable "${name}" is null/undefined for template "${template.slice(0, 80)}${template.length > 80 ? "\u2026" : ""}"`
20
+ );
21
+ }
22
+ return String(value);
23
+ });
24
+ }
25
+
26
+ // conformance/i18n/runner.texts.ts
27
+ var CONFORMANCE_RUNNER_TEXTS = {
28
+ priorScanFailed: "setup.priorScans step `{{fixture}}` failed with exit {{exit}}: {{stderr}}",
29
+ pathMustBeRelative: 'conformance: {{label}} path "{{path}}" must be relative to its anchor ({{anchor}})',
30
+ pathEscapesAnchor: 'conformance: {{label}} path "{{path}}" escapes its anchor ({{anchor}})',
31
+ expectedExitCode: "expected exit {{expected}}, got {{actual}}",
32
+ fileNotFound: "file not found: {{path}}",
33
+ targetNotFound: "target not found: {{path}}",
34
+ targetMissingFixture: "target does not contain fixture {{fixture}} verbatim",
35
+ fileMatchesSchemaUnimplemented: "file-matches-schema not yet implemented (requires ajv; lands with Step 2)",
36
+ stderrDidNotMatch: "stderr did not match /{{pattern}}/",
37
+ stdoutNotJson: "stdout is not valid JSON: {{message}}",
38
+ unsupportedJsonPath: "unsupported jsonpath: {{path}}",
39
+ expectedArrayAtPath: "expected array at {{path}}",
40
+ cannotTraverseSegment: "cannot traverse {{type}} at segment '{{segment}}'",
41
+ jsonPathEqualsMismatch: "{{path}} = {{actual}}, expected {{expected}}",
42
+ jsonPathNotGreaterThan: "{{path}} not > {{value}}",
43
+ jsonPathNotLessThan: "{{path}} not < {{value}}",
44
+ jsonPathDidNotMatch: "{{path}} did not match /{{pattern}}/",
45
+ jsonPathNoComparator: "no comparator on json-path assertion",
46
+ specRootMissingIndex: "spec root missing index.json at {{specRoot}}"
47
+ };
48
+
49
+ // conformance/index.ts
50
+ function disableEnv(setup) {
51
+ const env = {};
52
+ if (setup?.disableAllProviders) env["SKILL_MAP_DISABLE_ALL_PROVIDERS"] = "1";
53
+ if (setup?.disableAllExtractors) env["SKILL_MAP_DISABLE_ALL_EXTRACTORS"] = "1";
54
+ if (setup?.disableAllRules) env["SKILL_MAP_DISABLE_ALL_RULES"] = "1";
55
+ return env;
56
+ }
57
+ function runConformanceCase(options) {
58
+ const raw = readFileSync(options.casePath, "utf8");
59
+ const c = JSON.parse(raw);
60
+ const fixturesRoot = options.fixturesRoot ?? join(options.specRoot, "conformance", "fixtures");
61
+ const safeId = c.id.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 32);
62
+ const scope = mkdtempSync(join(tmpdir(), `sm-conformance-${safeId}-`));
63
+ const setupEnv = disableEnv(c.setup);
64
+ try {
65
+ const priorFailure = runPriorScansSetup(c, options, scope, fixturesRoot, setupEnv);
66
+ if (priorFailure) return priorFailure;
67
+ if (c.fixture) {
68
+ replaceFixture(scope, fixturesRoot, c.fixture);
69
+ }
70
+ const argv = [c.invoke.verb];
71
+ if (c.invoke.sub) argv.push(c.invoke.sub);
72
+ if (c.invoke.args) argv.push(...c.invoke.args);
73
+ if (c.invoke.flags) argv.push(...c.invoke.flags);
74
+ const child = spawnSync(process.execPath, [options.binary, ...argv], {
75
+ cwd: scope,
76
+ env: { ...process.env, ...options.env, ...setupEnv },
77
+ encoding: "utf8"
78
+ });
79
+ const stdout = child.stdout ?? "";
80
+ const stderr = child.stderr ?? "";
81
+ const exitCode = child.status ?? 0;
82
+ const assertions = c.assertions.map(
83
+ (a) => evaluateAssertion(a, {
84
+ exitCode,
85
+ stdout,
86
+ stderr,
87
+ scope,
88
+ specRoot: options.specRoot,
89
+ fixturesRoot
90
+ })
91
+ );
92
+ const passed = assertions.every((a) => a.ok);
93
+ return { caseId: c.id, passed, exitCode, stdout, stderr, assertions };
94
+ } finally {
95
+ rmSync(scope, { recursive: true, force: true });
96
+ }
97
+ }
98
+ function runPriorScansSetup(c, options, scope, fixturesRoot, setupEnv) {
99
+ for (const step of c.setup?.priorScans ?? []) {
100
+ replaceFixture(scope, fixturesRoot, step.fixture);
101
+ const stepArgv = ["scan", ...step.flags ?? []];
102
+ const stepChild = spawnSync(process.execPath, [options.binary, ...stepArgv], {
103
+ cwd: scope,
104
+ env: { ...process.env, ...options.env, ...setupEnv },
105
+ encoding: "utf8"
106
+ });
107
+ if ((stepChild.status ?? 0) !== 0) {
108
+ return {
109
+ caseId: c.id,
110
+ passed: false,
111
+ exitCode: stepChild.status ?? 0,
112
+ stdout: stepChild.stdout ?? "",
113
+ stderr: stepChild.stderr ?? "",
114
+ assertions: [
115
+ {
116
+ ok: false,
117
+ type: "priorScan",
118
+ reason: tx(CONFORMANCE_RUNNER_TEXTS.priorScanFailed, {
119
+ fixture: step.fixture,
120
+ exit: stepChild.status ?? 0,
121
+ stderr: stepChild.stderr ?? ""
122
+ })
123
+ }
124
+ ]
125
+ };
126
+ }
127
+ }
128
+ return null;
129
+ }
130
+ function replaceFixture(scope, fixturesRoot, fixture) {
131
+ assertContained(fixturesRoot, fixture, "fixture");
132
+ for (const entry of readdirSync(scope)) {
133
+ if (entry === ".skill-map") continue;
134
+ rmSync(join(scope, entry), { recursive: true, force: true });
135
+ }
136
+ const src = join(fixturesRoot, fixture);
137
+ cpSync(src, scope, { recursive: true });
138
+ }
139
+ function assertContained(root, rel, label) {
140
+ if (isAbsolute(rel)) {
141
+ throw new Error(
142
+ tx(CONFORMANCE_RUNNER_TEXTS.pathMustBeRelative, { label, path: rel, anchor: root })
143
+ );
144
+ }
145
+ const abs = resolve(root, rel);
146
+ const r = relative(root, abs);
147
+ if (r.startsWith("..") || isAbsolute(r)) {
148
+ throw new Error(
149
+ tx(CONFORMANCE_RUNNER_TEXTS.pathEscapesAnchor, { label, path: rel, anchor: root })
150
+ );
151
+ }
152
+ }
153
+ function evaluateAssertion(a, ctx) {
154
+ switch (a.type) {
155
+ case "exit-code":
156
+ return ctx.exitCode === a.value ? { ok: true, type: a.type } : {
157
+ ok: false,
158
+ type: a.type,
159
+ reason: tx(CONFORMANCE_RUNNER_TEXTS.expectedExitCode, {
160
+ expected: a.value,
161
+ actual: ctx.exitCode
162
+ })
163
+ };
164
+ case "json-path":
165
+ return evaluateJsonPath(a, ctx);
166
+ case "file-exists": {
167
+ try {
168
+ assertContained(ctx.scope, a.path, "file-exists");
169
+ } catch (err) {
170
+ return { ok: false, type: a.type, reason: err.message };
171
+ }
172
+ const abs = resolve(ctx.scope, a.path);
173
+ return existsSync(abs) ? { ok: true, type: a.type } : {
174
+ ok: false,
175
+ type: a.type,
176
+ reason: tx(CONFORMANCE_RUNNER_TEXTS.fileNotFound, { path: a.path })
177
+ };
178
+ }
179
+ case "file-contains-verbatim": {
180
+ try {
181
+ assertContained(ctx.fixturesRoot, a.fixture, "file-contains-verbatim/fixture");
182
+ assertContained(ctx.scope, a.path, "file-contains-verbatim/path");
183
+ } catch (err) {
184
+ return { ok: false, type: a.type, reason: err.message };
185
+ }
186
+ const fixturePath = join(ctx.fixturesRoot, a.fixture);
187
+ const targetPath = resolve(ctx.scope, a.path);
188
+ if (!existsSync(targetPath)) {
189
+ return {
190
+ ok: false,
191
+ type: a.type,
192
+ reason: tx(CONFORMANCE_RUNNER_TEXTS.targetNotFound, { path: a.path })
193
+ };
194
+ }
195
+ const needle = readFileSync(fixturePath);
196
+ const haystack = readFileSync(targetPath);
197
+ return haystack.includes(needle) ? { ok: true, type: a.type } : {
198
+ ok: false,
199
+ type: a.type,
200
+ reason: tx(CONFORMANCE_RUNNER_TEXTS.targetMissingFixture, { fixture: a.fixture })
201
+ };
202
+ }
203
+ case "file-matches-schema":
204
+ return {
205
+ ok: false,
206
+ type: a.type,
207
+ reason: CONFORMANCE_RUNNER_TEXTS.fileMatchesSchemaUnimplemented
208
+ };
209
+ case "stderr-matches": {
210
+ const re = new RegExp(a.pattern);
211
+ return re.test(ctx.stderr) ? { ok: true, type: a.type } : {
212
+ ok: false,
213
+ type: a.type,
214
+ reason: tx(CONFORMANCE_RUNNER_TEXTS.stderrDidNotMatch, { pattern: a.pattern })
215
+ };
216
+ }
217
+ }
218
+ }
219
+ function evaluateJsonPath(a, ctx) {
220
+ let doc;
221
+ try {
222
+ doc = JSON.parse(ctx.stdout);
223
+ } catch (err) {
224
+ return {
225
+ ok: false,
226
+ type: a.type,
227
+ reason: tx(CONFORMANCE_RUNNER_TEXTS.stdoutNotJson, { message: err.message })
228
+ };
229
+ }
230
+ const segments = parsePath(a.path);
231
+ if (!segments) {
232
+ return {
233
+ ok: false,
234
+ type: a.type,
235
+ reason: tx(CONFORMANCE_RUNNER_TEXTS.unsupportedJsonPath, { path: a.path })
236
+ };
237
+ }
238
+ const walked = traverseJsonPath(doc, segments, a.path);
239
+ if (!walked.ok) return { ok: false, type: a.type, reason: walked.reason };
240
+ return applyJsonPathComparator(a, walked.value);
241
+ }
242
+ function traverseJsonPath(doc, segments, path) {
243
+ let current = doc;
244
+ for (const seg of segments) {
245
+ if (typeof seg === "number") {
246
+ if (!Array.isArray(current)) {
247
+ return { ok: false, reason: tx(CONFORMANCE_RUNNER_TEXTS.expectedArrayAtPath, { path }) };
248
+ }
249
+ current = current[seg];
250
+ } else if (seg === "length" && Array.isArray(current)) {
251
+ current = current.length;
252
+ } else if (typeof current === "object" && current !== null) {
253
+ current = current[seg];
254
+ } else {
255
+ return {
256
+ ok: false,
257
+ reason: tx(CONFORMANCE_RUNNER_TEXTS.cannotTraverseSegment, {
258
+ type: typeof current,
259
+ segment: String(seg)
260
+ })
261
+ };
262
+ }
263
+ }
264
+ return { ok: true, value: current };
265
+ }
266
+ function applyJsonPathComparator(a, current) {
267
+ if ("equals" in a && a.equals !== void 0) {
268
+ return deepEqual(current, a.equals) ? { ok: true, type: a.type } : {
269
+ ok: false,
270
+ type: a.type,
271
+ reason: tx(CONFORMANCE_RUNNER_TEXTS.jsonPathEqualsMismatch, {
272
+ path: a.path,
273
+ actual: JSON.stringify(current),
274
+ expected: JSON.stringify(a.equals)
275
+ })
276
+ };
277
+ }
278
+ if ("greaterThan" in a && typeof a.greaterThan === "number") {
279
+ return typeof current === "number" && current > a.greaterThan ? { ok: true, type: a.type } : {
280
+ ok: false,
281
+ type: a.type,
282
+ reason: tx(CONFORMANCE_RUNNER_TEXTS.jsonPathNotGreaterThan, {
283
+ path: a.path,
284
+ value: a.greaterThan
285
+ })
286
+ };
287
+ }
288
+ if ("lessThan" in a && typeof a.lessThan === "number") {
289
+ return typeof current === "number" && current < a.lessThan ? { ok: true, type: a.type } : {
290
+ ok: false,
291
+ type: a.type,
292
+ reason: tx(CONFORMANCE_RUNNER_TEXTS.jsonPathNotLessThan, {
293
+ path: a.path,
294
+ value: a.lessThan
295
+ })
296
+ };
297
+ }
298
+ if ("matches" in a && typeof a.matches === "string") {
299
+ const re = new RegExp(a.matches);
300
+ return typeof current === "string" && re.test(current) ? { ok: true, type: a.type } : {
301
+ ok: false,
302
+ type: a.type,
303
+ reason: tx(CONFORMANCE_RUNNER_TEXTS.jsonPathDidNotMatch, {
304
+ path: a.path,
305
+ pattern: a.matches
306
+ })
307
+ };
308
+ }
309
+ return { ok: false, type: a.type, reason: CONFORMANCE_RUNNER_TEXTS.jsonPathNoComparator };
310
+ }
311
+ function parsePath(path) {
312
+ if (!path.startsWith("$")) return null;
313
+ const tail = path.slice(1);
314
+ const segments = [];
315
+ const re = /\.([a-zA-Z_][a-zA-Z0-9_-]*)|\[(\d+)\]/g;
316
+ let lastIndex = 0;
317
+ let match;
318
+ while ((match = re.exec(tail)) !== null) {
319
+ if (match.index !== lastIndex) return null;
320
+ if (match[1] !== void 0) segments.push(match[1]);
321
+ else if (match[2] !== void 0) segments.push(Number.parseInt(match[2], 10));
322
+ lastIndex = re.lastIndex;
323
+ }
324
+ if (lastIndex !== tail.length) return null;
325
+ return segments;
326
+ }
327
+ function deepEqual(a, b) {
328
+ if (a === b) return true;
329
+ if (typeof a !== typeof b) return false;
330
+ if (a && b && typeof a === "object" && typeof b === "object") {
331
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
332
+ const ak = Object.keys(a);
333
+ const bk = Object.keys(b);
334
+ if (ak.length !== bk.length) return false;
335
+ for (const k of ak) {
336
+ if (!deepEqual(
337
+ a[k],
338
+ b[k]
339
+ )) {
340
+ return false;
341
+ }
342
+ }
343
+ return true;
344
+ }
345
+ return false;
346
+ }
347
+ function assertSpecRoot(specRoot) {
348
+ const indexPath = join(specRoot, "index.json");
349
+ if (!existsSync(indexPath) || !statSync(indexPath).isFile()) {
350
+ throw new Error(tx(CONFORMANCE_RUNNER_TEXTS.specRootMissingIndex, { specRoot }));
351
+ }
352
+ }
353
+ export {
354
+ assertSpecRoot,
355
+ runConformanceCase
356
+ };
357
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../conformance/index.ts","../../kernel/util/tx.ts","../../conformance/i18n/runner.texts.ts"],"sourcesContent":["/**\n * Contract runner — executes the conformance cases shipped with\n * `@skill-map/spec` against an installed binary and emits a pass/fail result\n * per case.\n *\n * Implements the six assertion types from `spec/schemas/conformance-case.schema.json`.\n * Provisions a clean tmp scope per case, optionally pre-populated with the\n * referenced fixture corpus.\n *\n * Step 0b scope: single-case dispatch. Suite-level runner + reporter land\n * alongside Step 2 extensions.\n */\n\nimport { spawnSync } from 'node:child_process';\nimport { cpSync, existsSync, mkdtempSync, readdirSync, readFileSync, rmSync, statSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { isAbsolute, join, relative, resolve } from 'node:path';\n\nimport { tx } from '../kernel/util/tx.js';\nimport { CONFORMANCE_RUNNER_TEXTS } from './i18n/runner.texts.js';\n\nexport type IAssertionResult =\n | { ok: true; type: string }\n | { ok: false; type: string; reason: string };\n\nexport interface IRunCaseResult {\n caseId: string;\n passed: boolean;\n exitCode: number;\n stdout: string;\n stderr: string;\n assertions: IAssertionResult[];\n}\n\nexport interface IRunCaseOptions {\n /** Absolute path to the binary wrapper (e.g. `bin/sm.js`). */\n binary: string;\n /** Absolute path to the `@skill-map/spec` root. */\n specRoot: string;\n /** Absolute path to the case JSON under `<conformance-root>/cases/`. */\n casePath: string;\n /**\n * Absolute path to the `<conformance-root>/fixtures/` directory backing\n * this case (or the parent conformance suite).\n *\n * Phase 5 / A.13 introduced per-Provider conformance directories that\n * live outside the spec tree (Claude-specific cases moved to\n * `src/extensions/providers/claude/conformance/`). Cases reference\n * fixtures by directory name; the runner resolves them under\n * `fixturesRoot` so the spec-agnostic kernel-empty-boot case and the\n * Claude `basic-scan` / `rename-high` / `orphan-detection` cases can\n * coexist without colliding fixture namespaces. Defaults to\n * `<specRoot>/conformance/fixtures` for the legacy spec layout.\n */\n fixturesRoot?: string;\n /** Extra env vars passed to the child. */\n env?: NodeJS.ProcessEnv;\n}\n\ninterface IConformanceCase {\n id: string;\n description: string;\n fixture?: string;\n setup?: {\n disableAllProviders?: boolean;\n disableAllExtractors?: boolean;\n disableAllRules?: boolean;\n priorScans?: Array<{ fixture: string; flags?: string[] }>;\n };\n invoke: {\n verb: string;\n sub?: string;\n args?: string[];\n flags?: string[];\n };\n assertions: IAssertion[];\n}\n\n/**\n * Build the env-var bag a case's `setup.disableAll*` toggles inject into\n * every child invocation (priorScans + the main `invoke`). The CLI's scan\n * composer (`composeScanExtensions`) reads these vars and drops every\n * extension of the matching kind from the in-scan pipeline.\n */\nfunction disableEnv(setup: IConformanceCase['setup']): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = {};\n if (setup?.disableAllProviders) env['SKILL_MAP_DISABLE_ALL_PROVIDERS'] = '1';\n if (setup?.disableAllExtractors) env['SKILL_MAP_DISABLE_ALL_EXTRACTORS'] = '1';\n if (setup?.disableAllRules) env['SKILL_MAP_DISABLE_ALL_RULES'] = '1';\n return env;\n}\n\nexport type IAssertion =\n | { type: 'exit-code'; value: number }\n | {\n type: 'json-path';\n path: string;\n equals?: unknown;\n greaterThan?: number;\n lessThan?: number;\n matches?: string;\n }\n | { type: 'file-exists'; path: string }\n | { type: 'file-contains-verbatim'; path: string; fixture: string }\n | { type: 'file-matches-schema'; path: string; schema: string }\n | { type: 'stderr-matches'; pattern: string };\n\n// eslint-disable-next-line complexity\nexport function runConformanceCase(options: IRunCaseOptions): IRunCaseResult {\n const raw = readFileSync(options.casePath, 'utf8');\n const c: IConformanceCase = JSON.parse(raw);\n\n const fixturesRoot = options.fixturesRoot ?? join(options.specRoot, 'conformance', 'fixtures');\n\n // Defence in depth (audit L5): the conformance case id is JSON-author-\n // controlled. Replace anything that isn't a safe filesystem char and\n // cap the length so an over-long id (or one carrying path separators\n // / control bytes) can't escape `tmpdir()` or grow the prefix beyond\n // a reasonable bound.\n const safeId = c.id.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 32);\n const scope = mkdtempSync(join(tmpdir(), `sm-conformance-${safeId}-`));\n const setupEnv = disableEnv(c.setup);\n try {\n // 1. Replay every `setup.priorScans` step into the scope DB before\n // the main invoke runs. Returns the failure result early if any\n // step exits non-zero.\n const priorFailure = runPriorScansSetup(c, options, scope, fixturesRoot, setupEnv);\n if (priorFailure) return priorFailure;\n\n // 2. Copy the main fixture (replacing prior fixture content but\n // preserving the DB), then run the case's `invoke`.\n if (c.fixture) {\n replaceFixture(scope, fixturesRoot, c.fixture);\n }\n\n const argv = [c.invoke.verb];\n if (c.invoke.sub) argv.push(c.invoke.sub);\n if (c.invoke.args) argv.push(...c.invoke.args);\n if (c.invoke.flags) argv.push(...c.invoke.flags);\n\n const child = spawnSync(process.execPath, [options.binary, ...argv], {\n cwd: scope,\n env: { ...process.env, ...options.env, ...setupEnv },\n encoding: 'utf8',\n });\n\n const stdout = child.stdout ?? '';\n const stderr = child.stderr ?? '';\n const exitCode = child.status ?? 0;\n\n const assertions = c.assertions.map((a) =>\n evaluateAssertion(a, {\n exitCode,\n stdout,\n stderr,\n scope,\n specRoot: options.specRoot,\n fixturesRoot,\n }),\n );\n const passed = assertions.every((a) => a.ok);\n\n return { caseId: c.id, passed, exitCode, stdout, stderr, assertions };\n } finally {\n rmSync(scope, { recursive: true, force: true });\n }\n}\n\n/**\n * Phase 1 of `runConformanceCase` — replay every `setup.priorScans`\n * step in order. Each step replaces every non-`.skill-map/` directory\n * with the named fixture, then runs `sm scan` so the snapshot persists\n * into the scope DB. The scope DB survives across steps (we never\n * delete `.skill-map/`).\n *\n * Returns `null` on success (caller continues) or a `IRunCaseResult`\n * with a single `priorScan` failure assertion (caller returns it\n * unchanged).\n */\n// Per-step replay: replace fixture, spawn `sm scan`, check exit. The\n// failure-result construction is verbose because it carries every\n// stream the caller reports back.\n// eslint-disable-next-line complexity\nfunction runPriorScansSetup(\n c: IConformanceCase,\n options: IRunCaseOptions,\n scope: string,\n fixturesRoot: string,\n setupEnv: NodeJS.ProcessEnv,\n): IRunCaseResult | null {\n for (const step of c.setup?.priorScans ?? []) {\n replaceFixture(scope, fixturesRoot, step.fixture);\n const stepArgv = ['scan', ...(step.flags ?? [])];\n const stepChild = spawnSync(process.execPath, [options.binary, ...stepArgv], {\n cwd: scope,\n env: { ...process.env, ...options.env, ...setupEnv },\n encoding: 'utf8',\n });\n if ((stepChild.status ?? 0) !== 0) {\n return {\n caseId: c.id,\n passed: false,\n exitCode: stepChild.status ?? 0,\n stdout: stepChild.stdout ?? '',\n stderr: stepChild.stderr ?? '',\n assertions: [\n {\n ok: false,\n type: 'priorScan',\n reason: tx(CONFORMANCE_RUNNER_TEXTS.priorScanFailed, {\n fixture: step.fixture,\n exit: stepChild.status ?? 0,\n stderr: stepChild.stderr ?? '',\n }),\n },\n ],\n };\n }\n }\n return null;\n}\n\n/**\n * Replace every top-level entry in `scope` EXCEPT `.skill-map/` (which\n * holds the kernel DB and persists across staging steps), then copy\n * the fixture's contents on top. Used by `priorScans` and the main\n * fixture phase to swap Provider content while keeping the DB stable.\n *\n * `fixturesRoot` is the absolute path to the `fixtures/` directory of\n * the conformance suite hosting the case (spec-owned for kernel cases,\n * Provider-owned for Provider cases — see `IRunCaseOptions.fixturesRoot`).\n */\nfunction replaceFixture(scope: string, fixturesRoot: string, fixture: string): void {\n assertContained(fixturesRoot, fixture, 'fixture');\n for (const entry of readdirSync(scope)) {\n if (entry === '.skill-map') continue;\n rmSync(join(scope, entry), { recursive: true, force: true });\n }\n const src = join(fixturesRoot, fixture);\n cpSync(src, scope, { recursive: true });\n}\n\n/**\n * Reject case-supplied path strings that escape the directory tree they\n * are anchored to. A hostile case JSON would otherwise be able to copy\n * arbitrary filesystem content into the tmp scope (`fixture: \"../..\"`)\n * or read files outside the conformance sandbox via `file-exists` /\n * `file-contains-verbatim` assertions.\n */\nfunction assertContained(root: string, rel: string, label: string): void {\n if (isAbsolute(rel)) {\n throw new Error(\n tx(CONFORMANCE_RUNNER_TEXTS.pathMustBeRelative, { label, path: rel, anchor: root }),\n );\n }\n const abs = resolve(root, rel);\n const r = relative(root, abs);\n if (r.startsWith('..') || isAbsolute(r)) {\n throw new Error(\n tx(CONFORMANCE_RUNNER_TEXTS.pathEscapesAnchor, { label, path: rel, anchor: root }),\n );\n }\n}\n\ninterface IAssertionContext {\n exitCode: number;\n stdout: string;\n stderr: string;\n scope: string;\n specRoot: string;\n fixturesRoot: string;\n}\n\n// Switch over assertion types (`exit-code` / `stdout-matches` /\n// `file-exists` / `file-contains-verbatim` / `file-matches-schema` /\n// `stderr-matches` / `json-path`) with one branch per type. Splitting\n// per type would scatter the discriminated-union dispatch.\n// eslint-disable-next-line complexity\nfunction evaluateAssertion(a: IAssertion, ctx: IAssertionContext): IAssertionResult {\n switch (a.type) {\n case 'exit-code':\n return ctx.exitCode === a.value\n ? { ok: true, type: a.type }\n : {\n ok: false,\n type: a.type,\n reason: tx(CONFORMANCE_RUNNER_TEXTS.expectedExitCode, {\n expected: a.value,\n actual: ctx.exitCode,\n }),\n };\n case 'json-path':\n return evaluateJsonPath(a, ctx);\n case 'file-exists': {\n try {\n assertContained(ctx.scope, a.path, 'file-exists');\n } catch (err) {\n return { ok: false, type: a.type, reason: (err as Error).message };\n }\n const abs = resolve(ctx.scope, a.path);\n return existsSync(abs)\n ? { ok: true, type: a.type }\n : {\n ok: false,\n type: a.type,\n reason: tx(CONFORMANCE_RUNNER_TEXTS.fileNotFound, { path: a.path }),\n };\n }\n case 'file-contains-verbatim': {\n try {\n assertContained(ctx.fixturesRoot, a.fixture, 'file-contains-verbatim/fixture');\n assertContained(ctx.scope, a.path, 'file-contains-verbatim/path');\n } catch (err) {\n return { ok: false, type: a.type, reason: (err as Error).message };\n }\n const fixturePath = join(ctx.fixturesRoot, a.fixture);\n const targetPath = resolve(ctx.scope, a.path);\n if (!existsSync(targetPath)) {\n return {\n ok: false,\n type: a.type,\n reason: tx(CONFORMANCE_RUNNER_TEXTS.targetNotFound, { path: a.path }),\n };\n }\n const needle = readFileSync(fixturePath);\n const haystack = readFileSync(targetPath);\n return haystack.includes(needle)\n ? { ok: true, type: a.type }\n : {\n ok: false,\n type: a.type,\n reason: tx(CONFORMANCE_RUNNER_TEXTS.targetMissingFixture, { fixture: a.fixture }),\n };\n }\n case 'file-matches-schema':\n return {\n ok: false,\n type: a.type,\n reason: CONFORMANCE_RUNNER_TEXTS.fileMatchesSchemaUnimplemented,\n };\n case 'stderr-matches': {\n const re = new RegExp(a.pattern);\n return re.test(ctx.stderr)\n ? { ok: true, type: a.type }\n : {\n ok: false,\n type: a.type,\n reason: tx(CONFORMANCE_RUNNER_TEXTS.stderrDidNotMatch, { pattern: a.pattern }),\n };\n }\n }\n}\n\n/**\n * Minimal JSONPath evaluator — supports only the subset used by the stub\n * conformance suite: `$.foo`, `$.foo.bar`, `$.foo.length`, `$[0]`.\n * The full RFC 9535 implementation lands with Step 2.\n */\nfunction evaluateJsonPath(\n a: Extract<IAssertion, { type: 'json-path' }>,\n ctx: IAssertionContext,\n): IAssertionResult {\n let doc: unknown;\n try {\n doc = JSON.parse(ctx.stdout);\n } catch (err) {\n return {\n ok: false,\n type: a.type,\n reason: tx(CONFORMANCE_RUNNER_TEXTS.stdoutNotJson, { message: (err as Error).message }),\n };\n }\n\n const segments = parsePath(a.path);\n if (!segments) {\n return {\n ok: false,\n type: a.type,\n reason: tx(CONFORMANCE_RUNNER_TEXTS.unsupportedJsonPath, { path: a.path }),\n };\n }\n\n const walked = traverseJsonPath(doc, segments, a.path);\n if (!walked.ok) return { ok: false, type: a.type, reason: walked.reason };\n\n return applyJsonPathComparator(a, walked.value);\n}\n\n/**\n * Walk a parsed JSONPath segment list against a JSON document. Returns\n * the resolved value or a structured failure (caller maps to\n * `IAssertionResult`). Pure — no IO, no shared state.\n */\nfunction traverseJsonPath(\n doc: unknown,\n segments: Array<string | number>,\n path: string,\n): { ok: true; value: unknown } | { ok: false; reason: string } {\n let current: unknown = doc;\n for (const seg of segments) {\n if (typeof seg === 'number') {\n if (!Array.isArray(current)) {\n return { ok: false, reason: tx(CONFORMANCE_RUNNER_TEXTS.expectedArrayAtPath, { path }) };\n }\n current = current[seg];\n } else if (seg === 'length' && Array.isArray(current)) {\n current = current.length;\n } else if (typeof current === 'object' && current !== null) {\n current = (current as Record<string, unknown>)[seg];\n } else {\n return {\n ok: false,\n reason: tx(CONFORMANCE_RUNNER_TEXTS.cannotTraverseSegment, {\n type: typeof current,\n segment: String(seg),\n }),\n };\n }\n }\n return { ok: true, value: current };\n}\n\n/**\n * Apply the comparator clause (`equals` / `greaterThan` / `lessThan` /\n * `matches`) of a `json-path` assertion against the value resolved at\n * the requested path. Returns the final `IAssertionResult` directly.\n *\n * Complexity from the four parallel comparator branches; splitting into\n * one helper per comparator would be ceremony.\n */\n// eslint-disable-next-line complexity\nfunction applyJsonPathComparator(\n a: Extract<IAssertion, { type: 'json-path' }>,\n current: unknown,\n): IAssertionResult {\n if ('equals' in a && a.equals !== undefined) {\n return deepEqual(current, a.equals)\n ? { ok: true, type: a.type }\n : {\n ok: false,\n type: a.type,\n reason: tx(CONFORMANCE_RUNNER_TEXTS.jsonPathEqualsMismatch, {\n path: a.path,\n actual: JSON.stringify(current),\n expected: JSON.stringify(a.equals),\n }),\n };\n }\n if ('greaterThan' in a && typeof a.greaterThan === 'number') {\n return typeof current === 'number' && current > a.greaterThan\n ? { ok: true, type: a.type }\n : {\n ok: false,\n type: a.type,\n reason: tx(CONFORMANCE_RUNNER_TEXTS.jsonPathNotGreaterThan, {\n path: a.path,\n value: a.greaterThan,\n }),\n };\n }\n if ('lessThan' in a && typeof a.lessThan === 'number') {\n return typeof current === 'number' && current < a.lessThan\n ? { ok: true, type: a.type }\n : {\n ok: false,\n type: a.type,\n reason: tx(CONFORMANCE_RUNNER_TEXTS.jsonPathNotLessThan, {\n path: a.path,\n value: a.lessThan,\n }),\n };\n }\n if ('matches' in a && typeof a.matches === 'string') {\n const re = new RegExp(a.matches);\n return typeof current === 'string' && re.test(current)\n ? { ok: true, type: a.type }\n : {\n ok: false,\n type: a.type,\n reason: tx(CONFORMANCE_RUNNER_TEXTS.jsonPathDidNotMatch, {\n path: a.path,\n pattern: a.matches,\n }),\n };\n }\n return { ok: false, type: a.type, reason: CONFORMANCE_RUNNER_TEXTS.jsonPathNoComparator };\n}\n\nfunction parsePath(path: string): Array<string | number> | null {\n if (!path.startsWith('$')) return null;\n const tail = path.slice(1);\n const segments: Array<string | number> = [];\n const re = /\\.([a-zA-Z_][a-zA-Z0-9_-]*)|\\[(\\d+)\\]/g;\n let lastIndex = 0;\n let match: RegExpExecArray | null;\n while ((match = re.exec(tail)) !== null) {\n if (match.index !== lastIndex) return null;\n if (match[1] !== undefined) segments.push(match[1]);\n else if (match[2] !== undefined) segments.push(Number.parseInt(match[2], 10));\n lastIndex = re.lastIndex;\n }\n if (lastIndex !== tail.length) return null;\n return segments;\n}\n\n// eslint-disable-next-line complexity\nfunction deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a !== typeof b) return false;\n if (a && b && typeof a === 'object' && typeof b === 'object') {\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n const ak = Object.keys(a as object);\n const bk = Object.keys(b as object);\n if (ak.length !== bk.length) return false;\n for (const k of ak) {\n if (\n !deepEqual(\n (a as Record<string, unknown>)[k],\n (b as Record<string, unknown>)[k],\n )\n )\n {return false;}\n }\n return true;\n }\n return false;\n}\n\n/** Verifies the spec root looks sane (contains `index.json`). */\nexport function assertSpecRoot(specRoot: string): void {\n const indexPath = join(specRoot, 'index.json');\n if (!existsSync(indexPath) || !statSync(indexPath).isFile()) {\n throw new Error(tx(CONFORMANCE_RUNNER_TEXTS.specRootMissingIndex, { specRoot }));\n }\n}\n","/**\n * `tx(template, vars)` — string interpolation for the project's text\n * tables (`*.texts.ts` files under `kernel/i18n/` and `cli/i18n/`).\n *\n * Templates use the `{{name}}` placeholder shape (Mustache / Handlebars\n * / Transloco compatible) so the same string tables drop into a real\n * i18n library on the day this project migrates.\n *\n * Contract:\n * - Every `{{name}}` token in `template` MUST have a matching key in\n * `vars`. A missing key throws — silent fallback would hide a\n * forgotten arg in a production build, which is the worst kind of\n * bug to chase down.\n * - Values can be `string | number`. `null` / `undefined` keys are\n * rejected; the caller is expected to coerce upstream (e.g. format\n * a missing path as `'(unknown)'` before passing).\n * - Whitespace inside the braces is tolerated (`{{ name }}`); the\n * parser strips it. This keeps long templates readable when wrapped\n * across multiple TS lines via `+`.\n * - Literal `{{` is not currently supported — no real text needs it.\n * Add escaping the day a template needs to render Handlebars-style\n * content.\n *\n * Plural / conditional logic does NOT live in the template. The caller\n * picks the correct template (e.g. `entries_singular` vs\n * `entries_plural`) or composes the variable value upstream and passes\n * the finished string. Keeping templates flat is the price for staying\n * Transloco-ready.\n */\n\nconst TOKEN_RE = /\\{\\{\\s*([A-Za-z][A-Za-z0-9_]*)\\s*\\}\\}/g;\n\nexport function tx(\n template: string,\n vars: Record<string, string | number> = {},\n): string {\n return template.replace(TOKEN_RE, (_match, name: string) => {\n if (!Object.prototype.hasOwnProperty.call(vars, name)) {\n throw new Error(\n `tx: missing variable \"${name}\" for template \"${template.slice(0, 80)}${template.length > 80 ? '…' : ''}\"`,\n );\n }\n const value = vars[name];\n if (value === null || value === undefined) {\n throw new Error(\n `tx: variable \"${name}\" is null/undefined for template \"${template.slice(0, 80)}${template.length > 80 ? '…' : ''}\"`,\n );\n }\n return String(value);\n });\n}\n","/**\n * Strings emitted by the conformance runner (`conformance/index.ts`).\n * Same `tx(template, vars)` convention as every other `*.texts.ts` peer.\n *\n * Reasons surface in `IAssertionResult.reason` — visible to anyone\n * reading the runner output (CI logs, `sm conformance run --json`).\n * Keeping them in the catalog unblocks a future Transloco migration and\n * keeps the wording in one place.\n */\n\nexport const CONFORMANCE_RUNNER_TEXTS = {\n priorScanFailed:\n 'setup.priorScans step `{{fixture}}` failed with exit {{exit}}: {{stderr}}',\n\n pathMustBeRelative:\n 'conformance: {{label}} path \"{{path}}\" must be relative to its anchor ({{anchor}})',\n\n pathEscapesAnchor:\n 'conformance: {{label}} path \"{{path}}\" escapes its anchor ({{anchor}})',\n\n expectedExitCode:\n 'expected exit {{expected}}, got {{actual}}',\n\n fileNotFound:\n 'file not found: {{path}}',\n\n targetNotFound:\n 'target not found: {{path}}',\n\n targetMissingFixture:\n 'target does not contain fixture {{fixture}} verbatim',\n\n fileMatchesSchemaUnimplemented:\n 'file-matches-schema not yet implemented (requires ajv; lands with Step 2)',\n\n stderrDidNotMatch:\n 'stderr did not match /{{pattern}}/',\n\n stdoutNotJson:\n 'stdout is not valid JSON: {{message}}',\n\n unsupportedJsonPath:\n 'unsupported jsonpath: {{path}}',\n\n expectedArrayAtPath:\n 'expected array at {{path}}',\n\n cannotTraverseSegment:\n \"cannot traverse {{type}} at segment '{{segment}}'\",\n\n jsonPathEqualsMismatch:\n '{{path}} = {{actual}}, expected {{expected}}',\n\n jsonPathNotGreaterThan:\n '{{path}} not > {{value}}',\n\n jsonPathNotLessThan:\n '{{path}} not < {{value}}',\n\n jsonPathDidNotMatch:\n '{{path}} did not match /{{pattern}}/',\n\n jsonPathNoComparator:\n 'no comparator on json-path assertion',\n\n specRootMissingIndex:\n 'spec root missing index.json at {{specRoot}}',\n} as const;\n"],"mappings":"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","names":[]}
@@ -0,0 +1 @@
1
+ export { Confidence, DuplicateExtensionError, EXTENSION_KINDS, ExecutionFailureReason, ExecutionKind, ExecutionRecord, ExecutionRunner, ExecutionStatus, ExportQueryError, Extension, ExtensionKind, FilesystemPort, HOOK_TRIGGERS, HistoryStats, HistoryStatsErrorRates, HistoryStatsExecutionsPerPeriod, HistoryStatsPerActionRate, HistoryStatsTokensPerAction, HistoryStatsTopNode, HistoryStatsTotals, IAction, IActionPrecondition, ICreateFsWatcherOptions, IDedicatedStorePersist, IDedicatedStoreWrapper, IDiscoveredPlugin, IEnrichmentRecord, IExportQuery, IExportSubset, IExtensionBase, IExtractor, IExtractorCallbacks, IExtractorContext, IExtractorRunRecord, IFormatter, IFormatterContext, IFsWatcher, IHook, IHookContext, IIssueRow, IKvStorePersist, IKvStoreWrapper, ILoadedExtension, INodeBundle, INodeChange, INodeCounts, INodeFilter, IPersistOptions, IPersistedEnrichment, IPluginManifest, IPluginStorageSchema, IPluginStore, IProvider, IRawNode, IRule, IRuleContext, IRunOptions, IRunResult, IScanDelta, ITransactionalStorage, IWalkOptions, IWatchBatch, IWatchEvent, InMemoryProgressEmitter, Issue, IssueFix, KV_SCHEMA_KEY, Kernel, LOG_LEVELS, Link, LinkKind, LinkLocation, LinkTrigger, LogLevel, LogMethodLevel, LogRecord, LoggerPort, Node, NodeKind, NodeStat, PluginLoaderPort, ProgressEmitterPort, ProgressEvent, ProgressListener, Registry, RenameOp, RunScanOptions, RunnerPort, ScanResult, ScanScannedBy, ScanStats, Severity, SilentLogger, Stability, StoragePort, TExecutionMode, TGranularity, THookFilter, THookTrigger, TNodeChangeReason, TPluginLoadStatus, TPluginStorage, TWatchEventKind, TripleSplit, applyExportQuery, computeScanDelta, configureLogger, createChokidarWatcher, createKernel, detectRenamesAndOrphans, getActiveLogger, isEmptyDelta, isLogLevel, log, logLevelRank, makeDedicatedStoreWrapper, makeKvStoreWrapper, makePluginStore, mergeNodeWithEnrichments, parseExportQuery, parseLogLevel, qualifiedExtensionId, resetLogger, runExtractorsForNode, runScan, runScanWithRenames } from './kernel/index.js';