@agimon-ai/doompi-workflow 0.0.1-alpha.95 → 0.0.1-alpha.97

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.
@@ -3321,6 +3321,27 @@ const ERROR_COLOUR = "error";
3321
3321
  * user in a session that will not close.
3322
3322
  */
3323
3323
  const SHUTDOWN_FINALIZE_TIMEOUT_MS = 1e4;
3324
+ /**
3325
+ * Pi awaits extension disposal before it exits the process, so any unbounded
3326
+ * wait in dispose keeps an `--auto-stop` session alive after it asked to stop.
3327
+ */
3328
+ const SHUTDOWN_STEP_TIMEOUT_MS = 5e3;
3329
+ /**
3330
+ * Rejects as soon as the signal aborts, so a registry read that never answers
3331
+ * cannot hold the readiness task, and every disposal waiting on it, open.
3332
+ */
3333
+ function untilAborted(work, signal) {
3334
+ if (signal.aborted) return Promise.reject(signal.reason);
3335
+ return new Promise((resolveWork, rejectWork) => {
3336
+ const onAbort = () => rejectWork(signal.reason);
3337
+ signal.addEventListener("abort", onAbort, { once: true });
3338
+ work.then(resolveWork, rejectWork).finally(() => signal.removeEventListener("abort", onAbort));
3339
+ });
3340
+ }
3341
+ /** Resolves when the work does or the timeout passes; a rejection still propagates. */
3342
+ async function withinTimeout(work, timeoutMs) {
3343
+ await Promise.race([work, new Promise((settle) => setTimeout(settle, timeoutMs).unref?.())]);
3344
+ }
3324
3345
  const FOLLOW_INTERVAL_MS = 2e3;
3325
3346
  const TAIL_LINES = 24;
3326
3347
  /** Below these a resized run has no room left to draw, so it keeps its own size and the panel clips. */
@@ -4939,10 +4960,10 @@ function createWorkflowPiRuntime(pi, options) {
4939
4960
  const retired = () => ownReadinessAbort.signal.aborted || !ownsSession();
4940
4961
  signal.throwIfAborted();
4941
4962
  if (retired()) return { value: void 0 };
4942
- await startRunControl(ctx);
4963
+ await untilAborted(startRunControl(ctx), signal);
4943
4964
  signal.throwIfAborted();
4944
4965
  if (retired()) return { value: void 0 };
4945
- await refreshStatus(ctx, false);
4966
+ await untilAborted(refreshStatus(ctx, false), signal);
4946
4967
  signal.throwIfAborted();
4947
4968
  if (retired()) return { value: void 0 };
4948
4969
  lifecycleNarrationReady = true;
@@ -4976,13 +4997,13 @@ function createWorkflowPiRuntime(pi, options) {
4976
4997
  const ownedReadiness = standaloneReadiness;
4977
4998
  standaloneReadiness = void 0;
4978
4999
  if (ownedReadiness) await runCleanup("dispose standalone workflow readiness", () => ownedReadiness.dispose());
4979
- else if (pendingReadiness) await Promise.allSettled([pendingReadiness.then((handle) => handle.wait())]);
5000
+ else if (pendingReadiness) await withinTimeout(Promise.allSettled([pendingReadiness.then((handle) => handle.wait())]), SHUTDOWN_STEP_TIMEOUT_MS);
4980
5001
  if (pendingInlineRuns.size > 0) {
4981
5002
  for (const service of [runService, recoverService]) await runCleanup("interrupt an inline workflow", () => service.interrupt("SIGTERM", {
4982
5003
  phase: "workflow",
4983
5004
  source: "pi-session-shutdown"
4984
5005
  }));
4985
- await Promise.race([Promise.allSettled(pendingInlineRuns), new Promise((settle) => setTimeout(settle, SHUTDOWN_FINALIZE_TIMEOUT_MS).unref?.())]);
5006
+ await withinTimeout(Promise.allSettled(pendingInlineRuns), SHUTDOWN_FINALIZE_TIMEOUT_MS);
4986
5007
  }
4987
5008
  if (monitorTimer) clearInterval(monitorTimer);
4988
5009
  monitorTimer = void 0;
@@ -5017,13 +5038,13 @@ function createWorkflowPiRuntime(pi, options) {
5017
5038
  const pendingCount = pendingInlineRuns.size;
5018
5039
  const activeTelemetry = telemetry;
5019
5040
  telemetry = void 0;
5020
- if (activeTelemetry) {
5041
+ if (activeTelemetry) await runCleanup("stop workflow telemetry", () => withinTimeout((async () => {
5021
5042
  await runCleanup("record the workflow session finish", () => activeTelemetry.recordEvent("doom_workflow.session_finished", {
5022
5043
  "workflow.pending_count": pendingCount,
5023
5044
  outcome: pendingCount === 0 ? "completed" : "interrupted"
5024
5045
  }));
5025
- await runCleanup("stop workflow telemetry", () => activeTelemetry.shutdown());
5026
- }
5046
+ await activeTelemetry.shutdown();
5047
+ })(), SHUTDOWN_STEP_TIMEOUT_MS));
5027
5048
  pendingInlineRuns.clear();
5028
5049
  pendingTerminalRuns.clear();
5029
5050
  deliveredTerminalRuns.clear();