skillwiki 0.10.110 → 0.10.112
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-25OXNFDV.js +133 -0
- package/dist/{chunk-R2DJ7IJ5.js → chunk-7POLZOFY.js} +44 -375
- package/dist/chunk-ABRYBO4T.js +275 -0
- package/dist/{chunk-6X6PPQNI.js → chunk-APKDTEVV.js} +280 -446
- package/dist/{chunk-5MV5SSRM.js → chunk-CKQPUHM2.js} +5 -3
- package/dist/chunk-DOHWNPAZ.js +60 -0
- package/dist/chunk-EE7W3GLA.js +55 -0
- package/dist/chunk-FCA3RRNF.js +60 -0
- package/dist/{chunk-KX5Y3GSX.js → chunk-IR2DI4Y5.js} +5 -3
- package/dist/chunk-K3M6OSUW.js +77 -0
- package/dist/{chunk-WPJHDRTP.js → chunk-KJG2CSYD.js} +12 -57
- package/dist/chunk-LOVLZNLX.js +111 -0
- package/dist/chunk-OSL4J7GF.js +32 -0
- package/dist/{chunk-QU2CKXM4.js → chunk-Q6EZF37H.js} +91 -199
- package/dist/chunk-QESNTTVY.js +50 -0
- package/dist/{chunk-NA3TZ4JN.js → chunk-RR6VDWSI.js} +8 -6
- package/dist/chunk-SKOLE6US.js +126 -0
- package/dist/chunk-TKX6PSWZ.js +344 -0
- package/dist/chunk-ZRGZBAVS.js +98 -0
- package/dist/cli.js +359 -305
- package/dist/{index-projection-6XGESSHV.js → index-projection-UNZG5UJZ.js} +5 -3
- package/dist/journal-5IW3TZ5F.js +13 -0
- package/dist/{managed-write-preflight-JPOBVVSU.js → managed-write-preflight-L7IRQ76C.js} +7 -4
- package/dist/mcp-auth-env-X5MI5IX6.js +25 -0
- package/dist/migrate-RO4BJP5T.js +22 -0
- package/dist/mirror-H5BTBAON.js +151 -0
- package/dist/ready-S7F53Q2D.js +9 -0
- package/dist/runtime-VMFYW2K3.js +20 -0
- package/dist/skillwiki-mcp.js +14 -7
- package/dist/sources-AOYP6ROO.js +10 -0
- package/dist/upload-HTE62TOV.js +14 -0
- package/dist/watcher-MGHQD3UI.js +526 -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 +3 -0
- package/skills/using-skillwiki/SKILL.md +1 -1
- package/skills/wiki-init/SKILL.md +3 -0
- package/templates/launchd/com.karlchow.skillwiki-clip-outbox.plist +12 -13
- package/templates/launchd/com.karlchow.skillwiki-mirror-sse.plist +20 -0
- 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-RR6VDWSI.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-IR2DI4Y5.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,54 @@ import {
|
|
|
39
47
|
runStale,
|
|
40
48
|
satelliteGateFromFleetLoad,
|
|
41
49
|
snapshotterAliasForLocalHost,
|
|
42
|
-
toUndirectedWeighted
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
toUndirectedWeighted
|
|
51
|
+
} from "./chunk-Q6EZF37H.js";
|
|
52
|
+
import {
|
|
53
|
+
eventPathFor,
|
|
54
|
+
writeLogEvent
|
|
55
|
+
} from "./chunk-CKQPUHM2.js";
|
|
45
56
|
import {
|
|
46
|
-
atomicWriteText,
|
|
47
57
|
prepareTypedPage
|
|
48
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-KJG2CSYD.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-TKX6PSWZ.js";
|
|
62
68
|
import {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
isMcpOnlyLeaf,
|
|
70
|
+
mcpAuthFromEnv,
|
|
71
|
+
mergeMcpAuthIntoEnv,
|
|
72
|
+
redactMcpSecret
|
|
73
|
+
} from "./chunk-DOHWNPAZ.js";
|
|
74
|
+
import {
|
|
75
|
+
xml
|
|
76
|
+
} from "./chunk-25OXNFDV.js";
|
|
77
|
+
import {
|
|
78
|
+
atomicWriteText
|
|
79
|
+
} from "./chunk-EE7W3GLA.js";
|
|
80
|
+
import {
|
|
81
|
+
CLIP_NOT_CONFIGURED,
|
|
82
|
+
PRODUCTION_MIRROR_LABEL,
|
|
83
|
+
PRODUCTION_WATCHER_LABEL,
|
|
84
|
+
RETIRED_WATCHER_LABELS,
|
|
85
|
+
conditionalCreateProven,
|
|
86
|
+
loadClipCredentials,
|
|
87
|
+
loadClipOutboxConfig
|
|
88
|
+
} from "./chunk-ABRYBO4T.js";
|
|
89
|
+
import {
|
|
90
|
+
CONFIG_KEYS,
|
|
91
|
+
isValidWikiProfileKey,
|
|
92
|
+
parseDotenvFile,
|
|
93
|
+
parseDotenvText,
|
|
94
|
+
resolveSkillwikiHome,
|
|
95
|
+
writeDotenv
|
|
96
|
+
} from "./chunk-SKOLE6US.js";
|
|
66
97
|
import {
|
|
67
|
-
CLIP_OUTBOX_DEFAULTS,
|
|
68
98
|
CompoundSchema,
|
|
69
99
|
ExitCode,
|
|
70
100
|
MetaSchema,
|
|
@@ -73,20 +103,13 @@ import {
|
|
|
73
103
|
WorkItemSchema,
|
|
74
104
|
detectSchema,
|
|
75
105
|
err,
|
|
76
|
-
extractFrontmatter,
|
|
77
106
|
isClipOutboxKey,
|
|
78
107
|
isVaultSyncKey,
|
|
79
108
|
ok,
|
|
80
109
|
parseClipOutboxKeyValue,
|
|
81
110
|
parseVaultSyncKeyValue,
|
|
82
|
-
readPage,
|
|
83
|
-
redactSensitiveContent,
|
|
84
|
-
resolveReadOnlyVaultRoot,
|
|
85
|
-
scanSensitiveContent,
|
|
86
|
-
scanVault,
|
|
87
|
-
splitFrontmatter,
|
|
88
111
|
systemdPropertyFor
|
|
89
|
-
} from "./chunk-
|
|
112
|
+
} from "./chunk-7POLZOFY.js";
|
|
90
113
|
|
|
91
114
|
// src/commands/log-append.ts
|
|
92
115
|
import { readFile, stat } from "fs/promises";
|
|
@@ -1095,66 +1118,23 @@ async function runConfigPath(input) {
|
|
|
1095
1118
|
return { exitCode: ExitCode.OK, result: ok({ path: filePath, exists: existsSync2(filePath), humanHint: filePath }) };
|
|
1096
1119
|
}
|
|
1097
1120
|
|
|
1098
|
-
// src/utils/mcp-auth-env.ts
|
|
1099
|
-
import { join as join6 } from "path";
|
|
1100
|
-
var MCP_URL_ENV = "SKILLWIKI_MCP_URL";
|
|
1101
|
-
var MCP_TOKEN_ENV = "SKILLWIKI_MCP_TOKEN";
|
|
1102
|
-
var MCP_HOST_ID_ENV = "SKILLWIKI_HOST_ID";
|
|
1103
|
-
function nonEmptyEnvValue(value) {
|
|
1104
|
-
if (typeof value !== "string") return void 0;
|
|
1105
|
-
const trimmed = value.trim();
|
|
1106
|
-
return trimmed.length > 0 ? trimmed : void 0;
|
|
1107
|
-
}
|
|
1108
|
-
function mcpAuthFromEnv(env) {
|
|
1109
|
-
return {
|
|
1110
|
-
url: nonEmptyEnvValue(env[MCP_URL_ENV]),
|
|
1111
|
-
token: nonEmptyEnvValue(env[MCP_TOKEN_ENV]),
|
|
1112
|
-
hostId: nonEmptyEnvValue(env[MCP_HOST_ID_ENV])
|
|
1113
|
-
};
|
|
1114
|
-
}
|
|
1115
|
-
async function resolveMcpAuthEnv(input) {
|
|
1116
|
-
const processAuth = mcpAuthFromEnv(input.env ?? process.env);
|
|
1117
|
-
const dotenv = await parseDotenvFile(join6(resolveSkillwikiHome(input.home, input.env), ".skillwiki", ".env"));
|
|
1118
|
-
const fileAuth = mcpAuthFromEnv(dotenv);
|
|
1119
|
-
return {
|
|
1120
|
-
url: processAuth.url ?? fileAuth.url,
|
|
1121
|
-
token: processAuth.token ?? fileAuth.token,
|
|
1122
|
-
hostId: processAuth.hostId ?? fileAuth.hostId
|
|
1123
|
-
};
|
|
1124
|
-
}
|
|
1125
|
-
async function mergeMcpAuthIntoEnv(home, env) {
|
|
1126
|
-
const auth = await resolveMcpAuthEnv({ home, env });
|
|
1127
|
-
const merged = { ...env };
|
|
1128
|
-
if (auth.url && !nonEmptyEnvValue(env[MCP_URL_ENV])) merged[MCP_URL_ENV] = auth.url;
|
|
1129
|
-
if (auth.token && !nonEmptyEnvValue(env[MCP_TOKEN_ENV])) merged[MCP_TOKEN_ENV] = auth.token;
|
|
1130
|
-
if (auth.hostId && !nonEmptyEnvValue(env[MCP_HOST_ID_ENV])) merged[MCP_HOST_ID_ENV] = auth.hostId;
|
|
1131
|
-
return merged;
|
|
1132
|
-
}
|
|
1133
|
-
function redactMcpSecret(text, secret) {
|
|
1134
|
-
if (!secret || secret.length === 0 || !text.includes(secret)) return text;
|
|
1135
|
-
return text.split(secret).join("[REDACTED]");
|
|
1136
|
-
}
|
|
1137
|
-
function isMcpOnlyLeaf(input) {
|
|
1138
|
-
return !input.resolvedPath && Boolean(input.token) && !input.vaultSyncInstalled;
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
1121
|
// src/doctor/runner.ts
|
|
1142
|
-
import { existsSync as
|
|
1122
|
+
import { existsSync as existsSync19 } from "fs";
|
|
1143
1123
|
|
|
1144
1124
|
// src/doctor/probes/environment.ts
|
|
1145
1125
|
import { existsSync as existsSync4, lstatSync, readlinkSync } from "fs";
|
|
1146
|
-
import { resolve as resolve2, join as
|
|
1126
|
+
import { resolve as resolve2, join as join7 } from "path";
|
|
1147
1127
|
import { execSync } from "child_process";
|
|
1148
1128
|
|
|
1149
1129
|
// src/utils/plugin-registry.ts
|
|
1150
1130
|
import { existsSync as existsSync3, readdirSync, readFileSync as readFileSync2 } from "fs";
|
|
1151
|
-
import { join as
|
|
1152
|
-
var REGISTRY_PATH =
|
|
1153
|
-
var CODEX_CONFIG_PATH =
|
|
1131
|
+
import { join as join6 } from "path";
|
|
1132
|
+
var REGISTRY_PATH = join6(".claude", "plugins", "installed_plugins.json");
|
|
1133
|
+
var CODEX_CONFIG_PATH = join6(".codex", "config.toml");
|
|
1154
1134
|
var PLUGIN_KEY = "skillwiki@llm-wiki";
|
|
1155
1135
|
function readInstalledPlugins(home) {
|
|
1156
1136
|
try {
|
|
1157
|
-
const raw = readFileSync2(
|
|
1137
|
+
const raw = readFileSync2(join6(home, REGISTRY_PATH), "utf8");
|
|
1158
1138
|
return JSON.parse(raw);
|
|
1159
1139
|
} catch {
|
|
1160
1140
|
return null;
|
|
@@ -1190,7 +1170,7 @@ function findPluginInstallations(home, key = PLUGIN_KEY) {
|
|
|
1190
1170
|
return installs;
|
|
1191
1171
|
}
|
|
1192
1172
|
function findGrokPlugin(home, key, pluginName, marketplace) {
|
|
1193
|
-
const pluginsRoot =
|
|
1173
|
+
const pluginsRoot = join6(home, ".grok", "installed-plugins");
|
|
1194
1174
|
if (!existsSync3(pluginsRoot)) return null;
|
|
1195
1175
|
let entries;
|
|
1196
1176
|
try {
|
|
@@ -1201,10 +1181,10 @@ function findGrokPlugin(home, key, pluginName, marketplace) {
|
|
|
1201
1181
|
let best = null;
|
|
1202
1182
|
for (const entry of entries) {
|
|
1203
1183
|
if (!entry.isDirectory()) continue;
|
|
1204
|
-
const installPath =
|
|
1184
|
+
const installPath = join6(pluginsRoot, entry.name);
|
|
1205
1185
|
let manifest;
|
|
1206
1186
|
try {
|
|
1207
|
-
manifest = JSON.parse(readFileSync2(
|
|
1187
|
+
manifest = JSON.parse(readFileSync2(join6(installPath, ".claude-plugin", "plugin.json"), "utf8"));
|
|
1208
1188
|
} catch {
|
|
1209
1189
|
continue;
|
|
1210
1190
|
}
|
|
@@ -1228,7 +1208,7 @@ function findGrokPlugin(home, key, pluginName, marketplace) {
|
|
|
1228
1208
|
function findCodexPlugin(home, key, pluginName, marketplace) {
|
|
1229
1209
|
const config = readCodexPluginConfig(home, key, marketplace);
|
|
1230
1210
|
if (!config?.enabled) return null;
|
|
1231
|
-
const cacheRoot =
|
|
1211
|
+
const cacheRoot = join6(home, ".codex", "plugins", "cache", marketplace, pluginName);
|
|
1232
1212
|
if (!existsSync3(cacheRoot)) return null;
|
|
1233
1213
|
let versions;
|
|
1234
1214
|
try {
|
|
@@ -1244,7 +1224,7 @@ function findCodexPlugin(home, key, pluginName, marketplace) {
|
|
|
1244
1224
|
key,
|
|
1245
1225
|
pluginName,
|
|
1246
1226
|
marketplace,
|
|
1247
|
-
installPath:
|
|
1227
|
+
installPath: join6(cacheRoot, version),
|
|
1248
1228
|
version,
|
|
1249
1229
|
sourceType: config.sourceType,
|
|
1250
1230
|
source: config.source
|
|
@@ -1261,7 +1241,7 @@ function parsePluginKey(key) {
|
|
|
1261
1241
|
function readCodexPluginConfig(home, key, marketplace) {
|
|
1262
1242
|
let raw;
|
|
1263
1243
|
try {
|
|
1264
|
-
raw = readFileSync2(
|
|
1244
|
+
raw = readFileSync2(join6(home, CODEX_CONFIG_PATH), "utf8");
|
|
1265
1245
|
} catch {
|
|
1266
1246
|
return null;
|
|
1267
1247
|
}
|
|
@@ -1338,12 +1318,12 @@ function detectCliChannels(argv, home) {
|
|
|
1338
1318
|
}
|
|
1339
1319
|
const plugin = findPlugin(home);
|
|
1340
1320
|
if (plugin) {
|
|
1341
|
-
const pluginBin =
|
|
1321
|
+
const pluginBin = join7(plugin.installPath, "bin", "skillwiki");
|
|
1342
1322
|
if (existsSync4(pluginBin)) {
|
|
1343
1323
|
channels.push({ name: "plugin", path: pluginBin, isDevLink: false });
|
|
1344
1324
|
}
|
|
1345
1325
|
}
|
|
1346
|
-
const installBin =
|
|
1326
|
+
const installBin = join7(home, ".claude", "skills", "bin", "skillwiki");
|
|
1347
1327
|
if (existsSync4(installBin)) {
|
|
1348
1328
|
channels.push({ name: "install", path: installBin, isDevLink: false });
|
|
1349
1329
|
}
|
|
@@ -1435,7 +1415,7 @@ async function checkProfiles(home) {
|
|
|
1435
1415
|
}
|
|
1436
1416
|
async function checkProjectLocalOverride(cwd) {
|
|
1437
1417
|
const dir = cwd ?? process.cwd();
|
|
1438
|
-
const envPath =
|
|
1418
|
+
const envPath = join7(dir, ".skillwiki", ".env");
|
|
1439
1419
|
if (existsSync4(envPath)) {
|
|
1440
1420
|
return check("pass", "project_local", "Project-local config", `Found: ${envPath}`);
|
|
1441
1421
|
}
|
|
@@ -1471,7 +1451,7 @@ var environmentProbe = {
|
|
|
1471
1451
|
|
|
1472
1452
|
// src/doctor/probes/vault-structure.ts
|
|
1473
1453
|
import { existsSync as existsSync5, statSync as statSync2 } from "fs";
|
|
1474
|
-
import { join as
|
|
1454
|
+
import { join as join8 } from "path";
|
|
1475
1455
|
function checkWikiPathExists(resolvedPath, mcpOnlyLeaf) {
|
|
1476
1456
|
if (resolvedPath === void 0) {
|
|
1477
1457
|
return mcpOnlyOr(
|
|
@@ -1499,9 +1479,9 @@ function checkVaultStructure(resolvedPath, mcpOnlyLeaf) {
|
|
|
1499
1479
|
return check("error", "vault_structure", "Vault structure valid", "Cannot check \u2014 vault directory does not exist");
|
|
1500
1480
|
}
|
|
1501
1481
|
const missing = [];
|
|
1502
|
-
if (!existsSync5(
|
|
1482
|
+
if (!existsSync5(join8(resolvedPath, "SCHEMA.md"))) missing.push("SCHEMA.md");
|
|
1503
1483
|
for (const dir of ["raw", "entities", "concepts", "meta"]) {
|
|
1504
|
-
if (!existsSync5(
|
|
1484
|
+
if (!existsSync5(join8(resolvedPath, dir))) missing.push(dir + "/");
|
|
1505
1485
|
}
|
|
1506
1486
|
if (missing.length === 0) {
|
|
1507
1487
|
return check("pass", "vault_structure", "Vault structure valid", "All required files and directories present");
|
|
@@ -1518,9 +1498,9 @@ function checkObsidianTemplates(resolvedPath, mcpOnlyLeaf) {
|
|
|
1518
1498
|
);
|
|
1519
1499
|
}
|
|
1520
1500
|
const missing = [];
|
|
1521
|
-
if (!existsSync5(
|
|
1522
|
-
if (!existsSync5(
|
|
1523
|
-
if (!existsSync5(
|
|
1501
|
+
if (!existsSync5(join8(resolvedPath, "_Templates"))) missing.push("_Templates/");
|
|
1502
|
+
if (!existsSync5(join8(resolvedPath, ".obsidian", "templates.json"))) missing.push(".obsidian/templates.json");
|
|
1503
|
+
if (!existsSync5(join8(resolvedPath, ".obsidian", "app.json"))) missing.push(".obsidian/app.json");
|
|
1524
1504
|
if (missing.length === 0) {
|
|
1525
1505
|
return check("pass", "obsidian_templates", "Obsidian templates", "Template folder and config present");
|
|
1526
1506
|
}
|
|
@@ -1539,7 +1519,7 @@ var vaultStructureProbe = {
|
|
|
1539
1519
|
|
|
1540
1520
|
// src/doctor/probes/git-fleet.ts
|
|
1541
1521
|
import { existsSync as existsSync6, readFileSync as readFileSync3 } from "fs";
|
|
1542
|
-
import { join as
|
|
1522
|
+
import { join as join9 } from "path";
|
|
1543
1523
|
import { execSync as execSync2 } from "child_process";
|
|
1544
1524
|
import { platform } from "os";
|
|
1545
1525
|
function checkVaultGitRemote(resolvedPath, mcpOnlyLeaf = false) {
|
|
@@ -1551,7 +1531,7 @@ function checkVaultGitRemote(resolvedPath, mcpOnlyLeaf = false) {
|
|
|
1551
1531
|
check("error", "vault_git_remote", "Vault git remote", "Cannot check \u2014 WIKI_PATH not resolved")
|
|
1552
1532
|
);
|
|
1553
1533
|
}
|
|
1554
|
-
if (!existsSync6(
|
|
1534
|
+
if (!existsSync6(join9(resolvedPath, ".git"))) {
|
|
1555
1535
|
return check("warn", "vault_git_remote", "Vault git remote", "Vault is not a git repository \u2014 sync features unavailable");
|
|
1556
1536
|
}
|
|
1557
1537
|
try {
|
|
@@ -1599,7 +1579,7 @@ function checkSyncLastPush(resolvedPath, mcpOnlyLeaf = false) {
|
|
|
1599
1579
|
check("error", "sync_last_push", "Vault sync recency", "Cannot check \u2014 WIKI_PATH not resolved")
|
|
1600
1580
|
);
|
|
1601
1581
|
}
|
|
1602
|
-
if (!existsSync6(
|
|
1582
|
+
if (!existsSync6(join9(resolvedPath, ".git"))) {
|
|
1603
1583
|
return check("pass", "sync_last_push", "Vault sync recency", "No git repo \u2014 sync check skipped");
|
|
1604
1584
|
}
|
|
1605
1585
|
let timestamp;
|
|
@@ -1648,7 +1628,7 @@ function checkVaultGitDirty(resolvedPath) {
|
|
|
1648
1628
|
if (resolvedPath === void 0) {
|
|
1649
1629
|
return check("pass", "vault_git_dirty", "Vault git dirty state", "No vault path \u2014 check skipped");
|
|
1650
1630
|
}
|
|
1651
|
-
if (!existsSync6(
|
|
1631
|
+
if (!existsSync6(join9(resolvedPath, ".git"))) {
|
|
1652
1632
|
return check("pass", "vault_git_dirty", "Vault git dirty state", "No git repo \u2014 check skipped");
|
|
1653
1633
|
}
|
|
1654
1634
|
try {
|
|
@@ -1695,7 +1675,7 @@ function remoteMainHash(resolvedPath) {
|
|
|
1695
1675
|
}
|
|
1696
1676
|
function checkStaleRemoteMain(resolvedPath) {
|
|
1697
1677
|
if (resolvedPath === void 0) return void 0;
|
|
1698
|
-
if (!existsSync6(
|
|
1678
|
+
if (!existsSync6(join9(resolvedPath, ".git"))) return void 0;
|
|
1699
1679
|
const localOrigin = gitRefHash(resolvedPath, "origin/main");
|
|
1700
1680
|
if (!localOrigin) return void 0;
|
|
1701
1681
|
const remoteMain = remoteMainHash(resolvedPath);
|
|
@@ -1711,7 +1691,7 @@ function checkVaultGitComparison(resolvedPath, id, label, range, nonZeroSuffix,
|
|
|
1711
1691
|
if (resolvedPath === void 0) {
|
|
1712
1692
|
return check("pass", id, label, "No vault path \u2014 check skipped");
|
|
1713
1693
|
}
|
|
1714
|
-
if (!existsSync6(
|
|
1694
|
+
if (!existsSync6(join9(resolvedPath, ".git"))) {
|
|
1715
1695
|
return check("pass", id, label, "No git repo \u2014 check skipped");
|
|
1716
1696
|
}
|
|
1717
1697
|
if (!hasOriginMain(resolvedPath)) {
|
|
@@ -1756,11 +1736,11 @@ function checkVaultGitBehind(resolvedPath) {
|
|
|
1756
1736
|
}
|
|
1757
1737
|
function pullLogPaths(home) {
|
|
1758
1738
|
const paths = platform() === "darwin" ? [
|
|
1759
|
-
|
|
1760
|
-
|
|
1739
|
+
join9(home, "Library", "Logs", "wiki-pull.log"),
|
|
1740
|
+
join9(home, ".local", "state", "vault-sync", "log", "wiki-pull.log")
|
|
1761
1741
|
] : [
|
|
1762
|
-
|
|
1763
|
-
|
|
1742
|
+
join9(home, ".local", "state", "vault-sync", "log", "wiki-pull.log"),
|
|
1743
|
+
join9(home, "Library", "Logs", "wiki-pull.log")
|
|
1764
1744
|
];
|
|
1765
1745
|
return [...new Set(paths)];
|
|
1766
1746
|
}
|
|
@@ -1800,7 +1780,7 @@ function checkVaultLocalGit(resolvedPath, mcpOnlyLeaf = false) {
|
|
|
1800
1780
|
check("warn", "vault_local_git", "Vault local git", "Cannot check \u2014 WIKI_PATH not resolved")
|
|
1801
1781
|
);
|
|
1802
1782
|
}
|
|
1803
|
-
if (!existsSync6(
|
|
1783
|
+
if (!existsSync6(join9(resolvedPath, ".git"))) {
|
|
1804
1784
|
return check("warn", "vault_local_git", "Vault local git", "Not a git repository - sync features unavailable");
|
|
1805
1785
|
}
|
|
1806
1786
|
try {
|
|
@@ -1819,7 +1799,7 @@ function checkVaultGithubRemote(resolvedPath, exec) {
|
|
|
1819
1799
|
if (resolvedPath === void 0) {
|
|
1820
1800
|
return check("pass", "vault_github_remote", "Vault GitHub remote", "No vault path \u2014 check skipped");
|
|
1821
1801
|
}
|
|
1822
|
-
if (!existsSync6(
|
|
1802
|
+
if (!existsSync6(join9(resolvedPath, ".git"))) {
|
|
1823
1803
|
return check("pass", "vault_github_remote", "Vault GitHub remote", "No git repo \u2014 check skipped");
|
|
1824
1804
|
}
|
|
1825
1805
|
const state = probeGithubReachability(resolvedPath, exec);
|
|
@@ -1863,7 +1843,7 @@ function checkVaultPromotionLag(resolvedPath) {
|
|
|
1863
1843
|
if (resolvedPath === void 0) {
|
|
1864
1844
|
return check("pass", "vault_promotion_lag", "Vault promotion lag", "No vault path \u2014 check skipped");
|
|
1865
1845
|
}
|
|
1866
|
-
if (!existsSync6(
|
|
1846
|
+
if (!existsSync6(join9(resolvedPath, ".git"))) {
|
|
1867
1847
|
return check("pass", "vault_promotion_lag", "Vault promotion lag", "No git repo \u2014 check skipped");
|
|
1868
1848
|
}
|
|
1869
1849
|
try {
|
|
@@ -1914,11 +1894,11 @@ var gitFleetProbe = {
|
|
|
1914
1894
|
|
|
1915
1895
|
// src/doctor/probes/hygiene.ts
|
|
1916
1896
|
import { existsSync as existsSync8, readdirSync as readdirSync3, readFileSync as readFileSync5 } from "fs";
|
|
1917
|
-
import { join as
|
|
1897
|
+
import { join as join11 } from "path";
|
|
1918
1898
|
|
|
1919
1899
|
// src/utils/conflict-markers.ts
|
|
1920
1900
|
import { existsSync as existsSync7, readdirSync as readdirSync2, readFileSync as readFileSync4 } from "fs";
|
|
1921
|
-
import { join as
|
|
1901
|
+
import { join as join10 } from "path";
|
|
1922
1902
|
function scanConflictMarkerBlocksInText(relPath, text) {
|
|
1923
1903
|
const findings = [];
|
|
1924
1904
|
const lines = text.split(/\r?\n/);
|
|
@@ -1969,7 +1949,7 @@ function walkMarkdownFiles(root, dir, rel, out) {
|
|
|
1969
1949
|
for (const entry of entries) {
|
|
1970
1950
|
if (entry.isDirectory()) {
|
|
1971
1951
|
if (PRUNE_DIRS.has(entry.name)) continue;
|
|
1972
|
-
walkMarkdownFiles(root,
|
|
1952
|
+
walkMarkdownFiles(root, join10(dir, entry.name), rel ? `${rel}/${entry.name}` : entry.name, out);
|
|
1973
1953
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
1974
1954
|
out.push(rel ? `${rel}/${entry.name}` : entry.name);
|
|
1975
1955
|
}
|
|
@@ -1983,7 +1963,7 @@ function scanVaultConflictMarkers(vaultRoot) {
|
|
|
1983
1963
|
for (const rel of relPaths) {
|
|
1984
1964
|
let text;
|
|
1985
1965
|
try {
|
|
1986
|
-
text = readFileSync4(
|
|
1966
|
+
text = readFileSync4(join10(vaultRoot, rel), "utf8");
|
|
1987
1967
|
} catch {
|
|
1988
1968
|
continue;
|
|
1989
1969
|
}
|
|
@@ -2002,7 +1982,7 @@ function checkDotStoreClean(resolvedPath, mcpOnlyLeaf = false) {
|
|
|
2002
1982
|
check("error", "dsstore_clean", "No .DS_Store in raw/", "Cannot check \u2014 WIKI_PATH not resolved")
|
|
2003
1983
|
);
|
|
2004
1984
|
}
|
|
2005
|
-
const rawDir =
|
|
1985
|
+
const rawDir = join11(resolvedPath, "raw");
|
|
2006
1986
|
if (!existsSync8(rawDir)) {
|
|
2007
1987
|
return check("pass", "dsstore_clean", "No .DS_Store in raw/", "raw/ directory not found \u2014 check skipped");
|
|
2008
1988
|
}
|
|
@@ -2018,7 +1998,7 @@ function checkDotStoreClean(resolvedPath, mcpOnlyLeaf = false) {
|
|
|
2018
1998
|
if (entry.name === ".DS_Store") {
|
|
2019
1999
|
found.push(rel ? `${rel}/.DS_Store` : ".DS_Store");
|
|
2020
2000
|
} else if (entry.isDirectory()) {
|
|
2021
|
-
walk(
|
|
2001
|
+
walk(join11(dir, entry.name), rel ? `${rel}/${entry.name}` : entry.name);
|
|
2022
2002
|
}
|
|
2023
2003
|
}
|
|
2024
2004
|
})(rawDir, "");
|
|
@@ -2047,7 +2027,7 @@ function checkVaultConflictMarkers(resolvedPath) {
|
|
|
2047
2027
|
}
|
|
2048
2028
|
function githubSyncedGitRoot(gitRoot) {
|
|
2049
2029
|
if (gitRoot === void 0) return { ok: false, reason: "No vault path \u2014 check skipped" };
|
|
2050
|
-
if (!existsSync8(
|
|
2030
|
+
if (!existsSync8(join11(gitRoot, ".git"))) return { ok: false, reason: "Not a git repository \u2014 check skipped" };
|
|
2051
2031
|
if (!git(gitRoot, ["remote"])) return { ok: false, reason: "No git remote \u2014 not GitHub-synced, check skipped" };
|
|
2052
2032
|
return { ok: true, gitRoot };
|
|
2053
2033
|
}
|
|
@@ -2057,7 +2037,7 @@ function checkVaultGitignoreHygiene(synced) {
|
|
|
2057
2037
|
}
|
|
2058
2038
|
let content = "";
|
|
2059
2039
|
try {
|
|
2060
|
-
content = readFileSync5(
|
|
2040
|
+
content = readFileSync5(join11(synced.gitRoot, ".gitignore"), "utf8");
|
|
2061
2041
|
} catch {
|
|
2062
2042
|
content = "";
|
|
2063
2043
|
}
|
|
@@ -2105,7 +2085,7 @@ var hygieneProbe = {
|
|
|
2105
2085
|
|
|
2106
2086
|
// src/doctor/probes/s3-mount-health.ts
|
|
2107
2087
|
import { existsSync as existsSync10 } from "fs";
|
|
2108
|
-
import { join as
|
|
2088
|
+
import { join as join13 } from "path";
|
|
2109
2089
|
import { execSync as execSync4 } from "child_process";
|
|
2110
2090
|
|
|
2111
2091
|
// src/utils/s3-mount-health.ts
|
|
@@ -2114,7 +2094,7 @@ import { platform as platform2 } from "os";
|
|
|
2114
2094
|
import { readFileSync as readFileSync6 } from "fs";
|
|
2115
2095
|
import { readFile as readFile6, writeFile as writeFile2, unlink } from "fs/promises";
|
|
2116
2096
|
import { randomUUID } from "crypto";
|
|
2117
|
-
import { join as
|
|
2097
|
+
import { join as join12 } from "path";
|
|
2118
2098
|
var OS = platform2();
|
|
2119
2099
|
function findRcloneMountPid() {
|
|
2120
2100
|
try {
|
|
@@ -2272,7 +2252,7 @@ function detectFuseMount(vaultPath) {
|
|
|
2272
2252
|
return null;
|
|
2273
2253
|
}
|
|
2274
2254
|
async function writeTest(dir, options = {}) {
|
|
2275
|
-
const testFile =
|
|
2255
|
+
const testFile = join12(dir, options.fileName ?? `.doctor-write-test-${process.pid}.tmp`);
|
|
2276
2256
|
const io = options.io ?? {
|
|
2277
2257
|
write: (path, payload2) => writeFile2(path, payload2, "utf8"),
|
|
2278
2258
|
read: (path) => readFile6(path, "utf8"),
|
|
@@ -2362,7 +2342,7 @@ function checkS3MountPerf(resolvedPath) {
|
|
|
2362
2342
|
return check("pass", "s3_mount_perf", "S3 mount performance", "local disk");
|
|
2363
2343
|
}
|
|
2364
2344
|
const mountPoint = fuse.mountPoint;
|
|
2365
|
-
const conceptsDir =
|
|
2345
|
+
const conceptsDir = join13(resolvedPath, "concepts");
|
|
2366
2346
|
if (!existsSync10(conceptsDir)) {
|
|
2367
2347
|
return check("pass", "s3_mount_perf", "S3 mount performance", `S3 FUSE mount (${mountPoint}), no concepts/ to benchmark`);
|
|
2368
2348
|
}
|
|
@@ -2551,7 +2531,7 @@ async function checkWriteTest(resolvedPath) {
|
|
|
2551
2531
|
if (!fuse) {
|
|
2552
2532
|
return check("pass", "s3_write_test", "S3 write test", "local disk \u2014 check skipped");
|
|
2553
2533
|
}
|
|
2554
|
-
const conceptsDir =
|
|
2534
|
+
const conceptsDir = join13(resolvedPath, "concepts");
|
|
2555
2535
|
if (!existsSync10(conceptsDir)) {
|
|
2556
2536
|
return check("pass", "s3_write_test", "S3 write test", "no concepts/ dir to test \u2014 check skipped");
|
|
2557
2537
|
}
|
|
@@ -2652,7 +2632,7 @@ var s3MountHealthProbe = {
|
|
|
2652
2632
|
|
|
2653
2633
|
// src/doctor/probes/skills-plugins.ts
|
|
2654
2634
|
import { existsSync as existsSync11, readdirSync as readdirSync4, readFileSync as readFileSync7 } from "fs";
|
|
2655
|
-
import { join as
|
|
2635
|
+
import { join as join14 } from "path";
|
|
2656
2636
|
function findSkillMd(dir) {
|
|
2657
2637
|
const results = [];
|
|
2658
2638
|
let entries;
|
|
@@ -2663,9 +2643,9 @@ function findSkillMd(dir) {
|
|
|
2663
2643
|
}
|
|
2664
2644
|
for (const entry of entries) {
|
|
2665
2645
|
if (entry.isFile() && entry.name === "SKILL.md") {
|
|
2666
|
-
results.push(
|
|
2646
|
+
results.push(join14(dir, entry.name));
|
|
2667
2647
|
} else if (entry.isDirectory()) {
|
|
2668
|
-
results.push(...findSkillMd(
|
|
2648
|
+
results.push(...findSkillMd(join14(dir, entry.name)));
|
|
2669
2649
|
}
|
|
2670
2650
|
}
|
|
2671
2651
|
return results;
|
|
@@ -2679,18 +2659,18 @@ function findSkillNames(dir) {
|
|
|
2679
2659
|
return results;
|
|
2680
2660
|
}
|
|
2681
2661
|
for (const entry of entries) {
|
|
2682
|
-
if (entry.isDirectory() && existsSync11(
|
|
2662
|
+
if (entry.isDirectory() && existsSync11(join14(dir, entry.name, "SKILL.md"))) {
|
|
2683
2663
|
results.push(entry.name);
|
|
2684
2664
|
}
|
|
2685
2665
|
}
|
|
2686
2666
|
return results;
|
|
2687
2667
|
}
|
|
2688
2668
|
function findInstalledSkillMd(dir) {
|
|
2689
|
-
const directSkills = findSkillNames(dir).map((name) =>
|
|
2669
|
+
const directSkills = findSkillNames(dir).map((name) => join14(dir, name, "SKILL.md"));
|
|
2690
2670
|
return directSkills.length > 0 ? directSkills : findSkillMd(dir);
|
|
2691
2671
|
}
|
|
2692
2672
|
function checkSkillsInstalled(home, cwd) {
|
|
2693
|
-
const srcDir = cwd ?
|
|
2673
|
+
const srcDir = cwd ? join14(cwd, "packages", "skills") : void 0;
|
|
2694
2674
|
if (srcDir && existsSync11(srcDir)) {
|
|
2695
2675
|
const found = findInstalledSkillMd(srcDir);
|
|
2696
2676
|
if (found.length > 0) {
|
|
@@ -2704,7 +2684,7 @@ function checkSkillsInstalled(home, cwd) {
|
|
|
2704
2684
|
return check("pass", "skills_installed", "Skills installed", `${found.length} SKILL.md file(s) found (plugin v${plugin.version})`);
|
|
2705
2685
|
}
|
|
2706
2686
|
}
|
|
2707
|
-
const skillsDir =
|
|
2687
|
+
const skillsDir = join14(home, ".claude", "skills");
|
|
2708
2688
|
if (existsSync11(skillsDir)) {
|
|
2709
2689
|
const found = findInstalledSkillMd(skillsDir);
|
|
2710
2690
|
if (found.length > 0) {
|
|
@@ -2715,10 +2695,10 @@ function checkSkillsInstalled(home, cwd) {
|
|
|
2715
2695
|
}
|
|
2716
2696
|
function checkDuplicateSkills(home) {
|
|
2717
2697
|
const plugin = findPlugin(home);
|
|
2718
|
-
const skillsDir =
|
|
2698
|
+
const skillsDir = join14(home, ".claude", "skills");
|
|
2719
2699
|
const agentSkillDirs = [
|
|
2720
|
-
{ label: "~/.codex/skills/", path:
|
|
2721
|
-
{ label: "~/.agents/skills/", path:
|
|
2700
|
+
{ label: "~/.codex/skills/", path: join14(home, ".codex", "skills") },
|
|
2701
|
+
{ label: "~/.agents/skills/", path: join14(home, ".agents", "skills") }
|
|
2722
2702
|
];
|
|
2723
2703
|
if (!plugin) {
|
|
2724
2704
|
return check("pass", "skills_duplicate", "Skills not duplicated", "Single install channel");
|
|
@@ -2751,10 +2731,10 @@ var STALE_GROK_ACTIVATION_REFERENCE = "Read @skillwiki.md";
|
|
|
2751
2731
|
var ACTIVATION_FIX_HINT = "run `npm run install:activation` from the llm-wiki repo";
|
|
2752
2732
|
function findGrokActivationTemplate(home, cwd) {
|
|
2753
2733
|
if (cwd) {
|
|
2754
|
-
const src =
|
|
2734
|
+
const src = join14(cwd, "packages", "skills", "using-skillwiki", "activation.md");
|
|
2755
2735
|
if (existsSync11(src)) return src;
|
|
2756
2736
|
}
|
|
2757
|
-
const pluginsRoot =
|
|
2737
|
+
const pluginsRoot = join14(home, ".grok", "installed-plugins");
|
|
2758
2738
|
if (!existsSync11(pluginsRoot)) return void 0;
|
|
2759
2739
|
let entries;
|
|
2760
2740
|
try {
|
|
@@ -2764,21 +2744,21 @@ function findGrokActivationTemplate(home, cwd) {
|
|
|
2764
2744
|
}
|
|
2765
2745
|
for (const entry of entries) {
|
|
2766
2746
|
if (!entry.isDirectory()) continue;
|
|
2767
|
-
const root =
|
|
2747
|
+
const root = join14(pluginsRoot, entry.name);
|
|
2768
2748
|
for (const rel of ["using-skillwiki/activation.md", "skills/using-skillwiki/activation.md"]) {
|
|
2769
|
-
const candidate =
|
|
2749
|
+
const candidate = join14(root, rel);
|
|
2770
2750
|
if (existsSync11(candidate)) return candidate;
|
|
2771
2751
|
}
|
|
2772
2752
|
}
|
|
2773
2753
|
return void 0;
|
|
2774
2754
|
}
|
|
2775
2755
|
function checkGrokActivation(home, cwd) {
|
|
2776
|
-
const grokDir =
|
|
2756
|
+
const grokDir = join14(home, ".grok");
|
|
2777
2757
|
if (!existsSync11(grokDir)) {
|
|
2778
2758
|
return check("pass", "activation_grok", "Grok activation", "Not a Grok host");
|
|
2779
2759
|
}
|
|
2780
|
-
const activationPath =
|
|
2781
|
-
const agentsPath =
|
|
2760
|
+
const activationPath = join14(grokDir, "skillwiki.md");
|
|
2761
|
+
const agentsPath = join14(grokDir, "AGENTS.md");
|
|
2782
2762
|
const hasActivation = existsSync11(activationPath);
|
|
2783
2763
|
const issues = [];
|
|
2784
2764
|
if (!hasActivation) {
|
|
@@ -2893,7 +2873,7 @@ var skillsPluginsProbe = {
|
|
|
2893
2873
|
|
|
2894
2874
|
// src/doctor/probes/vault-sync.ts
|
|
2895
2875
|
import { existsSync as existsSync12, readFileSync as readFileSync8 } from "fs";
|
|
2896
|
-
import { join as
|
|
2876
|
+
import { join as join15 } from "path";
|
|
2897
2877
|
import { execSync as execSync5 } from "child_process";
|
|
2898
2878
|
import { platform as platform3 } from "os";
|
|
2899
2879
|
function readPushResultState(stateFile) {
|
|
@@ -2922,7 +2902,7 @@ function readPushResultState(stateFile) {
|
|
|
2922
2902
|
}
|
|
2923
2903
|
function readVaultSyncConfig(home) {
|
|
2924
2904
|
try {
|
|
2925
|
-
const content = readFileSync8(
|
|
2905
|
+
const content = readFileSync8(join15(home, ".skillwiki", ".env"), "utf8");
|
|
2926
2906
|
let installed = false;
|
|
2927
2907
|
let role;
|
|
2928
2908
|
let serviceScope;
|
|
@@ -3225,7 +3205,7 @@ function snapshotterHealthChecks(scope, logDir, env) {
|
|
|
3225
3205
|
let completionOutcome = "unknown";
|
|
3226
3206
|
const logRecords = fixture ? fixture.log_records : (() => {
|
|
3227
3207
|
try {
|
|
3228
|
-
const content = readFileSync8(
|
|
3208
|
+
const content = readFileSync8(join15(logDir, "wiki-snapshot.log"), "utf8");
|
|
3229
3209
|
return content.split(/\r?\n/).filter(Boolean);
|
|
3230
3210
|
} catch {
|
|
3231
3211
|
return [];
|
|
@@ -3403,11 +3383,11 @@ function vaultSyncChecks(input) {
|
|
|
3403
3383
|
];
|
|
3404
3384
|
}
|
|
3405
3385
|
const isMac = os === "darwin";
|
|
3406
|
-
const logDir = input.logDir ?? (isMac ?
|
|
3407
|
-
const cacheDir = input.cacheDir ?? (isMac ?
|
|
3408
|
-
const shareDir = input.shareDir ?? (isMac ?
|
|
3409
|
-
const filterPath = input.filterPath ??
|
|
3410
|
-
const packagedSnapshotPath =
|
|
3386
|
+
const logDir = input.logDir ?? (isMac ? join15(home, "Library", "Logs") : join15(home, ".local", "state", "vault-sync", "log"));
|
|
3387
|
+
const cacheDir = input.cacheDir ?? (isMac ? join15(home, "Library", "Caches", "vault-sync") : join15(home, ".cache", "vault-sync"));
|
|
3388
|
+
const shareDir = input.shareDir ?? (isMac ? join15(home, "Library", "Application Support", "vault-sync", "bin") : join15(home, ".local", "share", "vault-sync", "bin"));
|
|
3389
|
+
const filterPath = input.filterPath ?? join15(home, ".config", "rclone", "wiki-push-filters.txt");
|
|
3390
|
+
const packagedSnapshotPath = join15(shareDir, "wiki-snapshot.sh");
|
|
3411
3391
|
const legacySnapshotPath = "/root/.hermes/scripts/wiki-snapshot-v3.sh";
|
|
3412
3392
|
const snapshotPath = input.snapshotScriptPath ?? (existsSync12(packagedSnapshotPath) ? packagedSnapshotPath : legacySnapshotPath);
|
|
3413
3393
|
if (input.vaultSyncRole === "snapshotter") {
|
|
@@ -3464,9 +3444,9 @@ function vaultSyncChecks(input) {
|
|
|
3464
3444
|
return [c12, ...healthChecks, cFetch2, c42, c52];
|
|
3465
3445
|
}
|
|
3466
3446
|
const env = input.env ?? process.env;
|
|
3467
|
-
const fetchLogFile =
|
|
3447
|
+
const fetchLogFile = join15(logDir, "wiki-fetch.log");
|
|
3468
3448
|
if (input.pushEnabled === false) {
|
|
3469
|
-
const fetchHelperPath =
|
|
3449
|
+
const fetchHelperPath = join15(shareDir, "wiki-fetch-notify.sh");
|
|
3470
3450
|
const c12 = existsSync12(fetchHelperPath) ? check("pass", "vault_sync_installed", "Vault sync installed", `Found: ${fetchHelperPath}`) : check(
|
|
3471
3451
|
"error",
|
|
3472
3452
|
"vault_sync_installed",
|
|
@@ -3501,7 +3481,7 @@ function vaultSyncChecks(input) {
|
|
|
3501
3481
|
);
|
|
3502
3482
|
return [c12, c22, c32, cPushResult2, cFetch2, c42, c52];
|
|
3503
3483
|
}
|
|
3504
|
-
const pushScriptPath =
|
|
3484
|
+
const pushScriptPath = join15(shareDir, "wiki-push.sh");
|
|
3505
3485
|
const c1 = existsSync12(pushScriptPath) ? check("pass", "vault_sync_installed", "Vault sync installed", `Found: ${pushScriptPath}`) : check("error", "vault_sync_installed", "Vault sync installed", `Script not found at ${pushScriptPath} \u2014 run vault-sync-install`);
|
|
3506
3486
|
let c2;
|
|
3507
3487
|
try {
|
|
@@ -3553,9 +3533,9 @@ function vaultSyncChecks(input) {
|
|
|
3553
3533
|
"Scheduler check failed \u2014 run vault-sync-install"
|
|
3554
3534
|
);
|
|
3555
3535
|
}
|
|
3556
|
-
const stateFile =
|
|
3536
|
+
const stateFile = join15(cacheDir, "wiki-push-result.state");
|
|
3557
3537
|
const pushState = readPushResultState(stateFile);
|
|
3558
|
-
const logFile =
|
|
3538
|
+
const logFile = join15(logDir, "wiki-push.log");
|
|
3559
3539
|
let c3;
|
|
3560
3540
|
if (pushState.exists && !pushState.malformed && pushState.result === "refused") {
|
|
3561
3541
|
const reasonSuffix = pushState.reason ? `: ${pushState.reason}` : "";
|
|
@@ -3705,7 +3685,7 @@ function checkVaultSyncPullHelper(home, env) {
|
|
|
3705
3685
|
);
|
|
3706
3686
|
}
|
|
3707
3687
|
function isGitDir(path) {
|
|
3708
|
-
return Boolean(path && existsSync12(
|
|
3688
|
+
return Boolean(path && existsSync12(join15(path, ".git")));
|
|
3709
3689
|
}
|
|
3710
3690
|
function checkVaultSyncReviewRequiredJournals(ctx) {
|
|
3711
3691
|
const live = ctx.resolvedPath;
|
|
@@ -3800,10 +3780,10 @@ import { platform as platform4 } from "os";
|
|
|
3800
3780
|
|
|
3801
3781
|
// src/utils/satellite-run-health.ts
|
|
3802
3782
|
import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
|
|
3803
|
-
import { join as
|
|
3783
|
+
import { join as join16 } from "path";
|
|
3804
3784
|
var SATELLITE_STALE_MS = 26 * 60 * 60 * 1e3;
|
|
3805
3785
|
function satelliteLatestRunPath(vault) {
|
|
3806
|
-
return
|
|
3786
|
+
return join16(vault, ".skillwiki", "agent-memory-trends", "latest-run.json");
|
|
3807
3787
|
}
|
|
3808
3788
|
function isFailedRunStatus(status) {
|
|
3809
3789
|
return status === "fail" || status === "failure";
|
|
@@ -3945,7 +3925,7 @@ var satelliteProbe = {
|
|
|
3945
3925
|
|
|
3946
3926
|
// src/doctor/probes/metrics.ts
|
|
3947
3927
|
import { readFileSync as readFileSync10 } from "fs";
|
|
3948
|
-
import { join as
|
|
3928
|
+
import { join as join17 } from "path";
|
|
3949
3929
|
var METRIC_TYPES = ["entities", "concepts", "comparisons", "queries", "meta"];
|
|
3950
3930
|
function doctorReadOnlyScanRoot(resolvedPath) {
|
|
3951
3931
|
return resolveReadOnlyVaultRoot(resolvedPath).root;
|
|
@@ -3989,7 +3969,7 @@ async function vaultMetrics(resolvedPath) {
|
|
|
3989
3969
|
}
|
|
3990
3970
|
let logLines = 0;
|
|
3991
3971
|
try {
|
|
3992
|
-
logLines = readFileSync10(
|
|
3972
|
+
logLines = readFileSync10(join17(scanRoot, "log.md"), "utf8").split("\n").length;
|
|
3993
3973
|
} catch {
|
|
3994
3974
|
}
|
|
3995
3975
|
return [
|
|
@@ -4125,18 +4105,18 @@ var fuseStalenessProbe = {
|
|
|
4125
4105
|
|
|
4126
4106
|
// src/doctor/probes/activation-marker.ts
|
|
4127
4107
|
import { existsSync as existsSync15, readFileSync as readFileSync11, readdirSync as readdirSync5 } from "fs";
|
|
4128
|
-
import { join as
|
|
4108
|
+
import { join as join18 } from "path";
|
|
4129
4109
|
var GROK_ACTIVATION_REFERENCE2 = "Read @~/.grok/skillwiki.md for SkillWiki activation context.";
|
|
4130
4110
|
var STALE_GROK_ACTIVATION_REFERENCE2 = "Read @skillwiki.md";
|
|
4131
4111
|
var ACTIVATION_FIX_HINT2 = "run `npm run install:activation` from the llm-wiki repo";
|
|
4132
4112
|
function findGrokActivationTemplate2(home, cwd) {
|
|
4133
4113
|
if (cwd) {
|
|
4134
|
-
const src =
|
|
4114
|
+
const src = join18(cwd, "packages", "skills", "using-skillwiki", "activation.md");
|
|
4135
4115
|
if (existsSync15(src)) return src;
|
|
4136
|
-
const directSrc =
|
|
4116
|
+
const directSrc = join18(cwd, "skills", "using-skillwiki", "activation.md");
|
|
4137
4117
|
if (existsSync15(directSrc)) return directSrc;
|
|
4138
4118
|
}
|
|
4139
|
-
const pluginsRoot =
|
|
4119
|
+
const pluginsRoot = join18(home, ".grok", "installed-plugins");
|
|
4140
4120
|
if (!existsSync15(pluginsRoot)) return void 0;
|
|
4141
4121
|
let entries;
|
|
4142
4122
|
try {
|
|
@@ -4146,21 +4126,21 @@ function findGrokActivationTemplate2(home, cwd) {
|
|
|
4146
4126
|
}
|
|
4147
4127
|
for (const entry of entries) {
|
|
4148
4128
|
if (!entry.isDirectory()) continue;
|
|
4149
|
-
const root =
|
|
4129
|
+
const root = join18(pluginsRoot, entry.name);
|
|
4150
4130
|
for (const rel of ["using-skillwiki/activation.md", "skills/using-skillwiki/activation.md"]) {
|
|
4151
|
-
const candidate =
|
|
4131
|
+
const candidate = join18(root, rel);
|
|
4152
4132
|
if (existsSync15(candidate)) return candidate;
|
|
4153
4133
|
}
|
|
4154
4134
|
}
|
|
4155
4135
|
return void 0;
|
|
4156
4136
|
}
|
|
4157
4137
|
function checkActivationMarker(home, cwd) {
|
|
4158
|
-
const grokDir =
|
|
4138
|
+
const grokDir = join18(home, ".grok");
|
|
4159
4139
|
if (!existsSync15(grokDir)) {
|
|
4160
4140
|
return check("pass", "activation_marker", "Activation marker", "Not a Grok host \u2014 check skipped");
|
|
4161
4141
|
}
|
|
4162
|
-
const activationPath =
|
|
4163
|
-
const agentsPath =
|
|
4142
|
+
const activationPath = join18(grokDir, "skillwiki.md");
|
|
4143
|
+
const agentsPath = join18(grokDir, "AGENTS.md");
|
|
4164
4144
|
const hasActivation = existsSync15(activationPath);
|
|
4165
4145
|
const issues = [];
|
|
4166
4146
|
if (!hasActivation) {
|
|
@@ -4217,7 +4197,7 @@ var activationMarkerProbe = {
|
|
|
4217
4197
|
|
|
4218
4198
|
// src/doctor/probes/ds-store-noise.ts
|
|
4219
4199
|
import { existsSync as existsSync16, readdirSync as readdirSync6 } from "fs";
|
|
4220
|
-
import { join as
|
|
4200
|
+
import { join as join19 } from "path";
|
|
4221
4201
|
var VAULT_TRACKED_DIRS = ["raw", "entities", "concepts", "comparisons", "queries", "meta", "_archive", "_Templates"];
|
|
4222
4202
|
function checkDsStoreNoise(resolvedPath) {
|
|
4223
4203
|
if (resolvedPath === void 0) {
|
|
@@ -4239,13 +4219,13 @@ function checkDsStoreNoise(resolvedPath) {
|
|
|
4239
4219
|
found.push(rel ? `${rel}/.DS_Store` : ".DS_Store");
|
|
4240
4220
|
} else if (entry.isDirectory()) {
|
|
4241
4221
|
if (entry.name === ".git" || entry.name === "node_modules") continue;
|
|
4242
|
-
walk(
|
|
4222
|
+
walk(join19(dir, entry.name), rel ? `${rel}/${entry.name}` : entry.name);
|
|
4243
4223
|
}
|
|
4244
4224
|
}
|
|
4245
4225
|
}
|
|
4246
4226
|
let scannedAny = false;
|
|
4247
4227
|
for (const sub of VAULT_TRACKED_DIRS) {
|
|
4248
|
-
const subDir =
|
|
4228
|
+
const subDir = join19(resolvedPath, sub);
|
|
4249
4229
|
if (existsSync16(subDir)) {
|
|
4250
4230
|
scannedAny = true;
|
|
4251
4231
|
walk(subDir, sub);
|
|
@@ -4275,7 +4255,7 @@ var dsStoreNoiseProbe = {
|
|
|
4275
4255
|
|
|
4276
4256
|
// src/doctor/probes/mcp-handshake.ts
|
|
4277
4257
|
import { existsSync as existsSync17 } from "fs";
|
|
4278
|
-
import { join as
|
|
4258
|
+
import { join as join20 } from "path";
|
|
4279
4259
|
|
|
4280
4260
|
// src/utils/mcp-client.ts
|
|
4281
4261
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
@@ -4346,7 +4326,7 @@ function checkMcpCredential(ctx) {
|
|
|
4346
4326
|
}
|
|
4347
4327
|
function checkFrozenLeafWritePath(ctx) {
|
|
4348
4328
|
const vault = ctx.resolvedPath;
|
|
4349
|
-
if (!vault || !existsSync17(
|
|
4329
|
+
if (!vault || !existsSync17(join20(vault, ".WIKI_GIT_FROZEN"))) {
|
|
4350
4330
|
return check(
|
|
4351
4331
|
"pass",
|
|
4352
4332
|
"mcp_frozen_leaf_write_path",
|
|
@@ -4407,7 +4387,7 @@ async function checkMcpHandshake(ctx) {
|
|
|
4407
4387
|
if (!advertised) {
|
|
4408
4388
|
return handshakeRow("error", "handshake failed \u2014 missing serverInfo.version", token);
|
|
4409
4389
|
}
|
|
4410
|
-
const frozen = Boolean(ctx.resolvedPath && existsSync17(
|
|
4390
|
+
const frozen = Boolean(ctx.resolvedPath && existsSync17(join20(ctx.resolvedPath, ".WIKI_GIT_FROZEN")));
|
|
4411
4391
|
if (frozen && !tools.includes(WORKITEM_TOOL)) {
|
|
4412
4392
|
return handshakeRow(
|
|
4413
4393
|
"error",
|
|
@@ -4443,182 +4423,10 @@ var mcpHandshakeProbe = {
|
|
|
4443
4423
|
};
|
|
4444
4424
|
|
|
4445
4425
|
// src/doctor/probes/clip-outbox.ts
|
|
4446
|
-
import { existsSync as
|
|
4426
|
+
import { existsSync as existsSync18, readFileSync as readFileSync12 } from "fs";
|
|
4447
4427
|
import { execSync as execSync7 } from "child_process";
|
|
4448
4428
|
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
|
|
4429
|
+
import { join as join21 } from "path";
|
|
4622
4430
|
var CLIP_CHECK_IDS = [
|
|
4623
4431
|
"clip_config",
|
|
4624
4432
|
"clip_frozen_mirror",
|
|
@@ -4669,7 +4477,7 @@ function launchdLoaded(label) {
|
|
|
4669
4477
|
return false;
|
|
4670
4478
|
}
|
|
4671
4479
|
}
|
|
4672
|
-
function watcherStatus(env, label) {
|
|
4480
|
+
function watcherStatus(env, label, home, root) {
|
|
4673
4481
|
const fixture = env.CLIP_WATCHER_FIXTURE;
|
|
4674
4482
|
if (fixture === "loaded-enabled") return { loaded: true, enabled: true, kind: "production" };
|
|
4675
4483
|
if (fixture === "stopped") return { loaded: false, enabled: false, kind: "production" };
|
|
@@ -4681,8 +4489,17 @@ function watcherStatus(env, label) {
|
|
|
4681
4489
|
if (!launchdLoaded(label)) {
|
|
4682
4490
|
return { loaded: false, enabled: false, kind: "unknown" };
|
|
4683
4491
|
}
|
|
4684
|
-
const plist =
|
|
4685
|
-
|
|
4492
|
+
const plist = join21(home, "Library", "LaunchAgents", `${label}.plist`);
|
|
4493
|
+
try {
|
|
4494
|
+
const text = readFileSync12(plist, "utf8");
|
|
4495
|
+
const xmlRoot = xml(root);
|
|
4496
|
+
const matchesRoot = text.includes(`<key>WatchPaths</key><array><string>${xmlRoot}</string></array>`);
|
|
4497
|
+
const disabled = execSync7(`launchctl print-disabled gui/${process.getuid()}`, { encoding: "utf8", timeout: 2e3, stdio: ["ignore", "pipe", "ignore"] });
|
|
4498
|
+
const explicitlyDisabled = disabled.split("\n").some((line) => line.includes(`"${label}"`) && line.includes("true"));
|
|
4499
|
+
return { loaded: true, enabled: matchesRoot && !explicitlyDisabled, kind: "production" };
|
|
4500
|
+
} catch {
|
|
4501
|
+
return { loaded: true, enabled: false, kind: "unknown" };
|
|
4502
|
+
}
|
|
4686
4503
|
}
|
|
4687
4504
|
function pushLoaded(env) {
|
|
4688
4505
|
if (env.CLIP_PUSH_FIXTURE === "loaded") return true;
|
|
@@ -4695,9 +4512,20 @@ function credentialPresent(env, ref) {
|
|
|
4695
4512
|
const value = env[ref];
|
|
4696
4513
|
return typeof value === "string" && value.length > 0;
|
|
4697
4514
|
}
|
|
4698
|
-
function listenerOk(env) {
|
|
4515
|
+
function listenerOk(env, home) {
|
|
4699
4516
|
if (env.CLIP_LISTENER_FIXTURE === "ok") return true;
|
|
4700
|
-
return false;
|
|
4517
|
+
if (env.CLIP_LISTENER_FIXTURE === "missing" || env.CLIP_LISTENER_FIXTURE === "disabled") return false;
|
|
4518
|
+
if (!launchdLoaded(PRODUCTION_MIRROR_LABEL)) return false;
|
|
4519
|
+
const plist = join21(home, "Library", "LaunchAgents", `${PRODUCTION_MIRROR_LABEL}.plist`);
|
|
4520
|
+
try {
|
|
4521
|
+
const text = readFileSync12(plist, "utf8");
|
|
4522
|
+
if (text.includes("<key>WatchPaths</key>")) return false;
|
|
4523
|
+
const disabled = execSync7(`launchctl print-disabled gui/${process.getuid()}`, { encoding: "utf8", timeout: 2e3, stdio: ["ignore", "pipe", "ignore"] });
|
|
4524
|
+
const explicitlyDisabled = disabled.split("\n").some((line) => line.includes(`"${PRODUCTION_MIRROR_LABEL}"`) && line.includes("true"));
|
|
4525
|
+
return text.includes("mirror-watch") && text.includes(PRODUCTION_MIRROR_LABEL) && !explicitlyDisabled;
|
|
4526
|
+
} catch {
|
|
4527
|
+
return false;
|
|
4528
|
+
}
|
|
4701
4529
|
}
|
|
4702
4530
|
function conditionalCreateEvidence(env) {
|
|
4703
4531
|
return env.CLIP_CONDITIONAL_CREATE_FIXTURE === "ok";
|
|
@@ -4722,14 +4550,26 @@ var clipOutboxProbe = {
|
|
|
4722
4550
|
return notConfigured();
|
|
4723
4551
|
}
|
|
4724
4552
|
const cfg = resolved.config;
|
|
4725
|
-
const frozen =
|
|
4553
|
+
const frozen = existsSync18(join21(cfg.mirrorRoot, ".WIKI_GIT_FROZEN"));
|
|
4726
4554
|
const pushOn = ctx.vsConfig.pushEnabled !== false;
|
|
4727
4555
|
const pushIsLoaded = pushLoaded(env);
|
|
4728
|
-
const watch = watcherStatus(env, cfg.watcherLabel);
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4556
|
+
const watch = watcherStatus(env, cfg.watcherLabel, ctx.input.home, cfg.root);
|
|
4557
|
+
let s3Creds = credentialPresent(env, cfg.s3CredentialRef);
|
|
4558
|
+
let readyCreds = credentialPresent(env, cfg.readyCredentialRef);
|
|
4559
|
+
let condCreate = conditionalCreateEvidence(env);
|
|
4560
|
+
if (!env.CLIP_CREDENTIAL_FIXTURE) {
|
|
4561
|
+
try {
|
|
4562
|
+
const credentials = await loadClipCredentials(ctx.input.home, cfg, env);
|
|
4563
|
+
s3Creds = true;
|
|
4564
|
+
readyCreds = true;
|
|
4565
|
+
condCreate = await conditionalCreateProven(cfg, credentials.s3.endpoint);
|
|
4566
|
+
} catch {
|
|
4567
|
+
s3Creds = false;
|
|
4568
|
+
readyCreds = false;
|
|
4569
|
+
condCreate = false;
|
|
4570
|
+
}
|
|
4571
|
+
}
|
|
4572
|
+
const listener = listenerOk(env, ctx.input.home);
|
|
4733
4573
|
return [
|
|
4734
4574
|
check("pass", "clip_config", clipLabel("clip_config"), "clip_outbox.enabled=true; schema valid"),
|
|
4735
4575
|
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"),
|
|
@@ -4738,7 +4578,7 @@ var clipOutboxProbe = {
|
|
|
4738
4578
|
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"),
|
|
4739
4579
|
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"),
|
|
4740
4580
|
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"),
|
|
4741
|
-
listener ? check("pass", "clip_mirror_listener", clipLabel("clip_mirror_listener"),
|
|
4581
|
+
listener ? check("pass", "clip_mirror_listener", clipLabel("clip_mirror_listener"), `loaded and enabled: ${PRODUCTION_MIRROR_LABEL}`) : check("error", "clip_mirror_listener", clipLabel("clip_mirror_listener"), "inbound SSE listener disabled or missing")
|
|
4742
4582
|
];
|
|
4743
4583
|
}
|
|
4744
4584
|
};
|
|
@@ -4769,7 +4609,7 @@ function resolveSnapshotGitWorktree(home) {
|
|
|
4769
4609
|
const configured = resolveConfiguredSnapshotWorktree(home);
|
|
4770
4610
|
if (configured) return configured;
|
|
4771
4611
|
const defaultPath = "/root/wiki-git";
|
|
4772
|
-
return
|
|
4612
|
+
return existsSync19(defaultPath) ? defaultPath : void 0;
|
|
4773
4613
|
}
|
|
4774
4614
|
var DoctorRunner = class {
|
|
4775
4615
|
probes;
|
|
@@ -4849,6 +4689,9 @@ var DoctorRunner = class {
|
|
|
4849
4689
|
if (summary.info > 0) summaryParts.push(`${summary.info} info`);
|
|
4850
4690
|
summaryParts.push(`${summary.warn} warn`, `${summary.error} error`);
|
|
4851
4691
|
lines.push(summaryParts.join(" \xB7 "));
|
|
4692
|
+
if (checks.some((c) => c.id === "clip_config" && c.detail === "clip channel not configured")) {
|
|
4693
|
+
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.");
|
|
4694
|
+
}
|
|
4852
4695
|
const humanHint = redactMcpSecret(lines.join("\n"), auth.token);
|
|
4853
4696
|
return { exitCode, result: ok({ checks, summary, humanHint }) };
|
|
4854
4697
|
}
|
|
@@ -4858,7 +4701,7 @@ async function runDoctor(input) {
|
|
|
4858
4701
|
}
|
|
4859
4702
|
|
|
4860
4703
|
// src/utils/package-info.ts
|
|
4861
|
-
import { readFileSync as
|
|
4704
|
+
import { readFileSync as readFileSync13 } from "fs";
|
|
4862
4705
|
function packageJsonCandidateUrls(baseUrl = import.meta.url) {
|
|
4863
4706
|
return [
|
|
4864
4707
|
new URL("../package.json", baseUrl),
|
|
@@ -4868,7 +4711,7 @@ function packageJsonCandidateUrls(baseUrl = import.meta.url) {
|
|
|
4868
4711
|
function readCliPackageJson(baseUrl = import.meta.url) {
|
|
4869
4712
|
for (const url of packageJsonCandidateUrls(baseUrl)) {
|
|
4870
4713
|
try {
|
|
4871
|
-
const pkg = JSON.parse(
|
|
4714
|
+
const pkg = JSON.parse(readFileSync13(url, "utf8"));
|
|
4872
4715
|
if (typeof pkg.version === "string") {
|
|
4873
4716
|
return { ...pkg, version: pkg.version };
|
|
4874
4717
|
}
|
|
@@ -4880,8 +4723,8 @@ function readCliPackageJson(baseUrl = import.meta.url) {
|
|
|
4880
4723
|
|
|
4881
4724
|
// src/utils/vault-write-gates.ts
|
|
4882
4725
|
import { execFileSync } from "child_process";
|
|
4883
|
-
import { existsSync as
|
|
4884
|
-
import { join as
|
|
4726
|
+
import { existsSync as existsSync20, readdirSync as readdirSync7, readFileSync as readFileSync14, statSync as statSync3 } from "fs";
|
|
4727
|
+
import { join as join22, relative as relative2 } from "path";
|
|
4885
4728
|
var DEFAULT_DIRTY_VOLUME_THRESHOLD = 50;
|
|
4886
4729
|
var DEFAULT_CAPTURE_BUDGET = 20;
|
|
4887
4730
|
var DEFAULT_NO_DECISION_STREAK = 3;
|
|
@@ -4937,7 +4780,7 @@ function isEventLedgerPath(rel) {
|
|
|
4937
4780
|
return n === "meta/log-events" || n.startsWith("meta/log-events/");
|
|
4938
4781
|
}
|
|
4939
4782
|
function countEventLedgerFiles(vault) {
|
|
4940
|
-
return listFilesRecursive(
|
|
4783
|
+
return listFilesRecursive(join22(vault, "meta", "log-events")).length;
|
|
4941
4784
|
}
|
|
4942
4785
|
function measureDirtyVolume(vault) {
|
|
4943
4786
|
const empty = (extra = {}) => ({
|
|
@@ -4953,7 +4796,7 @@ function measureDirtyVolume(vault) {
|
|
|
4953
4796
|
is_git_repo: false,
|
|
4954
4797
|
...extra
|
|
4955
4798
|
});
|
|
4956
|
-
if (!
|
|
4799
|
+
if (!existsSync20(vault) || !statSync3(vault).isDirectory()) {
|
|
4957
4800
|
return empty();
|
|
4958
4801
|
}
|
|
4959
4802
|
const gitDir = git(vault, ["rev-parse", "--absolute-git-dir"]);
|
|
@@ -4997,8 +4840,8 @@ function measureDirtyVolume(vault) {
|
|
|
4997
4840
|
if (!rel) continue;
|
|
4998
4841
|
if (code === "??") {
|
|
4999
4842
|
untracked += 1;
|
|
5000
|
-
const abs =
|
|
5001
|
-
if (
|
|
4843
|
+
const abs = join22(vault, rel);
|
|
4844
|
+
if (existsSync20(abs) && statSync3(abs).isDirectory()) {
|
|
5002
4845
|
const files = listFilesRecursive(abs);
|
|
5003
4846
|
expanded += files.length;
|
|
5004
4847
|
addBucket(rel, files.length);
|
|
@@ -5041,9 +4884,9 @@ function listFilesRecursive(dir) {
|
|
|
5041
4884
|
}
|
|
5042
4885
|
for (const name of entries) {
|
|
5043
4886
|
if (name === ".git") continue;
|
|
5044
|
-
const p =
|
|
4887
|
+
const p = join22(dir, name);
|
|
5045
4888
|
try {
|
|
5046
|
-
const st =
|
|
4889
|
+
const st = statSync3(p);
|
|
5047
4890
|
if (st.isDirectory()) out.push(...listFilesRecursive(p));
|
|
5048
4891
|
else if (st.isFile()) out.push(p);
|
|
5049
4892
|
} catch {
|
|
@@ -5136,7 +4979,7 @@ var CAPTURE_HYGIENE_CONTRACT = `After each productive cycle (or when daily captu
|
|
|
5136
4979
|
function listProjectDayCaptures(vault, project, day) {
|
|
5137
4980
|
const found = [];
|
|
5138
4981
|
const slug = project.replace(/^\[\[/, "").replace(/\]\]$/, "").trim();
|
|
5139
|
-
if (!slug || !
|
|
4982
|
+
if (!slug || !existsSync20(vault)) return found;
|
|
5140
4983
|
const consider = (abs, rel) => {
|
|
5141
4984
|
if (!rel.endsWith(".md")) return;
|
|
5142
4985
|
const base = rel.split(/[/\\]/).pop() ?? "";
|
|
@@ -5153,7 +4996,7 @@ function listProjectDayCaptures(vault, project, day) {
|
|
|
5153
4996
|
}
|
|
5154
4997
|
if (norm.startsWith("raw/transcripts/")) {
|
|
5155
4998
|
try {
|
|
5156
|
-
const body =
|
|
4999
|
+
const body = readFileSync14(abs, "utf8");
|
|
5157
5000
|
if (body.includes(`project: ${slug}`) || body.includes(`project: "[[${slug}]]"`) || body.includes(`project: [[${slug}]]`)) {
|
|
5158
5001
|
found.push(norm);
|
|
5159
5002
|
} else if (base.includes(slug)) {
|
|
@@ -5164,7 +5007,7 @@ function listProjectDayCaptures(vault, project, day) {
|
|
|
5164
5007
|
}
|
|
5165
5008
|
};
|
|
5166
5009
|
const walk = (dir, relBase) => {
|
|
5167
|
-
if (!
|
|
5010
|
+
if (!existsSync20(dir)) return;
|
|
5168
5011
|
let entries;
|
|
5169
5012
|
try {
|
|
5170
5013
|
entries = readdirSync7(dir);
|
|
@@ -5172,27 +5015,27 @@ function listProjectDayCaptures(vault, project, day) {
|
|
|
5172
5015
|
return;
|
|
5173
5016
|
}
|
|
5174
5017
|
for (const name of entries) {
|
|
5175
|
-
const abs =
|
|
5018
|
+
const abs = join22(dir, name);
|
|
5176
5019
|
const rel = relBase ? `${relBase}/${name}` : name;
|
|
5177
5020
|
try {
|
|
5178
|
-
const st =
|
|
5021
|
+
const st = statSync3(abs);
|
|
5179
5022
|
if (st.isDirectory()) walk(abs, rel);
|
|
5180
5023
|
else if (st.isFile()) consider(abs, rel);
|
|
5181
5024
|
} catch {
|
|
5182
5025
|
}
|
|
5183
5026
|
}
|
|
5184
5027
|
};
|
|
5185
|
-
walk(
|
|
5186
|
-
walk(
|
|
5187
|
-
walk(
|
|
5188
|
-
const workRoot =
|
|
5189
|
-
if (
|
|
5028
|
+
walk(join22(vault, "raw", "transcripts"), "raw/transcripts");
|
|
5029
|
+
walk(join22(vault, "projects", slug, "raw", "transcripts"), `projects/${slug}/raw/transcripts`);
|
|
5030
|
+
walk(join22(vault, "projects", slug, "requirements"), `projects/${slug}/requirements`);
|
|
5031
|
+
const workRoot = join22(vault, "projects", slug, "work");
|
|
5032
|
+
if (existsSync20(workRoot)) {
|
|
5190
5033
|
try {
|
|
5191
5034
|
for (const name of readdirSync7(workRoot)) {
|
|
5192
5035
|
if (!name.startsWith(day)) continue;
|
|
5193
5036
|
if (!/investigate|pilot-q|research|cycle|dev-loop/.test(name)) continue;
|
|
5194
|
-
const abs =
|
|
5195
|
-
if (
|
|
5037
|
+
const abs = join22(workRoot, name);
|
|
5038
|
+
if (statSync3(abs).isDirectory()) {
|
|
5196
5039
|
for (const f of listFilesRecursive(abs)) {
|
|
5197
5040
|
const rel = relative2(vault, f).replace(/\\/g, "/");
|
|
5198
5041
|
if (rel.endsWith(".md")) found.push(rel);
|
|
@@ -5236,7 +5079,7 @@ function evaluateCaptureBudget(input) {
|
|
|
5236
5079
|
return { allowed: true, reason: "under_budget", report };
|
|
5237
5080
|
}
|
|
5238
5081
|
function runWritePreflight(input) {
|
|
5239
|
-
if (!input.vault || !
|
|
5082
|
+
if (!input.vault || !existsSync20(input.vault)) {
|
|
5240
5083
|
return err(GateError.VAULT_PATH_INVALID, { path: input.vault });
|
|
5241
5084
|
}
|
|
5242
5085
|
const want = new Set(input.checks ?? ["all"]);
|
|
@@ -5296,8 +5139,8 @@ function runWritePreflight(input) {
|
|
|
5296
5139
|
|
|
5297
5140
|
// src/commands/observe.ts
|
|
5298
5141
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
5299
|
-
import { existsSync as
|
|
5300
|
-
import { join as
|
|
5142
|
+
import { existsSync as existsSync21, statSync as statSync4 } from "fs";
|
|
5143
|
+
import { join as join23 } from "path";
|
|
5301
5144
|
import { createHash as createHash2 } from "crypto";
|
|
5302
5145
|
var ALLOWED_KINDS = /* @__PURE__ */ new Set(["note", "bug", "task", "idea", "session-log"]);
|
|
5303
5146
|
function slugify(text) {
|
|
@@ -5320,7 +5163,7 @@ async function runObserve(input) {
|
|
|
5320
5163
|
result: err("SCHEME_REJECTED", { message: "Text must not be empty" })
|
|
5321
5164
|
};
|
|
5322
5165
|
}
|
|
5323
|
-
if (!
|
|
5166
|
+
if (!existsSync21(input.vault) || !statSync4(input.vault).isDirectory()) {
|
|
5324
5167
|
return {
|
|
5325
5168
|
exitCode: ExitCode.VAULT_PATH_INVALID,
|
|
5326
5169
|
result: err("VAULT_PATH_INVALID", { path: input.vault })
|
|
@@ -5346,7 +5189,7 @@ async function runObserve(input) {
|
|
|
5346
5189
|
};
|
|
5347
5190
|
}
|
|
5348
5191
|
}
|
|
5349
|
-
const transcriptsDir =
|
|
5192
|
+
const transcriptsDir = join23(input.vault, "raw", "transcripts");
|
|
5350
5193
|
try {
|
|
5351
5194
|
await mkdir3(transcriptsDir, { recursive: true });
|
|
5352
5195
|
} catch {
|
|
@@ -5358,7 +5201,7 @@ async function runObserve(input) {
|
|
|
5358
5201
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
5359
5202
|
const slug = slugify(input.text);
|
|
5360
5203
|
const fileName = `${today}-observation-${slug}.md`;
|
|
5361
|
-
const filePath =
|
|
5204
|
+
const filePath = join23(transcriptsDir, fileName);
|
|
5362
5205
|
const body = `
|
|
5363
5206
|
${input.text.trim()}
|
|
5364
5207
|
`;
|
|
@@ -5400,7 +5243,7 @@ ${input.text.trim()}
|
|
|
5400
5243
|
// src/commands/memory.ts
|
|
5401
5244
|
import { createHash as createHash3 } from "crypto";
|
|
5402
5245
|
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
|
|
5246
|
+
import { basename as basename2, extname, join as join24, relative as relative3, sep as sep2 } from "path";
|
|
5404
5247
|
|
|
5405
5248
|
// src/utils/memory-authority.ts
|
|
5406
5249
|
var TIER_RANK = {
|
|
@@ -5519,8 +5362,8 @@ async function runMemoryIndex(input) {
|
|
|
5519
5362
|
}
|
|
5520
5363
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
5521
5364
|
const relCachePath = memoryCacheRelPath(input.project);
|
|
5522
|
-
const absCachePath =
|
|
5523
|
-
await mkdir4(
|
|
5365
|
+
const absCachePath = join24(input.vault, relCachePath);
|
|
5366
|
+
await mkdir4(join24(input.vault, ".skillwiki", "memory", input.project), { recursive: true });
|
|
5524
5367
|
await writeFile4(absCachePath, `${JSON.stringify({
|
|
5525
5368
|
generated_at: generatedAt,
|
|
5526
5369
|
project: input.project,
|
|
@@ -5712,7 +5555,7 @@ async function buildMemoryIndexState(pages, project) {
|
|
|
5712
5555
|
}
|
|
5713
5556
|
async function checkMemoryIndex(vault, project, current) {
|
|
5714
5557
|
const relCachePath = memoryCacheRelPath(project);
|
|
5715
|
-
const cacheText = await readIfExists(
|
|
5558
|
+
const cacheText = await readIfExists(join24(vault, relCachePath));
|
|
5716
5559
|
if (!cacheText) {
|
|
5717
5560
|
return {
|
|
5718
5561
|
ok: true,
|
|
@@ -6121,7 +5964,7 @@ async function walkImportFiles(dir, out) {
|
|
|
6121
5964
|
const entries = await readdir2(dir, { withFileTypes: true });
|
|
6122
5965
|
for (const entry of entries) {
|
|
6123
5966
|
if (entry.name === ".git" || entry.name === "node_modules") continue;
|
|
6124
|
-
const path =
|
|
5967
|
+
const path = join24(dir, entry.name);
|
|
6125
5968
|
if (entry.isDirectory()) {
|
|
6126
5969
|
await walkImportFiles(path, out);
|
|
6127
5970
|
} else if (entry.isFile() && isImportCandidate(path)) {
|
|
@@ -6171,7 +6014,7 @@ async function buildImportEntry(file, sourceRoot, project, today, maxBytes) {
|
|
|
6171
6014
|
const redacted = redactSensitiveContent(extracted, { file });
|
|
6172
6015
|
const privacy = redacted.findings.length > 0 ? "sensitive" : "local";
|
|
6173
6016
|
const sourceSlug = slugify2(basename2(file, extname(file)));
|
|
6174
|
-
const relSource = relative3(sourceRoot, file).split(
|
|
6017
|
+
const relSource = relative3(sourceRoot, file).split(sep2).join("/");
|
|
6175
6018
|
const entry = {
|
|
6176
6019
|
...baseEntry,
|
|
6177
6020
|
status: "ready",
|
|
@@ -6188,8 +6031,8 @@ async function writeImportCapture(vault, entry, today) {
|
|
|
6188
6031
|
const content = hiddenString(entry, "__content");
|
|
6189
6032
|
const project = hiddenString(entry, "__project");
|
|
6190
6033
|
const relPath = await availableImportPath(vault, entry.proposed_path);
|
|
6191
|
-
const absPath =
|
|
6192
|
-
await mkdir4(
|
|
6034
|
+
const absPath = join24(vault, relPath);
|
|
6035
|
+
await mkdir4(join24(vault, "raw", "transcripts"), { recursive: true });
|
|
6193
6036
|
await writeFile4(absPath, renderImportCapture(entry, content, project, today), "utf8");
|
|
6194
6037
|
const validation = await runValidate({ file: absPath });
|
|
6195
6038
|
return {
|
|
@@ -6205,7 +6048,7 @@ async function availableImportPath(vault, proposed) {
|
|
|
6205
6048
|
const stem = proposed.slice(0, -ext.length);
|
|
6206
6049
|
let candidate = proposed;
|
|
6207
6050
|
let i = 2;
|
|
6208
|
-
while (await readIfExists(
|
|
6051
|
+
while (await readIfExists(join24(vault, candidate))) {
|
|
6209
6052
|
candidate = `${stem}-${i}${ext}`;
|
|
6210
6053
|
i++;
|
|
6211
6054
|
}
|
|
@@ -6243,7 +6086,7 @@ function hiddenString(entry, key) {
|
|
|
6243
6086
|
return entry[key] ?? "";
|
|
6244
6087
|
}
|
|
6245
6088
|
function classifyImportSource(file) {
|
|
6246
|
-
const rel = file.split(
|
|
6089
|
+
const rel = file.split(sep2).join("/");
|
|
6247
6090
|
const name = basename2(file);
|
|
6248
6091
|
if (rel.includes("/.codex/memories/")) return "codex-memory";
|
|
6249
6092
|
if (rel.includes("/.codex/rules/")) return "codex-rule";
|
|
@@ -6390,10 +6233,10 @@ function memoryCacheRelPath(project) {
|
|
|
6390
6233
|
}
|
|
6391
6234
|
async function readMemoryCache(vault, project) {
|
|
6392
6235
|
if (project) {
|
|
6393
|
-
const projectCache = await readIfExists(
|
|
6236
|
+
const projectCache = await readIfExists(join24(vault, memoryCacheRelPath(project)));
|
|
6394
6237
|
if (projectCache) return projectCache;
|
|
6395
6238
|
}
|
|
6396
|
-
return readIfExists(
|
|
6239
|
+
return readIfExists(join24(vault, ".skillwiki", "memory-topics.json"));
|
|
6397
6240
|
}
|
|
6398
6241
|
function dedupePages(pages) {
|
|
6399
6242
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -6485,7 +6328,7 @@ function slugify2(value) {
|
|
|
6485
6328
|
|
|
6486
6329
|
// src/commands/query.ts
|
|
6487
6330
|
import { readFile as readFile9, stat as stat4 } from "fs/promises";
|
|
6488
|
-
import { join as
|
|
6331
|
+
import { join as join26 } from "path";
|
|
6489
6332
|
|
|
6490
6333
|
// src/utils/rrf.ts
|
|
6491
6334
|
var RRF_K = 60;
|
|
@@ -6501,8 +6344,8 @@ function fuseRankings(lists, k = RRF_K) {
|
|
|
6501
6344
|
|
|
6502
6345
|
// src/utils/vector-index.ts
|
|
6503
6346
|
import { mkdir as mkdir5, readFile as readFile8, stat as stat3 } from "fs/promises";
|
|
6504
|
-
import { join as
|
|
6505
|
-
import { existsSync as
|
|
6347
|
+
import { join as join25 } from "path";
|
|
6348
|
+
import { existsSync as existsSync22 } from "fs";
|
|
6506
6349
|
var VECTOR_INDEX_REL = ".skillwiki/vectors/index.json";
|
|
6507
6350
|
var VECTOR_INDEX_SCHEMA = "skillwiki-tfidf-index/v1";
|
|
6508
6351
|
function tokenize(text) {
|
|
@@ -6516,7 +6359,7 @@ function extractPageTokens(text) {
|
|
|
6516
6359
|
return tokenize(`${title} ${body}`);
|
|
6517
6360
|
}
|
|
6518
6361
|
function vectorIndexPath(vault) {
|
|
6519
|
-
return
|
|
6362
|
+
return join25(vault, ...VECTOR_INDEX_REL.split("/"));
|
|
6520
6363
|
}
|
|
6521
6364
|
function termFreq(tokens) {
|
|
6522
6365
|
const tf = /* @__PURE__ */ new Map();
|
|
@@ -6571,7 +6414,7 @@ async function buildVectorIndex(vault, now = (/* @__PURE__ */ new Date()).toISOS
|
|
|
6571
6414
|
docs
|
|
6572
6415
|
};
|
|
6573
6416
|
const dest = vectorIndexPath(vault);
|
|
6574
|
-
await mkdir5(
|
|
6417
|
+
await mkdir5(join25(vault, ".skillwiki", "vectors"), { recursive: true });
|
|
6575
6418
|
await atomicWriteText(dest, `${JSON.stringify(index)}
|
|
6576
6419
|
`);
|
|
6577
6420
|
return ok(index);
|
|
@@ -6614,7 +6457,7 @@ async function reindexPageInVectorIndex(vault, pageRelPath, now = (/* @__PURE__
|
|
|
6614
6457
|
if (!normalizedPage.endsWith(".md")) {
|
|
6615
6458
|
return err("USAGE", { message: `Page must be a .md file: ${pageRelPath}` });
|
|
6616
6459
|
}
|
|
6617
|
-
const absPath =
|
|
6460
|
+
const absPath = join25(vault, ...normalizedPage.split("/"));
|
|
6618
6461
|
let text;
|
|
6619
6462
|
try {
|
|
6620
6463
|
text = await readFile8(absPath, "utf8");
|
|
@@ -6699,7 +6542,7 @@ async function reindexPageInVectorIndex(vault, pageRelPath, now = (/* @__PURE__
|
|
|
6699
6542
|
}
|
|
6700
6543
|
}
|
|
6701
6544
|
const dest = vectorIndexPath(vault);
|
|
6702
|
-
await mkdir5(
|
|
6545
|
+
await mkdir5(join25(vault, ".skillwiki", "vectors"), { recursive: true });
|
|
6703
6546
|
await atomicWriteText(dest, `${JSON.stringify(index)}
|
|
6704
6547
|
`);
|
|
6705
6548
|
return ok({
|
|
@@ -6717,8 +6560,8 @@ async function pruneVectorIndex(vault, opts) {
|
|
|
6717
6560
|
const orphans = [];
|
|
6718
6561
|
for (const docKey of Object.keys(index.docs)) {
|
|
6719
6562
|
const normalizedKey = docKey.split(/\\|\//).join("/");
|
|
6720
|
-
const absPath =
|
|
6721
|
-
if (!
|
|
6563
|
+
const absPath = join25(vault, ...normalizedKey.split("/"));
|
|
6564
|
+
if (!existsSync22(absPath)) {
|
|
6722
6565
|
orphans.push(normalizedKey);
|
|
6723
6566
|
}
|
|
6724
6567
|
}
|
|
@@ -6764,7 +6607,7 @@ async function pruneVectorIndex(vault, opts) {
|
|
|
6764
6607
|
index.docs[docKey] = toTfIdf(termFreq(tokens), index.df, newPageCount);
|
|
6765
6608
|
} else {
|
|
6766
6609
|
try {
|
|
6767
|
-
const text = await readFile8(
|
|
6610
|
+
const text = await readFile8(join25(vault, ...docKey.split("/")), "utf8");
|
|
6768
6611
|
const tokens = extractPageTokens(text);
|
|
6769
6612
|
index.docs[docKey] = toTfIdf(termFreq(tokens), index.df, newPageCount);
|
|
6770
6613
|
} catch {
|
|
@@ -6774,7 +6617,7 @@ async function pruneVectorIndex(vault, opts) {
|
|
|
6774
6617
|
}
|
|
6775
6618
|
if (!opts?.dryRun) {
|
|
6776
6619
|
const dest = vectorIndexPath(vault);
|
|
6777
|
-
await mkdir5(
|
|
6620
|
+
await mkdir5(join25(vault, ".skillwiki", "vectors"), { recursive: true });
|
|
6778
6621
|
await atomicWriteText(dest, `${JSON.stringify(index)}
|
|
6779
6622
|
`);
|
|
6780
6623
|
}
|
|
@@ -6905,7 +6748,7 @@ async function runQuery(input) {
|
|
|
6905
6748
|
}
|
|
6906
6749
|
let pendingSources;
|
|
6907
6750
|
if (input.includePending) {
|
|
6908
|
-
const { runSourcesPending: runSourcesPending2 } = await import("./sources-
|
|
6751
|
+
const { runSourcesPending: runSourcesPending2 } = await import("./sources-AOYP6ROO.js");
|
|
6909
6752
|
const pending = await runSourcesPending2({
|
|
6910
6753
|
vault: input.vault,
|
|
6911
6754
|
match: input.text,
|
|
@@ -7075,7 +6918,7 @@ function computeKeywordScore(terms, title, tags, body, relPath) {
|
|
|
7075
6918
|
return score;
|
|
7076
6919
|
}
|
|
7077
6920
|
async function loadOrBuildGraph(vault) {
|
|
7078
|
-
const graphPath =
|
|
6921
|
+
const graphPath = join26(vault, ".skillwiki", "graph.json");
|
|
7079
6922
|
let needsBuild = false;
|
|
7080
6923
|
try {
|
|
7081
6924
|
const fileStat = await stat4(graphPath);
|
|
@@ -7164,27 +7007,27 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
7164
7007
|
import { z } from "zod";
|
|
7165
7008
|
|
|
7166
7009
|
// src/mcp/vault-resolve.ts
|
|
7167
|
-
import { join as
|
|
7010
|
+
import { join as join27, resolve as resolve4 } from "path";
|
|
7168
7011
|
|
|
7169
7012
|
// src/mcp/allowlist.ts
|
|
7170
|
-
import { resolve as
|
|
7171
|
-
import { realpathSync
|
|
7013
|
+
import { resolve as resolve3, sep as sep3 } from "path";
|
|
7014
|
+
import { realpathSync } from "fs";
|
|
7172
7015
|
function parseVaultAllowlist(envValue) {
|
|
7173
7016
|
if (envValue === void 0 || envValue.trim() === "") return null;
|
|
7174
|
-
return envValue.split(",").map((s) => s.trim()).filter((s) => s.length > 0).map((p) =>
|
|
7017
|
+
return envValue.split(",").map((s) => s.trim()).filter((s) => s.length > 0).map((p) => resolve3(p));
|
|
7175
7018
|
}
|
|
7176
7019
|
function vaultAllowedByList(vaultPath, allowlist) {
|
|
7177
7020
|
if (!allowlist || allowlist.length === 0) return true;
|
|
7178
7021
|
let canonical = vaultPath;
|
|
7179
7022
|
try {
|
|
7180
|
-
canonical =
|
|
7023
|
+
canonical = realpathSync(vaultPath);
|
|
7181
7024
|
} catch {
|
|
7182
|
-
canonical =
|
|
7025
|
+
canonical = resolve3(vaultPath);
|
|
7183
7026
|
}
|
|
7184
|
-
const resolved =
|
|
7027
|
+
const resolved = resolve3(canonical);
|
|
7185
7028
|
return allowlist.some((root) => {
|
|
7186
|
-
const r =
|
|
7187
|
-
return resolved === r || resolved.startsWith(r +
|
|
7029
|
+
const r = resolve3(root);
|
|
7030
|
+
return resolved === r || resolved.startsWith(r + sep3);
|
|
7188
7031
|
});
|
|
7189
7032
|
}
|
|
7190
7033
|
function getVaultAllowlistFromEnv() {
|
|
@@ -7197,7 +7040,7 @@ async function resolveMcpVault(input) {
|
|
|
7197
7040
|
let vaultPath;
|
|
7198
7041
|
let source = "resolved";
|
|
7199
7042
|
if (input.vault !== void 0 && input.vault.length > 0) {
|
|
7200
|
-
vaultPath =
|
|
7043
|
+
vaultPath = resolve4(input.vault);
|
|
7201
7044
|
source = "flag";
|
|
7202
7045
|
} else {
|
|
7203
7046
|
const r = await resolveRuntimePath({
|
|
@@ -7209,7 +7052,7 @@ async function resolveMcpVault(input) {
|
|
|
7209
7052
|
cwd: input.cwd ?? process.cwd()
|
|
7210
7053
|
});
|
|
7211
7054
|
if (!r.ok) return r;
|
|
7212
|
-
vaultPath =
|
|
7055
|
+
vaultPath = resolve4(r.data.path);
|
|
7213
7056
|
source = r.data.source;
|
|
7214
7057
|
}
|
|
7215
7058
|
const scan = await scanVault(vaultPath);
|
|
@@ -7226,7 +7069,7 @@ async function resolveMcpVault(input) {
|
|
|
7226
7069
|
return ok({ vault: vaultPath, source });
|
|
7227
7070
|
}
|
|
7228
7071
|
function defaultGraphOut(vault) {
|
|
7229
|
-
return
|
|
7072
|
+
return join27(vault, ".skillwiki", "graph.json");
|
|
7230
7073
|
}
|
|
7231
7074
|
|
|
7232
7075
|
// src/mcp/result-format.ts
|
|
@@ -7242,7 +7085,7 @@ function formatToolResult(payload) {
|
|
|
7242
7085
|
|
|
7243
7086
|
// src/mcp/audit-log.ts
|
|
7244
7087
|
import { appendFileSync, mkdirSync as mkdirSync2 } from "fs";
|
|
7245
|
-
import { join as
|
|
7088
|
+
import { join as join28 } from "path";
|
|
7246
7089
|
function auditEnabled() {
|
|
7247
7090
|
const v = process.env.SKILLWIKI_MCP_AUDIT;
|
|
7248
7091
|
if (v === "0" || v === "false") return false;
|
|
@@ -7254,7 +7097,7 @@ function auditSink() {
|
|
|
7254
7097
|
function auditFilePath() {
|
|
7255
7098
|
const custom = process.env.SKILLWIKI_MCP_AUDIT_FILE;
|
|
7256
7099
|
if (custom && custom.length > 0) return custom;
|
|
7257
|
-
return
|
|
7100
|
+
return join28(resolveSkillwikiHome(), ".skillwiki", "mcp-audit.jsonl");
|
|
7258
7101
|
}
|
|
7259
7102
|
function auditMcpToolCall(entry) {
|
|
7260
7103
|
if (!auditEnabled()) return;
|
|
@@ -7264,7 +7107,7 @@ function auditMcpToolCall(entry) {
|
|
|
7264
7107
|
return;
|
|
7265
7108
|
}
|
|
7266
7109
|
const path = auditFilePath();
|
|
7267
|
-
mkdirSync2(
|
|
7110
|
+
mkdirSync2(join28(path, ".."), { recursive: true });
|
|
7268
7111
|
appendFileSync(path, line, "utf8");
|
|
7269
7112
|
}
|
|
7270
7113
|
async function runMcpToolHandler(tool, input, fn) {
|
|
@@ -7539,7 +7382,7 @@ function registerMcpMutatingTools(server) {
|
|
|
7539
7382
|
|
|
7540
7383
|
// src/mcp/resources.ts
|
|
7541
7384
|
import { readFile as readFile11 } from "fs/promises";
|
|
7542
|
-
import { join as
|
|
7385
|
+
import { join as join30 } from "path";
|
|
7543
7386
|
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
7544
7387
|
|
|
7545
7388
|
// src/mcp/lint-bucket.ts
|
|
@@ -7669,8 +7512,8 @@ async function fetchQueryPreview(input) {
|
|
|
7669
7512
|
|
|
7670
7513
|
// src/mcp/graph-html.ts
|
|
7671
7514
|
import { readFile as readFile10 } from "fs/promises";
|
|
7672
|
-
import { join as
|
|
7673
|
-
import { existsSync as
|
|
7515
|
+
import { join as join29 } from "path";
|
|
7516
|
+
import { existsSync as existsSync23 } from "fs";
|
|
7674
7517
|
var TYPE_COLORS = {
|
|
7675
7518
|
entities: "#e74c3c",
|
|
7676
7519
|
concepts: "#27ae60",
|
|
@@ -7738,9 +7581,9 @@ ${nodeSvg}
|
|
|
7738
7581
|
return { html, node_count: nodes.length, edge_count: edges.length, truncated };
|
|
7739
7582
|
}
|
|
7740
7583
|
async function fetchGraphHtmlReport(input) {
|
|
7741
|
-
const graphPath = input.graphPath ??
|
|
7584
|
+
const graphPath = input.graphPath ?? join29(input.vault, ".skillwiki", "graph.json");
|
|
7742
7585
|
const maxNodes = Math.min(Math.max(10, input.maxNodes ?? 120), 500);
|
|
7743
|
-
if (!
|
|
7586
|
+
if (!existsSync23(graphPath)) {
|
|
7744
7587
|
return {
|
|
7745
7588
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
7746
7589
|
result: err("GRAPH_MISSING", { path: graphPath, hint: "Run skillwiki.graph_build first." })
|
|
@@ -7812,7 +7655,7 @@ async function fetchStaleSummary(input) {
|
|
|
7812
7655
|
|
|
7813
7656
|
// src/mcp/resources.ts
|
|
7814
7657
|
async function readVaultFile(vault, rel) {
|
|
7815
|
-
return readFile11(
|
|
7658
|
+
return readFile11(join30(vault, rel), "utf8");
|
|
7816
7659
|
}
|
|
7817
7660
|
async function tailLines(text, lines) {
|
|
7818
7661
|
const parts = text.split(/\r?\n/);
|
|
@@ -7898,7 +7741,7 @@ function registerMcpResources(server) {
|
|
|
7898
7741
|
if (!v.ok) {
|
|
7899
7742
|
return { contents: [{ uri: uri.href, mimeType: "text/plain", text: JSON.stringify(v) }] };
|
|
7900
7743
|
}
|
|
7901
|
-
const path =
|
|
7744
|
+
const path = join30(v.data.vault, ".skillwiki", "graph.json");
|
|
7902
7745
|
try {
|
|
7903
7746
|
const raw = await readFile11(path, "utf8");
|
|
7904
7747
|
const graph = JSON.parse(raw);
|
|
@@ -8249,13 +8092,6 @@ export {
|
|
|
8249
8092
|
renderProjectIndex,
|
|
8250
8093
|
runProjectIndex,
|
|
8251
8094
|
scanConflictMarkerBlocksInText,
|
|
8252
|
-
MCP_URL_ENV,
|
|
8253
|
-
MCP_TOKEN_ENV,
|
|
8254
|
-
MCP_HOST_ID_ENV,
|
|
8255
|
-
nonEmptyEnvValue,
|
|
8256
|
-
mcpAuthFromEnv,
|
|
8257
|
-
mergeMcpAuthIntoEnv,
|
|
8258
|
-
redactMcpSecret,
|
|
8259
8095
|
configPath,
|
|
8260
8096
|
runConfigGet,
|
|
8261
8097
|
runConfigSet,
|
|
@@ -8273,8 +8109,6 @@ export {
|
|
|
8273
8109
|
evaluateSatelliteRunHealthState,
|
|
8274
8110
|
withMcpClient,
|
|
8275
8111
|
DEFAULT_MCP_URL,
|
|
8276
|
-
CLIP_NOT_CONFIGURED,
|
|
8277
|
-
loadClipOutboxConfig,
|
|
8278
8112
|
runDoctor,
|
|
8279
8113
|
readCliPackageJson,
|
|
8280
8114
|
DEFAULT_DIRTY_VOLUME_THRESHOLD,
|