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/gateway.js CHANGED
@@ -105,9 +105,9 @@ function parseGatewayArgs(argv) {
105
105
  }
106
106
 
107
107
  // packages/gateway/src/gateway.ts
108
- import { randomUUID } from "crypto";
109
- import { mkdir as mkdir2, readFile as readFile5, writeFile as writeFile2 } from "fs/promises";
110
- import { basename as basename4, dirname as dirname6, join as join9 } from "path";
108
+ import { randomUUID as randomUUID2 } from "crypto";
109
+ import { mkdir as mkdir3, readFile as readFile5, writeFile as writeFile3 } from "fs/promises";
110
+ import { basename as basename4, dirname as dirname7, join as join10 } from "path";
111
111
  import { BACKGROUND_CONTEXT as BACKGROUND_CONTEXT2 } from "@earendil-works/chord/context";
112
112
  import { isServerId } from "@earendil-works/pi-protocol";
113
113
  import { Server, SessionNotFoundError } from "@earendil-works/pi-server";
@@ -226,6 +226,7 @@ class CompactionManager {
226
226
  import { existsSync, readFileSync } from "fs";
227
227
  import { homedir } from "os";
228
228
  import { dirname, join, resolve } from "path";
229
+ var DEFAULT_SKILL_MARKET_URL = "https://skill.kirineko.tech";
229
230
  var NEKO_CONFIG_BASENAME = "neko.config.json";
230
231
  function findNekoConfigFile(startDir = process.cwd()) {
231
232
  let dir = resolve(startDir);
@@ -328,6 +329,16 @@ function validate(config, source) {
328
329
  if (theme !== undefined && theme !== "light" && theme !== "dark" && theme !== "auto") {
329
330
  throw new Error(`neko config: ${source}: "theme" must be "light", "dark", or "auto".`);
330
331
  }
332
+ const skills = config.skills;
333
+ if (skills !== undefined) {
334
+ if (typeof skills !== "object" || skills === null) {
335
+ throw new Error(`neko config: ${source}: "skills" must be an object.`);
336
+ }
337
+ const { marketUrl } = skills;
338
+ if (marketUrl !== undefined && typeof marketUrl !== "string") {
339
+ throw new Error(`neko config: ${source}: "skills.marketUrl" must be a string.`);
340
+ }
341
+ }
331
342
  }
332
343
  // packages/core/src/credentials.ts
333
344
  import { chmod, mkdir, open, readFile, rename, unlink } from "fs/promises";
@@ -936,6 +947,32 @@ function contextTokens(entries) {
936
947
  }
937
948
  return null;
938
949
  }
950
+ // packages/core/src/prompt/frontmatter.ts
951
+ import { parse } from "yaml";
952
+ var normalizeNewlines = (value) => value.replace(/\r\n/g, `
953
+ `).replace(/\r/g, `
954
+ `);
955
+ var extractFrontmatter = (content) => {
956
+ const normalized = normalizeNewlines(content.replace(/^\uFEFF/, ""));
957
+ const opening = /^---[ \t]*\n/.exec(normalized);
958
+ if (!opening)
959
+ return { yamlString: null, body: normalized };
960
+ const rest = normalized.slice(opening[0].length);
961
+ const closing = /^---[ \t]*(?:\n|$)/m.exec(rest);
962
+ if (!closing)
963
+ return { yamlString: null, body: normalized };
964
+ return { yamlString: rest.slice(0, closing.index), body: rest.slice(closing.index + closing[0].length).trim() };
965
+ };
966
+ var parseFrontmatter = (content) => {
967
+ const { yamlString, body } = extractFrontmatter(content);
968
+ if (!yamlString)
969
+ return { frontmatter: {}, body };
970
+ const parsed = parse(yamlString);
971
+ if (parsed !== null && (typeof parsed !== "object" || Array.isArray(parsed)))
972
+ throw new Error("Frontmatter must be a YAML mapping.");
973
+ return { frontmatter: parsed ?? {}, body };
974
+ };
975
+ var stripFrontmatter = (content) => extractFrontmatter(content).body;
939
976
  // packages/core/src/runtime.ts
940
977
  import { homedir as homedir4 } from "os";
941
978
  import { join as join5 } from "path";
@@ -965,33 +1002,6 @@ var warnPromptDiagnostic = ({ path, message }) => {
965
1002
  };
966
1003
  var isMissing = (error) => typeof error === "object" && error !== null && ("code" in error) && (error.code === "ENOENT" || error.code === "ENOTDIR");
967
1004
 
968
- // packages/core/src/prompt/frontmatter.ts
969
- import { parse } from "yaml";
970
- var normalizeNewlines = (value) => value.replace(/\r\n/g, `
971
- `).replace(/\r/g, `
972
- `);
973
- var extractFrontmatter = (content) => {
974
- const normalized = normalizeNewlines(content.replace(/^\uFEFF/, ""));
975
- const opening = /^---[ \t]*\n/.exec(normalized);
976
- if (!opening)
977
- return { yamlString: null, body: normalized };
978
- const rest = normalized.slice(opening[0].length);
979
- const closing = /^---[ \t]*(?:\n|$)/m.exec(rest);
980
- if (!closing)
981
- return { yamlString: null, body: normalized };
982
- return { yamlString: rest.slice(0, closing.index), body: rest.slice(closing.index + closing[0].length).trim() };
983
- };
984
- var parseFrontmatter = (content) => {
985
- const { yamlString, body } = extractFrontmatter(content);
986
- if (!yamlString)
987
- return { frontmatter: {}, body };
988
- const parsed = parse(yamlString);
989
- if (parsed !== null && (typeof parsed !== "object" || Array.isArray(parsed)))
990
- throw new Error("Frontmatter must be a YAML mapping.");
991
- return { frontmatter: parsed ?? {}, body };
992
- };
993
- var stripFrontmatter = (content) => extractFrontmatter(content).body;
994
-
995
1005
  // packages/core/src/prompt/skills.ts
996
1006
  import { readdir, readFile as readFile2 } from "fs/promises";
997
1007
  import { basename, dirname as dirname3, join as join3 } from "path";
@@ -1182,14 +1192,25 @@ ${text}
1182
1192
  };
1183
1193
 
1184
1194
  // packages/core/src/prompt/resources.ts
