replicas-engine 0.1.21 → 0.1.23
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 +151 -45
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
import "dotenv/config";
|
|
5
5
|
import { serve } from "@hono/node-server";
|
|
6
6
|
import { Hono as Hono3 } from "hono";
|
|
7
|
-
import { readFile as
|
|
7
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
8
8
|
import { execSync as execSync2 } from "child_process";
|
|
9
9
|
|
|
10
10
|
// src/middleware/auth.ts
|
|
@@ -56,9 +56,9 @@ async function readJSONL(filePath) {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
// src/services/codex-manager.ts
|
|
59
|
-
import { readdir, stat, writeFile, mkdir } from "fs/promises";
|
|
60
|
-
import { join } from "path";
|
|
61
|
-
import { homedir } from "os";
|
|
59
|
+
import { readdir, stat, writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
60
|
+
import { join as join2 } from "path";
|
|
61
|
+
import { homedir as homedir2 } from "os";
|
|
62
62
|
|
|
63
63
|
// src/services/monolith-service.ts
|
|
64
64
|
var MonolithService = class {
|
|
@@ -385,6 +385,53 @@ function convertCodexEvent(event, linearSessionId) {
|
|
|
385
385
|
|
|
386
386
|
// src/utils/git.ts
|
|
387
387
|
import { execSync } from "child_process";
|
|
388
|
+
|
|
389
|
+
// src/services/engine-state.ts
|
|
390
|
+
import { readFile as readFile2, writeFile, mkdir } from "fs/promises";
|
|
391
|
+
import { existsSync } from "fs";
|
|
392
|
+
import { join } from "path";
|
|
393
|
+
import { homedir } from "os";
|
|
394
|
+
var STATE_DIR = join(homedir(), ".replicas");
|
|
395
|
+
var STATE_FILE = join(STATE_DIR, "engine-state.json");
|
|
396
|
+
var DEFAULT_STATE = {
|
|
397
|
+
branch: null,
|
|
398
|
+
prUrl: null,
|
|
399
|
+
claudeSessionId: null,
|
|
400
|
+
codexThreadId: null
|
|
401
|
+
};
|
|
402
|
+
async function loadEngineState() {
|
|
403
|
+
try {
|
|
404
|
+
if (!existsSync(STATE_FILE)) {
|
|
405
|
+
return { ...DEFAULT_STATE };
|
|
406
|
+
}
|
|
407
|
+
const content = await readFile2(STATE_FILE, "utf-8");
|
|
408
|
+
const state = JSON.parse(content);
|
|
409
|
+
return {
|
|
410
|
+
...DEFAULT_STATE,
|
|
411
|
+
...state
|
|
412
|
+
};
|
|
413
|
+
} catch (error) {
|
|
414
|
+
console.error("[EngineState] Failed to load state, using defaults:", error);
|
|
415
|
+
return { ...DEFAULT_STATE };
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
async function saveEngineState(state) {
|
|
419
|
+
try {
|
|
420
|
+
await mkdir(STATE_DIR, { recursive: true });
|
|
421
|
+
const currentState = await loadEngineState();
|
|
422
|
+
const newState = {
|
|
423
|
+
...currentState,
|
|
424
|
+
...state
|
|
425
|
+
};
|
|
426
|
+
await writeFile(STATE_FILE, JSON.stringify(newState, null, 2), "utf-8");
|
|
427
|
+
console.log("[EngineState] State saved:", newState);
|
|
428
|
+
} catch (error) {
|
|
429
|
+
console.error("[EngineState] Failed to save state:", error);
|
|
430
|
+
throw error;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// src/utils/git.ts
|
|
388
435
|
var cachedPr = null;
|
|
389
436
|
function runGitCommand(command, cwd) {
|
|
390
437
|
return execSync(command, {
|
|
@@ -443,7 +490,7 @@ function getGitDiff(cwd) {
|
|
|
443
490
|
return null;
|
|
444
491
|
}
|
|
445
492
|
}
|
|
446
|
-
function getPullRequestUrl(cwd) {
|
|
493
|
+
async function getPullRequestUrl(cwd) {
|
|
447
494
|
try {
|
|
448
495
|
const currentBranch = getCurrentBranch(cwd);
|
|
449
496
|
if (!currentBranch) {
|
|
@@ -452,6 +499,14 @@ function getPullRequestUrl(cwd) {
|
|
|
452
499
|
if (cachedPr && cachedPr.branch === currentBranch) {
|
|
453
500
|
return cachedPr.prUrl;
|
|
454
501
|
}
|
|
502
|
+
const persistedState = await loadEngineState();
|
|
503
|
+
if (persistedState.prUrl && persistedState.branch === currentBranch) {
|
|
504
|
+
cachedPr = {
|
|
505
|
+
prUrl: persistedState.prUrl,
|
|
506
|
+
branch: currentBranch
|
|
507
|
+
};
|
|
508
|
+
return cachedPr.prUrl;
|
|
509
|
+
}
|
|
455
510
|
cachedPr = null;
|
|
456
511
|
try {
|
|
457
512
|
const remoteRef = execSync(`git ls-remote --heads origin ${currentBranch}`, {
|
|
@@ -476,6 +531,7 @@ function getPullRequestUrl(cwd) {
|
|
|
476
531
|
prUrl: prInfo,
|
|
477
532
|
branch: currentBranch
|
|
478
533
|
};
|
|
534
|
+
await saveEngineState({ prUrl: prInfo });
|
|
479
535
|
return cachedPr.prUrl;
|
|
480
536
|
}
|
|
481
537
|
} catch {
|
|
@@ -487,11 +543,11 @@ function getPullRequestUrl(cwd) {
|
|
|
487
543
|
return null;
|
|
488
544
|
}
|
|
489
545
|
}
|
|
490
|
-
function getGitStatus(workingDirectory) {
|
|
546
|
+
async function getGitStatus(workingDirectory) {
|
|
491
547
|
return {
|
|
492
548
|
branch: getCurrentBranch(workingDirectory),
|
|
493
549
|
gitDiff: getGitDiff(workingDirectory),
|
|
494
|
-
prUrl: getPullRequestUrl(workingDirectory)
|
|
550
|
+
prUrl: await getPullRequestUrl(workingDirectory)
|
|
495
551
|
};
|
|
496
552
|
}
|
|
497
553
|
|
|
@@ -665,6 +721,7 @@ async function normalizeImages(images) {
|
|
|
665
721
|
}
|
|
666
722
|
|
|
667
723
|
// src/services/codex-manager.ts
|
|
724
|
+
var DEFAULT_MODEL = "gpt-5.1-codex";
|
|
668
725
|
var CodexManager = class {
|
|
669
726
|
codex;
|
|
670
727
|
currentThreadId = null;
|
|
@@ -673,21 +730,30 @@ var CodexManager = class {
|
|
|
673
730
|
messageQueue;
|
|
674
731
|
baseSystemPrompt;
|
|
675
732
|
tempImageDir;
|
|
733
|
+
initialized;
|
|
676
734
|
constructor(workingDirectory) {
|
|
677
735
|
this.codex = new Codex();
|
|
678
736
|
if (workingDirectory) {
|
|
679
737
|
this.workingDirectory = workingDirectory;
|
|
680
738
|
} else {
|
|
681
739
|
const repoName = process.env.REPLICAS_REPO_NAME;
|
|
682
|
-
const workspaceHome = process.env.WORKSPACE_HOME || process.env.HOME ||
|
|
740
|
+
const workspaceHome = process.env.WORKSPACE_HOME || process.env.HOME || homedir2();
|
|
683
741
|
if (repoName) {
|
|
684
|
-
this.workingDirectory =
|
|
742
|
+
this.workingDirectory = join2(workspaceHome, "workspaces", repoName);
|
|
685
743
|
} else {
|
|
686
744
|
this.workingDirectory = workspaceHome;
|
|
687
745
|
}
|
|
688
746
|
}
|
|
689
|
-
this.tempImageDir =
|
|
747
|
+
this.tempImageDir = join2(homedir2(), ".replicas", "codex", "temp-images");
|
|
690
748
|
this.messageQueue = new MessageQueue(this.processMessageInternal.bind(this));
|
|
749
|
+
this.initialized = this.initialize();
|
|
750
|
+
}
|
|
751
|
+
async initialize() {
|
|
752
|
+
const persistedState = await loadEngineState();
|
|
753
|
+
if (persistedState.codexThreadId) {
|
|
754
|
+
this.currentThreadId = persistedState.codexThreadId;
|
|
755
|
+
console.log(`[CodexManager] Restored thread ID from persisted state: ${this.currentThreadId}`);
|
|
756
|
+
}
|
|
691
757
|
}
|
|
692
758
|
isProcessing() {
|
|
693
759
|
return this.messageQueue.isProcessing();
|
|
@@ -698,6 +764,7 @@ var CodexManager = class {
|
|
|
698
764
|
* @returns Object with queued status, messageId, and position in queue
|
|
699
765
|
*/
|
|
700
766
|
async enqueueMessage(message, model, customInstructions, images) {
|
|
767
|
+
await this.initialized;
|
|
701
768
|
return this.messageQueue.enqueue(message, model, customInstructions, images);
|
|
702
769
|
}
|
|
703
770
|
/**
|
|
@@ -731,14 +798,14 @@ var CodexManager = class {
|
|
|
731
798
|
* @returns Array of temp file paths
|
|
732
799
|
*/
|
|
733
800
|
async saveImagesToTempFiles(images) {
|
|
734
|
-
await
|
|
801
|
+
await mkdir2(this.tempImageDir, { recursive: true });
|
|
735
802
|
const tempPaths = [];
|
|
736
803
|
for (const image of images) {
|
|
737
804
|
const ext = image.source.media_type.split("/")[1] || "png";
|
|
738
805
|
const filename = `img_${randomUUID()}.${ext}`;
|
|
739
|
-
const filepath =
|
|
806
|
+
const filepath = join2(this.tempImageDir, filename);
|
|
740
807
|
const buffer = Buffer.from(image.source.data, "base64");
|
|
741
|
-
await
|
|
808
|
+
await writeFile2(filepath, buffer);
|
|
742
809
|
tempPaths.push(filepath);
|
|
743
810
|
}
|
|
744
811
|
return tempPaths;
|
|
@@ -760,14 +827,14 @@ var CodexManager = class {
|
|
|
760
827
|
workingDirectory: this.workingDirectory,
|
|
761
828
|
skipGitRepoCheck: true,
|
|
762
829
|
sandboxMode: "danger-full-access",
|
|
763
|
-
model: model ||
|
|
830
|
+
model: model || DEFAULT_MODEL
|
|
764
831
|
});
|
|
765
832
|
} else {
|
|
766
833
|
this.currentThread = this.codex.startThread({
|
|
767
834
|
workingDirectory: this.workingDirectory,
|
|
768
835
|
skipGitRepoCheck: true,
|
|
769
836
|
sandboxMode: "danger-full-access",
|
|
770
|
-
model: model ||
|
|
837
|
+
model: model || DEFAULT_MODEL
|
|
771
838
|
});
|
|
772
839
|
let combinedInstructions;
|
|
773
840
|
if (this.baseSystemPrompt && customInstructions) {
|
|
@@ -784,11 +851,14 @@ ${customInstructions}`;
|
|
|
784
851
|
for await (const event of events2) {
|
|
785
852
|
if (event.type === "thread.started") {
|
|
786
853
|
this.currentThreadId = event.thread_id;
|
|
787
|
-
|
|
854
|
+
await saveEngineState({ codexThreadId: this.currentThreadId });
|
|
855
|
+
console.log(`[CodexManager] Captured and persisted thread ID: ${this.currentThreadId}`);
|
|
788
856
|
}
|
|
789
857
|
}
|
|
790
858
|
if (!this.currentThreadId && this.currentThread.id) {
|
|
791
859
|
this.currentThreadId = this.currentThread.id;
|
|
860
|
+
await saveEngineState({ codexThreadId: this.currentThreadId });
|
|
861
|
+
console.log(`[CodexManager] Captured and persisted thread ID from thread.id: ${this.currentThreadId}`);
|
|
792
862
|
}
|
|
793
863
|
}
|
|
794
864
|
}
|
|
@@ -814,7 +884,7 @@ ${customInstructions}`;
|
|
|
814
884
|
}
|
|
815
885
|
} finally {
|
|
816
886
|
if (linearSessionId) {
|
|
817
|
-
const status = getGitStatus(this.workingDirectory);
|
|
887
|
+
const status = await getGitStatus(this.workingDirectory);
|
|
818
888
|
monolithService.sendEvent({ type: "agent_turn_complete", payload: { linearSessionId, status } }).catch(() => {
|
|
819
889
|
});
|
|
820
890
|
}
|
|
@@ -856,6 +926,7 @@ ${customInstructions}`;
|
|
|
856
926
|
this.currentThread = null;
|
|
857
927
|
this.currentThreadId = null;
|
|
858
928
|
this.messageQueue.reset();
|
|
929
|
+
await saveEngineState({ codexThreadId: null });
|
|
859
930
|
}
|
|
860
931
|
getThreadId() {
|
|
861
932
|
return this.currentThreadId;
|
|
@@ -884,13 +955,13 @@ ${customInstructions}`;
|
|
|
884
955
|
}
|
|
885
956
|
// Helper methods for finding session files
|
|
886
957
|
async findSessionFile(threadId) {
|
|
887
|
-
const sessionsDir =
|
|
958
|
+
const sessionsDir = join2(homedir2(), ".codex", "sessions");
|
|
888
959
|
try {
|
|
889
960
|
const now = /* @__PURE__ */ new Date();
|
|
890
961
|
const year = now.getFullYear();
|
|
891
962
|
const month = String(now.getMonth() + 1).padStart(2, "0");
|
|
892
963
|
const day = String(now.getDate()).padStart(2, "0");
|
|
893
|
-
const todayDir =
|
|
964
|
+
const todayDir = join2(sessionsDir, String(year), month, day);
|
|
894
965
|
const file = await this.findFileInDirectory(todayDir, threadId);
|
|
895
966
|
if (file) return file;
|
|
896
967
|
for (let daysAgo = 1; daysAgo <= 7; daysAgo++) {
|
|
@@ -899,7 +970,7 @@ ${customInstructions}`;
|
|
|
899
970
|
const searchYear = date.getFullYear();
|
|
900
971
|
const searchMonth = String(date.getMonth() + 1).padStart(2, "0");
|
|
901
972
|
const searchDay = String(date.getDate()).padStart(2, "0");
|
|
902
|
-
const searchDir =
|
|
973
|
+
const searchDir = join2(sessionsDir, String(searchYear), searchMonth, searchDay);
|
|
903
974
|
const file2 = await this.findFileInDirectory(searchDir, threadId);
|
|
904
975
|
if (file2) return file2;
|
|
905
976
|
}
|
|
@@ -913,7 +984,7 @@ ${customInstructions}`;
|
|
|
913
984
|
const files = await readdir(directory);
|
|
914
985
|
for (const file of files) {
|
|
915
986
|
if (file.endsWith(".jsonl") && file.includes(threadId)) {
|
|
916
|
-
const fullPath =
|
|
987
|
+
const fullPath = join2(directory, file);
|
|
917
988
|
const stats = await stat(fullPath);
|
|
918
989
|
if (stats.isFile()) {
|
|
919
990
|
return fullPath;
|
|
@@ -1055,9 +1126,9 @@ import { Hono as Hono2 } from "hono";
|
|
|
1055
1126
|
import {
|
|
1056
1127
|
query
|
|
1057
1128
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
1058
|
-
import { join as
|
|
1059
|
-
import { mkdir as
|
|
1060
|
-
import { homedir as
|
|
1129
|
+
import { join as join3 } from "path";
|
|
1130
|
+
import { mkdir as mkdir3, appendFile, rm } from "fs/promises";
|
|
1131
|
+
import { homedir as homedir3 } from "os";
|
|
1061
1132
|
var ClaudeManager = class {
|
|
1062
1133
|
workingDirectory;
|
|
1063
1134
|
historyFile;
|
|
@@ -1070,14 +1141,14 @@ var ClaudeManager = class {
|
|
|
1070
1141
|
this.workingDirectory = workingDirectory;
|
|
1071
1142
|
} else {
|
|
1072
1143
|
const repoName = process.env.REPLICAS_REPO_NAME;
|
|
1073
|
-
const workspaceHome = process.env.WORKSPACE_HOME || process.env.HOME ||
|
|
1144
|
+
const workspaceHome = process.env.WORKSPACE_HOME || process.env.HOME || homedir3();
|
|
1074
1145
|
if (repoName) {
|
|
1075
|
-
this.workingDirectory =
|
|
1146
|
+
this.workingDirectory = join3(workspaceHome, "workspaces", repoName);
|
|
1076
1147
|
} else {
|
|
1077
1148
|
this.workingDirectory = workspaceHome;
|
|
1078
1149
|
}
|
|
1079
1150
|
}
|
|
1080
|
-
this.historyFile =
|
|
1151
|
+
this.historyFile = join3(homedir3(), ".replicas", "claude", "history.jsonl");
|
|
1081
1152
|
this.initialized = this.initialize();
|
|
1082
1153
|
this.messageQueue = new MessageQueue(this.processMessageInternal.bind(this));
|
|
1083
1154
|
}
|
|
@@ -1198,7 +1269,7 @@ ${customInstructions}`;
|
|
|
1198
1269
|
}
|
|
1199
1270
|
} finally {
|
|
1200
1271
|
if (linearSessionId) {
|
|
1201
|
-
const status = getGitStatus(this.workingDirectory);
|
|
1272
|
+
const status = await getGitStatus(this.workingDirectory);
|
|
1202
1273
|
monolithService.sendEvent({ type: "agent_turn_complete", payload: { linearSessionId, status } }).catch(() => {
|
|
1203
1274
|
});
|
|
1204
1275
|
}
|
|
@@ -1232,18 +1303,26 @@ ${customInstructions}`;
|
|
|
1232
1303
|
await this.initialized;
|
|
1233
1304
|
this.sessionId = null;
|
|
1234
1305
|
this.messageQueue.reset();
|
|
1306
|
+
await saveEngineState({ claudeSessionId: null });
|
|
1235
1307
|
try {
|
|
1236
1308
|
await rm(this.historyFile, { force: true });
|
|
1237
1309
|
} catch {
|
|
1238
1310
|
}
|
|
1239
1311
|
}
|
|
1240
1312
|
async initialize() {
|
|
1241
|
-
const historyDir =
|
|
1242
|
-
await
|
|
1313
|
+
const historyDir = join3(homedir3(), ".replicas", "claude");
|
|
1314
|
+
await mkdir3(historyDir, { recursive: true });
|
|
1315
|
+
const persistedState = await loadEngineState();
|
|
1316
|
+
if (persistedState.claudeSessionId) {
|
|
1317
|
+
this.sessionId = persistedState.claudeSessionId;
|
|
1318
|
+
console.log(`[ClaudeManager] Restored session ID from persisted state: ${this.sessionId}`);
|
|
1319
|
+
}
|
|
1243
1320
|
}
|
|
1244
1321
|
async handleMessage(message) {
|
|
1245
1322
|
if ("session_id" in message && message.session_id && !this.sessionId) {
|
|
1246
1323
|
this.sessionId = message.session_id;
|
|
1324
|
+
await saveEngineState({ claudeSessionId: this.sessionId });
|
|
1325
|
+
console.log(`[ClaudeManager] Captured and persisted session ID: ${this.sessionId}`);
|
|
1247
1326
|
}
|
|
1248
1327
|
await this.recordEvent(message);
|
|
1249
1328
|
}
|
|
@@ -1637,7 +1716,7 @@ var CodexTokenManager = class {
|
|
|
1637
1716
|
var codexTokenManager = new CodexTokenManager();
|
|
1638
1717
|
|
|
1639
1718
|
// src/services/git-init.ts
|
|
1640
|
-
import { existsSync } from "fs";
|
|
1719
|
+
import { existsSync as existsSync2 } from "fs";
|
|
1641
1720
|
import path4 from "path";
|
|
1642
1721
|
var initializedBranch = null;
|
|
1643
1722
|
function findAvailableBranchName(baseName, cwd) {
|
|
@@ -1673,7 +1752,7 @@ async function initializeGitRepository() {
|
|
|
1673
1752
|
};
|
|
1674
1753
|
}
|
|
1675
1754
|
const repoPath = path4.join(workspaceHome, "workspaces", repoName);
|
|
1676
|
-
if (!
|
|
1755
|
+
if (!existsSync2(repoPath)) {
|
|
1677
1756
|
console.log(`[GitInit] Repository directory does not exist: ${repoPath}`);
|
|
1678
1757
|
console.log("[GitInit] Waiting for initializer to clone the repository...");
|
|
1679
1758
|
return {
|
|
@@ -1681,7 +1760,7 @@ async function initializeGitRepository() {
|
|
|
1681
1760
|
branch: null
|
|
1682
1761
|
};
|
|
1683
1762
|
}
|
|
1684
|
-
if (!
|
|
1763
|
+
if (!existsSync2(path4.join(repoPath, ".git"))) {
|
|
1685
1764
|
return {
|
|
1686
1765
|
success: false,
|
|
1687
1766
|
branch: null,
|
|
@@ -1690,8 +1769,32 @@ async function initializeGitRepository() {
|
|
|
1690
1769
|
}
|
|
1691
1770
|
console.log(`[GitInit] Initializing repository at ${repoPath}`);
|
|
1692
1771
|
try {
|
|
1772
|
+
const persistedState = await loadEngineState();
|
|
1773
|
+
const persistedBranch = persistedState.branch;
|
|
1693
1774
|
console.log("[GitInit] Fetching all remotes...");
|
|
1694
1775
|
runGitCommand("git fetch --all --prune", repoPath);
|
|
1776
|
+
if (persistedBranch && branchExists(persistedBranch, repoPath)) {
|
|
1777
|
+
console.log(`[GitInit] Found persisted branch: ${persistedBranch}`);
|
|
1778
|
+
const currentBranch = getCurrentBranch(repoPath);
|
|
1779
|
+
if (currentBranch === persistedBranch) {
|
|
1780
|
+
console.log(`[GitInit] Already on persisted branch: ${persistedBranch}`);
|
|
1781
|
+
initializedBranch = persistedBranch;
|
|
1782
|
+
return {
|
|
1783
|
+
success: true,
|
|
1784
|
+
branch: persistedBranch,
|
|
1785
|
+
resumed: true
|
|
1786
|
+
};
|
|
1787
|
+
}
|
|
1788
|
+
console.log(`[GitInit] Resuming on persisted branch: ${persistedBranch}`);
|
|
1789
|
+
runGitCommand(`git checkout ${persistedBranch}`, repoPath);
|
|
1790
|
+
initializedBranch = persistedBranch;
|
|
1791
|
+
console.log(`[GitInit] Successfully resumed on branch: ${persistedBranch}`);
|
|
1792
|
+
return {
|
|
1793
|
+
success: true,
|
|
1794
|
+
branch: persistedBranch,
|
|
1795
|
+
resumed: true
|
|
1796
|
+
};
|
|
1797
|
+
}
|
|
1695
1798
|
console.log(`[GitInit] Checking out default branch: ${defaultBranch}`);
|
|
1696
1799
|
runGitCommand(`git checkout ${defaultBranch}`, repoPath);
|
|
1697
1800
|
console.log("[GitInit] Pulling latest changes...");
|
|
@@ -1707,10 +1810,12 @@ async function initializeGitRepository() {
|
|
|
1707
1810
|
console.log(`[GitInit] Creating workspace branch: ${branchName}`);
|
|
1708
1811
|
runGitCommand(`git checkout -b ${branchName}`, repoPath);
|
|
1709
1812
|
initializedBranch = branchName;
|
|
1813
|
+
await saveEngineState({ branch: branchName });
|
|
1710
1814
|
console.log(`[GitInit] Successfully initialized on branch: ${branchName}`);
|
|
1711
1815
|
return {
|
|
1712
1816
|
success: true,
|
|
1713
|
-
branch: branchName
|
|
1817
|
+
branch: branchName,
|
|
1818
|
+
resumed: false
|
|
1714
1819
|
};
|
|
1715
1820
|
} catch (error) {
|
|
1716
1821
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
@@ -1724,10 +1829,10 @@ async function initializeGitRepository() {
|
|
|
1724
1829
|
}
|
|
1725
1830
|
|
|
1726
1831
|
// src/services/replicas-config.ts
|
|
1727
|
-
import { readFile as
|
|
1728
|
-
import { existsSync as
|
|
1729
|
-
import { join as
|
|
1730
|
-
import { homedir as
|
|
1832
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
1833
|
+
import { existsSync as existsSync3 } from "fs";
|
|
1834
|
+
import { join as join4 } from "path";
|
|
1835
|
+
import { homedir as homedir4 } from "os";
|
|
1731
1836
|
import { exec } from "child_process";
|
|
1732
1837
|
import { promisify } from "util";
|
|
1733
1838
|
var execAsync = promisify(exec);
|
|
@@ -1737,9 +1842,9 @@ var ReplicasConfigService = class {
|
|
|
1737
1842
|
hooksExecuted = false;
|
|
1738
1843
|
constructor() {
|
|
1739
1844
|
const repoName = process.env.REPLICAS_REPO_NAME;
|
|
1740
|
-
const workspaceHome = process.env.WORKSPACE_HOME || process.env.HOME ||
|
|
1845
|
+
const workspaceHome = process.env.WORKSPACE_HOME || process.env.HOME || homedir4();
|
|
1741
1846
|
if (repoName) {
|
|
1742
|
-
this.workingDirectory =
|
|
1847
|
+
this.workingDirectory = join4(workspaceHome, "workspaces", repoName);
|
|
1743
1848
|
} else {
|
|
1744
1849
|
this.workingDirectory = workspaceHome;
|
|
1745
1850
|
}
|
|
@@ -1755,14 +1860,14 @@ var ReplicasConfigService = class {
|
|
|
1755
1860
|
* Load and parse the replicas.json config file
|
|
1756
1861
|
*/
|
|
1757
1862
|
async loadConfig() {
|
|
1758
|
-
const configPath =
|
|
1759
|
-
if (!
|
|
1863
|
+
const configPath = join4(this.workingDirectory, "replicas.json");
|
|
1864
|
+
if (!existsSync3(configPath)) {
|
|
1760
1865
|
console.log("No replicas.json found in workspace directory");
|
|
1761
1866
|
this.config = null;
|
|
1762
1867
|
return;
|
|
1763
1868
|
}
|
|
1764
1869
|
try {
|
|
1765
|
-
const data = await
|
|
1870
|
+
const data = await readFile3(configPath, "utf-8");
|
|
1766
1871
|
const config = JSON.parse(data);
|
|
1767
1872
|
if (config.copy && !Array.isArray(config.copy)) {
|
|
1768
1873
|
throw new Error('Invalid replicas.json: "copy" must be an array of file paths');
|
|
@@ -1880,7 +1985,7 @@ function checkActiveSSHSessions() {
|
|
|
1880
1985
|
var app = new Hono3();
|
|
1881
1986
|
app.get("/health", async (c) => {
|
|
1882
1987
|
try {
|
|
1883
|
-
const logContent = await
|
|
1988
|
+
const logContent = await readFile4("/var/log/cloud-init-output.log", "utf-8");
|
|
1884
1989
|
let status;
|
|
1885
1990
|
if (logContent.includes(COMPLETION_MESSAGE)) {
|
|
1886
1991
|
status = "active";
|
|
@@ -1905,13 +2010,14 @@ app.get("/status", async (c) => {
|
|
|
1905
2010
|
const claudeStatus = await claudeManager.getStatus();
|
|
1906
2011
|
const workingDirectory = claudeStatus.working_directory;
|
|
1907
2012
|
const hasActiveSSHSessions = checkActiveSSHSessions();
|
|
2013
|
+
const gitStatus = await getGitStatus(workingDirectory);
|
|
1908
2014
|
return c.json({
|
|
1909
2015
|
isCodexProcessing,
|
|
1910
2016
|
isClaudeProcessing,
|
|
1911
2017
|
isCodexUsed,
|
|
1912
2018
|
isClaudeUsed,
|
|
1913
2019
|
hasActiveSSHSessions,
|
|
1914
|
-
...
|
|
2020
|
+
...gitStatus,
|
|
1915
2021
|
linearBetaEnabled: true
|
|
1916
2022
|
// TODO: delete
|
|
1917
2023
|
});
|