@threadbase-sh/streamer 1.63.0 → 1.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (300) hide show
  1. package/dist/agent/agent-client.d.ts +14 -0
  2. package/dist/agent/agent-client.d.ts.map +1 -0
  3. package/dist/agent/agent-config.d.ts +24 -0
  4. package/dist/agent/agent-config.d.ts.map +1 -0
  5. package/dist/agent/conversation-writer.d.ts +13 -0
  6. package/dist/agent/conversation-writer.d.ts.map +1 -0
  7. package/dist/agent/dedupe.d.ts +6 -0
  8. package/dist/agent/dedupe.d.ts.map +1 -0
  9. package/dist/agent/errors.d.ts +23 -0
  10. package/dist/agent/errors.d.ts.map +1 -0
  11. package/dist/agent/handle-send-agent-input.d.ts +21 -0
  12. package/dist/agent/handle-send-agent-input.d.ts.map +1 -0
  13. package/dist/agent/handle-start-agent-session.d.ts +21 -0
  14. package/dist/agent/handle-start-agent-session.d.ts.map +1 -0
  15. package/dist/agent/history-mapper.d.ts +4 -0
  16. package/dist/agent/history-mapper.d.ts.map +1 -0
  17. package/dist/agent/payload-guard.d.ts +29 -0
  18. package/dist/agent/payload-guard.d.ts.map +1 -0
  19. package/dist/api/app.d.ts +28 -0
  20. package/dist/api/app.d.ts.map +1 -0
  21. package/dist/api/handlers/conversations.handlers.d.ts +69 -0
  22. package/dist/api/handlers/conversations.handlers.d.ts.map +1 -0
  23. package/dist/api/handlers/http-helpers.d.ts +50 -0
  24. package/dist/api/handlers/http-helpers.d.ts.map +1 -0
  25. package/dist/api/handlers/sessions.handlers.d.ts +236 -0
  26. package/dist/api/handlers/sessions.handlers.d.ts.map +1 -0
  27. package/dist/api/middleware/auth.middleware.d.ts +5 -0
  28. package/dist/api/middleware/auth.middleware.d.ts.map +1 -0
  29. package/dist/api/middleware/cors.middleware.d.ts +5 -0
  30. package/dist/api/middleware/cors.middleware.d.ts.map +1 -0
  31. package/dist/api/middleware/error.middleware.d.ts +4 -0
  32. package/dist/api/middleware/error.middleware.d.ts.map +1 -0
  33. package/dist/api/routes/backup.routes.d.ts +5 -0
  34. package/dist/api/routes/backup.routes.d.ts.map +1 -0
  35. package/dist/api/routes/browse.routes.d.ts +5 -0
  36. package/dist/api/routes/browse.routes.d.ts.map +1 -0
  37. package/dist/api/routes/cacheAlert.routes.d.ts +5 -0
  38. package/dist/api/routes/cacheAlert.routes.d.ts.map +1 -0
  39. package/dist/api/routes/config.routes.d.ts +5 -0
  40. package/dist/api/routes/config.routes.d.ts.map +1 -0
  41. package/dist/api/routes/conversations.routes.d.ts +5 -0
  42. package/dist/api/routes/conversations.routes.d.ts.map +1 -0
  43. package/dist/api/routes/devices.routes.d.ts +17 -0
  44. package/dist/api/routes/devices.routes.d.ts.map +1 -0
  45. package/dist/api/routes/diagnostics.routes.d.ts +5 -0
  46. package/dist/api/routes/diagnostics.routes.d.ts.map +1 -0
  47. package/dist/api/routes/health.routes.d.ts +5 -0
  48. package/dist/api/routes/health.routes.d.ts.map +1 -0
  49. package/dist/api/routes/logs.routes.d.ts +3 -0
  50. package/dist/api/routes/logs.routes.d.ts.map +1 -0
  51. package/dist/api/routes/misc.routes.d.ts +77 -0
  52. package/dist/api/routes/misc.routes.d.ts.map +1 -0
  53. package/dist/api/routes/pair.routes.d.ts +5 -0
  54. package/dist/api/routes/pair.routes.d.ts.map +1 -0
  55. package/dist/api/routes/progress.routes.d.ts +39 -0
  56. package/dist/api/routes/progress.routes.d.ts.map +1 -0
  57. package/dist/api/routes/projects.routes.d.ts +5 -0
  58. package/dist/api/routes/projects.routes.d.ts.map +1 -0
  59. package/dist/api/routes/providers.routes.d.ts +19 -0
  60. package/dist/api/routes/providers.routes.d.ts.map +1 -0
  61. package/dist/api/routes/scanner.routes.d.ts +5 -0
  62. package/dist/api/routes/scanner.routes.d.ts.map +1 -0
  63. package/dist/api/routes/sessions.routes.d.ts +6 -0
  64. package/dist/api/routes/sessions.routes.d.ts.map +1 -0
  65. package/dist/api/routes/ws.routes.d.ts +7 -0
  66. package/dist/api/routes/ws.routes.d.ts.map +1 -0
  67. package/dist/api/types/api-deps.d.ts +114 -0
  68. package/dist/api/types/api-deps.d.ts.map +1 -0
  69. package/dist/auth.d.ts +81 -0
  70. package/dist/auth.d.ts.map +1 -0
  71. package/dist/browse.d.ts +17 -0
  72. package/dist/browse.d.ts.map +1 -0
  73. package/dist/claude-flags.d.ts +76 -0
  74. package/dist/claude-flags.d.ts.map +1 -0
  75. package/dist/cli.cjs +121 -7
  76. package/dist/cli.cjs.map +1 -1
  77. package/dist/codex-pty-runner.d.ts +90 -0
  78. package/dist/codex-pty-runner.d.ts.map +1 -0
  79. package/dist/config/update-config.d.ts +13 -0
  80. package/dist/config/update-config.d.ts.map +1 -0
  81. package/dist/conversation-cache.d.ts +336 -0
  82. package/dist/conversation-cache.d.ts.map +1 -0
  83. package/dist/db/config.d.ts +11 -0
  84. package/dist/db/config.d.ts.map +1 -0
  85. package/dist/db/index.d.ts +5 -0
  86. package/dist/db/index.d.ts.map +1 -0
  87. package/dist/db/migrations.d.ts +3 -0
  88. package/dist/db/migrations.d.ts.map +1 -0
  89. package/dist/db/pool.d.ts +5 -0
  90. package/dist/db/pool.d.ts.map +1 -0
  91. package/dist/db/query-timing.d.ts +52 -0
  92. package/dist/db/query-timing.d.ts.map +1 -0
  93. package/dist/db/repositories/cacheMetadata.repository.d.ts +12 -0
  94. package/dist/db/repositories/cacheMetadata.repository.d.ts.map +1 -0
  95. package/dist/db/repositories/conversations.repository.d.ts +27 -0
  96. package/dist/db/repositories/conversations.repository.d.ts.map +1 -0
  97. package/dist/db/repositories/devices.repository.d.ts +137 -0
  98. package/dist/db/repositories/devices.repository.d.ts.map +1 -0
  99. package/dist/db/repositories/managed-sessions.repository.d.ts +127 -0
  100. package/dist/db/repositories/managed-sessions.repository.d.ts.map +1 -0
  101. package/dist/db/repositories/projects.repository.d.ts +28 -0
  102. package/dist/db/repositories/projects.repository.d.ts.map +1 -0
  103. package/dist/db/repositories/push.repository.d.ts +186 -0
  104. package/dist/db/repositories/push.repository.d.ts.map +1 -0
  105. package/dist/db/repositories/sessions.repository.d.ts +16 -0
  106. package/dist/db/repositories/sessions.repository.d.ts.map +1 -0
  107. package/dist/db/runtime-store.d.ts +80 -0
  108. package/dist/db/runtime-store.d.ts.map +1 -0
  109. package/dist/db/sqlite-migrate.d.ts +13 -0
  110. package/dist/db/sqlite-migrate.d.ts.map +1 -0
  111. package/dist/db/upload-records.d.ts +11 -0
  112. package/dist/db/upload-records.d.ts.map +1 -0
  113. package/dist/e2ee/noise.d.ts +261 -0
  114. package/dist/e2ee/noise.d.ts.map +1 -0
  115. package/dist/e2ee/pair-payload.d.ts +60 -0
  116. package/dist/e2ee/pair-payload.d.ts.map +1 -0
  117. package/dist/e2ee/pair-request.d.ts +24 -0
  118. package/dist/e2ee/pair-request.d.ts.map +1 -0
  119. package/dist/external-tails.d.ts +91 -0
  120. package/dist/external-tails.d.ts.map +1 -0
  121. package/dist/feature-flags.d.ts +212 -0
  122. package/dist/feature-flags.d.ts.map +1 -0
  123. package/dist/handlers/handleListProjects.d.ts +3 -0
  124. package/dist/handlers/handleListProjects.d.ts.map +1 -0
  125. package/dist/index.cjs +101 -2
  126. package/dist/index.cjs.map +1 -1
  127. package/dist/index.d.ts +18 -2571
  128. package/dist/index.d.ts.map +1 -0
  129. package/dist/index.js +101 -2
  130. package/dist/index.js.map +1 -1
  131. package/dist/lifecycle/constants.d.ts +21 -0
  132. package/dist/lifecycle/constants.d.ts.map +1 -0
  133. package/dist/lifecycle/process-liveness.d.ts +7 -0
  134. package/dist/lifecycle/process-liveness.d.ts.map +1 -0
  135. package/dist/live-session-manager.d.ts +59 -0
  136. package/dist/live-session-manager.d.ts.map +1 -0
  137. package/dist/logger.d.ts +14 -0
  138. package/dist/logger.d.ts.map +1 -0
  139. package/dist/pair-store.d.ts +60 -0
  140. package/dist/pair-store.d.ts.map +1 -0
  141. package/dist/platform.d.ts +25 -0
  142. package/dist/platform.d.ts.map +1 -0
  143. package/dist/process-discovery.d.ts +35 -0
  144. package/dist/process-discovery.d.ts.map +1 -0
  145. package/dist/providers.d.ts +7 -0
  146. package/dist/providers.d.ts.map +1 -0
  147. package/dist/pty-host/protocol.d.ts +270 -0
  148. package/dist/pty-host/protocol.d.ts.map +1 -0
  149. package/dist/pty-host/remote-session-runner.d.ts +133 -0
  150. package/dist/pty-host/remote-session-runner.d.ts.map +1 -0
  151. package/dist/pty-host/socket.d.ts +54 -0
  152. package/dist/pty-host/socket.d.ts.map +1 -0
  153. package/dist/pty-host/spawn-host.d.ts +30 -0
  154. package/dist/pty-host/spawn-host.d.ts.map +1 -0
  155. package/dist/pty-manager.d.ts +65 -0
  156. package/dist/pty-manager.d.ts.map +1 -0
  157. package/dist/pty-shared.d.ts +27 -0
  158. package/dist/pty-shared.d.ts.map +1 -0
  159. package/dist/scanner-manager.d.ts +126 -0
  160. package/dist/scanner-manager.d.ts.map +1 -0
  161. package/dist/schemas/cacheAlert.schema.d.ts +14 -0
  162. package/dist/schemas/cacheAlert.schema.d.ts.map +1 -0
  163. package/dist/schemas/claudeFlags.schema.d.ts +7 -0
  164. package/dist/schemas/claudeFlags.schema.d.ts.map +1 -0
  165. package/dist/schemas/project.schema.d.ts +18 -0
  166. package/dist/schemas/project.schema.d.ts.map +1 -0
  167. package/dist/schemas/updateConfig.schema.d.ts +19 -0
  168. package/dist/schemas/updateConfig.schema.d.ts.map +1 -0
  169. package/dist/seal.d.ts +14 -0
  170. package/dist/seal.d.ts.map +1 -0
  171. package/dist/server-identity.d.ts +43 -0
  172. package/dist/server-identity.d.ts.map +1 -0
  173. package/dist/server-wiring.d.ts +189 -0
  174. package/dist/server-wiring.d.ts.map +1 -0
  175. package/dist/server.d.ts +404 -0
  176. package/dist/server.d.ts.map +1 -0
  177. package/dist/services/backup/backup.d.ts +103 -0
  178. package/dist/services/backup/backup.d.ts.map +1 -0
  179. package/dist/services/cache/cacheMetadata.d.ts +8 -0
  180. package/dist/services/cache/cacheMetadata.d.ts.map +1 -0
  181. package/dist/services/cache-integrity/alertStore.d.ts +24 -0
  182. package/dist/services/cache-integrity/alertStore.d.ts.map +1 -0
  183. package/dist/services/cache-integrity/backup.d.ts +8 -0
  184. package/dist/services/cache-integrity/backup.d.ts.map +1 -0
  185. package/dist/services/cache-integrity/cacheIntegrityMonitor.d.ts +71 -0
  186. package/dist/services/cache-integrity/cacheIntegrityMonitor.d.ts.map +1 -0
  187. package/dist/services/conversations/conversationWatcher.d.ts +99 -0
  188. package/dist/services/conversations/conversationWatcher.d.ts.map +1 -0
  189. package/dist/services/conversations/findSearchTarget.d.ts +30 -0
  190. package/dist/services/conversations/findSearchTarget.d.ts.map +1 -0
  191. package/dist/services/conversations/isAgentConversation.d.ts +8 -0
  192. package/dist/services/conversations/isAgentConversation.d.ts.map +1 -0
  193. package/dist/services/conversations/pruneAgentConversations.d.ts +8 -0
  194. package/dist/services/conversations/pruneAgentConversations.d.ts.map +1 -0
  195. package/dist/services/conversations/refreshConversationCache.d.ts +27 -0
  196. package/dist/services/conversations/refreshConversationCache.d.ts.map +1 -0
  197. package/dist/services/conversations/shouldRefreshProjectsFromHdd.d.ts +33 -0
  198. package/dist/services/conversations/shouldRefreshProjectsFromHdd.d.ts.map +1 -0
  199. package/dist/services/diagnostics/diagnostics.d.ts +66 -0
  200. package/dist/services/diagnostics/diagnostics.d.ts.map +1 -0
  201. package/dist/services/projectChats/deriveProjectChatTitle.d.ts +15 -0
  202. package/dist/services/projectChats/deriveProjectChatTitle.d.ts.map +1 -0
  203. package/dist/services/projects/ensureProjectsForConversations.d.ts +15 -0
  204. package/dist/services/projects/ensureProjectsForConversations.d.ts.map +1 -0
  205. package/dist/services/providers/capabilities.d.ts +105 -0
  206. package/dist/services/providers/capabilities.d.ts.map +1 -0
  207. package/dist/services/providers/providerHealth.d.ts +72 -0
  208. package/dist/services/providers/providerHealth.d.ts.map +1 -0
  209. package/dist/services/push/apnsClient.d.ts +105 -0
  210. package/dist/services/push/apnsClient.d.ts.map +1 -0
  211. package/dist/services/push/expoPushSender.d.ts +37 -0
  212. package/dist/services/push/expoPushSender.d.ts.map +1 -0
  213. package/dist/services/push/liveActivityContentState.d.ts +60 -0
  214. package/dist/services/push/liveActivityContentState.d.ts.map +1 -0
  215. package/dist/services/push/liveActivityNotifier.d.ts +49 -0
  216. package/dist/services/push/liveActivityNotifier.d.ts.map +1 -0
  217. package/dist/services/push/liveActivityRenewal.d.ts +63 -0
  218. package/dist/services/push/liveActivityRenewal.d.ts.map +1 -0
  219. package/dist/services/push/liveActivitySender.d.ts +88 -0
  220. package/dist/services/push/liveActivitySender.d.ts.map +1 -0
  221. package/dist/services/push/waitingInputNotifier.d.ts +41 -0
  222. package/dist/services/push/waitingInputNotifier.d.ts.map +1 -0
  223. package/dist/services/questions/answersToKeystrokes.d.ts +8 -0
  224. package/dist/services/questions/answersToKeystrokes.d.ts.map +1 -0
  225. package/dist/services/questions/codexGateAnswers.d.ts +14 -0
  226. package/dist/services/questions/codexGateAnswers.d.ts.map +1 -0
  227. package/dist/services/questions/codexScreen.d.ts +74 -0
  228. package/dist/services/questions/codexScreen.d.ts.map +1 -0
  229. package/dist/services/questions/detectAskUserQuestion.d.ts +6 -0
  230. package/dist/services/questions/detectAskUserQuestion.d.ts.map +1 -0
  231. package/dist/services/questions/detectPermissionGate.d.ts +62 -0
  232. package/dist/services/questions/detectPermissionGate.d.ts.map +1 -0
  233. package/dist/services/questions/detectQuestionFromScreen.d.ts +30 -0
  234. package/dist/services/questions/detectQuestionFromScreen.d.ts.map +1 -0
  235. package/dist/services/questions/detectShellPrompt.d.ts +18 -0
  236. package/dist/services/questions/detectShellPrompt.d.ts.map +1 -0
  237. package/dist/services/questions/parseAgentPhase.d.ts +12 -0
  238. package/dist/services/questions/parseAgentPhase.d.ts.map +1 -0
  239. package/dist/services/questions/parseStatusLine.d.ts +19 -0
  240. package/dist/services/questions/parseStatusLine.d.ts.map +1 -0
  241. package/dist/services/questions/questionBroadcast.d.ts +18 -0
  242. package/dist/services/questions/questionBroadcast.d.ts.map +1 -0
  243. package/dist/services/questions/resolveAnswer.d.ts +16 -0
  244. package/dist/services/questions/resolveAnswer.d.ts.map +1 -0
  245. package/dist/services/search/searchQuery.d.ts +78 -0
  246. package/dist/services/search/searchQuery.d.ts.map +1 -0
  247. package/dist/services/security/capabilities.d.ts +50 -0
  248. package/dist/services/security/capabilities.d.ts.map +1 -0
  249. package/dist/services/sessions/autoResumeOnBoot.d.ts +28 -0
  250. package/dist/services/sessions/autoResumeOnBoot.d.ts.map +1 -0
  251. package/dist/services/sessions/codexRolloutOwner.d.ts +55 -0
  252. package/dist/services/sessions/codexRolloutOwner.d.ts.map +1 -0
  253. package/dist/services/sessions/conversationBusy.d.ts +32 -0
  254. package/dist/services/sessions/conversationBusy.d.ts.map +1 -0
  255. package/dist/services/sessions/idempotency.d.ts +67 -0
  256. package/dist/services/sessions/idempotency.d.ts.map +1 -0
  257. package/dist/services/sessions/reconcileSessions.d.ts +63 -0
  258. package/dist/services/sessions/reconcileSessions.d.ts.map +1 -0
  259. package/dist/services/sessions/rehydrateSessions.d.ts +68 -0
  260. package/dist/services/sessions/rehydrateSessions.d.ts.map +1 -0
  261. package/dist/services/sessions/resumeIdentity.d.ts +16 -0
  262. package/dist/services/sessions/resumeIdentity.d.ts.map +1 -0
  263. package/dist/session-registry-boot.d.ts +142 -0
  264. package/dist/session-registry-boot.d.ts.map +1 -0
  265. package/dist/session-store.d.ts +32 -0
  266. package/dist/session-store.d.ts.map +1 -0
  267. package/dist/session-watchers.d.ts +60 -0
  268. package/dist/session-watchers.d.ts.map +1 -0
  269. package/dist/types.d.ts +616 -0
  270. package/dist/types.d.ts.map +1 -0
  271. package/dist/uploads.d.ts +16 -0
  272. package/dist/uploads.d.ts.map +1 -0
  273. package/dist/utils/bootToken.d.ts +3 -0
  274. package/dist/utils/bootToken.d.ts.map +1 -0
  275. package/dist/utils/canonicalizeFilePath.d.ts +75 -0
  276. package/dist/utils/canonicalizeFilePath.d.ts.map +1 -0
  277. package/dist/utils/canonicalizeProjectPath.d.ts +13 -0
  278. package/dist/utils/canonicalizeProjectPath.d.ts.map +1 -0
  279. package/dist/utils/codexConversationLine.d.ts +38 -0
  280. package/dist/utils/codexConversationLine.d.ts.map +1 -0
  281. package/dist/utils/conversationEtag.d.ts +19 -0
  282. package/dist/utils/conversationEtag.d.ts.map +1 -0
  283. package/dist/utils/dates.d.ts +12 -0
  284. package/dist/utils/dates.d.ts.map +1 -0
  285. package/dist/utils/debounce.d.ts +15 -0
  286. package/dist/utils/debounce.d.ts.map +1 -0
  287. package/dist/utils/deriveSessionName.d.ts +10 -0
  288. package/dist/utils/deriveSessionName.d.ts.map +1 -0
  289. package/dist/utils/fileIdentity.d.ts +36 -0
  290. package/dist/utils/fileIdentity.d.ts.map +1 -0
  291. package/dist/utils/isScannedSnapshotStale.d.ts +16 -0
  292. package/dist/utils/isScannedSnapshotStale.d.ts.map +1 -0
  293. package/dist/utils/scanProgressThrottle.d.ts +12 -0
  294. package/dist/utils/scanProgressThrottle.d.ts.map +1 -0
  295. package/dist/version.d.ts +3 -0
  296. package/dist/version.d.ts.map +1 -0
  297. package/dist/ws-hub.d.ts +15 -0
  298. package/dist/ws-hub.d.ts.map +1 -0
  299. package/package.json +3 -4
  300. package/dist/index.d.cts +0 -2571
