t3code-cli 0.13.0 → 0.14.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.
Files changed (324) hide show
  1. package/README.md +87 -1
  2. package/dist/application.d.ts +2 -0
  3. package/dist/application.js +1 -1
  4. package/dist/auth.d.ts +50 -0
  5. package/dist/auth.js +1 -1
  6. package/dist/bin.d.ts +1 -0
  7. package/dist/bin.js +355 -606
  8. package/dist/cli.d.ts +66 -0
  9. package/dist/cli.js +1 -1
  10. package/dist/client-runtime/authorization.d.ts +2 -0
  11. package/dist/client-runtime/authorization.js +2 -0
  12. package/dist/client-runtime/connection.d.ts +2 -0
  13. package/dist/client-runtime/connection.js +2 -0
  14. package/dist/client-runtime/environment.d.ts +57 -0
  15. package/dist/client-runtime/environment.js +2 -0
  16. package/dist/client-runtime/errors.d.ts +28 -0
  17. package/dist/client-runtime/errors.js +35 -0
  18. package/dist/client-runtime/operations/projects.d.ts +2 -0
  19. package/dist/client-runtime/operations/projects.js +2 -0
  20. package/dist/client-runtime/operations.d.ts +2 -0
  21. package/dist/client-runtime/operations.js +2 -0
  22. package/dist/client-runtime/platform.d.ts +26 -0
  23. package/dist/client-runtime/platform.js +74 -0
  24. package/dist/client-runtime/relay.d.ts +121 -0
  25. package/dist/client-runtime/relay.js +245 -0
  26. package/dist/client-runtime/rpc.d.ts +2 -0
  27. package/dist/client-runtime/rpc.js +2 -0
  28. package/dist/client-runtime/state/assets.d.ts +40 -0
  29. package/dist/client-runtime/state/assets.js +53 -0
  30. package/dist/client-runtime/state/auth.d.ts +98 -0
  31. package/dist/client-runtime/state/auth.js +48 -0
  32. package/dist/client-runtime/state/connections.d.ts +2 -0
  33. package/dist/client-runtime/state/connections.js +52 -0
  34. package/dist/client-runtime/state/entities.d.ts +33 -0
  35. package/dist/client-runtime/state/entities.js +2 -0
  36. package/dist/client-runtime/state/filesystem.d.ts +42 -0
  37. package/dist/client-runtime/state/filesystem.js +48 -0
  38. package/dist/client-runtime/state/git.d.ts +43 -0
  39. package/dist/client-runtime/state/git.js +18 -0
  40. package/dist/client-runtime/state/models.d.ts +2 -0
  41. package/dist/client-runtime/state/models.js +2 -0
  42. package/dist/client-runtime/state/orchestration.d.ts +128 -0
  43. package/dist/client-runtime/state/orchestration.js +20 -0
  44. package/dist/client-runtime/state/presentation.d.ts +277 -0
  45. package/dist/client-runtime/state/presentation.js +34 -0
  46. package/dist/client-runtime/state/preview.d.ts +447 -0
  47. package/dist/client-runtime/state/preview.js +103 -0
  48. package/dist/client-runtime/state/project-grouping.d.ts +26 -0
  49. package/dist/client-runtime/state/project-grouping.js +73 -0
  50. package/dist/client-runtime/state/projects.d.ts +192 -0
  51. package/dist/client-runtime/state/projects.js +2 -0
  52. package/dist/client-runtime/state/relay.d.ts +10 -0
  53. package/dist/client-runtime/state/relay.js +19 -0
  54. package/dist/client-runtime/state/review.d.ts +28 -0
  55. package/dist/client-runtime/state/review.js +11 -0
  56. package/dist/client-runtime/state/runtime.d.ts +2 -0
  57. package/dist/client-runtime/state/runtime.js +2 -0
  58. package/dist/client-runtime/state/server.d.ts +1495 -0
  59. package/dist/client-runtime/state/server.js +207 -0
  60. package/dist/client-runtime/state/session.d.ts +532 -0
  61. package/dist/client-runtime/state/session.js +21 -0
  62. package/dist/client-runtime/state/shell.d.ts +529 -0
  63. package/dist/client-runtime/state/shell.js +2 -0
  64. package/dist/client-runtime/state/source-control.d.ts +92 -0
  65. package/dist/client-runtime/state/source-control.js +36 -0
  66. package/dist/client-runtime/state/terminal.d.ts +237 -0
  67. package/dist/client-runtime/state/terminal.js +173 -0
  68. package/dist/client-runtime/state/thread-settled.d.ts +104 -0
  69. package/dist/client-runtime/state/thread-settled.js +157 -0
  70. package/dist/client-runtime/state/thread-sort.d.ts +23 -0
  71. package/dist/client-runtime/state/thread-sort.js +47 -0
  72. package/dist/client-runtime/state/threads.d.ts +538 -0
  73. package/dist/client-runtime/state/threads.js +934 -0
  74. package/dist/client-runtime/state/vcs.d.ts +442 -0
  75. package/dist/client-runtime/state/vcs.js +756 -0
  76. package/dist/config.d.ts +84 -0
  77. package/dist/config.js +1 -1
  78. package/dist/connection.d.ts +7 -0
  79. package/dist/connection.js +1 -1
  80. package/dist/contracts.d.ts +2 -0
  81. package/dist/contracts.js +2 -1
  82. package/dist/index.d.ts +2 -0
  83. package/dist/index.js +1 -1
  84. package/dist/node.d.ts +6 -0
  85. package/dist/node.js +1 -1
  86. package/dist/orchestration.d.ts +1420 -0
  87. package/dist/orchestration.js +1 -1
  88. package/dist/preview.d.ts +2 -0
  89. package/dist/preview.js +2 -0
  90. package/dist/rpc.d.ts +6043 -0
  91. package/dist/rpc.js +1 -1
  92. package/dist/runtime.d.ts +2 -0
  93. package/dist/runtime.js +2 -2
  94. package/dist/shared/DrainableWorker.d.ts +28 -0
  95. package/dist/shared/DrainableWorker.js +24 -0
  96. package/dist/shared/KeyedCoalescingWorker.d.ts +13 -0
  97. package/dist/shared/KeyedCoalescingWorker.js +89 -0
  98. package/dist/shared/Net.d.ts +43 -0
  99. package/dist/shared/Net.js +126 -0
  100. package/dist/shared/String.d.ts +4 -0
  101. package/dist/shared/String.js +8 -0
  102. package/dist/shared/Struct.d.ts +5 -0
  103. package/dist/shared/Struct.js +2 -0
  104. package/dist/shared/advertisedEndpoint.d.ts +2 -0
  105. package/dist/shared/advertisedEndpoint.js +2 -0
  106. package/dist/shared/agentAwareness.d.ts +27 -0
  107. package/dist/shared/agentAwareness.js +54 -0
  108. package/dist/shared/backgroundActivitySettings.d.ts +23 -0
  109. package/dist/shared/backgroundActivitySettings.js +2 -0
  110. package/dist/shared/chatList.d.ts +12 -0
  111. package/dist/shared/chatList.js +14 -0
  112. package/dist/shared/cliArgs.d.ts +33 -0
  113. package/dist/shared/cliArgs.js +103 -0
  114. package/dist/shared/composerInlineTokens.d.ts +20 -0
  115. package/dist/shared/composerInlineTokens.js +72 -0
  116. package/dist/shared/composerTrigger.d.ts +26 -0
  117. package/dist/shared/composerTrigger.js +97 -0
  118. package/dist/shared/connectAuth.d.ts +58 -0
  119. package/dist/shared/connectAuth.js +89 -0
  120. package/dist/shared/devHome.d.ts +21 -0
  121. package/dist/shared/devHome.js +65 -0
  122. package/dist/shared/devProxy.d.ts +15 -0
  123. package/dist/shared/devProxy.js +22 -0
  124. package/dist/shared/dpop.d.ts +32 -0
  125. package/dist/shared/dpop.js +2724 -0
  126. package/dist/shared/dpopCommon.d.ts +2 -0
  127. package/dist/shared/dpopCommon.js +2 -0
  128. package/dist/shared/filePreview.d.ts +8 -0
  129. package/dist/shared/filePreview.js +31 -0
  130. package/dist/shared/git.d.ts +41 -0
  131. package/dist/shared/git.js +2 -0
  132. package/dist/shared/hostProcess.d.ts +13 -0
  133. package/dist/shared/hostProcess.js +2 -0
  134. package/dist/shared/httpObservability.d.ts +5 -0
  135. package/dist/shared/httpObservability.js +2 -0
  136. package/dist/shared/httpReadiness.d.ts +38 -0
  137. package/dist/shared/httpReadiness.js +110 -0
  138. package/dist/shared/keybindings.d.ts +35 -0
  139. package/dist/shared/keybindings.js +330 -0
  140. package/dist/shared/logging.d.ts +39 -0
  141. package/dist/shared/logging.js +2 -0
  142. package/dist/shared/model.d.ts +44 -0
  143. package/dist/shared/model.js +2 -0
  144. package/dist/shared/oauthScope.d.ts +23 -0
  145. package/dist/shared/oauthScope.js +2 -0
  146. package/dist/shared/observability.d.ts +105 -0
  147. package/dist/shared/observability.js +346 -0
  148. package/dist/shared/orchestrationTiming.d.ts +16 -0
  149. package/dist/shared/orchestrationTiming.js +32 -0
  150. package/dist/shared/path.d.ts +2 -0
  151. package/dist/shared/path.js +2 -0
  152. package/dist/shared/preview.d.ts +35 -0
  153. package/dist/shared/preview.js +103 -0
  154. package/dist/shared/previewViewport.d.ts +16 -0
  155. package/dist/shared/previewViewport.js +159 -0
  156. package/dist/shared/projectFavicon.d.ts +5 -0
  157. package/dist/shared/projectFavicon.js +13 -0
  158. package/dist/shared/projectScripts.d.ts +19 -0
  159. package/dist/shared/projectScripts.js +18 -0
  160. package/dist/shared/qrCode.d.ts +87 -0
  161. package/dist/shared/qrCode.js +870 -0
  162. package/dist/shared/relayAuth.d.ts +27 -0
  163. package/dist/shared/relayAuth.js +83 -0
  164. package/dist/shared/relayClient.d.ts +58 -0
  165. package/dist/shared/relayClient.js +245 -0
  166. package/dist/shared/relayJwt.d.ts +39 -0
  167. package/dist/shared/relayJwt.js +2 -0
  168. package/dist/shared/relaySigning.d.ts +4 -0
  169. package/dist/shared/relaySigning.js +2 -0
  170. package/dist/shared/relayTracing.d.ts +25 -0
  171. package/dist/shared/relayTracing.js +2 -0
  172. package/dist/shared/relayUrl.d.ts +5 -0
  173. package/dist/shared/relayUrl.js +2 -0
  174. package/dist/shared/remote.d.ts +57 -0
  175. package/dist/shared/remote.js +2 -0
  176. package/dist/shared/schemaJson.d.ts +35 -0
  177. package/dist/shared/schemaJson.js +2 -0
  178. package/dist/shared/schemaYaml.d.ts +86 -0
  179. package/dist/shared/schemaYaml.js +99 -0
  180. package/dist/shared/searchRanking.d.ts +30 -0
  181. package/dist/shared/searchRanking.js +99 -0
  182. package/dist/shared/semver.d.ts +23 -0
  183. package/dist/shared/semver.js +124 -0
  184. package/dist/shared/serverSettings.d.ts +19 -0
  185. package/dist/shared/serverSettings.js +103 -0
  186. package/dist/shared/shell.d.ts +51 -0
  187. package/dist/shared/shell.js +408 -0
  188. package/dist/shared/sourceControl.d.ts +26 -0
  189. package/dist/shared/sourceControl.js +2 -0
  190. package/dist/shared/t3ProjectFile.d.ts +27 -0
  191. package/dist/shared/t3ProjectFile.js +25 -0
  192. package/dist/shared/terminalLabels.d.ts +16 -0
  193. package/dist/shared/terminalLabels.js +28 -0
  194. package/dist/shared/toolActivity.d.ts +16 -0
  195. package/dist/shared/toolActivity.js +159 -0
  196. package/dist/shared.d.ts +43036 -0
  197. package/dist/shared.js +25428 -12277
  198. package/dist/t3tools.d.ts +2 -0
  199. package/dist/t3tools.js +1 -1
  200. package/package.json +39 -21
  201. package/src/auth/index.ts +2 -0
  202. package/src/auth/pairing.ts +8 -5
  203. package/src/auth/service.ts +2 -1
  204. package/src/auth/transport.ts +4 -0
  205. package/src/auth/type.ts +6 -0
  206. package/src/bin.ts +10 -7
  207. package/src/cli/auth.ts +7 -1
  208. package/src/contracts/index.ts +8 -0
  209. package/src/orchestration/layer.ts +36 -0
  210. package/src/orchestration/service.ts +5 -0
  211. package/src/preview/index.ts +11 -0
  212. package/src/preview/service.ts +52 -0
  213. package/src/rpc/error.ts +2 -0
  214. package/src/rpc/layer.ts +5 -4
  215. package/src/rpc/operation.ts +5 -4
  216. package/src/rpc/ws-group.ts +6 -0
  217. package/src/runtime/index.ts +1 -0
  218. package/src/runtime/layer.ts +5 -0
  219. package/src/sql/node-sqlite-client.ts +3 -0
  220. package/dist/src/application/actions.d.ts +0 -25
  221. package/dist/src/application/error.d.ts +0 -3
  222. package/dist/src/application/index.d.ts +0 -4
  223. package/dist/src/application/layer.d.ts +0 -117
  224. package/dist/src/application/model-selection.d.ts +0 -34
  225. package/dist/src/application/models.d.ts +0 -8
  226. package/dist/src/application/project-commands.d.ts +0 -44
  227. package/dist/src/application/projects.d.ts +0 -23
  228. package/dist/src/application/service.d.ts +0 -243
  229. package/dist/src/application/shell-sequence.d.ts +0 -96
  230. package/dist/src/application/terminals.d.ts +0 -66
  231. package/dist/src/application/thread-commands.d.ts +0 -157
  232. package/dist/src/application/thread-update.d.ts +0 -8
  233. package/dist/src/application/thread-wait.d.ts +0 -106
  234. package/dist/src/application/threads.d.ts +0 -660
  235. package/dist/src/auth/error.d.ts +0 -50
  236. package/dist/src/auth/index.d.ts +0 -10
  237. package/dist/src/auth/layer.d.ts +0 -53
  238. package/dist/src/auth/local-base-dir.d.ts +0 -8
  239. package/dist/src/auth/local-origin.d.ts +0 -18
  240. package/dist/src/auth/local-token.d.ts +0 -26
  241. package/dist/src/auth/local.d.ts +0 -24
  242. package/dist/src/auth/pairing.d.ts +0 -22
  243. package/dist/src/auth/remote-error.d.ts +0 -3
  244. package/dist/src/auth/schema.d.ts +0 -58
  245. package/dist/src/auth/service.d.ts +0 -27
  246. package/dist/src/auth/transport.d.ts +0 -22
  247. package/dist/src/auth/type.d.ts +0 -83
  248. package/dist/src/cli/env/flag.d.ts +0 -2
  249. package/dist/src/cli/env/index.d.ts +0 -2
  250. package/dist/src/cli/env/selection-layer.d.ts +0 -3
  251. package/dist/src/cli/flags.d.ts +0 -20
  252. package/dist/src/cli/format/index.d.ts +0 -1
  253. package/dist/src/cli/format/output.d.ts +0 -12
  254. package/dist/src/cli/index.d.ts +0 -5
  255. package/dist/src/cli/runtime/index.d.ts +0 -1
  256. package/dist/src/cli/runtime/service.d.ts +0 -16
  257. package/dist/src/cli/scope/index.d.ts +0 -1
  258. package/dist/src/cli/scope/resolve.d.ts +0 -20
  259. package/dist/src/cli-path/layer.d.ts +0 -3
  260. package/dist/src/cli-path/service.d.ts +0 -8
  261. package/dist/src/config/config.d.ts +0 -49
  262. package/dist/src/config/credential/cipher-node.d.ts +0 -3
  263. package/dist/src/config/credential/cipher-web.d.ts +0 -3
  264. package/dist/src/config/credential/cipher.d.ts +0 -29
  265. package/dist/src/config/credential/env.d.ts +0 -3
  266. package/dist/src/config/credential/error.d.ts +0 -8
  267. package/dist/src/config/credential/index.d.ts +0 -6
  268. package/dist/src/config/credential/service.d.ts +0 -34
  269. package/dist/src/config/env/env.d.ts +0 -55
  270. package/dist/src/config/env/index.d.ts +0 -2
  271. package/dist/src/config/env/layout.d.ts +0 -11
  272. package/dist/src/config/environment-name/index.d.ts +0 -1
  273. package/dist/src/config/environment-name/name.d.ts +0 -10
  274. package/dist/src/config/error.d.ts +0 -11
  275. package/dist/src/config/index.d.ts +0 -10
  276. package/dist/src/config/keystore/error.d.ts +0 -8
  277. package/dist/src/config/keystore/file.d.ts +0 -9
  278. package/dist/src/config/keystore/index.d.ts +0 -4
  279. package/dist/src/config/keystore/keyring-node.d.ts +0 -4
  280. package/dist/src/config/keystore/service.d.ts +0 -33
  281. package/dist/src/config/paths/index.d.ts +0 -1
  282. package/dist/src/config/paths/paths.d.ts +0 -6
  283. package/dist/src/config/persist/file-mode.d.ts +0 -4
  284. package/dist/src/config/persist/migration.d.ts +0 -68
  285. package/dist/src/config/persist/persist.d.ts +0 -40
  286. package/dist/src/config/persist/schema.d.ts +0 -68
  287. package/dist/src/config/resolve/resolve.d.ts +0 -40
  288. package/dist/src/config/selection/index.d.ts +0 -1
  289. package/dist/src/config/selection/resolve.d.ts +0 -4
  290. package/dist/src/config/selection/service.d.ts +0 -10
  291. package/dist/src/config/types.d.ts +0 -36
  292. package/dist/src/config/url/error.d.ts +0 -10
  293. package/dist/src/config/url/index.d.ts +0 -2
  294. package/dist/src/config/url/url.d.ts +0 -6
  295. package/dist/src/connection/error.d.ts +0 -10
  296. package/dist/src/connection/index.d.ts +0 -4
  297. package/dist/src/connection/layer.d.ts +0 -3
  298. package/dist/src/connection/prepared.d.ts +0 -14
  299. package/dist/src/connection/service.d.ts +0 -13
  300. package/dist/src/connection/type.d.ts +0 -10
  301. package/dist/src/contracts/index.d.ts +0 -1
  302. package/dist/src/domain/error.d.ts +0 -57
  303. package/dist/src/domain/helpers.d.ts +0 -179
  304. package/dist/src/domain/model-config.d.ts +0 -330
  305. package/dist/src/domain/thread-activities.d.ts +0 -14
  306. package/dist/src/domain/thread-lifecycle.d.ts +0 -120
  307. package/dist/src/index.d.ts +0 -3
  308. package/dist/src/node/connection.d.ts +0 -2
  309. package/dist/src/node/index.d.ts +0 -1
  310. package/dist/src/orchestration/index.d.ts +0 -2
  311. package/dist/src/orchestration/layer.d.ts +0 -1419
  312. package/dist/src/orchestration/service.d.ts +0 -28
  313. package/dist/src/rpc/error.d.ts +0 -16
  314. package/dist/src/rpc/index.d.ts +0 -6
  315. package/dist/src/rpc/layer.d.ts +0 -5862
  316. package/dist/src/rpc/operation.d.ts +0 -24
  317. package/dist/src/rpc/service.d.ts +0 -15
  318. package/dist/src/rpc/session.d.ts +0 -22
  319. package/dist/src/rpc/ws-group.d.ts +0 -1984
  320. package/dist/src/runtime/index.d.ts +0 -1
  321. package/dist/src/runtime/layer.d.ts +0 -15
  322. package/dist/src/sql/node-sqlite-client.d.ts +0 -10
  323. package/dist/src/sql/service.d.ts +0 -17
  324. package/dist/src/t3tools/index.d.ts +0 -1
