@skylandnpm/octopus-proxy 0.1.4 → 0.1.5

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/README.md CHANGED
@@ -17,6 +17,15 @@ octopus-proxy onboard
17
17
 
18
18
  添加授权项目时,填写项目 ID 后会询问是否继续添加;直接回车即可结束添加并继续保存配置。
19
19
 
20
+ 如果旧配置中的项目 ID 重复或有错误项,先列出项目,再按序号删除指定项。此命令直接读取原始配置,因此配置校验失败时也能使用;删除前会生成仅当前用户可读的备份。清理完成后检查配置并重启服务:
21
+
22
+ ```sh
23
+ octopus-proxy projects
24
+ octopus-proxy projects --remove 2
25
+ octopus-proxy doctor
26
+ octopus-proxy restart
27
+ ```
28
+
20
29
  Claw 打开机器人工作区时会通过 Hub 向 Proxy 发送只读 `runtime.snapshot` 命令。响应包含当前运行状态、Hub 和工具设置、授权项目路径,以及工具可提供的模型信息;机器人 Secret、工具密码和提供商凭据不会返回。工作区的“Proxy 信息”按钮可查看这些内容。
21
30
 
22
31
  ## Pi agent
@@ -11645,7 +11645,7 @@ async function loadConfig(path) {
11645
11645
  const local = new URL(config.tool.baseUrl);
11646
11646
  if (!["127.0.0.1", "localhost", "[::1]"].includes(local.hostname) || local.protocol !== "http:") throw new Error("OpenCode must be an HTTP loopback endpoint");
11647
11647
  }
11648
- if (new Set(config.projects.map((p) => p.id)).size !== config.projects.length) throw new Error("Project ids must be unique");
11648
+ if (new Set(config.projects.map((p) => p.id)).size !== config.projects.length) throw new Error("\u9879\u76EE ID \u91CD\u590D\uFF1B\u8FD0\u884C octopus-proxy projects \u67E5\u770B\u9879\u76EE\uFF0C\u518D\u7528 projects --remove <\u5E8F\u53F7> \u5220\u9664\u9519\u8BEF\u9879");
11649
11649
  return config;
11650
11650
  } catch (error) {
11651
11651
  if (error instanceof ConfigError) throw error;
package/dist/cli.js CHANGED
@@ -17,7 +17,7 @@ import {
17
17
  runDaemon,
18
18
  supportedPlatform,
19
19
  systemdUnitPath
20
- } from "./chunk-3TRTDBUO.js";
20
+ } from "./chunk-JWIM27KY.js";
21
21
 
22
22
  // src/cli.ts
23
23
  import { spawn } from "node:child_process";
@@ -454,7 +454,8 @@ var validUrl = (value) => {
454
454
  return "\u8BF7\u8F93\u5165\u5408\u6CD5 URL\uFF0C\u4F8B\u5982 https://hub.example.com";
455
455
  }
456
456
  };
457
- var validId = (value) => /^[a-zA-Z0-9_-]+$/.test(value) ? void 0 : "\u4EC5\u9650\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\u548C\u8FDE\u5B57\u7B26";
457
+ var validId = (value) => !value ? "\u9879\u76EE ID \u4E0D\u80FD\u4E3A\u7A7A" : /^[a-zA-Z0-9_-]+$/.test(value) ? void 0 : "\u4EC5\u9650\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\u548C\u8FDE\u5B57\u7B26";
458
+ var validateProjectId = (value, previousProjects) => validId(value) ?? (previousProjects.some((project) => project.id === value) ? `\u9879\u76EE ID\u300C${value}\u300D\u5DF2\u5B58\u5728\uFF0C\u8BF7\u8F93\u5165\u5176\u4ED6 ID` : void 0);
458
459
  var validBotId = (value) => /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value) ? void 0 : "\u8BF7\u8F93\u5165\u673A\u5668\u4EBA UUID";
459
460
  var run5 = promisify5(execFile5);
