@aiden-ade/sandbox-agent 0.1.75 → 0.1.77

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 +174 -46
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -15231,7 +15231,7 @@ function describeError(error61) {
15231
15231
  }
15232
15232
 
15233
15233
  // src/version.ts
15234
- var AGENT_VERSION = "0.1.75";
15234
+ var AGENT_VERSION = "0.1.77";
15235
15235
 
15236
15236
  // src/daemon-worktree.ts
15237
15237
  var import_node_child_process3 = require("child_process");
@@ -37172,6 +37172,13 @@ var ACTIVE_AGENT_RUN_STATUSES = [
37172
37172
  ];
37173
37173
  var STOPPABLE_AGENT_RUN_STATUSES = [...ACTIVE_AGENT_RUN_STATUSES, "paused"];
37174
37174
 
37175
+ // ../shared/dist/agent/types.js
37176
+ function resolveEffectiveBackendKind(backendKind) {
37177
+ if (backendKind === "codex")
37178
+ return "codex_app_server";
37179
+ return backendKind || "claude_cli";
37180
+ }
37181
+
37175
37182
  // ../shared/dist/effort.js
37176
37183
  var EFFORT_LEVELS = ["minimal", "low", "medium", "high", "xhigh", "max", "ultra"];
37177
37184
  var CLAUDE_EFFORT_LEVELS = [
@@ -38415,7 +38422,12 @@ function findManagedAlanServer(servers) {
38415
38422
  }
38416
38423
  return null;
38417
38424
  }
38418
- var RETIRED_SESSION_HEADER_NAMES = ["x-conversation-id", "x-team-id", "x-allowed-tools"];
38425
+ var RETIRED_SESSION_HEADER_NAMES = [
38426
+ "x-conversation-id",
38427
+ "x-team-id",
38428
+ "x-allowed-tools",
38429
+ "authorization"
38430
+ ];
38419
38431
  function buildSessionHeaders(input2) {
38420
38432
  const headers = {};
38421
38433
  for (const [key, value2] of Object.entries(input2.runHeaders)) {
@@ -41648,7 +41660,7 @@ function createClaudeCliBackend(command = "claude", defaultArgs = []) {
41648
41660
  } else if (resumeId && context.config.systemPromptAppend?.trim()) {
41649
41661
  args.push("--append-system-prompt", context.config.systemPromptAppend.trim());
41650
41662
  }
41651
- if (context.config.teamId?.trim() && await cliSupportsFlag(command, "--approve-mcps", context.env)) {
41663
+ if (context.config.alanMcp && await cliSupportsFlag(command, "--approve-mcps", context.env)) {
41652
41664
  args.push("--approve-mcps");
41653
41665
  }
41654
41666
  const baseModel = collapseModelIdToBase(context.config.selectedModel?.trim() || "");
@@ -42384,7 +42396,15 @@ function emitCodexFileChanges(context, state, itemId, changes) {
42384
42396
  const toolName = kind === "add" ? "write_file" : "edit_file";
42385
42397
  const toolId = changes.length > 1 ? `${itemId}:${index}` : itemId;
42386
42398
  trackCodexStreamedToolId(state, toolId);
42387
- void context.presenter.onToolUse(toolName, { file_path: filePath, kind }, toolId);
42399
+ const diffMetadata = {};
42400
+ for (const key of ["additions", "deletions", "patch", "diff"]) {
42401
+ if (record2[key] !== void 0) diffMetadata[key] = record2[key];
42402
+ }
42403
+ void context.presenter.onToolUse(
42404
+ toolName,
42405
+ { file_path: filePath, kind, ...diffMetadata },
42406
+ toolId
42407
+ );
42388
42408
  void context.presenter.onToolResult?.(toolId, `${kind} ${filePath}`);
42389
42409
  });
42390
42410
  }
@@ -43789,7 +43809,7 @@ function createCursorAgentCliBackend(command = "cursor-agent", defaultArgs = [])
43789
43809
  context.config.images,
43790
43810
  context.cwd
43791
43811
  );
