replicas-engine 0.1.51 → 0.1.53
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 +169 -231
- package/package.json +1 -2
package/dist/src/index.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import "./chunk-ZXMDA7VB.js";
|
|
3
3
|
|
|
4
4
|
// src/index.ts
|
|
5
|
-
import "dotenv/config";
|
|
6
5
|
import { serve } from "@hono/node-server";
|
|
7
6
|
import { Hono as Hono2 } from "hono";
|
|
8
7
|
import { readFile as readFile9 } from "fs/promises";
|
|
@@ -44,35 +43,36 @@ function requireValidURL(value, name) {
|
|
|
44
43
|
throw new Error(`Invalid engine environment: ${name} must be a valid URL`);
|
|
45
44
|
}
|
|
46
45
|
}
|
|
46
|
+
var IS_WARMING_MODE = process.argv.includes("--warming");
|
|
47
47
|
function loadEngineEnv() {
|
|
48
|
-
const HOME_DIR =
|
|
49
|
-
|
|
50
|
-
//
|
|
48
|
+
const HOME_DIR = homedir();
|
|
49
|
+
const env = {
|
|
50
|
+
// Defined: always available
|
|
51
51
|
REPLICAS_ENGINE_SECRET: requireDefined(readEnv("REPLICAS_ENGINE_SECRET"), "REPLICAS_ENGINE_SECRET"),
|
|
52
|
-
WORKSPACE_ID: requireDefined(readEnv("WORKSPACE_ID"), "WORKSPACE_ID"),
|
|
53
|
-
MONOLITH_URL: requireValidURL(requireDefined(readEnv("MONOLITH_URL"), "MONOLITH_URL"), "MONOLITH_URL"),
|
|
54
|
-
// Engine config defaults.
|
|
55
52
|
REPLICAS_ENGINE_PORT: parsePort(readEnv("REPLICAS_ENGINE_PORT")),
|
|
53
|
+
MONOLITH_URL: requireValidURL(requireDefined(readEnv("MONOLITH_URL"), "MONOLITH_URL"), "MONOLITH_URL"),
|
|
54
|
+
GH_TOKEN: readEnv("GH_TOKEN"),
|
|
56
55
|
HOME_DIR,
|
|
57
56
|
WORKSPACE_ROOT: join(HOME_DIR, "workspaces"),
|
|
58
|
-
//
|
|
57
|
+
// Runtime: may not be set during warming
|
|
58
|
+
WORKSPACE_ID: readEnv("WORKSPACE_ID"),
|
|
59
59
|
WORKSPACE_NAME: readEnv("WORKSPACE_NAME"),
|
|
60
60
|
LINEAR_SESSION_ID: readEnv("LINEAR_SESSION_ID"),
|
|
61
61
|
LINEAR_ACCESS_TOKEN: readEnv("LINEAR_ACCESS_TOKEN"),
|
|
62
62
|
SLACK_BOT_TOKEN: readEnv("SLACK_BOT_TOKEN"),
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// not directly used by the engine code, but are required in the VM
|
|
66
|
-
// for use by the agent or SDKs (e.g claude/codex)
|
|
63
|
+
SLACK_CHANNEL_ID: readEnv("SLACK_CHANNEL_ID"),
|
|
64
|
+
SLACK_THREAD_TS: readEnv("SLACK_THREAD_TS"),
|
|
67
65
|
ANTHROPIC_API_KEY: readEnv("ANTHROPIC_API_KEY"),
|
|
68
66
|
OPENAI_API_KEY: readEnv("OPENAI_API_KEY"),
|
|
69
67
|
CLAUDE_CODE_USE_BEDROCK: readEnv("CLAUDE_CODE_USE_BEDROCK"),
|
|
70
68
|
AWS_ACCESS_KEY_ID: readEnv("AWS_ACCESS_KEY_ID"),
|
|
71
69
|
AWS_SECRET_ACCESS_KEY: readEnv("AWS_SECRET_ACCESS_KEY"),
|
|
72
|
-
AWS_REGION: readEnv("AWS_REGION")
|
|
73
|
-
SLACK_CHANNEL_ID: readEnv("SLACK_CHANNEL_ID"),
|
|
74
|
-
SLACK_THREAD_TS: readEnv("SLACK_THREAD_TS")
|
|
70
|
+
AWS_REGION: readEnv("AWS_REGION")
|
|
75
71
|
};
|
|
72
|
+
if (!IS_WARMING_MODE && !env.WORKSPACE_ID) {
|
|
73
|
+
console.error("WORKSPACE_ID is not set \u2014 this is required in normal (non-warming) mode");
|
|
74
|
+
}
|
|
75
|
+
return env;
|
|
76
76
|
}
|
|
77
77
|
var ENGINE_ENV = loadEngineEnv();
|
|
78
78
|
|
|
@@ -96,7 +96,7 @@ var BaseRefreshManager = class {
|
|
|
96
96
|
if (this.intervalHandle) {
|
|
97
97
|
return;
|
|
98
98
|
}
|
|
99
|
-
const skipReason = this.
|
|
99
|
+
const skipReason = this.getSkipReason();
|
|
100
100
|
if (skipReason) {
|
|
101
101
|
console.log(`[${this.managerName}] Skipping: ${skipReason}`);
|
|
102
102
|
return;
|
|
@@ -127,21 +127,17 @@ var BaseRefreshManager = class {
|
|
|
127
127
|
return null;
|
|
128
128
|
}
|
|
129
129
|
getRuntimeConfig() {
|
|
130
|
+
if (!ENGINE_ENV.WORKSPACE_ID) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
130
133
|
return {
|
|
131
134
|
monolithUrl: ENGINE_ENV.MONOLITH_URL,
|
|
132
135
|
workspaceId: ENGINE_ENV.WORKSPACE_ID,
|
|
133
136
|
engineSecret: ENGINE_ENV.REPLICAS_ENGINE_SECRET
|
|
134
137
|
};
|
|
135
138
|
}
|
|
136
|
-
getSkipReasonForRun() {
|
|
137
|
-
const skipReason = this.getSkipReason();
|
|
138
|
-
if (skipReason) {
|
|
139
|
-
return skipReason;
|
|
140
|
-
}
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
139
|
async refreshOnce() {
|
|
144
|
-
if (this.
|
|
140
|
+
if (this.getSkipReason()) {
|
|
145
141
|
return;
|
|
146
142
|
}
|
|
147
143
|
const config = this.getRuntimeConfig();
|
|
@@ -829,11 +825,13 @@ var EngineLogger = class {
|
|
|
829
825
|
};
|
|
830
826
|
var engineLogger = new EngineLogger();
|
|
831
827
|
|
|
832
|
-
// src/services/
|
|
833
|
-
import {
|
|
834
|
-
import { existsSync as
|
|
835
|
-
import {
|
|
836
|
-
import {
|
|
828
|
+
// src/services/replicas-config-service.ts
|
|
829
|
+
import { readFile as readFile3, appendFile as appendFile2, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
|
|
830
|
+
import { existsSync as existsSync4 } from "fs";
|
|
831
|
+
import { join as join6 } from "path";
|
|
832
|
+
import { homedir as homedir5 } from "os";
|
|
833
|
+
import { exec } from "child_process";
|
|
834
|
+
import { promisify as promisify2 } from "util";
|
|
837
835
|
|
|
838
836
|
// ../shared/src/sandbox.ts
|
|
839
837
|
var SANDBOX_LIFECYCLE = {
|
|
@@ -842,6 +840,14 @@ var SANDBOX_LIFECYCLE = {
|
|
|
842
840
|
AUTO_DELETE_MINUTES: -1,
|
|
843
841
|
SSH_TOKEN_EXPIRATION_MINUTES: 3 * 60
|
|
844
842
|
};
|
|
843
|
+
var SANDBOX_PATHS = {
|
|
844
|
+
HOME_DIR: "/home/ubuntu",
|
|
845
|
+
WORKSPACES_DIR: "/home/ubuntu/workspaces",
|
|
846
|
+
REPLICAS_DIR: "/home/ubuntu/.replicas",
|
|
847
|
+
REPLICAS_FILES_DIR: "/home/ubuntu/.replicas/files",
|
|
848
|
+
REPLICAS_FILES_DISPLAY_DIR: "~/.replicas/files",
|
|
849
|
+
REPLICAS_RUNTIME_ENV_FILE: "/home/ubuntu/.replicas/runtime-env.sh"
|
|
850
|
+
};
|
|
845
851
|
|
|
846
852
|
// ../shared/src/warm-hooks.ts
|
|
847
853
|
var DEFAULT_WARM_HOOK_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
@@ -911,34 +917,18 @@ var WORKSPACE_FILE_UPLOAD_MAX_SIZE_BYTES = 20 * 1024 * 1024;
|
|
|
911
917
|
var WORKSPACE_FILE_CONTENT_MAX_SIZE_BYTES = 1 * 1024 * 1024;
|
|
912
918
|
|
|
913
919
|
// src/services/environment-details-service.ts
|
|
914
|
-
|
|
915
|
-
|
|
920
|
+
import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile3 } from "fs/promises";
|
|
921
|
+
import { existsSync as existsSync3 } from "fs";
|
|
922
|
+
import { homedir as homedir4 } from "os";
|
|
923
|
+
import { join as join5 } from "path";
|
|
924
|
+
import { execFile } from "child_process";
|
|
925
|
+
import { promisify } from "util";
|
|
926
|
+
var execFileAsync = promisify(execFile);
|
|
927
|
+
var REPLICAS_DIR = SANDBOX_PATHS.REPLICAS_DIR;
|
|
928
|
+
var DETAILS_FILE = join5(REPLICAS_DIR, "environment-details.json");
|
|
916
929
|
var CLAUDE_CREDENTIALS_PATH = join5(homedir4(), ".claude", ".credentials.json");
|
|
917
930
|
var CODEX_AUTH_PATH = join5(homedir4(), ".codex", "auth.json");
|
|
918
|
-
function
|
|
919
|
-
return { status, details: details ?? null };
|
|
920
|
-
}
|
|
921
|
-
function createDefaultDetails() {
|
|
922
|
-
return {
|
|
923
|
-
engineVersion: REPLICAS_ENGINE_VERSION,
|
|
924
|
-
globalWarmHookCompleted: createExecutionItem("n/a"),
|
|
925
|
-
repositories: [],
|
|
926
|
-
filesUploaded: [],
|
|
927
|
-
envVarsSet: [],
|
|
928
|
-
skillsInstalled: [],
|
|
929
|
-
runtimeEnvVarsSet: [],
|
|
930
|
-
repositoriesCloned: [],
|
|
931
|
-
gitIdentityConfigured: false,
|
|
932
|
-
githubCredentialsConfigured: false,
|
|
933
|
-
linearAccessConfigured: false,
|
|
934
|
-
slackAccessConfigured: false,
|
|
935
|
-
githubAccessConfigured: false,
|
|
936
|
-
claudeAuthMethod: "none",
|
|
937
|
-
codexAuthMethod: "none",
|
|
938
|
-
lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
939
|
-
};
|
|
940
|
-
}
|
|
941
|
-
function getClaudeAuthMethod() {
|
|
931
|
+
function detectClaudeAuthMethod() {
|
|
942
932
|
if (existsSync3(CLAUDE_CREDENTIALS_PATH)) {
|
|
943
933
|
return "oauth";
|
|
944
934
|
}
|
|
@@ -950,7 +940,7 @@ function getClaudeAuthMethod() {
|
|
|
950
940
|
}
|
|
951
941
|
return "none";
|
|
952
942
|
}
|
|
953
|
-
function
|
|
943
|
+
function detectCodexAuthMethod() {
|
|
954
944
|
if (existsSync3(CODEX_AUTH_PATH)) {
|
|
955
945
|
return "oauth";
|
|
956
946
|
}
|
|
@@ -959,133 +949,129 @@ function getCodexAuthMethod() {
|
|
|
959
949
|
}
|
|
960
950
|
return "none";
|
|
961
951
|
}
|
|
962
|
-
function
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
linearAccessConfigured: Boolean(ENGINE_ENV.LINEAR_SESSION_ID || ENGINE_ENV.LINEAR_ACCESS_TOKEN),
|
|
969
|
-
slackAccessConfigured: Boolean(ENGINE_ENV.SLACK_BOT_TOKEN),
|
|
970
|
-
githubAccessConfigured: Boolean(ENGINE_ENV.GH_TOKEN),
|
|
971
|
-
githubCredentialsConfigured: Boolean(ENGINE_ENV.GH_TOKEN),
|
|
972
|
-
claudeAuthMethod,
|
|
973
|
-
codexAuthMethod
|
|
974
|
-
};
|
|
975
|
-
}
|
|
976
|
-
function mergeUnique(current, incoming) {
|
|
977
|
-
if (!incoming || incoming.length === 0) {
|
|
978
|
-
return current;
|
|
952
|
+
async function detectGitIdentityConfigured() {
|
|
953
|
+
try {
|
|
954
|
+
const { stdout } = await execFileAsync("git", ["config", "--global", "user.name"]);
|
|
955
|
+
return stdout.trim().length > 0;
|
|
956
|
+
} catch {
|
|
957
|
+
return false;
|
|
979
958
|
}
|
|
980
|
-
return Array.from(/* @__PURE__ */ new Set([...current, ...incoming]));
|
|
981
959
|
}
|
|
982
960
|
function upsertRepositoryStatus(current, incoming) {
|
|
983
|
-
const byName = new Map(current.map((
|
|
984
|
-
for (const
|
|
985
|
-
const existing = byName.get(
|
|
986
|
-
byName.set(
|
|
987
|
-
repositoryName:
|
|
988
|
-
warmHookCompleted:
|
|
989
|
-
startHookCompleted:
|
|
961
|
+
const byName = new Map(current.map((r) => [r.repositoryName, r]));
|
|
962
|
+
for (const repo of incoming) {
|
|
963
|
+
const existing = byName.get(repo.repositoryName);
|
|
964
|
+
byName.set(repo.repositoryName, {
|
|
965
|
+
repositoryName: repo.repositoryName,
|
|
966
|
+
warmHookCompleted: repo.warmHookCompleted !== "n/a" ? repo.warmHookCompleted : existing?.warmHookCompleted ?? "n/a",
|
|
967
|
+
startHookCompleted: repo.startHookCompleted !== "n/a" ? repo.startHookCompleted : existing?.startHookCompleted ?? "n/a"
|
|
990
968
|
});
|
|
991
969
|
}
|
|
992
970
|
return [...byName.values()].sort((a, b) => a.repositoryName.localeCompare(b.repositoryName));
|
|
993
971
|
}
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
972
|
+
function createDefaultDetails() {
|
|
973
|
+
return {
|
|
974
|
+
engineVersion: REPLICAS_ENGINE_VERSION,
|
|
975
|
+
globalWarmHookCompleted: { status: "n/a", details: null },
|
|
976
|
+
repositories: [],
|
|
977
|
+
filesUploaded: [],
|
|
978
|
+
envVarsSet: [],
|
|
979
|
+
skillsInstalled: [],
|
|
980
|
+
gitIdentityConfigured: false,
|
|
981
|
+
githubCredentialsConfigured: false,
|
|
982
|
+
linearAccessConfigured: false,
|
|
983
|
+
slackAccessConfigured: false,
|
|
984
|
+
githubAccessConfigured: false,
|
|
985
|
+
claudeAuthMethod: "none",
|
|
986
|
+
codexAuthMethod: "none",
|
|
987
|
+
lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
988
|
+
};
|
|
989
|
+
}
|
|
990
|
+
async function readDetails() {
|
|
991
|
+
try {
|
|
992
|
+
if (!existsSync3(DETAILS_FILE)) {
|
|
993
|
+
return createDefaultDetails();
|
|
994
|
+
}
|
|
995
|
+
const raw = await readFile2(DETAILS_FILE, "utf-8");
|
|
996
|
+
const parsed = JSON.parse(raw);
|
|
997
|
+
return { ...createDefaultDetails(), ...parsed };
|
|
998
|
+
} catch {
|
|
999
|
+
return createDefaultDetails();
|
|
1012
1000
|
}
|
|
1001
|
+
}
|
|
1002
|
+
async function writeDetails(details) {
|
|
1003
|
+
await mkdir3(REPLICAS_DIR, { recursive: true });
|
|
1004
|
+
await writeFile3(DETAILS_FILE, `${JSON.stringify(details, null, 2)}
|
|
1005
|
+
`, "utf-8");
|
|
1006
|
+
}
|
|
1007
|
+
var EnvironmentDetailsService = class {
|
|
1013
1008
|
async getDetails() {
|
|
1014
|
-
const
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1009
|
+
const [details, repositories, gitIdentityConfigured] = await Promise.all([
|
|
1010
|
+
readDetails(),
|
|
1011
|
+
gitService.listRepositories(),
|
|
1012
|
+
detectGitIdentityConfigured()
|
|
1013
|
+
]);
|
|
1014
|
+
details.engineVersion = REPLICAS_ENGINE_VERSION;
|
|
1015
|
+
details.claudeAuthMethod = detectClaudeAuthMethod();
|
|
1016
|
+
details.codexAuthMethod = detectCodexAuthMethod();
|
|
1017
|
+
details.gitIdentityConfigured = gitIdentityConfigured;
|
|
1018
|
+
details.githubAccessConfigured = Boolean(ENGINE_ENV.GH_TOKEN);
|
|
1019
|
+
details.githubCredentialsConfigured = Boolean(ENGINE_ENV.GH_TOKEN);
|
|
1020
|
+
details.linearAccessConfigured = Boolean(ENGINE_ENV.LINEAR_SESSION_ID || ENGINE_ENV.LINEAR_ACCESS_TOKEN);
|
|
1021
|
+
details.slackAccessConfigured = Boolean(ENGINE_ENV.SLACK_BOT_TOKEN);
|
|
1022
|
+
const freshRepos = repositories.map((repo) => ({
|
|
1023
|
+
repositoryName: repo.name,
|
|
1024
|
+
warmHookCompleted: "n/a",
|
|
1025
|
+
startHookCompleted: "n/a"
|
|
1026
|
+
}));
|
|
1027
|
+
details.repositories = upsertRepositoryStatus(details.repositories, freshRepos);
|
|
1028
|
+
return details;
|
|
1029
|
+
}
|
|
1030
|
+
async trackEnvironment(req) {
|
|
1031
|
+
const details = await readDetails();
|
|
1032
|
+
if (req.filesUploaded) {
|
|
1033
|
+
details.filesUploaded = req.filesUploaded;
|
|
1034
|
+
}
|
|
1035
|
+
if (req.envVarsSet) {
|
|
1036
|
+
details.envVarsSet = req.envVarsSet;
|
|
1037
|
+
}
|
|
1038
|
+
if (req.skillsInstalled) {
|
|
1039
|
+
details.skillsInstalled = req.skillsInstalled;
|
|
1040
|
+
}
|
|
1041
|
+
details.lastUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1042
|
+
await writeDetails(details);
|
|
1035
1043
|
}
|
|
1036
1044
|
async setGlobalWarmHook(status, details) {
|
|
1037
|
-
await
|
|
1038
|
-
|
|
1039
|
-
|
|
1045
|
+
const current = await readDetails();
|
|
1046
|
+
current.globalWarmHookCompleted = { status, details: details ?? null };
|
|
1047
|
+
current.lastUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1048
|
+
await writeDetails(current);
|
|
1040
1049
|
}
|
|
1041
1050
|
async setRepositoryWarmHook(repositoryName, status) {
|
|
1042
|
-
await
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1051
|
+
const current = await readDetails();
|
|
1052
|
+
current.repositories = upsertRepositoryStatus(current.repositories, [{
|
|
1053
|
+
repositoryName,
|
|
1054
|
+
warmHookCompleted: status,
|
|
1055
|
+
startHookCompleted: "n/a"
|
|
1056
|
+
}]);
|
|
1057
|
+
current.lastUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1058
|
+
await writeDetails(current);
|
|
1049
1059
|
}
|
|
1050
1060
|
async setRepositoryStartHook(repositoryName, status) {
|
|
1051
|
-
await
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
async readDetails() {
|
|
1060
|
-
try {
|
|
1061
|
-
if (!existsSync3(ENVIRONMENT_DETAILS_FILE)) {
|
|
1062
|
-
return createDefaultDetails();
|
|
1063
|
-
}
|
|
1064
|
-
const raw = await readFile2(ENVIRONMENT_DETAILS_FILE, "utf-8");
|
|
1065
|
-
return getLiveDetails({
|
|
1066
|
-
...createDefaultDetails(),
|
|
1067
|
-
...JSON.parse(raw)
|
|
1068
|
-
});
|
|
1069
|
-
} catch {
|
|
1070
|
-
return createDefaultDetails();
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
async writeDetails(details) {
|
|
1074
|
-
await mkdir3(REPLICAS_DIR, { recursive: true });
|
|
1075
|
-
await writeFile3(ENVIRONMENT_DETAILS_FILE, `${JSON.stringify(details, null, 2)}
|
|
1076
|
-
`, "utf-8");
|
|
1061
|
+
const current = await readDetails();
|
|
1062
|
+
current.repositories = upsertRepositoryStatus(current.repositories, [{
|
|
1063
|
+
repositoryName,
|
|
1064
|
+
warmHookCompleted: "n/a",
|
|
1065
|
+
startHookCompleted: status
|
|
1066
|
+
}]);
|
|
1067
|
+
current.lastUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1068
|
+
await writeDetails(current);
|
|
1077
1069
|
}
|
|
1078
1070
|
};
|
|
1079
1071
|
var environmentDetailsService = new EnvironmentDetailsService();
|
|
1080
1072
|
|
|
1081
1073
|
// src/services/replicas-config-service.ts
|
|
1082
|
-
|
|
1083
|
-
import { existsSync as existsSync4 } from "fs";
|
|
1084
|
-
import { join as join6 } from "path";
|
|
1085
|
-
import { homedir as homedir5 } from "os";
|
|
1086
|
-
import { exec } from "child_process";
|
|
1087
|
-
import { promisify } from "util";
|
|
1088
|
-
var execAsync = promisify(exec);
|
|
1074
|
+
var execAsync = promisify2(exec);
|
|
1089
1075
|
var START_HOOKS_LOG = join6(homedir5(), ".replicas", "startHooks.log");
|
|
1090
1076
|
var START_HOOKS_RUNNING_PROMPT = `IMPORTANT - Start Hooks Running:
|
|
1091
1077
|
Start hooks are shell commands/scripts set by repository owners that run on workspace startup.
|
|
@@ -1430,6 +1416,9 @@ async function readJSONL(filePath) {
|
|
|
1430
1416
|
// src/services/monolith-service.ts
|
|
1431
1417
|
var MonolithService = class {
|
|
1432
1418
|
async sendEvent(event) {
|
|
1419
|
+
if (!ENGINE_ENV.WORKSPACE_ID) {
|
|
1420
|
+
return;
|
|
1421
|
+
}
|
|
1433
1422
|
try {
|
|
1434
1423
|
const response = await fetch(`${ENGINE_ENV.MONOLITH_URL}/v1/engine/webhook`, {
|
|
1435
1424
|
method: "POST",
|
|
@@ -3017,51 +3006,15 @@ var PlanService = class {
|
|
|
3017
3006
|
var planService = new PlanService();
|
|
3018
3007
|
|
|
3019
3008
|
// src/services/warm-hooks-service.ts
|
|
3020
|
-
import { execFile } from "child_process";
|
|
3021
|
-
import { promisify as
|
|
3009
|
+
import { execFile as execFile2 } from "child_process";
|
|
3010
|
+
import { promisify as promisify3 } from "util";
|
|
3022
3011
|
import { readFile as readFile8 } from "fs/promises";
|
|
3023
3012
|
import { join as join12 } from "path";
|
|
3024
|
-
var
|
|
3025
|
-
async function installSkill(params) {
|
|
3026
|
-
const timeout = clampWarmHookTimeoutMs(params.timeoutMs);
|
|
3027
|
-
try {
|
|
3028
|
-
const { stdout, stderr } = await execFileAsync(
|
|
3029
|
-
"npx",
|
|
3030
|
-
["skills", "add", params.source, "--all", "--global"],
|
|
3031
|
-
{
|
|
3032
|
-
cwd: params.cwd,
|
|
3033
|
-
timeout,
|
|
3034
|
-
maxBuffer: 1024 * 1024,
|
|
3035
|
-
env: process.env
|
|
3036
|
-
}
|
|
3037
|
-
);
|
|
3038
|
-
const combined = [`$ npx skills add ${params.source} --all --global`, stdout ?? "", stderr ?? ""].filter(Boolean).join("\n");
|
|
3039
|
-
return {
|
|
3040
|
-
exitCode: 0,
|
|
3041
|
-
output: truncateWarmHookOutput(combined),
|
|
3042
|
-
timedOut: false
|
|
3043
|
-
};
|
|
3044
|
-
} catch (error) {
|
|
3045
|
-
const execError = error;
|
|
3046
|
-
const timedOut = execError.signal === "SIGTERM" || execError.killed === true;
|
|
3047
|
-
const exitCode = typeof execError.code === "number" ? execError.code : 1;
|
|
3048
|
-
const combined = [
|
|
3049
|
-
`$ npx skills add ${params.source} --all --global`,
|
|
3050
|
-
execError.stdout ?? "",
|
|
3051
|
-
execError.stderr ?? "",
|
|
3052
|
-
execError.message
|
|
3053
|
-
].filter(Boolean).join("\n");
|
|
3054
|
-
return {
|
|
3055
|
-
exitCode,
|
|
3056
|
-
output: truncateWarmHookOutput(combined),
|
|
3057
|
-
timedOut
|
|
3058
|
-
};
|
|
3059
|
-
}
|
|
3060
|
-
}
|
|
3013
|
+
var execFileAsync2 = promisify3(execFile2);
|
|
3061
3014
|
async function executeHookScript(params) {
|
|
3062
3015
|
const timeout = clampWarmHookTimeoutMs(params.timeoutMs);
|
|
3063
3016
|
try {
|
|
3064
|
-
const { stdout, stderr } = await
|
|
3017
|
+
const { stdout, stderr } = await execFileAsync2("bash", ["-lc", params.content], {
|
|
3065
3018
|
cwd: params.cwd,
|
|
3066
3019
|
timeout,
|
|
3067
3020
|
maxBuffer: 1024 * 1024,
|
|
@@ -3122,27 +3075,7 @@ async function collectRepoWarmHooks() {
|
|
|
3122
3075
|
}
|
|
3123
3076
|
async function runWarmHooks(params) {
|
|
3124
3077
|
const outputBlocks = [];
|
|
3125
|
-
const skills = params.skills ?? [];
|
|
3126
3078
|
const orgHook = params.organizationWarmHook?.trim();
|
|
3127
|
-
for (const source of skills) {
|
|
3128
|
-
const installResult = await installSkill({
|
|
3129
|
-
source,
|
|
3130
|
-
cwd: gitService.getWorkspaceRoot(),
|
|
3131
|
-
timeoutMs: params.timeoutMs
|
|
3132
|
-
});
|
|
3133
|
-
outputBlocks.push(installResult.output);
|
|
3134
|
-
if (installResult.exitCode === 0) {
|
|
3135
|
-
await environmentDetailsService.track({ skillsInstalled: [source] });
|
|
3136
|
-
}
|
|
3137
|
-
if (installResult.exitCode !== 0) {
|
|
3138
|
-
await environmentDetailsService.setGlobalWarmHook("no", installResult.output);
|
|
3139
|
-
return {
|
|
3140
|
-
exitCode: installResult.exitCode,
|
|
3141
|
-
output: outputBlocks.join("\n\n"),
|
|
3142
|
-
timedOut: installResult.timedOut
|
|
3143
|
-
};
|
|
3144
|
-
}
|
|
3145
|
-
}
|
|
3146
3079
|
if (orgHook) {
|
|
3147
3080
|
const orgResult = await executeHookScript({
|
|
3148
3081
|
label: "org-warm-hook",
|
|
@@ -3453,11 +3386,11 @@ function createV1Routes(deps) {
|
|
|
3453
3386
|
app2.post("/environment/track", async (c) => {
|
|
3454
3387
|
try {
|
|
3455
3388
|
const body = await c.req.json();
|
|
3456
|
-
|
|
3457
|
-
return c.json(
|
|
3389
|
+
await environmentDetailsService.trackEnvironment(body);
|
|
3390
|
+
return c.json({ success: true });
|
|
3458
3391
|
} catch (error) {
|
|
3459
3392
|
return c.json(
|
|
3460
|
-
jsonError("Failed to track environment
|
|
3393
|
+
jsonError("Failed to track environment", error instanceof Error ? error.message : "Unknown error"),
|
|
3461
3394
|
500
|
|
3462
3395
|
);
|
|
3463
3396
|
}
|
|
@@ -3489,7 +3422,6 @@ function createV1Routes(deps) {
|
|
|
3489
3422
|
// src/index.ts
|
|
3490
3423
|
await engineLogger.initialize();
|
|
3491
3424
|
await eventService.initialize();
|
|
3492
|
-
await environmentDetailsService.initialize();
|
|
3493
3425
|
var READY_MESSAGE = "========= REPLICAS WORKSPACE READY ==========";
|
|
3494
3426
|
var COMPLETION_MESSAGE = "========= REPLICAS WORKSPACE INITIALIZATION COMPLETE ==========";
|
|
3495
3427
|
function checkActiveSSHSessions() {
|
|
@@ -3674,7 +3606,11 @@ serve(
|
|
|
3674
3606
|
port
|
|
3675
3607
|
},
|
|
3676
3608
|
async (info) => {
|
|
3677
|
-
|
|
3609
|
+
if (IS_WARMING_MODE) {
|
|
3610
|
+
console.log(`Replicas Engine running on port ${info.port} (warming mode)`);
|
|
3611
|
+
} else {
|
|
3612
|
+
console.log(`Replicas Engine running on port ${info.port}`);
|
|
3613
|
+
}
|
|
3678
3614
|
const gitResult = await gitService.initializeGitRepository();
|
|
3679
3615
|
if (!gitResult.success) {
|
|
3680
3616
|
console.warn(`Git initialization warning: ${gitResult.error}`);
|
|
@@ -3682,9 +3618,11 @@ serve(
|
|
|
3682
3618
|
await replicasConfigService.initialize();
|
|
3683
3619
|
await chatService.initialize();
|
|
3684
3620
|
engineReady = true;
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3621
|
+
if (!IS_WARMING_MODE) {
|
|
3622
|
+
await githubTokenManager.start();
|
|
3623
|
+
await claudeTokenManager.start();
|
|
3624
|
+
await codexTokenManager.start();
|
|
3625
|
+
}
|
|
3688
3626
|
const repos = await gitService.listRepos();
|
|
3689
3627
|
await eventService.publish({
|
|
3690
3628
|
id: randomUUID4(),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "replicas-engine",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.53",
|
|
4
4
|
"description": "Lightweight API server for Replicas workspaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
"@anthropic-ai/claude-agent-sdk": "^0.2.41",
|
|
31
31
|
"@hono/node-server": "^1.19.5",
|
|
32
32
|
"@openai/codex-sdk": "^0.111.0",
|
|
33
|
-
"dotenv": "^17.2.3",
|
|
34
33
|
"hono": "^4.10.3",
|
|
35
34
|
"smol-toml": "^1.6.0",
|
|
36
35
|
"zod": "^4.0.0"
|