weacpx 0.4.0 → 0.4.2
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 +858 -289
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2610,18 +2610,22 @@ class DaemonController {
|
|
|
2610
2610
|
statusStore;
|
|
2611
2611
|
startupPollIntervalMs;
|
|
2612
2612
|
startupTimeoutMs;
|
|
2613
|
+
onboardingStartupTimeoutMs;
|
|
2613
2614
|
onStartupPoll;
|
|
2614
2615
|
shutdownPollIntervalMs;
|
|
2615
2616
|
shutdownTimeoutMs;
|
|
2616
2617
|
onShutdownPoll;
|
|
2618
|
+
now;
|
|
2617
2619
|
constructor(paths, deps) {
|
|
2618
2620
|
this.paths = paths;
|
|
2619
2621
|
this.deps = deps;
|
|
2620
2622
|
this.statusStore = new DaemonStatusStore(paths.statusFile);
|
|
2621
2623
|
this.startupPollIntervalMs = deps.startupPollIntervalMs ?? 50;
|
|
2622
2624
|
this.startupTimeoutMs = deps.startupTimeoutMs ?? 5000;
|
|
2625
|
+
this.onboardingStartupTimeoutMs = deps.onboardingStartupTimeoutMs ?? 300000;
|
|
2623
2626
|
this.shutdownPollIntervalMs = deps.shutdownPollIntervalMs ?? 50;
|
|
2624
2627
|
this.shutdownTimeoutMs = deps.shutdownTimeoutMs ?? 5000;
|
|
2628
|
+
this.now = deps.now ?? (() => Date.now());
|
|
2625
2629
|
this.onStartupPoll = deps.onStartupPoll ?? (async () => {
|
|
2626
2630
|
await new Promise((resolve) => setTimeout(resolve, this.startupPollIntervalMs));
|
|
2627
2631
|
});
|
|
@@ -2648,7 +2652,7 @@ class DaemonController {
|
|
|
2648
2652
|
status
|
|
2649
2653
|
};
|
|
2650
2654
|
}
|
|
2651
|
-
async start() {
|
|
2655
|
+
async start(options = {}) {
|
|
2652
2656
|
const current = await this.getStatus();
|
|
2653
2657
|
if (current.state === "running") {
|
|
2654
2658
|
return { state: "already-running", pid: current.pid };
|
|
@@ -2657,9 +2661,9 @@ class DaemonController {
|
|
|
2657
2661
|
throw new Error(`weacpx daemon process is already running (pid ${current.pid}) but status metadata is missing`);
|
|
2658
2662
|
}
|
|
2659
2663
|
await this.statusStore.clear();
|
|
2660
|
-
const pid = await this.deps.spawnDetached();
|
|
2664
|
+
const pid = await this.deps.spawnDetached(options);
|
|
2661
2665
|
await this.writePid(pid);
|
|
2662
|
-
await this.waitForStartupMetadata(pid);
|
|
2666
|
+
await this.waitForStartupMetadata(pid, options.firstRunOnboarding ? this.onboardingStartupTimeoutMs : this.startupTimeoutMs, options.startupWait);
|
|
2663
2667
|
return { state: "started", pid };
|
|
2664
2668
|
}
|
|
2665
2669
|
async stop() {
|
|
@@ -2695,9 +2699,10 @@ class DaemonController {
|
|
|
2695
2699
|
await rm2(this.paths.pidFile, { force: true });
|
|
2696
2700
|
await this.statusStore.clear();
|
|
2697
2701
|
}
|
|
2698
|
-
async waitForStartupMetadata(pid) {
|
|
2699
|
-
const
|
|
2700
|
-
|
|
2702
|
+
async waitForStartupMetadata(pid, timeoutMs, startupWait) {
|
|
2703
|
+
const startedAt = this.now();
|
|
2704
|
+
const deadline = startedAt + timeoutMs;
|
|
2705
|
+
while (this.now() < deadline) {
|
|
2701
2706
|
const status = await this.statusStore.load();
|
|
2702
2707
|
if (status?.pid === pid) {
|
|
2703
2708
|
return;
|
|
@@ -2706,9 +2711,17 @@ class DaemonController {
|
|
|
2706
2711
|
await this.clearRuntimeFiles();
|
|
2707
2712
|
throw new Error(`weacpx daemon exited before reporting ready state (pid ${pid})`);
|
|
2708
2713
|
}
|
|
2714
|
+
if (startupWait?.shouldStopWaiting?.()) {
|
|
2715
|
+
return;
|
|
2716
|
+
}
|
|
2717
|
+
await startupWait?.onPoll?.({
|
|
2718
|
+
elapsedMs: this.now() - startedAt,
|
|
2719
|
+
timeoutMs,
|
|
2720
|
+
pid
|
|
2721
|
+
});
|
|
2709
2722
|
await this.onStartupPoll();
|
|
2710
2723
|
}
|
|
2711
|
-
throw new Error(`weacpx daemon did not report ready state within ${
|
|
2724
|
+
throw new Error(`weacpx daemon did not report ready state within ${timeoutMs}ms (pid ${pid})`);
|
|
2712
2725
|
}
|
|
2713
2726
|
async waitForShutdown(pid) {
|
|
2714
2727
|
const deadline = Date.now() + this.shutdownTimeoutMs;
|
|
@@ -2782,12 +2795,12 @@ import { spawn as spawn2 } from "node:child_process";
|
|
|
2782
2795
|
function createDaemonController(paths, options) {
|
|
2783
2796
|
return new DaemonController(paths, {
|
|
2784
2797
|
isProcessRunning: options.isProcessRunning ?? defaultIsProcessRunning2,
|
|
2785
|
-
spawnDetached: async () => {
|
|
2798
|
+
spawnDetached: async (spawnOptions) => {
|
|
2786
2799
|
await mkdir4(paths.runtimeDir, { recursive: true });
|
|
2787
2800
|
const stdoutHandle = await open(paths.stdoutLog, "a");
|
|
2788
2801
|
const stderrHandle = await open(paths.stderrLog, "a");
|
|
2789
2802
|
try {
|
|
2790
|
-
return await (options.spawnProcess ?? defaultSpawnProcess)(buildSpawnRequest(paths, options, stdoutHandle.fd, stderrHandle.fd));
|
|
2803
|
+
return await (options.spawnProcess ?? defaultSpawnProcess)(buildSpawnRequest(paths, options, stdoutHandle.fd, stderrHandle.fd, spawnOptions));
|
|
2791
2804
|
} finally {
|
|
2792
2805
|
await stdoutHandle.close();
|
|
2793
2806
|
await stderrHandle.close();
|
|
@@ -2804,7 +2817,7 @@ function defaultIsProcessRunning2(pid) {
|
|
|
2804
2817
|
return false;
|
|
2805
2818
|
}
|
|
2806
2819
|
}
|
|
2807
|
-
function buildSpawnRequest(paths, options, stdoutFd, stderrFd) {
|
|
2820
|
+
function buildSpawnRequest(paths, options, stdoutFd, stderrFd, spawnOptions = {}) {
|
|
2808
2821
|
const platform = options.platform ?? process.platform;
|
|
2809
2822
|
if (platform === "win32") {
|
|
2810
2823
|
return {
|
|
@@ -2825,7 +2838,8 @@ function buildSpawnRequest(paths, options, stdoutFd, stderrFd) {
|
|
|
2825
2838
|
WEACPX_DAEMON_ARG1: "run",
|
|
2826
2839
|
WEACPX_DAEMON_CWD: options.cwd,
|
|
2827
2840
|
WEACPX_DAEMON_STDOUT: paths.stdoutLog,
|
|
2828
|
-
WEACPX_DAEMON_STDERR: paths.stderrLog
|
|
2841
|
+
WEACPX_DAEMON_STDERR: paths.stderrLog,
|
|
2842
|
+
...spawnOptions.firstRunOnboarding ? { WEACPX_FIRST_RUN_ONBOARDING: spawnOptions.firstRunOnboarding } : {}
|
|
2829
2843
|
},
|
|
2830
2844
|
stdio: ["ignore", "pipe", "ignore"],
|
|
2831
2845
|
windowsHide: true
|
|
@@ -2839,7 +2853,10 @@ function buildSpawnRequest(paths, options, stdoutFd, stderrFd) {
|
|
|
2839
2853
|
options: {
|
|
2840
2854
|
cwd: options.cwd,
|
|
2841
2855
|
detached: true,
|
|
2842
|
-
env:
|
|
2856
|
+
env: {
|
|
2857
|
+
...options.env,
|
|
2858
|
+
...spawnOptions.firstRunOnboarding ? { WEACPX_FIRST_RUN_ONBOARDING: spawnOptions.firstRunOnboarding } : {}
|
|
2859
|
+
},
|
|
2843
2860
|
stdio: ["ignore", stdoutFd, stderrFd]
|
|
2844
2861
|
}
|
|
2845
2862
|
};
|
|
@@ -9829,74 +9846,58 @@ var init_state_store = __esm(() => {
|
|
|
9829
9846
|
init_types();
|
|
9830
9847
|
});
|
|
9831
9848
|
|
|
9832
|
-
// src/
|
|
9833
|
-
|
|
9834
|
-
|
|
9835
|
-
|
|
9836
|
-
|
|
9837
|
-
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
|
|
9841
|
-
|
|
9842
|
-
|
|
9843
|
-
|
|
9844
|
-
|
|
9845
|
-
|
|
9849
|
+
// src/config/agent-templates.ts
|
|
9850
|
+
function getAgentTemplate(name) {
|
|
9851
|
+
const template = TEMPLATES[name];
|
|
9852
|
+
if (!template) {
|
|
9853
|
+
return null;
|
|
9854
|
+
}
|
|
9855
|
+
return {
|
|
9856
|
+
...template
|
|
9857
|
+
};
|
|
9858
|
+
}
|
|
9859
|
+
function listAgentTemplates() {
|
|
9860
|
+
return Object.keys(TEMPLATES);
|
|
9861
|
+
}
|
|
9862
|
+
var TEMPLATES;
|
|
9863
|
+
var init_agent_templates = __esm(() => {
|
|
9864
|
+
TEMPLATES = {
|
|
9865
|
+
codex: {
|
|
9866
|
+
driver: "codex"
|
|
9846
9867
|
},
|
|
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;
|
|
9868
|
+
claude: {
|
|
9869
|
+
driver: "claude"
|
|
9854
9870
|
},
|
|
9855
|
-
|
|
9856
|
-
|
|
9871
|
+
opencode: {
|
|
9872
|
+
driver: "opencode"
|
|
9857
9873
|
},
|
|
9858
|
-
|
|
9859
|
-
|
|
9874
|
+
gemini: {
|
|
9875
|
+
driver: "gemini"
|
|
9860
9876
|
}
|
|
9861
9877
|
};
|
|
9862
9878
|
});
|
|
9863
9879
|
|
|
9864
|
-
// src/
|
|
9865
|
-
|
|
9866
|
-
|
|
9867
|
-
|
|
9868
|
-
|
|
9869
|
-
if (
|
|
9870
|
-
|
|
9871
|
-
if (
|
|
9872
|
-
|
|
9873
|
-
|
|
9874
|
-
|
|
9875
|
-
}
|
|
9876
|
-
function hasChannelCliProvider(type) {
|
|
9877
|
-
bootstrapBuiltinChannelCliProviders();
|
|
9878
|
-
return cliProviders.has(type);
|
|
9879
|
-
}
|
|
9880
|
-
function bootstrapBuiltinChannelCliProviders() {
|
|
9881
|
-
if (builtinProvidersRegistered)
|
|
9882
|
-
return;
|
|
9883
|
-
builtinProvidersRegistered = true;
|
|
9884
|
-
if (!cliProviders.has(weixinCliProvider.type))
|
|
9885
|
-
registerChannelCliProvider(weixinCliProvider);
|
|
9886
|
-
}
|
|
9887
|
-
function listChannelCliProviders() {
|
|
9888
|
-
bootstrapBuiltinChannelCliProviders();
|
|
9889
|
-
return Array.from(cliProviders.values());
|
|
9880
|
+
// src/plugins/plugin-home.ts
|
|
9881
|
+
import { mkdir as mkdir6, writeFile as writeFile5 } from "node:fs/promises";
|
|
9882
|
+
import { homedir as homedir3 } from "node:os";
|
|
9883
|
+
import { join as join3 } from "node:path";
|
|
9884
|
+
function resolvePluginHome(input = {}) {
|
|
9885
|
+
if (input.pluginHome?.trim())
|
|
9886
|
+
return input.pluginHome;
|
|
9887
|
+
if (process.env.WEACPX_PLUGIN_HOME?.trim())
|
|
9888
|
+
return process.env.WEACPX_PLUGIN_HOME;
|
|
9889
|
+
const home = input.home ?? process.env.HOME ?? homedir3();
|
|
9890
|
+
return join3(home, ".weacpx", "plugins");
|
|
9890
9891
|
}
|
|
9891
|
-
function
|
|
9892
|
-
|
|
9893
|
-
|
|
9892
|
+
async function ensurePluginHome(pluginHome) {
|
|
9893
|
+
await mkdir6(pluginHome, { recursive: true, mode: 448 });
|
|
9894
|
+
await writeFile5(join3(pluginHome, "package.json"), JSON.stringify({ private: true, type: "module" }, null, 2) + `
|
|
9895
|
+
`, { flag: "wx" }).catch((error2) => {
|
|
9896
|
+
if (error2.code !== "EEXIST")
|
|
9897
|
+
throw error2;
|
|
9898
|
+
});
|
|
9894
9899
|
}
|
|
9895
|
-
var
|
|
9896
|
-
var init_registry = __esm(() => {
|
|
9897
|
-
init_weixin_provider();
|
|
9898
|
-
cliProviders = new Map;
|
|
9899
|
-
});
|
|
9900
|
+
var init_plugin_home = () => {};
|
|
9900
9901
|
|
|
9901
9902
|
// src/weixin/storage/ensure-dir.ts
|
|
9902
9903
|
import fs2 from "node:fs";
|
|
@@ -11984,7 +11985,7 @@ var init_types2 = __esm(() => {
|
|
|
11984
11985
|
});
|
|
11985
11986
|
|
|
11986
11987
|
// src/channels/media-store.ts
|
|
11987
|
-
import { access as access2, mkdir as
|
|
11988
|
+
import { access as access2, mkdir as mkdir7, readdir, rm as rm4, stat, writeFile as writeFile6 } from "node:fs/promises";
|
|
11988
11989
|
import path6 from "node:path";
|
|
11989
11990
|
|
|
11990
11991
|
class RuntimeMediaStore {
|
|
@@ -12002,13 +12003,13 @@ class RuntimeMediaStore {
|
|
|
12002
12003
|
const safeMessageId = safePathSegment(input.messageId || "message");
|
|
12003
12004
|
const baseFileName = sanitizeMediaFileName(input.fileName ?? "attachment", input.mimeType);
|
|
12004
12005
|
const dir = path6.join(this.rootDir, input.channelId, safeChatKey, safeMessageId);
|
|
12005
|
-
await
|
|
12006
|
+
await mkdir7(dir, { recursive: true });
|
|
12006
12007
|
const resolvedRoot = path6.resolve(this.rootDir);
|
|
12007
12008
|
const resolvedFile = path6.resolve(path6.join(dir, await uniqueFileName(dir, baseFileName)));
|
|
12008
12009
|
if (!isPathInside(resolvedFile, resolvedRoot)) {
|
|
12009
12010
|
throw new Error("media path escapes runtime media root");
|
|
12010
12011
|
}
|
|
12011
|
-
await
|
|
12012
|
+
await writeFile6(resolvedFile, input.buffer);
|
|
12012
12013
|
return {
|
|
12013
12014
|
kind: input.kind,
|
|
12014
12015
|
filePath: resolvedFile,
|
|
@@ -14167,16 +14168,16 @@ var init_deliver_coordinator_message = __esm(() => {
|
|
|
14167
14168
|
});
|
|
14168
14169
|
|
|
14169
14170
|
// src/weixin/monitor/consumer-lock.ts
|
|
14170
|
-
import { mkdir as
|
|
14171
|
-
import { dirname as dirname6, join as
|
|
14172
|
-
import { homedir as
|
|
14171
|
+
import { mkdir as mkdir8, open as open2, readFile as readFile6, rm as rm5 } from "node:fs/promises";
|
|
14172
|
+
import { dirname as dirname6, join as join4 } from "node:path";
|
|
14173
|
+
import { homedir as homedir4 } from "node:os";
|
|
14173
14174
|
function createWeixinConsumerLock(options = {}) {
|
|
14174
|
-
const lockFilePath = options.lockFilePath ??
|
|
14175
|
+
const lockFilePath = options.lockFilePath ?? join4(homedir4(), ".weacpx", "runtime", "weixin-consumer.lock.json");
|
|
14175
14176
|
const isProcessRunning = options.isProcessRunning ?? defaultIsProcessRunning4;
|
|
14176
14177
|
const onDiagnostic = options.onDiagnostic;
|
|
14177
14178
|
return {
|
|
14178
14179
|
async acquire(meta2) {
|
|
14179
|
-
await
|
|
14180
|
+
await mkdir8(dirname6(lockFilePath), { recursive: true });
|
|
14180
14181
|
while (true) {
|
|
14181
14182
|
try {
|
|
14182
14183
|
const handle = await open2(lockFilePath, "wx");
|
|
@@ -14569,27 +14570,74 @@ var init_create_channel = __esm(() => {
|
|
|
14569
14570
|
channelFactories = new Map;
|
|
14570
14571
|
});
|
|
14571
14572
|
|
|
14572
|
-
// src/
|
|
14573
|
-
|
|
14574
|
-
|
|
14575
|
-
|
|
14576
|
-
|
|
14577
|
-
|
|
14578
|
-
|
|
14579
|
-
|
|
14580
|
-
|
|
14581
|
-
|
|
14582
|
-
|
|
14573
|
+
// src/channels/cli/weixin-provider.ts
|
|
14574
|
+
var weixinCliProvider;
|
|
14575
|
+
var init_weixin_provider = __esm(() => {
|
|
14576
|
+
weixinCliProvider = {
|
|
14577
|
+
type: "weixin",
|
|
14578
|
+
displayName: "Weixin",
|
|
14579
|
+
supportsLogin: true,
|
|
14580
|
+
parseAddArgs(args) {
|
|
14581
|
+
if (args.length > 0)
|
|
14582
|
+
return { ok: false, message: `unknown weixin options: ${args.join(" ")}` };
|
|
14583
|
+
return { ok: true, input: {} };
|
|
14584
|
+
},
|
|
14585
|
+
buildDefaultConfig(_input) {
|
|
14586
|
+
return { id: "weixin", type: "weixin", enabled: true };
|
|
14587
|
+
},
|
|
14588
|
+
validateConfig(config2) {
|
|
14589
|
+
const issues = [];
|
|
14590
|
+
if (config2.id !== "weixin")
|
|
14591
|
+
issues.push({ kind: "invalid-config", message: "weixin channel id must be weixin" });
|
|
14592
|
+
if (config2.type !== "weixin")
|
|
14593
|
+
issues.push({ kind: "invalid-config", message: "weixin channel type must be weixin" });
|
|
14594
|
+
return issues;
|
|
14595
|
+
},
|
|
14596
|
+
renderSummary(config2) {
|
|
14597
|
+
return [`type: ${config2.type}`, `enabled: ${config2.enabled}`];
|
|
14598
|
+
},
|
|
14599
|
+
async promptForMissingFields(input, _io) {
|
|
14600
|
+
return input;
|
|
14601
|
+
}
|
|
14602
|
+
};
|
|
14603
|
+
});
|
|
14604
|
+
|
|
14605
|
+
// src/channels/cli/registry.ts
|
|
14606
|
+
function registerChannelCliProvider(provider) {
|
|
14607
|
+
const type = provider.type.trim();
|
|
14608
|
+
if (!type)
|
|
14609
|
+
throw new Error("channel CLI provider type must be non-empty");
|
|
14610
|
+
if (type.includes(":"))
|
|
14611
|
+
throw new Error("channel CLI provider type must not contain ':'");
|
|
14612
|
+
if (cliProviders.has(type)) {
|
|
14613
|
+
throw new Error(`channel CLI provider is already registered: ${type}`);
|
|
14614
|
+
}
|
|
14615
|
+
cliProviders.set(type, provider);
|
|
14583
14616
|
}
|
|
14584
|
-
|
|
14585
|
-
|
|
14586
|
-
|
|
14587
|
-
`, { flag: "wx" }).catch((error2) => {
|
|
14588
|
-
if (error2.code !== "EEXIST")
|
|
14589
|
-
throw error2;
|
|
14590
|
-
});
|
|
14617
|
+
function hasChannelCliProvider(type) {
|
|
14618
|
+
bootstrapBuiltinChannelCliProviders();
|
|
14619
|
+
return cliProviders.has(type);
|
|
14591
14620
|
}
|
|
14592
|
-
|
|
14621
|
+
function bootstrapBuiltinChannelCliProviders() {
|
|
14622
|
+
if (builtinProvidersRegistered)
|
|
14623
|
+
return;
|
|
14624
|
+
builtinProvidersRegistered = true;
|
|
14625
|
+
if (!cliProviders.has(weixinCliProvider.type))
|
|
14626
|
+
registerChannelCliProvider(weixinCliProvider);
|
|
14627
|
+
}
|
|
14628
|
+
function listChannelCliProviders() {
|
|
14629
|
+
bootstrapBuiltinChannelCliProviders();
|
|
14630
|
+
return Array.from(cliProviders.values());
|
|
14631
|
+
}
|
|
14632
|
+
function getChannelCliProvider(type) {
|
|
14633
|
+
bootstrapBuiltinChannelCliProviders();
|
|
14634
|
+
return cliProviders.get(type) ?? null;
|
|
14635
|
+
}
|
|
14636
|
+
var cliProviders, builtinProvidersRegistered = false;
|
|
14637
|
+
var init_registry = __esm(() => {
|
|
14638
|
+
init_weixin_provider();
|
|
14639
|
+
cliProviders = new Map;
|
|
14640
|
+
});
|
|
14593
14641
|
|
|
14594
14642
|
// src/channels/plugin.ts
|
|
14595
14643
|
function registerChannelPlugin(plugin) {
|
|
@@ -14852,7 +14900,7 @@ var init_bootstrap = __esm(() => {
|
|
|
14852
14900
|
|
|
14853
14901
|
// src/logging/app-logger.ts
|
|
14854
14902
|
import { appendFile, mkdir as mkdir9, readdir as readdir2, rename, rm as rm6, stat as stat2 } from "node:fs/promises";
|
|
14855
|
-
import { basename, dirname as
|
|
14903
|
+
import { basename, dirname as dirname8, join as join9 } from "node:path";
|
|
14856
14904
|
function createNoopAppLogger() {
|
|
14857
14905
|
return {
|
|
14858
14906
|
debug: async () => {},
|
|
@@ -14892,7 +14940,7 @@ function createAppLogger(options) {
|
|
|
14892
14940
|
return;
|
|
14893
14941
|
}
|
|
14894
14942
|
const line = formatLogLine(now(), level, event, message, context);
|
|
14895
|
-
await mkdir9(
|
|
14943
|
+
await mkdir9(dirname8(options.filePath), { recursive: true });
|
|
14896
14944
|
await rotateIfNeeded(options.filePath, Buffer.byteLength(line), options.maxSizeBytes, options.maxFiles);
|
|
14897
14945
|
await appendFile(options.filePath, line, "utf8");
|
|
14898
14946
|
}
|
|
@@ -14930,7 +14978,7 @@ async function rotateIfNeeded(filePath, incomingSize, maxSizeBytes, maxFiles) {
|
|
|
14930
14978
|
await rename(filePath, `${filePath}.1`);
|
|
14931
14979
|
}
|
|
14932
14980
|
async function cleanupExpiredRotatedLogs(filePath, retentionDays, now) {
|
|
14933
|
-
const parentDir =
|
|
14981
|
+
const parentDir = dirname8(filePath);
|
|
14934
14982
|
const prefix = `${basename(filePath)}.`;
|
|
14935
14983
|
const cutoff = now().getTime() - retentionDays * 24 * 60 * 60 * 1000;
|
|
14936
14984
|
let files = [];
|
|
@@ -14946,7 +14994,7 @@ async function cleanupExpiredRotatedLogs(filePath, retentionDays, now) {
|
|
|
14946
14994
|
if (!file.startsWith(prefix) || !/^\d+$/.test(file.slice(prefix.length))) {
|
|
14947
14995
|
continue;
|
|
14948
14996
|
}
|
|
14949
|
-
const candidate =
|
|
14997
|
+
const candidate = join9(parentDir, file);
|
|
14950
14998
|
const details = await stat2(candidate);
|
|
14951
14999
|
if (details.mtime.getTime() < cutoff) {
|
|
14952
15000
|
await rm6(candidate, { force: true });
|
|
@@ -14981,7 +15029,7 @@ var init_app_logger = __esm(() => {
|
|
|
14981
15029
|
});
|
|
14982
15030
|
|
|
14983
15031
|
// src/transport/acpx-session-index.ts
|
|
14984
|
-
import { readFile as
|
|
15032
|
+
import { readFile as readFile10 } from "node:fs/promises";
|
|
14985
15033
|
import { homedir as homedir5 } from "node:os";
|
|
14986
15034
|
import { resolve as resolve2 } from "node:path";
|
|
14987
15035
|
async function resolveSessionAgentCommandFromIndex(session) {
|
|
@@ -14990,7 +15038,7 @@ async function resolveSessionAgentCommandFromIndex(session) {
|
|
|
14990
15038
|
return;
|
|
14991
15039
|
}
|
|
14992
15040
|
try {
|
|
14993
|
-
const raw = await
|
|
15041
|
+
const raw = await readFile10(resolve2(home, ".acpx", "sessions", "index.json"), "utf8");
|
|
14994
15042
|
const parsed = JSON.parse(raw);
|
|
14995
15043
|
const targetCwd = resolve2(session.cwd);
|
|
14996
15044
|
const match = parsed.entries?.find((entry) => entry.name === session.transportSession && entry.cwd === targetCwd && typeof entry.agentCommand === "string" && entry.agentCommand.trim().length > 0);
|
|
@@ -17304,37 +17352,6 @@ function isPartialPromptOutputError(message) {
|
|
|
17304
17352
|
return message.includes("未收到最终回复");
|
|
17305
17353
|
}
|
|
17306
17354
|
|
|
17307
|
-
// src/config/agent-templates.ts
|
|
17308
|
-
function getAgentTemplate(name) {
|
|
17309
|
-
const template = TEMPLATES[name];
|
|
17310
|
-
if (!template) {
|
|
17311
|
-
return null;
|
|
17312
|
-
}
|
|
17313
|
-
return {
|
|
17314
|
-
...template
|
|
17315
|
-
};
|
|
17316
|
-
}
|
|
17317
|
-
function listAgentTemplates() {
|
|
17318
|
-
return Object.keys(TEMPLATES);
|
|
17319
|
-
}
|
|
17320
|
-
var TEMPLATES;
|
|
17321
|
-
var init_agent_templates = __esm(() => {
|
|
17322
|
-
TEMPLATES = {
|
|
17323
|
-
codex: {
|
|
17324
|
-
driver: "codex"
|
|
17325
|
-
},
|
|
17326
|
-
claude: {
|
|
17327
|
-
driver: "claude"
|
|
17328
|
-
},
|
|
17329
|
-
opencode: {
|
|
17330
|
-
driver: "opencode"
|
|
17331
|
-
},
|
|
17332
|
-
gemini: {
|
|
17333
|
-
driver: "gemini"
|
|
17334
|
-
}
|
|
17335
|
-
};
|
|
17336
|
-
});
|
|
17337
|
-
|
|
17338
17355
|
// src/commands/handlers/agent-handler.ts
|
|
17339
17356
|
function handleAgents(context) {
|
|
17340
17357
|
return { text: context.config ? renderAgents(context.config) : "No config loaded." };
|
|
@@ -17790,11 +17807,11 @@ var init_session_recovery_handler = __esm(() => {
|
|
|
17790
17807
|
});
|
|
17791
17808
|
|
|
17792
17809
|
// src/recovery/auto-install-optional-dep.ts
|
|
17793
|
-
import { spawn as
|
|
17810
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
17794
17811
|
import { createWriteStream } from "node:fs";
|
|
17795
17812
|
import { mkdir as mkdir10 } from "node:fs/promises";
|
|
17796
17813
|
import { homedir as homedir6 } from "node:os";
|
|
17797
|
-
import { join as
|
|
17814
|
+
import { join as join10 } from "node:path";
|
|
17798
17815
|
async function autoInstallOptionalDep(pkg, parentPackages, options = {}) {
|
|
17799
17816
|
const runCli = options.runCli ?? defaultRunCli;
|
|
17800
17817
|
const openLog = options.openLog ?? defaultLogSink;
|
|
@@ -17873,7 +17890,7 @@ function tail(text, lines) {
|
|
|
17873
17890
|
}
|
|
17874
17891
|
var PRECISE_TIMEOUT_MS = 90000, GLOBAL_TIMEOUT_MS = 90000, TAIL_LINES = 10, PRECISE_COMMANDS, defaultRunCli = async (cmd, args, options) => {
|
|
17875
17892
|
return await new Promise((resolve3) => {
|
|
17876
|
-
const child =
|
|
17893
|
+
const child = spawn5(cmd, args, {
|
|
17877
17894
|
cwd: options.cwd,
|
|
17878
17895
|
stdio: ["ignore", "pipe", "pipe"],
|
|
17879
17896
|
shell: process.platform === "win32"
|
|
@@ -17909,10 +17926,10 @@ ${err.message}`, reason: "spawn" });
|
|
|
17909
17926
|
});
|
|
17910
17927
|
});
|
|
17911
17928
|
}, defaultLogSink = async () => {
|
|
17912
|
-
const dir =
|
|
17929
|
+
const dir = join10(homedir6(), ".weacpx", "logs");
|
|
17913
17930
|
await mkdir10(dir, { recursive: true });
|
|
17914
17931
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "").replace(/-/g, "");
|
|
17915
|
-
const path13 =
|
|
17932
|
+
const path13 = join10(dir, `auto-install-${timestamp}.log`);
|
|
17916
17933
|
const stream = createWriteStream(path13, { flags: "a" });
|
|
17917
17934
|
return {
|
|
17918
17935
|
path: path13,
|
|
@@ -17934,11 +17951,11 @@ var init_auto_install_optional_dep = __esm(() => {
|
|
|
17934
17951
|
});
|
|
17935
17952
|
|
|
17936
17953
|
// src/recovery/discover-parent-package-paths.ts
|
|
17937
|
-
import { spawn as
|
|
17954
|
+
import { spawn as spawn6 } from "node:child_process";
|
|
17938
17955
|
import { createRequire as createRequire3 } from "node:module";
|
|
17939
17956
|
import { access as access3 } from "node:fs/promises";
|
|
17940
17957
|
import { homedir as homedir7 } from "node:os";
|
|
17941
|
-
import { dirname as
|
|
17958
|
+
import { dirname as dirname9, join as join11 } from "node:path";
|
|
17942
17959
|
function deriveParentPackageName(platformPackage) {
|
|
17943
17960
|
return platformPackage.replace(/-(?:linux|darwin|win32|windows|freebsd|openbsd|sunos|aix)(?:-(?:x64|arm64|ia32|arm|ppc64|s390x))?(?:-(?:baseline|musl|gnu|gnueabihf|musleabihf|msvc))?$/, "");
|
|
17944
17961
|
}
|
|
@@ -17951,7 +17968,7 @@ async function discoverParentPackagePaths(platformPackage, seedPath, deps = {})
|
|
|
17951
17968
|
const queryRoot = deps.queryPackageManagerRoot ?? defaultQueryPackageManagerRoot;
|
|
17952
17969
|
const parentName = deriveParentPackageName(platformPackage);
|
|
17953
17970
|
const rawCandidates = [];
|
|
17954
|
-
const bunGlobalRoot = env.BUN_INSTALL ?
|
|
17971
|
+
const bunGlobalRoot = env.BUN_INSTALL ? join11(env.BUN_INSTALL, "install", "global", "node_modules") : join11(home, ".bun", "install", "global", "node_modules");
|
|
17955
17972
|
const [npmRoot, pnpmRoot, yarnRoot] = await Promise.all([
|
|
17956
17973
|
queryRoot("npm"),
|
|
17957
17974
|
queryRoot("pnpm"),
|
|
@@ -17974,20 +17991,20 @@ async function discoverParentPackagePaths(platformPackage, seedPath, deps = {})
|
|
|
17974
17991
|
if (resolved)
|
|
17975
17992
|
rawCandidates.push({ path: resolved, manager: classify(resolved) });
|
|
17976
17993
|
}
|
|
17977
|
-
rawCandidates.push({ path:
|
|
17994
|
+
rawCandidates.push({ path: join11(bunGlobalRoot, parentName), manager: "bun" });
|
|
17978
17995
|
if (npmRoot)
|
|
17979
|
-
rawCandidates.push({ path:
|
|
17996
|
+
rawCandidates.push({ path: join11(npmRoot, parentName), manager: "npm" });
|
|
17980
17997
|
if (pnpmRoot)
|
|
17981
|
-
rawCandidates.push({ path:
|
|
17998
|
+
rawCandidates.push({ path: join11(pnpmRoot, parentName), manager: "pnpm" });
|
|
17982
17999
|
if (yarnRoot)
|
|
17983
|
-
rawCandidates.push({ path:
|
|
18000
|
+
rawCandidates.push({ path: join11(yarnRoot, parentName), manager: "yarn" });
|
|
17984
18001
|
const seen = new Set;
|
|
17985
18002
|
const verified = [];
|
|
17986
18003
|
for (const candidate of rawCandidates) {
|
|
17987
18004
|
if (seen.has(candidate.path))
|
|
17988
18005
|
continue;
|
|
17989
18006
|
seen.add(candidate.path);
|
|
17990
|
-
if (await fsExists(
|
|
18007
|
+
if (await fsExists(join11(candidate.path, "package.json"))) {
|
|
17991
18008
|
verified.push(candidate);
|
|
17992
18009
|
}
|
|
17993
18010
|
}
|
|
@@ -18011,7 +18028,7 @@ function defaultResolveFromCwd(name, cwd) {
|
|
|
18011
18028
|
const pkgJson = require2.resolve(`${name}/package.json`, {
|
|
18012
18029
|
paths: [cwd, ...require2.resolve.paths(name) ?? []]
|
|
18013
18030
|
});
|
|
18014
|
-
return
|
|
18031
|
+
return dirname9(pkgJson);
|
|
18015
18032
|
} catch {
|
|
18016
18033
|
return null;
|
|
18017
18034
|
}
|
|
@@ -18028,7 +18045,7 @@ async function defaultQueryPackageManagerRoot(tool) {
|
|
|
18028
18045
|
};
|
|
18029
18046
|
let child;
|
|
18030
18047
|
try {
|
|
18031
|
-
child =
|
|
18048
|
+
child = spawn6(spec.cmd, spec.args, {
|
|
18032
18049
|
stdio: ["ignore", "pipe", "pipe"],
|
|
18033
18050
|
shell: process.platform === "win32"
|
|
18034
18051
|
});
|
|
@@ -18058,7 +18075,7 @@ async function defaultQueryPackageManagerRoot(tool) {
|
|
|
18058
18075
|
const trimmed = stdout2.trim().split(/\r?\n/).pop()?.trim() ?? "";
|
|
18059
18076
|
if (!trimmed)
|
|
18060
18077
|
return done(null);
|
|
18061
|
-
done(spec.postfix ?
|
|
18078
|
+
done(spec.postfix ? join11(trimmed, spec.postfix) : trimmed);
|
|
18062
18079
|
});
|
|
18063
18080
|
});
|
|
18064
18081
|
}
|
|
@@ -22624,6 +22641,7 @@ async function runConsole(paths, deps) {
|
|
|
22624
22641
|
let heartbeatTimer = null;
|
|
22625
22642
|
let gcResetTimer = null;
|
|
22626
22643
|
let consumerLockAcquired = false;
|
|
22644
|
+
let daemonRuntimeStarted = false;
|
|
22627
22645
|
const shutdownController = new AbortController;
|
|
22628
22646
|
const signalHandler = () => {
|
|
22629
22647
|
shutdownController.abort();
|
|
@@ -22632,6 +22650,9 @@ async function runConsole(paths, deps) {
|
|
|
22632
22650
|
addProcessListener("SIGTERM", signalHandler);
|
|
22633
22651
|
try {
|
|
22634
22652
|
runtime = await deps.buildApp(paths);
|
|
22653
|
+
if (deps.afterBuild) {
|
|
22654
|
+
await deps.afterBuild(runtime);
|
|
22655
|
+
}
|
|
22635
22656
|
try {
|
|
22636
22657
|
await runtime.orchestration.service.purgeExpiredResetCoordinators({
|
|
22637
22658
|
cutoffDays: 7,
|
|
@@ -22639,20 +22660,6 @@ async function runConsole(paths, deps) {
|
|
|
22639
22660
|
});
|
|
22640
22661
|
} catch {}
|
|
22641
22662
|
consumerLock = deps.consumerLock ?? deps.consumerLockFactory?.(runtime);
|
|
22642
|
-
if (deps.daemonRuntime) {
|
|
22643
|
-
await deps.daemonRuntime.start({
|
|
22644
|
-
configPath: paths.configPath,
|
|
22645
|
-
statePath: paths.statePath
|
|
22646
|
-
});
|
|
22647
|
-
await runtime.orchestration.server.start();
|
|
22648
|
-
heartbeatTimer = setIntervalFn(() => {
|
|
22649
|
-
deps.daemonRuntime?.heartbeat().catch(() => {});
|
|
22650
|
-
}, deps.heartbeatIntervalMs ?? 30000);
|
|
22651
|
-
const runtimeForGc = runtime;
|
|
22652
|
-
gcResetTimer = setIntervalFn(() => {
|
|
22653
|
-
runtimeForGc.orchestration.service.purgeExpiredResetCoordinators({ cutoffDays: 7, trigger: "interval" }).catch(() => {});
|
|
22654
|
-
}, 86400000);
|
|
22655
|
-
}
|
|
22656
22663
|
if (consumerLock) {
|
|
22657
22664
|
const lockMeta = {
|
|
22658
22665
|
pid: processPid,
|
|
@@ -22700,6 +22707,24 @@ async function runConsole(paths, deps) {
|
|
|
22700
22707
|
throw error2;
|
|
22701
22708
|
}
|
|
22702
22709
|
}
|
|
22710
|
+
if (deps.beforeReady) {
|
|
22711
|
+
await deps.beforeReady(runtime);
|
|
22712
|
+
}
|
|
22713
|
+
if (deps.daemonRuntime) {
|
|
22714
|
+
await deps.daemonRuntime.start({
|
|
22715
|
+
configPath: paths.configPath,
|
|
22716
|
+
statePath: paths.statePath
|
|
22717
|
+
});
|
|
22718
|
+
daemonRuntimeStarted = true;
|
|
22719
|
+
await runtime.orchestration.server.start();
|
|
22720
|
+
heartbeatTimer = setIntervalFn(() => {
|
|
22721
|
+
deps.daemonRuntime?.heartbeat().catch(() => {});
|
|
22722
|
+
}, deps.heartbeatIntervalMs ?? 30000);
|
|
22723
|
+
const runtimeForGc = runtime;
|
|
22724
|
+
gcResetTimer = setIntervalFn(() => {
|
|
22725
|
+
runtimeForGc.orchestration.service.purgeExpiredResetCoordinators({ cutoffDays: 7, trigger: "interval" }).catch(() => {});
|
|
22726
|
+
}, 86400000);
|
|
22727
|
+
}
|
|
22703
22728
|
await deps.channels.startAll({
|
|
22704
22729
|
agent: runtime.agent,
|
|
22705
22730
|
abortSignal: shutdownController.signal,
|
|
@@ -22718,7 +22743,8 @@ async function runConsole(paths, deps) {
|
|
|
22718
22743
|
consumerLock,
|
|
22719
22744
|
consumerLockAcquired,
|
|
22720
22745
|
processPid,
|
|
22721
|
-
channels: deps.channels
|
|
22746
|
+
channels: deps.channels,
|
|
22747
|
+
daemonRuntimeStarted
|
|
22722
22748
|
});
|
|
22723
22749
|
}
|
|
22724
22750
|
}
|
|
@@ -22753,7 +22779,7 @@ async function runCleanupSequence(input) {
|
|
|
22753
22779
|
cleanupError ??= error2;
|
|
22754
22780
|
}
|
|
22755
22781
|
}
|
|
22756
|
-
if (input.daemonRuntime) {
|
|
22782
|
+
if (input.daemonRuntime && input.daemonRuntimeStarted) {
|
|
22757
22783
|
try {
|
|
22758
22784
|
await input.daemonRuntime.stop();
|
|
22759
22785
|
} catch (error2) {
|
|
@@ -22803,8 +22829,8 @@ function encodeBridgeSessionNoteEvent(event) {
|
|
|
22803
22829
|
}
|
|
22804
22830
|
|
|
22805
22831
|
// src/transport/acpx-bridge/acpx-bridge-client.ts
|
|
22806
|
-
import { spawn as
|
|
22807
|
-
import { fileURLToPath as
|
|
22832
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
22833
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
22808
22834
|
import { createInterface } from "node:readline";
|
|
22809
22835
|
|
|
22810
22836
|
class AcpxBridgeClient {
|
|
@@ -22924,12 +22950,12 @@ function buildBridgeSpawnSpec(options) {
|
|
|
22924
22950
|
};
|
|
22925
22951
|
}
|
|
22926
22952
|
async function spawnAcpxBridgeClient(options = {}) {
|
|
22927
|
-
const bridgeEntryPath = options.bridgeEntryPath ??
|
|
22953
|
+
const bridgeEntryPath = options.bridgeEntryPath ?? fileURLToPath3(new URL("../../bridge/bridge-main.ts", import.meta.url));
|
|
22928
22954
|
const spawnSpec = buildBridgeSpawnSpec({
|
|
22929
22955
|
execPath: process.execPath,
|
|
22930
22956
|
bridgeEntryPath
|
|
22931
22957
|
});
|
|
22932
|
-
const child =
|
|
22958
|
+
const child = spawn7(spawnSpec.command, spawnSpec.args, {
|
|
22933
22959
|
cwd: options.cwd ?? process.cwd(),
|
|
22934
22960
|
env: {
|
|
22935
22961
|
...process.env,
|
|
@@ -23743,12 +23769,12 @@ var init_streaming_prompt = __esm(() => {
|
|
|
23743
23769
|
|
|
23744
23770
|
// src/transport/acpx-cli/node-pty-helper.ts
|
|
23745
23771
|
import { chmod as chmodFs } from "node:fs/promises";
|
|
23746
|
-
import { dirname as
|
|
23772
|
+
import { dirname as dirname10, join as join12 } from "node:path";
|
|
23747
23773
|
function resolveNodePtyHelperPath(packageJsonPath, platform, arch) {
|
|
23748
23774
|
if (platform === "win32") {
|
|
23749
23775
|
return null;
|
|
23750
23776
|
}
|
|
23751
|
-
return
|
|
23777
|
+
return join12(dirname10(packageJsonPath), "prebuilds", `${platform}-${arch}`, "spawn-helper");
|
|
23752
23778
|
}
|
|
23753
23779
|
async function ensureNodePtyHelperExecutable(helperPath, chmod2 = chmodFs) {
|
|
23754
23780
|
if (!helperPath) {
|
|
@@ -23767,10 +23793,10 @@ var init_node_pty_helper = () => {};
|
|
|
23767
23793
|
|
|
23768
23794
|
// src/transport/acpx-queue-owner-launcher.ts
|
|
23769
23795
|
import { createHash as createHash3 } from "node:crypto";
|
|
23770
|
-
import { spawn as
|
|
23771
|
-
import { readFile as
|
|
23796
|
+
import { spawn as spawn8 } from "node:child_process";
|
|
23797
|
+
import { readFile as readFile11, unlink } from "node:fs/promises";
|
|
23772
23798
|
import { homedir as homedir8 } from "node:os";
|
|
23773
|
-
import { join as
|
|
23799
|
+
import { join as join13 } from "node:path";
|
|
23774
23800
|
function buildWeacpxMcpServerSpec(input) {
|
|
23775
23801
|
const { command, args } = splitCommandLine(input.weacpxCommand);
|
|
23776
23802
|
return {
|
|
@@ -23900,7 +23926,7 @@ function stringEnv(env) {
|
|
|
23900
23926
|
}
|
|
23901
23927
|
async function defaultQueueOwnerSpawner(command, args, options) {
|
|
23902
23928
|
await new Promise((resolve3, reject) => {
|
|
23903
|
-
const child =
|
|
23929
|
+
const child = spawn8(command, args, {
|
|
23904
23930
|
detached: true,
|
|
23905
23931
|
stdio: "ignore",
|
|
23906
23932
|
env: options.env,
|
|
@@ -23922,7 +23948,7 @@ async function terminateAcpxQueueOwner(sessionId) {
|
|
|
23922
23948
|
const lockPath = queueLockFilePath(sessionId);
|
|
23923
23949
|
let owner;
|
|
23924
23950
|
try {
|
|
23925
|
-
owner = JSON.parse(await
|
|
23951
|
+
owner = JSON.parse(await readFile11(lockPath, "utf8"));
|
|
23926
23952
|
} catch {
|
|
23927
23953
|
return;
|
|
23928
23954
|
}
|
|
@@ -23932,7 +23958,7 @@ async function terminateAcpxQueueOwner(sessionId) {
|
|
|
23932
23958
|
await unlink(lockPath).catch(() => {});
|
|
23933
23959
|
}
|
|
23934
23960
|
function queueLockFilePath(sessionId) {
|
|
23935
|
-
return
|
|
23961
|
+
return join13(homedir8(), ".acpx", "queues", `${shortHash(sessionId, 24)}.lock`);
|
|
23936
23962
|
}
|
|
23937
23963
|
function shortHash(value, length) {
|
|
23938
23964
|
return createHash3("sha256").update(value).digest("hex").slice(0, length);
|
|
@@ -23971,12 +23997,12 @@ function permissionModeToFlag(permissionMode) {
|
|
|
23971
23997
|
|
|
23972
23998
|
// src/transport/acpx-cli/acpx-cli-transport.ts
|
|
23973
23999
|
import { createRequire as createRequire5 } from "node:module";
|
|
23974
|
-
import { spawn as
|
|
24000
|
+
import { spawn as spawn9 } from "node:child_process";
|
|
23975
24001
|
import { spawn as spawnPty } from "node-pty";
|
|
23976
24002
|
async function defaultRunner(command, args, options) {
|
|
23977
24003
|
return await new Promise((resolve3, reject) => {
|
|
23978
24004
|
const spawnSpec = resolveSpawnCommand(command, args);
|
|
23979
|
-
const child =
|
|
24005
|
+
const child = spawn9(spawnSpec.command, spawnSpec.args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
23980
24006
|
let stdout2 = "";
|
|
23981
24007
|
let stderr = "";
|
|
23982
24008
|
const onAbort = () => {
|
|
@@ -24223,7 +24249,7 @@ ${baseText}` : "" };
|
|
|
24223
24249
|
}
|
|
24224
24250
|
async runStreamingPrompt(command, args, reply, formatToolCalls = false, toolEventMode = "text", replyContext, onSegment, onToolEvent) {
|
|
24225
24251
|
const hooks = this.streamingHooks;
|
|
24226
|
-
const doSpawn = hooks.spawnPrompt ?? ((cmd, spawnArgs) =>
|
|
24252
|
+
const doSpawn = hooks.spawnPrompt ?? ((cmd, spawnArgs) => spawn9(cmd, spawnArgs, { stdio: ["ignore", "pipe", "pipe"] }));
|
|
24227
24253
|
const setIntervalFn = hooks.setIntervalFn ?? ((fn, delay) => setInterval(fn, delay));
|
|
24228
24254
|
const clearIntervalFn = hooks.clearIntervalFn ?? ((timer) => clearInterval(timer));
|
|
24229
24255
|
const maxSegmentWaitMs = hooks.maxSegmentWaitMs ?? 30000;
|
|
@@ -24583,8 +24609,8 @@ __export(exports_main, {
|
|
|
24583
24609
|
});
|
|
24584
24610
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
24585
24611
|
import { homedir as homedir9 } from "node:os";
|
|
24586
|
-
import { dirname as
|
|
24587
|
-
import { fileURLToPath as
|
|
24612
|
+
import { dirname as dirname11, join as join14 } from "node:path";
|
|
24613
|
+
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
24588
24614
|
function startProgressHeartbeat(orchestration, config2, logger2, channel) {
|
|
24589
24615
|
const thresholdSeconds = config2.orchestration.progressHeartbeatSeconds;
|
|
24590
24616
|
if (thresholdSeconds <= 0) {
|
|
@@ -24989,6 +25015,7 @@ async function buildApp(paths, deps = {}) {
|
|
|
24989
25015
|
configStore,
|
|
24990
25016
|
logger: logger2,
|
|
24991
25017
|
quota,
|
|
25018
|
+
transport,
|
|
24992
25019
|
orchestration: {
|
|
24993
25020
|
service: orchestration,
|
|
24994
25021
|
server: orchestrationServer,
|
|
@@ -25038,8 +25065,8 @@ async function main() {
|
|
|
25038
25065
|
}
|
|
25039
25066
|
}
|
|
25040
25067
|
async function prepareChannelMedia(configPath, config2) {
|
|
25041
|
-
const runtimeDir =
|
|
25042
|
-
const mediaRootDir =
|
|
25068
|
+
const runtimeDir = join14(dirname11(configPath), "runtime");
|
|
25069
|
+
const mediaRootDir = join14(runtimeDir, "media");
|
|
25043
25070
|
const mediaStore = new RuntimeMediaStore({ rootDir: mediaRootDir });
|
|
25044
25071
|
await mediaStore.cleanupExpired().catch((error2) => {
|
|
25045
25072
|
console.error("[weacpx] media cleanup failed:", error2 instanceof Error ? error2.message : String(error2));
|
|
@@ -25053,7 +25080,7 @@ function resolveRuntimePaths() {
|
|
|
25053
25080
|
throw new Error("Unable to resolve the current user home directory");
|
|
25054
25081
|
}
|
|
25055
25082
|
const configPath = process.env.WEACPX_CONFIG ?? `${home}/.weacpx/config.json`;
|
|
25056
|
-
const runtimeDir =
|
|
25083
|
+
const runtimeDir = join14(dirname11(configPath), "runtime");
|
|
25057
25084
|
return {
|
|
25058
25085
|
configPath,
|
|
25059
25086
|
statePath: process.env.WEACPX_STATE ?? `${home}/.weacpx/state.json`,
|
|
@@ -25062,14 +25089,14 @@ function resolveRuntimePaths() {
|
|
|
25062
25089
|
}
|
|
25063
25090
|
function resolveBridgeEntryPath() {
|
|
25064
25091
|
if (import.meta.url.includes("/dist/")) {
|
|
25065
|
-
return
|
|
25092
|
+
return fileURLToPath4(new URL("./bridge/bridge-main.js", import.meta.url));
|
|
25066
25093
|
}
|
|
25067
|
-
return
|
|
25094
|
+
return fileURLToPath4(new URL("./bridge/bridge-main.ts", import.meta.url));
|
|
25068
25095
|
}
|
|
25069
25096
|
function resolveAppLogPath(configPath) {
|
|
25070
|
-
const rootDir =
|
|
25071
|
-
const runtimeDir =
|
|
25072
|
-
return
|
|
25097
|
+
const rootDir = dirname11(configPath);
|
|
25098
|
+
const runtimeDir = join14(rootDir, "runtime");
|
|
25099
|
+
return join14(runtimeDir, "app.log");
|
|
25073
25100
|
}
|
|
25074
25101
|
function resolveOrchestrationSocketPathFromConfigPath(configPath) {
|
|
25075
25102
|
const runtimeDir = resolveRuntimeDirFromConfigPath(configPath);
|
|
@@ -25106,7 +25133,7 @@ var init_main = __esm(async () => {
|
|
|
25106
25133
|
});
|
|
25107
25134
|
|
|
25108
25135
|
// src/doctor/checks/acpx-check.ts
|
|
25109
|
-
import { spawn as
|
|
25136
|
+
import { spawn as spawn10 } from "node:child_process";
|
|
25110
25137
|
async function checkAcpx(options = {}) {
|
|
25111
25138
|
const runtimePaths = (options.resolveRuntimePaths ?? resolveRuntimePaths)();
|
|
25112
25139
|
try {
|
|
@@ -25153,7 +25180,7 @@ function buildDetails(metadata, version2, verbose) {
|
|
|
25153
25180
|
async function defaultRunVersion(command) {
|
|
25154
25181
|
const spawnSpec = resolveSpawnCommand(command, ["--version"]);
|
|
25155
25182
|
return await new Promise((resolve3, reject) => {
|
|
25156
|
-
const child =
|
|
25183
|
+
const child = spawn10(spawnSpec.command, spawnSpec.args, {
|
|
25157
25184
|
stdio: ["ignore", "pipe", "pipe"]
|
|
25158
25185
|
});
|
|
25159
25186
|
let stdout2 = "";
|
|
@@ -25291,7 +25318,7 @@ var init_config_check = __esm(async () => {
|
|
|
25291
25318
|
});
|
|
25292
25319
|
|
|
25293
25320
|
// src/doctor/checks/daemon-check.ts
|
|
25294
|
-
import { fileURLToPath as
|
|
25321
|
+
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
25295
25322
|
import { homedir as homedir10 } from "node:os";
|
|
25296
25323
|
async function checkDaemon(options = {}) {
|
|
25297
25324
|
const home = options.home ?? process.env.HOME ?? homedir10();
|
|
@@ -25381,7 +25408,7 @@ function defaultIsProcessRunning5(pid) {
|
|
|
25381
25408
|
}
|
|
25382
25409
|
}
|
|
25383
25410
|
function resolveCliEntryPath() {
|
|
25384
|
-
return process.argv[1] ??
|
|
25411
|
+
return process.argv[1] ?? fileURLToPath5(import.meta.url);
|
|
25385
25412
|
}
|
|
25386
25413
|
function formatError5(error2) {
|
|
25387
25414
|
return error2 instanceof Error ? error2.message : String(error2);
|
|
@@ -25443,7 +25470,7 @@ async function checkOrchestrationHealth(options) {
|
|
|
25443
25470
|
// src/doctor/checks/runtime-check.ts
|
|
25444
25471
|
import { constants } from "node:fs";
|
|
25445
25472
|
import { access as access4, stat as stat3 } from "node:fs/promises";
|
|
25446
|
-
import { dirname as
|
|
25473
|
+
import { dirname as dirname12 } from "node:path";
|
|
25447
25474
|
import { homedir as homedir11 } from "node:os";
|
|
25448
25475
|
async function checkRuntime(options = {}) {
|
|
25449
25476
|
const home = options.home ?? process.env.HOME ?? homedir11();
|
|
@@ -25540,7 +25567,7 @@ async function checkFileCreatable(label, path14, probe, platform) {
|
|
|
25540
25567
|
detail: `${label}: ${path14} (unusable: ${formatError6(error2)})`
|
|
25541
25568
|
};
|
|
25542
25569
|
}
|
|
25543
|
-
const parentCheck = await checkCreatableAncestorDirectory(
|
|
25570
|
+
const parentCheck = await checkCreatableAncestorDirectory(dirname12(path14), probe, platform);
|
|
25544
25571
|
if (!parentCheck.ok) {
|
|
25545
25572
|
return {
|
|
25546
25573
|
ok: false,
|
|
@@ -25576,7 +25603,7 @@ async function checkCreatableAncestorDirectory(path14, probe, platform) {
|
|
|
25576
25603
|
blockingPath: path14
|
|
25577
25604
|
};
|
|
25578
25605
|
}
|
|
25579
|
-
const parent =
|
|
25606
|
+
const parent = dirname12(path14);
|
|
25580
25607
|
if (parent === path14) {
|
|
25581
25608
|
return {
|
|
25582
25609
|
ok: false,
|
|
@@ -25999,7 +26026,7 @@ var init_render_doctor = __esm(() => {
|
|
|
25999
26026
|
|
|
26000
26027
|
// src/doctor/doctor.ts
|
|
26001
26028
|
import { homedir as homedir12 } from "node:os";
|
|
26002
|
-
import { join as
|
|
26029
|
+
import { join as join15 } from "node:path";
|
|
26003
26030
|
async function runDoctor(options = {}, deps = {}) {
|
|
26004
26031
|
const home = deps.home ?? process.env.HOME ?? homedir12();
|
|
26005
26032
|
const runtimePaths = resolveDoctorRuntimePaths(home, deps.resolveRuntimePaths);
|
|
@@ -26052,8 +26079,8 @@ function resolveDoctorRuntimePaths(home, resolver) {
|
|
|
26052
26079
|
return resolveRuntimePaths();
|
|
26053
26080
|
}
|
|
26054
26081
|
return {
|
|
26055
|
-
configPath:
|
|
26056
|
-
statePath:
|
|
26082
|
+
configPath: join15(home, ".weacpx", "config.json"),
|
|
26083
|
+
statePath: join15(home, ".weacpx", "state.json")
|
|
26057
26084
|
};
|
|
26058
26085
|
}
|
|
26059
26086
|
function depsUseExplicitRuntimeOverrides() {
|
|
@@ -26158,8 +26185,8 @@ init_create_daemon_controller();
|
|
|
26158
26185
|
init_daemon_files();
|
|
26159
26186
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
26160
26187
|
import { homedir as homedir13 } from "node:os";
|
|
26161
|
-
import { sep } from "node:path";
|
|
26162
|
-
import { fileURLToPath as
|
|
26188
|
+
import { dirname as dirname13, join as join16, sep } from "node:path";
|
|
26189
|
+
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
26163
26190
|
|
|
26164
26191
|
// src/daemon/daemon-runtime.ts
|
|
26165
26192
|
init_daemon_status();
|
|
@@ -39577,6 +39604,372 @@ function parseSourceHandle(args, env = process.env) {
|
|
|
39577
39604
|
// src/cli.ts
|
|
39578
39605
|
init_workspace_path();
|
|
39579
39606
|
init_state_store();
|
|
39607
|
+
|
|
39608
|
+
// src/onboarding.ts
|
|
39609
|
+
init_workspace_path();
|
|
39610
|
+
init_agent_templates();
|
|
39611
|
+
function isFirstUse(config2, state) {
|
|
39612
|
+
return Object.keys(state.sessions ?? {}).length === 0 && Object.keys(config2.workspaces ?? {}).length === 0 && (config2.plugins ?? []).length === 0;
|
|
39613
|
+
}
|
|
39614
|
+
async function maybeRunFirstUseOnboarding(input) {
|
|
39615
|
+
if (!isFirstUse(input.config, input.state))
|
|
39616
|
+
return { created: false };
|
|
39617
|
+
if (!input.deps.isInteractive())
|
|
39618
|
+
return { created: false };
|
|
39619
|
+
const cwd = normalizeWorkspacePath(input.deps.cwd());
|
|
39620
|
+
const workspaceName = allocateName(sanitizeName(basenameForWorkspacePath(cwd), "workspace"), input.config.workspaces);
|
|
39621
|
+
const yes = (await input.deps.promptText(`检测到首次使用 weacpx。是否将当前目录创建为工作区「${workspaceName}」?[Y/n] `)).trim().toLowerCase();
|
|
39622
|
+
if (yes === "n" || yes === "no")
|
|
39623
|
+
return { created: false };
|
|
39624
|
+
const templateNames = listAgentTemplates();
|
|
39625
|
+
input.deps.print("请选择要添加并创建初始会话的 Agent:");
|
|
39626
|
+
for (let index = 0;index < templateNames.length; index += 1) {
|
|
39627
|
+
input.deps.print(`${index + 1}. ${templateNames[index]}`);
|
|
39628
|
+
}
|
|
39629
|
+
const answer = (await input.deps.promptText("输入数字或名称(默认 1):")).trim();
|
|
39630
|
+
const agentName = resolveTemplateChoice(answer, templateNames);
|
|
39631
|
+
if (!agentName) {
|
|
39632
|
+
input.deps.print("未选择有效 Agent,已跳过首次初始化。");
|
|
39633
|
+
return { created: false };
|
|
39634
|
+
}
|
|
39635
|
+
const template = getAgentTemplate(agentName);
|
|
39636
|
+
if (!template)
|
|
39637
|
+
return { created: false };
|
|
39638
|
+
const workspaceExisted = Boolean(input.config.workspaces[workspaceName]);
|
|
39639
|
+
const agentExisted = Boolean(input.config.agents[agentName]);
|
|
39640
|
+
input.config.workspaces[workspaceName] = { cwd };
|
|
39641
|
+
input.config.agents[agentName] = template;
|
|
39642
|
+
await input.saveConfig(input.config);
|
|
39643
|
+
const alias = `${workspaceName}:${agentName}`;
|
|
39644
|
+
input.deps.print(`已创建工作区「${workspaceName}」,正在创建初始会话「${alias}」...`);
|
|
39645
|
+
return {
|
|
39646
|
+
created: true,
|
|
39647
|
+
workspace: workspaceName,
|
|
39648
|
+
agent: agentName,
|
|
39649
|
+
alias,
|
|
39650
|
+
rollback: { workspaceExisted, agentExisted }
|
|
39651
|
+
};
|
|
39652
|
+
}
|
|
39653
|
+
function resolveTemplateChoice(answer, names) {
|
|
39654
|
+
if (!answer)
|
|
39655
|
+
return names[0] ?? null;
|
|
39656
|
+
const index = Number.parseInt(answer, 10);
|
|
39657
|
+
if (Number.isFinite(index) && index >= 1 && index <= names.length)
|
|
39658
|
+
return names[index - 1];
|
|
39659
|
+
return names.includes(answer) ? answer : null;
|
|
39660
|
+
}
|
|
39661
|
+
function allocateName(base, existing) {
|
|
39662
|
+
if (!existing[base])
|
|
39663
|
+
return base;
|
|
39664
|
+
let suffix = 2;
|
|
39665
|
+
while (existing[`${base}-${suffix}`])
|
|
39666
|
+
suffix += 1;
|
|
39667
|
+
return `${base}-${suffix}`;
|
|
39668
|
+
}
|
|
39669
|
+
function sanitizeName(input, fallback) {
|
|
39670
|
+
const sanitized = input.trim().replace(/[^a-zA-Z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
39671
|
+
return sanitized || fallback;
|
|
39672
|
+
}
|
|
39673
|
+
|
|
39674
|
+
// src/cli-update.ts
|
|
39675
|
+
init_plugin_home();
|
|
39676
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
39677
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
39678
|
+
import { dirname as dirname7, join as join6 } from "node:path";
|
|
39679
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
39680
|
+
|
|
39681
|
+
// src/plugins/package-manager.ts
|
|
39682
|
+
import { spawn as spawn3 } from "node:child_process";
|
|
39683
|
+
async function defaultRunCommand(command, args, options) {
|
|
39684
|
+
await new Promise((resolve, reject) => {
|
|
39685
|
+
const child = spawn3(command, args, { cwd: options.cwd, stdio: "inherit" });
|
|
39686
|
+
child.on("error", reject);
|
|
39687
|
+
child.on("exit", (code) => {
|
|
39688
|
+
if (code === 0)
|
|
39689
|
+
resolve();
|
|
39690
|
+
else
|
|
39691
|
+
reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
|
|
39692
|
+
});
|
|
39693
|
+
});
|
|
39694
|
+
}
|
|
39695
|
+
async function silentRun(command, args, options) {
|
|
39696
|
+
await new Promise((resolve, reject) => {
|
|
39697
|
+
const child = spawn3(command, args, { cwd: options.cwd, stdio: "ignore" });
|
|
39698
|
+
child.on("error", reject);
|
|
39699
|
+
child.on("exit", (code) => {
|
|
39700
|
+
if (code === 0)
|
|
39701
|
+
resolve();
|
|
39702
|
+
else
|
|
39703
|
+
reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
|
|
39704
|
+
});
|
|
39705
|
+
});
|
|
39706
|
+
}
|
|
39707
|
+
async function detectPackageManager(runCommand) {
|
|
39708
|
+
const override = process.env.WEACPX_PACKAGE_MANAGER?.trim().toLowerCase();
|
|
39709
|
+
if (override === "bun" || override === "npm")
|
|
39710
|
+
return override;
|
|
39711
|
+
const probe = runCommand ?? silentRun;
|
|
39712
|
+
try {
|
|
39713
|
+
await probe("bun", ["--version"], { cwd: process.cwd() });
|
|
39714
|
+
return "bun";
|
|
39715
|
+
} catch {
|
|
39716
|
+
return "npm";
|
|
39717
|
+
}
|
|
39718
|
+
}
|
|
39719
|
+
async function installPluginPackage(input) {
|
|
39720
|
+
const runCommand = input.runCommand ?? defaultRunCommand;
|
|
39721
|
+
const packageManager = input.packageManager ?? await detectPackageManager();
|
|
39722
|
+
const spec = input.version ? `${input.packageName}@${input.version}` : input.packageName;
|
|
39723
|
+
if (packageManager === "bun") {
|
|
39724
|
+
await runCommand("bun", ["add", spec], { cwd: input.pluginHome });
|
|
39725
|
+
return;
|
|
39726
|
+
}
|
|
39727
|
+
await runCommand("npm", ["install", spec], { cwd: input.pluginHome });
|
|
39728
|
+
}
|
|
39729
|
+
async function updatePluginPackage(input) {
|
|
39730
|
+
await installPluginPackage(input);
|
|
39731
|
+
}
|
|
39732
|
+
async function removePluginPackage(input) {
|
|
39733
|
+
const runCommand = input.runCommand ?? defaultRunCommand;
|
|
39734
|
+
const packageManager = input.packageManager ?? await detectPackageManager();
|
|
39735
|
+
if (packageManager === "bun") {
|
|
39736
|
+
await runCommand("bun", ["remove", input.packageName], { cwd: input.pluginHome });
|
|
39737
|
+
return;
|
|
39738
|
+
}
|
|
39739
|
+
await runCommand("npm", ["uninstall", input.packageName], { cwd: input.pluginHome });
|
|
39740
|
+
}
|
|
39741
|
+
|
|
39742
|
+
// src/cli-update.ts
|
|
39743
|
+
init_plugin_loader();
|
|
39744
|
+
init_validate_plugin();
|
|
39745
|
+
async function handleUpdateCli(args, deps) {
|
|
39746
|
+
let all = false;
|
|
39747
|
+
const explicitTargets = [];
|
|
39748
|
+
for (const arg of args) {
|
|
39749
|
+
if (arg === "--all")
|
|
39750
|
+
all = true;
|
|
39751
|
+
else
|
|
39752
|
+
explicitTargets.push(arg);
|
|
39753
|
+
}
|
|
39754
|
+
if (all && explicitTargets.length > 0)
|
|
39755
|
+
return null;
|
|
39756
|
+
if (explicitTargets.length > 1)
|
|
39757
|
+
return null;
|
|
39758
|
+
const config2 = await deps.loadConfig();
|
|
39759
|
+
const packageName = deps.packageName ?? await readPackageName();
|
|
39760
|
+
const latestOf = deps.getLatestVersion ?? getLatestNpmVersion;
|
|
39761
|
+
const targets = [
|
|
39762
|
+
{
|
|
39763
|
+
kind: "self",
|
|
39764
|
+
name: packageName,
|
|
39765
|
+
currentVersion: deps.readCurrentVersion(),
|
|
39766
|
+
latestVersion: await latestOf(packageName)
|
|
39767
|
+
}
|
|
39768
|
+
];
|
|
39769
|
+
for (const plugin of config2.plugins ?? []) {
|
|
39770
|
+
targets.push({
|
|
39771
|
+
kind: "plugin",
|
|
39772
|
+
name: plugin.name,
|
|
39773
|
+
currentVersion: plugin.version,
|
|
39774
|
+
pinned: Boolean(plugin.version),
|
|
39775
|
+
latestVersion: await latestOf(plugin.name)
|
|
39776
|
+
});
|
|
39777
|
+
}
|
|
39778
|
+
deps.print("可更新项:");
|
|
39779
|
+
for (let index = 0;index < targets.length; index += 1) {
|
|
39780
|
+
const target = targets[index];
|
|
39781
|
+
deps.print(`${index + 1}. ${formatTarget(target)}`);
|
|
39782
|
+
}
|
|
39783
|
+
const unavailable = targets.filter((target) => !target.latestVersion || target.kind === "plugin" && !target.pinned);
|
|
39784
|
+
if (all && unavailable.length > 0) {
|
|
39785
|
+
deps.print(`以下项目无法检查最新版本,已取消更新:${unavailable.map((target) => target.name).join(", ")}`);
|
|
39786
|
+
return 1;
|
|
39787
|
+
}
|
|
39788
|
+
const candidates = targets.filter((target) => target.latestVersion && (target.kind !== "plugin" || target.pinned) && target.currentVersion !== target.latestVersion);
|
|
39789
|
+
const selected = await selectTargets(targets, candidates, { all, explicitTarget: explicitTargets[0], deps });
|
|
39790
|
+
if (!selected.ok) {
|
|
39791
|
+
deps.print(selected.message);
|
|
39792
|
+
return selected.exitCode;
|
|
39793
|
+
}
|
|
39794
|
+
if (selected.targets.length === 0) {
|
|
39795
|
+
deps.print("没有需要更新的项目。");
|
|
39796
|
+
return 0;
|
|
39797
|
+
}
|
|
39798
|
+
const selfUpdater = deps.updateSelf ?? defaultUpdateSelf;
|
|
39799
|
+
const pluginHome = deps.pluginHome ?? resolvePluginHome();
|
|
39800
|
+
const pluginUpdater = deps.updatePlugin ?? (async (input) => {
|
|
39801
|
+
await ensurePluginHome(pluginHome);
|
|
39802
|
+
await updatePluginPackage({ ...input, pluginHome });
|
|
39803
|
+
});
|
|
39804
|
+
const validatePlugin = deps.validatePlugin ?? validatePluginDefault;
|
|
39805
|
+
const updatedPlugins = [...config2.plugins ?? []];
|
|
39806
|
+
for (const target of selected.targets) {
|
|
39807
|
+
try {
|
|
39808
|
+
if (target.kind === "self") {
|
|
39809
|
+
if (!all && !explicitTargets[0]) {
|
|
39810
|
+
if (!deps.isInteractive()) {
|
|
39811
|
+
deps.print("更新 weacpx 本体需要确认;非交互模式请使用 `weacpx update --all` 或 `weacpx update weacpx`。");
|
|
39812
|
+
return 1;
|
|
39813
|
+
}
|
|
39814
|
+
const answer = (await deps.promptText("确认更新 weacpx 本体?[y/N] ")).trim().toLowerCase();
|
|
39815
|
+
if (answer !== "y" && answer !== "yes") {
|
|
39816
|
+
deps.print("已取消更新 weacpx 本体。");
|
|
39817
|
+
continue;
|
|
39818
|
+
}
|
|
39819
|
+
}
|
|
39820
|
+
await selfUpdater(target.name);
|
|
39821
|
+
deps.print(`weacpx 已更新:${target.latestVersion ?? "latest"}`);
|
|
39822
|
+
continue;
|
|
39823
|
+
}
|
|
39824
|
+
const existing = updatedPlugins.find((plugin) => plugin.name === target.name);
|
|
39825
|
+
const previousVersion = existing?.version;
|
|
39826
|
+
const updateInput = target.latestVersion ? { packageName: target.name, version: target.latestVersion } : { packageName: target.name };
|
|
39827
|
+
await pluginUpdater(updateInput);
|
|
39828
|
+
try {
|
|
39829
|
+
await validatePlugin(target.name, pluginHome);
|
|
39830
|
+
} catch (validationError) {
|
|
39831
|
+
if (previousVersion) {
|
|
39832
|
+
try {
|
|
39833
|
+
await pluginUpdater({ packageName: target.name, version: previousVersion });
|
|
39834
|
+
} catch (rollbackError) {
|
|
39835
|
+
deps.print(`回滚 ${target.name} 到 ${previousVersion} 失败:${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`);
|
|
39836
|
+
}
|
|
39837
|
+
}
|
|
39838
|
+
throw validationError;
|
|
39839
|
+
}
|
|
39840
|
+
if (!existing)
|
|
39841
|
+
throw new Error(`配置中没有找到插件 ${target.name}`);
|
|
39842
|
+
if (existing && target.latestVersion)
|
|
39843
|
+
existing.version = target.latestVersion;
|
|
39844
|
+
deps.print(`插件 ${target.name} 已更新:${target.latestVersion ?? "latest"}`);
|
|
39845
|
+
} catch (error2) {
|
|
39846
|
+
deps.print(`${target.name} 更新失败:${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
39847
|
+
return 1;
|
|
39848
|
+
}
|
|
39849
|
+
}
|
|
39850
|
+
if (selected.targets.some((target) => target.kind === "plugin")) {
|
|
39851
|
+
config2.plugins = updatedPlugins;
|
|
39852
|
+
await deps.saveConfig(config2);
|
|
39853
|
+
}
|
|
39854
|
+
return 0;
|
|
39855
|
+
}
|
|
39856
|
+
function formatTarget(target) {
|
|
39857
|
+
const current = target.currentVersion ?? "未锁定";
|
|
39858
|
+
const latest = target.latestVersion ?? "无法检查";
|
|
39859
|
+
const label = target.kind === "self" ? "weacpx" : `插件 ${target.name}`;
|
|
39860
|
+
return `${label} (${current} -> ${latest})`;
|
|
39861
|
+
}
|
|
39862
|
+
async function selectTargets(targets, candidates, input) {
|
|
39863
|
+
if (input.explicitTarget) {
|
|
39864
|
+
const target = targets.find((entry) => entry.name === input.explicitTarget || input.explicitTarget === "weacpx" && entry.kind === "self");
|
|
39865
|
+
if (!target)
|
|
39866
|
+
return { ok: false, message: `没有找到更新项:${input.explicitTarget}`, exitCode: 1 };
|
|
39867
|
+
if (!target.latestVersion)
|
|
39868
|
+
return { ok: false, message: `${target.name} 无法检查最新版本,已跳过。`, exitCode: 1 };
|
|
39869
|
+
if (target.kind === "plugin" && !target.pinned)
|
|
39870
|
+
return { ok: false, message: `${target.name} 未记录当前版本;请先使用 \`weacpx plugin update ${target.name}\` 或显式选择版本。`, exitCode: 1 };
|
|
39871
|
+
if (target.currentVersion === target.latestVersion)
|
|
39872
|
+
return { ok: true, targets: [] };
|
|
39873
|
+
return { ok: true, targets: [target] };
|
|
39874
|
+
}
|
|
39875
|
+
if (input.all || targets.length === 1)
|
|
39876
|
+
return { ok: true, targets: candidates };
|
|
39877
|
+
if (!input.deps.isInteractive()) {
|
|
39878
|
+
return { ok: false, message: "检测到已安装插件;非交互模式请使用 `weacpx update --all` 或 `weacpx update <name>`。", exitCode: 1 };
|
|
39879
|
+
}
|
|
39880
|
+
const answer = (await input.deps.promptText("请选择要更新的项目(数字,逗号分隔,a=全部,回车取消):")).trim().toLowerCase();
|
|
39881
|
+
if (!answer)
|
|
39882
|
+
return { ok: true, targets: [] };
|
|
39883
|
+
if (answer === "a" || answer === "all")
|
|
39884
|
+
return { ok: true, targets: candidates };
|
|
39885
|
+
const selected = [];
|
|
39886
|
+
for (const part of answer.split(",")) {
|
|
39887
|
+
const index = Number.parseInt(part.trim(), 10);
|
|
39888
|
+
if (!Number.isFinite(index) || index < 1 || index > targets.length) {
|
|
39889
|
+
return { ok: false, message: `无效选择:${part.trim()}`, exitCode: 1 };
|
|
39890
|
+
}
|
|
39891
|
+
const target = targets[index - 1];
|
|
39892
|
+
if (!target.latestVersion)
|
|
39893
|
+
return { ok: false, message: `${target.name} 无法检查最新版本,已跳过。`, exitCode: 1 };
|
|
39894
|
+
if (target.kind === "plugin" && !target.pinned)
|
|
39895
|
+
return { ok: false, message: `${target.name} 未记录当前版本;请先使用 \`weacpx plugin update ${target.name}\` 或显式选择版本。`, exitCode: 1 };
|
|
39896
|
+
if (target.currentVersion === target.latestVersion)
|
|
39897
|
+
continue;
|
|
39898
|
+
if (!selected.includes(target))
|
|
39899
|
+
selected.push(target);
|
|
39900
|
+
}
|
|
39901
|
+
return { ok: true, targets: selected };
|
|
39902
|
+
}
|
|
39903
|
+
async function getLatestNpmVersion(packageName) {
|
|
39904
|
+
const result = await runCapture("npm", ["view", packageName, "version", "--json"]);
|
|
39905
|
+
if (result.code !== 0)
|
|
39906
|
+
return null;
|
|
39907
|
+
const raw = result.stdout.trim();
|
|
39908
|
+
if (!raw)
|
|
39909
|
+
return null;
|
|
39910
|
+
try {
|
|
39911
|
+
const parsed = JSON.parse(raw);
|
|
39912
|
+
return typeof parsed === "string" ? parsed : null;
|
|
39913
|
+
} catch {
|
|
39914
|
+
return raw.replace(/^"|"$/g, "") || null;
|
|
39915
|
+
}
|
|
39916
|
+
}
|
|
39917
|
+
async function defaultUpdateSelf(packageName) {
|
|
39918
|
+
const manager = process.env.WEACPX_PACKAGE_MANAGER?.trim().toLowerCase() === "bun" ? "bun" : "npm";
|
|
39919
|
+
if (manager === "bun") {
|
|
39920
|
+
await runInherit("bun", ["add", "-g", packageName]);
|
|
39921
|
+
return;
|
|
39922
|
+
}
|
|
39923
|
+
await runInherit("npm", ["install", "-g", packageName]);
|
|
39924
|
+
}
|
|
39925
|
+
async function runCapture(command, args) {
|
|
39926
|
+
return await new Promise((resolve, reject) => {
|
|
39927
|
+
const child = spawn4(command, args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
39928
|
+
let stdout2 = "";
|
|
39929
|
+
let stderr = "";
|
|
39930
|
+
child.stdout.setEncoding("utf8");
|
|
39931
|
+
child.stderr.setEncoding("utf8");
|
|
39932
|
+
child.stdout.on("data", (chunk) => {
|
|
39933
|
+
stdout2 += chunk;
|
|
39934
|
+
});
|
|
39935
|
+
child.stderr.on("data", (chunk) => {
|
|
39936
|
+
stderr += chunk;
|
|
39937
|
+
});
|
|
39938
|
+
child.on("error", reject);
|
|
39939
|
+
child.on("close", (code) => resolve({ code: code ?? 1, stdout: stdout2, stderr }));
|
|
39940
|
+
});
|
|
39941
|
+
}
|
|
39942
|
+
async function runInherit(command, args) {
|
|
39943
|
+
await new Promise((resolve, reject) => {
|
|
39944
|
+
const child = spawn4(command, args, { stdio: "inherit" });
|
|
39945
|
+
child.on("error", reject);
|
|
39946
|
+
child.on("exit", (code) => {
|
|
39947
|
+
if (code === 0)
|
|
39948
|
+
resolve();
|
|
39949
|
+
else
|
|
39950
|
+
reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
|
|
39951
|
+
});
|
|
39952
|
+
});
|
|
39953
|
+
}
|
|
39954
|
+
async function readPackageName() {
|
|
39955
|
+
try {
|
|
39956
|
+
const here = dirname7(fileURLToPath2(import.meta.url));
|
|
39957
|
+
for (const candidate of [join6(here, "..", "package.json"), join6(here, "..", "..", "package.json")]) {
|
|
39958
|
+
try {
|
|
39959
|
+
const parsed = JSON.parse(await readFile7(candidate, "utf8"));
|
|
39960
|
+
if (typeof parsed.name === "string" && parsed.name.trim())
|
|
39961
|
+
return parsed.name.trim();
|
|
39962
|
+
} catch {}
|
|
39963
|
+
}
|
|
39964
|
+
} catch {}
|
|
39965
|
+
return "weacpx";
|
|
39966
|
+
}
|
|
39967
|
+
async function validatePluginDefault(packageName, pluginHome) {
|
|
39968
|
+
const moduleValue = await importPluginFromHome(packageName, pluginHome);
|
|
39969
|
+
validateWeacpxPlugin(moduleValue, packageName);
|
|
39970
|
+
}
|
|
39971
|
+
|
|
39972
|
+
// src/cli.ts
|
|
39580
39973
|
init_version();
|
|
39581
39974
|
|
|
39582
39975
|
// src/channels/cli/channel-cli.ts
|
|
@@ -40186,71 +40579,8 @@ async function setChannelAccountEnabled(type, accountId, enabled, rawArgs, deps)
|
|
|
40186
40579
|
|
|
40187
40580
|
// src/plugins/plugin-cli.ts
|
|
40188
40581
|
init_plugin_home();
|
|
40189
|
-
import { readFile as
|
|
40190
|
-
import { isAbsolute, join as
|
|
40191
|
-
|
|
40192
|
-
// src/plugins/package-manager.ts
|
|
40193
|
-
import { spawn as spawn3 } from "node:child_process";
|
|
40194
|
-
async function defaultRunCommand(command, args, options) {
|
|
40195
|
-
await new Promise((resolve, reject) => {
|
|
40196
|
-
const child = spawn3(command, args, { cwd: options.cwd, stdio: "inherit" });
|
|
40197
|
-
child.on("error", reject);
|
|
40198
|
-
child.on("exit", (code) => {
|
|
40199
|
-
if (code === 0)
|
|
40200
|
-
resolve();
|
|
40201
|
-
else
|
|
40202
|
-
reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
|
|
40203
|
-
});
|
|
40204
|
-
});
|
|
40205
|
-
}
|
|
40206
|
-
async function silentRun(command, args, options) {
|
|
40207
|
-
await new Promise((resolve, reject) => {
|
|
40208
|
-
const child = spawn3(command, args, { cwd: options.cwd, stdio: "ignore" });
|
|
40209
|
-
child.on("error", reject);
|
|
40210
|
-
child.on("exit", (code) => {
|
|
40211
|
-
if (code === 0)
|
|
40212
|
-
resolve();
|
|
40213
|
-
else
|
|
40214
|
-
reject(new Error(`${command} ${args.join(" ")} exited with code ${code}`));
|
|
40215
|
-
});
|
|
40216
|
-
});
|
|
40217
|
-
}
|
|
40218
|
-
async function detectPackageManager(runCommand) {
|
|
40219
|
-
const override = process.env.WEACPX_PACKAGE_MANAGER?.trim().toLowerCase();
|
|
40220
|
-
if (override === "bun" || override === "npm")
|
|
40221
|
-
return override;
|
|
40222
|
-
const probe = runCommand ?? silentRun;
|
|
40223
|
-
try {
|
|
40224
|
-
await probe("bun", ["--version"], { cwd: process.cwd() });
|
|
40225
|
-
return "bun";
|
|
40226
|
-
} catch {
|
|
40227
|
-
return "npm";
|
|
40228
|
-
}
|
|
40229
|
-
}
|
|
40230
|
-
async function installPluginPackage(input) {
|
|
40231
|
-
const runCommand = input.runCommand ?? defaultRunCommand;
|
|
40232
|
-
const packageManager = input.packageManager ?? await detectPackageManager();
|
|
40233
|
-
const spec = input.version ? `${input.packageName}@${input.version}` : input.packageName;
|
|
40234
|
-
if (packageManager === "bun") {
|
|
40235
|
-
await runCommand("bun", ["add", spec], { cwd: input.pluginHome });
|
|
40236
|
-
return;
|
|
40237
|
-
}
|
|
40238
|
-
await runCommand("npm", ["install", spec], { cwd: input.pluginHome });
|
|
40239
|
-
}
|
|
40240
|
-
async function updatePluginPackage(input) {
|
|
40241
|
-
await installPluginPackage(input);
|
|
40242
|
-
}
|
|
40243
|
-
async function removePluginPackage(input) {
|
|
40244
|
-
const runCommand = input.runCommand ?? defaultRunCommand;
|
|
40245
|
-
const packageManager = input.packageManager ?? await detectPackageManager();
|
|
40246
|
-
if (packageManager === "bun") {
|
|
40247
|
-
await runCommand("bun", ["remove", input.packageName], { cwd: input.pluginHome });
|
|
40248
|
-
return;
|
|
40249
|
-
}
|
|
40250
|
-
await runCommand("npm", ["uninstall", input.packageName], { cwd: input.pluginHome });
|
|
40251
|
-
}
|
|
40252
|
-
|
|
40253
|
-
// src/plugins/plugin-cli.ts
|
|
40582
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
40583
|
+
import { isAbsolute, join as join8, resolve } from "node:path";
|
|
40254
40584
|
init_plugin_loader();
|
|
40255
40585
|
init_validate_plugin();
|
|
40256
40586
|
|
|
@@ -40259,14 +40589,14 @@ init_channel_scope();
|
|
|
40259
40589
|
init_plugin_loader();
|
|
40260
40590
|
init_validate_plugin();
|
|
40261
40591
|
init_known_plugins();
|
|
40262
|
-
import { readFile as
|
|
40263
|
-
import { join as
|
|
40592
|
+
import { readFile as readFile8 } from "node:fs/promises";
|
|
40593
|
+
import { join as join7 } from "node:path";
|
|
40264
40594
|
function suggestedPluginPackageForChannel(type) {
|
|
40265
40595
|
return findKnownPluginByChannel(type)?.packageName ?? `<npm-package-that-provides-${type}>`;
|
|
40266
40596
|
}
|
|
40267
40597
|
async function readDependencyEntries(pluginHome) {
|
|
40268
40598
|
try {
|
|
40269
|
-
const raw = await
|
|
40599
|
+
const raw = await readFile8(join7(pluginHome, "package.json"), "utf8");
|
|
40270
40600
|
const parsed = JSON.parse(raw);
|
|
40271
40601
|
const out = {};
|
|
40272
40602
|
for (const [name, value] of Object.entries(parsed.dependencies ?? {})) {
|
|
@@ -40368,7 +40698,7 @@ function looksLikePath(spec) {
|
|
|
40368
40698
|
}
|
|
40369
40699
|
async function readDependencyEntries2(pluginHome) {
|
|
40370
40700
|
try {
|
|
40371
|
-
const raw = await
|
|
40701
|
+
const raw = await readFile9(join8(pluginHome, "package.json"), "utf8");
|
|
40372
40702
|
const parsed = JSON.parse(raw);
|
|
40373
40703
|
const out = {};
|
|
40374
40704
|
for (const [name, value] of Object.entries(parsed.dependencies ?? {})) {
|
|
@@ -40394,7 +40724,7 @@ async function resolveLocalPluginName(installSpec, pluginHome, namesBeforeInstal
|
|
|
40394
40724
|
return name;
|
|
40395
40725
|
}
|
|
40396
40726
|
try {
|
|
40397
|
-
const raw = await
|
|
40727
|
+
const raw = await readFile9(join8(installSpec, "package.json"), "utf8");
|
|
40398
40728
|
const parsed = JSON.parse(raw);
|
|
40399
40729
|
if (typeof parsed.name === "string" && parsed.name.trim())
|
|
40400
40730
|
return parsed.name.trim();
|
|
@@ -40822,6 +41152,79 @@ async function runRestart2(deps) {
|
|
|
40822
41152
|
}
|
|
40823
41153
|
}
|
|
40824
41154
|
|
|
41155
|
+
// src/cli/startup-wait-ui.ts
|
|
41156
|
+
var SPINNER_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
41157
|
+
var DEFAULT_SPINNER_FRAME = "⠋";
|
|
41158
|
+
var ENVIRONMENT_HINT_DELAY_MS = 20000;
|
|
41159
|
+
function renderStartupWaitLine(input) {
|
|
41160
|
+
const elapsedSeconds = Math.floor(input.elapsedMs / 1000);
|
|
41161
|
+
const timeoutSeconds = Math.ceil(input.timeoutMs / 1000);
|
|
41162
|
+
const detail = input.elapsedMs >= ENVIRONMENT_HINT_DELAY_MS ? ",首次启动可能需要准备依赖和运行环境" : "";
|
|
41163
|
+
return `${input.frame} 正在创建初始会话${detail} ${elapsedSeconds}s / ${timeoutSeconds}s,按 Ctrl+B 跳过等待`;
|
|
41164
|
+
}
|
|
41165
|
+
function createStartupWaitUi(input) {
|
|
41166
|
+
const stdin2 = input.stdin ?? process.stdin;
|
|
41167
|
+
const stdout2 = input.stdout ?? process.stdout;
|
|
41168
|
+
if (!input.isInteractive() || !stdin2.isTTY || !stdout2.isTTY) {
|
|
41169
|
+
return { stop: () => {} };
|
|
41170
|
+
}
|
|
41171
|
+
let skipped = false;
|
|
41172
|
+
let interrupted = false;
|
|
41173
|
+
let frameIndex = 0;
|
|
41174
|
+
let rawModeEnabled = false;
|
|
41175
|
+
let stopped = false;
|
|
41176
|
+
const cleanup = () => {
|
|
41177
|
+
if (stopped) {
|
|
41178
|
+
return;
|
|
41179
|
+
}
|
|
41180
|
+
stopped = true;
|
|
41181
|
+
stdin2.off("data", onData);
|
|
41182
|
+
if (rawModeEnabled && typeof stdin2.setRawMode === "function") {
|
|
41183
|
+
stdin2.setRawMode(false);
|
|
41184
|
+
}
|
|
41185
|
+
stdin2.pause();
|
|
41186
|
+
stdout2.write("\r\x1B[2K");
|
|
41187
|
+
};
|
|
41188
|
+
const onData = (chunk) => {
|
|
41189
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
41190
|
+
if (buffer.includes(2)) {
|
|
41191
|
+
skipped = true;
|
|
41192
|
+
}
|
|
41193
|
+
if (buffer.includes(3)) {
|
|
41194
|
+
interrupted = true;
|
|
41195
|
+
cleanup();
|
|
41196
|
+
(input.onInterrupt ?? (() => process.kill(process.pid, "SIGINT")))();
|
|
41197
|
+
}
|
|
41198
|
+
};
|
|
41199
|
+
if (typeof stdin2.setRawMode === "function") {
|
|
41200
|
+
stdin2.setRawMode(true);
|
|
41201
|
+
rawModeEnabled = true;
|
|
41202
|
+
}
|
|
41203
|
+
stdin2.resume();
|
|
41204
|
+
stdin2.on("data", onData);
|
|
41205
|
+
const render = (poll) => {
|
|
41206
|
+
const frame = SPINNER_FRAMES[frameIndex % SPINNER_FRAMES.length] ?? DEFAULT_SPINNER_FRAME;
|
|
41207
|
+
frameIndex += 1;
|
|
41208
|
+
stdout2.write(`\r\x1B[2K${renderStartupWaitLine({
|
|
41209
|
+
elapsedMs: poll.elapsedMs,
|
|
41210
|
+
timeoutMs: poll.timeoutMs,
|
|
41211
|
+
frame
|
|
41212
|
+
})}`);
|
|
41213
|
+
};
|
|
41214
|
+
return {
|
|
41215
|
+
wait: {
|
|
41216
|
+
onPoll: render,
|
|
41217
|
+
shouldStopWaiting: () => {
|
|
41218
|
+
if (interrupted) {
|
|
41219
|
+
throw new Error("startup wait interrupted");
|
|
41220
|
+
}
|
|
41221
|
+
return skipped;
|
|
41222
|
+
}
|
|
41223
|
+
},
|
|
41224
|
+
stop: cleanup
|
|
41225
|
+
};
|
|
41226
|
+
}
|
|
41227
|
+
|
|
40825
41228
|
// src/cli.ts
|
|
40826
41229
|
init_bootstrap();
|
|
40827
41230
|
async function prepareMcpCoordinatorStartup(input) {
|
|
@@ -40923,6 +41326,7 @@ var HELP_LINES = [
|
|
|
40923
41326
|
"weacpx status - 查看状态",
|
|
40924
41327
|
"weacpx stop - 停止服务",
|
|
40925
41328
|
"weacpx restart - 重启后台服务",
|
|
41329
|
+
"weacpx update [--all|<name>] - 更新 weacpx 和已安装插件",
|
|
40926
41330
|
"weacpx channel|ch list|show|add|rm|enable|disable [--account <id>] - 管理消息频道(多 bot 用 --account)",
|
|
40927
41331
|
"weacpx plugin list|add|update|remove|enable|disable|doctor|known - 管理插件",
|
|
40928
41332
|
"weacpx doctor - 运行诊断",
|
|
@@ -40958,8 +41362,28 @@ async function runCli(args, deps = {}) {
|
|
|
40958
41362
|
await (deps.logout ?? defaultLogout)();
|
|
40959
41363
|
return 0;
|
|
40960
41364
|
case "run":
|
|
40961
|
-
|
|
41365
|
+
const onboarding = await runOnboardingBeforeStart({
|
|
41366
|
+
print,
|
|
41367
|
+
cwd: deps.cwd ?? (() => process.cwd()),
|
|
41368
|
+
isInteractive: deps.isInteractive,
|
|
41369
|
+
promptText: deps.promptText
|
|
41370
|
+
});
|
|
41371
|
+
await (deps.run ?? defaultRun)({ firstRunOnboarding: onboarding ?? undefined });
|
|
40962
41372
|
return 0;
|
|
41373
|
+
case "update": {
|
|
41374
|
+
const result = await (deps.update ?? ((subArgs) => defaultUpdate(subArgs, {
|
|
41375
|
+
print,
|
|
41376
|
+
isInteractive: deps.isInteractive,
|
|
41377
|
+
promptText: deps.promptText,
|
|
41378
|
+
overrides: deps.updateCliDeps
|
|
41379
|
+
})))(args.slice(1));
|
|
41380
|
+
if (result === null) {
|
|
41381
|
+
for (const line of HELP_LINES)
|
|
41382
|
+
print(line);
|
|
41383
|
+
return 1;
|
|
41384
|
+
}
|
|
41385
|
+
return result;
|
|
41386
|
+
}
|
|
40963
41387
|
case "doctor": {
|
|
40964
41388
|
const parsed = parseDoctorArgs(args.slice(1));
|
|
40965
41389
|
if (!parsed.ok) {
|
|
@@ -41025,7 +41449,32 @@ async function runCli(args, deps = {}) {
|
|
|
41025
41449
|
case "start": {
|
|
41026
41450
|
const controller = deps.controller ?? createDefaultController();
|
|
41027
41451
|
try {
|
|
41028
|
-
const
|
|
41452
|
+
const isInteractive = deps.isInteractive ?? defaultIsInteractive;
|
|
41453
|
+
const status = await controller.getStatus();
|
|
41454
|
+
if (status.state === "running") {
|
|
41455
|
+
print("weacpx 已在后台运行");
|
|
41456
|
+
print(`PID: ${status.pid}`);
|
|
41457
|
+
return 0;
|
|
41458
|
+
}
|
|
41459
|
+
if (status.state === "indeterminate") {
|
|
41460
|
+
throw new Error(`weacpx daemon process is already running (pid ${status.pid}) but status metadata is missing`);
|
|
41461
|
+
}
|
|
41462
|
+
const onboarding2 = await runOnboardingBeforeStart({
|
|
41463
|
+
print,
|
|
41464
|
+
cwd: deps.cwd ?? (() => process.cwd()),
|
|
41465
|
+
isInteractive,
|
|
41466
|
+
promptText: deps.promptText
|
|
41467
|
+
});
|
|
41468
|
+
const startupWaitUi = onboarding2 ? createStartupWaitUi({ isInteractive }) : null;
|
|
41469
|
+
let result;
|
|
41470
|
+
try {
|
|
41471
|
+
result = await controller.start({
|
|
41472
|
+
firstRunOnboarding: onboarding2 ?? undefined,
|
|
41473
|
+
...startupWaitUi?.wait ? { startupWait: startupWaitUi.wait } : {}
|
|
41474
|
+
});
|
|
41475
|
+
} finally {
|
|
41476
|
+
startupWaitUi?.stop();
|
|
41477
|
+
}
|
|
41029
41478
|
if (result.state === "already-running") {
|
|
41030
41479
|
print("weacpx 已在后台运行");
|
|
41031
41480
|
print(`PID: ${result.pid}`);
|
|
@@ -41036,9 +41485,7 @@ async function runCli(args, deps = {}) {
|
|
|
41036
41485
|
return 0;
|
|
41037
41486
|
} catch (error2) {
|
|
41038
41487
|
print(`weacpx 启动失败:${describeFriendlyError(error2)}`);
|
|
41039
|
-
|
|
41040
|
-
if (stderrPath)
|
|
41041
|
-
print(`请查看 Stderr: ${stderrPath}`);
|
|
41488
|
+
printDaemonLogHints(print);
|
|
41042
41489
|
return 1;
|
|
41043
41490
|
}
|
|
41044
41491
|
}
|
|
@@ -41081,9 +41528,7 @@ async function runCli(args, deps = {}) {
|
|
|
41081
41528
|
return await restartDaemonCli(controller, print);
|
|
41082
41529
|
} catch (error2) {
|
|
41083
41530
|
print(`weacpx 重启失败:${describeFriendlyError(error2)}`);
|
|
41084
|
-
|
|
41085
|
-
if (stderrPath)
|
|
41086
|
-
print(`请查看 Stderr: ${stderrPath}`);
|
|
41531
|
+
printDaemonLogHints(print);
|
|
41087
41532
|
return 1;
|
|
41088
41533
|
}
|
|
41089
41534
|
}
|
|
@@ -41094,6 +41539,44 @@ async function runCli(args, deps = {}) {
|
|
|
41094
41539
|
return 1;
|
|
41095
41540
|
}
|
|
41096
41541
|
}
|
|
41542
|
+
async function defaultUpdate(args, input) {
|
|
41543
|
+
const store = await createCliConfigStore();
|
|
41544
|
+
const deps = {
|
|
41545
|
+
loadConfig: async () => await store.load(),
|
|
41546
|
+
saveConfig: async (config2) => await store.save(config2),
|
|
41547
|
+
readCurrentVersion: readVersion,
|
|
41548
|
+
print: input.print,
|
|
41549
|
+
isInteractive: input.isInteractive ?? defaultIsInteractive,
|
|
41550
|
+
promptText: input.promptText ?? defaultPromptText,
|
|
41551
|
+
...input.overrides
|
|
41552
|
+
};
|
|
41553
|
+
return await handleUpdateCli(args, deps);
|
|
41554
|
+
}
|
|
41555
|
+
async function runOnboardingBeforeStart(input) {
|
|
41556
|
+
const runtimePaths = (await init_main().then(() => exports_main)).resolveRuntimePaths();
|
|
41557
|
+
await ensureConfigExists(runtimePaths.configPath);
|
|
41558
|
+
const configStore = new ConfigStore(runtimePaths.configPath);
|
|
41559
|
+
const stateStore = new StateStore(runtimePaths.statePath);
|
|
41560
|
+
const config2 = await configStore.load();
|
|
41561
|
+
const state = await stateStore.load();
|
|
41562
|
+
const result = await maybeRunFirstUseOnboarding({
|
|
41563
|
+
config: config2,
|
|
41564
|
+
state,
|
|
41565
|
+
saveConfig: async (next) => await configStore.save(next),
|
|
41566
|
+
deps: {
|
|
41567
|
+
print: input.print,
|
|
41568
|
+
cwd: input.cwd,
|
|
41569
|
+
isInteractive: input.isInteractive ?? defaultIsInteractive,
|
|
41570
|
+
promptText: input.promptText ?? defaultPromptText
|
|
41571
|
+
}
|
|
41572
|
+
});
|
|
41573
|
+
return result.created ? {
|
|
41574
|
+
alias: result.alias,
|
|
41575
|
+
agent: result.agent,
|
|
41576
|
+
workspace: result.workspace,
|
|
41577
|
+
rollback: result.rollback
|
|
41578
|
+
} : null;
|
|
41579
|
+
}
|
|
41097
41580
|
async function handleWorkspaceCli(args, deps) {
|
|
41098
41581
|
const subcommand = args[0];
|
|
41099
41582
|
switch (subcommand) {
|
|
@@ -41189,7 +41672,7 @@ async function defaultLoadConfiguredPluginsForChannelCli() {
|
|
|
41189
41672
|
const { loadConfiguredPlugins: loadConfiguredPlugins2 } = await Promise.resolve().then(() => (init_plugin_loader(), exports_plugin_loader));
|
|
41190
41673
|
await loadConfiguredPlugins2({ plugins: config2.plugins });
|
|
41191
41674
|
}
|
|
41192
|
-
async function defaultRun() {
|
|
41675
|
+
async function defaultRun(options = {}) {
|
|
41193
41676
|
const [{ buildApp: buildApp2, resolveRuntimePaths: resolveRuntimePaths2, prepareChannelMedia: prepareChannelMedia2 }, { runConsole: runConsole2 }] = await Promise.all([
|
|
41194
41677
|
init_main().then(() => exports_main),
|
|
41195
41678
|
Promise.resolve().then(() => (init_run_console(), exports_run_console))
|
|
@@ -41207,11 +41690,15 @@ async function defaultRun() {
|
|
|
41207
41690
|
const channelRegistry = new MessageChannelRegistry2(createMessageChannels2(config2.channels, channelDeps));
|
|
41208
41691
|
const lockCreators = channelRegistry.createConsumerLocks();
|
|
41209
41692
|
const firstLockCreator = lockCreators[0];
|
|
41693
|
+
const firstRunOnboarding = options.firstRunOnboarding ?? decodeFirstRunOnboarding(process.env.WEACPX_FIRST_RUN_ONBOARDING);
|
|
41210
41694
|
await runConsole2(runtimePaths, {
|
|
41211
41695
|
buildApp: (paths) => buildApp2(paths, {
|
|
41212
41696
|
defaultLoggingLevel: resolveCliEntryPath2().includes(`${sep}src${sep}`) ? "debug" : "info",
|
|
41213
41697
|
channel: channelRegistry
|
|
41214
41698
|
}),
|
|
41699
|
+
beforeReady: firstRunOnboarding ? async (runtime) => {
|
|
41700
|
+
await createFirstRunSession(runtime, firstRunOnboarding);
|
|
41701
|
+
} : undefined,
|
|
41215
41702
|
channels: channelRegistry,
|
|
41216
41703
|
daemonRuntime,
|
|
41217
41704
|
...firstLockCreator ? {
|
|
@@ -41224,6 +41711,42 @@ async function defaultRun() {
|
|
|
41224
41711
|
} : {}
|
|
41225
41712
|
});
|
|
41226
41713
|
}
|
|
41714
|
+
async function createFirstRunSession(runtime, plan) {
|
|
41715
|
+
const session = runtime.sessions.resolveSession(plan.alias, plan.agent, plan.workspace, plan.alias);
|
|
41716
|
+
try {
|
|
41717
|
+
await runtime.transport.ensureSession(session);
|
|
41718
|
+
const exists = await runtime.transport.hasSession(session);
|
|
41719
|
+
if (!exists) {
|
|
41720
|
+
throw new Error(`first-run onboarding failed to create transport session: ${plan.alias}`);
|
|
41721
|
+
}
|
|
41722
|
+
await runtime.sessions.attachSession(plan.alias, plan.agent, plan.workspace, session.transportSession);
|
|
41723
|
+
} catch (error2) {
|
|
41724
|
+
await rollbackFirstRunConfig(runtime, plan);
|
|
41725
|
+
throw error2;
|
|
41726
|
+
}
|
|
41727
|
+
await runtime.logger.info("onboarding.session_created", "created first-run transport session", {
|
|
41728
|
+
alias: plan.alias,
|
|
41729
|
+
agent: plan.agent,
|
|
41730
|
+
workspace: plan.workspace
|
|
41731
|
+
});
|
|
41732
|
+
}
|
|
41733
|
+
async function rollbackFirstRunConfig(runtime, plan) {
|
|
41734
|
+
try {
|
|
41735
|
+
const config2 = await runtime.configStore.load();
|
|
41736
|
+
if (!plan.rollback.workspaceExisted && config2.workspaces[plan.workspace]) {
|
|
41737
|
+
delete config2.workspaces[plan.workspace];
|
|
41738
|
+
}
|
|
41739
|
+
if (!plan.rollback.agentExisted && config2.agents[plan.agent]) {
|
|
41740
|
+
delete config2.agents[plan.agent];
|
|
41741
|
+
}
|
|
41742
|
+
await runtime.configStore.save(config2);
|
|
41743
|
+
} catch (error2) {
|
|
41744
|
+
await runtime.logger.error("onboarding.rollback_failed", "failed to roll back first-run config", {
|
|
41745
|
+
alias: plan.alias,
|
|
41746
|
+
error: error2 instanceof Error ? error2.message : String(error2)
|
|
41747
|
+
});
|
|
41748
|
+
}
|
|
41749
|
+
}
|
|
41227
41750
|
async function defaultDoctor(options) {
|
|
41228
41751
|
const { main: main3 } = await init_doctor2().then(() => exports_doctor);
|
|
41229
41752
|
return await main3(options);
|
|
@@ -41310,7 +41833,7 @@ async function createChannelCliDeps(input) {
|
|
|
41310
41833
|
saveConfig: async (config2) => await store.save(config2),
|
|
41311
41834
|
print: input.print,
|
|
41312
41835
|
stderr: input.stderr ?? ((text) => process.stderr.write(text)),
|
|
41313
|
-
isInteractive: input.isInteractive ??
|
|
41836
|
+
isInteractive: input.isInteractive ?? defaultIsInteractive,
|
|
41314
41837
|
promptText: input.promptText ?? defaultPromptText,
|
|
41315
41838
|
promptSecret: input.promptSecret ?? defaultPromptSecret,
|
|
41316
41839
|
getDaemonStatus: async () => {
|
|
@@ -41332,7 +41855,7 @@ async function createPluginCliDeps(input) {
|
|
|
41332
41855
|
loadConfig: async () => await store.load(),
|
|
41333
41856
|
saveConfig: async (config2) => await store.save(config2),
|
|
41334
41857
|
print: input.print,
|
|
41335
|
-
isInteractive: input.isInteractive ??
|
|
41858
|
+
isInteractive: input.isInteractive ?? defaultIsInteractive,
|
|
41336
41859
|
promptText: input.promptText ?? defaultPromptText,
|
|
41337
41860
|
getDaemonStatus: async () => {
|
|
41338
41861
|
const status = await controller.getStatus();
|
|
@@ -41408,12 +41931,43 @@ async function defaultPromptSecret(message) {
|
|
|
41408
41931
|
}
|
|
41409
41932
|
function createDefaultController() {
|
|
41410
41933
|
const daemonPaths = resolveDaemonPaths({ home: requireHome2() });
|
|
41411
|
-
|
|
41934
|
+
const controller = createDaemonController(daemonPaths, {
|
|
41412
41935
|
processExecPath: process.execPath,
|
|
41413
41936
|
cliEntryPath: resolveCliEntryPath2(),
|
|
41414
41937
|
cwd: process.cwd(),
|
|
41415
41938
|
env: process.env
|
|
41416
41939
|
});
|
|
41940
|
+
return {
|
|
41941
|
+
getStatus: () => controller.getStatus(),
|
|
41942
|
+
stop: () => controller.stop(),
|
|
41943
|
+
start: (options) => controller.start({
|
|
41944
|
+
...options?.firstRunOnboarding ? { firstRunOnboarding: encodeFirstRunOnboarding(options.firstRunOnboarding) } : {},
|
|
41945
|
+
...options?.startupWait ? { startupWait: options.startupWait } : {}
|
|
41946
|
+
})
|
|
41947
|
+
};
|
|
41948
|
+
}
|
|
41949
|
+
function encodeFirstRunOnboarding(plan) {
|
|
41950
|
+
return Buffer.from(JSON.stringify(plan), "utf8").toString("base64url");
|
|
41951
|
+
}
|
|
41952
|
+
function decodeFirstRunOnboarding(raw) {
|
|
41953
|
+
if (!raw)
|
|
41954
|
+
return null;
|
|
41955
|
+
try {
|
|
41956
|
+
const parsed = JSON.parse(Buffer.from(raw, "base64url").toString("utf8"));
|
|
41957
|
+
if (typeof parsed.alias === "string" && typeof parsed.agent === "string" && typeof parsed.workspace === "string") {
|
|
41958
|
+
const rollback = typeof parsed.rollback === "object" && parsed.rollback !== null ? parsed.rollback : {};
|
|
41959
|
+
return {
|
|
41960
|
+
alias: parsed.alias,
|
|
41961
|
+
agent: parsed.agent,
|
|
41962
|
+
workspace: parsed.workspace,
|
|
41963
|
+
rollback: {
|
|
41964
|
+
workspaceExisted: rollback.workspaceExisted === true,
|
|
41965
|
+
agentExisted: rollback.agentExisted === true
|
|
41966
|
+
}
|
|
41967
|
+
};
|
|
41968
|
+
}
|
|
41969
|
+
} catch {}
|
|
41970
|
+
return null;
|
|
41417
41971
|
}
|
|
41418
41972
|
function requireHome2() {
|
|
41419
41973
|
const home = process.env.HOME ?? homedir13();
|
|
@@ -41422,12 +41976,27 @@ function requireHome2() {
|
|
|
41422
41976
|
}
|
|
41423
41977
|
return home;
|
|
41424
41978
|
}
|
|
41979
|
+
function defaultIsInteractive() {
|
|
41980
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
41981
|
+
}
|
|
41425
41982
|
function describeFriendlyError(error2) {
|
|
41426
41983
|
return error2 instanceof Error ? error2.message : String(error2);
|
|
41427
41984
|
}
|
|
41428
|
-
function
|
|
41985
|
+
function printDaemonLogHints(print) {
|
|
41986
|
+
const paths = safeDaemonLogPaths();
|
|
41987
|
+
if (!paths)
|
|
41988
|
+
return;
|
|
41989
|
+
print(`请查看 App Log: ${paths.appLog}`);
|
|
41990
|
+
print(`请查看 Stderr: ${paths.stderrLog}`);
|
|
41991
|
+
}
|
|
41992
|
+
function safeDaemonLogPaths() {
|
|
41429
41993
|
try {
|
|
41430
|
-
|
|
41994
|
+
const configPath = process.env.WEACPX_CONFIG ?? `${requireHome2()}/.weacpx/config.json`;
|
|
41995
|
+
const paths = resolveDaemonPaths({ home: requireHome2() });
|
|
41996
|
+
return {
|
|
41997
|
+
appLog: join16(dirname13(configPath), "runtime", "app.log"),
|
|
41998
|
+
stderrLog: paths.stderrLog
|
|
41999
|
+
};
|
|
41431
42000
|
} catch {
|
|
41432
42001
|
return null;
|
|
41433
42002
|
}
|
|
@@ -41436,7 +42005,7 @@ function resolveCliEntryPath2() {
|
|
|
41436
42005
|
if (process.argv[1]) {
|
|
41437
42006
|
return process.argv[1];
|
|
41438
42007
|
}
|
|
41439
|
-
return
|
|
42008
|
+
return fileURLToPath6(import.meta.url);
|
|
41440
42009
|
}
|
|
41441
42010
|
function parseDoctorArgs(args) {
|
|
41442
42011
|
const options = {};
|