oysterun 1.6.0-beta.13 → 1.6.0-beta.15

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 (55) hide show
  1. package/dev/client/web/index.html +239 -115
  2. package/dev/client/web-chat/dist/assets/{ReactPrism-B8NIa4fv.js → ReactPrism-B3KTEOXB.js} +1 -1
  3. package/dev/client/web-chat/dist/assets/ReactPrism-B3KTEOXB.js.map +1 -0
  4. package/dev/client/web-chat/dist/assets/index-B9fWrEk-.js.map +1 -1
  5. package/dev/client/web-chat/dist/assets/{index-BlWA-FTm.js → index-BKVXuim6.js} +87 -87
  6. package/dev/client/web-chat/dist/assets/index-BKVXuim6.js.map +1 -0
  7. package/dev/client/web-chat/dist/assets/{index-DWHevaWh.js → index-CThbbx52.js} +1 -1
  8. package/dev/client/web-chat/dist/assets/index-CThbbx52.js.map +1 -0
  9. package/dev/client/web-chat/dist/assets/{index-B09yxZJ9.js → index-DbcfVePP.js} +2 -2
  10. package/dev/client/web-chat/dist/assets/index-DbcfVePP.js.map +1 -0
  11. package/dev/client/web-chat/dist/assets/{index-N037moyv.css → index-EZ7ql7FL.css} +1 -1
  12. package/dev/client/web-chat/dist/assets/{pdf-DommA-BA.js → pdf-Brm5ylv3.js} +3 -3
  13. package/dev/client/web-chat/dist/assets/pdf-Brm5ylv3.js.map +1 -0
  14. package/dev/client/web-chat/dist/assets/{web-Dd1cwRmr.js → web-DvtxcIZY.js} +1 -1
  15. package/dev/client/web-chat/dist/assets/web-DvtxcIZY.js.map +1 -0
  16. package/dev/client/web-chat/dist/assets/{web-DBEyaPWp.js → web-ootKKj01.js} +1 -1
  17. package/dev/client/web-chat/dist/assets/web-ootKKj01.js.map +1 -0
  18. package/dev/client/web-chat/dist/index.html +2 -2
  19. package/docs/routec/provider_contract.md +35 -5
  20. package/host-service/claude-acp-model-discovery.mjs +23 -18
  21. package/host-service/cli/reconcile-initial-preflight.mjs +19 -0
  22. package/host-service/codex-model-discovery.mjs +23 -18
  23. package/host-service/grok-acp-model-discovery.mjs +31 -33
  24. package/host-service/initial-preflight-recovery.mjs +71 -0
  25. package/host-service/lifecycle-compat-cli.mjs +13 -0
  26. package/host-service/lifecycle-compat-preload.mjs +89 -0
  27. package/host-service/lifecycle-compatibility.mjs +164 -0
  28. package/host-service/lifecycle-continuity-assets.mjs +8 -1
  29. package/host-service/lifecycle-continuity-projection.mjs +9 -2
  30. package/host-service/lifecycle-continuity-runner.mjs +4 -6
  31. package/host-service/lifecycle-continuity.mjs +21 -0
  32. package/host-service/lifecycle-user-path.mjs +34 -0
  33. package/host-service/model-discovery-guardian.mjs +40 -0
  34. package/host-service/model-discovery-process.mjs +141 -0
  35. package/host-service/package.json +1 -1
  36. package/host-service/provider-model-params.mjs +14 -17
  37. package/host-service/provider-model-refresh-runner.mjs +124 -169
  38. package/host-service/provider-model-refresh-schedule.mjs +11 -0
  39. package/host-service/restart-restore-state.mjs +11 -0
  40. package/host-service/scheduler-service.mjs +6 -1
  41. package/host-service/server.mjs +68 -15
  42. package/host-service/service-definition-migration.mjs +5 -2
  43. package/host-service/session-loop-definitions.mjs +67 -73
  44. package/host-service/update-reminder-state.mjs +2 -0
  45. package/package.json +1 -1
  46. package/tool_scripts/oysterun_continuity_transaction.mjs +61 -5
  47. package/tool_scripts/oysterun_npm_package_manifest.mjs +4 -0
  48. package/tool_scripts/oysterun_update_restart_runner.mjs +3 -2
  49. package/dev/client/web-chat/dist/assets/ReactPrism-B8NIa4fv.js.map +0 -1
  50. package/dev/client/web-chat/dist/assets/index-B09yxZJ9.js.map +0 -1
  51. package/dev/client/web-chat/dist/assets/index-BlWA-FTm.js.map +0 -1
  52. package/dev/client/web-chat/dist/assets/index-DWHevaWh.js.map +0 -1
  53. package/dev/client/web-chat/dist/assets/pdf-DommA-BA.js.map +0 -1
  54. package/dev/client/web-chat/dist/assets/web-DBEyaPWp.js.map +0 -1
  55. package/dev/client/web-chat/dist/assets/web-Dd1cwRmr.js.map +0 -1
