weacpx 0.4.0-beta.3 → 0.4.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 -0
- package/dist/cli.js +820 -360
- package/dist/weixin/storage/ensure-dir.d.ts +1 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2648,7 +2648,7 @@ class DaemonController {
|
|
|
2648
2648
|
status
|
|
2649
2649
|
};
|
|
2650
2650
|
}
|
|
2651
|
-
async start() {
|
|
2651
|
+
async start(options = {}) {
|
|
2652
2652
|
const current = await this.getStatus();
|
|
2653
2653
|
if (current.state === "running") {
|
|
2654
2654
|
return { state: "already-running", pid: current.pid };
|
|
@@ -2657,7 +2657,7 @@ class DaemonController {
|
|
|
2657
2657
|
throw new Error(`weacpx daemon process is already running (pid ${current.pid}) but status metadata is missing`);
|
|
2658
2658
|
}
|
|
2659
2659
|
await this.statusStore.clear();
|
|
2660
|
-
const pid = await this.deps.spawnDetached();
|
|
2660
|
+
const pid = await this.deps.spawnDetached(options);
|
|
2661
2661
|
await this.writePid(pid);
|
|
2662
2662
|
await this.waitForStartupMetadata(pid);
|
|
2663
2663
|
return { state: "started", pid };
|
|
@@ -2782,12 +2782,12 @@ import { spawn as spawn2 } from "node:child_process";
|
|
|
2782
2782
|
function createDaemonController(paths, options) {
|
|
2783
2783
|
return new DaemonController(paths, {
|
|
2784
2784
|
isProcessRunning: options.isProcessRunning ?? defaultIsProcessRunning2,
|
|
2785
|
-
spawnDetached: async () => {
|
|
2785
|
+
spawnDetached: async (spawnOptions) => {
|
|
2786
2786
|
await mkdir4(paths.runtimeDir, { recursive: true });
|
|
2787
2787
|
const stdoutHandle = await open(paths.stdoutLog, "a");
|
|
2788
2788
|
const stderrHandle = await open(paths.stderrLog, "a");
|
|
2789
2789
|
try {
|
|
2790
|
-
return await (options.spawnProcess ?? defaultSpawnProcess)(buildSpawnRequest(paths, options, stdoutHandle.fd, stderrHandle.fd));
|
|
2790
|
+
return await (options.spawnProcess ?? defaultSpawnProcess)(buildSpawnRequest(paths, options, stdoutHandle.fd, stderrHandle.fd, spawnOptions));
|
|
2791
2791
|
} finally {
|
|
2792
2792
|
await stdoutHandle.close();
|
|
2793
2793
|
await stderrHandle.close();
|
|
@@ -2804,7 +2804,7 @@ function defaultIsProcessRunning2(pid) {
|
|
|
2804
2804
|
return false;
|
|
2805
2805
|
}
|
|
2806
2806
|
}
|
|
2807
|
-
function buildSpawnRequest(paths, options, stdoutFd, stderrFd) {
|
|
2807
|
+
function buildSpawnRequest(paths, options, stdoutFd, stderrFd, spawnOptions = {}) {
|
|
2808
2808
|
const platform = options.platform ?? process.platform;
|
|
2809
2809
|
if (platform === "win32") {
|
|
2810
2810
|
return {
|
|
@@ -2825,7 +2825,8 @@ function buildSpawnRequest(paths, options, stdoutFd, stderrFd) {
|
|
|
2825
2825
|
WEACPX_DAEMON_ARG1: "run",
|
|
2826
2826
|
WEACPX_DAEMON_CWD: options.cwd,
|
|
2827
2827
|
WEACPX_DAEMON_STDOUT: paths.stdoutLog,
|
|
2828
|
-
WEACPX_DAEMON_STDERR: paths.stderrLog
|
|
2828
|
+
WEACPX_DAEMON_STDERR: paths.stderrLog,
|
|
2829
|
+
...spawnOptions.firstRunOnboarding ? { WEACPX_FIRST_RUN_ONBOARDING: spawnOptions.firstRunOnboarding } : {}
|
|
2829
2830
|
},
|
|
2830
2831
|
stdio: ["ignore", "pipe", "ignore"],
|
|
2831
2832
|
windowsHide: true
|
|
@@ -2839,7 +2840,10 @@ function buildSpawnRequest(paths, options, stdoutFd, stderrFd) {
|
|
|
2839
2840
|
options: {
|
|
2840
2841
|
cwd: options.cwd,
|
|
2841
2842
|
detached: true,
|
|
2842
|
-
env:
|
|
2843
|
+
env: {
|
|
2844
|
+
...options.env,
|
|
2845
|
+
...spawnOptions.firstRunOnboarding ? { WEACPX_FIRST_RUN_ONBOARDING: spawnOptions.firstRunOnboarding } : {}
|
|
2846
|
+
},
|
|
2843
2847
|
stdio: ["ignore", stdoutFd, stderrFd]
|
|
2844
2848
|
}
|
|
2845
2849
|
};
|
|
@@ -9829,74 +9833,74 @@ var init_state_store = __esm(() => {
|
|
|
9829
9833
|
init_types();
|
|
9830
9834
|
});
|
|
9831
9835
|
|
|
9832
|
-
// src/
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
|
|
9837
|
-
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
|
|
9841
|
-
|
|
9842
|
-
|
|
9843
|
-
|
|
9844
|
-
|
|
9845
|
-
|
|
9836
|
+
// src/config/agent-templates.ts
|
|
9837
|
+
function getAgentTemplate(name) {
|
|
9838
|
+
const template = TEMPLATES[name];
|
|
9839
|
+
if (!template) {
|
|
9840
|
+
return null;
|
|
9841
|
+
}
|
|
9842
|
+
return {
|
|
9843
|
+
...template
|
|
9844
|
+
};
|
|
9845
|
+
}
|
|
9846
|
+
function listAgentTemplates() {
|
|
9847
|
+
return Object.keys(TEMPLATES);
|
|
9848
|
+
}
|
|
9849
|
+
var TEMPLATES;
|
|
9850
|
+
var init_agent_templates = __esm(() => {
|
|
9851
|
+
TEMPLATES = {
|
|
9852
|
+
codex: {
|
|
9853
|
+
driver: "codex"
|
|
9846
9854
|
},
|
|
9847
|
-
|
|
9848
|
-
|
|
9849
|
-
if (config2.id !== "weixin")
|
|
9850
|
-
issues.push({ kind: "invalid-config", message: "weixin channel id must be weixin" });
|
|
9851
|
-
if (config2.type !== "weixin")
|
|
9852
|
-
issues.push({ kind: "invalid-config", message: "weixin channel type must be weixin" });
|
|
9853
|
-
return issues;
|
|
9855
|
+
claude: {
|
|
9856
|
+
driver: "claude"
|
|
9854
9857
|
},
|
|
9855
|
-
|
|
9856
|
-
|
|
9858
|
+
opencode: {
|
|
9859
|
+
driver: "opencode"
|
|
9857
9860
|
},
|
|
9858
|
-
|
|
9859
|
-
|
|
9861
|
+
gemini: {
|
|
9862
|
+
driver: "gemini"
|
|
9860
9863
|
}
|
|
9861
9864
|
};
|
|
9862
9865
|
});
|
|
9863
9866
|
|
|
9864
|
-
// src/
|
|
9865
|
-
|
|
9866
|
-
|
|
9867
|
-
|
|
9868
|
-
|
|
9869
|
-
if (
|
|
9870
|
-
|
|
9871
|
-
if (
|
|
9872
|
-
|
|
9873
|
-
|
|
9874
|
-
|
|
9867
|
+
// src/plugins/plugin-home.ts
|
|
9868
|
+
import { mkdir as mkdir6, writeFile as writeFile5 } from "node:fs/promises";
|
|
9869
|
+
import { homedir as homedir3 } from "node:os";
|
|
9870
|
+
import { join as join3 } from "node:path";
|
|
9871
|
+
function resolvePluginHome(input = {}) {
|
|
9872
|
+
if (input.pluginHome?.trim())
|
|
9873
|
+
return input.pluginHome;
|
|
9874
|
+
if (process.env.WEACPX_PLUGIN_HOME?.trim())
|
|
9875
|
+
return process.env.WEACPX_PLUGIN_HOME;
|
|
9876
|
+
const home = input.home ?? process.env.HOME ?? homedir3();
|
|
9877
|
+
return join3(home, ".weacpx", "plugins");
|
|
9875
9878
|
}
|
|
9876
|
-
function
|
|
9877
|
-
|
|
9878
|
-
|
|
9879
|
+
async function ensurePluginHome(pluginHome) {
|
|
9880
|
+
await mkdir6(pluginHome, { recursive: true, mode: 448 });
|
|
9881
|
+
await writeFile5(join3(pluginHome, "package.json"), JSON.stringify({ private: true, type: "module" }, null, 2) + `
|
|
9882
|
+
`, { flag: "wx" }).catch((error2) => {
|
|
9883
|
+
if (error2.code !== "EEXIST")
|
|
9884
|
+
throw error2;
|
|
9885
|
+
});
|
|
9879
9886
|
}
|
|
9880
|
-
|
|
9881
|
-
|
|
9887
|
+
var init_plugin_home = () => {};
|
|
9888
|
+
|
|
9889
|
+
// src/weixin/storage/ensure-dir.ts
|
|
9890
|
+
import fs2 from "node:fs";
|
|
9891
|
+
function ensureDirSync(dir) {
|
|
9892
|
+
try {
|
|
9893
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
9882
9894
|
return;
|
|
9883
|
-
|
|
9884
|
-
|
|
9885
|
-
|
|
9886
|
-
|
|
9887
|
-
|
|
9888
|
-
|
|
9889
|
-
|
|
9890
|
-
}
|
|
9891
|
-
function getChannelCliProvider(type) {
|
|
9892
|
-
bootstrapBuiltinChannelCliProviders();
|
|
9893
|
-
return cliProviders.get(type) ?? null;
|
|
9895
|
+
} catch (err) {
|
|
9896
|
+
try {
|
|
9897
|
+
if (fs2.statSync(dir).isDirectory())
|
|
9898
|
+
return;
|
|
9899
|
+
} catch {}
|
|
9900
|
+
throw err;
|
|
9901
|
+
}
|
|
9894
9902
|
}
|
|
9895
|
-
var
|
|
9896
|
-
var init_registry = __esm(() => {
|
|
9897
|
-
init_weixin_provider();
|
|
9898
|
-
cliProviders = new Map;
|
|
9899
|
-
});
|
|
9903
|
+
var init_ensure_dir = () => {};
|
|
9900
9904
|
|
|
9901
9905
|
// src/weixin/storage/state-dir.ts
|
|
9902
9906
|
import os from "node:os";
|
|
@@ -9907,7 +9911,7 @@ function resolveStateDir() {
|
|
|
9907
9911
|
var init_state_dir = () => {};
|
|
9908
9912
|
|
|
9909
9913
|
// src/weixin/auth/accounts.ts
|
|
9910
|
-
import
|
|
9914
|
+
import fs3 from "node:fs";
|
|
9911
9915
|
import path4 from "node:path";
|
|
9912
9916
|
function normalizeAccountId(raw) {
|
|
9913
9917
|
return raw.trim().toLowerCase().replace(/[@.]/g, "-");
|
|
@@ -9930,9 +9934,9 @@ function resolveAccountIndexPath() {
|
|
|
9930
9934
|
function listIndexedWeixinAccountIds() {
|
|
9931
9935
|
const filePath = resolveAccountIndexPath();
|
|
9932
9936
|
try {
|
|
9933
|
-
if (!
|
|
9937
|
+
if (!fs3.existsSync(filePath))
|
|
9934
9938
|
return [];
|
|
9935
|
-
const raw =
|
|
9939
|
+
const raw = fs3.readFileSync(filePath, "utf-8");
|
|
9936
9940
|
const parsed = JSON.parse(raw);
|
|
9937
9941
|
if (!Array.isArray(parsed))
|
|
9938
9942
|
return [];
|
|
@@ -9943,8 +9947,8 @@ function listIndexedWeixinAccountIds() {
|
|
|
9943
9947
|
}
|
|
9944
9948
|
function registerWeixinAccountId(accountId) {
|
|
9945
9949
|
const dir = resolveWeixinStateDir();
|
|
9946
|
-
|
|
9947
|
-
|
|
9950
|
+
ensureDirSync(dir);
|
|
9951
|
+
fs3.writeFileSync(resolveAccountIndexPath(), JSON.stringify([accountId], null, 2), "utf-8");
|
|
9948
9952
|
}
|
|
9949
9953
|
function resolveAccountsDir() {
|
|
9950
9954
|
return path4.join(resolveWeixinStateDir(), "accounts");
|
|
@@ -9955,9 +9959,9 @@ function resolveAccountPath(accountId) {
|
|
|
9955
9959
|
function loadLegacyToken() {
|
|
9956
9960
|
const legacyPath = path4.join(resolveStateDir(), "credentials", "openclaw-weixin", "credentials.json");
|
|
9957
9961
|
try {
|
|
9958
|
-
if (!
|
|
9962
|
+
if (!fs3.existsSync(legacyPath))
|
|
9959
9963
|
return;
|
|
9960
|
-
const raw =
|
|
9964
|
+
const raw = fs3.readFileSync(legacyPath, "utf-8");
|
|
9961
9965
|
const parsed = JSON.parse(raw);
|
|
9962
9966
|
return typeof parsed.token === "string" ? parsed.token : undefined;
|
|
9963
9967
|
} catch {
|
|
@@ -9966,8 +9970,8 @@ function loadLegacyToken() {
|
|
|
9966
9970
|
}
|
|
9967
9971
|
function readAccountFile(filePath) {
|
|
9968
9972
|
try {
|
|
9969
|
-
if (
|
|
9970
|
-
return JSON.parse(
|
|
9973
|
+
if (fs3.existsSync(filePath)) {
|
|
9974
|
+
return JSON.parse(fs3.readFileSync(filePath, "utf-8"));
|
|
9971
9975
|
}
|
|
9972
9976
|
} catch {}
|
|
9973
9977
|
return null;
|
|
@@ -9989,7 +9993,7 @@ function loadWeixinAccount(accountId) {
|
|
|
9989
9993
|
}
|
|
9990
9994
|
function saveWeixinAccount(accountId, update) {
|
|
9991
9995
|
const dir = resolveAccountsDir();
|
|
9992
|
-
|
|
9996
|
+
ensureDirSync(dir);
|
|
9993
9997
|
const existing = loadWeixinAccount(accountId) ?? {};
|
|
9994
9998
|
const token = update.token?.trim() || existing.token;
|
|
9995
9999
|
const baseUrl = update.baseUrl?.trim() || existing.baseUrl;
|
|
@@ -10000,14 +10004,14 @@ function saveWeixinAccount(accountId, update) {
|
|
|
10000
10004
|
...userId ? { userId } : {}
|
|
10001
10005
|
};
|
|
10002
10006
|
const filePath = resolveAccountPath(accountId);
|
|
10003
|
-
|
|
10007
|
+
fs3.writeFileSync(filePath, JSON.stringify(data, null, 2), "utf-8");
|
|
10004
10008
|
try {
|
|
10005
|
-
|
|
10009
|
+
fs3.chmodSync(filePath, 384);
|
|
10006
10010
|
} catch {}
|
|
10007
10011
|
}
|
|
10008
10012
|
function clearWeixinAccount(accountId) {
|
|
10009
10013
|
try {
|
|
10010
|
-
|
|
10014
|
+
fs3.unlinkSync(resolveAccountPath(accountId));
|
|
10011
10015
|
} catch {}
|
|
10012
10016
|
}
|
|
10013
10017
|
function clearAllWeixinAccounts() {
|
|
@@ -10016,7 +10020,7 @@ function clearAllWeixinAccounts() {
|
|
|
10016
10020
|
clearWeixinAccount(id);
|
|
10017
10021
|
}
|
|
10018
10022
|
try {
|
|
10019
|
-
|
|
10023
|
+
fs3.writeFileSync(resolveAccountIndexPath(), "[]", "utf-8");
|
|
10020
10024
|
} catch {}
|
|
10021
10025
|
}
|
|
10022
10026
|
function resolveConfigPath() {
|
|
@@ -10028,9 +10032,9 @@ function resolveConfigPath() {
|
|
|
10028
10032
|
function loadConfigRouteTag(accountId) {
|
|
10029
10033
|
try {
|
|
10030
10034
|
const configPath = resolveConfigPath();
|
|
10031
|
-
if (!
|
|
10035
|
+
if (!fs3.existsSync(configPath))
|
|
10032
10036
|
return;
|
|
10033
|
-
const raw =
|
|
10037
|
+
const raw = fs3.readFileSync(configPath, "utf-8");
|
|
10034
10038
|
const cfg = JSON.parse(raw);
|
|
10035
10039
|
const channels = cfg.channels;
|
|
10036
10040
|
const section = channels?.["openclaw-weixin"];
|
|
@@ -10074,11 +10078,12 @@ function resolveWeixinAccount(accountId) {
|
|
|
10074
10078
|
}
|
|
10075
10079
|
var DEFAULT_BASE_URL = "https://ilinkai.weixin.qq.com", CDN_BASE_URL = "https://novac2c.cdn.weixin.qq.com/c2c";
|
|
10076
10080
|
var init_accounts = __esm(() => {
|
|
10081
|
+
init_ensure_dir();
|
|
10077
10082
|
init_state_dir();
|
|
10078
10083
|
});
|
|
10079
10084
|
|
|
10080
10085
|
// src/weixin/util/logger.ts
|
|
10081
|
-
import
|
|
10086
|
+
import fs4 from "node:fs";
|
|
10082
10087
|
import os2 from "node:os";
|
|
10083
10088
|
import path5 from "node:path";
|
|
10084
10089
|
function resolveMinLevel() {
|
|
@@ -10128,10 +10133,10 @@ function writeLog(level, message, accountId) {
|
|
|
10128
10133
|
});
|
|
10129
10134
|
try {
|
|
10130
10135
|
if (!logDirEnsured) {
|
|
10131
|
-
|
|
10136
|
+
fs4.mkdirSync(MAIN_LOG_DIR, { recursive: true });
|
|
10132
10137
|
logDirEnsured = true;
|
|
10133
10138
|
}
|
|
10134
|
-
|
|
10139
|
+
fs4.appendFileSync(resolveMainLogPath(), `${entry}
|
|
10135
10140
|
`, "utf-8");
|
|
10136
10141
|
} catch {}
|
|
10137
10142
|
}
|
|
@@ -11967,7 +11972,7 @@ var init_types2 = __esm(() => {
|
|
|
11967
11972
|
});
|
|
11968
11973
|
|
|
11969
11974
|
// src/channels/media-store.ts
|
|
11970
|
-
import { access as access2, mkdir as
|
|
11975
|
+
import { access as access2, mkdir as mkdir7, readdir, rm as rm4, stat, writeFile as writeFile6 } from "node:fs/promises";
|
|
11971
11976
|
import path6 from "node:path";
|
|
11972
11977
|
|
|
11973
11978
|
class RuntimeMediaStore {
|
|
@@ -11985,13 +11990,13 @@ class RuntimeMediaStore {
|
|
|
11985
11990
|
const safeMessageId = safePathSegment(input.messageId || "message");
|
|
11986
11991
|
const baseFileName = sanitizeMediaFileName(input.fileName ?? "attachment", input.mimeType);
|
|
11987
11992
|
const dir = path6.join(this.rootDir, input.channelId, safeChatKey, safeMessageId);
|
|
11988
|
-
await
|
|
11993
|
+
await mkdir7(dir, { recursive: true });
|
|
11989
11994
|
const resolvedRoot = path6.resolve(this.rootDir);
|
|
11990
11995
|
const resolvedFile = path6.resolve(path6.join(dir, await uniqueFileName(dir, baseFileName)));
|
|
11991
11996
|
if (!isPathInside(resolvedFile, resolvedRoot)) {
|
|
11992
11997
|
throw new Error("media path escapes runtime media root");
|
|
11993
11998
|
}
|
|
11994
|
-
await
|
|
11999
|
+
await writeFile6(resolvedFile, input.buffer);
|
|
11995
12000
|
return {
|
|
11996
12001
|
kind: input.kind,
|
|
11997
12002
|
filePath: resolvedFile,
|
|
@@ -12103,7 +12108,7 @@ var init_media_store = __esm(() => {
|
|
|
12103
12108
|
});
|
|
12104
12109
|
|
|
12105
12110
|
// src/channels/outbound-media-safety.ts
|
|
12106
|
-
import
|
|
12111
|
+
import fs5 from "node:fs/promises";
|
|
12107
12112
|
import path7 from "node:path";
|
|
12108
12113
|
async function resolveSafeOutboundMediaPath(mediaPath, allowedRoots) {
|
|
12109
12114
|
if (mediaPath.startsWith("http://") || mediaPath.startsWith("https://")) {
|
|
@@ -12114,7 +12119,7 @@ async function resolveSafeOutboundMediaPath(mediaPath, allowedRoots) {
|
|
|
12114
12119
|
if (!realCandidate) {
|
|
12115
12120
|
return null;
|
|
12116
12121
|
}
|
|
12117
|
-
const stat2 = await
|
|
12122
|
+
const stat2 = await fs5.stat(realCandidate).catch(() => null);
|
|
12118
12123
|
if (!stat2?.isFile()) {
|
|
12119
12124
|
return null;
|
|
12120
12125
|
}
|
|
@@ -12128,7 +12133,7 @@ async function resolveSafeOutboundMediaPath(mediaPath, allowedRoots) {
|
|
|
12128
12133
|
}
|
|
12129
12134
|
async function realpathOrNull(filePath) {
|
|
12130
12135
|
try {
|
|
12131
|
-
return await
|
|
12136
|
+
return await fs5.realpath(filePath);
|
|
12132
12137
|
} catch {
|
|
12133
12138
|
return null;
|
|
12134
12139
|
}
|
|
@@ -12824,10 +12829,10 @@ var init_cdn_upload = __esm(() => {
|
|
|
12824
12829
|
|
|
12825
12830
|
// src/weixin/cdn/upload.ts
|
|
12826
12831
|
import crypto3 from "node:crypto";
|
|
12827
|
-
import
|
|
12832
|
+
import fs6 from "node:fs/promises";
|
|
12828
12833
|
async function uploadMediaToCdn(params) {
|
|
12829
12834
|
const { filePath, toUserId, opts, cdnBaseUrl, mediaType, label } = params;
|
|
12830
|
-
const plaintext = await
|
|
12835
|
+
const plaintext = await fs6.readFile(filePath);
|
|
12831
12836
|
const rawsize = plaintext.length;
|
|
12832
12837
|
const rawfilemd5 = crypto3.createHash("md5").update(plaintext).digest("hex");
|
|
12833
12838
|
const filesize = aesEcbPaddedSize(rawsize);
|
|
@@ -12947,14 +12952,14 @@ var init_send_media = __esm(() => {
|
|
|
12947
12952
|
});
|
|
12948
12953
|
|
|
12949
12954
|
// src/weixin/messaging/debug-mode.ts
|
|
12950
|
-
import
|
|
12955
|
+
import fs7 from "node:fs";
|
|
12951
12956
|
import path10 from "node:path";
|
|
12952
12957
|
function resolveDebugModePath() {
|
|
12953
12958
|
return path10.join(resolveStateDir(), "openclaw-weixin", "debug-mode.json");
|
|
12954
12959
|
}
|
|
12955
12960
|
function loadState() {
|
|
12956
12961
|
try {
|
|
12957
|
-
const raw =
|
|
12962
|
+
const raw = fs7.readFileSync(resolveDebugModePath(), "utf-8");
|
|
12958
12963
|
const parsed = JSON.parse(raw);
|
|
12959
12964
|
if (parsed && typeof parsed.accounts === "object")
|
|
12960
12965
|
return parsed;
|
|
@@ -12963,8 +12968,8 @@ function loadState() {
|
|
|
12963
12968
|
}
|
|
12964
12969
|
function saveState(state) {
|
|
12965
12970
|
const filePath = resolveDebugModePath();
|
|
12966
|
-
|
|
12967
|
-
|
|
12971
|
+
ensureDirSync(path10.dirname(filePath));
|
|
12972
|
+
fs7.writeFileSync(filePath, JSON.stringify(state, null, 2), "utf-8");
|
|
12968
12973
|
}
|
|
12969
12974
|
function toggleDebugMode(accountId) {
|
|
12970
12975
|
const state = loadState();
|
|
@@ -12978,6 +12983,7 @@ function toggleDebugMode(accountId) {
|
|
|
12978
12983
|
return next;
|
|
12979
12984
|
}
|
|
12980
12985
|
var init_debug_mode = __esm(() => {
|
|
12986
|
+
init_ensure_dir();
|
|
12981
12987
|
init_state_dir();
|
|
12982
12988
|
init_logger();
|
|
12983
12989
|
});
|
|
@@ -13130,7 +13136,7 @@ function normalizeMediaArray(media) {
|
|
|
13130
13136
|
|
|
13131
13137
|
// src/weixin/messaging/handle-weixin-message-turn.ts
|
|
13132
13138
|
import crypto4 from "node:crypto";
|
|
13133
|
-
import
|
|
13139
|
+
import fs8 from "node:fs/promises";
|
|
13134
13140
|
import { tmpdir } from "node:os";
|
|
13135
13141
|
import path11 from "node:path";
|
|
13136
13142
|
function utf8ByteLength(s) {
|
|
@@ -13230,7 +13236,7 @@ function createSaveMediaBuffer(mediaTempDir) {
|
|
|
13230
13236
|
throw new Error(`media exceeds ${maxBytes} bytes`);
|
|
13231
13237
|
}
|
|
13232
13238
|
const dir = path11.join(resolveMediaTempDir(mediaTempDir), subdir ?? "");
|
|
13233
|
-
await
|
|
13239
|
+
await fs8.mkdir(dir, { recursive: true });
|
|
13234
13240
|
let ext = ".bin";
|
|
13235
13241
|
if (originalFilename) {
|
|
13236
13242
|
ext = path11.extname(originalFilename) || ".bin";
|
|
@@ -13239,7 +13245,7 @@ function createSaveMediaBuffer(mediaTempDir) {
|
|
|
13239
13245
|
}
|
|
13240
13246
|
const name = `${Date.now()}-${crypto4.randomBytes(4).toString("hex")}${ext}`;
|
|
13241
13247
|
const filePath = path11.join(dir, name);
|
|
13242
|
-
await
|
|
13248
|
+
await fs8.writeFile(filePath, buffer);
|
|
13243
13249
|
return { path: filePath };
|
|
13244
13250
|
};
|
|
13245
13251
|
}
|
|
@@ -13379,7 +13385,7 @@ async function handleWeixinMessageTurn(full, deps) {
|
|
|
13379
13385
|
continue;
|
|
13380
13386
|
}
|
|
13381
13387
|
try {
|
|
13382
|
-
const buffer = await
|
|
13388
|
+
const buffer = await fs8.readFile(filePath);
|
|
13383
13389
|
const mimeType = downloaded.fileMediaType ?? downloaded.voiceMediaType ?? defaultWeixinMime(descriptor.kind);
|
|
13384
13390
|
media.push(await mediaStore.saveMediaBuffer({
|
|
13385
13391
|
channelId: "weixin",
|
|
@@ -13393,7 +13399,7 @@ async function handleWeixinMessageTurn(full, deps) {
|
|
|
13393
13399
|
maxBytes: descriptor.kind === "image" ? DEFAULT_IMAGE_MAX_BYTES : DEFAULT_ATTACHMENT_MAX_BYTES
|
|
13394
13400
|
}));
|
|
13395
13401
|
} finally {
|
|
13396
|
-
await
|
|
13402
|
+
await fs8.rm(filePath, { force: true }).catch(() => {});
|
|
13397
13403
|
}
|
|
13398
13404
|
} catch (err) {
|
|
13399
13405
|
deps.errLog(`media download failed: ${String(err)}`);
|
|
@@ -13565,7 +13571,7 @@ var init_handle_weixin_message_turn = __esm(() => {
|
|
|
13565
13571
|
});
|
|
13566
13572
|
|
|
13567
13573
|
// src/weixin/storage/sync-buf.ts
|
|
13568
|
-
import
|
|
13574
|
+
import fs9 from "node:fs";
|
|
13569
13575
|
import path12 from "node:path";
|
|
13570
13576
|
function resolveAccountsDir2() {
|
|
13571
13577
|
return path12.join(resolveStateDir(), "openclaw-weixin", "accounts");
|
|
@@ -13578,7 +13584,7 @@ function getLegacySyncBufDefaultJsonPath() {
|
|
|
13578
13584
|
}
|
|
13579
13585
|
function readSyncBufFile(filePath) {
|
|
13580
13586
|
try {
|
|
13581
|
-
const raw =
|
|
13587
|
+
const raw = fs9.readFileSync(filePath, "utf-8");
|
|
13582
13588
|
const data = JSON.parse(raw);
|
|
13583
13589
|
if (typeof data.get_updates_buf === "string") {
|
|
13584
13590
|
return data.get_updates_buf;
|
|
@@ -13602,11 +13608,12 @@ function loadGetUpdatesBuf(filePath) {
|
|
|
13602
13608
|
}
|
|
13603
13609
|
function saveGetUpdatesBuf(filePath, getUpdatesBuf) {
|
|
13604
13610
|
const dir = path12.dirname(filePath);
|
|
13605
|
-
|
|
13606
|
-
|
|
13611
|
+
ensureDirSync(dir);
|
|
13612
|
+
fs9.writeFileSync(filePath, JSON.stringify({ get_updates_buf: getUpdatesBuf }, null, 0), "utf-8");
|
|
13607
13613
|
}
|
|
13608
13614
|
var init_sync_buf = __esm(() => {
|
|
13609
13615
|
init_accounts();
|
|
13616
|
+
init_ensure_dir();
|
|
13610
13617
|
init_state_dir();
|
|
13611
13618
|
});
|
|
13612
13619
|
|
|
@@ -14148,16 +14155,16 @@ var init_deliver_coordinator_message = __esm(() => {
|
|
|
14148
14155
|
});
|
|
14149
14156
|
|
|
14150
14157
|
// src/weixin/monitor/consumer-lock.ts
|
|
14151
|
-
import { mkdir as
|
|
14152
|
-
import { dirname as dirname6, join as
|
|
14153
|
-
import { homedir as
|
|
14158
|
+
import { mkdir as mkdir8, open as open2, readFile as readFile6, rm as rm5 } from "node:fs/promises";
|
|
14159
|
+
import { dirname as dirname6, join as join4 } from "node:path";
|
|
14160
|
+
import { homedir as homedir4 } from "node:os";
|
|
14154
14161
|
function createWeixinConsumerLock(options = {}) {
|
|
14155
|
-
const lockFilePath = options.lockFilePath ??
|
|
14162
|
+
const lockFilePath = options.lockFilePath ?? join4(homedir4(), ".weacpx", "runtime", "weixin-consumer.lock.json");
|
|
14156
14163
|
const isProcessRunning = options.isProcessRunning ?? defaultIsProcessRunning4;
|
|
14157
14164
|
const onDiagnostic = options.onDiagnostic;
|
|
14158
14165
|
return {
|
|
14159
14166
|
async acquire(meta2) {
|
|
14160
|
-
await
|
|
14167
|
+
await mkdir8(dirname6(lockFilePath), { recursive: true });
|
|
14161
14168
|
while (true) {
|
|
14162
14169
|
try {
|
|
14163
14170
|
const handle = await open2(lockFilePath, "wx");
|
|
@@ -14550,27 +14557,74 @@ var init_create_channel = __esm(() => {
|
|
|
14550
14557
|
channelFactories = new Map;
|
|
14551
14558
|
});
|
|
14552
14559
|
|
|
14553
|
-
// src/
|
|
14554
|
-
|
|
14555
|
-
|
|
14556
|
-
|
|
14557
|
-
|
|
14558
|
-
|
|
14559
|
-
|
|
14560
|
-
|
|
14561
|
-
|
|
14562
|
-
|
|
14563
|
-
|
|
14560
|
+
// src/channels/cli/weixin-provider.ts
|
|
14561
|
+
var weixinCliProvider;
|
|
14562
|
+
var init_weixin_provider = __esm(() => {
|
|
14563
|
+
weixinCliProvider = {
|
|
14564
|
+
type: "weixin",
|
|
14565
|
+
displayName: "Weixin",
|
|
14566
|
+
supportsLogin: true,
|
|
14567
|
+
parseAddArgs(args) {
|
|
14568
|
+
if (args.length > 0)
|
|
14569
|
+
return { ok: false, message: `unknown weixin options: ${args.join(" ")}` };
|
|
14570
|
+
return { ok: true, input: {} };
|
|
14571
|
+
},
|
|
14572
|
+
buildDefaultConfig(_input) {
|
|
14573
|
+
return { id: "weixin", type: "weixin", enabled: true };
|
|
14574
|
+
},
|
|
14575
|
+
validateConfig(config2) {
|
|
14576
|
+
const issues = [];
|
|
14577
|
+
if (config2.id !== "weixin")
|
|
14578
|
+
issues.push({ kind: "invalid-config", message: "weixin channel id must be weixin" });
|
|
14579
|
+
if (config2.type !== "weixin")
|
|
14580
|
+
issues.push({ kind: "invalid-config", message: "weixin channel type must be weixin" });
|
|
14581
|
+
return issues;
|
|
14582
|
+
},
|
|
14583
|
+
renderSummary(config2) {
|
|
14584
|
+
return [`type: ${config2.type}`, `enabled: ${config2.enabled}`];
|
|
14585
|
+
},
|
|
14586
|
+
async promptForMissingFields(input, _io) {
|
|
14587
|
+
return input;
|
|
14588
|
+
}
|
|
14589
|
+
};
|
|
14590
|
+
});
|
|
14591
|
+
|
|
14592
|
+
// src/channels/cli/registry.ts
|
|
14593
|
+
function registerChannelCliProvider(provider) {
|
|
14594
|
+
const type = provider.type.trim();
|
|
14595
|
+
if (!type)
|
|
14596
|
+
throw new Error("channel CLI provider type must be non-empty");
|
|
14597
|
+
if (type.includes(":"))
|
|
14598
|
+
throw new Error("channel CLI provider type must not contain ':'");
|
|
14599
|
+
if (cliProviders.has(type)) {
|
|
14600
|
+
throw new Error(`channel CLI provider is already registered: ${type}`);
|
|
14601
|
+
}
|
|
14602
|
+
cliProviders.set(type, provider);
|
|
14564
14603
|
}
|
|
14565
|
-
|
|
14566
|
-
|
|
14567
|
-
|
|
14568
|
-
`, { flag: "wx" }).catch((error2) => {
|
|
14569
|
-
if (error2.code !== "EEXIST")
|
|
14570
|
-
throw error2;
|
|
14571
|
-
});
|
|
14604
|
+
function hasChannelCliProvider(type) {
|
|
14605
|
+
bootstrapBuiltinChannelCliProviders();
|
|
14606
|
+
return cliProviders.has(type);
|
|
14572
14607
|
}
|
|
14573
|
-
|
|
14608
|
+
function bootstrapBuiltinChannelCliProviders() {
|
|
14609
|
+
if (builtinProvidersRegistered)
|
|
14610
|
+
return;
|
|
14611
|
+
builtinProvidersRegistered = true;
|
|
14612
|
+
if (!cliProviders.has(weixinCliProvider.type))
|
|
14613
|
+
registerChannelCliProvider(weixinCliProvider);
|
|
14614
|
+
}
|
|
14615
|
+
function listChannelCliProviders() {
|
|
14616
|
+
bootstrapBuiltinChannelCliProviders();
|
|
14617
|
+
return Array.from(cliProviders.values());
|
|
14618
|
+
}
|
|
14619
|
+
function getChannelCliProvider(type) {
|
|
14620
|
+
bootstrapBuiltinChannelCliProviders();
|
|
14621
|
+
return cliProviders.get(type) ?? null;
|
|
14622
|
+
}
|
|
14623
|
+
var cliProviders, builtinProvidersRegistered = false;
|
|
14624
|
+
var init_registry = __esm(() => {
|
|
14625
|
+
init_weixin_provider();
|
|
14626
|
+
cliProviders = new Map;
|
|
14627
|
+
});
|
|
14574
14628
|
|
|
14575
14629
|
// src/channels/plugin.ts
|
|
14576
14630
|
function registerChannelPlugin(plugin) {
|
|
@@ -14833,7 +14887,7 @@ var init_bootstrap = __esm(() => {
|
|
|
14833
14887
|
|
|
14834
14888
|
// src/logging/app-logger.ts
|
|
14835
14889
|
import { appendFile, mkdir as mkdir9, readdir as readdir2, rename, rm as rm6, stat as stat2 } from "node:fs/promises";
|
|
14836
|
-
import { basename, dirname as
|
|
14890
|
+
import { basename, dirname as dirname8, join as join9 } from "node:path";
|
|
14837
14891
|
function createNoopAppLogger() {
|
|
14838
14892
|
return {
|
|
14839
14893
|
debug: async () => {},
|
|
@@ -14873,7 +14927,7 @@ function createAppLogger(options) {
|
|
|
14873
14927
|
return;
|
|
14874
14928
|
}
|
|
14875
14929
|
const line = formatLogLine(now(), level, event, message, context);
|
|
14876
|
-
await mkdir9(
|
|
14930
|
+
await mkdir9(dirname8(options.filePath), { recursive: true });
|
|
14877
14931
|
await rotateIfNeeded(options.filePath, Buffer.byteLength(line), options.maxSizeBytes, options.maxFiles);
|
|
14878
14932
|
await appendFile(options.filePath, line, "utf8");
|
|
14879
14933
|
}
|
|
@@ -14911,7 +14965,7 @@ async function rotateIfNeeded(filePath, incomingSize, maxSizeBytes, maxFiles) {
|
|
|
14911
14965
|
await rename(filePath, `${filePath}.1`);
|
|
14912
14966
|
}
|
|
14913
14967
|
async function cleanupExpiredRotatedLogs(filePath, retentionDays, now) {
|
|
14914
|
-
const parentDir =
|
|
14968
|
+
const parentDir = dirname8(filePath);
|
|
14915
14969
|
const prefix = `${basename(filePath)}.`;
|
|
14916
14970
|
const cutoff = now().getTime() - retentionDays * 24 * 60 * 60 * 1000;
|
|
14917
14971
|
let files = [];
|
|
@@ -14927,7 +14981,7 @@ async function cleanupExpiredRotatedLogs(filePath, retentionDays, now) {
|
|
|
14927
14981
|
if (!file.startsWith(prefix) || !/^\d+$/.test(file.slice(prefix.length))) {
|
|
14928
14982
|
continue;
|
|
14929
14983
|
}
|
|
14930
|
-
const candidate =
|
|
14984
|
+
const candidate = join9(parentDir, file);
|
|
14931
14985
|
const details = await stat2(candidate);
|
|
14932
14986
|
if (details.mtime.getTime() < cutoff) {
|
|
14933
14987
|
await rm6(candidate, { force: true });
|
|
@@ -14962,7 +15016,7 @@ var init_app_logger = __esm(() => {
|
|
|
14962
15016
|
});
|
|
14963
15017
|
|
|
14964
15018
|
// src/transport/acpx-session-index.ts
|
|
14965
|
-
import { readFile as
|
|
15019
|
+
import { readFile as readFile10 } from "node:fs/promises";
|
|
14966
15020
|
import { homedir as homedir5 } from "node:os";
|
|
14967
15021
|
import { resolve as resolve2 } from "node:path";
|
|
14968
15022
|
async function resolveSessionAgentCommandFromIndex(session) {
|
|
@@ -14971,7 +15025,7 @@ async function resolveSessionAgentCommandFromIndex(session) {
|
|
|
14971
15025
|
return;
|
|
14972
15026
|
}
|
|
14973
15027
|
try {
|
|
14974
|
-
const raw = await
|
|
15028
|
+
const raw = await readFile10(resolve2(home, ".acpx", "sessions", "index.json"), "utf8");
|
|
14975
15029
|
const parsed = JSON.parse(raw);
|
|
14976
15030
|
const targetCwd = resolve2(session.cwd);
|
|
14977
15031
|
const match = parsed.entries?.find((entry) => entry.name === session.transportSession && entry.cwd === targetCwd && typeof entry.agentCommand === "string" && entry.agentCommand.trim().length > 0);
|
|
@@ -17285,37 +17339,6 @@ function isPartialPromptOutputError(message) {
|
|
|
17285
17339
|
return message.includes("未收到最终回复");
|
|
17286
17340
|
}
|
|
17287
17341
|
|
|
17288
|
-
// src/config/agent-templates.ts
|
|
17289
|
-
function getAgentTemplate(name) {
|
|
17290
|
-
const template = TEMPLATES[name];
|
|
17291
|
-
if (!template) {
|
|
17292
|
-
return null;
|
|
17293
|
-
}
|
|
17294
|
-
return {
|
|
17295
|
-
...template
|
|
17296
|
-
};
|
|
17297
|
-
}
|
|
17298
|
-
function listAgentTemplates() {
|
|
17299
|
-
return Object.keys(TEMPLATES);
|
|
17300
|
-
}
|
|
17301
|
-
var TEMPLATES;
|
|
17302
|
-
var init_agent_templates = __esm(() => {
|
|
17303
|
-
TEMPLATES = {
|
|
17304
|
-
codex: {
|
|
17305
|
-
driver: "codex"
|
|
17306
|
-
},
|
|
17307
|
-
claude: {
|
|
17308
|
-
driver: "claude"
|
|
17309
|
-
},
|
|
17310
|
-
opencode: {
|
|
17311
|
-
driver: "opencode"
|
|
17312
|
-
},
|
|
17313
|
-
gemini: {
|
|
17314
|
-
driver: "gemini"
|
|
17315
|
-
}
|
|
17316
|
-
};
|
|
17317
|
-
});
|
|
17318
|
-
|
|
17319
17342
|
// src/commands/handlers/agent-handler.ts
|
|
17320
17343
|
function handleAgents(context) {
|
|
17321
17344
|
return { text: context.config ? renderAgents(context.config) : "No config loaded." };
|
|
@@ -17771,11 +17794,11 @@ var init_session_recovery_handler = __esm(() => {
|
|
|
17771
17794
|
});
|
|
17772
17795
|
|
|
17773
17796
|
// src/recovery/auto-install-optional-dep.ts
|
|
17774
|
-
import { spawn as
|
|
17797
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
17775
17798
|
import { createWriteStream } from "node:fs";
|
|
17776
17799
|
import { mkdir as mkdir10 } from "node:fs/promises";
|
|
17777
17800
|
import { homedir as homedir6 } from "node:os";
|
|
17778
|
-
import { join as
|
|
17801
|
+
import { join as join10 } from "node:path";
|
|
17779
17802
|
async function autoInstallOptionalDep(pkg, parentPackages, options = {}) {
|
|
17780
17803
|
const runCli = options.runCli ?? defaultRunCli;
|
|
17781
17804
|
const openLog = options.openLog ?? defaultLogSink;
|
|
@@ -17854,7 +17877,7 @@ function tail(text, lines) {
|
|
|
17854
17877
|
}
|
|
17855
17878
|
var PRECISE_TIMEOUT_MS = 90000, GLOBAL_TIMEOUT_MS = 90000, TAIL_LINES = 10, PRECISE_COMMANDS, defaultRunCli = async (cmd, args, options) => {
|
|
17856
17879
|
return await new Promise((resolve3) => {
|
|
17857
|
-
const child =
|
|
17880
|
+
const child = spawn5(cmd, args, {
|
|
17858
17881
|
cwd: options.cwd,
|
|
17859
17882
|
stdio: ["ignore", "pipe", "pipe"],
|
|
17860
17883
|
shell: process.platform === "win32"
|
|
@@ -17890,10 +17913,10 @@ ${err.message}`, reason: "spawn" });
|
|
|
17890
17913
|
});
|
|
17891
17914
|
});
|
|
17892
17915
|
}, defaultLogSink = async () => {
|
|
17893
|
-
const dir =
|
|
17916
|
+
const dir = join10(homedir6(), ".weacpx", "logs");
|
|
17894
17917
|
await mkdir10(dir, { recursive: true });
|
|
17895
17918
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "").replace(/-/g, "");
|
|
17896
|
-
const path13 =
|
|
17919
|
+
const path13 = join10(dir, `auto-install-${timestamp}.log`);
|
|
17897
17920
|
const stream = createWriteStream(path13, { flags: "a" });
|
|
17898
17921
|
return {
|
|
17899
17922
|
path: path13,
|
|
@@ -17915,11 +17938,11 @@ var init_auto_install_optional_dep = __esm(() => {
|
|
|
17915
17938
|
});
|
|
17916
17939
|
|
|
17917
17940
|
// src/recovery/discover-parent-package-paths.ts
|
|
17918
|
-
import { spawn as
|
|
17941
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
17919
17942
|
import { createRequire as createRequire3 } from "node:module";
|
|
17920
17943
|
import { access as access3 } from "node:fs/promises";
|
|
17921
17944
|
import { homedir as homedir7 } from "node:os";
|
|
17922
|
-
import { dirname as
|
|
17945
|
+
import { dirname as dirname9, join as join11 } from "node:path";
|
|
17923
17946
|
function deriveParentPackageName(platformPackage) {
|
|
17924
17947
|
return platformPackage.replace(/-(?:linux|darwin|win32|windows|freebsd|openbsd|sunos|aix)(?:-(?:x64|arm64|ia32|arm|ppc64|s390x))?(?:-(?:baseline|musl|gnu|gnueabihf|musleabihf|msvc))?$/, "");
|
|
17925
17948
|
}
|
|
@@ -17932,7 +17955,7 @@ async function discoverParentPackagePaths(platformPackage, seedPath, deps = {})
|
|
|
17932
17955
|
const queryRoot = deps.queryPackageManagerRoot ?? defaultQueryPackageManagerRoot;
|
|
17933
17956
|
const parentName = deriveParentPackageName(platformPackage);
|
|
17934
17957
|
const rawCandidates = [];
|
|
17935
|
-
const bunGlobalRoot = env.BUN_INSTALL ?
|
|
17958
|
+
const bunGlobalRoot = env.BUN_INSTALL ? join11(env.BUN_INSTALL, "install", "global", "node_modules") : join11(home, ".bun", "install", "global", "node_modules");
|
|
17936
17959
|
const [npmRoot, pnpmRoot, yarnRoot] = await Promise.all([
|
|
17937
17960
|
queryRoot("npm"),
|
|
17938
17961
|
queryRoot("pnpm"),
|
|
@@ -17955,20 +17978,20 @@ async function discoverParentPackagePaths(platformPackage, seedPath, deps = {})
|
|
|
17955
17978
|
if (resolved)
|
|
17956
17979
|
rawCandidates.push({ path: resolved, manager: classify(resolved) });
|
|
17957
17980
|
}
|
|
17958
|
-
rawCandidates.push({ path:
|
|
17981
|
+
rawCandidates.push({ path: join11(bunGlobalRoot, parentName), manager: "bun" });
|
|
17959
17982
|
if (npmRoot)
|
|
17960
|
-
rawCandidates.push({ path:
|
|
17983
|
+
rawCandidates.push({ path: join11(npmRoot, parentName), manager: "npm" });
|
|
17961
17984
|
if (pnpmRoot)
|
|
17962
|
-
rawCandidates.push({ path:
|
|
17985
|
+
rawCandidates.push({ path: join11(pnpmRoot, parentName), manager: "pnpm" });
|
|
17963
17986
|
if (yarnRoot)
|
|
17964
|
-
rawCandidates.push({ path:
|
|
17987
|
+
rawCandidates.push({ path: join11(yarnRoot, parentName), manager: "yarn" });
|
|
17965
17988
|
const seen = new Set;
|
|
17966
17989
|
const verified = [];
|
|
17967
17990
|
for (const candidate of rawCandidates) {
|
|
17968
17991
|
if (seen.has(candidate.path))
|
|
17969
17992
|
continue;
|
|
17970
17993
|
seen.add(candidate.path);
|
|
17971
|
-
if (await fsExists(
|
|
17994
|
+
if (await fsExists(join11(candidate.path, "package.json"))) {
|
|
17972
17995
|
verified.push(candidate);
|
|
17973
17996
|
}
|
|
17974
17997
|
}
|
|
@@ -17992,7 +18015,7 @@ function defaultResolveFromCwd(name, cwd) {
|
|
|
17992
18015
|
const pkgJson = require2.resolve(`${name}/package.json`, {
|
|
17993
18016
|
paths: [cwd, ...require2.resolve.paths(name) ?? []]
|
|
17994
18017
|
});
|
|
17995
|
-
return
|
|
18018
|
+
return dirname9(pkgJson);
|
|
17996
18019
|
} catch {
|
|
17997
18020
|
return null;
|
|
17998
18021
|
}
|
|
@@ -18009,7 +18032,7 @@ async function defaultQueryPackageManagerRoot(tool) {
|
|
|
18009
18032
|
};
|
|
18010
18033
|
let child;
|
|
18011
18034
|
try {
|
|
18012
|
-
child =
|
|
18035
|
+
child = spawn6(spec.cmd, spec.args, {
|
|
18013
18036
|
stdio: ["ignore", "pipe", "pipe"],
|
|
18014
18037
|
shell: process.platform === "win32"
|
|
18015
18038
|
});
|
|
@@ -18039,7 +18062,7 @@ async function defaultQueryPackageManagerRoot(tool) {
|
|
|
18039
18062
|
const trimmed = stdout2.trim().split(/\r?\n/).pop()?.trim() ?? "";
|
|
18040
18063
|
if (!trimmed)
|
|
18041
18064
|
return done(null);
|
|
18042
|
-
done(spec.postfix ?
|
|
18065
|
+
done(spec.postfix ? join11(trimmed, spec.postfix) : trimmed);
|
|
18043
18066
|
});
|
|
18044
18067
|
});
|
|
18045
18068
|
}
|
|
@@ -22605,6 +22628,7 @@ async function runConsole(paths, deps) {
|
|
|
22605
22628
|
let heartbeatTimer = null;
|
|
22606
22629
|
let gcResetTimer = null;
|
|
22607
22630
|
let consumerLockAcquired = false;
|
|
22631
|
+
let daemonRuntimeStarted = false;
|
|
22608
22632
|
const shutdownController = new AbortController;
|
|
22609
22633
|
const signalHandler = () => {
|
|
22610
22634
|
shutdownController.abort();
|
|
@@ -22613,6 +22637,9 @@ async function runConsole(paths, deps) {
|
|
|
22613
22637
|
addProcessListener("SIGTERM", signalHandler);
|
|
22614
22638
|
try {
|
|
22615
22639
|
runtime = await deps.buildApp(paths);
|
|
22640
|
+
if (deps.afterBuild) {
|
|
22641
|
+
await deps.afterBuild(runtime);
|
|
22642
|
+
}
|
|
22616
22643
|
try {
|
|
22617
22644
|
await runtime.orchestration.service.purgeExpiredResetCoordinators({
|
|
22618
22645
|
cutoffDays: 7,
|
|
@@ -22620,20 +22647,6 @@ async function runConsole(paths, deps) {
|
|
|
22620
22647
|
});
|
|
22621
22648
|
} catch {}
|
|
22622
22649
|
consumerLock = deps.consumerLock ?? deps.consumerLockFactory?.(runtime);
|
|
22623
|
-
if (deps.daemonRuntime) {
|
|
22624
|
-
await deps.daemonRuntime.start({
|
|
22625
|
-
configPath: paths.configPath,
|
|
22626
|
-
statePath: paths.statePath
|
|
22627
|
-
});
|
|
22628
|
-
await runtime.orchestration.server.start();
|
|
22629
|
-
heartbeatTimer = setIntervalFn(() => {
|
|
22630
|
-
deps.daemonRuntime?.heartbeat().catch(() => {});
|
|
22631
|
-
}, deps.heartbeatIntervalMs ?? 30000);
|
|
22632
|
-
const runtimeForGc = runtime;
|
|
22633
|
-
gcResetTimer = setIntervalFn(() => {
|
|
22634
|
-
runtimeForGc.orchestration.service.purgeExpiredResetCoordinators({ cutoffDays: 7, trigger: "interval" }).catch(() => {});
|
|
22635
|
-
}, 86400000);
|
|
22636
|
-
}
|
|
22637
22650
|
if (consumerLock) {
|
|
22638
22651
|
const lockMeta = {
|
|
22639
22652
|
pid: processPid,
|
|
@@ -22681,6 +22694,24 @@ async function runConsole(paths, deps) {
|
|
|
22681
22694
|
throw error2;
|
|
22682
22695
|
}
|
|
22683
22696
|
}
|
|
22697
|
+
if (deps.beforeReady) {
|
|
22698
|
+
await deps.beforeReady(runtime);
|
|
22699
|
+
}
|
|
22700
|
+
if (deps.daemonRuntime) {
|
|
22701
|
+
await deps.daemonRuntime.start({
|
|
22702
|
+
configPath: paths.configPath,
|
|
22703
|
+
statePath: paths.statePath
|
|
22704
|
+
});
|
|
22705
|
+
daemonRuntimeStarted = true;
|
|
22706
|
+
await runtime.orchestration.server.start();
|
|
22707
|
+
heartbeatTimer = setIntervalFn(() => {
|
|
22708
|
+
deps.daemonRuntime?.heartbeat().catch(() => {});
|
|
22709
|
+
}, deps.heartbeatIntervalMs ?? 30000);
|
|
22710
|
+
const runtimeForGc = runtime;
|
|
22711
|
+
gcResetTimer = setIntervalFn(() => {
|
|
22712
|
+
runtimeForGc.orchestration.service.purgeExpiredResetCoordinators({ cutoffDays: 7, trigger: "interval" }).catch(() => {});
|
|
22713
|
+
}, 86400000);
|
|
22714
|
+
}
|
|
22684
22715
|
await deps.channels.startAll({
|
|
22685
22716
|
agent: runtime.agent,
|
|
22686
22717
|
abortSignal: shutdownController.signal,
|
|
@@ -22699,7 +22730,8 @@ async function runConsole(paths, deps) {
|
|
|
22699
22730
|
consumerLock,
|
|
22700
22731
|
consumerLockAcquired,
|
|
22701
22732
|
processPid,
|
|
22702
|
-
channels: deps.channels
|
|
22733
|
+
channels: deps.channels,
|
|
22734
|
+
daemonRuntimeStarted
|
|
22703
22735
|
});
|
|
22704
22736
|
}
|
|
22705
22737
|
}
|
|
@@ -22734,7 +22766,7 @@ async function runCleanupSequence(input) {
|
|
|
22734
22766
|
cleanupError ??= error2;
|
|
22735
22767
|
}
|
|
22736
22768
|
}
|
|
22737
|
-
if (input.daemonRuntime) {
|
|
22769
|
+
if (input.daemonRuntime && input.daemonRuntimeStarted) {
|
|
22738
22770
|
try {
|
|
22739
22771
|
await input.daemonRuntime.stop();
|
|
22740
22772
|
} catch (error2) {
|
|
@@ -22784,8 +22816,8 @@ function encodeBridgeSessionNoteEvent(event) {
|
|
|
22784
22816
|
}
|
|
22785
22817
|
|
|
22786
22818
|
// src/transport/acpx-bridge/acpx-bridge-client.ts
|
|
22787
|
-
import { spawn as
|
|
22788
|
-
import { fileURLToPath as
|
|
22819
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
22820
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
22789
22821
|
import { createInterface } from "node:readline";
|
|
22790
22822
|
|
|
22791
22823
|
class AcpxBridgeClient {
|
|
@@ -22905,12 +22937,12 @@ function buildBridgeSpawnSpec(options) {
|
|
|
22905
22937
|
};
|
|
22906
22938
|
}
|
|
22907
22939
|
async function spawnAcpxBridgeClient(options = {}) {
|
|
22908
|
-
const bridgeEntryPath = options.bridgeEntryPath ??
|
|
22940
|
+
const bridgeEntryPath = options.bridgeEntryPath ?? fileURLToPath3(new URL("../../bridge/bridge-main.ts", import.meta.url));
|
|
22909
22941
|
const spawnSpec = buildBridgeSpawnSpec({
|
|
22910
22942
|
execPath: process.execPath,
|
|
22911
22943
|
bridgeEntryPath
|
|
22912
22944
|
});
|
|
22913
|
-
const child =
|
|
22945
|
+
const child = spawn7(spawnSpec.command, spawnSpec.args, {
|
|
22914
22946
|
cwd: options.cwd ?? process.cwd(),
|
|
22915
22947
|
env: {
|
|
22916
22948
|
...process.env,
|
|
@@ -23724,12 +23756,12 @@ var init_streaming_prompt = __esm(() => {
|
|
|
23724
23756
|
|
|
23725
23757
|
// src/transport/acpx-cli/node-pty-helper.ts
|
|
23726
23758
|
import { chmod as chmodFs } from "node:fs/promises";
|
|
23727
|
-
import { dirname as
|
|
23759
|
+
import { dirname as dirname10, join as join12 } from "node:path";
|
|
23728
23760
|
function resolveNodePtyHelperPath(packageJsonPath, platform, arch) {
|
|
23729
23761
|
if (platform === "win32") {
|
|
23730
23762
|
return null;
|
|
23731
23763
|
}
|
|
23732
|
-
return
|
|
23764
|
+
return join12(dirname10(packageJsonPath), "prebuilds", `${platform}-${arch}`, "spawn-helper");
|
|
23733
23765
|
}
|
|
23734
23766
|
async function ensureNodePtyHelperExecutable(helperPath, chmod2 = chmodFs) {
|
|
23735
23767
|
if (!helperPath) {
|
|
@@ -23748,10 +23780,10 @@ var init_node_pty_helper = () => {};
|
|
|
23748
23780
|
|
|
23749
23781
|
// src/transport/acpx-queue-owner-launcher.ts
|
|
23750
23782
|
import { createHash as createHash3 } from "node:crypto";
|
|
23751
|
-
import { spawn as
|
|
23752
|
-
import { readFile as
|
|
23783
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
23784
|
+
import { readFile as readFile11, unlink } from "node:fs/promises";
|
|
23753
23785
|
import { homedir as homedir8 } from "node:os";
|
|
23754
|
-
import { join as
|
|
23786
|
+
import { join as join13 } from "node:path";
|
|
23755
23787
|
function buildWeacpxMcpServerSpec(input) {
|
|
23756
23788
|
const { command, args } = splitCommandLine(input.weacpxCommand);
|
|
23757
23789
|
return {
|
|
@@ -23881,7 +23913,7 @@ function stringEnv(env) {
|
|
|
23881
23913
|
}
|
|
23882
23914
|
async function defaultQueueOwnerSpawner(command, args, options) {
|
|
23883
23915
|
await new Promise((resolve3, reject) => {
|
|
23884
|
-
const child =
|
|
23916
|
+
const child = spawn8(command, args, {
|
|
23885
23917
|
detached: true,
|
|
23886
23918
|
stdio: "ignore",
|
|
23887
23919
|
env: options.env,
|
|
@@ -23903,7 +23935,7 @@ async function terminateAcpxQueueOwner(sessionId) {
|
|
|
23903
23935
|
const lockPath = queueLockFilePath(sessionId);
|
|
23904
23936
|
let owner;
|
|
23905
23937
|
try {
|
|
23906
|
-
owner = JSON.parse(await
|
|
23938
|
+
owner = JSON.parse(await readFile11(lockPath, "utf8"));
|
|
23907
23939
|
} catch {
|
|
23908
23940
|
return;
|
|
23909
23941
|
}
|
|
@@ -23913,7 +23945,7 @@ async function terminateAcpxQueueOwner(sessionId) {
|
|
|
23913
23945
|
await unlink(lockPath).catch(() => {});
|
|
23914
23946
|
}
|
|
23915
23947
|
function queueLockFilePath(sessionId) {
|
|
23916
|
-
return
|
|
23948
|
+
return join13(homedir8(), ".acpx", "queues", `${shortHash(sessionId, 24)}.lock`);
|
|
23917
23949
|
}
|
|
23918
23950
|
function shortHash(value, length) {
|
|
23919
23951
|
return createHash3("sha256").update(value).digest("hex").slice(0, length);
|
|
@@ -23952,12 +23984,12 @@ function permissionModeToFlag(permissionMode) {
|
|
|
23952
23984
|
|
|
23953
23985
|
// src/transport/acpx-cli/acpx-cli-transport.ts
|
|
23954
23986
|
import { createRequire as createRequire5 } from "node:module";
|
|
23955
|
-
import { spawn as
|
|
23987
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
23956
23988
|
import { spawn as spawnPty } from "node-pty";
|
|
23957
23989
|
async function defaultRunner(command, args, options) {
|
|
23958
23990
|
return await new Promise((resolve3, reject) => {
|
|
23959
23991
|
const spawnSpec = resolveSpawnCommand(command, args);
|
|
23960
|
-
const child =
|
|
23992
|
+
const child = spawn9(spawnSpec.command, spawnSpec.args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
23961
23993
|
let stdout2 = "";
|
|
23962
23994
|
let stderr = "";
|
|
23963
23995
|
const onAbort = () => {
|
|
@@ -24204,7 +24236,7 @@ ${baseText}` : "" };
|
|
|
24204
24236
|
}
|
|
24205
24237
|
async runStreamingPrompt(command, args, reply, formatToolCalls = false, toolEventMode = "text", replyContext, onSegment, onToolEvent) {
|
|
24206
24238
|
const hooks = this.streamingHooks;
|
|
24207
|
-
const doSpawn = hooks.spawnPrompt ?? ((cmd, spawnArgs) =>
|
|
24239
|
+
const doSpawn = hooks.spawnPrompt ?? ((cmd, spawnArgs) => spawn9(cmd, spawnArgs, { stdio: ["ignore", "pipe", "pipe"] }));
|
|
24208
24240
|
const setIntervalFn = hooks.setIntervalFn ?? ((fn, delay) => setInterval(fn, delay));
|
|
24209
24241
|
const clearIntervalFn = hooks.clearIntervalFn ?? ((timer) => clearInterval(timer));
|
|
24210
24242
|
const maxSegmentWaitMs = hooks.maxSegmentWaitMs ?? 30000;
|
|
@@ -24564,8 +24596,8 @@ __export(exports_main, {
|
|
|
24564
24596
|
});
|
|
24565
24597
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
24566
24598
|
import { homedir as homedir9 } from "node:os";
|
|
24567
|
-
import { dirname as
|
|
24568
|
-
import { fileURLToPath as
|
|
24599
|
+
import { dirname as dirname11, join as join14 } from "node:path";
|
|
24600
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
24569
24601
|
function startProgressHeartbeat(orchestration, config2, logger2, channel) {
|
|
24570
24602
|
const thresholdSeconds = config2.orchestration.progressHeartbeatSeconds;
|
|
24571
24603
|
if (thresholdSeconds <= 0) {
|
|
@@ -24970,6 +25002,7 @@ async function buildApp(paths, deps = {}) {
|
|
|
24970
25002
|
configStore,
|
|
24971
25003
|
logger: logger2,
|
|
24972
25004
|
quota,
|
|
25005
|
+
transport,
|
|
24973
25006
|
orchestration: {
|
|
24974
25007
|
service: orchestration,
|
|
24975
25008
|
server: orchestrationServer,
|
|
@@ -25019,8 +25052,8 @@ async function main() {
|
|
|
25019
25052
|
}
|
|
25020
25053
|
}
|
|
25021
25054
|
async function prepareChannelMedia(configPath, config2) {
|
|
25022
|
-
const runtimeDir =
|
|
25023
|
-
const mediaRootDir =
|
|
25055
|
+
const runtimeDir = join14(dirname11(configPath), "runtime");
|
|
25056
|
+
const mediaRootDir = join14(runtimeDir, "media");
|
|
25024
25057
|
const mediaStore = new RuntimeMediaStore({ rootDir: mediaRootDir });
|
|
25025
25058
|
await mediaStore.cleanupExpired().catch((error2) => {
|
|
25026
25059
|
console.error("[weacpx] media cleanup failed:", error2 instanceof Error ? error2.message : String(error2));
|
|
@@ -25034,7 +25067,7 @@ function resolveRuntimePaths() {
|
|
|
25034
25067
|
throw new Error("Unable to resolve the current user home directory");
|
|
25035
25068
|
}
|
|
25036
25069
|
const configPath = process.env.WEACPX_CONFIG ?? `${home}/.weacpx/config.json`;
|
|
25037
|
-
const runtimeDir =
|
|
25070
|
+
const runtimeDir = join14(dirname11(configPath), "runtime");
|
|
25038
25071
|
return {
|
|
25039
25072
|
configPath,
|
|
25040
25073
|
statePath: process.env.WEACPX_STATE ?? `${home}/.weacpx/state.json`,
|
|
@@ -25043,14 +25076,14 @@ function resolveRuntimePaths() {
|
|
|
25043
25076
|
}
|
|
25044
25077
|
function resolveBridgeEntryPath() {
|
|
25045
25078
|
if (import.meta.url.includes("/dist/")) {
|
|
25046
|
-
return
|
|
25079
|
+
return fileURLToPath4(new URL("./bridge/bridge-main.js", import.meta.url));
|
|
25047
25080
|
}
|
|
25048
|
-
return
|
|
25081
|
+
return fileURLToPath4(new URL("./bridge/bridge-main.ts", import.meta.url));
|
|
25049
25082
|
}
|
|
25050
25083
|
function resolveAppLogPath(configPath) {
|
|
25051
|
-
const rootDir =
|
|
25052
|
-
const runtimeDir =
|
|
25053
|
-
return
|
|
25084
|
+
const rootDir = dirname11(configPath);
|
|
25085
|
+
const runtimeDir = join14(rootDir, "runtime");
|
|
25086
|
+
return join14(runtimeDir, "app.log");
|
|
25054
25087
|
}
|
|
25055
25088
|
function resolveOrchestrationSocketPathFromConfigPath(configPath) {
|
|
25056
25089
|
const runtimeDir = resolveRuntimeDirFromConfigPath(configPath);
|
|
@@ -25087,7 +25120,7 @@ var init_main = __esm(async () => {
|
|
|
25087
25120
|
});
|
|
25088
25121
|
|
|
25089
25122
|
// src/doctor/checks/acpx-check.ts
|
|
25090
|
-
import { spawn as
|
|
25123
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
25091
25124
|
async function checkAcpx(options = {}) {
|
|
25092
25125
|
const runtimePaths = (options.resolveRuntimePaths ?? resolveRuntimePaths)();
|
|
25093
25126
|
try {
|
|
@@ -25134,7 +25167,7 @@ function buildDetails(metadata, version2, verbose) {
|
|
|
25134
25167
|
async function defaultRunVersion(command) {
|
|
25135
25168
|
const spawnSpec = resolveSpawnCommand(command, ["--version"]);
|
|
25136
25169
|
return await new Promise((resolve3, reject) => {
|
|
25137
|
-
const child =
|
|
25170
|
+
const child = spawn10(spawnSpec.command, spawnSpec.args, {
|
|
25138
25171
|
stdio: ["ignore", "pipe", "pipe"]
|
|
25139
25172
|
});
|
|
25140
25173
|
let stdout2 = "";
|
|
@@ -25272,7 +25305,7 @@ var init_config_check = __esm(async () => {
|
|
|
25272
25305
|
});
|
|
25273
25306
|
|
|
25274
25307
|
// src/doctor/checks/daemon-check.ts
|
|
25275
|
-
import { fileURLToPath as
|
|
25308
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
25276
25309
|
import { homedir as homedir10 } from "node:os";
|
|
25277
25310
|
async function checkDaemon(options = {}) {
|
|
25278
25311
|
const home = options.home ?? process.env.HOME ?? homedir10();
|
|
@@ -25362,7 +25395,7 @@ function defaultIsProcessRunning5(pid) {
|
|
|
25362
25395
|
}
|
|
25363
25396
|
}
|
|
25364
25397
|
function resolveCliEntryPath() {
|
|
25365
|
-
return process.argv[1] ??
|
|
25398
|
+
return process.argv[1] ?? fileURLToPath5(import.meta.url);
|
|
25366
25399
|
}
|
|
25367
25400
|
function formatError5(error2) {
|
|
25368
25401
|
return error2 instanceof Error ? error2.message : String(error2);
|
|
@@ -25424,7 +25457,7 @@ async function checkOrchestrationHealth(options) {
|
|
|
25424
25457
|
// src/doctor/checks/runtime-check.ts
|
|
25425
25458
|
import { constants } from "node:fs";
|
|
25426
25459
|
import { access as access4, stat as stat3 } from "node:fs/promises";
|
|
25427
|
-
import { dirname as
|
|
25460
|
+
import { dirname as dirname12 } from "node:path";
|
|
25428
25461
|
import { homedir as homedir11 } from "node:os";
|
|
25429
25462
|
async function checkRuntime(options = {}) {
|
|
25430
25463
|
const home = options.home ?? process.env.HOME ?? homedir11();
|
|
@@ -25521,7 +25554,7 @@ async function checkFileCreatable(label, path14, probe, platform) {
|
|
|
25521
25554
|
detail: `${label}: ${path14} (unusable: ${formatError6(error2)})`
|
|
25522
25555
|
};
|
|
25523
25556
|
}
|
|
25524
|
-
const parentCheck = await checkCreatableAncestorDirectory(
|
|
25557
|
+
const parentCheck = await checkCreatableAncestorDirectory(dirname12(path14), probe, platform);
|
|
25525
25558
|
if (!parentCheck.ok) {
|
|
25526
25559
|
return {
|
|
25527
25560
|
ok: false,
|
|
@@ -25557,7 +25590,7 @@ async function checkCreatableAncestorDirectory(path14, probe, platform) {
|
|
|
25557
25590
|
blockingPath: path14
|
|
25558
25591
|
};
|
|
25559
25592
|
}
|
|
25560
|
-
const parent =
|
|
25593
|
+
const parent = dirname12(path14);
|
|
25561
25594
|
if (parent === path14) {
|
|
25562
25595
|
return {
|
|
25563
25596
|
ok: false,
|
|
@@ -25980,7 +26013,7 @@ var init_render_doctor = __esm(() => {
|
|
|
25980
26013
|
|
|
25981
26014
|
// src/doctor/doctor.ts
|
|
25982
26015
|
import { homedir as homedir12 } from "node:os";
|
|
25983
|
-
import { join as
|
|
26016
|
+
import { join as join15 } from "node:path";
|
|
25984
26017
|
async function runDoctor(options = {}, deps = {}) {
|
|
25985
26018
|
const home = deps.home ?? process.env.HOME ?? homedir12();
|
|
25986
26019
|
const runtimePaths = resolveDoctorRuntimePaths(home, deps.resolveRuntimePaths);
|
|
@@ -26033,8 +26066,8 @@ function resolveDoctorRuntimePaths(home, resolver) {
|
|
|
26033
26066
|
return resolveRuntimePaths();
|
|
26034
26067
|
}
|
|
26035
26068
|
return {
|
|
26036
|
-
configPath:
|
|
26037
|
-
statePath:
|
|
26069
|
+
configPath: join15(home, ".weacpx", "config.json"),
|
|
26070
|
+
statePath: join15(home, ".weacpx", "state.json")
|
|
26038
26071
|
};
|
|
26039
26072
|
}
|
|
26040
26073
|
function depsUseExplicitRuntimeOverrides() {
|
|
@@ -26140,7 +26173,7 @@ init_daemon_files();
|
|
|
26140
26173
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
26141
26174
|
import { homedir as homedir13 } from "node:os";
|
|
26142
26175
|
import { sep } from "node:path";
|
|
26143
|
-
import { fileURLToPath as
|
|
26176
|
+
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
26144
26177
|
|
|
26145
26178
|
// src/daemon/daemon-runtime.ts
|
|
26146
26179
|
init_daemon_status();
|
|
@@ -38874,7 +38907,7 @@ async function asToolResult(action) {
|
|
|
38874
38907
|
text: "Outbound budget exhausted; the action has been recorded as pending and will retry automatically after the next user inbound resets the quota window. No further action required."
|
|
38875
38908
|
}
|
|
38876
38909
|
],
|
|
38877
|
-
structuredContent: { status: "deferred_quota"
|
|
38910
|
+
structuredContent: { status: "deferred_quota" },
|
|
38878
38911
|
isError: false
|
|
38879
38912
|
};
|
|
38880
38913
|
}
|
|
@@ -39085,7 +39118,9 @@ function renderCoordinatorReviewContestedResultSuccess(task, decision) {
|
|
|
39085
39118
|
}
|
|
39086
39119
|
function formatToolError(error2) {
|
|
39087
39120
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
39088
|
-
|
|
39121
|
+
const code = typeof error2 === "object" && error2 !== null && "code" in error2 ? error2.code : undefined;
|
|
39122
|
+
const isConnectionError = code === "ECONNREFUSED" || code === "ENOENT" || code === "ECONNRESET" || code === "EPIPE" || /server closed without a response|socket hang up/i.test(message);
|
|
39123
|
+
if (isConnectionError) {
|
|
39089
39124
|
return `Failed to connect to the orchestration daemon: ${message}`;
|
|
39090
39125
|
}
|
|
39091
39126
|
return message;
|
|
@@ -39246,9 +39281,9 @@ function createOrchestrationTransport(endpoint, deps = {}) {
|
|
|
39246
39281
|
sourceHandle: input.sourceHandle ?? input.coordinatorSession,
|
|
39247
39282
|
targetAgent: input.targetAgent,
|
|
39248
39283
|
task: input.task,
|
|
39249
|
-
...input.workingDirectory ? { cwd: input.workingDirectory } : {},
|
|
39250
|
-
...input.role ? { role: input.role } : {},
|
|
39251
|
-
...input.groupId ? { groupId: input.groupId } : {}
|
|
39284
|
+
...input.workingDirectory !== undefined ? { cwd: input.workingDirectory } : {},
|
|
39285
|
+
...input.role !== undefined ? { role: input.role } : {},
|
|
39286
|
+
...input.groupId !== undefined ? { groupId: input.groupId } : {}
|
|
39252
39287
|
}),
|
|
39253
39288
|
createGroup: async (input) => await client.createGroup(input),
|
|
39254
39289
|
getGroup: async (input) => await client.getGroup(input),
|
|
@@ -39257,10 +39292,10 @@ function createOrchestrationTransport(endpoint, deps = {}) {
|
|
|
39257
39292
|
getTask: async (input) => await client.getTaskForCoordinator(input),
|
|
39258
39293
|
listTasks: async (input) => await client.listTasks({
|
|
39259
39294
|
coordinatorSession: input.coordinatorSession,
|
|
39260
|
-
...input.status ? { status: input.status } : {},
|
|
39295
|
+
...input.status !== undefined ? { status: input.status } : {},
|
|
39261
39296
|
...input.stuck !== undefined ? { stuck: input.stuck } : {},
|
|
39262
|
-
...input.sort ? { sort: input.sort } : {},
|
|
39263
|
-
...input.order ? { order: input.order } : {}
|
|
39297
|
+
...input.sort !== undefined ? { sort: input.sort } : {},
|
|
39298
|
+
...input.order !== undefined ? { order: input.order } : {}
|
|
39264
39299
|
}),
|
|
39265
39300
|
approveTask: async (input) => await client.approveTask(input),
|
|
39266
39301
|
rejectTask: async (input) => await client.rejectTask(input),
|
|
@@ -39376,9 +39411,11 @@ function installMcpStdioShutdownHooks(options) {
|
|
|
39376
39411
|
const parentPid = options.parentPid ?? process.ppid;
|
|
39377
39412
|
const parentCheckIntervalMs = options.parentCheckIntervalMs ?? parseParentCheckIntervalMs(process.env.WEACPX_MCP_PARENT_CHECK_INTERVAL_MS);
|
|
39378
39413
|
let disposed = false;
|
|
39414
|
+
let triggered = false;
|
|
39379
39415
|
const triggerShutdown = (reason, context) => {
|
|
39380
|
-
if (disposed)
|
|
39416
|
+
if (disposed || triggered)
|
|
39381
39417
|
return;
|
|
39418
|
+
triggered = true;
|
|
39382
39419
|
options.onDiagnostic?.("mcp.stdio.shutdown", { reason, ...context ?? {} });
|
|
39383
39420
|
options.shutdown();
|
|
39384
39421
|
};
|
|
@@ -39503,18 +39540,18 @@ function sanitizeMcpClientName(input) {
|
|
|
39503
39540
|
return normalized.length > 0 ? normalized : "mcp-host";
|
|
39504
39541
|
}
|
|
39505
39542
|
|
|
39506
|
-
// src/mcp/parse-
|
|
39507
|
-
function
|
|
39543
|
+
// src/mcp/parse-string-flag.ts
|
|
39544
|
+
function parseStringFlag(args, env, options) {
|
|
39508
39545
|
let fromFlag = null;
|
|
39509
39546
|
for (let index = 0;index < args.length; index += 1) {
|
|
39510
|
-
if (args[index] ===
|
|
39547
|
+
if (args[index] === options.flag) {
|
|
39511
39548
|
const value = args[index + 1];
|
|
39512
39549
|
if (value === undefined) {
|
|
39513
|
-
throw new Error(
|
|
39550
|
+
throw new Error(`${options.flag} requires a non-empty value`);
|
|
39514
39551
|
}
|
|
39515
39552
|
const trimmedValue = value.trim();
|
|
39516
39553
|
if (trimmedValue.length === 0 || trimmedValue.startsWith("-")) {
|
|
39517
|
-
throw new Error(
|
|
39554
|
+
throw new Error(`${options.flag} requires a non-empty value`);
|
|
39518
39555
|
}
|
|
39519
39556
|
fromFlag = value;
|
|
39520
39557
|
}
|
|
@@ -39523,61 +39560,403 @@ function parseCoordinatorWorkspace(args, env = process.env) {
|
|
|
39523
39560
|
if (trimmedFlag && trimmedFlag.length > 0) {
|
|
39524
39561
|
return trimmedFlag;
|
|
39525
39562
|
}
|
|
39526
|
-
const trimmedEnv = env.
|
|
39563
|
+
const trimmedEnv = env[options.envKey]?.trim();
|
|
39527
39564
|
return trimmedEnv && trimmedEnv.length > 0 ? trimmedEnv : null;
|
|
39528
39565
|
}
|
|
39529
39566
|
|
|
39567
|
+
// src/mcp/parse-coordinator-workspace.ts
|
|
39568
|
+
function parseCoordinatorWorkspace(args, env = process.env) {
|
|
39569
|
+
return parseStringFlag(args, env, {
|
|
39570
|
+
flag: "--workspace",
|
|
39571
|
+
envKey: "WEACPX_COORDINATOR_WORKSPACE"
|
|
39572
|
+
});
|
|
39573
|
+
}
|
|
39574
|
+
|
|
39530
39575
|
// src/mcp/parse-coordinator-session.ts
|
|
39531
39576
|
function parseCoordinatorSession(args, env = process.env) {
|
|
39532
|
-
|
|
39533
|
-
|
|
39534
|
-
|
|
39535
|
-
|
|
39536
|
-
if (value === undefined) {
|
|
39537
|
-
throw new Error("--coordinator-session requires a non-empty value");
|
|
39538
|
-
}
|
|
39539
|
-
const trimmedValue = value.trim();
|
|
39540
|
-
if (trimmedValue.length === 0 || trimmedValue.startsWith("-")) {
|
|
39541
|
-
throw new Error("--coordinator-session requires a non-empty value");
|
|
39542
|
-
}
|
|
39543
|
-
fromFlag = value;
|
|
39544
|
-
}
|
|
39545
|
-
}
|
|
39546
|
-
const trimmedFlag = fromFlag?.trim();
|
|
39547
|
-
if (trimmedFlag && trimmedFlag.length > 0) {
|
|
39548
|
-
return trimmedFlag;
|
|
39549
|
-
}
|
|
39550
|
-
const trimmedEnv = env.WEACPX_COORDINATOR_SESSION?.trim();
|
|
39551
|
-
return trimmedEnv && trimmedEnv.length > 0 ? trimmedEnv : null;
|
|
39577
|
+
return parseStringFlag(args, env, {
|
|
39578
|
+
flag: "--coordinator-session",
|
|
39579
|
+
envKey: "WEACPX_COORDINATOR_SESSION"
|
|
39580
|
+
});
|
|
39552
39581
|
}
|
|
39553
39582
|
|
|
39554
39583
|
// src/mcp/parse-source-handle.ts
|
|
39555
39584
|
function parseSourceHandle(args, env = process.env) {
|
|
39556
|
-
|
|
39557
|
-
|
|
39558
|
-
|
|
39559
|
-
|
|
39560
|
-
|
|
39561
|
-
|
|
39585
|
+
return parseStringFlag(args, env, {
|
|
39586
|
+
flag: "--source-handle",
|
|
39587
|
+
envKey: "WEACPX_SOURCE_HANDLE"
|
|
39588
|
+
});
|
|
39589
|
+
}
|
|
39590
|
+
|
|
39591
|
+
// src/cli.ts
|
|
39592
|
+
init_workspace_path();
|
|
39593
|
+
init_state_store();
|
|
39594
|
+
|
|
39595
|
+
// src/onboarding.ts
|
|
39596
|
+
init_workspace_path();
|
|
39597
|
+
init_agent_templates();
|
|
39598
|
+
function isFirstUse(config2, state) {
|
|
39599
|
+
return Object.keys(state.sessions ?? {}).length === 0 && Object.keys(config2.workspaces ?? {}).length === 0 && (config2.plugins ?? []).length === 0;
|
|
39600
|
+
}
|
|
39601
|
+
async function maybeRunFirstUseOnboarding(input) {
|
|
39602
|
+
if (!isFirstUse(input.config, input.state))
|
|
39603
|
+
return { created: false };
|
|
39604
|
+
if (!input.deps.isInteractive())
|
|
39605
|
+
return { created: false };
|
|
39606
|
+
const cwd = normalizeWorkspacePath(input.deps.cwd());
|
|
39607
|
+
const workspaceName = allocateName(sanitizeName(basenameForWorkspacePath(cwd), "workspace"), input.config.workspaces);
|
|
39608
|
+
const yes = (await input.deps.promptText(`检测到首次使用 weacpx。是否将当前目录创建为工作区「${workspaceName}」?[Y/n] `)).trim().toLowerCase();
|
|
39609
|
+
if (yes === "n" || yes === "no")
|
|
39610
|
+
return { created: false };
|
|
39611
|
+
const templateNames = listAgentTemplates();
|
|
39612
|
+
input.deps.print("请选择要添加并创建初始会话的 Agent:");
|
|
39613
|
+
for (let index = 0;index < templateNames.length; index += 1) {
|
|
39614
|
+
input.deps.print(`${index + 1}. ${templateNames[index]}`);
|
|
39615
|
+
}
|
|
39616
|
+
const answer = (await input.deps.promptText("输入数字或名称(默认 1):")).trim();
|
|
39617
|
+
const agentName = resolveTemplateChoice(answer, templateNames);
|
|
39618
|
+
if (!agentName) {
|
|
39619
|
+
input.deps.print("未选择有效 Agent,已跳过首次初始化。");
|
|
39620
|
+
return { created: false };
|
|
39621
|
+
}
|
|
39622
|
+
const template = getAgentTemplate(agentName);
|
|
39623
|
+
if (!template)
|
|
39624
|
+
return { created: false };
|
|
39625
|
+
const workspaceExisted = Boolean(input.config.workspaces[workspaceName]);
|
|
39626
|
+
const agentExisted = Boolean(input.config.agents[agentName]);
|
|
39627
|
+
input.config.workspaces[workspaceName] = { cwd };
|
|
39628
|
+
input.config.agents[agentName] = template;
|
|
39629
|
+
await input.saveConfig(input.config);
|
|
39630
|
+
const alias = `${workspaceName}:${agentName}`;
|
|
39631
|
+
input.deps.print(`已创建工作区「${workspaceName}」,正在创建初始会话「${alias}」...`);
|
|
39632
|
+
return {
|
|
39633
|
+
created: true,
|
|
39634
|
+
workspace: workspaceName,
|
|
39635
|
+
agent: agentName,
|
|
39636
|
+
alias,
|
|
39637
|
+
rollback: { workspaceExisted, agentExisted }
|
|
39638
|
+
};
|
|
39639
|
+
}
|
|
39640
|
+
function resolveTemplateChoice(answer, names) {
|
|
39641
|
+
if (!answer)
|
|
39642
|
+
return names[0] ?? null;
|
|
39643
|
+
const index = Number.parseInt(answer, 10);
|
|
39644
|
+
if (Number.isFinite(index) && index >= 1 && index <= names.length)
|
|
39645
|
+
return names[index - 1];
|
|
39646
|
+
return names.includes(answer) ? answer : null;
|
|
39647
|
+
}
|
|
39648
|
+
function allocateName(base, existing) {
|
|
39649
|
+
if (!existing[base])
|
|
39650
|
+
return base;
|
|
39651
|
+
let suffix = 2;
|
|
39652
|
+
while (existing[`${base}-${suffix}`])
|
|
39653
|
+
suffix += 1;
|
|
39654
|
+
return `${base}-${suffix}`;
|
|
39655
|
+
}
|
|
39656
|
+
function sanitizeName(input, fallback) {
|
|
39657
|
+
const sanitized = input.trim().replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
39658
|
+
return sanitized || fallback;
|
|
39659
|
+
}
|
|
39660
|
+
|
|
39661
|
+
// src/cli-update.ts
|
|
39662
|
+
init_plugin_home();
|
|
39663
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
39664
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
39665
|
+
import { dirname as dirname7, join as join6 } from "node:path";
|
|
39666
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
39667
|
+
|
|
39668
|
+
// src/plugins/package-manager.ts
|
|
39669
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
39670
|
+
async function defaultRunCommand(command, args, options) {
|
|
39671
|
+
await new Promise((resolve, reject) => {
|
|
39672
|
+
const child = spawn3(command, args, { cwd: options.cwd, stdio: "inherit" });
|
|
39673
|
+
child.on("error", reject);
|
|
39674
|
+
child.on("exit", (code) => {
|
|
39675
|
+
if (code === 0)
|
|
39676
|
+
resolve();
|
|
39677
|
+
else
|
|
39678
|
+
reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
|
|
39679
|
+
});
|
|
39680
|
+
});
|
|
39681
|
+
}
|
|
39682
|
+
async function silentRun(command, args, options) {
|
|
39683
|
+
await new Promise((resolve, reject) => {
|
|
39684
|
+
const child = spawn3(command, args, { cwd: options.cwd, stdio: "ignore" });
|
|
39685
|
+
child.on("error", reject);
|
|
39686
|
+
child.on("exit", (code) => {
|
|
39687
|
+
if (code === 0)
|
|
39688
|
+
resolve();
|
|
39689
|
+
else
|
|
39690
|
+
reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
|
|
39691
|
+
});
|
|
39692
|
+
});
|
|
39693
|
+
}
|
|
39694
|
+
async function detectPackageManager(runCommand) {
|
|
39695
|
+
const override = process.env.WEACPX_PACKAGE_MANAGER?.trim().toLowerCase();
|
|
39696
|
+
if (override === "bun" || override === "npm")
|
|
39697
|
+
return override;
|
|
39698
|
+
const probe = runCommand ?? silentRun;
|
|
39699
|
+
try {
|
|
39700
|
+
await probe("bun", ["--version"], { cwd: process.cwd() });
|
|
39701
|
+
return "bun";
|
|
39702
|
+
} catch {
|
|
39703
|
+
return "npm";
|
|
39704
|
+
}
|
|
39705
|
+
}
|
|
39706
|
+
async function installPluginPackage(input) {
|
|
39707
|
+
const runCommand = input.runCommand ?? defaultRunCommand;
|
|
39708
|
+
const packageManager = input.packageManager ?? await detectPackageManager();
|
|
39709
|
+
const spec = input.version ? `${input.packageName}@${input.version}` : input.packageName;
|
|
39710
|
+
if (packageManager === "bun") {
|
|
39711
|
+
await runCommand("bun", ["add", spec], { cwd: input.pluginHome });
|
|
39712
|
+
return;
|
|
39713
|
+
}
|
|
39714
|
+
await runCommand("npm", ["install", spec], { cwd: input.pluginHome });
|
|
39715
|
+
}
|
|
39716
|
+
async function updatePluginPackage(input) {
|
|
39717
|
+
await installPluginPackage(input);
|
|
39718
|
+
}
|
|
39719
|
+
async function removePluginPackage(input) {
|
|
39720
|
+
const runCommand = input.runCommand ?? defaultRunCommand;
|
|
39721
|
+
const packageManager = input.packageManager ?? await detectPackageManager();
|
|
39722
|
+
if (packageManager === "bun") {
|
|
39723
|
+
await runCommand("bun", ["remove", input.packageName], { cwd: input.pluginHome });
|
|
39724
|
+
return;
|
|
39725
|
+
}
|
|
39726
|
+
await runCommand("npm", ["uninstall", input.packageName], { cwd: input.pluginHome });
|
|
39727
|
+
}
|
|
39728
|
+
|
|
39729
|
+
// src/cli-update.ts
|
|
39730
|
+
init_plugin_loader();
|
|
39731
|
+
init_validate_plugin();
|
|
39732
|
+
async function handleUpdateCli(args, deps) {
|
|
39733
|
+
let all = false;
|
|
39734
|
+
const explicitTargets = [];
|
|
39735
|
+
for (const arg of args) {
|
|
39736
|
+
if (arg === "--all")
|
|
39737
|
+
all = true;
|
|
39738
|
+
else
|
|
39739
|
+
explicitTargets.push(arg);
|
|
39740
|
+
}
|
|
39741
|
+
if (all && explicitTargets.length > 0)
|
|
39742
|
+
return null;
|
|
39743
|
+
if (explicitTargets.length > 1)
|
|
39744
|
+
return null;
|
|
39745
|
+
const config2 = await deps.loadConfig();
|
|
39746
|
+
const packageName = deps.packageName ?? await readPackageName();
|
|
39747
|
+
const latestOf = deps.getLatestVersion ?? getLatestNpmVersion;
|
|
39748
|
+
const targets = [
|
|
39749
|
+
{
|
|
39750
|
+
kind: "self",
|
|
39751
|
+
name: packageName,
|
|
39752
|
+
currentVersion: deps.readCurrentVersion(),
|
|
39753
|
+
latestVersion: await latestOf(packageName)
|
|
39754
|
+
}
|
|
39755
|
+
];
|
|
39756
|
+
for (const plugin of config2.plugins ?? []) {
|
|
39757
|
+
targets.push({
|
|
39758
|
+
kind: "plugin",
|
|
39759
|
+
name: plugin.name,
|
|
39760
|
+
currentVersion: plugin.version,
|
|
39761
|
+
pinned: Boolean(plugin.version),
|
|
39762
|
+
latestVersion: await latestOf(plugin.name)
|
|
39763
|
+
});
|
|
39764
|
+
}
|
|
39765
|
+
deps.print("可更新项:");
|
|
39766
|
+
for (let index = 0;index < targets.length; index += 1) {
|
|
39767
|
+
const target = targets[index];
|
|
39768
|
+
deps.print(`${index + 1}. ${formatTarget(target)}`);
|
|
39769
|
+
}
|
|
39770
|
+
const unavailable = targets.filter((target) => !target.latestVersion || target.kind === "plugin" && !target.pinned);
|
|
39771
|
+
if (all && unavailable.length > 0) {
|
|
39772
|
+
deps.print(`以下项目无法检查最新版本,已取消更新:${unavailable.map((target) => target.name).join(", ")}`);
|
|
39773
|
+
return 1;
|
|
39774
|
+
}
|
|
39775
|
+
const candidates = targets.filter((target) => target.latestVersion && (target.kind !== "plugin" || target.pinned) && target.currentVersion !== target.latestVersion);
|
|
39776
|
+
const selected = await selectTargets(targets, candidates, { all, explicitTarget: explicitTargets[0], deps });
|
|
39777
|
+
if (!selected.ok) {
|
|
39778
|
+
deps.print(selected.message);
|
|
39779
|
+
return selected.exitCode;
|
|
39780
|
+
}
|
|
39781
|
+
if (selected.targets.length === 0) {
|
|
39782
|
+
deps.print("没有需要更新的项目。");
|
|
39783
|
+
return 0;
|
|
39784
|
+
}
|
|
39785
|
+
const selfUpdater = deps.updateSelf ?? defaultUpdateSelf;
|
|
39786
|
+
const pluginHome = deps.pluginHome ?? resolvePluginHome();
|
|
39787
|
+
const pluginUpdater = deps.updatePlugin ?? (async (input) => {
|
|
39788
|
+
await ensurePluginHome(pluginHome);
|
|
39789
|
+
await updatePluginPackage({ ...input, pluginHome });
|
|
39790
|
+
});
|
|
39791
|
+
const validatePlugin = deps.validatePlugin ?? validatePluginDefault;
|
|
39792
|
+
const updatedPlugins = [...config2.plugins ?? []];
|
|
39793
|
+
for (const target of selected.targets) {
|
|
39794
|
+
try {
|
|
39795
|
+
if (target.kind === "self") {
|
|
39796
|
+
if (!all && !explicitTargets[0]) {
|
|
39797
|
+
if (!deps.isInteractive()) {
|
|
39798
|
+
deps.print("更新 weacpx 本体需要确认;非交互模式请使用 `weacpx update --all` 或 `weacpx update weacpx`。");
|
|
39799
|
+
return 1;
|
|
39800
|
+
}
|
|
39801
|
+
const answer = (await deps.promptText("确认更新 weacpx 本体?[y/N] ")).trim().toLowerCase();
|
|
39802
|
+
if (answer !== "y" && answer !== "yes") {
|
|
39803
|
+
deps.print("已取消更新 weacpx 本体。");
|
|
39804
|
+
continue;
|
|
39805
|
+
}
|
|
39806
|
+
}
|
|
39807
|
+
await selfUpdater(target.name);
|
|
39808
|
+
deps.print(`weacpx 已更新:${target.latestVersion ?? "latest"}`);
|
|
39809
|
+
continue;
|
|
39562
39810
|
}
|
|
39563
|
-
const
|
|
39564
|
-
|
|
39565
|
-
|
|
39811
|
+
const existing = updatedPlugins.find((plugin) => plugin.name === target.name);
|
|
39812
|
+
const previousVersion = existing?.version;
|
|
39813
|
+
const updateInput = target.latestVersion ? { packageName: target.name, version: target.latestVersion } : { packageName: target.name };
|
|
39814
|
+
await pluginUpdater(updateInput);
|
|
39815
|
+
try {
|
|
39816
|
+
await validatePlugin(target.name, pluginHome);
|
|
39817
|
+
} catch (validationError) {
|
|
39818
|
+
if (previousVersion) {
|
|
39819
|
+
try {
|
|
39820
|
+
await pluginUpdater({ packageName: target.name, version: previousVersion });
|
|
39821
|
+
} catch (rollbackError) {
|
|
39822
|
+
deps.print(`回滚 ${target.name} 到 ${previousVersion} 失败:${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
|
|
39823
|
+
}
|
|
39824
|
+
}
|
|
39825
|
+
throw validationError;
|
|
39566
39826
|
}
|
|
39567
|
-
|
|
39827
|
+
if (!existing)
|
|
39828
|
+
throw new Error(`配置中没有找到插件 ${target.name}`);
|
|
39829
|
+
if (existing && target.latestVersion)
|
|
39830
|
+
existing.version = target.latestVersion;
|
|
39831
|
+
deps.print(`插件 ${target.name} 已更新:${target.latestVersion ?? "latest"}`);
|
|
39832
|
+
} catch (error2) {
|
|
39833
|
+
deps.print(`${target.name} 更新失败:${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
39834
|
+
return 1;
|
|
39568
39835
|
}
|
|
39569
39836
|
}
|
|
39570
|
-
|
|
39571
|
-
|
|
39572
|
-
|
|
39837
|
+
if (selected.targets.some((target) => target.kind === "plugin")) {
|
|
39838
|
+
config2.plugins = updatedPlugins;
|
|
39839
|
+
await deps.saveConfig(config2);
|
|
39573
39840
|
}
|
|
39574
|
-
|
|
39575
|
-
|
|
39841
|
+
return 0;
|
|
39842
|
+
}
|
|
39843
|
+
function formatTarget(target) {
|
|
39844
|
+
const current = target.currentVersion ?? "未锁定";
|
|
39845
|
+
const latest = target.latestVersion ?? "无法检查";
|
|
39846
|
+
const label = target.kind === "self" ? "weacpx" : `插件 ${target.name}`;
|
|
39847
|
+
return `${label} (${current} -> ${latest})`;
|
|
39848
|
+
}
|
|
39849
|
+
async function selectTargets(targets, candidates, input) {
|
|
39850
|
+
if (input.explicitTarget) {
|
|
39851
|
+
const target = targets.find((entry) => entry.name === input.explicitTarget || input.explicitTarget === "weacpx" && entry.kind === "self");
|
|
39852
|
+
if (!target)
|
|
39853
|
+
return { ok: false, message: `没有找到更新项:${input.explicitTarget}`, exitCode: 1 };
|
|
39854
|
+
if (!target.latestVersion)
|
|
39855
|
+
return { ok: false, message: `${target.name} 无法检查最新版本,已跳过。`, exitCode: 1 };
|
|
39856
|
+
if (target.kind === "plugin" && !target.pinned)
|
|
39857
|
+
return { ok: false, message: `${target.name} 未记录当前版本;请先使用 \`weacpx plugin update ${target.name}\` 或显式选择版本。`, exitCode: 1 };
|
|
39858
|
+
if (target.currentVersion === target.latestVersion)
|
|
39859
|
+
return { ok: true, targets: [] };
|
|
39860
|
+
return { ok: true, targets: [target] };
|
|
39861
|
+
}
|
|
39862
|
+
if (input.all || targets.length === 1)
|
|
39863
|
+
return { ok: true, targets: candidates };
|
|
39864
|
+
if (!input.deps.isInteractive()) {
|
|
39865
|
+
return { ok: false, message: "检测到已安装插件;非交互模式请使用 `weacpx update --all` 或 `weacpx update <name>`。", exitCode: 1 };
|
|
39866
|
+
}
|
|
39867
|
+
const answer = (await input.deps.promptText("请选择要更新的项目(数字,逗号分隔,a=全部,回车取消):")).trim().toLowerCase();
|
|
39868
|
+
if (!answer)
|
|
39869
|
+
return { ok: true, targets: [] };
|
|
39870
|
+
if (answer === "a" || answer === "all")
|
|
39871
|
+
return { ok: true, targets: candidates };
|
|
39872
|
+
const selected = [];
|
|
39873
|
+
for (const part of answer.split(",")) {
|
|
39874
|
+
const index = Number.parseInt(part.trim(), 10);
|
|
39875
|
+
if (!Number.isFinite(index) || index < 1 || index > targets.length) {
|
|
39876
|
+
return { ok: false, message: `无效选择:${part.trim()}`, exitCode: 1 };
|
|
39877
|
+
}
|
|
39878
|
+
const target = targets[index - 1];
|
|
39879
|
+
if (!target.latestVersion)
|
|
39880
|
+
return { ok: false, message: `${target.name} 无法检查最新版本,已跳过。`, exitCode: 1 };
|
|
39881
|
+
if (target.kind === "plugin" && !target.pinned)
|
|
39882
|
+
return { ok: false, message: `${target.name} 未记录当前版本;请先使用 \`weacpx plugin update ${target.name}\` 或显式选择版本。`, exitCode: 1 };
|
|
39883
|
+
if (target.currentVersion === target.latestVersion)
|
|
39884
|
+
continue;
|
|
39885
|
+
if (!selected.includes(target))
|
|
39886
|
+
selected.push(target);
|
|
39887
|
+
}
|
|
39888
|
+
return { ok: true, targets: selected };
|
|
39889
|
+
}
|
|
39890
|
+
async function getLatestNpmVersion(packageName) {
|
|
39891
|
+
const result = await runCapture("npm", ["view", packageName, "version", "--json"]);
|
|
39892
|
+
if (result.code !== 0)
|
|
39893
|
+
return null;
|
|
39894
|
+
const raw = result.stdout.trim();
|
|
39895
|
+
if (!raw)
|
|
39896
|
+
return null;
|
|
39897
|
+
try {
|
|
39898
|
+
const parsed = JSON.parse(raw);
|
|
39899
|
+
return typeof parsed === "string" ? parsed : null;
|
|
39900
|
+
} catch {
|
|
39901
|
+
return raw.replace(/^"|"$/g, "") || null;
|
|
39902
|
+
}
|
|
39903
|
+
}
|
|
39904
|
+
async function defaultUpdateSelf(packageName) {
|
|
39905
|
+
const manager = process.env.WEACPX_PACKAGE_MANAGER?.trim().toLowerCase() === "bun" ? "bun" : "npm";
|
|
39906
|
+
if (manager === "bun") {
|
|
39907
|
+
await runInherit("bun", ["add", "-g", packageName]);
|
|
39908
|
+
return;
|
|
39909
|
+
}
|
|
39910
|
+
await runInherit("npm", ["install", "-g", packageName]);
|
|
39911
|
+
}
|
|
39912
|
+
async function runCapture(command, args) {
|
|
39913
|
+
return await new Promise((resolve, reject) => {
|
|
39914
|
+
const child = spawn4(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
39915
|
+
let stdout2 = "";
|
|
39916
|
+
let stderr = "";
|
|
39917
|
+
child.stdout.setEncoding("utf8");
|
|
39918
|
+
child.stderr.setEncoding("utf8");
|
|
39919
|
+
child.stdout.on("data", (chunk) => {
|
|
39920
|
+
stdout2 += chunk;
|
|
39921
|
+
});
|
|
39922
|
+
child.stderr.on("data", (chunk) => {
|
|
39923
|
+
stderr += chunk;
|
|
39924
|
+
});
|
|
39925
|
+
child.on("error", reject);
|
|
39926
|
+
child.on("close", (code) => resolve({ code: code ?? 1, stdout: stdout2, stderr }));
|
|
39927
|
+
});
|
|
39928
|
+
}
|
|
39929
|
+
async function runInherit(command, args) {
|
|
39930
|
+
await new Promise((resolve, reject) => {
|
|
39931
|
+
const child = spawn4(command, args, { stdio: "inherit" });
|
|
39932
|
+
child.on("error", reject);
|
|
39933
|
+
child.on("exit", (code) => {
|
|
39934
|
+
if (code === 0)
|
|
39935
|
+
resolve();
|
|
39936
|
+
else
|
|
39937
|
+
reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
|
|
39938
|
+
});
|
|
39939
|
+
});
|
|
39940
|
+
}
|
|
39941
|
+
async function readPackageName() {
|
|
39942
|
+
try {
|
|
39943
|
+
const here = dirname7(fileURLToPath2(import.meta.url));
|
|
39944
|
+
for (const candidate of [join6(here, "..", "package.json"), join6(here, "..", "..", "package.json")]) {
|
|
39945
|
+
try {
|
|
39946
|
+
const parsed = JSON.parse(await readFile7(candidate, "utf8"));
|
|
39947
|
+
if (typeof parsed.name === "string" && parsed.name.trim())
|
|
39948
|
+
return parsed.name.trim();
|
|
39949
|
+
} catch {}
|
|
39950
|
+
}
|
|
39951
|
+
} catch {}
|
|
39952
|
+
return "weacpx";
|
|
39953
|
+
}
|
|
39954
|
+
async function validatePluginDefault(packageName, pluginHome) {
|
|
39955
|
+
const moduleValue = await importPluginFromHome(packageName, pluginHome);
|
|
39956
|
+
validateWeacpxPlugin(moduleValue, packageName);
|
|
39576
39957
|
}
|
|
39577
39958
|
|
|
39578
39959
|
// src/cli.ts
|
|
39579
|
-
init_workspace_path();
|
|
39580
|
-
init_state_store();
|
|
39581
39960
|
init_version();
|
|
39582
39961
|
|
|
39583
39962
|
// src/channels/cli/channel-cli.ts
|
|
@@ -40187,71 +40566,8 @@ async function setChannelAccountEnabled(type, accountId, enabled, rawArgs, deps)
|
|
|
40187
40566
|
|
|
40188
40567
|
// src/plugins/plugin-cli.ts
|
|
40189
40568
|
init_plugin_home();
|
|
40190
|
-
import { readFile as
|
|
40191
|
-
import { isAbsolute, join as
|
|
40192
|
-
|
|
40193
|
-
// src/plugins/package-manager.ts
|
|
40194
|
-
import { spawn as spawn3 } from "node:child_process";
|
|
40195
|
-
async function defaultRunCommand(command, args, options) {
|
|
40196
|
-
await new Promise((resolve, reject) => {
|
|
40197
|
-
const child = spawn3(command, args, { cwd: options.cwd, stdio: "inherit" });
|
|
40198
|
-
child.on("error", reject);
|
|
40199
|
-
child.on("exit", (code) => {
|
|
40200
|
-
if (code === 0)
|
|
40201
|
-
resolve();
|
|
40202
|
-
else
|
|
40203
|
-
reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
|
|
40204
|
-
});
|
|
40205
|
-
});
|
|
40206
|
-
}
|
|
40207
|
-
async function silentRun(command, args, options) {
|
|
40208
|
-
await new Promise((resolve, reject) => {
|
|
40209
|
-
const child = spawn3(command, args, { cwd: options.cwd, stdio: "ignore" });
|
|
40210
|
-
child.on("error", reject);
|
|
40211
|
-
child.on("exit", (code) => {
|
|
40212
|
-
if (code === 0)
|
|
40213
|
-
resolve();
|
|
40214
|
-
else
|
|
40215
|
-
reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
|
|
40216
|
-
});
|
|
40217
|
-
});
|
|
40218
|
-
}
|
|
40219
|
-
async function detectPackageManager(runCommand) {
|
|
40220
|
-
const override = process.env.WEACPX_PACKAGE_MANAGER?.trim().toLowerCase();
|
|
40221
|
-
if (override === "bun" || override === "npm")
|
|
40222
|
-
return override;
|
|
40223
|
-
const probe = runCommand ?? silentRun;
|
|
40224
|
-
try {
|
|
40225
|
-
await probe("bun", ["--version"], { cwd: process.cwd() });
|
|
40226
|
-
return "bun";
|
|
40227
|
-
} catch {
|
|
40228
|
-
return "npm";
|
|
40229
|
-
}
|
|
40230
|
-
}
|
|
40231
|
-
async function installPluginPackage(input) {
|
|
40232
|
-
const runCommand = input.runCommand ?? defaultRunCommand;
|
|
40233
|
-
const packageManager = input.packageManager ?? await detectPackageManager();
|
|
40234
|
-
const spec = input.version ? `${input.packageName}@${input.version}` : input.packageName;
|
|
40235
|
-
if (packageManager === "bun") {
|
|
40236
|
-
await runCommand("bun", ["add", spec], { cwd: input.pluginHome });
|
|
40237
|
-
return;
|
|
40238
|
-
}
|
|
40239
|
-
await runCommand("npm", ["install", spec], { cwd: input.pluginHome });
|
|
40240
|
-
}
|
|
40241
|
-
async function updatePluginPackage(input) {
|
|
40242
|
-
await installPluginPackage(input);
|
|
40243
|
-
}
|
|
40244
|
-
async function removePluginPackage(input) {
|
|
40245
|
-
const runCommand = input.runCommand ?? defaultRunCommand;
|
|
40246
|
-
const packageManager = input.packageManager ?? await detectPackageManager();
|
|
40247
|
-
if (packageManager === "bun") {
|
|
40248
|
-
await runCommand("bun", ["remove", input.packageName], { cwd: input.pluginHome });
|
|
40249
|
-
return;
|
|
40250
|
-
}
|
|
40251
|
-
await runCommand("npm", ["uninstall", input.packageName], { cwd: input.pluginHome });
|
|
40252
|
-
}
|
|
40253
|
-
|
|
40254
|
-
// src/plugins/plugin-cli.ts
|
|
40569
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
40570
|
+
import { isAbsolute, join as join8, resolve } from "node:path";
|
|
40255
40571
|
init_plugin_loader();
|
|
40256
40572
|
init_validate_plugin();
|
|
40257
40573
|
|
|
@@ -40260,14 +40576,14 @@ init_channel_scope();
|
|
|
40260
40576
|
init_plugin_loader();
|
|
40261
40577
|
init_validate_plugin();
|
|
40262
40578
|
init_known_plugins();
|
|
40263
|
-
import { readFile as
|
|
40264
|
-
import { join as
|
|
40579
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
40580
|
+
import { join as join7 } from "node:path";
|
|
40265
40581
|
function suggestedPluginPackageForChannel(type) {
|
|
40266
40582
|
return findKnownPluginByChannel(type)?.packageName ?? `<npm-package-that-provides-${type}>`;
|
|
40267
40583
|
}
|
|
40268
40584
|
async function readDependencyEntries(pluginHome) {
|
|
40269
40585
|
try {
|
|
40270
|
-
const raw = await
|
|
40586
|
+
const raw = await readFile8(join7(pluginHome, "package.json"), "utf8");
|
|
40271
40587
|
const parsed = JSON.parse(raw);
|
|
40272
40588
|
const out = {};
|
|
40273
40589
|
for (const [name, value] of Object.entries(parsed.dependencies ?? {})) {
|
|
@@ -40369,7 +40685,7 @@ function looksLikePath(spec) {
|
|
|
40369
40685
|
}
|
|
40370
40686
|
async function readDependencyEntries2(pluginHome) {
|
|
40371
40687
|
try {
|
|
40372
|
-
const raw = await
|
|
40688
|
+
const raw = await readFile9(join8(pluginHome, "package.json"), "utf8");
|
|
40373
40689
|
const parsed = JSON.parse(raw);
|
|
40374
40690
|
const out = {};
|
|
40375
40691
|
for (const [name, value] of Object.entries(parsed.dependencies ?? {})) {
|
|
@@ -40395,7 +40711,7 @@ async function resolveLocalPluginName(installSpec, pluginHome, namesBeforeInstal
|
|
|
40395
40711
|
return name;
|
|
40396
40712
|
}
|
|
40397
40713
|
try {
|
|
40398
|
-
const raw = await
|
|
40714
|
+
const raw = await readFile9(join8(installSpec, "package.json"), "utf8");
|
|
40399
40715
|
const parsed = JSON.parse(raw);
|
|
40400
40716
|
if (typeof parsed.name === "string" && parsed.name.trim())
|
|
40401
40717
|
return parsed.name.trim();
|
|
@@ -40924,6 +41240,7 @@ var HELP_LINES = [
|
|
|
40924
41240
|
"weacpx status - 查看状态",
|
|
40925
41241
|
"weacpx stop - 停止服务",
|
|
40926
41242
|
"weacpx restart - 重启后台服务",
|
|
41243
|
+
"weacpx update [--all|<name>] - 更新 weacpx 和已安装插件",
|
|
40927
41244
|
"weacpx channel|ch list|show|add|rm|enable|disable [--account <id>] - 管理消息频道(多 bot 用 --account)",
|
|
40928
41245
|
"weacpx plugin list|add|update|remove|enable|disable|doctor|known - 管理插件",
|
|
40929
41246
|
"weacpx doctor - 运行诊断",
|
|
@@ -40959,8 +41276,28 @@ async function runCli(args, deps = {}) {
|
|
|
40959
41276
|
await (deps.logout ?? defaultLogout)();
|
|
40960
41277
|
return 0;
|
|
40961
41278
|
case "run":
|
|
40962
|
-
|
|
41279
|
+
const onboarding = await runOnboardingBeforeStart({
|
|
41280
|
+
print,
|
|
41281
|
+
cwd: deps.cwd ?? (() => process.cwd()),
|
|
41282
|
+
isInteractive: deps.isInteractive,
|
|
41283
|
+
promptText: deps.promptText
|
|
41284
|
+
});
|
|
41285
|
+
await (deps.run ?? defaultRun)({ firstRunOnboarding: onboarding ?? undefined });
|
|
40963
41286
|
return 0;
|
|
41287
|
+
case "update": {
|
|
41288
|
+
const result = await (deps.update ?? ((subArgs) => defaultUpdate(subArgs, {
|
|
41289
|
+
print,
|
|
41290
|
+
isInteractive: deps.isInteractive,
|
|
41291
|
+
promptText: deps.promptText,
|
|
41292
|
+
overrides: deps.updateCliDeps
|
|
41293
|
+
})))(args.slice(1));
|
|
41294
|
+
if (result === null) {
|
|
41295
|
+
for (const line of HELP_LINES)
|
|
41296
|
+
print(line);
|
|
41297
|
+
return 1;
|
|
41298
|
+
}
|
|
41299
|
+
return result;
|
|
41300
|
+
}
|
|
40964
41301
|
case "doctor": {
|
|
40965
41302
|
const parsed = parseDoctorArgs(args.slice(1));
|
|
40966
41303
|
if (!parsed.ok) {
|
|
@@ -41026,7 +41363,22 @@ async function runCli(args, deps = {}) {
|
|
|
41026
41363
|
case "start": {
|
|
41027
41364
|
const controller = deps.controller ?? createDefaultController();
|
|
41028
41365
|
try {
|
|
41029
|
-
const
|
|
41366
|
+
const status = await controller.getStatus();
|
|
41367
|
+
if (status.state === "running") {
|
|
41368
|
+
print("weacpx 已在后台运行");
|
|
41369
|
+
print(`PID: ${status.pid}`);
|
|
41370
|
+
return 0;
|
|
41371
|
+
}
|
|
41372
|
+
if (status.state === "indeterminate") {
|
|
41373
|
+
throw new Error(`weacpx daemon process is already running (pid ${status.pid}) but status metadata is missing`);
|
|
41374
|
+
}
|
|
41375
|
+
const onboarding2 = await runOnboardingBeforeStart({
|
|
41376
|
+
print,
|
|
41377
|
+
cwd: deps.cwd ?? (() => process.cwd()),
|
|
41378
|
+
isInteractive: deps.isInteractive,
|
|
41379
|
+
promptText: deps.promptText
|
|
41380
|
+
});
|
|
41381
|
+
const result = await controller.start({ firstRunOnboarding: onboarding2 ?? undefined });
|
|
41030
41382
|
if (result.state === "already-running") {
|
|
41031
41383
|
print("weacpx 已在后台运行");
|
|
41032
41384
|
print(`PID: ${result.pid}`);
|
|
@@ -41095,6 +41447,44 @@ async function runCli(args, deps = {}) {
|
|
|
41095
41447
|
return 1;
|
|
41096
41448
|
}
|
|
41097
41449
|
}
|
|
41450
|
+
async function defaultUpdate(args, input) {
|
|
41451
|
+
const store = await createCliConfigStore();
|
|
41452
|
+
const deps = {
|
|
41453
|
+
loadConfig: async () => await store.load(),
|
|
41454
|
+
saveConfig: async (config2) => await store.save(config2),
|
|
41455
|
+
readCurrentVersion: readVersion,
|
|
41456
|
+
print: input.print,
|
|
41457
|
+
isInteractive: input.isInteractive ?? (() => Boolean(process.stdin.isTTY && process.stdout.isTTY)),
|
|
41458
|
+
promptText: input.promptText ?? defaultPromptText,
|
|
41459
|
+
...input.overrides
|
|
41460
|
+
};
|
|
41461
|
+
return await handleUpdateCli(args, deps);
|
|
41462
|
+
}
|
|
41463
|
+
async function runOnboardingBeforeStart(input) {
|
|
41464
|
+
const runtimePaths = (await init_main().then(() => exports_main)).resolveRuntimePaths();
|
|
41465
|
+
await ensureConfigExists(runtimePaths.configPath);
|
|
41466
|
+
const configStore = new ConfigStore(runtimePaths.configPath);
|
|
41467
|
+
const stateStore = new StateStore(runtimePaths.statePath);
|
|
41468
|
+
const config2 = await configStore.load();
|
|
41469
|
+
const state = await stateStore.load();
|
|
41470
|
+
const result = await maybeRunFirstUseOnboarding({
|
|
41471
|
+
config: config2,
|
|
41472
|
+
state,
|
|
41473
|
+
saveConfig: async (next) => await configStore.save(next),
|
|
41474
|
+
deps: {
|
|
41475
|
+
print: input.print,
|
|
41476
|
+
cwd: input.cwd,
|
|
41477
|
+
isInteractive: input.isInteractive ?? (() => Boolean(process.stdin.isTTY && process.stdout.isTTY)),
|
|
41478
|
+
promptText: input.promptText ?? defaultPromptText
|
|
41479
|
+
}
|
|
41480
|
+
});
|
|
41481
|
+
return result.created ? {
|
|
41482
|
+
alias: result.alias,
|
|
41483
|
+
agent: result.agent,
|
|
41484
|
+
workspace: result.workspace,
|
|
41485
|
+
rollback: result.rollback
|
|
41486
|
+
} : null;
|
|
41487
|
+
}
|
|
41098
41488
|
async function handleWorkspaceCli(args, deps) {
|
|
41099
41489
|
const subcommand = args[0];
|
|
41100
41490
|
switch (subcommand) {
|
|
@@ -41190,7 +41580,7 @@ async function defaultLoadConfiguredPluginsForChannelCli() {
|
|
|
41190
41580
|
const { loadConfiguredPlugins: loadConfiguredPlugins2 } = await Promise.resolve().then(() => (init_plugin_loader(), exports_plugin_loader));
|
|
41191
41581
|
await loadConfiguredPlugins2({ plugins: config2.plugins });
|
|
41192
41582
|
}
|
|
41193
|
-
async function defaultRun() {
|
|
41583
|
+
async function defaultRun(options = {}) {
|
|
41194
41584
|
const [{ buildApp: buildApp2, resolveRuntimePaths: resolveRuntimePaths2, prepareChannelMedia: prepareChannelMedia2 }, { runConsole: runConsole2 }] = await Promise.all([
|
|
41195
41585
|
init_main().then(() => exports_main),
|
|
41196
41586
|
Promise.resolve().then(() => (init_run_console(), exports_run_console))
|
|
@@ -41208,11 +41598,15 @@ async function defaultRun() {
|
|
|
41208
41598
|
const channelRegistry = new MessageChannelRegistry2(createMessageChannels2(config2.channels, channelDeps));
|
|
41209
41599
|
const lockCreators = channelRegistry.createConsumerLocks();
|
|
41210
41600
|
const firstLockCreator = lockCreators[0];
|
|
41601
|
+
const firstRunOnboarding = options.firstRunOnboarding ?? decodeFirstRunOnboarding(process.env.WEACPX_FIRST_RUN_ONBOARDING);
|
|
41211
41602
|
await runConsole2(runtimePaths, {
|
|
41212
41603
|
buildApp: (paths) => buildApp2(paths, {
|
|
41213
41604
|
defaultLoggingLevel: resolveCliEntryPath2().includes(`${sep}src${sep}`) ? "debug" : "info",
|
|
41214
41605
|
channel: channelRegistry
|
|
41215
41606
|
}),
|
|
41607
|
+
beforeReady: firstRunOnboarding ? async (runtime) => {
|
|
41608
|
+
await createFirstRunSession(runtime, firstRunOnboarding);
|
|
41609
|
+
} : undefined,
|
|
41216
41610
|
channels: channelRegistry,
|
|
41217
41611
|
daemonRuntime,
|
|
41218
41612
|
...firstLockCreator ? {
|
|
@@ -41225,6 +41619,42 @@ async function defaultRun() {
|
|
|
41225
41619
|
} : {}
|
|
41226
41620
|
});
|
|
41227
41621
|
}
|
|
41622
|
+
async function createFirstRunSession(runtime, plan) {
|
|
41623
|
+
const session = runtime.sessions.resolveSession(plan.alias, plan.agent, plan.workspace, plan.alias);
|
|
41624
|
+
try {
|
|
41625
|
+
await runtime.transport.ensureSession(session);
|
|
41626
|
+
const exists = await runtime.transport.hasSession(session);
|
|
41627
|
+
if (!exists) {
|
|
41628
|
+
throw new Error(`first-run onboarding failed to create transport session: ${plan.alias}`);
|
|
41629
|
+
}
|
|
41630
|
+
await runtime.sessions.attachSession(plan.alias, plan.agent, plan.workspace, session.transportSession);
|
|
41631
|
+
} catch (error2) {
|
|
41632
|
+
await rollbackFirstRunConfig(runtime, plan);
|
|
41633
|
+
throw error2;
|
|
41634
|
+
}
|
|
41635
|
+
await runtime.logger.info("onboarding.session_created", "created first-run transport session", {
|
|
41636
|
+
alias: plan.alias,
|
|
41637
|
+
agent: plan.agent,
|
|
41638
|
+
workspace: plan.workspace
|
|
41639
|
+
});
|
|
41640
|
+
}
|
|
41641
|
+
async function rollbackFirstRunConfig(runtime, plan) {
|
|
41642
|
+
try {
|
|
41643
|
+
const config2 = await runtime.configStore.load();
|
|
41644
|
+
if (!plan.rollback.workspaceExisted && config2.workspaces[plan.workspace]) {
|
|
41645
|
+
delete config2.workspaces[plan.workspace];
|
|
41646
|
+
}
|
|
41647
|
+
if (!plan.rollback.agentExisted && config2.agents[plan.agent]) {
|
|
41648
|
+
delete config2.agents[plan.agent];
|
|
41649
|
+
}
|
|
41650
|
+
await runtime.configStore.save(config2);
|
|
41651
|
+
} catch (error2) {
|
|
41652
|
+
await runtime.logger.error("onboarding.rollback_failed", "failed to roll back first-run config", {
|
|
41653
|
+
alias: plan.alias,
|
|
41654
|
+
error: error2 instanceof Error ? error2.message : String(error2)
|
|
41655
|
+
});
|
|
41656
|
+
}
|
|
41657
|
+
}
|
|
41228
41658
|
async function defaultDoctor(options) {
|
|
41229
41659
|
const { main: main3 } = await init_doctor2().then(() => exports_doctor);
|
|
41230
41660
|
return await main3(options);
|
|
@@ -41409,12 +41839,42 @@ async function defaultPromptSecret(message) {
|
|
|
41409
41839
|
}
|
|
41410
41840
|
function createDefaultController() {
|
|
41411
41841
|
const daemonPaths = resolveDaemonPaths({ home: requireHome2() });
|
|
41412
|
-
|
|
41842
|
+
const controller = createDaemonController(daemonPaths, {
|
|
41413
41843
|
processExecPath: process.execPath,
|
|
41414
41844
|
cliEntryPath: resolveCliEntryPath2(),
|
|
41415
41845
|
cwd: process.cwd(),
|
|
41416
41846
|
env: process.env
|
|
41417
41847
|
});
|
|
41848
|
+
return {
|
|
41849
|
+
getStatus: () => controller.getStatus(),
|
|
41850
|
+
stop: () => controller.stop(),
|
|
41851
|
+
start: (options) => controller.start({
|
|
41852
|
+
...options?.firstRunOnboarding ? { firstRunOnboarding: encodeFirstRunOnboarding(options.firstRunOnboarding) } : {}
|
|
41853
|
+
})
|
|
41854
|
+
};
|
|
41855
|
+
}
|
|
41856
|
+
function encodeFirstRunOnboarding(plan) {
|
|
41857
|
+
return Buffer.from(JSON.stringify(plan), "utf8").toString("base64url");
|
|
41858
|
+
}
|
|
41859
|
+
function decodeFirstRunOnboarding(raw) {
|
|
41860
|
+
if (!raw)
|
|
41861
|
+
return null;
|
|
41862
|
+
try {
|
|
41863
|
+
const parsed = JSON.parse(Buffer.from(raw, "base64url").toString("utf8"));
|
|
41864
|
+
if (typeof parsed.alias === "string" && typeof parsed.agent === "string" && typeof parsed.workspace === "string") {
|
|
41865
|
+
const rollback = typeof parsed.rollback === "object" && parsed.rollback !== null ? parsed.rollback : {};
|
|
41866
|
+
return {
|
|
41867
|
+
alias: parsed.alias,
|
|
41868
|
+
agent: parsed.agent,
|
|
41869
|
+
workspace: parsed.workspace,
|
|
41870
|
+
rollback: {
|
|
41871
|
+
workspaceExisted: rollback.workspaceExisted === true,
|
|
41872
|
+
agentExisted: rollback.agentExisted === true
|
|
41873
|
+
}
|
|
41874
|
+
};
|
|
41875
|
+
}
|
|
41876
|
+
} catch {}
|
|
41877
|
+
return null;
|
|
41418
41878
|
}
|
|
41419
41879
|
function requireHome2() {
|
|
41420
41880
|
const home = process.env.HOME ?? homedir13();
|
|
@@ -41437,7 +41897,7 @@ function resolveCliEntryPath2() {
|
|
|
41437
41897
|
if (process.argv[1]) {
|
|
41438
41898
|
return process.argv[1];
|
|
41439
41899
|
}
|
|
41440
|
-
return
|
|
41900
|
+
return fileURLToPath6(import.meta.url);
|
|
41441
41901
|
}
|
|
41442
41902
|
function parseDoctorArgs(args) {
|
|
41443
41903
|
const options = {};
|