skillwiki 0.10.109 → 0.10.111

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.
Files changed (42) hide show
  1. package/dist/{chunk-JCDAEZVD.js → chunk-5IBLXGLY.js} +5 -3
  2. package/dist/chunk-6OQLBNKR.js +250 -0
  3. package/dist/chunk-GQWCTJTU.js +55 -0
  4. package/dist/{chunk-FYAKMULW.js → chunk-HBJLFPQP.js} +91 -198
  5. package/dist/chunk-I2J3IJB7.js +54 -0
  6. package/dist/{chunk-HMHMCPCE.js → chunk-I6IRJCUJ.js} +12 -57
  7. package/dist/{chunk-QU2IXZRN.js → chunk-JQV5KNPT.js} +8 -6
  8. package/dist/chunk-KWEYA3OE.js +60 -0
  9. package/dist/{chunk-DTTKCCQ4.js → chunk-MRPJ7X7W.js} +5 -3
  10. package/dist/{chunk-LDEZQXH6.js → chunk-OJJBZDPR.js} +306 -116
  11. package/dist/chunk-OSL4J7GF.js +32 -0
  12. package/dist/chunk-PYPPG7RF.js +126 -0
  13. package/dist/chunk-QESNTTVY.js +50 -0
  14. package/dist/chunk-TDBUJUYH.js +109 -0
  15. package/dist/{chunk-GJC2CI3W.js → chunk-UIEQIJXP.js} +108 -336
  16. package/dist/chunk-X5GL2FCU.js +344 -0
  17. package/dist/chunk-ZRGZBAVS.js +98 -0
  18. package/dist/cli.js +352 -297
  19. package/dist/{index-projection-ESBJOBS7.js → index-projection-2K672CBO.js} +5 -3
  20. package/dist/journal-QU5IDXQF.js +13 -0
  21. package/dist/{managed-write-preflight-MAIGWFQJ.js → managed-write-preflight-GRSHQYKC.js} +7 -4
  22. package/dist/migrate-PIB4QA54.js +21 -0
  23. package/dist/ready-S7F53Q2D.js +9 -0
  24. package/dist/runtime-GLMI5OCT.js +15 -0
  25. package/dist/skillwiki-mcp.js +12 -7
  26. package/dist/sources-D2MGP246.js +10 -0
  27. package/dist/upload-HTE62TOV.js +14 -0
  28. package/dist/watcher-MHG46J3R.js +616 -0
  29. package/docs/clip-outbox.md +119 -0
  30. package/package.json +5 -1
  31. package/skills/.claude-plugin/plugin.json +1 -1
  32. package/skills/.codex-plugin/plugin.json +1 -1
  33. package/skills/.cursor-plugin/plugin.json +1 -1
  34. package/skills/package.json +1 -1
  35. package/skills/skills/using-skillwiki/SKILL.md +1 -1
  36. package/skills/skills/wiki-init/SKILL.md +12 -11
  37. package/skills/using-skillwiki/SKILL.md +1 -1
  38. package/skills/wiki-init/SKILL.md +12 -11
  39. package/templates/launchd/com.karlchow.skillwiki-clip-outbox.plist +21 -0
  40. package/templates/web-clipper/llm-wiki-clippings.json +1 -1
  41. package/templates/web-clipper/readme.txt +13 -13
  42. package/dist/sources-QTQSZMST.js +0 -9
@@ -1,4 +1,17 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ applySourceCompileClaim,
4
+ applySourceCompilePublished,
5
+ applySourceCompileRelease,
6
+ applySourceReview,
7
+ listCompileStatus,
8
+ listSourceReviews,
9
+ planSourceCompileClaim,
10
+ planSourceCompilePublished,
11
+ planSourceCompileRelease,
12
+ planSourceReview,
13
+ runSourcesPending
14
+ } from "./chunk-JQV5KNPT.js";
2
15
  import {
3
16
  latestFromCache,
4
17
  semverGt
@@ -6,9 +19,8 @@ import {
6
19
  import {
7
20
  renderRootIndex,
8
21
  writeRootIndexProjection
9
- } from "./chunk-DTTKCCQ4.js";
22
+ } from "./chunk-MRPJ7X7W.js";
10
23
  import {
11
- CONFIG_KEYS,
12
24
  VAULT_HYGIENE_GENERATED_COMMIT_PATHS,
13
25
  VAULT_HYGIENE_GITIGNORE_PATTERNS,
14
26
  VAULT_SYNC_FILTER_REQUIRED_EXCLUDES,
@@ -18,20 +30,16 @@ import {
18
30
  communityCohesion,
19
31
  git,
20
32
  hasUnmergedPaths,
21
- isValidWikiProfileKey,
22
33
  listReviewRequiredOps,
23
34
  loadFleetManifestAndHost,
24
35
  louvain,
25
36
  missingIgnorePatterns,
26
- parseDotenvFile,
27
- parseDotenvText,
28
37
  probeGithubReachability,
29
38
  probeS3Reachability,
30
39
  probeSnapshotterSsh,
31
40
  releaseOwnedSyncLock,
32
41
  resolveConfiguredSnapshotWorktree,
33
42
  resolveRuntimePath,
34
- resolveSkillwikiHome,
35
43
  resolveVaultSyncPullHelper,
36
44
  resolveWikiS3Remote,
37
45
  runLint,
@@ -39,30 +47,46 @@ import {
39
47
  runStale,
40
48
  satelliteGateFromFleetLoad,
41
49
  snapshotterAliasForLocalHost,
42
- toUndirectedWeighted,
43
- writeDotenv
44
- } from "./chunk-FYAKMULW.js";
50
+ toUndirectedWeighted
51
+ } from "./chunk-HBJLFPQP.js";
52
+ import {
53
+ eventPathFor,
54
+ writeLogEvent
55
+ } from "./chunk-5IBLXGLY.js";
45
56
  import {
46
- atomicWriteText,
47
57
  prepareTypedPage
48
- } from "./chunk-HMHMCPCE.js";
58
+ } from "./chunk-I6IRJCUJ.js";
49
59
  import {
50
- applySourceCompileClaim,
51
- applySourceCompilePublished,
52
- applySourceCompileRelease,
53
- applySourceReview,
54
- listCompileStatus,
55
- listSourceReviews,
56
- planSourceCompileClaim,
57
- planSourceCompilePublished,
58
- planSourceCompileRelease,
59
- planSourceReview,
60
- runSourcesPending
61
- } from "./chunk-QU2IXZRN.js";
60
+ extractFrontmatter,
61
+ readPage,
62
+ redactSensitiveContent,
63
+ resolveReadOnlyVaultRoot,
64
+ scanSensitiveContent,
65
+ scanVault,
66
+ splitFrontmatter
67
+ } from "./chunk-X5GL2FCU.js";
62
68
  import {
63
- eventPathFor,
64
- writeLogEvent
65
- } from "./chunk-JCDAEZVD.js";
69
+ xml
70
+ } from "./chunk-TDBUJUYH.js";
71
+ import {
72
+ CLIP_NOT_CONFIGURED,
73
+ PRODUCTION_WATCHER_LABEL,
74
+ RETIRED_WATCHER_LABELS,
75
+ conditionalCreateProven,
76
+ loadClipCredentials,
77
+ loadClipOutboxConfig
78
+ } from "./chunk-6OQLBNKR.js";
79
+ import {
80
+ CONFIG_KEYS,
81
+ isValidWikiProfileKey,
82
+ parseDotenvFile,
83
+ parseDotenvText,
84
+ resolveSkillwikiHome,
85
+ writeDotenv
86
+ } from "./chunk-PYPPG7RF.js";
87
+ import {
88
+ atomicWriteText
89
+ } from "./chunk-GQWCTJTU.js";
66
90
  import {
67
91
  CompoundSchema,
68
92
  ExitCode,
@@ -72,18 +96,13 @@ import {
72
96
  WorkItemSchema,
73
97
  detectSchema,
74
98
  err,
75
- extractFrontmatter,
99
+ isClipOutboxKey,
76
100
  isVaultSyncKey,
77
101
  ok,
102
+ parseClipOutboxKeyValue,
78
103
  parseVaultSyncKeyValue,
79
- readPage,
80
- redactSensitiveContent,
81
- resolveReadOnlyVaultRoot,
82
- scanSensitiveContent,
83
- scanVault,
84
- splitFrontmatter,
85
104
  systemdPropertyFor
86
- } from "./chunk-GJC2CI3W.js";
105
+ } from "./chunk-UIEQIJXP.js";
87
106
 
