t3code-cli 0.14.0 → 0.14.2

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 (163) hide show
  1. package/README.md +1 -0
  2. package/dist/application.d.ts +2 -2
  3. package/dist/application.js +1 -1
  4. package/dist/auth.d.ts +1 -1
  5. package/dist/auth.js +1 -1
  6. package/dist/bin.js +551 -265
  7. package/dist/cli.d.ts +1 -1
  8. package/dist/cli.js +1 -1
  9. package/dist/client-runtime/authorization.d.ts +1 -1
  10. package/dist/client-runtime/authorization.js +1 -1
  11. package/dist/client-runtime/connection.d.ts +1 -1
  12. package/dist/client-runtime/connection.js +1 -1
  13. package/dist/client-runtime/environment.d.ts +5 -1
  14. package/dist/client-runtime/environment.js +1 -1
  15. package/dist/client-runtime/errors.js +1 -1
  16. package/dist/client-runtime/operations/projects.d.ts +2 -2
  17. package/dist/client-runtime/operations/projects.js +2 -2
  18. package/dist/client-runtime/operations.d.ts +2 -2
  19. package/dist/client-runtime/operations.js +2 -2
  20. package/dist/client-runtime/platform.d.ts +1 -1
  21. package/dist/client-runtime/platform.js +1 -1
  22. package/dist/client-runtime/relay.d.ts +5 -1
  23. package/dist/client-runtime/relay.js +1 -1
  24. package/dist/client-runtime/rpc.d.ts +2 -2
  25. package/dist/client-runtime/rpc.js +2 -2
  26. package/dist/client-runtime/state/assets.d.ts +17 -11
  27. package/dist/client-runtime/state/assets.js +1 -1
  28. package/dist/client-runtime/state/auth.d.ts +1 -1
  29. package/dist/client-runtime/state/auth.js +1 -1
  30. package/dist/client-runtime/state/connections.js +1 -1
  31. package/dist/client-runtime/state/entities.d.ts +1 -1
  32. package/dist/client-runtime/state/entities.js +1 -1
  33. package/dist/client-runtime/state/filesystem.d.ts +1 -1
  34. package/dist/client-runtime/state/filesystem.js +1 -1
  35. package/dist/client-runtime/state/git.d.ts +5 -5
  36. package/dist/client-runtime/state/git.js +1 -1
  37. package/dist/client-runtime/state/models.d.ts +1 -1
  38. package/dist/client-runtime/state/models.js +1 -1
  39. package/dist/client-runtime/state/orchestration.d.ts +42 -2
  40. package/dist/client-runtime/state/orchestration.js +13 -1
  41. package/dist/client-runtime/state/presentation.d.ts +9 -3
  42. package/dist/client-runtime/state/presentation.js +1 -1
  43. package/dist/client-runtime/state/preview.d.ts +55 -48
  44. package/dist/client-runtime/state/preview.js +1 -1
  45. package/dist/client-runtime/state/project-grouping.d.ts +26 -2
  46. package/dist/client-runtime/state/project-grouping.js +83 -3
  47. package/dist/client-runtime/state/projects.d.ts +24 -18
  48. package/dist/client-runtime/state/projects.js +1 -1
  49. package/dist/client-runtime/state/relay.d.ts +1 -1
  50. package/dist/client-runtime/state/relay.js +1 -1
  51. package/dist/client-runtime/state/review.d.ts +16 -1
  52. package/dist/client-runtime/state/review.js +27 -6
  53. package/dist/client-runtime/state/runtime.d.ts +2 -2
  54. package/dist/client-runtime/state/runtime.js +2 -2
  55. package/dist/client-runtime/state/server.d.ts +299 -172
  56. package/dist/client-runtime/state/server.js +192 -16
  57. package/dist/client-runtime/state/session.d.ts +65 -7
  58. package/dist/client-runtime/state/session.js +32 -3
  59. package/dist/client-runtime/state/shell.d.ts +41 -7
  60. package/dist/client-runtime/state/shell.js +1 -1
  61. package/dist/client-runtime/state/source-control.d.ts +2 -2
  62. package/dist/client-runtime/state/source-control.js +1 -1
  63. package/dist/client-runtime/state/subagentRuntime.d.ts +145 -0
  64. package/dist/client-runtime/state/subagentRuntime.js +521 -0
  65. package/dist/client-runtime/state/terminal.d.ts +17 -17
  66. package/dist/client-runtime/state/terminal.js +1 -1
  67. package/dist/client-runtime/state/thread-search.d.ts +23 -0
  68. package/dist/client-runtime/state/thread-search.js +38 -0
  69. package/dist/client-runtime/state/thread-settled.d.ts +28 -3
  70. package/dist/client-runtime/state/thread-settled.js +74 -2
  71. package/dist/client-runtime/state/thread-sort.d.ts +59 -2
  72. package/dist/client-runtime/state/thread-sort.js +128 -2
  73. package/dist/client-runtime/state/threads.d.ts +115 -3
  74. package/dist/client-runtime/state/threads.js +309 -28
  75. package/dist/client-runtime/state/vcs.d.ts +14 -14
  76. package/dist/client-runtime/state/vcs.js +1 -1
  77. package/dist/config.d.ts +1 -1
  78. package/dist/config.js +1 -1
  79. package/dist/connection.d.ts +1 -1
  80. package/dist/connection.js +1 -1
  81. package/dist/contracts.d.ts +1 -1
  82. package/dist/contracts.js +1 -1
  83. package/dist/index.d.ts +1 -1
  84. package/dist/index.js +1 -1
  85. package/dist/node.d.ts +1 -1
  86. package/dist/node.js +1 -1
  87. package/dist/orchestration.d.ts +144 -1
  88. package/dist/orchestration.js +1 -1
  89. package/dist/preview.d.ts +1 -1
  90. package/dist/preview.js +1 -1
  91. package/dist/rpc.d.ts +883 -351
  92. package/dist/rpc.js +1 -1
  93. package/dist/runtime.d.ts +1 -1
  94. package/dist/runtime.js +1 -1
  95. package/dist/shared/DrainableWorker.js +1 -1
  96. package/dist/shared/KeyedCoalescingWorker.js +1 -1
  97. package/dist/shared/Net.js +1 -1
  98. package/dist/shared/advertisedEndpoint.d.ts +1 -1
  99. package/dist/shared/advertisedEndpoint.js +1 -1
  100. package/dist/shared/agentAwareness.d.ts +1 -1
  101. package/dist/shared/backgroundActivitySettings.d.ts +1 -1
  102. package/dist/shared/composerInlineTokens.js +1 -1
  103. package/dist/shared/connectAuth.js +1 -1
  104. package/dist/shared/devHome.js +1 -1
  105. package/dist/shared/dpop.js +1 -1
  106. package/dist/shared/git.d.ts +1 -1
  107. package/dist/shared/httpObservability.js +1 -1
  108. package/dist/shared/httpReadiness.js +1 -1
  109. package/dist/shared/keybindings.d.ts +2 -2
  110. package/dist/shared/keybindings.js +15 -1
  111. package/dist/shared/model.d.ts +1 -1
  112. package/dist/shared/oauthScope.js +1 -1
  113. package/dist/shared/observability.d.ts +8 -1
  114. package/dist/shared/observability.js +49 -5
  115. package/dist/shared/path.js +1 -1
  116. package/dist/shared/preview.js +1 -1
  117. package/dist/shared/previewViewport.d.ts +1 -1
  118. package/dist/shared/previewViewport.js +1 -1
  119. package/dist/shared/projectFavicon.d.ts +2 -1
  120. package/dist/shared/projectFavicon.js +13 -1
  121. package/dist/shared/projectScripts.d.ts +1 -1
  122. package/dist/shared/relayAuth.js +1 -1
  123. package/dist/shared/relayClient.d.ts +1 -1
  124. package/dist/shared/relayClient.js +1 -1
  125. package/dist/shared/relayJwt.js +1 -1
  126. package/dist/shared/relayTracing.js +1 -1
  127. package/dist/shared/relayUrl.js +1 -1
  128. package/dist/shared/remote.js +1 -1
  129. package/dist/shared/schemaYaml.js +3 -3
  130. package/dist/shared/semver.js +1 -1
  131. package/dist/shared/serverSettings.d.ts +1 -1
  132. package/dist/shared/serverSettings.js +1 -1
  133. package/dist/shared/shell.d.ts +6 -1
  134. package/dist/shared/shell.js +42 -4
  135. package/dist/shared/sourceControl.d.ts +1 -1
  136. package/dist/shared/t3ProjectFile.d.ts +9 -1
  137. package/dist/shared/t3ProjectFile.js +12 -2
  138. package/dist/shared/terminalLabels.d.ts +1 -1
  139. package/dist/shared/threadEnvMode.d.ts +29 -0
  140. package/dist/shared/threadEnvMode.js +24 -0
  141. package/dist/shared/toolActivity.d.ts +1 -1
  142. package/dist/shared/usageFormat.d.ts +21 -0
  143. package/dist/shared/usageFormat.js +90 -0
  144. package/dist/shared/usageMerge.d.ts +67 -0
  145. package/dist/shared/usageMerge.js +218 -0
  146. package/dist/shared.d.ts +4472 -668
  147. package/dist/shared.js +16867 -16273
  148. package/dist/t3tools.d.ts +2 -2
  149. package/dist/t3tools.js +2 -2
  150. package/package.json +5 -5
  151. package/src/application/index.ts +1 -0
  152. package/src/application/service.ts +5 -1
  153. package/src/application/threads.ts +43 -1
  154. package/src/bin.ts +10 -7
  155. package/src/cli/app.ts +2 -0
  156. package/src/cli/format/thread.ts +23 -1
  157. package/src/cli/search.ts +48 -0
  158. package/src/config/persist/schema.ts +1 -1
  159. package/src/orchestration/layer.ts +6 -0
  160. package/src/orchestration/service.ts +5 -0
  161. package/src/rpc/error.ts +2 -0
  162. package/src/rpc/operation.ts +2 -0
  163. package/src/rpc/ws-group.ts +2 -0
