@moxt-ai/mobius 0.0.27 → 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/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 +826 -113
- package/dist/cli.js.map +4 -4
- package/dist/index.js +849 -137
- 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/run-daemon.d.ts.map +1 -1
- package/dist/run-daemon.js +30 -7
- package/dist/run-daemon.js.map +1 -1
- package/dist/runtime.js +845 -133
- 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),
|
|
@@ -23077,9 +23079,9 @@ function createDaemonConfig(connection, agents = [], installableAgents = []) {
|
|
|
23077
23079
|
|
|
23078
23080
|
// src/run-daemon.ts
|
|
23079
23081
|
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
23080
|
-
import { basename as
|
|
23082
|
+
import { basename as basename4, join as join15 } from "node:path";
|
|
23081
23083
|
import { styleText } from "node:util";
|
|
23082
|
-
import { fetch as
|
|
23084
|
+
import { fetch as fetch6, WebSocket as WebSocket2 } from "undici";
|
|
23083
23085
|
|
|
23084
23086
|
// src/acp/session-manager.ts
|
|
23085
23087
|
import { spawn as spawn3 } from "node:child_process";
|
|
@@ -23090,6 +23092,212 @@ import {
|
|
|
23090
23092
|
RequestError as RequestError2
|
|
23091
23093
|
} from "@agentclientprotocol/sdk";
|
|
23092
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
|
+
|
|
23093
23301
|
// src/acp/activity.ts
|
|
23094
23302
|
var TRUNCATION_MARKER = "\n\u2026 output truncated by Mobius";
|
|
23095
23303
|
function isRecord6(value) {
|
|
@@ -23187,6 +23395,7 @@ function readContentOutputDetail(content) {
|
|
|
23187
23395
|
function summarizeDisplayContent(content) {
|
|
23188
23396
|
return {
|
|
23189
23397
|
...content,
|
|
23398
|
+
artifactId: truncate(content.artifactId, 128),
|
|
23190
23399
|
data: truncate(content.data, AGENT_ACTIVITY_DETAIL_LIMIT),
|
|
23191
23400
|
mimeType: truncate(content.mimeType, 255),
|
|
23192
23401
|
name: truncate(content.name, 500),
|
|
@@ -23199,7 +23408,7 @@ function summarizeDisplayContent(content) {
|
|
|
23199
23408
|
};
|
|
23200
23409
|
}
|
|
23201
23410
|
function contentFitsRecordingEnvelope(content) {
|
|
23202
|
-
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;
|
|
23203
23412
|
}
|
|
23204
23413
|
function encodedByteLength(value) {
|
|
23205
23414
|
return new TextEncoder().encode(JSON.stringify(value)).byteLength;
|
|
@@ -23225,6 +23434,7 @@ function recordedDetail(activity) {
|
|
|
23225
23434
|
}
|
|
23226
23435
|
function emptyDisplayContent(type) {
|
|
23227
23436
|
return {
|
|
23437
|
+
artifactId: "",
|
|
23228
23438
|
data: "",
|
|
23229
23439
|
mimeType: "",
|
|
23230
23440
|
name: "",
|
|
@@ -23237,6 +23447,16 @@ function emptyDisplayContent(type) {
|
|
|
23237
23447
|
uri: ""
|
|
23238
23448
|
};
|
|
23239
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
|
+
}
|
|
23240
23460
|
function normalizeContentBlock(content) {
|
|
23241
23461
|
if (content.type === "text") {
|
|
23242
23462
|
return { ...emptyDisplayContent("text"), text: content.text };
|
|
@@ -24028,7 +24248,6 @@ var AcpHistoryReplay = class {
|
|
|
24028
24248
|
#messages = [];
|
|
24029
24249
|
#lastMessageId = null;
|
|
24030
24250
|
#characters = 0;
|
|
24031
|
-
#imageCharacters = 0;
|
|
24032
24251
|
#truncated = false;
|
|
24033
24252
|
record = (update) => {
|
|
24034
24253
|
if (update.sessionUpdate !== "user_message_chunk" && update.sessionUpdate !== "agent_message_chunk") {
|
|
@@ -24039,40 +24258,30 @@ var AcpHistoryReplay = class {
|
|
|
24039
24258
|
}
|
|
24040
24259
|
const role = update.sessionUpdate === "user_message_chunk" ? "user" : "assistant";
|
|
24041
24260
|
const content = update.content;
|
|
24042
|
-
const
|
|
24043
|
-
|
|
24044
|
-
);
|
|
24045
|
-
const text = parsed.text;
|
|
24046
|
-
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) {
|
|
24047
24263
|
return;
|
|
24048
24264
|
}
|
|
24049
24265
|
const previous = this.#messages.at(-1);
|
|
24050
24266
|
const id = update.messageId ?? null;
|
|
24051
24267
|
const continuation = previous?.role === role && id === this.#lastMessageId;
|
|
24052
24268
|
const combined = continuation ? `${previous.text}${text}` : text;
|
|
24053
|
-
const allImages = continuation ? [...previous.images ?? [], ...parsed.images] : parsed.images;
|
|
24054
|
-
const images = allImages.slice(0, 8);
|
|
24055
|
-
this.#truncated ||= images.length < allImages.length;
|
|
24056
24269
|
if (continuation) {
|
|
24057
24270
|
this.#messages.pop();
|
|
24058
24271
|
this.#characters -= previous.text.length;
|
|
24059
|
-
this.#imageCharacters -= (previous.images ?? []).reduce((size, image) => size + image.data.length, 0);
|
|
24060
24272
|
}
|
|
24061
24273
|
const bounded = combined.slice(-SESSION_HISTORY_CHARACTER_LIMIT);
|
|
24062
24274
|
this.#truncated ||= bounded.length < combined.length;
|
|
24063
24275
|
this.#messages.push({
|
|
24064
24276
|
role,
|
|
24065
|
-
text: bounded
|
|
24066
|
-
...images.length > 0 ? { images } : {}
|
|
24277
|
+
text: bounded
|
|
24067
24278
|
});
|
|
24068
24279
|
this.#characters += bounded.length;
|
|
24069
|
-
this.#imageCharacters += images.reduce((size, image) => size + image.data.length, 0);
|
|
24070
24280
|
this.#lastMessageId = id;
|
|
24071
|
-
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) {
|
|
24072
24282
|
const removed = this.#messages.shift();
|
|
24073
24283
|
if (removed !== void 0) {
|
|
24074
24284
|
this.#characters -= removed.text.length;
|
|
24075
|
-
this.#imageCharacters -= (removed.images ?? []).reduce((size, image) => size + image.data.length, 0);
|
|
24076
24285
|
}
|
|
24077
24286
|
this.#truncated = true;
|
|
24078
24287
|
}
|
|
@@ -24295,6 +24504,10 @@ var MAX_PRE_SESSION_UPDATES = 100;
|
|
|
24295
24504
|
var MAX_PRE_SESSION_UPDATE_BYTES = 1024 * 1024;
|
|
24296
24505
|
var SESSION_CONTROL_COMMAND_ID = "session-control";
|
|
24297
24506
|
var NullAcpSessionObserver = class {
|
|
24507
|
+
importLocalImage = (_sessionId, _image, signal) => {
|
|
24508
|
+
signal.throwIfAborted();
|
|
24509
|
+
return Promise.resolve("");
|
|
24510
|
+
};
|
|
24298
24511
|
onCommands = () => Promise.resolve();
|
|
24299
24512
|
onConfig = () => Promise.resolve();
|
|
24300
24513
|
onContent = () => Promise.resolve();
|
|
@@ -24917,11 +25130,75 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
24917
25130
|
);
|
|
24918
25131
|
await this.#updateTail;
|
|
24919
25132
|
signal.throwIfAborted();
|
|
24920
|
-
return
|
|
25133
|
+
return await embedLocalHistoryImages(
|
|
25134
|
+
history.snapshot(),
|
|
25135
|
+
[this.#cwd, ...this.#additionalDirectories],
|
|
25136
|
+
signal
|
|
25137
|
+
);
|
|
24921
25138
|
} finally {
|
|
24922
25139
|
this.#replay = { kind: "idle" };
|
|
24923
25140
|
}
|
|
24924
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
|
+
};
|
|
24925
25202
|
async #initializeAgent(signal) {
|
|
24926
25203
|
const initialized = await this.race(
|
|
24927
25204
|
this.#connection.agent.request(
|
|
@@ -25624,18 +25901,14 @@ var AcpProcessSession = class _AcpProcessSession {
|
|
|
25624
25901
|
);
|
|
25625
25902
|
} else {
|
|
25626
25903
|
await this.#turn.activities.finishNarrative();
|
|
25627
|
-
await this
|
|
25904
|
+
await this.emitAgentText(update.content.text, truncate3(update.messageId ?? "", 255));
|
|
25628
25905
|
}
|
|
25629
25906
|
} else {
|
|
25630
25907
|
await this.#turn.activities.finishNarrative();
|
|
25631
|
-
await this
|
|
25632
|
-
|
|
25633
|
-
|
|
25634
|
-
|
|
25635
|
-
kind: AGENT_CONTENT_KIND,
|
|
25636
|
-
messageId: truncate3(update.messageId ?? "", 255),
|
|
25637
|
-
sessionId: this.#mobiusSessionId
|
|
25638
|
-
});
|
|
25908
|
+
await this.emitAgentContent(
|
|
25909
|
+
normalizeContentBlock(update.content),
|
|
25910
|
+
truncate3(update.messageId ?? "", 255)
|
|
25911
|
+
);
|
|
25639
25912
|
}
|
|
25640
25913
|
return;
|
|
25641
25914
|
}
|
|
@@ -26996,6 +27269,402 @@ var FixedInstallationExecutor = class {
|
|
|
26996
27269
|
};
|
|
26997
27270
|
};
|
|
26998
27271
|
|
|
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 = {}) {
|
|
27279
|
+
super(message, options);
|
|
27280
|
+
this.code = code;
|
|
27281
|
+
this.name = "MobiusError";
|
|
27282
|
+
}
|
|
27283
|
+
};
|
|
27284
|
+
var MobiusProtocolError = class extends MobiusError {
|
|
27285
|
+
constructor(message, options = {}) {
|
|
27286
|
+
super("invalid_service_response", message, options);
|
|
27287
|
+
this.name = "MobiusProtocolError";
|
|
27288
|
+
}
|
|
27289
|
+
};
|
|
27290
|
+
var MobiusValidationError = class extends MobiusError {
|
|
27291
|
+
constructor(message, options = {}) {
|
|
27292
|
+
super("invalid_request", message, options);
|
|
27293
|
+
this.name = "MobiusValidationError";
|
|
27294
|
+
}
|
|
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);
|
|
27301
|
+
}
|
|
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}`);
|
|
27308
|
+
}
|
|
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}`);
|
|
27315
|
+
}
|
|
27316
|
+
return candidate;
|
|
27317
|
+
}
|
|
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}`);
|
|
27322
|
+
}
|
|
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");
|
|
27346
|
+
}
|
|
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
|
+
|
|
26999
27668
|
// src/authorization/local-authorization-error.ts
|
|
27000
27669
|
var LocalAuthorizationError = class extends Error {
|
|
27001
27670
|
code = "local_authorization_failed";
|
|
@@ -27006,9 +27675,9 @@ var LocalAuthorizationError = class extends Error {
|
|
|
27006
27675
|
};
|
|
27007
27676
|
|
|
27008
27677
|
// src/authorization/workspace-directory.ts
|
|
27009
|
-
import { readdir, realpath as
|
|
27678
|
+
import { readdir, realpath as realpath7, stat as stat6 } from "node:fs/promises";
|
|
27010
27679
|
import { homedir as homedir2 } from "node:os";
|
|
27011
|
-
import { basename, dirname as dirname5, isAbsolute as
|
|
27680
|
+
import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute8, join as join14, normalize as normalize3, relative as relative5 } from "node:path";
|
|
27012
27681
|
var WorkspaceDirectoryListing = class {
|
|
27013
27682
|
directoryId;
|
|
27014
27683
|
directoryLabel;
|
|
@@ -27034,7 +27703,7 @@ function decodePath(value, prefix) {
|
|
|
27034
27703
|
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
27035
27704
|
}
|
|
27036
27705
|
const decoded = Buffer.from(encoded, "base64url").toString("utf8");
|
|
27037
|
-
if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") ||
|
|
27706
|
+
if (Buffer.from(decoded, "utf8").toString("base64url") !== encoded || decoded.includes("\0") || normalize3(decoded) !== decoded) {
|
|
27038
27707
|
throw new LocalAuthorizationError("The directory identifier is invalid");
|
|
27039
27708
|
}
|
|
27040
27709
|
return decoded;
|
|
@@ -27060,7 +27729,7 @@ var WorkspaceDirectoryService = class {
|
|
|
27060
27729
|
}
|
|
27061
27730
|
if (id.startsWith("path-")) {
|
|
27062
27731
|
const path2 = decodePath(id, "path-");
|
|
27063
|
-
if (
|
|
27732
|
+
if (isAbsolute8(path2)) {
|
|
27064
27733
|
return path2;
|
|
27065
27734
|
}
|
|
27066
27735
|
}
|
|
@@ -27068,15 +27737,15 @@ var WorkspaceDirectoryService = class {
|
|
|
27068
27737
|
};
|
|
27069
27738
|
resolvePath = async (requested, signal) => {
|
|
27070
27739
|
signal.throwIfAborted();
|
|
27071
|
-
if (!
|
|
27740
|
+
if (!isAbsolute8(requested) || requested.includes("\0") || normalize3(requested) !== requested) {
|
|
27072
27741
|
throw new LocalAuthorizationError("The local directory path is invalid");
|
|
27073
27742
|
}
|
|
27074
27743
|
try {
|
|
27075
|
-
const target = await
|
|
27744
|
+
const target = await realpath7(requested);
|
|
27076
27745
|
signal.throwIfAborted();
|
|
27077
|
-
const metadata = await
|
|
27746
|
+
const metadata = await stat6(target);
|
|
27078
27747
|
signal.throwIfAborted();
|
|
27079
|
-
if (!
|
|
27748
|
+
if (!isAbsolute8(target) || normalize3(target) !== target || !metadata.isDirectory()) {
|
|
27080
27749
|
throw new LocalAuthorizationError("The selected location is not a directory");
|
|
27081
27750
|
}
|
|
27082
27751
|
return target;
|
|
@@ -27091,8 +27760,8 @@ var WorkspaceDirectoryService = class {
|
|
|
27091
27760
|
}
|
|
27092
27761
|
};
|
|
27093
27762
|
label = (path2) => {
|
|
27094
|
-
const suffix =
|
|
27095
|
-
return suffix === "" ? "~" : !
|
|
27763
|
+
const suffix = relative5(homedir2(), path2);
|
|
27764
|
+
return suffix === "" ? "~" : !isAbsolute8(suffix) && suffix !== ".." && !suffix.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) ? `~/${suffix.replaceAll("\\", "/")}` : path2;
|
|
27096
27765
|
};
|
|
27097
27766
|
identify = async (bindingId, requestedPath, signal) => {
|
|
27098
27767
|
this.authorizeMachine(bindingId);
|
|
@@ -27100,7 +27769,7 @@ var WorkspaceDirectoryService = class {
|
|
|
27100
27769
|
return {
|
|
27101
27770
|
path: path2,
|
|
27102
27771
|
directoryId: encodePath(path2),
|
|
27103
|
-
name:
|
|
27772
|
+
name: basename2(path2) || path2,
|
|
27104
27773
|
label: this.label(path2)
|
|
27105
27774
|
};
|
|
27106
27775
|
};
|
|
@@ -27157,8 +27826,8 @@ var WorkspaceDirectoryService = class {
|
|
|
27157
27826
|
};
|
|
27158
27827
|
|
|
27159
27828
|
// src/bots/local-bot-grant-store.ts
|
|
27160
|
-
import { createHash as
|
|
27161
|
-
import { stat as
|
|
27829
|
+
import { createHash as createHash3, randomUUID } from "node:crypto";
|
|
27830
|
+
import { stat as stat7 } from "node:fs/promises";
|
|
27162
27831
|
import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
|
|
27163
27832
|
var LOCAL_BOT_GRANT_LIFETIME_MILLISECONDS = 90 * 24 * 60 * 60 * 1e3;
|
|
27164
27833
|
var LocalBotAuthorizationError = class extends Error {
|
|
@@ -27202,7 +27871,7 @@ var LocalBotGrant = class {
|
|
|
27202
27871
|
}
|
|
27203
27872
|
};
|
|
27204
27873
|
function digest(value) {
|
|
27205
|
-
return
|
|
27874
|
+
return createHash3("sha256").update(value, "utf8").digest("hex");
|
|
27206
27875
|
}
|
|
27207
27876
|
function agentDigest(agent) {
|
|
27208
27877
|
return digest(
|
|
@@ -27216,7 +27885,7 @@ function agentDigest(agent) {
|
|
|
27216
27885
|
);
|
|
27217
27886
|
}
|
|
27218
27887
|
async function workspaceDigest(path2) {
|
|
27219
|
-
const metadata = await
|
|
27888
|
+
const metadata = await stat7(path2);
|
|
27220
27889
|
if (!metadata.isDirectory()) {
|
|
27221
27890
|
throw new LocalBotAuthorizationError("binding_incompatible", "The Bot workspace is not a directory");
|
|
27222
27891
|
}
|
|
@@ -27633,12 +28302,12 @@ var BotExecutionContextRegistry = class {
|
|
|
27633
28302
|
// src/bots/bot-outbound-ipc.ts
|
|
27634
28303
|
import { chmod as chmod2, mkdir as mkdir3, unlink } from "node:fs/promises";
|
|
27635
28304
|
import { createServer } from "node:net";
|
|
27636
|
-
import { dirname as dirname6, isAbsolute as
|
|
27637
|
-
import { fetch as
|
|
28305
|
+
import { dirname as dirname6, isAbsolute as isAbsolute9 } from "node:path";
|
|
28306
|
+
import { fetch as fetch4 } from "undici";
|
|
27638
28307
|
var BOT_IPC_REQUEST_LIMIT = 32 * 1024;
|
|
27639
28308
|
var BOT_IPC_TIMEOUT_MILLISECONDS = 2e4;
|
|
27640
28309
|
var BOT_RELAY_TIMEOUT_MILLISECONDS = 2e4;
|
|
27641
|
-
var
|
|
28310
|
+
var IDENTIFIER_PATTERN6 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
27642
28311
|
var WINDOWS_NAMED_PIPE_PREFIX = "\\\\.\\pipe\\";
|
|
27643
28312
|
var BotOutboundIpcRequest = class {
|
|
27644
28313
|
contextHandle;
|
|
@@ -27652,7 +28321,7 @@ var BotOutboundIpcRequest = class {
|
|
|
27652
28321
|
this.text = text;
|
|
27653
28322
|
}
|
|
27654
28323
|
};
|
|
27655
|
-
function
|
|
28324
|
+
function isRecord10(value) {
|
|
27656
28325
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
27657
28326
|
}
|
|
27658
28327
|
function decodeRequest(encoded) {
|
|
@@ -27662,7 +28331,7 @@ function decodeRequest(encoded) {
|
|
|
27662
28331
|
} catch (cause) {
|
|
27663
28332
|
throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid", { cause });
|
|
27664
28333
|
}
|
|
27665
|
-
if (!
|
|
28334
|
+
if (!isRecord10(value)) {
|
|
27666
28335
|
throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
|
|
27667
28336
|
}
|
|
27668
28337
|
const keys = Object.keys(value);
|
|
@@ -27673,7 +28342,7 @@ function decodeRequest(encoded) {
|
|
|
27673
28342
|
const idempotencyKey = value["idempotencyKey"];
|
|
27674
28343
|
const target = value["target"];
|
|
27675
28344
|
const text = value["text"];
|
|
27676
|
-
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) {
|
|
27677
28346
|
throw new LocalBotAuthorizationError("invalid_request", "The local Bot request is invalid");
|
|
27678
28347
|
}
|
|
27679
28348
|
return new BotOutboundIpcRequest(contextHandle, idempotencyKey, target, text);
|
|
@@ -27695,7 +28364,7 @@ function relayEndpoint(relayUrl, context, target) {
|
|
|
27695
28364
|
endpoint.pathname = `${MOBIUS_API_PREFIX}/v1/bot-executions/${execution}/delivery-targets/${encodeURIComponent(deliveryTargetId)}/messages`;
|
|
27696
28365
|
return endpoint;
|
|
27697
28366
|
}
|
|
27698
|
-
function
|
|
28367
|
+
function daemonToken2(relayUrl) {
|
|
27699
28368
|
const token = relayUrl.searchParams.get("token") ?? "";
|
|
27700
28369
|
if (!/^[a-zA-Z0-9_-]{32,256}$/.test(token)) {
|
|
27701
28370
|
throw new LocalBotAuthorizationError("bot_service_unavailable", "The Runtime credential is unavailable");
|
|
@@ -27712,10 +28381,10 @@ async function decodeRelayResponse(response) {
|
|
|
27712
28381
|
cause
|
|
27713
28382
|
});
|
|
27714
28383
|
}
|
|
27715
|
-
if (response.status === 202 &&
|
|
28384
|
+
if (response.status === 202 && isRecord10(value) && typeof value["outboundMessageId"] === "string") {
|
|
27716
28385
|
return value["outboundMessageId"];
|
|
27717
28386
|
}
|
|
27718
|
-
if (
|
|
28387
|
+
if (isRecord10(value) && isRecord10(value["error"])) {
|
|
27719
28388
|
const error61 = value["error"];
|
|
27720
28389
|
if (typeof error61["code"] === "string" && typeof error61["message"] === "string") {
|
|
27721
28390
|
throw new LocalBotAuthorizationError(error61["code"], error61["message"]);
|
|
@@ -27731,7 +28400,7 @@ var BotOutboundIpcServer = class {
|
|
|
27731
28400
|
#usesFilesystemSocket;
|
|
27732
28401
|
constructor(socketPath, relayUrl, registry2) {
|
|
27733
28402
|
const usesFilesystemSocket = !socketPath.startsWith(WINDOWS_NAMED_PIPE_PREFIX);
|
|
27734
|
-
if (usesFilesystemSocket && !
|
|
28403
|
+
if (usesFilesystemSocket && !isAbsolute9(socketPath)) {
|
|
27735
28404
|
throw new Error("The Bot IPC path must be absolute");
|
|
27736
28405
|
}
|
|
27737
28406
|
this.#registry = registry2;
|
|
@@ -27748,7 +28417,7 @@ var BotOutboundIpcServer = class {
|
|
|
27748
28417
|
if (this.#usesFilesystemSocket) {
|
|
27749
28418
|
await mkdir3(dirname6(this.#socketPath), { mode: 448, recursive: true });
|
|
27750
28419
|
await unlink(this.#socketPath).catch((error61) => {
|
|
27751
|
-
if (!
|
|
28420
|
+
if (!isRecord10(error61) || error61["code"] !== "ENOENT") {
|
|
27752
28421
|
throw error61;
|
|
27753
28422
|
}
|
|
27754
28423
|
});
|
|
@@ -27783,7 +28452,7 @@ var BotOutboundIpcServer = class {
|
|
|
27783
28452
|
}
|
|
27784
28453
|
if (this.#usesFilesystemSocket) {
|
|
27785
28454
|
await unlink(this.#socketPath).catch((error61) => {
|
|
27786
|
-
if (!
|
|
28455
|
+
if (!isRecord10(error61) || error61["code"] !== "ENOENT") {
|
|
27787
28456
|
throw error61;
|
|
27788
28457
|
}
|
|
27789
28458
|
});
|
|
@@ -27847,10 +28516,10 @@ var BotOutboundIpcServer = class {
|
|
|
27847
28516
|
const requestSignal = AbortSignal.any([signal, timeout]);
|
|
27848
28517
|
let response;
|
|
27849
28518
|
try {
|
|
27850
|
-
response = await
|
|
28519
|
+
response = await fetch4(relayEndpoint(this.#relayUrl, context, request.target), {
|
|
27851
28520
|
body: JSON.stringify({ idempotencyKey: request.idempotencyKey, text: request.text }),
|
|
27852
28521
|
headers: {
|
|
27853
|
-
authorization: `Bearer ${
|
|
28522
|
+
authorization: `Bearer ${daemonToken2(this.#relayUrl)}`,
|
|
27854
28523
|
"content-type": "application/json",
|
|
27855
28524
|
"x-mobius-bot-execution-capability": context.command.executionCapabilitySecret
|
|
27856
28525
|
},
|
|
@@ -27871,7 +28540,7 @@ var BotOutboundIpcServer = class {
|
|
|
27871
28540
|
|
|
27872
28541
|
// src/native-sessions/service.ts
|
|
27873
28542
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
27874
|
-
import { basename as
|
|
28543
|
+
import { basename as basename3 } from "node:path";
|
|
27875
28544
|
|
|
27876
28545
|
// src/native-sessions/codex-history.ts
|
|
27877
28546
|
import { spawn as spawn4 } from "node:child_process";
|
|
@@ -27904,7 +28573,6 @@ function decodeHistory(thread, value) {
|
|
|
27904
28573
|
const page = turnsSchema.parse(value);
|
|
27905
28574
|
const messages = [];
|
|
27906
28575
|
let characters = 0;
|
|
27907
|
-
let imageCharacters = 0;
|
|
27908
28576
|
let truncated = page.nextCursor != null;
|
|
27909
28577
|
for (const turn of page.data.toReversed()) {
|
|
27910
28578
|
for (const item of turn.items) {
|
|
@@ -27912,22 +28580,19 @@ function decodeHistory(thread, value) {
|
|
|
27912
28580
|
let message;
|
|
27913
28581
|
if (type === "userMessage") {
|
|
27914
28582
|
const { content } = userMessageSchema.parse(item);
|
|
27915
|
-
const
|
|
27916
|
-
|
|
27917
|
-
|
|
27918
|
-
|
|
27919
|
-
|
|
27920
|
-
|
|
27921
|
-
|
|
27922
|
-
|
|
27923
|
-
|
|
27924
|
-
|
|
27925
|
-
}).join("")
|
|
27926
|
-
);
|
|
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("");
|
|
27927
28593
|
message = {
|
|
27928
28594
|
role: "user",
|
|
27929
|
-
text:
|
|
27930
|
-
...parsed.images.length > 0 ? { images: parsed.images } : {}
|
|
28595
|
+
text: text2
|
|
27931
28596
|
};
|
|
27932
28597
|
} else if (type === "agentMessage") {
|
|
27933
28598
|
const agent = agentMessageSchema.parse(item);
|
|
@@ -27945,12 +28610,10 @@ function decodeHistory(thread, value) {
|
|
|
27945
28610
|
truncated ||= text.length < message.text.length;
|
|
27946
28611
|
messages.push({ ...message, text });
|
|
27947
28612
|
characters += text.length;
|
|
27948
|
-
|
|
27949
|
-
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) {
|
|
27950
28614
|
const removed = messages.shift();
|
|
27951
28615
|
if (removed !== void 0) {
|
|
27952
28616
|
characters -= removed.text.length;
|
|
27953
|
-
imageCharacters -= (removed.images ?? []).reduce((size, image) => size + image.data.length, 0);
|
|
27954
28617
|
}
|
|
27955
28618
|
truncated = true;
|
|
27956
28619
|
}
|
|
@@ -28108,7 +28771,11 @@ async function readCodexHistory(agent, cwd, nativeSessionId, signal) {
|
|
|
28108
28771
|
params: { clientInfo: { name: "mobius_history", version: "1.0.0" } }
|
|
28109
28772
|
});
|
|
28110
28773
|
}
|
|
28111
|
-
|
|
28774
|
+
const snapshot = await response.promise;
|
|
28775
|
+
return {
|
|
28776
|
+
...snapshot,
|
|
28777
|
+
history: await embedLocalHistoryImages(snapshot.history, [cwd, snapshot.cwd], signal)
|
|
28778
|
+
};
|
|
28112
28779
|
} finally {
|
|
28113
28780
|
clearTimeout(timeout);
|
|
28114
28781
|
signal.removeEventListener("abort", abort);
|
|
@@ -28362,7 +29029,7 @@ var NativeSessionService = class {
|
|
|
28362
29029
|
}
|
|
28363
29030
|
resolvedPaths.add(path2);
|
|
28364
29031
|
additionalDirectories.push(path2);
|
|
28365
|
-
additionalEntries.push({ directoryId: directoryId2, name:
|
|
29032
|
+
additionalEntries.push({ directoryId: directoryId2, name: basename3(path2) });
|
|
28366
29033
|
}
|
|
28367
29034
|
const listing = await this.#directories.list(this.#config.bindingId, command.directoryId, signal);
|
|
28368
29035
|
const opened = await this.#sessions.forkSessionAtTurn(
|
|
@@ -28501,13 +29168,13 @@ var NativeSessionService = class {
|
|
|
28501
29168
|
};
|
|
28502
29169
|
|
|
28503
29170
|
// src/prompt-artifact-resolver.ts
|
|
28504
|
-
import { createHash as
|
|
28505
|
-
import { fetch as
|
|
29171
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
29172
|
+
import { fetch as fetch5 } from "undici";
|
|
28506
29173
|
var ARTIFACT_SCHEME = "mobius-artifact:";
|
|
28507
29174
|
var ARTIFACT_DOWNLOAD_TIMEOUT_MILLISECONDS = 2e4;
|
|
28508
29175
|
var MAX_AGENT_IMAGE_BASE64_LENGTH = 4e6;
|
|
28509
29176
|
var MAX_AGENT_RESOURCE_BYTE_LENGTH = 1e6;
|
|
28510
|
-
var
|
|
29177
|
+
var IDENTIFIER_PATTERN7 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
28511
29178
|
var PromptArtifactError = class extends Error {
|
|
28512
29179
|
code;
|
|
28513
29180
|
constructor(code, message, options = {}) {
|
|
@@ -28550,7 +29217,7 @@ function parseReference(resource) {
|
|
|
28550
29217
|
const encodedByteLength2 = url2.searchParams.get("byteLength") ?? "";
|
|
28551
29218
|
const sha256 = url2.searchParams.get("sha256") ?? "";
|
|
28552
29219
|
const byteLength = Number(encodedByteLength2);
|
|
28553
|
-
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)) {
|
|
28554
29221
|
throw new PromptArtifactError("artifact_reference_invalid", "The prompt artifact reference is invalid");
|
|
28555
29222
|
}
|
|
28556
29223
|
return new PromptArtifactReference(artifactId, byteLength, sha256, resource);
|
|
@@ -28616,7 +29283,7 @@ async function download(config2, command, reference, signal) {
|
|
|
28616
29283
|
const requestSignal = AbortSignal.any([signal, timeoutSignal]);
|
|
28617
29284
|
let response;
|
|
28618
29285
|
try {
|
|
28619
|
-
response = await
|
|
29286
|
+
response = await fetch5(downloadUrl(config2, command, reference), {
|
|
28620
29287
|
dispatcher: environmentProxyDispatcher,
|
|
28621
29288
|
headers: {
|
|
28622
29289
|
accept: reference.resource.mimeType,
|
|
@@ -28640,7 +29307,7 @@ async function download(config2, command, reference, signal) {
|
|
|
28640
29307
|
);
|
|
28641
29308
|
}
|
|
28642
29309
|
const bytes = await responseBytes(response, reference.byteLength, requestSignal);
|
|
28643
|
-
if (
|
|
29310
|
+
if (createHash4("sha256").update(bytes).digest("hex") !== reference.sha256) {
|
|
28644
29311
|
throw new PromptArtifactError(
|
|
28645
29312
|
"artifact_integrity_failed",
|
|
28646
29313
|
"The prompt artifact failed integrity validation"
|
|
@@ -29676,10 +30343,23 @@ function botIpcSocketPath() {
|
|
|
29676
30343
|
return join15("/tmp", `mobius-bot-${randomUUID4()}.sock`);
|
|
29677
30344
|
}
|
|
29678
30345
|
var DaemonAcpObserver = class {
|
|
30346
|
+
#config;
|
|
29679
30347
|
#record;
|
|
29680
|
-
constructor(
|
|
29681
|
-
this.#
|
|
30348
|
+
constructor(config2, record3) {
|
|
30349
|
+
this.#config = config2;
|
|
30350
|
+
this.#record = record3;
|
|
29682
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
|
+
};
|
|
29683
30363
|
onCommands = (event) => {
|
|
29684
30364
|
this.#record(event.sessionId, encodeSessionCommandsUpdatedEvent(event));
|
|
29685
30365
|
return Promise.resolve();
|
|
@@ -29889,7 +30569,7 @@ async function reconcileActiveTurn(config2, turn, signal) {
|
|
|
29889
30569
|
const requestSignal = AbortSignal.any([signal, timeoutSignal]);
|
|
29890
30570
|
let response;
|
|
29891
30571
|
try {
|
|
29892
|
-
response = await
|
|
30572
|
+
response = await fetch6(activeTurnReconciliationEndpoint(config2, turn), {
|
|
29893
30573
|
body: JSON.stringify({ outcome: { kind: "running" } }),
|
|
29894
30574
|
dispatcher: environmentProxyDispatcher,
|
|
29895
30575
|
headers: { ...runtimeAuthorization(config2.relayUrl), "content-type": "application/json" },
|
|
@@ -30205,7 +30885,7 @@ async function resolveSessionDirectories(directories, bindingId, directoryId2, a
|
|
|
30205
30885
|
additionalDirectories.push(directory);
|
|
30206
30886
|
additionalDirectoryEntries.push({
|
|
30207
30887
|
directoryId: additionalDirectoryId,
|
|
30208
|
-
name:
|
|
30888
|
+
name: basename4(directory)
|
|
30209
30889
|
});
|
|
30210
30890
|
}
|
|
30211
30891
|
return new ResolvedSessionDirectories(cwd, additionalDirectories, additionalDirectoryEntries);
|
|
@@ -30716,8 +31396,7 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30716
31396
|
rejectConnection(failure);
|
|
30717
31397
|
};
|
|
30718
31398
|
const processingDeliveryIds = /* @__PURE__ */ new Set();
|
|
30719
|
-
const processDeliveredPrompt = async (delivery) => {
|
|
30720
|
-
const command = decodeSessionPromptCommand(delivery.payload);
|
|
31399
|
+
const processDeliveredPrompt = async (delivery, command, trackActiveAttempt, execute) => {
|
|
30721
31400
|
if (command.sessionId !== delivery.sessionId) {
|
|
30722
31401
|
throw new Error("Runtime delivery Session identity does not match its payload");
|
|
30723
31402
|
}
|
|
@@ -30745,22 +31424,11 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30745
31424
|
}
|
|
30746
31425
|
const turn = new ActiveDaemonTurn(command, receipt.attemptId);
|
|
30747
31426
|
activeTurns.set(command.commandId, turn);
|
|
30748
|
-
if (
|
|
31427
|
+
if (trackActiveAttempt) {
|
|
30749
31428
|
activeAttemptIds.set(command.sessionId, receipt.attemptId);
|
|
30750
31429
|
}
|
|
30751
31430
|
try {
|
|
30752
|
-
await
|
|
30753
|
-
outbox,
|
|
30754
|
-
publisher,
|
|
30755
|
-
command,
|
|
30756
|
-
config2,
|
|
30757
|
-
directories,
|
|
30758
|
-
audit,
|
|
30759
|
-
sessions,
|
|
30760
|
-
receipt.attemptId,
|
|
30761
|
-
timer,
|
|
30762
|
-
turn.signal
|
|
30763
|
-
);
|
|
31431
|
+
await execute(receipt.attemptId, turn.signal);
|
|
30764
31432
|
} finally {
|
|
30765
31433
|
activeTurns.delete(command.commandId);
|
|
30766
31434
|
if (activeAttemptIds.get(command.sessionId) === receipt.attemptId) {
|
|
@@ -30839,8 +31507,50 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30839
31507
|
}
|
|
30840
31508
|
return;
|
|
30841
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
|
+
}
|
|
30842
31535
|
if (kind === SESSION_PROMPT_KIND) {
|
|
30843
|
-
|
|
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
|
+
);
|
|
30844
31554
|
return;
|
|
30845
31555
|
}
|
|
30846
31556
|
throw new Error("Runtime delivery contains an unsupported protocol message");
|
|
@@ -30878,6 +31588,8 @@ async function runRelayConnection(config2, directories, audit, sessions, install
|
|
|
30878
31588
|
payloadSessionId = decodeSessionElicitationRespondCommand(delivery.payload).sessionId;
|
|
30879
31589
|
} else if (payloadKind === SESSION_PROMPT_KIND) {
|
|
30880
31590
|
payloadSessionId = decodeSessionPromptCommand(delivery.payload).sessionId;
|
|
31591
|
+
} else if (payloadKind === BOT_SESSION_PROMPT_KIND) {
|
|
31592
|
+
payloadSessionId = decodeBotSessionPromptCommand(delivery.payload).sessionId;
|
|
30881
31593
|
} else {
|
|
30882
31594
|
throw new Error("Runtime delivery contains an unsupported protocol message");
|
|
30883
31595
|
}
|
|
@@ -31475,7 +32187,7 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31475
32187
|
}
|
|
31476
32188
|
publisher.recordAttempt(sessionId, payload, attemptId);
|
|
31477
32189
|
};
|
|
31478
|
-
const sessions = new AcpSessionManager(new DaemonAcpObserver(recordSessionEvent), sessionStore);
|
|
32190
|
+
const sessions = new AcpSessionManager(new DaemonAcpObserver(config2, recordSessionEvent), sessionStore);
|
|
31479
32191
|
const directories = new WorkspaceDirectoryService(config2.bindingId, config2.defaultWorkspace);
|
|
31480
32192
|
const installationObserver = new DaemonInstallationObserver();
|
|
31481
32193
|
const diagnostics = new RelayConnectionDiagnostics(audit, config2.channelId, config2.relayUrl);
|
|
@@ -31574,13 +32286,13 @@ async function runDaemon(config2, audit, signal, timer = systemDaemonTimer) {
|
|
|
31574
32286
|
|
|
31575
32287
|
// src/pairing/pair-local-machine.ts
|
|
31576
32288
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
31577
|
-
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";
|
|
31578
32290
|
import { hostname as hostname3 } from "node:os";
|
|
31579
|
-
import { basename as
|
|
31580
|
-
import { fetch as
|
|
32291
|
+
import { basename as basename5, join as join16, resolve as resolve4 } from "node:path";
|
|
32292
|
+
import { fetch as fetch7 } from "undici";
|
|
31581
32293
|
var PAIRING_TIMEOUT_MILLISECONDS = 2e4;
|
|
31582
32294
|
var PAIRING_CODE_PATTERN = /^[A-HJ-NP-Z2-9]{4}(?:-[A-HJ-NP-Z2-9]{4}){4}$/;
|
|
31583
|
-
var
|
|
32295
|
+
var IDENTIFIER_PATTERN8 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
31584
32296
|
var TOKEN_PATTERN2 = /^[a-zA-Z0-9_-]{32,256}$/;
|
|
31585
32297
|
var MAX_CONNECTION_FILE_LENGTH = 16 * 1024;
|
|
31586
32298
|
var CLAIM_RESPONSE_KEYS = ["channelId", "daemonToken", "runtimeId"];
|
|
@@ -31595,7 +32307,7 @@ var PairingClientError = class extends Error {
|
|
|
31595
32307
|
this.name = "PairingClientError";
|
|
31596
32308
|
}
|
|
31597
32309
|
};
|
|
31598
|
-
function
|
|
32310
|
+
function isRecord11(value) {
|
|
31599
32311
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31600
32312
|
}
|
|
31601
32313
|
function hasExactKeys(value, expectedKeys) {
|
|
@@ -31634,7 +32346,7 @@ function parsePairingCode(value) {
|
|
|
31634
32346
|
return code;
|
|
31635
32347
|
}
|
|
31636
32348
|
function validatePairingId(value) {
|
|
31637
|
-
if (!
|
|
32349
|
+
if (!IDENTIFIER_PATTERN8.test(value)) {
|
|
31638
32350
|
throw new PairingClientError("invalid_pairing_id", "The Runtime pairing ID is invalid");
|
|
31639
32351
|
}
|
|
31640
32352
|
return value;
|
|
@@ -31643,8 +32355,8 @@ async function resolveDefaultWorkspace2(path2) {
|
|
|
31643
32355
|
const requestedWorkspace = resolve4(path2);
|
|
31644
32356
|
try {
|
|
31645
32357
|
await mkdir4(requestedWorkspace, { recursive: true, mode: 448 });
|
|
31646
|
-
const defaultWorkspace = await
|
|
31647
|
-
const metadata = await
|
|
32358
|
+
const defaultWorkspace = await realpath8(requestedWorkspace);
|
|
32359
|
+
const metadata = await stat8(defaultWorkspace);
|
|
31648
32360
|
if (!metadata.isDirectory()) {
|
|
31649
32361
|
throw new PairingClientError("invalid_workspace", "The default workspace is not a directory");
|
|
31650
32362
|
}
|
|
@@ -31673,9 +32385,9 @@ async function readJsonResponse(response) {
|
|
|
31673
32385
|
}
|
|
31674
32386
|
}
|
|
31675
32387
|
function readRelayError(value) {
|
|
31676
|
-
if (
|
|
32388
|
+
if (isRecord11(value)) {
|
|
31677
32389
|
const error61 = value["error"];
|
|
31678
|
-
if (
|
|
32390
|
+
if (isRecord11(error61)) {
|
|
31679
32391
|
const code = error61["code"];
|
|
31680
32392
|
const message = error61["message"];
|
|
31681
32393
|
if (typeof code === "string" && typeof message === "string") {
|
|
@@ -31686,13 +32398,13 @@ function readRelayError(value) {
|
|
|
31686
32398
|
return new PairingClientError("pairing_failed", "The relay could not pair this machine");
|
|
31687
32399
|
}
|
|
31688
32400
|
function decodePairingResponse(value, credentialField, expectedKeys) {
|
|
31689
|
-
if (!
|
|
32401
|
+
if (!isRecord11(value) || !hasExactKeys(value, expectedKeys)) {
|
|
31690
32402
|
throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
|
|
31691
32403
|
}
|
|
31692
32404
|
const channelId = value["channelId"];
|
|
31693
32405
|
const runtimeCredential2 = value[credentialField];
|
|
31694
32406
|
const runtimeId = value["runtimeId"];
|
|
31695
|
-
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)) {
|
|
31696
32408
|
throw new PairingClientError("invalid_relay_response", "The relay returned an invalid pairing response");
|
|
31697
32409
|
}
|
|
31698
32410
|
return { channelId, runtimeCredential: runtimeCredential2, runtimeId };
|
|
@@ -31708,13 +32420,13 @@ async function claimPairing(options, defaultWorkspace, localAgents, installableA
|
|
|
31708
32420
|
const endpoint = options.pairingId.length > 0 ? mobiusApiUrl(options.relayOrigin, `/v1/runtime-pairings/${encodeURIComponent(options.pairingId)}/redeem`) : mobiusApiUrl(options.relayOrigin, "/pairings/claim");
|
|
31709
32421
|
let response;
|
|
31710
32422
|
try {
|
|
31711
|
-
response = await
|
|
32423
|
+
response = await fetch7(endpoint, {
|
|
31712
32424
|
body: JSON.stringify({
|
|
31713
32425
|
agents,
|
|
31714
32426
|
installableAgents,
|
|
31715
32427
|
machineName: hostname3(),
|
|
31716
32428
|
pairingCode: options.code,
|
|
31717
|
-
workspaceName:
|
|
32429
|
+
workspaceName: basename5(defaultWorkspace) || "Local workspace"
|
|
31718
32430
|
}),
|
|
31719
32431
|
dispatcher: environmentProxyDispatcher,
|
|
31720
32432
|
headers: { "content-type": "application/json" },
|
|
@@ -31754,14 +32466,14 @@ async function persistConnection(channelId, relayOrigin, runtimeCredential2, def
|
|
|
31754
32466
|
return connectionPath;
|
|
31755
32467
|
}
|
|
31756
32468
|
function decodeSavedConnection(value, expectedChannelId) {
|
|
31757
|
-
if (!
|
|
32469
|
+
if (!isRecord11(value) || !hasExactKeys(value, SAVED_CONNECTION_KEYS) && !hasExactKeys(value, LEGACY_SAVED_CONNECTION_KEYS)) {
|
|
31758
32470
|
throw new PairingClientError("invalid_connection", "The saved connection is invalid");
|
|
31759
32471
|
}
|
|
31760
32472
|
const defaultWorkspace = value["defaultWorkspace"];
|
|
31761
32473
|
const channelId = value["channelId"];
|
|
31762
32474
|
const runtimeCredential2 = value["runtimeCredential"] ?? value["daemonToken"];
|
|
31763
32475
|
const relayOrigin = value["relayOrigin"];
|
|
31764
|
-
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") {
|
|
31765
32477
|
throw new PairingClientError("invalid_connection", "The saved connection is invalid");
|
|
31766
32478
|
}
|
|
31767
32479
|
return {
|
|
@@ -31880,7 +32592,7 @@ async function resumeMobiusRuntime(channelId, signal, environment = process.env)
|
|
|
31880
32592
|
// src/runtime.ts
|
|
31881
32593
|
var APP_CREDENTIAL_PATTERN = /^mapp_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
|
|
31882
32594
|
var CONVERSATION_CREDENTIAL_PATTERN = /^mconv_[a-zA-Z0-9_-]{22}_[a-zA-Z0-9_-]{43}$/;
|
|
31883
|
-
var
|
|
32595
|
+
var IDENTIFIER_PATTERN9 = /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/;
|
|
31884
32596
|
var RUNTIME_CREDENTIAL_PATTERN = /^[a-zA-Z0-9_-]{32,256}$/;
|
|
31885
32597
|
var MobiusRuntimeConfigurationError = class extends Error {
|
|
31886
32598
|
code = "runtime_configuration_invalid";
|
|
@@ -31938,7 +32650,7 @@ function relayUrlFromConnection(connection) {
|
|
|
31938
32650
|
}
|
|
31939
32651
|
function loadMobiusRuntimeConnection(environment = process.env) {
|
|
31940
32652
|
const channelId = requiredEnvironmentValue(environment, "MOBIUS_CHANNEL_ID");
|
|
31941
|
-
if (!
|
|
32653
|
+
if (!IDENTIFIER_PATTERN9.test(channelId)) {
|
|
31942
32654
|
throw new MobiusRuntimeConfigurationError("MOBIUS_CHANNEL_ID is invalid");
|
|
31943
32655
|
}
|
|
31944
32656
|
return Object.freeze({
|
|
@@ -31953,8 +32665,8 @@ async function resolveWorkspace(path2) {
|
|
|
31953
32665
|
const requested = resolve5(path2);
|
|
31954
32666
|
try {
|
|
31955
32667
|
await mkdir5(requested, { recursive: true, mode: 448 });
|
|
31956
|
-
const resolved = await
|
|
31957
|
-
const metadata = await
|
|
32668
|
+
const resolved = await realpath9(requested);
|
|
32669
|
+
const metadata = await stat9(resolved);
|
|
31958
32670
|
if (!metadata.isDirectory()) {
|
|
31959
32671
|
throw new MobiusRuntimeConfigurationError("The Runtime workspace is not a directory");
|
|
31960
32672
|
}
|