replicas-engine 0.1.441 → 0.1.443

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 +199 -13
  2. package/package.json +4 -1
package/dist/src/index.js CHANGED
@@ -27,6 +27,21 @@ async function raceWithTimeout(promise, ms) {
27
27
  }
28
28
  }
29
29
 
30
+ // ../shared/src/result.ts
31
+ function createSuccessResult(data) {
32
+ return { ok: true, data };
33
+ }
34
+ function createErrorResult(error) {
35
+ return {
36
+ ok: false,
37
+ error: {
38
+ message: error.message,
39
+ code: error.code,
40
+ details: error.details
41
+ }
42
+ };
43
+ }
44
+
30
45
  // ../shared/src/agent.ts
31
46
  var VALID_AGENT_PROVIDERS = ["claude", "codex", "cursor", "opencode", "relay"];
32
47
  var VALID_CODING_AGENT_PROVIDERS = VALID_AGENT_PROVIDERS.filter(
@@ -506,7 +521,7 @@ var WORKSPACE_SIZES = ["small", "large"];
506
521
  var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
507
522
 
508
523
  // ../shared/src/e2b.ts
509
- var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-16-v1";
524
+ var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-16-v3";
510
525
 
511
526
  // ../shared/src/runtime-env.ts
512
527
  function shellQuotePosix(value) {
@@ -3331,7 +3346,7 @@ var MEDIA_KINDS = [MEDIA_KIND.IMAGE, MEDIA_KIND.VIDEO, MEDIA_KIND.AUDIO];
3331
3346
  var SKILL_REGISTRY_MANIFEST_VERSION = 1;
3332
3347
 
3333
3348
  // src/index.ts
3334
- import { randomUUID as randomUUID6 } from "crypto";
3349
+ import { randomUUID as randomUUID7 } from "crypto";
3335
3350
  import { connect } from "net";
3336
3351
 
3337
3352
  // src/utils/exec.ts
@@ -8577,7 +8592,7 @@ var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
8577
8592
  var MIN_CODEX_CLI_VERSION = "0.144.0";
8578
8593
  var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
8579
8594
  var codexCliVersionEnsured = null;
8580
- var ENGINE_PACKAGE_VERSION = "0.1.441";
8595
+ var ENGINE_PACKAGE_VERSION = "0.1.443";
8581
8596
  var INITIALIZE_METHOD = "initialize";
8582
8597
  var INITIALIZED_NOTIFICATION = "initialized";
8583
8598
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -14141,6 +14156,98 @@ ${combinedScript}` : combinedScript;
14141
14156
  return result;
14142
14157
  }
14143
14158
 
14159
+ // src/services/terminal-service.ts
14160
+ import { randomUUID as randomUUID6 } from "crypto";
14161
+ import { existsSync as existsSync9 } from "fs";
14162
+ import { spawn as spawn5 } from "node-pty";
14163
+ var MAX_REPLAY_CHARS = 1024 * 1024;
14164
+ var MAX_TERMINAL_SESSIONS = 8;
14165
+ var TerminalService = class {
14166
+ sessions = /* @__PURE__ */ new Map();
14167
+ nextTitleNumber = 1;
14168
+ list() {
14169
+ return [...this.sessions.values()].map(({ pty: _pty, replay: _replay, subscribers: _subscribers, ...session }) => session);
14170
+ }
14171
+ create(cwd, cols, rows) {
14172
+ if (this.sessions.size >= MAX_TERMINAL_SESSIONS) {
14173
+ return createErrorResult({
14174
+ message: `Terminal session limit reached (${MAX_TERMINAL_SESSIONS})`,
14175
+ code: "limit"
14176
+ });
14177
+ }
14178
+ const id = randomUUID6();
14179
+ const shell = process.env.SHELL && existsSync9(process.env.SHELL) ? process.env.SHELL : "/bin/bash";
14180
+ const pty = spawn5(shell, ["-l"], {
14181
+ name: "xterm-256color",
14182
+ cols,
14183
+ rows,
14184
+ cwd,
14185
+ env: {
14186
+ ...process.env,
14187
+ TERM: "xterm-256color",
14188
+ COLORTERM: "truecolor"
14189
+ }
14190
+ });
14191
+ const session = {
14192
+ id,
14193
+ title: `Terminal ${this.nextTitleNumber++}`,
14194
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
14195
+ exited: false,
14196
+ pty,
14197
+ replay: "",
14198
+ subscribers: /* @__PURE__ */ new Set()
14199
+ };
14200
+ this.sessions.set(id, session);
14201
+ pty.onData((data) => {
14202
+ session.replay = (session.replay + data).slice(-MAX_REPLAY_CHARS);
14203
+ for (const subscriber of session.subscribers) subscriber(data);
14204
+ });
14205
+ pty.onExit(({ exitCode }) => {
14206
+ session.exited = true;
14207
+ session.exitCode = exitCode;
14208
+ const data = `\r
14209
+ \x1B[2m[Process exited with code ${exitCode}]\x1B[0m\r
14210
+ `;
14211
+ session.replay = (session.replay + data).slice(-MAX_REPLAY_CHARS);
14212
+ for (const subscriber of session.subscribers) subscriber(data);
14213
+ });
14214
+ return createSuccessResult(this.publicSession(session));
14215
+ }
14216
+ write(id, data) {
14217
+ const session = this.sessions.get(id);
14218
+ if (!session || session.exited) return false;
14219
+ session.pty.write(data);
14220
+ return true;
14221
+ }
14222
+ resize(id, cols, rows) {
14223
+ const session = this.sessions.get(id);
14224
+ if (!session || session.exited) return false;
14225
+ session.pty.resize(cols, rows);
14226
+ return true;
14227
+ }
14228
+ subscribe(id, subscriber) {
14229
+ const session = this.sessions.get(id);
14230
+ if (!session) return null;
14231
+ session.subscribers.add(subscriber);
14232
+ return {
14233
+ replay: session.replay,
14234
+ unsubscribe: () => session.subscribers.delete(subscriber)
14235
+ };
14236
+ }
14237
+ delete(id) {
14238
+ const session = this.sessions.get(id);
14239
+ if (!session) return false;
14240
+ if (!session.exited) session.pty.kill();
14241
+ this.sessions.delete(id);
14242
+ return true;
14243
+ }
14244
+ publicSession(session) {
14245
+ const { pty: _pty, replay: _replay, subscribers: _subscribers, ...value } = session;
14246
+ return value;
14247
+ }
14248
+ };
14249
+ var terminalService = new TerminalService();
14250
+
14144
14251
  // src/v1-routes.ts
14145
14252
  var setWorkspaceNameSchema = z2.object({
14146
14253
  name: z2.string().min(1).max(48)
@@ -14156,6 +14263,13 @@ var createPreviewSchema = z2.object({
14156
14263
  port: z2.number().int().min(1).max(65535),
14157
14264
  publicUrl: z2.string().min(1)
14158
14265
  });
14266
+ var terminalSizeSchema = z2.object({
14267
+ cols: z2.number().int().min(2).max(500),
14268
+ rows: z2.number().int().min(1).max(200)
14269
+ });
14270
+ var writeTerminalSessionSchema = z2.object({
14271
+ data: z2.string().max(64 * 1024)
14272
+ });
14159
14273
  var sendMessageSchema = z2.object({
14160
14274
  message: z2.string().min(1),
14161
14275
  model: z2.string().optional(),
@@ -14529,6 +14643,78 @@ function createV1Routes(deps) {
14529
14643
  }
14530
14644
  return c.json(result);
14531
14645
  });
14646
+ app2.get("/terminal/sessions", (c) => {
14647
+ return c.json({ sessions: terminalService.list() });
14648
+ });
14649
+ app2.post("/terminal/sessions", async (c) => {
14650
+ const size = terminalSizeSchema.parse(await c.req.json());
14651
+ const result = terminalService.create(gitService.getWorkspaceRoot(), size.cols, size.rows);
14652
+ if (!result.ok) return c.json(jsonError(result.error.message), 429);
14653
+ return c.json({
14654
+ session: result.data
14655
+ }, 201);
14656
+ });
14657
+ app2.post("/terminal/sessions/:id/input", async (c) => {
14658
+ const body = writeTerminalSessionSchema.parse(await c.req.json());
14659
+ if (!terminalService.write(c.req.param("id"), body.data)) {
14660
+ return c.json(jsonError("Terminal session not found or exited"), 404);
14661
+ }
14662
+ return c.body(null, 204);
14663
+ });
14664
+ app2.post("/terminal/sessions/:id/resize", async (c) => {
14665
+ const size = terminalSizeSchema.parse(await c.req.json());
14666
+ if (!terminalService.resize(c.req.param("id"), size.cols, size.rows)) {
14667
+ return c.json(jsonError("Terminal session not found or exited"), 404);
14668
+ }
14669
+ return c.body(null, 204);
14670
+ });
14671
+ app2.delete("/terminal/sessions/:id", (c) => {
14672
+ if (!terminalService.delete(c.req.param("id"))) {
14673
+ return c.json(jsonError("Terminal session not found"), 404);
14674
+ }
14675
+ return c.body(null, 204);
14676
+ });
14677
+ app2.get("/terminal/sessions/:id/stream", (c) => {
14678
+ const encoder = new TextEncoder();
14679
+ let cleanup = () => {
14680
+ };
14681
+ const stream = new ReadableStream({
14682
+ start(controller) {
14683
+ const subscription = terminalService.subscribe(c.req.param("id"), (data) => {
14684
+ controller.enqueue(encoder.encode(`data: ${JSON.stringify(data)}
14685
+
14686
+ `));
14687
+ });
14688
+ if (!subscription) {
14689
+ controller.enqueue(encoder.encode(`event: error
14690
+ data: ${JSON.stringify("Terminal session not found")}
14691
+
14692
+ `));
14693
+ controller.close();
14694
+ return;
14695
+ }
14696
+ if (subscription.replay) controller.enqueue(encoder.encode(`data: ${JSON.stringify(subscription.replay)}
14697
+
14698
+ `));
14699
+ const heartbeat = setInterval(() => controller.enqueue(encoder.encode(": keepalive\n\n")), 15e3);
14700
+ cleanup = () => {
14701
+ clearInterval(heartbeat);
14702
+ subscription.unsubscribe();
14703
+ };
14704
+ },
14705
+ cancel() {
14706
+ cleanup();
14707
+ }
14708
+ });
14709
+ c.req.raw.signal.addEventListener("abort", cleanup, { once: true });
14710
+ return new Response(stream, {
14711
+ headers: {
14712
+ "Content-Type": "text/event-stream",
14713
+ "Cache-Control": "no-cache",
14714
+ Connection: "keep-alive"
14715
+ }
14716
+ });
14717
+ });
14532
14718
  app2.get("/canvas", async (c) => {
14533
14719
  try {
14534
14720
  const items = await canvasService.listItems();
@@ -15139,7 +15325,7 @@ function startStatusBroadcaster() {
15139
15325
  if (serialized !== previousRepoStatus) {
15140
15326
  previousRepoStatus = serialized;
15141
15327
  eventService.publish({
15142
- id: randomUUID6(),
15328
+ id: randomUUID7(),
15143
15329
  ts: (/* @__PURE__ */ new Date()).toISOString(),
15144
15330
  type: "repo.status.changed",
15145
15331
  payload: { repos }
@@ -15160,7 +15346,7 @@ function startStatusBroadcaster() {
15160
15346
  if (engineStatusJson !== previousEngineStatus) {
15161
15347
  previousEngineStatus = engineStatusJson;
15162
15348
  eventService.publish({
15163
- id: randomUUID6(),
15349
+ id: randomUUID7(),
15164
15350
  ts: (/* @__PURE__ */ new Date()).toISOString(),
15165
15351
  type: "engine.status.changed",
15166
15352
  payload: { status: engineStatus }
@@ -15179,7 +15365,7 @@ function startStatusBroadcaster() {
15179
15365
  previousHookStatus = hookSnapshot;
15180
15366
  if (!lastHooksRunning && hooksRunning) {
15181
15367
  eventService.publish({
15182
- id: randomUUID6(),
15368
+ id: randomUUID7(),
15183
15369
  ts: (/* @__PURE__ */ new Date()).toISOString(),
15184
15370
  type: "hooks.started",
15185
15371
  payload: { running: true, completed: false }
@@ -15188,7 +15374,7 @@ function startStatusBroadcaster() {
15188
15374
  }
15189
15375
  if (hooksRunning) {
15190
15376
  eventService.publish({
15191
- id: randomUUID6(),
15377
+ id: randomUUID7(),
15192
15378
  ts: (/* @__PURE__ */ new Date()).toISOString(),
15193
15379
  type: "hooks.progress",
15194
15380
  payload: { running: true, completed: false }
@@ -15197,7 +15383,7 @@ function startStatusBroadcaster() {
15197
15383
  }
15198
15384
  if (lastHooksRunning && !hooksRunning && hooksCompleted && !hooksFailed) {
15199
15385
  eventService.publish({
15200
- id: randomUUID6(),
15386
+ id: randomUUID7(),
15201
15387
  ts: (/* @__PURE__ */ new Date()).toISOString(),
15202
15388
  type: "hooks.completed",
15203
15389
  payload: { running: false, completed: true }
@@ -15206,7 +15392,7 @@ function startStatusBroadcaster() {
15206
15392
  }
15207
15393
  if (lastHooksRunning && !hooksRunning && hooksFailed) {
15208
15394
  eventService.publish({
15209
- id: randomUUID6(),
15395
+ id: randomUUID7(),
15210
15396
  ts: (/* @__PURE__ */ new Date()).toISOString(),
15211
15397
  type: "hooks.failed",
15212
15398
  payload: { running: false, completed: hooksCompleted }
@@ -15214,7 +15400,7 @@ function startStatusBroadcaster() {
15214
15400
  });
15215
15401
  }
15216
15402
  eventService.publish({
15217
- id: randomUUID6(),
15403
+ id: randomUUID7(),
15218
15404
  ts: (/* @__PURE__ */ new Date()).toISOString(),
15219
15405
  type: "hooks.status",
15220
15406
  payload: {
@@ -15266,20 +15452,20 @@ serve(
15266
15452
  }
15267
15453
  const repos = await gitService.listRepos();
15268
15454
  await eventService.publish({
15269
- id: randomUUID6(),
15455
+ id: randomUUID7(),
15270
15456
  ts: (/* @__PURE__ */ new Date()).toISOString(),
15271
15457
  type: "repo.discovered",
15272
15458
  payload: { repos }
15273
15459
  });
15274
15460
  const repoStatuses = await gitService.listRepos();
15275
15461
  await eventService.publish({
15276
- id: randomUUID6(),
15462
+ id: randomUUID7(),
15277
15463
  ts: (/* @__PURE__ */ new Date()).toISOString(),
15278
15464
  type: "repo.status.changed",
15279
15465
  payload: { repos: repoStatuses }
15280
15466
  });
15281
15467
  await eventService.publish({
15282
- id: randomUUID6(),
15468
+ id: randomUUID7(),
15283
15469
  ts: (/* @__PURE__ */ new Date()).toISOString(),
15284
15470
  type: "engine.ready",
15285
15471
  payload: { version: "v1" }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.441",
3
+ "version": "0.1.443",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",
@@ -43,6 +43,9 @@
43
43
  "yaml": "^2.8.2",
44
44
  "zod": "^4.0.0"
45
45
  },
46
+ "optionalDependencies": {
47
+ "node-pty": "1.2.0-beta.14"
48
+ },
46
49
  "devDependencies": {
47
50
  "@replicas/codex-asp-types": "file:../codex-asp-types",
48
51
  "@replicas/shared": "workspace:*",