1195
+ import { existsSync as existsSync2 } from "fs";
1185
1196
  import { readFile as readFile3 } from "fs/promises";
1186
1197
  import { homedir as homedir3 } from "os";
1187
1198
  import { join as join4 } from "path";
1199
+ import { fileURLToPath } from "url";
1188
1200
  var userAgentsFile = (home) => join4(home, ".agents", "AGENTS.md");
1189
1201
  var userSkillsDir = (home) => join4(home, ".agents", "skills");
1190
1202
  var workspaceAgentsFile = (workspace) => join4(workspace, "AGENTS.md");
1191
1203
  var workspaceSkillsDir = (workspace) => join4(workspace, ".agents", "skills");
1192
- var readResources = async (workspace, home, report, invocationName) => {
1204
+ var resolveBuiltinSkillsDir = () => {
1205
+ for (const url of [new URL("./skills/", import.meta.url), new URL("../../skills/", import.meta.url)]) {
1206
+ const path = fileURLToPath(url);
1207
+ if (existsSync2(join4(path, "skill-creator", "SKILL.md")))
1208
+ return path;
1209
+ }
1210
+ return null;
1211
+ };
1212
+ var BUILTIN_SKILLS_DIR = resolveBuiltinSkillsDir();
1213
+ var readResources = async (workspace, home, builtinDir, report, invocationName) => {
1193
1214
  const contextFiles = [];
1194
1215
  for (const path of [userAgentsFile(home), workspaceAgentsFile(workspace)]) {
1195
1216
  try {
@@ -1210,11 +1231,13 @@ var readResources = async (workspace, home, report, invocationName) => {
1210
1231
  if (skill.name === invocationName)
1211
1232
  candidates.set(skill.filePath, content);
1212
1233
  } : undefined;
1213
- const [user, project] = await Promise.all([
1214
- scanSkillsDir(userSkillsDir(home), report, capture),
1215
- scanSkillsDir(workspaceSkillsDir(workspace), report, capture)
1234
+ const scan = async (dir, level) => (await scanSkillsDir(dir, report, capture)).map((skill) => ({ ...skill, level }));
1235
+ const [builtin, user, project] = await Promise.all([
1236
+ builtinDir === null ? Promise.resolve([]) : scan(builtinDir, "builtin"),
1237
+ scan(userSkillsDir(home), "user"),
1238
+ scan(workspaceSkillsDir(workspace), "project")
1216
1239
  ]);
1217
- const skills = mergeSkills([user, project]);
1240
+ const skills = mergeSkills([builtin, user, project]);
1218
1241
  const winner = invocationName === undefined ? undefined : skills.find((skill) => skill.name === invocationName);
1219
1242
  if (winner && candidates) {
1220
1243
  const content = candidates.get(winner.filePath);
@@ -1223,11 +1246,12 @@ var readResources = async (workspace, home, report, invocationName) => {
1223
1246
  }
1224
1247
  return { contextFiles, skills };
1225
1248
  };
1226
- var createResourceLoader = (home = homedir3(), report = warnPromptDiagnostic) => {
1249
+ var createResourceLoader = (home = homedir3(), report = warnPromptDiagnostic, options) => {
1250
+ const builtinDir = options?.builtinDir === undefined ? BUILTIN_SKILLS_DIR : options.builtinDir;
1227
1251
  const previous = new Map;
1228
1252
  return async (workspace, invocationName) => {
1229
1253
  const diagnostics = [];
1230
- const resources = await readResources(workspace, home, (d) => diagnostics.push(d), invocationName);
1254
+ const resources = await readResources(workspace, home, builtinDir, (d) => diagnostics.push(d), invocationName);
1231
1255
  const known = previous.get(workspace);
1232
1256
  const current = new Set;
1233
1257
  for (const diagnostic of diagnostics) {
@@ -1243,6 +1267,15 @@ var createResourceLoader = (home = homedir3(), report = warnPromptDiagnostic) =>
1243
1267
  return resources;
1244
1268
  };
1245
1269
  };
1270
+ var scanSkillsByLevel = async (workspace, home = homedir3(), builtinDir = BUILTIN_SKILLS_DIR, report = warnPromptDiagnostic) => {
1271
+ const scan = async (dir, level) => (await scanSkillsDir(dir, report)).map((skill) => ({ ...skill, level }));
1272
+ const [builtin, user, project] = await Promise.all([
1273
+ builtinDir === null ? [] : scan(builtinDir, "builtin"),
1274
+ scan(userSkillsDir(home), "user"),
1275
+ scan(workspaceSkillsDir(workspace), "project")
1276
+ ]);
1277
+ return [...project, ...user, ...builtin];
1278
+ };
1246
1279
 
1247
1280
  // packages/core/src/prompt/snapshots.ts
1248
1281
  var createResourceSnapshots = (load, submission) => {
@@ -2416,7 +2449,21 @@ async function createNekoRuntime(options = {}) {
2416
2449
  const session = await sessionFor(id);
2417
2450
  const agent = await session.conversation.agent(context);
2418
2451
  const { skills } = await loadResources(savedWorkspace(agent.cwd));
2419
- return skills.map((skill) => ({ name: skill.name, description: skill.description, location: skill.filePath }));
2452
+ return skills.map((skill) => ({
2453
+ name: skill.name,
2454
+ description: skill.description,
2455
+ location: skill.filePath,
2456
+ level: skill.level
2457
+ }));
2458
+ },
2459
+ async listSkillsByLevel(cwd) {
2460
+ const skills = await scanSkillsByLevel(normalizeWorkspace(cwd ?? defaultCwd), options.promptHome ?? homedir4());
2461
+ return skills.map((skill) => ({
2462
+ name: skill.name,
2463
+ description: skill.description,
2464
+ location: skill.filePath,
2465
+ level: skill.level
2466
+ }));
2420
2467
  },
2421
2468
  installExtension(extension) {
2422
2469
  registry.install(extension);
@@ -2585,6 +2632,7 @@ var NekoChat = defineService("neko.chat");
2585
2632
  var NekoWorkspaces = defineService("neko.workspaces");
2586
2633
  var NekoCredentials = defineService("neko.credentials");
2587
2634
  var NekoWorkspaceFiles = defineService("neko.workspace-files");
2635
+ var NekoSkillMarket = defineService("neko.skill-market");
2588
2636
 
2589
2637
  // packages/gateway/src/file-search-help.ts
2590
2638
  function fileSearchInstallHelp(platform = process.platform) {
@@ -2606,10 +2654,644 @@ function fileSearchInstallHelp(platform = process.platform) {
2606
2654
  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`;
2607
2655
  }
2608
2656
 
2657
+ // packages/gateway/src/skill-market.ts
2658
+ import { createHash as createHash2, randomUUID } from "crypto";
2659
+ import { mkdir as mkdir2, readdir as readdir2, rename as rename2, rm as rm2, stat as stat2, writeFile as writeFile2 } from "fs/promises";
2660
+ import { homedir as homedir5 } from "os";
2661
+ import { dirname as dirname5, join as join8 } from "path";
2662
+
2663
+ // node_modules/fflate/esm/index.mjs
2664
+ import { createRequire } from "module";
2665
+ var require2 = createRequire("/");
2666
+ var _a;
2667
+ var Worker;
2668
+ var isMarkedAsUntransferable;
2669
+ try {
2670
+ _a = require2("worker_threads"), Worker = _a.Worker, isMarkedAsUntransferable = _a.isMarkedAsUntransferable;
2671
+ } catch (e) {}
2672
+ var u8 = Uint8Array;
2673
+ var u16 = Uint16Array;
2674
+ var i32 = Int32Array;
2675
+ var 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]);
2676
+ var 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]);
2677
+ var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
2678
+ var freb = function(eb, start) {
2679
+ var b = new u16(31);
2680
+ for (var i = 0;i < 31; ++i) {
2681
+ b[i] = start += 1 << eb[i - 1];
2682
+ }
2683
+ var r = new i32(b[30]);
2684
+ for (var i = 1;i < 30; ++i) {
2685
+ for (var j = b[i];j < b[i + 1]; ++j) {
2686
+ r[j] = j - b[i] << 5 | i;
2687
+ }
2688
+ }
2689
+ return { b, r };
2690
+ };
2691
+ var _a = freb(fleb, 2);
2692
+ var fl = _a.b;
2693
+ var revfl = _a.r;
2694
+ fl[28] = 258, revfl[258] = 28;
2695
+ var _b = freb(fdeb, 0);
2696
+ var fd = _b.b;
2697
+ var revfd = _b.r;
2698
+ var rev = new u16(32768);
2699
+ for (i = 0;i < 32768; ++i) {
2700
+ x = (i & 43690) >> 1 | (i & 21845) << 1;
2701
+ x = (x & 52428) >> 2 | (x & 13107) << 2;
2702
+ x = (x & 61680) >> 4 | (x & 3855) << 4;
2703
+ rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
2704
+ }
2705
+ var x;
2706
+ var i;
2707
+ var hMap = function(cd, mb, r) {
2708
+ var s = cd.length;
2709
+ var i = 0;
2710
+ var l = new u16(mb);
2711
+ for (;i < s; ++i) {
2712
+ if (cd[i])
2713
+ ++l[cd[i] - 1];
2714
+ }
2715
+ var le = new u16(mb);
2716
+ for (i = 1;i < mb; ++i) {
2717
+ le[i] = le[i - 1] + l[i - 1] << 1;
2718
+ }
2719
+ var co;
2720
+ if (r) {
2721
+ co = new u16(1 << mb);
2722
+ var rvb = 15 - mb;
2723
+ for (i = 0;i < s; ++i) {
2724
+ if (cd[i]) {
2725
+ var sv = i << 4 | cd[i];
2726
+ var r_1 = mb - cd[i];
2727
+ var v = le[cd[i] - 1]++ << r_1;
2728
+ for (var m = v | (1 << r_1) - 1;v <= m; ++v) {
2729
+ co[rev[v] >> rvb] = sv;
2730
+ }
2731
+ }
2732
+ }
2733
+ } else {
2734
+ co = new u16(s);
2735
+ for (i = 0;i < s; ++i) {
2736
+ if (cd[i]) {
2737
+ co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];
2738
+ }
2739
+ }
2740
+ }
2741
+ return co;
2742
+ };
2743
+ var flt = new u8(288);
2744
+ for (i = 0;i < 144; ++i)
2745
+ flt[i] = 8;
2746
+ var i;
2747
+ for (i = 144;i < 256; ++i)
2748
+ flt[i] = 9;
2749
+ var i;
2750
+ for (i = 256;i < 280; ++i)
2751
+ flt[i] = 7;
2752
+ var i;
2753
+ for (i = 280;i < 288; ++i)
2754
+ flt[i] = 8;
2755
+ var i;
2756
+ var fdt = new u8(32);
2757
+ for (i = 0;i < 32; ++i)
2758
+ fdt[i] = 5;
2759
+ var i;
2760
+ var flrm = /* @__PURE__ */ hMap(flt, 9, 1);
2761
+ var fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);
2762
+ var max = function(a) {
2763
+ var m = a[0];
2764
+ for (var i = 1;i < a.length; ++i) {
2765
+ if (a[i] > m)
2766
+ m = a[i];
2767
+ }
2768
+ return m;
2769
+ };
2770
+ var bits = function(d, p, m) {
2771
+ var o = p / 8 | 0;
2772
+ return (d[o] | d[o + 1] << 8) >> (p & 7) & m;
2773
+ };
2774
+ var bits16 = function(d, p) {
2775
+ var o = p / 8 | 0;
2776
+ return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);
2777
+ };
2778
+ var shft = function(p) {
2779
+ return (p + 7) / 8 | 0;
2780
+ };
2781
+ var slc = function(v, s, e) {
2782
+ if (s == null || s < 0)
2783
+ s = 0;
2784
+ if (e == null || e > v.length)
2785
+ e = v.length;
2786
+ return new u8(v.subarray(s, e));
2787
+ };
2788
+ var ec = [
2789
+ "unexpected EOF",
2790
+ "invalid block type",
2791
+ "invalid length/literal",
2792
+ "invalid distance",
2793
+ "stream finished",
2794
+ "no stream handler",
2795
+ ,
2796
+ "no callback",
2797
+ "invalid UTF-8 data",
2798
+ "extra field too long",
2799
+ "date not in range 1980-2099",
2800
+ "filename too long",
2801
+ "stream finishing",
2802
+ "invalid zip data"
2803
+ ];
2804
+ var err = function(ind, msg, nt) {
2805
+ var e = new Error(msg || ec[ind]);
2806
+ e.code = ind;
2807
+ if (Error.captureStackTrace)
2808
+ Error.captureStackTrace(e, err);
2809
+ if (!nt)
2810
+ throw e;
2811
+ return e;
2812
+ };
2813
+ var inflt = function(dat, st, buf, dict) {
2814
+ var sl = dat.length, dl = dict ? dict.length : 0;
2815
+ if (!sl || st.f && !st.l)
2816
+ return buf || new u8(0);
2817
+ var noBuf = !buf;
2818
+ var resize = noBuf || st.i != 2;
2819
+ var noSt = st.i;
2820
+ if (noBuf)
2821
+ buf = new u8(sl * 3);
2822
+ var cbuf = function(l) {
2823
+ var bl = buf.length;
2824
+ if (l > bl) {
2825
+ var nbuf = new u8(Math.max(bl * 2, l));
2826
+ nbuf.set(buf);
2827
+ buf = nbuf;
2828
+ }
2829
+ };
2830
+ var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, { l: lm, d: dm, m: lbt, n: dbt } = st;
2831
+ var tbts = sl * 8;
2832
+ do {
2833
+ if (!lm) {
2834
+ final = bits(dat, pos, 1);
2835
+ var type = bits(dat, pos + 1, 3);
2836
+ pos += 3;
2837
+ if (!type) {
2838
+ var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;
2839
+ if (t > sl) {
2840
+ if (noSt)
2841
+ err(0);
2842
+ break;
2843
+ }
2844
+ if (resize)
2845
+ cbuf(bt + l);
2846
+ buf.set(dat.subarray(s, t), bt);
2847
+ st.b = bt += l, st.p = pos = t * 8, st.f = final;
2848
+ continue;
2849
+ } else if (type == 1)
2850
+ lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
2851
+ else if (type == 2) {
2852
+ var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
2853
+ var tl = hLit + bits(dat, pos + 5, 31) + 1;
2854
+ pos += 14;
2855
+ var ldt = new u8(tl);
2856
+ var clt = new u8(19);
2857
+ for (var i = 0;i < hcLen; ++i) {
2858
+ clt[clim[i]] = bits(dat, pos + i * 3, 7);
2859
+ }
2860
+ pos += hcLen * 3;
2861
+ var clb = max(clt), clbmsk = (1 << clb) - 1;
2862
+ var clm = hMap(clt, clb, 1);
2863
+ for (var i = 0;i < tl; ) {
2864
+ var r = clm[bits(dat, pos, clbmsk)];
2865
+ pos += r & 15;
2866
+ var s = r >> 4;
2867
+ if (s < 16) {
2868
+ ldt[i++] = s;
2869
+ } else {
2870
+ var c = 0, n = 0;
2871
+ if (s == 16)
2872
+ n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];
2873
+ else if (s == 17)
2874
+ n = 3 + bits(dat, pos, 7), pos += 3;
2875
+ else if (s == 18)
2876
+ n = 11 + bits(dat, pos, 127), pos += 7;
2877
+ while (n--)
2878
+ ldt[i++] = c;
2879
+ }
2880
+ }
2881
+ var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
2882
+ lbt = max(lt);
2883
+ dbt = max(dt);
2884
+ lm = hMap(lt, lbt, 1);
2885
+ dm = hMap(dt, dbt, 1);
2886
+ } else
2887
+ err(1);
2888
+ if (pos > tbts) {
2889
+ if (noSt)
2890
+ err(0);
2891
+ break;
2892
+ }
2893
+ }
2894
+ if (resize)
2895
+ cbuf(bt + 131072);
2896
+ var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
2897
+ var lpos = pos;
2898
+ for (;; lpos = pos) {
2899
+ var c = lm[bits16(dat, pos) & lms], sym = c >> 4;
2900
+ pos += c & 15;
2901
+ if (pos > tbts) {
2902
+ if (noSt)
2903
+ err(0);
2904
+ break;
2905
+ }
2906
+ if (!c)
2907
+ err(2);
2908
+ if (sym < 256)
2909
+ buf[bt++] = sym;
2910
+ else if (sym == 256) {
2911
+ lpos = pos, lm = null;
2912
+ break;
2913
+ } else {
2914
+ var add = sym - 254;
2915
+ if (sym > 264) {
2916
+ var i = sym - 257, b = fleb[i];
2917
+ add = bits(dat, pos, (1 << b) - 1) + fl[i];
2918
+ pos += b;
2919
+ }
2920
+ var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;
2921
+ if (!d)
2922
+ err(3);
2923
+ pos += d & 15;
2924
+ var dt = fd[dsym];
2925
+ if (dsym > 3) {
2926
+ var b = fdeb[dsym];
2927
+ dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
2928
+ }
2929
+ if (pos > tbts) {
2930
+ if (noSt)
2931
+ err(0);
2932
+ break;
2933
+ }
2934
+ if (resize)
2935
+ cbuf(bt + 131072);
2936
+ var end = bt + add;
2937
+ if (bt < dt) {
2938
+ var shift = dl - dt, dend = Math.min(dt, end);
2939
+ if (shift + bt < 0)
2940
+ err(3);
2941
+ for (;bt < dend; ++bt)
2942
+ buf[bt] = dict[shift + bt];
2943
+ }
2944
+ for (;bt < end; ++bt)
2945
+ buf[bt] = buf[bt - dt];
2946
+ }
2947
+ }
2948
+ st.l = lm, st.p = lpos, st.b = bt, st.f = final;
2949
+ if (lm)
2950
+ final = 1, st.m = lbt, st.d = dm, st.n = dbt;
2951
+ } while (!final);
2952
+ return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
2953
+ };
2954
+ var et = /* @__PURE__ */ new u8(0);
2955
+ var b2 = function(d, b) {
2956
+ return d[b] | d[b + 1] << 8;
2957
+ };
2958
+ var b4 = function(d, b) {
2959
+ return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
2960
+ };
2961
+ var b8 = function(d, b) {
2962
+ return b4(d, b) + b4(d, b + 4) * 4294967296;
2963
+ };
2964
+ function inflateSync(data, opts) {
2965
+ return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);
2966
+ }
2967
+ var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder;
2968
+ var tds = 0;
2969
+ try {
2970
+ td.decode(et, { stream: true });
2971
+ tds = 1;
2972
+ } catch (e) {}
2973
+ var dutf8 = function(d) {
2974
+ for (var r = "", i = 0;; ) {
2975
+ var c = d[i++];
2976
+ var eb = (c > 127) + (c > 223) + (c > 239);
2977
+ if (i + eb > d.length)
2978
+ return { s: r, r: slc(d, i - 1) };
2979
+ if (!eb)
2980
+ r += String.fromCharCode(c);
2981
+ else if (eb == 3) {
2982
+ 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);
2983
+ } else if (eb & 1)
2984
+ r += String.fromCharCode((c & 31) << 6 | d[i++] & 63);
2985
+ else
2986
+ r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | d[i++] & 63);
2987
+ }
2988
+ };
2989
+ function strFromU8(dat, latin1) {
2990
+ if (latin1) {
2991
+ var r = "";
2992
+ for (var i = 0;i < dat.length; i += 16384)
2993
+ r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));
2994
+ return r;
2995
+ } else if (td) {
2996
+ return td.decode(dat);
2997
+ } else {
2998
+ var _a = dutf8(dat), { s, r } = _a;
2999
+ if (r.length)
3000
+ err(8);
3001
+ return s;
3002
+ }
3003
+ }
3004
+ var slzh = function(d, b) {
3005
+ return b + 30 + b2(d, b + 26) + b2(d, b + 28);
3006
+ };
3007
+ var zh = function(d, b, z) {
3008
+ 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;
3009
+ 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];
3010
+ return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off];
3011
+ };
3012
+ var z64hs = function(d, b, l, z, sc, su, off) {
3013
+ var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l;
3014
+ var nf = nsc + nsu + noff;
3015
+ if (z && nf) {
3016
+ for (;b + 4 < e; b += 4 + b2(d, b + 2)) {
3017
+ if (b2(d, b) == 1) {
3018
+ return [
3019
+ nsc ? b8(d, b + 4 + 8 * nsu) : sc,
3020
+ nsu ? b8(d, b + 4) : su,
3021
+ noff ? b8(d, b + 4 + 8 * (nsu + nsc)) : off,
3022
+ 1
3023
+ ];
3024
+ }
3025
+ }
3026
+ if (z < 2)
3027
+ err(13);
3028
+ }
3029
+ return [sc, su, off, 0];
3030
+ };
3031
+ function unzipSync(data, opts) {
3032
+ var files = {};
3033
+ var e = data.length - 22;
3034
+ for (;b4(data, e) != 101010256; --e) {
3035
+ if (!e || data.length - e > 65558)
3036
+ err(13);
3037
+ }
3038
+ var c = b2(data, e + 8);
3039
+ if (!c)
3040
+ return {};
3041
+ var o = b4(data, e + 16);
3042
+ var z = b4(data, e - 20) == 117853008;
3043
+ if (z) {
3044
+ var ze = b4(data, e - 12);
3045
+ z = b4(data, ze) == 101075792;
3046
+ if (z) {
3047
+ c = b4(data, ze + 32);
3048
+ o = b4(data, ze + 48);
3049
+ }
3050
+ }
3051
+ var fltr = opts && opts.filter;
3052
+ for (var i = 0;i < c; ++i) {
3053
+ 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);
3054
+ o = no;
3055
+ if (!fltr || fltr({
3056
+ name: fn,
3057
+ size: sc,
3058
+ originalSize: su,
3059
+ compression: c_2
3060
+ })) {
3061
+ if (!c_2)
3062
+ files[fn] = slc(data, b, b + sc);
3063
+ else if (c_2 == 8)
3064
+ files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) });
3065
+ else
3066
+ err(14, "unknown compression type " + c_2);
3067
+ }
3068
+ }
3069
+ return files;
3070
+ }
3071
+
3072
+ // packages/gateway/src/skill-market.ts
3073
+ class SkillMarketError extends Error {
3074
+ code;
3075
+ constructor(code, message) {
3076
+ super(message);
3077
+ this.name = "SkillMarketError";
3078
+ this.code = code;
3079
+ }
3080
+ }
3081
+ var CATALOG_TTL_MS = 60000;
3082
+ var ZIP_CACHE_MAX = 16;
3083
+ var MAX_PACKAGE_BYTES = 32 * 1024 * 1024;
3084
+ var userSkillsDir2 = (home) => join8(home, ".agents", "skills");
3085
+ var projectSkillsDir = (workspaceRoot) => join8(workspaceRoot, ".agents", "skills");
3086
+ var activeLevelOf = (state) => state.project ? "project" : state.user ? "user" : state.builtin ? "builtin" : null;
3087
+ var normalizeEntry = (raw) => {
3088
+ const row = raw ?? {};
3089
+ const metadata = row.metadata;
3090
+ const source = metadata !== null && typeof metadata === "object" ? metadata.source : undefined;
3091
+ return {
3092
+ name: String(row.name ?? ""),
3093
+ description: String(row.description ?? ""),
3094
+ category: typeof row.category === "string" && row.category !== "" ? row.category : "uncategorized",
3095
+ source: typeof source === "string" && source !== "" ? source : "unknown",
3096
+ license: String(row.license ?? ""),
3097
+ version: String(row.version ?? ""),
3098
+ sha256: String(row.sha256 ?? ""),
3099
+ sizeBytes: Number(row.size_bytes ?? 0),
3100
+ uploadedAt: String(row.uploaded_at ?? "")
3101
+ };
3102
+ };
3103
+ function createSkillMarketClient(options) {
3104
+ const home = options.home ?? homedir5();
3105
+ const fetchImpl = options.fetchImpl ?? fetch;
3106
+ const now = options.now ?? Date.now;
3107
+ let base;
3108
+ try {
3109
+ base = new URL(options.marketUrl);
3110
+ if (base.protocol !== "https:" && base.protocol !== "http:")
3111
+ throw new Error("unsupported protocol");
3112
+ } catch {
3113
+ throw new SkillMarketError("market_invalid_url", `Invalid skill market URL: ${options.marketUrl}`);
3114
+ }
3115
+ base = new URL(base.toString().replace(/\/+$/, ""));
3116
+ let catalog;
3117
+ const zipCache = new Map;
3118
+ const request = async (path) => {
3119
+ let response;
3120
+ try {
3121
+ response = await fetchImpl(new URL(path, `${base}/`).toString());
3122
+ } catch (error) {
3123
+ throw new SkillMarketError("market_unavailable", `Skill market unreachable: ${error instanceof Error ? error.message : String(error)}`);
3124
+ }
3125
+ return response;
3126
+ };
3127
+ const refreshCatalog = async () => {
3128
+ const response = await request("api/skills");
3129
+ if (!response.ok)
3130
+ throw new SkillMarketError("market_unavailable", `Skill list failed with HTTP ${response.status}`);
3131
+ const data = await response.json();
3132
+ const skills = Array.isArray(data.skills) ? data.skills.map(normalizeEntry) : [];
3133
+ catalog = { at: now(), skills };
3134
+ return skills;
3135
+ };
3136
+ const listSkills = async () => catalog !== undefined && now() - catalog.at < CATALOG_TTL_MS ? catalog.skills : refreshCatalog();
3137
+ const detail = async (name) => {
3138
+ let hit = (await listSkills()).find((skill) => skill.name === name);
3139
+ if (hit === undefined)
3140
+ hit = (await refreshCatalog()).find((skill) => skill.name === name);
3141
+ if (hit === undefined)
3142
+ throw new SkillMarketError("skill_not_found", `Skill not found on market: ${name}`);
3143
+ return hit;
3144
+ };
3145
+ const download = async (skill) => {
3146
+ const cached = zipCache.get(skill.sha256);
3147
+ if (cached !== undefined) {
3148
+ zipCache.delete(skill.sha256);
3149
+ zipCache.set(skill.sha256, cached);
3150
+ return cached;
3151
+ }
3152
+ if (skill.sizeBytes > MAX_PACKAGE_BYTES)
3153
+ throw new SkillMarketError("skill_too_large", `Package ${skill.name} is ${skill.sizeBytes} bytes (limit ${MAX_PACKAGE_BYTES})`);
3154
+ const response = await request(`api/skills/${encodeURIComponent(skill.name)}/download`);
3155
+ if (!response.ok)
3156
+ throw new SkillMarketError(response.status === 404 ? "skill_not_found" : "market_unavailable", `Download of ${skill.name} failed with HTTP ${response.status}`);
3157
+ const bytes = new Uint8Array(await response.arrayBuffer());
3158
+ if (bytes.byteLength > MAX_PACKAGE_BYTES)
3159
+ throw new SkillMarketError("skill_too_large", `Package ${skill.name} exceeds ${MAX_PACKAGE_BYTES} bytes`);
3160
+ const digest = createHash2("sha256").update(bytes).digest("hex");
3161
+ if (digest !== skill.sha256)
3162
+ throw new SkillMarketError("skill_hash_mismatch", `SHA-256 mismatch for ${skill.name}: catalog says ${skill.sha256}, got ${digest}`);
3163
+ zipCache.set(skill.sha256, bytes);
3164
+ while (zipCache.size > ZIP_CACHE_MAX) {
3165
+ const oldest = zipCache.keys().next().value;
3166
+ if (oldest === undefined)
3167
+ break;
3168
+ zipCache.delete(oldest);
3169
+ }
3170
+ return bytes;
3171
+ };
3172
+ const unpack = (skill, zip) => {
3173
+ let entries;
3174
+ try {
3175
+ entries = unzipSync(zip);
3176
+ } catch {
3177
+ throw new SkillMarketError("skill_invalid_package", `Package ${skill.name} is not a valid zip archive`);
3178
+ }
3179
+ const files = new Map;
3180
+ const skillMds = [];
3181
+ for (const name of Object.keys(entries)) {
3182
+ if (name.endsWith("/"))
3183
+ continue;
3184
+ if (name.includes("\\") || name.startsWith("/"))
3185
+ throw new SkillMarketError("skill_invalid_package", `Unsafe path in package: ${name}`);
3186
+ const segments = name.split("/");
3187
+ if (segments.some((s) => s === ".." || s === ""))
3188
+ throw new SkillMarketError("skill_invalid_package", `Unsafe path in package: ${name}`);
3189
+ if (segments[segments.length - 1] === "SKILL.md")
3190
+ skillMds.push(name);
3191
+ files.set(name, entries[name]);
3192
+ }
3193
+ if (skillMds.length !== 1)
3194
+ throw new SkillMarketError("skill_invalid_package", skillMds.length === 0 ? `Package ${skill.name} contains no SKILL.md` : `Package ${skill.name} contains multiple SKILL.md files`);
3195
+ const root = skillMds[0].slice(0, -"SKILL.md".length);
3196
+ const inner = new Map;
3197
+ for (const [name, bytes] of files) {
3198
+ if (!name.startsWith(root))
3199
+ continue;
3200
+ inner.set(name.slice(root.length), bytes);
3201
+ }
3202
+ return inner;
3203
+ };
3204
+ const skillsDirFor = (scope, workspaceRoot) => {
3205
+ if (scope === "user")
3206
+ return userSkillsDir2(home);
3207
+ if (workspaceRoot === undefined || workspaceRoot === "")
3208
+ throw new SkillMarketError("market_unavailable", "Project-scope install needs a workspaceRoot");
3209
+ return projectSkillsDir(workspaceRoot);
3210
+ };
3211
+ const sweepTempDirs = async (skillsDir) => {
3212
+ const parent = dirname5(skillsDir);
3213
+ let names = [];
3214
+ try {
3215
+ names = await readdir2(parent);
3216
+ } catch {
3217
+ return;
3218
+ }
3219
+ await Promise.all(names.filter((n) => n.startsWith(".tmp-")).map((n) => rm2(join8(parent, n), { recursive: true, force: true }).catch(() => {})));
3220
+ };
3221
+ const install = async ({ name, scope, workspaceRoot, overwrite }) => {
3222
+ const skillsDir = skillsDirFor(scope, workspaceRoot);
3223
+ const target = join8(skillsDir, name);
3224
+ const exists = await stat2(target).catch(() => {
3225
+ return;
3226
+ }) !== undefined;
3227
+ if (exists && overwrite !== true)
3228
+ throw new SkillMarketError("skill_exists", `Skill ${name} already exists at ${scope} level (${target})`);
3229
+ const skill = await detail(name);
3230
+ const files = unpack(skill, await download(skill));
3231
+ await sweepTempDirs(skillsDir);
3232
+ const temp = join8(dirname5(skillsDir), `.tmp-${randomUUID()}`);
3233
+ try {
3234
+ for (const [relative, bytes] of files) {
3235
+ const dest = join8(temp, ...relative.split("/"));
3236
+ await mkdir2(dirname5(dest), { recursive: true });
3237
+ await writeFile2(dest, bytes);
3238
+ }
3239
+ if (exists)
3240
+ await rm2(target, { recursive: true, force: true });
3241
+ await mkdir2(skillsDir, { recursive: true });
3242
+ await rename2(temp, target);
3243
+ } finally {
3244
+ await rm2(temp, { recursive: true, force: true }).catch(() => {});
3245
+ }
3246
+ let shadowedBy;
3247
+ if (scope === "user" && workspaceRoot !== undefined && workspaceRoot !== "") {
3248
+ const projectDir = join8(projectSkillsDir(workspaceRoot), name);
3249
+ if (await stat2(projectDir).catch(() => {
3250
+ return;
3251
+ }) !== undefined)
3252
+ shadowedBy = "project";
3253
+ }
3254
+ return { name, scope, path: target, ...shadowedBy !== undefined ? { shadowedBy } : {} };
3255
+ };
3256
+ const uninstall = async ({ name, scope, workspaceRoot }) => {
3257
+ const skillsDir = skillsDirFor(scope, workspaceRoot);
3258
+ const target = join8(skillsDir, name);
3259
+ if (await stat2(target).catch(() => {
3260
+ return;
3261
+ }) === undefined)
3262
+ throw new SkillMarketError("skill_not_installed", `Skill ${name} is not installed at ${scope} level`);
3263
+ await rm2(target, { recursive: true, force: true });
3264
+ };
3265
+ return {
3266
+ async list(query) {
3267
+ if (query !== undefined && query.trim() !== "") {
3268
+ const response = await request(`api/skills?q=${encodeURIComponent(query.trim())}`);
3269
+ if (!response.ok)
3270
+ throw new SkillMarketError("market_unavailable", `Skill search failed with HTTP ${response.status}`);
3271
+ const data = await response.json();
3272
+ return Array.isArray(data.skills) ? data.skills.map(normalizeEntry) : [];
3273
+ }
3274
+ return listSkills();
3275
+ },
3276
+ detail,
3277
+ async preview(name) {
3278
+ const skill = await detail(name);
3279
+ const inner = unpack(skill, await download(skill));
3280
+ const bodyBytes = inner.get("SKILL.md");
3281
+ if (bodyBytes === undefined)
3282
+ throw new SkillMarketError("skill_invalid_package", `Package ${name} lost its SKILL.md`);
3283
+ const body = stripFrontmatter(new TextDecoder().decode(bodyBytes));
3284
+ return { body, files: [...inner.keys()].sort() };
3285
+ },
3286
+ install,
3287
+ uninstall
3288
+ };
3289
+ }
3290
+
2609
3291
  // packages/gateway/src/workspaces.ts
2610
3292
  import { constants as constants3 } from "fs";
2611
- import { access, readdir as readdir2, stat as stat2 } from "fs/promises";
2612
- import { dirname as dirname5, isAbsolute as isAbsolute3, join as join8 } from "path";
3293
+ import { access, readdir as readdir3, stat as stat3 } from "fs/promises";
3294
+ import { dirname as dirname6, isAbsolute as isAbsolute3, join as join9 } from "path";
2613
3295
  async function browseWorkspaces(options) {
2614
3296
  const requested = options.path.replace(/^\/+([A-Za-z]:[\\/])/, "$1");
2615
3297
  if (process.platform === "win32" && (requested === "/" || requested === "\\")) {
@@ -2631,16 +3313,16 @@ async function browseWorkspaces(options) {
2631
3313
  throw new Error("\u76EE\u5F55\u5206\u9875\u5DF2\u5931\u6548\uFF0C\u8BF7\u5237\u65B0\u5217\u8868");
2632
3314
  }
2633
3315
  }
2634
- const entries = (await readdir2(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);
3316
+ 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);
2635
3317
  const directories = [];
2636
3318
  let next = offset;
2637
3319
  for (;next < entries.length && directories.length < 100; next++) {
2638
3320
  const entry = entries[next];
2639
- const target = join8(path, entry.name);
3321
+ const target = join9(path, entry.name);
2640
3322
  if (!entry.isDirectory() && !entry.isSymbolicLink())
2641
3323
  continue;
2642
3324
  try {
2643
- if (!(await stat2(target)).isDirectory())
3325
+ if (!(await stat3(target)).isDirectory())
2644
3326
  continue;
2645
3327
  await access(target, constants3.R_OK | constants3.X_OK);
2646
3328
  directories.push({ name: entry.name, path: target });
@@ -2650,7 +3332,7 @@ async function browseWorkspaces(options) {
2650
3332
  }
2651
3333
  return {
2652
3334
  path,
2653
- parent: dirname5(path) === path ? null : dirname5(path),
3335
+ parent: dirname6(path) === path ? null : dirname6(path),
2654
3336
  entries: directories,
2655
3337
  next: next < entries.length ? JSON.stringify({ key, offset: next }) : null
2656
3338
  };
@@ -2670,6 +3352,26 @@ async function listDrives() {
2670
3352
  // packages/gateway/src/server-services.ts
2671
3353
  async function createNekoServerServices(options) {
2672
3354
  const { runtime, context } = options;
3355
+ const market = createSkillMarketClient({
3356
+ marketUrl: options.marketUrl,
3357
+ ...options.promptHome !== undefined ? { home: options.promptHome } : {}
3358
+ });
3359
+ const toRemote = (error) => {
3360
+ if (error instanceof SkillMarketError) {
3361
+ const code = error.code === "skill_not_found" || error.code === "skill_not_installed" ? "service_not_found" : "service_invalid_value";
3362
+ throw new RemoteServiceError(code, `[${error.code}] ${error.message}`);
3363
+ }
3364
+ throw error;
3365
+ };
3366
+ const withInstallState = async (skill, workspaceRoot) => {
3367
+ const locals = await runtime.listSkillsByLevel(workspaceRoot);
3368
+ const installed = {
3369
+ project: locals.some((s) => s.name === skill.name && s.level === "project"),
3370
+ user: locals.some((s) => s.name === skill.name && s.level === "user"),
3371
+ builtin: locals.some((s) => s.name === skill.name && s.level === "builtin")
3372
+ };
3373
+ return { ...skill, installed, activeLevel: activeLevelOf(installed) };
3374
+ };
2673
3375
  const list = async () => (await runtime.listConversations()).map((info) => ({
2674
3376
  id: String(info.id),
2675
3377
  workspaceRoot: info.workspaceRoot,
@@ -2725,7 +3427,8 @@ async function createNekoServerServices(options) {
2725
3427
  { service: NekoModels, mode: "singleton" },
2726
3428
  { service: NekoCredentials, mode: "singleton" },
2727
3429
  { service: NekoWorkspaces, mode: "singleton" },
2728
- { service: NekoWorkspaceFiles, mode: "singleton" }
3430
+ { service: NekoWorkspaceFiles, mode: "singleton" },
3431
+ { service: NekoSkillMarket, mode: "singleton" }
2729
3432
  ]);
2730
3433
  provider.provide(NekoSessionDirectory, { state: directory });
2731
3434
  const updateCredentials = (operation) => serialize(async () => {
@@ -2775,6 +3478,13 @@ async function createNekoServerServices(options) {
2775
3478
  }
2776
3479
  });
2777
3480
  provider.provide(NekoModels, { list: async () => runtime.listModels() });
3481
+ provider.provide(NekoSkillMarket, {
3482
+ list: (input) => market.list(input.query).then((skills) => Promise.all(skills.map((skill) => withInstallState(skill, input.workspaceRoot)))).catch(toRemote),
3483
+ detail: (input) => market.detail(input.name).then((skill) => withInstallState(skill, input.workspaceRoot)).catch(toRemote),
3484
+ preview: (input) => market.preview(input.name).catch(toRemote),
3485
+ install: (input) => serialize(() => market.install(input).then((result) => ({ ...result })).catch(toRemote)),
3486
+ uninstall: (input) => serialize(() => market.uninstall(input).catch(toRemote))
3487
+ });
2778
3488
  provider.provide(NekoSessionManagement, {
2779
3489
  create: (createOptions) => serialize(async () => {
2780
3490
  const created = await runtime.createConversation(createOptions.model !== undefined || createOptions.thinkingLevel !== undefined || createOptions.cwd !== undefined ? {
@@ -3293,9 +4003,10 @@ async function startGateway(options = {}) {
3293
4003
  const storagePath = options.storagePath ?? fileConfig.storagePath ?? DEFAULT_STORAGE_PATH;
3294
4004
  const host = options.host ?? fileConfig.gateway?.host ?? DEFAULT_HOST;
3295
4005
  const port = options.port !== undefined ? options.port : fileConfig.gateway?.port ?? (process.platform === "win32" ? 0 : DEFAULT_PORT);
3296
- const nekoDir = dirname6(storagePath);
4006
+ const marketUrl = options.marketUrl ?? fileConfig.skills?.marketUrl ?? DEFAULT_SKILL_MARKET_URL;
4007
+ const nekoDir = dirname7(storagePath);
3297
4008
  const serverId = options.serverId ?? await loadOrCreateServerId(nekoDir);
3298
- const socketPath = options.socketPath !== undefined ? options.socketPath : fileConfig.gateway?.socketPath !== undefined ? fileConfig.gateway.socketPath : process.platform === "win32" ? null : join9(nekoDir, `${serverId}.sock`);
4009
+ const socketPath = options.socketPath !== undefined ? options.socketPath : fileConfig.gateway?.socketPath !== undefined ? fileConfig.gateway.socketPath : process.platform === "win32" ? null : join10(nekoDir, `${serverId}.sock`);
3299
4010
  const runtime = await createNekoRuntime({
3300
4011
  context,
3301
4012
  storage: options.storage ?? "sqlite",
@@ -3318,6 +4029,8 @@ async function startGateway(options = {}) {
3318
4029
  serverId,
3319
4030
  nekoDir,
3320
4031
  model,
4032
+ marketUrl,
4033
+ promptHome: options.promptHome,
3321
4034
  onError: options.onError
3322
4035
  });
3323
4036
  } catch (error) {
@@ -3328,7 +4041,12 @@ async function startGateway(options = {}) {
3328
4041
  async function bindGateway(runtime, options) {
3329
4042
  const { context, host, port, socketPath, serverId, nekoDir, model } = options;
3330
4043
  const modelLabel = `${model.provider}/${model.modelId}`;
3331
- const serverServices = await createNekoServerServices({ runtime, context });
4044
+ const serverServices = await createNekoServerServices({
4045
+ runtime,
4046
+ context,
4047
+ marketUrl: options.marketUrl,
4048
+ ...options.promptHome !== undefined ? { promptHome: options.promptHome } : {}
4049
+ });
3332
4050
  let wsListener;
3333
4051
  const listeners = [];
3334
4052
  if (socketPath !== null) {
@@ -3406,15 +4124,15 @@ function serverIdFromSocketPath(socketPath) {
3406
4124
  return isServerId(candidate) ? candidate : undefined;
3407
4125
  }
3408
4126
  async function loadOrCreateServerId(nekoDir) {
3409
- const file = join9(nekoDir, SERVER_ID_FILENAME);
4127
+ const file = join10(nekoDir, SERVER_ID_FILENAME);
3410
4128
  try {
3411
4129
  const existing = (await readFile5(file, "utf8")).trim();
3412
4130
  if (existing !== "")
3413
4131
  return existing;
3414
4132
  } catch {}
3415
- const created = randomUUID();
3416
- await mkdir2(nekoDir, { recursive: true, mode: 448 });
3417
- await writeFile2(file, `${created}
4133
+ const created = randomUUID2();
4134
+ await mkdir3(nekoDir, { recursive: true, mode: 448 });
4135
+ await writeFile3(file, `${created}
3418
4136
  `, { mode: 384 });
3419
4137
  return created;
3420
4138
  }