skillwiki 0.9.48 → 0.9.50

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.
@@ -672,13 +672,7 @@ function vaultIoConcurrency() {
672
672
  function decodeProcMountPath(value) {
673
673
  return value.replace(/\\040/g, " ");
674
674
  }
675
- function isRcloneFuseVault(root) {
676
- let mounts;
677
- try {
678
- mounts = readFileSync("/proc/mounts", "utf8");
679
- } catch {
680
- return false;
681
- }
675
+ function isRcloneFuseVaultFromMounts(root, mounts) {
682
676
  return mounts.split(/\r?\n/).some((line) => {
683
677
  const parts = line.split(" ");
684
678
  if (parts.length < 3) return false;
@@ -687,7 +681,7 @@ function isRcloneFuseVault(root) {
687
681
  return fsType === "fuse.rclone" && (root === mountPoint || root.startsWith(`${mountPoint}/`));
688
682
  });
689
683
  }
690
- function resolveReadOnlyVaultRoot(root) {
684
+ function resolveReadOnlyVaultRootWithMounts(root, mounts) {
691
685
  if (/^(1|true|yes)$/i.test(process.env.SKILLWIKI_DISABLE_VAULT_READ_MIRROR ?? "")) {
692
686
  return { root, mirrored: false };
693
687
  }
@@ -696,11 +690,19 @@ function resolveReadOnlyVaultRoot(root) {
696
690
  return { root: explicitMirror, mirrored: explicitMirror !== root };
697
691
  }
698
692
  const siblingMirror = `${root}-git`;
699
- if (isRcloneFuseVault(root) && existsSync(join2(siblingMirror, "SCHEMA.md"))) {
693
+ if (isRcloneFuseVaultFromMounts(root, mounts) && existsSync(join2(siblingMirror, "SCHEMA.md"))) {
700
694
  return { root: siblingMirror, mirrored: true };
701
695
  }
702
696
  return { root, mirrored: false };
703
697
  }
698
+ function resolveReadOnlyVaultRoot(root) {
699
+ let mounts = "";
700
+ try {
701
+ mounts = readFileSync("/proc/mounts", "utf8");
702
+ } catch {
703
+ }
704
+ return resolveReadOnlyVaultRootWithMounts(root, mounts);
705
+ }
704
706
  async function mapWithConcurrency(items, limit, mapper) {
705
707
  const out = new Array(items.length);
706
708
  let next = 0;
@@ -3133,7 +3135,7 @@ function severityForBucket(kind) {
3133
3135
  if (WARNING_ORDER.includes(kind)) return "warning";
3134
3136
  return "info";
3135
3137
  }
3136
- function outputForOnlyBucket(input, match, fixed, unresolved) {
3138
+ function outputForOnlyBucket(input, match, fixed, unresolved, readVault = lintReadVault(input)) {
3137
3139
  const severity = severityForBucket(input.only);
3138
3140
  const filtered = severity === "error" ? { error: match, warning: [], info: [] } : severity === "warning" ? { error: [], warning: match, info: [] } : { error: [], warning: [], info: match };
3139
3141
  const summary = {
@@ -3144,14 +3146,19 @@ function outputForOnlyBucket(input, match, fixed, unresolved) {
3144
3146
  let exitCode = ExitCode.OK;
3145
3147
  if (summary.errors > 0) exitCode = ExitCode.LINT_HAS_ERRORS;
3146
3148
  else if (summary.warnings > 0 || summary.info > 0) exitCode = ExitCode.LINT_HAS_WARNINGS;
3149
+ const vault = lintVaultOutput(input, readVault);
3150
+ const hintLines = [
3151
+ ...readMirrorHintLines(vault),
3152
+ `--only ${input.only}`,
3153
+ match.length === 0 ? "0 violations" : match.map((b) => ` ${b.kind}: ${b.items.length}`).join("\n")
3154
+ ];
3147
3155
  const output = {
3148
- vault: { path: input.vault, source: input.source ?? "resolved" },
3156
+ vault,
3149
3157
  summary,
3150
3158
  by_severity: filtered,
3151
3159
  fixed,
3152
3160
  unresolved,
3153
- humanHint: `--only ${input.only}
3154
- ${match.length === 0 ? "0 violations" : match.map((b) => ` ${b.kind}: ${b.items.length}`).join("\n")}`
3161
+ humanHint: hintLines.join("\n")
3155
3162
  };
3156
3163
  if (input.fix) appendLintFixLastOp(input.vault, fixed);
3157
3164
  return {
@@ -3160,7 +3167,27 @@ ${match.length === 0 ? "0 violations" : match.map((b) => ` ${b.kind}: ${b.items
3160
3167
  };
3161
3168
  }
3162
3169
  function lintReadVault(input) {
3163
- return input.fix ? input.vault : resolveReadOnlyVaultRoot(input.vault).root;
3170
+ if (input.fix) {
3171
+ return { readPath: input.vault, readMirror: false };
3172
+ }
3173
+ const resolved = resolveReadOnlyVaultRoot(input.vault);
3174
+ return { readPath: resolved.root, readMirror: resolved.mirrored };
3175
+ }
3176
+ function lintVaultOutput(input, readVault) {
3177
+ return {
3178
+ path: input.vault,
3179
+ source: input.source ?? "resolved",
3180
+ read_path: readVault.readPath,
3181
+ read_mirror: readVault.readMirror
3182
+ };
3183
+ }
3184
+ function readMirrorHintLines(vault) {
3185
+ if (!vault.read_mirror) return [];
3186
+ return [
3187
+ `read mirror: ${vault.read_path}`,
3188
+ `requested vault: ${vault.path}`,
3189
+ "if results look stale, refresh the read mirror or rerun with SKILLWIKI_DISABLE_VAULT_READ_MIRROR=1 for a live scan; live scans may be slower"
3190
+ ];
3164
3191
  }
3165
3192
  function recomputeRawSha256IfPresent(content) {
3166
3193
  const split = splitFrontmatter(content);
@@ -3189,6 +3216,7 @@ function summarizeLintOutput(output, examplesLimit = 3) {
3189
3216
  ...output.by_severity.info.map((bucket) => summarizeBucket(bucket, "info", output.vault.path, examplesLimit))
3190
3217
  ];
3191
3218
  const lines = [];
3219
+ lines.push(...readMirrorHintLines(output.vault));
3192
3220
  lines.push(`errors: ${output.summary.errors}`);
3193
3221
  lines.push(`warnings: ${output.summary.warnings}`);
3194
3222
  lines.push(`info: ${output.summary.info}`);
@@ -3236,7 +3264,8 @@ async function collectCliRefsPages(vault) {
3236
3264
  return ok(pages);
3237
3265
  }
3238
3266
  async function runCliRefsOnly(input) {
3239
- const lintVault = lintReadVault(input);
3267
+ const readVault = lintReadVault(input);
3268
+ const lintVault = readVault.readPath;
3240
3269
  const pages = await collectCliRefsPages(lintVault);
3241
3270
  if (!pages.ok) {
3242
3271
  return { exitCode: ExitCode.VAULT_PATH_INVALID, result: pages };
@@ -3253,14 +3282,19 @@ async function runCliRefsOnly(input) {
3253
3282
  const infoOut = cliRefFlags.length > 0 ? [{ kind: "cli_refs", items: cliRefFlags }] : [];
3254
3283
  const summary = { errors: 0, warnings: 0, info: cliRefFlags.length };
3255
3284
  const exitCode = cliRefFlags.length > 0 ? ExitCode.LINT_HAS_WARNINGS : ExitCode.OK;
3285
+ const vault = lintVaultOutput(input, readVault);
3286
+ const hintLines = [
3287
+ ...readMirrorHintLines(vault),
3288
+ `--only cli_refs`,
3289
+ cliRefFlags.length === 0 ? "0 violations" : ` cli_refs: ${cliRefFlags.length}`
3290
+ ];
3256
3291
  const output = {
3257
- vault: { path: input.vault, source: input.source ?? "resolved" },
3292
+ vault,
3258
3293
  summary,
3259
3294
  by_severity: { error: [], warning: [], info: infoOut },
3260
3295
  fixed: [],
3261
3296
  unresolved: [],
3262
- humanHint: `--only cli_refs
3263
- ${cliRefFlags.length === 0 ? "0 violations" : ` cli_refs: ${cliRefFlags.length}`}`
3297
+ humanHint: hintLines.join("\n")
3264
3298
  };
3265
3299
  return {
3266
3300
  exitCode,
@@ -3395,7 +3429,8 @@ async function applyFileSourceUrlFix(input, scan, fileSourceUrlFlags, fileSource
3395
3429
  return remaining;
3396
3430
  }
3397
3431
  async function runFileSourceUrlOnly(input) {
3398
- const lintVault = lintReadVault(input);
3432
+ const readVault = lintReadVault(input);
3433
+ const lintVault = readVault.readPath;
3399
3434
  const scanResult = await scanVault(lintVault);
3400
3435
  if (!scanResult.ok) return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scanResult };
3401
3436
  const pageTextCache = /* @__PURE__ */ new Map();
@@ -3411,7 +3446,7 @@ async function runFileSourceUrlOnly(input) {
3411
3446
  unresolved
3412
3447
  );
3413
3448
  const match = remaining.size > 0 ? [{ kind: "file_source_url", items: [...remaining] }] : [];
3414
- return outputForOnlyBucket(input, match, fixed, unresolved);
3449
+ return outputForOnlyBucket(input, match, fixed, unresolved, readVault);
3415
3450
  }
3416
3451
  async function runLint(input) {
3417
3452
  if (input.only && !KNOWN_BUCKETS.includes(input.only)) {
@@ -3427,7 +3462,8 @@ async function runLint(input) {
3427
3462
  return runFileSourceUrlOnly(input);
3428
3463
  }
3429
3464
  const shouldFix = (bucket) => !!input.fix && (!input.only || input.only === bucket);
3430
- const lintVault = lintReadVault(input);
3465
+ const readVault = lintReadVault(input);
3466
+ const lintVault = readVault.readPath;
3431
3467
  const buckets = {};
3432
3468
  const fixed = [];
3433
3469
  const unresolved = [];
@@ -4148,7 +4184,7 @@ ${split.data.body}`;
4148
4184
  const infoOut = INFO_ORDER.flatMap((k) => buckets[k] ? [{ kind: k, items: buckets[k] }] : []);
4149
4185
  if (input.only) {
4150
4186
  const match = [...errorOut, ...warningOut, ...infoOut].filter((b) => b.kind === input.only);
4151
- return outputForOnlyBucket(input, match, fixed, unresolved);
4187
+ return outputForOnlyBucket(input, match, fixed, unresolved, readVault);
4152
4188
  }
4153
4189
  const summary = {
4154
4190
  errors: errorOut.reduce((n, b) => n + b.items.length, 0),
@@ -4158,7 +4194,9 @@ ${split.data.body}`;
4158
4194
  let exitCode = ExitCode.OK;
4159
4195
  if (summary.errors > 0) exitCode = ExitCode.LINT_HAS_ERRORS;
4160
4196
  else if (summary.warnings > 0 || summary.info > 0) exitCode = ExitCode.LINT_HAS_WARNINGS;
4197
+ const vault = lintVaultOutput(input, readVault);
4161
4198
  const hintLines = [];
4199
+ hintLines.push(...readMirrorHintLines(vault));
4162
4200
  if (summary.errors > 0) hintLines.push(`errors: ${summary.errors}`);
4163
4201
  if (summary.warnings > 0) hintLines.push(`warnings: ${summary.warnings}`);
4164
4202
  if (summary.info > 0) hintLines.push(`info: ${summary.info}`);
@@ -4169,7 +4207,7 @@ ${split.data.body}`;
4169
4207
  if (hintLines.length === 0) hintLines.push("0 errors, 0 warnings, 0 info");
4170
4208
  if (input.fix) appendLintFixLastOp(input.vault, fixed);
4171
4209
  const output = {
4172
- vault: { path: input.vault, source: input.source ?? "resolved" },
4210
+ vault,
4173
4211
  summary,
4174
4212
  by_severity: { error: errorOut, warning: warningOut, info: infoOut },
4175
4213
  fixed,
package/dist/cli.js CHANGED
@@ -75,7 +75,7 @@ import {
75
75
  triggerAutoUpdate,
76
76
  writeCache,
77
77
  writeDotenv
78
- } from "./chunk-UCTLPX3M.js";
78
+ } from "./chunk-O3WK7GBV.js";
79
79
  import {
80
80
  normalizeDistTag
81
81
  } from "./chunk-E6UWZ3S3.js";
@@ -321,6 +321,8 @@ async function runInstall(input) {
321
321
  const hintLines2 = [
322
322
  `deferred to plugin: skillwiki@llm-wiki v${plugin.version}`,
323
323
  `plugin provides skills at ${plugin.installPath}`,
324
+ "Plugin-managed skills are not refreshed with `skillwiki install`.",
325
+ "Do not run `skillwiki install` just to refresh plugin-managed skills; update the active plugin channel instead.",
324
326
  `use --force to install CLI copies into ${input.target} anyway`
325
327
  ];
326
328
  return {
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runSkillwikiMcpStdio
4
- } from "./chunk-UCTLPX3M.js";
4
+ } from "./chunk-O3WK7GBV.js";
5
5
  import "./chunk-E6UWZ3S3.js";
6
6
 
7
7
  // src/mcp-entry.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillwiki",
3
- "version": "0.9.48",
3
+ "version": "0.9.50",
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.9.48",
3
+ "version": "0.9.50",
4
4
  "skills": "./",
5
5
  "description": "Project-aware Karpathy-style knowledge base for Claude Code: 18 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.9.48",
3
+ "version": "0.9.50",
4
4
  "description": "Project-aware Karpathy-style knowledge base for Codex with 18 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.9.48",
3
+ "version": "0.9.50",
4
4
  "private": true,
5
5
  "files": [
6
6
  "wiki-*",
@@ -172,11 +172,13 @@ skillwiki has multiple distribution channels that can drift:
172
172
  | Channel | Location | Update Command |
173
173
  |---------|----------|----------------|
174
174
  | npm CLI | `/usr/local/bin/skillwiki` | `npm install -g skillwiki@latest` |
175
- | npm skills | `/usr/local/lib/node_modules/skillwiki/skills/` | `skillwiki install` (copies to `~/.claude/skills/`) |
175
+ | npm skills | `/usr/local/lib/node_modules/skillwiki/skills/` | `skillwiki install` only for standalone CLI skill copies; defers when the plugin channel is active |
176
176
  | Claude plugin | `~/.claude/plugins/cache/llm-wiki/` | `claude plugin update skillwiki@llm-wiki` |
177
177
  | Codex plugin | `~/.codex/plugins/cache/llm-wiki/` | `codex plugin marketplace upgrade llm-wiki`, then reinstall or restart Codex as needed |
178
178
  | Local git dev | source repo checkout | `npm link ./packages/cli` (from repo root) |
179
179
  **Check versions:** `skillwiki doctor` reports Plugin/CLI version mismatch warnings when installed channels disagree.
180
+ **Plugin channel rule:** Plugin-managed skills are not refreshed with `skillwiki install`. When Claude or Codex plugin is installed and enabled, the plugin cache is the skill provider; `skillwiki install` is only a legacy/standalone copier for `~/.claude/skills/`.
181
+ **Agent update rule:** Do not run `skillwiki install` just to refresh plugin-managed skills. If `skillwiki install` reports `deferred_to_plugin: true`, stop there and update the active plugin channel instead: Claude uses `claude plugin update skillwiki@llm-wiki`; Codex uses `codex plugin marketplace upgrade llm-wiki`, then reinstall or restart Codex as needed. Only use `skillwiki install --force` when the user explicitly wants duplicate CLI-managed copies under `~/.claude/skills/` and accepts that `skillwiki doctor` may report overlap.
180
182
  **Authoring rule:** `SKILL.md` frontmatter follows the Agent Skills schema: top-level `name` and `description` plus optional schema fields such as `metadata`. Do not put release version fields at the top level of `SKILL.md`; plugin and package release versions live in `plugin.json` and `package.json`.
181
183
  **Fix:** If developing locally, use the repo source plus `npm link`. If using released versions, update the relevant plugin or npm channel; do not infer release freshness from `SKILL.md` frontmatter.
182
184
 
@@ -172,11 +172,13 @@ skillwiki has multiple distribution channels that can drift:
172
172
  | Channel | Location | Update Command |
173
173
  |---------|----------|----------------|
174
174
  | npm CLI | `/usr/local/bin/skillwiki` | `npm install -g skillwiki@latest` |
175
- | npm skills | `/usr/local/lib/node_modules/skillwiki/skills/` | `skillwiki install` (copies to `~/.claude/skills/`) |
175
+ | npm skills | `/usr/local/lib/node_modules/skillwiki/skills/` | `skillwiki install` only for standalone CLI skill copies; defers when the plugin channel is active |
176
176
  | Claude plugin | `~/.claude/plugins/cache/llm-wiki/` | `claude plugin update skillwiki@llm-wiki` |
177
177
  | Codex plugin | `~/.codex/plugins/cache/llm-wiki/` | `codex plugin marketplace upgrade llm-wiki`, then reinstall or restart Codex as needed |
178
178
  | Local git dev | source repo checkout | `npm link ./packages/cli` (from repo root) |
179
179
  **Check versions:** `skillwiki doctor` reports Plugin/CLI version mismatch warnings when installed channels disagree.
180
+ **Plugin channel rule:** Plugin-managed skills are not refreshed with `skillwiki install`. When Claude or Codex plugin is installed and enabled, the plugin cache is the skill provider; `skillwiki install` is only a legacy/standalone copier for `~/.claude/skills/`.
181
+ **Agent update rule:** Do not run `skillwiki install` just to refresh plugin-managed skills. If `skillwiki install` reports `deferred_to_plugin: true`, stop there and update the active plugin channel instead: Claude uses `claude plugin update skillwiki@llm-wiki`; Codex uses `codex plugin marketplace upgrade llm-wiki`, then reinstall or restart Codex as needed. Only use `skillwiki install --force` when the user explicitly wants duplicate CLI-managed copies under `~/.claude/skills/` and accepts that `skillwiki doctor` may report overlap.
180
182
  **Authoring rule:** `SKILL.md` frontmatter follows the Agent Skills schema: top-level `name` and `description` plus optional schema fields such as `metadata`. Do not put release version fields at the top level of `SKILL.md`; plugin and package release versions live in `plugin.json` and `package.json`.
181
183
  **Fix:** If developing locally, use the repo source plus `npm link`. If using released versions, update the relevant plugin or npm channel; do not infer release freshness from `SKILL.md` frontmatter.
182
184