@@ -1,4 +1,4 @@
1
- import { _v as OrchestrationThreadShell } from "../../shared.js";
1
+ import { Vy as OrchestrationThreadShell } from "../../shared.js";
2
2
  //#region upstream-t3code/packages/client-runtime/src/state/threadSettled.d.ts
3
3
  type ChangeRequestStateLike = "open" | "closed" | "merged";
4
4
  declare function threadLastActivityAt(shell: OrchestrationThreadShell): string | null;
@@ -91,7 +91,8 @@ declare function threadWokeAt(shell: ThreadSnoozeShell, options: {
91
91
  * override. Past the blockers, the explicit user override (thread.settle /
92
92
  * thread.unsettle commands, projected into settledOverride + settledAt)
93
93
  * wins in both directions; without one, a thread auto-settles on a
94
- * merged/closed PR immediately or on inactivity past the window. The server
94
+ * merged/closed PR immediately or on inactivity past the window except
95
+ * that an open PR blocks the inactivity path entirely. The server
95
96
  * un-settles on real activity (user message, session start, approval/
96
97
  * user-input request), so an override never goes stale silently.
97
98
  */
@@ -100,5 +101,29 @@ declare function effectiveSettled(shell: OrchestrationThreadShell, options: {
100
101
  readonly autoSettleAfterDays: number | null;
101
102
  readonly changeRequestState?: ChangeRequestStateLike | null;
102
103
  }): boolean;
104
+ type SnoozePresetId = "hour" | "evening" | "tomorrow" | "next-week";
105
+ interface SnoozePreset {
106
+ readonly id: SnoozePresetId;
107
+ readonly label: string;
108
+ /** Menu-row time column. Complements the label instead of repeating it:
109
+ "Tomorrow" pairs with "9:00 AM", not "tomorrow 9:00 AM". */
110
+ readonly whenLabel: string;
111
+ /** ISO wake time. */
112
+ readonly snoozedUntil: string;
113
+ }
114
+ /**
115
+ * Shared "snooze until" choices for every client. "This evening" only
116
+ * appears while it is meaningfully before evening; after that the list
117
+ * starts at "Tomorrow".
118
+ */
119
+ declare function resolveSnoozePresets(now: Date): ReadonlyArray<SnoozePreset>;
120
+ /**
121
+ * Compact "wakes in" label for snoozed rows: "2h", "18h", "3d". Minutes
122
+ * round up so a snooze never reads "0m" while still hidden. Shared by web
123
+ * and mobile so the same wake time never reads differently per client.
124
+ */
125
+ declare function snoozeWakeLabel(snoozedUntil: string, options: {
126
+ readonly now: string;
127
+ }): string;
103
128
  //#endregion
104
- export { ChangeRequestStateLike, QUEUED_TURN_START_GRACE_MS, ThreadSnoozeShell, canSettle, canSnooze, effectiveSettled, effectiveSnoozed, hasQueuedTurnStart, threadLastActivityAt, threadRaisedHandWhileSnoozed, threadWokeAt };
129
+ export { ChangeRequestStateLike, QUEUED_TURN_START_GRACE_MS, SnoozePreset, SnoozePresetId, ThreadSnoozeShell, canSettle, canSnooze, effectiveSettled, effectiveSnoozed, hasQueuedTurnStart, resolveSnoozePresets, snoozeWakeLabel, threadLastActivityAt, threadRaisedHandWhileSnoozed, threadWokeAt };
@@ -135,7 +135,8 @@ function threadWokeAt(shell, options) {
135
135
  * override. Past the blockers, the explicit user override (thread.settle /
136
136
  * thread.unsettle commands, projected into settledOverride + settledAt)
137
137
  * wins in both directions; without one, a thread auto-settles on a
138
- * merged/closed PR immediately or on inactivity past the window. The server
138
+ * merged/closed PR immediately or on inactivity past the window except
139
+ * that an open PR blocks the inactivity path entirely. The server
139
140
  * un-settles on real activity (user message, session start, approval/
140
141
  * user-input request), so an override never goes stale silently.
141
142
  */
@@ -148,10 +149,81 @@ function effectiveSettled(shell, options) {
148
149
  if (shell.settledOverride === "settled") return true;
149
150
  if (shell.settledOverride === "active") return false;
150
151
  if (options.changeRequestState === "merged" || options.changeRequestState === "closed") return true;
152
+ if (options.changeRequestState === "open") return false;
151
153
  if (options.autoSettleAfterDays === null) return false;
152
154
  const lastActivityAt = threadLastActivityAt(shell);
153
155
  if (lastActivityAt === null) return false;
154
156
  return Date.parse(lastActivityAt) < Date.parse(options.now) - options.autoSettleAfterDays * DAY_MS;
155
157
  }
158
+ const HOUR_MS = 3600 * 1e3;
159
+ const EVENING_HOUR = 18;
160
+ const MORNING_HOUR = 9;
161
+ function snoozeTimeOfDayLabel(date) {
162
+ return date.toLocaleTimeString(void 0, {
163
+ hour: "numeric",
164
+ minute: "2-digit"
165
+ });
166
+ }
167
+ function snoozeAtHour(base, hour) {
168
+ const next = new Date(base);
169
+ next.setHours(hour, 0, 0, 0);
170
+ return next;
171
+ }
172
+ function addSnoozeDays(base, days) {
173
+ const next = new Date(base);
174
+ next.setDate(next.getDate() + days);
175
+ return next;
176
+ }
177
+ /**
178
+ * Shared "snooze until" choices for every client. "This evening" only
179
+ * appears while it is meaningfully before evening; after that the list
180
+ * starts at "Tomorrow".
181
+ */
182
+ function resolveSnoozePresets(now) {
183
+ const inAnHour = new Date(now.getTime() + HOUR_MS);
184
+ const presets = [{
185
+ id: "hour",
186
+ label: "In 1 hour",
187
+ whenLabel: snoozeTimeOfDayLabel(inAnHour),
188
+ snoozedUntil: inAnHour.toISOString()
189
+ }];
190
+ const evening = snoozeAtHour(now, EVENING_HOUR);
191
+ if (evening.getTime() - now.getTime() > HOUR_MS) presets.push({
192
+ id: "evening",
193
+ label: "This evening",
194
+ whenLabel: snoozeTimeOfDayLabel(evening),
195
+ snoozedUntil: evening.toISOString()
196
+ });
197
+ const tomorrow = snoozeAtHour(addSnoozeDays(now, 1), MORNING_HOUR);
198
+ presets.push({
199
+ id: "tomorrow",
200
+ label: "Tomorrow",
201
+ whenLabel: snoozeTimeOfDayLabel(tomorrow),
202
+ snoozedUntil: tomorrow.toISOString()
203
+ });
204
+ const nextWeek = snoozeAtHour(addSnoozeDays(now, (1 - now.getDay() + 7) % 7 || 7), MORNING_HOUR);
205
+ presets.push({
206
+ id: "next-week",
207
+ label: "Next week",
208
+ whenLabel: `${nextWeek.toLocaleDateString(void 0, { weekday: "short" })} ${snoozeTimeOfDayLabel(nextWeek)}`,
209
+ snoozedUntil: nextWeek.toISOString()
210
+ });
211
+ return presets;
212
+ }
213
+ /**
214
+ * Compact "wakes in" label for snoozed rows: "2h", "18h", "3d". Minutes
215
+ * round up so a snooze never reads "0m" while still hidden. Shared by web
216
+ * and mobile so the same wake time never reads differently per client.
217
+ */
218
+ function snoozeWakeLabel(snoozedUntil, options) {
219
+ const wakeMs = Date.parse(snoozedUntil);
220
+ const nowMs = Date.parse(options.now);
221
+ if (Number.isNaN(wakeMs) || Number.isNaN(nowMs)) return "now";
222
+ const remainingMs = wakeMs - nowMs;
223
+ if (remainingMs <= 0) return "now";
224
+ if (remainingMs < HOUR_MS) return `${Math.max(1, Math.ceil(remainingMs / 6e4))}m`;
225
+ if (remainingMs < DAY_MS) return `${Math.ceil(remainingMs / HOUR_MS)}h`;
226
+ return `${Math.ceil(remainingMs / DAY_MS)}d`;
227
+ }
156
228
  //#endregion
157
- export { QUEUED_TURN_START_GRACE_MS, canSettle, canSnooze, effectiveSettled, effectiveSnoozed, hasQueuedTurnStart, threadLastActivityAt, threadRaisedHandWhileSnoozed, threadWokeAt };
229
+ export { QUEUED_TURN_START_GRACE_MS, canSettle, canSnooze, effectiveSettled, effectiveSnoozed, hasQueuedTurnStart, resolveSnoozePresets, snoozeWakeLabel, threadLastActivityAt, threadRaisedHandWhileSnoozed, threadWokeAt };
@@ -1,4 +1,4 @@
1
- import { KT as ProjectId, f_ as SidebarThreadSortOrder, u_ as SidebarProjectSortOrder } from "../../shared.js";
1
+ import { Ev as SidebarThreadSortOrder, jD as ProjectId, wv as SidebarProjectSortOrder } from "../../shared.js";
2
2
  //#region upstream-t3code/packages/client-runtime/src/state/threadSort.d.ts
3
3
  interface ThreadSortInput {
4
4
  readonly createdAt: string;
@@ -19,5 +19,62 @@ declare function getLatestThreadForProject<T extends {
19
19
  readonly projectId: ProjectId;
20
20
  readonly archivedAt: string | null;
21
21
  } & ThreadSortInput>(threads: readonly T[], projectId: ProjectId, sortOrder: SidebarThreadSortOrder): T | null;
22
+ /** Key that sorts strictly between two neighbors; null bounds mean "top of
23
+ the pinned block" / "bottom of the keyed run". Returns null instead of
24
+ throwing when existing keys are corrupt or out of order — callers fall
25
+ back to rewriting the section. */
26
+ declare function pinOrderKeyBetween(before: string | null, after: string | null): string | null;
27
+ /** Evenly spaced keys for rewriting a whole pinned section (used when a
28
+ drop lands next to keyless threads, so single-key insertion has nothing
29
+ to anchor on). Two base-26 digits give 675 slots — far beyond any real
30
+ pinned section — with monotonicity enforced as a belt-and-braces. */
31
+ declare function generateSpreadPinOrderKeys(count: number): string[];
32
+ /**
33
+ * Assignments needed to realize a new pinned order. When the moved thread
34
+ * sits between two keyed (or absent) neighbors, this is a single write to
35
+ * the moved thread. When a neighbor is keyless (threads pinned before
36
+ * reordering shipped), the whole section gets fresh spread keys — a
37
+ * one-time materialization; every move after that is single-write.
38
+ */
39
+ declare function planPinnedReorder(input: {
40
+ /** Thread ids in the desired visual order (after the move). */
41
+ readonly orderedIds: readonly string[];
42
+ readonly keysById: ReadonlyMap<string, string | null | undefined>;
43
+ readonly movedId: string;
44
+ }): ReadonlyArray<{
45
+ readonly id: string;
46
+ readonly orderKey: string;
47
+ }>;
48
+ /**
49
+ * Pinned block order: user-arranged keys first (string comparison, id
50
+ * tiebreak), then keyless threads newest-created first — so threads on
51
+ * servers that predate reordering keep the static creation order at the
52
+ * bottom of the block instead of breaking the section.
53
+ */
54
+ declare function sortPinnedThreadsByOrderKey<T extends {
55
+ readonly id: string;
56
+ readonly createdAt: string;
57
+ readonly pinOrderKey?: string | null | undefined;
58
+ /** Thread ids are only unique within an environment, and the pinned
59
+ block merges environments — the tiebreak needs both parts or two
60
+ clients could render equal-key threads in stream-arrival order. */
61
+ readonly environmentId?: string | undefined;
62
+ }>(threads: readonly T[]): T[];
63
+ /**
64
+ * planPinnedReorder specialized for mobile's Move up / Move down menu
65
+ * actions: swap the moved thread with its displayed neighbor. Null when the
66
+ * move falls off either end of the list. Same single-write-per-move
67
+ * semantics as a web drag.
68
+ */
69
+ declare function planPinnedMove(input: {
70
+ /** Reorder-capable pinned thread ids in displayed order. */
71
+ readonly orderedIds: readonly string[];
72
+ readonly keysById: ReadonlyMap<string, string | null | undefined>;
73
+ readonly movedId: string;
74
+ readonly direction: "up" | "down";
75
+ }): ReadonlyArray<{
76
+ readonly id: string;
77
+ readonly orderKey: string;
78
+ }> | null;
22
79
  //#endregion
23
- export { ThreadSortInput, getLatestThreadForProject, getThreadSortTimestamp, sortThreads, toSortableTimestamp };
80
+ export { ThreadSortInput, generateSpreadPinOrderKeys, getLatestThreadForProject, getThreadSortTimestamp, pinOrderKeyBetween, planPinnedMove, planPinnedReorder, sortPinnedThreadsByOrderKey, sortThreads, toSortableTimestamp };
@@ -1,4 +1,4 @@
1
- import { Jk as Struct, Kk as Number$1, Qk as mapInput, Zk as flip, qk as String, vk as sort } from "../../shared.js";
1
+ import { Fj as Struct, Nj as Number$1, Pj as String, Rj as flip, rj as sort, zj as mapInput } from "../../shared.js";
2
2
  //#region upstream-t3code/packages/client-runtime/src/state/threadSort.ts
3
3
  function toSortableTimestamp(iso) {
4
4
  if (!iso) return null;
@@ -43,5 +43,131 @@ function sortThreads(threads, sortOrder) {
43
43
  function getLatestThreadForProject(threads, projectId, sortOrder) {
44
44
  return sortThreads(threads.filter((thread) => thread.projectId === projectId && thread.archivedAt === null), sortOrder)[0] ?? null;
45
45
  }
46
+ const PIN_ORDER_DIGITS = "abcdefghijklmnopqrstuvwxyz";
47
+ function isValidPinOrderKey(key) {
48
+ if (key.length === 0) return false;
49
+ for (const char of key) if (!PIN_ORDER_DIGITS.includes(char)) return false;
50
+ return key.at(-1) !== PIN_ORDER_DIGITS[0];
51
+ }
52
+ /** Midpoint of two digit strings interpreted as fractions in (0, 1).
53
+ "" stands for the open bound on either side. Requires a < b. */
54
+ function pinOrderMidpoint(a, b) {
55
+ if (b !== "" && a >= b) throw new Error("pinOrderMidpoint: bounds out of order");
56
+ if (b !== "") {
57
+ let n = 0;
58
+ while ((a.charAt(n) || PIN_ORDER_DIGITS[0]) === b.charAt(n)) n += 1;
59
+ if (n > 0) return b.slice(0, n) + pinOrderMidpoint(a.slice(n), b.slice(n));
60
+ }
61
+ const digitA = a === "" ? 0 : PIN_ORDER_DIGITS.indexOf(a.charAt(0));
62
+ const digitB = b === "" ? 26 : PIN_ORDER_DIGITS.indexOf(b.charAt(0));
63
+ if (digitB - digitA > 1) return PIN_ORDER_DIGITS.charAt(Math.round((digitA + digitB) / 2));
64
+ if (b.length > 1) return b.charAt(0);
65
+ return PIN_ORDER_DIGITS.charAt(digitA) + pinOrderMidpoint(a.slice(1), "");
66
+ }
67
+ /** Key that sorts strictly between two neighbors; null bounds mean "top of
68
+ the pinned block" / "bottom of the keyed run". Returns null instead of
69
+ throwing when existing keys are corrupt or out of order — callers fall
70
+ back to rewriting the section. */
71
+ function pinOrderKeyBetween(before, after) {
72
+ const a = before ?? "";
73
+ const b = after ?? "";
74
+ if (a !== "" && !isValidPinOrderKey(a)) return null;
75
+ if (b !== "" && !isValidPinOrderKey(b)) return null;
76
+ if (b !== "" && a >= b) return null;
77
+ return pinOrderMidpoint(a, b);
78
+ }
79
+ /** Evenly spaced keys for rewriting a whole pinned section (used when a
80
+ drop lands next to keyless threads, so single-key insertion has nothing
81
+ to anchor on). Two base-26 digits give 675 slots — far beyond any real
82
+ pinned section — with monotonicity enforced as a belt-and-braces. */
83
+ function generateSpreadPinOrderKeys(count) {
84
+ const space = 676;
85
+ const step = space / (count + 1);
86
+ const keys = [];
87
+ let previous = 0;
88
+ for (let i = 0; i < count; i += 1) {
89
+ let value = Math.max(Math.round(step * (i + 1)), previous + 1);
90
+ if (value % 26 === 0) value += 1;
91
+ value = Math.min(value, space - 1);
92
+ previous = value;
93
+ keys.push(PIN_ORDER_DIGITS.charAt(Math.floor(value / 26)) + PIN_ORDER_DIGITS.charAt(value % 26));
94
+ }
95
+ return keys;
96
+ }
97
+ /**
98
+ * Assignments needed to realize a new pinned order. When the moved thread
99
+ * sits between two keyed (or absent) neighbors, this is a single write to
100
+ * the moved thread. When a neighbor is keyless (threads pinned before
101
+ * reordering shipped), the whole section gets fresh spread keys — a
102
+ * one-time materialization; every move after that is single-write.
103
+ */
104
+ function planPinnedReorder(input) {
105
+ const { orderedIds, keysById, movedId } = input;
106
+ const movedIndex = orderedIds.indexOf(movedId);
107
+ if (movedIndex === -1) return [];
108
+ const beforeId = movedIndex > 0 ? orderedIds[movedIndex - 1] : null;
109
+ const afterId = movedIndex < orderedIds.length - 1 ? orderedIds[movedIndex + 1] : null;
110
+ const beforeKey = beforeId != null ? keysById.get(beforeId) ?? null : null;
111
+ const afterKey = afterId != null ? keysById.get(afterId) ?? null : null;
112
+ if ((beforeId === null || beforeKey != null) && (afterId === null || afterKey != null)) {
113
+ const key = pinOrderKeyBetween(beforeKey, afterKey);
114
+ if (key !== null) return [{
115
+ id: movedId,
116
+ orderKey: key
117
+ }];
118
+ }
119
+ const keys = generateSpreadPinOrderKeys(orderedIds.length);
120
+ return orderedIds.flatMap((id, index) => {
121
+ const key = keys[index];
122
+ return keysById.get(id) === key ? [] : [{
123
+ id,
124
+ orderKey: key
125
+ }];
126
+ });
127
+ }
128
+ /**
129
+ * Pinned block order: user-arranged keys first (string comparison, id
130
+ * tiebreak), then keyless threads newest-created first — so threads on
131
+ * servers that predate reordering keep the static creation order at the
132
+ * bottom of the block instead of breaking the section.
133
+ */
134
+ function sortPinnedThreadsByOrderKey(threads) {
135
+ const keyed = [];
136
+ const keyless = [];
137
+ for (const thread of threads) (thread.pinOrderKey != null ? keyed : keyless).push(thread);
138
+ const identityTiebreak = (left, right) => left.id.localeCompare(right.id) || (left.environmentId ?? "").localeCompare(right.environmentId ?? "");
139
+ keyed.sort((left, right) => {
140
+ const leftKey = left.pinOrderKey;
141
+ const rightKey = right.pinOrderKey;
142
+ return leftKey < rightKey ? -1 : leftKey > rightKey ? 1 : identityTiebreak(left, right);
143
+ });
144
+ keyless.sort((left, right) => {
145
+ const leftMs = Date.parse(left.createdAt);
146
+ const rightMs = Date.parse(right.createdAt);
147
+ return (Number.isNaN(rightMs) ? 0 : rightMs) - (Number.isNaN(leftMs) ? 0 : leftMs) || identityTiebreak(left, right);
148
+ });
149
+ return [...keyed, ...keyless];
150
+ }
151
+ /**
152
+ * planPinnedReorder specialized for mobile's Move up / Move down menu
153
+ * actions: swap the moved thread with its displayed neighbor. Null when the
154
+ * move falls off either end of the list. Same single-write-per-move
155
+ * semantics as a web drag.
156
+ */
157
+ function planPinnedMove(input) {
158
+ const { orderedIds, keysById, movedId, direction } = input;
159
+ const from = orderedIds.indexOf(movedId);
160
+ if (from === -1) return null;
161
+ const to = direction === "up" ? from - 1 : from + 1;
162
+ if (to < 0 || to >= orderedIds.length) return null;
163
+ const newOrder = [...orderedIds];
164
+ newOrder.splice(from, 1);
165
+ newOrder.splice(to, 0, movedId);
166
+ return planPinnedReorder({
167
+ orderedIds: newOrder,
168
+ keysById,
169
+ movedId
170
+ });
171
+ }
46
172
  //#endregion
47
- export { getLatestThreadForProject, getThreadSortTimestamp, sortThreads, toSortableTimestamp };
173
+ export { generateSpreadPinOrderKeys, getLatestThreadForProject, getThreadSortTimestamp, pinOrderKeyBetween, planPinnedMove, planPinnedReorder, sortPinnedThreadsByOrderKey, sortThreads, toSortableTimestamp };
@@ -1,4 +1,4 @@
1
- import { $T as ThreadId, B_ as OrchestrationEvent, Ca as EnvironmentCacheStore, Ct as StartThreadTurnInput, Dt as UnsnoozeThreadInput, Et as UnsettleThreadInput, G_ as OrchestrationGetFullThreadDiffResult, Mw as ScopedThreadRef, St as SnoozeThreadInput, Tt as UnarchiveThreadInput, Ua as RemoteEnvironmentRequestError, Y_ as OrchestrationGetTurnDiffResult, _a as EnvironmentSupervisor, _t as RespondToThreadUserInputInput, at as EnvironmentThreadShell, bT as EnvironmentAuthorizationError, bt as SetThreadRuntimeModeInput, cv as OrchestrationShellSnapshot, es as PreparedConnection, f as AtomCommand, ft as CreateThreadInput, gt as RespondToThreadApprovalInput, gv as OrchestrationThreadDetailSnapshot, ha as EnvironmentRegistry, ht as InterruptThreadTurnInput, it as EnvironmentThread, jw as ScopedProjectRef, kt as UpdateThreadMetadataInput, ma as EnvironmentNotRegisteredError, mt as DeleteThreadInput, on as EnvironmentRpcUnavailableError, pv as OrchestrationThread, u as EnvironmentCatalogState, uo as ManagedRelayDpopSigner, ut as ArchiveThreadInput, vt as RevertThreadCheckpointInput, wt as StopThreadSessionInput, xt as SettleThreadInput, yt as SetThreadInteractionModeInput, zT as EnvironmentId, z_ as OrchestrationDispatchCommandError } from "../../shared.js";
1
+ import { $a as RemoteEnvironmentRequestError, $v as OrchestrationDispatchCommandError, At as UnpinThreadInput, CD as EnvironmentId, Ct as SetThreadInteractionModeInput, Da as EnvironmentSupervisor, Dt as StartThreadTurnInput, Et as SnoozeThreadInput, Ly as OrchestrationThreadDetailSnapshot, Mt as UnsnoozeThreadInput, Na as EnvironmentCacheStore, Ny as OrchestrationThread, Ot as StopThreadSessionInput, Oy as OrchestrationShellSnapshot, Pt as UpdateThreadMetadataInput, RD as ThreadId, St as RevertThreadCheckpointInput, Ta as EnvironmentRegistry, Tt as SettleThreadInput, _t as InterruptThreadTurnInput, ay as OrchestrationGetFullThreadDiffResult, bo as ManagedRelayDpopSigner, bt as RespondToThreadApprovalInput, ey as OrchestrationEvent, f as AtomCommand, ft as ArchiveThreadInput, gt as DeleteThreadInput, hE as ScopedThreadRef, iD as EnvironmentAuthorizationError, jt as UnsettleThreadInput, kt as UnarchiveThreadInput, ly as OrchestrationGetTurnDiffResult, mE as ScopedProjectRef, mn as EnvironmentRpcUnavailableError, mt as CreateThreadInput, ot as EnvironmentThread, st as EnvironmentThreadShell, u as EnvironmentCatalogState, us as PreparedConnection, vt as PinThreadInput, wa as EnvironmentNotRegisteredError, wt as SetThreadRuntimeModeInput, xt as RespondToThreadUserInputInput, yt as ReorderPinnedThreadInput } from "../../shared.js";
2
2
  import * as Context from "effect/Context";
3
3
  import * as Effect from "effect/Effect";
4
4
  import * as Stream from "effect/Stream";
@@ -15,11 +15,21 @@ import { AsyncResult, Atom } from "effect/unstable/reactivity";
15
15
  * WebSocket subscription's first frame. The response is gzip-compressible by
16
16
  * the transport and keeps the (potentially multi-KB) snapshot off the socket.
17
17
  */
18
+ /**
19
+ * Optional turn window for a snapshot fetch. Only send a window to servers
20
+ * that advertise `threadSnapshotPagination`; older servers reject unknown
21
+ * query parameters.
22
+ */
23
+ interface ThreadSnapshotWindow {
24
+ readonly turnLimit: number;
25
+ readonly beforeCursor?: string;
26
+ }
18
27
  declare const fetchEnvironmentThreadSnapshot: (input: {
19
28
  readonly prepared: PreparedConnection;
20
29
  readonly threadId: ThreadId;
21
30
  readonly signer: Option.Option<ManagedRelayDpopSigner["Service"]>;
22
31
  readonly timeoutMs?: number;
32
+ readonly window?: ThreadSnapshotWindow;
23
33
  }) => Effect.Effect<{
24
34
  readonly snapshotSequence: number;
25
35
  readonly thread: {
@@ -57,6 +67,12 @@ declare const fetchEnvironmentThreadSnapshot: (input: {
57
67
  readonly settledAt: string | null;
58
68
  readonly snoozedUntil?: string | null | undefined;
59
69
  readonly snoozedAt?: string | null | undefined;
70
+ readonly pinnedAt?: string | null | undefined;
71
+ readonly pinOrderKey?: string | null | undefined;
72
+ readonly titleRegeneration?: {
73
+ readonly requestId: string & import("effect/Brand").Brand<"CommandId">;
74
+ readonly startedAt: string;
75
+ } | null | undefined;
60
76
  readonly deletedAt: string | null;
61
77
  readonly messages: readonly {
62
78
  readonly id: string & import("effect/Brand").Brand<"MessageId">;
@@ -118,10 +134,16 @@ declare const fetchEnvironmentThreadSnapshot: (input: {
118
134
  readonly updatedAt: string;
119
135
  } | null;
120
136
  };
137
+ readonly page?: {
138
+ readonly beforeCursor: string | null;
139
+ readonly hasMore: boolean;
140
+ readonly snapshotSequence: number;
141
+ readonly threadSequence?: number;
142
+ } | undefined;
121
143
  }, RemoteEnvironmentRequestError, HttpClient.HttpClient>;
122
144
  type FetchEnvironmentThreadSnapshotError = RemoteEnvironmentRequestError;
123
145
  declare const ThreadSnapshotLoader_base: Context.ServiceClass<ThreadSnapshotLoader, "@t3tools/client-runtime/state/threadSnapshotHttp/ThreadSnapshotLoader", {
124
- readonly load: (prepared: PreparedConnection, threadId: ThreadId) => Effect.Effect<Option.Option<OrchestrationThreadDetailSnapshot>>;
146
+ readonly load: (prepared: PreparedConnection, threadId: ThreadId, window?: ThreadSnapshotWindow) => Effect.Effect<Option.Option<OrchestrationThreadDetailSnapshot>>;
125
147
  }>;
126
148
  /**
127
149
  * Loads a thread's detail snapshot over HTTP, returning `Option.none()` when it
@@ -134,12 +156,28 @@ declare const threadSnapshotLoaderLayer: Layer.Layer<ThreadSnapshotLoader, never
134
156
  //#endregion
135
157
  //#region upstream-t3code/packages/client-runtime/src/state/threadState.d.ts
136
158
  type EnvironmentThreadStatus = "empty" | "cached" | "synchronizing" | "live" | "deleted";
159
+ /**
160
+ * Pagination state for a windowed thread. Present only when the loaded thread
161
+ * is a window (the server returned `page` metadata); absent means the thread is
162
+ * fully loaded — either the server predates pagination or the window reached
163
+ * the top.
164
+ */
165
+ interface EnvironmentThreadPageState {
166
+ /** Opaque exclusive cursor for the next older slice; null when fully loaded. */
167
+ readonly beforeCursor: string | null;
168
+ readonly hasMore: boolean;
169
+ /** True while an older page fetch is in flight. */
170
+ readonly loadingOlder: boolean;
171
+ }
137
172
  interface EnvironmentThreadState {
138
173
  readonly data: Option.Option<OrchestrationThread>;
139
174
  readonly status: EnvironmentThreadStatus;
140
175
  readonly error: Option.Option<string>;
176
+ readonly page: Option.Option<EnvironmentThreadPageState>;
141
177
  }
142
178
  declare const EMPTY_ENVIRONMENT_THREAD_STATE: EnvironmentThreadState;
179
+ /** Whether the thread has older turns that can be loaded with more pages. */
180
+ declare function threadHasOlderTurns(state: EnvironmentThreadState): boolean;
143
181
  //#endregion
144
182
  //#region upstream-t3code/packages/client-runtime/src/state/archivedThreads.d.ts
145
183
  interface ArchivedSnapshotEntry {
@@ -241,6 +279,24 @@ declare function createThreadEnvironmentAtoms<R, E>(runtime: Atom.AtomRuntime<En
241
279
  }, {
242
280
  readonly sequence: number;
243
281
  }, E | EnvironmentAuthorizationError | EnvironmentNotRegisteredError | EnvironmentRpcUnavailableError | OrchestrationDispatchCommandError | import("effect/unstable/rpc/RpcClientError").RpcClientError>;
282
+ pin: AtomCommand<{
283
+ readonly environmentId: EnvironmentId;
284
+ readonly input: PinThreadInput;
285
+ }, {
286
+ readonly sequence: number;
287
+ }, E | EnvironmentAuthorizationError | EnvironmentNotRegisteredError | EnvironmentRpcUnavailableError | OrchestrationDispatchCommandError | import("effect/unstable/rpc/RpcClientError").RpcClientError>;
288
+ unpin: AtomCommand<{
289
+ readonly environmentId: EnvironmentId;
290
+ readonly input: UnpinThreadInput;
291
+ }, {
292
+ readonly sequence: number;
293
+ }, E | EnvironmentAuthorizationError | EnvironmentNotRegisteredError | EnvironmentRpcUnavailableError | OrchestrationDispatchCommandError | import("effect/unstable/rpc/RpcClientError").RpcClientError>;
294
+ reorderPin: AtomCommand<{
295
+ readonly environmentId: EnvironmentId;
296
+ readonly input: ReorderPinnedThreadInput;
297
+ }, {
298
+ readonly sequence: number;
299
+ }, E | EnvironmentAuthorizationError | EnvironmentNotRegisteredError | EnvironmentRpcUnavailableError | OrchestrationDispatchCommandError | import("effect/unstable/rpc/RpcClientError").RpcClientError>;
244
300
  updateMetadata: AtomCommand<{
245
301
  readonly environmentId: EnvironmentId;
246
302
  readonly input: UpdateThreadMetadataInput;
@@ -446,6 +502,12 @@ declare function createEnvironmentThreadShellAtoms(input: {
446
502
  readonly settledAt: string | null;
447
503
  readonly snoozedUntil?: string | null | undefined;
448
504
  readonly snoozedAt?: string | null | undefined;
505
+ readonly pinnedAt?: string | null | undefined;
506
+ readonly pinOrderKey?: string | null | undefined;
507
+ readonly titleRegeneration?: {
508
+ readonly requestId: string & import("effect/Brand").Brand<"CommandId">;
509
+ readonly startedAt: string;
510
+ } | null | undefined;
449
511
  readonly session: {
450
512
  readonly threadId: string & import("effect/Brand").Brand<"ThreadId">;
451
513
  readonly status: "error" | "idle" | "interrupted" | "ready" | "running" | "starting" | "stopped";
@@ -460,6 +522,12 @@ declare function createEnvironmentThreadShellAtoms(input: {
460
522
  readonly hasPendingApprovals: boolean;
461
523
  readonly hasPendingUserInput: boolean;
462
524
  readonly hasActionableProposedPlan: boolean;
525
+ readonly backgroundLiveness?: "monitoring" | "working" | null | undefined;
526
+ readonly planProgress?: {
527
+ readonly step: string;
528
+ readonly completedSteps: number;
529
+ readonly totalSteps: number;
530
+ } | null | undefined;
463
531
  }[]>;
464
532
  environmentThreadIndexAtom: (arg: string & import("effect/Brand").Brand<"EnvironmentId">) => Atom.Atom<ReadonlyMap<string & import("effect/Brand").Brand<"ThreadId">, {
465
533
  readonly id: string & import("effect/Brand").Brand<"ThreadId">;
@@ -496,6 +564,12 @@ declare function createEnvironmentThreadShellAtoms(input: {
496
564
  readonly settledAt: string | null;
497
565
  readonly snoozedUntil?: string | null | undefined;
498
566
  readonly snoozedAt?: string | null | undefined;
567
+ readonly pinnedAt?: string | null | undefined;
568
+ readonly pinOrderKey?: string | null | undefined;
569
+ readonly titleRegeneration?: {
570
+ readonly requestId: string & import("effect/Brand").Brand<"CommandId">;
571
+ readonly startedAt: string;
572
+ } | null | undefined;
499
573
  readonly session: {
500
574
  readonly threadId: string & import("effect/Brand").Brand<"ThreadId">;
501
575
  readonly status: "error" | "idle" | "interrupted" | "ready" | "running" | "starting" | "stopped";
@@ -510,6 +584,12 @@ declare function createEnvironmentThreadShellAtoms(input: {
510
584
  readonly hasPendingApprovals: boolean;
511
585
  readonly hasPendingUserInput: boolean;
512
586
  readonly hasActionableProposedPlan: boolean;
587
+ readonly backgroundLiveness?: "monitoring" | "working" | null | undefined;
588
+ readonly planProgress?: {
589
+ readonly step: string;
590
+ readonly completedSteps: number;
591
+ readonly totalSteps: number;
592
+ } | null | undefined;
513
593
  }>>;
514
594
  environmentThreadRefsAtom: (arg: string & import("effect/Brand").Brand<"EnvironmentId">) => Atom.Atom<readonly {
515
595
  readonly environmentId: string & import("effect/Brand").Brand<"EnvironmentId">;
@@ -529,10 +609,42 @@ declare function createEnvironmentThreadShellAtoms(input: {
529
609
  };
530
610
  //#endregion
531
611
  //#region upstream-t3code/packages/client-runtime/src/state/threads.d.ts
612
+ /**
613
+ * Turn window sizes for paginated thread loads: the initial page covers the
614
+ * last 10 user-anchored turns (subagent/fan-out turns ride along), each
615
+ * "load earlier" tap fetches 20 more. Sized so first paint on the heaviest
616
+ * observed threads stays around 100K gzipped while median threads load fully.
617
+ */
618
+ declare const INITIAL_THREAD_USER_TURN_LIMIT = 10;
619
+ declare const OLDER_THREAD_PAGE_USER_TURN_LIMIT = 20;
620
+ interface ThreadOlderTurnRequestRegistry {
621
+ /**
622
+ * Registers the live state machine for a thread. Returns the deregistration
623
+ * cleanup; registration lives exactly as long as the machine's scope, and a
624
+ * successor machine for the same thread simply replaces the entry.
625
+ */
626
+ readonly register: (key: string, handler: () => void) => () => void;
627
+ readonly request: (key: string) => boolean;
628
+ }
629
+ declare const ThreadOlderTurnRequests_base: Context.Reference<ThreadOlderTurnRequestRegistry>;
630
+ /**
631
+ * Channel from UI actions to the live per-thread state machines. The machines
632
+ * resolve it from the Effect environment (overridable in tests); the default
633
+ * instance is shared with the sync `requestOlderThreadTurns` entry point so
634
+ * the apps get working wiring without providing anything.
635
+ */
636
+ declare class ThreadOlderTurnRequests extends ThreadOlderTurnRequests_base {}
637
+ /**
638
+ * Asks the live state machine for `threadId` to fetch the next older page.
639
+ * Returns false when no machine is live or no fetch was started (no cursor,
640
+ * already loading); callers render from `EnvironmentThreadState.page` and can
641
+ * treat false as "nothing to do".
642
+ */
643
+ declare function requestOlderThreadTurns(environmentId: EnvironmentId, threadId: ThreadId): boolean;
532
644
  declare const makeEnvironmentThreadState: (threadId: string & import("effect/Brand").Brand<"ThreadId">) => Effect.Effect<SubscriptionRef.SubscriptionRef<EnvironmentThreadState>, never, EnvironmentCacheStore | EnvironmentSupervisor | import("effect/Scope").Scope | ThreadSnapshotLoader>;
533
645
  declare function threadStateChanges(environmentId: EnvironmentId, threadId: ThreadId): Stream.Stream<EnvironmentThreadState, never, EnvironmentCacheStore | EnvironmentRegistry | ThreadSnapshotLoader>;
534
646
  declare function createEnvironmentThreadStateAtoms<R, E>(runtime: Atom.AtomRuntime<EnvironmentRegistry | EnvironmentCacheStore | ThreadSnapshotLoader | R, E>): {
535
647
  stateAtom: (environmentId: EnvironmentId, threadId: ThreadId) => Atom.Atom<import("effect/unstable/reactivity/AsyncResult").AsyncResult<EnvironmentThreadState, E | Cause.NoSuchElementError>>;
536
648
  };
537
649
  //#endregion
538
- export { type ArchiveThreadInput, ArchivedSnapshotEntry, ArchivedThreadSnapshotsState, CheckpointDiffResult, CheckpointDiffState, CheckpointDiffTarget, ComposerPathSearchEntry, ComposerPathSearchState, ComposerPathSearchTarget, type CreateThreadInput, type DeleteThreadInput, EMPTY_ENVIRONMENT_THREAD_STATE, EnvironmentThreadState, EnvironmentThreadStatus, FetchEnvironmentThreadSnapshotError, type InterruptThreadTurnInput, type RespondToThreadApprovalInput, type RespondToThreadUserInputInput, type RevertThreadCheckpointInput, type SetThreadInteractionModeInput, type SetThreadRuntimeModeInput, type SettleThreadInput, type SnoozeThreadInput, type StartThreadTurnInput, type StopThreadSessionInput, ThreadDetailReducerResult, ThreadSnapshotLoader, type UnarchiveThreadInput, type UnsettleThreadInput, type UnsnoozeThreadInput, type UpdateThreadMetadataInput, applyThreadDetailEvent, createArchivedThreadSnapshotsAtomFamily, createEnvironmentThreadDetailAtoms, createEnvironmentThreadShellAtoms, createEnvironmentThreadStateAtoms, createThreadEnvironmentAtoms, fetchEnvironmentThreadSnapshot, makeArchivedThreadsEnvironmentKey, makeEnvironmentThreadState, mergeEnvironmentThread, parseArchivedThreadsEnvironmentKey, threadSnapshotLoaderLayer, threadStateChanges };
650
+ export { type ArchiveThreadInput, ArchivedSnapshotEntry, ArchivedThreadSnapshotsState, CheckpointDiffResult, CheckpointDiffState, CheckpointDiffTarget, ComposerPathSearchEntry, ComposerPathSearchState, ComposerPathSearchTarget, type CreateThreadInput, type DeleteThreadInput, EMPTY_ENVIRONMENT_THREAD_STATE, EnvironmentThreadPageState, EnvironmentThreadState, EnvironmentThreadStatus, FetchEnvironmentThreadSnapshotError, INITIAL_THREAD_USER_TURN_LIMIT, type InterruptThreadTurnInput, OLDER_THREAD_PAGE_USER_TURN_LIMIT, type PinThreadInput, type ReorderPinnedThreadInput, type RespondToThreadApprovalInput, type RespondToThreadUserInputInput, type RevertThreadCheckpointInput, type SetThreadInteractionModeInput, type SetThreadRuntimeModeInput, type SettleThreadInput, type SnoozeThreadInput, type StartThreadTurnInput, type StopThreadSessionInput, ThreadDetailReducerResult, ThreadOlderTurnRequests, ThreadSnapshotLoader, ThreadSnapshotWindow, type UnarchiveThreadInput, type UnpinThreadInput, type UnsettleThreadInput, type UnsnoozeThreadInput, type UpdateThreadMetadataInput, applyThreadDetailEvent, createArchivedThreadSnapshotsAtomFamily, createEnvironmentThreadDetailAtoms, createEnvironmentThreadShellAtoms, createEnvironmentThreadStateAtoms, createThreadEnvironmentAtoms, fetchEnvironmentThreadSnapshot, makeArchivedThreadsEnvironmentKey, makeEnvironmentThreadState, mergeEnvironmentThread, parseArchivedThreadsEnvironmentKey, requestOlderThreadTurns, threadHasOlderTurns, threadSnapshotLoaderLayer, threadStateChanges };