replicas-engine 0.1.312 → 0.1.314
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/src/index.js +271 -123
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -117,9 +117,9 @@ var EXT_TO_LANGUAGE = {
|
|
|
117
117
|
function detectLanguageByPath(filePath) {
|
|
118
118
|
const dot = filePath.lastIndexOf(".");
|
|
119
119
|
if (dot === -1) {
|
|
120
|
-
const
|
|
121
|
-
if (
|
|
122
|
-
if (
|
|
120
|
+
const basename2 = filePath.split("/").pop() ?? "";
|
|
121
|
+
if (basename2 === "Dockerfile") return "dockerfile";
|
|
122
|
+
if (basename2 === "Makefile") return "makefile";
|
|
123
123
|
return null;
|
|
124
124
|
}
|
|
125
125
|
const ext = filePath.slice(dot).toLowerCase();
|
|
@@ -287,7 +287,7 @@ var WORKSPACE_SIZES = ["small", "large"];
|
|
|
287
287
|
var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
|
|
288
288
|
|
|
289
289
|
// ../shared/src/e2b.ts
|
|
290
|
-
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-13-
|
|
290
|
+
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-13-v10";
|
|
291
291
|
|
|
292
292
|
// ../shared/src/runtime-env.ts
|
|
293
293
|
function parsePosixEnvFile(content) {
|
|
@@ -2076,6 +2076,35 @@ var MODEL_LABELS = {
|
|
|
2076
2076
|
"gpt-5.2": "GPT-5.2"
|
|
2077
2077
|
};
|
|
2078
2078
|
var IMAGE_MEDIA_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"];
|
|
2079
|
+
var MAX_CANVAS_FILE_BYTES = 5 * 1024 * 1024;
|
|
2080
|
+
function isCanvasTextKind(kind) {
|
|
2081
|
+
return kind === "markdown" || kind === "html";
|
|
2082
|
+
}
|
|
2083
|
+
function sanitizeCanvasFilename(filename) {
|
|
2084
|
+
const safe = filename.split(/[\\/]/).pop() ?? "";
|
|
2085
|
+
if (!safe || safe !== filename || safe.startsWith(".")) return null;
|
|
2086
|
+
return safe;
|
|
2087
|
+
}
|
|
2088
|
+
function bytesToBase64(bytes) {
|
|
2089
|
+
let binary = "";
|
|
2090
|
+
const chunkSize = 32768;
|
|
2091
|
+
for (let i = 0; i < bytes.length; i += chunkSize) {
|
|
2092
|
+
binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize));
|
|
2093
|
+
}
|
|
2094
|
+
return btoa(binary);
|
|
2095
|
+
}
|
|
2096
|
+
function serializeCanvasContentResponse(input) {
|
|
2097
|
+
const base = {
|
|
2098
|
+
filename: input.filename,
|
|
2099
|
+
kind: input.kind,
|
|
2100
|
+
sizeBytes: input.sizeBytes,
|
|
2101
|
+
mimeType: input.mimeType
|
|
2102
|
+
};
|
|
2103
|
+
if (isCanvasTextKind(input.kind)) {
|
|
2104
|
+
return { ...base, content: new TextDecoder().decode(input.bytes) };
|
|
2105
|
+
}
|
|
2106
|
+
return { ...base, base64: bytesToBase64(input.bytes) };
|
|
2107
|
+
}
|
|
2079
2108
|
var CANVAS_KIND_BY_EXTENSION = {
|
|
2080
2109
|
".md": { kind: "markdown", mimeType: "text/markdown; charset=utf-8" },
|
|
2081
2110
|
".markdown": { kind: "markdown", mimeType: "text/markdown; charset=utf-8" },
|
|
@@ -4904,9 +4933,9 @@ async function registerDesktopPreview() {
|
|
|
4904
4933
|
|
|
4905
4934
|
// src/services/chat/chat-service.ts
|
|
4906
4935
|
import { existsSync as existsSync7 } from "fs";
|
|
4907
|
-
import { appendFile as appendFile4, copyFile, mkdir as mkdir11, readFile as
|
|
4908
|
-
import { homedir as
|
|
4909
|
-
import { join as
|
|
4936
|
+
import { appendFile as appendFile4, copyFile, mkdir as mkdir11, readFile as readFile12, rename as rename2, rm } from "fs/promises";
|
|
4937
|
+
import { homedir as homedir14 } from "os";
|
|
4938
|
+
import { join as join16 } from "path";
|
|
4910
4939
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
4911
4940
|
|
|
4912
4941
|
// src/managers/claude-manager.ts
|
|
@@ -6851,7 +6880,7 @@ var AspClient = class {
|
|
|
6851
6880
|
// src/managers/codex-asp/app-server-process.ts
|
|
6852
6881
|
var DEFAULT_CODEX_BINARY = "codex";
|
|
6853
6882
|
var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
|
|
6854
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
6883
|
+
var ENGINE_PACKAGE_VERSION = "0.1.314";
|
|
6855
6884
|
var INITIALIZE_METHOD = "initialize";
|
|
6856
6885
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
6857
6886
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|
|
@@ -9154,15 +9183,190 @@ var KeepAliveService = class _KeepAliveService {
|
|
|
9154
9183
|
};
|
|
9155
9184
|
var keepAliveService = new KeepAliveService();
|
|
9156
9185
|
|
|
9157
|
-
// src/services/
|
|
9158
|
-
import { readdir as readdir3, readFile as readFile10 } from "fs/promises";
|
|
9159
|
-
import { basename, join as join14 } from "path";
|
|
9186
|
+
// src/services/canvas-service.ts
|
|
9187
|
+
import { readdir as readdir3, readFile as readFile10, stat as stat2 } from "fs/promises";
|
|
9160
9188
|
import { homedir as homedir12 } from "os";
|
|
9161
|
-
|
|
9189
|
+
import { join as join14 } from "path";
|
|
9190
|
+
var CANVAS_DIRECTORIES = [
|
|
9191
|
+
join14(homedir12(), ".claude", "plans"),
|
|
9192
|
+
join14(homedir12(), ".replicas", "canvas")
|
|
9193
|
+
];
|
|
9194
|
+
var CanvasService = class {
|
|
9195
|
+
async listItems() {
|
|
9196
|
+
const items = /* @__PURE__ */ new Map();
|
|
9197
|
+
for (const directory of CANVAS_DIRECTORIES) {
|
|
9198
|
+
let entries;
|
|
9199
|
+
try {
|
|
9200
|
+
entries = await readdir3(directory, { withFileTypes: true });
|
|
9201
|
+
} catch {
|
|
9202
|
+
continue;
|
|
9203
|
+
}
|
|
9204
|
+
for (const entry of entries) {
|
|
9205
|
+
if (!entry.isFile()) continue;
|
|
9206
|
+
if (entry.name.startsWith(".")) continue;
|
|
9207
|
+
if (items.has(entry.name)) continue;
|
|
9208
|
+
const { kind } = classifyCanvasFilename(entry.name);
|
|
9209
|
+
let sizeBytes = 0;
|
|
9210
|
+
try {
|
|
9211
|
+
const s = await stat2(join14(directory, entry.name));
|
|
9212
|
+
sizeBytes = s.size;
|
|
9213
|
+
} catch {
|
|
9214
|
+
continue;
|
|
9215
|
+
}
|
|
9216
|
+
items.set(entry.name, { filename: entry.name, kind, sizeBytes });
|
|
9217
|
+
}
|
|
9218
|
+
}
|
|
9219
|
+
return Array.from(items.values()).sort((a, b) => a.filename.localeCompare(b.filename));
|
|
9220
|
+
}
|
|
9221
|
+
async getItemFile(filename) {
|
|
9222
|
+
const safe = sanitizeCanvasFilename(filename);
|
|
9223
|
+
if (!safe) return null;
|
|
9224
|
+
const { kind, mimeType } = classifyCanvasFilename(safe);
|
|
9225
|
+
for (const directory of CANVAS_DIRECTORIES) {
|
|
9226
|
+
const filePath = join14(directory, safe);
|
|
9227
|
+
let sizeBytes = 0;
|
|
9228
|
+
let updatedAt = "";
|
|
9229
|
+
try {
|
|
9230
|
+
const s = await stat2(filePath);
|
|
9231
|
+
sizeBytes = s.size;
|
|
9232
|
+
updatedAt = s.mtime.toISOString();
|
|
9233
|
+
} catch {
|
|
9234
|
+
continue;
|
|
9235
|
+
}
|
|
9236
|
+
if (sizeBytes > MAX_CANVAS_FILE_BYTES) {
|
|
9237
|
+
return {
|
|
9238
|
+
filename: safe,
|
|
9239
|
+
kind,
|
|
9240
|
+
sizeBytes,
|
|
9241
|
+
mimeType,
|
|
9242
|
+
updatedAt,
|
|
9243
|
+
tooLarge: true
|
|
9244
|
+
};
|
|
9245
|
+
}
|
|
9246
|
+
try {
|
|
9247
|
+
const bytes = await readFile10(filePath);
|
|
9248
|
+
return { filename: safe, kind, sizeBytes, mimeType, updatedAt, bytes };
|
|
9249
|
+
} catch {
|
|
9250
|
+
continue;
|
|
9251
|
+
}
|
|
9252
|
+
}
|
|
9253
|
+
return null;
|
|
9254
|
+
}
|
|
9255
|
+
async getItem(filename) {
|
|
9256
|
+
const item = await this.getItemFile(filename);
|
|
9257
|
+
if (!item) return null;
|
|
9258
|
+
if (item.tooLarge || !item.bytes) {
|
|
9259
|
+
return {
|
|
9260
|
+
filename: item.filename,
|
|
9261
|
+
kind: item.kind,
|
|
9262
|
+
sizeBytes: item.sizeBytes,
|
|
9263
|
+
mimeType: item.mimeType,
|
|
9264
|
+
tooLarge: true
|
|
9265
|
+
};
|
|
9266
|
+
}
|
|
9267
|
+
return serializeCanvasContentResponse({
|
|
9268
|
+
filename: item.filename,
|
|
9269
|
+
kind: item.kind,
|
|
9270
|
+
sizeBytes: item.sizeBytes,
|
|
9271
|
+
mimeType: item.mimeType,
|
|
9272
|
+
bytes: item.bytes
|
|
9273
|
+
});
|
|
9274
|
+
}
|
|
9275
|
+
};
|
|
9276
|
+
var canvasService = new CanvasService();
|
|
9277
|
+
|
|
9278
|
+
// src/services/upload-canvas-items.ts
|
|
9279
|
+
var uploadedCanvasItems = /* @__PURE__ */ new Map();
|
|
9280
|
+
function isReconcileCanvasItemsResponse(value) {
|
|
9281
|
+
return typeof value === "object" && value !== null && "deleted" in value && typeof value.deleted === "number" && (!("skipped" in value) || typeof value.skipped === "string");
|
|
9282
|
+
}
|
|
9283
|
+
async function flushAllCanvasItems() {
|
|
9284
|
+
let flushed = 0;
|
|
9285
|
+
let skipped = 0;
|
|
9286
|
+
let failed = 0;
|
|
9287
|
+
let deleted = 0;
|
|
9288
|
+
const filenames = [];
|
|
9289
|
+
const items = await canvasService.listItems();
|
|
9290
|
+
await Promise.all(items.map(async (item) => {
|
|
9291
|
+
if (item.sizeBytes > MAX_CANVAS_FILE_BYTES) {
|
|
9292
|
+
skipped++;
|
|
9293
|
+
return;
|
|
9294
|
+
}
|
|
9295
|
+
try {
|
|
9296
|
+
const file = await canvasService.getItemFile(item.filename);
|
|
9297
|
+
if (!file?.bytes || file.tooLarge) {
|
|
9298
|
+
skipped++;
|
|
9299
|
+
return;
|
|
9300
|
+
}
|
|
9301
|
+
const uploaded = uploadedCanvasItems.get(file.filename);
|
|
9302
|
+
if (uploaded?.sizeBytes === file.sizeBytes && uploaded.updatedAt === file.updatedAt) {
|
|
9303
|
+
filenames.push(file.filename);
|
|
9304
|
+
skipped++;
|
|
9305
|
+
return;
|
|
9306
|
+
}
|
|
9307
|
+
await uploadCanvasItem(file);
|
|
9308
|
+
uploadedCanvasItems.set(file.filename, { sizeBytes: file.sizeBytes, updatedAt: file.updatedAt });
|
|
9309
|
+
filenames.push(file.filename);
|
|
9310
|
+
flushed++;
|
|
9311
|
+
} catch (err) {
|
|
9312
|
+
failed++;
|
|
9313
|
+
console.error("[CanvasUploader] upload failed:", { filename: item.filename, err });
|
|
9314
|
+
}
|
|
9315
|
+
}));
|
|
9316
|
+
if (failed === 0) {
|
|
9317
|
+
try {
|
|
9318
|
+
deleted = await reconcileCanvasItems(filenames);
|
|
9319
|
+
const currentFilenames = new Set(filenames);
|
|
9320
|
+
for (const filename of uploadedCanvasItems.keys()) {
|
|
9321
|
+
if (!currentFilenames.has(filename)) uploadedCanvasItems.delete(filename);
|
|
9322
|
+
}
|
|
9323
|
+
} catch (err) {
|
|
9324
|
+
failed++;
|
|
9325
|
+
console.error("[CanvasUploader] reconcile failed:", err);
|
|
9326
|
+
}
|
|
9327
|
+
}
|
|
9328
|
+
return { flushed, skipped, failed, deleted };
|
|
9329
|
+
}
|
|
9330
|
+
async function uploadCanvasItem(item) {
|
|
9331
|
+
if (!item.bytes || item.tooLarge) return;
|
|
9332
|
+
const form = new FormData();
|
|
9333
|
+
form.append("filename", item.filename);
|
|
9334
|
+
form.append("updated_at", item.updatedAt);
|
|
9335
|
+
form.append(
|
|
9336
|
+
"file",
|
|
9337
|
+
new Blob([item.bytes], { type: item.mimeType }),
|
|
9338
|
+
item.filename
|
|
9339
|
+
);
|
|
9340
|
+
const response = await monolithRequest("/v1/engine/canvas", { body: form });
|
|
9341
|
+
if (!response.ok) {
|
|
9342
|
+
const errorText = await response.text();
|
|
9343
|
+
throw new Error(`upload failed: ${response.status} ${errorText}`);
|
|
9344
|
+
}
|
|
9345
|
+
}
|
|
9346
|
+
async function reconcileCanvasItems(filenames) {
|
|
9347
|
+
const response = await monolithRequest("/v1/engine/canvas/reconcile", {
|
|
9348
|
+
body: { filenames }
|
|
9349
|
+
});
|
|
9350
|
+
if (!response.ok) {
|
|
9351
|
+
const errorText = await response.text();
|
|
9352
|
+
throw new Error(`reconcile failed: ${response.status} ${errorText}`);
|
|
9353
|
+
}
|
|
9354
|
+
const data = await response.json();
|
|
9355
|
+
if (!isReconcileCanvasItemsResponse(data)) {
|
|
9356
|
+
throw new Error("Invalid response from reconcile endpoint");
|
|
9357
|
+
}
|
|
9358
|
+
return data.deleted;
|
|
9359
|
+
}
|
|
9360
|
+
|
|
9361
|
+
// src/services/upload-chat-transcripts.ts
|
|
9362
|
+
import { readdir as readdir4, readFile as readFile11 } from "fs/promises";
|
|
9363
|
+
import { basename, join as join15 } from "path";
|
|
9364
|
+
import { homedir as homedir13 } from "os";
|
|
9365
|
+
var ENGINE_DIR2 = join15(homedir13(), ".replicas", "engine");
|
|
9162
9366
|
var HISTORY_DIRS = [
|
|
9163
|
-
|
|
9164
|
-
|
|
9165
|
-
|
|
9367
|
+
join15(ENGINE_DIR2, "claude-histories"),
|
|
9368
|
+
join15(ENGINE_DIR2, "relay-histories"),
|
|
9369
|
+
join15(ENGINE_DIR2, "codex-histories")
|
|
9166
9370
|
];
|
|
9167
9371
|
async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
9168
9372
|
let flushed = 0;
|
|
@@ -9171,7 +9375,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
|
9171
9375
|
for (const dir of HISTORY_DIRS) {
|
|
9172
9376
|
let entries;
|
|
9173
9377
|
try {
|
|
9174
|
-
entries = await
|
|
9378
|
+
entries = await readdir4(dir);
|
|
9175
9379
|
} catch {
|
|
9176
9380
|
continue;
|
|
9177
9381
|
}
|
|
@@ -9179,7 +9383,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
|
9179
9383
|
if (!entry.endsWith(".jsonl")) continue;
|
|
9180
9384
|
const chatId = basename(entry, ".jsonl");
|
|
9181
9385
|
tasks.push(
|
|
9182
|
-
uploadChatTranscript(chatId,
|
|
9386
|
+
uploadChatTranscript(chatId, join15(dir, entry), chatsById.get(chatId)).then(() => {
|
|
9183
9387
|
flushed++;
|
|
9184
9388
|
}).catch((err) => {
|
|
9185
9389
|
failed++;
|
|
@@ -9192,7 +9396,7 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
|
9192
9396
|
return { flushed, failed };
|
|
9193
9397
|
}
|
|
9194
9398
|
async function uploadChatTranscript(chatId, filePath, chat) {
|
|
9195
|
-
const bytes = await
|
|
9399
|
+
const bytes = await readFile11(filePath);
|
|
9196
9400
|
if (bytes.byteLength === 0) return;
|
|
9197
9401
|
const form = new FormData();
|
|
9198
9402
|
form.append("chat_id", chatId);
|
|
@@ -9249,18 +9453,18 @@ var DuplicateDefaultChatError = class extends Error {
|
|
|
9249
9453
|
};
|
|
9250
9454
|
|
|
9251
9455
|
// src/services/chat/chat-service.ts
|
|
9252
|
-
var ENGINE_DIR3 =
|
|
9253
|
-
var CHATS_FILE =
|
|
9254
|
-
var CLAUDE_HISTORY_DIR =
|
|
9255
|
-
var RELAY_HISTORY_DIR =
|
|
9256
|
-
var CODEX_HISTORY_DIR =
|
|
9456
|
+
var ENGINE_DIR3 = join16(homedir14(), ".replicas", "engine");
|
|
9457
|
+
var CHATS_FILE = join16(ENGINE_DIR3, "chats.json");
|
|
9458
|
+
var CLAUDE_HISTORY_DIR = join16(ENGINE_DIR3, "claude-histories");
|
|
9459
|
+
var RELAY_HISTORY_DIR = join16(ENGINE_DIR3, "relay-histories");
|
|
9460
|
+
var CODEX_HISTORY_DIR = join16(ENGINE_DIR3, "codex-histories");
|
|
9257
9461
|
var HISTORY_DIR_BY_PROVIDER = {
|
|
9258
9462
|
claude: CLAUDE_HISTORY_DIR,
|
|
9259
9463
|
relay: RELAY_HISTORY_DIR,
|
|
9260
9464
|
codex: CODEX_HISTORY_DIR
|
|
9261
9465
|
};
|
|
9262
|
-
var CHAT_SENDERS_DIR =
|
|
9263
|
-
var CODEX_AUTH_PATH2 =
|
|
9466
|
+
var CHAT_SENDERS_DIR = join16(ENGINE_DIR3, "chat-senders");
|
|
9467
|
+
var CODEX_AUTH_PATH2 = join16(homedir14(), ".codex", "auth.json");
|
|
9264
9468
|
var CHATS_BACKUP_FILE = `${CHATS_FILE}.bak`;
|
|
9265
9469
|
function isChatMessageSender(value) {
|
|
9266
9470
|
if (!isRecord4(value)) return false;
|
|
@@ -9458,7 +9662,7 @@ var ChatService = class {
|
|
|
9458
9662
|
};
|
|
9459
9663
|
}
|
|
9460
9664
|
senderFilePath(chatId) {
|
|
9461
|
-
return
|
|
9665
|
+
return join16(CHAT_SENDERS_DIR, `${chatId}.jsonl`);
|
|
9462
9666
|
}
|
|
9463
9667
|
async appendSender(chatId, sender) {
|
|
9464
9668
|
try {
|
|
@@ -9469,7 +9673,7 @@ var ChatService = class {
|
|
|
9469
9673
|
}
|
|
9470
9674
|
async readSenders(chatId) {
|
|
9471
9675
|
try {
|
|
9472
|
-
const content = await
|
|
9676
|
+
const content = await readFile12(this.senderFilePath(chatId), "utf-8");
|
|
9473
9677
|
const lines = content.split("\n").filter((line) => line.trim().length > 0);
|
|
9474
9678
|
const senders = [];
|
|
9475
9679
|
for (const line of lines) {
|
|
@@ -9614,7 +9818,7 @@ var ChatService = class {
|
|
|
9614
9818
|
return descendants;
|
|
9615
9819
|
}
|
|
9616
9820
|
async deleteHistoryFile(persisted) {
|
|
9617
|
-
await rm(
|
|
9821
|
+
await rm(join16(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`), { force: true });
|
|
9618
9822
|
await rm(this.senderFilePath(persisted.id), { force: true });
|
|
9619
9823
|
}
|
|
9620
9824
|
async getChatHistory(chatId) {
|
|
@@ -9652,6 +9856,16 @@ var ChatService = class {
|
|
|
9652
9856
|
[...this.chats.entries()].map(([chatId, chat]) => [chatId, this.toSummary(chat)])
|
|
9653
9857
|
));
|
|
9654
9858
|
}
|
|
9859
|
+
async flushAllWorkspaceArtifacts() {
|
|
9860
|
+
const chatsById = new Map(
|
|
9861
|
+
[...this.chats.entries()].map(([chatId, chat]) => [chatId, this.toSummary(chat)])
|
|
9862
|
+
);
|
|
9863
|
+
const [chatTranscripts, canvas] = await Promise.all([
|
|
9864
|
+
flushAllChatTranscripts(chatsById),
|
|
9865
|
+
flushAllCanvasItems()
|
|
9866
|
+
]);
|
|
9867
|
+
return { chatTranscripts, canvas };
|
|
9868
|
+
}
|
|
9655
9869
|
createRuntimeChat(persisted) {
|
|
9656
9870
|
const saveSession = async (sessionId) => {
|
|
9657
9871
|
persisted.providerSessionId = sessionId;
|
|
@@ -9675,7 +9889,7 @@ var ChatService = class {
|
|
|
9675
9889
|
if (persisted.provider === "claude") {
|
|
9676
9890
|
provider = new ClaudeManager({
|
|
9677
9891
|
workingDirectory: this.workingDirectory,
|
|
9678
|
-
historyFilePath:
|
|
9892
|
+
historyFilePath: join16(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
9679
9893
|
initialSessionId: persisted.providerSessionId,
|
|
9680
9894
|
onSaveSessionId: saveSession,
|
|
9681
9895
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -9684,7 +9898,7 @@ var ChatService = class {
|
|
|
9684
9898
|
} else if (persisted.provider === "relay") {
|
|
9685
9899
|
provider = new RelayManager({
|
|
9686
9900
|
workingDirectory: this.workingDirectory,
|
|
9687
|
-
historyFilePath:
|
|
9901
|
+
historyFilePath: join16(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
9688
9902
|
initialSessionId: persisted.providerSessionId,
|
|
9689
9903
|
onSaveSessionId: saveSession,
|
|
9690
9904
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -9695,7 +9909,7 @@ var ChatService = class {
|
|
|
9695
9909
|
} else {
|
|
9696
9910
|
provider = new CodexAspManager({
|
|
9697
9911
|
workingDirectory: this.workingDirectory,
|
|
9698
|
-
historyFilePath:
|
|
9912
|
+
historyFilePath: join16(CODEX_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
9699
9913
|
initialSessionId: persisted.providerSessionId,
|
|
9700
9914
|
onSaveSessionId: saveSession,
|
|
9701
9915
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -9833,11 +10047,14 @@ var ChatService = class {
|
|
|
9833
10047
|
});
|
|
9834
10048
|
uploadChatTranscript(
|
|
9835
10049
|
chatId,
|
|
9836
|
-
|
|
10050
|
+
join16(HISTORY_DIR_BY_PROVIDER[chat.persisted.provider], `${chatId}.jsonl`),
|
|
9837
10051
|
this.toSummary(chat)
|
|
9838
10052
|
).catch((err) => {
|
|
9839
10053
|
console.error("[ChatService] Failed to upload chat transcript:", { chatId, err });
|
|
9840
10054
|
});
|
|
10055
|
+
flushAllCanvasItems().catch((err) => {
|
|
10056
|
+
console.error("[ChatService] Failed to upload canvas items:", { chatId, err });
|
|
10057
|
+
});
|
|
9841
10058
|
await this.publishAgentTurnCompleteWebhook(chat);
|
|
9842
10059
|
}
|
|
9843
10060
|
getRuntimeChat(chatId) {
|
|
@@ -9845,7 +10062,7 @@ var ChatService = class {
|
|
|
9845
10062
|
}
|
|
9846
10063
|
async loadChats() {
|
|
9847
10064
|
try {
|
|
9848
|
-
const content = await
|
|
10065
|
+
const content = await readFile12(CHATS_FILE, "utf-8");
|
|
9849
10066
|
return parsePersistedChatsContent(content);
|
|
9850
10067
|
} catch (error) {
|
|
9851
10068
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
@@ -9860,7 +10077,7 @@ var ChatService = class {
|
|
|
9860
10077
|
console.error("[ChatService] Failed to quarantine corrupt chats file:", renameError);
|
|
9861
10078
|
}
|
|
9862
10079
|
try {
|
|
9863
|
-
const backupContent = await
|
|
10080
|
+
const backupContent = await readFile12(CHATS_BACKUP_FILE, "utf-8");
|
|
9864
10081
|
return parsePersistedChatsContent(backupContent);
|
|
9865
10082
|
} catch (backupError) {
|
|
9866
10083
|
if (backupError && typeof backupError === "object" && "code" in backupError && backupError.code === "ENOENT") {
|
|
@@ -9945,8 +10162,8 @@ var ChatService = class {
|
|
|
9945
10162
|
|
|
9946
10163
|
// src/services/repo-file-service.ts
|
|
9947
10164
|
import { execFile as execFile2 } from "child_process";
|
|
9948
|
-
import { readFile as
|
|
9949
|
-
import { join as
|
|
10165
|
+
import { readFile as readFile13, realpath, stat as stat3 } from "fs/promises";
|
|
10166
|
+
import { join as join17, resolve, extname } from "path";
|
|
9950
10167
|
var CACHE_TTL_MS = 3e4;
|
|
9951
10168
|
var SEARCH_TIMEOUT_MS = 15e3;
|
|
9952
10169
|
var MAX_CONTENT_BYTES = 256 * 1024;
|
|
@@ -10006,11 +10223,11 @@ function scoreMatch(query2, filePath) {
|
|
|
10006
10223
|
const lowerQuery = query2.toLowerCase();
|
|
10007
10224
|
const lowerPath = filePath.toLowerCase();
|
|
10008
10225
|
const segments = lowerPath.split("/");
|
|
10009
|
-
const
|
|
10010
|
-
if (
|
|
10011
|
-
if (
|
|
10226
|
+
const basename2 = segments[segments.length - 1] ?? "";
|
|
10227
|
+
if (basename2 === lowerQuery) return 100;
|
|
10228
|
+
if (basename2.startsWith(lowerQuery)) return 90;
|
|
10012
10229
|
if (segments.some((seg) => seg === lowerQuery)) return 80;
|
|
10013
|
-
if (
|
|
10230
|
+
if (basename2.includes(lowerQuery)) return 70;
|
|
10014
10231
|
if (segments.some((seg) => seg.includes(lowerQuery))) return 60;
|
|
10015
10232
|
if (lowerPath.includes(lowerQuery)) return 50;
|
|
10016
10233
|
return 0;
|
|
@@ -10106,11 +10323,11 @@ var RepoFileService = class {
|
|
|
10106
10323
|
const repo = repos.find((r) => r.name === repoName);
|
|
10107
10324
|
if (!repo) return null;
|
|
10108
10325
|
try {
|
|
10109
|
-
const fullPath = await realpath(resolve(
|
|
10326
|
+
const fullPath = await realpath(resolve(join17(repo.path, filePath)));
|
|
10110
10327
|
const repoRoot = await realpath(repo.path);
|
|
10111
10328
|
const repoPrefix = repoRoot.endsWith("/") ? repoRoot : repoRoot + "/";
|
|
10112
10329
|
if (!fullPath.startsWith(repoPrefix) && fullPath !== repoRoot) return null;
|
|
10113
|
-
const fileStat = await
|
|
10330
|
+
const fileStat = await stat3(fullPath);
|
|
10114
10331
|
if (!fileStat.isFile()) return null;
|
|
10115
10332
|
const sizeBytes = fileStat.size;
|
|
10116
10333
|
if (isBinaryExtension(filePath)) {
|
|
@@ -10135,7 +10352,7 @@ var RepoFileService = class {
|
|
|
10135
10352
|
tooLarge: true
|
|
10136
10353
|
};
|
|
10137
10354
|
}
|
|
10138
|
-
const content = await
|
|
10355
|
+
const content = await readFile13(fullPath, "utf-8");
|
|
10139
10356
|
return {
|
|
10140
10357
|
repoName,
|
|
10141
10358
|
path: filePath,
|
|
@@ -10216,86 +10433,6 @@ import { z as z2 } from "zod";
|
|
|
10216
10433
|
import { readdir as readdir6, stat as stat4, readFile as readFile16 } from "fs/promises";
|
|
10217
10434
|
import { join as join20, resolve as resolve2 } from "path";
|
|
10218
10435
|
|
|
10219
|
-
// src/services/canvas-service.ts
|
|
10220
|
-
import { readdir as readdir4, readFile as readFile13, stat as stat3 } from "fs/promises";
|
|
10221
|
-
import { homedir as homedir14 } from "os";
|
|
10222
|
-
import { basename as basename2, join as join17 } from "path";
|
|
10223
|
-
var CANVAS_DIRECTORIES = [
|
|
10224
|
-
join17(homedir14(), ".claude", "plans"),
|
|
10225
|
-
join17(homedir14(), ".replicas", "canvas")
|
|
10226
|
-
];
|
|
10227
|
-
var MAX_CANVAS_FILE_BYTES = 5 * 1024 * 1024;
|
|
10228
|
-
function isTextKind(kind) {
|
|
10229
|
-
return kind === "markdown" || kind === "html";
|
|
10230
|
-
}
|
|
10231
|
-
function sanitizeFilename(filename) {
|
|
10232
|
-
return basename2(filename);
|
|
10233
|
-
}
|
|
10234
|
-
var CanvasService = class {
|
|
10235
|
-
async listItems() {
|
|
10236
|
-
const items = /* @__PURE__ */ new Map();
|
|
10237
|
-
for (const directory of CANVAS_DIRECTORIES) {
|
|
10238
|
-
let entries;
|
|
10239
|
-
try {
|
|
10240
|
-
entries = await readdir4(directory, { withFileTypes: true });
|
|
10241
|
-
} catch {
|
|
10242
|
-
continue;
|
|
10243
|
-
}
|
|
10244
|
-
for (const entry of entries) {
|
|
10245
|
-
if (!entry.isFile()) continue;
|
|
10246
|
-
if (entry.name.startsWith(".")) continue;
|
|
10247
|
-
if (items.has(entry.name)) continue;
|
|
10248
|
-
const { kind } = classifyCanvasFilename(entry.name);
|
|
10249
|
-
let sizeBytes = 0;
|
|
10250
|
-
try {
|
|
10251
|
-
const s = await stat3(join17(directory, entry.name));
|
|
10252
|
-
sizeBytes = s.size;
|
|
10253
|
-
} catch {
|
|
10254
|
-
continue;
|
|
10255
|
-
}
|
|
10256
|
-
items.set(entry.name, { filename: entry.name, kind, sizeBytes });
|
|
10257
|
-
}
|
|
10258
|
-
}
|
|
10259
|
-
return Array.from(items.values()).sort((a, b) => a.filename.localeCompare(b.filename));
|
|
10260
|
-
}
|
|
10261
|
-
async getItem(filename) {
|
|
10262
|
-
const safe = sanitizeFilename(filename);
|
|
10263
|
-
if (!safe || safe !== filename || safe.startsWith(".")) return null;
|
|
10264
|
-
const { kind, mimeType } = classifyCanvasFilename(safe);
|
|
10265
|
-
for (const directory of CANVAS_DIRECTORIES) {
|
|
10266
|
-
const filePath = join17(directory, safe);
|
|
10267
|
-
let sizeBytes = 0;
|
|
10268
|
-
try {
|
|
10269
|
-
const s = await stat3(filePath);
|
|
10270
|
-
sizeBytes = s.size;
|
|
10271
|
-
} catch {
|
|
10272
|
-
continue;
|
|
10273
|
-
}
|
|
10274
|
-
if (sizeBytes > MAX_CANVAS_FILE_BYTES) {
|
|
10275
|
-
return {
|
|
10276
|
-
filename: safe,
|
|
10277
|
-
kind,
|
|
10278
|
-
sizeBytes,
|
|
10279
|
-
mimeType,
|
|
10280
|
-
tooLarge: true
|
|
10281
|
-
};
|
|
10282
|
-
}
|
|
10283
|
-
try {
|
|
10284
|
-
if (isTextKind(kind)) {
|
|
10285
|
-
const content = await readFile13(filePath, "utf-8");
|
|
10286
|
-
return { filename: safe, kind, sizeBytes, mimeType, content };
|
|
10287
|
-
}
|
|
10288
|
-
const buf = await readFile13(filePath);
|
|
10289
|
-
return { filename: safe, kind, sizeBytes, mimeType, base64: buf.toString("base64") };
|
|
10290
|
-
} catch {
|
|
10291
|
-
continue;
|
|
10292
|
-
}
|
|
10293
|
-
}
|
|
10294
|
-
return null;
|
|
10295
|
-
}
|
|
10296
|
-
};
|
|
10297
|
-
var canvasService = new CanvasService();
|
|
10298
|
-
|
|
10299
10436
|
// src/services/warm-hooks-service.ts
|
|
10300
10437
|
import { spawn as spawn4 } from "child_process";
|
|
10301
10438
|
import { readFile as readFile15 } from "fs/promises";
|
|
@@ -10912,6 +11049,17 @@ function createV1Routes(deps) {
|
|
|
10912
11049
|
);
|
|
10913
11050
|
}
|
|
10914
11051
|
});
|
|
11052
|
+
app2.post("/workspace-artifacts/flush-all", async (c) => {
|
|
11053
|
+
try {
|
|
11054
|
+
const result = await deps.chatService.flushAllWorkspaceArtifacts();
|
|
11055
|
+
return c.json(result);
|
|
11056
|
+
} catch (error) {
|
|
11057
|
+
return c.json(
|
|
11058
|
+
jsonError("Failed to flush workspace artifacts", error instanceof Error ? error.message : "Unknown error"),
|
|
11059
|
+
500
|
|
11060
|
+
);
|
|
11061
|
+
}
|
|
11062
|
+
});
|
|
10915
11063
|
app2.get("/chats/:chatId/queue", (c) => {
|
|
10916
11064
|
try {
|
|
10917
11065
|
const result = deps.chatService.getChatQueue(c.req.param("chatId"));
|