skillwiki 0.10.110 → 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 (36) hide show
  1. package/dist/{chunk-5MV5SSRM.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-QU2CKXM4.js → chunk-HBJLFPQP.js} +91 -199
  5. package/dist/chunk-I2J3IJB7.js +54 -0
  6. package/dist/{chunk-WPJHDRTP.js → chunk-I6IRJCUJ.js} +12 -57
  7. package/dist/{chunk-NA3TZ4JN.js → chunk-JQV5KNPT.js} +8 -6
  8. package/dist/chunk-KWEYA3OE.js +60 -0
  9. package/dist/{chunk-KX5Y3GSX.js → chunk-MRPJ7X7W.js} +5 -3
  10. package/dist/{chunk-6X6PPQNI.js → chunk-OJJBZDPR.js} +162 -296
  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-R2DJ7IJ5.js → chunk-UIEQIJXP.js} +5 -336
  16. package/dist/chunk-X5GL2FCU.js +344 -0
  17. package/dist/chunk-ZRGZBAVS.js +98 -0
  18. package/dist/cli.js +308 -298
  19. package/dist/{index-projection-6XGESSHV.js → index-projection-2K672CBO.js} +5 -3
  20. package/dist/journal-QU5IDXQF.js +13 -0
  21. package/dist/{managed-write-preflight-JPOBVVSU.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/templates/launchd/com.karlchow.skillwiki-clip-outbox.plist +12 -13
  36. package/dist/sources-CLOF5VAT.js +0 -9
package/dist/cli.js CHANGED
@@ -1,7 +1,16 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ runFetchGuard,
4
+ runFetchGuardSync
5
+ } from "./chunk-I2J3IJB7.js";
6
+ import {
7
+ buildDeleteIntent,
8
+ normalizeVaultRelPath,
9
+ pathToIntentFilename,
10
+ writeDeleteIntent
11
+ } from "./chunk-QESNTTVY.js";
2
12
  import {
3
13
  CAPTURE_HYGIENE_CONTRACT,
4
- CLIP_NOT_CONFIGURED,
5
14
  DEFAULT_CAPTURE_BUDGET,
6
15
  DEFAULT_DIRTY_VOLUME_THRESHOLD,
7
16
  DEFAULT_MCP_URL,
@@ -22,7 +31,6 @@ import {
22
31
  guardProtectedVaultWrite,
23
32
  isEventLedgerPath,
24
33
  isFailedRunStatus,
25
- loadClipOutboxConfig,
26
34
  mcpAuthFromEnv,
27
35
  measureDirtyVolume,
28
36
  memoryAuthorityTiersRank,
@@ -67,7 +75,15 @@ import {
67
75
  upsertIndexEntry,
68
76
  vectorIndexStatus,
69
77
  withMcpClient
70
- } from "./chunk-6X6PPQNI.js";
78
+ } from "./chunk-OJJBZDPR.js";
79
+ import {
80
+ applySourceDisposition,
81
+ decodeSourceActionApproval,
82
+ encodeSourceActionApproval,
83
+ inventorySources,
84
+ planSourceDisposition,
85
+ runSourcesPending
86
+ } from "./chunk-JQV5KNPT.js";
71
87
  import {
72
88
  normalizeDistTag,
73
89
  readCache,
@@ -80,7 +96,7 @@ import {
80
96
  UNMANAGED_START,
81
97
  renderRootIndex,
82
98
  writeRootIndexProjection
83
- } from "./chunk-KX5Y3GSX.js";
99
+ } from "./chunk-MRPJ7X7W.js";
84
100
  import {
85
101
  FLEET_REL_PATH,
86
102
  REDACTED_MALFORMED_REFERENCE,
@@ -120,13 +136,10 @@ import {
120
136
  normalizeProjectSlug,
121
137
  normalizeRemoteRoot,
122
138
  parseActiveWorkPath,
123
- parseDotenvFile,
124
- parseDotenvText,
125
139
  parseJournalEnv,
126
140
  planAndMaybePruneRemoteObjects,
127
141
  planRawStructuralMove,
128
142
  probeS3Reachability,
129
- profileKey,
130
143
  readJournal,
131
144
  readLastOp,
132
145
  readSkillWikiConfig,
@@ -137,7 +150,6 @@ import {
137
150
  resolveFleetHostId,
138
151
  resolveInitTimePath,
139
152
  resolveRuntimePath,
140
- resolveSkillwikiHome,
141
153
  resolveWikiS3Remote,
142
154
  rewriteRawSourceReferences,
143
155
  runAudit,
@@ -171,22 +183,8 @@ import {
171
183
  snapshotterAliasForLocalHost,
172
184
  stageVaultContentChanges,
173
185
  supersedeStaleReviewRequiredJournals,
174
- taxonomyCommentForPage,
175
- writeDotenv
176
- } from "./chunk-QU2CKXM4.js";
177
- import {
178
- assertTargetInsideVault,
179
- atomicWriteText,
180
- prepareTypedPage
181
- } from "./chunk-WPJHDRTP.js";
182
- import {
183
- applySourceDisposition,
184
- decodeSourceActionApproval,
185
- encodeSourceActionApproval,
186
- inventorySources,
187
- planSourceDisposition,
188
- runSourcesPending
189
- } from "./chunk-NA3TZ4JN.js";
186
+ taxonomyCommentForPage
187
+ } from "./chunk-HBJLFPQP.js";
190
188
  import {
191
189
  authorizeRawOperation,
192
190
  buildSourceReferenceIndex,
@@ -203,31 +201,54 @@ import {
203
201
  resolveExistingRegularFileInsideVault,
204
202
  validateLogEvent,
205
203
  writeLogEvent
206
- } from "./chunk-5MV5SSRM.js";
204
+ } from "./chunk-5IBLXGLY.js";
205
+ import {
206
+ assertTargetInsideVault,
207
+ prepareTypedPage
208
+ } from "./chunk-I6IRJCUJ.js";
207
209
  import {
208
- ExitCode,
209
- MetaSchema,
210
- RawSourceSchema,
211
- TypedKnowledgeSchema,
212
- detectSchema,
213
- err,
214
210
  extractFrontmatter,
215
- isBlockedHost,
216
211
  mapWithConcurrency,
217
- ok,
218
212
  readPage,
219
213
  readPageCached,
220
214
  redactSensitiveContent,
221
215
  resolveReadOnlyVaultRoot,
222
- resolveSessionKind,
223
216
  scanSensitiveContent,
224
217
  scanVault,
225
218
  splitFrontmatter,
226
219
  vaultIoConcurrency
227
- } from "./chunk-R2DJ7IJ5.js";
220
+ } from "./chunk-X5GL2FCU.js";
221
+ import {
222
+ CLIP_MIGRATION_HINT,
223
+ refreshInstalledClipPlist
224
+ } from "./chunk-TDBUJUYH.js";
225
+ import {
226
+ CLIP_NOT_CONFIGURED,
227
+ loadClipOutboxConfig
228
+ } from "./chunk-6OQLBNKR.js";
229
+ import {
230
+ parseDotenvFile,
231
+ parseDotenvText,
232
+ profileKey,
233
+ resolveSkillwikiHome,
234
+ writeDotenv
235
+ } from "./chunk-PYPPG7RF.js";
236
+ import {
237
+ atomicWriteText
238
+ } from "./chunk-GQWCTJTU.js";
239
+ import {
240
+ ExitCode,
241
+ MetaSchema,
242
+ RawSourceSchema,
243
+ TypedKnowledgeSchema,
244
+ detectSchema,
245
+ err,
246
+ ok,
247
+ resolveSessionKind
248
+ } from "./chunk-UIEQIJXP.js";
228
249
 
229
250
  // src/cli.ts
230
- import { join as join45 } from "path";
251
+ import { join as join44 } from "path";
231
252
  import { Command } from "commander";
232
253
 
233
254
  // src/utils/output.ts
@@ -343,48 +364,6 @@ async function runHash(input) {
343
364
  };
344
365
  }
345
366
 
346
- // src/commands/fetch-guard.ts
347
- var REDACT_PARAMS = /* @__PURE__ */ new Set(["api_key", "token", "key", "auth", "password", "secret", "access_token"]);
348
- var PATH_TOKEN_RE = /[A-Fa-f0-9]{32,}|[A-Za-z0-9_\-]{40,}/g;
349
- function runFetchGuard(input) {
350
- return Promise.resolve(runFetchGuardSync(input));
351
- }
352
- function runFetchGuardSync(input) {
353
- let u;
354
- try {
355
- u = new URL(input.url);
356
- } catch {
357
- return { exitCode: ExitCode.MALFORMED_URL, result: err("MALFORMED_URL", { url: input.url }) };
358
- }
359
- const sanitized = sanitizeUrl(u);
360
- if (u.protocol !== "https:") {
361
- return {
362
- exitCode: ExitCode.SCHEME_REJECTED,
363
- result: err("SCHEME_REJECTED", { sanitized_url: sanitized, scheme: u.protocol })
364
- };
365
- }
366
- if (isBlockedHost(u.hostname)) {
367
- return {
368
- exitCode: ExitCode.HOST_BLOCKED,
369
- result: err("HOST_BLOCKED", { sanitized_url: sanitized, host: u.hostname })
370
- };
371
- }
372
- return { exitCode: ExitCode.OK, result: ok({ allowed: true, sanitized_url: sanitized, humanHint: `ALLOWED: ${sanitized}` }) };
373
- }
374
- function sanitizeUrl(u) {
375
- const clone = new URL(u.toString());
376
- if (clone.username || clone.password) {
377
- clone.username = "";
378
- clone.password = "";
379
- }
380
- for (const k of Array.from(clone.searchParams.keys())) {
381
- if (REDACT_PARAMS.has(k.toLowerCase())) clone.searchParams.set(k, "REDACTED");
382
- }
383
- let s = clone.toString();
384
- s = s.replace(PATH_TOKEN_RE, "REDACTED");
385
- return s;
386
- }
387
-
388
367
  // src/commands/eval.ts
389
368
  import { execFileSync } from "child_process";
390
369
  import { existsSync, mkdtempSync, rmSync } from "fs";
@@ -3604,14 +3583,76 @@ async function runClipOutboxStatus(home) {
3604
3583
  result: ok({ enabled: false, humanHint: CLIP_NOT_CONFIGURED })
3605
3584
  };
3606
3585
  }
3586
+ const { readJournal: readJournal2 } = await import("./journal-QU5IDXQF.js");
3587
+ let queue;
3588
+ try {
3589
+ queue = (await readJournal2(resolved.config.stateRoot)).map(({ captureId, state, reason, attempts }) => ({ captureId, state, reason, attempts }));
3590
+ } catch {
3591
+ return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: "clip journal unreadable; retain it for attended recovery" }) };
3592
+ }
3607
3593
  return {
3608
3594
  exitCode: ExitCode.OK,
3609
3595
  result: ok({
3610
3596
  enabled: true,
3611
- humanHint: `clip-outbox enabled root=${resolved.config.root} mode=${resolved.config.mode}`
3597
+ queue,
3598
+ humanHint: [`clip-outbox enabled root=${resolved.config.root} mode=${resolved.config.mode}`, ...queue.map((e) => `${e.captureId}: ${e.state}${e.reason ? ` (${e.reason})` : ""}; attempts=${e.attempts ?? 0}`)].join("\n")
3612
3599
  })
3613
3600
  };
3614
3601
  }
