@ganglion/xacpx 0.20.3 → 0.22.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 +5 -1
- package/dist/channels/cli/provider.d.ts +17 -0
- package/dist/channels/plugin.d.ts +21 -0
- package/dist/channels/types.d.ts +16 -2
- package/dist/cli.js +374 -73
- package/dist/config/local-agent-bin.d.ts +6 -0
- package/dist/config/resolve-agent-command.d.ts +1 -1
- package/dist/config/types.d.ts +6 -4
- package/dist/i18n/types.d.ts +1 -0
- package/dist/plugin-api.d.ts +4 -3
- package/dist/plugin-api.js +2 -0
- package/dist/sessions/session-resource-catalog.d.ts +96 -0
- package/dist/sessions/session-service.d.ts +30 -1
- package/dist/state/state-store.d.ts +23 -4
- package/dist/state/types.d.ts +8 -0
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -927,6 +927,7 @@ var init_channel_cli = __esm(() => {
|
|
|
927
927
|
channelAdded: (type) => `Channel ${type} added`,
|
|
928
928
|
cannotRemoveLastEnabled: "Cannot remove the last enabled channel.",
|
|
929
929
|
channelRemoved: (id) => `Channel ${id} removed`,
|
|
930
|
+
channelRetirementFailed: (id, error) => `Channel ${id} retirement cleanup failed: ${error}`,
|
|
930
931
|
channelCredentialsCleared: (id) => `Removed stored credentials for channel ${id}`,
|
|
931
932
|
channelCredentialsClearFailed: (id, error) => `Channel ${id} removed, but clearing its stored credentials failed: ${error}`,
|
|
932
933
|
channelCredentialsKept: (id) => `Kept stored credentials for channel ${id} (--keep-credentials)`,
|
|
@@ -2053,6 +2054,7 @@ var init_channel_cli2 = __esm(() => {
|
|
|
2053
2054
|
channelAdded: (type) => `频道 ${type} 已添加`,
|
|
2054
2055
|
cannotRemoveLastEnabled: "不能删除最后一个启用的频道。",
|
|
2055
2056
|
channelRemoved: (id) => `频道 ${id} 已删除`,
|
|
2057
|
+
channelRetirementFailed: (id, error) => `频道 ${id} 退役清理失败:${error}`,
|
|
2056
2058
|
channelCredentialsCleared: (id) => `已移除频道 ${id} 的存储凭证`,
|
|
2057
2059
|
channelCredentialsClearFailed: (id, error) => `频道 ${id} 已删除,但清除其存储凭证失败:${error}`,
|
|
2058
2060
|
channelCredentialsKept: (id) => `已保留频道 ${id} 的存储凭证(--keep-credentials)`,
|
|
@@ -4690,7 +4692,9 @@ var LOCAL_AGENT_BINS;
|
|
|
4690
4692
|
var init_local_agent_bin = __esm(() => {
|
|
4691
4693
|
LOCAL_AGENT_BINS = {
|
|
4692
4694
|
opencode: { bin: "opencode", args: ["acp"] },
|
|
4693
|
-
kilocode: { bin: "kilocode", args: ["acp"] }
|
|
4695
|
+
kilocode: { bin: "kilocode", args: ["acp"] },
|
|
4696
|
+
reasonix: { bin: "reasonix", args: ["acp"] },
|
|
4697
|
+
omp: { bin: "omp", args: ["acp"] }
|
|
4694
4698
|
};
|
|
4695
4699
|
});
|
|
4696
4700
|
|
|
@@ -6721,6 +6725,9 @@ var init_agent_templates = __esm(() => {
|
|
|
6721
6725
|
mux: {
|
|
6722
6726
|
driver: "mux"
|
|
6723
6727
|
},
|
|
6728
|
+
omp: {
|
|
6729
|
+
driver: "omp"
|
|
6730
|
+
},
|
|
6724
6731
|
opencode: {
|
|
6725
6732
|
driver: "opencode"
|
|
6726
6733
|
},
|
|
@@ -6733,6 +6740,9 @@ var init_agent_templates = __esm(() => {
|
|
|
6733
6740
|
qwen: {
|
|
6734
6741
|
driver: "qwen"
|
|
6735
6742
|
},
|
|
6743
|
+
reasonix: {
|
|
6744
|
+
driver: "reasonix"
|
|
6745
|
+
},
|
|
6736
6746
|
trae: {
|
|
6737
6747
|
driver: "trae"
|
|
6738
6748
|
},
|
|
@@ -8203,7 +8213,7 @@ function createCoreRuntimeLock(options) {
|
|
|
8203
8213
|
try {
|
|
8204
8214
|
if (isBunRuntime() && !options.loadFsExt) {
|
|
8205
8215
|
await handle.close();
|
|
8206
|
-
posixHelper = await acquireFlockHelper(options.lockFilePath, options.helperAcquireTimeoutMs, options.helperHandshakeDelayMs);
|
|
8216
|
+
posixHelper = await acquireFlockHelper(options.lockFilePath, options.helperAcquireTimeoutMs, options.helperHandshakeDelayMs, onDiagnostic);
|
|
8207
8217
|
await emitDiagnostic(onDiagnostic, "lock_helper_started", {
|
|
8208
8218
|
lockFilePath: options.lockFilePath,
|
|
8209
8219
|
helperPid: posixHelper.pid
|
|
@@ -8301,11 +8311,17 @@ async function releasePosixLock(options, handle, helper) {
|
|
|
8301
8311
|
function isBunRuntime() {
|
|
8302
8312
|
return Boolean(globalThis.Bun);
|
|
8303
8313
|
}
|
|
8304
|
-
async function acquireFlockHelper(lockFilePath, timeoutMs = 1e4, handshakeDelayMs = 0) {
|
|
8314
|
+
async function acquireFlockHelper(lockFilePath, timeoutMs = 1e4, handshakeDelayMs = 0, onDiagnostic) {
|
|
8305
8315
|
const fsExtPath = require2.resolve("fs-ext");
|
|
8306
8316
|
const child = spawn7("node", ["-e", FLOCK_HELPER_SOURCE, fsExtPath, lockFilePath, String(handshakeDelayMs)], {
|
|
8307
8317
|
stdio: ["pipe", "pipe", "pipe"]
|
|
8308
8318
|
});
|
|
8319
|
+
if (child.pid) {
|
|
8320
|
+
await emitDiagnostic(onDiagnostic, "lock_helper_spawned", {
|
|
8321
|
+
lockFilePath,
|
|
8322
|
+
helperPid: child.pid
|
|
8323
|
+
});
|
|
8324
|
+
}
|
|
8309
8325
|
const line = await new Promise((resolve5, reject) => {
|
|
8310
8326
|
let stdout = "";
|
|
8311
8327
|
let stderr = "";
|
|
@@ -29367,6 +29383,7 @@ function createEmptyState() {
|
|
|
29367
29383
|
var init_types4 = () => {};
|
|
29368
29384
|
|
|
29369
29385
|
// src/state/state-store.ts
|
|
29386
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
29370
29387
|
import { readFile as readFile10, rename as rename3, writeFile as writeFile4 } from "node:fs/promises";
|
|
29371
29388
|
function isRecord3(value) {
|
|
29372
29389
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -29619,6 +29636,9 @@ function parseOrchestrationState(raw, dropped) {
|
|
|
29619
29636
|
function isReplyMode2(value) {
|
|
29620
29637
|
return value === "stream" || value === "final" || value === "verbose";
|
|
29621
29638
|
}
|
|
29639
|
+
function isLogicalSessionId(value) {
|
|
29640
|
+
return typeof value === "string" && /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
|
|
29641
|
+
}
|
|
29622
29642
|
function isSessionSource(value) {
|
|
29623
29643
|
return value === undefined || value === "weacpx" || value === "xacpx" || value === "agent-side";
|
|
29624
29644
|
}
|
|
@@ -29626,16 +29646,26 @@ function isSessionRecord(value) {
|
|
|
29626
29646
|
if (!isRecord3(value)) {
|
|
29627
29647
|
return false;
|
|
29628
29648
|
}
|
|
29629
|
-
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.transport_acpx_agent) && (value.transport_agent_argv === undefined || isStringArray(value.transport_agent_argv)) && isOptionalString(value.mode_id) && isOptionalString(value.effort) && (value.reply_mode === undefined || isReplyMode2(value.reply_mode)) && isString(value.created_at) && isString(value.last_used_at);
|
|
29649
|
+
return isString(value.alias) && isString(value.agent) && isString(value.workspace) && isString(value.transport_session) && (value.logical_session_id === undefined || isLogicalSessionId(value.logical_session_id)) && 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.transport_acpx_agent) && (value.transport_agent_argv === undefined || isStringArray(value.transport_agent_argv)) && isOptionalString(value.mode_id) && isOptionalString(value.effort) && (value.reply_mode === undefined || isReplyMode2(value.reply_mode)) && isString(value.created_at) && isString(value.last_used_at);
|
|
29630
29650
|
}
|
|
29631
|
-
function parseSessions(raw, dropped) {
|
|
29651
|
+
function parseSessions(raw, dropped, migrated) {
|
|
29632
29652
|
const sessions = {};
|
|
29633
29653
|
for (const [alias, value] of Object.entries(raw)) {
|
|
29634
29654
|
if (!isSessionRecord(value)) {
|
|
29635
29655
|
dropped.push({ section: "sessions", key: alias, reason: "malformed session record" });
|
|
29636
29656
|
continue;
|
|
29637
29657
|
}
|
|
29638
|
-
|
|
29658
|
+
if (value.logical_session_id === undefined) {
|
|
29659
|
+
migrated.push({
|
|
29660
|
+
section: "sessions",
|
|
29661
|
+
key: alias,
|
|
29662
|
+
reason: "legacy record missing logical_session_id; assigned a new UUIDv4"
|
|
29663
|
+
});
|
|
29664
|
+
}
|
|
29665
|
+
sessions[alias] = {
|
|
29666
|
+
...value,
|
|
29667
|
+
logical_session_id: value.logical_session_id ?? randomUUID6()
|
|
29668
|
+
};
|
|
29639
29669
|
}
|
|
29640
29670
|
return sessions;
|
|
29641
29671
|
}
|
|
@@ -29700,11 +29730,11 @@ function parseScheduledTasks(raw, dropped) {
|
|
|
29700
29730
|
}
|
|
29701
29731
|
return tasks;
|
|
29702
29732
|
}
|
|
29703
|
-
function parseState(raw, path3, dropped = []) {
|
|
29733
|
+
function parseState(raw, path3, dropped = [], migrated = []) {
|
|
29704
29734
|
if (!isRecord3(raw)) {
|
|
29705
29735
|
throw new Error(`state file "${path3}" must contain a JSON object`);
|
|
29706
29736
|
}
|
|
29707
|
-
const parsedSessions = parseSessions(sectionRecord(raw.sessions, "sessions", dropped), dropped);
|
|
29737
|
+
const parsedSessions = parseSessions(sectionRecord(raw.sessions, "sessions", dropped), dropped, migrated);
|
|
29708
29738
|
const orchestration3 = parseOrchestrationState(raw.orchestration, dropped);
|
|
29709
29739
|
repairExternalCoordinatorIdentityCollisions(parsedSessions, orchestration3, dropped);
|
|
29710
29740
|
return {
|
|
@@ -29765,20 +29795,31 @@ class StateStore {
|
|
|
29765
29795
|
if (read.kind === "corrupt") {
|
|
29766
29796
|
return await this.recoverFromCorruptFile(read.reason);
|
|
29767
29797
|
}
|
|
29768
|
-
if (read.dropped.length === 0) {
|
|
29798
|
+
if (read.dropped.length === 0 && read.migrated.length === 0) {
|
|
29769
29799
|
return read.state;
|
|
29770
29800
|
}
|
|
29771
29801
|
const report = { dropped: read.dropped };
|
|
29772
|
-
|
|
29773
|
-
|
|
29774
|
-
|
|
29775
|
-
|
|
29776
|
-
|
|
29777
|
-
|
|
29802
|
+
if (read.migrated.length > 0) {
|
|
29803
|
+
report.migrated = read.migrated;
|
|
29804
|
+
}
|
|
29805
|
+
if (read.dropped.length > 0) {
|
|
29806
|
+
const quarantinePath = `${this.path}.quarantine-${this.fileTimestamp()}`;
|
|
29807
|
+
try {
|
|
29808
|
+
const written = await (this.options.writeBackup ?? defaultWriteBackup)(quarantinePath, read.content);
|
|
29809
|
+
report.quarantinePath = typeof written === "string" ? written : quarantinePath;
|
|
29810
|
+
} catch (error2) {
|
|
29811
|
+
report.backupError = error2 instanceof Error ? error2.message : String(error2);
|
|
29812
|
+
}
|
|
29813
|
+
}
|
|
29814
|
+
if (read.migrated.length > 0) {
|
|
29815
|
+
await this.persistMigration(read.state);
|
|
29778
29816
|
}
|
|
29779
29817
|
this.loadReport = report;
|
|
29780
29818
|
return read.state;
|
|
29781
29819
|
}
|
|
29820
|
+
async persistMigration(state) {
|
|
29821
|
+
await (this.options.writeMigration ?? ((next) => this.save(next)))(state);
|
|
29822
|
+
}
|
|
29782
29823
|
async inspect() {
|
|
29783
29824
|
const read = await this.readAndParse();
|
|
29784
29825
|
if (read.kind === "absent") {
|
|
@@ -29792,7 +29833,10 @@ class StateStore {
|
|
|
29792
29833
|
}
|
|
29793
29834
|
return {
|
|
29794
29835
|
state: read.state,
|
|
29795
|
-
report: read.dropped.length > 0
|
|
29836
|
+
report: read.dropped.length > 0 || read.migrated.length > 0 ? {
|
|
29837
|
+
dropped: read.dropped,
|
|
29838
|
+
...read.migrated.length > 0 ? { migrated: read.migrated } : {}
|
|
29839
|
+
} : null
|
|
29796
29840
|
};
|
|
29797
29841
|
}
|
|
29798
29842
|
async readAndParse() {
|
|
@@ -29821,7 +29865,8 @@ class StateStore {
|
|
|
29821
29865
|
return { kind: "corrupt", reason: "top-level value is not an object" };
|
|
29822
29866
|
}
|
|
29823
29867
|
const dropped = [];
|
|
29824
|
-
|
|
29868
|
+
const migrated = [];
|
|
29869
|
+
return { kind: "parsed", state: parseState(parsed, this.path, dropped, migrated), dropped, migrated, content };
|
|
29825
29870
|
}
|
|
29826
29871
|
async save(state) {
|
|
29827
29872
|
await writePrivateFileAtomic(this.path, JSON.stringify({ version: STATE_FILE_VERSION, ...state }, null, 2));
|
|
@@ -30404,6 +30449,27 @@ var init_plugin_home = __esm(() => {
|
|
|
30404
30449
|
import { spawn as spawn8 } from "node:child_process";
|
|
30405
30450
|
import { rm as rm6 } from "node:fs/promises";
|
|
30406
30451
|
import { join as join15 } from "node:path";
|
|
30452
|
+
function pluginRegistryInstallArgs(registry2 = effectivePluginRegistry()) {
|
|
30453
|
+
return [
|
|
30454
|
+
`--registry=${registry2}`,
|
|
30455
|
+
`--@ganglion:registry=${registry2}`
|
|
30456
|
+
];
|
|
30457
|
+
}
|
|
30458
|
+
function effectivePluginRegistry(env = process.env) {
|
|
30459
|
+
const raw = coreEnv("PLUGIN_REGISTRY", env)?.trim();
|
|
30460
|
+
if (!raw)
|
|
30461
|
+
return DEFAULT_PLUGIN_REGISTRY;
|
|
30462
|
+
let url;
|
|
30463
|
+
try {
|
|
30464
|
+
url = new URL(raw);
|
|
30465
|
+
} catch {
|
|
30466
|
+
throw new Error("XACPX_PLUGIN_REGISTRY must be a valid http(s) URL");
|
|
30467
|
+
}
|
|
30468
|
+
if (url.protocol !== "https:" && url.protocol !== "http:" || !url.hostname) {
|
|
30469
|
+
throw new Error("XACPX_PLUGIN_REGISTRY must be a valid http(s) URL");
|
|
30470
|
+
}
|
|
30471
|
+
return url.toString().replace(/\/+$/, "");
|
|
30472
|
+
}
|
|
30407
30473
|
function shellSpawnPlan(args) {
|
|
30408
30474
|
const shell = process.platform === "win32";
|
|
30409
30475
|
return { shell, args: shell ? args.map((arg) => `"${arg}"`) : args };
|
|
@@ -30454,11 +30520,12 @@ async function installPluginPackage(input) {
|
|
|
30454
30520
|
await rm6(join15(input.pluginHome, "bun.lock"), { force: true }).catch(() => {});
|
|
30455
30521
|
}
|
|
30456
30522
|
const spec = input.version ? `${input.packageName}@${input.version}` : input.packageName;
|
|
30523
|
+
const registryArgs = pluginRegistryInstallArgs();
|
|
30457
30524
|
if (packageManager === "bun") {
|
|
30458
|
-
await runCommand("bun", ["add", spec], { cwd: input.pluginHome });
|
|
30525
|
+
await runCommand("bun", ["add", spec, ...registryArgs], { cwd: input.pluginHome });
|
|
30459
30526
|
return;
|
|
30460
30527
|
}
|
|
30461
|
-
await runCommand("npm", ["install", spec], { cwd: input.pluginHome });
|
|
30528
|
+
await runCommand("npm", ["install", spec, ...registryArgs], { cwd: input.pluginHome });
|
|
30462
30529
|
}
|
|
30463
30530
|
async function updatePluginPackage(input) {
|
|
30464
30531
|
await installPluginPackage(input);
|
|
@@ -30472,6 +30539,7 @@ async function removePluginPackage(input) {
|
|
|
30472
30539
|
}
|
|
30473
30540
|
await runCommand("npm", ["uninstall", input.packageName], { cwd: input.pluginHome });
|
|
30474
30541
|
}
|
|
30542
|
+
var DEFAULT_PLUGIN_REGISTRY = "https://registry.npmjs.org";
|
|
30475
30543
|
var init_package_manager = __esm(() => {
|
|
30476
30544
|
init_plugin_home();
|
|
30477
30545
|
});
|
|
@@ -32272,7 +32340,7 @@ var require_main = __commonJS((exports, module) => {
|
|
|
32272
32340
|
});
|
|
32273
32341
|
|
|
32274
32342
|
// src/weixin/auth/login-qr.ts
|
|
32275
|
-
import { randomUUID as
|
|
32343
|
+
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
32276
32344
|
function isLoginFresh(login3) {
|
|
32277
32345
|
return Date.now() - login3.startedAt < ACTIVE_LOGIN_TTL_MS;
|
|
32278
32346
|
}
|
|
@@ -32375,7 +32443,7 @@ async function readVerifyCodeFromStdin(prompt) {
|
|
|
32375
32443
|
});
|
|
32376
32444
|
}
|
|
32377
32445
|
async function startWeixinLoginWithQr(opts) {
|
|
32378
|
-
const sessionKey = opts.accountId ||
|
|
32446
|
+
const sessionKey = opts.accountId || randomUUID7();
|
|
32379
32447
|
purgeExpiredLogins();
|
|
32380
32448
|
const existing = activeLogins.get(sessionKey);
|
|
32381
32449
|
if (!opts.force && existing && isLoginFresh(existing) && existing.qrcodeUrl) {
|
|
@@ -32398,7 +32466,7 @@ async function startWeixinLoginWithQr(opts) {
|
|
|
32398
32466
|
});
|
|
32399
32467
|
const login3 = {
|
|
32400
32468
|
sessionKey,
|
|
32401
|
-
id:
|
|
32469
|
+
id: randomUUID7(),
|
|
32402
32470
|
qrcode: qrResponse.qrcode,
|
|
32403
32471
|
qrcodeUrl: qrResponse.qrcode_img_content,
|
|
32404
32472
|
startedAt: Date.now()
|
|
@@ -36388,7 +36456,7 @@ var init_scheduled_turn = __esm(() => {
|
|
|
36388
36456
|
});
|
|
36389
36457
|
|
|
36390
36458
|
// src/weixin/monitor/consumer-lock.ts
|
|
36391
|
-
import { randomUUID as
|
|
36459
|
+
import { randomUUID as randomUUID8 } from "node:crypto";
|
|
36392
36460
|
import { mkdir as mkdir10, open as open6, readFile as readFile12, rm as rm9, writeFile as writeFile7 } from "node:fs/promises";
|
|
36393
36461
|
import { dirname as dirname15, join as join17 } from "node:path";
|
|
36394
36462
|
import { homedir as homedir6 } from "node:os";
|
|
@@ -36412,7 +36480,7 @@ function createWeixinConsumerLock(options = {}) {
|
|
|
36412
36480
|
const existing = await loadLockMetadata(lockFilePath) ?? meta2;
|
|
36413
36481
|
throw new ActiveWeixinConsumerLockError(lockFilePath, existing);
|
|
36414
36482
|
}
|
|
36415
|
-
windowsLockId = meta2.lockId ??
|
|
36483
|
+
windowsLockId = meta2.lockId ?? randomUUID8();
|
|
36416
36484
|
const metadata = {
|
|
36417
36485
|
...meta2,
|
|
36418
36486
|
schemaVersion: 2,
|
|
@@ -36432,7 +36500,7 @@ function createWeixinConsumerLock(options = {}) {
|
|
|
36432
36500
|
return;
|
|
36433
36501
|
}
|
|
36434
36502
|
const requestedIdentity = await (options.probeProcessIdentity ?? probePosixProcessIdentity)(meta2.pid);
|
|
36435
|
-
posixLockId = meta2.lockId ??
|
|
36503
|
+
posixLockId = meta2.lockId ?? randomUUID8();
|
|
36436
36504
|
const requested = requestedIdentity.status === "found" ? { ...meta2, schemaVersion: 2, lockId: posixLockId, processStartedAtMs: requestedIdentity.identity.startedAtMs } : { ...meta2, schemaVersion: 2, lockId: posixLockId };
|
|
36437
36505
|
while (true) {
|
|
36438
36506
|
try {
|
|
@@ -36916,6 +36984,12 @@ var init_registry = __esm(() => {
|
|
|
36916
36984
|
});
|
|
36917
36985
|
|
|
36918
36986
|
// src/channels/plugin.ts
|
|
36987
|
+
var exports_plugin = {};
|
|
36988
|
+
__export(exports_plugin, {
|
|
36989
|
+
registerChannelPlugin: () => registerChannelPlugin,
|
|
36990
|
+
invokeChannelRetireHook: () => invokeChannelRetireHook,
|
|
36991
|
+
getChannelRetireHook: () => getChannelRetireHook
|
|
36992
|
+
});
|
|
36919
36993
|
function registerChannelPlugin(plugin) {
|
|
36920
36994
|
bootstrapBuiltinChannelFactories();
|
|
36921
36995
|
bootstrapBuiltinChannelCliProviders();
|
|
@@ -36930,10 +37004,23 @@ function registerChannelPlugin(plugin) {
|
|
|
36930
37004
|
registerChannelFactory(plugin.type, plugin.factory);
|
|
36931
37005
|
if (plugin.cliProvider)
|
|
36932
37006
|
registerChannelCliProvider(plugin.cliProvider);
|
|
37007
|
+
if (plugin.retireChannel)
|
|
37008
|
+
retireHooks.set(channelType, plugin.retireChannel);
|
|
36933
37009
|
}
|
|
37010
|
+
function getChannelRetireHook(type) {
|
|
37011
|
+
return retireHooks.get(type);
|
|
37012
|
+
}
|
|
37013
|
+
async function invokeChannelRetireHook(ctx) {
|
|
37014
|
+
const hook = retireHooks.get(ctx.channel.type);
|
|
37015
|
+
if (!hook)
|
|
37016
|
+
return;
|
|
37017
|
+
await hook(ctx);
|
|
37018
|
+
}
|
|
37019
|
+
var retireHooks;
|
|
36934
37020
|
var init_plugin = __esm(() => {
|
|
36935
37021
|
init_create_channel();
|
|
36936
37022
|
init_registry();
|
|
37023
|
+
retireHooks = new Map;
|
|
36937
37024
|
});
|
|
36938
37025
|
|
|
36939
37026
|
// src/plugins/compatibility.ts
|
|
@@ -38373,6 +38460,13 @@ async function removeChannel(type, rawArgs, deps) {
|
|
|
38373
38460
|
deps.print(t().channelCli.cannotRemoveLastEnabled);
|
|
38374
38461
|
return 1;
|
|
38375
38462
|
}
|
|
38463
|
+
if (deps.retireChannel) {
|
|
38464
|
+
try {
|
|
38465
|
+
await deps.retireChannel(channel, "removed");
|
|
38466
|
+
} catch (error2) {
|
|
38467
|
+
deps.print(t().channelCli.channelRetirementFailed(channel.id, error2 instanceof Error ? error2.message : String(error2)));
|
|
38468
|
+
}
|
|
38469
|
+
}
|
|
38376
38470
|
config4.channels = config4.channels.filter((entry) => entry.id !== channel.id);
|
|
38377
38471
|
await deps.saveChannels(config4.channels);
|
|
38378
38472
|
deps.print(t().channelCli.channelRemoved(channel.id));
|
|
@@ -38405,6 +38499,13 @@ async function setChannelEnabled(type, enabled, rawArgs, deps) {
|
|
|
38405
38499
|
deps.print(t().channelCli.cannotDisableLastEnabled);
|
|
38406
38500
|
return 1;
|
|
38407
38501
|
}
|
|
38502
|
+
if (!enabled && channel.enabled && deps.retireChannel) {
|
|
38503
|
+
try {
|
|
38504
|
+
await deps.retireChannel(channel, "disabled");
|
|
38505
|
+
} catch (error2) {
|
|
38506
|
+
deps.print(t().channelCli.channelRetirementFailed(channel.id, error2 instanceof Error ? error2.message : String(error2)));
|
|
38507
|
+
}
|
|
38508
|
+
}
|
|
38408
38509
|
channel.enabled = enabled;
|
|
38409
38510
|
await deps.saveChannels(config4.channels);
|
|
38410
38511
|
deps.print(t().channelCli.channelEnabledToggled(channel.id, enabled));
|
|
@@ -38770,6 +38871,16 @@ async function inspectPlugins(input) {
|
|
|
38770
38871
|
message: configPlugin.enabled ? `plugin is installed and valid; channels: ${channelTypes.length > 0 ? channelTypes.join(", ") : "none"}` : `plugin is installed and valid but disabled; run xacpx plugin enable ${configPlugin.name}`,
|
|
38771
38872
|
...configPlugin.enabled ? {} : { suggestion: `xacpx plugin enable ${configPlugin.name}` }
|
|
38772
38873
|
});
|
|
38874
|
+
if (configPlugin.enabled) {
|
|
38875
|
+
for (const finding of await collectChannelDiagnoseFindings(plugin.channels ?? [], input.config)) {
|
|
38876
|
+
pushIfRelevant({
|
|
38877
|
+
level: finding.level === "skip" ? "ok" : finding.level,
|
|
38878
|
+
plugin: configPlugin.name,
|
|
38879
|
+
message: finding.level === "skip" ? `${finding.code}: ${finding.message}` : `${finding.code}: ${finding.message}`,
|
|
38880
|
+
...finding.suggestion ? { suggestion: finding.suggestion } : {}
|
|
38881
|
+
});
|
|
38882
|
+
}
|
|
38883
|
+
}
|
|
38773
38884
|
} catch (error2) {
|
|
38774
38885
|
const message = error2 instanceof Error ? error2.message : String(error2);
|
|
38775
38886
|
pushIfRelevant({ level: "error", plugin: configPlugin.name, message });
|
|
@@ -38804,6 +38915,28 @@ async function inspectPlugins(input) {
|
|
|
38804
38915
|
}
|
|
38805
38916
|
return issues;
|
|
38806
38917
|
}
|
|
38918
|
+
async function collectChannelDiagnoseFindings(channelDefs, config4) {
|
|
38919
|
+
const findings = [];
|
|
38920
|
+
for (const def of channelDefs) {
|
|
38921
|
+
const diagnose = def.cliProvider?.diagnose;
|
|
38922
|
+
if (!diagnose)
|
|
38923
|
+
continue;
|
|
38924
|
+
const runtimeChannels = (config4.channels ?? []).filter((channel) => channel.type === def.type && channel.enabled !== false);
|
|
38925
|
+
for (const channel of runtimeChannels) {
|
|
38926
|
+
try {
|
|
38927
|
+
const result = await diagnose(channel);
|
|
38928
|
+
findings.push(...result);
|
|
38929
|
+
} catch (error2) {
|
|
38930
|
+
findings.push({
|
|
38931
|
+
level: "error",
|
|
38932
|
+
code: "channel-diagnose-failed",
|
|
38933
|
+
message: `channel ${channel.type} diagnose hook failed: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
38934
|
+
});
|
|
38935
|
+
}
|
|
38936
|
+
}
|
|
38937
|
+
}
|
|
38938
|
+
return findings;
|
|
38939
|
+
}
|
|
38807
38940
|
var init_plugin_doctor = __esm(() => {
|
|
38808
38941
|
init_channel_scope();
|
|
38809
38942
|
init_plugin_loader();
|
|
@@ -49610,7 +49743,7 @@ function replaceRuntimeState(target, source) {
|
|
|
49610
49743
|
}
|
|
49611
49744
|
|
|
49612
49745
|
// src/sessions/session-service.ts
|
|
49613
|
-
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
49746
|
+
import { randomBytes as randomBytes2, randomUUID as randomUUID9 } from "node:crypto";
|
|
49614
49747
|
import { dirname as dirname19 } from "node:path";
|
|
49615
49748
|
|
|
49616
49749
|
class SessionService {
|
|
@@ -49622,6 +49755,7 @@ class SessionService {
|
|
|
49622
49755
|
platform;
|
|
49623
49756
|
runtimeRoot;
|
|
49624
49757
|
pendingSessionAliasOperations = new Set;
|
|
49758
|
+
lifecyclePublisher;
|
|
49625
49759
|
constructor(config4, stateStore, state, options = {}) {
|
|
49626
49760
|
this.config = config4;
|
|
49627
49761
|
this.stateStore = stateStore;
|
|
@@ -49667,6 +49801,7 @@ class SessionService {
|
|
|
49667
49801
|
agent: agent3,
|
|
49668
49802
|
workspace: workspace3,
|
|
49669
49803
|
transport_session: transportSession,
|
|
49804
|
+
logical_session_id: existing?.logical_session_id ?? randomUUID9(),
|
|
49670
49805
|
transport_agent_command: sameAgentExisting?.transport_agent_command,
|
|
49671
49806
|
transport_acpx_agent: sameAgentExisting?.transport_acpx_agent,
|
|
49672
49807
|
transport_agent_argv: sameAgentExisting?.transport_agent_argv,
|
|
@@ -49740,30 +49875,42 @@ class SessionService {
|
|
|
49740
49875
|
if (!session3) {
|
|
49741
49876
|
throw new Error(`session "${alias}" does not exist`);
|
|
49742
49877
|
}
|
|
49743
|
-
const prevCtx = this.state.chat_contexts[chatKey];
|
|
49744
|
-
const previousCurrent = prevCtx?.current_session;
|
|
49745
|
-
const carriedPrevious = previousCurrent && previousCurrent !== internalAlias ? previousCurrent : prevCtx?.previous_session;
|
|
49746
|
-
session3.last_used_at = new Date().toISOString();
|
|
49747
49878
|
if (session3.archived) {
|
|
49748
|
-
|
|
49749
|
-
|
|
49879
|
+
const nextState = structuredClone(this.state);
|
|
49880
|
+
const result2 = this.applyUseSession(nextState, chatKey, internalAlias);
|
|
49881
|
+
await this.commitLifecycleTransition(nextState);
|
|
49882
|
+
this.publishLifecycleEvent("restored", nextState.sessions[internalAlias]);
|
|
49883
|
+
return result2;
|
|
49750
49884
|
}
|
|
49751
|
-
const
|
|
49752
|
-
if (carriedPrevious) {
|
|
49753
|
-
nextCtx.previous_session = carriedPrevious;
|
|
49754
|
-
} else {
|
|
49755
|
-
delete nextCtx.previous_session;
|
|
49756
|
-
}
|
|
49757
|
-
this.state.chat_contexts[chatKey] = nextCtx;
|
|
49885
|
+
const result = this.applyUseSession(this.state, chatKey, internalAlias);
|
|
49758
49886
|
await this.persist();
|
|
49759
|
-
return
|
|
49760
|
-
alias: toDisplaySessionAlias(session3.alias),
|
|
49761
|
-
agent: session3.agent,
|
|
49762
|
-
workspace: session3.workspace,
|
|
49763
|
-
previousAlias: carriedPrevious ? toDisplaySessionAlias(carriedPrevious) : undefined
|
|
49764
|
-
};
|
|
49887
|
+
return result;
|
|
49765
49888
|
});
|
|
49766
49889
|
}
|
|
49890
|
+
applyUseSession(state, chatKey, internalAlias) {
|
|
49891
|
+
const session3 = state.sessions[internalAlias];
|
|
49892
|
+
const prevCtx = state.chat_contexts[chatKey];
|
|
49893
|
+
const previousCurrent = prevCtx?.current_session;
|
|
49894
|
+
const carriedPrevious = previousCurrent && previousCurrent !== internalAlias ? previousCurrent : prevCtx?.previous_session;
|
|
49895
|
+
session3.last_used_at = new Date().toISOString();
|
|
49896
|
+
if (session3.archived) {
|
|
49897
|
+
delete session3.archived;
|
|
49898
|
+
delete session3.archived_at;
|
|
49899
|
+
}
|
|
49900
|
+
const nextCtx = { ...prevCtx, current_session: internalAlias };
|
|
49901
|
+
if (carriedPrevious) {
|
|
49902
|
+
nextCtx.previous_session = carriedPrevious;
|
|
49903
|
+
} else {
|
|
49904
|
+
delete nextCtx.previous_session;
|
|
49905
|
+
}
|
|
49906
|
+
state.chat_contexts[chatKey] = nextCtx;
|
|
49907
|
+
return {
|
|
49908
|
+
alias: toDisplaySessionAlias(session3.alias),
|
|
49909
|
+
agent: session3.agent,
|
|
49910
|
+
workspace: session3.workspace,
|
|
49911
|
+
previousAlias: carriedPrevious ? toDisplaySessionAlias(carriedPrevious) : undefined
|
|
49912
|
+
};
|
|
49913
|
+
}
|
|
49767
49914
|
async usePreviousSession(chatKey) {
|
|
49768
49915
|
return await this.mutate(async () => {
|
|
49769
49916
|
const ctx = this.state.chat_contexts[chatKey];
|
|
@@ -49927,6 +50074,12 @@ class SessionService {
|
|
|
49927
50074
|
listInternalAliases() {
|
|
49928
50075
|
return Object.keys(this.state.sessions);
|
|
49929
50076
|
}
|
|
50077
|
+
getLogicalSessionRecord(alias) {
|
|
50078
|
+
return this.state.sessions[alias] ?? null;
|
|
50079
|
+
}
|
|
50080
|
+
listLogicalSessionRecords() {
|
|
50081
|
+
return Object.values(this.state.sessions);
|
|
50082
|
+
}
|
|
49930
50083
|
async setCurrentSessionMode(chatKey, modeId) {
|
|
49931
50084
|
await this.mutate(async () => {
|
|
49932
50085
|
const currentAlias = this.state.chat_contexts[chatKey]?.current_session;
|
|
@@ -50005,20 +50158,37 @@ class SessionService {
|
|
|
50005
50158
|
}
|
|
50006
50159
|
return count;
|
|
50007
50160
|
}
|
|
50161
|
+
setSessionResourceLifecyclePublisher(publish) {
|
|
50162
|
+
this.lifecyclePublisher = publish;
|
|
50163
|
+
}
|
|
50164
|
+
publishLifecycleEvent(type, record3) {
|
|
50165
|
+
this.lifecyclePublisher?.({ type, record: record3 });
|
|
50166
|
+
}
|
|
50167
|
+
async commitLifecycleTransition(nextState) {
|
|
50168
|
+
await this.stateStore.saveNow(nextState);
|
|
50169
|
+
replaceRuntimeState(this.state, nextState);
|
|
50170
|
+
}
|
|
50008
50171
|
async setArchived(alias, archived) {
|
|
50009
50172
|
await this.mutate(async () => {
|
|
50010
50173
|
const session3 = this.state.sessions[alias];
|
|
50011
50174
|
if (!session3) {
|
|
50012
50175
|
throw new Error(`session "${alias}" does not exist`);
|
|
50013
50176
|
}
|
|
50177
|
+
const wasArchived = session3.archived === true;
|
|
50178
|
+
if (wasArchived === archived) {
|
|
50179
|
+
return;
|
|
50180
|
+
}
|
|
50181
|
+
const nextState = structuredClone(this.state);
|
|
50182
|
+
const nextSession = nextState.sessions[alias];
|
|
50014
50183
|
if (archived) {
|
|
50015
|
-
|
|
50016
|
-
|
|
50184
|
+
nextSession.archived = true;
|
|
50185
|
+
nextSession.archived_at = new Date(this.now()).toISOString();
|
|
50017
50186
|
} else {
|
|
50018
|
-
delete
|
|
50019
|
-
delete
|
|
50187
|
+
delete nextSession.archived;
|
|
50188
|
+
delete nextSession.archived_at;
|
|
50020
50189
|
}
|
|
50021
|
-
await this.
|
|
50190
|
+
await this.commitLifecycleTransition(nextState);
|
|
50191
|
+
this.publishLifecycleEvent(archived ? "archived" : "restored", nextSession);
|
|
50022
50192
|
});
|
|
50023
50193
|
}
|
|
50024
50194
|
async removeSession(alias) {
|
|
@@ -50027,9 +50197,11 @@ class SessionService {
|
|
|
50027
50197
|
if (!session3) {
|
|
50028
50198
|
throw new Error(`session "${alias}" does not exist`);
|
|
50029
50199
|
}
|
|
50030
|
-
const
|
|
50031
|
-
|
|
50032
|
-
|
|
50200
|
+
const snapshot = structuredClone(session3);
|
|
50201
|
+
const nextState = structuredClone(this.state);
|
|
50202
|
+
const wasActive = Object.values(nextState.chat_contexts).some((ctx) => ctx.current_session === alias);
|
|
50203
|
+
delete nextState.sessions[alias];
|
|
50204
|
+
for (const [chatKey, ctx] of Object.entries(nextState.chat_contexts)) {
|
|
50033
50205
|
if (ctx.previous_session === alias) {
|
|
50034
50206
|
delete ctx.previous_session;
|
|
50035
50207
|
}
|
|
@@ -50048,10 +50220,11 @@ class SessionService {
|
|
|
50048
50220
|
}
|
|
50049
50221
|
}
|
|
50050
50222
|
if (!ctx.current_session && !ctx.previous_session && !ctx.background_results) {
|
|
50051
|
-
delete
|
|
50223
|
+
delete nextState.chat_contexts[chatKey];
|
|
50052
50224
|
}
|
|
50053
50225
|
}
|
|
50054
|
-
await this.
|
|
50226
|
+
await this.commitLifecycleTransition(nextState);
|
|
50227
|
+
this.publishLifecycleEvent("removed", snapshot);
|
|
50055
50228
|
return { wasActive };
|
|
50056
50229
|
});
|
|
50057
50230
|
}
|
|
@@ -50309,6 +50482,7 @@ class SessionService {
|
|
|
50309
50482
|
agent: agent3,
|
|
50310
50483
|
workspace: workspace3,
|
|
50311
50484
|
transport_session: transportSession,
|
|
50485
|
+
logical_session_id: randomUUID9(),
|
|
50312
50486
|
source: native?.source,
|
|
50313
50487
|
agent_session_id: native?.agentSessionId,
|
|
50314
50488
|
agent_session_title: native?.title ?? undefined,
|
|
@@ -50358,6 +50532,89 @@ var init_session_service = __esm(() => {
|
|
|
50358
50532
|
init_channel_scope();
|
|
50359
50533
|
});
|
|
50360
50534
|
|
|
50535
|
+
// src/sessions/session-resource-catalog.ts
|
|
50536
|
+
class CoreSessionResourceCatalog {
|
|
50537
|
+
deps;
|
|
50538
|
+
listeners = new Set;
|
|
50539
|
+
constructor(deps) {
|
|
50540
|
+
this.deps = deps;
|
|
50541
|
+
}
|
|
50542
|
+
async resolve(chatKey, alias) {
|
|
50543
|
+
let internalAlias;
|
|
50544
|
+
try {
|
|
50545
|
+
internalAlias = await this.deps.sessions.resolveAliasForChat(chatKey, alias);
|
|
50546
|
+
} catch {
|
|
50547
|
+
return null;
|
|
50548
|
+
}
|
|
50549
|
+
const record3 = this.deps.sessions.getLogicalSessionRecord(internalAlias);
|
|
50550
|
+
if (!record3) {
|
|
50551
|
+
return null;
|
|
50552
|
+
}
|
|
50553
|
+
const channelId = getChannelIdFromChatKey(chatKey);
|
|
50554
|
+
if (!isSessionAliasVisibleInChannel(record3.alias, channelId)) {
|
|
50555
|
+
return null;
|
|
50556
|
+
}
|
|
50557
|
+
return this.toDescriptor(record3);
|
|
50558
|
+
}
|
|
50559
|
+
async list(channelId) {
|
|
50560
|
+
const descriptors = [];
|
|
50561
|
+
for (const record3 of this.deps.sessions.listLogicalSessionRecords()) {
|
|
50562
|
+
if (!isSessionAliasVisibleInChannel(record3.alias, channelId)) {
|
|
50563
|
+
continue;
|
|
50564
|
+
}
|
|
50565
|
+
const descriptor = this.toDescriptor(record3);
|
|
50566
|
+
if (descriptor) {
|
|
50567
|
+
descriptors.push(descriptor);
|
|
50568
|
+
}
|
|
50569
|
+
}
|
|
50570
|
+
return descriptors;
|
|
50571
|
+
}
|
|
50572
|
+
subscribe(listener) {
|
|
50573
|
+
this.listeners.add(listener);
|
|
50574
|
+
return () => {
|
|
50575
|
+
this.listeners.delete(listener);
|
|
50576
|
+
};
|
|
50577
|
+
}
|
|
50578
|
+
publishLifecycleEvent(input) {
|
|
50579
|
+
const descriptor = this.toDescriptor(input.record);
|
|
50580
|
+
if (!descriptor) {
|
|
50581
|
+
return;
|
|
50582
|
+
}
|
|
50583
|
+
this.emit({ type: input.type, session: descriptor });
|
|
50584
|
+
}
|
|
50585
|
+
emit(event) {
|
|
50586
|
+
for (const listener of [...this.listeners]) {
|
|
50587
|
+
try {
|
|
50588
|
+
listener(event);
|
|
50589
|
+
} catch (error2) {
|
|
50590
|
+
this.deps.logger.error("sessions.resource_catalog.listener_failed", "session resource listener threw; delivery continues", {
|
|
50591
|
+
message: error2 instanceof Error ? error2.message : String(error2),
|
|
50592
|
+
eventType: event.type,
|
|
50593
|
+
internalAlias: event.session.internalAlias
|
|
50594
|
+
}).catch(() => {});
|
|
50595
|
+
}
|
|
50596
|
+
}
|
|
50597
|
+
}
|
|
50598
|
+
toDescriptor(record3) {
|
|
50599
|
+
const workspace3 = this.deps.config.workspaces[record3.workspace];
|
|
50600
|
+
if (!workspace3) {
|
|
50601
|
+
return null;
|
|
50602
|
+
}
|
|
50603
|
+
return {
|
|
50604
|
+
logicalSessionId: record3.logical_session_id,
|
|
50605
|
+
channelId: getChannelIdFromChatKey(record3.alias),
|
|
50606
|
+
internalAlias: record3.alias,
|
|
50607
|
+
displayAlias: toDisplaySessionAlias(record3.alias),
|
|
50608
|
+
workspace: record3.workspace,
|
|
50609
|
+
cwd: workspace3.cwd,
|
|
50610
|
+
archived: record3.archived === true
|
|
50611
|
+
};
|
|
50612
|
+
}
|
|
50613
|
+
}
|
|
50614
|
+
var init_session_resource_catalog = __esm(() => {
|
|
50615
|
+
init_channel_scope();
|
|
50616
|
+
});
|
|
50617
|
+
|
|
50361
50618
|
// src/sessions/active-turn-registry.ts
|
|
50362
50619
|
function createActiveTurnRegistry() {
|
|
50363
50620
|
const byChat = new Map;
|
|
@@ -50619,7 +50876,7 @@ async function deleteAcpxSessionFiles(options) {
|
|
|
50619
50876
|
var init_acpx_session_files = () => {};
|
|
50620
50877
|
|
|
50621
50878
|
// src/transport/acpx-queue-owner-launcher.ts
|
|
50622
|
-
import { createHash as createHash9, randomUUID as
|
|
50879
|
+
import { createHash as createHash9, randomUUID as randomUUID10 } from "node:crypto";
|
|
50623
50880
|
import { spawn as spawn13 } from "node:child_process";
|
|
50624
50881
|
import { access as access6, readFile as readFile18, unlink as unlink2 } from "node:fs/promises";
|
|
50625
50882
|
import { join as join27 } from "node:path";
|
|
@@ -50694,7 +50951,7 @@ class AcpxQueueOwnerLauncher {
|
|
|
50694
50951
|
this.probeSpawnedProcess = options.probeSpawnedProcess ?? defaultProbeSpawnedProcess;
|
|
50695
50952
|
this.handshakeTimeoutMs = options.handshakeTimeoutMs ?? 1e4;
|
|
50696
50953
|
this.handshakePollMs = options.handshakePollMs ?? 50;
|
|
50697
|
-
this.uuid = options.uuid ??
|
|
50954
|
+
this.uuid = options.uuid ?? randomUUID10;
|
|
50698
50955
|
this.sleep = options.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
50699
50956
|
}
|
|
50700
50957
|
async launch(input) {
|
|
@@ -56556,7 +56813,7 @@ var init_session_turn_runner = __esm(() => {
|
|
|
56556
56813
|
});
|
|
56557
56814
|
|
|
56558
56815
|
// src/control/turn-queue.ts
|
|
56559
|
-
import { randomUUID as
|
|
56816
|
+
import { randomUUID as randomUUID11 } from "node:crypto";
|
|
56560
56817
|
|
|
56561
56818
|
class TurnQueue {
|
|
56562
56819
|
deps;
|
|
@@ -56600,7 +56857,7 @@ class TurnQueue {
|
|
|
56600
56857
|
if (q.length >= QUEUE_MAX_DEPTH) {
|
|
56601
56858
|
return { ok: false, errorMessage: "queue-full" };
|
|
56602
56859
|
}
|
|
56603
|
-
const id =
|
|
56860
|
+
const id = randomUUID11();
|
|
56604
56861
|
const item = {
|
|
56605
56862
|
id,
|
|
56606
56863
|
text: params.text,
|
|
@@ -57403,7 +57660,7 @@ function warmthKey(session3) {
|
|
|
57403
57660
|
}
|
|
57404
57661
|
|
|
57405
57662
|
// src/control/terminal-service.ts
|
|
57406
|
-
import { randomUUID as
|
|
57663
|
+
import { randomUUID as randomUUID12 } from "node:crypto";
|
|
57407
57664
|
import { createRequire as createRequire8 } from "node:module";
|
|
57408
57665
|
import { statSync as statSync4 } from "node:fs";
|
|
57409
57666
|
import { spawn as spawnPty2 } from "node-pty";
|
|
@@ -57514,7 +57771,7 @@ function createTerminalService(deps) {
|
|
|
57514
57771
|
return {
|
|
57515
57772
|
create({ cwd, cols, rows }) {
|
|
57516
57773
|
const shell = resolveShell({ platform, env: process.env, shellOverride: deps.shell?.() });
|
|
57517
|
-
const terminalId =
|
|
57774
|
+
const terminalId = randomUUID12();
|
|
57518
57775
|
const handle = spawn18(shell, [], { name: "xterm-256color", cols, rows, cwd, env: scrubEnv() });
|
|
57519
57776
|
const session3 = { handle, seq: 0, idleTimer: null, buffer: "", bufBytes: 0, pending: "", pendingBytes: 0, flushTimer: null };
|
|
57520
57777
|
sessions.set(terminalId, session3);
|
|
@@ -58260,7 +58517,7 @@ __export(exports_main, {
|
|
|
58260
58517
|
main: () => main,
|
|
58261
58518
|
buildApp: () => buildApp
|
|
58262
58519
|
});
|
|
58263
|
-
import { randomUUID as
|
|
58520
|
+
import { randomUUID as randomUUID13 } from "node:crypto";
|
|
58264
58521
|
import { homedir as homedir17 } from "node:os";
|
|
58265
58522
|
import { dirname as dirname24, join as join35 } from "node:path";
|
|
58266
58523
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
@@ -58376,6 +58633,14 @@ async function buildApp(paths, deps = {}) {
|
|
|
58376
58633
|
message: stateLoadReport.backupError
|
|
58377
58634
|
});
|
|
58378
58635
|
}
|
|
58636
|
+
for (const record3 of stateLoadReport.migrated ?? []) {
|
|
58637
|
+
await logger.info("state.session_id_migrated", "assigned a new logical_session_id to a legacy session record", {
|
|
58638
|
+
statePath: paths.statePath,
|
|
58639
|
+
section: record3.section,
|
|
58640
|
+
key: record3.key,
|
|
58641
|
+
reason: record3.reason
|
|
58642
|
+
});
|
|
58643
|
+
}
|
|
58379
58644
|
}
|
|
58380
58645
|
const stateMutex = new AsyncMutex;
|
|
58381
58646
|
const debouncedStateStore = new DebouncedStateStore({
|
|
@@ -58389,11 +58654,13 @@ async function buildApp(paths, deps = {}) {
|
|
|
58389
58654
|
});
|
|
58390
58655
|
const runtimeRoot = dirname24(paths.configPath);
|
|
58391
58656
|
const sessions = new SessionService(config4, debouncedStateStore, state, { stateMutex, runtimeRoot });
|
|
58657
|
+
const sessionResources = new CoreSessionResourceCatalog({ sessions, config: config4, logger });
|
|
58658
|
+
sessions.setSessionResourceLifecyclePublisher((transition) => sessionResources.publishLifecycleEvent(transition));
|
|
58392
58659
|
const launchIntentCoordinator = new LaunchIntentCoordinator({
|
|
58393
58660
|
platform: process.platform,
|
|
58394
58661
|
runtimeRoot,
|
|
58395
58662
|
configRoot: runtimeRoot,
|
|
58396
|
-
generationId: deps.daemonIdentity?.generationId ??
|
|
58663
|
+
generationId: deps.daemonIdentity?.generationId ?? randomUUID13(),
|
|
58397
58664
|
...deps.orphanRegistry ? { registry: deps.orphanRegistry } : {},
|
|
58398
58665
|
classifyAdapter: (command) => classifyPreinstalledAdapterCommandShape(command),
|
|
58399
58666
|
resolveAdapter: async (command) => (await validateAndReResolveAdapterCommand(runtimeRoot, command)).agentCommand,
|
|
@@ -58735,7 +59002,7 @@ async function buildApp(paths, deps = {}) {
|
|
|
58735
59002
|
};
|
|
58736
59003
|
orchestration3 = new OrchestrationService({
|
|
58737
59004
|
now: deps.loggerNow ?? (() => new Date),
|
|
58738
|
-
createId: () =>
|
|
59005
|
+
createId: () => randomUUID13(),
|
|
58739
59006
|
config: config4,
|
|
58740
59007
|
loadState: async () => JSON.parse(JSON.stringify(state)),
|
|
58741
59008
|
saveState: async (nextState) => {
|
|
@@ -59008,6 +59275,7 @@ async function buildApp(paths, deps = {}) {
|
|
|
59008
59275
|
agent: agent3,
|
|
59009
59276
|
router: router3,
|
|
59010
59277
|
sessions,
|
|
59278
|
+
sessionResources,
|
|
59011
59279
|
activeTurns,
|
|
59012
59280
|
stateStore,
|
|
59013
59281
|
configStore,
|
|
@@ -59144,6 +59412,7 @@ var init_main = __esm(() => {
|
|
|
59144
59412
|
init_scheduled_route_create();
|
|
59145
59413
|
init_scheduled_route_manage();
|
|
59146
59414
|
init_session_service();
|
|
59415
|
+
init_session_resource_catalog();
|
|
59147
59416
|
init_state_store();
|
|
59148
59417
|
init_acpx_bridge_client();
|
|
59149
59418
|
init_acpx_bridge_transport();
|
|
@@ -59344,6 +59613,7 @@ async function runConsole(paths, deps) {
|
|
|
59344
59613
|
abortSignal: shutdownController.signal,
|
|
59345
59614
|
quota: runtime.quota,
|
|
59346
59615
|
sessions: runtime.sessions,
|
|
59616
|
+
sessionResources: runtime.sessionResources,
|
|
59347
59617
|
activeTurns: runtime.activeTurns,
|
|
59348
59618
|
logger: runtime.logger,
|
|
59349
59619
|
perfTracer: runtime.perfTracer,
|
|
@@ -59509,14 +59779,14 @@ class MessageChannelRegistry {
|
|
|
59509
59779
|
throw new Error("all channels failed to start");
|
|
59510
59780
|
}
|
|
59511
59781
|
}
|
|
59512
|
-
async stopAll() {
|
|
59782
|
+
async stopAll(reason = "shutdown") {
|
|
59513
59783
|
let firstError;
|
|
59514
59784
|
for (const channel of this.channels.values()) {
|
|
59515
59785
|
try {
|
|
59516
59786
|
if (channel.stop) {
|
|
59517
|
-
await channel.stop();
|
|
59787
|
+
await channel.stop(reason);
|
|
59518
59788
|
} else {
|
|
59519
|
-
channel.logout();
|
|
59789
|
+
await channel.logout();
|
|
59520
59790
|
}
|
|
59521
59791
|
} catch (error2) {
|
|
59522
59792
|
firstError ??= error2;
|
|
@@ -61232,11 +61502,20 @@ function applyStateInspectionReport(result, report, statePath, daemonRunning, is
|
|
|
61232
61502
|
if (!report) {
|
|
61233
61503
|
return result;
|
|
61234
61504
|
}
|
|
61505
|
+
const migrated = report.migrated ?? [];
|
|
61506
|
+
const migrationDetails = migrated.map((record3) => `legacy session record ${record3.section}["${record3.key}"]: ${record3.reason} (applied automatically at next daemon startup)`);
|
|
61507
|
+
if (report.dropped.length === 0) {
|
|
61508
|
+
return {
|
|
61509
|
+
...result,
|
|
61510
|
+
details: [...result.details ?? [], `state path: ${statePath}`, ...migrationDetails]
|
|
61511
|
+
};
|
|
61512
|
+
}
|
|
61235
61513
|
const fileCorrupt = report.dropped.some((record3) => record3.section === "file");
|
|
61236
61514
|
const details = [
|
|
61237
61515
|
...result.details ?? [],
|
|
61238
61516
|
`state path: ${statePath}`,
|
|
61239
|
-
...report.dropped.map((record3) => record3.section === "file" ? `state.json is unreadable: ${record3.reason}` : `invalid state record ${record3.section}["${record3.key}"]: ${record3.reason}`)
|
|
61517
|
+
...report.dropped.map((record3) => record3.section === "file" ? `state.json is unreadable: ${record3.reason}` : `invalid state record ${record3.section}["${record3.key}"]: ${record3.reason}`),
|
|
61518
|
+
...migrationDetails
|
|
61240
61519
|
];
|
|
61241
61520
|
return {
|
|
61242
61521
|
...result,
|
|
@@ -61272,9 +61551,11 @@ function createStateQuarantineFix(statePath, daemonRunning, isDaemonRunning) {
|
|
|
61272
61551
|
return { ok: true, message: `state.json was unreadable; renamed to ${report.corruptPath} and reset` };
|
|
61273
61552
|
}
|
|
61274
61553
|
const backup = report.quarantinePath ? ` (original backed up to ${report.quarantinePath})` : "";
|
|
61554
|
+
const migratedCount = report.migrated?.length ?? 0;
|
|
61555
|
+
const migration = migratedCount > 0 ? `; assigned logical_session_id to ${migratedCount} legacy session record(s)` : "";
|
|
61275
61556
|
return {
|
|
61276
61557
|
ok: true,
|
|
61277
|
-
message: `quarantined ${report.dropped.length} invalid state.json record(s)${backup}`
|
|
61558
|
+
message: `quarantined ${report.dropped.length} invalid state.json record(s)${backup}${migration}`
|
|
61278
61559
|
};
|
|
61279
61560
|
}
|
|
61280
61561
|
};
|
|
@@ -61354,7 +61635,7 @@ __export(exports_cli, {
|
|
|
61354
61635
|
getUsageText: () => getUsageText,
|
|
61355
61636
|
createMcpStdioIdentityResolver: () => createMcpStdioIdentityResolver
|
|
61356
61637
|
});
|
|
61357
|
-
import { randomUUID as
|
|
61638
|
+
import { randomUUID as randomUUID14 } from "node:crypto";
|
|
61358
61639
|
import { homedir as homedir23 } from "node:os";
|
|
61359
61640
|
import { dirname as dirname26, join as join39, sep as sep6 } from "node:path";
|
|
61360
61641
|
import { fileURLToPath as fileURLToPath8 } from "node:url";
|
|
@@ -61400,7 +61681,7 @@ async function prepareMcpCoordinatorStartup(input) {
|
|
|
61400
61681
|
return { kind: "external-coordinator" };
|
|
61401
61682
|
}
|
|
61402
61683
|
function createMcpStdioIdentityResolver(input) {
|
|
61403
|
-
const instanceId =
|
|
61684
|
+
const instanceId = randomUUID14().slice(0, 8);
|
|
61404
61685
|
return async (context) => {
|
|
61405
61686
|
const parsedCoordinatorSession = input.parsedCoordinatorSession?.trim() || null;
|
|
61406
61687
|
const workspace3 = input.workspace?.trim() || null;
|
|
@@ -61745,6 +62026,10 @@ function warnStateLoadReport(store, writeStderr = (text) => process.stderr.write
|
|
|
61745
62026
|
}
|
|
61746
62027
|
if (report.backupError) {
|
|
61747
62028
|
writeStderr(`[xacpx] state.quarantine_backup_failed ${report.backupError}
|
|
62029
|
+
`);
|
|
62030
|
+
}
|
|
62031
|
+
for (const record3 of report.migrated ?? []) {
|
|
62032
|
+
writeStderr(`[xacpx] state.session_id_migrated section=${record3.section}${record3.key ? ` key=${record3.key}` : ""} reason=${record3.reason}
|
|
61748
62033
|
`);
|
|
61749
62034
|
}
|
|
61750
62035
|
}
|
|
@@ -62064,7 +62349,7 @@ async function defaultLogin() {
|
|
|
62064
62349
|
}
|
|
62065
62350
|
async function defaultLogout() {
|
|
62066
62351
|
const channel = await resolveLoginChannelForCli();
|
|
62067
|
-
channel.logout();
|
|
62352
|
+
await channel.logout();
|
|
62068
62353
|
}
|
|
62069
62354
|
async function defaultLoadConfiguredPluginsForChannelCli() {
|
|
62070
62355
|
const store = await createCliConfigStore();
|
|
@@ -62294,7 +62579,23 @@ async function createChannelCliDeps(input) {
|
|
|
62294
62579
|
restartDaemon: async () => await restartDaemonCli(controller, input.print),
|
|
62295
62580
|
clearChannelCredentials: async (channel) => {
|
|
62296
62581
|
const { createMessageChannel: createMessageChannel2 } = await Promise.resolve().then(() => (init_create_channel(), exports_create_channel));
|
|
62297
|
-
createMessageChannel2(channel.type, channel).logout();
|
|
62582
|
+
await createMessageChannel2(channel.type, channel).logout();
|
|
62583
|
+
},
|
|
62584
|
+
retireChannel: async (channel, reason) => {
|
|
62585
|
+
const { invokeChannelRetireHook: invokeChannelRetireHook2 } = await Promise.resolve().then(() => (init_plugin(), exports_plugin));
|
|
62586
|
+
await invokeChannelRetireHook2({
|
|
62587
|
+
channel,
|
|
62588
|
+
reason,
|
|
62589
|
+
print: input.print,
|
|
62590
|
+
getDaemonStatus: async () => {
|
|
62591
|
+
const status = await controller.getStatus();
|
|
62592
|
+
if (status.state === "running")
|
|
62593
|
+
return { state: "running" };
|
|
62594
|
+
if (status.state === "indeterminate")
|
|
62595
|
+
return { state: "indeterminate" };
|
|
62596
|
+
return { state: "stopped" };
|
|
62597
|
+
}
|
|
62598
|
+
});
|
|
62298
62599
|
}
|
|
62299
62600
|
};
|
|
62300
62601
|
return { ...base, ...input.overrides };
|