@ganglion/xacpx 0.9.1 → 0.9.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 +4 -2
- package/dist/bridge/bridge-main.js +39 -15
- package/dist/cli.js +195 -77
- package/dist/commands/command-hints.d.ts +1 -1
- package/dist/commands/command-list.d.ts +3 -3
- package/dist/commands/handlers/resolve-reply-mode.d.ts +13 -0
- package/dist/config/types.d.ts +1 -0
- package/dist/i18n/types.d.ts +6 -1
- package/dist/plugin-api.d.ts +1 -1
- package/dist/plugin-api.js +27 -11
- package/dist/plugins/compatibility.d.ts +4 -1
- package/dist/plugins/types.d.ts +2 -2
- package/dist/state/types.d.ts +1 -1
- package/dist/transport/types.d.ts +9 -1
- package/dist/version.d.ts +2 -2
- package/dist/weixin/agent/interface.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -13,6 +13,8 @@ English · **[中文](./docs/zh/README_zh.md)**
|
|
|
13
13
|
|
|
14
14
|
`xacpx` is a tool that lets you control ACP agents such as Codex / Claude Code / Gemini / OpenCode directly from WeChat, Feishu, or Yuanbao. It connects chat messages to your agent CLI sessions through `acpx`, so you can, right from your phone:
|
|
15
15
|
|
|
16
|
+
[](https://imgchr.com/i/pmZXIv6)
|
|
17
|
+
|
|
16
18
|
- Create and switch between sessions
|
|
17
19
|
- Have the agent keep working in a specific project directory
|
|
18
20
|
- View streaming replies, final results, and tool-call summaries
|
|
@@ -427,7 +429,7 @@ Notes:
|
|
|
427
429
|
|
|
428
430
|
If you want to first understand when to delegate and when to dispatch multiple subtasks in parallel, see:
|
|
429
431
|
|
|
430
|
-
- [docs/
|
|
432
|
+
- [docs/xacpx-group-usage-guide.md](./docs/xacpx-group-usage-guide.md)
|
|
431
433
|
|
|
432
434
|
|
|
433
435
|
### MCP integration: external coordinator
|
|
@@ -579,7 +581,7 @@ If what you're about to do is one of the following, you can continue from here:
|
|
|
579
581
|
|
|
580
582
|
- Want the full chat-command reference: [docs/commands.md](./docs/commands.md)
|
|
581
583
|
- Want to schedule a one-time future message with scheduled tasks (`/later`): [docs/later-command.md](./docs/later-command.md)
|
|
582
|
-
- Want to understand when to delegate and when to open a group: [docs/
|
|
584
|
+
- Want to understand when to delegate and when to open a group: [docs/xacpx-group-usage-guide.md](./docs/xacpx-group-usage-guide.md)
|
|
583
585
|
|
|
584
586
|
### Troubleshooting and verification
|
|
585
587
|
|
|
@@ -880,10 +880,11 @@ var init_session = __esm(() => {
|
|
|
880
880
|
replyModeHeader: "Current reply mode:",
|
|
881
881
|
replyModeSessionLabel: (alias) => `- Session: ${alias}`,
|
|
882
882
|
replyModeGlobalDefault: (value) => `- Global default: ${value}`,
|
|
883
|
+
replyModeChannelDefault: (value) => `- Channel default: ${value}`,
|
|
883
884
|
replyModeSessionOverride: (value) => `- Session override: ${value}`,
|
|
884
885
|
replyModeEffective: (value) => `- Effective: ${value}`,
|
|
885
886
|
replyModeSet: (replyMode) => `Current session reply mode set to: ${replyMode}`,
|
|
886
|
-
replyModeReset: (
|
|
887
|
+
replyModeReset: (effective) => `Session reply mode reset. Now effective: ${effective}`,
|
|
887
888
|
statusHeader: "Current session:",
|
|
888
889
|
statusNameLabel: (alias) => `- Name: ${alias}`,
|
|
889
890
|
statusAgentLabel: (agent) => `- Agent: ${agent}`,
|
|
@@ -1426,6 +1427,8 @@ var init_config = __esm(() => {
|
|
|
1426
1427
|
mustBePositiveNumber: (path2) => `${path2} must be a positive number.`,
|
|
1427
1428
|
channelTypeDisabled: "channel.type is a legacy single-channel field; /config set writes are disabled. Use `xacpx channel ...` to manage channels[], then restart xacpx.",
|
|
1428
1429
|
channelReplyModeInvalid: "channel.replyMode only supports: stream, final, verbose",
|
|
1430
|
+
channelRuntimeNotFound: (id) => `Channel "${id}" does not exist; add it first with \`xacpx channel add ${id}\`.`,
|
|
1431
|
+
channelRuntimeReplyModeInvalid: (id) => `channels.${id}.replyMode only supports: stream, final, verbose`,
|
|
1429
1432
|
wechatReplyModeInvalid: "wechat.replyMode only supports: stream, final, verbose",
|
|
1430
1433
|
wechatReplyModeMapped: (value) => `${value} (mapped to channel.replyMode)`,
|
|
1431
1434
|
agentNotFound: (name) => `Agent "${name}" does not exist. Create it first.`,
|
|
@@ -1646,6 +1649,8 @@ var init_channel_cli = __esm(() => {
|
|
|
1646
1649
|
channelRemoved: (id) => `Channel ${id} removed`,
|
|
1647
1650
|
cannotDisableLastEnabled: "Cannot disable the last enabled channel.",
|
|
1648
1651
|
channelEnabledToggled: (id, enabled) => `Channel ${id} ${enabled ? "enabled" : "disabled"}`,
|
|
1652
|
+
channelReplyModeSet: (id, mode) => `Channel ${id} default reply mode set to: ${mode}`,
|
|
1653
|
+
channelReplyModeInvalid: (mode) => `reply mode must be stream / final / verbose, got: ${mode}`,
|
|
1649
1654
|
channelAccountAlreadyExists: (type, accountId) => `Account ${accountId} already exists on channel ${type}; run xacpx channel rm ${type} --account ${accountId} first`,
|
|
1650
1655
|
channelAccountAdded: (type, accountId) => `Channel ${type} account ${accountId} added`,
|
|
1651
1656
|
channelReEnabled: (type) => `Channel ${type} was disabled; it has been automatically re-enabled.`,
|
|
@@ -1946,10 +1951,11 @@ var init_session2 = __esm(() => {
|
|
|
1946
1951
|
replyModeHeader: "当前 reply mode:",
|
|
1947
1952
|
replyModeSessionLabel: (alias) => `- 会话:${alias}`,
|
|
1948
1953
|
replyModeGlobalDefault: (value) => `- 全局默认:${value}`,
|
|
1954
|
+
replyModeChannelDefault: (value) => `- 频道默认:${value}`,
|
|
1949
1955
|
replyModeSessionOverride: (value) => `- 当前会话覆盖:${value}`,
|
|
1950
1956
|
replyModeEffective: (value) => `- 当前生效:${value}`,
|
|
1951
1957
|
replyModeSet: (replyMode) => `已设置当前会话 reply mode:${replyMode}`,
|
|
1952
|
-
replyModeReset: (
|
|
1958
|
+
replyModeReset: (effective) => `已重置当前会话 reply mode,当前生效:${effective}`,
|
|
1953
1959
|
statusHeader: "当前会话:",
|
|
1954
1960
|
statusNameLabel: (alias) => `- 名称:${alias}`,
|
|
1955
1961
|
statusAgentLabel: (agent2) => `- Agent:${agent2}`,
|
|
@@ -2492,6 +2498,8 @@ var init_config2 = __esm(() => {
|
|
|
2492
2498
|
mustBePositiveNumber: (path2) => `${path2} 必须是正数。`,
|
|
2493
2499
|
channelTypeDisabled: "channel.type 是旧单频道字段,/config set 已禁用写入;请使用 `xacpx channel ...` 管理 channels[],然后重启 xacpx。",
|
|
2494
2500
|
channelReplyModeInvalid: "channel.replyMode 只支持:stream、final、verbose",
|
|
2501
|
+
channelRuntimeNotFound: (id) => `频道「${id}」不存在;请先用 \`xacpx channel add ${id}\` 添加。`,
|
|
2502
|
+
channelRuntimeReplyModeInvalid: (id) => `channels.${id}.replyMode 只支持:stream、final、verbose`,
|
|
2495
2503
|
wechatReplyModeInvalid: "wechat.replyMode 只支持:stream、final、verbose",
|
|
2496
2504
|
wechatReplyModeMapped: (value) => `${value}(已映射到 channel.replyMode)`,
|
|
2497
2505
|
agentNotFound: (name) => `Agent「${name}」不存在,请先创建。`,
|
|
@@ -2712,6 +2720,8 @@ var init_channel_cli2 = __esm(() => {
|
|
|
2712
2720
|
channelRemoved: (id) => `频道 ${id} 已删除`,
|
|
2713
2721
|
cannotDisableLastEnabled: "不能禁用最后一个启用的频道。",
|
|
2714
2722
|
channelEnabledToggled: (id, enabled) => `频道 ${id} 已${enabled ? "启用" : "禁用"}`,
|
|
2723
|
+
channelReplyModeSet: (id, mode) => `频道 ${id} 的默认 reply mode 已设置为:${mode}`,
|
|
2724
|
+
channelReplyModeInvalid: (mode) => `reply mode 只支持 stream / final / verbose,收到:${mode}`,
|
|
2715
2725
|
channelAccountAlreadyExists: (type, accountId) => `频道 ${type} 的账号 ${accountId} 已存在;先 xacpx channel rm ${type} --account ${accountId}`,
|
|
2716
2726
|
channelAccountAdded: (type, accountId) => `频道 ${type} 账号 ${accountId} 已添加`,
|
|
2717
2727
|
channelReEnabled: (type) => `频道 ${type} 此前是 disabled 状态,已自动启用。`,
|
|
@@ -3030,10 +3040,10 @@ import { spawn as spawn3 } from "node:child_process";
|
|
|
3030
3040
|
import { readFile, unlink } from "node:fs/promises";
|
|
3031
3041
|
import { homedir as homedir2 } from "node:os";
|
|
3032
3042
|
import { join as join2 } from "node:path";
|
|
3033
|
-
function
|
|
3034
|
-
const { command, args } = splitCommandLine(input.
|
|
3043
|
+
function buildXacpxMcpServerSpec(input) {
|
|
3044
|
+
const { command, args } = splitCommandLine(input.xacpxCommand);
|
|
3035
3045
|
return {
|
|
3036
|
-
name: "
|
|
3046
|
+
name: "xacpx",
|
|
3037
3047
|
type: "stdio",
|
|
3038
3048
|
command,
|
|
3039
3049
|
args: [
|
|
@@ -3060,7 +3070,7 @@ function buildQueueOwnerPayload(input) {
|
|
|
3060
3070
|
|
|
3061
3071
|
class AcpxQueueOwnerLauncher {
|
|
3062
3072
|
acpxCommand;
|
|
3063
|
-
|
|
3073
|
+
xacpxCommand;
|
|
3064
3074
|
spawnOwner;
|
|
3065
3075
|
terminateOwner;
|
|
3066
3076
|
baseEnv;
|
|
@@ -3069,7 +3079,7 @@ class AcpxQueueOwnerLauncher {
|
|
|
3069
3079
|
launchLocks = new Map;
|
|
3070
3080
|
constructor(options) {
|
|
3071
3081
|
this.acpxCommand = options.acpxCommand;
|
|
3072
|
-
this.
|
|
3082
|
+
this.xacpxCommand = options.xacpxCommand ?? resolveDefaultXacpxCommand(options.baseEnv ?? process.env);
|
|
3073
3083
|
this.spawnOwner = options.spawnOwner ?? defaultQueueOwnerSpawner;
|
|
3074
3084
|
this.terminateOwner = options.terminateOwner ?? createDefaultQueueOwnerTerminator(options.acpxCommand);
|
|
3075
3085
|
this.baseEnv = options.baseEnv ?? process.env;
|
|
@@ -3097,8 +3107,8 @@ class AcpxQueueOwnerLauncher {
|
|
|
3097
3107
|
nonInteractivePermissions: input.nonInteractivePermissions,
|
|
3098
3108
|
ttlMs: this.ttlMs,
|
|
3099
3109
|
maxQueueDepth: this.maxQueueDepth,
|
|
3100
|
-
mcpServers: [
|
|
3101
|
-
|
|
3110
|
+
mcpServers: [buildXacpxMcpServerSpec({
|
|
3111
|
+
xacpxCommand: this.xacpxCommand,
|
|
3102
3112
|
coordinatorSession: input.coordinatorSession,
|
|
3103
3113
|
...input.sourceHandle ? { sourceHandle: input.sourceHandle } : {}
|
|
3104
3114
|
})]
|
|
@@ -3153,13 +3163,13 @@ function splitCommandLine(value) {
|
|
|
3153
3163
|
current += "\\";
|
|
3154
3164
|
}
|
|
3155
3165
|
if (quote) {
|
|
3156
|
-
throw new Error("
|
|
3166
|
+
throw new Error("xacpx MCP command has an unterminated quote");
|
|
3157
3167
|
}
|
|
3158
3168
|
if (current.length > 0) {
|
|
3159
3169
|
parts.push(current);
|
|
3160
3170
|
}
|
|
3161
3171
|
if (parts.length === 0) {
|
|
3162
|
-
throw new Error("
|
|
3172
|
+
throw new Error("xacpx MCP command must not be empty");
|
|
3163
3173
|
}
|
|
3164
3174
|
return { command: parts[0], args: parts.slice(1) };
|
|
3165
3175
|
}
|
|
@@ -3205,7 +3215,7 @@ function queueLockFilePath(sessionId) {
|
|
|
3205
3215
|
function shortHash(value, length) {
|
|
3206
3216
|
return createHash("sha256").update(value).digest("hex").slice(0, length);
|
|
3207
3217
|
}
|
|
3208
|
-
function
|
|
3218
|
+
function resolveDefaultXacpxCommand(env) {
|
|
3209
3219
|
const cliCommand = coreEnv("CLI_COMMAND", env);
|
|
3210
3220
|
if (cliCommand?.trim()) {
|
|
3211
3221
|
return cliCommand.trim();
|
|
@@ -3641,8 +3651,9 @@ class BridgeRuntime {
|
|
|
3641
3651
|
} else if (typeof parsed.id === "string") {
|
|
3642
3652
|
acpxRecordId = parsed.id;
|
|
3643
3653
|
}
|
|
3654
|
+
const agentSessionId = typeof parsed.agentSessionId === "string" ? parsed.agentSessionId : undefined;
|
|
3644
3655
|
if (acpxRecordId) {
|
|
3645
|
-
return { acpxRecordId };
|
|
3656
|
+
return { acpxRecordId, agentSessionId };
|
|
3646
3657
|
}
|
|
3647
3658
|
} catch {
|
|
3648
3659
|
const firstLine = result.stdout.trim().split(/\r?\n/, 1)[0];
|
|
@@ -3652,6 +3663,10 @@ class BridgeRuntime {
|
|
|
3652
3663
|
}
|
|
3653
3664
|
throw new Error("failed to resolve acpx session record id");
|
|
3654
3665
|
}
|
|
3666
|
+
async getAgentSessionId(input) {
|
|
3667
|
+
const record = await this.readSessionRecord(input);
|
|
3668
|
+
return { agentSessionId: record.agentSessionId };
|
|
3669
|
+
}
|
|
3655
3670
|
async setMode(input) {
|
|
3656
3671
|
const spawnSpec = resolveSpawnCommand(this.command, this.buildSessionArgs(input, [
|
|
3657
3672
|
"set-mode",
|
|
@@ -3919,7 +3934,8 @@ var BRIDGE_METHODS = new Set([
|
|
|
3919
3934
|
"prompt",
|
|
3920
3935
|
"setMode",
|
|
3921
3936
|
"cancel",
|
|
3922
|
-
"removeSession"
|
|
3937
|
+
"removeSession",
|
|
3938
|
+
"getAgentSessionId"
|
|
3923
3939
|
]);
|
|
3924
3940
|
var SESSION_SCOPED_METHODS = new Set([
|
|
3925
3941
|
"hasSession",
|
|
@@ -3929,7 +3945,8 @@ var SESSION_SCOPED_METHODS = new Set([
|
|
|
3929
3945
|
"prompt",
|
|
3930
3946
|
"setMode",
|
|
3931
3947
|
"cancel",
|
|
3932
|
-
"removeSession"
|
|
3948
|
+
"removeSession",
|
|
3949
|
+
"getAgentSessionId"
|
|
3933
3950
|
]);
|
|
3934
3951
|
|
|
3935
3952
|
class BridgeServer {
|
|
@@ -4105,6 +4122,13 @@ class BridgeServer {
|
|
|
4105
4122
|
cwd: requireString(params, "cwd"),
|
|
4106
4123
|
name: requireString(params, "name")
|
|
4107
4124
|
});
|
|
4125
|
+
case "getAgentSessionId":
|
|
4126
|
+
return await this.runtime.getAgentSessionId({
|
|
4127
|
+
agent: requireString(params, "agent"),
|
|
4128
|
+
agentCommand: asOptionalString(params.agentCommand),
|
|
4129
|
+
cwd: requireString(params, "cwd"),
|
|
4130
|
+
name: requireString(params, "name")
|
|
4131
|
+
});
|
|
4108
4132
|
default:
|
|
4109
4133
|
throw new Error(`unsupported bridge method: ${method}`);
|
|
4110
4134
|
}
|
package/dist/cli.js
CHANGED
|
@@ -113,10 +113,11 @@ var init_session = __esm(() => {
|
|
|
113
113
|
replyModeHeader: "Current reply mode:",
|
|
114
114
|
replyModeSessionLabel: (alias) => `- Session: ${alias}`,
|
|
115
115
|
replyModeGlobalDefault: (value) => `- Global default: ${value}`,
|
|
116
|
+
replyModeChannelDefault: (value) => `- Channel default: ${value}`,
|
|
116
117
|
replyModeSessionOverride: (value) => `- Session override: ${value}`,
|
|
117
118
|
replyModeEffective: (value) => `- Effective: ${value}`,
|
|
118
119
|
replyModeSet: (replyMode) => `Current session reply mode set to: ${replyMode}`,
|
|
119
|
-
replyModeReset: (
|
|
120
|
+
replyModeReset: (effective) => `Session reply mode reset. Now effective: ${effective}`,
|
|
120
121
|
statusHeader: "Current session:",
|
|
121
122
|
statusNameLabel: (alias) => `- Name: ${alias}`,
|
|
122
123
|
statusAgentLabel: (agent) => `- Agent: ${agent}`,
|
|
@@ -659,6 +660,8 @@ var init_config = __esm(() => {
|
|
|
659
660
|
mustBePositiveNumber: (path) => `${path} must be a positive number.`,
|
|
660
661
|
channelTypeDisabled: "channel.type is a legacy single-channel field; /config set writes are disabled. Use `xacpx channel ...` to manage channels[], then restart xacpx.",
|
|
661
662
|
channelReplyModeInvalid: "channel.replyMode only supports: stream, final, verbose",
|
|
663
|
+
channelRuntimeNotFound: (id) => `Channel "${id}" does not exist; add it first with \`xacpx channel add ${id}\`.`,
|
|
664
|
+
channelRuntimeReplyModeInvalid: (id) => `channels.${id}.replyMode only supports: stream, final, verbose`,
|
|
662
665
|
wechatReplyModeInvalid: "wechat.replyMode only supports: stream, final, verbose",
|
|
663
666
|
wechatReplyModeMapped: (value) => `${value} (mapped to channel.replyMode)`,
|
|
664
667
|
agentNotFound: (name) => `Agent "${name}" does not exist. Create it first.`,
|
|
@@ -879,6 +882,8 @@ var init_channel_cli = __esm(() => {
|
|
|
879
882
|
channelRemoved: (id) => `Channel ${id} removed`,
|
|
880
883
|
cannotDisableLastEnabled: "Cannot disable the last enabled channel.",
|
|
881
884
|
channelEnabledToggled: (id, enabled) => `Channel ${id} ${enabled ? "enabled" : "disabled"}`,
|
|
885
|
+
channelReplyModeSet: (id, mode) => `Channel ${id} default reply mode set to: ${mode}`,
|
|
886
|
+
channelReplyModeInvalid: (mode) => `reply mode must be stream / final / verbose, got: ${mode}`,
|
|
882
887
|
channelAccountAlreadyExists: (type, accountId) => `Account ${accountId} already exists on channel ${type}; run xacpx channel rm ${type} --account ${accountId} first`,
|
|
883
888
|
channelAccountAdded: (type, accountId) => `Channel ${type} account ${accountId} added`,
|
|
884
889
|
channelReEnabled: (type) => `Channel ${type} was disabled; it has been automatically re-enabled.`,
|
|
@@ -1179,10 +1184,11 @@ var init_session2 = __esm(() => {
|
|
|
1179
1184
|
replyModeHeader: "当前 reply mode:",
|
|
1180
1185
|
replyModeSessionLabel: (alias) => `- 会话:${alias}`,
|
|
1181
1186
|
replyModeGlobalDefault: (value) => `- 全局默认:${value}`,
|
|
1187
|
+
replyModeChannelDefault: (value) => `- 频道默认:${value}`,
|
|
1182
1188
|
replyModeSessionOverride: (value) => `- 当前会话覆盖:${value}`,
|
|
1183
1189
|
replyModeEffective: (value) => `- 当前生效:${value}`,
|
|
1184
1190
|
replyModeSet: (replyMode) => `已设置当前会话 reply mode:${replyMode}`,
|
|
1185
|
-
replyModeReset: (
|
|
1191
|
+
replyModeReset: (effective) => `已重置当前会话 reply mode,当前生效:${effective}`,
|
|
1186
1192
|
statusHeader: "当前会话:",
|
|
1187
1193
|
statusNameLabel: (alias) => `- 名称:${alias}`,
|
|
1188
1194
|
statusAgentLabel: (agent2) => `- Agent:${agent2}`,
|
|
@@ -1725,6 +1731,8 @@ var init_config2 = __esm(() => {
|
|
|
1725
1731
|
mustBePositiveNumber: (path) => `${path} 必须是正数。`,
|
|
1726
1732
|
channelTypeDisabled: "channel.type 是旧单频道字段,/config set 已禁用写入;请使用 `xacpx channel ...` 管理 channels[],然后重启 xacpx。",
|
|
1727
1733
|
channelReplyModeInvalid: "channel.replyMode 只支持:stream、final、verbose",
|
|
1734
|
+
channelRuntimeNotFound: (id) => `频道「${id}」不存在;请先用 \`xacpx channel add ${id}\` 添加。`,
|
|
1735
|
+
channelRuntimeReplyModeInvalid: (id) => `channels.${id}.replyMode 只支持:stream、final、verbose`,
|
|
1728
1736
|
wechatReplyModeInvalid: "wechat.replyMode 只支持:stream、final、verbose",
|
|
1729
1737
|
wechatReplyModeMapped: (value) => `${value}(已映射到 channel.replyMode)`,
|
|
1730
1738
|
agentNotFound: (name) => `Agent「${name}」不存在,请先创建。`,
|
|
@@ -1945,6 +1953,8 @@ var init_channel_cli2 = __esm(() => {
|
|
|
1945
1953
|
channelRemoved: (id) => `频道 ${id} 已删除`,
|
|
1946
1954
|
cannotDisableLastEnabled: "不能禁用最后一个启用的频道。",
|
|
1947
1955
|
channelEnabledToggled: (id, enabled) => `频道 ${id} 已${enabled ? "启用" : "禁用"}`,
|
|
1956
|
+
channelReplyModeSet: (id, mode) => `频道 ${id} 的默认 reply mode 已设置为:${mode}`,
|
|
1957
|
+
channelReplyModeInvalid: (mode) => `reply mode 只支持 stream / final / verbose,收到:${mode}`,
|
|
1948
1958
|
channelAccountAlreadyExists: (type, accountId) => `频道 ${type} 的账号 ${accountId} 已存在;先 xacpx channel rm ${type} --account ${accountId}`,
|
|
1949
1959
|
channelAccountAdded: (type, accountId) => `频道 ${type} 账号 ${accountId} 已添加`,
|
|
1950
1960
|
channelReEnabled: (type) => `频道 ${type} 此前是 disabled 状态,已自动启用。`,
|
|
@@ -4647,6 +4657,9 @@ function parseRuntimeChannelConfig(raw, index) {
|
|
|
4647
4657
|
throw new Error(`channels[${index}].type must be a non-empty string`);
|
|
4648
4658
|
}
|
|
4649
4659
|
const enabled = raw.enabled !== false;
|
|
4660
|
+
if ("replyMode" in raw && !isReplyMode(raw.replyMode)) {
|
|
4661
|
+
throw new Error(`channels[${index}].replyMode must be stream, final, or verbose`);
|
|
4662
|
+
}
|
|
4650
4663
|
let options = undefined;
|
|
4651
4664
|
if ("feishu" in raw && isRecord(raw.feishu)) {
|
|
4652
4665
|
options = raw.feishu;
|
|
@@ -4657,6 +4670,7 @@ function parseRuntimeChannelConfig(raw, index) {
|
|
|
4657
4670
|
id,
|
|
4658
4671
|
type: raw.type,
|
|
4659
4672
|
enabled,
|
|
4673
|
+
...isReplyMode(raw.replyMode) ? { replyMode: raw.replyMode } : {},
|
|
4660
4674
|
...options ? { options } : {}
|
|
4661
4675
|
};
|
|
4662
4676
|
}
|
|
@@ -5394,7 +5408,7 @@ function resolveOrchestrationEndpoint(runtimeDir, platform = process.platform) {
|
|
|
5394
5408
|
const suffix = createHash("sha256").update(runtimeDir).digest("hex").slice(0, 12);
|
|
5395
5409
|
return {
|
|
5396
5410
|
kind: "named-pipe",
|
|
5397
|
-
path: `\\\\.\\pipe\\
|
|
5411
|
+
path: `\\\\.\\pipe\\xacpx-orchestration-${suffix}`
|
|
5398
5412
|
};
|
|
5399
5413
|
}
|
|
5400
5414
|
return {
|
|
@@ -11940,9 +11954,9 @@ function readVersion(moduleUrl = import.meta.url) {
|
|
|
11940
11954
|
}
|
|
11941
11955
|
return "unknown";
|
|
11942
11956
|
}
|
|
11943
|
-
var PACKAGE_NAME = "@ganglion/xacpx",
|
|
11957
|
+
var PACKAGE_NAME = "@ganglion/xacpx", XACPX_CORE_VERSION;
|
|
11944
11958
|
var init_version = __esm(() => {
|
|
11945
|
-
|
|
11959
|
+
XACPX_CORE_VERSION = readVersion();
|
|
11946
11960
|
});
|
|
11947
11961
|
|
|
11948
11962
|
// src/orchestration/task-watch-timeouts.ts
|
|
@@ -12281,7 +12295,7 @@ function isReplyMode2(value) {
|
|
|
12281
12295
|
return value === "stream" || value === "final" || value === "verbose";
|
|
12282
12296
|
}
|
|
12283
12297
|
function isSessionSource(value) {
|
|
12284
|
-
return value === undefined || value === "weacpx" || value === "agent-side";
|
|
12298
|
+
return value === undefined || value === "weacpx" || value === "xacpx" || value === "agent-side";
|
|
12285
12299
|
}
|
|
12286
12300
|
function isSessionRecord(value) {
|
|
12287
12301
|
if (!isRecord2(value)) {
|
|
@@ -12813,7 +12827,7 @@ async function ensureCoreResolution(pluginHome) {
|
|
|
12813
12827
|
await copyFile(srcJs, dstJs);
|
|
12814
12828
|
} catch (error2) {
|
|
12815
12829
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
12816
|
-
console.warn(`
|
|
12830
|
+
console.warn(`xacpx: skipped plugin-api resolution shim for "${name}" — could not copy ${srcJs} (${message}). ` + `Channel plugins importing "${name}/plugin-api" at runtime may fail to load.`);
|
|
12817
12831
|
continue;
|
|
12818
12832
|
}
|
|
12819
12833
|
await writeFile4(join6(targetDir, "package.json"), JSON.stringify({
|
|
@@ -13712,7 +13726,7 @@ async function sendTyping(params) {
|
|
|
13712
13726
|
label: "sendTyping"
|
|
13713
13727
|
});
|
|
13714
13728
|
}
|
|
13715
|
-
var CHANNEL_VERSION, ILINK_APP_CLIENT_VERSION, ILINK_APP_ID, DEFAULT_BOT_AGENT = "
|
|
13729
|
+
var CHANNEL_VERSION, ILINK_APP_CLIENT_VERSION, ILINK_APP_ID, DEFAULT_BOT_AGENT = "xacpx", BOT_AGENT_MAX_LEN = 256, DEFAULT_LONG_POLL_TIMEOUT_MS = 35000, DEFAULT_API_TIMEOUT_MS = 15000, DEFAULT_CONFIG_TIMEOUT_MS = 1e4;
|
|
13716
13730
|
var init_api = __esm(() => {
|
|
13717
13731
|
init_version();
|
|
13718
13732
|
init_accounts();
|
|
@@ -19158,19 +19172,19 @@ function cmpTuple(a, b) {
|
|
|
19158
19172
|
return 0;
|
|
19159
19173
|
}
|
|
19160
19174
|
function validatePluginCompatibility(metadata, context) {
|
|
19161
|
-
const { packageName,
|
|
19175
|
+
const { packageName, currentXacpxVersion } = context;
|
|
19162
19176
|
const apiVersion = metadata.apiVersion;
|
|
19163
19177
|
if (typeof apiVersion !== "number") {
|
|
19164
19178
|
throw new Error(t().pluginCli.compatMissingApiVersion(packageName));
|
|
19165
19179
|
}
|
|
19166
|
-
if (!
|
|
19167
|
-
const supported =
|
|
19180
|
+
if (!XACPX_PLUGIN_API_SUPPORTED_VERSIONS.includes(apiVersion)) {
|
|
19181
|
+
const supported = XACPX_PLUGIN_API_SUPPORTED_VERSIONS.join(", ");
|
|
19168
19182
|
throw new Error(t().pluginCli.compatUnsupportedApiVersion(packageName, apiVersion, supported));
|
|
19169
19183
|
}
|
|
19170
|
-
if (!
|
|
19184
|
+
if (!currentXacpxVersion || currentXacpxVersion === "unknown") {
|
|
19171
19185
|
return;
|
|
19172
19186
|
}
|
|
19173
|
-
const normalizedCurrent = normalizeCoreVersionForCompat(
|
|
19187
|
+
const normalizedCurrent = normalizeCoreVersionForCompat(currentXacpxVersion);
|
|
19174
19188
|
const minVersion = metadata.minXacpxVersion ?? metadata.minWeacpxVersion;
|
|
19175
19189
|
const minVersionField = metadata.minXacpxVersion !== undefined ? "minXacpxVersion" : "minWeacpxVersion";
|
|
19176
19190
|
if (minVersion !== undefined) {
|
|
@@ -19185,7 +19199,7 @@ function validatePluginCompatibility(metadata, context) {
|
|
|
19185
19199
|
throw new Error(t().pluginCli.compatInvalidMinVersionDetail(packageName, minVersionField, detail));
|
|
19186
19200
|
}
|
|
19187
19201
|
if (!satisfied) {
|
|
19188
|
-
throw new Error(t().pluginCli.compatMinVersionNotSatisfied(packageName, minVersion,
|
|
19202
|
+
throw new Error(t().pluginCli.compatMinVersionNotSatisfied(packageName, minVersion, currentXacpxVersion));
|
|
19189
19203
|
}
|
|
19190
19204
|
}
|
|
19191
19205
|
const compatibleVersions = metadata.compatibleXacpxVersions ?? metadata.compatibleWeacpxVersions;
|
|
@@ -19202,14 +19216,17 @@ function validatePluginCompatibility(metadata, context) {
|
|
|
19202
19216
|
throw new Error(t().pluginCli.compatInvalidCompatibleVersionsDetail(packageName, compatibleField, detail));
|
|
19203
19217
|
}
|
|
19204
19218
|
if (!satisfied) {
|
|
19205
|
-
throw new Error(t().pluginCli.compatCompatibleVersionsNotSatisfied(packageName, compatibleVersions,
|
|
19219
|
+
throw new Error(t().pluginCli.compatCompatibleVersionsNotSatisfied(packageName, compatibleVersions, currentXacpxVersion));
|
|
19206
19220
|
}
|
|
19207
19221
|
}
|
|
19208
19222
|
}
|
|
19209
|
-
var
|
|
19223
|
+
var XACPX_PLUGIN_API_VERSION = 1, XACPX_PLUGIN_API_SUPPORTED_VERSIONS, XACPX_PLUGIN_MIN_CORE_VERSION = "0.5.0", WEACPX_PLUGIN_API_VERSION, WEACPX_PLUGIN_API_SUPPORTED_VERSIONS, WEACPX_PLUGIN_MIN_CORE_VERSION, SEMVER_RE;
|
|
19210
19224
|
var init_compatibility = __esm(() => {
|
|
19211
19225
|
init_i18n();
|
|
19212
|
-
|
|
19226
|
+
XACPX_PLUGIN_API_SUPPORTED_VERSIONS = [1];
|
|
19227
|
+
WEACPX_PLUGIN_API_VERSION = XACPX_PLUGIN_API_VERSION;
|
|
19228
|
+
WEACPX_PLUGIN_API_SUPPORTED_VERSIONS = XACPX_PLUGIN_API_SUPPORTED_VERSIONS;
|
|
19229
|
+
WEACPX_PLUGIN_MIN_CORE_VERSION = XACPX_PLUGIN_MIN_CORE_VERSION;
|
|
19213
19230
|
SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)$/;
|
|
19214
19231
|
});
|
|
19215
19232
|
|
|
@@ -19224,14 +19241,14 @@ function validateWeacpxPlugin(value, packageName, options = {}) {
|
|
|
19224
19241
|
if (!isRecord(plugin)) {
|
|
19225
19242
|
throw new Error(t().pluginCli.pluginNoDefaultExport(packageName));
|
|
19226
19243
|
}
|
|
19227
|
-
const
|
|
19244
|
+
const currentXacpxVersion = options.currentXacpxVersion ?? readVersion();
|
|
19228
19245
|
validatePluginCompatibility({
|
|
19229
19246
|
apiVersion: plugin.apiVersion,
|
|
19230
19247
|
minWeacpxVersion: plugin.minWeacpxVersion,
|
|
19231
19248
|
compatibleWeacpxVersions: plugin.compatibleWeacpxVersions,
|
|
19232
19249
|
minXacpxVersion: plugin.minXacpxVersion,
|
|
19233
19250
|
compatibleXacpxVersions: plugin.compatibleXacpxVersions
|
|
19234
|
-
}, { packageName,
|
|
19251
|
+
}, { packageName, currentXacpxVersion });
|
|
19235
19252
|
if ("name" in plugin && typeof plugin.name === "string" && plugin.name.trim() && plugin.name.trim() !== packageName) {
|
|
19236
19253
|
throw new Error(t().pluginCli.pluginNameMismatch(packageName, plugin.name));
|
|
19237
19254
|
}
|
|
@@ -19260,7 +19277,7 @@ function validateWeacpxPlugin(value, packageName, options = {}) {
|
|
|
19260
19277
|
}
|
|
19261
19278
|
}
|
|
19262
19279
|
const normalized = {
|
|
19263
|
-
apiVersion:
|
|
19280
|
+
apiVersion: XACPX_PLUGIN_API_VERSION,
|
|
19264
19281
|
...typeof plugin.name === "string" && plugin.name.trim() ? { name: plugin.name.trim() } : { name: packageName },
|
|
19265
19282
|
channels
|
|
19266
19283
|
};
|
|
@@ -19314,7 +19331,7 @@ async function loadConfiguredPlugins(input) {
|
|
|
19314
19331
|
throw new Error(`failed to load plugin ${config4.name}: ${message}`);
|
|
19315
19332
|
}
|
|
19316
19333
|
const plugin = validateWeacpxPlugin(moduleValue, config4.name, {
|
|
19317
|
-
...input.
|
|
19334
|
+
...input.currentXacpxVersion !== undefined ? { currentXacpxVersion: input.currentXacpxVersion } : {}
|
|
19318
19335
|
});
|
|
19319
19336
|
const channels = plugin.channels ?? [];
|
|
19320
19337
|
for (const channel of channels) {
|
|
@@ -19566,16 +19583,16 @@ var init_prompt_output = __esm(() => {
|
|
|
19566
19583
|
});
|
|
19567
19584
|
|
|
19568
19585
|
// src/commands/command-list.ts
|
|
19569
|
-
function
|
|
19586
|
+
function isKnownXacpxCommandPrefix(prefix) {
|
|
19570
19587
|
return KNOWN_COMMAND_PREFIX_SET.has(prefix.toLowerCase());
|
|
19571
19588
|
}
|
|
19572
|
-
function
|
|
19589
|
+
function isKnownXacpxCommandText(text) {
|
|
19573
19590
|
const firstToken = text.trim().split(/\s+/, 1)[0];
|
|
19574
|
-
return Boolean(firstToken &&
|
|
19591
|
+
return Boolean(firstToken && isKnownXacpxCommandPrefix(firstToken));
|
|
19575
19592
|
}
|
|
19576
|
-
var
|
|
19593
|
+
var XACPX_KNOWN_COMMAND_PREFIXES, KNOWN_COMMAND_PREFIX_SET;
|
|
19577
19594
|
var init_command_list = __esm(() => {
|
|
19578
|
-
|
|
19595
|
+
XACPX_KNOWN_COMMAND_PREFIXES = [
|
|
19579
19596
|
"/help",
|
|
19580
19597
|
"/agents",
|
|
19581
19598
|
"/workspaces",
|
|
@@ -19605,7 +19622,7 @@ var init_command_list = __esm(() => {
|
|
|
19605
19622
|
"/later",
|
|
19606
19623
|
"/lt"
|
|
19607
19624
|
];
|
|
19608
|
-
KNOWN_COMMAND_PREFIX_SET = new Set(
|
|
19625
|
+
KNOWN_COMMAND_PREFIX_SET = new Set(XACPX_KNOWN_COMMAND_PREFIXES);
|
|
19609
19626
|
});
|
|
19610
19627
|
|
|
19611
19628
|
// src/commands/parse-command.ts
|
|
@@ -20095,7 +20112,7 @@ function normalizeCommand(command) {
|
|
|
20095
20112
|
return command;
|
|
20096
20113
|
}
|
|
20097
20114
|
function isRecognizedCommand(command) {
|
|
20098
|
-
return
|
|
20115
|
+
return isKnownXacpxCommandPrefix(command);
|
|
20099
20116
|
}
|
|
20100
20117
|
function toPermissionMode(value) {
|
|
20101
20118
|
if (value === "allow")
|
|
@@ -20609,6 +20626,23 @@ function applySupportedConfigUpdate(config4, path14, rawValue) {
|
|
|
20609
20626
|
}
|
|
20610
20627
|
return { renderedValue: rawValue };
|
|
20611
20628
|
}
|
|
20629
|
+
const channelMatch = path14.match(/^channels\.([^.]+)\.replyMode$/);
|
|
20630
|
+
if (channelMatch) {
|
|
20631
|
+
const [, id] = channelMatch;
|
|
20632
|
+
if (!id) {
|
|
20633
|
+
return { error: c.pathNotSupported(path14) };
|
|
20634
|
+
}
|
|
20635
|
+
const channel = config4.channels.find((entry) => entry.id === id);
|
|
20636
|
+
if (!channel) {
|
|
20637
|
+
return { error: c.channelRuntimeNotFound(id) };
|
|
20638
|
+
}
|
|
20639
|
+
const parsed = parseEnum(rawValue, ["stream", "final", "verbose"]);
|
|
20640
|
+
if (!parsed) {
|
|
20641
|
+
return { error: c.channelRuntimeReplyModeInvalid(id) };
|
|
20642
|
+
}
|
|
20643
|
+
channel.replyMode = parsed;
|
|
20644
|
+
return { renderedValue: parsed };
|
|
20645
|
+
}
|
|
20612
20646
|
return { error: c.pathNotSupported(path14) };
|
|
20613
20647
|
}
|
|
20614
20648
|
function parseEnum(value, allowed) {
|
|
@@ -20638,6 +20672,7 @@ var init_config_handler = __esm(() => {
|
|
|
20638
20672
|
"logging.maxFiles",
|
|
20639
20673
|
"logging.retentionDays",
|
|
20640
20674
|
"channel.replyMode",
|
|
20675
|
+
"channels.<id>.replyMode",
|
|
20641
20676
|
"agents.<name>.driver",
|
|
20642
20677
|
"agents.<name>.command",
|
|
20643
20678
|
"workspaces.<name>.cwd",
|
|
@@ -20978,6 +21013,20 @@ var init_build_coordinator_prompt = __esm(() => {
|
|
|
20978
21013
|
init_render_delegate_question_package();
|
|
20979
21014
|
});
|
|
20980
21015
|
|
|
21016
|
+
// src/commands/handlers/resolve-reply-mode.ts
|
|
21017
|
+
function resolveChannelDefaultReplyMode(config4, chatKey) {
|
|
21018
|
+
if (!config4)
|
|
21019
|
+
return;
|
|
21020
|
+
const channelId = getChannelIdFromChatKey(chatKey);
|
|
21021
|
+
return config4.channels.find((channel) => channel.id === channelId)?.replyMode;
|
|
21022
|
+
}
|
|
21023
|
+
function resolveEffectiveReplyMode(config4, chatKey, sessionOverride) {
|
|
21024
|
+
return sessionOverride ?? resolveChannelDefaultReplyMode(config4, chatKey) ?? config4?.channel.replyMode ?? "verbose";
|
|
21025
|
+
}
|
|
21026
|
+
var init_resolve_reply_mode = __esm(() => {
|
|
21027
|
+
init_channel_scope();
|
|
21028
|
+
});
|
|
21029
|
+
|
|
20981
21030
|
// src/commands/handlers/session-list-marker.ts
|
|
20982
21031
|
function decorateUnread(label, hasUnread) {
|
|
20983
21032
|
return hasUnread ? `● ${label}` : label;
|
|
@@ -21282,14 +21331,16 @@ async function handleReplyModeShow(context, chatKey) {
|
|
|
21282
21331
|
return { text: t().session.noCurrent };
|
|
21283
21332
|
}
|
|
21284
21333
|
const globalDefault = context.config?.channel.replyMode ?? "verbose";
|
|
21334
|
+
const channelDefault = resolveChannelDefaultReplyMode(context.config, chatKey);
|
|
21285
21335
|
const sessionOverride = session3.replyMode;
|
|
21286
|
-
const effective =
|
|
21336
|
+
const effective = resolveEffectiveReplyMode(context.config, chatKey, sessionOverride);
|
|
21287
21337
|
const s = t().session;
|
|
21288
21338
|
return {
|
|
21289
21339
|
text: [
|
|
21290
21340
|
s.replyModeHeader,
|
|
21291
21341
|
s.replyModeSessionLabel(toDisplaySessionAlias(session3.alias)),
|
|
21292
21342
|
s.replyModeGlobalDefault(globalDefault),
|
|
21343
|
+
s.replyModeChannelDefault(channelDefault ?? s.modeNotSet),
|
|
21293
21344
|
s.replyModeSessionOverride(sessionOverride ?? s.modeNotSet),
|
|
21294
21345
|
s.replyModeEffective(effective)
|
|
21295
21346
|
].join(`
|
|
@@ -21310,8 +21361,8 @@ async function handleReplyModeReset(context, chatKey) {
|
|
|
21310
21361
|
return { text: t().session.noCurrent };
|
|
21311
21362
|
}
|
|
21312
21363
|
await context.sessions.setCurrentSessionReplyMode(chatKey, undefined);
|
|
21313
|
-
const
|
|
21314
|
-
return { text: t().session.replyModeReset(
|
|
21364
|
+
const fallback = resolveEffectiveReplyMode(context.config, chatKey, undefined);
|
|
21365
|
+
return { text: t().session.replyModeReset(fallback) };
|
|
21315
21366
|
}
|
|
21316
21367
|
async function handleStatus(context, chatKey) {
|
|
21317
21368
|
const session3 = await context.sessions.getCurrentSession(chatKey);
|
|
@@ -21458,7 +21509,7 @@ async function handleSessionRemove(context, chatKey, alias) {
|
|
|
21458
21509
|
`) };
|
|
21459
21510
|
}
|
|
21460
21511
|
async function promptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata) {
|
|
21461
|
-
const effectiveReplyMode =
|
|
21512
|
+
const effectiveReplyMode = resolveEffectiveReplyMode(context.config, chatKey, session3.replyMode);
|
|
21462
21513
|
if (!session3.replyMode)
|
|
21463
21514
|
session3.replyMode = effectiveReplyMode;
|
|
21464
21515
|
const transportReply = effectiveReplyMode !== "final" ? reply : undefined;
|
|
@@ -21606,6 +21657,7 @@ var DEFAULT_SESSION_TAIL_LINES = 50, MAX_SESSION_TAIL_LINES = 500;
|
|
|
21606
21657
|
var init_session_handler = __esm(() => {
|
|
21607
21658
|
init_build_coordinator_prompt();
|
|
21608
21659
|
init_channel_scope();
|
|
21660
|
+
init_resolve_reply_mode();
|
|
21609
21661
|
init_workspace_name();
|
|
21610
21662
|
init_i18n();
|
|
21611
21663
|
});
|
|
@@ -23657,23 +23709,43 @@ var init_translate_acpx_note = __esm(() => {
|
|
|
23657
23709
|
|
|
23658
23710
|
// src/commands/handlers/session-reset-handler.ts
|
|
23659
23711
|
async function handleSessionResetCommand(context, ops, chatKey) {
|
|
23660
|
-
const
|
|
23661
|
-
if (!
|
|
23712
|
+
const previous = await context.sessions.getCurrentSession(chatKey);
|
|
23713
|
+
if (!previous) {
|
|
23662
23714
|
return { text: t().misc.sessionResetNoCurrentSession };
|
|
23663
23715
|
}
|
|
23664
|
-
const
|
|
23716
|
+
const wasNative = previous.source === "agent-side";
|
|
23717
|
+
const resetSession = ops.resolveSession(previous.alias, previous.agent, previous.workspace, buildResetTransportSessionName(previous, ops.now()));
|
|
23665
23718
|
const releaseTransportReservation = await ops.reserveTransportSession(resetSession.transportSession);
|
|
23666
23719
|
try {
|
|
23667
23720
|
try {
|
|
23668
23721
|
await ops.ensureTransportSession(resetSession);
|
|
23669
23722
|
const exists = await ops.checkTransportSession(resetSession);
|
|
23670
23723
|
if (!exists) {
|
|
23671
|
-
return { text: t().misc.sessionResetFailed(
|
|
23724
|
+
return { text: t().misc.sessionResetFailed(previous.alias) };
|
|
23672
23725
|
}
|
|
23673
23726
|
} catch (error2) {
|
|
23674
23727
|
return renderTransportError(resetSession, error2);
|
|
23675
23728
|
}
|
|
23676
|
-
|
|
23729
|
+
let freshAgentSessionId;
|
|
23730
|
+
if (wasNative) {
|
|
23731
|
+
try {
|
|
23732
|
+
freshAgentSessionId = await context.transport.getAgentSessionId?.(resetSession);
|
|
23733
|
+
} catch (error2) {
|
|
23734
|
+
await context.logger.info("session.reset.native_id_unavailable", "failed to read fresh agent session id; falling back to xacpx session", { alias: resetSession.alias, error: error2 instanceof Error ? error2.message : String(error2) });
|
|
23735
|
+
}
|
|
23736
|
+
}
|
|
23737
|
+
if (wasNative && freshAgentSessionId) {
|
|
23738
|
+
await context.sessions.attachNativeSession({
|
|
23739
|
+
alias: resetSession.alias,
|
|
23740
|
+
agent: resetSession.agent,
|
|
23741
|
+
workspace: resetSession.workspace,
|
|
23742
|
+
transportSession: resetSession.transportSession,
|
|
23743
|
+
agentSessionId: freshAgentSessionId,
|
|
23744
|
+
updatedAt: new Date(ops.now()).toISOString()
|
|
23745
|
+
});
|
|
23746
|
+
} else {
|
|
23747
|
+
await context.sessions.attachSession(resetSession.alias, resetSession.agent, resetSession.workspace, resetSession.transportSession);
|
|
23748
|
+
}
|
|
23677
23749
|
await ops.refreshSessionTransportAgentCommand(resetSession.alias);
|
|
23678
23750
|
await context.sessions.useSession(chatKey, resetSession.alias);
|
|
23679
23751
|
await context.logger.info("session.reset", "reset current logical session", {
|
|
@@ -23681,8 +23753,19 @@ async function handleSessionResetCommand(context, ops, chatKey) {
|
|
|
23681
23753
|
agent: resetSession.agent,
|
|
23682
23754
|
workspace: resetSession.workspace,
|
|
23683
23755
|
transportSession: resetSession.transportSession,
|
|
23684
|
-
chatKey
|
|
23756
|
+
chatKey,
|
|
23757
|
+
native: wasNative && Boolean(freshAgentSessionId)
|
|
23685
23758
|
});
|
|
23759
|
+
if (wasNative && context.transport.removeSession && context.sessions.countAliasesSharingTransport(previous.transportSession) === 0) {
|
|
23760
|
+
try {
|
|
23761
|
+
await context.transport.removeSession(previous);
|
|
23762
|
+
} catch (error2) {
|
|
23763
|
+
await context.logger.info("session.reset.close_previous_failed", "failed to close previous native session after reset", {
|
|
23764
|
+
transportSession: previous.transportSession,
|
|
23765
|
+
error: error2 instanceof Error ? error2.message : String(error2)
|
|
23766
|
+
});
|
|
23767
|
+
}
|
|
23768
|
+
}
|
|
23686
23769
|
} finally {
|
|
23687
23770
|
await releaseTransportReservation();
|
|
23688
23771
|
}
|
|
@@ -24351,7 +24434,7 @@ class ConsoleAgent {
|
|
|
24351
24434
|
return await this.router.handle(request.conversationId, request.text, request.reply, request.replyContextToken, request.accountId, promptMedia, request.metadata, request.abortSignal, request.onToolEvent, request.onThought, request.perfSpan);
|
|
24352
24435
|
}
|
|
24353
24436
|
isKnownCommand(text) {
|
|
24354
|
-
return
|
|
24437
|
+
return isKnownXacpxCommandText(text);
|
|
24355
24438
|
}
|
|
24356
24439
|
async clearSession(conversationId) {
|
|
24357
24440
|
await this.router.clearSession?.(conversationId);
|
|
@@ -29175,7 +29258,7 @@ class DebouncedStateStore {
|
|
|
29175
29258
|
}
|
|
29176
29259
|
|
|
29177
29260
|
// src/commands/command-hints.ts
|
|
29178
|
-
function
|
|
29261
|
+
function listXacpxCommandHints() {
|
|
29179
29262
|
const hints3 = [{ name: "/help", description: t().hints.helpDescription }];
|
|
29180
29263
|
for (const topic of listHelpTopics()) {
|
|
29181
29264
|
const name = PRIMARY_COMMAND_BY_TOPIC[topic.topic];
|
|
@@ -29323,8 +29406,8 @@ async function runConsole(paths, deps) {
|
|
|
29323
29406
|
activeTurns: runtime.activeTurns,
|
|
29324
29407
|
logger: runtime.logger,
|
|
29325
29408
|
perfTracer: runtime.perfTracer,
|
|
29326
|
-
commandHints:
|
|
29327
|
-
coreVersion:
|
|
29409
|
+
commandHints: listXacpxCommandHints(),
|
|
29410
|
+
coreVersion: XACPX_CORE_VERSION,
|
|
29328
29411
|
locale: getLocale()
|
|
29329
29412
|
});
|
|
29330
29413
|
channelStartPromise.catch(() => {});
|
|
@@ -30016,6 +30099,10 @@ ${result.text}` : "" };
|
|
|
30016
30099
|
async removeSession(session3) {
|
|
30017
30100
|
await this.client.request("removeSession", this.toParams(session3));
|
|
30018
30101
|
}
|
|
30102
|
+
async getAgentSessionId(session3) {
|
|
30103
|
+
const result = await this.client.request("getAgentSessionId", this.toParams(session3));
|
|
30104
|
+
return result.agentSessionId;
|
|
30105
|
+
}
|
|
30019
30106
|
async hasSession(session3) {
|
|
30020
30107
|
const result = await this.client.request("hasSession", this.toParams(session3));
|
|
30021
30108
|
return result.exists;
|
|
@@ -30510,10 +30597,10 @@ import { spawn as spawn8 } from "node:child_process";
|
|
|
30510
30597
|
import { readFile as readFile12, unlink } from "node:fs/promises";
|
|
30511
30598
|
import { homedir as homedir8 } from "node:os";
|
|
30512
30599
|
import { join as join17 } from "node:path";
|
|
30513
|
-
function
|
|
30514
|
-
const { command, args } = splitCommandLine(input.
|
|
30600
|
+
function buildXacpxMcpServerSpec(input) {
|
|
30601
|
+
const { command, args } = splitCommandLine(input.xacpxCommand);
|
|
30515
30602
|
return {
|
|
30516
|
-
name: "
|
|
30603
|
+
name: "xacpx",
|
|
30517
30604
|
type: "stdio",
|
|
30518
30605
|
command,
|
|
30519
30606
|
args: [
|
|
@@ -30540,7 +30627,7 @@ function buildQueueOwnerPayload(input) {
|
|
|
30540
30627
|
|
|
30541
30628
|
class AcpxQueueOwnerLauncher {
|
|
30542
30629
|
acpxCommand;
|
|
30543
|
-
|
|
30630
|
+
xacpxCommand;
|
|
30544
30631
|
spawnOwner;
|
|
30545
30632
|
terminateOwner;
|
|
30546
30633
|
baseEnv;
|
|
@@ -30549,7 +30636,7 @@ class AcpxQueueOwnerLauncher {
|
|
|
30549
30636
|
launchLocks = new Map;
|
|
30550
30637
|
constructor(options) {
|
|
30551
30638
|
this.acpxCommand = options.acpxCommand;
|
|
30552
|
-
this.
|
|
30639
|
+
this.xacpxCommand = options.xacpxCommand ?? resolveDefaultXacpxCommand(options.baseEnv ?? process.env);
|
|
30553
30640
|
this.spawnOwner = options.spawnOwner ?? defaultQueueOwnerSpawner;
|
|
30554
30641
|
this.terminateOwner = options.terminateOwner ?? createDefaultQueueOwnerTerminator(options.acpxCommand);
|
|
30555
30642
|
this.baseEnv = options.baseEnv ?? process.env;
|
|
@@ -30577,8 +30664,8 @@ class AcpxQueueOwnerLauncher {
|
|
|
30577
30664
|
nonInteractivePermissions: input.nonInteractivePermissions,
|
|
30578
30665
|
ttlMs: this.ttlMs,
|
|
30579
30666
|
maxQueueDepth: this.maxQueueDepth,
|
|
30580
|
-
mcpServers: [
|
|
30581
|
-
|
|
30667
|
+
mcpServers: [buildXacpxMcpServerSpec({
|
|
30668
|
+
xacpxCommand: this.xacpxCommand,
|
|
30582
30669
|
coordinatorSession: input.coordinatorSession,
|
|
30583
30670
|
...input.sourceHandle ? { sourceHandle: input.sourceHandle } : {}
|
|
30584
30671
|
})]
|
|
@@ -30633,13 +30720,13 @@ function splitCommandLine(value) {
|
|
|
30633
30720
|
current += "\\";
|
|
30634
30721
|
}
|
|
30635
30722
|
if (quote) {
|
|
30636
|
-
throw new Error("
|
|
30723
|
+
throw new Error("xacpx MCP command has an unterminated quote");
|
|
30637
30724
|
}
|
|
30638
30725
|
if (current.length > 0) {
|
|
30639
30726
|
parts.push(current);
|
|
30640
30727
|
}
|
|
30641
30728
|
if (parts.length === 0) {
|
|
30642
|
-
throw new Error("
|
|
30729
|
+
throw new Error("xacpx MCP command must not be empty");
|
|
30643
30730
|
}
|
|
30644
30731
|
return { command: parts[0], args: parts.slice(1) };
|
|
30645
30732
|
}
|
|
@@ -30685,7 +30772,7 @@ function queueLockFilePath(sessionId) {
|
|
|
30685
30772
|
function shortHash(value, length) {
|
|
30686
30773
|
return createHash3("sha256").update(value).digest("hex").slice(0, length);
|
|
30687
30774
|
}
|
|
30688
|
-
function
|
|
30775
|
+
function resolveDefaultXacpxCommand(env) {
|
|
30689
30776
|
const cliCommand = coreEnv("CLI_COMMAND", env);
|
|
30690
30777
|
if (cliCommand?.trim()) {
|
|
30691
30778
|
return cliCommand.trim();
|
|
@@ -31036,8 +31123,9 @@ ${baseText}` : "" };
|
|
|
31036
31123
|
try {
|
|
31037
31124
|
const parsed = JSON.parse(result.stdout);
|
|
31038
31125
|
const acpxRecordId = typeof parsed.acpxRecordId === "string" ? parsed.acpxRecordId : typeof parsed.id === "string" ? parsed.id : undefined;
|
|
31126
|
+
const agentSessionId = typeof parsed.agentSessionId === "string" ? parsed.agentSessionId : undefined;
|
|
31039
31127
|
if (acpxRecordId) {
|
|
31040
|
-
return { acpxRecordId };
|
|
31128
|
+
return { acpxRecordId, agentSessionId };
|
|
31041
31129
|
}
|
|
31042
31130
|
} catch {
|
|
31043
31131
|
const firstLine = result.stdout.trim().split(/\r?\n/, 1)[0];
|
|
@@ -31047,6 +31135,10 @@ ${baseText}` : "" };
|
|
|
31047
31135
|
}
|
|
31048
31136
|
throw new Error("failed to resolve acpx session record id");
|
|
31049
31137
|
}
|
|
31138
|
+
async getAgentSessionId(session3) {
|
|
31139
|
+
const record3 = await this.readSessionRecord(session3);
|
|
31140
|
+
return record3.agentSessionId;
|
|
31141
|
+
}
|
|
31050
31142
|
async run(args, options) {
|
|
31051
31143
|
const result = await this.runCommandWithTimeout(this.runCommand, args, options);
|
|
31052
31144
|
if (result.code !== 0) {
|
|
@@ -33583,7 +33675,7 @@ class DaemonRuntime {
|
|
|
33583
33675
|
}
|
|
33584
33676
|
}
|
|
33585
33677
|
|
|
33586
|
-
// src/mcp/
|
|
33678
|
+
// src/mcp/xacpx-mcp-server.ts
|
|
33587
33679
|
import { stdin, stdout } from "node:process";
|
|
33588
33680
|
|
|
33589
33681
|
// node_modules/@modelcontextprotocol/sdk/node_modules/zod/v4/core/core.js
|
|
@@ -45939,7 +46031,7 @@ class StdioServerTransport {
|
|
|
45939
46031
|
}
|
|
45940
46032
|
}
|
|
45941
46033
|
|
|
45942
|
-
// src/mcp/
|
|
46034
|
+
// src/mcp/xacpx-mcp-server.ts
|
|
45943
46035
|
init_version();
|
|
45944
46036
|
|
|
45945
46037
|
// src/mcp/resolve-endpoint.ts
|
|
@@ -45967,7 +46059,7 @@ function requireHome(env) {
|
|
|
45967
46059
|
return home;
|
|
45968
46060
|
}
|
|
45969
46061
|
|
|
45970
|
-
// src/mcp/
|
|
46062
|
+
// src/mcp/xacpx-mcp-tools.ts
|
|
45971
46063
|
init_task_watch_timeouts();
|
|
45972
46064
|
init_quota_errors();
|
|
45973
46065
|
var taskStatusSchema = exports_external.enum([
|
|
@@ -45988,7 +46080,7 @@ var taskQuestionSchema = exports_external.object({
|
|
|
45988
46080
|
taskId: exports_external.string().min(1),
|
|
45989
46081
|
questionId: exports_external.string().min(1)
|
|
45990
46082
|
}).strict();
|
|
45991
|
-
function
|
|
46083
|
+
function buildXacpxMcpToolRegistry(input) {
|
|
45992
46084
|
const { transport, coordinatorSession, sourceHandle, isExternalCoordinator, internalSessionTools, availableAgents } = input;
|
|
45993
46085
|
const tools = [
|
|
45994
46086
|
{
|
|
@@ -46146,7 +46238,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
46146
46238
|
}).strict(),
|
|
46147
46239
|
handler: async (args) => await asToolResult(async () => {
|
|
46148
46240
|
if (!sourceHandle || sourceHandle.trim().length === 0) {
|
|
46149
|
-
throw new Error("worker_raise_question requires a bound sourceHandle; start mcp-stdio with --source-handle or
|
|
46241
|
+
throw new Error("worker_raise_question requires a bound sourceHandle; start mcp-stdio with --source-handle or XACPX_SOURCE_HANDLE");
|
|
46150
46242
|
}
|
|
46151
46243
|
const result = await transport.workerRaiseQuestion({
|
|
46152
46244
|
sourceHandle,
|
|
@@ -46209,7 +46301,7 @@ function buildWeacpxMcpToolRegistry(input) {
|
|
|
46209
46301
|
if (internalSessionTools && !isExternalCoordinator && !sourceHandle) {
|
|
46210
46302
|
tools.push({
|
|
46211
46303
|
name: "scheduled_create",
|
|
46212
|
-
description: "Schedule a one-shot task to run a natural-language message at a future time, using the recorded chat route. By default — and like /later — the task runs in a FRESH TEMPORARY session (it snapshots the current agent and workspace but starts with brand-new history and is destroyed after running, so it does not pollute this conversation); the reply is still pushed back to this chat. Provide only timeText and message and OMIT mode to get this default. Routing, session, and account are resolved by
|
|
46304
|
+
description: "Schedule a one-shot task to run a natural-language message at a future time, using the recorded chat route. By default — and like /later — the task runs in a FRESH TEMPORARY session (it snapshots the current agent and workspace but starts with brand-new history and is destroyed after running, so it does not pollute this conversation); the reply is still pushed back to this chat. Provide only timeText and message and OMIT mode to get this default. Routing, session, and account are resolved by xacpx.",
|
|
46213
46305
|
inputSchema: exports_external.object({
|
|
46214
46306
|
timeText: exports_external.string().min(1).describe("Time expression, e.g. 'in 2h', '30分钟后', 'tomorrow 09:00', or '周五 09:00'."),
|
|
46215
46307
|
message: exports_external.string().min(1).describe("Natural-language message to run at the scheduled time."),
|
|
@@ -46619,7 +46711,7 @@ function getWatchRequestTimeoutMs(watchTimeoutMs, defaultTimeoutMs) {
|
|
|
46619
46711
|
return Math.max(defaultTimeoutMs, boundedWatchTimeoutMs + TASK_WATCH_RPC_TIMEOUT_PADDING_MS);
|
|
46620
46712
|
}
|
|
46621
46713
|
|
|
46622
|
-
// src/mcp/
|
|
46714
|
+
// src/mcp/xacpx-mcp-transport.ts
|
|
46623
46715
|
function createOrchestrationTransport(endpoint, deps = {}) {
|
|
46624
46716
|
const client = deps.client ?? new OrchestrationClient(endpoint);
|
|
46625
46717
|
return {
|
|
@@ -46647,7 +46739,7 @@ function createOrchestrationTransport(endpoint, deps = {}) {
|
|
|
46647
46739
|
workerRaiseQuestion: async (input) => {
|
|
46648
46740
|
const sourceHandle = input.sourceHandle.trim();
|
|
46649
46741
|
if (sourceHandle.length === 0) {
|
|
46650
|
-
throw new Error("worker_raise_question requires a bound sourceHandle; start mcp-stdio with --source-handle or
|
|
46742
|
+
throw new Error("worker_raise_question requires a bound sourceHandle; start mcp-stdio with --source-handle or XACPX_SOURCE_HANDLE");
|
|
46651
46743
|
}
|
|
46652
46744
|
return await client.workerRaiseQuestion({
|
|
46653
46745
|
taskId: input.taskId,
|
|
@@ -46681,11 +46773,11 @@ function createOrchestrationTransport(endpoint, deps = {}) {
|
|
|
46681
46773
|
};
|
|
46682
46774
|
}
|
|
46683
46775
|
|
|
46684
|
-
// src/mcp/
|
|
46776
|
+
// src/mcp/xacpx-mcp-server.ts
|
|
46685
46777
|
var TASK_OPTIONS_CACHE_LIMIT = 1000;
|
|
46686
46778
|
var TASKS_LIST_PAGE_SIZE = 100;
|
|
46687
46779
|
var WATCH_TASKS_CACHE_LIMIT = 256;
|
|
46688
|
-
var
|
|
46780
|
+
var XACPX_MCP_SERVER_INSTRUCTIONS = [
|
|
46689
46781
|
"Use these tools to orchestrate work across other agents under your coordinator session.",
|
|
46690
46782
|
"",
|
|
46691
46783
|
"Delegate with delegate_request (one task) or delegate_batch (several at once). Each returns a taskId and a status.",
|
|
@@ -46696,12 +46788,12 @@ var WEACPX_MCP_SERVER_INSTRUCTIONS = [
|
|
|
46696
46788
|
"worker_raise_question is worker-side only — call it from inside a delegated task when you are blocked, not from the coordinator waiting on a delegation."
|
|
46697
46789
|
].join(`
|
|
46698
46790
|
`);
|
|
46699
|
-
function
|
|
46791
|
+
function createXacpxMcpServer(options) {
|
|
46700
46792
|
let getToolState;
|
|
46701
46793
|
const taskOptionsById = new Map;
|
|
46702
46794
|
const watchTasksById = new Map;
|
|
46703
46795
|
const server = new Server({
|
|
46704
|
-
name: "
|
|
46796
|
+
name: "xacpx",
|
|
46705
46797
|
version: readVersion()
|
|
46706
46798
|
}, {
|
|
46707
46799
|
capabilities: {
|
|
@@ -46712,8 +46804,8 @@ function createWeacpxMcpServer(options) {
|
|
|
46712
46804
|
requests: { tools: { call: {} } }
|
|
46713
46805
|
}
|
|
46714
46806
|
},
|
|
46715
|
-
instructions:
|
|
46716
|
-
taskStore:
|
|
46807
|
+
instructions: XACPX_MCP_SERVER_INSTRUCTIONS,
|
|
46808
|
+
taskStore: createXacpxTaskStore(async () => await getToolState(), taskOptionsById, watchTasksById)
|
|
46717
46809
|
});
|
|
46718
46810
|
let toolState = null;
|
|
46719
46811
|
let toolStatePromise = null;
|
|
@@ -46726,7 +46818,7 @@ function createWeacpxMcpServer(options) {
|
|
|
46726
46818
|
}
|
|
46727
46819
|
toolStatePromise = resolveMcpIdentity(server, options).then((identity) => {
|
|
46728
46820
|
if (!options.transport) {
|
|
46729
|
-
throw new Error("
|
|
46821
|
+
throw new Error("xacpx MCP transport is not configured");
|
|
46730
46822
|
}
|
|
46731
46823
|
toolState = buildToolState({
|
|
46732
46824
|
transport: options.transport,
|
|
@@ -46807,7 +46899,7 @@ function createWeacpxMcpServer(options) {
|
|
|
46807
46899
|
return server;
|
|
46808
46900
|
}
|
|
46809
46901
|
function buildToolState(options) {
|
|
46810
|
-
const tools =
|
|
46902
|
+
const tools = buildXacpxMcpToolRegistry(options);
|
|
46811
46903
|
return {
|
|
46812
46904
|
tools,
|
|
46813
46905
|
toolMap: new Map(tools.map((tool) => [tool.name, tool])),
|
|
@@ -46966,10 +47058,10 @@ function renderWatchMcpTaskResult(result, watchTaskId) {
|
|
|
46966
47058
|
structuredContent: { watchTaskId, ...result }
|
|
46967
47059
|
};
|
|
46968
47060
|
}
|
|
46969
|
-
function
|
|
47061
|
+
function createXacpxTaskStore(resolveState, taskOptionsById, watchTasksById) {
|
|
46970
47062
|
return {
|
|
46971
47063
|
createTask: async () => {
|
|
46972
|
-
throw new Error("
|
|
47064
|
+
throw new Error("xacpx native MCP tasks are created by delegate_request");
|
|
46973
47065
|
},
|
|
46974
47066
|
getTask: async (taskId) => {
|
|
46975
47067
|
const watchTask = watchTasksById.get(taskId);
|
|
@@ -46980,7 +47072,7 @@ function createWeacpxTaskStore(resolveState, taskOptionsById, watchTasksById) {
|
|
|
46980
47072
|
return task ? toMcpTask(task, taskOptionsById.get(taskId)) : null;
|
|
46981
47073
|
},
|
|
46982
47074
|
storeTaskResult: async () => {
|
|
46983
|
-
throw new Error("
|
|
47075
|
+
throw new Error("xacpx native MCP task results are stored by orchestration");
|
|
46984
47076
|
},
|
|
46985
47077
|
getTaskResult: async (taskId) => {
|
|
46986
47078
|
const watchTask = watchTasksById.get(taskId);
|
|
@@ -47004,7 +47096,7 @@ function createWeacpxTaskStore(resolveState, taskOptionsById, watchTasksById) {
|
|
|
47004
47096
|
await state.transport.cancelTask({ coordinatorSession: state.coordinatorSession, taskId });
|
|
47005
47097
|
return;
|
|
47006
47098
|
}
|
|
47007
|
-
throw new Error(`
|
|
47099
|
+
throw new Error(`xacpx MCP task status is read-only (${status}${statusMessage ? `: ${statusMessage}` : ""})`);
|
|
47008
47100
|
},
|
|
47009
47101
|
listTasks: async (cursor) => {
|
|
47010
47102
|
const state = await resolveState();
|
|
@@ -47264,9 +47356,9 @@ function defaultIsProcessRunning3(pid) {
|
|
|
47264
47356
|
return code !== "ESRCH";
|
|
47265
47357
|
}
|
|
47266
47358
|
}
|
|
47267
|
-
async function
|
|
47359
|
+
async function runXacpxMcpServer(options) {
|
|
47268
47360
|
const transport = options.transport ?? createOrchestrationTransport(options.endpoint ?? resolveDefaultOrchestrationEndpoint(process.env, process.platform));
|
|
47269
|
-
const server =
|
|
47361
|
+
const server = createXacpxMcpServer({
|
|
47270
47362
|
transport,
|
|
47271
47363
|
...options.coordinatorSession ? { coordinatorSession: options.coordinatorSession } : {},
|
|
47272
47364
|
...options.sourceHandle ? { sourceHandle: options.sourceHandle } : {},
|
|
@@ -47851,6 +47943,10 @@ async function handleChannelCli(args, deps) {
|
|
|
47851
47943
|
if (args.length < 2 || !args[1])
|
|
47852
47944
|
return null;
|
|
47853
47945
|
return await dispatchSetEnabled(args[1], false, args.slice(2), deps);
|
|
47946
|
+
case "set-reply-mode":
|
|
47947
|
+
if (args.length < 3 || !args[1] || !args[2])
|
|
47948
|
+
return null;
|
|
47949
|
+
return await setChannelReplyMode(args[1], args[2], args.slice(3), deps);
|
|
47854
47950
|
default:
|
|
47855
47951
|
return null;
|
|
47856
47952
|
}
|
|
@@ -48167,6 +48263,28 @@ async function setChannelEnabled(type, enabled, rawArgs, deps) {
|
|
|
48167
48263
|
deps.print(t().channelCli.channelEnabledToggled(channel.id, enabled));
|
|
48168
48264
|
return await maybeRestartAfterMutation(restartFlags.restart, deps);
|
|
48169
48265
|
}
|
|
48266
|
+
async function setChannelReplyMode(type, mode, rawArgs, deps) {
|
|
48267
|
+
const restartFlags = parseRestartFlags(rawArgs);
|
|
48268
|
+
if (!restartFlags.ok) {
|
|
48269
|
+
deps.print(restartFlags.message);
|
|
48270
|
+
return 1;
|
|
48271
|
+
}
|
|
48272
|
+
if (mode !== "stream" && mode !== "final" && mode !== "verbose") {
|
|
48273
|
+
deps.print(t().channelCli.channelReplyModeInvalid(mode));
|
|
48274
|
+
return 1;
|
|
48275
|
+
}
|
|
48276
|
+
const config4 = await deps.loadConfig();
|
|
48277
|
+
ensureChannelsArray(config4);
|
|
48278
|
+
const channel = findChannel(config4.channels, type);
|
|
48279
|
+
if (!channel) {
|
|
48280
|
+
deps.print(t().channelCli.channelNotFound(type));
|
|
48281
|
+
return 1;
|
|
48282
|
+
}
|
|
48283
|
+
channel.replyMode = mode;
|
|
48284
|
+
await deps.saveConfig(config4);
|
|
48285
|
+
deps.print(t().channelCli.channelReplyModeSet(channel.id, mode));
|
|
48286
|
+
return await maybeRestartAfterMutation(restartFlags.restart, deps);
|
|
48287
|
+
}
|
|
48170
48288
|
function requireMultiAccountProvider(type, deps) {
|
|
48171
48289
|
const provider = getChannelCliProvider(type);
|
|
48172
48290
|
if (!provider) {
|
|
@@ -48493,7 +48611,7 @@ async function inspectPlugins(input) {
|
|
|
48493
48611
|
}
|
|
48494
48612
|
try {
|
|
48495
48613
|
const plugin = validateWeacpxPlugin(moduleValue, configPlugin.name, {
|
|
48496
|
-
...input.
|
|
48614
|
+
...input.currentXacpxVersion !== undefined ? { currentXacpxVersion: input.currentXacpxVersion } : {}
|
|
48497
48615
|
});
|
|
48498
48616
|
const channels = plugin.channels ?? [];
|
|
48499
48617
|
const channelTypes = channels.map((channel) => channel.type);
|
|
@@ -49836,7 +49954,7 @@ async function defaultMcpStdio(args, deps = {}) {
|
|
|
49836
49954
|
`);
|
|
49837
49955
|
return 2;
|
|
49838
49956
|
}
|
|
49839
|
-
await
|
|
49957
|
+
await runXacpxMcpServer({
|
|
49840
49958
|
transport,
|
|
49841
49959
|
...coordinatorSession ? { coordinatorSession } : {},
|
|
49842
49960
|
...sourceHandle ? { sourceHandle } : {},
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export declare const
|
|
2
|
-
export declare function
|
|
3
|
-
export declare function
|
|
1
|
+
export declare const XACPX_KNOWN_COMMAND_PREFIXES: readonly ["/help", "/agents", "/workspaces", "/sessions", "/tasks", "/status", "/cancel", "/stop", "/clear", "/mode", "/replymode", "/config", "/permission", "/pm", "/session", "/ss", "/ssn", "/workspace", "/ws", "/use", "/agent", "/delegate", "/dg", "/group", "/groups", "/task", "/later", "/lt"];
|
|
2
|
+
export declare function isKnownXacpxCommandPrefix(prefix: string): boolean;
|
|
3
|
+
export declare function isKnownXacpxCommandText(text: string): boolean;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AppConfig, ReplyMode } from "../../config/types";
|
|
2
|
+
/**
|
|
3
|
+
* The per-channel default reply mode declared on `channels[].replyMode`, or
|
|
4
|
+
* `undefined` when the channel does not set one (so callers fall through to the
|
|
5
|
+
* global default). The channel is derived from the chatKey the same way the rest
|
|
6
|
+
* of the system scopes sessions.
|
|
7
|
+
*/
|
|
8
|
+
export declare function resolveChannelDefaultReplyMode(config: AppConfig | undefined, chatKey: string): ReplyMode | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Effective reply mode precedence:
|
|
11
|
+
* session override → per-channel default → global channel.replyMode → "verbose".
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveEffectiveReplyMode(config: AppConfig | undefined, chatKey: string, sessionOverride: ReplyMode | undefined): ReplyMode;
|
package/dist/config/types.d.ts
CHANGED
package/dist/i18n/types.d.ts
CHANGED
|
@@ -27,10 +27,11 @@ export interface SessionMessages {
|
|
|
27
27
|
replyModeHeader: string;
|
|
28
28
|
replyModeSessionLabel: (alias: string) => string;
|
|
29
29
|
replyModeGlobalDefault: (value: string) => string;
|
|
30
|
+
replyModeChannelDefault: (value: string) => string;
|
|
30
31
|
replyModeSessionOverride: (value: string) => string;
|
|
31
32
|
replyModeEffective: (value: string) => string;
|
|
32
33
|
replyModeSet: (replyMode: string) => string;
|
|
33
|
-
replyModeReset: (
|
|
34
|
+
replyModeReset: (effective: string) => string;
|
|
34
35
|
statusHeader: string;
|
|
35
36
|
statusNameLabel: (alias: string) => string;
|
|
36
37
|
statusAgentLabel: (agent: string) => string;
|
|
@@ -503,6 +504,8 @@ export interface ConfigMessages {
|
|
|
503
504
|
mustBePositiveNumber: (path: string) => string;
|
|
504
505
|
channelTypeDisabled: string;
|
|
505
506
|
channelReplyModeInvalid: string;
|
|
507
|
+
channelRuntimeNotFound: (id: string) => string;
|
|
508
|
+
channelRuntimeReplyModeInvalid: (id: string) => string;
|
|
506
509
|
wechatReplyModeInvalid: string;
|
|
507
510
|
wechatReplyModeMapped: (value: string) => string;
|
|
508
511
|
agentNotFound: (name: string) => string;
|
|
@@ -658,6 +661,8 @@ export interface ChannelCliMessages {
|
|
|
658
661
|
channelRemoved: (id: string) => string;
|
|
659
662
|
cannotDisableLastEnabled: string;
|
|
660
663
|
channelEnabledToggled: (id: string, enabled: boolean) => string;
|
|
664
|
+
channelReplyModeSet: (id: string, mode: string) => string;
|
|
665
|
+
channelReplyModeInvalid: (mode: string) => string;
|
|
661
666
|
channelAccountAlreadyExists: (type: string, accountId: string) => string;
|
|
662
667
|
channelAccountAdded: (type: string, accountId: string) => string;
|
|
663
668
|
channelReEnabled: (type: string) => string;
|
package/dist/plugin-api.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export type { ChannelRuntimeConfig } from "./config/types.js";
|
|
|
6
6
|
export type { CommandHint } from "./commands/command-hints.js";
|
|
7
7
|
export type { AppLogger } from "./logging/app-logger.js";
|
|
8
8
|
export type { WeacpxPlugin, XacpxPlugin } from "./plugins/types.js";
|
|
9
|
-
export { WEACPX_PLUGIN_API_VERSION, WEACPX_PLUGIN_API_SUPPORTED_VERSIONS, WEACPX_PLUGIN_MIN_CORE_VERSION, } from "./plugins/types.js";
|
|
9
|
+
export { XACPX_PLUGIN_API_VERSION, XACPX_PLUGIN_API_SUPPORTED_VERSIONS, XACPX_PLUGIN_MIN_CORE_VERSION, WEACPX_PLUGIN_API_VERSION, WEACPX_PLUGIN_API_SUPPORTED_VERSIONS, WEACPX_PLUGIN_MIN_CORE_VERSION, } from "./plugins/types.js";
|
|
10
10
|
export { createConversationExecutor } from "./runtime/conversation-executor.js";
|
|
11
11
|
export type { ConversationExecutor, ConversationExecutorLane } from "./runtime/conversation-executor.js";
|
|
12
12
|
export { resolveTurnLane } from "./runtime/turn-lane.js";
|
package/dist/plugin-api.js
CHANGED
|
@@ -88,10 +88,11 @@ var init_session = __esm(() => {
|
|
|
88
88
|
replyModeHeader: "Current reply mode:",
|
|
89
89
|
replyModeSessionLabel: (alias) => `- Session: ${alias}`,
|
|
90
90
|
replyModeGlobalDefault: (value) => `- Global default: ${value}`,
|
|
91
|
+
replyModeChannelDefault: (value) => `- Channel default: ${value}`,
|
|
91
92
|
replyModeSessionOverride: (value) => `- Session override: ${value}`,
|
|
92
93
|
replyModeEffective: (value) => `- Effective: ${value}`,
|
|
93
94
|
replyModeSet: (replyMode) => `Current session reply mode set to: ${replyMode}`,
|
|
94
|
-
replyModeReset: (
|
|
95
|
+
replyModeReset: (effective) => `Session reply mode reset. Now effective: ${effective}`,
|
|
95
96
|
statusHeader: "Current session:",
|
|
96
97
|
statusNameLabel: (alias) => `- Name: ${alias}`,
|
|
97
98
|
statusAgentLabel: (agent) => `- Agent: ${agent}`,
|
|
@@ -634,6 +635,8 @@ var init_config = __esm(() => {
|
|
|
634
635
|
mustBePositiveNumber: (path) => `${path} must be a positive number.`,
|
|
635
636
|
channelTypeDisabled: "channel.type is a legacy single-channel field; /config set writes are disabled. Use `xacpx channel ...` to manage channels[], then restart xacpx.",
|
|
636
637
|
channelReplyModeInvalid: "channel.replyMode only supports: stream, final, verbose",
|
|
638
|
+
channelRuntimeNotFound: (id) => `Channel "${id}" does not exist; add it first with \`xacpx channel add ${id}\`.`,
|
|
639
|
+
channelRuntimeReplyModeInvalid: (id) => `channels.${id}.replyMode only supports: stream, final, verbose`,
|
|
637
640
|
wechatReplyModeInvalid: "wechat.replyMode only supports: stream, final, verbose",
|
|
638
641
|
wechatReplyModeMapped: (value) => `${value} (mapped to channel.replyMode)`,
|
|
639
642
|
agentNotFound: (name) => `Agent "${name}" does not exist. Create it first.`,
|
|
@@ -854,6 +857,8 @@ var init_channel_cli = __esm(() => {
|
|
|
854
857
|
channelRemoved: (id) => `Channel ${id} removed`,
|
|
855
858
|
cannotDisableLastEnabled: "Cannot disable the last enabled channel.",
|
|
856
859
|
channelEnabledToggled: (id, enabled) => `Channel ${id} ${enabled ? "enabled" : "disabled"}`,
|
|
860
|
+
channelReplyModeSet: (id, mode) => `Channel ${id} default reply mode set to: ${mode}`,
|
|
861
|
+
channelReplyModeInvalid: (mode) => `reply mode must be stream / final / verbose, got: ${mode}`,
|
|
857
862
|
channelAccountAlreadyExists: (type, accountId) => `Account ${accountId} already exists on channel ${type}; run xacpx channel rm ${type} --account ${accountId} first`,
|
|
858
863
|
channelAccountAdded: (type, accountId) => `Channel ${type} account ${accountId} added`,
|
|
859
864
|
channelReEnabled: (type) => `Channel ${type} was disabled; it has been automatically re-enabled.`,
|
|
@@ -1154,10 +1159,11 @@ var init_session2 = __esm(() => {
|
|
|
1154
1159
|
replyModeHeader: "当前 reply mode:",
|
|
1155
1160
|
replyModeSessionLabel: (alias) => `- 会话:${alias}`,
|
|
1156
1161
|
replyModeGlobalDefault: (value) => `- 全局默认:${value}`,
|
|
1162
|
+
replyModeChannelDefault: (value) => `- 频道默认:${value}`,
|
|
1157
1163
|
replyModeSessionOverride: (value) => `- 当前会话覆盖:${value}`,
|
|
1158
1164
|
replyModeEffective: (value) => `- 当前生效:${value}`,
|
|
1159
1165
|
replyModeSet: (replyMode) => `已设置当前会话 reply mode:${replyMode}`,
|
|
1160
|
-
replyModeReset: (
|
|
1166
|
+
replyModeReset: (effective) => `已重置当前会话 reply mode,当前生效:${effective}`,
|
|
1161
1167
|
statusHeader: "当前会话:",
|
|
1162
1168
|
statusNameLabel: (alias) => `- 名称:${alias}`,
|
|
1163
1169
|
statusAgentLabel: (agent2) => `- Agent:${agent2}`,
|
|
@@ -1700,6 +1706,8 @@ var init_config2 = __esm(() => {
|
|
|
1700
1706
|
mustBePositiveNumber: (path) => `${path} 必须是正数。`,
|
|
1701
1707
|
channelTypeDisabled: "channel.type 是旧单频道字段,/config set 已禁用写入;请使用 `xacpx channel ...` 管理 channels[],然后重启 xacpx。",
|
|
1702
1708
|
channelReplyModeInvalid: "channel.replyMode 只支持:stream、final、verbose",
|
|
1709
|
+
channelRuntimeNotFound: (id) => `频道「${id}」不存在;请先用 \`xacpx channel add ${id}\` 添加。`,
|
|
1710
|
+
channelRuntimeReplyModeInvalid: (id) => `channels.${id}.replyMode 只支持:stream、final、verbose`,
|
|
1703
1711
|
wechatReplyModeInvalid: "wechat.replyMode 只支持:stream、final、verbose",
|
|
1704
1712
|
wechatReplyModeMapped: (value) => `${value}(已映射到 channel.replyMode)`,
|
|
1705
1713
|
agentNotFound: (name) => `Agent「${name}」不存在,请先创建。`,
|
|
@@ -1920,6 +1928,8 @@ var init_channel_cli2 = __esm(() => {
|
|
|
1920
1928
|
channelRemoved: (id) => `频道 ${id} 已删除`,
|
|
1921
1929
|
cannotDisableLastEnabled: "不能禁用最后一个启用的频道。",
|
|
1922
1930
|
channelEnabledToggled: (id, enabled) => `频道 ${id} 已${enabled ? "启用" : "禁用"}`,
|
|
1931
|
+
channelReplyModeSet: (id, mode) => `频道 ${id} 的默认 reply mode 已设置为:${mode}`,
|
|
1932
|
+
channelReplyModeInvalid: (mode) => `reply mode 只支持 stream / final / verbose,收到:${mode}`,
|
|
1923
1933
|
channelAccountAlreadyExists: (type, accountId) => `频道 ${type} 的账号 ${accountId} 已存在;先 xacpx channel rm ${type} --account ${accountId}`,
|
|
1924
1934
|
channelAccountAdded: (type, accountId) => `频道 ${type} 账号 ${accountId} 已添加`,
|
|
1925
1935
|
channelReEnabled: (type) => `频道 ${type} 此前是 disabled 状态,已自动启用。`,
|
|
@@ -2295,19 +2305,19 @@ function cmpTuple(a, b) {
|
|
|
2295
2305
|
return 0;
|
|
2296
2306
|
}
|
|
2297
2307
|
function validatePluginCompatibility(metadata, context) {
|
|
2298
|
-
const { packageName,
|
|
2308
|
+
const { packageName, currentXacpxVersion } = context;
|
|
2299
2309
|
const apiVersion = metadata.apiVersion;
|
|
2300
2310
|
if (typeof apiVersion !== "number") {
|
|
2301
2311
|
throw new Error(t().pluginCli.compatMissingApiVersion(packageName));
|
|
2302
2312
|
}
|
|
2303
|
-
if (!
|
|
2304
|
-
const supported =
|
|
2313
|
+
if (!XACPX_PLUGIN_API_SUPPORTED_VERSIONS.includes(apiVersion)) {
|
|
2314
|
+
const supported = XACPX_PLUGIN_API_SUPPORTED_VERSIONS.join(", ");
|
|
2305
2315
|
throw new Error(t().pluginCli.compatUnsupportedApiVersion(packageName, apiVersion, supported));
|
|
2306
2316
|
}
|
|
2307
|
-
if (!
|
|
2317
|
+
if (!currentXacpxVersion || currentXacpxVersion === "unknown") {
|
|
2308
2318
|
return;
|
|
2309
2319
|
}
|
|
2310
|
-
const normalizedCurrent = normalizeCoreVersionForCompat(
|
|
2320
|
+
const normalizedCurrent = normalizeCoreVersionForCompat(currentXacpxVersion);
|
|
2311
2321
|
const minVersion = metadata.minXacpxVersion ?? metadata.minWeacpxVersion;
|
|
2312
2322
|
const minVersionField = metadata.minXacpxVersion !== undefined ? "minXacpxVersion" : "minWeacpxVersion";
|
|
2313
2323
|
if (minVersion !== undefined) {
|
|
@@ -2322,7 +2332,7 @@ function validatePluginCompatibility(metadata, context) {
|
|
|
2322
2332
|
throw new Error(t().pluginCli.compatInvalidMinVersionDetail(packageName, minVersionField, detail));
|
|
2323
2333
|
}
|
|
2324
2334
|
if (!satisfied) {
|
|
2325
|
-
throw new Error(t().pluginCli.compatMinVersionNotSatisfied(packageName, minVersion,
|
|
2335
|
+
throw new Error(t().pluginCli.compatMinVersionNotSatisfied(packageName, minVersion, currentXacpxVersion));
|
|
2326
2336
|
}
|
|
2327
2337
|
}
|
|
2328
2338
|
const compatibleVersions = metadata.compatibleXacpxVersions ?? metadata.compatibleWeacpxVersions;
|
|
@@ -2339,14 +2349,17 @@ function validatePluginCompatibility(metadata, context) {
|
|
|
2339
2349
|
throw new Error(t().pluginCli.compatInvalidCompatibleVersionsDetail(packageName, compatibleField, detail));
|
|
2340
2350
|
}
|
|
2341
2351
|
if (!satisfied) {
|
|
2342
|
-
throw new Error(t().pluginCli.compatCompatibleVersionsNotSatisfied(packageName, compatibleVersions,
|
|
2352
|
+
throw new Error(t().pluginCli.compatCompatibleVersionsNotSatisfied(packageName, compatibleVersions, currentXacpxVersion));
|
|
2343
2353
|
}
|
|
2344
2354
|
}
|
|
2345
2355
|
}
|
|
2346
|
-
var
|
|
2356
|
+
var XACPX_PLUGIN_API_VERSION = 1, XACPX_PLUGIN_API_SUPPORTED_VERSIONS, XACPX_PLUGIN_MIN_CORE_VERSION = "0.5.0", WEACPX_PLUGIN_API_VERSION, WEACPX_PLUGIN_API_SUPPORTED_VERSIONS, WEACPX_PLUGIN_MIN_CORE_VERSION, SEMVER_RE;
|
|
2347
2357
|
var init_compatibility = __esm(() => {
|
|
2348
2358
|
init_i18n();
|
|
2349
|
-
|
|
2359
|
+
XACPX_PLUGIN_API_SUPPORTED_VERSIONS = [1];
|
|
2360
|
+
WEACPX_PLUGIN_API_VERSION = XACPX_PLUGIN_API_VERSION;
|
|
2361
|
+
WEACPX_PLUGIN_API_SUPPORTED_VERSIONS = XACPX_PLUGIN_API_SUPPORTED_VERSIONS;
|
|
2362
|
+
WEACPX_PLUGIN_MIN_CORE_VERSION = XACPX_PLUGIN_MIN_CORE_VERSION;
|
|
2350
2363
|
SEMVER_RE = /^(\d+)\.(\d+)\.(\d+)$/;
|
|
2351
2364
|
});
|
|
2352
2365
|
|
|
@@ -2517,6 +2530,9 @@ export {
|
|
|
2517
2530
|
getLocale,
|
|
2518
2531
|
createConversationExecutor,
|
|
2519
2532
|
createActiveTurnRegistry,
|
|
2533
|
+
XACPX_PLUGIN_MIN_CORE_VERSION,
|
|
2534
|
+
XACPX_PLUGIN_API_VERSION,
|
|
2535
|
+
XACPX_PLUGIN_API_SUPPORTED_VERSIONS,
|
|
2520
2536
|
WEACPX_PLUGIN_MIN_CORE_VERSION,
|
|
2521
2537
|
WEACPX_PLUGIN_API_VERSION,
|
|
2522
2538
|
WEACPX_PLUGIN_API_SUPPORTED_VERSIONS
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
export declare const XACPX_PLUGIN_API_VERSION: 1;
|
|
2
|
+
export declare const XACPX_PLUGIN_API_SUPPORTED_VERSIONS: readonly number[];
|
|
3
|
+
export declare const XACPX_PLUGIN_MIN_CORE_VERSION: "0.5.0";
|
|
1
4
|
export declare const WEACPX_PLUGIN_API_VERSION: 1;
|
|
2
5
|
export declare const WEACPX_PLUGIN_API_SUPPORTED_VERSIONS: readonly number[];
|
|
3
6
|
export declare const WEACPX_PLUGIN_MIN_CORE_VERSION: "0.5.0";
|
|
@@ -13,6 +16,6 @@ export interface PluginCompatibilityMetadata {
|
|
|
13
16
|
}
|
|
14
17
|
export interface PluginCompatibilityContext {
|
|
15
18
|
packageName: string;
|
|
16
|
-
|
|
19
|
+
currentXacpxVersion: string;
|
|
17
20
|
}
|
|
18
21
|
export declare function validatePluginCompatibility(metadata: PluginCompatibilityMetadata, context: PluginCompatibilityContext): void;
|
package/dist/plugins/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ChannelPluginDefinition } from "../channels/plugin.js";
|
|
2
|
-
import { WEACPX_PLUGIN_API_VERSION, WEACPX_PLUGIN_API_SUPPORTED_VERSIONS, WEACPX_PLUGIN_MIN_CORE_VERSION } from "./compatibility.js";
|
|
3
|
-
export { WEACPX_PLUGIN_API_VERSION, WEACPX_PLUGIN_API_SUPPORTED_VERSIONS, WEACPX_PLUGIN_MIN_CORE_VERSION, };
|
|
2
|
+
import { XACPX_PLUGIN_API_VERSION, XACPX_PLUGIN_API_SUPPORTED_VERSIONS, XACPX_PLUGIN_MIN_CORE_VERSION, WEACPX_PLUGIN_API_VERSION, WEACPX_PLUGIN_API_SUPPORTED_VERSIONS, WEACPX_PLUGIN_MIN_CORE_VERSION } from "./compatibility.js";
|
|
3
|
+
export { XACPX_PLUGIN_API_VERSION, XACPX_PLUGIN_API_SUPPORTED_VERSIONS, XACPX_PLUGIN_MIN_CORE_VERSION, WEACPX_PLUGIN_API_VERSION, WEACPX_PLUGIN_API_SUPPORTED_VERSIONS, WEACPX_PLUGIN_MIN_CORE_VERSION, };
|
|
4
4
|
export interface WeacpxPlugin {
|
|
5
5
|
apiVersion: 1;
|
|
6
6
|
name?: string;
|
package/dist/state/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type OrchestrationState } from "../orchestration/orchestration-types";
|
|
2
2
|
import type { ScheduledTaskRecord } from "../scheduled/scheduled-types";
|
|
3
|
-
export type LogicalSessionSource = "
|
|
3
|
+
export type LogicalSessionSource = "xacpx" | "agent-side";
|
|
4
4
|
export interface NativeSessionCacheEntry {
|
|
5
5
|
session_id: string;
|
|
6
6
|
cwd?: string;
|
|
@@ -24,7 +24,7 @@ export interface ResolvedSession {
|
|
|
24
24
|
agentCommand?: string;
|
|
25
25
|
workspace: string;
|
|
26
26
|
transportSession: string;
|
|
27
|
-
source?: "
|
|
27
|
+
source?: "xacpx" | "agent-side";
|
|
28
28
|
agentSessionId?: string;
|
|
29
29
|
agentSessionTitle?: string;
|
|
30
30
|
agentSessionUpdatedAt?: string;
|
|
@@ -124,6 +124,14 @@ export interface SessionTransport {
|
|
|
124
124
|
listAgentSessions?(query: AgentSessionListQuery): Promise<AgentSessionListResult | undefined>;
|
|
125
125
|
resumeAgentSession?(session: ResolvedSession, agentSessionId: string): Promise<void>;
|
|
126
126
|
removeSession?(session: ResolvedSession): Promise<void>;
|
|
127
|
+
/**
|
|
128
|
+
* Read the underlying agent-native session id for an existing transport
|
|
129
|
+
* session. Used by `/clear` to keep a native session native: the fresh
|
|
130
|
+
* post-clear session is itself backed by a new agent rollout, and this
|
|
131
|
+
* returns that rollout's resumable id. Returns undefined when the agent did
|
|
132
|
+
* not advertise one. Optional: transports that can't resolve it omit it.
|
|
133
|
+
*/
|
|
134
|
+
getAgentSessionId?(session: ResolvedSession): Promise<string | undefined>;
|
|
127
135
|
updatePermissionPolicy?(policy: PermissionPolicy): Promise<void>;
|
|
128
136
|
dispose?(): Promise<void>;
|
|
129
137
|
}
|
package/dist/version.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export declare function readVersion(moduleUrl?: string): string;
|
|
2
|
-
/**
|
|
3
|
-
export declare const
|
|
2
|
+
/** xacpx 核心版本,派生自 package.json(经 readVersion 动态读取,无硬编码漂移)。 */
|
|
3
|
+
export declare const XACPX_CORE_VERSION: string;
|
|
@@ -62,7 +62,7 @@ export interface ChatRequestMetadata {
|
|
|
62
62
|
senderName?: string;
|
|
63
63
|
groupId?: string;
|
|
64
64
|
isOwner?: boolean;
|
|
65
|
-
/** Internal
|
|
65
|
+
/** Internal xacpx session alias to use for non-interactive scheduled prompts. */
|
|
66
66
|
scheduledSessionAlias?: string;
|
|
67
67
|
/** Transient session descriptor for temp-mode scheduled prompts (no persisted alias). */
|
|
68
68
|
scheduledSessionDescriptor?: ScheduledSessionDescriptor;
|