neko-harness 0.2.2 → 0.2.4
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 +770 -52
- package/dist/neko.js +1148 -111
- package/dist/skills/skill-creator/LICENSE.txt +202 -0
- package/dist/skills/skill-creator/SKILL.md +270 -0
- package/dist/skills/skill-creator/assets/eval_review.html +146 -0
- package/dist/skills/skill-finder/SKILL.md +51 -0
- 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";
|
|
@@ -1088,10 +1098,19 @@ var init_prompt = __esm(() => {
|
|
|
1088
1098
|
});
|
|
1089
1099
|
|
|
1090
1100
|
// packages/core/src/prompt/resources.ts
|
|
1101
|
+
import { existsSync as existsSync2 } from "fs";
|
|
1091
1102
|
import { readFile as readFile3 } from "fs/promises";
|
|
1092
1103
|
import { homedir as homedir3 } from "os";
|
|
1093
1104
|
import { join as join4 } from "path";
|
|
1094
|
-
|
|
1105
|
+
import { fileURLToPath } from "url";
|
|
1106
|
+
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"), resolveBuiltinSkillsDir = () => {
|
|
1107
|
+
for (const url of [new URL("./skills/", import.meta.url), new URL("../../skills/", import.meta.url)]) {
|
|
1108
|
+
const path = fileURLToPath(url);
|
|
1109
|
+
if (existsSync2(join4(path, "skill-creator", "SKILL.md")))
|
|
1110
|
+
return path;
|
|
1111
|
+
}
|
|
1112
|
+
return null;
|
|
1113
|
+
}, BUILTIN_SKILLS_DIR, readResources = async (workspace, home, builtinDir, report, invocationName) => {
|
|
1095
1114
|
const contextFiles = [];
|
|
1096
1115
|
for (const path of [userAgentsFile(home), workspaceAgentsFile(workspace)]) {
|
|
1097
1116
|
try {
|
|
@@ -1112,11 +1131,13 @@ var userAgentsFile = (home) => join4(home, ".agents", "AGENTS.md"), userSkillsDi
|
|
|
1112
1131
|
if (skill.name === invocationName)
|
|
1113
1132
|
candidates.set(skill.filePath, content);
|
|
1114
1133
|
} : undefined;
|
|
1115
|
-
const
|
|
1116
|
-
|
|
1117
|
-
|
|
1134
|
+
const scan = async (dir, level) => (await scanSkillsDir(dir, report, capture)).map((skill) => ({ ...skill, level }));
|
|
1135
|
+
const [builtin, user, project] = await Promise.all([
|
|
1136
|
+
builtinDir === null ? Promise.resolve([]) : scan(builtinDir, "builtin"),
|
|
1137
|
+
scan(userSkillsDir(home), "user"),
|
|
1138
|
+
scan(workspaceSkillsDir(workspace), "project")
|
|
1118
1139
|
]);
|
|
1119
|
-
const skills = mergeSkills([user, project]);
|
|
1140
|
+
const skills = mergeSkills([builtin, user, project]);
|
|
1120
1141
|
const winner = invocationName === undefined ? undefined : skills.find((skill) => skill.name === invocationName);
|
|
1121
1142
|
if (winner && candidates) {
|
|
1122
1143
|
const content = candidates.get(winner.filePath);
|
|
@@ -1124,11 +1145,12 @@ var userAgentsFile = (home) => join4(home, ".agents", "AGENTS.md"), userSkillsDi
|
|
|
1124
1145
|
return { contextFiles, skills, invocation: { filePath: winner.filePath, content } };
|
|
1125
1146
|
}
|
|
1126
1147
|
return { contextFiles, skills };
|
|
1127
|
-
}, createResourceLoader = (home = homedir3(), report = warnPromptDiagnostic) => {
|
|
1148
|
+
}, createResourceLoader = (home = homedir3(), report = warnPromptDiagnostic, options) => {
|
|
1149
|
+
const builtinDir = options?.builtinDir === undefined ? BUILTIN_SKILLS_DIR : options.builtinDir;
|
|
1128
1150
|
const previous = new Map;
|
|
1129
1151
|
return async (workspace, invocationName) => {
|
|
1130
1152
|
const diagnostics = [];
|
|
1131
|
-
const resources = await readResources(workspace, home, (d) => diagnostics.push(d), invocationName);
|
|
1153
|
+
const resources = await readResources(workspace, home, builtinDir, (d) => diagnostics.push(d), invocationName);
|
|
1132
1154
|
const known = previous.get(workspace);
|
|
1133
1155
|
const current = new Set;
|
|
1134
1156
|
for (const diagnostic of diagnostics) {
|
|
@@ -1143,9 +1165,18 @@ var userAgentsFile = (home) => join4(home, ".agents", "AGENTS.md"), userSkillsDi
|
|
|
1143
1165
|
previous.delete(workspace);
|
|
1144
1166
|
return resources;
|
|
1145
1167
|
};
|
|
1168
|
+
}, scanSkillsByLevel = async (workspace, home = homedir3(), builtinDir = BUILTIN_SKILLS_DIR, report = warnPromptDiagnostic) => {
|
|
1169
|
+
const scan = async (dir, level) => (await scanSkillsDir(dir, report)).map((skill) => ({ ...skill, level }));
|
|
1170
|
+
const [builtin, user, project] = await Promise.all([
|
|
1171
|
+
builtinDir === null ? [] : scan(builtinDir, "builtin"),
|
|
1172
|
+
scan(userSkillsDir(home), "user"),
|
|
1173
|
+
scan(workspaceSkillsDir(workspace), "project")
|
|
1174
|
+
]);
|
|
1175
|
+
return [...project, ...user, ...builtin];
|
|
1146
1176
|
};
|
|
1147
1177
|
var init_resources = __esm(() => {
|
|
1148
1178
|
init_skills();
|
|
1179
|
+
BUILTIN_SKILLS_DIR = resolveBuiltinSkillsDir();
|
|
1149
1180
|
});
|
|
1150
1181
|
|
|
1151
1182
|
// packages/core/src/prompt/snapshots.ts
|
|
@@ -2313,7 +2344,21 @@ async function createNekoRuntime(options = {}) {
|
|
|
2313
2344
|
const session = await sessionFor(id);
|
|
2314
2345
|
const agent = await session.conversation.agent(context);
|
|
2315
2346
|
const { skills } = await loadResources(savedWorkspace(agent.cwd));
|
|
2316
|
-
return skills.map((skill) => ({
|
|
2347
|
+
return skills.map((skill) => ({
|
|
2348
|
+
name: skill.name,
|
|
2349
|
+
description: skill.description,
|
|
2350
|
+
location: skill.filePath,
|
|
2351
|
+
level: skill.level
|
|
2352
|
+
}));
|
|
2353
|
+
},
|
|
2354
|
+
async listSkillsByLevel(cwd) {
|
|
2355
|
+
const skills = await scanSkillsByLevel(normalizeWorkspace(cwd ?? defaultCwd), options.promptHome ?? homedir4());
|
|
2356
|
+
return skills.map((skill) => ({
|
|
2357
|
+
name: skill.name,
|
|
2358
|
+
description: skill.description,
|
|
2359
|
+
location: skill.filePath,
|
|
2360
|
+
level: skill.level
|
|
2361
|
+
}));
|
|
2317
2362
|
},
|
|
2318
2363
|
installExtension(extension) {
|
|
2319
2364
|
registry.install(extension);
|
|
@@ -2367,6 +2412,27 @@ var init_runtime = __esm(() => {
|
|
|
2367
2412
|
});
|
|
2368
2413
|
});
|
|
2369
2414
|
|
|
2415
|
+
// packages/core/src/skill-invocation.ts
|
|
2416
|
+
var unescapeXml = (value) => value.replace(/'/g, "'").replace(/"/g, '"').replace(/>/g, ">").replace(/</g, "<").replace(/&/g, "&"), parseSkillInvocation = (text) => {
|
|
2417
|
+
const open = /^<skill name="([^"]*)" location="([^"]*)">/.exec(text);
|
|
2418
|
+
if (!open)
|
|
2419
|
+
return null;
|
|
2420
|
+
const close = text.lastIndexOf("</skill>");
|
|
2421
|
+
if (close < open[0].length)
|
|
2422
|
+
return null;
|
|
2423
|
+
const rest = text.slice(close + "</skill>".length);
|
|
2424
|
+
if (rest !== "" && !rest.startsWith(`
|
|
2425
|
+
|
|
2426
|
+
`))
|
|
2427
|
+
return null;
|
|
2428
|
+
return {
|
|
2429
|
+
name: unescapeXml(open[1]),
|
|
2430
|
+
location: unescapeXml(open[2]),
|
|
2431
|
+
body: text.slice(open[0].length, close),
|
|
2432
|
+
args: rest.slice(2)
|
|
2433
|
+
};
|
|
2434
|
+
};
|
|
2435
|
+
|
|
2370
2436
|
// packages/core/src/index.ts
|
|
2371
2437
|
var init_src = __esm(() => {
|
|
2372
2438
|
init_compaction();
|
|
@@ -2375,6 +2441,7 @@ var init_src = __esm(() => {
|
|
|
2375
2441
|
init_image_metadata();
|
|
2376
2442
|
init_images();
|
|
2377
2443
|
init_projection();
|
|
2444
|
+
init_frontmatter();
|
|
2378
2445
|
init_runtime();
|
|
2379
2446
|
init_session_metadata();
|
|
2380
2447
|
init_workspace();
|
|
@@ -2770,7 +2837,8 @@ var init_labels = __esm(() => {
|
|
|
2770
2837
|
{ name: "model", description: "Choose a model" },
|
|
2771
2838
|
{ name: "think", description: "Set thinking level (/think high)" },
|
|
2772
2839
|
{ name: "fork", description: "Fork this session" },
|
|
2773
|
-
{ name: "archive", description: "Archive this session" }
|
|
2840
|
+
{ name: "archive", description: "Archive this session" },
|
|
2841
|
+
{ name: "skills", description: "Browse and install skills from the market" }
|
|
2774
2842
|
];
|
|
2775
2843
|
labels = {
|
|
2776
2844
|
ready: "Ready",
|
|
@@ -3174,17 +3242,62 @@ class PickerPanel {
|
|
|
3174
3242
|
}
|
|
3175
3243
|
close() {
|
|
3176
3244
|
++this.#generation;
|
|
3245
|
+
this.#details = [];
|
|
3177
3246
|
this.#state = "closed";
|
|
3178
3247
|
this.closed();
|
|
3179
3248
|
this.changed();
|
|
3180
3249
|
}
|
|
3250
|
+
showDetail(detail) {
|
|
3251
|
+
if (!this.open)
|
|
3252
|
+
return;
|
|
3253
|
+
this.#details.push(detail);
|
|
3254
|
+
this.changed();
|
|
3255
|
+
}
|
|
3256
|
+
popDetail() {
|
|
3257
|
+
if (this.#details.length === 0)
|
|
3258
|
+
return;
|
|
3259
|
+
this.#details.pop();
|
|
3260
|
+
this.changed();
|
|
3261
|
+
}
|
|
3262
|
+
get detailOpen() {
|
|
3263
|
+
return this.#details.length > 0;
|
|
3264
|
+
}
|
|
3265
|
+
get #detail() {
|
|
3266
|
+
return this.#details[this.#details.length - 1];
|
|
3267
|
+
}
|
|
3268
|
+
#details = [];
|
|
3181
3269
|
#filtered() {
|
|
3182
3270
|
const query = this.search.getValue().toLowerCase();
|
|
3183
|
-
|
|
3271
|
+
if (query !== "")
|
|
3272
|
+
return this.#items.filter((item) => !item.header && this.#matches(item, query));
|
|
3273
|
+
return this.#items;
|
|
3274
|
+
}
|
|
3275
|
+
#matches(item, query) {
|
|
3276
|
+
return `${item.label} ${item.description ?? ""} ${item.searchText ?? ""}`.toLowerCase().includes(query);
|
|
3277
|
+
}
|
|
3278
|
+
#firstSelectable(items) {
|
|
3279
|
+
return items.findIndex((item) => !item.header);
|
|
3280
|
+
}
|
|
3281
|
+
#move(delta) {
|
|
3282
|
+
const items = this.#filtered();
|
|
3283
|
+
let next = this.#index + delta;
|
|
3284
|
+
while (next >= 0 && next < items.length && items[next]?.header)
|
|
3285
|
+
next += delta;
|
|
3286
|
+
this.#index = Math.max(0, Math.min(Math.max(0, items.length - 1), next));
|
|
3287
|
+
if (items[this.#index]?.header)
|
|
3288
|
+
this.#index = this.#firstSelectable(items);
|
|
3184
3289
|
}
|
|
3185
3290
|
handleInput(data) {
|
|
3186
3291
|
if (isKeyRelease3(data))
|
|
3187
3292
|
return;
|
|
3293
|
+
if (this.#detail !== undefined) {
|
|
3294
|
+
if (matchesKey3(data, "escape") || matchesKey3(data, "ctrl+c")) {
|
|
3295
|
+
this.popDetail();
|
|
3296
|
+
} else if (this.#detail.handleKey(data)) {
|
|
3297
|
+
this.changed();
|
|
3298
|
+
}
|
|
3299
|
+
return;
|
|
3300
|
+
}
|
|
3188
3301
|
if (matchesKey3(data, "escape") || matchesKey3(data, "ctrl+c")) {
|
|
3189
3302
|
this.close();
|
|
3190
3303
|
return;
|
|
@@ -3198,18 +3311,25 @@ class PickerPanel {
|
|
|
3198
3311
|
return;
|
|
3199
3312
|
const items = this.#filtered();
|
|
3200
3313
|
if (matchesKey3(data, "up"))
|
|
3201
|
-
this.#
|
|
3314
|
+
this.#move(-1);
|
|
3202
3315
|
else if (matchesKey3(data, "down"))
|
|
3203
|
-
this.#
|
|
3316
|
+
this.#move(1);
|
|
3204
3317
|
else if (matchesKey3(data, "enter")) {
|
|
3205
3318
|
const item = items[this.#index];
|
|
3206
|
-
if (!item)
|
|
3319
|
+
if (!item || item.header)
|
|
3207
3320
|
return;
|
|
3208
3321
|
const generation = this.#generation;
|
|
3209
3322
|
this.#state = "applying";
|
|
3210
|
-
this.#pick(item.value).then(() => {
|
|
3211
|
-
if (generation
|
|
3212
|
-
|
|
3323
|
+
this.#pick(item.value).then((result) => {
|
|
3324
|
+
if (generation !== this.#generation)
|
|
3325
|
+
return;
|
|
3326
|
+
if (result !== undefined && typeof result === "object" && "lines" in result) {
|
|
3327
|
+
this.#state = "ready";
|
|
3328
|
+
this.showDetail(result);
|
|
3329
|
+
this.changed();
|
|
3330
|
+
return;
|
|
3331
|
+
}
|
|
3332
|
+
this.close();
|
|
3213
3333
|
}, (error) => {
|
|
3214
3334
|
if (generation !== this.#generation)
|
|
3215
3335
|
return;
|
|
@@ -3219,7 +3339,7 @@ class PickerPanel {
|
|
|
3219
3339
|
});
|
|
3220
3340
|
} else {
|
|
3221
3341
|
this.search.handleInput(data);
|
|
3222
|
-
this.#index =
|
|
3342
|
+
this.#index = this.#firstSelectable(this.#filtered());
|
|
3223
3343
|
}
|
|
3224
3344
|
this.changed();
|
|
3225
3345
|
}
|
|
@@ -3227,6 +3347,15 @@ class PickerPanel {
|
|
|
3227
3347
|
const height = Math.max(1, this.height);
|
|
3228
3348
|
const w = Math.max(1, width - 2);
|
|
3229
3349
|
const rows = [style.bold(this.#title)];
|
|
3350
|
+
if (this.#detail !== undefined) {
|
|
3351
|
+
const body = this.#detail.lines(w, Math.max(1, height - 2));
|
|
3352
|
+
rows.push(...body);
|
|
3353
|
+
while (rows.length < height - 1)
|
|
3354
|
+
rows.push("");
|
|
3355
|
+
if (height > 1)
|
|
3356
|
+
rows.push(this.#detail.help);
|
|
3357
|
+
return rows.slice(0, height).map((line) => theme.panel(` ${truncateToWidth3(line, w, "...", true)} `));
|
|
3358
|
+
}
|
|
3230
3359
|
if (height >= 4)
|
|
3231
3360
|
rows.push(...this.search.render(w).slice(0, 1));
|
|
3232
3361
|
const help = this.#state === "error" ? labels.retry : this.#state === "ready" ? labels.select : labels.close;
|
|
@@ -3236,11 +3365,20 @@ class PickerPanel {
|
|
|
3236
3365
|
else {
|
|
3237
3366
|
const items = this.#filtered();
|
|
3238
3367
|
this.#index = Math.min(this.#index, Math.max(0, items.length - 1));
|
|
3368
|
+
if (items[this.#index]?.header) {
|
|
3369
|
+
const first = this.#firstSelectable(items);
|
|
3370
|
+
if (first >= 0)
|
|
3371
|
+
this.#index = first;
|
|
3372
|
+
}
|
|
3239
3373
|
const selected = items[this.#index];
|
|
3240
3374
|
const details = height >= 9 && selected?.description ? wrapTextWithAnsi(selected.description, w).slice(0, 2) : [];
|
|
3241
3375
|
const count = Math.max(1, available - details.length);
|
|
3242
3376
|
const start = Math.max(0, Math.min(this.#index - Math.floor(count / 2), items.length - count));
|
|
3243
3377
|
for (const [i, item] of items.slice(start, start + count).entries()) {
|
|
3378
|
+
if (item.header) {
|
|
3379
|
+
rows.push(theme.dim(` ${item.label}`));
|
|
3380
|
+
continue;
|
|
3381
|
+
}
|
|
3244
3382
|
const right = item.rightLabel ?? "";
|
|
3245
3383
|
const leftWidth = Math.max(1, w - 3 - visibleWidth2(right));
|
|
3246
3384
|
const left = truncateToWidth3(item.label, leftWidth, "...");
|
|
@@ -3341,7 +3479,7 @@ ${theme.error(state.note)}`;
|
|
|
3341
3479
|
});
|
|
3342
3480
|
|
|
3343
3481
|
// packages/tui/src/components/user-message.ts
|
|
3344
|
-
import { Container as Container4, Markdown as Markdown2 } from "@earendil-works/pi-tui";
|
|
3482
|
+
import { Container as Container4, Markdown as Markdown2, Text as Text4 } from "@earendil-works/pi-tui";
|
|
3345
3483
|
var UserMessageComponent;
|
|
3346
3484
|
var init_user_message = __esm(() => {
|
|
3347
3485
|
init_theme();
|
|
@@ -3358,6 +3496,16 @@ var init_user_message = __esm(() => {
|
|
|
3358
3496
|
}
|
|
3359
3497
|
#rebuild() {
|
|
3360
3498
|
this.clear();
|
|
3499
|
+
const invocation = parseSkillInvocation(this.#text);
|
|
3500
|
+
if (invocation !== null) {
|
|
3501
|
+
const args = invocation.args.replace(/\s+/g, " ").trim();
|
|
3502
|
+
const preview = args.length > 100 ? `${args.slice(0, 99)}\u2026` : args;
|
|
3503
|
+
const head = `${theme.toolTitle(`\u2726 skill:${invocation.name}`)}${preview ? ` ${theme.userText(preview)}` : ""}`;
|
|
3504
|
+
const source = theme.dim(`skill body from ${invocation.location} (collapsed)`);
|
|
3505
|
+
this.addChild(new Text4(`${head}
|
|
3506
|
+
${source}`, 1, 0, theme.userBg));
|
|
3507
|
+
return;
|
|
3508
|
+
}
|
|
3361
3509
|
this.addChild(new Markdown2(this.#text, 1, 0, getMarkdownTheme(), {
|
|
3362
3510
|
color: theme.userText,
|
|
3363
3511
|
bgColor: theme.userBg
|
|
@@ -3621,7 +3769,7 @@ var init_file_completion = __esm(() => {
|
|
|
3621
3769
|
|
|
3622
3770
|
// packages/gateway/src/contract.ts
|
|
3623
3771
|
import { defineService } from "@earendil-works/chord";
|
|
3624
|
-
var NekoSessionDirectory, NekoSessionManagement, NekoModels, NekoChat, NekoWorkspaces, NekoCredentials, NekoWorkspaceFiles;
|
|
3772
|
+
var NekoSessionDirectory, NekoSessionManagement, NekoModels, NekoChat, NekoWorkspaces, NekoCredentials, NekoWorkspaceFiles, NekoSkillMarket;
|
|
3625
3773
|
var init_contract = __esm(() => {
|
|
3626
3774
|
NekoSessionDirectory = defineService("neko.session-directory");
|
|
3627
3775
|
NekoSessionManagement = defineService("neko.session-management");
|
|
@@ -3630,6 +3778,7 @@ var init_contract = __esm(() => {
|
|
|
3630
3778
|
NekoWorkspaces = defineService("neko.workspaces");
|
|
3631
3779
|
NekoCredentials = defineService("neko.credentials");
|
|
3632
3780
|
NekoWorkspaceFiles = defineService("neko.workspace-files");
|
|
3781
|
+
NekoSkillMarket = defineService("neko.skill-market");
|
|
3633
3782
|
});
|
|
3634
3783
|
|
|
3635
3784
|
// packages/gateway/src/ws-listener.ts
|
|
@@ -3782,7 +3931,8 @@ async function connectNekoGateway(address) {
|
|
|
3782
3931
|
NekoModels,
|
|
3783
3932
|
NekoWorkspaces,
|
|
3784
3933
|
NekoWorkspaceFiles,
|
|
3785
|
-
NekoCredentials
|
|
3934
|
+
NekoCredentials,
|
|
3935
|
+
NekoSkillMarket
|
|
3786
3936
|
],
|
|
3787
3937
|
transport: serverTransport
|
|
3788
3938
|
});
|
|
@@ -3798,6 +3948,7 @@ async function connectNekoGateway(address) {
|
|
|
3798
3948
|
workspaces: serverBinding.use(NekoWorkspaces),
|
|
3799
3949
|
workspaceFiles: serverBinding.use(NekoWorkspaceFiles),
|
|
3800
3950
|
credentials: serverBinding.use(NekoCredentials),
|
|
3951
|
+
skillMarket: serverBinding.use(NekoSkillMarket),
|
|
3801
3952
|
listModels: () => models.list(BACKGROUND_CONTEXT2),
|
|
3802
3953
|
async attach(sessionId) {
|
|
3803
3954
|
await sessionBinding?.dispose(BACKGROUND_CONTEXT2).catch(() => {});
|
|
@@ -3913,10 +4064,617 @@ function fileSearchInstallHelp(platform = process.platform) {
|
|
|
3913
4064
|
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
4065
|
}
|
|
3915
4066
|
|
|
4067
|
+
// node_modules/fflate/esm/index.mjs
|
|
4068
|
+
import { createRequire } from "module";
|
|
4069
|
+
function inflateSync(data, opts) {
|
|
4070
|
+
return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);
|
|
4071
|
+
}
|
|
4072
|
+
function strFromU8(dat, latin1) {
|
|
4073
|
+
if (latin1) {
|
|
4074
|
+
var r = "";
|
|
4075
|
+
for (var i = 0;i < dat.length; i += 16384)
|
|
4076
|
+
r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));
|
|
4077
|
+
return r;
|
|
4078
|
+
} else if (td) {
|
|
4079
|
+
return td.decode(dat);
|
|
4080
|
+
} else {
|
|
4081
|
+
var _a = dutf8(dat), { s, r } = _a;
|
|
4082
|
+
if (r.length)
|
|
4083
|
+
err(8);
|
|
4084
|
+
return s;
|
|
4085
|
+
}
|
|
4086
|
+
}
|
|
4087
|
+
function unzipSync(data, opts) {
|
|
4088
|
+
var files = {};
|
|
4089
|
+
var e = data.length - 22;
|
|
4090
|
+
for (;b4(data, e) != 101010256; --e) {
|
|
4091
|
+
if (!e || data.length - e > 65558)
|
|
4092
|
+
err(13);
|
|
4093
|
+
}
|
|
4094
|
+
var c = b2(data, e + 8);
|
|
4095
|
+
if (!c)
|
|
4096
|
+
return {};
|
|
4097
|
+
var o = b4(data, e + 16);
|
|
4098
|
+
var z = b4(data, e - 20) == 117853008;
|
|
4099
|
+
if (z) {
|
|
4100
|
+
var ze = b4(data, e - 12);
|
|
4101
|
+
z = b4(data, ze) == 101075792;
|
|
4102
|
+
if (z) {
|
|
4103
|
+
c = b4(data, ze + 32);
|
|
4104
|
+
o = b4(data, ze + 48);
|
|
4105
|
+
}
|
|
4106
|
+
}
|
|
4107
|
+
var fltr = opts && opts.filter;
|
|
4108
|
+
for (var i = 0;i < c; ++i) {
|
|
4109
|
+
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);
|
|
4110
|
+
o = no;
|
|
4111
|
+
if (!fltr || fltr({
|
|
4112
|
+
name: fn,
|
|
4113
|
+
size: sc,
|
|
4114
|
+
originalSize: su,
|
|
4115
|
+
compression: c_2
|
|
4116
|
+
})) {
|
|
4117
|
+
if (!c_2)
|
|
4118
|
+
files[fn] = slc(data, b, b + sc);
|
|
4119
|
+
else if (c_2 == 8)
|
|
4120
|
+
files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) });
|
|
4121
|
+
else
|
|
4122
|
+
err(14, "unknown compression type " + c_2);
|
|
4123
|
+
}
|
|
4124
|
+
}
|
|
4125
|
+
return files;
|
|
4126
|
+
}
|
|
4127
|
+
var require2, _a, Worker, isMarkedAsUntransferable, u8, u16, i32, fleb, fdeb, clim, freb = function(eb, start) {
|
|
4128
|
+
var b = new u16(31);
|
|
4129
|
+
for (var i = 0;i < 31; ++i) {
|
|
4130
|
+
b[i] = start += 1 << eb[i - 1];
|
|
4131
|
+
}
|
|
4132
|
+
var r = new i32(b[30]);
|
|
4133
|
+
for (var i = 1;i < 30; ++i) {
|
|
4134
|
+
for (var j = b[i];j < b[i + 1]; ++j) {
|
|
4135
|
+
r[j] = j - b[i] << 5 | i;
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
return { b, r };
|
|
4139
|
+
}, _a, fl, revfl, _b, fd, revfd, rev, x, i, hMap = function(cd, mb, r) {
|
|
4140
|
+
var s = cd.length;
|
|
4141
|
+
var i = 0;
|
|
4142
|
+
var l = new u16(mb);
|
|
4143
|
+
for (;i < s; ++i) {
|
|
4144
|
+
if (cd[i])
|
|
4145
|
+
++l[cd[i] - 1];
|
|
4146
|
+
}
|
|
4147
|
+
var le = new u16(mb);
|
|
4148
|
+
for (i = 1;i < mb; ++i) {
|
|
4149
|
+
le[i] = le[i - 1] + l[i - 1] << 1;
|
|
4150
|
+
}
|
|
4151
|
+
var co;
|
|
4152
|
+
if (r) {
|
|
4153
|
+
co = new u16(1 << mb);
|
|
4154
|
+
var rvb = 15 - mb;
|
|
4155
|
+
for (i = 0;i < s; ++i) {
|
|
4156
|
+
if (cd[i]) {
|
|
4157
|
+
var sv = i << 4 | cd[i];
|
|
4158
|
+
var r_1 = mb - cd[i];
|
|
4159
|
+
var v = le[cd[i] - 1]++ << r_1;
|
|
4160
|
+
for (var m = v | (1 << r_1) - 1;v <= m; ++v) {
|
|
4161
|
+
co[rev[v] >> rvb] = sv;
|
|
4162
|
+
}
|
|
4163
|
+
}
|
|
4164
|
+
}
|
|
4165
|
+
} else {
|
|
4166
|
+
co = new u16(s);
|
|
4167
|
+
for (i = 0;i < s; ++i) {
|
|
4168
|
+
if (cd[i]) {
|
|
4169
|
+
co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];
|
|
4170
|
+
}
|
|
4171
|
+
}
|
|
4172
|
+
}
|
|
4173
|
+
return co;
|
|
4174
|
+
}, flt, i, i, i, i, fdt, i, flrm, fdrm, max = function(a) {
|
|
4175
|
+
var m = a[0];
|
|
4176
|
+
for (var i = 1;i < a.length; ++i) {
|
|
4177
|
+
if (a[i] > m)
|
|
4178
|
+
m = a[i];
|
|
4179
|
+
}
|
|
4180
|
+
return m;
|
|
4181
|
+
}, bits = function(d, p, m) {
|
|
4182
|
+
var o = p / 8 | 0;
|
|
4183
|
+
return (d[o] | d[o + 1] << 8) >> (p & 7) & m;
|
|
4184
|
+
}, bits16 = function(d, p) {
|
|
4185
|
+
var o = p / 8 | 0;
|
|
4186
|
+
return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);
|
|
4187
|
+
}, shft = function(p) {
|
|
4188
|
+
return (p + 7) / 8 | 0;
|
|
4189
|
+
}, slc = function(v, s, e) {
|
|
4190
|
+
if (s == null || s < 0)
|
|
4191
|
+
s = 0;
|
|
4192
|
+
if (e == null || e > v.length)
|
|
4193
|
+
e = v.length;
|
|
4194
|
+
return new u8(v.subarray(s, e));
|
|
4195
|
+
}, ec, err = function(ind, msg, nt) {
|
|
4196
|
+
var e = new Error(msg || ec[ind]);
|
|
4197
|
+
e.code = ind;
|
|
4198
|
+
if (Error.captureStackTrace)
|
|
4199
|
+
Error.captureStackTrace(e, err);
|
|
4200
|
+
if (!nt)
|
|
4201
|
+
throw e;
|
|
4202
|
+
return e;
|
|
4203
|
+
}, inflt = function(dat, st, buf, dict) {
|
|
4204
|
+
var sl = dat.length, dl = dict ? dict.length : 0;
|
|
4205
|
+
if (!sl || st.f && !st.l)
|
|
4206
|
+
return buf || new u8(0);
|
|
4207
|
+
var noBuf = !buf;
|
|
4208
|
+
var resize = noBuf || st.i != 2;
|
|
4209
|
+
var noSt = st.i;
|
|
4210
|
+
if (noBuf)
|
|
4211
|
+
buf = new u8(sl * 3);
|
|
4212
|
+
var cbuf = function(l) {
|
|
4213
|
+
var bl = buf.length;
|
|
4214
|
+
if (l > bl) {
|
|
4215
|
+
var nbuf = new u8(Math.max(bl * 2, l));
|
|
4216
|
+
nbuf.set(buf);
|
|
4217
|
+
buf = nbuf;
|
|
4218
|
+
}
|
|
4219
|
+
};
|
|
4220
|
+
var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, { l: lm, d: dm, m: lbt, n: dbt } = st;
|
|
4221
|
+
var tbts = sl * 8;
|
|
4222
|
+
do {
|
|
4223
|
+
if (!lm) {
|
|
4224
|
+
final = bits(dat, pos, 1);
|
|
4225
|
+
var type = bits(dat, pos + 1, 3);
|
|
4226
|
+
pos += 3;
|
|
4227
|
+
if (!type) {
|
|
4228
|
+
var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;
|
|
4229
|
+
if (t > sl) {
|
|
4230
|
+
if (noSt)
|
|
4231
|
+
err(0);
|
|
4232
|
+
break;
|
|
4233
|
+
}
|
|
4234
|
+
if (resize)
|
|
4235
|
+
cbuf(bt + l);
|
|
4236
|
+
buf.set(dat.subarray(s, t), bt);
|
|
4237
|
+
st.b = bt += l, st.p = pos = t * 8, st.f = final;
|
|
4238
|
+
continue;
|
|
4239
|
+
} else if (type == 1)
|
|
4240
|
+
lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
|
|
4241
|
+
else if (type == 2) {
|
|
4242
|
+
var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
|
|
4243
|
+
var tl = hLit + bits(dat, pos + 5, 31) + 1;
|
|
4244
|
+
pos += 14;
|
|
4245
|
+
var ldt = new u8(tl);
|
|
4246
|
+
var clt = new u8(19);
|
|
4247
|
+
for (var i = 0;i < hcLen; ++i) {
|
|
4248
|
+
clt[clim[i]] = bits(dat, pos + i * 3, 7);
|
|
4249
|
+
}
|
|
4250
|
+
pos += hcLen * 3;
|
|
4251
|
+
var clb = max(clt), clbmsk = (1 << clb) - 1;
|
|
4252
|
+
var clm = hMap(clt, clb, 1);
|
|
4253
|
+
for (var i = 0;i < tl; ) {
|
|
4254
|
+
var r = clm[bits(dat, pos, clbmsk)];
|
|
4255
|
+
pos += r & 15;
|
|
4256
|
+
var s = r >> 4;
|
|
4257
|
+
if (s < 16) {
|
|
4258
|
+
ldt[i++] = s;
|
|
4259
|
+
} else {
|
|
4260
|
+
var c = 0, n = 0;
|
|
4261
|
+
if (s == 16)
|
|
4262
|
+
n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];
|
|
4263
|
+
else if (s == 17)
|
|
4264
|
+
n = 3 + bits(dat, pos, 7), pos += 3;
|
|
4265
|
+
else if (s == 18)
|
|
4266
|
+
n = 11 + bits(dat, pos, 127), pos += 7;
|
|
4267
|
+
while (n--)
|
|
4268
|
+
ldt[i++] = c;
|
|
4269
|
+
}
|
|
4270
|
+
}
|
|
4271
|
+
var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
|
|
4272
|
+
lbt = max(lt);
|
|
4273
|
+
dbt = max(dt);
|
|
4274
|
+
lm = hMap(lt, lbt, 1);
|
|
4275
|
+
dm = hMap(dt, dbt, 1);
|
|
4276
|
+
} else
|
|
4277
|
+
err(1);
|
|
4278
|
+
if (pos > tbts) {
|
|
4279
|
+
if (noSt)
|
|
4280
|
+
err(0);
|
|
4281
|
+
break;
|
|
4282
|
+
}
|
|
4283
|
+
}
|
|
4284
|
+
if (resize)
|
|
4285
|
+
cbuf(bt + 131072);
|
|
4286
|
+
var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
|
|
4287
|
+
var lpos = pos;
|
|
4288
|
+
for (;; lpos = pos) {
|
|
4289
|
+
var c = lm[bits16(dat, pos) & lms], sym = c >> 4;
|
|
4290
|
+
pos += c & 15;
|
|
4291
|
+
if (pos > tbts) {
|
|
4292
|
+
if (noSt)
|
|
4293
|
+
err(0);
|
|
4294
|
+
break;
|
|
4295
|
+
}
|
|
4296
|
+
if (!c)
|
|
4297
|
+
err(2);
|
|
4298
|
+
if (sym < 256)
|
|
4299
|
+
buf[bt++] = sym;
|
|
4300
|
+
else if (sym == 256) {
|
|
4301
|
+
lpos = pos, lm = null;
|
|
4302
|
+
break;
|
|
4303
|
+
} else {
|
|
4304
|
+
var add = sym - 254;
|
|
4305
|
+
if (sym > 264) {
|
|
4306
|
+
var i = sym - 257, b = fleb[i];
|
|
4307
|
+
add = bits(dat, pos, (1 << b) - 1) + fl[i];
|
|
4308
|
+
pos += b;
|
|
4309
|
+
}
|
|
4310
|
+
var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;
|
|
4311
|
+
if (!d)
|
|
4312
|
+
err(3);
|
|
4313
|
+
pos += d & 15;
|
|
4314
|
+
var dt = fd[dsym];
|
|
4315
|
+
if (dsym > 3) {
|
|
4316
|
+
var b = fdeb[dsym];
|
|
4317
|
+
dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
|
|
4318
|
+
}
|
|
4319
|
+
if (pos > tbts) {
|
|
4320
|
+
if (noSt)
|
|
4321
|
+
err(0);
|
|
4322
|
+
break;
|
|
4323
|
+
}
|
|
4324
|
+
if (resize)
|
|
4325
|
+
cbuf(bt + 131072);
|
|
4326
|
+
var end = bt + add;
|
|
4327
|
+
if (bt < dt) {
|
|
4328
|
+
var shift = dl - dt, dend = Math.min(dt, end);
|
|
4329
|
+
if (shift + bt < 0)
|
|
4330
|
+
err(3);
|
|
4331
|
+
for (;bt < dend; ++bt)
|
|
4332
|
+
buf[bt] = dict[shift + bt];
|
|
4333
|
+
}
|
|
4334
|
+
for (;bt < end; ++bt)
|
|
4335
|
+
buf[bt] = buf[bt - dt];
|
|
4336
|
+
}
|
|
4337
|
+
}
|
|
4338
|
+
st.l = lm, st.p = lpos, st.b = bt, st.f = final;
|
|
4339
|
+
if (lm)
|
|
4340
|
+
final = 1, st.m = lbt, st.d = dm, st.n = dbt;
|
|
4341
|
+
} while (!final);
|
|
4342
|
+
return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
|
|
4343
|
+
}, et, b2 = function(d, b) {
|
|
4344
|
+
return d[b] | d[b + 1] << 8;
|
|
4345
|
+
}, b4 = function(d, b) {
|
|
4346
|
+
return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
|
|
4347
|
+
}, b8 = function(d, b) {
|
|
4348
|
+
return b4(d, b) + b4(d, b + 4) * 4294967296;
|
|
4349
|
+
}, td, tds = 0, dutf8 = function(d) {
|
|
4350
|
+
for (var r = "", i = 0;; ) {
|
|
4351
|
+
var c = d[i++];
|
|
4352
|
+
var eb = (c > 127) + (c > 223) + (c > 239);
|
|
4353
|
+
if (i + eb > d.length)
|
|
4354
|
+
return { s: r, r: slc(d, i - 1) };
|
|
4355
|
+
if (!eb)
|
|
4356
|
+
r += String.fromCharCode(c);
|
|
4357
|
+
else if (eb == 3) {
|
|
4358
|
+
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);
|
|
4359
|
+
} else if (eb & 1)
|
|
4360
|
+
r += String.fromCharCode((c & 31) << 6 | d[i++] & 63);
|
|
4361
|
+
else
|
|
4362
|
+
r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | d[i++] & 63);
|
|
4363
|
+
}
|
|
4364
|
+
}, slzh = function(d, b) {
|
|
4365
|
+
return b + 30 + b2(d, b + 26) + b2(d, b + 28);
|
|
4366
|
+
}, zh = function(d, b, z) {
|
|
4367
|
+
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;
|
|
4368
|
+
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];
|
|
4369
|
+
return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off];
|
|
4370
|
+
}, z64hs = function(d, b, l, z, sc, su, off) {
|
|
4371
|
+
var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l;
|
|
4372
|
+
var nf = nsc + nsu + noff;
|
|
4373
|
+
if (z && nf) {
|
|
4374
|
+
for (;b + 4 < e; b += 4 + b2(d, b + 2)) {
|
|
4375
|
+
if (b2(d, b) == 1) {
|
|
4376
|
+
return [
|
|
4377
|
+
nsc ? b8(d, b + 4 + 8 * nsu) : sc,
|
|
4378
|
+
nsu ? b8(d, b + 4) : su,
|
|
4379
|
+
noff ? b8(d, b + 4 + 8 * (nsu + nsc)) : off,
|
|
4380
|
+
1
|
|
4381
|
+
];
|
|
4382
|
+
}
|
|
4383
|
+
}
|
|
4384
|
+
if (z < 2)
|
|
4385
|
+
err(13);
|
|
4386
|
+
}
|
|
4387
|
+
return [sc, su, off, 0];
|
|
4388
|
+
};
|
|
4389
|
+
var init_esm = __esm(() => {
|
|
4390
|
+
require2 = createRequire("/");
|
|
4391
|
+
try {
|
|
4392
|
+
_a = require2("worker_threads"), Worker = _a.Worker, isMarkedAsUntransferable = _a.isMarkedAsUntransferable;
|
|
4393
|
+
} catch (e) {}
|
|
4394
|
+
u8 = Uint8Array;
|
|
4395
|
+
u16 = Uint16Array;
|
|
4396
|
+
i32 = Int32Array;
|
|
4397
|
+
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]);
|
|
4398
|
+
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]);
|
|
4399
|
+
clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
|
|
4400
|
+
_a = freb(fleb, 2);
|
|
4401
|
+
fl = _a.b;
|
|
4402
|
+
revfl = _a.r;
|
|
4403
|
+
fl[28] = 258, revfl[258] = 28;
|
|
4404
|
+
_b = freb(fdeb, 0);
|
|
4405
|
+
fd = _b.b;
|
|
4406
|
+
revfd = _b.r;
|
|
4407
|
+
rev = new u16(32768);
|
|
4408
|
+
for (i = 0;i < 32768; ++i) {
|
|
4409
|
+
x = (i & 43690) >> 1 | (i & 21845) << 1;
|
|
4410
|
+
x = (x & 52428) >> 2 | (x & 13107) << 2;
|
|
4411
|
+
x = (x & 61680) >> 4 | (x & 3855) << 4;
|
|
4412
|
+
rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
|
|
4413
|
+
}
|
|
4414
|
+
flt = new u8(288);
|
|
4415
|
+
for (i = 0;i < 144; ++i)
|
|
4416
|
+
flt[i] = 8;
|
|
4417
|
+
for (i = 144;i < 256; ++i)
|
|
4418
|
+
flt[i] = 9;
|
|
4419
|
+
for (i = 256;i < 280; ++i)
|
|
4420
|
+
flt[i] = 7;
|
|
4421
|
+
for (i = 280;i < 288; ++i)
|
|
4422
|
+
flt[i] = 8;
|
|
4423
|
+
fdt = new u8(32);
|
|
4424
|
+
for (i = 0;i < 32; ++i)
|
|
4425
|
+
fdt[i] = 5;
|
|
4426
|
+
flrm = /* @__PURE__ */ hMap(flt, 9, 1);
|
|
4427
|
+
fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);
|
|
4428
|
+
ec = [
|
|
4429
|
+
"unexpected EOF",
|
|
4430
|
+
"invalid block type",
|
|
4431
|
+
"invalid length/literal",
|
|
4432
|
+
"invalid distance",
|
|
4433
|
+
"stream finished",
|
|
4434
|
+
"no stream handler",
|
|
4435
|
+
,
|
|
4436
|
+
"no callback",
|
|
4437
|
+
"invalid UTF-8 data",
|
|
4438
|
+
"extra field too long",
|
|
4439
|
+
"date not in range 1980-2099",
|
|
4440
|
+
"filename too long",
|
|
4441
|
+
"stream finishing",
|
|
4442
|
+
"invalid zip data"
|
|
4443
|
+
];
|
|
4444
|
+
et = /* @__PURE__ */ new u8(0);
|
|
4445
|
+
td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder;
|
|
4446
|
+
try {
|
|
4447
|
+
td.decode(et, { stream: true });
|
|
4448
|
+
tds = 1;
|
|
4449
|
+
} catch (e) {}
|
|
4450
|
+
});
|
|
4451
|
+
|
|
4452
|
+
// packages/gateway/src/skill-market.ts
|
|
4453
|
+
import { createHash as createHash2, randomUUID } from "crypto";
|
|
4454
|
+
import { mkdir as mkdir2, readdir as readdir2, rename as rename2, rm as rm2, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
4455
|
+
import { homedir as homedir5 } from "os";
|
|
4456
|
+
import { dirname as dirname5, join as join8 } from "path";
|
|
4457
|
+
function createSkillMarketClient(options) {
|
|
4458
|
+
const home = options.home ?? homedir5();
|
|
4459
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
4460
|
+
const now = options.now ?? Date.now;
|
|
4461
|
+
let base;
|
|
4462
|
+
try {
|
|
4463
|
+
base = new URL(options.marketUrl);
|
|
4464
|
+
if (base.protocol !== "https:" && base.protocol !== "http:")
|
|
4465
|
+
throw new Error("unsupported protocol");
|
|
4466
|
+
} catch {
|
|
4467
|
+
throw new SkillMarketError("market_invalid_url", `Invalid skill market URL: ${options.marketUrl}`);
|
|
4468
|
+
}
|
|
4469
|
+
base = new URL(base.toString().replace(/\/+$/, ""));
|
|
4470
|
+
let catalog;
|
|
4471
|
+
const zipCache = new Map;
|
|
4472
|
+
const request = async (path) => {
|
|
4473
|
+
let response;
|
|
4474
|
+
try {
|
|
4475
|
+
response = await fetchImpl(new URL(path, `${base}/`).toString());
|
|
4476
|
+
} catch (error) {
|
|
4477
|
+
throw new SkillMarketError("market_unavailable", `Skill market unreachable: ${error instanceof Error ? error.message : String(error)}`);
|
|
4478
|
+
}
|
|
4479
|
+
return response;
|
|
4480
|
+
};
|
|
4481
|
+
const refreshCatalog = async () => {
|
|
4482
|
+
const response = await request("api/skills");
|
|
4483
|
+
if (!response.ok)
|
|
4484
|
+
throw new SkillMarketError("market_unavailable", `Skill list failed with HTTP ${response.status}`);
|
|
4485
|
+
const data = await response.json();
|
|
4486
|
+
const skills = Array.isArray(data.skills) ? data.skills.map(normalizeEntry) : [];
|
|
4487
|
+
catalog = { at: now(), skills };
|
|
4488
|
+
return skills;
|
|
4489
|
+
};
|
|
4490
|
+
const listSkills = async () => catalog !== undefined && now() - catalog.at < CATALOG_TTL_MS ? catalog.skills : refreshCatalog();
|
|
4491
|
+
const detail = async (name) => {
|
|
4492
|
+
let hit = (await listSkills()).find((skill) => skill.name === name);
|
|
4493
|
+
if (hit === undefined)
|
|
4494
|
+
hit = (await refreshCatalog()).find((skill) => skill.name === name);
|
|
4495
|
+
if (hit === undefined)
|
|
4496
|
+
throw new SkillMarketError("skill_not_found", `Skill not found on market: ${name}`);
|
|
4497
|
+
return hit;
|
|
4498
|
+
};
|
|
4499
|
+
const download = async (skill) => {
|
|
4500
|
+
const cached = zipCache.get(skill.sha256);
|
|
4501
|
+
if (cached !== undefined) {
|
|
4502
|
+
zipCache.delete(skill.sha256);
|
|
4503
|
+
zipCache.set(skill.sha256, cached);
|
|
4504
|
+
return cached;
|
|
4505
|
+
}
|
|
4506
|
+
if (skill.sizeBytes > MAX_PACKAGE_BYTES)
|
|
4507
|
+
throw new SkillMarketError("skill_too_large", `Package ${skill.name} is ${skill.sizeBytes} bytes (limit ${MAX_PACKAGE_BYTES})`);
|
|
4508
|
+
const response = await request(`api/skills/${encodeURIComponent(skill.name)}/download`);
|
|
4509
|
+
if (!response.ok)
|
|
4510
|
+
throw new SkillMarketError(response.status === 404 ? "skill_not_found" : "market_unavailable", `Download of ${skill.name} failed with HTTP ${response.status}`);
|
|
4511
|
+
const bytes = new Uint8Array(await response.arrayBuffer());
|
|
4512
|
+
if (bytes.byteLength > MAX_PACKAGE_BYTES)
|
|
4513
|
+
throw new SkillMarketError("skill_too_large", `Package ${skill.name} exceeds ${MAX_PACKAGE_BYTES} bytes`);
|
|
4514
|
+
const digest = createHash2("sha256").update(bytes).digest("hex");
|
|
4515
|
+
if (digest !== skill.sha256)
|
|
4516
|
+
throw new SkillMarketError("skill_hash_mismatch", `SHA-256 mismatch for ${skill.name}: catalog says ${skill.sha256}, got ${digest}`);
|
|
4517
|
+
zipCache.set(skill.sha256, bytes);
|
|
4518
|
+
while (zipCache.size > ZIP_CACHE_MAX) {
|
|
4519
|
+
const oldest = zipCache.keys().next().value;
|
|
4520
|
+
if (oldest === undefined)
|
|
4521
|
+
break;
|
|
4522
|
+
zipCache.delete(oldest);
|
|
4523
|
+
}
|
|
4524
|
+
return bytes;
|
|
4525
|
+
};
|
|
4526
|
+
const unpack = (skill, zip) => {
|
|
4527
|
+
let entries;
|
|
4528
|
+
try {
|
|
4529
|
+
entries = unzipSync(zip);
|
|
4530
|
+
} catch {
|
|
4531
|
+
throw new SkillMarketError("skill_invalid_package", `Package ${skill.name} is not a valid zip archive`);
|
|
4532
|
+
}
|
|
4533
|
+
const files = new Map;
|
|
4534
|
+
const skillMds = [];
|
|
4535
|
+
for (const name of Object.keys(entries)) {
|
|
4536
|
+
if (name.endsWith("/"))
|
|
4537
|
+
continue;
|
|
4538
|
+
if (name.includes("\\") || name.startsWith("/"))
|
|
4539
|
+
throw new SkillMarketError("skill_invalid_package", `Unsafe path in package: ${name}`);
|
|
4540
|
+
const segments = name.split("/");
|
|
4541
|
+
if (segments.some((s) => s === ".." || s === ""))
|
|
4542
|
+
throw new SkillMarketError("skill_invalid_package", `Unsafe path in package: ${name}`);
|
|
4543
|
+
if (segments[segments.length - 1] === "SKILL.md")
|
|
4544
|
+
skillMds.push(name);
|
|
4545
|
+
files.set(name, entries[name]);
|
|
4546
|
+
}
|
|
4547
|
+
if (skillMds.length !== 1)
|
|
4548
|
+
throw new SkillMarketError("skill_invalid_package", skillMds.length === 0 ? `Package ${skill.name} contains no SKILL.md` : `Package ${skill.name} contains multiple SKILL.md files`);
|
|
4549
|
+
const root = skillMds[0].slice(0, -"SKILL.md".length);
|
|
4550
|
+
const inner = new Map;
|
|
4551
|
+
for (const [name, bytes] of files) {
|
|
4552
|
+
if (!name.startsWith(root))
|
|
4553
|
+
continue;
|
|
4554
|
+
inner.set(name.slice(root.length), bytes);
|
|
4555
|
+
}
|
|
4556
|
+
return inner;
|
|
4557
|
+
};
|
|
4558
|
+
const skillsDirFor = (scope, workspaceRoot) => {
|
|
4559
|
+
if (scope === "user")
|
|
4560
|
+
return userSkillsDir2(home);
|
|
4561
|
+
if (workspaceRoot === undefined || workspaceRoot === "")
|
|
4562
|
+
throw new SkillMarketError("market_unavailable", "Project-scope install needs a workspaceRoot");
|
|
4563
|
+
return projectSkillsDir(workspaceRoot);
|
|
4564
|
+
};
|
|
4565
|
+
const sweepTempDirs = async (skillsDir) => {
|
|
4566
|
+
const parent = dirname5(skillsDir);
|
|
4567
|
+
let names = [];
|
|
4568
|
+
try {
|
|
4569
|
+
names = await readdir2(parent);
|
|
4570
|
+
} catch {
|
|
4571
|
+
return;
|
|
4572
|
+
}
|
|
4573
|
+
await Promise.all(names.filter((n) => n.startsWith(".tmp-")).map((n) => rm2(join8(parent, n), { recursive: true, force: true }).catch(() => {})));
|
|
4574
|
+
};
|
|
4575
|
+
const install = async ({ name, scope, workspaceRoot, overwrite }) => {
|
|
4576
|
+
const skillsDir = skillsDirFor(scope, workspaceRoot);
|
|
4577
|
+
const target = join8(skillsDir, name);
|
|
4578
|
+
const exists = await stat2(target).catch(() => {
|
|
4579
|
+
return;
|
|
4580
|
+
}) !== undefined;
|
|
4581
|
+
if (exists && overwrite !== true)
|
|
4582
|
+
throw new SkillMarketError("skill_exists", `Skill ${name} already exists at ${scope} level (${target})`);
|
|
4583
|
+
const skill = await detail(name);
|
|
4584
|
+
const files = unpack(skill, await download(skill));
|
|
4585
|
+
await sweepTempDirs(skillsDir);
|
|
4586
|
+
const temp = join8(dirname5(skillsDir), `.tmp-${randomUUID()}`);
|
|
4587
|
+
try {
|
|
4588
|
+
for (const [relative, bytes] of files) {
|
|
4589
|
+
const dest = join8(temp, ...relative.split("/"));
|
|
4590
|
+
await mkdir2(dirname5(dest), { recursive: true });
|
|
4591
|
+
await writeFile2(dest, bytes);
|
|
4592
|
+
}
|
|
4593
|
+
if (exists)
|
|
4594
|
+
await rm2(target, { recursive: true, force: true });
|
|
4595
|
+
await mkdir2(skillsDir, { recursive: true });
|
|
4596
|
+
await rename2(temp, target);
|
|
4597
|
+
} finally {
|
|
4598
|
+
await rm2(temp, { recursive: true, force: true }).catch(() => {});
|
|
4599
|
+
}
|
|
4600
|
+
let shadowedBy;
|
|
4601
|
+
if (scope === "user" && workspaceRoot !== undefined && workspaceRoot !== "") {
|
|
4602
|
+
const projectDir = join8(projectSkillsDir(workspaceRoot), name);
|
|
4603
|
+
if (await stat2(projectDir).catch(() => {
|
|
4604
|
+
return;
|
|
4605
|
+
}) !== undefined)
|
|
4606
|
+
shadowedBy = "project";
|
|
4607
|
+
}
|
|
4608
|
+
return { name, scope, path: target, ...shadowedBy !== undefined ? { shadowedBy } : {} };
|
|
4609
|
+
};
|
|
4610
|
+
const uninstall = async ({ name, scope, workspaceRoot }) => {
|
|
4611
|
+
const skillsDir = skillsDirFor(scope, workspaceRoot);
|
|
4612
|
+
const target = join8(skillsDir, name);
|
|
4613
|
+
if (await stat2(target).catch(() => {
|
|
4614
|
+
return;
|
|
4615
|
+
}) === undefined)
|
|
4616
|
+
throw new SkillMarketError("skill_not_installed", `Skill ${name} is not installed at ${scope} level`);
|
|
4617
|
+
await rm2(target, { recursive: true, force: true });
|
|
4618
|
+
};
|
|
4619
|
+
return {
|
|
4620
|
+
async list(query) {
|
|
4621
|
+
if (query !== undefined && query.trim() !== "") {
|
|
4622
|
+
const response = await request(`api/skills?q=${encodeURIComponent(query.trim())}`);
|
|
4623
|
+
if (!response.ok)
|
|
4624
|
+
throw new SkillMarketError("market_unavailable", `Skill search failed with HTTP ${response.status}`);
|
|
4625
|
+
const data = await response.json();
|
|
4626
|
+
return Array.isArray(data.skills) ? data.skills.map(normalizeEntry) : [];
|
|
4627
|
+
}
|
|
4628
|
+
return listSkills();
|
|
4629
|
+
},
|
|
4630
|
+
detail,
|
|
4631
|
+
async preview(name) {
|
|
4632
|
+
const skill = await detail(name);
|
|
4633
|
+
const inner = unpack(skill, await download(skill));
|
|
4634
|
+
const bodyBytes = inner.get("SKILL.md");
|
|
4635
|
+
if (bodyBytes === undefined)
|
|
4636
|
+
throw new SkillMarketError("skill_invalid_package", `Package ${name} lost its SKILL.md`);
|
|
4637
|
+
const body = stripFrontmatter(new TextDecoder().decode(bodyBytes));
|
|
4638
|
+
return { body, files: [...inner.keys()].sort() };
|
|
4639
|
+
},
|
|
4640
|
+
install,
|
|
4641
|
+
uninstall
|
|
4642
|
+
};
|
|
4643
|
+
}
|
|
4644
|
+
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) => {
|
|
4645
|
+
const row = raw ?? {};
|
|
4646
|
+
const metadata = row.metadata;
|
|
4647
|
+
const source = metadata !== null && typeof metadata === "object" ? metadata.source : undefined;
|
|
4648
|
+
return {
|
|
4649
|
+
name: String(row.name ?? ""),
|
|
4650
|
+
description: String(row.description ?? ""),
|
|
4651
|
+
category: typeof row.category === "string" && row.category !== "" ? row.category : "uncategorized",
|
|
4652
|
+
source: typeof source === "string" && source !== "" ? source : "unknown",
|
|
4653
|
+
license: String(row.license ?? ""),
|
|
4654
|
+
version: String(row.version ?? ""),
|
|
4655
|
+
sha256: String(row.sha256 ?? ""),
|
|
4656
|
+
sizeBytes: Number(row.size_bytes ?? 0),
|
|
4657
|
+
uploadedAt: String(row.uploaded_at ?? "")
|
|
4658
|
+
};
|
|
4659
|
+
};
|
|
4660
|
+
var init_skill_market = __esm(() => {
|
|
4661
|
+
init_src();
|
|
4662
|
+
init_esm();
|
|
4663
|
+
SkillMarketError = class SkillMarketError extends Error {
|
|
4664
|
+
code;
|
|
4665
|
+
constructor(code, message) {
|
|
4666
|
+
super(message);
|
|
4667
|
+
this.name = "SkillMarketError";
|
|
4668
|
+
this.code = code;
|
|
4669
|
+
}
|
|
4670
|
+
};
|
|
4671
|
+
MAX_PACKAGE_BYTES = 32 * 1024 * 1024;
|
|
4672
|
+
});
|
|
4673
|
+
|
|
3916
4674
|
// packages/gateway/src/workspaces.ts
|
|
3917
4675
|
import { constants as constants3 } from "fs";
|
|
3918
|
-
import { access, readdir as
|
|
3919
|
-
import { dirname as
|
|
4676
|
+
import { access, readdir as readdir3, stat as stat3 } from "fs/promises";
|
|
4677
|
+
import { dirname as dirname6, isAbsolute as isAbsolute3, join as join9 } from "path";
|
|
3920
4678
|
async function browseWorkspaces(options) {
|
|
3921
4679
|
const requested = options.path.replace(/^\/+([A-Za-z]:[\\/])/, "$1");
|
|
3922
4680
|
if (process.platform === "win32" && (requested === "/" || requested === "\\")) {
|
|
@@ -3938,16 +4696,16 @@ async function browseWorkspaces(options) {
|
|
|
3938
4696
|
throw new Error("\u76EE\u5F55\u5206\u9875\u5DF2\u5931\u6548\uFF0C\u8BF7\u5237\u65B0\u5217\u8868");
|
|
3939
4697
|
}
|
|
3940
4698
|
}
|
|
3941
|
-
const entries = (await
|
|
4699
|
+
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
4700
|
const directories = [];
|
|
3943
4701
|
let next = offset;
|
|
3944
4702
|
for (;next < entries.length && directories.length < 100; next++) {
|
|
3945
4703
|
const entry = entries[next];
|
|
3946
|
-
const target =
|
|
4704
|
+
const target = join9(path, entry.name);
|
|
3947
4705
|
if (!entry.isDirectory() && !entry.isSymbolicLink())
|
|
3948
4706
|
continue;
|
|
3949
4707
|
try {
|
|
3950
|
-
if (!(await
|
|
4708
|
+
if (!(await stat3(target)).isDirectory())
|
|
3951
4709
|
continue;
|
|
3952
4710
|
await access(target, constants3.R_OK | constants3.X_OK);
|
|
3953
4711
|
directories.push({ name: entry.name, path: target });
|
|
@@ -3957,7 +4715,7 @@ async function browseWorkspaces(options) {
|
|
|
3957
4715
|
}
|
|
3958
4716
|
return {
|
|
3959
4717
|
path,
|
|
3960
|
-
parent:
|
|
4718
|
+
parent: dirname6(path) === path ? null : dirname6(path),
|
|
3961
4719
|
entries: directories,
|
|
3962
4720
|
next: next < entries.length ? JSON.stringify({ key, offset: next }) : null
|
|
3963
4721
|
};
|
|
@@ -3986,6 +4744,26 @@ import {
|
|
|
3986
4744
|
} from "@earendil-works/chord";
|
|
3987
4745
|
async function createNekoServerServices(options) {
|
|
3988
4746
|
const { runtime, context } = options;
|
|
4747
|
+
const market = createSkillMarketClient({
|
|
4748
|
+
marketUrl: options.marketUrl,
|
|
4749
|
+
...options.promptHome !== undefined ? { home: options.promptHome } : {}
|
|
4750
|
+
});
|
|
4751
|
+
const toRemote = (error) => {
|
|
4752
|
+
if (error instanceof SkillMarketError) {
|
|
4753
|
+
const code = error.code === "skill_not_found" || error.code === "skill_not_installed" ? "service_not_found" : "service_invalid_value";
|
|
4754
|
+
throw new RemoteServiceError(code, `[${error.code}] ${error.message}`);
|
|
4755
|
+
}
|
|
4756
|
+
throw error;
|
|
4757
|
+
};
|
|
4758
|
+
const withInstallState = async (skill, workspaceRoot) => {
|
|
4759
|
+
const locals = await runtime.listSkillsByLevel(workspaceRoot);
|
|
4760
|
+
const installed = {
|
|
4761
|
+
project: locals.some((s) => s.name === skill.name && s.level === "project"),
|
|
4762
|
+
user: locals.some((s) => s.name === skill.name && s.level === "user"),
|
|
4763
|
+
builtin: locals.some((s) => s.name === skill.name && s.level === "builtin")
|
|
4764
|
+
};
|
|
4765
|
+
return { ...skill, installed, activeLevel: activeLevelOf(installed) };
|
|
4766
|
+
};
|
|
3989
4767
|
const list = async () => (await runtime.listConversations()).map((info) => ({
|
|
3990
4768
|
id: String(info.id),
|
|
3991
4769
|
workspaceRoot: info.workspaceRoot,
|
|
@@ -4041,7 +4819,8 @@ async function createNekoServerServices(options) {
|
|
|
4041
4819
|
{ service: NekoModels, mode: "singleton" },
|
|
4042
4820
|
{ service: NekoCredentials, mode: "singleton" },
|
|
4043
4821
|
{ service: NekoWorkspaces, mode: "singleton" },
|
|
4044
|
-
{ service: NekoWorkspaceFiles, mode: "singleton" }
|
|
4822
|
+
{ service: NekoWorkspaceFiles, mode: "singleton" },
|
|
4823
|
+
{ service: NekoSkillMarket, mode: "singleton" }
|
|
4045
4824
|
]);
|
|
4046
4825
|
provider.provide(NekoSessionDirectory, { state: directory });
|
|
4047
4826
|
const updateCredentials = (operation) => serialize(async () => {
|
|
@@ -4091,6 +4870,13 @@ async function createNekoServerServices(options) {
|
|
|
4091
4870
|
}
|
|
4092
4871
|
});
|
|
4093
4872
|
provider.provide(NekoModels, { list: async () => runtime.listModels() });
|
|
4873
|
+
provider.provide(NekoSkillMarket, {
|
|
4874
|
+
list: (input) => market.list(input.query).then((skills) => Promise.all(skills.map((skill) => withInstallState(skill, input.workspaceRoot)))).catch(toRemote),
|
|
4875
|
+
detail: (input) => market.detail(input.name).then((skill) => withInstallState(skill, input.workspaceRoot)).catch(toRemote),
|
|
4876
|
+
preview: (input) => market.preview(input.name).catch(toRemote),
|
|
4877
|
+
install: (input) => serialize(() => market.install(input).then((result) => ({ ...result })).catch(toRemote)),
|
|
4878
|
+
uninstall: (input) => serialize(() => market.uninstall(input).catch(toRemote))
|
|
4879
|
+
});
|
|
4094
4880
|
provider.provide(NekoSessionManagement, {
|
|
4095
4881
|
create: (createOptions) => serialize(async () => {
|
|
4096
4882
|
const created = await runtime.createConversation(createOptions.model !== undefined || createOptions.thinkingLevel !== undefined || createOptions.cwd !== undefined ? {
|
|
@@ -4171,6 +4957,7 @@ var init_server_services = __esm(() => {
|
|
|
4171
4957
|
init_src();
|
|
4172
4958
|
init_workspace_files();
|
|
4173
4959
|
init_contract();
|
|
4960
|
+
init_skill_market();
|
|
4174
4961
|
init_workspaces();
|
|
4175
4962
|
});
|
|
4176
4963
|
|
|
@@ -4517,9 +5304,9 @@ var init_session_host = __esm(() => {
|
|
|
4517
5304
|
});
|
|
4518
5305
|
|
|
4519
5306
|
// packages/gateway/src/gateway.ts
|
|
4520
|
-
import { randomUUID } from "crypto";
|
|
4521
|
-
import { mkdir as
|
|
4522
|
-
import { basename as basename5, dirname as
|
|
5307
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
5308
|
+
import { mkdir as mkdir3, readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
|
|
5309
|
+
import { basename as basename5, dirname as dirname7, join as join10 } from "path";
|
|
4523
5310
|
import { BACKGROUND_CONTEXT as BACKGROUND_CONTEXT3 } from "@earendil-works/chord/context";
|
|
4524
5311
|
import { isServerId } from "@earendil-works/pi-protocol";
|
|
4525
5312
|
import { Server, SessionNotFoundError } from "@earendil-works/pi-server";
|
|
@@ -4531,9 +5318,10 @@ async function startGateway(options = {}) {
|
|
|
4531
5318
|
const storagePath = options.storagePath ?? fileConfig.storagePath ?? DEFAULT_STORAGE_PATH;
|
|
4532
5319
|
const host = options.host ?? fileConfig.gateway?.host ?? DEFAULT_HOST;
|
|
4533
5320
|
const port = options.port !== undefined ? options.port : fileConfig.gateway?.port ?? (process.platform === "win32" ? 0 : DEFAULT_PORT);
|
|
4534
|
-
const
|
|
5321
|
+
const marketUrl = options.marketUrl ?? fileConfig.skills?.marketUrl ?? DEFAULT_SKILL_MARKET_URL;
|
|
5322
|
+
const nekoDir = dirname7(storagePath);
|
|
4535
5323
|
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 :
|
|
5324
|
+
const socketPath = options.socketPath !== undefined ? options.socketPath : fileConfig.gateway?.socketPath !== undefined ? fileConfig.gateway.socketPath : process.platform === "win32" ? null : join10(nekoDir, `${serverId}.sock`);
|
|
4537
5325
|
const runtime = await createNekoRuntime({
|
|
4538
5326
|
context,
|
|
4539
5327
|
storage: options.storage ?? "sqlite",
|
|
@@ -4556,6 +5344,8 @@ async function startGateway(options = {}) {
|
|
|
4556
5344
|
serverId,
|
|
4557
5345
|
nekoDir,
|
|
4558
5346
|
model,
|
|
5347
|
+
marketUrl,
|
|
5348
|
+
promptHome: options.promptHome,
|
|
4559
5349
|
onError: options.onError
|
|
4560
5350
|
});
|
|
4561
5351
|
} catch (error) {
|
|
@@ -4566,7 +5356,12 @@ async function startGateway(options = {}) {
|
|
|
4566
5356
|
async function bindGateway(runtime, options) {
|
|
4567
5357
|
const { context, host, port, socketPath, serverId, nekoDir, model } = options;
|
|
4568
5358
|
const modelLabel = `${model.provider}/${model.modelId}`;
|
|
4569
|
-
const serverServices = await createNekoServerServices({
|
|
5359
|
+
const serverServices = await createNekoServerServices({
|
|
5360
|
+
runtime,
|
|
5361
|
+
context,
|
|
5362
|
+
marketUrl: options.marketUrl,
|
|
5363
|
+
...options.promptHome !== undefined ? { promptHome: options.promptHome } : {}
|
|
5364
|
+
});
|
|
4570
5365
|
let wsListener;
|
|
4571
5366
|
const listeners = [];
|
|
4572
5367
|
if (socketPath !== null) {
|
|
@@ -4644,15 +5439,15 @@ function serverIdFromSocketPath(socketPath) {
|
|
|
4644
5439
|
return isServerId(candidate) ? candidate : undefined;
|
|
4645
5440
|
}
|
|
4646
5441
|
async function loadOrCreateServerId(nekoDir) {
|
|
4647
|
-
const file =
|
|
5442
|
+
const file = join10(nekoDir, SERVER_ID_FILENAME);
|
|
4648
5443
|
try {
|
|
4649
5444
|
const existing = (await readFile5(file, "utf8")).trim();
|
|
4650
5445
|
if (existing !== "")
|
|
4651
5446
|
return existing;
|
|
4652
5447
|
} catch {}
|
|
4653
|
-
const created =
|
|
4654
|
-
await
|
|
4655
|
-
await
|
|
5448
|
+
const created = randomUUID2();
|
|
5449
|
+
await mkdir3(nekoDir, { recursive: true, mode: 448 });
|
|
5450
|
+
await writeFile3(file, `${created}
|
|
4656
5451
|
`, { mode: 384 });
|
|
4657
5452
|
return created;
|
|
4658
5453
|
}
|
|
@@ -4666,14 +5461,14 @@ var init_gateway = __esm(() => {
|
|
|
4666
5461
|
});
|
|
4667
5462
|
|
|
4668
5463
|
// packages/gateway/src/process.ts
|
|
4669
|
-
import { fileURLToPath } from "url";
|
|
5464
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4670
5465
|
function gatewayCommand(args) {
|
|
4671
5466
|
const source = import.meta.url.endsWith(".ts");
|
|
4672
5467
|
return {
|
|
4673
5468
|
binary: process.execPath,
|
|
4674
5469
|
args: [
|
|
4675
5470
|
...source ? ["--conditions=neko-source"] : [],
|
|
4676
|
-
|
|
5471
|
+
fileURLToPath2(new URL("./gateway.js", import.meta.url)),
|
|
4677
5472
|
...args
|
|
4678
5473
|
]
|
|
4679
5474
|
};
|
|
@@ -4704,14 +5499,14 @@ var init_src2 = __esm(() => {
|
|
|
4704
5499
|
|
|
4705
5500
|
// packages/tui/src/gateway.ts
|
|
4706
5501
|
import { spawn as spawn2 } from "child_process";
|
|
4707
|
-
import { existsSync as
|
|
4708
|
-
import { basename as basename6, dirname as
|
|
5502
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
5503
|
+
import { basename as basename6, dirname as dirname8, join as join11 } from "path";
|
|
4709
5504
|
import { isServerId as isServerId2 } from "@earendil-works/pi-protocol";
|
|
4710
5505
|
async function connectToGateway(options = {}) {
|
|
4711
5506
|
const config = loadNekoConfig(options.configDir);
|
|
4712
5507
|
const storagePath = options.storagePath ?? config.storagePath ?? DEFAULT_STORAGE_PATH;
|
|
4713
|
-
const nekoDir =
|
|
4714
|
-
const fileServerId = readServerId(
|
|
5508
|
+
const nekoDir = dirname8(storagePath);
|
|
5509
|
+
const fileServerId = readServerId(join11(nekoDir, SERVER_ID_FILENAME2));
|
|
4715
5510
|
if (process.platform === "win32") {
|
|
4716
5511
|
if (fileServerId !== undefined) {
|
|
4717
5512
|
const wsUrl = await readGatewayPortFile(nekoDir, fileServerId);
|
|
@@ -4724,9 +5519,9 @@ async function connectToGateway(options = {}) {
|
|
|
4724
5519
|
}
|
|
4725
5520
|
return spawnAndConnect({ ...options, storagePath, socketPath: undefined, nekoDir, fileServerId });
|
|
4726
5521
|
}
|
|
4727
|
-
const socketPath = options.socketPath ?? config.gateway?.socketPath ?? (fileServerId !== undefined ?
|
|
4728
|
-
const serverIdFor = (path) => fileServerId ?? serverIdFromSocketPath2(path) ?? readServerId(
|
|
4729
|
-
if (socketPath !== undefined &&
|
|
5522
|
+
const socketPath = options.socketPath ?? config.gateway?.socketPath ?? (fileServerId !== undefined ? join11(nekoDir, `${fileServerId}.sock`) : undefined);
|
|
5523
|
+
const serverIdFor = (path) => fileServerId ?? serverIdFromSocketPath2(path) ?? readServerId(join11(nekoDir, SERVER_ID_FILENAME2));
|
|
5524
|
+
if (socketPath !== undefined && existsSync3(socketPath)) {
|
|
4730
5525
|
const serverId = serverIdFor(socketPath);
|
|
4731
5526
|
if (serverId !== undefined) {
|
|
4732
5527
|
try {
|
|
@@ -4755,7 +5550,7 @@ async function spawnAndConnect(plan) {
|
|
|
4755
5550
|
async function connectSpawned(plan, child, outputTail, spawnError) {
|
|
4756
5551
|
const timeoutMs = plan.spawnTimeoutMs ?? 20000;
|
|
4757
5552
|
if (process.platform === "win32") {
|
|
4758
|
-
const serverId = plan.fileServerId ?? await waitForValue(() => readServerId(
|
|
5553
|
+
const serverId = plan.fileServerId ?? await waitForValue(() => readServerId(join11(plan.nekoDir, SERVER_ID_FILENAME2)), "gateway serverId file", timeoutMs, child, outputTail, spawnError);
|
|
4759
5554
|
const wsUrl = await waitForValue(() => readGatewayPortFile(plan.nekoDir, serverId), "gateway ready (port file)", timeoutMs, child, outputTail, spawnError);
|
|
4760
5555
|
let lastError;
|
|
4761
5556
|
for (let attempt = 0;attempt < CONNECT_RETRIES; attempt++) {
|
|
@@ -4784,11 +5579,11 @@ ${outputTail()}`);
|
|
|
4784
5579
|
}
|
|
4785
5580
|
let socketPath = plan.socketPath;
|
|
4786
5581
|
if (socketPath === undefined) {
|
|
4787
|
-
const generated = await waitForValue(() => readServerId(
|
|
4788
|
-
socketPath =
|
|
5582
|
+
const generated = await waitForValue(() => readServerId(join11(plan.nekoDir, SERVER_ID_FILENAME2)), "gateway serverId file", timeoutMs, child, outputTail, spawnError);
|
|
5583
|
+
socketPath = join11(plan.nekoDir, `${generated}.sock`);
|
|
4789
5584
|
}
|
|
4790
|
-
await waitForValue(() =>
|
|
4791
|
-
const serverId = plan.fileServerId ?? serverIdFromSocketPath2(socketPath) ?? readServerId(
|
|
5585
|
+
await waitForValue(() => existsSync3(socketPath) ? true : undefined, `gateway ready (socket: ${socketPath})`, timeoutMs, child, outputTail, spawnError);
|
|
5586
|
+
const serverId = plan.fileServerId ?? serverIdFromSocketPath2(socketPath) ?? readServerId(join11(plan.nekoDir, SERVER_ID_FILENAME2));
|
|
4792
5587
|
if (serverId === undefined) {
|
|
4793
5588
|
throw new Error(`Cannot determine gateway serverId (socket: ${socketPath})`);
|
|
4794
5589
|
}
|
|
@@ -4900,8 +5695,8 @@ var init_gateway2 = __esm(() => {
|
|
|
4900
5695
|
|
|
4901
5696
|
// packages/tui/src/image-input.ts
|
|
4902
5697
|
import { execFile } from "child_process";
|
|
4903
|
-
import { readFile as readFile6, stat as
|
|
4904
|
-
import { homedir as
|
|
5698
|
+
import { readFile as readFile6, stat as stat4 } from "fs/promises";
|
|
5699
|
+
import { homedir as homedir6 } from "os";
|
|
4905
5700
|
import { basename as basename7, resolve as resolve5 } from "path";
|
|
4906
5701
|
import { promisify } from "util";
|
|
4907
5702
|
import { isKeyRelease as isKeyRelease4, isKeyRepeat as isKeyRepeat2, matchesKey as matchesKey4 } from "@earendil-works/pi-tui";
|
|
@@ -4936,12 +5731,12 @@ function imagePaths(text, platform = process.platform) {
|
|
|
4936
5731
|
return paths.length && paths.every((p) => /\.(png|jpe?g|webp)$/i.test(p)) ? paths : null;
|
|
4937
5732
|
}
|
|
4938
5733
|
async function readImageFile(path, cwd) {
|
|
4939
|
-
const full = resolve5(cwd, path.startsWith("~/") ?
|
|
4940
|
-
const info = await
|
|
5734
|
+
const full = resolve5(cwd, path.startsWith("~/") ? homedir6() + path.slice(1) : path);
|
|
5735
|
+
const info = await stat4(full);
|
|
4941
5736
|
if (!info.isFile() || info.size > 20 * 1024 * 1024)
|
|
4942
5737
|
throw new Error("Image must be a file no larger than 20 MiB");
|
|
4943
5738
|
const bytes = await readFile6(full);
|
|
4944
|
-
const after = await
|
|
5739
|
+
const after = await stat4(full);
|
|
4945
5740
|
if (bytes.length !== info.size || after.size !== info.size || after.mtimeMs !== info.mtimeMs)
|
|
4946
5741
|
throw new Error("Image changed while reading");
|
|
4947
5742
|
const mimeType = /\.png$/i.test(full) ? "image/png" : /\.webp$/i.test(full) ? "image/webp" : "image/jpeg";
|
|
@@ -5006,7 +5801,7 @@ var init_image_input = __esm(() => {
|
|
|
5006
5801
|
});
|
|
5007
5802
|
|
|
5008
5803
|
// packages/tui/src/layout.ts
|
|
5009
|
-
import { Text as
|
|
5804
|
+
import { Text as Text5, VStack } from "@earendil-works/pi-tui";
|
|
5010
5805
|
function createAppLayout(parts) {
|
|
5011
5806
|
const normal = (v) => {
|
|
5012
5807
|
parts.footer.panelOpen = parts.panelOpen();
|
|
@@ -5016,7 +5811,7 @@ function createAppLayout(parts) {
|
|
|
5016
5811
|
};
|
|
5017
5812
|
return new VStack([
|
|
5018
5813
|
{
|
|
5019
|
-
component: new
|
|
5814
|
+
component: new Text5("Terminal too small. Resize to 40x10. Ctrl+C Exit", 0, 0),
|
|
5020
5815
|
visible: (v) => !normal(v),
|
|
5021
5816
|
grow: 1
|
|
5022
5817
|
},
|
|
@@ -5030,6 +5825,235 @@ function createAppLayout(parts) {
|
|
|
5030
5825
|
var usableSize = (width, height) => width >= 40 && height >= 10;
|
|
5031
5826
|
var init_layout = () => {};
|
|
5032
5827
|
|
|
5828
|
+
// packages/tui/src/skill-market-ui.ts
|
|
5829
|
+
import { BACKGROUND_CONTEXT as BACKGROUND_CONTEXT4 } from "@earendil-works/chord/context";
|
|
5830
|
+
import { Markdown as Markdown3, matchesKey as matchesKey5, wrapTextWithAnsi as wrapTextWithAnsi2 } from "@earendil-works/pi-tui";
|
|
5831
|
+
|
|
5832
|
+
class SkillDetailView {
|
|
5833
|
+
#skill = null;
|
|
5834
|
+
#error = "";
|
|
5835
|
+
#notice = "";
|
|
5836
|
+
#busy = false;
|
|
5837
|
+
#confirm = null;
|
|
5838
|
+
#name;
|
|
5839
|
+
#client;
|
|
5840
|
+
#workspaceRoot;
|
|
5841
|
+
#panel;
|
|
5842
|
+
#openPreview;
|
|
5843
|
+
constructor(name, client, workspaceRoot, panel, openPreview) {
|
|
5844
|
+
this.#name = name;
|
|
5845
|
+
this.#client = client;
|
|
5846
|
+
this.#workspaceRoot = workspaceRoot;
|
|
5847
|
+
this.#panel = panel;
|
|
5848
|
+
this.#openPreview = openPreview;
|
|
5849
|
+
this.refresh();
|
|
5850
|
+
}
|
|
5851
|
+
get help() {
|
|
5852
|
+
if (this.#confirm)
|
|
5853
|
+
return hint(["y", "Confirm"], ["n", "Cancel"]);
|
|
5854
|
+
const skill = this.#skill;
|
|
5855
|
+
const builtinOnly = skill?.installed.builtin === true && !skill.installed.user && !skill.installed.project;
|
|
5856
|
+
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"]);
|
|
5857
|
+
}
|
|
5858
|
+
async refresh() {
|
|
5859
|
+
try {
|
|
5860
|
+
this.#skill = await this.#client.skillMarket.detail({ name: this.#name, workspaceRoot: this.#workspaceRoot }, CTX);
|
|
5861
|
+
this.#error = "";
|
|
5862
|
+
} catch (error) {
|
|
5863
|
+
this.#error = error instanceof Error ? error.message : String(error);
|
|
5864
|
+
}
|
|
5865
|
+
this.#panel.changed();
|
|
5866
|
+
}
|
|
5867
|
+
handleKey(data) {
|
|
5868
|
+
if (this.#confirm) {
|
|
5869
|
+
if (matchesKey5(data, "y")) {
|
|
5870
|
+
const pending = this.#confirm;
|
|
5871
|
+
this.#confirm = null;
|
|
5872
|
+
this.run(pending.run);
|
|
5873
|
+
} else if (matchesKey5(data, "n")) {
|
|
5874
|
+
this.#confirm = null;
|
|
5875
|
+
}
|
|
5876
|
+
return true;
|
|
5877
|
+
}
|
|
5878
|
+
if (this.#busy || this.#skill === null)
|
|
5879
|
+
return true;
|
|
5880
|
+
const skill = this.#skill;
|
|
5881
|
+
const builtinOnly = skill.installed.builtin && !skill.installed.user && !skill.installed.project;
|
|
5882
|
+
if (matchesKey5(data, "v")) {
|
|
5883
|
+
this.#openPreview(this.#name);
|
|
5884
|
+
return true;
|
|
5885
|
+
}
|
|
5886
|
+
if (builtinOnly)
|
|
5887
|
+
return true;
|
|
5888
|
+
if (matchesKey5(data, "u"))
|
|
5889
|
+
this.askInstall("user", skill);
|
|
5890
|
+
else if (matchesKey5(data, "p"))
|
|
5891
|
+
this.askInstall("project", skill);
|
|
5892
|
+
else if (matchesKey5(data, "d"))
|
|
5893
|
+
this.askUninstall(skill);
|
|
5894
|
+
else
|
|
5895
|
+
return false;
|
|
5896
|
+
return true;
|
|
5897
|
+
}
|
|
5898
|
+
askInstall(scope, skill) {
|
|
5899
|
+
const exists = scope === "user" ? skill.installed.user : skill.installed.project;
|
|
5900
|
+
const shadowed = scope === "user" && skill.installed.project;
|
|
5901
|
+
if (exists) {
|
|
5902
|
+
this.#confirm = {
|
|
5903
|
+
prompt: `${skill.name} exists at ${scope} level. Overwrite with market version ${skill.version}? Local edits are lost.`,
|
|
5904
|
+
run: () => this.install(scope, true)
|
|
5905
|
+
};
|
|
5906
|
+
} else if (shadowed) {
|
|
5907
|
+
this.#confirm = {
|
|
5908
|
+
prompt: `Project level already has ${skill.name} and wins. Install at user level anyway?`,
|
|
5909
|
+
run: () => this.install(scope, false)
|
|
5910
|
+
};
|
|
5911
|
+
} else {
|
|
5912
|
+
this.run(() => this.install(scope, false));
|
|
5913
|
+
}
|
|
5914
|
+
}
|
|
5915
|
+
askUninstall(skill) {
|
|
5916
|
+
const scope = skill.installed.project ? "project" : skill.installed.user ? "user" : null;
|
|
5917
|
+
if (scope === null) {
|
|
5918
|
+
this.#notice = "Not installed locally.";
|
|
5919
|
+
return;
|
|
5920
|
+
}
|
|
5921
|
+
this.#confirm = {
|
|
5922
|
+
prompt: `Uninstall ${skill.name} from ${scope} level? This cannot be undone.`,
|
|
5923
|
+
run: async () => {
|
|
5924
|
+
await this.#client.skillMarket.uninstall({ name: this.#name, scope, workspaceRoot: this.#workspaceRoot }, CTX);
|
|
5925
|
+
this.#notice = `Uninstalled from ${scope}. Takes effect on the next message.`;
|
|
5926
|
+
}
|
|
5927
|
+
};
|
|
5928
|
+
}
|
|
5929
|
+
async install(scope, overwrite) {
|
|
5930
|
+
try {
|
|
5931
|
+
const result = await this.#client.skillMarket.install({ name: this.#name, scope, workspaceRoot: this.#workspaceRoot, overwrite }, CTX);
|
|
5932
|
+
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.`;
|
|
5933
|
+
} catch (error) {
|
|
5934
|
+
if (marketErrorCode(error) === "skill_exists") {
|
|
5935
|
+
this.#confirm = {
|
|
5936
|
+
prompt: `${this.#name} already exists at ${scope} level. Overwrite with the market version?`,
|
|
5937
|
+
run: () => this.install(scope, true)
|
|
5938
|
+
};
|
|
5939
|
+
return;
|
|
5940
|
+
}
|
|
5941
|
+
throw error;
|
|
5942
|
+
}
|
|
5943
|
+
}
|
|
5944
|
+
async run(action) {
|
|
5945
|
+
this.#busy = true;
|
|
5946
|
+
this.#notice = "";
|
|
5947
|
+
this.#panel.changed();
|
|
5948
|
+
try {
|
|
5949
|
+
await action();
|
|
5950
|
+
} catch (error) {
|
|
5951
|
+
this.#notice = `Failed: ${error instanceof Error ? error.message : String(error)}`;
|
|
5952
|
+
} finally {
|
|
5953
|
+
this.#busy = false;
|
|
5954
|
+
await this.refresh();
|
|
5955
|
+
}
|
|
5956
|
+
}
|
|
5957
|
+
lines(width, _height) {
|
|
5958
|
+
if (this.#confirm) {
|
|
5959
|
+
return [theme.accent("Confirm"), "", ...wrapTextWithAnsi2(this.#confirm.prompt, width), ""];
|
|
5960
|
+
}
|
|
5961
|
+
const skill = this.#skill;
|
|
5962
|
+
if (skill === null)
|
|
5963
|
+
return [this.#error !== "" ? theme.error(`Error: ${this.#error}`) : theme.dim("Loading...")];
|
|
5964
|
+
const mark = (on, label) => on ? theme.ok(`${label} \u2713`) : theme.dim(`${label} \u2014`);
|
|
5965
|
+
const state = [
|
|
5966
|
+
mark(skill.installed.project, "project"),
|
|
5967
|
+
mark(skill.installed.user, "user"),
|
|
5968
|
+
mark(skill.installed.builtin, "builtin")
|
|
5969
|
+
].join(" ");
|
|
5970
|
+
const rows = [
|
|
5971
|
+
`${style.bold(skill.name)} ${theme.dim(skill.version)}`,
|
|
5972
|
+
theme.dim(`${skill.source} \xB7 ${skill.category} \xB7 ${formatSize(skill.sizeBytes)} \xB7 sha256 ${skill.sha256.slice(0, 10)}\u2026`),
|
|
5973
|
+
`${theme.dim("installed:")} ${state}${skill.activeLevel ? theme.dim(` (active: ${skill.activeLevel})`) : ""}`,
|
|
5974
|
+
"",
|
|
5975
|
+
...wrapTextWithAnsi2(skill.description, width)
|
|
5976
|
+
];
|
|
5977
|
+
if (this.#busy)
|
|
5978
|
+
rows.push("", theme.dim("Working..."));
|
|
5979
|
+
if (this.#notice !== "")
|
|
5980
|
+
rows.push("", theme.accent(this.#notice));
|
|
5981
|
+
return rows;
|
|
5982
|
+
}
|
|
5983
|
+
}
|
|
5984
|
+
|
|
5985
|
+
class SkillPreviewView {
|
|
5986
|
+
#header = null;
|
|
5987
|
+
#markdown = null;
|
|
5988
|
+
#error = "";
|
|
5989
|
+
#offset = 0;
|
|
5990
|
+
#panel;
|
|
5991
|
+
get help() {
|
|
5992
|
+
return hint(["Up/Down", "Scroll"], ["Esc", "Back"]);
|
|
5993
|
+
}
|
|
5994
|
+
constructor(name, client, panel) {
|
|
5995
|
+
this.#panel = panel;
|
|
5996
|
+
client.skillMarket.preview({ name }, CTX).then((preview) => {
|
|
5997
|
+
this.#header = [`${theme.dim("files:")} ${preview.files.join(" ")}`, ""];
|
|
5998
|
+
this.#markdown = new Markdown3(preview.body, 0, 0, getMarkdownTheme());
|
|
5999
|
+
this.#panel.changed();
|
|
6000
|
+
}).catch((error) => {
|
|
6001
|
+
this.#error = error instanceof Error ? error.message : String(error);
|
|
6002
|
+
this.#panel.changed();
|
|
6003
|
+
});
|
|
6004
|
+
}
|
|
6005
|
+
handleKey(data) {
|
|
6006
|
+
if (matchesKey5(data, "up"))
|
|
6007
|
+
this.#offset = Math.max(0, this.#offset - 1);
|
|
6008
|
+
else if (matchesKey5(data, "down"))
|
|
6009
|
+
this.#offset += 1;
|
|
6010
|
+
else
|
|
6011
|
+
return false;
|
|
6012
|
+
return true;
|
|
6013
|
+
}
|
|
6014
|
+
lines(width, height) {
|
|
6015
|
+
if (this.#markdown === null || this.#header === null)
|
|
6016
|
+
return [this.#error !== "" ? theme.error(`Error: ${this.#error}`) : theme.dim("Loading preview...")];
|
|
6017
|
+
const flat = [...this.#header, ...this.#markdown.render(width)];
|
|
6018
|
+
const max = Math.max(0, flat.length - height);
|
|
6019
|
+
this.#offset = Math.min(this.#offset, max);
|
|
6020
|
+
return flat.slice(this.#offset, this.#offset + height);
|
|
6021
|
+
}
|
|
6022
|
+
}
|
|
6023
|
+
async function openSkillMarket(panel, client, workspaceRoot) {
|
|
6024
|
+
const openPreview = (name) => panel.showDetail(new SkillPreviewView(name, client, panel));
|
|
6025
|
+
await panel.show("Skills Market", async () => toItems(await client.skillMarket.list({ workspaceRoot }, CTX)), async (name) => new SkillDetailView(name, client, workspaceRoot, panel, openPreview));
|
|
6026
|
+
}
|
|
6027
|
+
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) => {
|
|
6028
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
6029
|
+
return /^\[([a-z_]+)\]/.exec(message)?.[1] ?? null;
|
|
6030
|
+
}, stateMarks = (skill) => `${skill.installed.user ? "[u]" : ""}${skill.installed.project ? "[p]" : ""}${skill.installed.builtin ? "[b]" : ""}`, toItems = (skills) => {
|
|
6031
|
+
const groups = new Map;
|
|
6032
|
+
for (const skill of skills) {
|
|
6033
|
+
const list = groups.get(skill.category) ?? [];
|
|
6034
|
+
list.push(skill);
|
|
6035
|
+
groups.set(skill.category, list);
|
|
6036
|
+
}
|
|
6037
|
+
const items = [];
|
|
6038
|
+
for (const [category, members] of [...groups.entries()].sort((a, b) => b[1].length - a[1].length)) {
|
|
6039
|
+
items.push({ value: `header:${category}`, label: `${category} (${members.length})`, header: true });
|
|
6040
|
+
for (const skill of members) {
|
|
6041
|
+
items.push({
|
|
6042
|
+
value: skill.name,
|
|
6043
|
+
label: skill.name,
|
|
6044
|
+
description: skill.description,
|
|
6045
|
+
searchText: `${skill.source} ${skill.category}`,
|
|
6046
|
+
rightLabel: `${skill.source} ${skill.version} ${stateMarks(skill)}`.trim()
|
|
6047
|
+
});
|
|
6048
|
+
}
|
|
6049
|
+
}
|
|
6050
|
+
return items;
|
|
6051
|
+
};
|
|
6052
|
+
var init_skill_market_ui = __esm(() => {
|
|
6053
|
+
init_theme();
|
|
6054
|
+
CTX = BACKGROUND_CONTEXT4;
|
|
6055
|
+
});
|
|
6056
|
+
|
|
5033
6057
|
// packages/core/src/session-display.ts
|
|
5034
6058
|
function relativeTime(at, now, language = "en") {
|
|
5035
6059
|
const minutes = Math.floor(Math.max(0, now - at) / 60000);
|
|
@@ -5064,15 +6088,15 @@ ${new Date(messageTime(s)).toLocaleString("en-GB")}`
|
|
|
5064
6088
|
var init_workspace2 = () => {};
|
|
5065
6089
|
|
|
5066
6090
|
// packages/tui/src/tui.ts
|
|
5067
|
-
import { BACKGROUND_CONTEXT as
|
|
6091
|
+
import { BACKGROUND_CONTEXT as BACKGROUND_CONTEXT5 } from "@earendil-works/chord/context";
|
|
5068
6092
|
import {
|
|
5069
6093
|
Container as Container5,
|
|
5070
6094
|
isKeyRelease as isKeyRelease5,
|
|
5071
|
-
matchesKey as
|
|
6095
|
+
matchesKey as matchesKey6,
|
|
5072
6096
|
ProcessTerminal,
|
|
5073
6097
|
ScrollView,
|
|
5074
6098
|
Spacer as Spacer2,
|
|
5075
|
-
Text as
|
|
6099
|
+
Text as Text6,
|
|
5076
6100
|
TruncatedText,
|
|
5077
6101
|
TuiAltScreen
|
|
5078
6102
|
} from "@earendil-works/pi-tui";
|
|
@@ -5138,8 +6162,8 @@ class NekoTuiApp {
|
|
|
5138
6162
|
this.#login = new LoginPanel({
|
|
5139
6163
|
changed: () => this.#ui.requestRender(),
|
|
5140
6164
|
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 },
|
|
6165
|
+
save: (provider, key) => this.#gateway.client.credentials.save({ provider, key }, BACKGROUND_CONTEXT5),
|
|
6166
|
+
remove: (provider) => this.#gateway.client.credentials.remove({ provider }, BACKGROUND_CONTEXT5)
|
|
5143
6167
|
});
|
|
5144
6168
|
const complete = fileCompletion(this.#commands, options.cwd ?? process.cwd(), (text) => this.addNotice(text));
|
|
5145
6169
|
const original = complete.applyCompletion.bind(complete);
|
|
@@ -5175,10 +6199,10 @@ class NekoTuiApp {
|
|
|
5175
6199
|
this.#ui.addInputListener((data) => {
|
|
5176
6200
|
if (isKeyRelease5(data))
|
|
5177
6201
|
return { consume: true };
|
|
5178
|
-
if (!
|
|
6202
|
+
if (!matchesKey6(data, "escape") || this.#panel.open || this.#login.open || this.#busyText !== undefined || this.#lastView?.compaction?.active.length)
|
|
5179
6203
|
this.#editor.resetEscapeSequence();
|
|
5180
6204
|
if (!usableSize(this.#terminal.columns, this.#terminal.rows)) {
|
|
5181
|
-
if (
|
|
6205
|
+
if (matchesKey6(data, "ctrl+c"))
|
|
5182
6206
|
this.exit();
|
|
5183
6207
|
return { consume: true };
|
|
5184
6208
|
}
|
|
@@ -5187,7 +6211,7 @@ class NekoTuiApp {
|
|
|
5187
6211
|
}
|
|
5188
6212
|
if (this.#sessionOperation)
|
|
5189
6213
|
return { consume: true };
|
|
5190
|
-
if (
|
|
6214
|
+
if (matchesKey6(data, process.platform === "win32" ? "alt+v" : "ctrl+v")) {
|
|
5191
6215
|
if (isClipboardShortcut(data))
|
|
5192
6216
|
this.pasteClipboard();
|
|
5193
6217
|
return { consume: true };
|
|
@@ -5204,26 +6228,26 @@ class NekoTuiApp {
|
|
|
5204
6228
|
return { consume: true };
|
|
5205
6229
|
}
|
|
5206
6230
|
}
|
|
5207
|
-
if (
|
|
6231
|
+
if (matchesKey6(data, "escape") && this.#editor.isShowingAutocomplete()) {
|
|
5208
6232
|
this.#editor.resetEscapeSequence();
|
|
5209
6233
|
return;
|
|
5210
6234
|
}
|
|
5211
|
-
if (
|
|
6235
|
+
if (matchesKey6(data, "ctrl+c")) {
|
|
5212
6236
|
if (this.#busyText !== undefined)
|
|
5213
6237
|
this.abort();
|
|
5214
6238
|
else
|
|
5215
6239
|
this.exit();
|
|
5216
6240
|
return { consume: true };
|
|
5217
6241
|
}
|
|
5218
|
-
if (
|
|
6242
|
+
if (matchesKey6(data, "escape") && (this.#busyText !== undefined || this.#lastView?.compaction?.active.some((c) => c.reason === "manual" || c.blocking))) {
|
|
5219
6243
|
this.abort();
|
|
5220
6244
|
return { consume: true };
|
|
5221
6245
|
}
|
|
5222
|
-
if (
|
|
6246
|
+
if (matchesKey6(data, "ctrl+s")) {
|
|
5223
6247
|
this.openSessionsOverlay();
|
|
5224
6248
|
return { consume: true };
|
|
5225
6249
|
}
|
|
5226
|
-
if (this.#busyText !== undefined &&
|
|
6250
|
+
if (this.#busyText !== undefined && matchesKey6(data, "alt+enter")) {
|
|
5227
6251
|
this.submitFollowUp();
|
|
5228
6252
|
return { consume: true };
|
|
5229
6253
|
}
|
|
@@ -5285,7 +6309,7 @@ class NekoTuiApp {
|
|
|
5285
6309
|
const chat = this.#chatFacade;
|
|
5286
6310
|
const session = this.#sessionId;
|
|
5287
6311
|
if (chat)
|
|
5288
|
-
chat.compact({ instructions },
|
|
6312
|
+
chat.compact({ instructions }, BACKGROUND_CONTEXT5).catch((e) => {
|
|
5289
6313
|
if (session === this.#sessionId) {
|
|
5290
6314
|
this.#editor.setText(text);
|
|
5291
6315
|
this.addNotice(messageOf(e), true);
|
|
@@ -5317,6 +6341,10 @@ class NekoTuiApp {
|
|
|
5317
6341
|
this.openModelOverlay();
|
|
5318
6342
|
return;
|
|
5319
6343
|
}
|
|
6344
|
+
if (trimmed === "/skills") {
|
|
6345
|
+
this.openSkillsOverlay();
|
|
6346
|
+
return;
|
|
6347
|
+
}
|
|
5320
6348
|
if (trimmed.startsWith("/think")) {
|
|
5321
6349
|
this.configureThinking(trimmed.slice("/think".length).trim());
|
|
5322
6350
|
return;
|
|
@@ -5402,14 +6430,14 @@ class NekoTuiApp {
|
|
|
5402
6430
|
for (const [ref, promise] of refs) {
|
|
5403
6431
|
const file = await promise;
|
|
5404
6432
|
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,
|
|
6433
|
+
begin: (i) => chat.beginImage(i, BACKGROUND_CONTEXT5),
|
|
6434
|
+
append: (i) => chat.appendImage(i, BACKGROUND_CONTEXT5),
|
|
6435
|
+
finish: (id) => chat.finishImage(id, BACKGROUND_CONTEXT5),
|
|
6436
|
+
release: (id) => chat.releaseImage(id, BACKGROUND_CONTEXT5)
|
|
5409
6437
|
}));
|
|
5410
6438
|
content = content.replaceAll(ref, "");
|
|
5411
6439
|
}
|
|
5412
|
-
await chat.submit({ content: content.trim(), images: ids, requestId, ...whenBusy ? { whenBusy } : {} },
|
|
6440
|
+
await chat.submit({ content: content.trim(), images: ids, requestId, ...whenBusy ? { whenBusy } : {} }, BACKGROUND_CONTEXT5);
|
|
5413
6441
|
if (session === this.#sessionId && this.#editor.getText() === before)
|
|
5414
6442
|
this.#editor.setText("");
|
|
5415
6443
|
if (this.#texts.get(session) === before)
|
|
@@ -5424,7 +6452,7 @@ class NekoTuiApp {
|
|
|
5424
6452
|
this.addNotice(messageOf(e), true);
|
|
5425
6453
|
} finally {
|
|
5426
6454
|
for (const id of ids)
|
|
5427
|
-
await chat.releaseImage(id,
|
|
6455
|
+
await chat.releaseImage(id, BACKGROUND_CONTEXT5).catch(() => {});
|
|
5428
6456
|
this.#sending.delete(session);
|
|
5429
6457
|
this.#ui.requestRender();
|
|
5430
6458
|
}
|
|
@@ -5433,7 +6461,7 @@ class NekoTuiApp {
|
|
|
5433
6461
|
const chat = this.#chatFacade;
|
|
5434
6462
|
if (chat === undefined)
|
|
5435
6463
|
return;
|
|
5436
|
-
chat.abort(
|
|
6464
|
+
chat.abort(BACKGROUND_CONTEXT5).catch((error) => this.addNotice(messageOf(error), true));
|
|
5437
6465
|
}
|
|
5438
6466
|
exit() {
|
|
5439
6467
|
if (this.#exitStarted)
|
|
@@ -5464,7 +6492,7 @@ class NekoTuiApp {
|
|
|
5464
6492
|
async#refreshSkills(facade) {
|
|
5465
6493
|
this.#commands.splice(0, this.#commands.length, ...commands);
|
|
5466
6494
|
try {
|
|
5467
|
-
const skills = await facade.skills(
|
|
6495
|
+
const skills = await facade.skills(BACKGROUND_CONTEXT5);
|
|
5468
6496
|
if (facade !== this.#chatFacade)
|
|
5469
6497
|
return;
|
|
5470
6498
|
for (const skill of skills)
|
|
@@ -5484,16 +6512,16 @@ class NekoTuiApp {
|
|
|
5484
6512
|
}
|
|
5485
6513
|
}
|
|
5486
6514
|
async createSession() {
|
|
5487
|
-
const created = await this.#gateway.client.management.create({ ...this.#options.cwd !== undefined ? { cwd: this.#options.cwd } : {} },
|
|
6515
|
+
const created = await this.#gateway.client.management.create({ ...this.#options.cwd !== undefined ? { cwd: this.#options.cwd } : {} }, BACKGROUND_CONTEXT5);
|
|
5488
6516
|
await this.switchSession(created.id);
|
|
5489
6517
|
}
|
|
5490
6518
|
async forkSession() {
|
|
5491
|
-
const forked = await this.#gateway.client.management.fork(this.#sessionId,
|
|
6519
|
+
const forked = await this.#gateway.client.management.fork(this.#sessionId, BACKGROUND_CONTEXT5);
|
|
5492
6520
|
await this.switchSession(forked.id);
|
|
5493
6521
|
}
|
|
5494
6522
|
async archiveSession() {
|
|
5495
6523
|
const current = this.#sessionId;
|
|
5496
|
-
await this.#gateway.client.management.archive(current,
|
|
6524
|
+
await this.#gateway.client.management.archive(current, BACKGROUND_CONTEXT5);
|
|
5497
6525
|
const next = recentlyVisited(this.#gateway.client.directory.state.value?.sessions ?? [], this.#options.cwd).find((s) => s.id !== current);
|
|
5498
6526
|
if (next)
|
|
5499
6527
|
await this.switchSession(next.id);
|
|
@@ -5518,6 +6546,14 @@ class NekoTuiApp {
|
|
|
5518
6546
|
this.#sessionPanelTimer = setInterval(() => this.#panel.update(this.sessionItems()), 60000);
|
|
5519
6547
|
this.#ui.setFocus(this.#panel);
|
|
5520
6548
|
}
|
|
6549
|
+
async openSkillsOverlay() {
|
|
6550
|
+
if (this.#exitStarted || this.#panel.open || this.#login.open)
|
|
6551
|
+
return;
|
|
6552
|
+
const workspace = this.#options.cwd ?? process.cwd();
|
|
6553
|
+
const ready = openSkillMarket(this.#panel, this.#gateway.client, workspace);
|
|
6554
|
+
this.#ui.setFocus(this.#panel);
|
|
6555
|
+
await ready;
|
|
6556
|
+
}
|
|
5521
6557
|
async openModelOverlay() {
|
|
5522
6558
|
if (this.#exitStarted || this.#panel.open || this.#login.open)
|
|
5523
6559
|
return;
|
|
@@ -5535,7 +6571,7 @@ class NekoTuiApp {
|
|
|
5535
6571
|
}, async (value) => {
|
|
5536
6572
|
const selected = models.find((m) => keyOf(m) === value);
|
|
5537
6573
|
if (selected && value !== currentKey)
|
|
5538
|
-
await chat?.configure({ model: { provider: selected.provider, modelId: selected.modelId } },
|
|
6574
|
+
await chat?.configure({ model: { provider: selected.provider, modelId: selected.modelId } }, BACKGROUND_CONTEXT5);
|
|
5539
6575
|
});
|
|
5540
6576
|
this.#ui.setFocus(this.#panel);
|
|
5541
6577
|
await ready;
|
|
@@ -5557,14 +6593,14 @@ class NekoTuiApp {
|
|
|
5557
6593
|
this.addNotice(`Available levels: ${model.supportedThinkingLevels.join(" / ")}`, true);
|
|
5558
6594
|
return;
|
|
5559
6595
|
}
|
|
5560
|
-
await chat.configure({ thinkingLevel: level },
|
|
6596
|
+
await chat.configure({ thinkingLevel: level }, BACKGROUND_CONTEXT5);
|
|
5561
6597
|
} else {
|
|
5562
6598
|
this.#thinkingModel = keyOf(model);
|
|
5563
6599
|
this.#panel.show("Thinking level", async () => model.supportedThinkingLevels.map((level) => ({
|
|
5564
6600
|
value: level,
|
|
5565
6601
|
label: `${level}${level === this.#lastView?.agent.thinkingLevel ? " (Current)" : ""}`
|
|
5566
6602
|
})), async (value) => {
|
|
5567
|
-
await chat.configure({ thinkingLevel: value },
|
|
6603
|
+
await chat.configure({ thinkingLevel: value }, BACKGROUND_CONTEXT5);
|
|
5568
6604
|
});
|
|
5569
6605
|
this.#ui.setFocus(this.#panel);
|
|
5570
6606
|
}
|
|
@@ -5676,7 +6712,7 @@ class NekoTuiApp {
|
|
|
5676
6712
|
if (!chat)
|
|
5677
6713
|
return;
|
|
5678
6714
|
for (const image of images) {
|
|
5679
|
-
const component = new HistoryImage(image, () => downloadImage((offset) => chat.getImage({ entryId: image.entryId, contentIndex: image.contentIndex, offset },
|
|
6715
|
+
const component = new HistoryImage(image, () => downloadImage((offset) => chat.getImage({ entryId: image.entryId, contentIndex: image.contentIndex, offset }, BACKGROUND_CONTEXT5)), () => {
|
|
5680
6716
|
if (session === this.#sessionId)
|
|
5681
6717
|
this.#ui.requestRender();
|
|
5682
6718
|
});
|
|
@@ -5712,7 +6748,7 @@ class NekoTuiApp {
|
|
|
5712
6748
|
this.#items.set(item.key, { kind: "tool", component });
|
|
5713
6749
|
return;
|
|
5714
6750
|
}
|
|
5715
|
-
const component = new
|
|
6751
|
+
const component = new Text6(theme.dim(item.text), 1, 0);
|
|
5716
6752
|
this.#chat.addChild(component);
|
|
5717
6753
|
this.#items.set(item.key, { kind: "system", component });
|
|
5718
6754
|
}
|
|
@@ -5876,7 +6912,7 @@ async function initialSessionId(gateway, cwd) {
|
|
|
5876
6912
|
const first = recentlyVisited(sessions, cwd)[0];
|
|
5877
6913
|
if (first !== undefined)
|
|
5878
6914
|
return first.id;
|
|
5879
|
-
return (await gateway.client.management.create({ ...cwd !== undefined ? { cwd } : {} },
|
|
6915
|
+
return (await gateway.client.management.create({ ...cwd !== undefined ? { cwd } : {} }, BACKGROUND_CONTEXT5)).id;
|
|
5880
6916
|
}
|
|
5881
6917
|
var EXIT_COMMANDS, SESSIONS_COMMANDS, NEW_SESSION_VALUE = "__new__";
|
|
5882
6918
|
var init_tui = __esm(() => {
|
|
@@ -5894,6 +6930,7 @@ var init_tui = __esm(() => {
|
|
|
5894
6930
|
init_image_input();
|
|
5895
6931
|
init_labels();
|
|
5896
6932
|
init_layout();
|
|
6933
|
+
init_skill_market_ui();
|
|
5897
6934
|
init_theme();
|
|
5898
6935
|
init_workspace2();
|
|
5899
6936
|
EXIT_COMMANDS = new Set(["/exit", "/quit"]);
|
|
@@ -6011,11 +7048,11 @@ var init_open_browser = () => {};
|
|
|
6011
7048
|
|
|
6012
7049
|
// packages/web/src/gateway-spawn.ts
|
|
6013
7050
|
import { spawn as spawn3 } from "child_process";
|
|
6014
|
-
import { randomUUID as
|
|
6015
|
-
import { mkdir as
|
|
6016
|
-
import { dirname as
|
|
7051
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
7052
|
+
import { mkdir as mkdir4, readFile as readFile7, writeFile as writeFile4 } from "fs/promises";
|
|
7053
|
+
import { dirname as dirname9, join as join12 } from "path";
|
|
6017
7054
|
async function ensureNekoGateway(options) {
|
|
6018
|
-
const nekoDir =
|
|
7055
|
+
const nekoDir = dirname9(options.storagePath);
|
|
6019
7056
|
const serverId = options.serverId ?? await loadOrCreateServerId2(nekoDir);
|
|
6020
7057
|
if (process.platform === "win32") {
|
|
6021
7058
|
const discovered = await readGatewayPortFile(nekoDir, serverId);
|
|
@@ -6054,7 +7091,7 @@ async function ensureNekoGateway(options) {
|
|
|
6054
7091
|
throw error;
|
|
6055
7092
|
}
|
|
6056
7093
|
}
|
|
6057
|
-
const socketPath = options.socketPath ??
|
|
7094
|
+
const socketPath = options.socketPath ?? join12(nekoDir, `${serverId}.sock`);
|
|
6058
7095
|
const host = options.host ?? "127.0.0.1";
|
|
6059
7096
|
const port = options.port ?? 8321;
|
|
6060
7097
|
if (await probeGateway(socketPath, serverId)) {
|
|
@@ -6157,15 +7194,15 @@ function makeHandle(serverId, socketPath, wsUrl, spawned, nekoDir) {
|
|
|
6157
7194
|
};
|
|
6158
7195
|
}
|
|
6159
7196
|
async function loadOrCreateServerId2(nekoDir) {
|
|
6160
|
-
const file =
|
|
7197
|
+
const file = join12(nekoDir, SERVER_ID_FILENAME3);
|
|
6161
7198
|
try {
|
|
6162
7199
|
const existing = (await readFile7(file, "utf8")).trim();
|
|
6163
7200
|
if (existing !== "")
|
|
6164
7201
|
return existing;
|
|
6165
7202
|
} catch {}
|
|
6166
|
-
const created =
|
|
6167
|
-
await
|
|
6168
|
-
await
|
|
7203
|
+
const created = randomUUID3();
|
|
7204
|
+
await mkdir4(nekoDir, { recursive: true, mode: 448 });
|
|
7205
|
+
await writeFile4(file, `${created}
|
|
6169
7206
|
`, { mode: 384 });
|
|
6170
7207
|
return created;
|
|
6171
7208
|
}
|
|
@@ -6179,10 +7216,10 @@ var init_gateway_spawn = __esm(() => {
|
|
|
6179
7216
|
|
|
6180
7217
|
// packages/web/src/server.ts
|
|
6181
7218
|
import { createReadStream } from "fs";
|
|
6182
|
-
import { stat as
|
|
7219
|
+
import { stat as stat5 } from "fs/promises";
|
|
6183
7220
|
import { createServer } from "http";
|
|
6184
7221
|
import { extname as extname2, resolve as resolve6, sep as sep2 } from "path";
|
|
6185
|
-
import { fileURLToPath as
|
|
7222
|
+
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
6186
7223
|
async function startWebServer(options = {}) {
|
|
6187
7224
|
const staticDir = resolve6(options.staticDir ?? DEFAULT_STATIC_DIR);
|
|
6188
7225
|
const workspaceRoot = normalizeWorkspace(options.gateway?.cwd ?? process.cwd());
|
|
@@ -6245,18 +7282,18 @@ async function serveStatic(pathname, method, response, staticDir) {
|
|
|
6245
7282
|
return;
|
|
6246
7283
|
}
|
|
6247
7284
|
let file = candidate;
|
|
6248
|
-
let stats = await
|
|
7285
|
+
let stats = await stat5(file).catch(() => {
|
|
6249
7286
|
return;
|
|
6250
7287
|
});
|
|
6251
7288
|
if (stats?.isDirectory()) {
|
|
6252
7289
|
file = resolve6(file, "index.html");
|
|
6253
|
-
stats = await
|
|
7290
|
+
stats = await stat5(file).catch(() => {
|
|
6254
7291
|
return;
|
|
6255
7292
|
});
|
|
6256
7293
|
}
|
|
6257
7294
|
if (stats === undefined && extname2(candidate) === "") {
|
|
6258
7295
|
file = resolve6(staticDir, "index.html");
|
|
6259
|
-
stats = await
|
|
7296
|
+
stats = await stat5(file).catch(() => {
|
|
6260
7297
|
return;
|
|
6261
7298
|
});
|
|
6262
7299
|
}
|
|
@@ -6281,7 +7318,7 @@ var DEFAULT_PORT2 = 8322, DEFAULT_HOST2 = "127.0.0.1", DEFAULT_STATIC_DIR, MIME;
|
|
|
6281
7318
|
var init_server = __esm(() => {
|
|
6282
7319
|
init_src();
|
|
6283
7320
|
init_gateway_spawn();
|
|
6284
|
-
DEFAULT_STATIC_DIR =
|
|
7321
|
+
DEFAULT_STATIC_DIR = fileURLToPath3(new URL("./client", import.meta.url));
|
|
6285
7322
|
MIME = {
|
|
6286
7323
|
".html": "text/html; charset=utf-8",
|
|
6287
7324
|
".js": "text/javascript; charset=utf-8",
|
|
@@ -6615,7 +7652,7 @@ switch (command2) {
|
|
|
6615
7652
|
}
|
|
6616
7653
|
case "--version":
|
|
6617
7654
|
case "-v":
|
|
6618
|
-
console.log("0.2.
|
|
7655
|
+
console.log("0.2.4");
|
|
6619
7656
|
break;
|
|
6620
7657
|
case undefined:
|
|
6621
7658
|
case "-h":
|