replicas-engine 0.1.45 → 0.1.46
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 +215 -21
- package/dist/src/{lib-YXLVEBQC.js → lib-WNJM7YOZ.js} +10 -10
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import "./chunk-ZXMDA7VB.js";
|
|
|
5
5
|
import "dotenv/config";
|
|
6
6
|
import { serve } from "@hono/node-server";
|
|
7
7
|
import { Hono as Hono2 } from "hono";
|
|
8
|
-
import { readFile as
|
|
8
|
+
import { readFile as readFile8 } from "fs/promises";
|
|
9
9
|
import { execSync } from "child_process";
|
|
10
10
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
11
11
|
|
|
@@ -836,6 +836,80 @@ import { join as join5 } from "path";
|
|
|
836
836
|
import { homedir as homedir4 } from "os";
|
|
837
837
|
import { exec } from "child_process";
|
|
838
838
|
import { promisify } from "util";
|
|
839
|
+
|
|
840
|
+
// ../shared/src/sandbox.ts
|
|
841
|
+
var SANDBOX_LIFECYCLE = {
|
|
842
|
+
AUTO_STOP_MINUTES: 60,
|
|
843
|
+
AUTO_ARCHIVE_MINUTES: 60 * 24 * 7,
|
|
844
|
+
AUTO_DELETE_MINUTES: -1,
|
|
845
|
+
SSH_TOKEN_EXPIRATION_MINUTES: 3 * 60
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
// ../shared/src/warm-hooks.ts
|
|
849
|
+
var DEFAULT_WARM_HOOK_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
850
|
+
var MAX_WARM_HOOK_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
851
|
+
var DEFAULT_WARM_HOOK_OUTPUT_MAX_CHARS = 12e3;
|
|
852
|
+
function isRecord2(value) {
|
|
853
|
+
return typeof value === "object" && value !== null;
|
|
854
|
+
}
|
|
855
|
+
function clampWarmHookTimeoutMs(timeoutMs) {
|
|
856
|
+
if (!timeoutMs || Number.isNaN(timeoutMs) || timeoutMs <= 0) {
|
|
857
|
+
return DEFAULT_WARM_HOOK_TIMEOUT_MS;
|
|
858
|
+
}
|
|
859
|
+
return Math.min(timeoutMs, MAX_WARM_HOOK_TIMEOUT_MS);
|
|
860
|
+
}
|
|
861
|
+
function truncateWarmHookOutput(text, maxChars = DEFAULT_WARM_HOOK_OUTPUT_MAX_CHARS) {
|
|
862
|
+
if (text.length <= maxChars) {
|
|
863
|
+
return text;
|
|
864
|
+
}
|
|
865
|
+
return `${text.slice(0, maxChars)}
|
|
866
|
+
...[truncated]`;
|
|
867
|
+
}
|
|
868
|
+
function parseWarmHookConfig(value) {
|
|
869
|
+
if (typeof value === "string") {
|
|
870
|
+
return value;
|
|
871
|
+
}
|
|
872
|
+
if (!isRecord2(value)) {
|
|
873
|
+
throw new Error('Invalid replicas.json: "warmHook" must be a string or object');
|
|
874
|
+
}
|
|
875
|
+
if (typeof value.content !== "string") {
|
|
876
|
+
throw new Error('Invalid replicas.json: "warmHook.content" must be a string');
|
|
877
|
+
}
|
|
878
|
+
if (value.timeout !== void 0 && (typeof value.timeout !== "number" || value.timeout <= 0)) {
|
|
879
|
+
throw new Error('Invalid replicas.json: "warmHook.timeout" must be a positive number');
|
|
880
|
+
}
|
|
881
|
+
return {
|
|
882
|
+
content: value.content,
|
|
883
|
+
timeout: value.timeout
|
|
884
|
+
};
|
|
885
|
+
}
|
|
886
|
+
function resolveWarmHookConfig(value) {
|
|
887
|
+
if (value === void 0) {
|
|
888
|
+
return null;
|
|
889
|
+
}
|
|
890
|
+
const parsed = parseWarmHookConfig(value);
|
|
891
|
+
const content = (typeof parsed === "string" ? parsed : parsed.content).trim();
|
|
892
|
+
if (!content) {
|
|
893
|
+
return null;
|
|
894
|
+
}
|
|
895
|
+
return {
|
|
896
|
+
content,
|
|
897
|
+
timeoutMs: typeof parsed === "string" ? void 0 : parsed.timeout
|
|
898
|
+
};
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
// ../shared/src/engine/types.ts
|
|
902
|
+
var DEFAULT_CHAT_TITLES = {
|
|
903
|
+
claude: "Claude Code",
|
|
904
|
+
codex: "Codex"
|
|
905
|
+
};
|
|
906
|
+
var IMAGE_MEDIA_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"];
|
|
907
|
+
|
|
908
|
+
// ../shared/src/routes/workspaces.ts
|
|
909
|
+
var WORKSPACE_FILE_UPLOAD_MAX_SIZE_BYTES = 20 * 1024 * 1024;
|
|
910
|
+
var WORKSPACE_FILE_CONTENT_MAX_SIZE_BYTES = 1 * 1024 * 1024;
|
|
911
|
+
|
|
912
|
+
// src/services/replicas-config-service.ts
|
|
839
913
|
var execAsync = promisify(exec);
|
|
840
914
|
var START_HOOKS_LOG = join5(homedir4(), ".replicas", "startHooks.log");
|
|
841
915
|
var START_HOOKS_RUNNING_PROMPT = `IMPORTANT - Start Hooks Running:
|
|
@@ -888,6 +962,9 @@ function parseReplicasConfig(value) {
|
|
|
888
962
|
}
|
|
889
963
|
config.startHook = { commands, timeout };
|
|
890
964
|
}
|
|
965
|
+
if ("warmHook" in value) {
|
|
966
|
+
config.warmHook = parseWarmHookConfig(value.warmHook);
|
|
967
|
+
}
|
|
891
968
|
return config;
|
|
892
969
|
}
|
|
893
970
|
var ReplicasConfigService = class {
|
|
@@ -1120,25 +1197,6 @@ import { homedir as homedir8 } from "os";
|
|
|
1120
1197
|
import { join as join9 } from "path";
|
|
1121
1198
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
1122
1199
|
|
|
1123
|
-
// ../shared/src/sandbox.ts
|
|
1124
|
-
var SANDBOX_LIFECYCLE = {
|
|
1125
|
-
AUTO_STOP_MINUTES: 60,
|
|
1126
|
-
AUTO_ARCHIVE_MINUTES: 60 * 24 * 7,
|
|
1127
|
-
AUTO_DELETE_MINUTES: -1,
|
|
1128
|
-
SSH_TOKEN_EXPIRATION_MINUTES: 3 * 60
|
|
1129
|
-
};
|
|
1130
|
-
|
|
1131
|
-
// ../shared/src/engine/types.ts
|
|
1132
|
-
var DEFAULT_CHAT_TITLES = {
|
|
1133
|
-
claude: "Claude Code",
|
|
1134
|
-
codex: "Codex"
|
|
1135
|
-
};
|
|
1136
|
-
var IMAGE_MEDIA_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"];
|
|
1137
|
-
|
|
1138
|
-
// ../shared/src/routes/workspaces.ts
|
|
1139
|
-
var WORKSPACE_FILE_UPLOAD_MAX_SIZE_BYTES = 20 * 1024 * 1024;
|
|
1140
|
-
var WORKSPACE_FILE_CONTENT_MAX_SIZE_BYTES = 1 * 1024 * 1024;
|
|
1141
|
-
|
|
1142
1200
|
// src/managers/claude-manager.ts
|
|
1143
1201
|
import {
|
|
1144
1202
|
query
|
|
@@ -2767,6 +2825,122 @@ var PlanService = class {
|
|
|
2767
2825
|
};
|
|
2768
2826
|
var planService = new PlanService();
|
|
2769
2827
|
|
|
2828
|
+
// src/services/warm-hooks-service.ts
|
|
2829
|
+
import { execFile } from "child_process";
|
|
2830
|
+
import { promisify as promisify2 } from "util";
|
|
2831
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
2832
|
+
import { join as join11 } from "path";
|
|
2833
|
+
var execFileAsync = promisify2(execFile);
|
|
2834
|
+
async function executeHookScript(params) {
|
|
2835
|
+
const timeout = clampWarmHookTimeoutMs(params.timeoutMs);
|
|
2836
|
+
try {
|
|
2837
|
+
const { stdout, stderr } = await execFileAsync("bash", ["-lc", params.content], {
|
|
2838
|
+
cwd: params.cwd,
|
|
2839
|
+
timeout,
|
|
2840
|
+
maxBuffer: 1024 * 1024,
|
|
2841
|
+
env: process.env
|
|
2842
|
+
});
|
|
2843
|
+
const combined = [`$ ${params.label}`, stdout ?? "", stderr ?? ""].filter(Boolean).join("\n");
|
|
2844
|
+
return {
|
|
2845
|
+
exitCode: 0,
|
|
2846
|
+
output: truncateWarmHookOutput(combined),
|
|
2847
|
+
timedOut: false
|
|
2848
|
+
};
|
|
2849
|
+
} catch (error) {
|
|
2850
|
+
const execError = error;
|
|
2851
|
+
const timedOut = execError.signal === "SIGTERM" || execError.killed === true;
|
|
2852
|
+
const exitCode = typeof execError.code === "number" ? execError.code : 1;
|
|
2853
|
+
const combined = [`$ ${params.label}`, execError.stdout ?? "", execError.stderr ?? "", execError.message].filter(Boolean).join("\n");
|
|
2854
|
+
return {
|
|
2855
|
+
exitCode,
|
|
2856
|
+
output: truncateWarmHookOutput(combined),
|
|
2857
|
+
timedOut
|
|
2858
|
+
};
|
|
2859
|
+
}
|
|
2860
|
+
}
|
|
2861
|
+
async function readRepoWarmHook(repoPath) {
|
|
2862
|
+
const configPath = join11(repoPath, "replicas.json");
|
|
2863
|
+
try {
|
|
2864
|
+
const raw = await readFile7(configPath, "utf-8");
|
|
2865
|
+
const parsed = JSON.parse(raw);
|
|
2866
|
+
if (!isRecord(parsed) || !("warmHook" in parsed)) {
|
|
2867
|
+
return null;
|
|
2868
|
+
}
|
|
2869
|
+
return resolveWarmHookConfig(parsed.warmHook);
|
|
2870
|
+
} catch {
|
|
2871
|
+
return null;
|
|
2872
|
+
}
|
|
2873
|
+
}
|
|
2874
|
+
async function collectRepoWarmHooks() {
|
|
2875
|
+
const repos = await gitService.listRepositories();
|
|
2876
|
+
const collected = [];
|
|
2877
|
+
for (const repo of repos) {
|
|
2878
|
+
const warmHook = await readRepoWarmHook(repo.path);
|
|
2879
|
+
if (!warmHook) {
|
|
2880
|
+
continue;
|
|
2881
|
+
}
|
|
2882
|
+
collected.push({
|
|
2883
|
+
repoName: repo.name,
|
|
2884
|
+
repoPath: repo.path,
|
|
2885
|
+
content: warmHook.content,
|
|
2886
|
+
timeoutMs: warmHook.timeoutMs
|
|
2887
|
+
});
|
|
2888
|
+
}
|
|
2889
|
+
collected.sort((a, b) => a.repoName.localeCompare(b.repoName));
|
|
2890
|
+
return collected;
|
|
2891
|
+
}
|
|
2892
|
+
async function runWarmHooks(params) {
|
|
2893
|
+
const outputBlocks = [];
|
|
2894
|
+
const orgHook = params.organizationWarmHook?.trim();
|
|
2895
|
+
if (orgHook) {
|
|
2896
|
+
const orgResult = await executeHookScript({
|
|
2897
|
+
label: "org-warm-hook",
|
|
2898
|
+
cwd: gitService.getWorkspaceRoot(),
|
|
2899
|
+
content: orgHook,
|
|
2900
|
+
timeoutMs: params.timeoutMs
|
|
2901
|
+
});
|
|
2902
|
+
outputBlocks.push(orgResult.output);
|
|
2903
|
+
if (orgResult.exitCode !== 0) {
|
|
2904
|
+
return {
|
|
2905
|
+
exitCode: orgResult.exitCode,
|
|
2906
|
+
output: outputBlocks.join("\n\n"),
|
|
2907
|
+
timedOut: orgResult.timedOut
|
|
2908
|
+
};
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
if (params.includeRepoHooks !== false) {
|
|
2912
|
+
const repoHooks = await collectRepoWarmHooks();
|
|
2913
|
+
for (const repoHook of repoHooks) {
|
|
2914
|
+
const repoResult = await executeHookScript({
|
|
2915
|
+
label: `repo-warm-hook:${repoHook.repoName}`,
|
|
2916
|
+
cwd: repoHook.repoPath,
|
|
2917
|
+
content: repoHook.content,
|
|
2918
|
+
timeoutMs: repoHook.timeoutMs
|
|
2919
|
+
});
|
|
2920
|
+
outputBlocks.push(repoResult.output);
|
|
2921
|
+
if (repoResult.exitCode !== 0) {
|
|
2922
|
+
return {
|
|
2923
|
+
exitCode: repoResult.exitCode,
|
|
2924
|
+
output: outputBlocks.join("\n\n"),
|
|
2925
|
+
timedOut: repoResult.timedOut
|
|
2926
|
+
};
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
}
|
|
2930
|
+
if (outputBlocks.length === 0) {
|
|
2931
|
+
return {
|
|
2932
|
+
exitCode: 0,
|
|
2933
|
+
output: "No warm hooks configured.",
|
|
2934
|
+
timedOut: false
|
|
2935
|
+
};
|
|
2936
|
+
}
|
|
2937
|
+
return {
|
|
2938
|
+
exitCode: 0,
|
|
2939
|
+
output: outputBlocks.join("\n\n"),
|
|
2940
|
+
timedOut: false
|
|
2941
|
+
};
|
|
2942
|
+
}
|
|
2943
|
+
|
|
2770
2944
|
// src/v1-routes.ts
|
|
2771
2945
|
var createChatSchema = z.object({
|
|
2772
2946
|
provider: z.enum(["claude", "codex"]),
|
|
@@ -2987,6 +3161,26 @@ function createV1Routes(deps) {
|
|
|
2987
3161
|
};
|
|
2988
3162
|
return c.json(response);
|
|
2989
3163
|
});
|
|
3164
|
+
app2.post("/warm-hooks/run", async (c) => {
|
|
3165
|
+
try {
|
|
3166
|
+
const body = await c.req.json();
|
|
3167
|
+
const result = await runWarmHooks({
|
|
3168
|
+
organizationWarmHook: body.organizationWarmHook,
|
|
3169
|
+
includeRepoHooks: body.includeRepoHooks,
|
|
3170
|
+
timeoutMs: body.timeoutMs
|
|
3171
|
+
});
|
|
3172
|
+
return c.json({
|
|
3173
|
+
exit_code: result.exitCode,
|
|
3174
|
+
output: result.output,
|
|
3175
|
+
timed_out: result.timedOut
|
|
3176
|
+
});
|
|
3177
|
+
} catch (error) {
|
|
3178
|
+
return c.json(
|
|
3179
|
+
jsonError("Failed to run warm hooks", error instanceof Error ? error.message : "Unknown error"),
|
|
3180
|
+
500
|
|
3181
|
+
);
|
|
3182
|
+
}
|
|
3183
|
+
});
|
|
2990
3184
|
return app2;
|
|
2991
3185
|
}
|
|
2992
3186
|
|
|
@@ -3027,7 +3221,7 @@ app.get("/health", async (c) => {
|
|
|
3027
3221
|
return c.json({ status: "initializing", timestamp: (/* @__PURE__ */ new Date()).toISOString() }, 503);
|
|
3028
3222
|
}
|
|
3029
3223
|
try {
|
|
3030
|
-
const logContent = await
|
|
3224
|
+
const logContent = await readFile8("/var/log/cloud-init-output.log", "utf-8");
|
|
3031
3225
|
let status;
|
|
3032
3226
|
if (logContent.includes(COMPLETION_MESSAGE)) {
|
|
3033
3227
|
status = "active";
|
|
@@ -167,8 +167,8 @@ var require_utils = __commonJS({
|
|
|
167
167
|
Object.defineProperty(target, keys[i], Object.getOwnPropertyDescriptor(source, keys[i]));
|
|
168
168
|
}
|
|
169
169
|
};
|
|
170
|
-
module.exports.wrapperSymbol =
|
|
171
|
-
module.exports.implSymbol =
|
|
170
|
+
module.exports.wrapperSymbol = Symbol("wrapper");
|
|
171
|
+
module.exports.implSymbol = Symbol("impl");
|
|
172
172
|
module.exports.wrapperForImpl = function(impl) {
|
|
173
173
|
return impl[module.exports.wrapperSymbol];
|
|
174
174
|
};
|
|
@@ -361,7 +361,7 @@ var require_url_state_machine = __commonJS({
|
|
|
361
361
|
ws: 80,
|
|
362
362
|
wss: 443
|
|
363
363
|
};
|
|
364
|
-
var failure =
|
|
364
|
+
var failure = Symbol("failure");
|
|
365
365
|
function countSymbols(str) {
|
|
366
366
|
return punycode.ucs2.decode(str).length;
|
|
367
367
|
}
|
|
@@ -1787,8 +1787,8 @@ var require_lib2 = __commonJS({
|
|
|
1787
1787
|
var https = _interopDefault(__require("https"));
|
|
1788
1788
|
var zlib = _interopDefault(__require("zlib"));
|
|
1789
1789
|
var Readable = Stream.Readable;
|
|
1790
|
-
var BUFFER =
|
|
1791
|
-
var TYPE =
|
|
1790
|
+
var BUFFER = Symbol("buffer");
|
|
1791
|
+
var TYPE = Symbol("type");
|
|
1792
1792
|
var Blob = class _Blob {
|
|
1793
1793
|
constructor() {
|
|
1794
1794
|
this[TYPE] = "";
|
|
@@ -1899,7 +1899,7 @@ var require_lib2 = __commonJS({
|
|
|
1899
1899
|
FetchError.prototype.constructor = FetchError;
|
|
1900
1900
|
FetchError.prototype.name = "FetchError";
|
|
1901
1901
|
var convert;
|
|
1902
|
-
var INTERNALS =
|
|
1902
|
+
var INTERNALS = Symbol("Body internals");
|
|
1903
1903
|
var PassThrough = Stream.PassThrough;
|
|
1904
1904
|
function Body(body) {
|
|
1905
1905
|
var _this = this;
|
|
@@ -2239,7 +2239,7 @@ var require_lib2 = __commonJS({
|
|
|
2239
2239
|
}
|
|
2240
2240
|
return void 0;
|
|
2241
2241
|
}
|
|
2242
|
-
var MAP =
|
|
2242
|
+
var MAP = Symbol("map");
|
|
2243
2243
|
var Headers = class _Headers {
|
|
2244
2244
|
/**
|
|
2245
2245
|
* Headers class
|
|
@@ -2447,7 +2447,7 @@ var require_lib2 = __commonJS({
|
|
|
2447
2447
|
return [k.toLowerCase(), headers[MAP][k].join(", ")];
|
|
2448
2448
|
});
|
|
2449
2449
|
}
|
|
2450
|
-
var INTERNAL =
|
|
2450
|
+
var INTERNAL = Symbol("internal");
|
|
2451
2451
|
function createHeadersIterator(target, kind) {
|
|
2452
2452
|
const iterator = Object.create(HeadersIteratorPrototype);
|
|
2453
2453
|
iterator[INTERNAL] = {
|
|
@@ -2516,7 +2516,7 @@ var require_lib2 = __commonJS({
|
|
|
2516
2516
|
}
|
|
2517
2517
|
return headers;
|
|
2518
2518
|
}
|
|
2519
|
-
var INTERNALS$1 =
|
|
2519
|
+
var INTERNALS$1 = Symbol("Response internals");
|
|
2520
2520
|
var STATUS_CODES = http.STATUS_CODES;
|
|
2521
2521
|
var Response = class _Response {
|
|
2522
2522
|
constructor() {
|
|
@@ -2592,7 +2592,7 @@ var require_lib2 = __commonJS({
|
|
|
2592
2592
|
enumerable: false,
|
|
2593
2593
|
configurable: true
|
|
2594
2594
|
});
|
|
2595
|
-
var INTERNALS$2 =
|
|
2595
|
+
var INTERNALS$2 = Symbol("Request internals");
|
|
2596
2596
|
var URL = Url.URL || whatwgUrl.URL;
|
|
2597
2597
|
var parse_url = Url.parse;
|
|
2598
2598
|
var format_url = Url.format;
|