@@ -0,0 +1,133 @@
1
+ import type { ManagedSession, PTYManagerOptions, SessionRunner, StartFreshSessionOptions, StartSessionOptions, UserMessage } from "../types";
2
+ import { type HostHeartbeatState, type HostTransport } from "./protocol";
3
+ export declare class PtyHostProtocolMismatchError extends Error {
4
+ readonly hostVersion: number;
5
+ readonly streamerVersion: number;
6
+ constructor(hostVersion: number, streamerVersion: number);
7
+ }
8
+ export declare const HOST_HEARTBEAT_INTERVAL_MS = 10000;
9
+ export declare const HOST_HEARTBEAT_REQUEST_TIMEOUT_MS = 5000;
10
+ export declare const HOST_SHUTDOWN_REQUEST_TIMEOUT_MS = 1000;
11
+ /**
12
+ * `SessionRunner` backed by an out-of-process pty-host (plan Phase 6a).
13
+ *
14
+ * `LiveSessionManager` selects this runner at boot when the `ptyHost` feature
15
+ * flag is enabled; the default-off path keeps the in-process runners.
16
+ *
17
+ * **The mirror is the whole design problem.** `SessionRunner` is mostly
18
+ * synchronous — `hasSession`, `getPid`, `listSessions`, `getOutput` and
19
+ * `sendInput` all return values, not promises — and they are called from
20
+ * request handlers that cannot await a socket round-trip. So the runner keeps a
21
+ * local copy of session state, seeded by `status` on connect and kept current
22
+ * by pushed events. Reads answer from the mirror; only mutations and the two
23
+ * genuinely async methods cross the wire.
24
+ *
25
+ * The consequence worth stating: a mirror can be stale, and the honest failure
26
+ * for a stale mirror is the same one an in-process runner gives for an unknown
27
+ * session — throw. It must never invent a session, and it must never answer
28
+ * "no such session" for one the host is holding, which is why `status` is
29
+ * awaited before the runner is handed out (see `connect`).
30
+ */
31
+ export declare class RemoteSessionRunner implements SessionRunner {
32
+ private transport;
33
+ private options;
34
+ private decoder;
35
+ private nextRequestId;
36
+ private pending;
37
+ /** The mirror. Rebuilt wholesale by `status`, patched by events. */
38
+ private sessions;
39
+ /** Ring buffers, fed by `output` events so `getOutput` stays synchronous. */
40
+ private output;
41
+ private inputHistory;
42
+ /** Fixed for a session's lifetime, so only spawn and status carry it. */
43
+ private pids;
44
+ private closed;
45
+ private heartbeatTimer;
46
+ private heartbeatInFlight;
47
+ /**
48
+ * The only supported way to build one: a runner whose mirror has not been
49
+ * seeded yet would answer `hasSession` with a confident, wrong `false` for
50
+ * every session the host is holding — which reads as "the agent is gone" and
51
+ * routes the user to start a new one.
52
+ */
53
+ static connect(transport: HostTransport, options?: PTYManagerOptions): Promise<RemoteSessionRunner>;
54
+ private constructor();
55
+ private handleLine;
56
+ /**
57
+ * Fail every in-flight request when the socket drops.
58
+ *
59
+ * Without this each one stays pending forever and the caller — a session
60
+ * start, an input write — hangs rather than erroring. PR 9 adds reconnection;
61
+ * until then a dropped host is a hard failure that says so.
62
+ */
63
+ private handleClose;
64
+ private request;
65
+ /**
66
+ * Fire-and-forget for the synchronous parts of `SessionRunner`.
67
+ *
68
+ * `sendKeys`, `cancel`, `killPid` and `putOnHold` all return void, so there is
69
+ * no channel to report a failure through even if we waited for one. The
70
+ * response is still consumed — an unhandled rejection would take the process
71
+ * down over a keystroke that failed to land.
72
+ */
73
+ private fireAndForget;
74
+ private readStatus;
75
+ private refreshMirror;
76
+ heartbeat(state: HostHeartbeatState, timeoutMs?: number): Promise<void>;
77
+ startHeartbeat(getState: () => HostHeartbeatState, intervalMs?: number): void;
78
+ private stopHeartbeat;
79
+ private handleEvent;
80
+ start(sessionId: string, options: StartSessionOptions): Promise<ManagedSession>;
81
+ startFresh(options: StartFreshSessionOptions): Promise<ManagedSession>;
82
+ /**
83
+ * Take a spawn answer into the mirror.
84
+ *
85
+ * The pid lands here and nowhere else in the live path: `recordSessionSpawn`
86
+ * reads it immediately after start to write the durable registry row, and a
87
+ * null there costs the next boot its ability to probe whether the agent
88
+ * outlived us.
89
+ */
90
+ private adopt;
91
+ /**
92
+ * Returns the mirror's promptCount, optimistically incremented.
93
+ *
94
+ * The interface is synchronous, so there is no way to return the host's
95
+ * authoritative count. The increment matches what an in-process runner does
96
+ * for the same call, and the next `status-change` event overwrites it — so a
97
+ * mirror that guessed wrong is corrected within one round trip rather than
98
+ * drifting.
99
+ */
100
+ sendInput(sessionId: string, input: string): number;
101
+ sendKeys(sessionId: string, keys: string): void;
102
+ cancel(sessionId: string): void;
103
+ killPid(pid: number): void;
104
+ putOnHold(sessionId: string): void;
105
+ getOutput(sessionId: string): string;
106
+ getOutputLines(sessionId: string, maxLines: number): Promise<string[]>;
107
+ /**
108
+ * Synchronous, so it answers from the mirror rather than the host.
109
+ *
110
+ * Seeded lazily: `user-message` events append as they arrive, and a session
111
+ * this streamer did not start has none until `hydrateInputHistory` fetches
112
+ * them. Empty is the same answer an in-process runner gives for an unknown
113
+ * session, so a caller cannot tell "none yet" from "not fetched" — which is
114
+ * why the fetch is explicit rather than hidden behind this getter.
115
+ */
116
+ getInputHistory(sessionId: string): UserMessage[];
117
+ /** Pull a session's recorded messages from the host into the mirror. */
118
+ hydrateInputHistory(sessionId: string): Promise<UserMessage[]>;
119
+ getPid(sessionId: string): number | null;
120
+ getSession(sessionId: string): ManagedSession | null;
121
+ hasSession(sessionId: string): boolean;
122
+ listSessions(): ManagedSession[];
123
+ /**
124
+ * Drops this streamer's connection and nothing else.
125
+ *
126
+ * Emphatically NOT the in-process `dispose()`, which signals every child. The
127
+ * entire point of the host is that its PTYs outlive the streamer, so tearing
128
+ * them down here would spend the feature to implement a method name.
129
+ */
130
+ dispose(): void;
131
+ private requireSession;
132
+ }
133
+ //# sourceMappingURL=remote-session-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-session-runner.d.ts","sourceRoot":"","sources":["../../src/pty-host/remote-session-runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ import { type Server, type Socket } from "node:net";
2
+ import { encodeMessage, type HostTransport } from "./protocol";
3
+ /**
4
+ * Socket plumbing for the pty-host (plan Phase 6b).
5
+ *
6
+ * A unix domain socket on POSIX, a named pipe on Windows. Both are local-only
7
+ * by construction, which is the security property that matters: the host can
8
+ * spawn arbitrary agent processes, so it must never be reachable over a TCP
9
+ * port that something else on the network could find.
10
+ */
11
+ /**
12
+ * Where the host listens.
13
+ *
14
+ * Scoped by instance id, so two streamers configured as separate instances on
15
+ * one machine do not fight over one host — the same reason DB-persisted
16
+ * sessions are scoped by it.
17
+ *
18
+ * POSIX puts it under the config dir rather than /tmp: `THREADBASE_CONFIG_DIR`
19
+ * already redirects the whole config tree in tests, and a path under a
20
+ * user-owned directory cannot be pre-created by another user to hijack the
21
+ * bind. Windows named pipes are not filesystem paths at all, so the config dir
22
+ * has nothing to say about them.
23
+ */
24
+ export declare function hostSocketPath(instanceId: string): string;
25
+ /** Wrap a connected socket as the duplex line channel the runner expects. */
26
+ export declare function socketTransport(socket: Socket): HostTransport;
27
+ /** Connect to a host that is already listening. Rejects if none is. */
28
+ export declare function connectToHost(socketPath: string): Promise<HostTransport>;
29
+ export type PtyHostStatusProbe = {
30
+ reachable: true;
31
+ protocolVersion: number;
32
+ sessionCount: number;
33
+ } | {
34
+ reachable: false;
35
+ error: string;
36
+ };
37
+ /** Query host status without subscribing to events or adopting its sessions. */
38
+ export declare function probePtyHostStatus(socketPath: string, timeoutMs?: number): Promise<PtyHostStatusProbe>;
39
+ export interface HostServerHandlers {
40
+ /** One connected streamer. Returns a disposer run when it disconnects. */
41
+ onConnection: (transport: HostTransport) => () => void;
42
+ }
43
+ /**
44
+ * Listen for streamer connections.
45
+ *
46
+ * A stale socket file from a host that died without cleaning up would make
47
+ * `listen` fail with EADDRINUSE forever, so an unconnectable one is removed
48
+ * first — but only after a probe confirms nothing answers on it, because
49
+ * deleting a live host's socket would strand every session it holds.
50
+ */
51
+ export declare function listenForStreamers(socketPath: string, handlers: HostServerHandlers): Promise<Server>;
52
+ /** Broadcast helper: a message to every currently-connected streamer. */
53
+ export declare function broadcast(transports: Iterable<HostTransport>, message: Parameters<typeof encodeMessage>[0]): void;
54
+ //# sourceMappingURL=socket.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket.d.ts","sourceRoot":"","sources":["../../src/pty-host/socket.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkC,KAAK,MAAM,EAAE,KAAK,MAAM,EAAE,MAAM,UAAU,CAAC;AAGpF,OAAO,EACL,aAAa,EAEb,KAAK,aAAa,EAGnB,MAAM,YAAY,CAAC;AAEpB;;;;;;;GAOG;AAEH;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED,6EAA6E;AAC7E,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,aAAa,CA2B7D;AAED,uEAAuE;AACvE,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CASxE;AAED,MAAM,MAAM,kBAAkB,GAC1B;IAAE,SAAS,EAAE,IAAI,CAAC;IAAC,eAAe,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAClE;IAAE,SAAS,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAExC,gFAAgF;AAChF,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,SAAS,SAAQ,GAChB,OAAO,CAAC,kBAAkB,CAAC,CA2E7B;AAED,MAAM,WAAW,kBAAkB;IACjC,0EAA0E;IAC1E,YAAY,EAAE,CAAC,SAAS,EAAE,aAAa,KAAK,MAAM,IAAI,CAAC;CACxD;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,kBAAkB,GAC3B,OAAO,CAAC,MAAM,CAAC,CA6BjB;AAED,yEAAyE;AACzE,wBAAgB,SAAS,CACvB,UAAU,EAAE,QAAQ,CAAC,aAAa,CAAC,EACnC,OAAO,EAAE,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC,GAC3C,IAAI,CAUN"}
@@ -0,0 +1,30 @@
1
+ import type { HostTransport } from "./protocol";
2
+ export interface SpawnHostOptions {
3
+ instanceId: string;
4
+ /** argv[1] for the child — the CLI entry point. Defaults to this process's. */
5
+ entryPoint?: string;
6
+ timeoutMs?: number;
7
+ }
8
+ /**
9
+ * Connect to the host for this instance, spawning it if none is listening.
10
+ *
11
+ * Attach-first rather than spawn-first: the host outliving the streamer is the
12
+ * feature, so the common case after a restart is that one is already there.
13
+ */
14
+ export declare function connectOrSpawnHost(options: SpawnHostOptions): Promise<HostTransport>;
15
+ /**
16
+ * Spawn the host so it survives this process.
17
+ *
18
+ * Three properties, each load-bearing:
19
+ *
20
+ * - `detached` puts it in its own process group, so a Ctrl-C or a group kill
21
+ * aimed at the streamer does not take the agents with it.
22
+ * - `stdio: "ignore"` means it holds none of our descriptors. A child that
23
+ * inherited our stdout keeps a pipe open that the parent's exit cannot
24
+ * close, and on POSIX would also receive our terminal's SIGHUP — which is
25
+ * precisely the hangup this whole feature exists to avoid.
26
+ * - `unref()` removes it from our event loop, so the streamer can exit while
27
+ * the host keeps running.
28
+ */
29
+ export declare function spawnDetachedHost(socketPath: string, entryPoint?: string): void;
30
+ //# sourceMappingURL=spawn-host.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spawn-host.d.ts","sourceRoot":"","sources":["../../src/pty-host/spawn-host.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAahD,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CA4B1F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAO/E"}
@@ -0,0 +1,65 @@
1
+ import type { ManagedSession, PTYManagerOptions, SessionRunner, StartFreshSessionOptions, StartSessionOptions, UserMessage } from "./types";
2
+ export declare class PTYManager implements SessionRunner {
3
+ private sessions;
4
+ private onOutput;
5
+ private onStatusChange;
6
+ private onReady;
7
+ private onPermissionChange;
8
+ private onPhaseChange;
9
+ private onLiveQuestion;
10
+ private onLiveQuestionGone;
11
+ private onUserMessage;
12
+ private permissionOpen;
13
+ private oscTail;
14
+ private lastDetectAt;
15
+ private lastScreenQuestionKey;
16
+ private shellPromptOpen;
17
+ private closedGateKey;
18
+ private pendingReady;
19
+ private queuedInputs;
20
+ private log;
21
+ private firstChunkAt;
22
+ private chunkIndex;
23
+ private lastChunkAt;
24
+ private quietCheckers;
25
+ private readyFallbackTimers;
26
+ private startPromises;
27
+ constructor(options?: PTYManagerOptions);
28
+ start(sessionId: string, options: StartSessionOptions): Promise<ManagedSession>;
29
+ private doStart;
30
+ startFresh(options: StartFreshSessionOptions): Promise<ManagedSession>;
31
+ sendKeys(sessionId: string, keys: string): void;
32
+ sendInput(sessionId: string, input: string): number;
33
+ private writeSubmit;
34
+ private flushQueuedInputs;
35
+ cancel(sessionId: string): void;
36
+ killPid(pid: number): void;
37
+ putOnHold(sessionId: string): void;
38
+ getOutput(sessionId: string): string;
39
+ getOutputLines(sessionId: string, maxLines: number): Promise<string[]>;
40
+ getInputHistory(sessionId: string): UserMessage[];
41
+ getPid(sessionId: string): number | null;
42
+ private recordUserMessage;
43
+ getSession(sessionId: string): ManagedSession | null;
44
+ hasSession(sessionId: string): boolean;
45
+ listSessions(): ManagedSession[];
46
+ dispose(): void;
47
+ private handleOutput;
48
+ private detectLivePrompts;
49
+ private handleQuiet;
50
+ private recheckReadyFromScreen;
51
+ private armReadyFallback;
52
+ private clearReadyFallback;
53
+ /**
54
+ * Record the agent's phase and notify only on a real change.
55
+ *
56
+ * The change guard is load-bearing, not an optimisation: the scrape pass runs
57
+ * on every chunk, so an unguarded setter would fire the callback — and the
58
+ * WS frame behind it — several times a second for the entire duration of a
59
+ * turn while reporting the same value.
60
+ */
61
+ private setPhase;
62
+ private markReady;
63
+ private handleExit;
64
+ }
65
+ //# sourceMappingURL=pty-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pty-manager.d.ts","sourceRoot":"","sources":["../src/pty-manager.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAEV,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,wBAAwB,EACxB,mBAAmB,EAEnB,WAAW,EACZ,MAAM,SAAS,CAAC;AAyHjB,qBAAa,UAAW,YAAW,aAAa;IAC9C,OAAO,CAAC,QAAQ,CAAsC;IACtD,OAAO,CAAC,QAAQ,CAAgC;IAChD,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,OAAO,CAA+B;IAC9C,OAAO,CAAC,kBAAkB,CAA0C;IACpE,OAAO,CAAC,aAAa,CAAqC;IAC1D,OAAO,CAAC,cAAc,CAAsC;IAC5D,OAAO,CAAC,kBAAkB,CAA0C;IACpE,OAAO,CAAC,aAAa,CAAqC;IAI1D,OAAO,CAAC,cAAc,CAAqB;IAG3C,OAAO,CAAC,OAAO,CAA6B;IAG5C,OAAO,CAAC,YAAY,CAA6B;IAGjD,OAAO,CAAC,qBAAqB,CAA6B;IAK1D,OAAO,CAAC,eAAe,CAA6B;IAOpD,OAAO,CAAC,aAAa,CAA6B;IAGlD,OAAO,CAAC,YAAY,CAAqB;IAMzC,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,GAAG,CAAS;IAGpB,OAAO,CAAC,YAAY,CAA6B;IAIjD,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,WAAW,CAA6B;IAIhD,OAAO,CAAC,aAAa,CAAkD;IAEvE,OAAO,CAAC,mBAAmB,CAAqC;IAIhE,OAAO,CAAC,aAAa,CAA8C;IAEnE,YAAY,OAAO,GAAE,iBAAsB,EAU1C;IAkBK,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,cAAc,CAAC,CAkBpF;YAEa,OAAO;IAkFf,UAAU,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,cAAc,CAAC,CA2E3E;IAID,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAmB9C;IAED,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAyClD;IAgBD,OAAO,CAAC,WAAW;IAwDnB,OAAO,CAAC,iBAAiB;IA8BzB,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAI9B;IAED,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAMzB;IAGD,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CA2BjC;IAED,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAInC;IAUK,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAkB3E;IAED,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,WAAW,EAAE,CAEhD;IAMD,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAEvC;IAKD,OAAO,CAAC,iBAAiB;IAgBzB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAGnD;IAED,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAErC;IAED,YAAY,IAAI,cAAc,EAAE,CAE/B;IAED,OAAO,IAAI,IAAI,CAuBd;IAED,OAAO,CAAC,YAAY;YA2FN,iBAAiB;IAmN/B,OAAO,CAAC,WAAW;YAkDL,sBAAsB;IAgBpC,OAAO,CAAC,gBAAgB;IAYxB,OAAO,CAAC,kBAAkB;IAQ1B;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ;IAOhB,OAAO,CAAC,SAAS;IA2CjB,OAAO,CAAC,UAAU;CAoCnB"}
@@ -0,0 +1,27 @@
1
+ import { Terminal } from "@xterm/headless";
2
+ import type { ManagedSession, UserMessage } from "./types";
3
+ /**
4
+ * Plumbing shared by the two PTY runners (`pty-manager.ts` for Claude,
5
+ * `codex-pty-runner.ts` for Codex). These were duplicated byte-for-byte in both
6
+ * files; the copies drifted only in their comments.
7
+ *
8
+ * Deliberately plumbing only. The two runners' *detection* logic stays
9
+ * provider-specific and is not shared: Claude signals readiness with OSC 777
10
+ * plus prompt markers, Codex with rendered status-bar predicates and no OSC at
11
+ * all. Merging those would couple two independent provider contracts.
12
+ */
13
+ export declare const PTY_COLS = 120;
14
+ export declare const PTY_ROWS = 40;
15
+ export declare const SCREEN_SCROLLBACK = 1000;
16
+ export declare const REPLAY_MAX_LINES: number;
17
+ export declare function digestBytes(s: string): string;
18
+ export declare function loadPty(): Promise<typeof import("node-pty")>;
19
+ export interface InternalSession extends ManagedSession {
20
+ process: any;
21
+ outputBuffer: Buffer;
22
+ screen: Terminal;
23
+ inputHistory: UserMessage[];
24
+ }
25
+ export declare function createScreen(): Terminal;
26
+ export declare function stripAnsi(str: string): string;
27
+ //# sourceMappingURL=pty-shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pty-shared.d.ts","sourceRoot":"","sources":["../src/pty-shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAE3D;;;;;;;;;GASG;AAKH,eAAO,MAAM,QAAQ,MAAM,CAAC;AAC5B,eAAO,MAAM,QAAQ,KAAK,CAAC;AAE3B,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAOtC,eAAO,MAAM,gBAAgB,QAA+B,CAAC;AAE7D,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAW7C;AAKD,wBAAsB,OAAO,IAAI,OAAO,CAAC,cAAc,UAAU,CAAC,CAAC,CAYlE;AAED,MAAM,WAAW,eAAgB,SAAQ,cAAc;IACrD,OAAO,EAAE,GAAG,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IAKrB,MAAM,EAAE,QAAQ,CAAC;IAGjB,YAAY,EAAE,WAAW,EAAE,CAAC;CAC7B;AAED,wBAAgB,YAAY,IAAI,QAAQ,CAOvC;AAGD,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG7C"}
@@ -0,0 +1,126 @@
1
+ import { type Conversation, type ConversationMeta, ConversationScanner, type FileStatEntry } from "@threadbase-sh/scanner";
2
+ import type { ConversationCache } from "./conversation-cache";
3
+ import type { CacheMetadataRepository } from "./db/repositories/cacheMetadata.repository";
4
+ import type { ConversationsRepository } from "./db/repositories/conversations.repository";
5
+ import type { ProjectsRepository } from "./db/repositories/projects.repository";
6
+ import type { CacheIntegrityMonitor } from "./services/cache-integrity/cacheIntegrityMonitor";
7
+ import { debounce } from "./utils/debounce";
8
+ export type ConversationReconcileMode = "files" | "full";
9
+ export type ScanProfile = {
10
+ id: string;
11
+ label: string;
12
+ configDir: string;
13
+ enabled: boolean;
14
+ emoji: string;
15
+ };
16
+ /**
17
+ * Everything ScannerManager reads from the server. Nullable collaborators are
18
+ * thunks rather than values because they are opened during listen() and
19
+ * rebound by the integrity monitor's reset-and-rescan — the same reason
20
+ * ApiDeps passes `cache: () => ConversationCache | null`.
21
+ */
22
+ export type ScannerManagerDeps = {
23
+ scanProfiles: ScanProfile[] | undefined;
24
+ codexRoots: string[];
25
+ directoryDebounceMs: number;
26
+ persistenceDisabled: boolean;
27
+ cache: () => ConversationCache | null;
28
+ cacheMonitor: () => CacheIntegrityMonitor | null;
29
+ projectsRepo: () => ProjectsRepository | null;
30
+ conversationsRepo: () => ConversationsRepository | null;
31
+ cacheMetadataRepo: () => CacheMetadataRepository | null;
32
+ trackCacheWrite: (task: Promise<unknown>) => void;
33
+ };
34
+ /**
35
+ * Owns the conversation scanner's lifecycle and freshness state: which scanner
36
+ * instance is current, whether a scan is in flight, which files went stale, and
37
+ * the cache↔disk reconcile that closes the gap.
38
+ *
39
+ * Extracted from StreamerServer so scanner work stops editing the server file
40
+ * (see docs/plans/2026-07-12-server-ts-split.md, PR 2).
41
+ */
42
+ export declare class ScannerManager {
43
+ private deps;
44
+ private scanner;
45
+ private scannerReady;
46
+ private scannerStale;
47
+ private persistenceDisabled;
48
+ private allScanners;
49
+ private stalePaths;
50
+ private reconcileInFlight;
51
+ private lastAutoFullReconcileAt;
52
+ private static readonly AUTO_FULL_RECONCILE_COOLDOWN_MS;
53
+ private refreshInFlight;
54
+ private log;
55
+ /**
56
+ * Trailing-debounced "the directory changed" signal. Kept public because the
57
+ * server wires it straight into the watcher callback and cancels it in
58
+ * close(); `.cancel()` is part of its contract.
59
+ */
60
+ readonly markStaleDebounced: ReturnType<typeof debounce>;
61
+ constructor(deps: ScannerManagerDeps);
62
+ /** The current scanner without triggering a scan; null before the first one. */
63
+ get current(): ConversationScanner | null;
64
+ /** The in-flight (or settled) scan promise; null when no scanner was ever built. */
65
+ get ready(): Promise<unknown> | null;
66
+ get stale(): boolean;
67
+ set stale(value: boolean);
68
+ /** The stale-path set itself, so callers can add/clear/size it in place. */
69
+ get staleFiles(): Set<string>;
70
+ /** Drop the current scanner so the next get() builds a fresh one. */
71
+ invalidate(): void;
72
+ /**
73
+ * A new JSONL bound to a live session: the index must pick it up.
74
+ *
75
+ * Arm the stale flag when a scan already exists, so the next get() reconciles
76
+ * in place. With no scanner yet there is nothing to mark, so drop it instead
77
+ * and let the next get() build one. Exactly one of the two happens — dropping
78
+ * the scanner in both cases would throw away a live index on every bind.
79
+ */
80
+ markStaleOrDrop(): void;
81
+ /** Persistent indexes are disabled for the rest of this process's life. */
82
+ disablePersistence(): void;
83
+ /** Track a scanner the server built itself so close() still tears it down. */
84
+ track(scanner: ConversationScanner): void;
85
+ /**
86
+ * Adopt the warm-up scanner as the live one, but only if nothing else claimed
87
+ * the slot while the warm-up scan ran.
88
+ */
89
+ adoptIfUnclaimed(scanner: ConversationScanner): boolean;
90
+ buildStatCache(previousScanner: ConversationScanner | null): Map<string, {
91
+ stat: FileStatEntry;
92
+ meta: ConversationMeta;
93
+ }> | undefined;
94
+ codexScanOpts(): {
95
+ providers: ("claude-code" | "codex-cli")[];
96
+ codexRoots: string[];
97
+ };
98
+ newScanner(options?: ConstructorParameters<typeof ConversationScanner>[0]): ConversationScanner;
99
+ /**
100
+ * The projects dirs disk discovery should walk — the single source of truth
101
+ * for "where do this server's JSONLs live", mirroring the warm-up watcher
102
+ * (see listen()). Derived from the enabled scanProfiles' configDirs, or the
103
+ * real ~/.claude/projects when no profiles are configured. An all-disabled
104
+ * profile set intentionally yields [] (nothing to discover), matching the
105
+ * watcher — it does NOT fall back to home in that case.
106
+ */
107
+ projectsDirs(): string[];
108
+ takeStaleFiles(): string[];
109
+ refreshStaleFiles(scanner: ConversationScanner, paths: string[]): Promise<ConversationMeta[]>;
110
+ isConversationSnapshotStale(conv: Conversation): boolean;
111
+ refreshFileGuarded(scanner: ConversationScanner, filePath: string): Promise<Awaited<ReturnType<ConversationScanner["refreshFile"]>> | null>;
112
+ get(skipStaleRescan?: boolean): Promise<ConversationScanner>;
113
+ getFresh(): Promise<ConversationScanner>;
114
+ rescanForRefresh(onProgress?: (scanned: number, total: number) => void): Promise<ConversationScanner>;
115
+ /**
116
+ * Full-glob scan + cache upsert/delete reconcile. Used by ?refresh=1 and by
117
+ * the automatic freshness path when the directory watcher marked the scanner
118
+ * stale or shouldRefreshProjectsFromHdd detected disk drift.
119
+ */
120
+ reconcileFromDisk(onProgress?: (scanned: number, total: number) => void): Promise<void>;
121
+ startBackgroundReconcile(mode?: ConversationReconcileMode): void;
122
+ reconcileMode(): ConversationReconcileMode | null;
123
+ private reconcileStaleFilesFromDisk;
124
+ close(): Promise<void>;
125
+ }
126
+ //# sourceMappingURL=scanner-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner-manager.d.ts","sourceRoot":"","sources":["../src/scanner-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import { z } from "zod";
2
+ /** Body for POST /api/cache/alert/resolve. */
3
+ export declare const ResolveCacheAlertSchema: z.ZodObject<{
4
+ fingerprint: z.ZodString;
5
+ action: z.ZodEnum<{
6
+ ignore: "ignore";
7
+ prune_all: "prune_all";
8
+ prune_selected: "prune_selected";
9
+ reset_rescan: "reset_rescan";
10
+ }>;
11
+ ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
12
+ }, z.core.$strip>;
13
+ export type ResolveCacheAlertBody = z.infer<typeof ResolveCacheAlertSchema>;
14
+ //# sourceMappingURL=cacheAlert.schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cacheAlert.schema.d.ts","sourceRoot":"","sources":["../../src/schemas/cacheAlert.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,8CAA8C;AAC9C,eAAO,MAAM,uBAAuB;;;;;;;;;iBAShC,CAAC;AAEL,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,uBAAuB,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { z } from "zod";
2
+ export declare const ClaudeFlagsBodySchema: z.ZodObject<{
3
+ values: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodString, z.ZodBoolean, z.ZodArray<z.ZodString>]>>>;
4
+ extraArgs: z.ZodOptional<z.ZodString>;
5
+ }, z.core.$strict>;
6
+ export type ClaudeFlagsBody = z.infer<typeof ClaudeFlagsBodySchema>;
7
+ //# sourceMappingURL=claudeFlags.schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claudeFlags.schema.d.ts","sourceRoot":"","sources":["../../src/schemas/claudeFlags.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAYxB,eAAO,MAAM,qBAAqB;;;kBAYvB,CAAC;AAEZ,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * Persisted Project row. Mirrors the projects SQLite table.
4
+ */
5
+ export declare const ProjectSchema: z.ZodObject<{
6
+ id: z.ZodString;
7
+ path: z.ZodString;
8
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
9
+ lastConversationId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
10
+ lastConversationCreatedAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
11
+ lastIndexedAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
12
+ latestMessageAt: z.ZodOptional<z.ZodNullable<z.ZodString>>;
13
+ latestMessageId: z.ZodOptional<z.ZodNullable<z.ZodString>>;
14
+ createdAt: z.ZodString;
15
+ updatedAt: z.ZodString;
16
+ }, z.core.$strip>;
17
+ export type Project = z.infer<typeof ProjectSchema>;
18
+ //# sourceMappingURL=project.schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project.schema.d.ts","sourceRoot":"","sources":["../../src/schemas/project.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;GAEG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;iBAcxB,CAAC;AAEH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ import { z } from "zod";
2
+ export declare const UpdateConfigSchema: z.ZodObject<{
3
+ auto_update: z.ZodDefault<z.ZodBoolean>;
4
+ channel: z.ZodDefault<z.ZodEnum<{
5
+ next: "next";
6
+ stable: "stable";
7
+ }>>;
8
+ allow: z.ZodDefault<z.ZodArray<z.ZodEnum<{
9
+ major: "major";
10
+ minor: "minor";
11
+ patch: "patch";
12
+ }>>>;
13
+ poll_interval_minutes: z.ZodDefault<z.ZodNumber>;
14
+ defer_if_active_sessions: z.ZodDefault<z.ZodBoolean>;
15
+ github_repo: z.ZodString;
16
+ webhook_secret: z.ZodDefault<z.ZodNullable<z.ZodString>>;
17
+ }, z.core.$strict>;
18
+ export type UpdateConfig = z.infer<typeof UpdateConfigSchema>;
19
+ //# sourceMappingURL=updateConfig.schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"updateConfig.schema.d.ts","sourceRoot":"","sources":["../../src/schemas/updateConfig.schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;kBAUpB,CAAC;AAEZ,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
package/dist/seal.d.ts ADDED
@@ -0,0 +1,14 @@
1
+ export interface SealedPayload {
2
+ ciphertext: string;
3
+ nonce: string;
4
+ ephemeralPublicKey: string;
5
+ }
6
+ /**
7
+ * Encrypts a plaintext to a recipient's X25519 public key using NaCl box with
8
+ * an ephemeral sender keypair. The phone holds the recipient private key in
9
+ * its own memory and decrypts with nacl.box.open(ciphertext, nonce, ephemeralPublicKey, recipientPrivateKey).
10
+ *
11
+ * The wire format is custom (not libsodium crypto_box_seal) but cryptographically equivalent.
12
+ */
13
+ export declare function seal(plaintext: string, recipientPublicKeyBase64: string): SealedPayload;
14
+ //# sourceMappingURL=seal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"seal.d.ts","sourceRoot":"","sources":["../src/seal.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,IAAI,CAAC,SAAS,EAAE,MAAM,EAAE,wBAAwB,EAAE,MAAM,GAAG,aAAa,CAgBvF"}
@@ -0,0 +1,43 @@
1
+ import { type KeyObject } from "crypto";
2
+ export interface ServerIdentity {
3
+ /** Raw X25519 public key, base64url, 43 chars. Public: the QR, /api/info, logs. */
4
+ publicKey: string;
5
+ /** Never leaves the process — not a log line, not a response, not an error message. */
6
+ privateKey: KeyObject;
7
+ }
8
+ /**
9
+ * `~/.threadbase/keys/server-identity.key`.
10
+ *
11
+ * Its own file, not a `server.yaml` key: that file is parsed by single-line
12
+ * regex and users are invited to hand-edit it, which is no place for a private
13
+ * key. The config dir is resolved per call, and inlined rather than imported
14
+ * from auth.ts, matching runtime-store.ts / pty-host/socket.ts /
15
+ * codexGateAnswers.ts — tests redirect it with THREADBASE_CONFIG_DIR.
16
+ */
17
+ export declare function serverIdentityKeyPath(): string;
18
+ /**
19
+ * The server identity, generated on first call and stable forever after —
20
+ * across restarts and across API-key rotation.
21
+ *
22
+ * Stability is the whole point. The public half goes into a pair QR, so minting
23
+ * a second key would silently invalidate every device that scanned the first.
24
+ * A file that exists but cannot be read therefore **throws** rather than
25
+ * regenerating: losing this key must be a deliberate act (delete the file), not
26
+ * the recovery path for a bad read.
27
+ */
28
+ export declare function loadOrCreateServerIdentity(): ServerIdentity;
29
+ /** The public half alone, for callers that must never hold the private key. */
30
+ export declare function serverIdentityPublicKey(): string;
31
+ /**
32
+ * The fingerprint a user compares out of band (design.md §2.2): SHA-256 over
33
+ * the raw 32 public-key bytes, truncated to the first 16, printed as 8
34
+ * space-separated groups of 4 lowercase hex characters.
35
+ *
36
+ * Pure function of the base64url string `serverIdentityPublicKey()` returns —
37
+ * decode that, not the JWK or any other encoding, or this hashes different
38
+ * bytes than the phone does and the two fingerprints never match.
39
+ */
40
+ export declare function serverIdentityFingerprint(publicKeyBase64url: string): string;
41
+ /** Convenience over the real, on-disk identity key. */
42
+ export declare function currentServerIdentityFingerprint(): string;
43
+ //# sourceMappingURL=server-identity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-identity.d.ts","sourceRoot":"","sources":["../src/server-identity.ts"],"names":[],"mappings":"AAcA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,QAAQ,CAAC;AAqBhB,MAAM,WAAW,cAAc;IAC7B,mFAAmF;IACnF,SAAS,EAAE,MAAM,CAAC;IAClB,uFAAuF;IACvF,UAAU,EAAE,SAAS,CAAC;CACvB;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAG9C;AAED;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,IAAI,cAAc,CAuB3D;AAED,+EAA+E;AAC/E,wBAAgB,uBAAuB,IAAI,MAAM,CAEhD;AAED;;;;;;;;GAQG;AACH,wBAAgB,yBAAyB,CAAC,kBAAkB,EAAE,MAAM,GAAG,MAAM,CAI5E;AAED,uDAAuD;AACvD,wBAAgB,gCAAgC,IAAI,MAAM,CAEzD"}