oysterun 1.6.0-beta.2 → 1.6.0-beta.21

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 (242) hide show
  1. package/bin/oysterun.mjs +64 -17
  2. package/dev/client/connectivity/completed-message-neighbor-click.mjs +78 -0
  3. package/dev/client/connectivity/completed-message-neighbor-contract.mjs +205 -0
  4. package/dev/client/connectivity/completed-message-visibility.d.mts +4 -4
  5. package/dev/client/connectivity/completed-message-visibility.mjs +14 -11
  6. package/dev/client/connectivity/desktop-chat-sidebar-preference.mjs +57 -0
  7. package/dev/client/connectivity/host-connection-feedback.mjs +12 -1
  8. package/dev/client/connectivity/managed-host-browser.mjs +10 -0
  9. package/dev/client/connectivity/session-navigation-intent.mjs +189 -0
  10. package/dev/client/connectivity/session-transition-state.mjs +18 -6
  11. package/dev/client/connectivity/test-completed-message-neighbor-click.mjs +180 -0
  12. package/dev/client/web/index.html +5367 -609
  13. package/dev/client/web-chat/dist/assets/{ReactPrism-BwJhidYf.js → ReactPrism-C6YiTZTC.js} +1 -1
  14. package/dev/client/web-chat/dist/assets/{ReactPrism-BwJhidYf.js.map → ReactPrism-C6YiTZTC.js.map} +1 -1
  15. package/dev/client/web-chat/dist/assets/SessionsSetupApp-CKJOSPFP.js +6442 -0
  16. package/dev/client/web-chat/dist/assets/SessionsSetupApp-CKJOSPFP.js.map +1 -0
  17. package/dev/client/web-chat/dist/assets/SessionsSetupApp-Dx09Uz-6.css +1 -0
  18. package/dev/client/web-chat/dist/assets/index-Ae5I4LHp.js +9 -0
  19. package/dev/client/web-chat/dist/assets/index-Ae5I4LHp.js.map +1 -0
  20. package/dev/client/web-chat/dist/assets/index-CN_FoTB1.js +2 -0
  21. package/dev/client/web-chat/dist/assets/index-CN_FoTB1.js.map +1 -0
  22. package/dev/client/web-chat/dist/assets/{index--1xmQ99x.js → index-DCQFwgGf.js} +2 -2
  23. package/dev/client/web-chat/dist/assets/{index--1xmQ99x.js.map → index-DCQFwgGf.js.map} +1 -1
  24. package/dev/client/web-chat/dist/assets/matrix-entry-BV7G38kH.css +10 -0
  25. package/dev/client/web-chat/dist/assets/matrix-entry-abAy3aOo.js +594 -0
  26. package/dev/client/web-chat/dist/assets/matrix-entry-abAy3aOo.js.map +1 -0
  27. package/dev/client/web-chat/dist/assets/{pdf-ZjtalfgI.js → pdf-DN7oVvM6.js} +5 -5
  28. package/dev/client/web-chat/dist/assets/pdf-DN7oVvM6.js.map +1 -0
  29. package/dev/client/web-chat/dist/assets/session-notice-DlyODy1z.css +1 -0
  30. package/dev/client/web-chat/dist/assets/web-BlYuDlOV.js +1 -0
  31. package/dev/client/web-chat/dist/assets/{web-c70YaskK.js.map → web-BlYuDlOV.js.map} +1 -1
  32. package/dev/client/web-chat/dist/assets/web-Dabw6cJi.js +1 -0
  33. package/dev/client/web-chat/dist/assets/{web-BzHcZK2M.js.map → web-Dabw6cJi.js.map} +1 -1
  34. package/dev/client/web-chat/dist/index.html +1 -2
  35. package/docs/routec/dev/cloud_deplyments.md +5 -0
  36. package/docs/routec/dev/npm_native_dependency_install.md +6 -2
  37. package/docs/routec/dev/npmjs_publish.md +55 -19
  38. package/docs/routec/dev/p262_setup_input_file.md +117 -0
  39. package/docs/routec/host2_turn_started_idempotency_diagnostics.md +8 -7
  40. package/docs/routec/host_setup.md +39 -10
  41. package/docs/routec/oysterun_operation_interface_spec.md +78 -2
  42. package/docs/routec/provider_contract.md +35 -5
  43. package/host-service/README.md +36 -0
  44. package/host-service/adapters/claude-code-adapter.mjs +48 -5
  45. package/host-service/adapters/codex-app-server-adapter.mjs +320 -18
  46. package/host-service/adapters/debug-fixture-provider-adapter.mjs +102 -1
  47. package/host-service/adapters/debug-large-tool-spillover-provider-adapter.mjs +2 -0
  48. package/host-service/adapters/debug-p135-codex-replay-provider-adapter.mjs +2 -0
  49. package/host-service/adapters/debug-routec-structural-replay-provider-adapter.mjs +2 -0
  50. package/host-service/agent-config.mjs +16 -5
  51. package/host-service/agent-folder-availability.mjs +41 -0
  52. package/host-service/apns-complete-message-dispatcher.mjs +1 -0
  53. package/host-service/assets/product-skills/Oysterun/modules/oysterun-find-context/SKILL.md +24 -0
  54. package/host-service/assets/product-skills/Oysterun/modules/oysterun-session-chat/SKILL.md +94 -5
  55. package/host-service/assets/product-skills/Oysterun/modules/oysterun-sessions/SKILL.md +103 -0
  56. package/host-service/assets/product-skills/Oysterun/modules/oysterun-website/SKILL.md +7 -0
  57. package/host-service/assets/product-skills/oysterun-find-context/SKILL.md +24 -0
  58. package/host-service/assets/product-skills/oysterun-session-chat/SKILL.md +94 -5
  59. package/host-service/assets/product-skills/oysterun-sessions/SKILL.md +103 -0
  60. package/host-service/assets/product-skills/oysterun-website/SKILL.md +7 -0
  61. package/host-service/callback-durable-store.mjs +354 -47
  62. package/host-service/callback-foundation.mjs +21 -1
  63. package/host-service/callback-host-integration.mjs +345 -30
  64. package/host-service/claude-acp-model-discovery.mjs +23 -18
  65. package/host-service/cli/assert-installer-reinstall-target.mjs +9 -0
  66. package/host-service/cli/installer-recovery-guidance.mjs +20 -0
  67. package/host-service/cli/prepare-restart-restore.mjs +2 -0
  68. package/host-service/cli/product-cli.mjs +34 -33
  69. package/host-service/cli/reconcile-initial-preflight.mjs +19 -0
  70. package/host-service/cli/recover-installer-lifecycle.mjs +24 -0
  71. package/host-service/cli/run-host-lifecycle.mjs +2 -0
  72. package/host-service/cli/run-staged-lifecycle-recovery.mjs +161 -0
  73. package/host-service/codex-model-discovery.mjs +23 -18
  74. package/host-service/complete-cli-uninstall.mjs +176 -0
  75. package/host-service/complete-message-notification-predicate.mjs +8 -6
  76. package/host-service/complete-message-notification-title.mjs +4 -0
  77. package/host-service/completed-session-unread.mjs +425 -42
  78. package/host-service/completed-turn-navigation.mjs +444 -144
  79. package/host-service/completed-turn-notification-observer.mjs +116 -0
  80. package/host-service/completed-turn-service.mjs +445 -0
  81. package/host-service/config.mjs +115 -9
  82. package/host-service/desired-open-session-state.mjs +331 -0
  83. package/host-service/fixtures/p218-completed-turn-notification.json +11 -0
  84. package/host-service/frp-agent.mjs +9 -9
  85. package/host-service/grok-acp-model-discovery.mjs +31 -33
  86. package/host-service/host-lifecycle-recovery.mjs +37 -0
  87. package/host-service/host-port-resolution.mjs +98 -0
  88. package/host-service/host-runtime-diagnostics.mjs +18 -1
  89. package/host-service/initial-preflight-recovery.mjs +71 -0
  90. package/host-service/installer-recovery-guidance.mjs +85 -0
  91. package/host-service/installer-reinstall-bindings.mjs +49 -0
  92. package/host-service/installer-reinstall-target.mjs +49 -0
  93. package/host-service/legacy-continuity-observation.mjs +33 -0
  94. package/host-service/lifecycle-compat-cli.mjs +13 -0
  95. package/host-service/lifecycle-compat-preload.mjs +89 -0
  96. package/host-service/lifecycle-compatibility.mjs +164 -0
  97. package/host-service/lifecycle-continuity-assets.mjs +222 -0
  98. package/host-service/lifecycle-continuity-probe.mjs +97 -0
  99. package/host-service/lifecycle-continuity-projection.mjs +29 -0
  100. package/host-service/lifecycle-continuity-runner.mjs +192 -0
  101. package/host-service/lifecycle-continuity.mjs +493 -0
  102. package/host-service/lifecycle-service-render-bundle.mjs +120 -0
  103. package/host-service/lifecycle-user-path.mjs +34 -0
  104. package/host-service/link-annotations.mjs +10 -0
  105. package/host-service/matrix-credential-issuer.mjs +32 -1
  106. package/host-service/matrix-event-correlator.mjs +166 -27
  107. package/host-service/matrix-facade.mjs +96 -19
  108. package/host-service/matrix-room-binding.mjs +24 -0
  109. package/host-service/matrix-transcript-read-adapter.mjs +17 -3
  110. package/host-service/model-discovery-guardian.mjs +40 -0
  111. package/host-service/model-discovery-process.mjs +141 -0
  112. package/host-service/onboard-lifecycle-status.mjs +28 -0
  113. package/host-service/onboard.mjs +479 -0
  114. package/host-service/package.json +2 -1
  115. package/host-service/portable-scheduler-definitions.mjs +28 -0
  116. package/host-service/product-runtime-host-origin.mjs +22 -0
  117. package/host-service/provider-model-params.mjs +14 -17
  118. package/host-service/provider-model-refresh-runner.mjs +124 -169
  119. package/host-service/provider-model-refresh-schedule.mjs +11 -0
  120. package/host-service/provider-resume-contract.mjs +9 -3
  121. package/host-service/restart-restore-state.mjs +25 -0
  122. package/host-service/retained-host-state-holder.mjs +57 -0
  123. package/host-service/routec-matrix-sqlite-store.mjs +155 -10
  124. package/host-service/routec-matrix-storage-adapter.mjs +208 -25
  125. package/host-service/routec-matrix-storage-paths.mjs +12 -0
  126. package/host-service/routec-request-delay-window.mjs +55 -0
  127. package/host-service/scheduler-acp-provider-runner.mjs +2 -1
  128. package/host-service/scheduler-direct-provider-runner.mjs +71 -9
  129. package/host-service/scheduler-run-timeout-policy.mjs +85 -0
  130. package/host-service/scheduler-service.mjs +96 -9
  131. package/host-service/scheduler-store.mjs +9 -2
  132. package/host-service/server.mjs +2202 -552
  133. package/host-service/service-definition-migration.mjs +10 -3
  134. package/host-service/session-collection-service.mjs +320 -0
  135. package/host-service/session-history.mjs +99 -15
  136. package/host-service/session-list-preview-service.mjs +87 -12
  137. package/host-service/session-list-projection-service.mjs +182 -0
  138. package/host-service/session-loop-definitions.mjs +702 -75
  139. package/host-service/session-manager.mjs +473 -38
  140. package/host-service/session-switcher-projection.mjs +11 -3
  141. package/host-service/session-tags.mjs +451 -0
  142. package/host-service/session-transcript-target.mjs +103 -0
  143. package/host-service/setup-input-file.mjs +91 -0
  144. package/host-service/setup-provider-model-defaults.mjs +53 -0
  145. package/host-service/setup.mjs +133 -101
  146. package/host-service/stopped-user-host-package.mjs +60 -0
  147. package/host-service/test-fixtures/p236-navigation-original.mjs +500 -0
  148. package/host-service/update-reminder-state.mjs +7 -0
  149. package/host-service/voice-input-receipt-store.mjs +60 -0
  150. package/package.json +1 -1
  151. package/static/oysterun-social-preview.png +0 -0
  152. package/static/site/assets/oysterun-social-preview.png +0 -0
  153. package/static/site/blog/en/index.html +17 -0
  154. package/static/site/blog/generated_manifest.json +9 -9
  155. package/static/site/blog/index.html +18 -0
  156. package/static/site/blog/voice-input-model-experiment/en/index.html +17 -0
  157. package/static/site/blog/voice-input-model-experiment/zh/index.html +17 -0
  158. package/static/site/blog/zh/index.html +17 -0
  159. package/static/site/docs/choose-and-recover-a-provider/en/index.html +17 -0
  160. package/static/site/docs/choose-and-recover-a-provider/zh/index.html +17 -0
  161. package/static/site/docs/configure-session-files-and-settings/en/index.html +17 -0
  162. package/static/site/docs/configure-session-files-and-settings/zh/index.html +17 -0
  163. package/static/site/docs/en/index.html +17 -0
  164. package/static/site/docs/generated_manifest.json +60 -60
  165. package/static/site/docs/host-authentication-and-connection/en/index.html +17 -0
  166. package/static/site/docs/host-authentication-and-connection/zh/index.html +17 -0
  167. package/static/site/docs/index.html +18 -0
  168. package/static/site/docs/install-and-use-a-skill/en/index.html +17 -0
  169. package/static/site/docs/install-and-use-a-skill/zh/index.html +17 -0
  170. package/static/site/docs/read-large-tool-results/en/index.html +17 -0
  171. package/static/site/docs/read-large-tool-results/zh/index.html +17 -0
  172. package/static/site/docs/recover-from-a-host-runtime-error/en/index.html +17 -0
  173. package/static/site/docs/recover-from-a-host-runtime-error/zh/index.html +17 -0
  174. package/static/site/docs/restore-work-after-a-host-restart/en/index.html +17 -0
  175. package/static/site/docs/restore-work-after-a-host-restart/zh/index.html +17 -0
  176. package/static/site/docs/send-images-and-media/en/index.html +17 -0
  177. package/static/site/docs/send-images-and-media/zh/index.html +17 -0
  178. package/static/site/docs/set-up-and-understand-a-host/en/index.html +17 -0
  179. package/static/site/docs/set-up-and-understand-a-host/zh/index.html +17 -0
  180. package/static/site/docs/understand-agent-activity/en/index.html +19 -2
  181. package/static/site/docs/understand-agent-activity/en/index.md +2 -2
  182. package/static/site/docs/understand-agent-activity/zh/index.html +19 -2
  183. package/static/site/docs/understand-agent-activity/zh/index.md +2 -2
  184. package/static/site/docs/use-the-oysterun-cli-safely/en/index.html +17 -0
  185. package/static/site/docs/use-the-oysterun-cli-safely/zh/index.html +17 -0
  186. package/static/site/docs/zh/index.html +17 -0
  187. package/static/site/en/index.html +18 -1
  188. package/static/site/en/index.md +1 -1
  189. package/static/site/faq/en/index.html +17 -0
  190. package/static/site/faq/index.html +18 -0
  191. package/static/site/faq/zh/index.html +17 -0
  192. package/static/site/getting-started/en/index.html +23 -1
  193. package/static/site/getting-started/en/index.md +7 -1
  194. package/static/site/getting-started/index.html +18 -0
  195. package/static/site/getting-started/zh/index.html +23 -1
  196. package/static/site/getting-started/zh/index.md +7 -1
  197. package/static/site/index.html +18 -0
  198. package/static/site/install.sh +676 -127
  199. package/static/site/overview/en/index.html +18 -1
  200. package/static/site/overview/en/index.md +2 -2
  201. package/static/site/overview/index.html +18 -0
  202. package/static/site/overview/zh/index.html +18 -1
  203. package/static/site/overview/zh/index.md +2 -2
  204. package/static/site/privacy/en/index.html +17 -0
  205. package/static/site/privacy/index.html +18 -0
  206. package/static/site/privacy/zh/index.html +17 -0
  207. package/static/site/zh/index.html +18 -1
  208. package/static/site/zh/index.md +1 -1
  209. package/static/site_source/content/tutorials/published/understand-agent-activity/en/article.html +2 -2
  210. package/static/site_source/content/tutorials/published/understand-agent-activity/zh/article.html +2 -2
  211. package/static/site_source/downloads/install.sh +676 -127
  212. package/static/site_source/manifests/host_install.json +2 -10
  213. package/static/site_source/pages/getting-started/en.html +6 -1
  214. package/static/site_source/pages/getting-started/zh.html +6 -1
  215. package/static/site_source/pages/home/en.html +1 -1
  216. package/static/site_source/pages/home/zh.html +1 -1
  217. package/static/site_source/pages/home_main.html +3 -2
  218. package/static/site_source/pages/overview/en.html +1 -1
  219. package/static/site_source/pages/overview/zh.html +1 -1
  220. package/tool_scripts/install_oysterun_update.mjs +78 -13
  221. package/tool_scripts/oysterun_continuity_transaction.mjs +438 -0
  222. package/tool_scripts/oysterun_npm_package_manifest.mjs +32 -0
  223. package/tool_scripts/oysterun_release_service.sh +5 -0
  224. package/tool_scripts/oysterun_service_common.sh +59 -24
  225. package/tool_scripts/oysterun_setup_input.sh +97 -0
  226. package/tool_scripts/oysterun_update_restart_runner.mjs +19 -3
  227. package/tool_scripts/p233_legacy_bootstrap.mjs +254 -0
  228. package/tool_scripts/resolve_user_host_port.mjs +15 -0
  229. package/tool_scripts/restart_oysterun.sh +8 -2
  230. package/tool_scripts/stack_dashboard_credentials.mjs +2 -1
  231. package/tool_scripts/status_oysterun_launch_agents.sh +13 -1
  232. package/tool_scripts/sync_host_stack_config.mjs +9 -6
  233. package/tool_scripts/test_environment_remote_cloud_deprovision.mjs +419 -0
  234. package/tool_scripts/uninstall_oysterun_launch_agents.sh +3 -5
  235. package/dev/client/web-chat/dist/assets/index-Ce9NZBZf.js +0 -129
  236. package/dev/client/web-chat/dist/assets/index-Ce9NZBZf.js.map +0 -1
  237. package/dev/client/web-chat/dist/assets/index-DzIClZ3T.js +0 -2
  238. package/dev/client/web-chat/dist/assets/index-DzIClZ3T.js.map +0 -1
  239. package/dev/client/web-chat/dist/assets/index-NYnaSGBb.css +0 -1
  240. package/dev/client/web-chat/dist/assets/pdf-ZjtalfgI.js.map +0 -1
  241. package/dev/client/web-chat/dist/assets/web-BzHcZK2M.js +0 -1
  242. package/dev/client/web-chat/dist/assets/web-c70YaskK.js +0 -1
