replicas-engine 0.1.259 → 0.1.261

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/README.md CHANGED
@@ -31,10 +31,10 @@ Chats:
31
31
  - `POST /chats/:chatId/messages`
32
32
  - `POST /chats/:chatId/interrupt`
33
33
 
34
- Plans:
34
+ Canvas:
35
35
 
36
- - `GET /plans`
37
- - `GET /plans/:filename`
36
+ - `GET /canvas`
37
+ - `GET /canvas/:filename`
38
38
 
39
39
  Repos and hooks:
40
40
 
@@ -93,9 +93,9 @@ Engine persistence locations:
93
93
  - `~/.replicas/engine/events.jsonl`
94
94
  - `~/.replicas/engine-state.json`
95
95
  - `~/.replicas/startHooks.log`
96
- - Plan read locations (for `/plans` endpoints):
97
- - `~/.claude/plans`
98
- - `~/.replicas/plans`
96
+ - Canvas read locations (for `/canvas` endpoints):
97
+ - `~/.claude/plans` (where Claude Code writes its plans)
98
+ - `~/.replicas/canvas`
99
99
  - Health endpoint readiness signal file:
100
100
  - `/var/log/cloud-init-output.log` (if missing, `/health` reports `initializing`)
101
101
 
package/dist/src/index.js CHANGED
@@ -286,7 +286,7 @@ var WORKSPACE_SIZES = ["small", "large"];
286
286
  var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
287
287
 
288
288
  // ../shared/src/e2b.ts
289
- var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-04-v1";
289
+ var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-06-04-v3";
290
290
 
291
291
  // ../shared/src/runtime-env.ts