3602
+ async function runClipOutboxInstall(input) {
3603
+ try {
3604
+ const { migrateClipOutbox } = await import("./migrate-PIB4QA54.js");
3605
+ return { exitCode: ExitCode.OK, result: ok(await migrateClipOutbox(input)) };
3606
+ } catch (e) {
3607
+ return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: e instanceof Error ? e.message : "clip migration failed" }) };
3608
+ }
3609
+ }
3610
+ async function runClipOutboxWatch(home) {
3611
+ const resolved = await loadClipOutboxConfig(home);
3612
+ if (!resolved.ok || !resolved.enabled) return { exitCode: ExitCode.INVALID_CONFIG_VALUE, result: err("INVALID_CONFIG_VALUE", { message: resolved.ok ? CLIP_NOT_CONFIGURED : resolved.message }) };
3613
+ if (process.platform !== "darwin") return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: "clip-outbox watch requires macOS FSEvents" }) };
3614
+ let client;
3615
+ try {
3616
+ const { S3Client: S3Client3 } = await import("@aws-sdk/client-s3");
3617
+ const { loadClipCredentials, validateRuntime } = await import("./runtime-GLMI5OCT.js");
3618
+ const { createS3CreateOnlyPut, parseDestination } = await import("./upload-HTE62TOV.js");
3619
+ const { postReadyHint } = await import("./ready-S7F53Q2D.js");
3620
+ const { startClipWorker } = await import("./watcher-MHG46J3R.js");
3621
+ const cfg = resolved.config;
3622
+ const credentials = await loadClipCredentials(home, cfg);
3623
+ await validateRuntime(home, cfg, credentials.s3.endpoint);
3624
+ const destination = parseDestination(cfg.destination);
3625
+ client = new S3Client3({ endpoint: credentials.s3.endpoint, region: credentials.s3.region, credentials: credentials.s3, forcePathStyle: true, maxAttempts: 1 });
3626
+ let finish;
3627
+ const done = new Promise((r) => {
3628
+ finish = r;
3629
+ });
3630
+ let failed = false;
3631
+ const worker = await startClipWorker(cfg, {
3632
+ put: createS3CreateOnlyPut({ client, bucket: destination.bucket, prefix: destination.prefix }),
3633
+ ready: (hint) => postReadyHint({ url: cfg.readyUrl, token: credentials.readyToken, hint }),
3634
+ validate: () => validateRuntime(home, cfg, credentials.s3.endpoint),
3635
+ onError: () => {
3636
+ failed = true;
3637
+ finish();
3638
+ }
3639
+ });
3640
+ process.once("SIGTERM", finish);
3641
+ process.once("SIGINT", finish);
3642
+ try {
3643
+ await done;
3644
+ } finally {
3645
+ process.removeListener("SIGTERM", finish);
3646
+ process.removeListener("SIGINT", finish);
3647
+ await worker.stop();
3648
+ }
3649
+ return failed ? { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: "clip worker stopped; inspect configuration and retained journal" }) } : { exitCode: ExitCode.OK, result: ok({ humanHint: "Clip worker stopped; snapshots and journal retained." }) };
3650
+ } catch {
3651
+ return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: "clip worker startup failed; check configuration, protected credential references, conditional-create evidence and worker lock" }) };
3652
+ } finally {
3653
+ client?.destroy();
3654
+ }
3655
+ }
3615
3656
 
3616
3657
  // src/commands/connect.ts
3617
3658
  import { chmod, mkdir as mkdir5, readFile as readFile6, stat as stat3 } from "fs/promises";
@@ -3922,50 +3963,8 @@ async function runConnect(input) {
3922
3963
  }
3923
3964
 
3924
3965
  // src/commands/archive.ts