@@ -0,0 +1,192 @@
1
+ import {
2
+ CONTINUITY_STATES, advanceContinuity, continuityDigest, continuityFailure, readContinuity, qualifyContinuityHost,
3
+ qualifyContinuityRestoreResult, qualifyContinuitySessions, qualifyContinuityTunnel,
4
+ recordContinuityRosterPending,
5
+ } from "./lifecycle-continuity.mjs";
6
+ import { fetchContinuityObservation } from "./lifecycle-continuity-probe.mjs";
7
+ import { lstatSync, readFileSync } from "node:fs";
8
+ import { join } from "node:path";
9
+
10
+ export function resolveContinuityQualificationOrigin({
11
+ connectionMode,
12
+ managedEndpoint,
13
+ directHostUrl,
14
+ loopbackOrigin,
15
+ }) {
16
+ // Old receipts did not retain connection_mode. Keep their Managed-first
17
+ // interpretation so a later Direct login cannot rewrite their authority.
18
+ // New receipts bind the selected runtime route explicitly: a dormant
19
+ // Managed endpoint remains identity metadata while Direct mode is active.
20
+ const retainedRoute = connectionMode === "direct"
21
+ ? directHostUrl
22
+ : managedEndpoint || directHostUrl;
23
+ const retainedOrigin = retainedRoute ? new URL(retainedRoute).origin : null;
24
+ if (!retainedOrigin) return loopbackOrigin;
25
+ const retainedUrl = new URL(retainedOrigin);
26
+ return retainedUrl.protocol === "https:" ||
27
+ ["127.0.0.1", "localhost", "[::1]"].includes(retainedUrl.hostname)
28
+ ? retainedOrigin
29
+ : loopbackOrigin;
30
+ }
31
+
32
+ // beta.9 did not store the room or adapter declaration in its outer-v1
33
+ // baseline. Its committed anchor must still resolve in the retained binding,
34
+ // or an empty Session must retain its exact deterministic Host-to-room binding,
35
+ // before the target may attach the room to this read-only legacy observation.
36
+ function qualifyLegacyObservation(rows, peer, configDir) {
37
+ if (rows.every((row) => row.matrix_room_id && row.adapter_resume_identity_kind)) return rows;
38
+ const bindingPath = join(configDir, "routec-matrix-bindings.json");
39
+ let bindings;
40
+ try {
41
+ const stat = lstatSync(bindingPath);
42
+ if (!stat.isFile() || stat.isSymbolicLink() || stat.size > 8 * 1024 * 1024) return rows;
43
+ bindings = JSON.parse(readFileSync(bindingPath, "utf8"));
44
+ if (!bindings || typeof bindings !== "object" || Array.isArray(bindings)) return rows;
45
+ } catch { return rows; }
46
+ return rows.map((row) => {
47
+ if (row.matrix_room_id && row.adapter_resume_identity_kind) return row;
48
+ const after = peer.find((candidate) => candidate.session_id === row.session_id);
49
+ const binding = bindings[row.session_id];
50
+ const anchors = row.history_anchors;
51
+ const anchored = Array.isArray(anchors) && anchors.length > 0 &&
52
+ anchors.every((anchor) => after?.history_anchors?.some((candidate) =>
53
+ candidate.event_id === anchor.event_id && candidate.sha256 === anchor.sha256));
54
+ const emptyDeterministic = Array.isArray(anchors) && anchors.length === 0 &&
55
+ Array.isArray(after?.history_anchors) && after.history_anchors.length === 0 &&
56
+ binding?.binding_source === "host_session_id_deterministic_room" &&
57
+ binding.matrix_room_id === `!oysterun-routec-${row.session_id}:oysterun.local`;
58
+ if (!after || !binding || binding.host_session_id !== row.session_id ||
59
+ !["codex", "claude", "xai"].includes(row.provider) ||
60
+ row.provider !== after.provider || !(anchored || emptyDeterministic)) return row;
61
+ return { ...row, matrix_binding_host_session_id: binding.host_session_id,
62
+ matrix_room_id: binding.matrix_room_id, adapter_resume_identity_kind: "provider_metadata",
63
+ adapter_registered: true };
64
+ });
65
+ }
66
+
67
+ /** Shared qualification used by the existing runner and the one-time adapter.
68
+ * Observations are live authenticated reads; the retained baseline is never
69
+ * replaced by a new observation after a restart or a failed qualification.
70
+ */
71
+ export async function qualifyLifecycleContinuity({
72
+ path, operationId, configDir, healthUrl, version, definitionDigest,
73
+ rollback = false, requireRestore = true, restartId = null,
74
+ timeoutMs = 180_000, onStage = () => {}, observe = fetchContinuityObservation,
75
+ }) {
76
+ const receipt = readContinuity(path, operationId);
77
+ const baseline = receipt.baseline;
78
+ const loopbackOrigin = new URL(healthUrl).origin;
79
+ // Fixed/local task stacks legitimately have no public route configured.
80
+ // Their retained user route is the exact loopback health origin selected by
81
+ // the canonical lifecycle command; it still receives the same authenticated
82
+ // user-path, Host, Session and history qualification below.
83
+ // The lifecycle grant is a privileged one-operation credential. Never send
84
+ // it to a configured plaintext Direct URL: qualify the same Host through
85
+ // the retained loopback listener instead. HTTPS Managed/Direct routes keep
86
+ // their normal authenticated user-path qualification.
87
+ const expectedOrigin = resolveContinuityQualificationOrigin({
88
+ connectionMode: baseline.host.connection_mode,
89
+ managedEndpoint: baseline.host.managed_endpoint,
90
+ directHostUrl: baseline.host.direct_host_url,
91
+ loopbackOrigin,
92
+ });
93
+ const result = {};
94
+ const advance = (stage, proof) => {
95
+ if (rollback) return;
96
+ const current = readContinuity(path, operationId);
97
+ if (CONTINUITY_STATES.indexOf(current.state) < CONTINUITY_STATES.indexOf(stage)) {
98
+ advanceContinuity(path, operationId, stage, proof);
99
+ }
100
+ };
101
+ const waitFor = async (stage, callback) => {
102
+ await onStage(stage);
103
+ const deadline = Date.now() + timeoutMs;
104
+ let failure;
105
+ do {
106
+ try { return await callback(); } catch (error) {
107
+ failure = error;
108
+ // Identity, lost history, explicit failed/skipped restores and changed
109
+ // resume IDs cannot be repaired by waiting. Provider boot and route
110
+ // readiness may be transient.
111
+ const transient = error.transient === true || new Set([
112
+ "p233_runtime_not_ready", "p233_http_status", "p233_authenticated_path",
113
+ "p233_restart_not_consumed", "p233_user_path_pending",
114
+ ]).has(error.code) || ["TypeError", "TimeoutError", "AbortError"].includes(error.name);
115
+ if (!transient) throw error;
116
+ if (Date.now() < deadline) await new Promise((resolve) => setTimeout(resolve, Math.min(1000, deadline - Date.now())));
117
+ }
118
+ } while (Date.now() < deadline);
119
+ throw failure;
120
+ };
121
+ const local = () => observe({ configDir, operationId, origin: loopbackOrigin });
122
+ const checkHost = (observation) => {
123
+ const proof = qualifyContinuityHost(baseline.host, observation.host, {
124
+ version, runtimeIdentityDigest: receipt.source.runtime_identity_digest,
125
+ expectNewPid: requireRestore, definitionDigest,
126
+ });
127
+ if (result.host && proof.pid !== result.host.pid) throw continuityFailure("host_qualification", "qualification_pid_changed", "Host PID changed during qualification; retain recovery assets.");
128
+ return proof;
129
+ };
130
+ const checkSessions = (observation) => {
131
+ if (requireRestore && (observation.restart_state !== "consumed" || observation.restart_id !== restartId)) {
132
+ throw continuityFailure("session_qualification", "restart_not_consumed", "Waiting for the exact fresh Session restore receipt.");
133
+ }
134
+ const source = qualifyLegacyObservation(baseline.sessions, observation.sessions, configDir);
135
+ const target = qualifyLegacyObservation(observation.sessions, source, configDir);
136
+ if (requireRestore && source.length > target.length) {
137
+ const expectedIds = new Set(source.map((row) => row.session_id));
138
+ const observedIds = target.map((row) => row.session_id);
139
+ const observedIsExpectedSubset = new Set(observedIds).size === observedIds.length &&
140
+ observedIds.every((sessionId) => expectedIds.has(sessionId));
141
+ if (observedIsExpectedSubset) {
142
+ const restoreResult = observation.restore_result?.session_restore;
143
+ // Failed/skipped or unproved restores are terminal even while another
144
+ // provider runtime is still becoming observable.
145
+ qualifyContinuityRestoreResult(source, restoreResult);
146
+ recordContinuityRosterPending(source, target, { path, operationId });
147
+ // Validate every already-observable Session before waiting for the
148
+ // absent runtime. Identity, room, history or observation errors fail
149
+ // immediately instead of being hidden by the partial roster.
150
+ const presentSource = target.map((row) => source.find((candidate) =>
151
+ candidate.session_id === row.session_id));
152
+ qualifyContinuitySessions(presentSource, target, restoreResult,
153
+ { requireRestore, path, operationId });
154
+ const waiting = continuityFailure("session_qualification", "roster_changed",
155
+ "Waiting for every receipt-restored Session to become observable and ready.");
156
+ waiting.transient = true;
157
+ throw waiting;
158
+ }
159
+ }
160
+ return qualifyContinuitySessions(source, target,
161
+ observation.restore_result?.session_restore, { requireRestore, path, operationId });
162
+ };
163
+ result.host = await waitFor("HOST_QUALIFIED", async () => checkHost(await local()));
164
+ advance("HOST_QUALIFIED", result.host);
165
+ result.sessions = await waitFor("SESSIONS_QUALIFIED", async () => {
166
+ const observation = await local();
167
+ checkHost(observation);
168
+ return checkSessions(observation);
169
+ });
170
+ advance("SESSIONS_QUALIFIED", result.sessions);
171
+ result.tunnel = await waitFor("TUNNEL_QUALIFIED", async () => {
172
+ const observation = await observe({ configDir, operationId, origin: expectedOrigin });
173
+ // A provider can exit during transport qualification. Commit only a fresh
174
+ // observation that still proves the same Host and complete live Sessions.
175
+ const freshHost = checkHost(observation);
176
+ const freshSessions = checkSessions(observation);
177
+ // The scoped route probe proves transport and Host identity; a real
178
+ // dashboard-authenticated request on that origin proves the normal user
179
+ // path separately. Waiting for a person is not part of mutation completion.
180
+ return {
181
+ ...qualifyContinuityTunnel({ origin: expectedOrigin, device_id: baseline.host.device_id, operation_id: operationId }, observation.route),
182
+ requalified_at: new Date().toISOString(), host: freshHost, sessions: freshSessions,
183
+ history_anchors_digest: continuityDigest(observation.sessions.map(row => ({
184
+ session_id: row.session_id, history_anchors: row.history_anchors,
185
+ }))),
186
+ authenticated_user_path: observation.authenticated_user_path?.pid === freshHost.pid
187
+ ? observation.authenticated_user_path : null,
188
+ };
189
+ });
190
+ advance("TUNNEL_QUALIFIED", result.tunnel);
191
+ return result;
192
+ }