@moxt-ai/mobius 0.0.5 → 0.0.6
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/acp/native-session.d.ts +30 -0
- package/dist/acp/native-session.d.ts.map +1 -0
- package/dist/acp/native-session.js +25 -0
- package/dist/acp/native-session.js.map +1 -0
- package/dist/acp/session-history.d.ts +9 -0
- package/dist/acp/session-history.d.ts.map +1 -0
- package/dist/acp/session-history.js +69 -0
- package/dist/acp/session-history.js.map +1 -0
- package/dist/acp/session-manager.d.ts +16 -5
- package/dist/acp/session-manager.d.ts.map +1 -1
- package/dist/acp/session-manager.js +211 -12
- package/dist/acp/session-manager.js.map +1 -1
- package/dist/acp/session-store.d.ts +9 -0
- package/dist/acp/session-store.d.ts.map +1 -1
- package/dist/acp/session-store.js +43 -0
- package/dist/acp/session-store.js.map +1 -1
- package/dist/agent-catalog/discover-local-agents.d.ts +1 -1
- package/dist/agent-catalog/discover-local-agents.d.ts.map +1 -1
- package/dist/agent-catalog/discover-local-agents.js +19 -30
- package/dist/agent-catalog/discover-local-agents.js.map +1 -1
- package/dist/agent-installation/automatic-adapter-provisioner.d.ts +1 -1
- package/dist/agent-installation/automatic-adapter-provisioner.d.ts.map +1 -1
- package/dist/agent-installation/automatic-adapter-provisioner.js +1 -1
- package/dist/agent-installation/automatic-adapter-provisioner.js.map +1 -1
- package/dist/agent-installation/fixed-installation-executor.d.ts +1 -1
- package/dist/agent-installation/fixed-installation-executor.d.ts.map +1 -1
- package/dist/agent-installation/fixed-installation-executor.js +9 -18
- package/dist/agent-installation/fixed-installation-executor.js.map +1 -1
- package/dist/agent-installation/managed-adapter-installer.d.ts +0 -1
- package/dist/agent-installation/managed-adapter-installer.d.ts.map +1 -1
- package/dist/agent-installation/managed-adapter-installer.js +1 -3
- package/dist/agent-installation/managed-adapter-installer.js.map +1 -1
- package/dist/authorization/local-authorization-error.d.ts +5 -0
- package/dist/authorization/local-authorization-error.d.ts.map +1 -0
- package/dist/authorization/local-authorization-error.js +8 -0
- package/dist/authorization/local-authorization-error.js.map +1 -0
- package/dist/authorization/workspace-directory.d.ts +16 -5
- package/dist/authorization/workspace-directory.d.ts.map +1 -1
- package/dist/authorization/workspace-directory.js +109 -119
- package/dist/authorization/workspace-directory.js.map +1 -1
- package/dist/cli.js +1851 -543
- package/dist/cli.js.map +4 -4
- package/dist/config.d.ts +3 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +7 -5
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1866 -593
- package/dist/index.js.map +4 -4
- package/dist/native-sessions/codex-history.d.ts +11 -0
- package/dist/native-sessions/codex-history.d.ts.map +1 -0
- package/dist/native-sessions/codex-history.js +223 -0
- package/dist/native-sessions/codex-history.js.map +1 -0
- package/dist/native-sessions/service.d.ts +14 -0
- package/dist/native-sessions/service.d.ts.map +1 -0
- package/dist/native-sessions/service.js +249 -0
- package/dist/native-sessions/service.js.map +1 -0
- package/dist/pairing/pair-local-machine.d.ts.map +1 -1
- package/dist/pairing/pair-local-machine.js +29 -26
- package/dist/pairing/pair-local-machine.js.map +1 -1
- package/dist/process/executable.d.ts +1 -1
- package/dist/process/executable.d.ts.map +1 -1
- package/dist/process/executable.js +3 -11
- package/dist/process/executable.js.map +1 -1
- package/dist/run-daemon.d.ts.map +1 -1
- package/dist/run-daemon.js +274 -193
- package/dist/run-daemon.js.map +1 -1
- package/package.json +3 -2
- package/dist/authorization/authorize-binding.d.ts +0 -6
- package/dist/authorization/authorize-binding.d.ts.map +0 -1
- package/dist/authorization/authorize-binding.js +0 -30
- package/dist/authorization/authorize-binding.js.map +0 -1
package/dist/cli.js
CHANGED
|
@@ -5,10 +5,12 @@ var __export = (target, all) => {
|
|
|
5
5
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
+
// src/cli.ts
|
|
9
|
+
import { mkdir as mkdir4 } from "node:fs/promises";
|
|
10
|
+
|
|
8
11
|
// src/agent-catalog/discover-local-agents.ts
|
|
9
12
|
import { spawn as spawn2 } from "node:child_process";
|
|
10
|
-
import {
|
|
11
|
-
import { isAbsolute as isAbsolute2, join as join5, relative as relative3, resolve as resolve3 } from "node:path";
|
|
13
|
+
import { isAbsolute, join as join5 } from "node:path";
|
|
12
14
|
import {
|
|
13
15
|
methods as methods2,
|
|
14
16
|
ndJsonStream,
|
|
@@ -41,10 +43,10 @@ function isRecord(value) {
|
|
|
41
43
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
42
44
|
}
|
|
43
45
|
async function readGrantedAgents(stateDirectory) {
|
|
44
|
-
const
|
|
46
|
+
const path2 = join(stateDirectory, "installation-grants.json");
|
|
45
47
|
let handle;
|
|
46
48
|
try {
|
|
47
|
-
handle = await open(
|
|
49
|
+
handle = await open(path2, "r");
|
|
48
50
|
} catch (error61) {
|
|
49
51
|
if (error61 instanceof Error && "code" in error61 && error61.code === "ENOENT") {
|
|
50
52
|
return /* @__PURE__ */ new Set();
|
|
@@ -84,13 +86,13 @@ import {
|
|
|
84
86
|
rm,
|
|
85
87
|
stat as stat2
|
|
86
88
|
} from "node:fs/promises";
|
|
87
|
-
import { delimiter, dirname, join as join3, relative
|
|
89
|
+
import { delimiter, dirname, join as join3, relative } from "node:path";
|
|
88
90
|
|
|
89
91
|
// src/process/executable.ts
|
|
90
92
|
import { spawn } from "node:child_process";
|
|
91
93
|
import { constants } from "node:fs";
|
|
92
94
|
import { access, realpath, stat } from "node:fs/promises";
|
|
93
|
-
import {
|
|
95
|
+
import { join as join2, resolve } from "node:path";
|
|
94
96
|
var DEFAULT_OUTPUT_LIMIT_BYTES = 16 * 1024;
|
|
95
97
|
var PROCESS_GRACEFUL_STOP_TIMEOUT_MILLISECONDS = 1e3;
|
|
96
98
|
var PROCESS_FORCED_STOP_TIMEOUT_MILLISECONDS = 5e3;
|
|
@@ -114,9 +116,9 @@ var ExecutableIdentity = class {
|
|
|
114
116
|
var ResolvedExecutable = class {
|
|
115
117
|
identity;
|
|
116
118
|
path;
|
|
117
|
-
constructor(
|
|
118
|
-
this.identity =
|
|
119
|
-
this.path =
|
|
119
|
+
constructor(identity2) {
|
|
120
|
+
this.identity = identity2;
|
|
121
|
+
this.path = identity2.realPath;
|
|
120
122
|
}
|
|
121
123
|
};
|
|
122
124
|
var ProcessExecutionError = class extends Error {
|
|
@@ -135,10 +137,6 @@ var ProcessResult = class {
|
|
|
135
137
|
this.stdout = stdout;
|
|
136
138
|
}
|
|
137
139
|
};
|
|
138
|
-
function isInside(root, candidate) {
|
|
139
|
-
const difference = relative(root, candidate);
|
|
140
|
-
return difference.length === 0 || !difference.startsWith("..") && !isAbsolute(difference);
|
|
141
|
-
}
|
|
142
140
|
function executableExtensions(executableName, environment, platform) {
|
|
143
141
|
if (platform !== "win32") {
|
|
144
142
|
return [""];
|
|
@@ -177,10 +175,9 @@ async function resolveExecutablePath(requestedPath, platform = process.platform)
|
|
|
177
175
|
return null;
|
|
178
176
|
}
|
|
179
177
|
}
|
|
180
|
-
async function findExecutableOnPath(executableName, environment,
|
|
178
|
+
async function findExecutableOnPath(executableName, environment, platform = process.platform) {
|
|
181
179
|
const encodedPath = environment["PATH"] ?? "";
|
|
182
180
|
const separator = platform === "win32" ? ";" : ":";
|
|
183
|
-
const approvedRealPath = await realpath(resolve(approvedRoot));
|
|
184
181
|
const extensions = executableExtensions(
|
|
185
182
|
executableName,
|
|
186
183
|
environment,
|
|
@@ -195,16 +192,16 @@ async function findExecutableOnPath(executableName, environment, approvedRoot, p
|
|
|
195
192
|
join2(entry, `${executableName}${extension}`)
|
|
196
193
|
);
|
|
197
194
|
const executable = await resolveExecutablePath(requestedPath, platform);
|
|
198
|
-
if (executable !== null
|
|
195
|
+
if (executable !== null) {
|
|
199
196
|
return executable;
|
|
200
197
|
}
|
|
201
198
|
}
|
|
202
199
|
}
|
|
203
200
|
return null;
|
|
204
201
|
}
|
|
205
|
-
async function revalidateExecutable(
|
|
206
|
-
const current = await resolveExecutablePath(
|
|
207
|
-
return current !== null &&
|
|
202
|
+
async function revalidateExecutable(identity2, platform = process.platform) {
|
|
203
|
+
const current = await resolveExecutablePath(identity2.requestedPath, platform);
|
|
204
|
+
return current !== null && identity2.matches(current.identity);
|
|
208
205
|
}
|
|
209
206
|
function appendBounded(chunks, chunk, currentBytes, limitBytes) {
|
|
210
207
|
const nextBytes = currentBytes + chunk.byteLength;
|
|
@@ -444,8 +441,8 @@ function isRecord2(value) {
|
|
|
444
441
|
function packagePath(root, packageName) {
|
|
445
442
|
return join3(root, "node_modules", ...packageName.split("/"));
|
|
446
443
|
}
|
|
447
|
-
async function readPackageJson(
|
|
448
|
-
const handle = await open2(
|
|
444
|
+
async function readPackageJson(path2) {
|
|
445
|
+
const handle = await open2(path2, "r");
|
|
449
446
|
try {
|
|
450
447
|
const metadata = await handle.stat();
|
|
451
448
|
if (!metadata.isFile() || metadata.size > PACKAGE_METADATA_LIMIT_BYTES) {
|
|
@@ -486,7 +483,7 @@ async function validateManagedAdapter(root, specification) {
|
|
|
486
483
|
const packageRoot = await realpath2(
|
|
487
484
|
packagePath(rootPath, specification.adapterPackage)
|
|
488
485
|
);
|
|
489
|
-
const packageDifference =
|
|
486
|
+
const packageDifference = relative(rootPath, packageRoot);
|
|
490
487
|
if (packageDifference.startsWith("..") || packageDifference.length === 0) {
|
|
491
488
|
throw new ManagedAdapterInstallError(
|
|
492
489
|
"adapter_verification_failed",
|
|
@@ -510,7 +507,7 @@ async function validateManagedAdapter(root, specification) {
|
|
|
510
507
|
"The managed adapter executable is invalid"
|
|
511
508
|
);
|
|
512
509
|
}
|
|
513
|
-
const executableDifference =
|
|
510
|
+
const executableDifference = relative(rootPath, executable.path);
|
|
514
511
|
if (executableDifference.startsWith("..") || executableDifference.length === 0) {
|
|
515
512
|
throw new ManagedAdapterInstallError(
|
|
516
513
|
"adapter_verification_failed",
|
|
@@ -520,11 +517,9 @@ async function validateManagedAdapter(root, specification) {
|
|
|
520
517
|
return executable;
|
|
521
518
|
}
|
|
522
519
|
var ManagedAdapterInstaller = class {
|
|
523
|
-
#approvedRoot;
|
|
524
520
|
#environment;
|
|
525
521
|
#stateDirectory;
|
|
526
522
|
constructor(options) {
|
|
527
|
-
this.#approvedRoot = options.approvedRoot;
|
|
528
523
|
this.#environment = options.environment;
|
|
529
524
|
this.#stateDirectory = options.stateDirectory;
|
|
530
525
|
}
|
|
@@ -549,8 +544,7 @@ var ManagedAdapterInstaller = class {
|
|
|
549
544
|
try {
|
|
550
545
|
const npm = await findExecutableOnPath(
|
|
551
546
|
process.platform === "win32" ? "npm.cmd" : "npm",
|
|
552
|
-
this.#environment
|
|
553
|
-
this.#approvedRoot
|
|
547
|
+
this.#environment
|
|
554
548
|
);
|
|
555
549
|
if (npm === null) {
|
|
556
550
|
throw new ManagedAdapterInstallError(
|
|
@@ -633,8 +627,8 @@ function readStateDirectory(environment = process.env) {
|
|
|
633
627
|
|
|
634
628
|
// src/agent-catalog/local-agent.ts
|
|
635
629
|
import { realpathSync, statSync } from "node:fs";
|
|
636
|
-
function readTrustedIdentity(
|
|
637
|
-
const resolvedPath = realpathSync(
|
|
630
|
+
function readTrustedIdentity(path2) {
|
|
631
|
+
const resolvedPath = realpathSync(path2);
|
|
638
632
|
const metadata = statSync(resolvedPath);
|
|
639
633
|
return new ExecutableIdentity(
|
|
640
634
|
resolvedPath,
|
|
@@ -894,23 +888,11 @@ var DiscoveryAcpHandler = class {
|
|
|
894
888
|
onPermission = (_request, _signal) => Promise.reject(new Error("ACP probe does not grant permissions"));
|
|
895
889
|
onUpdate = (_notification) => Promise.resolve();
|
|
896
890
|
};
|
|
897
|
-
async function authorizeManagedExecutable(managed, options) {
|
|
898
|
-
const approvedRoot = await realpath3(resolve3(options.approvedRoot));
|
|
899
|
-
const requestedDifference = relative3(
|
|
900
|
-
approvedRoot,
|
|
901
|
-
managed.identity.requestedPath
|
|
902
|
-
);
|
|
903
|
-
const resolvedDifference = relative3(approvedRoot, managed.path);
|
|
904
|
-
const requestedInside = requestedDifference.length === 0 || !requestedDifference.startsWith("..") && !isAbsolute2(requestedDifference);
|
|
905
|
-
const resolvedInside = resolvedDifference.length === 0 || !resolvedDifference.startsWith("..") && !isAbsolute2(resolvedDifference);
|
|
906
|
-
return requestedInside || resolvedInside ? null : managed;
|
|
907
|
-
}
|
|
908
891
|
async function resolveManagedExecutable(managedExecutablePath, options) {
|
|
909
|
-
|
|
892
|
+
return await resolveExecutablePath(
|
|
910
893
|
join5(readStateDirectory(options.environment), ...managedExecutablePath),
|
|
911
894
|
options.platform
|
|
912
895
|
);
|
|
913
|
-
return managed === null ? null : await authorizeManagedExecutable(managed, options);
|
|
914
896
|
}
|
|
915
897
|
async function resolveManagedAdapterExecutable(specification, options) {
|
|
916
898
|
let managed;
|
|
@@ -927,12 +909,12 @@ async function resolveManagedAdapterExecutable(specification, options) {
|
|
|
927
909
|
} catch {
|
|
928
910
|
return null;
|
|
929
911
|
}
|
|
930
|
-
return
|
|
912
|
+
return managed;
|
|
931
913
|
}
|
|
932
914
|
async function resolveSpecificationExecutables(executableName, overrideVariable, resolveManaged, options) {
|
|
933
915
|
const override = options.environment[overrideVariable];
|
|
934
916
|
if (override !== void 0) {
|
|
935
|
-
if (override.length === 0 || !
|
|
917
|
+
if (override.length === 0 || !isAbsolute(override)) {
|
|
936
918
|
return [];
|
|
937
919
|
}
|
|
938
920
|
const executable = await resolveExecutablePath(override, options.platform);
|
|
@@ -941,7 +923,6 @@ async function resolveSpecificationExecutables(executableName, overrideVariable,
|
|
|
941
923
|
const external = await findExecutableOnPath(
|
|
942
924
|
executableName,
|
|
943
925
|
options.environment,
|
|
944
|
-
options.approvedRoot,
|
|
945
926
|
options.platform
|
|
946
927
|
);
|
|
947
928
|
const managed = await resolveManaged();
|
|
@@ -983,11 +964,11 @@ async function resolveAdapterExecutable(specification, options) {
|
|
|
983
964
|
function normalizedVersion(output2) {
|
|
984
965
|
return output2.trim().split(/\r?\n/, 1)[0]?.trim().slice(0, 128) ?? "";
|
|
985
966
|
}
|
|
986
|
-
async function probeVersion(executable, environment,
|
|
967
|
+
async function probeVersion(executable, environment, defaultWorkspace, signal) {
|
|
987
968
|
const result = await runBoundedProcess({
|
|
988
969
|
arguments: ["--version"],
|
|
989
970
|
command: executable.path,
|
|
990
|
-
cwd:
|
|
971
|
+
cwd: defaultWorkspace,
|
|
991
972
|
environment,
|
|
992
973
|
signal,
|
|
993
974
|
timeoutMilliseconds: VERSION_PROBE_TIMEOUT_MILLISECONDS
|
|
@@ -1016,7 +997,7 @@ async function findVerifiedAgentExecutable(specification, options) {
|
|
|
1016
997
|
const version2 = await probeVersion(
|
|
1017
998
|
executable,
|
|
1018
999
|
options.environment,
|
|
1019
|
-
options.
|
|
1000
|
+
options.defaultWorkspace,
|
|
1020
1001
|
options.signal
|
|
1021
1002
|
);
|
|
1022
1003
|
return new VerifiedAgentExecutable(executable, version2);
|
|
@@ -1083,7 +1064,7 @@ function writableAcpStream(output2) {
|
|
|
1083
1064
|
}
|
|
1084
1065
|
});
|
|
1085
1066
|
}
|
|
1086
|
-
async function probeAcp(agent, environment,
|
|
1067
|
+
async function probeAcp(agent, environment, defaultWorkspace, signal) {
|
|
1087
1068
|
signal.throwIfAborted();
|
|
1088
1069
|
const controller = new AbortController();
|
|
1089
1070
|
let timedOut = false;
|
|
@@ -1097,12 +1078,18 @@ async function probeAcp(agent, environment, approvedRoot, signal) {
|
|
|
1097
1078
|
abort();
|
|
1098
1079
|
}
|
|
1099
1080
|
const child = spawn2(agent.adapterPath, [...agent.arguments], {
|
|
1100
|
-
cwd:
|
|
1081
|
+
cwd: defaultWorkspace,
|
|
1101
1082
|
detached: process.platform !== "win32",
|
|
1102
1083
|
env: { ...environment, ...agent.environment },
|
|
1103
1084
|
shell: false,
|
|
1104
1085
|
stdio: ["pipe", "pipe", "pipe"]
|
|
1105
1086
|
});
|
|
1087
|
+
const processExit = new Promise((_resolve, reject) => {
|
|
1088
|
+
const rejectExit = () => reject(new Error("ACP adapter exited during initialization"));
|
|
1089
|
+
child.once("error", reject);
|
|
1090
|
+
child.once("exit", rejectExit);
|
|
1091
|
+
if (child.exitCode !== null || child.signalCode !== null) rejectExit();
|
|
1092
|
+
});
|
|
1106
1093
|
const stdin = child.stdin;
|
|
1107
1094
|
const stdout = child.stdout;
|
|
1108
1095
|
const stderr = child.stderr;
|
|
@@ -1124,13 +1111,6 @@ async function probeAcp(agent, environment, approvedRoot, signal) {
|
|
|
1124
1111
|
const connection = createAcpClient(new DiscoveryAcpHandler()).connect(
|
|
1125
1112
|
ndJsonStream(writableAcpStream(stdin), readableAcpStream(stdout))
|
|
1126
1113
|
);
|
|
1127
|
-
const processExit = new Promise((_resolve, reject) => {
|
|
1128
|
-
child.once("error", (error61) => reject(error61));
|
|
1129
|
-
child.once(
|
|
1130
|
-
"exit",
|
|
1131
|
-
() => reject(new Error("ACP adapter exited during initialization"))
|
|
1132
|
-
);
|
|
1133
|
-
});
|
|
1134
1114
|
try {
|
|
1135
1115
|
const initialized = await Promise.race([
|
|
1136
1116
|
connection.agent.request(
|
|
@@ -1215,7 +1195,7 @@ async function discoverSpecification(specification, options) {
|
|
|
1215
1195
|
agentVersion = await probeVersion(
|
|
1216
1196
|
agent,
|
|
1217
1197
|
options.environment,
|
|
1218
|
-
options.
|
|
1198
|
+
options.defaultWorkspace,
|
|
1219
1199
|
options.signal
|
|
1220
1200
|
);
|
|
1221
1201
|
} catch (error61) {
|
|
@@ -1234,7 +1214,7 @@ async function discoverSpecification(specification, options) {
|
|
|
1234
1214
|
...options.environment,
|
|
1235
1215
|
[specification.adapterEnvironmentVariable]: agent.path
|
|
1236
1216
|
},
|
|
1237
|
-
options.
|
|
1217
|
+
options.defaultWorkspace,
|
|
1238
1218
|
options.signal
|
|
1239
1219
|
);
|
|
1240
1220
|
} catch (error61) {
|
|
@@ -1259,7 +1239,7 @@ async function discoverSpecification(specification, options) {
|
|
|
1259
1239
|
await probeAcp(
|
|
1260
1240
|
definition,
|
|
1261
1241
|
options.environment,
|
|
1262
|
-
options.
|
|
1242
|
+
options.defaultWorkspace,
|
|
1263
1243
|
options.signal
|
|
1264
1244
|
);
|
|
1265
1245
|
return new AvailableAgent(specification, definition);
|
|
@@ -1374,9 +1354,9 @@ import { dirname as dirname2 } from "node:path";
|
|
|
1374
1354
|
import { DatabaseSync } from "node:sqlite";
|
|
1375
1355
|
var AuditStore = class {
|
|
1376
1356
|
database;
|
|
1377
|
-
constructor(
|
|
1378
|
-
mkdirSync(dirname2(
|
|
1379
|
-
this.database = new DatabaseSync(
|
|
1357
|
+
constructor(path2) {
|
|
1358
|
+
mkdirSync(dirname2(path2), { recursive: true });
|
|
1359
|
+
this.database = new DatabaseSync(path2);
|
|
1380
1360
|
this.database.exec(`
|
|
1381
1361
|
CREATE TABLE IF NOT EXISTS audit_events (
|
|
1382
1362
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -1419,13 +1399,15 @@ var AuditStore = class {
|
|
|
1419
1399
|
};
|
|
1420
1400
|
|
|
1421
1401
|
// src/config.ts
|
|
1422
|
-
|
|
1423
|
-
|
|
1402
|
+
import { join as join6 } from "node:path";
|
|
1403
|
+
function loadDefaultWorkspace() {
|
|
1404
|
+
const { MOBIUS_DEFAULT_WORKSPACE: configuredWorkspace } = process.env;
|
|
1405
|
+
return configuredWorkspace ?? join6(readStateDirectory(), "workspace");
|
|
1424
1406
|
}
|
|
1425
1407
|
function createDaemonConfig(connection, agents = [], installableAgents = []) {
|
|
1426
1408
|
return {
|
|
1427
1409
|
agents,
|
|
1428
|
-
|
|
1410
|
+
defaultWorkspace: connection.defaultWorkspace,
|
|
1429
1411
|
auditDatabasePath: connection.auditDatabasePath,
|
|
1430
1412
|
bindingId: "workspace",
|
|
1431
1413
|
catalog: new LocalAgentCatalog(agents, installableAgents),
|
|
@@ -1440,13 +1422,13 @@ import { randomUUID } from "node:crypto";
|
|
|
1440
1422
|
import {
|
|
1441
1423
|
mkdir as mkdir2,
|
|
1442
1424
|
open as open3,
|
|
1443
|
-
realpath as
|
|
1425
|
+
realpath as realpath3,
|
|
1444
1426
|
rename as rename2,
|
|
1445
1427
|
stat as stat3,
|
|
1446
1428
|
writeFile
|
|
1447
1429
|
} from "node:fs/promises";
|
|
1448
1430
|
import { hostname } from "node:os";
|
|
1449
|
-
import { basename, join as
|
|
1431
|
+
import { basename, join as join7, resolve as resolve3 } from "node:path";
|
|
1450
1432
|
import { fetch } from "undici";
|
|
1451
1433
|
|
|
1452
1434
|
// src/network/environment-proxy.ts
|
|
@@ -1461,7 +1443,7 @@ var TOKEN_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
|
|
|
1461
1443
|
var MAX_CONNECTION_FILE_LENGTH = 16 * 1024;
|
|
1462
1444
|
var CLAIM_RESPONSE_KEYS = ["channelId", "daemonToken"];
|
|
1463
1445
|
var SAVED_CONNECTION_KEYS = [
|
|
1464
|
-
"
|
|
1446
|
+
"defaultWorkspace",
|
|
1465
1447
|
"channelId",
|
|
1466
1448
|
"daemonToken",
|
|
1467
1449
|
"relayOrigin"
|
|
@@ -1508,7 +1490,7 @@ function readSingleOption(arguments_, option) {
|
|
|
1508
1490
|
function assertKnownArguments(arguments_) {
|
|
1509
1491
|
for (let index = 0; index < arguments_.length; index += 2) {
|
|
1510
1492
|
const option = arguments_[index];
|
|
1511
|
-
if (option !== "--url" && option !== "--code" && option !== "--
|
|
1493
|
+
if (option !== "--url" && option !== "--code" && option !== "--workspace") {
|
|
1512
1494
|
throw new PairingClientError(
|
|
1513
1495
|
"invalid_arguments",
|
|
1514
1496
|
`Unknown pairing option: ${option ?? "missing option"}`
|
|
@@ -1565,7 +1547,7 @@ function parsePairCommand(arguments_) {
|
|
|
1565
1547
|
return {
|
|
1566
1548
|
code: parsePairingCode(readSingleOption(arguments_, "--code")),
|
|
1567
1549
|
relayOrigin: parseRelayOrigin(readSingleOption(arguments_, "--url")),
|
|
1568
|
-
|
|
1550
|
+
workspace: arguments_.includes("--workspace") ? readSingleOption(arguments_, "--workspace") : loadDefaultWorkspace()
|
|
1569
1551
|
};
|
|
1570
1552
|
}
|
|
1571
1553
|
function parseChannelArgument(arguments_) {
|
|
@@ -1584,25 +1566,26 @@ function parseChannelArgument(arguments_) {
|
|
|
1584
1566
|
}
|
|
1585
1567
|
return channelId;
|
|
1586
1568
|
}
|
|
1587
|
-
async function
|
|
1588
|
-
const
|
|
1569
|
+
async function resolveDefaultWorkspace(path2) {
|
|
1570
|
+
const requestedWorkspace = resolve3(path2);
|
|
1589
1571
|
try {
|
|
1590
|
-
|
|
1591
|
-
const
|
|
1572
|
+
await mkdir2(requestedWorkspace, { recursive: true, mode: 448 });
|
|
1573
|
+
const defaultWorkspace = await realpath3(requestedWorkspace);
|
|
1574
|
+
const metadata = await stat3(defaultWorkspace);
|
|
1592
1575
|
if (!metadata.isDirectory()) {
|
|
1593
1576
|
throw new PairingClientError(
|
|
1594
1577
|
"invalid_workspace",
|
|
1595
|
-
"The
|
|
1578
|
+
"The default workspace is not a directory"
|
|
1596
1579
|
);
|
|
1597
1580
|
}
|
|
1598
|
-
return
|
|
1581
|
+
return defaultWorkspace;
|
|
1599
1582
|
} catch (error61) {
|
|
1600
1583
|
if (error61 instanceof PairingClientError) {
|
|
1601
1584
|
throw error61;
|
|
1602
1585
|
}
|
|
1603
1586
|
throw new PairingClientError(
|
|
1604
1587
|
"invalid_workspace",
|
|
1605
|
-
"The
|
|
1588
|
+
"The default workspace cannot be resolved",
|
|
1606
1589
|
{ cause: error61 }
|
|
1607
1590
|
);
|
|
1608
1591
|
}
|
|
@@ -1658,7 +1641,7 @@ function decodeClaimResponse(value) {
|
|
|
1658
1641
|
}
|
|
1659
1642
|
return { channelId, daemonToken };
|
|
1660
1643
|
}
|
|
1661
|
-
async function claimPairing(options,
|
|
1644
|
+
async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
|
|
1662
1645
|
const agents = localAgents.map((agent) => ({
|
|
1663
1646
|
id: agent.id,
|
|
1664
1647
|
label: agent.label
|
|
@@ -1676,7 +1659,7 @@ async function claimPairing(options, approvedRoot, localAgents, installableAgent
|
|
|
1676
1659
|
})),
|
|
1677
1660
|
machineName: hostname(),
|
|
1678
1661
|
pairingCode: options.code,
|
|
1679
|
-
workspaceName: basename(
|
|
1662
|
+
workspaceName: basename(defaultWorkspace) || "Local workspace"
|
|
1680
1663
|
}),
|
|
1681
1664
|
dispatcher: environmentProxyDispatcher,
|
|
1682
1665
|
headers: { "content-type": "application/json" },
|
|
@@ -1699,11 +1682,11 @@ async function claimPairing(options, approvedRoot, localAgents, installableAgent
|
|
|
1699
1682
|
}
|
|
1700
1683
|
return decodeClaimResponse(value);
|
|
1701
1684
|
}
|
|
1702
|
-
async function persistConnection(channelId, relayOrigin, daemonToken,
|
|
1703
|
-
const connectionsDirectory =
|
|
1685
|
+
async function persistConnection(channelId, relayOrigin, daemonToken, defaultWorkspace) {
|
|
1686
|
+
const connectionsDirectory = join7(readStateDirectory(), "connections");
|
|
1704
1687
|
await mkdir2(connectionsDirectory, { mode: 448, recursive: true });
|
|
1705
|
-
const connectionPath =
|
|
1706
|
-
const temporaryPath =
|
|
1688
|
+
const connectionPath = join7(connectionsDirectory, `${channelId}.json`);
|
|
1689
|
+
const temporaryPath = join7(
|
|
1707
1690
|
connectionsDirectory,
|
|
1708
1691
|
`.${channelId}.${randomUUID()}.tmp`
|
|
1709
1692
|
);
|
|
@@ -1711,7 +1694,7 @@ async function persistConnection(channelId, relayOrigin, daemonToken, approvedRo
|
|
|
1711
1694
|
temporaryPath,
|
|
1712
1695
|
`${JSON.stringify(
|
|
1713
1696
|
{
|
|
1714
|
-
|
|
1697
|
+
defaultWorkspace,
|
|
1715
1698
|
channelId,
|
|
1716
1699
|
daemonToken,
|
|
1717
1700
|
relayOrigin: relayOrigin.toString()
|
|
@@ -1732,25 +1715,25 @@ function decodeSavedConnection(value, expectedChannelId) {
|
|
|
1732
1715
|
"The saved connection is invalid"
|
|
1733
1716
|
);
|
|
1734
1717
|
}
|
|
1735
|
-
const
|
|
1718
|
+
const defaultWorkspace = value["defaultWorkspace"];
|
|
1736
1719
|
const channelId = value["channelId"];
|
|
1737
1720
|
const daemonToken = value["daemonToken"];
|
|
1738
1721
|
const relayOrigin = value["relayOrigin"];
|
|
1739
|
-
if (typeof
|
|
1722
|
+
if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN.test(channelId) || typeof daemonToken !== "string" || !TOKEN_PATTERN.test(daemonToken) || typeof relayOrigin !== "string") {
|
|
1740
1723
|
throw new PairingClientError(
|
|
1741
1724
|
"invalid_connection",
|
|
1742
1725
|
"The saved connection is invalid"
|
|
1743
1726
|
);
|
|
1744
1727
|
}
|
|
1745
1728
|
return {
|
|
1746
|
-
|
|
1729
|
+
defaultWorkspace,
|
|
1747
1730
|
channelId,
|
|
1748
1731
|
daemonToken,
|
|
1749
1732
|
relayOrigin: parseRelayOrigin(relayOrigin)
|
|
1750
1733
|
};
|
|
1751
1734
|
}
|
|
1752
1735
|
async function readSavedConnection(channelId) {
|
|
1753
|
-
const connectionPath =
|
|
1736
|
+
const connectionPath = join7(
|
|
1754
1737
|
readStateDirectory(),
|
|
1755
1738
|
"connections",
|
|
1756
1739
|
`${channelId}.json`
|
|
@@ -1781,7 +1764,9 @@ async function readSavedConnection(channelId) {
|
|
|
1781
1764
|
}
|
|
1782
1765
|
const connection = decodeSavedConnection(value, channelId);
|
|
1783
1766
|
return {
|
|
1784
|
-
|
|
1767
|
+
defaultWorkspace: await resolveDefaultWorkspace(
|
|
1768
|
+
connection.defaultWorkspace
|
|
1769
|
+
),
|
|
1785
1770
|
channelId: connection.channelId,
|
|
1786
1771
|
daemonToken: connection.daemonToken,
|
|
1787
1772
|
relayOrigin: connection.relayOrigin
|
|
@@ -1803,7 +1788,7 @@ function buildPairedDaemon(connection, connectionPath, inventory) {
|
|
|
1803
1788
|
);
|
|
1804
1789
|
relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
1805
1790
|
relayUrl.searchParams.set("token", connection.daemonToken);
|
|
1806
|
-
const auditDatabasePath =
|
|
1791
|
+
const auditDatabasePath = join7(
|
|
1807
1792
|
readStateDirectory(),
|
|
1808
1793
|
"audit",
|
|
1809
1794
|
`${connection.channelId}.sqlite`
|
|
@@ -1815,7 +1800,7 @@ function buildPairedDaemon(connection, connectionPath, inventory) {
|
|
|
1815
1800
|
).toString(),
|
|
1816
1801
|
config: createDaemonConfig(
|
|
1817
1802
|
{
|
|
1818
|
-
|
|
1803
|
+
defaultWorkspace: connection.defaultWorkspace,
|
|
1819
1804
|
auditDatabasePath,
|
|
1820
1805
|
channelId: connection.channelId,
|
|
1821
1806
|
relayUrl
|
|
@@ -1828,9 +1813,9 @@ function buildPairedDaemon(connection, connectionPath, inventory) {
|
|
|
1828
1813
|
}
|
|
1829
1814
|
async function pairLocalMachine(arguments_, signal = new AbortController().signal) {
|
|
1830
1815
|
const options = parsePairCommand(arguments_);
|
|
1831
|
-
const
|
|
1816
|
+
const defaultWorkspace = await resolveDefaultWorkspace(options.workspace);
|
|
1832
1817
|
const inventory = await discoverLocalAgentInventory({
|
|
1833
|
-
|
|
1818
|
+
defaultWorkspace,
|
|
1834
1819
|
environment: process.env,
|
|
1835
1820
|
signal
|
|
1836
1821
|
});
|
|
@@ -1838,7 +1823,7 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
|
|
|
1838
1823
|
const agents = inventory.readyAgents();
|
|
1839
1824
|
const claim2 = await claimPairing(
|
|
1840
1825
|
options,
|
|
1841
|
-
|
|
1826
|
+
defaultWorkspace,
|
|
1842
1827
|
agents,
|
|
1843
1828
|
inventory.installable,
|
|
1844
1829
|
signal
|
|
@@ -1847,11 +1832,11 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
|
|
|
1847
1832
|
claim2.channelId,
|
|
1848
1833
|
options.relayOrigin,
|
|
1849
1834
|
claim2.daemonToken,
|
|
1850
|
-
|
|
1835
|
+
defaultWorkspace
|
|
1851
1836
|
);
|
|
1852
1837
|
return buildPairedDaemon(
|
|
1853
1838
|
{
|
|
1854
|
-
|
|
1839
|
+
defaultWorkspace,
|
|
1855
1840
|
channelId: claim2.channelId,
|
|
1856
1841
|
daemonToken: claim2.daemonToken,
|
|
1857
1842
|
relayOrigin: options.relayOrigin
|
|
@@ -1862,14 +1847,14 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
|
|
|
1862
1847
|
}
|
|
1863
1848
|
async function resumeLocalMachine(arguments_, signal = new AbortController().signal) {
|
|
1864
1849
|
const channelId = parseChannelArgument(arguments_);
|
|
1865
|
-
const connectionPath =
|
|
1850
|
+
const connectionPath = join7(
|
|
1866
1851
|
readStateDirectory(),
|
|
1867
1852
|
"connections",
|
|
1868
1853
|
`${channelId}.json`
|
|
1869
1854
|
);
|
|
1870
1855
|
const connection = await readSavedConnection(channelId);
|
|
1871
1856
|
const inventory = await discoverLocalAgentInventory({
|
|
1872
|
-
|
|
1857
|
+
defaultWorkspace: connection.defaultWorkspace,
|
|
1873
1858
|
environment: process.env,
|
|
1874
1859
|
signal
|
|
1875
1860
|
});
|
|
@@ -1877,7 +1862,7 @@ async function resumeLocalMachine(arguments_, signal = new AbortController().sig
|
|
|
1877
1862
|
}
|
|
1878
1863
|
|
|
1879
1864
|
// src/run-daemon.ts
|
|
1880
|
-
import { randomUUID as
|
|
1865
|
+
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
1881
1866
|
import { basename as basename3 } from "node:path";
|
|
1882
1867
|
|
|
1883
1868
|
// ../../node_modules/.pnpm/zod@4.5.4/node_modules/zod/v4/classic/external.js
|
|
@@ -2624,10 +2609,10 @@ function mergeDefs(...defs) {
|
|
|
2624
2609
|
function cloneDef(schema) {
|
|
2625
2610
|
return mergeDefs(schema._zod.def);
|
|
2626
2611
|
}
|
|
2627
|
-
function getElementAtPath(obj,
|
|
2628
|
-
if (!
|
|
2612
|
+
function getElementAtPath(obj, path2) {
|
|
2613
|
+
if (!path2)
|
|
2629
2614
|
return obj;
|
|
2630
|
-
return
|
|
2615
|
+
return path2.reduce((acc, key) => acc?.[key], obj);
|
|
2631
2616
|
}
|
|
2632
2617
|
function promiseAllObject(promisesObj) {
|
|
2633
2618
|
const keys = Object.keys(promisesObj);
|
|
@@ -3039,11 +3024,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
3039
3024
|
}
|
|
3040
3025
|
return false;
|
|
3041
3026
|
}
|
|
3042
|
-
function prefixIssues(
|
|
3027
|
+
function prefixIssues(path2, issues) {
|
|
3043
3028
|
return issues.map((iss) => {
|
|
3044
3029
|
var _a3;
|
|
3045
3030
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
3046
|
-
iss.path.unshift(
|
|
3031
|
+
iss.path.unshift(path2);
|
|
3047
3032
|
return iss;
|
|
3048
3033
|
});
|
|
3049
3034
|
}
|
|
@@ -3476,16 +3461,16 @@ function flattenError(error61, mapper = (issue2) => issue2.message) {
|
|
|
3476
3461
|
}
|
|
3477
3462
|
function formatError(error61, mapper = (issue2) => issue2.message) {
|
|
3478
3463
|
const fieldErrors = { _errors: [] };
|
|
3479
|
-
const processError = (error62,
|
|
3464
|
+
const processError = (error62, path2 = []) => {
|
|
3480
3465
|
for (const issue2 of error62.issues) {
|
|
3481
3466
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
3482
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
3467
|
+
issue2.errors.map((issues) => processError({ issues }, [...path2, ...issue2.path]));
|
|
3483
3468
|
} else if (issue2.code === "invalid_key") {
|
|
3484
|
-
processError({ issues: issue2.issues }, [...
|
|
3469
|
+
processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
|
|
3485
3470
|
} else if (issue2.code === "invalid_element") {
|
|
3486
|
-
processError({ issues: issue2.issues }, [...
|
|
3471
|
+
processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
|
|
3487
3472
|
} else {
|
|
3488
|
-
const fullpath = [...
|
|
3473
|
+
const fullpath = [...path2, ...issue2.path];
|
|
3489
3474
|
if (fullpath.length === 0) {
|
|
3490
3475
|
fieldErrors._errors.push(mapper(issue2));
|
|
3491
3476
|
} else {
|
|
@@ -3524,17 +3509,17 @@ function formatError(error61, mapper = (issue2) => issue2.message) {
|
|
|
3524
3509
|
}
|
|
3525
3510
|
function treeifyError(error61, mapper = (issue2) => issue2.message) {
|
|
3526
3511
|
const result = { errors: [] };
|
|
3527
|
-
const processError = (error62,
|
|
3512
|
+
const processError = (error62, path2 = []) => {
|
|
3528
3513
|
var _a3;
|
|
3529
3514
|
for (const issue2 of error62.issues) {
|
|
3530
3515
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
3531
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
3516
|
+
issue2.errors.map((issues) => processError({ issues }, [...path2, ...issue2.path]));
|
|
3532
3517
|
} else if (issue2.code === "invalid_key") {
|
|
3533
|
-
processError({ issues: issue2.issues }, [...
|
|
3518
|
+
processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
|
|
3534
3519
|
} else if (issue2.code === "invalid_element") {
|
|
3535
|
-
processError({ issues: issue2.issues }, [...
|
|
3520
|
+
processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
|
|
3536
3521
|
} else {
|
|
3537
|
-
const fullpath = [...
|
|
3522
|
+
const fullpath = [...path2, ...issue2.path];
|
|
3538
3523
|
if (fullpath.length === 0) {
|
|
3539
3524
|
result.errors.push(mapper(issue2));
|
|
3540
3525
|
continue;
|
|
@@ -3573,8 +3558,8 @@ function treeifyError(error61, mapper = (issue2) => issue2.message) {
|
|
|
3573
3558
|
}
|
|
3574
3559
|
function toDotPath(_path) {
|
|
3575
3560
|
const segs = [];
|
|
3576
|
-
const
|
|
3577
|
-
for (const seg of
|
|
3561
|
+
const path2 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
3562
|
+
for (const seg of path2) {
|
|
3578
3563
|
if (typeof seg === "number")
|
|
3579
3564
|
segs.push(`[${seg}]`);
|
|
3580
3565
|
else if (typeof seg === "symbol")
|
|
@@ -20084,13 +20069,13 @@ function resolveRef(ref, ctx) {
|
|
|
20084
20069
|
if (!ref.startsWith("#")) {
|
|
20085
20070
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
20086
20071
|
}
|
|
20087
|
-
const
|
|
20088
|
-
if (
|
|
20072
|
+
const path2 = ref.slice(1).split("/").filter(Boolean);
|
|
20073
|
+
if (path2.length === 0) {
|
|
20089
20074
|
return ctx.rootSchema;
|
|
20090
20075
|
}
|
|
20091
20076
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
20092
|
-
if (
|
|
20093
|
-
const key =
|
|
20077
|
+
if (path2[0] === defsKey) {
|
|
20078
|
+
const key = path2[1] === void 0 ? void 0 : decodeJSONPointerSegment(path2[1]);
|
|
20094
20079
|
if (!key || !ctx.defs[key]) {
|
|
20095
20080
|
throw new Error(`Reference not found: ${ref}`);
|
|
20096
20081
|
}
|
|
@@ -20746,6 +20731,56 @@ function date4(params) {
|
|
|
20746
20731
|
return _coercedDate(ZodDate, params);
|
|
20747
20732
|
}
|
|
20748
20733
|
|
|
20734
|
+
// ../protocol/src/prompt-usage.ts
|
|
20735
|
+
var TOKEN_COUNT = external_exports.number().int().nonnegative();
|
|
20736
|
+
var promptUsageSchema = external_exports.object({
|
|
20737
|
+
cachedReadTokens: TOKEN_COUNT.nullish(),
|
|
20738
|
+
cachedWriteTokens: TOKEN_COUNT.nullish(),
|
|
20739
|
+
inputTokens: TOKEN_COUNT,
|
|
20740
|
+
outputTokens: TOKEN_COUNT,
|
|
20741
|
+
thoughtTokens: TOKEN_COUNT.nullish(),
|
|
20742
|
+
totalTokens: TOKEN_COUNT
|
|
20743
|
+
}).readonly();
|
|
20744
|
+
var quotaTokenCountSchema = external_exports.object({
|
|
20745
|
+
cachedInputTokens: TOKEN_COUNT,
|
|
20746
|
+
cachedWriteTokens: TOKEN_COUNT.optional(),
|
|
20747
|
+
inputTokens: TOKEN_COUNT,
|
|
20748
|
+
outputTokens: TOKEN_COUNT,
|
|
20749
|
+
reasoningOutputTokens: TOKEN_COUNT,
|
|
20750
|
+
totalTokens: TOKEN_COUNT
|
|
20751
|
+
}).readonly();
|
|
20752
|
+
var promptMetadataSchema = external_exports.object({
|
|
20753
|
+
quota: external_exports.object({
|
|
20754
|
+
model_usage: external_exports.array(
|
|
20755
|
+
external_exports.object({
|
|
20756
|
+
model: external_exports.string().min(1).max(255),
|
|
20757
|
+
token_count: quotaTokenCountSchema
|
|
20758
|
+
}).readonly()
|
|
20759
|
+
).max(100).readonly(),
|
|
20760
|
+
token_count: quotaTokenCountSchema.nullable()
|
|
20761
|
+
}).readonly().optional()
|
|
20762
|
+
}).readonly();
|
|
20763
|
+
var agentPromptResponseSchema = external_exports.object({
|
|
20764
|
+
_meta: promptMetadataSchema.nullish(),
|
|
20765
|
+
stopReason: external_exports.enum([
|
|
20766
|
+
"end_turn",
|
|
20767
|
+
"max_tokens",
|
|
20768
|
+
"max_turn_requests",
|
|
20769
|
+
"refusal",
|
|
20770
|
+
"cancelled"
|
|
20771
|
+
]),
|
|
20772
|
+
usage: promptUsageSchema.nullish()
|
|
20773
|
+
}).readonly();
|
|
20774
|
+
function decodeAgentPromptResponse(value) {
|
|
20775
|
+
const result = agentPromptResponseSchema.safeParse(value);
|
|
20776
|
+
if (!result.success) {
|
|
20777
|
+
throw new ProtocolMessageError("Invalid agent prompt response", {
|
|
20778
|
+
cause: result.error
|
|
20779
|
+
});
|
|
20780
|
+
}
|
|
20781
|
+
return result.data;
|
|
20782
|
+
}
|
|
20783
|
+
|
|
20749
20784
|
// ../protocol/src/version.ts
|
|
20750
20785
|
var MOBIUS_PROTOCOL_VERSION = 1;
|
|
20751
20786
|
|
|
@@ -20812,7 +20847,8 @@ var sessionCapabilitiesSchema = external_exports.strictObject({
|
|
|
20812
20847
|
imagePrompt: external_exports.boolean(),
|
|
20813
20848
|
listSessions: external_exports.boolean(),
|
|
20814
20849
|
loadSession: external_exports.boolean(),
|
|
20815
|
-
resumeSession: external_exports.boolean()
|
|
20850
|
+
resumeSession: external_exports.boolean(),
|
|
20851
|
+
unstableForkSession: external_exports.boolean().default(false)
|
|
20816
20852
|
}).readonly();
|
|
20817
20853
|
var sessionCommandSchema = external_exports.strictObject({
|
|
20818
20854
|
description: SHORT_TEXT,
|
|
@@ -20953,7 +20989,7 @@ var sessionConfigUpdatedEventSchema = external_exports.strictObject({
|
|
|
20953
20989
|
requestId: IDENTIFIER,
|
|
20954
20990
|
sessionId: IDENTIFIER
|
|
20955
20991
|
}).readonly();
|
|
20956
|
-
var
|
|
20992
|
+
var sessionContextUsageUpdatedEventSchema = external_exports.strictObject({
|
|
20957
20993
|
costAmount: external_exports.number().finite().nonnegative(),
|
|
20958
20994
|
costCurrency: external_exports.string().max(16),
|
|
20959
20995
|
hasCost: external_exports.boolean(),
|
|
@@ -20961,8 +20997,22 @@ var sessionUsageUpdatedEventSchema = external_exports.strictObject({
|
|
|
20961
20997
|
protocolVersion: PROTOCOL_VERSION2,
|
|
20962
20998
|
sessionId: IDENTIFIER,
|
|
20963
20999
|
size: external_exports.number().int().nonnegative(),
|
|
21000
|
+
source: external_exports.literal("context").default("context"),
|
|
20964
21001
|
used: external_exports.number().int().nonnegative()
|
|
20965
21002
|
}).readonly();
|
|
21003
|
+
var sessionPromptUsageUpdatedEventSchema = external_exports.strictObject({
|
|
21004
|
+
_meta: promptMetadataSchema.nullable(),
|
|
21005
|
+
commandId: IDENTIFIER,
|
|
21006
|
+
kind: external_exports.literal(SESSION_USAGE_UPDATED_KIND),
|
|
21007
|
+
protocolVersion: PROTOCOL_VERSION2,
|
|
21008
|
+
sessionId: IDENTIFIER,
|
|
21009
|
+
source: external_exports.literal("prompt"),
|
|
21010
|
+
usage: promptUsageSchema.nullable()
|
|
21011
|
+
}).refine((event) => event.usage !== null || event._meta?.quota !== void 0).readonly();
|
|
21012
|
+
var sessionUsageUpdatedEventSchema = external_exports.union([
|
|
21013
|
+
sessionContextUsageUpdatedEventSchema,
|
|
21014
|
+
sessionPromptUsageUpdatedEventSchema
|
|
21015
|
+
]);
|
|
20966
21016
|
var sessionCommandsUpdatedEventSchema = external_exports.strictObject({
|
|
20967
21017
|
commands: external_exports.array(sessionCommandSchema).max(500).readonly(),
|
|
20968
21018
|
kind: external_exports.literal(SESSION_COMMANDS_UPDATED_KIND),
|
|
@@ -20973,7 +21023,7 @@ var sessionInfoUpdatedEventSchema = external_exports.strictObject({
|
|
|
20973
21023
|
kind: external_exports.literal(SESSION_INFO_UPDATED_KIND),
|
|
20974
21024
|
protocolVersion: PROTOCOL_VERSION2,
|
|
20975
21025
|
sessionId: IDENTIFIER,
|
|
20976
|
-
title: external_exports.string().max(500),
|
|
21026
|
+
title: external_exports.string().max(500).nullable(),
|
|
20977
21027
|
updatedAt: external_exports.string().max(128)
|
|
20978
21028
|
}).readonly();
|
|
20979
21029
|
var sessionPermissionRequestedEventSchema = external_exports.strictObject({
|
|
@@ -21550,6 +21600,160 @@ function encodeSessionFailedEvent(message) {
|
|
|
21550
21600
|
return JSON.stringify(decodeSessionFailedEvent(JSON.stringify(message)));
|
|
21551
21601
|
}
|
|
21552
21602
|
|
|
21603
|
+
// ../protocol/src/session-history.ts
|
|
21604
|
+
var SESSION_HISTORY_CHARACTER_LIMIT = 256e3;
|
|
21605
|
+
var SESSION_HISTORY_MESSAGE_LIMIT = 1e3;
|
|
21606
|
+
var SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT = 10;
|
|
21607
|
+
var SESSION_HISTORY_IMAGE_CHARACTER_LIMIT = 4e6;
|
|
21608
|
+
var historyImage = external_exports.strictObject({
|
|
21609
|
+
data: external_exports.string().min(4).max(SESSION_HISTORY_IMAGE_CHARACTER_LIMIT).refine(
|
|
21610
|
+
(data) => data.length % 4 === 0 && /^[A-Za-z0-9+/]*={0,2}$/.test(data)
|
|
21611
|
+
),
|
|
21612
|
+
mimeType: external_exports.enum(["image/png", "image/jpeg", "image/gif", "image/webp"]),
|
|
21613
|
+
name: external_exports.string().min(1).max(500)
|
|
21614
|
+
}).readonly();
|
|
21615
|
+
function parseNativeHistoryText(text) {
|
|
21616
|
+
const images = [];
|
|
21617
|
+
let imageCharacters = 0;
|
|
21618
|
+
const plainText = text.replace(
|
|
21619
|
+
/\[@image\]\(([^)\r\n]*)(?:\)|$)/g,
|
|
21620
|
+
(_marker, uri) => {
|
|
21621
|
+
const header = /^data:(image\/[a-z+]+);base64,/.exec(uri);
|
|
21622
|
+
if (header === null) return "[Image unavailable]";
|
|
21623
|
+
const parsed = historyImage.safeParse({
|
|
21624
|
+
data: uri.slice(header[0].length),
|
|
21625
|
+
mimeType: header[1],
|
|
21626
|
+
name: `Image ${(images.length + 1).toString()}`
|
|
21627
|
+
});
|
|
21628
|
+
if (!parsed.success || images.length >= 8 || imageCharacters + parsed.data.data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT)
|
|
21629
|
+
return "[Image unavailable]";
|
|
21630
|
+
images.push(parsed.data);
|
|
21631
|
+
imageCharacters += parsed.data.data.length;
|
|
21632
|
+
return "";
|
|
21633
|
+
}
|
|
21634
|
+
);
|
|
21635
|
+
return { text: plainText, images };
|
|
21636
|
+
}
|
|
21637
|
+
var historyMessage = external_exports.strictObject({
|
|
21638
|
+
role: external_exports.enum(["user", "assistant"]),
|
|
21639
|
+
text: external_exports.string().max(SESSION_HISTORY_CHARACTER_LIMIT),
|
|
21640
|
+
images: external_exports.array(historyImage).max(8).readonly().optional()
|
|
21641
|
+
}).readonly();
|
|
21642
|
+
var sessionHistorySchema = external_exports.discriminatedUnion("status", [
|
|
21643
|
+
external_exports.strictObject({
|
|
21644
|
+
status: external_exports.literal("available"),
|
|
21645
|
+
messages: external_exports.array(historyMessage).max(SESSION_HISTORY_MESSAGE_LIMIT).readonly(),
|
|
21646
|
+
truncated: external_exports.boolean(),
|
|
21647
|
+
coveredCommandIds: external_exports.array(external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/)).max(1e4).readonly()
|
|
21648
|
+
}).readonly(),
|
|
21649
|
+
external_exports.strictObject({ status: external_exports.literal("unavailable") }).readonly()
|
|
21650
|
+
]).refine(
|
|
21651
|
+
(history) => history.status === "unavailable" || history.messages.reduce(
|
|
21652
|
+
(total, message) => total + message.text.length,
|
|
21653
|
+
0
|
|
21654
|
+
) <= SESSION_HISTORY_CHARACTER_LIMIT && history.messages.reduce(
|
|
21655
|
+
(total, message) => total + (message.images ?? []).reduce(
|
|
21656
|
+
(size, image) => size + image.data.length,
|
|
21657
|
+
0
|
|
21658
|
+
),
|
|
21659
|
+
0
|
|
21660
|
+
) <= SESSION_HISTORY_IMAGE_CHARACTER_LIMIT
|
|
21661
|
+
);
|
|
21662
|
+
|
|
21663
|
+
// ../protocol/src/native-sessions.ts
|
|
21664
|
+
var NATIVE_SESSION_REQUEST_KIND = "native.session.request";
|
|
21665
|
+
var NATIVE_SESSION_RESULT_KIND = "native.session.result";
|
|
21666
|
+
var NATIVE_SESSION_CANCEL_KIND = "native.session.cancel";
|
|
21667
|
+
var identifier = external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/);
|
|
21668
|
+
var directoryId = external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,2047}$/);
|
|
21669
|
+
var envelope = {
|
|
21670
|
+
protocolVersion: external_exports.literal(MOBIUS_PROTOCOL_VERSION),
|
|
21671
|
+
requestId: identifier,
|
|
21672
|
+
sessionId: identifier
|
|
21673
|
+
};
|
|
21674
|
+
var identity = {
|
|
21675
|
+
...envelope,
|
|
21676
|
+
kind: external_exports.literal(NATIVE_SESSION_REQUEST_KIND),
|
|
21677
|
+
additionalDirectoryIds: external_exports.array(directoryId).max(16).readonly(),
|
|
21678
|
+
agentId: identifier,
|
|
21679
|
+
bindingId: identifier,
|
|
21680
|
+
directoryId
|
|
21681
|
+
};
|
|
21682
|
+
var nativeSessionCommandSchema = external_exports.discriminatedUnion("action", [
|
|
21683
|
+
external_exports.strictObject({
|
|
21684
|
+
...identity,
|
|
21685
|
+
action: external_exports.literal("list"),
|
|
21686
|
+
cursor: identifier.nullable()
|
|
21687
|
+
}).readonly(),
|
|
21688
|
+
external_exports.strictObject({
|
|
21689
|
+
...identity,
|
|
21690
|
+
action: external_exports.enum(["import", "fork"]),
|
|
21691
|
+
entryId: identifier,
|
|
21692
|
+
targetSessionId: identifier
|
|
21693
|
+
}).readonly(),
|
|
21694
|
+
external_exports.strictObject({
|
|
21695
|
+
...identity,
|
|
21696
|
+
action: external_exports.literal("delete"),
|
|
21697
|
+
entryId: identifier
|
|
21698
|
+
}).readonly()
|
|
21699
|
+
]);
|
|
21700
|
+
var nativeSessionEntrySchema = external_exports.strictObject({
|
|
21701
|
+
entryId: identifier,
|
|
21702
|
+
title: external_exports.string().max(500),
|
|
21703
|
+
directoryId,
|
|
21704
|
+
directoryLabel: external_exports.string().min(1).max(2048),
|
|
21705
|
+
updatedAt: external_exports.iso.datetime({ offset: true }).nullable(),
|
|
21706
|
+
additionalDirectories: external_exports.array(
|
|
21707
|
+
external_exports.strictObject({ directoryId, name: external_exports.string().min(1).max(255) }).readonly()
|
|
21708
|
+
).max(16).readonly()
|
|
21709
|
+
}).readonly();
|
|
21710
|
+
var resultEnvelope = {
|
|
21711
|
+
...envelope,
|
|
21712
|
+
kind: external_exports.literal(NATIVE_SESSION_RESULT_KIND)
|
|
21713
|
+
};
|
|
21714
|
+
var nativeSessionResultSchema = external_exports.discriminatedUnion("action", [
|
|
21715
|
+
external_exports.strictObject({
|
|
21716
|
+
...resultEnvelope,
|
|
21717
|
+
action: external_exports.literal("list"),
|
|
21718
|
+
capabilities: sessionCapabilitiesSchema,
|
|
21719
|
+
entries: external_exports.array(nativeSessionEntrySchema).max(500).readonly(),
|
|
21720
|
+
nextCursor: identifier.nullable()
|
|
21721
|
+
}).readonly(),
|
|
21722
|
+
external_exports.strictObject({
|
|
21723
|
+
...resultEnvelope,
|
|
21724
|
+
action: external_exports.enum(["import", "fork"]),
|
|
21725
|
+
ready: sessionReadyEventSchema,
|
|
21726
|
+
history: sessionHistorySchema,
|
|
21727
|
+
title: external_exports.string().max(500)
|
|
21728
|
+
}).readonly(),
|
|
21729
|
+
external_exports.strictObject({
|
|
21730
|
+
...resultEnvelope,
|
|
21731
|
+
action: external_exports.literal("preview"),
|
|
21732
|
+
entryId: identifier,
|
|
21733
|
+
reason: external_exports.literal("continuation_unavailable"),
|
|
21734
|
+
history: sessionHistorySchema,
|
|
21735
|
+
title: external_exports.string().max(500)
|
|
21736
|
+
}).readonly(),
|
|
21737
|
+
external_exports.strictObject({
|
|
21738
|
+
...resultEnvelope,
|
|
21739
|
+
action: external_exports.literal("delete"),
|
|
21740
|
+
entryId: identifier,
|
|
21741
|
+
deletedSessionIds: external_exports.array(identifier).max(500).readonly()
|
|
21742
|
+
}).readonly()
|
|
21743
|
+
]);
|
|
21744
|
+
var nativeSessionCancelSchema = external_exports.strictObject({ ...envelope, kind: external_exports.literal(NATIVE_SESSION_CANCEL_KIND) }).readonly();
|
|
21745
|
+
function decode4(schema, encoded) {
|
|
21746
|
+
try {
|
|
21747
|
+
const value = JSON.parse(encoded);
|
|
21748
|
+
return schema.parse(value);
|
|
21749
|
+
} catch (cause) {
|
|
21750
|
+
throw new ProtocolMessageError("Invalid native session message", { cause });
|
|
21751
|
+
}
|
|
21752
|
+
}
|
|
21753
|
+
var decodeNativeSessionCommand = (encoded) => decode4(nativeSessionCommandSchema, encoded);
|
|
21754
|
+
var encodeNativeSessionResult = (value) => JSON.stringify(nativeSessionResultSchema.parse(value));
|
|
21755
|
+
var decodeNativeSessionCancel = (encoded) => decode4(nativeSessionCancelSchema, encoded);
|
|
21756
|
+
|
|
21553
21757
|
// src/run-daemon.ts
|
|
21554
21758
|
import { WebSocket as WebSocket2 } from "undici";
|
|
21555
21759
|
|
|
@@ -21799,15 +22003,15 @@ var AcpActivityTracker = class {
|
|
|
21799
22003
|
await this.finishNarrative();
|
|
21800
22004
|
}
|
|
21801
22005
|
const previous = this.#activities.get(key);
|
|
21802
|
-
const
|
|
22006
|
+
const identity2 = this.#identity(key);
|
|
21803
22007
|
const activity = new AcpActivity(
|
|
21804
|
-
|
|
22008
|
+
identity2.id,
|
|
21805
22009
|
activityType,
|
|
21806
22010
|
"",
|
|
21807
22011
|
[],
|
|
21808
22012
|
"",
|
|
21809
22013
|
truncate(`${previous?.output ?? ""}${text}`, AGENT_ACTIVITY_DETAIL_LIMIT),
|
|
21810
|
-
|
|
22014
|
+
identity2.sequence,
|
|
21811
22015
|
"running",
|
|
21812
22016
|
activityType === "reasoning" ? "Reasoning" : "Progress update",
|
|
21813
22017
|
activityType === "reasoning" ? "think" : ""
|
|
@@ -21827,18 +22031,18 @@ var AcpActivityTracker = class {
|
|
|
21827
22031
|
await this.#recordPlanEntries(key, plan.entries);
|
|
21828
22032
|
return;
|
|
21829
22033
|
}
|
|
21830
|
-
const
|
|
22034
|
+
const identity2 = this.#identity(key);
|
|
21831
22035
|
const output2 = plan.type === "markdown" ? plan.content : `Plan file: ${plan.uri}`;
|
|
21832
22036
|
await this.#record(
|
|
21833
22037
|
key,
|
|
21834
22038
|
new AcpActivity(
|
|
21835
|
-
|
|
22039
|
+
identity2.id,
|
|
21836
22040
|
"plan",
|
|
21837
22041
|
"",
|
|
21838
22042
|
[],
|
|
21839
22043
|
"",
|
|
21840
22044
|
truncate(output2, AGENT_ACTIVITY_DETAIL_LIMIT),
|
|
21841
|
-
|
|
22045
|
+
identity2.sequence,
|
|
21842
22046
|
"running",
|
|
21843
22047
|
"Plan",
|
|
21844
22048
|
""
|
|
@@ -21871,18 +22075,18 @@ var AcpActivityTracker = class {
|
|
|
21871
22075
|
recordToolCall = async (update) => {
|
|
21872
22076
|
await this.finishNarrative();
|
|
21873
22077
|
const key = `tool:${update.toolCallId}`;
|
|
21874
|
-
const
|
|
22078
|
+
const identity2 = this.#identity(key);
|
|
21875
22079
|
const output2 = update.rawOutput === void 0 ? readContentOutput(update.content) : formatUnknown(update.rawOutput);
|
|
21876
22080
|
await this.#record(
|
|
21877
22081
|
key,
|
|
21878
22082
|
new AcpActivity(
|
|
21879
|
-
|
|
22083
|
+
identity2.id,
|
|
21880
22084
|
"tool",
|
|
21881
22085
|
update.rawInput === void 0 ? "" : formatUnknown(update.rawInput),
|
|
21882
22086
|
normalizeLocations(update.locations ?? []),
|
|
21883
22087
|
truncate(update.name ?? "", 128),
|
|
21884
22088
|
output2,
|
|
21885
|
-
|
|
22089
|
+
identity2.sequence,
|
|
21886
22090
|
normalizeToolStatus(update.status ?? "pending", "pending"),
|
|
21887
22091
|
normalizeTitle(update.title, "Tool call"),
|
|
21888
22092
|
update.kind ?? "other",
|
|
@@ -21894,19 +22098,19 @@ var AcpActivityTracker = class {
|
|
|
21894
22098
|
await this.finishNarrative();
|
|
21895
22099
|
const key = `tool:${update.toolCallId}`;
|
|
21896
22100
|
const previous = this.#activities.get(key);
|
|
21897
|
-
const
|
|
22101
|
+
const identity2 = this.#identity(key);
|
|
21898
22102
|
const output2 = update.rawOutput !== void 0 ? formatUnknown(update.rawOutput) : update.content !== void 0 && update.content !== null ? readContentOutput(update.content) : previous?.output ?? "";
|
|
21899
22103
|
const content = update.content === void 0 || update.content === null ? previous?.content ?? [] : normalizeToolContent(update.content);
|
|
21900
22104
|
await this.#record(
|
|
21901
22105
|
key,
|
|
21902
22106
|
new AcpActivity(
|
|
21903
|
-
|
|
22107
|
+
identity2.id,
|
|
21904
22108
|
"tool",
|
|
21905
22109
|
update.rawInput === void 0 ? previous?.input ?? "" : formatUnknown(update.rawInput),
|
|
21906
22110
|
update.locations === void 0 || update.locations === null ? previous?.locations ?? [] : normalizeLocations(update.locations),
|
|
21907
22111
|
update.name === void 0 || update.name === null ? previous?.name ?? "" : truncate(update.name, 128),
|
|
21908
22112
|
output2,
|
|
21909
|
-
|
|
22113
|
+
identity2.sequence,
|
|
21910
22114
|
update.status === void 0 || update.status === null ? previous?.status ?? "pending" : normalizeToolStatus(update.status, previous?.status ?? "pending"),
|
|
21911
22115
|
update.title === void 0 || update.title === null ? previous?.title ?? "Tool call" : normalizeTitle(update.title, "Tool call"),
|
|
21912
22116
|
update.kind === void 0 || update.kind === null ? previous?.toolKind ?? "other" : update.kind,
|
|
@@ -21946,30 +22150,30 @@ var AcpActivityTracker = class {
|
|
|
21946
22150
|
if (existing !== void 0) {
|
|
21947
22151
|
return existing;
|
|
21948
22152
|
}
|
|
21949
|
-
const
|
|
22153
|
+
const identity2 = new ActivityIdentity(
|
|
21950
22154
|
`activity-${crypto.randomUUID()}`,
|
|
21951
22155
|
this.#nextSequence
|
|
21952
22156
|
);
|
|
21953
22157
|
this.#nextSequence += 1;
|
|
21954
|
-
this.#identities.set(key,
|
|
21955
|
-
return
|
|
22158
|
+
this.#identities.set(key, identity2);
|
|
22159
|
+
return identity2;
|
|
21956
22160
|
};
|
|
21957
22161
|
#record = async (key, activity) => {
|
|
21958
22162
|
this.#activities.set(key, activity);
|
|
21959
22163
|
await this.#onActivity(activity);
|
|
21960
22164
|
};
|
|
21961
22165
|
#recordPlanEntries = async (key, entries) => {
|
|
21962
|
-
const
|
|
22166
|
+
const identity2 = this.#identity(key);
|
|
21963
22167
|
await this.#record(
|
|
21964
22168
|
key,
|
|
21965
22169
|
new AcpActivity(
|
|
21966
|
-
|
|
22170
|
+
identity2.id,
|
|
21967
22171
|
"plan",
|
|
21968
22172
|
"",
|
|
21969
22173
|
[],
|
|
21970
22174
|
"",
|
|
21971
22175
|
formatPlanEntries(entries),
|
|
21972
|
-
|
|
22176
|
+
identity2.sequence,
|
|
21973
22177
|
planStatus(entries),
|
|
21974
22178
|
"Plan",
|
|
21975
22179
|
""
|
|
@@ -21978,6 +22182,88 @@ var AcpActivityTracker = class {
|
|
|
21978
22182
|
};
|
|
21979
22183
|
};
|
|
21980
22184
|
|
|
22185
|
+
// src/acp/native-session.ts
|
|
22186
|
+
var path = external_exports.string().min(1).max(2048).refine((value) => !value.includes("\0"));
|
|
22187
|
+
var nativeSessionIdSchema = external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,255}$/);
|
|
22188
|
+
var nativeSessionInfoSchema = external_exports.object({
|
|
22189
|
+
sessionId: nativeSessionIdSchema,
|
|
22190
|
+
cwd: path,
|
|
22191
|
+
additionalDirectories: external_exports.array(path).max(16).default([]).readonly(),
|
|
22192
|
+
title: external_exports.string().max(500).nullish(),
|
|
22193
|
+
updatedAt: external_exports.iso.datetime({ offset: true }).nullish()
|
|
22194
|
+
}).readonly();
|
|
22195
|
+
var nativeSessionPageSchema = external_exports.object({
|
|
22196
|
+
sessions: external_exports.array(nativeSessionInfoSchema).max(500).readonly(),
|
|
22197
|
+
nextCursor: external_exports.string().min(1).max(4096).nullish()
|
|
22198
|
+
}).readonly();
|
|
22199
|
+
|
|
22200
|
+
// src/acp/session-history.ts
|
|
22201
|
+
var AcpHistoryReplay = class {
|
|
22202
|
+
#messages = [];
|
|
22203
|
+
#lastMessageId = null;
|
|
22204
|
+
#characters = 0;
|
|
22205
|
+
#imageCharacters = 0;
|
|
22206
|
+
#truncated = false;
|
|
22207
|
+
record = (update) => {
|
|
22208
|
+
if (update.sessionUpdate !== "user_message_chunk" && update.sessionUpdate !== "agent_message_chunk")
|
|
22209
|
+
return;
|
|
22210
|
+
if (update.sessionUpdate === "agent_message_chunk" && isProgressMessage(update))
|
|
22211
|
+
return;
|
|
22212
|
+
const role = update.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
|
|
22213
|
+
const content = update.content;
|
|
22214
|
+
const parsed = parseNativeHistoryText(
|
|
22215
|
+
content.type === "text" ? content.text : content.type === "image" ? `[@image](data:${content.mimeType};base64,${content.data})` : `[${content.type} attachment]`
|
|
22216
|
+
);
|
|
22217
|
+
const text = parsed.text;
|
|
22218
|
+
if (text.length === 0 && parsed.images.length === 0) return;
|
|
22219
|
+
const previous = this.#messages.at(-1);
|
|
22220
|
+
const id = update.messageId ?? null;
|
|
22221
|
+
const continuation = previous?.role === role && id === this.#lastMessageId;
|
|
22222
|
+
const combined = continuation ? `${previous.text}${text}` : text;
|
|
22223
|
+
const allImages = continuation ? [...previous.images ?? [], ...parsed.images] : parsed.images;
|
|
22224
|
+
const images = allImages.slice(0, 8);
|
|
22225
|
+
this.#truncated ||= images.length < allImages.length;
|
|
22226
|
+
if (continuation) {
|
|
22227
|
+
this.#messages.pop();
|
|
22228
|
+
this.#characters -= previous.text.length;
|
|
22229
|
+
this.#imageCharacters -= (previous.images ?? []).reduce(
|
|
22230
|
+
(size, image) => size + image.data.length,
|
|
22231
|
+
0
|
|
22232
|
+
);
|
|
22233
|
+
}
|
|
22234
|
+
const bounded = combined.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
|
|
22235
|
+
this.#truncated ||= bounded.length < combined.length;
|
|
22236
|
+
this.#messages.push({
|
|
22237
|
+
role,
|
|
22238
|
+
text: bounded,
|
|
22239
|
+
...images.length > 0 ? { images } : {}
|
|
22240
|
+
});
|
|
22241
|
+
this.#characters += bounded.length;
|
|
22242
|
+
this.#imageCharacters += images.reduce(
|
|
22243
|
+
(size, image) => size + image.data.length,
|
|
22244
|
+
0
|
|
22245
|
+
);
|
|
22246
|
+
this.#lastMessageId = id;
|
|
22247
|
+
while (this.#messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || this.#characters > SESSION_HISTORY_CHARACTER_LIMIT || this.#imageCharacters > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
|
|
22248
|
+
const removed = this.#messages.shift();
|
|
22249
|
+
if (removed !== void 0) {
|
|
22250
|
+
this.#characters -= removed.text.length;
|
|
22251
|
+
this.#imageCharacters -= (removed.images ?? []).reduce(
|
|
22252
|
+
(size, image) => size + image.data.length,
|
|
22253
|
+
0
|
|
22254
|
+
);
|
|
22255
|
+
}
|
|
22256
|
+
this.#truncated = true;
|
|
22257
|
+
}
|
|
22258
|
+
};
|
|
22259
|
+
snapshot = () => ({
|
|
22260
|
+
status: "available",
|
|
22261
|
+
messages: [...this.#messages],
|
|
22262
|
+
truncated: this.#truncated,
|
|
22263
|
+
coveredCommandIds: []
|
|
22264
|
+
});
|
|
22265
|
+
};
|
|
22266
|
+
|
|
21981
22267
|
// src/acp/session-store.ts
|
|
21982
22268
|
import { mkdirSync as mkdirSync2 } from "node:fs";
|
|
21983
22269
|
import { dirname as dirname3 } from "node:path";
|
|
@@ -22011,6 +22297,9 @@ var FoundAcpStoredSession = class extends AcpStoredSessionLookup {
|
|
|
22011
22297
|
this.session = session;
|
|
22012
22298
|
}
|
|
22013
22299
|
};
|
|
22300
|
+
var DeletedAcpStoredSession = class extends AcpStoredSessionLookup {
|
|
22301
|
+
found = false;
|
|
22302
|
+
};
|
|
22014
22303
|
function readString2(value, field) {
|
|
22015
22304
|
if (typeof value !== "string" || value.length === 0) {
|
|
22016
22305
|
throw new Error(`Stored ACP session has an invalid ${field}`);
|
|
@@ -22051,7 +22340,22 @@ function decodeSessionRow(row) {
|
|
|
22051
22340
|
}
|
|
22052
22341
|
var MemoryAcpSessionStore = class {
|
|
22053
22342
|
#sessions = /* @__PURE__ */ new Map();
|
|
22343
|
+
#deleted = /* @__PURE__ */ new Set();
|
|
22344
|
+
findNative = (agentId, nativeSessionId) => [...this.#sessions.values()].filter(
|
|
22345
|
+
(session) => session.agentId === agentId && session.nativeSessionId === nativeSessionId
|
|
22346
|
+
);
|
|
22347
|
+
markDeleted = (agentId, nativeSessionId) => {
|
|
22348
|
+
const ids = this.findNative(agentId, nativeSessionId).map(
|
|
22349
|
+
(session) => session.sessionId
|
|
22350
|
+
);
|
|
22351
|
+
for (const id of ids) {
|
|
22352
|
+
this.#sessions.delete(id);
|
|
22353
|
+
this.#deleted.add(id);
|
|
22354
|
+
}
|
|
22355
|
+
return ids;
|
|
22356
|
+
};
|
|
22054
22357
|
read = (sessionId) => {
|
|
22358
|
+
if (this.#deleted.has(sessionId)) return new DeletedAcpStoredSession();
|
|
22055
22359
|
const session = this.#sessions.get(sessionId);
|
|
22056
22360
|
return session === void 0 ? new MissingAcpStoredSession() : new FoundAcpStoredSession(session);
|
|
22057
22361
|
};
|
|
@@ -22064,10 +22368,11 @@ var MemoryAcpSessionStore = class {
|
|
|
22064
22368
|
};
|
|
22065
22369
|
var SqliteAcpSessionStore = class {
|
|
22066
22370
|
#database;
|
|
22067
|
-
constructor(
|
|
22068
|
-
mkdirSync2(dirname3(
|
|
22069
|
-
this.#database = new DatabaseSync2(
|
|
22371
|
+
constructor(path2) {
|
|
22372
|
+
mkdirSync2(dirname3(path2), { recursive: true });
|
|
22373
|
+
this.#database = new DatabaseSync2(path2);
|
|
22070
22374
|
this.#database.exec(`
|
|
22375
|
+
CREATE TABLE IF NOT EXISTS acp_deleted_sessions (session_id TEXT PRIMARY KEY) STRICT;
|
|
22071
22376
|
CREATE TABLE IF NOT EXISTS acp_sessions (
|
|
22072
22377
|
session_id TEXT PRIMARY KEY,
|
|
22073
22378
|
agent_id TEXT NOT NULL,
|
|
@@ -22090,6 +22395,10 @@ var SqliteAcpSessionStore = class {
|
|
|
22090
22395
|
}
|
|
22091
22396
|
}
|
|
22092
22397
|
read = (sessionId) => {
|
|
22398
|
+
if (this.#database.prepare(
|
|
22399
|
+
"SELECT session_id FROM acp_deleted_sessions WHERE session_id = ?"
|
|
22400
|
+
).get(sessionId) !== void 0)
|
|
22401
|
+
return new DeletedAcpStoredSession();
|
|
22093
22402
|
const row = this.#database.prepare(
|
|
22094
22403
|
`
|
|
22095
22404
|
SELECT
|
|
@@ -22108,6 +22417,28 @@ var SqliteAcpSessionStore = class {
|
|
|
22108
22417
|
remove = (sessionId) => {
|
|
22109
22418
|
this.#database.prepare("DELETE FROM acp_sessions WHERE session_id = ?").run(sessionId);
|
|
22110
22419
|
};
|
|
22420
|
+
findNative = (agentId, nativeSessionId) => this.#database.prepare(
|
|
22421
|
+
"SELECT * FROM acp_sessions WHERE agent_id = ? AND native_session_id = ?"
|
|
22422
|
+
).all(agentId, nativeSessionId).map(decodeSessionRow);
|
|
22423
|
+
markDeleted = (agentId, nativeSessionId) => {
|
|
22424
|
+
const ids = this.findNative(agentId, nativeSessionId).map(
|
|
22425
|
+
(session) => session.sessionId
|
|
22426
|
+
);
|
|
22427
|
+
this.#database.exec("BEGIN");
|
|
22428
|
+
try {
|
|
22429
|
+
for (const id of ids) {
|
|
22430
|
+
this.#database.prepare(
|
|
22431
|
+
"INSERT OR IGNORE INTO acp_deleted_sessions (session_id) VALUES (?)"
|
|
22432
|
+
).run(id);
|
|
22433
|
+
this.remove(id);
|
|
22434
|
+
}
|
|
22435
|
+
this.#database.exec("COMMIT");
|
|
22436
|
+
return ids;
|
|
22437
|
+
} catch (error61) {
|
|
22438
|
+
this.#database.exec("ROLLBACK");
|
|
22439
|
+
throw error61;
|
|
22440
|
+
}
|
|
22441
|
+
};
|
|
22111
22442
|
write = (session) => {
|
|
22112
22443
|
this.#database.prepare(
|
|
22113
22444
|
`
|
|
@@ -22237,7 +22568,7 @@ function createWritableAcpStream(output2) {
|
|
|
22237
22568
|
if (outputFailure !== void 0) {
|
|
22238
22569
|
return Promise.reject(outputFailure);
|
|
22239
22570
|
}
|
|
22240
|
-
return new Promise((
|
|
22571
|
+
return new Promise((resolve5, reject) => {
|
|
22241
22572
|
pendingWriteFailures.add(reject);
|
|
22242
22573
|
output2.write(chunk, (error61) => {
|
|
22243
22574
|
pendingWriteFailures.delete(reject);
|
|
@@ -22250,7 +22581,7 @@ function createWritableAcpStream(output2) {
|
|
|
22250
22581
|
reject(outputFailure);
|
|
22251
22582
|
return;
|
|
22252
22583
|
}
|
|
22253
|
-
|
|
22584
|
+
resolve5();
|
|
22254
22585
|
});
|
|
22255
22586
|
});
|
|
22256
22587
|
}
|
|
@@ -22411,7 +22742,8 @@ function normalizeCapabilities(capabilities) {
|
|
|
22411
22742
|
imagePrompt: prompt?.image === true,
|
|
22412
22743
|
listSessions: session?.list != null,
|
|
22413
22744
|
loadSession: capabilities.loadSession === true,
|
|
22414
|
-
resumeSession: session?.resume != null
|
|
22745
|
+
resumeSession: session?.resume != null,
|
|
22746
|
+
unstableForkSession: session?.fork != null
|
|
22415
22747
|
};
|
|
22416
22748
|
}
|
|
22417
22749
|
function elicitationFieldType(value) {
|
|
@@ -22759,15 +23091,18 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22759
23091
|
imagePrompt: false,
|
|
22760
23092
|
listSessions: false,
|
|
22761
23093
|
loadSession: false,
|
|
22762
|
-
resumeSession: false
|
|
23094
|
+
resumeSession: false,
|
|
23095
|
+
unstableForkSession: false
|
|
22763
23096
|
};
|
|
22764
23097
|
#commands = [];
|
|
22765
23098
|
#configOptions = [];
|
|
22766
23099
|
#nativeSessionId = "";
|
|
22767
23100
|
#prompted = false;
|
|
22768
|
-
#
|
|
23101
|
+
#replay = {
|
|
23102
|
+
kind: "idle"
|
|
23103
|
+
};
|
|
22769
23104
|
#restored = false;
|
|
22770
|
-
#sessionTitle =
|
|
23105
|
+
#sessionTitle = null;
|
|
22771
23106
|
#sessionUpdatedAt = "";
|
|
22772
23107
|
#turn = new IdleAcpTurn();
|
|
22773
23108
|
#updateTail = Promise.resolve();
|
|
@@ -22796,9 +23131,9 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22796
23131
|
stderr.on("data", (chunk) => {
|
|
22797
23132
|
process.stderr.write(`[${agent.id}-acp] ${chunk}`);
|
|
22798
23133
|
});
|
|
22799
|
-
this.#processExit = new Promise((
|
|
22800
|
-
this.#child.once("error",
|
|
22801
|
-
this.#child.once("exit",
|
|
23134
|
+
this.#processExit = new Promise((resolve5) => {
|
|
23135
|
+
this.#child.once("error", resolve5);
|
|
23136
|
+
this.#child.once("exit", resolve5);
|
|
22802
23137
|
});
|
|
22803
23138
|
const stream = ndJsonStream2(
|
|
22804
23139
|
createWritableAcpStream(stdin),
|
|
@@ -22829,10 +23164,11 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22829
23164
|
store
|
|
22830
23165
|
);
|
|
22831
23166
|
try {
|
|
22832
|
-
await runtime.initialize(options.signal);
|
|
23167
|
+
await runtime.initialize(options.signal, options.origin);
|
|
22833
23168
|
return runtime;
|
|
22834
23169
|
} catch (error61) {
|
|
22835
23170
|
await runtime.closeProcess();
|
|
23171
|
+
options.signal.throwIfAborted();
|
|
22836
23172
|
if (error61 instanceof AcpExecutionError) {
|
|
22837
23173
|
throw error61;
|
|
22838
23174
|
}
|
|
@@ -22851,7 +23187,33 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22851
23187
|
this.#configOptions,
|
|
22852
23188
|
this.#restored
|
|
22853
23189
|
);
|
|
22854
|
-
|
|
23190
|
+
loadHistory = async (signal) => {
|
|
23191
|
+
if (!this.#capabilities.loadSession) return { status: "unavailable" };
|
|
23192
|
+
const history = new AcpHistoryReplay();
|
|
23193
|
+
this.#replay = { kind: "capture", history };
|
|
23194
|
+
try {
|
|
23195
|
+
await this.race(
|
|
23196
|
+
this.#connection.agent.request(
|
|
23197
|
+
methods3.agent.session.load,
|
|
23198
|
+
{
|
|
23199
|
+
additionalDirectories: [...this.#additionalDirectories],
|
|
23200
|
+
cwd: this.#cwd,
|
|
23201
|
+
mcpServers: [],
|
|
23202
|
+
sessionId: this.#nativeSessionId
|
|
23203
|
+
},
|
|
23204
|
+
{ cancellationSignal: signal }
|
|
23205
|
+
),
|
|
23206
|
+
"ACP agent exited while loading history",
|
|
23207
|
+
signal
|
|
23208
|
+
);
|
|
23209
|
+
await this.#updateTail;
|
|
23210
|
+
signal.throwIfAborted();
|
|
23211
|
+
return history.snapshot();
|
|
23212
|
+
} finally {
|
|
23213
|
+
this.#replay = { kind: "idle" };
|
|
23214
|
+
}
|
|
23215
|
+
};
|
|
23216
|
+
initialize = async (signal, origin) => {
|
|
22855
23217
|
const initialized = await this.race(
|
|
22856
23218
|
this.#connection.agent.request(
|
|
22857
23219
|
methods3.agent.initialize,
|
|
@@ -22883,9 +23245,56 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22883
23245
|
255
|
|
22884
23246
|
);
|
|
22885
23247
|
this.#agentVersion = truncate2(initialized.agentInfo?.version ?? "", 128);
|
|
22886
|
-
const stored =
|
|
23248
|
+
const stored = origin?.kind === "import" ? new FoundAcpStoredSession(
|
|
23249
|
+
new AcpStoredSession(
|
|
23250
|
+
this.#mobiusSessionId,
|
|
23251
|
+
this.#agentId,
|
|
23252
|
+
nativeSessionIdSchema.parse(origin.nativeSessionId),
|
|
23253
|
+
this.#cwd,
|
|
23254
|
+
this.#additionalDirectories,
|
|
23255
|
+
true
|
|
23256
|
+
)
|
|
23257
|
+
) : this.#store.read(this.#mobiusSessionId);
|
|
23258
|
+
if (stored instanceof DeletedAcpStoredSession)
|
|
23259
|
+
throw new AcpExecutionError(
|
|
23260
|
+
"The native Agent session was deleted. Start a new chat.",
|
|
23261
|
+
{},
|
|
23262
|
+
"native_session_deleted"
|
|
23263
|
+
);
|
|
22887
23264
|
let lifecycleResponse;
|
|
22888
|
-
if (
|
|
23265
|
+
if (origin?.kind === "fork") {
|
|
23266
|
+
if (!this.#capabilities.unstableForkSession)
|
|
23267
|
+
throw new AcpExecutionError(
|
|
23268
|
+
"This Agent does not support session forking",
|
|
23269
|
+
{},
|
|
23270
|
+
"native_session_unsupported"
|
|
23271
|
+
);
|
|
23272
|
+
const forked = await this.race(
|
|
23273
|
+
this.#connection.agent.request(
|
|
23274
|
+
methods3.agent.session.fork,
|
|
23275
|
+
{
|
|
23276
|
+
sessionId: nativeSessionIdSchema.parse(origin.nativeSessionId),
|
|
23277
|
+
cwd: this.#cwd,
|
|
23278
|
+
additionalDirectories: [...this.#additionalDirectories],
|
|
23279
|
+
mcpServers: []
|
|
23280
|
+
},
|
|
23281
|
+
{ cancellationSignal: signal }
|
|
23282
|
+
),
|
|
23283
|
+
"ACP agent exited while forking a session",
|
|
23284
|
+
signal
|
|
23285
|
+
);
|
|
23286
|
+
this.#nativeSessionId = nativeSessionIdSchema.parse(forked.sessionId);
|
|
23287
|
+
if (this.#nativeSessionId === origin.nativeSessionId || this.#store.findNative(this.#agentId, this.#nativeSessionId).length > 0) {
|
|
23288
|
+
throw new AcpExecutionError(
|
|
23289
|
+
"The Agent did not create an independent fork",
|
|
23290
|
+
{},
|
|
23291
|
+
"invalid_native_session_response"
|
|
23292
|
+
);
|
|
23293
|
+
}
|
|
23294
|
+
this.#prompted = true;
|
|
23295
|
+
this.#restored = true;
|
|
23296
|
+
lifecycleResponse = forked;
|
|
23297
|
+
} else if (stored instanceof FoundAcpStoredSession && stored.session.agentId === this.#agentId && stored.session.cwd === this.#cwd && arraysEqual(
|
|
22889
23298
|
stored.session.additionalDirectories,
|
|
22890
23299
|
this.#additionalDirectories
|
|
22891
23300
|
)) {
|
|
@@ -22908,7 +23317,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22908
23317
|
signal
|
|
22909
23318
|
);
|
|
22910
23319
|
} else if (this.#capabilities.loadSession) {
|
|
22911
|
-
this.#
|
|
23320
|
+
this.#replay = { kind: "discard" };
|
|
22912
23321
|
try {
|
|
22913
23322
|
lifecycleResponse = await this.race(
|
|
22914
23323
|
this.#connection.agent.request(
|
|
@@ -22925,7 +23334,8 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22925
23334
|
signal
|
|
22926
23335
|
);
|
|
22927
23336
|
} finally {
|
|
22928
|
-
this.#
|
|
23337
|
+
await this.#updateTail;
|
|
23338
|
+
this.#replay = { kind: "idle" };
|
|
22929
23339
|
}
|
|
22930
23340
|
} else {
|
|
22931
23341
|
throw new AcpExecutionError(
|
|
@@ -22978,7 +23388,60 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22978
23388
|
);
|
|
22979
23389
|
await this.#updateTail;
|
|
22980
23390
|
signal.throwIfAborted();
|
|
23391
|
+
this.#store.write(
|
|
23392
|
+
new AcpStoredSession(
|
|
23393
|
+
this.#mobiusSessionId,
|
|
23394
|
+
this.#agentId,
|
|
23395
|
+
this.#nativeSessionId,
|
|
23396
|
+
this.#cwd,
|
|
23397
|
+
this.#additionalDirectories,
|
|
23398
|
+
this.#prompted
|
|
23399
|
+
)
|
|
23400
|
+
);
|
|
23401
|
+
};
|
|
23402
|
+
listNativeSessions = async (cursor, signal) => {
|
|
23403
|
+
if (!this.#capabilities.listSessions)
|
|
23404
|
+
throw new AcpExecutionError(
|
|
23405
|
+
"This Agent does not support native session listing",
|
|
23406
|
+
{},
|
|
23407
|
+
"native_session_unsupported"
|
|
23408
|
+
);
|
|
23409
|
+
const response = await this.race(
|
|
23410
|
+
this.#connection.agent.request(
|
|
23411
|
+
methods3.agent.session.list,
|
|
23412
|
+
cursor === null ? {} : { cursor },
|
|
23413
|
+
{ cancellationSignal: signal }
|
|
23414
|
+
),
|
|
23415
|
+
"ACP agent exited while listing sessions",
|
|
23416
|
+
signal
|
|
23417
|
+
);
|
|
23418
|
+
const decoded = nativeSessionPageSchema.safeParse(response);
|
|
23419
|
+
if (!decoded.success)
|
|
23420
|
+
throw new AcpExecutionError(
|
|
23421
|
+
"The Agent returned an invalid native session list",
|
|
23422
|
+
{ cause: decoded.error },
|
|
23423
|
+
"invalid_native_session_response"
|
|
23424
|
+
);
|
|
23425
|
+
return decoded.data;
|
|
23426
|
+
};
|
|
23427
|
+
deleteNativeSession = async (nativeSessionId, signal) => {
|
|
23428
|
+
if (!this.#capabilities.deleteSession || !this.#capabilities.listSessions)
|
|
23429
|
+
throw new AcpExecutionError(
|
|
23430
|
+
"This Agent does not support native session deletion",
|
|
23431
|
+
{},
|
|
23432
|
+
"native_session_unsupported"
|
|
23433
|
+
);
|
|
23434
|
+
await this.race(
|
|
23435
|
+
this.#connection.agent.request(
|
|
23436
|
+
methods3.agent.session.delete,
|
|
23437
|
+
{ sessionId: nativeSessionIdSchema.parse(nativeSessionId) },
|
|
23438
|
+
{ cancellationSignal: signal }
|
|
23439
|
+
),
|
|
23440
|
+
"ACP agent exited while deleting a session",
|
|
23441
|
+
signal
|
|
23442
|
+
);
|
|
22981
23443
|
};
|
|
23444
|
+
nativeSessionId = () => this.#nativeSessionId;
|
|
22982
23445
|
configure = async (options) => {
|
|
22983
23446
|
const existing = this.#configOptions.find(
|
|
22984
23447
|
(option) => option.id === options.configId
|
|
@@ -23141,7 +23604,28 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
23141
23604
|
);
|
|
23142
23605
|
await this.#updateTail;
|
|
23143
23606
|
await running.activities.finish();
|
|
23144
|
-
|
|
23607
|
+
let result;
|
|
23608
|
+
try {
|
|
23609
|
+
result = decodeAgentPromptResponse(response);
|
|
23610
|
+
} catch (cause) {
|
|
23611
|
+
throw new AcpExecutionError(
|
|
23612
|
+
"ACP agent returned an invalid prompt response",
|
|
23613
|
+
{ cause },
|
|
23614
|
+
"acp_invalid_prompt_response"
|
|
23615
|
+
);
|
|
23616
|
+
}
|
|
23617
|
+
if (result.usage != null || result._meta?.quota !== void 0) {
|
|
23618
|
+
await this.#getObserver().onUsage({
|
|
23619
|
+
_meta: result._meta ?? null,
|
|
23620
|
+
commandId: options.commandId,
|
|
23621
|
+
kind: SESSION_USAGE_UPDATED_KIND,
|
|
23622
|
+
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
23623
|
+
sessionId: this.#mobiusSessionId,
|
|
23624
|
+
source: "prompt",
|
|
23625
|
+
usage: result.usage ?? null
|
|
23626
|
+
});
|
|
23627
|
+
}
|
|
23628
|
+
return result;
|
|
23145
23629
|
} catch (error61) {
|
|
23146
23630
|
await running.activities.finish();
|
|
23147
23631
|
if (error61 instanceof AcpExecutionError) {
|
|
@@ -23361,7 +23845,8 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
23361
23845
|
processUpdate = async (notification) => {
|
|
23362
23846
|
this.assertNativeSession(notification.sessionId);
|
|
23363
23847
|
const update = notification.update;
|
|
23364
|
-
if (this.#
|
|
23848
|
+
if (this.#replay.kind === "capture") this.#replay.history.record(update);
|
|
23849
|
+
if (this.#replay.kind !== "idle" && (update.sessionUpdate === "user_message_chunk" || update.sessionUpdate === "agent_message_chunk" || update.sessionUpdate === "agent_thought_chunk" || update.sessionUpdate === "tool_call" || update.sessionUpdate === "tool_call_update" || update.sessionUpdate === "plan" || update.sessionUpdate === "plan_update" || update.sessionUpdate === "plan_removed")) {
|
|
23365
23850
|
return;
|
|
23366
23851
|
}
|
|
23367
23852
|
if (update.sessionUpdate === "agent_message_chunk") {
|
|
@@ -23475,6 +23960,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
23475
23960
|
protocolVersion: MOBIUS_PROTOCOL_VERSION,
|
|
23476
23961
|
sessionId: this.#mobiusSessionId,
|
|
23477
23962
|
size: Math.max(0, Math.trunc(update.size)),
|
|
23963
|
+
source: "context",
|
|
23478
23964
|
used: Math.max(0, Math.trunc(update.used))
|
|
23479
23965
|
});
|
|
23480
23966
|
}
|
|
@@ -23596,6 +24082,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
23596
24082
|
};
|
|
23597
24083
|
};
|
|
23598
24084
|
var AcpSessionManager = class {
|
|
24085
|
+
#nativeOperations = /* @__PURE__ */ new Set();
|
|
23599
24086
|
#activeSessionIds = /* @__PURE__ */ new Set();
|
|
23600
24087
|
#cancellationRequests = /* @__PURE__ */ new Set();
|
|
23601
24088
|
#preparing = /* @__PURE__ */ new Map();
|
|
@@ -23647,6 +24134,21 @@ var AcpSessionManager = class {
|
|
|
23647
24134
|
return await operation;
|
|
23648
24135
|
}
|
|
23649
24136
|
prepareSession = async (options) => {
|
|
24137
|
+
const stored = this.#store.read(options.sessionId);
|
|
24138
|
+
if (stored instanceof DeletedAcpStoredSession)
|
|
24139
|
+
throw new AcpExecutionError(
|
|
24140
|
+
"The native Agent session was deleted. Start a new chat.",
|
|
24141
|
+
{},
|
|
24142
|
+
"native_session_deleted"
|
|
24143
|
+
);
|
|
24144
|
+
if (stored instanceof FoundAcpStoredSession && this.#nativeOperations.has(
|
|
24145
|
+
`${stored.session.agentId}:${stored.session.nativeSessionId}`
|
|
24146
|
+
))
|
|
24147
|
+
throw new AcpExecutionError(
|
|
24148
|
+
"The native session is being managed",
|
|
24149
|
+
{},
|
|
24150
|
+
"session_busy"
|
|
24151
|
+
);
|
|
23650
24152
|
const pending = this.#preparing.get(options.sessionId);
|
|
23651
24153
|
if (pending !== void 0) {
|
|
23652
24154
|
const runtime2 = await pending;
|
|
@@ -23693,6 +24195,16 @@ var AcpSessionManager = class {
|
|
|
23693
24195
|
}
|
|
23694
24196
|
};
|
|
23695
24197
|
runPrompt = async (options) => {
|
|
24198
|
+
const stored = this.#store.read(options.sessionId);
|
|
24199
|
+
if (stored instanceof FoundAcpStoredSession && this.#nativeOperations.has(
|
|
24200
|
+
`${stored.session.agentId}:${stored.session.nativeSessionId}`
|
|
24201
|
+
)) {
|
|
24202
|
+
throw new AcpExecutionError(
|
|
24203
|
+
"The native session is being managed",
|
|
24204
|
+
{},
|
|
24205
|
+
"session_busy"
|
|
24206
|
+
);
|
|
24207
|
+
}
|
|
23696
24208
|
if (this.#activeSessionIds.has(options.sessionId)) {
|
|
23697
24209
|
throw new AcpExecutionError(
|
|
23698
24210
|
"Another prompt is already running in this conversation",
|
|
@@ -23706,6 +24218,14 @@ var AcpSessionManager = class {
|
|
|
23706
24218
|
return { stopReason: "cancelled" };
|
|
23707
24219
|
}
|
|
23708
24220
|
const runtime = await this.ensureSession(options);
|
|
24221
|
+
if (this.#nativeOperations.has(
|
|
24222
|
+
`${options.agent.id}:${runtime.nativeSessionId()}`
|
|
24223
|
+
))
|
|
24224
|
+
throw new AcpExecutionError(
|
|
24225
|
+
"The native session is being managed",
|
|
24226
|
+
{},
|
|
24227
|
+
"session_busy"
|
|
24228
|
+
);
|
|
23709
24229
|
if (this.#cancellationRequests.has(options.sessionId)) {
|
|
23710
24230
|
return { stopReason: "cancelled" };
|
|
23711
24231
|
}
|
|
@@ -23777,6 +24297,124 @@ var AcpSessionManager = class {
|
|
|
23777
24297
|
}
|
|
23778
24298
|
return started;
|
|
23779
24299
|
};
|
|
24300
|
+
listNativeSessions = async (options, cursor) => await (await this.ensureSession(options)).listNativeSessions(
|
|
24301
|
+
cursor,
|
|
24302
|
+
options.signal
|
|
24303
|
+
);
|
|
24304
|
+
openNativeSession = async (options, origin) => {
|
|
24305
|
+
const key = `${options.agent.id}:${origin.nativeSessionId}`;
|
|
24306
|
+
if (this.#nativeOperations.has(key))
|
|
24307
|
+
throw new AcpExecutionError(
|
|
24308
|
+
"The native session is being managed",
|
|
24309
|
+
{},
|
|
24310
|
+
"session_busy"
|
|
24311
|
+
);
|
|
24312
|
+
const linked = this.#store.findNative(
|
|
24313
|
+
options.agent.id,
|
|
24314
|
+
origin.nativeSessionId
|
|
24315
|
+
);
|
|
24316
|
+
if (linked.some(
|
|
24317
|
+
(entry) => this.#activeSessionIds.has(entry.sessionId) || this.#preparing.has(entry.sessionId)
|
|
24318
|
+
))
|
|
24319
|
+
throw new AcpExecutionError(
|
|
24320
|
+
"Wait for the native session's running operation to finish",
|
|
24321
|
+
{},
|
|
24322
|
+
"session_busy"
|
|
24323
|
+
);
|
|
24324
|
+
const existing = linked[0];
|
|
24325
|
+
if (origin.kind === "import" && existing !== void 0) {
|
|
24326
|
+
const runtime = await this.ensureSession({
|
|
24327
|
+
...options,
|
|
24328
|
+
sessionId: existing.sessionId
|
|
24329
|
+
});
|
|
24330
|
+
if (this.#activeSessionIds.has(existing.sessionId) || this.#nativeOperations.has(key))
|
|
24331
|
+
throw new AcpExecutionError(
|
|
24332
|
+
"Wait for the native session's running operation to finish",
|
|
24333
|
+
{},
|
|
24334
|
+
"session_busy"
|
|
24335
|
+
);
|
|
24336
|
+
this.#nativeOperations.add(key);
|
|
24337
|
+
try {
|
|
24338
|
+
const history = await runtime.loadHistory(options.signal);
|
|
24339
|
+
return {
|
|
24340
|
+
prepared: runtime.prepared(),
|
|
24341
|
+
sessionId: existing.sessionId,
|
|
24342
|
+
history
|
|
24343
|
+
};
|
|
24344
|
+
} catch (error61) {
|
|
24345
|
+
this.#sessions.delete(existing.sessionId);
|
|
24346
|
+
await runtime.closeProcess();
|
|
24347
|
+
throw error61;
|
|
24348
|
+
} finally {
|
|
24349
|
+
this.#nativeOperations.delete(key);
|
|
24350
|
+
}
|
|
24351
|
+
}
|
|
24352
|
+
if (this.#sessions.has(options.sessionId) || this.#preparing.has(options.sessionId) || this.#store.read(options.sessionId) instanceof FoundAcpStoredSession || this.#store.read(options.sessionId) instanceof DeletedAcpStoredSession)
|
|
24353
|
+
throw new AcpExecutionError(
|
|
24354
|
+
"The destination conversation already exists",
|
|
24355
|
+
{},
|
|
24356
|
+
"session_identity_mismatch"
|
|
24357
|
+
);
|
|
24358
|
+
this.#nativeOperations.add(key);
|
|
24359
|
+
try {
|
|
24360
|
+
const runtime = await this.#startPreparation({ ...options, origin });
|
|
24361
|
+
const openedKey = `${options.agent.id}:${runtime.nativeSessionId()}`;
|
|
24362
|
+
this.#nativeOperations.add(openedKey);
|
|
24363
|
+
try {
|
|
24364
|
+
const history = await runtime.loadHistory(options.signal);
|
|
24365
|
+
return {
|
|
24366
|
+
sessionId: options.sessionId,
|
|
24367
|
+
prepared: runtime.prepared(),
|
|
24368
|
+
history
|
|
24369
|
+
};
|
|
24370
|
+
} catch (error61) {
|
|
24371
|
+
this.#sessions.delete(options.sessionId);
|
|
24372
|
+
this.#store.remove(options.sessionId);
|
|
24373
|
+
await runtime.closeProcess();
|
|
24374
|
+
throw error61;
|
|
24375
|
+
} finally {
|
|
24376
|
+
this.#nativeOperations.delete(openedKey);
|
|
24377
|
+
}
|
|
24378
|
+
} finally {
|
|
24379
|
+
this.#nativeOperations.delete(key);
|
|
24380
|
+
}
|
|
24381
|
+
};
|
|
24382
|
+
deleteNativeSession = async (options, nativeSessionId) => {
|
|
24383
|
+
const runtime = await this.ensureSession(options);
|
|
24384
|
+
const key = `${options.agent.id}:${nativeSessionId}`;
|
|
24385
|
+
const linked = this.#store.findNative(options.agent.id, nativeSessionId);
|
|
24386
|
+
if (this.#nativeOperations.has(key) || linked.some(
|
|
24387
|
+
(entry) => this.#activeSessionIds.has(entry.sessionId) || this.#preparing.has(entry.sessionId)
|
|
24388
|
+
))
|
|
24389
|
+
throw new AcpExecutionError(
|
|
24390
|
+
"Wait for the native session's running operation to finish",
|
|
24391
|
+
{},
|
|
24392
|
+
"session_busy"
|
|
24393
|
+
);
|
|
24394
|
+
this.#nativeOperations.add(key);
|
|
24395
|
+
try {
|
|
24396
|
+
for (const entry of linked) {
|
|
24397
|
+
const active = this.#sessions.get(entry.sessionId);
|
|
24398
|
+
if (active !== void 0 && active !== runtime) {
|
|
24399
|
+
this.#sessions.delete(entry.sessionId);
|
|
24400
|
+
await active.close();
|
|
24401
|
+
}
|
|
24402
|
+
}
|
|
24403
|
+
options.signal.throwIfAborted();
|
|
24404
|
+
await runtime.deleteNativeSession(nativeSessionId, options.signal);
|
|
24405
|
+
const deleted = this.#store.markDeleted(
|
|
24406
|
+
options.agent.id,
|
|
24407
|
+
nativeSessionId
|
|
24408
|
+
);
|
|
24409
|
+
if (runtime.nativeSessionId() === nativeSessionId) {
|
|
24410
|
+
this.#sessions.delete(options.sessionId);
|
|
24411
|
+
await runtime.close();
|
|
24412
|
+
}
|
|
24413
|
+
return deleted;
|
|
24414
|
+
} finally {
|
|
24415
|
+
this.#nativeOperations.delete(key);
|
|
24416
|
+
}
|
|
24417
|
+
};
|
|
23780
24418
|
};
|
|
23781
24419
|
|
|
23782
24420
|
// src/agent-catalog/publish-agent-catalog.ts
|
|
@@ -24224,7 +24862,7 @@ function stableFailureCode(error61) {
|
|
|
24224
24862
|
function discoveryOptions(options, environment, signal, specifications) {
|
|
24225
24863
|
return {
|
|
24226
24864
|
...options.architecture === void 0 ? {} : { architecture: options.architecture },
|
|
24227
|
-
|
|
24865
|
+
defaultWorkspace: options.defaultWorkspace,
|
|
24228
24866
|
environment,
|
|
24229
24867
|
...options.platform === void 0 ? {} : { platform: options.platform },
|
|
24230
24868
|
signal,
|
|
@@ -24380,11 +25018,11 @@ var AutomaticAdapterProvisioner = class {
|
|
|
24380
25018
|
|
|
24381
25019
|
// src/agent-installation/fixed-installation-executor.ts
|
|
24382
25020
|
import { realpathSync as realpathSync2, statSync as statSync2 } from "node:fs";
|
|
24383
|
-
import {
|
|
25021
|
+
import { resolve as resolve4 } from "node:path";
|
|
24384
25022
|
|
|
24385
25023
|
// src/agent-installation/fixed-agent-install-recipes.ts
|
|
24386
25024
|
import { mkdir as mkdir3, mkdtemp as mkdtemp2, rm as rm2 } from "node:fs/promises";
|
|
24387
|
-
import { join as
|
|
25025
|
+
import { join as join8 } from "node:path";
|
|
24388
25026
|
|
|
24389
25027
|
// src/agent-installation/verified-download.ts
|
|
24390
25028
|
import { createHash } from "node:crypto";
|
|
@@ -24591,8 +25229,8 @@ var FixedAgentInstallRecipe = class {
|
|
|
24591
25229
|
);
|
|
24592
25230
|
}
|
|
24593
25231
|
};
|
|
24594
|
-
requireInstalledExecutable = async (
|
|
24595
|
-
const executable = await resolveExecutablePath(
|
|
25232
|
+
requireInstalledExecutable = async (path2) => {
|
|
25233
|
+
const executable = await resolveExecutablePath(path2);
|
|
24596
25234
|
if (executable === null) {
|
|
24597
25235
|
throw new InstallationManagerError(
|
|
24598
25236
|
"agent_verification_failed",
|
|
@@ -24608,18 +25246,18 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
24608
25246
|
releaseChannel = "latest";
|
|
24609
25247
|
install = async (options) => {
|
|
24610
25248
|
this.assertSupportedPlatform();
|
|
24611
|
-
const root =
|
|
24612
|
-
const temporaryRoot =
|
|
25249
|
+
const root = join8(options.stateDirectory, "agents", this.id);
|
|
25250
|
+
const temporaryRoot = join8(options.stateDirectory, "temporary");
|
|
24613
25251
|
await Promise.all([
|
|
24614
25252
|
mkdir3(root, { mode: 448, recursive: true }),
|
|
24615
25253
|
mkdir3(temporaryRoot, { mode: 448, recursive: true })
|
|
24616
25254
|
]);
|
|
24617
25255
|
const temporaryDirectory = await mkdtemp2(
|
|
24618
|
-
|
|
25256
|
+
join8(temporaryRoot, ".codex-install-")
|
|
24619
25257
|
);
|
|
24620
|
-
const installerPath =
|
|
24621
|
-
const installDirectory =
|
|
24622
|
-
const codexHome =
|
|
25258
|
+
const installerPath = join8(temporaryDirectory, "install.sh");
|
|
25259
|
+
const installDirectory = join8(root, "bin");
|
|
25260
|
+
const codexHome = join8(root, "home");
|
|
24623
25261
|
try {
|
|
24624
25262
|
await Promise.all([
|
|
24625
25263
|
mkdir3(installDirectory, { mode: 448, recursive: true }),
|
|
@@ -24663,7 +25301,7 @@ var CodexInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
24663
25301
|
timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
|
|
24664
25302
|
});
|
|
24665
25303
|
return await this.requireInstalledExecutable(
|
|
24666
|
-
|
|
25304
|
+
join8(installDirectory, "codex")
|
|
24667
25305
|
);
|
|
24668
25306
|
} catch (error61) {
|
|
24669
25307
|
if (options.signal.aborted) {
|
|
@@ -24687,17 +25325,17 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
24687
25325
|
releaseChannel = "stable";
|
|
24688
25326
|
install = async (options) => {
|
|
24689
25327
|
this.assertSupportedPlatform();
|
|
24690
|
-
const root =
|
|
24691
|
-
const managedHome =
|
|
24692
|
-
const temporaryRoot =
|
|
25328
|
+
const root = join8(options.stateDirectory, "agents", this.id);
|
|
25329
|
+
const managedHome = join8(root, "home");
|
|
25330
|
+
const temporaryRoot = join8(options.stateDirectory, "temporary");
|
|
24693
25331
|
await Promise.all([
|
|
24694
25332
|
mkdir3(managedHome, { mode: 448, recursive: true }),
|
|
24695
25333
|
mkdir3(temporaryRoot, { mode: 448, recursive: true })
|
|
24696
25334
|
]);
|
|
24697
25335
|
const temporaryDirectory = await mkdtemp2(
|
|
24698
|
-
|
|
25336
|
+
join8(temporaryRoot, ".claude-install-")
|
|
24699
25337
|
);
|
|
24700
|
-
const installerPath =
|
|
25338
|
+
const installerPath = join8(temporaryDirectory, "install.sh");
|
|
24701
25339
|
try {
|
|
24702
25340
|
await options.report("downloading");
|
|
24703
25341
|
const download = await downloadVerifiedFile({
|
|
@@ -24734,7 +25372,7 @@ var ClaudeCodeInstallRecipe = class extends FixedAgentInstallRecipe {
|
|
|
24734
25372
|
timeoutMilliseconds: AGENT_INSTALL_TIMEOUT_MILLISECONDS
|
|
24735
25373
|
});
|
|
24736
25374
|
return await this.requireInstalledExecutable(
|
|
24737
|
-
|
|
25375
|
+
join8(managedHome, ".local", "bin", "claude")
|
|
24738
25376
|
);
|
|
24739
25377
|
} catch (error61) {
|
|
24740
25378
|
if (options.signal.aborted) {
|
|
@@ -24782,28 +25420,24 @@ function findRecipe(recipes, agentId) {
|
|
|
24782
25420
|
"The requested Agent does not have an approved installation recipe"
|
|
24783
25421
|
);
|
|
24784
25422
|
}
|
|
24785
|
-
function
|
|
24786
|
-
const difference = relative4(resolve5(root), resolve5(candidate));
|
|
24787
|
-
return difference.length === 0 || !difference.startsWith("..") && !isAbsolute3(difference);
|
|
24788
|
-
}
|
|
24789
|
-
function resolveApprovedRoot2(path) {
|
|
25423
|
+
function resolveDefaultWorkspace2(path2) {
|
|
24790
25424
|
try {
|
|
24791
|
-
const directory = realpathSync2(
|
|
25425
|
+
const directory = realpathSync2(resolve4(path2));
|
|
24792
25426
|
if (!statSync2(directory).isDirectory()) {
|
|
24793
|
-
throw new Error("
|
|
25427
|
+
throw new Error("Default workspace is not a directory");
|
|
24794
25428
|
}
|
|
24795
25429
|
return directory;
|
|
24796
25430
|
} catch (error61) {
|
|
24797
25431
|
throw new InstallationManagerError(
|
|
24798
25432
|
"unsafe_installation_root",
|
|
24799
|
-
"The
|
|
25433
|
+
"The default workspace is unavailable or unsafe",
|
|
24800
25434
|
{ cause: error61 }
|
|
24801
25435
|
);
|
|
24802
25436
|
}
|
|
24803
25437
|
}
|
|
24804
|
-
function resolveUserInstallationDirectory(
|
|
25438
|
+
function resolveUserInstallationDirectory(path2) {
|
|
24805
25439
|
try {
|
|
24806
|
-
const directory = realpathSync2(
|
|
25440
|
+
const directory = realpathSync2(resolve4(path2));
|
|
24807
25441
|
const metadata = statSync2(directory);
|
|
24808
25442
|
if (!metadata.isDirectory() || typeof process.getuid === "function" && metadata.uid !== process.getuid()) {
|
|
24809
25443
|
throw new Error("Installation directory is not user-owned");
|
|
@@ -24840,7 +25474,7 @@ function requiresAdapterReplacement(code) {
|
|
|
24840
25474
|
}
|
|
24841
25475
|
var FixedInstallationExecutor = class {
|
|
24842
25476
|
#adapterInstaller;
|
|
24843
|
-
#
|
|
25477
|
+
#defaultWorkspace;
|
|
24844
25478
|
#audit;
|
|
24845
25479
|
#catalog;
|
|
24846
25480
|
#environment;
|
|
@@ -24849,17 +25483,11 @@ var FixedInstallationExecutor = class {
|
|
|
24849
25483
|
#specifications;
|
|
24850
25484
|
#stateDirectory;
|
|
24851
25485
|
constructor(options, specifications = supportedLocalAgentSpecifications(), recipes = fixedAgentInstallRecipes(), adapterInstaller) {
|
|
24852
|
-
const
|
|
25486
|
+
const defaultWorkspace = resolveDefaultWorkspace2(options.defaultWorkspace);
|
|
24853
25487
|
const stateDirectory = resolveUserInstallationDirectory(
|
|
24854
25488
|
options.stateDirectory
|
|
24855
25489
|
);
|
|
24856
|
-
|
|
24857
|
-
throw new InstallationManagerError(
|
|
24858
|
-
"unsafe_installation_root",
|
|
24859
|
-
"The Mobius state directory cannot be inside the approved workspace"
|
|
24860
|
-
);
|
|
24861
|
-
}
|
|
24862
|
-
this.#approvedRoot = approvedRoot;
|
|
25490
|
+
this.#defaultWorkspace = defaultWorkspace;
|
|
24863
25491
|
this.#audit = options.audit;
|
|
24864
25492
|
this.#catalog = options.catalog;
|
|
24865
25493
|
this.#environment = Object.freeze({ ...options.environment });
|
|
@@ -24868,7 +25496,6 @@ var FixedInstallationExecutor = class {
|
|
|
24868
25496
|
this.#specifications = Object.freeze([...specifications]);
|
|
24869
25497
|
this.#stateDirectory = stateDirectory;
|
|
24870
25498
|
this.#adapterInstaller = adapterInstaller ?? new ManagedAdapterInstaller({
|
|
24871
|
-
approvedRoot,
|
|
24872
25499
|
environment: this.#environment,
|
|
24873
25500
|
stateDirectory
|
|
24874
25501
|
});
|
|
@@ -24887,7 +25514,7 @@ var FixedInstallationExecutor = class {
|
|
|
24887
25514
|
}
|
|
24888
25515
|
);
|
|
24889
25516
|
const discoveryOptions2 = {
|
|
24890
|
-
|
|
25517
|
+
defaultWorkspace: this.#defaultWorkspace,
|
|
24891
25518
|
environment: this.#environment,
|
|
24892
25519
|
signal
|
|
24893
25520
|
};
|
|
@@ -24922,7 +25549,7 @@ var FixedInstallationExecutor = class {
|
|
|
24922
25549
|
environment[specification.agentOverrideVariable] = agent.path;
|
|
24923
25550
|
environment[specification.adapterOverrideVariable] = adapter.path;
|
|
24924
25551
|
const inventory = await discoverLocalAgentInventory({
|
|
24925
|
-
|
|
25552
|
+
defaultWorkspace: this.#defaultWorkspace,
|
|
24926
25553
|
environment,
|
|
24927
25554
|
signal,
|
|
24928
25555
|
specifications: this.#specifications
|
|
@@ -25034,7 +25661,7 @@ Mobius Web requested installation of ${label} (${requestId}). Allow this fixed u
|
|
|
25034
25661
|
};
|
|
25035
25662
|
};
|
|
25036
25663
|
|
|
25037
|
-
// src/authorization/
|
|
25664
|
+
// src/authorization/local-authorization-error.ts
|
|
25038
25665
|
var LocalAuthorizationError = class extends Error {
|
|
25039
25666
|
code = "local_authorization_failed";
|
|
25040
25667
|
constructor(message, options = {}) {
|
|
@@ -25044,18 +25671,16 @@ var LocalAuthorizationError = class extends Error {
|
|
|
25044
25671
|
};
|
|
25045
25672
|
|
|
25046
25673
|
// src/authorization/workspace-directory.ts
|
|
25047
|
-
import { readdir, realpath as
|
|
25674
|
+
import { readdir, realpath as realpath4, stat as stat4 } from "node:fs/promises";
|
|
25675
|
+
import { homedir as homedir2 } from "node:os";
|
|
25048
25676
|
import {
|
|
25049
25677
|
basename as basename2,
|
|
25050
25678
|
dirname as dirname4,
|
|
25051
|
-
isAbsolute as
|
|
25052
|
-
join as
|
|
25679
|
+
isAbsolute as isAbsolute2,
|
|
25680
|
+
join as join9,
|
|
25053
25681
|
normalize,
|
|
25054
|
-
relative as
|
|
25682
|
+
relative as relative2
|
|
25055
25683
|
} from "node:path";
|
|
25056
|
-
var ROOT_DIRECTORY_ID = "root";
|
|
25057
|
-
var DIRECTORY_ID_PREFIX = "dir-";
|
|
25058
|
-
var DIRECTORY_ID_PATTERN = /^[a-zA-Z0-9_-]+$/;
|
|
25059
25684
|
var WorkspaceDirectoryListing = class {
|
|
25060
25685
|
directoryId;
|
|
25061
25686
|
directoryLabel;
|
|
@@ -25068,150 +25693,690 @@ var WorkspaceDirectoryListing = class {
|
|
|
25068
25693
|
this.parentDirectoryId = parentDirectoryId;
|
|
25069
25694
|
}
|
|
25070
25695
|
};
|
|
25071
|
-
function
|
|
25072
|
-
|
|
25073
|
-
|
|
25696
|
+
function encodePath(path2) {
|
|
25697
|
+
const encoded = Buffer.from(path2, "utf8").toString("base64url");
|
|
25698
|
+
if (encoded.length === 0 || encoded.length > 2e3) {
|
|
25699
|
+
throw new LocalAuthorizationError(
|
|
25700
|
+
"The local directory path is too long to select"
|
|
25701
|
+
);
|
|
25074
25702
|
}
|
|
25075
|
-
return
|
|
25703
|
+
return `path-${encoded}`;
|
|
25076
25704
|
}
|
|
25077
|
-
function
|
|
25078
|
-
|
|
25079
|
-
|
|
25080
|
-
|
|
25081
|
-
if (!value.startsWith(DIRECTORY_ID_PREFIX)) {
|
|
25082
|
-
throw new LocalAuthorizationError("The workspace directory is invalid");
|
|
25083
|
-
}
|
|
25084
|
-
const encoded = value.slice(DIRECTORY_ID_PREFIX.length);
|
|
25085
|
-
if (encoded.length === 0 || encoded.length > 2e3 || !DIRECTORY_ID_PATTERN.test(encoded)) {
|
|
25086
|
-
throw new LocalAuthorizationError("The workspace directory is invalid");
|
|
25087
|
-
}
|
|
25705
|
+
function decodePath(value, prefix) {
|
|
25706
|
+
const encoded = value.slice(prefix.length);
|
|
25707
|
+
if (encoded.length === 0 || encoded.length > 2e3 || !/^[a-zA-Z0-9_-]+$/.test(encoded))
|
|
25708
|
+
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
25088
25709
|
const decoded = Buffer.from(encoded, "base64url").toString("utf8");
|
|
25089
|
-
if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded)
|
|
25090
|
-
throw new LocalAuthorizationError("The
|
|
25091
|
-
|
|
25092
|
-
const normalized = normalize(decoded);
|
|
25093
|
-
if (decoded.includes("\0") || isAbsolute4(decoded) || normalized === ".." || normalized.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) || normalized !== decoded) {
|
|
25094
|
-
throw new LocalAuthorizationError("The workspace directory is invalid");
|
|
25095
|
-
}
|
|
25096
|
-
return normalized;
|
|
25097
|
-
}
|
|
25098
|
-
function isContained(root, target) {
|
|
25099
|
-
const remainder = relative5(root, target);
|
|
25100
|
-
return remainder.length === 0 || !isAbsolute4(remainder) && remainder !== ".." && !remainder.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`);
|
|
25710
|
+
if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize(decoded) !== decoded)
|
|
25711
|
+
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
25712
|
+
return decoded;
|
|
25101
25713
|
}
|
|
25102
25714
|
var WorkspaceDirectoryService = class {
|
|
25103
|
-
#
|
|
25104
|
-
#
|
|
25105
|
-
constructor(
|
|
25106
|
-
this.#
|
|
25107
|
-
this.#
|
|
25108
|
-
}
|
|
25109
|
-
|
|
25110
|
-
if (
|
|
25715
|
+
#bindingId;
|
|
25716
|
+
#defaultWorkspace;
|
|
25717
|
+
constructor(bindingId, defaultWorkspace) {
|
|
25718
|
+
this.#bindingId = bindingId;
|
|
25719
|
+
this.#defaultWorkspace = defaultWorkspace;
|
|
25720
|
+
}
|
|
25721
|
+
authorizeMachine = (bindingId) => {
|
|
25722
|
+
if (bindingId !== this.#bindingId)
|
|
25111
25723
|
throw new LocalAuthorizationError(
|
|
25112
25724
|
"The runtime binding is not authorized"
|
|
25113
25725
|
);
|
|
25726
|
+
};
|
|
25727
|
+
requestedPath = (id) => {
|
|
25728
|
+
if (id === "default") return this.#defaultWorkspace;
|
|
25729
|
+
if (id === "home") return homedir2();
|
|
25730
|
+
if (id.startsWith("path-")) {
|
|
25731
|
+
const path2 = decodePath(id, "path-");
|
|
25732
|
+
if (isAbsolute2(path2)) return path2;
|
|
25114
25733
|
}
|
|
25115
|
-
|
|
25116
|
-
|
|
25734
|
+
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
25735
|
+
};
|
|
25736
|
+
resolvePath = async (requested, signal) => {
|
|
25737
|
+
signal.throwIfAborted();
|
|
25738
|
+
if (!isAbsolute2(requested) || requested.includes("\0") || normalize(requested) !== requested)
|
|
25739
|
+
throw new LocalAuthorizationError("The local directory path is invalid");
|
|
25117
25740
|
try {
|
|
25118
|
-
const target = await
|
|
25741
|
+
const target = await realpath4(requested);
|
|
25742
|
+
signal.throwIfAborted();
|
|
25119
25743
|
const metadata = await stat4(target);
|
|
25120
|
-
|
|
25744
|
+
signal.throwIfAborted();
|
|
25745
|
+
if (!isAbsolute2(target) || normalize(target) !== target || !metadata.isDirectory())
|
|
25121
25746
|
throw new LocalAuthorizationError(
|
|
25122
|
-
"The
|
|
25747
|
+
"The selected location is not a directory"
|
|
25123
25748
|
);
|
|
25124
|
-
}
|
|
25125
25749
|
return target;
|
|
25126
|
-
} catch (
|
|
25127
|
-
|
|
25128
|
-
|
|
25129
|
-
}
|
|
25750
|
+
} catch (cause) {
|
|
25751
|
+
signal.throwIfAborted();
|
|
25752
|
+
if (cause instanceof LocalAuthorizationError) throw cause;
|
|
25130
25753
|
throw new LocalAuthorizationError(
|
|
25131
|
-
"
|
|
25132
|
-
{ cause
|
|
25754
|
+
"This directory is missing or unavailable to your user account",
|
|
25755
|
+
{ cause }
|
|
25133
25756
|
);
|
|
25134
25757
|
}
|
|
25135
25758
|
};
|
|
25136
|
-
|
|
25137
|
-
const
|
|
25138
|
-
|
|
25139
|
-
|
|
25759
|
+
label = (path2) => {
|
|
25760
|
+
const suffix = relative2(homedir2(), path2);
|
|
25761
|
+
return suffix === "" ? "~" : !isAbsolute2(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
|
|
25762
|
+
};
|
|
25763
|
+
identify = async (bindingId, requestedPath, signal) => {
|
|
25764
|
+
this.authorizeMachine(bindingId);
|
|
25765
|
+
const path2 = await this.resolvePath(requestedPath, signal);
|
|
25766
|
+
return {
|
|
25767
|
+
path: path2,
|
|
25768
|
+
directoryId: encodePath(path2),
|
|
25769
|
+
name: basename2(path2) || path2,
|
|
25770
|
+
label: this.label(path2)
|
|
25771
|
+
};
|
|
25772
|
+
};
|
|
25773
|
+
resolve = async (bindingId, id, signal) => {
|
|
25774
|
+
this.authorizeMachine(bindingId);
|
|
25775
|
+
return await this.resolvePath(this.requestedPath(id), signal);
|
|
25776
|
+
};
|
|
25777
|
+
list = async (bindingId, id, signal) => {
|
|
25778
|
+
const target = await this.resolve(bindingId, id, signal);
|
|
25140
25779
|
try {
|
|
25141
|
-
const entries = [];
|
|
25142
25780
|
const children = await readdir(target, { withFileTypes: true });
|
|
25781
|
+
signal.throwIfAborted();
|
|
25782
|
+
const entries = [];
|
|
25143
25783
|
for (const child of children) {
|
|
25144
|
-
if (entries.length === 500)
|
|
25145
|
-
|
|
25784
|
+
if (entries.length === 500) break;
|
|
25785
|
+
if (child.isFile() || child.isBlockDevice() || child.isCharacterDevice() || child.isFIFO() || child.isSocket()) {
|
|
25786
|
+
continue;
|
|
25146
25787
|
}
|
|
25147
|
-
const logicalChild = logicalRelativePath.length === 0 ? child.name : join8(logicalRelativePath, child.name);
|
|
25148
25788
|
try {
|
|
25149
|
-
const
|
|
25150
|
-
|
|
25151
|
-
|
|
25152
|
-
|
|
25153
|
-
|
|
25154
|
-
name: child.name
|
|
25155
|
-
});
|
|
25156
|
-
}
|
|
25157
|
-
} catch {
|
|
25789
|
+
const path2 = await this.resolvePath(join9(target, child.name), signal);
|
|
25790
|
+
entries.push({ directoryId: encodePath(path2), name: child.name });
|
|
25791
|
+
} catch (cause) {
|
|
25792
|
+
signal.throwIfAborted();
|
|
25793
|
+
if (!(cause instanceof LocalAuthorizationError)) throw cause;
|
|
25158
25794
|
}
|
|
25159
25795
|
}
|
|
25160
|
-
entries.sort((
|
|
25161
|
-
const
|
|
25162
|
-
const parentRelative = logicalRelativePath.length === 0 || dirname4(logicalRelativePath) === "." ? "" : dirname4(logicalRelativePath);
|
|
25796
|
+
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
25797
|
+
const parent = dirname4(target);
|
|
25163
25798
|
return new WorkspaceDirectoryListing(
|
|
25164
|
-
|
|
25165
|
-
|
|
25799
|
+
id,
|
|
25800
|
+
this.label(target),
|
|
25166
25801
|
entries,
|
|
25167
|
-
|
|
25802
|
+
parent === target ? "" : encodePath(parent)
|
|
25168
25803
|
);
|
|
25169
|
-
} catch (
|
|
25170
|
-
|
|
25171
|
-
|
|
25172
|
-
}
|
|
25804
|
+
} catch (cause) {
|
|
25805
|
+
signal.throwIfAborted();
|
|
25806
|
+
if (cause instanceof LocalAuthorizationError) throw cause;
|
|
25173
25807
|
throw new LocalAuthorizationError(
|
|
25174
|
-
"
|
|
25175
|
-
{ cause
|
|
25808
|
+
"This directory cannot be browsed by your user account",
|
|
25809
|
+
{ cause }
|
|
25176
25810
|
);
|
|
25177
25811
|
}
|
|
25178
25812
|
};
|
|
25179
|
-
resolveMany = async (
|
|
25180
|
-
const
|
|
25181
|
-
const
|
|
25182
|
-
|
|
25183
|
-
|
|
25184
|
-
|
|
25185
|
-
|
|
25813
|
+
resolveMany = async (bindingId, ids, signal) => {
|
|
25814
|
+
const paths = /* @__PURE__ */ new Set();
|
|
25815
|
+
for (const id of ids) paths.add(await this.resolve(bindingId, id, signal));
|
|
25816
|
+
return [...paths];
|
|
25817
|
+
};
|
|
25818
|
+
};
|
|
25819
|
+
|
|
25820
|
+
// src/native-sessions/service.ts
|
|
25821
|
+
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
25822
|
+
|
|
25823
|
+
// src/native-sessions/codex-history.ts
|
|
25824
|
+
import { spawn as spawn4 } from "node:child_process";
|
|
25825
|
+
var responseSchema = external_exports.union([
|
|
25826
|
+
external_exports.object({
|
|
25827
|
+
id: external_exports.number(),
|
|
25828
|
+
error: external_exports.object({ code: external_exports.number(), message: external_exports.string() })
|
|
25829
|
+
}),
|
|
25830
|
+
external_exports.object({ id: external_exports.number(), result: external_exports.unknown() }),
|
|
25831
|
+
external_exports.object({ method: external_exports.string() })
|
|
25832
|
+
]);
|
|
25833
|
+
var threadSchema = external_exports.object({
|
|
25834
|
+
thread: external_exports.object({
|
|
25835
|
+
id: nativeSessionIdSchema,
|
|
25836
|
+
cwd: external_exports.string().min(1).max(2048).refine((path2) => !path2.includes("\0"))
|
|
25837
|
+
})
|
|
25838
|
+
});
|
|
25839
|
+
var turnsSchema = external_exports.object({
|
|
25840
|
+
data: external_exports.array(external_exports.object({ items: external_exports.array(external_exports.unknown()).max(1e5) })).max(SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT),
|
|
25841
|
+
nextCursor: external_exports.string().nullish()
|
|
25842
|
+
});
|
|
25843
|
+
var itemTypeSchema = external_exports.object({ type: external_exports.string().min(1).max(80) });
|
|
25844
|
+
var userMessageSchema = external_exports.object({
|
|
25845
|
+
content: external_exports.array(external_exports.unknown()).max(1e4)
|
|
25846
|
+
});
|
|
25847
|
+
var textSchema = external_exports.object({ text: external_exports.string() });
|
|
25848
|
+
var imageSchema = external_exports.object({ url: external_exports.string() });
|
|
25849
|
+
var agentMessageSchema = textSchema.extend({ phase: external_exports.string().nullish() });
|
|
25850
|
+
function decodeHistory(thread, value) {
|
|
25851
|
+
const page = turnsSchema.parse(value);
|
|
25852
|
+
const messages = [];
|
|
25853
|
+
let characters = 0;
|
|
25854
|
+
let imageCharacters = 0;
|
|
25855
|
+
let truncated = page.nextCursor != null;
|
|
25856
|
+
for (const turn of page.data.toReversed()) {
|
|
25857
|
+
for (const item of turn.items) {
|
|
25858
|
+
const { type } = itemTypeSchema.parse(item);
|
|
25859
|
+
let message;
|
|
25860
|
+
if (type === "userMessage") {
|
|
25861
|
+
const { content } = userMessageSchema.parse(item);
|
|
25862
|
+
const parsed = parseNativeHistoryText(
|
|
25863
|
+
content.map((block) => {
|
|
25864
|
+
const { type: type2 } = itemTypeSchema.parse(block);
|
|
25865
|
+
if (type2 === "text") return textSchema.parse(block).text;
|
|
25866
|
+
if (type2 === "image")
|
|
25867
|
+
return `[@image](${imageSchema.parse(block).url})`;
|
|
25868
|
+
return "[Attachment]";
|
|
25869
|
+
}).join("")
|
|
25870
|
+
);
|
|
25871
|
+
message = {
|
|
25872
|
+
role: "user",
|
|
25873
|
+
text: parsed.text,
|
|
25874
|
+
...parsed.images.length > 0 ? { images: parsed.images } : {}
|
|
25875
|
+
};
|
|
25876
|
+
} else if (type === "agentMessage") {
|
|
25877
|
+
const agent = agentMessageSchema.parse(item);
|
|
25878
|
+
if (agent.phase === "commentary") continue;
|
|
25879
|
+
message = { role: "assistant", text: agent.text };
|
|
25880
|
+
} else {
|
|
25881
|
+
continue;
|
|
25882
|
+
}
|
|
25883
|
+
const text = message.text.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
|
|
25884
|
+
if (text.length === 0 && (message.images?.length ?? 0) === 0) continue;
|
|
25885
|
+
truncated ||= text.length < message.text.length;
|
|
25886
|
+
messages.push({ ...message, text });
|
|
25887
|
+
characters += text.length;
|
|
25888
|
+
imageCharacters += (message.images ?? []).reduce(
|
|
25889
|
+
(size, image) => size + image.data.length,
|
|
25890
|
+
0
|
|
25186
25891
|
);
|
|
25187
|
-
|
|
25188
|
-
|
|
25189
|
-
|
|
25892
|
+
while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT || imageCharacters > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
|
|
25893
|
+
const removed = messages.shift();
|
|
25894
|
+
if (removed !== void 0) {
|
|
25895
|
+
characters -= removed.text.length;
|
|
25896
|
+
imageCharacters -= (removed.images ?? []).reduce(
|
|
25897
|
+
(size, image) => size + image.data.length,
|
|
25898
|
+
0
|
|
25899
|
+
);
|
|
25900
|
+
}
|
|
25901
|
+
truncated = true;
|
|
25190
25902
|
}
|
|
25191
25903
|
}
|
|
25192
|
-
|
|
25904
|
+
}
|
|
25905
|
+
return {
|
|
25906
|
+
nativeSessionId: thread.id,
|
|
25907
|
+
cwd: thread.cwd,
|
|
25908
|
+
history: {
|
|
25909
|
+
status: "available",
|
|
25910
|
+
messages,
|
|
25911
|
+
truncated,
|
|
25912
|
+
coveredCommandIds: []
|
|
25913
|
+
}
|
|
25193
25914
|
};
|
|
25194
|
-
|
|
25915
|
+
}
|
|
25916
|
+
async function readCodexHistory(agent, cwd, nativeSessionId, signal) {
|
|
25917
|
+
signal.throwIfAborted();
|
|
25918
|
+
nativeSessionIdSchema.parse(nativeSessionId);
|
|
25919
|
+
if (agent.id !== "codex" || !await revalidateExecutable(agent.agentIdentity))
|
|
25920
|
+
throw new AcpExecutionError(
|
|
25921
|
+
"The local Codex executable changed. Restart Mobius to discover it again.",
|
|
25922
|
+
{},
|
|
25923
|
+
"agent_executable_changed"
|
|
25924
|
+
);
|
|
25925
|
+
signal.throwIfAborted();
|
|
25926
|
+
const child = spawn4(agent.agentIdentity.realPath, ["app-server"], {
|
|
25927
|
+
cwd,
|
|
25928
|
+
env: { ...process.env, ...agent.environment },
|
|
25929
|
+
detached: process.platform !== "win32",
|
|
25930
|
+
shell: false,
|
|
25931
|
+
stdio: ["pipe", "pipe", "ignore"]
|
|
25932
|
+
});
|
|
25933
|
+
const response = Promise.withResolvers();
|
|
25934
|
+
let state = { kind: "initializing", requestId: 1 };
|
|
25935
|
+
let pending = "";
|
|
25936
|
+
let receivedBytes = 0;
|
|
25937
|
+
const fail = (cause) => response.reject(
|
|
25938
|
+
cause instanceof AcpExecutionError ? cause : new AcpExecutionError(
|
|
25939
|
+
"Saved Codex history could not be read.",
|
|
25940
|
+
{ cause },
|
|
25941
|
+
"native_history_unavailable"
|
|
25942
|
+
)
|
|
25943
|
+
);
|
|
25944
|
+
const send2 = (message) => {
|
|
25945
|
+
child.stdin.write(`${JSON.stringify(message)}
|
|
25946
|
+
`);
|
|
25947
|
+
};
|
|
25948
|
+
const onData = (chunk) => {
|
|
25195
25949
|
try {
|
|
25196
|
-
|
|
25197
|
-
|
|
25198
|
-
|
|
25199
|
-
|
|
25200
|
-
|
|
25950
|
+
receivedBytes += Buffer.byteLength(chunk);
|
|
25951
|
+
if (receivedBytes > 32 * 1024 * 1024)
|
|
25952
|
+
throw new AcpExecutionError(
|
|
25953
|
+
"This saved conversation is too large to preview.",
|
|
25954
|
+
{},
|
|
25955
|
+
"native_history_too_large"
|
|
25201
25956
|
);
|
|
25957
|
+
pending += chunk;
|
|
25958
|
+
let newline = pending.indexOf("\n");
|
|
25959
|
+
while (newline >= 0) {
|
|
25960
|
+
const line = pending.slice(0, newline);
|
|
25961
|
+
pending = pending.slice(newline + 1);
|
|
25962
|
+
newline = pending.indexOf("\n");
|
|
25963
|
+
if (line.trim().length === 0) continue;
|
|
25964
|
+
const value = JSON.parse(line);
|
|
25965
|
+
const message = responseSchema.parse(value);
|
|
25966
|
+
if (!("id" in message)) continue;
|
|
25967
|
+
if (message.id !== state.requestId)
|
|
25968
|
+
throw new AcpExecutionError(
|
|
25969
|
+
"Codex returned an invalid history response.",
|
|
25970
|
+
{},
|
|
25971
|
+
"invalid_native_session_response"
|
|
25972
|
+
);
|
|
25973
|
+
if ("error" in message) {
|
|
25974
|
+
fail(
|
|
25975
|
+
new AcpExecutionError(
|
|
25976
|
+
"Saved Codex history could not be read.",
|
|
25977
|
+
{ cause: message.error },
|
|
25978
|
+
"native_history_unavailable"
|
|
25979
|
+
)
|
|
25980
|
+
);
|
|
25981
|
+
return;
|
|
25982
|
+
}
|
|
25983
|
+
switch (state.kind) {
|
|
25984
|
+
case "initializing":
|
|
25985
|
+
state = { kind: "metadata", requestId: 2 };
|
|
25986
|
+
send2({ method: "initialized", params: {} });
|
|
25987
|
+
send2({
|
|
25988
|
+
id: state.requestId,
|
|
25989
|
+
method: "thread/read",
|
|
25990
|
+
params: { threadId: nativeSessionId, includeTurns: false }
|
|
25991
|
+
});
|
|
25992
|
+
break;
|
|
25993
|
+
case "metadata": {
|
|
25994
|
+
const { thread } = threadSchema.parse(message.result);
|
|
25995
|
+
state = { kind: "turns", requestId: 3, thread };
|
|
25996
|
+
send2({
|
|
25997
|
+
id: state.requestId,
|
|
25998
|
+
method: "thread/turns/list",
|
|
25999
|
+
params: {
|
|
26000
|
+
threadId: nativeSessionId,
|
|
26001
|
+
limit: SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT,
|
|
26002
|
+
sortDirection: "desc",
|
|
26003
|
+
itemsView: "summary"
|
|
26004
|
+
}
|
|
26005
|
+
});
|
|
26006
|
+
break;
|
|
26007
|
+
}
|
|
26008
|
+
case "turns":
|
|
26009
|
+
response.resolve(decodeHistory(state.thread, message.result));
|
|
26010
|
+
return;
|
|
26011
|
+
default: {
|
|
26012
|
+
const unhandled = state;
|
|
26013
|
+
throw new Error(`Unknown history read state: ${String(unhandled)}`);
|
|
26014
|
+
}
|
|
26015
|
+
}
|
|
25202
26016
|
}
|
|
25203
|
-
|
|
25204
|
-
|
|
25205
|
-
|
|
25206
|
-
|
|
26017
|
+
} catch (cause) {
|
|
26018
|
+
fail(cause);
|
|
26019
|
+
}
|
|
26020
|
+
};
|
|
26021
|
+
const abort = () => response.reject(signal.reason);
|
|
26022
|
+
const onExit = () => fail(
|
|
26023
|
+
new AcpExecutionError(
|
|
26024
|
+
"Codex stopped before its saved history was available.",
|
|
26025
|
+
{},
|
|
26026
|
+
"native_history_unavailable"
|
|
26027
|
+
)
|
|
26028
|
+
);
|
|
26029
|
+
const timeout = setTimeout(
|
|
26030
|
+
() => fail(
|
|
26031
|
+
new AcpExecutionError(
|
|
26032
|
+
"Reading saved Codex history timed out.",
|
|
26033
|
+
{},
|
|
26034
|
+
"native_history_timeout"
|
|
26035
|
+
)
|
|
26036
|
+
),
|
|
26037
|
+
15e3
|
|
26038
|
+
);
|
|
26039
|
+
child.stdout.setEncoding("utf8");
|
|
26040
|
+
child.stdout.on("data", onData);
|
|
26041
|
+
child.stdin.on("error", fail);
|
|
26042
|
+
child.on("error", fail);
|
|
26043
|
+
child.on("exit", onExit);
|
|
26044
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
26045
|
+
try {
|
|
26046
|
+
if (signal.aborted) abort();
|
|
26047
|
+
else
|
|
26048
|
+
send2({
|
|
26049
|
+
id: 1,
|
|
26050
|
+
method: "initialize",
|
|
26051
|
+
params: { clientInfo: { name: "mobius_history", version: "1.0.0" } }
|
|
26052
|
+
});
|
|
26053
|
+
return await response.promise;
|
|
26054
|
+
} finally {
|
|
26055
|
+
clearTimeout(timeout);
|
|
26056
|
+
signal.removeEventListener("abort", abort);
|
|
26057
|
+
child.stdout.removeListener("data", onData);
|
|
26058
|
+
if (child.pid !== void 0) await stopProcessTree(child);
|
|
26059
|
+
child.stdin.removeListener("error", fail);
|
|
26060
|
+
child.removeListener("error", fail);
|
|
26061
|
+
child.removeListener("exit", onExit);
|
|
26062
|
+
}
|
|
26063
|
+
}
|
|
26064
|
+
|
|
26065
|
+
// src/native-sessions/service.ts
|
|
26066
|
+
var NativeSessionService = class {
|
|
26067
|
+
#entries = /* @__PURE__ */ new Map();
|
|
26068
|
+
#cursors = /* @__PURE__ */ new Map();
|
|
26069
|
+
#config;
|
|
26070
|
+
#directories;
|
|
26071
|
+
#sessions;
|
|
26072
|
+
#audit;
|
|
26073
|
+
constructor(config2, directories, sessions, audit) {
|
|
26074
|
+
this.#config = config2;
|
|
26075
|
+
this.#directories = directories;
|
|
26076
|
+
this.#sessions = sessions;
|
|
26077
|
+
this.#audit = audit;
|
|
26078
|
+
}
|
|
26079
|
+
execute = async (command, signal) => {
|
|
26080
|
+
signal.throwIfAborted();
|
|
26081
|
+
const cwd = await this.#directories.resolve(
|
|
26082
|
+
command.bindingId,
|
|
26083
|
+
command.directoryId,
|
|
26084
|
+
signal
|
|
26085
|
+
);
|
|
26086
|
+
const additionalDirectories = await this.#directories.resolveMany(
|
|
26087
|
+
command.bindingId,
|
|
26088
|
+
command.additionalDirectoryIds,
|
|
26089
|
+
signal
|
|
26090
|
+
);
|
|
26091
|
+
signal.throwIfAborted();
|
|
26092
|
+
const options = {
|
|
26093
|
+
additionalDirectories,
|
|
26094
|
+
agent: this.#config.catalog.find(command.agentId),
|
|
26095
|
+
cwd,
|
|
26096
|
+
sessionId: command.sessionId,
|
|
26097
|
+
signal
|
|
26098
|
+
};
|
|
26099
|
+
const prepared = await this.#sessions.prepareSession(options);
|
|
26100
|
+
if (!prepared.capabilities.listSessions)
|
|
26101
|
+
throw new AcpExecutionError(
|
|
26102
|
+
"This Agent does not support native session listing",
|
|
26103
|
+
{},
|
|
26104
|
+
"native_session_unsupported"
|
|
26105
|
+
);
|
|
26106
|
+
const scope = JSON.stringify([
|
|
26107
|
+
command.agentId,
|
|
26108
|
+
command.bindingId,
|
|
26109
|
+
command.sessionId,
|
|
26110
|
+
cwd
|
|
26111
|
+
]);
|
|
26112
|
+
const envelope2 = {
|
|
26113
|
+
kind: "native.session.result",
|
|
26114
|
+
protocolVersion: 1,
|
|
26115
|
+
requestId: command.requestId,
|
|
26116
|
+
sessionId: command.sessionId
|
|
26117
|
+
};
|
|
26118
|
+
if (command.action === "list") {
|
|
26119
|
+
let cursor = null;
|
|
26120
|
+
if (command.cursor !== null) {
|
|
26121
|
+
const known = this.#cursors.get(command.cursor);
|
|
26122
|
+
if (known?.scope !== scope)
|
|
26123
|
+
throw new AcpExecutionError(
|
|
26124
|
+
"Refresh the native session list before continuing",
|
|
26125
|
+
{},
|
|
26126
|
+
"native_session_cursor_expired"
|
|
26127
|
+
);
|
|
26128
|
+
cursor = known.cursor;
|
|
25207
26129
|
}
|
|
25208
|
-
|
|
25209
|
-
|
|
25210
|
-
|
|
25211
|
-
|
|
25212
|
-
|
|
26130
|
+
const page = await this.#sessions.listNativeSessions(options, cursor);
|
|
26131
|
+
const entries = [];
|
|
26132
|
+
for (const info of page.sessions) {
|
|
26133
|
+
const authorized = await this.authorizeEntry(command, options, info);
|
|
26134
|
+
if (authorized === null) continue;
|
|
26135
|
+
const entryId = randomUUID3();
|
|
26136
|
+
if (this.#entries.size >= 5e3) this.#entries.clear();
|
|
26137
|
+
this.#entries.set(entryId, {
|
|
26138
|
+
scope,
|
|
26139
|
+
nativeSessionId: info.sessionId,
|
|
26140
|
+
cwd: authorized.cwd,
|
|
26141
|
+
additionalDirectories: authorized.additionalDirectories
|
|
26142
|
+
});
|
|
26143
|
+
entries.push({
|
|
26144
|
+
entryId,
|
|
26145
|
+
title: info.title ?? "Untitled session",
|
|
26146
|
+
directoryId: authorized.directoryId,
|
|
26147
|
+
directoryLabel: authorized.directoryLabel,
|
|
26148
|
+
updatedAt: info.updatedAt ?? null,
|
|
26149
|
+
additionalDirectories: authorized.additionalEntries
|
|
26150
|
+
});
|
|
26151
|
+
}
|
|
26152
|
+
let nextCursor = null;
|
|
26153
|
+
if (page.nextCursor != null) {
|
|
26154
|
+
if (page.nextCursor === cursor)
|
|
26155
|
+
throw new AcpExecutionError(
|
|
26156
|
+
"The Agent returned a repeated session cursor",
|
|
26157
|
+
{},
|
|
26158
|
+
"invalid_native_session_response"
|
|
26159
|
+
);
|
|
26160
|
+
nextCursor = randomUUID3();
|
|
26161
|
+
if (this.#cursors.size >= 500) this.#cursors.clear();
|
|
26162
|
+
this.#cursors.set(nextCursor, { scope, cursor: page.nextCursor });
|
|
26163
|
+
}
|
|
26164
|
+
this.record(command, "native_sessions_listed");
|
|
26165
|
+
return {
|
|
26166
|
+
...envelope2,
|
|
26167
|
+
action: "list",
|
|
26168
|
+
capabilities: prepared.capabilities,
|
|
26169
|
+
entries,
|
|
26170
|
+
nextCursor
|
|
26171
|
+
};
|
|
26172
|
+
}
|
|
26173
|
+
const selected = this.#entries.get(command.entryId);
|
|
26174
|
+
if (selected?.scope !== scope)
|
|
26175
|
+
throw new AcpExecutionError(
|
|
26176
|
+
"Select a session from a fresh native session list",
|
|
26177
|
+
{},
|
|
26178
|
+
"native_session_not_found"
|
|
26179
|
+
);
|
|
26180
|
+
const target = await this.resolveTarget(command, options, selected);
|
|
26181
|
+
if (command.action === "delete") {
|
|
26182
|
+
if (!prepared.capabilities.deleteSession)
|
|
26183
|
+
throw new AcpExecutionError(
|
|
26184
|
+
"This Agent does not support native session deletion",
|
|
26185
|
+
{},
|
|
26186
|
+
"native_session_unsupported"
|
|
26187
|
+
);
|
|
26188
|
+
signal.throwIfAborted();
|
|
26189
|
+
this.record(command, "native_session_delete_authorized");
|
|
26190
|
+
const deletedSessionIds = await this.#sessions.deleteNativeSession(
|
|
26191
|
+
options,
|
|
26192
|
+
target.info.sessionId
|
|
26193
|
+
);
|
|
26194
|
+
this.record(command, "native_session_deleted");
|
|
26195
|
+
return {
|
|
26196
|
+
...envelope2,
|
|
26197
|
+
action: "delete",
|
|
26198
|
+
entryId: command.entryId,
|
|
26199
|
+
deletedSessionIds
|
|
26200
|
+
};
|
|
26201
|
+
}
|
|
26202
|
+
if (command.action === "import" && !prepared.capabilities.loadSession && !prepared.capabilities.resumeSession)
|
|
26203
|
+
throw new AcpExecutionError(
|
|
26204
|
+
"This Agent cannot import native sessions",
|
|
26205
|
+
{},
|
|
26206
|
+
"native_session_unsupported"
|
|
26207
|
+
);
|
|
26208
|
+
if (command.action === "fork" && !prepared.capabilities.unstableForkSession)
|
|
26209
|
+
throw new AcpExecutionError(
|
|
26210
|
+
"This Agent does not support session forking",
|
|
26211
|
+
{},
|
|
26212
|
+
"native_session_unsupported"
|
|
26213
|
+
);
|
|
26214
|
+
if (target.additionalDirectories.length > 0 && !prepared.capabilities.additionalDirectories)
|
|
26215
|
+
throw new AcpExecutionError(
|
|
26216
|
+
"This Agent cannot restore additional working directories",
|
|
26217
|
+
{},
|
|
26218
|
+
"native_session_unsupported"
|
|
26219
|
+
);
|
|
26220
|
+
const opening = this.#sessions.openNativeSession(
|
|
26221
|
+
{
|
|
26222
|
+
...options,
|
|
26223
|
+
cwd: target.cwd,
|
|
26224
|
+
sessionId: command.targetSessionId,
|
|
26225
|
+
additionalDirectories: target.additionalDirectories
|
|
26226
|
+
},
|
|
26227
|
+
{ kind: command.action, nativeSessionId: target.info.sessionId }
|
|
26228
|
+
);
|
|
26229
|
+
const opened = await opening.catch(async (cause) => {
|
|
26230
|
+
signal.throwIfAborted();
|
|
26231
|
+
if (command.action !== "import" || options.agent.id !== "codex" || !(cause instanceof AcpExecutionError) || cause.code !== "acp_execution_failed")
|
|
26232
|
+
throw cause;
|
|
26233
|
+
const snapshot = await readCodexHistory(
|
|
26234
|
+
options.agent,
|
|
26235
|
+
target.cwd,
|
|
26236
|
+
target.info.sessionId,
|
|
26237
|
+
signal
|
|
26238
|
+
);
|
|
26239
|
+
const resolved = await this.#directories.identify(
|
|
26240
|
+
command.bindingId,
|
|
26241
|
+
snapshot.cwd,
|
|
26242
|
+
signal
|
|
26243
|
+
);
|
|
26244
|
+
if (snapshot.nativeSessionId !== target.info.sessionId || resolved.path !== target.cwd)
|
|
26245
|
+
throw new AcpExecutionError(
|
|
26246
|
+
"Codex returned history for a different session or workspace.",
|
|
26247
|
+
{ cause },
|
|
26248
|
+
"invalid_native_session_response"
|
|
26249
|
+
);
|
|
26250
|
+
signal.throwIfAborted();
|
|
26251
|
+
this.record(command, "native_session_previewed");
|
|
26252
|
+
return { kind: "preview", history: snapshot.history };
|
|
26253
|
+
});
|
|
26254
|
+
if ("kind" in opened)
|
|
26255
|
+
return {
|
|
26256
|
+
...envelope2,
|
|
26257
|
+
action: "preview",
|
|
26258
|
+
entryId: command.entryId,
|
|
26259
|
+
reason: "continuation_unavailable",
|
|
26260
|
+
title: target.info.title ?? "Untitled session",
|
|
26261
|
+
history: opened.history
|
|
26262
|
+
};
|
|
26263
|
+
signal.throwIfAborted();
|
|
26264
|
+
const ready = {
|
|
26265
|
+
additionalDirectories: target.additionalEntries,
|
|
26266
|
+
agentId: command.agentId,
|
|
26267
|
+
agentName: opened.prepared.agentName,
|
|
26268
|
+
agentVersion: opened.prepared.agentVersion,
|
|
26269
|
+
capabilities: opened.prepared.capabilities,
|
|
26270
|
+
commands: opened.prepared.commands,
|
|
26271
|
+
configOptions: opened.prepared.configOptions,
|
|
26272
|
+
directoryId: target.directoryId,
|
|
26273
|
+
directoryLabel: target.directoryLabel,
|
|
26274
|
+
kind: "session.ready",
|
|
26275
|
+
protocolVersion: 1,
|
|
26276
|
+
requestId: command.requestId,
|
|
26277
|
+
restored: true,
|
|
26278
|
+
sessionId: opened.sessionId
|
|
26279
|
+
};
|
|
26280
|
+
this.record(
|
|
26281
|
+
command,
|
|
26282
|
+
command.action === "fork" ? "native_session_forked" : "native_session_imported"
|
|
26283
|
+
);
|
|
26284
|
+
return {
|
|
26285
|
+
...envelope2,
|
|
26286
|
+
action: command.action,
|
|
26287
|
+
ready,
|
|
26288
|
+
title: target.info.title ?? "Untitled session",
|
|
26289
|
+
history: opened.history
|
|
26290
|
+
};
|
|
26291
|
+
};
|
|
26292
|
+
authorizeEntry = async (command, options, info) => {
|
|
26293
|
+
try {
|
|
26294
|
+
const primary = await this.#directories.identify(
|
|
26295
|
+
command.bindingId,
|
|
26296
|
+
info.cwd,
|
|
26297
|
+
options.signal
|
|
26298
|
+
);
|
|
26299
|
+
const additionalDirectories = [];
|
|
26300
|
+
const additionalEntries = [];
|
|
26301
|
+
const paths = /* @__PURE__ */ new Set([primary.path]);
|
|
26302
|
+
for (const path2 of info.additionalDirectories) {
|
|
26303
|
+
const directory = await this.#directories.identify(
|
|
26304
|
+
command.bindingId,
|
|
26305
|
+
path2,
|
|
26306
|
+
options.signal
|
|
26307
|
+
);
|
|
26308
|
+
if (paths.has(directory.path))
|
|
26309
|
+
throw new LocalAuthorizationError(
|
|
26310
|
+
"Native session roots must be distinct"
|
|
26311
|
+
);
|
|
26312
|
+
paths.add(directory.path);
|
|
26313
|
+
additionalDirectories.push(directory.path);
|
|
26314
|
+
additionalEntries.push({
|
|
26315
|
+
directoryId: directory.directoryId,
|
|
26316
|
+
name: directory.name
|
|
26317
|
+
});
|
|
26318
|
+
}
|
|
26319
|
+
return {
|
|
26320
|
+
info,
|
|
26321
|
+
cwd: primary.path,
|
|
26322
|
+
directoryId: primary.directoryId,
|
|
26323
|
+
directoryLabel: primary.label,
|
|
26324
|
+
additionalDirectories,
|
|
26325
|
+
additionalEntries
|
|
26326
|
+
};
|
|
26327
|
+
} catch (error61) {
|
|
26328
|
+
options.signal.throwIfAborted();
|
|
26329
|
+
if (error61 instanceof LocalAuthorizationError) return null;
|
|
26330
|
+
throw error61;
|
|
26331
|
+
}
|
|
26332
|
+
};
|
|
26333
|
+
resolveTarget = async (command, options, selected) => {
|
|
26334
|
+
let cursor = null;
|
|
26335
|
+
const visited = /* @__PURE__ */ new Set();
|
|
26336
|
+
for (let index = 0; index < 100; index += 1) {
|
|
26337
|
+
const page = await this.#sessions.listNativeSessions(options, cursor);
|
|
26338
|
+
const info = page.sessions.find(
|
|
26339
|
+
(entry) => entry.sessionId === selected.nativeSessionId
|
|
25213
26340
|
);
|
|
26341
|
+
if (info !== void 0) {
|
|
26342
|
+
const target = await this.authorizeEntry(command, options, info);
|
|
26343
|
+
if (target === null)
|
|
26344
|
+
throw new LocalAuthorizationError(
|
|
26345
|
+
"The selected native session is not authorized"
|
|
26346
|
+
);
|
|
26347
|
+
if (target.cwd !== selected.cwd || target.additionalDirectories.length !== selected.additionalDirectories.length || target.additionalDirectories.some(
|
|
26348
|
+
(path2, index2) => path2 !== selected.additionalDirectories[index2]
|
|
26349
|
+
))
|
|
26350
|
+
throw new AcpExecutionError(
|
|
26351
|
+
"This session's directory changed. Refresh the list before continuing.",
|
|
26352
|
+
{},
|
|
26353
|
+
"native_session_target_changed"
|
|
26354
|
+
);
|
|
26355
|
+
return target;
|
|
26356
|
+
}
|
|
26357
|
+
cursor = page.nextCursor ?? null;
|
|
26358
|
+
if (cursor === null) break;
|
|
26359
|
+
if (visited.has(cursor))
|
|
26360
|
+
throw new AcpExecutionError(
|
|
26361
|
+
"The Agent returned a repeated session cursor",
|
|
26362
|
+
{},
|
|
26363
|
+
"invalid_native_session_response"
|
|
26364
|
+
);
|
|
26365
|
+
visited.add(cursor);
|
|
25214
26366
|
}
|
|
26367
|
+
throw new AcpExecutionError(
|
|
26368
|
+
"The selected native session no longer exists. Refresh the list.",
|
|
26369
|
+
{},
|
|
26370
|
+
"native_session_not_found"
|
|
26371
|
+
);
|
|
26372
|
+
};
|
|
26373
|
+
record = (command, event) => {
|
|
26374
|
+
this.#audit.record({
|
|
26375
|
+
commandId: command.requestId,
|
|
26376
|
+
sessionId: command.sessionId,
|
|
26377
|
+
event,
|
|
26378
|
+
details: { agentId: command.agentId }
|
|
26379
|
+
});
|
|
25215
26380
|
};
|
|
25216
26381
|
};
|
|
25217
26382
|
|
|
@@ -25228,7 +26393,7 @@ var RelayConnectionError = class extends Error {
|
|
|
25228
26393
|
};
|
|
25229
26394
|
function connectRelay(url2, signal) {
|
|
25230
26395
|
signal.throwIfAborted();
|
|
25231
|
-
return new Promise((
|
|
26396
|
+
return new Promise((resolve5, reject) => {
|
|
25232
26397
|
const socket = new WebSocket(url2, {
|
|
25233
26398
|
dispatcher: environmentProxyDispatcher
|
|
25234
26399
|
});
|
|
@@ -25281,7 +26446,7 @@ function connectRelay(url2, signal) {
|
|
|
25281
26446
|
}
|
|
25282
26447
|
finished = true;
|
|
25283
26448
|
cleanup();
|
|
25284
|
-
|
|
26449
|
+
resolve5(socket);
|
|
25285
26450
|
};
|
|
25286
26451
|
function onTimeout() {
|
|
25287
26452
|
fail(
|
|
@@ -25302,7 +26467,7 @@ function connectRelay(url2, signal) {
|
|
|
25302
26467
|
}
|
|
25303
26468
|
|
|
25304
26469
|
// src/relay-connection/liveness.ts
|
|
25305
|
-
import { randomUUID as
|
|
26470
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
25306
26471
|
var HEARTBEAT_ACK_TIMEOUT_MILLISECONDS = 1e4;
|
|
25307
26472
|
var HEARTBEAT_INTERVAL_MILLISECONDS = 2e4;
|
|
25308
26473
|
var RelayLivenessState = class {
|
|
@@ -25393,7 +26558,7 @@ var RelayConnectionLiveness = class {
|
|
|
25393
26558
|
}
|
|
25394
26559
|
throw new Error("Heartbeat was scheduled in an invalid state");
|
|
25395
26560
|
}
|
|
25396
|
-
const heartbeatId =
|
|
26561
|
+
const heartbeatId = randomUUID4();
|
|
25397
26562
|
this.#state = new AwaitingHeartbeatAckState(
|
|
25398
26563
|
heartbeatId,
|
|
25399
26564
|
this.#timer.schedule(
|
|
@@ -25720,15 +26885,16 @@ function reportOperationFailure(socket, requestId, sessionId, error61) {
|
|
|
25720
26885
|
})
|
|
25721
26886
|
);
|
|
25722
26887
|
}
|
|
25723
|
-
async function resolveSessionDirectories(directories, bindingId, directoryId2, additionalDirectoryIds) {
|
|
25724
|
-
const cwd = await directories.resolve(bindingId, directoryId2);
|
|
26888
|
+
async function resolveSessionDirectories(directories, bindingId, directoryId2, additionalDirectoryIds, signal) {
|
|
26889
|
+
const cwd = await directories.resolve(bindingId, directoryId2, signal);
|
|
25725
26890
|
const additionalDirectories = [];
|
|
25726
26891
|
const additionalDirectoryEntries = [];
|
|
25727
26892
|
const unique = /* @__PURE__ */ new Set([cwd]);
|
|
25728
26893
|
for (const additionalDirectoryId of additionalDirectoryIds) {
|
|
25729
26894
|
const directory = await directories.resolve(
|
|
25730
26895
|
bindingId,
|
|
25731
|
-
additionalDirectoryId
|
|
26896
|
+
additionalDirectoryId,
|
|
26897
|
+
signal
|
|
25732
26898
|
);
|
|
25733
26899
|
if (unique.has(directory)) {
|
|
25734
26900
|
throw new LocalAuthorizationError(
|
|
@@ -25748,11 +26914,12 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
|
|
|
25748
26914
|
additionalDirectoryEntries
|
|
25749
26915
|
);
|
|
25750
26916
|
}
|
|
25751
|
-
async function executeWorkspaceList(socket, command, directories, audit) {
|
|
26917
|
+
async function executeWorkspaceList(socket, command, directories, audit, signal) {
|
|
25752
26918
|
try {
|
|
25753
26919
|
const listing = await directories.list(
|
|
25754
26920
|
command.bindingId,
|
|
25755
|
-
command.directoryId
|
|
26921
|
+
command.directoryId,
|
|
26922
|
+
signal
|
|
25756
26923
|
);
|
|
25757
26924
|
audit.record({
|
|
25758
26925
|
commandId: command.requestId,
|
|
@@ -25782,7 +26949,8 @@ async function executeSessionPrepare(socket, command, config2, directories, audi
|
|
|
25782
26949
|
directories,
|
|
25783
26950
|
command.bindingId,
|
|
25784
26951
|
command.directoryId,
|
|
25785
|
-
command.additionalDirectoryIds
|
|
26952
|
+
command.additionalDirectoryIds,
|
|
26953
|
+
signal
|
|
25786
26954
|
);
|
|
25787
26955
|
const agent = config2.catalog.find(command.agentId);
|
|
25788
26956
|
const prepared = await sessions.prepareSession({
|
|
@@ -25794,7 +26962,8 @@ async function executeSessionPrepare(socket, command, config2, directories, audi
|
|
|
25794
26962
|
});
|
|
25795
26963
|
const listing = await directories.list(
|
|
25796
26964
|
command.bindingId,
|
|
25797
|
-
command.directoryId
|
|
26965
|
+
command.directoryId,
|
|
26966
|
+
signal
|
|
25798
26967
|
);
|
|
25799
26968
|
audit.record({
|
|
25800
26969
|
commandId: command.requestId,
|
|
@@ -25830,7 +26999,8 @@ async function executeSessionConfigure(socket, command, config2, directories, au
|
|
|
25830
26999
|
directories,
|
|
25831
27000
|
command.bindingId,
|
|
25832
27001
|
command.directoryId,
|
|
25833
|
-
command.additionalDirectoryIds
|
|
27002
|
+
command.additionalDirectoryIds,
|
|
27003
|
+
signal
|
|
25834
27004
|
);
|
|
25835
27005
|
const configOptions = await sessions.configureSession({
|
|
25836
27006
|
additionalDirectories: resolved.additionalDirectories,
|
|
@@ -25869,10 +27039,11 @@ async function executePrompt(socket, command, config2, directories, audit, sessi
|
|
|
25869
27039
|
directories,
|
|
25870
27040
|
command.bindingId,
|
|
25871
27041
|
command.directoryId,
|
|
25872
|
-
command.additionalDirectoryIds
|
|
27042
|
+
command.additionalDirectoryIds,
|
|
27043
|
+
signal
|
|
25873
27044
|
);
|
|
25874
27045
|
const agent = config2.catalog.find(command.agentId);
|
|
25875
|
-
const processAttemptId =
|
|
27046
|
+
const processAttemptId = randomUUID5();
|
|
25876
27047
|
audit.record({
|
|
25877
27048
|
commandId: command.commandId,
|
|
25878
27049
|
event: "session_authorized",
|
|
@@ -25970,262 +27141,383 @@ function waitForRelayRetry(signal, timer) {
|
|
|
25970
27141
|
if (signal.aborted) {
|
|
25971
27142
|
return Promise.resolve();
|
|
25972
27143
|
}
|
|
25973
|
-
return new Promise((
|
|
27144
|
+
return new Promise((resolve5) => {
|
|
25974
27145
|
const retry = timer.schedule(finish, RELAY_RECONNECT_DELAY_MILLISECONDS);
|
|
25975
27146
|
function finish() {
|
|
25976
27147
|
retry.cancel();
|
|
25977
27148
|
signal.removeEventListener("abort", finish);
|
|
25978
|
-
|
|
27149
|
+
resolve5();
|
|
25979
27150
|
}
|
|
25980
27151
|
signal.addEventListener("abort", finish, { once: true });
|
|
25981
27152
|
});
|
|
25982
27153
|
}
|
|
25983
|
-
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, signal, timer) {
|
|
27154
|
+
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, signal, timer) {
|
|
25984
27155
|
const relayUrl = new URL(config2.relayUrl);
|
|
25985
27156
|
relayUrl.searchParams.set("liveness", "1");
|
|
25986
27157
|
const socket = await connectRelay(relayUrl, signal);
|
|
25987
27158
|
const activeTurns = /* @__PURE__ */ new Map();
|
|
25988
27159
|
const connectionController = new AbortController();
|
|
27160
|
+
const nativeRequests = /* @__PURE__ */ new Map();
|
|
25989
27161
|
sessions.setObserver(new DaemonAcpObserver(socket));
|
|
25990
27162
|
installationObserver.connect(socket);
|
|
25991
|
-
|
|
25992
|
-
|
|
25993
|
-
|
|
25994
|
-
|
|
25995
|
-
|
|
25996
|
-
|
|
25997
|
-
|
|
25998
|
-
|
|
25999
|
-
|
|
26000
|
-
|
|
26001
|
-
|
|
26002
|
-
|
|
26003
|
-
turn.
|
|
26004
|
-
|
|
26005
|
-
|
|
26006
|
-
|
|
26007
|
-
|
|
26008
|
-
|
|
26009
|
-
|
|
26010
|
-
|
|
26011
|
-
|
|
26012
|
-
|
|
26013
|
-
|
|
26014
|
-
|
|
26015
|
-
|
|
26016
|
-
|
|
26017
|
-
|
|
26018
|
-
|
|
26019
|
-
|
|
26020
|
-
|
|
26021
|
-
|
|
26022
|
-
|
|
26023
|
-
|
|
26024
|
-
|
|
26025
|
-
|
|
26026
|
-
};
|
|
26027
|
-
const refreshConnection = () => {
|
|
26028
|
-
socket.close(1e3, "Refreshing idle relay connection");
|
|
26029
|
-
resolveConnection();
|
|
26030
|
-
};
|
|
26031
|
-
const connectionLiveness = new RelayConnectionLiveness(timer, {
|
|
26032
|
-
send: (message) => send(socket, message),
|
|
26033
|
-
unresponsive: () => {
|
|
26034
|
-
socket.close(4001, "Relay liveness check timed out");
|
|
27163
|
+
try {
|
|
27164
|
+
await new Promise((resolve5, reject) => {
|
|
27165
|
+
let finished = false;
|
|
27166
|
+
const cleanup = () => {
|
|
27167
|
+
connectionRefresh.close();
|
|
27168
|
+
connectionLiveness.close();
|
|
27169
|
+
signal.removeEventListener("abort", stop);
|
|
27170
|
+
socket.removeEventListener("close", handleClose);
|
|
27171
|
+
socket.removeEventListener("error", handleError);
|
|
27172
|
+
socket.removeEventListener("message", handleMessage);
|
|
27173
|
+
installationObserver.disconnect(socket);
|
|
27174
|
+
connectionController.abort();
|
|
27175
|
+
for (const turn of activeTurns.values()) {
|
|
27176
|
+
turn.abortConnection();
|
|
27177
|
+
}
|
|
27178
|
+
activeTurns.clear();
|
|
27179
|
+
};
|
|
27180
|
+
const resolveConnection = () => {
|
|
27181
|
+
if (finished) {
|
|
27182
|
+
return;
|
|
27183
|
+
}
|
|
27184
|
+
finished = true;
|
|
27185
|
+
cleanup();
|
|
27186
|
+
resolve5();
|
|
27187
|
+
};
|
|
27188
|
+
const rejectConnection = () => {
|
|
27189
|
+
if (finished) {
|
|
27190
|
+
return;
|
|
27191
|
+
}
|
|
27192
|
+
finished = true;
|
|
27193
|
+
cleanup();
|
|
27194
|
+
reject(new Error("Relay WebSocket failed"));
|
|
27195
|
+
};
|
|
27196
|
+
const stop = () => {
|
|
27197
|
+
socket.close(1e3, "Daemon stopped");
|
|
26035
27198
|
resolveConnection();
|
|
26036
|
-
}
|
|
26037
|
-
|
|
26038
|
-
|
|
26039
|
-
timer,
|
|
26040
|
-
() => activeTurns.size === 0,
|
|
26041
|
-
refreshConnection
|
|
26042
|
-
);
|
|
26043
|
-
signal.addEventListener("abort", stop, { once: true });
|
|
26044
|
-
const handleClose = () => {
|
|
26045
|
-
resolveConnection();
|
|
26046
|
-
};
|
|
26047
|
-
const handleError = () => {
|
|
26048
|
-
if (signal.aborted) {
|
|
27199
|
+
};
|
|
27200
|
+
const refreshConnection = () => {
|
|
27201
|
+
socket.close(1e3, "Refreshing idle relay connection");
|
|
26049
27202
|
resolveConnection();
|
|
26050
|
-
|
|
26051
|
-
|
|
26052
|
-
|
|
26053
|
-
|
|
26054
|
-
|
|
26055
|
-
|
|
26056
|
-
|
|
26057
|
-
|
|
26058
|
-
|
|
26059
|
-
|
|
26060
|
-
|
|
26061
|
-
|
|
26062
|
-
|
|
26063
|
-
|
|
26064
|
-
|
|
26065
|
-
|
|
27203
|
+
};
|
|
27204
|
+
const connectionLiveness = new RelayConnectionLiveness(timer, {
|
|
27205
|
+
send: (message) => send(socket, message),
|
|
27206
|
+
unresponsive: () => {
|
|
27207
|
+
socket.close(4001, "Relay liveness check timed out");
|
|
27208
|
+
resolveConnection();
|
|
27209
|
+
}
|
|
27210
|
+
});
|
|
27211
|
+
const connectionRefresh = new RelayConnectionRefresh(
|
|
27212
|
+
timer,
|
|
27213
|
+
() => activeTurns.size === 0,
|
|
27214
|
+
refreshConnection
|
|
27215
|
+
);
|
|
27216
|
+
signal.addEventListener("abort", stop, { once: true });
|
|
27217
|
+
const handleClose = () => {
|
|
27218
|
+
resolveConnection();
|
|
27219
|
+
};
|
|
27220
|
+
const handleError = () => {
|
|
27221
|
+
if (signal.aborted) {
|
|
27222
|
+
resolveConnection();
|
|
26066
27223
|
return;
|
|
26067
27224
|
}
|
|
26068
|
-
|
|
26069
|
-
|
|
26070
|
-
|
|
26071
|
-
|
|
27225
|
+
rejectConnection();
|
|
27226
|
+
};
|
|
27227
|
+
const handleMessage = (event) => {
|
|
27228
|
+
const encoded = event.data;
|
|
27229
|
+
if (typeof encoded !== "string") {
|
|
27230
|
+
socket.close(4003, "Text message required");
|
|
27231
|
+
rejectConnection();
|
|
26072
27232
|
return;
|
|
26073
27233
|
}
|
|
26074
|
-
|
|
26075
|
-
const
|
|
26076
|
-
|
|
26077
|
-
|
|
26078
|
-
|
|
26079
|
-
|
|
27234
|
+
try {
|
|
27235
|
+
const kind = decodeMessageKind(encoded);
|
|
27236
|
+
if (kind === NATIVE_SESSION_CANCEL_KIND) {
|
|
27237
|
+
const command2 = decodeNativeSessionCancel(encoded);
|
|
27238
|
+
const pending = nativeRequests.get(command2.requestId);
|
|
27239
|
+
if (pending?.sessionId === command2.sessionId)
|
|
27240
|
+
pending.controller.abort(
|
|
27241
|
+
new AcpExecutionError(
|
|
27242
|
+
"Native session operation cancelled",
|
|
27243
|
+
{},
|
|
27244
|
+
"native_session_cancelled"
|
|
27245
|
+
)
|
|
27246
|
+
);
|
|
27247
|
+
return;
|
|
27248
|
+
}
|
|
27249
|
+
if (kind === NATIVE_SESSION_REQUEST_KIND) {
|
|
27250
|
+
const command2 = decodeNativeSessionCommand(encoded);
|
|
27251
|
+
const previous = [...nativeRequests.values()].filter(
|
|
27252
|
+
(request) => request.agentId === command2.agentId
|
|
26080
27253
|
);
|
|
27254
|
+
if (nativeRequests.has(command2.requestId) || nativeRequests.size >= 4 || previous.some((request) => !request.controller.signal.aborted)) {
|
|
27255
|
+
reportOperationFailure(
|
|
27256
|
+
socket,
|
|
27257
|
+
command2.requestId,
|
|
27258
|
+
command2.sessionId,
|
|
27259
|
+
new AcpExecutionError(
|
|
27260
|
+
"Another native session operation is running",
|
|
27261
|
+
{},
|
|
27262
|
+
"native_session_busy"
|
|
27263
|
+
)
|
|
27264
|
+
);
|
|
27265
|
+
return;
|
|
27266
|
+
}
|
|
27267
|
+
const controller = new AbortController();
|
|
27268
|
+
const operationSignal = AbortSignal.any([
|
|
27269
|
+
connectionController.signal,
|
|
27270
|
+
controller.signal
|
|
27271
|
+
]);
|
|
27272
|
+
const timeout = timer.schedule(
|
|
27273
|
+
() => controller.abort(
|
|
27274
|
+
new AcpExecutionError(
|
|
27275
|
+
"Native session operation timed out",
|
|
27276
|
+
{},
|
|
27277
|
+
"native_session_timeout"
|
|
27278
|
+
)
|
|
27279
|
+
),
|
|
27280
|
+
9e4
|
|
27281
|
+
);
|
|
27282
|
+
const completion = (async () => {
|
|
27283
|
+
try {
|
|
27284
|
+
operationSignal.throwIfAborted();
|
|
27285
|
+
if (previous.length > 0) {
|
|
27286
|
+
await new Promise((resolve6, reject2) => {
|
|
27287
|
+
const cancel = () => reject2(operationSignal.reason);
|
|
27288
|
+
operationSignal.addEventListener("abort", cancel, {
|
|
27289
|
+
once: true
|
|
27290
|
+
});
|
|
27291
|
+
void Promise.all(
|
|
27292
|
+
previous.map((request) => request.completion)
|
|
27293
|
+
).then(
|
|
27294
|
+
() => {
|
|
27295
|
+
operationSignal.removeEventListener("abort", cancel);
|
|
27296
|
+
resolve6();
|
|
27297
|
+
},
|
|
27298
|
+
(error61) => {
|
|
27299
|
+
operationSignal.removeEventListener("abort", cancel);
|
|
27300
|
+
reject2(error61);
|
|
27301
|
+
}
|
|
27302
|
+
);
|
|
27303
|
+
});
|
|
27304
|
+
}
|
|
27305
|
+
operationSignal.throwIfAborted();
|
|
27306
|
+
const result = await nativeSessions.execute(
|
|
27307
|
+
command2,
|
|
27308
|
+
operationSignal
|
|
27309
|
+
);
|
|
27310
|
+
if (socket.readyState === WebSocket2.OPEN)
|
|
27311
|
+
send(socket, encodeNativeSessionResult(result));
|
|
27312
|
+
} catch (error61) {
|
|
27313
|
+
const failure = operationSignal.aborted ? controller.signal.reason ?? new AcpExecutionError(
|
|
27314
|
+
"Native session operation cancelled",
|
|
27315
|
+
{},
|
|
27316
|
+
"native_session_cancelled"
|
|
27317
|
+
) : error61;
|
|
27318
|
+
audit.record({
|
|
27319
|
+
commandId: command2.requestId,
|
|
27320
|
+
sessionId: command2.sessionId,
|
|
27321
|
+
event: "native_session_operation_failed",
|
|
27322
|
+
details: { code: operationErrorCode(failure) }
|
|
27323
|
+
});
|
|
27324
|
+
reportOperationFailure(
|
|
27325
|
+
socket,
|
|
27326
|
+
command2.requestId,
|
|
27327
|
+
command2.sessionId,
|
|
27328
|
+
failure
|
|
27329
|
+
);
|
|
27330
|
+
} finally {
|
|
27331
|
+
timeout.cancel();
|
|
27332
|
+
nativeRequests.delete(command2.requestId);
|
|
27333
|
+
}
|
|
27334
|
+
})();
|
|
27335
|
+
nativeRequests.set(command2.requestId, {
|
|
27336
|
+
agentId: command2.agentId,
|
|
27337
|
+
sessionId: command2.sessionId,
|
|
27338
|
+
controller,
|
|
27339
|
+
completion
|
|
27340
|
+
});
|
|
26081
27341
|
return;
|
|
26082
27342
|
}
|
|
26083
|
-
if (
|
|
27343
|
+
if (kind === RUNTIME_LIVENESS_READY_KIND) {
|
|
27344
|
+
decodeRuntimeLivenessReadyEvent(encoded);
|
|
27345
|
+
connectionLiveness.start();
|
|
26084
27346
|
return;
|
|
26085
27347
|
}
|
|
26086
|
-
|
|
26087
|
-
|
|
26088
|
-
|
|
26089
|
-
sessionId: cancellation.sessionId
|
|
26090
|
-
});
|
|
26091
|
-
void sessions.cancelPrompt(cancellation.sessionId).catch((error61) => {
|
|
26092
|
-
console.error(
|
|
26093
|
-
"Mobius daemon could not cancel the agent turn",
|
|
26094
|
-
error61
|
|
27348
|
+
if (kind === RUNTIME_HEARTBEAT_ACK_KIND) {
|
|
27349
|
+
connectionLiveness.acknowledge(
|
|
27350
|
+
decodeRuntimeHeartbeatAckEvent(encoded)
|
|
26095
27351
|
);
|
|
26096
|
-
|
|
26097
|
-
|
|
26098
|
-
|
|
26099
|
-
|
|
26100
|
-
|
|
26101
|
-
|
|
26102
|
-
|
|
26103
|
-
|
|
26104
|
-
|
|
26105
|
-
|
|
26106
|
-
|
|
26107
|
-
|
|
26108
|
-
|
|
26109
|
-
|
|
26110
|
-
directories,
|
|
26111
|
-
audit,
|
|
26112
|
-
sessions,
|
|
26113
|
-
connectionController.signal
|
|
26114
|
-
);
|
|
26115
|
-
return;
|
|
26116
|
-
}
|
|
26117
|
-
if (kind === SESSION_CONFIGURE_KIND) {
|
|
26118
|
-
const command2 = decodeSessionConfigureCommand(encoded);
|
|
26119
|
-
void executeSessionConfigure(
|
|
26120
|
-
socket,
|
|
26121
|
-
command2,
|
|
26122
|
-
config2,
|
|
26123
|
-
directories,
|
|
26124
|
-
audit,
|
|
26125
|
-
sessions,
|
|
26126
|
-
connectionController.signal
|
|
26127
|
-
);
|
|
26128
|
-
return;
|
|
26129
|
-
}
|
|
26130
|
-
if (kind === SESSION_PERMISSION_RESPOND_KIND) {
|
|
26131
|
-
const command2 = decodeSessionPermissionRespondCommand(encoded);
|
|
26132
|
-
void sessions.respondPermission(command2).then(() => {
|
|
27352
|
+
return;
|
|
27353
|
+
}
|
|
27354
|
+
if (kind === SESSION_CANCEL_KIND) {
|
|
27355
|
+
const cancellation = decodeSessionCancelCommand(encoded);
|
|
27356
|
+
const turn2 = activeTurns.get(cancellation.commandId);
|
|
27357
|
+
if (turn2 === void 0 || !turn2.matches(cancellation)) {
|
|
27358
|
+
console.warn(
|
|
27359
|
+
"Mobius daemon ignored cancellation for an inactive turn"
|
|
27360
|
+
);
|
|
27361
|
+
return;
|
|
27362
|
+
}
|
|
27363
|
+
if (!turn2.requestCancellation()) {
|
|
27364
|
+
return;
|
|
27365
|
+
}
|
|
26133
27366
|
audit.record({
|
|
26134
|
-
commandId:
|
|
26135
|
-
event: "
|
|
26136
|
-
sessionId:
|
|
27367
|
+
commandId: cancellation.commandId,
|
|
27368
|
+
event: "session_cancellation_requested",
|
|
27369
|
+
sessionId: cancellation.sessionId
|
|
27370
|
+
});
|
|
27371
|
+
void sessions.cancelPrompt(cancellation.sessionId).catch((error61) => {
|
|
27372
|
+
console.error(
|
|
27373
|
+
"Mobius daemon could not cancel the agent turn",
|
|
27374
|
+
error61
|
|
27375
|
+
);
|
|
26137
27376
|
});
|
|
26138
|
-
|
|
26139
|
-
|
|
27377
|
+
return;
|
|
27378
|
+
}
|
|
27379
|
+
if (kind === WORKSPACE_LIST_KIND) {
|
|
27380
|
+
const command2 = decodeWorkspaceListCommand(encoded);
|
|
27381
|
+
void executeWorkspaceList(
|
|
26140
27382
|
socket,
|
|
26141
|
-
command2
|
|
26142
|
-
|
|
26143
|
-
|
|
27383
|
+
command2,
|
|
27384
|
+
directories,
|
|
27385
|
+
audit,
|
|
27386
|
+
connectionController.signal
|
|
26144
27387
|
);
|
|
26145
|
-
|
|
26146
|
-
|
|
26147
|
-
|
|
26148
|
-
|
|
26149
|
-
|
|
26150
|
-
|
|
26151
|
-
|
|
26152
|
-
|
|
26153
|
-
|
|
26154
|
-
|
|
27388
|
+
return;
|
|
27389
|
+
}
|
|
27390
|
+
if (kind === SESSION_PREPARE_KIND) {
|
|
27391
|
+
const command2 = decodeSessionPrepareCommand(encoded);
|
|
27392
|
+
void executeSessionPrepare(
|
|
27393
|
+
socket,
|
|
27394
|
+
command2,
|
|
27395
|
+
config2,
|
|
27396
|
+
directories,
|
|
27397
|
+
audit,
|
|
27398
|
+
sessions,
|
|
27399
|
+
connectionController.signal
|
|
27400
|
+
);
|
|
27401
|
+
return;
|
|
27402
|
+
}
|
|
27403
|
+
if (kind === SESSION_CONFIGURE_KIND) {
|
|
27404
|
+
const command2 = decodeSessionConfigureCommand(encoded);
|
|
27405
|
+
void executeSessionConfigure(
|
|
27406
|
+
socket,
|
|
27407
|
+
command2,
|
|
27408
|
+
config2,
|
|
27409
|
+
directories,
|
|
27410
|
+
audit,
|
|
27411
|
+
sessions,
|
|
27412
|
+
connectionController.signal
|
|
27413
|
+
);
|
|
27414
|
+
return;
|
|
27415
|
+
}
|
|
27416
|
+
if (kind === SESSION_PERMISSION_RESPOND_KIND) {
|
|
27417
|
+
const command2 = decodeSessionPermissionRespondCommand(encoded);
|
|
27418
|
+
void sessions.respondPermission(command2).then(() => {
|
|
27419
|
+
audit.record({
|
|
27420
|
+
commandId: command2.interactionId,
|
|
27421
|
+
event: "session_permission_resolved",
|
|
27422
|
+
sessionId: command2.sessionId
|
|
27423
|
+
});
|
|
27424
|
+
}).catch((error61) => {
|
|
27425
|
+
reportOperationFailure(
|
|
27426
|
+
socket,
|
|
27427
|
+
command2.interactionId,
|
|
27428
|
+
command2.sessionId,
|
|
27429
|
+
error61
|
|
27430
|
+
);
|
|
27431
|
+
});
|
|
27432
|
+
return;
|
|
27433
|
+
}
|
|
27434
|
+
if (kind === SESSION_ELICITATION_RESPOND_KIND) {
|
|
27435
|
+
const command2 = decodeSessionElicitationRespondCommand(encoded);
|
|
27436
|
+
void sessions.respondElicitation(command2).then(() => {
|
|
27437
|
+
audit.record({
|
|
27438
|
+
commandId: command2.interactionId,
|
|
27439
|
+
event: "session_elicitation_resolved",
|
|
27440
|
+
sessionId: command2.sessionId
|
|
27441
|
+
});
|
|
27442
|
+
}).catch((error61) => {
|
|
27443
|
+
reportOperationFailure(
|
|
27444
|
+
socket,
|
|
27445
|
+
command2.interactionId,
|
|
27446
|
+
command2.sessionId,
|
|
27447
|
+
error61
|
|
27448
|
+
);
|
|
27449
|
+
});
|
|
27450
|
+
return;
|
|
27451
|
+
}
|
|
27452
|
+
if (kind === AGENT_INSTALL_REQUEST_KIND) {
|
|
27453
|
+
const command2 = decodeAgentInstallRequestCommand(encoded);
|
|
27454
|
+
void installations.request(command2, signal).catch((error61) => {
|
|
27455
|
+
console.error("Mobius Agent installation failed", error61);
|
|
27456
|
+
});
|
|
27457
|
+
return;
|
|
27458
|
+
}
|
|
27459
|
+
if (kind === AGENT_INSTALL_CANCEL_KIND) {
|
|
27460
|
+
const command2 = decodeAgentInstallCancelCommand(encoded);
|
|
27461
|
+
void installations.cancel(command2.requestId).catch((error61) => {
|
|
27462
|
+
reportOperationFailure(socket, command2.requestId, "", error61);
|
|
26155
27463
|
});
|
|
26156
|
-
|
|
26157
|
-
|
|
27464
|
+
return;
|
|
27465
|
+
}
|
|
27466
|
+
if (kind !== SESSION_PROMPT_KIND) {
|
|
27467
|
+
throw new Error("Unsupported protocol message");
|
|
27468
|
+
}
|
|
27469
|
+
const command = decodeSessionPromptCommand(encoded);
|
|
27470
|
+
if (activeTurns.has(command.commandId)) {
|
|
27471
|
+
reportFailure(
|
|
26158
27472
|
socket,
|
|
26159
|
-
|
|
26160
|
-
|
|
26161
|
-
|
|
27473
|
+
command,
|
|
27474
|
+
"duplicate_command",
|
|
27475
|
+
"The command is already running"
|
|
26162
27476
|
);
|
|
26163
|
-
|
|
26164
|
-
|
|
26165
|
-
|
|
26166
|
-
|
|
26167
|
-
|
|
26168
|
-
void installations.request(command2, signal).catch((error61) => {
|
|
26169
|
-
console.error("Mobius Agent installation failed", error61);
|
|
26170
|
-
});
|
|
26171
|
-
return;
|
|
26172
|
-
}
|
|
26173
|
-
if (kind === AGENT_INSTALL_CANCEL_KIND) {
|
|
26174
|
-
const command2 = decodeAgentInstallCancelCommand(encoded);
|
|
26175
|
-
void installations.cancel(command2.requestId).catch((error61) => {
|
|
26176
|
-
reportOperationFailure(socket, command2.requestId, "", error61);
|
|
26177
|
-
});
|
|
26178
|
-
return;
|
|
26179
|
-
}
|
|
26180
|
-
if (kind !== SESSION_PROMPT_KIND) {
|
|
26181
|
-
throw new Error("Unsupported protocol message");
|
|
26182
|
-
}
|
|
26183
|
-
const command = decodeSessionPromptCommand(encoded);
|
|
26184
|
-
if (activeTurns.has(command.commandId)) {
|
|
26185
|
-
reportFailure(
|
|
27477
|
+
return;
|
|
27478
|
+
}
|
|
27479
|
+
const turn = new ActiveDaemonTurn(command, new AbortController());
|
|
27480
|
+
activeTurns.set(command.commandId, turn);
|
|
27481
|
+
void executePrompt(
|
|
26186
27482
|
socket,
|
|
26187
27483
|
command,
|
|
26188
|
-
|
|
26189
|
-
|
|
26190
|
-
|
|
26191
|
-
|
|
27484
|
+
config2,
|
|
27485
|
+
directories,
|
|
27486
|
+
audit,
|
|
27487
|
+
sessions,
|
|
27488
|
+
turn.signal
|
|
27489
|
+
).catch((error61) => {
|
|
27490
|
+
console.error("Mobius daemon turn failed", error61);
|
|
27491
|
+
}).finally(() => {
|
|
27492
|
+
activeTurns.delete(command.commandId);
|
|
27493
|
+
connectionRefresh.afterTurnFinished();
|
|
27494
|
+
});
|
|
27495
|
+
} catch (error61) {
|
|
27496
|
+
console.error("Mobius daemon rejected a message", error61);
|
|
27497
|
+
socket.close(4008, "Invalid protocol message");
|
|
27498
|
+
rejectConnection();
|
|
26192
27499
|
}
|
|
26193
|
-
|
|
26194
|
-
|
|
26195
|
-
|
|
26196
|
-
|
|
26197
|
-
|
|
26198
|
-
|
|
26199
|
-
directories,
|
|
26200
|
-
audit,
|
|
26201
|
-
sessions,
|
|
26202
|
-
turn.signal
|
|
26203
|
-
).catch((error61) => {
|
|
26204
|
-
console.error("Mobius daemon turn failed", error61);
|
|
26205
|
-
}).finally(() => {
|
|
26206
|
-
activeTurns.delete(command.commandId);
|
|
26207
|
-
connectionRefresh.afterTurnFinished();
|
|
26208
|
-
});
|
|
26209
|
-
} catch (error61) {
|
|
26210
|
-
console.error("Mobius daemon rejected a message", error61);
|
|
26211
|
-
socket.close(4008, "Invalid protocol message");
|
|
26212
|
-
rejectConnection();
|
|
27500
|
+
};
|
|
27501
|
+
socket.addEventListener("close", handleClose);
|
|
27502
|
+
socket.addEventListener("error", handleError);
|
|
27503
|
+
socket.addEventListener("message", handleMessage);
|
|
27504
|
+
if (signal.aborted) {
|
|
27505
|
+
stop();
|
|
26213
27506
|
}
|
|
26214
|
-
};
|
|
26215
|
-
|
|
26216
|
-
|
|
26217
|
-
|
|
26218
|
-
|
|
26219
|
-
|
|
26220
|
-
|
|
26221
|
-
});
|
|
27507
|
+
});
|
|
27508
|
+
} finally {
|
|
27509
|
+
connectionController.abort();
|
|
27510
|
+
await Promise.all(
|
|
27511
|
+
[...nativeRequests.values()].map((request) => request.completion)
|
|
27512
|
+
);
|
|
27513
|
+
}
|
|
26222
27514
|
}
|
|
26223
27515
|
async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
26224
27516
|
const installationAudit = new AuditInstallationEvents(audit);
|
|
26225
27517
|
const stateDirectory = readStateDirectory();
|
|
26226
27518
|
const specifications = supportedLocalAgentSpecifications();
|
|
26227
27519
|
const installationExecutor = new FixedInstallationExecutor({
|
|
26228
|
-
|
|
27520
|
+
defaultWorkspace: config2.defaultWorkspace,
|
|
26229
27521
|
audit: installationAudit,
|
|
26230
27522
|
catalog: config2.catalog,
|
|
26231
27523
|
environment: process.env,
|
|
@@ -26234,13 +27526,12 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
26234
27526
|
});
|
|
26235
27527
|
await new AutomaticAdapterProvisioner(
|
|
26236
27528
|
{
|
|
26237
|
-
|
|
27529
|
+
defaultWorkspace: config2.defaultWorkspace,
|
|
26238
27530
|
audit: installationAudit,
|
|
26239
27531
|
catalog: config2.catalog,
|
|
26240
27532
|
environment: process.env
|
|
26241
27533
|
},
|
|
26242
27534
|
new ManagedAdapterInstaller({
|
|
26243
|
-
approvedRoot: config2.approvedRoot,
|
|
26244
27535
|
environment: process.env,
|
|
26245
27536
|
stateDirectory
|
|
26246
27537
|
}),
|
|
@@ -26253,9 +27544,15 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
26253
27544
|
);
|
|
26254
27545
|
const directories = new WorkspaceDirectoryService(
|
|
26255
27546
|
config2.bindingId,
|
|
26256
|
-
config2.
|
|
27547
|
+
config2.defaultWorkspace
|
|
26257
27548
|
);
|
|
26258
27549
|
const installationObserver = new DaemonInstallationObserver();
|
|
27550
|
+
const nativeSessions = new NativeSessionService(
|
|
27551
|
+
config2,
|
|
27552
|
+
directories,
|
|
27553
|
+
sessions,
|
|
27554
|
+
audit
|
|
27555
|
+
);
|
|
26259
27556
|
const installations = new AgentInstallationManager(
|
|
26260
27557
|
specifications,
|
|
26261
27558
|
new ConsoleInstallationAuthorizer(stateDirectory),
|
|
@@ -26275,6 +27572,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
26275
27572
|
sessions,
|
|
26276
27573
|
installations,
|
|
26277
27574
|
installationObserver,
|
|
27575
|
+
nativeSessions,
|
|
26278
27576
|
signal,
|
|
26279
27577
|
timer
|
|
26280
27578
|
);
|
|
@@ -26310,7 +27608,7 @@ process.once("SIGTERM", () => shutdown.abort());
|
|
|
26310
27608
|
var USAGE = `Mobius CLI
|
|
26311
27609
|
|
|
26312
27610
|
Usage:
|
|
26313
|
-
mobius pair --url <relay-url> --code <pairing-code> --
|
|
27611
|
+
mobius pair --url <relay-url> --code <pairing-code> [--workspace <directory>]
|
|
26314
27612
|
mobius start --channel <channel-id>
|
|
26315
27613
|
mobius agents [--json]
|
|
26316
27614
|
|
|
@@ -26318,6 +27616,9 @@ Commands:
|
|
|
26318
27616
|
pair Pair this machine and start its local daemon
|
|
26319
27617
|
start Start the local daemon for a saved channel
|
|
26320
27618
|
agents Show locally available and installable Agents
|
|
27619
|
+
|
|
27620
|
+
Pairing grants this browser access to the machine with your user account's permissions.
|
|
27621
|
+
New conversations default to ~/.mobius/workspace; choose other directories in the browser.
|
|
26321
27622
|
`;
|
|
26322
27623
|
async function main() {
|
|
26323
27624
|
const command = process.argv[2];
|
|
@@ -26330,8 +27631,9 @@ async function main() {
|
|
|
26330
27631
|
if (arguments_.length > 1 || arguments_.length === 1 && arguments_[0] !== "--json") {
|
|
26331
27632
|
throw new Error("Usage: mobius agents [--json]");
|
|
26332
27633
|
}
|
|
27634
|
+
await mkdir4(loadDefaultWorkspace(), { recursive: true, mode: 448 });
|
|
26333
27635
|
const inventory = await discoverLocalAgentInventory({
|
|
26334
|
-
|
|
27636
|
+
defaultWorkspace: loadDefaultWorkspace(),
|
|
26335
27637
|
environment: process.env,
|
|
26336
27638
|
signal: shutdown.signal
|
|
26337
27639
|
});
|
|
@@ -26373,6 +27675,12 @@ async function main() {
|
|
|
26373
27675
|
process.stdout.write(
|
|
26374
27676
|
"Starting the local daemon. Keep this terminal open.\n\n"
|
|
26375
27677
|
);
|
|
27678
|
+
process.stdout.write(
|
|
27679
|
+
"This paired browser can use the machine with your user account's permissions.\n"
|
|
27680
|
+
);
|
|
27681
|
+
process.stdout.write(`Default workspace: ${config2.defaultWorkspace}
|
|
27682
|
+
|
|
27683
|
+
`);
|
|
26376
27684
|
const audit = new AuditStore(config2.auditDatabasePath);
|
|
26377
27685
|
try {
|
|
26378
27686
|
await runDaemon(config2, audit, shutdown.signal);
|