skillwiki 0.10.36 → 0.10.39

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.
@@ -5968,6 +5968,7 @@ export {
5968
5968
  isFailedRunStatus,
5969
5969
  readSatelliteLatestRunFromText,
5970
5970
  evaluateSatelliteRunHealth,
5971
+ detectFuseMount,
5971
5972
  snapshotterHealthChecks,
5972
5973
  runDoctor,
5973
5974
  readCliPackageJson,
package/dist/cli.js CHANGED
@@ -7,6 +7,7 @@ import {
7
7
  GateError,
8
8
  SATELLITE_STALE_MS,
9
9
  configPath,
10
+ detectFuseMount,
10
11
  evaluateDirtyVolumeGate,
11
12
  evaluateSatelliteRunHealth,
12
13
  findPlugin,
@@ -38,7 +39,7 @@ import {
38
39
  scanConflictMarkerBlocksInText,
39
40
  snapshotterHealthChecks,
40
41
  upsertIndexEntry
41
- } from "./chunk-WJVG3DD5.js";
42
+ } from "./chunk-NDR2OY4K.js";
42
43
  import {
43
44
  normalizeDistTag,
44
45
  readCache,
@@ -168,6 +169,7 @@ import {
168
169
  ok,
169
170
  readPage,
170
171
  redactSensitiveContent,
172
+ resolveReadOnlyVaultRoot,
171
173
  scanSensitiveContent,
172
174
  scanVault,
173
175
  splitFrontmatter
@@ -181,11 +183,19 @@ import { Command } from "commander";
181
183
  function printJson(r) {
182
184
  process.stdout.write(JSON.stringify(r) + "\n");
183
185
  }
184
- function printHuman(r) {
186
+ function printHuman(r, opts = {}) {
185
187
  if (r.ok) {
186
188
  if (typeof r.data === "object" && r.data !== null && "humanHint" in r.data) {
187
- process.stdout.write(`${r.data.humanHint}
189
+ const humanHint = r.data.humanHint;
190
+ if (!opts.detailHints?.length) {
191
+ process.stdout.write(`${humanHint}
188
192
  `);
193
+ } else {
194
+ const existingLines = new Set(humanHint.split("\n"));
195
+ const detailLines2 = opts.detailHints.filter((line) => !existingLines.has(line));
196
+ process.stdout.write(`${[humanHint, ...detailLines2].join("\n")}
197
+ `);
198
+ }
189
199
  } else {
190
200
  process.stdout.write(`OK
191
201
  ${formatData(r.data)}
@@ -202,6 +212,45 @@ function formatData(d) {
202
212
  return JSON.stringify(d, null, 2);
203
213
  }
204
214
 
215
+ // src/utils/lint-detail-hints.ts
216
+ function lintDetailHints(data) {
217
+ const record = asRecord(data);
218
+ if (!record) return [];
219
+ const bySeverity = asRecord(record.by_severity);
220
+ if (bySeverity && Array.isArray(bySeverity.error)) {
221
+ return detailLines(bySeverity.error, false);
222
+ }
223
+ return Array.isArray(record.buckets) ? detailLines(record.buckets, true) : [];
224
+ }
225
+ function healthLintDetailHints(data) {
226
+ const record = asRecord(data);
227
+ const components = asRecord(record?.components);
228
+ const lint = asRecord(components?.lint);
229
+ return Array.isArray(lint?.buckets) ? detailLines(lint.buckets, true) : [];
230
+ }
231
+ function detailLines(buckets, requireErrorSeverity) {
232
+ const seen = /* @__PURE__ */ new Set();
233
+ const lines = [];
234
+ for (const bucket of buckets) {
235
+ const record = asRecord(bucket);
236
+ if (!record || requireErrorSeverity && record.severity !== "error") continue;
237
+ const name = nonEmptyBucketName(record);
238
+ if (!name || seen.has(name)) continue;
239
+ seen.add(name);
240
+ lines.push(`detail: skillwiki lint --only ${name} --examples 3`);
241
+ }
242
+ return lines;
243
+ }
244
+ function nonEmptyBucketName(bucket) {
245
+ if (typeof bucket.kind !== "string" || !/^[a-z0-9_]+$/.test(bucket.kind)) return null;
246
+ if (typeof bucket.count === "number") return bucket.count > 0 ? bucket.kind : null;
247
+ if (Array.isArray(bucket.items)) return bucket.items.length > 0 ? bucket.kind : null;
248
+ return null;
249
+ }
250
+ function asRecord(value) {
251
+ return typeof value === "object" && value !== null ? value : null;
252
+ }
253
+
205
254
  // src/utils/deprecation.ts
206
255
  import { readFileSync } from "fs";
207
256
  import { join } from "path";
@@ -4424,7 +4473,8 @@ import { mkdir as mkdir8, readFile as readFile11, writeFile as writeFile7 } from
4424
4473
  import { join as join24, relative, sep } from "path";
4425
4474
  var MAX_WORDS = 900;
4426
4475
  async function runSessionBrief(input) {
4427
- const scan = await scanVault(input.vault);
4476
+ const { root: scanRoot } = resolveReadOnlyVaultRoot(input.vault);
4477
+ const scan = await scanVault(scanRoot);
4428
4478
  if (!scan.ok) {
4429
4479
  return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scan };
4430
4480
  }
@@ -4450,7 +4500,7 @@ async function runSessionBrief(input) {
4450
4500
  loadSatelliteHealth(input.vault),
4451
4501
  loadSessionPins(input.vault, project),
4452
4502
  project ? loadMemoryTopics(input.vault, project) : Promise.resolve([]),
4453
- loadPendingSources(input.vault, today)
4503
+ loadPendingSources(scanRoot, today)
4454
4504
  ]);
4455
4505
  const healthWarnings = [
4456
4506
  ...baseHealthWarnings,
@@ -8357,11 +8407,23 @@ async function runBackupRestore(input) {
8357
8407
  import { existsSync as existsSync10, statSync as statSync4 } from "fs";
8358
8408
  import { readFile as readFile16 } from "fs/promises";
8359
8409
  import { join as join32 } from "path";
8410
+ var FUSE_NO_MIRROR_NOTE = "FUSE vault with no read mirror - status scan may be slow";
8360
8411
  async function runStatus(input) {
8361
8412
  if (!existsSync10(input.vault)) {
8362
8413
  return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { vault: input.vault }) };
8363
8414
  }
8364
- const scan = await scanVault(input.vault);
8415
+ const { root: scanRoot, mirrored } = resolveReadOnlyVaultRoot(input.vault);
8416
+ let readSource = "live";
8417
+ if (mirrored) {
8418
+ readSource = "mirror";
8419
+ } else if (detectFuseMount(input.vault)) {
8420
+ readSource = "fuse-no-mirror";
8421
+ }
8422
+ if (readSource === "fuse-no-mirror") {
8423
+ process.stderr.write(`warning: ${FUSE_NO_MIRROR_NOTE}
8424
+ `);
8425
+ }
8426
+ const scan = await scanVault(scanRoot);
8365
8427
  if (!scan.ok) {
8366
8428
  return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scan };
8367
8429
  }
@@ -8383,7 +8445,7 @@ async function runStatus(input) {
8383
8445
  const compound = scan.data.compound.length;
8384
8446
  let schemaVersion = "v1";
8385
8447
  try {
8386
- const schemaContent = await readFile16(join32(input.vault, "SCHEMA.md"), "utf8");
8448
+ const schemaContent = await readFile16(join32(scanRoot, "SCHEMA.md"), "utf8");
8387
8449
  const versionMatch = schemaContent.match(/version:\s*["']?([^"'\s\n]+)/i);
8388
8450
  if (versionMatch) schemaVersion = versionMatch[1];
8389
8451
  } catch {
@@ -8420,14 +8482,20 @@ async function runStatus(input) {
8420
8482
  };
8421
8483
  const totalPages = Object.values(pageCounts).reduce((a, b) => a + b, 0);
8422
8484
  const rawTotal = rawArticles + rawTranscripts;
8423
- const humanHint = [
8485
+ const hintLines = [
8424
8486
  `vault: ${input.vault}`,
8425
8487
  `lang: ${langResult.value}`,
8426
8488
  `total: ${totalPages} pages`,
8427
8489
  ` entities: ${pageCounts.entities} concepts: ${pageCounts.concepts} comparisons: ${pageCounts.comparisons} queries: ${pageCounts.queries} meta: ${pageCounts.meta}`,
8428
8490
  ` raw: ${rawTotal} work_items: ${workItems} compound: ${compound}`,
8429
8491
  `last modified: ${lastModified.slice(0, 10)}`
8430
- ].join("\n");
8492
+ ];
8493
+ if (readSource === "mirror") {
8494
+ hintLines.push(`read source: mirror (${scanRoot}) - page counts may lag up to 30m`);
8495
+ } else if (readSource === "fuse-no-mirror") {
8496
+ hintLines.push(FUSE_NO_MIRROR_NOTE);
8497
+ }
8498
+ const humanHint = hintLines.join("\n");
8431
8499
  return {
8432
8500
  exitCode: ExitCode.OK,
8433
8501
  result: ok({
@@ -8437,6 +8505,7 @@ async function runStatus(input) {
8437
8505
  page_counts: pageCounts,
8438
8506
  total_pages: totalPages,
8439
8507
  last_modified: lastModified,
8508
+ read_source: readSource,
8440
8509
  humanHint
8441
8510
  })
8442
8511
  };
@@ -9354,9 +9423,16 @@ var program = new Command();
9354
9423
  program.name("skillwiki").description("Deterministic helpers for CodeWiki skills").version(pkg.version);
9355
9424
  program.option("--human", "render terminal-readable output instead of JSON");
9356
9425
  async function emit(r, vault, opts) {
9357
- if (program.opts().human) printHuman(r.result);
9358
- else printJson(r.result);
9426
+ if (program.opts().human) {
9427
+ const detailHints = r.result.ok ? opts?.humanDetailHints?.(r.result.data) : void 0;
9428
+ printHuman(r.result, { detailHints });
9429
+ } else {
9430
+ printJson(r.result);
9431
+ }
9359
9432
  if (vault && opts?.postCommit !== false) await postCommit(vault, r.exitCode);
9433
+ await new Promise((resolve6, reject) => {
9434
+ process.stdout.write("", (error) => error ? reject(error) : resolve6());
9435
+ });
9360
9436
  process.exit(r.exitCode);
9361
9437
  }
9362
9438
  function dirtyVolumeBlock(vault, command) {
@@ -9835,6 +9911,7 @@ projectionsCmd.command("repair-legacy [vault]").description("repair one supporte
9835
9911
  });
9836
9912
  program.command("lint [vault]").description("run all vault health checks").option("--days <n>", "stale threshold", (s) => parseInt(s, 10), 90).option("--lines <n>", "pagesize threshold", (s) => parseInt(s, 10), 200).option("--log-threshold <n>", "log rotation threshold", (s) => parseInt(s, 10), 500).option("--fix", "auto-fix supported lint violations").option("--only <bucket>", "run only the specified lint bucket").option("--summary", "emit bounded bucket counts instead of full item arrays", false).option("--examples <n>", "example count per bucket in summary mode", (s) => parseInt(s, 10), 3).option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
9837
9913
  const v = await resolveVaultArg(vault, opts.wiki);
9914
+ const humanDetailHints = opts.only ? void 0 : lintDetailHints;
9838
9915
  if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
9839
9916
  else if (opts.fix && opts.summary) return emitGuardedVaultWrite(
9840
9917
  v.vault,
@@ -9849,7 +9926,8 @@ program.command("lint [vault]").description("run all vault health checks").optio
9849
9926
  only: opts.only,
9850
9927
  summary: true,
9851
9928
  examplesLimit: opts.examples
9852
- })
9929
+ }),
9930
+ { humanDetailHints }
9853
9931
  );
9854
9932
  else if (opts.fix) return emitGuardedVaultWrite(
9855
9933
  v.vault,
@@ -9863,7 +9941,8 @@ program.command("lint [vault]").description("run all vault health checks").optio
9863
9941
  fix: true,
9864
9942
  only: opts.only,
9865
9943
  summary: false
9866
- })
9944
+ }),
9945
+ { humanDetailHints }
9867
9946
  );
9868
9947
  else if (opts.summary) emit(await runLint({
9869
9948
  vault: v.vault,
@@ -9875,7 +9954,7 @@ program.command("lint [vault]").description("run all vault health checks").optio
9875
9954
  only: opts.only,
9876
9955
  summary: true,
9877
9956
  examplesLimit: opts.examples
9878
- }), v.vault);
9957
+ }), v.vault, { humanDetailHints });
9879
9958
  else emit(await runLint({
9880
9959
  vault: v.vault,
9881
9960
  source: vault ? "flag" : void 0,
@@ -9884,7 +9963,7 @@ program.command("lint [vault]").description("run all vault health checks").optio
9884
9963
  logThreshold: opts.logThreshold,
9885
9964
  fix: false,
9886
9965
  only: opts.only
9887
- }), v.vault);
9966
+ }), v.vault, { humanDetailHints });
9888
9967
  });
