@chatcode/chatcode-cli 3.0.4-rc.1 → 3.0.4-rc.3

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 (136) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +2 -0
  3. package/README.zh.md +2 -0
  4. package/lib/{command-errors-BkCHTQHj.js → command-errors-BJ_ZWzUU.js} +12 -12
  5. package/lib/{command-trees-5HFyC5sI.js → command-trees-C9b7-bci.js} +2 -2
  6. package/lib/{component-identity-De91VHwW.js → component-identity-Jb1DYjke.js} +3 -3
  7. package/lib/{dist-CsDWUvQ4.js → dist-w_sIm4VD.js} +231 -231
  8. package/lib/{extension-events-CdYCRP0o.js → extension-events-DKX4LXOd.js} +26 -26
  9. package/lib/{frames-DOX-Jgk8.js → frames-B89znn_0.js} +4 -4
  10. package/lib/{host-access-Bk4xps5E.js → host-access-CMg6rsWt.js} +1 -1
  11. package/lib/{keymap-CJ1kvLR2.js → keymap-CrC4pSNH.js} +2 -2
  12. package/lib/{plugin-XR7ncbnW.js → plugin-CmyMCGfb.js} +1651 -1365
  13. package/lib/{scenes-CAmWncZD.js → scenes-Cil9RnwU.js} +3 -3
  14. package/lib/{settings-sections-CakcvBv9.js → settings-sections-jVCqXwdH.js} +3 -3
  15. package/lib/{statusBarSettings-BPPS_Usm.js → statusBarSettings-DNoBH3Cq.js} +3 -3
  16. package/lib/{supports-color-DyChQwlI.js → supports-color-CcW-FGjr.js} +2 -2
  17. package/lib/{themes-OjcUpZzw.js → themes-BdgeY3It.js} +12 -12
  18. package/lib/tui-compat-command-trees.js +1 -1
  19. package/lib/tui-compat-extensions.js +3 -3
  20. package/lib/tui-compat-plugin-host.js +5 -5
  21. package/lib/tui-compat-scenes.js +1 -1
  22. package/lib/tui-compat-settings-sections.js +1 -1
  23. package/lib/tui-compat-working-activity.js +4 -4
  24. package/lib/tui-compat-workspaces.js +1 -1
  25. package/lib/tui-compat.js +5 -5
  26. package/lib/{workspaces-XY7UdfXp.js → workspaces-DOatJRYr.js} +2 -2
  27. package/package.json +30 -29
  28. package/runtime/manifest.json +2 -2
  29. package/runtime/node_modules/@deepseek-ai/dsh-agent-default-model/lib/index.js +118 -22
  30. package/runtime/node_modules/@deepseek-ai/dsh-agent-default-model/lib/types/index.d.ts +20 -3
  31. package/runtime/node_modules/@deepseek-ai/dsh-api-remotes/lib/client.js +113 -39
  32. package/runtime/node_modules/@deepseek-ai/dsh-api-remotes/lib/index.js +4 -0
  33. package/runtime/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.d.ts +3 -0
  34. package/runtime/node_modules/@deepseek-ai/dsh-api-remotes/lib/types/remote-events.js +1 -0
  35. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/index.js +173 -34
  36. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/typert.host.js +48 -28
  37. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/typert.remote-client.js +24 -19
  38. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/agent.d.ts +9 -1
  39. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/agent.js +36 -6
  40. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/archived-session-gate.js +1 -1
  41. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/catalog.js +4 -1
  42. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/client/sessions/service.d.ts +1 -1
  43. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/commands.d.ts +2 -2
  44. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/commands.js +24 -8
  45. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/index.d.ts +4 -3
  46. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/index.js +31 -14
  47. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/list.d.ts +6 -0
  48. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/list.js +89 -4
  49. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/remote-events.d.ts +1 -1
  50. package/runtime/node_modules/@deepseek-ai/dsh-api-session-controller/lib/types/types.d.ts +18 -1
  51. package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/client.js +30 -0
  52. package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/index.js +83 -2
  53. package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/typert.host.js +104 -11
  54. package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/typert.remote-client.d.ts +5 -1
  55. package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/typert.remote-client.js +78 -11
  56. package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/client/model.d.ts +14 -1
  57. package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/client/model.js +17 -0
  58. package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/client/service.d.ts +15 -0
  59. package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/client/service.js +12 -0
  60. package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/commands.d.ts +13 -1
  61. package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/commands.js +44 -2
  62. package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/index.d.ts +13 -1
  63. package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/index.js +22 -0
  64. package/runtime/node_modules/@deepseek-ai/dsh-api-workspace-controller/lib/types/types.d.ts +17 -0
  65. package/runtime/node_modules/@deepseek-ai/dsh-app-boot/lib/index.js +2 -1
  66. package/runtime/node_modules/@deepseek-ai/dsh-atomic-write/lib/index.js +167 -44
  67. package/runtime/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/index.d.ts +14 -6
  68. package/runtime/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/linux-lock.d.ts +18 -0
  69. package/runtime/node_modules/@deepseek-ai/dsh-atomic-write/lib/types/windows-lock.d.ts +7 -0
  70. package/runtime/node_modules/@deepseek-ai/dsh-client-hmr/lib/client.js +931 -7
  71. package/runtime/node_modules/@deepseek-ai/dsh-client-hmr/lib/index.js +57 -19
  72. package/runtime/node_modules/@deepseek-ai/dsh-client-hmr/lib/types/client/index.d.ts +5 -2
  73. package/runtime/node_modules/@deepseek-ai/dsh-client-hmr/lib/types/config.d.ts +12 -0
  74. package/runtime/node_modules/@deepseek-ai/dsh-client-hmr/lib/types/events.d.ts +4 -4
  75. package/runtime/node_modules/@deepseek-ai/dsh-client-hmr/lib/types/index.d.ts +3 -8
  76. package/runtime/node_modules/@deepseek-ai/dsh-client-hmr/package.json +6 -2
  77. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-commands/lib/client.js +10 -0
  78. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-deliverables/lib/types/client/present-open.d.ts +1 -1
  79. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-model-selection/lib/client.js +8 -4
  80. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-settings-account/lib/client.js +2 -2
  81. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-settings-general/lib/client.js +1 -1
  82. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-sidebar/lib/client.js +1 -1
  83. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/client.js +1917 -206
  84. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/ArchivedSessions.d.ts +13 -0
  85. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/contract/slots.d.ts +4 -0
  86. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/locales.d.ts +40 -0
  87. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/recent.d.ts +11 -0
  88. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/rows/RecentList.d.ts +15 -0
  89. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/rows/Rows.d.ts +6 -1
  90. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/session-actions/DeleteSession.d.ts +24 -0
  91. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/stores.d.ts +2 -2
  92. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/lib/types/client/tree.d.ts +15 -13
  93. package/runtime/node_modules/@deepseek-ai/dsh-client-ui-workspace/package.json +3 -1
  94. package/runtime/node_modules/@deepseek-ai/dsh-commands/lib/index.js +16 -0
  95. package/runtime/node_modules/@deepseek-ai/dsh-commands/lib/typert.host.js +7 -3
  96. package/runtime/node_modules/@deepseek-ai/dsh-commands/lib/typert.remote-client.js +6 -2
  97. package/runtime/node_modules/@deepseek-ai/dsh-commands/lib/types/index.js +20 -0
  98. package/runtime/node_modules/@deepseek-ai/dsh-commands/lib/types/types.d.ts +5 -0
  99. package/runtime/node_modules/@deepseek-ai/dsh-cordis-client-runner/lib/client.js +5 -2
  100. package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/adapter.d.ts +1 -1
  101. package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek/lib/types/config.d.ts +3 -3
  102. package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek-account/lib/types/config.d.ts +2 -2
  103. package/runtime/node_modules/@deepseek-ai/dsh-llm-deepseek-api-key/lib/types/config.d.ts +2 -2
  104. package/runtime/node_modules/@deepseek-ai/dsh-schedule/lib/index.js +4 -0
  105. package/runtime/node_modules/@deepseek-ai/dsh-schedule/lib/typert.host.js +5 -5
  106. package/runtime/node_modules/@deepseek-ai/dsh-schedule/lib/typert.remote-client.js +5 -5
  107. package/runtime/node_modules/@deepseek-ai/dsh-schedule/lib/types/index.js +5 -0
  108. package/runtime/node_modules/@deepseek-ai/dsh-session/lib/types/index.d.ts +21 -0
  109. package/runtime/node_modules/@deepseek-ai/dsh-session-persistence/lib/index.js +12 -0
  110. package/runtime/node_modules/@deepseek-ai/dsh-session-persistence/lib/types/index.d.ts +15 -0
  111. package/runtime/node_modules/@deepseek-ai/dsh-session-persistence-jsonl/lib/index.js +95 -2
  112. package/runtime/node_modules/@deepseek-ai/dsh-session-persistence-jsonl/lib/types/index.d.ts +3 -1
  113. package/runtime/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/index.js +25 -1
  114. package/runtime/node_modules/@deepseek-ai/dsh-session-projection-cache/lib/types/index.d.ts +1 -0
  115. package/runtime/node_modules/@deepseek-ai/dsh-session-projection-cache/package.json +2 -1
  116. package/runtime/node_modules/@deepseek-ai/dsh-session-query/lib/index.js +13 -0
  117. package/runtime/node_modules/@deepseek-ai/dsh-session-query/lib/types/observation.d.ts +5 -0
  118. package/runtime/node_modules/@deepseek-ai/dsh-session-query-sqlite/lib/index.js +26 -0
  119. package/runtime/node_modules/@deepseek-ai/dsh-session-query-sqlite/package.json +2 -1
  120. package/runtime/node_modules/@deepseek-ai/dsh-storage-domain/lib/index.js +5 -1
  121. package/runtime/node_modules/@deepseek-ai/dsh-storage-domain/lib/types/domain.d.ts +2 -2
  122. package/runtime/node_modules/@deepseek-ai/dsh-subagent/lib/types/control.d.ts +1 -1
  123. package/runtime/node_modules/@deepseek-ai/dsh-tianti/lib/index.js +106 -56
  124. package/runtime/node_modules/@deepseek-ai/dsh-tianti/lib/types/config.d.ts +2 -2
  125. package/runtime/node_modules/@deepseek-ai/dsh-tianti/lib/types/index.d.ts +2 -1
  126. package/runtime/node_modules/@deepseek-ai/dsh-tianti/lib/types/services/tianti/config.d.ts +4 -2
  127. package/runtime/node_modules/@deepseek-ai/dsh-tianti/lib/types/tools.d.ts +2 -2
  128. package/runtime/node_modules/@deepseek-ai/dsh-tianti/package.json +2 -0
  129. package/runtime/node_modules/@deepseek-ai/dsh-tool-cordis/lib/types/api-catalog.js +104 -13
  130. package/runtime/node_modules/@deepseek-ai/dsh-workspace/lib/index.js +215 -4
  131. package/runtime/node_modules/@deepseek-ai/dsh-workspace/lib/invariant.js +6 -1
  132. package/runtime/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.d.ts +31 -0
  133. package/runtime/node_modules/@deepseek-ai/dsh-workspace/lib/types/index.js +219 -2
  134. package/runtime/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.d.ts +4 -0
  135. package/runtime/node_modules/@deepseek-ai/dsh-workspace/lib/types/spec.js +4 -0
  136. package/scripts/launch.mjs +8 -0