@@ -2906,18 +2906,6 @@
2906
2906
  overflow-wrap: anywhere;
2907
2907
  }
2908
2908
 
2909
- .session-loop-recovery-actions {
2910
- display: flex;
2911
- flex: 1 0 100%;
2912
- flex-wrap: wrap;
2913
- gap: 8px;
2914
- }
2915
-
2916
- .session-loop-recovery-action {
2917
- min-height: 44px;
2918
- white-space: normal;
2919
- }
2920
-
2921
2909
  .session-loop-form-row {
2922
2910
  display: grid;
2923
2911
  grid-template-columns: repeat(3, minmax(0, 1fr));
@@ -3005,10 +2993,6 @@
3005
2993
  .scheduler-row.session-loop-row .scheduler-row-toggle {
3006
2994
  order: 3;
3007
2995
  }
3008
-
3009
- .session-loop-recovery-actions > button {
3010
- flex: 1 1 100%;
3011
- }
3012
2996
  }
3013
2997
 
3014
2998
  .scheduler-panel {
@@ -8139,13 +8123,18 @@
8139
8123
  try {
8140
8124
  window.localStorage?.setItem("oysterun_token", token);
8141
8125
  const plugin = window.Capacitor?.Plugins?.OysterunDashboardAuth;
8142
- if (plugin && typeof plugin.save === "function") {
8126
+ if (
8127
+ params.get("oysterun_auth_restore") !== "1" &&
8128
+ plugin &&
8129
+ typeof plugin.save === "function"
8130
+ ) {
8143
8131
  void plugin
8144
8132
  .save({ origin: window.location.origin, token })
8145
8133
  .catch(() => {});
8146
8134
  }
8147
8135
  params.delete("oysterun_token");
8148
8136
  params.delete("oysterun_bootstrap");
8137
+ params.delete("oysterun_auth_restore");
8149
8138
  const nextHash = params.toString() ? `#${params.toString()}` : "";
8150
8139
  window.history.replaceState(
8151
8140
  null,
@@ -9502,6 +9491,7 @@
9502
9491
 
9503
9492
  <div
9504
9493
  id="create-error"
9494
+ role="alert"
9505
9495
  class="error-box hidden settings-order-actions"
9506
9496
  ></div>
9507
9497
  <div class="toolbar setup-actions settings-order-actions">
@@ -29088,6 +29078,66 @@ Waiting for Claude login output…</pre
29088
29078
  : "ready";
29089
29079
  }
29090
29080
 
29081
+ function renderHostProviderModelRefreshStatus(providerId) {
29082
+ const el = $(`host-${providerId}-model-refresh-status`);
29083
+ if (!el) return;
29084
+ const status = providerCatalogState.providers.find(
29085
+ (entry) => entry.id === providerId
29086
+ )?.modelCatalogStatus;
29087
+ if (!status) return;
29088
+ const formatTime = (value, timeZone) =>
29089
+ value
29090
+ ? new Date(value).toLocaleString(
29091
+ undefined,
29092
+ timeZone ? { timeZone } : undefined
29093
+ )
29094
+ : "Not yet";
29095
+ const source =
29096
+ status.last_attempt_source === "background"
29097
+ ? "Background"
29098
+ : status.last_attempt_source
29099
+ ? "Manual"
29100
+ : "";
29101
+ const lines = [
29102
+ `Last successful refresh: ${formatTime(status.last_success_at)}`,
29103
+ status.last_attempt_at
29104
+ ? `Latest attempt: ${source} ${
29105
+ status.last_attempt_status || "unknown"
29106
+ } · ${formatTime(status.last_attempt_at)}`
29107
+ : "No refresh attempt recorded.",
29108
+ ];
29109
+ if (status.last_attempt_reason)
29110
+ lines.push(
29111
+ `Reason: ${
29112
+ status.last_attempt_reason === "provider_unavailable"
29113
+ ? "Provider command is unavailable."
29114
+ : status.last_attempt_reason
29115
+ }`
29116
+ );
29117
+ if (status.using_previous_catalog)
29118
+ lines.push("Still using the previous model list.");
29119
+ lines.push(
29120
+ status.next_refresh_at
29121
+ ? `Next background refresh: ${formatTime(
29122
+ status.next_refresh_at,
29123
+ status.refresh_time_zone
29124
+ )} (Host time${
29125
+ status.refresh_time_zone ? ` · ${status.refresh_time_zone}` : ""
29126
+ })`
29127
+ : "Next background refresh: not scheduled."
29128
+ );
29129
+ const transient = getProviderModelRefreshState(providerId);
29130
+ if (
29131
+ transient.error &&
29132
+ !status.last_attempt_reason?.includes(transient.error)
29133
+ )
29134
+ lines.push(transient.error);
29135
+ if (transient.refreshing) lines.push("Refreshing models…");
29136
+ el.textContent = lines.join("\n");
29137
+ el.style.whiteSpace = "pre-line";
29138
+ el.style.overflowWrap = "anywhere";
29139
+ }
29140
+
29091
29141
  function renderProviderModelRefreshControls() {
29092
29142
  const createProviderId = getEffectiveCreateRuntime(createRuntime);
29093
29143
  renderProviderModelRefreshControlInstance({
@@ -29106,6 +29156,7 @@ Waiting for Claude login output…</pre
29106
29156
  statusEl: $(`host-${providerId}-model-refresh-status`),
29107
29157
  disabled: hostDisabled,
29108
29158
  });
29159
+ renderHostProviderModelRefreshStatus(providerId);
29109
29160
  }
29110
29161
  }
29111
29162
 
@@ -34788,6 +34839,14 @@ Waiting for Claude login output…</pre
34788
34839
  if (operation.running === true) {
34789
34840
  return operation.phase || "Installing...";
34790
34841
  }
34842
+ if (
34843
+ ["update_complete", "rolled_back", "restart_complete"].includes(
34844
+ operation.status
34845
+ ) &&
34846
+ operation.user_path_verification
34847
+ ) {
34848
+ return operation.phase;
34849
+ }
34791
34850
  if (operation.status === "update_complete") {
34792
34851
  return operation.final_observed_version
34793
34852
  ? `Oysterun updated to ${operation.final_observed_version}.`
@@ -35042,6 +35101,12 @@ Waiting for Claude login output…</pre
35042
35101
  }
35043
35102
 
35044
35103
  function isConfirmedDashboardAuthRejection(err) {
35104
+ if (
35105
+ isOysterunCapacitorIOSRuntime() &&
35106
+ getOysterunDashboardAuthPlugin()
35107
+ ) {
35108
+ return err?.confirmedDashboardTokenRejection === true;
35109
+ }
35045
35110
  const status = Number(err?.status || 0);
35046
35111
  if (status === 401 || status === 403) return true;
35047
35112
  const message = String(err?.message || "").trim();
@@ -35138,6 +35203,13 @@ Waiting for Claude login output…</pre
35138
35203
  const err = new Error(data.error || `HTTP ${resp.status}`);
35139
35204
  err.status = resp.status;
35140
35205
  err.data = data;
35206
+ err.confirmedDashboardTokenRejection =
35207
+ method === "GET" &&
35208
+ path === "/dev/preferences" &&
35209
+ Boolean(authToken) &&
35210
+ authToken === syncTokenFromStorage() &&
35211
+ (resp.status === 401 || resp.status === 403) &&
35212
+ data.error === "Authentication required";
35141
35213
  throw err;
35142
35214
  }
35143
35215
  return data;
@@ -35172,6 +35244,13 @@ Waiting for Claude login output…</pre
35172
35244
  const err = new Error(data.error || `HTTP ${resp.status}`);
35173
35245
  err.status = resp.status;
35174
35246
  err.data = data;
35247
+ err.confirmedDashboardTokenRejection =
35248
+ method === "GET" &&
35249
+ path === "/dev/preferences" &&
35250
+ Boolean(authToken) &&
35251
+ authToken === syncTokenFromStorage() &&
35252
+ (resp.status === 401 || resp.status === 403) &&
35253
+ data.error === "Authentication required";
35175
35254
  throw err;
35176
35255
  }
35177
35256
  return resp;
@@ -40947,6 +41026,29 @@ Waiting for Claude login output…</pre
40947
41026
  return "capacitor://localhost/index.html?logged_out=1";
40948
41027
  }
