replicas-engine 0.1.50 → 0.1.52
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 +211 -154
- package/package.json +1 -1
- package/dist/tsup.config.js +0 -28
package/dist/src/index.js
CHANGED
|
@@ -44,35 +44,36 @@ function requireValidURL(value, name) {
|
|
|
44
44
|
throw new Error(`Invalid engine environment: ${name} must be a valid URL`);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
+
var IS_WARMING_MODE = process.argv.includes("--warming");
|
|
47
48
|
function loadEngineEnv() {
|
|
48
|
-
const HOME_DIR =
|
|
49
|
-
|
|
50
|
-
//
|
|
49
|
+
const HOME_DIR = homedir();
|
|
50
|
+
const env = {
|
|
51
|
+
// Defined: always available
|
|
51
52
|
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
53
|
REPLICAS_ENGINE_PORT: parsePort(readEnv("REPLICAS_ENGINE_PORT")),
|
|
54
|
+
MONOLITH_URL: requireValidURL(requireDefined(readEnv("MONOLITH_URL"), "MONOLITH_URL"), "MONOLITH_URL"),
|
|
55
|
+
GH_TOKEN: readEnv("GH_TOKEN"),
|
|
56
56
|
HOME_DIR,
|
|
57
57
|
WORKSPACE_ROOT: join(HOME_DIR, "workspaces"),
|
|
58
|
-
//
|
|
58
|
+
// Runtime: may not be set during warming
|
|
59
|
+
WORKSPACE_ID: readEnv("WORKSPACE_ID"),
|
|
59
60
|
WORKSPACE_NAME: readEnv("WORKSPACE_NAME"),
|
|
60
61
|
LINEAR_SESSION_ID: readEnv("LINEAR_SESSION_ID"),
|
|
61
62
|
LINEAR_ACCESS_TOKEN: readEnv("LINEAR_ACCESS_TOKEN"),
|
|
62
63
|
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)
|
|
64
|
+
SLACK_CHANNEL_ID: readEnv("SLACK_CHANNEL_ID"),
|
|
65
|
+
SLACK_THREAD_TS: readEnv("SLACK_THREAD_TS"),
|
|
67
66
|
ANTHROPIC_API_KEY: readEnv("ANTHROPIC_API_KEY"),
|
|
68
67
|
OPENAI_API_KEY: readEnv("OPENAI_API_KEY"),
|
|
69
68
|
CLAUDE_CODE_USE_BEDROCK: readEnv("CLAUDE_CODE_USE_BEDROCK"),
|
|
70
69
|
AWS_ACCESS_KEY_ID: readEnv("AWS_ACCESS_KEY_ID"),
|
|
71
70
|
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")
|
|
71
|
+
AWS_REGION: readEnv("AWS_REGION")
|
|
75
72
|
};
|
|
73
|
+
if (!IS_WARMING_MODE && !env.WORKSPACE_ID) {
|
|
74
|
+
console.error("WORKSPACE_ID is not set \u2014 this is required in normal (non-warming) mode");
|
|
75
|
+
}
|
|
76
|
+
return env;
|
|
76
77
|
}
|
|
77
78
|
var ENGINE_ENV = loadEngineEnv();
|
|
78
79
|
|
|
@@ -96,7 +97,7 @@ var BaseRefreshManager = class {
|
|
|
96
97
|
if (this.intervalHandle) {
|
|
97
98
|
return;
|
|
98
99
|
}
|
|
99
|
-
const skipReason = this.
|
|
100
|
+
const skipReason = this.getSkipReason();
|
|
100
101
|
if (skipReason) {
|
|
101
102
|
console.log(`[${this.managerName}] Skipping: ${skipReason}`);
|
|
102
103
|
return;
|
|
@@ -127,21 +128,17 @@ var BaseRefreshManager = class {
|
|
|
127
128
|
return null;
|
|
128
129
|
}
|
|
129
130
|
getRuntimeConfig() {
|
|
131
|
+
if (!ENGINE_ENV.WORKSPACE_ID) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
130
134
|
return {
|
|
131
135
|
monolithUrl: ENGINE_ENV.MONOLITH_URL,
|
|
132
136
|
workspaceId: ENGINE_ENV.WORKSPACE_ID,
|
|
133
137
|
engineSecret: ENGINE_ENV.REPLICAS_ENGINE_SECRET
|
|
134
138
|
};
|
|
135
139
|
}
|
|
136
|
-
getSkipReasonForRun() {
|
|
137
|
-
const skipReason = this.getSkipReason();
|
|
138
|
-
if (skipReason) {
|
|
139
|
-
return skipReason;
|
|
140
|
-
}
|
|
141
|
-
return null;
|
|
142
|
-
}
|
|
143
140
|
async refreshOnce() {
|
|
144
|
-
if (this.
|
|
141
|
+
if (this.getSkipReason()) {
|
|
145
142
|
return;
|
|
146
143
|
}
|
|
147
144
|
const config = this.getRuntimeConfig();
|
|
@@ -830,10 +827,12 @@ var EngineLogger = class {
|
|
|
830
827
|
var engineLogger = new EngineLogger();
|
|
831
828
|
|
|
832
829
|
// src/services/environment-details-service.ts
|
|
833
|
-
import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile3 } from "fs/promises";
|
|
830
|
+
import { mkdir as mkdir3, readdir as readdir2, readFile as readFile2, writeFile as writeFile3 } from "fs/promises";
|
|
834
831
|
import { existsSync as existsSync3 } from "fs";
|
|
835
832
|
import { homedir as homedir4 } from "os";
|
|
836
833
|
import { join as join5 } from "path";
|
|
834
|
+
import { execFile } from "child_process";
|
|
835
|
+
import { promisify } from "util";
|
|
837
836
|
|
|
838
837
|
// ../shared/src/sandbox.ts
|
|
839
838
|
var SANDBOX_LIFECYCLE = {
|
|
@@ -842,6 +841,14 @@ var SANDBOX_LIFECYCLE = {
|
|
|
842
841
|
AUTO_DELETE_MINUTES: -1,
|
|
843
842
|
SSH_TOKEN_EXPIRATION_MINUTES: 3 * 60
|
|
844
843
|
};
|
|
844
|
+
var SANDBOX_PATHS = {
|
|
845
|
+
HOME_DIR: "/home/ubuntu",
|
|
846
|
+
WORKSPACES_DIR: "/home/ubuntu/workspaces",
|
|
847
|
+
REPLICAS_DIR: "/home/ubuntu/.replicas",
|
|
848
|
+
REPLICAS_FILES_DIR: "/home/ubuntu/.replicas/files",
|
|
849
|
+
REPLICAS_FILES_DISPLAY_DIR: "~/.replicas/files",
|
|
850
|
+
REPLICAS_RUNTIME_ENV_FILE: "/home/ubuntu/.replicas/runtime-env.sh"
|
|
851
|
+
};
|
|
845
852
|
|
|
846
853
|
// ../shared/src/warm-hooks.ts
|
|
847
854
|
var DEFAULT_WARM_HOOK_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
@@ -911,137 +918,190 @@ var WORKSPACE_FILE_UPLOAD_MAX_SIZE_BYTES = 20 * 1024 * 1024;
|
|
|
911
918
|
var WORKSPACE_FILE_CONTENT_MAX_SIZE_BYTES = 1 * 1024 * 1024;
|
|
912
919
|
|
|
913
920
|
// src/services/environment-details-service.ts
|
|
914
|
-
var
|
|
915
|
-
var
|
|
916
|
-
|
|
917
|
-
|
|
921
|
+
var execFileAsync = promisify(execFile);
|
|
922
|
+
var REPLICAS_DIR = SANDBOX_PATHS.REPLICAS_DIR;
|
|
923
|
+
var RUNTIME_ENV_FILE = SANDBOX_PATHS.REPLICAS_RUNTIME_ENV_FILE;
|
|
924
|
+
var FILES_DIR = SANDBOX_PATHS.REPLICAS_FILES_DIR;
|
|
925
|
+
var PERSISTED_STATE_FILE = join5(REPLICAS_DIR, "environment-details.json");
|
|
926
|
+
var CLAUDE_CREDENTIALS_PATH = join5(homedir4(), ".claude", ".credentials.json");
|
|
927
|
+
var CODEX_AUTH_PATH = join5(homedir4(), ".codex", "auth.json");
|
|
928
|
+
function detectClaudeAuthMethod() {
|
|
929
|
+
if (existsSync3(CLAUDE_CREDENTIALS_PATH)) {
|
|
930
|
+
return "oauth";
|
|
931
|
+
}
|
|
932
|
+
if (ENGINE_ENV.CLAUDE_CODE_USE_BEDROCK && ENGINE_ENV.AWS_ACCESS_KEY_ID && ENGINE_ENV.AWS_SECRET_ACCESS_KEY) {
|
|
933
|
+
return "bedrock";
|
|
934
|
+
}
|
|
935
|
+
if (ENGINE_ENV.ANTHROPIC_API_KEY) {
|
|
936
|
+
return "api_key";
|
|
937
|
+
}
|
|
938
|
+
return "none";
|
|
939
|
+
}
|
|
940
|
+
function detectCodexAuthMethod() {
|
|
941
|
+
if (existsSync3(CODEX_AUTH_PATH)) {
|
|
942
|
+
return "oauth";
|
|
943
|
+
}
|
|
944
|
+
if (ENGINE_ENV.OPENAI_API_KEY) {
|
|
945
|
+
return "api_key";
|
|
946
|
+
}
|
|
947
|
+
return "none";
|
|
948
|
+
}
|
|
949
|
+
async function detectGitIdentityConfigured() {
|
|
950
|
+
try {
|
|
951
|
+
const { stdout } = await execFileAsync("git", ["config", "--global", "user.name"]);
|
|
952
|
+
return stdout.trim().length > 0;
|
|
953
|
+
} catch {
|
|
954
|
+
return false;
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
async function parseRuntimeEnvKeys() {
|
|
958
|
+
try {
|
|
959
|
+
if (!existsSync3(RUNTIME_ENV_FILE)) {
|
|
960
|
+
return [];
|
|
961
|
+
}
|
|
962
|
+
const content = await readFile2(RUNTIME_ENV_FILE, "utf-8");
|
|
963
|
+
const keys = [];
|
|
964
|
+
for (const line of content.split("\n")) {
|
|
965
|
+
const trimmed = line.trim();
|
|
966
|
+
if (!trimmed.startsWith("export ")) {
|
|
967
|
+
continue;
|
|
968
|
+
}
|
|
969
|
+
const assignment = trimmed.slice("export ".length);
|
|
970
|
+
const eqIndex = assignment.indexOf("=");
|
|
971
|
+
if (eqIndex > 0) {
|
|
972
|
+
const key = assignment.slice(0, eqIndex).trim();
|
|
973
|
+
if (key) {
|
|
974
|
+
keys.push(key);
|
|
975
|
+
}
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
return keys;
|
|
979
|
+
} catch {
|
|
980
|
+
return [];
|
|
981
|
+
}
|
|
918
982
|
}
|
|
919
|
-
function
|
|
983
|
+
async function detectStaticState() {
|
|
984
|
+
const [repositories, gitIdentityConfigured, runtimeEnvKeys] = await Promise.all([
|
|
985
|
+
gitService.listRepositories(),
|
|
986
|
+
detectGitIdentityConfigured(),
|
|
987
|
+
parseRuntimeEnvKeys()
|
|
988
|
+
]);
|
|
920
989
|
return {
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
codexAuthConfigured: false,
|
|
932
|
-
claudeAuthConfigured: false,
|
|
933
|
-
bedrockAuthConfigured: false,
|
|
934
|
-
lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
990
|
+
repositoriesCloned: repositories.map((repo) => repo.name),
|
|
991
|
+
gitIdentityConfigured,
|
|
992
|
+
envVarsSet: runtimeEnvKeys,
|
|
993
|
+
runtimeEnvVarsSet: runtimeEnvKeys,
|
|
994
|
+
claudeAuthMethod: detectClaudeAuthMethod(),
|
|
995
|
+
codexAuthMethod: detectCodexAuthMethod(),
|
|
996
|
+
githubAccessConfigured: Boolean(ENGINE_ENV.GH_TOKEN),
|
|
997
|
+
githubCredentialsConfigured: Boolean(ENGINE_ENV.GH_TOKEN),
|
|
998
|
+
linearAccessConfigured: Boolean(ENGINE_ENV.LINEAR_SESSION_ID || ENGINE_ENV.LINEAR_ACCESS_TOKEN),
|
|
999
|
+
slackAccessConfigured: Boolean(ENGINE_ENV.SLACK_BOT_TOKEN)
|
|
935
1000
|
};
|
|
936
1001
|
}
|
|
937
|
-
function
|
|
938
|
-
|
|
939
|
-
|
|
1002
|
+
async function detectUploadedFiles() {
|
|
1003
|
+
try {
|
|
1004
|
+
if (!existsSync3(FILES_DIR)) {
|
|
1005
|
+
return [];
|
|
1006
|
+
}
|
|
1007
|
+
const entries = await readdir2(FILES_DIR);
|
|
1008
|
+
return entries.filter((entry) => !entry.startsWith(".")).map((entry) => `${SANDBOX_PATHS.REPLICAS_FILES_DISPLAY_DIR}/${entry}`);
|
|
1009
|
+
} catch {
|
|
1010
|
+
return [];
|
|
940
1011
|
}
|
|
941
|
-
|
|
1012
|
+
}
|
|
1013
|
+
function createDefaultPersistedState() {
|
|
1014
|
+
return {
|
|
1015
|
+
globalWarmHookCompleted: { status: "n/a", details: null },
|
|
1016
|
+
repositories: [],
|
|
1017
|
+
skillsInstalled: []
|
|
1018
|
+
};
|
|
942
1019
|
}
|
|
943
1020
|
function upsertRepositoryStatus(current, incoming) {
|
|
944
|
-
const byName = new Map(current.map((
|
|
945
|
-
for (const
|
|
946
|
-
const existing = byName.get(
|
|
947
|
-
byName.set(
|
|
948
|
-
repositoryName:
|
|
949
|
-
warmHookCompleted:
|
|
950
|
-
startHookCompleted:
|
|
1021
|
+
const byName = new Map(current.map((r) => [r.repositoryName, r]));
|
|
1022
|
+
for (const repo of incoming) {
|
|
1023
|
+
const existing = byName.get(repo.repositoryName);
|
|
1024
|
+
byName.set(repo.repositoryName, {
|
|
1025
|
+
repositoryName: repo.repositoryName,
|
|
1026
|
+
warmHookCompleted: repo.warmHookCompleted !== "n/a" ? repo.warmHookCompleted : existing?.warmHookCompleted ?? "n/a",
|
|
1027
|
+
startHookCompleted: repo.startHookCompleted !== "n/a" ? repo.startHookCompleted : existing?.startHookCompleted ?? "n/a"
|
|
951
1028
|
});
|
|
952
1029
|
}
|
|
953
1030
|
return [...byName.values()].sort((a, b) => a.repositoryName.localeCompare(b.repositoryName));
|
|
954
1031
|
}
|
|
1032
|
+
async function readPersistedState() {
|
|
1033
|
+
try {
|
|
1034
|
+
if (!existsSync3(PERSISTED_STATE_FILE)) {
|
|
1035
|
+
return createDefaultPersistedState();
|
|
1036
|
+
}
|
|
1037
|
+
const raw = await readFile2(PERSISTED_STATE_FILE, "utf-8");
|
|
1038
|
+
const parsed = JSON.parse(raw);
|
|
1039
|
+
return { ...createDefaultPersistedState(), ...parsed };
|
|
1040
|
+
} catch {
|
|
1041
|
+
return createDefaultPersistedState();
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
async function writePersistedState(state) {
|
|
1045
|
+
await mkdir3(REPLICAS_DIR, { recursive: true });
|
|
1046
|
+
await writeFile3(PERSISTED_STATE_FILE, `${JSON.stringify(state, null, 2)}
|
|
1047
|
+
`, "utf-8");
|
|
1048
|
+
}
|
|
955
1049
|
var EnvironmentDetailsService = class {
|
|
1050
|
+
staticState = null;
|
|
956
1051
|
async initialize() {
|
|
957
|
-
|
|
958
|
-
const
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
repositoryName:
|
|
1052
|
+
this.staticState = await detectStaticState();
|
|
1053
|
+
const persisted = await readPersistedState();
|
|
1054
|
+
persisted.repositories = upsertRepositoryStatus(
|
|
1055
|
+
persisted.repositories,
|
|
1056
|
+
this.staticState.repositoriesCloned.map((name) => ({
|
|
1057
|
+
repositoryName: name,
|
|
963
1058
|
warmHookCompleted: "n/a",
|
|
964
1059
|
startHookCompleted: "n/a"
|
|
965
1060
|
}))
|
|
966
1061
|
);
|
|
967
|
-
await
|
|
968
|
-
...current,
|
|
969
|
-
engineVersion: REPLICAS_ENGINE_VERSION,
|
|
970
|
-
repositories: merged,
|
|
971
|
-
lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
972
|
-
});
|
|
1062
|
+
await writePersistedState(persisted);
|
|
973
1063
|
}
|
|
974
1064
|
async getDetails() {
|
|
975
|
-
const
|
|
1065
|
+
const staticState = this.staticState ?? await detectStaticState();
|
|
1066
|
+
const [persisted, filesUploaded] = await Promise.all([
|
|
1067
|
+
readPersistedState(),
|
|
1068
|
+
detectUploadedFiles()
|
|
1069
|
+
]);
|
|
976
1070
|
return {
|
|
977
|
-
...current,
|
|
978
|
-
engineVersion: REPLICAS_ENGINE_VERSION
|
|
979
|
-
};
|
|
980
|
-
}
|
|
981
|
-
async track(update) {
|
|
982
|
-
const current = await this.readDetails();
|
|
983
|
-
const next = {
|
|
984
|
-
...current,
|
|
985
1071
|
engineVersion: REPLICAS_ENGINE_VERSION,
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
filesUploaded
|
|
989
|
-
envVarsSet: mergeUnique(current.envVarsSet, update.envVarsSet),
|
|
990
|
-
skillsInstalled: mergeUnique(current.skillsInstalled, update.skillsInstalled),
|
|
991
|
-
runtimeEnvVarsSet: mergeUnique(current.runtimeEnvVarsSet, update.runtimeEnvVarsSet),
|
|
992
|
-
repositoriesCloned: mergeUnique(current.repositoriesCloned, update.repositoriesCloned),
|
|
993
|
-
gitIdentityConfigured: update.gitIdentityConfigured ?? current.gitIdentityConfigured,
|
|
994
|
-
githubCredentialsConfigured: update.githubCredentialsConfigured ?? current.githubCredentialsConfigured,
|
|
995
|
-
codexAuthConfigured: update.codexAuthConfigured ?? current.codexAuthConfigured,
|
|
996
|
-
claudeAuthConfigured: update.claudeAuthConfigured ?? current.claudeAuthConfigured,
|
|
997
|
-
bedrockAuthConfigured: update.bedrockAuthConfigured ?? current.bedrockAuthConfigured,
|
|
1072
|
+
...staticState,
|
|
1073
|
+
...persisted,
|
|
1074
|
+
filesUploaded,
|
|
998
1075
|
lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
999
1076
|
};
|
|
1000
|
-
|
|
1001
|
-
|
|
1077
|
+
}
|
|
1078
|
+
async trackSkillsInstalled(skills) {
|
|
1079
|
+
const persisted = await readPersistedState();
|
|
1080
|
+
persisted.skillsInstalled = Array.from(/* @__PURE__ */ new Set([...persisted.skillsInstalled, ...skills]));
|
|
1081
|
+
await writePersistedState(persisted);
|
|
1002
1082
|
}
|
|
1003
1083
|
async setGlobalWarmHook(status, details) {
|
|
1004
|
-
await
|
|
1005
|
-
|
|
1006
|
-
|
|
1084
|
+
const persisted = await readPersistedState();
|
|
1085
|
+
persisted.globalWarmHookCompleted = { status, details: details ?? null };
|
|
1086
|
+
await writePersistedState(persisted);
|
|
1007
1087
|
}
|
|
1008
1088
|
async setRepositoryWarmHook(repositoryName, status) {
|
|
1009
|
-
await
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1089
|
+
const persisted = await readPersistedState();
|
|
1090
|
+
persisted.repositories = upsertRepositoryStatus(persisted.repositories, [{
|
|
1091
|
+
repositoryName,
|
|
1092
|
+
warmHookCompleted: status,
|
|
1093
|
+
startHookCompleted: "n/a"
|
|
1094
|
+
}]);
|
|
1095
|
+
await writePersistedState(persisted);
|
|
1016
1096
|
}
|
|
1017
1097
|
async setRepositoryStartHook(repositoryName, status) {
|
|
1018
|
-
await
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
}
|
|
1026
|
-
async readDetails() {
|
|
1027
|
-
try {
|
|
1028
|
-
if (!existsSync3(ENVIRONMENT_DETAILS_FILE)) {
|
|
1029
|
-
return createDefaultDetails();
|
|
1030
|
-
}
|
|
1031
|
-
const raw = await readFile2(ENVIRONMENT_DETAILS_FILE, "utf-8");
|
|
1032
|
-
return {
|
|
1033
|
-
...createDefaultDetails(),
|
|
1034
|
-
...JSON.parse(raw),
|
|
1035
|
-
engineVersion: REPLICAS_ENGINE_VERSION
|
|
1036
|
-
};
|
|
1037
|
-
} catch {
|
|
1038
|
-
return createDefaultDetails();
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
async writeDetails(details) {
|
|
1042
|
-
await mkdir3(REPLICAS_DIR, { recursive: true });
|
|
1043
|
-
await writeFile3(ENVIRONMENT_DETAILS_FILE, `${JSON.stringify(details, null, 2)}
|
|
1044
|
-
`, "utf-8");
|
|
1098
|
+
const persisted = await readPersistedState();
|
|
1099
|
+
persisted.repositories = upsertRepositoryStatus(persisted.repositories, [{
|
|
1100
|
+
repositoryName,
|
|
1101
|
+
warmHookCompleted: "n/a",
|
|
1102
|
+
startHookCompleted: status
|
|
1103
|
+
}]);
|
|
1104
|
+
await writePersistedState(persisted);
|
|
1045
1105
|
}
|
|
1046
1106
|
};
|
|
1047
1107
|
var environmentDetailsService = new EnvironmentDetailsService();
|
|
@@ -1052,8 +1112,8 @@ import { existsSync as existsSync4 } from "fs";
|
|
|
1052
1112
|
import { join as join6 } from "path";
|
|
1053
1113
|
import { homedir as homedir5 } from "os";
|
|
1054
1114
|
import { exec } from "child_process";
|
|
1055
|
-
import { promisify } from "util";
|
|
1056
|
-
var execAsync =
|
|
1115
|
+
import { promisify as promisify2 } from "util";
|
|
1116
|
+
var execAsync = promisify2(exec);
|
|
1057
1117
|
var START_HOOKS_LOG = join6(homedir5(), ".replicas", "startHooks.log");
|
|
1058
1118
|
var START_HOOKS_RUNNING_PROMPT = `IMPORTANT - Start Hooks Running:
|
|
1059
1119
|
Start hooks are shell commands/scripts set by repository owners that run on workspace startup.
|
|
@@ -1398,6 +1458,9 @@ async function readJSONL(filePath) {
|
|
|
1398
1458
|
// src/services/monolith-service.ts
|
|
1399
1459
|
var MonolithService = class {
|
|
1400
1460
|
async sendEvent(event) {
|
|
1461
|
+
if (!ENGINE_ENV.WORKSPACE_ID) {
|
|
1462
|
+
return;
|
|
1463
|
+
}
|
|
1401
1464
|
try {
|
|
1402
1465
|
const response = await fetch(`${ENGINE_ENV.MONOLITH_URL}/v1/engine/webhook`, {
|
|
1403
1466
|
method: "POST",
|
|
@@ -2289,7 +2352,7 @@ var ClaudeManager = class extends CodingAgentManager {
|
|
|
2289
2352
|
// src/managers/codex-manager.ts
|
|
2290
2353
|
import { Codex } from "@openai/codex-sdk";
|
|
2291
2354
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
2292
|
-
import { readdir as
|
|
2355
|
+
import { readdir as readdir3, stat as stat2, writeFile as writeFile5, mkdir as mkdir7, readFile as readFile5 } from "fs/promises";
|
|
2293
2356
|
import { existsSync as existsSync5 } from "fs";
|
|
2294
2357
|
import { join as join9 } from "path";
|
|
2295
2358
|
import { homedir as homedir8 } from "os";
|
|
@@ -2531,7 +2594,7 @@ var CodexManager = class extends CodingAgentManager {
|
|
|
2531
2594
|
}
|
|
2532
2595
|
async findFileInDirectory(directory, threadId) {
|
|
2533
2596
|
try {
|
|
2534
|
-
const files = await
|
|
2597
|
+
const files = await readdir3(directory);
|
|
2535
2598
|
for (const file of files) {
|
|
2536
2599
|
if (file.endsWith(".jsonl") && file.includes(threadId)) {
|
|
2537
2600
|
const fullPath = join9(directory, file);
|
|
@@ -2933,7 +2996,7 @@ import { Hono } from "hono";
|
|
|
2933
2996
|
import { z } from "zod";
|
|
2934
2997
|
|
|
2935
2998
|
// src/services/plan-service.ts
|
|
2936
|
-
import { readdir as
|
|
2999
|
+
import { readdir as readdir4, readFile as readFile7 } from "fs/promises";
|
|
2937
3000
|
import { homedir as homedir10 } from "os";
|
|
2938
3001
|
import { basename, join as join11 } from "path";
|
|
2939
3002
|
var PLAN_DIRECTORIES = [
|
|
@@ -2951,7 +3014,7 @@ var PlanService = class {
|
|
|
2951
3014
|
const planNames = /* @__PURE__ */ new Set();
|
|
2952
3015
|
for (const directory of PLAN_DIRECTORIES) {
|
|
2953
3016
|
try {
|
|
2954
|
-
const entries = await
|
|
3017
|
+
const entries = await readdir4(directory, { withFileTypes: true });
|
|
2955
3018
|
for (const entry of entries) {
|
|
2956
3019
|
if (!entry.isFile()) {
|
|
2957
3020
|
continue;
|
|
@@ -2985,15 +3048,15 @@ var PlanService = class {
|
|
|
2985
3048
|
var planService = new PlanService();
|
|
2986
3049
|
|
|
2987
3050
|
// src/services/warm-hooks-service.ts
|
|
2988
|
-
import { execFile } from "child_process";
|
|
2989
|
-
import { promisify as
|
|
3051
|
+
import { execFile as execFile2 } from "child_process";
|
|
3052
|
+
import { promisify as promisify3 } from "util";
|
|
2990
3053
|
import { readFile as readFile8 } from "fs/promises";
|
|
2991
3054
|
import { join as join12 } from "path";
|
|
2992
|
-
var
|
|
3055
|
+
var execFileAsync2 = promisify3(execFile2);
|
|
2993
3056
|
async function installSkill(params) {
|
|
2994
3057
|
const timeout = clampWarmHookTimeoutMs(params.timeoutMs);
|
|
2995
3058
|
try {
|
|
2996
|
-
const { stdout, stderr } = await
|
|
3059
|
+
const { stdout, stderr } = await execFileAsync2(
|
|
2997
3060
|
"npx",
|
|
2998
3061
|
["skills", "add", params.source, "--all", "--global"],
|
|
2999
3062
|
{
|
|
@@ -3029,7 +3092,7 @@ async function installSkill(params) {
|
|
|
3029
3092
|
async function executeHookScript(params) {
|
|
3030
3093
|
const timeout = clampWarmHookTimeoutMs(params.timeoutMs);
|
|
3031
3094
|
try {
|
|
3032
|
-
const { stdout, stderr } = await
|
|
3095
|
+
const { stdout, stderr } = await execFileAsync2("bash", ["-lc", params.content], {
|
|
3033
3096
|
cwd: params.cwd,
|
|
3034
3097
|
timeout,
|
|
3035
3098
|
maxBuffer: 1024 * 1024,
|
|
@@ -3100,7 +3163,7 @@ async function runWarmHooks(params) {
|
|
|
3100
3163
|
});
|
|
3101
3164
|
outputBlocks.push(installResult.output);
|
|
3102
3165
|
if (installResult.exitCode === 0) {
|
|
3103
|
-
await environmentDetailsService.
|
|
3166
|
+
await environmentDetailsService.trackSkillsInstalled([source]);
|
|
3104
3167
|
}
|
|
3105
3168
|
if (installResult.exitCode !== 0) {
|
|
3106
3169
|
await environmentDetailsService.setGlobalWarmHook("no", installResult.output);
|
|
@@ -3418,18 +3481,6 @@ function createV1Routes(deps) {
|
|
|
3418
3481
|
);
|
|
3419
3482
|
}
|
|
3420
3483
|
});
|
|
3421
|
-
app2.post("/environment/track", async (c) => {
|
|
3422
|
-
try {
|
|
3423
|
-
const body = await c.req.json();
|
|
3424
|
-
const details = await environmentDetailsService.track(body);
|
|
3425
|
-
return c.json(details);
|
|
3426
|
-
} catch (error) {
|
|
3427
|
-
return c.json(
|
|
3428
|
-
jsonError("Failed to track environment details", error instanceof Error ? error.message : "Unknown error"),
|
|
3429
|
-
500
|
|
3430
|
-
);
|
|
3431
|
-
}
|
|
3432
|
-
});
|
|
3433
3484
|
app2.post("/warm-hooks/run", async (c) => {
|
|
3434
3485
|
try {
|
|
3435
3486
|
const body = await c.req.json();
|
|
@@ -3642,7 +3693,11 @@ serve(
|
|
|
3642
3693
|
port
|
|
3643
3694
|
},
|
|
3644
3695
|
async (info) => {
|
|
3645
|
-
|
|
3696
|
+
if (IS_WARMING_MODE) {
|
|
3697
|
+
console.log(`Replicas Engine running on port ${info.port} (warming mode)`);
|
|
3698
|
+
} else {
|
|
3699
|
+
console.log(`Replicas Engine running on port ${info.port}`);
|
|
3700
|
+
}
|
|
3646
3701
|
const gitResult = await gitService.initializeGitRepository();
|
|
3647
3702
|
if (!gitResult.success) {
|
|
3648
3703
|
console.warn(`Git initialization warning: ${gitResult.error}`);
|
|
@@ -3650,9 +3705,11 @@ serve(
|
|
|
3650
3705
|
await replicasConfigService.initialize();
|
|
3651
3706
|
await chatService.initialize();
|
|
3652
3707
|
engineReady = true;
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3708
|
+
if (!IS_WARMING_MODE) {
|
|
3709
|
+
await githubTokenManager.start();
|
|
3710
|
+
await claudeTokenManager.start();
|
|
3711
|
+
await codexTokenManager.start();
|
|
3712
|
+
}
|
|
3656
3713
|
const repos = await gitService.listRepos();
|
|
3657
3714
|
await eventService.publish({
|
|
3658
3715
|
id: randomUUID4(),
|
package/package.json
CHANGED
package/dist/tsup.config.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { defineConfig } from 'tsup';
|
|
2
|
-
export default defineConfig({
|
|
3
|
-
entry: ['src/index.ts'],
|
|
4
|
-
format: ['esm'],
|
|
5
|
-
bundle: true,
|
|
6
|
-
// Bundle @replicas/shared inline, all other dependencies are automatically external
|
|
7
|
-
noExternal: ['@replicas/shared'],
|
|
8
|
-
dts: false, // We don't need type definitions for the published package
|
|
9
|
-
clean: true,
|
|
10
|
-
// Output to dist/src to match existing structure
|
|
11
|
-
outDir: 'dist/src',
|
|
12
|
-
// Add shebang for the bin script
|
|
13
|
-
banner: {
|
|
14
|
-
js: '#!/usr/bin/env node',
|
|
15
|
-
},
|
|
16
|
-
// Preserve the directory structure
|
|
17
|
-
outExtension() {
|
|
18
|
-
return {
|
|
19
|
-
js: '.js',
|
|
20
|
-
};
|
|
21
|
-
},
|
|
22
|
-
// Resolve path mappings from tsconfig
|
|
23
|
-
esbuildOptions(options) {
|
|
24
|
-
options.alias = {
|
|
25
|
-
'@replicas/shared': '../shared/src',
|
|
26
|
-
};
|
|
27
|
-
},
|
|
28
|
-
});
|