88
107
  // src/commands/log-append.ts
89
108
  import { readFile, stat } from "fs/promises";
@@ -1017,7 +1036,7 @@ import { readFile as readFile5 } from "fs/promises";
1017
1036
  import { existsSync as existsSync2 } from "fs";
1018
1037
  import { join as join5 } from "path";
1019
1038
  function validateKey(key) {
1020
- return CONFIG_KEYS.includes(key) || isValidWikiProfileKey(key) || isVaultSyncKey(key);
1039
+ return CONFIG_KEYS.includes(key) || isValidWikiProfileKey(key) || isVaultSyncKey(key) || isClipOutboxKey(key);
1021
1040
  }
1022
1041
  function displayConfigValue(key, value) {
1023
1042
  if (key === "SKILLWIKI_MCP_TOKEN") return value.length > 0 ? "TOKEN_SET" : "";
@@ -1044,6 +1063,12 @@ async function runConfigSet(input) {
1044
1063
  return { exitCode: ExitCode.INVALID_CONFIG_VALUE, result: err("INVALID_CONFIG_VALUE", { key: input.key, value: input.value, message: parsed.message }) };
1045
1064
  }
1046
1065
  }
1066
+ if (isClipOutboxKey(input.key)) {
1067
+ const parsed = parseClipOutboxKeyValue(input.key, input.value);
1068
+ if (!parsed.ok) {
1069
+ return { exitCode: ExitCode.INVALID_CONFIG_VALUE, result: err("INVALID_CONFIG_VALUE", { key: input.key, value: input.value, message: parsed.message }) };
1070
+ }
1071
+ }
1047
1072
  const filePath = configPath(input.home);
1048
1073
  try {
1049
1074
  let originalContent;
@@ -1130,7 +1155,7 @@ function isMcpOnlyLeaf(input) {
1130
1155
  }
1131
1156
 
1132
1157
  // src/doctor/runner.ts
1133
- import { existsSync as existsSync18 } from "fs";
1158
+ import { existsSync as existsSync19 } from "fs";
1134
1159
 
1135
1160
  // src/doctor/probes/environment.ts
1136
1161
  import { existsSync as existsSync4, lstatSync, readlinkSync } from "fs";
@@ -2102,7 +2127,9 @@ import { execSync as execSync4 } from "child_process";
2102
2127
  // src/utils/s3-mount-health.ts
2103
2128
  import { execSync as execSync3 } from "child_process";
2104
2129
  import { platform as platform2 } from "os";
2105
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync2, unlinkSync as unlinkSync2, readFileSync as readFile6 } from "fs";
2130
+ import { readFileSync as readFileSync6 } from "fs";
2131
+ import { readFile as readFile6, writeFile as writeFile2, unlink } from "fs/promises";
2132
+ import { randomUUID } from "crypto";
2106
2133
  import { join as join13 } from "path";
2107
2134
  var OS = platform2();
2108
2135
  function findRcloneMountPid() {
@@ -2260,36 +2287,45 @@ function detectFuseMount(vaultPath) {
2260
2287
  }
2261
2288
  return null;
2262
2289
  }
