replicas-engine 0.1.433 → 0.1.435

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
@@ -97,6 +97,7 @@ Engine persistence locations:
97
97
  - `~/.replicas/startHooks.log`
98
98
  - Canvas read locations (for `/canvas` endpoints):
99
99
  - `~/.claude/plans` (where Claude Code writes its plans)
100
+ - `~/.local/share/opencode/plans` and each repository's `.opencode/plans`
100
101
  - `~/.replicas/canvas`
101
102
  - Health endpoint readiness signal file:
102
103
  - `/var/log/cloud-init-output.log` (if missing, `/health` reports `initializing`)
package/dist/src/index.js CHANGED
@@ -506,7 +506,7 @@ var WORKSPACE_SIZES = ["small", "large"];
506
506
  var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
507
507
 
508
508
  // ../shared/src/e2b.ts
509
- var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-14-v4";
509
+ var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-14-v6";
510
510
 
511
511
  // ../shared/src/runtime-env.ts
512
512
  function shellQuotePosix(value) {
@@ -4218,21 +4218,35 @@ var GitService = class {
4218
4218
  return { repos: states, complete };
4219
4219
  }
4220
4220
  async refreshRepos(observedBranchesByRepo, options) {
4221
- const repos = await this.listRepositories();
4221
+ return (await this.refreshReposWithCompleteness(observedBranchesByRepo, options)).repos;
4222
+ }
4223
+ async refreshReposWithCompleteness(observedBranchesByRepo, options) {
4224
+ const discovered = await this.listRepositoriesWithCompleteness();
4222
4225
  const states = [];
4223
- for (const repo of repos) {
4226
+ let complete = discovered.complete;
4227
+ for (const repo of discovered.repos) {
4224
4228
  try {
4225
4229
  const persistedState = await loadRepoState(repo.name);
4226
4230
  const currentBranch = await getCurrentBranch(repo.path) ?? repo.defaultBranch;
4227
4231
  const startHooksCompleted = persistedState?.startHooksCompleted ?? false;
4228
4232
  const observed = observedBranchesByRepo?.get(repo.name);
4229
- states.push(
4230
- await this.refreshRepoMetadata(repo, currentBranch, startHooksCompleted, persistedState, observed, options?.includeDiffs === true)
4233
+ const state = await this.refreshRepoMetadata(
4234
+ repo,
4235
+ currentBranch,
4236
+ startHooksCompleted,
4237
+ persistedState,
4238
+ observed,
4239
+ options?.includeDiffs === true
4231
4240
  );
4241
+ if (state.gitDiff === null || options?.includeDiffs === true && state.gitDiff.fullDiff === void 0) {
4242
+ complete = false;
4243
+ }
4244
+ states.push(state);
4232
4245
  } catch {
4246
+ complete = false;
4233
4247
  }
4234
4248
  }
4235
- return states;
4249
+ return { repos: states, complete };
4236
4250
  }
4237
4251
  // Fast branch snapshot for per-event observation during a turn. Reads
4238
4252
  // .git/HEAD directly for each repo (no subprocess) so callers can safely
@@ -8464,7 +8478,7 @@ var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
8464
8478
  var MIN_CODEX_CLI_VERSION = "0.144.0";
8465
8479
  var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
8466
8480
  var codexCliVersionEnsured = null;
8467
- var ENGINE_PACKAGE_VERSION = "0.1.433";
8481
+ var ENGINE_PACKAGE_VERSION = "0.1.435";
8468
8482
  var INITIALIZE_METHOD = "initialize";
8469
8483
  var INITIALIZED_NOTIFICATION = "initialized";
8470
8484
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -9210,7 +9224,7 @@ async function buildTurnInput(request) {
9210
9224
  })));
9211
9225
  return { input, tempImagePaths };
9212
9226
  }