3925
- import { rename as rename2, mkdir as mkdir7, readFile as readFile8 } from "fs/promises";
3926
- import { join as join20, dirname as dirname5 } from "path";
3927
-
3928
- // src/utils/delete-intent.ts
3929
- import { mkdir as mkdir6, writeFile as writeFile4, readdir as readdir4, readFile as readFile7 } from "fs/promises";
3930
- import { join as join19 } from "path";
3931
- var DELETE_INTENT_SCHEMA = "vault-delete-intent/v1";
3932
- var DELETE_INTENT_DIR = "meta/delete-intents";
3933
- function normalizeVaultRelPath(path) {
3934
- const p = path.replace(/\\/g, "/").replace(/^\/+/, "");
3935
- if (!p || p.includes("..") || p.startsWith(".git/")) {
3936
- throw new Error(`invalid vault-relative path: ${path}`);
3937
- }
3938
- return p;
3939
- }
3940
- function pathToIntentFilename(path) {
3941
- const p = normalizeVaultRelPath(path);
3942
- return `${p.replace(/\//g, "__")}.json`;
3943
- }
3944
- function intentHostId() {
3945
- return process.env.SKILLWIKI_HOST_ID ?? process.env.AGENT_HOST_ID ?? "unknown";
3946
- }
3947
- function buildDeleteIntent(input) {
3948
- return {
3949
- schema: DELETE_INTENT_SCHEMA,
3950
- path: normalizeVaultRelPath(input.path),
3951
- action: input.action,
3952
- created: input.created ?? (/* @__PURE__ */ new Date()).toISOString(),
3953
- host: input.host ?? intentHostId(),
3954
- actor: input.actor,
3955
- reason: input.reason,
3956
- source: input.source,
3957
- expires: input.expires ?? null
3958
- };
3959
- }
3960
- async function writeDeleteIntent(vault, intent) {
3961
- const dir = join19(vault, DELETE_INTENT_DIR);
3962
- await mkdir6(dir, { recursive: true });
3963
- const rel = `${DELETE_INTENT_DIR}/${pathToIntentFilename(intent.path)}`;
3964
- await writeFile4(join19(vault, rel), JSON.stringify(intent, null, 2) + "\n", "utf8");
3965
- return rel;
3966
- }
3967
-
3968
- // src/commands/archive.ts
3966
+ import { rename as rename2, mkdir as mkdir6, readFile as readFile7 } from "fs/promises";
3967
+ import { join as join19, dirname as dirname5 } from "path";
3969
3968
  function countWikilinks(body, slug) {
3970
3969
  const escaped = slug.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3971
3970
  const re = new RegExp(`\\[\\[${escaped}(?:[|#][^\\]]*)?\\]\\]`, "g");
@@ -4001,7 +4000,7 @@ async function runArchive(input) {
4001
4000
  const slug = relPath.replace(/\.md$/, "").split("/").pop();
4002
4001
  const rawArchive = isRaw ? lifecycleDestination(relPath, "archive") : void 0;
4003
4002
  if (rawArchive && !rawArchive.ok) return { exitCode: ExitCode.USAGE, result: rawArchive };
4004
- const archivePath = isRaw ? rawArchive.data : join20("_archive", relPath).replace(/\\/g, "/");
4003
+ const archivePath = isRaw ? rawArchive.data : join19("_archive", relPath).replace(/\\/g, "/");
4005
4004
  const remoteRoot = normalizeRemoteRoot(input.remote);
4006
4005
  const remoteObjectPath = buildRemoteObjectPath(remoteRoot, relPath);
4007
4006
  let cascade;
@@ -4031,7 +4030,7 @@ async function runArchive(input) {
4031
4030
  const indexRefs = [];
4032
4031
  if (!isRaw) {
4033
4032
  try {
4034
- const idx = await readFile8(join20(input.vault, "index.md"), "utf8");
4033
+ const idx = await readFile7(join19(input.vault, "index.md"), "utf8");
4035
4034
  idx.split("\n").forEach((line, i) => {
4036
4035
  if (line.includes(`[[${slug}]]`)) indexRefs.push({ line: i + 1, text: line });
4037
4036
  });
@@ -4089,8 +4088,8 @@ async function runArchive(input) {
4089
4088
  const rewrittenCascadePages = [];
4090
4089
  if ((input.cascade || isRaw) && input.apply && cascade) {
4091
4090
  for (const ref of cascade.source_array_refs) {
4092
- const absPath = join20(input.vault, ref.page);
4093
- const text = await readFile8(absPath, "utf8");
4091
+ const absPath = join19(input.vault, ref.page);
4092
+ const text = await readFile7(absPath, "utf8");
4094
4093
  if (!arraysEqual(ref.sources_after, ref.sources_before)) {
4095
4094
  let updated;
4096
4095
  if (isRaw) {
@@ -4116,8 +4115,8 @@ ${fmRewritten}
4116
4115
  if (isRaw) {
4117
4116
  for (const ref of cascade.citation_refs) {
4118
4117
  if (cascade.source_array_refs.some((sourceRef) => sourceRef.page === ref.page)) continue;
4119
- const absPath = join20(input.vault, ref.page);
4120
- const original = await readFile8(absPath, "utf8");
4118
+ const absPath = join19(input.vault, ref.page);
4119
+ const original = await readFile7(absPath, "utf8");
4121
4120
  const updated = rewriteRawSourceReferences(original, relPath, archivePath).text;
4122
4121
  if (updated !== original) {
4123
4122
  const write = await safeWritePage(absPath, updated);
@@ -4128,13 +4127,13 @@ ${fmRewritten}
4128
4127
  }
4129
4128
  }
4130
4129
  if (!isRaw) {
4131
- await mkdir7(dirname5(join20(input.vault, archivePath)), { recursive: true });
4132
- await rename2(join20(input.vault, relPath), join20(input.vault, archivePath));
4130
+ await mkdir6(dirname5(join19(input.vault, archivePath)), { recursive: true });
4131
+ await rename2(join19(input.vault, relPath), join19(input.vault, archivePath));
4133
4132
  }
4134
4133
  let indexUpdated = false;
4135
4134
  if (!isRaw) {
4136
- const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-6XGESSHV.js");
4137
- const before = await readFile8(join20(input.vault, "index.md"), "utf8").catch(() => "");
4135
+ const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-2K672CBO.js");
4136
+ const before = await readFile7(join19(input.vault, "index.md"), "utf8").catch(() => "");
4138
4137
  const fullTarget = relPath.replace(/\.md$/, "");
4139
4138
  const bare = fullTarget.split("/").pop() ?? fullTarget;
4140
4139
  const hadIndexEntry = before.includes(`[[${fullTarget}]]`) || before.includes(`[[${bare}]]`);
@@ -4188,7 +4187,7 @@ ${fmRewritten}
4188
4187
 
4189
4188
  // src/commands/remove.ts
4190
4189
  import { unlink as unlink2, access } from "fs/promises";
4191
- import { join as join21 } from "path";
4190
+ import { join as join20 } from "path";
4192
4191
  async function pathExists(abs) {
4193
4192
  try {
4194
4193
  await access(abs);
@@ -4214,7 +4213,7 @@ async function runRemove(input) {
4214
4213
  if (!relPath) {
4215
4214
  try {
4216
4215
  const candidate = normalizeVaultRelPath(input.page);
4217
- if (await pathExists(join21(input.vault, candidate))) {
4216
+ if (await pathExists(join20(input.vault, candidate))) {
4218
4217
  relPath = candidate;
4219
4218
  }
4220
4219
  } catch {
@@ -4252,12 +4251,12 @@ async function runRemove(input) {
4252
4251
  reason: input.reason
4253
4252
  });
4254
4253
  const tombstonePath = await writeDeleteIntent(input.vault, intent);
4255
- await unlink2(join21(input.vault, relPath));
4254
+ await unlink2(join20(input.vault, relPath));
4256
4255
  if (relPath.endsWith(".md") && !relPath.startsWith("raw/")) {
4257
- const { readFile: readFile24 } = await import("fs/promises");
4256
+ const { readFile: readFile23 } = await import("fs/promises");
4258
4257
  const { join: pathJoin } = await import("path");
4259
- const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-6XGESSHV.js");
4260
- const before = await readFile24(pathJoin(input.vault, "index.md"), "utf8").catch(() => "");
4258
+ const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-2K672CBO.js");
4259
+ const before = await readFile23(pathJoin(input.vault, "index.md"), "utf8").catch(() => "");
4261
4260
  const fullTarget = relPath.replace(/\.md$/, "");
4262
4261
  const bare = fullTarget.split("/").pop() ?? fullTarget;
4263
4262
  const hadIndexEntry = before.includes(`[[${fullTarget}]]`) || before.includes(`[[${bare}]]`);
@@ -4606,7 +4605,7 @@ ${migratedBody}${newFooter}`;
4606
4605
 
4607
4606
  // src/commands/update.ts
4608
4607
  import { execSync } from "child_process";
4609
- import { join as join22 } from "path";
4608
+ import { join as join21 } from "path";
4610
4609
  function parseCoreSemver(version) {
4611
4610
  const m = version.match(/^(\d+)\.(\d+)\.(\d+)/);
4612
4611
  if (!m) return null;
@@ -4650,6 +4649,8 @@ function migrationNotesForUpgrade(previousVersion, newVersion) {
4650
4649
  "- frozen-leaf hosts write via HTTP MCP only; do not local-write raw/transcripts/ or vault git"
4651
4650
  );
4652
4651
  }
4652
+ const next = parseCoreSemver(newVersion);
4653
+ if (next && isAtLeast(next, 0, 10, 111)) notes.push(CLIP_MIGRATION_HINT);
4653
4654
  return notes;
4654
4655
  }
4655
4656
  function resolveGlobalSkillsRoot() {
@@ -4658,7 +4659,7 @@ function resolveGlobalSkillsRoot() {
4658
4659
  encoding: "utf8",
4659
4660
  timeout: 5e3
4660
4661
  }).trim();
4661
- return join22(globalRoot, "skillwiki", "skills");
4662
+ return join21(globalRoot, "skillwiki", "skills");
4662
4663
  } catch {
4663
4664
  return null;
4664
4665
  }
@@ -4686,7 +4687,7 @@ async function runUpdate(input) {
4686
4687
  const pkg2 = readCliPackageJson();
4687
4688
  const currentVersion = pkg2.version;
4688
4689
  const tag = normalizeDistTag(input.distTag);
4689
- const target = join22(input.home, ".claude", "skills");
4690
+ const target = join21(input.home, ".claude", "skills");
4690
4691
  let latest;
4691
4692
  try {
4692
4693
  latest = execSync(`npm view skillwiki@${tag} version`, {
@@ -4719,7 +4720,8 @@ async function runUpdate(input) {
4719
4720
  version_warnings: [],
4720
4721
  skills_refreshed: false,
4721
4722
  deferred_to_plugin: false,
4722
- humanHint: `Already on npm@${tag}: v${currentVersion}`
4723
+ humanHint: `Already on npm@${tag}: v${currentVersion}
4724
+ ${CLIP_MIGRATION_HINT}`
4723
4725
  })
4724
4726
  };
4725
4727
  }
@@ -4750,6 +4752,12 @@ async function runUpdate(input) {
4750
4752
  for (const line of migrationNotesForUpgrade(currentVersion, latest)) {
4751
4753
  hintLines.push(line);
4752
4754
  }
4755
+ try {
4756
+ const clipHint = await refreshInstalledClipPlist(input.home);
4757
+ if (clipHint) hintLines.push(clipHint);
4758
+ } catch (e) {
4759
+ hintLines.push(`clip plist refresh skipped: ${e instanceof Error ? e.message : "migration failed"}`);
4760
+ }
4753
4761
  return {
4754
4762
  exitCode: ExitCode.OK,
4755
4763
  result: ok({
@@ -4767,13 +4775,13 @@ async function runUpdate(input) {
4767
4775
  // src/commands/self-update.ts
4768
4776
  import { execSync as execSync2 } from "child_process";
4769
4777
  import { existsSync as existsSync8, readFileSync as readFileSync11 } from "fs";
4770
- import { join as join23 } from "path";
4778
+ import { join as join22 } from "path";
4771
4779
  var DEFAULT_SOURCE_ROOT_SUFFIX = "/Desktop/code/llm-wiki";
4772
4780
  async function runSelfUpdate(input) {
4773
4781
  const currentVersion = readCliPackageJson().version;
4774
4782
  const sourceRoot = input.sourceRoot ?? `${input.home}${DEFAULT_SOURCE_ROOT_SUFFIX}`;
4775
4783
  const distTag = normalizeDistTag(input.distTag);
4776
- const localPkgPath = join23(sourceRoot, "packages", "cli", "package.json");
4784
+ const localPkgPath = join22(sourceRoot, "packages", "cli", "package.json");
4777
4785
  const hasLocalSource = existsSync8(localPkgPath);
4778
4786
  if (input.check) {
4779
4787
  let availableVersion = null;
@@ -4905,21 +4913,21 @@ async function runSelfUpdate(input) {
4905
4913
  }
4906
4914
 
4907
4915
  // src/commands/transcripts.ts
4908
- import { readdir as readdir5, stat as stat4, readFile as readFile10 } from "fs/promises";
4909
- import { join as join24 } from "path";
4916
+ import { readdir as readdir4, stat as stat4, readFile as readFile9 } from "fs/promises";
4917
+ import { join as join23 } from "path";
4910
4918
  async function runTranscripts(input) {
4911
- const dir = join24(input.vault, "raw", "transcripts");
4919
+ const dir = join23(input.vault, "raw", "transcripts");
4912
4920
  let entries;
4913
4921
  try {
4914
- entries = await readdir5(dir, { withFileTypes: true });
4922
+ entries = await readdir4(dir, { withFileTypes: true });
4915
4923
  } catch {
4916
4924
  return { exitCode: ExitCode.VAULT_PATH_INVALID, result: { ok: false, error: "VAULT_PATH_INVALID", detail: `raw/transcripts/ not found: ${dir}` } };
4917
4925
  }
4918
4926
  const transcripts = [];
4919
4927
  for (const entry of entries) {
4920
4928
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
4921
- const filePath = join24(dir, entry.name);
4922
- const content = await readFile10(filePath, "utf8");
4929
+ const filePath = join23(dir, entry.name);
4930
+ const content = await readFile9(filePath, "utf8");
4923
4931
  const fm = extractFrontmatter(content);
4924
4932
  if (!fm.ok) continue;
4925
4933
  const ingested = typeof fm.data.ingested === "string" ? fm.data.ingested : "";
@@ -4936,8 +4944,8 @@ async function runTranscripts(input) {
4936
4944
  }
4937
4945
 
4938
4946
  // src/commands/claims-audit.ts
4939
- import { readFile as readFile11 } from "fs/promises";
4940
- import { join as join25 } from "path";
4947
+ import { readFile as readFile10 } from "fs/promises";
4948
+ import { join as join24 } from "path";
4941
4949
  function safeProjectPresentation(raw) {
4942
4950
  if (safeDiagnosticValue(raw) === REDACTED_MALFORMED_REFERENCE) {
4943
4951
  return REDACTED_MALFORMED_REFERENCE;
@@ -4977,9 +4985,9 @@ async function runClaimsAudit(input) {
4977
4985
  return !input.project || slugByDir.get(relDir) === input.project;
4978
4986
  });
4979
4987
  const claimSourceResults = await mapWithConcurrency(scopedSpecDirs, vaultIoConcurrency(), async (relDir) => {
4980
- const specPath = join25(input.vault, relDir, "spec.md");
4988
+ const specPath = join24(input.vault, relDir, "spec.md");
4981
4989
  try {
4982
- const specText = await readFile11(specPath, "utf8");
4990
+ const specText = await readFile10(specPath, "utf8");
4983
4991
  const fm = extractFrontmatter(specText);
4984
4992
  if (!fm.ok) return null;
4985
4993
  return {
@@ -5073,10 +5081,10 @@ async function runClaimsAudit(input) {
5073
5081
  }
5074
5082
 
5075
5083
  // src/commands/compound.ts
5076
- import { writeFile as writeFile6, mkdir as mkdir8, readdir as readdir6, unlink as unlink3 } from "fs/promises";
5077
- import { join as join26 } from "path";
5084
+ import { writeFile as writeFile5, mkdir as mkdir7, readdir as readdir5, unlink as unlink3 } from "fs/promises";
5085
+ import { join as join25 } from "path";
5078
5086
  import { existsSync as existsSync9 } from "fs";
5079
- import { readFile as readFile12 } from "fs/promises";
5087
+ import { readFile as readFile11 } from "fs/promises";
5080
5088
  var RETRO_HEADING_RE = /^## \[(\d{4}-\d{2}-\d{2})(?:\s+[^\]]+)?\] retro \| loop cycle(?: (\d+))?: (.+)$/;
5081
5089
  var FIELD_RE = {
5082
5090
  improve: /^-\s+\*?\*?Improve:?\*?\*?\s*(.+)$/m,
@@ -5174,17 +5182,17 @@ function extractRetroFields(date, cycleName, block) {
5174
5182
  };
5175
5183
  }
5176
5184
  async function runCompound(input) {
5177
- const logPath = join26(input.vault, "log.md");
5185
+ const logPath = join25(input.vault, "log.md");
5178
5186
  let logText;
5179
5187
  try {
5180
- logText = await readFile12(logPath, "utf8");
5188
+ logText = await readFile11(logPath, "utf8");
5181
5189
  } catch {
5182
5190
  return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path: logPath }) };
5183
5191
  }
5184
5192
  const entries = parseRetroEntries(logText);
5185
5193
  const promoted = [];
5186
5194
  const skipped = [];
5187
- const compoundDir = join26(input.vault, "projects", input.project, "compound");
5195
+ const compoundDir = join25(input.vault, "projects", input.project, "compound");
5188
5196
  for (const entry of entries) {
5189
5197
  const generalizeValue = entry.generalize.trim();
5190
5198
  if (!/^yes/i.test(generalizeValue)) {
@@ -5192,7 +5200,7 @@ async function runCompound(input) {
5192
5200
  continue;
5193
5201
  }
5194
5202
  const slug = slugify(entry.cycleName);
5195
- const compoundPath = join26(compoundDir, `${slug}.md`);
5203
+ const compoundPath = join25(compoundDir, `${slug}.md`);
5196
5204
  if (existsSync9(compoundPath)) {
5197
5205
  skipped.push(entry.date);
5198
5206
  continue;
@@ -5232,9 +5240,9 @@ async function runCompound(input) {
5232
5240
  const content = frontmatter + "\n" + body;
5233
5241
  if (!input.dryRun) {
5234
5242
  if (!existsSync9(compoundDir)) {
5235
- await mkdir8(compoundDir, { recursive: true });
5243
+ await mkdir7(compoundDir, { recursive: true });
5236
5244
  }
5237
- await writeFile6(compoundPath, content, "utf8");
5245
+ await writeFile5(compoundPath, content, "utf8");
5238
5246
  }
5239
5247
  promoted.push(`${slug}.md`);
5240
5248
  }
@@ -5253,7 +5261,7 @@ async function runCompound(input) {
5253
5261
  };
5254
5262
  }
5255
5263
  async function runCompoundDelete(input) {
5256
- const projectDir = join26(input.vault, "projects", input.project);
5264
+ const projectDir = join25(input.vault, "projects", input.project);
5257
5265
  if (!existsSync9(projectDir)) {
5258
5266
  return {
5259
5267
  exitCode: ExitCode.PROJECT_NOT_FOUND,
@@ -5261,7 +5269,7 @@ async function runCompoundDelete(input) {
5261
5269
  };
5262
5270
  }
5263
5271
  const entryName = input.entry.replace(/\.md$/, "");
5264
- const compoundPath = join26(projectDir, "compound", `${entryName}.md`);
5272
+ const compoundPath = join25(projectDir, "compound", `${entryName}.md`);
5265
5273
  if (!existsSync9(compoundPath)) {
5266
5274
  return {
5267
5275
  exitCode: ExitCode.FILE_NOT_FOUND,
@@ -5295,7 +5303,7 @@ knowledge.md regenerated`
5295
5303
  };
5296
5304
  }
5297
5305
  async function runCompoundList(input) {
5298
- const compoundDir = join26(input.vault, "projects", input.project, "compound");
5306
+ const compoundDir = join25(input.vault, "projects", input.project, "compound");
5299
5307
  if (!existsSync9(compoundDir)) {
5300
5308
  return {
5301
5309
  exitCode: ExitCode.OK,
@@ -5310,7 +5318,7 @@ no compound directory found`
5310
5318
  }
5311
5319
  let dirents;
5312
5320
  try {
5313
- dirents = await readdir6(compoundDir, { withFileTypes: true });
5321
+ dirents = await readdir5(compoundDir, { withFileTypes: true });
5314
5322
  } catch {
5315
5323
  return {
5316
5324
  exitCode: ExitCode.OK,
@@ -5326,10 +5334,10 @@ could not read compound directory`
5326
5334
  const entries = [];
5327
5335
  for (const dirent of dirents) {
5328
5336
  if (!dirent.isFile() || !dirent.name.endsWith(".md")) continue;
5329
- const filePath = join26(compoundDir, dirent.name);
5337
+ const filePath = join25(compoundDir, dirent.name);
5330
5338
  let text;
5331
5339
  try {
5332
- text = await readFile12(filePath, "utf8");
5340
+ text = await readFile11(filePath, "utf8");
5333
5341
  } catch {
5334
5342
  continue;
5335
5343
  }
@@ -5358,8 +5366,8 @@ no compound entries found`;
5358
5366
  }
5359
5367
 
5360
5368
  // src/commands/session-brief.ts
5361
- import { mkdir as mkdir9, readFile as readFile13, writeFile as writeFile7 } from "fs/promises";
5362
- import { join as join27, relative, sep } from "path";
5369
+ import { mkdir as mkdir8, readFile as readFile12, writeFile as writeFile6 } from "fs/promises";
5370
+ import { join as join26, relative, sep } from "path";
5363
5371
  var MAX_WORDS = 900;
5364
5372
  async function runSessionBrief(input) {
5365
5373
  const { root: scanRoot } = resolveReadOnlyVaultRoot(input.vault);
@@ -5473,7 +5481,7 @@ async function resolveProject(input) {
5473
5481
  const envProject = input.env?.SKILLWIKI_PROJECT;
5474
5482
  if (envProject) return envProject;
5475
5483
  const cwd = input.cwd ?? process.cwd();
5476
- const projectDotenv = await readProjectSlug(join27(cwd, ".skillwiki", ".env"));
5484
+ const projectDotenv = await readProjectSlug(join26(cwd, ".skillwiki", ".env"));
5477
5485
  if (projectDotenv) return projectDotenv;
5478
5486
  const inferred = inferProjectFromPath(input.vault, cwd);
5479
5487
  if (inferred) return inferred;
@@ -5482,7 +5490,7 @@ async function resolveProject(input) {
5482
5490
  async function readProjectSlug(file) {
5483
5491
  let text;
5484
5492
  try {
5485
- text = await readFile13(file, "utf8");
5493
+ text = await readFile12(file, "utf8");
5486
5494
  } catch {
5487
5495
  return void 0;
5488
5496
  }
@@ -5573,7 +5581,7 @@ async function loadTrendPages(typedPages, pathPattern) {
5573
5581
  return out;
5574
5582
  }
5575
5583
  async function loadSessionPins(vault, project) {
5576
- const text = await readIfExists(join27(vault, "meta", "session-pins.md"));
5584
+ const text = await readIfExists(join26(vault, "meta", "session-pins.md"));
5577
5585
  if (!text) return [];
5578
5586
  const fm = extractFrontmatter(text);
5579
5587
  if (!fm.ok) return [];
@@ -5719,7 +5727,7 @@ function satelliteHealthWarning(health) {
5719
5727
  return null;
5720
5728
  }
5721
5729
  async function loadHealthWarnings(vault) {
5722
- const text = await readIfExists(join27(vault, ".skillwiki", "health.json"));
5730
+ const text = await readIfExists(join26(vault, ".skillwiki", "health.json"));
5723
5731
  if (!text) return [];
5724
5732
  try {
5725
5733
  const parsed = JSON.parse(text);
@@ -5732,7 +5740,7 @@ async function loadHealthWarnings(vault) {
5732
5740
  }
5733
5741
  }
5734
5742
  async function loadMemoryTopics(vault, project) {
5735
- const text = await readIfExists(join27(vault, ".skillwiki", "memory", project, "topics.json"));
5743
+ const text = await readIfExists(join26(vault, ".skillwiki", "memory", project, "topics.json"));
5736
5744
  if (!text) return [];
5737
5745
  try {
5738
5746
  const parsed = JSON.parse(text);
@@ -5757,18 +5765,18 @@ async function loadMemoryTopics(vault, project) {
5757
5765
  }
5758
5766
  }
5759
5767
  async function writeBriefArtifacts(vault, input) {
5760
- const metaPath = join27(vault, "meta", "latest-session-brief.md");
5761
- const cacheMdPath = join27(vault, ".skillwiki", "session-brief.md");
5762
- const cacheJsonPath = join27(vault, ".skillwiki", "session-brief.json");
5763
- await mkdir9(join27(vault, "meta"), { recursive: true });
5764
- await mkdir9(join27(vault, ".skillwiki"), { recursive: true });
5768
+ const metaPath = join26(vault, "meta", "latest-session-brief.md");
5769
+ const cacheMdPath = join26(vault, ".skillwiki", "session-brief.md");
5770
+ const cacheJsonPath = join26(vault, ".skillwiki", "session-brief.json");
5771
+ await mkdir8(join26(vault, "meta"), { recursive: true });
5772
+ await mkdir8(join26(vault, ".skillwiki"), { recursive: true });
5765
5773
  const committed = renderCommittedBrief(input);
5766
5774
  const previousComparable = comparableBrief(await readIfExists(metaPath));
5767
5775
  const nextComparable = comparableBrief(committed);
5768
5776
  const materialChange = previousComparable !== nextComparable;
5769
- await writeFile7(metaPath, committed, "utf8");
5770
- await writeFile7(cacheMdPath, input.brief, "utf8");
5771
- await writeFile7(cacheJsonPath, `${JSON.stringify({
5777
+ await writeFile6(metaPath, committed, "utf8");
5778
+ await writeFile6(cacheMdPath, input.brief, "utf8");
5779
+ await writeFile6(cacheJsonPath, `${JSON.stringify({
5772
5780
  project: input.project,
5773
5781
  brief: input.brief,
5774
5782
  word_count: input.wordCount,
@@ -5834,7 +5842,7 @@ function renderCommittedBrief(input) {
5834
5842
  ].filter((line) => line !== "").join("\n");
5835
5843
  }
5836
5844
  async function rebuildRootIndexProjection(vault) {
5837
- const before = await readIfExists(join27(vault, "index.md"));
5845
+ const before = await readIfExists(join26(vault, "index.md"));
5838
5846
  if (!before) return false;
5839
5847
  const projection = await renderRootIndex({ vault, currentText: before });
5840
5848
  if (!projection.ok) return false;
@@ -5844,7 +5852,7 @@ async function rebuildRootIndexProjection(vault) {
5844
5852
  }
5845
5853
  async function readIfExists(path) {
5846
5854
  try {
5847
- return await readFile13(path, "utf8");
5855
+ return await readFile12(path, "utf8");
5848
5856
  } catch {
5849
5857
  return "";
5850
5858
  }
@@ -5886,14 +5894,14 @@ function dateFromPath(path) {
5886
5894
  }
5887
5895
 
5888
5896
  // src/commands/ingest.ts
5889
- import { readFile as readFile16, open, unlink as unlink4, mkdir as mkdir11 } from "fs/promises";
5890
- import { join as join32 } from "path";
5897
+ import { readFile as readFile15, open, unlink as unlink4, mkdir as mkdir10 } from "fs/promises";
5898
+ import { join as join31 } from "path";
5891
5899
  import { createHash as createHash5 } from "crypto";
5892
5900
 
5893
5901
  // src/commands/page-publish.ts
5894
5902
  import { readFileSync as readFileSync13, realpathSync as realpathSync2 } from "fs";
5895
- import { mkdir as mkdir10, readFile as readFile15 } from "fs/promises";
5896
- import { dirname as dirname8, join as join31, resolve as resolve4 } from "path";
5903
+ import { mkdir as mkdir9, readFile as readFile14 } from "fs/promises";
5904
+ import { dirname as dirname8, join as join30, resolve as resolve4 } from "path";
5897
5905
 
5898
5906
  // src/utils/publication-approval.ts
5899
5907
  import { createHash as createHash4 } from "crypto";
@@ -6121,8 +6129,8 @@ function redactApprovalTokens(text) {
6121
6129
  }
6122
6130
 
6123
6131
  // src/publish/pipeline.ts
6124
- import { readFile as readFile14 } from "fs/promises";
6125
- import { dirname as dirname7, join as join30, resolve as resolve3 } from "path";
6132
+ import { readFile as readFile13 } from "fs/promises";
6133
+ import { dirname as dirname7, join as join29, resolve as resolve3 } from "path";
6126
6134
 
6127
6135
  // src/utils/publication-operation-journal.ts
6128
6136
  import {
@@ -6135,7 +6143,7 @@ import {
6135
6143
  unlinkSync,
6136
6144
  writeFileSync as writeFileSync5
6137
6145
  } from "fs";
6138
- import { dirname as dirname6, join as join28 } from "path";
6146
+ import { dirname as dirname6, join as join27 } from "path";
6139
6147
  var PUBLICATION_JOURNAL_SCHEMA = "skillwiki-publication-operation-v1";
6140
6148
  var PHASE_ORDER2 = [
6141
6149
  "locked",
@@ -6164,16 +6172,16 @@ function vaultIdentity(vaultPath) {
6164
6172
  return sha256Hex(real).slice(0, 16);
6165
6173
  }
6166
6174
  function publicationJournalRoot(home = resolveSkillwikiHome()) {
6167
- return join28(resolveSkillwikiHome(home), ".skillwiki", "publication-operations");
6175
+ return join27(resolveSkillwikiHome(home), ".skillwiki", "publication-operations");
6168
6176
  }
6169
6177
  function resolveJournalPaths(vaultPath, operationId2, home = resolveSkillwikiHome()) {
6170
6178
  const identity = vaultIdentity(vaultPath);
6171
6179
  const rootDir = publicationJournalRoot(home);
6172
- const vaultDir = join28(rootDir, identity);
6180
+ const vaultDir = join27(rootDir, identity);
6173
6181
  return {
6174
6182
  rootDir,
6175
6183
  vaultDir,
6176
- journalPath: join28(vaultDir, `${operationId2}.json`)
6184
+ journalPath: join27(vaultDir, `${operationId2}.json`)
6177
6185
  };
6178
6186
  }
6179
6187
  function ensurePrivateDir(dir) {
@@ -6394,7 +6402,7 @@ function completePublicationJournal(input) {
6394
6402
  }
6395
6403
 
6396
6404
  // src/publish/hold-gates.ts
6397
- import { join as join29 } from "path";
6405
+ import { join as join28 } from "path";
6398
6406
  function evaluateSchemaGate(content, target, publisherKind) {
6399
6407
  const frontmatter = extractFrontmatter(content);
6400
6408
  if (!frontmatter.ok) return false;
@@ -6430,7 +6438,7 @@ function evaluateSchemaGate(content, target, publisherKind) {
6430
6438
  return false;
6431
6439
  }
6432
6440
  function evaluateBrokenWikilinkGate(body, scan, ownTarget) {
6433
- const draftPage = { absPath: join29(scan.root, ownTarget), relPath: ownTarget };
6441
+ const draftPage = { absPath: join28(scan.root, ownTarget), relPath: ownTarget };
6434
6442
  const resolver = buildWikilinkResolver([...scan.allMarkdown, draftPage]);
6435
6443
  const wikilinks = extractBodyWikilinks(body);
6436
6444
  for (const link of wikilinks) {
@@ -6617,7 +6625,7 @@ function phaseAtLeast(current, needed) {
6617
6625
  }
6618
6626
  async function readPageChanged(targetPath, content) {
6619
6627
  try {
6620
- return ok(await readFile14(targetPath, "utf8") !== content);
6628
+ return ok(await readFile13(targetPath, "utf8") !== content);
6621
6629
  } catch (error) {
6622
6630
  if (error.code === "ENOENT") return ok(true);
6623
6631
  return err("WRITE_FAILED", { path: targetPath, message: String(error) });
@@ -6625,7 +6633,7 @@ async function readPageChanged(targetPath, content) {
6625
6633
  }
6626
6634
  async function readPriorTargetSha(targetPath) {
6627
6635
  try {
6628
- const text = await readFile14(targetPath, "utf8");
6636
+ const text = await readFile13(targetPath, "utf8");
6629
6637
  return ok(sha256Hex(text));
6630
6638
  } catch (error) {
6631
6639
  if (error.code === "ENOENT") return ok("absent");
@@ -6658,10 +6666,10 @@ function successReceipt(strategy, prepared, details) {
6658
6666
  };
6659
6667
  }
6660
6668
  async function runPipelinePreview(strategy, prepared, vault) {
6661
- const schemaPath = join30(vault, "SCHEMA.md");
6669
+ const schemaPath = join29(vault, "SCHEMA.md");
6662
6670
  let schemaText;
6663
6671
  try {
6664
- schemaText = await readFile14(schemaPath, "utf8");
6672
+ schemaText = await readFile13(schemaPath, "utf8");
6665
6673
  } catch (error) {
6666
6674
  const result = err("FILE_NOT_FOUND", { path: schemaPath, message: String(error) });
6667
6675
  return { exitCode: ExitCode.FILE_NOT_FOUND, result };
@@ -6685,10 +6693,10 @@ async function runPipelinePreview(strategy, prepared, vault) {
6685
6693
  if (!indices.ok) {
6686
6694
  return { exitCode: indices.exitCode, result: indices.result };
6687
6695
  }
6688
- const logPath = join30(vault, "log.md");
6696
+ const logPath = join29(vault, "log.md");
6689
6697
  let logAppended;
6690
6698
  try {
6691
- const logText = await readFile14(logPath, "utf8");
6699
+ const logText = await readFile13(logPath, "utf8");
6692
6700
  const marker = strategy.publisherKind === "page" ? `<!-- skillwiki-page-publish:${prepared.operationId} -->` : `<!-- skillwiki-project-page-publish:${prepared.operationId} -->`;
6693
6701
  logAppended = !logText.includes(marker);
6694
6702
  } catch (error) {
@@ -6779,10 +6787,10 @@ async function runPipelineLockedPrimaryStages(strategy, prepared, vault, deps, j
6779
6787
  return { ok: false, exitCode: ExitCode.WRITE_FAILED, stage: "journal", state, cause: journalHook };
6780
6788
  }
6781
6789
  }
6782
- const schemaPath = join30(vault, "SCHEMA.md");
6790
+ const schemaPath = join29(vault, "SCHEMA.md");
6783
6791
  let schemaText;
6784
6792
  try {
6785
- schemaText = await readFile14(schemaPath, "utf8");
6793
+ schemaText = await readFile13(schemaPath, "utf8");
6786
6794
  } catch (error) {
6787
6795
  return {
6788
6796
  ok: false,
@@ -6831,8 +6839,8 @@ async function runPipelineLockedPrimaryStages(strategy, prepared, vault, deps, j
6831
6839
  if (!strategy.usesJournal || !phaseAtLeast(currentPhase, "page")) {
6832
6840
  if (strategy.publisherKind === "project-page") {
6833
6841
  try {
6834
- const { mkdir: mkdir14 } = await import("fs/promises");
6835
- await mkdir14(dirname7(prepared.targetPath), { recursive: true });
6842
+ const { mkdir: mkdir13 } = await import("fs/promises");
6843
+ await mkdir13(dirname7(prepared.targetPath), { recursive: true });
6836
6844
  } catch (error) {
6837
6845
  return {
6838
6846
  ok: false,
@@ -6880,8 +6888,8 @@ async function runPipelineLockedPrimaryStages(strategy, prepared, vault, deps, j
6880
6888
  let visibleSchema;
6881
6889
  try {
6882
6890
  [visible, visibleSchema] = await Promise.all([
6883
- readFile14(prepared.targetPath, "utf8"),
6884
- readFile14(schemaPath, "utf8")
6891
+ readFile13(prepared.targetPath, "utf8"),
6892
+ readFile13(schemaPath, "utf8")
6885
6893
  ]);
6886
6894
  } catch (error) {
6887
6895
  return {
@@ -7273,16 +7281,16 @@ async function refreshProjectIndexForTarget(vault, projectSlugs, today) {
7273
7281
  for (const slug of projectSlugs) {
7274
7282
  const rendered = await renderProjectIndex(vault, slug, { today });
7275
7283
  if (!rendered.ok) return rendered;
7276
- const indexPath = join31(vault, rendered.data.index_path);
7284
+ const indexPath = join30(vault, rendered.data.index_path);
7277
7285
  try {
7278
- await mkdir10(dirname8(indexPath), { recursive: true });
7286
+ await mkdir9(dirname8(indexPath), { recursive: true });
7279
7287
  } catch (error) {
7280
7288
  return err("WRITE_FAILED", { path: indexPath, message: String(error) });
7281
7289
  }
7282
7290
  const written = await atomicWriteText(indexPath, rendered.data.text);
7283
7291
  if (!written.ok) return written;
7284
7292
  try {
7285
- const visible = await readFile15(indexPath, "utf8");
7293
+ const visible = await readFile14(indexPath, "utf8");
7286
7294
  if (visible !== rendered.data.text) {
7287
7295
  return err("WRITE_FAILED", { path: indexPath, message: "project index verification failed" });
7288
7296
  }
@@ -7383,7 +7391,7 @@ function preparePagePublicationFromContent(input) {
7383
7391
  async function preparePagePublication(input) {
7384
7392
  let content;
7385
7393
  try {
7386
- content = await readFile15(input.draftPath, "utf8");
7394
+ content = await readFile14(input.draftPath, "utf8");
7387
7395
  } catch (error) {
7388
7396
  return err("FILE_NOT_FOUND", { path: input.draftPath, message: String(error) });
7389
7397
  }
@@ -7471,10 +7479,10 @@ var PAGE_PUBLISH_STRATEGY = {
7471
7479
  return void 0;
7472
7480
  },
7473
7481
  async previewIndices(prepared, vault, pageChanged) {
7474
- const indexPath = join31(vault, "index.md");
7482
+ const indexPath = join30(vault, "index.md");
7475
7483
  let indexText;
7476
7484
  try {
7477
- indexText = await readFile15(indexPath, "utf8");
7485
+ indexText = await readFile14(indexPath, "utf8");
7478
7486
  } catch (error) {
7479
7487
  const result = err("FILE_NOT_FOUND", { path: indexPath, message: String(error) });
7480
7488
  return { ok: false, exitCode: ExitCode.FILE_NOT_FOUND, result };
@@ -7492,7 +7500,7 @@ var PAGE_PUBLISH_STRATEGY = {
7492
7500
  if (!renderedProject.ok) {
7493
7501
  return { ok: false, exitCode: errorExitCode(renderedProject.error), result: renderedProject };
7494
7502
  }
7495
- const projectIndexPath = join31(vault, renderedProject.data.index_path);
7503
+ const projectIndexPath = join30(vault, renderedProject.data.index_path);
7496
7504
  const projectIndexChanged = await readPageChanged(projectIndexPath, renderedProject.data.text);
7497
7505
  if (!projectIndexChanged.ok) {
7498
7506
  return { ok: false, exitCode: errorExitCode(projectIndexChanged.error), result: projectIndexChanged };
@@ -7680,7 +7688,7 @@ function buildTypedContent(title, ingested, type, tags, rawRelPath, provenance)
7680
7688
  }
7681
7689
  async function resolveRawCapture(input) {
7682
7690
  try {
7683
- const existing = await readFile16(input.path, "utf8");
7691
+ const existing = await readFile15(input.path, "utf8");
7684
7692
  const frontmatter = extractFrontmatter(existing);
7685
7693
  if (!frontmatter.ok) {
7686
7694
  return err("INGEST_VALIDATION_FAILED", {
@@ -7819,7 +7827,7 @@ async function runIngest(input, pagePublishDeps = defaultPagePublishDeps()) {
7819
7827
  sourceContent = fetchResult.data.body;
7820
7828
  } else {
7821
7829
  try {
7822
- sourceContent = await readFile16(input.source, "utf8");
7830
+ sourceContent = await readFile15(input.source, "utf8");
7823
7831
  } catch {
7824
7832
  return {
7825
7833
  exitCode: ExitCode.FILE_NOT_FOUND,
@@ -7844,7 +7852,7 @@ async function runIngest(input, pagePublishDeps = defaultPagePublishDeps()) {
7844
7852
  const rawRelPath = `raw/articles/${slug}.md`;
7845
7853
  const typedDir = TYPE_DIR[input.type] ?? `${input.type}s`;
7846
7854
  const typedRelPath = `${typedDir}/${slug}.md`;
7847
- const rawAbsPath = join32(input.vault, rawRelPath);
7855
+ const rawAbsPath = join31(input.vault, rawRelPath);
7848
7856
  const identity = assessSourceIdentity({
7849
7857
  rawPath: rawRelPath,
7850
7858
  sourceUrl: sourceUrl ?? void 0,
@@ -7888,11 +7896,11 @@ async function runIngest(input, pagePublishDeps = defaultPagePublishDeps()) {
7888
7896
  );
7889
7897
  if (!input.dryRun) {
7890
7898
  try {
7891
- await mkdir11(join32(input.vault, typedDir), { recursive: true });
7899
+ await mkdir10(join31(input.vault, typedDir), { recursive: true });
7892
7900
  } catch (error) {
7893
7901
  return {
7894
7902
  exitCode: ExitCode.WRITE_FAILED,
7895
- result: err("WRITE_FAILED", { path: join32(input.vault, typedDir), message: String(error) })
7903
+ result: err("WRITE_FAILED", { path: join31(input.vault, typedDir), message: String(error) })
7896
7904
  };
7897
7905
  }
7898
7906
  }
@@ -7946,11 +7954,11 @@ async function runIngest(input, pagePublishDeps = defaultPagePublishDeps()) {
7946
7954
  preflight: pagePublishDeps.preflight,
7947
7955
  mutate: async (receipt) => {
7948
7956
  try {
7949
- await mkdir11(join32(input.vault, "raw", "articles"), { recursive: true });
7957
+ await mkdir10(join31(input.vault, "raw", "articles"), { recursive: true });
7950
7958
  } catch (error) {
7951
7959
  return {
7952
7960
  exitCode: ExitCode.WRITE_FAILED,
7953
- result: err("WRITE_FAILED", { path: join32(input.vault, "raw", "articles"), message: String(error) })
7961
+ result: err("WRITE_FAILED", { path: join31(input.vault, "raw", "articles"), message: String(error) })
7954
7962
  };
7955
7963
  }
7956
7964
  const rawWrite = await writeResolvedRaw({
@@ -8186,8 +8194,8 @@ ${body}`;
8186
8194
  }
8187
8195
 
8188
8196
  // src/commands/tag-reconcile.ts
8189
- import { readFile as readFile17 } from "fs/promises";
8190
- import { join as join33, posix } from "path";
8197
+ import { readFile as readFile16 } from "fs/promises";
8198
+ import { join as join32, posix } from "path";
8191
8199
  var TYPED_TARGET_RE = /^(entities|concepts|comparisons|queries|meta)\/[a-z0-9][a-z0-9./_-]*\.md$/;
8192
8200
  function errorExitCode2(error) {
8193
8201
  switch (error) {
@@ -8230,7 +8238,7 @@ function asTagArray(frontmatter, path) {
8230
8238
  async function readTagsFromFile(path) {
8231
8239
  let text;
8232
8240
  try {
8233
- text = await readFile17(path, "utf8");
8241
+ text = await readFile16(path, "utf8");
8234
8242
  } catch (error) {
8235
8243
  if (error.code === "ENOENT") {
8236
8244
  return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path }) };
@@ -8251,7 +8259,7 @@ async function resolveRequestedTags(input, page) {
8251
8259
  result: err("INVALID_FRONTMATTER", { message: "explicit tags must be an array of strings" })
8252
8260
  };
8253
8261
  }
8254
- const source = input.from ?? (explicit.length === 0 ? join33(input.vault, page) : void 0);
8262
+ const source = input.from ?? (explicit.length === 0 ? join32(input.vault, page) : void 0);
8255
8263
  if (!source) return { exitCode: ExitCode.OK, result: ok({ tags: [...new Set(explicit)].sort() }) };
8256
8264
  const sourced = await readTagsFromFile(source);
8257
8265
  if (!sourced.result.ok) return { exitCode: sourced.exitCode, result: sourced.result };
@@ -8262,7 +8270,7 @@ async function resolveRequestedTags(input, page) {
8262
8270
  }
8263
8271
  async function readSchema(schemaPath) {
8264
8272
  try {
8265
- return { exitCode: ExitCode.OK, result: ok(await readFile17(schemaPath, "utf8")) };
8273
+ return { exitCode: ExitCode.OK, result: ok(await readFile16(schemaPath, "utf8")) };
8266
8274
  } catch (error) {
8267
8275
  if (error.code === "ENOENT") {
8268
8276
  return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND", { path: schemaPath }) };
@@ -8290,7 +8298,7 @@ function previewResult(page, tags, reconciled, dryRun, filesChanged) {
8290
8298
  };
8291
8299
  }
8292
8300
  async function reconcileTagsWhileLocked(input, page, tags, comment) {
8293
- const schemaPath = join33(input.vault, "SCHEMA.md");
8301
+ const schemaPath = join32(input.vault, "SCHEMA.md");
8294
8302
  const current = await readSchema(schemaPath);
8295
8303
  if (!current.result.ok) return { exitCode: current.exitCode, result: current.result };
8296
8304
  const next = reconcileTaxonomyDocument(current.result.data, { tags, comment });
@@ -8301,7 +8309,7 @@ async function reconcileTagsWhileLocked(input, page, tags, comment) {
8301
8309
  }
8302
8310
  let verifiedText;
8303
8311
  try {
8304
- verifiedText = await readFile17(schemaPath, "utf8");
8312
+ verifiedText = await readFile16(schemaPath, "utf8");
8305
8313
  } catch (error) {
8306
8314
  return {
8307
8315
  exitCode: ExitCode.WRITE_FAILED,
@@ -8327,7 +8335,7 @@ async function runTagReconcile(input) {
8327
8335
  const comment = taxonomyCommentForPage(page.data, date, input.reason);
8328
8336
  if (!comment.ok) return { exitCode: ExitCode.SCHEME_REJECTED, result: comment };
8329
8337
  if (!input.write) {
8330
- const schema = await readSchema(join33(input.vault, "SCHEMA.md"));
8338
+ const schema = await readSchema(join32(input.vault, "SCHEMA.md"));
8331
8339
  if (!schema.result.ok) return { exitCode: schema.exitCode, result: schema.result };
8332
8340
  const preview = reconcileTaxonomyDocument(schema.result.data, { tags, comment: comment.data });
8333
8341
  return previewResult(page.data, tags, preview, true, []);
@@ -8380,8 +8388,8 @@ async function runTagReconcile(input) {
8380
8388
 
8381
8389
  // src/commands/project-page-publish.ts
8382
8390
  import { realpathSync as realpathSync4 } from "fs";
8383
- import { mkdir as mkdir12, readFile as readFile18 } from "fs/promises";
8384
- import { dirname as dirname10, join as join34, resolve as resolve6 } from "path";
8391
+ import { mkdir as mkdir11, readFile as readFile17 } from "fs/promises";
8392
+ import { dirname as dirname10, join as join33, resolve as resolve6 } from "path";
8385
8393
 
8386
8394
  // src/utils/architecture-page.ts
8387
8395
  import { lstatSync, realpathSync as realpathSync3 } from "fs";
@@ -8553,7 +8561,7 @@ function validateLogNote(logNote) {
8553
8561
  async function prepareProjectPagePublication(input) {
8554
8562
  let content;
8555
8563
  try {
8556
- content = await readFile18(input.draftPath, "utf8");
8564
+ content = await readFile17(input.draftPath, "utf8");
8557
8565
  } catch (error) {
8558
8566
  return err("FILE_NOT_FOUND", { path: input.draftPath, message: String(error) });
8559
8567
  }
@@ -8686,9 +8694,9 @@ var PROJECT_PAGE_PUBLISH_STRATEGY = {
8686
8694
  async updateIndicesLocked(prepared, vault, state, observe) {
8687
8695
  const rendered = await renderProjectIndex(vault, prepared.page.project, { today: prepared.date });
8688
8696
  if (!rendered.ok) return rendered;
8689
- const knowledgePath = join34(vault, rendered.data.index_path);
8697
+ const knowledgePath = join33(vault, rendered.data.index_path);
8690
8698
  try {
8691
- await mkdir12(dirname10(knowledgePath), { recursive: true });
8699
+ await mkdir11(dirname10(knowledgePath), { recursive: true });
8692
8700
  } catch (error) {
8693
8701
  return err("WRITE_FAILED", { message: String(error) });
8694
8702
  }
@@ -8697,7 +8705,7 @@ var PROJECT_PAGE_PUBLISH_STRATEGY = {
8697
8705
  state.projectIndexUpdated = knowledgeWrite.data.changed;
8698
8706
  if (state.projectIndexUpdated) state.changed.add(rendered.data.index_path);
8699
8707
  try {
8700
- const visibleIndex = await readFile18(knowledgePath, "utf8");
8708
+ const visibleIndex = await readFile17(knowledgePath, "utf8");
8701
8709
  if (visibleIndex !== rendered.data.text) {
8702
8710
  return err("WRITE_FAILED", { message: "project knowledge.md verification failed" });
8703
8711
  }
@@ -8717,9 +8725,9 @@ var PROJECT_PAGE_PUBLISH_STRATEGY = {
8717
8725
  }
8718
8726
  let projectIndexChanged = true;
8719
8727
  if (projectIndex.ok) {
8720
- const indexPath = join34(vault, projectIndex.data.index_path);
8728
+ const indexPath = join33(vault, projectIndex.data.index_path);
8721
8729
  try {
8722
- const existing = await readFile18(indexPath, "utf8");
8730
+ const existing = await readFile17(indexPath, "utf8");
8723
8731
  projectIndexChanged = existing !== projectIndex.data.text || pageChanged;
8724
8732
  } catch {
8725
8733
  projectIndexChanged = true;
@@ -8879,7 +8887,7 @@ import { existsSync as existsSync11, writeFileSync as writeFileSync6, mkdirSync
8879
8887
  import { createHash as createHash6 } from "crypto";
8880
8888
  import { execSync as execSync3, spawn } from "child_process";
8881
8889
  import { platform as platform2 } from "os";
8882
- import { join as join35, resolve as resolvePath } from "path";
8890
+ import { join as join34, resolve as resolvePath } from "path";
8883
8891
  var MAINTENANCE_SCHEMA_VERSION = 1;
8884
8892
  var MAINTENANCE_COMMAND = "snapshot-maintenance journal clear-stale";
8885
8893
  var REPAIR_COMMAND = "snapshot-maintenance projection-conflict repair";
@@ -8944,7 +8952,7 @@ async function runSnapshotMaintenanceDryRun(input) {
8944
8952
  audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_WRONG_WORKTREE"));
8945
8953
  return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_WRONG_WORKTREE", `requested path '${requested}' is not the configured snapshot worktree '${canonicalize(configuredWorktree)}'`) };
8946
8954
  }
8947
- if (!existsSync11(requested) || !existsSync11(join35(requested, ".git"))) {
8955
+ if (!existsSync11(requested) || !existsSync11(join34(requested, ".git"))) {
8948
8956
  audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_MISSING_GIT_REPO"));
8949
8957
  return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_MISSING_GIT_REPO", `snapshot worktree is not a git repository: ${requested}`) };
8950
8958
  }
@@ -9024,14 +9032,14 @@ async function resolveLiveVault(input) {
9024
9032
  return resolved.ok ? canonicalize(resolved.data.path) : void 0;
9025
9033
  }
9026
9034
  function snapshotMaintenanceAuditLogPath(home) {
9027
- const stateDir = platform2() === "darwin" ? join35(home, "Library", "Application Support", "vault-sync") : join35(home, ".local", "state", "vault-sync");
9028
- return join35(stateDir, "snapshot-maintenance-audit.jsonl");
9035
+ const stateDir = platform2() === "darwin" ? join34(home, "Library", "Application Support", "vault-sync") : join34(home, ".local", "state", "vault-sync");
9036
+ return join34(stateDir, "snapshot-maintenance-audit.jsonl");
9029
9037
  }
9030
9038
  function defaultAuditSink(home) {
9031
9039
  return (event) => {
9032
9040
  try {
9033
9041
  const logPath = snapshotMaintenanceAuditLogPath(home);
9034
- mkdirSync4(join35(logPath, ".."), { recursive: true });
9042
+ mkdirSync4(join34(logPath, ".."), { recursive: true });
9035
9043
  appendFileSync(logPath, JSON.stringify(event) + "\n", { encoding: "utf8" });
9036
9044
  } catch {
9037
9045
  }
@@ -9179,9 +9187,9 @@ function nonMergeSequencerActive(repo) {
9179
9187
  const gitDir = git(repo, ["rev-parse", "--absolute-git-dir"]);
9180
9188
  if (!gitDir) return false;
9181
9189
  for (const m of ["CHERRY_PICK_HEAD", "REVERT_HEAD"]) {
9182
- if (existsSync11(join35(gitDir, m))) return true;
9190
+ if (existsSync11(join34(gitDir, m))) return true;
9183
9191
  }
9184
- return existsSync11(join35(gitDir, "rebase-merge")) || existsSync11(join35(gitDir, "rebase-apply"));
9192
+ return existsSync11(join34(gitDir, "rebase-merge")) || existsSync11(join34(gitDir, "rebase-apply"));
9185
9193
  }
9186
9194
  function extraUnmergedPaths(unmerged) {
9187
9195
  const allow = new Set(PROJECTION_CONFLICT_ALLOWLIST);
@@ -9220,7 +9228,7 @@ async function authorizeRepairContext(input) {
9220
9228
  audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_WRONG_WORKTREE", void 0, REPAIR_COMMAND));
9221
9229
  return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_WRONG_WORKTREE", `requested path '${requested}' is not the configured snapshot worktree '${canonicalize(configuredWorktree)}'`) };
9222
9230
  }
9223
- if (!existsSync11(requested) || !existsSync11(join35(requested, ".git"))) {
9231
+ if (!existsSync11(requested) || !existsSync11(join34(requested, ".git"))) {
9224
9232
  audit(makeAuditEvent(input, fleetLoad.hostId, now, "refusal", "MAINTENANCE_MISSING_GIT_REPO", void 0, REPAIR_COMMAND));
9225
9233
  return { exitCode: ExitCode.PROTECTED_SNAPSHOTTER_WRITE_BLOCKED, result: refusalErr("MAINTENANCE_MISSING_GIT_REPO", `snapshot worktree is not a git repository: ${requested}`) };
9226
9234
  }
@@ -9321,8 +9329,8 @@ async function performProjectionRepair(input, plan, audit, now) {
9321
9329
  return { exitCode: ExitCode.WRITE_FAILED, result: rendered };
9322
9330
  }
9323
9331
  try {
9324
- writeFileSync6(join35(plan.snapshot_worktree, "index.md"), rendered.data.index);
9325
- writeFileSync6(join35(plan.snapshot_worktree, "log.md"), rendered.data.log);
9332
+ writeFileSync6(join34(plan.snapshot_worktree, "index.md"), rendered.data.index);
9333
+ writeFileSync6(join34(plan.snapshot_worktree, "log.md"), rendered.data.log);
9326
9334
  gitStrict(plan.snapshot_worktree, ["add", "--", "index.md", "log.md"]);
9327
9335
  gitStrict(plan.snapshot_worktree, [
9328
9336
  "commit",
@@ -9430,7 +9438,7 @@ function releaseSnapshotFlock(handle) {
9430
9438
 
9431
9439
  // src/commands/backup.ts
9432
9440
  import { statSync as statSync3, readdirSync as readdirSync2, readFileSync as readFileSync15, mkdirSync as mkdirSync5, writeFileSync as writeFileSync7 } from "fs";
9433
- import { join as join36, relative as relative3, dirname as dirname11 } from "path";
9441
+ import { join as join35, relative as relative3, dirname as dirname11 } from "path";
9434
9442
  import { PutObjectCommand, HeadObjectCommand, ListObjectsV2Command, GetObjectCommand, DeleteObjectsCommand } from "@aws-sdk/client-s3";
9435
9443
 
9436
9444
  // src/utils/s3-client.ts
@@ -9454,7 +9462,7 @@ var SKIP_DIRS = /* @__PURE__ */ new Set([".git", ".obsidian", "_archive", "node_
9454
9462
  function* walkMarkdown(dir, base) {
9455
9463
  for (const entry of readdirSync2(dir, { withFileTypes: true })) {
9456
9464
  if (SKIP_DIRS.has(entry.name)) continue;
9457
- const full = join36(dir, entry.name);
9465
+ const full = join35(dir, entry.name);
9458
9466
  if (entry.isDirectory()) {
9459
9467
  yield* walkMarkdown(full, base);
9460
9468
  } else if (entry.name.endsWith(".md")) {
@@ -9477,7 +9485,7 @@ async function runBackupSync(input) {
9477
9485
  let failed = 0;
9478
9486
  const files = [...walkMarkdown(input.vault, input.vault)];
9479
9487
  for (const relPath of files) {
9480
- const absPath = join36(input.vault, relPath);
9488
+ const absPath = join35(input.vault, relPath);
9481
9489
  const localStat = statSync3(absPath);
9482
9490
  let needsUpload = true;
9483
9491
  try {
@@ -9553,7 +9561,7 @@ async function runBackupRestore(input) {
9553
9561
  const objects = list.Contents ?? [];
9554
9562
  for (const obj of objects) {
9555
9563
  if (!obj.Key) continue;
9556
- const localPath = join36(target, obj.Key);
9564
+ const localPath = join35(target, obj.Key);
9557
9565
  try {
9558
9566
  const localStat = statSync3(localPath);
9559
9567
  if (obj.LastModified && localStat.mtime > obj.LastModified) {
@@ -9600,8 +9608,8 @@ async function runBackupRestore(input) {
9600
9608
 
9601
9609
  // src/commands/status.ts
9602
9610
  import { existsSync as existsSync12, statSync as statSync4 } from "fs";
9603
- import { readFile as readFile19 } from "fs/promises";
9604
- import { join as join37 } from "path";
9611
+ import { readFile as readFile18 } from "fs/promises";
9612
+ import { join as join36 } from "path";
9605
9613
  var FUSE_NO_MIRROR_NOTE = "FUSE vault with no read mirror - status scan may be slow";
9606
9614
  async function runStatus(input) {
9607
9615
  if (!existsSync12(input.vault)) {
@@ -9640,7 +9648,7 @@ async function runStatus(input) {
9640
9648
  const compound = scan.data.compound.length;
9641
9649
  let schemaVersion = "v1";
9642
9650
  try {
9643
- const schemaContent = await readFile19(join37(scanRoot, "SCHEMA.md"), "utf8");
9651
+ const schemaContent = await readFile18(join36(scanRoot, "SCHEMA.md"), "utf8");
9644
9652
  const versionMatch = schemaContent.match(/version:\s*["']?([^"'\s\n]+)/i);
9645
9653
  if (versionMatch) schemaVersion = versionMatch[1];
9646
9654
  } catch {
@@ -9708,13 +9716,13 @@ async function runStatus(input) {
9708
9716
 
9709
9717
  // src/commands/copy-status.ts
9710
9718
  import { existsSync as existsSync13, realpathSync as realpathSync5 } from "fs";
9711
- import { isAbsolute as isAbsolute2, join as join39, relative as relative5, resolve as resolve8 } from "path";
9719
+ import { isAbsolute as isAbsolute2, join as join38, relative as relative5, resolve as resolve8 } from "path";
9712
9720
 
9713
9721
  // src/utils/fetch-projection.ts
9714
- import { isAbsolute, join as join38, resolve as resolve7 } from "path";
9722
+ import { isAbsolute, join as join37, resolve as resolve7 } from "path";
9715
9723
  function inspectConfiguredFetchProjection(home) {
9716
9724
  if (!home) return { configured: false };
9717
- const config = readSkillWikiConfig(join38(home, ".skillwiki", ".env"));
9725
+ const config = readSkillWikiConfig(join37(home, ".skillwiki", ".env"));
9718
9726
  const configured = config["vault_sync.fetch_projection"];
9719
9727
  if (!configured || configured === "none") return { configured: false };
9720
9728
  if (!isAbsolute(configured)) {
@@ -9725,7 +9733,7 @@ function inspectConfiguredFetchProjection(home) {
9725
9733
 
9726
9734
  // src/utils/live-drift.ts
9727
9735
  import { createHash as createHash7 } from "crypto";
9728
- import { readFile as readFile20 } from "fs/promises";
9736
+ import { readFile as readFile19 } from "fs/promises";
9729
9737
  import { relative as relative4, sep as sep3 } from "path";
9730
9738
 
9731
9739
  // src/utils/git-promotion.ts
@@ -9770,7 +9778,7 @@ async function measureAuthoritativeLiveDrift(liveVault, projection) {
9770
9778
  const rel = relative4(liveVault, page.absPath).split(sep3).join("/");
9771
9779
  if (!isGitPromotablePath(rel)) continue;
9772
9780
  livePromotable.add(rel);
9773
- const bytes = await readFile20(page.absPath);
9781
+ const bytes = await readFile19(page.absPath);
9774
9782
  if (projectionBlobs.get(rel) !== gitBlobOid(bytes)) content += 1;
9775
9783
  }
9776
9784
  for (const rel of projectionBlobs.keys()) {
@@ -9965,7 +9973,7 @@ function defaultCopyStatusDeps(input) {
9965
9973
  const projectionWarning = selection.configured ? `configured fetch projection ignored for Git status; using live vault${projectionProblem ? ` (${projectionProblem})` : ""}` : void 0;
9966
9974
  const invalidProjectionDetail = projectionProblem ?? "configured fetch projection is not a git repository";
9967
9975
  const gitRootProblem = () => {
9968
- if (!existsSync13(join39(gitVault, ".git"))) {
9976
+ if (!existsSync13(join38(gitVault, ".git"))) {
9969
9977
  return "vault is not a git repository";
9970
9978
  }
9971
9979
  return void 0;
@@ -10045,7 +10053,7 @@ function defaultCopyStatusDeps(input) {
10045
10053
  detail: projectionProblem ?? "live drift requires a configured fetch projection"
10046
10054
  };
10047
10055
  }
10048
- if (!existsSync13(join39(configuredProjection, ".git"))) {
10056
+ if (!existsSync13(join38(configuredProjection, ".git"))) {
10049
10057
  return {
10050
10058
  unknown: true,
10051
10059
  reason_code: "fetch_projection_invalid",
@@ -10065,8 +10073,8 @@ async function runCopyStatusCommand(input) {
10065
10073
  }
10066
10074
 
10067
10075
  // src/commands/seed.ts
10068
- import { mkdir as mkdir13, writeFile as writeFile8, stat as stat5 } from "fs/promises";
10069
- import { join as join40 } from "path";
10076
+ import { mkdir as mkdir12, writeFile as writeFile7, stat as stat5 } from "fs/promises";
10077
+ import { join as join39 } from "path";
10070
10078
  var TODAY = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
10071
10079
  var EXAMPLE_PAGES = {
10072
10080
  "entities/example-project.md": `---
@@ -10135,30 +10143,30 @@ Real sources are immutable after ingestion \u2014 never edit them.
10135
10143
  `;
10136
10144
  async function runSeed(input) {
10137
10145
  try {
10138
- await stat5(join40(input.vault, "SCHEMA.md"));
10146
+ await stat5(join39(input.vault, "SCHEMA.md"));
10139
10147
  } catch {
10140
10148
  return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID", { root: input.vault, reason: "SCHEMA.md missing \u2014 run `skillwiki init` first" }) };
10141
10149
  }
10142
10150
  const created = [];
10143
10151
  const skipped = [];
10144
10152
  for (const [relPath, content] of Object.entries(EXAMPLE_PAGES)) {
10145
- const absPath = join40(input.vault, relPath);
10153
+ const absPath = join39(input.vault, relPath);
10146
10154
  try {
10147
10155
  await stat5(absPath);
10148
10156
  skipped.push(relPath);
10149
10157
  } catch {
10150
- await mkdir13(join40(absPath, ".."), { recursive: true });
10151
- await writeFile8(absPath, content, "utf8");
10158
+ await mkdir12(join39(absPath, ".."), { recursive: true });
10159
+ await writeFile7(absPath, content, "utf8");
10152
10160
  created.push(relPath);
10153
10161
  }
10154
10162
  }
10155
- const rawPath = join40(input.vault, "raw", "articles", "example-source.md");
10163
+ const rawPath = join39(input.vault, "raw", "articles", "example-source.md");
10156
10164
  try {
10157
10165
  await stat5(rawPath);
10158
10166
  skipped.push("raw/articles/example-source.md");
10159
10167
  } catch {
10160
- await mkdir13(join40(rawPath, ".."), { recursive: true });
10161
- await writeFile8(rawPath, EXAMPLE_RAW, "utf8");
10168
+ await mkdir12(join39(rawPath, ".."), { recursive: true });
10169
+ await writeFile7(rawPath, EXAMPLE_RAW, "utf8");
10162
10170
  created.push("raw/articles/example-source.md");
10163
10171
  }
10164
10172
  if (created.length > 0) {
@@ -10180,9 +10188,9 @@ async function runSeed(input) {
10180
10188
  }
10181
10189
 
10182
10190
  // src/commands/canvas.ts
10183
- import { readFile as readFile21, writeFile as writeFile9 } from "fs/promises";
10191
+ import { readFile as readFile20, writeFile as writeFile8 } from "fs/promises";
10184
10192
  import { existsSync as existsSync14 } from "fs";
10185
- import { join as join41 } from "path";
10193
+ import { join as join40 } from "path";
10186
10194
  var NODE_WIDTH = 240;
10187
10195
  var NODE_HEIGHT = 60;
10188
10196
  var COLUMN_SPACING = 400;
@@ -10260,7 +10268,7 @@ function buildCanvasEdges(adjacency) {
10260
10268
  return edges;
10261
10269
  }
10262
10270
  async function runCanvasGenerate(input) {
10263
- const graphPath = input.graphPath ?? join41(input.vault, ".skillwiki", "graph.json");
10271
+ const graphPath = input.graphPath ?? join40(input.vault, ".skillwiki", "graph.json");
10264
10272
  if (!existsSync14(graphPath)) {
10265
10273
  return {
10266
10274
  exitCode: ExitCode.FILE_NOT_FOUND,
@@ -10272,7 +10280,7 @@ async function runCanvasGenerate(input) {
10272
10280
  }
10273
10281
  let raw;
10274
10282
  try {
10275
- raw = await readFile21(graphPath, "utf8");
10283
+ raw = await readFile20(graphPath, "utf8");
10276
10284
  } catch (e) {
10277
10285
  return {
10278
10286
  exitCode: ExitCode.FILE_NOT_FOUND,
@@ -10298,9 +10306,9 @@ async function runCanvasGenerate(input) {
10298
10306
  const nodes = buildCanvasNodes(paths);
10299
10307
  const edges = buildCanvasEdges(graph.adjacency);
10300
10308
  const canvas = { nodes, edges };
10301
- const outPath = join41(input.vault, "vault-graph.canvas");
10309
+ const outPath = join40(input.vault, "vault-graph.canvas");
10302
10310
  try {
10303
- await writeFile9(outPath, JSON.stringify(canvas, null, 2));
10311
+ await writeFile8(outPath, JSON.stringify(canvas, null, 2));
10304
10312
  } catch (e) {
10305
10313
  return {
10306
10314
  exitCode: ExitCode.WRITE_FAILED,
@@ -10443,22 +10451,22 @@ async function runSourceDisposition(input) {
10443
10451
 
10444
10452
  // src/utils/source-disposal.ts
10445
10453
  import { createHash as createHash8 } from "crypto";
10446
- import { readFile as readFile23, unlink as unlink5 } from "fs/promises";
10454
+ import { readFile as readFile22, unlink as unlink5 } from "fs/promises";
10447
10455
 
10448
10456
  // src/utils/raw-asset-reference-index.ts
10449
- import { readdir as readdir7, readFile as readFile22 } from "fs/promises";
10450
- import { join as join42, relative as relative6, sep as sep4 } from "path";
10457
+ import { readdir as readdir6, readFile as readFile21 } from "fs/promises";
10458
+ import { join as join41, relative as relative6, sep as sep4 } from "path";
10451
10459
  var PREVIEW_EXTENSIONS = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "webp", "svg", "bmp", "avif", "pdf", "mp3", "wav", "m4a", "mp4", "webm"]);
10452
10460
  async function walkFiles(root, dir = root) {
10453
10461
  let entries;
10454
10462
  try {
10455
- entries = await readdir7(dir, { withFileTypes: true });
10463
+ entries = await readdir6(dir, { withFileTypes: true });
10456
10464
  } catch {
10457
10465
  return [];
10458
10466
  }
10459
10467
  const out = [];
10460
10468
  for (const entry of entries) {
10461
- const path = join42(dir, entry.name);
10469
+ const path = join41(dir, entry.name);
10462
10470
  if (entry.isDirectory()) out.push(...await walkFiles(root, path));
10463
10471
  else if (entry.isFile()) out.push(relative6(root, path).split(sep4).join("/"));
10464
10472
  }
@@ -10474,7 +10482,7 @@ function addInbound(map, target, source) {
10474
10482
  map.set(target, refs);
10475
10483
  }
10476
10484
  async function buildRawAssetReferenceIndex(vault) {
10477
- const assetRoot = join42(vault, "raw", "assets");
10485
+ const assetRoot = join41(vault, "raw", "assets");
10478
10486
  const relativeAssets = await walkFiles(assetRoot);
10479
10487
  const assets = relativeAssets.map((path) => `raw/assets/${path}`).sort((a, b) => a.localeCompare(b));
10480
10488
  const assetSet = new Set(assets);
@@ -10490,7 +10498,7 @@ async function buildRawAssetReferenceIndex(vault) {
10490
10498
  for (const page of scan.data.allMarkdown) {
10491
10499
  let text;
10492
10500
  try {
10493
- text = await readFile22(page.absPath, "utf8");
10501
+ text = await readFile21(page.absPath, "utf8");
10494
10502
  } catch {
10495
10503
  continue;
10496
10504
  }
@@ -10550,7 +10558,7 @@ async function planSourceDisposal(input) {
10550
10558
  if (sensitive.length > 0) return err("SENSITIVE_CONTENT_DETECTED", { findings: sensitive });
10551
10559
  const target = await resolveExistingRegularFileInsideVault(input.vault, input.rawPath);
10552
10560
  if (!target.ok) return err("RAW_DISPOSAL_TARGET_INVALID", { path: input.rawPath, cause: target });
10553
- const bytes = await readFile23(target.data);
10561
+ const bytes = await readFile22(target.data);
10554
10562
  const size = bytes.byteLength;
10555
10563
  let typedReferences = [];
10556
10564
  let otherReferences = [];
@@ -10674,7 +10682,7 @@ async function runSourceDisposal(input) {
10674
10682
  import { existsSync as existsSync15, readFileSync as readFileSync16 } from "fs";
10675
10683
  import { execSync as nodeExecSync } from "child_process";
10676
10684
  import { hostname as nodeHostname, platform as nodePlatform } from "os";
10677
- import { join as join43 } from "path";
10685
+ import { join as join42 } from "path";
10678
10686
  var SSH_TIMEOUT_MS = 15e3;
10679
10687
  var TIMER_UNIT = "agent-memory-trends.timer";
10680
10688
  var SERVICE_UNIT = "agent-memory-trends.service";
@@ -10904,7 +10912,7 @@ async function runFleetHealth(input) {
10904
10912
  const home = resolveSkillwikiHome(input.home, env);
10905
10913
  const osHostname = input.osHostname ?? env.HOSTNAME ?? nodeHostname();
10906
10914
  const vault = input.vault ?? env.WIKI_PATH;
10907
- const file = input.file ?? (vault ? join43(vault, FLEET_REL_PATH) : void 0);
10915
+ const file = input.file ?? (vault ? join42(vault, FLEET_REL_PATH) : void 0);
10908
10916
  if (!file) {
10909
10917
  return {
10910
10918
  exitCode: ExitCode.NO_VAULT_CONFIGURED,
@@ -10989,7 +10997,7 @@ async function runFleetHealth(input) {
10989
10997
 
10990
10998
  // src/utils/auto-commit.ts
10991
10999
  import { existsSync as existsSync16 } from "fs";
10992
- import { isAbsolute as isAbsolute3, join as join44, normalize } from "path";
11000
+ import { isAbsolute as isAbsolute3, join as join43, normalize } from "path";
10993
11001
  function isValidLastOpPath(file) {
10994
11002
  if (!file || typeof file !== "string") return false;
10995
11003
  const trimmed = file.trim();
@@ -11010,7 +11018,7 @@ async function postCommit(vault, exitCode) {
11010
11018
  const dotenv = await parseDotenvFile(configPath(home));
11011
11019
  const autoCommit = process.env.AUTO_COMMIT ?? dotenv["AUTO_COMMIT"];
11012
11020
  if (autoCommit === "false") return;
11013
- if (!existsSync16(join44(vault, ".git"))) return;
11021
+ if (!existsSync16(join43(vault, ".git"))) return;
11014
11022
  const lastOps = readLastOp(vault);
11015
11023
  if (lastOps.length === 0) return;
11016
11024
  const porcelain = git(vault, ["status", "--porcelain", "--", ...VAULT_COMMIT_PATHSPEC]);
@@ -11058,8 +11066,8 @@ function preflight(error) {
11058
11066
  }
11059
11067
  async function runMcpAuthIssueHost(input) {
11060
11068
  const isTty = input.isTty ?? Boolean(process.stdin.isTTY && process.stdout.isTTY);
11061
- const readFile24 = input.readFile ?? readFileSync17;
11062
- const writeFile10 = input.writeFile ?? writeFileSync8;
11069
+ const readFile23 = input.readFile ?? readFileSync17;
11070
+ const writeFile9 = input.writeFile ?? writeFileSync8;
11063
11071
  const stderrWrite = input.stderrWrite ?? ((s) => {
11064
11072
  process.stderr.write(s);
11065
11073
  });
@@ -11073,7 +11081,7 @@ async function runMcpAuthIssueHost(input) {
11073
11081
  if (write && !isTty) return preflight("NO_TTY");
11074
11082
  let yamlText = "";
11075
11083
  try {
11076
- yamlText = readFile24(mapPath, "utf8");
11084
+ yamlText = readFile23(mapPath, "utf8");
11077
11085
  } catch (error) {
11078
11086
  if (!isEnoent(error)) throw error;
11079
11087
  }
@@ -11095,7 +11103,7 @@ async function runMcpAuthIssueHost(input) {
11095
11103
  const appended = appendHostHash(yamlText, hashHex, hostId, granted.vaults);
11096
11104
  if ("error" in appended) return preflight(appended.error);
11097
11105
  try {
11098
- writeFile10(mapPath, appended.yaml, { encoding: "utf8", mode: 416 });
11106
+ writeFile9(mapPath, appended.yaml, { encoding: "utf8", mode: 416 });
11099
11107
  } catch (error) {
11100
11108
  if (isEnoent(error)) {
11101
11109
  return { exitCode: ExitCode.FILE_NOT_FOUND, result: err("FILE_NOT_FOUND") };
@@ -11255,7 +11263,7 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
11255
11263
  if (dirty) {
11256
11264
  return emit(dirty, void 0, { postCommit: false });
11257
11265
  }
11258
- const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-JPOBVVSU.js");
11266
+ const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-GRSHQYKC.js");
11259
11267
  const run = await runManagedWriteTransaction2({
11260
11268
  vault,
11261
11269
  command,
@@ -11285,7 +11293,7 @@ program.command("validate <file>").description("validate vault page frontmatter
11285
11293
  emit(await runValidate({ file, apply: !!opts.apply, vault }), vault);
11286
11294
  });
11287
11295
  program.command("graph").description("graph subcommands").command("build <vault>").option("--out <path>", "graph output path (default: <vault>/.skillwiki/graph.json)").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => {
11288
- const out = opts.out ?? join45(vault, ".skillwiki", "graph.json");
11296
+ const out = opts.out ?? join44(vault, ".skillwiki", "graph.json");
11289
11297
  return emitGuardedVaultWrite(vault, "graph build", () => runGraphBuild({ vault, out }));
11290
11298
  });
11291
11299
  var canvasCmd = program.command("canvas").description("manage Obsidian canvas files");
@@ -11901,6 +11909,8 @@ program.command("doctor").description("diagnose skillwiki setup issues").option(
11901
11909
  })));
11902
11910
  var clipOutboxCmd = program.command("clip-outbox").description("dedicated file-level web-clip outbox");
11903
11911
  clipOutboxCmd.command("status").description("show whether the clip-outbox channel is configured").action(async () => emit(await runClipOutboxStatus(resolveSkillwikiHome())));
11912
+ clipOutboxCmd.command("watch").description("run the enabled dedicated outbox worker using macOS FSEvents").action(async () => emit(await runClipOutboxWatch(resolveSkillwikiHome())));
11913
+ clipOutboxCmd.command("install-or-migrate").description("refresh the packaged launchd plist without enabling the channel").option("--load", "attended launchd bootstrap; requires existing enabled=true", false).option("--conditional-create-proven", "attest the deployed SeaweedFS If-None-Match:* race test passed", false).action(async (opts) => emit(await runClipOutboxInstall({ home: resolveSkillwikiHome(), load: opts.load, conditionalCreateProven: opts.conditionalCreateProven })));
11904
11914
  program.command("connect").description(CONNECT_DESCRIPTION).option("--from-file <path>", "chat-attached env file (not Drive / \u4E91\u76D8)").option("--from-stdin", "read env file from stdin (no echo)").option("--dry-run", "validate without writing ~/.skillwiki/.env").option("--force", "overwrite a different existing token").action(async (opts) => emit(await runConnect({
11905
11915
  home: resolveSkillwikiHome(),
11906
11916
  fromFile: opts.fromFile,