replicas-engine 0.1.42 → 0.1.44

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 CHANGED
@@ -65,6 +65,7 @@ function loadEngineEnv() {
65
65
  // not directly used by the engine code, but are required in the VM
66
66
  // for use by the agent or SDKs (e.g claude/codex)
67
67
  ANTHROPIC_API_KEY: readEnv("ANTHROPIC_API_KEY"),
68
+ OPENAI_API_KEY: readEnv("OPENAI_API_KEY"),
68
69
  CLAUDE_CODE_USE_BEDROCK: readEnv("CLAUDE_CODE_USE_BEDROCK"),
69
70
  AWS_ACCESS_KEY_ID: readEnv("AWS_ACCESS_KEY_ID"),
70
71
  AWS_SECRET_ACCESS_KEY: readEnv("AWS_SECRET_ACCESS_KEY"),
@@ -1134,6 +1135,10 @@ var DEFAULT_CHAT_TITLES = {
1134
1135
  };
1135
1136
  var IMAGE_MEDIA_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"];
1136
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
+
1137
1142
  // src/managers/claude-manager.ts
1138
1143
  import {
1139
1144
  query
@@ -1330,6 +1335,46 @@ function convertClaudeEvent(event, linearSessionId) {
1330
1335
  }
1331
1336
  return null;
1332
1337
  }
1338
+ function mapTodoStatus(status) {
1339
+ if (status === "in_progress") {
1340
+ return "inProgress";
1341
+ }
1342
+ if (status === "completed") {
1343
+ return "completed";
1344
+ }
1345
+ if (status === "cancelled" || status === "canceled") {
1346
+ return "canceled";
1347
+ }
1348
+ return "pending";
1349
+ }
1350
+ function extractPlanFromClaudeEvent(event) {
1351
+ if (event.type !== "assistant") {
1352
+ return null;
1353
+ }
1354
+ const message = event;
1355
+ const contentBlocks = message.message?.content || [];
1356
+ for (const block of contentBlocks) {
1357
+ if (block.type !== "tool_use" || block.name !== "TodoWrite") {
1358
+ continue;
1359
+ }
1360
+ const input = typeof block.input === "string" ? (() => {
1361
+ try {
1362
+ return JSON.parse(block.input);
1363
+ } catch {
1364
+ return null;
1365
+ }
1366
+ })() : typeof block.input === "object" && block.input !== null ? block.input : null;
1367
+ const todos = input?.todos;
1368
+ if (!todos || todos.length === 0) {
1369
+ return null;
1370
+ }
1371
+ return todos.filter((todo) => Boolean(todo.content && todo.content.trim().length > 0)).map((todo) => ({
1372
+ content: todo.content.trim(),
1373
+ status: mapTodoStatus(todo.status)
1374
+ }));
1375
+ }
1376
+ return null;
1377
+ }
1333
1378
  function convertCodexEvent(event, linearSessionId) {
1334
1379
  if (event.type === "turn.started") {
1335
1380
  return {
@@ -1518,6 +1563,24 @@ function convertCodexEvent(event, linearSessionId) {
1518
1563
  }
1519
1564
  return null;
1520
1565
  }
1566
+ function extractPlanFromCodexEvent(event) {
1567
+ if (event.type !== "item.started" && event.type !== "item.completed") {
1568
+ return null;
1569
+ }
1570
+ const item = event.item;
1571
+ if (!item || item.type !== "todo_list") {
1572
+ return null;
1573
+ }
1574
+ const items = "items" in item && Array.isArray(item.items) ? item.items : [];
1575
+ if (items.length === 0) {
1576
+ return null;
1577
+ }
1578
+ const hasIncomplete = items.some((entry) => !entry.completed);
1579
+ return items.filter((entry) => Boolean(entry.text && entry.text.trim().length > 0)).map((entry) => ({
1580
+ content: entry.text.trim(),
1581
+ status: entry.completed ? "completed" : hasIncomplete ? "inProgress" : "pending"
1582
+ }));
1583
+ }
1521
1584
 
1522
1585
  // src/utils/image-utils.ts
1523
1586
  function isImageMediaType(value) {
@@ -1551,15 +1614,24 @@ async function fetchImageAsBase64(url) {
1551
1614
  }
1552
1615
  if (hostname === "files.slack.com") {
1553
1616
  const token = ENGINE_ENV.SLACK_BOT_TOKEN;
1554
- if (token) {
1555
- headers["Authorization"] = `Bearer ${token}`;
1617
+ if (!token) {
1618
+ throw new Error(`Cannot fetch Slack file from ${url}: SLACK_BOT_TOKEN is not configured`);
1556
1619
  }
1620
+ headers["Authorization"] = `Bearer ${token}`;
1557
1621
  }
1558
- const response = await fetch(url, { headers });
1622
+ const response = await fetch(url, { headers, redirect: "follow" });
1559
1623
  if (!response.ok) {
1560
1624
  throw new Error(`Failed to fetch image from ${url}: ${response.status} ${response.statusText}`);
1561
1625
  }
1562
1626
  const contentType = response.headers.get("content-type");
1627
+ if (contentType) {
1628
+ const normalizedContentType = contentType.toLowerCase().split(";")[0].trim();
1629
+ if (!normalizedContentType.startsWith("image/")) {
1630
+ throw new Error(
1631
+ `Expected image content from ${url} but received Content-Type: ${normalizedContentType}. This may indicate an authentication or redirect issue.`
1632
+ );
1633
+ }
1634
+ }
1563
1635
  const mediaType = inferMediaType(url, contentType);
1564
1636
  const arrayBuffer = await response.arrayBuffer();
1565
1637
  const buffer = Buffer.from(arrayBuffer);
@@ -1913,6 +1985,14 @@ var ClaudeManager = class extends CodingAgentManager {
1913
1985
  for await (const msg of response) {
1914
1986
  await this.handleMessage(msg);
1915
1987
  if (linearSessionId) {
1988
+ const plan = extractPlanFromClaudeEvent(msg);
1989
+ if (plan) {
1990
+ monolithService.sendEvent({
1991
+ type: "agent_plan_update",
1992
+ payload: { linearSessionId, plan }
1993
+ }).catch(() => {
1994
+ });
1995
+ }
1916
1996
  const linearEvent = convertClaudeEvent(msg, linearSessionId);
1917
1997
  if (linearEvent) {
1918
1998
  if (latestThoughtEvent) {
@@ -2141,6 +2221,14 @@ var CodexManager = class extends CodingAgentManager {
2141
2221
  let latestThoughtEvent = null;
2142
2222
  for await (const event of events) {
2143
2223
  if (linearSessionId) {
2224
+ const plan = extractPlanFromCodexEvent(event);
2225
+ if (plan) {
2226
+ monolithService.sendEvent({
2227
+ type: "agent_plan_update",
2228
+ payload: { linearSessionId, plan }
2229
+ }).catch(() => {
2230
+ });
2231
+ }
2144
2232
  const linearEvent = convertCodexEvent(event, linearSessionId);
2145
2233
  if (linearEvent) {
2146
2234
  if (latestThoughtEvent) {
@@ -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 = /* @__PURE__ */ Symbol("wrapper");
171
- module.exports.implSymbol = /* @__PURE__ */ Symbol("impl");
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 = /* @__PURE__ */ Symbol("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 = /* @__PURE__ */ Symbol("buffer");
1791
- var TYPE = /* @__PURE__ */ Symbol("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 = /* @__PURE__ */ Symbol("Body 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 = /* @__PURE__ */ Symbol("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 = /* @__PURE__ */ Symbol("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 = /* @__PURE__ */ Symbol("Response internals");
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 = /* @__PURE__ */ Symbol("Request internals");
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.42",
3
+ "version": "0.1.44",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",