@@ -177,6 +177,7 @@ async function inspectApiSession(ctx, sessionId, signal) {
177
177
  /** Owns every operation that may create, resume, or configure a Web Agent. */
178
178
  var ApiSessionAgentController = class {
179
179
  ctx;
180
+ owned = /* @__PURE__ */ new Map();
180
181
  resumes = /* @__PURE__ */ new Map();
181
182
  creations = /* @__PURE__ */ new Map();
182
183
  selections = /* @__PURE__ */ new WeakMap();
@@ -184,6 +185,18 @@ var ApiSessionAgentController = class {
184
185
  /** @param ctx - Host context carrying Agent, model, persistence, and Typert services. */
185
186
  constructor(ctx) {
186
187
  this.ctx = ctx;
188
+ ctx.on("session/delete-release", async ({ sessionIds }) => {
189
+ for (const id of sessionIds) {
190
+ const handle = this.owned.get(id);
191
+ if (handle?.agent.status === "idle") await handle.dispose();
192
+ }
193
+ });
194
+ ctx.on("agent/disposed", ({ agent }) => {
195
+ if (this.owned.get(agent.session.id)?.agent === agent) this.owned.delete(agent.session.id);
196
+ });
197
+ ctx.effect(() => async () => {
198
+ await Promise.all([...this.owned.values()].map((handle) => handle.dispose()));
199
+ }, "api-session.ownedAgents");
187
200
  ctx.typert.lookups.configure("agent", async (sessionId) => {
188
201
  const found = await this.resolveAgent(sessionId);
189
202
  if ("error" in found) throw found.error;
@@ -287,6 +300,7 @@ var ApiSessionAgentController = class {
287
300
  const defaultModel = this.ctx.agentDefaultModel;
288
301
  const selection = {
289
302
  get current() {
303
+ if (defaultModel.usesSharedPreference()) return defaultModel.currentSelection();
290
304
  if (picked !== void 0) return picked;
291
305
  const loggedHeader = agent.session.requestHeader();
292
306
  if (loggedHeader === void 0) return defaultModel.currentSelection();
@@ -403,11 +417,11 @@ var ApiSessionAgentController = class {
403
417
  const published = this.ctx.sessions.get(sessionId);
404
418
  const live = this.ctx.agents.get(sessionId);
405
419
  if (published !== void 0 && hasApiSessionSubagentOwner(this.ctx, published, live)) throw new ApiSessionSubagentOwnership(sessionId);
406
- return (await this.ctx.agents.resume({
420
+ return (await this.remember(this.ctx.agents.resume({
407
421
  resumeSessionId: sessionId,
408
422
  agentOptions: this.agentOptions(),
409
423
  setup: composition.setup
410
- })).agent;
424
+ }))).agent;
411
425
  }
412
426
  async createOrAdopt(sessionId, cwd, checkPersistedIdentity, presetId) {
413
427
  const attached = this.ctx.sessions.get(sessionId);
@@ -427,11 +441,11 @@ var ApiSessionAgentController = class {
427
441
  const storedPreset = this.presetForObservation(observation);
428
442
  this.assertPresetUnchanged(sessionId, presetId, storedPreset);
429
443
  const composition = await this.composeAgent(storedPreset);
430
- return (await this.ctx.agents.resume({
444
+ return (await this.remember(this.ctx.agents.resume({
431
445
  resumeSessionId: sessionId,
432
446
  agentOptions: this.agentOptions(),
433
447
  setup: composition.setup
434
- })).agent;
448
+ }))).agent;
435
449
  } catch (e_3) {
436
450
  env_3.error = e_3;
437
451
  env_3.hasError = true;
@@ -447,7 +461,7 @@ var ApiSessionAgentController = class {
447
461
  throw new Error(`failed to ensure project directory "${cwd}": ${String(error)}`, { cause: error });
448
462
  }
449
463
  const composition = await this.composeAgent(presetId);
450
- return (await this.ctx.agents.create({
464
+ return (await this.remember(this.ctx.agents.create({
451
465
  sessionId,
452
466
  agentOptions: this.agentOptions(),
453
467
  meta: {
@@ -455,7 +469,20 @@ var ApiSessionAgentController = class {
455
469
  ...composition.agentPreset === void 0 ? {} : { agentPreset: composition.agentPreset }
456
470
  },
457
471
  setup: composition.setup
458
- })).agent;
472
+ }))).agent;
473
+ }
474
+ /**
475
+ * Create a Web-owned Agent whose idle handle can be released before permanent deletion.
476
+ * @param options - Agent creation input shared by new Sessions and ordinary forks.
477
+ * @returns the owned Agent handle.
478
+ */
479
+ createOwned(options) {
480
+ return this.remember(this.ctx.agents.create(options));
481
+ }
482
+ async remember(pending) {
483
+ const handle = await pending;
484
+ this.owned.set(handle.agent.session.id, handle);
485
+ return handle;
459
486
  }
460
487
  agentOptions() {
461
488
  const { provider, model } = this.ctx.agentDefaultModel.currentSelection();
@@ -543,8 +570,10 @@ async function buildModelCatalog(ctx, defaultSelection = ctx.agentDefaultModel.c
543
570
  }));
544
571
  const groups = catalog.flatMap((item) => item.kind === "group" ? [item.group] : []).filter((group) => group.models.length > 0);
545
572
  const savedDisplayName = ctx.agentDefaultModel.sharedDisplayName();
573
+ const processSelection = ctx.agentDefaultModel.usesSharedPreference();
546
574
  return {
547
- default: { ...defaultSelection },
575
+ default: { ...processSelection ? await ctx.agentDefaultModel.resolveSelection() : defaultSelection },
576
+ ...processSelection ? { selectionScope: "process" } : {},
548
577
  ...savedDisplayName === void 0 ? {} : { savedDisplayName },
549
578
  routableProviders: groups.map((group) => group.id),
550
579
  groups,
@@ -718,9 +747,9 @@ var SessionCommandController = class {
718
747
  };
719
748
  }
720
749
  /**
721
- * Validate and install one Session-local model selection; save the default in the background.
750
+ * Validate, persist the default, and install one model selection before acknowledging success.
722
751
  * @param request - Session identity and requested model selection.
723
- * @returns the normalized selection installed for the Session, without waiting for default persistence.
752
+ * @returns the normalized selection after the shared save and Session selection succeed.
724
753
  */
725
754
  async selectModel(request) {
726
755
  const agent = await this.resolveAgent(request.sessionId);
@@ -737,10 +766,24 @@ var SessionCommandController = class {
737
766
  model: resolved.model,
738
767
  ...resolved.reasoningEffort === void 0 ? {} : { reasoningEffort: resolved.reasoningEffort }
739
768
  };
740
- this.agents.selectForNextRequest(agent, selected);
741
- this.ctx.agentDefaultModel.saveSelection(selected).catch((error) => {
742
- this.ctx.logger.warn(`session-controller: model selection changed for the Session but the default was not saved: ${String(error)}`);
743
- });
769
+ const info = await this.ctx.llm.resolveModelInfo(selected.provider, selected.model);
770
+ try {
771
+ await this.ctx.agentDefaultModel.saveSelection(selected, info.name);
772
+ } catch (error) {
773
+ throw new RemoteError("session/model-save-failed", `model selection was not changed because the default could not be saved: ${String(error)}`, {
774
+ provider: selected.provider,
775
+ model: selected.model
776
+ });
777
+ }
778
+ this.ctx.emit("api-session/model-updated");
779
+ try {
780
+ this.agents.selectForNextRequest(agent, selected);
781
+ } catch (error) {
782
+ throw new RemoteError("session/model-install-failed", `the default model was saved, but the Session selection could not be recorded: ${String(error)}`, {
783
+ provider: selected.provider,
784
+ model: selected.model
785
+ });
786
+ }
744
787
  return { selected: { ...selected } };
745
788
  } catch (error) {
746
789
  if (remoteErrorOf(error) !== void 0) throw error;
@@ -812,7 +855,7 @@ var SessionCommandController = class {
812
855
  const composition = await this.agents.composeAgent(this.agents.presetForObservation(source));
813
856
  try {
814
857
  const { provider, model } = this.ctx.agentDefaultModel.currentSelection();
815
- await this.ctx.agents.create({
858
+ await this.agents.createOwned({
816
859
  sessionId: childId,
817
860
  seed,
818
861
  inheritedEventCount: SessionLogOffset(boundary + 1),
@@ -872,6 +915,13 @@ var SessionCommandController = class {
872
915
  hasError: false
873
916
  };
874
917
  try {
918
+ if (this.ctx.agentDefaultModel.usesSharedPreference()) {
919
+ const route = await this.ctx.agentDefaultModel.resolveSelection();
920
+ if (route.provider === "" || route.model === "") throw new RemoteError("session/model-unavailable", "the selected model is unavailable; select a model before sending a message", {
921
+ provider: route.provider,
922
+ model: route.model
923
+ });
924
+ }
875
925
  if (hasImage) {
876
926
  const current = this.agents.selectionFor(agent).current;
877
927
  const model = await this.ctx.llm.resolveModelInfo(current.provider, current.model);
@@ -900,7 +950,7 @@ var SessionCommandController = class {
900
950
  }
901
951
  return { accepted: true };
902
952
  };
903
- return hasImage ? this.agents.serializeImageAdmission(agent, admit) : admit();
953
+ return hasImage || this.ctx.agentDefaultModel.usesSharedPreference() ? this.agents.serializeImageAdmission(agent, admit) : admit();
904
954
  }
905
955
  async requireModel(selection) {
906
956
  if (!await modelAvailable(this.ctx, selection)) throw new RemoteError("session/model-unavailable", "Select an available model before sending a message.", {
@@ -1792,6 +1842,7 @@ const SEARCH_PROVIDER_CALL_LIMIT = 100;
1792
1842
  const SESSION_SEARCH_QUERY_MAX_CHARS = 500;
1793
1843
  const MESSAGE_TYPES = new Set(["user/message", "assistant/message"]);
1794
1844
  const sessionListMetadataSchema = z$1.object({
1845
+ hasUserPrompt: z$1.boolean().default(false),
1795
1846
  blank: z$1.boolean(),
1796
1847
  lastPromptAt: z$1.number().nullable()
1797
1848
  });
@@ -1811,12 +1862,21 @@ const imageLimitsSchema = z$1.object({
1811
1862
  */
1812
1863
  function applySessionListMetadata(state, event) {
1813
1864
  const blank = state.blank && event.type !== "turn/start";
1865
+ const hasUserPrompt = state.hasUserPrompt === true || hasHumanInput(event);
1814
1866
  const lastPromptAt = event.type === "user/message" && event.data.source.kind === "user" ? event.time : state.lastPromptAt;
1815
- return blank === state.blank && lastPromptAt === state.lastPromptAt ? state : {
1867
+ return blank === state.blank && lastPromptAt === state.lastPromptAt && hasUserPrompt === state.hasUserPrompt ? state : {
1816
1868
  blank,
1817
- lastPromptAt
1869
+ lastPromptAt,
1870
+ hasUserPrompt
1818
1871
  };
1819
1872
  }
1873
+ /** User-origin text or media is conversation input; injected context is not. */
1874
+ function hasHumanInput(event) {
1875
+ return (event.type === "user/message" ? [{
1876
+ ...event.data,
1877
+ role: "user"
1878
+ }] : event.type === "agent/inbox/spliced" ? event.data.inserted : []).some((message) => message.role === "user" && message.source.kind === "user" && message.content.some((block) => block.type !== "text" || block.text.trim() !== ""));
1879
+ }
1820
1880
  /**
1821
1881
  * Return the longest prefix containing at most `maximum` Unicode code points.
1822
1882
  * @param value - source text.
@@ -1836,6 +1896,10 @@ function truncateUnicodeCodePoints(value, maximum) {
1836
1896
  /** Owns list projection registration, bounded cold summaries, and authorized search. */
1837
1897
  var ApiSessionList = class {
1838
1898
  ctx;
1899
+ backfillAbort = new AbortController();
1900
+ backfills = /* @__PURE__ */ new Set();
1901
+ checkedRevisions = /* @__PURE__ */ new Map();
1902
+ backfill = Promise.resolve();
1839
1903
  /** @param ctx - Host context carrying Session, query, persistence, and projection services. */
1840
1904
  constructor(ctx) {
1841
1905
  this.ctx = ctx;
@@ -1844,14 +1908,22 @@ var ApiSessionList = class {
1844
1908
  stateSchema: sessionListMetadataSchema,
1845
1909
  init: () => ({
1846
1910
  blank: true,
1847
- lastPromptAt: null
1911
+ lastPromptAt: null,
1912
+ hasUserPrompt: false
1848
1913
  }),
1849
1914
  apply: applySessionListMetadata,
1850
1915
  wire: {
1851
1916
  viewSchema: sessionListMetadataSchema,
1852
1917
  view: (state) => state
1853
1918
  },
1854
- stateVersion: 1
1919
+ stateVersion: 2
1920
+ });
1921
+ ctx.effect(() => async () => {
1922
+ this.backfillAbort.abort();
1923
+ await this.backfill;
1924
+ }, "session-list: stop summary backfill");
1925
+ ctx.on("session/event", (session, event) => {
1926
+ if (hasHumanInput(event)) ctx.emit("api-session/added", this.summaryFor(session));
1855
1927
  });
1856
1928
  ctx.inject(["attachments"], (attachmentCtx) => {
1857
1929
  ctx.sessionProjections.register({
@@ -1893,6 +1965,8 @@ var ApiSessionList = class {
1893
1965
  async list(signal) {
1894
1966
  signal?.throwIfAborted();
1895
1967
  const records = await this.ctx.sessionQuery.listSessions(signal);
1968
+ const listedIds = new Set(records.map((record) => record.header.id));
1969
+ for (const id of this.checkedRevisions.keys()) if (!listedIds.has(id)) this.checkedRevisions.delete(id);
1896
1970
  signal?.throwIfAborted();
1897
1971
  const items = [];
1898
1972
  const cold = [];
@@ -1916,6 +1990,7 @@ var ApiSessionList = class {
1916
1990
  async summarizeCold(header) {
1917
1991
  const projections = await this.projectionsFor(header, void 0);
1918
1992
  const metadata = projections?.values.sessionListMetadata;
1993
+ if (metadata?.hasUserPrompt !== true) this.backfillCold(header.id);
1919
1994
  return {
1920
1995
  sessionId: header.id,
1921
1996
  updatedAt: updatedAt(header, metadata),
@@ -1926,6 +2001,58 @@ var ApiSessionList = class {
1926
2001
  ...projections === void 0 ? {} : { projections }
1927
2002
  };
1928
2003
  }
2004
+ /** Serialize missing summaries outside list latency; unreadable history stays unknown. */
2005
+ backfillCold(sessionId) {
2006
+ if (this.backfillAbort.signal.aborted || this.backfills.has(sessionId)) return;
2007
+ const persistence = this.ctx.get("sessionPersistence");
2008
+ const cache = this.ctx.get("sessionProjectionCache");
2009
+ if (persistence === void 0 || cache === void 0) return;
2010
+ this.backfills.add(sessionId);
2011
+ this.backfill = this.backfill.then(async () => {
2012
+ const signal = this.backfillAbort.signal;
2013
+ signal.throwIfAborted();
2014
+ const live = this.ctx.sessions.get(sessionId);
2015
+ if (live !== void 0) {
2016
+ this.ctx.emit("api-session/added", this.summaryFor(live));
2017
+ return;
2018
+ }
2019
+ const before = await persistence.stat(sessionId, { signal });
2020
+ if (before === void 0 || before.revision === this.checkedRevisions.get(sessionId)) return;
2021
+ const handle = await persistence.open(sessionId, "read", { signal });
2022
+ let snapshot;
2023
+ try {
2024
+ const read = await handle.read(SessionLogOffset(0), void 0, { signal });
2025
+ signal.throwIfAborted();
2026
+ const after = await persistence.stat(sessionId, { signal });
2027
+ if (after?.revision !== before.revision || after.header.createdAt !== handle.header.createdAt) return;
2028
+ snapshot = await cache.coldSnapshot(handle.header, handle.inheritedEventCount, read.events);
2029
+ this.checkedRevisions.set(sessionId, before.revision);
2030
+ } finally {
2031
+ await handle.close();
2032
+ }
2033
+ signal.throwIfAborted();
2034
+ const attached = this.ctx.sessions.get(sessionId);
2035
+ if (attached !== void 0) {
2036
+ this.ctx.emit("api-session/added", this.summaryFor(attached));
2037
+ return;
2038
+ }
2039
+ if ((await persistence.stat(sessionId, { signal }))?.revision !== before.revision) return;
2040
+ const projections = hintsOf("cached", snapshot);
2041
+ this.ctx.emit("api-session/added", {
2042
+ sessionId,
2043
+ updatedAt: updatedAt(handle.header, snapshot.values.sessionListMetadata),
2044
+ agentAvailable: false,
2045
+ running: false,
2046
+ blank: snapshot.values.sessionListMetadata?.blank ?? false,
2047
+ ...listFields(handle.header),
2048
+ ...projections === void 0 ? {} : { projections }
2049
+ });
2050
+ }).catch((error) => {
2051
+ if (!this.backfillAbort.signal.aborted) this.ctx.logger.warn(`api-session.list: summary backfill for "${sessionId}" failed: ${String(error)}`);
2052
+ }).finally(() => {
2053
+ this.backfills.delete(sessionId);
2054
+ });
2055
+ }
1929
2056
  /**
1930
2057
  * Search current visible message content without activating any matching Session.
1931
2058
  * @param query - literal message-content query.
@@ -2457,7 +2584,7 @@ const ArchivedSessionGate = {
2457
2584
  * @returns whether an archived Session owns the step.
2458
2585
  */
2459
2586
  function underArchivedSession(ctx, agent) {
2460
- const archived = ctx.workspaceRegistry.archivedSessionIds;
2587
+ const archived = [...ctx.workspaceRegistry.archivedSessionIds, ...ctx.workspaceRegistry.deletedSessionIds];
2461
2588
  let header = agent.session.header;
2462
2589
  const visited = /* @__PURE__ */ new Set();
2463
2590
  while (!visited.has(header.id)) {
@@ -2887,6 +3014,9 @@ let SessionController = (() => {
2887
3014
  ctx.plugin(SessionMediaReferences);
2888
3015
  ctx.plugin(SessionSkillCatalog);
2889
3016
  ctx.plugin(ArchivedSessionGate);
3017
+ ctx.on("session/deleted", (ids) => {
3018
+ for (const id of ids) ctx.emit("api-session/removed", id);
3019
+ });
2890
3020
  ctx.on("session/created", (session) => {
2891
3021
  ctx.emit("api-session/added", this.listState.summaryFor(session));
2892
3022
  });
@@ -2985,22 +3115,24 @@ let SessionController = (() => {
2985
3115
  * @param request - requested identity, location, and Agent preset.
2986
3116
  * @returns the Session identity and resolved preset when configured.
2987
3117
  */
2988
- create(request) {
3118
+ async create(request) {
3119
+ if (request.sessionId !== void 0) await this.assertNotDeleted(request.sessionId);
2989
3120
  return this.commands.create(request);
2990
3121
  }
2991
3122
  /**
2992
- * Select one Session-local model after explicitly resuming the Session; save the default in the background.
3123
+ * Select a model after explicitly resuming the Session and awaiting default persistence.
2993
3124
  * @param request - Session identity and requested model selection.
2994
- * @returns the normalized selection installed for the Session, without waiting for default persistence.
3125
+ * @returns the normalized selection after the shared save and Session selection succeed.
2995
3126
  */
2996
3127
  selectModel(request) {
2997
- return this.commands.selectModel(request);
3128
+ return this.assertNotDeleted(request.sessionId).then(() => this.commands.selectModel(request));
2998
3129
  }
2999
3130
  /**
3000
- * Select the first available account model after login when no provider API key is configured.
3131
+ * Initialize legacy account deployments without changing a product process's cached selection.
3001
3132
  * @returns after saving the first available model or retaining the existing default.
3002
3133
  */
3003
3134
  async initializeDefaultModel() {
3135
+ if (this.ctx.agentDefaultModel.usesSharedPreference()) return;
3004
3136
  const provider = "deepseek-account";
3005
3137
  if (await hasProviderApiKey(this.ctx)) return;
3006
3138
  const model = (await buildModelCatalog(this.ctx)).groups.find((group) => group.id === provider)?.models[0];
@@ -3010,7 +3142,8 @@ let SessionController = (() => {
3010
3142
  model: model.id,
3011
3143
  ...model.reasoning?.defaultEffort === void 0 ? {} : { reasoningEffort: ReasoningEffortId(model.reasoning.defaultEffort) }
3012
3144
  };
3013
- await this.ctx.agentDefaultModel.saveSelection(selection);
3145
+ await this.ctx.agentDefaultModel.saveSelection(selection, model.name);
3146
+ this.ctx.emit("api-session/model-updated");
3014
3147
  }
3015
3148
  /**
3016
3149
  * Describe every currently routable model for Host-generation selectors.
@@ -3092,7 +3225,7 @@ let SessionController = (() => {
3092
3225
  * @returns the accepted title and durable event sequence.
3093
3226
  */
3094
3227
  rename(request) {
3095
- return this.commands.rename(request);
3228
+ return this.assertNotDeleted(request.sessionId).then(() => this.commands.rename(request));
3096
3229
  }
3097
3230
  /**
3098
3231
  * Fork one cold-readable exact event prefix into a new Session. An omitted
@@ -3102,7 +3235,7 @@ let SessionController = (() => {
3102
3235
  * @returns the new Session identity.
3103
3236
  */
3104
3237
  fork(request) {
3105
- return this.commands.fork(request);
3238
+ return this.assertNotDeleted(request.sessionId).then(() => this.commands.fork(request));
3106
3239
  }
3107
3240
  /**
3108
3241
  * Admit one prompt after explicitly resuming its Session.
@@ -3112,7 +3245,7 @@ let SessionController = (() => {
3112
3245
  */
3113
3246
  prompt(request, signal) {
3114
3247
  signal.throwIfAborted();
3115
- return this.commands.prompt(request);
3248
+ return this.assertNotDeleted(request.sessionId).then(() => this.commands.prompt(request));
3116
3249
  }
3117
3250
  /**
3118
3251
  * Read one image proven reachable from the addressed Session log.
@@ -3120,7 +3253,7 @@ let SessionController = (() => {
3120
3253
  * @returns the durable attachment reference and base64-encoded bytes.
3121
3254
  */
3122
3255
  attachment(request) {
3123
- return this.commands.attachment(request);
3256
+ return this.assertNotDeleted(request.sessionId).then(() => this.commands.attachment(request));
3124
3257
  }
3125
3258
  /**
3126
3259
  * Mutate one still-pending queue occurrence, resuming a cold Agent first.
@@ -3128,7 +3261,7 @@ let SessionController = (() => {
3128
3261
  * @returns acknowledgement that the queue mutation was applied.
3129
3262
  */
3130
3263
  updateQueue(request) {
3131
- return this.commands.updateQueue(request);
3264
+ return this.assertNotDeleted(request.sessionId).then(() => this.commands.updateQueue(request));
3132
3265
  }
3133
3266
  /**
3134
3267
  * Cancel one active Agent turn without dropping its pending inbox.
@@ -3145,7 +3278,7 @@ let SessionController = (() => {
3145
3278
  * @returns one chronological page.
3146
3279
  */
3147
3280
  page(request, signal) {
3148
- return this.history.page(request, signal);
3281
+ return this.assertNotDeleted(request.address.kind === "session" ? request.address.sessionId : request.address.childSessionId).then(() => this.history.page(request, signal));
3149
3282
  }
3150
3283
  /**
3151
3284
  * Follow one Session log from its opening or resume cursor.
@@ -3154,8 +3287,13 @@ let SessionController = (() => {
3154
3287
  * @returns a complete opening snapshot followed by gap-free durable event
3155
3288
  * frames and optional cursorless assistant-stream frames.
3156
3289
  */
3157
- follow(request, signal) {
3158
- return this.history.follow(request, signal);
3290
+ async *follow(request, signal) {
3291
+ await this.assertNotDeleted(request.address.kind === "session" ? request.address.sessionId : request.address.childSessionId);
3292
+ yield* this.history.follow(request, signal);
3293
+ }
3294
+ async assertNotDeleted(sessionId) {
3295
+ await this.ctx.workspaceRegistry.refresh();
3296
+ if (this.ctx.workspaceRegistry.deletedSessionIds.includes(sessionId)) throw new RemoteError("session/not-found", "Session has been permanently deleted", { sessionId });
3159
3297
  }
3160
3298
  /**
3161
3299
  * Read all registered projections without activating an Agent.
@@ -3166,6 +3304,7 @@ let SessionController = (() => {
3166
3304
  async projections(request, signal) {
3167
3305
  const { sessionId } = request;
3168
3306
  if (sessionId.length === 0) throw new RemoteError("gateway/bad-request", "sessionId must not be empty", {});
3307
+ await this.assertNotDeleted(sessionId);
3169
3308
  try {
3170
3309
  const env_2 = {
3171
3310
  stack: [],