@deepseek-ai/dsh-api-session-controller 0.2.0-rc.1 → 0.2.1-alpha.1

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/lib/index.js CHANGED
@@ -17,6 +17,8 @@ import { SessionTitleInvalidError } from "@deepseek-ai/dsh-session-title";
17
17
  import { canonicalClientTimeZone } from "@deepseek-ai/dsh-util-time";
18
18
  import { assertNever } from "@deepseek-ai/dsh-util-values";
19
19
  import { Deque } from "@deepseek-ai/dsh-deque";
20
+ import { performance } from "node:perf_hooks";
21
+ import { scheduler } from "node:timers/promises";
20
22
  import { z as z$1 } from "zod";
21
23
  import { isUserInvocable } from "@deepseek-ai/dsh-skill";
22
24
  import { FsError } from "@deepseek-ai/dsh-fs";
@@ -1831,9 +1833,14 @@ function truncateUnicodeCodePoints(value, maximum) {
1831
1833
  /** Owns list projection registration, bounded cold summaries, and authorized search. */
1832
1834
  var ApiSessionList = class {
1833
1835
  ctx;
1834
- /** @param ctx - Host context carrying Session, query, persistence, and projection services. */
1835
- constructor(ctx) {
1836
+ workSliceMs;
1837
+ /**
1838
+ * @param ctx - Host context carrying Session, query, persistence, and projection services.
1839
+ * @param workSliceMs - Resolved positive integral list-work budget in milliseconds.
1840
+ */
1841
+ constructor(ctx, workSliceMs) {
1836
1842
  this.ctx = ctx;
1843
+ this.workSliceMs = workSliceMs;
1837
1844
  ctx.sessionProjections.register({
1838
1845
  key: "sessionListMetadata",
1839
1846
  stateSchema: sessionListMetadataSchema,
@@ -1882,7 +1889,7 @@ var ApiSessionList = class {
1882
1889
  }
1883
1890
  /**
1884
1891
  * Read every visible attached and persisted Session without activating an Agent.
1885
- * @param signal - optional cancellation for persistence reads.
1892
+ * @param signal - optional cancellation for persistence reads and summary generation.
1886
1893
  * @returns visible Session summaries ordered by activity.
1887
1894
  */
1888
1895
  async list(signal) {
@@ -1891,16 +1898,28 @@ var ApiSessionList = class {
1891
1898
  signal?.throwIfAborted();
1892
1899
  const items = [];
1893
1900
  const cold = [];
1901
+ let yieldDeadline = performance.now() + this.workSliceMs;
1894
1902
  for (const record of records) {
1903
+ signal?.throwIfAborted();
1895
1904
  const live = this.ctx.sessions.get(record.header.id);
1896
- if (live !== void 0) {
1897
- items.push(this.summaryFor(live));
1898
- continue;
1905
+ if (live !== void 0) items.push(this.summaryFor(live));
1906
+ else if (record.header.cwd !== void 0) cold.push(record.header);
1907
+ if (performance.now() >= yieldDeadline) {
1908
+ await scheduler.yield();
1909
+ signal?.throwIfAborted();
1910
+ yieldDeadline = performance.now() + this.workSliceMs;
1911
+ }
1912
+ }
1913
+ for (const header of cold) {
1914
+ signal?.throwIfAborted();
1915
+ items.push(this.summarizeCold(header));
1916
+ if (performance.now() >= yieldDeadline) {
1917
+ await scheduler.yield();
1918
+ signal?.throwIfAborted();
1919
+ yieldDeadline = performance.now() + this.workSliceMs;
1899
1920
  }
1900
- if (record.header.cwd === void 0) continue;
1901
- cold.push(record.header);
1902
1921
  }
1903
- for (const header of cold) items.push(this.summarizeCold(header));
1922
+ signal?.throwIfAborted();
1904
1923
  items.sort((left, right) => right.updatedAt - left.updatedAt);
1905
1924
  return items;
1906
1925
  }
@@ -2826,7 +2845,10 @@ let SessionController = (() => {
2826
2845
  "typert",
2827
2846
  "workspaceRegistry"
2828
2847
  ];
2829
- static Config = z.object({ nativeOpen: z.boolean() });
2848
+ static Config = z.object({
2849
+ nativeOpen: z.boolean(),
2850
+ listWorkSliceMs: z.natural().min(1).default(16)
2851
+ });
2830
2852
  agents = __runInitializers(this, _instanceExtraInitializers);
2831
2853
  commands;
2832
2854
  controlState;
@@ -2840,11 +2862,12 @@ let SessionController = (() => {
2840
2862
  promotions = /* @__PURE__ */ new Set();
2841
2863
  /**
2842
2864
  * @param ctx - Host context containing the Session capability assembly.
2843
- * @param config - native-opener deployment policy.
2865
+ * @param config - native-opener and list-scheduling deployment policy.
2844
2866
  * @param internals - host integrations replaceable by direct unit tests.
2845
2867
  */
2846
2868
  constructor(ctx, config, internals = {}) {
2847
2869
  super(ctx, "sessionController", { namespace: "session" });
2870
+ const resolved = SessionController.Config(config);
2848
2871
  installModelSelectionProjection(ctx);
2849
2872
  this.agents = new ApiSessionAgentController(ctx);
2850
2873
  this.commands = new SessionCommandController(ctx, this.agents, process.cwd());
@@ -2860,7 +2883,7 @@ let SessionController = (() => {
2860
2883
  this.history = new SessionHistoryController(ctx, (observation) => {
2861
2884
  this.promote(observation);
2862
2885
  });
2863
- this.listState = new ApiSessionList(ctx);
2886
+ this.listState = new ApiSessionList(ctx, resolved.listWorkSliceMs);
2864
2887
  this.fileApplications = internals.fileApplications ?? nativeFileApplications;
2865
2888
  this.openFileApplication = internals.openFileApplication ?? openNativeFileApplication;
2866
2889
  this.openPath = internals.openPath ?? openNativeAssociatedPath;
@@ -2948,7 +2971,7 @@ let SessionController = (() => {
2948
2971
  /**
2949
2972
  * Read all visible Session rows without resuming an Agent.
2950
2973
  * @param _request - reserved empty list request.
2951
- * @param signal - cancellation for persistence reads.
2974
+ * @param signal - cancellation for persistence reads and summary generation.
2952
2975
  * @returns visible Session summaries ordered by activity.
2953
2976
  */
2954
2977
  async list(_request, signal) {