@moxt-ai/mobius 0.0.23 → 0.0.25
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/session-capabilities.d.ts +2 -2
- package/dist/acp/session-capabilities.d.ts.map +1 -1
- package/dist/acp/session-capabilities.js +16 -1
- package/dist/acp/session-capabilities.js.map +1 -1
- package/dist/acp/session-manager.d.ts +47 -6
- package/dist/acp/session-manager.d.ts.map +1 -1
- package/dist/acp/session-manager.js +250 -8
- package/dist/acp/session-manager.js.map +1 -1
- package/dist/agent-catalog/acp-readiness-probe.js +1 -1
- package/dist/agent-catalog/acp-readiness-probe.js.map +1 -1
- package/dist/agent-catalog/publish-agent-catalog.d.ts.map +1 -1
- package/dist/agent-catalog/publish-agent-catalog.js +12 -7
- package/dist/agent-catalog/publish-agent-catalog.js.map +1 -1
- package/dist/bots/local-bot-grant-store.d.ts +2 -1
- package/dist/bots/local-bot-grant-store.d.ts.map +1 -1
- package/dist/bots/local-bot-grant-store.js +8 -5
- package/dist/bots/local-bot-grant-store.js.map +1 -1
- package/dist/cli.js +949 -260
- package/dist/cli.js.map +4 -4
- package/dist/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +3 -3
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1002 -216
- package/dist/index.js.map +4 -4
- package/dist/native-sessions/service.d.ts +2 -1
- package/dist/native-sessions/service.d.ts.map +1 -1
- package/dist/native-sessions/service.js +65 -0
- package/dist/native-sessions/service.js.map +1 -1
- package/dist/pairing/pair-local-machine.d.ts +8 -0
- package/dist/pairing/pair-local-machine.d.ts.map +1 -1
- package/dist/pairing/pair-local-machine.js +64 -37
- package/dist/pairing/pair-local-machine.js.map +1 -1
- package/dist/prompt-artifact-resolver.d.ts.map +1 -1
- package/dist/prompt-artifact-resolver.js +11 -3
- package/dist/prompt-artifact-resolver.js.map +1 -1
- package/dist/relay-connection/connect.d.ts.map +1 -1
- package/dist/relay-connection/connect.js +9 -1
- package/dist/relay-connection/connect.js.map +1 -1
- package/dist/relay-connection/session-event-outbox.d.ts +1 -0
- package/dist/relay-connection/session-event-outbox.d.ts.map +1 -1
- package/dist/relay-connection/session-event-outbox.js +7 -0
- package/dist/relay-connection/session-event-outbox.js.map +1 -1
- package/dist/run-daemon.d.ts.map +1 -1
- package/dist/run-daemon.js +165 -54
- package/dist/run-daemon.js.map +1 -1
- package/dist/runtime.d.ts +23 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +31046 -0
- package/dist/runtime.js.map +7 -0
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -19006,7 +19006,9 @@ var sessionCapabilitiesSchema = external_exports.strictObject({
|
|
|
19006
19006
|
imagePrompt: external_exports.boolean(),
|
|
19007
19007
|
listSessions: external_exports.boolean(),
|
|
19008
19008
|
loadSession: external_exports.boolean(),
|
|
19009
|
+
promptQueueing: external_exports.boolean().default(false),
|
|
19009
19010
|
resumeSession: external_exports.boolean(),
|
|
19011
|
+
steering: external_exports.boolean().default(false),
|
|
19010
19012
|
unstableForkSession: external_exports.boolean().default(false)
|
|
19011
19013
|
}).readonly();
|
|
19012
19014
|
var sessionCommandSchema = external_exports.strictObject({
|
|
@@ -19348,6 +19350,11 @@ var AGENT_ACTIVITY_LOCATION_LIMIT = 12;
|
|
|
19348
19350
|
var AGENT_ACTIVITY_LOCATION_LENGTH_LIMIT = 1024;
|
|
19349
19351
|
var SESSION_COMPLETED_KIND = "session.completed";
|
|
19350
19352
|
var SESSION_FAILED_KIND = "session.failed";
|
|
19353
|
+
var SessionPromptDisposition = Object.freeze({
|
|
19354
|
+
Queue: "queue",
|
|
19355
|
+
Reject: "reject",
|
|
19356
|
+
Steer: "steer"
|
|
19357
|
+
});
|
|
19351
19358
|
|
|
19352
19359
|
// ../protocol/src/codecs/messages.ts
|
|
19353
19360
|
var IDENTIFIER_PATTERN2 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
@@ -19422,6 +19429,19 @@ function readAllowedString(value, key, allowedValues) {
|
|
|
19422
19429
|
}
|
|
19423
19430
|
return field;
|
|
19424
19431
|
}
|
|
19432
|
+
function readPromptDisposition(value) {
|
|
19433
|
+
const field = value["disposition"];
|
|
19434
|
+
if (field === void 0 || field === SessionPromptDisposition.Reject) {
|
|
19435
|
+
return SessionPromptDisposition.Reject;
|
|
19436
|
+
}
|
|
19437
|
+
if (field === SessionPromptDisposition.Queue) {
|
|
19438
|
+
return SessionPromptDisposition.Queue;
|
|
19439
|
+
}
|
|
19440
|
+
if (field === SessionPromptDisposition.Steer) {
|
|
19441
|
+
return SessionPromptDisposition.Steer;
|
|
19442
|
+
}
|
|
19443
|
+
throw new ProtocolMessageError("Invalid value field: disposition");
|
|
19444
|
+
}
|
|
19425
19445
|
function readSequence(value, key) {
|
|
19426
19446
|
const field = value[key];
|
|
19427
19447
|
if (typeof field !== "number" || !Number.isSafeInteger(field) || field < 0) {
|
|
@@ -19546,11 +19566,13 @@ function decodeSessionPromptCommand(encoded) {
|
|
|
19546
19566
|
"bindingId",
|
|
19547
19567
|
"commandId",
|
|
19548
19568
|
"directoryId",
|
|
19569
|
+
"disposition",
|
|
19549
19570
|
"images",
|
|
19550
19571
|
"kind",
|
|
19551
19572
|
"prompt",
|
|
19552
19573
|
"resources",
|
|
19553
|
-
"sessionId"
|
|
19574
|
+
"sessionId",
|
|
19575
|
+
"targetCommandId"
|
|
19554
19576
|
]);
|
|
19555
19577
|
assertKind(value, SESSION_PROMPT_KIND);
|
|
19556
19578
|
const prompt = readText(value, "prompt", MAX_PROMPT_LENGTH);
|
|
@@ -19563,17 +19585,25 @@ function decodeSessionPromptCommand(encoded) {
|
|
|
19563
19585
|
if (prompt.trim().length === 0 && images.length === 0 && resources.length === 0) {
|
|
19564
19586
|
throw new ProtocolMessageError("Prompt must contain content");
|
|
19565
19587
|
}
|
|
19588
|
+
const disposition = readPromptDisposition(value);
|
|
19589
|
+
const rawTargetCommandId = value["targetCommandId"];
|
|
19590
|
+
const targetCommandId = rawTargetCommandId === void 0 ? "" : readText(value, "targetCommandId", 128);
|
|
19591
|
+
if (disposition === SessionPromptDisposition.Reject && targetCommandId.length > 0 || disposition !== SessionPromptDisposition.Reject && !IDENTIFIER_PATTERN2.test(targetCommandId)) {
|
|
19592
|
+
throw new ProtocolMessageError("Prompt disposition has an invalid target command");
|
|
19593
|
+
}
|
|
19566
19594
|
return {
|
|
19567
19595
|
additionalDirectoryIds: readDirectoryIdentifiers(value, "additionalDirectoryIds", 16),
|
|
19568
19596
|
agentId: readIdentifier(value, "agentId"),
|
|
19569
19597
|
bindingId: readIdentifier(value, "bindingId"),
|
|
19570
19598
|
commandId: readIdentifier(value, "commandId"),
|
|
19571
19599
|
directoryId: readDirectoryIdentifier(value, "directoryId"),
|
|
19600
|
+
disposition,
|
|
19572
19601
|
images,
|
|
19573
19602
|
kind: SESSION_PROMPT_KIND,
|
|
19574
19603
|
prompt,
|
|
19575
19604
|
resources,
|
|
19576
|
-
sessionId: readIdentifier(value, "sessionId")
|
|
19605
|
+
sessionId: readIdentifier(value, "sessionId"),
|
|
19606
|
+
targetCommandId
|
|
19577
19607
|
};
|
|
19578
19608
|
}
|
|
19579
19609
|
function decodeSessionCancelCommand(encoded) {
|
|
@@ -19623,11 +19653,12 @@ function decodeSessionStartedEvent(encoded) {
|
|
|
19623
19653
|
}
|
|
19624
19654
|
function decodeAgentMessageDeltaEvent(encoded) {
|
|
19625
19655
|
const value = parseJson2(encoded);
|
|
19626
|
-
assertExactKeys(value, ["commandId", "kind", "sessionId", "text"]);
|
|
19656
|
+
assertExactKeys(value, ["commandId", "kind", "messageId", "sessionId", "text"]);
|
|
19627
19657
|
assertKind(value, AGENT_MESSAGE_DELTA_KIND);
|
|
19628
19658
|
return {
|
|
19629
19659
|
commandId: readIdentifier(value, "commandId"),
|
|
19630
19660
|
kind: AGENT_MESSAGE_DELTA_KIND,
|
|
19661
|
+
messageId: value["messageId"] === void 0 ? "" : readText(value, "messageId", 255),
|
|
19631
19662
|
sessionId: readIdentifier(value, "sessionId"),
|
|
19632
19663
|
text: readString(value, "text", MAX_EVENT_TEXT_LENGTH)
|
|
19633
19664
|
};
|
|
@@ -20273,6 +20304,8 @@ var sessionHistorySchema = external_exports.discriminatedUnion("status", [
|
|
|
20273
20304
|
var NATIVE_SESSION_REQUEST_KIND = "native.session.request";
|
|
20274
20305
|
var NATIVE_SESSION_RESULT_KIND = "native.session.result";
|
|
20275
20306
|
var NATIVE_SESSION_CANCEL_KIND = "native.session.cancel";
|
|
20307
|
+
var NATIVE_SESSION_TURN_FORK_REQUEST_KIND = "native.session.turn-fork.request";
|
|
20308
|
+
var NATIVE_SESSION_TURN_FORK_KIND = "native.session.turn-fork";
|
|
20276
20309
|
var identifier = external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/);
|
|
20277
20310
|
var directoryId = external_exports.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]{0,2047}$/);
|
|
20278
20311
|
var envelope = {
|
|
@@ -20287,6 +20320,28 @@ var identity = {
|
|
|
20287
20320
|
bindingId: identifier,
|
|
20288
20321
|
directoryId
|
|
20289
20322
|
};
|
|
20323
|
+
var turnForkIdentity = {
|
|
20324
|
+
additionalDirectoryIds: external_exports.array(directoryId).max(16).readonly(),
|
|
20325
|
+
agentId: identifier,
|
|
20326
|
+
bindingId: identifier,
|
|
20327
|
+
directoryId,
|
|
20328
|
+
requestId: identifier,
|
|
20329
|
+
sessionId: identifier,
|
|
20330
|
+
sourceCommandId: identifier,
|
|
20331
|
+
targetSessionId: identifier
|
|
20332
|
+
};
|
|
20333
|
+
var nativeSessionTurnForkRequestSchema = external_exports.strictObject({
|
|
20334
|
+
...turnForkIdentity,
|
|
20335
|
+
kind: external_exports.literal(NATIVE_SESSION_TURN_FORK_REQUEST_KIND)
|
|
20336
|
+
}).readonly();
|
|
20337
|
+
var nativeSessionTurnForkCommandSchema = external_exports.strictObject({
|
|
20338
|
+
...turnForkIdentity,
|
|
20339
|
+
kind: external_exports.literal(NATIVE_SESSION_TURN_FORK_KIND),
|
|
20340
|
+
messageFingerprint: external_exports.string().regex(/^sha256:[a-f0-9]{64}$/),
|
|
20341
|
+
messageId: external_exports.string().min(1).max(255),
|
|
20342
|
+
messageOccurrence: external_exports.number().int().positive(),
|
|
20343
|
+
title: external_exports.string().max(500)
|
|
20344
|
+
}).readonly();
|
|
20290
20345
|
var nativeSessionCommandSchema = external_exports.discriminatedUnion("action", [
|
|
20291
20346
|
external_exports.strictObject({
|
|
20292
20347
|
...identity,
|
|
@@ -20361,6 +20416,7 @@ function decode4(schema, encoded) {
|
|
|
20361
20416
|
var decodeNativeSessionCommand = (encoded) => decode4(nativeSessionCommandSchema, encoded);
|
|
20362
20417
|
var encodeNativeSessionResult = (value) => JSON.stringify(nativeSessionResultSchema.parse(value));
|
|
20363
20418
|
var decodeNativeSessionCancel = (encoded) => decode4(nativeSessionCancelSchema, encoded);
|
|
20419
|
+
var decodeNativeSessionTurnForkCommand = (encoded) => decode4(nativeSessionTurnForkCommandSchema, encoded);
|
|
20364
20420
|
|
|
20365
20421
|
// ../protocol/src/session-events.ts
|
|
20366
20422
|
var SESSION_EVENT_KIND = "session.event";
|
|
@@ -20449,6 +20505,16 @@ var decodeSessionEventRejection = (encoded) => decode5(encoded, eventRejectionSc
|
|
|
20449
20505
|
import { realpathSync, statSync } from "node:fs";
|
|
20450
20506
|
|
|
20451
20507
|
// src/acp/session-capabilities.ts
|
|
20508
|
+
function isRecord3(value) {
|
|
20509
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
20510
|
+
}
|
|
20511
|
+
function hasTrueChildField(value, childKey, fieldKey) {
|
|
20512
|
+
if (!isRecord3(value)) {
|
|
20513
|
+
return false;
|
|
20514
|
+
}
|
|
20515
|
+
const child = Reflect.get(value, childKey);
|
|
20516
|
+
return isRecord3(child) && Reflect.get(child, fieldKey) === true;
|
|
20517
|
+
}
|
|
20452
20518
|
function unsupportedSessionCapabilities() {
|
|
20453
20519
|
return Object.freeze({
|
|
20454
20520
|
additionalDirectories: false,
|
|
@@ -20459,11 +20525,14 @@ function unsupportedSessionCapabilities() {
|
|
|
20459
20525
|
imagePrompt: false,
|
|
20460
20526
|
listSessions: false,
|
|
20461
20527
|
loadSession: false,
|
|
20528
|
+
promptQueueing: false,
|
|
20462
20529
|
resumeSession: false,
|
|
20530
|
+
steering: false,
|
|
20463
20531
|
unstableForkSession: false
|
|
20464
20532
|
});
|
|
20465
20533
|
}
|
|
20466
|
-
function normalizeAcpCapabilities(
|
|
20534
|
+
function normalizeAcpCapabilities(initialized) {
|
|
20535
|
+
const capabilities = initialized.agentCapabilities ?? {};
|
|
20467
20536
|
const session = capabilities.sessionCapabilities;
|
|
20468
20537
|
const prompt = capabilities.promptCapabilities;
|
|
20469
20538
|
return Object.freeze({
|
|
@@ -20475,7 +20544,9 @@ function normalizeAcpCapabilities(capabilities) {
|
|
|
20475
20544
|
imagePrompt: prompt?.image === true,
|
|
20476
20545
|
listSessions: session?.list != null,
|
|
20477
20546
|
loadSession: capabilities.loadSession === true,
|
|
20547
|
+
promptQueueing: hasTrueChildField(capabilities._meta, "claudeCode", "promptQueueing"),
|
|
20478
20548
|
resumeSession: session?.resume != null,
|
|
20549
|
+
steering: hasTrueChildField(initialized._meta, "steering", "supported"),
|
|
20479
20550
|
unstableForkSession: session?.fork != null
|
|
20480
20551
|
});
|
|
20481
20552
|
}
|
|
@@ -21036,9 +21107,9 @@ function readStateDirectory(environment = process.env) {
|
|
|
21036
21107
|
}
|
|
21037
21108
|
|
|
21038
21109
|
// src/config.ts
|
|
21039
|
-
function loadDefaultWorkspace() {
|
|
21040
|
-
const { MOBIUS_DEFAULT_WORKSPACE: configuredWorkspace } =
|
|
21041
|
-
return configuredWorkspace ?? join3(readStateDirectory(), "workspace");
|
|
21110
|
+
function loadDefaultWorkspace(environment = process.env) {
|
|
21111
|
+
const { MOBIUS_DEFAULT_WORKSPACE: configuredWorkspace } = environment;
|
|
21112
|
+
return configuredWorkspace ?? join3(readStateDirectory(environment), "workspace");
|
|
21042
21113
|
}
|
|
21043
21114
|
function createDaemonConfig(connection, agents = [], installableAgents = []) {
|
|
21044
21115
|
return {
|
|
@@ -21092,7 +21163,7 @@ import {
|
|
|
21092
21163
|
|
|
21093
21164
|
// src/acp/activity.ts
|
|
21094
21165
|
var TRUNCATION_MARKER = "\n\u2026 output truncated by Mobius";
|
|
21095
|
-
function
|
|
21166
|
+
function isRecord4(value) {
|
|
21096
21167
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21097
21168
|
}
|
|
21098
21169
|
var AcpActivity = class _AcpActivity {
|
|
@@ -21359,7 +21430,7 @@ function contentPhase(content) {
|
|
|
21359
21430
|
return "";
|
|
21360
21431
|
}
|
|
21361
21432
|
const codex = metadata["codex"];
|
|
21362
|
-
if (!
|
|
21433
|
+
if (!isRecord4(codex)) {
|
|
21363
21434
|
return "";
|
|
21364
21435
|
}
|
|
21365
21436
|
const phase = codex["phase"];
|
|
@@ -21597,7 +21668,7 @@ var SessionConfigProtocolError = class extends Error {
|
|
|
21597
21668
|
this.name = "SessionConfigProtocolError";
|
|
21598
21669
|
}
|
|
21599
21670
|
};
|
|
21600
|
-
function
|
|
21671
|
+
function isRecord5(value) {
|
|
21601
21672
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
21602
21673
|
}
|
|
21603
21674
|
function readString2(value, fallback = "") {
|
|
@@ -21624,7 +21695,7 @@ function normalizeConfigValues(value) {
|
|
|
21624
21695
|
}
|
|
21625
21696
|
const normalized = [];
|
|
21626
21697
|
for (const entry of value) {
|
|
21627
|
-
if (!
|
|
21698
|
+
if (!isRecord5(entry)) {
|
|
21628
21699
|
continue;
|
|
21629
21700
|
}
|
|
21630
21701
|
const groupedOptions = entry["options"];
|
|
@@ -21632,7 +21703,7 @@ function normalizeConfigValues(value) {
|
|
|
21632
21703
|
const groupId = readString2(entry["group"]);
|
|
21633
21704
|
const groupName = readString2(entry["name"]);
|
|
21634
21705
|
for (const groupedOption of groupedOptions) {
|
|
21635
|
-
if (
|
|
21706
|
+
if (isRecord5(groupedOption)) {
|
|
21636
21707
|
normalized.push(normalizeConfigValue(groupedOption, groupId, groupName));
|
|
21637
21708
|
}
|
|
21638
21709
|
}
|
|
@@ -21646,7 +21717,7 @@ function normalizeConfigOptions(value, modes) {
|
|
|
21646
21717
|
const normalized = [];
|
|
21647
21718
|
if (Array.isArray(value)) {
|
|
21648
21719
|
for (const option2 of value) {
|
|
21649
|
-
if (!
|
|
21720
|
+
if (!isRecord5(option2)) {
|
|
21650
21721
|
continue;
|
|
21651
21722
|
}
|
|
21652
21723
|
const id = truncate2(readString2(option2["id"]), 128);
|
|
@@ -21685,12 +21756,12 @@ function normalizeConfigOptions(value, modes) {
|
|
|
21685
21756
|
}
|
|
21686
21757
|
}
|
|
21687
21758
|
}
|
|
21688
|
-
if (
|
|
21759
|
+
if (isRecord5(modes)) {
|
|
21689
21760
|
const values = [];
|
|
21690
21761
|
const availableModes = modes["availableModes"];
|
|
21691
21762
|
if (Array.isArray(availableModes)) {
|
|
21692
21763
|
for (const mode of availableModes) {
|
|
21693
|
-
if (!
|
|
21764
|
+
if (!isRecord5(mode)) {
|
|
21694
21765
|
continue;
|
|
21695
21766
|
}
|
|
21696
21767
|
const id = truncate2(readString2(mode["id"]), 500);
|
|
@@ -21768,7 +21839,7 @@ function ensureReasoningEffortOption(current) {
|
|
|
21768
21839
|
return [...current.slice(0, MAXIMUM_CONFIG_OPTIONS - 2), model, unavailable];
|
|
21769
21840
|
}
|
|
21770
21841
|
function normalizeStandardLifecycle(response) {
|
|
21771
|
-
const lifecycle =
|
|
21842
|
+
const lifecycle = isRecord5(response) ? response : {};
|
|
21772
21843
|
return ensureReasoningEffortOption(normalizeConfigOptions(lifecycle["configOptions"], lifecycle["modes"]));
|
|
21773
21844
|
}
|
|
21774
21845
|
function replaceStandardConfigOptions(current, value) {
|
|
@@ -21810,7 +21881,7 @@ var StandardSessionConfigProtocol = class {
|
|
|
21810
21881
|
"ACP agent exited while changing session configuration",
|
|
21811
21882
|
change.signal
|
|
21812
21883
|
);
|
|
21813
|
-
if (!
|
|
21884
|
+
if (!isRecord5(response) || !Array.isArray(response["configOptions"])) {
|
|
21814
21885
|
throw new SessionConfigProtocolError("The Agent returned an invalid session configuration response");
|
|
21815
21886
|
}
|
|
21816
21887
|
return replaceStandardConfigOptions(current, response["configOptions"]);
|
|
@@ -21824,18 +21895,18 @@ var standardSessionConfigProtocol = new StandardSessionConfigProtocol();
|
|
|
21824
21895
|
var LEGACY_MODEL_CONFIG_ID = "grok_build_legacy_model";
|
|
21825
21896
|
var LEGACY_REASONING_EFFORT_CONFIG_ID = "grok_build_legacy_reasoning_effort";
|
|
21826
21897
|
function legacyOptions(response) {
|
|
21827
|
-
if (!
|
|
21898
|
+
if (!isRecord5(response)) {
|
|
21828
21899
|
return [];
|
|
21829
21900
|
}
|
|
21830
21901
|
const metadata = response["_meta"];
|
|
21831
|
-
if (!
|
|
21902
|
+
if (!isRecord5(metadata)) {
|
|
21832
21903
|
return [];
|
|
21833
21904
|
}
|
|
21834
21905
|
const sessionConfig = metadata["x.ai/sessionConfig"];
|
|
21835
|
-
if (!
|
|
21906
|
+
if (!isRecord5(sessionConfig) || !Array.isArray(sessionConfig["options"])) {
|
|
21836
21907
|
return [];
|
|
21837
21908
|
}
|
|
21838
|
-
return sessionConfig["options"].slice(0, 500).filter(
|
|
21909
|
+
return sessionConfig["options"].slice(0, 500).filter(isRecord5);
|
|
21839
21910
|
}
|
|
21840
21911
|
function legacyValue(option2) {
|
|
21841
21912
|
const value = readString2(option2["id"]);
|
|
@@ -21848,7 +21919,7 @@ function legacyValue(option2) {
|
|
|
21848
21919
|
};
|
|
21849
21920
|
}
|
|
21850
21921
|
function modelsRecord(response) {
|
|
21851
|
-
if (!
|
|
21922
|
+
if (!isRecord5(response) || !isRecord5(response["models"])) {
|
|
21852
21923
|
return {};
|
|
21853
21924
|
}
|
|
21854
21925
|
return response["models"];
|
|
@@ -21867,7 +21938,7 @@ function legacyModelOptions(response) {
|
|
|
21867
21938
|
}
|
|
21868
21939
|
if (values.length === 0 && Array.isArray(models["availableModels"])) {
|
|
21869
21940
|
for (const model of models["availableModels"]) {
|
|
21870
|
-
if (!
|
|
21941
|
+
if (!isRecord5(model)) {
|
|
21871
21942
|
continue;
|
|
21872
21943
|
}
|
|
21873
21944
|
const value = readString2(model["modelId"]).slice(0, 500);
|
|
@@ -21947,7 +22018,7 @@ function legacyReasoningEffortOptions(response) {
|
|
|
21947
22018
|
return [result];
|
|
21948
22019
|
}
|
|
21949
22020
|
function normalizeGrokLifecycle(response) {
|
|
21950
|
-
const lifecycle =
|
|
22021
|
+
const lifecycle = isRecord5(response) ? response : {};
|
|
21951
22022
|
const standard = normalizeConfigOptions(lifecycle["configOptions"], lifecycle["modes"]);
|
|
21952
22023
|
const normalized = [...standard];
|
|
21953
22024
|
if (!normalized.some((option2) => option2.category === "model")) {
|
|
@@ -21966,11 +22037,11 @@ function updateCurrentValue2(current, category, value) {
|
|
|
21966
22037
|
return current.map((option2) => option2.category === category ? { ...option2, currentValue: value } : option2);
|
|
21967
22038
|
}
|
|
21968
22039
|
function validateGrokResponse(response, modelId) {
|
|
21969
|
-
if (!
|
|
22040
|
+
if (!isRecord5(response) || !isRecord5(response["_meta"])) {
|
|
21970
22041
|
throw new SessionConfigProtocolError("Grok Build returned an invalid session configuration response");
|
|
21971
22042
|
}
|
|
21972
22043
|
const model = response["_meta"]["model"];
|
|
21973
|
-
const appliedModel =
|
|
22044
|
+
const appliedModel = isRecord5(model) ? model["Ok"] : model;
|
|
21974
22045
|
if (appliedModel !== modelId) {
|
|
21975
22046
|
throw new SessionConfigProtocolError("Grok Build returned an invalid session configuration response");
|
|
21976
22047
|
}
|
|
@@ -22391,7 +22462,7 @@ function createWritableAcpStream(output2) {
|
|
|
22391
22462
|
if (outputFailure !== void 0) {
|
|
22392
22463
|
return Promise.reject(outputFailure);
|
|
22393
22464
|
}
|
|
22394
|
-
return new Promise((
|
|
22465
|
+
return new Promise((resolve6, reject) => {
|
|
22395
22466
|
pendingWriteFailures.add(reject);
|
|
22396
22467
|
output2.write(chunk, (error61) => {
|
|
22397
22468
|
pendingWriteFailures.delete(reject);
|
|
@@ -22404,7 +22475,7 @@ function createWritableAcpStream(output2) {
|
|
|
22404
22475
|
reject(outputFailure);
|
|
22405
22476
|
return;
|
|
22406
22477
|
}
|
|
22407
|
-
|
|
22478
|
+
resolve6();
|
|
22408
22479
|
});
|
|
22409
22480
|
});
|
|
22410
22481
|
}
|
|
@@ -22413,7 +22484,7 @@ function createWritableAcpStream(output2) {
|
|
|
22413
22484
|
function truncate3(value, maximumLength) {
|
|
22414
22485
|
return value.length <= maximumLength ? value : `${value.slice(0, Math.max(0, maximumLength - 1))}\u2026`;
|
|
22415
22486
|
}
|
|
22416
|
-
function
|
|
22487
|
+
function isRecord6(value) {
|
|
22417
22488
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
22418
22489
|
}
|
|
22419
22490
|
function readString4(value, fallback = "") {
|
|
@@ -22422,6 +22493,11 @@ function readString4(value, fallback = "") {
|
|
|
22422
22493
|
function arraysEqual(left, right) {
|
|
22423
22494
|
return left.length === right.length && left.every((value, index) => value === right[index]);
|
|
22424
22495
|
}
|
|
22496
|
+
function recordsEqual(left, right) {
|
|
22497
|
+
const leftEntries = Object.entries(left);
|
|
22498
|
+
const rightEntries = Object.entries(right);
|
|
22499
|
+
return leftEntries.length === rightEntries.length && leftEntries.every(([name, value]) => right[name] === value);
|
|
22500
|
+
}
|
|
22425
22501
|
function elicitationFieldType(value) {
|
|
22426
22502
|
if (value === "boolean") {
|
|
22427
22503
|
return "boolean";
|
|
@@ -22442,7 +22518,7 @@ function normalizeElicitationOptions(schema) {
|
|
|
22442
22518
|
const oneOf = schema["oneOf"];
|
|
22443
22519
|
if (Array.isArray(oneOf)) {
|
|
22444
22520
|
for (const option2 of oneOf) {
|
|
22445
|
-
if (
|
|
22521
|
+
if (isRecord6(option2) && typeof option2["const"] === "string") {
|
|
22446
22522
|
normalized.push({
|
|
22447
22523
|
description: truncate3(readString4(option2["description"]), 500),
|
|
22448
22524
|
label: truncate3(readString4(option2["title"], option2["const"]), 255),
|
|
@@ -22462,7 +22538,7 @@ function normalizeElicitationOptions(schema) {
|
|
|
22462
22538
|
return normalized.slice(0, 200);
|
|
22463
22539
|
}
|
|
22464
22540
|
const items = schema["items"];
|
|
22465
|
-
if (!
|
|
22541
|
+
if (!isRecord6(items)) {
|
|
22466
22542
|
return normalized;
|
|
22467
22543
|
}
|
|
22468
22544
|
const anyOf = items["anyOf"];
|
|
@@ -22475,7 +22551,7 @@ function numericString(value) {
|
|
|
22475
22551
|
return typeof value === "number" && Number.isFinite(value) ? value.toString() : "";
|
|
22476
22552
|
}
|
|
22477
22553
|
function normalizeElicitationFields(requestedSchema) {
|
|
22478
|
-
if (!
|
|
22554
|
+
if (!isRecord6(requestedSchema) || !isRecord6(requestedSchema["properties"])) {
|
|
22479
22555
|
return [];
|
|
22480
22556
|
}
|
|
22481
22557
|
const properties = requestedSchema["properties"];
|
|
@@ -22485,7 +22561,7 @@ function normalizeElicitationFields(requestedSchema) {
|
|
|
22485
22561
|
);
|
|
22486
22562
|
const normalized = [];
|
|
22487
22563
|
for (const [name, property] of Object.entries(properties)) {
|
|
22488
|
-
if (!
|
|
22564
|
+
if (!isRecord6(property)) {
|
|
22489
22565
|
continue;
|
|
22490
22566
|
}
|
|
22491
22567
|
const type = elicitationFieldType(property["type"]);
|
|
@@ -22576,7 +22652,7 @@ function validateElicitationContent(encoded, requestedSchema) {
|
|
|
22576
22652
|
"invalid_elicitation_response"
|
|
22577
22653
|
);
|
|
22578
22654
|
}
|
|
22579
|
-
if (!
|
|
22655
|
+
if (!isRecord6(decoded) || !isRecord6(requestedSchema) || !isRecord6(requestedSchema["properties"])) {
|
|
22580
22656
|
throw new AcpExecutionError(
|
|
22581
22657
|
"Elicitation response does not match the requested form",
|
|
22582
22658
|
{},
|
|
@@ -22596,7 +22672,7 @@ function validateElicitationContent(encoded, requestedSchema) {
|
|
|
22596
22672
|
const validated = {};
|
|
22597
22673
|
for (const [name, value] of Object.entries(decoded)) {
|
|
22598
22674
|
const property = properties[name];
|
|
22599
|
-
if (!
|
|
22675
|
+
if (!isRecord6(property)) {
|
|
22600
22676
|
throw new AcpExecutionError(
|
|
22601
22677
|
`Elicitation field ${name} was not requested`,
|
|
22602
22678
|
{},
|
|
@@ -22738,6 +22814,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22738
22814
|
#child;
|
|
22739
22815
|
#connection;
|
|
22740
22816
|
#cwd;
|
|
22817
|
+
#environment;
|
|
22741
22818
|
#getObserver;
|
|
22742
22819
|
#mobiusSessionId;
|
|
22743
22820
|
#pendingElicitations = /* @__PURE__ */ new Map();
|
|
@@ -22759,7 +22836,9 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22759
22836
|
imagePrompt: false,
|
|
22760
22837
|
listSessions: false,
|
|
22761
22838
|
loadSession: false,
|
|
22839
|
+
promptQueueing: false,
|
|
22762
22840
|
resumeSession: false,
|
|
22841
|
+
steering: false,
|
|
22763
22842
|
unstableForkSession: false
|
|
22764
22843
|
};
|
|
22765
22844
|
#commands = [];
|
|
@@ -22779,6 +22858,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22779
22858
|
this.#additionalDirectories = [...additionalDirectories];
|
|
22780
22859
|
this.#agentId = agent.id;
|
|
22781
22860
|
this.#cwd = cwd;
|
|
22861
|
+
this.#environment = agent.environment;
|
|
22782
22862
|
this.#getObserver = getObserver;
|
|
22783
22863
|
this.#mobiusSessionId = mobiusSessionId;
|
|
22784
22864
|
this.#sessionConfigProtocol = sessionConfigProtocolForAgent(agent.id);
|
|
@@ -22802,9 +22882,9 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22802
22882
|
stderr.on("data", (chunk) => {
|
|
22803
22883
|
process.stderr.write(`[${agent.id}-acp] ${chunk}`);
|
|
22804
22884
|
});
|
|
22805
|
-
this.#processExit = new Promise((
|
|
22806
|
-
this.#child.once("error",
|
|
22807
|
-
this.#child.once("exit",
|
|
22885
|
+
this.#processExit = new Promise((resolve6) => {
|
|
22886
|
+
this.#child.once("error", resolve6);
|
|
22887
|
+
this.#child.once("exit", resolve6);
|
|
22808
22888
|
});
|
|
22809
22889
|
const stream = ndJsonStream(createWritableAcpStream(stdin), readableWebStream(stdout));
|
|
22810
22890
|
this.#connection = createAcpClient(this).connect(stream);
|
|
@@ -22864,7 +22944,18 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22864
22944
|
store,
|
|
22865
22945
|
async (runtime) => await runtime.#initializeAgent(options.signal)
|
|
22866
22946
|
);
|
|
22947
|
+
static startSessionForkAtTurn = async (options, sourceNativeSessionId, forkPoint, getObserver, store) => await _AcpProcessSession.#start(
|
|
22948
|
+
options,
|
|
22949
|
+
getObserver,
|
|
22950
|
+
store,
|
|
22951
|
+
async (runtime) => await runtime.initialize(
|
|
22952
|
+
options.signal,
|
|
22953
|
+
{ kind: "fork", nativeSessionId: sourceNativeSessionId },
|
|
22954
|
+
forkPoint
|
|
22955
|
+
)
|
|
22956
|
+
);
|
|
22867
22957
|
belongsTo = (agentId, cwd, additionalDirectories) => this.#agentId === agentId && this.#cwd === cwd && arraysEqual(this.#additionalDirectories, additionalDirectories);
|
|
22958
|
+
usesEnvironment = (environment) => recordsEqual(this.#environment, environment);
|
|
22868
22959
|
canRebind = () => !this.#prompted && !this.#turn.running;
|
|
22869
22960
|
prepared = () => new AcpPreparedSession(
|
|
22870
22961
|
this.#agentName,
|
|
@@ -22930,15 +23021,14 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22930
23021
|
"unsupported_acp_protocol"
|
|
22931
23022
|
);
|
|
22932
23023
|
}
|
|
22933
|
-
|
|
22934
|
-
this.#capabilities = normalizeAcpCapabilities(capabilities);
|
|
23024
|
+
this.#capabilities = normalizeAcpCapabilities(initialized);
|
|
22935
23025
|
this.#agentName = truncate3(initialized.agentInfo?.title ?? initialized.agentInfo?.name ?? this.#agentId, 255);
|
|
22936
23026
|
this.#agentVersion = truncate3(
|
|
22937
23027
|
this.#verifiedAgentVersion.length > 0 ? this.#verifiedAgentVersion : initialized.agentInfo?.version ?? "",
|
|
22938
23028
|
128
|
|
22939
23029
|
);
|
|
22940
23030
|
}
|
|
22941
|
-
initialize = async (signal, origin) => {
|
|
23031
|
+
initialize = async (signal, origin, forkPoint) => {
|
|
22942
23032
|
await this.#initializeAgent(signal);
|
|
22943
23033
|
let stored = origin?.kind === "import" ? new FoundAcpStoredSession(
|
|
22944
23034
|
new AcpStoredSession(
|
|
@@ -22970,6 +23060,13 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22970
23060
|
"native_session_unsupported"
|
|
22971
23061
|
);
|
|
22972
23062
|
}
|
|
23063
|
+
if (this.#additionalDirectories.length > 0 && !this.#capabilities.additionalDirectories) {
|
|
23064
|
+
throw new AcpExecutionError(
|
|
23065
|
+
"This Agent cannot restore additional working directories",
|
|
23066
|
+
{},
|
|
23067
|
+
"native_session_unsupported"
|
|
23068
|
+
);
|
|
23069
|
+
}
|
|
22973
23070
|
const forked = await this.race(
|
|
22974
23071
|
this.#connection.agent.request(
|
|
22975
23072
|
methods3.agent.session.fork,
|
|
@@ -22977,7 +23074,21 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
22977
23074
|
sessionId: nativeSessionIdSchema.parse(origin.nativeSessionId),
|
|
22978
23075
|
cwd: this.#cwd,
|
|
22979
23076
|
additionalDirectories: [...this.#additionalDirectories],
|
|
22980
|
-
mcpServers: []
|
|
23077
|
+
mcpServers: [],
|
|
23078
|
+
...forkPoint === void 0 ? {} : {
|
|
23079
|
+
_meta: {
|
|
23080
|
+
jetbrains: {
|
|
23081
|
+
air: {
|
|
23082
|
+
fork: {
|
|
23083
|
+
version: 1,
|
|
23084
|
+
messageFingerprint: forkPoint.messageFingerprint,
|
|
23085
|
+
messageId: forkPoint.messageId,
|
|
23086
|
+
messageOccurrence: forkPoint.messageOccurrence
|
|
23087
|
+
}
|
|
23088
|
+
}
|
|
23089
|
+
}
|
|
23090
|
+
}
|
|
23091
|
+
}
|
|
22981
23092
|
},
|
|
22982
23093
|
{ cancellationSignal: signal }
|
|
22983
23094
|
),
|
|
@@ -23182,10 +23293,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
23182
23293
|
}
|
|
23183
23294
|
return this.#configOptions;
|
|
23184
23295
|
};
|
|
23185
|
-
|
|
23186
|
-
if (this.#turn.running) {
|
|
23187
|
-
throw new AcpExecutionError("Another prompt is already running in this conversation", {}, "session_busy");
|
|
23188
|
-
}
|
|
23296
|
+
buildPrompt = (options) => {
|
|
23189
23297
|
if (options.images.length > 0 && !this.#capabilities.imagePrompt) {
|
|
23190
23298
|
throw new AcpExecutionError(
|
|
23191
23299
|
"The selected agent does not accept image prompts",
|
|
@@ -23234,6 +23342,13 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
23234
23342
|
if (prompt.length === 0) {
|
|
23235
23343
|
throw new AcpExecutionError("A prompt must contain text or an attachment", {}, "empty_prompt");
|
|
23236
23344
|
}
|
|
23345
|
+
return prompt;
|
|
23346
|
+
};
|
|
23347
|
+
prompt = async (options) => {
|
|
23348
|
+
if (this.#turn.running) {
|
|
23349
|
+
throw new AcpExecutionError("Another prompt is already running in this conversation", {}, "session_busy");
|
|
23350
|
+
}
|
|
23351
|
+
const prompt = this.buildPrompt(options);
|
|
23237
23352
|
this.#store.write(
|
|
23238
23353
|
new AcpStoredSession(
|
|
23239
23354
|
this.#mobiusSessionId,
|
|
@@ -23292,6 +23407,54 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
23292
23407
|
this.#turn = new IdleAcpTurn();
|
|
23293
23408
|
}
|
|
23294
23409
|
};
|
|
23410
|
+
steer = async (options) => {
|
|
23411
|
+
if (!this.#capabilities.steering) {
|
|
23412
|
+
throw new AcpExecutionError(
|
|
23413
|
+
"The selected agent does not support mid-turn steering",
|
|
23414
|
+
{},
|
|
23415
|
+
"steering_unsupported"
|
|
23416
|
+
);
|
|
23417
|
+
}
|
|
23418
|
+
if (!this.#turn.running || this.#turn.commandId !== options.targetCommandId) {
|
|
23419
|
+
throw new AcpExecutionError("The target turn is no longer active", {}, "steering_target_unavailable");
|
|
23420
|
+
}
|
|
23421
|
+
const prompt = this.buildPrompt(options);
|
|
23422
|
+
const response = await this.race(
|
|
23423
|
+
this.#connection.agent.request("_session/steering", {
|
|
23424
|
+
_meta: { steering: { idleBehavior: "promptRequired" } },
|
|
23425
|
+
prompt,
|
|
23426
|
+
sessionId: this.#nativeSessionId
|
|
23427
|
+
}),
|
|
23428
|
+
"ACP agent exited during steering",
|
|
23429
|
+
options.signal
|
|
23430
|
+
);
|
|
23431
|
+
if (!isRecord6(response)) {
|
|
23432
|
+
throw new AcpExecutionError(
|
|
23433
|
+
"ACP agent returned an invalid steering response",
|
|
23434
|
+
{},
|
|
23435
|
+
"acp_invalid_steering_response"
|
|
23436
|
+
);
|
|
23437
|
+
}
|
|
23438
|
+
const outcome = response["outcome"];
|
|
23439
|
+
if (outcome === "injected" || outcome === "startedNewTurn") {
|
|
23440
|
+
return outcome;
|
|
23441
|
+
}
|
|
23442
|
+
if (outcome === "promptRequired") {
|
|
23443
|
+
throw new AcpExecutionError(
|
|
23444
|
+
"The target turn finished before steering could be injected",
|
|
23445
|
+
{},
|
|
23446
|
+
"steering_target_unavailable"
|
|
23447
|
+
);
|
|
23448
|
+
}
|
|
23449
|
+
if (outcome === "failed") {
|
|
23450
|
+
throw new AcpExecutionError("The Agent could not inject steering", {}, "steering_failed");
|
|
23451
|
+
}
|
|
23452
|
+
throw new AcpExecutionError(
|
|
23453
|
+
"ACP agent returned an invalid steering response",
|
|
23454
|
+
{},
|
|
23455
|
+
"acp_invalid_steering_response"
|
|
23456
|
+
);
|
|
23457
|
+
};
|
|
23295
23458
|
cancel = async () => {
|
|
23296
23459
|
const capturedProcesses = await captureProcessTree(this.#child);
|
|
23297
23460
|
try {
|
|
@@ -23532,7 +23695,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
23532
23695
|
);
|
|
23533
23696
|
} else {
|
|
23534
23697
|
await this.#turn.activities.finishNarrative();
|
|
23535
|
-
await this.#turn.onText(update.content.text);
|
|
23698
|
+
await this.#turn.onText(update.content.text, truncate3(update.messageId ?? "", 255));
|
|
23536
23699
|
}
|
|
23537
23700
|
} else {
|
|
23538
23701
|
await this.#turn.activities.finishNarrative();
|
|
@@ -23758,6 +23921,7 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
23758
23921
|
};
|
|
23759
23922
|
};
|
|
23760
23923
|
var AcpSessionManager = class {
|
|
23924
|
+
#activeCommandIds = /* @__PURE__ */ new Map();
|
|
23761
23925
|
#nativeOperations = /* @__PURE__ */ new Set();
|
|
23762
23926
|
#nativeBrowserObserver = new NullAcpSessionObserver();
|
|
23763
23927
|
#nativeBrowserPreparing = /* @__PURE__ */ new Map();
|
|
@@ -23826,6 +23990,25 @@ var AcpSessionManager = class {
|
|
|
23826
23990
|
this.#preparing.set(options.sessionId, operation);
|
|
23827
23991
|
return await operation;
|
|
23828
23992
|
}
|
|
23993
|
+
async #startSessionForkAtTurnPreparation(options, sourceNativeSessionId, forkPoint) {
|
|
23994
|
+
const operation = (async () => {
|
|
23995
|
+
try {
|
|
23996
|
+
const runtime = await AcpProcessSession.startSessionForkAtTurn(
|
|
23997
|
+
options,
|
|
23998
|
+
sourceNativeSessionId,
|
|
23999
|
+
forkPoint,
|
|
24000
|
+
() => this.#observer,
|
|
24001
|
+
this.#store
|
|
24002
|
+
);
|
|
24003
|
+
this.#sessions.set(options.sessionId, runtime);
|
|
24004
|
+
return runtime;
|
|
24005
|
+
} finally {
|
|
24006
|
+
this.#preparing.delete(options.sessionId);
|
|
24007
|
+
}
|
|
24008
|
+
})();
|
|
24009
|
+
this.#preparing.set(options.sessionId, operation);
|
|
24010
|
+
return await operation;
|
|
24011
|
+
}
|
|
23829
24012
|
async #replacePreparation(existing, options) {
|
|
23830
24013
|
const operation = (async () => {
|
|
23831
24014
|
try {
|
|
@@ -23842,6 +24025,58 @@ var AcpSessionManager = class {
|
|
|
23842
24025
|
this.#preparing.set(options.sessionId, operation);
|
|
23843
24026
|
return await operation;
|
|
23844
24027
|
}
|
|
24028
|
+
async #replaceExecutionPreparation(existing, options) {
|
|
24029
|
+
const desiredConfigOptions = existing.prepared().configOptions;
|
|
24030
|
+
const operation = (async () => {
|
|
24031
|
+
try {
|
|
24032
|
+
this.#sessions.delete(options.sessionId);
|
|
24033
|
+
await existing.close();
|
|
24034
|
+
this.#store.remove(options.sessionId);
|
|
24035
|
+
const runtime = await AcpProcessSession.start(options, () => this.#observer, this.#store);
|
|
24036
|
+
try {
|
|
24037
|
+
for (const desired of desiredConfigOptions) {
|
|
24038
|
+
const current = runtime.prepared().configOptions.find((option2) => option2.id === desired.id);
|
|
24039
|
+
if (current === void 0 || current.type !== desired.type) {
|
|
24040
|
+
continue;
|
|
24041
|
+
}
|
|
24042
|
+
if (desired.type === "boolean") {
|
|
24043
|
+
if (current.booleanValue !== desired.booleanValue) {
|
|
24044
|
+
await runtime.configure({
|
|
24045
|
+
...options,
|
|
24046
|
+
booleanValue: desired.booleanValue,
|
|
24047
|
+
configId: desired.id,
|
|
24048
|
+
requestId: `execution-prepare-${desired.id}`,
|
|
24049
|
+
value: "",
|
|
24050
|
+
valueType: "boolean"
|
|
24051
|
+
});
|
|
24052
|
+
}
|
|
24053
|
+
continue;
|
|
24054
|
+
}
|
|
24055
|
+
if (current.currentValue !== desired.currentValue && current.values.some((value) => value.value === desired.currentValue)) {
|
|
24056
|
+
await runtime.configure({
|
|
24057
|
+
...options,
|
|
24058
|
+
booleanValue: false,
|
|
24059
|
+
configId: desired.id,
|
|
24060
|
+
requestId: `execution-prepare-${desired.id}`,
|
|
24061
|
+
value: desired.currentValue,
|
|
24062
|
+
valueType: "select"
|
|
24063
|
+
});
|
|
24064
|
+
}
|
|
24065
|
+
}
|
|
24066
|
+
} catch (error61) {
|
|
24067
|
+
await runtime.close();
|
|
24068
|
+
this.#store.remove(options.sessionId);
|
|
24069
|
+
throw error61;
|
|
24070
|
+
}
|
|
24071
|
+
this.#sessions.set(options.sessionId, runtime);
|
|
24072
|
+
return runtime;
|
|
24073
|
+
} finally {
|
|
24074
|
+
this.#preparing.delete(options.sessionId);
|
|
24075
|
+
}
|
|
24076
|
+
})();
|
|
24077
|
+
this.#preparing.set(options.sessionId, operation);
|
|
24078
|
+
return await operation;
|
|
24079
|
+
}
|
|
23845
24080
|
prepareSession = async (options) => {
|
|
23846
24081
|
const stored = this.#store.read(options.sessionId);
|
|
23847
24082
|
if (stored instanceof DeletedAcpStoredSession) {
|
|
@@ -23880,6 +24115,35 @@ var AcpSessionManager = class {
|
|
|
23880
24115
|
const runtime = await this.#startPreparation(options);
|
|
23881
24116
|
return runtime.prepared();
|
|
23882
24117
|
};
|
|
24118
|
+
prepareExecutionSession = async (options) => {
|
|
24119
|
+
const pending = this.#preparing.get(options.sessionId);
|
|
24120
|
+
if (pending !== void 0) {
|
|
24121
|
+
await pending;
|
|
24122
|
+
return await this.prepareExecutionSession(options);
|
|
24123
|
+
}
|
|
24124
|
+
const existing = this.#sessions.get(options.sessionId);
|
|
24125
|
+
if (existing === void 0) {
|
|
24126
|
+
return (await this.#startPreparation(options)).prepared();
|
|
24127
|
+
}
|
|
24128
|
+
if (!existing.belongsTo(options.agent.id, options.cwd, options.additionalDirectories)) {
|
|
24129
|
+
throw new AcpExecutionError(
|
|
24130
|
+
"The agent or workspace cannot change after a conversation has started",
|
|
24131
|
+
{},
|
|
24132
|
+
"session_identity_mismatch"
|
|
24133
|
+
);
|
|
24134
|
+
}
|
|
24135
|
+
if (existing.usesEnvironment(options.agent.environment)) {
|
|
24136
|
+
return existing.prepared();
|
|
24137
|
+
}
|
|
24138
|
+
if (!existing.canRebind()) {
|
|
24139
|
+
throw new AcpExecutionError(
|
|
24140
|
+
"The execution environment cannot change after a conversation has started",
|
|
24141
|
+
{},
|
|
24142
|
+
"session_identity_mismatch"
|
|
24143
|
+
);
|
|
24144
|
+
}
|
|
24145
|
+
return (await this.#replaceExecutionPreparation(existing, options)).prepared();
|
|
24146
|
+
};
|
|
23883
24147
|
prepareNativeSessionBrowser = async (options) => {
|
|
23884
24148
|
const pending = this.#nativeBrowserPreparing.get(options.sessionId);
|
|
23885
24149
|
if (pending !== void 0) {
|
|
@@ -23924,6 +24188,47 @@ var AcpSessionManager = class {
|
|
|
23924
24188
|
}
|
|
23925
24189
|
}
|
|
23926
24190
|
};
|
|
24191
|
+
steerPrompt = async (options) => {
|
|
24192
|
+
if (this.#activeCommandIds.get(options.sessionId) !== options.targetCommandId) {
|
|
24193
|
+
throw new AcpExecutionError("The target turn is no longer active", {}, "steering_target_unavailable");
|
|
24194
|
+
}
|
|
24195
|
+
const pending = this.#preparing.get(options.sessionId);
|
|
24196
|
+
if (pending !== void 0) {
|
|
24197
|
+
await pending;
|
|
24198
|
+
}
|
|
24199
|
+
if (this.#activeCommandIds.get(options.sessionId) !== options.targetCommandId) {
|
|
24200
|
+
throw new AcpExecutionError("The target turn is no longer active", {}, "steering_target_unavailable");
|
|
24201
|
+
}
|
|
24202
|
+
const runtime = this.#sessions.get(options.sessionId);
|
|
24203
|
+
if (runtime === void 0 || !runtime.belongsTo(options.agent.id, options.cwd, options.additionalDirectories)) {
|
|
24204
|
+
throw new AcpExecutionError(
|
|
24205
|
+
"The target turn execution context is unavailable",
|
|
24206
|
+
{},
|
|
24207
|
+
"steering_target_unavailable"
|
|
24208
|
+
);
|
|
24209
|
+
}
|
|
24210
|
+
const deadlineController = new AbortController();
|
|
24211
|
+
const deadline = setTimeout(
|
|
24212
|
+
() => deadlineController.abort(
|
|
24213
|
+
new AcpExecutionError("The steering request exceeded its deadline", {}, "steering_timeout")
|
|
24214
|
+
),
|
|
24215
|
+
options.agent.promptTimeoutMilliseconds
|
|
24216
|
+
);
|
|
24217
|
+
deadline.unref();
|
|
24218
|
+
try {
|
|
24219
|
+
return await runtime.steer({
|
|
24220
|
+
...options,
|
|
24221
|
+
signal: AbortSignal.any([options.signal, deadlineController.signal])
|
|
24222
|
+
});
|
|
24223
|
+
} catch (error61) {
|
|
24224
|
+
if (error61 instanceof AcpExecutionError) {
|
|
24225
|
+
throw error61;
|
|
24226
|
+
}
|
|
24227
|
+
throw new AcpExecutionError("ACP agent steering failed", { cause: error61 }, "steering_failed");
|
|
24228
|
+
} finally {
|
|
24229
|
+
clearTimeout(deadline);
|
|
24230
|
+
}
|
|
24231
|
+
};
|
|
23927
24232
|
runPrompt = async (options) => {
|
|
23928
24233
|
const stored = this.#store.read(options.sessionId);
|
|
23929
24234
|
if (stored instanceof FoundAcpStoredSession && this.#nativeOperations.has(`${stored.session.agentId}:${stored.session.nativeSessionId}`)) {
|
|
@@ -23948,6 +24253,7 @@ var AcpSessionManager = class {
|
|
|
23948
24253
|
signal: AbortSignal.any([options.signal, deadlineController.signal])
|
|
23949
24254
|
};
|
|
23950
24255
|
this.#activeSessionIds.add(options.sessionId);
|
|
24256
|
+
this.#activeCommandIds.set(options.sessionId, options.commandId);
|
|
23951
24257
|
try {
|
|
23952
24258
|
if (this.#cancellationRequests.has(options.sessionId)) {
|
|
23953
24259
|
return { stopReason: "cancelled" };
|
|
@@ -23987,6 +24293,9 @@ var AcpSessionManager = class {
|
|
|
23987
24293
|
} finally {
|
|
23988
24294
|
clearTimeout(deadline);
|
|
23989
24295
|
this.#activeSessionIds.delete(options.sessionId);
|
|
24296
|
+
if (this.#activeCommandIds.get(options.sessionId) === options.commandId) {
|
|
24297
|
+
this.#activeCommandIds.delete(options.sessionId);
|
|
24298
|
+
}
|
|
23990
24299
|
this.#cancellationRequests.delete(options.sessionId);
|
|
23991
24300
|
}
|
|
23992
24301
|
};
|
|
@@ -24011,6 +24320,7 @@ var AcpSessionManager = class {
|
|
|
24011
24320
|
this.#nativeBrowserSessions.clear();
|
|
24012
24321
|
await Promise.all([...sessions, ...nativeBrowserSessions].map(async (session) => await session.close()));
|
|
24013
24322
|
};
|
|
24323
|
+
hasPreparedSession = (sessionId, agentId, cwd, additionalDirectories) => this.#sessions.get(sessionId)?.belongsTo(agentId, cwd, additionalDirectories) === true;
|
|
24014
24324
|
ensureSession = async (options) => {
|
|
24015
24325
|
const existing = this.#sessions.get(options.sessionId);
|
|
24016
24326
|
if (existing !== void 0) {
|
|
@@ -24119,6 +24429,68 @@ var AcpSessionManager = class {
|
|
|
24119
24429
|
this.#nativeOperations.delete(key);
|
|
24120
24430
|
}
|
|
24121
24431
|
};
|
|
24432
|
+
forkSessionAtTurn = async (options, sourceSessionId, forkPoint) => {
|
|
24433
|
+
if (sourceSessionId === options.sessionId) {
|
|
24434
|
+
throw new AcpExecutionError(
|
|
24435
|
+
"The fork destination must be a new conversation",
|
|
24436
|
+
{},
|
|
24437
|
+
"session_identity_mismatch"
|
|
24438
|
+
);
|
|
24439
|
+
}
|
|
24440
|
+
const source = this.#store.read(sourceSessionId);
|
|
24441
|
+
if (!(source instanceof FoundAcpStoredSession) || !source.session.prompted) {
|
|
24442
|
+
throw new AcpExecutionError(
|
|
24443
|
+
"The source conversation has no resumable native Agent session",
|
|
24444
|
+
{},
|
|
24445
|
+
"native_session_not_found"
|
|
24446
|
+
);
|
|
24447
|
+
}
|
|
24448
|
+
if (source.session.agentId !== options.agent.id || source.session.cwd !== options.cwd || !arraysEqual(source.session.additionalDirectories, options.additionalDirectories)) {
|
|
24449
|
+
throw new AcpExecutionError(
|
|
24450
|
+
"The source conversation execution target does not match the fork request",
|
|
24451
|
+
{},
|
|
24452
|
+
"native_session_target_changed"
|
|
24453
|
+
);
|
|
24454
|
+
}
|
|
24455
|
+
const key = `${options.agent.id}:${source.session.nativeSessionId}`;
|
|
24456
|
+
const linked = this.#store.findNative(options.agent.id, source.session.nativeSessionId);
|
|
24457
|
+
if (this.#nativeOperations.has(key) || linked.some((entry) => this.#activeSessionIds.has(entry.sessionId) || this.#preparing.has(entry.sessionId))) {
|
|
24458
|
+
throw new AcpExecutionError(
|
|
24459
|
+
"Wait for the source conversation's running operation to finish",
|
|
24460
|
+
{},
|
|
24461
|
+
"session_busy"
|
|
24462
|
+
);
|
|
24463
|
+
}
|
|
24464
|
+
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) {
|
|
24465
|
+
throw new AcpExecutionError("The destination conversation already exists", {}, "session_identity_mismatch");
|
|
24466
|
+
}
|
|
24467
|
+
this.#nativeOperations.add(key);
|
|
24468
|
+
try {
|
|
24469
|
+
const runtime = await this.#startSessionForkAtTurnPreparation(
|
|
24470
|
+
options,
|
|
24471
|
+
source.session.nativeSessionId,
|
|
24472
|
+
forkPoint
|
|
24473
|
+
);
|
|
24474
|
+
const openedKey = `${options.agent.id}:${runtime.nativeSessionId()}`;
|
|
24475
|
+
this.#nativeOperations.add(openedKey);
|
|
24476
|
+
try {
|
|
24477
|
+
return {
|
|
24478
|
+
history: await runtime.loadHistory(options.signal),
|
|
24479
|
+
prepared: runtime.prepared(),
|
|
24480
|
+
sessionId: options.sessionId
|
|
24481
|
+
};
|
|
24482
|
+
} catch (error61) {
|
|
24483
|
+
this.#sessions.delete(options.sessionId);
|
|
24484
|
+
this.#store.remove(options.sessionId);
|
|
24485
|
+
await runtime.closeProcess();
|
|
24486
|
+
throw error61;
|
|
24487
|
+
} finally {
|
|
24488
|
+
this.#nativeOperations.delete(openedKey);
|
|
24489
|
+
}
|
|
24490
|
+
} finally {
|
|
24491
|
+
this.#nativeOperations.delete(key);
|
|
24492
|
+
}
|
|
24493
|
+
};
|
|
24122
24494
|
deleteNativeSession = async (options, nativeSessionId) => {
|
|
24123
24495
|
const runtime = await this.#ensureNativeSessionBrowser(options);
|
|
24124
24496
|
const key = `${options.agent.id}:${nativeSessionId}`;
|
|
@@ -24263,7 +24635,8 @@ var LocalBotGrant = class {
|
|
|
24263
24635
|
revocationEpoch;
|
|
24264
24636
|
workspaceIdentityDigest;
|
|
24265
24637
|
workspacePath;
|
|
24266
|
-
|
|
24638
|
+
workspaceRef;
|
|
24639
|
+
constructor(localGrantId, botId, behaviorRevisionId, behaviorDigest, bindingId, bindingRevision, agent, agentIdentityDigest, workspaceRef, workspacePath, workspaceIdentityDigest, allowedDeliveryTargetIds, expiresAt, revocationEpoch) {
|
|
24267
24640
|
this.localGrantId = localGrantId;
|
|
24268
24641
|
this.botId = botId;
|
|
24269
24642
|
this.behaviorRevisionId = behaviorRevisionId;
|
|
@@ -24272,6 +24645,7 @@ var LocalBotGrant = class {
|
|
|
24272
24645
|
this.bindingRevision = bindingRevision;
|
|
24273
24646
|
this.agent = agent;
|
|
24274
24647
|
this.agentIdentityDigest = agentIdentityDigest;
|
|
24648
|
+
this.workspaceRef = workspaceRef;
|
|
24275
24649
|
this.workspacePath = workspacePath;
|
|
24276
24650
|
this.workspaceIdentityDigest = workspaceIdentityDigest;
|
|
24277
24651
|
this.allowedDeliveryTargetIds = Object.freeze([...allowedDeliveryTargetIds]);
|
|
@@ -24456,7 +24830,7 @@ var LocalBotGrantStore = class {
|
|
|
24456
24830
|
WHERE local_grant_id = ? AND bot_id = ?
|
|
24457
24831
|
AND behavior_revision_id = ? AND behavior_digest = ?
|
|
24458
24832
|
AND binding_id = ? AND binding_revision = ?
|
|
24459
|
-
AND agent_ref = ?
|
|
24833
|
+
AND agent_ref = ?
|
|
24460
24834
|
AND revoked_at IS NULL AND expires_at > ?`
|
|
24461
24835
|
).get(
|
|
24462
24836
|
command.localGrantId,
|
|
@@ -24466,7 +24840,6 @@ var LocalBotGrantStore = class {
|
|
|
24466
24840
|
command.bindingId,
|
|
24467
24841
|
command.bindingRevision,
|
|
24468
24842
|
command.agentId,
|
|
24469
|
-
command.directoryId,
|
|
24470
24843
|
now
|
|
24471
24844
|
);
|
|
24472
24845
|
if (row === void 0) {
|
|
@@ -24489,7 +24862,8 @@ var LocalBotGrantStore = class {
|
|
|
24489
24862
|
revalidateExecutable(agent.agentIdentity)
|
|
24490
24863
|
]);
|
|
24491
24864
|
signal.throwIfAborted();
|
|
24492
|
-
const
|
|
24865
|
+
const workspaceRef = rowString(row, "workspace_ref");
|
|
24866
|
+
const workspacePath = await directories.resolve(bindingAuthorityId, workspaceRef, signal);
|
|
24493
24867
|
const currentAgentDigest = agentDigest(agent);
|
|
24494
24868
|
const currentWorkspaceDigest = await workspaceDigest(workspacePath);
|
|
24495
24869
|
signal.throwIfAborted();
|
|
@@ -24515,6 +24889,7 @@ var LocalBotGrantStore = class {
|
|
|
24515
24889
|
command.bindingRevision,
|
|
24516
24890
|
agent,
|
|
24517
24891
|
currentAgentDigest,
|
|
24892
|
+
workspaceRef,
|
|
24518
24893
|
workspacePath,
|
|
24519
24894
|
currentWorkspaceDigest,
|
|
24520
24895
|
approvedTargets,
|
|
@@ -24683,7 +25058,7 @@ var BotMessageCommandError = class extends Error {
|
|
|
24683
25058
|
this.name = "BotMessageCommandError";
|
|
24684
25059
|
}
|
|
24685
25060
|
};
|
|
24686
|
-
function
|
|
25061
|
+
function isRecord7(value) {
|
|
24687
25062
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24688
25063
|
}
|
|
24689
25064
|
function requiredEnvironment(environment, name) {
|
|
@@ -24734,21 +25109,21 @@ function decodeResponse(encoded) {
|
|
|
24734
25109
|
cause
|
|
24735
25110
|
});
|
|
24736
25111
|
}
|
|
24737
|
-
if (!
|
|
25112
|
+
if (!isRecord7(value) || typeof value["ok"] !== "boolean") {
|
|
24738
25113
|
throw new BotMessageCommandError("bot_service_unavailable", "The local Bot service returned invalid data");
|
|
24739
25114
|
}
|
|
24740
25115
|
if (value["ok"] === true && typeof value["outboundMessageId"] === "string") {
|
|
24741
25116
|
return value["outboundMessageId"];
|
|
24742
25117
|
}
|
|
24743
25118
|
const error61 = value["error"];
|
|
24744
|
-
if (value["ok"] === false &&
|
|
25119
|
+
if (value["ok"] === false && isRecord7(error61) && typeof error61["code"] === "string" && typeof error61["message"] === "string") {
|
|
24745
25120
|
throw new BotMessageCommandError(error61["code"], error61["message"]);
|
|
24746
25121
|
}
|
|
24747
25122
|
throw new BotMessageCommandError("bot_service_unavailable", "The local Bot service returned invalid data");
|
|
24748
25123
|
}
|
|
24749
25124
|
async function requestLocalBotService(socketPath, payload, signal) {
|
|
24750
25125
|
signal.throwIfAborted();
|
|
24751
|
-
return await new Promise((
|
|
25126
|
+
return await new Promise((resolve6, reject) => {
|
|
24752
25127
|
const socket = createConnection(socketPath);
|
|
24753
25128
|
const chunks = [];
|
|
24754
25129
|
let length = 0;
|
|
@@ -24797,7 +25172,7 @@ async function requestLocalBotService(socketPath, payload, signal) {
|
|
|
24797
25172
|
finished = true;
|
|
24798
25173
|
signal.removeEventListener("abort", abort);
|
|
24799
25174
|
try {
|
|
24800
|
-
|
|
25175
|
+
resolve6(decodeResponse(Buffer.concat(chunks).toString("utf8")));
|
|
24801
25176
|
} catch (error61) {
|
|
24802
25177
|
reject(error61);
|
|
24803
25178
|
} finally {
|
|
@@ -24850,7 +25225,7 @@ var BotOutboundIpcRequest = class {
|
|
|
24850
25225
|
this.text = text;
|
|
24851
25226
|
}
|
|
24852
25227
|
};
|
|
24853
|
-
function
|
|
25228
|
+
function isRecord8(value) {
|
|
24854
25229
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24855
25230
|
}
|
|
24856
25231
|
function decodeRequest(encoded) {
|
|
@@ -24860,7 +25235,7 @@ function decodeRequest(encoded) {
|
|
|
24860
25235
|
} catch (cause) {
|
|
24861
25236
|
throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid", { cause });
|
|
24862
25237
|
}
|
|
24863
|
-
if (!
|
|
25238
|
+
if (!isRecord8(value)) {
|
|
24864
25239
|
throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
|
|
24865
25240
|
}
|
|
24866
25241
|
const keys = Object.keys(value);
|
|
@@ -24910,10 +25285,10 @@ async function decodeRelayResponse(response) {
|
|
|
24910
25285
|
cause
|
|
24911
25286
|
});
|
|
24912
25287
|
}
|
|
24913
|
-
if (response.status === 202 &&
|
|
25288
|
+
if (response.status === 202 && isRecord8(value) && typeof value["outboundMessageId"] === "string") {
|
|
24914
25289
|
return value["outboundMessageId"];
|
|
24915
25290
|
}
|
|
24916
|
-
if (
|
|
25291
|
+
if (isRecord8(value) && isRecord8(value["error"])) {
|
|
24917
25292
|
const error61 = value["error"];
|
|
24918
25293
|
if (typeof error61["code"] === "string" && typeof error61["message"] === "string") {
|
|
24919
25294
|
throw new LocalBotAuthorizationError(error61["code"], error61["message"]);
|
|
@@ -24946,17 +25321,17 @@ var BotOutboundIpcServer = class {
|
|
|
24946
25321
|
if (this.#usesFilesystemSocket) {
|
|
24947
25322
|
await mkdir(dirname3(this.#socketPath), { mode: 448, recursive: true });
|
|
24948
25323
|
await unlink(this.#socketPath).catch((error61) => {
|
|
24949
|
-
if (!
|
|
25324
|
+
if (!isRecord8(error61) || error61["code"] !== "ENOENT") {
|
|
24950
25325
|
throw error61;
|
|
24951
25326
|
}
|
|
24952
25327
|
});
|
|
24953
25328
|
}
|
|
24954
|
-
await new Promise((
|
|
25329
|
+
await new Promise((resolve6, reject) => {
|
|
24955
25330
|
const fail = (error61) => reject(error61);
|
|
24956
25331
|
this.#server.once("error", fail);
|
|
24957
25332
|
this.#server.listen(this.#socketPath, () => {
|
|
24958
25333
|
this.#server.removeListener("error", fail);
|
|
24959
|
-
|
|
25334
|
+
resolve6();
|
|
24960
25335
|
});
|
|
24961
25336
|
});
|
|
24962
25337
|
if (this.#usesFilesystemSocket) {
|
|
@@ -24969,10 +25344,10 @@ var BotOutboundIpcServer = class {
|
|
|
24969
25344
|
};
|
|
24970
25345
|
close = async () => {
|
|
24971
25346
|
if (this.#server.listening) {
|
|
24972
|
-
await new Promise((
|
|
25347
|
+
await new Promise((resolve6, reject) => {
|
|
24973
25348
|
this.#server.close((error61) => {
|
|
24974
25349
|
if (error61 === void 0) {
|
|
24975
|
-
|
|
25350
|
+
resolve6();
|
|
24976
25351
|
return;
|
|
24977
25352
|
}
|
|
24978
25353
|
reject(error61);
|
|
@@ -24981,7 +25356,7 @@ var BotOutboundIpcServer = class {
|
|
|
24981
25356
|
}
|
|
24982
25357
|
if (this.#usesFilesystemSocket) {
|
|
24983
25358
|
await unlink(this.#socketPath).catch((error61) => {
|
|
24984
|
-
if (!
|
|
25359
|
+
if (!isRecord8(error61) || error61["code"] !== "ENOENT") {
|
|
24985
25360
|
throw error61;
|
|
24986
25361
|
}
|
|
24987
25362
|
});
|
|
@@ -25228,7 +25603,7 @@ var ManagedNpmPackageError = class extends Error {
|
|
|
25228
25603
|
this.name = "ManagedNpmPackageError";
|
|
25229
25604
|
}
|
|
25230
25605
|
};
|
|
25231
|
-
function
|
|
25606
|
+
function isRecord9(value) {
|
|
25232
25607
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25233
25608
|
}
|
|
25234
25609
|
function packagePath(root, packageName) {
|
|
@@ -25250,7 +25625,7 @@ async function readJsonRecord(path2, maximumBytes) {
|
|
|
25250
25625
|
);
|
|
25251
25626
|
}
|
|
25252
25627
|
const value = JSON.parse(await handle.readFile({ encoding: "utf8" }));
|
|
25253
|
-
if (!
|
|
25628
|
+
if (!isRecord9(value)) {
|
|
25254
25629
|
throw new ManagedNpmPackageError(
|
|
25255
25630
|
"managed_package_verification_failed",
|
|
25256
25631
|
"The managed npm package metadata is invalid"
|
|
@@ -25276,7 +25651,7 @@ function readBinPath(packageMetadata, executableName) {
|
|
|
25276
25651
|
if (typeof bin === "string") {
|
|
25277
25652
|
return bin;
|
|
25278
25653
|
}
|
|
25279
|
-
if (
|
|
25654
|
+
if (isRecord9(bin) && typeof bin[executableName] === "string") {
|
|
25280
25655
|
return bin[executableName];
|
|
25281
25656
|
}
|
|
25282
25657
|
throw new ManagedNpmPackageError(
|
|
@@ -25292,7 +25667,7 @@ function verifyPackageLockEntry(lock, definition, verifyDependencyClosure) {
|
|
|
25292
25667
|
);
|
|
25293
25668
|
}
|
|
25294
25669
|
const packages = lock["packages"];
|
|
25295
|
-
if (!
|
|
25670
|
+
if (!isRecord9(packages)) {
|
|
25296
25671
|
throw new ManagedNpmPackageError(
|
|
25297
25672
|
"managed_package_verification_failed",
|
|
25298
25673
|
"The managed npm package lockfile is invalid"
|
|
@@ -25306,7 +25681,7 @@ function verifyPackageLockEntry(lock, definition, verifyDependencyClosure) {
|
|
|
25306
25681
|
if (verifyDependencyClosure && normalizedKey.length > 0) {
|
|
25307
25682
|
let resolved;
|
|
25308
25683
|
try {
|
|
25309
|
-
if (!normalizedKey.split("/").includes("node_modules") || !
|
|
25684
|
+
if (!normalizedKey.split("/").includes("node_modules") || !isRecord9(candidate) || typeof candidate["version"] !== "string" || candidate["version"].length === 0 || typeof candidate["integrity"] !== "string" || !/^sha512-[A-Za-z0-9+/]{86}==$/.test(candidate["integrity"]) || typeof candidate["resolved"] !== "string") {
|
|
25310
25685
|
throw new Error("Invalid locked dependency");
|
|
25311
25686
|
}
|
|
25312
25687
|
resolved = new URL(candidate["resolved"]);
|
|
@@ -25329,7 +25704,7 @@ function verifyPackageLockEntry(lock, definition, verifyDependencyClosure) {
|
|
|
25329
25704
|
matches += 1;
|
|
25330
25705
|
}
|
|
25331
25706
|
}
|
|
25332
|
-
if (matches !== 1 || !
|
|
25707
|
+
if (matches !== 1 || !isRecord9(entry) || entry["integrity"] !== definition.integrity || entry["resolved"] !== definition.tarballUrl || entry["version"] !== definition.version) {
|
|
25333
25708
|
throw new ManagedNpmPackageError(
|
|
25334
25709
|
"managed_package_verification_failed",
|
|
25335
25710
|
"The managed npm package lockfile does not match the pinned artifact"
|
|
@@ -25959,7 +26334,7 @@ var ManagedAgentArchiveError = class extends Error {
|
|
|
25959
26334
|
this.name = "ManagedAgentArchiveError";
|
|
25960
26335
|
}
|
|
25961
26336
|
};
|
|
25962
|
-
function
|
|
26337
|
+
function isRecord10(value) {
|
|
25963
26338
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
25964
26339
|
}
|
|
25965
26340
|
function isContainedPath3(root, candidate) {
|
|
@@ -26016,7 +26391,7 @@ async function readManifest(path2) {
|
|
|
26016
26391
|
);
|
|
26017
26392
|
}
|
|
26018
26393
|
const parsed = JSON.parse(await handle.readFile({ encoding: "utf8" }));
|
|
26019
|
-
if (!
|
|
26394
|
+
if (!isRecord10(parsed)) {
|
|
26020
26395
|
throw new ManagedAgentArchiveError(
|
|
26021
26396
|
"managed_archive_verification_failed",
|
|
26022
26397
|
"The managed Agent archive manifest is invalid"
|
|
@@ -26709,7 +27084,7 @@ async function probeAcpReadiness(specification, agent, environment, defaultWorks
|
|
|
26709
27084
|
await specification.verifyAcp(connection, initialized, defaultWorkspace, controller.signal);
|
|
26710
27085
|
return new VerifiedAcpReadiness(
|
|
26711
27086
|
normalizedVersion(initialized.agentInfo?.version ?? ""),
|
|
26712
|
-
normalizeAcpCapabilities(initialized
|
|
27087
|
+
normalizeAcpCapabilities(initialized)
|
|
26713
27088
|
);
|
|
26714
27089
|
} catch (error61) {
|
|
26715
27090
|
if (signal.aborted) {
|
|
@@ -26895,7 +27270,9 @@ var IDENTIFIER_PATTERN6 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
|
26895
27270
|
var TOKEN_PATTERN2 = /^[a-zA-Z0-9_-]{32,256}$/;
|
|
26896
27271
|
var MAX_CONNECTION_FILE_LENGTH = 16 * 1024;
|
|
26897
27272
|
var CLAIM_RESPONSE_KEYS = ["channelId", "daemonToken", "runtimeId"];
|
|
26898
|
-
var
|
|
27273
|
+
var REDEEM_RESPONSE_KEYS = ["channelId", "runtimeCredential", "runtimeId"];
|
|
27274
|
+
var LEGACY_SAVED_CONNECTION_KEYS = ["defaultWorkspace", "channelId", "daemonToken", "relayOrigin"];
|
|
27275
|
+
var SAVED_CONNECTION_KEYS = ["defaultWorkspace", "channelId", "relayOrigin", "runtimeCredential"];
|
|
26899
27276
|
var PairingClientError = class extends Error {
|
|
26900
27277
|
code;
|
|
26901
27278
|
constructor(code, message, options = {}) {
|
|
@@ -26904,7 +27281,7 @@ var PairingClientError = class extends Error {
|
|
|
26904
27281
|
this.name = "PairingClientError";
|
|
26905
27282
|
}
|
|
26906
27283
|
};
|
|
26907
|
-
function
|
|
27284
|
+
function isRecord11(value) {
|
|
26908
27285
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26909
27286
|
}
|
|
26910
27287
|
function hasExactKeys(value, expectedKeys) {
|
|
@@ -26932,7 +27309,7 @@ function readSingleOption(arguments_, option2) {
|
|
|
26932
27309
|
function assertKnownArguments(arguments_) {
|
|
26933
27310
|
for (let index = 0; index < arguments_.length; index += 2) {
|
|
26934
27311
|
const option2 = arguments_[index];
|
|
26935
|
-
if (option2 !== "--url" && option2 !== "--code" && option2 !== "--workspace") {
|
|
27312
|
+
if (option2 !== "--url" && option2 !== "--code" && option2 !== "--pairing" && option2 !== "--workspace") {
|
|
26936
27313
|
throw new PairingClientError("invalid_arguments", `Unknown pairing option: ${option2 ?? "missing option"}`);
|
|
26937
27314
|
}
|
|
26938
27315
|
}
|
|
@@ -26972,10 +27349,17 @@ function parsePairCommand(arguments_) {
|
|
|
26972
27349
|
assertKnownArguments(arguments_);
|
|
26973
27350
|
return {
|
|
26974
27351
|
code: parsePairingCode(readSingleOption(arguments_, "--code")),
|
|
27352
|
+
pairingId: arguments_.includes("--pairing") ? validatePairingId(readSingleOption(arguments_, "--pairing")) : "",
|
|
26975
27353
|
relayOrigin: parseRelayOrigin(readSingleOption(arguments_, "--url")),
|
|
26976
27354
|
workspace: arguments_.includes("--workspace") ? readSingleOption(arguments_, "--workspace") : loadDefaultWorkspace()
|
|
26977
27355
|
};
|
|
26978
27356
|
}
|
|
27357
|
+
function validatePairingId(value) {
|
|
27358
|
+
if (!IDENTIFIER_PATTERN6.test(value)) {
|
|
27359
|
+
throw new PairingClientError("invalid_pairing_id", "The Runtime pairing ID is invalid");
|
|
27360
|
+
}
|
|
27361
|
+
return value;
|
|
27362
|
+
}
|
|
26979
27363
|
function parseChannelArgument(arguments_) {
|
|
26980
27364
|
if (arguments_.length !== 2 || arguments_[0] !== "--channel") {
|
|
26981
27365
|
throw new PairingClientError("invalid_arguments", "Usage: mobius start --channel <channel-id>");
|
|
@@ -27020,9 +27404,9 @@ async function readJsonResponse(response) {
|
|
|
27020
27404
|
}
|
|
27021
27405
|
}
|
|
27022
27406
|
function readRelayError(value) {
|
|
27023
|
-
if (
|
|
27407
|
+
if (isRecord11(value)) {
|
|
27024
27408
|
const error61 = value["error"];
|
|
27025
|
-
if (
|
|
27409
|
+
if (isRecord11(error61)) {
|
|
27026
27410
|
const code = error61["code"];
|
|
27027
27411
|
const message = error61["message"];
|
|
27028
27412
|
if (typeof code === "string" && typeof message === "string") {
|
|
@@ -27032,17 +27416,17 @@ function readRelayError(value) {
|
|
|
27032
27416
|
}
|
|
27033
27417
|
return new PairingClientError("pairing_failed", "The relay could not pair this machine");
|
|
27034
27418
|
}
|
|
27035
|
-
function
|
|
27036
|
-
if (!
|
|
27419
|
+
function decodePairingResponse(value, credentialField, expectedKeys) {
|
|
27420
|
+
if (!isRecord11(value) || !hasExactKeys(value, expectedKeys)) {
|
|
27037
27421
|
throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
|
|
27038
27422
|
}
|
|
27039
27423
|
const channelId = value["channelId"];
|
|
27040
|
-
const
|
|
27424
|
+
const runtimeCredential = value[credentialField];
|
|
27041
27425
|
const runtimeId = value["runtimeId"];
|
|
27042
|
-
if (typeof channelId !== "string" || !IDENTIFIER_PATTERN6.test(channelId) || typeof
|
|
27426
|
+
if (typeof channelId !== "string" || !IDENTIFIER_PATTERN6.test(channelId) || typeof runtimeCredential !== "string" || !TOKEN_PATTERN2.test(runtimeCredential) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN6.test(runtimeId)) {
|
|
27043
27427
|
throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
|
|
27044
27428
|
}
|
|
27045
|
-
return { channelId,
|
|
27429
|
+
return { channelId, runtimeCredential, runtimeId };
|
|
27046
27430
|
}
|
|
27047
27431
|
async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
|
|
27048
27432
|
const agents = localAgents.map((agent) => ({
|
|
@@ -27052,7 +27436,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
27052
27436
|
id: agent.id,
|
|
27053
27437
|
label: agent.label
|
|
27054
27438
|
}));
|
|
27055
|
-
const endpoint = mobiusApiUrl(options.relayOrigin, "/pairings/claim");
|
|
27439
|
+
const endpoint = options.pairingId.length > 0 ? mobiusApiUrl(options.relayOrigin, `/v1/runtime-pairings/${encodeURIComponent(options.pairingId)}/redeem`) : mobiusApiUrl(options.relayOrigin, "/pairings/claim");
|
|
27056
27440
|
let response;
|
|
27057
27441
|
try {
|
|
27058
27442
|
response = await fetch3(endpoint, {
|
|
@@ -27075,10 +27459,10 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
27075
27459
|
if (!response.ok) {
|
|
27076
27460
|
throw readRelayError(value);
|
|
27077
27461
|
}
|
|
27078
|
-
return
|
|
27462
|
+
return options.pairingId.length > 0 ? decodePairingResponse(value, "runtimeCredential", REDEEM_RESPONSE_KEYS) : decodePairingResponse(value, "daemonToken", CLAIM_RESPONSE_KEYS);
|
|
27079
27463
|
}
|
|
27080
|
-
async function persistConnection(channelId, relayOrigin,
|
|
27081
|
-
const connectionsDirectory = join14(readStateDirectory(), "connections");
|
|
27464
|
+
async function persistConnection(channelId, relayOrigin, runtimeCredential, defaultWorkspace, environment) {
|
|
27465
|
+
const connectionsDirectory = join14(readStateDirectory(environment), "connections");
|
|
27082
27466
|
await mkdir4(connectionsDirectory, { mode: 448, recursive: true });
|
|
27083
27467
|
const connectionPath = join14(connectionsDirectory, `${channelId}.json`);
|
|
27084
27468
|
const temporaryPath = join14(connectionsDirectory, `.${channelId}.${randomUUID3()}.tmp`);
|
|
@@ -27088,8 +27472,8 @@ async function persistConnection(channelId, relayOrigin, daemonToken2, defaultWo
|
|
|
27088
27472
|
{
|
|
27089
27473
|
defaultWorkspace,
|
|
27090
27474
|
channelId,
|
|
27091
|
-
|
|
27092
|
-
|
|
27475
|
+
relayOrigin: relayOrigin.toString(),
|
|
27476
|
+
runtimeCredential
|
|
27093
27477
|
},
|
|
27094
27478
|
null,
|
|
27095
27479
|
2
|
|
@@ -27101,25 +27485,25 @@ async function persistConnection(channelId, relayOrigin, daemonToken2, defaultWo
|
|
|
27101
27485
|
return connectionPath;
|
|
27102
27486
|
}
|
|
27103
27487
|
function decodeSavedConnection(value, expectedChannelId) {
|
|
27104
|
-
if (!
|
|
27488
|
+
if (!isRecord11(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS) && !hasExactKeys(value, LEGACY_SAVED_CONNECTION_KEYS)) {
|
|
27105
27489
|
throw new PairingClientError("invalid_connection", "The saved connection is invalid");
|
|
27106
27490
|
}
|
|
27107
27491
|
const defaultWorkspace = value["defaultWorkspace"];
|
|
27108
27492
|
const channelId = value["channelId"];
|
|
27109
|
-
const
|
|
27493
|
+
const runtimeCredential = value["runtimeCredential"] ?? value["daemonToken"];
|
|
27110
27494
|
const relayOrigin = value["relayOrigin"];
|
|
27111
|
-
if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN6.test(channelId) || typeof
|
|
27495
|
+
if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN6.test(channelId) || typeof runtimeCredential !== "string" || !TOKEN_PATTERN2.test(runtimeCredential) || typeof relayOrigin !== "string") {
|
|
27112
27496
|
throw new PairingClientError("invalid_connection", "The saved connection is invalid");
|
|
27113
27497
|
}
|
|
27114
27498
|
return {
|
|
27115
27499
|
defaultWorkspace,
|
|
27116
27500
|
channelId,
|
|
27117
|
-
|
|
27118
|
-
|
|
27501
|
+
relayOrigin: parseRelayOrigin(relayOrigin),
|
|
27502
|
+
runtimeCredential
|
|
27119
27503
|
};
|
|
27120
27504
|
}
|
|
27121
|
-
async function readSavedConnection(channelId) {
|
|
27122
|
-
const connectionPath = join14(readStateDirectory(), "connections", `${channelId}.json`);
|
|
27505
|
+
async function readSavedConnection(channelId, environment) {
|
|
27506
|
+
const connectionPath = join14(readStateDirectory(environment), "connections", `${channelId}.json`);
|
|
27123
27507
|
let encoded = "";
|
|
27124
27508
|
const handle = await open4(connectionPath, "r");
|
|
27125
27509
|
try {
|
|
@@ -27141,8 +27525,8 @@ async function readSavedConnection(channelId) {
|
|
|
27141
27525
|
return {
|
|
27142
27526
|
defaultWorkspace: await resolveDefaultWorkspace(connection.defaultWorkspace),
|
|
27143
27527
|
channelId: connection.channelId,
|
|
27144
|
-
|
|
27145
|
-
|
|
27528
|
+
relayOrigin: connection.relayOrigin,
|
|
27529
|
+
runtimeCredential: connection.runtimeCredential
|
|
27146
27530
|
};
|
|
27147
27531
|
}
|
|
27148
27532
|
function assertInventoryUsable(inventory) {
|
|
@@ -27150,15 +27534,12 @@ function assertInventoryUsable(inventory) {
|
|
|
27150
27534
|
throw new PairingClientError("no_supported_agent", "No supported Agent is available for local discovery");
|
|
27151
27535
|
}
|
|
27152
27536
|
}
|
|
27153
|
-
function buildPairedDaemon(connection, connectionPath, inventory) {
|
|
27537
|
+
function buildPairedDaemon(connection, connectionPath, inventory, environment) {
|
|
27154
27538
|
assertInventoryUsable(inventory);
|
|
27155
|
-
const relayUrl = mobiusApiUrl(
|
|
27156
|
-
connection.relayOrigin,
|
|
27157
|
-
`/channels/${encodeURIComponent(connection.channelId)}/daemon`
|
|
27158
|
-
);
|
|
27539
|
+
const relayUrl = mobiusApiUrl(connection.relayOrigin, "/v1/runtimes/connect");
|
|
27159
27540
|
relayUrl.protocol = relayUrl.protocol === "https:" ? "wss:" : "ws:";
|
|
27160
|
-
relayUrl.searchParams.set("token", connection.
|
|
27161
|
-
const auditDatabasePath = join14(readStateDirectory(), "audit", `${connection.channelId}.sqlite`);
|
|
27541
|
+
relayUrl.searchParams.set("token", connection.runtimeCredential);
|
|
27542
|
+
const auditDatabasePath = join14(readStateDirectory(environment), "audit", `${connection.channelId}.sqlite`);
|
|
27162
27543
|
return {
|
|
27163
27544
|
channelUrl: new URL(`/channels/${encodeURIComponent(connection.channelId)}`, connection.relayOrigin).toString(),
|
|
27164
27545
|
config: createDaemonConfig(
|
|
@@ -27174,12 +27555,11 @@ function buildPairedDaemon(connection, connectionPath, inventory) {
|
|
|
27174
27555
|
connectionPath
|
|
27175
27556
|
};
|
|
27176
27557
|
}
|
|
27177
|
-
async function
|
|
27178
|
-
const options = parsePairCommand(arguments_);
|
|
27558
|
+
async function pairRuntime(options, signal, environment) {
|
|
27179
27559
|
const defaultWorkspace = await resolveDefaultWorkspace(options.workspace);
|
|
27180
27560
|
const inventory = await discoverLocalAgentInventory({
|
|
27181
27561
|
defaultWorkspace,
|
|
27182
|
-
environment
|
|
27562
|
+
environment,
|
|
27183
27563
|
signal
|
|
27184
27564
|
});
|
|
27185
27565
|
assertInventoryUsable(inventory);
|
|
@@ -27188,35 +27568,55 @@ async function pairLocalMachine(arguments_, signal = new AbortController().signa
|
|
|
27188
27568
|
const connectionPath = await persistConnection(
|
|
27189
27569
|
claim2.channelId,
|
|
27190
27570
|
options.relayOrigin,
|
|
27191
|
-
claim2.
|
|
27192
|
-
defaultWorkspace
|
|
27571
|
+
claim2.runtimeCredential,
|
|
27572
|
+
defaultWorkspace,
|
|
27573
|
+
environment
|
|
27193
27574
|
);
|
|
27194
27575
|
return buildPairedDaemon(
|
|
27195
27576
|
{
|
|
27196
27577
|
defaultWorkspace,
|
|
27197
27578
|
channelId: claim2.channelId,
|
|
27198
|
-
|
|
27199
|
-
|
|
27579
|
+
relayOrigin: options.relayOrigin,
|
|
27580
|
+
runtimeCredential: claim2.runtimeCredential
|
|
27200
27581
|
},
|
|
27201
27582
|
connectionPath,
|
|
27202
|
-
inventory
|
|
27583
|
+
inventory,
|
|
27584
|
+
environment
|
|
27203
27585
|
);
|
|
27204
27586
|
}
|
|
27205
|
-
async function
|
|
27206
|
-
|
|
27207
|
-
|
|
27208
|
-
|
|
27587
|
+
async function pairMobiusRuntime(options, signal, environment = process.env) {
|
|
27588
|
+
return await pairRuntime(
|
|
27589
|
+
{
|
|
27590
|
+
code: parsePairingCode(options.pairingCode),
|
|
27591
|
+
pairingId: validatePairingId(options.pairingId),
|
|
27592
|
+
relayOrigin: parseRelayOrigin(options.relayOrigin),
|
|
27593
|
+
workspace: options.defaultWorkspace
|
|
27594
|
+
},
|
|
27595
|
+
signal,
|
|
27596
|
+
environment
|
|
27597
|
+
);
|
|
27598
|
+
}
|
|
27599
|
+
async function pairLocalMachine(arguments_, signal = new AbortController().signal) {
|
|
27600
|
+
return await pairRuntime(parsePairCommand(arguments_), signal, process.env);
|
|
27601
|
+
}
|
|
27602
|
+
async function resumeMobiusRuntime(channelId, signal, environment = process.env) {
|
|
27603
|
+
const normalizedChannelId = validatePairingId(channelId);
|
|
27604
|
+
const connectionPath = join14(readStateDirectory(environment), "connections", `${normalizedChannelId}.json`);
|
|
27605
|
+
const connection = await readSavedConnection(normalizedChannelId, environment);
|
|
27209
27606
|
const inventory = await discoverLocalAgentInventory({
|
|
27210
27607
|
defaultWorkspace: connection.defaultWorkspace,
|
|
27211
|
-
environment
|
|
27608
|
+
environment,
|
|
27212
27609
|
signal
|
|
27213
27610
|
});
|
|
27214
|
-
return buildPairedDaemon(connection, connectionPath, inventory);
|
|
27611
|
+
return buildPairedDaemon(connection, connectionPath, inventory, environment);
|
|
27612
|
+
}
|
|
27613
|
+
async function resumeLocalMachine(arguments_, signal = new AbortController().signal) {
|
|
27614
|
+
return await resumeMobiusRuntime(parseChannelArgument(arguments_), signal, process.env);
|
|
27215
27615
|
}
|
|
27216
27616
|
|
|
27217
27617
|
// src/run-daemon.ts
|
|
27218
27618
|
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
27219
|
-
import { basename as
|
|
27619
|
+
import { basename as basename4, join as join16 } from "node:path";
|
|
27220
27620
|
import { styleText } from "node:util";
|
|
27221
27621
|
import { fetch as fetch6, WebSocket as WebSocket2 } from "undici";
|
|
27222
27622
|
|
|
@@ -27230,14 +27630,19 @@ var AgentCatalogPublishError = class extends Error {
|
|
|
27230
27630
|
this.name = "AgentCatalogPublishError";
|
|
27231
27631
|
}
|
|
27232
27632
|
};
|
|
27233
|
-
function catalogEndpoint(
|
|
27234
|
-
const endpoint = new URL(relayUrl);
|
|
27633
|
+
function catalogEndpoint(config2) {
|
|
27634
|
+
const endpoint = new URL(config2.relayUrl);
|
|
27235
27635
|
endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
|
|
27236
|
-
if (
|
|
27237
|
-
|
|
27636
|
+
if (endpoint.pathname.endsWith("/daemon")) {
|
|
27637
|
+
endpoint.pathname = `${endpoint.pathname.slice(0, -"/daemon".length)}/catalog`;
|
|
27638
|
+
return endpoint;
|
|
27238
27639
|
}
|
|
27239
|
-
|
|
27240
|
-
|
|
27640
|
+
const runtimePath = "/v1/runtimes/connect";
|
|
27641
|
+
if (endpoint.pathname.endsWith(runtimePath)) {
|
|
27642
|
+
endpoint.pathname = `${endpoint.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}/catalog`;
|
|
27643
|
+
return endpoint;
|
|
27644
|
+
}
|
|
27645
|
+
throw new AgentCatalogPublishError("The Relay URL is invalid");
|
|
27241
27646
|
}
|
|
27242
27647
|
async function publishAgentCatalog(config2, signal) {
|
|
27243
27648
|
signal.throwIfAborted();
|
|
@@ -27246,7 +27651,7 @@ async function publishAgentCatalog(config2, signal) {
|
|
|
27246
27651
|
let response;
|
|
27247
27652
|
const catalog = config2.catalog.read();
|
|
27248
27653
|
try {
|
|
27249
|
-
response = await fetch4(catalogEndpoint(config2
|
|
27654
|
+
response = await fetch4(catalogEndpoint(config2), {
|
|
27250
27655
|
body: JSON.stringify({
|
|
27251
27656
|
agents: catalog.agents.map((agent) => ({
|
|
27252
27657
|
agentPath: agent.agentIdentity.requestedPath,
|
|
@@ -27929,6 +28334,7 @@ var EmbeddedBotContextApplicator = class {
|
|
|
27929
28334
|
|
|
27930
28335
|
// src/native-sessions/service.ts
|
|
27931
28336
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
28337
|
+
import { basename as basename3 } from "node:path";
|
|
27932
28338
|
|
|
27933
28339
|
// src/native-sessions/codex-history.ts
|
|
27934
28340
|
import { spawn as spawn4 } from "node:child_process";
|
|
@@ -28406,16 +28812,84 @@ var NativeSessionService = class {
|
|
|
28406
28812
|
history: opened.history
|
|
28407
28813
|
};
|
|
28408
28814
|
};
|
|
28409
|
-
|
|
28410
|
-
|
|
28411
|
-
|
|
28412
|
-
|
|
28413
|
-
|
|
28414
|
-
|
|
28415
|
-
|
|
28416
|
-
|
|
28417
|
-
|
|
28418
|
-
|
|
28815
|
+
executeTurnFork = async (command, signal) => {
|
|
28816
|
+
signal.throwIfAborted();
|
|
28817
|
+
const cwd = await this.#directories.resolve(this.#config.bindingId, command.directoryId, signal);
|
|
28818
|
+
const additionalDirectories = [];
|
|
28819
|
+
const additionalEntries = [];
|
|
28820
|
+
const resolvedPaths = /* @__PURE__ */ new Set([cwd]);
|
|
28821
|
+
for (const directoryId2 of command.additionalDirectoryIds) {
|
|
28822
|
+
const path2 = await this.#directories.resolve(this.#config.bindingId, directoryId2, signal);
|
|
28823
|
+
if (resolvedPaths.has(path2)) {
|
|
28824
|
+
throw new LocalAuthorizationError("Workspace directories must resolve to distinct locations");
|
|
28825
|
+
}
|
|
28826
|
+
resolvedPaths.add(path2);
|
|
28827
|
+
additionalDirectories.push(path2);
|
|
28828
|
+
additionalEntries.push({ directoryId: directoryId2, name: basename3(path2) });
|
|
28829
|
+
}
|
|
28830
|
+
const listing = await this.#directories.list(this.#config.bindingId, command.directoryId, signal);
|
|
28831
|
+
const opened = await this.#sessions.forkSessionAtTurn(
|
|
28832
|
+
{
|
|
28833
|
+
additionalDirectories,
|
|
28834
|
+
agent: this.#config.catalog.find(command.agentId),
|
|
28835
|
+
cwd,
|
|
28836
|
+
sessionId: command.targetSessionId,
|
|
28837
|
+
signal
|
|
28838
|
+
},
|
|
28839
|
+
command.sessionId,
|
|
28840
|
+
{
|
|
28841
|
+
messageFingerprint: command.messageFingerprint,
|
|
28842
|
+
messageId: command.messageId,
|
|
28843
|
+
messageOccurrence: command.messageOccurrence
|
|
28844
|
+
}
|
|
28845
|
+
);
|
|
28846
|
+
signal.throwIfAborted();
|
|
28847
|
+
const ready = {
|
|
28848
|
+
additionalDirectories: additionalEntries,
|
|
28849
|
+
agentId: command.agentId,
|
|
28850
|
+
agentName: opened.prepared.agentName,
|
|
28851
|
+
agentVersion: opened.prepared.agentVersion,
|
|
28852
|
+
capabilities: opened.prepared.capabilities,
|
|
28853
|
+
commands: opened.prepared.commands,
|
|
28854
|
+
configOptions: opened.prepared.configOptions,
|
|
28855
|
+
directoryId: command.directoryId,
|
|
28856
|
+
directoryLabel: listing.directoryLabel,
|
|
28857
|
+
kind: "session.ready",
|
|
28858
|
+
requestId: command.requestId,
|
|
28859
|
+
restored: true,
|
|
28860
|
+
sessionId: opened.sessionId
|
|
28861
|
+
};
|
|
28862
|
+
this.#audit.record({
|
|
28863
|
+
commandId: command.requestId,
|
|
28864
|
+
details: {
|
|
28865
|
+
agentId: command.agentId,
|
|
28866
|
+
messageId: command.messageId,
|
|
28867
|
+
sourceCommandId: command.sourceCommandId
|
|
28868
|
+
},
|
|
28869
|
+
event: "native_session_turn_forked",
|
|
28870
|
+
sessionId: command.sessionId
|
|
28871
|
+
});
|
|
28872
|
+
return {
|
|
28873
|
+
action: "fork",
|
|
28874
|
+
history: opened.history,
|
|
28875
|
+
kind: "native.session.result",
|
|
28876
|
+
ready,
|
|
28877
|
+
requestId: command.requestId,
|
|
28878
|
+
sessionId: command.sessionId,
|
|
28879
|
+
targetSessionId: command.targetSessionId,
|
|
28880
|
+
title: command.title
|
|
28881
|
+
};
|
|
28882
|
+
};
|
|
28883
|
+
authorizeEntry = async (command, options, info) => {
|
|
28884
|
+
try {
|
|
28885
|
+
const primary = await this.#directories.identify(command.bindingId, info.cwd, options.signal);
|
|
28886
|
+
const additionalDirectories = [];
|
|
28887
|
+
const additionalEntries = [];
|
|
28888
|
+
const paths = /* @__PURE__ */ new Set([primary.path]);
|
|
28889
|
+
for (const path2 of info.additionalDirectories) {
|
|
28890
|
+
const directory = await this.#directories.identify(command.bindingId, path2, options.signal);
|
|
28891
|
+
if (paths.has(directory.path)) {
|
|
28892
|
+
throw new LocalAuthorizationError("Native session roots must be distinct");
|
|
28419
28893
|
}
|
|
28420
28894
|
paths.add(directory.path);
|
|
28421
28895
|
additionalDirectories.push(directory.path);
|
|
@@ -28547,10 +29021,17 @@ function parseReference(resource) {
|
|
|
28547
29021
|
function downloadUrl(config2, command, reference) {
|
|
28548
29022
|
const url2 = new URL(config2.relayUrl);
|
|
28549
29023
|
url2.protocol = url2.protocol === "wss:" ? "https:" : "http:";
|
|
28550
|
-
|
|
28551
|
-
|
|
29024
|
+
let channelPath = "";
|
|
29025
|
+
if (url2.pathname.endsWith("/daemon")) {
|
|
29026
|
+
channelPath = url2.pathname.slice(0, -"/daemon".length);
|
|
29027
|
+
} else {
|
|
29028
|
+
const runtimePath = "/v1/runtimes/connect";
|
|
29029
|
+
if (!url2.pathname.endsWith(runtimePath)) {
|
|
29030
|
+
throw new PromptArtifactError("artifact_endpoint_invalid", "The Relay artifact endpoint is invalid");
|
|
29031
|
+
}
|
|
29032
|
+
channelPath = `${url2.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
|
|
28552
29033
|
}
|
|
28553
|
-
url2.pathname = `${
|
|
29034
|
+
url2.pathname = `${channelPath}/sessions/${encodeURIComponent(command.sessionId)}/commands/${encodeURIComponent(command.commandId)}/artifacts/${encodeURIComponent(reference.artifactId)}/content`;
|
|
28554
29035
|
url2.searchParams.delete("liveness");
|
|
28555
29036
|
return url2;
|
|
28556
29037
|
}
|
|
@@ -28708,9 +29189,17 @@ var RelayConnectionError = class extends Error {
|
|
|
28708
29189
|
};
|
|
28709
29190
|
function connectRelay(url2, signal) {
|
|
28710
29191
|
signal.throwIfAborted();
|
|
28711
|
-
return new Promise((
|
|
28712
|
-
const
|
|
28713
|
-
|
|
29192
|
+
return new Promise((resolve6, reject) => {
|
|
29193
|
+
const endpoint = new URL(url2);
|
|
29194
|
+
const headers = {};
|
|
29195
|
+
if (endpoint.pathname.endsWith("/v1/runtimes/connect")) {
|
|
29196
|
+
const runtimeCredential = endpoint.searchParams.get("token") ?? "";
|
|
29197
|
+
endpoint.searchParams.delete("token");
|
|
29198
|
+
headers["authorization"] = `Bearer ${runtimeCredential}`;
|
|
29199
|
+
}
|
|
29200
|
+
const socket = new WebSocket(endpoint, {
|
|
29201
|
+
dispatcher: environmentProxyDispatcher,
|
|
29202
|
+
headers
|
|
28714
29203
|
});
|
|
28715
29204
|
let finished = false;
|
|
28716
29205
|
const timeout = setTimeout(onTimeout, CONNECTION_TIMEOUT_MILLISECONDS);
|
|
@@ -28749,7 +29238,7 @@ function connectRelay(url2, signal) {
|
|
|
28749
29238
|
}
|
|
28750
29239
|
finished = true;
|
|
28751
29240
|
cleanup();
|
|
28752
|
-
|
|
29241
|
+
resolve6(socket);
|
|
28753
29242
|
};
|
|
28754
29243
|
function onTimeout() {
|
|
28755
29244
|
fail(new RelayConnectionError("relay_connection_timeout", "Relay connection timed out"));
|
|
@@ -28970,6 +29459,11 @@ var SessionEventOutbox = class {
|
|
|
28970
29459
|
}
|
|
28971
29460
|
this.#database.prepare(`UPDATE relay_turn_receipts SET state = ? WHERE command_id = ?`).run(state, commandId);
|
|
28972
29461
|
};
|
|
29462
|
+
isTerminalExecution = (commandId, sessionId) => {
|
|
29463
|
+
const row = this.#database.prepare(`SELECT state FROM relay_turn_receipts WHERE command_id = ? AND session_id = ?`).get(commandId, sessionId);
|
|
29464
|
+
const state = typeof row === "object" && row !== null ? Reflect.get(row, "state") : void 0;
|
|
29465
|
+
return state === "succeeded" || state === "failed" || state === "cancelled";
|
|
29466
|
+
};
|
|
28973
29467
|
acknowledge = (acknowledgement) => {
|
|
28974
29468
|
this.#database.prepare(
|
|
28975
29469
|
`DELETE FROM relay_session_event_outbox
|
|
@@ -29326,10 +29820,17 @@ var ActiveTurnReconciliationError = class extends Error {
|
|
|
29326
29820
|
function activeTurnReconciliationEndpoint(config2, turn) {
|
|
29327
29821
|
const endpoint = new URL(config2.relayUrl);
|
|
29328
29822
|
endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
|
|
29329
|
-
|
|
29330
|
-
|
|
29823
|
+
let channelPath = "";
|
|
29824
|
+
if (endpoint.pathname.endsWith("/daemon")) {
|
|
29825
|
+
channelPath = endpoint.pathname.slice(0, -"/daemon".length);
|
|
29826
|
+
} else {
|
|
29827
|
+
const runtimePath = "/v1/runtimes/connect";
|
|
29828
|
+
if (!endpoint.pathname.endsWith(runtimePath)) {
|
|
29829
|
+
throw new ActiveTurnReconciliationError("The Relay URL is invalid");
|
|
29830
|
+
}
|
|
29831
|
+
channelPath = `${endpoint.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
|
|
29331
29832
|
}
|
|
29332
|
-
endpoint.pathname = `${
|
|
29833
|
+
endpoint.pathname = `${channelPath}/sessions/${encodeURIComponent(turn.command.sessionId)}/attempts/${encodeURIComponent(turn.attemptId)}/reconciliation`;
|
|
29333
29834
|
endpoint.searchParams.delete("liveness");
|
|
29334
29835
|
return endpoint;
|
|
29335
29836
|
}
|
|
@@ -29482,7 +29983,7 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
|
|
|
29482
29983
|
additionalDirectories.push(directory);
|
|
29483
29984
|
additionalDirectoryEntries.push({
|
|
29484
29985
|
directoryId: additionalDirectoryId,
|
|
29485
|
-
name:
|
|
29986
|
+
name: basename4(directory)
|
|
29486
29987
|
});
|
|
29487
29988
|
}
|
|
29488
29989
|
return new ResolvedSessionDirectories(cwd, additionalDirectories, additionalDirectoryEntries);
|
|
@@ -29631,68 +30132,96 @@ async function executePrompt(outbox, publisher, command, config2, directories, a
|
|
|
29631
30132
|
attemptId
|
|
29632
30133
|
);
|
|
29633
30134
|
const attachments = await resolvePromptArtifacts(config2, command, signal);
|
|
29634
|
-
|
|
29635
|
-
|
|
29636
|
-
|
|
29637
|
-
|
|
29638
|
-
|
|
29639
|
-
|
|
29640
|
-
|
|
29641
|
-
|
|
29642
|
-
|
|
29643
|
-
|
|
29644
|
-
|
|
29645
|
-
|
|
29646
|
-
|
|
29647
|
-
|
|
29648
|
-
|
|
29649
|
-
|
|
29650
|
-
|
|
29651
|
-
|
|
29652
|
-
|
|
29653
|
-
|
|
29654
|
-
|
|
29655
|
-
sessionId: command.sessionId,
|
|
29656
|
-
status: activity.status,
|
|
29657
|
-
title: activity.title,
|
|
29658
|
-
toolKind: activity.toolKind
|
|
29659
|
-
}),
|
|
29660
|
-
attemptId
|
|
29661
|
-
);
|
|
29662
|
-
return Promise.resolve();
|
|
29663
|
-
},
|
|
29664
|
-
onText: (text) => {
|
|
29665
|
-
publisher.recordAttempt(
|
|
29666
|
-
command.sessionId,
|
|
29667
|
-
encodeAgentMessageDeltaEvent({
|
|
29668
|
-
commandId: command.commandId,
|
|
29669
|
-
kind: AGENT_MESSAGE_DELTA_KIND,
|
|
29670
|
-
sessionId: command.sessionId,
|
|
29671
|
-
text
|
|
29672
|
-
}),
|
|
29673
|
-
attemptId
|
|
30135
|
+
let stopReason;
|
|
30136
|
+
if (command.disposition === SessionPromptDisposition.Steer) {
|
|
30137
|
+
await sessions.steerPrompt({
|
|
30138
|
+
additionalDirectories: resolved.additionalDirectories,
|
|
30139
|
+
agent,
|
|
30140
|
+
commandId: command.commandId,
|
|
30141
|
+
cwd: resolved.cwd,
|
|
30142
|
+
images: attachments.images,
|
|
30143
|
+
prompt: command.prompt,
|
|
30144
|
+
resources: attachments.resources,
|
|
30145
|
+
sessionId: command.sessionId,
|
|
30146
|
+
signal,
|
|
30147
|
+
targetCommandId: command.targetCommandId
|
|
30148
|
+
});
|
|
30149
|
+
stopReason = "steered";
|
|
30150
|
+
} else {
|
|
30151
|
+
if (command.disposition === SessionPromptDisposition.Queue && !outbox.isTerminalExecution(command.targetCommandId, command.sessionId)) {
|
|
30152
|
+
throw new AcpExecutionError(
|
|
30153
|
+
"The queued prompt target is unavailable",
|
|
30154
|
+
{},
|
|
30155
|
+
"prompt_queue_target_unavailable"
|
|
29674
30156
|
);
|
|
29675
|
-
|
|
29676
|
-
|
|
29677
|
-
|
|
29678
|
-
|
|
29679
|
-
|
|
29680
|
-
|
|
29681
|
-
|
|
30157
|
+
}
|
|
30158
|
+
const result = await sessions.runPrompt({
|
|
30159
|
+
additionalDirectories: resolved.additionalDirectories,
|
|
30160
|
+
agent,
|
|
30161
|
+
commandId: command.commandId,
|
|
30162
|
+
cwd: resolved.cwd,
|
|
30163
|
+
disposition: command.disposition,
|
|
30164
|
+
images: attachments.images,
|
|
30165
|
+
onActivity: (activity) => {
|
|
30166
|
+
publisher.recordAttempt(
|
|
30167
|
+
command.sessionId,
|
|
30168
|
+
encodeAgentActivityEvent({
|
|
30169
|
+
activityId: activity.activityId,
|
|
30170
|
+
activityType: activity.activityType,
|
|
30171
|
+
commandId: command.commandId,
|
|
30172
|
+
content: activity.content,
|
|
30173
|
+
detail: activity.detail,
|
|
30174
|
+
input: activity.input,
|
|
30175
|
+
kind: AGENT_ACTIVITY_KIND,
|
|
30176
|
+
locations: activity.locations,
|
|
30177
|
+
name: activity.name,
|
|
30178
|
+
output: activity.output,
|
|
30179
|
+
sequence: activity.sequence,
|
|
30180
|
+
sessionId: command.sessionId,
|
|
30181
|
+
status: activity.status,
|
|
30182
|
+
title: activity.title,
|
|
30183
|
+
toolKind: activity.toolKind
|
|
30184
|
+
}),
|
|
30185
|
+
attemptId
|
|
30186
|
+
);
|
|
30187
|
+
return Promise.resolve();
|
|
30188
|
+
},
|
|
30189
|
+
onText: (text, messageId) => {
|
|
30190
|
+
publisher.recordAttempt(
|
|
30191
|
+
command.sessionId,
|
|
30192
|
+
encodeAgentMessageDeltaEvent({
|
|
30193
|
+
commandId: command.commandId,
|
|
30194
|
+
kind: AGENT_MESSAGE_DELTA_KIND,
|
|
30195
|
+
messageId,
|
|
30196
|
+
sessionId: command.sessionId,
|
|
30197
|
+
text
|
|
30198
|
+
}),
|
|
30199
|
+
attemptId
|
|
30200
|
+
);
|
|
30201
|
+
return Promise.resolve();
|
|
30202
|
+
},
|
|
30203
|
+
prompt: command.prompt,
|
|
30204
|
+
resources: attachments.resources,
|
|
30205
|
+
sessionId: command.sessionId,
|
|
30206
|
+
signal,
|
|
30207
|
+
targetCommandId: command.targetCommandId
|
|
30208
|
+
});
|
|
30209
|
+
stopReason = result.stopReason;
|
|
30210
|
+
}
|
|
29682
30211
|
publisher.recordAttempt(
|
|
29683
30212
|
command.sessionId,
|
|
29684
30213
|
encodeSessionCompletedEvent({
|
|
29685
30214
|
commandId: command.commandId,
|
|
29686
30215
|
kind: SESSION_COMPLETED_KIND,
|
|
29687
30216
|
sessionId: command.sessionId,
|
|
29688
|
-
stopReason
|
|
30217
|
+
stopReason
|
|
29689
30218
|
}),
|
|
29690
30219
|
attemptId
|
|
29691
30220
|
);
|
|
29692
|
-
outbox.transitionExecution(command.commandId,
|
|
30221
|
+
outbox.transitionExecution(command.commandId, stopReason === "cancelled" ? "cancelled" : "succeeded");
|
|
29693
30222
|
audit.record({
|
|
29694
30223
|
commandId: command.commandId,
|
|
29695
|
-
event:
|
|
30224
|
+
event: stopReason === "cancelled" ? "session_cancelled" : "session_completed",
|
|
29696
30225
|
sessionId: command.sessionId
|
|
29697
30226
|
});
|
|
29698
30227
|
} catch (error61) {
|
|
@@ -29736,12 +30265,6 @@ function botExecutionAgent(agent, contextHandle, socketPath) {
|
|
|
29736
30265
|
}
|
|
29737
30266
|
async function executeBotPrompt(outbox, publisher, command, config2, directories, audit, sessions, grants, contexts, applicator, ipc, attemptId, signal) {
|
|
29738
30267
|
try {
|
|
29739
|
-
if (command.additionalDirectoryIds.length > 0) {
|
|
29740
|
-
throw new LocalBotAuthorizationError(
|
|
29741
|
-
"binding_not_approved",
|
|
29742
|
-
"The Bot execution requested unapproved additional directories"
|
|
29743
|
-
);
|
|
29744
|
-
}
|
|
29745
30268
|
const deadline = Date.parse(command.executionDeadlineAt);
|
|
29746
30269
|
const remaining = deadline - Date.now();
|
|
29747
30270
|
if (!Number.isSafeInteger(deadline) || remaining <= 0) {
|
|
@@ -29755,6 +30278,32 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
29755
30278
|
Date.now(),
|
|
29756
30279
|
signal
|
|
29757
30280
|
);
|
|
30281
|
+
const requestedExecutionTargetOverridden = command.directoryId !== grant.workspaceRef || command.additionalDirectoryIds.length > 0;
|
|
30282
|
+
if (requestedExecutionTargetOverridden && !(command.replyRoute instanceof OwnerBotReplyRoute)) {
|
|
30283
|
+
throw new LocalBotAuthorizationError(
|
|
30284
|
+
"binding_not_approved",
|
|
30285
|
+
"Only a paired owner conversation can override the approved Bot workspace"
|
|
30286
|
+
);
|
|
30287
|
+
}
|
|
30288
|
+
const resolved = await resolveSessionDirectories(
|
|
30289
|
+
directories,
|
|
30290
|
+
config2.bindingId,
|
|
30291
|
+
command.directoryId,
|
|
30292
|
+
command.additionalDirectoryIds,
|
|
30293
|
+
signal
|
|
30294
|
+
);
|
|
30295
|
+
const executionTargetOverridden = resolved.cwd !== grant.workspacePath || resolved.additionalDirectories.length > 0;
|
|
30296
|
+
if (executionTargetOverridden && !sessions.hasPreparedSession(
|
|
30297
|
+
command.sessionId,
|
|
30298
|
+
grant.agent.id,
|
|
30299
|
+
resolved.cwd,
|
|
30300
|
+
resolved.additionalDirectories
|
|
30301
|
+
)) {
|
|
30302
|
+
throw new LocalBotAuthorizationError(
|
|
30303
|
+
"local_approval_required",
|
|
30304
|
+
"Open this Bot conversation in the paired local Web app before using the selected workspace"
|
|
30305
|
+
);
|
|
30306
|
+
}
|
|
29758
30307
|
const attachments = await resolvePromptArtifacts(config2, command, signal);
|
|
29759
30308
|
const applied = await applicator.apply(command, grant, attachments.resources, signal);
|
|
29760
30309
|
const lease = contexts.activate(command);
|
|
@@ -29762,6 +30311,13 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
29762
30311
|
const deadlineSignal = AbortSignal.timeout(remaining);
|
|
29763
30312
|
const executionSignal = AbortSignal.any([signal, deadlineSignal]);
|
|
29764
30313
|
const agent = botExecutionAgent(grant.agent, lease.context.contextHandle, ipc.socketPath);
|
|
30314
|
+
await sessions.prepareExecutionSession({
|
|
30315
|
+
additionalDirectories: resolved.additionalDirectories,
|
|
30316
|
+
agent,
|
|
30317
|
+
cwd: resolved.cwd,
|
|
30318
|
+
sessionId: command.sessionId,
|
|
30319
|
+
signal: executionSignal
|
|
30320
|
+
});
|
|
29765
30321
|
audit.record({
|
|
29766
30322
|
commandId: command.commandId,
|
|
29767
30323
|
details: {
|
|
@@ -29786,10 +30342,10 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
29786
30342
|
attemptId
|
|
29787
30343
|
);
|
|
29788
30344
|
const result = await sessions.runPrompt({
|
|
29789
|
-
additionalDirectories:
|
|
30345
|
+
additionalDirectories: resolved.additionalDirectories,
|
|
29790
30346
|
agent,
|
|
29791
30347
|
commandId: command.commandId,
|
|
29792
|
-
cwd:
|
|
30348
|
+
cwd: resolved.cwd,
|
|
29793
30349
|
images: attachments.images,
|
|
29794
30350
|
onActivity: (activity) => {
|
|
29795
30351
|
publisher.recordAttempt(
|
|
@@ -29815,12 +30371,13 @@ async function executeBotPrompt(outbox, publisher, command, config2, directories
|
|
|
29815
30371
|
);
|
|
29816
30372
|
return Promise.resolve();
|
|
29817
30373
|
},
|
|
29818
|
-
onText: (text) => {
|
|
30374
|
+
onText: (text, messageId) => {
|
|
29819
30375
|
publisher.recordAttempt(
|
|
29820
30376
|
command.sessionId,
|
|
29821
30377
|
encodeAgentMessageDeltaEvent({
|
|
29822
30378
|
commandId: command.commandId,
|
|
29823
30379
|
kind: AGENT_MESSAGE_DELTA_KIND,
|
|
30380
|
+
messageId,
|
|
29824
30381
|
sessionId: command.sessionId,
|
|
29825
30382
|
text
|
|
29826
30383
|
}),
|
|
@@ -29886,12 +30443,12 @@ function waitForRelayRetry(signal, timer) {
|
|
|
29886
30443
|
if (signal.aborted) {
|
|
29887
30444
|
return Promise.resolve();
|
|
29888
30445
|
}
|
|
29889
|
-
return new Promise((
|
|
30446
|
+
return new Promise((resolve6) => {
|
|
29890
30447
|
const retry = timer.schedule(finish, RELAY_RECONNECT_DELAY_MILLISECONDS);
|
|
29891
30448
|
function finish() {
|
|
29892
30449
|
retry.cancel();
|
|
29893
30450
|
signal.removeEventListener("abort", finish);
|
|
29894
|
-
|
|
30451
|
+
resolve6();
|
|
29895
30452
|
}
|
|
29896
30453
|
signal.addEventListener("abort", finish, { once: true });
|
|
29897
30454
|
});
|
|
@@ -29928,7 +30485,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
29928
30485
|
const nativeRequests = /* @__PURE__ */ new Map();
|
|
29929
30486
|
installationObserver.connect(socket);
|
|
29930
30487
|
try {
|
|
29931
|
-
await new Promise((
|
|
30488
|
+
await new Promise((resolve6, reject) => {
|
|
29932
30489
|
let finished = false;
|
|
29933
30490
|
const cleanup = () => {
|
|
29934
30491
|
connectionRefresh.close();
|
|
@@ -29947,7 +30504,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
29947
30504
|
}
|
|
29948
30505
|
finished = true;
|
|
29949
30506
|
cleanup();
|
|
29950
|
-
|
|
30507
|
+
resolve6();
|
|
29951
30508
|
};
|
|
29952
30509
|
const rejectConnection = () => {
|
|
29953
30510
|
if (finished) {
|
|
@@ -30127,7 +30684,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30127
30684
|
try {
|
|
30128
30685
|
operationSignal.throwIfAborted();
|
|
30129
30686
|
if (previous.length > 0) {
|
|
30130
|
-
await new Promise((
|
|
30687
|
+
await new Promise((resolve7, reject2) => {
|
|
30131
30688
|
const cancel = () => reject2(operationSignal.reason);
|
|
30132
30689
|
operationSignal.addEventListener("abort", cancel, {
|
|
30133
30690
|
once: true
|
|
@@ -30135,7 +30692,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30135
30692
|
void Promise.all(previous.map((request) => request.completion)).then(
|
|
30136
30693
|
() => {
|
|
30137
30694
|
operationSignal.removeEventListener("abort", cancel);
|
|
30138
|
-
|
|
30695
|
+
resolve7();
|
|
30139
30696
|
},
|
|
30140
30697
|
(error61) => {
|
|
30141
30698
|
operationSignal.removeEventListener("abort", cancel);
|
|
@@ -30175,6 +30732,86 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30175
30732
|
});
|
|
30176
30733
|
return;
|
|
30177
30734
|
}
|
|
30735
|
+
if (kind === NATIVE_SESSION_TURN_FORK_KIND) {
|
|
30736
|
+
const command2 = decodeNativeSessionTurnForkCommand(encoded);
|
|
30737
|
+
const previous = [...nativeRequests.values()].filter(
|
|
30738
|
+
(request) => request.agentId === command2.agentId
|
|
30739
|
+
);
|
|
30740
|
+
if (nativeRequests.has(command2.requestId) || nativeRequests.size >= 4 || previous.some((request) => !request.controller.signal.aborted)) {
|
|
30741
|
+
reportOperationFailure(
|
|
30742
|
+
socket,
|
|
30743
|
+
command2.requestId,
|
|
30744
|
+
command2.sessionId,
|
|
30745
|
+
new AcpExecutionError(
|
|
30746
|
+
"Another native session operation is running",
|
|
30747
|
+
{},
|
|
30748
|
+
"native_session_busy"
|
|
30749
|
+
)
|
|
30750
|
+
);
|
|
30751
|
+
return;
|
|
30752
|
+
}
|
|
30753
|
+
const controller = new AbortController();
|
|
30754
|
+
const operationSignal = AbortSignal.any([connectionController.signal, controller.signal]);
|
|
30755
|
+
const timeout = timer.schedule(
|
|
30756
|
+
() => controller.abort(
|
|
30757
|
+
new AcpExecutionError(
|
|
30758
|
+
"Native session operation timed out",
|
|
30759
|
+
{},
|
|
30760
|
+
"native_session_timeout"
|
|
30761
|
+
)
|
|
30762
|
+
),
|
|
30763
|
+
9e4
|
|
30764
|
+
);
|
|
30765
|
+
const completion = (async () => {
|
|
30766
|
+
try {
|
|
30767
|
+
operationSignal.throwIfAborted();
|
|
30768
|
+
if (previous.length > 0) {
|
|
30769
|
+
await new Promise((resolve7, reject2) => {
|
|
30770
|
+
const cancel = () => reject2(operationSignal.reason);
|
|
30771
|
+
operationSignal.addEventListener("abort", cancel, { once: true });
|
|
30772
|
+
void Promise.all(previous.map((request) => request.completion)).then(
|
|
30773
|
+
() => {
|
|
30774
|
+
operationSignal.removeEventListener("abort", cancel);
|
|
30775
|
+
resolve7();
|
|
30776
|
+
},
|
|
30777
|
+
(error61) => {
|
|
30778
|
+
operationSignal.removeEventListener("abort", cancel);
|
|
30779
|
+
reject2(error61);
|
|
30780
|
+
}
|
|
30781
|
+
);
|
|
30782
|
+
});
|
|
30783
|
+
}
|
|
30784
|
+
operationSignal.throwIfAborted();
|
|
30785
|
+
const result = await nativeSessions.executeTurnFork(command2, operationSignal);
|
|
30786
|
+
if (socket.readyState === WebSocket2.OPEN) {
|
|
30787
|
+
send(socket, encodeNativeSessionResult(result));
|
|
30788
|
+
}
|
|
30789
|
+
} catch (error61) {
|
|
30790
|
+
const failure = operationSignal.aborted ? controller.signal.reason ?? new AcpExecutionError(
|
|
30791
|
+
"Native session operation cancelled",
|
|
30792
|
+
{},
|
|
30793
|
+
"native_session_cancelled"
|
|
30794
|
+
) : error61;
|
|
30795
|
+
audit.record({
|
|
30796
|
+
commandId: command2.requestId,
|
|
30797
|
+
details: { code: operationErrorCode(failure) },
|
|
30798
|
+
event: "native_session_turn_fork_failed",
|
|
30799
|
+
sessionId: command2.sessionId
|
|
30800
|
+
});
|
|
30801
|
+
reportOperationFailure(socket, command2.requestId, command2.sessionId, failure);
|
|
30802
|
+
} finally {
|
|
30803
|
+
timeout.cancel();
|
|
30804
|
+
nativeRequests.delete(command2.requestId);
|
|
30805
|
+
}
|
|
30806
|
+
})();
|
|
30807
|
+
nativeRequests.set(command2.requestId, {
|
|
30808
|
+
agentId: command2.agentId,
|
|
30809
|
+
completion,
|
|
30810
|
+
controller,
|
|
30811
|
+
sessionId: command2.sessionId
|
|
30812
|
+
});
|
|
30813
|
+
return;
|
|
30814
|
+
}
|
|
30178
30815
|
if (kind === RUNTIME_LIVENESS_READY_KIND) {
|
|
30179
30816
|
decodeRuntimeLivenessReadyEvent(encoded);
|
|
30180
30817
|
connectionLiveness.start();
|
|
@@ -30328,7 +30965,9 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30328
30965
|
}
|
|
30329
30966
|
const turn = new ActiveDaemonTurn(command, receipt.attemptId);
|
|
30330
30967
|
activeTurns.set(command.commandId, turn);
|
|
30331
|
-
|
|
30968
|
+
if (command.disposition !== SessionPromptDisposition.Steer) {
|
|
30969
|
+
activeAttemptIds.set(command.sessionId, receipt.attemptId);
|
|
30970
|
+
}
|
|
30332
30971
|
void executePrompt(
|
|
30333
30972
|
outbox,
|
|
30334
30973
|
publisher,
|
|
@@ -30515,6 +31154,147 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
30515
31154
|
}
|
|
30516
31155
|
}
|
|
30517
31156
|
}
|
|
31157
|
+
|
|
31158
|
+
// src/runtime.ts
|
|
31159
|
+
import { mkdir as mkdir5, realpath as realpath8, stat as stat8 } from "node:fs/promises";
|
|
31160
|
+
import { dirname as dirname8, join as join17, resolve as resolve5 } from "node:path";
|
|
31161
|
+
var APP_CREDENTIAL_PATTERN = /^mapp_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
|
|
31162
|
+
var CONVERSATION_CREDENTIAL_PATTERN = /^mconv_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
|
|
31163
|
+
var IDENTIFIER_PATTERN8 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
31164
|
+
var RUNTIME_CREDENTIAL_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
|
|
31165
|
+
var MobiusRuntimeConfigurationError = class extends Error {
|
|
31166
|
+
code = "runtime_configuration_invalid";
|
|
31167
|
+
constructor(message, options = {}) {
|
|
31168
|
+
super(message, options);
|
|
31169
|
+
this.name = "MobiusRuntimeConfigurationError";
|
|
31170
|
+
}
|
|
31171
|
+
};
|
|
31172
|
+
var MobiusRuntimeState = class {
|
|
31173
|
+
};
|
|
31174
|
+
var IdleMobiusRuntimeState = class extends MobiusRuntimeState {
|
|
31175
|
+
};
|
|
31176
|
+
var RunningMobiusRuntimeState = class extends MobiusRuntimeState {
|
|
31177
|
+
};
|
|
31178
|
+
var FinishedMobiusRuntimeState = class extends MobiusRuntimeState {
|
|
31179
|
+
};
|
|
31180
|
+
function validateRuntimeRelay(relayUrl) {
|
|
31181
|
+
if (relayUrl.protocol !== "ws:" && relayUrl.protocol !== "wss:") {
|
|
31182
|
+
throw new MobiusRuntimeConfigurationError("The Runtime relay URL must use WebSocket transport");
|
|
31183
|
+
}
|
|
31184
|
+
const credential = relayUrl.searchParams.get("token") ?? "";
|
|
31185
|
+
if (credential.length === 0) {
|
|
31186
|
+
throw new MobiusRuntimeConfigurationError("The Runtime relay credential is required");
|
|
31187
|
+
}
|
|
31188
|
+
if (APP_CREDENTIAL_PATTERN.test(credential)) {
|
|
31189
|
+
throw new MobiusRuntimeConfigurationError("An AppCredential cannot be held by a local Runtime");
|
|
31190
|
+
}
|
|
31191
|
+
if (CONVERSATION_CREDENTIAL_PATTERN.test(credential)) {
|
|
31192
|
+
throw new MobiusRuntimeConfigurationError("A ConversationAccessToken cannot be held by a local Runtime");
|
|
31193
|
+
}
|
|
31194
|
+
if (!RUNTIME_CREDENTIAL_PATTERN.test(credential)) {
|
|
31195
|
+
throw new MobiusRuntimeConfigurationError("The Runtime relay credential is invalid");
|
|
31196
|
+
}
|
|
31197
|
+
}
|
|
31198
|
+
function validateRuntimeConfiguration(config2) {
|
|
31199
|
+
validateRuntimeRelay(config2.relayUrl);
|
|
31200
|
+
}
|
|
31201
|
+
function requiredEnvironmentValue(environment, name) {
|
|
31202
|
+
const value = environment[name]?.trim();
|
|
31203
|
+
if (value === void 0 || value.length === 0) {
|
|
31204
|
+
throw new MobiusRuntimeConfigurationError(`${name} is required`);
|
|
31205
|
+
}
|
|
31206
|
+
return value;
|
|
31207
|
+
}
|
|
31208
|
+
function relayUrlFromConnection(connection) {
|
|
31209
|
+
let relayUrl;
|
|
31210
|
+
try {
|
|
31211
|
+
relayUrl = new URL(connection.relayUrl);
|
|
31212
|
+
} catch (error61) {
|
|
31213
|
+
throw new MobiusRuntimeConfigurationError("The Runtime relay URL is invalid", { cause: error61 });
|
|
31214
|
+
}
|
|
31215
|
+
relayUrl.searchParams.set("token", connection.runtimeCredential);
|
|
31216
|
+
validateRuntimeRelay(relayUrl);
|
|
31217
|
+
return relayUrl;
|
|
31218
|
+
}
|
|
31219
|
+
function loadMobiusRuntimeConnection(environment = process.env) {
|
|
31220
|
+
const channelId = requiredEnvironmentValue(environment, "MOBIUS_CHANNEL_ID");
|
|
31221
|
+
if (!IDENTIFIER_PATTERN8.test(channelId)) {
|
|
31222
|
+
throw new MobiusRuntimeConfigurationError("MOBIUS_CHANNEL_ID is invalid");
|
|
31223
|
+
}
|
|
31224
|
+
return Object.freeze({
|
|
31225
|
+
auditDatabasePath: environment["MOBIUS_AUDIT_DATABASE"]?.trim() || join17(readStateDirectory(environment), "audit", `${channelId}.sqlite`),
|
|
31226
|
+
channelId,
|
|
31227
|
+
defaultWorkspace: loadDefaultWorkspace(environment),
|
|
31228
|
+
relayUrl: requiredEnvironmentValue(environment, "MOBIUS_RELAY_URL"),
|
|
31229
|
+
runtimeCredential: requiredEnvironmentValue(environment, "MOBIUS_RELAY_TOKEN")
|
|
31230
|
+
});
|
|
31231
|
+
}
|
|
31232
|
+
async function resolveWorkspace(path2) {
|
|
31233
|
+
const requested = resolve5(path2);
|
|
31234
|
+
try {
|
|
31235
|
+
await mkdir5(requested, { recursive: true, mode: 448 });
|
|
31236
|
+
const resolved = await realpath8(requested);
|
|
31237
|
+
const metadata = await stat8(resolved);
|
|
31238
|
+
if (!metadata.isDirectory()) {
|
|
31239
|
+
throw new MobiusRuntimeConfigurationError("The Runtime workspace is not a directory");
|
|
31240
|
+
}
|
|
31241
|
+
return resolved;
|
|
31242
|
+
} catch (error61) {
|
|
31243
|
+
if (error61 instanceof MobiusRuntimeConfigurationError) {
|
|
31244
|
+
throw error61;
|
|
31245
|
+
}
|
|
31246
|
+
throw new MobiusRuntimeConfigurationError("The Runtime workspace cannot be resolved", { cause: error61 });
|
|
31247
|
+
}
|
|
31248
|
+
}
|
|
31249
|
+
async function createMobiusRuntimeEngine(connection, signal, environment = process.env) {
|
|
31250
|
+
signal.throwIfAborted();
|
|
31251
|
+
const relayUrl = relayUrlFromConnection(connection);
|
|
31252
|
+
const defaultWorkspace = await resolveWorkspace(connection.defaultWorkspace);
|
|
31253
|
+
const auditDatabasePath = resolve5(connection.auditDatabasePath);
|
|
31254
|
+
await mkdir5(dirname8(auditDatabasePath), { recursive: true, mode: 448 });
|
|
31255
|
+
const inventory = await discoverLocalAgentInventory({
|
|
31256
|
+
defaultWorkspace,
|
|
31257
|
+
environment,
|
|
31258
|
+
signal
|
|
31259
|
+
});
|
|
31260
|
+
if (inventory.available.length + inventory.installable.length === 0) {
|
|
31261
|
+
throw new MobiusRuntimeConfigurationError("No supported Agent is available for the local Runtime");
|
|
31262
|
+
}
|
|
31263
|
+
return new MobiusRuntimeEngine(
|
|
31264
|
+
createDaemonConfig(
|
|
31265
|
+
{
|
|
31266
|
+
auditDatabasePath,
|
|
31267
|
+
channelId: connection.channelId,
|
|
31268
|
+
defaultWorkspace,
|
|
31269
|
+
relayUrl
|
|
31270
|
+
},
|
|
31271
|
+
inventory.readyAgents(),
|
|
31272
|
+
inventory.installable
|
|
31273
|
+
)
|
|
31274
|
+
);
|
|
31275
|
+
}
|
|
31276
|
+
var MobiusRuntimeEngine = class {
|
|
31277
|
+
#config;
|
|
31278
|
+
#state = new IdleMobiusRuntimeState();
|
|
31279
|
+
constructor(config2) {
|
|
31280
|
+
validateRuntimeConfiguration(config2);
|
|
31281
|
+
this.#config = config2;
|
|
31282
|
+
}
|
|
31283
|
+
run = async (signal) => {
|
|
31284
|
+
if (!(this.#state instanceof IdleMobiusRuntimeState)) {
|
|
31285
|
+
throw new MobiusRuntimeConfigurationError("A Mobius Runtime engine can only be started once");
|
|
31286
|
+
}
|
|
31287
|
+
signal.throwIfAborted();
|
|
31288
|
+
this.#state = new RunningMobiusRuntimeState();
|
|
31289
|
+
const audit = new AuditStore(this.#config.auditDatabasePath);
|
|
31290
|
+
try {
|
|
31291
|
+
await runDaemon(this.#config, audit, signal);
|
|
31292
|
+
} finally {
|
|
31293
|
+
audit.close();
|
|
31294
|
+
this.#state = new FinishedMobiusRuntimeState();
|
|
31295
|
+
}
|
|
31296
|
+
};
|
|
31297
|
+
};
|
|
30518
31298
|
export {
|
|
30519
31299
|
AcpExecutionError,
|
|
30520
31300
|
AuditStore,
|
|
@@ -30522,12 +31302,18 @@ export {
|
|
|
30522
31302
|
BotMessageCommandError,
|
|
30523
31303
|
BotOutboundIpcServer,
|
|
30524
31304
|
LocalAuthorizationError,
|
|
31305
|
+
MobiusRuntimeConfigurationError,
|
|
31306
|
+
MobiusRuntimeEngine,
|
|
30525
31307
|
PairingClientError,
|
|
30526
31308
|
createAcpClient,
|
|
31309
|
+
createMobiusRuntimeEngine,
|
|
30527
31310
|
executeBotMessageCommand,
|
|
30528
31311
|
loadDaemonConfig,
|
|
31312
|
+
loadMobiusRuntimeConnection,
|
|
30529
31313
|
pairLocalMachine,
|
|
31314
|
+
pairMobiusRuntime,
|
|
30530
31315
|
resumeLocalMachine,
|
|
31316
|
+
resumeMobiusRuntime,
|
|
30531
31317
|
runAcpPrompt,
|
|
30532
31318
|
runDaemon
|
|
30533
31319
|
};
|