skillwiki 0.9.55 → 0.9.57
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/auto-update-bg.js +28 -8
- package/dist/chunk-7I2TPIV5.js +154 -0
- package/dist/{chunk-4BT3HY4K.js → chunk-NIPZVIHT.js} +311 -222
- package/dist/cli.js +68 -16
- package/dist/skillwiki-mcp.js +2 -2
- package/package.json +1 -1
- package/skills/.claude-plugin/plugin.json +1 -1
- package/skills/.codex-plugin/plugin.json +1 -1
- package/skills/README.md +16 -2
- package/skills/package.json +1 -1
- package/skills/skills/wiki-sync/SKILL.md +20 -3
- package/skills/wiki-sync/SKILL.md +20 -3
- package/dist/chunk-E6UWZ3S3.js +0 -62
|
@@ -1,13 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
CHECK_INTERVAL_MS,
|
|
5
|
-
CLI_DISABLE_FLAG,
|
|
6
|
-
DIST_TAG,
|
|
7
|
-
ENV_DISABLE_KEY,
|
|
8
|
-
normalizeDistTag,
|
|
3
|
+
latestFromCache,
|
|
9
4
|
semverGt
|
|
10
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-7I2TPIV5.js";
|
|
11
6
|
|
|
12
7
|
// ../shared/src/exit-codes.ts
|
|
13
8
|
var ExitCode = {
|
|
@@ -2893,6 +2888,7 @@ function buildCliSurface() {
|
|
|
2893
2888
|
syncCmd.command("lock").option("--summary <text>").option("--ttl-minutes <n>").option("--force").option("--wiki <name>");
|
|
2894
2889
|
syncCmd.command("unlock").option("--force").option("--wiki <name>");
|
|
2895
2890
|
syncCmd.command("peers").option("--wiki <name>");
|
|
2891
|
+
syncCmd.command("lint-delta").option("--base-ref <ref>").option("--wiki <name>");
|
|
2896
2892
|
const backupCmd = program.commands.find((c) => c.name() === "backup");
|
|
2897
2893
|
backupCmd.command("sync").option("--dry-run").option("--bucket <name>").option("--endpoint <url>").option("--region <region>").option("--prune").option("--wiki <name>");
|
|
2898
2894
|
backupCmd.command("restore").option("--bucket <name>").option("--endpoint <url>").option("--region <region>").option("--target <dir>").option("--wiki <name>");
|
|
@@ -4255,6 +4251,159 @@ ${split.data.body}`;
|
|
|
4255
4251
|
result: ok(input.summary ? summarizeLintOutput(output, input.examplesLimit) : output)
|
|
4256
4252
|
};
|
|
4257
4253
|
}
|
|
4254
|
+
function lintIssueFingerprint(bucket, item) {
|
|
4255
|
+
const page = extractIssuePage(item);
|
|
4256
|
+
const detail = normalizeIssueDetail(item);
|
|
4257
|
+
return `${bucket}\0${page}\0${detail}`;
|
|
4258
|
+
}
|
|
4259
|
+
function extractIssuePage(item) {
|
|
4260
|
+
if (typeof item === "string") {
|
|
4261
|
+
const m = item.match(/^([^:]+?)(?::\s|$)/);
|
|
4262
|
+
return (m?.[1] ?? item).trim();
|
|
4263
|
+
}
|
|
4264
|
+
if (item && typeof item === "object") {
|
|
4265
|
+
const obj = item;
|
|
4266
|
+
for (const key of ["path", "file", "page", "relPath"]) {
|
|
4267
|
+
if (typeof obj[key] === "string") return obj[key];
|
|
4268
|
+
}
|
|
4269
|
+
}
|
|
4270
|
+
return "";
|
|
4271
|
+
}
|
|
4272
|
+
function normalizeIssueDetail(item) {
|
|
4273
|
+
if (typeof item === "string") {
|
|
4274
|
+
return item.replace(/\s+/g, " ").trim();
|
|
4275
|
+
}
|
|
4276
|
+
try {
|
|
4277
|
+
return JSON.stringify(item, Object.keys(item).sort());
|
|
4278
|
+
} catch {
|
|
4279
|
+
return String(item);
|
|
4280
|
+
}
|
|
4281
|
+
}
|
|
4282
|
+
function collectLintErrorFingerprints(output) {
|
|
4283
|
+
const fps = /* @__PURE__ */ new Set();
|
|
4284
|
+
for (const bucket of output.by_severity.error) {
|
|
4285
|
+
for (const item of bucket.items) {
|
|
4286
|
+
fps.add(lintIssueFingerprint(bucket.kind, item));
|
|
4287
|
+
}
|
|
4288
|
+
}
|
|
4289
|
+
return fps;
|
|
4290
|
+
}
|
|
4291
|
+
async function runSyncLintDelta(input) {
|
|
4292
|
+
const { mkdtempSync, rmSync, existsSync: fsExists } = await import("fs");
|
|
4293
|
+
const { join: pathJoin } = await import("path");
|
|
4294
|
+
const { tmpdir } = await import("os");
|
|
4295
|
+
const { execFileSync: execFileSync2 } = await import("child_process");
|
|
4296
|
+
const vault = input.vault;
|
|
4297
|
+
const baseRef = input.baseRef ?? "origin/main";
|
|
4298
|
+
const days = input.days ?? 90;
|
|
4299
|
+
const lines = input.lines ?? 200;
|
|
4300
|
+
const logThreshold = input.logThreshold ?? 500;
|
|
4301
|
+
if (!fsExists(pathJoin(vault, ".git"))) {
|
|
4302
|
+
return {
|
|
4303
|
+
exitCode: ExitCode.VAULT_PATH_INVALID,
|
|
4304
|
+
result: err("NOT_A_GIT_REPO", { path: vault })
|
|
4305
|
+
};
|
|
4306
|
+
}
|
|
4307
|
+
try {
|
|
4308
|
+
execFileSync2("git", ["rev-parse", "--verify", baseRef], {
|
|
4309
|
+
cwd: vault,
|
|
4310
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
4311
|
+
});
|
|
4312
|
+
} catch {
|
|
4313
|
+
return {
|
|
4314
|
+
exitCode: ExitCode.LINT_HAS_ERRORS,
|
|
4315
|
+
result: err("LINT_DELTA_BASE_UNAVAILABLE", {
|
|
4316
|
+
baseRef,
|
|
4317
|
+
message: `base ref ${baseRef} does not resolve \u2014 fail closed`
|
|
4318
|
+
})
|
|
4319
|
+
};
|
|
4320
|
+
}
|
|
4321
|
+
const fullLint = await runLint({ vault, days, lines, logThreshold });
|
|
4322
|
+
if (!fullLint.result.ok) {
|
|
4323
|
+
return {
|
|
4324
|
+
exitCode: ExitCode.LINT_HAS_ERRORS,
|
|
4325
|
+
result: err("LINT_DELTA_FULL_FAILED", { detail: fullLint.result })
|
|
4326
|
+
};
|
|
4327
|
+
}
|
|
4328
|
+
const fullOutput = fullLint.result.data;
|
|
4329
|
+
if (!("by_severity" in fullOutput) || !fullOutput.by_severity) {
|
|
4330
|
+
return {
|
|
4331
|
+
exitCode: ExitCode.LINT_HAS_ERRORS,
|
|
4332
|
+
result: err("LINT_DELTA_MALFORMED", { message: "full lint missing by_severity" })
|
|
4333
|
+
};
|
|
4334
|
+
}
|
|
4335
|
+
const fullFps = collectLintErrorFingerprints(fullOutput);
|
|
4336
|
+
const tmpRoot = mkdtempSync(pathJoin(tmpdir(), "skillwiki-lint-delta-"));
|
|
4337
|
+
try {
|
|
4338
|
+
const archive = execFileSync2("git", ["archive", "--format=tar", baseRef], {
|
|
4339
|
+
cwd: vault,
|
|
4340
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
4341
|
+
maxBuffer: 256 * 1024 * 1024
|
|
4342
|
+
});
|
|
4343
|
+
execFileSync2("tar", ["-xf", "-"], {
|
|
4344
|
+
cwd: tmpRoot,
|
|
4345
|
+
input: archive,
|
|
4346
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
4347
|
+
});
|
|
4348
|
+
if (!fsExists(pathJoin(tmpRoot, "SCHEMA.md"))) {
|
|
4349
|
+
}
|
|
4350
|
+
const baseLint = await runLint({ vault: tmpRoot, days, lines, logThreshold });
|
|
4351
|
+
if (!baseLint.result.ok) {
|
|
4352
|
+
return {
|
|
4353
|
+
exitCode: ExitCode.LINT_HAS_ERRORS,
|
|
4354
|
+
result: err("LINT_DELTA_BASE_LINT_FAILED", {
|
|
4355
|
+
baseRef,
|
|
4356
|
+
detail: baseLint.result
|
|
4357
|
+
})
|
|
4358
|
+
};
|
|
4359
|
+
}
|
|
4360
|
+
const baseOutput = baseLint.result.data;
|
|
4361
|
+
if (!("by_severity" in baseOutput) || !baseOutput.by_severity) {
|
|
4362
|
+
return {
|
|
4363
|
+
exitCode: ExitCode.LINT_HAS_ERRORS,
|
|
4364
|
+
result: err("LINT_DELTA_MALFORMED", { message: "base lint missing by_severity" })
|
|
4365
|
+
};
|
|
4366
|
+
}
|
|
4367
|
+
const baseFps = collectLintErrorFingerprints(baseOutput);
|
|
4368
|
+
const newFps = [];
|
|
4369
|
+
const resolvedFps = [];
|
|
4370
|
+
for (const fp of fullFps) {
|
|
4371
|
+
if (!baseFps.has(fp)) newFps.push(fp);
|
|
4372
|
+
}
|
|
4373
|
+
for (const fp of baseFps) {
|
|
4374
|
+
if (!fullFps.has(fp)) resolvedFps.push(fp);
|
|
4375
|
+
}
|
|
4376
|
+
newFps.sort();
|
|
4377
|
+
resolvedFps.sort();
|
|
4378
|
+
const fullList = [...fullFps].sort();
|
|
4379
|
+
const output = {
|
|
4380
|
+
full_errors: fullFps.size,
|
|
4381
|
+
base_errors: baseFps.size,
|
|
4382
|
+
new_errors: newFps.length,
|
|
4383
|
+
resolved_errors: resolvedFps.length,
|
|
4384
|
+
full_fingerprints: fullList,
|
|
4385
|
+
new_fingerprints: newFps,
|
|
4386
|
+
resolved_fingerprints: resolvedFps,
|
|
4387
|
+
base_ref: baseRef,
|
|
4388
|
+
humanHint: newFps.length > 0 ? `lint delta: ${newFps.length} new error(s) vs ${baseRef} (full=${fullFps.size}, base=${baseFps.size}, resolved=${resolvedFps.length})` : fullFps.size > 0 ? `lint delta: 0 new errors vs ${baseRef}; inherited full_errors=${fullFps.size} (base=${baseFps.size}, resolved=${resolvedFps.length})` : `lint delta: clean (0 errors) vs ${baseRef}`
|
|
4389
|
+
};
|
|
4390
|
+
const exitCode = output.new_errors > 0 ? ExitCode.LINT_HAS_ERRORS : fullLint.exitCode === ExitCode.LINT_HAS_WARNINGS ? ExitCode.LINT_HAS_WARNINGS : ExitCode.OK;
|
|
4391
|
+
return { exitCode, result: ok(output) };
|
|
4392
|
+
} catch (e) {
|
|
4393
|
+
return {
|
|
4394
|
+
exitCode: ExitCode.LINT_HAS_ERRORS,
|
|
4395
|
+
result: err("LINT_DELTA_ARCHIVE_FAILED", {
|
|
4396
|
+
baseRef,
|
|
4397
|
+
message: String(e)
|
|
4398
|
+
})
|
|
4399
|
+
};
|
|
4400
|
+
} finally {
|
|
4401
|
+
try {
|
|
4402
|
+
rmSync(tmpRoot, { recursive: true, force: true });
|
|
4403
|
+
} catch {
|
|
4404
|
+
}
|
|
4405
|
+
}
|
|
4406
|
+
}
|
|
4258
4407
|
|
|
4259
4408
|
// src/commands/config.ts
|
|
4260
4409
|
import { readFile as readFile13 } from "fs/promises";
|
|
@@ -4317,71 +4466,12 @@ async function runConfigPath(input) {
|
|
|
4317
4466
|
return { exitCode: ExitCode.OK, result: ok({ path: filePath, exists: existsSync6(filePath), humanHint: filePath }) };
|
|
4318
4467
|
}
|
|
4319
4468
|
|
|
4320
|
-
// src/utils/auto-update.ts
|
|
4321
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync7, mkdirSync as mkdirSync3 } from "fs";
|
|
4322
|
-
import { join as join17, dirname as dirname7 } from "path";
|
|
4323
|
-
import { spawn } from "child_process";
|
|
4324
|
-
function cachePath(home) {
|
|
4325
|
-
return join17(home, ".skillwiki", CACHE_FILENAME);
|
|
4326
|
-
}
|
|
4327
|
-
function readCacheRaw(home) {
|
|
4328
|
-
try {
|
|
4329
|
-
const raw = readFileSync4(cachePath(home), "utf8");
|
|
4330
|
-
return JSON.parse(raw);
|
|
4331
|
-
} catch {
|
|
4332
|
-
return null;
|
|
4333
|
-
}
|
|
4334
|
-
}
|
|
4335
|
-
function readCache(home) {
|
|
4336
|
-
const cache = readCacheRaw(home);
|
|
4337
|
-
if (!cache) return { cache: null, hasUpdate: false, isStale: true };
|
|
4338
|
-
const isStale = Date.now() - cache.lastCheck >= CHECK_INTERVAL_MS;
|
|
4339
|
-
const hasUpdate = !!cache.latestVersion && semverGt(cache.latestVersion, cache.currentVersion);
|
|
4340
|
-
return { cache, hasUpdate, isStale };
|
|
4341
|
-
}
|
|
4342
|
-
function writeCache(home, cache) {
|
|
4343
|
-
const p = cachePath(home);
|
|
4344
|
-
mkdirSync3(dirname7(p), { recursive: true });
|
|
4345
|
-
writeFileSync3(p, JSON.stringify(cache, null, 2));
|
|
4346
|
-
}
|
|
4347
|
-
function latestFromCache(home, currentVersion) {
|
|
4348
|
-
const { cache } = readCache(home);
|
|
4349
|
-
if (!cache || !cache.latestVersion) return { hasUpdate: false, latest: null, distTag: DIST_TAG };
|
|
4350
|
-
const distTag = normalizeDistTag(cache.distTag);
|
|
4351
|
-
return {
|
|
4352
|
-
hasUpdate: semverGt(cache.latestVersion, currentVersion),
|
|
4353
|
-
latest: cache.latestVersion,
|
|
4354
|
-
distTag
|
|
4355
|
-
};
|
|
4356
|
-
}
|
|
4357
|
-
function distTagFromCache(home) {
|
|
4358
|
-
return normalizeDistTag(readCacheRaw(home)?.distTag);
|
|
4359
|
-
}
|
|
4360
|
-
function isDisabled() {
|
|
4361
|
-
return !!(process.env[ENV_DISABLE_KEY] || process.env.NODE_ENV === "test" || process.argv.includes(CLI_DISABLE_FLAG));
|
|
4362
|
-
}
|
|
4363
|
-
function triggerAutoUpdate(home, currentVersion) {
|
|
4364
|
-
if (isDisabled()) return;
|
|
4365
|
-
const { isStale } = readCache(home);
|
|
4366
|
-
if (!isStale) return;
|
|
4367
|
-
const distTag = distTagFromCache(home);
|
|
4368
|
-
const bgScript = new URL("../auto-update-bg.js", import.meta.url).pathname;
|
|
4369
|
-
if (!existsSync7(bgScript)) return;
|
|
4370
|
-
const child = spawn(process.execPath, [bgScript, home, currentVersion, distTag], {
|
|
4371
|
-
detached: true,
|
|
4372
|
-
stdio: "ignore"
|
|
4373
|
-
});
|
|
4374
|
-
child.on("error", () => {
|
|
4375
|
-
});
|
|
4376
|
-
child.unref();
|
|
4377
|
-
}
|
|
4378
|
-
|
|
4379
4469
|
// src/commands/fleet.ts
|
|
4380
4470
|
import { readFile as readFile14 } from "fs/promises";
|
|
4381
4471
|
import { hostname as nodeHostname, userInfo } from "os";
|
|
4382
|
-
import { join as
|
|
4472
|
+
import { join as join17 } from "path";
|
|
4383
4473
|
import yaml3 from "js-yaml";
|
|
4384
|
-
var FLEET_REL_PATH =
|
|
4474
|
+
var FLEET_REL_PATH = join17("projects", "llm-wiki", "architecture", "fleet.yaml");
|
|
4385
4475
|
async function runFleetValidate(input) {
|
|
4386
4476
|
const loaded = await loadFleetManifest(input.file);
|
|
4387
4477
|
if (!loaded.ok) {
|
|
@@ -4412,7 +4502,7 @@ async function runFleetContext(input) {
|
|
|
4412
4502
|
const osHostname = input.osHostname ?? safeEnvValue(env.HOSTNAME) ?? nodeHostname();
|
|
4413
4503
|
const user = input.user ?? safeEnvValue(env.USER) ?? safeUserName();
|
|
4414
4504
|
const vault = input.vault ?? safeEnvValue(env.WIKI_PATH);
|
|
4415
|
-
const file = input.file ?? (vault ?
|
|
4505
|
+
const file = input.file ?? (vault ? join17(vault, FLEET_REL_PATH) : void 0);
|
|
4416
4506
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
4417
4507
|
const loaded = file ? await loadFleetManifest(file) : { ok: false, error: "FILE_NOT_FOUND" };
|
|
4418
4508
|
if (!loaded.ok) {
|
|
@@ -4532,7 +4622,7 @@ function fleetContextEnv(input) {
|
|
|
4532
4622
|
const home = input.home ?? env.HOME ?? "";
|
|
4533
4623
|
const osHostname = input.osHostname ?? safeEnvValue(env.HOSTNAME) ?? nodeHostname();
|
|
4534
4624
|
const vault = input.vault ?? safeEnvValue(env.WIKI_PATH);
|
|
4535
|
-
const file = input.file ?? (vault ?
|
|
4625
|
+
const file = input.file ?? (vault ? join17(vault, FLEET_REL_PATH) : void 0);
|
|
4536
4626
|
return { env, home, osHostname, vault, file };
|
|
4537
4627
|
}
|
|
4538
4628
|
async function loadFleetManifestAndHost(input) {
|
|
@@ -4666,7 +4756,7 @@ async function resolveFleetHostId(input) {
|
|
|
4666
4756
|
}
|
|
4667
4757
|
trace.push({ source: "AGENT_HOST_ID", status: "unset" });
|
|
4668
4758
|
if (input.home) {
|
|
4669
|
-
const dotenv = await parseDotenvFile(
|
|
4759
|
+
const dotenv = await parseDotenvFile(join17(input.home, ".skillwiki", ".env"));
|
|
4670
4760
|
if (dotenv.SKILLWIKI_HOST_ID) {
|
|
4671
4761
|
trace.push({ source: "~/.skillwiki/.env:SKILLWIKI_HOST_ID", status: "matched", value: dotenv.SKILLWIKI_HOST_ID });
|
|
4672
4762
|
return { hostId: dotenv.SKILLWIKI_HOST_ID, source: "~/.skillwiki/.env:SKILLWIKI_HOST_ID", trace };
|
|
@@ -4839,20 +4929,20 @@ function safeUserName() {
|
|
|
4839
4929
|
}
|
|
4840
4930
|
|
|
4841
4931
|
// src/commands/doctor.ts
|
|
4842
|
-
import { existsSync as
|
|
4843
|
-
import { join as
|
|
4932
|
+
import { existsSync as existsSync12, lstatSync, readlinkSync, readdirSync as readdirSync3, statSync, readFileSync as readFileSync9 } from "fs";
|
|
4933
|
+
import { join as join23, resolve as resolve5 } from "path";
|
|
4844
4934
|
import { execSync as execSync2 } from "child_process";
|
|
4845
4935
|
import { platform as platform2 } from "os";
|
|
4846
4936
|
|
|
4847
4937
|
// src/utils/plugin-registry.ts
|
|
4848
|
-
import { existsSync as
|
|
4849
|
-
import { join as
|
|
4850
|
-
var REGISTRY_PATH =
|
|
4851
|
-
var CODEX_CONFIG_PATH =
|
|
4938
|
+
import { existsSync as existsSync7, readdirSync, readFileSync as readFileSync4 } from "fs";
|
|
4939
|
+
import { join as join18 } from "path";
|
|
4940
|
+
var REGISTRY_PATH = join18(".claude", "plugins", "installed_plugins.json");
|
|
4941
|
+
var CODEX_CONFIG_PATH = join18(".codex", "config.toml");
|
|
4852
4942
|
var PLUGIN_KEY = "skillwiki@llm-wiki";
|
|
4853
4943
|
function readInstalledPlugins(home) {
|
|
4854
4944
|
try {
|
|
4855
|
-
const raw =
|
|
4945
|
+
const raw = readFileSync4(join18(home, REGISTRY_PATH), "utf8");
|
|
4856
4946
|
return JSON.parse(raw);
|
|
4857
4947
|
} catch {
|
|
4858
4948
|
return null;
|
|
@@ -4888,8 +4978,8 @@ function findPluginInstallations(home, key = PLUGIN_KEY) {
|
|
|
4888
4978
|
function findCodexPlugin(home, key, pluginName, marketplace) {
|
|
4889
4979
|
const config = readCodexPluginConfig(home, key, marketplace);
|
|
4890
4980
|
if (!config?.enabled) return null;
|
|
4891
|
-
const cacheRoot =
|
|
4892
|
-
if (!
|
|
4981
|
+
const cacheRoot = join18(home, ".codex", "plugins", "cache", marketplace, pluginName);
|
|
4982
|
+
if (!existsSync7(cacheRoot)) return null;
|
|
4893
4983
|
let versions;
|
|
4894
4984
|
try {
|
|
4895
4985
|
versions = readdirSync(cacheRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
@@ -4904,7 +4994,7 @@ function findCodexPlugin(home, key, pluginName, marketplace) {
|
|
|
4904
4994
|
key,
|
|
4905
4995
|
pluginName,
|
|
4906
4996
|
marketplace,
|
|
4907
|
-
installPath:
|
|
4997
|
+
installPath: join18(cacheRoot, version),
|
|
4908
4998
|
version,
|
|
4909
4999
|
sourceType: config.sourceType,
|
|
4910
5000
|
source: config.source
|
|
@@ -4921,7 +5011,7 @@ function parsePluginKey(key) {
|
|
|
4921
5011
|
function readCodexPluginConfig(home, key, marketplace) {
|
|
4922
5012
|
let raw;
|
|
4923
5013
|
try {
|
|
4924
|
-
raw =
|
|
5014
|
+
raw = readFileSync4(join18(home, CODEX_CONFIG_PATH), "utf8");
|
|
4925
5015
|
} catch {
|
|
4926
5016
|
return null;
|
|
4927
5017
|
}
|
|
@@ -4963,8 +5053,8 @@ function parseTomlScalar(rawValue) {
|
|
|
4963
5053
|
}
|
|
4964
5054
|
|
|
4965
5055
|
// src/utils/conflict-markers.ts
|
|
4966
|
-
import { existsSync as
|
|
4967
|
-
import { join as
|
|
5056
|
+
import { existsSync as existsSync8, readdirSync as readdirSync2, readFileSync as readFileSync5 } from "fs";
|
|
5057
|
+
import { join as join19 } from "path";
|
|
4968
5058
|
function scanConflictMarkerBlocksInText(relPath, text) {
|
|
4969
5059
|
const findings = [];
|
|
4970
5060
|
const lines = text.split(/\r?\n/);
|
|
@@ -5015,21 +5105,21 @@ function walkMarkdownFiles2(root, dir, rel, out) {
|
|
|
5015
5105
|
for (const entry of entries) {
|
|
5016
5106
|
if (entry.isDirectory()) {
|
|
5017
5107
|
if (PRUNE_DIRS.has(entry.name)) continue;
|
|
5018
|
-
walkMarkdownFiles2(root,
|
|
5108
|
+
walkMarkdownFiles2(root, join19(dir, entry.name), rel ? `${rel}/${entry.name}` : entry.name, out);
|
|
5019
5109
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
5020
5110
|
out.push(rel ? `${rel}/${entry.name}` : entry.name);
|
|
5021
5111
|
}
|
|
5022
5112
|
}
|
|
5023
5113
|
}
|
|
5024
5114
|
function scanVaultConflictMarkers(vaultRoot) {
|
|
5025
|
-
if (!
|
|
5115
|
+
if (!existsSync8(vaultRoot)) return [];
|
|
5026
5116
|
const relPaths = [];
|
|
5027
5117
|
walkMarkdownFiles2(vaultRoot, vaultRoot, "", relPaths);
|
|
5028
5118
|
const all = [];
|
|
5029
5119
|
for (const rel of relPaths) {
|
|
5030
5120
|
let text;
|
|
5031
5121
|
try {
|
|
5032
|
-
text =
|
|
5122
|
+
text = readFileSync5(join19(vaultRoot, rel), "utf8");
|
|
5033
5123
|
} catch {
|
|
5034
5124
|
continue;
|
|
5035
5125
|
}
|
|
@@ -5039,8 +5129,8 @@ function scanVaultConflictMarkers(vaultRoot) {
|
|
|
5039
5129
|
}
|
|
5040
5130
|
|
|
5041
5131
|
// src/utils/remote-health.ts
|
|
5042
|
-
import { existsSync as
|
|
5043
|
-
import { join as
|
|
5132
|
+
import { existsSync as existsSync9, readFileSync as readFileSync6 } from "fs";
|
|
5133
|
+
import { join as join20 } from "path";
|
|
5044
5134
|
import { execFileSync } from "child_process";
|
|
5045
5135
|
var REMOTE_PROBE_TIMEOUT_MS = 3e3;
|
|
5046
5136
|
var defaultExec = (file, args, cwd) => execFileSync(file, args, {
|
|
@@ -5052,7 +5142,7 @@ var defaultExec = (file, args, cwd) => execFileSync(file, args, {
|
|
|
5052
5142
|
var DEFAULT_WIKI_S3_REMOTE = "seaweed-wiki:cloud/wiki";
|
|
5053
5143
|
function readWikiS3RemoteConfigured(home) {
|
|
5054
5144
|
try {
|
|
5055
|
-
const content =
|
|
5145
|
+
const content = readFileSync6(join20(home, ".skillwiki", ".env"), "utf8");
|
|
5056
5146
|
for (const line of content.split(/\r?\n/)) {
|
|
5057
5147
|
const trimmed = line.trim();
|
|
5058
5148
|
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
@@ -5070,7 +5160,7 @@ function readWikiS3RemoteFromEnv(home) {
|
|
|
5070
5160
|
return readWikiS3RemoteConfigured(home) ?? DEFAULT_WIKI_S3_REMOTE;
|
|
5071
5161
|
}
|
|
5072
5162
|
function probeGithubReachability(vaultPath, exec = defaultExec) {
|
|
5073
|
-
if (!
|
|
5163
|
+
if (!existsSync9(join20(vaultPath, ".git"))) return "unknown";
|
|
5074
5164
|
try {
|
|
5075
5165
|
exec("git", ["remote", "get-url", "origin"], vaultPath);
|
|
5076
5166
|
} catch {
|
|
@@ -5131,11 +5221,11 @@ function probeRemoteHealth(input) {
|
|
|
5131
5221
|
}
|
|
5132
5222
|
|
|
5133
5223
|
// src/utils/satellite-run-health.ts
|
|
5134
|
-
import { existsSync as
|
|
5135
|
-
import { join as
|
|
5224
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7 } from "fs";
|
|
5225
|
+
import { join as join21 } from "path";
|
|
5136
5226
|
var SATELLITE_STALE_MS = 26 * 60 * 60 * 1e3;
|
|
5137
5227
|
function satelliteLatestRunPath(vault) {
|
|
5138
|
-
return
|
|
5228
|
+
return join21(vault, ".skillwiki", "agent-memory-trends", "latest-run.json");
|
|
5139
5229
|
}
|
|
5140
5230
|
function isFailedRunStatus(status) {
|
|
5141
5231
|
return status === "fail" || status === "failure";
|
|
@@ -5157,9 +5247,9 @@ function readSatelliteLatestRunFromText(text) {
|
|
|
5157
5247
|
}
|
|
5158
5248
|
function readSatelliteLatestRun(vault) {
|
|
5159
5249
|
const latestPath = satelliteLatestRunPath(vault);
|
|
5160
|
-
if (!
|
|
5250
|
+
if (!existsSync10(latestPath)) return null;
|
|
5161
5251
|
try {
|
|
5162
|
-
return parseLatestRunFile(
|
|
5252
|
+
return parseLatestRunFile(readFileSync7(latestPath, "utf8"));
|
|
5163
5253
|
} catch {
|
|
5164
5254
|
return null;
|
|
5165
5255
|
}
|
|
@@ -5188,8 +5278,8 @@ function evaluateSatelliteRunHealth(vault, now) {
|
|
|
5188
5278
|
// src/utils/s3-mount-health.ts
|
|
5189
5279
|
import { execSync } from "child_process";
|
|
5190
5280
|
import { platform } from "os";
|
|
5191
|
-
import { readFileSync as
|
|
5192
|
-
import { join as
|
|
5281
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync3, unlinkSync as unlinkSync3, readFileSync as readFile15 } from "fs";
|
|
5282
|
+
import { join as join22 } from "path";
|
|
5193
5283
|
var OS = platform();
|
|
5194
5284
|
function findRcloneMountPid() {
|
|
5195
5285
|
try {
|
|
@@ -5273,7 +5363,7 @@ function extractRcloneFs(args) {
|
|
|
5273
5363
|
function getRcloneArgs(pid) {
|
|
5274
5364
|
try {
|
|
5275
5365
|
if (OS === "linux") {
|
|
5276
|
-
const raw =
|
|
5366
|
+
const raw = readFileSync8(`/proc/${pid}/cmdline`);
|
|
5277
5367
|
return new TextDecoder().decode(raw).split("\0").filter(Boolean);
|
|
5278
5368
|
} else {
|
|
5279
5369
|
const out = execSync(`ps -o args= -p ${pid}`, {
|
|
@@ -5316,7 +5406,7 @@ function queryRcloneRC(rcAddr, fs) {
|
|
|
5316
5406
|
function detectFuseMount(vaultPath) {
|
|
5317
5407
|
try {
|
|
5318
5408
|
if (OS === "linux") {
|
|
5319
|
-
const mounts =
|
|
5409
|
+
const mounts = readFileSync8("/proc/mounts", "utf8");
|
|
5320
5410
|
let best = null;
|
|
5321
5411
|
for (const line of mounts.split("\n")) {
|
|
5322
5412
|
const parts = line.split(" ");
|
|
@@ -5347,11 +5437,11 @@ function detectFuseMount(vaultPath) {
|
|
|
5347
5437
|
return null;
|
|
5348
5438
|
}
|
|
5349
5439
|
function writeTest(dir) {
|
|
5350
|
-
const testFile =
|
|
5440
|
+
const testFile = join22(dir, `.doctor-write-test-${process.pid}.tmp`);
|
|
5351
5441
|
const payload = `skillwiki doctor write test \u2014 ${Date.now()} \u2014 ${Math.random().toString(36).slice(2)}`;
|
|
5352
5442
|
const start = Date.now();
|
|
5353
5443
|
try {
|
|
5354
|
-
|
|
5444
|
+
writeFileSync3(testFile, payload, "utf8");
|
|
5355
5445
|
} catch (e) {
|
|
5356
5446
|
return { success: false, writeMs: Date.now() - start, readMs: 0, size: 0, error: `write failed: ${e.message}` };
|
|
5357
5447
|
}
|
|
@@ -5447,13 +5537,13 @@ function detectCliChannels(argv, home) {
|
|
|
5447
5537
|
}
|
|
5448
5538
|
const plugin = findPlugin(home);
|
|
5449
5539
|
if (plugin) {
|
|
5450
|
-
const pluginBin =
|
|
5451
|
-
if (
|
|
5540
|
+
const pluginBin = join23(plugin.installPath, "bin", "skillwiki");
|
|
5541
|
+
if (existsSync12(pluginBin)) {
|
|
5452
5542
|
channels.push({ name: "plugin", path: pluginBin, isDevLink: false });
|
|
5453
5543
|
}
|
|
5454
5544
|
}
|
|
5455
|
-
const installBin =
|
|
5456
|
-
if (
|
|
5545
|
+
const installBin = join23(home, ".claude", "skills", "bin", "skillwiki");
|
|
5546
|
+
if (existsSync12(installBin)) {
|
|
5457
5547
|
channels.push({ name: "install", path: installBin, isDevLink: false });
|
|
5458
5548
|
}
|
|
5459
5549
|
return channels;
|
|
@@ -5514,7 +5604,7 @@ function isDevSourceRun(argv) {
|
|
|
5514
5604
|
}
|
|
5515
5605
|
async function checkConfigFile(home) {
|
|
5516
5606
|
const cfgPath = configPath(home);
|
|
5517
|
-
if (!
|
|
5607
|
+
if (!existsSync12(cfgPath)) {
|
|
5518
5608
|
return check("warn", "config_file", "Config file exists", `${cfgPath} not found`);
|
|
5519
5609
|
}
|
|
5520
5610
|
try {
|
|
@@ -5529,7 +5619,7 @@ function checkWikiPathExists(resolvedPath) {
|
|
|
5529
5619
|
if (resolvedPath === void 0) {
|
|
5530
5620
|
return check("error", "wiki_path_exists", "Vault directory exists", "Cannot check \u2014 WIKI_PATH not resolved");
|
|
5531
5621
|
}
|
|
5532
|
-
if (
|
|
5622
|
+
if (existsSync12(resolvedPath) && statSync(resolvedPath).isDirectory()) {
|
|
5533
5623
|
return check("pass", "wiki_path_exists", "Vault directory exists", resolvedPath);
|
|
5534
5624
|
}
|
|
5535
5625
|
return check("error", "wiki_path_exists", "Vault directory exists", `${resolvedPath} does not exist or is not a directory`);
|
|
@@ -5538,13 +5628,13 @@ function checkVaultStructure(resolvedPath) {
|
|
|
5538
5628
|
if (resolvedPath === void 0) {
|
|
5539
5629
|
return check("error", "vault_structure", "Vault structure valid", "Cannot check \u2014 WIKI_PATH not resolved");
|
|
5540
5630
|
}
|
|
5541
|
-
if (!
|
|
5631
|
+
if (!existsSync12(resolvedPath)) {
|
|
5542
5632
|
return check("error", "vault_structure", "Vault structure valid", "Cannot check \u2014 vault directory does not exist");
|
|
5543
5633
|
}
|
|
5544
5634
|
const missing = [];
|
|
5545
|
-
if (!
|
|
5635
|
+
if (!existsSync12(join23(resolvedPath, "SCHEMA.md"))) missing.push("SCHEMA.md");
|
|
5546
5636
|
for (const dir of ["raw", "entities", "concepts", "meta"]) {
|
|
5547
|
-
if (!
|
|
5637
|
+
if (!existsSync12(join23(resolvedPath, dir))) missing.push(dir + "/");
|
|
5548
5638
|
}
|
|
5549
5639
|
if (missing.length === 0) {
|
|
5550
5640
|
return check("pass", "vault_structure", "Vault structure valid", "All required files and directories present");
|
|
@@ -5552,8 +5642,8 @@ function checkVaultStructure(resolvedPath) {
|
|
|
5552
5642
|
return check("warn", "vault_structure", "Vault structure valid", `Missing: ${missing.join(", ")} \u2014 run \`skillwiki init\` to add CodeWiki structure`);
|
|
5553
5643
|
}
|
|
5554
5644
|
function checkSkillsInstalled(home, cwd) {
|
|
5555
|
-
const srcDir = cwd ?
|
|
5556
|
-
if (srcDir &&
|
|
5645
|
+
const srcDir = cwd ? join23(cwd, "packages", "skills") : void 0;
|
|
5646
|
+
if (srcDir && existsSync12(srcDir)) {
|
|
5557
5647
|
const found = findInstalledSkillMd(srcDir);
|
|
5558
5648
|
if (found.length > 0) {
|
|
5559
5649
|
return check("pass", "skills_installed", "Skills installed", `${found.length} SKILL.md file(s) found (source)`);
|
|
@@ -5566,8 +5656,8 @@ function checkSkillsInstalled(home, cwd) {
|
|
|
5566
5656
|
return check("pass", "skills_installed", "Skills installed", `${found.length} SKILL.md file(s) found (plugin v${plugin.version})`);
|
|
5567
5657
|
}
|
|
5568
5658
|
}
|
|
5569
|
-
const skillsDir =
|
|
5570
|
-
if (
|
|
5659
|
+
const skillsDir = join23(home, ".claude", "skills");
|
|
5660
|
+
if (existsSync12(skillsDir)) {
|
|
5571
5661
|
const found = findInstalledSkillMd(skillsDir);
|
|
5572
5662
|
if (found.length > 0) {
|
|
5573
5663
|
return check("pass", "skills_installed", "Skills installed", `${found.length} SKILL.md file(s) found (CLI install)`);
|
|
@@ -5577,10 +5667,10 @@ function checkSkillsInstalled(home, cwd) {
|
|
|
5577
5667
|
}
|
|
5578
5668
|
function checkDuplicateSkills(home) {
|
|
5579
5669
|
const plugin = findPlugin(home);
|
|
5580
|
-
const skillsDir =
|
|
5670
|
+
const skillsDir = join23(home, ".claude", "skills");
|
|
5581
5671
|
const agentSkillDirs = [
|
|
5582
|
-
{ label: "~/.codex/skills/", path:
|
|
5583
|
-
{ label: "~/.agents/skills/", path:
|
|
5672
|
+
{ label: "~/.codex/skills/", path: join23(home, ".codex", "skills") },
|
|
5673
|
+
{ label: "~/.agents/skills/", path: join23(home, ".agents", "skills") }
|
|
5584
5674
|
];
|
|
5585
5675
|
if (!plugin) {
|
|
5586
5676
|
return check("pass", "skills_duplicate", "Skills not duplicated", "Single install channel");
|
|
@@ -5683,8 +5773,8 @@ async function checkProfiles(home) {
|
|
|
5683
5773
|
}
|
|
5684
5774
|
async function checkProjectLocalOverride(cwd) {
|
|
5685
5775
|
const dir = cwd ?? process.cwd();
|
|
5686
|
-
const envPath =
|
|
5687
|
-
if (
|
|
5776
|
+
const envPath = join23(dir, ".skillwiki", ".env");
|
|
5777
|
+
if (existsSync12(envPath)) {
|
|
5688
5778
|
return check("pass", "project_local", "Project-local config", `Found: ${envPath}`);
|
|
5689
5779
|
}
|
|
5690
5780
|
return check("pass", "project_local", "Project-local config", "None");
|
|
@@ -5693,7 +5783,7 @@ function checkVaultGitRemote(resolvedPath) {
|
|
|
5693
5783
|
if (resolvedPath === void 0) {
|
|
5694
5784
|
return check("error", "vault_git_remote", "Vault git remote", "Cannot check \u2014 WIKI_PATH not resolved");
|
|
5695
5785
|
}
|
|
5696
|
-
if (!
|
|
5786
|
+
if (!existsSync12(join23(resolvedPath, ".git"))) {
|
|
5697
5787
|
return check("warn", "vault_git_remote", "Vault git remote", "Vault is not a git repository \u2014 sync features unavailable");
|
|
5698
5788
|
}
|
|
5699
5789
|
try {
|
|
@@ -5716,9 +5806,9 @@ function checkObsidianTemplates(resolvedPath) {
|
|
|
5716
5806
|
return check("error", "obsidian_templates", "Obsidian templates", "Cannot check \u2014 WIKI_PATH not resolved");
|
|
5717
5807
|
}
|
|
5718
5808
|
const missing = [];
|
|
5719
|
-
if (!
|
|
5720
|
-
if (!
|
|
5721
|
-
if (!
|
|
5809
|
+
if (!existsSync12(join23(resolvedPath, "_Templates"))) missing.push("_Templates/");
|
|
5810
|
+
if (!existsSync12(join23(resolvedPath, ".obsidian", "templates.json"))) missing.push(".obsidian/templates.json");
|
|
5811
|
+
if (!existsSync12(join23(resolvedPath, ".obsidian", "app.json"))) missing.push(".obsidian/app.json");
|
|
5722
5812
|
if (missing.length === 0) {
|
|
5723
5813
|
return check("pass", "obsidian_templates", "Obsidian templates", "Template folder and config present");
|
|
5724
5814
|
}
|
|
@@ -5728,8 +5818,8 @@ function checkDotStoreClean(resolvedPath) {
|
|
|
5728
5818
|
if (resolvedPath === void 0) {
|
|
5729
5819
|
return check("error", "dsstore_clean", "No .DS_Store in raw/", "Cannot check \u2014 WIKI_PATH not resolved");
|
|
5730
5820
|
}
|
|
5731
|
-
const rawDir =
|
|
5732
|
-
if (!
|
|
5821
|
+
const rawDir = join23(resolvedPath, "raw");
|
|
5822
|
+
if (!existsSync12(rawDir)) {
|
|
5733
5823
|
return check("pass", "dsstore_clean", "No .DS_Store in raw/", "raw/ directory not found \u2014 check skipped");
|
|
5734
5824
|
}
|
|
5735
5825
|
const found = [];
|
|
@@ -5744,7 +5834,7 @@ function checkDotStoreClean(resolvedPath) {
|
|
|
5744
5834
|
if (entry.name === ".DS_Store") {
|
|
5745
5835
|
found.push(rel ? `${rel}/.DS_Store` : ".DS_Store");
|
|
5746
5836
|
} else if (entry.isDirectory()) {
|
|
5747
|
-
walk2(
|
|
5837
|
+
walk2(join23(dir, entry.name), rel ? `${rel}/${entry.name}` : entry.name);
|
|
5748
5838
|
}
|
|
5749
5839
|
}
|
|
5750
5840
|
})(rawDir, "");
|
|
@@ -5775,7 +5865,7 @@ function checkSyncLastPush(resolvedPath) {
|
|
|
5775
5865
|
if (resolvedPath === void 0) {
|
|
5776
5866
|
return check("error", "sync_last_push", "Vault sync recency", "Cannot check \u2014 WIKI_PATH not resolved");
|
|
5777
5867
|
}
|
|
5778
|
-
if (!
|
|
5868
|
+
if (!existsSync12(join23(resolvedPath, ".git"))) {
|
|
5779
5869
|
return check("pass", "sync_last_push", "Vault sync recency", "No git repo \u2014 sync check skipped");
|
|
5780
5870
|
}
|
|
5781
5871
|
let timestamp;
|
|
@@ -5823,7 +5913,7 @@ function checkVaultGitDirty(resolvedPath) {
|
|
|
5823
5913
|
if (resolvedPath === void 0) {
|
|
5824
5914
|
return check("pass", "vault_git_dirty", "Vault git dirty state", "No vault path \u2014 check skipped");
|
|
5825
5915
|
}
|
|
5826
|
-
if (!
|
|
5916
|
+
if (!existsSync12(join23(resolvedPath, ".git"))) {
|
|
5827
5917
|
return check("pass", "vault_git_dirty", "Vault git dirty state", "No git repo \u2014 check skipped");
|
|
5828
5918
|
}
|
|
5829
5919
|
try {
|
|
@@ -5891,7 +5981,7 @@ function remoteMainHash(resolvedPath) {
|
|
|
5891
5981
|
}
|
|
5892
5982
|
function checkStaleRemoteMain(resolvedPath) {
|
|
5893
5983
|
if (resolvedPath === void 0) return void 0;
|
|
5894
|
-
if (!
|
|
5984
|
+
if (!existsSync12(join23(resolvedPath, ".git"))) return void 0;
|
|
5895
5985
|
const localOrigin = gitRefHash(resolvedPath, "origin/main");
|
|
5896
5986
|
if (!localOrigin) return void 0;
|
|
5897
5987
|
const remoteMain = remoteMainHash(resolvedPath);
|
|
@@ -5907,7 +5997,7 @@ function checkVaultLocalGit(resolvedPath) {
|
|
|
5907
5997
|
if (resolvedPath === void 0) {
|
|
5908
5998
|
return check("warn", "vault_local_git", "Vault local git", "Cannot check \u2014 WIKI_PATH not resolved");
|
|
5909
5999
|
}
|
|
5910
|
-
if (!
|
|
6000
|
+
if (!existsSync12(join23(resolvedPath, ".git"))) {
|
|
5911
6001
|
return check("warn", "vault_local_git", "Vault local git", "Not a git repository - sync features unavailable");
|
|
5912
6002
|
}
|
|
5913
6003
|
try {
|
|
@@ -5926,7 +6016,7 @@ function checkVaultGithubRemote(resolvedPath, exec) {
|
|
|
5926
6016
|
if (resolvedPath === void 0) {
|
|
5927
6017
|
return check("pass", "vault_github_remote", "Vault GitHub remote", "No vault path \u2014 check skipped");
|
|
5928
6018
|
}
|
|
5929
|
-
if (!
|
|
6019
|
+
if (!existsSync12(join23(resolvedPath, ".git"))) {
|
|
5930
6020
|
return check("pass", "vault_github_remote", "Vault GitHub remote", "No git repo \u2014 check skipped");
|
|
5931
6021
|
}
|
|
5932
6022
|
const state = probeGithubReachability(resolvedPath, exec);
|
|
@@ -5970,7 +6060,7 @@ function checkVaultPromotionLag(resolvedPath) {
|
|
|
5970
6060
|
if (resolvedPath === void 0) {
|
|
5971
6061
|
return check("pass", "vault_promotion_lag", "Vault promotion lag", "No vault path \u2014 check skipped");
|
|
5972
6062
|
}
|
|
5973
|
-
if (!
|
|
6063
|
+
if (!existsSync12(join23(resolvedPath, ".git"))) {
|
|
5974
6064
|
return check("pass", "vault_promotion_lag", "Vault promotion lag", "No git repo \u2014 check skipped");
|
|
5975
6065
|
}
|
|
5976
6066
|
try {
|
|
@@ -5997,7 +6087,7 @@ function checkVaultGitComparison(resolvedPath, id, label, range, nonZeroSuffix,
|
|
|
5997
6087
|
if (resolvedPath === void 0) {
|
|
5998
6088
|
return check("pass", id, label, "No vault path \u2014 check skipped");
|
|
5999
6089
|
}
|
|
6000
|
-
if (!
|
|
6090
|
+
if (!existsSync12(join23(resolvedPath, ".git"))) {
|
|
6001
6091
|
return check("pass", id, label, "No git repo \u2014 check skipped");
|
|
6002
6092
|
}
|
|
6003
6093
|
if (!hasOriginMain(resolvedPath)) {
|
|
@@ -6025,7 +6115,7 @@ function checkSatelliteLastRun(vaultPath, satelliteExpected) {
|
|
|
6025
6115
|
return check("pass", "satellite_job_last_run", "Satellite job last run", "No vault path \u2014 check skipped");
|
|
6026
6116
|
}
|
|
6027
6117
|
const latestPath = satelliteLatestRunPath(vaultPath);
|
|
6028
|
-
if (!
|
|
6118
|
+
if (!existsSync12(latestPath)) {
|
|
6029
6119
|
return check("pass", "satellite_job_last_run", "Satellite job last run", "No latest-run.json \u2014 satellite has not run yet");
|
|
6030
6120
|
}
|
|
6031
6121
|
try {
|
|
@@ -6113,11 +6203,11 @@ async function checkFleetIdentity(input) {
|
|
|
6113
6203
|
}
|
|
6114
6204
|
function pullLogPaths(home) {
|
|
6115
6205
|
const paths = platform2() === "darwin" ? [
|
|
6116
|
-
|
|
6117
|
-
|
|
6206
|
+
join23(home, "Library", "Logs", "wiki-pull.log"),
|
|
6207
|
+
join23(home, ".local", "state", "vault-sync", "log", "wiki-pull.log")
|
|
6118
6208
|
] : [
|
|
6119
|
-
|
|
6120
|
-
|
|
6209
|
+
join23(home, ".local", "state", "vault-sync", "log", "wiki-pull.log"),
|
|
6210
|
+
join23(home, "Library", "Logs", "wiki-pull.log")
|
|
6121
6211
|
];
|
|
6122
6212
|
return [...new Set(paths)];
|
|
6123
6213
|
}
|
|
@@ -6129,12 +6219,12 @@ function isRecentLogLine(line, nowMs) {
|
|
|
6129
6219
|
return nowMs - ts <= 24 * 60 * 60 * 1e3;
|
|
6130
6220
|
}
|
|
6131
6221
|
function checkVaultGitPullFailures(home) {
|
|
6132
|
-
const path = pullLogPaths(home).find((p) =>
|
|
6222
|
+
const path = pullLogPaths(home).find((p) => existsSync12(p));
|
|
6133
6223
|
if (!path) {
|
|
6134
6224
|
return check("pass", "vault_git_pull_failures", "Vault pull failures", "No wiki-pull.log found \u2014 check skipped");
|
|
6135
6225
|
}
|
|
6136
6226
|
try {
|
|
6137
|
-
const lines =
|
|
6227
|
+
const lines = readFileSync9(path, "utf8").split(/\r?\n/).filter(Boolean);
|
|
6138
6228
|
const now = Date.now();
|
|
6139
6229
|
const failures = lines.filter(
|
|
6140
6230
|
(line) => isRecentLogLine(line, now) && /(pre-push pull failed|FAIL .*pull|FAIL .*rebase|cannot pull with rebase|unstaged changes)/i.test(line)
|
|
@@ -6157,8 +6247,8 @@ function checkS3MountPerf(resolvedPath) {
|
|
|
6157
6247
|
return check("pass", "s3_mount_perf", "S3 mount performance", "local disk");
|
|
6158
6248
|
}
|
|
6159
6249
|
const mountPoint = fuse.mountPoint;
|
|
6160
|
-
const conceptsDir =
|
|
6161
|
-
if (!
|
|
6250
|
+
const conceptsDir = join23(resolvedPath, "concepts");
|
|
6251
|
+
if (!existsSync12(conceptsDir)) {
|
|
6162
6252
|
return check("pass", "s3_mount_perf", "S3 mount performance", `S3 FUSE mount (${mountPoint}), no concepts/ to benchmark`);
|
|
6163
6253
|
}
|
|
6164
6254
|
const start = Date.now();
|
|
@@ -6340,8 +6430,8 @@ function checkWriteTest(resolvedPath) {
|
|
|
6340
6430
|
if (!fuse) {
|
|
6341
6431
|
return check("pass", "s3_write_test", "S3 write test", "local disk \u2014 check skipped");
|
|
6342
6432
|
}
|
|
6343
|
-
const conceptsDir =
|
|
6344
|
-
if (!
|
|
6433
|
+
const conceptsDir = join23(resolvedPath, "concepts");
|
|
6434
|
+
if (!existsSync12(conceptsDir)) {
|
|
6345
6435
|
return check("pass", "s3_write_test", "S3 write test", "no concepts/ dir to test \u2014 check skipped");
|
|
6346
6436
|
}
|
|
6347
6437
|
const result = writeTest(conceptsDir);
|
|
@@ -6427,7 +6517,7 @@ function checkVfsCacheHealth(resolvedPath) {
|
|
|
6427
6517
|
}
|
|
6428
6518
|
function readVaultSyncConfig(home) {
|
|
6429
6519
|
try {
|
|
6430
|
-
const content =
|
|
6520
|
+
const content = readFileSync9(join23(home, ".skillwiki", ".env"), "utf8");
|
|
6431
6521
|
let installed = false;
|
|
6432
6522
|
let role;
|
|
6433
6523
|
let serviceScope;
|
|
@@ -6456,7 +6546,7 @@ function readVaultSyncConfig(home) {
|
|
|
6456
6546
|
}
|
|
6457
6547
|
function readKeyFromEnvFile(path, keys) {
|
|
6458
6548
|
try {
|
|
6459
|
-
const content =
|
|
6549
|
+
const content = readFileSync9(path, "utf8");
|
|
6460
6550
|
for (const line of content.split(/\r?\n/)) {
|
|
6461
6551
|
const trimmed = line.trim();
|
|
6462
6552
|
if (trimmed.length === 0 || trimmed.startsWith("#")) continue;
|
|
@@ -6478,7 +6568,7 @@ function resolveSnapshotGitWorktree(config) {
|
|
|
6478
6568
|
if (fromProfile) return fromProfile;
|
|
6479
6569
|
}
|
|
6480
6570
|
const defaultPath = "/root/wiki-git";
|
|
6481
|
-
return
|
|
6571
|
+
return existsSync12(defaultPath) ? defaultPath : void 0;
|
|
6482
6572
|
}
|
|
6483
6573
|
function vaultSyncChecks(input) {
|
|
6484
6574
|
const os = input.os ?? platform2();
|
|
@@ -6495,16 +6585,16 @@ function vaultSyncChecks(input) {
|
|
|
6495
6585
|
];
|
|
6496
6586
|
}
|
|
6497
6587
|
const isMac = os === "darwin";
|
|
6498
|
-
const logDir = input.logDir ?? (isMac ?
|
|
6499
|
-
const shareDir = input.shareDir ?? (isMac ?
|
|
6500
|
-
const filterPath = input.filterPath ??
|
|
6501
|
-
const packagedSnapshotPath =
|
|
6588
|
+
const logDir = input.logDir ?? (isMac ? join23(home, "Library", "Logs") : join23(home, ".local", "state", "vault-sync", "log"));
|
|
6589
|
+
const shareDir = input.shareDir ?? (isMac ? join23(home, "Library", "Application Support", "vault-sync", "bin") : join23(home, ".local", "share", "vault-sync", "bin"));
|
|
6590
|
+
const filterPath = input.filterPath ?? join23(home, ".config", "rclone", "wiki-push-filters.txt");
|
|
6591
|
+
const packagedSnapshotPath = join23(shareDir, "wiki-snapshot.sh");
|
|
6502
6592
|
const legacySnapshotPath = "/root/.hermes/scripts/wiki-snapshot-v3.sh";
|
|
6503
|
-
const snapshotPath = input.snapshotScriptPath ?? (
|
|
6593
|
+
const snapshotPath = input.snapshotScriptPath ?? (existsSync12(packagedSnapshotPath) ? packagedSnapshotPath : legacySnapshotPath);
|
|
6504
6594
|
function snapshotLastStatusCheck() {
|
|
6505
|
-
const snapshotLog =
|
|
6595
|
+
const snapshotLog = join23(logDir, "wiki-snapshot.log");
|
|
6506
6596
|
try {
|
|
6507
|
-
const logContent =
|
|
6597
|
+
const logContent = readFileSync9(snapshotLog, "utf8");
|
|
6508
6598
|
const lines = logContent.trim().split("\n").filter(Boolean);
|
|
6509
6599
|
if (lines.length === 0) {
|
|
6510
6600
|
return check(
|
|
@@ -6549,14 +6639,14 @@ function vaultSyncChecks(input) {
|
|
|
6549
6639
|
}
|
|
6550
6640
|
}
|
|
6551
6641
|
if (input.vaultSyncRole === "snapshotter") {
|
|
6552
|
-
const c12 =
|
|
6642
|
+
const c12 = existsSync12(snapshotPath) ? check("pass", "vault_sync_installed", "Vault sync installed", `Found snapshot script: ${snapshotPath}`) : check("error", "vault_sync_installed", "Vault sync installed", `Snapshot script not found at ${snapshotPath}`);
|
|
6553
6643
|
const serviceScope = input.vaultSyncServiceScope ?? "user";
|
|
6554
|
-
const userTimerPath =
|
|
6644
|
+
const userTimerPath = join23(home, ".config", "systemd", "user", "wiki-snapshot.timer");
|
|
6555
6645
|
const systemTimerPath = "/etc/systemd/system/wiki-snapshot.timer";
|
|
6556
6646
|
let c22;
|
|
6557
|
-
if (serviceScope === "user" &&
|
|
6647
|
+
if (serviceScope === "user" && existsSync12(userTimerPath)) {
|
|
6558
6648
|
c22 = check("pass", "vault_sync_jobs_enabled", "Vault sync jobs enabled", `Found: ${userTimerPath}`);
|
|
6559
|
-
} else if (serviceScope === "system" &&
|
|
6649
|
+
} else if (serviceScope === "system" && existsSync12(systemTimerPath)) {
|
|
6560
6650
|
c22 = check("pass", "vault_sync_jobs_enabled", "Vault sync jobs enabled", `Found: ${systemTimerPath}`);
|
|
6561
6651
|
} else if (os !== "linux") {
|
|
6562
6652
|
c22 = check("warn", "vault_sync_jobs_enabled", "Vault sync jobs enabled", "Snapshotter scheduler is Linux-only and no wiki-snapshot.timer file was found");
|
|
@@ -6588,7 +6678,7 @@ function vaultSyncChecks(input) {
|
|
|
6588
6678
|
);
|
|
6589
6679
|
let c52;
|
|
6590
6680
|
try {
|
|
6591
|
-
if (!
|
|
6681
|
+
if (!existsSync12(snapshotPath)) {
|
|
6592
6682
|
c52 = check(
|
|
6593
6683
|
"error",
|
|
6594
6684
|
"vault_sync_snapshot_guard",
|
|
@@ -6596,7 +6686,7 @@ function vaultSyncChecks(input) {
|
|
|
6596
6686
|
`Snapshot script not found at ${snapshotPath}`
|
|
6597
6687
|
);
|
|
6598
6688
|
} else {
|
|
6599
|
-
const content =
|
|
6689
|
+
const content = readFileSync9(snapshotPath, "utf8");
|
|
6600
6690
|
if (!content.includes("--max-delete")) {
|
|
6601
6691
|
c52 = check(
|
|
6602
6692
|
"error",
|
|
@@ -6623,8 +6713,8 @@ function vaultSyncChecks(input) {
|
|
|
6623
6713
|
}
|
|
6624
6714
|
return [c12, c22, c32, cFetch2, c42, c52];
|
|
6625
6715
|
}
|
|
6626
|
-
const pushScriptPath =
|
|
6627
|
-
const c1 =
|
|
6716
|
+
const pushScriptPath = join23(shareDir, "wiki-push.sh");
|
|
6717
|
+
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`);
|
|
6628
6718
|
let c2;
|
|
6629
6719
|
try {
|
|
6630
6720
|
if (isMac) {
|
|
@@ -6675,10 +6765,10 @@ function vaultSyncChecks(input) {
|
|
|
6675
6765
|
"Scheduler check failed \u2014 run vault-sync-install"
|
|
6676
6766
|
);
|
|
6677
6767
|
}
|
|
6678
|
-
const logFile =
|
|
6768
|
+
const logFile = join23(logDir, "wiki-push.log");
|
|
6679
6769
|
let c3;
|
|
6680
6770
|
try {
|
|
6681
|
-
const logContent =
|
|
6771
|
+
const logContent = readFileSync9(logFile, "utf8");
|
|
6682
6772
|
const lines = logContent.trim().split("\n").filter(Boolean);
|
|
6683
6773
|
if (lines.length === 0) {
|
|
6684
6774
|
c3 = check(
|
|
@@ -6734,7 +6824,7 @@ function vaultSyncChecks(input) {
|
|
|
6734
6824
|
}
|
|
6735
6825
|
}
|
|
6736
6826
|
} catch {
|
|
6737
|
-
c3 =
|
|
6827
|
+
c3 = existsSync12(logDir) ? check(
|
|
6738
6828
|
"warn",
|
|
6739
6829
|
"vault_sync_last_push_age",
|
|
6740
6830
|
"Vault sync last push recency",
|
|
@@ -6746,10 +6836,10 @@ function vaultSyncChecks(input) {
|
|
|
6746
6836
|
`Log directory not found at ${logDir}`
|
|
6747
6837
|
);
|
|
6748
6838
|
}
|
|
6749
|
-
const fetchLogFile =
|
|
6839
|
+
const fetchLogFile = join23(logDir, "wiki-fetch.log");
|
|
6750
6840
|
let cFetch;
|
|
6751
6841
|
try {
|
|
6752
|
-
const logContent =
|
|
6842
|
+
const logContent = readFileSync9(fetchLogFile, "utf8");
|
|
6753
6843
|
const lines = logContent.trim().split("\n").filter(Boolean);
|
|
6754
6844
|
if (lines.length === 0) {
|
|
6755
6845
|
cFetch = check(
|
|
@@ -6793,7 +6883,7 @@ function vaultSyncChecks(input) {
|
|
|
6793
6883
|
}
|
|
6794
6884
|
let c4;
|
|
6795
6885
|
try {
|
|
6796
|
-
if (!
|
|
6886
|
+
if (!existsSync12(filterPath)) {
|
|
6797
6887
|
c4 = check(
|
|
6798
6888
|
"error",
|
|
6799
6889
|
"vault_sync_filter_present",
|
|
@@ -6801,7 +6891,7 @@ function vaultSyncChecks(input) {
|
|
|
6801
6891
|
`Filter file not found at ${filterPath}`
|
|
6802
6892
|
);
|
|
6803
6893
|
} else {
|
|
6804
|
-
const content =
|
|
6894
|
+
const content = readFileSync9(filterPath, "utf8");
|
|
6805
6895
|
const requiredExcludes = [
|
|
6806
6896
|
"remotely-save/data.json",
|
|
6807
6897
|
".skillwiki/sync.lock",
|
|
@@ -6844,7 +6934,7 @@ function vaultSyncChecks(input) {
|
|
|
6844
6934
|
);
|
|
6845
6935
|
} else {
|
|
6846
6936
|
try {
|
|
6847
|
-
if (!
|
|
6937
|
+
if (!existsSync12(snapshotPath)) {
|
|
6848
6938
|
c5 = check(
|
|
6849
6939
|
"error",
|
|
6850
6940
|
"vault_sync_snapshot_guard",
|
|
@@ -6852,7 +6942,7 @@ function vaultSyncChecks(input) {
|
|
|
6852
6942
|
`Snapshot script not found at ${snapshotPath}`
|
|
6853
6943
|
);
|
|
6854
6944
|
} else {
|
|
6855
|
-
const content =
|
|
6945
|
+
const content = readFileSync9(snapshotPath, "utf8");
|
|
6856
6946
|
if (!content.includes("--max-delete")) {
|
|
6857
6947
|
c5 = check(
|
|
6858
6948
|
"error",
|
|
@@ -6890,15 +6980,15 @@ function findSkillMd(dir) {
|
|
|
6890
6980
|
}
|
|
6891
6981
|
for (const entry of entries) {
|
|
6892
6982
|
if (entry.isFile() && entry.name === "SKILL.md") {
|
|
6893
|
-
results.push(
|
|
6983
|
+
results.push(join23(dir, entry.name));
|
|
6894
6984
|
} else if (entry.isDirectory()) {
|
|
6895
|
-
results.push(...findSkillMd(
|
|
6985
|
+
results.push(...findSkillMd(join23(dir, entry.name)));
|
|
6896
6986
|
}
|
|
6897
6987
|
}
|
|
6898
6988
|
return results;
|
|
6899
6989
|
}
|
|
6900
6990
|
function findInstalledSkillMd(dir) {
|
|
6901
|
-
const directSkills = findSkillNames(dir).map((name) =>
|
|
6991
|
+
const directSkills = findSkillNames(dir).map((name) => join23(dir, name, "SKILL.md"));
|
|
6902
6992
|
return directSkills.length > 0 ? directSkills : findSkillMd(dir);
|
|
6903
6993
|
}
|
|
6904
6994
|
function findSkillNames(dir) {
|
|
@@ -6910,7 +7000,7 @@ function findSkillNames(dir) {
|
|
|
6910
7000
|
return results;
|
|
6911
7001
|
}
|
|
6912
7002
|
for (const entry of entries) {
|
|
6913
|
-
if (entry.isDirectory() &&
|
|
7003
|
+
if (entry.isDirectory() && existsSync12(join23(dir, entry.name, "SKILL.md"))) {
|
|
6914
7004
|
results.push(entry.name);
|
|
6915
7005
|
}
|
|
6916
7006
|
}
|
|
@@ -6954,7 +7044,7 @@ async function vaultMetrics(resolvedPath) {
|
|
|
6954
7044
|
}
|
|
6955
7045
|
let logLines = 0;
|
|
6956
7046
|
try {
|
|
6957
|
-
logLines =
|
|
7047
|
+
logLines = readFileSync9(join23(resolvedPath, "log.md"), "utf8").split("\n").length;
|
|
6958
7048
|
} catch {
|
|
6959
7049
|
}
|
|
6960
7050
|
return [
|
|
@@ -7062,7 +7152,7 @@ async function runDoctor(input) {
|
|
|
7062
7152
|
}
|
|
7063
7153
|
|
|
7064
7154
|
// src/utils/package-info.ts
|
|
7065
|
-
import { readFileSync as
|
|
7155
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
7066
7156
|
function packageJsonCandidateUrls(baseUrl = import.meta.url) {
|
|
7067
7157
|
return [
|
|
7068
7158
|
new URL("../package.json", baseUrl),
|
|
@@ -7072,7 +7162,7 @@ function packageJsonCandidateUrls(baseUrl = import.meta.url) {
|
|
|
7072
7162
|
function readCliPackageJson(baseUrl = import.meta.url) {
|
|
7073
7163
|
for (const url of packageJsonCandidateUrls(baseUrl)) {
|
|
7074
7164
|
try {
|
|
7075
|
-
const pkg = JSON.parse(
|
|
7165
|
+
const pkg = JSON.parse(readFileSync10(url, "utf8"));
|
|
7076
7166
|
if (typeof pkg.version === "string") {
|
|
7077
7167
|
return { ...pkg, version: pkg.version };
|
|
7078
7168
|
}
|
|
@@ -7084,7 +7174,7 @@ function readCliPackageJson(baseUrl = import.meta.url) {
|
|
|
7084
7174
|
|
|
7085
7175
|
// src/commands/project-index.ts
|
|
7086
7176
|
import { readdir as readdir4, readFile as readFile16, writeFile as writeFile6, mkdir as mkdir5 } from "fs/promises";
|
|
7087
|
-
import { join as
|
|
7177
|
+
import { join as join24, dirname as dirname7, basename as basename2 } from "path";
|
|
7088
7178
|
var LAYER2_DIRS = ["entities", "concepts", "comparisons", "queries", "meta"];
|
|
7089
7179
|
var PROJECT_LOCAL_DIRS = ["requirements", "work", "architecture", "history"];
|
|
7090
7180
|
async function scanMarkdownTree(rootAbs, rootRel) {
|
|
@@ -7096,7 +7186,7 @@ async function scanMarkdownTree(rootAbs, rootRel) {
|
|
|
7096
7186
|
return found;
|
|
7097
7187
|
}
|
|
7098
7188
|
for (const entry of entries) {
|
|
7099
|
-
const abs =
|
|
7189
|
+
const abs = join24(rootAbs, entry.name);
|
|
7100
7190
|
const rel = `${rootRel}/${entry.name}`;
|
|
7101
7191
|
if (entry.isDirectory()) {
|
|
7102
7192
|
found.push(...await scanMarkdownTree(abs, rel));
|
|
@@ -7126,7 +7216,7 @@ function projectLocalType(slug, page, data) {
|
|
|
7126
7216
|
}
|
|
7127
7217
|
async function runProjectIndex(input) {
|
|
7128
7218
|
const slug = input.slug;
|
|
7129
|
-
const projectDir =
|
|
7219
|
+
const projectDir = join24(input.vault, "projects", slug);
|
|
7130
7220
|
try {
|
|
7131
7221
|
await readdir4(projectDir);
|
|
7132
7222
|
} catch {
|
|
@@ -7137,12 +7227,12 @@ async function runProjectIndex(input) {
|
|
|
7137
7227
|
}
|
|
7138
7228
|
const wikilinkPattern = `[[${slug}]]`;
|
|
7139
7229
|
const entries = [];
|
|
7140
|
-
const compoundDir =
|
|
7230
|
+
const compoundDir = join24(input.vault, "projects", slug, "compound");
|
|
7141
7231
|
try {
|
|
7142
7232
|
const compoundFiles = await readdir4(compoundDir, { withFileTypes: true });
|
|
7143
7233
|
for (const entry of compoundFiles) {
|
|
7144
7234
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
7145
|
-
const filePath =
|
|
7235
|
+
const filePath = join24(compoundDir, entry.name);
|
|
7146
7236
|
let text;
|
|
7147
7237
|
try {
|
|
7148
7238
|
text = await readFile16(filePath, "utf8");
|
|
@@ -7162,13 +7252,13 @@ async function runProjectIndex(input) {
|
|
|
7162
7252
|
for (const dir of LAYER2_DIRS) {
|
|
7163
7253
|
let files;
|
|
7164
7254
|
try {
|
|
7165
|
-
files = await readdir4(
|
|
7255
|
+
files = await readdir4(join24(input.vault, dir), { withFileTypes: true });
|
|
7166
7256
|
} catch {
|
|
7167
7257
|
continue;
|
|
7168
7258
|
}
|
|
7169
7259
|
for (const entry of files) {
|
|
7170
7260
|
if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
|
|
7171
|
-
const filePath =
|
|
7261
|
+
const filePath = join24(input.vault, dir, entry.name);
|
|
7172
7262
|
let text;
|
|
7173
7263
|
try {
|
|
7174
7264
|
text = await readFile16(filePath, "utf8");
|
|
@@ -7187,11 +7277,11 @@ async function runProjectIndex(input) {
|
|
|
7187
7277
|
}
|
|
7188
7278
|
}
|
|
7189
7279
|
for (const dir of PROJECT_LOCAL_DIRS) {
|
|
7190
|
-
const rootAbs =
|
|
7280
|
+
const rootAbs = join24(projectDir, dir);
|
|
7191
7281
|
const rootRel = `projects/${slug}/${dir}`;
|
|
7192
7282
|
const pages = await scanMarkdownTree(rootAbs, rootRel);
|
|
7193
7283
|
for (const page of pages) {
|
|
7194
|
-
const filePath =
|
|
7284
|
+
const filePath = join24(input.vault, page);
|
|
7195
7285
|
let text;
|
|
7196
7286
|
try {
|
|
7197
7287
|
text = await readFile16(filePath, "utf8");
|
|
@@ -7213,7 +7303,7 @@ async function runProjectIndex(input) {
|
|
|
7213
7303
|
const tb = typeOrder[b.type] ?? 99;
|
|
7214
7304
|
return ta !== tb ? ta - tb : a.title.localeCompare(b.title);
|
|
7215
7305
|
});
|
|
7216
|
-
const indexPath =
|
|
7306
|
+
const indexPath = join24(projectDir, "knowledge.md");
|
|
7217
7307
|
let existing = false;
|
|
7218
7308
|
let stale = false;
|
|
7219
7309
|
try {
|
|
@@ -7257,7 +7347,7 @@ Autogenerated by \`skillwiki project-index\` on ${today}.
|
|
|
7257
7347
|
}
|
|
7258
7348
|
if (input.apply) {
|
|
7259
7349
|
try {
|
|
7260
|
-
await mkdir5(
|
|
7350
|
+
await mkdir5(dirname7(indexPath), { recursive: true });
|
|
7261
7351
|
await writeFile6(indexPath, body, "utf8");
|
|
7262
7352
|
} catch (e) {
|
|
7263
7353
|
return {
|
|
@@ -7287,8 +7377,8 @@ ${entries.map((e) => ` ${e.type}: [[${e.page.replace(/\.md$/, "")}]] \u2014 ${e
|
|
|
7287
7377
|
|
|
7288
7378
|
// src/commands/observe.ts
|
|
7289
7379
|
import { mkdir as mkdir6, writeFile as writeFile7 } from "fs/promises";
|
|
7290
|
-
import { existsSync as
|
|
7291
|
-
import { join as
|
|
7380
|
+
import { existsSync as existsSync13, statSync as statSync2 } from "fs";
|
|
7381
|
+
import { join as join25 } from "path";
|
|
7292
7382
|
import { createHash as createHash5 } from "crypto";
|
|
7293
7383
|
var ALLOWED_KINDS = /* @__PURE__ */ new Set(["note", "bug", "task", "idea", "session-log"]);
|
|
7294
7384
|
function slugify(text) {
|
|
@@ -7311,13 +7401,13 @@ async function runObserve(input) {
|
|
|
7311
7401
|
result: err("SCHEME_REJECTED", { message: "Text must not be empty" })
|
|
7312
7402
|
};
|
|
7313
7403
|
}
|
|
7314
|
-
if (!
|
|
7404
|
+
if (!existsSync13(input.vault) || !statSync2(input.vault).isDirectory()) {
|
|
7315
7405
|
return {
|
|
7316
7406
|
exitCode: ExitCode.VAULT_PATH_INVALID,
|
|
7317
7407
|
result: err("VAULT_PATH_INVALID", { path: input.vault })
|
|
7318
7408
|
};
|
|
7319
7409
|
}
|
|
7320
|
-
const transcriptsDir =
|
|
7410
|
+
const transcriptsDir = join25(input.vault, "raw", "transcripts");
|
|
7321
7411
|
try {
|
|
7322
7412
|
await mkdir6(transcriptsDir, { recursive: true });
|
|
7323
7413
|
} catch {
|
|
@@ -7329,7 +7419,7 @@ async function runObserve(input) {
|
|
|
7329
7419
|
const today = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
7330
7420
|
const slug = slugify(input.text);
|
|
7331
7421
|
const fileName = `${today}-observation-${slug}.md`;
|
|
7332
|
-
const filePath =
|
|
7422
|
+
const filePath = join25(transcriptsDir, fileName);
|
|
7333
7423
|
const body = `
|
|
7334
7424
|
${input.text.trim()}
|
|
7335
7425
|
`;
|
|
@@ -7371,7 +7461,7 @@ ${input.text.trim()}
|
|
|
7371
7461
|
// src/commands/memory.ts
|
|
7372
7462
|
import { createHash as createHash6 } from "crypto";
|
|
7373
7463
|
import { mkdir as mkdir7, readFile as readFile17, readdir as readdir5, stat as stat5, writeFile as writeFile8 } from "fs/promises";
|
|
7374
|
-
import { basename as basename3, extname, join as
|
|
7464
|
+
import { basename as basename3, extname, join as join26, relative as relative4, sep as sep4 } from "path";
|
|
7375
7465
|
async function runMemoryTopics(input) {
|
|
7376
7466
|
const scan = await scanVault(input.vault);
|
|
7377
7467
|
if (!scan.ok) return { exitCode: ExitCode.VAULT_PATH_INVALID, result: scan };
|
|
@@ -7435,8 +7525,8 @@ async function runMemoryIndex(input) {
|
|
|
7435
7525
|
}
|
|
7436
7526
|
const generatedAt = (/* @__PURE__ */ new Date()).toISOString().replace(/\.\d{3}Z$/, "Z");
|
|
7437
7527
|
const relCachePath = memoryCacheRelPath(input.project);
|
|
7438
|
-
const absCachePath =
|
|
7439
|
-
await mkdir7(
|
|
7528
|
+
const absCachePath = join26(input.vault, relCachePath);
|
|
7529
|
+
await mkdir7(join26(input.vault, ".skillwiki", "memory", input.project), { recursive: true });
|
|
7440
7530
|
await writeFile8(absCachePath, `${JSON.stringify({
|
|
7441
7531
|
generated_at: generatedAt,
|
|
7442
7532
|
project: input.project,
|
|
@@ -7628,7 +7718,7 @@ async function buildMemoryIndexState(pages, project) {
|
|
|
7628
7718
|
}
|
|
7629
7719
|
async function checkMemoryIndex(vault, project, current) {
|
|
7630
7720
|
const relCachePath = memoryCacheRelPath(project);
|
|
7631
|
-
const cacheText = await readIfExists2(
|
|
7721
|
+
const cacheText = await readIfExists2(join26(vault, relCachePath));
|
|
7632
7722
|
if (!cacheText) {
|
|
7633
7723
|
return {
|
|
7634
7724
|
ok: true,
|
|
@@ -8037,7 +8127,7 @@ async function walkImportFiles(dir, out) {
|
|
|
8037
8127
|
const entries = await readdir5(dir, { withFileTypes: true });
|
|
8038
8128
|
for (const entry of entries) {
|
|
8039
8129
|
if (entry.name === ".git" || entry.name === "node_modules") continue;
|
|
8040
|
-
const path =
|
|
8130
|
+
const path = join26(dir, entry.name);
|
|
8041
8131
|
if (entry.isDirectory()) {
|
|
8042
8132
|
await walkImportFiles(path, out);
|
|
8043
8133
|
} else if (entry.isFile() && isImportCandidate(path)) {
|
|
@@ -8104,8 +8194,8 @@ async function writeImportCapture(vault, entry, today) {
|
|
|
8104
8194
|
const content = hiddenString(entry, "__content");
|
|
8105
8195
|
const project = hiddenString(entry, "__project");
|
|
8106
8196
|
const relPath = await availableImportPath(vault, entry.proposed_path);
|
|
8107
|
-
const absPath =
|
|
8108
|
-
await mkdir7(
|
|
8197
|
+
const absPath = join26(vault, relPath);
|
|
8198
|
+
await mkdir7(join26(vault, "raw", "transcripts"), { recursive: true });
|
|
8109
8199
|
await writeFile8(absPath, renderImportCapture(entry, content, project, today), "utf8");
|
|
8110
8200
|
const validation = await runValidate({ file: absPath });
|
|
8111
8201
|
return {
|
|
@@ -8121,7 +8211,7 @@ async function availableImportPath(vault, proposed) {
|
|
|
8121
8211
|
const stem = proposed.slice(0, -ext.length);
|
|
8122
8212
|
let candidate = proposed;
|
|
8123
8213
|
let i = 2;
|
|
8124
|
-
while (await readIfExists2(
|
|
8214
|
+
while (await readIfExists2(join26(vault, candidate))) {
|
|
8125
8215
|
candidate = `${stem}-${i}${ext}`;
|
|
8126
8216
|
i++;
|
|
8127
8217
|
}
|
|
@@ -8293,10 +8383,10 @@ function memoryCacheRelPath(project) {
|
|
|
8293
8383
|
}
|
|
8294
8384
|
async function readMemoryCache(vault, project) {
|
|
8295
8385
|
if (project) {
|
|
8296
|
-
const projectCache = await readIfExists2(
|
|
8386
|
+
const projectCache = await readIfExists2(join26(vault, memoryCacheRelPath(project)));
|
|
8297
8387
|
if (projectCache) return projectCache;
|
|
8298
8388
|
}
|
|
8299
|
-
return readIfExists2(
|
|
8389
|
+
return readIfExists2(join26(vault, ".skillwiki", "memory-topics.json"));
|
|
8300
8390
|
}
|
|
8301
8391
|
function dedupePages(pages) {
|
|
8302
8392
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -8383,7 +8473,7 @@ function slugify2(value) {
|
|
|
8383
8473
|
|
|
8384
8474
|
// src/commands/query.ts
|
|
8385
8475
|
import { readFile as readFile18, stat as stat6 } from "fs/promises";
|
|
8386
|
-
import { join as
|
|
8476
|
+
import { join as join27 } from "path";
|
|
8387
8477
|
var W_KEYWORD = 2;
|
|
8388
8478
|
var W_SOURCE_OVERLAP = 4;
|
|
8389
8479
|
var W_WIKILINK = 3;
|
|
@@ -8504,7 +8594,7 @@ function computeKeywordScore(terms, title, tags, body) {
|
|
|
8504
8594
|
return score;
|
|
8505
8595
|
}
|
|
8506
8596
|
async function loadOrBuildGraph(vault) {
|
|
8507
|
-
const graphPath =
|
|
8597
|
+
const graphPath = join27(vault, ".skillwiki", "graph.json");
|
|
8508
8598
|
let needsBuild = false;
|
|
8509
8599
|
try {
|
|
8510
8600
|
const fileStat = await stat6(graphPath);
|
|
@@ -8533,7 +8623,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
8533
8623
|
import { z as z2 } from "zod";
|
|
8534
8624
|
|
|
8535
8625
|
// src/mcp/vault-resolve.ts
|
|
8536
|
-
import { join as
|
|
8626
|
+
import { join as join28, resolve as resolve7 } from "path";
|
|
8537
8627
|
|
|
8538
8628
|
// src/mcp/allowlist.ts
|
|
8539
8629
|
import { resolve as resolve6, sep as sep5 } from "path";
|
|
@@ -8595,7 +8685,7 @@ async function resolveMcpVault(input) {
|
|
|
8595
8685
|
return ok({ vault: vaultPath, source });
|
|
8596
8686
|
}
|
|
8597
8687
|
function defaultGraphOut(vault) {
|
|
8598
|
-
return
|
|
8688
|
+
return join28(vault, ".skillwiki", "graph.json");
|
|
8599
8689
|
}
|
|
8600
8690
|
|
|
8601
8691
|
// src/mcp/result-format.ts
|
|
@@ -8610,9 +8700,9 @@ function formatToolResult(payload) {
|
|
|
8610
8700
|
}
|
|
8611
8701
|
|
|
8612
8702
|
// src/mcp/audit-log.ts
|
|
8613
|
-
import { appendFileSync, mkdirSync as
|
|
8703
|
+
import { appendFileSync, mkdirSync as mkdirSync3 } from "fs";
|
|
8614
8704
|
import { homedir } from "os";
|
|
8615
|
-
import { join as
|
|
8705
|
+
import { join as join29 } from "path";
|
|
8616
8706
|
function auditEnabled() {
|
|
8617
8707
|
const v = process.env.SKILLWIKI_MCP_AUDIT;
|
|
8618
8708
|
if (v === "0" || v === "false") return false;
|
|
@@ -8624,7 +8714,7 @@ function auditSink() {
|
|
|
8624
8714
|
function auditFilePath() {
|
|
8625
8715
|
const custom = process.env.SKILLWIKI_MCP_AUDIT_FILE;
|
|
8626
8716
|
if (custom && custom.length > 0) return custom;
|
|
8627
|
-
return
|
|
8717
|
+
return join29(homedir(), ".skillwiki", "mcp-audit.jsonl");
|
|
8628
8718
|
}
|
|
8629
8719
|
function auditMcpToolCall(entry) {
|
|
8630
8720
|
if (!auditEnabled()) return;
|
|
@@ -8634,7 +8724,7 @@ function auditMcpToolCall(entry) {
|
|
|
8634
8724
|
return;
|
|
8635
8725
|
}
|
|
8636
8726
|
const path = auditFilePath();
|
|
8637
|
-
|
|
8727
|
+
mkdirSync3(join29(path, ".."), { recursive: true });
|
|
8638
8728
|
appendFileSync(path, line, "utf8");
|
|
8639
8729
|
}
|
|
8640
8730
|
async function runMcpToolHandler(tool, input, fn) {
|
|
@@ -8855,7 +8945,7 @@ function registerMcpMutatingTools(server) {
|
|
|
8855
8945
|
|
|
8856
8946
|
// src/mcp/resources.ts
|
|
8857
8947
|
import { readFile as readFile20 } from "fs/promises";
|
|
8858
|
-
import { join as
|
|
8948
|
+
import { join as join31 } from "path";
|
|
8859
8949
|
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
8860
8950
|
|
|
8861
8951
|
// src/mcp/lint-bucket.ts
|
|
@@ -8984,8 +9074,8 @@ async function fetchQueryPreview(input) {
|
|
|
8984
9074
|
|
|
8985
9075
|
// src/mcp/graph-html.ts
|
|
8986
9076
|
import { readFile as readFile19 } from "fs/promises";
|
|
8987
|
-
import { join as
|
|
8988
|
-
import { existsSync as
|
|
9077
|
+
import { join as join30 } from "path";
|
|
9078
|
+
import { existsSync as existsSync14 } from "fs";
|
|
8989
9079
|
var TYPE_COLORS = {
|
|
8990
9080
|
entities: "#e74c3c",
|
|
8991
9081
|
concepts: "#27ae60",
|
|
@@ -9053,9 +9143,9 @@ ${nodeSvg}
|
|
|
9053
9143
|
return { html, node_count: nodes.length, edge_count: edges.length, truncated };
|
|
9054
9144
|
}
|
|
9055
9145
|
async function fetchGraphHtmlReport(input) {
|
|
9056
|
-
const graphPath = input.graphPath ??
|
|
9146
|
+
const graphPath = input.graphPath ?? join30(input.vault, ".skillwiki", "graph.json");
|
|
9057
9147
|
const maxNodes = Math.min(Math.max(10, input.maxNodes ?? 120), 500);
|
|
9058
|
-
if (!
|
|
9148
|
+
if (!existsSync14(graphPath)) {
|
|
9059
9149
|
return {
|
|
9060
9150
|
exitCode: ExitCode.FILE_NOT_FOUND,
|
|
9061
9151
|
result: err("GRAPH_MISSING", { path: graphPath, hint: "Run skillwiki.graph_build first." })
|
|
@@ -9127,7 +9217,7 @@ async function fetchStaleSummary(input) {
|
|
|
9127
9217
|
|
|
9128
9218
|
// src/mcp/resources.ts
|
|
9129
9219
|
async function readVaultFile(vault, rel) {
|
|
9130
|
-
return readFile20(
|
|
9220
|
+
return readFile20(join31(vault, rel), "utf8");
|
|
9131
9221
|
}
|
|
9132
9222
|
async function tailLines(text, lines) {
|
|
9133
9223
|
const parts = text.split(/\r?\n/);
|
|
@@ -9213,7 +9303,7 @@ function registerMcpResources(server) {
|
|
|
9213
9303
|
if (!v.ok) {
|
|
9214
9304
|
return { contents: [{ uri: uri.href, mimeType: "text/plain", text: JSON.stringify(v) }] };
|
|
9215
9305
|
}
|
|
9216
|
-
const path =
|
|
9306
|
+
const path = join31(v.data.vault, ".skillwiki", "graph.json");
|
|
9217
9307
|
try {
|
|
9218
9308
|
const raw = await readFile20(path, "utf8");
|
|
9219
9309
|
const graph = JSON.parse(raw);
|
|
@@ -9571,13 +9661,12 @@ export {
|
|
|
9571
9661
|
fixPathTooLong,
|
|
9572
9662
|
assessSourceIdentity,
|
|
9573
9663
|
runLint,
|
|
9664
|
+
runSyncLintDelta,
|
|
9574
9665
|
configPath,
|
|
9575
9666
|
runConfigGet,
|
|
9576
9667
|
runConfigSet,
|
|
9577
9668
|
runConfigList,
|
|
9578
9669
|
runConfigPath,
|
|
9579
|
-
writeCache,
|
|
9580
|
-
triggerAutoUpdate,
|
|
9581
9670
|
buildDegradedReasons,
|
|
9582
9671
|
probeRemoteHealth,
|
|
9583
9672
|
FLEET_REL_PATH,
|