43792
- const approveMcps = context.config.teamId?.trim() ? await cliSupportsFlag(command, "--approve-mcps", context.env) : false;
43812
+ const approveMcps = context.config.alanMcp ? await cliSupportsFlag(command, "--approve-mcps", context.env) : false;
43793
43813
  try {
43794
43814
  return await createGenericCliBackend({
43795
43815
  kind: "cursor_agent_cli",
@@ -46246,10 +46266,6 @@ ${ctx.promptText}` : ctx.promptText;
46246
46266
  }
46247
46267
  var DROID_DEFAULT_MODEL = "claude-opus-4-8";
46248
46268
  var AGENT_ACTIVITY_HEARTBEAT_MS = 1e4;
46249
- function normalizeBackendKind(kind) {
46250
- if (kind === "codex") return "codex_app_server";
46251
- return kind || "claude_cli";
46252
- }
46253
46269
  function firstCatalogModelId(backendKind) {
46254
46270
  const fromPicker = catalogModelsForProvider(backendKind, PROVIDER_MODELS[backendKind]).find(
46255
46271
  (model) => model.id.trim()
@@ -46496,7 +46512,7 @@ var BaseMachineAgent = class _BaseMachineAgent {
46496
46512
  return message.includes("aborted") || message.includes("interrupted") || message.includes("cancelled") || message.includes("canceled");
46497
46513
  }
46498
46514
  resolveBackendKind(config2) {
46499
- return normalizeBackendKind(this.runtime.backendKind || config2.backendKind);
46515
+ return resolveEffectiveBackendKind(this.runtime.backendKind || config2.backendKind);
46500
46516
  }
46501
46517
  getDefaultSupportTier(backendKind) {
46502
46518
  switch (backendKind) {
@@ -49442,7 +49458,7 @@ async function discoverProviderModelDetails(provider, executable, env) {
49442
49458
  }
49443
49459
 
49444
49460
  // src/daemon-provider-scan.ts
49445
- function normalizeBackendKind2(backendKind) {
49461
+ function normalizeBackendKind(backendKind) {
49446
49462
  if (backendKind === "codex") return "codex_app_server";
49447
49463
  return backendKind;
49448
49464
  }
@@ -55672,7 +55688,7 @@ function removeAlanFromJsonConfig(path2, existingContent) {
55672
55688
  }
55673
55689
  return JSON.stringify(config2);
55674
55690
  }
55675
- async function unregisterAlanMcp(backendKind, home = (0, import_node_os8.homedir)()) {
55691
+ async function unregisterAlanMcp(backendKind, home = (0, import_node_os8.homedir)(), options = {}) {
55676
55692
  const removedPaths = [];
55677
55693
  const errors = [];
55678
55694
  const files = alanMcpConfigFilesForBackend(backendKind, {}, home);
@@ -55681,6 +55697,12 @@ async function unregisterAlanMcp(backendKind, home = (0, import_node_os8.homedir
55681
55697
  const releaseLock = await waitForConfigLock(`${file2.path}.alan-lock`);
55682
55698
  try {
55683
55699
  const current = (0, import_node_fs14.readFileSync)(file2.path, "utf8");
55700
+ if (options.onlyIfRegistration && !registrationsMatch(
55701
+ parseAlanMcpRegistration(file2.path, current),
55702
+ options.onlyIfRegistration
55703
+ )) {
55704
+ continue;
55705
+ }
55684
55706
  let next;
55685
55707
  if (file2.path.endsWith(".toml")) {
55686
55708
  const stripped = stripCodexAlanMcpSection(current);
@@ -55737,7 +55759,9 @@ function hasUsableRegistrationCredential(headers) {
55737
55759
  return Boolean(normalized.get("x-alan-run-reference") || normalized.get("authorization"));
55738
55760
  }
55739
55761
  function readAlanMcpRegistration(path2) {
55740
- const content = (0, import_node_fs14.readFileSync)(path2, "utf8");
55762
+ return parseAlanMcpRegistration(path2, (0, import_node_fs14.readFileSync)(path2, "utf8"));
55763
+ }
55764
+ function parseAlanMcpRegistration(path2, content) {
55741
55765
  if (path2.endsWith(".toml")) {
55742
55766
  try {
55743
55767
  const parsed = parse5(content);
@@ -72923,7 +72947,7 @@ async function handleAgentExecute(ctx, payload) {
72923
72947
  });
72924
72948
  return;
72925
72949
  }
72926
- const backendKind = normalizeBackendKind2(payload.backendKind);
72950
+ const backendKind = normalizeBackendKind(payload.backendKind);
72927
72951
  let runtimeCommand = resolveBackendRuntimeCommand(backendKind ?? payload.backendKind);
72928
72952
  if (!runtimeCommand && backendKind) {
72929
72953
  runtimeCommand = revalidateBackendRuntimeCommand(backendKind);
@@ -73108,12 +73132,13 @@ async function handleAgentExecute(ctx, payload) {
73108
73132
  });
73109
73133
  return;
73110
73134
  }
73135
+ const registrationBackendKind = resolveEffectiveBackendKind(payload.backendKind);
73111
73136
  const authPromise = backendKind && runtimeCommand && !payload.providerApiKey ? preflightProviderAuth({
73112
73137
  backendKind,
73113
73138
  executable: runtimeCommand,
73114
73139
  env: getDaemonCliEnvironment()
73115
73140
  }).catch(() => ({ status: "unknown" })) : Promise.resolve({ status: "unknown" });
73116
- const mcpPromise = backendKind ? prepareAlanMcpForRun(backendKind, alanMcp, {
73141
+ const mcpPromise = prepareAlanMcpForRun(registrationBackendKind, alanMcp, {
73117
73142
  // Observe mode resolves after the run has already been accepted, so
73118
73143
  // the verdict is logged here rather than folded into the result.
73119
73144
  onObservedResult: (failure) => {
@@ -73124,7 +73149,7 @@ async function handleAgentExecute(ctx, payload) {
73124
73149
  stage: failure.stage
73125
73150
  });
73126
73151
  }
73127
- }) : Promise.resolve(null);
73152
+ });
73128
73153
  const skillTaskPromise = prepareSkillInvocationTask({
73129
73154
  manager: runtimeSkillManager,
73130
73155
  runtimeId,
@@ -73160,7 +73185,7 @@ async function handleAgentExecute(ctx, payload) {
73160
73185
  });
73161
73186
  return;
73162
73187
  }
73163
- if (backendKind && mcpOutcome && !mcpOutcome.ok) {
73188
+ if (!mcpOutcome.ok) {
73164
73189
  pendingRunStarts.delete(payload.runId);
73165
73190
  releaseRunStart();
73166
73191
  const readinessCode = mcpOutcome.code;
@@ -73177,7 +73202,7 @@ async function handleAgentExecute(ctx, payload) {
73177
73202
  });
73178
73203
  return;
73179
73204
  }
73180
- if (backendKind && alanMcp && mcpOutcome && mcpOutcome.ok && "paths" in mcpOutcome) {
73205
+ if ("paths" in mcpOutcome) {
73181
73206
  pushLog(
73182
73207
  `mcp-ready run=${payload.runId} verification=${"verification" in mcpOutcome ? mcpOutcome.verification : "file"}`
73183
73208
  );
@@ -73346,10 +73371,8 @@ async function handleAgentExecute(ctx, payload) {
73346
73371
  workspaceLease: workspaceLeaseCapture.lease
73347
73372
  });
73348
73373
  pendingRunStarts.delete(payload.runId);
73349
- if (payload.alanMcp && backendKind) {
73350
- alanMcpRegisteredRuns.add(payload.runId);
73351
- alanMcpRegisteredBackends.add(backendKind);
73352
- }
73374
+ alanMcpRegisteredRuns.set(payload.runId, alanMcp);
73375
+ alanMcpRegisteredBackends.add(registrationBackendKind);
73353
73376
  void agent.run({
73354
73377
  task: preparedTask,
73355
73378
  maxIterations: payload.maxIterations ?? 50,
@@ -74766,6 +74789,15 @@ var SKILL_PROVIDER_SOURCE_DEFINITIONS = [
74766
74789
  userDirectories: [".cursor/skills"],
74767
74790
  repositoryDirectories: [".cursor/skills"]
74768
74791
  },
74792
+ {
74793
+ // Canonical kind, not the `codex_cli` / `codex` aliases: LEGACY_PROVIDER_KIND_MAP
74794
+ // normalizes both to this, and the enabled-provider set is built from
74795
+ // normalized kinds, so a source declared under an alias never matches.
74796
+ providerKind: "codex_app_server",
74797
+ label: "Codex skills",
74798
+ userDirectories: [".codex/skills"],
74799
+ repositoryDirectories: [".codex/skills"]
74800
+ },
74769
74801
  {
74770
74802
  providerKind: "copilot_cli",
74771
74803
  label: "Copilot skills",
@@ -74807,8 +74839,6 @@ function providerKindsForUserDirectory(relativeDirectory) {
74807
74839
  const providers = SKILL_PROVIDER_SOURCE_DEFINITIONS.flatMap((definition) => definition.userDirectories.includes(normalized) ? [definition.providerKind] : []);
74808
74840
  if (providers.length > 0)
74809
74841
  return providers;
74810
- if (normalized === ".codex/skills")
74811
- return ["cursor_agent_cli"];
74812
74842
  if (normalized === ".gemini/config/skills")
74813
74843
  return [];
74814
74844
  return void 0;
@@ -74844,6 +74874,11 @@ path = "~/.cursor/skills"
74844
74874
  label = "Cursor skills"
74845
74875
  providers = ["cursor_agent_cli"]
74846
74876
 
74877
+ [[skills.sources]]
74878
+ path = "~/.codex/skills"
74879
+ label = "Codex skills"
74880
+ providers = ["codex_app_server"]
74881
+
74847
74882
  [[skills.sources]]
74848
74883
  path = "~/.copilot/skills"
74849
74884
  label = "Copilot skills"
@@ -74864,12 +74899,15 @@ var LocalSkillSource = class {
74864
74899
  const candidates = [];
74865
74900
  const visitedDirectories = /* @__PURE__ */ new Set();
74866
74901
  let incompleteRoot = false;
74867
- for (const resolvedRoot of resolveScanRoots(input2.roots, input2.enabledProviderKinds ?? [])) {
74902
+ const resolvedRoots = resolveScanRoots(input2.roots, input2.enabledProviderKinds ?? []);
74903
+ const declaredRoots = await canonicalDirectories(resolvedRoots.map((root) => root.directory));
74904
+ for (const resolvedRoot of resolvedRoots) {
74868
74905
  const rootResult = await this.scanRoot(
74869
74906
  resolvedRoot,
74870
74907
  visitedDirectories,
74871
74908
  input2.ignoredPaths ?? [],
74872
- input2.mode
74909
+ input2.mode,
74910
+ declaredRoots
74873
74911
  );
74874
74912
  candidates.push(...rootResult.candidates);
74875
74913
  diagnostics.push(...rootResult.diagnostics);
@@ -74924,7 +74962,63 @@ var LocalSkillSource = class {
74924
74962
  if (cached2?.contentHash === expectedContentHash) return cached2;
74925
74963
  return inspectSkillPackage(absolutePath, { expectedName: null });
74926
74964
  }
74927
- async scanRoot(resolvedRoot, visitedDirectories, ignoredPaths, mode) {
74965
+ /**
74966
+ * The root read as one package, or null when it does not hold a SKILL.md.
74967
+ *
74968
+ * `expectedName` is null here on purpose. A package inside a library must be
74969
+ * named for its directory, but a root is whatever the person called the
74970
+ * folder, so that rule would reject it with DIRECTORY_NAME_MISMATCH.
74971
+ */
74972
+ async scanRootAsPackage(resolvedRoot, ignoredPaths, mode) {
74973
+ const directory = resolvedRoot.directory;
74974
+ if (!await pathExists((0, import_node_path16.join)(directory, "SKILL.md"))) return null;
74975
+ const canonicalRoot = await (0, import_promises2.realpath)(directory).catch(() => directory);
74976
+ const name = import_node_path16.default.basename(canonicalRoot);
74977
+ try {
74978
+ const fingerprint = await fingerprintPackage(canonicalRoot);
74979
+ const ignoreSignature = JSON.stringify(ignoredPaths);
74980
+ const cached2 = this.inspectionCache.get(canonicalRoot);
74981
+ const inspected = mode === "incremental" && cached2?.fingerprint === fingerprint && cached2.ignoreSignature === ignoreSignature ? cached2.inspected : await inspectSkillPackage(canonicalRoot, { ignoredPaths, expectedName: null });
74982
+ this.inspectionCache.set(canonicalRoot, { fingerprint, ignoreSignature, inspected });
74983
+ return {
74984
+ candidates: [
74985
+ {
74986
+ absolutePath: canonicalRoot,
74987
+ rootPath: canonicalRoot,
74988
+ order: `${resolvedRoot.order}:${name}`,
74989
+ candidate: {
74990
+ localKey: createLocalKey(resolvedRoot.root, inspected.metadata.name),
74991
+ name: inspected.metadata.name,
74992
+ description: inspected.metadata.description,
74993
+ contentHash: inspected.contentHash,
74994
+ fileCount: inspected.fileCount,
74995
+ totalBytes: inspected.totalBytes,
74996
+ origin: candidateOrigin(resolvedRoot.root),
74997
+ diagnostics: inspected.diagnostics
74998
+ }
74999
+ }
75000
+ ],
75001
+ diagnostics: [],
75002
+ incomplete: false
75003
+ };
75004
+ } catch (error61) {
75005
+ return {
75006
+ candidates: [],
75007
+ diagnostics: [
75008
+ {
75009
+ code: "INVALID_SKILL",
75010
+ message: error61 instanceof Error ? error61.message : String(error61),
75011
+ rootLabel: resolvedRoot.root.label,
75012
+ localKey: createLocalKey(resolvedRoot.root, name)
75013
+ }
75014
+ ],
75015
+ incomplete: false
75016
+ };
75017
+ }
75018
+ }
75019
+ async scanRoot(resolvedRoot, visitedDirectories, ignoredPaths, mode, declaredRoots) {
75020
+ const rootPackage = await this.scanRootAsPackage(resolvedRoot, ignoredPaths, mode);
75021
+ if (rootPackage) return rootPackage;
74928
75022
  let entries;
74929
75023
  try {
74930
75024
  entries = await (0, import_promises2.readdir)(resolvedRoot.directory, { withFileTypes: true });
@@ -74959,10 +75053,11 @@ var LocalSkillSource = class {
74959
75053
  });
74960
75054
  continue;
74961
75055
  }
74962
- if (!isWithinDirectory(canonicalRoot, canonicalPath)) {
75056
+ const roots = declaredRoots.length > 0 ? declaredRoots : [canonicalRoot];
75057
+ if (!roots.some((root) => isWithinDirectory(root, canonicalPath))) {
74963
75058
  diagnostics.push({
74964
75059
  code: "SOURCE_OUTSIDE_DECLARED_ROOT",
74965
- message: `Skill ${entry.name} resolves outside ${resolvedRoot.root.label}`,
75060
+ message: `Skill ${entry.name} resolves outside every declared Skill source`,
74966
75061
  rootLabel: resolvedRoot.root.label
74967
75062
  });
74968
75063
  continue;
@@ -74980,6 +75075,7 @@ var LocalSkillSource = class {
74980
75075
  const localKey = createLocalKey(resolvedRoot.root, entry.name);
74981
75076
  candidates.push({
74982
75077
  absolutePath: canonicalPath,
75078
+ rootPath: canonicalRoot,
74983
75079
  order: `${resolvedRoot.order}:${entry.name}`,
74984
75080
  candidate: {
74985
75081
  localKey,
@@ -75022,6 +75118,21 @@ async function fingerprintPackage(root) {
75022
75118
  }
75023
75119
  }
75024
75120
  }
75121
+ var CODEX_SOURCE_LABEL = "Codex skills";
75122
+ var STALE_CODEX_LABEL = "Legacy Cursor-compatible skills";
75123
+ var STALE_CODEX_PROVIDER = "cursor_agent_cli";
75124
+ function staleCodexDeclaration(relativeDirectory, label, providerKinds) {
75125
+ const normalized = relativeDirectory.replaceAll("\\", "/").replace(/^\.\//, "");
75126
+ if (normalized !== ".codex/skills") return false;
75127
+ const ownedByCursor = providerKinds !== void 0 && providerKinds.length === 1 && providerKinds[0] === STALE_CODEX_PROVIDER;
75128
+ return ownedByCursor || label === STALE_CODEX_LABEL;
75129
+ }
75130
+ async function canonicalDirectories(directories) {
75131
+ const canonical = await Promise.all(
75132
+ directories.map((directory) => (0, import_promises2.realpath)(directory).catch(() => directory))
75133
+ );
75134
+ return [...new Set(canonical)];
75135
+ }
75025
75136
  function isWithinDirectory(parent, candidate) {
75026
75137
  const path2 = (0, import_node_path16.relative)(parent, candidate);
75027
75138
  return path2 !== ".." && !path2.startsWith(`..${import_node_path16.sep}`) && !(0, import_node_path16.isAbsolute)(path2);
@@ -75119,12 +75230,14 @@ function parseSkillSourceConfig(content, homeDirectory) {
75119
75230
  );
75120
75231
  const relativeDirectory = import_node_path16.default.relative(homeDirectory, sourcePath);
75121
75232
  const inferredProviders = providerKindsForUserDirectory(relativeDirectory);
75233
+ const declaredProviders = value2.providers === void 0 ? inferredProviders : [...new Set(explicitProviders.map((provider) => provider.trim()).filter(Boolean))];
75234
+ const stale = staleCodexDeclaration(relativeDirectory, label, declaredProviders);
75122
75235
  return {
75123
75236
  declarationId,
75124
75237
  path: sourcePath,
75125
- label,
75238
+ label: stale ? CODEX_SOURCE_LABEL : label,
75126
75239
  precedence: index,
75127
- providerKinds: value2.providers === void 0 ? inferredProviders : [...new Set(explicitProviders.map((provider) => provider.trim()).filter(Boolean))]
75240
+ providerKinds: stale ? inferredProviders : declaredProviders
75128
75241
  };
75129
75242
  });
75130
75243
  const duplicateId = sources.find(
@@ -75219,12 +75332,23 @@ function hashInventory(candidates) {
75219
75332
  return `sha256:${hash2.digest("hex")}`;
75220
75333
  }
75221
75334
  function deduplicateCandidatesByContent(candidates) {
75222
- const seen = /* @__PURE__ */ new Set();
75223
- return candidates.filter(({ candidate }) => {
75224
- if (seen.has(candidate.contentHash)) return false;
75225
- seen.add(candidate.contentHash);
75335
+ const bestByContent = /* @__PURE__ */ new Map();
75336
+ for (const located of candidates) {
75337
+ const existing = bestByContent.get(located.candidate.contentHash);
75338
+ if (!existing || located.rootPath.length > existing.rootPath.length) {
75339
+ bestByContent.set(located.candidate.contentHash, located);
75340
+ }
75341
+ }
75342
+ const winners = new Set(bestByContent.values());
75343
+ return candidates.filter((located) => winners.has(located));
75344
+ }
75345
+ async function pathExists(candidate) {
75346
+ try {
75347
+ await (0, import_promises2.access)(candidate);
75226
75348
  return true;
75227
- });
75349
+ } catch {
75350
+ return false;
75351
+ }
75228
75352
  }
75229
75353
  async function hasManagedMarker(directory) {
75230
75354
  try {
@@ -76060,7 +76184,7 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76060
76184
  }
76061
76185
  async adoptLegacyProjection(entry) {
76062
76186
  const destination = (0, import_node_path19.join)(this.managedSkillsDirectory, entry.runtimeDirectory);
76063
- if (await pathExists(destination)) return;
76187
+ if (await pathExists2(destination)) return;
76064
76188
  const manifest = await readLegacyManifest(this.legacyManifestPath);
76065
76189
  const legacy = manifest?.skills[entry.slug];
76066
76190
  if (!legacy) return;
@@ -76150,7 +76274,7 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76150
76274
  if (!await packageMatches(pending, entry.contentHash)) {
76151
76275
  throw new Error("Pending managed Skill projection failed content verification");
76152
76276
  }
76153
- if (await pathExists(destination)) {
76277
+ if (await pathExists2(destination)) {
76154
76278
  await (0, import_promises5.rename)(destination, backup);
76155
76279
  movedExisting = true;
76156
76280
  }
@@ -76172,7 +76296,7 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76172
76296
  } catch (error61) {
76173
76297
  if (!completed && installedPending) {
76174
76298
  await (0, import_promises5.rm)(destination, { recursive: true, force: true });
76175
- if (movedExisting && await pathExists(backup)) await (0, import_promises5.rename)(backup, destination);
76299
+ if (movedExisting && await pathExists2(backup)) await (0, import_promises5.rename)(backup, destination);
76176
76300
  }
76177
76301
  throw error61;
76178
76302
  } finally {
@@ -76184,7 +76308,7 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76184
76308
  }
76185
76309
  async requireReplaceable(entry) {
76186
76310
  const destination = (0, import_node_path19.join)(this.managedSkillsDirectory, entry.runtimeDirectory);
76187
- if (!await pathExists(destination)) return;
76311
+ if (!await pathExists2(destination)) return;
76188
76312
  const marker = await readMarker(destination);
76189
76313
  if (!marker) throw unmanagedPathConflict(entry.runtimeDirectory);
76190
76314
  if (marker.skillId === entry.skillId && marker.versionId === entry.versionId && marker.contentHash === entry.contentHash && await packageMatches(destination, entry.contentHash)) {
@@ -76203,7 +76327,7 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76203
76327
  const destination = (0, import_node_path19.join)(this.managedSkillsDirectory, runtimeDirectory);
76204
76328
  const compatibility = (0, import_node_path19.join)(this.compatibilitySkillsDirectory, runtimeDirectory);
76205
76329
  const marker = await readMarker(destination);
76206
- if (!await pathExists(destination)) continue;
76330
+ if (!await pathExists2(destination)) continue;
76207
76331
  if (marker && markerMatchesProjection(marker, recorded)) {
76208
76332
  if (!await removeCompatibilityProjection(compatibility, destination, recorded)) {
76209
76333
  failures.push({
@@ -76233,7 +76357,7 @@ var RuntimeSkillManager = class _RuntimeSkillManager {
76233
76357
  async ensureCompatibilityProjection(entry, canonicalDirectory) {
76234
76358
  await (0, import_promises5.mkdir)(this.compatibilitySkillsDirectory, { recursive: true, mode: 448 });
76235
76359
  const destination = (0, import_node_path19.join)(this.compatibilitySkillsDirectory, entry.runtimeDirectory);
76236
- if (await pathExists(destination)) {
76360
+ if (await pathExists2(destination)) {
76237
76361
  if (await compatibilityProjectionMatches(destination, canonicalDirectory, entry)) return;
76238
76362
  throw unmanagedCompatibilityConflict(entry.runtimeDirectory);
76239
76363
  }
@@ -76350,7 +76474,7 @@ async function compatibilityProjectionMatches(destination, canonicalDirectory, e
76350
76474
  return marker?.canonicalDirectory === canonicalDirectory && marker.skillId === entry.skillId && marker.versionId === entry.versionId && marker.contentHash === entry.contentHash && await packageMatches(destination, entry.contentHash);
76351
76475
  }
76352
76476
  async function removeCompatibilityProjection(destination, canonicalDirectory, projection) {
76353
- if (!await pathExists(destination)) return true;
76477
+ if (!await pathExists2(destination)) return true;
76354
76478
  const metadata = await (0, import_promises5.lstat)(destination);
76355
76479
  if (metadata.isSymbolicLink()) {
76356
76480
  const target = await (0, import_promises5.readlink)(destination);
@@ -76437,7 +76561,7 @@ function localRasterMediaType(path2) {
76437
76561
  function localTextMediaType(path2) {
76438
76562
  return path2.toLowerCase().endsWith(".md") ? "text/markdown; charset=utf-8" : "text/plain; charset=utf-8";
76439
76563
  }
76440
- async function pathExists(path2) {
76564
+ async function pathExists2(path2) {
76441
76565
  try {
76442
76566
  await (0, import_promises5.lstat)(path2);
76443
76567
  return true;
@@ -76680,17 +76804,21 @@ async function startDaemon(args) {
76680
76804
  if (sleepInhibitor.backendNames().length > 0) {
76681
76805
  pushLog(`sleep-inhibitor backends=${sleepInhibitor.backendNames().join(",")}`);
76682
76806
  }
76683
- const alanMcpRegisteredRuns = /* @__PURE__ */ new Set();
76807
+ const alanMcpRegisteredRuns = /* @__PURE__ */ new Map();
76684
76808
  const alanMcpRegisteredBackends = /* @__PURE__ */ new Set();
76685
76809
  const finalizeAlanMcpForRun = (runId) => {
76810
+ const registration = alanMcpRegisteredRuns.get(runId);
76686
76811
  if (!alanMcpRegisteredRuns.delete(runId)) return;
76687
76812
  if (alanMcpRegisteredRuns.size > 0) return;
76688
76813
  const backends = [...alanMcpRegisteredBackends];
76689
76814
  alanMcpRegisteredBackends.clear();
76690
76815
  void (async () => {
76691
76816
  for (const backend of backends) {
76817
+ if (alanMcpRegisteredRuns.size > 0) return;
76692
76818
  try {
76693
- const { removedPaths } = await unregisterAlanMcp(backend);
76819
+ const { removedPaths } = await unregisterAlanMcp(backend, void 0, {
76820
+ onlyIfRegistration: registration
76821
+ });
76694
76822
  if (removedPaths.length > 0) {
76695
76823
  pushLog(`mcp-unregistered backend=${backend} run=${runId}`);
76696
76824
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aiden-ade/sandbox-agent",
3
- "version": "0.1.75",
3
+ "version": "0.1.77",
4
4
  "type": "module",
5
5
  "description": "Alan agent runtime — cloud sandbox and local daemon (alan-agent CLI)",
6
6
  "bin": {