replicas-engine 0.1.115 → 0.1.117

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 +114 -17
  2. package/package.json +1 -1
package/dist/src/index.js CHANGED
@@ -995,7 +995,8 @@ import { parse as parseYaml } from "yaml";
995
995
  // ../shared/src/warm-hooks.ts
996
996
  var DEFAULT_WARM_HOOK_TIMEOUT_MS = 5 * 60 * 1e3;
997
997
  var MAX_WARM_HOOK_TIMEOUT_MS = 15 * 60 * 1e3;
998
- var DEFAULT_WARM_HOOK_OUTPUT_MAX_CHARS = 12e3;
998
+ var DEFAULT_HOOK_OUTPUT_PREVIEW_CHARS = 1e5;
999
+ var HOOK_EXEC_MAX_BUFFER_BYTES = 10 * 1024 * 1024;
999
1000
  function isRecord2(value) {
1000
1001
  return typeof value === "object" && value !== null;
1001
1002
  }
@@ -1005,12 +1006,16 @@ function clampWarmHookTimeoutMs(timeoutMs) {
1005
1006
  }
1006
1007
  return Math.min(timeoutMs, MAX_WARM_HOOK_TIMEOUT_MS);
1007
1008
  }
1008
- function truncateWarmHookOutput(text, maxChars = DEFAULT_WARM_HOOK_OUTPUT_MAX_CHARS) {
1009
+ function buildHookOutputPreview(text, maxChars = DEFAULT_HOOK_OUTPUT_PREVIEW_CHARS) {
1009
1010
  if (text.length <= maxChars) {
1010
- return text;
1011
+ return { output: text, outputTruncated: false, outputTotalChars: text.length };
1011
1012
  }
1012
- return `${text.slice(0, maxChars)}
1013
- ...[truncated]`;
1013
+ return {
1014
+ output: `${text.slice(0, maxChars)}
1015
+ ...[truncated \u2014 download the full log to see the rest]`,
1016
+ outputTruncated: true,
1017
+ outputTotalChars: text.length
1018
+ };
1014
1019
  }
1015
1020
  function parseWarmHookConfig(value, filename = "replicas.json") {
1016
1021
  if (typeof value === "string") {
@@ -1097,7 +1102,7 @@ function parseReplicasConfigString(content, filename) {
1097
1102
  }
1098
1103
 
1099
1104
  // ../shared/src/engine/environment.ts
1100
- var DAYTONA_SNAPSHOT_ID = "18-04-2026-islington-v3";
1105
+ var DAYTONA_SNAPSHOT_ID = "21-04-2026-islington-v2";
1101
1106
 
1102
1107
  // ../shared/src/engine/types.ts
1103
1108
  var DEFAULT_CHAT_TITLES = {
@@ -1275,6 +1280,13 @@ function sanitizeFilename(name) {
1275
1280
  const hash = createHash("sha256").update(name).digest("hex").slice(0, 8);
1276
1281
  return `${safe}-${hash}`;
1277
1282
  }
1283
+ function repoFilename(repoName) {
1284
+ return `repo-${sanitizeFilename(repoName)}.json`;
1285
+ }
1286
+ function withPreview(stored) {
1287
+ const preview = buildHookOutputPreview(stored.output);
1288
+ return { ...stored, ...preview };
1289
+ }
1278
1290
  var StartHookLogsService = class {
1279
1291
  async ensureDir() {
1280
1292
  await mkdir4(LOGS_DIR, { recursive: true });
@@ -1282,8 +1294,7 @@ var StartHookLogsService = class {
1282
1294
  async saveRepoLog(repoName, entry) {
1283
1295
  await this.ensureDir();
1284
1296
  const log = { repoName, ...entry };
1285
- const filename = `repo-${sanitizeFilename(repoName)}.json`;
1286
- await writeFile4(join6(LOGS_DIR, filename), `${JSON.stringify(log, null, 2)}
1297
+ await writeFile4(join6(LOGS_DIR, repoFilename(repoName)), `${JSON.stringify(log, null, 2)}
1287
1298
  `, "utf-8");
1288
1299
  }
1289
1300
  async getAllLogs() {
@@ -1303,13 +1314,29 @@ var StartHookLogsService = class {
1303
1314
  }
1304
1315
  try {
1305
1316
  const raw = await readFile3(join6(LOGS_DIR, file), "utf-8");
1306
- logs.push(JSON.parse(raw));
1317
+ const stored = JSON.parse(raw);
1318
+ logs.push(withPreview(stored));
1307
1319
  } catch {
1308
1320
  }
1309
1321
  }
1310
1322
  logs.sort((a, b) => a.repoName.localeCompare(b.repoName));
1311
1323
  return logs;
1312
1324
  }
1325
+ async getFullOutput(repoName) {
1326
+ try {
1327
+ const raw = await readFile3(join6(LOGS_DIR, repoFilename(repoName)), "utf-8");
1328
+ const stored = JSON.parse(raw);
1329
+ if (stored.repoName !== repoName) {
1330
+ return null;
1331
+ }
1332
+ return stored.output;
1333
+ } catch (err) {
1334
+ if (err.code === "ENOENT") {
1335
+ return null;
1336
+ }
1337
+ throw err;
1338
+ }
1339
+ }
1313
1340
  };
1314
1341
  var startHookLogsService = new StartHookLogsService();
1315
1342
 
@@ -1454,6 +1481,7 @@ Repositories: ${hookEntries.length}
1454
1481
  const { stdout, stderr } = await execAsync(hook, {
1455
1482
  cwd: entry.workingDirectory,
1456
1483
  timeout,
1484
+ maxBuffer: HOOK_EXEC_MAX_BUFFER_BYTES,
1457
1485
  env: process.env
1458
1486
  });
1459
1487
  if (stdout) {
@@ -1466,7 +1494,6 @@ Repositories: ${hookEntries.length}
1466
1494
  }
1467
1495
  await this.logToFile(`[${entry.repoName}] --- Completed: ${hook} ---`);
1468
1496
  } catch (error) {
1469
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
1470
1497
  const execError = error;
1471
1498
  lastExitCode = execError.code ?? 1;
1472
1499
  if (execError.killed) {
@@ -1474,6 +1501,16 @@ Repositories: ${hookEntries.length}
1474
1501
  }
1475
1502
  this.hooksFailed = true;
1476
1503
  repoFailed = true;
1504
+ if (execError.stdout) {
1505
+ repoOutput.push(execError.stdout);
1506
+ await this.logToFile(`[${entry.repoName}] [stdout] ${execError.stdout}`);
1507
+ }
1508
+ if (execError.stderr) {
1509
+ repoOutput.push(execError.stderr);
1510
+ await this.logToFile(`[${entry.repoName}] [stderr] ${execError.stderr}`);
1511
+ }
1512
+ const rawMessage = execError.message ?? "Unknown error";
1513
+ const errorMessage = rawMessage.split("\n", 1)[0];
1477
1514
  repoOutput.push(`[ERROR] ${hook} failed: ${errorMessage}`);
1478
1515
  await this.logToFile(`[${entry.repoName}] [ERROR] ${hook} failed: ${errorMessage}`);
1479
1516
  await environmentDetailsService.setRepositoryStartHook(entry.repoName, "no");
@@ -4046,6 +4083,16 @@ function sanitizeFilename2(name) {
4046
4083
  const hash = createHash2("sha256").update(name).digest("hex").slice(0, 8);
4047
4084
  return `${safe}-${hash}`;
4048
4085
  }
4086
+ function globalFilename() {
4087
+ return "global.json";
4088
+ }
4089
+ function repoFilename2(repoName) {
4090
+ return `repo-${sanitizeFilename2(repoName)}.json`;
4091
+ }
4092
+ function withPreview2(stored) {
4093
+ const preview = buildHookOutputPreview(stored.output);
4094
+ return { ...stored, ...preview };
4095
+ }
4049
4096
  var WarmHookLogsService = class {
4050
4097
  async ensureDir() {
4051
4098
  await mkdir11(LOGS_DIR2, { recursive: true });
@@ -4057,7 +4104,7 @@ var WarmHookLogsService = class {
4057
4104
  hookName: "organization",
4058
4105
  ...entry
4059
4106
  };
4060
- await writeFile9(join13(LOGS_DIR2, "global.json"), `${JSON.stringify(log, null, 2)}
4107
+ await writeFile9(join13(LOGS_DIR2, globalFilename()), `${JSON.stringify(log, null, 2)}
4061
4108
  `, "utf-8");
4062
4109
  }
4063
4110
  async saveRepoHookLog(repoName, entry) {
@@ -4067,8 +4114,7 @@ var WarmHookLogsService = class {
4067
4114
  hookName: repoName,
4068
4115
  ...entry
4069
4116
  };
4070
- const filename = `repo-${sanitizeFilename2(repoName)}.json`;
4071
- await writeFile9(join13(LOGS_DIR2, filename), `${JSON.stringify(log, null, 2)}
4117
+ await writeFile9(join13(LOGS_DIR2, repoFilename2(repoName)), `${JSON.stringify(log, null, 2)}
4072
4118
  `, "utf-8");
4073
4119
  }
4074
4120
  async getAllLogs() {
@@ -4088,7 +4134,8 @@ var WarmHookLogsService = class {
4088
4134
  }
4089
4135
  try {
4090
4136
  const raw = await readFile10(join13(LOGS_DIR2, file), "utf-8");
4091
- logs.push(JSON.parse(raw));
4137
+ const stored = JSON.parse(raw);
4138
+ logs.push(withPreview2(stored));
4092
4139
  } catch {
4093
4140
  }
4094
4141
  }
@@ -4100,6 +4147,22 @@ var WarmHookLogsService = class {
4100
4147
  });
4101
4148
  return logs;
4102
4149
  }
4150
+ async getFullOutput(hookType, hookName) {
4151
+ const filename = hookType === "global" ? globalFilename() : repoFilename2(hookName);
4152
+ try {
4153
+ const raw = await readFile10(join13(LOGS_DIR2, filename), "utf-8");
4154
+ const stored = JSON.parse(raw);
4155
+ if (stored.hookType !== hookType || stored.hookName !== hookName) {
4156
+ return null;
4157
+ }
4158
+ return stored.output;
4159
+ } catch (err) {
4160
+ if (err.code === "ENOENT") {
4161
+ return null;
4162
+ }
4163
+ throw err;
4164
+ }
4165
+ }
4103
4166
  };
4104
4167
  var warmHookLogsService = new WarmHookLogsService();
4105
4168
 
@@ -4111,13 +4174,13 @@ async function executeHookScript(params) {
4111
4174
  const { stdout, stderr } = await execFileAsync2("bash", ["-lc", params.content], {
4112
4175
  cwd: params.cwd,
4113
4176
  timeout,
4114
- maxBuffer: 1024 * 1024,
4177
+ maxBuffer: HOOK_EXEC_MAX_BUFFER_BYTES,
4115
4178
  env: process.env
4116
4179
  });
4117
4180
  const combined = [`$ ${params.label}`, stdout ?? "", stderr ?? ""].filter(Boolean).join("\n");
4118
4181
  return {
4119
4182
  exitCode: 0,
4120
- output: truncateWarmHookOutput(combined),
4183
+ output: combined,
4121
4184
  timedOut: false
4122
4185
  };
4123
4186
  } catch (error) {
@@ -4127,7 +4190,7 @@ async function executeHookScript(params) {
4127
4190
  const combined = [`$ ${params.label}`, execError.stdout ?? "", execError.stderr ?? "", execError.message].filter(Boolean).join("\n");
4128
4191
  return {
4129
4192
  exitCode,
4130
- output: truncateWarmHookOutput(combined),
4193
+ output: combined,
4131
4194
  timedOut
4132
4195
  };
4133
4196
  }
@@ -4573,6 +4636,25 @@ function createV1Routes(deps) {
4573
4636
  );
4574
4637
  }
4575
4638
  });
4639
+ app2.get("/warm-hooks/logs/:hookType/:hookName/full", async (c) => {
4640
+ try {
4641
+ const hookType = c.req.param("hookType");
4642
+ const hookName = c.req.param("hookName");
4643
+ if (hookType !== "global" && hookType !== "repository") {
4644
+ return c.json(jsonError("Invalid hookType", 'Must be "global" or "repository"'), 400);
4645
+ }
4646
+ const output = await warmHookLogsService.getFullOutput(hookType, hookName);
4647
+ if (output === null) {
4648
+ return c.json(jsonError("Warm hook log not found"), 404);
4649
+ }
4650
+ return c.json({ output });
4651
+ } catch (error) {
4652
+ return c.json(
4653
+ jsonError("Failed to read warm hook log", error instanceof Error ? error.message : "Unknown error"),
4654
+ 500
4655
+ );
4656
+ }
4657
+ });
4576
4658
  app2.get("/start-hooks/logs", async (c) => {
4577
4659
  try {
4578
4660
  const logs = await startHookLogsService.getAllLogs();
@@ -4584,6 +4666,21 @@ function createV1Routes(deps) {
4584
4666
  );
4585
4667
  }
4586
4668
  });
4669
+ app2.get("/start-hooks/logs/:repoName/full", async (c) => {
4670
+ try {
4671
+ const repoName = c.req.param("repoName");
4672
+ const output = await startHookLogsService.getFullOutput(repoName);
4673
+ if (output === null) {
4674
+ return c.json(jsonError("Start hook log not found"), 404);
4675
+ }
4676
+ return c.json({ output });
4677
+ } catch (error) {
4678
+ return c.json(
4679
+ jsonError("Failed to read start hook log", error instanceof Error ? error.message : "Unknown error"),
4680
+ 500
4681
+ );
4682
+ }
4683
+ });
4587
4684
  app2.post("/workspace-name", async (c) => {
4588
4685
  try {
4589
4686
  const body = setWorkspaceNameSchema.parse(await c.req.json());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.115",
3
+ "version": "0.1.117",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",