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.
- package/dist/{chunk-5MV5SSRM.js → chunk-5IBLXGLY.js} +5 -3
- package/dist/chunk-6OQLBNKR.js +250 -0
- package/dist/chunk-GQWCTJTU.js +55 -0
- package/dist/{chunk-QU2CKXM4.js → chunk-HBJLFPQP.js} +91 -199
- package/dist/chunk-I2J3IJB7.js +54 -0
- package/dist/{chunk-WPJHDRTP.js → chunk-I6IRJCUJ.js} +12 -57
- package/dist/{chunk-NA3TZ4JN.js → chunk-JQV5KNPT.js} +8 -6
- package/dist/chunk-KWEYA3OE.js +60 -0
- package/dist/{chunk-KX5Y3GSX.js → chunk-MRPJ7X7W.js} +5 -3
- package/dist/{chunk-6X6PPQNI.js → chunk-OJJBZDPR.js} +162 -296
- 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-R2DJ7IJ5.js → chunk-UIEQIJXP.js} +5 -336
- package/dist/chunk-X5GL2FCU.js +344 -0
- package/dist/chunk-ZRGZBAVS.js +98 -0
- package/dist/cli.js +308 -298
- package/dist/{index-projection-6XGESSHV.js → index-projection-2K672CBO.js} +5 -3
- package/dist/journal-QU5IDXQF.js +13 -0
- package/dist/{managed-write-preflight-JPOBVVSU.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/templates/launchd/com.karlchow.skillwiki-clip-outbox.plist +12 -13
- package/dist/sources-CLOF5VAT.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,32 +47,47 @@ 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-NA3TZ4JN.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
|
-
CLIP_OUTBOX_DEFAULTS,
|
|
68
91
|
CompoundSchema,
|
|
69
92
|
ExitCode,
|
|
70
93
|
MetaSchema,
|
|
@@ -73,20 +96,13 @@ import {
|
|
|
73
96
|
WorkItemSchema,
|
|
74
97
|
detectSchema,
|
|
75
98
|
err,
|
|
76
|
-
extractFrontmatter,
|
|
77
99
|
isClipOutboxKey,
|
|
78
100
|
isVaultSyncKey,
|
|
79
101
|
ok,
|
|
80
102
|
parseClipOutboxKeyValue,
|
|
81
103
|
parseVaultSyncKeyValue,
|
|
82
|
-
readPage,
|
|
83
|
-
redactSensitiveContent,
|
|
84
|
-
resolveReadOnlyVaultRoot,
|
|
85
|
-
scanSensitiveContent,
|
|
86
|
-
scanVault,
|
|
87
|
-
splitFrontmatter,
|
|
88
104
|
systemdPropertyFor
|
|
89
|
-
} from "./chunk-
|
|
105
|
+
} from "./chunk-UIEQIJXP.js";
|
|
90
106
|
|
|
91
107
|
// src/commands/log-append.ts
|
|
92
108
|
import { readFile, stat } from "fs/promises";
|
|
@@ -1139,7 +1155,7 @@ function isMcpOnlyLeaf(input) {
|
|
|
1139
1155
|
}
|
|
1140
1156
|
|
|
1141
1157
|
// src/doctor/runner.ts
|
|
1142
|
-
import { existsSync as
|
|
1158
|
+
import { existsSync as existsSync19 } from "fs";
|
|
1143
1159
|
|
|
1144
1160
|
// src/doctor/probes/environment.ts
|
|
1145
1161
|
import { existsSync as existsSync4, lstatSync, readlinkSync } from "fs";
|
|
@@ -4443,182 +4459,10 @@ var mcpHandshakeProbe = {
|
|
|
4443
4459
|
};
|
|
4444
4460
|
|
|
4445
4461
|
// src/doctor/probes/clip-outbox.ts
|
|
4446
|
-
import { existsSync as
|
|
4462
|
+
import { existsSync as existsSync18, readFileSync as readFileSync12 } from "fs";
|
|
4447
4463
|
import { execSync as execSync7 } from "child_process";
|
|
4448
4464
|
import { platform as platform6 } from "os";
|
|
4449
|
-
import { join as
|
|
4450
|
-
|
|
4451
|
-
// src/utils/clip-outbox-config.ts
|
|
4452
|
-
import { realpathSync, statSync as statSync3, existsSync as existsSync18, accessSync, constants } from "fs";
|
|
4453
|
-
import { homedir } from "os";
|
|
4454
|
-
import { isAbsolute, join as join22, resolve as resolve3, sep as sep2 } from "path";
|
|
4455
|
-
var CLIP_NOT_CONFIGURED = "clip channel not configured";
|
|
4456
|
-
var PRODUCTION_WATCHER_LABEL = CLIP_OUTBOX_DEFAULTS.watcher_label;
|
|
4457
|
-
var RETIRED_WATCHER_LABELS = [
|
|
4458
|
-
"com.karlchow.wiki-dev-outbox",
|
|
4459
|
-
"com.karlchow.wiki-dev-sse",
|
|
4460
|
-
"com.karlchow.wiki-dev-hourly",
|
|
4461
|
-
"com.karlchow.skillwiki-note-outbox"
|
|
4462
|
-
];
|
|
4463
|
-
function expandUserPath(raw, home) {
|
|
4464
|
-
if (raw === "~") return home;
|
|
4465
|
-
if (raw.startsWith("~/")) return resolve3(home, raw.slice(2));
|
|
4466
|
-
return raw;
|
|
4467
|
-
}
|
|
4468
|
-
function canonicalPath(raw, home) {
|
|
4469
|
-
const expanded = expandUserPath(raw.trim(), home);
|
|
4470
|
-
if (expanded.includes("\0")) return { ok: false, message: "path contains NUL" };
|
|
4471
|
-
if (expanded.includes("://") || expanded.includes("@")) {
|
|
4472
|
-
return { ok: false, message: "path must not include URL credentials" };
|
|
4473
|
-
}
|
|
4474
|
-
if (!isAbsolute(expanded)) return { ok: false, message: "must be an absolute path" };
|
|
4475
|
-
try {
|
|
4476
|
-
const real = existsSync18(expanded) ? realpathSync(expanded) : resolve3(expanded);
|
|
4477
|
-
if (real.split(sep2).some((seg) => seg === "..")) {
|
|
4478
|
-
return { ok: false, message: "path must not contain traversal" };
|
|
4479
|
-
}
|
|
4480
|
-
return { ok: true, path: real };
|
|
4481
|
-
} catch (error) {
|
|
4482
|
-
return { ok: false, message: error instanceof Error ? error.message : "invalid path" };
|
|
4483
|
-
}
|
|
4484
|
-
}
|
|
4485
|
-
function nestedOrEqual(a, b) {
|
|
4486
|
-
if (a === b) return true;
|
|
4487
|
-
const prefixA = a.endsWith(sep2) ? a : a + sep2;
|
|
4488
|
-
const prefixB = b.endsWith(sep2) ? b : b + sep2;
|
|
4489
|
-
return prefixA.startsWith(prefixB) || prefixB.startsWith(prefixA);
|
|
4490
|
-
}
|
|
4491
|
-
function intField(value, fallback) {
|
|
4492
|
-
return Number(value && value.length > 0 ? value : fallback);
|
|
4493
|
-
}
|
|
4494
|
-
function requireWritableDir(path, label) {
|
|
4495
|
-
try {
|
|
4496
|
-
const st = statSync3(path);
|
|
4497
|
-
if (!st.isDirectory()) return `${label} is not a directory`;
|
|
4498
|
-
accessSync(path, constants.W_OK);
|
|
4499
|
-
return void 0;
|
|
4500
|
-
} catch {
|
|
4501
|
-
return `${label} is missing or not writable`;
|
|
4502
|
-
}
|
|
4503
|
-
}
|
|
4504
|
-
function resolveClipOutboxConfig(map, home) {
|
|
4505
|
-
const present = Object.keys(map).filter(isClipOutboxKey);
|
|
4506
|
-
for (const key of present) {
|
|
4507
|
-
const parsed = parseClipOutboxKeyValue(key, map[key] ?? "");
|
|
4508
|
-
if (!parsed.ok) return { ok: false, message: `${key}: ${parsed.message}` };
|
|
4509
|
-
}
|
|
4510
|
-
const enabled = (map["clip_outbox.enabled"] ?? CLIP_OUTBOX_DEFAULTS.enabled) === "true";
|
|
4511
|
-
if (!enabled) {
|
|
4512
|
-
return { ok: true, enabled: false };
|
|
4513
|
-
}
|
|
4514
|
-
const required = [
|
|
4515
|
-
"clip_outbox.root",
|
|
4516
|
-
"clip_outbox.state_root",
|
|
4517
|
-
"clip_outbox.mirror_root",
|
|
4518
|
-
"clip_outbox.ready_url",
|
|
4519
|
-
"clip_outbox.s3_credential_ref",
|
|
4520
|
-
"clip_outbox.ready_credential_ref"
|
|
4521
|
-
];
|
|
4522
|
-
for (const key of required) {
|
|
4523
|
-
if (!map[key]) return { ok: false, message: `${key} is required when clip_outbox.enabled=true` };
|
|
4524
|
-
}
|
|
4525
|
-
const d8Absent = map["clip_outbox.d8_note_absent"] === "true";
|
|
4526
|
-
const d8RootRaw = map["clip_outbox.d8_note_root"];
|
|
4527
|
-
if (d8Absent && d8RootRaw) {
|
|
4528
|
-
return { ok: false, message: "clip_outbox.d8_note_root and clip_outbox.d8_note_absent cannot both be set" };
|
|
4529
|
-
}
|
|
4530
|
-
if (!d8Absent && !d8RootRaw) {
|
|
4531
|
-
return { ok: false, message: "clip_outbox.d8_note_root or clip_outbox.d8_note_absent=true is required when enabled" };
|
|
4532
|
-
}
|
|
4533
|
-
const root = canonicalPath(map["clip_outbox.root"], home);
|
|
4534
|
-
const stateRoot = canonicalPath(map["clip_outbox.state_root"], home);
|
|
4535
|
-
const mirrorRoot = canonicalPath(map["clip_outbox.mirror_root"], home);
|
|
4536
|
-
if (!root.ok) return { ok: false, message: `clip_outbox.root: ${root.message}` };
|
|
4537
|
-
if (!stateRoot.ok) return { ok: false, message: `clip_outbox.state_root: ${stateRoot.message}` };
|
|
4538
|
-
if (!mirrorRoot.ok) return { ok: false, message: `clip_outbox.mirror_root: ${mirrorRoot.message}` };
|
|
4539
|
-
let d8NoteRoot = null;
|
|
4540
|
-
if (d8RootRaw) {
|
|
4541
|
-
const d8 = canonicalPath(d8RootRaw, home);
|
|
4542
|
-
if (!d8.ok) return { ok: false, message: `clip_outbox.d8_note_root: ${d8.message}` };
|
|
4543
|
-
d8NoteRoot = d8.path;
|
|
4544
|
-
}
|
|
4545
|
-
if (nestedOrEqual(root.path, mirrorRoot.path)) {
|
|
4546
|
-
return { ok: false, message: "clip_outbox.root must be outside the frozen mirror" };
|
|
4547
|
-
}
|
|
4548
|
-
if (nestedOrEqual(root.path, stateRoot.path) || nestedOrEqual(stateRoot.path, mirrorRoot.path)) {
|
|
4549
|
-
return { ok: false, message: "clip_outbox.state_root must be disjoint from outbox and mirror" };
|
|
4550
|
-
}
|
|
4551
|
-
if (d8NoteRoot && (nestedOrEqual(root.path, d8NoteRoot) || nestedOrEqual(stateRoot.path, d8NoteRoot))) {
|
|
4552
|
-
return { ok: false, message: "clip outbox must not equal or nest the D8 note outbox" };
|
|
4553
|
-
}
|
|
4554
|
-
const rootErr = requireWritableDir(root.path, "clip_outbox.root");
|
|
4555
|
-
if (rootErr) return { ok: false, message: rootErr };
|
|
4556
|
-
const stateErr = requireWritableDir(stateRoot.path, "clip_outbox.state_root");
|
|
4557
|
-
if (stateErr) {
|
|
4558
|
-
if (existsSync18(stateRoot.path)) return { ok: false, message: stateErr };
|
|
4559
|
-
const parentErr = requireWritableDir(resolve3(stateRoot.path, ".."), "clip_outbox.state_root parent");
|
|
4560
|
-
if (parentErr) return { ok: false, message: stateErr };
|
|
4561
|
-
}
|
|
4562
|
-
if (!existsSync18(mirrorRoot.path)) {
|
|
4563
|
-
return { ok: false, message: "clip_outbox.mirror_root does not exist" };
|
|
4564
|
-
}
|
|
4565
|
-
const vaultId = map["clip_outbox.vault_id"] ?? CLIP_OUTBOX_DEFAULTS.vault_id;
|
|
4566
|
-
if (vaultId !== "central") return { ok: false, message: "clip_outbox.vault_id must be central" };
|
|
4567
|
-
const destination = map["clip_outbox.destination"] ?? CLIP_OUTBOX_DEFAULTS.destination;
|
|
4568
|
-
if (destination !== CLIP_OUTBOX_DEFAULTS.destination) {
|
|
4569
|
-
return { ok: false, message: "clip_outbox.destination must be seaweed-wiki:cloud/wiki" };
|
|
4570
|
-
}
|
|
4571
|
-
const mode = map["clip_outbox.mode"] ?? CLIP_OUTBOX_DEFAULTS.mode;
|
|
4572
|
-
if (mode !== "event-watch") return { ok: false, message: "clip_outbox.mode must be event-watch" };
|
|
4573
|
-
const watcherLabel = map["clip_outbox.watcher_label"] ?? CLIP_OUTBOX_DEFAULTS.watcher_label;
|
|
4574
|
-
if (watcherLabel !== PRODUCTION_WATCHER_LABEL) {
|
|
4575
|
-
return { ok: false, message: "clip_outbox.watcher_label must be the production clip watcher" };
|
|
4576
|
-
}
|
|
4577
|
-
const imageTypes = (map["clip_outbox.image_types"] ?? CLIP_OUTBOX_DEFAULTS.image_types).split(",").map((p) => p.trim()).filter(Boolean);
|
|
4578
|
-
return {
|
|
4579
|
-
ok: true,
|
|
4580
|
-
enabled: true,
|
|
4581
|
-
config: {
|
|
4582
|
-
enabled: true,
|
|
4583
|
-
root: root.path,
|
|
4584
|
-
stateRoot: stateRoot.path,
|
|
4585
|
-
mirrorRoot: mirrorRoot.path,
|
|
4586
|
-
d8NoteRoot,
|
|
4587
|
-
d8NoteAbsent: d8Absent,
|
|
4588
|
-
vaultId: "central",
|
|
4589
|
-
allowedPrefixes: ["raw/articles", "raw/assets"],
|
|
4590
|
-
destination: "seaweed-wiki:cloud/wiki",
|
|
4591
|
-
mode: "event-watch",
|
|
4592
|
-
pollFallbackEnabled: (map["clip_outbox.poll_fallback_enabled"] ?? CLIP_OUTBOX_DEFAULTS.poll_fallback_enabled) === "true",
|
|
4593
|
-
reconcileSeconds: intField(map["clip_outbox.reconcile_seconds"], CLIP_OUTBOX_DEFAULTS.reconcile_seconds),
|
|
4594
|
-
debounceMs: intField(map["clip_outbox.debounce_ms"], CLIP_OUTBOX_DEFAULTS.debounce_ms),
|
|
4595
|
-
stableHashMs: intField(map["clip_outbox.stable_hash_ms"], CLIP_OUTBOX_DEFAULTS.stable_hash_ms),
|
|
4596
|
-
maxArticleBytes: intField(map["clip_outbox.max_article_bytes"], CLIP_OUTBOX_DEFAULTS.max_article_bytes),
|
|
4597
|
-
maxImages: intField(map["clip_outbox.max_images"], CLIP_OUTBOX_DEFAULTS.max_images),
|
|
4598
|
-
maxImageBytes: intField(map["clip_outbox.max_image_bytes"], CLIP_OUTBOX_DEFAULTS.max_image_bytes),
|
|
4599
|
-
maxBundleBytes: intField(map["clip_outbox.max_bundle_bytes"], CLIP_OUTBOX_DEFAULTS.max_bundle_bytes),
|
|
4600
|
-
maxPixels: intField(map["clip_outbox.max_pixels"], CLIP_OUTBOX_DEFAULTS.max_pixels),
|
|
4601
|
-
downloadConcurrency: intField(map["clip_outbox.download_concurrency"], CLIP_OUTBOX_DEFAULTS.download_concurrency),
|
|
4602
|
-
imageTypes,
|
|
4603
|
-
maxRedirects: intField(map["clip_outbox.max_redirects"], CLIP_OUTBOX_DEFAULTS.max_redirects),
|
|
4604
|
-
requestTimeoutMs: intField(map["clip_outbox.request_timeout_ms"], CLIP_OUTBOX_DEFAULTS.request_timeout_ms),
|
|
4605
|
-
localizeTimeoutMs: intField(map["clip_outbox.localize_timeout_ms"], CLIP_OUTBOX_DEFAULTS.localize_timeout_ms),
|
|
4606
|
-
readyUrl: map["clip_outbox.ready_url"],
|
|
4607
|
-
s3CredentialRef: map["clip_outbox.s3_credential_ref"],
|
|
4608
|
-
readyCredentialRef: map["clip_outbox.ready_credential_ref"],
|
|
4609
|
-
watcherLabel: PRODUCTION_WATCHER_LABEL
|
|
4610
|
-
}
|
|
4611
|
-
};
|
|
4612
|
-
}
|
|
4613
|
-
function clipOutboxConfigPath(home) {
|
|
4614
|
-
return join22(resolveSkillwikiHome(home), ".skillwiki", ".env");
|
|
4615
|
-
}
|
|
4616
|
-
async function loadClipOutboxConfig(home) {
|
|
4617
|
-
const map = await parseDotenvFile(clipOutboxConfigPath(home));
|
|
4618
|
-
return resolveClipOutboxConfig(map, home || homedir());
|
|
4619
|
-
}
|
|
4620
|
-
|
|
4621
|
-
// src/doctor/probes/clip-outbox.ts
|
|
4465
|
+
import { join as join22 } from "path";
|
|
4622
4466
|
var CLIP_CHECK_IDS = [
|
|
4623
4467
|
"clip_config",
|
|
4624
4468
|
"clip_frozen_mirror",
|
|
@@ -4669,7 +4513,7 @@ function launchdLoaded(label) {
|
|
|
4669
4513
|
return false;
|
|
4670
4514
|
}
|
|
4671
4515
|
}
|
|
4672
|
-
function watcherStatus(env, label) {
|
|
4516
|
+
function watcherStatus(env, label, home, root) {
|
|
4673
4517
|
const fixture = env.CLIP_WATCHER_FIXTURE;
|
|
4674
4518
|
if (fixture === "loaded-enabled") return { loaded: true, enabled: true, kind: "production" };
|
|
4675
4519
|
if (fixture === "stopped") return { loaded: false, enabled: false, kind: "production" };
|
|
@@ -4681,8 +4525,17 @@ function watcherStatus(env, label) {
|
|
|
4681
4525
|
if (!launchdLoaded(label)) {
|
|
4682
4526
|
return { loaded: false, enabled: false, kind: "unknown" };
|
|
4683
4527
|
}
|
|
4684
|
-
const plist =
|
|
4685
|
-
|
|
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
|
+
}
|
|
4686
4539
|
}
|
|
4687
4540
|
function pushLoaded(env) {
|
|
4688
4541
|
if (env.CLIP_PUSH_FIXTURE === "loaded") return true;
|
|
@@ -4722,13 +4575,25 @@ var clipOutboxProbe = {
|
|
|
4722
4575
|
return notConfigured();
|
|
4723
4576
|
}
|
|
4724
4577
|
const cfg = resolved.config;
|
|
4725
|
-
const frozen =
|
|
4578
|
+
const frozen = existsSync18(join22(cfg.mirrorRoot, ".WIKI_GIT_FROZEN"));
|
|
4726
4579
|
const pushOn = ctx.vsConfig.pushEnabled !== false;
|
|
4727
4580
|
const pushIsLoaded = pushLoaded(env);
|
|
4728
|
-
const watch = watcherStatus(env, cfg.watcherLabel);
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
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
|
+
}
|
|
4732
4597
|
const listener = listenerOk(env);
|
|
4733
4598
|
return [
|
|
4734
4599
|
check("pass", "clip_config", clipLabel("clip_config"), "clip_outbox.enabled=true; schema valid"),
|
|
@@ -4769,7 +4634,7 @@ function resolveSnapshotGitWorktree(home) {
|
|
|
4769
4634
|
const configured = resolveConfiguredSnapshotWorktree(home);
|
|
4770
4635
|
if (configured) return configured;
|
|
4771
4636
|
const defaultPath = "/root/wiki-git";
|
|
4772
|
-
return
|
|
4637
|
+
return existsSync19(defaultPath) ? defaultPath : void 0;
|
|
4773
4638
|
}
|
|
4774
4639
|
var DoctorRunner = class {
|
|
4775
4640
|
probes;
|
|
@@ -4849,6 +4714,9 @@ var DoctorRunner = class {
|
|
|
4849
4714
|
if (summary.info > 0) summaryParts.push(`${summary.info} info`);
|
|
4850
4715
|
summaryParts.push(`${summary.warn} warn`, `${summary.error} error`);
|
|
4851
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
|
+
}
|
|
4852
4720
|
const humanHint = redactMcpSecret(lines.join("\n"), auth.token);
|
|
4853
4721
|
return { exitCode, result: ok({ checks, summary, humanHint }) };
|
|
4854
4722
|
}
|
|
@@ -4858,7 +4726,7 @@ async function runDoctor(input) {
|
|
|
4858
4726
|
}
|
|
4859
4727
|
|
|
4860
4728
|
// src/utils/package-info.ts
|
|
4861
|
-
import { readFileSync as
|
|
4729
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
4862
4730
|
function packageJsonCandidateUrls(baseUrl = import.meta.url) {
|
|
4863
4731
|
return [
|
|
4864
4732
|
new URL("../package.json", baseUrl),
|
|
@@ -4868,7 +4736,7 @@ function packageJsonCandidateUrls(baseUrl = import.meta.url) {
|
|
|
4868
4736
|
function readCliPackageJson(baseUrl = import.meta.url) {
|
|
4869
4737
|
for (const url of packageJsonCandidateUrls(baseUrl)) {
|
|
4870
4738
|
try {
|
|
4871
|
-
const pkg = JSON.parse(
|
|
4739
|
+
const pkg = JSON.parse(readFileSync13(url, "utf8"));
|
|
4872
4740
|
if (typeof pkg.version === "string") {
|
|
4873
4741
|
return { ...pkg, version: pkg.version };
|
|
4874
4742
|
}
|
|
@@ -4880,8 +4748,8 @@ function readCliPackageJson(baseUrl = import.meta.url) {
|
|
|
4880
4748
|
|
|
4881
4749
|
// src/utils/vault-write-gates.ts
|
|
4882
4750
|
import { execFileSync } from "child_process";
|
|
4883
|
-
import { existsSync as
|
|
4884
|
-
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";
|
|
4885
4753
|
var DEFAULT_DIRTY_VOLUME_THRESHOLD = 50;
|
|
4886
4754
|
var DEFAULT_CAPTURE_BUDGET = 20;
|
|
4887
4755
|
var DEFAULT_NO_DECISION_STREAK = 3;
|
|
@@ -4937,7 +4805,7 @@ function isEventLedgerPath(rel) {
|
|
|
4937
4805
|
return n === "meta/log-events" || n.startsWith("meta/log-events/");
|
|
4938
4806
|
}
|
|
4939
4807
|
function countEventLedgerFiles(vault) {
|
|
4940
|
-
return listFilesRecursive(
|
|
4808
|
+
return listFilesRecursive(join23(vault, "meta", "log-events")).length;
|
|
4941
4809
|
}
|
|
4942
4810
|
function measureDirtyVolume(vault) {
|
|
4943
4811
|
const empty = (extra = {}) => ({
|
|
@@ -4953,7 +4821,7 @@ function measureDirtyVolume(vault) {
|
|
|
4953
4821
|
is_git_repo: false,
|
|
4954
4822
|
...extra
|
|
4955
4823
|
});
|
|
4956
|
-
if (!
|
|
4824
|
+
if (!existsSync20(vault) || !statSync3(vault).isDirectory()) {
|
|
4957
4825
|
return empty();
|
|
4958
4826
|
}
|
|
4959
4827
|
const gitDir = git(vault, ["rev-parse", "--absolute-git-dir"]);
|
|
@@ -4997,8 +4865,8 @@ function measureDirtyVolume(vault) {
|
|
|
4997
4865
|
if (!rel) continue;
|
|
4998
4866
|
if (code === "??") {
|
|
4999
4867
|
untracked += 1;
|
|
5000
|
-
const abs =
|
|
5001
|
-
if (
|
|
4868
|
+
const abs = join23(vault, rel);
|
|
4869
|
+
if (existsSync20(abs) && statSync3(abs).isDirectory()) {
|
|
5002
4870
|
const files = listFilesRecursive(abs);
|
|
5003
4871
|
expanded += files.length;
|
|
5004
4872
|
addBucket(rel, files.length);
|
|
@@ -5041,9 +4909,9 @@ function listFilesRecursive(dir) {
|
|
|
5041
4909
|
}
|
|
5042
4910
|
for (const name of entries) {
|
|
5043
4911
|
if (name === ".git") continue;
|
|
5044
|
-
const p =
|
|
4912
|
+
const p = join23(dir, name);
|
|
5045
4913
|
try {
|
|
5046
|
-
const st =
|
|
4914
|
+
const st = statSync3(p);
|
|
5047
4915
|
if (st.isDirectory()) out.push(...listFilesRecursive(p));
|
|
5048
4916
|
else if (st.isFile()) out.push(p);
|
|
5049
4917
|
} catch {
|
|
@@ -5136,7 +5004,7 @@ var CAPTURE_HYGIENE_CONTRACT = `After each productive cycle (or when daily captu
|
|
|
5136
5004
|
function listProjectDayCaptures(vault, project, day) {
|
|
5137
5005
|
const found = [];
|
|
5138
5006
|
const slug = project.replace(/^\[\[/, "").replace(/\]\]$/, "").trim();
|
|
5139
|
-
if (!slug || !
|
|
5007
|
+
if (!slug || !existsSync20(vault)) return found;
|
|
5140
5008
|
const consider = (abs, rel) => {
|
|
5141
5009
|
if (!rel.endsWith(".md")) return;
|
|
5142
5010
|
const base = rel.split(/[/\\]/).pop() ?? "";
|
|
@@ -5153,7 +5021,7 @@ function listProjectDayCaptures(vault, project, day) {
|
|
|
5153
5021
|
}
|
|
5154
5022
|
if (norm.startsWith("raw/transcripts/")) {
|
|
5155
5023
|
try {
|
|
5156
|
-
const body =
|
|
5024
|
+
const body = readFileSync14(abs, "utf8");
|
|
5157
5025
|
if (body.includes(`project: ${slug}`) || body.includes(`project: "[[${slug}]]"`) || body.includes(`project: [[${slug}]]`)) {
|
|
5158
5026
|
found.push(norm);
|
|
5159
5027
|
} else if (base.includes(slug)) {
|
|
@@ -5164,7 +5032,7 @@ function listProjectDayCaptures(vault, project, day) {
|
|
|
5164
5032
|
}
|
|
5165
5033
|
};
|
|
5166
5034
|
const walk = (dir, relBase) => {
|
|
5167
|
-
if (!
|
|
5035
|
+
if (!existsSync20(dir)) return;
|
|
5168
5036
|
let entries;
|
|
5169
5037
|
try {
|
|
5170
5038
|
entries = readdirSync7(dir);
|
|
@@ -5172,27 +5040,27 @@ function listProjectDayCaptures(vault, project, day) {
|
|
|
5172
5040
|
return;
|
|
5173
5041
|
}
|
|
5174
5042
|
for (const name of entries) {
|
|
5175
|
-
const abs =
|
|
5043
|
+
const abs = join23(dir, name);
|
|
5176
5044
|
const rel = relBase ? `${relBase}/${name}` : name;
|
|
5177
5045
|
try {
|
|
5178
|
-
const st =
|
|
5046
|
+
const st = statSync3(abs);
|
|
5179
5047
|
if (st.isDirectory()) walk(abs, rel);
|
|
5180
5048
|
else if (st.isFile()) consider(abs, rel);
|
|
5181
5049
|
} catch {
|
|
5182
5050
|
}
|
|
5183
5051
|
}
|
|
5184
5052
|
};
|
|
5185
|
-
walk(
|
|
5186
|
-
walk(
|
|
5187
|
-
walk(
|
|
5188
|
-
const workRoot =
|
|
5189
|
-
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)) {
|
|
5190
5058
|
try {
|
|
5191
5059
|
for (const name of readdirSync7(workRoot)) {
|
|
5192
5060
|
if (!name.startsWith(day)) continue;
|
|
5193
5061
|
if (!/investigate|pilot-q|research|cycle|dev-loop/.test(name)) continue;
|
|
5194
|
-
const abs =
|
|
5195
|
-
if (
|
|
5062
|
+
const abs = join23(workRoot, name);
|
|
5063
|
+
if (statSync3(abs).isDirectory()) {
|
|
5196
5064
|
for (const f of listFilesRecursive(abs)) {
|
|
5197
5065
|
const rel = relative2(vault, f).replace(/\\/g, "/");
|
|
5198
5066
|
if (rel.endsWith(".md")) found.push(rel);
|
|
@@ -5236,7 +5104,7 @@ function evaluateCaptureBudget(input) {
|
|
|
5236
5104
|
return { allowed: true, reason: "under_budget", report };
|
|
5237
5105
|
}
|
|
5238
5106
|
function runWritePreflight(input) {
|
|
5239
|
-
if (!input.vault || !
|
|
5107
|
+
if (!input.vault || !existsSync20(input.vault)) {
|
|
5240
5108
|
return err(GateError.VAULT_PATH_INVALID, { path: input.vault });
|
|
5241
5109
|
}
|
|
5242
5110
|
const want = new Set(input.checks ?? ["all"]);
|
|
@@ -5296,8 +5164,8 @@ function runWritePreflight(input) {
|
|
|
5296
5164
|
|
|
5297
5165
|
// src/commands/observe.ts
|
|
5298
5166
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
5299
|
-
import { existsSync as
|
|
5300
|
-
import { join as
|
|
5167
|
+
import { existsSync as existsSync21, statSync as statSync4 } from "fs";
|
|
5168
|
+
import { join as join24 } from "path";
|
|
5301
5169
|
import { createHash as createHash2 } from "crypto";
|
|
5302
5170
|
var ALLOWED_KINDS = /* @__PURE__ */ new Set(["note", "bug", "task", "idea", "session-log"]);
|
|
5303
5171
|
function slugify(text) {
|
|
@@ -5320,7 +5188,7 @@ async function runObserve(input) {
|
|
|
5320
5188
|
result: err("SCHEME_REJECTED", { message: "Text must not be empty" })
|
|
5321
5189
|
};
|
|
5322
5190
|
}
|
|
5323
|
-
if (!
|
|
5191
|
+
if (!existsSync21(input.vault) || !statSync4(input.vault).isDirectory()) {
|
|
5324
5192
|
return {
|
|
5325
5193
|
exitCode: ExitCode.VAULT_PATH_INVALID,
|
|
5326
5194
|
result: err("VAULT_PATH_INVALID", { path: input.vault })
|
|
@@ -5346,7 +5214,7 @@ async function runObserve(input) {
|
|
|
5346
5214
|
};
|
|
5347
5215
|
}
|
|
5348
5216
|
}
|
|
5349
|
-
const transcriptsDir =
|
|
5217
|
+
const transcriptsDir = join24(input.vault, "raw", "transcripts");
|
|
5350
5218
|
try {
|
|
5351
5219
|
await mkdir3(transcriptsDir, { recursive: true });
|
|
5352
5220
|
} catch {
|
|
@@ -5358,7 +5226,7 @@ async function runObserve(input) {
|
|
|
5358
5226
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
5359
5227
|
const slug = slugify(input.text);
|
|
5360
5228
|
const fileName = `${today}-observation-${slug}.md`;
|
|
5361
|
-
const filePath =
|
|
5229
|
+
const filePath = join24(transcriptsDir, fileName);
|
|
5362
5230
|
const body = `
|
|
5363
5231
|
${input.text.trim()}
|
|
5364
5232
|
`;
|
|
@@ -5400,7 +5268,7 @@ ${input.text.trim()}
|
|
|
5400
5268
|
// src/commands/memory.ts
|
|
5401
5269
|
import { createHash as createHash3 } from "crypto";
|
|
5402
5270
|
import { mkdir as mkdir4, readFile as readFile7, readdir as readdir2, stat as stat2, writeFile as writeFile4 } from "fs/promises";
|
|
5403
|
-
import { basename as basename2, extname, join as
|
|
5271
|
+
import { basename as basename2, extname, join as join25, relative as relative3, sep as sep2 } from "path";
|
|
5404
5272
|
|
|
5405
5273
|
// src/utils/memory-authority.ts
|
|
5406
5274
|
var TIER_RANK = {
|
|
@@ -5519,8 +5387,8 @@ async function runMemoryIndex(input) {
|
|
|
5519
5387
|
}
|
|
5520
5388
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
5521
5389
|
const relCachePath = memoryCacheRelPath(input.project);
|
|
5522
|
-
const absCachePath =
|
|
5523
|
-
await mkdir4(
|
|
5390
|
+
const absCachePath = join25(input.vault, relCachePath);
|
|
5391
|
+
await mkdir4(join25(input.vault, ".skillwiki", "memory", input.project), { recursive: true });
|
|
5524
5392
|
await writeFile4(absCachePath, `${JSON.stringify({
|
|
5525
5393
|
generated_at: generatedAt,
|
|
5526
5394
|
project: input.project,
|
|
@@ -5712,7 +5580,7 @@ async function buildMemoryIndexState(pages, project) {
|
|
|
5712
5580
|
}
|
|
5713
5581
|
async function checkMemoryIndex(vault, project, current) {
|
|
5714
5582
|
const relCachePath = memoryCacheRelPath(project);
|
|
5715
|
-
const cacheText = await readIfExists(
|
|
5583
|
+
const cacheText = await readIfExists(join25(vault, relCachePath));
|
|
5716
5584
|
if (!cacheText) {
|
|
5717
5585
|
return {
|
|
5718
5586
|
ok: true,
|
|
@@ -6121,7 +5989,7 @@ async function walkImportFiles(dir, out) {
|
|
|
6121
5989
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
6122
5990
|
for (const entry of entries) {
|
|
6123
5991
|
if (entry.name === ".git" || entry.name === "node_modules") continue;
|
|
6124
|
-
const path =
|
|
5992
|
+
const path = join25(dir, entry.name);
|
|
6125
5993
|
if (entry.isDirectory()) {
|
|
6126
5994
|
await walkImportFiles(path, out);
|
|
6127
5995
|
} else if (entry.isFile() && isImportCandidate(path)) {
|
|
@@ -6171,7 +6039,7 @@ async function buildImportEntry(file, sourceRoot, project, today, maxBytes) {
|
|
|
6171
6039
|
const redacted = redactSensitiveContent(extracted, { file });
|
|
6172
6040
|
const privacy = redacted.findings.length > 0 ? "sensitive" : "local";
|
|
6173
6041
|
const sourceSlug = slugify2(basename2(file, extname(file)));
|
|
6174
|
-
const relSource = relative3(sourceRoot, file).split(
|
|
6042
|
+
const relSource = relative3(sourceRoot, file).split(sep2).join("/");
|
|
6175
6043
|
const entry = {
|
|
6176
6044
|
...baseEntry,
|
|
6177
6045
|
status: "ready",
|
|
@@ -6188,8 +6056,8 @@ async function writeImportCapture(vault, entry, today) {
|
|
|
6188
6056
|
const content = hiddenString(entry, "__content");
|
|
6189
6057
|
const project = hiddenString(entry, "__project");
|
|
6190
6058
|
const relPath = await availableImportPath(vault, entry.proposed_path);
|
|
6191
|
-
const absPath =
|
|
6192
|
-
await mkdir4(
|
|
6059
|
+
const absPath = join25(vault, relPath);
|
|
6060
|
+
await mkdir4(join25(vault, "raw", "transcripts"), { recursive: true });
|
|
6193
6061
|
await writeFile4(absPath, renderImportCapture(entry, content, project, today), "utf8");
|
|
6194
6062
|
const validation = await runValidate({ file: absPath });
|
|
6195
6063
|
return {
|
|
@@ -6205,7 +6073,7 @@ async function availableImportPath(vault, proposed) {
|
|
|
6205
6073
|
const stem = proposed.slice(0, -ext.length);
|
|
6206
6074
|
let candidate = proposed;
|
|
6207
6075
|
let i = 2;
|
|
6208
|
-
while (await readIfExists(
|
|
6076
|
+
while (await readIfExists(join25(vault, candidate))) {
|
|
6209
6077
|
candidate = `${stem}-${i}${ext}`;
|
|
6210
6078
|
i++;
|
|
6211
6079
|
}
|
|
@@ -6243,7 +6111,7 @@ function hiddenString(entry, key) {
|
|
|
6243
6111
|
return entry[key] ?? "";
|
|
6244
6112
|
}
|
|
6245
6113
|
function classifyImportSource(file) {
|
|
6246
|
-
const rel = file.split(
|
|
6114
|
+
const rel = file.split(sep2).join("/");
|
|
6247
6115
|
const name = basename2(file);
|
|
6248
6116
|
if (rel.includes("/.codex/memories/")) return "codex-memory";
|
|
6249
6117
|
if (rel.includes("/.codex/rules/")) return "codex-rule";
|
|
@@ -6390,10 +6258,10 @@ function memoryCacheRelPath(project) {
|
|
|
6390
6258
|
}
|
|
6391
6259
|
async function readMemoryCache(vault, project) {
|
|
6392
6260
|
if (project) {
|
|
6393
|
-
const projectCache = await readIfExists(
|
|
6261
|
+
const projectCache = await readIfExists(join25(vault, memoryCacheRelPath(project)));
|
|
6394
6262
|
if (projectCache) return projectCache;
|
|
6395
6263
|
}
|
|
6396
|
-
return readIfExists(
|
|
6264
|
+
return readIfExists(join25(vault, ".skillwiki", "memory-topics.json"));
|
|
6397
6265
|
}
|
|
6398
6266
|
function dedupePages(pages) {
|
|
6399
6267
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -6485,7 +6353,7 @@ function slugify2(value) {
|
|
|
6485
6353
|
|
|
6486
6354
|
// src/commands/query.ts
|
|
6487
6355
|
import { readFile as readFile9, stat as stat4 } from "fs/promises";
|
|
6488
|
-
import { join as
|
|
6356
|
+
import { join as join27 } from "path";
|
|
6489
6357
|
|
|
6490
6358
|
// src/utils/rrf.ts
|
|
6491
6359
|
var RRF_K = 60;
|
|
@@ -6501,8 +6369,8 @@ function fuseRankings(lists, k = RRF_K) {
|
|
|
6501
6369
|
|
|
6502
6370
|
// src/utils/vector-index.ts
|
|
6503
6371
|
import { mkdir as mkdir5, readFile as readFile8, stat as stat3 } from "fs/promises";
|
|
6504
|
-
import { join as
|
|
6505
|
-
import { existsSync as
|
|
6372
|
+
import { join as join26 } from "path";
|
|
6373
|
+
import { existsSync as existsSync22 } from "fs";
|
|
6506
6374
|
var VECTOR_INDEX_REL = ".skillwiki/vectors/index.json";
|
|
6507
6375
|
var VECTOR_INDEX_SCHEMA = "skillwiki-tfidf-index/v1";
|
|
6508
6376
|
function tokenize(text) {
|
|
@@ -6516,7 +6384,7 @@ function extractPageTokens(text) {
|
|
|
6516
6384
|
return tokenize(`${title} ${body}`);
|
|
6517
6385
|
}
|
|
6518
6386
|
function vectorIndexPath(vault) {
|
|
6519
|
-
return
|
|
6387
|
+
return join26(vault, ...VECTOR_INDEX_REL.split("/"));
|
|
6520
6388
|
}
|
|
6521
6389
|
function termFreq(tokens) {
|
|
6522
6390
|
const tf = /* @__PURE__ */ new Map();
|
|
@@ -6571,7 +6439,7 @@ async function buildVectorIndex(vault, now = (/* @__PURE__ */ new Date()).toISOS
|
|
|
6571
6439
|
docs
|
|
6572
6440
|
};
|
|
6573
6441
|
const dest = vectorIndexPath(vault);
|
|
6574
|
-
await mkdir5(
|
|
6442
|
+
await mkdir5(join26(vault, ".skillwiki", "vectors"), { recursive: true });
|
|
6575
6443
|
await atomicWriteText(dest, `${JSON.stringify(index)}
|
|
6576
6444
|
`);
|
|
6577
6445
|
return ok(index);
|
|
@@ -6614,7 +6482,7 @@ async function reindexPageInVectorIndex(vault, pageRelPath, now = (/* @__PURE__
|
|
|
6614
6482
|
if (!normalizedPage.endsWith(".md")) {
|
|
6615
6483
|
return err("USAGE", { message: `Page must be a .md file: ${pageRelPath}` });
|
|
6616
6484
|
}
|
|
6617
|
-
const absPath =
|
|
6485
|
+
const absPath = join26(vault, ...normalizedPage.split("/"));
|
|
6618
6486
|
let text;
|
|
6619
6487
|
try {
|
|
6620
6488
|
text = await readFile8(absPath, "utf8");
|
|
@@ -6699,7 +6567,7 @@ async function reindexPageInVectorIndex(vault, pageRelPath, now = (/* @__PURE__
|
|
|
6699
6567
|
}
|
|
6700
6568
|
}
|
|
6701
6569
|
const dest = vectorIndexPath(vault);
|
|
6702
|
-
await mkdir5(
|
|
6570
|
+
await mkdir5(join26(vault, ".skillwiki", "vectors"), { recursive: true });
|
|
6703
6571
|
await atomicWriteText(dest, `${JSON.stringify(index)}
|
|
6704
6572
|
`);
|
|
6705
6573
|
return ok({
|
|
@@ -6717,8 +6585,8 @@ async function pruneVectorIndex(vault, opts) {
|
|
|
6717
6585
|
const orphans = [];
|
|
6718
6586
|
for (const docKey of Object.keys(index.docs)) {
|
|
6719
6587
|
const normalizedKey = docKey.split(/\\|\//).join("/");
|
|
6720
|
-
const absPath =
|
|
6721
|
-
if (!
|
|
6588
|
+
const absPath = join26(vault, ...normalizedKey.split("/"));
|
|
6589
|
+
if (!existsSync22(absPath)) {
|
|
6722
6590
|
orphans.push(normalizedKey);
|
|
6723
6591
|
}
|
|
6724
6592
|
}
|
|
@@ -6764,7 +6632,7 @@ async function pruneVectorIndex(vault, opts) {
|
|
|
6764
6632
|
index.docs[docKey] = toTfIdf(termFreq(tokens), index.df, newPageCount);
|
|
6765
6633
|
} else {
|
|
6766
6634
|
try {
|
|
6767
|
-
const text = await readFile8(
|
|
6635
|
+
const text = await readFile8(join26(vault, ...docKey.split("/")), "utf8");
|
|
6768
6636
|
const tokens = extractPageTokens(text);
|
|
6769
6637
|
index.docs[docKey] = toTfIdf(termFreq(tokens), index.df, newPageCount);
|
|
6770
6638
|
} catch {
|
|
@@ -6774,7 +6642,7 @@ async function pruneVectorIndex(vault, opts) {
|
|
|
6774
6642
|
}
|
|
6775
6643
|
if (!opts?.dryRun) {
|
|
6776
6644
|
const dest = vectorIndexPath(vault);
|
|
6777
|
-
await mkdir5(
|
|
6645
|
+
await mkdir5(join26(vault, ".skillwiki", "vectors"), { recursive: true });
|
|
6778
6646
|
await atomicWriteText(dest, `${JSON.stringify(index)}
|
|
6779
6647
|
`);
|
|
6780
6648
|
}
|
|
@@ -6905,7 +6773,7 @@ async function runQuery(input) {
|
|
|
6905
6773
|
}
|
|
6906
6774
|
let pendingSources;
|
|
6907
6775
|
if (input.includePending) {
|
|
6908
|
-
const { runSourcesPending: runSourcesPending2 } = await import("./sources-
|
|
6776
|
+
const { runSourcesPending: runSourcesPending2 } = await import("./sources-D2MGP246.js");
|
|
6909
6777
|
const pending = await runSourcesPending2({
|
|
6910
6778
|
vault: input.vault,
|
|
6911
6779
|
match: input.text,
|
|
@@ -7075,7 +6943,7 @@ function computeKeywordScore(terms, title, tags, body, relPath) {
|
|
|
7075
6943
|
return score;
|
|
7076
6944
|
}
|
|
7077
6945
|
async function loadOrBuildGraph(vault) {
|
|
7078
|
-
const graphPath =
|
|
6946
|
+
const graphPath = join27(vault, ".skillwiki", "graph.json");
|
|
7079
6947
|
let needsBuild = false;
|
|
7080
6948
|
try {
|
|
7081
6949
|
const fileStat = await stat4(graphPath);
|
|
@@ -7164,27 +7032,27 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
7164
7032
|
import { z } from "zod";
|
|
7165
7033
|
|
|
7166
7034
|
// src/mcp/vault-resolve.ts
|
|
7167
|
-
import { join as
|
|
7035
|
+
import { join as join28, resolve as resolve4 } from "path";
|
|
7168
7036
|
|
|
7169
7037
|
// src/mcp/allowlist.ts
|
|
7170
|
-
import { resolve as
|
|
7171
|
-
import { realpathSync
|
|
7038
|
+
import { resolve as resolve3, sep as sep3 } from "path";
|
|
7039
|
+
import { realpathSync } from "fs";
|
|
7172
7040
|
function parseVaultAllowlist(envValue) {
|
|
7173
7041
|
if (envValue === void 0 || envValue.trim() === "") return null;
|
|
7174
|
-
return envValue.split(",").map((s) => s.trim()).filter((s) => s.length > 0).map((p) =>
|
|
7042
|
+
return envValue.split(",").map((s) => s.trim()).filter((s) => s.length > 0).map((p) => resolve3(p));
|
|
7175
7043
|
}
|
|
7176
7044
|
function vaultAllowedByList(vaultPath, allowlist) {
|
|
7177
7045
|
if (!allowlist || allowlist.length === 0) return true;
|
|
7178
7046
|
let canonical = vaultPath;
|
|
7179
7047
|
try {
|
|
7180
|
-
canonical =
|
|
7048
|
+
canonical = realpathSync(vaultPath);
|
|
7181
7049
|
} catch {
|
|
7182
|
-
canonical =
|
|
7050
|
+
canonical = resolve3(vaultPath);
|
|
7183
7051
|
}
|
|
7184
|
-
const resolved =
|
|
7052
|
+
const resolved = resolve3(canonical);
|
|
7185
7053
|
return allowlist.some((root) => {
|
|
7186
|
-
const r =
|
|
7187
|
-
return resolved === r || resolved.startsWith(r +
|
|
7054
|
+
const r = resolve3(root);
|
|
7055
|
+
return resolved === r || resolved.startsWith(r + sep3);
|
|
7188
7056
|
});
|
|
7189
7057
|
}
|
|
7190
7058
|
function getVaultAllowlistFromEnv() {
|
|
@@ -7197,7 +7065,7 @@ async function resolveMcpVault(input) {
|
|
|
7197
7065
|
let vaultPath;
|
|
7198
7066
|
let source = "resolved";
|
|
7199
7067
|
if (input.vault !== void 0 && input.vault.length > 0) {
|
|
7200
|
-
vaultPath =
|
|
7068
|
+
vaultPath = resolve4(input.vault);
|
|
7201
7069
|
source = "flag";
|
|
7202
7070
|
} else {
|
|
7203
7071
|
const r = await resolveRuntimePath({
|
|
@@ -7209,7 +7077,7 @@ async function resolveMcpVault(input) {
|
|
|
7209
7077
|
cwd: input.cwd ?? process.cwd()
|
|
7210
7078
|
});
|
|
7211
7079
|
if (!r.ok) return r;
|
|
7212
|
-
vaultPath =
|
|
7080
|
+
vaultPath = resolve4(r.data.path);
|
|
7213
7081
|
source = r.data.source;
|
|
7214
7082
|
}
|
|
7215
7083
|
const scan = await scanVault(vaultPath);
|
|
@@ -7226,7 +7094,7 @@ async function resolveMcpVault(input) {
|
|
|
7226
7094
|
return ok({ vault: vaultPath, source });
|
|
7227
7095
|
}
|
|
7228
7096
|
function defaultGraphOut(vault) {
|
|
7229
|
-
return
|
|
7097
|
+
return join28(vault, ".skillwiki", "graph.json");
|
|
7230
7098
|
}
|
|
7231
7099
|
|
|
7232
7100
|
// src/mcp/result-format.ts
|
|
@@ -7242,7 +7110,7 @@ function formatToolResult(payload) {
|
|
|
7242
7110
|
|
|
7243
7111
|
// src/mcp/audit-log.ts
|
|
7244
7112
|
import { appendFileSync, mkdirSync as mkdirSync2 } from "fs";
|
|
7245
|
-
import { join as
|
|
7113
|
+
import { join as join29 } from "path";
|
|
7246
7114
|
function auditEnabled() {
|
|
7247
7115
|
const v = process.env.SKILLWIKI_MCP_AUDIT;
|
|
7248
7116
|
if (v === "0" || v === "false") return false;
|
|
@@ -7254,7 +7122,7 @@ function auditSink() {
|
|
|
7254
7122
|
function auditFilePath() {
|
|
7255
7123
|
const custom = process.env.SKILLWIKI_MCP_AUDIT_FILE;
|
|
7256
7124
|
if (custom && custom.length > 0) return custom;
|
|
7257
|
-
return
|
|
7125
|
+
return join29(resolveSkillwikiHome(), ".skillwiki", "mcp-audit.jsonl");
|
|
7258
7126
|
}
|
|
7259
7127
|
function auditMcpToolCall(entry) {
|
|
7260
7128
|
if (!auditEnabled()) return;
|
|
@@ -7264,7 +7132,7 @@ function auditMcpToolCall(entry) {
|
|
|
7264
7132
|
return;
|
|
7265
7133
|
}
|
|
7266
7134
|
const path = auditFilePath();
|
|
7267
|
-
mkdirSync2(
|
|
7135
|
+
mkdirSync2(join29(path, ".."), { recursive: true });
|
|
7268
7136
|
appendFileSync(path, line, "utf8");
|
|
7269
7137
|
}
|
|
7270
7138
|
async function runMcpToolHandler(tool, input, fn) {
|
|
@@ -7539,7 +7407,7 @@ function registerMcpMutatingTools(server) {
|
|
|
7539
7407
|
|
|
7540
7408
|
// src/mcp/resources.ts
|
|
7541
7409
|
import { readFile as readFile11 } from "fs/promises";
|
|
7542
|
-
import { join as
|
|
7410
|
+
import { join as join31 } from "path";
|
|
7543
7411
|
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7544
7412
|
|
|
7545
7413
|
// src/mcp/lint-bucket.ts
|
|
@@ -7669,8 +7537,8 @@ async function fetchQueryPreview(input) {
|
|
|
7669
7537
|
|
|
7670
7538
|
// src/mcp/graph-html.ts
|
|
7671
7539
|
import { readFile as readFile10 } from "fs/promises";
|
|
7672
|
-
import { join as
|
|
7673
|
-
import { existsSync as
|
|
7540
|
+
import { join as join30 } from "path";
|
|
7541
|
+
import { existsSync as existsSync23 } from "fs";
|
|
7674
7542
|
var TYPE_COLORS = {
|
|
7675
7543
|
entities: "#e74c3c",
|
|
7676
7544
|
concepts: "#27ae60",
|
|
@@ -7738,9 +7606,9 @@ ${nodeSvg}
|
|
|
7738
7606
|
return { html, node_count: nodes.length, edge_count: edges.length, truncated };
|
|
7739
7607
|
}
|
|
7740
7608
|
async function fetchGraphHtmlReport(input) {
|
|
7741
|
-
const graphPath = input.graphPath ??
|
|
7609
|
+
const graphPath = input.graphPath ?? join30(input.vault, ".skillwiki", "graph.json");
|
|
7742
7610
|
const maxNodes = Math.min(Math.max(10, input.maxNodes ?? 120), 500);
|
|
7743
|
-
if (!
|
|
7611
|
+
if (!existsSync23(graphPath)) {
|
|
7744
7612
|
return {
|
|
7745
7613
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
7746
7614
|
result: err("GRAPH_MISSING", { path: graphPath, hint: "Run skillwiki.graph_build first." })
|
|
@@ -7812,7 +7680,7 @@ async function fetchStaleSummary(input) {
|
|
|
7812
7680
|
|
|
7813
7681
|
// src/mcp/resources.ts
|
|
7814
7682
|
async function readVaultFile(vault, rel) {
|
|
7815
|
-
return readFile11(
|
|
7683
|
+
return readFile11(join31(vault, rel), "utf8");
|
|
7816
7684
|
}
|
|
7817
7685
|
async function tailLines(text, lines) {
|
|
7818
7686
|
const parts = text.split(/\r?\n/);
|
|
@@ -7898,7 +7766,7 @@ function registerMcpResources(server) {
|
|
|
7898
7766
|
if (!v.ok) {
|
|
7899
7767
|
return { contents: [{ uri: uri.href, mimeType: "text/plain", text: JSON.stringify(v) }] };
|
|
7900
7768
|
}
|
|
7901
|
-
const path =
|
|
7769
|
+
const path = join31(v.data.vault, ".skillwiki", "graph.json");
|
|
7902
7770
|
try {
|
|
7903
7771
|
const raw = await readFile11(path, "utf8");
|
|
7904
7772
|
const graph = JSON.parse(raw);
|
|
@@ -8273,8 +8141,6 @@ export {
|
|
|
8273
8141
|
evaluateSatelliteRunHealthState,
|
|
8274
8142
|
withMcpClient,
|
|
8275
8143
|
DEFAULT_MCP_URL,
|
|
8276
|
-
CLIP_NOT_CONFIGURED,
|
|
8277
|
-
loadClipOutboxConfig,
|
|
8278
8144
|
runDoctor,
|
|
8279
8145
|
readCliPackageJson,
|
|
8280
8146
|
DEFAULT_DIRTY_VOLUME_THRESHOLD,
|