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.
- package/dist/src/index.js +199 -13
- 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-
|
|
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
|
|
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.
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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.
|
|
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:*",
|