neko-harness 0.1.0 → 0.2.0

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.
@@ -9,8 +9,8 @@
9
9
  href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' rx='26' fill='%23ffb7c5'/%3E%3Ctext x='50' y='70' font-size='58' text-anchor='middle' fill='%23ffffff' font-family='sans-serif' font-weight='bold'%3En%3C/text%3E%3C/svg%3E"
10
10
  />
11
11
  <title>neko harness</title>
12
- <script type="module" crossorigin src="/assets/index-B1I59uXv.js"></script>
13
- <link rel="stylesheet" crossorigin href="/assets/index-U3kl-2BJ.css">
12
+ <script type="module" crossorigin src="/assets/index-D6NpJLXy.js"></script>
13
+ <link rel="stylesheet" crossorigin href="/assets/index-CxnbrvVk.css">
14
14
  </head>
15
15
  <body>
16
16
  <div id="root"></div>
package/dist/gateway.js CHANGED
@@ -1,10 +1,113 @@
1
1
  #!/usr/bin/env bun
2
2
  // @bun
3
3
 
4
+ // packages/gateway/src/cli-args.ts
5
+ var GATEWAY_USAGE = `\u7528\u6CD5: main.ts [\u9009\u9879]
6
+
7
+ \u9009\u9879:
8
+ --host <ip> WebSocket \u76D1\u542C\u5730\u5740\uFF08\u9ED8\u8BA4 127.0.0.1\uFF0C\u4EC5\u672C\u673A\uFF09
9
+ --port <n> WebSocket \u76D1\u542C\u7AEF\u53E3\uFF08\u9ED8\u8BA4 8321\uFF0CWindows \u9ED8\u8BA4\u968F\u673A\uFF1B0/null \u7981\u7528 WS\uFF09
10
+ --socket-path <path> Unix socket \u8DEF\u5F84\uFF08\u9ED8\u8BA4 <\u6570\u636E\u76EE\u5F55>/<serverId>.sock\uFF1BWindows \u9ED8\u8BA4\u7981\u7528\uFF09
11
+ --no-socket \u7981\u7528 Unix socket \u4F20\u8F93\uFF08\u4EC5 WebSocket\uFF09
12
+ --server-id <id> \u903B\u8F91\u670D\u52A1\u5668\u8EAB\u4EFD\uFF08\u9ED8\u8BA4\u8BFB\u53D6/\u751F\u6210 <\u6570\u636E\u76EE\u5F55>/gateway-server-id\uFF09
13
+ --cwd <dir> \u4F1A\u8BDD\u5DE5\u5177\u7684\u5DE5\u4F5C\u76EE\u5F55\uFF08\u9ED8\u8BA4\u5F53\u524D\u76EE\u5F55\uFF09
14
+ --model <ref> \u6A21\u578B\uFF0C\u683C\u5F0F provider/modelId\uFF08\u9ED8\u8BA4 deepseek/deepseek-flash\uFF09
15
+ --storage <path> SQLite \u5B58\u50A8\u6587\u4EF6\uFF08\u9ED8\u8BA4 ~/.neko/neko.sqlite\uFF09
16
+ --credentials <path> \u7528\u6237\u51ED\u636E\u6587\u4EF6\uFF08\u9ED8\u8BA4 ~/.neko/credentials.json\uFF09
17
+ --config <dir> neko.config.json \u67E5\u627E\u8D77\u59CB\u76EE\u5F55\uFF08\u9ED8\u8BA4\u5F53\u524D\u76EE\u5F55\uFF09
18
+ -h, --help \u663E\u793A\u6B64\u5E2E\u52A9
19
+
20
+ \u53EF\u901A\u8FC7\u524D\u7AEF\u8BBE\u7F6E\u6216 DEEPSEEK_API_KEY \u914D\u7F6E\u51ED\u636E\u3002`;
21
+ function parseGatewayArgs(argv) {
22
+ let port;
23
+ const options = {};
24
+ for (let i = 0;i < argv.length; i++) {
25
+ const arg = argv[i];
26
+ const next = argv[i + 1];
27
+ switch (arg) {
28
+ case "--host":
29
+ if (next === undefined)
30
+ throw new Error("--host \u9700\u8981\u53C2\u6570");
31
+ options.host = next;
32
+ i++;
33
+ break;
34
+ case "--port": {
35
+ if (next === undefined)
36
+ throw new Error("--port \u9700\u8981\u53C2\u6570");
37
+ if (next === "0" || next === "null") {
38
+ port = null;
39
+ } else {
40
+ const parsed = Number(next);
41
+ if (!Number.isInteger(parsed) || parsed < 0 || parsed > 65535) {
42
+ throw new Error(`--port \u9700\u8981 0-65535 \u7684\u6574\u6570: ${next}`);
43
+ }
44
+ port = parsed;
45
+ }
46
+ i++;
47
+ break;
48
+ }
49
+ case "--socket-path":
50
+ if (next === undefined)
51
+ throw new Error("--socket-path \u9700\u8981\u53C2\u6570");
52
+ options.socketPath = next;
53
+ i++;
54
+ break;
55
+ case "--no-socket":
56
+ options.socketPath = null;
57
+ break;
58
+ case "--server-id":
59
+ if (next === undefined)
60
+ throw new Error("--server-id \u9700\u8981\u53C2\u6570");
61
+ options.serverId = next;
62
+ i++;
63
+ break;
64
+ case "--cwd":
65
+ if (next === undefined)
66
+ throw new Error("--cwd \u9700\u8981\u53C2\u6570");
67
+ options.cwd = next;
68
+ i++;
69
+ break;
70
+ case "--model": {
71
+ if (next === undefined)
72
+ throw new Error("--model \u9700\u8981\u53C2\u6570");
73
+ const slash = next.indexOf("/");
74
+ if (slash <= 0 || slash === next.length - 1)
75
+ throw new Error(`--model \u683C\u5F0F\u4E3A provider/modelId: ${next}`);
76
+ options.model = { provider: next.slice(0, slash), modelId: next.slice(slash + 1) };
77
+ i++;
78
+ break;
79
+ }
80
+ case "--credentials":
81
+ if (next === undefined)
82
+ throw new Error("--credentials \u9700\u8981\u53C2\u6570");
83
+ options.credentialsPath = next;
84
+ i++;
85
+ break;
86
+ case "--storage":
87
+ if (next === undefined)
88
+ throw new Error("--storage \u9700\u8981\u53C2\u6570");
89
+ options.storagePath = next;
90
+ i++;
91
+ break;
92
+ case "--config":
93
+ if (next === undefined)
94
+ throw new Error("--config \u9700\u8981\u53C2\u6570");
95
+ options.configDir = next;
96
+ i++;
97
+ break;
98
+ default:
99
+ throw new Error(`\u672A\u77E5\u9009\u9879: ${arg}`);
100
+ }
101
+ }
102
+ if (port !== undefined)
103
+ options.port = port;
104
+ return options;
105
+ }
106
+
4
107
  // packages/gateway/src/gateway.ts
