@workerdeck/server 0.19.0 → 0.21.0

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.
package/build/index.mjs CHANGED
@@ -2016,6 +2016,10 @@ async function handleCommand(ctx, frame, runner) {
2016
2016
  case "interrupt":
2017
2017
  await runner.interrupt();
2018
2018
  return;
2019
+ case "clear_context":
2020
+ if (!runner.clearContext) throw new Error(`the ${runner.info().engine ?? "claude"} engine cannot clear a conversation`);
2021
+ await runner.clearContext();
2022
+ return;
2019
2023
  case "set_permission_mode":
2020
2024
  if (frame.mode === "bypassPermissions" && ctx.options.disableBypassPermissions) throw new Error("bypassPermissions is disabled on this server (disableBypassPermissions)");
2021
2025
  await runner.setPermissionMode(frame.mode);
@@ -2632,6 +2636,17 @@ var SessionParkManager = class {
2632
2636
  * one thing a runner doesn't carry on its public surface. */
2633
2637
  #configs = /* @__PURE__ */ new Map();
2634
2638
  /**
2639
+ * Sessions this process has written a dormant record for. Its only job is to
2640
+ * tell "the engine has not named its session *yet*" apart from "the engine
2641
+ * had named it and no longer has one" (a `conversation_reset` on an engine
2642
+ * whose fresh id is not known until its next turn) — the first is the normal
2643
+ * startup window and must cost no store write, the second must delete a
2644
+ * record that has gone stale. It is accurate for exactly the sessions that
2645
+ * matter: a woken session's runner is rebuilt with `resume` set, so it names
2646
+ * its engine session immediately and re-enters the set on its first save.
2647
+ */
2648
+ #remembered = /* @__PURE__ */ new Set();
2649
+ /**
2635
2650
  * In-flight store work per session, so operations on one record run in order.
2636
2651
  *
2637
2652
  * Load-bearing with any store whose writes are real I/O. `#park` must evict the
@@ -2721,6 +2736,10 @@ var SessionParkManager = class {
2721
2736
  case "system_init":
2722
2737
  this.#rememberDormant(runner);
2723
2738
  return;
2739
+ case "conversation_reset":
2740
+ this.#rememberDormant(runner);
2741
+ this.#persistLive(runner);
2742
+ return;
2724
2743
  case "session_closed":
2725
2744
  if (this.#closed) return;
2726
2745
  this.discard(runner.id);
@@ -2797,6 +2816,7 @@ var SessionParkManager = class {
2797
2816
  clearTimeout(this.#detachTimers.get(sessionId));
2798
2817
  this.#detachTimers.delete(sessionId);
2799
2818
  this.#configs.delete(sessionId);
2819
+ this.#remembered.delete(sessionId);
2800
2820
  for (const [executionId, owner] of this.#owners) if (owner === sessionId) this.#forget(executionId);
2801
2821
  for (const [executionId, owner] of this.#settled) if (owner === sessionId) this.#settled.delete(executionId);
2802
2822
  await this.#queue(sessionId, () => this.#options.store.delete(sessionId));
@@ -2826,12 +2846,15 @@ var SessionParkManager = class {
2826
2846
  async #rememberDormant(runner) {
2827
2847
  if (this.#closed) return;
2828
2848
  const info = runner.info();
2829
- const sdkSessionId = info.sdkSessionId;
2830
- if (sdkSessionId === void 0) return;
2831
2849
  if (!(info.capabilities ?? ENGINE_CAPABILITIES[info.engine ?? "claude"]).resume) return;
2832
2850
  const config = this.#configs.get(runner.id);
2833
2851
  if (!config) return;
2834
2852
  if (this.#options.registry.get(runner.id) !== runner) return;
2853
+ const sdkSessionId = info.sdkSessionId;
2854
+ if (sdkSessionId === void 0) {
2855
+ if (this.#remembered.has(runner.id)) await this.#forgetDormant(runner.id);
2856
+ return;
2857
+ }
2835
2858
  const record = {
2836
2859
  kind: "dormant",
2837
2860
  id: runner.id,
@@ -2848,6 +2871,7 @@ var SessionParkManager = class {
2848
2871
  savedAt: Date.now()
2849
2872
  };
2850
2873
  try {
2874
+ this.#remembered.add(runner.id);
2851
2875
  await this.#queue(runner.id, () => this.#options.store.save(record));
2852
2876
  } catch (error) {
2853
2877
  this.#options.onError?.(error, {
@@ -2857,6 +2881,28 @@ var SessionParkManager = class {
2857
2881
  }
2858
2882
  }
2859
2883
  /**
2884
+ * Drop a dormant record that has stopped being true, leaving the live session
2885
+ * alone — the narrow counterpart to {@link ParkingService.discard}, which also
2886
+ * forgets the config and the session's executions and would therefore make a
2887
+ * clear cost the session its ability to go dormant ever again.
2888
+ *
2889
+ * Only ever called behind {@link ParkingService.#rememberDormant}'s guards,
2890
+ * which is what keeps it off a parked record: a park evicts the runner from
2891
+ * the registry before it saves, and the ownership guard turns a late event
2892
+ * from an evicted runner into a no-op.
2893
+ */
2894
+ async #forgetDormant(sessionId) {
2895
+ this.#remembered.delete(sessionId);
2896
+ try {
2897
+ await this.#queue(sessionId, () => this.#options.store.delete(sessionId));
2898
+ } catch (error) {
2899
+ this.#options.onError?.(error, {
2900
+ sessionId,
2901
+ phase: "remember"
2902
+ });
2903
+ }
2904
+ }
2905
+ /**
2860
2906
  * Write a live session's snapshot through to the store, so a restart can
2861
2907
  * rebuild it. The counterpart to {@link #rememberDormant} for the engine that
2862
2908
  * has no engine-side session to resume from — same discipline, different