460
461
  var MACOS_TOOL_EXAMPLES = {
@@ -509,7 +510,7 @@ async function runOnboard(opts) {
509
510
  console.log(` \u5DF2\u786E\u8BA4 ${descriptor.label} \u547D\u4EE4\u53EF\u6267\u884C\uFF1A${toolCommand}`);
510
511
  if (toolKind === "opencode") mode = await ask(rl, "OpenCode \u6A21\u5F0F\uFF08managed=\u7531\u4EE3\u7406\u6258\u7BA1\u542F\u52A8\uFF0Cexternal=\u4EC5\u8FDE\u63A5\u5DF2\u6709\u670D\u52A1\uFF09", { default: mode, validate: (value) => value === "managed" || value === "external" ? void 0 : "\u8F93\u5165 managed \u6216 external" });
511
512
  if (projects.length) console.log("\n\u5DF2\u6709\u6388\u6743\u9879\u76EE\uFF08\u76F4\u63A5\u56DE\u8F66\u4FDD\u7559\u5404\u9879\uFF09\uFF1A");
512
- for (const project of projects) {
513
+ for (const [index, project] of projects.entries()) {
513
514
  project.name = await ask(rl, " \u9879\u76EE\u540D\u79F0", { default: project.name });
514
515
  for (; ; ) {
515
516
  project.directory = expandHome(await ask(rl, ` \u300C${project.name}\u300D\u76EE\u5F55\uFF08\u7EDD\u5BF9\u8DEF\u5F84\uFF09`, { default: project.directory }));
@@ -523,7 +524,7 @@ async function runOnboard(opts) {
523
524
  }
524
525
  break;
525
526
  }
526
- project.id = await ask(rl, " \u9879\u76EE ID", { default: project.id ?? slug(project.name), validate: validId });
527
+ project.id = await ask(rl, " \u9879\u76EE ID", { default: project.id ?? slug(project.name), validate: (value) => validateProjectId(value, projects.slice(0, index)) });
527
528
  }
528
529
  console.log("\n\u6DFB\u52A0\u6388\u6743\u9879\u76EE\uFF08\u540D\u79F0\u7559\u7A7A\u7ED3\u675F\uFF09\uFF1A");
529
530
  for (; ; ) {
@@ -542,7 +543,7 @@ async function runOnboard(opts) {
542
543
  }
543
544
  break;
544
545
  }
545
- const id = await ask(rl, " \u9879\u76EE ID", { default: slug(name), validate: validId });
546
+ const id = await ask(rl, " \u9879\u76EE ID", { default: slug(name), validate: (value) => validateProjectId(value, projects) });
546
547
  projects.push({ id, name, directory });
547
548
  const addMore = await ask(rl, " \u7EE7\u7EED\u6DFB\u52A0\u66F4\u591A\u6388\u6743\u9879\u76EE\uFF1F(y/N)", {
548
549
  default: "n",
@@ -566,6 +567,11 @@ async function runOnboard(opts) {
566
567
  projects = projects.map((project) => ({ ...project, id: project.id ?? slug(project.name) }));
567
568
  const invalid = projects.find((project) => validId(project.id ?? "") !== void 0);
568
569
  if (invalid) throw new Error(`\u9879\u76EE\u300C${invalid.name}\u300D\u65E0\u6CD5\u63A8\u5BFC\u51FA\u5408\u6CD5 ID\uFF08\u4EC5\u9650\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u4E0B\u5212\u7EBF\u548C\u8FDE\u5B57\u7B26\uFF09\uFF0C\u8BF7\u8C03\u6574\u540D\u79F0\u6216\u624B\u5DE5\u6307\u5B9A ID`);
570
+ const seenIds = /* @__PURE__ */ new Set();
571
+ for (const project of projects) {
572
+ if (seenIds.has(project.id)) throw new Error(`\u9879\u76EE ID\u300C${project.id}\u300D\u91CD\u590D\uFF0C\u8BF7\u8C03\u6574\u9879\u76EE\u540D\u79F0\u6216\u624B\u5DE5\u6307\u5B9A\u4E0D\u540C ID`);
573
+ seenIds.add(project.id);
574
+ }
569
575
  if (projects.some((project) => !isAbsolute3(project.directory))) throw new Error("--project \u7684\u76EE\u5F55\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84");
570
576
  const descriptor = describeTool(toolKind);
571
577
  toolCommand = toolCommand ? expandHome(toolCommand) : await resolveCommandOnPath(toolKind, toolSearchDirs(toolKind)) ?? descriptor.defaultCommand;
@@ -619,6 +625,48 @@ async function runOnboard(opts) {
619
625
  } else console.log("\u5DF2\u8DF3\u8FC7\u670D\u52A1\u5B89\u88C5\uFF1B\u4E4B\u540E\u53EF\u8FD0\u884C octopus-proxy install");
620
626
  }
621
627
 
628
+ // src/projects-command.ts
629
+ import { randomUUID } from "node:crypto";
630
+ import { readFile as readFile2, writeFile as writeFile3 } from "node:fs/promises";
631
+ function asConfig(value) {
632
+ if (typeof value !== "object" || value === null || Array.isArray(value) || !Array.isArray(value.projects)) {
633
+ throw new Error("\u914D\u7F6E\u6587\u4EF6\u7F3A\u5C11 projects \u6570\u7EC4\uFF0C\u65E0\u6CD5\u7BA1\u7406\u6388\u6743\u9879\u76EE");
634
+ }
635
+ return value;
636
+ }
637
+ function display(value) {
638
+ return typeof value === "string" && value.length > 0 ? JSON.stringify(value) : "\uFF08\u7A7A\uFF09";
639
+ }
640
+ async function manageProjects(configPath2, remove) {
641
+ const original = await readFile2(configPath2);
642
+ const config = asConfig(JSON.parse(original.toString("utf8")));
643
+ if (remove === void 0) {
644
+ if (config.projects.length === 0) console.log("\u914D\u7F6E\u4E2D\u6CA1\u6709\u6388\u6743\u9879\u76EE");
645
+ else for (const [index2, entry] of config.projects.entries()) {
646
+ const project = typeof entry === "object" && entry !== null && !Array.isArray(entry) ? entry : {};
647
+ console.log(`${index2 + 1}. ID=${display(project.id)} \u540D\u79F0=${display(project.name)} \u76EE\u5F55=${display(project.directory)}`);
648
+ }
649
+ console.log("\u5220\u9664\u9519\u8BEF\u9879\uFF1Aoctopus-proxy projects --remove <\u5E8F\u53F7>");
650
+ return;
651
+ }
652
+ if (!/^[1-9][0-9]*$/.test(remove)) throw new Error("--remove \u9700\u8981\u4E0A\u65B9\u5217\u8868\u4E2D\u7684\u6B63\u6574\u6570\u5E8F\u53F7");
653
+ const index = Number(remove) - 1;
654
+ if (!Number.isSafeInteger(index) || index >= config.projects.length) throw new Error(`\u9879\u76EE\u5E8F\u53F7\u8D85\u51FA\u8303\u56F4\uFF1A${remove}`);
655
+ if (config.projects.length === 1) throw new Error("\u81F3\u5C11\u9700\u8981\u4FDD\u7559\u4E00\u4E2A\u6388\u6743\u9879\u76EE\uFF1B\u65E0\u6CD5\u5220\u9664\u6700\u540E\u4E00\u9879");
656
+ const backupPath = `${configPath2}.backup-${randomUUID()}`;
657
+ await writeFile3(backupPath, original, { mode: 384, flag: "wx" });
658
+ config.projects.splice(index, 1);
659
+ await atomicJson(configPath2, config);
660
+ console.log(`\u5DF2\u5220\u9664\u7B2C ${remove} \u4E2A\u6388\u6743\u9879\u76EE\uFF1B\u539F\u914D\u7F6E\u5907\u4EFD\uFF1A${backupPath}`);
661
+ try {
662
+ await loadConfig(configPath2);
663
+ console.log("\u914D\u7F6E\u6821\u9A8C\u901A\u8FC7\uFF1B\u8FD0\u884C octopus-proxy restart \u4F7F\u670D\u52A1\u4F7F\u7528\u65B0\u914D\u7F6E");
664
+ } catch (error) {
665
+ console.log(`\u914D\u7F6E\u4ECD\u6709\u9519\u8BEF\uFF1A${error instanceof Error ? error.message : String(error)}`);
666
+ console.log("\u7EE7\u7EED\u6E05\u7406\u540E\u8FD0\u884C octopus-proxy doctor \u68C0\u67E5\u914D\u7F6E");
667
+ }
668
+ }
669
+
622
670
  // src/cli.ts
623
671
  var USAGE = `octopus-proxy \u2014 Octopus \u4E3B\u673A\u4EE3\u7406
624
672
 
@@ -626,6 +674,7 @@ var USAGE = `octopus-proxy \u2014 Octopus \u4E3B\u673A\u4EE3\u7406
626
674
 
627
675
  \u547D\u4EE4:
628
676
  onboard \u4EA4\u4E92\u5F0F\u521D\u59CB\u5316\u914D\u7F6E\uFF0C\u5E76\u9ED8\u8BA4\u5B89\u88C5\u7CFB\u7EDF\u670D\u52A1
677
+ projects \u5217\u51FA\u6388\u6743\u9879\u76EE\uFF1B\u53EF\u6309\u5E8F\u53F7\u5220\u9664\u9519\u8BEF\u914D\u7F6E\u9879
629
678
  install \u6821\u9A8C\u914D\u7F6E\u540E\u5B89\u88C5/\u66F4\u65B0\u7CFB\u7EDF\u670D\u52A1\uFF08\u5E42\u7B49\uFF0C\u81EA\u52A8\u542F\u52A8\uFF09
630
679
  uninstall \u505C\u6B62\u5E76\u79FB\u9664\u7CFB\u7EDF\u670D\u52A1\uFF08\u4FDD\u7559\u914D\u7F6E\u4E0E\u72B6\u6001\u6570\u636E\uFF09
631
680
  start \u542F\u52A8\u670D\u52A1
@@ -656,12 +705,15 @@ install \u9009\u9879:
656
705
  --force \u91CD\u5199\u670D\u52A1\u5B9A\u4E49\u5E76\u91CD\u542F\uFF08\u914D\u7F6E\u6216\u8DEF\u5F84\u53D8\u5316\u540E\u4F7F\u7528\uFF09
657
706
  --node-path <p> \u56FA\u5B9A\u670D\u52A1\u4F7F\u7528\u7684 node \u7EDD\u5BF9\u8DEF\u5F84
658
707
 
708
+ projects \u9009\u9879:
709
+ --remove <\u5E8F\u53F7> \u5220\u9664\u6307\u5B9A\u9879\u76EE\uFF08\u5148\u8FD0\u884C projects \u67E5\u770B\u5E8F\u53F7\uFF1B\u81EA\u52A8\u5907\u4EFD\u539F\u914D\u7F6E\uFF09
710
+
659
711
  doctor / logs \u9009\u9879:
660
712
  --fix \u81EA\u52A8\u4FEE\u590D\uFF08\u914D\u7F6E\u6743\u9650\u3001\u670D\u52A1\u5B9A\u4E49\u3001\u542F\u52A8\u670D\u52A1\uFF09
661
713
  -f, --follow \u6301\u7EED\u8F93\u51FA\u65E5\u5FD7
662
714
 
663
715
  \u9000\u51FA\u7801: 0 \u6210\u529F\uFF1B1 \u4E00\u822C\u9519\u8BEF\uFF1B78 \u914D\u7F6E\u65E0\u6548\uFF08\u670D\u52A1\u5355\u5143\u5DF2\u914D\u7F6E\u4E0D\u56E0\u6B64\u91CD\u542F\uFF09`;
664
- var VALUE_FLAGS = /* @__PURE__ */ new Set(["--config", "--node-path", "--hub-url", "--bot-id", "--secret-key", "--state-dir", "--tool", "--tool-command", "--opencode-command", "--project"]);
716
+ var VALUE_FLAGS = /* @__PURE__ */ new Set(["--config", "--node-path", "--hub-url", "--bot-id", "--secret-key", "--state-dir", "--tool", "--tool-command", "--opencode-command", "--project", "--remove"]);
665
717
  function parse(argv) {
666
718
  const flags2 = {}, projectArgs2 = [];
667
719
  let command2;
@@ -748,6 +800,9 @@ try {
748
800
  });
749
801
  break;
750
802
  }
803
+ case "projects":
804
+ await manageProjects(configPath, flags["--remove"]);
805
+ break;
751
806
  case "install": {
752
807
  const outcome = await installService({ configPath, nodePath: flags["--node-path"], force: flags["--force"] === "true" });
753
808
  console.log(outcome.changed ? `\u5DF2\u5B89\u88C5\u5E76\u542F\u52A8\u670D\u52A1\uFF1A${outcome.serviceFile}` : `\u670D\u52A1\u5B9A\u4E49\u4E0E\u914D\u7F6E\u4E00\u81F4\uFF0C\u5DF2\u786E\u4FDD\u8FD0\u884C\uFF1A${outcome.serviceFile}`);
package/dist/main.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  ConfigError,
4
4
  runDaemon
5
- } from "./chunk-3TRTDBUO.js";
5
+ } from "./chunk-JWIM27KY.js";
6
6
 
7
7
  // src/main.ts
8
8
  runDaemon(process.env.OCTOPUS_PROXY_CONFIG ?? "proxy.json").catch((error) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skylandnpm/octopus-proxy",
3
- "version": "0.1.4",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "description": "Octopus host proxy: OpenCode, Codex, ZCode and Pi adapters with service installer CLI",
6
6
  "bin": {