@moxt-ai/mobius 0.0.26 → 0.0.28
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/activity.d.ts +1 -0
- package/dist/acp/activity.d.ts.map +1 -1
- package/dist/acp/activity.js +14 -1
- package/dist/acp/activity.js.map +1 -1
- package/dist/acp/session-history.d.ts.map +1 -1
- package/dist/acp/session-history.js +10 -16
- package/dist/acp/session-history.js.map +1 -1
- package/dist/acp/session-manager.d.ts +7 -0
- package/dist/acp/session-manager.d.ts.map +1 -1
- package/dist/acp/session-manager.js +65 -11
- package/dist/acp/session-manager.js.map +1 -1
- package/dist/agent-catalog/publish-agent-catalog.js +3 -3
- package/dist/agent-catalog/publish-agent-catalog.js.map +1 -1
- package/dist/artifacts/runtime-artifact-uploader.d.ts +12 -0
- package/dist/artifacts/runtime-artifact-uploader.d.ts.map +1 -0
- package/dist/artifacts/runtime-artifact-uploader.js +157 -0
- package/dist/artifacts/runtime-artifact-uploader.js.map +1 -0
- package/dist/authorization/local-raster.d.ts +10 -0
- package/dist/authorization/local-raster.d.ts.map +1 -0
- package/dist/authorization/local-raster.js +134 -0
- package/dist/authorization/local-raster.js.map +1 -0
- package/dist/cli.js +1644 -235
- package/dist/cli.js.map +4 -4
- package/dist/index.js +1652 -251
- package/dist/index.js.map +4 -4
- package/dist/native-sessions/codex-history.d.ts.map +1 -1
- package/dist/native-sessions/codex-history.js +11 -11
- package/dist/native-sessions/codex-history.js.map +1 -1
- package/dist/native-sessions/history-images.d.ts +3 -0
- package/dist/native-sessions/history-images.d.ts.map +1 -0
- package/dist/native-sessions/history-images.js +74 -0
- package/dist/native-sessions/history-images.js.map +1 -0
- package/dist/prompt-artifact-resolver.d.ts.map +1 -1
- package/dist/prompt-artifact-resolver.js +7 -4
- 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 +3 -6
- package/dist/relay-connection/connect.js.map +1 -1
- package/dist/relay-connection/runtime-authentication.d.ts +3 -0
- package/dist/relay-connection/runtime-authentication.d.ts.map +1 -0
- package/dist/relay-connection/runtime-authentication.js +14 -0
- package/dist/relay-connection/runtime-authentication.js.map +1 -0
- package/dist/relay-connection/session-event-outbox.d.ts +32 -2
- package/dist/relay-connection/session-event-outbox.d.ts.map +1 -1
- package/dist/relay-connection/session-event-outbox.js +362 -11
- 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 +297 -24
- package/dist/run-daemon.js.map +1 -1
- package/dist/runtime.js +1654 -253
- package/dist/runtime.js.map +4 -4
- package/package.json +2 -1
package/dist/runtime.js
CHANGED
|
@@ -5,7 +5,7 @@ var __export = (target, all) => {
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
// src/runtime.ts
|
|
8
|
-
import { mkdir as mkdir5, realpath as
|
|
8
|
+
import { mkdir as mkdir5, realpath as realpath9, stat as stat9 } from "node:fs/promises";
|
|
9
9
|
import { dirname as dirname8, join as join17, resolve as resolve5 } from "node:path";
|
|
10
10
|
|
|
11
11
|
// src/agent-catalog/local-agent.ts
|
|
@@ -2524,7 +2524,7 @@ var AuditStore = class {
|
|
|
2524
2524
|
this.database.exec("ALTER TABLE audit_events ADD COLUMN details_json TEXT NOT NULL DEFAULT '{}'");
|
|
2525
2525
|
}
|
|
2526
2526
|
}
|
|
2527
|
-
record(
|
|
2527
|
+
record(record3) {
|
|
2528
2528
|
this.database.prepare(
|
|
2529
2529
|
`
|
|
2530
2530
|
INSERT INTO audit_events (
|
|
@@ -2537,10 +2537,10 @@ var AuditStore = class {
|
|
|
2537
2537
|
`
|
|
2538
2538
|
).run(
|
|
2539
2539
|
(/* @__PURE__ */ new Date()).toISOString(),
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
JSON.stringify(
|
|
2540
|
+
record3.event,
|
|
2541
|
+
record3.commandId,
|
|
2542
|
+
record3.sessionId,
|
|
2543
|
+
JSON.stringify(record3.details ?? {})
|
|
2544
2544
|
);
|
|
2545
2545
|
}
|
|
2546
2546
|
close() {
|
|
@@ -18603,8 +18603,8 @@ function rewriteKeyNames(ctx) {
|
|
|
18603
18603
|
bySchema.set(entry.schema, entry);
|
|
18604
18604
|
}
|
|
18605
18605
|
const rewrites = /* @__PURE__ */ new Map();
|
|
18606
|
-
for (const
|
|
18607
|
-
const seen = ctx.seen.get(
|
|
18606
|
+
for (const record3 of pendingRecords.get(ctx) ?? []) {
|
|
18607
|
+
const seen = ctx.seen.get(record3);
|
|
18608
18608
|
const names = (seen?.def ?? seen?.schema)?.propertyNames;
|
|
18609
18609
|
if (!names || names === true || rewrites.has(names))
|
|
18610
18610
|
continue;
|
|
@@ -21561,6 +21561,7 @@ var elicitationFieldSchema = external_exports.strictObject({
|
|
|
21561
21561
|
type: external_exports.enum(["boolean", "integer", "multiselect", "number", "select", "string"])
|
|
21562
21562
|
}).readonly();
|
|
21563
21563
|
var displayContentSchema = external_exports.strictObject({
|
|
21564
|
+
artifactId: external_exports.string().max(128).default(""),
|
|
21564
21565
|
data: external_exports.string().max(4e6),
|
|
21565
21566
|
mimeType: external_exports.string().max(255),
|
|
21566
21567
|
name: external_exports.string().max(500),
|
|
@@ -21573,6 +21574,7 @@ var displayContentSchema = external_exports.strictObject({
|
|
|
21573
21574
|
uri: external_exports.string().max(4096)
|
|
21574
21575
|
}).readonly();
|
|
21575
21576
|
var recordedDisplayContentSchema = external_exports.strictObject({
|
|
21577
|
+
artifactId: external_exports.string().max(128).default(""),
|
|
21576
21578
|
data: external_exports.string().max(4e6),
|
|
21577
21579
|
mimeType: external_exports.string().max(255),
|
|
21578
21580
|
name: external_exports.string().max(500),
|
|
@@ -21856,6 +21858,9 @@ var SESSION_CANCEL_KIND = "session.cancel";
|
|
|
21856
21858
|
var RUNTIME_LIVENESS_READY_KIND = "runtime.liveness.ready";
|
|
21857
21859
|
var RUNTIME_HEARTBEAT_KIND = "runtime.heartbeat";
|
|
21858
21860
|
var RUNTIME_HEARTBEAT_ACK_KIND = "runtime.heartbeat.ack";
|
|
21861
|
+
var RUNTIME_DELIVERY_KIND = "runtime.delivery";
|
|
21862
|
+
var RUNTIME_DELIVERY_RECEIVED_KIND = "runtime.delivery.received";
|
|
21863
|
+
var RUNTIME_DELIVERY_COMMITTED_KIND = "runtime.delivery.committed";
|
|
21859
21864
|
var SESSION_STARTED_KIND = "session.started";
|
|
21860
21865
|
var AGENT_MESSAGE_DELTA_KIND = "agent.message.delta";
|
|
21861
21866
|
var AGENT_ACTIVITY_KIND = "agent.activity";
|
|
@@ -21878,6 +21883,7 @@ var DIRECTORY_IDENTIFIER_PATTERN2 = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,2047}$/;
|
|
|
21878
21883
|
var MAX_PROMPT_LENGTH = 1e4;
|
|
21879
21884
|
var MAX_PROMPT_ATTACHMENT_LENGTH = 6e6;
|
|
21880
21885
|
var MAX_EVENT_TEXT_LENGTH = 1e5;
|
|
21886
|
+
var MAX_RUNTIME_DELIVERY_PAYLOAD_LENGTH = 8 * 1024 * 1024;
|
|
21881
21887
|
var ACTIVITY_TYPES = /* @__PURE__ */ new Set(["plan", "progress", "reasoning", "tool"]);
|
|
21882
21888
|
var ACTIVITY_STATUSES = /* @__PURE__ */ new Set(["pending", "running", "completed", "failed"]);
|
|
21883
21889
|
var TOOL_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -22156,6 +22162,37 @@ function decodeRuntimeHeartbeatAckEvent(encoded) {
|
|
|
22156
22162
|
kind: RUNTIME_HEARTBEAT_ACK_KIND
|
|
22157
22163
|
};
|
|
22158
22164
|
}
|
|
22165
|
+
function decodeRuntimeDelivery(encoded) {
|
|
22166
|
+
const value = parseJson2(encoded);
|
|
22167
|
+
assertExactKeys(value, ["deliveryId", "kind", "payload", "sessionId"]);
|
|
22168
|
+
assertKind(value, RUNTIME_DELIVERY_KIND);
|
|
22169
|
+
return {
|
|
22170
|
+
deliveryId: readIdentifier(value, "deliveryId"),
|
|
22171
|
+
kind: RUNTIME_DELIVERY_KIND,
|
|
22172
|
+
payload: readString(value, "payload", MAX_RUNTIME_DELIVERY_PAYLOAD_LENGTH),
|
|
22173
|
+
sessionId: readIdentifier(value, "sessionId")
|
|
22174
|
+
};
|
|
22175
|
+
}
|
|
22176
|
+
function decodeRuntimeDeliveryReceived(encoded) {
|
|
22177
|
+
const value = parseJson2(encoded);
|
|
22178
|
+
assertExactKeys(value, ["deliveryId", "kind", "sessionId"]);
|
|
22179
|
+
assertKind(value, RUNTIME_DELIVERY_RECEIVED_KIND);
|
|
22180
|
+
return {
|
|
22181
|
+
deliveryId: readIdentifier(value, "deliveryId"),
|
|
22182
|
+
kind: RUNTIME_DELIVERY_RECEIVED_KIND,
|
|
22183
|
+
sessionId: readIdentifier(value, "sessionId")
|
|
22184
|
+
};
|
|
22185
|
+
}
|
|
22186
|
+
function decodeRuntimeDeliveryCommitted(encoded) {
|
|
22187
|
+
const value = parseJson2(encoded);
|
|
22188
|
+
assertExactKeys(value, ["deliveryId", "kind", "sessionId"]);
|
|
22189
|
+
assertKind(value, RUNTIME_DELIVERY_COMMITTED_KIND);
|
|
22190
|
+
return {
|
|
22191
|
+
deliveryId: readIdentifier(value, "deliveryId"),
|
|
22192
|
+
kind: RUNTIME_DELIVERY_COMMITTED_KIND,
|
|
22193
|
+
sessionId: readIdentifier(value, "sessionId")
|
|
22194
|
+
};
|
|
22195
|
+
}
|
|
22159
22196
|
function decodeSessionStartedEvent(encoded) {
|
|
22160
22197
|
const value = parseJson2(encoded);
|
|
22161
22198
|
assertExactKeys(value, ["commandId", "kind", "attemptId", "sessionId"]);
|
|
@@ -22243,6 +22280,9 @@ function decodeSessionFailedEvent(encoded) {
|
|
|
22243
22280
|
function encodeRuntimeHeartbeatEvent(message) {
|
|
22244
22281
|
return JSON.stringify(decodeRuntimeHeartbeatEvent(JSON.stringify(message)));
|
|
22245
22282
|
}
|
|
22283
|
+
function encodeRuntimeDeliveryReceived(message) {
|
|
22284
|
+
return JSON.stringify(decodeRuntimeDeliveryReceived(JSON.stringify(message)));
|
|
22285
|
+
}
|
|
22246
22286
|
function encodeSessionStartedEvent(message) {
|
|
22247
22287
|
return JSON.stringify(decodeSessionStartedEvent(JSON.stringify(message)));
|
|
22248
22288
|
}
|
|
@@ -22941,7 +22981,8 @@ var SESSION_EVENT_COMMITTED_KIND = "session.event.committed";
|
|
|
22941
22981
|
var SESSION_EVENT_REJECTED_KIND = "session.event.rejected";
|
|
22942
22982
|
var SessionEventRejectionCode = {
|
|
22943
22983
|
SessionDeleted: "session_deleted",
|
|
22944
|
-
SessionNotFound: "session_not_found"
|
|
22984
|
+
SessionNotFound: "session_not_found",
|
|
22985
|
+
SessionRejected: "session_rejected"
|
|
22945
22986
|
};
|
|
22946
22987
|
var IDENTIFIER_PATTERN4 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
22947
22988
|
var CURSOR_PATTERN = /^[A-Za-z0-9_-]{1,512}$/;
|
|
@@ -23038,9 +23079,9 @@ function createDaemonConfig(connection, agents = [], installableAgents = []) {
|
|
|
23038
23079
|
|
|
23039
23080
|
// src/run-daemon.ts
|
|
23040
23081
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
23041
|
-
import { basename as
|
|
23082
|
+
import { basename as basename4, join as join15 } from "node:path";
|
|
23042
23083
|
import { styleText } from "node:util";
|
|
23043
|
-
import { fetch as
|
|
23084
|
+
import { fetch as fetch6, WebSocket as WebSocket2 } from "undici";
|
|
23044
23085
|
|
|
23045
23086
|
// src/acp/session-manager.ts
|
|
23046
23087
|
import { spawn as spawn3 } from "node:child_process";
|
|
@@ -23051,6 +23092,212 @@ import {
|
|
|
23051
23092
|
RequestError as RequestError2
|
|
23052
23093
|
} from "@agentclientprotocol/sdk";
|
|
23053
23094
|
|
|
23095
|
+
// src/authorization/local-raster.ts
|
|
23096
|
+
import { readFile, realpath as realpath6, stat as stat5 } from "node:fs/promises";
|
|
23097
|
+
import { basename, isAbsolute as isAbsolute7, normalize as normalize2, relative as relative4, sep as sep4 } from "node:path";
|
|
23098
|
+
import { fileURLToPath } from "node:url";
|
|
23099
|
+
var MAX_LOCAL_RASTER_BYTES = 3e6;
|
|
23100
|
+
var PNG_SIGNATURE = Uint8Array.of(137, 80, 78, 71);
|
|
23101
|
+
var JPEG_SIGNATURE = Uint8Array.of(255, 216, 255);
|
|
23102
|
+
var GIF87_SIGNATURE = new TextEncoder().encode("GIF87a");
|
|
23103
|
+
var GIF89_SIGNATURE = new TextEncoder().encode("GIF89a");
|
|
23104
|
+
var RIFF_SIGNATURE = new TextEncoder().encode("RIFF");
|
|
23105
|
+
var WEBP_SIGNATURE = new TextEncoder().encode("WEBP");
|
|
23106
|
+
var LocalRasterImage = class {
|
|
23107
|
+
bytes;
|
|
23108
|
+
mimeType;
|
|
23109
|
+
name;
|
|
23110
|
+
constructor(name, mimeType, bytes) {
|
|
23111
|
+
this.bytes = bytes;
|
|
23112
|
+
this.mimeType = mimeType;
|
|
23113
|
+
this.name = name;
|
|
23114
|
+
}
|
|
23115
|
+
base64 = () => Buffer.from(this.bytes).toString("base64");
|
|
23116
|
+
};
|
|
23117
|
+
function startsWith(bytes, signature, offset = 0) {
|
|
23118
|
+
if (bytes.byteLength < offset + signature.byteLength) {
|
|
23119
|
+
return false;
|
|
23120
|
+
}
|
|
23121
|
+
return signature.every((value, index) => bytes[offset + index] === value);
|
|
23122
|
+
}
|
|
23123
|
+
function sniffRasterMime(bytes) {
|
|
23124
|
+
if (startsWith(bytes, PNG_SIGNATURE)) {
|
|
23125
|
+
return "image/png";
|
|
23126
|
+
}
|
|
23127
|
+
if (startsWith(bytes, JPEG_SIGNATURE)) {
|
|
23128
|
+
return "image/jpeg";
|
|
23129
|
+
}
|
|
23130
|
+
if (startsWith(bytes, GIF87_SIGNATURE) || startsWith(bytes, GIF89_SIGNATURE)) {
|
|
23131
|
+
return "image/gif";
|
|
23132
|
+
}
|
|
23133
|
+
if (startsWith(bytes, RIFF_SIGNATURE) && startsWith(bytes, WEBP_SIGNATURE, 8)) {
|
|
23134
|
+
return "image/webp";
|
|
23135
|
+
}
|
|
23136
|
+
return null;
|
|
23137
|
+
}
|
|
23138
|
+
function isInsideRoot(root, target) {
|
|
23139
|
+
const relation = relative4(root, target);
|
|
23140
|
+
return relation !== ".." && !relation.startsWith(`..${sep4}`) && !isAbsolute7(relation);
|
|
23141
|
+
}
|
|
23142
|
+
async function resolveCanonicalPath(requested, signal) {
|
|
23143
|
+
signal.throwIfAborted();
|
|
23144
|
+
if (!isAbsolute7(requested) || requested.includes("\0") || normalize2(requested) !== requested) {
|
|
23145
|
+
return null;
|
|
23146
|
+
}
|
|
23147
|
+
try {
|
|
23148
|
+
const target = await realpath6(requested);
|
|
23149
|
+
signal.throwIfAborted();
|
|
23150
|
+
if (!isAbsolute7(target) || normalize2(target) !== target) {
|
|
23151
|
+
return null;
|
|
23152
|
+
}
|
|
23153
|
+
return target;
|
|
23154
|
+
} catch (cause) {
|
|
23155
|
+
signal.throwIfAborted();
|
|
23156
|
+
if (cause instanceof Error && cause.name === "AbortError") {
|
|
23157
|
+
throw cause;
|
|
23158
|
+
}
|
|
23159
|
+
return null;
|
|
23160
|
+
}
|
|
23161
|
+
}
|
|
23162
|
+
function parseLocalImageUri(uri) {
|
|
23163
|
+
const trimmed = uri.trim();
|
|
23164
|
+
if (trimmed.length === 0 || trimmed.length > 2048 || trimmed.includes("\0")) {
|
|
23165
|
+
return null;
|
|
23166
|
+
}
|
|
23167
|
+
if (trimmed.startsWith("data:")) {
|
|
23168
|
+
return null;
|
|
23169
|
+
}
|
|
23170
|
+
if (trimmed.startsWith("file:")) {
|
|
23171
|
+
try {
|
|
23172
|
+
const url2 = new URL(trimmed);
|
|
23173
|
+
if (url2.protocol !== "file:" || url2.host.length > 0) {
|
|
23174
|
+
return null;
|
|
23175
|
+
}
|
|
23176
|
+
return fileURLToPath(url2);
|
|
23177
|
+
} catch {
|
|
23178
|
+
return null;
|
|
23179
|
+
}
|
|
23180
|
+
}
|
|
23181
|
+
if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(trimmed)) {
|
|
23182
|
+
return null;
|
|
23183
|
+
}
|
|
23184
|
+
return trimmed;
|
|
23185
|
+
}
|
|
23186
|
+
async function readAuthorizedRaster(uri, roots, signal) {
|
|
23187
|
+
signal.throwIfAborted();
|
|
23188
|
+
const requested = parseLocalImageUri(uri);
|
|
23189
|
+
if (requested === null) {
|
|
23190
|
+
return null;
|
|
23191
|
+
}
|
|
23192
|
+
const target = await resolveCanonicalPath(requested, signal);
|
|
23193
|
+
if (target === null) {
|
|
23194
|
+
return null;
|
|
23195
|
+
}
|
|
23196
|
+
const targetMetadata = await stat5(target);
|
|
23197
|
+
signal.throwIfAborted();
|
|
23198
|
+
if (!targetMetadata.isFile() || targetMetadata.size < 1 || targetMetadata.size > MAX_LOCAL_RASTER_BYTES) {
|
|
23199
|
+
return null;
|
|
23200
|
+
}
|
|
23201
|
+
const authorizedRoots = [];
|
|
23202
|
+
for (const root of roots) {
|
|
23203
|
+
const directory = await resolveCanonicalPath(root, signal);
|
|
23204
|
+
if (directory === null) {
|
|
23205
|
+
continue;
|
|
23206
|
+
}
|
|
23207
|
+
const metadata = await stat5(directory);
|
|
23208
|
+
signal.throwIfAborted();
|
|
23209
|
+
if (metadata.isDirectory()) {
|
|
23210
|
+
authorizedRoots.push(directory);
|
|
23211
|
+
}
|
|
23212
|
+
}
|
|
23213
|
+
if (!authorizedRoots.some((root) => isInsideRoot(root, target))) {
|
|
23214
|
+
return null;
|
|
23215
|
+
}
|
|
23216
|
+
const bytes = new Uint8Array(await readFile(target));
|
|
23217
|
+
signal.throwIfAborted();
|
|
23218
|
+
if (bytes.byteLength < 1 || bytes.byteLength > MAX_LOCAL_RASTER_BYTES) {
|
|
23219
|
+
return null;
|
|
23220
|
+
}
|
|
23221
|
+
const mimeType = sniffRasterMime(bytes);
|
|
23222
|
+
if (mimeType === null) {
|
|
23223
|
+
return null;
|
|
23224
|
+
}
|
|
23225
|
+
return new LocalRasterImage(basename(target) || "Image", mimeType, bytes);
|
|
23226
|
+
}
|
|
23227
|
+
|
|
23228
|
+
// src/native-sessions/history-images.ts
|
|
23229
|
+
var IMAGE_MARKER = /\[@image\]\(([^)\r\n]*)(?:\)|$)/g;
|
|
23230
|
+
async function embedLocalHistoryImages(history, roots, signal) {
|
|
23231
|
+
if (history.status !== "available") {
|
|
23232
|
+
return history;
|
|
23233
|
+
}
|
|
23234
|
+
const messages = [];
|
|
23235
|
+
let imageCharacters = 0;
|
|
23236
|
+
for (const message of history.messages) {
|
|
23237
|
+
signal.throwIfAborted();
|
|
23238
|
+
const resolved = await resolveMessageImages(message, roots, imageCharacters, signal);
|
|
23239
|
+
imageCharacters += (resolved.images ?? []).reduce((size, image) => size + image.data.length, 0);
|
|
23240
|
+
messages.push(resolved);
|
|
23241
|
+
}
|
|
23242
|
+
return {
|
|
23243
|
+
...history,
|
|
23244
|
+
messages
|
|
23245
|
+
};
|
|
23246
|
+
}
|
|
23247
|
+
async function resolveMessageImages(message, roots, usedCharacters, signal) {
|
|
23248
|
+
const images = [...message.images ?? []];
|
|
23249
|
+
let imageCharacters = images.reduce((size, image) => size + image.data.length, 0);
|
|
23250
|
+
const text = await replaceImageMarkers(message.text, async (uri) => {
|
|
23251
|
+
if (images.length >= 8 || usedCharacters + imageCharacters >= SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
|
|
23252
|
+
return "[Image unavailable]";
|
|
23253
|
+
}
|
|
23254
|
+
const embedded = parseNativeHistoryText(`[@image](${uri})`).images[0];
|
|
23255
|
+
if (embedded !== void 0) {
|
|
23256
|
+
if (usedCharacters + imageCharacters + embedded.data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
|
|
23257
|
+
return "[Image unavailable]";
|
|
23258
|
+
}
|
|
23259
|
+
images.push(embedded);
|
|
23260
|
+
imageCharacters += embedded.data.length;
|
|
23261
|
+
return "";
|
|
23262
|
+
}
|
|
23263
|
+
const local = await readAuthorizedRaster(uri, roots, signal);
|
|
23264
|
+
if (local === null) {
|
|
23265
|
+
return "[Image unavailable]";
|
|
23266
|
+
}
|
|
23267
|
+
const data = local.base64();
|
|
23268
|
+
if (usedCharacters + imageCharacters + data.length > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
|
|
23269
|
+
return "[Image unavailable]";
|
|
23270
|
+
}
|
|
23271
|
+
images.push({
|
|
23272
|
+
data,
|
|
23273
|
+
mimeType: local.mimeType,
|
|
23274
|
+
name: local.name
|
|
23275
|
+
});
|
|
23276
|
+
imageCharacters += data.length;
|
|
23277
|
+
return "";
|
|
23278
|
+
});
|
|
23279
|
+
return {
|
|
23280
|
+
...message,
|
|
23281
|
+
text,
|
|
23282
|
+
...images.length > 0 ? { images } : {}
|
|
23283
|
+
};
|
|
23284
|
+
}
|
|
23285
|
+
async function replaceImageMarkers(text, replace) {
|
|
23286
|
+
const matches = [...text.matchAll(IMAGE_MARKER)];
|
|
23287
|
+
if (matches.length === 0) {
|
|
23288
|
+
return text;
|
|
23289
|
+
}
|
|
23290
|
+
let cursor = 0;
|
|
23291
|
+
let rewritten = "";
|
|
23292
|
+
for (const match of matches) {
|
|
23293
|
+
const index = match.index ?? 0;
|
|
23294
|
+
rewritten += text.slice(cursor, index);
|
|
23295
|
+
rewritten += await replace(match[1] ?? "");
|
|
23296
|
+
cursor = index + match[0].length;
|
|
23297
|
+
}
|
|
23298
|
+
return `${rewritten}${text.slice(cursor)}`;
|
|
23299
|
+
}
|
|
23300
|
+
|
|
23054
23301
|
// src/acp/activity.ts
|
|
23055
23302
|
var TRUNCATION_MARKER = "\n\u2026 output truncated by Mobius";
|
|
23056
23303
|
function isRecord6(value) {
|
|
@@ -23148,6 +23395,7 @@ function readContentOutputDetail(content) {
|
|
|
23148
23395
|
function summarizeDisplayContent(content) {
|
|
23149
23396
|
return {
|
|
23150
23397
|
...content,
|
|
23398
|
+
artifactId: truncate(content.artifactId, 128),
|
|
23151
23399
|
data: truncate(content.data, AGENT_ACTIVITY_DETAIL_LIMIT),
|
|
23152
23400
|
mimeType: truncate(content.mimeType, 255),
|
|
23153
23401
|
name: truncate(content.name, 500),
|
|
@@ -23160,7 +23408,7 @@ function summarizeDisplayContent(content) {
|
|
|
23160
23408
|
};
|
|
23161
23409
|
}
|
|
23162
23410
|
function contentFitsRecordingEnvelope(content) {
|
|
23163
|
-
return content.data.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.mimeType.length <= 255 && content.name.length <= 500 && content.newText.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.oldText.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.path.length <= 2048 && content.terminalId.length <= 255 && content.text.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.uri.length <= 4096;
|
|
23411
|
+
return content.artifactId.length <= 128 && content.data.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.mimeType.length <= 255 && content.name.length <= 500 && content.newText.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.oldText.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.path.length <= 2048 && content.terminalId.length <= 255 && content.text.length <= AGENT_ACTIVITY_RECORDED_FIELD_LIMIT && content.uri.length <= 4096;
|
|
23164
23412
|
}
|
|
23165
23413
|
function encodedByteLength(value) {
|
|
23166
23414
|
return new TextEncoder().encode(JSON.stringify(value)).byteLength;
|
|
@@ -23186,6 +23434,7 @@ function recordedDetail(activity) {
|
|
|
23186
23434
|
}
|
|
23187
23435
|
function emptyDisplayContent(type) {
|
|
23188
23436
|
return {
|
|
23437
|
+
artifactId: "",
|
|
23189
23438
|
data: "",
|
|
23190
23439
|
mimeType: "",
|
|
23191
23440
|
name: "",
|
|
@@ -23198,6 +23447,16 @@ function emptyDisplayContent(type) {
|
|
|
23198
23447
|
uri: ""
|
|
23199
23448
|
};
|
|
23200
23449
|
}
|
|
23450
|
+
function imageDisplayContent(mimeType, name, data, artifactId = "", uri = "") {
|
|
23451
|
+
return {
|
|
23452
|
+
...emptyDisplayContent("image"),
|
|
23453
|
+
artifactId,
|
|
23454
|
+
data,
|
|
23455
|
+
mimeType,
|
|
23456
|
+
name,
|
|
23457
|
+
uri
|
|
23458
|
+
};
|
|
23459
|
+
}
|
|
23201
23460
|
function normalizeContentBlock(content) {
|
|
23202
23461
|
if (content.type === "text") {
|
|
23203
23462
|
return { ...emptyDisplayContent("text"), text: content.text };
|
|
@@ -23989,7 +24248,6 @@ var AcpHistoryReplay = class {
|
|
|
23989
24248
|
#messages = [];
|
|
23990
24249
|
#lastMessageId = null;
|
|
23991
24250
|
#characters = 0;
|
|
23992
|
-
#imageCharacters = 0;
|
|
23993
24251
|
#truncated = false;
|
|
23994
24252
|
record = (update) => {
|
|
23995
24253
|
if (update.sessionUpdate !== "user_message_chunk" && update.sessionUpdate !== "agent_message_chunk") {
|
|
@@ -24000,40 +24258,30 @@ var AcpHistoryReplay = class {
|
|
|
24000
24258
|
}
|
|
24001
24259
|
const role = update.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
|
|
24002
24260
|
const content = update.content;
|
|
24003
|
-
const
|
|
24004
|
-
|
|
24005
|
-
);
|
|
24006
|
-
const text = parsed.text;
|
|
24007
|
-
if (text.length === 0 && parsed.images.length === 0) {
|
|
24261
|
+
const text = content.type === "text" ? content.text : content.type === "image" ? content.data.length > 0 ? `[@image](data:${content.mimeType};base64,${content.data})` : content.uri != null && content.uri.length > 0 ? `[@image](${content.uri})` : "[image attachment]" : `[${content.type} attachment]`;
|
|
24262
|
+
if (text.length === 0) {
|
|
24008
24263
|
return;
|
|
24009
24264
|
}
|
|
24010
24265
|
const previous = this.#messages.at(-1);
|
|
24011
24266
|
const id = update.messageId ?? null;
|
|
24012
24267
|
const continuation = previous?.role === role && id === this.#lastMessageId;
|
|
24013
24268
|
const combined = continuation ? `${previous.text}${text}` : text;
|
|
24014
|
-
const allImages = continuation ? [...previous.images ?? [], ...parsed.images] : parsed.images;
|
|
24015
|
-
const images = allImages.slice(0, 8);
|
|
24016
|
-
this.#truncated ||= images.length < allImages.length;
|
|
24017
24269
|
if (continuation) {
|
|
24018
24270
|
this.#messages.pop();
|
|
24019
24271
|
this.#characters -= previous.text.length;
|
|
24020
|
-
this.#imageCharacters -= (previous.images ?? []).reduce((size, image) => size + image.data.length, 0);
|
|
24021
24272
|
}
|
|
24022
24273
|
const bounded = combined.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
|
|
24023
24274
|
this.#truncated ||= bounded.length < combined.length;
|
|
24024
24275
|
this.#messages.push({
|
|
24025
24276
|
role,
|
|
24026
|
-
text: bounded
|
|
24027
|
-
...images.length > 0 ? { images } : {}
|
|
24277
|
+
text: bounded
|
|
24028
24278
|
});
|
|
24029
24279
|
this.#characters += bounded.length;
|
|
24030
|
-
this.#imageCharacters += images.reduce((size, image) => size + image.data.length, 0);
|
|
24031
24280
|
this.#lastMessageId = id;
|
|
24032
|
-
while (this.#messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || this.#characters > SESSION_HISTORY_CHARACTER_LIMIT
|
|
24281
|
+
while (this.#messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || this.#characters > SESSION_HISTORY_CHARACTER_LIMIT) {
|
|
24033
24282
|
const removed = this.#messages.shift();
|
|
24034
24283
|
if (removed !== void 0) {
|
|
24035
24284
|
this.#characters -= removed.text.length;
|
|
24036
|
-
this.#imageCharacters -= (removed.images ?? []).reduce((size, image) => size + image.data.length, 0);
|
|
24037
24285
|
}
|
|
24038
24286
|
this.#truncated = true;
|
|
24039
24287
|
}
|
|
@@ -24256,6 +24504,10 @@ var MAX_PRE_SESSION_UPDATES = 100;
|
|
|
24256
24504
|
var MAX_PRE_SESSION_UPDATE_BYTES = 1024 * 1024;
|
|
24257
24505
|
var SESSION_CONTROL_COMMAND_ID = "session-control";
|
|
24258
24506
|
var NullAcpSessionObserver = class {
|
|
24507
|
+
importLocalImage = (_sessionId, _image, signal) => {
|
|
24508
|
+
signal.throwIfAborted();
|
|
24509
|
+
return Promise.resolve("");
|
|
24510
|
+
};
|
|
24259
24511
|
onCommands = () => Promise.resolve();
|
|
24260
24512
|
onConfig = () => Promise.resolve();
|
|
24261
24513
|
onContent = () => Promise.resolve();
|
|
@@ -24878,11 +25130,75 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24878
25130
|
);
|
|
24879
25131
|
await this.#updateTail;
|
|
24880
25132
|
signal.throwIfAborted();
|
|
24881
|
-
return
|
|
25133
|
+
return await embedLocalHistoryImages(
|
|
25134
|
+
history.snapshot(),
|
|
25135
|
+
[this.#cwd, ...this.#additionalDirectories],
|
|
25136
|
+
signal
|
|
25137
|
+
);
|
|
24882
25138
|
} finally {
|
|
24883
25139
|
this.#replay = { kind: "idle" };
|
|
24884
25140
|
}
|
|
24885
25141
|
};
|
|
25142
|
+
imageRoots = () => [this.#cwd, ...this.#additionalDirectories];
|
|
25143
|
+
emitAgentText = async (text, messageId) => {
|
|
25144
|
+
const signal = AbortSignal.timeout(2e4);
|
|
25145
|
+
const parts = text.split(/(\[@image\]\([^)\r\n]*(?:\)|$))/);
|
|
25146
|
+
let leftover = "";
|
|
25147
|
+
for (const part of parts) {
|
|
25148
|
+
const marker = /^\[@image\]\(([^)\r\n]*)(?:\)|$)/.exec(part);
|
|
25149
|
+
if (marker === null) {
|
|
25150
|
+
leftover += part;
|
|
25151
|
+
continue;
|
|
25152
|
+
}
|
|
25153
|
+
if (leftover.length > 0) {
|
|
25154
|
+
await this.#turn.onText(leftover, messageId);
|
|
25155
|
+
leftover = "";
|
|
25156
|
+
}
|
|
25157
|
+
const raster = await readAuthorizedRaster(marker[1] ?? "", this.imageRoots(), signal);
|
|
25158
|
+
if (raster === null) {
|
|
25159
|
+
leftover += "[Image unavailable]";
|
|
25160
|
+
continue;
|
|
25161
|
+
}
|
|
25162
|
+
await this.emitRaster(raster, messageId, signal);
|
|
25163
|
+
}
|
|
25164
|
+
if (leftover.length > 0) {
|
|
25165
|
+
await this.#turn.onText(leftover, messageId);
|
|
25166
|
+
}
|
|
25167
|
+
};
|
|
25168
|
+
emitAgentContent = async (content, messageId) => {
|
|
25169
|
+
if (content.type === "image" && content.data.length === 0 && content.uri.length > 0) {
|
|
25170
|
+
const signal = AbortSignal.timeout(2e4);
|
|
25171
|
+
const raster = await readAuthorizedRaster(content.uri, this.imageRoots(), signal);
|
|
25172
|
+
if (raster !== null) {
|
|
25173
|
+
await this.emitRaster(raster, messageId, signal);
|
|
25174
|
+
return;
|
|
25175
|
+
}
|
|
25176
|
+
}
|
|
25177
|
+
await this.#getObserver().onContent({
|
|
25178
|
+
commandId: this.#turn.commandId,
|
|
25179
|
+
content,
|
|
25180
|
+
contentId: `content-${crypto.randomUUID()}`,
|
|
25181
|
+
kind: AGENT_CONTENT_KIND,
|
|
25182
|
+
messageId,
|
|
25183
|
+
sessionId: this.#mobiusSessionId
|
|
25184
|
+
});
|
|
25185
|
+
};
|
|
25186
|
+
emitRaster = async (raster, messageId, signal) => {
|
|
25187
|
+
const artifactId = await this.#getObserver().importLocalImage(this.#mobiusSessionId, raster, signal);
|
|
25188
|
+
await this.#getObserver().onContent({
|
|
25189
|
+
commandId: this.#turn.commandId,
|
|
25190
|
+
content: imageDisplayContent(
|
|
25191
|
+
raster.mimeType,
|
|
25192
|
+
raster.name,
|
|
25193
|
+
artifactId.length > 0 ? "" : raster.base64(),
|
|
25194
|
+
artifactId
|
|
25195
|
+
),
|
|
25196
|
+
contentId: `content-${crypto.randomUUID()}`,
|
|
25197
|
+
kind: AGENT_CONTENT_KIND,
|
|
25198
|
+
messageId,
|
|
25199
|
+
sessionId: this.#mobiusSessionId
|
|
25200
|
+
});
|
|
25201
|
+
};
|
|
24886
25202
|
async #initializeAgent(signal) {
|
|
24887
25203
|
const initialized = await this.race(
|
|
24888
25204
|
this.#connection.agent.request(
|
|
@@ -25585,18 +25901,14 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
25585
25901
|
);
|
|
25586
25902
|
} else {
|
|
25587
25903
|
await this.#turn.activities.finishNarrative();
|
|
25588
|
-
await this
|
|
25904
|
+
await this.emitAgentText(update.content.text, truncate3(update.messageId ?? "", 255));
|
|
25589
25905
|
}
|
|
25590
25906
|
} else {
|
|
25591
25907
|
await this.#turn.activities.finishNarrative();
|
|
25592
|
-
await this
|
|
25593
|
-
|
|
25594
|
-
|
|
25595
|
-
|
|
25596
|
-
kind: AGENT_CONTENT_KIND,
|
|
25597
|
-
messageId: truncate3(update.messageId ?? "", 255),
|
|
25598
|
-
sessionId: this.#mobiusSessionId
|
|
25599
|
-
});
|
|
25908
|
+
await this.emitAgentContent(
|
|
25909
|
+
normalizeContentBlock(update.content),
|
|
25910
|
+
truncate3(update.messageId ?? "", 255)
|
|
25911
|
+
);
|
|
25600
25912
|
}
|
|
25601
25913
|
return;
|
|
25602
25914
|
}
|
|
@@ -26418,6 +26730,23 @@ var AcpSessionManager = class {
|
|
|
26418
26730
|
|
|
26419
26731
|
// src/agent-catalog/publish-agent-catalog.ts
|
|
26420
26732
|
import { fetch as fetch2 } from "undici";
|
|
26733
|
+
|
|
26734
|
+
// src/relay-connection/runtime-authentication.ts
|
|
26735
|
+
function runtimeCredential(relayUrl) {
|
|
26736
|
+
return relayUrl.searchParams.get("token") ?? "";
|
|
26737
|
+
}
|
|
26738
|
+
function runtimeAuthorization(relayUrl) {
|
|
26739
|
+
const credential = runtimeCredential(relayUrl);
|
|
26740
|
+
return credential.length === 0 ? {} : { authorization: `Bearer ${credential}` };
|
|
26741
|
+
}
|
|
26742
|
+
function relayHttpEndpoint(relayUrl) {
|
|
26743
|
+
const endpoint = new URL(relayUrl);
|
|
26744
|
+
endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
|
|
26745
|
+
endpoint.search = "";
|
|
26746
|
+
return endpoint;
|
|
26747
|
+
}
|
|
26748
|
+
|
|
26749
|
+
// src/agent-catalog/publish-agent-catalog.ts
|
|
26421
26750
|
var CATALOG_UPDATE_TIMEOUT_MILLISECONDS = 2e4;
|
|
26422
26751
|
var AgentCatalogPublishError = class extends Error {
|
|
26423
26752
|
code = "agent_catalog_update_failed";
|
|
@@ -26427,8 +26756,7 @@ var AgentCatalogPublishError = class extends Error {
|
|
|
26427
26756
|
}
|
|
26428
26757
|
};
|
|
26429
26758
|
function catalogEndpoint(config2) {
|
|
26430
|
-
const endpoint =
|
|
26431
|
-
endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
|
|
26759
|
+
const endpoint = relayHttpEndpoint(config2.relayUrl);
|
|
26432
26760
|
if (endpoint.pathname.endsWith("/daemon")) {
|
|
26433
26761
|
endpoint.pathname = `${endpoint.pathname.slice(0, -"/daemon".length)}/catalog`;
|
|
26434
26762
|
return endpoint;
|
|
@@ -26459,7 +26787,7 @@ async function publishAgentCatalog(config2, signal) {
|
|
|
26459
26787
|
installableAgents: catalog.installableAgents
|
|
26460
26788
|
}),
|
|
26461
26789
|
dispatcher: environmentProxyDispatcher,
|
|
26462
|
-
headers: { "content-type": "application/json" },
|
|
26790
|
+
headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
|
|
26463
26791
|
method: "PUT",
|
|
26464
26792
|
signal: requestSignal
|
|
26465
26793
|
});
|
|
@@ -26941,114 +27269,510 @@ var FixedInstallationExecutor = class {
|
|
|
26941
27269
|
};
|
|
26942
27270
|
};
|
|
26943
27271
|
|
|
26944
|
-
// src/
|
|
26945
|
-
|
|
26946
|
-
|
|
26947
|
-
|
|
27272
|
+
// src/artifacts/runtime-artifact-uploader.ts
|
|
27273
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
27274
|
+
|
|
27275
|
+
// ../mobius-sdk/src/errors.ts
|
|
27276
|
+
var MobiusError = class extends Error {
|
|
27277
|
+
code;
|
|
27278
|
+
constructor(code, message, options = {}) {
|
|
26948
27279
|
super(message, options);
|
|
26949
|
-
this.
|
|
27280
|
+
this.code = code;
|
|
27281
|
+
this.name = "MobiusError";
|
|
26950
27282
|
}
|
|
26951
27283
|
};
|
|
26952
|
-
|
|
26953
|
-
|
|
26954
|
-
|
|
26955
|
-
|
|
26956
|
-
import { basename, dirname as dirname5, isAbsolute as isAbsolute7, join as join14, normalize as normalize2, relative as relative4 } from "node:path";
|
|
26957
|
-
var WorkspaceDirectoryListing = class {
|
|
26958
|
-
directoryId;
|
|
26959
|
-
directoryLabel;
|
|
26960
|
-
entries;
|
|
26961
|
-
parentDirectoryId;
|
|
26962
|
-
constructor(directoryId2, directoryLabel, entries, parentDirectoryId) {
|
|
26963
|
-
this.directoryId = directoryId2;
|
|
26964
|
-
this.directoryLabel = directoryLabel;
|
|
26965
|
-
this.entries = entries;
|
|
26966
|
-
this.parentDirectoryId = parentDirectoryId;
|
|
27284
|
+
var MobiusProtocolError = class extends MobiusError {
|
|
27285
|
+
constructor(message, options = {}) {
|
|
27286
|
+
super("invalid_service_response", message, options);
|
|
27287
|
+
this.name = "MobiusProtocolError";
|
|
26967
27288
|
}
|
|
26968
27289
|
};
|
|
26969
|
-
|
|
26970
|
-
|
|
26971
|
-
|
|
26972
|
-
|
|
27290
|
+
var MobiusValidationError = class extends MobiusError {
|
|
27291
|
+
constructor(message, options = {}) {
|
|
27292
|
+
super("invalid_request", message, options);
|
|
27293
|
+
this.name = "MobiusValidationError";
|
|
26973
27294
|
}
|
|
26974
|
-
|
|
27295
|
+
};
|
|
27296
|
+
|
|
27297
|
+
// ../mobius-sdk/src/resources.ts
|
|
27298
|
+
var IDENTIFIER_PATTERN5 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
27299
|
+
function invalidResponse(message) {
|
|
27300
|
+
return new MobiusProtocolError(message);
|
|
26975
27301
|
}
|
|
26976
|
-
function
|
|
26977
|
-
|
|
26978
|
-
|
|
26979
|
-
|
|
27302
|
+
function isRecord9(value) {
|
|
27303
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27304
|
+
}
|
|
27305
|
+
function record2(value, name) {
|
|
27306
|
+
if (!isRecord9(value)) {
|
|
27307
|
+
throw invalidResponse(`The service returned an invalid ${name}`);
|
|
26980
27308
|
}
|
|
26981
|
-
|
|
26982
|
-
|
|
26983
|
-
|
|
27309
|
+
return value;
|
|
27310
|
+
}
|
|
27311
|
+
function stringField(value, field, maximumLength = 85e5) {
|
|
27312
|
+
const candidate = value[field];
|
|
27313
|
+
if (typeof candidate !== "string" || candidate.length > maximumLength) {
|
|
27314
|
+
throw invalidResponse(`The service returned an invalid ${field}`);
|
|
26984
27315
|
}
|
|
26985
|
-
return
|
|
27316
|
+
return candidate;
|
|
26986
27317
|
}
|
|
26987
|
-
|
|
26988
|
-
|
|
26989
|
-
|
|
26990
|
-
|
|
26991
|
-
this.#bindingId = bindingId;
|
|
26992
|
-
this.#defaultWorkspace = defaultWorkspace;
|
|
27318
|
+
function identifierField(value, field) {
|
|
27319
|
+
const candidate = stringField(value, field, 128);
|
|
27320
|
+
if (!IDENTIFIER_PATTERN5.test(candidate)) {
|
|
27321
|
+
throw invalidResponse(`The service returned an invalid ${field}`);
|
|
26993
27322
|
}
|
|
26994
|
-
|
|
26995
|
-
|
|
26996
|
-
|
|
26997
|
-
|
|
26998
|
-
|
|
26999
|
-
|
|
27000
|
-
|
|
27001
|
-
|
|
27002
|
-
|
|
27003
|
-
|
|
27004
|
-
|
|
27005
|
-
}
|
|
27006
|
-
|
|
27007
|
-
|
|
27008
|
-
|
|
27009
|
-
|
|
27010
|
-
|
|
27011
|
-
|
|
27012
|
-
|
|
27013
|
-
|
|
27014
|
-
|
|
27015
|
-
|
|
27016
|
-
|
|
27017
|
-
throw new LocalAuthorizationError("The local directory path is invalid");
|
|
27018
|
-
}
|
|
27019
|
-
try {
|
|
27020
|
-
const target = await realpath6(requested);
|
|
27021
|
-
signal.throwIfAborted();
|
|
27022
|
-
const metadata = await stat5(target);
|
|
27023
|
-
signal.throwIfAborted();
|
|
27024
|
-
if (!isAbsolute7(target) || normalize2(target) !== target || !metadata.isDirectory()) {
|
|
27025
|
-
throw new LocalAuthorizationError("The selected location is not a directory");
|
|
27026
|
-
}
|
|
27027
|
-
return target;
|
|
27028
|
-
} catch (cause) {
|
|
27029
|
-
signal.throwIfAborted();
|
|
27030
|
-
if (cause instanceof LocalAuthorizationError) {
|
|
27031
|
-
throw cause;
|
|
27032
|
-
}
|
|
27033
|
-
throw new LocalAuthorizationError("This directory is missing or unavailable to your user account", {
|
|
27034
|
-
cause
|
|
27035
|
-
});
|
|
27323
|
+
return candidate;
|
|
27324
|
+
}
|
|
27325
|
+
function integerField(value, field) {
|
|
27326
|
+
const candidate = value[field];
|
|
27327
|
+
if (typeof candidate !== "number" || !Number.isSafeInteger(candidate) || candidate < 0) {
|
|
27328
|
+
throw invalidResponse(`The service returned an invalid ${field}`);
|
|
27329
|
+
}
|
|
27330
|
+
return candidate;
|
|
27331
|
+
}
|
|
27332
|
+
function validateTimestamp(value, field) {
|
|
27333
|
+
if (Number.isNaN(Date.parse(value))) {
|
|
27334
|
+
throw invalidResponse(`The service returned an invalid ${field}`);
|
|
27335
|
+
}
|
|
27336
|
+
return value;
|
|
27337
|
+
}
|
|
27338
|
+
var MobiusArtifactUploadRequest = class {
|
|
27339
|
+
byteLength;
|
|
27340
|
+
mediaType;
|
|
27341
|
+
name;
|
|
27342
|
+
sha256;
|
|
27343
|
+
constructor(name, mediaType, byteLength, sha256) {
|
|
27344
|
+
if (name.length < 1 || name.length > 500 || name.includes("\0") || mediaType.length < 1 || mediaType.length > 255 || mediaType.includes("\r") || mediaType.includes("\n") || !Number.isSafeInteger(byteLength) || byteLength < 1 || !/^[a-f0-9]{64}$/.test(sha256)) {
|
|
27345
|
+
throw new MobiusValidationError("The artifact upload request is invalid");
|
|
27036
27346
|
}
|
|
27037
|
-
|
|
27038
|
-
|
|
27039
|
-
|
|
27040
|
-
|
|
27041
|
-
}
|
|
27042
|
-
|
|
27043
|
-
|
|
27044
|
-
|
|
27045
|
-
|
|
27046
|
-
|
|
27047
|
-
|
|
27048
|
-
|
|
27049
|
-
|
|
27050
|
-
|
|
27051
|
-
|
|
27347
|
+
this.byteLength = byteLength;
|
|
27348
|
+
this.mediaType = mediaType;
|
|
27349
|
+
this.name = name;
|
|
27350
|
+
this.sha256 = sha256;
|
|
27351
|
+
}
|
|
27352
|
+
};
|
|
27353
|
+
var MobiusArtifact = class {
|
|
27354
|
+
artifactId;
|
|
27355
|
+
byteLength;
|
|
27356
|
+
createdAt;
|
|
27357
|
+
mediaType;
|
|
27358
|
+
name;
|
|
27359
|
+
sessionId;
|
|
27360
|
+
sha256;
|
|
27361
|
+
constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt) {
|
|
27362
|
+
this.artifactId = artifactId;
|
|
27363
|
+
this.byteLength = byteLength;
|
|
27364
|
+
this.createdAt = createdAt;
|
|
27365
|
+
this.mediaType = mediaType;
|
|
27366
|
+
this.name = name;
|
|
27367
|
+
this.sessionId = sessionId;
|
|
27368
|
+
this.sha256 = sha256;
|
|
27369
|
+
}
|
|
27370
|
+
};
|
|
27371
|
+
var MobiusUploadingArtifact = class extends MobiusArtifact {
|
|
27372
|
+
expiresAt;
|
|
27373
|
+
state = "uploading";
|
|
27374
|
+
constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, expiresAt) {
|
|
27375
|
+
super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
|
|
27376
|
+
this.expiresAt = expiresAt;
|
|
27377
|
+
}
|
|
27378
|
+
};
|
|
27379
|
+
var MobiusArtifactUpload = class extends MobiusUploadingArtifact {
|
|
27380
|
+
uploadToken;
|
|
27381
|
+
constructor(artifact, uploadToken) {
|
|
27382
|
+
super(
|
|
27383
|
+
artifact.sessionId,
|
|
27384
|
+
artifact.artifactId,
|
|
27385
|
+
artifact.name,
|
|
27386
|
+
artifact.mediaType,
|
|
27387
|
+
artifact.byteLength,
|
|
27388
|
+
artifact.sha256,
|
|
27389
|
+
artifact.createdAt,
|
|
27390
|
+
artifact.expiresAt
|
|
27391
|
+
);
|
|
27392
|
+
this.uploadToken = uploadToken;
|
|
27393
|
+
}
|
|
27394
|
+
};
|
|
27395
|
+
var MobiusAvailableArtifact = class extends MobiusArtifact {
|
|
27396
|
+
availableAt;
|
|
27397
|
+
state = "available";
|
|
27398
|
+
constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, availableAt) {
|
|
27399
|
+
super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
|
|
27400
|
+
this.availableAt = availableAt;
|
|
27401
|
+
}
|
|
27402
|
+
};
|
|
27403
|
+
var MobiusExpiredArtifact = class extends MobiusArtifact {
|
|
27404
|
+
expiredAt;
|
|
27405
|
+
state = "expired";
|
|
27406
|
+
constructor(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt, expiredAt) {
|
|
27407
|
+
super(sessionId, artifactId, name, mediaType, byteLength, sha256, createdAt);
|
|
27408
|
+
this.expiredAt = expiredAt;
|
|
27409
|
+
}
|
|
27410
|
+
};
|
|
27411
|
+
function artifactFields(value) {
|
|
27412
|
+
const sha256 = stringField(value, "sha256", 64);
|
|
27413
|
+
if (!/^[a-f0-9]{64}$/.test(sha256)) {
|
|
27414
|
+
throw invalidResponse("The service returned an invalid artifact digest");
|
|
27415
|
+
}
|
|
27416
|
+
return {
|
|
27417
|
+
artifactId: identifierField(value, "artifactId"),
|
|
27418
|
+
byteLength: integerField(value, "byteLength"),
|
|
27419
|
+
createdAt: validateTimestamp(stringField(value, "createdAt", 128), "createdAt"),
|
|
27420
|
+
mediaType: stringField(value, "mediaType", 255),
|
|
27421
|
+
name: stringField(value, "name", 500),
|
|
27422
|
+
sessionId: identifierField(value, "sessionId"),
|
|
27423
|
+
sha256
|
|
27424
|
+
};
|
|
27425
|
+
}
|
|
27426
|
+
function uploadingArtifact(value) {
|
|
27427
|
+
const fields = artifactFields(value);
|
|
27428
|
+
return new MobiusUploadingArtifact(
|
|
27429
|
+
fields.sessionId,
|
|
27430
|
+
fields.artifactId,
|
|
27431
|
+
fields.name,
|
|
27432
|
+
fields.mediaType,
|
|
27433
|
+
fields.byteLength,
|
|
27434
|
+
fields.sha256,
|
|
27435
|
+
fields.createdAt,
|
|
27436
|
+
validateTimestamp(stringField(value, "expiresAt", 128), "expiresAt")
|
|
27437
|
+
);
|
|
27438
|
+
}
|
|
27439
|
+
function decodeMobiusArtifactUpload(value) {
|
|
27440
|
+
const artifact = record2(value, "artifact upload authorization");
|
|
27441
|
+
return new MobiusArtifactUpload(uploadingArtifact(artifact), stringField(artifact, "uploadToken", 256));
|
|
27442
|
+
}
|
|
27443
|
+
function decodeMobiusArtifact(value) {
|
|
27444
|
+
const artifact = record2(value, "artifact");
|
|
27445
|
+
const state = stringField(artifact, "state", 32);
|
|
27446
|
+
if (state === "uploading") {
|
|
27447
|
+
return uploadingArtifact(artifact);
|
|
27448
|
+
}
|
|
27449
|
+
const fields = artifactFields(artifact);
|
|
27450
|
+
if (state === "available") {
|
|
27451
|
+
return new MobiusAvailableArtifact(
|
|
27452
|
+
fields.sessionId,
|
|
27453
|
+
fields.artifactId,
|
|
27454
|
+
fields.name,
|
|
27455
|
+
fields.mediaType,
|
|
27456
|
+
fields.byteLength,
|
|
27457
|
+
fields.sha256,
|
|
27458
|
+
fields.createdAt,
|
|
27459
|
+
validateTimestamp(stringField(artifact, "availableAt", 128), "availableAt")
|
|
27460
|
+
);
|
|
27461
|
+
}
|
|
27462
|
+
if (state === "expired") {
|
|
27463
|
+
return new MobiusExpiredArtifact(
|
|
27464
|
+
fields.sessionId,
|
|
27465
|
+
fields.artifactId,
|
|
27466
|
+
fields.name,
|
|
27467
|
+
fields.mediaType,
|
|
27468
|
+
fields.byteLength,
|
|
27469
|
+
fields.sha256,
|
|
27470
|
+
fields.createdAt,
|
|
27471
|
+
validateTimestamp(stringField(artifact, "expiredAt", 128), "expiredAt")
|
|
27472
|
+
);
|
|
27473
|
+
}
|
|
27474
|
+
throw invalidResponse("The service returned an invalid artifact state");
|
|
27475
|
+
}
|
|
27476
|
+
function decodeMobiusAvailableArtifact(value) {
|
|
27477
|
+
const artifact = decodeMobiusArtifact(value);
|
|
27478
|
+
if (!(artifact instanceof MobiusAvailableArtifact)) {
|
|
27479
|
+
throw invalidResponse("The service did not make the artifact available");
|
|
27480
|
+
}
|
|
27481
|
+
return artifact;
|
|
27482
|
+
}
|
|
27483
|
+
var MobiusRuntimePairingLifecycle = Object.freeze({
|
|
27484
|
+
Expired: "expired",
|
|
27485
|
+
Paired: "paired",
|
|
27486
|
+
Pending: "pending",
|
|
27487
|
+
Revoked: "revoked"
|
|
27488
|
+
});
|
|
27489
|
+
|
|
27490
|
+
// src/artifacts/runtime-artifact-uploader.ts
|
|
27491
|
+
import { fetch as fetch3 } from "undici";
|
|
27492
|
+
var UPLOAD_TIMEOUT_MILLISECONDS = 2e4;
|
|
27493
|
+
var RuntimeArtifactUploadError = class extends Error {
|
|
27494
|
+
code;
|
|
27495
|
+
constructor(code, message, options = {}) {
|
|
27496
|
+
super(message, options);
|
|
27497
|
+
this.code = code;
|
|
27498
|
+
this.name = "RuntimeArtifactUploadError";
|
|
27499
|
+
}
|
|
27500
|
+
};
|
|
27501
|
+
var UploadedRuntimeArtifact = class {
|
|
27502
|
+
artifactId;
|
|
27503
|
+
byteLength;
|
|
27504
|
+
mimeType;
|
|
27505
|
+
name;
|
|
27506
|
+
sha256;
|
|
27507
|
+
constructor(artifactId, name, mimeType, byteLength, sha256) {
|
|
27508
|
+
this.artifactId = artifactId;
|
|
27509
|
+
this.byteLength = byteLength;
|
|
27510
|
+
this.mimeType = mimeType;
|
|
27511
|
+
this.name = name;
|
|
27512
|
+
this.sha256 = sha256;
|
|
27513
|
+
}
|
|
27514
|
+
};
|
|
27515
|
+
function daemonToken(config2) {
|
|
27516
|
+
const token = config2.relayUrl.searchParams.get("token");
|
|
27517
|
+
if (token === null || token.length < 32) {
|
|
27518
|
+
throw new RuntimeArtifactUploadError("artifact_endpoint_invalid", "The Relay daemon token is missing");
|
|
27519
|
+
}
|
|
27520
|
+
return token;
|
|
27521
|
+
}
|
|
27522
|
+
function channelOrigin(config2) {
|
|
27523
|
+
const url2 = new URL(config2.relayUrl);
|
|
27524
|
+
url2.protocol = url2.protocol === "wss:" ? "https:" : "http:";
|
|
27525
|
+
let channelPath = "";
|
|
27526
|
+
if (url2.pathname.endsWith("/daemon")) {
|
|
27527
|
+
channelPath = url2.pathname.slice(0, -"/daemon".length);
|
|
27528
|
+
} else {
|
|
27529
|
+
const runtimePath = `${MOBIUS_API_PREFIX}/v1/runtimes/connect`;
|
|
27530
|
+
if (!url2.pathname.endsWith("/v1/runtimes/connect") && !url2.pathname.endsWith(runtimePath)) {
|
|
27531
|
+
throw new RuntimeArtifactUploadError("artifact_endpoint_invalid", "The Relay artifact endpoint is invalid");
|
|
27532
|
+
}
|
|
27533
|
+
channelPath = `${url2.pathname.replace(/\/v1\/runtimes\/connect$/, "")}/channels/${encodeURIComponent(config2.channelId)}`;
|
|
27534
|
+
}
|
|
27535
|
+
url2.pathname = channelPath;
|
|
27536
|
+
url2.search = "";
|
|
27537
|
+
url2.hash = "";
|
|
27538
|
+
return url2;
|
|
27539
|
+
}
|
|
27540
|
+
function uploadError(code, message, cause) {
|
|
27541
|
+
return new RuntimeArtifactUploadError(code, message, cause === void 0 ? {} : { cause });
|
|
27542
|
+
}
|
|
27543
|
+
function translateSdkError(cause) {
|
|
27544
|
+
if (cause instanceof MobiusValidationError) {
|
|
27545
|
+
throw uploadError("artifact_upload_failed", cause.message, cause);
|
|
27546
|
+
}
|
|
27547
|
+
if (cause instanceof MobiusProtocolError) {
|
|
27548
|
+
throw uploadError("artifact_upload_failed", "The Relay returned an invalid upload response", cause);
|
|
27549
|
+
}
|
|
27550
|
+
throw cause;
|
|
27551
|
+
}
|
|
27552
|
+
async function readJson(response) {
|
|
27553
|
+
try {
|
|
27554
|
+
return await response.json();
|
|
27555
|
+
} catch (cause) {
|
|
27556
|
+
throw uploadError("artifact_upload_failed", "The Relay returned an invalid upload response", cause);
|
|
27557
|
+
}
|
|
27558
|
+
}
|
|
27559
|
+
async function readAuthorization(response) {
|
|
27560
|
+
try {
|
|
27561
|
+
return decodeMobiusArtifactUpload(await readJson(response));
|
|
27562
|
+
} catch (cause) {
|
|
27563
|
+
translateSdkError(cause);
|
|
27564
|
+
}
|
|
27565
|
+
}
|
|
27566
|
+
function sessionArtifactUrl(origin, sessionId, resourcePath, token) {
|
|
27567
|
+
const url2 = new URL(`${origin.pathname}/sessions/${encodeURIComponent(sessionId)}/${resourcePath}`, origin);
|
|
27568
|
+
url2.searchParams.set("token", token);
|
|
27569
|
+
return url2;
|
|
27570
|
+
}
|
|
27571
|
+
async function postLease(url2, request, signal) {
|
|
27572
|
+
return await fetch3(url2, {
|
|
27573
|
+
dispatcher: environmentProxyDispatcher,
|
|
27574
|
+
headers: { "content-type": "application/json" },
|
|
27575
|
+
method: "POST",
|
|
27576
|
+
body: JSON.stringify(request),
|
|
27577
|
+
signal
|
|
27578
|
+
});
|
|
27579
|
+
}
|
|
27580
|
+
async function putContent(url2, authorization, bytes, signal) {
|
|
27581
|
+
return await fetch3(url2, {
|
|
27582
|
+
dispatcher: environmentProxyDispatcher,
|
|
27583
|
+
headers: {
|
|
27584
|
+
"content-type": authorization.mediaType,
|
|
27585
|
+
"x-mobius-upload-token": authorization.uploadToken
|
|
27586
|
+
},
|
|
27587
|
+
method: "PUT",
|
|
27588
|
+
body: bytes,
|
|
27589
|
+
signal
|
|
27590
|
+
});
|
|
27591
|
+
}
|
|
27592
|
+
async function uploadRuntimeArtifact(config2, sessionId, image, signal) {
|
|
27593
|
+
signal.throwIfAborted();
|
|
27594
|
+
let request;
|
|
27595
|
+
try {
|
|
27596
|
+
request = new MobiusArtifactUploadRequest(
|
|
27597
|
+
image.name,
|
|
27598
|
+
image.mimeType,
|
|
27599
|
+
image.bytes.byteLength,
|
|
27600
|
+
createHash2("sha256").update(image.bytes).digest("hex")
|
|
27601
|
+
);
|
|
27602
|
+
} catch (cause) {
|
|
27603
|
+
translateSdkError(cause);
|
|
27604
|
+
}
|
|
27605
|
+
const timeoutSignal = AbortSignal.timeout(UPLOAD_TIMEOUT_MILLISECONDS);
|
|
27606
|
+
const requestSignal = AbortSignal.any([signal, timeoutSignal]);
|
|
27607
|
+
const origin = channelOrigin(config2);
|
|
27608
|
+
const token = daemonToken(config2);
|
|
27609
|
+
let created;
|
|
27610
|
+
try {
|
|
27611
|
+
created = await postLease(
|
|
27612
|
+
sessionArtifactUrl(origin, sessionId, "artifacts/uploads", token),
|
|
27613
|
+
request,
|
|
27614
|
+
requestSignal
|
|
27615
|
+
);
|
|
27616
|
+
} catch (cause) {
|
|
27617
|
+
signal.throwIfAborted();
|
|
27618
|
+
throw uploadError(
|
|
27619
|
+
timeoutSignal.aborted ? "artifact_upload_timeout" : "artifact_upload_failed",
|
|
27620
|
+
timeoutSignal.aborted ? "The artifact upload authorization timed out" : "The artifact upload could not start",
|
|
27621
|
+
cause
|
|
27622
|
+
);
|
|
27623
|
+
}
|
|
27624
|
+
if (!created.ok) {
|
|
27625
|
+
await created.body?.cancel();
|
|
27626
|
+
throw uploadError("artifact_upload_rejected", "The Relay rejected the artifact upload");
|
|
27627
|
+
}
|
|
27628
|
+
const authorization = await readAuthorization(created);
|
|
27629
|
+
let uploaded;
|
|
27630
|
+
try {
|
|
27631
|
+
uploaded = await putContent(
|
|
27632
|
+
sessionArtifactUrl(
|
|
27633
|
+
origin,
|
|
27634
|
+
sessionId,
|
|
27635
|
+
`artifacts/${encodeURIComponent(authorization.artifactId)}/content`,
|
|
27636
|
+
token
|
|
27637
|
+
),
|
|
27638
|
+
authorization,
|
|
27639
|
+
image.bytes,
|
|
27640
|
+
requestSignal
|
|
27641
|
+
);
|
|
27642
|
+
} catch (cause) {
|
|
27643
|
+
signal.throwIfAborted();
|
|
27644
|
+
throw uploadError(
|
|
27645
|
+
timeoutSignal.aborted ? "artifact_upload_timeout" : "artifact_upload_failed",
|
|
27646
|
+
timeoutSignal.aborted ? "The artifact upload timed out" : "The artifact content could not be uploaded",
|
|
27647
|
+
cause
|
|
27648
|
+
);
|
|
27649
|
+
}
|
|
27650
|
+
if (!uploaded.ok) {
|
|
27651
|
+
await uploaded.body?.cancel();
|
|
27652
|
+
throw uploadError("artifact_upload_rejected", "The Relay rejected the artifact content");
|
|
27653
|
+
}
|
|
27654
|
+
try {
|
|
27655
|
+
const available = decodeMobiusAvailableArtifact(await readJson(uploaded));
|
|
27656
|
+
return new UploadedRuntimeArtifact(
|
|
27657
|
+
available.artifactId,
|
|
27658
|
+
available.name,
|
|
27659
|
+
available.mediaType,
|
|
27660
|
+
available.byteLength,
|
|
27661
|
+
available.sha256
|
|
27662
|
+
);
|
|
27663
|
+
} catch (cause) {
|
|
27664
|
+
translateSdkError(cause);
|
|
27665
|
+
}
|
|
27666
|
+
}
|
|
27667
|
+
|
|
27668
|
+
// src/authorization/local-authorization-error.ts
|
|
27669
|
+
var LocalAuthorizationError = class extends Error {
|
|
27670
|
+
code = "local_authorization_failed";
|
|
27671
|
+
constructor(message, options = {}) {
|
|
27672
|
+
super(message, options);
|
|
27673
|
+
this.name = "LocalAuthorizationError";
|
|
27674
|
+
}
|
|
27675
|
+
};
|
|
27676
|
+
|
|
27677
|
+
// src/authorization/workspace-directory.ts
|
|
27678
|
+
import { readdir, realpath as realpath7, stat as stat6 } from "node:fs/promises";
|
|
27679
|
+
import { homedir as homedir2 } from "node:os";
|
|
27680
|
+
import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute8, join as join14, normalize as normalize3, relative as relative5 } from "node:path";
|
|
27681
|
+
var WorkspaceDirectoryListing = class {
|
|
27682
|
+
directoryId;
|
|
27683
|
+
directoryLabel;
|
|
27684
|
+
entries;
|
|
27685
|
+
parentDirectoryId;
|
|
27686
|
+
constructor(directoryId2, directoryLabel, entries, parentDirectoryId) {
|
|
27687
|
+
this.directoryId = directoryId2;
|
|
27688
|
+
this.directoryLabel = directoryLabel;
|
|
27689
|
+
this.entries = entries;
|
|
27690
|
+
this.parentDirectoryId = parentDirectoryId;
|
|
27691
|
+
}
|
|
27692
|
+
};
|
|
27693
|
+
function encodePath(path2) {
|
|
27694
|
+
const encoded = Buffer.from(path2, "utf8").toString("base64url");
|
|
27695
|
+
if (encoded.length === 0 || encoded.length > 2e3) {
|
|
27696
|
+
throw new LocalAuthorizationError("The local directory path is too long to select");
|
|
27697
|
+
}
|
|
27698
|
+
return `path-${encoded}`;
|
|
27699
|
+
}
|
|
27700
|
+
function decodePath(value, prefix) {
|
|
27701
|
+
const encoded = value.slice(prefix.length);
|
|
27702
|
+
if (encoded.length === 0 || encoded.length > 2e3 || !/^[a-zA-Z0-9_-]+$/.test(encoded)) {
|
|
27703
|
+
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
27704
|
+
}
|
|
27705
|
+
const decoded = Buffer.from(encoded, "base64url").toString("utf8");
|
|
27706
|
+
if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize3(decoded) !== decoded) {
|
|
27707
|
+
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
27708
|
+
}
|
|
27709
|
+
return decoded;
|
|
27710
|
+
}
|
|
27711
|
+
var WorkspaceDirectoryService = class {
|
|
27712
|
+
#bindingId;
|
|
27713
|
+
#defaultWorkspace;
|
|
27714
|
+
constructor(bindingId, defaultWorkspace) {
|
|
27715
|
+
this.#bindingId = bindingId;
|
|
27716
|
+
this.#defaultWorkspace = defaultWorkspace;
|
|
27717
|
+
}
|
|
27718
|
+
authorizeMachine = (bindingId) => {
|
|
27719
|
+
if (bindingId !== this.#bindingId) {
|
|
27720
|
+
throw new LocalAuthorizationError("The runtime binding is not authorized");
|
|
27721
|
+
}
|
|
27722
|
+
};
|
|
27723
|
+
requestedPath = (id) => {
|
|
27724
|
+
if (id === "default") {
|
|
27725
|
+
return this.#defaultWorkspace;
|
|
27726
|
+
}
|
|
27727
|
+
if (id === "home") {
|
|
27728
|
+
return homedir2();
|
|
27729
|
+
}
|
|
27730
|
+
if (id.startsWith("path-")) {
|
|
27731
|
+
const path2 = decodePath(id, "path-");
|
|
27732
|
+
if (isAbsolute8(path2)) {
|
|
27733
|
+
return path2;
|
|
27734
|
+
}
|
|
27735
|
+
}
|
|
27736
|
+
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
27737
|
+
};
|
|
27738
|
+
resolvePath = async (requested, signal) => {
|
|
27739
|
+
signal.throwIfAborted();
|
|
27740
|
+
if (!isAbsolute8(requested) || requested.includes("\0") || normalize3(requested) !== requested) {
|
|
27741
|
+
throw new LocalAuthorizationError("The local directory path is invalid");
|
|
27742
|
+
}
|
|
27743
|
+
try {
|
|
27744
|
+
const target = await realpath7(requested);
|
|
27745
|
+
signal.throwIfAborted();
|
|
27746
|
+
const metadata = await stat6(target);
|
|
27747
|
+
signal.throwIfAborted();
|
|
27748
|
+
if (!isAbsolute8(target) || normalize3(target) !== target || !metadata.isDirectory()) {
|
|
27749
|
+
throw new LocalAuthorizationError("The selected location is not a directory");
|
|
27750
|
+
}
|
|
27751
|
+
return target;
|
|
27752
|
+
} catch (cause) {
|
|
27753
|
+
signal.throwIfAborted();
|
|
27754
|
+
if (cause instanceof LocalAuthorizationError) {
|
|
27755
|
+
throw cause;
|
|
27756
|
+
}
|
|
27757
|
+
throw new LocalAuthorizationError("This directory is missing or unavailable to your user account", {
|
|
27758
|
+
cause
|
|
27759
|
+
});
|
|
27760
|
+
}
|
|
27761
|
+
};
|
|
27762
|
+
label = (path2) => {
|
|
27763
|
+
const suffix = relative5(homedir2(), path2);
|
|
27764
|
+
return suffix === "" ? "~" : !isAbsolute8(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
|
|
27765
|
+
};
|
|
27766
|
+
identify = async (bindingId, requestedPath, signal) => {
|
|
27767
|
+
this.authorizeMachine(bindingId);
|
|
27768
|
+
const path2 = await this.resolvePath(requestedPath, signal);
|
|
27769
|
+
return {
|
|
27770
|
+
path: path2,
|
|
27771
|
+
directoryId: encodePath(path2),
|
|
27772
|
+
name: basename2(path2) || path2,
|
|
27773
|
+
label: this.label(path2)
|
|
27774
|
+
};
|
|
27775
|
+
};
|
|
27052
27776
|
resolve = async (bindingId, id, signal) => {
|
|
27053
27777
|
this.authorizeMachine(bindingId);
|
|
27054
27778
|
return await this.resolvePath(this.requestedPath(id), signal);
|
|
@@ -27102,8 +27826,8 @@ var WorkspaceDirectoryService = class {
|
|
|
27102
27826
|
};
|
|
27103
27827
|
|
|
27104
27828
|
// src/bots/local-bot-grant-store.ts
|
|
27105
|
-
import { createHash as
|
|
27106
|
-
import { stat as
|
|
27829
|
+
import { createHash as createHash3, randomUUID } from "node:crypto";
|
|
27830
|
+
import { stat as stat7 } from "node:fs/promises";
|
|
27107
27831
|
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
27108
27832
|
var LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS = 90 * 24 * 60 * 60 * 1e3;
|
|
27109
27833
|
var LocalBotAuthorizationError = class extends Error {
|
|
@@ -27147,7 +27871,7 @@ var LocalBotGrant = class {
|
|
|
27147
27871
|
}
|
|
27148
27872
|
};
|
|
27149
27873
|
function digest(value) {
|
|
27150
|
-
return
|
|
27874
|
+
return createHash3("sha256").update(value, "utf8").digest("hex");
|
|
27151
27875
|
}
|
|
27152
27876
|
function agentDigest(agent) {
|
|
27153
27877
|
return digest(
|
|
@@ -27161,7 +27885,7 @@ function agentDigest(agent) {
|
|
|
27161
27885
|
);
|
|
27162
27886
|
}
|
|
27163
27887
|
async function workspaceDigest(path2) {
|
|
27164
|
-
const metadata = await
|
|
27888
|
+
const metadata = await stat7(path2);
|
|
27165
27889
|
if (!metadata.isDirectory()) {
|
|
27166
27890
|
throw new LocalBotAuthorizationError("binding_incompatible", "The Bot workspace is not a directory");
|
|
27167
27891
|
}
|
|
@@ -27578,12 +28302,12 @@ var BotExecutionContextRegistry = class {
|
|
|
27578
28302
|
// src/bots/bot-outbound-ipc.ts
|
|
27579
28303
|
import { chmod as chmod2, mkdir as mkdir3, unlink } from "node:fs/promises";
|
|
27580
28304
|
import { createServer } from "node:net";
|
|
27581
|
-
import { dirname as dirname6, isAbsolute as
|
|
27582
|
-
import { fetch as
|
|
28305
|
+
import { dirname as dirname6, isAbsolute as isAbsolute9 } from "node:path";
|
|
28306
|
+
import { fetch as fetch4 } from "undici";
|
|
27583
28307
|
var BOT_IPC_REQUEST_LIMIT = 32 * 1024;
|
|
27584
28308
|
var BOT_IPC_TIMEOUT_MILLISECONDS = 2e4;
|
|
27585
28309
|
var BOT_RELAY_TIMEOUT_MILLISECONDS = 2e4;
|
|
27586
|
-
var
|
|
28310
|
+
var IDENTIFIER_PATTERN6 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
27587
28311
|
var WINDOWS_NAMED_PIPE_PREFIX = "\\\\.\\pipe\\";
|
|
27588
28312
|
var BotOutboundIpcRequest = class {
|
|
27589
28313
|
contextHandle;
|
|
@@ -27597,7 +28321,7 @@ var BotOutboundIpcRequest = class {
|
|
|
27597
28321
|
this.text = text;
|
|
27598
28322
|
}
|
|
27599
28323
|
};
|
|
27600
|
-
function
|
|
28324
|
+
function isRecord10(value) {
|
|
27601
28325
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27602
28326
|
}
|
|
27603
28327
|
function decodeRequest(encoded) {
|
|
@@ -27607,7 +28331,7 @@ function decodeRequest(encoded) {
|
|
|
27607
28331
|
} catch (cause) {
|
|
27608
28332
|
throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid", { cause });
|
|
27609
28333
|
}
|
|
27610
|
-
if (!
|
|
28334
|
+
if (!isRecord10(value)) {
|
|
27611
28335
|
throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
|
|
27612
28336
|
}
|
|
27613
28337
|
const keys = Object.keys(value);
|
|
@@ -27618,7 +28342,7 @@ function decodeRequest(encoded) {
|
|
|
27618
28342
|
const idempotencyKey = value["idempotencyKey"];
|
|
27619
28343
|
const target = value["target"];
|
|
27620
28344
|
const text = value["text"];
|
|
27621
|
-
if (typeof contextHandle !== "string" || !/^ctx_[a-zA-Z0-9_-]{43}$/.test(contextHandle) || typeof idempotencyKey !== "string" || !
|
|
28345
|
+
if (typeof contextHandle !== "string" || !/^ctx_[a-zA-Z0-9_-]{43}$/.test(contextHandle) || typeof idempotencyKey !== "string" || !IDENTIFIER_PATTERN6.test(idempotencyKey) || typeof target !== "string" || !IDENTIFIER_PATTERN6.test(target) || typeof text !== "string" || text.trim().length === 0 || text.length > 1e4) {
|
|
27622
28346
|
throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
|
|
27623
28347
|
}
|
|
27624
28348
|
return new BotOutboundIpcRequest(contextHandle, idempotencyKey, target, text);
|
|
@@ -27640,7 +28364,7 @@ function relayEndpoint(relayUrl, context, target) {
|
|
|
27640
28364
|
endpoint.pathname = `${MOBIUS_API_PREFIX}/v1/bot-executions/${execution}/delivery-targets/${encodeURIComponent(deliveryTargetId)}/messages`;
|
|
27641
28365
|
return endpoint;
|
|
27642
28366
|
}
|
|
27643
|
-
function
|
|
28367
|
+
function daemonToken2(relayUrl) {
|
|
27644
28368
|
const token = relayUrl.searchParams.get("token") ?? "";
|
|
27645
28369
|
if (!/^[a-zA-Z0-9_-]{32,256}$/.test(token)) {
|
|
27646
28370
|
throw new LocalBotAuthorizationError("bot_service_unavailable", "The Runtime credential is unavailable");
|
|
@@ -27657,10 +28381,10 @@ async function decodeRelayResponse(response) {
|
|
|
27657
28381
|
cause
|
|
27658
28382
|
});
|
|
27659
28383
|
}
|
|
27660
|
-
if (response.status === 202 &&
|
|
28384
|
+
if (response.status === 202 && isRecord10(value) && typeof value["outboundMessageId"] === "string") {
|
|
27661
28385
|
return value["outboundMessageId"];
|
|
27662
28386
|
}
|
|
27663
|
-
if (
|
|
28387
|
+
if (isRecord10(value) && isRecord10(value["error"])) {
|
|
27664
28388
|
const error61 = value["error"];
|
|
27665
28389
|
if (typeof error61["code"] === "string" && typeof error61["message"] === "string") {
|
|
27666
28390
|
throw new LocalBotAuthorizationError(error61["code"], error61["message"]);
|
|
@@ -27676,7 +28400,7 @@ var BotOutboundIpcServer = class {
|
|
|
27676
28400
|
#usesFilesystemSocket;
|
|
27677
28401
|
constructor(socketPath, relayUrl, registry2) {
|
|
27678
28402
|
const usesFilesystemSocket = !socketPath.startsWith(WINDOWS_NAMED_PIPE_PREFIX);
|
|
27679
|
-
if (usesFilesystemSocket && !
|
|
28403
|
+
if (usesFilesystemSocket && !isAbsolute9(socketPath)) {
|
|
27680
28404
|
throw new Error("The Bot IPC path must be absolute");
|
|
27681
28405
|
}
|
|
27682
28406
|
this.#registry = registry2;
|
|
@@ -27693,7 +28417,7 @@ var BotOutboundIpcServer = class {
|
|
|
27693
28417
|
if (this.#usesFilesystemSocket) {
|
|
27694
28418
|
await mkdir3(dirname6(this.#socketPath), { mode: 448, recursive: true });
|
|
27695
28419
|
await unlink(this.#socketPath).catch((error61) => {
|
|
27696
|
-
if (!
|
|
28420
|
+
if (!isRecord10(error61) || error61["code"] !== "ENOENT") {
|
|
27697
28421
|
throw error61;
|
|
27698
28422
|
}
|
|
27699
28423
|
});
|
|
@@ -27728,7 +28452,7 @@ var BotOutboundIpcServer = class {
|
|
|
27728
28452
|
}
|
|
27729
28453
|
if (this.#usesFilesystemSocket) {
|
|
27730
28454
|
await unlink(this.#socketPath).catch((error61) => {
|
|
27731
|
-
if (!
|
|
28455
|
+
if (!isRecord10(error61) || error61["code"] !== "ENOENT") {
|
|
27732
28456
|
throw error61;
|
|
27733
28457
|
}
|
|
27734
28458
|
});
|
|
@@ -27792,10 +28516,10 @@ var BotOutboundIpcServer = class {
|
|
|
27792
28516
|
const requestSignal = AbortSignal.any([signal, timeout]);
|
|
27793
28517
|
let response;
|
|
27794
28518
|
try {
|
|
27795
|
-
response = await
|
|
28519
|
+
response = await fetch4(relayEndpoint(this.#relayUrl, context, request.target), {
|
|
27796
28520
|
body: JSON.stringify({ idempotencyKey: request.idempotencyKey, text: request.text }),
|
|
27797
28521
|
headers: {
|
|
27798
|
-
authorization: `Bearer ${
|
|
28522
|
+
authorization: `Bearer ${daemonToken2(this.#relayUrl)}`,
|
|
27799
28523
|
"content-type": "application/json",
|
|
27800
28524
|
"x-mobius-bot-execution-capability": context.command.executionCapabilitySecret
|
|
27801
28525
|
},
|
|
@@ -27816,7 +28540,7 @@ var BotOutboundIpcServer = class {
|
|
|
27816
28540
|
|
|
27817
28541
|
// src/native-sessions/service.ts
|
|
27818
28542
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
27819
|
-
import { basename as
|
|
28543
|
+
import { basename as basename3 } from "node:path";
|
|
27820
28544
|
|
|
27821
28545
|
// src/native-sessions/codex-history.ts
|
|
27822
28546
|
import { spawn as spawn4 } from "node:child_process";
|
|
@@ -27849,7 +28573,6 @@ function decodeHistory(thread, value) {
|
|
|
27849
28573
|
const page = turnsSchema.parse(value);
|
|
27850
28574
|
const messages = [];
|
|
27851
28575
|
let characters = 0;
|
|
27852
|
-
let imageCharacters = 0;
|
|
27853
28576
|
let truncated = page.nextCursor != null;
|
|
27854
28577
|
for (const turn of page.data.toReversed()) {
|
|
27855
28578
|
for (const item of turn.items) {
|
|
@@ -27857,22 +28580,19 @@ function decodeHistory(thread, value) {
|
|
|
27857
28580
|
let message;
|
|
27858
28581
|
if (type === "userMessage") {
|
|
27859
28582
|
const { content } = userMessageSchema.parse(item);
|
|
27860
|
-
const
|
|
27861
|
-
|
|
27862
|
-
|
|
27863
|
-
|
|
27864
|
-
|
|
27865
|
-
|
|
27866
|
-
|
|
27867
|
-
|
|
27868
|
-
|
|
27869
|
-
|
|
27870
|
-
}).join("")
|
|
27871
|
-
);
|
|
28583
|
+
const text2 = content.map((block) => {
|
|
28584
|
+
const { type: type2 } = itemTypeSchema.parse(block);
|
|
28585
|
+
if (type2 === "text") {
|
|
28586
|
+
return textSchema.parse(block).text;
|
|
28587
|
+
}
|
|
28588
|
+
if (type2 === "image") {
|
|
28589
|
+
return `[@image](${imageSchema.parse(block).url})`;
|
|
28590
|
+
}
|
|
28591
|
+
return "[Attachment]";
|
|
28592
|
+
}).join("");
|
|
27872
28593
|
message = {
|
|
27873
28594
|
role: "user",
|
|
27874
|
-
text:
|
|
27875
|
-
...parsed.images.length > 0 ? { images: parsed.images } : {}
|
|
28595
|
+
text: text2
|
|
27876
28596
|
};
|
|
27877
28597
|
} else if (type === "agentMessage") {
|
|
27878
28598
|
const agent = agentMessageSchema.parse(item);
|
|
@@ -27890,12 +28610,10 @@ function decodeHistory(thread, value) {
|
|
|
27890
28610
|
truncated ||= text.length < message.text.length;
|
|
27891
28611
|
messages.push({ ...message, text });
|
|
27892
28612
|
characters += text.length;
|
|
27893
|
-
|
|
27894
|
-
while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT || imageCharacters > SESSION_HISTORY_IMAGE_CHARACTER_LIMIT) {
|
|
28613
|
+
while (messages.length > SESSION_HISTORY_PREVIEW_MESSAGE_LIMIT || characters > SESSION_HISTORY_CHARACTER_LIMIT) {
|
|
27895
28614
|
const removed = messages.shift();
|
|
27896
28615
|
if (removed !== void 0) {
|
|
27897
28616
|
characters -= removed.text.length;
|
|
27898
|
-
imageCharacters -= (removed.images ?? []).reduce((size, image) => size + image.data.length, 0);
|
|
27899
28617
|
}
|
|
27900
28618
|
truncated = true;
|
|
27901
28619
|
}
|
|
@@ -28053,7 +28771,11 @@ async function readCodexHistory(agent, cwd, nativeSessionId, signal) {
|
|
|
28053
28771
|
params: { clientInfo: { name: "mobius_history", version: "1.0.0" } }
|
|
28054
28772
|
});
|
|
28055
28773
|
}
|
|
28056
|
-
|
|
28774
|
+
const snapshot = await response.promise;
|
|
28775
|
+
return {
|
|
28776
|
+
...snapshot,
|
|
28777
|
+
history: await embedLocalHistoryImages(snapshot.history, [cwd, snapshot.cwd], signal)
|
|
28778
|
+
};
|
|
28057
28779
|
} finally {
|
|
28058
28780
|
clearTimeout(timeout);
|
|
28059
28781
|
signal.removeEventListener("abort", abort);
|
|
@@ -28307,7 +29029,7 @@ var NativeSessionService = class {
|
|
|
28307
29029
|
}
|
|
28308
29030
|
resolvedPaths.add(path2);
|
|
28309
29031
|
additionalDirectories.push(path2);
|
|
28310
|
-
additionalEntries.push({ directoryId: directoryId2, name:
|
|
29032
|
+
additionalEntries.push({ directoryId: directoryId2, name: basename3(path2) });
|
|
28311
29033
|
}
|
|
28312
29034
|
const listing = await this.#directories.list(this.#config.bindingId, command.directoryId, signal);
|
|
28313
29035
|
const opened = await this.#sessions.forkSessionAtTurn(
|
|
@@ -28446,13 +29168,13 @@ var NativeSessionService = class {
|
|
|
28446
29168
|
};
|
|
28447
29169
|
|
|
28448
29170
|
// src/prompt-artifact-resolver.ts
|
|
28449
|
-
import { createHash as
|
|
28450
|
-
import { fetch as
|
|
29171
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
29172
|
+
import { fetch as fetch5 } from "undici";
|
|
28451
29173
|
var ARTIFACT_SCHEME = "mobius-artifact:";
|
|
28452
29174
|
var ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS = 2e4;
|
|
28453
29175
|
var MAX_AGENT_IMAGE_BASE64_LENGTH = 4e6;
|
|
28454
29176
|
var MAX_AGENT_RESOURCE_BYTE_LENGTH = 1e6;
|
|
28455
|
-
var
|
|
29177
|
+
var IDENTIFIER_PATTERN7 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
28456
29178
|
var PromptArtifactError = class extends Error {
|
|
28457
29179
|
code;
|
|
28458
29180
|
constructor(code, message, options = {}) {
|
|
@@ -28495,14 +29217,13 @@ function parseReference(resource) {
|
|
|
28495
29217
|
const encodedByteLength2 = url2.searchParams.get("byteLength") ?? "";
|
|
28496
29218
|
const sha256 = url2.searchParams.get("sha256") ?? "";
|
|
28497
29219
|
const byteLength = Number(encodedByteLength2);
|
|
28498
|
-
if (url2.protocol !== ARTIFACT_SCHEME || url2.hash.length > 0 || resource.type !== "link" || resource.text.length > 0 || !
|
|
29220
|
+
if (url2.protocol !== ARTIFACT_SCHEME || url2.hash.length > 0 || resource.type !== "link" || resource.text.length > 0 || !IDENTIFIER_PATTERN7.test(artifactId) || keys.length !== 2 || keys[0] !== "byteLength" || keys[1] !== "sha256" || !/^[1-9][0-9]*$/.test(encodedByteLength2) || !Number.isSafeInteger(byteLength) || !/^[a-f0-9]{64}$/.test(sha256)) {
|
|
28499
29221
|
throw new PromptArtifactError("artifact_reference_invalid", "The prompt artifact reference is invalid");
|
|
28500
29222
|
}
|
|
28501
29223
|
return new PromptArtifactReference(artifactId, byteLength, sha256, resource);
|
|
28502
29224
|
}
|
|
28503
29225
|
function downloadUrl(config2, command, reference) {
|
|
28504
|
-
const url2 =
|
|
28505
|
-
url2.protocol = url2.protocol === "wss:" ? "https:" : "http:";
|
|
29226
|
+
const url2 = relayHttpEndpoint(config2.relayUrl);
|
|
28506
29227
|
let channelPath = "";
|
|
28507
29228
|
if (url2.pathname.endsWith("/daemon")) {
|
|
28508
29229
|
channelPath = url2.pathname.slice(0, -"/daemon".length);
|
|
@@ -28514,7 +29235,6 @@ function downloadUrl(config2, command, reference) {
|
|
|
28514
29235
|
channelPath = `${url2.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
|
|
28515
29236
|
}
|
|
28516
29237
|
url2.pathname = `${channelPath}/sessions/${encodeURIComponent(command.sessionId)}/commands/${encodeURIComponent(command.commandId)}/artifacts/${encodeURIComponent(reference.artifactId)}/content`;
|
|
28517
|
-
url2.searchParams.delete("liveness");
|
|
28518
29238
|
return url2;
|
|
28519
29239
|
}
|
|
28520
29240
|
async function responseBytes(response, expectedByteLength, signal) {
|
|
@@ -28563,9 +29283,13 @@ async function download(config2, command, reference, signal) {
|
|
|
28563
29283
|
const requestSignal = AbortSignal.any([signal, timeoutSignal]);
|
|
28564
29284
|
let response;
|
|
28565
29285
|
try {
|
|
28566
|
-
response = await
|
|
29286
|
+
response = await fetch5(downloadUrl(config2, command, reference), {
|
|
28567
29287
|
dispatcher: environmentProxyDispatcher,
|
|
28568
|
-
headers: {
|
|
29288
|
+
headers: {
|
|
29289
|
+
accept: reference.resource.mimeType,
|
|
29290
|
+
"accept-encoding": "identity",
|
|
29291
|
+
...runtimeAuthorization(config2.relayUrl)
|
|
29292
|
+
},
|
|
28569
29293
|
signal: requestSignal
|
|
28570
29294
|
});
|
|
28571
29295
|
if (!response.ok) {
|
|
@@ -28583,7 +29307,7 @@ async function download(config2, command, reference, signal) {
|
|
|
28583
29307
|
);
|
|
28584
29308
|
}
|
|
28585
29309
|
const bytes = await responseBytes(response, reference.byteLength, requestSignal);
|
|
28586
|
-
if (
|
|
29310
|
+
if (createHash4("sha256").update(bytes).digest("hex") !== reference.sha256) {
|
|
28587
29311
|
throw new PromptArtifactError(
|
|
28588
29312
|
"artifact_integrity_failed",
|
|
28589
29313
|
"The prompt artifact failed integrity validation"
|
|
@@ -28675,12 +29399,8 @@ function connectRelay(url2, signal) {
|
|
|
28675
29399
|
signal.throwIfAborted();
|
|
28676
29400
|
return new Promise((resolve6, reject) => {
|
|
28677
29401
|
const endpoint = new URL(url2);
|
|
28678
|
-
const headers =
|
|
28679
|
-
|
|
28680
|
-
const runtimeCredential = endpoint.searchParams.get("token") ?? "";
|
|
28681
|
-
endpoint.searchParams.delete("token");
|
|
28682
|
-
headers["authorization"] = `Bearer ${runtimeCredential}`;
|
|
28683
|
-
}
|
|
29402
|
+
const headers = runtimeAuthorization(endpoint);
|
|
29403
|
+
endpoint.searchParams.delete("token");
|
|
28684
29404
|
const socket = new WebSocket(endpoint, {
|
|
28685
29405
|
dispatcher: environmentProxyDispatcher,
|
|
28686
29406
|
headers
|
|
@@ -29003,6 +29723,42 @@ var RelayConnectionLiveness = class {
|
|
|
29003
29723
|
import { mkdirSync as mkdirSync3 } from "node:fs";
|
|
29004
29724
|
import { dirname as dirname7 } from "node:path";
|
|
29005
29725
|
import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
|
|
29726
|
+
var DEFAULT_OUTBOX_LIMITS = {
|
|
29727
|
+
criticalEventBytes: 136 * 1024 * 1024,
|
|
29728
|
+
criticalEventCount: 10128,
|
|
29729
|
+
runtimeDeliveryBytes: 64 * 1024 * 1024,
|
|
29730
|
+
runtimeDeliveryCount: 64,
|
|
29731
|
+
standardEventBytes: 128 * 1024 * 1024,
|
|
29732
|
+
standardEventCount: 1e4
|
|
29733
|
+
};
|
|
29734
|
+
var SessionEventOutboxCapacityError = class extends Error {
|
|
29735
|
+
code = "session_event_outbox_full";
|
|
29736
|
+
constructor() {
|
|
29737
|
+
super("The durable Session event outbox is full");
|
|
29738
|
+
this.name = "SessionEventOutboxCapacityError";
|
|
29739
|
+
}
|
|
29740
|
+
};
|
|
29741
|
+
var RuntimeDeliveryInboxCapacityError = class extends Error {
|
|
29742
|
+
code = "runtime_delivery_inbox_full";
|
|
29743
|
+
constructor() {
|
|
29744
|
+
super("The durable Runtime delivery inbox is full");
|
|
29745
|
+
this.name = "RuntimeDeliveryInboxCapacityError";
|
|
29746
|
+
}
|
|
29747
|
+
};
|
|
29748
|
+
var StoredRuntimeDelivery = class {
|
|
29749
|
+
deliveryId;
|
|
29750
|
+
duplicate;
|
|
29751
|
+
payload;
|
|
29752
|
+
sessionId;
|
|
29753
|
+
state;
|
|
29754
|
+
constructor(deliveryId, sessionId, payload, state, duplicate) {
|
|
29755
|
+
this.deliveryId = deliveryId;
|
|
29756
|
+
this.duplicate = duplicate;
|
|
29757
|
+
this.payload = payload;
|
|
29758
|
+
this.sessionId = sessionId;
|
|
29759
|
+
this.state = state;
|
|
29760
|
+
}
|
|
29761
|
+
};
|
|
29006
29762
|
function readPendingEnvelope(row) {
|
|
29007
29763
|
if (typeof row !== "object" || row === null || Array.isArray(row)) {
|
|
29008
29764
|
throw new Error("SQLite returned an invalid session event outbox row");
|
|
@@ -29013,9 +29769,26 @@ function readPendingEnvelope(row) {
|
|
|
29013
29769
|
}
|
|
29014
29770
|
return envelope2;
|
|
29015
29771
|
}
|
|
29772
|
+
function rowNumber(row, field) {
|
|
29773
|
+
const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
|
|
29774
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
|
|
29775
|
+
throw new Error(`SQLite returned an invalid ${field} value`);
|
|
29776
|
+
}
|
|
29777
|
+
return value;
|
|
29778
|
+
}
|
|
29779
|
+
function rowString2(row, field) {
|
|
29780
|
+
const value = typeof row === "object" && row !== null ? Reflect.get(row, field) : void 0;
|
|
29781
|
+
if (typeof value !== "string" || value.length === 0) {
|
|
29782
|
+
throw new Error(`SQLite returned an invalid ${field} value`);
|
|
29783
|
+
}
|
|
29784
|
+
return value;
|
|
29785
|
+
}
|
|
29016
29786
|
var SessionEventOutbox = class {
|
|
29017
29787
|
#database;
|
|
29018
|
-
|
|
29788
|
+
#limits;
|
|
29789
|
+
constructor(path2, limits = DEFAULT_OUTBOX_LIMITS) {
|
|
29790
|
+
validateLimits(limits);
|
|
29791
|
+
this.#limits = limits;
|
|
29019
29792
|
mkdirSync3(dirname7(path2), { recursive: true });
|
|
29020
29793
|
this.#database = new DatabaseSync4(path2);
|
|
29021
29794
|
this.#database.exec(`
|
|
@@ -29024,6 +29797,7 @@ var SessionEventOutbox = class {
|
|
|
29024
29797
|
event_id TEXT NOT NULL UNIQUE,
|
|
29025
29798
|
session_id TEXT NOT NULL,
|
|
29026
29799
|
source_key TEXT NOT NULL,
|
|
29800
|
+
byte_length INTEGER NOT NULL,
|
|
29027
29801
|
envelope_json TEXT NOT NULL
|
|
29028
29802
|
) STRICT;
|
|
29029
29803
|
CREATE INDEX IF NOT EXISTS relay_session_event_outbox_order
|
|
@@ -29034,7 +29808,7 @@ var SessionEventOutbox = class {
|
|
|
29034
29808
|
session_id TEXT NOT NULL,
|
|
29035
29809
|
envelope_json TEXT NOT NULL,
|
|
29036
29810
|
rejection_code TEXT NOT NULL CHECK (
|
|
29037
|
-
rejection_code IN ('session_deleted', 'session_not_found')
|
|
29811
|
+
rejection_code IN ('session_deleted', 'session_not_found', 'session_rejected')
|
|
29038
29812
|
)
|
|
29039
29813
|
) STRICT;
|
|
29040
29814
|
CREATE TABLE IF NOT EXISTS relay_session_event_sources (
|
|
@@ -29050,7 +29824,53 @@ var SessionEventOutbox = class {
|
|
|
29050
29824
|
state IN ('dispatching', 'running', 'succeeded', 'failed', 'cancelled')
|
|
29051
29825
|
)
|
|
29052
29826
|
) STRICT;
|
|
29827
|
+
CREATE TABLE IF NOT EXISTS relay_session_event_outbox_state (
|
|
29828
|
+
singleton INTEGER PRIMARY KEY CHECK (singleton = 1),
|
|
29829
|
+
event_count INTEGER NOT NULL,
|
|
29830
|
+
total_bytes INTEGER NOT NULL
|
|
29831
|
+
) STRICT;
|
|
29832
|
+
INSERT OR IGNORE INTO relay_session_event_outbox_state (
|
|
29833
|
+
singleton, event_count, total_bytes
|
|
29834
|
+
) VALUES (1, 0, 0);
|
|
29835
|
+
CREATE TABLE IF NOT EXISTS relay_runtime_deliveries (
|
|
29836
|
+
delivery_id TEXT PRIMARY KEY,
|
|
29837
|
+
session_id TEXT NOT NULL,
|
|
29838
|
+
payload_json TEXT NOT NULL,
|
|
29839
|
+
payload_bytes INTEGER NOT NULL,
|
|
29840
|
+
state TEXT NOT NULL CHECK (
|
|
29841
|
+
state IN ('received', 'relay_committed', 'processed')
|
|
29842
|
+
),
|
|
29843
|
+
received_at INTEGER NOT NULL
|
|
29844
|
+
) STRICT;
|
|
29053
29845
|
`);
|
|
29846
|
+
const deadLetterTable = this.#database.prepare(
|
|
29847
|
+
`SELECT sql FROM sqlite_master
|
|
29848
|
+
WHERE type = 'table' AND name = 'relay_session_event_dead_letters'`
|
|
29849
|
+
).get();
|
|
29850
|
+
const deadLetterSql = typeof deadLetterTable === "object" && deadLetterTable !== null ? Reflect.get(deadLetterTable, "sql") : void 0;
|
|
29851
|
+
if (typeof deadLetterSql !== "string" || !deadLetterSql.includes("'session_rejected'")) {
|
|
29852
|
+
this.#database.exec(`
|
|
29853
|
+
BEGIN IMMEDIATE;
|
|
29854
|
+
ALTER TABLE relay_session_event_dead_letters
|
|
29855
|
+
RENAME TO relay_session_event_dead_letters_legacy;
|
|
29856
|
+
CREATE TABLE relay_session_event_dead_letters (
|
|
29857
|
+
ordinal INTEGER PRIMARY KEY,
|
|
29858
|
+
event_id TEXT NOT NULL UNIQUE,
|
|
29859
|
+
session_id TEXT NOT NULL,
|
|
29860
|
+
envelope_json TEXT NOT NULL,
|
|
29861
|
+
rejection_code TEXT NOT NULL CHECK (
|
|
29862
|
+
rejection_code IN ('session_deleted', 'session_not_found', 'session_rejected')
|
|
29863
|
+
)
|
|
29864
|
+
) STRICT;
|
|
29865
|
+
INSERT INTO relay_session_event_dead_letters (
|
|
29866
|
+
ordinal, event_id, session_id, envelope_json, rejection_code
|
|
29867
|
+
)
|
|
29868
|
+
SELECT ordinal, event_id, session_id, envelope_json, rejection_code
|
|
29869
|
+
FROM relay_session_event_dead_letters_legacy;
|
|
29870
|
+
DROP TABLE relay_session_event_dead_letters_legacy;
|
|
29871
|
+
COMMIT;
|
|
29872
|
+
`);
|
|
29873
|
+
}
|
|
29054
29874
|
const outboxColumns = this.#database.prepare("PRAGMA table_info(relay_session_event_outbox)").all();
|
|
29055
29875
|
const hasSourceKey = outboxColumns.some(
|
|
29056
29876
|
(column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "source_key"
|
|
@@ -29061,6 +29881,15 @@ var SessionEventOutbox = class {
|
|
|
29061
29881
|
ADD COLUMN source_key TEXT NOT NULL DEFAULT '';
|
|
29062
29882
|
`);
|
|
29063
29883
|
}
|
|
29884
|
+
const hasByteLength = outboxColumns.some(
|
|
29885
|
+
(column) => typeof column === "object" && column !== null && Reflect.get(column, "name") === "byte_length"
|
|
29886
|
+
);
|
|
29887
|
+
if (!hasByteLength) {
|
|
29888
|
+
this.#database.exec(`
|
|
29889
|
+
ALTER TABLE relay_session_event_outbox
|
|
29890
|
+
ADD COLUMN byte_length INTEGER NOT NULL DEFAULT 0;
|
|
29891
|
+
`);
|
|
29892
|
+
}
|
|
29064
29893
|
this.#database.exec(`
|
|
29065
29894
|
UPDATE relay_session_event_outbox
|
|
29066
29895
|
SET source_key = CASE json_extract(envelope_json, '$.source.kind')
|
|
@@ -29069,6 +29898,16 @@ var SessionEventOutbox = class {
|
|
|
29069
29898
|
ELSE 'runtime:' || session_id
|
|
29070
29899
|
END
|
|
29071
29900
|
WHERE source_key = '';
|
|
29901
|
+
UPDATE relay_session_event_outbox
|
|
29902
|
+
SET byte_length = length(CAST(envelope_json AS BLOB))
|
|
29903
|
+
WHERE byte_length = 0;
|
|
29904
|
+
UPDATE relay_session_event_outbox_state
|
|
29905
|
+
SET event_count = (SELECT COUNT(*) FROM relay_session_event_outbox),
|
|
29906
|
+
total_bytes = (
|
|
29907
|
+
SELECT COALESCE(SUM(byte_length), 0)
|
|
29908
|
+
FROM relay_session_event_outbox
|
|
29909
|
+
)
|
|
29910
|
+
WHERE singleton = 1;
|
|
29072
29911
|
CREATE INDEX IF NOT EXISTS relay_session_event_outbox_source_order
|
|
29073
29912
|
ON relay_session_event_outbox(source_key, ordinal);
|
|
29074
29913
|
`);
|
|
@@ -29129,13 +29968,19 @@ var SessionEventOutbox = class {
|
|
|
29129
29968
|
const state = typeof row === "object" && row !== null ? Reflect.get(row, "state") : void 0;
|
|
29130
29969
|
return state === "succeeded" || state === "failed" || state === "cancelled";
|
|
29131
29970
|
};
|
|
29132
|
-
acknowledge = (acknowledgement) => this.#
|
|
29133
|
-
`DELETE FROM relay_session_event_outbox
|
|
29134
|
-
WHERE event_id = ? AND session_id = ?`
|
|
29135
|
-
).run(acknowledgement.eventId, acknowledgement.sessionId).changes === 1;
|
|
29971
|
+
acknowledge = (acknowledgement) => this.#removeAcknowledgedEvent(acknowledgement.eventId, acknowledgement.sessionId);
|
|
29136
29972
|
quarantine = (rejection) => {
|
|
29137
29973
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
29138
29974
|
try {
|
|
29975
|
+
const stored = this.#database.prepare(
|
|
29976
|
+
`SELECT byte_length FROM relay_session_event_outbox
|
|
29977
|
+
WHERE event_id = ? AND session_id = ?`
|
|
29978
|
+
).get(rejection.eventId, rejection.sessionId);
|
|
29979
|
+
if (stored === void 0) {
|
|
29980
|
+
this.#database.exec("COMMIT");
|
|
29981
|
+
return false;
|
|
29982
|
+
}
|
|
29983
|
+
const byteLength = rowNumber(stored, "byte_length");
|
|
29139
29984
|
const insertion = this.#database.prepare(
|
|
29140
29985
|
`INSERT INTO relay_session_event_dead_letters (
|
|
29141
29986
|
ordinal, event_id, session_id, envelope_json, rejection_code
|
|
@@ -29155,6 +30000,7 @@ var SessionEventOutbox = class {
|
|
|
29155
30000
|
if (deletion.changes !== 1) {
|
|
29156
30001
|
throw new Error("The rejected session event could not be removed from the durable outbox");
|
|
29157
30002
|
}
|
|
30003
|
+
this.#decrementEventState(byteLength);
|
|
29158
30004
|
this.#database.exec("COMMIT");
|
|
29159
30005
|
return true;
|
|
29160
30006
|
} catch (error61) {
|
|
@@ -29166,7 +30012,129 @@ var SessionEventOutbox = class {
|
|
|
29166
30012
|
this.#database.close();
|
|
29167
30013
|
};
|
|
29168
30014
|
enqueue = (sessionId, payload, attemptId = null) => {
|
|
29169
|
-
|
|
30015
|
+
return this.#enqueueBounded(
|
|
30016
|
+
sessionId,
|
|
30017
|
+
payload,
|
|
30018
|
+
attemptId ?? "",
|
|
30019
|
+
this.#limits.standardEventCount,
|
|
30020
|
+
this.#limits.standardEventBytes
|
|
30021
|
+
);
|
|
30022
|
+
};
|
|
30023
|
+
enqueueCritical = (sessionId, payload, attemptId = "") => this.#enqueueBounded(
|
|
30024
|
+
sessionId,
|
|
30025
|
+
payload,
|
|
30026
|
+
attemptId,
|
|
30027
|
+
this.#limits.criticalEventCount,
|
|
30028
|
+
this.#limits.criticalEventBytes
|
|
30029
|
+
);
|
|
30030
|
+
claimRuntimeDelivery = (delivery) => {
|
|
30031
|
+
const payloadBytes = new TextEncoder().encode(delivery.payload).byteLength;
|
|
30032
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
30033
|
+
try {
|
|
30034
|
+
const existing = this.#database.prepare(
|
|
30035
|
+
`SELECT session_id, payload_json, state
|
|
30036
|
+
FROM relay_runtime_deliveries
|
|
30037
|
+
WHERE delivery_id = ?`
|
|
30038
|
+
).get(delivery.deliveryId);
|
|
30039
|
+
if (existing !== void 0) {
|
|
30040
|
+
const sessionId = rowString2(existing, "session_id");
|
|
30041
|
+
const payload = rowString2(existing, "payload_json");
|
|
30042
|
+
const state = runtimeDeliveryState(existing);
|
|
30043
|
+
if (sessionId !== delivery.sessionId || payload !== delivery.payload) {
|
|
30044
|
+
throw new Error("The Runtime delivery identity conflicts with its durable receipt");
|
|
30045
|
+
}
|
|
30046
|
+
this.#database.exec("COMMIT");
|
|
30047
|
+
return new StoredRuntimeDelivery(delivery.deliveryId, sessionId, payload, state, true);
|
|
30048
|
+
}
|
|
30049
|
+
const usage = this.#database.prepare(
|
|
30050
|
+
`SELECT COUNT(*) AS delivery_count,
|
|
30051
|
+
COALESCE(SUM(payload_bytes), 0) AS delivery_bytes
|
|
30052
|
+
FROM relay_runtime_deliveries`
|
|
30053
|
+
).get();
|
|
30054
|
+
if (rowNumber(usage, "delivery_count") + 1 > this.#limits.runtimeDeliveryCount || rowNumber(usage, "delivery_bytes") + payloadBytes > this.#limits.runtimeDeliveryBytes) {
|
|
30055
|
+
throw new RuntimeDeliveryInboxCapacityError();
|
|
30056
|
+
}
|
|
30057
|
+
this.#database.prepare(
|
|
30058
|
+
`INSERT INTO relay_runtime_deliveries (
|
|
30059
|
+
delivery_id, session_id, payload_json, payload_bytes, state, received_at
|
|
30060
|
+
) VALUES (?, ?, ?, ?, 'received', ?)`
|
|
30061
|
+
).run(delivery.deliveryId, delivery.sessionId, delivery.payload, payloadBytes, Date.now());
|
|
30062
|
+
this.#database.exec("COMMIT");
|
|
30063
|
+
return new StoredRuntimeDelivery(
|
|
30064
|
+
delivery.deliveryId,
|
|
30065
|
+
delivery.sessionId,
|
|
30066
|
+
delivery.payload,
|
|
30067
|
+
"received",
|
|
30068
|
+
false
|
|
30069
|
+
);
|
|
30070
|
+
} catch (error61) {
|
|
30071
|
+
this.#database.exec("ROLLBACK");
|
|
30072
|
+
throw error61;
|
|
30073
|
+
}
|
|
30074
|
+
};
|
|
30075
|
+
markRuntimeDeliveryCommitted = (deliveryId, sessionId) => {
|
|
30076
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
30077
|
+
try {
|
|
30078
|
+
const row = this.#database.prepare(
|
|
30079
|
+
`SELECT state FROM relay_runtime_deliveries
|
|
30080
|
+
WHERE delivery_id = ? AND session_id = ?`
|
|
30081
|
+
).get(deliveryId, sessionId);
|
|
30082
|
+
if (row === void 0) {
|
|
30083
|
+
this.#database.exec("COMMIT");
|
|
30084
|
+
return false;
|
|
30085
|
+
}
|
|
30086
|
+
const state = runtimeDeliveryState(row);
|
|
30087
|
+
if (state === "processed") {
|
|
30088
|
+
this.#database.prepare(`DELETE FROM relay_runtime_deliveries WHERE delivery_id = ?`).run(deliveryId);
|
|
30089
|
+
} else if (state === "received") {
|
|
30090
|
+
this.#database.prepare(`UPDATE relay_runtime_deliveries SET state = 'relay_committed' WHERE delivery_id = ?`).run(deliveryId);
|
|
30091
|
+
}
|
|
30092
|
+
this.#database.exec("COMMIT");
|
|
30093
|
+
return true;
|
|
30094
|
+
} catch (error61) {
|
|
30095
|
+
this.#database.exec("ROLLBACK");
|
|
30096
|
+
throw error61;
|
|
30097
|
+
}
|
|
30098
|
+
};
|
|
30099
|
+
markRuntimeDeliveryProcessed = (deliveryId, sessionId) => {
|
|
30100
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
30101
|
+
try {
|
|
30102
|
+
const row = this.#database.prepare(
|
|
30103
|
+
`SELECT state FROM relay_runtime_deliveries
|
|
30104
|
+
WHERE delivery_id = ? AND session_id = ?`
|
|
30105
|
+
).get(deliveryId, sessionId);
|
|
30106
|
+
if (row === void 0) {
|
|
30107
|
+
this.#database.exec("COMMIT");
|
|
30108
|
+
return false;
|
|
30109
|
+
}
|
|
30110
|
+
const state = runtimeDeliveryState(row);
|
|
30111
|
+
if (state === "relay_committed") {
|
|
30112
|
+
this.#database.prepare(`DELETE FROM relay_runtime_deliveries WHERE delivery_id = ?`).run(deliveryId);
|
|
30113
|
+
} else if (state === "received") {
|
|
30114
|
+
this.#database.prepare(`UPDATE relay_runtime_deliveries SET state = 'processed' WHERE delivery_id = ?`).run(deliveryId);
|
|
30115
|
+
}
|
|
30116
|
+
this.#database.exec("COMMIT");
|
|
30117
|
+
return true;
|
|
30118
|
+
} catch (error61) {
|
|
30119
|
+
this.#database.exec("ROLLBACK");
|
|
30120
|
+
throw error61;
|
|
30121
|
+
}
|
|
30122
|
+
};
|
|
30123
|
+
runtimeDeliveries = () => this.#database.prepare(
|
|
30124
|
+
`SELECT delivery_id, session_id, payload_json, state
|
|
30125
|
+
FROM relay_runtime_deliveries
|
|
30126
|
+
ORDER BY received_at, delivery_id`
|
|
30127
|
+
).all().map(
|
|
30128
|
+
(row) => new StoredRuntimeDelivery(
|
|
30129
|
+
rowString2(row, "delivery_id"),
|
|
30130
|
+
rowString2(row, "session_id"),
|
|
30131
|
+
rowString2(row, "payload_json"),
|
|
30132
|
+
runtimeDeliveryState(row),
|
|
30133
|
+
true
|
|
30134
|
+
)
|
|
30135
|
+
);
|
|
30136
|
+
#enqueueBounded = (sessionId, payload, attemptId, maximumEventCount, maximumEventBytes) => {
|
|
30137
|
+
const sourceKey = attemptId.length === 0 ? `runtime:${sessionId}` : `attempt:${sessionId}:${attemptId}`;
|
|
29170
30138
|
this.#database.exec("BEGIN IMMEDIATE");
|
|
29171
30139
|
try {
|
|
29172
30140
|
const row = this.#database.prepare(
|
|
@@ -29183,13 +30151,22 @@ var SessionEventOutbox = class {
|
|
|
29183
30151
|
kind: SESSION_EVENT_KIND,
|
|
29184
30152
|
payload,
|
|
29185
30153
|
sessionId,
|
|
29186
|
-
source: attemptId ===
|
|
30154
|
+
source: attemptId.length === 0 ? { kind: "runtime", sourceSeq: nextSourceSeq.toString() } : {
|
|
29187
30155
|
attemptId,
|
|
29188
30156
|
kind: "attempt",
|
|
29189
30157
|
sourceSeq: nextSourceSeq.toString()
|
|
29190
30158
|
}
|
|
29191
30159
|
};
|
|
29192
30160
|
const encoded = encodeSessionEventEnvelope(envelope2);
|
|
30161
|
+
const byteLength = new TextEncoder().encode(encoded).byteLength;
|
|
30162
|
+
const state = this.#database.prepare(
|
|
30163
|
+
`SELECT event_count, total_bytes
|
|
30164
|
+
FROM relay_session_event_outbox_state
|
|
30165
|
+
WHERE singleton = 1`
|
|
30166
|
+
).get();
|
|
30167
|
+
if (rowNumber(state, "event_count") + 1 > maximumEventCount || rowNumber(state, "total_bytes") + byteLength > maximumEventBytes) {
|
|
30168
|
+
throw new SessionEventOutboxCapacityError();
|
|
30169
|
+
}
|
|
29193
30170
|
this.#database.prepare(
|
|
29194
30171
|
`INSERT INTO relay_session_event_sources (
|
|
29195
30172
|
source_key, next_source_seq
|
|
@@ -29199,9 +30176,15 @@ var SessionEventOutbox = class {
|
|
|
29199
30176
|
).run(sourceKey, nextSourceSeq + 1);
|
|
29200
30177
|
this.#database.prepare(
|
|
29201
30178
|
`INSERT INTO relay_session_event_outbox (
|
|
29202
|
-
event_id, session_id, source_key, envelope_json
|
|
29203
|
-
) VALUES (?, ?, ?, ?)`
|
|
29204
|
-
).run(envelope2.eventId, envelope2.sessionId, sourceKey, encoded);
|
|
30179
|
+
event_id, session_id, source_key, byte_length, envelope_json
|
|
30180
|
+
) VALUES (?, ?, ?, ?, ?)`
|
|
30181
|
+
).run(envelope2.eventId, envelope2.sessionId, sourceKey, byteLength, encoded);
|
|
30182
|
+
this.#database.prepare(
|
|
30183
|
+
`UPDATE relay_session_event_outbox_state
|
|
30184
|
+
SET event_count = event_count + 1,
|
|
30185
|
+
total_bytes = total_bytes + ?
|
|
30186
|
+
WHERE singleton = 1`
|
|
30187
|
+
).run(byteLength);
|
|
29205
30188
|
this.#database.exec("COMMIT");
|
|
29206
30189
|
return encoded;
|
|
29207
30190
|
} catch (error61) {
|
|
@@ -29209,6 +30192,44 @@ var SessionEventOutbox = class {
|
|
|
29209
30192
|
throw error61;
|
|
29210
30193
|
}
|
|
29211
30194
|
};
|
|
30195
|
+
#removeAcknowledgedEvent = (eventId, sessionId) => {
|
|
30196
|
+
this.#database.exec("BEGIN IMMEDIATE");
|
|
30197
|
+
try {
|
|
30198
|
+
const stored = this.#database.prepare(
|
|
30199
|
+
`SELECT byte_length FROM relay_session_event_outbox
|
|
30200
|
+
WHERE event_id = ? AND session_id = ?`
|
|
30201
|
+
).get(eventId, sessionId);
|
|
30202
|
+
if (stored === void 0) {
|
|
30203
|
+
this.#database.exec("COMMIT");
|
|
30204
|
+
return false;
|
|
30205
|
+
}
|
|
30206
|
+
const byteLength = rowNumber(stored, "byte_length");
|
|
30207
|
+
const deletion = this.#database.prepare(
|
|
30208
|
+
`DELETE FROM relay_session_event_outbox
|
|
30209
|
+
WHERE event_id = ? AND session_id = ?`
|
|
30210
|
+
).run(eventId, sessionId);
|
|
30211
|
+
if (deletion.changes !== 1) {
|
|
30212
|
+
throw new Error("The acknowledged session event could not be removed from the durable outbox");
|
|
30213
|
+
}
|
|
30214
|
+
this.#decrementEventState(byteLength);
|
|
30215
|
+
this.#database.exec("COMMIT");
|
|
30216
|
+
return true;
|
|
30217
|
+
} catch (error61) {
|
|
30218
|
+
this.#database.exec("ROLLBACK");
|
|
30219
|
+
throw error61;
|
|
30220
|
+
}
|
|
30221
|
+
};
|
|
30222
|
+
#decrementEventState = (byteLength) => {
|
|
30223
|
+
const result = this.#database.prepare(
|
|
30224
|
+
`UPDATE relay_session_event_outbox_state
|
|
30225
|
+
SET event_count = event_count - 1,
|
|
30226
|
+
total_bytes = total_bytes - ?
|
|
30227
|
+
WHERE singleton = 1 AND event_count > 0 AND total_bytes >= ?`
|
|
30228
|
+
).run(byteLength, byteLength);
|
|
30229
|
+
if (result.changes !== 1) {
|
|
30230
|
+
throw new Error("The Session event outbox capacity state is inconsistent");
|
|
30231
|
+
}
|
|
30232
|
+
};
|
|
29212
30233
|
pending = () => this.#database.prepare(
|
|
29213
30234
|
`SELECT envelope_json
|
|
29214
30235
|
FROM relay_session_event_outbox
|
|
@@ -29235,7 +30256,68 @@ var SessionEventOutbox = class {
|
|
|
29235
30256
|
LIMIT ?`
|
|
29236
30257
|
).all(limit).map(readPendingEnvelope);
|
|
29237
30258
|
};
|
|
30259
|
+
pendingSourceHeads = (limit, excludedEventIds, excludedSourceKeys) => {
|
|
30260
|
+
if (!Number.isSafeInteger(limit) || limit < 1) {
|
|
30261
|
+
throw new Error("Session event replay batch limit must be a positive integer");
|
|
30262
|
+
}
|
|
30263
|
+
const exclusions = [];
|
|
30264
|
+
const parameters = [];
|
|
30265
|
+
if (excludedEventIds.length > 0) {
|
|
30266
|
+
exclusions.push(`event_id NOT IN (${excludedEventIds.map(() => "?").join(", ")})`);
|
|
30267
|
+
parameters.push(...excludedEventIds);
|
|
30268
|
+
}
|
|
30269
|
+
if (excludedSourceKeys.length > 0) {
|
|
30270
|
+
exclusions.push(`source_key NOT IN (${excludedSourceKeys.map(() => "?").join(", ")})`);
|
|
30271
|
+
parameters.push(...excludedSourceKeys);
|
|
30272
|
+
}
|
|
30273
|
+
parameters.push(limit.toString());
|
|
30274
|
+
const where = exclusions.length === 0 ? "" : `WHERE ${exclusions.join(" AND ")}`;
|
|
30275
|
+
return this.#database.prepare(
|
|
30276
|
+
`WITH available_events AS (
|
|
30277
|
+
SELECT ordinal, source_key
|
|
30278
|
+
FROM relay_session_event_outbox
|
|
30279
|
+
${where}
|
|
30280
|
+
), ranked_events AS (
|
|
30281
|
+
SELECT ordinal,
|
|
30282
|
+
ROW_NUMBER() OVER (
|
|
30283
|
+
PARTITION BY source_key
|
|
30284
|
+
ORDER BY ordinal
|
|
30285
|
+
) AS source_position
|
|
30286
|
+
FROM available_events
|
|
30287
|
+
)
|
|
30288
|
+
SELECT outbox.envelope_json
|
|
30289
|
+
FROM ranked_events AS ranked
|
|
30290
|
+
INNER JOIN relay_session_event_outbox AS outbox
|
|
30291
|
+
ON outbox.ordinal = ranked.ordinal
|
|
30292
|
+
WHERE ranked.source_position = 1
|
|
30293
|
+
ORDER BY outbox.ordinal
|
|
30294
|
+
LIMIT ?`
|
|
30295
|
+
).all(...parameters).map(readPendingEnvelope);
|
|
30296
|
+
};
|
|
29238
30297
|
};
|
|
30298
|
+
function validateLimits(limits) {
|
|
30299
|
+
const values = [
|
|
30300
|
+
limits.criticalEventBytes,
|
|
30301
|
+
limits.criticalEventCount,
|
|
30302
|
+
limits.runtimeDeliveryBytes,
|
|
30303
|
+
limits.runtimeDeliveryCount,
|
|
30304
|
+
limits.standardEventBytes,
|
|
30305
|
+
limits.standardEventCount
|
|
30306
|
+
];
|
|
30307
|
+
if (values.some((value) => !Number.isSafeInteger(value) || value < 1)) {
|
|
30308
|
+
throw new Error("Session event outbox limits must be positive integers");
|
|
30309
|
+
}
|
|
30310
|
+
if (limits.criticalEventBytes < limits.standardEventBytes || limits.criticalEventCount < limits.standardEventCount) {
|
|
30311
|
+
throw new Error("Critical Session event capacity must include the standard capacity");
|
|
30312
|
+
}
|
|
30313
|
+
}
|
|
30314
|
+
function runtimeDeliveryState(row) {
|
|
30315
|
+
const state = rowString2(row, "state");
|
|
30316
|
+
if (state !== "received" && state !== "relay_committed" && state !== "processed") {
|
|
30317
|
+
throw new Error("SQLite returned an invalid Runtime delivery state");
|
|
30318
|
+
}
|
|
30319
|
+
return state;
|
|
30320
|
+
}
|
|
29239
30321
|
function isDaemonExecutionState(value) {
|
|
29240
30322
|
return value === "cancelled" || value === "dispatching" || value === "failed" || value === "running" || value === "succeeded";
|
|
29241
30323
|
}
|
|
@@ -29261,10 +30343,23 @@ function botIpcSocketPath() {
|
|
|
29261
30343
|
return join15("/tmp", `mobius-bot-${randomUUID4()}.sock`);
|
|
29262
30344
|
}
|
|
29263
30345
|
var DaemonAcpObserver = class {
|
|
30346
|
+
#config;
|
|
29264
30347
|
#record;
|
|
29265
|
-
constructor(
|
|
29266
|
-
this.#
|
|
30348
|
+
constructor(config2, record3) {
|
|
30349
|
+
this.#config = config2;
|
|
30350
|
+
this.#record = record3;
|
|
29267
30351
|
}
|
|
30352
|
+
importLocalImage = async (sessionId, image, signal) => {
|
|
30353
|
+
try {
|
|
30354
|
+
return (await uploadRuntimeArtifact(this.#config, sessionId, image, signal)).artifactId;
|
|
30355
|
+
} catch (cause) {
|
|
30356
|
+
signal.throwIfAborted();
|
|
30357
|
+
if (cause instanceof Error && cause.name === "AbortError") {
|
|
30358
|
+
throw cause;
|
|
30359
|
+
}
|
|
30360
|
+
return "";
|
|
30361
|
+
}
|
|
30362
|
+
};
|
|
29268
30363
|
onCommands = (event) => {
|
|
29269
30364
|
this.#record(event.sessionId, encodeSessionCommandsUpdatedEvent(event));
|
|
29270
30365
|
return Promise.resolve();
|
|
@@ -29454,8 +30549,7 @@ var ActiveTurnReconciliationError = class extends Error {
|
|
|
29454
30549
|
}
|
|
29455
30550
|
};
|
|
29456
30551
|
function activeTurnReconciliationEndpoint(config2, turn) {
|
|
29457
|
-
const endpoint =
|
|
29458
|
-
endpoint.protocol = endpoint.protocol === "wss:" ? "https:" : "http:";
|
|
30552
|
+
const endpoint = relayHttpEndpoint(config2.relayUrl);
|
|
29459
30553
|
let channelPath = "";
|
|
29460
30554
|
if (endpoint.pathname.endsWith("/daemon")) {
|
|
29461
30555
|
channelPath = endpoint.pathname.slice(0, -"/daemon".length);
|
|
@@ -29467,7 +30561,6 @@ function activeTurnReconciliationEndpoint(config2, turn) {
|
|
|
29467
30561
|
channelPath = `${endpoint.pathname.slice(0, -runtimePath.length)}/channels/${encodeURIComponent(config2.channelId)}`;
|
|
29468
30562
|
}
|
|
29469
30563
|
endpoint.pathname = `${channelPath}/sessions/${encodeURIComponent(turn.command.sessionId)}/attempts/${encodeURIComponent(turn.attemptId)}/reconciliation`;
|
|
29470
|
-
endpoint.searchParams.delete("liveness");
|
|
29471
30564
|
return endpoint;
|
|
29472
30565
|
}
|
|
29473
30566
|
async function reconcileActiveTurn(config2, turn, signal) {
|
|
@@ -29476,10 +30569,10 @@ async function reconcileActiveTurn(config2, turn, signal) {
|
|
|
29476
30569
|
const requestSignal = AbortSignal.any([signal, timeoutSignal]);
|
|
29477
30570
|
let response;
|
|
29478
30571
|
try {
|
|
29479
|
-
response = await
|
|
30572
|
+
response = await fetch6(activeTurnReconciliationEndpoint(config2, turn), {
|
|
29480
30573
|
body: JSON.stringify({ outcome: { kind: "running" } }),
|
|
29481
30574
|
dispatcher: environmentProxyDispatcher,
|
|
29482
|
-
headers: { "content-type": "application/json" },
|
|
30575
|
+
headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
|
|
29483
30576
|
method: "POST",
|
|
29484
30577
|
signal: requestSignal
|
|
29485
30578
|
});
|
|
@@ -29547,17 +30640,31 @@ var ConnectedDaemonSessionEventState = class extends DaemonSessionEventConnectio
|
|
|
29547
30640
|
}
|
|
29548
30641
|
};
|
|
29549
30642
|
};
|
|
29550
|
-
var SESSION_EVENT_REPLAY_WINDOW =
|
|
30643
|
+
var SESSION_EVENT_REPLAY_WINDOW = 16;
|
|
30644
|
+
var SESSION_EVENT_SOURCE_REPLAY_WINDOW = 4;
|
|
30645
|
+
var SESSION_EVENT_REPLAY_BYTE_LIMIT = 32 * 1024 * 1024;
|
|
30646
|
+
var InFlightSessionEvent = class {
|
|
30647
|
+
byteLength;
|
|
30648
|
+
sourceKey;
|
|
30649
|
+
constructor(sourceKey, byteLength) {
|
|
30650
|
+
this.byteLength = byteLength;
|
|
30651
|
+
this.sourceKey = sourceKey;
|
|
30652
|
+
}
|
|
30653
|
+
};
|
|
30654
|
+
function sessionEventSourceKey(envelope2) {
|
|
30655
|
+
return envelope2.source.kind === "attempt" ? `attempt:${envelope2.sessionId}:${envelope2.source.attemptId}` : `runtime:${envelope2.sessionId}`;
|
|
30656
|
+
}
|
|
29551
30657
|
var DaemonSessionEventPublisher = class {
|
|
29552
30658
|
#outbox;
|
|
29553
|
-
#
|
|
30659
|
+
#inFlightEvents = /* @__PURE__ */ new Map();
|
|
30660
|
+
#inFlightBytes = 0;
|
|
29554
30661
|
#connection = new DisconnectedDaemonSessionEventState();
|
|
29555
30662
|
constructor(outbox) {
|
|
29556
30663
|
this.#outbox = outbox;
|
|
29557
30664
|
}
|
|
29558
30665
|
connect = (socket) => {
|
|
29559
30666
|
this.#connection = new ConnectedDaemonSessionEventState(socket);
|
|
29560
|
-
this.#
|
|
30667
|
+
this.#clearInFlight();
|
|
29561
30668
|
this.#publishNextBatch();
|
|
29562
30669
|
};
|
|
29563
30670
|
disconnect = (socket) => {
|
|
@@ -29565,10 +30672,15 @@ var DaemonSessionEventPublisher = class {
|
|
|
29565
30672
|
return;
|
|
29566
30673
|
}
|
|
29567
30674
|
this.#connection = this.#connection.disconnect(socket);
|
|
29568
|
-
this.#
|
|
30675
|
+
this.#clearInFlight();
|
|
29569
30676
|
};
|
|
29570
30677
|
recordAttempt = (sessionId, payload, attemptId) => {
|
|
29571
|
-
|
|
30678
|
+
const kind = decodeMessageKind(payload);
|
|
30679
|
+
if (kind === SESSION_COMPLETED_KIND || kind === SESSION_FAILED_KIND) {
|
|
30680
|
+
this.#outbox.enqueueCritical(sessionId, payload, attemptId);
|
|
30681
|
+
} else {
|
|
30682
|
+
this.#outbox.enqueue(sessionId, payload, attemptId);
|
|
30683
|
+
}
|
|
29572
30684
|
this.#publishNextBatch();
|
|
29573
30685
|
};
|
|
29574
30686
|
recordRuntime = (sessionId, payload) => {
|
|
@@ -29579,7 +30691,7 @@ var DaemonSessionEventPublisher = class {
|
|
|
29579
30691
|
if (!this.#outbox.acknowledge(acknowledgement)) {
|
|
29580
30692
|
return;
|
|
29581
30693
|
}
|
|
29582
|
-
this.#
|
|
30694
|
+
this.#removeInFlight(acknowledgement.eventId);
|
|
29583
30695
|
this.#publishNextBatch();
|
|
29584
30696
|
};
|
|
29585
30697
|
quarantine = (rejection) => {
|
|
@@ -29587,24 +30699,60 @@ var DaemonSessionEventPublisher = class {
|
|
|
29587
30699
|
if (!quarantined) {
|
|
29588
30700
|
return false;
|
|
29589
30701
|
}
|
|
29590
|
-
this.#
|
|
30702
|
+
this.#removeInFlight(rejection.eventId);
|
|
29591
30703
|
this.#publishNextBatch();
|
|
29592
30704
|
return true;
|
|
29593
30705
|
};
|
|
29594
30706
|
#publishNextBatch = () => {
|
|
29595
|
-
|
|
29596
|
-
|
|
29597
|
-
|
|
29598
|
-
|
|
29599
|
-
|
|
29600
|
-
const
|
|
29601
|
-
|
|
29602
|
-
this.#
|
|
30707
|
+
while (this.#inFlightEvents.size < SESSION_EVENT_REPLAY_WINDOW) {
|
|
30708
|
+
const sourceCounts = /* @__PURE__ */ new Map();
|
|
30709
|
+
for (const inFlight of this.#inFlightEvents.values()) {
|
|
30710
|
+
sourceCounts.set(inFlight.sourceKey, (sourceCounts.get(inFlight.sourceKey) ?? 0) + 1);
|
|
30711
|
+
}
|
|
30712
|
+
const saturatedSources = [...sourceCounts.entries()].filter(([, count]) => count >= SESSION_EVENT_SOURCE_REPLAY_WINDOW).map(([sourceKey]) => sourceKey);
|
|
30713
|
+
const batch = this.#outbox.pendingSourceHeads(
|
|
30714
|
+
SESSION_EVENT_REPLAY_WINDOW - this.#inFlightEvents.size,
|
|
30715
|
+
[...this.#inFlightEvents.keys()],
|
|
30716
|
+
saturatedSources
|
|
30717
|
+
);
|
|
30718
|
+
let sent = 0;
|
|
30719
|
+
for (const encoded of batch) {
|
|
30720
|
+
const envelope2 = decodeSessionEventEnvelope(encoded);
|
|
30721
|
+
const sourceKey = sessionEventSourceKey(envelope2);
|
|
30722
|
+
const sourceCount = sourceCounts.get(sourceKey) ?? 0;
|
|
30723
|
+
if (sourceCount >= SESSION_EVENT_SOURCE_REPLAY_WINDOW) {
|
|
30724
|
+
continue;
|
|
30725
|
+
}
|
|
30726
|
+
const byteLength = new TextEncoder().encode(encoded).byteLength;
|
|
30727
|
+
if (this.#inFlightBytes + byteLength > SESSION_EVENT_REPLAY_BYTE_LIMIT) {
|
|
30728
|
+
continue;
|
|
30729
|
+
}
|
|
30730
|
+
if (!this.#connection.send(encoded)) {
|
|
30731
|
+
this.#clearInFlight();
|
|
30732
|
+
return;
|
|
30733
|
+
}
|
|
30734
|
+
this.#inFlightEvents.set(envelope2.eventId, new InFlightSessionEvent(sourceKey, byteLength));
|
|
30735
|
+
this.#inFlightBytes += byteLength;
|
|
30736
|
+
sourceCounts.set(sourceKey, sourceCount + 1);
|
|
30737
|
+
sent += 1;
|
|
30738
|
+
}
|
|
30739
|
+
if (sent === 0) {
|
|
29603
30740
|
return;
|
|
29604
30741
|
}
|
|
29605
|
-
this.#inFlightEventIds.add(envelope2.eventId);
|
|
29606
30742
|
}
|
|
29607
30743
|
};
|
|
30744
|
+
#removeInFlight = (eventId) => {
|
|
30745
|
+
const inFlight = this.#inFlightEvents.get(eventId);
|
|
30746
|
+
if (inFlight === void 0) {
|
|
30747
|
+
return;
|
|
30748
|
+
}
|
|
30749
|
+
this.#inFlightEvents.delete(eventId);
|
|
30750
|
+
this.#inFlightBytes -= inFlight.byteLength;
|
|
30751
|
+
};
|
|
30752
|
+
#clearInFlight = () => {
|
|
30753
|
+
this.#inFlightEvents.clear();
|
|
30754
|
+
this.#inFlightBytes = 0;
|
|
30755
|
+
};
|
|
29608
30756
|
};
|
|
29609
30757
|
var CoalescingDaemonActivityPublisher = class {
|
|
29610
30758
|
#pending = /* @__PURE__ */ new Map();
|
|
@@ -29737,7 +30885,7 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
|
|
|
29737
30885
|
additionalDirectories.push(directory);
|
|
29738
30886
|
additionalDirectoryEntries.push({
|
|
29739
30887
|
directoryId: additionalDirectoryId,
|
|
29740
|
-
name:
|
|
30888
|
+
name: basename4(directory)
|
|
29741
30889
|
});
|
|
29742
30890
|
}
|
|
29743
30891
|
return new ResolvedSessionDirectories(cwd, additionalDirectories, additionalDirectoryEntries);
|
|
@@ -29856,6 +31004,9 @@ async function executeSessionConfigure(publisher, socket, command, config2, dire
|
|
|
29856
31004
|
})
|
|
29857
31005
|
);
|
|
29858
31006
|
} catch (error61) {
|
|
31007
|
+
if (signal.aborted) {
|
|
31008
|
+
signal.throwIfAborted();
|
|
31009
|
+
}
|
|
29859
31010
|
reportOperationFailure(socket, command.requestId, command.sessionId, error61);
|
|
29860
31011
|
}
|
|
29861
31012
|
}
|
|
@@ -30195,6 +31346,7 @@ async function publishAgentCatalogUntilAvailable(config2, diagnostics, signal, t
|
|
|
30195
31346
|
}
|
|
30196
31347
|
async function runRelayConnection(config2, directories, audit, sessions, installations, installationObserver, nativeSessions, outbox, publisher, grants, contexts, applicator, ipc, activeTurns, activeAttemptIds, connectionEpoch, diagnostics, onConnected, signal, timer) {
|
|
30197
31348
|
const relayUrl = new URL(config2.relayUrl);
|
|
31349
|
+
relayUrl.searchParams.set("deliveryReceipts", "1");
|
|
30198
31350
|
relayUrl.searchParams.set("liveness", "1");
|
|
30199
31351
|
const socket = await connectRelay(relayUrl, signal);
|
|
30200
31352
|
const reconnectingTurns = [...activeTurns.values()];
|
|
@@ -30243,6 +31395,239 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30243
31395
|
closeRelaySocket(socket, code, reason);
|
|
30244
31396
|
rejectConnection(failure);
|
|
30245
31397
|
};
|
|
31398
|
+
const processingDeliveryIds = /* @__PURE__ */ new Set();
|
|
31399
|
+
const processDeliveredPrompt = async (delivery, command, trackActiveAttempt, execute) => {
|
|
31400
|
+
if (command.sessionId !== delivery.sessionId) {
|
|
31401
|
+
throw new Error("Runtime delivery Session identity does not match its payload");
|
|
31402
|
+
}
|
|
31403
|
+
const active = activeTurns.get(command.commandId);
|
|
31404
|
+
if (active !== void 0) {
|
|
31405
|
+
await active.completion;
|
|
31406
|
+
return;
|
|
31407
|
+
}
|
|
31408
|
+
const receipt = outbox.claimExecution(command.commandId, command.sessionId, delivery.payload);
|
|
31409
|
+
if (receipt.kind === "duplicate") {
|
|
31410
|
+
if (receipt.state === "running") {
|
|
31411
|
+
reportFailure(
|
|
31412
|
+
publisher,
|
|
31413
|
+
command,
|
|
31414
|
+
"agent_execution_interrupted",
|
|
31415
|
+
"The local Agent execution was interrupted before it completed",
|
|
31416
|
+
receipt.attemptId
|
|
31417
|
+
);
|
|
31418
|
+
outbox.transitionExecution(command.commandId, "failed");
|
|
31419
|
+
return;
|
|
31420
|
+
}
|
|
31421
|
+
if (receipt.state !== "dispatching") {
|
|
31422
|
+
return;
|
|
31423
|
+
}
|
|
31424
|
+
}
|
|
31425
|
+
const turn = new ActiveDaemonTurn(command, receipt.attemptId);
|
|
31426
|
+
activeTurns.set(command.commandId, turn);
|
|
31427
|
+
if (trackActiveAttempt) {
|
|
31428
|
+
activeAttemptIds.set(command.sessionId, receipt.attemptId);
|
|
31429
|
+
}
|
|
31430
|
+
try {
|
|
31431
|
+
await execute(receipt.attemptId, turn.signal);
|
|
31432
|
+
} finally {
|
|
31433
|
+
activeTurns.delete(command.commandId);
|
|
31434
|
+
if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
|
|
31435
|
+
activeAttemptIds.delete(command.sessionId);
|
|
31436
|
+
}
|
|
31437
|
+
turn.finish();
|
|
31438
|
+
}
|
|
31439
|
+
};
|
|
31440
|
+
const processDeliveredPayload = async (delivery) => {
|
|
31441
|
+
const kind = decodeMessageKind(delivery.payload);
|
|
31442
|
+
if (kind === SESSION_CANCEL_KIND) {
|
|
31443
|
+
const cancellation = decodeSessionCancelCommand(delivery.payload);
|
|
31444
|
+
if (cancellation.sessionId !== delivery.sessionId) {
|
|
31445
|
+
throw new Error("Runtime delivery Session identity does not match its payload");
|
|
31446
|
+
}
|
|
31447
|
+
const turn = activeTurns.get(cancellation.commandId);
|
|
31448
|
+
if (turn === void 0 || !turn.matches(cancellation) || !turn.requestCancellation()) {
|
|
31449
|
+
return;
|
|
31450
|
+
}
|
|
31451
|
+
audit.record({
|
|
31452
|
+
commandId: cancellation.commandId,
|
|
31453
|
+
event: "session_cancellation_requested",
|
|
31454
|
+
sessionId: cancellation.sessionId
|
|
31455
|
+
});
|
|
31456
|
+
await sessions.cancelPrompt(cancellation.sessionId);
|
|
31457
|
+
return;
|
|
31458
|
+
}
|
|
31459
|
+
if (kind === SESSION_CONFIGURE_KIND) {
|
|
31460
|
+
const command = decodeSessionConfigureCommand(delivery.payload);
|
|
31461
|
+
if (command.sessionId !== delivery.sessionId) {
|
|
31462
|
+
throw new Error("Runtime delivery Session identity does not match its payload");
|
|
31463
|
+
}
|
|
31464
|
+
await executeSessionConfigure(
|
|
31465
|
+
publisher,
|
|
31466
|
+
socket,
|
|
31467
|
+
command,
|
|
31468
|
+
config2,
|
|
31469
|
+
directories,
|
|
31470
|
+
audit,
|
|
31471
|
+
sessions,
|
|
31472
|
+
connectionController.signal
|
|
31473
|
+
);
|
|
31474
|
+
return;
|
|
31475
|
+
}
|
|
31476
|
+
if (kind === SESSION_PERMISSION_RESPOND_KIND) {
|
|
31477
|
+
const command = decodeSessionPermissionRespondCommand(delivery.payload);
|
|
31478
|
+
if (command.sessionId !== delivery.sessionId) {
|
|
31479
|
+
throw new Error("Runtime delivery Session identity does not match its payload");
|
|
31480
|
+
}
|
|
31481
|
+
try {
|
|
31482
|
+
await sessions.respondPermission(command);
|
|
31483
|
+
audit.record({
|
|
31484
|
+
commandId: command.interactionId,
|
|
31485
|
+
event: "session_permission_resolved",
|
|
31486
|
+
sessionId: command.sessionId
|
|
31487
|
+
});
|
|
31488
|
+
} catch (error61) {
|
|
31489
|
+
reportOperationFailure(socket, command.interactionId, command.sessionId, error61);
|
|
31490
|
+
}
|
|
31491
|
+
return;
|
|
31492
|
+
}
|
|
31493
|
+
if (kind === SESSION_ELICITATION_RESPOND_KIND) {
|
|
31494
|
+
const command = decodeSessionElicitationRespondCommand(delivery.payload);
|
|
31495
|
+
if (command.sessionId !== delivery.sessionId) {
|
|
31496
|
+
throw new Error("Runtime delivery Session identity does not match its payload");
|
|
31497
|
+
}
|
|
31498
|
+
try {
|
|
31499
|
+
await sessions.respondElicitation(command);
|
|
31500
|
+
audit.record({
|
|
31501
|
+
commandId: command.interactionId,
|
|
31502
|
+
event: "session_elicitation_resolved",
|
|
31503
|
+
sessionId: command.sessionId
|
|
31504
|
+
});
|
|
31505
|
+
} catch (error61) {
|
|
31506
|
+
reportOperationFailure(socket, command.interactionId, command.sessionId, error61);
|
|
31507
|
+
}
|
|
31508
|
+
return;
|
|
31509
|
+
}
|
|
31510
|
+
if (kind === BOT_SESSION_PROMPT_KIND) {
|
|
31511
|
+
const command = decodeBotSessionPromptCommand(delivery.payload);
|
|
31512
|
+
await processDeliveredPrompt(
|
|
31513
|
+
delivery,
|
|
31514
|
+
command,
|
|
31515
|
+
true,
|
|
31516
|
+
(attemptId, executionSignal) => executeBotPrompt(
|
|
31517
|
+
outbox,
|
|
31518
|
+
publisher,
|
|
31519
|
+
command,
|
|
31520
|
+
config2,
|
|
31521
|
+
directories,
|
|
31522
|
+
audit,
|
|
31523
|
+
sessions,
|
|
31524
|
+
grants,
|
|
31525
|
+
contexts,
|
|
31526
|
+
applicator,
|
|
31527
|
+
ipc,
|
|
31528
|
+
attemptId,
|
|
31529
|
+
timer,
|
|
31530
|
+
executionSignal
|
|
31531
|
+
)
|
|
31532
|
+
);
|
|
31533
|
+
return;
|
|
31534
|
+
}
|
|
31535
|
+
if (kind === SESSION_PROMPT_KIND) {
|
|
31536
|
+
const command = decodeSessionPromptCommand(delivery.payload);
|
|
31537
|
+
await processDeliveredPrompt(
|
|
31538
|
+
delivery,
|
|
31539
|
+
command,
|
|
31540
|
+
command.disposition !== SessionPromptDisposition.Steer,
|
|
31541
|
+
(attemptId, executionSignal) => executePrompt(
|
|
31542
|
+
outbox,
|
|
31543
|
+
publisher,
|
|
31544
|
+
command,
|
|
31545
|
+
config2,
|
|
31546
|
+
directories,
|
|
31547
|
+
audit,
|
|
31548
|
+
sessions,
|
|
31549
|
+
attemptId,
|
|
31550
|
+
timer,
|
|
31551
|
+
executionSignal
|
|
31552
|
+
)
|
|
31553
|
+
);
|
|
31554
|
+
return;
|
|
31555
|
+
}
|
|
31556
|
+
throw new Error("Runtime delivery contains an unsupported protocol message");
|
|
31557
|
+
};
|
|
31558
|
+
const processRuntimeDelivery = (delivery, state) => {
|
|
31559
|
+
if (state === "processed" || processingDeliveryIds.has(delivery.deliveryId)) {
|
|
31560
|
+
return;
|
|
31561
|
+
}
|
|
31562
|
+
processingDeliveryIds.add(delivery.deliveryId);
|
|
31563
|
+
void processDeliveredPayload(delivery).then(() => {
|
|
31564
|
+
outbox.markRuntimeDeliveryProcessed(delivery.deliveryId, delivery.sessionId);
|
|
31565
|
+
}).catch((error61) => {
|
|
31566
|
+
if (connectionController.signal.aborted) {
|
|
31567
|
+
return;
|
|
31568
|
+
}
|
|
31569
|
+
console.error("Mobius daemon could not process a durable Runtime delivery", error61);
|
|
31570
|
+
failAndClose(
|
|
31571
|
+
new Error("Runtime delivery processing failed", { cause: error61 }),
|
|
31572
|
+
4008,
|
|
31573
|
+
"Invalid Runtime delivery",
|
|
31574
|
+
"delivery"
|
|
31575
|
+
);
|
|
31576
|
+
}).finally(() => processingDeliveryIds.delete(delivery.deliveryId));
|
|
31577
|
+
};
|
|
31578
|
+
const receiveRuntimeDelivery = (delivery) => {
|
|
31579
|
+
const payloadKind = decodeMessageKind(delivery.payload);
|
|
31580
|
+
let payloadSessionId = "";
|
|
31581
|
+
if (payloadKind === SESSION_CANCEL_KIND) {
|
|
31582
|
+
payloadSessionId = decodeSessionCancelCommand(delivery.payload).sessionId;
|
|
31583
|
+
} else if (payloadKind === SESSION_CONFIGURE_KIND) {
|
|
31584
|
+
payloadSessionId = decodeSessionConfigureCommand(delivery.payload).sessionId;
|
|
31585
|
+
} else if (payloadKind === SESSION_PERMISSION_RESPOND_KIND) {
|
|
31586
|
+
payloadSessionId = decodeSessionPermissionRespondCommand(delivery.payload).sessionId;
|
|
31587
|
+
} else if (payloadKind === SESSION_ELICITATION_RESPOND_KIND) {
|
|
31588
|
+
payloadSessionId = decodeSessionElicitationRespondCommand(delivery.payload).sessionId;
|
|
31589
|
+
} else if (payloadKind === SESSION_PROMPT_KIND) {
|
|
31590
|
+
payloadSessionId = decodeSessionPromptCommand(delivery.payload).sessionId;
|
|
31591
|
+
} else if (payloadKind === BOT_SESSION_PROMPT_KIND) {
|
|
31592
|
+
payloadSessionId = decodeBotSessionPromptCommand(delivery.payload).sessionId;
|
|
31593
|
+
} else {
|
|
31594
|
+
throw new Error("Runtime delivery contains an unsupported protocol message");
|
|
31595
|
+
}
|
|
31596
|
+
if (payloadSessionId !== delivery.sessionId) {
|
|
31597
|
+
throw new Error("Runtime delivery Session identity does not match its payload");
|
|
31598
|
+
}
|
|
31599
|
+
const stored = outbox.claimRuntimeDelivery(delivery);
|
|
31600
|
+
send(
|
|
31601
|
+
socket,
|
|
31602
|
+
encodeRuntimeDeliveryReceived({
|
|
31603
|
+
deliveryId: delivery.deliveryId,
|
|
31604
|
+
kind: RUNTIME_DELIVERY_RECEIVED_KIND,
|
|
31605
|
+
sessionId: delivery.sessionId
|
|
31606
|
+
})
|
|
31607
|
+
);
|
|
31608
|
+
processRuntimeDelivery(delivery, stored.state);
|
|
31609
|
+
};
|
|
31610
|
+
const resumeRuntimeDeliveries = () => {
|
|
31611
|
+
for (const stored of outbox.runtimeDeliveries()) {
|
|
31612
|
+
const delivery = {
|
|
31613
|
+
deliveryId: stored.deliveryId,
|
|
31614
|
+
kind: RUNTIME_DELIVERY_KIND,
|
|
31615
|
+
payload: stored.payload,
|
|
31616
|
+
sessionId: stored.sessionId
|
|
31617
|
+
};
|
|
31618
|
+
if (stored.state !== "relay_committed") {
|
|
31619
|
+
send(
|
|
31620
|
+
socket,
|
|
31621
|
+
encodeRuntimeDeliveryReceived({
|
|
31622
|
+
deliveryId: stored.deliveryId,
|
|
31623
|
+
kind: RUNTIME_DELIVERY_RECEIVED_KIND,
|
|
31624
|
+
sessionId: stored.sessionId
|
|
31625
|
+
})
|
|
31626
|
+
);
|
|
31627
|
+
}
|
|
31628
|
+
processRuntimeDelivery(delivery, stored.state);
|
|
31629
|
+
}
|
|
31630
|
+
};
|
|
30246
31631
|
const connectionLiveness = new RelayConnectionLiveness(timer, {
|
|
30247
31632
|
send: (message) => send(socket, message),
|
|
30248
31633
|
unresponsive: (heartbeatId, timeoutMilliseconds) => {
|
|
@@ -30281,6 +31666,17 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30281
31666
|
}
|
|
30282
31667
|
try {
|
|
30283
31668
|
const kind = decodeMessageKind(encoded);
|
|
31669
|
+
if (kind === RUNTIME_DELIVERY_COMMITTED_KIND) {
|
|
31670
|
+
const committed = decodeRuntimeDeliveryCommitted(encoded);
|
|
31671
|
+
if (!outbox.markRuntimeDeliveryCommitted(committed.deliveryId, committed.sessionId)) {
|
|
31672
|
+
console.warn("Mobius daemon ignored confirmation for an unknown Runtime delivery");
|
|
31673
|
+
}
|
|
31674
|
+
return;
|
|
31675
|
+
}
|
|
31676
|
+
if (kind === RUNTIME_DELIVERY_KIND) {
|
|
31677
|
+
receiveRuntimeDelivery(decodeRuntimeDelivery(encoded));
|
|
31678
|
+
return;
|
|
31679
|
+
}
|
|
30284
31680
|
if (kind === SESSION_EVENT_ACK_KIND) {
|
|
30285
31681
|
publisher.acknowledge(decodeSessionEventAcknowledgement(encoded));
|
|
30286
31682
|
return;
|
|
@@ -30717,6 +32113,10 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30717
32113
|
});
|
|
30718
32114
|
} catch (error61) {
|
|
30719
32115
|
console.error("Mobius daemon rejected a message", error61);
|
|
32116
|
+
if (error61 instanceof RuntimeDeliveryInboxCapacityError) {
|
|
32117
|
+
failAndClose(error61, 4013, "Runtime delivery queue full", "delivery_backpressure");
|
|
32118
|
+
return;
|
|
32119
|
+
}
|
|
30720
32120
|
failAndClose(
|
|
30721
32121
|
new Error("Relay sent an invalid protocol message", { cause: error61 }),
|
|
30722
32122
|
4008,
|
|
@@ -30734,6 +32134,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30734
32134
|
return;
|
|
30735
32135
|
}
|
|
30736
32136
|
publisher.connect(socket);
|
|
32137
|
+
resumeRuntimeDeliveries();
|
|
30737
32138
|
},
|
|
30738
32139
|
(error61) => {
|
|
30739
32140
|
if (finished) {
|
|
@@ -30786,7 +32187,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
30786
32187
|
}
|
|
30787
32188
|
publisher.recordAttempt(sessionId, payload, attemptId);
|
|
30788
32189
|
};
|
|
30789
|
-
const sessions = new AcpSessionManager(new DaemonAcpObserver(recordSessionEvent), sessionStore);
|
|
32190
|
+
const sessions = new AcpSessionManager(new DaemonAcpObserver(config2, recordSessionEvent), sessionStore);
|
|
30790
32191
|
const directories = new WorkspaceDirectoryService(config2.bindingId, config2.defaultWorkspace);
|
|
30791
32192
|
const installationObserver = new DaemonInstallationObserver();
|
|
30792
32193
|
const diagnostics = new RelayConnectionDiagnostics(audit, config2.channelId, config2.relayUrl);
|
|
@@ -30885,13 +32286,13 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
30885
32286
|
|
|
30886
32287
|
// src/pairing/pair-local-machine.ts
|
|
30887
32288
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
30888
|
-
import { mkdir as mkdir4, open as open4, realpath as
|
|
32289
|
+
import { mkdir as mkdir4, open as open4, realpath as realpath8, rename as rename3, stat as stat8, writeFile as writeFile2 } from "node:fs/promises";
|
|
30889
32290
|
import { hostname as hostname3 } from "node:os";
|
|
30890
|
-
import { basename as
|
|
30891
|
-
import { fetch as
|
|
32291
|
+
import { basename as basename5, join as join16, resolve as resolve4 } from "node:path";
|
|
32292
|
+
import { fetch as fetch7 } from "undici";
|
|
30892
32293
|
var PAIRING_TIMEOUT_MILLISECONDS = 2e4;
|
|
30893
32294
|
var PAIRING_CODE_PATTERN = /^[A-HJ-NP-Z2-9]{4}(?:-[A-HJ-NP-Z2-9]{4}){4}$/;
|
|
30894
|
-
var
|
|
32295
|
+
var IDENTIFIER_PATTERN8 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
30895
32296
|
var TOKEN_PATTERN2 = /^[a-zA-Z0-9_-]{32,256}$/;
|
|
30896
32297
|
var MAX_CONNECTION_FILE_LENGTH = 16 * 1024;
|
|
30897
32298
|
var CLAIM_RESPONSE_KEYS = ["channelId", "daemonToken", "runtimeId"];
|
|
@@ -30906,7 +32307,7 @@ var PairingClientError = class extends Error {
|
|
|
30906
32307
|
this.name = "PairingClientError";
|
|
30907
32308
|
}
|
|
30908
32309
|
};
|
|
30909
|
-
function
|
|
32310
|
+
function isRecord11(value) {
|
|
30910
32311
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
30911
32312
|
}
|
|
30912
32313
|
function hasExactKeys(value, expectedKeys) {
|
|
@@ -30945,7 +32346,7 @@ function parsePairingCode(value) {
|
|
|
30945
32346
|
return code;
|
|
30946
32347
|
}
|
|
30947
32348
|
function validatePairingId(value) {
|
|
30948
|
-
if (!
|
|
32349
|
+
if (!IDENTIFIER_PATTERN8.test(value)) {
|
|
30949
32350
|
throw new PairingClientError("invalid_pairing_id", "The Runtime pairing ID is invalid");
|
|
30950
32351
|
}
|
|
30951
32352
|
return value;
|
|
@@ -30954,8 +32355,8 @@ async function resolveDefaultWorkspace2(path2) {
|
|
|
30954
32355
|
const requestedWorkspace = resolve4(path2);
|
|
30955
32356
|
try {
|
|
30956
32357
|
await mkdir4(requestedWorkspace, { recursive: true, mode: 448 });
|
|
30957
|
-
const defaultWorkspace = await
|
|
30958
|
-
const metadata = await
|
|
32358
|
+
const defaultWorkspace = await realpath8(requestedWorkspace);
|
|
32359
|
+
const metadata = await stat8(defaultWorkspace);
|
|
30959
32360
|
if (!metadata.isDirectory()) {
|
|
30960
32361
|
throw new PairingClientError("invalid_workspace", "The default workspace is not a directory");
|
|
30961
32362
|
}
|
|
@@ -30984,9 +32385,9 @@ async function readJsonResponse(response) {
|
|
|
30984
32385
|
}
|
|
30985
32386
|
}
|
|
30986
32387
|
function readRelayError(value) {
|
|
30987
|
-
if (
|
|
32388
|
+
if (isRecord11(value)) {
|
|
30988
32389
|
const error61 = value["error"];
|
|
30989
|
-
if (
|
|
32390
|
+
if (isRecord11(error61)) {
|
|
30990
32391
|
const code = error61["code"];
|
|
30991
32392
|
const message = error61["message"];
|
|
30992
32393
|
if (typeof code === "string" && typeof message === "string") {
|
|
@@ -30997,16 +32398,16 @@ function readRelayError(value) {
|
|
|
30997
32398
|
return new PairingClientError("pairing_failed", "The relay could not pair this machine");
|
|
30998
32399
|
}
|
|
30999
32400
|
function decodePairingResponse(value, credentialField, expectedKeys) {
|
|
31000
|
-
if (!
|
|
32401
|
+
if (!isRecord11(value) || !hasExactKeys(value, expectedKeys)) {
|
|
31001
32402
|
throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
|
|
31002
32403
|
}
|
|
31003
32404
|
const channelId = value["channelId"];
|
|
31004
|
-
const
|
|
32405
|
+
const runtimeCredential2 = value[credentialField];
|
|
31005
32406
|
const runtimeId = value["runtimeId"];
|
|
31006
|
-
if (typeof channelId !== "string" || !
|
|
32407
|
+
if (typeof channelId !== "string" || !IDENTIFIER_PATTERN8.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof runtimeId !== "string" || !IDENTIFIER_PATTERN8.test(runtimeId)) {
|
|
31007
32408
|
throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
|
|
31008
32409
|
}
|
|
31009
|
-
return { channelId, runtimeCredential, runtimeId };
|
|
32410
|
+
return { channelId, runtimeCredential: runtimeCredential2, runtimeId };
|
|
31010
32411
|
}
|
|
31011
32412
|
async function claimPairing(options, defaultWorkspace, localAgents, installableAgents, signal) {
|
|
31012
32413
|
const agents = localAgents.map((agent) => ({
|
|
@@ -31019,13 +32420,13 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
31019
32420
|
const endpoint = options.pairingId.length > 0 ? mobiusApiUrl(options.relayOrigin, `/v1/runtime-pairings/${encodeURIComponent(options.pairingId)}/redeem`) : mobiusApiUrl(options.relayOrigin, "/pairings/claim");
|
|
31020
32421
|
let response;
|
|
31021
32422
|
try {
|
|
31022
|
-
response = await
|
|
32423
|
+
response = await fetch7(endpoint, {
|
|
31023
32424
|
body: JSON.stringify({
|
|
31024
32425
|
agents,
|
|
31025
32426
|
installableAgents,
|
|
31026
32427
|
machineName: hostname3(),
|
|
31027
32428
|
pairingCode: options.code,
|
|
31028
|
-
workspaceName:
|
|
32429
|
+
workspaceName: basename5(defaultWorkspace) || "Local workspace"
|
|
31029
32430
|
}),
|
|
31030
32431
|
dispatcher: environmentProxyDispatcher,
|
|
31031
32432
|
headers: { "content-type": "application/json" },
|
|
@@ -31041,7 +32442,7 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
31041
32442
|
}
|
|
31042
32443
|
return options.pairingId.length > 0 ? decodePairingResponse(value, "runtimeCredential", REDEEM_RESPONSE_KEYS) : decodePairingResponse(value, "daemonToken", CLAIM_RESPONSE_KEYS);
|
|
31043
32444
|
}
|
|
31044
|
-
async function persistConnection(channelId, relayOrigin,
|
|
32445
|
+
async function persistConnection(channelId, relayOrigin, runtimeCredential2, defaultWorkspace, environment) {
|
|
31045
32446
|
const connectionsDirectory = join16(readStateDirectory(environment), "connections");
|
|
31046
32447
|
await mkdir4(connectionsDirectory, { mode: 448, recursive: true });
|
|
31047
32448
|
const connectionPath = join16(connectionsDirectory, `${channelId}.json`);
|
|
@@ -31053,7 +32454,7 @@ async function persistConnection(channelId, relayOrigin, runtimeCredential, defa
|
|
|
31053
32454
|
defaultWorkspace,
|
|
31054
32455
|
channelId,
|
|
31055
32456
|
relayOrigin: relayOrigin.toString(),
|
|
31056
|
-
runtimeCredential
|
|
32457
|
+
runtimeCredential: runtimeCredential2
|
|
31057
32458
|
},
|
|
31058
32459
|
null,
|
|
31059
32460
|
2
|
|
@@ -31065,21 +32466,21 @@ async function persistConnection(channelId, relayOrigin, runtimeCredential, defa
|
|
|
31065
32466
|
return connectionPath;
|
|
31066
32467
|
}
|
|
31067
32468
|
function decodeSavedConnection(value, expectedChannelId) {
|
|
31068
|
-
if (!
|
|
32469
|
+
if (!isRecord11(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS) && !hasExactKeys(value, LEGACY_SAVED_CONNECTION_KEYS)) {
|
|
31069
32470
|
throw new PairingClientError("invalid_connection", "The saved connection is invalid");
|
|
31070
32471
|
}
|
|
31071
32472
|
const defaultWorkspace = value["defaultWorkspace"];
|
|
31072
32473
|
const channelId = value["channelId"];
|
|
31073
|
-
const
|
|
32474
|
+
const runtimeCredential2 = value["runtimeCredential"] ?? value["daemonToken"];
|
|
31074
32475
|
const relayOrigin = value["relayOrigin"];
|
|
31075
|
-
if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !
|
|
32476
|
+
if (typeof defaultWorkspace !== "string" || typeof channelId !== "string" || channelId !== expectedChannelId || !IDENTIFIER_PATTERN8.test(channelId) || typeof runtimeCredential2 !== "string" || !TOKEN_PATTERN2.test(runtimeCredential2) || typeof relayOrigin !== "string") {
|
|
31076
32477
|
throw new PairingClientError("invalid_connection", "The saved connection is invalid");
|
|
31077
32478
|
}
|
|
31078
32479
|
return {
|
|
31079
32480
|
defaultWorkspace,
|
|
31080
32481
|
channelId,
|
|
31081
32482
|
relayOrigin: parseRelayOrigin(relayOrigin),
|
|
31082
|
-
runtimeCredential
|
|
32483
|
+
runtimeCredential: runtimeCredential2
|
|
31083
32484
|
};
|
|
31084
32485
|
}
|
|
31085
32486
|
async function readSavedConnection(channelId, environment) {
|
|
@@ -31191,7 +32592,7 @@ async function resumeMobiusRuntime(channelId, signal, environment = process.env)
|
|
|
31191
32592
|
// src/runtime.ts
|
|
31192
32593
|
var APP_CREDENTIAL_PATTERN = /^mapp_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
|
|
31193
32594
|
var CONVERSATION_CREDENTIAL_PATTERN = /^mconv_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
|
|
31194
|
-
var
|
|
32595
|
+
var IDENTIFIER_PATTERN9 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
31195
32596
|
var RUNTIME_CREDENTIAL_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
|
|
31196
32597
|
var MobiusRuntimeConfigurationError = class extends Error {
|
|
31197
32598
|
code = "runtime_configuration_invalid";
|
|
@@ -31249,7 +32650,7 @@ function relayUrlFromConnection(connection) {
|
|
|
31249
32650
|
}
|
|
31250
32651
|
function loadMobiusRuntimeConnection(environment = process.env) {
|
|
31251
32652
|
const channelId = requiredEnvironmentValue(environment, "MOBIUS_CHANNEL_ID");
|
|
31252
|
-
if (!
|
|
32653
|
+
if (!IDENTIFIER_PATTERN9.test(channelId)) {
|
|
31253
32654
|
throw new MobiusRuntimeConfigurationError("MOBIUS_CHANNEL_ID is invalid");
|
|
31254
32655
|
}
|
|
31255
32656
|
return Object.freeze({
|
|
@@ -31264,8 +32665,8 @@ async function resolveWorkspace(path2) {
|
|
|
31264
32665
|
const requested = resolve5(path2);
|
|
31265
32666
|
try {
|
|
31266
32667
|
await mkdir5(requested, { recursive: true, mode: 448 });
|
|
31267
|
-
const resolved = await
|
|
31268
|
-
const metadata = await
|
|
32668
|
+
const resolved = await realpath9(requested);
|
|
32669
|
+
const metadata = await stat9(resolved);
|
|
31269
32670
|
if (!metadata.isDirectory()) {
|
|
31270
32671
|
throw new MobiusRuntimeConfigurationError("The Runtime workspace is not a directory");
|
|
31271
32672
|
}
|