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