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
@@ -27,6 +27,7 @@ import {
27
27
  recordHostTelemetryCounter,
28
28
  recordHostTelemetryFeature,
29
29
  } from "./host-telemetry.mjs";
30
+ import { resolveSchedulerRunTimeout } from "./scheduler-run-timeout-policy.mjs";
30
31
 
31
32
  const SCHEDULER_LOOP_ACTIVE_REASON =
32
33
  "P12.2 in-session loop CLI dispatch is enabled";
@@ -59,7 +60,7 @@ function recordSchedulerRunTelemetry(status) {
59
60
  recordHostTelemetryCounter("scheduler_run_count");
60
61
  if (status === "dispatched") {
61
62
  recordHostTelemetryCounter("scheduler_run_success_count");
62
- } else if (status === "failed") {
63
+ } else if (status === "failed" || status === "timed_out") {
63
64
  recordHostTelemetryCounter("scheduler_run_failed_count");
64
65
  }
65
66
  recordHostTelemetryFeature("scheduler");
@@ -404,6 +405,7 @@ function getHostScheduleRunOutcome(run) {
404
405
  ? metadata.provider_exit_code
405
406
  : null;
406
407
  if (run.status === "failed") return "failed";
408
+ if (run.status === "timed_out") return "timed_out";
407
409
  if (run.status === "skipped") return "skipped";
408
410
  if (exitCode === 0) return "success";
409
411
  return run.status || null;
@@ -423,8 +425,15 @@ function buildProviderRunMetadata({
423
425
  ? providerRun.exit_code
424
426
  : null;
425
427
  const signal = normalizeOptionalString(providerRun?.signal);
428
+ const timedOut =
429
+ signal === "timeout" ||
430
+ providerRun?.error_summary === "scheduler_provider_run_timed_out";
426
431
  const outcome =
427
- providerRun?.ok === true && exitCode === 0 ? "success" : "failed";
432
+ providerRun?.ok === true && exitCode === 0
433
+ ? "success"
434
+ : timedOut
435
+ ? "timed_out"
436
+ : "failed";
428
437
  const startedAt = normalizeOptionalString(providerRun?.started_at);
429
438
  const completedAt = normalizeOptionalString(providerRun?.completed_at);
430
439
  return {
@@ -449,7 +458,7 @@ function buildProviderRunMetadata({
449
458
  providerRun?.log_summary ||
450
459
  fallbackLogSummary ||
451
460
  "Host scheduler direct provider run finished",
452
- ...(outcome === "failed"
461
+ ...(outcome !== "success"
453
462
  ? {
454
463
  error_summary:
455
464
  providerRun?.error_summary ||
@@ -654,6 +663,7 @@ export class SchedulerService {
654
663
  portableDefinitionStore = null,
655
664
  clock = () => new Date(),
656
665
  recheckMs = SCHEDULER_BUSY_RECHECK_MS,
666
+ sessionLoopUnavailableGraceMs = undefined,
657
667
  sessionLoopService = null,
658
668
  } = {}) {
659
669
  this.store = store;
@@ -673,6 +683,9 @@ export class SchedulerService {
673
683
  new SessionLoopDefinitionService({
674
684
  clock,
675
685
  recheckMs,
686
+ ...(sessionLoopUnavailableGraceMs === undefined
687
+ ? {}
688
+ : { unavailableGraceMs: sessionLoopUnavailableGraceMs }),
676
689
  lifecycleStore: new SessionLoopLifecycleStore({
677
690
  configDir: store.configDir,
678
691
  clock,
@@ -916,6 +929,22 @@ export class SchedulerService {
916
929
  });
917
930
  }
918
931
 
932
+ resolveSessionLoopIncidentForGui({
933
+ hostSessionId,
934
+ agentId,
935
+ agentFolder,
936
+ scheduleId,
937
+ action,
938
+ }) {
939
+ return this.sessionLoopService.resolveIncidentForGui({
940
+ hostSessionId,
941
+ agentId,
942
+ agentFolder,
943
+ scheduleId,
944
+ action,
945
+ });
946
+ }
947
+
919
948
  clearSessionLoopRuntimeState({ hostSessionId, reason = "session_stop" }) {
920
949
  return this.sessionLoopService.clearRuntimeSession({
921
950
  hostSessionId,
@@ -962,6 +991,8 @@ export class SchedulerService {
962
991
  rule,
963
992
  timezone = getHostSystemTimezone(),
964
993
  enabled = true,
994
+ runTimeoutSeconds = undefined,
995
+ runTimeoutSource = null,
965
996
  }) {
966
997
  const normalizedRule = normalizeScheduleRule(rule, { timezone });
967
998
  const now = nowIso(this.clock);
@@ -985,6 +1016,10 @@ export class SchedulerService {
985
1016
  const scheduleHostSessionId = `portable:${normalizedTargetBinding.setup_snapshot.agent_folder}`;
986
1017
  const normalizedPrompt = normalizeHostSchedulePrompt(prompt);
987
1018
  const active = enabled === true;
1019
+ const runTimeout = resolveSchedulerRunTimeout(runTimeoutSeconds, {
1020
+ present: runTimeoutSeconds !== undefined,
1021
+ source: runTimeoutSource,
1022
+ });
988
1023
  return {
989
1024
  hostSessionId: scheduleHostSessionId,
990
1025
  agentId: normalizedAgentId,
@@ -996,6 +1031,7 @@ export class SchedulerService {
996
1031
  availabilityReason: active
997
1032
  ? HOST_SCHEDULE_ACTIVE_REASON
998
1033
  : HOST_SCHEDULE_UI_PAUSED_REASON,
1034
+ runTimeout,
999
1035
  metadata: {
1000
1036
  source: "p12_5_host_scheduler_dashboard_ui",
1001
1037
  schedule_rule: normalizedRule,
@@ -1026,6 +1062,7 @@ export class SchedulerService {
1026
1062
  rule,
1027
1063
  timezone = getHostSystemTimezone(),
1028
1064
  enabled = true,
1065
+ runTimeoutSeconds = undefined,
1029
1066
  }) {
1030
1067
  this.initialize();
1031
1068
  const normalized = this.normalizeDashboardHostScheduleInput({
@@ -1036,6 +1073,7 @@ export class SchedulerService {
1036
1073
  rule,
1037
1074
  timezone,
1038
1075
  enabled,
1076
+ runTimeoutSeconds,
1039
1077
  });
1040
1078
  const runtimeSetupSnapshot = normalized.metadata.target_binding.setup_snapshot;
1041
1079
  const schedule = this.portableDefinitionStore.createSchedule(
@@ -1052,6 +1090,10 @@ export class SchedulerService {
1052
1090
  schedule_rule: normalized.metadata.schedule_rule,
1053
1091
  timezone: normalized.metadata.timezone,
1054
1092
  setup_snapshot: runtimeSetupSnapshot,
1093
+ run_timeout_seconds: normalized.runTimeout.seconds,
1094
+ run_timeout_source: normalized.runTimeout.source === "explicit"
1095
+ ? "explicit"
1096
+ : "default",
1055
1097
  metadata: normalized.metadata,
1056
1098
  },
1057
1099
  { agentFolder: runtimeSetupSnapshot.agent_folder }
@@ -1092,6 +1134,15 @@ export class SchedulerService {
1092
1134
  const enabled = enabledProvided
1093
1135
  ? input.enabled === true
1094
1136
  : existing.status === "active";
1137
+ const runTimeout = inputHas("runTimeoutSeconds")
1138
+ ? resolveSchedulerRunTimeout(input.runTimeoutSeconds, {
1139
+ present: true,
1140
+ source: "explicit",
1141
+ })
1142
+ : resolveSchedulerRunTimeout(existing.run_timeout_seconds, {
1143
+ present: true,
1144
+ source: existing.run_timeout_source,
1145
+ });
1095
1146
  const normalized = this.normalizeDashboardHostScheduleInput({
1096
1147
  targetBinding,
1097
1148
  hostSessionId,
@@ -1100,6 +1151,8 @@ export class SchedulerService {
1100
1151
  rule,
1101
1152
  timezone,
1102
1153
  enabled,
1154
+ runTimeoutSeconds: runTimeout.seconds,
1155
+ runTimeoutSource: runTimeout.source,
1103
1156
  });
1104
1157
  const preserveNextRunAt =
1105
1158
  !inputHas("rule") &&
@@ -1124,6 +1177,8 @@ export class SchedulerService {
1124
1177
  schedule_rule: normalized.metadata.schedule_rule,
1125
1178
  timezone: normalized.metadata.timezone,
1126
1179
  setup_snapshot: normalized.metadata.target_binding.setup_snapshot,
1180
+ run_timeout_seconds: runTimeout.seconds,
1181
+ run_timeout_source: runTimeout.source,
1127
1182
  metadata: normalized.metadata,
1128
1183
  });
1129
1184
  return {
@@ -1293,6 +1348,7 @@ export class SchedulerService {
1293
1348
  prompt,
1294
1349
  rule,
1295
1350
  timezone = getHostSystemTimezone(),
1351
+ runTimeoutSeconds = undefined,
1296
1352
  }) {
1297
1353
  this.initialize();
1298
1354
  const normalized = this.normalizeDashboardHostScheduleInput({
@@ -1303,6 +1359,7 @@ export class SchedulerService {
1303
1359
  rule,
1304
1360
  timezone,
1305
1361
  enabled: true,
1362
+ runTimeoutSeconds,
1306
1363
  });
1307
1364
  const runtimeSetupSnapshot = normalized.metadata.target_binding.setup_snapshot;
1308
1365
  const schedule = this.portableDefinitionStore.createSchedule(
@@ -1319,6 +1376,10 @@ export class SchedulerService {
1319
1376
  schedule_rule: normalized.metadata.schedule_rule,
1320
1377
  timezone: normalized.metadata.timezone,
1321
1378
  setup_snapshot: runtimeSetupSnapshot,
1379
+ run_timeout_seconds: normalized.runTimeout.seconds,
1380
+ run_timeout_source: normalized.runTimeout.source === "explicit"
1381
+ ? "explicit"
1382
+ : "default",
1322
1383
  metadata: {
1323
1384
  ...normalized.metadata,
1324
1385
  source: "browser_root_portable_host_scheduler_model",
@@ -1451,7 +1512,12 @@ export class SchedulerService {
1451
1512
  }
1452
1513
 
1453
1514
  async drainSingleSessionLoopDue(loopSchedule, { now, dispatcher }) {
1454
- const { runtime, definition, state } = loopSchedule;
1515
+ const current = this.sessionLoopService.refreshDueLoopForDispatch(loopSchedule);
1516
+ if (!current) return {
1517
+ status: "skipped", schedule_id: loopSchedule.definition.id,
1518
+ reason: "loop_occurrence_superseded",
1519
+ };
1520
+ const { runtime, definition, state } = current;
1455
1521
  const triggeredAt = normalizeRequiredString(now, "now");
1456
1522
  const serializedSchedule = this.sessionLoopService.serializeForFeedback({
1457
1523
  definition,
@@ -1611,6 +1677,8 @@ export class SchedulerService {
1611
1677
  claimed_target_binding: structuredClone(targetBinding),
1612
1678
  trigger_basis: "schedule_rule_after_actual_trigger_time",
1613
1679
  actual_triggered_at: triggeredAt,
1680
+ run_timeout_seconds: schedule.run_timeout_seconds,
1681
+ run_timeout_source: schedule.run_timeout_source,
1614
1682
  ...buildHostScheduleDispatchProvenance({
1615
1683
  dispatchOrigin,
1616
1684
  dispatchAuthority,
@@ -1652,6 +1720,9 @@ export class SchedulerService {
1652
1720
  mailCapability
1653
1721
  );
1654
1722
  if (safeProviderRun?.ok !== true) {
1723
+ const timedOut =
1724
+ safeProviderRun?.signal === "timeout" ||
1725
+ safeProviderRun?.error_summary === "scheduler_provider_run_timed_out";
1655
1726
  const reason =
1656
1727
  safeProviderRun?.log_summary ||
1657
1728
  safeProviderRun?.error_summary ||
@@ -1662,7 +1733,7 @@ export class SchedulerService {
1662
1733
  const statusAfter = nextRunAt ? "active" : "stopped";
1663
1734
  const failedRun = this.store.updateScheduleRun(run.id, {
1664
1735
  completedAt: safeProviderRun?.completed_at || triggeredAt,
1665
- status: "failed",
1736
+ status: timedOut ? "timed_out" : "failed",
1666
1737
  error: reason,
1667
1738
  metadata: {
1668
1739
  ...claimedMetadata,
@@ -1703,7 +1774,7 @@ export class SchedulerService {
1703
1774
  });
1704
1775
  }
1705
1776
  return {
1706
- status: "failed",
1777
+ status: timedOut ? "timed_out" : "failed",
1707
1778
  schedule_id: schedule.id,
1708
1779
  run_id: failedRun.id,
1709
1780
  reason,
@@ -1863,6 +1934,8 @@ export class SchedulerService {
1863
1934
  claimed_target_binding: structuredClone(targetBinding),
1864
1935
  trigger_basis: "manual_dashboard_test_run",
1865
1936
  actual_triggered_at: triggeredAt,
1937
+ run_timeout_seconds: schedule.run_timeout_seconds,
1938
+ run_timeout_source: schedule.run_timeout_source,
1866
1939
  next_run_at_preserved: schedule.next_run_at,
1867
1940
  ...buildHostScheduleDispatchProvenance({
1868
1941
  dispatchOrigin,
@@ -1906,6 +1979,9 @@ export class SchedulerService {
1906
1979
  mailCapability
1907
1980
  );
1908
1981
  if (safeProviderRun?.ok !== true) {
1982
+ const timedOut =
1983
+ safeProviderRun?.signal === "timeout" ||
1984
+ safeProviderRun?.error_summary === "scheduler_provider_run_timed_out";
1909
1985
  const reason =
1910
1986
  safeProviderRun?.log_summary ||
1911
1987
  safeProviderRun?.error_summary ||
@@ -1914,7 +1990,7 @@ export class SchedulerService {
1914
1990
  : "scheduler_direct_provider_run_failed");
1915
1991
  const failedRun = this.store.updateScheduleRun(run.id, {
1916
1992
  completedAt: safeProviderRun?.completed_at || triggeredAt,
1917
- status: "failed",
1993
+ status: timedOut ? "timed_out" : "failed",
1918
1994
  error: reason,
1919
1995
  metadata: {
1920
1996
  ...claimedMetadata,
@@ -1956,10 +2032,10 @@ export class SchedulerService {
1956
2032
  const retainedSchedule =
1957
2033
  this.portableDefinitionStore.getSchedule(schedule.id);
1958
2034
  return {
1959
- status: "test_run_failed",
2035
+ status: timedOut ? "test_run_timed_out" : "test_run_failed",
1960
2036
  schedule_id: schedule.id,
1961
2037
  run: {
1962
- status: "failed",
2038
+ status: timedOut ? "timed_out" : "failed",
1963
2039
  schedule_id: schedule.id,
1964
2040
  run_id: failedRun.id,
1965
2041
  reason,
@@ -2609,6 +2685,10 @@ export class SchedulerService {
2609
2685
  provider_command: metadata.provider_command || null,
2610
2686
  exit_code: exitCode,
2611
2687
  signal: metadata.provider_signal || null,
2688
+ run_timeout_seconds:
2689
+ metadata.run_timeout_seconds || schedule.run_timeout_seconds,
2690
+ run_timeout_source:
2691
+ metadata.run_timeout_source || schedule.run_timeout_source,
2612
2692
  log_summary: redactHostScheduleTextForApi(
2613
2693
  metadata.log_summary,
2614
2694
  tokens
@@ -2656,12 +2736,19 @@ export class SchedulerService {
2656
2736
  targetBinding,
2657
2737
  inputText
2658
2738
  );
2739
+ const runTimeout = resolveSchedulerRunTimeout(schedule.run_timeout_seconds, {
2740
+ present: schedule.run_timeout_seconds !== undefined,
2741
+ source: schedule.run_timeout_source,
2742
+ });
2659
2743
  return {
2660
2744
  id: schedule.id,
2661
2745
  host_session: serializeHostScheduleSessionBoundary(schedule),
2662
2746
  agent: serializeHostScheduleAgentBoundary(schedule),
2663
2747
  schedule_kind: schedule.schedule_kind,
2664
2748
  status: schedule.status,
2749
+ run_timeout_seconds: runTimeout.seconds,
2750
+ run_timeout_source: runTimeout.source,
2751
+ run_timeout_explicit: runTimeout.explicit,
2665
2752
  next_run_at: schedule.next_run_at,
2666
2753
  rule: metadata.schedule_rule
2667
2754
  ? serializeScheduleRuleForSummary(metadata.schedule_rule)
@@ -79,6 +79,7 @@ function normalizeRunStatus(value) {
79
79
  "dispatched",
80
80
  "skipped",
81
81
  "failed",
82
+ "timed_out",
82
83
  "canceled",
83
84
  ].includes(status)
84
85
  ) {
@@ -240,7 +241,7 @@ export class SchedulerStore {
240
241
  scheduled_for TEXT NOT NULL,
241
242
  claimed_at TEXT,
242
243
  completed_at TEXT,
243
- status TEXT NOT NULL CHECK (status IN ('planned', 'claimed', 'dispatched', 'skipped', 'failed', 'canceled')),
244
+ status TEXT NOT NULL CHECK (status IN ('planned', 'claimed', 'dispatched', 'skipped', 'failed', 'timed_out', 'canceled')),
244
245
  dispatched_message_id TEXT,
245
246
  error TEXT,
246
247
  metadata_json TEXT,
@@ -352,6 +353,12 @@ export class SchedulerStore {
352
353
  if (hasForeignKeys(this.db, "schedule_runs")) {
353
354
  this.rebuildScheduleRunsWithoutForeignKeys();
354
355
  }
356
+ const scheduleRunsSql = this.db
357
+ .prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'schedule_runs'")
358
+ .get()?.sql;
359
+ if (!String(scheduleRunsSql || "").includes("'timed_out'")) {
360
+ this.rebuildScheduleRunsWithoutForeignKeys();
361
+ }
355
362
  if (hasForeignKeys(this.db, "schedule_run_logs")) {
356
363
  this.rebuildScheduleRunLogsWithoutForeignKeys();
357
364
  }
@@ -374,7 +381,7 @@ export class SchedulerStore {
374
381
  scheduled_for TEXT NOT NULL,
375
382
  claimed_at TEXT,
376
383
  completed_at TEXT,
377
- status TEXT NOT NULL CHECK (status IN ('planned', 'claimed', 'dispatched', 'skipped', 'failed', 'canceled')),
384
+ status TEXT NOT NULL CHECK (status IN ('planned', 'claimed', 'dispatched', 'skipped', 'failed', 'timed_out', 'canceled')),
378
385
  dispatched_message_id TEXT,
379
386
  error TEXT,
380
387
  metadata_json TEXT,