9889
9968
  program.command("health [vault]").description("bounded whole-system wiki health report").option("--wiki <name>", "wiki profile name").option("--sync <mode>", "vault-sync policy: optional|required|off", "optional").option("--no-fail", "always exit 0 while reporting status in JSON").option("--out <path>", "write JSON result envelope to this path").option("--examples <n>", "example count per lint bucket", (s) => parseInt(s, 10), 3).action(async (vault, opts) => {
9890
9969
  const sync = String(opts.sync ?? "optional");
@@ -9905,7 +9984,7 @@ program.command("health [vault]").description("bounded whole-system wiki health
9905
9984
  noFail: opts.fail === false,
9906
9985
  out: opts.out,
9907
9986
  examplesLimit: opts.examples
9908
- }), void 0, { postCommit: false });
9987
+ }), void 0, { postCommit: false, humanDetailHints: healthLintDetailHints });
9909
9988
  });
9910
9989
  var configCmd = program.command("config").description("manage skillwiki configuration");
9911
9990
  configCmd.command("get <key>").description("print the value of a config key").action(async (key) => emit(await runConfigGet({ key, home: process.env.HOME ?? "" })));
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runSkillwikiMcpStdio
4
- } from "./chunk-WJVG3DD5.js";
4
+ } from "./chunk-NDR2OY4K.js";
5
5
  import "./chunk-7I2TPIV5.js";
6
6
  import "./chunk-QVO332CT.js";
7
7
  import "./chunk-XRBUABGE.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.10.36",
3
+ "version": "0.10.39",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "skillwiki": "dist/cli.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.10.36",
3
+ "version": "0.10.39",
4
4
  "skills": "./",
5
5
  "description": "Project-aware Karpathy-style knowledge base for Claude Code: 19 prompt-only skills (wiki-*, proj-*, using-skillwiki) backed by the deterministic `skillwiki` CLI.",
6
6
  "author": {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.10.36",
3
+ "version": "0.10.39",
4
4
  "description": "Project-aware Karpathy-style knowledge base for Codex with 19 prompt-only skills backed by the deterministic skillwiki CLI.",
5
5
  "author": {
6
6
  "name": "karlorz",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillwiki/skills",
3
- "version": "0.10.36",
3
+ "version": "0.10.39",
4
4
  "private": true,
5
5
  "files": [
6
6
  "wiki-*",