replicas-engine 0.1.485 → 0.1.492
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 +209 -60
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -408,6 +408,25 @@ function classifyCanvasFilename(filename) {
|
|
|
408
408
|
const ext = idx === -1 ? "" : filename.slice(idx).toLowerCase();
|
|
409
409
|
return CANVAS_KIND_BY_EXTENSION[ext] ?? { kind: "other", mimeType: "application/octet-stream" };
|
|
410
410
|
}
|
|
411
|
+
function isValidEngineLogSessionId(sessionId) {
|
|
412
|
+
return Boolean(sessionId) && !/[/\\]/.test(sessionId) && !sessionId.includes("..");
|
|
413
|
+
}
|
|
414
|
+
function paginateEngineLogContent(input) {
|
|
415
|
+
const parsedOffset = Number.parseInt(input.offset ?? "0", 10);
|
|
416
|
+
const parsedLimit = Number.parseInt(input.limit ?? "500", 10);
|
|
417
|
+
const offset = Number.isFinite(parsedOffset) && parsedOffset >= 0 ? parsedOffset : 0;
|
|
418
|
+
const limit = Number.isFinite(parsedLimit) && parsedLimit >= 0 ? Math.min(parsedLimit, 5e3) : 500;
|
|
419
|
+
const lines = input.content.split("\n");
|
|
420
|
+
if (lines.at(-1) === "") lines.pop();
|
|
421
|
+
return {
|
|
422
|
+
sessionId: input.sessionId,
|
|
423
|
+
totalLines: lines.length,
|
|
424
|
+
offset,
|
|
425
|
+
limit,
|
|
426
|
+
hasMore: offset + limit < lines.length,
|
|
427
|
+
lines: lines.slice(offset, offset + limit)
|
|
428
|
+
};
|
|
429
|
+
}
|
|
411
430
|
|
|
412
431
|
// ../shared/src/context-usage.ts
|
|
413
432
|
var CODEX_CATEGORY_COLORS = {
|
|
@@ -583,7 +602,7 @@ var WORKSPACE_SIZES = ["small", "large"];
|
|
|
583
602
|
var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
|
|
584
603
|
|
|
585
604
|
// ../shared/src/e2b.ts
|
|
586
|
-
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-23-
|
|
605
|
+
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-23-v12";
|
|
587
606
|
|
|
588
607
|
// ../shared/src/runtime-env.ts
|
|
589
608
|
function shellQuotePosix(value) {
|
|
@@ -4684,6 +4703,7 @@ var MEDIA_KIND = {
|
|
|
4684
4703
|
AUDIO: "audio"
|
|
4685
4704
|
};
|
|
4686
4705
|
var MEDIA_KINDS = [MEDIA_KIND.IMAGE, MEDIA_KIND.VIDEO, MEDIA_KIND.AUDIO];
|
|
4706
|
+
var MAX_ENGINE_LOG_BYTES = 50 * 1024 * 1024;
|
|
4687
4707
|
|
|
4688
4708
|
// ../shared/src/skill-registry.ts
|
|
4689
4709
|
var SKILL_REGISTRY_MANIFEST_VERSION = 1;
|
|
@@ -6129,8 +6149,8 @@ var StreamWriter = class {
|
|
|
6129
6149
|
}
|
|
6130
6150
|
return true;
|
|
6131
6151
|
}
|
|
6132
|
-
flush() {
|
|
6133
|
-
return new Promise((resolve4) => {
|
|
6152
|
+
flush(signal) {
|
|
6153
|
+
return new Promise((resolve4, reject) => {
|
|
6134
6154
|
if (!this.stream) {
|
|
6135
6155
|
resolve4();
|
|
6136
6156
|
return;
|
|
@@ -6140,8 +6160,17 @@ var StreamWriter = class {
|
|
|
6140
6160
|
this.flushTimer = null;
|
|
6141
6161
|
}
|
|
6142
6162
|
const s = this.stream;
|
|
6143
|
-
|
|
6144
|
-
|
|
6163
|
+
const onAbort = () => reject(signal?.reason);
|
|
6164
|
+
if (signal?.aborted) {
|
|
6165
|
+
reject(signal.reason);
|
|
6166
|
+
return;
|
|
6167
|
+
}
|
|
6168
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
6169
|
+
s.write("", (error) => {
|
|
6170
|
+
signal?.removeEventListener("abort", onAbort);
|
|
6171
|
+
if (error) reject(error);
|
|
6172
|
+
else resolve4();
|
|
6173
|
+
});
|
|
6145
6174
|
});
|
|
6146
6175
|
}
|
|
6147
6176
|
scheduleDropWarning() {
|
|
@@ -6202,8 +6231,11 @@ var EngineLogger = class {
|
|
|
6202
6231
|
this.writer.write(`[${(/* @__PURE__ */ new Date()).toISOString()}] [${level}] ${message}
|
|
6203
6232
|
`);
|
|
6204
6233
|
}
|
|
6205
|
-
flush() {
|
|
6206
|
-
return this.writer.flush();
|
|
6234
|
+
flush(signal) {
|
|
6235
|
+
return this.writer.flush(signal);
|
|
6236
|
+
}
|
|
6237
|
+
error(...args) {
|
|
6238
|
+
this.log("ERROR", format(...args));
|
|
6207
6239
|
}
|
|
6208
6240
|
createSessionId() {
|
|
6209
6241
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
|
|
@@ -7113,7 +7145,7 @@ async function registerDesktopPreview() {
|
|
|
7113
7145
|
import { existsSync as existsSync7 } from "fs";
|
|
7114
7146
|
import { appendFile as appendFile3, copyFile, mkdir as mkdir14, readFile as readFile14, rename as rename2, rm as rm2 } from "fs/promises";
|
|
7115
7147
|
import { homedir as homedir14 } from "os";
|
|
7116
|
-
import { join as
|
|
7148
|
+
import { join as join24 } from "path";
|
|
7117
7149
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
7118
7150
|
|
|
7119
7151
|
// src/managers/claude-manager.ts
|
|
@@ -9851,7 +9883,7 @@ var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
|
|
|
9851
9883
|
var MIN_CODEX_CLI_VERSION = "0.144.6";
|
|
9852
9884
|
var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
|
|
9853
9885
|
var codexCliVersionEnsured = null;
|
|
9854
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
9886
|
+
var ENGINE_PACKAGE_VERSION = "0.1.492";
|
|
9855
9887
|
var INITIALIZE_METHOD = "initialize";
|
|
9856
9888
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
9857
9889
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|
|
@@ -14255,9 +14287,136 @@ async function flushRepoState() {
|
|
|
14255
14287
|
}
|
|
14256
14288
|
}
|
|
14257
14289
|
|
|
14290
|
+
// src/services/upload-engine-logs.ts
|
|
14291
|
+
import { createReadStream } from "fs";
|
|
14292
|
+
import { readdir as readdir8, stat as stat4 } from "fs/promises";
|
|
14293
|
+
import { join as join23 } from "path";
|
|
14294
|
+
var MAX_ENGINE_LOG_FLUSH_SESSIONS = 10;
|
|
14295
|
+
var MAX_ENGINE_LOG_FLUSH_BYTES = 5 * 1024 * 1024;
|
|
14296
|
+
var ENGINE_LOG_FLUSH_TIMEOUT_MS = 2e4;
|
|
14297
|
+
async function flushAllEngineLogs() {
|
|
14298
|
+
let flushed = 0;
|
|
14299
|
+
let skipped = 0;
|
|
14300
|
+
let failed = 0;
|
|
14301
|
+
const deadline = Date.now() + ENGINE_LOG_FLUSH_TIMEOUT_MS;
|
|
14302
|
+
await runBeforeDeadline((signal) => engineLogger.flush(signal), deadline);
|
|
14303
|
+
const files = await runBeforeDeadline(() => readdir8(LOG_DIR), deadline).catch(() => []);
|
|
14304
|
+
const currentFilename = engineLogger.sessionId ? `${engineLogger.sessionId}.log` : null;
|
|
14305
|
+
const filenames = files.filter((filename) => {
|
|
14306
|
+
if (!filename.endsWith(".log")) return false;
|
|
14307
|
+
const sessionId = filename.slice(0, -".log".length);
|
|
14308
|
+
if (!isValidEngineLogSessionId(sessionId)) {
|
|
14309
|
+
skipped++;
|
|
14310
|
+
return false;
|
|
14311
|
+
}
|
|
14312
|
+
return true;
|
|
14313
|
+
}).sort((a, b) => {
|
|
14314
|
+
if (a === currentFilename) return -1;
|
|
14315
|
+
if (b === currentFilename) return 1;
|
|
14316
|
+
return b.localeCompare(a);
|
|
14317
|
+
});
|
|
14318
|
+
skipped += Math.max(0, filenames.length - MAX_ENGINE_LOG_FLUSH_SESSIONS);
|
|
14319
|
+
const candidates = (await Promise.all(filenames.slice(0, MAX_ENGINE_LOG_FLUSH_SESSIONS).map(async (filename) => {
|
|
14320
|
+
try {
|
|
14321
|
+
const sessionId = filename.slice(0, -".log".length);
|
|
14322
|
+
const filePath = join23(LOG_DIR, filename);
|
|
14323
|
+
const fileStat = await runBeforeDeadline(() => stat4(filePath), deadline);
|
|
14324
|
+
if (!fileStat.isFile()) {
|
|
14325
|
+
skipped++;
|
|
14326
|
+
return null;
|
|
14327
|
+
}
|
|
14328
|
+
return { sessionId, filename, filePath, fileStat };
|
|
14329
|
+
} catch (error) {
|
|
14330
|
+
failed++;
|
|
14331
|
+
engineLogger.error("[EngineLogUploader] upload failed:", { filename, error });
|
|
14332
|
+
return null;
|
|
14333
|
+
}
|
|
14334
|
+
}))).filter((candidate) => candidate !== null);
|
|
14335
|
+
const selected = [];
|
|
14336
|
+
let selectedBytes = 0;
|
|
14337
|
+
for (const candidate of candidates) {
|
|
14338
|
+
const length = Math.min(candidate.fileStat.size, MAX_ENGINE_LOG_FLUSH_BYTES);
|
|
14339
|
+
if (selected.length >= MAX_ENGINE_LOG_FLUSH_SESSIONS || selectedBytes + length > MAX_ENGINE_LOG_FLUSH_BYTES) {
|
|
14340
|
+
skipped++;
|
|
14341
|
+
continue;
|
|
14342
|
+
}
|
|
14343
|
+
selected.push({ ...candidate, offset: candidate.fileStat.size - length, length });
|
|
14344
|
+
selectedBytes += length;
|
|
14345
|
+
}
|
|
14346
|
+
for (const [index, candidate] of selected.entries()) {
|
|
14347
|
+
if (Date.now() >= deadline) {
|
|
14348
|
+
skipped += selected.length - index;
|
|
14349
|
+
break;
|
|
14350
|
+
}
|
|
14351
|
+
try {
|
|
14352
|
+
const content = await runBeforeDeadline(async (signal) => {
|
|
14353
|
+
if (candidate.length === 0) return Buffer.alloc(0);
|
|
14354
|
+
const chunks = [];
|
|
14355
|
+
for await (const chunk of createReadStream(candidate.filePath, {
|
|
14356
|
+
start: candidate.offset,
|
|
14357
|
+
end: candidate.offset + candidate.length - 1,
|
|
14358
|
+
signal
|
|
14359
|
+
})) {
|
|
14360
|
+
chunks.push(Buffer.from(chunk));
|
|
14361
|
+
}
|
|
14362
|
+
return Buffer.concat(chunks);
|
|
14363
|
+
}, deadline);
|
|
14364
|
+
const timeoutMs = deadline - Date.now();
|
|
14365
|
+
if (timeoutMs <= 0) {
|
|
14366
|
+
skipped += selected.length - index;
|
|
14367
|
+
break;
|
|
14368
|
+
}
|
|
14369
|
+
await uploadEngineLog({
|
|
14370
|
+
sessionId: candidate.sessionId,
|
|
14371
|
+
filename: candidate.filename,
|
|
14372
|
+
updatedAt: candidate.fileStat.mtime.toISOString(),
|
|
14373
|
+
content
|
|
14374
|
+
}, timeoutMs);
|
|
14375
|
+
flushed++;
|
|
14376
|
+
} catch (error) {
|
|
14377
|
+
failed++;
|
|
14378
|
+
engineLogger.error("[EngineLogUploader] upload failed:", { filename: candidate.filename, error });
|
|
14379
|
+
}
|
|
14380
|
+
}
|
|
14381
|
+
return { flushed, skipped, failed };
|
|
14382
|
+
}
|
|
14383
|
+
function runBeforeDeadline(operation, deadline) {
|
|
14384
|
+
const timeoutMs = deadline - Date.now();
|
|
14385
|
+
if (timeoutMs <= 0) return Promise.reject(new DOMException("engine log flush deadline exceeded", "TimeoutError"));
|
|
14386
|
+
const signal = AbortSignal.timeout(timeoutMs);
|
|
14387
|
+
return new Promise((resolve4, reject) => {
|
|
14388
|
+
const onAbort = () => reject(signal.reason);
|
|
14389
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
14390
|
+
operation(signal).then(
|
|
14391
|
+
(value) => {
|
|
14392
|
+
signal.removeEventListener("abort", onAbort);
|
|
14393
|
+
resolve4(value);
|
|
14394
|
+
},
|
|
14395
|
+
(error) => {
|
|
14396
|
+
signal.removeEventListener("abort", onAbort);
|
|
14397
|
+
reject(error);
|
|
14398
|
+
}
|
|
14399
|
+
);
|
|
14400
|
+
});
|
|
14401
|
+
}
|
|
14402
|
+
async function uploadEngineLog(input, timeoutMs) {
|
|
14403
|
+
const form = new FormData();
|
|
14404
|
+
form.append("session_id", input.sessionId);
|
|
14405
|
+
form.append("filename", input.filename);
|
|
14406
|
+
form.append("updated_at", input.updatedAt);
|
|
14407
|
+
form.append("file", new Blob([input.content], { type: "text/plain" }), input.filename);
|
|
14408
|
+
const response = await monolithRequest("/v1/engine/logs", {
|
|
14409
|
+
body: form,
|
|
14410
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
14411
|
+
});
|
|
14412
|
+
if (!response.ok) {
|
|
14413
|
+
throw new Error(`upload failed: ${response.status} ${await response.text()}`);
|
|
14414
|
+
}
|
|
14415
|
+
}
|
|
14416
|
+
|
|
14258
14417
|
// src/services/chat/chat-service.ts
|
|
14259
|
-
var CODEX_AUTH_PATH2 =
|
|
14260
|
-
var OPENCODE_AUTH_PATH3 =
|
|
14418
|
+
var CODEX_AUTH_PATH2 = join24(homedir14(), ".codex", "auth.json");
|
|
14419
|
+
var OPENCODE_AUTH_PATH3 = join24(homedir14(), ".local", "share", "opencode", "auth.json");
|
|
14261
14420
|
var CHATS_BACKUP_FILE = `${CHATS_FILE}.bak`;
|
|
14262
14421
|
function isCodexAvailable() {
|
|
14263
14422
|
return existsSync7(CODEX_AUTH_PATH2) || Boolean(ENGINE_ENV.OPENAI_API_KEY);
|
|
@@ -14719,7 +14878,7 @@ var ChatService = class {
|
|
|
14719
14878
|
return descendants;
|
|
14720
14879
|
}
|
|
14721
14880
|
async deleteHistoryFile(persisted) {
|
|
14722
|
-
await rm2(
|
|
14881
|
+
await rm2(join24(HISTORY_DIR_BY_PROVIDER[persisted.provider], `${persisted.id}.jsonl`), { force: true });
|
|
14723
14882
|
await rm2(chatMessageSendersFilePath(persisted.id), { force: true });
|
|
14724
14883
|
}
|
|
14725
14884
|
async getChatHistory(chatId, page = {}) {
|
|
@@ -14762,12 +14921,13 @@ var ChatService = class {
|
|
|
14762
14921
|
const chatsById = new Map(
|
|
14763
14922
|
[...this.chats.entries()].map(([chatId, chat]) => [chatId, this.toSummary(chat)])
|
|
14764
14923
|
);
|
|
14765
|
-
const [chatTranscripts, canvas, repoState] = await Promise.all([
|
|
14924
|
+
const [chatTranscripts, canvas, repoState, engineLogs] = await Promise.all([
|
|
14766
14925
|
flushAllChatTranscripts(chatsById),
|
|
14767
14926
|
flushAllCanvasItems(),
|
|
14768
|
-
flushRepoState()
|
|
14927
|
+
flushRepoState(),
|
|
14928
|
+
flushAllEngineLogs()
|
|
14769
14929
|
]);
|
|
14770
|
-
return { chatTranscripts, canvas, repoState };
|
|
14930
|
+
return { chatTranscripts, canvas, repoState, engineLogs };
|
|
14771
14931
|
}
|
|
14772
14932
|
createRuntimeChat(persisted) {
|
|
14773
14933
|
const saveSession = async (sessionId) => {
|
|
@@ -14794,7 +14954,7 @@ var ChatService = class {
|
|
|
14794
14954
|
if (persisted.provider === "claude") {
|
|
14795
14955
|
provider = new ClaudeManager({
|
|
14796
14956
|
workingDirectory: this.workingDirectory,
|
|
14797
|
-
historyFilePath:
|
|
14957
|
+
historyFilePath: join24(CLAUDE_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
14798
14958
|
initialSessionId: persisted.providerSessionId,
|
|
14799
14959
|
onSaveSessionId: saveSession,
|
|
14800
14960
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -14803,7 +14963,7 @@ var ChatService = class {
|
|
|
14803
14963
|
} else if (persisted.provider === "relay") {
|
|
14804
14964
|
provider = new RelayManager({
|
|
14805
14965
|
workingDirectory: this.workingDirectory,
|
|
14806
|
-
historyFilePath:
|
|
14966
|
+
historyFilePath: join24(RELAY_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
14807
14967
|
initialSessionId: persisted.providerSessionId,
|
|
14808
14968
|
onSaveSessionId: saveSession,
|
|
14809
14969
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -14817,7 +14977,7 @@ var ChatService = class {
|
|
|
14817
14977
|
} else if (persisted.provider === "cursor") {
|
|
14818
14978
|
provider = new CursorManager({
|
|
14819
14979
|
workingDirectory: this.workingDirectory,
|
|
14820
|
-
historyFilePath:
|
|
14980
|
+
historyFilePath: join24(CURSOR_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
14821
14981
|
initialSessionId: persisted.providerSessionId,
|
|
14822
14982
|
onSaveSessionId: saveSession,
|
|
14823
14983
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -14826,7 +14986,7 @@ var ChatService = class {
|
|
|
14826
14986
|
} else if (persisted.provider === "opencode") {
|
|
14827
14987
|
provider = new OpencodeManager({
|
|
14828
14988
|
workingDirectory: this.workingDirectory,
|
|
14829
|
-
historyFilePath:
|
|
14989
|
+
historyFilePath: join24(OPENCODE_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
14830
14990
|
initialSessionId: persisted.providerSessionId,
|
|
14831
14991
|
onSaveSessionId: saveSession,
|
|
14832
14992
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -14835,7 +14995,7 @@ var ChatService = class {
|
|
|
14835
14995
|
} else if (persisted.provider === "pi") {
|
|
14836
14996
|
provider = new PiManager({
|
|
14837
14997
|
workingDirectory: this.workingDirectory,
|
|
14838
|
-
historyFilePath:
|
|
14998
|
+
historyFilePath: join24(PI_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
14839
14999
|
initialSessionId: persisted.providerSessionId,
|
|
14840
15000
|
onSaveSessionId: saveSession,
|
|
14841
15001
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -14844,7 +15004,7 @@ var ChatService = class {
|
|
|
14844
15004
|
} else {
|
|
14845
15005
|
provider = new CodexAspManager({
|
|
14846
15006
|
workingDirectory: this.workingDirectory,
|
|
14847
|
-
historyFilePath:
|
|
15007
|
+
historyFilePath: join24(CODEX_HISTORY_DIR, `${persisted.id}.jsonl`),
|
|
14848
15008
|
initialSessionId: persisted.providerSessionId,
|
|
14849
15009
|
onSaveSessionId: saveSession,
|
|
14850
15010
|
onTurnComplete: onProviderTurnComplete,
|
|
@@ -14993,7 +15153,7 @@ var ChatService = class {
|
|
|
14993
15153
|
});
|
|
14994
15154
|
uploadChatTranscript(
|
|
14995
15155
|
chatId,
|
|
14996
|
-
|
|
15156
|
+
join24(HISTORY_DIR_BY_PROVIDER[chat.persisted.provider], `${chatId}.jsonl`),
|
|
14997
15157
|
this.toSummary(chat)
|
|
14998
15158
|
).catch((err) => {
|
|
14999
15159
|
console.error("[ChatService] Failed to upload chat transcript:", { chatId, err });
|
|
@@ -15128,8 +15288,8 @@ var ChatService = class {
|
|
|
15128
15288
|
|
|
15129
15289
|
// src/services/repo-file-service.ts
|
|
15130
15290
|
import { execFile as execFile2 } from "child_process";
|
|
15131
|
-
import { readFile as readFile15, realpath, stat as
|
|
15132
|
-
import { join as
|
|
15291
|
+
import { readFile as readFile15, realpath, stat as stat5 } from "fs/promises";
|
|
15292
|
+
import { join as join25, resolve as resolve2, extname as extname2 } from "path";
|
|
15133
15293
|
var CACHE_TTL_MS = 3e4;
|
|
15134
15294
|
var SEARCH_TIMEOUT_MS = 15e3;
|
|
15135
15295
|
var MAX_CONTENT_BYTES = 256 * 1024;
|
|
@@ -15289,11 +15449,11 @@ var RepoFileService = class {
|
|
|
15289
15449
|
const repo = repos.find((r) => r.name === repoName);
|
|
15290
15450
|
if (!repo) return null;
|
|
15291
15451
|
try {
|
|
15292
|
-
const fullPath = await realpath(resolve2(
|
|
15452
|
+
const fullPath = await realpath(resolve2(join25(repo.path, filePath)));
|
|
15293
15453
|
const repoRoot = await realpath(repo.path);
|
|
15294
15454
|
const repoPrefix = repoRoot.endsWith("/") ? repoRoot : repoRoot + "/";
|
|
15295
15455
|
if (!fullPath.startsWith(repoPrefix) && fullPath !== repoRoot) return null;
|
|
15296
|
-
const fileStat = await
|
|
15456
|
+
const fileStat = await stat5(fullPath);
|
|
15297
15457
|
if (!fileStat.isFile()) return null;
|
|
15298
15458
|
const sizeBytes = fileStat.size;
|
|
15299
15459
|
if (isBinaryExtension(filePath)) {
|
|
@@ -15396,21 +15556,21 @@ var RepoFileService = class {
|
|
|
15396
15556
|
// src/v1-routes.ts
|
|
15397
15557
|
import { Hono } from "hono";
|
|
15398
15558
|
import { z as z7 } from "zod";
|
|
15399
|
-
import { readdir as
|
|
15400
|
-
import { join as
|
|
15559
|
+
import { readdir as readdir10, stat as stat6, readFile as readFile18 } from "fs/promises";
|
|
15560
|
+
import { join as join28, resolve as resolve3 } from "path";
|
|
15401
15561
|
|
|
15402
15562
|
// src/services/warm-hooks-service.ts
|
|
15403
15563
|
import { spawn as spawn4 } from "child_process";
|
|
15404
15564
|
import { readFile as readFile17 } from "fs/promises";
|
|
15405
15565
|
import { existsSync as existsSync8 } from "fs";
|
|
15406
|
-
import { join as
|
|
15566
|
+
import { join as join27 } from "path";
|
|
15407
15567
|
|
|
15408
15568
|
// src/services/warm-hook-logs-service.ts
|
|
15409
|
-
import { mkdir as mkdir15, readFile as readFile16, writeFile as writeFile6, readdir as
|
|
15569
|
+
import { mkdir as mkdir15, readFile as readFile16, writeFile as writeFile6, readdir as readdir9, appendFile as appendFile4, unlink as unlink3 } from "fs/promises";
|
|
15410
15570
|
import { homedir as homedir15 } from "os";
|
|
15411
|
-
import { join as
|
|
15412
|
-
var LOGS_DIR2 =
|
|
15413
|
-
var CURRENT_RUN_LOG =
|
|
15571
|
+
import { join as join26 } from "path";
|
|
15572
|
+
var LOGS_DIR2 = join26(homedir15(), ".replicas", "warm-hook-logs");
|
|
15573
|
+
var CURRENT_RUN_LOG = join26(LOGS_DIR2, "current-run.log");
|
|
15414
15574
|
var GLOBAL_FILENAME = "global.json";
|
|
15415
15575
|
function withPreview2(stored) {
|
|
15416
15576
|
const preview = buildHookOutputPreview(stored.output);
|
|
@@ -15427,7 +15587,7 @@ var WarmHookLogsService = class {
|
|
|
15427
15587
|
hookName: "organization",
|
|
15428
15588
|
...entry
|
|
15429
15589
|
};
|
|
15430
|
-
await writeFile6(
|
|
15590
|
+
await writeFile6(join26(LOGS_DIR2, GLOBAL_FILENAME), `${JSON.stringify(log, null, 2)}
|
|
15431
15591
|
`, "utf-8");
|
|
15432
15592
|
}
|
|
15433
15593
|
async saveEnvironmentHookLog(entry) {
|
|
@@ -15437,7 +15597,7 @@ var WarmHookLogsService = class {
|
|
|
15437
15597
|
hookName: "environment",
|
|
15438
15598
|
...entry
|
|
15439
15599
|
};
|
|
15440
|
-
await writeFile6(
|
|
15600
|
+
await writeFile6(join26(LOGS_DIR2, ENVIRONMENT_HOOK_LOG_FILENAME), `${JSON.stringify(log, null, 2)}
|
|
15441
15601
|
`, "utf-8");
|
|
15442
15602
|
}
|
|
15443
15603
|
async saveRepoHookLog(repoName, entry) {
|
|
@@ -15447,13 +15607,13 @@ var WarmHookLogsService = class {
|
|
|
15447
15607
|
hookName: repoName,
|
|
15448
15608
|
...entry
|
|
15449
15609
|
};
|
|
15450
|
-
await writeFile6(
|
|
15610
|
+
await writeFile6(join26(LOGS_DIR2, repoHookLogFilename(repoName)), `${JSON.stringify(log, null, 2)}
|
|
15451
15611
|
`, "utf-8");
|
|
15452
15612
|
}
|
|
15453
15613
|
async getAllLogs() {
|
|
15454
15614
|
let files;
|
|
15455
15615
|
try {
|
|
15456
|
-
files = await
|
|
15616
|
+
files = await readdir9(LOGS_DIR2);
|
|
15457
15617
|
} catch (err) {
|
|
15458
15618
|
if (err.code === "ENOENT") {
|
|
15459
15619
|
return [];
|
|
@@ -15466,7 +15626,7 @@ var WarmHookLogsService = class {
|
|
|
15466
15626
|
continue;
|
|
15467
15627
|
}
|
|
15468
15628
|
try {
|
|
15469
|
-
const raw = await readFile16(
|
|
15629
|
+
const raw = await readFile16(join26(LOGS_DIR2, file), "utf-8");
|
|
15470
15630
|
const stored = JSON.parse(raw);
|
|
15471
15631
|
logs.push(withPreview2(stored));
|
|
15472
15632
|
} catch {
|
|
@@ -15504,7 +15664,7 @@ var WarmHookLogsService = class {
|
|
|
15504
15664
|
async getFullOutput(hookType, hookName) {
|
|
15505
15665
|
const filename = hookType === "global" ? GLOBAL_FILENAME : hookType === "environment" ? ENVIRONMENT_HOOK_LOG_FILENAME : repoHookLogFilename(hookName);
|
|
15506
15666
|
try {
|
|
15507
|
-
const raw = await readFile16(
|
|
15667
|
+
const raw = await readFile16(join26(LOGS_DIR2, filename), "utf-8");
|
|
15508
15668
|
const stored = JSON.parse(raw);
|
|
15509
15669
|
if (stored.hookType !== hookType || stored.hookName !== hookName) {
|
|
15510
15670
|
return null;
|
|
@@ -15523,7 +15683,7 @@ var warmHookLogsService = new WarmHookLogsService();
|
|
|
15523
15683
|
// src/services/warm-hooks-service.ts
|
|
15524
15684
|
async function readRepoWarmHook(repoPath) {
|
|
15525
15685
|
for (const filename of REPLICAS_CONFIG_FILENAMES) {
|
|
15526
|
-
const configPath =
|
|
15686
|
+
const configPath = join27(repoPath, filename);
|
|
15527
15687
|
if (!existsSync8(configPath)) {
|
|
15528
15688
|
continue;
|
|
15529
15689
|
}
|
|
@@ -16752,12 +16912,12 @@ data: ${JSON.stringify("Terminal session not found")}
|
|
|
16752
16912
|
});
|
|
16753
16913
|
app2.get("/logs", async (c) => {
|
|
16754
16914
|
try {
|
|
16755
|
-
const files = await
|
|
16915
|
+
const files = await readdir10(LOG_DIR).catch(() => []);
|
|
16756
16916
|
const logFiles = files.filter((f) => f.endsWith(".log"));
|
|
16757
16917
|
const sessions = await Promise.all(
|
|
16758
16918
|
logFiles.map(async (filename) => {
|
|
16759
|
-
const filePath =
|
|
16760
|
-
const fileStat = await
|
|
16919
|
+
const filePath = join28(LOG_DIR, filename);
|
|
16920
|
+
const fileStat = await stat6(filePath);
|
|
16761
16921
|
const sessionId = filename.replace(/\.log$/, "");
|
|
16762
16922
|
return {
|
|
16763
16923
|
sessionId,
|
|
@@ -16782,36 +16942,25 @@ data: ${JSON.stringify("Terminal session not found")}
|
|
|
16782
16942
|
app2.get("/logs/:sessionId", async (c) => {
|
|
16783
16943
|
try {
|
|
16784
16944
|
const sessionId = c.req.param("sessionId");
|
|
16785
|
-
if (!
|
|
16945
|
+
if (!isValidEngineLogSessionId(sessionId)) {
|
|
16786
16946
|
return c.json(jsonError("Invalid session ID"), 400);
|
|
16787
16947
|
}
|
|
16788
16948
|
const filePath = resolve3(LOG_DIR, `${sessionId}.log`);
|
|
16789
16949
|
if (!filePath.startsWith(resolve3(LOG_DIR))) {
|
|
16790
16950
|
return c.json(jsonError("Invalid session ID"), 400);
|
|
16791
16951
|
}
|
|
16792
|
-
const offset = parseInt(c.req.query("offset") || "0", 10);
|
|
16793
|
-
const limit = Math.min(parseInt(c.req.query("limit") || "500", 10), 5e3);
|
|
16794
16952
|
let content;
|
|
16795
16953
|
try {
|
|
16796
16954
|
content = await readFile18(filePath, "utf-8");
|
|
16797
16955
|
} catch {
|
|
16798
16956
|
return c.json(jsonError("Log session not found"), 404);
|
|
16799
16957
|
}
|
|
16800
|
-
|
|
16801
|
-
if (allLines.length > 0 && allLines[allLines.length - 1] === "") {
|
|
16802
|
-
allLines.pop();
|
|
16803
|
-
}
|
|
16804
|
-
const totalLines = allLines.length;
|
|
16805
|
-
const slicedLines = allLines.slice(offset, offset + limit);
|
|
16806
|
-
const hasMore = offset + limit < totalLines;
|
|
16807
|
-
return c.json({
|
|
16958
|
+
return c.json(paginateEngineLogContent({
|
|
16808
16959
|
sessionId,
|
|
16809
|
-
|
|
16810
|
-
offset,
|
|
16811
|
-
limit
|
|
16812
|
-
|
|
16813
|
-
lines: slicedLines
|
|
16814
|
-
});
|
|
16960
|
+
content,
|
|
16961
|
+
offset: c.req.query("offset"),
|
|
16962
|
+
limit: c.req.query("limit")
|
|
16963
|
+
}));
|
|
16815
16964
|
} catch (error) {
|
|
16816
16965
|
return c.json(
|
|
16817
16966
|
jsonError("Failed to read log", error instanceof Error ? error.message : "Unknown error"),
|