@@ -0,0 +1,934 @@
1
+ import { $D as flatMap, $t as projectRefCollectionKey, Aa as EnvironmentSupervisor, BD as andThen, BE as filter$1, Bk as isSome, Cn as startThreadTurn, Cv as get$1, Dn as unsnoozeThread, EO as succeed, En as unsettleThread, Ev as update, Fk as getOrElse, Fr as buildEnvironmentAuthHeaders, GC as set, GD as catchCause, Gr as family, HD as as, Hk as match, IC as HttpClient, IE as debounce, Ik as getOrNull, Io as environmentEndpointUrl, Ir as withEnvironmentCredentials, JD as catchTags, JS as EnvironmentId, Ja as ManagedRelayDpopSigner, Jr as setIdleTTL, Jt as arrayElementsEqual, KE as map$3, Kk as Number$1, La as EnvironmentCacheStore, Lk as getOrThrow, Mo as executeEnvironmentHttpRequest, No as makeEnvironmentHttpApiClient, QO as effect, Qk as mapInput, RD as addFinalizer, RO as void_, Sn as snoozeThread, Sv as changes, Tn as unarchiveThread, Tv as set$1, UC as get, Uk as none, VD as annotateLogs, Vk as map$2, WC as make$2, WE as fromQueue, Wk as some, Wr as subscribeDynamic, XE as never, XO as pretty, Xk as combineAll, Xr as withLabel, Xt as parseProjectRefCollectionKey, YD as catch_, Yk as combine, ZO as squash, Zt as parseThreadKey, _O as orElseSucceed, _k as map$1, _n as respondToThreadUserInput, aO as gen, bO as provideService, bn as setThreadRuntimeMode, cA as pipe, cO as logDebug, eO as fn, fn as createThread, gk as filter, gn as respondToThreadApproval, hk as append, hn as interruptThreadTurn, iO as forkScoped, ja as ConnectionWakeups, kk as Service, kn as updateThreadMetadata, ky as ORCHESTRATION_WS_METHODS, lD as unwrap, lO as logWarning, lr as createAtomCommandScheduler, mn as deleteThread, nD as runHead, nn as threadRefsEqual, or as scopeThread, qk as String, qr as make, sr as scopeThreadShell, tD as runForEach, ti as value, tn as threadKey, uO as map, un as archiveThread, ur as createEnvironmentCommand, vD as offer, vk as sort, vn as revertThreadCheckpoint, wO as serviceOption, wn as stopThreadSession, wv as make$1, xD as sliding, xn as settleThread, xr as followStreamInEnvironment, xs as connectionProjectionPhase, yn as setThreadInteractionMode, zD as all, zk as isNone } from "../../shared.js";
2
+ //#region upstream-t3code/packages/client-runtime/src/state/threadSnapshotHttp.ts
3
+ const DEFAULT_THREAD_SNAPSHOT_TIMEOUT_MS = 6e3;
4
+ /**
5
+ * Load a thread's detail snapshot over HTTP instead of embedding it in the
6
+ * WebSocket subscription's first frame. The response is gzip-compressible by
7
+ * the transport and keeps the (potentially multi-KB) snapshot off the socket.
8
+ */
9
+ const fetchEnvironmentThreadSnapshot = fn("clientRuntime.state.fetchEnvironmentThreadSnapshot")(function* (input) {
10
+ const requestUrl = environmentEndpointUrl(input.prepared.httpBaseUrl, `/api/orchestration/threads/${input.threadId}`);
11
+ const client = yield* makeEnvironmentHttpApiClient(input.prepared.httpBaseUrl);
12
+ const headers = yield* buildEnvironmentAuthHeaders(input.prepared.httpAuthorization, "GET", requestUrl, input.signer);
13
+ return yield* executeEnvironmentHttpRequest(requestUrl, input.timeoutMs ?? DEFAULT_THREAD_SNAPSHOT_TIMEOUT_MS, withEnvironmentCredentials(input.prepared.httpAuthorization, client.orchestration.threadSnapshot({
14
+ params: { threadId: input.threadId },
15
+ headers
16
+ })));
17
+ });
18
+ /**
19
+ * Loads a thread's detail snapshot over HTTP, returning `Option.none()` when it
20
+ * cannot be loaded (so the caller falls back to the socket-embedded snapshot).
21
+ * Decouples the thread state machine from the underlying HTTP + DPoP details and
22
+ * keeps them out of test contexts.
23
+ */
24
+ var ThreadSnapshotLoader = class extends Service()("@t3tools/client-runtime/state/threadSnapshotHttp/ThreadSnapshotLoader") {};
25
+ const threadSnapshotLoaderLayer = effect(ThreadSnapshotLoader, gen(function* () {
26
+ const httpClient = yield* HttpClient;
27
+ const signer = yield* serviceOption(ManagedRelayDpopSigner);
28
+ return ThreadSnapshotLoader.of({ load: (prepared, threadId) => fetchEnvironmentThreadSnapshot({
29
+ prepared,
30
+ threadId,
31
+ signer
32
+ }).pipe(map(some), provideService(HttpClient, httpClient), catchTags({ EnvironmentResourceNotFoundError: () => logDebug("Thread snapshot not found over HTTP; deferring to the socket subscription.").pipe(annotateLogs({ threadId }), as(none())) }), catchCause((cause) => logWarning("Could not load the thread snapshot over HTTP; using the socket snapshot instead.").pipe(annotateLogs({
33
+ threadId,
34
+ cause: pretty(cause)
35
+ }), as(none())))) });
36
+ }));
37
+ //#endregion
38
+ //#region upstream-t3code/packages/client-runtime/src/state/threadReducer.ts
39
+ const proposedPlanOrder = combine(mapInput(String, (p) => p.createdAt), mapInput(String, (p) => p.id));
40
+ const checkpointOrder = mapInput(Number$1, (cp) => cp.checkpointTurnCount ?? Number.MAX_SAFE_INTEGER);
41
+ const activityOrder = combineAll([
42
+ mapInput(Number$1, (a) => a.sequence ?? Number.MAX_SAFE_INTEGER),
43
+ mapInput(String, (a) => a.createdAt),
44
+ mapInput(String, (a) => a.id)
45
+ ]);
46
+ /**
47
+ * Apply a single orchestration event to an `OrchestrationThread`, returning
48
+ * the updated thread, a deletion signal, or an "unchanged" marker when the
49
+ * event doesn't affect this thread.
50
+ *
51
+ * This is a pure reducer operating on contract types. UI-specific mapping
52
+ * (e.g. resolving attachment preview URLs, normalising model slugs, adding
53
+ * scoped fields like `environmentId`) is the caller's responsibility.
54
+ */
55
+ function applyThreadDetailEvent(thread, event) {
56
+ switch (event.type) {
57
+ case "project.created":
58
+ case "project.meta-updated":
59
+ case "project.deleted": return { kind: "unchanged" };
60
+ case "thread.created": return {
61
+ kind: "updated",
62
+ thread: {
63
+ id: event.payload.threadId,
64
+ projectId: event.payload.projectId,
65
+ title: event.payload.title,
66
+ modelSelection: event.payload.modelSelection,
67
+ runtimeMode: event.payload.runtimeMode,
68
+ interactionMode: event.payload.interactionMode,
69
+ branch: event.payload.branch,
70
+ worktreePath: event.payload.worktreePath,
71
+ latestTurn: null,
72
+ createdAt: event.payload.createdAt,
73
+ updatedAt: event.payload.updatedAt,
74
+ archivedAt: null,
75
+ settledOverride: null,
76
+ settledAt: null,
77
+ snoozedUntil: null,
78
+ snoozedAt: null,
79
+ deletedAt: null,
80
+ messages: [],
81
+ proposedPlans: [],
82
+ activities: [],
83
+ checkpoints: [],
84
+ session: null
85
+ }
86
+ };
87
+ case "thread.deleted": return { kind: "deleted" };
88
+ case "thread.archived": return {
89
+ kind: "updated",
90
+ thread: {
91
+ ...thread,
92
+ archivedAt: event.payload.archivedAt,
93
+ updatedAt: event.payload.updatedAt
94
+ }
95
+ };
96
+ case "thread.unarchived": return {
97
+ kind: "updated",
98
+ thread: {
99
+ ...thread,
100
+ archivedAt: null,
101
+ updatedAt: event.payload.updatedAt
102
+ }
103
+ };
104
+ case "thread.settled": return {
105
+ kind: "updated",
106
+ thread: {
107
+ ...thread,
108
+ settledOverride: "settled",
109
+ settledAt: event.payload.settledAt,
110
+ updatedAt: event.payload.updatedAt
111
+ }
112
+ };
113
+ case "thread.unsettled": return {
114
+ kind: "updated",
115
+ thread: {
116
+ ...thread,
117
+ settledOverride: event.payload.reason === "user" ? "active" : null,
118
+ settledAt: null,
119
+ updatedAt: event.payload.updatedAt
120
+ }
121
+ };
122
+ case "thread.snoozed": return {
123
+ kind: "updated",
124
+ thread: {
125
+ ...thread,
126
+ snoozedUntil: event.payload.snoozedUntil,
127
+ snoozedAt: event.payload.snoozedAt,
128
+ updatedAt: event.payload.updatedAt
129
+ }
130
+ };
131
+ case "thread.unsnoozed": return {
132
+ kind: "updated",
133
+ thread: {
134
+ ...thread,
135
+ snoozedUntil: null,
136
+ snoozedAt: null,
137
+ updatedAt: event.payload.updatedAt
138
+ }
139
+ };
140
+ case "thread.meta-updated": return {
141
+ kind: "updated",
142
+ thread: {
143
+ ...thread,
144
+ ...event.payload.title !== void 0 ? { title: event.payload.title } : {},
145
+ ...event.payload.modelSelection !== void 0 ? { modelSelection: event.payload.modelSelection } : {},
146
+ ...event.payload.branch !== void 0 ? { branch: event.payload.branch } : {},
147
+ ...event.payload.worktreePath !== void 0 ? { worktreePath: event.payload.worktreePath } : {},
148
+ updatedAt: event.payload.updatedAt
149
+ }
150
+ };
151
+ case "thread.runtime-mode-set": return {
152
+ kind: "updated",
153
+ thread: {
154
+ ...thread,
155
+ runtimeMode: event.payload.runtimeMode,
156
+ updatedAt: event.payload.updatedAt
157
+ }
158
+ };
159
+ case "thread.interaction-mode-set": return {
160
+ kind: "updated",
161
+ thread: {
162
+ ...thread,
163
+ interactionMode: event.payload.interactionMode,
164
+ updatedAt: event.payload.updatedAt
165
+ }
166
+ };
167
+ case "thread.turn-start-requested": return {
168
+ kind: "updated",
169
+ thread: {
170
+ ...thread,
171
+ ...event.payload.modelSelection !== void 0 ? { modelSelection: event.payload.modelSelection } : {},
172
+ runtimeMode: event.payload.runtimeMode,
173
+ interactionMode: event.payload.interactionMode,
174
+ updatedAt: event.occurredAt
175
+ }
176
+ };
177
+ case "thread.turn-interrupt-requested": {
178
+ if (event.payload.turnId === void 0) return { kind: "unchanged" };
179
+ const latestTurn = thread.latestTurn;
180
+ if (latestTurn === null || latestTurn.turnId !== event.payload.turnId) return { kind: "unchanged" };
181
+ return {
182
+ kind: "updated",
183
+ thread: {
184
+ ...thread,
185
+ latestTurn: {
186
+ ...latestTurn,
187
+ state: "interrupted",
188
+ startedAt: latestTurn.startedAt ?? event.payload.createdAt,
189
+ completedAt: latestTurn.completedAt ?? event.payload.createdAt
190
+ },
191
+ updatedAt: event.occurredAt
192
+ }
193
+ };
194
+ }
195
+ case "thread.message-sent": {
196
+ const message = {
197
+ id: event.payload.messageId,
198
+ role: event.payload.role,
199
+ text: event.payload.text,
200
+ ...event.payload.attachments !== void 0 ? { attachments: event.payload.attachments } : {},
201
+ turnId: event.payload.turnId,
202
+ streaming: event.payload.streaming,
203
+ createdAt: event.payload.createdAt,
204
+ updatedAt: event.payload.updatedAt
205
+ };
206
+ const messages = thread.messages.find((entry) => entry.id === message.id) ? map$1(thread.messages, (entry) => entry.id !== message.id ? entry : {
207
+ ...entry,
208
+ text: message.streaming ? `${entry.text}${message.text}` : message.text.length > 0 ? message.text : entry.text,
209
+ streaming: message.streaming,
210
+ ...message.turnId !== void 0 ? { turnId: message.turnId } : {},
211
+ ...message.streaming ? {} : { updatedAt: message.updatedAt },
212
+ ...message.attachments !== void 0 ? { attachments: message.attachments } : {}
213
+ }) : append(thread.messages, message);
214
+ const turnStillRunning = event.payload.turnId !== null && thread.session?.status === "running" && thread.session.activeTurnId === event.payload.turnId;
215
+ const settlesTurn = !event.payload.streaming && !turnStillRunning;
216
+ const latestTurn = event.payload.role === "assistant" && event.payload.turnId !== null && (thread.latestTurn === null || thread.latestTurn.turnId === event.payload.turnId) ? {
217
+ turnId: event.payload.turnId,
218
+ state: settlesTurn ? thread.latestTurn?.state === "interrupted" ? "interrupted" : thread.latestTurn?.state === "error" ? "error" : "completed" : "running",
219
+ requestedAt: thread.latestTurn?.turnId === event.payload.turnId ? thread.latestTurn.requestedAt : event.payload.createdAt,
220
+ startedAt: thread.latestTurn?.turnId === event.payload.turnId ? thread.latestTurn.startedAt ?? event.payload.createdAt : event.payload.createdAt,
221
+ completedAt: settlesTurn ? event.payload.updatedAt : thread.latestTurn?.turnId === event.payload.turnId ? thread.latestTurn.completedAt ?? null : null,
222
+ assistantMessageId: event.payload.messageId
223
+ } : thread.latestTurn;
224
+ const checkpoints = event.payload.role === "assistant" && event.payload.turnId !== null ? rebindCheckpointAssistantMessage(thread.checkpoints, event.payload.turnId, event.payload.messageId) : thread.checkpoints;
225
+ return {
226
+ kind: "updated",
227
+ thread: {
228
+ ...thread,
229
+ messages,
230
+ checkpoints,
231
+ latestTurn,
232
+ updatedAt: event.occurredAt
233
+ }
234
+ };
235
+ }
236
+ case "thread.session-set": {
237
+ const settledTurnState = settledTurnStateForSessionStatus(event.payload.session.status);
238
+ const latestTurn = event.payload.session.status === "running" && event.payload.session.activeTurnId !== null ? {
239
+ turnId: event.payload.session.activeTurnId,
240
+ state: "running",
241
+ requestedAt: thread.latestTurn?.turnId === event.payload.session.activeTurnId ? thread.latestTurn.requestedAt : event.payload.session.updatedAt,
242
+ startedAt: thread.latestTurn?.turnId === event.payload.session.activeTurnId ? thread.latestTurn.startedAt ?? event.payload.session.updatedAt : event.payload.session.updatedAt,
243
+ completedAt: null,
244
+ assistantMessageId: thread.latestTurn?.turnId === event.payload.session.activeTurnId ? thread.latestTurn.assistantMessageId : null
245
+ } : thread.latestTurn !== null && thread.latestTurn.state === "running" && settledTurnState !== null ? {
246
+ ...thread.latestTurn,
247
+ state: settledTurnState,
248
+ completedAt: event.payload.session.updatedAt
249
+ } : thread.latestTurn;
250
+ return {
251
+ kind: "updated",
252
+ thread: {
253
+ ...thread,
254
+ session: event.payload.session,
255
+ latestTurn,
256
+ updatedAt: event.occurredAt
257
+ }
258
+ };
259
+ }
260
+ case "thread.session-stop-requested": return thread.session === null ? { kind: "unchanged" } : {
261
+ kind: "updated",
262
+ thread: {
263
+ ...thread,
264
+ session: {
265
+ ...thread.session,
266
+ status: "stopped",
267
+ activeTurnId: null,
268
+ updatedAt: event.payload.createdAt
269
+ },
270
+ updatedAt: event.occurredAt
271
+ }
272
+ };
273
+ case "thread.proposed-plan-upserted": {
274
+ const proposedPlan = event.payload.proposedPlan;
275
+ const proposedPlans = pipe(thread.proposedPlans, filter((entry) => entry.id !== proposedPlan.id), append(proposedPlan), sort(proposedPlanOrder));
276
+ return {
277
+ kind: "updated",
278
+ thread: {
279
+ ...thread,
280
+ proposedPlans,
281
+ updatedAt: event.occurredAt
282
+ }
283
+ };
284
+ }
285
+ case "thread.turn-diff-completed": {
286
+ const checkpoint = {
287
+ turnId: event.payload.turnId,
288
+ checkpointTurnCount: event.payload.checkpointTurnCount,
289
+ checkpointRef: event.payload.checkpointRef,
290
+ status: event.payload.status,
291
+ files: event.payload.files,
292
+ assistantMessageId: event.payload.assistantMessageId,
293
+ completedAt: event.payload.completedAt
294
+ };
295
+ const existing = thread.checkpoints.find((entry) => entry.turnId === checkpoint.turnId);
296
+ if (existing && existing.status !== "missing" && checkpoint.status === "missing") return { kind: "unchanged" };
297
+ const checkpoints = pipe(thread.checkpoints, filter((entry) => entry.turnId !== checkpoint.turnId), append(checkpoint), sort(checkpointOrder));
298
+ const latestTurn = !(thread.session?.status === "running" && thread.session.activeTurnId === event.payload.turnId) && (thread.latestTurn === null || thread.latestTurn.turnId === event.payload.turnId) ? {
299
+ turnId: event.payload.turnId,
300
+ state: checkpointStatusToTurnState(event.payload.status),
301
+ requestedAt: thread.latestTurn?.requestedAt ?? event.payload.completedAt,
302
+ startedAt: thread.latestTurn?.startedAt ?? event.payload.completedAt,
303
+ completedAt: event.payload.completedAt,
304
+ assistantMessageId: event.payload.assistantMessageId
305
+ } : thread.latestTurn;
306
+ return {
307
+ kind: "updated",
308
+ thread: {
309
+ ...thread,
310
+ checkpoints,
311
+ latestTurn,
312
+ updatedAt: event.occurredAt
313
+ }
314
+ };
315
+ }
316
+ case "thread.reverted": {
317
+ const checkpoints = pipe(thread.checkpoints, filter((entry) => entry.checkpointTurnCount !== void 0 && entry.checkpointTurnCount <= event.payload.turnCount), sort(checkpointOrder));
318
+ const retainedTurnIds = new Set(map$1(checkpoints, (entry) => entry.turnId));
319
+ const messages = retainMessagesAfterRevert(thread.messages, retainedTurnIds);
320
+ const proposedPlans = pipe(thread.proposedPlans, filter((plan) => plan.turnId === null || retainedTurnIds.has(plan.turnId)));
321
+ const activities = pipe(thread.activities, filter((activity) => activity.turnId === null || retainedTurnIds.has(activity.turnId)));
322
+ const latestCheckpoint = checkpoints.at(-1) ?? null;
323
+ return {
324
+ kind: "updated",
325
+ thread: {
326
+ ...thread,
327
+ checkpoints,
328
+ messages,
329
+ proposedPlans,
330
+ activities,
331
+ latestTurn: latestCheckpoint === null ? null : {
332
+ turnId: latestCheckpoint.turnId,
333
+ state: checkpointStatusToTurnState(latestCheckpoint.status),
334
+ requestedAt: latestCheckpoint.completedAt,
335
+ startedAt: latestCheckpoint.completedAt,
336
+ completedAt: latestCheckpoint.completedAt,
337
+ assistantMessageId: latestCheckpoint.assistantMessageId ?? null
338
+ },
339
+ updatedAt: event.occurredAt
340
+ }
341
+ };
342
+ }
343
+ case "thread.activity-appended": {
344
+ const activities = pipe(thread.activities, filter((activity) => activity.id !== event.payload.activity.id), append(event.payload.activity), sort(activityOrder));
345
+ return {
346
+ kind: "updated",
347
+ thread: {
348
+ ...thread,
349
+ activities,
350
+ updatedAt: event.occurredAt
351
+ }
352
+ };
353
+ }
354
+ case "thread.approval-response-requested":
355
+ case "thread.user-input-response-requested":
356
+ case "thread.checkpoint-revert-requested": return { kind: "unchanged" };
357
+ }
358
+ return { kind: "unchanged" };
359
+ }
360
+ /**
361
+ * Turn state to settle a still-running latest turn with when its session
362
+ * leaves the "running" status, or null while the session is (re)starting or
363
+ * running and the turn must stay unsettled.
364
+ */
365
+ function settledTurnStateForSessionStatus(status) {
366
+ switch (status) {
367
+ case "idle":
368
+ case "ready": return "completed";
369
+ case "error": return "error";
370
+ case "interrupted":
371
+ case "stopped": return "interrupted";
372
+ case "starting":
373
+ case "running": return null;
374
+ }
375
+ }
376
+ function checkpointStatusToTurnState(status) {
377
+ switch (status) {
378
+ case "ready": return "completed";
379
+ case "error": return "error";
380
+ case "missing": return "completed";
381
+ }
382
+ }
383
+ function rebindCheckpointAssistantMessage(checkpoints, turnId, messageId) {
384
+ return map$1(checkpoints, (entry) => entry.turnId === turnId ? {
385
+ ...entry,
386
+ assistantMessageId: messageId
387
+ } : entry);
388
+ }
389
+ function retainMessagesAfterRevert(messages, retainedTurnIds) {
390
+ return filter(messages, (message) => {
391
+ if (message.role === "system") return true;
392
+ if (message.turnId === null) return true;
393
+ return retainedTurnIds.has(message.turnId);
394
+ });
395
+ }
396
+ //#endregion
397
+ //#region upstream-t3code/packages/client-runtime/src/state/threadRetention.ts
398
+ const THREAD_STATE_IDLE_TTL_MS = 5 * 6e4;
399
+ //#endregion
400
+ //#region upstream-t3code/packages/client-runtime/src/state/threadState.ts
401
+ const EMPTY_ENVIRONMENT_THREAD_STATE = {
402
+ data: none(),
403
+ status: "empty",
404
+ error: none()
405
+ };
406
+ //#endregion
407
+ //#region upstream-t3code/packages/client-runtime/src/state/archivedThreads.ts
408
+ const ARCHIVED_THREADS_ENVIRONMENT_KEY_SEPARATOR = "";
409
+ const environmentIdOrder = String;
410
+ function makeArchivedThreadsEnvironmentKey(environmentIds) {
411
+ return pipe(environmentIds, sort(environmentIdOrder), (sortedEnvironmentIds) => sortedEnvironmentIds.join(ARCHIVED_THREADS_ENVIRONMENT_KEY_SEPARATOR));
412
+ }
413
+ function parseArchivedThreadsEnvironmentKey(key) {
414
+ if (key.length === 0) return [];
415
+ return pipe(key.split(ARCHIVED_THREADS_ENVIRONMENT_KEY_SEPARATOR), map$1((environmentId) => EnvironmentId.make(environmentId)));
416
+ }
417
+ function createArchivedThreadSnapshotsAtomFamily(options) {
418
+ return family((environmentKey) => make((get) => {
419
+ const snapshots = [];
420
+ let error = null;
421
+ let isLoading = false;
422
+ for (const environmentId of parseArchivedThreadsEnvironmentKey(environmentKey)) {
423
+ const result = get(options.getSnapshotAtom(environmentId));
424
+ isLoading ||= result.waiting;
425
+ const snapshot = getOrNull(value(result));
426
+ if (snapshot !== null) snapshots.push({
427
+ environmentId,
428
+ snapshot
429
+ });
430
+ if (error === null && result._tag === "Failure") error = "Failed to load archived threads.";
431
+ }
432
+ return {
433
+ snapshots,
434
+ error,
435
+ isLoading
436
+ };
437
+ }).pipe(withLabel(`${options.labelPrefix}:${environmentKey}`)));
438
+ }
439
+ //#endregion
440
+ //#region upstream-t3code/packages/client-runtime/src/state/threadCommands.ts
441
+ function createThreadEnvironmentAtoms(runtime) {
442
+ const scheduler = createAtomCommandScheduler();
443
+ const concurrency = {
444
+ mode: "serial",
445
+ key: ({ environmentId, input }) => JSON.stringify([environmentId, input.threadId])
446
+ };
447
+ return {
448
+ create: createEnvironmentCommand(runtime, {
449
+ label: "environment-data:commands:thread:create",
450
+ execute: (input) => createThread(input),
451
+ scheduler,
452
+ concurrency
453
+ }),
454
+ delete: createEnvironmentCommand(runtime, {
455
+ label: "environment-data:commands:thread:delete",
456
+ execute: (input) => deleteThread(input),
457
+ scheduler,
458
+ concurrency
459
+ }),
460
+ archive: createEnvironmentCommand(runtime, {
461
+ label: "environment-data:commands:thread:archive",
462
+ execute: (input) => archiveThread(input),
463
+ scheduler,
464
+ concurrency
465
+ }),
466
+ unarchive: createEnvironmentCommand(runtime, {
467
+ label: "environment-data:commands:thread:unarchive",
468
+ execute: (input) => unarchiveThread(input),
469
+ scheduler,
470
+ concurrency
471
+ }),
472
+ settle: createEnvironmentCommand(runtime, {
473
+ label: "environment-data:commands:thread:settle",
474
+ execute: (input) => settleThread(input),
475
+ scheduler,
476
+ concurrency
477
+ }),
478
+ unsettle: createEnvironmentCommand(runtime, {
479
+ label: "environment-data:commands:thread:unsettle",
480
+ execute: (input) => unsettleThread(input),
481
+ scheduler,
482
+ concurrency
483
+ }),
484
+ snooze: createEnvironmentCommand(runtime, {
485
+ label: "environment-data:commands:thread:snooze",
486
+ execute: (input) => snoozeThread(input),
487
+ scheduler,
488
+ concurrency
489
+ }),
490
+ unsnooze: createEnvironmentCommand(runtime, {
491
+ label: "environment-data:commands:thread:unsnooze",
492
+ execute: (input) => unsnoozeThread(input),
493
+ scheduler,
494
+ concurrency
495
+ }),
496
+ updateMetadata: createEnvironmentCommand(runtime, {
497
+ label: "environment-data:commands:thread:update-metadata",
498
+ execute: (input) => updateThreadMetadata(input),
499
+ scheduler,
500
+ concurrency
501
+ }),
502
+ setRuntimeMode: createEnvironmentCommand(runtime, {
503
+ label: "environment-data:commands:thread:set-runtime-mode",
504
+ execute: (input) => setThreadRuntimeMode(input),
505
+ scheduler,
506
+ concurrency
507
+ }),
508
+ setInteractionMode: createEnvironmentCommand(runtime, {
509
+ label: "environment-data:commands:thread:set-interaction-mode",
510
+ execute: (input) => setThreadInteractionMode(input),
511
+ scheduler,
512
+ concurrency
513
+ }),
514
+ startTurn: createEnvironmentCommand(runtime, {
515
+ label: "environment-data:commands:thread:start-turn",
516
+ execute: (input) => startThreadTurn(input),
517
+ scheduler,
518
+ concurrency
519
+ }),
520
+ interruptTurn: createEnvironmentCommand(runtime, {
521
+ label: "environment-data:commands:thread:interrupt-turn",
522
+ execute: (input) => interruptThreadTurn(input),
523
+ scheduler,
524
+ concurrency
525
+ }),
526
+ respondToApproval: createEnvironmentCommand(runtime, {
527
+ label: "environment-data:commands:thread:respond-to-approval",
528
+ execute: (input) => respondToThreadApproval(input),
529
+ scheduler,
530
+ concurrency
531
+ }),
532
+ respondToUserInput: createEnvironmentCommand(runtime, {
533
+ label: "environment-data:commands:thread:respond-to-user-input",
534
+ execute: (input) => respondToThreadUserInput(input),
535
+ scheduler,
536
+ concurrency
537
+ }),
538
+ revertCheckpoint: createEnvironmentCommand(runtime, {
539
+ label: "environment-data:commands:thread:revert-checkpoint",
540
+ execute: (input) => revertThreadCheckpoint(input),
541
+ scheduler,
542
+ concurrency
543
+ }),
544
+ stopSession: createEnvironmentCommand(runtime, {
545
+ label: "environment-data:commands:thread:stop-session",
546
+ execute: (input) => stopThreadSession(input),
547
+ scheduler,
548
+ concurrency
549
+ })
550
+ };
551
+ }
552
+ //#endregion
553
+ //#region upstream-t3code/packages/client-runtime/src/state/threadDetail.ts
554
+ const EMPTY_MESSAGES = Object.freeze([]);
555
+ const EMPTY_ACTIVITIES = Object.freeze([]);
556
+ const EMPTY_PROPOSED_PLANS = Object.freeze([]);
557
+ const EMPTY_CHECKPOINTS = Object.freeze([]);
558
+ /**
559
+ * Combine detail-only collections with the shell's authoritative thread metadata.
560
+ *
561
+ * Shell and detail subscriptions are intentionally independent. A cached detail can
562
+ * therefore briefly outlive a newer shell snapshot after reconnecting. Workspace
563
+ * consumers must use the shell branch/worktree/project fields so they do not target
564
+ * a stale checkout while retaining messages, activities, plans, and checkpoints
565
+ * from the detail subscription.
566
+ */
567
+ function mergeEnvironmentThread(detail, shell) {
568
+ if (detail === null || shell === null) return detail;
569
+ if (detail.environmentId !== shell.environmentId || detail.id !== shell.id) return detail;
570
+ return {
571
+ ...detail,
572
+ environmentId: shell.environmentId,
573
+ id: shell.id,
574
+ projectId: shell.projectId,
575
+ title: shell.title,
576
+ modelSelection: shell.modelSelection,
577
+ runtimeMode: shell.runtimeMode,
578
+ interactionMode: shell.interactionMode,
579
+ branch: shell.branch,
580
+ worktreePath: shell.worktreePath,
581
+ latestTurn: shell.latestTurn,
582
+ createdAt: shell.createdAt,
583
+ updatedAt: shell.updatedAt,
584
+ archivedAt: shell.archivedAt,
585
+ settledOverride: shell.settledOverride,
586
+ settledAt: shell.settledAt,
587
+ snoozedUntil: shell.snoozedUntil,
588
+ snoozedAt: shell.snoozedAt,
589
+ session: shell.session
590
+ };
591
+ }
592
+ function createEnvironmentThreadDetailAtoms(threadStateAtom) {
593
+ const threadStateValueAtomFamily = family((key) => {
594
+ const ref = parseThreadKey(key);
595
+ return make((get) => getOrElse(value(get(threadStateAtom(ref.environmentId, ref.threadId))), () => EMPTY_ENVIRONMENT_THREAD_STATE)).pipe(setIdleTTL(THREAD_STATE_IDLE_TTL_MS), withLabel(`environment-thread-state-value:${key}`));
596
+ });
597
+ const threadDetailAtomFamily = family((key) => {
598
+ const ref = parseThreadKey(key);
599
+ let previousSource = null;
600
+ let previousValue = null;
601
+ return make((get) => {
602
+ const source = getOrNull(get(threadStateValueAtomFamily(key)).data);
603
+ if (source === previousSource) return previousValue;
604
+ previousSource = source;
605
+ previousValue = source === null ? null : scopeThread(ref.environmentId, source);
606
+ return previousValue;
607
+ }).pipe(setIdleTTL(THREAD_STATE_IDLE_TTL_MS), withLabel(`environment-thread-detail:${key}`));
608
+ });
609
+ const threadStatusAtomFamily = family((key) => make((get) => get(threadStateValueAtomFamily(key)).status).pipe(setIdleTTL(THREAD_STATE_IDLE_TTL_MS), withLabel(`environment-thread-status:${key}`)));
610
+ const threadErrorAtomFamily = family((key) => make((get) => getOrNull(get(threadStateValueAtomFamily(key)).error)).pipe(setIdleTTL(THREAD_STATE_IDLE_TTL_MS), withLabel(`environment-thread-error:${key}`)));
611
+ const threadMessagesAtomFamily = family((key) => make((get) => get(threadDetailAtomFamily(key))?.messages ?? EMPTY_MESSAGES).pipe(setIdleTTL(THREAD_STATE_IDLE_TTL_MS), withLabel(`environment-thread-messages:${key}`)));
612
+ const threadActivitiesAtomFamily = family((key) => make((get) => get(threadDetailAtomFamily(key))?.activities ?? EMPTY_ACTIVITIES).pipe(setIdleTTL(THREAD_STATE_IDLE_TTL_MS), withLabel(`environment-thread-activities:${key}`)));
613
+ const threadProposedPlansAtomFamily = family((key) => make((get) => get(threadDetailAtomFamily(key))?.proposedPlans ?? EMPTY_PROPOSED_PLANS).pipe(setIdleTTL(THREAD_STATE_IDLE_TTL_MS), withLabel(`environment-thread-proposed-plans:${key}`)));
614
+ const threadCheckpointsAtomFamily = family((key) => make((get) => get(threadDetailAtomFamily(key))?.checkpoints ?? EMPTY_CHECKPOINTS).pipe(setIdleTTL(THREAD_STATE_IDLE_TTL_MS), withLabel(`environment-thread-checkpoints:${key}`)));
615
+ const threadSessionAtomFamily = family((key) => make((get) => get(threadDetailAtomFamily(key))?.session ?? null).pipe(setIdleTTL(THREAD_STATE_IDLE_TTL_MS), withLabel(`environment-thread-session:${key}`)));
616
+ const threadLatestTurnAtomFamily = family((key) => make((get) => get(threadDetailAtomFamily(key))?.latestTurn ?? null).pipe(setIdleTTL(THREAD_STATE_IDLE_TTL_MS), withLabel(`environment-thread-latest-turn:${key}`)));
617
+ return {
618
+ stateAtom: (ref) => threadStateValueAtomFamily(threadKey(ref)),
619
+ detailAtom: (ref) => threadDetailAtomFamily(threadKey(ref)),
620
+ statusAtom: (ref) => threadStatusAtomFamily(threadKey(ref)),
621
+ errorAtom: (ref) => threadErrorAtomFamily(threadKey(ref)),
622
+ messagesAtom: (ref) => threadMessagesAtomFamily(threadKey(ref)),
623
+ activitiesAtom: (ref) => threadActivitiesAtomFamily(threadKey(ref)),
624
+ proposedPlansAtom: (ref) => threadProposedPlansAtomFamily(threadKey(ref)),
625
+ checkpointsAtom: (ref) => threadCheckpointsAtomFamily(threadKey(ref)),
626
+ sessionAtom: (ref) => threadSessionAtomFamily(threadKey(ref)),
627
+ latestTurnAtom: (ref) => threadLatestTurnAtomFamily(threadKey(ref))
628
+ };
629
+ }
630
+ //#endregion
631
+ //#region upstream-t3code/packages/client-runtime/src/state/threadShell.ts
632
+ const EMPTY_THREADS = Object.freeze([]);
633
+ const EMPTY_SCOPED_THREAD_REFS = Object.freeze([]);
634
+ const EMPTY_THREAD_INDEX = /* @__PURE__ */ new Map();
635
+ const EMPTY_THREAD_REFS_BY_PROJECT = /* @__PURE__ */ new Map();
636
+ function createEnvironmentThreadShellAtoms(input) {
637
+ const environmentThreadsAtom = family((environmentId) => make((get) => get(input.snapshotAtom(environmentId))?.threads ?? EMPTY_THREADS).pipe(withLabel(`environment-threads:${environmentId}`)));
638
+ const environmentThreadIndexAtom = family((environmentId) => make((get) => {
639
+ const threads = get(environmentThreadsAtom(environmentId));
640
+ if (threads.length === 0) return EMPTY_THREAD_INDEX;
641
+ return new Map(threads.map((thread) => [thread.id, thread]));
642
+ }).pipe(withLabel(`environment-thread-index:${environmentId}`)));
643
+ const environmentThreadRefsAtom = family((environmentId) => {
644
+ let previous = [];
645
+ return make((get) => {
646
+ const next = get(environmentThreadsAtom(environmentId)).map((thread) => ({
647
+ environmentId,
648
+ threadId: thread.id
649
+ }));
650
+ if (threadRefsEqual(previous, next)) return previous;
651
+ previous = next;
652
+ return next;
653
+ }).pipe(withLabel(`environment-thread-refs:${environmentId}`));
654
+ });
655
+ const environmentThreadRefsByProjectAtom = family((environmentId) => {
656
+ let previous = EMPTY_THREAD_REFS_BY_PROJECT;
657
+ return make((get) => {
658
+ const grouped = /* @__PURE__ */ new Map();
659
+ for (const thread of get(environmentThreadsAtom(environmentId))) {
660
+ const refs = grouped.get(thread.projectId);
661
+ const ref = {
662
+ environmentId,
663
+ threadId: thread.id
664
+ };
665
+ if (refs === void 0) grouped.set(thread.projectId, [ref]);
666
+ else refs.push(ref);
667
+ }
668
+ if (grouped.size === 0) {
669
+ previous = EMPTY_THREAD_REFS_BY_PROJECT;
670
+ return previous;
671
+ }
672
+ const next = /* @__PURE__ */ new Map();
673
+ for (const [projectId, refs] of grouped) {
674
+ const previousRefs = previous.get(projectId);
675
+ next.set(projectId, previousRefs !== void 0 && threadRefsEqual(previousRefs, refs) ? previousRefs : refs);
676
+ }
677
+ previous = next;
678
+ return previous;
679
+ }).pipe(withLabel(`environment-thread-refs-by-project:${environmentId}`));
680
+ });
681
+ const threadShellAtomFamily = family((key) => {
682
+ const ref = parseThreadKey(key);
683
+ let previousSource = null;
684
+ let previousValue = null;
685
+ return make((get) => {
686
+ const source = get(environmentThreadIndexAtom(ref.environmentId)).get(ref.threadId) ?? null;
687
+ if (source === previousSource) return previousValue;
688
+ previousSource = source;
689
+ previousValue = source === null ? null : scopeThreadShell(ref.environmentId, source);
690
+ return previousValue;
691
+ }).pipe(withLabel(`environment-thread-shell:${key}`));
692
+ });
693
+ const threadShellsForProjectRefsAtomFamily = family((key) => {
694
+ const projectRefs = parseProjectRefCollectionKey(key);
695
+ let previous = [];
696
+ return make((get) => {
697
+ const next = [];
698
+ const seen = /* @__PURE__ */ new Set();
699
+ for (const projectRef of projectRefs) {
700
+ const refs = get(environmentThreadRefsByProjectAtom(projectRef.environmentId)).get(projectRef.projectId) ?? EMPTY_SCOPED_THREAD_REFS;
701
+ for (const ref of refs) {
702
+ const key = threadKey(ref);
703
+ if (seen.has(key)) continue;
704
+ seen.add(key);
705
+ const thread = get(threadShellAtomFamily(key));
706
+ if (thread !== null) next.push(thread);
707
+ }
708
+ }
709
+ if (arrayElementsEqual(previous, next)) return previous;
710
+ previous = next;
711
+ return previous;
712
+ }).pipe(withLabel(`environment-thread-shells-for-projects:${key}`));
713
+ });
714
+ let previousThreadRefs = [];
715
+ const threadRefsAtom = make((get) => {
716
+ const refs = [];
717
+ for (const environmentId of get(input.catalogValueAtom).entries.keys()) refs.push(...get(environmentThreadRefsAtom(environmentId)));
718
+ if (threadRefsEqual(previousThreadRefs, refs)) return previousThreadRefs;
719
+ previousThreadRefs = refs;
720
+ return refs;
721
+ }).pipe(withLabel("environment-thread-refs"));
722
+ let previousThreadShells = [];
723
+ return {
724
+ environmentThreadsAtom,
725
+ environmentThreadIndexAtom,
726
+ environmentThreadRefsAtom,
727
+ environmentThreadRefsByProjectAtom,
728
+ threadRefsAtom,
729
+ threadShellsAtom: make((get) => {
730
+ const next = get(threadRefsAtom).flatMap((ref) => {
731
+ const thread = get(threadShellAtomFamily(threadKey(ref)));
732
+ return thread === null ? [] : [thread];
733
+ });
734
+ if (arrayElementsEqual(previousThreadShells, next)) return previousThreadShells;
735
+ previousThreadShells = next;
736
+ return previousThreadShells;
737
+ }).pipe(withLabel("environment-thread-shell-list")),
738
+ threadShellsForProjectRefsAtom: (refs) => threadShellsForProjectRefsAtomFamily(projectRefCollectionKey(refs)),
739
+ threadShellAtom: (ref) => threadShellAtomFamily(threadKey(ref))
740
+ };
741
+ }
742
+ //#endregion
743
+ //#region upstream-t3code/packages/client-runtime/src/state/threads.ts
744
+ function statusWithoutLiveData(data) {
745
+ return isSome(data) ? "cached" : "empty";
746
+ }
747
+ function formatThreadError(cause) {
748
+ const error = squash(cause);
749
+ return error instanceof Error && error.message.trim().length > 0 ? error.message : "Could not synchronize the thread.";
750
+ }
751
+ function shouldPersistThread(thread) {
752
+ const status = thread.session?.status;
753
+ return status !== "starting" && status !== "running";
754
+ }
755
+ const makeEnvironmentThreadState = fn("EnvironmentThreadState.make")(function* (threadId) {
756
+ const supervisor = yield* EnvironmentSupervisor;
757
+ const cache = yield* EnvironmentCacheStore;
758
+ const snapshotLoader = yield* ThreadSnapshotLoader;
759
+ const wakeups = yield* serviceOption(ConnectionWakeups);
760
+ const environmentId = supervisor.target.environmentId;
761
+ const cached = yield* cache.loadThread(environmentId, threadId).pipe(catch_((error) => logWarning("Could not load cached thread.").pipe(annotateLogs({
762
+ environmentId,
763
+ threadId,
764
+ error: error.message
765
+ }), as(none()))));
766
+ const cachedThread = map$2(cached, (snapshot) => snapshot.thread);
767
+ const state = yield* make$1({
768
+ data: cachedThread,
769
+ status: statusWithoutLiveData(cachedThread),
770
+ error: none()
771
+ });
772
+ const lastSequence = yield* make$1(match(cached, {
773
+ onNone: () => 0,
774
+ onSome: (snapshot) => snapshot.snapshotSequence
775
+ }));
776
+ const awaitingCompletion = yield* make$2(false);
777
+ const persistence = yield* sliding(1);
778
+ const persist = fn("EnvironmentThreadState.persist")(function* (snapshot) {
779
+ yield* cache.saveThread(environmentId, snapshot).pipe(catch_((error) => logWarning("Could not persist the thread cache.").pipe(annotateLogs({
780
+ environmentId,
781
+ threadId,
782
+ error: error.message
783
+ }))));
784
+ });
785
+ yield* fromQueue(persistence).pipe(debounce("500 millis"), runForEach(persist), forkScoped);
786
+ const setSynchronizing = update(state, (current) => current.status === "deleted" ? current : {
787
+ ...current,
788
+ status: "synchronizing",
789
+ error: none()
790
+ });
791
+ const setReady = update(state, (current) => current.status === "live" || current.status === "deleted" ? current : {
792
+ ...current,
793
+ status: "synchronizing",
794
+ error: none()
795
+ });
796
+ const setDisconnected = gen(function* () {
797
+ yield* set(awaitingCompletion, false);
798
+ yield* update(state, (current) => ({
799
+ ...current,
800
+ status: current.status === "deleted" ? current.status : statusWithoutLiveData(current.data)
801
+ }));
802
+ });
803
+ const setStreamError = (cause) => set(awaitingCompletion, false).pipe(andThen(update(state, (current) => ({
804
+ ...current,
805
+ status: current.status === "deleted" ? current.status : statusWithoutLiveData(current.data),
806
+ error: some(formatThreadError(cause))
807
+ }))));
808
+ const setThread = fn("EnvironmentThreadState.setThread")(function* (thread) {
809
+ const waiting = yield* get(awaitingCompletion);
810
+ yield* set$1(state, {
811
+ data: some(thread),
812
+ status: waiting ? "synchronizing" : "live",
813
+ error: none()
814
+ });
815
+ if (shouldPersistThread(thread)) {
816
+ const snapshotSequence = yield* get$1(lastSequence);
817
+ yield* offer(persistence, {
818
+ snapshotSequence,
819
+ thread
820
+ });
821
+ }
822
+ });
823
+ const setDeleted = fn("EnvironmentThreadState.setDeleted")(function* () {
824
+ yield* set(awaitingCompletion, false);
825
+ yield* set$1(state, {
826
+ data: none(),
827
+ status: "deleted",
828
+ error: none()
829
+ });
830
+ yield* cache.removeThread(environmentId, threadId).pipe(catch_((error) => logWarning("Could not remove the cached thread.").pipe(annotateLogs({
831
+ environmentId,
832
+ threadId,
833
+ error: error.message
834
+ }))));
835
+ });
836
+ const applyItem = fn("EnvironmentThreadState.applyItem")(function* (item) {
837
+ if (item.kind === "synchronized") {
838
+ yield* set(awaitingCompletion, false);
839
+ yield* update(state, (current) => isSome(current.data) && current.status !== "deleted" ? {
840
+ ...current,
841
+ status: "live",
842
+ error: none()
843
+ } : current);
844
+ return;
845
+ }
846
+ if (item.kind === "snapshot") {
847
+ yield* set$1(lastSequence, item.snapshot.snapshotSequence);
848
+ yield* setThread(item.snapshot.thread);
849
+ return;
850
+ }
851
+ const sequence = yield* get$1(lastSequence);
852
+ if (item.event.sequence <= sequence) return;
853
+ yield* set$1(lastSequence, item.event.sequence);
854
+ const current = yield* get$1(state);
855
+ if (isNone(current.data)) {
856
+ if (item.event.type === "thread.deleted") yield* setDeleted();
857
+ return;
858
+ }
859
+ const result = applyThreadDetailEvent(current.data.value, item.event);
860
+ if (result.kind === "updated") yield* setThread(result.thread);
861
+ else if (result.kind === "deleted") yield* setDeleted();
862
+ });
863
+ yield* changes(supervisor.state).pipe(runForEach((connectionState) => {
864
+ switch (connectionProjectionPhase(connectionState)) {
865
+ case "synchronizing": return setSynchronizing;
866
+ case "disconnected": return setDisconnected;
867
+ case "ready": return setReady;
868
+ }
869
+ }), forkScoped);
870
+ const foregroundResubscriptions = match(wakeups, {
871
+ onNone: () => never,
872
+ onSome: (service) => service.changes.pipe(filter$1((reason) => reason === "application-active"))
873
+ });
874
+ yield* setSynchronizing;
875
+ yield* forkScoped(subscribeDynamic(ORCHESTRATION_WS_METHODS.subscribeThread, fn("EnvironmentThreadState.makeSubscribeInput")(function* (session) {
876
+ const supportsCompletionMarker = yield* session.initialConfig.pipe(map((config) => config.threadResumeCompletionMarker === true), orElseSucceed(() => false));
877
+ yield* set(awaitingCompletion, supportsCompletionMarker);
878
+ yield* setSynchronizing;
879
+ let current = yield* get$1(state);
880
+ if (isNone(current.data) && current.status !== "deleted") {
881
+ const prepared = yield* get$1(supervisor.prepared).pipe(flatMap(match({
882
+ onSome: succeed,
883
+ onNone: () => changes(supervisor.prepared).pipe(filter$1(isSome), map$3((value) => value.value), runHead, map(getOrThrow))
884
+ })));
885
+ const httpSnapshot = yield* snapshotLoader.load(prepared, threadId);
886
+ if (isSome(httpSnapshot)) {
887
+ yield* applyItem({
888
+ kind: "snapshot",
889
+ snapshot: httpSnapshot.value
890
+ });
891
+ current = yield* get$1(state);
892
+ }
893
+ }
894
+ const sequence = yield* get$1(lastSequence);
895
+ const canResume = isSome(current.data);
896
+ if (!supportsCompletionMarker && canResume) yield* update(state, (value) => ({
897
+ ...value,
898
+ status: value.status === "deleted" ? value.status : "live",
899
+ error: none()
900
+ }));
901
+ return {
902
+ threadId,
903
+ ...canResume ? { afterSequence: sequence } : {},
904
+ ...supportsCompletionMarker ? { requestCompletionMarker: true } : {}
905
+ };
906
+ }), {
907
+ onExpectedFailure: setStreamError,
908
+ retryExpectedFailureAfter: "250 millis",
909
+ resubscribe: foregroundResubscriptions
910
+ }).pipe(runForEach(applyItem)));
911
+ yield* addFinalizer(() => all([get$1(state), get$1(lastSequence)]).pipe(flatMap(([current, snapshotSequence]) => match(current.data, {
912
+ onNone: () => void_,
913
+ onSome: (thread) => shouldPersistThread(thread) ? persist({
914
+ snapshotSequence,
915
+ thread
916
+ }) : void_
917
+ }))));
918
+ return state;
919
+ });
920
+ function threadStateChanges(environmentId, threadId) {
921
+ return followStreamInEnvironment(environmentId, unwrap(makeEnvironmentThreadState(threadId).pipe(map(changes))));
922
+ }
923
+ function createEnvironmentThreadStateAtoms(runtime) {
924
+ const family$1 = family((key) => {
925
+ const { environmentId, threadId } = parseThreadKey(key);
926
+ return runtime.atom(threadStateChanges(environmentId, threadId), { initialValue: EMPTY_ENVIRONMENT_THREAD_STATE }).pipe(setIdleTTL(THREAD_STATE_IDLE_TTL_MS), withLabel(`environment-thread-state:${key}`));
927
+ });
928
+ return { stateAtom: (environmentId, threadId) => family$1(threadKey({
929
+ environmentId,
930
+ threadId
931
+ })) };
932
+ }
933
+ //#endregion
934
+ export { EMPTY_ENVIRONMENT_THREAD_STATE, ThreadSnapshotLoader, applyThreadDetailEvent, createArchivedThreadSnapshotsAtomFamily, createEnvironmentThreadDetailAtoms, createEnvironmentThreadShellAtoms, createEnvironmentThreadStateAtoms, createThreadEnvironmentAtoms, fetchEnvironmentThreadSnapshot, makeArchivedThreadsEnvironmentKey, makeEnvironmentThreadState, mergeEnvironmentThread, parseArchivedThreadsEnvironmentKey, threadSnapshotLoaderLayer, threadStateChanges };