skillwiki 0.10.111 → 0.10.112
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-TDBUJUYH.js → chunk-25OXNFDV.js} +42 -18
- package/dist/{chunk-6OQLBNKR.js → chunk-ABRYBO4T.js} +29 -4
- package/dist/{chunk-OJJBZDPR.js → chunk-APKDTEVV.js} +178 -210
- package/dist/{chunk-5IBLXGLY.js → chunk-CKQPUHM2.js} +2 -2
- package/dist/chunk-DOHWNPAZ.js +60 -0
- package/dist/{chunk-GQWCTJTU.js → chunk-EE7W3GLA.js} +1 -1
- package/dist/{chunk-KWEYA3OE.js → chunk-FCA3RRNF.js} +1 -1
- package/dist/{chunk-MRPJ7X7W.js → chunk-IR2DI4Y5.js} +3 -3
- package/dist/chunk-K3M6OSUW.js +77 -0
- package/dist/{chunk-I6IRJCUJ.js → chunk-KJG2CSYD.js} +2 -2
- package/dist/chunk-LOVLZNLX.js +111 -0
- package/dist/{chunk-HBJLFPQP.js → chunk-Q6EZF37H.js} +8 -8
- package/dist/{chunk-JQV5KNPT.js → chunk-RR6VDWSI.js} +3 -3
- package/dist/{chunk-PYPPG7RF.js → chunk-SKOLE6US.js} +1 -1
- package/dist/{chunk-X5GL2FCU.js → chunk-TKX6PSWZ.js} +1 -1
- package/dist/cli.js +77 -33
- package/dist/{index-projection-2K672CBO.js → index-projection-UNZG5UJZ.js} +5 -5
- package/dist/{journal-QU5IDXQF.js → journal-5IW3TZ5F.js} +3 -3
- package/dist/{managed-write-preflight-GRSHQYKC.js → managed-write-preflight-L7IRQ76C.js} +7 -7
- package/dist/mcp-auth-env-X5MI5IX6.js +25 -0
- package/dist/{migrate-PIB4QA54.js → migrate-RO4BJP5T.js} +6 -5
- package/dist/mirror-H5BTBAON.js +151 -0
- package/dist/runtime-VMFYW2K3.js +20 -0
- package/dist/skillwiki-mcp.js +14 -12
- package/dist/sources-AOYP6ROO.js +10 -0
- package/dist/{watcher-MHG46J3R.js → watcher-MGHQD3UI.js} +20 -110
- 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/using-skillwiki/SKILL.md +1 -1
- package/skills/skills/wiki-init/SKILL.md +3 -0
- package/skills/using-skillwiki/SKILL.md +1 -1
- package/skills/wiki-init/SKILL.md +3 -0
- package/templates/launchd/com.karlchow.skillwiki-mirror-sse.plist +20 -0
- package/dist/chunk-I2J3IJB7.js +0 -54
- package/dist/runtime-GLMI5OCT.js +0 -15
- package/dist/sources-D2MGP246.js +0 -10
- package/dist/{chunk-UIEQIJXP.js → chunk-7POLZOFY.js} +42 -42
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
readPage,
|
|
5
5
|
scanSensitiveContent,
|
|
6
6
|
splitFrontmatter
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-TKX6PSWZ.js";
|
|
8
8
|
import {
|
|
9
9
|
err,
|
|
10
10
|
ok
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-7POLZOFY.js";
|
|
12
12
|
|
|
13
13
|
// src/utils/vault-path-safety.ts
|
|
14
14
|
import { lstatSync, realpathSync } from "fs";
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
parseDotenvFile,
|
|
4
|
+
resolveSkillwikiHome
|
|
5
|
+
} from "./chunk-SKOLE6US.js";
|
|
6
|
+
|
|
7
|
+
// src/utils/mcp-auth-env.ts
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
var MCP_URL_ENV = "SKILLWIKI_MCP_URL";
|
|
10
|
+
var MCP_TOKEN_ENV = "SKILLWIKI_MCP_TOKEN";
|
|
11
|
+
var MCP_HOST_ID_ENV = "SKILLWIKI_HOST_ID";
|
|
12
|
+
function nonEmptyEnvValue(value) {
|
|
13
|
+
if (typeof value !== "string") return void 0;
|
|
14
|
+
const trimmed = value.trim();
|
|
15
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
16
|
+
}
|
|
17
|
+
function mcpAuthFromEnv(env) {
|
|
18
|
+
return {
|
|
19
|
+
url: nonEmptyEnvValue(env[MCP_URL_ENV]),
|
|
20
|
+
token: nonEmptyEnvValue(env[MCP_TOKEN_ENV]),
|
|
21
|
+
hostId: nonEmptyEnvValue(env[MCP_HOST_ID_ENV])
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
async function resolveMcpAuthEnv(input) {
|
|
25
|
+
const processAuth = mcpAuthFromEnv(input.env ?? process.env);
|
|
26
|
+
const dotenv = await parseDotenvFile(join(resolveSkillwikiHome(input.home, input.env), ".skillwiki", ".env"));
|
|
27
|
+
const fileAuth = mcpAuthFromEnv(dotenv);
|
|
28
|
+
return {
|
|
29
|
+
url: processAuth.url ?? fileAuth.url,
|
|
30
|
+
token: processAuth.token ?? fileAuth.token,
|
|
31
|
+
hostId: processAuth.hostId ?? fileAuth.hostId
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
async function mergeMcpAuthIntoEnv(home, env) {
|
|
35
|
+
const auth = await resolveMcpAuthEnv({ home, env });
|
|
36
|
+
const merged = { ...env };
|
|
37
|
+
if (auth.url && !nonEmptyEnvValue(env[MCP_URL_ENV])) merged[MCP_URL_ENV] = auth.url;
|
|
38
|
+
if (auth.token && !nonEmptyEnvValue(env[MCP_TOKEN_ENV])) merged[MCP_TOKEN_ENV] = auth.token;
|
|
39
|
+
if (auth.hostId && !nonEmptyEnvValue(env[MCP_HOST_ID_ENV])) merged[MCP_HOST_ID_ENV] = auth.hostId;
|
|
40
|
+
return merged;
|
|
41
|
+
}
|
|
42
|
+
function redactMcpSecret(text, secret) {
|
|
43
|
+
if (!secret || secret.length === 0 || !text.includes(secret)) return text;
|
|
44
|
+
return text.split(secret).join("[REDACTED]");
|
|
45
|
+
}
|
|
46
|
+
function isMcpOnlyLeaf(input) {
|
|
47
|
+
return !input.resolvedPath && Boolean(input.token) && !input.vaultSyncInstalled;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
MCP_URL_ENV,
|
|
52
|
+
MCP_TOKEN_ENV,
|
|
53
|
+
MCP_HOST_ID_ENV,
|
|
54
|
+
nonEmptyEnvValue,
|
|
55
|
+
mcpAuthFromEnv,
|
|
56
|
+
resolveMcpAuthEnv,
|
|
57
|
+
mergeMcpAuthIntoEnv,
|
|
58
|
+
redactMcpSecret,
|
|
59
|
+
isMcpOnlyLeaf
|
|
60
|
+
};
|
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
import {
|
|
3
3
|
ROOT_INDEX_SECTION_ORDER,
|
|
4
4
|
buildRootIndexUniverse
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-KJG2CSYD.js";
|
|
6
6
|
import {
|
|
7
7
|
atomicWriteText
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-EE7W3GLA.js";
|
|
9
9
|
import {
|
|
10
10
|
err,
|
|
11
11
|
ok
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-7POLZOFY.js";
|
|
13
13
|
|
|
14
14
|
// src/utils/index-projection.ts
|
|
15
15
|
import { readFile } from "fs/promises";
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/clip-outbox/files.ts
|
|
4
|
+
import { constants } from "fs";
|
|
5
|
+
import { lstat, mkdir, open, realpath } from "fs/promises";
|
|
6
|
+
import { dirname, isAbsolute, relative, resolve, sep } from "path";
|
|
7
|
+
async function readRegular(root, path, maxBytes) {
|
|
8
|
+
const rel = relative(root, path);
|
|
9
|
+
if (!rel || rel.startsWith(`..${sep}`) || rel === ".." || isAbsolute(rel)) throw new Error("unsafe input path");
|
|
10
|
+
let current = resolve(root);
|
|
11
|
+
for (const part of ["", ...rel.split(sep)]) {
|
|
12
|
+
current = resolve(current, part);
|
|
13
|
+
const st = await lstat(current);
|
|
14
|
+
if (st.isSymbolicLink()) throw new Error("symlink input refused");
|
|
15
|
+
if (current !== path && !st.isDirectory()) throw new Error("invalid input parent");
|
|
16
|
+
}
|
|
17
|
+
const handle = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
18
|
+
try {
|
|
19
|
+
const before = await handle.stat();
|
|
20
|
+
if (!before.isFile() || before.size > maxBytes) throw new Error("input type or size refused");
|
|
21
|
+
const bytes = Buffer.alloc(before.size + 1);
|
|
22
|
+
let bytesRead = 0;
|
|
23
|
+
while (bytesRead < bytes.length) {
|
|
24
|
+
const chunk = await handle.read(bytes, bytesRead, bytes.length - bytesRead, bytesRead);
|
|
25
|
+
if (chunk.bytesRead === 0) break;
|
|
26
|
+
bytesRead += chunk.bytesRead;
|
|
27
|
+
}
|
|
28
|
+
const after = await handle.stat();
|
|
29
|
+
if (await realpath(path) !== path) throw new Error("input path changed during read");
|
|
30
|
+
const leaf = await lstat(path);
|
|
31
|
+
if (leaf.ino !== before.ino || leaf.dev !== before.dev) throw new Error("input identity changed during read");
|
|
32
|
+
if (bytesRead !== before.size || after.size !== before.size || after.mtimeMs !== before.mtimeMs) throw new Error("input changed during read");
|
|
33
|
+
return bytes.subarray(0, bytesRead);
|
|
34
|
+
} finally {
|
|
35
|
+
await handle.close();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async function writeRegularExclusive(root, rel, body) {
|
|
39
|
+
const dest = resolve(root, ...rel.split("/"));
|
|
40
|
+
const checked = relative(root, dest);
|
|
41
|
+
if (!checked || checked.startsWith(`..${sep}`) || checked === ".." || isAbsolute(checked)) throw new Error("unsafe dest path");
|
|
42
|
+
let current = resolve(root);
|
|
43
|
+
const parts = checked.split(sep);
|
|
44
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
45
|
+
current = resolve(current, parts[i]);
|
|
46
|
+
try {
|
|
47
|
+
const st = await lstat(current);
|
|
48
|
+
if (st.isSymbolicLink()) throw new Error("symlink dest refused");
|
|
49
|
+
if (!st.isDirectory()) throw new Error("invalid dest parent");
|
|
50
|
+
} catch (error) {
|
|
51
|
+
if (error.code !== "ENOENT") throw error;
|
|
52
|
+
await mkdir(current);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const leaf = resolve(current, parts[parts.length - 1]);
|
|
56
|
+
if (dirname(leaf) !== current) throw new Error("unsafe dest path");
|
|
57
|
+
try {
|
|
58
|
+
const handle = await open(leaf, constants.O_WRONLY | constants.O_CREAT | constants.O_EXCL | constants.O_NOFOLLOW, 420);
|
|
59
|
+
try {
|
|
60
|
+
await handle.writeFile(body);
|
|
61
|
+
} finally {
|
|
62
|
+
await handle.close();
|
|
63
|
+
}
|
|
64
|
+
return "created";
|
|
65
|
+
} catch (error) {
|
|
66
|
+
if (error.code !== "EEXIST") throw error;
|
|
67
|
+
const st = await lstat(leaf);
|
|
68
|
+
if (st.isSymbolicLink() || !st.isFile() || st.size !== body.length) return "conflict";
|
|
69
|
+
const existing = await readRegular(root, leaf, body.length);
|
|
70
|
+
return existing.equals(body) ? "idempotent" : "conflict";
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export {
|
|
75
|
+
readRegular,
|
|
76
|
+
writeRegularExclusive
|
|
77
|
+
};
|
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
extractFrontmatter,
|
|
4
4
|
scanSensitiveContent,
|
|
5
5
|
scanVault
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-TKX6PSWZ.js";
|
|
7
7
|
import {
|
|
8
8
|
MetaSchema,
|
|
9
9
|
TypedKnowledgeSchema,
|
|
10
10
|
detectSchema,
|
|
11
11
|
err,
|
|
12
12
|
ok
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-7POLZOFY.js";
|
|
14
14
|
|
|
15
15
|
// src/utils/index-universe.ts
|
|
16
16
|
import { readFile } from "fs/promises";
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
ExitCode,
|
|
4
|
+
err,
|
|
5
|
+
ipv4InCidr,
|
|
6
|
+
isBlockedHost,
|
|
7
|
+
ok
|
|
8
|
+
} from "./chunk-7POLZOFY.js";
|
|
9
|
+
|
|
10
|
+
// src/commands/fetch-guard.ts
|
|
11
|
+
var REDACT_PARAMS = /* @__PURE__ */ new Set(["api_key", "token", "key", "auth", "password", "secret", "access_token"]);
|
|
12
|
+
var PATH_TOKEN_RE = /[A-Fa-f0-9]{32,}|[A-Za-z0-9_\-]{40,}/g;
|
|
13
|
+
function runFetchGuard(input) {
|
|
14
|
+
return Promise.resolve(runFetchGuardSync(input));
|
|
15
|
+
}
|
|
16
|
+
function runFetchGuardSync(input) {
|
|
17
|
+
let u;
|
|
18
|
+
try {
|
|
19
|
+
u = new URL(input.url);
|
|
20
|
+
} catch {
|
|
21
|
+
return { exitCode: ExitCode.MALFORMED_URL, result: err("MALFORMED_URL", { url: input.url }) };
|
|
22
|
+
}
|
|
23
|
+
const sanitized = sanitizeUrl(u);
|
|
24
|
+
if (u.protocol !== "https:") {
|
|
25
|
+
return {
|
|
26
|
+
exitCode: ExitCode.SCHEME_REJECTED,
|
|
27
|
+
result: err("SCHEME_REJECTED", { sanitized_url: sanitized, scheme: u.protocol })
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
if (isBlockedHost(u.hostname)) {
|
|
31
|
+
return {
|
|
32
|
+
exitCode: ExitCode.HOST_BLOCKED,
|
|
33
|
+
result: err("HOST_BLOCKED", { sanitized_url: sanitized, host: u.hostname })
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return { exitCode: ExitCode.OK, result: ok({ allowed: true, sanitized_url: sanitized, humanHint: `ALLOWED: ${sanitized}` }) };
|
|
37
|
+
}
|
|
38
|
+
function sanitizeUrl(u) {
|
|
39
|
+
const clone = new URL(u.toString());
|
|
40
|
+
if (clone.username || clone.password) {
|
|
41
|
+
clone.username = "";
|
|
42
|
+
clone.password = "";
|
|
43
|
+
}
|
|
44
|
+
for (const k of Array.from(clone.searchParams.keys())) {
|
|
45
|
+
if (REDACT_PARAMS.has(k.toLowerCase())) clone.searchParams.set(k, "REDACTED");
|
|
46
|
+
}
|
|
47
|
+
let s = clone.toString();
|
|
48
|
+
s = s.replace(PATH_TOKEN_RE, "REDACTED");
|
|
49
|
+
return s;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/clip-outbox/ssrf.ts
|
|
53
|
+
import { isIP } from "net";
|
|
54
|
+
import { lookup as dnsLookup } from "dns/promises";
|
|
55
|
+
var extraBlockedV4 = [
|
|
56
|
+
["0.0.0.0", 8],
|
|
57
|
+
["100.64.0.0", 10],
|
|
58
|
+
["192.0.2.0", 24],
|
|
59
|
+
["198.18.0.0", 15],
|
|
60
|
+
["198.51.100.0", 24],
|
|
61
|
+
["203.0.113.0", 24],
|
|
62
|
+
["224.0.0.0", 4],
|
|
63
|
+
["240.0.0.0", 4]
|
|
64
|
+
];
|
|
65
|
+
function isBlockedAddress(address) {
|
|
66
|
+
if (isBlockedHost(address)) return true;
|
|
67
|
+
const version = isIP(address);
|
|
68
|
+
if (version === 4) {
|
|
69
|
+
return extraBlockedV4.some(([base, prefix]) => ipv4InCidr(address, base, prefix));
|
|
70
|
+
}
|
|
71
|
+
if (version === 6) {
|
|
72
|
+
const lower = address.toLowerCase();
|
|
73
|
+
return lower === "::" || lower === "::1" || lower.startsWith("fc") || lower.startsWith("fd") || lower.startsWith("fe80:");
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
async function assertPublicHttpsUrl(url, lookup = defaultLookup) {
|
|
78
|
+
const guard = runFetchGuardSync({ url });
|
|
79
|
+
if (!guard.result.ok) {
|
|
80
|
+
return { ok: false, reason: guard.result.error };
|
|
81
|
+
}
|
|
82
|
+
let parsed;
|
|
83
|
+
try {
|
|
84
|
+
parsed = new URL(url);
|
|
85
|
+
} catch {
|
|
86
|
+
return { ok: false, reason: "MALFORMED_URL" };
|
|
87
|
+
}
|
|
88
|
+
if (isBlockedAddress(parsed.hostname)) {
|
|
89
|
+
return { ok: false, reason: "HOST_BLOCKED" };
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
const addresses = await lookup(parsed.hostname);
|
|
93
|
+
if (addresses.length === 0) return { ok: false, reason: "DNS_EMPTY" };
|
|
94
|
+
if (addresses.some(isBlockedAddress)) return { ok: false, reason: "HOST_BLOCKED" };
|
|
95
|
+
} catch {
|
|
96
|
+
return { ok: false, reason: "DNS_FAILED" };
|
|
97
|
+
}
|
|
98
|
+
return { ok: true, href: parsed.href };
|
|
99
|
+
}
|
|
100
|
+
async function defaultLookup(hostname) {
|
|
101
|
+
if (isIP(hostname)) return [hostname];
|
|
102
|
+
const v4 = await dnsLookup(hostname, { all: true, verbatim: true });
|
|
103
|
+
return v4.map((row) => row.address);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export {
|
|
107
|
+
runFetchGuard,
|
|
108
|
+
runFetchGuardSync,
|
|
109
|
+
assertPublicHttpsUrl,
|
|
110
|
+
defaultLookup
|
|
111
|
+
};
|
|
@@ -18,10 +18,10 @@ import {
|
|
|
18
18
|
resolveExistingRegularFileInsideVault,
|
|
19
19
|
stripFencedBlocks,
|
|
20
20
|
writeLogEvent
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-CKQPUHM2.js";
|
|
22
22
|
import {
|
|
23
23
|
buildRootIndexUniverse
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-KJG2CSYD.js";
|
|
25
25
|
import {
|
|
26
26
|
extractFrontmatter,
|
|
27
27
|
filterGitIgnoredRelativePaths,
|
|
@@ -34,23 +34,23 @@ import {
|
|
|
34
34
|
scanVault,
|
|
35
35
|
splitFrontmatter,
|
|
36
36
|
vaultIoConcurrency
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-TKX6PSWZ.js";
|
|
38
|
+
import {
|
|
39
|
+
atomicWriteText
|
|
40
|
+
} from "./chunk-EE7W3GLA.js";
|
|
38
41
|
import {
|
|
39
42
|
parseDotenvFile,
|
|
40
43
|
parseDotenvText,
|
|
41
44
|
profileKey,
|
|
42
45
|
resolveSkillwikiHome
|
|
43
|
-
} from "./chunk-
|
|
44
|
-
import {
|
|
45
|
-
atomicWriteText
|
|
46
|
-
} from "./chunk-GQWCTJTU.js";
|
|
46
|
+
} from "./chunk-SKOLE6US.js";
|
|
47
47
|
import {
|
|
48
48
|
ExitCode,
|
|
49
49
|
FleetManifestSchema,
|
|
50
50
|
err,
|
|
51
51
|
getErrorMessage,
|
|
52
52
|
ok
|
|
53
|
-
} from "./chunk-
|
|
53
|
+
} from "./chunk-7POLZOFY.js";
|
|
54
54
|
|
|
55
55
|
// src/utils/managed-write-preflight.ts
|
|
56
56
|
import { existsSync as existsSync11 } from "fs";
|
|
@@ -8,20 +8,20 @@ import {
|
|
|
8
8
|
readLogEvents,
|
|
9
9
|
resolveExistingRegularFileInsideVault,
|
|
10
10
|
writeLogEvent
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-CKQPUHM2.js";
|
|
12
12
|
import {
|
|
13
13
|
extractFrontmatter,
|
|
14
14
|
readPage,
|
|
15
15
|
scanSensitiveContent,
|
|
16
16
|
scanVault,
|
|
17
17
|
splitFrontmatter
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-TKX6PSWZ.js";
|
|
19
19
|
import {
|
|
20
20
|
ExitCode,
|
|
21
21
|
RawSourceSchema,
|
|
22
22
|
err,
|
|
23
23
|
ok
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-7POLZOFY.js";
|
|
25
25
|
|
|
26
26
|
// src/commands/sources.ts
|
|
27
27
|
import { readFile as readFile4 } from "fs/promises";
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
runFetchGuard,
|
|
4
|
-
runFetchGuardSync
|
|
5
|
-
} from "./chunk-I2J3IJB7.js";
|
|
6
2
|
import {
|
|
7
3
|
buildDeleteIntent,
|
|
8
4
|
normalizeVaultRelPath,
|
|
@@ -16,9 +12,6 @@ import {
|
|
|
16
12
|
DEFAULT_MCP_URL,
|
|
17
13
|
DEFAULT_NO_DECISION_STREAK,
|
|
18
14
|
GateError,
|
|
19
|
-
MCP_HOST_ID_ENV,
|
|
20
|
-
MCP_TOKEN_ENV,
|
|
21
|
-
MCP_URL_ENV,
|
|
22
15
|
PUSH_NOT_IN_PROFILE,
|
|
23
16
|
SATELLITE_STALE_MS,
|
|
24
17
|
buildVectorIndex,
|
|
@@ -31,17 +24,13 @@ import {
|
|
|
31
24
|
guardProtectedVaultWrite,
|
|
32
25
|
isEventLedgerPath,
|
|
33
26
|
isFailedRunStatus,
|
|
34
|
-
mcpAuthFromEnv,
|
|
35
27
|
measureDirtyVolume,
|
|
36
28
|
memoryAuthorityTiersRank,
|
|
37
|
-
mergeMcpAuthIntoEnv,
|
|
38
|
-
nonEmptyEnvValue,
|
|
39
29
|
pruneVectorIndex,
|
|
40
30
|
readCliPackageJson,
|
|
41
31
|
readSatelliteLatestRunAt,
|
|
42
32
|
readSatelliteLatestRunFromText,
|
|
43
33
|
readVaultSyncConfig,
|
|
44
|
-
redactMcpSecret,
|
|
45
34
|
reindexPageInVectorIndex,
|
|
46
35
|
renderIndexUpsert,
|
|
47
36
|
renderProjectIndex,
|
|
@@ -75,7 +64,7 @@ import {
|
|
|
75
64
|
upsertIndexEntry,
|
|
76
65
|
vectorIndexStatus,
|
|
77
66
|
withMcpClient
|
|
78
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-APKDTEVV.js";
|
|
79
68
|
import {
|
|
80
69
|
applySourceDisposition,
|
|
81
70
|
decodeSourceActionApproval,
|
|
@@ -83,7 +72,7 @@ import {
|
|
|
83
72
|
inventorySources,
|
|
84
73
|
planSourceDisposition,
|
|
85
74
|
runSourcesPending
|
|
86
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-RR6VDWSI.js";
|
|
87
76
|
import {
|
|
88
77
|
normalizeDistTag,
|
|
89
78
|
readCache,
|
|
@@ -96,7 +85,7 @@ import {
|
|
|
96
85
|
UNMANAGED_START,
|
|
97
86
|
renderRootIndex,
|
|
98
87
|
writeRootIndexProjection
|
|
99
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-IR2DI4Y5.js";
|
|
100
89
|
import {
|
|
101
90
|
FLEET_REL_PATH,
|
|
102
91
|
REDACTED_MALFORMED_REFERENCE,
|
|
@@ -184,7 +173,7 @@ import {
|
|
|
184
173
|
stageVaultContentChanges,
|
|
185
174
|
supersedeStaleReviewRequiredJournals,
|
|
186
175
|
taxonomyCommentForPage
|
|
187
|
-
} from "./chunk-
|
|
176
|
+
} from "./chunk-Q6EZF37H.js";
|
|
188
177
|
import {
|
|
189
178
|
authorizeRawOperation,
|
|
190
179
|
buildSourceReferenceIndex,
|
|
@@ -201,11 +190,11 @@ import {
|
|
|
201
190
|
resolveExistingRegularFileInsideVault,
|
|
202
191
|
validateLogEvent,
|
|
203
192
|
writeLogEvent
|
|
204
|
-
} from "./chunk-
|
|
193
|
+
} from "./chunk-CKQPUHM2.js";
|
|
205
194
|
import {
|
|
206
195
|
assertTargetInsideVault,
|
|
207
196
|
prepareTypedPage
|
|
208
|
-
} from "./chunk-
|
|
197
|
+
} from "./chunk-KJG2CSYD.js";
|
|
209
198
|
import {
|
|
210
199
|
extractFrontmatter,
|
|
211
200
|
mapWithConcurrency,
|
|
@@ -217,25 +206,38 @@ import {
|
|
|
217
206
|
scanVault,
|
|
218
207
|
splitFrontmatter,
|
|
219
208
|
vaultIoConcurrency
|
|
220
|
-
} from "./chunk-
|
|
209
|
+
} from "./chunk-TKX6PSWZ.js";
|
|
210
|
+
import {
|
|
211
|
+
MCP_HOST_ID_ENV,
|
|
212
|
+
MCP_TOKEN_ENV,
|
|
213
|
+
MCP_URL_ENV,
|
|
214
|
+
mcpAuthFromEnv,
|
|
215
|
+
mergeMcpAuthIntoEnv,
|
|
216
|
+
nonEmptyEnvValue,
|
|
217
|
+
redactMcpSecret
|
|
218
|
+
} from "./chunk-DOHWNPAZ.js";
|
|
221
219
|
import {
|
|
222
220
|
CLIP_MIGRATION_HINT,
|
|
223
221
|
refreshInstalledClipPlist
|
|
224
|
-
} from "./chunk-
|
|
222
|
+
} from "./chunk-25OXNFDV.js";
|
|
223
|
+
import {
|
|
224
|
+
atomicWriteText
|
|
225
|
+
} from "./chunk-EE7W3GLA.js";
|
|
225
226
|
import {
|
|
226
227
|
CLIP_NOT_CONFIGURED,
|
|
227
228
|
loadClipOutboxConfig
|
|
228
|
-
} from "./chunk-
|
|
229
|
+
} from "./chunk-ABRYBO4T.js";
|
|
230
|
+
import {
|
|
231
|
+
runFetchGuard,
|
|
232
|
+
runFetchGuardSync
|
|
233
|
+
} from "./chunk-LOVLZNLX.js";
|
|
229
234
|
import {
|
|
230
235
|
parseDotenvFile,
|
|
231
236
|
parseDotenvText,
|
|
232
237
|
profileKey,
|
|
233
238
|
resolveSkillwikiHome,
|
|
234
239
|
writeDotenv
|
|
235
|
-
} from "./chunk-
|
|
236
|
-
import {
|
|
237
|
-
atomicWriteText
|
|
238
|
-
} from "./chunk-GQWCTJTU.js";
|
|
240
|
+
} from "./chunk-SKOLE6US.js";
|
|
239
241
|
import {
|
|
240
242
|
ExitCode,
|
|
241
243
|
MetaSchema,
|
|
@@ -245,7 +247,7 @@ import {
|
|
|
245
247
|
err,
|
|
246
248
|
ok,
|
|
247
249
|
resolveSessionKind
|
|
248
|
-
} from "./chunk-
|
|
250
|
+
} from "./chunk-7POLZOFY.js";
|
|
249
251
|
|
|
250
252
|
// src/cli.ts
|
|
251
253
|
import { join as join44 } from "path";
|
|
@@ -3583,7 +3585,7 @@ async function runClipOutboxStatus(home) {
|
|
|
3583
3585
|
result: ok({ enabled: false, humanHint: CLIP_NOT_CONFIGURED })
|
|
3584
3586
|
};
|
|
3585
3587
|
}
|
|
3586
|
-
const { readJournal: readJournal2 } = await import("./journal-
|
|
3588
|
+
const { readJournal: readJournal2 } = await import("./journal-5IW3TZ5F.js");
|
|
3587
3589
|
let queue;
|
|
3588
3590
|
try {
|
|
3589
3591
|
queue = (await readJournal2(resolved.config.stateRoot)).map(({ captureId, state, reason, attempts }) => ({ captureId, state, reason, attempts }));
|
|
@@ -3601,7 +3603,7 @@ async function runClipOutboxStatus(home) {
|
|
|
3601
3603
|
}
|
|
3602
3604
|
async function runClipOutboxInstall(input) {
|
|
3603
3605
|
try {
|
|
3604
|
-
const { migrateClipOutbox } = await import("./migrate-
|
|
3606
|
+
const { migrateClipOutbox } = await import("./migrate-RO4BJP5T.js");
|
|
3605
3607
|
return { exitCode: ExitCode.OK, result: ok(await migrateClipOutbox(input)) };
|
|
3606
3608
|
} catch (e) {
|
|
3607
3609
|
return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: e instanceof Error ? e.message : "clip migration failed" }) };
|
|
@@ -3614,10 +3616,10 @@ async function runClipOutboxWatch(home) {
|
|
|
3614
3616
|
let client;
|
|
3615
3617
|
try {
|
|
3616
3618
|
const { S3Client: S3Client3 } = await import("@aws-sdk/client-s3");
|
|
3617
|
-
const { loadClipCredentials, validateRuntime } = await import("./runtime-
|
|
3619
|
+
const { loadClipCredentials, validateRuntime } = await import("./runtime-VMFYW2K3.js");
|
|
3618
3620
|
const { createS3CreateOnlyPut, parseDestination } = await import("./upload-HTE62TOV.js");
|
|
3619
3621
|
const { postReadyHint } = await import("./ready-S7F53Q2D.js");
|
|
3620
|
-
const { startClipWorker } = await import("./watcher-
|
|
3622
|
+
const { startClipWorker } = await import("./watcher-MGHQD3UI.js");
|
|
3621
3623
|
const cfg = resolved.config;
|
|
3622
3624
|
const credentials = await loadClipCredentials(home, cfg);
|
|
3623
3625
|
await validateRuntime(home, cfg, credentials.s3.endpoint);
|
|
@@ -3653,6 +3655,47 @@ async function runClipOutboxWatch(home) {
|
|
|
3653
3655
|
client?.destroy();
|
|
3654
3656
|
}
|
|
3655
3657
|
}
|
|
3658
|
+
async function runClipOutboxMirrorWatch(home) {
|
|
3659
|
+
const resolved = await loadClipOutboxConfig(home);
|
|
3660
|
+
if (!resolved.ok || !resolved.enabled) return { exitCode: ExitCode.INVALID_CONFIG_VALUE, result: err("INVALID_CONFIG_VALUE", { message: resolved.ok ? CLIP_NOT_CONFIGURED : resolved.message }) };
|
|
3661
|
+
let client;
|
|
3662
|
+
const abort = new AbortController();
|
|
3663
|
+
try {
|
|
3664
|
+
const { S3Client: S3Client3 } = await import("@aws-sdk/client-s3");
|
|
3665
|
+
const { loadClipCredentials, validateRuntime } = await import("./runtime-VMFYW2K3.js");
|
|
3666
|
+
const { createS3GetObject, eventsUrlFromMcp, parseDestinationForMirror, startMirrorListener } = await import("./mirror-H5BTBAON.js");
|
|
3667
|
+
const { resolveMcpAuthEnv } = await import("./mcp-auth-env-X5MI5IX6.js");
|
|
3668
|
+
const cfg = resolved.config;
|
|
3669
|
+
const credentials = await loadClipCredentials(home, cfg);
|
|
3670
|
+
await validateRuntime(home, cfg, credentials.s3.endpoint);
|
|
3671
|
+
const auth = await resolveMcpAuthEnv({ home });
|
|
3672
|
+
if (!auth.url || !auth.token) throw new Error("MCP bearer required for inbound SSE");
|
|
3673
|
+
const destination = parseDestinationForMirror(cfg.destination);
|
|
3674
|
+
client = new S3Client3({ endpoint: credentials.s3.endpoint, region: credentials.s3.region, credentials: credentials.s3, forcePathStyle: true, maxAttempts: 1 });
|
|
3675
|
+
const done = new Promise((resolve9) => {
|
|
3676
|
+
abort.signal.addEventListener("abort", () => resolve9(), { once: true });
|
|
3677
|
+
});
|
|
3678
|
+
process.once("SIGTERM", () => abort.abort());
|
|
3679
|
+
process.once("SIGINT", () => abort.abort());
|
|
3680
|
+
await Promise.race([
|
|
3681
|
+
startMirrorListener({
|
|
3682
|
+
home,
|
|
3683
|
+
config: cfg,
|
|
3684
|
+
eventsUrl: eventsUrlFromMcp(auth.url),
|
|
3685
|
+
mcpToken: auth.token,
|
|
3686
|
+
getObject: createS3GetObject({ client, bucket: destination.bucket, prefix: destination.prefix, maxBytes: cfg.maxBundleBytes }),
|
|
3687
|
+
signal: abort.signal
|
|
3688
|
+
}),
|
|
3689
|
+
done
|
|
3690
|
+
]);
|
|
3691
|
+
return { exitCode: ExitCode.OK, result: ok({ humanHint: "Inbound SSE listener stopped." }) };
|
|
3692
|
+
} catch {
|
|
3693
|
+
return { exitCode: ExitCode.PREFLIGHT_FAILED, result: err("PREFLIGHT_FAILED", { message: "inbound SSE listener startup failed; check MCP bearer, clip credentials, frozen mirror and wiki-push isolation" }) };
|
|
3694
|
+
} finally {
|
|
3695
|
+
abort.abort();
|
|
3696
|
+
client?.destroy();
|
|
3697
|
+
}
|
|
3698
|
+
}
|
|
3656
3699
|
|
|
3657
3700
|
// src/commands/connect.ts
|
|
3658
3701
|
import { chmod, mkdir as mkdir5, readFile as readFile6, stat as stat3 } from "fs/promises";
|
|
@@ -4132,7 +4175,7 @@ ${fmRewritten}
|
|
|
4132
4175
|
}
|
|
4133
4176
|
let indexUpdated = false;
|
|
4134
4177
|
if (!isRaw) {
|
|
4135
|
-
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-
|
|
4178
|
+
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-UNZG5UJZ.js");
|
|
4136
4179
|
const before = await readFile7(join19(input.vault, "index.md"), "utf8").catch(() => "");
|
|
4137
4180
|
const fullTarget = relPath.replace(/\.md$/, "");
|
|
4138
4181
|
const bare = fullTarget.split("/").pop() ?? fullTarget;
|
|
@@ -4255,7 +4298,7 @@ async function runRemove(input) {
|
|
|
4255
4298
|
if (relPath.endsWith(".md") && !relPath.startsWith("raw/")) {
|
|
4256
4299
|
const { readFile: readFile23 } = await import("fs/promises");
|
|
4257
4300
|
const { join: pathJoin } = await import("path");
|
|
4258
|
-
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-
|
|
4301
|
+
const { renderRootIndex: renderRootIndex2, writeRootIndexProjection: writeRootIndexProjection2 } = await import("./index-projection-UNZG5UJZ.js");
|
|
4259
4302
|
const before = await readFile23(pathJoin(input.vault, "index.md"), "utf8").catch(() => "");
|
|
4260
4303
|
const fullTarget = relPath.replace(/\.md$/, "");
|
|
4261
4304
|
const bare = fullTarget.split("/").pop() ?? fullTarget;
|
|
@@ -11263,7 +11306,7 @@ async function emitManagedVaultWrite(vault, command, mutate, opts) {
|
|
|
11263
11306
|
if (dirty) {
|
|
11264
11307
|
return emit(dirty, void 0, { postCommit: false });
|
|
11265
11308
|
}
|
|
11266
|
-
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-
|
|
11309
|
+
const { runManagedWriteTransaction: runManagedWriteTransaction2 } = await import("./managed-write-preflight-L7IRQ76C.js");
|
|
11267
11310
|
const run = await runManagedWriteTransaction2({
|
|
11268
11311
|
vault,
|
|
11269
11312
|
command,
|
|
@@ -11910,7 +11953,8 @@ program.command("doctor").description("diagnose skillwiki setup issues").option(
|
|
|
11910
11953
|
var clipOutboxCmd = program.command("clip-outbox").description("dedicated file-level web-clip outbox");
|
|
11911
11954
|
clipOutboxCmd.command("status").description("show whether the clip-outbox channel is configured").action(async () => emit(await runClipOutboxStatus(resolveSkillwikiHome())));
|
|
11912
11955
|
clipOutboxCmd.command("watch").description("run the enabled dedicated outbox worker using macOS FSEvents").action(async () => emit(await runClipOutboxWatch(resolveSkillwikiHome())));
|
|
11913
|
-
clipOutboxCmd.command("
|
|
11956
|
+
clipOutboxCmd.command("mirror-watch").description("copy admitted raw/articles and raw/assets from storage into the frozen mirror using MCP SSE").action(async () => emit(await runClipOutboxMirrorWatch(resolveSkillwikiHome())));
|
|
11957
|
+
clipOutboxCmd.command("install-or-migrate").description("refresh the packaged launchd plist without enabling the channel").option("--load", "attended clip watcher bootstrap; requires existing enabled=true", false).option("--load-mirror", "attended inbound SSE bootstrap; requires existing enabled=true; never auto-loaded on upgrade", false).option("--conditional-create-proven", "attest the deployed SeaweedFS If-None-Match:* race test passed", false).action(async (opts) => emit(await runClipOutboxInstall({ home: resolveSkillwikiHome(), load: opts.load, loadMirror: opts.loadMirror, conditionalCreateProven: opts.conditionalCreateProven })));
|
|
11914
11958
|
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({
|
|
11915
11959
|
home: resolveSkillwikiHome(),
|
|
11916
11960
|
fromFile: opts.fromFile,
|