9213
- async function buildTurnStartParams(threadId, request, developerInstructions, serviceTier) {
9227
+ async function buildTurnStartParams(threadId, request, serviceTier) {
9214
9228
  const effort = toReasoningEffort(request.thinkingLevel);
9215
9229
  const model = request.model ?? DEFAULT_MODEL;
9216
9230
  const { input, tempImagePaths } = await buildTurnInput(request);
@@ -9222,16 +9236,14 @@ async function buildTurnStartParams(threadId, request, developerInstructions, se
9222
9236
  ...serviceTier !== void 0 ? { serviceTier } : {},
9223
9237
  ...codexApprovalPolicyOverrides(),
9224
9238
  ...effort ? { effort } : {},
9225
- ...developerInstructions ? {
9226
- collaborationMode: {
9227
- mode: "default",
9228
- settings: {
9229
- model,
9230
- reasoning_effort: effort ?? null,
9231
- developer_instructions: developerInstructions
9232
- }
9239
+ collaborationMode: {
9240
+ mode: request.planMode ? "plan" : "default",
9241
+ settings: {
9242
+ model,
9243
+ reasoning_effort: effort ?? null,
9244
+ developer_instructions: null
9233
9245
  }
9234
- } : {}
9246
+ }
9235
9247
  },
9236
9248
  tempImagePaths
9237
9249
  };
@@ -9710,10 +9722,10 @@ var CodexAspManager = class extends CodingAgentManager {
9710
9722
  const threadId = await this.ensureThread(host, request, developerInstructions);
9711
9723
  const serviceTier = await this.resolveRequestedServiceTier(host, request);
9712
9724
  await this.applyThreadServiceTier(host, threadId, serviceTier);
9713
- const runTurn = options.runTurn ?? ((aspHost, aspThreadId, aspInstructions) => this.runTurn(aspHost, aspThreadId, request, aspInstructions, serviceTier));
9725
+ const runTurn = options.runTurn ?? ((aspHost, aspThreadId) => this.runTurn(aspHost, aspThreadId, request, serviceTier));
9714
9726
  let completedTurn;
9715
9727
  try {
9716
- completedTurn = await runTurn(host, threadId, developerInstructions);
9728
+ completedTurn = await runTurn(host, threadId);
9717
9729
  } catch (error) {
9718
9730
  await this.refreshQuotaSnapshot(host);
9719
9731
  if (this.quotaStatus.blocked) {
@@ -9808,8 +9820,8 @@ var CodexAspManager = class extends CodingAgentManager {
9808
9820
  console.warn("[CodexAspManager] Failed to apply skill registries:", error);
9809
9821
  }
9810
9822
  }
9811
- async runTurn(host, threadId, request, developerInstructions, serviceTier) {
9812
- const { params, tempImagePaths } = await buildTurnStartParams(threadId, request, developerInstructions, serviceTier);
9823
+ async runTurn(host, threadId, request, serviceTier) {
9824
+ const { params, tempImagePaths } = await buildTurnStartParams(threadId, request, serviceTier);
9813
9825
  return this.observeTurn(host, threadId, request, async () => {
9814
9826
  const turnStartResponse = await host.client.request(
9815
9827
  TURN_START_METHOD,
@@ -12276,14 +12288,22 @@ var keepAliveService = new KeepAliveService();
12276
12288
  import { readdir as readdir6, readFile as readFile12, stat as stat3 } from "fs/promises";
12277
12289
  import { homedir as homedir13 } from "os";
12278
12290
  import { join as join19 } from "path";
12279
- var CANVAS_DIRECTORIES = [
12280
- join19(homedir13(), ".replicas", "canvas"),
12281
- join19(homedir13(), ".claude", "plans")
12291
+ var GLOBAL_CANVAS_DIRECTORIES = [
12292
+ join19(homedir13(), ".claude", "plans"),
12293
+ join19(process.env.XDG_DATA_HOME ?? join19(homedir13(), ".local", "share"), "opencode", "plans"),
12294
+ join19(homedir13(), ".replicas", "canvas")
12282
12295
  ];
12296
+ async function canvasDirectories() {
12297
+ const repositories = await gitService.listRepositories().catch(() => []);
12298
+ return [
12299
+ ...GLOBAL_CANVAS_DIRECTORIES,
12300
+ ...repositories.map((repository) => join19(repository.path, ".opencode", "plans"))
12301
+ ];
12302
+ }
12283
12303
  var CanvasService = class {
12284
12304
  async listItems() {
12285
12305
  const items = /* @__PURE__ */ new Map();
12286
- for (const directory of CANVAS_DIRECTORIES) {
12306
+ for (const directory of await canvasDirectories()) {
12287
12307
  let entries;
12288
12308
  try {
12289
12309
  entries = await readdir6(directory, { withFileTypes: true });
@@ -12311,7 +12331,7 @@ var CanvasService = class {
12311
12331
  const safe = sanitizeCanvasFilename(filename);
12312
12332
  if (!safe) return null;
12313
12333
  const { kind, mimeType } = classifyCanvasFilename(safe);
12314
- for (const directory of CANVAS_DIRECTORIES) {
12334
+ for (const directory of await canvasDirectories()) {
12315
12335
  const filePath = join19(directory, safe);
12316
12336
  let sizeBytes = 0;
12317
12337
  let updatedAt = "";
@@ -12515,6 +12535,39 @@ async function uploadChatTranscript(chatId, filePath, chat) {
12515
12535
  }
12516
12536
  }
12517
12537
 
12538
+ // src/services/upload-repo-state.ts
12539
+ var uploadQueue = Promise.resolve();
12540
+ async function sendRepoState(repos) {
12541
+ const form = new FormData();
12542
+ form.append(
12543
+ "file",
12544
+ new Blob([JSON.stringify({ repos })], { type: "application/json" }),
12545
+ "repo-state.json"
12546
+ );
12547
+ const response = await monolithRequest("/v1/engine/repo-state", { body: form });
12548
+ if (!response.ok) {
12549
+ const errorText = await response.text();
12550
+ throw new Error(`upload failed: ${response.status} ${errorText}`);
12551
+ }
12552
+ }
12553
+ function uploadRepoState(repos) {
12554
+ const upload = uploadQueue.then(() => sendRepoState(repos));
12555
+ uploadQueue = upload.catch(() => {
12556
+ });
12557
+ return upload;
12558
+ }
12559
+ async function flushRepoState() {
12560
+ try {
12561
+ const { repos, complete } = await gitService.listReposWithCompleteness({ includeDiffs: true });
12562
+ if (!complete) return { flushed: 0, skipped: 1, failed: 0 };
12563
+ await uploadRepoState(repos);
12564
+ return { flushed: 1, skipped: 0, failed: 0 };
12565
+ } catch (err) {
12566
+ console.error("[RepoStateUploader] upload failed:", err);
12567
+ return { flushed: 0, skipped: 0, failed: 1 };
12568
+ }
12569
+ }
12570
+
12518
12571
  // src/services/chat/chat-service.ts
12519
12572
  var CHAT_SENDERS_DIR = join21(ENGINE_DIR2, "chat-senders");
12520
12573
  var CODEX_AUTH_PATH2 = join21(homedir15(), ".codex", "auth.json");
@@ -12986,11 +13039,12 @@ var ChatService = class {
12986
13039
  const chatsById = new Map(
12987
13040
  [...this.chats.entries()].map(([chatId, chat]) => [chatId, this.toSummary(chat)])
12988
13041
  );
12989
- const [chatTranscripts, canvas] = await Promise.all([
13042
+ const [chatTranscripts, canvas, repoState] = await Promise.all([
12990
13043
  flushAllChatTranscripts(chatsById),
12991
- flushAllCanvasItems()
13044
+ flushAllCanvasItems(),
13045
+ flushRepoState()
12992
13046
  ]);
12993
- return { chatTranscripts, canvas };
13047
+ return { chatTranscripts, canvas, repoState };
12994
13048
  }
12995
13049
  createRuntimeChat(persisted) {
12996
13050
  const saveSession = async (sessionId) => {
@@ -13293,15 +13347,23 @@ var ChatService = class {
13293
13347
  const linearSessionId = ENGINE_ENV.LINEAR_SESSION_ID;
13294
13348
  const observedBranches = chat.observedBranchesByRepo;
13295
13349
  chat.observedBranchesByRepo = /* @__PURE__ */ new Map();
13296
- let repoStatuses;
13350
+ let repoStatuses = [];
13351
+ let repoStateComplete = false;
13297
13352
  try {
13298
- repoStatuses = await gitService.refreshRepos(observedBranches, { includeDiffs: true });
13353
+ const refreshed = await gitService.refreshReposWithCompleteness(observedBranches, { includeDiffs: true });
13354
+ repoStatuses = refreshed.repos;
13355
+ repoStateComplete = refreshed.complete;
13299
13356
  console.log(`Repository Statuses Refreshed: `, repoStatuses);
13300
13357
  } catch (error) {
13301
13358
  console.error("[ChatService] Failed to refresh repo statuses:", error);
13302
13359
  }
13360
+ if (repoStateComplete) {
13361
+ uploadRepoState(repoStatuses).catch((err) => {
13362
+ console.error("[ChatService] Failed to upload repository state:", err);
13363
+ });
13364
+ }
13303
13365
  try {
13304
- const payload = linearSessionId ? { linearSessionId, repoStatuses: repoStatuses ?? [] } : { repoStatuses: repoStatuses ?? [] };
13366
+ const payload = linearSessionId ? { linearSessionId, repoStatuses } : { repoStatuses };
13305
13367
  await monolithService.sendEvent({ type: "agent_turn_complete", payload });
13306
13368
  } catch (error) {
13307
13369
  console.error("[ChatService] Failed to send agent_turn_complete event:", error);
@@ -14325,11 +14387,10 @@ function createV1Routes(deps) {
14325
14387
  });
14326
14388
  app2.get("/repos", async (c) => {
14327
14389
  const includeDiffs = c.req.query("includeDiffs") === "true";
14328
- const { repos, complete } = await gitService.listReposWithCompleteness({ includeDiffs });
14390
+ const repos = await gitService.listRepos({ includeDiffs });
14329
14391
  const response = {
14330
14392
  repos,
14331
- workspaceRoot: gitService.getWorkspaceRoot(),
14332
- complete
14393
+ workspaceRoot: gitService.getWorkspaceRoot()
14333
14394
  };
14334
14395
  return c.json(response);
14335
14396
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.433",
3
+ "version": "0.1.435",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",