5
108
  import { randomUUID } from "crypto";
6
- import { mkdir as mkdir2, readFile as readFile4, writeFile } from "fs/promises";
7
- import { basename as basename4, dirname as dirname6, join as join8 } from "path";
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";
8
111
  import { BACKGROUND_CONTEXT as BACKGROUND_CONTEXT2 } from "@earendil-works/chord/context";
9
112
  import { isServerId } from "@earendil-works/pi-protocol";
10
113
  import { Server, SessionNotFoundError } from "@earendil-works/pi-server";
@@ -217,8 +320,8 @@ function validate(config, source) {
217
320
  if (port !== undefined && (!Number.isInteger(port) || port < 0 || port > 65535)) {
218
321
  throw new Error(`neko config: ${source}: "gateway.port" must be an integer between 0 and 65535.`);
219
322
  }
220
- if (socketPath !== undefined && typeof socketPath !== "string") {
221
- throw new Error(`neko config: ${source}: "gateway.socketPath" must be a string.`);
323
+ if (socketPath !== undefined && socketPath !== null && typeof socketPath !== "string") {
324
+ throw new Error(`neko config: ${source}: "gateway.socketPath" must be a string or null.`);
222
325
  }
223
326
  }
224
327
  const theme = config.theme;
@@ -1897,7 +2000,10 @@ async function createNekoRuntime(options = {}) {
1897
2000
  conversationCreated: async (tx, record) => {
1898
2001
  (await tx.doc(SessionMetadataDoc, record.id)).createdAt = Date.now();
1899
2002
  },
1900
- env: ({ cwd }) => new NodeExecutionEnv({ cwd: executionWorkspace(cwd) })
2003
+ env: ({ cwd }) => new NodeExecutionEnv({
2004
+ cwd: executionWorkspace(cwd),
2005
+ ...process.platform === "win32" ? { shellEnv: { PYTHONIOENCODING: "utf-8", PYTHONUTF8: "1" } } : {}
2006
+ })
1901
2007
  }, context);