292
292
  function parsePosixEnvFile(content) {
@@ -1839,6 +1839,29 @@ var MODEL_LABELS = {
1839
1839
  "gpt-5": "GPT-5"
1840
1840
  };
1841
1841
  var IMAGE_MEDIA_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"];
1842
+ var CANVAS_KIND_BY_EXTENSION = {
1843
+ ".md": { kind: "markdown", mimeType: "text/markdown; charset=utf-8" },
1844
+ ".markdown": { kind: "markdown", mimeType: "text/markdown; charset=utf-8" },
1845
+ ".html": { kind: "html", mimeType: "text/html; charset=utf-8" },
1846
+ ".htm": { kind: "html", mimeType: "text/html; charset=utf-8" },
1847
+ ".png": { kind: "image", mimeType: "image/png" },
1848
+ ".jpg": { kind: "image", mimeType: "image/jpeg" },
1849
+ ".jpeg": { kind: "image", mimeType: "image/jpeg" },
1850
+ ".gif": { kind: "image", mimeType: "image/gif" },
1851
+ ".webp": { kind: "image", mimeType: "image/webp" },
1852
+ ".svg": { kind: "image", mimeType: "image/svg+xml" },
1853
+ ".mp4": { kind: "video", mimeType: "video/mp4" },
1854
+ ".webm": { kind: "video", mimeType: "video/webm" },
1855
+ ".mov": { kind: "video", mimeType: "video/quicktime" },
1856
+ ".mp3": { kind: "audio", mimeType: "audio/mpeg" },
1857
+ ".wav": { kind: "audio", mimeType: "audio/wav" },
1858
+ ".ogg": { kind: "audio", mimeType: "audio/ogg" }
1859
+ };
1860
+ function classifyCanvasFilename(filename) {
1861
+ const idx = filename.lastIndexOf(".");
1862
+ const ext = idx === -1 ? "" : filename.slice(idx).toLowerCase();
1863
+ return CANVAS_KIND_BY_EXTENSION[ext] ?? { kind: "other", mimeType: "application/octet-stream" };
1864
+ }
1842
1865
 
1843
1866
  // ../shared/src/engine/v1.ts
1844
1867
  var MERGED_MESSAGE_SEPARATOR = "\n\n<!-- replicas:merged -->\n\n";
@@ -2005,6 +2028,7 @@ var CLAUDE_AUTH_ENV_KEYS_BY_METHOD = {
2005
2028
  // ../shared/src/routes/workspaces.ts
2006
2029
  var WORKSPACE_FILE_UPLOAD_MAX_SIZE_BYTES = 20 * 1024 * 1024;
2007
2030
  var WORKSPACE_FILE_CONTENT_MAX_SIZE_BYTES = 1 * 1024 * 1024;
2031
+ var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
2008
2032
 
2009
2033
  // ../shared/src/audit-log.ts
2010
2034
  var AUDIT_LOG_ACTION = {
@@ -6349,7 +6373,7 @@ var AspClient = class {
6349
6373
  // src/managers/codex-asp/app-server-process.ts
6350
6374
  var DEFAULT_CODEX_BINARY = "codex";
6351
6375
  var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
6352
- var ENGINE_PACKAGE_VERSION = "0.1.259";
6376
+ var ENGINE_PACKAGE_VERSION = "0.1.261";
6353
6377
  var INITIALIZE_METHOD = "initialize";
6354
6378
  var INITIALIZED_NOTIFICATION = "initialized";
6355
6379
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -9904,60 +9928,88 @@ var RepoFileService = class {
9904
9928
  // src/v1-routes.ts
9905
9929
  import { Hono } from "hono";
9906
9930
  import { z as z2 } from "zod";
9907
- import { readdir as readdir6, stat as stat4, readFile as readFile14 } from "fs/promises";
9931
+ import { readdir as readdir6, stat as stat5, readFile as readFile14 } from "fs/promises";
9908
9932
  import { join as join20, resolve as resolve2 } from "path";
9909
9933
 
9910
- // src/services/plan-service.ts
9911
- import { readdir as readdir4, readFile as readFile11 } from "fs/promises";
9934
+ // src/services/canvas-service.ts
9935
+ import { readdir as readdir4, readFile as readFile11, stat as stat4 } from "fs/promises";
9912
9936
  import { homedir as homedir14 } from "os";
9913
9937
  import { basename, join as join17 } from "path";
9914
- var PLAN_DIRECTORIES = [
9938
+ var CANVAS_DIRECTORIES = [
9915
9939
  join17(homedir14(), ".claude", "plans"),
9916
- join17(homedir14(), ".replicas", "plans")
9940
+ join17(homedir14(), ".replicas", "canvas")
9917
9941
  ];
9918
- function isMarkdownFile(filename) {
9919
- return filename.toLowerCase().endsWith(".md");
9942
+ var MAX_CANVAS_FILE_BYTES = 5 * 1024 * 1024;
9943
+ function isTextKind(kind) {
9944
+ return kind === "markdown" || kind === "html";
9920
9945
  }
9921
- function sanitizePlanFilename(filename) {
9946
+ function sanitizeFilename(filename) {
9922
9947
  return basename(filename);
9923
9948
  }
9924
- var PlanService = class {
9925
- async listPlans() {
9926
- const planNames = /* @__PURE__ */ new Set();
9927
- for (const directory of PLAN_DIRECTORIES) {
9949
+ var CanvasService = class {
9950
+ async listItems() {
9951
+ const items = /* @__PURE__ */ new Map();
9952
+ for (const directory of CANVAS_DIRECTORIES) {
9953
+ let entries;
9928
9954
  try {
9929
- const entries = await readdir4(directory, { withFileTypes: true });
9930
- for (const entry of entries) {
9931
- if (!entry.isFile()) {
9932
- continue;
9933
- }
9934
- if (!isMarkdownFile(entry.name)) {
9935
- continue;
9936
- }
9937
- planNames.add(entry.name);
9938
- }
9955
+ entries = await readdir4(directory, { withFileTypes: true });
9939
9956
  } catch {
9957
+ continue;
9958
+ }
9959
+ for (const entry of entries) {
9960
+ if (!entry.isFile()) continue;
9961
+ if (entry.name.startsWith(".")) continue;
9962
+ if (items.has(entry.name)) continue;
9963
+ const { kind } = classifyCanvasFilename(entry.name);
9964
+ let sizeBytes = 0;
9965
+ try {
9966
+ const s = await stat4(join17(directory, entry.name));
9967
+ sizeBytes = s.size;
9968
+ } catch {
9969
+ continue;
9970
+ }
9971
+ items.set(entry.name, { filename: entry.name, kind, sizeBytes });
9940
9972
  }
9941
9973
  }
9942
- return Array.from(planNames).sort((a, b) => a.localeCompare(b));
9974
+ return Array.from(items.values()).sort((a, b) => a.filename.localeCompare(b.filename));
9943
9975
  }
9944
- async getPlan(filename) {
9945
- const safeFilename = sanitizePlanFilename(filename);
9946
- if (!safeFilename || safeFilename !== filename || !isMarkdownFile(safeFilename)) {
9947
- return null;
9948
- }
9949
- for (const directory of PLAN_DIRECTORIES) {
9950
- const filePath = join17(directory, safeFilename);
9976
+ async getItem(filename) {
9977
+ const safe = sanitizeFilename(filename);
9978
+ if (!safe || safe !== filename || safe.startsWith(".")) return null;
9979
+ const { kind, mimeType } = classifyCanvasFilename(safe);
9980
+ for (const directory of CANVAS_DIRECTORIES) {
9981
+ const filePath = join17(directory, safe);
9982
+ let sizeBytes = 0;
9951
9983
  try {
9952
- const content = await readFile11(filePath, "utf-8");
9953
- return { filename: safeFilename, content };
9984
+ const s = await stat4(filePath);
9985
+ sizeBytes = s.size;
9954
9986
  } catch {
9987
+ continue;
9988
+ }
9989
+ if (sizeBytes > MAX_CANVAS_FILE_BYTES) {
9990
+ return {
9991
+ filename: safe,
9992
+ kind,
9993
+ sizeBytes,
9994
+ mimeType,
9995
+ tooLarge: true
9996
+ };
9997
+ }
9998
+ try {
9999
+ if (isTextKind(kind)) {
10000
+ const content = await readFile11(filePath, "utf-8");
10001
+ return { filename: safe, kind, sizeBytes, mimeType, content };
10002
+ }
10003
+ const buf = await readFile11(filePath);
10004
+ return { filename: safe, kind, sizeBytes, mimeType, base64: buf.toString("base64") };
10005
+ } catch {
10006
+ continue;
9955
10007
  }
9956
10008
  }
9957
10009
  return null;
9958
10010
  }
9959
10011
  };
9960
- var planService = new PlanService();
10012
+ var canvasService = new CanvasService();
9961
10013
 
9962
10014
  // src/services/warm-hooks-service.ts
9963
10015
  import { spawn as spawn4 } from "child_process";
@@ -10648,31 +10700,31 @@ function createV1Routes(deps) {
10648
10700
  }
10649
10701
  return c.json(result);
10650
10702
  });
10651
- app2.get("/plans", async (c) => {
10703
+ app2.get("/canvas", async (c) => {
10652
10704
  try {
10653
- const plans = await planService.listPlans();
10654
- return c.json({ plans });
10705
+ const items = await canvasService.listItems();
10706
+ return c.json({ items });
10655
10707
  } catch (error) {
10656
10708
  return c.json(
10657
- jsonError("Failed to list plans", error instanceof Error ? error.message : "Unknown error"),
10709
+ jsonError("Failed to list canvas items", error instanceof Error ? error.message : "Unknown error"),
10658
10710
  500
10659
10711
  );
10660
10712
  }
10661
10713
  });
10662
- app2.get("/plans/:filename", async (c) => {
10714
+ app2.get("/canvas/:filename", async (c) => {
10663
10715
  try {
10664
10716
  const filename = c.req.param("filename");
10665
10717
  if (!filename) {
10666
10718
  return c.json(jsonError("Filename required"), 400);
10667
10719
  }
10668
- const plan = await planService.getPlan(filename);
10669
- if (!plan) {
10670
- return c.json(jsonError("Plan not found"), 404);
10720
+ const item = await canvasService.getItem(filename);
10721
+ if (!item) {
10722
+ return c.json(jsonError("Canvas item not found"), 404);
10671
10723
  }
10672
- return c.json(plan);
10724
+ return c.json(item);
10673
10725
  } catch (error) {
10674
10726
  return c.json(
10675
- jsonError("Failed to read plan", error instanceof Error ? error.message : "Unknown error"),
10727
+ jsonError("Failed to read canvas item", error instanceof Error ? error.message : "Unknown error"),
10676
10728
  500
10677
10729
  );
10678
10730
  }
@@ -10986,7 +11038,7 @@ function createV1Routes(deps) {
10986
11038
  const sessions = await Promise.all(
10987
11039
  logFiles.map(async (filename) => {
10988
11040
  const filePath = join20(LOG_DIR, filename);
10989
- const fileStat = await stat4(filePath);
11041
+ const fileStat = await stat5(filePath);
10990
11042
  const sessionId = filename.replace(/\.log$/, "");
10991
11043
  return {
10992
11044
  sessionId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.259",
3
+ "version": "0.1.261",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",