replicas-engine 0.1.25 → 0.1.26
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 +149 -3
- package/package.json +2 -2
package/dist/src/index.js
CHANGED
|
@@ -54,6 +54,35 @@ async function readJSONL(filePath) {
|
|
|
54
54
|
return [];
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
|
+
async function readJSONLPaginated(filePath, limit, offset = 0) {
|
|
58
|
+
try {
|
|
59
|
+
const content = await readFile(filePath, "utf-8");
|
|
60
|
+
const lines = content.split("\n").filter((line) => line.trim());
|
|
61
|
+
const allEvents = lines.map((line) => {
|
|
62
|
+
try {
|
|
63
|
+
return JSON.parse(line);
|
|
64
|
+
} catch (e) {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}).filter((event) => event !== null);
|
|
68
|
+
const total = allEvents.length;
|
|
69
|
+
const startIndex = Math.max(0, total - offset - (limit ?? total));
|
|
70
|
+
const endIndex = Math.max(0, total - offset);
|
|
71
|
+
const events = allEvents.slice(startIndex, endIndex);
|
|
72
|
+
const hasMore = startIndex > 0;
|
|
73
|
+
return {
|
|
74
|
+
events,
|
|
75
|
+
total,
|
|
76
|
+
hasMore
|
|
77
|
+
};
|
|
78
|
+
} catch (error) {
|
|
79
|
+
return {
|
|
80
|
+
events: [],
|
|
81
|
+
total: 0,
|
|
82
|
+
hasMore: false
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
}
|
|
57
86
|
|
|
58
87
|
// src/services/codex-manager.ts
|
|
59
88
|
import { readdir, stat, writeFile as writeFile3, mkdir as mkdir3 } from "fs/promises";
|
|
@@ -110,6 +139,14 @@ function summarizeInput(input) {
|
|
|
110
139
|
if (obj.pattern) return `pattern: ${String(obj.pattern)}`;
|
|
111
140
|
if (obj.query) return String(obj.query);
|
|
112
141
|
if (obj.url) return String(obj.url);
|
|
142
|
+
if (obj.todos && Array.isArray(obj.todos)) {
|
|
143
|
+
const todos = obj.todos;
|
|
144
|
+
const completed = todos.filter((t) => t.status === "completed").length;
|
|
145
|
+
const total = todos.length;
|
|
146
|
+
const currentTask = todos.find((t) => t.status === "in_progress");
|
|
147
|
+
const summary = `${completed}/${total}`;
|
|
148
|
+
return currentTask?.content ? `${summary}: ${currentTask.content}` : summary;
|
|
149
|
+
}
|
|
113
150
|
const keys = Object.keys(obj);
|
|
114
151
|
if (keys.length > 0) {
|
|
115
152
|
const firstKey = keys[0];
|
|
@@ -298,12 +335,18 @@ function convertCodexEvent(event, linearSessionId) {
|
|
|
298
335
|
};
|
|
299
336
|
}
|
|
300
337
|
if (item.type === "todo_list") {
|
|
338
|
+
const items = "items" in item && Array.isArray(item.items) ? item.items : [];
|
|
339
|
+
const completed = items.filter((t) => t.completed).length;
|
|
340
|
+
const total = items.length;
|
|
341
|
+
const currentTask = items.find((t) => !t.completed);
|
|
342
|
+
const summary = `${completed}/${total}`;
|
|
343
|
+
const parameter = currentTask?.text ? `${summary}: ${currentTask.text}` : summary;
|
|
301
344
|
return {
|
|
302
345
|
linearSessionId,
|
|
303
346
|
content: {
|
|
304
347
|
type: "action",
|
|
305
348
|
action: "Updating plan",
|
|
306
|
-
parameter
|
|
349
|
+
parameter
|
|
307
350
|
}
|
|
308
351
|
};
|
|
309
352
|
}
|
|
@@ -366,12 +409,18 @@ function convertCodexEvent(event, linearSessionId) {
|
|
|
366
409
|
};
|
|
367
410
|
}
|
|
368
411
|
if (item.type === "todo_list") {
|
|
412
|
+
const items = "items" in item && Array.isArray(item.items) ? item.items : [];
|
|
413
|
+
const completed = items.filter((t) => t.completed).length;
|
|
414
|
+
const total = items.length;
|
|
415
|
+
const currentTask = items.find((t) => !t.completed);
|
|
416
|
+
const summary = `${completed}/${total}`;
|
|
417
|
+
const parameter = currentTask?.text ? `${summary}: ${currentTask.text}` : summary;
|
|
369
418
|
return {
|
|
370
419
|
linearSessionId,
|
|
371
420
|
content: {
|
|
372
421
|
type: "action",
|
|
373
422
|
action: "Updating plan",
|
|
374
|
-
parameter
|
|
423
|
+
parameter,
|
|
375
424
|
result: "Done"
|
|
376
425
|
}
|
|
377
426
|
};
|
|
@@ -518,6 +567,9 @@ async function getPullRequestUrl(cwd) {
|
|
|
518
567
|
return cachedPr.prUrl;
|
|
519
568
|
}
|
|
520
569
|
cachedPr = null;
|
|
570
|
+
if (persistedState.prUrl && persistedState.branch !== currentBranch) {
|
|
571
|
+
await saveEngineState({ prUrl: null });
|
|
572
|
+
}
|
|
521
573
|
try {
|
|
522
574
|
const remoteRef = execSync(`git ls-remote --heads origin ${currentBranch}`, {
|
|
523
575
|
cwd,
|
|
@@ -1153,6 +1205,38 @@ var CodexManager = class {
|
|
|
1153
1205
|
events
|
|
1154
1206
|
};
|
|
1155
1207
|
}
|
|
1208
|
+
/**
|
|
1209
|
+
* Get paginated history from the end (bottom-up pagination).
|
|
1210
|
+
* @param limit - Maximum number of events to return
|
|
1211
|
+
* @param offset - Number of events to skip from the end
|
|
1212
|
+
* @returns Paginated history result
|
|
1213
|
+
*/
|
|
1214
|
+
async getHistoryPaginated(limit, offset = 0) {
|
|
1215
|
+
if (!this.currentThreadId) {
|
|
1216
|
+
return {
|
|
1217
|
+
thread_id: null,
|
|
1218
|
+
events: [],
|
|
1219
|
+
total: 0,
|
|
1220
|
+
hasMore: false
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
const sessionFile = await this.findSessionFile(this.currentThreadId);
|
|
1224
|
+
if (!sessionFile) {
|
|
1225
|
+
return {
|
|
1226
|
+
thread_id: this.currentThreadId,
|
|
1227
|
+
events: [],
|
|
1228
|
+
total: 0,
|
|
1229
|
+
hasMore: false
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
const result = await readJSONLPaginated(sessionFile, limit, offset);
|
|
1233
|
+
return {
|
|
1234
|
+
thread_id: this.currentThreadId,
|
|
1235
|
+
events: result.events,
|
|
1236
|
+
total: result.total,
|
|
1237
|
+
hasMore: result.hasMore
|
|
1238
|
+
};
|
|
1239
|
+
}
|
|
1156
1240
|
async getStatus() {
|
|
1157
1241
|
let sessionFile = null;
|
|
1158
1242
|
if (this.currentThreadId) {
|
|
@@ -1273,6 +1357,29 @@ codex.post("/send", async (c) => {
|
|
|
1273
1357
|
});
|
|
1274
1358
|
codex.get("/history", async (c) => {
|
|
1275
1359
|
try {
|
|
1360
|
+
const limitStr = c.req.query("limit");
|
|
1361
|
+
const offsetStr = c.req.query("offset");
|
|
1362
|
+
if (limitStr !== void 0 || offsetStr !== void 0) {
|
|
1363
|
+
const limit = limitStr ? parseInt(limitStr, 10) : void 0;
|
|
1364
|
+
const offset = offsetStr ? parseInt(offsetStr, 10) : 0;
|
|
1365
|
+
if (limitStr && (isNaN(limit) || limit < 1)) {
|
|
1366
|
+
return c.json({ error: "limit must be a positive integer" }, 400);
|
|
1367
|
+
}
|
|
1368
|
+
if (isNaN(offset) || offset < 0) {
|
|
1369
|
+
return c.json({ error: "offset must be a non-negative integer" }, 400);
|
|
1370
|
+
}
|
|
1371
|
+
const history2 = await codexManager.getHistoryPaginated(limit, offset);
|
|
1372
|
+
if (!history2.thread_id) {
|
|
1373
|
+
return c.json({
|
|
1374
|
+
message: "No active thread",
|
|
1375
|
+
thread_id: null,
|
|
1376
|
+
events: [],
|
|
1377
|
+
total: 0,
|
|
1378
|
+
hasMore: false
|
|
1379
|
+
});
|
|
1380
|
+
}
|
|
1381
|
+
return c.json(history2);
|
|
1382
|
+
}
|
|
1276
1383
|
const history = await codexManager.getHistory();
|
|
1277
1384
|
if (!history.thread_id) {
|
|
1278
1385
|
return c.json({
|
|
@@ -1559,6 +1666,22 @@ var ClaudeManager = class {
|
|
|
1559
1666
|
events
|
|
1560
1667
|
};
|
|
1561
1668
|
}
|
|
1669
|
+
/**
|
|
1670
|
+
* Get paginated history from the end (bottom-up pagination).
|
|
1671
|
+
* @param limit - Maximum number of events to return
|
|
1672
|
+
* @param offset - Number of events to skip from the end
|
|
1673
|
+
* @returns Paginated history result
|
|
1674
|
+
*/
|
|
1675
|
+
async getHistoryPaginated(limit, offset = 0) {
|
|
1676
|
+
await this.initialized;
|
|
1677
|
+
const result = await readJSONLPaginated(this.historyFile, limit, offset);
|
|
1678
|
+
return {
|
|
1679
|
+
thread_id: this.sessionId,
|
|
1680
|
+
events: result.events,
|
|
1681
|
+
total: result.total,
|
|
1682
|
+
hasMore: result.hasMore
|
|
1683
|
+
};
|
|
1684
|
+
}
|
|
1562
1685
|
async getStatus() {
|
|
1563
1686
|
await this.initialized;
|
|
1564
1687
|
const status = {
|
|
@@ -1645,6 +1768,29 @@ claude.post("/send", async (c) => {
|
|
|
1645
1768
|
});
|
|
1646
1769
|
claude.get("/history", async (c) => {
|
|
1647
1770
|
try {
|
|
1771
|
+
const limitStr = c.req.query("limit");
|
|
1772
|
+
const offsetStr = c.req.query("offset");
|
|
1773
|
+
if (limitStr !== void 0 || offsetStr !== void 0) {
|
|
1774
|
+
const limit = limitStr ? parseInt(limitStr, 10) : void 0;
|
|
1775
|
+
const offset = offsetStr ? parseInt(offsetStr, 10) : 0;
|
|
1776
|
+
if (limitStr && (isNaN(limit) || limit < 1)) {
|
|
1777
|
+
return c.json({ error: "limit must be a positive integer" }, 400);
|
|
1778
|
+
}
|
|
1779
|
+
if (isNaN(offset) || offset < 0) {
|
|
1780
|
+
return c.json({ error: "offset must be a non-negative integer" }, 400);
|
|
1781
|
+
}
|
|
1782
|
+
const history2 = await claudeManager.getHistoryPaginated(limit, offset);
|
|
1783
|
+
if (!history2.thread_id) {
|
|
1784
|
+
return c.json({
|
|
1785
|
+
message: "No active session",
|
|
1786
|
+
thread_id: null,
|
|
1787
|
+
events: [],
|
|
1788
|
+
total: 0,
|
|
1789
|
+
hasMore: false
|
|
1790
|
+
});
|
|
1791
|
+
}
|
|
1792
|
+
return c.json(history2);
|
|
1793
|
+
}
|
|
1648
1794
|
const history = await claudeManager.getHistory();
|
|
1649
1795
|
if (!history.thread_id) {
|
|
1650
1796
|
return c.json({
|
|
@@ -2086,7 +2232,7 @@ async function initializeGitRepository() {
|
|
|
2086
2232
|
console.log(`[GitInit] Creating workspace branch: ${branchName}`);
|
|
2087
2233
|
runGitCommand(`git checkout -b ${branchName}`, repoPath);
|
|
2088
2234
|
initializedBranch = branchName;
|
|
2089
|
-
await saveEngineState({ branch: branchName });
|
|
2235
|
+
await saveEngineState({ branch: branchName, prUrl: null });
|
|
2090
2236
|
console.log(`[GitInit] Successfully initialized on branch: ${branchName}`);
|
|
2091
2237
|
return {
|
|
2092
2238
|
success: true,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "replicas-engine",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.26",
|
|
4
4
|
"description": "Lightweight API server for Replicas workspaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@openai/codex-sdk": "^0.50.0",
|
|
32
32
|
"dotenv": "^17.2.3",
|
|
33
33
|
"hono": "^4.10.3",
|
|
34
|
-
"zod": "3.
|
|
34
|
+
"zod": "^3.25.0"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
37
|
"@types/node": "^20.11.17",
|