skillwiki 0.10.107 → 0.10.109
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-PGD3J2GE.js → chunk-FYAKMULW.js} +44 -33
- package/dist/{chunk-Z4NCF6K6.js → chunk-LDEZQXH6.js} +59 -81
- package/dist/cli.js +81 -92
- package/dist/{managed-write-preflight-AYD3CJYD.js → managed-write-preflight-MAIGWFQJ.js} +1 -1
- package/dist/skillwiki-mcp.js +2 -2
- package/dist/vault-sync/scripts/wiki-snapshot.sh +20 -12
- package/package.json +1 -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/skillwiki-connect/SKILL.md +8 -0
- package/skills/skills/skillwiki-mcp/SKILL.md +8 -0
- package/skills/skillwiki-connect/SKILL.md +8 -0
- package/skills/skillwiki-mcp/SKILL.md +8 -0
|
@@ -43,9 +43,25 @@ import {
|
|
|
43
43
|
vaultIoConcurrency
|
|
44
44
|
} from "./chunk-GJC2CI3W.js";
|
|
45
45
|
|
|
46
|
+
// src/utils/home.ts
|
|
47
|
+
import { homedir } from "os";
|
|
48
|
+
import { resolve } from "path";
|
|
49
|
+
function resolveSkillwikiHome(home, env = process.env) {
|
|
50
|
+
for (const candidate of [home, env.HOME, env.USERPROFILE]) {
|
|
51
|
+
if (candidate?.trim()) return resolve(candidate);
|
|
52
|
+
}
|
|
53
|
+
try {
|
|
54
|
+
const fallback = homedir();
|
|
55
|
+
if (fallback?.trim()) return resolve(fallback);
|
|
56
|
+
} catch {
|
|
57
|
+
throw new Error("Could not resolve SkillWiki home directory");
|
|
58
|
+
}
|
|
59
|
+
throw new Error("Could not resolve SkillWiki home directory");
|
|
60
|
+
}
|
|
61
|
+
|
|
46
62
|
// src/utils/managed-write-preflight.ts
|
|
47
63
|
import { existsSync as existsSync11 } from "fs";
|
|
48
|
-
import { join as join21, resolve as
|
|
64
|
+
import { join as join21, resolve as resolve7 } from "path";
|
|
49
65
|
|
|
50
66
|
// src/commands/fleet.ts
|
|
51
67
|
import { readFile as readFile2 } from "fs/promises";
|
|
@@ -175,7 +191,7 @@ async function runFleetValidate(input) {
|
|
|
175
191
|
}
|
|
176
192
|
async function runFleetContext(input) {
|
|
177
193
|
const env = input.env ?? process.env;
|
|
178
|
-
const home = input.home
|
|
194
|
+
const home = resolveSkillwikiHome(input.home, env);
|
|
179
195
|
const cwd = input.cwd ?? process.cwd();
|
|
180
196
|
const osHostname = input.osHostname ?? safeEnvValue(env.HOSTNAME) ?? nodeHostname();
|
|
181
197
|
const user = input.user ?? safeEnvValue(env.USER) ?? safeUserName();
|
|
@@ -297,7 +313,7 @@ async function runFleetContext(input) {
|
|
|
297
313
|
}
|
|
298
314
|
function fleetContextEnv(input) {
|
|
299
315
|
const env = input.env ?? process.env;
|
|
300
|
-
const home = input.home
|
|
316
|
+
const home = resolveSkillwikiHome(input.home, env);
|
|
301
317
|
const osHostname = input.osHostname ?? safeEnvValue(env.HOSTNAME) ?? nodeHostname();
|
|
302
318
|
const vault = input.vault ?? safeEnvValue(env.WIKI_PATH);
|
|
303
319
|
const file = input.file ?? (vault ? join(vault, FLEET_REL_PATH) : void 0);
|
|
@@ -2414,7 +2430,7 @@ async function runTopicMapCheck(input) {
|
|
|
2414
2430
|
// src/commands/dedup.ts
|
|
2415
2431
|
import { createHash as createHash3 } from "crypto";
|
|
2416
2432
|
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
2417
|
-
import { dirname as dirname3, join as join10, posix, resolve } from "path";
|
|
2433
|
+
import { dirname as dirname3, join as join10, posix, resolve as resolve2 } from "path";
|
|
2418
2434
|
|
|
2419
2435
|
// src/utils/rclone.ts
|
|
2420
2436
|
import { execFile } from "child_process";
|
|
@@ -2649,7 +2665,7 @@ async function runDedup(input) {
|
|
|
2649
2665
|
const manifest = safeEntries.length > 0 ? {
|
|
2650
2666
|
version: 1,
|
|
2651
2667
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2652
|
-
vault:
|
|
2668
|
+
vault: resolve2(input.vault),
|
|
2653
2669
|
entries: safeEntries
|
|
2654
2670
|
} : void 0;
|
|
2655
2671
|
const remoteDeleteCount = safeEntries.reduce((count, entry) => count + entry.duplicates.length, 0);
|
|
@@ -2843,11 +2859,11 @@ function readManifest(path) {
|
|
|
2843
2859
|
}
|
|
2844
2860
|
}
|
|
2845
2861
|
function validateManifestLocalState(vault, manifest) {
|
|
2846
|
-
if (
|
|
2862
|
+
if (resolve2(manifest.vault) !== resolve2(vault)) {
|
|
2847
2863
|
return err("APPROVAL_INVALID", {
|
|
2848
2864
|
message: "dedup manifest belongs to a different vault",
|
|
2849
2865
|
manifest_vault: manifest.vault,
|
|
2850
|
-
vault:
|
|
2866
|
+
vault: resolve2(vault)
|
|
2851
2867
|
});
|
|
2852
2868
|
}
|
|
2853
2869
|
for (const entry of manifest.entries) {
|
|
@@ -2929,7 +2945,7 @@ async function runRawBodyDedup(vault, scan, pageTextCache) {
|
|
|
2929
2945
|
|
|
2930
2946
|
// src/commands/audit.ts
|
|
2931
2947
|
import { readFile as readFile11, stat as stat2 } from "fs/promises";
|
|
2932
|
-
import { dirname as dirname4, resolve as
|
|
2948
|
+
import { dirname as dirname4, resolve as resolve3, join as join11 } from "path";
|
|
2933
2949
|
async function runAudit(input) {
|
|
2934
2950
|
let text;
|
|
2935
2951
|
try {
|
|
@@ -2941,7 +2957,7 @@ async function runAudit(input) {
|
|
|
2941
2957
|
if (!fm.ok) return { exitCode: ExitCode.INVALID_FRONTMATTER, result: fm };
|
|
2942
2958
|
const split = splitFrontmatter(text);
|
|
2943
2959
|
const body = split.ok ? split.data.body : text;
|
|
2944
|
-
const vault = await findVaultRoot(dirname4(
|
|
2960
|
+
const vault = await findVaultRoot(dirname4(resolve3(input.file)));
|
|
2945
2961
|
if (!vault) return { exitCode: ExitCode.VAULT_PATH_INVALID, result: err("VAULT_PATH_INVALID") };
|
|
2946
2962
|
const markers = extractCitationMarkers(body);
|
|
2947
2963
|
const resolved = await Promise.all(markers.map(async (m) => {
|
|
@@ -3043,7 +3059,7 @@ async function validateCompoundReferences(vault, existingScan, pageTextCache) {
|
|
|
3043
3059
|
// src/commands/path-too-long.ts
|
|
3044
3060
|
import { existsSync as existsSync3 } from "fs";
|
|
3045
3061
|
import { mkdir as mkdir4, readFile as readFile12, rename as rename3, unlink as unlink2 } from "fs/promises";
|
|
3046
|
-
import { dirname as dirname5, join as join12, posix as posix2, resolve as
|
|
3062
|
+
import { dirname as dirname5, join as join12, posix as posix2, resolve as resolve4 } from "path";
|
|
3047
3063
|
var MAX_PATH_LENGTH = 240;
|
|
3048
3064
|
var WINDOWS_ABSOLUTE_PATH_LIMIT = 259;
|
|
3049
3065
|
async function runPathTooLong(input) {
|
|
@@ -3136,7 +3152,7 @@ function findPathTooLongViolations(pages, maxLength) {
|
|
|
3136
3152
|
}
|
|
3137
3153
|
function maxFixPathLength(vault) {
|
|
3138
3154
|
if (process.platform !== "win32") return MAX_PATH_LENGTH;
|
|
3139
|
-
const root =
|
|
3155
|
+
const root = resolve4(vault);
|
|
3140
3156
|
const separatorBudget = root.endsWith("\\") || root.endsWith("/") ? 0 : 1;
|
|
3141
3157
|
const absoluteSafeRelLength = WINDOWS_ABSOLUTE_PATH_LIMIT - root.length - separatorBudget;
|
|
3142
3158
|
return Math.max(1, Math.min(MAX_PATH_LENGTH, absoluteSafeRelLength));
|
|
@@ -5723,7 +5739,7 @@ function probeRemoteHealth(input) {
|
|
|
5723
5739
|
// src/utils/vault-sync-helper.ts
|
|
5724
5740
|
import { spawnSync } from "child_process";
|
|
5725
5741
|
import { existsSync as existsSync7 } from "fs";
|
|
5726
|
-
import {
|
|
5742
|
+
import { platform } from "os";
|
|
5727
5743
|
import { dirname as dirname6, join as join16 } from "path";
|
|
5728
5744
|
import { fileURLToPath } from "url";
|
|
5729
5745
|
var HELPER_NAME = "wiki-pull-with-auto-resolve.sh";
|
|
@@ -5746,13 +5762,7 @@ function candidateHelperPaths(input = { vault: "" }) {
|
|
|
5746
5762
|
paths.push(join16(here, "..", "..", "vault-sync", "scripts", HELPER_NAME));
|
|
5747
5763
|
paths.push(join16(here, "..", "..", "..", "vault-sync", "scripts", HELPER_NAME));
|
|
5748
5764
|
}
|
|
5749
|
-
const home = input.home
|
|
5750
|
-
try {
|
|
5751
|
-
return homedir();
|
|
5752
|
-
} catch {
|
|
5753
|
-
return void 0;
|
|
5754
|
-
}
|
|
5755
|
-
})();
|
|
5765
|
+
const home = resolveSkillwikiHome(input.home, env);
|
|
5756
5766
|
if (home) {
|
|
5757
5767
|
const xdg = env.XDG_DATA_HOME;
|
|
5758
5768
|
const isDarwin = platform() === "darwin";
|
|
@@ -5942,7 +5952,7 @@ function runSyncStatus(input) {
|
|
|
5942
5952
|
output.stashes = stashes;
|
|
5943
5953
|
}
|
|
5944
5954
|
if (input.includeRemoteHealth) {
|
|
5945
|
-
const home = input.home
|
|
5955
|
+
const home = resolveSkillwikiHome(input.home);
|
|
5946
5956
|
const remote_health = probeRemoteHealth({
|
|
5947
5957
|
vaultPath: vault,
|
|
5948
5958
|
home,
|
|
@@ -6527,7 +6537,7 @@ import {
|
|
|
6527
6537
|
writeFileSync as writeFileSync4
|
|
6528
6538
|
} from "fs";
|
|
6529
6539
|
import { hostname } from "os";
|
|
6530
|
-
import { dirname as dirname7, join as join18, resolve as
|
|
6540
|
+
import { dirname as dirname7, join as join18, resolve as resolve5 } from "path";
|
|
6531
6541
|
function managedWriteLockPath(vault) {
|
|
6532
6542
|
const gitPath = git(vault, ["rev-parse", "--git-path", "vault-sync/managed-write.lock"]);
|
|
6533
6543
|
if (gitPath) return gitPath.startsWith("/") ? gitPath : join18(vault, gitPath);
|
|
@@ -6572,7 +6582,7 @@ function hasLocalOwnerProof(vault, record) {
|
|
|
6572
6582
|
}
|
|
6573
6583
|
function reclaimDeadManagedWriteLockOwner(vault, options = {}) {
|
|
6574
6584
|
const path = managedWriteLockPath(vault);
|
|
6575
|
-
const gitStateVault =
|
|
6585
|
+
const gitStateVault = resolve5(options.gitStateVault ?? vault);
|
|
6576
6586
|
if (!existsSync9(path)) return ok({ reclaimed: false });
|
|
6577
6587
|
const record = readLockRecord(path);
|
|
6578
6588
|
if (!record) {
|
|
@@ -6859,7 +6869,7 @@ function supersedeStaleReviewRequiredJournals(vault, opts = {}) {
|
|
|
6859
6869
|
|
|
6860
6870
|
// src/utils/snapshot-worktree.ts
|
|
6861
6871
|
import { readFileSync as readFileSync8 } from "fs";
|
|
6862
|
-
import { join as join20, resolve as
|
|
6872
|
+
import { join as join20, resolve as resolve6 } from "path";
|
|
6863
6873
|
function readSkillWikiConfig(path) {
|
|
6864
6874
|
try {
|
|
6865
6875
|
return parseDotenvText(readFileSync8(path, "utf8"));
|
|
@@ -6888,12 +6898,12 @@ function resolveConfiguredSnapshotWorktree(home) {
|
|
|
6888
6898
|
if (!home) return void 0;
|
|
6889
6899
|
const config = readSkillWikiConfig(join20(home, ".skillwiki", ".env"));
|
|
6890
6900
|
const explicit = config["vault_sync.snapshot_worktree"];
|
|
6891
|
-
if (explicit) return
|
|
6901
|
+
if (explicit) return resolve6(explicit);
|
|
6892
6902
|
const snapshotProfile = config["vault_sync.snapshot_profile"];
|
|
6893
6903
|
if (!snapshotProfile) return void 0;
|
|
6894
|
-
const profile = readSnapshotProfile(
|
|
6904
|
+
const profile = readSnapshotProfile(resolve6(snapshotProfile));
|
|
6895
6905
|
const fromProfile = profile.WIKI_GIT_WORKTREE ?? profile.SNAPSHOT_WORKTREE ?? profile.GIT_DIR;
|
|
6896
|
-
return fromProfile ?
|
|
6906
|
+
return fromProfile ? resolve6(fromProfile) : void 0;
|
|
6897
6907
|
}
|
|
6898
6908
|
|
|
6899
6909
|
// src/utils/managed-write-preflight.ts
|
|
@@ -6910,7 +6920,7 @@ var DEFAULT_DEPS = {
|
|
|
6910
6920
|
converge: (input) => runVaultSyncPullHelper(input),
|
|
6911
6921
|
resolveConfiguredSnapshotWorktree,
|
|
6912
6922
|
syncPeers: runSyncPeers,
|
|
6913
|
-
sleepMs: (ms) => new Promise((
|
|
6923
|
+
sleepMs: (ms) => new Promise((resolve8) => setTimeout(resolve8, ms)),
|
|
6914
6924
|
nowMs: () => Date.now(),
|
|
6915
6925
|
logHeartbeat: (message) => {
|
|
6916
6926
|
process.stderr.write(`${message}
|
|
@@ -7102,8 +7112,8 @@ function isGitVault(vault) {
|
|
|
7102
7112
|
return Boolean(git(vault, ["rev-parse", "--absolute-git-dir"]));
|
|
7103
7113
|
}
|
|
7104
7114
|
async function runManagedWritePreflight(input, deps = DEFAULT_DEPS) {
|
|
7105
|
-
const mutationVault =
|
|
7106
|
-
let convergenceVault = input.convergenceVault &&
|
|
7115
|
+
const mutationVault = resolve7(input.vault);
|
|
7116
|
+
let convergenceVault = input.convergenceVault && resolve7(input.convergenceVault) !== mutationVault ? resolve7(input.convergenceVault) : void 0;
|
|
7107
7117
|
let convergenceSource = convergenceVault ? "explicit" : "single-path";
|
|
7108
7118
|
const mutationBlocker = preflightBlocker(mutationVault);
|
|
7109
7119
|
if (mutationBlocker) {
|
|
@@ -7181,7 +7191,7 @@ async function runManagedWritePreflight(input, deps = DEFAULT_DEPS) {
|
|
|
7181
7191
|
};
|
|
7182
7192
|
}
|
|
7183
7193
|
if (!convergenceVault && host.role === "snapshotter" && host.protected === true) {
|
|
7184
|
-
const home = input.home
|
|
7194
|
+
const home = resolveSkillwikiHome(input.home, input.env);
|
|
7185
7195
|
const configured = (deps.resolveConfiguredSnapshotWorktree ?? resolveConfiguredSnapshotWorktree)(home);
|
|
7186
7196
|
if (!configured) {
|
|
7187
7197
|
return {
|
|
@@ -7193,7 +7203,7 @@ async function runManagedWritePreflight(input, deps = DEFAULT_DEPS) {
|
|
|
7193
7203
|
})
|
|
7194
7204
|
};
|
|
7195
7205
|
}
|
|
7196
|
-
convergenceVault =
|
|
7206
|
+
convergenceVault = resolve7(configured);
|
|
7197
7207
|
convergenceSource = "configured";
|
|
7198
7208
|
if (convergenceVault === mutationVault) {
|
|
7199
7209
|
return {
|
|
@@ -7302,9 +7312,9 @@ async function runManagedWritePreflight(input, deps = DEFAULT_DEPS) {
|
|
|
7302
7312
|
};
|
|
7303
7313
|
}
|
|
7304
7314
|
async function runManagedWriteTransaction(input, deps = DEFAULT_DEPS) {
|
|
7305
|
-
const mutationVault =
|
|
7315
|
+
const mutationVault = resolve7(input.vault);
|
|
7306
7316
|
const lock = acquireManagedWriteLock(mutationVault, input.command, {
|
|
7307
|
-
gitStateVault: input.convergenceVault ?
|
|
7317
|
+
gitStateVault: input.convergenceVault ? resolve7(input.convergenceVault) : mutationVault
|
|
7308
7318
|
});
|
|
7309
7319
|
if (!lock.ok) {
|
|
7310
7320
|
return { exitCode: ExitCode.SYNC_LOCK_HELD, result: lock };
|
|
@@ -7357,6 +7367,7 @@ async function runManagedWriteTransaction(input, deps = DEFAULT_DEPS) {
|
|
|
7357
7367
|
}
|
|
7358
7368
|
|
|
7359
7369
|
export {
|
|
7370
|
+
resolveSkillwikiHome,
|
|
7360
7371
|
readLastOp,
|
|
7361
7372
|
appendLastOp,
|
|
7362
7373
|
clearLastOp,
|
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
releaseOwnedSyncLock,
|
|
32
32
|
resolveConfiguredSnapshotWorktree,
|
|
33
33
|
resolveRuntimePath,
|
|
34
|
+
resolveSkillwikiHome,
|
|
34
35
|
resolveVaultSyncPullHelper,
|
|
35
36
|
resolveWikiS3Remote,
|
|
36
37
|
runLint,
|
|
@@ -40,7 +41,7 @@ import {
|
|
|
40
41
|
snapshotterAliasForLocalHost,
|
|
41
42
|
toUndirectedWeighted,
|
|
42
43
|
writeDotenv
|
|
43
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-FYAKMULW.js";
|
|
44
45
|
import {
|
|
45
46
|
atomicWriteText,
|
|
46
47
|
prepareTypedPage
|
|
@@ -636,7 +637,7 @@ function computeAdamicAdar(adj) {
|
|
|
636
637
|
import { resolve as resolvePath } from "path";
|
|
637
638
|
async function guardProtectedVaultWrite(input) {
|
|
638
639
|
const env = input.env ?? process.env;
|
|
639
|
-
const home = input.home
|
|
640
|
+
const home = resolveSkillwikiHome(input.home, env);
|
|
640
641
|
const cwd = input.cwd ?? process.cwd();
|
|
641
642
|
const liveVaultPath = await resolveLiveVaultPath({ env, home, cwd });
|
|
642
643
|
const load = await loadFleetManifestAndHost({
|
|
@@ -1023,7 +1024,7 @@ function displayConfigValue(key, value) {
|
|
|
1023
1024
|
return value;
|
|
1024
1025
|
}
|
|
1025
1026
|
function configPath(home) {
|
|
1026
|
-
return join5(home, ".skillwiki", ".env");
|
|
1027
|
+
return join5(resolveSkillwikiHome(home), ".skillwiki", ".env");
|
|
1027
1028
|
}
|
|
1028
1029
|
async function runConfigGet(input) {
|
|
1029
1030
|
if (!validateKey(input.key)) {
|
|
@@ -1104,7 +1105,7 @@ function mcpAuthFromEnv(env) {
|
|
|
1104
1105
|
}
|
|
1105
1106
|
async function resolveMcpAuthEnv(input) {
|
|
1106
1107
|
const processAuth = mcpAuthFromEnv(input.env ?? process.env);
|
|
1107
|
-
const dotenv = await parseDotenvFile(join6(input.home, ".skillwiki", ".env"));
|
|
1108
|
+
const dotenv = await parseDotenvFile(join6(resolveSkillwikiHome(input.home, input.env), ".skillwiki", ".env"));
|
|
1108
1109
|
const fileAuth = mcpAuthFromEnv(dotenv);
|
|
1109
1110
|
return {
|
|
1110
1111
|
url: processAuth.url ?? fileAuth.url,
|
|
@@ -1398,7 +1399,7 @@ async function checkConfigFile(home) {
|
|
|
1398
1399
|
try {
|
|
1399
1400
|
const map = await parseDotenvFile(cfgPath);
|
|
1400
1401
|
const keys = Object.keys(map);
|
|
1401
|
-
return check("pass", "config_file", "Config file exists", `Found with keys: ${keys.length > 0 ? keys.join(", ") : "(none set)"}`);
|
|
1402
|
+
return check("pass", "config_file", "Config file exists", `Found ${cfgPath} with keys: ${keys.length > 0 ? keys.join(", ") : "(none set)"}`);
|
|
1402
1403
|
} catch (e) {
|
|
1403
1404
|
return check("warn", "config_file", "Config file exists", `Failed to parse ${cfgPath}: ${String(e)}`);
|
|
1404
1405
|
}
|
|
@@ -4255,6 +4256,46 @@ var dsStoreNoiseProbe = {
|
|
|
4255
4256
|
// src/doctor/probes/mcp-handshake.ts
|
|
4256
4257
|
import { existsSync as existsSync17 } from "fs";
|
|
4257
4258
|
import { join as join21 } from "path";
|
|
4259
|
+
|
|
4260
|
+
// src/utils/mcp-client.ts
|
|
4261
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
4262
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
4263
|
+
var MCP_PROBE_TIMEOUT_MS = 1e4;
|
|
4264
|
+
async function withMcpClient(input, probe) {
|
|
4265
|
+
const controller = new AbortController();
|
|
4266
|
+
const client = new Client({ name: input.clientName, version: input.version });
|
|
4267
|
+
const fetchFn = input.fetchFn ?? globalThis.fetch;
|
|
4268
|
+
const transport = new StreamableHTTPClientTransport(new URL(input.url), {
|
|
4269
|
+
requestInit: { headers: { Authorization: `Bearer ${input.token}` } },
|
|
4270
|
+
fetch: (url, init) => fetchFn(url, {
|
|
4271
|
+
...init,
|
|
4272
|
+
signal: init?.signal ? AbortSignal.any([init.signal, controller.signal]) : controller.signal
|
|
4273
|
+
})
|
|
4274
|
+
});
|
|
4275
|
+
let timer;
|
|
4276
|
+
const deadline = new Promise((_resolve, reject) => {
|
|
4277
|
+
timer = setTimeout(() => {
|
|
4278
|
+
const error = new Error(`MCP probe timed out after ${MCP_PROBE_TIMEOUT_MS}ms`);
|
|
4279
|
+
reject(error);
|
|
4280
|
+
controller.abort(error);
|
|
4281
|
+
}, MCP_PROBE_TIMEOUT_MS);
|
|
4282
|
+
});
|
|
4283
|
+
try {
|
|
4284
|
+
const work = async () => {
|
|
4285
|
+
await client.connect(transport, { signal: controller.signal, timeout: MCP_PROBE_TIMEOUT_MS });
|
|
4286
|
+
return probe(client, controller.signal);
|
|
4287
|
+
};
|
|
4288
|
+
return await Promise.race([work(), deadline]);
|
|
4289
|
+
} catch (error) {
|
|
4290
|
+
throw new Error(redactMcpSecret(error instanceof Error ? error.message : String(error), input.token));
|
|
4291
|
+
} finally {
|
|
4292
|
+
clearTimeout(timer);
|
|
4293
|
+
controller.abort();
|
|
4294
|
+
await client.close();
|
|
4295
|
+
}
|
|
4296
|
+
}
|
|
4297
|
+
|
|
4298
|
+
// src/doctor/probes/mcp-handshake.ts
|
|
4258
4299
|
var DEFAULT_MCP_URL = "https://wiki.karldigi.dev/mcp";
|
|
4259
4300
|
function mcpEnv(ctx) {
|
|
4260
4301
|
return ctx.input.env ?? process.env;
|
|
@@ -4322,54 +4363,6 @@ function redactSecret(detail, secret) {
|
|
|
4322
4363
|
function handshakeRow(status, detail, secret) {
|
|
4323
4364
|
return check(status, HANDSHAKE_ID, HANDSHAKE_LABEL, redactSecret(detail, secret));
|
|
4324
4365
|
}
|
|
4325
|
-
function parseMcpBody(text) {
|
|
4326
|
-
const trimmed = text.trim();
|
|
4327
|
-
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
4328
|
-
return JSON.parse(trimmed);
|
|
4329
|
-
}
|
|
4330
|
-
for (const line of trimmed.split(/\r?\n/)) {
|
|
4331
|
-
const prefix = line.startsWith("data:") ? line.slice(5).trim() : "";
|
|
4332
|
-
if (prefix.startsWith("{")) return JSON.parse(prefix);
|
|
4333
|
-
}
|
|
4334
|
-
throw new Error("non-JSON MCP body");
|
|
4335
|
-
}
|
|
4336
|
-
function jsonRpcResult(body) {
|
|
4337
|
-
if (typeof body !== "object" || body === null) {
|
|
4338
|
-
throw new Error("invalid JSON-RPC body");
|
|
4339
|
-
}
|
|
4340
|
-
const rec = body;
|
|
4341
|
-
if (rec.error) {
|
|
4342
|
-
throw new Error(typeof rec.error.message === "string" ? rec.error.message : "JSON-RPC error");
|
|
4343
|
-
}
|
|
4344
|
-
if (typeof rec.result !== "object" || rec.result === null) {
|
|
4345
|
-
throw new Error("missing JSON-RPC result");
|
|
4346
|
-
}
|
|
4347
|
-
return rec.result;
|
|
4348
|
-
}
|
|
4349
|
-
async function mcpJsonRpc(fetchFn, url, token, method, id, params, sessionId) {
|
|
4350
|
-
const headers = {
|
|
4351
|
-
Authorization: `Bearer ${token}`,
|
|
4352
|
-
"Content-Type": "application/json",
|
|
4353
|
-
Accept: "application/json, text/event-stream"
|
|
4354
|
-
};
|
|
4355
|
-
if (sessionId) headers["mcp-session-id"] = sessionId;
|
|
4356
|
-
const res = await fetchFn(url, {
|
|
4357
|
-
method: "POST",
|
|
4358
|
-
headers,
|
|
4359
|
-
body: JSON.stringify({ jsonrpc: "2.0", id, method, params })
|
|
4360
|
-
});
|
|
4361
|
-
if (!res.ok) {
|
|
4362
|
-
throw new Error(`HTTP ${res.status}`);
|
|
4363
|
-
}
|
|
4364
|
-
const nextSession = res.headers.get("mcp-session-id") ?? sessionId;
|
|
4365
|
-
const result = jsonRpcResult(parseMcpBody(await res.text()));
|
|
4366
|
-
return { result, sessionId: nextSession ?? void 0 };
|
|
4367
|
-
}
|
|
4368
|
-
function toolNames(result) {
|
|
4369
|
-
const tools = result.tools;
|
|
4370
|
-
if (!Array.isArray(tools)) return [];
|
|
4371
|
-
return tools.map((t) => typeof t === "object" && t !== null && typeof t.name === "string" ? t.name : "").filter((name) => name.length > 0);
|
|
4372
|
-
}
|
|
4373
4366
|
async function checkMcpHandshake(ctx) {
|
|
4374
4367
|
if (!ctx.input.checkMcp) {
|
|
4375
4368
|
return handshakeRow("pass", "not requested \u2014 check skipped");
|
|
@@ -4384,33 +4377,16 @@ async function checkMcpHandshake(ctx) {
|
|
|
4384
4377
|
const fetchFn = ctx.input.mcpFetch ?? globalThis.fetch;
|
|
4385
4378
|
const shipped = ctx.input.currentVersion;
|
|
4386
4379
|
try {
|
|
4387
|
-
const
|
|
4388
|
-
fetchFn,
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
|
|
4392
|
-
|
|
4393
|
-
{
|
|
4394
|
-
protocolVersion: "2025-11-25",
|
|
4395
|
-
capabilities: {},
|
|
4396
|
-
clientInfo: { name: "skillwiki-doctor", version: shipped }
|
|
4397
|
-
}
|
|
4380
|
+
const { advertised, tools } = await withMcpClient(
|
|
4381
|
+
{ fetchFn, url, token, clientName: "skillwiki-doctor", version: shipped },
|
|
4382
|
+
async (client, signal) => ({
|
|
4383
|
+
advertised: client.getServerVersion()?.version ?? "",
|
|
4384
|
+
tools: (await client.listTools({}, { signal })).tools.map((tool) => tool.name)
|
|
4385
|
+
})
|
|
4398
4386
|
);
|
|
4399
|
-
const serverInfo = init.result.serverInfo;
|
|
4400
|
-
const advertised = typeof serverInfo === "object" && serverInfo !== null && typeof serverInfo.version === "string" ? serverInfo.version : "";
|
|
4401
4387
|
if (!advertised) {
|
|
4402
4388
|
return handshakeRow("error", "handshake failed \u2014 missing serverInfo.version", token);
|
|
4403
4389
|
}
|
|
4404
|
-
const listed = await mcpJsonRpc(
|
|
4405
|
-
fetchFn,
|
|
4406
|
-
url,
|
|
4407
|
-
token,
|
|
4408
|
-
"tools/list",
|
|
4409
|
-
2,
|
|
4410
|
-
{},
|
|
4411
|
-
init.sessionId
|
|
4412
|
-
);
|
|
4413
|
-
const tools = toolNames(listed.result);
|
|
4414
4390
|
const frozen = Boolean(ctx.resolvedPath && existsSync17(join21(ctx.resolvedPath, ".WIKI_GIT_FROZEN")));
|
|
4415
4391
|
if (frozen && !tools.includes(WORKITEM_TOOL)) {
|
|
4416
4392
|
return handshakeRow(
|
|
@@ -4482,6 +4458,7 @@ var DoctorRunner = class {
|
|
|
4482
4458
|
return this.probes;
|
|
4483
4459
|
}
|
|
4484
4460
|
async run(input) {
|
|
4461
|
+
input = { ...input, home: resolveSkillwikiHome(input.home, input.env) };
|
|
4485
4462
|
const devSourceRun = isDevSourceRun(input.argv);
|
|
4486
4463
|
const vsConfig = readVaultSyncConfig(input.home);
|
|
4487
4464
|
const baseEnv = input.env ?? process.env;
|
|
@@ -6894,7 +6871,7 @@ function getVaultAllowlistFromEnv() {
|
|
|
6894
6871
|
|
|
6895
6872
|
// src/mcp/vault-resolve.ts
|
|
6896
6873
|
async function resolveMcpVault(input) {
|
|
6897
|
-
const home = input.home
|
|
6874
|
+
const home = resolveSkillwikiHome(input.home);
|
|
6898
6875
|
let vaultPath;
|
|
6899
6876
|
let source = "resolved";
|
|
6900
6877
|
if (input.vault !== void 0 && input.vault.length > 0) {
|
|
@@ -6943,7 +6920,6 @@ function formatToolResult(payload) {
|
|
|
6943
6920
|
|
|
6944
6921
|
// src/mcp/audit-log.ts
|
|
6945
6922
|
import { appendFileSync, mkdirSync as mkdirSync2 } from "fs";
|
|
6946
|
-
import { homedir } from "os";
|
|
6947
6923
|
import { join as join28 } from "path";
|
|
6948
6924
|
function auditEnabled() {
|
|
6949
6925
|
const v = process.env.SKILLWIKI_MCP_AUDIT;
|
|
@@ -6956,7 +6932,7 @@ function auditSink() {
|
|
|
6956
6932
|
function auditFilePath() {
|
|
6957
6933
|
const custom = process.env.SKILLWIKI_MCP_AUDIT_FILE;
|
|
6958
6934
|
if (custom && custom.length > 0) return custom;
|
|
6959
|
-
return join28(
|
|
6935
|
+
return join28(resolveSkillwikiHome(), ".skillwiki", "mcp-audit.jsonl");
|
|
6960
6936
|
}
|
|
6961
6937
|
function auditMcpToolCall(entry) {
|
|
6962
6938
|
if (!auditEnabled()) return;
|
|
@@ -7059,7 +7035,7 @@ function registerMcpTools(server) {
|
|
|
7059
7035
|
await resolveMcpVault({ vault, wiki });
|
|
7060
7036
|
const pkg = readCliPackageJson();
|
|
7061
7037
|
const r = await runDoctor({
|
|
7062
|
-
home:
|
|
7038
|
+
home: resolveSkillwikiHome(),
|
|
7063
7039
|
envValue: process.env.WIKI_PATH,
|
|
7064
7040
|
argv: process.argv,
|
|
7065
7041
|
currentVersion: pkg.version,
|
|
@@ -7132,7 +7108,7 @@ function registerMcpTools(server) {
|
|
|
7132
7108
|
})
|
|
7133
7109
|
},
|
|
7134
7110
|
async ({ key }) => runMcpToolHandler("skillwiki.config_get", {}, async () => {
|
|
7135
|
-
const r = await runConfigGet({ key, home:
|
|
7111
|
+
const r = await runConfigGet({ key, home: resolveSkillwikiHome() });
|
|
7136
7112
|
return formatToolResult(r);
|
|
7137
7113
|
})
|
|
7138
7114
|
);
|
|
@@ -7955,6 +7931,7 @@ export {
|
|
|
7955
7931
|
MCP_TOKEN_ENV,
|
|
7956
7932
|
MCP_HOST_ID_ENV,
|
|
7957
7933
|
nonEmptyEnvValue,
|
|
7934
|
+
mcpAuthFromEnv,
|
|
7958
7935
|
mergeMcpAuthIntoEnv,
|
|
7959
7936
|
redactMcpSecret,
|
|
7960
7937
|
configPath,
|
|
@@ -7972,6 +7949,7 @@ export {
|
|
|
7972
7949
|
readSatelliteLatestRunFromText,
|
|
7973
7950
|
readSatelliteLatestRunAt,
|
|
7974
7951
|
evaluateSatelliteRunHealthState,
|
|
7952
|
+
withMcpClient,
|
|
7975
7953
|
DEFAULT_MCP_URL,
|
|
7976
7954
|
runDoctor,
|
|
7977
7955
|
readCliPackageJson,
|
package/dist/cli.js
CHANGED
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
guardProtectedVaultWrite,
|
|
22
22
|
isEventLedgerPath,
|
|
23
23
|
isFailedRunStatus,
|
|
24
|
+
mcpAuthFromEnv,
|
|
24
25
|
measureDirtyVolume,
|
|
25
26
|
memoryAuthorityTiersRank,
|
|
26
27
|
mergeMcpAuthIntoEnv,
|
|
@@ -62,8 +63,9 @@ import {
|
|
|
62
63
|
scanConflictMarkerBlocksInText,
|
|
63
64
|
snapshotterHealthChecks,
|
|
64
65
|
upsertIndexEntry,
|
|
65
|
-
vectorIndexStatus
|
|
66
|
-
|
|
66
|
+
vectorIndexStatus,
|
|
67
|
+
withMcpClient
|
|
68
|
+
} from "./chunk-LDEZQXH6.js";
|
|
67
69
|
import {
|
|
68
70
|
normalizeDistTag,
|
|
69
71
|
readCache,
|
|
@@ -133,6 +135,7 @@ import {
|
|
|
133
135
|
resolveFleetHostId,
|
|
134
136
|
resolveInitTimePath,
|
|
135
137
|
resolveRuntimePath,
|
|
138
|
+
resolveSkillwikiHome,
|
|
136
139
|
resolveWikiS3Remote,
|
|
137
140
|
rewriteRawSourceReferences,
|
|
138
141
|
runAudit,
|
|
@@ -168,7 +171,7 @@ import {
|
|
|
168
171
|
supersedeStaleReviewRequiredJournals,
|
|
169
172
|
taxonomyCommentForPage,
|
|
170
173
|
writeDotenv
|
|
171
|
-
} from "./chunk-
|
|
174
|
+
} from "./chunk-FYAKMULW.js";
|
|
172
175
|
import {
|
|
173
176
|
assertTargetInsideVault,
|
|
174
177
|
atomicWriteText,
|
|
@@ -3671,6 +3674,7 @@ ${formatHostRow(normalizedHash, hostId, granted.vaults)}` };
|
|
|
3671
3674
|
}
|
|
3672
3675
|
|
|
3673
3676
|
// src/commands/connect.ts
|
|
3677
|
+
import { CallToolResultSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
3674
3678
|
var CONNECT_DESCRIPTION = "HTTP MCP leaf connect: ingest a chat-attached env file into ~/.skillwiki/.env (mode 0600). Never runs skillwiki init. Cloud Drive / \u4E91\u76D8 is unsupported.";
|
|
3675
3679
|
var RESERVED_HOST_IDS = ["msi", "doubao-linux-agent", "macos-dev"];
|
|
3676
3680
|
var DEST_MODE = 384;
|
|
@@ -3712,44 +3716,16 @@ function redactConnectPayload(data, secret) {
|
|
|
3712
3716
|
};
|
|
3713
3717
|
}
|
|
3714
3718
|
async function readWikiStatus(fetchFn, url, token) {
|
|
3715
|
-
const headers = {
|
|
3716
|
-
Authorization: `Bearer ${token}`,
|
|
3717
|
-
"Content-Type": "application/json",
|
|
3718
|
-
Accept: "application/json, text/event-stream"
|
|
3719
|
-
};
|
|
3720
3719
|
try {
|
|
3721
|
-
const
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
|
|
3727
|
-
method: "initialize",
|
|
3728
|
-
params: {
|
|
3729
|
-
protocolVersion: "2025-11-25",
|
|
3730
|
-
capabilities: {},
|
|
3731
|
-
clientInfo: { name: "skillwiki-connect", version: "0" }
|
|
3732
|
-
}
|
|
3733
|
-
})
|
|
3734
|
-
});
|
|
3735
|
-
const session = initRes.headers.get("mcp-session-id");
|
|
3736
|
-
if (session) headers["mcp-session-id"] = session;
|
|
3737
|
-
const statusRes = await fetchFn(url, {
|
|
3738
|
-
method: "POST",
|
|
3739
|
-
headers,
|
|
3740
|
-
body: JSON.stringify({
|
|
3741
|
-
jsonrpc: "2.0",
|
|
3742
|
-
id: 2,
|
|
3743
|
-
method: "tools/call",
|
|
3744
|
-
params: { name: "wiki_status", arguments: {} }
|
|
3745
|
-
})
|
|
3746
|
-
});
|
|
3747
|
-
const raw = await statusRes.text();
|
|
3748
|
-
const parsed = JSON.parse(raw.startsWith("data:") ? raw.replace(/^data:\s*/m, "") : raw);
|
|
3749
|
-
const structured = parsed.result?.structuredContent;
|
|
3750
|
-
let body = structured;
|
|
3720
|
+
const result = await withMcpClient(
|
|
3721
|
+
{ fetchFn, url, token, clientName: "skillwiki-connect", version: "0" },
|
|
3722
|
+
async (client, signal) => CallToolResultSchema.parse(await client.callTool({ name: "wiki_status", arguments: {} }, void 0, { signal }))
|
|
3723
|
+
);
|
|
3724
|
+
if (result.isError) return { writer_id: null, ok: null, reconcile_ready: null, error: "wiki_status returned a tool error" };
|
|
3725
|
+
let body = result.structuredContent;
|
|
3751
3726
|
if (!body) {
|
|
3752
|
-
const
|
|
3727
|
+
const content = result.content.find((item) => item.type === "text");
|
|
3728
|
+
const text = content?.type === "text" ? content.text : void 0;
|
|
3753
3729
|
if (text) {
|
|
3754
3730
|
try {
|
|
3755
3731
|
body = JSON.parse(text);
|
|
@@ -3758,17 +3734,26 @@ async function readWikiStatus(fetchFn, url, token) {
|
|
|
3758
3734
|
}
|
|
3759
3735
|
}
|
|
3760
3736
|
}
|
|
3761
|
-
if (!body
|
|
3737
|
+
if (!body || typeof body !== "object" || Array.isArray(body) || typeof body.ok !== "boolean" || typeof body.reconcile_ready !== "boolean" || body.writer_id !== void 0 && typeof body.writer_id !== "string") {
|
|
3738
|
+
return { writer_id: null, ok: null, reconcile_ready: null, error: "wiki_status returned an invalid status object" };
|
|
3739
|
+
}
|
|
3740
|
+
if (!body.ok) return { writer_id: null, ok: false, reconcile_ready: body.reconcile_ready, error: "wiki_status reported failure" };
|
|
3762
3741
|
return {
|
|
3763
|
-
writer_id:
|
|
3764
|
-
ok:
|
|
3765
|
-
reconcile_ready:
|
|
3742
|
+
writer_id: body.writer_id ?? null,
|
|
3743
|
+
ok: body.ok,
|
|
3744
|
+
reconcile_ready: body.reconcile_ready
|
|
3745
|
+
};
|
|
3746
|
+
} catch (error) {
|
|
3747
|
+
return {
|
|
3748
|
+
writer_id: null,
|
|
3749
|
+
ok: null,
|
|
3750
|
+
reconcile_ready: null,
|
|
3751
|
+
error: redactMcpSecret(error instanceof Error ? error.message : String(error), token)
|
|
3766
3752
|
};
|
|
3767
|
-
} catch {
|
|
3768
|
-
return { writer_id: null, ok: null, reconcile_ready: null };
|
|
3769
3753
|
}
|
|
3770
3754
|
}
|
|
3771
3755
|
async function runConnect(input) {
|
|
3756
|
+
input = { ...input, home: resolveSkillwikiHome(input.home, input.env) };
|
|
3772
3757
|
const dest = join18(input.home, ".skillwiki", ".env");
|
|
3773
3758
|
const fromFile = input.fromFile?.trim();
|
|
3774
3759
|
const fromStdin = Boolean(input.fromStdin);
|
|
@@ -3878,8 +3863,13 @@ async function runConnect(input) {
|
|
|
3878
3863
|
if (doctor.result.ok) {
|
|
3879
3864
|
handshake = doctor.result.data.checks.find((c) => c.id === "mcp_handshake")?.detail ?? null;
|
|
3880
3865
|
}
|
|
3881
|
-
const
|
|
3882
|
-
const
|
|
3866
|
+
const auth = mcpAuthFromEnv(env);
|
|
3867
|
+
const url = auth.url ?? DEFAULT_MCP_URL;
|
|
3868
|
+
const status = await readWikiStatus(input.mcpFetch ?? globalThis.fetch, url, auth.token ?? incomingToken);
|
|
3869
|
+
if (status.error) {
|
|
3870
|
+
doctorExit = ExitCode.DOCTOR_HAS_ERRORS;
|
|
3871
|
+
handshake = `${handshake ?? ""}; wiki_status verification failed \u2014 ${status.error}`;
|
|
3872
|
+
}
|
|
3883
3873
|
writerId = status.writer_id;
|
|
3884
3874
|
statusOk = status.ok;
|
|
3885
3875
|
reconcileReady = status.reconcile_ready;
|
|
@@ -6119,7 +6109,6 @@ import {
|
|
|
6119
6109
|
unlinkSync,
|
|
6120
6110
|
writeFileSync as writeFileSync5
|
|
6121
6111
|
} from "fs";
|
|
6122
|
-
import { homedir } from "os";
|
|
6123
6112
|
import { dirname as dirname6, join as join28 } from "path";
|
|
6124
6113
|
var PUBLICATION_JOURNAL_SCHEMA = "skillwiki-publication-operation-v1";
|
|
6125
6114
|
var PHASE_ORDER2 = [
|
|
@@ -6148,10 +6137,10 @@ function vaultIdentity(vaultPath) {
|
|
|
6148
6137
|
}
|
|
6149
6138
|
return sha256Hex(real).slice(0, 16);
|
|
6150
6139
|
}
|
|
6151
|
-
function publicationJournalRoot(home =
|
|
6152
|
-
return join28(home, ".skillwiki", "publication-operations");
|
|
6140
|
+
function publicationJournalRoot(home = resolveSkillwikiHome()) {
|
|
6141
|
+
return join28(resolveSkillwikiHome(home), ".skillwiki", "publication-operations");
|
|
6153
6142
|
}
|
|
6154
|
-
function resolveJournalPaths(vaultPath, operationId2, home =
|
|
6143
|
+
function resolveJournalPaths(vaultPath, operationId2, home = resolveSkillwikiHome()) {
|
|
6155
6144
|
const identity = vaultIdentity(vaultPath);
|
|
6156
6145
|
const rootDir = publicationJournalRoot(home);
|
|
6157
6146
|
const vaultDir = join28(rootDir, identity);
|
|
@@ -6261,7 +6250,7 @@ function buildIdentitySummary(input) {
|
|
|
6261
6250
|
prior_target_sha256: input.prior_target_sha256
|
|
6262
6251
|
};
|
|
6263
6252
|
}
|
|
6264
|
-
function readPublicationJournal(vaultPath, operationId2, home =
|
|
6253
|
+
function readPublicationJournal(vaultPath, operationId2, home = resolveSkillwikiHome()) {
|
|
6265
6254
|
const { journalPath: journalPath2 } = resolveJournalPaths(vaultPath, operationId2, home);
|
|
6266
6255
|
if (!existsSync10(journalPath2)) return ok(null);
|
|
6267
6256
|
let text;
|
|
@@ -6279,7 +6268,7 @@ function readPublicationJournal(vaultPath, operationId2, home = process.env.HOME
|
|
|
6279
6268
|
return validateRecord(parsed);
|
|
6280
6269
|
}
|
|
6281
6270
|
function createPublicationJournal(input) {
|
|
6282
|
-
const home = input.home
|
|
6271
|
+
const home = resolveSkillwikiHome(input.home);
|
|
6283
6272
|
const paths = resolveJournalPaths(input.vaultPath, input.operationId, home);
|
|
6284
6273
|
if (existsSync10(paths.journalPath)) {
|
|
6285
6274
|
return err("WRITE_FAILED", { message: "journal already exists", path: paths.journalPath });
|
|
@@ -6306,7 +6295,7 @@ function createPublicationJournal(input) {
|
|
|
6306
6295
|
return ok(record);
|
|
6307
6296
|
}
|
|
6308
6297
|
function advancePublicationJournal(input) {
|
|
6309
|
-
const home = input.home
|
|
6298
|
+
const home = resolveSkillwikiHome(input.home);
|
|
6310
6299
|
const existing = readPublicationJournal(input.vaultPath, input.operationId, home);
|
|
6311
6300
|
if (!existing.ok) return existing;
|
|
6312
6301
|
if (!existing.data) {
|
|
@@ -6351,7 +6340,7 @@ function advancePublicationJournal(input) {
|
|
|
6351
6340
|
}
|
|
6352
6341
|
return ok(record);
|
|
6353
6342
|
}
|
|
6354
|
-
function deletePublicationJournal(vaultPath, operationId2, home =
|
|
6343
|
+
function deletePublicationJournal(vaultPath, operationId2, home = resolveSkillwikiHome()) {
|
|
6355
6344
|
const { journalPath: journalPath2 } = resolveJournalPaths(vaultPath, operationId2, home);
|
|
6356
6345
|
if (!existsSync10(journalPath2)) return ok({ deleted: false });
|
|
6357
6346
|
try {
|
|
@@ -6372,7 +6361,7 @@ function completePublicationJournal(input) {
|
|
|
6372
6361
|
const deleted = deletePublicationJournal(
|
|
6373
6362
|
input.vaultPath,
|
|
6374
6363
|
input.operationId,
|
|
6375
|
-
input.home
|
|
6364
|
+
resolveSkillwikiHome(input.home)
|
|
6376
6365
|
);
|
|
6377
6366
|
if (!deleted.ok) return deleted;
|
|
6378
6367
|
return ok({ completed: true });
|
|
@@ -8898,7 +8887,7 @@ function refusalErr(code, reason, guidance) {
|
|
|
8898
8887
|
}
|
|
8899
8888
|
async function runSnapshotMaintenanceDryRun(input) {
|
|
8900
8889
|
const env = input.env ?? process.env;
|
|
8901
|
-
const home = input.home
|
|
8890
|
+
const home = resolveSkillwikiHome(input.home, env);
|
|
8902
8891
|
const audit = input.auditSink ?? defaultAuditSink(home);
|
|
8903
8892
|
const now = input.now ?? Date.now();
|
|
8904
8893
|
const liveVaultPath = input.liveVaultPath ? canonicalize(input.liveVaultPath) : await resolveLiveVault({ env, home });
|
|
@@ -9039,7 +9028,7 @@ function makeAuditEvent(input, hostId, now, result, errorCode, approvalId, comma
|
|
|
9039
9028
|
}
|
|
9040
9029
|
async function runSnapshotMaintenanceExecute(input) {
|
|
9041
9030
|
const env = input.env ?? process.env;
|
|
9042
|
-
const home = input.home
|
|
9031
|
+
const home = resolveSkillwikiHome(input.home, env);
|
|
9043
9032
|
const audit = input.auditSink ?? defaultAuditSink(home);
|
|
9044
9033
|
const now = input.now ?? Date.now();
|
|
9045
9034
|
const isTty = input.isTty ?? !!process.stdin.isTTY;
|
|
@@ -9174,7 +9163,7 @@ function extraUnmergedPaths(unmerged) {
|
|
|
9174
9163
|
}
|
|
9175
9164
|
async function authorizeRepairContext(input) {
|
|
9176
9165
|
const env = input.env ?? process.env;
|
|
9177
|
-
const home = input.home
|
|
9166
|
+
const home = resolveSkillwikiHome(input.home, env);
|
|
9178
9167
|
const audit = input.auditSink ?? defaultAuditSink(home);
|
|
9179
9168
|
const now = input.now ?? Date.now();
|
|
9180
9169
|
const liveVaultPath = input.liveVaultPath ? canonicalize(input.liveVaultPath) : await resolveLiveVault({ env, home });
|
|
@@ -9238,7 +9227,7 @@ async function authorizeRepairContext(input) {
|
|
|
9238
9227
|
}
|
|
9239
9228
|
async function runProjectionConflictRepairDryRun(input) {
|
|
9240
9229
|
const env = input.env ?? process.env;
|
|
9241
|
-
const home = input.home
|
|
9230
|
+
const home = resolveSkillwikiHome(input.home, env);
|
|
9242
9231
|
const audit = input.auditSink ?? defaultAuditSink(home);
|
|
9243
9232
|
const now = input.now ?? Date.now();
|
|
9244
9233
|
const ctx = await authorizeRepairContext(input);
|
|
@@ -9341,7 +9330,7 @@ async function performProjectionRepair(input, plan, audit, now) {
|
|
|
9341
9330
|
}
|
|
9342
9331
|
async function runProjectionConflictRepairExecute(input) {
|
|
9343
9332
|
const env = input.env ?? process.env;
|
|
9344
|
-
const home = input.home
|
|
9333
|
+
const home = resolveSkillwikiHome(input.home, env);
|
|
9345
9334
|
const audit = input.auditSink ?? defaultAuditSink(home);
|
|
9346
9335
|
const now = input.now ?? Date.now();
|
|
9347
9336
|
const isTty = input.isTty ?? !!process.stdin.isTTY;
|
|
@@ -10869,7 +10858,7 @@ function rowHealthy(reachable, timer, runUnhealthy, timerBad, platform3) {
|
|
|
10869
10858
|
async function runFleetHealth(input) {
|
|
10870
10859
|
const deps = input.deps ?? defaultDeps3();
|
|
10871
10860
|
const env = input.env ?? process.env;
|
|
10872
|
-
const home = input.home
|
|
10861
|
+
const home = resolveSkillwikiHome(input.home, env);
|
|
10873
10862
|
const osHostname = input.osHostname ?? env.HOSTNAME ?? nodeHostname();
|
|
10874
10863
|
const vault = input.vault ?? env.WIKI_PATH;
|
|
10875
10864
|
const file = input.file ?? (vault ? join43(vault, FLEET_REL_PATH) : void 0);
|
|
@@ -10974,7 +10963,7 @@ function isValidLastOpPath(file) {
|
|
|
10974
10963
|
}
|
|
10975
10964
|
async function postCommit(vault, exitCode) {
|
|
10976
10965
|
if (exitCode !== 0) return;
|
|
10977
|
-
const home =
|
|
10966
|
+
const home = resolveSkillwikiHome();
|
|
10978
10967
|
const dotenv = await parseDotenvFile(configPath(home));
|
|
10979
10968
|
const autoCommit = process.env.AUTO_COMMIT ?? dotenv["AUTO_COMMIT"];
|
|
10980
10969
|
if (autoCommit === "false") return;
|
|
@@ -11192,7 +11181,7 @@ async function emitGuardedVaultWrite(vault, command, run, opts) {
|
|
|
11192
11181
|
vault,
|
|
11193
11182
|
command,
|
|
11194
11183
|
env: process.env,
|
|
11195
|
-
home:
|
|
11184
|
+
home: resolveSkillwikiHome(),
|
|
11196
11185
|
cwd: process.cwd(),
|
|
11197
11186
|
osHostname: process.env.HOSTNAME,
|
|
11198
11187
|
user: process.env.USER
|
|
@@ -11211,7 +11200,7 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
|
|
|
11211
11200
|
vault,
|
|
11212
11201
|
command,
|
|
11213
11202
|
env: process.env,
|
|
11214
|
-
home:
|
|
11203
|
+
home: resolveSkillwikiHome(),
|
|
11215
11204
|
cwd: process.cwd(),
|
|
11216
11205
|
osHostname: process.env.HOSTNAME,
|
|
11217
11206
|
user: process.env.USER
|
|
@@ -11223,14 +11212,14 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
|
|
|
11223
11212
|
if (dirty) {
|
|
11224
11213
|
return emit(dirty, void 0, { postCommit: false });
|
|
11225
11214
|
}
|
|
11226
|
-
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-
|
|
11215
|
+
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-MAIGWFQJ.js");
|
|
11227
11216
|
const run = await runManagedWriteTransaction2({
|
|
11228
11217
|
vault,
|
|
11229
11218
|
command,
|
|
11230
11219
|
allowImmutableRecord: opts?.allowImmutableRecord === true,
|
|
11231
11220
|
convergenceVault: opts?.convergenceVault,
|
|
11232
11221
|
env: process.env,
|
|
11233
|
-
home:
|
|
11222
|
+
home: resolveSkillwikiHome(),
|
|
11234
11223
|
cwd: process.cwd(),
|
|
11235
11224
|
osHostname: process.env.HOSTNAME,
|
|
11236
11225
|
user: process.env.USER,
|
|
@@ -11476,14 +11465,14 @@ sourcesCmd.command("dispose <raw-path> [vault]").description("permanently delete
|
|
|
11476
11465
|
program.command("orphans [vault]").description("find pages not referenced by any other page").option("--wiki <name>", "wiki profile name").action(async (vault, opts) => emit(await runOrphans({
|
|
11477
11466
|
vault,
|
|
11478
11467
|
envValue: process.env.WIKI_PATH,
|
|
11479
|
-
home:
|
|
11468
|
+
home: resolveSkillwikiHome(),
|
|
11480
11469
|
wiki: opts.wiki,
|
|
11481
11470
|
cwd: process.cwd()
|
|
11482
11471
|
})));
|
|
11483
11472
|
program.command("audit <file>").description("audit citation markers and source provenance for a vault page").action(async (file) => emit(await runAudit({ file })));
|
|
11484
|
-
program.command("install").description("install skillwiki SKILL.md files into ~/.claude/skills/").option("--target <dir>", "target install directory", `${
|
|
11473
|
+
program.command("install").description("install skillwiki SKILL.md files into ~/.claude/skills/").option("--target <dir>", "target install directory", `${resolveSkillwikiHome()}/.claude/skills/`).option("--dry-run", "preview only", false).option("--skills-root <dir>", "source skills directory (defaults to packaged)").option("--symlink", "create symlinks instead of copies (dev mode \u2014 edits to source are immediately visible)", false).option("--force", "install CLI copies even when the skillwiki@llm-wiki plugin channel is active", false).action(async (opts) => {
|
|
11485
11474
|
const skillsRoot = opts.skillsRoot ?? new URL("../skills/", import.meta.url).pathname;
|
|
11486
|
-
emit(await runInstall({ skillsRoot, target: opts.target, dryRun: !!opts.dryRun, symlink: !!opts.symlink, home:
|
|
11475
|
+
emit(await runInstall({ skillsRoot, target: opts.target, dryRun: !!opts.dryRun, symlink: !!opts.symlink, home: resolveSkillwikiHome(), force: !!opts.force }));
|
|
11487
11476
|
});
|
|
11488
11477
|
program.command("path").description("show the resolved vault path").option("--vault <dir>", "explicit vault override (runtime)").option("--target <dir>", "explicit target override (init-time)").option("--wiki <name>", "wiki profile name").option("--init-time", "use init-time chain instead of runtime", false).option("--explain", "include resolution chain in output", false).option("--plain", "print only the vault path (no JSON wrapper)", false).action(async (opts) => {
|
|
11489
11478
|
const initTime = !!opts.initTime;
|
|
@@ -11491,7 +11480,7 @@ program.command("path").description("show the resolved vault path").option("--va
|
|
|
11491
11480
|
const r = await runPath({
|
|
11492
11481
|
flag,
|
|
11493
11482
|
envValue: process.env.WIKI_PATH,
|
|
11494
|
-
home:
|
|
11483
|
+
home: resolveSkillwikiHome(),
|
|
11495
11484
|
initTime,
|
|
11496
11485
|
wiki: opts.wiki,
|
|
11497
11486
|
cwd: process.cwd(),
|
|
@@ -11509,7 +11498,7 @@ program.command("lang").description("get or set the vault language").option("--l
|
|
|
11509
11498
|
emit(await runLang({
|
|
11510
11499
|
flag: opts.lang,
|
|
11511
11500
|
envValue: process.env.WIKI_LANG,
|
|
11512
|
-
home:
|
|
11501
|
+
home: resolveSkillwikiHome(),
|
|
11513
11502
|
explain: !!opts.explain
|
|
11514
11503
|
}));
|
|
11515
11504
|
});
|
|
@@ -11519,7 +11508,7 @@ program.command("init").description("bootstrap a new vault with SCHEMA.md, index
|
|
|
11519
11508
|
emit(await runInit({
|
|
11520
11509
|
flag: opts.target,
|
|
11521
11510
|
envValue: process.env.WIKI_PATH,
|
|
11522
|
-
home:
|
|
11511
|
+
home: resolveSkillwikiHome(),
|
|
11523
11512
|
templates,
|
|
11524
11513
|
domain: opts.domain,
|
|
11525
11514
|
taxonomy,
|
|
@@ -11537,7 +11526,7 @@ async function resolveVaultArg(arg, wiki) {
|
|
|
11537
11526
|
flag: void 0,
|
|
11538
11527
|
envValue: process.env.WIKI_PATH,
|
|
11539
11528
|
wikiEnv: process.env.WIKI,
|
|
11540
|
-
home:
|
|
11529
|
+
home: resolveSkillwikiHome(),
|
|
11541
11530
|
wiki,
|
|
11542
11531
|
cwd: process.cwd()
|
|
11543
11532
|
});
|
|
@@ -11841,7 +11830,7 @@ program.command("health [vault]").description("bounded whole-system wiki health
|
|
|
11841
11830
|
else emit(await runHealth({
|
|
11842
11831
|
vault: v.vault,
|
|
11843
11832
|
vaultSource: vault ? "flag" : "resolved",
|
|
11844
|
-
home:
|
|
11833
|
+
home: resolveSkillwikiHome(),
|
|
11845
11834
|
envValue: process.env.WIKI_PATH,
|
|
11846
11835
|
argv: process.argv,
|
|
11847
11836
|
currentVersion: pkg.version,
|
|
@@ -11853,12 +11842,12 @@ program.command("health [vault]").description("bounded whole-system wiki health
|
|
|
11853
11842
|
}), void 0, { postCommit: false, humanDetailHints: healthLintDetailHints });
|
|
11854
11843
|
});
|
|
11855
11844
|
var configCmd = program.command("config").description("manage skillwiki configuration");
|
|
11856
|
-
configCmd.command("get <key>").description("print the value of a config key").action(async (key) => emit(await runConfigGet({ key, home:
|
|
11857
|
-
configCmd.command("set <key> <value>").description("set a config key value").action(async (key, value) => emit(await runConfigSet({ key, value, home:
|
|
11858
|
-
configCmd.command("list").option("--profiles", "show wiki profiles summary", false).description("list all config key=value pairs").action(async (opts) => emit(await runConfigList({ home:
|
|
11859
|
-
configCmd.command("path").description("print the config file path").action(async () => emit(await runConfigPath({ home:
|
|
11845
|
+
configCmd.command("get <key>").description("print the value of a config key").action(async (key) => emit(await runConfigGet({ key, home: resolveSkillwikiHome() })));
|
|
11846
|
+
configCmd.command("set <key> <value>").description("set a config key value").action(async (key, value) => emit(await runConfigSet({ key, value, home: resolveSkillwikiHome() })));
|
|
11847
|
+
configCmd.command("list").option("--profiles", "show wiki profiles summary", false).description("list all config key=value pairs").action(async (opts) => emit(await runConfigList({ home: resolveSkillwikiHome(), profiles: !!opts.profiles })));
|
|
11848
|
+
configCmd.command("path").description("print the config file path").action(async () => emit(await runConfigPath({ home: resolveSkillwikiHome() })));
|
|
11860
11849
|
program.command("doctor").description("diagnose skillwiki setup issues").option("--check-snapshotter", "SSH-probe fleet snapshotter (short timeout)", false).option("--check-mcp", "live-handshake HTTP MCP initialize + tools/list (network)", false).action(async (opts) => emit(await runDoctor({
|
|
11861
|
-
home:
|
|
11850
|
+
home: resolveSkillwikiHome(),
|
|
11862
11851
|
envValue: process.env.WIKI_PATH,
|
|
11863
11852
|
argv: process.argv,
|
|
11864
11853
|
currentVersion: pkg.version,
|
|
@@ -11868,7 +11857,7 @@ program.command("doctor").description("diagnose skillwiki setup issues").option(
|
|
|
11868
11857
|
env: process.env
|
|
11869
11858
|
})));
|
|
11870
11859
|
program.command("connect").description(CONNECT_DESCRIPTION).option("--from-file <path>", "chat-attached env file (not Drive / \u4E91\u76D8)").option("--from-stdin", "read env file from stdin (no echo)").option("--dry-run", "validate without writing ~/.skillwiki/.env").option("--force", "overwrite a different existing token").action(async (opts) => emit(await runConnect({
|
|
11871
|
-
home:
|
|
11860
|
+
home: resolveSkillwikiHome(),
|
|
11872
11861
|
fromFile: opts.fromFile,
|
|
11873
11862
|
fromStdin: !!opts.fromStdin,
|
|
11874
11863
|
dryRun: !!opts.dryRun,
|
|
@@ -11882,7 +11871,7 @@ program.command("status [vault]").description("output vault diagnostics").option
|
|
|
11882
11871
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
11883
11872
|
else emit(await runStatus({
|
|
11884
11873
|
vault: v.vault,
|
|
11885
|
-
home:
|
|
11874
|
+
home: resolveSkillwikiHome(),
|
|
11886
11875
|
langEnvValue: process.env.WIKI_LANG
|
|
11887
11876
|
}), v.vault);
|
|
11888
11877
|
});
|
|
@@ -11891,7 +11880,7 @@ program.command("copy-status [vault]").description("plane-tagged vault freshness
|
|
|
11891
11880
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
11892
11881
|
else emit(await runCopyStatusCommand({
|
|
11893
11882
|
vault: v.vault,
|
|
11894
|
-
home:
|
|
11883
|
+
home: resolveSkillwikiHome()
|
|
11895
11884
|
}), v.vault, { postCommit: false });
|
|
11896
11885
|
});
|
|
11897
11886
|
program.command("archive <page> [vault]").description("archive a typed-knowledge or raw page").option("--wiki <name>", "wiki profile name").option("--cascade", "scan vault for references (wikilinks + sources arrays); preview by default", false).option("--apply", "with --cascade: mutate sources arrays and archive (without --apply, --cascade is preview-only)", false).option("--approve <token>", "approve an exact state-bound raw archive plan").option("--remote <remote>", "rclone remote root to prune the archived source path, for example seaweed-wiki:cloud/wiki").option("--remote-delete", "delete the archived source path from the remote after local archive", false).option("--max-remote-deletes <n>", "maximum remote object deletes allowed", "1").action(async (page, vault, opts) => {
|
|
@@ -11998,11 +11987,11 @@ program.command("frontmatter-fix [vault]").description("fix common frontmatter i
|
|
|
11998
11987
|
);
|
|
11999
11988
|
});
|
|
12000
11989
|
program.command("update").description("update skillwiki CLI from npm dist-tag").option("--tag <tag>", "npm dist-tag", "latest").action(async (opts) => emit(await runUpdate({
|
|
12001
|
-
home:
|
|
11990
|
+
home: resolveSkillwikiHome(),
|
|
12002
11991
|
distTag: opts.tag
|
|
12003
11992
|
})));
|
|
12004
11993
|
program.command("self-update").description("update skillwiki CLI from local source or npm dist-tag").option("--check", "check for updates without installing", false).option("--tag <tag>", "npm dist-tag", "latest").action(async (opts) => emit(await runSelfUpdate({
|
|
12005
|
-
home:
|
|
11994
|
+
home: resolveSkillwikiHome(),
|
|
12006
11995
|
check: !!opts.check,
|
|
12007
11996
|
distTag: opts.tag
|
|
12008
11997
|
})));
|
|
@@ -12071,7 +12060,7 @@ syncCmd.command("status [vault]").description("check vault git sync status").opt
|
|
|
12071
12060
|
const v = await resolveVaultArg(vault, opts.wiki);
|
|
12072
12061
|
if (!v.ok) emit({ exitCode: v.exitCode, result: v.payload });
|
|
12073
12062
|
else {
|
|
12074
|
-
const home =
|
|
12063
|
+
const home = resolveSkillwikiHome();
|
|
12075
12064
|
let snapshotterAlias;
|
|
12076
12065
|
if (opts.checkSnapshotter) {
|
|
12077
12066
|
const fleetLoad = await loadFleetManifestAndHost({
|
|
@@ -12205,7 +12194,7 @@ backupCmd.command("sync [vault]").description("sync vault to S3-compatible remot
|
|
|
12205
12194
|
emit({ exitCode: v.exitCode, result: v.payload });
|
|
12206
12195
|
return;
|
|
12207
12196
|
}
|
|
12208
|
-
const home =
|
|
12197
|
+
const home = resolveSkillwikiHome();
|
|
12209
12198
|
const dotenv = await parseDotenvFile(configPath(home));
|
|
12210
12199
|
emit(await runBackupSync({
|
|
12211
12200
|
vault: v.vault,
|
|
@@ -12224,7 +12213,7 @@ backupCmd.command("restore [vault]").description("restore vault from S3-compatib
|
|
|
12224
12213
|
emit({ exitCode: v.exitCode, result: v.payload });
|
|
12225
12214
|
return;
|
|
12226
12215
|
}
|
|
12227
|
-
const home =
|
|
12216
|
+
const home = resolveSkillwikiHome();
|
|
12228
12217
|
const dotenv = await parseDotenvFile(configPath(home));
|
|
12229
12218
|
return emitGuardedVaultWrite(
|
|
12230
12219
|
v.vault,
|
|
@@ -12403,7 +12392,7 @@ fleetCmd.command("context [vault]").description("render compact Runtime Host Con
|
|
|
12403
12392
|
file: opts.file,
|
|
12404
12393
|
hostId: opts.hostId,
|
|
12405
12394
|
env: process.env,
|
|
12406
|
-
home:
|
|
12395
|
+
home: resolveSkillwikiHome(),
|
|
12407
12396
|
cwd: process.cwd(),
|
|
12408
12397
|
osHostname: process.env.HOSTNAME,
|
|
12409
12398
|
user: process.env.USER
|
|
@@ -12416,7 +12405,7 @@ fleetCmd.command("health [vault]").description("read-only health probe for skill
|
|
|
12416
12405
|
hostId: opts.hostId,
|
|
12417
12406
|
json: !!opts.json,
|
|
12418
12407
|
env: process.env,
|
|
12419
|
-
home:
|
|
12408
|
+
home: resolveSkillwikiHome(),
|
|
12420
12409
|
cwd: process.cwd(),
|
|
12421
12410
|
osHostname: process.env.HOSTNAME,
|
|
12422
12411
|
user: process.env.USER
|
|
@@ -12481,10 +12470,10 @@ mcpAuthCmd.command("issue-host").description("append a host-id hash to the metal
|
|
|
12481
12470
|
allowedVaults
|
|
12482
12471
|
}));
|
|
12483
12472
|
});
|
|
12484
|
-
for (const w of getDeprecatedWarnings(
|
|
12473
|
+
for (const w of getDeprecatedWarnings(resolveSkillwikiHome())) {
|
|
12485
12474
|
process.stderr.write(w + "\n");
|
|
12486
12475
|
}
|
|
12487
|
-
triggerAutoUpdate(
|
|
12476
|
+
triggerAutoUpdate(resolveSkillwikiHome(), pkg.version);
|
|
12488
12477
|
program.parseAsync(process.argv).catch((e) => {
|
|
12489
12478
|
process.stdout.write(JSON.stringify({ ok: false, error: "INTERNAL", detail: { message: String(e) } }) + "\n");
|
|
12490
12479
|
process.exit(ExitCode.INTERNAL_ERROR);
|
package/dist/skillwiki-mcp.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
runSkillwikiMcpStdio
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-LDEZQXH6.js";
|
|
5
5
|
import "./chunk-7I2TPIV5.js";
|
|
6
6
|
import "./chunk-DTTKCCQ4.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-FYAKMULW.js";
|
|
8
8
|
import "./chunk-HMHMCPCE.js";
|
|
9
9
|
import "./chunk-QU2IXZRN.js";
|
|
10
10
|
import "./chunk-JCDAEZVD.js";
|
|
@@ -1067,28 +1067,33 @@ snapshot_post_sync_log_append_race_detected() {
|
|
|
1067
1067
|
# delete-intent reconciliation, re-read the current store, and re-run the
|
|
1068
1068
|
# existing exact worktree parity and semantic preview gates. Returns 0 only when
|
|
1069
1069
|
# the recovery converged; the caller refuses (without a second retry) otherwise.
|
|
1070
|
-
|
|
1070
|
+
# reason is log-append (store log is a strict prefix extension) or
|
|
1071
|
+
# semantic-preview (worktree matches store but preview reports index/log drift).
|
|
1072
|
+
snapshot_retry_sync_after_projection_race() {
|
|
1071
1073
|
local context="${1:-post-sync}"
|
|
1074
|
+
local reason="${2:-log-append}"
|
|
1072
1075
|
if ! rclone sync "$CLOUD_REMOTE" "$SNAPSHOT_WORKTREE" "${RCLONE_OPTS[@]}" --stats 10s 2>&1 | tee "$RCLONE_LOG"; then
|
|
1073
|
-
log "ERROR: $context
|
|
1076
|
+
log "ERROR: $context $reason race retry rclone sync failed"
|
|
1074
1077
|
tail -50 "$RCLONE_LOG" >> "$LOG_FILE" 2>/dev/null || true
|
|
1075
1078
|
rm -f "$RCLONE_LOG"
|
|
1076
1079
|
return 1
|
|
1077
1080
|
fi
|
|
1078
1081
|
rm -f "$RCLONE_LOG"
|
|
1079
|
-
log "post-sync
|
|
1082
|
+
log "post-sync $reason race detected; performed one additional rclone sync context=$context"
|
|
1080
1083
|
if ! snapshot_reconcile_delete_intents; then
|
|
1081
|
-
log "ERROR: $context
|
|
1084
|
+
log "ERROR: $context $reason race retry delete-intent reconciliation failed"
|
|
1082
1085
|
return 1
|
|
1083
1086
|
fi
|
|
1084
1087
|
snapshot_gate_projection_candidate \
|
|
1085
|
-
"FAIL $context
|
|
1086
|
-
"FAIL $context
|
|
1088
|
+
"FAIL $context $reason race retry projection expectation refresh; snapshot promotion refused" \
|
|
1089
|
+
"FAIL $context $reason race retry projection candidate verification; snapshot promotion refused"
|
|
1087
1090
|
}
|
|
1088
1091
|
|
|
1089
|
-
# Post-sync projection gate with at most one
|
|
1090
|
-
#
|
|
1091
|
-
#
|
|
1092
|
+
# Post-sync projection gate with at most one recoverable-race re-sync.
|
|
1093
|
+
# Recoverable shapes are a store-ahead log append, or exact worktree==store
|
|
1094
|
+
# byte parity whose semantic preview still reports index/log drift (a late
|
|
1095
|
+
# typed page whose matching index.md has not landed yet). Any other mismatch,
|
|
1096
|
+
# or a retry that does not converge, is the terminal refusal.
|
|
1092
1097
|
snapshot_gate_projection_candidate_with_race_retry() {
|
|
1093
1098
|
local context="${1:-post-sync}"
|
|
1094
1099
|
local refresh_fail="$2"
|
|
@@ -1097,14 +1102,17 @@ snapshot_gate_projection_candidate_with_race_retry() {
|
|
|
1097
1102
|
log "$refresh_fail"
|
|
1098
1103
|
return 1
|
|
1099
1104
|
fi
|
|
1100
|
-
# Exact byte parity is the ordinary path. Its semantic preview is terminal:
|
|
1101
|
-
# a later append must not turn a preview failure into a retry.
|
|
1102
1105
|
if [ -z "$PROJECTION_STATE_DIR" ] \
|
|
1103
1106
|
|| { cmp -s "$PROJECTION_STATE_DIR/expected-index.md" "$SNAPSHOT_WORKTREE/index.md" \
|
|
1104
1107
|
&& cmp -s "$PROJECTION_STATE_DIR/expected-log.md" "$SNAPSHOT_WORKTREE/log.md"; }; then
|
|
1105
1108
|
if snapshot_verify_projection_candidate; then
|
|
1106
1109
|
return 0
|
|
1107
1110
|
fi
|
|
1111
|
+
# Exact byte parity with a drifting preview is the page-vs-index race:
|
|
1112
|
+
# retry once. A later append must not get a second retry after this.
|
|
1113
|
+
if snapshot_retry_sync_after_projection_race "$context" "semantic-preview"; then
|
|
1114
|
+
return 0
|
|
1115
|
+
fi
|
|
1108
1116
|
log "$verify_fail"
|
|
1109
1117
|
return 1
|
|
1110
1118
|
fi
|
|
@@ -1113,7 +1121,7 @@ snapshot_gate_projection_candidate_with_race_retry() {
|
|
|
1113
1121
|
log "$verify_fail"
|
|
1114
1122
|
return 1
|
|
1115
1123
|
fi
|
|
1116
|
-
if
|
|
1124
|
+
if snapshot_retry_sync_after_projection_race "$context" "log-append"; then
|
|
1117
1125
|
return 0
|
|
1118
1126
|
fi
|
|
1119
1127
|
log "$verify_fail"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.109",
|
|
4
4
|
"skills": "./",
|
|
5
5
|
"description": "Project-aware Karpathy-style knowledge base for Claude Code: 22 prompt-only skills (wiki-*, proj-*, using-skillwiki, skillwiki-mcp, skillwiki-connect) backed by the deterministic `skillwiki` CLI.",
|
|
6
6
|
"author": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "skillwiki",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.109",
|
|
4
4
|
"description": "Project-aware Karpathy-style knowledge base: 22 prompt-only skills (wiki-*, proj-*, using-skillwiki, skillwiki-mcp, skillwiki-connect) backed by HTTP MCP wiki_capture.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "karlorz"
|
package/skills/package.json
CHANGED
|
@@ -68,6 +68,14 @@ skillwiki connect --from-stdin --dry-run
|
|
|
68
68
|
|
|
69
69
|
Doctor on an MCP-only leaf (no vault + token present + vault-sync not installed) treats missing `WIKI_PATH` as info, not an init cluster.
|
|
70
70
|
|
|
71
|
+
## Windows MCP-only leaves
|
|
72
|
+
|
|
73
|
+
- Do not configure an optional Git mirror as `WIKI_PATH`: CLI `skillwiki query` reads that local mirror, not HTTP MCP. Use the advertised `wiki_query` tool for live reads and `wiki_context` for active work.
|
|
74
|
+
- User config home resolves from a nonblank explicit home, then `HOME`, `USERPROFILE`, and the OS home directory. Empty or unset `HOME` does not require persisting a workaround environment variable. `skillwiki config path` and doctor's config-file row show the resolved absolute path.
|
|
75
|
+
- If the npm-generated PowerShell launcher fails or interrupts a command sequence, use `skillwiki.cmd config path` and `skillwiki.cmd doctor --check-mcp`, or invoke the installed `dist/cli.js` with Node. Do not edit generated shims or infer a SkillWiki defect without inspecting the failing wrapper.
|
|
76
|
+
- POSIX mode `0600` is not proof of a restrictive Windows ACL. The operator must keep the user config private. If a harness blocks attachment/stdin credential transfer, stop and request operator-controlled configuration of that resolved file with restricted access; never automatically bypass the harness, print the token, or store it in a repo or Drive.
|
|
77
|
+
- Record CLI/plugin/daemon versions separately when investigating drift. A scheduled notifier is not evidence that an upgrade completed; use an explicit operator-approved upgrade and restart the client when delivery includes installation changes.
|
|
78
|
+
|
|
71
79
|
## Stop conditions
|
|
72
80
|
|
|
73
81
|
- A non-local-only SkillWiki connector already authenticates.
|
|
@@ -45,10 +45,18 @@ Check the successful write receipt's `vault_id` against the intended vault befor
|
|
|
45
45
|
|
|
46
46
|
## Reads
|
|
47
47
|
|
|
48
|
+
CLI `skillwiki query` reads a local configured vault; it does not forward to HTTP MCP. On an MCP-only leaf, leave `WIKI_PATH` unset and use the advertised MCP `wiki_query` for live reads. Optional Git mirrors are read-only snapshots and may lag the live writer.
|
|
49
|
+
|
|
48
50
|
Local `~/wiki` (or `skillwiki path`) is fine for reads. MCP read tools are optional. Prefer ordinary file reads of the local mirror. Frozen-leaf agents should use HTTP `wiki_sources_pending`, `wiki_lint_summary`, `wiki_stale`, `wiki_compile_status`, and `wiki_reviews` instead of local CLI commands when those tools are advertised.
|
|
49
51
|
|
|
50
52
|
`wiki_query` is typed knowledge only unless `scope` is `work` or `all`. For recent progress, key projects, or to-dos, feature-detect and call `wiki_progress`; apply `project`, `host`, or `agent_role` filters when requested, and present `recent_progress`, `key_projects`, and `todos` as complete bullet lists. For queued work, doctor, plugin-drift, or MCP diagnose questions, call `wiki_context` first (active_work) or pass `scope: "work"` / `"all"`. Do not treat a top typed packet hit as the live work queue.
|
|
51
53
|
|
|
54
|
+
## Bridge diagnostics
|
|
55
|
+
|
|
56
|
+
Use a protocol SDK rather than copying a one-line SSE parser. SkillWiki diagnostic clients use the existing MCP TypeScript SDK to validate initialization, negotiate the protocol, send `notifications/initialized`, carry optional session IDs and negotiated protocol headers, and parse JSON or SSE (including multiline data). Empty HTTP 202 bodies acknowledge notifications/responses, not a successful initialize result. Doctor/connect probes have a 10-second overall deadline per connection and close their transports without terminating the server session.
|
|
57
|
+
|
|
58
|
+
Treat a missing/invalid initialize result, authentication refusal, or timeout as a failed handshake; do not proceed to tools calls merely because the HTTP status is successful. Preserve bearer redaction in all diagnostics.
|
|
59
|
+
|
|
52
60
|
## Errors
|
|
53
61
|
|
|
54
62
|
Report handshake, capture, and append failures literally. If tools are missing after a 401 or `missing_prereq`, stop and tell the operator to set `SKILLWIKI_MCP_TOKEN` via process env, host Configure, or `skillwiki connect --from-file` (unknown agents; never paste-into-chat), run `grok plugin update skillwiki`, and start a new session. Over SSH, treat an OAuth login URL the same way: report `headless_oauth_loopback` and stop. Do not fall back to local `raw/transcripts/` writes.
|
|
@@ -68,6 +68,14 @@ skillwiki connect --from-stdin --dry-run
|
|
|
68
68
|
|
|
69
69
|
Doctor on an MCP-only leaf (no vault + token present + vault-sync not installed) treats missing `WIKI_PATH` as info, not an init cluster.
|
|
70
70
|
|
|
71
|
+
## Windows MCP-only leaves
|
|
72
|
+
|
|
73
|
+
- Do not configure an optional Git mirror as `WIKI_PATH`: CLI `skillwiki query` reads that local mirror, not HTTP MCP. Use the advertised `wiki_query` tool for live reads and `wiki_context` for active work.
|
|
74
|
+
- User config home resolves from a nonblank explicit home, then `HOME`, `USERPROFILE`, and the OS home directory. Empty or unset `HOME` does not require persisting a workaround environment variable. `skillwiki config path` and doctor's config-file row show the resolved absolute path.
|
|
75
|
+
- If the npm-generated PowerShell launcher fails or interrupts a command sequence, use `skillwiki.cmd config path` and `skillwiki.cmd doctor --check-mcp`, or invoke the installed `dist/cli.js` with Node. Do not edit generated shims or infer a SkillWiki defect without inspecting the failing wrapper.
|
|
76
|
+
- POSIX mode `0600` is not proof of a restrictive Windows ACL. The operator must keep the user config private. If a harness blocks attachment/stdin credential transfer, stop and request operator-controlled configuration of that resolved file with restricted access; never automatically bypass the harness, print the token, or store it in a repo or Drive.
|
|
77
|
+
- Record CLI/plugin/daemon versions separately when investigating drift. A scheduled notifier is not evidence that an upgrade completed; use an explicit operator-approved upgrade and restart the client when delivery includes installation changes.
|
|
78
|
+
|
|
71
79
|
## Stop conditions
|
|
72
80
|
|
|
73
81
|
- A non-local-only SkillWiki connector already authenticates.
|
|
@@ -45,10 +45,18 @@ Check the successful write receipt's `vault_id` against the intended vault befor
|
|
|
45
45
|
|
|
46
46
|
## Reads
|
|
47
47
|
|
|
48
|
+
CLI `skillwiki query` reads a local configured vault; it does not forward to HTTP MCP. On an MCP-only leaf, leave `WIKI_PATH` unset and use the advertised MCP `wiki_query` for live reads. Optional Git mirrors are read-only snapshots and may lag the live writer.
|
|
49
|
+
|
|
48
50
|
Local `~/wiki` (or `skillwiki path`) is fine for reads. MCP read tools are optional. Prefer ordinary file reads of the local mirror. Frozen-leaf agents should use HTTP `wiki_sources_pending`, `wiki_lint_summary`, `wiki_stale`, `wiki_compile_status`, and `wiki_reviews` instead of local CLI commands when those tools are advertised.
|
|
49
51
|
|
|
50
52
|
`wiki_query` is typed knowledge only unless `scope` is `work` or `all`. For recent progress, key projects, or to-dos, feature-detect and call `wiki_progress`; apply `project`, `host`, or `agent_role` filters when requested, and present `recent_progress`, `key_projects`, and `todos` as complete bullet lists. For queued work, doctor, plugin-drift, or MCP diagnose questions, call `wiki_context` first (active_work) or pass `scope: "work"` / `"all"`. Do not treat a top typed packet hit as the live work queue.
|
|
51
53
|
|
|
54
|
+
## Bridge diagnostics
|
|
55
|
+
|
|
56
|
+
Use a protocol SDK rather than copying a one-line SSE parser. SkillWiki diagnostic clients use the existing MCP TypeScript SDK to validate initialization, negotiate the protocol, send `notifications/initialized`, carry optional session IDs and negotiated protocol headers, and parse JSON or SSE (including multiline data). Empty HTTP 202 bodies acknowledge notifications/responses, not a successful initialize result. Doctor/connect probes have a 10-second overall deadline per connection and close their transports without terminating the server session.
|
|
57
|
+
|
|
58
|
+
Treat a missing/invalid initialize result, authentication refusal, or timeout as a failed handshake; do not proceed to tools calls merely because the HTTP status is successful. Preserve bearer redaction in all diagnostics.
|
|
59
|
+
|
|
52
60
|
## Errors
|
|
53
61
|
|
|
54
62
|
Report handshake, capture, and append failures literally. If tools are missing after a 401 or `missing_prereq`, stop and tell the operator to set `SKILLWIKI_MCP_TOKEN` via process env, host Configure, or `skillwiki connect --from-file` (unknown agents; never paste-into-chat), run `grok plugin update skillwiki`, and start a new session. Over SSH, treat an OAuth login URL the same way: report `headless_oauth_loopback` and stop. Do not fall back to local `raw/transcripts/` writes.
|