replicas-engine 0.1.145 → 0.1.147
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 +327 -250
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -14,6 +14,315 @@ 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
|
+
"Up to 5 environments"
|
|
39
|
+
]
|
|
40
|
+
},
|
|
41
|
+
developer: {
|
|
42
|
+
id: "developer",
|
|
43
|
+
name: "Developer",
|
|
44
|
+
monthlyPrice: 120,
|
|
45
|
+
seatPriceCents: 12e3,
|
|
46
|
+
creditsIncluded: 0,
|
|
47
|
+
features: [
|
|
48
|
+
"Unlimited human-initiated workspaces",
|
|
49
|
+
"5,000 included automation/API minutes per month",
|
|
50
|
+
"Up to 10 repositories",
|
|
51
|
+
"Up to 15 environments",
|
|
52
|
+
"Up to 5 automations",
|
|
53
|
+
"Warm pools and warm hooks",
|
|
54
|
+
"API access"
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
team: {
|
|
58
|
+
id: "team",
|
|
59
|
+
name: "Team",
|
|
60
|
+
monthlyPrice: 300,
|
|
61
|
+
seatPriceCents: 3e4,
|
|
62
|
+
creditsIncluded: 0,
|
|
63
|
+
features: [
|
|
64
|
+
"Unlimited human-initiated workspaces",
|
|
65
|
+
"15,000 included automation/API minutes per month",
|
|
66
|
+
"Unlimited repositories",
|
|
67
|
+
"Unlimited automations",
|
|
68
|
+
"Higher API rate limits",
|
|
69
|
+
"Warm pools and warm hooks",
|
|
70
|
+
"Auto-upgraded sandbox resources (32 GB disk, 16 GB memory)",
|
|
71
|
+
"Shared Slack support channel"
|
|
72
|
+
]
|
|
73
|
+
},
|
|
74
|
+
enterprise: {
|
|
75
|
+
id: "enterprise",
|
|
76
|
+
name: "Enterprise",
|
|
77
|
+
monthlyPrice: 0,
|
|
78
|
+
seatPriceCents: 0,
|
|
79
|
+
creditsIncluded: 0,
|
|
80
|
+
features: [
|
|
81
|
+
"Unlimited usage",
|
|
82
|
+
"Unlimited automations",
|
|
83
|
+
"Custom API rates",
|
|
84
|
+
"Custom rate limits",
|
|
85
|
+
"Custom warm hooks and pools",
|
|
86
|
+
"Shared Slack support channel",
|
|
87
|
+
"SOC 2"
|
|
88
|
+
]
|
|
89
|
+
}
|
|
90
|
+
};
|
|
91
|
+
var TEAM_PLAN = PLANS.team;
|
|
92
|
+
var ENTERPRISE_PLAN = PLANS.enterprise;
|
|
93
|
+
|
|
94
|
+
// ../shared/src/sandbox.ts
|
|
95
|
+
var SANDBOX_LIFECYCLE = {
|
|
96
|
+
AUTO_STOP_MINUTES: 60,
|
|
97
|
+
AUTO_ARCHIVE_MINUTES: 60 * 24 * 7,
|
|
98
|
+
AUTO_DELETE_MINUTES: -1,
|
|
99
|
+
SSH_TOKEN_EXPIRATION_MINUTES: 3 * 60
|
|
100
|
+
};
|
|
101
|
+
var SANDBOX_PATHS = {
|
|
102
|
+
HOME_DIR: "/home/ubuntu",
|
|
103
|
+
WORKSPACES_DIR: "/home/ubuntu/workspaces",
|
|
104
|
+
REPLICAS_DIR: "/home/ubuntu/.replicas",
|
|
105
|
+
REPLICAS_FILES_DIR: "/home/ubuntu/.replicas/files",
|
|
106
|
+
REPLICAS_FILES_DISPLAY_DIR: "~/.replicas/files",
|
|
107
|
+
REPLICAS_RUNTIME_ENV_FILE: "/home/ubuntu/.replicas/runtime-env.sh",
|
|
108
|
+
REPLICAS_PREVIEW_PORTS_FILE: "/home/ubuntu/.replicas/preview-ports.json"
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// ../shared/src/runtime-env.ts
|
|
112
|
+
function parsePosixEnvFile(content) {
|
|
113
|
+
const result = {};
|
|
114
|
+
let pos = 0;
|
|
115
|
+
while (pos < content.length) {
|
|
116
|
+
let lineStart;
|
|
117
|
+
if (pos === 0 || content[pos - 1] === "\n") {
|
|
118
|
+
lineStart = pos;
|
|
119
|
+
} else {
|
|
120
|
+
const nl2 = content.indexOf("\n", pos);
|
|
121
|
+
if (nl2 === -1) break;
|
|
122
|
+
lineStart = nl2 + 1;
|
|
123
|
+
}
|
|
124
|
+
if (!content.startsWith("export ", lineStart)) {
|
|
125
|
+
const nl2 = content.indexOf("\n", lineStart);
|
|
126
|
+
if (nl2 === -1) break;
|
|
127
|
+
pos = nl2 + 1;
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
const nameStart = lineStart + "export ".length;
|
|
131
|
+
const eqIdx = content.indexOf("=", nameStart);
|
|
132
|
+
if (eqIdx === -1) break;
|
|
133
|
+
const name = content.slice(nameStart, eqIdx).trim();
|
|
134
|
+
let cursor = eqIdx + 1;
|
|
135
|
+
if (content[cursor] !== "'") {
|
|
136
|
+
const nl2 = content.indexOf("\n", cursor);
|
|
137
|
+
pos = nl2 === -1 ? content.length : nl2 + 1;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
cursor += 1;
|
|
141
|
+
let value = "";
|
|
142
|
+
let closed = false;
|
|
143
|
+
while (cursor < content.length) {
|
|
144
|
+
const ch = content[cursor];
|
|
145
|
+
if (ch === "'") {
|
|
146
|
+
if (content.startsWith("\\''", cursor + 1)) {
|
|
147
|
+
value += "'";
|
|
148
|
+
cursor += 4;
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
cursor += 1;
|
|
152
|
+
closed = true;
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
value += ch;
|
|
156
|
+
cursor += 1;
|
|
157
|
+
}
|
|
158
|
+
if (closed && name) {
|
|
159
|
+
result[name] = value;
|
|
160
|
+
}
|
|
161
|
+
const nl = content.indexOf("\n", cursor);
|
|
162
|
+
pos = nl === -1 ? content.length : nl + 1;
|
|
163
|
+
}
|
|
164
|
+
return result;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// ../shared/src/replicas-config.ts
|
|
168
|
+
import { parse as parseYaml } from "yaml";
|
|
169
|
+
|
|
170
|
+
// ../shared/src/warm-hooks.ts
|
|
171
|
+
var DEFAULT_WARM_HOOK_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
172
|
+
var MAX_WARM_HOOK_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
173
|
+
var DEFAULT_HOOK_OUTPUT_PREVIEW_CHARS = 1e5;
|
|
174
|
+
var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
|
|
175
|
+
function isRecord(value) {
|
|
176
|
+
return typeof value === "object" && value !== null;
|
|
177
|
+
}
|
|
178
|
+
function clampWarmHookTimeoutMs(timeoutMs) {
|
|
179
|
+
if (!timeoutMs || Number.isNaN(timeoutMs) || timeoutMs <= 0) {
|
|
180
|
+
return DEFAULT_WARM_HOOK_TIMEOUT_MS;
|
|
181
|
+
}
|
|
182
|
+
return Math.min(timeoutMs, MAX_WARM_HOOK_TIMEOUT_MS);
|
|
183
|
+
}
|
|
184
|
+
function buildHookOutputPreview(text, maxChars = DEFAULT_HOOK_OUTPUT_PREVIEW_CHARS) {
|
|
185
|
+
if (text.length <= maxChars) {
|
|
186
|
+
return { output: text, outputTruncated: false, outputTotalChars: text.length };
|
|
187
|
+
}
|
|
188
|
+
return {
|
|
189
|
+
output: `${text.slice(0, maxChars)}
|
|
190
|
+
...[truncated \u2014 download the full log to see the rest]`,
|
|
191
|
+
outputTruncated: true,
|
|
192
|
+
outputTotalChars: text.length
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function parseWarmHookConfig(value, filename = "replicas.json") {
|
|
196
|
+
if (typeof value === "string") {
|
|
197
|
+
return value;
|
|
198
|
+
}
|
|
199
|
+
if (!isRecord(value)) {
|
|
200
|
+
throw new Error(`Invalid ${filename}: "warmHook" must be a string or object`);
|
|
201
|
+
}
|
|
202
|
+
if (!Array.isArray(value.commands) || !value.commands.every((entry) => typeof entry === "string")) {
|
|
203
|
+
throw new Error(`Invalid ${filename}: "warmHook.commands" must be an array of shell commands`);
|
|
204
|
+
}
|
|
205
|
+
if (value.timeout !== void 0 && (typeof value.timeout !== "number" || value.timeout <= 0)) {
|
|
206
|
+
throw new Error(`Invalid ${filename}: "warmHook.timeout" must be a positive number`);
|
|
207
|
+
}
|
|
208
|
+
return {
|
|
209
|
+
commands: value.commands,
|
|
210
|
+
timeout: value.timeout
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function resolveWarmHookConfig(value) {
|
|
214
|
+
if (value === void 0) {
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
const parsed = parseWarmHookConfig(value);
|
|
218
|
+
const commands = typeof parsed === "string" ? [parsed.trim()].filter(Boolean) : parsed.commands.map((command) => command.trim()).filter(Boolean);
|
|
219
|
+
if (commands.length === 0) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
commands,
|
|
224
|
+
timeoutMs: typeof parsed === "string" ? void 0 : parsed.timeout
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// ../shared/src/replicas-config.ts
|
|
229
|
+
var REPLICAS_CONFIG_FILENAMES = ["replicas.json", "replicas.yaml", "replicas.yml"];
|
|
230
|
+
function isRecord2(value) {
|
|
231
|
+
return typeof value === "object" && value !== null;
|
|
232
|
+
}
|
|
233
|
+
function parseReplicasConfig(value, filename = "replicas.json") {
|
|
234
|
+
if (!isRecord2(value)) {
|
|
235
|
+
throw new Error(`Invalid ${filename}: expected an object`);
|
|
236
|
+
}
|
|
237
|
+
const config = {};
|
|
238
|
+
if ("organizationId" in value) {
|
|
239
|
+
if (typeof value.organizationId !== "string") {
|
|
240
|
+
throw new Error(`Invalid ${filename}: "organizationId" must be a string`);
|
|
241
|
+
}
|
|
242
|
+
config.organizationId = value.organizationId;
|
|
243
|
+
}
|
|
244
|
+
if ("systemPrompt" in value) {
|
|
245
|
+
if (typeof value.systemPrompt !== "string") {
|
|
246
|
+
throw new Error(`Invalid ${filename}: "systemPrompt" must be a string`);
|
|
247
|
+
}
|
|
248
|
+
config.systemPrompt = value.systemPrompt;
|
|
249
|
+
}
|
|
250
|
+
if ("startHook" in value) {
|
|
251
|
+
if (!isRecord2(value.startHook)) {
|
|
252
|
+
throw new Error(`Invalid ${filename}: "startHook" must be an object with "commands" array`);
|
|
253
|
+
}
|
|
254
|
+
const { commands, timeout } = value.startHook;
|
|
255
|
+
if (!Array.isArray(commands) || !commands.every((entry) => typeof entry === "string")) {
|
|
256
|
+
throw new Error(`Invalid ${filename}: "startHook.commands" must be an array of shell commands`);
|
|
257
|
+
}
|
|
258
|
+
if (timeout !== void 0 && (typeof timeout !== "number" || timeout <= 0)) {
|
|
259
|
+
throw new Error(`Invalid ${filename}: "startHook.timeout" must be a positive number`);
|
|
260
|
+
}
|
|
261
|
+
config.startHook = { commands, timeout };
|
|
262
|
+
}
|
|
263
|
+
if ("warmHook" in value) {
|
|
264
|
+
config.warmHook = parseWarmHookConfig(value.warmHook, filename);
|
|
265
|
+
}
|
|
266
|
+
return config;
|
|
267
|
+
}
|
|
268
|
+
function parseReplicasConfigString(content, filename) {
|
|
269
|
+
const isYaml = filename.endsWith(".yaml") || filename.endsWith(".yml");
|
|
270
|
+
let parsed;
|
|
271
|
+
if (isYaml) {
|
|
272
|
+
parsed = parseYaml(content);
|
|
273
|
+
} else {
|
|
274
|
+
parsed = JSON.parse(content);
|
|
275
|
+
}
|
|
276
|
+
return parseReplicasConfig(parsed, filename);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// ../shared/src/engine/environment.ts
|
|
280
|
+
var DAYTONA_SNAPSHOT_ID = "07-05-2026-royal-york-v4";
|
|
281
|
+
|
|
282
|
+
// ../shared/src/engine/types.ts
|
|
283
|
+
var DEFAULT_CHAT_TITLES = {
|
|
284
|
+
claude: "Claude Code",
|
|
285
|
+
codex: "Codex",
|
|
286
|
+
relay: "Relay"
|
|
287
|
+
};
|
|
288
|
+
var IMAGE_MEDIA_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"];
|
|
289
|
+
|
|
290
|
+
// ../shared/src/routes/workspaces.ts
|
|
291
|
+
var WORKSPACE_FILE_UPLOAD_MAX_SIZE_BYTES = 20 * 1024 * 1024;
|
|
292
|
+
var WORKSPACE_FILE_CONTENT_MAX_SIZE_BYTES = 1 * 1024 * 1024;
|
|
293
|
+
|
|
294
|
+
// ../shared/src/audit-log.ts
|
|
295
|
+
var AUDIT_LOG_ACTION = {
|
|
296
|
+
CREATE: "create",
|
|
297
|
+
UPDATE: "update",
|
|
298
|
+
DELETE: "delete",
|
|
299
|
+
CONNECT: "connect",
|
|
300
|
+
DISCONNECT: "disconnect"
|
|
301
|
+
};
|
|
302
|
+
var AUDIT_LOG_ACTIONS = Object.values(AUDIT_LOG_ACTION);
|
|
303
|
+
|
|
304
|
+
// ../shared/src/object-store/types.ts
|
|
305
|
+
var MEDIA_KIND = {
|
|
306
|
+
IMAGE: "image",
|
|
307
|
+
VIDEO: "video",
|
|
308
|
+
AUDIO: "audio"
|
|
309
|
+
};
|
|
310
|
+
var MEDIA_KINDS = [MEDIA_KIND.IMAGE, MEDIA_KIND.VIDEO, MEDIA_KIND.AUDIO];
|
|
311
|
+
|
|
312
|
+
// src/runtime-env-loader.ts
|
|
313
|
+
function loadRuntimeEnvFile() {
|
|
314
|
+
let content;
|
|
315
|
+
try {
|
|
316
|
+
content = readFileSync(SANDBOX_PATHS.REPLICAS_RUNTIME_ENV_FILE, "utf-8");
|
|
317
|
+
} catch {
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
for (const [key, value] of Object.entries(parsePosixEnvFile(content))) {
|
|
321
|
+
process.env[key] = value;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// src/engine-env.ts
|
|
17
326
|
function readEnv(name) {
|
|
18
327
|
const value = process.env[name]?.trim();
|
|
19
328
|
return value ? value : void 0;
|
|
@@ -56,6 +365,7 @@ function parseCodexAuthMethod(value) {
|
|
|
56
365
|
}
|
|
57
366
|
var IS_WARMING_MODE = process.argv.includes("--warming");
|
|
58
367
|
function loadEngineEnv() {
|
|
368
|
+
loadRuntimeEnvFile();
|
|
59
369
|
const HOME_DIR = homedir();
|
|
60
370
|
const env = {
|
|
61
371
|
// Defined: always available
|
|
@@ -386,7 +696,7 @@ import { join as join2 } from "path";
|
|
|
386
696
|
import { homedir as homedir2 } from "os";
|
|
387
697
|
|
|
388
698
|
// src/utils/type-guards.ts
|
|
389
|
-
function
|
|
699
|
+
function isRecord3(value) {
|
|
390
700
|
return typeof value === "object" && value !== null;
|
|
391
701
|
}
|
|
392
702
|
|
|
@@ -418,10 +728,10 @@ async function updateEngineState(updater) {
|
|
|
418
728
|
});
|
|
419
729
|
}
|
|
420
730
|
function isEngineRepoDiff(value) {
|
|
421
|
-
return
|
|
731
|
+
return isRecord3(value) && typeof value.added === "number" && typeof value.removed === "number";
|
|
422
732
|
}
|
|
423
733
|
function coerceRepoState(value) {
|
|
424
|
-
if (!
|
|
734
|
+
if (!isRecord3(value)) {
|
|
425
735
|
return null;
|
|
426
736
|
}
|
|
427
737
|
if (typeof value.name !== "string") return null;
|
|
@@ -447,11 +757,11 @@ function coerceRepoState(value) {
|
|
|
447
757
|
};
|
|
448
758
|
}
|
|
449
759
|
function coerceEngineState(value) {
|
|
450
|
-
if (!
|
|
760
|
+
if (!isRecord3(value)) {
|
|
451
761
|
return {};
|
|
452
762
|
}
|
|
453
763
|
const partial = {};
|
|
454
|
-
if (
|
|
764
|
+
if (isRecord3(value.repos)) {
|
|
455
765
|
const repos = {};
|
|
456
766
|
for (const [repoName, repoState] of Object.entries(value.repos)) {
|
|
457
767
|
const coerced = coerceRepoState(repoState);
|
|
@@ -502,7 +812,7 @@ async function saveRepoState(repoName, state, fallbackState) {
|
|
|
502
812
|
|
|
503
813
|
// src/git/commands.ts
|
|
504
814
|
import { execFileSync } from "child_process";
|
|
505
|
-
import { readFileSync } from "fs";
|
|
815
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
506
816
|
import { join as join3 } from "path";
|
|
507
817
|
function runGitCommand(args, cwd) {
|
|
508
818
|
return execFileSync("git", args, {
|
|
@@ -513,7 +823,7 @@ function runGitCommand(args, cwd) {
|
|
|
513
823
|
}
|
|
514
824
|
function readRepoHeadBranch(repoPath) {
|
|
515
825
|
try {
|
|
516
|
-
const contents =
|
|
826
|
+
const contents = readFileSync2(join3(repoPath, ".git", "HEAD"), "utf-8").trim();
|
|
517
827
|
const match = contents.match(/^ref:\s+refs\/heads\/(.+)$/);
|
|
518
828
|
return match ? match[1] : null;
|
|
519
829
|
} catch {
|
|
@@ -968,239 +1278,6 @@ import { homedir as homedir5 } from "os";
|
|
|
968
1278
|
import { exec } from "child_process";
|
|
969
1279
|
import { promisify as promisify2 } from "util";
|
|
970
1280
|
|
|
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
1281
|
// src/services/environment-details-service.ts
|
|
1205
1282
|
import { mkdir as mkdir3, readFile as readFile2, writeFile as writeFile3 } from "fs/promises";
|
|
1206
1283
|
import { existsSync as existsSync3 } from "fs";
|
|
@@ -1788,10 +1865,10 @@ import { homedir as homedir7 } from "os";
|
|
|
1788
1865
|
// src/utils/jsonl-reader.ts
|
|
1789
1866
|
import { readFile as readFile6 } from "fs/promises";
|
|
1790
1867
|
function isJsonlEvent(value) {
|
|
1791
|
-
if (!
|
|
1868
|
+
if (!isRecord3(value)) {
|
|
1792
1869
|
return false;
|
|
1793
1870
|
}
|
|
1794
|
-
return typeof value.timestamp === "string" && typeof value.type === "string" &&
|
|
1871
|
+
return typeof value.timestamp === "string" && typeof value.type === "string" && isRecord3(value.payload);
|
|
1795
1872
|
}
|
|
1796
1873
|
function parseJsonlEvents(lines) {
|
|
1797
1874
|
const events = [];
|
|
@@ -2844,20 +2921,20 @@ function isLinearThoughtEvent2(event) {
|
|
|
2844
2921
|
return event.content.type === "thought";
|
|
2845
2922
|
}
|
|
2846
2923
|
function isJsonlEvent2(value) {
|
|
2847
|
-
if (!
|
|
2924
|
+
if (!isRecord3(value)) {
|
|
2848
2925
|
return false;
|
|
2849
2926
|
}
|
|
2850
|
-
return typeof value.timestamp === "string" && typeof value.type === "string" &&
|
|
2927
|
+
return typeof value.timestamp === "string" && typeof value.type === "string" && isRecord3(value.payload);
|
|
2851
2928
|
}
|
|
2852
2929
|
function sleep(ms) {
|
|
2853
2930
|
return new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
2854
2931
|
}
|
|
2855
2932
|
function extractRateLimitsSnapshot(parsed) {
|
|
2856
|
-
if (!
|
|
2857
|
-
const payload =
|
|
2858
|
-
const rateLimits =
|
|
2933
|
+
if (!isRecord3(parsed)) return null;
|
|
2934
|
+
const payload = isRecord3(parsed.payload) ? parsed.payload : parsed;
|
|
2935
|
+
const rateLimits = isRecord3(payload.rate_limits) ? payload.rate_limits : null;
|
|
2859
2936
|
if (!rateLimits) return null;
|
|
2860
|
-
const credits =
|
|
2937
|
+
const credits = isRecord3(rateLimits.credits) ? rateLimits.credits : null;
|
|
2861
2938
|
const hasCredits = credits && typeof credits.has_credits === "boolean" ? credits.has_credits : null;
|
|
2862
2939
|
const unlimited = credits && typeof credits.unlimited === "boolean" ? credits.unlimited : null;
|
|
2863
2940
|
const balance = credits && typeof credits.balance === "string" ? credits.balance : null;
|
|
@@ -2987,7 +3064,7 @@ var CodexManager = class extends CodingAgentManager {
|
|
|
2987
3064
|
try {
|
|
2988
3065
|
const existingContent = await readFile7(CODEX_CONFIG_PATH, "utf-8");
|
|
2989
3066
|
const parsed = parseToml(existingContent);
|
|
2990
|
-
if (
|
|
3067
|
+
if (isRecord3(parsed)) {
|
|
2991
3068
|
config = parsed;
|
|
2992
3069
|
}
|
|
2993
3070
|
} catch (parseError) {
|
|
@@ -3913,7 +3990,7 @@ function isCodexAvailable() {
|
|
|
3913
3990
|
return existsSync7(CODEX_AUTH_PATH2) || Boolean(ENGINE_ENV.OPENAI_API_KEY);
|
|
3914
3991
|
}
|
|
3915
3992
|
function isPersistedChat(value) {
|
|
3916
|
-
if (!
|
|
3993
|
+
if (!isRecord3(value)) {
|
|
3917
3994
|
return false;
|
|
3918
3995
|
}
|
|
3919
3996
|
const candidate = value;
|