@aiden-ade/sandbox-agent 0.1.54 → 0.1.55

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/index.cjs +63 -69
  2. package/package.json +17 -18
package/dist/index.cjs CHANGED
@@ -16947,6 +16947,7 @@ var APPLICATION_PROBLEM_CODES = [
16947
16947
  "app.dispatch.runtime_offline",
16948
16948
  "app.dispatch.delivery_failed",
16949
16949
  "app.workspace.missing",
16950
+ "app.workspace.branch_changed",
16950
16951
  "app.transport.disconnected",
16951
16952
  "app.persistence.failed",
16952
16953
  "app.service.unavailable",
@@ -16981,6 +16982,7 @@ var APPLICATION_PROBLEM_TITLES = {
16981
16982
  "app.dispatch.runtime_offline": "Runtime unavailable",
16982
16983
  "app.dispatch.delivery_failed": "Agent delivery failed",
16983
16984
  "app.workspace.missing": "Workspace unavailable",
16985
+ "app.workspace.branch_changed": "Workspace branch changed",
16984
16986
  "app.transport.disconnected": "Connection lost",
16985
16987
  "app.persistence.failed": "Persistence failed",
16986
16988
  "app.service.unavailable": "Service unavailable",
@@ -17006,6 +17008,14 @@ var APPLICATION_PROBLEM_RECOVERY = {
17006
17008
  },
17007
17009
  "app.dispatch.delivery_failed": { mode: "manual", action: "start_new_attempt", safe: false },
17008
17010
  "app.workspace.missing": { mode: "after_user_action", action: "select_workspace", safe: true },
17011
+ // Distinct from `app.workspace.missing`: the folder is exactly where it was, so
17012
+ // telling the user to relocate it sends them looking for a problem that does not
17013
+ // exist. What they need to do is restore the branch the run was pinned to.
17014
+ "app.workspace.branch_changed": {
17015
+ mode: "after_user_action",
17016
+ action: "restore_branch",
17017
+ safe: true
17018
+ },
17009
17019
  "app.transport.disconnected": { mode: "automatic", action: "reconnect", safe: true },
17010
17020
  "app.persistence.failed": { mode: "automatic", action: "reconcile", safe: true },
17011
17021
  "app.service.unavailable": { mode: "after_user_action", action: "retry", safe: true },
@@ -51101,7 +51111,7 @@ var SuspensionDetector = class {
51101
51111
  };
51102
51112
 
51103
51113
  // src/version.ts
51104
- var AGENT_VERSION = "0.1.54";
51114
+ var AGENT_VERSION = "0.1.55";
51105
51115
 
51106
51116
  // src/workspace-relocation.ts
51107
51117
  var import_node_child_process6 = require("child_process");
@@ -51185,6 +51195,9 @@ var WORKSPACE_LEASE_GIT_TIMEOUT_MS = parsePositiveMs(
51185
51195
  process.env.ALAN_WORKSPACE_LEASE_GIT_TIMEOUT_MS,
51186
51196
  2e3
51187
51197
  );
51198
+ function applicationCodeForWorkspaceLeaseFailure(code) {
51199
+ return code === "workspace_lease_branch_changed" ? "app.workspace.branch_changed" : "app.workspace.missing";
51200
+ }
51188
51201
  function gitValue(cwd, args) {
51189
51202
  const result = (0, import_node_child_process7.spawnSync)("git", ["-C", cwd, ...args], {
51190
51203
  encoding: "utf8",
@@ -51209,8 +51222,8 @@ var DEFAULT_PROBE2 = {
51209
51222
  const repositoryRoot = gitValue(canonicalWorkspacePath, ["rev-parse", "--show-toplevel"]);
51210
51223
  const gitDirectory = gitValue(canonicalWorkspacePath, ["rev-parse", "--git-dir"]);
51211
51224
  const commonDirectory = gitValue(canonicalWorkspacePath, ["rev-parse", "--git-common-dir"]);
51212
- const branch = gitValue(canonicalWorkspacePath, ["rev-parse", "--abbrev-ref", "HEAD"]);
51213
- if (!repositoryRoot || !gitDirectory || !commonDirectory || !branch) return null;
51225
+ const branch = gitValue(canonicalWorkspacePath, ["branch", "--show-current"]) ?? "";
51226
+ if (!repositoryRoot || !gitDirectory || !commonDirectory) return null;
51214
51227
  const remote = gitValue(canonicalWorkspacePath, ["config", "--get", "remote.origin.url"]);
51215
51228
  const remoteIdentity = remote ? normalizeRepositoryIdentity(remote) : null;
51216
51229
  return {
@@ -51234,18 +51247,22 @@ var DEFAULT_PROBE2 = {
51234
51247
  }
51235
51248
  }
51236
51249
  };
51237
- function unavailableFailure(target) {
51250
+ var IDENTITY_FAILURE_MESSAGES = {
51251
+ workspace_lease_unavailable: "The workspace or Git checkout became unavailable while the run was active. Restore it and start a new run.",
51252
+ workspace_lease_path_changed: "The selected workspace folder changed while the run was active. The run stopped before continuing; choose the correct folder and start a new run.",
51253
+ workspace_lease_repository_changed: "The workspace now points to a different repository or worktree. The run stopped before continuing; restore the original checkout and start a new run."
51254
+ };
51255
+ function identityFailure(code, target) {
51238
51256
  return {
51239
- code: "workspace_lease_unavailable",
51240
- message: "The workspace or Git checkout became unavailable while the run was active. Restore it and start a new run.",
51241
- workspacePath: target.workspacePath,
51242
- expectedBranch: target.expectedBranch
51257
+ code,
51258
+ message: IDENTITY_FAILURE_MESSAGES[code],
51259
+ workspacePath: target.workspacePath
51243
51260
  };
51244
51261
  }
51245
51262
  function branchFailure(target, expectedBranch, actualBranch) {
51246
51263
  return {
51247
51264
  code: "workspace_lease_branch_changed",
51248
- message: `The workspace branch changed from ${expectedBranch} to ${actualBranch} while the run was active. Restore ${expectedBranch} and start a new run.`,
51265
+ message: `The workspace branch changed from ${expectedBranch} to ${actualBranch || "detached HEAD"} while the run was active. Restore ${expectedBranch} and start a new run.`,
51249
51266
  workspacePath: target.workspacePath,
51250
51267
  expectedBranch,
51251
51268
  actualBranch
@@ -51261,7 +51278,12 @@ var WorkspaceRunLease = class _WorkspaceRunLease {
51261
51278
  for (const target of targets) {
51262
51279
  const normalizedTarget = { ...target, workspacePath: (0, import_node_path11.resolve)(target.workspacePath) };
51263
51280
  const identity = probe.snapshot(normalizedTarget.workspacePath);
51264
- if (!identity) return { lease: null, failure: unavailableFailure(normalizedTarget) };
51281
+ if (!identity) {
51282
+ return {
51283
+ lease: null,
51284
+ failure: identityFailure("workspace_lease_unavailable", normalizedTarget)
51285
+ };
51286
+ }
51265
51287
  if (normalizedTarget.expectedBranch && identity.branch !== normalizedTarget.expectedBranch) {
51266
51288
  return {
51267
51289
  lease: null,
@@ -51282,81 +51304,49 @@ var WorkspaceRunLease = class _WorkspaceRunLease {
51282
51304
  /**
51283
51305
  * Classify the lease state for the run monitor.
51284
51306
  *
51285
- * - `transient: true`a null snapshot while the workspace path still exists:
51286
- * the git probe timed out or failed transiently (OS throttling / IO
51287
- * contention), NOT a vanished checkout. The monitor should retry (require N
51288
- * consecutive transient failures) before declaring the workspace lost.
51289
- * - `transient: false` a definitive change: the path is genuinely missing
51290
- * (ENOENT), or the workspace/repository/worktree/branch identity changed.
51291
- * These are real and fail fast.
51307
+ * Checks workspace identity only path, repository, worktree. The branch is
51308
+ * deliberately not checked here: it is working state, not identity, and the supervised
51309
+ * process is a coding agent. A conflicted rebase leaves HEAD detached for as long as
51310
+ * the agent takes to resolve it, so any mid-run branch assertion kills that run. What
51311
+ * keeps work in the right place is the worktree's path and git-dir identity, both
51312
+ * fenced below, plus `assertExpectedBranch` in binding-switch-git.ts at apply time.
51313
+ * `capture()` still refuses to start a run on the wrong branch.
51314
+ *
51315
+ * `transient: true` means retryable — a git probe that timed out under OS throttling
51316
+ * while the path still exists. `transient: false` is definitive and fails fast.
51292
51317
  */
51293
51318
  verifyDetailed() {
51294
- for (const captured of this.captured) {
51295
- const current = this.probe.snapshot(captured.target.workspacePath);
51319
+ for (const { target, identity } of this.captured) {
51320
+ const current = this.probe.snapshot(target.workspacePath);
51296
51321
  if (!current) {
51297
- const pathGone = this.probe.pathExists?.(captured.target.workspacePath) === false;
51298
- return { failure: unavailableFailure(captured.target), transient: !pathGone };
51299
- }
51300
- if (current.workspaceIdentity !== captured.identity.workspaceIdentity) {
51322
+ const pathGone = this.probe.pathExists?.(target.workspacePath) === false;
51301
51323
  return {
51302
- failure: {
51303
- code: "workspace_lease_path_changed",
51304
- message: "The selected workspace folder changed while the run was active. The run stopped before continuing; choose the correct folder and start a new run.",
51305
- workspacePath: captured.target.workspacePath,
51306
- expectedBranch: captured.identity.branch,
51307
- actualBranch: current.branch
51308
- },
51309
- transient: false
51324
+ failure: identityFailure("workspace_lease_unavailable", target),
51325
+ transient: !pathGone
51310
51326
  };
51311
51327
  }
51312
- if (current.repositoryIdentity !== captured.identity.repositoryIdentity || current.worktreeIdentity !== captured.identity.worktreeIdentity) {
51328
+ if (current.workspaceIdentity !== identity.workspaceIdentity) {
51313
51329
  return {
51314
- failure: {
51315
- code: "workspace_lease_repository_changed",
51316
- message: "The workspace now points to a different repository or worktree. The run stopped before continuing; restore the original checkout and start a new run.",
51317
- workspacePath: captured.target.workspacePath,
51318
- expectedBranch: captured.identity.branch,
51319
- actualBranch: current.branch
51320
- },
51330
+ failure: identityFailure("workspace_lease_path_changed", target),
51321
51331
  transient: false
51322
51332
  };
51323
51333
  }
51324
- if (current.branch !== captured.identity.branch) {
51334
+ if (current.repositoryIdentity !== identity.repositoryIdentity || current.worktreeIdentity !== identity.worktreeIdentity) {
51325
51335
  return {
51326
- failure: branchFailure(captured.target, captured.identity.branch, current.branch),
51336
+ failure: identityFailure("workspace_lease_repository_changed", target),
51327
51337
  transient: false
51328
51338
  };
51329
51339
  }
51330
51340
  }
51331
51341
  return { failure: null, transient: false };
51332
51342
  }
51343
+ /**
51344
+ * Failure-only view of {@link verifyDetailed}. Kept as a thin delegation rather than a
51345
+ * second copy of the checks: the two implementations previously duplicated all four
51346
+ * comparisons and had to be edited in lockstep.
51347
+ */
51333
51348
  verify() {
51334
- for (const captured of this.captured) {
51335
- const current = this.probe.snapshot(captured.target.workspacePath);
51336
- if (!current) return unavailableFailure(captured.target);
51337
- if (current.workspaceIdentity !== captured.identity.workspaceIdentity) {
51338
- return {
51339
- code: "workspace_lease_path_changed",
51340
- message: "The selected workspace folder changed while the run was active. The run stopped before continuing; choose the correct folder and start a new run.",
51341
- workspacePath: captured.target.workspacePath,
51342
- expectedBranch: captured.identity.branch,
51343
- actualBranch: current.branch
51344
- };
51345
- }
51346
- if (current.repositoryIdentity !== captured.identity.repositoryIdentity || current.worktreeIdentity !== captured.identity.worktreeIdentity) {
51347
- return {
51348
- code: "workspace_lease_repository_changed",
51349
- message: "The workspace now points to a different repository or worktree. The run stopped before continuing; restore the original checkout and start a new run.",
51350
- workspacePath: captured.target.workspacePath,
51351
- expectedBranch: captured.identity.branch,
51352
- actualBranch: current.branch
51353
- };
51354
- }
51355
- if (current.branch !== captured.identity.branch) {
51356
- return branchFailure(captured.target, captured.identity.branch, current.branch);
51357
- }
51358
- }
51359
- return null;
51349
+ return this.verifyDetailed().failure;
51360
51350
  }
51361
51351
  };
51362
51352
  var FRESH_LEASE_MONITOR_STATE = {
@@ -53292,7 +53282,10 @@ var RuntimePresenter = class {
53292
53282
  }
53293
53283
  failWorkspaceLease(failure) {
53294
53284
  return this.failApplicationProblem({
53295
- code: "app.workspace.missing",
53285
+ // A branch change is not a missing workspace. Reporting both as
53286
+ // `app.workspace.missing` told the user to "choose or relocate the project
53287
+ // folder" for a folder that never moved.
53288
+ code: applicationCodeForWorkspaceLeaseFailure(failure.code),
53296
53289
  detail: failure.message,
53297
53290
  component: "agent-manager-workspace-lease",
53298
53291
  phase: "delivery"
@@ -54593,7 +54586,8 @@ async function startDaemon(args) {
54593
54586
  const runFailure = buildApplicationRunFailure({
54594
54587
  conversationId: payload.conversationId,
54595
54588
  runId: payload.runId,
54596
- code: "app.workspace.missing",
54589
+ // A run dispatched onto the wrong branch is also not a missing workspace.
54590
+ code: applicationCodeForWorkspaceLeaseFailure(failure.code),
54597
54591
  detail: failure.message,
54598
54592
  component: "agent-manager-workspace-lease",
54599
54593
  phase: "dispatch"
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "@aiden-ade/sandbox-agent",
3
- "deprecated": "Use @alan-ai-hq/agent-manager instead.",
4
- "version": "0.1.54",
3
+ "version": "0.1.55",
5
4
  "type": "module",
6
5
  "description": "Alan agent runtime — cloud sandbox and local daemon (alan-agent CLI)",
7
6
  "bin": {
@@ -13,10 +12,24 @@
13
12
  "publishConfig": {
14
13
  "access": "public"
15
14
  },
15
+ "dependencies": {
16
+ "@modelcontextprotocol/sdk": "^1.29.0",
17
+ "smol-toml": "^1.6.1"
18
+ },
19
+ "devDependencies": {
20
+ "socket.io-client": "^4.8.0",
21
+ "socket.io": "^4.8.0",
22
+ "@types/node": "^22.0.0",
23
+ "tsup": "^8.5.1",
24
+ "tsx": "^4.19.0",
25
+ "typescript": "~5.9.3",
26
+ "@alan-ai/shared": "0.1.0",
27
+ "@alan-ai/agent-core": "0.1.0"
28
+ },
29
+ "deprecated": "Use @alan-ai-hq/agent-manager instead.",
16
30
  "scripts": {
17
31
  "build": "tsup",
18
32
  "dev": "tsx src/index.ts",
19
- "prepack": "pnpm build",
20
33
  "lint": "biome check .",
21
34
  "lint:fix": "biome check --write .",
22
35
  "format": "biome format --write .",
@@ -26,19 +39,5 @@
26
39
  "type-check": "tsc --noEmit",
27
40
  "publish:npm": "node ../../scripts/publish-agent-manager.mjs",
28
41
  "publish:npm:legacy": "node ../../scripts/publish-agent-manager.mjs --legacy-only"
29
- },
30
- "dependencies": {
31
- "@modelcontextprotocol/sdk": "^1.29.0",
32
- "smol-toml": "^1.6.1"
33
- },
34
- "devDependencies": {
35
- "@alan-ai/agent-core": "workspace:*",
36
- "@alan-ai/shared": "workspace:*",
37
- "socket.io-client": "^4.8.0",
38
- "socket.io": "^4.8.0",
39
- "@types/node": "^22.0.0",
40
- "tsup": "^8.5.1",
41
- "tsx": "^4.19.0",
42
- "typescript": "~5.9.3"
43
42
  }
44
- }
43
+ }