@aiden-ade/sandbox-agent 0.1.54 → 0.1.56

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 +509 -282
  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 },
@@ -17526,7 +17536,7 @@ function collapseModelIdToBase(modelId) {
17526
17536
  return parsed.baseId;
17527
17537
  }
17528
17538
 
17529
- // ../shared/dist/types/frontend.js
17539
+ // ../shared/dist/agent-selection/catalog/models/claude.js
17530
17540
  var CLAUDE_5_EFFORT_LEVELS = CLAUDE_EFFORT_LEVELS;
17531
17541
  var AVAILABLE_MODELS = [
17532
17542
  {
@@ -17567,7 +17577,9 @@ var CLAUDE_CLI_SEED_MODELS = [
17567
17577
  capabilities: { contextWindows: [], effortLevels: [] }
17568
17578
  }
17569
17579
  ];
17570
- var ANTIGRAVITY_CLI_SEED_MODELS = [{ id: "", name: "CLI default" }];
17580
+
17581
+ // ../shared/dist/agent-selection/catalog/models/cursor.js
17582
+ var CLAUDE_5_EFFORT_LEVELS2 = CLAUDE_EFFORT_LEVELS;
17571
17583
  var CURSOR_AGENT_MODELS = [
17572
17584
  { id: "auto", name: "Auto" },
17573
17585
  { id: "composer-2.5-fast", name: "Composer 2.5 Fast" },
@@ -17577,22 +17589,22 @@ var CURSOR_AGENT_MODELS = [
17577
17589
  {
17578
17590
  id: "claude-opus-4-8",
17579
17591
  name: "Opus 4.8 1M",
17580
- capabilities: { contextWindows: ["1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS }
17592
+ capabilities: { contextWindows: ["1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS2 }
17581
17593
  },
17582
17594
  {
17583
17595
  id: "claude-opus-4-8-thinking",
17584
17596
  name: "Opus 4.8 1M Thinking",
17585
- capabilities: { contextWindows: ["1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS }
17597
+ capabilities: { contextWindows: ["1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS2 }
17586
17598
  },
17587
17599
  {
17588
17600
  id: "claude-sonnet-5",
17589
17601
  name: "Sonnet 5",
17590
- capabilities: { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS }
17602
+ capabilities: { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS2 }
17591
17603
  },
17592
17604
  {
17593
17605
  id: "claude-sonnet-5-thinking",
17594
17606
  name: "Sonnet 5 Thinking",
17595
- capabilities: { contextWindows: ["1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS }
17607
+ capabilities: { contextWindows: ["1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS2 }
17596
17608
  },
17597
17609
  { id: "claude-4.6-sonnet", name: "Sonnet 4.6 1M" },
17598
17610
  {
@@ -17606,12 +17618,12 @@ var CURSOR_AGENT_MODELS = [
17606
17618
  {
17607
17619
  id: "claude-fable-5",
17608
17620
  name: "Fable 5 1M",
17609
- capabilities: { contextWindows: ["1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS }
17621
+ capabilities: { contextWindows: ["1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS2 }
17610
17622
  },
17611
17623
  {
17612
17624
  id: "claude-fable-5-thinking",
17613
17625
  name: "Fable 5 1M Thinking",
17614
- capabilities: { contextWindows: ["1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS }
17626
+ capabilities: { contextWindows: ["1m"], effortLevels: CLAUDE_5_EFFORT_LEVELS2 }
17615
17627
  },
17616
17628
  {
17617
17629
  id: "gpt-5.3-codex",
@@ -17644,10 +17656,173 @@ var CURSOR_AGENT_MODELS = [
17644
17656
  { id: "gemini-3-flash", name: "Gemini 3 Flash" },
17645
17657
  { id: "grok-4.5-fast", name: "Grok 4.5 Fast" }
17646
17658
  ];
17647
- var GROK_CLI_MODELS = [
17648
- { id: "grok-4.5", name: "Grok 4.5" },
17649
- { id: "grok-composer-2.5-fast", name: "Composer 2.5 Fast" }
17650
- ];
17659
+ function getCursorModelCollapseKey(modelId) {
17660
+ const parsed = parseModelEffortSuffix(modelId);
17661
+ if (parsed.fast && !parsed.effort)
17662
+ return modelId.trim();
17663
+ return parsed.baseId;
17664
+ }
17665
+ function getCursorCatalogCollapseKey(modelId) {
17666
+ const trimmed = modelId.trim();
17667
+ if (trimmed.endsWith("-medium-thinking")) {
17668
+ return trimmed.slice(0, -"-medium-thinking".length);
17669
+ }
17670
+ let key = getCursorModelCollapseKey(trimmed);
17671
+ if (key.endsWith("-thinking")) {
17672
+ key = getCursorModelCollapseKey(key.slice(0, -"-thinking".length));
17673
+ }
17674
+ return key;
17675
+ }
17676
+ function mergeContextWindows(existing, discovered) {
17677
+ const merged = /* @__PURE__ */ new Set([...existing ?? [], ...discovered ?? []]);
17678
+ return Array.from(merged);
17679
+ }
17680
+ function mergeModelCapabilities(preferred, other) {
17681
+ const contextWindows = mergeContextWindows(preferred.capabilities?.contextWindows, other.capabilities?.contextWindows);
17682
+ const effortLevels = mergeEffortLevels(preferred.capabilities?.effortLevels, new Set(other.capabilities?.effortLevels ?? []));
17683
+ if (contextWindows.length === 0 && effortLevels.length === 0)
17684
+ return preferred;
17685
+ return {
17686
+ ...preferred,
17687
+ capabilities: {
17688
+ contextWindows,
17689
+ effortLevels,
17690
+ ...preferred.capabilities?.defaultContext ? { defaultContext: preferred.capabilities.defaultContext } : {},
17691
+ ...preferred.capabilities?.defaultEffort ? { defaultEffort: preferred.capabilities.defaultEffort } : {},
17692
+ ...preferred.capabilities?.supportsAttachments !== void 0 ? { supportsAttachments: preferred.capabilities.supportsAttachments } : {}
17693
+ }
17694
+ };
17695
+ }
17696
+ function collapseCursorCatalogModels(catalogModels) {
17697
+ const mergedByKey = /* @__PURE__ */ new Map();
17698
+ for (const model of catalogModels) {
17699
+ const key = getCursorCatalogCollapseKey(model.id);
17700
+ const canonical = key === model.id ? model : { ...model, id: key };
17701
+ const existing = mergedByKey.get(key);
17702
+ if (!existing) {
17703
+ mergedByKey.set(key, canonical);
17704
+ continue;
17705
+ }
17706
+ const preferred = existing.id.endsWith("-thinking") ? canonical : existing;
17707
+ const secondary = preferred === existing ? canonical : existing;
17708
+ mergedByKey.set(key, mergeModelCapabilities(preferred, secondary));
17709
+ }
17710
+ const seen = /* @__PURE__ */ new Set();
17711
+ const result = [];
17712
+ for (const model of catalogModels) {
17713
+ const key = getCursorCatalogCollapseKey(model.id);
17714
+ if (seen.has(key))
17715
+ continue;
17716
+ seen.add(key);
17717
+ result.push(mergedByKey.get(key));
17718
+ }
17719
+ return result;
17720
+ }
17721
+ function collapseCursorDiscoveredModelIds(modelIds) {
17722
+ const keys = /* @__PURE__ */ new Set();
17723
+ for (const id of modelIds) {
17724
+ const trimmed = id.trim();
17725
+ if (trimmed)
17726
+ keys.add(getCursorModelCollapseKey(trimmed));
17727
+ }
17728
+ return Array.from(keys);
17729
+ }
17730
+ function mergeEffortLevels(existing, discovered) {
17731
+ const merged = new Set(existing ?? []);
17732
+ for (const level of discovered)
17733
+ merged.add(level);
17734
+ return orderEffortLevels(merged);
17735
+ }
17736
+ function orderEffortLevels(levels) {
17737
+ const set2 = levels instanceof Set ? levels : new Set(levels);
17738
+ return EFFORT_LEVELS.filter((level) => set2.has(level));
17739
+ }
17740
+ function lookupKnownModelCapabilities(modelId) {
17741
+ for (const catalog of [AVAILABLE_MODELS, CURSOR_AGENT_MODELS]) {
17742
+ const capabilities = catalog.find((model) => model.id === modelId)?.capabilities;
17743
+ if (capabilities?.effortLevels?.length)
17744
+ return capabilities;
17745
+ }
17746
+ return void 0;
17747
+ }
17748
+ function inferSlugModelCapabilities(providerKind, modelId) {
17749
+ const id = modelId.trim();
17750
+ if (!id)
17751
+ return void 0;
17752
+ const known = lookupKnownModelCapabilities(id);
17753
+ if (known)
17754
+ return known;
17755
+ if (providerKind === "codex_app_server") {
17756
+ if (id === "gpt-5.5") {
17757
+ return { contextWindows: ["1m"], effortLevels: GPT_5_5_EFFORT_LEVELS };
17758
+ }
17759
+ if (id === "gpt-5.4" || id === "gpt-5.4-mini") {
17760
+ return { contextWindows: [], effortLevels: GPT_5_4_EFFORT_LEVELS };
17761
+ }
17762
+ if (/^gpt-5\.6-/.test(id)) {
17763
+ const hasUltra = id.includes("-sol") || id.includes("-terra");
17764
+ return {
17765
+ contextWindows: [],
17766
+ effortLevels: hasUltra ? GPT_5_6_ULTRA_EFFORT_LEVELS : GPT_5_6_EFFORT_LEVELS
17767
+ };
17768
+ }
17769
+ if (id.includes("codex") || /^gpt-5\.[0-3]/.test(id)) {
17770
+ return { contextWindows: [], effortLevels: CODEX_5X_EFFORT_LEVELS };
17771
+ }
17772
+ return void 0;
17773
+ }
17774
+ if (providerKind === "claude_cli") {
17775
+ if (id === "haiku" || id.startsWith("claude-haiku-")) {
17776
+ return { contextWindows: ["200k"], effortLevels: [] };
17777
+ }
17778
+ if (id === "claude-opus-4-8") {
17779
+ return { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_EFFORT_LEVELS };
17780
+ }
17781
+ if (id === "sonnet" || id === "opus" || id === "fable" || /^claude-(sonnet|opus|fable)-/.test(id)) {
17782
+ return { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_EFFORT_LEVELS };
17783
+ }
17784
+ return void 0;
17785
+ }
17786
+ return void 0;
17787
+ }
17788
+
17789
+ // ../shared/dist/agent-selection/catalog/models/antigravity.js
17790
+ var ANTIGRAVITY_CLI_SEED_MODELS = [{ id: "", name: "CLI default" }];
17791
+ var ANTIGRAVITY_EFFORT_SUFFIX = /\s+\((High|Medium|Low|Max|Minimal)\)$/i;
17792
+ var ANTIGRAVITY_EFFORT_BY_LABEL = {
17793
+ High: "high",
17794
+ Medium: "medium",
17795
+ Low: "low",
17796
+ Max: "max",
17797
+ Minimal: "minimal"
17798
+ };
17799
+ function parseAntigravityModelId(modelId) {
17800
+ const trimmed = modelId.trim();
17801
+ const parenMatch = trimmed.match(ANTIGRAVITY_EFFORT_SUFFIX);
17802
+ if (parenMatch) {
17803
+ const effort = ANTIGRAVITY_EFFORT_BY_LABEL[parenMatch[1]] ?? null;
17804
+ return { baseId: trimmed.replace(ANTIGRAVITY_EFFORT_SUFFIX, ""), effort };
17805
+ }
17806
+ const dashParsed = parseModelEffortSuffix(trimmed);
17807
+ return { baseId: dashParsed.baseId, effort: dashParsed.effort };
17808
+ }
17809
+ function getAntigravityModelCollapseKey(modelId) {
17810
+ return parseAntigravityModelId(modelId).baseId;
17811
+ }
17812
+ function collapseAntigravityDiscoveredModelIds(modelIds) {
17813
+ const keys = /* @__PURE__ */ new Set();
17814
+ for (const id of modelIds) {
17815
+ const trimmed = id.trim();
17816
+ if (trimmed)
17817
+ keys.add(getAntigravityModelCollapseKey(trimmed));
17818
+ }
17819
+ return Array.from(keys);
17820
+ }
17821
+
17822
+ // ../shared/dist/agent-selection/catalog/models/codex.js
17823
+ var CODEX_APP_SERVER_MODELS = [];
17824
+
17825
+ // ../shared/dist/agent-selection/catalog/models/copilot.js
17651
17826
  var COPILOT_CLI_MODELS = [
17652
17827
  { id: "auto", name: "Auto" },
17653
17828
  {
@@ -17722,6 +17897,35 @@ var COPILOT_CLI_MODELS = [
17722
17897
  { id: "gemini-3.5-flash", name: "Gemini 3.5 Flash" },
17723
17898
  { id: "kimi-k2.7-code", name: "Kimi K2.7 Code" }
17724
17899
  ];
17900
+
17901
+ // ../shared/dist/agent-selection/catalog/models/droid.js
17902
+ var DROID_CLI_MODELS = [
17903
+ { id: "claude-opus-4-8", name: "Claude Opus 4.8" },
17904
+ { id: "claude-haiku-4-5-20251001", name: "Claude Haiku 4.5" },
17905
+ { id: "gpt-5.3-codex", name: "GPT-5.3 Codex" },
17906
+ { id: "gpt-5.2-codex", name: "GPT-5.2 Codex" },
17907
+ { id: "gpt-5.4-mini", name: "GPT-5.4 Mini" },
17908
+ { id: "gemini-3-pro-preview", name: "Antigravity 3 Pro" },
17909
+ { id: "gemini-3-flash-preview", name: "Antigravity 3 Flash" },
17910
+ { id: "glm-4.7", name: "GLM 4.7" },
17911
+ { id: "kimi-k2.5", name: "Kimi k2.5" }
17912
+ ];
17913
+
17914
+ // ../shared/dist/agent-selection/catalog/models/grok.js
17915
+ var GROK_CLI_MODELS = [
17916
+ { id: "grok-4.5", name: "Grok 4.5" },
17917
+ { id: "grok-composer-2.5-fast", name: "Composer 2.5 Fast" }
17918
+ ];
17919
+
17920
+ // ../shared/dist/agent-selection/catalog/models/kimi.js
17921
+ var KIMI_CLI_MODELS = [
17922
+ { id: "kimi-latest", name: "Kimi Latest" },
17923
+ { id: "kimi-k2.6", name: "Kimi K2.6" },
17924
+ { id: "kimi-k2.6-thinking", name: "Kimi K2.6 Thinking" },
17925
+ { id: "kimi-code/kimi-for-coding", name: "Kimi Code" }
17926
+ ];
17927
+
17928
+ // ../shared/dist/agent-selection/catalog/models/opencode.js
17725
17929
  var OPENCODE_PAID_MODEL = {
17726
17930
  billing: "paid",
17727
17931
  capabilities: { contextWindows: [], effortLevels: [] }
@@ -17799,187 +18003,8 @@ var OPENCODE_ZEN_MODELS = [
17799
18003
  { id: "opencode/qwen3.6-plus", name: "Qwen3.6 Plus", ...OPENCODE_PAID_MODEL },
17800
18004
  { id: "opencode/qwen3.5-plus", name: "Qwen3.5 Plus", ...OPENCODE_PAID_MODEL }
17801
18005
  ];
17802
- var PROVIDER_MODELS = {
17803
- claude_cli: CLAUDE_CLI_SEED_MODELS,
17804
- codex_app_server: [],
17805
- copilot_cli: COPILOT_CLI_MODELS,
17806
- cursor_agent_cli: CURSOR_AGENT_MODELS,
17807
- antigravity_cli: ANTIGRAVITY_CLI_SEED_MODELS,
17808
- opencode_cli: OPENCODE_ZEN_MODELS,
17809
- // Server transport dispatches the same "opencode" binary/models as opencode_cli —
17810
- // share the catalog reference rather than duplicating it.
17811
- opencode_serve: OPENCODE_ZEN_MODELS,
17812
- droid_cli: [
17813
- { id: "claude-opus-4-8", name: "Claude Opus 4.8" },
17814
- { id: "claude-haiku-4-5-20251001", name: "Claude Haiku 4.5" },
17815
- { id: "gpt-5.3-codex", name: "GPT-5.3 Codex" },
17816
- { id: "gpt-5.2-codex", name: "GPT-5.2 Codex" },
17817
- { id: "gpt-5.4-mini", name: "GPT-5.4 Mini" },
17818
- { id: "gemini-3-pro-preview", name: "Antigravity 3 Pro" },
17819
- { id: "gemini-3-flash-preview", name: "Antigravity 3 Flash" },
17820
- { id: "glm-4.7", name: "GLM 4.7" },
17821
- { id: "kimi-k2.5", name: "Kimi k2.5" }
17822
- ],
17823
- kimi_cli: [
17824
- { id: "kimi-latest", name: "Kimi Latest" },
17825
- { id: "kimi-k2.6", name: "Kimi K2.6" },
17826
- { id: "kimi-k2.6-thinking", name: "Kimi K2.6 Thinking" },
17827
- { id: "kimi-code/kimi-for-coding", name: "Kimi Code" }
17828
- ],
17829
- grok_cli: GROK_CLI_MODELS,
17830
- supatest_cli: [
17831
- { id: "small", name: "Small" },
17832
- { id: "medium", name: "Medium" },
17833
- { id: "premium", name: "Premium" },
17834
- { id: "claude-sonnet-4-5", name: "Sonnet 4.5" },
17835
- { id: "claude-opus-4-5", name: "Opus 4.5" },
17836
- { id: "claude-haiku-4-5", name: "Haiku 4.5" }
17837
- ],
17838
- generic_cli: []
17839
- };
17840
- function findModelDef(providerKind, modelId) {
17841
- if (!modelId)
17842
- return void 0;
17843
- if (providerKind) {
17844
- const fromProvider = PROVIDER_MODELS[providerKind]?.find((m) => m.id === modelId);
17845
- if (fromProvider)
17846
- return fromProvider;
17847
- }
17848
- return AVAILABLE_MODELS.find((m) => m.id === modelId);
17849
- }
17850
-
17851
- // ../shared/dist/cursor-agent-models.js
17852
- function getCursorModelCollapseKey(modelId) {
17853
- const parsed = parseModelEffortSuffix(modelId);
17854
- if (parsed.fast && !parsed.effort)
17855
- return modelId.trim();
17856
- return parsed.baseId;
17857
- }
17858
- function getCursorCatalogCollapseKey(modelId) {
17859
- const trimmed = modelId.trim();
17860
- if (trimmed.endsWith("-medium-thinking")) {
17861
- return trimmed.slice(0, -"-medium-thinking".length);
17862
- }
17863
- let key = getCursorModelCollapseKey(trimmed);
17864
- if (key.endsWith("-thinking")) {
17865
- key = getCursorModelCollapseKey(key.slice(0, -"-thinking".length));
17866
- }
17867
- return key;
17868
- }
17869
- function mergeContextWindows(existing, discovered) {
17870
- const merged = /* @__PURE__ */ new Set([...existing ?? [], ...discovered ?? []]);
17871
- return Array.from(merged);
17872
- }
17873
- function mergeModelCapabilities(preferred, other) {
17874
- const contextWindows = mergeContextWindows(preferred.capabilities?.contextWindows, other.capabilities?.contextWindows);
17875
- const effortLevels = mergeEffortLevels(preferred.capabilities?.effortLevels, new Set(other.capabilities?.effortLevels ?? []));
17876
- if (contextWindows.length === 0 && effortLevels.length === 0)
17877
- return preferred;
17878
- return {
17879
- ...preferred,
17880
- capabilities: {
17881
- contextWindows,
17882
- effortLevels,
17883
- ...preferred.capabilities?.defaultContext ? { defaultContext: preferred.capabilities.defaultContext } : {},
17884
- ...preferred.capabilities?.defaultEffort ? { defaultEffort: preferred.capabilities.defaultEffort } : {},
17885
- ...preferred.capabilities?.supportsAttachments !== void 0 ? { supportsAttachments: preferred.capabilities.supportsAttachments } : {}
17886
- }
17887
- };
17888
- }
17889
- function collapseCursorCatalogModels(catalogModels) {
17890
- const mergedByKey = /* @__PURE__ */ new Map();
17891
- for (const model of catalogModels) {
17892
- const key = getCursorCatalogCollapseKey(model.id);
17893
- const canonical = key === model.id ? model : { ...model, id: key };
17894
- const existing = mergedByKey.get(key);
17895
- if (!existing) {
17896
- mergedByKey.set(key, canonical);
17897
- continue;
17898
- }
17899
- const preferred = existing.id.endsWith("-thinking") ? canonical : existing;
17900
- const secondary = preferred === existing ? canonical : existing;
17901
- mergedByKey.set(key, mergeModelCapabilities(preferred, secondary));
17902
- }
17903
- const seen = /* @__PURE__ */ new Set();
17904
- const result = [];
17905
- for (const model of catalogModels) {
17906
- const key = getCursorCatalogCollapseKey(model.id);
17907
- if (seen.has(key))
17908
- continue;
17909
- seen.add(key);
17910
- result.push(mergedByKey.get(key));
17911
- }
17912
- return result;
17913
- }
17914
- function collapseCursorDiscoveredModelIds(modelIds) {
17915
- const keys = /* @__PURE__ */ new Set();
17916
- for (const id of modelIds) {
17917
- const trimmed = id.trim();
17918
- if (trimmed)
17919
- keys.add(getCursorModelCollapseKey(trimmed));
17920
- }
17921
- return Array.from(keys);
17922
- }
17923
- function mergeEffortLevels(existing, discovered) {
17924
- const merged = new Set(existing ?? []);
17925
- for (const level of discovered)
17926
- merged.add(level);
17927
- return orderEffortLevels(merged);
17928
- }
17929
- function orderEffortLevels(levels) {
17930
- const set2 = levels instanceof Set ? levels : new Set(levels);
17931
- return EFFORT_LEVELS.filter((level) => set2.has(level));
17932
- }
17933
- function lookupKnownModelCapabilities(modelId) {
17934
- for (const catalog of [AVAILABLE_MODELS, CURSOR_AGENT_MODELS]) {
17935
- const capabilities = catalog.find((model) => model.id === modelId)?.capabilities;
17936
- if (capabilities?.effortLevels?.length)
17937
- return capabilities;
17938
- }
17939
- return void 0;
17940
- }
17941
- function inferSlugModelCapabilities(providerKind, modelId) {
17942
- const id = modelId.trim();
17943
- if (!id)
17944
- return void 0;
17945
- const known = lookupKnownModelCapabilities(id);
17946
- if (known)
17947
- return known;
17948
- if (providerKind === "codex_app_server") {
17949
- if (id === "gpt-5.5") {
17950
- return { contextWindows: ["1m"], effortLevels: GPT_5_5_EFFORT_LEVELS };
17951
- }
17952
- if (id === "gpt-5.4" || id === "gpt-5.4-mini") {
17953
- return { contextWindows: [], effortLevels: GPT_5_4_EFFORT_LEVELS };
17954
- }
17955
- if (/^gpt-5\.6-/.test(id)) {
17956
- const hasUltra = id.includes("-sol") || id.includes("-terra");
17957
- return {
17958
- contextWindows: [],
17959
- effortLevels: hasUltra ? GPT_5_6_ULTRA_EFFORT_LEVELS : GPT_5_6_EFFORT_LEVELS
17960
- };
17961
- }
17962
- if (id.includes("codex") || /^gpt-5\.[0-3]/.test(id)) {
17963
- return { contextWindows: [], effortLevels: CODEX_5X_EFFORT_LEVELS };
17964
- }
17965
- return void 0;
17966
- }
17967
- if (providerKind === "claude_cli") {
17968
- if (id === "haiku" || id.startsWith("claude-haiku-")) {
17969
- return { contextWindows: ["200k"], effortLevels: [] };
17970
- }
17971
- if (id === "claude-opus-4-8") {
17972
- return { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_EFFORT_LEVELS };
17973
- }
17974
- if (id === "sonnet" || id === "opus" || id === "fable" || /^claude-(sonnet|opus|fable)-/.test(id)) {
17975
- return { contextWindows: ["200k", "1m"], effortLevels: CLAUDE_EFFORT_LEVELS };
17976
- }
17977
- return void 0;
17978
- }
17979
- return void 0;
17980
- }
17981
18006
 
17982
- // ../shared/dist/provider-picker-fallback-models.js
18007
+ // ../shared/dist/agent-selection/catalog/models/picker-fallback.js
17983
18008
  var CLAUDE_5_EFFORT = [
17984
18009
  "minimal",
17985
18010
  "low",
@@ -18052,12 +18077,10 @@ var COPILOT_CLI_PICKER_FALLBACK_MODELS = COPILOT_FALLBACK_IDS.map((id) => {
18052
18077
  const fromCatalog = COPILOT_CLI_MODELS.find((model) => model.id === id);
18053
18078
  if (!fromCatalog)
18054
18079
  return { id, name: id };
18055
- const inferred = id.startsWith("gpt-") ? inferSlugModelCapabilities("codex_app_server", id) : inferSlugModelCapabilities("claude_cli", id.replace("claude-", "claude-"));
18080
+ const inferred = id.startsWith("gpt-") ? inferSlugModelCapabilities("codex_app_server", id) : inferSlugModelCapabilities("claude_cli", id);
18056
18081
  return inferred ? { ...fromCatalog, capabilities: inferred } : fromCatalog;
18057
18082
  });
18058
- var DROID_CLI_PICKER_FALLBACK_MODELS = [
18059
- ...PROVIDER_MODELS.droid_cli ?? []
18060
- ];
18083
+ var DROID_CLI_PICKER_FALLBACK_MODELS = [...DROID_CLI_MODELS];
18061
18084
  var KIMI_CLI_PICKER_FALLBACK_MODELS = [
18062
18085
  { id: "kimi-latest", name: "Kimi Latest" },
18063
18086
  { id: "kimi-k2.6", name: "Kimi K2.6", capabilities: caps(CLAUDE_5_EFFORT) },
@@ -18092,8 +18115,178 @@ function getProviderPickerFallbackModels(providerKind) {
18092
18115
  return PROVIDER_PICKER_FALLBACK_MODELS[providerKind] ?? [];
18093
18116
  }
18094
18117
 
18118
+ // ../shared/dist/agent-selection/catalog/models/supatest.js
18119
+ var SUPATEST_CLI_MODELS = [
18120
+ { id: "small", name: "Small" },
18121
+ { id: "medium", name: "Medium" },
18122
+ { id: "premium", name: "Premium" },
18123
+ { id: "claude-sonnet-4-5", name: "Sonnet 4.5" },
18124
+ { id: "claude-opus-4-5", name: "Opus 4.5" },
18125
+ { id: "claude-haiku-4-5", name: "Haiku 4.5" }
18126
+ ];
18127
+
18128
+ // ../shared/dist/agent-selection/catalog/models/index.js
18129
+ var PROVIDER_MODELS = {
18130
+ claude_cli: CLAUDE_CLI_SEED_MODELS,
18131
+ codex_app_server: CODEX_APP_SERVER_MODELS,
18132
+ copilot_cli: COPILOT_CLI_MODELS,
18133
+ cursor_agent_cli: CURSOR_AGENT_MODELS,
18134
+ antigravity_cli: ANTIGRAVITY_CLI_SEED_MODELS,
18135
+ opencode_cli: OPENCODE_ZEN_MODELS,
18136
+ // Server transport dispatches the same "opencode" binary/models as opencode_cli —
18137
+ // share the catalog reference rather than duplicating it.
18138
+ opencode_serve: OPENCODE_ZEN_MODELS,
18139
+ droid_cli: DROID_CLI_MODELS,
18140
+ kimi_cli: KIMI_CLI_MODELS,
18141
+ grok_cli: GROK_CLI_MODELS,
18142
+ supatest_cli: SUPATEST_CLI_MODELS,
18143
+ generic_cli: []
18144
+ };
18145
+ function findModelDef(providerKind, modelId) {
18146
+ if (!modelId)
18147
+ return void 0;
18148
+ if (providerKind) {
18149
+ const fromProvider = PROVIDER_MODELS[providerKind]?.find((m) => m.id === modelId);
18150
+ if (fromProvider)
18151
+ return fromProvider;
18152
+ }
18153
+ return AVAILABLE_MODELS.find((m) => m.id === modelId);
18154
+ }
18155
+ function catalogProviderFor(providerKind) {
18156
+ return providerKind === "opencode_serve" ? "opencode_cli" : providerKind;
18157
+ }
18158
+ function providerCatalogModels(providerKind) {
18159
+ const catalogProvider = catalogProviderFor(providerKind);
18160
+ const curated = getProviderPickerFallbackModels(catalogProvider);
18161
+ const staticCatalog = PROVIDER_MODELS[catalogProvider] ?? [];
18162
+ if (staticCatalog.length === 0)
18163
+ return curated;
18164
+ const hasConcreteModel = staticCatalog.some((model) => model.id.trim());
18165
+ if (!hasConcreteModel && curated.length > 0)
18166
+ return curated;
18167
+ return staticCatalog;
18168
+ }
18169
+
18170
+ // ../shared/dist/agent-selection/catalog/providers.js
18171
+ var PROVIDERS = [
18172
+ {
18173
+ kind: "claude_cli",
18174
+ label: "Claude Code",
18175
+ selectable: true,
18176
+ localOnly: false,
18177
+ cloudNative: false,
18178
+ workflowEligible: true
18179
+ },
18180
+ {
18181
+ kind: "codex_app_server",
18182
+ label: "Codex",
18183
+ selectable: true,
18184
+ localOnly: false,
18185
+ cloudNative: true,
18186
+ // Codex runs through the managed cloud workflow path, not the user-managed
18187
+ // one, so it is deliberately absent from the workflow picker.
18188
+ workflowEligible: false
18189
+ },
18190
+ {
18191
+ kind: "copilot_cli",
18192
+ label: "GitHub Copilot",
18193
+ selectable: true,
18194
+ localOnly: false,
18195
+ cloudNative: false,
18196
+ workflowEligible: true
18197
+ },
18198
+ {
18199
+ kind: "cursor_agent_cli",
18200
+ label: "Cursor Agent",
18201
+ selectable: true,
18202
+ localOnly: false,
18203
+ cloudNative: false,
18204
+ workflowEligible: true
18205
+ },
18206
+ {
18207
+ kind: "droid_cli",
18208
+ label: "Droid",
18209
+ selectable: true,
18210
+ localOnly: false,
18211
+ cloudNative: false,
18212
+ workflowEligible: true
18213
+ },
18214
+ {
18215
+ kind: "antigravity_cli",
18216
+ label: "Antigravity",
18217
+ selectable: true,
18218
+ localOnly: false,
18219
+ cloudNative: false,
18220
+ workflowEligible: true
18221
+ },
18222
+ {
18223
+ kind: "grok_cli",
18224
+ label: "Grok Build",
18225
+ selectable: true,
18226
+ localOnly: false,
18227
+ cloudNative: false,
18228
+ workflowEligible: true
18229
+ },
18230
+ {
18231
+ kind: "kimi_cli",
18232
+ label: "Kimi",
18233
+ selectable: true,
18234
+ localOnly: false,
18235
+ cloudNative: false,
18236
+ workflowEligible: true
18237
+ },
18238
+ // Only the server transport is user-selectable — it's a strict superset of what
18239
+ // opencode_cli can do (subagent visibility, permission notices, session reuse),
18240
+ // matching how Claude Code/Codex are presented as one option each.
18241
+ {
18242
+ kind: "opencode_serve",
18243
+ label: "OpenCode",
18244
+ selectable: true,
18245
+ localOnly: false,
18246
+ cloudNative: false,
18247
+ workflowEligible: true
18248
+ },
18249
+ {
18250
+ kind: "supatest_cli",
18251
+ label: "Supatest CLI",
18252
+ selectable: true,
18253
+ localOnly: true,
18254
+ cloudNative: false,
18255
+ workflowEligible: false
18256
+ },
18257
+ // opencode_cli stays fully wired for dispatch (base-machine-agent.ts) and as the
18258
+ // OpenCode model catalog source, purely so already-existing opencode_cli sessions
18259
+ // and workflows keep working. It is deliberately not offered for new selection.
18260
+ {
18261
+ kind: "opencode_cli",
18262
+ label: "OpenCode",
18263
+ selectable: false,
18264
+ localOnly: false,
18265
+ cloudNative: false,
18266
+ workflowEligible: true
18267
+ }
18268
+ ];
18269
+ var SELECTABLE_PROVIDERS = PROVIDERS.filter((provider) => provider.selectable);
18270
+ var PROVIDER_BY_KIND = new Map(PROVIDERS.map((provider) => [provider.kind, provider]));
18271
+ var WORKFLOW_ELIGIBLE_PROVIDER_KINDS = PROVIDERS.filter((provider) => provider.workflowEligible).map((provider) => provider.kind);
18272
+
18095
18273
  // ../shared/dist/runtime-discovered-models.js
18096
18274
  var OPENCODE_ZEN_MODEL_BY_ID = new Map(OPENCODE_ZEN_MODELS.map((model) => [model.id, model]));
18275
+ var DROID_MODEL_ID_PATTERN = /^(?:claude-(?:sonnet|opus|haiku|fable)-[a-z0-9][a-z0-9.-]*|gpt-[a-z0-9][a-z0-9.-]*|gemini-[a-z0-9][a-z0-9.-]*|glm-[a-z0-9][a-z0-9.-]*|kimi-[a-z0-9][a-z0-9.-]*)$/i;
18276
+ function isValidDroidModelId(modelId) {
18277
+ const trimmed = modelId.trim();
18278
+ if (!trimmed || trimmed.length > 80)
18279
+ return false;
18280
+ if (/[\s│║╔╚═|]/.test(trimmed))
18281
+ return false;
18282
+ if (/^(tip|usage|error|warning|droid|skills|mcps|agents\.md|trust this)/i.test(trimmed)) {
18283
+ return false;
18284
+ }
18285
+ if (/^v\d+\.\d+/.test(trimmed))
18286
+ return false;
18287
+ return DROID_MODEL_ID_PATTERN.test(trimmed);
18288
+ }
18289
+ var SLUG_DISCOVERY_PROVIDERS = /* @__PURE__ */ new Set(["claude_cli", "codex_app_server"]);
18097
18290
  var DISCOVERY_SEED_PROVIDERS = /* @__PURE__ */ new Set([
18098
18291
  "claude_cli",
18099
18292
  "codex_app_server",
@@ -18106,30 +18299,50 @@ var DISCOVERY_SEED_PROVIDERS = /* @__PURE__ */ new Set([
18106
18299
  "copilot_cli",
18107
18300
  "droid_cli"
18108
18301
  ]);
18109
- function baseCatalogForProvider(providerKind) {
18110
- const catalogProvider = providerKind === "opencode_serve" ? "opencode_cli" : providerKind;
18111
- const fallback = getProviderPickerFallbackModels(catalogProvider);
18112
- const staticCatalog = PROVIDER_MODELS[catalogProvider] ?? [];
18113
- if (staticCatalog.length === 0) {
18114
- return fallback;
18115
- }
18116
- const hasConcreteModel = staticCatalog.some((model) => model.id.trim());
18117
- if (!hasConcreteModel && fallback.length > 0) {
18118
- return fallback;
18119
- }
18120
- return staticCatalog;
18121
- }
18122
- var PROVIDER_MODEL_INFERENCE_IDS = Object.keys(PROVIDER_MODELS).filter((providerId) => providerId !== "antigravity_cli");
18302
+ var baseCatalogForProvider = providerCatalogModels;
18123
18303
  function catalogModelsForProvider(providerKind, modelsFromConfig) {
18124
18304
  const catalog = baseCatalogForProvider(providerKind);
18125
18305
  if (!modelsFromConfig)
18126
18306
  return [...catalog];
18127
18307
  if (DISCOVERY_SEED_PROVIDERS.has(providerKind)) {
18128
18308
  const configById = new Map(modelsFromConfig.map((model) => [model.id, model]));
18129
- return catalog.map((entry) => configById.get(entry.id) ?? entry);
18309
+ const merged = catalog.map((entry) => configById.get(entry.id) ?? entry);
18310
+ const spineIds = new Set(catalog.map((entry) => entry.id));
18311
+ for (const entry of modelsFromConfig) {
18312
+ if (spineIds.has(entry.id))
18313
+ continue;
18314
+ const collapsesOntoSpine = collapseDiscoveredModelIdsForProvider(providerKind, [
18315
+ entry.id
18316
+ ]).some((base) => spineIds.has(base));
18317
+ if (collapsesOntoSpine)
18318
+ continue;
18319
+ merged.push(entry);
18320
+ }
18321
+ return merged;
18130
18322
  }
18131
18323
  return [...modelsFromConfig];
18132
18324
  }
18325
+ function collapseDiscoveredModelIdsForProvider(providerKind, discoveredModelIds) {
18326
+ if (providerKind === "cursor_agent_cli" || SLUG_DISCOVERY_PROVIDERS.has(providerKind)) {
18327
+ return collapseCursorDiscoveredModelIds(discoveredModelIds);
18328
+ }
18329
+ if (providerKind === "antigravity_cli") {
18330
+ return collapseAntigravityDiscoveredModelIds(discoveredModelIds);
18331
+ }
18332
+ if (providerKind === "droid_cli") {
18333
+ return discoveredModelIds.map((id) => id.trim()).filter(isValidDroidModelId);
18334
+ }
18335
+ if (providerKind === "opencode_cli" || providerKind === "opencode_serve") {
18336
+ const keys = /* @__PURE__ */ new Set();
18337
+ for (const id of discoveredModelIds) {
18338
+ const trimmed = id.trim();
18339
+ if (trimmed.startsWith("opencode/"))
18340
+ keys.add(collapseModelIdToBase(trimmed));
18341
+ }
18342
+ return Array.from(keys);
18343
+ }
18344
+ return discoveredModelIds.map((id) => id.trim()).filter(Boolean);
18345
+ }
18133
18346
 
18134
18347
  // ../agent-core/dist/index.js
18135
18348
  var import_crypto = require("crypto");
@@ -25894,7 +26107,7 @@ function expandSkillInvocationPrompt(text, cwd, home = (0, import_os9.homedir)()
25894
26107
  ].join("\n")
25895
26108
  };
25896
26109
  }
25897
- var DROID_DEFAULT_MODEL = "claude-opus-4-7";
26110
+ var DROID_DEFAULT_MODEL = "claude-opus-4-8";
25898
26111
  var AGENT_ACTIVITY_HEARTBEAT_MS = 1e4;
25899
26112
  function normalizeBackendKind(kind) {
25900
26113
  if (kind === "codex") return "codex_app_server";
@@ -51101,7 +51314,7 @@ var SuspensionDetector = class {
51101
51314
  };
51102
51315
 
51103
51316
  // src/version.ts
51104
- var AGENT_VERSION = "0.1.54";
51317
+ var AGENT_VERSION = "0.1.56";
51105
51318
 
51106
51319
  // src/workspace-relocation.ts
51107
51320
  var import_node_child_process6 = require("child_process");
@@ -51185,6 +51398,9 @@ var WORKSPACE_LEASE_GIT_TIMEOUT_MS = parsePositiveMs(
51185
51398
  process.env.ALAN_WORKSPACE_LEASE_GIT_TIMEOUT_MS,
51186
51399
  2e3
51187
51400
  );
51401
+ function applicationCodeForWorkspaceLeaseFailure(code) {
51402
+ return code === "workspace_lease_branch_changed" ? "app.workspace.branch_changed" : "app.workspace.missing";
51403
+ }
51188
51404
  function gitValue(cwd, args) {
51189
51405
  const result = (0, import_node_child_process7.spawnSync)("git", ["-C", cwd, ...args], {
51190
51406
  encoding: "utf8",
@@ -51209,8 +51425,8 @@ var DEFAULT_PROBE2 = {
51209
51425
  const repositoryRoot = gitValue(canonicalWorkspacePath, ["rev-parse", "--show-toplevel"]);
51210
51426
  const gitDirectory = gitValue(canonicalWorkspacePath, ["rev-parse", "--git-dir"]);
51211
51427
  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;
51428
+ const branch = gitValue(canonicalWorkspacePath, ["branch", "--show-current"]) ?? "";
51429
+ if (!repositoryRoot || !gitDirectory || !commonDirectory) return null;
51214
51430
  const remote = gitValue(canonicalWorkspacePath, ["config", "--get", "remote.origin.url"]);
51215
51431
  const remoteIdentity = remote ? normalizeRepositoryIdentity(remote) : null;
51216
51432
  return {
@@ -51234,18 +51450,22 @@ var DEFAULT_PROBE2 = {
51234
51450
  }
51235
51451
  }
51236
51452
  };
51237
- function unavailableFailure(target) {
51453
+ var IDENTITY_FAILURE_MESSAGES = {
51454
+ workspace_lease_unavailable: "The workspace or Git checkout became unavailable while the run was active. Restore it and start a new run.",
51455
+ 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.",
51456
+ 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."
51457
+ };
51458
+ function identityFailure(code, target) {
51238
51459
  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
51460
+ code,
51461
+ message: IDENTITY_FAILURE_MESSAGES[code],
51462
+ workspacePath: target.workspacePath
51243
51463
  };
51244
51464
  }
51245
51465
  function branchFailure(target, expectedBranch, actualBranch) {
51246
51466
  return {
51247
51467
  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.`,
51468
+ message: `The workspace branch changed from ${expectedBranch} to ${actualBranch || "detached HEAD"} while the run was active. Restore ${expectedBranch} and start a new run.`,
51249
51469
  workspacePath: target.workspacePath,
51250
51470
  expectedBranch,
51251
51471
  actualBranch
@@ -51261,7 +51481,12 @@ var WorkspaceRunLease = class _WorkspaceRunLease {
51261
51481
  for (const target of targets) {
51262
51482
  const normalizedTarget = { ...target, workspacePath: (0, import_node_path11.resolve)(target.workspacePath) };
51263
51483
  const identity = probe.snapshot(normalizedTarget.workspacePath);
51264
- if (!identity) return { lease: null, failure: unavailableFailure(normalizedTarget) };
51484
+ if (!identity) {
51485
+ return {
51486
+ lease: null,
51487
+ failure: identityFailure("workspace_lease_unavailable", normalizedTarget)
51488
+ };
51489
+ }
51265
51490
  if (normalizedTarget.expectedBranch && identity.branch !== normalizedTarget.expectedBranch) {
51266
51491
  return {
51267
51492
  lease: null,
@@ -51282,81 +51507,49 @@ var WorkspaceRunLease = class _WorkspaceRunLease {
51282
51507
  /**
51283
51508
  * Classify the lease state for the run monitor.
51284
51509
  *
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.
51510
+ * Checks workspace identity only path, repository, worktree. The branch is
51511
+ * deliberately not checked here: it is working state, not identity, and the supervised
51512
+ * process is a coding agent. A conflicted rebase leaves HEAD detached for as long as
51513
+ * the agent takes to resolve it, so any mid-run branch assertion kills that run. What
51514
+ * keeps work in the right place is the worktree's path and git-dir identity, both
51515
+ * fenced below, plus `assertExpectedBranch` in binding-switch-git.ts at apply time.
51516
+ * `capture()` still refuses to start a run on the wrong branch.
51517
+ *
51518
+ * `transient: true` means retryable — a git probe that timed out under OS throttling
51519
+ * while the path still exists. `transient: false` is definitive and fails fast.
51292
51520
  */
51293
51521
  verifyDetailed() {
51294
- for (const captured of this.captured) {
51295
- const current = this.probe.snapshot(captured.target.workspacePath);
51522
+ for (const { target, identity } of this.captured) {
51523
+ const current = this.probe.snapshot(target.workspacePath);
51296
51524
  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) {
51525
+ const pathGone = this.probe.pathExists?.(target.workspacePath) === false;
51301
51526
  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
51527
+ failure: identityFailure("workspace_lease_unavailable", target),
51528
+ transient: !pathGone
51310
51529
  };
51311
51530
  }
51312
- if (current.repositoryIdentity !== captured.identity.repositoryIdentity || current.worktreeIdentity !== captured.identity.worktreeIdentity) {
51531
+ if (current.workspaceIdentity !== identity.workspaceIdentity) {
51313
51532
  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
- },
51533
+ failure: identityFailure("workspace_lease_path_changed", target),
51321
51534
  transient: false
51322
51535
  };
51323
51536
  }
51324
- if (current.branch !== captured.identity.branch) {
51537
+ if (current.repositoryIdentity !== identity.repositoryIdentity || current.worktreeIdentity !== identity.worktreeIdentity) {
51325
51538
  return {
51326
- failure: branchFailure(captured.target, captured.identity.branch, current.branch),
51539
+ failure: identityFailure("workspace_lease_repository_changed", target),
51327
51540
  transient: false
51328
51541
  };
51329
51542
  }
51330
51543
  }
51331
51544
  return { failure: null, transient: false };
51332
51545
  }
51546
+ /**
51547
+ * Failure-only view of {@link verifyDetailed}. Kept as a thin delegation rather than a
51548
+ * second copy of the checks: the two implementations previously duplicated all four
51549
+ * comparisons and had to be edited in lockstep.
51550
+ */
51333
51551
  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;
51552
+ return this.verifyDetailed().failure;
51360
51553
  }
51361
51554
  };
51362
51555
  var FRESH_LEASE_MONITOR_STATE = {
@@ -52848,6 +53041,29 @@ async function refreshProviderVersions() {
52848
53041
  })
52849
53042
  );
52850
53043
  }
53044
+ var providerAuthCache = /* @__PURE__ */ new Map();
53045
+ async function refreshProviderAuthStates(providers = [...DISCOVERABLE_PROVIDER_KINDS]) {
53046
+ const env = getDaemonCliEnvironment();
53047
+ await Promise.allSettled(
53048
+ providers.map(async (provider) => {
53049
+ const executable = resolveProviderCliCommand(provider, env);
53050
+ if (!executable) {
53051
+ providerAuthCache.delete(provider);
53052
+ return;
53053
+ }
53054
+ const result = await preflightProviderAuth({ backendKind: provider, executable, env });
53055
+ if (result.status === "unknown") {
53056
+ providerAuthCache.delete(provider);
53057
+ return;
53058
+ }
53059
+ providerAuthCache.set(provider, {
53060
+ status: result.status,
53061
+ ...result.message ? { message: result.message } : {},
53062
+ checkedAt: (/* @__PURE__ */ new Date()).toISOString()
53063
+ });
53064
+ })
53065
+ );
53066
+ }
52851
53067
  function refreshSingleProviderModels(provider, executable, env) {
52852
53068
  if (!supportsProviderModelDiscovery(provider)) return Promise.resolve();
52853
53069
  const cacheKey = providerModelCacheKey(provider, executable);
@@ -52879,6 +53095,7 @@ async function refreshProviderModels(providers = DISCOVERABLE_PROVIDER_KINDS) {
52879
53095
  async function scanAgentCapabilities(providers = [...DISCOVERABLE_PROVIDER_KINDS]) {
52880
53096
  await refreshProviderVersions();
52881
53097
  await refreshProviderModels(providers);
53098
+ await refreshProviderAuthStates(providers);
52882
53099
  return discoverCapabilities();
52883
53100
  }
52884
53101
  async function printScanModels(args) {
@@ -52931,12 +53148,18 @@ function discoverCapabilities() {
52931
53148
  }
52932
53149
  const version2 = providerVersionCache.get(provider);
52933
53150
  const models = executable ? providerModelCache.get(providerModelCacheKey(provider, executable)) ?? [] : [];
53151
+ const auth2 = available ? providerAuthCache.get(provider) : void 0;
52934
53152
  return {
52935
53153
  provider,
52936
53154
  available,
52937
53155
  ...version2 ? { version: version2 } : {},
52938
53156
  models,
52939
- lastCheckedAt: now
53157
+ lastCheckedAt: now,
53158
+ ...auth2 ? {
53159
+ authStatus: auth2.status,
53160
+ ...auth2.message ? { authMessage: auth2.message } : {},
53161
+ authCheckedAt: auth2.checkedAt
53162
+ } : {}
52940
53163
  };
52941
53164
  }),
52942
53165
  hasGit: Boolean(resolveCliExecutable("git", env)),
@@ -53292,7 +53515,10 @@ var RuntimePresenter = class {
53292
53515
  }
53293
53516
  failWorkspaceLease(failure) {
53294
53517
  return this.failApplicationProblem({
53295
- code: "app.workspace.missing",
53518
+ // A branch change is not a missing workspace. Reporting both as
53519
+ // `app.workspace.missing` told the user to "choose or relocate the project
53520
+ // folder" for a folder that never moved.
53521
+ code: applicationCodeForWorkspaceLeaseFailure(failure.code),
53296
53522
  detail: failure.message,
53297
53523
  component: "agent-manager-workspace-lease",
53298
53524
  phase: "delivery"
@@ -54593,7 +54819,8 @@ async function startDaemon(args) {
54593
54819
  const runFailure = buildApplicationRunFailure({
54594
54820
  conversationId: payload.conversationId,
54595
54821
  runId: payload.runId,
54596
- code: "app.workspace.missing",
54822
+ // A run dispatched onto the wrong branch is also not a missing workspace.
54823
+ code: applicationCodeForWorkspaceLeaseFailure(failure.code),
54597
54824
  detail: failure.message,
54598
54825
  component: "agent-manager-workspace-lease",
54599
54826
  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.56",
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/agent-core": "0.1.0",
27
+ "@alan-ai/shared": "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
+ }