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
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
+
atomicWriteText
|
|
4
|
+
} from "./chunk-EE7W3GLA.js";
|
|
5
|
+
import {
|
|
6
|
+
PRODUCTION_MIRROR_LABEL,
|
|
3
7
|
PRODUCTION_WATCHER_LABEL,
|
|
4
8
|
evidencePath,
|
|
5
9
|
expandUserPath,
|
|
@@ -7,25 +11,22 @@ import {
|
|
|
7
11
|
nestedOrEqual,
|
|
8
12
|
resolveClipOutboxConfig,
|
|
9
13
|
validateRuntime
|
|
10
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-ABRYBO4T.js";
|
|
11
15
|
import {
|
|
12
16
|
parseDotenvFile
|
|
13
|
-
} from "./chunk-
|
|
14
|
-
import {
|
|
15
|
-
atomicWriteText
|
|
16
|
-
} from "./chunk-GQWCTJTU.js";
|
|
17
|
+
} from "./chunk-SKOLE6US.js";
|
|
17
18
|
|
|
18
19
|
// src/clip-outbox/migrate.ts
|
|
19
20
|
import { access, mkdir, readFile } from "fs/promises";
|
|
20
21
|
import { constants } from "fs";
|
|
21
22
|
import { basename, dirname, isAbsolute, join } from "path";
|
|
22
23
|
import { execFileSync } from "child_process";
|
|
23
|
-
var CLIP_MIGRATION_HINT = "Clip channel requires attended setup: run skillwiki clip-outbox install-or-migrate, then skillwiki doctor. Installation/update never sets clip_outbox.enabled=true or loads launchd. Prove deployed SeaweedFS If-None-Match:* create-only before
|
|
24
|
+
var CLIP_MIGRATION_HINT = "Clip channel requires attended setup: run skillwiki clip-outbox install-or-migrate, then skillwiki doctor. Installation/update never sets clip_outbox.enabled=true or loads launchd. Prove deployed SeaweedFS If-None-Match:* create-only before --load. Inbound SSE uses a separate --load-mirror and never watches ~/wiki as clip input.";
|
|
24
25
|
var xml = (s) => s.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
25
|
-
async function packagedPlist() {
|
|
26
|
+
async function packagedPlist(label = PRODUCTION_WATCHER_LABEL) {
|
|
26
27
|
for (const rel of ["../templates/launchd/", "../../templates/launchd/"]) {
|
|
27
28
|
try {
|
|
28
|
-
return await readFile(new URL(`${rel}${
|
|
29
|
+
return await readFile(new URL(`${rel}${label}.plist`, import.meta.url), "utf8");
|
|
29
30
|
} catch {
|
|
30
31
|
}
|
|
31
32
|
}
|
|
@@ -48,6 +49,7 @@ async function migrateClipOutbox(input) {
|
|
|
48
49
|
const resolved = resolveClipOutboxConfig(map, input.home);
|
|
49
50
|
if (!resolved.ok) throw new Error(resolved.message);
|
|
50
51
|
if (input.load && (!resolved.enabled || !input.conditionalCreateProven)) throw new Error("--load requires existing clip_outbox.enabled=true and --conditional-create-proven after the operator's deployed create-only race test");
|
|
52
|
+
if (input.loadMirror && !resolved.enabled) throw new Error("--load-mirror requires existing clip_outbox.enabled=true; upgrades never auto-load the inbound SSE listener");
|
|
51
53
|
if ((input.platform ?? process.platform) !== "darwin") throw new Error("clip launchd migration requires macOS");
|
|
52
54
|
const rawRoot = map["clip_outbox.root"] ?? "~/Obsidian/clip-outbox";
|
|
53
55
|
const root = resolved.enabled ? resolved.config.root : expandUserPath(rawRoot, input.home);
|
|
@@ -58,9 +60,16 @@ async function migrateClipOutbox(input) {
|
|
|
58
60
|
if (!isAbsolute(binary) || !isAbsolute(input.nodePath ?? process.execPath)) throw new Error("absolute executable paths required");
|
|
59
61
|
const logRoot = join(input.home, "Library", "Logs", "SkillWiki");
|
|
60
62
|
const plistPath = join(input.home, "Library", "LaunchAgents", `${PRODUCTION_WATCHER_LABEL}.plist`);
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
63
|
+
const mirrorPlistPath = join(input.home, "Library", "LaunchAgents", `${PRODUCTION_MIRROR_LABEL}.plist`);
|
|
64
|
+
const replacements = { NODE_BINARY: input.nodePath ?? process.execPath, CLI_BINARY: binary, OUTBOX_ROOT: root, HOME: input.home, LOG_ROOT: logRoot };
|
|
65
|
+
const render = async (label) => {
|
|
66
|
+
let plist = await packagedPlist(label);
|
|
67
|
+
for (const [key, value] of Object.entries(replacements)) plist = plist.replaceAll(`@${key}@`, xml(value));
|
|
68
|
+
if (label === PRODUCTION_MIRROR_LABEL && plist.includes("<key>WatchPaths</key>")) throw new Error("inbound SSE plist must not watch the frozen mirror");
|
|
69
|
+
return plist;
|
|
70
|
+
};
|
|
71
|
+
const watcherPlist = await render(PRODUCTION_WATCHER_LABEL);
|
|
72
|
+
const mirrorPlist = await render(PRODUCTION_MIRROR_LABEL);
|
|
64
73
|
if (input.load) {
|
|
65
74
|
if (!resolved.enabled) throw new Error("--load requires existing clip_outbox.enabled=true and --conditional-create-proven after the operator's deployed create-only race test");
|
|
66
75
|
const creds = await loadClipCredentials(input.home, resolved.config);
|
|
@@ -71,22 +80,37 @@ async function migrateClipOutbox(input) {
|
|
|
71
80
|
}
|
|
72
81
|
await mkdir(dirname(plistPath), { recursive: true });
|
|
73
82
|
await mkdir(logRoot, { recursive: true });
|
|
74
|
-
const result = await atomicWriteText(plistPath,
|
|
83
|
+
const result = await atomicWriteText(plistPath, watcherPlist);
|
|
75
84
|
if (!result.ok) throw new Error("cannot refresh clip plist");
|
|
76
|
-
|
|
85
|
+
const mirrorResult = await atomicWriteText(mirrorPlistPath, mirrorPlist);
|
|
86
|
+
if (!mirrorResult.ok) throw new Error("cannot refresh inbound SSE plist");
|
|
87
|
+
const bootstrap = (label, path) => {
|
|
77
88
|
if (typeof process.getuid !== "function") throw new Error("clip launchd load requires macOS");
|
|
78
89
|
const domain = `gui/${process.getuid()}`;
|
|
79
90
|
const launch = input.launch ?? ((args) => {
|
|
80
91
|
execFileSync("launchctl", args, { stdio: "ignore", timeout: 5e3 });
|
|
81
92
|
});
|
|
82
93
|
try {
|
|
83
|
-
launch(["bootout", `${domain}/${
|
|
94
|
+
launch(["bootout", `${domain}/${label}`]);
|
|
84
95
|
} catch {
|
|
85
96
|
}
|
|
86
|
-
launch(["enable", `${domain}/${
|
|
87
|
-
launch(["bootstrap", domain,
|
|
88
|
-
}
|
|
89
|
-
|
|
97
|
+
launch(["enable", `${domain}/${label}`]);
|
|
98
|
+
launch(["bootstrap", domain, path]);
|
|
99
|
+
};
|
|
100
|
+
if (input.load) bootstrap(PRODUCTION_WATCHER_LABEL, plistPath);
|
|
101
|
+
if (input.loadMirror) bootstrap(PRODUCTION_MIRROR_LABEL, mirrorPlistPath);
|
|
102
|
+
const loadedBits = [
|
|
103
|
+
input.load ? "Operator-gated clip watcher bootstrap requested." : void 0,
|
|
104
|
+
input.loadMirror ? "Operator-gated inbound SSE bootstrap requested." : void 0
|
|
105
|
+
].filter(Boolean).join(" ");
|
|
106
|
+
return {
|
|
107
|
+
plistPath,
|
|
108
|
+
mirrorPlistPath,
|
|
109
|
+
loaded: !!input.load,
|
|
110
|
+
mirrorLoaded: !!input.loadMirror,
|
|
111
|
+
enabled: resolved.enabled,
|
|
112
|
+
humanHint: `${result.data.changed ? "Refreshed" : "Current"} clip launchd plist: ${plistPath}. ${mirrorResult.data.changed ? "Refreshed" : "Current"} inbound SSE plist: ${mirrorPlistPath}. ${loadedBits || CLIP_MIGRATION_HINT}`
|
|
113
|
+
};
|
|
90
114
|
}
|
|
91
115
|
async function refreshInstalledClipPlist(home, opts) {
|
|
92
116
|
const plistPath = join(home, "Library", "LaunchAgents", `${PRODUCTION_WATCHER_LABEL}.plist`);
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
defaultLookup
|
|
4
|
+
} from "./chunk-LOVLZNLX.js";
|
|
2
5
|
import {
|
|
3
6
|
parseDotenvFile,
|
|
4
7
|
resolveSkillwikiHome
|
|
5
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-SKOLE6US.js";
|
|
6
9
|
import {
|
|
7
10
|
CLIP_OUTBOX_DEFAULTS,
|
|
11
|
+
ipv4InCidr,
|
|
8
12
|
isClipOutboxKey,
|
|
9
13
|
parseClipOutboxKeyValue
|
|
10
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-7POLZOFY.js";
|
|
11
15
|
|
|
12
16
|
// src/clip-outbox/runtime.ts
|
|
13
17
|
import { existsSync as existsSync2 } from "fs";
|
|
14
18
|
import { lstat, readFile } from "fs/promises";
|
|
19
|
+
import { isIP } from "net";
|
|
15
20
|
import { join as join2 } from "path";
|
|
16
21
|
import { execFileSync } from "child_process";
|
|
17
22
|
import { z } from "zod";
|
|
@@ -22,6 +27,7 @@ import { homedir } from "os";
|
|
|
22
27
|
import { isAbsolute, join, resolve, sep } from "path";
|
|
23
28
|
var CLIP_NOT_CONFIGURED = "clip channel not configured";
|
|
24
29
|
var PRODUCTION_WATCHER_LABEL = CLIP_OUTBOX_DEFAULTS.watcher_label;
|
|
30
|
+
var PRODUCTION_MIRROR_LABEL = "com.karlchow.skillwiki-mirror-sse";
|
|
25
31
|
var RETIRED_WATCHER_LABELS = [
|
|
26
32
|
"com.karlchow.wiki-dev-outbox",
|
|
27
33
|
"com.karlchow.wiki-dev-sse",
|
|
@@ -188,6 +194,23 @@ async function loadClipOutboxConfig(home) {
|
|
|
188
194
|
|
|
189
195
|
// src/clip-outbox/runtime.ts
|
|
190
196
|
var s3Schema = z.object({ endpoint: z.string().url(), region: z.string().default("us-east-1"), accessKeyId: z.string().min(1), secretAccessKey: z.string().min(1), sessionToken: z.string().optional() }).strict();
|
|
197
|
+
function isRfc1918OrLoopback(address) {
|
|
198
|
+
const version = isIP(address);
|
|
199
|
+
if (version === 4) {
|
|
200
|
+
return ipv4InCidr(address, "10.0.0.0", 8) || ipv4InCidr(address, "172.16.0.0", 12) || ipv4InCidr(address, "192.168.0.0", 16) || ipv4InCidr(address, "127.0.0.0", 8);
|
|
201
|
+
}
|
|
202
|
+
return version === 6 && address.toLowerCase() === "::1";
|
|
203
|
+
}
|
|
204
|
+
async function assertClipS3Endpoint(endpoint, lookup = defaultLookup) {
|
|
205
|
+
const url = new URL(endpoint);
|
|
206
|
+
if (url.username || url.password || url.search || url.hash) throw new Error("invalid clip S3 endpoint");
|
|
207
|
+
if (url.protocol === "https:") return;
|
|
208
|
+
if (url.protocol !== "http:") throw new Error("invalid clip S3 endpoint");
|
|
209
|
+
const addresses = isIP(url.hostname) ? [url.hostname] : await lookup(url.hostname);
|
|
210
|
+
if (addresses.length === 0 || !addresses.every(isRfc1918OrLoopback)) {
|
|
211
|
+
throw new Error("http clip S3 endpoint must resolve only to RFC1918 or loopback");
|
|
212
|
+
}
|
|
213
|
+
}
|
|
191
214
|
async function loadClipCredentials(home, config, env = process.env) {
|
|
192
215
|
let providers = {};
|
|
193
216
|
const path = join2(home, ".skillwiki", "clip-outbox-credentials.json");
|
|
@@ -201,8 +224,7 @@ async function loadClipCredentials(home, config, env = process.env) {
|
|
|
201
224
|
try {
|
|
202
225
|
const rawS3 = env[config.s3CredentialRef] ?? providers[config.s3CredentialRef];
|
|
203
226
|
const s3 = s3Schema.parse(typeof rawS3 === "string" ? JSON.parse(rawS3) : rawS3);
|
|
204
|
-
|
|
205
|
-
if (endpoint.protocol !== "https:" || endpoint.username || endpoint.password || endpoint.search || endpoint.hash) throw new Error();
|
|
227
|
+
await assertClipS3Endpoint(s3.endpoint);
|
|
206
228
|
const hostConfig = await parseDotenvFile(join2(home, ".skillwiki", ".env"));
|
|
207
229
|
const readyToken = env[config.readyCredentialRef] ?? providers[config.readyCredentialRef];
|
|
208
230
|
if (typeof readyToken !== "string" || !readyToken || config.readyCredentialRef === "SKILLWIKI_MCP_TOKEN" || readyToken === env.SKILLWIKI_MCP_TOKEN || readyToken === hostConfig.SKILLWIKI_MCP_TOKEN || config.readyCredentialRef === config.s3CredentialRef) throw new Error();
|
|
@@ -238,11 +260,14 @@ async function validateRuntime(home, config, endpoint) {
|
|
|
238
260
|
export {
|
|
239
261
|
CLIP_NOT_CONFIGURED,
|
|
240
262
|
PRODUCTION_WATCHER_LABEL,
|
|
263
|
+
PRODUCTION_MIRROR_LABEL,
|
|
241
264
|
RETIRED_WATCHER_LABELS,
|
|
242
265
|
expandUserPath,
|
|
243
266
|
nestedOrEqual,
|
|
244
267
|
resolveClipOutboxConfig,
|
|
245
268
|
loadClipOutboxConfig,
|
|
269
|
+
isRfc1918OrLoopback,
|
|
270
|
+
assertClipS3Endpoint,
|
|
246
271
|
loadClipCredentials,
|
|
247
272
|
evidencePath,
|
|
248
273
|
conditionalCreateProven,
|