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.
- package/dist/{chunk-JCDAEZVD.js → chunk-5IBLXGLY.js} +5 -3
- package/dist/chunk-6OQLBNKR.js +250 -0
- package/dist/chunk-GQWCTJTU.js +55 -0
- package/dist/{chunk-FYAKMULW.js → chunk-HBJLFPQP.js} +91 -198
- package/dist/chunk-I2J3IJB7.js +54 -0
- package/dist/{chunk-HMHMCPCE.js → chunk-I6IRJCUJ.js} +12 -57
- package/dist/{chunk-QU2IXZRN.js → chunk-JQV5KNPT.js} +8 -6
- package/dist/chunk-KWEYA3OE.js +60 -0
- package/dist/{chunk-DTTKCCQ4.js → chunk-MRPJ7X7W.js} +5 -3
- package/dist/{chunk-LDEZQXH6.js → chunk-OJJBZDPR.js} +306 -116
- package/dist/chunk-OSL4J7GF.js +32 -0
- package/dist/chunk-PYPPG7RF.js +126 -0
- package/dist/chunk-QESNTTVY.js +50 -0
- package/dist/chunk-TDBUJUYH.js +109 -0
- package/dist/{chunk-GJC2CI3W.js → chunk-UIEQIJXP.js} +108 -336
- package/dist/chunk-X5GL2FCU.js +344 -0
- package/dist/chunk-ZRGZBAVS.js +98 -0
- package/dist/cli.js +352 -297
- package/dist/{index-projection-ESBJOBS7.js → index-projection-2K672CBO.js} +5 -3
- package/dist/journal-QU5IDXQF.js +13 -0
- package/dist/{managed-write-preflight-MAIGWFQJ.js → managed-write-preflight-GRSHQYKC.js} +7 -4
- package/dist/migrate-PIB4QA54.js +21 -0
- package/dist/ready-S7F53Q2D.js +9 -0
- package/dist/runtime-GLMI5OCT.js +15 -0
- package/dist/skillwiki-mcp.js +12 -7
- package/dist/sources-D2MGP246.js +10 -0
- package/dist/upload-HTE62TOV.js +14 -0
- package/dist/watcher-MHG46J3R.js +616 -0
- package/docs/clip-outbox.md +119 -0
- package/package.json +5 -1
- package/skills/.claude-plugin/plugin.json +1 -1
- package/skills/.codex-plugin/plugin.json +1 -1
- package/skills/.cursor-plugin/plugin.json +1 -1
- package/skills/package.json +1 -1
- package/skills/skills/using-skillwiki/SKILL.md +1 -1
- package/skills/skills/wiki-init/SKILL.md +12 -11
- package/skills/using-skillwiki/SKILL.md +1 -1
- package/skills/wiki-init/SKILL.md +12 -11
- package/templates/launchd/com.karlchow.skillwiki-clip-outbox.plist +21 -0
- package/templates/web-clipper/llm-wiki-clippings.json +1 -1
- package/templates/web-clipper/readme.txt +13 -13
- 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-
|
|
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
|
-
|
|
44
|
-
|
|
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-
|
|
58
|
+
} from "./chunk-I6IRJCUJ.js";
|
|
49
59
|
import {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
64
|
-
|
|
65
|
-
|
|
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
|
-
|
|
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-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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 =
|
|
2311
|
+
const back = await io.read(testFile);
|
|
2276
2312
|
const readMs = Date.now() - readStart;
|
|
2277
2313
|
if (back !== payload) {
|
|
2278
2314
|
try {
|
|
2279
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
4562
|
-
import { join as
|
|
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(
|
|
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 (!
|
|
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 =
|
|
4679
|
-
if (
|
|
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 =
|
|
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 || !
|
|
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 =
|
|
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 (!
|
|
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 =
|
|
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(
|
|
4864
|
-
walk(
|
|
4865
|
-
walk(
|
|
4866
|
-
const workRoot =
|
|
4867
|
-
if (
|
|
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 =
|
|
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 || !
|
|
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
|
|
4977
|
-
import { existsSync as
|
|
4978
|
-
import { join as
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
5081
|
-
import { basename as basename2, extname, join as
|
|
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 =
|
|
5201
|
-
await mkdir4(
|
|
5202
|
-
await
|
|
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(
|
|
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 =
|
|
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 =
|
|
5870
|
-
await mkdir4(
|
|
5871
|
-
await
|
|
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(
|
|
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(
|
|
6261
|
+
const projectCache = await readIfExists(join25(vault, memoryCacheRelPath(project)));
|
|
6072
6262
|
if (projectCache) return projectCache;
|
|
6073
6263
|
}
|
|
6074
|
-
return readIfExists(
|
|
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
|
|
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
|
|
6183
|
-
import { existsSync as
|
|
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
|
|
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(
|
|
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 =
|
|
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(
|
|
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 =
|
|
6399
|
-
if (!
|
|
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(
|
|
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(
|
|
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-
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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
|
|
7351
|
-
import { existsSync as
|
|
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 ??
|
|
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 (!
|
|
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(
|
|
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 =
|
|
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);
|