1902
2008
  const scanConversations = () => harness.commit(async (tx) => {
1903
2009
  const records = [];
@@ -2323,6 +2429,20 @@ async function createNekoRuntime(options = {}) {
2323
2429
  }
2324
2430
  };
2325
2431
  }
2432
+ // packages/gateway/src/port-file.ts
2433
+ import { readFile as readFile4, rm, writeFile } from "fs/promises";
2434
+ import { join as join6 } from "path";
2435
+ function gatewayPortFilePath(nekoDir, serverId) {
2436
+ return join6(nekoDir, `${serverId}.port`);
2437
+ }
2438
+ async function writeGatewayPortFile(nekoDir, serverId, wsUrl) {
2439
+ await writeFile(gatewayPortFilePath(nekoDir, serverId), `${wsUrl}
2440
+ `, { mode: 384 });
2441
+ }
2442
+ async function removeGatewayPortFile(nekoDir, serverId) {
2443
+ await rm(gatewayPortFilePath(nekoDir, serverId), { force: true });
2444
+ }
2445
+
2326
2446
  // packages/gateway/src/server-services.ts
2327
2447
  import {
2328
2448
  createRemoteServiceEndpoint,
@@ -2334,13 +2454,13 @@ import {
2334
2454
  import { spawn } from "child_process";
2335
2455
  import { accessSync as accessSync2, constants as constants2 } from "fs";
2336
2456
  import { realpath, stat } from "fs/promises";
2337
- import { basename as basename2, delimiter, isAbsolute as isAbsolute2, join as join6, relative, resolve as resolve4, sep } from "path";
2457
+ import { basename as basename2, delimiter, isAbsolute as isAbsolute2, join as join7, relative, resolve as resolve4, sep } from "path";
2338
2458
  function findFd() {
2339
2459
  for (const name of process.platform === "win32" ? ["fd.exe", "fdfind.exe"] : ["fd", "fdfind"]) {
2340
2460
  for (const directory of (process.env.PATH ?? "").split(delimiter)) {
2341
2461
  if (!directory)
2342
2462
  continue;
2343
- const path = join6(directory, name);
2463
+ const path = join7(directory, name);
2344
2464
  try {
2345
2465
  accessSync2(path, constants2.X_OK);
2346
2466
  return path;
@@ -2459,11 +2579,15 @@ var NekoWorkspaceFiles = defineService("neko.workspace-files");
2459
2579
  // packages/gateway/src/workspaces.ts
2460
2580
  import { constants as constants3 } from "fs";
2461
2581
  import { access, readdir as readdir2, stat as stat2 } from "fs/promises";
2462
- import { dirname as dirname5, isAbsolute as isAbsolute3, join as join7 } from "path";
2582
+ import { dirname as dirname5, isAbsolute as isAbsolute3, join as join8 } from "path";
2463
2583
  async function browseWorkspaces(options) {
2464
- if (!isAbsolute3(options.path))
2584
+ const requested = options.path.replace(/^\/+([A-Za-z]:[\\/])/, "$1");
2585
+ if (process.platform === "win32" && (requested === "/" || requested === "\\")) {
2586
+ return { path: "/", parent: null, entries: await listDrives(), next: null };
2587
+ }
2588
+ if (!isAbsolute3(requested))
2465
2589
  throw new Error("\u8BF7\u9009\u62E9\u5B8C\u6574\u7684\u7EDD\u5BF9\u76EE\u5F55\u8DEF\u5F84");
2466
- const path = accessibleWorkspace(options.path);
2590
+ const path = accessibleWorkspace(requested);
2467
2591
  const query = options.query?.toLowerCase() ?? "";
2468
2592
  const key = JSON.stringify([path, query, options.showHidden === true]);
2469
2593
  let offset = 0;
@@ -2482,7 +2606,7 @@ async function browseWorkspaces(options) {
2482
2606
  let next = offset;
2483
2607
  for (;next < entries.length && directories.length < 100; next++) {
2484
2608
  const entry = entries[next];
2485
- const target = join7(path, entry.name);
2609
+ const target = join8(path, entry.name);
2486
2610
  if (!entry.isDirectory() && !entry.isSymbolicLink())
2487
2611
  continue;
2488
2612
  try {
@@ -2501,6 +2625,17 @@ async function browseWorkspaces(options) {
2501
2625
  next: next < entries.length ? JSON.stringify({ key, offset: next }) : null
2502
2626
  };
2503
2627
  }
2628
+ async function listDrives() {
2629
+ const drives = [];
2630
+ for (const letter of "ABCDEFGHIJKLMNOPQRSTUVWXYZ") {
2631
+ const root = `${letter}:\\`;
2632
+ try {
2633
+ await access(root);
2634
+ drives.push({ name: `${letter}:`, path: root });
2635
+ } catch {}
2636
+ }
2637
+ return drives;
2638
+ }
2504
2639
 
2505
2640
  // packages/gateway/src/server-services.ts
2506
2641
  async function createNekoServerServices(options) {
@@ -3123,10 +3258,10 @@ async function startGateway(options = {}) {
3123
3258
  const model = options.model ?? fileConfig.defaultModel ?? DEFAULT_MODEL;
3124
3259
  const storagePath = options.storagePath ?? fileConfig.storagePath ?? DEFAULT_STORAGE_PATH;
3125
3260
  const host = options.host ?? fileConfig.gateway?.host ?? DEFAULT_HOST;
3126
- const port = options.port !== undefined ? options.port : fileConfig.gateway?.port ?? DEFAULT_PORT;
3261
+ const port = options.port !== undefined ? options.port : fileConfig.gateway?.port ?? (process.platform === "win32" ? 0 : DEFAULT_PORT);
3127
3262
  const nekoDir = dirname6(storagePath);
3128
3263
  const serverId = options.serverId ?? await loadOrCreateServerId(nekoDir);
3129
- const socketPath = options.socketPath !== undefined ? options.socketPath : fileConfig.gateway?.socketPath ?? join8(nekoDir, `${serverId}.sock`);
3264
+ const socketPath = options.socketPath !== undefined ? options.socketPath : fileConfig.gateway?.socketPath !== undefined ? fileConfig.gateway.socketPath : process.platform === "win32" ? null : join9(nekoDir, `${serverId}.sock`);
3130
3265
  const runtime = await createNekoRuntime({
3131
3266
  context,
3132
3267
  storage: options.storage ?? "sqlite",
@@ -3147,6 +3282,7 @@ async function startGateway(options = {}) {
3147
3282
  port,
3148
3283
  socketPath,
3149
3284
  serverId,
3285
+ nekoDir,
3150
3286
  model,
3151
3287
  onError: options.onError
3152
3288
  });
@@ -3156,7 +3292,7 @@ async function startGateway(options = {}) {
3156
3292
  }
3157
3293
  }
3158
3294
  async function bindGateway(runtime, options) {
3159
- const { context, host, port, socketPath, serverId, model } = options;
3295
+ const { context, host, port, socketPath, serverId, nekoDir, model } = options;
3160
3296
  const modelLabel = `${model.provider}/${model.modelId}`;
3161
3297
  const serverServices = await createNekoServerServices({ runtime, context });
3162
3298
  let wsListener;
@@ -3189,6 +3325,10 @@ async function bindGateway(runtime, options) {
3189
3325
  await serverServices.dispose().catch(() => {});
3190
3326
  throw toStartupError(error, { socketPath, port, host, serverId });
3191
3327
  }
3328
+ const portFile = process.platform === "win32" && wsListener !== undefined ? { nekoDir, serverId } : undefined;
3329
+ if (portFile !== undefined && wsListener !== undefined) {
3330
+ await writeGatewayPortFile(portFile.nekoDir, portFile.serverId, `ws://${host}:${wsListener.port}`);
3331
+ }
3192
3332
  let closed = false;
3193
3333
  return {
3194
3334
  serverId,
@@ -3200,6 +3340,8 @@ async function bindGateway(runtime, options) {
3200
3340
  if (closed)
3201
3341
  return;
3202
3342
  closed = true;
3343
+ if (portFile !== undefined)
3344
+ await removeGatewayPortFile(portFile.nekoDir, portFile.serverId).catch(() => {});
3203
3345
  await server.close();
3204
3346
  await serverServices.dispose();
3205
3347
  await runtime.close();
@@ -3209,7 +3351,8 @@ async function bindGateway(runtime, options) {
3209
3351
  function toStartupError(error, info) {
3210
3352
  const message = error instanceof Error ? error.message : String(error);
3211
3353
  const existingServerId = info.socketPath === null ? undefined : serverIdFromSocketPath(info.socketPath);
3212
- const connectHint = existingServerId !== undefined ? `\u5982\u9700\u8FDE\u63A5\u5DF2\u6709\u5B9E\u4F8B\uFF1AUnix socket ${info.socketPath}\uFF08serverId: ${existingServerId}\uFF09\uFF0C\u6216\u505C\u6389\u5360\u7528\u65B9\u540E\u91CD\u8BD5\u3002` : `\u5982\u9700\u8FDE\u63A5\u5DF2\u6709\u5B9E\u4F8B\uFF1AUnix socket ${info.socketPath ?? "\uFF08\u672A\u542F\u7528\uFF09"}\uFF0C\u6216\u505C\u6389\u5360\u7528\u65B9\u540E\u91CD\u8BD5\u3002`;
3354
+ const existingAddress = info.socketPath !== null ? `Unix socket ${info.socketPath}${existingServerId !== undefined ? `\uFF08serverId: ${existingServerId}\uFF09` : ""}` : process.platform === "win32" ? `\u7AEF\u53E3\u6587\u4EF6 <\u6570\u636E\u76EE\u5F55>/${info.serverId}.port \u4E2D\u7684 ws \u5730\u5740` : "Unix socket\uFF08\u672A\u542F\u7528\uFF09";
3355
+ const connectHint = `\u5982\u9700\u8FDE\u63A5\u5DF2\u6709\u5B9E\u4F8B\uFF1A${existingAddress}\uFF0C\u6216\u505C\u6389\u5360\u7528\u65B9\u540E\u91CD\u8BD5\u3002`;
3213
3356
  if (message.includes("already running")) {
3214
3357
  return new Error(`neko gateway \u542F\u52A8\u5931\u8D25\uFF1A${message}
3215
3358
  \u8BE5\u5730\u5740\u5DF2\u88AB\u4E00\u4E2A\u6D3B\u8DC3\u7F51\u5173\u5360\u7528\uFF0C\u4E0D\u80FD\u542F\u52A8\u7B2C\u4E8C\u4E2A\u5B9E\u4F8B\u3002
@@ -3229,123 +3372,26 @@ function serverIdFromSocketPath(socketPath) {
3229
3372
  return isServerId(candidate) ? candidate : undefined;
3230
3373
  }
3231
3374
  async function loadOrCreateServerId(nekoDir) {
3232
- const file = join8(nekoDir, SERVER_ID_FILENAME);
3375
+ const file = join9(nekoDir, SERVER_ID_FILENAME);
3233
3376
  try {
3234
- const existing = (await readFile4(file, "utf8")).trim();
3377
+ const existing = (await readFile5(file, "utf8")).trim();
3235
3378
  if (existing !== "")
3236
3379
  return existing;
3237
3380
  } catch {}
3238
3381
  const created = randomUUID();
3239
3382
  await mkdir2(nekoDir, { recursive: true, mode: 448 });
3240
- await writeFile(file, `${created}
3383
+ await writeFile2(file, `${created}
3241
3384
  `, { mode: 384 });
3242
3385
  return created;
3243
3386
  }
3244
3387
 
3245
3388
  // packages/gateway/src/main.ts
3246
- var USAGE = `\u7528\u6CD5: main.ts [\u9009\u9879]
3247
-
3248
- \u9009\u9879:
3249
- --host <ip> WebSocket \u76D1\u542C\u5730\u5740\uFF08\u9ED8\u8BA4 127.0.0.1\uFF0C\u4EC5\u672C\u673A\uFF1B0/null \u7981\u7528 WS\uFF09
3250
- --port <n> WebSocket \u76D1\u542C\u7AEF\u53E3\uFF08\u9ED8\u8BA4 8321\uFF1B0 = \u968F\u673A\u5206\u914D\uFF09
3251
- --socket-path <path> Unix socket \u8DEF\u5F84\uFF08\u9ED8\u8BA4 <\u6570\u636E\u76EE\u5F55>/<serverId>.sock\uFF09
3252
- --server-id <id> \u903B\u8F91\u670D\u52A1\u5668\u8EAB\u4EFD\uFF08\u9ED8\u8BA4\u8BFB\u53D6/\u751F\u6210 <\u6570\u636E\u76EE\u5F55>/gateway-server-id\uFF09
3253
- --cwd <dir> \u4F1A\u8BDD\u5DE5\u5177\u7684\u5DE5\u4F5C\u76EE\u5F55\uFF08\u9ED8\u8BA4\u5F53\u524D\u76EE\u5F55\uFF09
3254
- --model <ref> \u6A21\u578B\uFF0C\u683C\u5F0F provider/modelId\uFF08\u9ED8\u8BA4 deepseek/deepseek-flash\uFF09
3255
- --storage <path> SQLite \u5B58\u50A8\u6587\u4EF6\uFF08\u9ED8\u8BA4 ~/.neko/neko.sqlite\uFF09
3256
- --credentials <path> \u7528\u6237\u51ED\u636E\u6587\u4EF6\uFF08\u9ED8\u8BA4 ~/.neko/credentials.json\uFF09
3257
- --config <dir> neko.config.json \u67E5\u627E\u8D77\u59CB\u76EE\u5F55\uFF08\u9ED8\u8BA4\u5F53\u524D\u76EE\u5F55\uFF09
3258
- -h, --help \u663E\u793A\u6B64\u5E2E\u52A9
3259
-
3260
- \u53EF\u901A\u8FC7\u524D\u7AEF\u8BBE\u7F6E\u6216 DEEPSEEK_API_KEY \u914D\u7F6E\u51ED\u636E\u3002`;
3261
- function parseArgs(argv) {
3262
- let port;
3263
- const options = {};
3264
- for (let i = 0;i < argv.length; i++) {
3265
- const arg = argv[i];
3266
- const next = argv[i + 1];
3267
- switch (arg) {
3268
- case "--host":
3269
- if (next === undefined)
3270
- throw new Error("--host \u9700\u8981\u53C2\u6570");
3271
- options.host = next;
3272
- i++;
3273
- break;
3274
- case "--port": {
3275
- if (next === undefined)
3276
- throw new Error("--port \u9700\u8981\u53C2\u6570");
3277
- if (next === "0" || next === "null") {
3278
- port = null;
3279
- } else {
3280
- const parsed = Number(next);
3281
- if (!Number.isInteger(parsed) || parsed < 0 || parsed > 65535) {
3282
- throw new Error(`--port \u9700\u8981 0-65535 \u7684\u6574\u6570: ${next}`);
3283
- }
3284
- port = parsed;
3285
- }
3286
- i++;
3287
- break;
3288
- }
3289
- case "--socket-path":
3290
- if (next === undefined)
3291
- throw new Error("--socket-path \u9700\u8981\u53C2\u6570");
3292
- options.socketPath = next;
3293
- i++;
3294
- break;
3295
- case "--server-id":
3296
- if (next === undefined)
3297
- throw new Error("--server-id \u9700\u8981\u53C2\u6570");
3298
- options.serverId = next;
3299
- i++;
3300
- break;
3301
- case "--cwd":
3302
- if (next === undefined)
3303
- throw new Error("--cwd \u9700\u8981\u53C2\u6570");
3304
- options.cwd = next;
3305
- i++;
3306
- break;
3307
- case "--model": {
3308
- if (next === undefined)
3309
- throw new Error("--model \u9700\u8981\u53C2\u6570");
3310
- const slash = next.indexOf("/");
3311
- if (slash <= 0 || slash === next.length - 1)
3312
- throw new Error(`--model \u683C\u5F0F\u4E3A provider/modelId: ${next}`);
3313
- options.model = { provider: next.slice(0, slash), modelId: next.slice(slash + 1) };
3314
- i++;
3315
- break;
3316
- }
3317
- case "--credentials":
3318
- if (next === undefined)
3319
- throw new Error("--credentials \u9700\u8981\u53C2\u6570");
3320
- options.credentialsPath = next;
3321
- i++;
3322
- break;
3323
- case "--storage":
3324
- if (next === undefined)
3325
- throw new Error("--storage \u9700\u8981\u53C2\u6570");
3326
- options.storagePath = next;
3327
- i++;
3328
- break;
3329
- case "--config":
3330
- if (next === undefined)
3331
- throw new Error("--config \u9700\u8981\u53C2\u6570");
3332
- options.configDir = next;
3333
- i++;
3334
- break;
3335
- case "-h":
3336
- case "--help":
3337
- console.log(USAGE);
3338
- process.exit(0);
3339
- break;
3340
- default:
3341
- throw new Error(`\u672A\u77E5\u9009\u9879: ${arg}`);
3342
- }
3343
- }
3344
- if (port !== undefined)
3345
- options.port = port;
3346
- return options;
3389
+ var argv = process.argv.slice(2);
3390
+ if (argv.includes("-h") || argv.includes("--help")) {
3391
+ console.log(GATEWAY_USAGE);
3392
+ process.exit(0);
3347
3393
  }
3348
- var options = parseArgs(process.argv.slice(2));
3394
+ var options = parseGatewayArgs(argv);
3349
3395
  var gateway = await startGateway({
3350
3396
  ...options,
3351
3397
  onError: (error) => console.error("gateway error:", error.message)