40949
41028
 
41029
+ let dashboardNativeRecoveryPending = false;
41030
+ function redirectToOysterunCapacitorBootstrapForRecovery() {
41031
+ if (
41032
+ !isOysterunCapacitorIOSRuntime() ||
41033
+ !getOysterunDashboardAuthPlugin()
41034
+ )
41035
+ return false;
41036
+ if (dashboardNativeRecoveryPending) return true;
41037
+ dashboardNativeRecoveryPending = true;
41038
+ const recoveryUrl = new URL("capacitor://localhost/index.html");
41039
+ recoveryUrl.searchParams.set(
41040
+ "auth_recovery",
41041
+ "local_browser_token_missing"
41042
+ );
41043
+ recoveryUrl.searchParams.set("host_origin", window.location.origin);
41044
+ const route = window.location.pathname + window.location.search;
41045
+ if (/^\/app(?:\/|\?|$)/.test(route))
41046
+ recoveryUrl.searchParams.set("return_route", route);
41047
+ showAuthCheckingState("Opening Oysterun...");
41048
+ window.location.replace(recoveryUrl.toString());
41049
+ return true;
41050
+ }
41051
+
40950
41052
  function resetDashboardRuntimeStateForLogout() {
40951
41053
  clearHostRestartTransientState();
40952
41054
  token = null;
@@ -41659,7 +41761,7 @@ Waiting for Claude login output…</pre
41659
41761
 
41660
41762
  function shouldAbortAppBootForLoggedOutState() {
41661
41763
  if (syncTokenFromStorage()) return false;
41662
- if (redirectToOysterunCapacitorBootstrapAfterLogout()) return true;
41764
+ if (redirectToOysterunCapacitorBootstrapForRecovery()) return true;
41663
41765
  showRealLoginFormState();
41664
41766
  setLoginBusy(false);
41665
41767
  startLoginAuthRecoveryLoop();
@@ -41801,6 +41903,11 @@ Waiting for Claude login output…</pre
41801
41903
  }
41802
41904
 
41803
41905
  async function handleStoredTokenBootFailure(err, opts = {}) {
41906
+ if (
41907
+ !syncTokenFromStorage() &&
41908
+ redirectToOysterunCapacitorBootstrapForRecovery()
41909
+ )
41910
+ return;
41804
41911
  const classification = classifyDashboardAuthNetworkError(err);
41805
41912
  if (classification.state === DASHBOARD_AUTH_STATE.UNAUTHENTICATED) {
41806
41913
  token = null;
@@ -41924,6 +42031,7 @@ Waiting for Claude login output…</pre
41924
42031
  }
41925
42032
  if (!hadAuthToken) {
41926
42033
  if (!opts.notice && opts.noticeIsError !== true && !opts.route) {
42034
+ if (redirectToOysterunCapacitorBootstrapAfterLogout()) return;
41927
42035
  return;
41928
42036
  }
41929
42037
  if (
@@ -43260,6 +43368,23 @@ Waiting for Claude login output…</pre
43260
43368
  "",
43261
43369
  runtime: liveSession.provider || liveSession.runtime || null,
43262
43370
  model: liveSession.model || null,
43371
+ // Only editable setup values cross this boundary. Native/thread,
43372
+ // Matrix, transcript and execution identity remain on the source.
43373
+ setupConfig: {
43374
+ provider: liveSession.provider || liveSession.runtime || null,
43375
+ model: liveSession.model || null,
43376
+ reasoningEffort: liveSession.reasoningEffort || null,
43377
+ permissionMode: liveSession.permissionMode || null,
43378
+ approvalPolicy: liveSession.approvalPolicy || null,
43379
+ sharedAllowedPaths: getAgentProfileWorkspaceAllowedPathValues(
43380
+ liveSession.workspacePolicy
43381
+ ),
43382
+ notifications: {
43383
+ notifications_enabled:
43384
+ liveSession.notificationSettings?.notifications_enabled !==
43385
+ false,
43386
+ },
43387
+ },
43263
43388
  created_at: liveSession.startedAt || liveSession.started_at || null,
43264
43389
  last_active_at:
43265
43390
  liveSession.lastActiveAt || liveSession.last_active_at || null,
@@ -51982,14 +52107,19 @@ Waiting for Claude login output…</pre
51982
52107
  setVisible("resume-context-note", true);
51983
52108
  setResumeFolderLock(true);
51984
52109
  } else {
51985
- setText("config-panel-mode", "Prefilled from history");
52110
+ setText(
52111
+ "config-panel-mode",
52112
+ opts.liveSetup ? "Duplicate Setup" : "Prefilled from history"
52113
+ );
51986
52114
  setText(
51987
52115
  "config-panel-title",
51988
52116
  `Open ${getHistorySessionDisplayName(record)}`
51989
52117
  );
51990
52118
  setText(
51991
52119
  "config-panel-subtitle",
51992
- "This fills Session Setup with the saved agent and folder. Runtime settings come from the current config layers for that folder."
52120
+ opts.liveSetup
52121
+ ? "Review or edit the current session settings. A new session starts only when you press Start."
52122
+ : "This fills Session Setup with the saved agent and folder. Runtime settings come from the current config layers for that folder."
51993
52123
  );
51994
52124
  setVisible("resume-context-note", false);
51995
52125
  setResumeFolderLock(false);
@@ -52004,7 +52134,12 @@ Waiting for Claude login output…</pre
52004
52134
  : null;
52005
52135
  await loadFolderConfigIntoCreateForm(record.agent_folder, {
52006
52136
  fillAgentIdIfEmpty: false,
52007
- providerOverride: opts.resume ? pendingResumeSourceRuntime : null,
52137
+ providerOverride: opts.liveSetup
52138
+ ? record.runtime
52139
+ : opts.resume
52140
+ ? pendingResumeSourceRuntime
52141
+ : null,
52142
+ setupConfig: opts.liveSetup ? record.setupConfig : null,
52008
52143
  modelOverride:
52009
52144
  resumeDisposition?.resume_identity_kind === "host_session"
52010
52145
  ? sanitizeRouteText(record.model)
@@ -52028,6 +52163,47 @@ Waiting for Claude login output…</pre
52028
52163
  let record = sessionHistory.find(
52029
52164
  (entry) => entry.session_id === sessionId
52030
52165
  );
52166
+ if (opts.resume !== true && getLiveSession(sessionId)) {
52167
+ // A Running row owns Duplicate Setup even if History has an older
52168
+ // copy. Collection rows are compact, so hydrate current settings.
52169
+ try {
52170
+ const payload = await apiWithAuthRetry(
52171
+ "GET",
52172
+ `/session/status?session_id=${encodeURIComponent(sessionId)}`
52173
+ );
52174
+ const route = getCurrentRoute();
52175
+ if (
52176
+ route.screen !== "session-setup" ||
52177
+ route.sourceSessionId !== sessionId
52178
+ )
52179
+ return;
52180
+ if (payload?.session_id !== sessionId || payload.alive !== true) {
52181
+ throw new Error(
52182
+ "The source session is no longer running. Return to Sessions and choose a source again."
52183
+ );
52184
+ }
52185
+ syncLiveSessionFromStatusPayload(payload);
52186
+ record = historyRecordFromLiveSession(getLiveSession(sessionId));
52187
+ opts = { ...opts, liveSetup: true };
52188
+ } catch (err) {
52189
+ const route = getCurrentRoute();
52190
+ if (
52191
+ route.screen !== "session-setup" ||
52192
+ route.sourceSessionId !== sessionId
52193
+ )
52194
+ return;
52195
+ clearPendingResume();
52196
+ showError(
52197
+ "create-error",
52198
+ `Could not load current session settings: ${err.message}`
52199
+ );
52200
+ showBanner(
52201
+ `Could not load current session settings: ${err.message}`,
52202
+ true
52203
+ );
52204
+ return;
52205
+ }
52206
+ }
52031
52207
  if (!record && opts.resume === true && opts.branch === true) {
52032
52208
  record = historyRecordFromLiveSession(getLiveSession(sessionId));
52033
52209
  if (record) {
@@ -52038,11 +52214,10 @@ Waiting for Claude login output…</pre
52038
52214
  }
52039
52215
  }
52040
52216
  if (!record) {
52041
- showBanner(
52042
- `Saved session ${sessionId} was not found in local history.`,
52043
- true
52044
- );
52045
- await navigateToRoute(buildSessionsRoute(), { replaceHistory: true });
52217
+ clearPendingResume();
52218
+ const message = `Session ${sessionId} is no longer available. Return to Sessions and choose another source.`;
52219
+ showError("create-error", message);
52220
+ showBanner(message, true);
52046
52221
  return;
52047
52222
  }
52048
52223
  let resumeUnavailableNotice = "";
@@ -53278,37 +53453,12 @@ Waiting for Claude login output…</pre
53278
53453
  const intervalLabel = row.interval_token
53279
53454
  ? formatSessionLoopIntervalToken(row.interval_token)
53280
53455
  : "--";
53281
- const incident = row.active_incident || null;
53282
53456
  const reasonLabel =
53283
53457
  row.suspension_reason === "checking_definition_availability"
53284
53458
  ? "Checking the shared Loop definition. Enabled intent is preserved."
53285
53459
  : row.suspension_reason === "definition_unavailable_confirmed"
53286
53460
  ? "Definition unavailable. This Loop is suspended without changing enabled intent."
53287
- : row.suspension_reason === "definition_changed_requires_review"
53288
- ? "Definition changed. Review it before Oysterun runs the updated command."
53289
- : row.suspension_reason === "legacy_reconciliation_intent_loss"
53290
- ? "A previous reconciliation may have stranded this Loop. Choose whether to restore it."
53291
53461
  : "";
53292
- const recoveryButtons = incident
53293
- ? (row.recovery_options || [])
53294
- .filter((option) => option !== "open_loop")
53295
- .map((option) => {
53296
- const label =
53297
- option === "use_updated_definition"
53298
- ? "Use updated definition"
53299
- : option === "restore_previous_enabled_state"
53300
- ? "Restore previous enabled state"
53301
- : option === "keep_disabled"
53302
- ? "Keep disabled"
53303
- : "Restore";
53304
- return `<button class="btn-ghost session-loop-recovery-action" type="button" data-loop-action="recover" data-loop-id="${esc(
53305
- row.id
53306
- )}" data-loop-recovery-action="${esc(option)}">${esc(
53307
- label
53308
- )}</button>`;
53309
- })
53310
- .join("")
53311
- : "";
53312
53462
  return `
53313
53463
  <article
53314
53464
  class="scheduler-row session-loop-row"
@@ -53351,15 +53501,6 @@ Waiting for Claude login output…</pre
53351
53501
  )}">${esc(reasonLabel)}</div>`
53352
53502
  : ""
53353
53503
  }
53354
- ${
53355
- incident
53356
- ? `<div class="session-loop-recovery-actions" data-oysterun-session-loop-incident="${esc(
53357
- incident.id
53358
- )}">${recoveryButtons}<button class="btn-ghost session-loop-recovery-action" type="button" data-loop-action="copy-diagnostic" data-loop-id="${esc(
53359
- row.id
53360
- )}">Copy diagnostic</button></div>`
53361
- : ""
53362
- }
53363
53504
  </div>
53364
53505
  <button
53365
53506
  class="scheduler-row-menu-button"
@@ -53634,48 +53775,6 @@ Waiting for Claude login output…</pre
53634
53775
  }
53635
53776
  }
53636
53777
 
53637
- async function resolveSessionLoopIncident(scheduleId, action) {
53638
- const liveSession = getSelectedLiveSession();
53639
- if (!liveSession) return;
53640
- try {
53641
- await api(
53642
- "POST",
53643
- `/session/loops/${encodeURIComponent(scheduleId)}/recovery`,
53644
- { session_id: liveSession.sessionId, action }
53645
- );
53646
- await loadSessionLoopSchedules(liveSession.sessionId, {
53647
- force: true,
53648
- });
53649
- showBanner("Loop recovery choice saved.");
53650
- } catch (err) {
53651
- sessionLoopState = {
53652
- ...sessionLoopState,
53653
- error: err.message || String(err),
53654
- };
53655
- renderSessionLoopSection(liveSession);
53656
- }
53657
- }
53658
-
53659
- async function copySessionLoopDiagnostic(scheduleId) {
53660
- const row = findSessionLoopRow(scheduleId);
53661
- if (!row) return;
53662
- const diagnostic = JSON.stringify(
53663
- {
53664
- loop_id: row.id,
53665
- status: row.status,
53666
- suspension_reason: row.suspension_reason,
53667
- definition_generation: row.definition_generation,
53668
- definition_revision: row.definition_revision,
53669
- candidate_definition_revision: row.candidate_definition_revision,
53670
- incident_id: row.active_incident?.id || null,
53671
- },
53672
- null,
53673
- 2
53674
- );
53675
- await navigator.clipboard.writeText(diagnostic);
53676
- showBanner("Loop diagnostic copied.");
53677
- }
53678
-
53679
53778
  async function deleteSessionLoop(scheduleId) {
53680
53779
  const liveSession = getSelectedLiveSession();
53681
53780
  if (!liveSession) return;
@@ -53761,17 +53860,6 @@ Waiting for Claude login output…</pre
53761
53860
  }
53762
53861
  return true;
53763
53862
  }
53764
- if (action === "recover") {
53765
- void resolveSessionLoopIncident(
53766
- scheduleId,
53767
- button.getAttribute("data-loop-recovery-action") || ""
53768
- );
53769
- return true;
53770
- }
53771
- if (action === "copy-diagnostic") {
53772
- void copySessionLoopDiagnostic(scheduleId);
53773
- return true;
53774
- }
53775
53863
  return false;
53776
53864
  }
53777
53865
 
@@ -64623,12 +64711,15 @@ Waiting for Claude login output…</pre
64623
64711
  const providerQuery = opts.providerOverride
64624
64712
  ? `&provider=${encodeURIComponent(opts.providerOverride)}`
64625
64713
  : "";
64626
- const data = await api(
64714
+ const folderConfig = await api(
64627
64715
  "GET",
64628
64716
  `/dev/folder-config?path=${encodeURIComponent(
64629
64717
  folderPath
64630
64718
  )}${providerQuery}`
64631
64719
  );
64720
+ const data = opts.setupConfig
64721
+ ? { ...folderConfig, ...opts.setupConfig }
64722
+ : folderConfig;
64632
64723
  const resolvedFolderPath = data.agent_folder || folderPath;
64633
64724
  const currentFolderPath = String(
64634
64725
  $("create-agent-folder").value || ""
@@ -64748,6 +64839,39 @@ Waiting for Claude login output…</pre
64748
64839
  preserveSelection: true,
64749
64840
  });
64750
64841
  $("create-model").value = model;
64842
+ if (opts.setupConfig) {
64843
+ // Preserve explicit live choices even if catalog/defaults
64844
+ // have changed; use the existing editable snapshot controls.
64845
+ applySelectValueFromSnapshot(
64846
+ $("create-model"),
64847
+ data.model,
64848
+ getNormalizedProviderModelSelection(
64849
+ provider,
64850
+ data.model,
64851
+ model
64852
+ ).options,
64853
+ (value) => getProviderModelLabel(provider, value)
64854
+ );
64855
+ applySelectValueFromSnapshot(
64856
+ getCreateReasoningEffortSelect(provider),
64857
+ data.reasoningEffort,
64858
+ getNormalizedProviderReasoningEffortSelection(
64859
+ provider,
64860
+ data.model,
64861
+ data.reasoningEffort,
64862
+ reasoningEffort
64863
+ ).options
64864
+ );
64865
+ const policy =
64866
+ getCreateOysterunPermissionPolicyKind(provider) ===
64867
+ "permission_mode"
64868
+ ? data.permissionMode
64869
+ : data.approvalPolicy;
64870
+ applySelectValueFromSnapshot(
64871
+ getCreateOysterunPermissionPolicyControl(provider),
64872
+ policy
64873
+ );
64874
+ }
64751
64875
  }
64752
64876
  }
64753
64877
  }
@@ -65658,7 +65782,7 @@ Waiting for Claude login output…</pre
65658
65782
  void maybeAutoRegisterOysterunIOSPush();
65659
65783
  },
65660
65784
  });
65661
- } else if (!redirectToOysterunCapacitorBootstrapAfterLogout()) {
65785
+ } else if (!redirectToOysterunCapacitorBootstrapForRecovery()) {
65662
65786
  resetCreateForm();
65663
65787
  renderPendingAttachments();
65664
65788
  updateComposerAvailability();
@@ -1,4 +1,4 @@
1
- import{g as ee,c as Y,r as K,j as Z}from"./index-BlWA-FTm.js";var X={exports:{}};(function(e){var t=typeof window<"u"?window:typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope?self:{};/**
1
+ import{g as ee,c as Y,r as K,j as Z}from"./index-BKVXuim6.js";var X={exports:{}};(function(e){var t=typeof window<"u"?window:typeof WorkerGlobalScope<"u"&&self instanceof WorkerGlobalScope?self:{};/**
2
2
  * Prism: Lightweight, robust, elegant syntax highlighting
3
3
  *
4
4
  * @license MIT <https://opensource.org/licenses/MIT>