weacpx 0.5.2 → 0.6.0
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 +15 -3
- package/dist/bridge/bridge-main.js +121 -1
- package/dist/channels/channel-scope.d.ts +8 -0
- package/dist/channels/types.d.ts +6 -0
- package/dist/channels/weixin-channel.d.ts +1 -0
- package/dist/cli.js +871 -45
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -9759,6 +9759,7 @@ function createEmptyState() {
|
|
|
9759
9759
|
return {
|
|
9760
9760
|
sessions: {},
|
|
9761
9761
|
chat_contexts: {},
|
|
9762
|
+
native_session_lists: {},
|
|
9762
9763
|
orchestration: createEmptyOrchestrationState(),
|
|
9763
9764
|
scheduled_tasks: {}
|
|
9764
9765
|
};
|
|
@@ -9977,11 +9978,14 @@ function parseOrchestrationState(raw, path3) {
|
|
|
9977
9978
|
function isReplyMode2(value) {
|
|
9978
9979
|
return value === "stream" || value === "final" || value === "verbose";
|
|
9979
9980
|
}
|
|
9981
|
+
function isSessionSource(value) {
|
|
9982
|
+
return value === undefined || value === "weacpx" || value === "agent-side";
|
|
9983
|
+
}
|
|
9980
9984
|
function isSessionRecord(value) {
|
|
9981
9985
|
if (!isRecord2(value)) {
|
|
9982
9986
|
return false;
|
|
9983
9987
|
}
|
|
9984
|
-
return isString(value.alias) && isString(value.agent) && isString(value.workspace) && isString(value.transport_session) && isOptionalString(value.transport_agent_command) && isOptionalString(value.mode_id) && (value.reply_mode === undefined || isReplyMode2(value.reply_mode)) && isString(value.created_at) && isString(value.last_used_at);
|
|
9988
|
+
return isString(value.alias) && isString(value.agent) && isString(value.workspace) && isString(value.transport_session) && isSessionSource(value.source) && isOptionalString(value.agent_session_id) && isOptionalString(value.agent_session_title) && isOptionalString(value.agent_session_updated_at) && isOptionalString(value.attached_at) && isOptionalString(value.transport_agent_command) && isOptionalString(value.mode_id) && (value.reply_mode === undefined || isReplyMode2(value.reply_mode)) && isString(value.created_at) && isString(value.last_used_at);
|
|
9985
9989
|
}
|
|
9986
9990
|
function parseSessions(raw, path3) {
|
|
9987
9991
|
const sessions = {};
|
|
@@ -10006,6 +10010,30 @@ function parseChatContexts(raw, path3) {
|
|
|
10006
10010
|
}
|
|
10007
10011
|
return chatContexts;
|
|
10008
10012
|
}
|
|
10013
|
+
function isNativeSessionCacheEntry(value) {
|
|
10014
|
+
if (!isRecord2(value)) {
|
|
10015
|
+
return false;
|
|
10016
|
+
}
|
|
10017
|
+
return isString(value.session_id) && isOptionalString(value.cwd) && (value.title === undefined || value.title === null || isString(value.title)) && isOptionalString(value.updated_at);
|
|
10018
|
+
}
|
|
10019
|
+
function isNativeSessionListCacheRecord(value) {
|
|
10020
|
+
if (!isRecord2(value)) {
|
|
10021
|
+
return false;
|
|
10022
|
+
}
|
|
10023
|
+
return isString(value.created_at) && isString(value.agent) && isOptionalString(value.workspace) && isString(value.cwd) && Array.isArray(value.sessions) && value.sessions.every(isNativeSessionCacheEntry) && (value.next_cursor === undefined || value.next_cursor === null || isString(value.next_cursor));
|
|
10024
|
+
}
|
|
10025
|
+
function parseNativeSessionLists(raw) {
|
|
10026
|
+
if (!isRecord2(raw)) {
|
|
10027
|
+
return {};
|
|
10028
|
+
}
|
|
10029
|
+
const nativeSessionLists = {};
|
|
10030
|
+
for (const [chatKey, value] of Object.entries(raw)) {
|
|
10031
|
+
if (isNativeSessionListCacheRecord(value)) {
|
|
10032
|
+
nativeSessionLists[chatKey] = value;
|
|
10033
|
+
}
|
|
10034
|
+
}
|
|
10035
|
+
return nativeSessionLists;
|
|
10036
|
+
}
|
|
10009
10037
|
function isScheduledTaskStatus(value) {
|
|
10010
10038
|
return value === "pending" || value === "triggering" || value === "executed" || value === "cancelled" || value === "missed" || value === "failed";
|
|
10011
10039
|
}
|
|
@@ -10050,6 +10078,7 @@ function parseState(raw, path3) {
|
|
|
10050
10078
|
return {
|
|
10051
10079
|
sessions: parsedSessions,
|
|
10052
10080
|
chat_contexts: parseChatContexts(chatContexts, path3),
|
|
10081
|
+
native_session_lists: parseNativeSessionLists(raw.native_session_lists),
|
|
10053
10082
|
orchestration,
|
|
10054
10083
|
scheduled_tasks: parseScheduledTasks(raw.scheduled_tasks, path3)
|
|
10055
10084
|
};
|
|
@@ -10167,6 +10196,13 @@ function resolveSessionAliasForInput(channelId, displayAlias, existingAliases) {
|
|
|
10167
10196
|
}
|
|
10168
10197
|
return scopedAlias;
|
|
10169
10198
|
}
|
|
10199
|
+
function scopeDisplayAliasToInternal(channelId, displayAlias) {
|
|
10200
|
+
const normalized = displayAlias.trim();
|
|
10201
|
+
if (normalized.length === 0) {
|
|
10202
|
+
throw new Error("display session alias must be non-empty");
|
|
10203
|
+
}
|
|
10204
|
+
return channelId === "weixin" ? normalized : toInternalSessionAlias(channelId, normalized);
|
|
10205
|
+
}
|
|
10170
10206
|
function buildDefaultTransportSession(channelId, displayAlias) {
|
|
10171
10207
|
const normalized = displayAlias.trim();
|
|
10172
10208
|
if (normalized.length === 0) {
|
|
@@ -16110,6 +16146,7 @@ var init_consumer_lock = __esm(() => {
|
|
|
16110
16146
|
// src/channels/weixin-channel.ts
|
|
16111
16147
|
class WeixinChannel {
|
|
16112
16148
|
id = "weixin";
|
|
16149
|
+
nativeSessionListFormat = "cards";
|
|
16113
16150
|
agent = null;
|
|
16114
16151
|
quota = null;
|
|
16115
16152
|
logger = null;
|
|
@@ -16917,6 +16954,7 @@ var init_command_list = __esm(() => {
|
|
|
16917
16954
|
"/pm",
|
|
16918
16955
|
"/session",
|
|
16919
16956
|
"/ss",
|
|
16957
|
+
"/ssn",
|
|
16920
16958
|
"/workspace",
|
|
16921
16959
|
"/ws",
|
|
16922
16960
|
"/use",
|
|
@@ -16999,6 +17037,51 @@ function parseCommand(input) {
|
|
|
16999
17037
|
if (command === "/session" && parts[1] === "rm" && parts[2] && parts.length === 3) {
|
|
17000
17038
|
return { kind: "session.rm", alias: parts[2] };
|
|
17001
17039
|
}
|
|
17040
|
+
if (command === "/ssn") {
|
|
17041
|
+
if (parts.length === 1) {
|
|
17042
|
+
return { kind: "session.native.list" };
|
|
17043
|
+
}
|
|
17044
|
+
const identifier = parts[1] ?? "";
|
|
17045
|
+
if (/^\d+$/.test(identifier)) {
|
|
17046
|
+
const selected = readNativeAttachCommand(parts, 1);
|
|
17047
|
+
if (!selected) {
|
|
17048
|
+
return { kind: "invalid", text: trimmed, recognizedCommand: "/ssn" };
|
|
17049
|
+
}
|
|
17050
|
+
return selected.alias ? { kind: "session.native.select", identifier, alias: selected.alias } : { kind: "session.native.select", identifier };
|
|
17051
|
+
}
|
|
17052
|
+
if (parts[1] === "attach") {
|
|
17053
|
+
if (!parts[2]) {
|
|
17054
|
+
return { kind: "invalid", text: trimmed, recognizedCommand: "/ssn" };
|
|
17055
|
+
}
|
|
17056
|
+
const attached = readNativeAttachCommand(parts, 2);
|
|
17057
|
+
if (attached) {
|
|
17058
|
+
return attached;
|
|
17059
|
+
}
|
|
17060
|
+
return { kind: "invalid", text: trimmed, recognizedCommand: "/ssn" };
|
|
17061
|
+
}
|
|
17062
|
+
const nativeList = readNativeListCommand(parts, 1);
|
|
17063
|
+
if (nativeList) {
|
|
17064
|
+
return nativeList;
|
|
17065
|
+
}
|
|
17066
|
+
return { kind: "invalid", text: trimmed, recognizedCommand: "/ssn" };
|
|
17067
|
+
}
|
|
17068
|
+
if (command === "/session" && parts[1] === "native") {
|
|
17069
|
+
const nativeList = readNativeListCommand(parts, 2);
|
|
17070
|
+
if (nativeList) {
|
|
17071
|
+
return nativeList;
|
|
17072
|
+
}
|
|
17073
|
+
return { kind: "invalid", text: trimmed, recognizedCommand: "/session" };
|
|
17074
|
+
}
|
|
17075
|
+
if (command === "/session" && parts[1] === "attach" && parts[2] === "native") {
|
|
17076
|
+
if (!parts[3]) {
|
|
17077
|
+
return { kind: "invalid", text: trimmed, recognizedCommand: "/session" };
|
|
17078
|
+
}
|
|
17079
|
+
const attached = readNativeAttachCommand(parts, 3);
|
|
17080
|
+
if (attached) {
|
|
17081
|
+
return attached;
|
|
17082
|
+
}
|
|
17083
|
+
return { kind: "invalid", text: trimmed, recognizedCommand: "/session" };
|
|
17084
|
+
}
|
|
17002
17085
|
if (command === "/group" && parts[1] === "new" && parts.length > 2) {
|
|
17003
17086
|
const title = parts.slice(2).join(" ");
|
|
17004
17087
|
if (title.trim().length > 0) {
|
|
@@ -17264,6 +17347,97 @@ function readSessionShortcutTarget(parts, startIndex) {
|
|
|
17264
17347
|
}
|
|
17265
17348
|
return null;
|
|
17266
17349
|
}
|
|
17350
|
+
function readNativeListCommand(parts, startIndex) {
|
|
17351
|
+
let agent = "";
|
|
17352
|
+
let cwd = "";
|
|
17353
|
+
let workspace = "";
|
|
17354
|
+
let all = false;
|
|
17355
|
+
let cursor = "";
|
|
17356
|
+
let invalid = false;
|
|
17357
|
+
if (startIndex < parts.length && !parts[startIndex]?.startsWith("-")) {
|
|
17358
|
+
agent = parts[startIndex] ?? "";
|
|
17359
|
+
startIndex += 1;
|
|
17360
|
+
}
|
|
17361
|
+
for (let index = startIndex;index < parts.length; index += 1) {
|
|
17362
|
+
const part = parts[index];
|
|
17363
|
+
if (part === "--all") {
|
|
17364
|
+
all = true;
|
|
17365
|
+
continue;
|
|
17366
|
+
}
|
|
17367
|
+
if (part === "--cursor") {
|
|
17368
|
+
const value = parts[index + 1] ?? "";
|
|
17369
|
+
if (index + 1 >= parts.length || value.startsWith("-")) {
|
|
17370
|
+
invalid = true;
|
|
17371
|
+
break;
|
|
17372
|
+
}
|
|
17373
|
+
cursor = value;
|
|
17374
|
+
index += 1;
|
|
17375
|
+
continue;
|
|
17376
|
+
}
|
|
17377
|
+
if (part === "--cwd" || part === "-d") {
|
|
17378
|
+
const value = parts[index + 1] ?? "";
|
|
17379
|
+
if (index + 1 >= parts.length || value.startsWith("-") || workspace) {
|
|
17380
|
+
invalid = true;
|
|
17381
|
+
break;
|
|
17382
|
+
}
|
|
17383
|
+
cwd = value;
|
|
17384
|
+
index += 1;
|
|
17385
|
+
continue;
|
|
17386
|
+
}
|
|
17387
|
+
if (part === "--ws" || part === "-ws") {
|
|
17388
|
+
const value = parts[index + 1] ?? "";
|
|
17389
|
+
if (index + 1 >= parts.length || value.startsWith("-") || cwd) {
|
|
17390
|
+
invalid = true;
|
|
17391
|
+
break;
|
|
17392
|
+
}
|
|
17393
|
+
workspace = value;
|
|
17394
|
+
index += 1;
|
|
17395
|
+
continue;
|
|
17396
|
+
}
|
|
17397
|
+
invalid = true;
|
|
17398
|
+
break;
|
|
17399
|
+
}
|
|
17400
|
+
if (invalid) {
|
|
17401
|
+
return null;
|
|
17402
|
+
}
|
|
17403
|
+
const result = {
|
|
17404
|
+
kind: "session.native.list"
|
|
17405
|
+
};
|
|
17406
|
+
if (agent.trim().length > 0)
|
|
17407
|
+
result.agent = agent;
|
|
17408
|
+
if (cwd.trim().length > 0)
|
|
17409
|
+
result.cwd = cwd;
|
|
17410
|
+
if (workspace.trim().length > 0)
|
|
17411
|
+
result.workspace = workspace;
|
|
17412
|
+
if (all)
|
|
17413
|
+
result.all = true;
|
|
17414
|
+
if (cursor.trim().length > 0)
|
|
17415
|
+
result.cursor = cursor;
|
|
17416
|
+
return Object.keys(result).length > 1 ? result : { kind: "session.native.list" };
|
|
17417
|
+
}
|
|
17418
|
+
function readNativeAttachCommand(parts, identifierIndex) {
|
|
17419
|
+
const identifier = parts[identifierIndex] ?? "";
|
|
17420
|
+
let alias = "";
|
|
17421
|
+
for (let index = identifierIndex + 1;index < parts.length; index += 1) {
|
|
17422
|
+
if (parts[index] === "-a" || parts[index] === "--alias") {
|
|
17423
|
+
const value = parts[index + 1] ?? "";
|
|
17424
|
+
if (index + 1 >= parts.length || value.startsWith("-")) {
|
|
17425
|
+
return null;
|
|
17426
|
+
}
|
|
17427
|
+
alias = value;
|
|
17428
|
+
index += 1;
|
|
17429
|
+
continue;
|
|
17430
|
+
}
|
|
17431
|
+
return null;
|
|
17432
|
+
}
|
|
17433
|
+
if (identifier.trim().length === 0 || identifier.startsWith("-")) {
|
|
17434
|
+
return null;
|
|
17435
|
+
}
|
|
17436
|
+
if (alias.trim().length > 0) {
|
|
17437
|
+
return { kind: "session.native.attach", identifier, alias };
|
|
17438
|
+
}
|
|
17439
|
+
return { kind: "session.native.attach", identifier };
|
|
17440
|
+
}
|
|
17267
17441
|
function normalizeCommand(command) {
|
|
17268
17442
|
if (command === "/ss")
|
|
17269
17443
|
return "/session";
|
|
@@ -17501,6 +17675,9 @@ var init_command_policy = __esm(() => {
|
|
|
17501
17675
|
"session.shortcut": "/session",
|
|
17502
17676
|
"session.shortcut.new": "/session",
|
|
17503
17677
|
"session.attach": "/session attach",
|
|
17678
|
+
"session.native.list": "/ssn",
|
|
17679
|
+
"session.native.select": "/ssn",
|
|
17680
|
+
"session.native.attach": "/ssn attach",
|
|
17504
17681
|
"later.create": "/later",
|
|
17505
17682
|
"later.list": "/later list",
|
|
17506
17683
|
"later.cancel": "/later cancel"
|
|
@@ -18161,7 +18338,7 @@ async function handleSessions(context, chatKey) {
|
|
|
18161
18338
|
}
|
|
18162
18339
|
async function handleSessionNew(context, chatKey, alias, agent, workspace) {
|
|
18163
18340
|
const channelId = getChannelIdFromChatKey(chatKey);
|
|
18164
|
-
const internalAlias =
|
|
18341
|
+
const internalAlias = scopeDisplayAliasToInternal(channelId, alias);
|
|
18165
18342
|
const session = context.lifecycle.resolveSession(internalAlias, agent, workspace, `${workspace}:${internalAlias}`);
|
|
18166
18343
|
const releaseTransportReservation = await context.lifecycle.reserveTransportSession(session.transportSession);
|
|
18167
18344
|
try {
|
|
@@ -18192,7 +18369,7 @@ async function handleSessionShortcut(context, chatKey, agent, target, createNew)
|
|
|
18192
18369
|
}
|
|
18193
18370
|
async function handleSessionAttach(context, chatKey, alias, agent, workspace, transportSession) {
|
|
18194
18371
|
const channelId = getChannelIdFromChatKey(chatKey);
|
|
18195
|
-
const internalAlias =
|
|
18372
|
+
const internalAlias = scopeDisplayAliasToInternal(channelId, alias);
|
|
18196
18373
|
const attached = context.lifecycle.resolveSession(internalAlias, agent, workspace, transportSession);
|
|
18197
18374
|
const releaseTransportReservation = await context.lifecycle.reserveTransportSession(attached.transportSession);
|
|
18198
18375
|
try {
|
|
@@ -18559,7 +18736,7 @@ async function markCoordinatorResultsInjectionFailed(context, taskIds, groupIds,
|
|
|
18559
18736
|
});
|
|
18560
18737
|
}
|
|
18561
18738
|
}
|
|
18562
|
-
var NO_CURRENT_SESSION_TEXT = "当前还没有选中的会话。请先执行 /session new ... 或 /use <alias>。", DEFAULT_SESSION_TAIL_LINES = 50, MAX_SESSION_TAIL_LINES = 500, sessionHelp, modeHelp, replyModeHelp, statusHelp, cancelHelp;
|
|
18739
|
+
var NO_CURRENT_SESSION_TEXT = "当前还没有选中的会话。请先执行 /session new ... 或 /use <alias>。", DEFAULT_SESSION_TAIL_LINES = 50, MAX_SESSION_TAIL_LINES = 500, sessionHelp, nativeSessionHelp, modeHelp, replyModeHelp, statusHelp, cancelHelp;
|
|
18563
18740
|
var init_session_handler = __esm(() => {
|
|
18564
18741
|
init_build_coordinator_prompt();
|
|
18565
18742
|
init_channel_scope();
|
|
@@ -18567,7 +18744,7 @@ var init_session_handler = __esm(() => {
|
|
|
18567
18744
|
sessionHelp = {
|
|
18568
18745
|
topic: "session",
|
|
18569
18746
|
aliases: ["ss", "sessions"],
|
|
18570
|
-
summary: "
|
|
18747
|
+
summary: "创建、复用、切换和重置 weacpx 逻辑会话。",
|
|
18571
18748
|
commands: [
|
|
18572
18749
|
{ usage: "/sessions", description: "查看当前会话列表" },
|
|
18573
18750
|
{ usage: "/session 或 /ss", description: "查看会话列表" },
|
|
@@ -18575,12 +18752,48 @@ var init_session_handler = __esm(() => {
|
|
|
18575
18752
|
{ usage: "/ss new <agent> (-d <path> | --ws <name>)", description: "强制新建会话" },
|
|
18576
18753
|
{ usage: "/ss new <alias> -a <name> --ws <name>", description: "按指定配置新建会话" },
|
|
18577
18754
|
{ usage: "/ss attach <alias> -a <name> --ws <name> --name <transport-session>", description: "绑定已有会话" },
|
|
18755
|
+
{ usage: "/ssn 或 /help ssn", description: "接入本地 native 会话(Codex 等 Agent 原生会话)" },
|
|
18578
18756
|
{ usage: "/session tail [N]", description: "补拉当前会话的历史输出(默认 50 行)" },
|
|
18579
18757
|
{ usage: "/session rm <alias>", description: "删除逻辑会话" },
|
|
18580
18758
|
{ usage: "/use <alias>", description: "切换当前会话" },
|
|
18581
18759
|
{ usage: "/session reset 或 /clear", description: "重置当前会话上下文" }
|
|
18582
18760
|
],
|
|
18583
|
-
examples: [
|
|
18761
|
+
examples: [
|
|
18762
|
+
"/ss codex -d /absolute/path/to/repo",
|
|
18763
|
+
"/ssn",
|
|
18764
|
+
"/ssn 1",
|
|
18765
|
+
"/use backend-fix",
|
|
18766
|
+
"/session rm old-session",
|
|
18767
|
+
"/session reset"
|
|
18768
|
+
]
|
|
18769
|
+
};
|
|
18770
|
+
nativeSessionHelp = {
|
|
18771
|
+
topic: "native",
|
|
18772
|
+
aliases: ["ssn", "native-session"],
|
|
18773
|
+
summary: "接入 Codex 等 Agent 的本地原生会话。",
|
|
18774
|
+
commands: [
|
|
18775
|
+
{ usage: "/ssn", description: "按当前 weacpx 会话上下文查看本地 native 会话" },
|
|
18776
|
+
{ usage: "/ssn <agent> --ws <workspace>", description: "查询指定工作区的本地 native 会话;只有一个候选时自动接入" },
|
|
18777
|
+
{ usage: "/ssn <agent> -d <path>", description: "按本机绝对路径查询;只有一个候选时自动接入" },
|
|
18778
|
+
{ usage: "/ssn <agent> --ws <workspace> --all", description: "跨 cwd 查看该 agent 的 native 会话" },
|
|
18779
|
+
{ usage: "/ssn 1", description: "接入或切换到最近一次列表里的第 1 个候选" },
|
|
18780
|
+
{ usage: "/ssn 1 -a <alias>", description: "接入第 1 个候选并指定 weacpx 别名(推荐,无需完整 sessionId)" },
|
|
18781
|
+
{ usage: "/ssn attach <sessionId> -a <alias>", description: "按原生 sessionId 接入(适合已知完整 id),并指定 weacpx 别名" },
|
|
18782
|
+
{ usage: "/ss attach native <sessionId> -a <alias>", description: "/ssn attach 的长写法" }
|
|
18783
|
+
],
|
|
18784
|
+
examples: [
|
|
18785
|
+
"/ssn codex --ws backend",
|
|
18786
|
+
"/ssn codex -d /absolute/path/to/repo",
|
|
18787
|
+
"/ssn",
|
|
18788
|
+
"/ssn 1",
|
|
18789
|
+
"/ssn 1 -a fix-ci"
|
|
18790
|
+
],
|
|
18791
|
+
notes: [
|
|
18792
|
+
"/ss 管 weacpx 逻辑会话;/ssn 只负责查询和接入 Agent 原生会话。",
|
|
18793
|
+
"接入后继续发普通消息,会继续同一个 Agent 原生会话,不是复制一份新上下文。",
|
|
18794
|
+
"如果当前 acpx 或 Agent 不支持 native 会话,请继续使用 /ss。",
|
|
18795
|
+
"完整说明见 docs/native-sessions.md。"
|
|
18796
|
+
]
|
|
18584
18797
|
};
|
|
18585
18798
|
modeHelp = {
|
|
18586
18799
|
topic: "mode",
|
|
@@ -19543,6 +19756,7 @@ var init_help_registry = __esm(() => {
|
|
|
19543
19756
|
init_later_handler();
|
|
19544
19757
|
HELP_TOPICS = [
|
|
19545
19758
|
sessionHelp,
|
|
19759
|
+
nativeSessionHelp,
|
|
19546
19760
|
workspaceHelp,
|
|
19547
19761
|
agentHelp,
|
|
19548
19762
|
permissionHelp,
|
|
@@ -19579,6 +19793,7 @@ function renderHelpIndex() {
|
|
|
19579
19793
|
return [
|
|
19580
19794
|
"常用入口:",
|
|
19581
19795
|
"- /ss <agent> (-d <path> | --ws <name>) - 快速新建或切到会话",
|
|
19796
|
+
"- /ssn <agent> (-d <path> | --ws <name>) - 接入本地 Agent 原生会话",
|
|
19582
19797
|
"- /use <alias> - 切换当前会话",
|
|
19583
19798
|
"- /status - 查看当前会话状态",
|
|
19584
19799
|
"",
|
|
@@ -19587,7 +19802,7 @@ function renderHelpIndex() {
|
|
|
19587
19802
|
"",
|
|
19588
19803
|
"查看专题说明:",
|
|
19589
19804
|
"- /help <topic>",
|
|
19590
|
-
"- 例如:/help ss、/help ws、/help pm"
|
|
19805
|
+
"- 例如:/help ss、/help ssn、/help ws、/help pm"
|
|
19591
19806
|
].join(`
|
|
19592
19807
|
`);
|
|
19593
19808
|
}
|
|
@@ -19669,7 +19884,7 @@ async function handleSessionShortcutCommand(context, ops, chatKey, agent, target
|
|
|
19669
19884
|
});
|
|
19670
19885
|
const baseAlias = `${workspace.name}:${agent}`;
|
|
19671
19886
|
const channelId = getChannelIdFromChatKey(chatKey);
|
|
19672
|
-
const scopedBase = channelId
|
|
19887
|
+
const scopedBase = scopeDisplayAliasToInternal(channelId, baseAlias);
|
|
19673
19888
|
const alias = createNew ? await allocateUniqueSessionAlias(context, scopedBase, chatKey) : scopedBase;
|
|
19674
19889
|
const display = toDisplaySessionAlias(alias);
|
|
19675
19890
|
if (!createNew && await hasLogicalSession(context, alias, chatKey)) {
|
|
@@ -19798,6 +20013,404 @@ var init_session_shortcut_handler = __esm(() => {
|
|
|
19798
20013
|
init_channel_scope();
|
|
19799
20014
|
});
|
|
19800
20015
|
|
|
20016
|
+
// src/commands/handlers/native-session-handler.ts
|
|
20017
|
+
async function handleNativeSessionList(context, chatKey, input) {
|
|
20018
|
+
const target = await resolveNativeTarget(context, chatKey, input);
|
|
20019
|
+
if (isRouterResponse(target)) {
|
|
20020
|
+
return target;
|
|
20021
|
+
}
|
|
20022
|
+
const listAgentSessions = context.transport.listAgentSessions?.bind(context.transport);
|
|
20023
|
+
if (!listAgentSessions) {
|
|
20024
|
+
return { text: `当前 transport 不支持列出本地会话,请继续使用 /ss。
|
|
20025
|
+
说明:/help ssn` };
|
|
20026
|
+
}
|
|
20027
|
+
const query = {
|
|
20028
|
+
agent: target.agent,
|
|
20029
|
+
agentCommand: target.agentCommand,
|
|
20030
|
+
cwd: target.cwd,
|
|
20031
|
+
...input.cursor ? { cursor: input.cursor } : {},
|
|
20032
|
+
...input.all ? {} : { filterCwd: target.cwd }
|
|
20033
|
+
};
|
|
20034
|
+
let result;
|
|
20035
|
+
try {
|
|
20036
|
+
result = await listAgentSessions(query);
|
|
20037
|
+
} catch (error2) {
|
|
20038
|
+
return { text: renderNativeListError(target, error2) };
|
|
20039
|
+
}
|
|
20040
|
+
if (!result) {
|
|
20041
|
+
return { text: `当前 transport 不支持列出本地会话,请继续使用 /ss。
|
|
20042
|
+
说明:/help ssn` };
|
|
20043
|
+
}
|
|
20044
|
+
await context.sessions.cacheNativeSessionList(chatKey, {
|
|
20045
|
+
agent: target.agent,
|
|
20046
|
+
workspace: target.workspace,
|
|
20047
|
+
cwd: target.cwd,
|
|
20048
|
+
sessions: result.sessions,
|
|
20049
|
+
...result.nextCursor !== undefined ? { nextCursor: result.nextCursor } : {}
|
|
20050
|
+
});
|
|
20051
|
+
if (result.sessions.length === 0) {
|
|
20052
|
+
return {
|
|
20053
|
+
text: [
|
|
20054
|
+
`没有找到本地 ${target.agentDisplayName} 会话(${target.workspaceLabel})。`,
|
|
20055
|
+
`你可以稍后再试,或先通过 /ss 保持当前逻辑会话。`
|
|
20056
|
+
].join(`
|
|
20057
|
+
`)
|
|
20058
|
+
};
|
|
20059
|
+
}
|
|
20060
|
+
const explicitAttachTarget = Boolean(input.workspace || input.cwd);
|
|
20061
|
+
if (explicitAttachTarget && !input.all && !input.cursor && result.sessions.length === 1) {
|
|
20062
|
+
return await attachNativeSession(context, chatKey, target, result.sessions[0], undefined);
|
|
20063
|
+
}
|
|
20064
|
+
const attachedEntries = await buildAttachedEntries(context, chatKey, target.agent, result.sessions);
|
|
20065
|
+
const nativeSessionListOptions = { format: context.resolveNativeSessionListFormat?.(chatKey) ?? "table" };
|
|
20066
|
+
return {
|
|
20067
|
+
text: renderNativeSessionList(target, result, attachedEntries, Boolean(input.all), nativeSessionListOptions)
|
|
20068
|
+
};
|
|
20069
|
+
}
|
|
20070
|
+
async function handleNativeSessionSelect(context, chatKey, identifier, alias) {
|
|
20071
|
+
const trimmed = identifier.trim();
|
|
20072
|
+
if (!trimmed) {
|
|
20073
|
+
return { text: `请选择要切换的 native 会话编号或 sessionId。
|
|
20074
|
+
说明:/help ssn` };
|
|
20075
|
+
}
|
|
20076
|
+
if (/^[0-9]+$/.test(trimmed)) {
|
|
20077
|
+
const cached2 = await context.sessions.getNativeSessionList(chatKey, NATIVE_SESSION_CACHE_TTL_MS);
|
|
20078
|
+
if (!cached2 || cached2.sessions.length === 0) {
|
|
20079
|
+
return { text: `当前没有可用的 native 会话列表,请先执行 /ssn 再选择。
|
|
20080
|
+
说明:/help ssn` };
|
|
20081
|
+
}
|
|
20082
|
+
const index = Number(trimmed) - 1;
|
|
20083
|
+
const session = cached2.sessions[index];
|
|
20084
|
+
if (!session) {
|
|
20085
|
+
return { text: "编号超出范围,请先执行 /ssn 重新获取列表。" };
|
|
20086
|
+
}
|
|
20087
|
+
const target2 = await resolveTargetFromCachedSession(context, chatKey, cached2, session);
|
|
20088
|
+
if (isRouterResponse(target2)) {
|
|
20089
|
+
return target2;
|
|
20090
|
+
}
|
|
20091
|
+
return await attachNativeSession(context, chatKey, target2, session, alias);
|
|
20092
|
+
}
|
|
20093
|
+
const target = await resolveNativeTarget(context, chatKey, {});
|
|
20094
|
+
if (isRouterResponse(target)) {
|
|
20095
|
+
return target;
|
|
20096
|
+
}
|
|
20097
|
+
return await attachNativeSession(context, chatKey, target, { sessionId: trimmed }, alias);
|
|
20098
|
+
}
|
|
20099
|
+
async function attachNativeSession(context, chatKey, target, session, alias) {
|
|
20100
|
+
if (!context.transport.resumeAgentSession) {
|
|
20101
|
+
return { text: "当前 transport 不支持接入本地会话,请继续使用 /ss。" };
|
|
20102
|
+
}
|
|
20103
|
+
const nativeTarget = target;
|
|
20104
|
+
const existing = await context.sessions.findAttachedNativeSession(chatKey, nativeTarget.agent, session.sessionId);
|
|
20105
|
+
if (existing) {
|
|
20106
|
+
await context.sessions.useSession(chatKey, existing.alias);
|
|
20107
|
+
const displayAlias2 = toDisplaySessionAlias(existing.alias);
|
|
20108
|
+
return {
|
|
20109
|
+
text: `已切换到已接入的本地会话:${nativeTarget.agentDisplayName} · ${displayAlias2}`
|
|
20110
|
+
};
|
|
20111
|
+
}
|
|
20112
|
+
const requestedAlias = alias?.trim() || buildDefaultNativeAlias(nativeTarget.agent, session.sessionId);
|
|
20113
|
+
const displayAlias = await allocateUniqueNativeAlias(context, chatKey, requestedAlias);
|
|
20114
|
+
const internalAlias = scopeDisplayAliasToInternal(getChannelIdFromChatKey(chatKey), displayAlias);
|
|
20115
|
+
const transportSession = context.sessions.buildDefaultTransportSessionForChat(chatKey, displayAlias);
|
|
20116
|
+
const resolvedSession = context.lifecycle.resolveSession(internalAlias, nativeTarget.agent, nativeTarget.workspace, transportSession);
|
|
20117
|
+
const releaseReservation = await context.lifecycle.reserveTransportSession(resolvedSession.transportSession);
|
|
20118
|
+
try {
|
|
20119
|
+
try {
|
|
20120
|
+
await context.transport.resumeAgentSession(resolvedSession, session.sessionId);
|
|
20121
|
+
} catch (error2) {
|
|
20122
|
+
return { text: renderNativeResumeError(target, error2) };
|
|
20123
|
+
}
|
|
20124
|
+
const verified = await context.lifecycle.checkTransportSession(resolvedSession);
|
|
20125
|
+
if (!verified) {
|
|
20126
|
+
return { text: `本地 ${target.agentDisplayName} 会话接入失败:未检测到已恢复的后端会话。` };
|
|
20127
|
+
}
|
|
20128
|
+
await context.sessions.attachNativeSession({
|
|
20129
|
+
alias: internalAlias,
|
|
20130
|
+
agent: nativeTarget.agent,
|
|
20131
|
+
workspace: nativeTarget.workspace,
|
|
20132
|
+
transportSession,
|
|
20133
|
+
...target.agentCommand ? { transportAgentCommand: target.agentCommand } : {},
|
|
20134
|
+
agentSessionId: session.sessionId,
|
|
20135
|
+
title: session.title,
|
|
20136
|
+
updatedAt: session.updatedAt
|
|
20137
|
+
});
|
|
20138
|
+
await context.sessions.useSession(chatKey, internalAlias);
|
|
20139
|
+
await refreshAgentCommandBestEffort(context, internalAlias);
|
|
20140
|
+
return {
|
|
20141
|
+
text: `已接入本地 ${target.agentDisplayName} 会话并切换:${toDisplaySessionAlias(internalAlias)}`
|
|
20142
|
+
};
|
|
20143
|
+
} finally {
|
|
20144
|
+
await releaseReservation();
|
|
20145
|
+
}
|
|
20146
|
+
}
|
|
20147
|
+
async function resolveNativeTarget(context, chatKey, input) {
|
|
20148
|
+
const currentSession = await context.sessions.getCurrentSession(chatKey);
|
|
20149
|
+
const agent = input.agent?.trim() || currentSession?.agent || "";
|
|
20150
|
+
if (!agent) {
|
|
20151
|
+
return {
|
|
20152
|
+
text: `请先选择上下文,例如:
|
|
20153
|
+
/ssn codex --ws project
|
|
20154
|
+
/ssn codex -d /Users/me/project
|
|
20155
|
+
说明:/help ssn`
|
|
20156
|
+
};
|
|
20157
|
+
}
|
|
20158
|
+
const agentConfig = context.config?.agents[agent];
|
|
20159
|
+
if (!agentConfig) {
|
|
20160
|
+
return { text: `Agent「${agent}」未注册。` };
|
|
20161
|
+
}
|
|
20162
|
+
const workspaceResolution = await resolveNativeWorkspace(context, input, currentSession);
|
|
20163
|
+
if (isRouterResponse(workspaceResolution)) {
|
|
20164
|
+
return workspaceResolution;
|
|
20165
|
+
}
|
|
20166
|
+
return {
|
|
20167
|
+
agent,
|
|
20168
|
+
agentDisplayName: displayAgentName(agent),
|
|
20169
|
+
agentCommand: resolveAgentCommand(agentConfig.driver, agentConfig.command),
|
|
20170
|
+
workspace: workspaceResolution.workspace,
|
|
20171
|
+
workspaceLabel: workspaceResolution.workspaceLabel,
|
|
20172
|
+
cwd: workspaceResolution.cwd,
|
|
20173
|
+
source: workspaceResolution.source
|
|
20174
|
+
};
|
|
20175
|
+
}
|
|
20176
|
+
async function resolveTargetFromCachedSession(context, chatKey, cached2, session) {
|
|
20177
|
+
if (session.cwd && !sameWorkspacePath(session.cwd, cached2.cwd)) {
|
|
20178
|
+
return await resolveNativeTarget(context, chatKey, {
|
|
20179
|
+
agent: cached2.agent,
|
|
20180
|
+
cwd: session.cwd
|
|
20181
|
+
});
|
|
20182
|
+
}
|
|
20183
|
+
return await resolveNativeTarget(context, chatKey, {
|
|
20184
|
+
agent: cached2.agent,
|
|
20185
|
+
...cached2.workspace ? { workspace: cached2.workspace } : { cwd: cached2.cwd }
|
|
20186
|
+
});
|
|
20187
|
+
}
|
|
20188
|
+
async function resolveNativeWorkspace(context, input, currentSession) {
|
|
20189
|
+
if (input.workspace) {
|
|
20190
|
+
const workspaceConfig = context.config?.workspaces[input.workspace];
|
|
20191
|
+
if (!workspaceConfig) {
|
|
20192
|
+
return { text: `工作区「${input.workspace}」未注册。` };
|
|
20193
|
+
}
|
|
20194
|
+
return {
|
|
20195
|
+
workspace: input.workspace,
|
|
20196
|
+
workspaceLabel: input.workspace,
|
|
20197
|
+
cwd: workspaceConfig.cwd,
|
|
20198
|
+
source: "workspace"
|
|
20199
|
+
};
|
|
20200
|
+
}
|
|
20201
|
+
if (input.cwd) {
|
|
20202
|
+
const cwd = normalizeWorkspacePath(input.cwd);
|
|
20203
|
+
const existing = Object.entries(context.config?.workspaces ?? {}).find(([, workspace]) => sameWorkspacePath(workspace.cwd, cwd));
|
|
20204
|
+
if (existing) {
|
|
20205
|
+
return {
|
|
20206
|
+
workspace: existing[0],
|
|
20207
|
+
workspaceLabel: existing[0],
|
|
20208
|
+
cwd: existing[1].cwd,
|
|
20209
|
+
source: "cwd"
|
|
20210
|
+
};
|
|
20211
|
+
}
|
|
20212
|
+
if (!await pathExists(cwd)) {
|
|
20213
|
+
return { text: `工作区路径不存在:${input.cwd}` };
|
|
20214
|
+
}
|
|
20215
|
+
if (!context.configStore || !context.config) {
|
|
20216
|
+
return { text: "当前没有加载可写入的配置,无法根据路径创建工作区。" };
|
|
20217
|
+
}
|
|
20218
|
+
const workspaceName = allocateWorkspaceName(sanitizeWorkspaceName(basenameForWorkspacePath(cwd)), context.config.workspaces);
|
|
20219
|
+
const updated = await context.configStore.upsertWorkspace(workspaceName, cwd);
|
|
20220
|
+
context.replaceConfig(updated);
|
|
20221
|
+
return {
|
|
20222
|
+
workspace: workspaceName,
|
|
20223
|
+
workspaceLabel: workspaceName,
|
|
20224
|
+
cwd,
|
|
20225
|
+
source: "cwd"
|
|
20226
|
+
};
|
|
20227
|
+
}
|
|
20228
|
+
if (currentSession) {
|
|
20229
|
+
return {
|
|
20230
|
+
workspace: currentSession.workspace,
|
|
20231
|
+
workspaceLabel: currentSession.workspace,
|
|
20232
|
+
cwd: currentSession.cwd,
|
|
20233
|
+
source: "workspace"
|
|
20234
|
+
};
|
|
20235
|
+
}
|
|
20236
|
+
return {
|
|
20237
|
+
text: `请先选择上下文,例如:
|
|
20238
|
+
/ssn codex --ws project
|
|
20239
|
+
/ssn codex -d /Users/me/project
|
|
20240
|
+
说明:/help ssn`
|
|
20241
|
+
};
|
|
20242
|
+
}
|
|
20243
|
+
async function buildAttachedEntries(context, chatKey, agent, sessions) {
|
|
20244
|
+
const currentSession = await context.sessions.getCurrentSession(chatKey);
|
|
20245
|
+
return await Promise.all(sessions.map(async (session) => {
|
|
20246
|
+
const attached = await context.sessions.findAttachedNativeSession(chatKey, agent, session.sessionId);
|
|
20247
|
+
if (!attached) {
|
|
20248
|
+
return { session };
|
|
20249
|
+
}
|
|
20250
|
+
return {
|
|
20251
|
+
session,
|
|
20252
|
+
attached: {
|
|
20253
|
+
alias: attached.alias,
|
|
20254
|
+
displayAlias: toDisplaySessionAlias(attached.alias),
|
|
20255
|
+
isCurrent: currentSession?.alias === attached.alias
|
|
20256
|
+
}
|
|
20257
|
+
};
|
|
20258
|
+
}));
|
|
20259
|
+
}
|
|
20260
|
+
function renderNativeSessionList(target, result, entries, includeAll, options = {}) {
|
|
20261
|
+
if (options.format === "cards") {
|
|
20262
|
+
return renderNativeSessionCardList(target, result, entries, includeAll);
|
|
20263
|
+
}
|
|
20264
|
+
return renderNativeSessionTableList(target, result, entries, includeAll);
|
|
20265
|
+
}
|
|
20266
|
+
function renderNativeSessionTableList(target, result, entries, includeAll) {
|
|
20267
|
+
const lines = [`本地 ${target.agentDisplayName} 会话(${target.workspaceLabel}):`];
|
|
20268
|
+
lines.push("| # | 标题 | 更新时间 | ID |");
|
|
20269
|
+
lines.push("|---|---|---|---|");
|
|
20270
|
+
entries.forEach((entry, index) => {
|
|
20271
|
+
const title = escapeMarkdownTableCell(renderNativeSessionTitle(entry.session.title, entry.session.sessionId));
|
|
20272
|
+
const updatedAt = entry.session.updatedAt ? formatNativeSessionTime(entry.session.updatedAt) : "-";
|
|
20273
|
+
const idParts = [entry.session.sessionId];
|
|
20274
|
+
if (entry.attached) {
|
|
20275
|
+
idParts.push(`已接入:${entry.attached.displayAlias}${entry.attached.isCurrent ? " [当前]" : ""}`);
|
|
20276
|
+
}
|
|
20277
|
+
lines.push(`| ${index + 1} | ${title} | ${escapeMarkdownTableCell(updatedAt)} | ${escapeMarkdownTableCell(idParts.join(" · "))} |`);
|
|
20278
|
+
});
|
|
20279
|
+
lines.push("");
|
|
20280
|
+
lines.push("操作:");
|
|
20281
|
+
lines.push("接入:/ssn 1");
|
|
20282
|
+
lines.push("指定别名:/ssn 1 -a fix-ci");
|
|
20283
|
+
lines.push("说明:/help ssn");
|
|
20284
|
+
if (result.nextCursor) {
|
|
20285
|
+
lines.push(`更多:${renderNextPageCommand(target, result.nextCursor, includeAll)}`);
|
|
20286
|
+
}
|
|
20287
|
+
return lines.join(`
|
|
20288
|
+
`);
|
|
20289
|
+
}
|
|
20290
|
+
function renderNativeSessionCardList(target, result, entries, includeAll) {
|
|
20291
|
+
const lines = [
|
|
20292
|
+
`本地 ${target.agentDisplayName} 会话(${target.workspaceLabel}):`,
|
|
20293
|
+
"回复编号接入,ID 尾号用于区分。"
|
|
20294
|
+
];
|
|
20295
|
+
entries.forEach((entry, index) => {
|
|
20296
|
+
const title = renderNativeSessionTitle(entry.session.title, entry.session.sessionId);
|
|
20297
|
+
const updatedAt = entry.session.updatedAt ? formatNativeSessionTime(entry.session.updatedAt) : "-";
|
|
20298
|
+
lines.push("");
|
|
20299
|
+
lines.push(`【${index + 1}】 ${title}`);
|
|
20300
|
+
lines.push(`时间:${updatedAt}`);
|
|
20301
|
+
lines.push(`ID:${formatSessionIdTail(entry.session.sessionId)}`);
|
|
20302
|
+
if (entry.attached) {
|
|
20303
|
+
lines.push(`已接入:${entry.attached.displayAlias}${entry.attached.isCurrent ? " [当前]" : ""}`);
|
|
20304
|
+
}
|
|
20305
|
+
});
|
|
20306
|
+
lines.push("");
|
|
20307
|
+
lines.push("操作:");
|
|
20308
|
+
lines.push("接入:/ssn 1");
|
|
20309
|
+
lines.push("指定别名:/ssn 1 -a fix-ci");
|
|
20310
|
+
lines.push("说明:/help ssn");
|
|
20311
|
+
if (result.nextCursor) {
|
|
20312
|
+
lines.push(`更多:${renderNextPageCommand(target, result.nextCursor, includeAll)}`);
|
|
20313
|
+
}
|
|
20314
|
+
return lines.join(`
|
|
20315
|
+
`);
|
|
20316
|
+
}
|
|
20317
|
+
function renderNativeSessionTitle(title, fallback) {
|
|
20318
|
+
const normalized = (title?.trim() || fallback).replace(/\s+/g, " ");
|
|
20319
|
+
const maxLength = 60;
|
|
20320
|
+
return normalized.length > maxLength ? `${normalized.slice(0, maxLength - 1)}…` : normalized;
|
|
20321
|
+
}
|
|
20322
|
+
function buildDefaultNativeAlias(agent, sessionId) {
|
|
20323
|
+
return `${agent}-${sessionIdTail(sessionId)}`;
|
|
20324
|
+
}
|
|
20325
|
+
function formatSessionIdTail(sessionId) {
|
|
20326
|
+
const tail = sessionIdTail(sessionId);
|
|
20327
|
+
return tail.length < sessionId.trim().length ? `…${tail}` : tail;
|
|
20328
|
+
}
|
|
20329
|
+
function sessionIdTail(sessionId) {
|
|
20330
|
+
const trimmed = sessionId.trim();
|
|
20331
|
+
if (trimmed.length <= 8) {
|
|
20332
|
+
return trimmed;
|
|
20333
|
+
}
|
|
20334
|
+
return trimmed.slice(-8);
|
|
20335
|
+
}
|
|
20336
|
+
function formatNativeSessionTime(value) {
|
|
20337
|
+
const date4 = new Date(value);
|
|
20338
|
+
if (Number.isNaN(date4.getTime())) {
|
|
20339
|
+
return value;
|
|
20340
|
+
}
|
|
20341
|
+
const pad = (input) => String(input).padStart(2, "0");
|
|
20342
|
+
return `${date4.getFullYear()}-${pad(date4.getMonth() + 1)}-${pad(date4.getDate())} ${pad(date4.getHours())}:${pad(date4.getMinutes())}`;
|
|
20343
|
+
}
|
|
20344
|
+
function escapeMarkdownTableCell(value) {
|
|
20345
|
+
return value.replace(/\|/g, "\\|").replace(/\r?\n/g, " ");
|
|
20346
|
+
}
|
|
20347
|
+
function renderNextPageCommand(target, nextCursor, includeAll) {
|
|
20348
|
+
const scope = target.source === "workspace" && target.workspace ? `--ws ${target.workspace}` : `-d ${target.cwd}`;
|
|
20349
|
+
const allFlag = includeAll ? " --all" : "";
|
|
20350
|
+
return `/ssn ${target.agent} ${scope}${allFlag} --cursor ${nextCursor}`;
|
|
20351
|
+
}
|
|
20352
|
+
async function allocateUniqueNativeAlias(context, chatKey, baseDisplayAlias) {
|
|
20353
|
+
const channelId = getChannelIdFromChatKey(chatKey);
|
|
20354
|
+
const visible = await context.sessions.listSessions(chatKey);
|
|
20355
|
+
const existing = new Set(visible.map((session) => session.internalAlias));
|
|
20356
|
+
const base = baseDisplayAlias.trim() || "native-session";
|
|
20357
|
+
const transportFor = (candidate) => context.sessions.buildDefaultTransportSessionForChat(chatKey, candidate);
|
|
20358
|
+
const isFree = (candidate) => !existing.has(scopeDisplayAliasToInternal(channelId, candidate)) && context.sessions.countAliasesSharingTransport(transportFor(candidate)) === 0;
|
|
20359
|
+
if (isFree(base)) {
|
|
20360
|
+
return base;
|
|
20361
|
+
}
|
|
20362
|
+
let suffix = 2;
|
|
20363
|
+
while (!isFree(`${base}-${suffix}`)) {
|
|
20364
|
+
suffix += 1;
|
|
20365
|
+
}
|
|
20366
|
+
return `${base}-${suffix}`;
|
|
20367
|
+
}
|
|
20368
|
+
async function refreshAgentCommandBestEffort(context, alias) {
|
|
20369
|
+
try {
|
|
20370
|
+
await context.lifecycle.refreshSessionTransportAgentCommand(alias);
|
|
20371
|
+
} catch (error2) {
|
|
20372
|
+
await context.logger.error("session.native.agent_command_refresh_failed", "failed to refresh native session agent command", {
|
|
20373
|
+
alias,
|
|
20374
|
+
error: error2 instanceof Error ? error2.message : String(error2)
|
|
20375
|
+
});
|
|
20376
|
+
}
|
|
20377
|
+
}
|
|
20378
|
+
function renderNativeListError(target, error2) {
|
|
20379
|
+
return [
|
|
20380
|
+
`本地 ${target.agentDisplayName} 会话查询失败:${formatErrorMessage(error2)}`,
|
|
20381
|
+
"请确认 acpx/Agent 支持 native 会话查询,或继续使用 /ss。",
|
|
20382
|
+
"说明:/help ssn"
|
|
20383
|
+
].join(`
|
|
20384
|
+
`);
|
|
20385
|
+
}
|
|
20386
|
+
function renderNativeResumeError(target, error2) {
|
|
20387
|
+
return [
|
|
20388
|
+
`本地 ${target.agentDisplayName} 会话接入失败:${formatErrorMessage(error2)}`,
|
|
20389
|
+
"请确认 acpx/Agent 支持 native 会话恢复,或继续使用 /ss。",
|
|
20390
|
+
"说明:/help ssn"
|
|
20391
|
+
].join(`
|
|
20392
|
+
`);
|
|
20393
|
+
}
|
|
20394
|
+
function formatErrorMessage(error2) {
|
|
20395
|
+
return error2 instanceof Error ? error2.message : String(error2);
|
|
20396
|
+
}
|
|
20397
|
+
function isRouterResponse(value) {
|
|
20398
|
+
return typeof value.text === "string";
|
|
20399
|
+
}
|
|
20400
|
+
function displayAgentName(agent) {
|
|
20401
|
+
if (!agent) {
|
|
20402
|
+
return agent;
|
|
20403
|
+
}
|
|
20404
|
+
return agent.charAt(0).toUpperCase() + agent.slice(1);
|
|
20405
|
+
}
|
|
20406
|
+
var NATIVE_SESSION_CACHE_TTL_MS;
|
|
20407
|
+
var init_native_session_handler = __esm(() => {
|
|
20408
|
+
init_channel_scope();
|
|
20409
|
+
init_workspace_name();
|
|
20410
|
+
init_workspace_path();
|
|
20411
|
+
NATIVE_SESSION_CACHE_TTL_MS = 10 * 60 * 1000;
|
|
20412
|
+
});
|
|
20413
|
+
|
|
19801
20414
|
// src/commands/handlers/session-recovery-handler.ts
|
|
19802
20415
|
function renderTransportError(session, error2) {
|
|
19803
20416
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
@@ -20265,6 +20878,7 @@ class CommandRouter {
|
|
|
20265
20878
|
quota;
|
|
20266
20879
|
scheduled;
|
|
20267
20880
|
scheduledDelivery;
|
|
20881
|
+
resolveNativeSessionListFormat;
|
|
20268
20882
|
logger;
|
|
20269
20883
|
autoInstall = autoInstallOptionalDep;
|
|
20270
20884
|
discoverPaths = discoverParentPackagePaths;
|
|
@@ -20274,7 +20888,7 @@ class CommandRouter {
|
|
|
20274
20888
|
__setDiscoverPathsForTest(fn) {
|
|
20275
20889
|
this.discoverPaths = fn;
|
|
20276
20890
|
}
|
|
20277
|
-
constructor(sessions, transport, config2, configStore, logger2, resolveSessionAgentCommand = resolveSessionAgentCommandFromIndex, orchestration, quota, scheduled, scheduledDelivery) {
|
|
20891
|
+
constructor(sessions, transport, config2, configStore, logger2, resolveSessionAgentCommand = resolveSessionAgentCommandFromIndex, orchestration, quota, scheduled, scheduledDelivery, resolveNativeSessionListFormat) {
|
|
20278
20892
|
this.sessions = sessions;
|
|
20279
20893
|
this.transport = transport;
|
|
20280
20894
|
this.config = config2;
|
|
@@ -20284,6 +20898,7 @@ class CommandRouter {
|
|
|
20284
20898
|
this.quota = quota;
|
|
20285
20899
|
this.scheduled = scheduled;
|
|
20286
20900
|
this.scheduledDelivery = scheduledDelivery;
|
|
20901
|
+
this.resolveNativeSessionListFormat = resolveNativeSessionListFormat;
|
|
20287
20902
|
this.logger = logger2 ?? createNoopAppLogger();
|
|
20288
20903
|
}
|
|
20289
20904
|
async handle(chatKey, input, reply, replyContextToken, accountId, media, metadata, abortSignal, onToolEvent, onThought, perfSpan) {
|
|
@@ -20358,6 +20973,12 @@ class CommandRouter {
|
|
|
20358
20973
|
return await handleSessionShortcut(this.createSessionHandlerContext(reply, perfSpan), chatKey, command.agent, command, true);
|
|
20359
20974
|
case "session.attach":
|
|
20360
20975
|
return await handleSessionAttach(this.createSessionHandlerContext(reply, perfSpan), chatKey, command.alias, command.agent, command.workspace, command.transportSession);
|
|
20976
|
+
case "session.native.list":
|
|
20977
|
+
return await handleNativeSessionList(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command);
|
|
20978
|
+
case "session.native.select":
|
|
20979
|
+
return await handleNativeSessionSelect(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.identifier, command.alias);
|
|
20980
|
+
case "session.native.attach":
|
|
20981
|
+
return await handleNativeSessionSelect(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.identifier, command.alias);
|
|
20361
20982
|
case "session.use":
|
|
20362
20983
|
return await handleSessionUse(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.alias);
|
|
20363
20984
|
case "mode.show":
|
|
@@ -20459,7 +21080,8 @@ class CommandRouter {
|
|
|
20459
21080
|
configStore: this.configStore,
|
|
20460
21081
|
logger: this.logger,
|
|
20461
21082
|
replaceConfig: (updated) => this.replaceConfig(updated),
|
|
20462
|
-
...this.quota ? { quota: this.quota } : {}
|
|
21083
|
+
...this.quota ? { quota: this.quota } : {},
|
|
21084
|
+
...this.resolveNativeSessionListFormat ? { resolveNativeSessionListFormat: this.resolveNativeSessionListFormat } : {}
|
|
20463
21085
|
};
|
|
20464
21086
|
}
|
|
20465
21087
|
createSessionHandlerContext(reply, perfSpan) {
|
|
@@ -20821,6 +21443,7 @@ var init_command_router = __esm(() => {
|
|
|
20821
21443
|
init_agent_handler();
|
|
20822
21444
|
init_workspace_handler();
|
|
20823
21445
|
init_session_shortcut_handler();
|
|
21446
|
+
init_native_session_handler();
|
|
20824
21447
|
init_later_handler();
|
|
20825
21448
|
init_session_recovery_handler();
|
|
20826
21449
|
init_auto_install_optional_dep();
|
|
@@ -25144,11 +25767,13 @@ class SessionService {
|
|
|
25144
25767
|
stateStore;
|
|
25145
25768
|
state;
|
|
25146
25769
|
stateMutex;
|
|
25770
|
+
now;
|
|
25147
25771
|
constructor(config2, stateStore, state, options = {}) {
|
|
25148
25772
|
this.config = config2;
|
|
25149
25773
|
this.stateStore = stateStore;
|
|
25150
25774
|
this.state = state;
|
|
25151
25775
|
this.stateMutex = options.stateMutex ?? new AsyncMutex;
|
|
25776
|
+
this.now = options.now ?? (() => Date.now());
|
|
25152
25777
|
}
|
|
25153
25778
|
async createSession(alias, agent, workspace) {
|
|
25154
25779
|
return await this.createLogicalSession(alias, agent, workspace, `${workspace}:${alias}`);
|
|
@@ -25182,6 +25807,14 @@ class SessionService {
|
|
|
25182
25807
|
async attachSession(alias, agent, workspace, transportSession, transportAgentCommand) {
|
|
25183
25808
|
return await this.createLogicalSession(alias, agent, workspace, transportSession, transportAgentCommand);
|
|
25184
25809
|
}
|
|
25810
|
+
async attachNativeSession(input) {
|
|
25811
|
+
return await this.createLogicalSession(input.alias, input.agent, input.workspace, input.transportSession, input.transportAgentCommand, {
|
|
25812
|
+
source: "agent-side",
|
|
25813
|
+
agentSessionId: input.agentSessionId,
|
|
25814
|
+
title: input.title,
|
|
25815
|
+
updatedAt: input.updatedAt
|
|
25816
|
+
});
|
|
25817
|
+
}
|
|
25185
25818
|
async getSession(alias) {
|
|
25186
25819
|
const session = this.state.sessions[alias];
|
|
25187
25820
|
if (!session) {
|
|
@@ -25196,6 +25829,22 @@ class SessionService {
|
|
|
25196
25829
|
const preferred = matches.find((session) => session.alias === expectedAlias && session.workspace === expectedWorkspace) ?? matches[0];
|
|
25197
25830
|
return preferred ? this.toResolvedSession(preferred) : null;
|
|
25198
25831
|
}
|
|
25832
|
+
async findAttachedNativeSession(chatKey, agent, agentSessionId) {
|
|
25833
|
+
const channelId = getChannelIdFromChatKey(chatKey);
|
|
25834
|
+
for (const session of Object.values(this.state.sessions)) {
|
|
25835
|
+
if (session.source !== "agent-side") {
|
|
25836
|
+
continue;
|
|
25837
|
+
}
|
|
25838
|
+
if (session.agent !== agent || session.agent_session_id !== agentSessionId) {
|
|
25839
|
+
continue;
|
|
25840
|
+
}
|
|
25841
|
+
if (!isSessionAliasVisibleInChannel(session.alias, channelId)) {
|
|
25842
|
+
continue;
|
|
25843
|
+
}
|
|
25844
|
+
return this.toResolvedSession(session);
|
|
25845
|
+
}
|
|
25846
|
+
return null;
|
|
25847
|
+
}
|
|
25199
25848
|
async useSession(chatKey, alias) {
|
|
25200
25849
|
await this.mutate(async () => {
|
|
25201
25850
|
const channelId = getChannelIdFromChatKey(chatKey);
|
|
@@ -25315,6 +25964,49 @@ class SessionService {
|
|
|
25315
25964
|
return { wasActive };
|
|
25316
25965
|
});
|
|
25317
25966
|
}
|
|
25967
|
+
async cacheNativeSessionList(chatKey, input) {
|
|
25968
|
+
await this.mutate(async () => {
|
|
25969
|
+
this.state.native_session_lists[chatKey] = {
|
|
25970
|
+
created_at: new Date(this.now()).toISOString(),
|
|
25971
|
+
agent: input.agent,
|
|
25972
|
+
...input.workspace !== undefined ? { workspace: input.workspace } : {},
|
|
25973
|
+
cwd: input.cwd,
|
|
25974
|
+
sessions: input.sessions.map((session) => ({
|
|
25975
|
+
session_id: session.sessionId,
|
|
25976
|
+
...session.cwd !== undefined ? { cwd: session.cwd } : {},
|
|
25977
|
+
...session.title !== undefined ? { title: session.title } : {},
|
|
25978
|
+
...session.updatedAt !== undefined ? { updated_at: session.updatedAt } : {}
|
|
25979
|
+
})),
|
|
25980
|
+
...input.nextCursor !== undefined ? { next_cursor: input.nextCursor } : {}
|
|
25981
|
+
};
|
|
25982
|
+
await this.persist();
|
|
25983
|
+
});
|
|
25984
|
+
}
|
|
25985
|
+
async getNativeSessionList(chatKey, ttlMs = 10 * 60 * 1000) {
|
|
25986
|
+
const cached2 = this.state.native_session_lists[chatKey];
|
|
25987
|
+
if (!cached2) {
|
|
25988
|
+
return null;
|
|
25989
|
+
}
|
|
25990
|
+
const createdAt = Date.parse(cached2.created_at);
|
|
25991
|
+
if (Number.isNaN(createdAt)) {
|
|
25992
|
+
return null;
|
|
25993
|
+
}
|
|
25994
|
+
if (this.now() - createdAt > ttlMs) {
|
|
25995
|
+
return null;
|
|
25996
|
+
}
|
|
25997
|
+
return {
|
|
25998
|
+
agent: cached2.agent,
|
|
25999
|
+
...cached2.workspace !== undefined ? { workspace: cached2.workspace } : {},
|
|
26000
|
+
cwd: cached2.cwd,
|
|
26001
|
+
sessions: cached2.sessions.map((session) => ({
|
|
26002
|
+
sessionId: session.session_id,
|
|
26003
|
+
...session.cwd !== undefined ? { cwd: session.cwd } : {},
|
|
26004
|
+
...session.title !== undefined ? { title: session.title } : {},
|
|
26005
|
+
...session.updated_at !== undefined ? { updatedAt: session.updated_at } : {}
|
|
26006
|
+
})),
|
|
26007
|
+
...cached2.next_cursor !== undefined ? { nextCursor: cached2.next_cursor } : {}
|
|
26008
|
+
};
|
|
26009
|
+
}
|
|
25318
26010
|
toResolvedSession(session) {
|
|
25319
26011
|
const agentConfig = this.config.agents[session.agent];
|
|
25320
26012
|
if (!agentConfig) {
|
|
@@ -25330,6 +26022,11 @@ class SessionService {
|
|
|
25330
26022
|
agentCommand: session.transport_agent_command ?? resolveAgentCommand(agentConfig.driver, agentConfig.command),
|
|
25331
26023
|
workspace: session.workspace,
|
|
25332
26024
|
transportSession: session.transport_session,
|
|
26025
|
+
source: session.source,
|
|
26026
|
+
agentSessionId: session.agent_session_id,
|
|
26027
|
+
agentSessionTitle: session.agent_session_title,
|
|
26028
|
+
agentSessionUpdatedAt: session.agent_session_updated_at,
|
|
26029
|
+
attachedAt: session.attached_at,
|
|
25333
26030
|
modeId: session.mode_id,
|
|
25334
26031
|
replyMode: session.reply_mode,
|
|
25335
26032
|
cwd: workspaceConfig.cwd
|
|
@@ -25357,20 +26054,25 @@ class SessionService {
|
|
|
25357
26054
|
async persist() {
|
|
25358
26055
|
await this.stateStore.save(this.state);
|
|
25359
26056
|
}
|
|
25360
|
-
async createLogicalSession(alias, agent, workspace, transportSession, transportAgentCommand) {
|
|
26057
|
+
async createLogicalSession(alias, agent, workspace, transportSession, transportAgentCommand, native) {
|
|
25361
26058
|
return await this.mutate(async () => {
|
|
25362
26059
|
this.validateSession(alias, agent, workspace);
|
|
25363
26060
|
if (this.state.orchestration.externalCoordinators[transportSession]) {
|
|
25364
26061
|
throw new Error(`transport session "${transportSession}" conflicts with an external coordinator`);
|
|
25365
26062
|
}
|
|
25366
26063
|
const existingSession = this.state.sessions[alias];
|
|
25367
|
-
const now = new Date().toISOString();
|
|
26064
|
+
const now = new Date(this.now()).toISOString();
|
|
25368
26065
|
const normalizedTransportAgentCommand = transportAgentCommand?.trim();
|
|
25369
26066
|
const session = {
|
|
25370
26067
|
alias,
|
|
25371
26068
|
agent,
|
|
25372
26069
|
workspace,
|
|
25373
26070
|
transport_session: transportSession,
|
|
26071
|
+
source: native?.source,
|
|
26072
|
+
agent_session_id: native?.agentSessionId,
|
|
26073
|
+
agent_session_title: native?.title ?? undefined,
|
|
26074
|
+
agent_session_updated_at: native?.updatedAt,
|
|
26075
|
+
attached_at: native ? now : undefined,
|
|
25374
26076
|
...normalizedTransportAgentCommand ? { transport_agent_command: normalizedTransportAgentCommand } : existingSession?.transport_agent_command ? { transport_agent_command: existingSession.transport_agent_command } : {},
|
|
25375
26077
|
mode_id: existingSession?.mode_id,
|
|
25376
26078
|
reply_mode: existingSession?.reply_mode,
|
|
@@ -26167,6 +26869,18 @@ class AcpxBridgeTransport {
|
|
|
26167
26869
|
lines
|
|
26168
26870
|
});
|
|
26169
26871
|
}
|
|
26872
|
+
async listAgentSessions(query) {
|
|
26873
|
+
return await this.client.request("listAgentSessions", { ...query });
|
|
26874
|
+
}
|
|
26875
|
+
async resumeAgentSession(session, agentSessionId) {
|
|
26876
|
+
await this.client.request("resumeAgentSession", {
|
|
26877
|
+
agent: session.agent,
|
|
26878
|
+
...session.agentCommand ? { agentCommand: session.agentCommand } : {},
|
|
26879
|
+
cwd: session.cwd,
|
|
26880
|
+
name: session.transportSession,
|
|
26881
|
+
agentSessionId
|
|
26882
|
+
});
|
|
26883
|
+
}
|
|
26170
26884
|
async prompt(session, text, reply, replyContext, options) {
|
|
26171
26885
|
const sink = reply ? createQuotaGatedReplySink({
|
|
26172
26886
|
reply,
|
|
@@ -26962,6 +27676,76 @@ function permissionModeToFlag(permissionMode) {
|
|
|
26962
27676
|
}
|
|
26963
27677
|
}
|
|
26964
27678
|
|
|
27679
|
+
// src/transport/agent-session-list.ts
|
|
27680
|
+
import path15 from "node:path";
|
|
27681
|
+
function isUnknownFilterCwdOption(output) {
|
|
27682
|
+
return /(?:unknown|unrecognized) option/i.test(output) && output.includes("--filter-cwd");
|
|
27683
|
+
}
|
|
27684
|
+
async function runAgentSessionList(options) {
|
|
27685
|
+
let result = await options.runList(true);
|
|
27686
|
+
let filterLocally = false;
|
|
27687
|
+
if (result.code !== 0 && options.filterCwd && isUnknownFilterCwdOption(result.stdout + result.stderr)) {
|
|
27688
|
+
result = await options.runList(false);
|
|
27689
|
+
filterLocally = true;
|
|
27690
|
+
}
|
|
27691
|
+
if (result.code !== 0) {
|
|
27692
|
+
if ((result.stdout + result.stderr).includes("sessionCapabilities.list")) {
|
|
27693
|
+
return;
|
|
27694
|
+
}
|
|
27695
|
+
throw new Error(options.formatError(result));
|
|
27696
|
+
}
|
|
27697
|
+
return parseAgentSessionListOutput(result.stdout, filterLocally ? options.filterCwd : undefined);
|
|
27698
|
+
}
|
|
27699
|
+
function parseAgentSessionListOutput(stdout2, filterCwd) {
|
|
27700
|
+
let parsed;
|
|
27701
|
+
try {
|
|
27702
|
+
parsed = JSON.parse(stdout2);
|
|
27703
|
+
} catch {
|
|
27704
|
+
throw new Error("failed to parse acpx sessions list output");
|
|
27705
|
+
}
|
|
27706
|
+
if (!isAgentSessionListResult(parsed)) {
|
|
27707
|
+
return;
|
|
27708
|
+
}
|
|
27709
|
+
return filterCwd ? filterAgentSessionListByCwd(parsed, filterCwd) : parsed;
|
|
27710
|
+
}
|
|
27711
|
+
function isAgentSessionListResult(value) {
|
|
27712
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
27713
|
+
return false;
|
|
27714
|
+
const record3 = value;
|
|
27715
|
+
if (record3.source !== "agent" || !Array.isArray(record3.sessions))
|
|
27716
|
+
return false;
|
|
27717
|
+
return record3.sessions.every((session) => {
|
|
27718
|
+
if (!session || typeof session !== "object" || Array.isArray(session))
|
|
27719
|
+
return false;
|
|
27720
|
+
const item = session;
|
|
27721
|
+
return typeof item.sessionId === "string";
|
|
27722
|
+
});
|
|
27723
|
+
}
|
|
27724
|
+
function filterAgentSessionListByCwd(result, cwd) {
|
|
27725
|
+
return {
|
|
27726
|
+
...result,
|
|
27727
|
+
sessions: result.sessions.filter((session) => session.cwd && sameAgentSessionCwd(session.cwd, cwd))
|
|
27728
|
+
};
|
|
27729
|
+
}
|
|
27730
|
+
function sameAgentSessionCwd(left, right) {
|
|
27731
|
+
const normalizedLeft = normalizeAgentSessionCwd(left);
|
|
27732
|
+
const normalizedRight = normalizeAgentSessionCwd(right);
|
|
27733
|
+
if (isWindowsLikePath2(normalizedLeft) || isWindowsLikePath2(normalizedRight)) {
|
|
27734
|
+
return normalizedLeft.toLowerCase() === normalizedRight.toLowerCase();
|
|
27735
|
+
}
|
|
27736
|
+
return normalizedLeft === normalizedRight;
|
|
27737
|
+
}
|
|
27738
|
+
function normalizeAgentSessionCwd(input) {
|
|
27739
|
+
if (isWindowsLikePath2(input)) {
|
|
27740
|
+
return path15.win32.normalize(input).replace(/\\/g, "/");
|
|
27741
|
+
}
|
|
27742
|
+
return path15.posix.normalize(input.replace(/\\/g, "/"));
|
|
27743
|
+
}
|
|
27744
|
+
function isWindowsLikePath2(input) {
|
|
27745
|
+
return /^[a-zA-Z]:[\\/]/.test(input) || input.startsWith("\\\\");
|
|
27746
|
+
}
|
|
27747
|
+
var init_agent_session_list = () => {};
|
|
27748
|
+
|
|
26965
27749
|
// src/transport/acpx-cli/acpx-cli-transport.ts
|
|
26966
27750
|
import { createRequire as createRequire5 } from "node:module";
|
|
26967
27751
|
import { spawn as spawn9 } from "node:child_process";
|
|
@@ -27071,6 +27855,23 @@ class AcpxCliTransport {
|
|
|
27071
27855
|
timeoutMs: this.sessionInitTimeoutMs
|
|
27072
27856
|
});
|
|
27073
27857
|
}
|
|
27858
|
+
async listAgentSessions(query) {
|
|
27859
|
+
return await runAgentSessionList({
|
|
27860
|
+
filterCwd: query.filterCwd,
|
|
27861
|
+
runList: async (includeFilterCwd) => {
|
|
27862
|
+
const args = this.buildAgentQueryArgs(query, "json", [
|
|
27863
|
+
"sessions",
|
|
27864
|
+
"list",
|
|
27865
|
+
...includeFilterCwd && query.filterCwd ? ["--filter-cwd", query.filterCwd] : [],
|
|
27866
|
+
...query.cursor ? ["--cursor", query.cursor] : []
|
|
27867
|
+
]);
|
|
27868
|
+
return await this.runCommandWithTimeout(this.runCommand, args, {
|
|
27869
|
+
timeoutMs: this.sessionInitTimeoutMs
|
|
27870
|
+
});
|
|
27871
|
+
},
|
|
27872
|
+
formatError: (result) => normalizeCommandError(result) ?? `command failed with exit code ${result.code}`
|
|
27873
|
+
});
|
|
27874
|
+
}
|
|
27074
27875
|
async tailSessionHistory(session, lines) {
|
|
27075
27876
|
const candidates = [
|
|
27076
27877
|
["sessions", "history", "quiet", "-s", session.transportSession, String(lines)],
|
|
@@ -27139,6 +27940,20 @@ ${baseText}` : "" };
|
|
|
27139
27940
|
message: output.trim()
|
|
27140
27941
|
};
|
|
27141
27942
|
}
|
|
27943
|
+
async resumeAgentSession(session, agentSessionId) {
|
|
27944
|
+
const args = this.buildArgs(session, [
|
|
27945
|
+
"sessions",
|
|
27946
|
+
"new",
|
|
27947
|
+
"--name",
|
|
27948
|
+
session.transportSession,
|
|
27949
|
+
"--resume-session",
|
|
27950
|
+
agentSessionId
|
|
27951
|
+
]);
|
|
27952
|
+
const runResume = session.agentCommand ? this.run : this.runWithPty;
|
|
27953
|
+
await runResume.call(this, args, {
|
|
27954
|
+
timeoutMs: this.sessionInitTimeoutMs
|
|
27955
|
+
});
|
|
27956
|
+
}
|
|
27142
27957
|
async updatePermissionPolicy(policy) {
|
|
27143
27958
|
this.permissionMode = policy.permissionMode;
|
|
27144
27959
|
this.nonInteractivePermissions = policy.nonInteractivePermissions;
|
|
@@ -27372,6 +28187,13 @@ ${baseText}` : "" };
|
|
|
27372
28187
|
}
|
|
27373
28188
|
return [...prefix, session.agent, ...tail2];
|
|
27374
28189
|
}
|
|
28190
|
+
buildAgentQueryArgs(query, format, tail2) {
|
|
28191
|
+
const prefix = ["--format", format, "--cwd", query.cwd, ...this.buildPermissionArgs()];
|
|
28192
|
+
if (query.agentCommand) {
|
|
28193
|
+
return [...prefix, "--agent", query.agentCommand, ...tail2];
|
|
28194
|
+
}
|
|
28195
|
+
return [...prefix, query.agent, ...tail2];
|
|
28196
|
+
}
|
|
27375
28197
|
buildPromptArgs(session, text, promptFile) {
|
|
27376
28198
|
const prefix = [
|
|
27377
28199
|
"--format",
|
|
@@ -27437,6 +28259,7 @@ var init_acpx_cli_transport = __esm(() => {
|
|
|
27437
28259
|
init_node_pty_helper();
|
|
27438
28260
|
init_terminate_process_tree();
|
|
27439
28261
|
init_acpx_queue_owner_launcher();
|
|
28262
|
+
init_agent_session_list();
|
|
27440
28263
|
require4 = createRequire5(import.meta.url);
|
|
27441
28264
|
});
|
|
27442
28265
|
|
|
@@ -27650,6 +28473,9 @@ class MessageChannelRegistry {
|
|
|
27650
28473
|
}
|
|
27651
28474
|
await channel.sendScheduledMessage(input);
|
|
27652
28475
|
}
|
|
28476
|
+
nativeSessionListFormat(chatKey) {
|
|
28477
|
+
return this.getByChatKey(chatKey)?.nativeSessionListFormat ?? "table";
|
|
28478
|
+
}
|
|
27653
28479
|
createConsumerLocks() {
|
|
27654
28480
|
const result = [];
|
|
27655
28481
|
for (const channel of this.channels.values()) {
|
|
@@ -28234,7 +29060,7 @@ async function buildApp(paths, deps = {}) {
|
|
|
28234
29060
|
listScheduledTasksFromRoute: async (input) => await listScheduledTasksFromRoute(input, { state, scheduled: scheduledService }),
|
|
28235
29061
|
cancelScheduledTaskFromRoute: async (input) => await cancelScheduledTaskFromRoute(input, { state, scheduled: scheduledService })
|
|
28236
29062
|
});
|
|
28237
|
-
const router = new CommandRouter(sessions, transport, config2, configStore, logger2, undefined, orchestration, quota, scheduledService, deps.channel?.supportsScheduledMessages ? { supportsScheduledMessages: deps.channel.supportsScheduledMessages.bind(deps.channel) } : undefined);
|
|
29063
|
+
const router = new CommandRouter(sessions, transport, config2, configStore, logger2, undefined, orchestration, quota, scheduledService, deps.channel?.supportsScheduledMessages ? { supportsScheduledMessages: deps.channel.supportsScheduledMessages.bind(deps.channel) } : undefined, deps.channel?.nativeSessionListFormat ? deps.channel.nativeSessionListFormat.bind(deps.channel) : undefined);
|
|
28238
29064
|
const agent = new ConsoleAgent(router, logger2);
|
|
28239
29065
|
const scheduledScheduler = new ScheduledTaskScheduler(scheduledService, {
|
|
28240
29066
|
dispatchTask: buildScheduledDispatchTask({
|
|
@@ -28825,107 +29651,107 @@ async function checkRuntime(options = {}) {
|
|
|
28825
29651
|
}
|
|
28826
29652
|
function createRuntimeFsProbe() {
|
|
28827
29653
|
return {
|
|
28828
|
-
stat: async (
|
|
28829
|
-
access: async (
|
|
29654
|
+
stat: async (path16) => await stat3(path16),
|
|
29655
|
+
access: async (path16, mode) => await access4(path16, mode)
|
|
28830
29656
|
};
|
|
28831
29657
|
}
|
|
28832
|
-
async function checkDirectoryCreatable(label,
|
|
29658
|
+
async function checkDirectoryCreatable(label, path16, probe, platform) {
|
|
28833
29659
|
try {
|
|
28834
|
-
const stats = await probe.stat(
|
|
29660
|
+
const stats = await probe.stat(path16);
|
|
28835
29661
|
if (!stats.isDirectory()) {
|
|
28836
29662
|
return {
|
|
28837
29663
|
ok: false,
|
|
28838
|
-
detail: `${label}: ${
|
|
29664
|
+
detail: `${label}: ${path16} (exists but is not a directory)`
|
|
28839
29665
|
};
|
|
28840
29666
|
}
|
|
28841
|
-
await probe.access(
|
|
29667
|
+
await probe.access(path16, directoryAccessMode(platform));
|
|
28842
29668
|
return {
|
|
28843
29669
|
ok: true,
|
|
28844
|
-
detail: `${label}: ${
|
|
29670
|
+
detail: `${label}: ${path16} (writable)`
|
|
28845
29671
|
};
|
|
28846
29672
|
} catch (error2) {
|
|
28847
29673
|
if (!isMissingPathError(error2)) {
|
|
28848
29674
|
return {
|
|
28849
29675
|
ok: false,
|
|
28850
|
-
detail: `${label}: ${
|
|
29676
|
+
detail: `${label}: ${path16} (unusable: ${formatError6(error2)})`
|
|
28851
29677
|
};
|
|
28852
29678
|
}
|
|
28853
|
-
const parentCheck = await checkCreatableAncestorDirectory(
|
|
29679
|
+
const parentCheck = await checkCreatableAncestorDirectory(path16, probe, platform);
|
|
28854
29680
|
if (!parentCheck.ok) {
|
|
28855
29681
|
return {
|
|
28856
29682
|
ok: false,
|
|
28857
|
-
detail: `${label}: ${
|
|
29683
|
+
detail: `${label}: ${path16} (parent not writable: ${parentCheck.blockingPath})`
|
|
28858
29684
|
};
|
|
28859
29685
|
}
|
|
28860
29686
|
return {
|
|
28861
29687
|
ok: true,
|
|
28862
|
-
detail: `${label}: ${
|
|
29688
|
+
detail: `${label}: ${path16} (creatable via ${parentCheck.creatableFrom})`
|
|
28863
29689
|
};
|
|
28864
29690
|
}
|
|
28865
29691
|
}
|
|
28866
|
-
async function checkFileCreatable(label,
|
|
29692
|
+
async function checkFileCreatable(label, path16, probe, platform) {
|
|
28867
29693
|
try {
|
|
28868
|
-
const stats = await probe.stat(
|
|
29694
|
+
const stats = await probe.stat(path16);
|
|
28869
29695
|
if (stats.isDirectory()) {
|
|
28870
29696
|
return {
|
|
28871
29697
|
ok: false,
|
|
28872
|
-
detail: `${label}: ${
|
|
29698
|
+
detail: `${label}: ${path16} (exists but is a directory)`
|
|
28873
29699
|
};
|
|
28874
29700
|
}
|
|
28875
|
-
await probe.access(
|
|
29701
|
+
await probe.access(path16, constants.W_OK);
|
|
28876
29702
|
return {
|
|
28877
29703
|
ok: true,
|
|
28878
|
-
detail: `${label}: ${
|
|
29704
|
+
detail: `${label}: ${path16} (writable)`
|
|
28879
29705
|
};
|
|
28880
29706
|
} catch (error2) {
|
|
28881
29707
|
if (!isMissingPathError(error2)) {
|
|
28882
29708
|
return {
|
|
28883
29709
|
ok: false,
|
|
28884
|
-
detail: `${label}: ${
|
|
29710
|
+
detail: `${label}: ${path16} (unusable: ${formatError6(error2)})`
|
|
28885
29711
|
};
|
|
28886
29712
|
}
|
|
28887
|
-
const parentCheck = await checkCreatableAncestorDirectory(dirname14(
|
|
29713
|
+
const parentCheck = await checkCreatableAncestorDirectory(dirname14(path16), probe, platform);
|
|
28888
29714
|
if (!parentCheck.ok) {
|
|
28889
29715
|
return {
|
|
28890
29716
|
ok: false,
|
|
28891
|
-
detail: `${label}: ${
|
|
29717
|
+
detail: `${label}: ${path16} (parent not writable: ${parentCheck.blockingPath})`
|
|
28892
29718
|
};
|
|
28893
29719
|
}
|
|
28894
29720
|
return {
|
|
28895
29721
|
ok: true,
|
|
28896
|
-
detail: `${label}: ${
|
|
29722
|
+
detail: `${label}: ${path16} (creatable via ${parentCheck.creatableFrom})`
|
|
28897
29723
|
};
|
|
28898
29724
|
}
|
|
28899
29725
|
}
|
|
28900
|
-
async function checkCreatableAncestorDirectory(
|
|
29726
|
+
async function checkCreatableAncestorDirectory(path16, probe, platform) {
|
|
28901
29727
|
try {
|
|
28902
|
-
const stats = await probe.stat(
|
|
29728
|
+
const stats = await probe.stat(path16);
|
|
28903
29729
|
if (!stats.isDirectory()) {
|
|
28904
29730
|
return {
|
|
28905
29731
|
ok: false,
|
|
28906
|
-
creatableFrom:
|
|
28907
|
-
blockingPath:
|
|
29732
|
+
creatableFrom: path16,
|
|
29733
|
+
blockingPath: path16
|
|
28908
29734
|
};
|
|
28909
29735
|
}
|
|
28910
|
-
await probe.access(
|
|
29736
|
+
await probe.access(path16, directoryAccessMode(platform));
|
|
28911
29737
|
return {
|
|
28912
29738
|
ok: true,
|
|
28913
|
-
creatableFrom:
|
|
29739
|
+
creatableFrom: path16
|
|
28914
29740
|
};
|
|
28915
29741
|
} catch (error2) {
|
|
28916
29742
|
if (!isMissingPathError(error2)) {
|
|
28917
29743
|
return {
|
|
28918
29744
|
ok: false,
|
|
28919
|
-
creatableFrom:
|
|
28920
|
-
blockingPath:
|
|
29745
|
+
creatableFrom: path16,
|
|
29746
|
+
blockingPath: path16
|
|
28921
29747
|
};
|
|
28922
29748
|
}
|
|
28923
|
-
const parent = dirname14(
|
|
28924
|
-
if (parent ===
|
|
29749
|
+
const parent = dirname14(path16);
|
|
29750
|
+
if (parent === path16) {
|
|
28925
29751
|
return {
|
|
28926
29752
|
ok: false,
|
|
28927
|
-
creatableFrom:
|
|
28928
|
-
blockingPath:
|
|
29753
|
+
creatableFrom: path16,
|
|
29754
|
+
blockingPath: path16
|
|
28929
29755
|
};
|
|
28930
29756
|
}
|
|
28931
29757
|
const parentCheck = await checkCreatableAncestorDirectory(parent, probe, platform);
|