@elizaos/plugin-agent-orchestrator 0.4.2 → 0.4.3

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.
@@ -9,8 +9,14 @@
9
9
  */
10
10
  import { type HandlerCallback, type IAgentRuntime } from "@elizaos/core";
11
11
  import type { PTYService } from "../services/pty-service.js";
12
- /** Create a scratch sandbox directory for non-repo tasks */
13
- export declare function createScratchDir(): string;
12
+ /**
13
+ * Create a scratch sandbox directory for non-repo tasks.
14
+ *
15
+ * When `PARALLAX_CODING_DIRECTORY` is set (e.g. `~/Projects`), creates a
16
+ * named subdir like `~/Projects/todo-app/` derived from the task label.
17
+ * Otherwise falls back to `~/.milady/workspaces/{uuid}`.
18
+ */
19
+ export declare function createScratchDir(runtime?: IAgentRuntime, label?: string): string;
14
20
  /**
15
21
  * Generate a short semantic label from repo URL and/or task description.
16
22
  * e.g. "git-workspace-service-testbed/hello-mima" or "scratch/react-research"
@@ -1 +1 @@
1
- {"version":3,"file":"coding-task-helpers.d.ts","sourceRoot":"","sources":["../../src/actions/coding-task-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,aAAa,EAEnB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AAG7D,4DAA4D;AAC5D,wBAAgB,gBAAgB,IAAI,MAAM,CAMzC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB,MAAM,CA4BR;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,QAAQ,CAAC,EAAE,eAAe,EAC1B,iBAAiB,UAAQ,GACxB,IAAI,CA6DN"}
1
+ {"version":3,"file":"coding-task-helpers.d.ts","sourceRoot":"","sources":["../../src/actions/coding-task-helpers.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,EACL,KAAK,eAAe,EACpB,KAAK,aAAa,EAEnB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AA+B7D;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,CAAC,EAAE,aAAa,EACvB,KAAK,CAAC,EAAE,MAAM,GACb,MAAM,CA0BR;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB,MAAM,CA4BR;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,MAAM,GAAG,IAAI,EACzB,QAAQ,CAAC,EAAE,eAAe,EAC1B,iBAAiB,UAAQ,GACxB,IAAI,CAsEN"}
package/dist/index.js CHANGED
@@ -3600,9 +3600,30 @@ class SwarmCoordinator {
3600
3600
  constructor(runtime) {
3601
3601
  this.runtime = runtime;
3602
3602
  }
3603
+ scratchDecisionWired = false;
3603
3604
  setChatCallback(cb) {
3604
3605
  this.chatCallback = cb;
3605
3606
  this.log("Chat callback wired");
3607
+ this.wireScratchDecisionCallback();
3608
+ }
3609
+ wireScratchDecisionCallback() {
3610
+ if (this.scratchDecisionWired || !this.chatCallback)
3611
+ return;
3612
+ const wsService = this.runtime.getService("CODING_WORKSPACE_SERVICE");
3613
+ if (wsService?.setScratchDecisionCallback) {
3614
+ const chatCb = this.chatCallback;
3615
+ wsService.setScratchDecisionCallback(async (record) => {
3616
+ const ttlNote = record.expiresAt ? (() => {
3617
+ const remainMs = record.expiresAt - Date.now();
3618
+ const hours = Math.round(remainMs / (60 * 60 * 1000));
3619
+ return hours >= 1 ? `It will be automatically cleaned up in ~${hours} hour${hours === 1 ? "" : "s"}.` : `It will be automatically cleaned up shortly.`;
3620
+ })() : "It will be automatically cleaned up after the configured retention period.";
3621
+ await chatCb(`Task "${record.label}" finished. Code is at \`${record.path}\`.
3622
+ ` + `${ttlNote} To keep it, say "keep the workspace" or manage it in Settings → Coding Agents.`, "coding-agent");
3623
+ });
3624
+ this.scratchDecisionWired = true;
3625
+ this.log("Scratch decision callback wired");
3626
+ }
3606
3627
  }
3607
3628
  setWsBroadcast(cb) {
3608
3629
  this.wsBroadcast = cb;
@@ -3911,6 +3932,9 @@ class SwarmCoordinator {
3911
3932
  } catch {}
3912
3933
  }
3913
3934
  async handleSessionEvent(sessionId, event, data) {
3935
+ if (!this.scratchDecisionWired) {
3936
+ this.wireScratchDecisionCallback();
3937
+ }
3914
3938
  const tsMatch = sessionId.match(/^pty-(\d+)-/);
3915
3939
  if (tsMatch) {
3916
3940
  const sessionCreatedAt = Number(tsMatch[1]);
@@ -5284,15 +5308,55 @@ function formatAge(timestamp) {
5284
5308
  // src/actions/coding-task-helpers.ts
5285
5309
  import { randomUUID } from "node:crypto";
5286
5310
  import * as fs2 from "node:fs";
5287
- import * as os3 from "node:os";
5288
- import * as path4 from "node:path";
5311
+ import * as os4 from "node:os";
5312
+ import * as path5 from "node:path";
5289
5313
  import {
5290
5314
  logger as logger5
5291
5315
  } from "@elizaos/core";
5292
- function createScratchDir() {
5293
- const baseDir = path4.join(os3.homedir(), ".milady", "workspaces");
5316
+
5317
+ // src/services/config-env.ts
5318
+ import { readFileSync } from "node:fs";
5319
+ import * as os3 from "node:os";
5320
+ import * as path4 from "node:path";
5321
+ function readConfigEnvKey(key) {
5322
+ try {
5323
+ const configPath = path4.join(process.env.MILADY_STATE_DIR ?? process.env.ELIZA_STATE_DIR ?? path4.join(os3.homedir(), ".milady"), process.env.ELIZA_NAMESPACE === "milady" || !process.env.ELIZA_NAMESPACE ? "milady.json" : `${process.env.ELIZA_NAMESPACE}.json`);
5324
+ const raw = readFileSync(configPath, "utf-8");
5325
+ const config = JSON.parse(raw);
5326
+ const val = config?.env?.[key];
5327
+ return typeof val === "string" ? val : undefined;
5328
+ } catch {
5329
+ return;
5330
+ }
5331
+ }
5332
+
5333
+ // src/actions/coding-task-helpers.ts
5334
+ function sanitizeDirName(label) {
5335
+ return label.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-{2,}/g, "-").replace(/^-|-$/g, "").slice(0, 60) || "scratch";
5336
+ }
5337
+ function resolveNonColliding(baseDir, name) {
5338
+ let candidate = path5.join(baseDir, name);
5339
+ if (!fs2.existsSync(candidate))
5340
+ return candidate;
5341
+ for (let i = 2;i < 100; i++) {
5342
+ candidate = path5.join(baseDir, `${name}-${i}`);
5343
+ if (!fs2.existsSync(candidate))
5344
+ return candidate;
5345
+ }
5346
+ return path5.join(baseDir, `${name}-${randomUUID().slice(0, 8)}`);
5347
+ }
5348
+ function createScratchDir(runtime, label) {
5349
+ const codingDir = runtime?.getSetting("PARALLAX_CODING_DIRECTORY") ?? readConfigEnvKey("PARALLAX_CODING_DIRECTORY") ?? process.env.PARALLAX_CODING_DIRECTORY;
5350
+ if (codingDir?.trim()) {
5351
+ const resolved = codingDir.startsWith("~") ? path5.join(os4.homedir(), codingDir.slice(1)) : path5.resolve(codingDir);
5352
+ const dirName = label ? sanitizeDirName(label) : `scratch-${randomUUID().slice(0, 8)}`;
5353
+ const scratchDir2 = resolveNonColliding(resolved, dirName);
5354
+ fs2.mkdirSync(scratchDir2, { recursive: true });
5355
+ return scratchDir2;
5356
+ }
5357
+ const baseDir = path5.join(os4.homedir(), ".milady", "workspaces");
5294
5358
  const scratchId = randomUUID();
5295
- const scratchDir = path4.join(baseDir, scratchId);
5359
+ const scratchDir = path5.join(baseDir, scratchId);
5296
5360
  fs2.mkdirSync(scratchDir, { recursive: true });
5297
5361
  return scratchDir;
5298
5362
  }
@@ -5312,6 +5376,7 @@ function generateLabel(repo, task) {
5312
5376
  return parts.join("/");
5313
5377
  }
5314
5378
  function registerSessionEvents(ptyService, runtime, sessionId, label, scratchDir, callback, coordinatorActive = false) {
5379
+ let scratchRegistered = false;
5315
5380
  ptyService.onSessionEvent((sid, event, data) => {
5316
5381
  if (sid !== sessionId)
5317
5382
  return;
@@ -5341,10 +5406,15 @@ ${preview}` : `Agent "${label}" completed the task.`
5341
5406
  });
5342
5407
  }
5343
5408
  }
5344
- if ((event === "stopped" || event === "task_complete" || event === "error") && scratchDir) {
5409
+ if ((event === "stopped" || event === "task_complete" || event === "error") && scratchDir && !scratchRegistered) {
5410
+ logger5.info(`[scratch-lifecycle] Terminal event "${event}" for "${label}" — registering scratch workspace at ${scratchDir}`);
5345
5411
  const wsService = runtime.getService("CODING_WORKSPACE_SERVICE");
5346
- if (wsService) {
5347
- wsService.registerScratchWorkspace(sessionId, scratchDir, label, event).catch((err) => {
5412
+ if (!wsService) {
5413
+ logger5.warn(`[scratch-lifecycle] CODING_WORKSPACE_SERVICE not found cannot register scratch workspace`);
5414
+ } else {
5415
+ wsService.registerScratchWorkspace(sessionId, scratchDir, label, event).then(() => {
5416
+ scratchRegistered = true;
5417
+ }).catch((err) => {
5348
5418
  logger5.warn(`[START_CODING_TASK] Failed to register scratch workspace for "${label}": ${err}`);
5349
5419
  });
5350
5420
  }
@@ -5523,7 +5593,7 @@ async function handleMultiAgent(ctx, agentsParam) {
5523
5593
  branch = workspace.branch;
5524
5594
  wsService.setLabel(workspace.id, specLabel);
5525
5595
  } else {
5526
- workdir = createScratchDir();
5596
+ workdir = createScratchDir(runtime, specLabel);
5527
5597
  }
5528
5598
  if (specAgentType !== "shell" && specAgentType !== "pi") {
5529
5599
  const [preflight] = await ptyService.checkAvailableAgents([
@@ -6191,7 +6261,7 @@ var activeWorkspaceContextProvider = {
6191
6261
  try {
6192
6262
  sessions = await Promise.race([
6193
6263
  ptyService.listSessions(),
6194
- new Promise((resolve3) => setTimeout(() => resolve3([]), 2000))
6264
+ new Promise((resolve4) => setTimeout(() => resolve4([]), 2000))
6195
6265
  ]);
6196
6266
  } catch {
6197
6267
  sessions = [];
@@ -6275,8 +6345,8 @@ var activeWorkspaceContextProvider = {
6275
6345
  };
6276
6346
 
6277
6347
  // src/services/workspace-service.ts
6278
- import * as os4 from "node:os";
6279
- import * as path6 from "node:path";
6348
+ import * as os6 from "node:os";
6349
+ import * as path7 from "node:path";
6280
6350
  import * as fs4 from "node:fs/promises";
6281
6351
  import {
6282
6352
  CredentialService,
@@ -6491,12 +6561,18 @@ async function createPR(workspaceService, workspace, workspaceId, options, log)
6491
6561
 
6492
6562
  // src/services/workspace-lifecycle.ts
6493
6563
  import * as fs3 from "node:fs";
6494
- import * as path5 from "node:path";
6495
- async function removeScratchDir(dirPath, baseDir, log) {
6496
- const resolved = path5.resolve(dirPath);
6497
- const resolvedBase = path5.resolve(baseDir) + path5.sep;
6498
- if (!resolved.startsWith(resolvedBase) && resolved !== path5.resolve(baseDir)) {
6499
- console.warn(`[CodingWorkspaceService] Refusing to remove dir outside base: ${resolved}`);
6564
+ import * as os5 from "node:os";
6565
+ import * as path6 from "node:path";
6566
+ async function removeScratchDir(dirPath, baseDir, log, allowedDirs) {
6567
+ const resolved = path6.resolve(dirPath);
6568
+ const expandTilde = (p) => p.startsWith("~") ? path6.join(os5.homedir(), p.slice(1)) : p;
6569
+ const allAllowed = [baseDir, ...allowedDirs ?? []];
6570
+ const isAllowed = allAllowed.some((dir) => {
6571
+ const resolvedDir = path6.resolve(expandTilde(dir)) + path6.sep;
6572
+ return resolved.startsWith(resolvedDir) || resolved === path6.resolve(expandTilde(dir));
6573
+ });
6574
+ if (!isAllowed) {
6575
+ console.warn(`[CodingWorkspaceService] Refusing to remove dir outside allowed paths: ${resolved}`);
6500
6576
  return;
6501
6577
  }
6502
6578
  try {
@@ -6527,7 +6603,7 @@ async function gcOrphanedWorkspaces(baseDir, workspaceTtlMs, trackedWorkspaceIds
6527
6603
  skipped++;
6528
6604
  continue;
6529
6605
  }
6530
- const dirPath = path5.join(baseDir, entry.name);
6606
+ const dirPath = path6.join(baseDir, entry.name);
6531
6607
  try {
6532
6608
  const stat2 = await fs3.promises.stat(dirPath);
6533
6609
  const age = now - stat2.mtimeMs;
@@ -6563,10 +6639,11 @@ class CodingWorkspaceService {
6563
6639
  scratchCleanupTimers = new Map;
6564
6640
  eventCallbacks = [];
6565
6641
  authPromptCallback = null;
6642
+ scratchDecisionCallback = null;
6566
6643
  constructor(runtime, config = {}) {
6567
6644
  this.runtime = runtime;
6568
6645
  this.serviceConfig = {
6569
- baseDir: config.baseDir ?? path6.join(os4.homedir(), ".milady", "workspaces"),
6646
+ baseDir: config.baseDir ?? path7.join(os6.homedir(), ".milady", "workspaces"),
6570
6647
  branchPrefix: config.branchPrefix ?? "milady",
6571
6648
  debug: config.debug ?? false,
6572
6649
  workspaceTtlMs: config.workspaceTtlMs ?? 24 * 60 * 60 * 1000
@@ -6761,6 +6838,9 @@ class CodingWorkspaceService {
6761
6838
  setAuthPromptCallback(callback) {
6762
6839
  this.authPromptCallback = callback;
6763
6840
  }
6841
+ setScratchDecisionCallback(callback) {
6842
+ this.scratchDecisionCallback = callback;
6843
+ }
6764
6844
  async createIssue(repo, options) {
6765
6845
  return createIssue(this.getGitHubContext(), repo, options);
6766
6846
  }
@@ -6819,7 +6899,10 @@ class CodingWorkspaceService {
6819
6899
  }
6820
6900
  }
6821
6901
  async removeScratchDir(dirPath) {
6822
- return removeScratchDir(dirPath, this.serviceConfig.baseDir, (msg) => this.log(msg));
6902
+ const rawCodingDir = this.runtime.getSetting("PARALLAX_CODING_DIRECTORY") ?? this.readConfigEnvKey("PARALLAX_CODING_DIRECTORY") ?? process.env.PARALLAX_CODING_DIRECTORY;
6903
+ const codingDir = rawCodingDir?.trim() ? rawCodingDir.trim().startsWith("~") ? path7.join(os6.homedir(), rawCodingDir.trim().slice(1)) : path7.resolve(rawCodingDir.trim()) : undefined;
6904
+ const allowedDirs = codingDir ? [codingDir] : undefined;
6905
+ return removeScratchDir(dirPath, this.serviceConfig.baseDir, (msg) => this.log(msg), allowedDirs);
6823
6906
  }
6824
6907
  listScratchWorkspaces() {
6825
6908
  return Array.from(this.scratchBySession.values()).sort((a, b) => b.terminalAt - a.terminalAt);
@@ -6837,6 +6920,7 @@ class CodingWorkspaceService {
6837
6920
  status: "pending_decision"
6838
6921
  };
6839
6922
  const policy = this.getScratchRetentionPolicy();
6923
+ this.log(`Scratch retention policy: "${policy}" for "${label}"`);
6840
6924
  if (policy === "ephemeral") {
6841
6925
  await this.removeScratchDir(dirPath);
6842
6926
  this.scratchBySession.delete(sessionId);
@@ -6857,6 +6941,14 @@ class CodingWorkspaceService {
6857
6941
  const ttlMs = this.getScratchDecisionTtlMs();
6858
6942
  record.expiresAt = now + ttlMs;
6859
6943
  this.scheduleScratchCleanup(sessionId, ttlMs);
6944
+ if (this.scratchDecisionCallback) {
6945
+ this.log(`Firing scratch decision prompt for "${label}" at ${dirPath}`);
6946
+ this.scratchDecisionCallback(record).catch((err) => {
6947
+ console.warn(`[workspace] Failed to send scratch decision prompt: ${err}`);
6948
+ });
6949
+ } else {
6950
+ this.log(`No scratch decision callback wired — skipping prompt for "${label}"`);
6951
+ }
6860
6952
  } else {
6861
6953
  this.clearScratchCleanupTimer(sessionId);
6862
6954
  }
@@ -6912,14 +7004,22 @@ class CodingWorkspaceService {
6912
7004
  console.log(`[CodingWorkspaceService] ${message}`);
6913
7005
  }
6914
7006
  }
7007
+ readConfigEnvKey(key) {
7008
+ return readConfigEnvKey(key);
7009
+ }
6915
7010
  getScratchRetentionPolicy() {
6916
- const setting = this.runtime.getSetting("PARALLAX_SCRATCH_RETENTION") ?? process.env.PARALLAX_SCRATCH_RETENTION;
7011
+ const setting = this.runtime.getSetting("PARALLAX_SCRATCH_RETENTION") ?? this.readConfigEnvKey("PARALLAX_SCRATCH_RETENTION") ?? process.env.PARALLAX_SCRATCH_RETENTION;
6917
7012
  const normalized = setting?.trim().toLowerCase();
6918
7013
  if (normalized === "ephemeral")
6919
7014
  return "ephemeral";
6920
7015
  if (normalized === "persistent" || normalized === "keep") {
6921
7016
  return "persistent";
6922
7017
  }
7018
+ if (!normalized) {
7019
+ const codingDir = this.runtime.getSetting("PARALLAX_CODING_DIRECTORY") ?? this.readConfigEnvKey("PARALLAX_CODING_DIRECTORY") ?? process.env.PARALLAX_CODING_DIRECTORY;
7020
+ if (codingDir?.trim())
7021
+ return "persistent";
7022
+ }
6923
7023
  return "pending_decision";
6924
7024
  }
6925
7025
  getScratchDecisionTtlMs() {
@@ -6965,11 +7065,11 @@ class CodingWorkspaceService {
6965
7065
  return compact || `scratch-${Date.now().toString(36)}`;
6966
7066
  }
6967
7067
  async allocatePromotedPath(baseDir, baseName) {
6968
- const baseResolved = path6.resolve(baseDir);
7068
+ const baseResolved = path7.resolve(baseDir);
6969
7069
  for (let i = 0;i < 1000; i++) {
6970
7070
  const candidateName = i === 0 ? baseName : `${baseName}-${i}`;
6971
- const candidate = path6.resolve(baseResolved, candidateName);
6972
- if (candidate !== baseResolved && !candidate.startsWith(`${baseResolved}${path6.sep}`)) {
7071
+ const candidate = path7.resolve(baseResolved, candidateName);
7072
+ if (candidate !== baseResolved && !candidate.startsWith(`${baseResolved}${path7.sep}`)) {
6973
7073
  continue;
6974
7074
  }
6975
7075
  try {
@@ -6984,8 +7084,8 @@ class CodingWorkspaceService {
6984
7084
  // src/api/agent-routes.ts
6985
7085
  import { access as access2, readFile as readFile4, realpath, rm as rm2 } from "node:fs/promises";
6986
7086
  import { createHash } from "node:crypto";
6987
- import * as os5 from "node:os";
6988
- import * as path7 from "node:path";
7087
+ import * as os7 from "node:os";
7088
+ import * as path8 from "node:path";
6989
7089
  import { execFile } from "node:child_process";
6990
7090
  import { promisify } from "node:util";
6991
7091
  var execFileAsync = promisify(execFile);
@@ -6997,23 +7097,23 @@ function shouldAutoPreflight() {
6997
7097
  return false;
6998
7098
  }
6999
7099
  function isPathInside(parent, candidate) {
7000
- return candidate === parent || candidate.startsWith(`${parent}${path7.sep}`);
7100
+ return candidate === parent || candidate.startsWith(`${parent}${path8.sep}`);
7001
7101
  }
7002
7102
  async function resolveSafeVenvPath(workdir, venvDirRaw) {
7003
7103
  const venvDir = venvDirRaw.trim();
7004
7104
  if (!venvDir) {
7005
7105
  throw new Error("PARALLAX_BENCHMARK_PREFLIGHT_VENV must be non-empty");
7006
7106
  }
7007
- if (path7.isAbsolute(venvDir)) {
7107
+ if (path8.isAbsolute(venvDir)) {
7008
7108
  throw new Error("PARALLAX_BENCHMARK_PREFLIGHT_VENV must be relative to workdir");
7009
7109
  }
7010
- const normalized = path7.normalize(venvDir);
7011
- if (normalized === "." || normalized === ".." || normalized.startsWith(`..${path7.sep}`)) {
7110
+ const normalized = path8.normalize(venvDir);
7111
+ if (normalized === "." || normalized === ".." || normalized.startsWith(`..${path8.sep}`)) {
7012
7112
  throw new Error("PARALLAX_BENCHMARK_PREFLIGHT_VENV must stay within workdir");
7013
7113
  }
7014
- const workdirResolved = path7.resolve(workdir);
7114
+ const workdirResolved = path8.resolve(workdir);
7015
7115
  const workdirReal = await realpath(workdirResolved);
7016
- const resolved = path7.resolve(workdirReal, normalized);
7116
+ const resolved = path8.resolve(workdirReal, normalized);
7017
7117
  if (!isPathInside(workdirReal, resolved)) {
7018
7118
  throw new Error("PARALLAX_BENCHMARK_PREFLIGHT_VENV resolves outside workdir");
7019
7119
  }
@@ -7029,7 +7129,7 @@ async function resolveSafeVenvPath(workdir, venvDirRaw) {
7029
7129
  const maybeErr = err;
7030
7130
  if (maybeErr?.code !== "ENOENT")
7031
7131
  throw err;
7032
- const parentReal = await realpath(path7.dirname(resolved));
7132
+ const parentReal = await realpath(path8.dirname(resolved));
7033
7133
  if (!isPathInside(workdirReal, parentReal)) {
7034
7134
  throw new Error("PARALLAX_BENCHMARK_PREFLIGHT_VENV parent resolves outside workdir");
7035
7135
  }
@@ -7045,10 +7145,10 @@ async function fileExists(filePath) {
7045
7145
  }
7046
7146
  }
7047
7147
  async function resolveRequirementsPath(workdir) {
7048
- const workdirReal = await realpath(path7.resolve(workdir));
7148
+ const workdirReal = await realpath(path8.resolve(workdir));
7049
7149
  const candidates = [
7050
- path7.join(workdir, "apps", "api", "requirements.txt"),
7051
- path7.join(workdir, "requirements.txt")
7150
+ path8.join(workdir, "apps", "api", "requirements.txt"),
7151
+ path8.join(workdir, "requirements.txt")
7052
7152
  ];
7053
7153
  for (const candidate of candidates) {
7054
7154
  if (!await fileExists(candidate))
@@ -7075,7 +7175,7 @@ async function runBenchmarkPreflight(workdir) {
7075
7175
  const mode = process.env.PARALLAX_BENCHMARK_PREFLIGHT_MODE?.toLowerCase() === "warm" ? "warm" : "cold";
7076
7176
  const venvDir = process.env.PARALLAX_BENCHMARK_PREFLIGHT_VENV || ".benchmark-venv";
7077
7177
  const venvPath = await resolveSafeVenvPath(workdir, venvDir);
7078
- const pythonInVenv = path7.join(venvPath, process.platform === "win32" ? "Scripts" : "bin", process.platform === "win32" ? "python.exe" : "python");
7178
+ const pythonInVenv = path8.join(venvPath, process.platform === "win32" ? "Scripts" : "bin", process.platform === "win32" ? "python.exe" : "python");
7079
7179
  const key = `${workdir}::${mode}::${venvPath}::${requirementsFingerprint}`;
7080
7180
  if (PREFLIGHT_DONE.has(key)) {
7081
7181
  if (await fileExists(pythonInVenv))
@@ -7283,21 +7383,21 @@ async function handleAgentRoutes(req, res, pathname, ctx) {
7283
7383
  customCredentials,
7284
7384
  metadata
7285
7385
  } = body;
7286
- const workspaceBaseDir = path7.join(os5.homedir(), ".milady", "workspaces");
7287
- const workspaceBaseDirResolved = path7.resolve(workspaceBaseDir);
7288
- const cwdResolved = path7.resolve(process.cwd());
7386
+ const workspaceBaseDir = path8.join(os7.homedir(), ".milady", "workspaces");
7387
+ const workspaceBaseDirResolved = path8.resolve(workspaceBaseDir);
7388
+ const cwdResolved = path8.resolve(process.cwd());
7289
7389
  const workspaceBaseDirReal = await realpath(workspaceBaseDirResolved).catch(() => workspaceBaseDirResolved);
7290
7390
  const cwdReal = await realpath(cwdResolved).catch(() => cwdResolved);
7291
7391
  const allowedPrefixes = [workspaceBaseDirReal, cwdReal];
7292
7392
  let workdir = rawWorkdir;
7293
7393
  if (workdir) {
7294
- const resolved = path7.resolve(workdir);
7394
+ const resolved = path8.resolve(workdir);
7295
7395
  const resolvedReal = await realpath(resolved).catch(() => null);
7296
7396
  if (!resolvedReal) {
7297
7397
  sendError(res, "workdir must exist", 403);
7298
7398
  return true;
7299
7399
  }
7300
- const isAllowed = allowedPrefixes.some((prefix2) => resolvedReal === prefix2 || resolvedReal.startsWith(prefix2 + path7.sep));
7400
+ const isAllowed = allowedPrefixes.some((prefix2) => resolvedReal === prefix2 || resolvedReal.startsWith(prefix2 + path8.sep));
7301
7401
  if (!isAllowed) {
7302
7402
  sendError(res, "workdir must be within workspace base directory or cwd", 403);
7303
7403
  return true;
@@ -7941,7 +8041,7 @@ async function handleWorkspaceRoutes(req, res, pathname, ctx) {
7941
8041
  // src/api/routes.ts
7942
8042
  var MAX_BODY_SIZE = 1024 * 1024;
7943
8043
  async function parseBody(req) {
7944
- return new Promise((resolve6, reject) => {
8044
+ return new Promise((resolve7, reject) => {
7945
8045
  let body = "";
7946
8046
  let size = 0;
7947
8047
  req.on("data", (chunk) => {
@@ -7955,7 +8055,7 @@ async function parseBody(req) {
7955
8055
  });
7956
8056
  req.on("end", () => {
7957
8057
  try {
7958
- resolve6(body ? JSON.parse(body) : {});
8058
+ resolve7(body ? JSON.parse(body) : {});
7959
8059
  } catch {
7960
8060
  reject(new Error("Invalid JSON body"));
7961
8061
  }
@@ -8043,5 +8143,5 @@ export {
8043
8143
  CodingWorkspaceService
8044
8144
  };
8045
8145
 
8046
- //# debugId=322E3591797FD51B64756E2164756E21
8146
+ //# debugId=CC31B3CD95C1813A64756E2164756E21
8047
8147
  //# sourceMappingURL=index.js.map