@skylandnpm/octopus-proxy 0.1.0 → 0.1.1
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 +3 -1
- package/dist/{chunk-TIHWE4WN.js → chunk-3TRTDBUO.js} +133 -45
- package/dist/cli.js +76 -21
- package/dist/main.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,9 @@ octopus-proxy help
|
|
|
10
10
|
octopus-proxy onboard
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
向导默认使用 `https://octopus.wuyehao.com` 作为 Hub 地址;按需可输入其他地址,或用 `--hub-url` 指定。再次运行向导时会读取现有配置,直接回车即可保留各项设置;机器人 Secret 只提示已配置,不在终端显示原值。macOS 上选择编码工具时,向导优先显示已配置或探测到的命令路径,否则给出该工具的 macOS 路径示例;回车后会检查文件可执行性并运行版本命令,失败时要求重新输入。无交互环境可使用 `octopus-proxy onboard --non-interactive`,未提供 `--hub-url` 时也使用该默认地址;完整选项见 `octopus-proxy help`。安装服务后可运行 `octopus-proxy status` 和 `octopus-proxy doctor` 检查状态。
|
|
14
|
+
|
|
15
|
+
Claw 打开机器人工作区时会通过 Hub 向 Proxy 发送只读 `runtime.snapshot` 命令。响应包含当前运行状态、Hub 和工具设置、授权项目路径,以及工具可提供的模型信息;机器人 Secret、工具密码和提供商凭据不会返回。工作区的“Proxy 信息”按钮可查看这些内容。
|
|
14
16
|
|
|
15
17
|
## Pi agent
|
|
16
18
|
|
|
@@ -11658,12 +11658,13 @@ async function loadConfig(path) {
|
|
|
11658
11658
|
import WebSocket2 from "ws";
|
|
11659
11659
|
import { mkdir as mkdir5 } from "node:fs/promises";
|
|
11660
11660
|
import { join as join9 } from "node:path";
|
|
11661
|
-
import { randomUUID as
|
|
11661
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
11662
11662
|
|
|
11663
11663
|
// ../../packages/protocol/src/index.ts
|
|
11664
11664
|
var PROTOCOL_VERSION = "1.0";
|
|
11665
11665
|
var Operations = [
|
|
11666
11666
|
"runtime.status",
|
|
11667
|
+
"runtime.snapshot",
|
|
11667
11668
|
"runtime.start",
|
|
11668
11669
|
"runtime.stop",
|
|
11669
11670
|
"runtime.restart",
|
|
@@ -11737,7 +11738,7 @@ var CommandSchema = z.object({
|
|
|
11737
11738
|
sessionId: z.string().optional(),
|
|
11738
11739
|
payload: z.record(z.unknown()).default({})
|
|
11739
11740
|
}).strict();
|
|
11740
|
-
var isReadOperation = (operation) => /\.(status|list|get|messages|diff|todos|children|logs|projects|read|search|history|models|agents|commands|providers|mcp)$/.test(operation);
|
|
11741
|
+
var isReadOperation = (operation) => /\.(status|snapshot|list|get|messages|diff|todos|children|logs|projects|read|search|history|models|agents|commands|providers|mcp)$/.test(operation);
|
|
11741
11742
|
|
|
11742
11743
|
// src/workspace-diff.ts
|
|
11743
11744
|
import { execFile } from "node:child_process";
|
|
@@ -12253,29 +12254,29 @@ var Artifacts = class {
|
|
|
12253
12254
|
}
|
|
12254
12255
|
if (!/\.(md|txt)$/i.test(entry.name)) continue;
|
|
12255
12256
|
seen.add(entry.path);
|
|
12256
|
-
const
|
|
12257
|
+
const record2 = index[entry.path] ?? { path: entry.path, revisions: [] };
|
|
12257
12258
|
if (entry.size > 2 * 1024 * 1024) {
|
|
12258
12259
|
const notice = "\u5F53\u524D\u6587\u4EF6\u8D85\u8FC7 2 MiB\uFF0C\u672A\u4FDD\u5B58\u65B0\u7684\u4FEE\u8BA2\u5FEB\u7167\uFF1B\u5DF2\u6709\u5386\u53F2\u4ECD\u53EF\u67E5\u770B\u3002";
|
|
12259
|
-
if (
|
|
12260
|
-
|
|
12261
|
-
index[entry.path] =
|
|
12260
|
+
if (record2.snapshotNotice !== notice) {
|
|
12261
|
+
record2.snapshotNotice = notice;
|
|
12262
|
+
index[entry.path] = record2;
|
|
12262
12263
|
changed = true;
|
|
12263
12264
|
}
|
|
12264
12265
|
continue;
|
|
12265
12266
|
}
|
|
12266
|
-
const data = await readFile3(await this.workspace.path(project, entry.path)), hash = createHash4("sha256").update(data).digest("hex"), previous =
|
|
12267
|
-
if (
|
|
12268
|
-
delete
|
|
12267
|
+
const data = await readFile3(await this.workspace.path(project, entry.path)), hash = createHash4("sha256").update(data).digest("hex"), previous = record2.revisions.at(-1);
|
|
12268
|
+
if (record2.snapshotNotice) {
|
|
12269
|
+
delete record2.snapshotNotice;
|
|
12269
12270
|
changed = true;
|
|
12270
12271
|
}
|
|
12271
12272
|
if (previous?.hash !== hash || previous.deleted) {
|
|
12272
12273
|
const dir = join4(this.directory, project, "blobs");
|
|
12273
12274
|
await mkdir3(dir, { recursive: true, mode: 448 });
|
|
12274
12275
|
await writeFile2(join4(dir, hash), data, { mode: 384 });
|
|
12275
|
-
|
|
12276
|
+
record2.revisions.push({ hash, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
12276
12277
|
changed = true;
|
|
12277
12278
|
}
|
|
12278
|
-
index[entry.path] =
|
|
12279
|
+
index[entry.path] = record2;
|
|
12279
12280
|
}
|
|
12280
12281
|
};
|
|
12281
12282
|
for (const dir of this.workspace.project(project).specDirectories) {
|
|
@@ -12388,8 +12389,85 @@ var EventStream = class {
|
|
|
12388
12389
|
}
|
|
12389
12390
|
};
|
|
12390
12391
|
|
|
12392
|
+
// src/proxy-snapshot.ts
|
|
12393
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
12394
|
+
function record(value) {
|
|
12395
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
12396
|
+
}
|
|
12397
|
+
function publicModels(value) {
|
|
12398
|
+
const result = [];
|
|
12399
|
+
const providers = record(value).providers;
|
|
12400
|
+
if (!Array.isArray(providers)) return result;
|
|
12401
|
+
for (const providerValue of providers) {
|
|
12402
|
+
const provider = record(providerValue);
|
|
12403
|
+
if (typeof provider.id !== "string") continue;
|
|
12404
|
+
for (const modelValue of Object.values(record(provider.models))) {
|
|
12405
|
+
const model = record(modelValue);
|
|
12406
|
+
if (typeof model.id !== "string") continue;
|
|
12407
|
+
result.push({ id: `${provider.id}/${model.id}`, name: typeof model.name === "string" ? model.name : model.id, isDefault: model.isDefault === true });
|
|
12408
|
+
if (result.length >= 500) return result;
|
|
12409
|
+
}
|
|
12410
|
+
}
|
|
12411
|
+
return result;
|
|
12412
|
+
}
|
|
12413
|
+
async function buildProxySnapshot(config, runtime, adapter, requestedProjectId) {
|
|
12414
|
+
const capabilities = adapter.supportedOperations();
|
|
12415
|
+
const status = record(await runtime.status());
|
|
12416
|
+
const projects = config.projects.map(({ id, name, directory, specDirectories }) => ({ id, name, directory, specDirectories }));
|
|
12417
|
+
const projectId = projects.find((project) => project.id === requestedProjectId)?.id ?? projects[0]?.id;
|
|
12418
|
+
const models = [];
|
|
12419
|
+
let modelCatalogStatus = capabilities.includes("configuration.models") ? "unavailable" : "unsupported";
|
|
12420
|
+
if (status.healthy === true && projectId && capabilities.includes("configuration.models")) {
|
|
12421
|
+
try {
|
|
12422
|
+
const command = { type: "command", id: randomUUID4(), botId: config.botId, operation: "configuration.models", projectId, payload: {} };
|
|
12423
|
+
models.push(...publicModels(await adapter.dispatch(command)));
|
|
12424
|
+
modelCatalogStatus = "available";
|
|
12425
|
+
} catch {
|
|
12426
|
+
modelCatalogStatus = "unavailable";
|
|
12427
|
+
}
|
|
12428
|
+
}
|
|
12429
|
+
let recentModel;
|
|
12430
|
+
if (status.healthy === true && projectId && modelCatalogStatus === "unsupported" && capabilities.includes("sessions.list")) {
|
|
12431
|
+
try {
|
|
12432
|
+
const command = { type: "command", id: randomUUID4(), botId: config.botId, operation: "sessions.list", projectId, payload: {} };
|
|
12433
|
+
const sessions = await adapter.dispatch(command);
|
|
12434
|
+
if (Array.isArray(sessions)) {
|
|
12435
|
+
const withModel = sessions.map(record).filter((session) => {
|
|
12436
|
+
const model = record(session.model);
|
|
12437
|
+
return typeof model.providerId === "string" && typeof model.modelId === "string";
|
|
12438
|
+
}).sort((left, right) => {
|
|
12439
|
+
const leftTime = record(left.time).updated, rightTime = record(right.time).updated;
|
|
12440
|
+
return (typeof rightTime === "number" ? rightTime : 0) - (typeof leftTime === "number" ? leftTime : 0);
|
|
12441
|
+
})[0];
|
|
12442
|
+
if (withModel) {
|
|
12443
|
+
const model = record(withModel.model);
|
|
12444
|
+
recentModel = { providerId: model.providerId, modelId: model.modelId };
|
|
12445
|
+
}
|
|
12446
|
+
}
|
|
12447
|
+
} catch {
|
|
12448
|
+
}
|
|
12449
|
+
}
|
|
12450
|
+
return {
|
|
12451
|
+
runtime: { ...status, capabilities },
|
|
12452
|
+
config: {
|
|
12453
|
+
hubUrl: config.hubUrl,
|
|
12454
|
+
botId: config.botId,
|
|
12455
|
+
stateDirectory: config.stateDirectory,
|
|
12456
|
+
tool: {
|
|
12457
|
+
kind: config.tool.kind,
|
|
12458
|
+
command: config.tool.command,
|
|
12459
|
+
mode: config.tool.mode,
|
|
12460
|
+
autoStart: config.tool.autoStart,
|
|
12461
|
+
...config.tool.kind === "opencode" ? { baseUrl: config.tool.baseUrl } : {}
|
|
12462
|
+
}
|
|
12463
|
+
},
|
|
12464
|
+
projects,
|
|
12465
|
+
modelCatalog: { projectId, status: modelCatalogStatus, models, ...recentModel ? { recentModel } : {} }
|
|
12466
|
+
};
|
|
12467
|
+
}
|
|
12468
|
+
|
|
12391
12469
|
// src/media.ts
|
|
12392
|
-
import { createHash as createHash5, randomUUID as
|
|
12470
|
+
import { createHash as createHash5, randomUUID as randomUUID5 } from "node:crypto";
|
|
12393
12471
|
import { constants as constants3 } from "node:fs";
|
|
12394
12472
|
import { open as open3, unlink as unlink3, realpath as realpath3 } from "node:fs/promises";
|
|
12395
12473
|
import { basename as basename3, isAbsolute as isAbsolute3, relative as relative3, resolve as resolve3, sep as sep2 } from "node:path";
|
|
@@ -12606,7 +12684,7 @@ var RemoteMedia = class {
|
|
|
12606
12684
|
if (bytes.length === 0 || bytes.length > this.imageLimit()) throw new Error("Image is empty or exceeds size limit");
|
|
12607
12685
|
const extension = { "image/png": "png", "image/jpeg": "jpg", "image/gif": "gif", "image/webp": "webp", "application/pdf": "pdf" }[mime] ?? "bin";
|
|
12608
12686
|
const directory = await this.workspace.attachmentDirectory(project, "media", sha256), path = directory + "/asset." + extension;
|
|
12609
|
-
const temp = await this.workspace.path(project, directory + "/.octopus-media-" +
|
|
12687
|
+
const temp = await this.workspace.path(project, directory + "/.octopus-media-" + randomUUID5(), true);
|
|
12610
12688
|
const file = await open3(temp, constants3.O_WRONLY | constants3.O_CREAT | constants3.O_EXCL | constants3.O_NOFOLLOW, 384);
|
|
12611
12689
|
try {
|
|
12612
12690
|
await file.writeFile(bytes);
|
|
@@ -14024,7 +14102,7 @@ function applyEdits(text, edits) {
|
|
|
14024
14102
|
|
|
14025
14103
|
// src/project-config.ts
|
|
14026
14104
|
import { readFile as readFile4, writeFile as writeFile3, unlink as unlink4 } from "node:fs/promises";
|
|
14027
|
-
import { createHash as createHash6, randomUUID as
|
|
14105
|
+
import { createHash as createHash6, randomUUID as randomUUID6 } from "node:crypto";
|
|
14028
14106
|
var ProjectConfig = class {
|
|
14029
14107
|
constructor(workspace, request) {
|
|
14030
14108
|
this.workspace = workspace;
|
|
@@ -14075,7 +14153,7 @@ var ProjectConfig = class {
|
|
|
14075
14153
|
if (!this.validator(parse2(updated))) throw new Error("Merged OpenCode configuration is invalid: " + JSON.stringify(this.validator.errors));
|
|
14076
14154
|
if (exists) await this.workspace.write(project, name, updated, createHash6("sha256").update(original).digest("hex"));
|
|
14077
14155
|
else {
|
|
14078
|
-
const temporary = await this.workspace.path(project, `.octopus-config-${
|
|
14156
|
+
const temporary = await this.workspace.path(project, `.octopus-config-${randomUUID6()}.tmp`, true);
|
|
14079
14157
|
try {
|
|
14080
14158
|
await writeFile3(temporary, updated, { mode: 384, flag: "wx" });
|
|
14081
14159
|
await this.workspace.publish(project, temporary, name);
|
|
@@ -14538,7 +14616,7 @@ import { open as open5 } from "node:fs/promises";
|
|
|
14538
14616
|
import { join as join6 } from "node:path";
|
|
14539
14617
|
|
|
14540
14618
|
// src/tools/line-rpc.ts
|
|
14541
|
-
import { randomUUID as
|
|
14619
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
14542
14620
|
import { crc32 } from "node:zlib";
|
|
14543
14621
|
import { StringDecoder } from "node:string_decoder";
|
|
14544
14622
|
function interrupted(message) {
|
|
@@ -14677,37 +14755,37 @@ var LineRpc = class {
|
|
|
14677
14755
|
return;
|
|
14678
14756
|
}
|
|
14679
14757
|
if (this.protocol === "pi") {
|
|
14680
|
-
const
|
|
14681
|
-
if (
|
|
14682
|
-
const waiter = this.pending.get(String(
|
|
14758
|
+
const record3 = message;
|
|
14759
|
+
if (record3.type === "response") {
|
|
14760
|
+
const waiter = this.pending.get(String(record3.id));
|
|
14683
14761
|
if (waiter) {
|
|
14684
14762
|
clearTimeout(waiter.timer);
|
|
14685
|
-
this.pending.delete(String(
|
|
14686
|
-
if (
|
|
14687
|
-
else waiter.reject(new Error(
|
|
14763
|
+
this.pending.delete(String(record3.id));
|
|
14764
|
+
if (record3.success === true) waiter.resolve(record3.data);
|
|
14765
|
+
else waiter.reject(new Error(record3.error ?? "Pi RPC command failed"));
|
|
14688
14766
|
}
|
|
14689
|
-
} else if (typeof
|
|
14767
|
+
} else if (typeof record3.type === "string") this.handlers.onNotification?.(record3.type, message);
|
|
14690
14768
|
return;
|
|
14691
14769
|
}
|
|
14692
|
-
const
|
|
14693
|
-
if (
|
|
14694
|
-
const waiter = this.pending.get(String(
|
|
14770
|
+
const record2 = message;
|
|
14771
|
+
if (record2.id !== void 0 && typeof record2.method !== "string") {
|
|
14772
|
+
const waiter = this.pending.get(String(record2.id));
|
|
14695
14773
|
if (waiter) {
|
|
14696
14774
|
clearTimeout(waiter.timer);
|
|
14697
|
-
this.pending.delete(String(
|
|
14698
|
-
if (
|
|
14699
|
-
else waiter.resolve(
|
|
14775
|
+
this.pending.delete(String(record2.id));
|
|
14776
|
+
if (record2.error) waiter.reject(new Error(record2.error.message ?? `App server error ${record2.error.code ?? ""}`));
|
|
14777
|
+
else waiter.resolve(record2.result);
|
|
14700
14778
|
}
|
|
14701
14779
|
return;
|
|
14702
14780
|
}
|
|
14703
|
-
if (typeof
|
|
14704
|
-
const respond = (result) => this.respond(
|
|
14705
|
-
const respondError = (code, messageText) => this.respondError(
|
|
14706
|
-
this.handlers.onServerRequest?.(
|
|
14781
|
+
if (typeof record2.method === "string" && record2.id !== void 0) {
|
|
14782
|
+
const respond = (result) => this.respond(record2.id, result);
|
|
14783
|
+
const respondError = (code, messageText) => this.respondError(record2.id, code, messageText);
|
|
14784
|
+
this.handlers.onServerRequest?.(record2.id, record2.method, message.params, respond, respondError);
|
|
14707
14785
|
return;
|
|
14708
14786
|
}
|
|
14709
|
-
if (typeof
|
|
14710
|
-
this.handlers.onNotification?.(
|
|
14787
|
+
if (typeof record2.method === "string") {
|
|
14788
|
+
this.handlers.onNotification?.(record2.method, message.params);
|
|
14711
14789
|
return;
|
|
14712
14790
|
}
|
|
14713
14791
|
}
|
|
@@ -14723,7 +14801,7 @@ var LineRpc = class {
|
|
|
14723
14801
|
}
|
|
14724
14802
|
};
|
|
14725
14803
|
function wrapEnvelope(frame) {
|
|
14726
|
-
return { wireVersion: 3, kind: "complete", deliveryKind: "desktop-continuous", logicalFrameId:
|
|
14804
|
+
return { wireVersion: 3, kind: "complete", deliveryKind: "desktop-continuous", logicalFrameId: randomUUID7(), logicalFrameOrdinal: 1, topic: "outbound", subscriptionId: "outbound", frame };
|
|
14727
14805
|
}
|
|
14728
14806
|
|
|
14729
14807
|
// src/tools/stdio-runtime.ts
|
|
@@ -14900,6 +14978,7 @@ import { join as join7 } from "node:path";
|
|
|
14900
14978
|
// src/adapter.ts
|
|
14901
14979
|
var DAEMON_OPERATIONS = [
|
|
14902
14980
|
"runtime.status",
|
|
14981
|
+
"runtime.snapshot",
|
|
14903
14982
|
"runtime.start",
|
|
14904
14983
|
"runtime.stop",
|
|
14905
14984
|
"runtime.restart",
|
|
@@ -14925,7 +15004,7 @@ function unsupportedOperation(kind, operation) {
|
|
|
14925
15004
|
}
|
|
14926
15005
|
|
|
14927
15006
|
// src/tools/codex.ts
|
|
14928
|
-
import { randomUUID as
|
|
15007
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
14929
15008
|
var OPERATIONS = [
|
|
14930
15009
|
...DAEMON_OPERATIONS,
|
|
14931
15010
|
"sessions.list",
|
|
@@ -14989,7 +15068,7 @@ var CodexAdapter = class {
|
|
|
14989
15068
|
}
|
|
14990
15069
|
onServerRequest(project, id, method, params, respond) {
|
|
14991
15070
|
const detail = params ?? {};
|
|
14992
|
-
const requestId =
|
|
15071
|
+
const requestId = randomUUID8();
|
|
14993
15072
|
const threadId = String(detail.threadId ?? "");
|
|
14994
15073
|
if (["item/permissions/requestApproval", "item/commandExecution/requestApproval", "item/fileChange/requestApproval"].includes(method)) {
|
|
14995
15074
|
this.approvals.set(requestId, { project, method, requestId, threadId, detail, respond });
|
|
@@ -15318,7 +15397,7 @@ var CodexAdapter = class {
|
|
|
15318
15397
|
};
|
|
15319
15398
|
|
|
15320
15399
|
// src/tools/zcode.ts
|
|
15321
|
-
import { randomUUID as
|
|
15400
|
+
import { randomUUID as randomUUID9 } from "node:crypto";
|
|
15322
15401
|
import { realpath as realpath5 } from "node:fs/promises";
|
|
15323
15402
|
var OPERATIONS2 = [
|
|
15324
15403
|
...DAEMON_OPERATIONS,
|
|
@@ -15370,7 +15449,7 @@ var ZcodeAdapter = class {
|
|
|
15370
15449
|
}
|
|
15371
15450
|
onServerRequest(project, id, method, params, respond, respondError) {
|
|
15372
15451
|
const detail = params ?? {};
|
|
15373
|
-
const requestId =
|
|
15452
|
+
const requestId = randomUUID9();
|
|
15374
15453
|
const sessionId = String(detail.sessionId ?? "");
|
|
15375
15454
|
if (method === "session/requestRuntimePreferences") {
|
|
15376
15455
|
respond({ nativeSearchEnhancementsEnabled: false });
|
|
@@ -15393,7 +15472,15 @@ var ZcodeAdapter = class {
|
|
|
15393
15472
|
return { workspaceKey: root, workspacePath: root };
|
|
15394
15473
|
}
|
|
15395
15474
|
sessionProjection(session) {
|
|
15396
|
-
|
|
15475
|
+
const model = session.model;
|
|
15476
|
+
return {
|
|
15477
|
+
id: session.sessionId,
|
|
15478
|
+
title: session.title ?? "",
|
|
15479
|
+
directory: session.workspace?.workspacePath,
|
|
15480
|
+
time: { created: session.createdAt, updated: session.updatedAt },
|
|
15481
|
+
status: session.status,
|
|
15482
|
+
...typeof model?.providerId === "string" && typeof model.modelId === "string" ? { model: { providerId: model.providerId, modelId: model.modelId } } : {}
|
|
15483
|
+
};
|
|
15397
15484
|
}
|
|
15398
15485
|
rowToPart(row) {
|
|
15399
15486
|
const data = row.data ?? row;
|
|
@@ -15587,7 +15674,7 @@ var ZcodeAdapter = class {
|
|
|
15587
15674
|
};
|
|
15588
15675
|
|
|
15589
15676
|
// src/tools/pi.ts
|
|
15590
|
-
import { randomUUID as
|
|
15677
|
+
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
15591
15678
|
import { readFile as readFile5, readdir as readdir3, rm } from "node:fs/promises";
|
|
15592
15679
|
import { dirname as dirname4 } from "node:path";
|
|
15593
15680
|
var OPERATIONS3 = [
|
|
@@ -15681,7 +15768,7 @@ var PiAdapter = class {
|
|
|
15681
15768
|
}
|
|
15682
15769
|
onQuestion(project, sessionId, detail) {
|
|
15683
15770
|
if (!["select", "confirm", "input", "editor"].includes(String(detail.method))) return;
|
|
15684
|
-
const id =
|
|
15771
|
+
const id = randomUUID10();
|
|
15685
15772
|
void this.rpc(project, sessionId).then((rpc) => {
|
|
15686
15773
|
if (rpc.exited) return;
|
|
15687
15774
|
const question = { id, project, sessionId, detail, rpc };
|
|
@@ -15781,7 +15868,7 @@ var PiAdapter = class {
|
|
|
15781
15868
|
return sessions.sort((a, b) => b.time.updated - a.time.updated);
|
|
15782
15869
|
}
|
|
15783
15870
|
if (op === "sessions.create") {
|
|
15784
|
-
const session2 = { id:
|
|
15871
|
+
const session2 = { id: randomUUID10(), title: typeof p.title === "string" && p.title.trim() ? p.title : "\u65B0\u4EFB\u52A1", directory: await this.workspace.root(project), time: { created: Date.now(), updated: Date.now() } };
|
|
15785
15872
|
try {
|
|
15786
15873
|
const rpc2 = await this.rpc(project, session2.id);
|
|
15787
15874
|
await rpc2.request("set_session_name", { name: session2.title });
|
|
@@ -16057,7 +16144,7 @@ async function runDaemon(configPath) {
|
|
|
16057
16144
|
const config = await loadConfig(configPath);
|
|
16058
16145
|
await mkdir5(config.stateDirectory, { recursive: true, mode: 448 });
|
|
16059
16146
|
const workspace = new Workspace(config.projects), runtime = createRuntime(config), uploads = new Uploads(workspace, join9(config.stateDirectory, "uploads")), journal = new Journal(join9(config.stateDirectory, "journal"));
|
|
16060
|
-
const epoch =
|
|
16147
|
+
const epoch = randomUUID11();
|
|
16061
16148
|
let stopping = false, botId = "";
|
|
16062
16149
|
const sockets = /* @__PURE__ */ new Set();
|
|
16063
16150
|
const events = new EventStream(epoch, () => {
|
|
@@ -16070,6 +16157,7 @@ async function runDaemon(configPath) {
|
|
|
16070
16157
|
async function dispatch(c) {
|
|
16071
16158
|
const p = c.payload;
|
|
16072
16159
|
if (c.operation === "runtime.status") return { ...await runtime.status(), capabilities: adapter.supportedOperations() };
|
|
16160
|
+
if (c.operation === "runtime.snapshot") return buildProxySnapshot(config, runtime, adapter, c.projectId);
|
|
16073
16161
|
if (c.operation === "runtime.logs") return runtime.logs();
|
|
16074
16162
|
if (c.operation === "runtime.start") return runtime.start();
|
|
16075
16163
|
if (c.operation === "runtime.stop") return runtime.stop();
|
package/dist/cli.js
CHANGED
|
@@ -17,11 +17,11 @@ import {
|
|
|
17
17
|
runDaemon,
|
|
18
18
|
supportedPlatform,
|
|
19
19
|
systemdUnitPath
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-3TRTDBUO.js";
|
|
21
21
|
|
|
22
22
|
// src/cli.ts
|
|
23
23
|
import { spawn } from "node:child_process";
|
|
24
|
-
import { access as
|
|
24
|
+
import { access as access4 } from "node:fs/promises";
|
|
25
25
|
|
|
26
26
|
// src/doctor.ts
|
|
27
27
|
import { access as access2, chmod, constants, mkdir as mkdir3, stat as stat2 } from "node:fs/promises";
|
|
@@ -423,14 +423,18 @@ async function runDoctor(opts) {
|
|
|
423
423
|
// src/onboard.ts
|
|
424
424
|
import { createInterface } from "node:readline/promises";
|
|
425
425
|
import { stdin, stdout } from "node:process";
|
|
426
|
-
import { mkdir as mkdir4, stat as stat3 } from "node:fs/promises";
|
|
426
|
+
import { access as access3, constants as constants2, mkdir as mkdir4, stat as stat3 } from "node:fs/promises";
|
|
427
|
+
import { execFile as execFile5 } from "node:child_process";
|
|
428
|
+
import { platform as platform2 } from "node:os";
|
|
427
429
|
import { isAbsolute as isAbsolute3 } from "node:path";
|
|
430
|
+
import { promisify as promisify5 } from "node:util";
|
|
431
|
+
var DEFAULT_HUB_URL = "https://octopus.wuyehao.com";
|
|
428
432
|
async function ask(rl, question, options = {}) {
|
|
429
433
|
for (; ; ) {
|
|
430
|
-
const suffix = options.default !== void 0 ? `\uFF08\u9ED8\u8BA4 ${options.default}\uFF09` : "";
|
|
434
|
+
const suffix = options.default !== void 0 ? `\uFF08\u9ED8\u8BA4 ${options.defaultDisplay ?? options.default}\uFF09` : "";
|
|
431
435
|
const answer = (await rl.question(`${question}${suffix}: `)).trim();
|
|
432
436
|
const value = answer || options.default || "";
|
|
433
|
-
const problem = options.validate?.(value);
|
|
437
|
+
const problem = await options.validate?.(value);
|
|
434
438
|
if (problem) {
|
|
435
439
|
console.log(` ${problem}`);
|
|
436
440
|
continue;
|
|
@@ -451,24 +455,76 @@ var validUrl = (value) => {
|
|
|
451
455
|
};
|
|
452
456
|
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";
|
|
453
457
|
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";
|
|
458
|
+
var run5 = promisify5(execFile5);
|
|
459
|
+
var MACOS_TOOL_EXAMPLES = {
|
|
460
|
+
opencode: "/opt/homebrew/bin/opencode",
|
|
461
|
+
codex: "/Applications/ChatGPT.app/Contents/Resources/codex",
|
|
462
|
+
zcode: "/Applications/ZCode.app/Contents/Resources/glm/zcode.cjs",
|
|
463
|
+
pi: "/opt/homebrew/bin/pi"
|
|
464
|
+
};
|
|
465
|
+
async function validateToolCommand(value, kind) {
|
|
466
|
+
const command2 = expandHome(value);
|
|
467
|
+
if (!isAbsolute3(command2)) return "\u670D\u52A1\u73AF\u5883\u9700\u8981\u7EDD\u5BF9\u8DEF\u5F84";
|
|
468
|
+
try {
|
|
469
|
+
if (!(await stat3(command2)).isFile()) return "\u547D\u4EE4\u8DEF\u5F84\u5FC5\u987B\u6307\u5411\u53EF\u6267\u884C\u6587\u4EF6";
|
|
470
|
+
await access3(command2, constants2.X_OK);
|
|
471
|
+
} catch {
|
|
472
|
+
return `\u547D\u4EE4\u4E0D\u5B58\u5728\u6216\u4E0D\u53EF\u6267\u884C\uFF1A${command2}`;
|
|
473
|
+
}
|
|
474
|
+
try {
|
|
475
|
+
await run5(command2, [...describeTool(kind).versionArgs], { timeout: 1e4 });
|
|
476
|
+
} catch {
|
|
477
|
+
return `${describeTool(kind).label} \u7248\u672C\u68C0\u67E5\u5931\u8D25\uFF0C\u8BF7\u786E\u8BA4\u547D\u4EE4\u8DEF\u5F84\uFF1A${command2}`;
|
|
478
|
+
}
|
|
479
|
+
return void 0;
|
|
480
|
+
}
|
|
454
481
|
async function runOnboard(opts) {
|
|
455
|
-
|
|
456
|
-
|
|
482
|
+
const configExists = await stat3(opts.configPath).then(() => true, (error) => {
|
|
483
|
+
if (error.code === "ENOENT") return false;
|
|
484
|
+
throw error;
|
|
485
|
+
});
|
|
486
|
+
const existing = opts.interactive && configExists ? await loadConfig(opts.configPath) : void 0;
|
|
487
|
+
let hubUrl = opts.hubUrl || existing?.hubUrl || DEFAULT_HUB_URL, botId = opts.botId ?? existing?.botId ?? "", secretKey = opts.secretKey ?? existing?.secretKey ?? "", stateDirectory = opts.stateDirectory ?? existing?.stateDirectory ?? defaultStateDirectory();
|
|
488
|
+
let toolKind = opts.toolKind ?? existing?.tool.kind ?? "opencode";
|
|
489
|
+
let toolCommand = opts.toolCommand ?? (toolKind === existing?.tool.kind ? existing.tool.command : "");
|
|
490
|
+
let mode = toolKind === existing?.tool.kind ? existing.tool.mode : "managed";
|
|
491
|
+
let projects = [...existing?.projects ?? [], ...opts.projects].map((project) => ({ ...project, directory: expandHome(project.directory) }));
|
|
457
492
|
if (opts.interactive) {
|
|
458
493
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
459
494
|
console.log("Octopus Proxy \u521D\u59CB\u5316\u5411\u5BFC");
|
|
460
495
|
console.log(`\u914D\u7F6E\u5C06\u5199\u5165 ${opts.configPath}\uFF1B\u6587\u4EF6\u5305\u542B\u673A\u5668\u4EBA Secret\uFF0C\u4F1A\u4EE5 0600 \u6743\u9650\u4FDD\u5B58\u3002
|
|
461
496
|
`);
|
|
462
497
|
hubUrl = await ask(rl, "Hub \u5730\u5740", { default: hubUrl || void 0, validate: validUrl });
|
|
463
|
-
botId = await ask(rl, "\u673A\u5668\u4EBA ID\uFF08\u5728 Claw \u6216 Taskhub \u4E2D\u521B\u5EFA\u5E76\u590D\u5236\uFF09", { validate: validBotId });
|
|
464
|
-
secretKey = await ask(rl, "\u673A\u5668\u4EBA Secret\uFF08\u5728 Claw \u6216 Taskhub \u521B\u5EFA\uFF1B\u8F93\u5165\u4F1A\u56DE\u663E\u5728\u7EC8\u7AEF\uFF09", { validate: (value) => value.length >= 20 ? void 0 : "\u8BF7\u8F93\u5165\u5B8C\u6574\u7684\u673A\u5668\u4EBA Secret" });
|
|
498
|
+
botId = await ask(rl, "\u673A\u5668\u4EBA ID\uFF08\u5728 Claw \u6216 Taskhub \u4E2D\u521B\u5EFA\u5E76\u590D\u5236\uFF09", { default: botId || void 0, validate: validBotId });
|
|
499
|
+
secretKey = await ask(rl, "\u673A\u5668\u4EBA Secret\uFF08\u5728 Claw \u6216 Taskhub \u521B\u5EFA\uFF1B\u8F93\u5165\u4F1A\u56DE\u663E\u5728\u7EC8\u7AEF\uFF09", { default: secretKey || void 0, defaultDisplay: existing?.secretKey ? "\u5DF2\u914D\u7F6E\uFF0C\u56DE\u8F66\u4FDD\u7559" : "\u5DF2\u63D0\u4F9B\uFF0C\u56DE\u8F66\u4F7F\u7528", validate: (value) => value.length >= 20 ? void 0 : "\u8BF7\u8F93\u5165\u5B8C\u6574\u7684\u673A\u5668\u4EBA Secret" });
|
|
465
500
|
stateDirectory = expandHome(await ask(rl, "\u72B6\u6001\u76EE\u5F55", { default: stateDirectory, validate: (value) => isAbsolute3(expandHome(value)) ? void 0 : "\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84" }));
|
|
501
|
+
const previousToolKind = toolKind;
|
|
466
502
|
toolKind = await ask(rl, `\u7F16\u7801\u5DE5\u5177\uFF08${TOOL_KINDS.join("/")}\uFF09`, { default: toolKind, validate: (value) => TOOL_KINDS.includes(value) ? void 0 : `\u8F93\u5165 ${TOOL_KINDS.join(" \u6216 ")}` });
|
|
503
|
+
if (toolKind !== previousToolKind) toolCommand = toolKind === existing?.tool.kind ? existing.tool.command : "";
|
|
467
504
|
const descriptor = describeTool(toolKind);
|
|
468
505
|
const found = await resolveCommandOnPath(toolKind, toolSearchDirs(toolKind));
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
console.log(
|
|
506
|
+
const example = platform2() === "darwin" ? MACOS_TOOL_EXAMPLES[toolKind] : void 0;
|
|
507
|
+
toolCommand = expandHome(await ask(rl, found ? `${descriptor.label} \u547D\u4EE4\uFF08\u63A2\u6D4B\u5230 ${found}\uFF1B\u56DE\u8F66\u4F1A\u9A8C\u8BC1\uFF09` : `${descriptor.label} \u547D\u4EE4\uFF08\u56DE\u8F66\u4F1A\u9A8C\u8BC1\u8DEF\u5F84\uFF09`, { default: toolCommand || found || example, validate: (value) => validateToolCommand(value, toolKind) }));
|
|
508
|
+
console.log(` \u5DF2\u786E\u8BA4 ${descriptor.label} \u547D\u4EE4\u53EF\u6267\u884C\uFF1A${toolCommand}`);
|
|
509
|
+
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" });
|
|
510
|
+
if (projects.length) console.log("\n\u5DF2\u6709\u6388\u6743\u9879\u76EE\uFF08\u76F4\u63A5\u56DE\u8F66\u4FDD\u7559\u5404\u9879\uFF09\uFF1A");
|
|
511
|
+
for (const project of projects) {
|
|
512
|
+
project.name = await ask(rl, " \u9879\u76EE\u540D\u79F0", { default: project.name });
|
|
513
|
+
for (; ; ) {
|
|
514
|
+
project.directory = expandHome(await ask(rl, ` \u300C${project.name}\u300D\u76EE\u5F55\uFF08\u7EDD\u5BF9\u8DEF\u5F84\uFF09`, { default: project.directory }));
|
|
515
|
+
if (!isAbsolute3(project.directory)) {
|
|
516
|
+
console.log(" \u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84");
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
if (!await stat3(project.directory).then(() => true, () => false)) {
|
|
520
|
+
console.log(" \u76EE\u5F55\u4E0D\u5B58\u5728");
|
|
521
|
+
continue;
|
|
522
|
+
}
|
|
523
|
+
break;
|
|
524
|
+
}
|
|
525
|
+
project.id = await ask(rl, " \u9879\u76EE ID", { default: project.id ?? slug(project.name), validate: validId });
|
|
526
|
+
}
|
|
527
|
+
console.log("\n\u6DFB\u52A0\u6388\u6743\u9879\u76EE\uFF08\u540D\u79F0\u7559\u7A7A\u7ED3\u675F\uFF09\uFF1A");
|
|
472
528
|
for (; ; ) {
|
|
473
529
|
const name = (await rl.question(" \u9879\u76EE\u540D\u79F0: ")).trim();
|
|
474
530
|
if (!name) break;
|
|
@@ -493,7 +549,6 @@ async function runOnboard(opts) {
|
|
|
493
549
|
console.log("");
|
|
494
550
|
} else {
|
|
495
551
|
const missing = [];
|
|
496
|
-
if (!hubUrl) missing.push("--hub-url");
|
|
497
552
|
if (!botId) missing.push("--bot-id");
|
|
498
553
|
if (!secretKey) missing.push("--secret-key");
|
|
499
554
|
if (!projects.length) missing.push("--project");
|
|
@@ -509,12 +564,12 @@ async function runOnboard(opts) {
|
|
|
509
564
|
toolCommand = toolCommand ? expandHome(toolCommand) : await resolveCommandOnPath(toolKind, toolSearchDirs(toolKind)) ?? descriptor.defaultCommand;
|
|
510
565
|
if (!isAbsolute3(toolCommand)) console.log(`\u63D0\u793A\uFF1A\u672A\u5728 PATH \u4E2D\u63A2\u6D4B\u5230 ${descriptor.label}\uFF0C\u914D\u7F6E\u4FDD\u7559\u547D\u4EE4\u540D\u300C${toolCommand}\u300D\uFF1B\u670D\u52A1\u73AF\u5883\u5EFA\u8BAE\u7EDD\u5BF9\u8DEF\u5F84\uFF08\u53EF\u7528 --tool-command \u6307\u5B9A\uFF09`);
|
|
511
566
|
}
|
|
512
|
-
if (
|
|
567
|
+
if (configExists) {
|
|
513
568
|
if (opts.interactive) {
|
|
514
569
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
515
|
-
const answer = (await rl.question(`\u914D\u7F6E ${opts.configPath}
|
|
570
|
+
const answer = (await rl.question(`\u4FDD\u5B58\u5230\u73B0\u6709\u914D\u7F6E ${opts.configPath}\uFF1F(Y/n): `)).trim();
|
|
516
571
|
rl.close();
|
|
517
|
-
if (
|
|
572
|
+
if (/^(n|no)$/i.test(answer)) {
|
|
518
573
|
console.log("\u5DF2\u53D6\u6D88\uFF0C\u672A\u5199\u5165\u4EFB\u4F55\u5185\u5BB9\u3002");
|
|
519
574
|
return;
|
|
520
575
|
}
|
|
@@ -528,8 +583,8 @@ async function runOnboard(opts) {
|
|
|
528
583
|
secretKey,
|
|
529
584
|
stateDirectory,
|
|
530
585
|
...loopbackHttp ? { allowInsecureLocalhost: true } : {},
|
|
531
|
-
projects: projects.map((project) => ({ id: project.id, name: project.name, directory: project.directory, specDirectories: ["specs", "docs"] })),
|
|
532
|
-
tool: { kind: toolKind, command: toolCommand || describeTool(toolKind).defaultCommand, ...toolKind === "opencode" ? { baseUrl: "http://127.0.0.1:4096", mode } : {}, autoStart: true }
|
|
586
|
+
projects: projects.map((project) => ({ id: project.id, name: project.name, directory: project.directory, specDirectories: project.specDirectories ?? ["specs", "docs"] })),
|
|
587
|
+
tool: { kind: toolKind, command: toolCommand || describeTool(toolKind).defaultCommand, ...toolKind === "opencode" ? { baseUrl: toolKind === existing?.tool.kind ? existing.tool.baseUrl : "http://127.0.0.1:4096", mode } : {}, ...toolKind === existing?.tool.kind && existing.tool.password ? { password: existing.tool.password } : {}, autoStart: toolKind === existing?.tool.kind ? existing.tool.autoStart : true }
|
|
533
588
|
});
|
|
534
589
|
await loadConfig(opts.configPath);
|
|
535
590
|
console.log(`\u5DF2\u5199\u5165\u914D\u7F6E\uFF1A${opts.configPath}\uFF080600\uFF09`);
|
|
@@ -579,8 +634,8 @@ var USAGE = `octopus-proxy \u2014 Octopus \u4E3B\u673A\u4EE3\u7406
|
|
|
579
634
|
--config <path> \u914D\u7F6E\u6587\u4EF6\u8DEF\u5F84\uFF08\u9ED8\u8BA4 $OCTOPUS_PROXY_CONFIG \u6216 ~/.config/octopus/proxy.json\uFF09
|
|
580
635
|
|
|
581
636
|
onboard \u9009\u9879:
|
|
582
|
-
--non-interactive \u975E\u4EA4\u4E92\u6A21\u5F0F\uFF1B\u9700\u63D0\u4F9B
|
|
583
|
-
--hub-url <url> Hub \u5730\u5740\
|
|
637
|
+
--non-interactive \u975E\u4EA4\u4E92\u6A21\u5F0F\uFF1B\u9700\u63D0\u4F9B\u673A\u5668\u4EBA ID\u3001Secret \u548C\u9879\u76EE
|
|
638
|
+
--hub-url <url> Hub \u5730\u5740\uFF08\u9ED8\u8BA4 https://octopus.wuyehao.com\uFF09
|
|
584
639
|
--bot-id <uuid> Claw \u6216 Taskhub \u4E2D\u521B\u5EFA\u7684\u673A\u5668\u4EBA ID
|
|
585
640
|
--secret-key <key> \u673A\u5668\u4EBA Secret\uFF08\u5728 Claw \u6216 Taskhub \u521B\u5EFA\uFF09
|
|
586
641
|
--state-dir <path> \u72B6\u6001\u76EE\u5F55\uFF08\u9ED8\u8BA4 ~/.local/state/octopus\uFF09
|
|
@@ -633,7 +688,7 @@ function parse(argv) {
|
|
|
633
688
|
}
|
|
634
689
|
async function showLogs(follow) {
|
|
635
690
|
const child = isMacOS() ? spawn("tail", ["-n", "200", ...follow ? ["-F"] : [], launchdLogPath()], { stdio: "inherit" }) : spawn("journalctl", ["--user", "-u", SYSTEMD_UNIT, "-n", "200", ...follow ? ["-f"] : ["--no-pager"]], { stdio: "inherit" });
|
|
636
|
-
if (isMacOS() && !await
|
|
691
|
+
if (isMacOS() && !await access4(launchdLogPath()).then(() => true, () => false)) {
|
|
637
692
|
console.error(`\u65E5\u5FD7\u6587\u4EF6\u5C1A\u672A\u751F\u6210\uFF1A${launchdLogPath()}`);
|
|
638
693
|
process.exit(1);
|
|
639
694
|
}
|
package/dist/main.js
CHANGED