@dzhechkov/harness-core 0.3.129 → 0.3.130

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,552 @@
1
+ /**
2
+ * `dz skills-verify` — does a project's `.claude/skills/` actually REGISTER?
3
+ *
4
+ * Origin (feature skills-verify, ADR-001): `@dzhechkov/health-advisor` 1.2.0 shipped to npm with zero
5
+ * skills registering while its layout test was green — the test asserted a PROXY (files on disk), not
6
+ * the PROPERTY (registration). This module makes the property observable.
7
+ *
8
+ * Two layers:
9
+ * L1 `scanSkillsLayout` — instant, no Claude session: which names CAN register, plus the three
10
+ * layout shapes that produced the 1.2.0 defect.
11
+ * L2 `parseInitFacts` — the authoritative listing, parsed from the `system/init` event of
12
+ * + `classifyRegistration` `claude -p --output-format stream-json --verbose`. No model prose.
13
+ *
14
+ * FAIL-CLOSED: anything that prevents an honest observation yields `inconclusive`, never `pass`.
15
+ */
16
+ import { existsSync, lstatSync, readdirSync, realpathSync, statSync } from 'node:fs';
17
+ import { basename, isAbsolute, join, resolve } from 'node:path';
18
+ const MAX_BURIED_DEPTH = 4; // enough to catch extended/<name>/SKILL.md without walking the world
19
+ function findBuriedSkillMd(dir, depth, acc, errors) {
20
+ if (depth > MAX_BURIED_DEPTH)
21
+ return;
22
+ let entries;
23
+ try {
24
+ entries = readdirSync(dir);
25
+ }
26
+ catch (error) {
27
+ // A subtree we cannot read is unknown territory, not proven-clean territory (QE2 #1).
28
+ errors.push(`cannot read ${dir}: ${error instanceof Error ? error.message : String(error)}`);
29
+ return;
30
+ }
31
+ for (const name of entries) {
32
+ if (name === 'node_modules' || name === '__pycache__' || name.startsWith('.'))
33
+ continue;
34
+ const full = join(dir, name);
35
+ let isDir = false;
36
+ try {
37
+ isDir = statSync(full).isDirectory();
38
+ }
39
+ catch (error) {
40
+ errors.push(`cannot stat ${full}: ${error instanceof Error ? error.message : String(error)}`);
41
+ continue;
42
+ }
43
+ if (isDir) {
44
+ findBuriedSkillMd(full, depth + 1, acc, errors);
45
+ }
46
+ else if (name === 'SKILL.md' && depth >= 2) {
47
+ acc.push(full);
48
+ }
49
+ }
50
+ }
51
+ function hasPluginManifest(dir) {
52
+ return existsSync(join(dir, '.claude-plugin', 'plugin.json'));
53
+ }
54
+ /**
55
+ * A directory registers only if `SKILL.md` is a regular FILE. `existsSync` also answers true for a
56
+ * DIRECTORY named SKILL.md, which registers nothing yet suppressed every other check (QE2 #4).
57
+ */
58
+ function hasSkillFile(dir) {
59
+ try {
60
+ return statSync(join(dir, 'SKILL.md')).isFile();
61
+ }
62
+ catch {
63
+ return false; // ENOENT, or a dangling symlink: either way it cannot register
64
+ }
65
+ }
66
+ /**
67
+ * Walk `<projectDir>/.claude/skills/` and report what can register and what cannot.
68
+ * Deterministic, needs no Claude session — safe for CI.
69
+ */
70
+ export function scanSkillsLayout(projectDir) {
71
+ const skillsRoot = join(resolve(projectDir), '.claude', 'skills');
72
+ // `existsSync` also answers false for a DANGLING SYMLINK — that is a broken tree, not an absent
73
+ // one, and must not scan as "clean" (QE2 #1). lstat distinguishes the two.
74
+ let rootLink = null;
75
+ try {
76
+ rootLink = lstatSync(skillsRoot);
77
+ }
78
+ catch (error) {
79
+ // Only ENOENT means "genuinely absent". ENOTDIR/EACCES mean the tree is BROKEN or unreadable —
80
+ // reporting that as an empty-and-clean project is a route to a false PASS (QE3 #3).
81
+ const code = error.code;
82
+ if (code !== 'ENOENT') {
83
+ return {
84
+ skillsRoot, projectDir: resolve(projectDir), exists: true, registrable: [], findings: [], advisories: [], containers: [],
85
+ scanError: `cannot stat ${skillsRoot}: ${error instanceof Error ? error.message : String(error)}`,
86
+ };
87
+ }
88
+ // ENOENT on .claude/skills can also mean .claude itself is a FILE or unreadable — check it.
89
+ const claudeDir = join(resolve(projectDir), '.claude');
90
+ try {
91
+ const st = lstatSync(claudeDir);
92
+ // A SYMLINK must be followed: a dangling `.claude` link is a broken tree, not an absent one.
93
+ if (st.isSymbolicLink() && !existsSync(claudeDir)) {
94
+ return {
95
+ skillsRoot, projectDir: resolve(projectDir), exists: true, registrable: [], findings: [], advisories: [], containers: [],
96
+ scanError: `${claudeDir} is a dangling symlink`,
97
+ };
98
+ }
99
+ if (!st.isDirectory() && !st.isSymbolicLink()) {
100
+ return {
101
+ skillsRoot, projectDir: resolve(projectDir), exists: true, registrable: [], findings: [], advisories: [], containers: [],
102
+ scanError: `${claudeDir} is not a directory`,
103
+ };
104
+ }
105
+ }
106
+ catch (claudeError) {
107
+ const cCode = claudeError.code;
108
+ if (cCode !== 'ENOENT') {
109
+ return {
110
+ skillsRoot, projectDir: resolve(projectDir), exists: true, registrable: [], findings: [], advisories: [], containers: [],
111
+ scanError: `cannot stat ${claudeDir}: ${claudeError instanceof Error ? claudeError.message : String(claudeError)}`,
112
+ };
113
+ }
114
+ }
115
+ return { skillsRoot, projectDir: resolve(projectDir), exists: false, registrable: [], findings: [], advisories: [], containers: [] }; // genuinely absent
116
+ }
117
+ if (rootLink.isSymbolicLink() && !existsSync(skillsRoot)) {
118
+ return {
119
+ skillsRoot,
120
+ projectDir: resolve(projectDir),
121
+ exists: true,
122
+ registrable: [],
123
+ findings: [],
124
+ advisories: [],
125
+ containers: [],
126
+ scanError: `${skillsRoot} is a dangling symlink`,
127
+ };
128
+ }
129
+ // `.claude/skills` must BE a directory. A file there scans as "empty and clean" otherwise (QE #4).
130
+ try {
131
+ if (!statSync(skillsRoot).isDirectory()) {
132
+ return { skillsRoot, projectDir: resolve(projectDir), exists: true, registrable: [], findings: [], advisories: [], containers: [], scanError: `${skillsRoot} is not a directory` };
133
+ }
134
+ }
135
+ catch (error) {
136
+ return {
137
+ skillsRoot,
138
+ projectDir: resolve(projectDir),
139
+ exists: true,
140
+ registrable: [],
141
+ findings: [],
142
+ advisories: [],
143
+ containers: [],
144
+ scanError: `cannot stat ${skillsRoot}: ${error instanceof Error ? error.message : String(error)}`,
145
+ };
146
+ }
147
+ const registrable = [];
148
+ const findings = [];
149
+ const advisories = [];
150
+ const containers = [];
151
+ const scanErrors = [];
152
+ let entries = [];
153
+ try {
154
+ entries = readdirSync(skillsRoot);
155
+ }
156
+ catch (error) {
157
+ // An unreadable root is NOT an empty project — say so, so the verdict can be inconclusive.
158
+ return {
159
+ skillsRoot,
160
+ projectDir: resolve(projectDir),
161
+ exists: true,
162
+ registrable: [],
163
+ findings: [],
164
+ advisories: [],
165
+ containers: [],
166
+ scanError: `cannot read ${skillsRoot}: ${error instanceof Error ? error.message : String(error)}`,
167
+ };
168
+ }
169
+ for (const name of entries) {
170
+ if (name.startsWith('.'))
171
+ continue; // hidden/backup dirs are not skills
172
+ const dir = join(skillsRoot, name);
173
+ let isDir = false;
174
+ try {
175
+ isDir = statSync(dir).isDirectory();
176
+ }
177
+ catch (error) {
178
+ // An entry we cannot stat is unknown, not absent — record it so the verdict stays honest.
179
+ scanErrors.push(`cannot stat ${dir}: ${error instanceof Error ? error.message : String(error)}`);
180
+ continue;
181
+ }
182
+ if (!isDir) {
183
+ // A SKILL.md dropped directly into .claude/skills/ registers nothing — it is a real defect,
184
+ // not something to skip silently (QE #4).
185
+ if (name === 'SKILL.md') {
186
+ findings.push({
187
+ dir: '.',
188
+ kind: 'no-skill-md',
189
+ detail: 'SKILL.md sits directly in .claude/skills/ — a skill must live in its own directory to register',
190
+ });
191
+ }
192
+ continue;
193
+ }
194
+ const registers = hasSkillFile(dir);
195
+ // A manifest-backed CONTAINER (`<dir>/.claude-plugin/plugin.json`) is a plugin-shaped layout.
196
+ // It did not register in measured practice, but the class may be supported under workspace
197
+ // trust — so the WHOLE container is advisory. Emitting the generic `no-skill-md` /
198
+ // `buried-skill-md` findings for it killed the layout anyway, which was the over-claim (QE4 #1).
199
+ const isPluginContainer = !registers && hasPluginManifest(dir);
200
+ const bucket = isPluginContainer ? advisories : findings;
201
+ if (registers) {
202
+ registrable.push(name);
203
+ }
204
+ else {
205
+ bucket.push({
206
+ dir: name,
207
+ kind: 'no-skill-md',
208
+ detail: isPluginContainer
209
+ ? `${name}/ is a plugin-shaped container (advisory): it has no depth-1 SKILL.md, so it registers only if the client loads it as a plugin`
210
+ : `no SKILL.md at ${name}/SKILL.md — this directory cannot register`,
211
+ });
212
+ }
213
+ // A plugin manifest under .claude/skills does NOT auto-register (plugins load from the
214
+ // marketplace only). This is the exact false premise that shipped health-advisor 1.2.0.
215
+ // Only a report when the dir registers NOTHING: a dir with its own depth-1 SKILL.md registers
216
+ // fine and a stray manifest beside it is inert, not a blocker (Codex QE #8).
217
+ if (isPluginContainer) {
218
+ // What would this container provide? The dir name of every nested SKILL.md.
219
+ const inner = [];
220
+ findBuriedSkillMd(dir, 1, inner, scanErrors);
221
+ const candidates = [...new Set(inner.map((f) => basename(join(f, '..'))))];
222
+ containers.push({ dir: name, candidates });
223
+ advisories.push({
224
+ dir: name,
225
+ kind: 'plugin-manifest-trap',
226
+ detail: `${name}/.claude-plugin/plugin.json did not register in measured practice (advisory, not a failure) — a plugin normally loads from the marketplace; if you meant these to register, install it as a plugin or use bare skills`,
227
+ });
228
+ }
229
+ // SKILL.md files buried too deep never register (health-advisor 1.2.0: extended/<name>/SKILL.md).
230
+ //
231
+ // FALSE-POSITIVE GUARD (found by dogfooding this gate on a healthy project): a dir that DOES
232
+ // register may legitimately bundle nested SKILL.md files as its own resources — health-advisor
233
+ // 1.2.1 co-locates its base deps under the master exactly so they do NOT register. Only a dir
234
+ // that registers NOTHING while hiding SKILL.md files inside is the 1.2.0 defect shape.
235
+ if (!registers) {
236
+ const buried = [];
237
+ findBuriedSkillMd(dir, 1, buried, scanErrors);
238
+ for (const path of buried) {
239
+ bucket.push({
240
+ dir: name,
241
+ kind: 'buried-skill-md',
242
+ detail: `${path.slice(skillsRoot.length + 1)} is 2+ levels deep in a directory that registers nothing — the loader scans one level, so it never registers`,
243
+ });
244
+ }
245
+ }
246
+ }
247
+ return {
248
+ skillsRoot,
249
+ projectDir: resolve(projectDir),
250
+ exists: true,
251
+ registrable: registrable.sort(),
252
+ findings,
253
+ advisories,
254
+ containers,
255
+ ...(scanErrors.length ? { scanError: scanErrors.join('; ') } : {}),
256
+ };
257
+ }
258
+ /**
259
+ * Parse the `system/init` event out of a `--output-format stream-json` stream. PURE: takes the raw
260
+ * text, returns facts, does no IO. Returns `null` when no init event is present (→ inconclusive).
261
+ */
262
+ /**
263
+ * The first init event's facts. Use ONLY for "has the event arrived yet?" during streaming —
264
+ * `classifyRegistration` deliberately does NOT accept bare facts, because the count must travel
265
+ * with them (a caller that forgot to pass `initEventCount` got a free PASS — QE2 #2).
266
+ */
267
+ export function parseInitFacts(streamText) {
268
+ return parseAllInitFacts(streamText)[0] ?? null;
269
+ }
270
+ /**
271
+ * Every `system/init` event in the stream. More than one means the observations may CONTRADICT each
272
+ * other (Codex QE #7) — the classifier refuses to pick a winner and returns `inconclusive`.
273
+ */
274
+ export function parseAllInitFacts(streamText) {
275
+ return parseStream(streamText).events;
276
+ }
277
+ function parseStream(streamText) {
278
+ const found = [];
279
+ let malformed = 0;
280
+ for (const raw of streamText.split('\n')) {
281
+ const line = raw.trim();
282
+ if (!line || line[0] !== '{')
283
+ continue;
284
+ let obj;
285
+ try {
286
+ obj = JSON.parse(line);
287
+ }
288
+ catch {
289
+ // A truncated `{"type":"system","subtype":"init",…` silently disappeared here, so a
290
+ // contradictory second event could be dropped and the first one believed (QE3 #2).
291
+ malformed += 1;
292
+ continue;
293
+ }
294
+ if (obj.type !== 'system' || obj.subtype !== 'init')
295
+ continue;
296
+ // The listing is authoritative or it is nothing: a partially-unparseable `skills` array (a
297
+ // non-string element) must NOT be silently narrowed to the strings it happens to contain —
298
+ // that turned an unreadable listing into a PASS (Codex QE #1). ABSENT key ≠ empty list (ADR SP-3).
299
+ const rawSkills = obj.skills;
300
+ const skills = Array.isArray(rawSkills)
301
+ ? rawSkills.every((s) => typeof s === 'string')
302
+ ? rawSkills
303
+ : null
304
+ : null;
305
+ const rawPlugins = obj.plugins;
306
+ const plugins = Array.isArray(rawPlugins)
307
+ ? rawPlugins
308
+ .filter((p) => !!p && typeof p === 'object')
309
+ .map((p) => {
310
+ const name = typeof p.name === 'string' ? p.name : '(unnamed)';
311
+ // exactOptionalPropertyTypes: omit `version` rather than set it to undefined.
312
+ return typeof p.version === 'string' ? { name, version: p.version } : { name };
313
+ })
314
+ : [];
315
+ found.push({
316
+ skills,
317
+ plugins,
318
+ // An empty or relative cwd testifies to nothing — `resolve("")` silently becomes the caller's
319
+ // own cwd and can forge a match (Codex QE #6). Only an absolute path counts as evidence.
320
+ cwd: typeof obj.cwd === 'string' && obj.cwd !== '' && isAbsolute(obj.cwd) ? obj.cwd : null,
321
+ clientVersion: typeof obj.claude_code_version === 'string' ? obj.claude_code_version : null,
322
+ });
323
+ }
324
+ return { events: found, malformedObjectLines: malformed };
325
+ }
326
+ /**
327
+ * The single entry point. PURE apart from the injected resolver. Fail-closed by construction: `pass`
328
+ * is reachable only from a completed scan, a probe that produced EXACTLY ONE well-formed init event
329
+ * from THIS project, a fully-readable skills listing, a performed provenance check with no ambiguity,
330
+ * and zero load-blocking layout findings.
331
+ */
332
+ export function verifyRegistration(evidence, options = {}) {
333
+ // A JavaScript caller can hand us an incomplete object; a crash is not a verdict (QE4 #7).
334
+ const bad = (reason) => ({
335
+ verdict: 'inconclusive',
336
+ reason,
337
+ expected: [],
338
+ missing: [],
339
+ registeredCount: null,
340
+ clientVersion: null,
341
+ plugins: [],
342
+ advisories: [],
343
+ controls: { cwdMatched: null, skillsListPresent: false },
344
+ layout: [],
345
+ });
346
+ if (!evidence || typeof evidence !== 'object')
347
+ return bad('no evidence supplied');
348
+ if (!evidence.scan || !evidence.probe || !evidence.provenance || typeof evidence.projectDir !== 'string') {
349
+ return bad('incomplete evidence (scan, probe, provenance and projectDir are all required)');
350
+ }
351
+ const { projectDir, scan, probe, provenance } = evidence;
352
+ // The contract is CANONICAL identity: a lexical `resolve` alone reports a symlinked project as a
353
+ // different one and turns a correct registration into `inconclusive` (QE4 #3).
354
+ const resolvePath = options.resolvePath ??
355
+ ((p) => {
356
+ try {
357
+ return realpathSync(p);
358
+ }
359
+ catch {
360
+ return resolve(p);
361
+ }
362
+ });
363
+ const expected = evidence.expected ?? scan.registrable;
364
+ const layout = scan.findings;
365
+ const fail = (verdict, reason, extra = {}) => ({
366
+ expected,
367
+ layout,
368
+ advisories: scan.advisories,
369
+ plugins: [],
370
+ clientVersion: null,
371
+ missing: [],
372
+ registeredCount: null,
373
+ controls: { cwdMatched: null, skillsListPresent: false },
374
+ ...extra,
375
+ verdict,
376
+ reason,
377
+ });
378
+ // 1. The scan must describe THIS project, and must have completed.
379
+ let scanIsOurs;
380
+ try {
381
+ scanIsOurs = resolvePath(scan.projectDir) === resolvePath(projectDir);
382
+ }
383
+ catch {
384
+ scanIsOurs = scan.projectDir === projectDir;
385
+ }
386
+ if (!scanIsOurs) {
387
+ return fail('inconclusive', `the layout scan describes ${scan.projectDir}, not ${projectDir} — evidence from another project`);
388
+ }
389
+ if (scan.scanError !== undefined)
390
+ return fail('inconclusive', `layout scan failed: ${scan.scanError}`);
391
+ // 2. The probe must have produced a stream.
392
+ if (!probe.ok)
393
+ return fail('inconclusive', `probe failed: ${probe.error}`);
394
+ // 3. Parsing must be intact and the evidence must be singular.
395
+ const parsed = parseStream(probe.stream);
396
+ if (parsed.malformedObjectLines > 0) {
397
+ return fail('inconclusive', `${parsed.malformedObjectLines} malformed JSON line(s) in the stream — a truncated event may be hiding contradictory evidence`);
398
+ }
399
+ if (parsed.events.length !== 1) {
400
+ return fail('inconclusive', parsed.events.length === 0
401
+ ? 'no system/init event in the stream — could not observe registration'
402
+ : `${parsed.events.length} init events in one stream — contradictory observations, refusing to pick one`);
403
+ }
404
+ const facts = parsed.events[0];
405
+ const withFacts = { plugins: facts.plugins, clientVersion: facts.clientVersion };
406
+ // 4. The cwd control: the session must have read THIS project.
407
+ if (facts.cwd === null) {
408
+ return fail('inconclusive', 'init event carried no usable absolute cwd — cannot confirm the session read this project', withFacts);
409
+ }
410
+ let cwdMatched;
411
+ try {
412
+ cwdMatched = resolvePath(facts.cwd) === resolvePath(projectDir);
413
+ }
414
+ catch (error) {
415
+ return fail('inconclusive', `cannot resolve the paths to compare (${error instanceof Error ? error.message : String(error)}) — the cwd control could not run`, withFacts);
416
+ }
417
+ if (!cwdMatched) {
418
+ return fail('inconclusive', `session read ${facts.cwd}, not ${projectDir} — its listing does not describe this project`, {
419
+ ...withFacts,
420
+ registeredCount: facts.skills?.length ?? null,
421
+ controls: { cwdMatched: false, skillsListPresent: facts.skills !== null },
422
+ });
423
+ }
424
+ // 5. The listing must be readable in full.
425
+ if (facts.skills === null) {
426
+ return fail('inconclusive', 'the init listing has no readable `skills` array (absent or not all strings) — cannot read it', {
427
+ ...withFacts,
428
+ controls: { cwdMatched: true, skillsListPresent: false },
429
+ });
430
+ }
431
+ const controls = { cwdMatched: true, skillsListPresent: true };
432
+ const registered = new Set(facts.skills);
433
+ const missing = expected.filter((name) => !registered.has(name));
434
+ const common = { ...withFacts, registeredCount: facts.skills.length, controls };
435
+ // 6. Load-blocking layout problems fail on their own — one healthy skill must not mask them.
436
+ if (layout.length > 0) {
437
+ return {
438
+ expected,
439
+ layout,
440
+ advisories: scan.advisories,
441
+ ...common,
442
+ missing,
443
+ verdict: 'fail',
444
+ reason: expected.length === 0
445
+ ? `nothing can register: ${layout.length} layout problem(s) and no registrable skill directory`
446
+ : `${layout.length} layout problem(s) can never register (alongside ${expected.length} expected skill(s))`,
447
+ };
448
+ }
449
+ // 6b. A plugin-shaped container is forgiven ONLY if the SESSION says that plugin loaded.
450
+ // Matching on skill NAMES was wrong: one incidental collision with an unrelated plugin's skill
451
+ // (e.g. `deep-research`) forgave the whole container, and the gate PASSED the broken
452
+ // health-advisor 1.2.0 (MEASURED — reproducer: `dz skills-verify` against that published
453
+ // install). `init.plugins` names what actually loaded, so ask that instead.
454
+ const loadedPlugins = new Set(facts.plugins.map((p) => p.name));
455
+ // Only the LOADED-PLUGIN list counts. A namespaced-name fallback (`<dir>:<skill>` present in the
456
+ // listing) was still name-based evidence — the very class that made the gate pass a broken install
457
+ // — and `init.plugins` already covers every legitimate case.
458
+ const deadContainers = scan.containers.filter((c) => c.candidates.length > 0 && !loadedPlugins.has(c.dir));
459
+ if (deadContainers.length > 0) {
460
+ return {
461
+ expected,
462
+ layout,
463
+ advisories: scan.advisories,
464
+ ...common,
465
+ missing,
466
+ verdict: 'fail',
467
+ reason: `${deadContainers.length} plugin-shaped container(s) did not load — ` +
468
+ deadContainers
469
+ .map((c) => `${c.dir}/ (${c.candidates.length} skill(s) inside, but no such plugin in the session)`)
470
+ .join('; '),
471
+ };
472
+ }
473
+ // 7. Provenance must have been CHECKED, and must be unambiguous.
474
+ if (!provenance.checked) {
475
+ return fail('inconclusive', 'provenance was not checked — a same-named skill outside this project would forge a pass', {
476
+ ...common,
477
+ });
478
+ }
479
+ const ambiguousExpected = expected.filter((name) => provenance.ambiguous.includes(name) && registered.has(name));
480
+ if (ambiguousExpected.length > 0 && missing.length === 0) {
481
+ return fail('inconclusive', `${ambiguousExpected.length} expected name(s) also exist outside this project (${ambiguousExpected.join(', ')}) — ` +
482
+ 'the listing carries names, not provenance, so registration cannot be attributed to this project', { ...common });
483
+ }
484
+ if (missing.length > 0) {
485
+ return {
486
+ expected,
487
+ layout,
488
+ advisories: scan.advisories,
489
+ ...common,
490
+ missing,
491
+ verdict: 'fail',
492
+ reason: `${missing.length} of ${expected.length} expected skill(s) did NOT register`,
493
+ };
494
+ }
495
+ return {
496
+ expected,
497
+ layout,
498
+ advisories: scan.advisories,
499
+ ...common,
500
+ missing: [],
501
+ verdict: 'pass',
502
+ reason: expected.length === 0
503
+ ? 'nothing was expected to register; the session listing was read successfully'
504
+ : `all ${expected.length} expected skill(s) are registered`,
505
+ };
506
+ }
507
+ /** Exit code contract: pass=0, fail=1, inconclusive=2 (distinct so CI can treat it separately). */
508
+ export function registrationExitCode(verdict, strict = false) {
509
+ if (verdict === 'pass')
510
+ return 0;
511
+ if (verdict === 'fail')
512
+ return 1;
513
+ return strict ? 1 : 2;
514
+ }
515
+ const VERDICT_LABEL = {
516
+ pass: 'PASS',
517
+ fail: 'FAIL',
518
+ inconclusive: 'INCONCLUSIVE',
519
+ };
520
+ export function renderRegistrationReport(result, scan) {
521
+ const out = [];
522
+ out.push(`dz skills-verify: ${VERDICT_LABEL[result.verdict]} — ${result.reason}`);
523
+ if (scan) {
524
+ out.push(` layout: ${scan.registrable.length} registrable skill dir(s) under ${scan.skillsRoot}` +
525
+ (scan.exists ? '' : ' (missing)'));
526
+ }
527
+ if (result.registeredCount !== null) {
528
+ out.push(` session: ${result.registeredCount} skill(s) registered` +
529
+ (result.clientVersion ? ` · client ${result.clientVersion}` : '') +
530
+ (result.plugins.length ? ` · ${result.plugins.length} plugin(s) loaded` : ''));
531
+ }
532
+ if (result.missing.length) {
533
+ out.push(' MISSING (expected but not registered):');
534
+ for (const name of result.missing)
535
+ out.push(` - ${name}`);
536
+ }
537
+ if (result.layout.length) {
538
+ out.push(' layout problems (these can never register):');
539
+ for (const f of result.layout)
540
+ out.push(` [${f.kind}] ${f.detail}`);
541
+ }
542
+ if (result.advisories.length) {
543
+ out.push(' advisories (reported, not failures):');
544
+ for (const f of result.advisories)
545
+ out.push(` [${f.kind}] ${f.detail}`);
546
+ }
547
+ if (result.verdict === 'inconclusive') {
548
+ out.push(' (inconclusive is never a pass — it means registration could not be observed honestly)');
549
+ }
550
+ return out.join('\n');
551
+ }
552
+ //# sourceMappingURL=skills-verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills-verify.js","sourceRoot":"","sources":["../src/skills-verify.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dzhechkov/harness-core",
3
- "version": "0.3.129",
3
+ "version": "0.3.130",
4
4
  "description": "Shared harness logic - skill loading, additive apply, and the init/sync/verify/doctor operations.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -32,13 +32,13 @@
32
32
  "@dzhechkov/adapter-openclaude": "^0.1.0",
33
33
  "@dzhechkov/adapter-opencode": "^0.2.0",
34
34
  "yaml": "^2.0.0",
35
- "@dzhechkov/adapter-copilot": "0.1.1",
36
- "@dzhechkov/adapter-windsurf": "0.1.1",
35
+ "@dzhechkov/adapter-cursor": "0.1.1",
37
36
  "@dzhechkov/adapter-agents-md": "0.1.1",
38
37
  "@dzhechkov/adapter-gemini": "0.1.1",
39
- "@dzhechkov/adapter-cursor": "0.1.1",
40
- "@dzhechkov/core": "0.2.14",
41
- "@dzhechkov/memory": "0.2.9"
38
+ "@dzhechkov/adapter-windsurf": "0.1.1",
39
+ "@dzhechkov/adapter-copilot": "0.1.1",
40
+ "@dzhechkov/memory": "0.2.9",
41
+ "@dzhechkov/core": "0.2.14"
42
42
  },
43
43
  "peerDependenciesMeta": {
44
44
  "@ruvector/rvf": {