replicas-engine 0.1.52 → 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.
Files changed (2) hide show
  1. package/dist/src/index.js +100 -187
  2. 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";
@@ -826,13 +825,13 @@ var EngineLogger = class {
826
825
  };
827
826
  var engineLogger = new EngineLogger();
828
827
 
829
- // src/services/environment-details-service.ts
830
- import { mkdir as mkdir3, readdir as readdir2, readFile as readFile2, writeFile as writeFile3 } from "fs/promises";
831
- import { existsSync as existsSync3 } from "fs";
832
- import { homedir as homedir4 } from "os";
833
- import { join as join5 } from "path";
834
- import { execFile } from "child_process";
835
- import { promisify } from "util";
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";
836
835
 
837
836
  // ../shared/src/sandbox.ts
838
837
  var SANDBOX_LIFECYCLE = {
@@ -918,11 +917,15 @@ var WORKSPACE_FILE_UPLOAD_MAX_SIZE_BYTES = 20 * 1024 * 1024;
918
917
  var WORKSPACE_FILE_CONTENT_MAX_SIZE_BYTES = 1 * 1024 * 1024;
919
918
 
920
919
  // src/services/environment-details-service.ts
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";
921
926
  var execFileAsync = promisify(execFile);
922
927
  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");
928
+ var DETAILS_FILE = join5(REPLICAS_DIR, "environment-details.json");
926
929
  var CLAUDE_CREDENTIALS_PATH = join5(homedir4(), ".claude", ".credentials.json");
927
930
  var CODEX_AUTH_PATH = join5(homedir4(), ".codex", "auth.json");
928
931
  function detectClaudeAuthMethod() {
@@ -954,69 +957,6 @@ async function detectGitIdentityConfigured() {
954
957
  return false;
955
958
  }
956
959
  }
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
- }
982
- }
983
- async function detectStaticState() {
984
- const [repositories, gitIdentityConfigured, runtimeEnvKeys] = await Promise.all([
985
- gitService.listRepositories(),
986
- detectGitIdentityConfigured(),
987
- parseRuntimeEnvKeys()
988
- ]);
989
- return {
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)
1000
- };
1001
- }
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 [];
1011
- }
1012
- }
1013
- function createDefaultPersistedState() {
1014
- return {
1015
- globalWarmHookCompleted: { status: "n/a", details: null },
1016
- repositories: [],
1017
- skillsInstalled: []
1018
- };
1019
- }
1020
960
  function upsertRepositoryStatus(current, incoming) {
1021
961
  const byName = new Map(current.map((r) => [r.repositoryName, r]));
1022
962
  for (const repo of incoming) {
@@ -1029,90 +969,108 @@ function upsertRepositoryStatus(current, incoming) {
1029
969
  }
1030
970
  return [...byName.values()].sort((a, b) => a.repositoryName.localeCompare(b.repositoryName));
1031
971
  }
1032
- async function readPersistedState() {
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() {
1033
991
  try {
1034
- if (!existsSync3(PERSISTED_STATE_FILE)) {
1035
- return createDefaultPersistedState();
992
+ if (!existsSync3(DETAILS_FILE)) {
993
+ return createDefaultDetails();
1036
994
  }
1037
- const raw = await readFile2(PERSISTED_STATE_FILE, "utf-8");
995
+ const raw = await readFile2(DETAILS_FILE, "utf-8");
1038
996
  const parsed = JSON.parse(raw);
1039
- return { ...createDefaultPersistedState(), ...parsed };
997
+ return { ...createDefaultDetails(), ...parsed };
1040
998
  } catch {
1041
- return createDefaultPersistedState();
999
+ return createDefaultDetails();
1042
1000
  }
1043
1001
  }
1044
- async function writePersistedState(state) {
1002
+ async function writeDetails(details) {
1045
1003
  await mkdir3(REPLICAS_DIR, { recursive: true });
1046
- await writeFile3(PERSISTED_STATE_FILE, `${JSON.stringify(state, null, 2)}
1004
+ await writeFile3(DETAILS_FILE, `${JSON.stringify(details, null, 2)}
1047
1005
  `, "utf-8");
1048
1006
  }
1049
1007
  var EnvironmentDetailsService = class {
1050
- staticState = null;
1051
- async initialize() {
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,
1058
- warmHookCompleted: "n/a",
1059
- startHookCompleted: "n/a"
1060
- }))
1061
- );
1062
- await writePersistedState(persisted);
1063
- }
1064
1008
  async getDetails() {
1065
- const staticState = this.staticState ?? await detectStaticState();
1066
- const [persisted, filesUploaded] = await Promise.all([
1067
- readPersistedState(),
1068
- detectUploadedFiles()
1009
+ const [details, repositories, gitIdentityConfigured] = await Promise.all([
1010
+ readDetails(),
1011
+ gitService.listRepositories(),
1012
+ detectGitIdentityConfigured()
1069
1013
  ]);
1070
- return {
1071
- engineVersion: REPLICAS_ENGINE_VERSION,
1072
- ...staticState,
1073
- ...persisted,
1074
- filesUploaded,
1075
- lastUpdatedAt: (/* @__PURE__ */ new Date()).toISOString()
1076
- };
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;
1077
1029
  }
1078
- async trackSkillsInstalled(skills) {
1079
- const persisted = await readPersistedState();
1080
- persisted.skillsInstalled = Array.from(/* @__PURE__ */ new Set([...persisted.skillsInstalled, ...skills]));
1081
- await writePersistedState(persisted);
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);
1082
1043
  }
1083
1044
  async setGlobalWarmHook(status, details) {
1084
- const persisted = await readPersistedState();
1085
- persisted.globalWarmHookCompleted = { status, details: details ?? null };
1086
- await writePersistedState(persisted);
1045
+ const current = await readDetails();
1046
+ current.globalWarmHookCompleted = { status, details: details ?? null };
1047
+ current.lastUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
1048
+ await writeDetails(current);
1087
1049
  }
1088
1050
  async setRepositoryWarmHook(repositoryName, status) {
1089
- const persisted = await readPersistedState();
1090
- persisted.repositories = upsertRepositoryStatus(persisted.repositories, [{
1051
+ const current = await readDetails();
1052
+ current.repositories = upsertRepositoryStatus(current.repositories, [{
1091
1053
  repositoryName,
1092
1054
  warmHookCompleted: status,
1093
1055
  startHookCompleted: "n/a"
1094
1056
  }]);
1095
- await writePersistedState(persisted);
1057
+ current.lastUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
1058
+ await writeDetails(current);
1096
1059
  }
1097
1060
  async setRepositoryStartHook(repositoryName, status) {
1098
- const persisted = await readPersistedState();
1099
- persisted.repositories = upsertRepositoryStatus(persisted.repositories, [{
1061
+ const current = await readDetails();
1062
+ current.repositories = upsertRepositoryStatus(current.repositories, [{
1100
1063
  repositoryName,
1101
1064
  warmHookCompleted: "n/a",
1102
1065
  startHookCompleted: status
1103
1066
  }]);
1104
- await writePersistedState(persisted);
1067
+ current.lastUpdatedAt = (/* @__PURE__ */ new Date()).toISOString();
1068
+ await writeDetails(current);
1105
1069
  }
1106
1070
  };
1107
1071
  var environmentDetailsService = new EnvironmentDetailsService();
1108
1072
 
1109
1073
  // src/services/replicas-config-service.ts
1110
- import { readFile as readFile3, appendFile as appendFile2, writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
1111
- import { existsSync as existsSync4 } from "fs";
1112
- import { join as join6 } from "path";
1113
- import { homedir as homedir5 } from "os";
1114
- import { exec } from "child_process";
1115
- import { promisify as promisify2 } from "util";
1116
1074
  var execAsync = promisify2(exec);
1117
1075
  var START_HOOKS_LOG = join6(homedir5(), ".replicas", "startHooks.log");
1118
1076
  var START_HOOKS_RUNNING_PROMPT = `IMPORTANT - Start Hooks Running:
@@ -2352,7 +2310,7 @@ var ClaudeManager = class extends CodingAgentManager {
2352
2310
  // src/managers/codex-manager.ts
2353
2311
  import { Codex } from "@openai/codex-sdk";
2354
2312
  import { randomUUID as randomUUID2 } from "crypto";
2355
- import { readdir as readdir3, stat as stat2, writeFile as writeFile5, mkdir as mkdir7, readFile as readFile5 } from "fs/promises";
2313
+ import { readdir as readdir2, stat as stat2, writeFile as writeFile5, mkdir as mkdir7, readFile as readFile5 } from "fs/promises";
2356
2314
  import { existsSync as existsSync5 } from "fs";
2357
2315
  import { join as join9 } from "path";
2358
2316
  import { homedir as homedir8 } from "os";
@@ -2594,7 +2552,7 @@ var CodexManager = class extends CodingAgentManager {
2594
2552
  }
2595
2553
  async findFileInDirectory(directory, threadId) {
2596
2554
  try {
2597
- const files = await readdir3(directory);
2555
+ const files = await readdir2(directory);
2598
2556
  for (const file of files) {
2599
2557
  if (file.endsWith(".jsonl") && file.includes(threadId)) {
2600
2558
  const fullPath = join9(directory, file);
@@ -2996,7 +2954,7 @@ import { Hono } from "hono";
2996
2954
  import { z } from "zod";
2997
2955
 
2998
2956
  // src/services/plan-service.ts
2999
- import { readdir as readdir4, readFile as readFile7 } from "fs/promises";
2957
+ import { readdir as readdir3, readFile as readFile7 } from "fs/promises";
3000
2958
  import { homedir as homedir10 } from "os";
3001
2959
  import { basename, join as join11 } from "path";
3002
2960
  var PLAN_DIRECTORIES = [
@@ -3014,7 +2972,7 @@ var PlanService = class {
3014
2972
  const planNames = /* @__PURE__ */ new Set();
3015
2973
  for (const directory of PLAN_DIRECTORIES) {
3016
2974
  try {
3017
- const entries = await readdir4(directory, { withFileTypes: true });
2975
+ const entries = await readdir3(directory, { withFileTypes: true });
3018
2976
  for (const entry of entries) {
3019
2977
  if (!entry.isFile()) {
3020
2978
  continue;
@@ -3053,42 +3011,6 @@ import { promisify as promisify3 } from "util";
3053
3011
  import { readFile as readFile8 } from "fs/promises";
3054
3012
  import { join as join12 } from "path";
3055
3013
  var execFileAsync2 = promisify3(execFile2);
3056
- async function installSkill(params) {
3057
- const timeout = clampWarmHookTimeoutMs(params.timeoutMs);
3058
- try {
3059
- const { stdout, stderr } = await execFileAsync2(
3060
- "npx",
3061
- ["skills", "add", params.source, "--all", "--global"],
3062
- {
3063
- cwd: params.cwd,
3064
- timeout,
3065
- maxBuffer: 1024 * 1024,
3066
- env: process.env
3067
- }
3068
- );
3069
- const combined = [`$ npx skills add ${params.source} --all --global`, stdout ?? "", stderr ?? ""].filter(Boolean).join("\n");
3070
- return {
3071
- exitCode: 0,
3072
- output: truncateWarmHookOutput(combined),
3073
- timedOut: false
3074
- };
3075
- } catch (error) {
3076
- const execError = error;
3077
- const timedOut = execError.signal === "SIGTERM" || execError.killed === true;
3078
- const exitCode = typeof execError.code === "number" ? execError.code : 1;
3079
- const combined = [
3080
- `$ npx skills add ${params.source} --all --global`,
3081
- execError.stdout ?? "",
3082
- execError.stderr ?? "",
3083
- execError.message
3084
- ].filter(Boolean).join("\n");
3085
- return {
3086
- exitCode,
3087
- output: truncateWarmHookOutput(combined),
3088
- timedOut
3089
- };
3090
- }
3091
- }
3092
3014
  async function executeHookScript(params) {
3093
3015
  const timeout = clampWarmHookTimeoutMs(params.timeoutMs);
3094
3016
  try {
@@ -3153,27 +3075,7 @@ async function collectRepoWarmHooks() {
3153
3075
  }
3154
3076
  async function runWarmHooks(params) {
3155
3077
  const outputBlocks = [];
3156
- const skills = params.skills ?? [];
3157
3078
  const orgHook = params.organizationWarmHook?.trim();
3158
- for (const source of skills) {
3159
- const installResult = await installSkill({
3160
- source,
3161
- cwd: gitService.getWorkspaceRoot(),
3162
- timeoutMs: params.timeoutMs
3163
- });
3164
- outputBlocks.push(installResult.output);
3165
- if (installResult.exitCode === 0) {
3166
- await environmentDetailsService.trackSkillsInstalled([source]);
3167
- }
3168
- if (installResult.exitCode !== 0) {
3169
- await environmentDetailsService.setGlobalWarmHook("no", installResult.output);
3170
- return {
3171
- exitCode: installResult.exitCode,
3172
- output: outputBlocks.join("\n\n"),
3173
- timedOut: installResult.timedOut
3174
- };
3175
- }
3176
- }
3177
3079
  if (orgHook) {
3178
3080
  const orgResult = await executeHookScript({
3179
3081
  label: "org-warm-hook",
@@ -3481,6 +3383,18 @@ function createV1Routes(deps) {
3481
3383
  );
3482
3384
  }
3483
3385
  });
3386
+ app2.post("/environment/track", async (c) => {
3387
+ try {
3388
+ const body = await c.req.json();
3389
+ await environmentDetailsService.trackEnvironment(body);
3390
+ return c.json({ success: true });
3391
+ } catch (error) {
3392
+ return c.json(
3393
+ jsonError("Failed to track environment", error instanceof Error ? error.message : "Unknown error"),
3394
+ 500
3395
+ );
3396
+ }
3397
+ });
3484
3398
  app2.post("/warm-hooks/run", async (c) => {
3485
3399
  try {
3486
3400
  const body = await c.req.json();
@@ -3508,7 +3422,6 @@ function createV1Routes(deps) {
3508
3422
  // src/index.ts
3509
3423
  await engineLogger.initialize();
3510
3424
  await eventService.initialize();
3511
- await environmentDetailsService.initialize();
3512
3425
  var READY_MESSAGE = "========= REPLICAS WORKSPACE READY ==========";
3513
3426
  var COMPLETION_MESSAGE = "========= REPLICAS WORKSPACE INITIALIZATION COMPLETE ==========";
3514
3427
  function checkActiveSSHSessions() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.52",
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"