neko-harness 0.2.2 → 0.2.3
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/client/assets/index-DXuZXmFD.js +90 -0
- package/dist/client/assets/index-wX6mP4oW.css +2 -0
- package/dist/client/index.html +2 -2
- package/dist/gateway.js +761 -52
- package/dist/neko.js +1137 -108
- package/package.json +1 -1
- package/dist/client/assets/index-6edxlI44.css +0 -2
- package/dist/client/assets/index-CZ-wxzM4.js +0 -88
package/dist/neko.js
CHANGED
|
@@ -229,8 +229,18 @@ function validate(config, source) {
|
|
|
229
229
|
if (theme !== undefined && theme !== "light" && theme !== "dark" && theme !== "auto") {
|
|
230
230
|
throw new Error(`neko config: ${source}: "theme" must be "light", "dark", or "auto".`);
|
|
231
231
|
}
|
|
232
|
+
const skills = config.skills;
|
|
233
|
+
if (skills !== undefined) {
|
|
234
|
+
if (typeof skills !== "object" || skills === null) {
|
|
235
|
+
throw new Error(`neko config: ${source}: "skills" must be an object.`);
|
|
236
|
+
}
|
|
237
|
+
const { marketUrl } = skills;
|
|
238
|
+
if (marketUrl !== undefined && typeof marketUrl !== "string") {
|
|
239
|
+
throw new Error(`neko config: ${source}: "skills.marketUrl" must be a string.`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
232
242
|
}
|
|
233
|
-
var NEKO_CONFIG_BASENAME = "neko.config.json", ENV_REFERENCE;
|
|
243
|
+
var DEFAULT_SKILL_MARKET_URL = "https://skill.kirineko.tech", NEKO_CONFIG_BASENAME = "neko.config.json", ENV_REFERENCE;
|
|
234
244
|
var init_config = __esm(() => {
|
|
235
245
|
ENV_REFERENCE = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g;
|
|
236
246
|
});
|
|
@@ -866,11 +876,6 @@ var init_projection = __esm(() => {
|
|
|
866
876
|
init_workspace();
|
|
867
877
|
});
|
|
868
878
|
|
|
869
|
-
// packages/core/src/prompt/diagnostics.ts
|
|
870
|
-
var ignorePromptDiagnostic = () => {}, warnPromptDiagnostic = ({ path, message }) => {
|
|
871
|
-
console.warn(`[neko-prompt] ${JSON.stringify(path)}: ${message}`);
|
|
872
|
-
}, isMissing = (error) => typeof error === "object" && error !== null && ("code" in error) && (error.code === "ENOENT" || error.code === "ENOTDIR");
|
|
873
|
-
|
|
874
879
|
// packages/core/src/prompt/frontmatter.ts
|
|
875
880
|
import { parse } from "yaml";
|
|
876
881
|
var normalizeNewlines = (value) => value.replace(/\r\n/g, `
|
|
@@ -896,6 +901,11 @@ var normalizeNewlines = (value) => value.replace(/\r\n/g, `
|
|
|
896
901
|
}, stripFrontmatter = (content) => extractFrontmatter(content).body;
|
|
897
902
|
var init_frontmatter = () => {};
|
|
898
903
|
|
|
904
|
+
// packages/core/src/prompt/diagnostics.ts
|
|
905
|
+
var ignorePromptDiagnostic = () => {}, warnPromptDiagnostic = ({ path, message }) => {
|
|
906
|
+
console.warn(`[neko-prompt] ${JSON.stringify(path)}: ${message}`);
|
|
907
|
+
}, isMissing = (error) => typeof error === "object" && error !== null && ("code" in error) && (error.code === "ENOENT" || error.code === "ENOTDIR");
|
|
908
|
+
|
|
899
909
|
// packages/core/src/prompt/skills.ts
|
|
900
910
|
import { readdir, readFile as readFile2 } from "fs/promises";
|
|
901
911
|
import { basename, dirname as dirname3, join as join3 } from "path";
|
|
@@ -1091,7 +1101,8 @@ var init_prompt = __esm(() => {
|
|
|
1091
1101
|
import { readFile as readFile3 } from "fs/promises";
|
|
1092
1102
|
import { homedir as homedir3 } from "os";
|
|
1093
1103
|
import { join as join4 } from "path";
|
|
1094
|
-
|
|
1104
|
+
import { fileURLToPath } from "url";
|
|
1105
|
+
var userAgentsFile = (home) => join4(home, ".agents", "AGENTS.md"), userSkillsDir = (home) => join4(home, ".agents", "skills"), workspaceAgentsFile = (workspace) => join4(workspace, "AGENTS.md"), workspaceSkillsDir = (workspace) => join4(workspace, ".agents", "skills"), BUILTIN_SKILLS_DIR, readResources = async (workspace, home, builtinDir, report, invocationName) => {
|
|
1095
1106
|
const contextFiles = [];
|
|
1096
1107
|
for (const path of [userAgentsFile(home), workspaceAgentsFile(workspace)]) {
|
|
1097
1108
|
try {
|
|
@@ -1112,11 +1123,13 @@ var userAgentsFile = (home) => join4(home, ".agents", "AGENTS.md"), userSkillsDi
|
|
|
1112
1123
|
if (skill.name === invocationName)
|
|
1113
1124
|
candidates.set(skill.filePath, content);
|
|
1114
1125
|
} : undefined;
|
|
1115
|
-
const
|
|
1116
|
-
|
|
1117
|
-
|
|
1126
|
+
const scan = async (dir, level) => (await scanSkillsDir(dir, report, capture)).map((skill) => ({ ...skill, level }));
|
|
1127
|
+
const [builtin, user, project] = await Promise.all([
|
|
1128
|
+
builtinDir === null ? Promise.resolve([]) : scan(builtinDir, "builtin"),
|
|
1129
|
+
scan(userSkillsDir(home), "user"),
|
|
1130
|
+
scan(workspaceSkillsDir(workspace), "project")
|
|
1118
1131
|
]);
|
|
1119
|
-
const skills = mergeSkills([user, project]);
|
|
1132
|
+
const skills = mergeSkills([builtin, user, project]);
|
|
1120
1133
|
const winner = invocationName === undefined ? undefined : skills.find((skill) => skill.name === invocationName);
|
|
1121
1134
|
if (winner && candidates) {
|
|
1122
1135
|
const content = candidates.get(winner.filePath);
|
|
@@ -1124,11 +1137,12 @@ var userAgentsFile = (home) => join4(home, ".agents", "AGENTS.md"), userSkillsDi
|
|
|
1124
1137
|
return { contextFiles, skills, invocation: { filePath: winner.filePath, content } };
|
|
1125
1138
|
}
|
|
1126
1139
|
return { contextFiles, skills };
|
|
1127
|
-
}, createResourceLoader = (home = homedir3(), report = warnPromptDiagnostic) => {
|
|
1140
|
+
}, createResourceLoader = (home = homedir3(), report = warnPromptDiagnostic, options) => {
|
|
1141
|
+
const builtinDir = options?.builtinDir === undefined ? BUILTIN_SKILLS_DIR : options.builtinDir;
|
|
1128
1142
|
const previous = new Map;
|
|
1129
1143
|
return async (workspace, invocationName) => {
|
|
1130
1144
|
const diagnostics = [];
|
|
1131
|
-
const resources = await readResources(workspace, home, (d) => diagnostics.push(d), invocationName);
|
|
1145
|
+
const resources = await readResources(workspace, home, builtinDir, (d) => diagnostics.push(d), invocationName);
|
|
1132
1146
|
const known = previous.get(workspace);
|
|
1133
1147
|
const current = new Set;
|
|
1134
1148
|
for (const diagnostic of diagnostics) {
|
|
@@ -1143,9 +1157,18 @@ var userAgentsFile = (home) => join4(home, ".agents", "AGENTS.md"), userSkillsDi
|
|
|
1143
1157
|
previous.delete(workspace);
|
|
1144
1158
|
return resources;
|
|
1145
1159
|
};
|
|
1160
|
+
}, scanSkillsByLevel = async (workspace, home = homedir3(), builtinDir = BUILTIN_SKILLS_DIR, report = warnPromptDiagnostic) => {
|
|
1161
|
+
const scan = async (dir, level) => (await scanSkillsDir(dir, report)).map((skill) => ({ ...skill, level }));
|
|
1162
|
+
const [builtin, user, project] = await Promise.all([
|
|
1163
|
+
builtinDir === null ? [] : scan(builtinDir, "builtin"),
|
|
1164
|
+
scan(userSkillsDir(home), "user"),
|
|
1165
|
+
scan(workspaceSkillsDir(workspace), "project")
|
|
1166
|
+
]);
|
|
1167
|
+
return [...project, ...user, ...builtin];
|
|
1146
1168
|
};
|
|
1147
1169
|
var init_resources = __esm(() => {
|
|
1148
1170
|
init_skills();
|
|
1171
|
+
BUILTIN_SKILLS_DIR = fileURLToPath(new URL("../../skills/", import.meta.url));
|
|
1149
1172
|
});
|
|
1150
1173
|
|
|
1151
1174
|
// packages/core/src/prompt/snapshots.ts
|
|
@@ -2313,7 +2336,21 @@ async function createNekoRuntime(options = {}) {
|
|
|
2313
2336
|
const session = await sessionFor(id);
|
|
2314
2337
|
const agent = await session.conversation.agent(context);
|
|
2315
2338
|
const { skills } = await loadResources(savedWorkspace(agent.cwd));
|
|
2316
|
-
return skills.map((skill) => ({
|
|
2339
|
+
return skills.map((skill) => ({
|
|
2340
|
+
name: skill.name,
|
|
2341
|
+
description: skill.description,
|
|
2342
|
+
location: skill.filePath,
|
|
2343
|
+
level: skill.level
|
|
2344
|
+
}));
|
|
2345
|
+
},
|
|
2346
|
+
async listSkillsByLevel(cwd) {
|
|
2347
|
+
const skills = await scanSkillsByLevel(normalizeWorkspace(cwd ?? defaultCwd), options.promptHome ?? homedir4());
|
|
2348
|
+
return skills.map((skill) => ({
|
|
2349
|
+
name: skill.name,
|
|
2350
|
+
description: skill.description,
|
|
2351
|
+
location: skill.filePath,
|
|
2352
|
+
level: skill.level
|
|
2353
|
+
}));
|
|
2317
2354
|
},
|
|
2318
2355
|
installExtension(extension) {
|
|
2319
2356
|
registry.install(extension);
|
|
@@ -2367,6 +2404,27 @@ var init_runtime = __esm(() => {
|
|
|
2367
2404
|
});
|
|
2368
2405
|
});
|
|
2369
2406
|
|
|
2407
|
+
// packages/core/src/skill-invocation.ts
|
|
2408
|
+
var unescapeXml = (value) => value.replace(/'/g, "'").replace(/"/g, '"').replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&"), parseSkillInvocation = (text) => {
|
|
2409
|
+
const open = /^<skill name="([^"]*)" location="([^"]*)">/.exec(text);
|
|
2410
|
+
if (!open)
|
|
2411
|
+
return null;
|
|
2412
|
+
const close = text.lastIndexOf("</skill>");
|
|
2413
|
+
if (close < open[0].length)
|
|
2414
|
+
return null;
|
|
2415
|
+
const rest = text.slice(close + "</skill>".length);
|
|
2416
|
+
if (rest !== "" && !rest.startsWith(`
|
|
2417
|
+
|
|
2418
|
+
`))
|
|
2419
|
+
return null;
|
|
2420
|
+
return {
|
|
2421
|
+
name: unescapeXml(open[1]),
|
|
2422
|
+
location: unescapeXml(open[2]),
|
|
2423
|
+
body: text.slice(open[0].length, close),
|
|
2424
|
+
args: rest.slice(2)
|
|
2425
|
+
};
|
|
2426
|
+
};
|
|
2427
|
+
|
|
2370
2428
|
// packages/core/src/index.ts
|
|
2371
2429
|
var init_src = __esm(() => {
|
|
2372
2430
|
init_compaction();
|
|
@@ -2375,6 +2433,7 @@ var init_src = __esm(() => {
|
|
|
2375
2433
|
init_image_metadata();
|
|
2376
2434
|
init_images();
|
|
2377
2435
|
init_projection();
|
|
2436
|
+
init_frontmatter();
|
|
2378
2437
|
init_runtime();
|
|
2379
2438
|
init_session_metadata();
|
|
2380
2439
|
init_workspace();
|
|
@@ -2770,7 +2829,8 @@ var init_labels = __esm(() => {
|
|
|
2770
2829
|
{ name: "model", description: "Choose a model" },
|
|
2771
2830
|
{ name: "think", description: "Set thinking level (/think high)" },
|
|
2772
2831
|
{ name: "fork", description: "Fork this session" },
|
|
2773
|
-
{ name: "archive", description: "Archive this session" }
|
|
2832
|
+
{ name: "archive", description: "Archive this session" },
|
|
2833
|
+
{ name: "skills", description: "Browse and install skills from the market" }
|
|
2774
2834
|
];
|
|
2775
2835
|
labels = {
|
|
2776
2836
|
ready: "Ready",
|
|
@@ -3174,17 +3234,62 @@ class PickerPanel {
|
|
|
3174
3234
|
}
|
|
3175
3235
|
close() {
|
|
3176
3236
|
++this.#generation;
|
|
3237
|
+
this.#details = [];
|
|
3177
3238
|
this.#state = "closed";
|
|
3178
3239
|
this.closed();
|
|
3179
3240
|
this.changed();
|
|
3180
3241
|
}
|
|
3242
|
+
showDetail(detail) {
|
|
3243
|
+
if (!this.open)
|
|
3244
|
+
return;
|
|
3245
|
+
this.#details.push(detail);
|
|
3246
|
+
this.changed();
|
|
3247
|
+
}
|
|
3248
|
+
popDetail() {
|
|
3249
|
+
if (this.#details.length === 0)
|
|
3250
|
+
return;
|
|
3251
|
+
this.#details.pop();
|
|
3252
|
+
this.changed();
|
|
3253
|
+
}
|
|
3254
|
+
get detailOpen() {
|
|
3255
|
+
return this.#details.length > 0;
|
|
3256
|
+
}
|
|
3257
|
+
get #detail() {
|
|
3258
|
+
return this.#details[this.#details.length - 1];
|
|
3259
|
+
}
|
|
3260
|
+
#details = [];
|
|
3181
3261
|
#filtered() {
|
|
3182
3262
|
const query = this.search.getValue().toLowerCase();
|
|
3183
|
-
|
|
3263
|
+
if (query !== "")
|
|
3264
|
+
return this.#items.filter((item) => !item.header && this.#matches(item, query));
|
|
3265
|
+
return this.#items;
|
|
3266
|
+
}
|
|
3267
|
+
#matches(item, query) {
|
|
3268
|
+
return `${item.label} ${item.description ?? ""} ${item.searchText ?? ""}`.toLowerCase().includes(query);
|
|
3269
|
+
}
|
|
3270
|
+
#firstSelectable(items) {
|
|
3271
|
+
return items.findIndex((item) => !item.header);
|
|
3272
|
+
}
|
|
3273
|
+
#move(delta) {
|
|
3274
|
+
const items = this.#filtered();
|
|
3275
|
+
let next = this.#index + delta;
|
|
3276
|
+
while (next >= 0 && next < items.length && items[next]?.header)
|
|
3277
|
+
next += delta;
|
|
3278
|
+
this.#index = Math.max(0, Math.min(Math.max(0, items.length - 1), next));
|
|
3279
|
+
if (items[this.#index]?.header)
|
|
3280
|
+
this.#index = this.#firstSelectable(items);
|
|
3184
3281
|
}
|
|
3185
3282
|
handleInput(data) {
|
|
3186
3283
|
if (isKeyRelease3(data))
|
|
3187
3284
|
return;
|
|
3285
|
+
if (this.#detail !== undefined) {
|
|
3286
|
+
if (matchesKey3(data, "escape") || matchesKey3(data, "ctrl+c")) {
|
|
3287
|
+
this.popDetail();
|
|
3288
|
+
} else if (this.#detail.handleKey(data)) {
|
|
3289
|
+
this.changed();
|
|
3290
|
+
}
|
|
3291
|
+
return;
|
|
3292
|
+
}
|
|
3188
3293
|
if (matchesKey3(data, "escape") || matchesKey3(data, "ctrl+c")) {
|
|
3189
3294
|
this.close();
|
|
3190
3295
|
return;
|
|
@@ -3198,18 +3303,25 @@ class PickerPanel {
|
|
|
3198
3303
|
return;
|
|
3199
3304
|
const items = this.#filtered();
|
|
3200
3305
|
if (matchesKey3(data, "up"))
|
|
3201
|
-
this.#
|
|
3306
|
+
this.#move(-1);
|
|
3202
3307
|
else if (matchesKey3(data, "down"))
|
|
3203
|
-
this.#
|
|
3308
|
+
this.#move(1);
|
|
3204
3309
|
else if (matchesKey3(data, "enter")) {
|
|
3205
3310
|
const item = items[this.#index];
|
|
3206
|
-
if (!item)
|
|
3311
|
+
if (!item || item.header)
|
|
3207
3312
|
return;
|
|
3208
3313
|
const generation = this.#generation;
|
|
3209
3314
|
this.#state = "applying";
|
|
3210
|
-
this.#pick(item.value).then(() => {
|
|
3211
|
-
if (generation
|
|
3212
|
-
|
|
3315
|
+
this.#pick(item.value).then((result) => {
|
|
3316
|
+
if (generation !== this.#generation)
|
|
3317
|
+
return;
|
|
3318
|
+
if (result !== undefined && typeof result === "object" && "lines" in result) {
|
|
3319
|
+
this.#state = "ready";
|
|
3320
|
+
this.showDetail(result);
|
|
3321
|
+
this.changed();
|
|
3322
|
+
return;
|
|
3323
|
+
}
|
|
3324
|
+
this.close();
|
|
3213
3325
|
}, (error) => {
|
|
3214
3326
|
if (generation !== this.#generation)
|
|
3215
3327
|
return;
|
|
@@ -3219,7 +3331,7 @@ class PickerPanel {
|
|
|
3219
3331
|
});
|
|
3220
3332
|
} else {
|
|
3221
3333
|
this.search.handleInput(data);
|
|
3222
|
-
this.#index =
|
|
3334
|
+
this.#index = this.#firstSelectable(this.#filtered());
|
|
3223
3335
|
}
|
|
3224
3336
|
this.changed();
|
|
3225
3337
|
}
|
|
@@ -3227,6 +3339,15 @@ class PickerPanel {
|
|
|
3227
3339
|
const height = Math.max(1, this.height);
|
|
3228
3340
|
const w = Math.max(1, width - 2);
|
|
3229
3341
|
const rows = [style.bold(this.#title)];
|
|
3342
|
+
if (this.#detail !== undefined) {
|
|
3343
|
+
const body = this.#detail.lines(w, Math.max(1, height - 2));
|
|
3344
|
+
rows.push(...body);
|
|
3345
|
+
while (rows.length < height - 1)
|
|
3346
|
+
rows.push("");
|
|
3347
|
+
if (height > 1)
|
|
3348
|
+
rows.push(this.#detail.help);
|
|
3349
|
+
return rows.slice(0, height).map((line) => theme.panel(` ${truncateToWidth3(line, w, "...", true)} `));
|
|
3350
|
+
}
|
|
3230
3351
|
if (height >= 4)
|
|
3231
3352
|
rows.push(...this.search.render(w).slice(0, 1));
|
|
3232
3353
|
const help = this.#state === "error" ? labels.retry : this.#state === "ready" ? labels.select : labels.close;
|
|
@@ -3236,11 +3357,20 @@ class PickerPanel {
|
|
|
3236
3357
|
else {
|
|
3237
3358
|
const items = this.#filtered();
|
|
3238
3359
|
this.#index = Math.min(this.#index, Math.max(0, items.length - 1));
|
|
3360
|
+
if (items[this.#index]?.header) {
|
|
3361
|
+
const first = this.#firstSelectable(items);
|
|
3362
|
+
if (first >= 0)
|
|
3363
|
+
this.#index = first;
|
|
3364
|
+
}
|
|
3239
3365
|
const selected = items[this.#index];
|
|
3240
3366
|
const details = height >= 9 && selected?.description ? wrapTextWithAnsi(selected.description, w).slice(0, 2) : [];
|
|
3241
3367
|
const count = Math.max(1, available - details.length);
|
|
3242
3368
|
const start = Math.max(0, Math.min(this.#index - Math.floor(count / 2), items.length - count));
|
|
3243
3369
|
for (const [i, item] of items.slice(start, start + count).entries()) {
|
|
3370
|
+
if (item.header) {
|
|
3371
|
+
rows.push(theme.dim(` ${item.label}`));
|
|
3372
|
+
continue;
|
|
3373
|
+
}
|
|
3244
3374
|
const right = item.rightLabel ?? "";
|
|
3245
3375
|
const leftWidth = Math.max(1, w - 3 - visibleWidth2(right));
|
|
3246
3376
|
const left = truncateToWidth3(item.label, leftWidth, "...");
|
|
@@ -3341,7 +3471,7 @@ ${theme.error(state.note)}`;
|
|
|
3341
3471
|
});
|
|
3342
3472
|
|
|
3343
3473
|
// packages/tui/src/components/user-message.ts
|
|
3344
|
-
import { Container as Container4, Markdown as Markdown2 } from "@earendil-works/pi-tui";
|
|
3474
|
+
import { Container as Container4, Markdown as Markdown2, Text as Text4 } from "@earendil-works/pi-tui";
|
|
3345
3475
|
var UserMessageComponent;
|
|
3346
3476
|
var init_user_message = __esm(() => {
|
|
3347
3477
|
init_theme();
|
|
@@ -3358,6 +3488,16 @@ var init_user_message = __esm(() => {
|
|
|
3358
3488
|
}
|
|
3359
3489
|
#rebuild() {
|
|
3360
3490
|
this.clear();
|
|
3491
|
+
const invocation = parseSkillInvocation(this.#text);
|
|
3492
|
+
if (invocation !== null) {
|
|
3493
|
+
const args = invocation.args.replace(/\s+/g, " ").trim();
|
|
3494
|
+
const preview = args.length > 100 ? `${args.slice(0, 99)}\u2026` : args;
|
|
3495
|
+
const head = `${theme.toolTitle(`\u2726 skill:${invocation.name}`)}${preview ? ` ${theme.userText(preview)}` : ""}`;
|
|
3496
|
+
const source = theme.dim(`skill body from ${invocation.location} (collapsed)`);
|
|
3497
|
+
this.addChild(new Text4(`${head}
|
|
3498
|
+
${source}`, 1, 0, theme.userBg));
|
|
3499
|
+
return;
|
|
3500
|
+
}
|
|
3361
3501
|
this.addChild(new Markdown2(this.#text, 1, 0, getMarkdownTheme(), {
|
|
3362
3502
|
color: theme.userText,
|
|
3363
3503
|
bgColor: theme.userBg
|
|
@@ -3621,7 +3761,7 @@ var init_file_completion = __esm(() => {
|
|
|
3621
3761
|
|
|
3622
3762
|
// packages/gateway/src/contract.ts
|
|
3623
3763
|
import { defineService } from "@earendil-works/chord";
|
|
3624
|
-
var NekoSessionDirectory, NekoSessionManagement, NekoModels, NekoChat, NekoWorkspaces, NekoCredentials, NekoWorkspaceFiles;
|
|
3764
|
+
var NekoSessionDirectory, NekoSessionManagement, NekoModels, NekoChat, NekoWorkspaces, NekoCredentials, NekoWorkspaceFiles, NekoSkillMarket;
|
|
3625
3765
|
var init_contract = __esm(() => {
|
|
3626
3766
|
NekoSessionDirectory = defineService("neko.session-directory");
|
|
3627
3767
|
NekoSessionManagement = defineService("neko.session-management");
|
|
@@ -3630,6 +3770,7 @@ var init_contract = __esm(() => {
|
|
|
3630
3770
|
NekoWorkspaces = defineService("neko.workspaces");
|
|
3631
3771
|
NekoCredentials = defineService("neko.credentials");
|
|
3632
3772
|
NekoWorkspaceFiles = defineService("neko.workspace-files");
|
|
3773
|
+
NekoSkillMarket = defineService("neko.skill-market");
|
|
3633
3774
|
});
|
|
3634
3775
|
|
|
3635
3776
|
// packages/gateway/src/ws-listener.ts
|
|
@@ -3782,7 +3923,8 @@ async function connectNekoGateway(address) {
|
|
|
3782
3923
|
NekoModels,
|
|
3783
3924
|
NekoWorkspaces,
|
|
3784
3925
|
NekoWorkspaceFiles,
|
|
3785
|
-
NekoCredentials
|
|
3926
|
+
NekoCredentials,
|
|
3927
|
+
NekoSkillMarket
|
|
3786
3928
|
],
|
|
3787
3929
|
transport: serverTransport
|
|
3788
3930
|
});
|
|
@@ -3798,6 +3940,7 @@ async function connectNekoGateway(address) {
|
|
|
3798
3940
|
workspaces: serverBinding.use(NekoWorkspaces),
|
|
3799
3941
|
workspaceFiles: serverBinding.use(NekoWorkspaceFiles),
|
|
3800
3942
|
credentials: serverBinding.use(NekoCredentials),
|
|
3943
|
+
skillMarket: serverBinding.use(NekoSkillMarket),
|
|
3801
3944
|
listModels: () => models.list(BACKGROUND_CONTEXT2),
|
|
3802
3945
|
async attach(sessionId) {
|
|
3803
3946
|
await sessionBinding?.dispose(BACKGROUND_CONTEXT2).catch(() => {});
|
|
@@ -3913,10 +4056,617 @@ function fileSearchInstallHelp(platform = process.platform) {
|
|
|
3913
4056
|
return `\u672A\u627E\u5230 fd \u6216 fdfind\uFF0C\u6682\u65F6\u65E0\u6CD5\u4F7F\u7528 @ \u6587\u4EF6\u8865\u5168\u3002\u8BF7\u5728\u8FD0\u884C neko \u7684\u7535\u8111\u4E0A\u5B89\u88C5\u3002${install}\u5B89\u88C5\u540E\u91CD\u65B0\u6253\u5F00\u7EC8\u7AEF\u5E76\u91CD\u542F neko\u3002`;
|
|
3914
4057
|
}
|
|
3915
4058
|
|
|
4059
|
+
// node_modules/fflate/esm/index.mjs
|
|
4060
|
+
import { createRequire } from "module";
|
|
4061
|
+
function inflateSync(data, opts) {
|
|
4062
|
+
return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);
|
|
4063
|
+
}
|
|
4064
|
+
function strFromU8(dat, latin1) {
|
|
4065
|
+
if (latin1) {
|
|
4066
|
+
var r = "";
|
|
4067
|
+
for (var i = 0;i < dat.length; i += 16384)
|
|
4068
|
+
r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));
|
|
4069
|
+
return r;
|
|
4070
|
+
} else if (td) {
|
|
4071
|
+
return td.decode(dat);
|
|
4072
|
+
} else {
|
|
4073
|
+
var _a = dutf8(dat), { s, r } = _a;
|
|
4074
|
+
if (r.length)
|
|
4075
|
+
err(8);
|
|
4076
|
+
return s;
|
|
4077
|
+
}
|
|
4078
|
+
}
|
|
4079
|
+
function unzipSync(data, opts) {
|
|
4080
|
+
var files = {};
|
|
4081
|
+
var e = data.length - 22;
|
|
4082
|
+
for (;b4(data, e) != 101010256; --e) {
|
|
4083
|
+
if (!e || data.length - e > 65558)
|
|
4084
|
+
err(13);
|
|
4085
|
+
}
|
|
4086
|
+
var c = b2(data, e + 8);
|
|
4087
|
+
if (!c)
|
|
4088
|
+
return {};
|
|
4089
|
+
var o = b4(data, e + 16);
|
|
4090
|
+
var z = b4(data, e - 20) == 117853008;
|
|
4091
|
+
if (z) {
|
|
4092
|
+
var ze = b4(data, e - 12);
|
|
4093
|
+
z = b4(data, ze) == 101075792;
|
|
4094
|
+
if (z) {
|
|
4095
|
+
c = b4(data, ze + 32);
|
|
4096
|
+
o = b4(data, ze + 48);
|
|
4097
|
+
}
|
|
4098
|
+
}
|
|
4099
|
+
var fltr = opts && opts.filter;
|
|
4100
|
+
for (var i = 0;i < c; ++i) {
|
|
4101
|
+
var _a = zh(data, o, z), c_2 = _a[0], sc = _a[1], su = _a[2], fn = _a[3], no = _a[4], off = _a[5], b = slzh(data, off);
|
|
4102
|
+
o = no;
|
|
4103
|
+
if (!fltr || fltr({
|
|
4104
|
+
name: fn,
|
|
4105
|
+
size: sc,
|
|
4106
|
+
originalSize: su,
|
|
4107
|
+
compression: c_2
|
|
4108
|
+
})) {
|
|
4109
|
+
if (!c_2)
|
|
4110
|
+
files[fn] = slc(data, b, b + sc);
|
|
4111
|
+
else if (c_2 == 8)
|
|
4112
|
+
files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) });
|
|
4113
|
+
else
|
|
4114
|
+
err(14, "unknown compression type " + c_2);
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
return files;
|
|
4118
|
+
}
|
|
4119
|
+
var require2, _a, Worker, isMarkedAsUntransferable, u8, u16, i32, fleb, fdeb, clim, freb = function(eb, start) {
|
|
4120
|
+
var b = new u16(31);
|
|
4121
|
+
for (var i = 0;i < 31; ++i) {
|
|
4122
|
+
b[i] = start += 1 << eb[i - 1];
|
|
4123
|
+
}
|
|
4124
|
+
var r = new i32(b[30]);
|
|
4125
|
+
for (var i = 1;i < 30; ++i) {
|
|
4126
|
+
for (var j = b[i];j < b[i + 1]; ++j) {
|
|
4127
|
+
r[j] = j - b[i] << 5 | i;
|
|
4128
|
+
}
|
|
4129
|
+
}
|
|
4130
|
+
return { b, r };
|
|
4131
|
+
}, _a, fl, revfl, _b, fd, revfd, rev, x, i, hMap = function(cd, mb, r) {
|
|
4132
|
+
var s = cd.length;
|
|
4133
|
+
var i = 0;
|
|
4134
|
+
var l = new u16(mb);
|
|
4135
|
+
for (;i < s; ++i) {
|
|
4136
|
+
if (cd[i])
|
|
4137
|
+
++l[cd[i] - 1];
|
|
4138
|
+
}
|
|
4139
|
+
var le = new u16(mb);
|
|
4140
|
+
for (i = 1;i < mb; ++i) {
|
|
4141
|
+
le[i] = le[i - 1] + l[i - 1] << 1;
|
|
4142
|
+
}
|
|
4143
|
+
var co;
|
|
4144
|
+
if (r) {
|
|
4145
|
+
co = new u16(1 << mb);
|
|
4146
|
+
var rvb = 15 - mb;
|
|
4147
|
+
for (i = 0;i < s; ++i) {
|
|
4148
|
+
if (cd[i]) {
|
|
4149
|
+
var sv = i << 4 | cd[i];
|
|
4150
|
+
var r_1 = mb - cd[i];
|
|
4151
|
+
var v = le[cd[i] - 1]++ << r_1;
|
|
4152
|
+
for (var m = v | (1 << r_1) - 1;v <= m; ++v) {
|
|
4153
|
+
co[rev[v] >> rvb] = sv;
|
|
4154
|
+
}
|
|
4155
|
+
}
|
|
4156
|
+
}
|
|
4157
|
+
} else {
|
|
4158
|
+
co = new u16(s);
|
|
4159
|
+
for (i = 0;i < s; ++i) {
|
|
4160
|
+
if (cd[i]) {
|
|
4161
|
+
co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];
|
|
4162
|
+
}
|
|
4163
|
+
}
|
|
4164
|
+
}
|
|
4165
|
+
return co;
|
|
4166
|
+
}, flt, i, i, i, i, fdt, i, flrm, fdrm, max = function(a) {
|
|
4167
|
+
var m = a[0];
|
|
4168
|
+
for (var i = 1;i < a.length; ++i) {
|
|
4169
|
+
if (a[i] > m)
|
|
4170
|
+
m = a[i];
|
|
4171
|
+
}
|
|
4172
|
+
return m;
|
|
4173
|
+
}, bits = function(d, p, m) {
|
|
4174
|
+
var o = p / 8 | 0;
|
|
4175
|
+
return (d[o] | d[o + 1] << 8) >> (p & 7) & m;
|
|
4176
|
+
}, bits16 = function(d, p) {
|
|
4177
|
+
var o = p / 8 | 0;
|
|
4178
|
+
return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);
|
|
4179
|
+
}, shft = function(p) {
|
|
4180
|
+
return (p + 7) / 8 | 0;
|
|
4181
|
+
}, slc = function(v, s, e) {
|
|
4182
|
+
if (s == null || s < 0)
|
|
4183
|
+
s = 0;
|
|
4184
|
+
if (e == null || e > v.length)
|
|
4185
|
+
e = v.length;
|
|
4186
|
+
return new u8(v.subarray(s, e));
|
|
4187
|
+
}, ec, err = function(ind, msg, nt) {
|
|
4188
|
+
var e = new Error(msg || ec[ind]);
|
|
4189
|
+
e.code = ind;
|
|
4190
|
+
if (Error.captureStackTrace)
|
|
4191
|
+
Error.captureStackTrace(e, err);
|
|
4192
|
+
if (!nt)
|
|
4193
|
+
throw e;
|
|
4194
|
+
return e;
|
|
4195
|
+
}, inflt = function(dat, st, buf, dict) {
|
|
4196
|
+
var sl = dat.length, dl = dict ? dict.length : 0;
|
|
4197
|
+
if (!sl || st.f && !st.l)
|
|
4198
|
+
return buf || new u8(0);
|
|
4199
|
+
var noBuf = !buf;
|
|
4200
|
+
var resize = noBuf || st.i != 2;
|
|
4201
|
+
var noSt = st.i;
|
|
4202
|
+
if (noBuf)
|
|
4203
|
+
buf = new u8(sl * 3);
|
|
4204
|
+
var cbuf = function(l) {
|
|
4205
|
+
var bl = buf.length;
|
|
4206
|
+
if (l > bl) {
|
|
4207
|
+
var nbuf = new u8(Math.max(bl * 2, l));
|
|
4208
|
+
nbuf.set(buf);
|
|
4209
|
+
buf = nbuf;
|
|
4210
|
+
}
|
|
4211
|
+
};
|
|
4212
|
+
var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, { l: lm, d: dm, m: lbt, n: dbt } = st;
|
|
4213
|
+
var tbts = sl * 8;
|
|
4214
|
+
do {
|
|
4215
|
+
if (!lm) {
|
|
4216
|
+
final = bits(dat, pos, 1);
|
|
4217
|
+
var type = bits(dat, pos + 1, 3);
|
|
4218
|
+
pos += 3;
|
|
4219
|
+
if (!type) {
|
|
4220
|
+
var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;
|
|
4221
|
+
if (t > sl) {
|
|
4222
|
+
if (noSt)
|
|
4223
|
+
err(0);
|
|
4224
|
+
break;
|
|
4225
|
+
}
|
|
4226
|
+
if (resize)
|
|
4227
|
+
cbuf(bt + l);
|
|
4228
|
+
buf.set(dat.subarray(s, t), bt);
|
|
4229
|
+
st.b = bt += l, st.p = pos = t * 8, st.f = final;
|
|
4230
|
+
continue;
|
|
4231
|
+
} else if (type == 1)
|
|
4232
|
+
lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
|
|
4233
|
+
else if (type == 2) {
|
|
4234
|
+
var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
|
|
4235
|
+
var tl = hLit + bits(dat, pos + 5, 31) + 1;
|
|
4236
|
+
pos += 14;
|
|
4237
|
+
var ldt = new u8(tl);
|
|
4238
|
+
var clt = new u8(19);
|
|
4239
|
+
for (var i = 0;i < hcLen; ++i) {
|
|
4240
|
+
clt[clim[i]] = bits(dat, pos + i * 3, 7);
|
|
4241
|
+
}
|
|
4242
|
+
pos += hcLen * 3;
|
|
4243
|
+
var clb = max(clt), clbmsk = (1 << clb) - 1;
|
|
4244
|
+
var clm = hMap(clt, clb, 1);
|
|
4245
|
+
for (var i = 0;i < tl; ) {
|
|
4246
|
+
var r = clm[bits(dat, pos, clbmsk)];
|
|
4247
|
+
pos += r & 15;
|
|
4248
|
+
var s = r >> 4;
|
|
4249
|
+
if (s < 16) {
|
|
4250
|
+
ldt[i++] = s;
|
|
4251
|
+
} else {
|
|
4252
|
+
var c = 0, n = 0;
|
|
4253
|
+
if (s == 16)
|
|
4254
|
+
n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];
|
|
4255
|
+
else if (s == 17)
|
|
4256
|
+
n = 3 + bits(dat, pos, 7), pos += 3;
|
|
4257
|
+
else if (s == 18)
|
|
4258
|
+
n = 11 + bits(dat, pos, 127), pos += 7;
|
|
4259
|
+
while (n--)
|
|
4260
|
+
ldt[i++] = c;
|
|
4261
|
+
}
|
|
4262
|
+
}
|
|
4263
|
+
var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
|
|
4264
|
+
lbt = max(lt);
|
|
4265
|
+
dbt = max(dt);
|
|
4266
|
+
lm = hMap(lt, lbt, 1);
|
|
4267
|
+
dm = hMap(dt, dbt, 1);
|
|
4268
|
+
} else
|
|
4269
|
+
err(1);
|
|
4270
|
+
if (pos > tbts) {
|
|
4271
|
+
if (noSt)
|
|
4272
|
+
err(0);
|
|
4273
|
+
break;
|
|
4274
|
+
}
|
|
4275
|
+
}
|
|
4276
|
+
if (resize)
|
|
4277
|
+
cbuf(bt + 131072);
|
|
4278
|
+
var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
|
|
4279
|
+
var lpos = pos;
|
|
4280
|
+
for (;; lpos = pos) {
|
|
4281
|
+
var c = lm[bits16(dat, pos) & lms], sym = c >> 4;
|
|
4282
|
+
pos += c & 15;
|
|
4283
|
+
if (pos > tbts) {
|
|
4284
|
+
if (noSt)
|
|
4285
|
+
err(0);
|
|
4286
|
+
break;
|
|
4287
|
+
}
|
|
4288
|
+
if (!c)
|
|
4289
|
+
err(2);
|
|
4290
|
+
if (sym < 256)
|
|
4291
|
+
buf[bt++] = sym;
|
|
4292
|
+
else if (sym == 256) {
|
|
4293
|
+
lpos = pos, lm = null;
|
|
4294
|
+
break;
|
|
4295
|
+
} else {
|
|
4296
|
+
var add = sym - 254;
|
|
4297
|
+
if (sym > 264) {
|
|
4298
|
+
var i = sym - 257, b = fleb[i];
|
|
4299
|
+
add = bits(dat, pos, (1 << b) - 1) + fl[i];
|
|
4300
|
+
pos += b;
|
|
4301
|
+
}
|
|
4302
|
+
var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;
|
|
4303
|
+
if (!d)
|
|
4304
|
+
err(3);
|
|
4305
|
+
pos += d & 15;
|
|
4306
|
+
var dt = fd[dsym];
|
|
4307
|
+
if (dsym > 3) {
|
|
4308
|
+
var b = fdeb[dsym];
|
|
4309
|
+
dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
|
|
4310
|
+
}
|
|
4311
|
+
if (pos > tbts) {
|
|
4312
|
+
if (noSt)
|
|
4313
|
+
err(0);
|
|
4314
|
+
break;
|
|
4315
|
+
}
|
|
4316
|
+
if (resize)
|
|
4317
|
+
cbuf(bt + 131072);
|
|
4318
|
+
var end = bt + add;
|
|
4319
|
+
if (bt < dt) {
|
|
4320
|
+
var shift = dl - dt, dend = Math.min(dt, end);
|
|
4321
|
+
if (shift + bt < 0)
|
|
4322
|
+
err(3);
|
|
4323
|
+
for (;bt < dend; ++bt)
|
|
4324
|
+
buf[bt] = dict[shift + bt];
|
|
4325
|
+
}
|
|
4326
|
+
for (;bt < end; ++bt)
|
|
4327
|
+
buf[bt] = buf[bt - dt];
|
|
4328
|
+
}
|
|
4329
|
+
}
|
|
4330
|
+
st.l = lm, st.p = lpos, st.b = bt, st.f = final;
|
|
4331
|
+
if (lm)
|
|
4332
|
+
final = 1, st.m = lbt, st.d = dm, st.n = dbt;
|
|
4333
|
+
} while (!final);
|
|
4334
|
+
return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
|
|
4335
|
+
}, et, b2 = function(d, b) {
|
|
4336
|
+
return d[b] | d[b + 1] << 8;
|
|
4337
|
+
}, b4 = function(d, b) {
|
|
4338
|
+
return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
|
|
4339
|
+
}, b8 = function(d, b) {
|
|
4340
|
+
return b4(d, b) + b4(d, b + 4) * 4294967296;
|
|
4341
|
+
}, td, tds = 0, dutf8 = function(d) {
|
|
4342
|
+
for (var r = "", i = 0;; ) {
|
|
4343
|
+
var c = d[i++];
|
|
4344
|
+
var eb = (c > 127) + (c > 223) + (c > 239);
|
|
4345
|
+
if (i + eb > d.length)
|
|
4346
|
+
return { s: r, r: slc(d, i - 1) };
|
|
4347
|
+
if (!eb)
|
|
4348
|
+
r += String.fromCharCode(c);
|
|
4349
|
+
else if (eb == 3) {
|
|
4350
|
+
c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | d[i++] & 63) - 65536, r += String.fromCharCode(55296 | c >> 10, 56320 | c & 1023);
|
|
4351
|
+
} else if (eb & 1)
|
|
4352
|
+
r += String.fromCharCode((c & 31) << 6 | d[i++] & 63);
|
|
4353
|
+
else
|
|
4354
|
+
r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | d[i++] & 63);
|
|
4355
|
+
}
|
|
4356
|
+
}, slzh = function(d, b) {
|
|
4357
|
+
return b + 30 + b2(d, b + 26) + b2(d, b + 28);
|
|
4358
|
+
}, zh = function(d, b, z) {
|
|
4359
|
+
var fnl = b2(d, b + 28), efl = b2(d, b + 30), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl;
|
|
4360
|
+
var _a = z64hs(d, es, efl, z, b4(d, b + 20), b4(d, b + 24), b4(d, b + 42)), sc = _a[0], su = _a[1], off = _a[2];
|
|
4361
|
+
return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off];
|
|
4362
|
+
}, z64hs = function(d, b, l, z, sc, su, off) {
|
|
4363
|
+
var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l;
|
|
4364
|
+
var nf = nsc + nsu + noff;
|
|
4365
|
+
if (z && nf) {
|
|
4366
|
+
for (;b + 4 < e; b += 4 + b2(d, b + 2)) {
|
|
4367
|
+
if (b2(d, b) == 1) {
|
|
4368
|
+
return [
|
|
4369
|
+
nsc ? b8(d, b + 4 + 8 * nsu) : sc,
|
|
4370
|
+
nsu ? b8(d, b + 4) : su,
|
|
4371
|
+
noff ? b8(d, b + 4 + 8 * (nsu + nsc)) : off,
|
|
4372
|
+
1
|
|
4373
|
+
];
|
|
4374
|
+
}
|
|
4375
|
+
}
|
|
4376
|
+
if (z < 2)
|
|
4377
|
+
err(13);
|
|
4378
|
+
}
|
|
4379
|
+
return [sc, su, off, 0];
|
|
4380
|
+
};
|
|
4381
|
+
var init_esm = __esm(() => {
|
|
4382
|
+
require2 = createRequire("/");
|
|
4383
|
+
try {
|
|
4384
|
+
_a = require2("worker_threads"), Worker = _a.Worker, isMarkedAsUntransferable = _a.isMarkedAsUntransferable;
|
|
4385
|
+
} catch (e) {}
|
|
4386
|
+
u8 = Uint8Array;
|
|
4387
|
+
u16 = Uint16Array;
|
|
4388
|
+
i32 = Int32Array;
|
|
4389
|
+
fleb = new u8([0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0, 0]);
|
|
4390
|
+
fdeb = new u8([0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0]);
|
|
4391
|
+
clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
|
|
4392
|
+
_a = freb(fleb, 2);
|
|
4393
|
+
fl = _a.b;
|
|
4394
|
+
revfl = _a.r;
|
|
4395
|
+
fl[28] = 258, revfl[258] = 28;
|
|
4396
|
+
_b = freb(fdeb, 0);
|
|
4397
|
+
fd = _b.b;
|
|
4398
|
+
revfd = _b.r;
|
|
4399
|
+
rev = new u16(32768);
|
|
4400
|
+
for (i = 0;i < 32768; ++i) {
|
|
4401
|
+
x = (i & 43690) >> 1 | (i & 21845) << 1;
|
|
4402
|
+
x = (x & 52428) >> 2 | (x & 13107) << 2;
|
|
4403
|
+
x = (x & 61680) >> 4 | (x & 3855) << 4;
|
|
4404
|
+
rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
|
|
4405
|
+
}
|
|
4406
|
+
flt = new u8(288);
|
|
4407
|
+
for (i = 0;i < 144; ++i)
|
|
4408
|
+
flt[i] = 8;
|
|
4409
|
+
for (i = 144;i < 256; ++i)
|
|
4410
|
+
flt[i] = 9;
|
|
4411
|
+
for (i = 256;i < 280; ++i)
|
|
4412
|
+
flt[i] = 7;
|
|
4413
|
+
for (i = 280;i < 288; ++i)
|
|
4414
|
+
flt[i] = 8;
|
|
4415
|
+
fdt = new u8(32);
|
|
4416
|
+
for (i = 0;i < 32; ++i)
|
|
4417
|
+
fdt[i] = 5;
|
|
4418
|
+
flrm = /* @__PURE__ */ hMap(flt, 9, 1);
|
|
4419
|
+
fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);
|
|
4420
|
+
ec = [
|
|
4421
|
+
"unexpected EOF",
|
|
4422
|
+
"invalid block type",
|
|
4423
|
+
"invalid length/literal",
|
|
4424
|
+
"invalid distance",
|
|
4425
|
+
"stream finished",
|
|
4426
|
+
"no stream handler",
|
|
4427
|
+
,
|
|
4428
|
+
"no callback",
|
|
4429
|
+
"invalid UTF-8 data",
|
|
4430
|
+
"extra field too long",
|
|
4431
|
+
"date not in range 1980-2099",
|
|
4432
|
+
"filename too long",
|
|
4433
|
+
"stream finishing",
|
|
4434
|
+
"invalid zip data"
|
|
4435
|
+
];
|
|
4436
|
+
et = /* @__PURE__ */ new u8(0);
|
|
4437
|
+
td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder;
|
|
4438
|
+
try {
|
|
4439
|
+
td.decode(et, { stream: true });
|
|
4440
|
+
tds = 1;
|
|
4441
|
+
} catch (e) {}
|
|
4442
|
+
});
|
|
4443
|
+
|
|
4444
|
+
// packages/gateway/src/skill-market.ts
|
|
4445
|
+
import { createHash as createHash2, randomUUID } from "crypto";
|
|
4446
|
+
import { mkdir as mkdir2, readdir as readdir2, rename as rename2, rm as rm2, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
4447
|
+
import { homedir as homedir5 } from "os";
|
|
4448
|
+
import { dirname as dirname5, join as join8 } from "path";
|
|
4449
|
+
function createSkillMarketClient(options) {
|
|
4450
|
+
const home = options.home ?? homedir5();
|
|
4451
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
4452
|
+
const now = options.now ?? Date.now;
|
|
4453
|
+
let base;
|
|
4454
|
+
try {
|
|
4455
|
+
base = new URL(options.marketUrl);
|
|
4456
|
+
if (base.protocol !== "https:" && base.protocol !== "http:")
|
|
4457
|
+
throw new Error("unsupported protocol");
|
|
4458
|
+
} catch {
|
|
4459
|
+
throw new SkillMarketError("market_invalid_url", `Invalid skill market URL: ${options.marketUrl}`);
|
|
4460
|
+
}
|
|
4461
|
+
base = new URL(base.toString().replace(/\/+$/, ""));
|
|
4462
|
+
let catalog;
|
|
4463
|
+
const zipCache = new Map;
|
|
4464
|
+
const request = async (path) => {
|
|
4465
|
+
let response;
|
|
4466
|
+
try {
|
|
4467
|
+
response = await fetchImpl(new URL(path, `${base}/`).toString());
|
|
4468
|
+
} catch (error) {
|
|
4469
|
+
throw new SkillMarketError("market_unavailable", `Skill market unreachable: ${error instanceof Error ? error.message : String(error)}`);
|
|
4470
|
+
}
|
|
4471
|
+
return response;
|
|
4472
|
+
};
|
|
4473
|
+
const refreshCatalog = async () => {
|
|
4474
|
+
const response = await request("api/skills");
|
|
4475
|
+
if (!response.ok)
|
|
4476
|
+
throw new SkillMarketError("market_unavailable", `Skill list failed with HTTP ${response.status}`);
|
|
4477
|
+
const data = await response.json();
|
|
4478
|
+
const skills = Array.isArray(data.skills) ? data.skills.map(normalizeEntry) : [];
|
|
4479
|
+
catalog = { at: now(), skills };
|
|
4480
|
+
return skills;
|
|
4481
|
+
};
|
|
4482
|
+
const listSkills = async () => catalog !== undefined && now() - catalog.at < CATALOG_TTL_MS ? catalog.skills : refreshCatalog();
|
|
4483
|
+
const detail = async (name) => {
|
|
4484
|
+
let hit = (await listSkills()).find((skill) => skill.name === name);
|
|
4485
|
+
if (hit === undefined)
|
|
4486
|
+
hit = (await refreshCatalog()).find((skill) => skill.name === name);
|
|
4487
|
+
if (hit === undefined)
|
|
4488
|
+
throw new SkillMarketError("skill_not_found", `Skill not found on market: ${name}`);
|
|
4489
|
+
return hit;
|
|
4490
|
+
};
|
|
4491
|
+
const download = async (skill) => {
|
|
4492
|
+
const cached = zipCache.get(skill.sha256);
|
|
4493
|
+
if (cached !== undefined) {
|
|
4494
|
+
zipCache.delete(skill.sha256);
|
|
4495
|
+
zipCache.set(skill.sha256, cached);
|
|
4496
|
+
return cached;
|
|
4497
|
+
}
|
|
4498
|
+
if (skill.sizeBytes > MAX_PACKAGE_BYTES)
|
|
4499
|
+
throw new SkillMarketError("skill_too_large", `Package ${skill.name} is ${skill.sizeBytes} bytes (limit ${MAX_PACKAGE_BYTES})`);
|
|
4500
|
+
const response = await request(`api/skills/${encodeURIComponent(skill.name)}/download`);
|
|
4501
|
+
if (!response.ok)
|
|
4502
|
+
throw new SkillMarketError(response.status === 404 ? "skill_not_found" : "market_unavailable", `Download of ${skill.name} failed with HTTP ${response.status}`);
|
|
4503
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
4504
|
+
if (bytes.byteLength > MAX_PACKAGE_BYTES)
|
|
4505
|
+
throw new SkillMarketError("skill_too_large", `Package ${skill.name} exceeds ${MAX_PACKAGE_BYTES} bytes`);
|
|
4506
|
+
const digest = createHash2("sha256").update(bytes).digest("hex");
|
|
4507
|
+
if (digest !== skill.sha256)
|
|
4508
|
+
throw new SkillMarketError("skill_hash_mismatch", `SHA-256 mismatch for ${skill.name}: catalog says ${skill.sha256}, got ${digest}`);
|
|
4509
|
+
zipCache.set(skill.sha256, bytes);
|
|
4510
|
+
while (zipCache.size > ZIP_CACHE_MAX) {
|
|
4511
|
+
const oldest = zipCache.keys().next().value;
|
|
4512
|
+
if (oldest === undefined)
|
|
4513
|
+
break;
|
|
4514
|
+
zipCache.delete(oldest);
|
|
4515
|
+
}
|
|
4516
|
+
return bytes;
|
|
4517
|
+
};
|
|
4518
|
+
const unpack = (skill, zip) => {
|
|
4519
|
+
let entries;
|
|
4520
|
+
try {
|
|
4521
|
+
entries = unzipSync(zip);
|
|
4522
|
+
} catch {
|
|
4523
|
+
throw new SkillMarketError("skill_invalid_package", `Package ${skill.name} is not a valid zip archive`);
|
|
4524
|
+
}
|
|
4525
|
+
const files = new Map;
|
|
4526
|
+
const skillMds = [];
|
|
4527
|
+
for (const name of Object.keys(entries)) {
|
|
4528
|
+
if (name.endsWith("/"))
|
|
4529
|
+
continue;
|
|
4530
|
+
if (name.includes("\\") || name.startsWith("/"))
|
|
4531
|
+
throw new SkillMarketError("skill_invalid_package", `Unsafe path in package: ${name}`);
|
|
4532
|
+
const segments = name.split("/");
|
|
4533
|
+
if (segments.some((s) => s === ".." || s === ""))
|
|
4534
|
+
throw new SkillMarketError("skill_invalid_package", `Unsafe path in package: ${name}`);
|
|
4535
|
+
if (segments[segments.length - 1] === "SKILL.md")
|
|
4536
|
+
skillMds.push(name);
|
|
4537
|
+
files.set(name, entries[name]);
|
|
4538
|
+
}
|
|
4539
|
+
if (skillMds.length !== 1)
|
|
4540
|
+
throw new SkillMarketError("skill_invalid_package", skillMds.length === 0 ? `Package ${skill.name} contains no SKILL.md` : `Package ${skill.name} contains multiple SKILL.md files`);
|
|
4541
|
+
const root = skillMds[0].slice(0, -"SKILL.md".length);
|
|
4542
|
+
const inner = new Map;
|
|
4543
|
+
for (const [name, bytes] of files) {
|
|
4544
|
+
if (!name.startsWith(root))
|
|
4545
|
+
continue;
|
|
4546
|
+
inner.set(name.slice(root.length), bytes);
|
|
4547
|
+
}
|
|
4548
|
+
return inner;
|
|
4549
|
+
};
|
|
4550
|
+
const skillsDirFor = (scope, workspaceRoot) => {
|
|
4551
|
+
if (scope === "user")
|
|
4552
|
+
return userSkillsDir2(home);
|
|
4553
|
+
if (workspaceRoot === undefined || workspaceRoot === "")
|
|
4554
|
+
throw new SkillMarketError("market_unavailable", "Project-scope install needs a workspaceRoot");
|
|
4555
|
+
return projectSkillsDir(workspaceRoot);
|
|
4556
|
+
};
|
|
4557
|
+
const sweepTempDirs = async (skillsDir) => {
|
|
4558
|
+
const parent = dirname5(skillsDir);
|
|
4559
|
+
let names = [];
|
|
4560
|
+
try {
|
|
4561
|
+
names = await readdir2(parent);
|
|
4562
|
+
} catch {
|
|
4563
|
+
return;
|
|
4564
|
+
}
|
|
4565
|
+
await Promise.all(names.filter((n) => n.startsWith(".tmp-")).map((n) => rm2(join8(parent, n), { recursive: true, force: true }).catch(() => {})));
|
|
4566
|
+
};
|
|
4567
|
+
const install = async ({ name, scope, workspaceRoot, overwrite }) => {
|
|
4568
|
+
const skillsDir = skillsDirFor(scope, workspaceRoot);
|
|
4569
|
+
const target = join8(skillsDir, name);
|
|
4570
|
+
const exists = await stat2(target).catch(() => {
|
|
4571
|
+
return;
|
|
4572
|
+
}) !== undefined;
|
|
4573
|
+
if (exists && overwrite !== true)
|
|
4574
|
+
throw new SkillMarketError("skill_exists", `Skill ${name} already exists at ${scope} level (${target})`);
|
|
4575
|
+
const skill = await detail(name);
|
|
4576
|
+
const files = unpack(skill, await download(skill));
|
|
4577
|
+
await sweepTempDirs(skillsDir);
|
|
4578
|
+
const temp = join8(dirname5(skillsDir), `.tmp-${randomUUID()}`);
|
|
4579
|
+
try {
|
|
4580
|
+
for (const [relative, bytes] of files) {
|
|
4581
|
+
const dest = join8(temp, ...relative.split("/"));
|
|
4582
|
+
await mkdir2(dirname5(dest), { recursive: true });
|
|
4583
|
+
await writeFile2(dest, bytes);
|
|
4584
|
+
}
|
|
4585
|
+
if (exists)
|
|
4586
|
+
await rm2(target, { recursive: true, force: true });
|
|
4587
|
+
await mkdir2(skillsDir, { recursive: true });
|
|
4588
|
+
await rename2(temp, target);
|
|
4589
|
+
} finally {
|
|
4590
|
+
await rm2(temp, { recursive: true, force: true }).catch(() => {});
|
|
4591
|
+
}
|
|
4592
|
+
let shadowedBy;
|
|
4593
|
+
if (scope === "user" && workspaceRoot !== undefined && workspaceRoot !== "") {
|
|
4594
|
+
const projectDir = join8(projectSkillsDir(workspaceRoot), name);
|
|
4595
|
+
if (await stat2(projectDir).catch(() => {
|
|
4596
|
+
return;
|
|
4597
|
+
}) !== undefined)
|
|
4598
|
+
shadowedBy = "project";
|
|
4599
|
+
}
|
|
4600
|
+
return { name, scope, path: target, ...shadowedBy !== undefined ? { shadowedBy } : {} };
|
|
4601
|
+
};
|
|
4602
|
+
const uninstall = async ({ name, scope, workspaceRoot }) => {
|
|
4603
|
+
const skillsDir = skillsDirFor(scope, workspaceRoot);
|
|
4604
|
+
const target = join8(skillsDir, name);
|
|
4605
|
+
if (await stat2(target).catch(() => {
|
|
4606
|
+
return;
|
|
4607
|
+
}) === undefined)
|
|
4608
|
+
throw new SkillMarketError("skill_not_installed", `Skill ${name} is not installed at ${scope} level`);
|
|
4609
|
+
await rm2(target, { recursive: true, force: true });
|
|
4610
|
+
};
|
|
4611
|
+
return {
|
|
4612
|
+
async list(query) {
|
|
4613
|
+
if (query !== undefined && query.trim() !== "") {
|
|
4614
|
+
const response = await request(`api/skills?q=${encodeURIComponent(query.trim())}`);
|
|
4615
|
+
if (!response.ok)
|
|
4616
|
+
throw new SkillMarketError("market_unavailable", `Skill search failed with HTTP ${response.status}`);
|
|
4617
|
+
const data = await response.json();
|
|
4618
|
+
return Array.isArray(data.skills) ? data.skills.map(normalizeEntry) : [];
|
|
4619
|
+
}
|
|
4620
|
+
return listSkills();
|
|
4621
|
+
},
|
|
4622
|
+
detail,
|
|
4623
|
+
async preview(name) {
|
|
4624
|
+
const skill = await detail(name);
|
|
4625
|
+
const inner = unpack(skill, await download(skill));
|
|
4626
|
+
const bodyBytes = inner.get("SKILL.md");
|
|
4627
|
+
if (bodyBytes === undefined)
|
|
4628
|
+
throw new SkillMarketError("skill_invalid_package", `Package ${name} lost its SKILL.md`);
|
|
4629
|
+
const body = stripFrontmatter(new TextDecoder().decode(bodyBytes));
|
|
4630
|
+
return { body, files: [...inner.keys()].sort() };
|
|
4631
|
+
},
|
|
4632
|
+
install,
|
|
4633
|
+
uninstall
|
|
4634
|
+
};
|
|
4635
|
+
}
|
|
4636
|
+
var SkillMarketError, CATALOG_TTL_MS = 60000, ZIP_CACHE_MAX = 16, MAX_PACKAGE_BYTES, userSkillsDir2 = (home) => join8(home, ".agents", "skills"), projectSkillsDir = (workspaceRoot) => join8(workspaceRoot, ".agents", "skills"), activeLevelOf = (state) => state.project ? "project" : state.user ? "user" : state.builtin ? "builtin" : null, normalizeEntry = (raw) => {
|
|
4637
|
+
const row = raw ?? {};
|
|
4638
|
+
const metadata = row.metadata;
|
|
4639
|
+
const source = metadata !== null && typeof metadata === "object" ? metadata.source : undefined;
|
|
4640
|
+
return {
|
|
4641
|
+
name: String(row.name ?? ""),
|
|
4642
|
+
description: String(row.description ?? ""),
|
|
4643
|
+
category: typeof row.category === "string" && row.category !== "" ? row.category : "uncategorized",
|
|
4644
|
+
source: typeof source === "string" && source !== "" ? source : "unknown",
|
|
4645
|
+
license: String(row.license ?? ""),
|
|
4646
|
+
version: String(row.version ?? ""),
|
|
4647
|
+
sha256: String(row.sha256 ?? ""),
|
|
4648
|
+
sizeBytes: Number(row.size_bytes ?? 0),
|
|
4649
|
+
uploadedAt: String(row.uploaded_at ?? "")
|
|
4650
|
+
};
|
|
4651
|
+
};
|
|
4652
|
+
var init_skill_market = __esm(() => {
|
|
4653
|
+
init_src();
|
|
4654
|
+
init_esm();
|
|
4655
|
+
SkillMarketError = class SkillMarketError extends Error {
|
|
4656
|
+
code;
|
|
4657
|
+
constructor(code, message) {
|
|
4658
|
+
super(message);
|
|
4659
|
+
this.name = "SkillMarketError";
|
|
4660
|
+
this.code = code;
|
|
4661
|
+
}
|
|
4662
|
+
};
|
|
4663
|
+
MAX_PACKAGE_BYTES = 32 * 1024 * 1024;
|
|
4664
|
+
});
|
|
4665
|
+
|
|
3916
4666
|
// packages/gateway/src/workspaces.ts
|
|
3917
4667
|
import { constants as constants3 } from "fs";
|
|
3918
|
-
import { access, readdir as
|
|
3919
|
-
import { dirname as
|
|
4668
|
+
import { access, readdir as readdir3, stat as stat3 } from "fs/promises";
|
|
4669
|
+
import { dirname as dirname6, isAbsolute as isAbsolute3, join as join9 } from "path";
|
|
3920
4670
|
async function browseWorkspaces(options) {
|
|
3921
4671
|
const requested = options.path.replace(/^\/+([A-Za-z]:[\\/])/, "$1");
|
|
3922
4672
|
if (process.platform === "win32" && (requested === "/" || requested === "\\")) {
|
|
@@ -3938,16 +4688,16 @@ async function browseWorkspaces(options) {
|
|
|
3938
4688
|
throw new Error("\u76EE\u5F55\u5206\u9875\u5DF2\u5931\u6548\uFF0C\u8BF7\u5237\u65B0\u5217\u8868");
|
|
3939
4689
|
}
|
|
3940
4690
|
}
|
|
3941
|
-
const entries = (await
|
|
4691
|
+
const entries = (await readdir3(path, { withFileTypes: true })).filter((entry) => (options.showHidden || !entry.name.startsWith(".")) && entry.name.toLowerCase().includes(query)).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
3942
4692
|
const directories = [];
|
|
3943
4693
|
let next = offset;
|
|
3944
4694
|
for (;next < entries.length && directories.length < 100; next++) {
|
|
3945
4695
|
const entry = entries[next];
|
|
3946
|
-
const target =
|
|
4696
|
+
const target = join9(path, entry.name);
|
|
3947
4697
|
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
3948
4698
|
continue;
|
|
3949
4699
|
try {
|
|
3950
|
-
if (!(await
|
|
4700
|
+
if (!(await stat3(target)).isDirectory())
|
|
3951
4701
|
continue;
|
|
3952
4702
|
await access(target, constants3.R_OK | constants3.X_OK);
|
|
3953
4703
|
directories.push({ name: entry.name, path: target });
|
|
@@ -3957,7 +4707,7 @@ async function browseWorkspaces(options) {
|
|
|
3957
4707
|
}
|
|
3958
4708
|
return {
|
|
3959
4709
|
path,
|
|
3960
|
-
parent:
|
|
4710
|
+
parent: dirname6(path) === path ? null : dirname6(path),
|
|
3961
4711
|
entries: directories,
|
|
3962
4712
|
next: next < entries.length ? JSON.stringify({ key, offset: next }) : null
|
|
3963
4713
|
};
|
|
@@ -3986,6 +4736,26 @@ import {
|
|
|
3986
4736
|
} from "@earendil-works/chord";
|
|
3987
4737
|
async function createNekoServerServices(options) {
|
|
3988
4738
|
const { runtime, context } = options;
|
|
4739
|
+
const market = createSkillMarketClient({
|
|
4740
|
+
marketUrl: options.marketUrl,
|
|
4741
|
+
...options.promptHome !== undefined ? { home: options.promptHome } : {}
|
|
4742
|
+
});
|
|
4743
|
+
const toRemote = (error) => {
|
|
4744
|
+
if (error instanceof SkillMarketError) {
|
|
4745
|
+
const code = error.code === "skill_not_found" || error.code === "skill_not_installed" ? "service_not_found" : "service_invalid_value";
|
|
4746
|
+
throw new RemoteServiceError(code, `[${error.code}] ${error.message}`);
|
|
4747
|
+
}
|
|
4748
|
+
throw error;
|
|
4749
|
+
};
|
|
4750
|
+
const withInstallState = async (skill, workspaceRoot) => {
|
|
4751
|
+
const locals = await runtime.listSkillsByLevel(workspaceRoot);
|
|
4752
|
+
const installed = {
|
|
4753
|
+
project: locals.some((s) => s.name === skill.name && s.level === "project"),
|
|
4754
|
+
user: locals.some((s) => s.name === skill.name && s.level === "user"),
|
|
4755
|
+
builtin: locals.some((s) => s.name === skill.name && s.level === "builtin")
|
|
4756
|
+
};
|
|
4757
|
+
return { ...skill, installed, activeLevel: activeLevelOf(installed) };
|
|
4758
|
+
};
|
|
3989
4759
|
const list = async () => (await runtime.listConversations()).map((info) => ({
|
|
3990
4760
|
id: String(info.id),
|
|
3991
4761
|
workspaceRoot: info.workspaceRoot,
|
|
@@ -4041,7 +4811,8 @@ async function createNekoServerServices(options) {
|
|
|
4041
4811
|
{ service: NekoModels, mode: "singleton" },
|
|
4042
4812
|
{ service: NekoCredentials, mode: "singleton" },
|
|
4043
4813
|
{ service: NekoWorkspaces, mode: "singleton" },
|
|
4044
|
-
{ service: NekoWorkspaceFiles, mode: "singleton" }
|
|
4814
|
+
{ service: NekoWorkspaceFiles, mode: "singleton" },
|
|
4815
|
+
{ service: NekoSkillMarket, mode: "singleton" }
|
|
4045
4816
|
]);
|
|
4046
4817
|
provider.provide(NekoSessionDirectory, { state: directory });
|
|
4047
4818
|
const updateCredentials = (operation) => serialize(async () => {
|
|
@@ -4091,6 +4862,13 @@ async function createNekoServerServices(options) {
|
|
|
4091
4862
|
}
|
|
4092
4863
|
});
|
|
4093
4864
|
provider.provide(NekoModels, { list: async () => runtime.listModels() });
|
|
4865
|
+
provider.provide(NekoSkillMarket, {
|
|
4866
|
+
list: (input) => market.list(input.query).then((skills) => Promise.all(skills.map((skill) => withInstallState(skill, input.workspaceRoot)))).catch(toRemote),
|
|
4867
|
+
detail: (input) => market.detail(input.name).then((skill) => withInstallState(skill, input.workspaceRoot)).catch(toRemote),
|
|
4868
|
+
preview: (input) => market.preview(input.name).catch(toRemote),
|
|
4869
|
+
install: (input) => serialize(() => market.install(input).then((result) => ({ ...result })).catch(toRemote)),
|
|
4870
|
+
uninstall: (input) => serialize(() => market.uninstall(input).catch(toRemote))
|
|
4871
|
+
});
|
|
4094
4872
|
provider.provide(NekoSessionManagement, {
|
|
4095
4873
|
create: (createOptions) => serialize(async () => {
|
|
4096
4874
|
const created = await runtime.createConversation(createOptions.model !== undefined || createOptions.thinkingLevel !== undefined || createOptions.cwd !== undefined ? {
|
|
@@ -4171,6 +4949,7 @@ var init_server_services = __esm(() => {
|
|
|
4171
4949
|
init_src();
|
|
4172
4950
|
init_workspace_files();
|
|
4173
4951
|
init_contract();
|
|
4952
|
+
init_skill_market();
|
|
4174
4953
|
init_workspaces();
|
|
4175
4954
|
});
|
|
4176
4955
|
|
|
@@ -4517,9 +5296,9 @@ var init_session_host = __esm(() => {
|
|
|
4517
5296
|
});
|
|
4518
5297
|
|
|
4519
5298
|
// packages/gateway/src/gateway.ts
|
|
4520
|
-
import { randomUUID } from "crypto";
|
|
4521
|
-
import { mkdir as
|
|
4522
|
-
import { basename as basename5, dirname as
|
|
5299
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
5300
|
+
import { mkdir as mkdir3, readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
|
|
5301
|
+
import { basename as basename5, dirname as dirname7, join as join10 } from "path";
|
|
4523
5302
|
import { BACKGROUND_CONTEXT as BACKGROUND_CONTEXT3 } from "@earendil-works/chord/context";
|
|
4524
5303
|
import { isServerId } from "@earendil-works/pi-protocol";
|
|
4525
5304
|
import { Server, SessionNotFoundError } from "@earendil-works/pi-server";
|
|
@@ -4531,9 +5310,10 @@ async function startGateway(options = {}) {
|
|
|
4531
5310
|
const storagePath = options.storagePath ?? fileConfig.storagePath ?? DEFAULT_STORAGE_PATH;
|
|
4532
5311
|
const host = options.host ?? fileConfig.gateway?.host ?? DEFAULT_HOST;
|
|
4533
5312
|
const port = options.port !== undefined ? options.port : fileConfig.gateway?.port ?? (process.platform === "win32" ? 0 : DEFAULT_PORT);
|
|
4534
|
-
const
|
|
5313
|
+
const marketUrl = options.marketUrl ?? fileConfig.skills?.marketUrl ?? DEFAULT_SKILL_MARKET_URL;
|
|
5314
|
+
const nekoDir = dirname7(storagePath);
|
|
4535
5315
|
const serverId = options.serverId ?? await loadOrCreateServerId(nekoDir);
|
|
4536
|
-
const socketPath = options.socketPath !== undefined ? options.socketPath : fileConfig.gateway?.socketPath !== undefined ? fileConfig.gateway.socketPath : process.platform === "win32" ? null :
|
|
5316
|
+
const socketPath = options.socketPath !== undefined ? options.socketPath : fileConfig.gateway?.socketPath !== undefined ? fileConfig.gateway.socketPath : process.platform === "win32" ? null : join10(nekoDir, `${serverId}.sock`);
|
|
4537
5317
|
const runtime = await createNekoRuntime({
|
|
4538
5318
|
context,
|
|
4539
5319
|
storage: options.storage ?? "sqlite",
|
|
@@ -4556,6 +5336,8 @@ async function startGateway(options = {}) {
|
|
|
4556
5336
|
serverId,
|
|
4557
5337
|
nekoDir,
|
|
4558
5338
|
model,
|
|
5339
|
+
marketUrl,
|
|
5340
|
+
promptHome: options.promptHome,
|
|
4559
5341
|
onError: options.onError
|
|
4560
5342
|
});
|
|
4561
5343
|
} catch (error) {
|
|
@@ -4566,7 +5348,12 @@ async function startGateway(options = {}) {
|
|
|
4566
5348
|
async function bindGateway(runtime, options) {
|
|
4567
5349
|
const { context, host, port, socketPath, serverId, nekoDir, model } = options;
|
|
4568
5350
|
const modelLabel = `${model.provider}/${model.modelId}`;
|
|
4569
|
-
const serverServices = await createNekoServerServices({
|
|
5351
|
+
const serverServices = await createNekoServerServices({
|
|
5352
|
+
runtime,
|
|
5353
|
+
context,
|
|
5354
|
+
marketUrl: options.marketUrl,
|
|
5355
|
+
...options.promptHome !== undefined ? { promptHome: options.promptHome } : {}
|
|
5356
|
+
});
|
|
4570
5357
|
let wsListener;
|
|
4571
5358
|
const listeners = [];
|
|
4572
5359
|
if (socketPath !== null) {
|
|
@@ -4644,15 +5431,15 @@ function serverIdFromSocketPath(socketPath) {
|
|
|
4644
5431
|
return isServerId(candidate) ? candidate : undefined;
|
|
4645
5432
|
}
|
|
4646
5433
|
async function loadOrCreateServerId(nekoDir) {
|
|
4647
|
-
const file =
|
|
5434
|
+
const file = join10(nekoDir, SERVER_ID_FILENAME);
|
|
4648
5435
|
try {
|
|
4649
5436
|
const existing = (await readFile5(file, "utf8")).trim();
|
|
4650
5437
|
if (existing !== "")
|
|
4651
5438
|
return existing;
|
|
4652
5439
|
} catch {}
|
|
4653
|
-
const created =
|
|
4654
|
-
await
|
|
4655
|
-
await
|
|
5440
|
+
const created = randomUUID2();
|
|
5441
|
+
await mkdir3(nekoDir, { recursive: true, mode: 448 });
|
|
5442
|
+
await writeFile3(file, `${created}
|
|
4656
5443
|
`, { mode: 384 });
|
|
4657
5444
|
return created;
|
|
4658
5445
|
}
|
|
@@ -4666,14 +5453,14 @@ var init_gateway = __esm(() => {
|
|
|
4666
5453
|
});
|
|
4667
5454
|
|
|
4668
5455
|
// packages/gateway/src/process.ts
|
|
4669
|
-
import { fileURLToPath } from "url";
|
|
5456
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4670
5457
|
function gatewayCommand(args) {
|
|
4671
5458
|
const source = import.meta.url.endsWith(".ts");
|
|
4672
5459
|
return {
|
|
4673
5460
|
binary: process.execPath,
|
|
4674
5461
|
args: [
|
|
4675
5462
|
...source ? ["--conditions=neko-source"] : [],
|
|
4676
|
-
|
|
5463
|
+
fileURLToPath2(new URL("./gateway.js", import.meta.url)),
|
|
4677
5464
|
...args
|
|
4678
5465
|
]
|
|
4679
5466
|
};
|
|
@@ -4705,13 +5492,13 @@ var init_src2 = __esm(() => {
|
|
|
4705
5492
|
// packages/tui/src/gateway.ts
|
|
4706
5493
|
import { spawn as spawn2 } from "child_process";
|
|
4707
5494
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
4708
|
-
import { basename as basename6, dirname as
|
|
5495
|
+
import { basename as basename6, dirname as dirname8, join as join11 } from "path";
|
|
4709
5496
|
import { isServerId as isServerId2 } from "@earendil-works/pi-protocol";
|
|
4710
5497
|
async function connectToGateway(options = {}) {
|
|
4711
5498
|
const config = loadNekoConfig(options.configDir);
|
|
4712
5499
|
const storagePath = options.storagePath ?? config.storagePath ?? DEFAULT_STORAGE_PATH;
|
|
4713
|
-
const nekoDir =
|
|
4714
|
-
const fileServerId = readServerId(
|
|
5500
|
+
const nekoDir = dirname8(storagePath);
|
|
5501
|
+
const fileServerId = readServerId(join11(nekoDir, SERVER_ID_FILENAME2));
|
|
4715
5502
|
if (process.platform === "win32") {
|
|
4716
5503
|
if (fileServerId !== undefined) {
|
|
4717
5504
|
const wsUrl = await readGatewayPortFile(nekoDir, fileServerId);
|
|
@@ -4724,8 +5511,8 @@ async function connectToGateway(options = {}) {
|
|
|
4724
5511
|
}
|
|
4725
5512
|
return spawnAndConnect({ ...options, storagePath, socketPath: undefined, nekoDir, fileServerId });
|
|
4726
5513
|
}
|
|
4727
|
-
const socketPath = options.socketPath ?? config.gateway?.socketPath ?? (fileServerId !== undefined ?
|
|
4728
|
-
const serverIdFor = (path) => fileServerId ?? serverIdFromSocketPath2(path) ?? readServerId(
|
|
5514
|
+
const socketPath = options.socketPath ?? config.gateway?.socketPath ?? (fileServerId !== undefined ? join11(nekoDir, `${fileServerId}.sock`) : undefined);
|
|
5515
|
+
const serverIdFor = (path) => fileServerId ?? serverIdFromSocketPath2(path) ?? readServerId(join11(nekoDir, SERVER_ID_FILENAME2));
|
|
4729
5516
|
if (socketPath !== undefined && existsSync2(socketPath)) {
|
|
4730
5517
|
const serverId = serverIdFor(socketPath);
|
|
4731
5518
|
if (serverId !== undefined) {
|
|
@@ -4755,7 +5542,7 @@ async function spawnAndConnect(plan) {
|
|
|
4755
5542
|
async function connectSpawned(plan, child, outputTail, spawnError) {
|
|
4756
5543
|
const timeoutMs = plan.spawnTimeoutMs ?? 20000;
|
|
4757
5544
|
if (process.platform === "win32") {
|
|
4758
|
-
const serverId = plan.fileServerId ?? await waitForValue(() => readServerId(
|
|
5545
|
+
const serverId = plan.fileServerId ?? await waitForValue(() => readServerId(join11(plan.nekoDir, SERVER_ID_FILENAME2)), "gateway serverId file", timeoutMs, child, outputTail, spawnError);
|
|
4759
5546
|
const wsUrl = await waitForValue(() => readGatewayPortFile(plan.nekoDir, serverId), "gateway ready (port file)", timeoutMs, child, outputTail, spawnError);
|
|
4760
5547
|
let lastError;
|
|
4761
5548
|
for (let attempt = 0;attempt < CONNECT_RETRIES; attempt++) {
|
|
@@ -4784,11 +5571,11 @@ ${outputTail()}`);
|
|
|
4784
5571
|
}
|
|
4785
5572
|
let socketPath = plan.socketPath;
|
|
4786
5573
|
if (socketPath === undefined) {
|
|
4787
|
-
const generated = await waitForValue(() => readServerId(
|
|
4788
|
-
socketPath =
|
|
5574
|
+
const generated = await waitForValue(() => readServerId(join11(plan.nekoDir, SERVER_ID_FILENAME2)), "gateway serverId file", timeoutMs, child, outputTail, spawnError);
|
|
5575
|
+
socketPath = join11(plan.nekoDir, `${generated}.sock`);
|
|
4789
5576
|
}
|
|
4790
5577
|
await waitForValue(() => existsSync2(socketPath) ? true : undefined, `gateway ready (socket: ${socketPath})`, timeoutMs, child, outputTail, spawnError);
|
|
4791
|
-
const serverId = plan.fileServerId ?? serverIdFromSocketPath2(socketPath) ?? readServerId(
|
|
5578
|
+
const serverId = plan.fileServerId ?? serverIdFromSocketPath2(socketPath) ?? readServerId(join11(plan.nekoDir, SERVER_ID_FILENAME2));
|
|
4792
5579
|
if (serverId === undefined) {
|
|
4793
5580
|
throw new Error(`Cannot determine gateway serverId (socket: ${socketPath})`);
|
|
4794
5581
|
}
|
|
@@ -4900,8 +5687,8 @@ var init_gateway2 = __esm(() => {
|
|
|
4900
5687
|
|
|
4901
5688
|
// packages/tui/src/image-input.ts
|
|
4902
5689
|
import { execFile } from "child_process";
|
|
4903
|
-
import { readFile as readFile6, stat as
|
|
4904
|
-
import { homedir as
|
|
5690
|
+
import { readFile as readFile6, stat as stat4 } from "fs/promises";
|
|
5691
|
+
import { homedir as homedir6 } from "os";
|
|
4905
5692
|
import { basename as basename7, resolve as resolve5 } from "path";
|
|
4906
5693
|
import { promisify } from "util";
|
|
4907
5694
|
import { isKeyRelease as isKeyRelease4, isKeyRepeat as isKeyRepeat2, matchesKey as matchesKey4 } from "@earendil-works/pi-tui";
|
|
@@ -4936,12 +5723,12 @@ function imagePaths(text, platform = process.platform) {
|
|
|
4936
5723
|
return paths.length && paths.every((p) => /\.(png|jpe?g|webp)$/i.test(p)) ? paths : null;
|
|
4937
5724
|
}
|
|
4938
5725
|
async function readImageFile(path, cwd) {
|
|
4939
|
-
const full = resolve5(cwd, path.startsWith("~/") ?
|
|
4940
|
-
const info = await
|
|
5726
|
+
const full = resolve5(cwd, path.startsWith("~/") ? homedir6() + path.slice(1) : path);
|
|
5727
|
+
const info = await stat4(full);
|
|
4941
5728
|
if (!info.isFile() || info.size > 20 * 1024 * 1024)
|
|
4942
5729
|
throw new Error("Image must be a file no larger than 20 MiB");
|
|
4943
5730
|
const bytes = await readFile6(full);
|
|
4944
|
-
const after = await
|
|
5731
|
+
const after = await stat4(full);
|
|
4945
5732
|
if (bytes.length !== info.size || after.size !== info.size || after.mtimeMs !== info.mtimeMs)
|
|
4946
5733
|
throw new Error("Image changed while reading");
|
|
4947
5734
|
const mimeType = /\.png$/i.test(full) ? "image/png" : /\.webp$/i.test(full) ? "image/webp" : "image/jpeg";
|
|
@@ -5006,7 +5793,7 @@ var init_image_input = __esm(() => {
|
|
|
5006
5793
|
});
|
|
5007
5794
|
|
|
5008
5795
|
// packages/tui/src/layout.ts
|
|
5009
|
-
import { Text as
|
|
5796
|
+
import { Text as Text5, VStack } from "@earendil-works/pi-tui";
|
|
5010
5797
|
function createAppLayout(parts) {
|
|
5011
5798
|
const normal = (v) => {
|
|
5012
5799
|
parts.footer.panelOpen = parts.panelOpen();
|
|
@@ -5016,7 +5803,7 @@ function createAppLayout(parts) {
|
|
|
5016
5803
|
};
|
|
5017
5804
|
return new VStack([
|
|
5018
5805
|
{
|
|
5019
|
-
component: new
|
|
5806
|
+
component: new Text5("Terminal too small. Resize to 40x10. Ctrl+C Exit", 0, 0),
|
|
5020
5807
|
visible: (v) => !normal(v),
|
|
5021
5808
|
grow: 1
|
|
5022
5809
|
},
|
|
@@ -5030,6 +5817,235 @@ function createAppLayout(parts) {
|
|
|
5030
5817
|
var usableSize = (width, height) => width >= 40 && height >= 10;
|
|
5031
5818
|
var init_layout = () => {};
|
|
5032
5819
|
|
|
5820
|
+
// packages/tui/src/skill-market-ui.ts
|
|
5821
|
+
import { BACKGROUND_CONTEXT as BACKGROUND_CONTEXT4 } from "@earendil-works/chord/context";
|
|
5822
|
+
import { Markdown as Markdown3, matchesKey as matchesKey5, wrapTextWithAnsi as wrapTextWithAnsi2 } from "@earendil-works/pi-tui";
|
|
5823
|
+
|
|
5824
|
+
class SkillDetailView {
|
|
5825
|
+
#skill = null;
|
|
5826
|
+
#error = "";
|
|
5827
|
+
#notice = "";
|
|
5828
|
+
#busy = false;
|
|
5829
|
+
#confirm = null;
|
|
5830
|
+
#name;
|
|
5831
|
+
#client;
|
|
5832
|
+
#workspaceRoot;
|
|
5833
|
+
#panel;
|
|
5834
|
+
#openPreview;
|
|
5835
|
+
constructor(name, client, workspaceRoot, panel, openPreview) {
|
|
5836
|
+
this.#name = name;
|
|
5837
|
+
this.#client = client;
|
|
5838
|
+
this.#workspaceRoot = workspaceRoot;
|
|
5839
|
+
this.#panel = panel;
|
|
5840
|
+
this.#openPreview = openPreview;
|
|
5841
|
+
this.refresh();
|
|
5842
|
+
}
|
|
5843
|
+
get help() {
|
|
5844
|
+
if (this.#confirm)
|
|
5845
|
+
return hint(["y", "Confirm"], ["n", "Cancel"]);
|
|
5846
|
+
const skill = this.#skill;
|
|
5847
|
+
const builtinOnly = skill?.installed.builtin === true && !skill.installed.user && !skill.installed.project;
|
|
5848
|
+
return builtinOnly ? hint(["v", "Preview"], ["Esc", "Back"]) + theme.dim(" (builtin ships with neko)") : hint(["u", "Install user"], ["p", "Install project"], ["d", "Uninstall"], ["v", "Preview"], ["Esc", "Back"]);
|
|
5849
|
+
}
|
|
5850
|
+
async refresh() {
|
|
5851
|
+
try {
|
|
5852
|
+
this.#skill = await this.#client.skillMarket.detail({ name: this.#name, workspaceRoot: this.#workspaceRoot }, CTX);
|
|
5853
|
+
this.#error = "";
|
|
5854
|
+
} catch (error) {
|
|
5855
|
+
this.#error = error instanceof Error ? error.message : String(error);
|
|
5856
|
+
}
|
|
5857
|
+
this.#panel.changed();
|
|
5858
|
+
}
|
|
5859
|
+
handleKey(data) {
|
|
5860
|
+
if (this.#confirm) {
|
|
5861
|
+
if (matchesKey5(data, "y")) {
|
|
5862
|
+
const pending = this.#confirm;
|
|
5863
|
+
this.#confirm = null;
|
|
5864
|
+
this.run(pending.run);
|
|
5865
|
+
} else if (matchesKey5(data, "n")) {
|
|
5866
|
+
this.#confirm = null;
|
|
5867
|
+
}
|
|
5868
|
+
return true;
|
|
5869
|
+
}
|
|
5870
|
+
if (this.#busy || this.#skill === null)
|
|
5871
|
+
return true;
|
|
5872
|
+
const skill = this.#skill;
|
|
5873
|
+
const builtinOnly = skill.installed.builtin && !skill.installed.user && !skill.installed.project;
|
|
5874
|
+
if (matchesKey5(data, "v")) {
|
|
5875
|
+
this.#openPreview(this.#name);
|
|
5876
|
+
return true;
|
|
5877
|
+
}
|
|
5878
|
+
if (builtinOnly)
|
|
5879
|
+
return true;
|
|
5880
|
+
if (matchesKey5(data, "u"))
|
|
5881
|
+
this.askInstall("user", skill);
|
|
5882
|
+
else if (matchesKey5(data, "p"))
|
|
5883
|
+
this.askInstall("project", skill);
|
|
5884
|
+
else if (matchesKey5(data, "d"))
|
|
5885
|
+
this.askUninstall(skill);
|
|
5886
|
+
else
|
|
5887
|
+
return false;
|
|
5888
|
+
return true;
|
|
5889
|
+
}
|
|
5890
|
+
askInstall(scope, skill) {
|
|
5891
|
+
const exists = scope === "user" ? skill.installed.user : skill.installed.project;
|
|
5892
|
+
const shadowed = scope === "user" && skill.installed.project;
|
|
5893
|
+
if (exists) {
|
|
5894
|
+
this.#confirm = {
|
|
5895
|
+
prompt: `${skill.name} exists at ${scope} level. Overwrite with market version ${skill.version}? Local edits are lost.`,
|
|
5896
|
+
run: () => this.install(scope, true)
|
|
5897
|
+
};
|
|
5898
|
+
} else if (shadowed) {
|
|
5899
|
+
this.#confirm = {
|
|
5900
|
+
prompt: `Project level already has ${skill.name} and wins. Install at user level anyway?`,
|
|
5901
|
+
run: () => this.install(scope, false)
|
|
5902
|
+
};
|
|
5903
|
+
} else {
|
|
5904
|
+
this.run(() => this.install(scope, false));
|
|
5905
|
+
}
|
|
5906
|
+
}
|
|
5907
|
+
askUninstall(skill) {
|
|
5908
|
+
const scope = skill.installed.project ? "project" : skill.installed.user ? "user" : null;
|
|
5909
|
+
if (scope === null) {
|
|
5910
|
+
this.#notice = "Not installed locally.";
|
|
5911
|
+
return;
|
|
5912
|
+
}
|
|
5913
|
+
this.#confirm = {
|
|
5914
|
+
prompt: `Uninstall ${skill.name} from ${scope} level? This cannot be undone.`,
|
|
5915
|
+
run: async () => {
|
|
5916
|
+
await this.#client.skillMarket.uninstall({ name: this.#name, scope, workspaceRoot: this.#workspaceRoot }, CTX);
|
|
5917
|
+
this.#notice = `Uninstalled from ${scope}. Takes effect on the next message.`;
|
|
5918
|
+
}
|
|
5919
|
+
};
|
|
5920
|
+
}
|
|
5921
|
+
async install(scope, overwrite) {
|
|
5922
|
+
try {
|
|
5923
|
+
const result = await this.#client.skillMarket.install({ name: this.#name, scope, workspaceRoot: this.#workspaceRoot, overwrite }, CTX);
|
|
5924
|
+
this.#notice = result.shadowedBy === "project" ? "Installed at user level, but the project-level copy still wins." : `Installed at ${scope} level. Takes effect on the next message.`;
|
|
5925
|
+
} catch (error) {
|
|
5926
|
+
if (marketErrorCode(error) === "skill_exists") {
|
|
5927
|
+
this.#confirm = {
|
|
5928
|
+
prompt: `${this.#name} already exists at ${scope} level. Overwrite with the market version?`,
|
|
5929
|
+
run: () => this.install(scope, true)
|
|
5930
|
+
};
|
|
5931
|
+
return;
|
|
5932
|
+
}
|
|
5933
|
+
throw error;
|
|
5934
|
+
}
|
|
5935
|
+
}
|
|
5936
|
+
async run(action) {
|
|
5937
|
+
this.#busy = true;
|
|
5938
|
+
this.#notice = "";
|
|
5939
|
+
this.#panel.changed();
|
|
5940
|
+
try {
|
|
5941
|
+
await action();
|
|
5942
|
+
} catch (error) {
|
|
5943
|
+
this.#notice = `Failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
5944
|
+
} finally {
|
|
5945
|
+
this.#busy = false;
|
|
5946
|
+
await this.refresh();
|
|
5947
|
+
}
|
|
5948
|
+
}
|
|
5949
|
+
lines(width, _height) {
|
|
5950
|
+
if (this.#confirm) {
|
|
5951
|
+
return [theme.accent("Confirm"), "", ...wrapTextWithAnsi2(this.#confirm.prompt, width), ""];
|
|
5952
|
+
}
|
|
5953
|
+
const skill = this.#skill;
|
|
5954
|
+
if (skill === null)
|
|
5955
|
+
return [this.#error !== "" ? theme.error(`Error: ${this.#error}`) : theme.dim("Loading...")];
|
|
5956
|
+
const mark = (on, label) => on ? theme.ok(`${label} \u2713`) : theme.dim(`${label} \u2014`);
|
|
5957
|
+
const state = [
|
|
5958
|
+
mark(skill.installed.project, "project"),
|
|
5959
|
+
mark(skill.installed.user, "user"),
|
|
5960
|
+
mark(skill.installed.builtin, "builtin")
|
|
5961
|
+
].join(" ");
|
|
5962
|
+
const rows = [
|
|
5963
|
+
`${style.bold(skill.name)} ${theme.dim(skill.version)}`,
|
|
5964
|
+
theme.dim(`${skill.source} \xB7 ${skill.category} \xB7 ${formatSize(skill.sizeBytes)} \xB7 sha256 ${skill.sha256.slice(0, 10)}\u2026`),
|
|
5965
|
+
`${theme.dim("installed:")} ${state}${skill.activeLevel ? theme.dim(` (active: ${skill.activeLevel})`) : ""}`,
|
|
5966
|
+
"",
|
|
5967
|
+
...wrapTextWithAnsi2(skill.description, width)
|
|
5968
|
+
];
|
|
5969
|
+
if (this.#busy)
|
|
5970
|
+
rows.push("", theme.dim("Working..."));
|
|
5971
|
+
if (this.#notice !== "")
|
|
5972
|
+
rows.push("", theme.accent(this.#notice));
|
|
5973
|
+
return rows;
|
|
5974
|
+
}
|
|
5975
|
+
}
|
|
5976
|
+
|
|
5977
|
+
class SkillPreviewView {
|
|
5978
|
+
#header = null;
|
|
5979
|
+
#markdown = null;
|
|
5980
|
+
#error = "";
|
|
5981
|
+
#offset = 0;
|
|
5982
|
+
#panel;
|
|
5983
|
+
get help() {
|
|
5984
|
+
return hint(["Up/Down", "Scroll"], ["Esc", "Back"]);
|
|
5985
|
+
}
|
|
5986
|
+
constructor(name, client, panel) {
|
|
5987
|
+
this.#panel = panel;
|
|
5988
|
+
client.skillMarket.preview({ name }, CTX).then((preview) => {
|
|
5989
|
+
this.#header = [`${theme.dim("files:")} ${preview.files.join(" ")}`, ""];
|
|
5990
|
+
this.#markdown = new Markdown3(preview.body, 0, 0, getMarkdownTheme());
|
|
5991
|
+
this.#panel.changed();
|
|
5992
|
+
}).catch((error) => {
|
|
5993
|
+
this.#error = error instanceof Error ? error.message : String(error);
|
|
5994
|
+
this.#panel.changed();
|
|
5995
|
+
});
|
|
5996
|
+
}
|
|
5997
|
+
handleKey(data) {
|
|
5998
|
+
if (matchesKey5(data, "up"))
|
|
5999
|
+
this.#offset = Math.max(0, this.#offset - 1);
|
|
6000
|
+
else if (matchesKey5(data, "down"))
|
|
6001
|
+
this.#offset += 1;
|
|
6002
|
+
else
|
|
6003
|
+
return false;
|
|
6004
|
+
return true;
|
|
6005
|
+
}
|
|
6006
|
+
lines(width, height) {
|
|
6007
|
+
if (this.#markdown === null || this.#header === null)
|
|
6008
|
+
return [this.#error !== "" ? theme.error(`Error: ${this.#error}`) : theme.dim("Loading preview...")];
|
|
6009
|
+
const flat = [...this.#header, ...this.#markdown.render(width)];
|
|
6010
|
+
const max = Math.max(0, flat.length - height);
|
|
6011
|
+
this.#offset = Math.min(this.#offset, max);
|
|
6012
|
+
return flat.slice(this.#offset, this.#offset + height);
|
|
6013
|
+
}
|
|
6014
|
+
}
|
|
6015
|
+
async function openSkillMarket(panel, client, workspaceRoot) {
|
|
6016
|
+
const openPreview = (name) => panel.showDetail(new SkillPreviewView(name, client, panel));
|
|
6017
|
+
await panel.show("Skills Market", async () => toItems(await client.skillMarket.list({ workspaceRoot }, CTX)), async (name) => new SkillDetailView(name, client, workspaceRoot, panel, openPreview));
|
|
6018
|
+
}
|
|
6019
|
+
var hint = (...parts) => parts.map(([key, label]) => `${theme.accent(key)} ${theme.dim(label)}`).join(theme.dim(" \xB7 ")), CTX, formatSize = (bytes) => bytes >= 1024 * 1024 ? `${(bytes / 1024 / 1024).toFixed(1)}MB` : `${Math.max(1, Math.round(bytes / 1024))}KB`, marketErrorCode = (error) => {
|
|
6020
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6021
|
+
return /^\[([a-z_]+)\]/.exec(message)?.[1] ?? null;
|
|
6022
|
+
}, stateMarks = (skill) => `${skill.installed.user ? "[u]" : ""}${skill.installed.project ? "[p]" : ""}${skill.installed.builtin ? "[b]" : ""}`, toItems = (skills) => {
|
|
6023
|
+
const groups = new Map;
|
|
6024
|
+
for (const skill of skills) {
|
|
6025
|
+
const list = groups.get(skill.category) ?? [];
|
|
6026
|
+
list.push(skill);
|
|
6027
|
+
groups.set(skill.category, list);
|
|
6028
|
+
}
|
|
6029
|
+
const items = [];
|
|
6030
|
+
for (const [category, members] of [...groups.entries()].sort((a, b) => b[1].length - a[1].length)) {
|
|
6031
|
+
items.push({ value: `header:${category}`, label: `${category} (${members.length})`, header: true });
|
|
6032
|
+
for (const skill of members) {
|
|
6033
|
+
items.push({
|
|
6034
|
+
value: skill.name,
|
|
6035
|
+
label: skill.name,
|
|
6036
|
+
description: skill.description,
|
|
6037
|
+
searchText: `${skill.source} ${skill.category}`,
|
|
6038
|
+
rightLabel: `${skill.source} ${skill.version} ${stateMarks(skill)}`.trim()
|
|
6039
|
+
});
|
|
6040
|
+
}
|
|
6041
|
+
}
|
|
6042
|
+
return items;
|
|
6043
|
+
};
|
|
6044
|
+
var init_skill_market_ui = __esm(() => {
|
|
6045
|
+
init_theme();
|
|
6046
|
+
CTX = BACKGROUND_CONTEXT4;
|
|
6047
|
+
});
|
|
6048
|
+
|
|
5033
6049
|
// packages/core/src/session-display.ts
|
|
5034
6050
|
function relativeTime(at, now, language = "en") {
|
|
5035
6051
|
const minutes = Math.floor(Math.max(0, now - at) / 60000);
|
|
@@ -5064,15 +6080,15 @@ ${new Date(messageTime(s)).toLocaleString("en-GB")}`
|
|
|
5064
6080
|
var init_workspace2 = () => {};
|
|
5065
6081
|
|
|
5066
6082
|
// packages/tui/src/tui.ts
|
|
5067
|
-
import { BACKGROUND_CONTEXT as
|
|
6083
|
+
import { BACKGROUND_CONTEXT as BACKGROUND_CONTEXT5 } from "@earendil-works/chord/context";
|
|
5068
6084
|
import {
|
|
5069
6085
|
Container as Container5,
|
|
5070
6086
|
isKeyRelease as isKeyRelease5,
|
|
5071
|
-
matchesKey as
|
|
6087
|
+
matchesKey as matchesKey6,
|
|
5072
6088
|
ProcessTerminal,
|
|
5073
6089
|
ScrollView,
|
|
5074
6090
|
Spacer as Spacer2,
|
|
5075
|
-
Text as
|
|
6091
|
+
Text as Text6,
|
|
5076
6092
|
TruncatedText,
|
|
5077
6093
|
TuiAltScreen
|
|
5078
6094
|
} from "@earendil-works/pi-tui";
|
|
@@ -5138,8 +6154,8 @@ class NekoTuiApp {
|
|
|
5138
6154
|
this.#login = new LoginPanel({
|
|
5139
6155
|
changed: () => this.#ui.requestRender(),
|
|
5140
6156
|
closed: () => this.#ui.setFocus(this.#editor),
|
|
5141
|
-
save: (provider, key) => this.#gateway.client.credentials.save({ provider, key },
|
|
5142
|
-
remove: (provider) => this.#gateway.client.credentials.remove({ provider },
|
|
6157
|
+
save: (provider, key) => this.#gateway.client.credentials.save({ provider, key }, BACKGROUND_CONTEXT5),
|
|
6158
|
+
remove: (provider) => this.#gateway.client.credentials.remove({ provider }, BACKGROUND_CONTEXT5)
|
|
5143
6159
|
});
|
|
5144
6160
|
const complete = fileCompletion(this.#commands, options.cwd ?? process.cwd(), (text) => this.addNotice(text));
|
|
5145
6161
|
const original = complete.applyCompletion.bind(complete);
|
|
@@ -5175,10 +6191,10 @@ class NekoTuiApp {
|
|
|
5175
6191
|
this.#ui.addInputListener((data) => {
|
|
5176
6192
|
if (isKeyRelease5(data))
|
|
5177
6193
|
return { consume: true };
|
|
5178
|
-
if (!
|
|
6194
|
+
if (!matchesKey6(data, "escape") || this.#panel.open || this.#login.open || this.#busyText !== undefined || this.#lastView?.compaction?.active.length)
|
|
5179
6195
|
this.#editor.resetEscapeSequence();
|
|
5180
6196
|
if (!usableSize(this.#terminal.columns, this.#terminal.rows)) {
|
|
5181
|
-
if (
|
|
6197
|
+
if (matchesKey6(data, "ctrl+c"))
|
|
5182
6198
|
this.exit();
|
|
5183
6199
|
return { consume: true };
|
|
5184
6200
|
}
|
|
@@ -5187,7 +6203,7 @@ class NekoTuiApp {
|
|
|
5187
6203
|
}
|
|
5188
6204
|
if (this.#sessionOperation)
|
|
5189
6205
|
return { consume: true };
|
|
5190
|
-
if (
|
|
6206
|
+
if (matchesKey6(data, process.platform === "win32" ? "alt+v" : "ctrl+v")) {
|
|
5191
6207
|
if (isClipboardShortcut(data))
|
|
5192
6208
|
this.pasteClipboard();
|
|
5193
6209
|
return { consume: true };
|
|
@@ -5204,26 +6220,26 @@ class NekoTuiApp {
|
|
|
5204
6220
|
return { consume: true };
|
|
5205
6221
|
}
|
|
5206
6222
|
}
|
|
5207
|
-
if (
|
|
6223
|
+
if (matchesKey6(data, "escape") && this.#editor.isShowingAutocomplete()) {
|
|
5208
6224
|
this.#editor.resetEscapeSequence();
|
|
5209
6225
|
return;
|
|
5210
6226
|
}
|
|
5211
|
-
if (
|
|
6227
|
+
if (matchesKey6(data, "ctrl+c")) {
|
|
5212
6228
|
if (this.#busyText !== undefined)
|
|
5213
6229
|
this.abort();
|
|
5214
6230
|
else
|
|
5215
6231
|
this.exit();
|
|
5216
6232
|
return { consume: true };
|
|
5217
6233
|
}
|
|
5218
|
-
if (
|
|
6234
|
+
if (matchesKey6(data, "escape") && (this.#busyText !== undefined || this.#lastView?.compaction?.active.some((c) => c.reason === "manual" || c.blocking))) {
|
|
5219
6235
|
this.abort();
|
|
5220
6236
|
return { consume: true };
|
|
5221
6237
|
}
|
|
5222
|
-
if (
|
|
6238
|
+
if (matchesKey6(data, "ctrl+s")) {
|
|
5223
6239
|
this.openSessionsOverlay();
|
|
5224
6240
|
return { consume: true };
|
|
5225
6241
|
}
|
|
5226
|
-
if (this.#busyText !== undefined &&
|
|
6242
|
+
if (this.#busyText !== undefined && matchesKey6(data, "alt+enter")) {
|
|
5227
6243
|
this.submitFollowUp();
|
|
5228
6244
|
return { consume: true };
|
|
5229
6245
|
}
|
|
@@ -5285,7 +6301,7 @@ class NekoTuiApp {
|
|
|
5285
6301
|
const chat = this.#chatFacade;
|
|
5286
6302
|
const session = this.#sessionId;
|
|
5287
6303
|
if (chat)
|
|
5288
|
-
chat.compact({ instructions },
|
|
6304
|
+
chat.compact({ instructions }, BACKGROUND_CONTEXT5).catch((e) => {
|
|
5289
6305
|
if (session === this.#sessionId) {
|
|
5290
6306
|
this.#editor.setText(text);
|
|
5291
6307
|
this.addNotice(messageOf(e), true);
|
|
@@ -5317,6 +6333,10 @@ class NekoTuiApp {
|
|
|
5317
6333
|
this.openModelOverlay();
|
|
5318
6334
|
return;
|
|
5319
6335
|
}
|
|
6336
|
+
if (trimmed === "/skills") {
|
|
6337
|
+
this.openSkillsOverlay();
|
|
6338
|
+
return;
|
|
6339
|
+
}
|
|
5320
6340
|
if (trimmed.startsWith("/think")) {
|
|
5321
6341
|
this.configureThinking(trimmed.slice("/think".length).trim());
|
|
5322
6342
|
return;
|
|
@@ -5402,14 +6422,14 @@ class NekoTuiApp {
|
|
|
5402
6422
|
for (const [ref, promise] of refs) {
|
|
5403
6423
|
const file = await promise;
|
|
5404
6424
|
ids.push(await uploadImage(file, {
|
|
5405
|
-
begin: (i) => chat.beginImage(i,
|
|
5406
|
-
append: (i) => chat.appendImage(i,
|
|
5407
|
-
finish: (id) => chat.finishImage(id,
|
|
5408
|
-
release: (id) => chat.releaseImage(id,
|
|
6425
|
+
begin: (i) => chat.beginImage(i, BACKGROUND_CONTEXT5),
|
|
6426
|
+
append: (i) => chat.appendImage(i, BACKGROUND_CONTEXT5),
|
|
6427
|
+
finish: (id) => chat.finishImage(id, BACKGROUND_CONTEXT5),
|
|
6428
|
+
release: (id) => chat.releaseImage(id, BACKGROUND_CONTEXT5)
|
|
5409
6429
|
}));
|
|
5410
6430
|
content = content.replaceAll(ref, "");
|
|
5411
6431
|
}
|
|
5412
|
-
await chat.submit({ content: content.trim(), images: ids, requestId, ...whenBusy ? { whenBusy } : {} },
|
|
6432
|
+
await chat.submit({ content: content.trim(), images: ids, requestId, ...whenBusy ? { whenBusy } : {} }, BACKGROUND_CONTEXT5);
|
|
5413
6433
|
if (session === this.#sessionId && this.#editor.getText() === before)
|
|
5414
6434
|
this.#editor.setText("");
|
|
5415
6435
|
if (this.#texts.get(session) === before)
|
|
@@ -5424,7 +6444,7 @@ class NekoTuiApp {
|
|
|
5424
6444
|
this.addNotice(messageOf(e), true);
|
|
5425
6445
|
} finally {
|
|
5426
6446
|
for (const id of ids)
|
|
5427
|
-
await chat.releaseImage(id,
|
|
6447
|
+
await chat.releaseImage(id, BACKGROUND_CONTEXT5).catch(() => {});
|
|
5428
6448
|
this.#sending.delete(session);
|
|
5429
6449
|
this.#ui.requestRender();
|
|
5430
6450
|
}
|
|
@@ -5433,7 +6453,7 @@ class NekoTuiApp {
|
|
|
5433
6453
|
const chat = this.#chatFacade;
|
|
5434
6454
|
if (chat === undefined)
|
|
5435
6455
|
return;
|
|
5436
|
-
chat.abort(
|
|
6456
|
+
chat.abort(BACKGROUND_CONTEXT5).catch((error) => this.addNotice(messageOf(error), true));
|
|
5437
6457
|
}
|
|
5438
6458
|
exit() {
|
|
5439
6459
|
if (this.#exitStarted)
|
|
@@ -5464,7 +6484,7 @@ class NekoTuiApp {
|
|
|
5464
6484
|
async#refreshSkills(facade) {
|
|
5465
6485
|
this.#commands.splice(0, this.#commands.length, ...commands);
|
|
5466
6486
|
try {
|
|
5467
|
-
const skills = await facade.skills(
|
|
6487
|
+
const skills = await facade.skills(BACKGROUND_CONTEXT5);
|
|
5468
6488
|
if (facade !== this.#chatFacade)
|
|
5469
6489
|
return;
|
|
5470
6490
|
for (const skill of skills)
|
|
@@ -5484,16 +6504,16 @@ class NekoTuiApp {
|
|
|
5484
6504
|
}
|
|
5485
6505
|
}
|
|
5486
6506
|
async createSession() {
|
|
5487
|
-
const created = await this.#gateway.client.management.create({ ...this.#options.cwd !== undefined ? { cwd: this.#options.cwd } : {} },
|
|
6507
|
+
const created = await this.#gateway.client.management.create({ ...this.#options.cwd !== undefined ? { cwd: this.#options.cwd } : {} }, BACKGROUND_CONTEXT5);
|
|
5488
6508
|
await this.switchSession(created.id);
|
|
5489
6509
|
}
|
|
5490
6510
|
async forkSession() {
|
|
5491
|
-
const forked = await this.#gateway.client.management.fork(this.#sessionId,
|
|
6511
|
+
const forked = await this.#gateway.client.management.fork(this.#sessionId, BACKGROUND_CONTEXT5);
|
|
5492
6512
|
await this.switchSession(forked.id);
|
|
5493
6513
|
}
|
|
5494
6514
|
async archiveSession() {
|
|
5495
6515
|
const current = this.#sessionId;
|
|
5496
|
-
await this.#gateway.client.management.archive(current,
|
|
6516
|
+
await this.#gateway.client.management.archive(current, BACKGROUND_CONTEXT5);
|
|
5497
6517
|
const next = recentlyVisited(this.#gateway.client.directory.state.value?.sessions ?? [], this.#options.cwd).find((s) => s.id !== current);
|
|
5498
6518
|
if (next)
|
|
5499
6519
|
await this.switchSession(next.id);
|
|
@@ -5518,6 +6538,14 @@ class NekoTuiApp {
|
|
|
5518
6538
|
this.#sessionPanelTimer = setInterval(() => this.#panel.update(this.sessionItems()), 60000);
|
|
5519
6539
|
this.#ui.setFocus(this.#panel);
|
|
5520
6540
|
}
|
|
6541
|
+
async openSkillsOverlay() {
|
|
6542
|
+
if (this.#exitStarted || this.#panel.open || this.#login.open)
|
|
6543
|
+
return;
|
|
6544
|
+
const workspace = this.#options.cwd ?? process.cwd();
|
|
6545
|
+
const ready = openSkillMarket(this.#panel, this.#gateway.client, workspace);
|
|
6546
|
+
this.#ui.setFocus(this.#panel);
|
|
6547
|
+
await ready;
|
|
6548
|
+
}
|
|
5521
6549
|
async openModelOverlay() {
|
|
5522
6550
|
if (this.#exitStarted || this.#panel.open || this.#login.open)
|
|
5523
6551
|
return;
|
|
@@ -5535,7 +6563,7 @@ class NekoTuiApp {
|
|
|
5535
6563
|
}, async (value) => {
|
|
5536
6564
|
const selected = models.find((m) => keyOf(m) === value);
|
|
5537
6565
|
if (selected && value !== currentKey)
|
|
5538
|
-
await chat?.configure({ model: { provider: selected.provider, modelId: selected.modelId } },
|
|
6566
|
+
await chat?.configure({ model: { provider: selected.provider, modelId: selected.modelId } }, BACKGROUND_CONTEXT5);
|
|
5539
6567
|
});
|
|
5540
6568
|
this.#ui.setFocus(this.#panel);
|
|
5541
6569
|
await ready;
|
|
@@ -5557,14 +6585,14 @@ class NekoTuiApp {
|
|
|
5557
6585
|
this.addNotice(`Available levels: ${model.supportedThinkingLevels.join(" / ")}`, true);
|
|
5558
6586
|
return;
|
|
5559
6587
|
}
|
|
5560
|
-
await chat.configure({ thinkingLevel: level },
|
|
6588
|
+
await chat.configure({ thinkingLevel: level }, BACKGROUND_CONTEXT5);
|
|
5561
6589
|
} else {
|
|
5562
6590
|
this.#thinkingModel = keyOf(model);
|
|
5563
6591
|
this.#panel.show("Thinking level", async () => model.supportedThinkingLevels.map((level) => ({
|
|
5564
6592
|
value: level,
|
|
5565
6593
|
label: `${level}${level === this.#lastView?.agent.thinkingLevel ? " (Current)" : ""}`
|
|
5566
6594
|
})), async (value) => {
|
|
5567
|
-
await chat.configure({ thinkingLevel: value },
|
|
6595
|
+
await chat.configure({ thinkingLevel: value }, BACKGROUND_CONTEXT5);
|
|
5568
6596
|
});
|
|
5569
6597
|
this.#ui.setFocus(this.#panel);
|
|
5570
6598
|
}
|
|
@@ -5676,7 +6704,7 @@ class NekoTuiApp {
|
|
|
5676
6704
|
if (!chat)
|
|
5677
6705
|
return;
|
|
5678
6706
|
for (const image of images) {
|
|
5679
|
-
const component = new HistoryImage(image, () => downloadImage((offset) => chat.getImage({ entryId: image.entryId, contentIndex: image.contentIndex, offset },
|
|
6707
|
+
const component = new HistoryImage(image, () => downloadImage((offset) => chat.getImage({ entryId: image.entryId, contentIndex: image.contentIndex, offset }, BACKGROUND_CONTEXT5)), () => {
|
|
5680
6708
|
if (session === this.#sessionId)
|
|
5681
6709
|
this.#ui.requestRender();
|
|
5682
6710
|
});
|
|
@@ -5712,7 +6740,7 @@ class NekoTuiApp {
|
|
|
5712
6740
|
this.#items.set(item.key, { kind: "tool", component });
|
|
5713
6741
|
return;
|
|
5714
6742
|
}
|
|
5715
|
-
const component = new
|
|
6743
|
+
const component = new Text6(theme.dim(item.text), 1, 0);
|
|
5716
6744
|
this.#chat.addChild(component);
|
|
5717
6745
|
this.#items.set(item.key, { kind: "system", component });
|
|
5718
6746
|
}
|
|
@@ -5876,7 +6904,7 @@ async function initialSessionId(gateway, cwd) {
|
|
|
5876
6904
|
const first = recentlyVisited(sessions, cwd)[0];
|
|
5877
6905
|
if (first !== undefined)
|
|
5878
6906
|
return first.id;
|
|
5879
|
-
return (await gateway.client.management.create({ ...cwd !== undefined ? { cwd } : {} },
|
|
6907
|
+
return (await gateway.client.management.create({ ...cwd !== undefined ? { cwd } : {} }, BACKGROUND_CONTEXT5)).id;
|
|
5880
6908
|
}
|
|
5881
6909
|
var EXIT_COMMANDS, SESSIONS_COMMANDS, NEW_SESSION_VALUE = "__new__";
|
|
5882
6910
|
var init_tui = __esm(() => {
|
|
@@ -5894,6 +6922,7 @@ var init_tui = __esm(() => {
|
|
|
5894
6922
|
init_image_input();
|
|
5895
6923
|
init_labels();
|
|
5896
6924
|
init_layout();
|
|
6925
|
+
init_skill_market_ui();
|
|
5897
6926
|
init_theme();
|
|
5898
6927
|
init_workspace2();
|
|
5899
6928
|
EXIT_COMMANDS = new Set(["/exit", "/quit"]);
|
|
@@ -6011,11 +7040,11 @@ var init_open_browser = () => {};
|
|
|
6011
7040
|
|
|
6012
7041
|
// packages/web/src/gateway-spawn.ts
|
|
6013
7042
|
import { spawn as spawn3 } from "child_process";
|
|
6014
|
-
import { randomUUID as
|
|
6015
|
-
import { mkdir as
|
|
6016
|
-
import { dirname as
|
|
7043
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
7044
|
+
import { mkdir as mkdir4, readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
|
|
7045
|
+
import { dirname as dirname9, join as join12 } from "path";
|
|
6017
7046
|
async function ensureNekoGateway(options) {
|
|
6018
|
-
const nekoDir =
|
|
7047
|
+
const nekoDir = dirname9(options.storagePath);
|
|
6019
7048
|
const serverId = options.serverId ?? await loadOrCreateServerId2(nekoDir);
|
|
6020
7049
|
if (process.platform === "win32") {
|
|
6021
7050
|
const discovered = await readGatewayPortFile(nekoDir, serverId);
|
|
@@ -6054,7 +7083,7 @@ async function ensureNekoGateway(options) {
|
|
|
6054
7083
|
throw error;
|
|
6055
7084
|
}
|
|
6056
7085
|
}
|
|
6057
|
-
const socketPath = options.socketPath ??
|
|
7086
|
+
const socketPath = options.socketPath ?? join12(nekoDir, `${serverId}.sock`);
|
|
6058
7087
|
const host = options.host ?? "127.0.0.1";
|
|
6059
7088
|
const port = options.port ?? 8321;
|
|
6060
7089
|
if (await probeGateway(socketPath, serverId)) {
|
|
@@ -6157,15 +7186,15 @@ function makeHandle(serverId, socketPath, wsUrl, spawned, nekoDir) {
|
|
|
6157
7186
|
};
|
|
6158
7187
|
}
|
|
6159
7188
|
async function loadOrCreateServerId2(nekoDir) {
|
|
6160
|
-
const file =
|
|
7189
|
+
const file = join12(nekoDir, SERVER_ID_FILENAME3);
|
|
6161
7190
|
try {
|
|
6162
7191
|
const existing = (await readFile7(file, "utf8")).trim();
|
|
6163
7192
|
if (existing !== "")
|
|
6164
7193
|
return existing;
|
|
6165
7194
|
} catch {}
|
|
6166
|
-
const created =
|
|
6167
|
-
await
|
|
6168
|
-
await
|
|
7195
|
+
const created = randomUUID3();
|
|
7196
|
+
await mkdir4(nekoDir, { recursive: true, mode: 448 });
|
|
7197
|
+
await writeFile4(file, `${created}
|
|
6169
7198
|
`, { mode: 384 });
|
|
6170
7199
|
return created;
|
|
6171
7200
|
}
|
|
@@ -6179,10 +7208,10 @@ var init_gateway_spawn = __esm(() => {
|
|
|
6179
7208
|
|
|
6180
7209
|
// packages/web/src/server.ts
|
|
6181
7210
|
import { createReadStream } from "fs";
|
|
6182
|
-
import { stat as
|
|
7211
|
+
import { stat as stat5 } from "fs/promises";
|
|
6183
7212
|
import { createServer } from "http";
|
|
6184
7213
|
import { extname as extname2, resolve as resolve6, sep as sep2 } from "path";
|
|
6185
|
-
import { fileURLToPath as
|
|
7214
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
6186
7215
|
async function startWebServer(options = {}) {
|
|
6187
7216
|
const staticDir = resolve6(options.staticDir ?? DEFAULT_STATIC_DIR);
|
|
6188
7217
|
const workspaceRoot = normalizeWorkspace(options.gateway?.cwd ?? process.cwd());
|
|
@@ -6245,18 +7274,18 @@ async function serveStatic(pathname, method, response, staticDir) {
|
|
|
6245
7274
|
return;
|
|
6246
7275
|
}
|
|
6247
7276
|
let file = candidate;
|
|
6248
|
-
let stats = await
|
|
7277
|
+
let stats = await stat5(file).catch(() => {
|
|
6249
7278
|
return;
|
|
6250
7279
|
});
|
|
6251
7280
|
if (stats?.isDirectory()) {
|
|
6252
7281
|
file = resolve6(file, "index.html");
|
|
6253
|
-
stats = await
|
|
7282
|
+
stats = await stat5(file).catch(() => {
|
|
6254
7283
|
return;
|
|
6255
7284
|
});
|
|
6256
7285
|
}
|
|
6257
7286
|
if (stats === undefined && extname2(candidate) === "") {
|
|
6258
7287
|
file = resolve6(staticDir, "index.html");
|
|
6259
|
-
stats = await
|
|
7288
|
+
stats = await stat5(file).catch(() => {
|
|
6260
7289
|
return;
|
|
6261
7290
|
});
|
|
6262
7291
|
}
|
|
@@ -6281,7 +7310,7 @@ var DEFAULT_PORT2 = 8322, DEFAULT_HOST2 = "127.0.0.1", DEFAULT_STATIC_DIR, MIME;
|
|
|
6281
7310
|
var init_server = __esm(() => {
|
|
6282
7311
|
init_src();
|
|
6283
7312
|
init_gateway_spawn();
|
|
6284
|
-
DEFAULT_STATIC_DIR =
|
|
7313
|
+
DEFAULT_STATIC_DIR = fileURLToPath3(new URL("./client", import.meta.url));
|
|
6285
7314
|
MIME = {
|
|
6286
7315
|
".html": "text/html; charset=utf-8",
|
|
6287
7316
|
".js": "text/javascript; charset=utf-8",
|
|
@@ -6615,7 +7644,7 @@ switch (command2) {
|
|
|
6615
7644
|
}
|
|
6616
7645
|
case "--version":
|
|
6617
7646
|
case "-v":
|
|
6618
|
-
console.log("0.2.
|
|
7647
|
+
console.log("0.2.3");
|
|
6619
7648
|
break;
|
|
6620
7649
|
case undefined:
|
|
6621
7650
|
case "-h":
|