@ganglion/xacpx 0.12.0 → 0.13.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/dist/bridge/bridge-main.js +61 -7
- package/dist/cli.js +254 -61
- package/dist/commands/handlers/session-handler.d.ts +1 -0
- package/dist/commands/parse-command.d.ts +3 -0
- package/dist/control/control-service.d.ts +8 -0
- package/dist/i18n/types.d.ts +4 -0
- package/dist/plugin-api.js +8 -0
- package/dist/sessions/session-service.d.ts +1 -0
- package/dist/state/types.d.ts +4 -0
- package/dist/transport/types.d.ts +12 -0
- package/package.json +1 -1
|
@@ -940,6 +940,7 @@ ${detail}`,
|
|
|
940
940
|
sessionBlockedByTasks: (alias, count) => `Session "${alias}" has ${count} unfinished task(s). Cancel or wait for them to complete first.`,
|
|
941
941
|
sessionBlockedByTasksHint: "Use /tasks to list tasks, or /task cancel <id> to cancel one.",
|
|
942
942
|
sessionRemoved: (alias) => `Session "${alias}" removed.`,
|
|
943
|
+
sessionArchived: (alias) => `Archived session "${alias}". Send a message to restore it.`,
|
|
943
944
|
sessionRemovedWasActive: "This was the active session. Its chat context has been cleared.",
|
|
944
945
|
sessionRemovedWasActivePromoted: (alias) => `This was the active session. Switched back to the previous session "${alias}".`,
|
|
945
946
|
sessionTransportShared: (transportSession, count) => `Note: backend session "${transportSession}" is still referenced by ${count} other session(s) and was not closed.`,
|
|
@@ -1697,6 +1698,9 @@ var init_channel_cli = __esm(() => {
|
|
|
1697
1698
|
channelAdded: (type) => `Channel ${type} added`,
|
|
1698
1699
|
cannotRemoveLastEnabled: "Cannot remove the last enabled channel.",
|
|
1699
1700
|
channelRemoved: (id) => `Channel ${id} removed`,
|
|
1701
|
+
channelCredentialsCleared: (id) => `Removed stored credentials for channel ${id}`,
|
|
1702
|
+
channelCredentialsClearFailed: (id, error) => `Channel ${id} removed, but clearing its stored credentials failed: ${error}`,
|
|
1703
|
+
channelCredentialsKept: (id) => `Kept stored credentials for channel ${id} (--keep-credentials)`,
|
|
1700
1704
|
cannotDisableLastEnabled: "Cannot disable the last enabled channel.",
|
|
1701
1705
|
channelEnabledToggled: (id, enabled) => `Channel ${id} ${enabled ? "enabled" : "disabled"}`,
|
|
1702
1706
|
channelReplyModeSet: (id, mode) => `Channel ${id} default reply mode set to: ${mode}`,
|
|
@@ -2032,6 +2036,7 @@ ${detail}`,
|
|
|
2032
2036
|
sessionBlockedByTasks: (alias, count) => `会话「${alias}」下还有 ${count} 个未结束的任务,请先取消或等待完成。`,
|
|
2033
2037
|
sessionBlockedByTasksHint: "使用 /tasks 查看任务列表,或 /task cancel <id> 取消任务。",
|
|
2034
2038
|
sessionRemoved: (alias) => `已删除会话「${alias}」。`,
|
|
2039
|
+
sessionArchived: (alias) => `已归档会话「${alias}」。发送消息即可恢复。`,
|
|
2035
2040
|
sessionRemovedWasActive: "该会话是当前活跃会话,已自动清除相关聊天上下文。",
|
|
2036
2041
|
sessionRemovedWasActivePromoted: (alias) => `该会话是当前活跃会话,已切换回上一个会话「${alias}」。`,
|
|
2037
2042
|
sessionTransportShared: (transportSession, count) => `提示:后端会话「${transportSession}」仍被其他 ${count} 个会话引用,未关闭。`,
|
|
@@ -2789,6 +2794,9 @@ var init_channel_cli2 = __esm(() => {
|
|
|
2789
2794
|
channelAdded: (type) => `频道 ${type} 已添加`,
|
|
2790
2795
|
cannotRemoveLastEnabled: "不能删除最后一个启用的频道。",
|
|
2791
2796
|
channelRemoved: (id) => `频道 ${id} 已删除`,
|
|
2797
|
+
channelCredentialsCleared: (id) => `已移除频道 ${id} 的存储凭证`,
|
|
2798
|
+
channelCredentialsClearFailed: (id, error) => `频道 ${id} 已删除,但清除其存储凭证失败:${error}`,
|
|
2799
|
+
channelCredentialsKept: (id) => `已保留频道 ${id} 的存储凭证(--keep-credentials)`,
|
|
2792
2800
|
cannotDisableLastEnabled: "不能禁用最后一个启用的频道。",
|
|
2793
2801
|
channelEnabledToggled: (id, enabled) => `频道 ${id} 已${enabled ? "启用" : "禁用"}`,
|
|
2794
2802
|
channelReplyModeSet: (id, mode) => `频道 ${id} 的默认 reply mode 已设置为:${mode}`,
|
|
@@ -3418,6 +3426,31 @@ var init_agent_session_list = __esm(() => {
|
|
|
3418
3426
|
init_path();
|
|
3419
3427
|
});
|
|
3420
3428
|
|
|
3429
|
+
// src/transport/acpx-session-files.ts
|
|
3430
|
+
import { readdir, unlink as unlink2 } from "node:fs/promises";
|
|
3431
|
+
import { homedir as homedir4 } from "node:os";
|
|
3432
|
+
import { join as join3 } from "node:path";
|
|
3433
|
+
async function deleteAcpxSessionFiles(options) {
|
|
3434
|
+
const dir = options.sessionsDir ?? join3(homedir4(), ".acpx", "sessions");
|
|
3435
|
+
const safeId = encodeURIComponent(options.acpxRecordId);
|
|
3436
|
+
await unlink2(join3(dir, `${safeId}.json`)).catch(() => {
|
|
3437
|
+
return;
|
|
3438
|
+
});
|
|
3439
|
+
let entries;
|
|
3440
|
+
try {
|
|
3441
|
+
entries = await readdir(dir);
|
|
3442
|
+
} catch {
|
|
3443
|
+
return;
|
|
3444
|
+
}
|
|
3445
|
+
const streamFiles = entries.filter((name) => name.startsWith(`${safeId}.stream.`));
|
|
3446
|
+
for (const name of streamFiles) {
|
|
3447
|
+
await unlink2(join3(dir, name)).catch(() => {
|
|
3448
|
+
return;
|
|
3449
|
+
});
|
|
3450
|
+
}
|
|
3451
|
+
}
|
|
3452
|
+
var init_acpx_session_files = () => {};
|
|
3453
|
+
|
|
3421
3454
|
// src/bridge/bridge-main.ts
|
|
3422
3455
|
import { createInterface } from "node:readline";
|
|
3423
3456
|
|
|
@@ -3490,9 +3523,9 @@ init_terminate_process_tree();
|
|
|
3490
3523
|
init_prompt_output();
|
|
3491
3524
|
init_prompt_media();
|
|
3492
3525
|
init_streaming_prompt();
|
|
3493
|
-
import { copyFile, readdir } from "node:fs/promises";
|
|
3494
|
-
import { homedir as
|
|
3495
|
-
import { dirname as dirname2, join as
|
|
3526
|
+
import { copyFile, readdir as readdir2 } from "node:fs/promises";
|
|
3527
|
+
import { homedir as homedir5 } from "node:os";
|
|
3528
|
+
import { dirname as dirname2, join as join4, win32 } from "node:path";
|
|
3496
3529
|
import { spawn as spawn4 } from "node:child_process";
|
|
3497
3530
|
|
|
3498
3531
|
// src/bridge/parse-missing-optional-dep.ts
|
|
@@ -3512,6 +3545,7 @@ function parseMissingOptionalDep(text) {
|
|
|
3512
3545
|
init_discover_parent_package_paths();
|
|
3513
3546
|
init_acpx_queue_owner_launcher();
|
|
3514
3547
|
init_agent_session_list();
|
|
3548
|
+
init_acpx_session_files();
|
|
3515
3549
|
class EnsureSessionFailedError extends Error {
|
|
3516
3550
|
kind;
|
|
3517
3551
|
data;
|
|
@@ -3792,7 +3826,7 @@ class BridgeRuntime {
|
|
|
3792
3826
|
acpxRecordId = parsed.id;
|
|
3793
3827
|
}
|
|
3794
3828
|
const agentSessionId = typeof parsed.agentSessionId === "string" ? parsed.agentSessionId : undefined;
|
|
3795
|
-
if (acpxRecordId) {
|
|
3829
|
+
if (acpxRecordId && /^[\w.:-]+$/.test(acpxRecordId) && acpxRecordId.length >= 8) {
|
|
3796
3830
|
return { acpxRecordId, agentSessionId };
|
|
3797
3831
|
}
|
|
3798
3832
|
} catch {
|
|
@@ -3884,6 +3918,17 @@ class BridgeRuntime {
|
|
|
3884
3918
|
}
|
|
3885
3919
|
throw new Error(result.stderr || result.stdout || "sessions close failed");
|
|
3886
3920
|
}
|
|
3921
|
+
async deleteSession(input) {
|
|
3922
|
+
let acpxRecordId;
|
|
3923
|
+
try {
|
|
3924
|
+
({ acpxRecordId } = await this.readSessionRecord(input));
|
|
3925
|
+
} catch {
|
|
3926
|
+
return {};
|
|
3927
|
+
}
|
|
3928
|
+
await this.removeSession(input);
|
|
3929
|
+
await deleteAcpxSessionFiles({ acpxRecordId });
|
|
3930
|
+
return {};
|
|
3931
|
+
}
|
|
3887
3932
|
async shutdown() {
|
|
3888
3933
|
return {};
|
|
3889
3934
|
}
|
|
@@ -4074,14 +4119,14 @@ async function tryRepairAcpxSessionIndex(deps = {}) {
|
|
|
4074
4119
|
if (platform !== "win32") {
|
|
4075
4120
|
return false;
|
|
4076
4121
|
}
|
|
4077
|
-
const home = deps.home ?? process.env.HOME ?? process.env.USERPROFILE ??
|
|
4122
|
+
const home = deps.home ?? process.env.HOME ?? process.env.USERPROFILE ?? homedir5();
|
|
4078
4123
|
if (!home) {
|
|
4079
4124
|
return false;
|
|
4080
4125
|
}
|
|
4081
|
-
const pathJoin = platform === "win32" ? win32.join :
|
|
4126
|
+
const pathJoin = platform === "win32" ? win32.join : join4;
|
|
4082
4127
|
const sessionsDir = pathJoin(home, ".acpx", "sessions");
|
|
4083
4128
|
const indexPath = pathJoin(sessionsDir, "index.json");
|
|
4084
|
-
const readdirFn = deps.readdirFn ??
|
|
4129
|
+
const readdirFn = deps.readdirFn ?? readdir2;
|
|
4085
4130
|
const copyFileFn = deps.copyFileFn ?? copyFile;
|
|
4086
4131
|
let files;
|
|
4087
4132
|
try {
|
|
@@ -4129,6 +4174,7 @@ var BRIDGE_METHODS = new Set([
|
|
|
4129
4174
|
"getSessionModel",
|
|
4130
4175
|
"cancel",
|
|
4131
4176
|
"removeSession",
|
|
4177
|
+
"deleteSession",
|
|
4132
4178
|
"getAgentSessionId"
|
|
4133
4179
|
]);
|
|
4134
4180
|
var SESSION_SCOPED_METHODS = new Set([
|
|
@@ -4142,6 +4188,7 @@ var SESSION_SCOPED_METHODS = new Set([
|
|
|
4142
4188
|
"getSessionModel",
|
|
4143
4189
|
"cancel",
|
|
4144
4190
|
"removeSession",
|
|
4191
|
+
"deleteSession",
|
|
4145
4192
|
"getAgentSessionId"
|
|
4146
4193
|
]);
|
|
4147
4194
|
|
|
@@ -4349,6 +4396,13 @@ class BridgeServer {
|
|
|
4349
4396
|
cwd: requireString(params, "cwd"),
|
|
4350
4397
|
name: requireString(params, "name")
|
|
4351
4398
|
});
|
|
4399
|
+
case "deleteSession":
|
|
4400
|
+
return await this.runtime.deleteSession({
|
|
4401
|
+
agent: requireString(params, "agent"),
|
|
4402
|
+
agentCommand: asOptionalString(params.agentCommand),
|
|
4403
|
+
cwd: requireString(params, "cwd"),
|
|
4404
|
+
name: requireString(params, "name")
|
|
4405
|
+
});
|
|
4352
4406
|
case "getAgentSessionId":
|
|
4353
4407
|
return await this.runtime.getAgentSessionId({
|
|
4354
4408
|
agent: requireString(params, "agent"),
|
package/dist/cli.js
CHANGED
|
@@ -141,6 +141,7 @@ ${detail}`,
|
|
|
141
141
|
sessionBlockedByTasks: (alias, count) => `Session "${alias}" has ${count} unfinished task(s). Cancel or wait for them to complete first.`,
|
|
142
142
|
sessionBlockedByTasksHint: "Use /tasks to list tasks, or /task cancel <id> to cancel one.",
|
|
143
143
|
sessionRemoved: (alias) => `Session "${alias}" removed.`,
|
|
144
|
+
sessionArchived: (alias) => `Archived session "${alias}". Send a message to restore it.`,
|
|
144
145
|
sessionRemovedWasActive: "This was the active session. Its chat context has been cleared.",
|
|
145
146
|
sessionRemovedWasActivePromoted: (alias) => `This was the active session. Switched back to the previous session "${alias}".`,
|
|
146
147
|
sessionTransportShared: (transportSession, count) => `Note: backend session "${transportSession}" is still referenced by ${count} other session(s) and was not closed.`,
|
|
@@ -898,6 +899,9 @@ var init_channel_cli = __esm(() => {
|
|
|
898
899
|
channelAdded: (type) => `Channel ${type} added`,
|
|
899
900
|
cannotRemoveLastEnabled: "Cannot remove the last enabled channel.",
|
|
900
901
|
channelRemoved: (id) => `Channel ${id} removed`,
|
|
902
|
+
channelCredentialsCleared: (id) => `Removed stored credentials for channel ${id}`,
|
|
903
|
+
channelCredentialsClearFailed: (id, error) => `Channel ${id} removed, but clearing its stored credentials failed: ${error}`,
|
|
904
|
+
channelCredentialsKept: (id) => `Kept stored credentials for channel ${id} (--keep-credentials)`,
|
|
901
905
|
cannotDisableLastEnabled: "Cannot disable the last enabled channel.",
|
|
902
906
|
channelEnabledToggled: (id, enabled) => `Channel ${id} ${enabled ? "enabled" : "disabled"}`,
|
|
903
907
|
channelReplyModeSet: (id, mode) => `Channel ${id} default reply mode set to: ${mode}`,
|
|
@@ -1233,6 +1237,7 @@ ${detail}`,
|
|
|
1233
1237
|
sessionBlockedByTasks: (alias, count) => `会话「${alias}」下还有 ${count} 个未结束的任务,请先取消或等待完成。`,
|
|
1234
1238
|
sessionBlockedByTasksHint: "使用 /tasks 查看任务列表,或 /task cancel <id> 取消任务。",
|
|
1235
1239
|
sessionRemoved: (alias) => `已删除会话「${alias}」。`,
|
|
1240
|
+
sessionArchived: (alias) => `已归档会话「${alias}」。发送消息即可恢复。`,
|
|
1236
1241
|
sessionRemovedWasActive: "该会话是当前活跃会话,已自动清除相关聊天上下文。",
|
|
1237
1242
|
sessionRemovedWasActivePromoted: (alias) => `该会话是当前活跃会话,已切换回上一个会话「${alias}」。`,
|
|
1238
1243
|
sessionTransportShared: (transportSession, count) => `提示:后端会话「${transportSession}」仍被其他 ${count} 个会话引用,未关闭。`,
|
|
@@ -1990,6 +1995,9 @@ var init_channel_cli2 = __esm(() => {
|
|
|
1990
1995
|
channelAdded: (type) => `频道 ${type} 已添加`,
|
|
1991
1996
|
cannotRemoveLastEnabled: "不能删除最后一个启用的频道。",
|
|
1992
1997
|
channelRemoved: (id) => `频道 ${id} 已删除`,
|
|
1998
|
+
channelCredentialsCleared: (id) => `已移除频道 ${id} 的存储凭证`,
|
|
1999
|
+
channelCredentialsClearFailed: (id, error) => `频道 ${id} 已删除,但清除其存储凭证失败:${error}`,
|
|
2000
|
+
channelCredentialsKept: (id) => `已保留频道 ${id} 的存储凭证(--keep-credentials)`,
|
|
1993
2001
|
cannotDisableLastEnabled: "不能禁用最后一个启用的频道。",
|
|
1994
2002
|
channelEnabledToggled: (id, enabled) => `频道 ${id} 已${enabled ? "启用" : "禁用"}`,
|
|
1995
2003
|
channelReplyModeSet: (id, mode) => `频道 ${id} 的默认 reply mode 已设置为:${mode}`,
|
|
@@ -4689,6 +4697,7 @@ function parseConfig(raw, options = {}) {
|
|
|
4689
4697
|
...typeof transport.command === "string" ? { command: transport.command } : {},
|
|
4690
4698
|
...typeof transport.sessionInitTimeoutMs === "number" ? { sessionInitTimeoutMs: transport.sessionInitTimeoutMs } : {},
|
|
4691
4699
|
...typeof transport.permissionPolicy === "string" ? { permissionPolicy: transport.permissionPolicy } : {},
|
|
4700
|
+
...typeof transport.preferLocalAgents === "boolean" ? { preferLocalAgents: transport.preferLocalAgents } : {},
|
|
4692
4701
|
type: transportType,
|
|
4693
4702
|
permissionMode,
|
|
4694
4703
|
nonInteractivePermissions,
|
|
@@ -20393,6 +20402,9 @@ function parseCommand(input) {
|
|
|
20393
20402
|
if (command === "/session" && parts[1] === "rm" && parts[2] && parts.length === 3) {
|
|
20394
20403
|
return { kind: "session.rm", alias: parts[2] };
|
|
20395
20404
|
}
|
|
20405
|
+
if (command === "/session" && parts[1] === "archive" && parts[2] && parts.length === 3) {
|
|
20406
|
+
return { kind: "session.archive", alias: parts[2] };
|
|
20407
|
+
}
|
|
20396
20408
|
if (command === "/ssn") {
|
|
20397
20409
|
if (parts.length === 1) {
|
|
20398
20410
|
return { kind: "session.native.list" };
|
|
@@ -20639,7 +20651,7 @@ function parseCommand(input) {
|
|
|
20639
20651
|
return { kind: "session.shortcut.new", agent: parts[2], ...shortcutTarget };
|
|
20640
20652
|
}
|
|
20641
20653
|
}
|
|
20642
|
-
if (command === "/session" && parts[1] && parts[1] !== "new" && parts[1] !== "attach" && parts[1] !== "reset" && parts[1] !== "rm") {
|
|
20654
|
+
if (command === "/session" && parts[1] && parts[1] !== "new" && parts[1] !== "attach" && parts[1] !== "reset" && parts[1] !== "rm" && parts[1] !== "archive") {
|
|
20643
20655
|
const shortcutTarget = readSessionShortcutTarget(parts, 2);
|
|
20644
20656
|
if (shortcutTarget) {
|
|
20645
20657
|
return { kind: "session.shortcut", agent: parts[1], ...shortcutTarget };
|
|
@@ -21103,6 +21115,7 @@ var init_command_policy = __esm(() => {
|
|
|
21103
21115
|
COMMAND_KIND_TO_LABEL = {
|
|
21104
21116
|
"session.reset": "/clear",
|
|
21105
21117
|
"session.rm": "/session rm",
|
|
21118
|
+
"session.archive": "/session archive",
|
|
21106
21119
|
"session.tail": "/session tail",
|
|
21107
21120
|
"replymode.set": "/replymode",
|
|
21108
21121
|
"replymode.reset": "/replymode reset",
|
|
@@ -22320,9 +22333,9 @@ async function handleSessionRemove(context, chatKey, alias) {
|
|
|
22320
22333
|
}
|
|
22321
22334
|
let transportTeardownWarning;
|
|
22322
22335
|
const shouldTeardownTransport = sharedAliasCount === 0;
|
|
22323
|
-
if (shouldTeardownTransport && context.transport.
|
|
22336
|
+
if (shouldTeardownTransport && context.transport.deleteSession) {
|
|
22324
22337
|
try {
|
|
22325
|
-
await context.transport.
|
|
22338
|
+
await context.transport.deleteSession(session3);
|
|
22326
22339
|
} catch (error2) {
|
|
22327
22340
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
22328
22341
|
transportTeardownWarning = message;
|
|
@@ -22355,7 +22368,19 @@ async function handleSessionRemove(context, chatKey, alias) {
|
|
|
22355
22368
|
return { text: lines.join(`
|
|
22356
22369
|
`) };
|
|
22357
22370
|
}
|
|
22371
|
+
async function handleSessionArchive(context, chatKey, alias, archive) {
|
|
22372
|
+
const internalAlias = await context.sessions.resolveAliasForChat(chatKey, alias);
|
|
22373
|
+
const session3 = await context.sessions.getSession(internalAlias);
|
|
22374
|
+
if (!session3) {
|
|
22375
|
+
return { text: t().session.sessionNotFound(alias) };
|
|
22376
|
+
}
|
|
22377
|
+
await archive(internalAlias);
|
|
22378
|
+
return { text: t().session.sessionArchived(alias) };
|
|
22379
|
+
}
|
|
22358
22380
|
async function promptWithSession(context, session3, chatKey, text, reply, replyContextToken, accountId, media, abortSignal, onToolEvent, onThought, perfSpan, metadata, onPlan, onUsage) {
|
|
22381
|
+
if (session3.archived) {
|
|
22382
|
+
await context.sessions.setArchived(session3.alias, false);
|
|
22383
|
+
}
|
|
22359
22384
|
const effectiveReplyMode = resolveEffectiveReplyMode(context.config, chatKey, session3.replyMode);
|
|
22360
22385
|
if (!session3.replyMode)
|
|
22361
22386
|
session3.replyMode = effectiveReplyMode;
|
|
@@ -24789,6 +24814,8 @@ class CommandRouter {
|
|
|
24789
24814
|
return await handleSessionTail(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.lines);
|
|
24790
24815
|
case "session.rm":
|
|
24791
24816
|
return await handleSessionRemove(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.alias);
|
|
24817
|
+
case "session.archive":
|
|
24818
|
+
return await handleSessionArchive(this.createSessionHandlerContext(undefined, perfSpan), chatKey, command.alias, (internalAlias) => this.archiveSessionWithTransport(internalAlias));
|
|
24792
24819
|
case "groups":
|
|
24793
24820
|
return await handleGroupList(this.createHandlerContext(), chatKey, command.filter);
|
|
24794
24821
|
case "group.new":
|
|
@@ -24937,6 +24964,82 @@ class CommandRouter {
|
|
|
24937
24964
|
await release();
|
|
24938
24965
|
}
|
|
24939
24966
|
}
|
|
24967
|
+
async removeSessionWithTransport(internalAlias) {
|
|
24968
|
+
const session3 = await this.sessions.getSession(internalAlias);
|
|
24969
|
+
if (!session3) {
|
|
24970
|
+
throw new Error(`session "${internalAlias}" does not exist`);
|
|
24971
|
+
}
|
|
24972
|
+
if (this.orchestration) {
|
|
24973
|
+
const blocking = await this.orchestration.listSessionBlockingTasks(session3.transportSession);
|
|
24974
|
+
if (blocking.length > 0) {
|
|
24975
|
+
throw new Error(`session "${internalAlias}" has ${blocking.length} blocking task(s); cancel them before deleting`);
|
|
24976
|
+
}
|
|
24977
|
+
}
|
|
24978
|
+
const sharedAliasCount = this.sessions.countAliasesSharingTransport(session3.transportSession, internalAlias);
|
|
24979
|
+
const { wasActive } = await this.sessions.removeSession(internalAlias);
|
|
24980
|
+
if (this.orchestration) {
|
|
24981
|
+
try {
|
|
24982
|
+
await this.orchestration.purgeSessionReferences(session3.transportSession);
|
|
24983
|
+
} catch (error2) {
|
|
24984
|
+
await this.logger.error("session.orchestration_purge_failed", "failed to purge orchestration references after web remove", {
|
|
24985
|
+
alias: internalAlias,
|
|
24986
|
+
transportSession: session3.transportSession,
|
|
24987
|
+
message: error2 instanceof Error ? error2.message : String(error2)
|
|
24988
|
+
});
|
|
24989
|
+
}
|
|
24990
|
+
}
|
|
24991
|
+
let transportTornDown = false;
|
|
24992
|
+
let transportTeardownWarning;
|
|
24993
|
+
if (sharedAliasCount === 0 && this.transport.deleteSession) {
|
|
24994
|
+
try {
|
|
24995
|
+
await this.transport.deleteSession(session3);
|
|
24996
|
+
transportTornDown = true;
|
|
24997
|
+
} catch (error2) {
|
|
24998
|
+
transportTeardownWarning = error2 instanceof Error ? error2.message : String(error2);
|
|
24999
|
+
await this.logger.error("session.transport_delete_failed", "failed to delete acpx session after logical remove", {
|
|
25000
|
+
alias: internalAlias,
|
|
25001
|
+
transportSession: session3.transportSession,
|
|
25002
|
+
message: transportTeardownWarning
|
|
25003
|
+
});
|
|
25004
|
+
}
|
|
25005
|
+
}
|
|
25006
|
+
return {
|
|
25007
|
+
wasActive,
|
|
25008
|
+
sharedAliasCount,
|
|
25009
|
+
transportTornDown,
|
|
25010
|
+
...transportTeardownWarning ? { transportTeardownWarning } : {}
|
|
25011
|
+
};
|
|
25012
|
+
}
|
|
25013
|
+
async archiveSessionWithTransport(internalAlias) {
|
|
25014
|
+
const session3 = await this.sessions.getSession(internalAlias);
|
|
25015
|
+
if (!session3) {
|
|
25016
|
+
throw new Error(`session "${internalAlias}" does not exist`);
|
|
25017
|
+
}
|
|
25018
|
+
if (this.activeTurns?.isActiveAnywhere(internalAlias)) {
|
|
25019
|
+
throw new Error(`session "${internalAlias}" has a running turn; stop it before archiving`);
|
|
25020
|
+
}
|
|
25021
|
+
const shared = this.sessions.countAliasesSharingTransport(session3.transportSession, internalAlias) > 0;
|
|
25022
|
+
if (!shared) {
|
|
25023
|
+
try {
|
|
25024
|
+
await this.transport.cancel(session3);
|
|
25025
|
+
} catch {}
|
|
25026
|
+
if (this.transport.removeSession) {
|
|
25027
|
+
try {
|
|
25028
|
+
await this.transport.removeSession(session3);
|
|
25029
|
+
} catch (error2) {
|
|
25030
|
+
await this.logger.error("session.archive_close_failed", "failed to close acpx session on archive", {
|
|
25031
|
+
alias: internalAlias,
|
|
25032
|
+
transportSession: session3.transportSession,
|
|
25033
|
+
message: error2 instanceof Error ? error2.message : String(error2)
|
|
25034
|
+
});
|
|
25035
|
+
}
|
|
25036
|
+
}
|
|
25037
|
+
}
|
|
25038
|
+
await this.sessions.setArchived(internalAlias, true);
|
|
25039
|
+
}
|
|
25040
|
+
async unarchiveSession(internalAlias) {
|
|
25041
|
+
await this.sessions.setArchived(internalAlias, false);
|
|
25042
|
+
}
|
|
24940
25043
|
async listNativeSessionsForControl(agent3, workspace3) {
|
|
24941
25044
|
const listAgentSessions = this.transport.listAgentSessions?.bind(this.transport);
|
|
24942
25045
|
if (!listAgentSessions)
|
|
@@ -29653,6 +29756,10 @@ class SessionService {
|
|
|
29653
29756
|
const previousCurrent = prevCtx?.current_session;
|
|
29654
29757
|
const carriedPrevious = previousCurrent && previousCurrent !== internalAlias ? previousCurrent : prevCtx?.previous_session;
|
|
29655
29758
|
session3.last_used_at = new Date().toISOString();
|
|
29759
|
+
if (session3.archived) {
|
|
29760
|
+
delete session3.archived;
|
|
29761
|
+
delete session3.archived_at;
|
|
29762
|
+
}
|
|
29656
29763
|
const nextCtx = { ...prevCtx, current_session: internalAlias };
|
|
29657
29764
|
if (carriedPrevious) {
|
|
29658
29765
|
nextCtx.previous_session = carriedPrevious;
|
|
@@ -29854,6 +29961,22 @@ class SessionService {
|
|
|
29854
29961
|
}
|
|
29855
29962
|
return count;
|
|
29856
29963
|
}
|
|
29964
|
+
async setArchived(alias, archived) {
|
|
29965
|
+
await this.mutate(async () => {
|
|
29966
|
+
const session3 = this.state.sessions[alias];
|
|
29967
|
+
if (!session3) {
|
|
29968
|
+
throw new Error(`session "${alias}" does not exist`);
|
|
29969
|
+
}
|
|
29970
|
+
if (archived) {
|
|
29971
|
+
session3.archived = true;
|
|
29972
|
+
session3.archived_at = new Date(this.now()).toISOString();
|
|
29973
|
+
} else {
|
|
29974
|
+
delete session3.archived;
|
|
29975
|
+
delete session3.archived_at;
|
|
29976
|
+
}
|
|
29977
|
+
await this.persist();
|
|
29978
|
+
});
|
|
29979
|
+
}
|
|
29857
29980
|
async removeSession(alias) {
|
|
29858
29981
|
return await this.mutate(async () => {
|
|
29859
29982
|
const session3 = this.state.sessions[alias];
|
|
@@ -29968,7 +30091,8 @@ class SessionService {
|
|
|
29968
30091
|
modeId: session3.mode_id,
|
|
29969
30092
|
replyMode: session3.reply_mode,
|
|
29970
30093
|
effectiveReplyMode,
|
|
29971
|
-
cwd: workspaceConfig.cwd
|
|
30094
|
+
cwd: workspaceConfig.cwd,
|
|
30095
|
+
archived: session3.archived === true
|
|
29972
30096
|
};
|
|
29973
30097
|
}
|
|
29974
30098
|
async setSessionModel(alias, modelId) {
|
|
@@ -31385,6 +31509,9 @@ ${result.text}` : "" };
|
|
|
31385
31509
|
async removeSession(session3) {
|
|
31386
31510
|
await this.client.request("removeSession", this.toParams(session3));
|
|
31387
31511
|
}
|
|
31512
|
+
async deleteSession(session3) {
|
|
31513
|
+
await this.client.request("deleteSession", this.toParams(session3));
|
|
31514
|
+
}
|
|
31388
31515
|
async getAgentSessionId(session3) {
|
|
31389
31516
|
const result = await this.client.request("getAgentSessionId", this.toParams(session3));
|
|
31390
31517
|
return result.agentSessionId;
|
|
@@ -31953,6 +32080,31 @@ var init_agent_session_list = __esm(() => {
|
|
|
31953
32080
|
init_path();
|
|
31954
32081
|
});
|
|
31955
32082
|
|
|
32083
|
+
// src/transport/acpx-session-files.ts
|
|
32084
|
+
import { readdir as readdir3, unlink as unlink2 } from "node:fs/promises";
|
|
32085
|
+
import { homedir as homedir9 } from "node:os";
|
|
32086
|
+
import { join as join19 } from "node:path";
|
|
32087
|
+
async function deleteAcpxSessionFiles(options) {
|
|
32088
|
+
const dir = options.sessionsDir ?? join19(homedir9(), ".acpx", "sessions");
|
|
32089
|
+
const safeId = encodeURIComponent(options.acpxRecordId);
|
|
32090
|
+
await unlink2(join19(dir, `${safeId}.json`)).catch(() => {
|
|
32091
|
+
return;
|
|
32092
|
+
});
|
|
32093
|
+
let entries;
|
|
32094
|
+
try {
|
|
32095
|
+
entries = await readdir3(dir);
|
|
32096
|
+
} catch {
|
|
32097
|
+
return;
|
|
32098
|
+
}
|
|
32099
|
+
const streamFiles = entries.filter((name) => name.startsWith(`${safeId}.stream.`));
|
|
32100
|
+
for (const name of streamFiles) {
|
|
32101
|
+
await unlink2(join19(dir, name)).catch(() => {
|
|
32102
|
+
return;
|
|
32103
|
+
});
|
|
32104
|
+
}
|
|
32105
|
+
}
|
|
32106
|
+
var init_acpx_session_files = () => {};
|
|
32107
|
+
|
|
31956
32108
|
// src/transport/acpx-cli/acpx-cli-transport.ts
|
|
31957
32109
|
import { createRequire as createRequire5 } from "node:module";
|
|
31958
32110
|
import { spawn as spawn9 } from "node:child_process";
|
|
@@ -32211,6 +32363,16 @@ ${baseText}` : "" };
|
|
|
32211
32363
|
const detail = normalizeCommandError(result) ?? `command failed with exit code ${result.code}`;
|
|
32212
32364
|
throw new Error(detail);
|
|
32213
32365
|
}
|
|
32366
|
+
async deleteSession(session3) {
|
|
32367
|
+
let acpxRecordId;
|
|
32368
|
+
try {
|
|
32369
|
+
({ acpxRecordId } = await this.readSessionRecord(session3));
|
|
32370
|
+
} catch {
|
|
32371
|
+
return;
|
|
32372
|
+
}
|
|
32373
|
+
await this.removeSession(session3);
|
|
32374
|
+
await deleteAcpxSessionFiles({ acpxRecordId });
|
|
32375
|
+
}
|
|
32214
32376
|
async hasSession(session3) {
|
|
32215
32377
|
const result = await this.runCommand(this.command, this.buildArgs(session3, [
|
|
32216
32378
|
"sessions",
|
|
@@ -32247,7 +32409,7 @@ ${baseText}` : "" };
|
|
|
32247
32409
|
const parsed = JSON.parse(result.stdout);
|
|
32248
32410
|
const acpxRecordId = typeof parsed.acpxRecordId === "string" ? parsed.acpxRecordId : typeof parsed.id === "string" ? parsed.id : undefined;
|
|
32249
32411
|
const agentSessionId = typeof parsed.agentSessionId === "string" ? parsed.agentSessionId : undefined;
|
|
32250
|
-
if (acpxRecordId) {
|
|
32412
|
+
if (acpxRecordId && /^[\w.:-]+$/.test(acpxRecordId) && acpxRecordId.length >= 8) {
|
|
32251
32413
|
return { acpxRecordId, agentSessionId };
|
|
32252
32414
|
}
|
|
32253
32415
|
} catch {
|
|
@@ -32526,6 +32688,7 @@ var init_acpx_cli_transport = __esm(() => {
|
|
|
32526
32688
|
init_terminate_process_tree();
|
|
32527
32689
|
init_acpx_queue_owner_launcher();
|
|
32528
32690
|
init_agent_session_list();
|
|
32691
|
+
init_acpx_session_files();
|
|
32529
32692
|
require4 = createRequire5(import.meta.url);
|
|
32530
32693
|
});
|
|
32531
32694
|
|
|
@@ -32997,8 +33160,8 @@ function createControlEventBus(logger2) {
|
|
|
32997
33160
|
|
|
32998
33161
|
// src/transport/native-session-history.ts
|
|
32999
33162
|
import { readFile as readFile14 } from "node:fs/promises";
|
|
33000
|
-
import { homedir as
|
|
33001
|
-
import { join as
|
|
33163
|
+
import { homedir as homedir10 } from "node:os";
|
|
33164
|
+
import { join as join20 } from "node:path";
|
|
33002
33165
|
function classifyToolKind(name) {
|
|
33003
33166
|
const n = name.toLowerCase();
|
|
33004
33167
|
if (/(^|[^a-z])(read|cat|view|open)([^a-z]|$)/.test(n))
|
|
@@ -33110,8 +33273,8 @@ function mapAcpxMessagesToHistory(raw) {
|
|
|
33110
33273
|
}
|
|
33111
33274
|
async function readNativeSessionHistory(opts) {
|
|
33112
33275
|
try {
|
|
33113
|
-
const dir = opts.sessionsDir ??
|
|
33114
|
-
const indexRaw = await readFile14(
|
|
33276
|
+
const dir = opts.sessionsDir ?? join20(opts.homeDir ?? homedir10(), ".acpx", "sessions");
|
|
33277
|
+
const indexRaw = await readFile14(join20(dir, "index.json"), "utf8").catch(() => null);
|
|
33115
33278
|
if (!indexRaw)
|
|
33116
33279
|
return [];
|
|
33117
33280
|
const index = JSON.parse(indexRaw);
|
|
@@ -33120,7 +33283,7 @@ async function readNativeSessionHistory(opts) {
|
|
|
33120
33283
|
for (const entry of candidates) {
|
|
33121
33284
|
if (!entry.file)
|
|
33122
33285
|
continue;
|
|
33123
|
-
const recRaw = await readFile14(
|
|
33286
|
+
const recRaw = await readFile14(join20(dir, entry.file), "utf8").catch(() => null);
|
|
33124
33287
|
if (!recRaw)
|
|
33125
33288
|
continue;
|
|
33126
33289
|
const record3 = JSON.parse(recRaw);
|
|
@@ -33138,14 +33301,14 @@ var init_native_session_history = () => {};
|
|
|
33138
33301
|
// src/control/workspace-fs.ts
|
|
33139
33302
|
import { execFile } from "node:child_process";
|
|
33140
33303
|
import { promisify } from "node:util";
|
|
33141
|
-
import { homedir as
|
|
33142
|
-
import { readdir as
|
|
33304
|
+
import { homedir as homedir11 } from "node:os";
|
|
33305
|
+
import { readdir as readdir4, realpath, stat as stat3, open as open5 } from "node:fs/promises";
|
|
33143
33306
|
import { isAbsolute as isAbsolute3, relative, resolve as resolve3, sep } from "node:path";
|
|
33144
33307
|
function expandHome2(p) {
|
|
33145
33308
|
if (p === "~")
|
|
33146
|
-
return
|
|
33309
|
+
return homedir11();
|
|
33147
33310
|
if (p.startsWith("~/") || p.startsWith("~" + sep))
|
|
33148
|
-
return resolve3(
|
|
33311
|
+
return resolve3(homedir11(), p.slice(2));
|
|
33149
33312
|
return p;
|
|
33150
33313
|
}
|
|
33151
33314
|
|
|
@@ -33180,7 +33343,7 @@ class WorkspaceFs {
|
|
|
33180
33343
|
}
|
|
33181
33344
|
async listDirectory(workspace3, relPath) {
|
|
33182
33345
|
const { abs, rel } = await this.resolve(workspace3, relPath);
|
|
33183
|
-
const dirents = await
|
|
33346
|
+
const dirents = await readdir4(abs, { withFileTypes: true });
|
|
33184
33347
|
const entries = [];
|
|
33185
33348
|
for (const d of dirents.slice(0, MAX_ENTRIES)) {
|
|
33186
33349
|
if (d.isDirectory()) {
|
|
@@ -33234,7 +33397,7 @@ class WorkspaceFs {
|
|
|
33234
33397
|
const dir = queue.shift();
|
|
33235
33398
|
let dirents;
|
|
33236
33399
|
try {
|
|
33237
|
-
dirents = await
|
|
33400
|
+
dirents = await readdir4(dir, { withFileTypes: true });
|
|
33238
33401
|
} catch {
|
|
33239
33402
|
continue;
|
|
33240
33403
|
}
|
|
@@ -33383,7 +33546,8 @@ class ControlService {
|
|
|
33383
33546
|
agent: session3.agent,
|
|
33384
33547
|
workspace: session3.workspace,
|
|
33385
33548
|
transportSession: session3.transportSession,
|
|
33386
|
-
running: this.deps.activeTurns.isActiveAnywhere(session3.alias)
|
|
33549
|
+
running: this.deps.activeTurns.isActiveAnywhere(session3.alias),
|
|
33550
|
+
archived: session3.archived === true
|
|
33387
33551
|
}));
|
|
33388
33552
|
}
|
|
33389
33553
|
async listNativeSessions(_chatKey, agent3, workspace3) {
|
|
@@ -33413,15 +33577,26 @@ class ControlService {
|
|
|
33413
33577
|
agent: session3.agent,
|
|
33414
33578
|
workspace: session3.workspace,
|
|
33415
33579
|
transportSession: session3.transportSession,
|
|
33416
|
-
running: false
|
|
33580
|
+
running: false,
|
|
33581
|
+
archived: false
|
|
33417
33582
|
};
|
|
33418
33583
|
}
|
|
33419
33584
|
async removeSession(chatKey, alias) {
|
|
33420
33585
|
const internalAlias = await this.deps.sessions.resolveAliasForChat(chatKey, alias);
|
|
33421
|
-
const result = await this.deps.
|
|
33586
|
+
const result = await this.deps.removeSessionWithTransport(internalAlias);
|
|
33422
33587
|
this.deps.events.emit({ type: "sessions-changed" });
|
|
33423
33588
|
return result;
|
|
33424
33589
|
}
|
|
33590
|
+
async archiveSession(chatKey, alias) {
|
|
33591
|
+
const internalAlias = await this.deps.sessions.resolveAliasForChat(chatKey, alias);
|
|
33592
|
+
await this.deps.archiveSessionWithTransport(internalAlias);
|
|
33593
|
+
this.deps.events.emit({ type: "sessions-changed" });
|
|
33594
|
+
}
|
|
33595
|
+
async unarchiveSession(chatKey, alias) {
|
|
33596
|
+
const internalAlias = await this.deps.sessions.resolveAliasForChat(chatKey, alias);
|
|
33597
|
+
await this.deps.unarchiveSession(internalAlias);
|
|
33598
|
+
this.deps.events.emit({ type: "sessions-changed" });
|
|
33599
|
+
}
|
|
33425
33600
|
listAgents() {
|
|
33426
33601
|
return this.deps.agents.list();
|
|
33427
33602
|
}
|
|
@@ -33686,7 +33861,7 @@ var init_control_service = __esm(() => {
|
|
|
33686
33861
|
|
|
33687
33862
|
// src/config/agent-catalog.ts
|
|
33688
33863
|
import { existsSync as existsSync3 } from "node:fs";
|
|
33689
|
-
import { delimiter as delimiter2, join as
|
|
33864
|
+
import { delimiter as delimiter2, join as join21 } from "node:path";
|
|
33690
33865
|
function isBinaryOnPath(binary) {
|
|
33691
33866
|
const path15 = process.env.PATH ?? "";
|
|
33692
33867
|
const exts = process.platform === "win32" ? ["", ".exe", ".cmd", ".bat"] : [""];
|
|
@@ -33695,7 +33870,7 @@ function isBinaryOnPath(binary) {
|
|
|
33695
33870
|
continue;
|
|
33696
33871
|
for (const ext of exts) {
|
|
33697
33872
|
try {
|
|
33698
|
-
if (existsSync3(
|
|
33873
|
+
if (existsSync3(join21(dir, binary + ext)))
|
|
33699
33874
|
return true;
|
|
33700
33875
|
} catch {}
|
|
33701
33876
|
}
|
|
@@ -33735,8 +33910,8 @@ __export(exports_main, {
|
|
|
33735
33910
|
buildApp: () => buildApp
|
|
33736
33911
|
});
|
|
33737
33912
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
33738
|
-
import { homedir as
|
|
33739
|
-
import { dirname as dirname12, join as
|
|
33913
|
+
import { homedir as homedir12 } from "node:os";
|
|
33914
|
+
import { dirname as dirname12, join as join22 } from "node:path";
|
|
33740
33915
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
33741
33916
|
function startProgressHeartbeat(orchestration3, config4, logger2, channel) {
|
|
33742
33917
|
const thresholdSeconds = config4.orchestration.progressHeartbeatSeconds;
|
|
@@ -34234,6 +34409,9 @@ async function buildApp(paths, deps = {}) {
|
|
|
34234
34409
|
createSessionWithTransport: (internalAlias, agent4, workspace3, model) => router3.createSessionWithTransport(internalAlias, agent4, workspace3, model),
|
|
34235
34410
|
listNativeSessions: (agent4, workspace3) => router3.listNativeSessionsForControl(agent4, workspace3),
|
|
34236
34411
|
attachNativeSessionWithTransport: (internalAlias, agent4, workspace3, agentSessionId, nativeMeta) => router3.attachNativeSessionWithTransport(internalAlias, agent4, workspace3, agentSessionId, nativeMeta),
|
|
34412
|
+
removeSessionWithTransport: (internalAlias) => router3.removeSessionWithTransport(internalAlias),
|
|
34413
|
+
archiveSessionWithTransport: (internalAlias) => router3.archiveSessionWithTransport(internalAlias),
|
|
34414
|
+
unarchiveSession: (internalAlias) => router3.unarchiveSession(internalAlias),
|
|
34237
34415
|
activeTurns,
|
|
34238
34416
|
scheduled: scheduledService,
|
|
34239
34417
|
orchestration: orchestration3,
|
|
@@ -34396,8 +34574,8 @@ async function main() {
|
|
|
34396
34574
|
}
|
|
34397
34575
|
}
|
|
34398
34576
|
async function prepareChannelMedia(configPath, config4) {
|
|
34399
|
-
const runtimeDir =
|
|
34400
|
-
const mediaRootDir =
|
|
34577
|
+
const runtimeDir = join22(dirname12(configPath), "runtime");
|
|
34578
|
+
const mediaRootDir = join22(runtimeDir, "media");
|
|
34401
34579
|
const mediaStore = new RuntimeMediaStore({ rootDir: mediaRootDir });
|
|
34402
34580
|
await mediaStore.cleanupExpired().catch((error2) => {
|
|
34403
34581
|
console.error("[xacpx] media cleanup failed:", error2 instanceof Error ? error2.message : String(error2));
|
|
@@ -34406,16 +34584,16 @@ async function prepareChannelMedia(configPath, config4) {
|
|
|
34406
34584
|
return { mediaStore, channelDeps: { mediaStore, allowedMediaRoots } };
|
|
34407
34585
|
}
|
|
34408
34586
|
function resolveRuntimePaths() {
|
|
34409
|
-
const home = process.env.HOME ??
|
|
34587
|
+
const home = process.env.HOME ?? homedir12();
|
|
34410
34588
|
if (!home) {
|
|
34411
34589
|
throw new Error("Unable to resolve the current user home directory");
|
|
34412
34590
|
}
|
|
34413
|
-
const configPath = coreEnv("CONFIG") ??
|
|
34414
|
-
const runtimeDir =
|
|
34591
|
+
const configPath = coreEnv("CONFIG") ?? join22(coreHomeDir(home), "config.json");
|
|
34592
|
+
const runtimeDir = join22(dirname12(configPath), "runtime");
|
|
34415
34593
|
return {
|
|
34416
34594
|
configPath,
|
|
34417
|
-
statePath: coreEnv("STATE") ??
|
|
34418
|
-
perfLogPath:
|
|
34595
|
+
statePath: coreEnv("STATE") ?? join22(coreHomeDir(home), "state.json"),
|
|
34596
|
+
perfLogPath: join22(runtimeDir, "perf.log"),
|
|
34419
34597
|
orchestrationSocketPath: coreEnv("ORCHESTRATION_SOCKET") ?? resolveDaemonOrchestrationSocketPath(runtimeDir)
|
|
34420
34598
|
};
|
|
34421
34599
|
}
|
|
@@ -34427,13 +34605,13 @@ function resolveBridgeEntryPath() {
|
|
|
34427
34605
|
}
|
|
34428
34606
|
function resolveAppLogPath(configPath) {
|
|
34429
34607
|
const rootDir = dirname12(configPath);
|
|
34430
|
-
const runtimeDir =
|
|
34431
|
-
return
|
|
34608
|
+
const runtimeDir = join22(rootDir, "runtime");
|
|
34609
|
+
return join22(runtimeDir, "app.log");
|
|
34432
34610
|
}
|
|
34433
34611
|
function resolvePerfLogPath(configPath) {
|
|
34434
34612
|
const rootDir = dirname12(configPath);
|
|
34435
|
-
const runtimeDir =
|
|
34436
|
-
return
|
|
34613
|
+
const runtimeDir = join22(rootDir, "runtime");
|
|
34614
|
+
return join22(runtimeDir, "perf.log");
|
|
34437
34615
|
}
|
|
34438
34616
|
function resolveOrchestrationSocketPathFromConfigPath(configPath) {
|
|
34439
34617
|
const runtimeDir = resolveRuntimeDirFromConfigPath(configPath);
|
|
@@ -34671,12 +34849,12 @@ var init_config_check = __esm(async () => {
|
|
|
34671
34849
|
});
|
|
34672
34850
|
|
|
34673
34851
|
// src/doctor/checks/daemon-check.ts
|
|
34674
|
-
import { readdir as
|
|
34852
|
+
import { readdir as readdir5, readFile as readFile15, rm as rm10 } from "node:fs/promises";
|
|
34675
34853
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
34676
|
-
import { homedir as
|
|
34677
|
-
import { join as
|
|
34854
|
+
import { homedir as homedir13 } from "node:os";
|
|
34855
|
+
import { join as join23 } from "node:path";
|
|
34678
34856
|
async function checkDaemon(options = {}) {
|
|
34679
|
-
const home = options.home ?? process.env.HOME ??
|
|
34857
|
+
const home = options.home ?? process.env.HOME ?? homedir13();
|
|
34680
34858
|
const runtimeDir = options.configPath ? resolveRuntimeDirFromConfigPath(options.configPath) : undefined;
|
|
34681
34859
|
const paths = (options.resolveDaemonPaths ?? resolveDaemonPaths)({
|
|
34682
34860
|
home,
|
|
@@ -34776,7 +34954,7 @@ async function detectStaleConsumerLockFix(runtimeDir, deps) {
|
|
|
34776
34954
|
if (!fileName.endsWith(CONSUMER_LOCK_SUFFIX)) {
|
|
34777
34955
|
continue;
|
|
34778
34956
|
}
|
|
34779
|
-
const lockPath =
|
|
34957
|
+
const lockPath = join23(runtimeDir, fileName);
|
|
34780
34958
|
const lock2 = await deps.readConsumerLock(lockPath);
|
|
34781
34959
|
if (lock2 && !deps.isProcessRunning(lock2.pid)) {
|
|
34782
34960
|
stalePaths.push(lockPath);
|
|
@@ -34810,7 +34988,7 @@ async function detectStaleConsumerLockFix(runtimeDir, deps) {
|
|
|
34810
34988
|
}
|
|
34811
34989
|
async function defaultListConsumerLocks(runtimeDir) {
|
|
34812
34990
|
try {
|
|
34813
|
-
return await
|
|
34991
|
+
return await readdir5(runtimeDir);
|
|
34814
34992
|
} catch {
|
|
34815
34993
|
return [];
|
|
34816
34994
|
}
|
|
@@ -34840,11 +35018,11 @@ var init_daemon_check = __esm(() => {
|
|
|
34840
35018
|
});
|
|
34841
35019
|
|
|
34842
35020
|
// src/doctor/checks/logs-check.ts
|
|
34843
|
-
import { stat as stat4, readdir as
|
|
34844
|
-
import { basename as basename3, join as
|
|
34845
|
-
import { homedir as
|
|
35021
|
+
import { stat as stat4, readdir as readdir6 } from "node:fs/promises";
|
|
35022
|
+
import { basename as basename3, join as join24 } from "node:path";
|
|
35023
|
+
import { homedir as homedir14 } from "node:os";
|
|
34846
35024
|
async function checkLogs(options = {}) {
|
|
34847
|
-
const home = options.home ?? process.env.HOME ??
|
|
35025
|
+
const home = options.home ?? process.env.HOME ?? homedir14();
|
|
34848
35026
|
const runtimeDir = options.configPath ? resolveRuntimeDirFromConfigPath(options.configPath) : undefined;
|
|
34849
35027
|
const paths = (options.resolveDaemonPaths ?? resolveDaemonPaths)({
|
|
34850
35028
|
home,
|
|
@@ -34876,7 +35054,7 @@ async function checkLogs(options = {}) {
|
|
|
34876
35054
|
const matched = entries.filter((entry) => isTrackedLogName(entry, tracked));
|
|
34877
35055
|
const files = [];
|
|
34878
35056
|
for (const name of matched) {
|
|
34879
|
-
const path15 =
|
|
35057
|
+
const path15 = join24(paths.runtimeDir, name);
|
|
34880
35058
|
try {
|
|
34881
35059
|
const fileStat = await probe.stat(path15);
|
|
34882
35060
|
if (fileStat.isDirectory()) {
|
|
@@ -34957,7 +35135,7 @@ function formatBytes(bytes) {
|
|
|
34957
35135
|
function createLogsFsProbe() {
|
|
34958
35136
|
return {
|
|
34959
35137
|
stat: async (path15) => await stat4(path15),
|
|
34960
|
-
readdir: async (path15) => await
|
|
35138
|
+
readdir: async (path15) => await readdir6(path15)
|
|
34961
35139
|
};
|
|
34962
35140
|
}
|
|
34963
35141
|
function formatError6(error2) {
|
|
@@ -35026,9 +35204,9 @@ var init_orchestration_health = __esm(() => {
|
|
|
35026
35204
|
});
|
|
35027
35205
|
|
|
35028
35206
|
// src/doctor/checks/orchestration-socket-check.ts
|
|
35029
|
-
import { homedir as
|
|
35207
|
+
import { homedir as homedir15 } from "node:os";
|
|
35030
35208
|
async function checkOrchestrationSocket(options = {}) {
|
|
35031
|
-
const home = options.home ?? process.env.HOME ??
|
|
35209
|
+
const home = options.home ?? process.env.HOME ?? homedir15();
|
|
35032
35210
|
const runtimeDir = options.configPath ? resolveRuntimeDirFromConfigPath(options.configPath) : undefined;
|
|
35033
35211
|
const paths = (options.resolveDaemonPaths ?? resolveDaemonPaths)({
|
|
35034
35212
|
home,
|
|
@@ -35203,9 +35381,9 @@ var init_plugin_check = __esm(async () => {
|
|
|
35203
35381
|
import { constants } from "node:fs";
|
|
35204
35382
|
import { access as access4, stat as stat5 } from "node:fs/promises";
|
|
35205
35383
|
import { dirname as dirname13 } from "node:path";
|
|
35206
|
-
import { homedir as
|
|
35384
|
+
import { homedir as homedir16 } from "node:os";
|
|
35207
35385
|
async function checkRuntime(options = {}) {
|
|
35208
|
-
const home = options.home ?? process.env.HOME ??
|
|
35386
|
+
const home = options.home ?? process.env.HOME ?? homedir16();
|
|
35209
35387
|
const runtimeDir = options.configPath ? resolveRuntimeDirFromConfigPath(options.configPath) : undefined;
|
|
35210
35388
|
const paths = (options.resolveDaemonPaths ?? resolveDaemonPaths)({
|
|
35211
35389
|
home,
|
|
@@ -35838,10 +36016,10 @@ var init_render_doctor = __esm(() => {
|
|
|
35838
36016
|
});
|
|
35839
36017
|
|
|
35840
36018
|
// src/doctor/doctor.ts
|
|
35841
|
-
import { homedir as
|
|
35842
|
-
import { join as
|
|
36019
|
+
import { homedir as homedir17 } from "node:os";
|
|
36020
|
+
import { join as join25 } from "node:path";
|
|
35843
36021
|
async function runDoctor(options = {}, deps = {}) {
|
|
35844
|
-
const home = deps.home ?? process.env.HOME ??
|
|
36022
|
+
const home = deps.home ?? process.env.HOME ?? homedir17();
|
|
35845
36023
|
const runtimePaths = resolveDoctorRuntimePaths(home, deps.resolveRuntimePaths);
|
|
35846
36024
|
const sharedLoadConfig = createSharedLoadConfig(runtimePaths, deps.loadConfig ?? loadConfig);
|
|
35847
36025
|
const runners = [
|
|
@@ -35994,8 +36172,8 @@ function resolveDoctorRuntimePaths(home, resolver) {
|
|
|
35994
36172
|
return resolveRuntimePaths();
|
|
35995
36173
|
}
|
|
35996
36174
|
return {
|
|
35997
|
-
configPath:
|
|
35998
|
-
statePath:
|
|
36175
|
+
configPath: join25(coreHomeDir(home), "config.json"),
|
|
36176
|
+
statePath: join25(coreHomeDir(home), "state.json")
|
|
35999
36177
|
};
|
|
36000
36178
|
}
|
|
36001
36179
|
function depsUseExplicitRuntimeOverrides() {
|
|
@@ -36178,8 +36356,8 @@ var init_doctor2 = __esm(async () => {
|
|
|
36178
36356
|
// src/cli.ts
|
|
36179
36357
|
init_core_home();
|
|
36180
36358
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
36181
|
-
import { homedir as
|
|
36182
|
-
import { dirname as dirname14, join as
|
|
36359
|
+
import { homedir as homedir18 } from "node:os";
|
|
36360
|
+
import { dirname as dirname14, join as join26, sep as sep2 } from "node:path";
|
|
36183
36361
|
import { fileURLToPath as fileURLToPath7 } from "node:url";
|
|
36184
36362
|
|
|
36185
36363
|
// src/runtime/migrate-core-home.ts
|
|
@@ -50901,6 +51079,7 @@ async function removeChannel(type, rawArgs, deps) {
|
|
|
50901
51079
|
deps.print(restartFlags.message);
|
|
50902
51080
|
return 1;
|
|
50903
51081
|
}
|
|
51082
|
+
const keepCredentials = restartFlags.rest.includes("--keep-credentials");
|
|
50904
51083
|
const config4 = await deps.loadConfig();
|
|
50905
51084
|
ensureChannelsArray(config4);
|
|
50906
51085
|
const channel = findChannel(config4.channels, type);
|
|
@@ -50915,6 +51094,16 @@ async function removeChannel(type, rawArgs, deps) {
|
|
|
50915
51094
|
config4.channels = config4.channels.filter((entry) => entry.id !== channel.id);
|
|
50916
51095
|
await deps.saveChannels(config4.channels);
|
|
50917
51096
|
deps.print(t().channelCli.channelRemoved(channel.id));
|
|
51097
|
+
if (keepCredentials) {
|
|
51098
|
+
deps.print(t().channelCli.channelCredentialsKept(channel.id));
|
|
51099
|
+
} else if (deps.clearChannelCredentials) {
|
|
51100
|
+
try {
|
|
51101
|
+
await deps.clearChannelCredentials(channel);
|
|
51102
|
+
deps.print(t().channelCli.channelCredentialsCleared(channel.id));
|
|
51103
|
+
} catch (error2) {
|
|
51104
|
+
deps.print(t().channelCli.channelCredentialsClearFailed(channel.id, error2 instanceof Error ? error2.message : String(error2)));
|
|
51105
|
+
}
|
|
51106
|
+
}
|
|
50918
51107
|
return await maybeRestartAfterMutation(restartFlags.restart, deps);
|
|
50919
51108
|
}
|
|
50920
51109
|
async function setChannelEnabled(type, enabled, rawArgs, deps) {
|
|
@@ -52422,7 +52611,7 @@ async function createCliScheduledTaskService() {
|
|
|
52422
52611
|
return new ScheduledTaskService(state, stateStore);
|
|
52423
52612
|
}
|
|
52424
52613
|
function resolveConfigPathForCurrentEnv() {
|
|
52425
|
-
return coreEnv("CONFIG") ??
|
|
52614
|
+
return coreEnv("CONFIG") ?? join26(coreHomeDir(requireHome2()), "config.json");
|
|
52426
52615
|
}
|
|
52427
52616
|
function resolveDaemonPathsForCurrentConfig() {
|
|
52428
52617
|
const configPath = resolveConfigPathForCurrentEnv();
|
|
@@ -52640,7 +52829,11 @@ async function createChannelCliDeps(input) {
|
|
|
52640
52829
|
return { state: "indeterminate", pid: status.pid, reason: status.reason };
|
|
52641
52830
|
return { state: "stopped" };
|
|
52642
52831
|
},
|
|
52643
|
-
restartDaemon: async () => await restartDaemonCli(controller, input.print)
|
|
52832
|
+
restartDaemon: async () => await restartDaemonCli(controller, input.print),
|
|
52833
|
+
clearChannelCredentials: async (channel) => {
|
|
52834
|
+
const { createMessageChannel: createMessageChannel2 } = await Promise.resolve().then(() => (init_create_channel(), exports_create_channel));
|
|
52835
|
+
createMessageChannel2(channel.type, channel).logout();
|
|
52836
|
+
}
|
|
52644
52837
|
};
|
|
52645
52838
|
return { ...base, ...input.overrides };
|
|
52646
52839
|
}
|
|
@@ -52769,7 +52962,7 @@ function decodeFirstRunOnboarding(raw) {
|
|
|
52769
52962
|
return null;
|
|
52770
52963
|
}
|
|
52771
52964
|
function requireHome2() {
|
|
52772
|
-
const home = process.env.HOME ??
|
|
52965
|
+
const home = process.env.HOME ?? homedir18();
|
|
52773
52966
|
if (!home) {
|
|
52774
52967
|
throw new Error("Unable to resolve the current user home directory");
|
|
52775
52968
|
}
|
|
@@ -52793,7 +52986,7 @@ function safeDaemonLogPaths() {
|
|
|
52793
52986
|
const configPath = resolveConfigPathForCurrentEnv();
|
|
52794
52987
|
const paths = resolveDaemonPathsForCurrentConfig();
|
|
52795
52988
|
return {
|
|
52796
|
-
appLog:
|
|
52989
|
+
appLog: join26(dirname14(configPath), "runtime", "app.log"),
|
|
52797
52990
|
stderrLog: paths.stderrLog
|
|
52798
52991
|
};
|
|
52799
52992
|
} catch {
|
|
@@ -38,6 +38,7 @@ export declare function handleCancel(context: SessionHandlerContext, chatKey: st
|
|
|
38
38
|
export declare function handleSessionReset(context: SessionHandlerContext, chatKey: string): Promise<RouterResponse>;
|
|
39
39
|
export declare function handleSessionTail(context: SessionHandlerContext, chatKey: string, lines?: number): Promise<RouterResponse>;
|
|
40
40
|
export declare function handleSessionRemove(context: SessionHandlerContext, chatKey: string, alias: string): Promise<RouterResponse>;
|
|
41
|
+
export declare function handleSessionArchive(context: SessionHandlerContext, chatKey: string, alias: string, archive: (internalAlias: string) => Promise<void>): Promise<RouterResponse>;
|
|
41
42
|
export declare function handlePromptWithSession(context: SessionHandlerContext, session: ResolvedSession, chatKey: string, text: string, reply?: (text: string) => Promise<void>, replyContextToken?: string, accountId?: string, media?: PromptMediaInput, abortSignal?: AbortSignal, onToolEvent?: (event: ToolUseEvent) => void | Promise<void>, onThought?: (chunk: string) => void | Promise<void>, perfSpan?: PerfSpan, metadata?: ChatRequestMetadata, onPlan?: (entries: PlanEntry[]) => void | Promise<void>, onUsage?: (usage: {
|
|
42
43
|
used: number;
|
|
43
44
|
size: number;
|
|
@@ -15,6 +15,7 @@ export interface ControlSessionInfo {
|
|
|
15
15
|
workspace: string;
|
|
16
16
|
transportSession: string;
|
|
17
17
|
running: boolean;
|
|
18
|
+
archived: boolean;
|
|
18
19
|
}
|
|
19
20
|
export interface ControlAgentInfo {
|
|
20
21
|
name: string;
|
|
@@ -37,6 +38,11 @@ export interface ControlServiceDeps {
|
|
|
37
38
|
sessions: Pick<SessionService, "listAllResolvedSessions" | "removeSession" | "useSession" | "resolveAliasForChat" | "getSession" | "setSessionModel">;
|
|
38
39
|
transport: Pick<SessionTransport, "setModel" | "getSessionModel">;
|
|
39
40
|
createSessionWithTransport: (internalAlias: string, agent: string, workspace: string, model?: string) => Promise<ResolvedSession>;
|
|
41
|
+
removeSessionWithTransport: (internalAlias: string) => Promise<{
|
|
42
|
+
wasActive: boolean;
|
|
43
|
+
}>;
|
|
44
|
+
archiveSessionWithTransport: (internalAlias: string) => Promise<void>;
|
|
45
|
+
unarchiveSession: (internalAlias: string) => Promise<void>;
|
|
40
46
|
listNativeSessions: (agent: string, workspace: string) => Promise<AgentSession[]>;
|
|
41
47
|
attachNativeSessionWithTransport: (internalAlias: string, agent: string, workspace: string, agentSessionId: string, nativeMeta?: {
|
|
42
48
|
title?: string | null;
|
|
@@ -121,6 +127,8 @@ export declare class ControlService {
|
|
|
121
127
|
removeSession(chatKey: string, alias: string): Promise<{
|
|
122
128
|
wasActive: boolean;
|
|
123
129
|
}>;
|
|
130
|
+
archiveSession(chatKey: string, alias: string): Promise<void>;
|
|
131
|
+
unarchiveSession(chatKey: string, alias: string): Promise<void>;
|
|
124
132
|
listAgents(): ControlAgentInfo[];
|
|
125
133
|
listWorkspaces(): ControlWorkspaceInfo[];
|
|
126
134
|
createWorkspace(name: string, cwd: string, description?: string): Promise<ControlWorkspaceInfo>;
|
package/dist/i18n/types.d.ts
CHANGED
|
@@ -50,6 +50,7 @@ export interface SessionMessages {
|
|
|
50
50
|
sessionBlockedByTasks: (alias: string, count: number) => string;
|
|
51
51
|
sessionBlockedByTasksHint: string;
|
|
52
52
|
sessionRemoved: (alias: string) => string;
|
|
53
|
+
sessionArchived: (alias: string) => string;
|
|
53
54
|
sessionRemovedWasActive: string;
|
|
54
55
|
sessionRemovedWasActivePromoted: (alias: string) => string;
|
|
55
56
|
sessionTransportShared: (transportSession: string, count: number) => string;
|
|
@@ -672,6 +673,9 @@ export interface ChannelCliMessages {
|
|
|
672
673
|
channelAdded: (type: string) => string;
|
|
673
674
|
cannotRemoveLastEnabled: string;
|
|
674
675
|
channelRemoved: (id: string) => string;
|
|
676
|
+
channelCredentialsCleared: (id: string) => string;
|
|
677
|
+
channelCredentialsClearFailed: (id: string, error: string) => string;
|
|
678
|
+
channelCredentialsKept: (id: string) => string;
|
|
675
679
|
cannotDisableLastEnabled: string;
|
|
676
680
|
channelEnabledToggled: (id: string, enabled: boolean) => string;
|
|
677
681
|
channelReplyModeSet: (id: string, mode: string) => string;
|
package/dist/plugin-api.js
CHANGED
|
@@ -116,6 +116,7 @@ ${detail}`,
|
|
|
116
116
|
sessionBlockedByTasks: (alias, count) => `Session "${alias}" has ${count} unfinished task(s). Cancel or wait for them to complete first.`,
|
|
117
117
|
sessionBlockedByTasksHint: "Use /tasks to list tasks, or /task cancel <id> to cancel one.",
|
|
118
118
|
sessionRemoved: (alias) => `Session "${alias}" removed.`,
|
|
119
|
+
sessionArchived: (alias) => `Archived session "${alias}". Send a message to restore it.`,
|
|
119
120
|
sessionRemovedWasActive: "This was the active session. Its chat context has been cleared.",
|
|
120
121
|
sessionRemovedWasActivePromoted: (alias) => `This was the active session. Switched back to the previous session "${alias}".`,
|
|
121
122
|
sessionTransportShared: (transportSession, count) => `Note: backend session "${transportSession}" is still referenced by ${count} other session(s) and was not closed.`,
|
|
@@ -873,6 +874,9 @@ var init_channel_cli = __esm(() => {
|
|
|
873
874
|
channelAdded: (type) => `Channel ${type} added`,
|
|
874
875
|
cannotRemoveLastEnabled: "Cannot remove the last enabled channel.",
|
|
875
876
|
channelRemoved: (id) => `Channel ${id} removed`,
|
|
877
|
+
channelCredentialsCleared: (id) => `Removed stored credentials for channel ${id}`,
|
|
878
|
+
channelCredentialsClearFailed: (id, error) => `Channel ${id} removed, but clearing its stored credentials failed: ${error}`,
|
|
879
|
+
channelCredentialsKept: (id) => `Kept stored credentials for channel ${id} (--keep-credentials)`,
|
|
876
880
|
cannotDisableLastEnabled: "Cannot disable the last enabled channel.",
|
|
877
881
|
channelEnabledToggled: (id, enabled) => `Channel ${id} ${enabled ? "enabled" : "disabled"}`,
|
|
878
882
|
channelReplyModeSet: (id, mode) => `Channel ${id} default reply mode set to: ${mode}`,
|
|
@@ -1208,6 +1212,7 @@ ${detail}`,
|
|
|
1208
1212
|
sessionBlockedByTasks: (alias, count) => `会话「${alias}」下还有 ${count} 个未结束的任务,请先取消或等待完成。`,
|
|
1209
1213
|
sessionBlockedByTasksHint: "使用 /tasks 查看任务列表,或 /task cancel <id> 取消任务。",
|
|
1210
1214
|
sessionRemoved: (alias) => `已删除会话「${alias}」。`,
|
|
1215
|
+
sessionArchived: (alias) => `已归档会话「${alias}」。发送消息即可恢复。`,
|
|
1211
1216
|
sessionRemovedWasActive: "该会话是当前活跃会话,已自动清除相关聊天上下文。",
|
|
1212
1217
|
sessionRemovedWasActivePromoted: (alias) => `该会话是当前活跃会话,已切换回上一个会话「${alias}」。`,
|
|
1213
1218
|
sessionTransportShared: (transportSession, count) => `提示:后端会话「${transportSession}」仍被其他 ${count} 个会话引用,未关闭。`,
|
|
@@ -1965,6 +1970,9 @@ var init_channel_cli2 = __esm(() => {
|
|
|
1965
1970
|
channelAdded: (type) => `频道 ${type} 已添加`,
|
|
1966
1971
|
cannotRemoveLastEnabled: "不能删除最后一个启用的频道。",
|
|
1967
1972
|
channelRemoved: (id) => `频道 ${id} 已删除`,
|
|
1973
|
+
channelCredentialsCleared: (id) => `已移除频道 ${id} 的存储凭证`,
|
|
1974
|
+
channelCredentialsClearFailed: (id, error) => `频道 ${id} 已删除,但清除其存储凭证失败:${error}`,
|
|
1975
|
+
channelCredentialsKept: (id) => `已保留频道 ${id} 的存储凭证(--keep-credentials)`,
|
|
1968
1976
|
cannotDisableLastEnabled: "不能禁用最后一个启用的频道。",
|
|
1969
1977
|
channelEnabledToggled: (id, enabled) => `频道 ${id} 已${enabled ? "启用" : "禁用"}`,
|
|
1970
1978
|
channelReplyModeSet: (id, mode) => `频道 ${id} 的默认 reply mode 已设置为:${mode}`,
|
|
@@ -106,6 +106,7 @@ export declare class SessionService {
|
|
|
106
106
|
getCurrentSession(chatKey: string): Promise<ResolvedSession | null>;
|
|
107
107
|
listSessions(chatKey: string): Promise<SessionListItem[]>;
|
|
108
108
|
countAliasesSharingTransport(transportSession: string, excludeAlias?: string): number;
|
|
109
|
+
setArchived(alias: string, archived: boolean): Promise<void>;
|
|
109
110
|
removeSession(alias: string): Promise<{
|
|
110
111
|
wasActive: boolean;
|
|
111
112
|
}>;
|
package/dist/state/types.d.ts
CHANGED
|
@@ -30,6 +30,10 @@ export interface LogicalSession {
|
|
|
30
30
|
/** Per-session LLM model override (e.g. `gpt-5.2[high]`); falls back to the agent config default. */
|
|
31
31
|
model?: string;
|
|
32
32
|
reply_mode?: "stream" | "final" | "verbose";
|
|
33
|
+
/** True when the user archived this session: process closed, row greyed + sunk.
|
|
34
|
+
* Cleared on the next useSession (restore-on-message). */
|
|
35
|
+
archived?: boolean;
|
|
36
|
+
archived_at?: string;
|
|
33
37
|
created_at: string;
|
|
34
38
|
last_used_at: string;
|
|
35
39
|
}
|
|
@@ -55,6 +55,11 @@ export interface ResolvedSession {
|
|
|
55
55
|
* persisted state by alias) does not apply.
|
|
56
56
|
*/
|
|
57
57
|
transient?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* True when the user archived this session (process closed, greyed out in the
|
|
60
|
+
* web dashboard). Surfaced to the control/web path via ControlSessionInfo.
|
|
61
|
+
*/
|
|
62
|
+
archived?: boolean;
|
|
58
63
|
}
|
|
59
64
|
export interface AgentSession {
|
|
60
65
|
sessionId: string;
|
|
@@ -160,6 +165,13 @@ export interface SessionTransport {
|
|
|
160
165
|
listAgentSessions?(query: AgentSessionListQuery): Promise<AgentSessionListResult | undefined>;
|
|
161
166
|
resumeAgentSession?(session: ResolvedSession, agentSessionId: string): Promise<void>;
|
|
162
167
|
removeSession?(session: ResolvedSession): Promise<void>;
|
|
168
|
+
/**
|
|
169
|
+
* Hard-delete the transport session AND its on-disk history: close the acpx
|
|
170
|
+
* process, then delete acpx's record files. Distinct from removeSession (=
|
|
171
|
+
* `acpx sessions close`, which keeps history for resume). Optional: transports
|
|
172
|
+
* that can't delete omit it. A missing acpx session is a no-op (idempotent).
|
|
173
|
+
*/
|
|
174
|
+
deleteSession?(session: ResolvedSession): Promise<void>;
|
|
163
175
|
/**
|
|
164
176
|
* Read the underlying agent-native session id for an existing transport
|
|
165
177
|
* session. Used by `/clear` to keep a native session native: the fresh
|