replicas-engine 0.1.62 → 0.1.64
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 +121 -16
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { serve } from "@hono/node-server";
|
|
5
5
|
import { Hono as Hono2 } from "hono";
|
|
6
|
-
import { readFile as
|
|
6
|
+
import { readFile as readFile13 } from "fs/promises";
|
|
7
7
|
import { execSync } from "child_process";
|
|
8
8
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
9
9
|
|
|
@@ -799,15 +799,18 @@ import { format } from "util";
|
|
|
799
799
|
import { randomBytes } from "crypto";
|
|
800
800
|
var LOG_DIR = join4(homedir3(), ".replicas", "logs");
|
|
801
801
|
var EngineLogger = class {
|
|
802
|
-
|
|
802
|
+
_sessionId = null;
|
|
803
803
|
filePath = null;
|
|
804
804
|
writeChain = Promise.resolve();
|
|
805
805
|
patched = false;
|
|
806
|
+
get sessionId() {
|
|
807
|
+
return this._sessionId;
|
|
808
|
+
}
|
|
806
809
|
async initialize() {
|
|
807
810
|
await mkdir2(LOG_DIR, { recursive: true });
|
|
808
|
-
this.
|
|
809
|
-
this.filePath = join4(LOG_DIR, `${this.
|
|
810
|
-
await writeFile2(this.filePath, `=== Replicas Engine Session ${this.
|
|
811
|
+
this._sessionId = this.createSessionId();
|
|
812
|
+
this.filePath = join4(LOG_DIR, `${this._sessionId}.log`);
|
|
813
|
+
await writeFile2(this.filePath, `=== Replicas Engine Session ${this._sessionId} ===
|
|
811
814
|
`, "utf-8");
|
|
812
815
|
this.patchConsole();
|
|
813
816
|
this.log("INFO", `Engine logging initialized at ${this.filePath}`);
|
|
@@ -844,6 +847,10 @@ var EngineLogger = class {
|
|
|
844
847
|
}
|
|
845
848
|
});
|
|
846
849
|
}
|
|
850
|
+
/** Wait for all queued log writes to complete. */
|
|
851
|
+
flush() {
|
|
852
|
+
return this.writeChain;
|
|
853
|
+
}
|
|
847
854
|
createSessionId() {
|
|
848
855
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/:/g, "-");
|
|
849
856
|
const suffix = randomBytes(3).toString("hex");
|
|
@@ -2147,7 +2154,9 @@ var MessageQueueService = class {
|
|
|
2147
2154
|
position: this.queue.length
|
|
2148
2155
|
};
|
|
2149
2156
|
}
|
|
2150
|
-
this.startProcessing(queuedMessage)
|
|
2157
|
+
this.startProcessing(queuedMessage).catch((error) => {
|
|
2158
|
+
console.error("[MessageQueue] Unhandled error in startProcessing:", error);
|
|
2159
|
+
});
|
|
2151
2160
|
return {
|
|
2152
2161
|
queued: false,
|
|
2153
2162
|
messageId,
|
|
@@ -2341,8 +2350,8 @@ var PromptStream = class {
|
|
|
2341
2350
|
if (this.closed) {
|
|
2342
2351
|
return Promise.resolve({ value: void 0, done: true });
|
|
2343
2352
|
}
|
|
2344
|
-
return new Promise((
|
|
2345
|
-
this.waiters.push(
|
|
2353
|
+
return new Promise((resolve2) => {
|
|
2354
|
+
this.waiters.push(resolve2);
|
|
2346
2355
|
});
|
|
2347
2356
|
}
|
|
2348
2357
|
};
|
|
@@ -2504,7 +2513,11 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
2504
2513
|
this.activePromptStream?.close();
|
|
2505
2514
|
this.activePromptStream = null;
|
|
2506
2515
|
this.pendingInterrupt = false;
|
|
2507
|
-
|
|
2516
|
+
try {
|
|
2517
|
+
await this.onTurnComplete();
|
|
2518
|
+
} catch (error) {
|
|
2519
|
+
console.error("[ClaudeManager] onTurnComplete failed:", error);
|
|
2520
|
+
}
|
|
2508
2521
|
}
|
|
2509
2522
|
}
|
|
2510
2523
|
/**
|
|
@@ -2597,7 +2610,7 @@ function isJsonlEvent2(value) {
|
|
|
2597
2610
|
return typeof value.timestamp === "string" && typeof value.type === "string" && isRecord(value.payload);
|
|
2598
2611
|
}
|
|
2599
2612
|
function sleep(ms) {
|
|
2600
|
-
return new Promise((
|
|
2613
|
+
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
2601
2614
|
}
|
|
2602
2615
|
var CodexManager = class extends CodingAgentManager {
|
|
2603
2616
|
codex;
|
|
@@ -2770,7 +2783,11 @@ var CodexManager = class extends CodingAgentManager {
|
|
|
2770
2783
|
if (stopTail) {
|
|
2771
2784
|
await stopTail();
|
|
2772
2785
|
}
|
|
2773
|
-
|
|
2786
|
+
try {
|
|
2787
|
+
await this.onTurnComplete();
|
|
2788
|
+
} catch (error) {
|
|
2789
|
+
console.error("[CodexManager] onTurnComplete failed:", error);
|
|
2790
|
+
}
|
|
2774
2791
|
this.activeAbortController = null;
|
|
2775
2792
|
}
|
|
2776
2793
|
}
|
|
@@ -3229,16 +3246,27 @@ var ChatService = class {
|
|
|
3229
3246
|
} catch {
|
|
3230
3247
|
}
|
|
3231
3248
|
const linearSessionId = ENGINE_ENV.LINEAR_SESSION_ID;
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3249
|
+
let repoStatuses;
|
|
3250
|
+
try {
|
|
3251
|
+
repoStatuses = await gitService.refreshRepos();
|
|
3252
|
+
console.log(`Repository Statuses Refreshed: `, repoStatuses);
|
|
3253
|
+
} catch (error) {
|
|
3254
|
+
console.error("[ChatService] Failed to refresh repo statuses:", error);
|
|
3255
|
+
}
|
|
3256
|
+
try {
|
|
3257
|
+
const payload = linearSessionId ? { linearSessionId, repoStatuses: repoStatuses ?? [] } : { repoStatuses: repoStatuses ?? [] };
|
|
3258
|
+
await monolithService.sendEvent({ type: "agent_turn_complete", payload });
|
|
3259
|
+
} catch (error) {
|
|
3260
|
+
console.error("[ChatService] Failed to send agent_turn_complete event:", error);
|
|
3261
|
+
}
|
|
3236
3262
|
}
|
|
3237
3263
|
};
|
|
3238
3264
|
|
|
3239
3265
|
// src/v1-routes.ts
|
|
3240
3266
|
import { Hono } from "hono";
|
|
3241
3267
|
import { z } from "zod";
|
|
3268
|
+
import { readdir as readdir6, stat as stat3, readFile as readFile12 } from "fs/promises";
|
|
3269
|
+
import { join as join15, resolve } from "path";
|
|
3242
3270
|
|
|
3243
3271
|
// src/services/plan-service.ts
|
|
3244
3272
|
import { readdir as readdir4, readFile as readFile9 } from "fs/promises";
|
|
@@ -3870,11 +3898,88 @@ function createV1Routes(deps) {
|
|
|
3870
3898
|
return c.json(jsonError("Failed to create preview", details), 400);
|
|
3871
3899
|
}
|
|
3872
3900
|
});
|
|
3901
|
+
app2.get("/logs", async (c) => {
|
|
3902
|
+
try {
|
|
3903
|
+
const files = await readdir6(LOG_DIR).catch(() => []);
|
|
3904
|
+
const logFiles = files.filter((f) => f.endsWith(".log"));
|
|
3905
|
+
const sessions = await Promise.all(
|
|
3906
|
+
logFiles.map(async (filename) => {
|
|
3907
|
+
const filePath = join15(LOG_DIR, filename);
|
|
3908
|
+
const fileStat = await stat3(filePath);
|
|
3909
|
+
const sessionId = filename.replace(/\.log$/, "");
|
|
3910
|
+
return {
|
|
3911
|
+
sessionId,
|
|
3912
|
+
filename,
|
|
3913
|
+
sizeBytes: fileStat.size,
|
|
3914
|
+
updatedAt: fileStat.mtime.toISOString()
|
|
3915
|
+
};
|
|
3916
|
+
})
|
|
3917
|
+
);
|
|
3918
|
+
sessions.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
3919
|
+
return c.json({
|
|
3920
|
+
currentSessionId: engineLogger.sessionId,
|
|
3921
|
+
sessions
|
|
3922
|
+
});
|
|
3923
|
+
} catch (error) {
|
|
3924
|
+
return c.json(
|
|
3925
|
+
jsonError("Failed to list logs", error instanceof Error ? error.message : "Unknown error"),
|
|
3926
|
+
500
|
|
3927
|
+
);
|
|
3928
|
+
}
|
|
3929
|
+
});
|
|
3930
|
+
app2.get("/logs/:sessionId", async (c) => {
|
|
3931
|
+
try {
|
|
3932
|
+
const sessionId = c.req.param("sessionId");
|
|
3933
|
+
if (!sessionId || /[/\\]/.test(sessionId) || sessionId.includes("..")) {
|
|
3934
|
+
return c.json(jsonError("Invalid session ID"), 400);
|
|
3935
|
+
}
|
|
3936
|
+
const filePath = resolve(LOG_DIR, `${sessionId}.log`);
|
|
3937
|
+
if (!filePath.startsWith(resolve(LOG_DIR))) {
|
|
3938
|
+
return c.json(jsonError("Invalid session ID"), 400);
|
|
3939
|
+
}
|
|
3940
|
+
const offset = parseInt(c.req.query("offset") || "0", 10);
|
|
3941
|
+
const limit = Math.min(parseInt(c.req.query("limit") || "500", 10), 5e3);
|
|
3942
|
+
let content;
|
|
3943
|
+
try {
|
|
3944
|
+
content = await readFile12(filePath, "utf-8");
|
|
3945
|
+
} catch {
|
|
3946
|
+
return c.json(jsonError("Log session not found"), 404);
|
|
3947
|
+
}
|
|
3948
|
+
const allLines = content.split("\n");
|
|
3949
|
+
if (allLines.length > 0 && allLines[allLines.length - 1] === "") {
|
|
3950
|
+
allLines.pop();
|
|
3951
|
+
}
|
|
3952
|
+
const totalLines = allLines.length;
|
|
3953
|
+
const slicedLines = allLines.slice(offset, offset + limit);
|
|
3954
|
+
const hasMore = offset + limit < totalLines;
|
|
3955
|
+
return c.json({
|
|
3956
|
+
sessionId,
|
|
3957
|
+
totalLines,
|
|
3958
|
+
offset,
|
|
3959
|
+
limit,
|
|
3960
|
+
hasMore,
|
|
3961
|
+
lines: slicedLines
|
|
3962
|
+
});
|
|
3963
|
+
} catch (error) {
|
|
3964
|
+
return c.json(
|
|
3965
|
+
jsonError("Failed to read log", error instanceof Error ? error.message : "Unknown error"),
|
|
3966
|
+
500
|
|
3967
|
+
);
|
|
3968
|
+
}
|
|
3969
|
+
});
|
|
3873
3970
|
return app2;
|
|
3874
3971
|
}
|
|
3875
3972
|
|
|
3876
3973
|
// src/index.ts
|
|
3877
3974
|
await engineLogger.initialize();
|
|
3975
|
+
process.on("uncaughtException", (error) => {
|
|
3976
|
+
console.error("[FATAL] Uncaught exception:", error);
|
|
3977
|
+
engineLogger.flush().finally(() => process.exit(1));
|
|
3978
|
+
});
|
|
3979
|
+
process.on("unhandledRejection", (reason) => {
|
|
3980
|
+
console.error("[FATAL] Unhandled rejection:", reason);
|
|
3981
|
+
engineLogger.flush().finally(() => process.exit(1));
|
|
3982
|
+
});
|
|
3878
3983
|
await eventService.initialize();
|
|
3879
3984
|
var READY_MESSAGE = "========= REPLICAS WORKSPACE READY ==========";
|
|
3880
3985
|
var COMPLETION_MESSAGE = "========= REPLICAS WORKSPACE INITIALIZATION COMPLETE ==========";
|
|
@@ -3910,7 +4015,7 @@ app.get("/health", async (c) => {
|
|
|
3910
4015
|
return c.json({ status: "initializing", timestamp: (/* @__PURE__ */ new Date()).toISOString() }, 503);
|
|
3911
4016
|
}
|
|
3912
4017
|
try {
|
|
3913
|
-
const logContent = await
|
|
4018
|
+
const logContent = await readFile13("/var/log/cloud-init-output.log", "utf-8");
|
|
3914
4019
|
let status;
|
|
3915
4020
|
if (logContent.includes(COMPLETION_MESSAGE)) {
|
|
3916
4021
|
status = "active";
|