2263
- function writeTest(dir) {
2264
- const testFile = join13(dir, `.doctor-write-test-${process.pid}.tmp`);
2265
- const payload = `skillwiki doctor write test \u2014 ${Date.now()} \u2014 ${Math.random().toString(36).slice(2)}`;
2290
+ async function writeTest(dir, options = {}) {
2291
+ const testFile = join13(dir, options.fileName ?? `.doctor-write-test-${process.pid}.tmp`);
2292
+ const io = options.io ?? {
2293
+ write: (path, payload2) => writeFile2(path, payload2, "utf8"),
2294
+ read: (path) => readFile6(path, "utf8"),
2295
+ remove: (path) => unlink(path)
2296
+ };
2297
+ const payload = `skillwiki write test \u2014 ${(/* @__PURE__ */ new Date()).toISOString()} \u2014 ${randomUUID()}`;
2266
2298
  const start = Date.now();
2267
2299
  try {
2268
- writeFileSync2(testFile, payload, "utf8");
2300
+ await io.write(testFile, payload);
2269
2301
  } catch (e) {
2302
+ try {
2303
+ await io.remove(testFile);
2304
+ } catch {
2305
+ }
2270
2306
  return { success: false, writeMs: Date.now() - start, readMs: 0, size: 0, error: `write failed: ${e.message}` };
2271
2307
  }
2272
2308
  const writeMs = Date.now() - start;
2273
2309
  const readStart = Date.now();
2274
2310
  try {
2275
- const back = readFile6(testFile, "utf8");
2311
+ const back = await io.read(testFile);
2276
2312
  const readMs = Date.now() - readStart;
2277
2313
  if (back !== payload) {
2278
2314
  try {
2279
- unlinkSync2(testFile);
2315
+ await io.remove(testFile);
2280
2316
  } catch {
2281
2317
  }
2282
2318
  return { success: false, writeMs, readMs, size: Buffer.byteLength(payload, "utf8"), error: "content mismatch \u2014 wrote and read-back differ" };
2283
2319
  }
2284
2320
  } catch (e) {
2285
2321
  try {
2286
- unlinkSync2(testFile);
2322
+ await io.remove(testFile);
2287
2323
  } catch {
2288
2324
  }
2289
2325
  return { success: false, writeMs, readMs: Date.now() - readStart, size: 0, error: `read failed: ${e.message}` };
2290
2326
  }
2291
2327
  try {
2292
- unlinkSync2(testFile);
2328
+ await io.remove(testFile);
2293
2329
  } catch {
2294
2330
  }
2295
2331
  return { success: true, writeMs, readMs: Date.now() - readStart, size: Buffer.byteLength(payload, "utf8") };
@@ -2523,7 +2559,7 @@ function checkRcloneVersion(resolvedPath, vaultSyncInstalled, pushEnabled = true
2523
2559
  }
2524
2560
  return check("pass", "rclone_version", "rclone version", ver.raw);
2525
2561
  }
2526
- function checkWriteTest(resolvedPath) {
2562
+ async function checkWriteTest(resolvedPath) {
2527
2563
  if (!resolvedPath) {
2528
2564
  return check("pass", "s3_write_test", "S3 write test", "No vault path \u2014 check skipped");
2529
2565
  }
@@ -2535,7 +2571,7 @@ function checkWriteTest(resolvedPath) {
2535
2571
  if (!existsSync10(conceptsDir)) {
2536
2572
  return check("pass", "s3_write_test", "S3 write test", "no concepts/ dir to test \u2014 check skipped");
2537
2573
  }
2538
- const result = writeTest(conceptsDir);
2574
+ const result = await writeTest(conceptsDir);
2539
2575
  if (result.success) {
2540
2576
  const totalMs = result.writeMs + result.readMs;
2541
2577
  if (totalMs > 3e3) {
@@ -2618,13 +2654,13 @@ function checkVfsCacheHealth(resolvedPath) {
2618
2654
  }
2619
2655
  var s3MountHealthProbe = {
2620
2656
  id: "s3_mount_health",
2621
- run(ctx) {
2657
+ async run(ctx) {
2622
2658
  return [
2623
2659
  checkS3MountPerf(ctx.resolvedPath),
2624
2660
  checkS3MountFreshness(ctx.resolvedPath),
2625
2661
  checkRcloneFlagAudit(ctx.resolvedPath),
2626
2662
  checkRcloneVersion(ctx.resolvedPath, ctx.vsConfig.installed, ctx.vsConfig.pushEnabled !== false, ctx.mcpOnlyLeaf),
2627
- checkWriteTest(ctx.resolvedPath),
2663
+ await checkWriteTest(ctx.resolvedPath),
2628
2664
  checkVfsCacheHealth(ctx.resolvedPath)
2629
2665
  ];
2630
2666
  }
@@ -4422,6 +4458,156 @@ var mcpHandshakeProbe = {
4422
4458
  }
4423
4459
  };
4424
4460
 
4461
+ // src/doctor/probes/clip-outbox.ts
4462
+ import { existsSync as existsSync18, readFileSync as readFileSync12 } from "fs";
4463
+ import { execSync as execSync7 } from "child_process";
4464
+ import { platform as platform6 } from "os";
4465
+ import { join as join22 } from "path";
4466
+ var CLIP_CHECK_IDS = [
4467
+ "clip_config",
4468
+ "clip_frozen_mirror",
4469
+ "clip_push_isolation",
4470
+ "clip_outbox_root",
4471
+ "clip_watcher",
4472
+ "clip_storage_credentials",
4473
+ "clip_ready_channel",
4474
+ "clip_mirror_listener"
4475
+ ];
4476
+ function notConfigured() {
4477
+ return CLIP_CHECK_IDS.map(
4478
+ (id) => check("info", id, clipLabel(id), CLIP_NOT_CONFIGURED)
4479
+ );
4480
+ }
4481
+ function clipLabel(id) {
4482
+ switch (id) {
4483
+ case "clip_config":
4484
+ return "Clip outbox configuration";
4485
+ case "clip_frozen_mirror":
4486
+ return "Clip frozen mirror";
4487
+ case "clip_push_isolation":
4488
+ return "Clip push isolation";
4489
+ case "clip_outbox_root":
4490
+ return "Clip outbox root";
4491
+ case "clip_watcher":
4492
+ return "Clip outbox watcher";
4493
+ case "clip_storage_credentials":
4494
+ return "Clip storage credentials";
4495
+ case "clip_ready_channel":
4496
+ return "Clip ready channel";
4497
+ case "clip_mirror_listener":
4498
+ return "Clip mirror listener";
4499
+ default:
4500
+ return id;
4501
+ }
4502
+ }
4503
+ function launchdLoaded(label) {
4504
+ if (platform6() !== "darwin") return false;
4505
+ try {
4506
+ execSync7(`launchctl list ${label}`, {
4507
+ encoding: "utf8",
4508
+ timeout: 2e3,
4509
+ stdio: ["pipe", "ignore", "ignore"]
4510
+ });
4511
+ return true;
4512
+ } catch {
4513
+ return false;
4514
+ }
4515
+ }
4516
+ function watcherStatus(env, label, home, root) {
4517
+ const fixture = env.CLIP_WATCHER_FIXTURE;
4518
+ if (fixture === "loaded-enabled") return { loaded: true, enabled: true, kind: "production" };
4519
+ if (fixture === "stopped") return { loaded: false, enabled: false, kind: "production" };
4520
+ if (fixture === "retired-wiki-dev") return { loaded: true, enabled: true, kind: "retired" };
4521
+ if (fixture === "missing") return { loaded: false, enabled: false, kind: "unknown" };
4522
+ if (RETIRED_WATCHER_LABELS.includes(label)) {
4523
+ return { loaded: false, enabled: false, kind: "retired" };
4524
+ }
4525
+ if (!launchdLoaded(label)) {
4526
+ return { loaded: false, enabled: false, kind: "unknown" };
4527
+ }
4528
+ const plist = join22(home, "Library", "LaunchAgents", `${label}.plist`);
4529
+ try {
4530
+ const text = readFileSync12(plist, "utf8");
4531
+ const xmlRoot = xml(root);
4532
+ const matchesRoot = text.includes(`<key>WatchPaths</key><array><string>${xmlRoot}</string></array>`);
4533
+ const disabled = execSync7(`launchctl print-disabled gui/${process.getuid()}`, { encoding: "utf8", timeout: 2e3, stdio: ["ignore", "pipe", "ignore"] });
4534
+ const explicitlyDisabled = disabled.split("\n").some((line) => line.includes(`"${label}"`) && line.includes("true"));
4535
+ return { loaded: true, enabled: matchesRoot && !explicitlyDisabled, kind: "production" };
4536
+ } catch {
4537
+ return { loaded: true, enabled: false, kind: "unknown" };
4538
+ }
4539
+ }
4540
+ function pushLoaded(env) {
4541
+ if (env.CLIP_PUSH_FIXTURE === "loaded") return true;
4542
+ if (env.CLIP_PUSH_FIXTURE === "unloaded") return false;
4543
+ return launchdLoaded("com.karlchow.wiki-push");
4544
+ }
4545
+ function credentialPresent(env, ref) {
4546
+ if (env.CLIP_CREDENTIAL_FIXTURE === "present") return true;
4547
+ if (env.CLIP_CREDENTIAL_FIXTURE === "absent") return false;
4548
+ const value = env[ref];
4549
+ return typeof value === "string" && value.length > 0;
4550
+ }
4551
+ function listenerOk(env) {
4552
+ if (env.CLIP_LISTENER_FIXTURE === "ok") return true;
4553
+ return false;
4554
+ }
4555
+ function conditionalCreateEvidence(env) {
4556
+ return env.CLIP_CONDITIONAL_CREATE_FIXTURE === "ok";
4557
+ }
4558
+ var clipOutboxProbe = {
4559
+ id: "clip_outbox",
4560
+ async run(ctx) {
4561
+ if (ctx.mcpOnlyLeaf) {
4562
+ return CLIP_CHECK_IDS.map(
4563
+ (id) => check("info", id, clipLabel(id), MCP_ONLY_LEAF_SKIP)
4564
+ );
4565
+ }
4566
+ const env = ctx.input.env ?? process.env;
4567
+ const resolved = await loadClipOutboxConfig(ctx.input.home);
4568
+ if (!resolved.ok) {
4569
+ return [
4570
+ check("error", "clip_config", clipLabel("clip_config"), resolved.message),
4571
+ ...CLIP_CHECK_IDS.slice(1).map((id) => check("error", id, clipLabel(id), "clip configuration invalid"))
4572
+ ];
4573
+ }
4574
+ if (!resolved.enabled) {
4575
+ return notConfigured();
4576
+ }
4577
+ const cfg = resolved.config;
4578
+ const frozen = existsSync18(join22(cfg.mirrorRoot, ".WIKI_GIT_FROZEN"));
4579
+ const pushOn = ctx.vsConfig.pushEnabled !== false;
4580
+ const pushIsLoaded = pushLoaded(env);
4581
+ const watch = watcherStatus(env, cfg.watcherLabel, ctx.input.home, cfg.root);
4582
+ let s3Creds = credentialPresent(env, cfg.s3CredentialRef);
4583
+ let readyCreds = credentialPresent(env, cfg.readyCredentialRef);
4584
+ let condCreate = conditionalCreateEvidence(env);
4585
+ if (!env.CLIP_CREDENTIAL_FIXTURE) {
4586
+ try {
4587
+ const credentials = await loadClipCredentials(ctx.input.home, cfg, env);
4588
+ s3Creds = true;
4589
+ readyCreds = true;
4590
+ condCreate = await conditionalCreateProven(cfg, credentials.s3.endpoint);
4591
+ } catch {
4592
+ s3Creds = false;
4593
+ readyCreds = false;
4594
+ condCreate = false;
4595
+ }
4596
+ }
4597
+ const listener = listenerOk(env);
4598
+ return [
4599
+ check("pass", "clip_config", clipLabel("clip_config"), "clip_outbox.enabled=true; schema valid"),
4600
+ frozen ? check("pass", "clip_frozen_mirror", clipLabel("clip_frozen_mirror"), "frozen marker present") : check("error", "clip_frozen_mirror", clipLabel("clip_frozen_mirror"), "frozen marker missing; do not unfreeze"),
4601
+ !pushOn && !pushIsLoaded ? check("pass", "clip_push_isolation", clipLabel("clip_push_isolation"), "wiki-push disabled and unloaded") : check("error", "clip_push_isolation", clipLabel("clip_push_isolation"), "wiki-push must stay disabled and unloaded"),
4602
+ check("pass", "clip_outbox_root", clipLabel("clip_outbox_root"), "outbox and state roots are canonical and disjoint"),
4603
+ watch.kind === "retired" ? check("error", "clip_watcher", clipLabel("clip_watcher"), "retired wiki-dev or D8 job does not satisfy the clip watcher") : watch.loaded && watch.enabled && watch.kind === "production" ? check("pass", "clip_watcher", clipLabel("clip_watcher"), `loaded and enabled: ${PRODUCTION_WATCHER_LABEL}`) : check("error", "clip_watcher", clipLabel("clip_watcher"), "production clip watcher not loaded and enabled"),
4604
+ s3Creds && readyCreds && condCreate ? check("pass", "clip_storage_credentials", clipLabel("clip_storage_credentials"), "credential references present; conditional-create evidence available") : check("error", "clip_storage_credentials", clipLabel("clip_storage_credentials"), "missing credential reference or conditional-create evidence"),
4605
+ readyCreds ? check("pass", "clip_ready_channel", clipLabel("clip_ready_channel"), "ready URL and credential reference present") : check("error", "clip_ready_channel", clipLabel("clip_ready_channel"), "ready credential missing"),
4606
+ listener ? check("pass", "clip_mirror_listener", clipLabel("clip_mirror_listener"), "inbound production SSE listener configured") : check("error", "clip_mirror_listener", clipLabel("clip_mirror_listener"), "inbound SSE listener disabled or missing")
4607
+ ];
4608
+ }
4609
+ };
4610
+
4425
4611
  // src/doctor/probes/index.ts
4426
4612
  var DOCTOR_PROBES = [
4427
4613
  environmentProbe,
@@ -4436,7 +4622,8 @@ var DOCTOR_PROBES = [
4436
4622
  fuseStalenessProbe,
4437
4623
  activationMarkerProbe,
4438
4624
  dsStoreNoiseProbe,
4439
- mcpHandshakeProbe
4625
+ mcpHandshakeProbe,
4626
+ clipOutboxProbe
4440
4627
  ];
4441
4628
 
4442
4629
  // src/doctor/runner.ts
@@ -4447,7 +4634,7 @@ function resolveSnapshotGitWorktree(home) {
4447
4634
  const configured = resolveConfiguredSnapshotWorktree(home);
4448
4635
  if (configured) return configured;
4449
4636
  const defaultPath = "/root/wiki-git";
4450
- return existsSync18(defaultPath) ? defaultPath : void 0;
4637
+ return existsSync19(defaultPath) ? defaultPath : void 0;
4451
4638
  }
4452
4639
  var DoctorRunner = class {
4453
4640
  probes;
@@ -4527,6 +4714,9 @@ var DoctorRunner = class {
4527
4714
  if (summary.info > 0) summaryParts.push(`${summary.info} info`);
4528
4715
  summaryParts.push(`${summary.warn} warn`, `${summary.error} error`);
4529
4716
  lines.push(summaryParts.join(" \xB7 "));
4717
+ if (checks.some((c) => c.id === "clip_config" && c.detail === "clip channel not configured")) {
4718
+ lines.push("Clip setup is attended: skillwiki clip-outbox install-or-migrate refreshes the packaged plist; prove SeaweedFS conditional-create before enabling/loading the channel.");
4719
+ }
4530
4720
  const humanHint = redactMcpSecret(lines.join("\n"), auth.token);
4531
4721
  return { exitCode, result: ok({ checks, summary, humanHint }) };
4532
4722
  }
@@ -4536,7 +4726,7 @@ async function runDoctor(input) {
4536
4726
  }
4537
4727
 
4538
4728
  // src/utils/package-info.ts
4539
- import { readFileSync as readFileSync12 } from "fs";
4729
+ import { readFileSync as readFileSync13 } from "fs";
4540
4730
  function packageJsonCandidateUrls(baseUrl = import.meta.url) {
4541
4731
  return [
4542
4732
  new URL("../package.json", baseUrl),
@@ -4546,7 +4736,7 @@ function packageJsonCandidateUrls(baseUrl = import.meta.url) {
4546
4736
  function readCliPackageJson(baseUrl = import.meta.url) {
4547
4737
  for (const url of packageJsonCandidateUrls(baseUrl)) {
4548
4738
  try {
4549
- const pkg = JSON.parse(readFileSync12(url, "utf8"));
4739
+ const pkg = JSON.parse(readFileSync13(url, "utf8"));
4550
4740
  if (typeof pkg.version === "string") {
4551
4741
  return { ...pkg, version: pkg.version };
4552
4742
  }
@@ -4558,8 +4748,8 @@ function readCliPackageJson(baseUrl = import.meta.url) {
4558
4748
 
4559
4749
  // src/utils/vault-write-gates.ts
4560
4750
  import { execFileSync } from "child_process";
4561
- import { existsSync as existsSync19, readdirSync as readdirSync7, readFileSync as readFileSync13, statSync as statSync3 } from "fs";
4562
- import { join as join22, relative as relative2 } from "path";
4751
+ import { existsSync as existsSync20, readdirSync as readdirSync7, readFileSync as readFileSync14, statSync as statSync3 } from "fs";
4752
+ import { join as join23, relative as relative2 } from "path";
4563
4753
  var DEFAULT_DIRTY_VOLUME_THRESHOLD = 50;
4564
4754
  var DEFAULT_CAPTURE_BUDGET = 20;
4565
4755
  var DEFAULT_NO_DECISION_STREAK = 3;
@@ -4615,7 +4805,7 @@ function isEventLedgerPath(rel) {
4615
4805
  return n === "meta/log-events" || n.startsWith("meta/log-events/");
4616
4806
  }
4617
4807
  function countEventLedgerFiles(vault) {
4618
- return listFilesRecursive(join22(vault, "meta", "log-events")).length;
4808
+ return listFilesRecursive(join23(vault, "meta", "log-events")).length;
4619
4809
  }
4620
4810
  function measureDirtyVolume(vault) {
4621
4811
  const empty = (extra = {}) => ({
@@ -4631,7 +4821,7 @@ function measureDirtyVolume(vault) {
4631
4821
  is_git_repo: false,
4632
4822
  ...extra
4633
4823
  });
4634
- if (!existsSync19(vault) || !statSync3(vault).isDirectory()) {
4824
+ if (!existsSync20(vault) || !statSync3(vault).isDirectory()) {
4635
4825
  return empty();
4636
4826
  }
4637
4827
  const gitDir = git(vault, ["rev-parse", "--absolute-git-dir"]);
@@ -4675,8 +4865,8 @@ function measureDirtyVolume(vault) {
4675
4865
  if (!rel) continue;
4676
4866
  if (code === "??") {
4677
4867
  untracked += 1;
4678
- const abs = join22(vault, rel);
4679
- if (existsSync19(abs) && statSync3(abs).isDirectory()) {
4868
+ const abs = join23(vault, rel);
4869
+ if (existsSync20(abs) && statSync3(abs).isDirectory()) {
4680
4870
  const files = listFilesRecursive(abs);
4681
4871
  expanded += files.length;
4682
4872
  addBucket(rel, files.length);
@@ -4719,7 +4909,7 @@ function listFilesRecursive(dir) {
4719
4909
  }
4720
4910
  for (const name of entries) {
4721
4911
  if (name === ".git") continue;
4722
- const p = join22(dir, name);
4912
+ const p = join23(dir, name);
4723
4913
  try {
4724
4914
  const st = statSync3(p);
4725
4915
  if (st.isDirectory()) out.push(...listFilesRecursive(p));
@@ -4814,7 +5004,7 @@ var CAPTURE_HYGIENE_CONTRACT = `After each productive cycle (or when daily captu
4814
5004
  function listProjectDayCaptures(vault, project, day) {
4815
5005
  const found = [];
4816
5006
  const slug = project.replace(/^\[\[/, "").replace(/\]\]$/, "").trim();
4817
- if (!slug || !existsSync19(vault)) return found;
5007
+ if (!slug || !existsSync20(vault)) return found;
4818
5008
  const consider = (abs, rel) => {
4819
5009
  if (!rel.endsWith(".md")) return;
4820
5010
  const base = rel.split(/[/\\]/).pop() ?? "";
@@ -4831,7 +5021,7 @@ function listProjectDayCaptures(vault, project, day) {
4831
5021
  }
4832
5022
  if (norm.startsWith("raw/transcripts/")) {
4833
5023
  try {
4834
- const body = readFileSync13(abs, "utf8");
5024
+ const body = readFileSync14(abs, "utf8");
4835
5025
  if (body.includes(`project: ${slug}`) || body.includes(`project: "[[${slug}]]"`) || body.includes(`project: [[${slug}]]`)) {
4836
5026
  found.push(norm);
4837
5027
  } else if (base.includes(slug)) {
@@ -4842,7 +5032,7 @@ function listProjectDayCaptures(vault, project, day) {
4842
5032
  }
4843
5033
  };
4844
5034
  const walk = (dir, relBase) => {
4845
- if (!existsSync19(dir)) return;
5035
+ if (!existsSync20(dir)) return;
4846
5036
  let entries;
4847
5037
  try {
4848
5038
  entries = readdirSync7(dir);
@@ -4850,7 +5040,7 @@ function listProjectDayCaptures(vault, project, day) {
4850
5040
  return;
4851
5041
  }
4852
5042
  for (const name of entries) {
4853
- const abs = join22(dir, name);
5043
+ const abs = join23(dir, name);
4854
5044
  const rel = relBase ? `${relBase}/${name}` : name;
4855
5045
  try {
4856
5046
  const st = statSync3(abs);
@@ -4860,16 +5050,16 @@ function listProjectDayCaptures(vault, project, day) {
4860
5050
  }
4861
5051
  }
4862
5052
  };
4863
- walk(join22(vault, "raw", "transcripts"), "raw/transcripts");
4864
- walk(join22(vault, "projects", slug, "raw", "transcripts"), `projects/${slug}/raw/transcripts`);
4865
- walk(join22(vault, "projects", slug, "requirements"), `projects/${slug}/requirements`);
4866
- const workRoot = join22(vault, "projects", slug, "work");
4867
- if (existsSync19(workRoot)) {
5053
+ walk(join23(vault, "raw", "transcripts"), "raw/transcripts");
5054
+ walk(join23(vault, "projects", slug, "raw", "transcripts"), `projects/${slug}/raw/transcripts`);
5055
+ walk(join23(vault, "projects", slug, "requirements"), `projects/${slug}/requirements`);
5056
+ const workRoot = join23(vault, "projects", slug, "work");
5057
+ if (existsSync20(workRoot)) {
4868
5058
  try {
4869
5059
  for (const name of readdirSync7(workRoot)) {
4870
5060
  if (!name.startsWith(day)) continue;
4871
5061
  if (!/investigate|pilot-q|research|cycle|dev-loop/.test(name)) continue;
4872
- const abs = join22(workRoot, name);
5062
+ const abs = join23(workRoot, name);
4873
5063
  if (statSync3(abs).isDirectory()) {
4874
5064
  for (const f of listFilesRecursive(abs)) {
4875
5065
  const rel = relative2(vault, f).replace(/\\/g, "/");
@@ -4914,7 +5104,7 @@ function evaluateCaptureBudget(input) {
4914
5104
  return { allowed: true, reason: "under_budget", report };
4915
5105
  }
4916
5106
  function runWritePreflight(input) {
4917
- if (!input.vault || !existsSync19(input.vault)) {
5107
+ if (!input.vault || !existsSync20(input.vault)) {
4918
5108
  return err(GateError.VAULT_PATH_INVALID, { path: input.vault });
4919
5109
  }
4920
5110
  const want = new Set(input.checks ?? ["all"]);
@@ -4973,9 +5163,9 @@ function runWritePreflight(input) {
4973
5163
  }
4974
5164
 
4975
5165
  // src/commands/observe.ts
4976
- import { mkdir as mkdir3, writeFile as writeFile2 } from "fs/promises";
4977
- import { existsSync as existsSync20, statSync as statSync4 } from "fs";
4978
- import { join as join23 } from "path";
5166
+ import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
5167
+ import { existsSync as existsSync21, statSync as statSync4 } from "fs";
5168
+ import { join as join24 } from "path";
4979
5169
  import { createHash as createHash2 } from "crypto";
4980
5170
  var ALLOWED_KINDS = /* @__PURE__ */ new Set(["note", "bug", "task", "idea", "session-log"]);
4981
5171
  function slugify(text) {
@@ -4998,7 +5188,7 @@ async function runObserve(input) {
4998
5188
  result: err("SCHEME_REJECTED", { message: "Text must not be empty" })
4999
5189
  };
5000
5190
  }
5001
- if (!existsSync20(input.vault) || !statSync4(input.vault).isDirectory()) {
5191
+ if (!existsSync21(input.vault) || !statSync4(input.vault).isDirectory()) {
5002
5192
  return {
5003
5193
  exitCode: ExitCode.VAULT_PATH_INVALID,
5004
5194
  result: err("VAULT_PATH_INVALID", { path: input.vault })
@@ -5024,7 +5214,7 @@ async function runObserve(input) {
5024
5214
  };
5025
5215
  }
5026
5216
  }
5027
- const transcriptsDir = join23(input.vault, "raw", "transcripts");
5217
+ const transcriptsDir = join24(input.vault, "raw", "transcripts");
5028
5218
  try {
5029
5219
  await mkdir3(transcriptsDir, { recursive: true });
5030
5220
  } catch {
@@ -5036,7 +5226,7 @@ async function runObserve(input) {
5036
5226
  const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
5037
5227
  const slug = slugify(input.text);
5038
5228
  const fileName = `${today}-observation-${slug}.md`;
5039
- const filePath = join23(transcriptsDir, fileName);
5229
+ const filePath = join24(transcriptsDir, fileName);
5040
5230
  const body = `
5041
5231
  ${input.text.trim()}
5042
5232
  `;
@@ -5054,7 +5244,7 @@ ${input.text.trim()}
5054
5244
  frontmatterLines.push("---");
5055
5245
  const content = frontmatterLines.join("\n") + body;
5056
5246
  try {
5057
- await writeFile2(filePath, content, "utf8");
5247
+ await writeFile3(filePath, content, "utf8");
5058
5248
  } catch (e) {
5059
5249
  return {
5060
5250
  exitCode: ExitCode.WRITE_FAILED,
@@ -5077,8 +5267,8 @@ ${input.text.trim()}
5077
5267
 
5078
5268
  // src/commands/memory.ts
5079
5269
  import { createHash as createHash3 } from "crypto";
5080
- import { mkdir as mkdir4, readFile as readFile7, readdir as readdir2, stat as stat2, writeFile as writeFile3 } from "fs/promises";
5081
- import { basename as basename2, extname, join as join24, relative as relative3, sep as sep2 } from "path";
5270
+ import { mkdir as mkdir4, readFile as readFile7, readdir as readdir2, stat as stat2, writeFile as writeFile4 } from "fs/promises";
5271
+ import { basename as basename2, extname, join as join25, relative as relative3, sep as sep2 } from "path";
5082
5272
 
5083
5273
  // src/utils/memory-authority.ts
5084
5274
  var TIER_RANK = {
@@ -5197,9 +5387,9 @@ async function runMemoryIndex(input) {
5197
5387
  }
5198
5388
  const generatedAt = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
5199
5389
  const relCachePath = memoryCacheRelPath(input.project);
5200
- const absCachePath = join24(input.vault, relCachePath);
5201
- await mkdir4(join24(input.vault, ".skillwiki", "memory", input.project), { recursive: true });
5202
- await writeFile3(absCachePath, `${JSON.stringify({
5390
+ const absCachePath = join25(input.vault, relCachePath);
5391
+ await mkdir4(join25(input.vault, ".skillwiki", "memory", input.project), { recursive: true });
5392
+ await writeFile4(absCachePath, `${JSON.stringify({
5203
5393
  generated_at: generatedAt,
5204
5394
  project: input.project,
5205
5395
  topics: state.topics,
@@ -5390,7 +5580,7 @@ async function buildMemoryIndexState(pages, project) {
5390
5580
  }
5391
5581
  async function checkMemoryIndex(vault, project, current) {
5392
5582
  const relCachePath = memoryCacheRelPath(project);
5393
- const cacheText = await readIfExists(join24(vault, relCachePath));
5583
+ const cacheText = await readIfExists(join25(vault, relCachePath));
5394
5584
  if (!cacheText) {
5395
5585
  return {
5396
5586
  ok: true,
@@ -5799,7 +5989,7 @@ async function walkImportFiles(dir, out) {
5799
5989
  const entries = await readdir2(dir, { withFileTypes: true });
5800
5990
  for (const entry of entries) {
5801
5991
  if (entry.name === ".git" || entry.name === "node_modules") continue;
5802
- const path = join24(dir, entry.name);
5992
+ const path = join25(dir, entry.name);
5803
5993
  if (entry.isDirectory()) {
5804
5994
  await walkImportFiles(path, out);
5805
5995
  } else if (entry.isFile() && isImportCandidate(path)) {
@@ -5866,9 +6056,9 @@ async function writeImportCapture(vault, entry, today) {
5866
6056
  const content = hiddenString(entry, "__content");
5867
6057
  const project = hiddenString(entry, "__project");
5868
6058
  const relPath = await availableImportPath(vault, entry.proposed_path);
5869
- const absPath = join24(vault, relPath);
5870
- await mkdir4(join24(vault, "raw", "transcripts"), { recursive: true });
5871
- await writeFile3(absPath, renderImportCapture(entry, content, project, today), "utf8");
6059
+ const absPath = join25(vault, relPath);
6060
+ await mkdir4(join25(vault, "raw", "transcripts"), { recursive: true });
6061
+ await writeFile4(absPath, renderImportCapture(entry, content, project, today), "utf8");
5872
6062
  const validation = await runValidate({ file: absPath });
5873
6063
  return {
5874
6064
  relPath,
@@ -5883,7 +6073,7 @@ async function availableImportPath(vault, proposed) {
5883
6073
  const stem = proposed.slice(0, -ext.length);
5884
6074
  let candidate = proposed;
5885
6075
  let i = 2;
5886
- while (await readIfExists(join24(vault, candidate))) {
6076
+ while (await readIfExists(join25(vault, candidate))) {
5887
6077
  candidate = `${stem}-${i}${ext}`;
5888
6078
  i++;
5889
6079
  }
@@ -6068,10 +6258,10 @@ function memoryCacheRelPath(project) {
6068
6258
  }
6069
6259
  async function readMemoryCache(vault, project) {
6070
6260
  if (project) {
6071
- const projectCache = await readIfExists(join24(vault, memoryCacheRelPath(project)));
6261
+ const projectCache = await readIfExists(join25(vault, memoryCacheRelPath(project)));
6072
6262
  if (projectCache) return projectCache;
6073
6263
  }
6074
- return readIfExists(join24(vault, ".skillwiki", "memory-topics.json"));
6264
+ return readIfExists(join25(vault, ".skillwiki", "memory-topics.json"));
6075
6265
  }
6076
6266
  function dedupePages(pages) {
6077
6267
  const seen = /* @__PURE__ */ new Set();
@@ -6163,7 +6353,7 @@ function slugify2(value) {
6163
6353
 
6164
6354
  // src/commands/query.ts
6165
6355
  import { readFile as readFile9, stat as stat4 } from "fs/promises";
6166
- import { join as join26 } from "path";
6356
+ import { join as join27 } from "path";
6167
6357
 
6168
6358
  // src/utils/rrf.ts
6169
6359
  var RRF_K = 60;
@@ -6179,8 +6369,8 @@ function fuseRankings(lists, k = RRF_K) {
6179
6369
 
6180
6370
  // src/utils/vector-index.ts
6181
6371
  import { mkdir as mkdir5, readFile as readFile8, stat as stat3 } from "fs/promises";
6182
- import { join as join25 } from "path";
6183
- import { existsSync as existsSync21 } from "fs";
6372
+ import { join as join26 } from "path";
6373
+ import { existsSync as existsSync22 } from "fs";
6184
6374
  var VECTOR_INDEX_REL = ".skillwiki/vectors/index.json";
6185
6375
  var VECTOR_INDEX_SCHEMA = "skillwiki-tfidf-index/v1";
6186
6376
  function tokenize(text) {
@@ -6194,7 +6384,7 @@ function extractPageTokens(text) {
6194
6384
  return tokenize(`${title} ${body}`);
6195
6385
  }
6196
6386
  function vectorIndexPath(vault) {
6197
- return join25(vault, ...VECTOR_INDEX_REL.split("/"));
6387
+ return join26(vault, ...VECTOR_INDEX_REL.split("/"));
6198
6388
  }
6199
6389
  function termFreq(tokens) {
6200
6390
  const tf = /* @__PURE__ */ new Map();
@@ -6249,7 +6439,7 @@ async function buildVectorIndex(vault, now = (/* @__PURE__ */ new Date()).toISOS
6249
6439
  docs
6250
6440
  };
6251
6441
  const dest = vectorIndexPath(vault);
6252
- await mkdir5(join25(vault, ".skillwiki", "vectors"), { recursive: true });
6442
+ await mkdir5(join26(vault, ".skillwiki", "vectors"), { recursive: true });
6253
6443
  await atomicWriteText(dest, `${JSON.stringify(index)}
6254
6444
  `);
6255
6445
  return ok(index);
@@ -6292,7 +6482,7 @@ async function reindexPageInVectorIndex(vault, pageRelPath, now = (/* @__PURE__
6292
6482
  if (!normalizedPage.endsWith(".md")) {
6293
6483
  return err("USAGE", { message: `Page must be a .md file: ${pageRelPath}` });
6294
6484
  }
6295
- const absPath = join25(vault, ...normalizedPage.split("/"));
6485
+ const absPath = join26(vault, ...normalizedPage.split("/"));
6296
6486
  let text;
6297
6487
  try {
6298
6488
  text = await readFile8(absPath, "utf8");
@@ -6377,7 +6567,7 @@ async function reindexPageInVectorIndex(vault, pageRelPath, now = (/* @__PURE__
6377
6567
  }
6378
6568
  }
6379
6569
  const dest = vectorIndexPath(vault);
6380
- await mkdir5(join25(vault, ".skillwiki", "vectors"), { recursive: true });
6570
+ await mkdir5(join26(vault, ".skillwiki", "vectors"), { recursive: true });
6381
6571
  await atomicWriteText(dest, `${JSON.stringify(index)}
6382
6572
  `);
6383
6573
  return ok({
@@ -6395,8 +6585,8 @@ async function pruneVectorIndex(vault, opts) {
6395
6585
  const orphans = [];
6396
6586
  for (const docKey of Object.keys(index.docs)) {
6397
6587
  const normalizedKey = docKey.split(/\\|\//).join("/");
6398
- const absPath = join25(vault, ...normalizedKey.split("/"));
6399
- if (!existsSync21(absPath)) {
6588
+ const absPath = join26(vault, ...normalizedKey.split("/"));
6589
+ if (!existsSync22(absPath)) {
6400
6590
  orphans.push(normalizedKey);
6401
6591
  }
6402
6592
  }
@@ -6442,7 +6632,7 @@ async function pruneVectorIndex(vault, opts) {
6442
6632
  index.docs[docKey] = toTfIdf(termFreq(tokens), index.df, newPageCount);
6443
6633
  } else {
6444
6634
  try {
6445
- const text = await readFile8(join25(vault, ...docKey.split("/")), "utf8");
6635
+ const text = await readFile8(join26(vault, ...docKey.split("/")), "utf8");
6446
6636
  const tokens = extractPageTokens(text);
6447
6637
  index.docs[docKey] = toTfIdf(termFreq(tokens), index.df, newPageCount);
6448
6638
  } catch {
@@ -6452,7 +6642,7 @@ async function pruneVectorIndex(vault, opts) {
6452
6642
  }
6453
6643
  if (!opts?.dryRun) {
6454
6644
  const dest = vectorIndexPath(vault);
6455
- await mkdir5(join25(vault, ".skillwiki", "vectors"), { recursive: true });
6645
+ await mkdir5(join26(vault, ".skillwiki", "vectors"), { recursive: true });
6456
6646
  await atomicWriteText(dest, `${JSON.stringify(index)}
6457
6647
  `);
6458
6648
  }
@@ -6583,7 +6773,7 @@ async function runQuery(input) {
6583
6773
  }
6584
6774
  let pendingSources;
6585
6775
  if (input.includePending) {
6586
- const { runSourcesPending: runSourcesPending2 } = await import("./sources-QTQSZMST.js");
6776
+ const { runSourcesPending: runSourcesPending2 } = await import("./sources-D2MGP246.js");
6587
6777
  const pending = await runSourcesPending2({
6588
6778
  vault: input.vault,
6589
6779
  match: input.text,
@@ -6753,7 +6943,7 @@ function computeKeywordScore(terms, title, tags, body, relPath) {
6753
6943
  return score;
6754
6944
  }
6755
6945
  async function loadOrBuildGraph(vault) {
6756
- const graphPath = join26(vault, ".skillwiki", "graph.json");
6946
+ const graphPath = join27(vault, ".skillwiki", "graph.json");
6757
6947
  let needsBuild = false;
6758
6948
  try {
6759
6949
  const fileStat = await stat4(graphPath);
@@ -6842,7 +7032,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
6842
7032
  import { z } from "zod";
6843
7033
 
6844
7034
  // src/mcp/vault-resolve.ts
6845
- import { join as join27, resolve as resolve4 } from "path";
7035
+ import { join as join28, resolve as resolve4 } from "path";
6846
7036
 
6847
7037
  // src/mcp/allowlist.ts
6848
7038
  import { resolve as resolve3, sep as sep3 } from "path";
@@ -6904,7 +7094,7 @@ async function resolveMcpVault(input) {
6904
7094
  return ok({ vault: vaultPath, source });
6905
7095
  }
6906
7096
  function defaultGraphOut(vault) {
6907
- return join27(vault, ".skillwiki", "graph.json");
7097
+ return join28(vault, ".skillwiki", "graph.json");
6908
7098
  }
6909
7099
 
6910
7100
  // src/mcp/result-format.ts
@@ -6920,7 +7110,7 @@ function formatToolResult(payload) {
6920
7110
 
6921
7111
  // src/mcp/audit-log.ts
6922
7112
  import { appendFileSync, mkdirSync as mkdirSync2 } from "fs";
6923
- import { join as join28 } from "path";
7113
+ import { join as join29 } from "path";
6924
7114
  function auditEnabled() {
6925
7115
  const v = process.env.SKILLWIKI_MCP_AUDIT;
6926
7116
  if (v === "0" || v === "false") return false;
@@ -6932,7 +7122,7 @@ function auditSink() {
6932
7122
  function auditFilePath() {
6933
7123
  const custom = process.env.SKILLWIKI_MCP_AUDIT_FILE;
6934
7124
  if (custom && custom.length > 0) return custom;
6935
- return join28(resolveSkillwikiHome(), ".skillwiki", "mcp-audit.jsonl");
7125
+ return join29(resolveSkillwikiHome(), ".skillwiki", "mcp-audit.jsonl");
6936
7126
  }
6937
7127
  function auditMcpToolCall(entry) {
6938
7128
  if (!auditEnabled()) return;
@@ -6942,7 +7132,7 @@ function auditMcpToolCall(entry) {
6942
7132
  return;
6943
7133
  }
6944
7134
  const path = auditFilePath();
6945
- mkdirSync2(join28(path, ".."), { recursive: true });
7135
+ mkdirSync2(join29(path, ".."), { recursive: true });
6946
7136
  appendFileSync(path, line, "utf8");
6947
7137
  }
6948
7138
  async function runMcpToolHandler(tool, input, fn) {
@@ -7217,7 +7407,7 @@ function registerMcpMutatingTools(server) {
7217
7407
 
7218
7408
  // src/mcp/resources.ts
7219
7409
  import { readFile as readFile11 } from "fs/promises";
7220
- import { join as join30 } from "path";
7410
+ import { join as join31 } from "path";
7221
7411
  import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
7222
7412
 
7223
7413
  // src/mcp/lint-bucket.ts
@@ -7347,8 +7537,8 @@ async function fetchQueryPreview(input) {
7347
7537
 
7348
7538
  // src/mcp/graph-html.ts
7349
7539
  import { readFile as readFile10 } from "fs/promises";
7350
- import { join as join29 } from "path";
7351
- import { existsSync as existsSync22 } from "fs";
7540
+ import { join as join30 } from "path";
7541
+ import { existsSync as existsSync23 } from "fs";
7352
7542
  var TYPE_COLORS = {
7353
7543
  entities: "#e74c3c",
7354
7544
  concepts: "#27ae60",
@@ -7416,9 +7606,9 @@ ${nodeSvg}
7416
7606
  return { html, node_count: nodes.length, edge_count: edges.length, truncated };
7417
7607
  }
7418
7608
  async function fetchGraphHtmlReport(input) {
7419
- const graphPath = input.graphPath ?? join29(input.vault, ".skillwiki", "graph.json");
7609
+ const graphPath = input.graphPath ?? join30(input.vault, ".skillwiki", "graph.json");
7420
7610
  const maxNodes = Math.min(Math.max(10, input.maxNodes ?? 120), 500);
7421
- if (!existsSync22(graphPath)) {
7611
+ if (!existsSync23(graphPath)) {
7422
7612
  return {
7423
7613
  exitCode: ExitCode.FILE_NOT_FOUND,
7424
7614
  result: err("GRAPH_MISSING", { path: graphPath, hint: "Run skillwiki.graph_build first." })
@@ -7490,7 +7680,7 @@ async function fetchStaleSummary(input) {
7490
7680
 
7491
7681
  // src/mcp/resources.ts
7492
7682
  async function readVaultFile(vault, rel) {
7493
- return readFile11(join30(vault, rel), "utf8");
7683
+ return readFile11(join31(vault, rel), "utf8");
7494
7684
  }
7495
7685
  async function tailLines(text, lines) {
7496
7686
  const parts = text.split(/\r?\n/);
@@ -7576,7 +7766,7 @@ function registerMcpResources(server) {
7576
7766
  if (!v.ok) {
7577
7767
  return { contents: [{ uri: uri.href, mimeType: "text/plain", text: JSON.stringify(v) }] };
7578
7768
  }
7579
- const path = join30(v.data.vault, ".skillwiki", "graph.json");
7769
+ const path = join31(v.data.vault, ".skillwiki", "graph.json");
7580
7770
  try {
7581
7771
  const raw = await readFile11(path, "utf8");
7582
7772
  const graph = JSON.parse(raw);