replicas-engine 0.1.145 → 0.1.146

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 +325 -250
  2. package/package.json +1 -1
package/dist/src/index.js CHANGED
@@ -14,6 +14,313 @@ import path from "path";
14
14
  // src/engine-env.ts
15
15
  import { homedir } from "os";
16
16
  import { join } from "path";
17
+
18
+ // src/runtime-env-loader.ts
19
+ import { readFileSync } from "fs";
20
+
21
+ // ../shared/src/event.ts
22
+ var CODEX_QUOTA_STATUS_EVENT_TYPE = "codex-quota-status";
23
+
24
+ // ../shared/src/pricing.ts
25
+ var PLANS = {
26
+ hobby: {
27
+ id: "hobby",
28
+ name: "Hobby",
29
+ monthlyPrice: 0,
30
+ seatPriceCents: 0,
31
+ creditsIncluded: 1200,
32
+ features: [
33
+ "1,200 minutes of human-initiated workspace usage (one-time)",
34
+ "1,200 minutes of API + automation usage (one-time)",
35
+ "Automations (limited to 2)",
36
+ "Warm pools and warm hooks",
37
+ "Up to 3 repositories"
38
+ ]
39
+ },
40
+ developer: {
41
+ id: "developer",
42
+ name: "Developer",
43
+ monthlyPrice: 120,
44
+ seatPriceCents: 12e3,
45
+ creditsIncluded: 0,
46
+ features: [
47
+ "Unlimited human-initiated workspaces",
48
+ "5,000 included automation/API minutes per month",
49
+ "Up to 10 repositories",
50
+ "Up to 5 automations",
51
+ "Warm pools and warm hooks",
52
+ "API access"
53
+ ]
54
+ },
55
+ team: {
56
+ id: "team",
57
+ name: "Team",
58
+ monthlyPrice: 300,
59
+ seatPriceCents: 3e4,
60
+ creditsIncluded: 0,
61
+ features: [
62
+ "Unlimited human-initiated workspaces",
63
+ "15,000 included automation/API minutes per month",
64
+ "Unlimited repositories",
65
+ "Unlimited automations",
66
+ "Higher API rate limits",
67
+ "Warm pools and warm hooks",
68
+ "Auto-upgraded sandbox resources (32 GB disk, 16 GB memory)",
69
+ "Shared Slack support channel"
70
+ ]
71
+ },
72
+ enterprise: {
73
+ id: "enterprise",
74
+ name: "Enterprise",
75
+ monthlyPrice: 0,
76
+ seatPriceCents: 0,
77
+ creditsIncluded: 0,
78
+ features: [
79
+ "Unlimited usage",
80
+ "Unlimited automations",
81
+ "Custom API rates",
82
+ "Custom rate limits",
83
+ "Custom warm hooks and pools",
84
+ "Shared Slack support channel",
85
+ "SOC 2"
86
+ ]
87
+ }
88
+ };
89
+ var TEAM_PLAN = PLANS.team;
90
+ var ENTERPRISE_PLAN = PLANS.enterprise;
91
+
92
+ // ../shared/src/sandbox.ts
93
+ var SANDBOX_LIFECYCLE = {
94
+ AUTO_STOP_MINUTES: 60,
95
+ AUTO_ARCHIVE_MINUTES: 60 * 24 * 7,
96
+ AUTO_DELETE_MINUTES: -1,
97
+ SSH_TOKEN_EXPIRATION_MINUTES: 3 * 60
98
+ };
99
+ var SANDBOX_PATHS = {
100
+ HOME_DIR: "/home/ubuntu",
101
+ WORKSPACES_DIR: "/home/ubuntu/workspaces",
102
+ REPLICAS_DIR: "/home/ubuntu/.replicas",
103
+ REPLICAS_FILES_DIR: "/home/ubuntu/.replicas/files",
104
+ REPLICAS_FILES_DISPLAY_DIR: "~/.replicas/files",
105
+ REPLICAS_RUNTIME_ENV_FILE: "/home/ubuntu/.replicas/runtime-env.sh",
106
+ REPLICAS_PREVIEW_PORTS_FILE: "/home/ubuntu/.replicas/preview-ports.json"
107
+ };
108
+
109
+ // ../shared/src/runtime-env.ts
110
+ function parsePosixEnvFile(content) {
111
+ const result = {};
112
+ let pos = 0;
113
+ while (pos < content.length) {
114
+ let lineStart;
115
+ if (pos === 0 || content[pos - 1] === "\n") {
116
+ lineStart = pos;
117
+ } else {
118
+ const nl2 = content.indexOf("\n", pos);
119
+ if (nl2 === -1) break;
120
+ lineStart = nl2 + 1;
121
+ }
122
+ if (!content.startsWith("export ", lineStart)) {
123
+ const nl2 = content.indexOf("\n", lineStart);
124
+ if (nl2 === -1) break;
125
+ pos = nl2 + 1;
126
+ continue;
127
+ }
128
+ const nameStart = lineStart + "export ".length;
129
+ const eqIdx = content.indexOf("=", nameStart);
130
+ if (eqIdx === -1) break;
131
+ const name = content.slice(nameStart, eqIdx).trim();
132
+ let cursor = eqIdx + 1;
133
+ if (content[cursor] !== "'") {
134
+ const nl2 = content.indexOf("\n", cursor);
135
+ pos = nl2 === -1 ? content.length : nl2 + 1;
136
+ continue;
137
+ }
138
+ cursor += 1;
139
+ let value = "";
140
+ let closed = false;
141
+ while (cursor < content.length) {
142
+ const ch = content[cursor];
143
+ if (ch === "'") {
144
+ if (content.startsWith("\\''", cursor + 1)) {
145
+ value += "'";
146
+ cursor += 4;
147
+ continue;
148
+ }
149
+ cursor += 1;
150
+ closed = true;
151
+ break;
152
+ }
153
+ value += ch;
154
+ cursor += 1;
155
+ }
156
+ if (closed && name) {
157
+ result[name] = value;
158
+ }
159
+ const nl = content.indexOf("\n", cursor);
160
+ pos = nl === -1 ? content.length : nl + 1;
161
+ }
162
+ return result;
163
+ }
164
+
165
+ // ../shared/src/replicas-config.ts
166
+ import { parse as parseYaml } from "yaml";
167
+
168
+ // ../shared/src/warm-hooks.ts
169
+ var DEFAULT_WARM_HOOK_TIMEOUT_MS = 5 * 60 * 1e3;
170
+ var MAX_WARM_HOOK_TIMEOUT_MS = 15 * 60 * 1e3;
171
+ var DEFAULT_HOOK_OUTPUT_PREVIEW_CHARS = 1e5;
172
+ var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
173
+ function isRecord(value) {
174
+ return typeof value === "object" && value !== null;
175
+ }
176
+ function clampWarmHookTimeoutMs(timeoutMs) {
177
+ if (!timeoutMs || Number.isNaN(timeoutMs) || timeoutMs <= 0) {
178
+ return DEFAULT_WARM_HOOK_TIMEOUT_MS;
179
+ }
180
+ return Math.min(timeoutMs, MAX_WARM_HOOK_TIMEOUT_MS);
181
+ }
182
+ function buildHookOutputPreview(text, maxChars = DEFAULT_HOOK_OUTPUT_PREVIEW_CHARS) {
183
+ if (text.length <= maxChars) {
184
+ return { output: text, outputTruncated: false, outputTotalChars: text.length };
185
+ }
186
+ return {
187
+ output: `${text.slice(0, maxChars)}
188
+ ...[truncated \u2014 download the full log to see the rest]`,
189
+ outputTruncated: true,
190
+ outputTotalChars: text.length
191
+ };
192
+ }
193
+ function parseWarmHookConfig(value, filename = "replicas.json") {
194
+ if (typeof value === "string") {
195
+ return value;
196
+ }
197
+ if (!isRecord(value)) {
198
+ throw new Error(`Invalid ${filename}: "warmHook" must be a string or object`);
199
+ }
200
+ if (!Array.isArray(value.commands) || !value.commands.every((entry) => typeof entry === "string")) {
201
+ throw new Error(`Invalid ${filename}: "warmHook.commands" must be an array of shell commands`);
202
+ }
203
+ if (value.timeout !== void 0 && (typeof value.timeout !== "number" || value.timeout <= 0)) {
204
+ throw new Error(`Invalid ${filename}: "warmHook.timeout" must be a positive number`);
205
+ }
206
+ return {
207
+ commands: value.commands,
208
+ timeout: value.timeout
209
+ };
210
+ }
211
+ function resolveWarmHookConfig(value) {
212
+ if (value === void 0) {
213
+ return null;
214
+ }
215
+ const parsed = parseWarmHookConfig(value);
216
+ const commands = typeof parsed === "string" ? [parsed.trim()].filter(Boolean) : parsed.commands.map((command) => command.trim()).filter(Boolean);
217
+ if (commands.length === 0) {
218
+ return null;
219
+ }
220
+ return {
221
+ commands,
222
+ timeoutMs: typeof parsed === "string" ? void 0 : parsed.timeout
223
+ };
224
+ }
225
+
226
+ // ../shared/src/replicas-config.ts
227
+ var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
228
+ function isRecord2(value) {
229
+ return typeof value === "object" && value !== null;
230
+ }
231
+ function parseReplicasConfig(value, filename = "replicas.json") {
232
+ if (!isRecord2(value)) {
233
+ throw new Error(`Invalid ${filename}: expected an object`);
234
+ }
235
+ const config = {};
236
+ if ("organizationId" in value) {
237
+ if (typeof value.organizationId !== "string") {
238
+ throw new Error(`Invalid ${filename}: "organizationId" must be a string`);
239
+ }
240
+ config.organizationId = value.organizationId;
241
+ }
242
+ if ("systemPrompt" in value) {
243
+ if (typeof value.systemPrompt !== "string") {
244
+ throw new Error(`Invalid ${filename}: "systemPrompt" must be a string`);
245
+ }
246
+ config.systemPrompt = value.systemPrompt;
247
+ }
248
+ if ("startHook" in value) {
249
+ if (!isRecord2(value.startHook)) {
250
+ throw new Error(`Invalid ${filename}: "startHook" must be an object with "commands" array`);
251
+ }
252
+ const { commands, timeout } = value.startHook;
253
+ if (!Array.isArray(commands) || !commands.every((entry) => typeof entry === "string")) {
254
+ throw new Error(`Invalid ${filename}: "startHook.commands" must be an array of shell commands`);
255
+ }
256
+ if (timeout !== void 0 && (typeof timeout !== "number" || timeout <= 0)) {
257
+ throw new Error(`Invalid ${filename}: "startHook.timeout" must be a positive number`);
258
+ }
259
+ config.startHook = { commands, timeout };
260
+ }
261
+ if ("warmHook" in value) {
262
+ config.warmHook = parseWarmHookConfig(value.warmHook, filename);
263
+ }
264
+ return config;
265
+ }
266
+ function parseReplicasConfigString(content, filename) {
267
+ const isYaml = filename.endsWith(".yaml") || filename.endsWith(".yml");
268
+ let parsed;
269
+ if (isYaml) {
270
+ parsed = parseYaml(content);
271
+ } else {
272
+ parsed = JSON.parse(content);
273
+ }
274
+ return parseReplicasConfig(parsed, filename);
275
+ }
276
+
277
+ // ../shared/src/engine/environment.ts
278
+ var DAYTONA_SNAPSHOT_ID = "07-05-2026-royal-york-v3";
279
+
280
+ // ../shared/src/engine/types.ts
281
+ var DEFAULT_CHAT_TITLES = {
282
+ claude: "Claude Code",
283
+ codex: "Codex",
284
+ relay: "Relay"
285
+ };
286
+ var IMAGE_MEDIA_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"];
287
+
288
+ // ../shared/src/routes/workspaces.ts
289
+ var WORKSPACE_FILE_UPLOAD_MAX_SIZE_BYTES = 20 * 1024 * 1024;
290
+ var WORKSPACE_FILE_CONTENT_MAX_SIZE_BYTES = 1 * 1024 * 1024;
291
+
292
+ // ../shared/src/audit-log.ts
293
+ var AUDIT_LOG_ACTION = {
294
+ CREATE: "create",
295
+ UPDATE: "update",
296
+ DELETE: "delete",
297
+ CONNECT: "connect",
298
+ DISCONNECT: "disconnect"
299
+ };
300
+ var AUDIT_LOG_ACTIONS = Object.values(AUDIT_LOG_ACTION);
301
+
302
+ // ../shared/src/object-store/types.ts
303
+ var MEDIA_KIND = {
304
+ IMAGE: "image",
305
+ VIDEO: "video",
306
+ AUDIO: "audio"
307
+ };
308
+ var MEDIA_KINDS = [MEDIA_KIND.IMAGE, MEDIA_KIND.VIDEO, MEDIA_KIND.AUDIO];
309
+
310
+ // src/runtime-env-loader.ts
311
+ function loadRuntimeEnvFile() {
312
+ let content;
313
+ try {
314
+ content = readFileSync(SANDBOX_PATHS.REPLICAS_RUNTIME_ENV_FILE, "utf-8");
315
+ } catch {
316
+ return;
317
+ }
318
+ for (const [key, value] of Object.entries(parsePosixEnvFile(content))) {
319
+ process.env[key] = value;
320
+ }
321
+ }
322
+
323
+ // src/engine-env.ts
17
324
  function readEnv(name) {
18
325
  const value = process.env[name]?.trim();
19
326
  return value ? value : void 0;
@@ -56,6 +363,7 @@ function parseCodexAuthMethod(value) {
56
363
  }
57
364
  var IS_WARMING_MODE = process.argv.includes("--warming");
58
365
  function loadEngineEnv() {
366
+ loadRuntimeEnvFile();
59
367
  const HOME_DIR = homedir();
60
368
  const env = {
61
369
  // Defined: always available
@@ -386,7 +694,7 @@ import { join as join2 } from "path";
386
694
  import { homedir as homedir2 } from "os";
387
695
 
388
696
  // src/utils/type-guards.ts
389
- function isRecord(value) {
697
+ function isRecord3(value) {
390
698
  return typeof value === "object" && value !== null;
391
699
  }
392
700
 
@@ -418,10 +726,10 @@ async function updateEngineState(updater) {
418
726
  });
419
727
  }
420
728
  function isEngineRepoDiff(value) {
421
- return isRecord(value) && typeof value.added === "number" && typeof value.removed === "number";
729
+ return isRecord3(value) && typeof value.added === "number" && typeof value.removed === "number";
422
730
  }
423
731
  function coerceRepoState(value) {
424
- if (!isRecord(value)) {
732
+ if (!isRecord3(value)) {
425
733
  return null;
426
734
  }
427
735
  if (typeof value.name !== "string") return null;
@@ -447,11 +755,11 @@ function coerceRepoState(value) {
447
755
  };
448
756
  }
449
757
  function coerceEngineState(value) {
450
- if (!isRecord(value)) {
758
+ if (!isRecord3(value)) {
451
759
  return {};
452
760
  }
453
761
  const partial = {};
454
- if (isRecord(value.repos)) {
762
+ if (isRecord3(value.repos)) {
455
763
  const repos = {};
456
764
  for (const [repoName, repoState] of Object.entries(value.repos)) {
457
765
  const coerced = coerceRepoState(repoState);
@@ -502,7 +810,7 @@ async function saveRepoState(repoName, state, fallbackState) {
502
810
 
503
811
  // src/git/commands.ts
504
812
  import { execFileSync } from "child_process";
505
- import { readFileSync } from "fs";
813
+ import { readFileSync as readFileSync2 } from "fs";
506
814
  import { join as join3 } from "path";
507
815
  function runGitCommand(args, cwd) {
508
816
  return execFileSync("git", args, {
@@ -513,7 +821,7 @@ function runGitCommand(args, cwd) {
513
821
  }
514
822
  function readRepoHeadBranch(repoPath) {
515
823
  try {
516
- const contents = readFileSync(join3(repoPath, ".git", "HEAD"), "utf-8").trim();
824
+ const contents = readFileSync2(join3(repoPath, ".git", "HEAD"), "utf-8").trim();
517
825
  const match = contents.match(/^ref:\s+refs\/heads\/(.+)$/);
518
826
  return match ? match[1] : null;
519
827
  } catch {
@@ -968,239 +1276,6 @@ import { homedir as homedir5 } from "os";
968
1276
  import { exec } from "child_process";
969
1277
  import { promisify as promisify2 } from "util";
970
1278
 
971
- // ../shared/src/event.ts
972
- var CODEX_QUOTA_STATUS_EVENT_TYPE = "codex-quota-status";
973
-
974
- // ../shared/src/pricing.ts
975
- var PLANS = {
976
- hobby: {
977
- id: "hobby",
978
- name: "Hobby",
979
- monthlyPrice: 0,
980
- seatPriceCents: 0,
981
- creditsIncluded: 1200,
982
- features: [
983
- "1,200 minutes of human-initiated workspace usage (one-time)",
984
- "1,200 minutes of API + automation usage (one-time)",
985
- "Automations (limited to 2)",
986
- "Warm pools and warm hooks",
987
- "Up to 3 repositories"
988
- ]
989
- },
990
- developer: {
991
- id: "developer",
992
- name: "Developer",
993
- monthlyPrice: 120,
994
- seatPriceCents: 12e3,
995
- creditsIncluded: 0,
996
- features: [
997
- "Unlimited human-initiated workspaces",
998
- "5,000 included automation/API minutes per month",
999
- "Up to 10 repositories",
1000
- "Up to 5 automations",
1001
- "Warm pools and warm hooks",
1002
- "API access"
1003
- ]
1004
- },
1005
- team: {
1006
- id: "team",
1007
- name: "Team",
1008
- monthlyPrice: 300,
1009
- seatPriceCents: 3e4,
1010
- creditsIncluded: 0,
1011
- features: [
1012
- "Unlimited human-initiated workspaces",
1013
- "15,000 included automation/API minutes per month",
1014
- "Unlimited repositories",
1015
- "Unlimited automations",
1016
- "Higher API rate limits",
1017
- "Warm pools and warm hooks",
1018
- "Auto-upgraded sandbox resources (32 GB disk, 16 GB memory)",
1019
- "Shared Slack support channel"
1020
- ]
1021
- },
1022
- enterprise: {
1023
- id: "enterprise",
1024
- name: "Enterprise",
1025
- monthlyPrice: 0,
1026
- seatPriceCents: 0,
1027
- creditsIncluded: 0,
1028
- features: [
1029
- "Unlimited usage",
1030
- "Unlimited automations",
1031
- "Custom API rates",
1032
- "Custom rate limits",
1033
- "Custom warm hooks and pools",
1034
- "Shared Slack support channel",
1035
- "SOC 2"
1036
- ]
1037
- }
1038
- };
1039
- var TEAM_PLAN = PLANS.team;
1040
- var ENTERPRISE_PLAN = PLANS.enterprise;
1041
-
1042
- // ../shared/src/sandbox.ts
1043
- var SANDBOX_LIFECYCLE = {
1044
- AUTO_STOP_MINUTES: 60,
1045
- AUTO_ARCHIVE_MINUTES: 60 * 24 * 7,
1046
- AUTO_DELETE_MINUTES: -1,
1047
- SSH_TOKEN_EXPIRATION_MINUTES: 3 * 60
1048
- };
1049
- var SANDBOX_PATHS = {
1050
- HOME_DIR: "/home/ubuntu",
1051
- WORKSPACES_DIR: "/home/ubuntu/workspaces",
1052
- REPLICAS_DIR: "/home/ubuntu/.replicas",
1053
- REPLICAS_FILES_DIR: "/home/ubuntu/.replicas/files",
1054
- REPLICAS_FILES_DISPLAY_DIR: "~/.replicas/files",
1055
- REPLICAS_RUNTIME_ENV_FILE: "/home/ubuntu/.replicas/runtime-env.sh",
1056
- REPLICAS_PREVIEW_PORTS_FILE: "/home/ubuntu/.replicas/preview-ports.json"
1057
- };
1058
-
1059
- // ../shared/src/replicas-config.ts
1060
- import { parse as parseYaml } from "yaml";
1061
-
1062
- // ../shared/src/warm-hooks.ts
1063
- var DEFAULT_WARM_HOOK_TIMEOUT_MS = 5 * 60 * 1e3;
1064
- var MAX_WARM_HOOK_TIMEOUT_MS = 15 * 60 * 1e3;
1065
- var DEFAULT_HOOK_OUTPUT_PREVIEW_CHARS = 1e5;
1066
- var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
1067
- function isRecord2(value) {
1068
- return typeof value === "object" && value !== null;
1069
- }
1070
- function clampWarmHookTimeoutMs(timeoutMs) {
1071
- if (!timeoutMs || Number.isNaN(timeoutMs) || timeoutMs <= 0) {
1072
- return DEFAULT_WARM_HOOK_TIMEOUT_MS;
1073
- }
1074
- return Math.min(timeoutMs, MAX_WARM_HOOK_TIMEOUT_MS);
1075
- }
1076
- function buildHookOutputPreview(text, maxChars = DEFAULT_HOOK_OUTPUT_PREVIEW_CHARS) {
1077
- if (text.length <= maxChars) {
1078
- return { output: text, outputTruncated: false, outputTotalChars: text.length };
1079
- }
1080
- return {
1081
- output: `${text.slice(0, maxChars)}
1082
- ...[truncated \u2014 download the full log to see the rest]`,
1083
- outputTruncated: true,
1084
- outputTotalChars: text.length
1085
- };
1086
- }
1087
- function parseWarmHookConfig(value, filename = "replicas.json") {
1088
- if (typeof value === "string") {
1089
- return value;
1090
- }
1091
- if (!isRecord2(value)) {
1092
- throw new Error(`Invalid ${filename}: "warmHook" must be a string or object`);
1093
- }
1094
- if (!Array.isArray(value.commands) || !value.commands.every((entry) => typeof entry === "string")) {
1095
- throw new Error(`Invalid ${filename}: "warmHook.commands" must be an array of shell commands`);
1096
- }
1097
- if (value.timeout !== void 0 && (typeof value.timeout !== "number" || value.timeout <= 0)) {
1098
- throw new Error(`Invalid ${filename}: "warmHook.timeout" must be a positive number`);
1099
- }
1100
- return {
1101
- commands: value.commands,
1102
- timeout: value.timeout
1103
- };
1104
- }
1105
- function resolveWarmHookConfig(value) {
1106
- if (value === void 0) {
1107
- return null;
1108
- }
1109
- const parsed = parseWarmHookConfig(value);
1110
- const commands = typeof parsed === "string" ? [parsed.trim()].filter(Boolean) : parsed.commands.map((command) => command.trim()).filter(Boolean);
1111
- if (commands.length === 0) {
1112
- return null;
1113
- }
1114
- return {
1115
- commands,
1116
- timeoutMs: typeof parsed === "string" ? void 0 : parsed.timeout
1117
- };
1118
- }
1119
-
1120
- // ../shared/src/replicas-config.ts
1121
- var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
1122
- function isRecord3(value) {
1123
- return typeof value === "object" && value !== null;
1124
- }
1125
- function parseReplicasConfig(value, filename = "replicas.json") {
1126
- if (!isRecord3(value)) {
1127
- throw new Error(`Invalid ${filename}: expected an object`);
1128
- }
1129
- const config = {};
1130
- if ("organizationId" in value) {
1131
- if (typeof value.organizationId !== "string") {
1132
- throw new Error(`Invalid ${filename}: "organizationId" must be a string`);
1133
- }
1134
- config.organizationId = value.organizationId;
1135
- }
1136
- if ("systemPrompt" in value) {
1137
- if (typeof value.systemPrompt !== "string") {
1138
- throw new Error(`Invalid ${filename}: "systemPrompt" must be a string`);
1139
- }
1140
- config.systemPrompt = value.systemPrompt;
1141
- }
1142
- if ("startHook" in value) {
1143
- if (!isRecord3(value.startHook)) {
1144
- throw new Error(`Invalid ${filename}: "startHook" must be an object with "commands" array`);
1145
- }
1146
- const { commands, timeout } = value.startHook;
1147
- if (!Array.isArray(commands) || !commands.every((entry) => typeof entry === "string")) {
1148
- throw new Error(`Invalid ${filename}: "startHook.commands" must be an array of shell commands`);
1149
- }
1150
- if (timeout !== void 0 && (typeof timeout !== "number" || timeout <= 0)) {
1151
- throw new Error(`Invalid ${filename}: "startHook.timeout" must be a positive number`);
1152
- }
1153
- config.startHook = { commands, timeout };
1154
- }
1155
- if ("warmHook" in value) {
1156
- config.warmHook = parseWarmHookConfig(value.warmHook, filename);
1157
- }
1158
- return config;
1159
- }
1160
- function parseReplicasConfigString(content, filename) {
1161
- const isYaml = filename.endsWith(".yaml") || filename.endsWith(".yml");
1162
- let parsed;
1163
- if (isYaml) {
1164
- parsed = parseYaml(content);
1165
- } else {
1166
- parsed = JSON.parse(content);
1167
- }
1168
- return parseReplicasConfig(parsed, filename);
1169
- }
1170
-
1171
- // ../shared/src/engine/environment.ts
1172
- var DAYTONA_SNAPSHOT_ID = "07-05-2026-royal-york-v2";
1173
-
1174
- // ../shared/src/engine/types.ts
1175
- var DEFAULT_CHAT_TITLES = {
1176
- claude: "Claude Code",
1177
- codex: "Codex",
1178
- relay: "Relay"
1179
- };
1180
- var IMAGE_MEDIA_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"];
1181
-
1182
- // ../shared/src/routes/workspaces.ts
1183
- var WORKSPACE_FILE_UPLOAD_MAX_SIZE_BYTES = 20 * 1024 * 1024;
1184
- var WORKSPACE_FILE_CONTENT_MAX_SIZE_BYTES = 1 * 1024 * 1024;
1185
-
1186
- // ../shared/src/audit-log.ts
1187
- var AUDIT_LOG_ACTION = {
1188
- CREATE: "create",
1189
- UPDATE: "update",
1190
- DELETE: "delete",
1191
- CONNECT: "connect",
1192
- DISCONNECT: "disconnect"
1193
- };
1194
- var AUDIT_LOG_ACTIONS = Object.values(AUDIT_LOG_ACTION);
1195
-
1196
- // ../shared/src/object-store/types.ts
1197
- var MEDIA_KIND = {
1198
- IMAGE: "image",
1199
- VIDEO: "video",
1200
- AUDIO: "audio"
1201
- };
1202
- var MEDIA_KINDS = [MEDIA_KIND.IMAGE, MEDIA_KIND.VIDEO, MEDIA_KIND.AUDIO];
1203
-
1204
1279
  // src/services/environment-details-service.ts
1205
1280
  import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile3 } from "fs/promises";
1206
1281
  import { existsSync as existsSync3 } from "fs";
@@ -1788,10 +1863,10 @@ import { homedir as homedir7 } from "os";
1788
1863
  // src/utils/jsonl-reader.ts
1789
1864
  import { readFile as readFile6 } from "fs/promises";
1790
1865
  function isJsonlEvent(value) {
1791
- if (!isRecord(value)) {
1866
+ if (!isRecord3(value)) {
1792
1867
  return false;
1793
1868
  }
1794
- return typeof value.timestamp === "string" && typeof value.type === "string" && isRecord(value.payload);
1869
+ return typeof value.timestamp === "string" && typeof value.type === "string" && isRecord3(value.payload);
1795
1870
  }
1796
1871
  function parseJsonlEvents(lines) {
1797
1872
  const events = [];
@@ -2844,20 +2919,20 @@ function isLinearThoughtEvent2(event) {
2844
2919
  return event.content.type === "thought";
2845
2920
  }
2846
2921
  function isJsonlEvent2(value) {
2847
- if (!isRecord(value)) {
2922
+ if (!isRecord3(value)) {
2848
2923
  return false;
2849
2924
  }
2850
- return typeof value.timestamp === "string" && typeof value.type === "string" && isRecord(value.payload);
2925
+ return typeof value.timestamp === "string" && typeof value.type === "string" && isRecord3(value.payload);
2851
2926
  }
2852
2927
  function sleep(ms) {
2853
2928
  return new Promise((resolve2) => setTimeout(resolve2, ms));
2854
2929
  }
2855
2930
  function extractRateLimitsSnapshot(parsed) {
2856
- if (!isRecord(parsed)) return null;
2857
- const payload = isRecord(parsed.payload) ? parsed.payload : parsed;
2858
- const rateLimits = isRecord(payload.rate_limits) ? payload.rate_limits : null;
2931
+ if (!isRecord3(parsed)) return null;
2932
+ const payload = isRecord3(parsed.payload) ? parsed.payload : parsed;
2933
+ const rateLimits = isRecord3(payload.rate_limits) ? payload.rate_limits : null;
2859
2934
  if (!rateLimits) return null;
2860
- const credits = isRecord(rateLimits.credits) ? rateLimits.credits : null;
2935
+ const credits = isRecord3(rateLimits.credits) ? rateLimits.credits : null;
2861
2936
  const hasCredits = credits && typeof credits.has_credits === "boolean" ? credits.has_credits : null;
2862
2937
  const unlimited = credits && typeof credits.unlimited === "boolean" ? credits.unlimited : null;
2863
2938
  const balance = credits && typeof credits.balance === "string" ? credits.balance : null;
@@ -2987,7 +3062,7 @@ var CodexManager = class extends CodingAgentManager {
2987
3062
  try {
2988
3063
  const existingContent = await readFile7(CODEX_CONFIG_PATH, "utf-8");
2989
3064
  const parsed = parseToml(existingContent);
2990
- if (isRecord(parsed)) {
3065
+ if (isRecord3(parsed)) {
2991
3066
  config = parsed;
2992
3067
  }
2993
3068
  } catch (parseError) {
@@ -3913,7 +3988,7 @@ function isCodexAvailable() {
3913
3988
  return existsSync7(CODEX_AUTH_PATH2) || Boolean(ENGINE_ENV.OPENAI_API_KEY);
3914
3989
  }
3915
3990
  function isPersistedChat(value) {
3916
- if (!isRecord(value)) {
3991
+ if (!isRecord3(value)) {
3917
3992
  return false;
3918
3993
  }
3919
3994
  const candidate = value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.145",
3
+ "version": "0.1.146",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",