tailii-host 0.1.0 → 0.3.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 (348) hide show
  1. package/README.md +35 -14
  2. package/dist/{broker.d.ts → approval/broker.d.ts} +9 -5
  3. package/dist/{broker.js → approval/broker.js} +42 -6
  4. package/dist/approval/broker.js.map +1 -0
  5. package/dist/{hook.d.ts → approval/hook.d.ts} +48 -7
  6. package/dist/{hook.js → approval/hook.js} +359 -50
  7. package/dist/approval/hook.js.map +1 -0
  8. package/dist/backend/herdr.d.ts +226 -0
  9. package/dist/backend/herdr.js +749 -0
  10. package/dist/backend/herdr.js.map +1 -0
  11. package/dist/backend/sessionBackend.d.ts +81 -0
  12. package/dist/backend/sessionBackend.js +114 -0
  13. package/dist/backend/sessionBackend.js.map +1 -0
  14. package/dist/backend/tmux.d.ts +125 -0
  15. package/dist/backend/tmux.js +392 -0
  16. package/dist/backend/tmux.js.map +1 -0
  17. package/dist/{chatTailController.d.ts → chat/chatTailController.d.ts} +29 -6
  18. package/dist/{chatTailController.js → chat/chatTailController.js} +94 -18
  19. package/dist/chat/chatTailController.js.map +1 -0
  20. package/dist/{imageService.d.ts → chat/imageService.d.ts} +12 -1
  21. package/dist/{imageService.js → chat/imageService.js} +39 -11
  22. package/dist/chat/imageService.js.map +1 -0
  23. package/dist/chat/remoteQuestionMonitor.d.ts +27 -0
  24. package/dist/chat/remoteQuestionMonitor.js +128 -0
  25. package/dist/chat/remoteQuestionMonitor.js.map +1 -0
  26. package/dist/chat/subagentTailer.d.ts +30 -0
  27. package/dist/chat/subagentTailer.js +704 -0
  28. package/dist/chat/subagentTailer.js.map +1 -0
  29. package/dist/chat/subagentTranscript.d.ts +20 -0
  30. package/dist/chat/subagentTranscript.js +273 -0
  31. package/dist/chat/subagentTranscript.js.map +1 -0
  32. package/dist/{transcriptTailer.d.ts → chat/transcriptTailer.d.ts} +12 -1
  33. package/dist/{transcriptTailer.js → chat/transcriptTailer.js} +183 -10
  34. package/dist/chat/transcriptTailer.js.map +1 -0
  35. package/dist/cli.js +15 -10
  36. package/dist/cli.js.map +1 -1
  37. package/dist/codex/codexAccountUsage.d.ts +22 -0
  38. package/dist/codex/codexAccountUsage.js +128 -0
  39. package/dist/codex/codexAccountUsage.js.map +1 -0
  40. package/dist/codex/codexAppServer.d.ts +166 -0
  41. package/dist/codex/codexAppServer.js +1297 -0
  42. package/dist/codex/codexAppServer.js.map +1 -0
  43. package/dist/codex/codexNativeTurnController.d.ts +153 -0
  44. package/dist/codex/codexNativeTurnController.js +673 -0
  45. package/dist/codex/codexNativeTurnController.js.map +1 -0
  46. package/dist/codex/codexRolloutTailer.d.ts +100 -0
  47. package/dist/codex/codexRolloutTailer.js +568 -0
  48. package/dist/codex/codexRolloutTailer.js.map +1 -0
  49. package/dist/{codexSessionStore.d.ts → codex/codexSessionStore.d.ts} +10 -2
  50. package/dist/{codexSessionStore.js → codex/codexSessionStore.js} +184 -15
  51. package/dist/codex/codexSessionStore.js.map +1 -0
  52. package/dist/codex/codexSubagentTracker.d.ts +21 -0
  53. package/dist/codex/codexSubagentTracker.js +281 -0
  54. package/dist/codex/codexSubagentTracker.js.map +1 -0
  55. package/dist/codex/codexToolActivity.d.ts +69 -0
  56. package/dist/codex/codexToolActivity.js +425 -0
  57. package/dist/codex/codexToolActivity.js.map +1 -0
  58. package/dist/{codexUsage.d.ts → codex/codexUsage.d.ts} +1 -1
  59. package/dist/{codexUsage.js → codex/codexUsage.js} +19 -26
  60. package/dist/codex/codexUsage.js.map +1 -0
  61. package/dist/commands/doctor.d.ts +65 -0
  62. package/dist/commands/doctor.js +425 -0
  63. package/dist/commands/doctor.js.map +1 -0
  64. package/dist/{hookSettings.d.ts → commands/hookSettings.d.ts} +14 -1
  65. package/dist/{hookSettings.js → commands/hookSettings.js} +96 -12
  66. package/dist/commands/hookSettings.js.map +1 -0
  67. package/dist/{kick.js → commands/kick.js} +16 -1
  68. package/dist/commands/kick.js.map +1 -0
  69. package/dist/{launch.d.ts → commands/launch.d.ts} +67 -5
  70. package/dist/commands/launch.js +716 -0
  71. package/dist/commands/launch.js.map +1 -0
  72. package/dist/commands/legacyHomeMigration.js.map +1 -0
  73. package/dist/{pairingCode.d.ts → commands/pairingCode.d.ts} +29 -2
  74. package/dist/{pairingCode.js → commands/pairingCode.js} +120 -11
  75. package/dist/commands/pairingCode.js.map +1 -0
  76. package/dist/{pushTokenCommand.d.ts → commands/pushTokenCommand.d.ts} +1 -1
  77. package/dist/{pushTokenCommand.js → commands/pushTokenCommand.js} +2 -2
  78. package/dist/commands/pushTokenCommand.js.map +1 -0
  79. package/dist/{setup.d.ts → commands/setup.d.ts} +17 -6
  80. package/dist/{setup.js → commands/setup.js} +133 -75
  81. package/dist/commands/setup.js.map +1 -0
  82. package/dist/engine/context.d.ts +145 -0
  83. package/dist/engine/context.js +184 -0
  84. package/dist/engine/context.js.map +1 -0
  85. package/dist/engine/engine.d.ts +121 -0
  86. package/dist/engine/engine.js +799 -0
  87. package/dist/engine/engine.js.map +1 -0
  88. package/dist/engine/handlers/accountUsage.d.ts +53 -0
  89. package/dist/engine/handlers/accountUsage.js +203 -0
  90. package/dist/engine/handlers/accountUsage.js.map +1 -0
  91. package/dist/engine/handlers/claudeModels.d.ts +2 -0
  92. package/dist/engine/handlers/claudeModels.js +23 -0
  93. package/dist/engine/handlers/claudeModels.js.map +1 -0
  94. package/dist/engine/handlers/codex.d.ts +2 -0
  95. package/dist/engine/handlers/codex.js +97 -0
  96. package/dist/engine/handlers/codex.js.map +1 -0
  97. package/dist/engine/handlers/conversation.d.ts +2 -0
  98. package/dist/engine/handlers/conversation.js +259 -0
  99. package/dist/engine/handlers/conversation.js.map +1 -0
  100. package/dist/engine/handlers/core.d.ts +2 -0
  101. package/dist/engine/handlers/core.js +66 -0
  102. package/dist/engine/handlers/core.js.map +1 -0
  103. package/dist/engine/handlers/git.d.ts +2 -0
  104. package/dist/engine/handlers/git.js +127 -0
  105. package/dist/engine/handlers/git.js.map +1 -0
  106. package/dist/engine/handlers/index.d.ts +2 -0
  107. package/dist/engine/handlers/index.js +32 -0
  108. package/dist/engine/handlers/index.js.map +1 -0
  109. package/dist/engine/handlers/mode.d.ts +2 -0
  110. package/dist/engine/handlers/mode.js +194 -0
  111. package/dist/engine/handlers/mode.js.map +1 -0
  112. package/dist/engine/handlers/officialApps.d.ts +2 -0
  113. package/dist/engine/handlers/officialApps.js +79 -0
  114. package/dist/engine/handlers/officialApps.js.map +1 -0
  115. package/dist/engine/handlers/preview.d.ts +2 -0
  116. package/dist/engine/handlers/preview.js +59 -0
  117. package/dist/engine/handlers/preview.js.map +1 -0
  118. package/dist/engine/handlers/session.d.ts +2 -0
  119. package/dist/engine/handlers/session.js +385 -0
  120. package/dist/engine/handlers/session.js.map +1 -0
  121. package/dist/engine/handlers/usage.d.ts +2 -0
  122. package/dist/engine/handlers/usage.js +96 -0
  123. package/dist/engine/handlers/usage.js.map +1 -0
  124. package/dist/engine/handlers/workspace.d.ts +2 -0
  125. package/dist/engine/handlers/workspace.js +110 -0
  126. package/dist/engine/handlers/workspace.js.map +1 -0
  127. package/dist/engine/slashCommands.d.ts +3 -0
  128. package/dist/engine/slashCommands.js +211 -0
  129. package/dist/engine/slashCommands.js.map +1 -0
  130. package/dist/hub/engineRelaySocket.d.ts +58 -0
  131. package/dist/hub/engineRelaySocket.js +161 -0
  132. package/dist/hub/engineRelaySocket.js.map +1 -0
  133. package/dist/hub/hubClient.d.ts +28 -0
  134. package/dist/hub/hubClient.js +187 -0
  135. package/dist/hub/hubClient.js.map +1 -0
  136. package/dist/hub/hubDaemon.d.ts +69 -0
  137. package/dist/hub/hubDaemon.js +466 -0
  138. package/dist/hub/hubDaemon.js.map +1 -0
  139. package/dist/hub/hubProtocol.d.ts +161 -0
  140. package/dist/hub/hubProtocol.js +379 -0
  141. package/dist/hub/hubProtocol.js.map +1 -0
  142. package/dist/hub/panePreviewPump.d.ts +65 -0
  143. package/dist/hub/panePreviewPump.js +187 -0
  144. package/dist/hub/panePreviewPump.js.map +1 -0
  145. package/dist/hub/questionInjection.d.ts +19 -0
  146. package/dist/hub/questionInjection.js +126 -0
  147. package/dist/hub/questionInjection.js.map +1 -0
  148. package/dist/hub/reaper.d.ts +74 -0
  149. package/dist/hub/reaper.js +333 -0
  150. package/dist/hub/reaper.js.map +1 -0
  151. package/dist/hub/sessionHub.d.ts +203 -0
  152. package/dist/hub/sessionHub.js +1862 -0
  153. package/dist/hub/sessionHub.js.map +1 -0
  154. package/dist/protocol/common.d.ts +18 -0
  155. package/dist/protocol/common.js +78 -0
  156. package/dist/protocol/common.js.map +1 -0
  157. package/dist/protocol/decode.d.ts +3 -0
  158. package/dist/protocol/decode.js +1036 -0
  159. package/dist/protocol/decode.js.map +1 -0
  160. package/dist/protocol/encode.d.ts +3 -0
  161. package/dist/protocol/encode.js +84 -0
  162. package/dist/protocol/encode.js.map +1 -0
  163. package/dist/protocol/messages.d.ts +1002 -0
  164. package/dist/protocol/messages.js +8 -0
  165. package/dist/protocol/messages.js.map +1 -0
  166. package/dist/protocol.d.ts +4 -329
  167. package/dist/protocol.js +13 -531
  168. package/dist/protocol.js.map +1 -1
  169. package/dist/push/apnsConfigStore.js.map +1 -0
  170. package/dist/push/apnsJwtProvider.js.map +1 -0
  171. package/dist/{apnsSender.js.map → push/apnsSender.js.map} +1 -1
  172. package/dist/{approvalPushNotifier.js → push/approvalPushNotifier.js} +1 -1
  173. package/dist/push/approvalPushNotifier.js.map +1 -0
  174. package/dist/push/deviceTokenStore.js.map +1 -0
  175. package/dist/{pushTypes.js → push/pushTypes.js} +1 -1
  176. package/dist/push/pushTypes.js.map +1 -0
  177. package/dist/push/sendLog.js.map +1 -0
  178. package/dist/services/accountIdentity.d.ts +44 -0
  179. package/dist/services/accountIdentity.js +184 -0
  180. package/dist/services/accountIdentity.js.map +1 -0
  181. package/dist/services/claudeCredentialRefresh.d.ts +30 -0
  182. package/dist/services/claudeCredentialRefresh.js +345 -0
  183. package/dist/services/claudeCredentialRefresh.js.map +1 -0
  184. package/dist/services/claudeModelCatalog.d.ts +21 -0
  185. package/dist/services/claudeModelCatalog.js +181 -0
  186. package/dist/services/claudeModelCatalog.js.map +1 -0
  187. package/dist/{dirLister.d.ts → services/dirLister.d.ts} +9 -4
  188. package/dist/services/dirLister.js +169 -0
  189. package/dist/services/dirLister.js.map +1 -0
  190. package/dist/services/fileService.d.ts +10 -0
  191. package/dist/services/fileService.js +123 -0
  192. package/dist/services/fileService.js.map +1 -0
  193. package/dist/services/gitService.d.ts +79 -0
  194. package/dist/services/gitService.js +648 -0
  195. package/dist/services/gitService.js.map +1 -0
  196. package/dist/services/hostVersions.d.ts +38 -0
  197. package/dist/services/hostVersions.js +120 -0
  198. package/dist/services/hostVersions.js.map +1 -0
  199. package/dist/services/officialApps.d.ts +148 -0
  200. package/dist/services/officialApps.js +1079 -0
  201. package/dist/services/officialApps.js.map +1 -0
  202. package/dist/services/planUsageFetcher.d.ts +119 -0
  203. package/dist/services/planUsageFetcher.js +357 -0
  204. package/dist/services/planUsageFetcher.js.map +1 -0
  205. package/dist/services/previewServer.d.ts +31 -0
  206. package/dist/services/previewServer.js +233 -0
  207. package/dist/services/previewServer.js.map +1 -0
  208. package/dist/services/quicGateway.d.ts +143 -0
  209. package/dist/services/quicGateway.js +292 -0
  210. package/dist/services/quicGateway.js.map +1 -0
  211. package/dist/services/serveService.d.ts +50 -0
  212. package/dist/services/serveService.js +302 -0
  213. package/dist/services/serveService.js.map +1 -0
  214. package/dist/services/usageAggregator.js.map +1 -0
  215. package/dist/sessions/claudeSessionStore.d.ts +80 -0
  216. package/dist/sessions/claudeSessionStore.js +477 -0
  217. package/dist/sessions/claudeSessionStore.js.map +1 -0
  218. package/dist/sessions/heartbeat.d.ts +24 -0
  219. package/dist/sessions/heartbeat.js +86 -0
  220. package/dist/sessions/heartbeat.js.map +1 -0
  221. package/dist/sessions/liveSessionJoin.d.ts +20 -0
  222. package/dist/sessions/liveSessionJoin.js +80 -0
  223. package/dist/sessions/liveSessionJoin.js.map +1 -0
  224. package/dist/sessions/sessionActivityProvider.d.ts +14 -0
  225. package/dist/sessions/sessionActivityProvider.js +57 -0
  226. package/dist/sessions/sessionActivityProvider.js.map +1 -0
  227. package/dist/{sessionListService.d.ts → sessions/sessionListService.d.ts} +3 -3
  228. package/dist/{sessionListService.js → sessions/sessionListService.js} +23 -6
  229. package/dist/sessions/sessionListService.js.map +1 -0
  230. package/dist/{sessionMetadataStore.d.ts → sessions/sessionMetadataStore.d.ts} +18 -0
  231. package/dist/{sessionMetadataStore.js → sessions/sessionMetadataStore.js} +36 -1
  232. package/dist/sessions/sessionMetadataStore.js.map +1 -0
  233. package/dist/{sessionSearch.d.ts → sessions/sessionSearch.d.ts} +1 -1
  234. package/dist/sessions/sessionSearch.js.map +1 -0
  235. package/dist/shared/hostDisplayName.d.ts +11 -0
  236. package/dist/shared/hostDisplayName.js +50 -0
  237. package/dist/shared/hostDisplayName.js.map +1 -0
  238. package/dist/{lineWriter.d.ts → shared/lineWriter.d.ts} +1 -1
  239. package/dist/{lineWriter.js → shared/lineWriter.js} +1 -1
  240. package/dist/shared/lineWriter.js.map +1 -0
  241. package/dist/{observationLog.js.map → shared/observationLog.js.map} +1 -1
  242. package/dist/{paths.d.ts → shared/paths.d.ts} +7 -0
  243. package/dist/{paths.js → shared/paths.js} +9 -0
  244. package/dist/shared/paths.js.map +1 -0
  245. package/dist/shared/permissionMode.d.ts +10 -0
  246. package/dist/shared/permissionMode.js +51 -0
  247. package/dist/shared/permissionMode.js.map +1 -0
  248. package/dist/shared/skillInjection.d.ts +9 -0
  249. package/dist/shared/skillInjection.js +16 -0
  250. package/dist/shared/skillInjection.js.map +1 -0
  251. package/dist/shared/sleep.js.map +1 -0
  252. package/dist/{socketPath.d.ts → shared/socketPath.d.ts} +4 -0
  253. package/dist/{socketPath.js → shared/socketPath.js} +22 -0
  254. package/dist/shared/socketPath.js.map +1 -0
  255. package/dist/shared/version.js.map +1 -0
  256. package/package.json +13 -7
  257. package/dist/apnsConfigStore.js.map +0 -1
  258. package/dist/apnsJwtProvider.js.map +0 -1
  259. package/dist/approvalPushNotifier.js.map +0 -1
  260. package/dist/broker.js.map +0 -1
  261. package/dist/chatTailController.js.map +0 -1
  262. package/dist/claudeSessionStore.d.ts +0 -15
  263. package/dist/claudeSessionStore.js +0 -201
  264. package/dist/claudeSessionStore.js.map +0 -1
  265. package/dist/codexRolloutTailer.d.ts +0 -56
  266. package/dist/codexRolloutTailer.js +0 -303
  267. package/dist/codexRolloutTailer.js.map +0 -1
  268. package/dist/codexSessionStore.js.map +0 -1
  269. package/dist/codexUsage.js.map +0 -1
  270. package/dist/deviceTokenStore.js.map +0 -1
  271. package/dist/dirLister.js +0 -98
  272. package/dist/dirLister.js.map +0 -1
  273. package/dist/doctor.d.ts +0 -36
  274. package/dist/doctor.js +0 -162
  275. package/dist/doctor.js.map +0 -1
  276. package/dist/engine.d.ts +0 -85
  277. package/dist/engine.js +0 -962
  278. package/dist/engine.js.map +0 -1
  279. package/dist/hook.js.map +0 -1
  280. package/dist/hookSettings.js.map +0 -1
  281. package/dist/idleReaper.d.ts +0 -13
  282. package/dist/idleReaper.js +0 -30
  283. package/dist/idleReaper.js.map +0 -1
  284. package/dist/imageService.js.map +0 -1
  285. package/dist/kick.js.map +0 -1
  286. package/dist/launch.js +0 -396
  287. package/dist/launch.js.map +0 -1
  288. package/dist/legacyHomeMigration.js.map +0 -1
  289. package/dist/lineWriter.js.map +0 -1
  290. package/dist/mdnsAdvertiser.d.ts +0 -46
  291. package/dist/mdnsAdvertiser.js +0 -268
  292. package/dist/mdnsAdvertiser.js.map +0 -1
  293. package/dist/pairingCode.js.map +0 -1
  294. package/dist/paths.js.map +0 -1
  295. package/dist/permissionMode.d.ts +0 -8
  296. package/dist/permissionMode.js +0 -32
  297. package/dist/permissionMode.js.map +0 -1
  298. package/dist/planUsageFetcher.d.ts +0 -35
  299. package/dist/planUsageFetcher.js +0 -172
  300. package/dist/planUsageFetcher.js.map +0 -1
  301. package/dist/pushTokenCommand.js.map +0 -1
  302. package/dist/pushTypes.js.map +0 -1
  303. package/dist/sendLog.js.map +0 -1
  304. package/dist/sessionActivityProvider.d.ts +0 -7
  305. package/dist/sessionActivityProvider.js +0 -44
  306. package/dist/sessionActivityProvider.js.map +0 -1
  307. package/dist/sessionIdleTracker.d.ts +0 -19
  308. package/dist/sessionIdleTracker.js +0 -42
  309. package/dist/sessionIdleTracker.js.map +0 -1
  310. package/dist/sessionListService.js.map +0 -1
  311. package/dist/sessionMetadataStore.js.map +0 -1
  312. package/dist/sessionSearch.js.map +0 -1
  313. package/dist/setup.js.map +0 -1
  314. package/dist/sleep.js.map +0 -1
  315. package/dist/socketPath.js.map +0 -1
  316. package/dist/subagentTailer.d.ts +0 -15
  317. package/dist/subagentTailer.js +0 -399
  318. package/dist/subagentTailer.js.map +0 -1
  319. package/dist/tmux.d.ts +0 -62
  320. package/dist/tmux.js +0 -163
  321. package/dist/tmux.js.map +0 -1
  322. package/dist/transcriptTailer.js.map +0 -1
  323. package/dist/usageAggregator.js.map +0 -1
  324. package/dist/version.js.map +0 -1
  325. /package/dist/{kick.d.ts → commands/kick.d.ts} +0 -0
  326. /package/dist/{legacyHomeMigration.d.ts → commands/legacyHomeMigration.d.ts} +0 -0
  327. /package/dist/{legacyHomeMigration.js → commands/legacyHomeMigration.js} +0 -0
  328. /package/dist/{apnsConfigStore.d.ts → push/apnsConfigStore.d.ts} +0 -0
  329. /package/dist/{apnsConfigStore.js → push/apnsConfigStore.js} +0 -0
  330. /package/dist/{apnsJwtProvider.d.ts → push/apnsJwtProvider.d.ts} +0 -0
  331. /package/dist/{apnsJwtProvider.js → push/apnsJwtProvider.js} +0 -0
  332. /package/dist/{apnsSender.d.ts → push/apnsSender.d.ts} +0 -0
  333. /package/dist/{apnsSender.js → push/apnsSender.js} +0 -0
  334. /package/dist/{approvalPushNotifier.d.ts → push/approvalPushNotifier.d.ts} +0 -0
  335. /package/dist/{deviceTokenStore.d.ts → push/deviceTokenStore.d.ts} +0 -0
  336. /package/dist/{deviceTokenStore.js → push/deviceTokenStore.js} +0 -0
  337. /package/dist/{pushTypes.d.ts → push/pushTypes.d.ts} +0 -0
  338. /package/dist/{sendLog.d.ts → push/sendLog.d.ts} +0 -0
  339. /package/dist/{sendLog.js → push/sendLog.js} +0 -0
  340. /package/dist/{usageAggregator.d.ts → services/usageAggregator.d.ts} +0 -0
  341. /package/dist/{usageAggregator.js → services/usageAggregator.js} +0 -0
  342. /package/dist/{sessionSearch.js → sessions/sessionSearch.js} +0 -0
  343. /package/dist/{observationLog.d.ts → shared/observationLog.d.ts} +0 -0
  344. /package/dist/{observationLog.js → shared/observationLog.js} +0 -0
  345. /package/dist/{sleep.d.ts → shared/sleep.d.ts} +0 -0
  346. /package/dist/{sleep.js → shared/sleep.js} +0 -0
  347. /package/dist/{version.d.ts → shared/version.d.ts} +0 -0
  348. /package/dist/{version.js → shared/version.js} +0 -0
@@ -0,0 +1,233 @@
1
+ // previewServer.ts
2
+ // tailii (TS host) — Web プレビュー用の loopback 静的ファイルサーバー。
3
+ //
4
+ // iOS の Web プレビューは既存 SSH 接続内の direct-tcpip トンネルで Mac の
5
+ // 127.0.0.1 へ到達する。dev サーバーはそのままトンネルで開けるが、
6
+ // ディスク上の HTML ファイルには配信元が必要なため、このサーバーが
7
+ // 「対象ファイルのディレクトリ」を root として loopback のみで配信する。
8
+ // ネットワークへは一切公開しない(bind は 127.0.0.1 固定)。
9
+ // URL には 128bit ランダムトークンのパス接頭辞を必須にする。
10
+ import { randomBytes } from "node:crypto";
11
+ import { createReadStream } from "node:fs";
12
+ import { stat } from "node:fs/promises";
13
+ import http from "node:http";
14
+ import path from "node:path";
15
+ /** open が失敗したときの型付きエラー。message はそのまま preview_error に載る。 */
16
+ export class PreviewError extends Error {
17
+ reason;
18
+ constructor(reason, detail) {
19
+ super(`${reason}: ${detail}`);
20
+ this.reason = reason;
21
+ this.name = "PreviewError";
22
+ }
23
+ }
24
+ const MIME_TYPES = {
25
+ ".html": "text/html; charset=utf-8",
26
+ ".htm": "text/html; charset=utf-8",
27
+ ".css": "text/css; charset=utf-8",
28
+ ".js": "text/javascript; charset=utf-8",
29
+ ".mjs": "text/javascript; charset=utf-8",
30
+ ".json": "application/json; charset=utf-8",
31
+ ".txt": "text/plain; charset=utf-8",
32
+ ".svg": "image/svg+xml",
33
+ ".png": "image/png",
34
+ ".jpg": "image/jpeg",
35
+ ".jpeg": "image/jpeg",
36
+ ".gif": "image/gif",
37
+ ".webp": "image/webp",
38
+ ".ico": "image/x-icon",
39
+ ".woff": "font/woff",
40
+ ".woff2": "font/woff2",
41
+ ".ttf": "font/ttf",
42
+ ".otf": "font/otf",
43
+ ".mp4": "video/mp4",
44
+ ".webm": "video/webm",
45
+ ".mp3": "audio/mpeg",
46
+ ".wav": "audio/wav",
47
+ ".map": "application/json; charset=utf-8",
48
+ ".wasm": "application/wasm",
49
+ };
50
+ const BIND_HOST = "127.0.0.1";
51
+ /** トークン cookie の名前接頭辞(`tailii_t_<token>=1`)。複数 site が同居しても衝突しない。 */
52
+ const COOKIE_PREFIX = "tailii_t_";
53
+ /**
54
+ * `.html/.htm` の絶対パスを受け取り、そのディレクトリを root に配信する
55
+ * loopback 静的サーバー群を管理する。同一ファイルの再 open はリスナーを
56
+ * 再利用し、`close(id)` で参照が尽きたら teardown する。
57
+ */
58
+ export class PreviewServer {
59
+ /** normalized file path → site */
60
+ sites = new Map();
61
+ /** preview 要求 id → normalized file path */
62
+ idToKey = new Map();
63
+ /** target(.html/.htm 絶対パス)の配信を開始し、到達 URL を返す。 */
64
+ async open(id, target) {
65
+ const key = this.validateTarget(target);
66
+ await this.requireReadableFile(key);
67
+ const existing = this.sites.get(key);
68
+ if (existing) {
69
+ existing.ids.add(id);
70
+ this.idToKey.set(id, key);
71
+ return { url: existing.url };
72
+ }
73
+ const rootDir = path.dirname(key);
74
+ const token = randomBytes(16).toString("hex");
75
+ const server = http.createServer((req, res) => {
76
+ void this.handleRequest(rootDir, token, req, res);
77
+ });
78
+ const sockets = new Set();
79
+ server.on("connection", (socket) => {
80
+ sockets.add(socket);
81
+ socket.on("close", () => sockets.delete(socket));
82
+ });
83
+ const port = await new Promise((resolve, reject) => {
84
+ server.once("error", reject);
85
+ server.listen(0, BIND_HOST, () => {
86
+ const address = server.address();
87
+ if (address === null || typeof address === "string") {
88
+ reject(new Error("listen address unavailable"));
89
+ return;
90
+ }
91
+ resolve(address.port);
92
+ });
93
+ });
94
+ const url = `http://${BIND_HOST}:${port}/t/${token}/${encodeURIComponent(path.basename(key))}`;
95
+ const site = { server, url, ids: new Set([id]), sockets };
96
+ this.sites.set(key, site);
97
+ this.idToKey.set(id, key);
98
+ return { url };
99
+ }
100
+ /** id の参照を外し、最後の参照ならサーバーを畳む。未知 id は no-op。 */
101
+ async close(id) {
102
+ const key = this.idToKey.get(id);
103
+ if (key === undefined)
104
+ return;
105
+ this.idToKey.delete(id);
106
+ const site = this.sites.get(key);
107
+ if (site === undefined)
108
+ return;
109
+ site.ids.delete(id);
110
+ if (site.ids.size > 0)
111
+ return;
112
+ this.sites.delete(key);
113
+ await PreviewServer.shutdown(site);
114
+ }
115
+ /** 全サーバーを畳む(engine 終了時)。冪等。 */
116
+ async closeAll() {
117
+ const sites = [...this.sites.values()];
118
+ this.sites.clear();
119
+ this.idToKey.clear();
120
+ await Promise.all(sites.map((site) => PreviewServer.shutdown(site)));
121
+ }
122
+ validateTarget(target) {
123
+ const normalized = path.normalize(target);
124
+ if (!path.isAbsolute(normalized)) {
125
+ throw new PreviewError("invalid-target", `絶対パスではない: ${target}`);
126
+ }
127
+ const ext = path.extname(normalized).toLowerCase();
128
+ if (ext !== ".html" && ext !== ".htm") {
129
+ throw new PreviewError("invalid-target", `.html/.htm ではない: ${target}`);
130
+ }
131
+ return normalized;
132
+ }
133
+ async requireReadableFile(filePath) {
134
+ try {
135
+ const info = await stat(filePath);
136
+ if (!info.isFile())
137
+ throw new PreviewError("not-found", filePath);
138
+ }
139
+ catch (error) {
140
+ if (error instanceof PreviewError)
141
+ throw error;
142
+ throw new PreviewError("not-found", filePath);
143
+ }
144
+ }
145
+ async handleRequest(rootDir, token, req, res) {
146
+ try {
147
+ const rawPath = (req.url ?? "/").split("?")[0] ?? "/";
148
+ const prefix = `/t/${token}/`;
149
+ if (rawPath.startsWith(prefix)) {
150
+ // トークン付きパス: HTML のディレクトリ配下を配信する(相対参照の解決)。
151
+ let decodedRel;
152
+ try {
153
+ decodedRel = decodeURIComponent(rawPath.slice(prefix.length));
154
+ }
155
+ catch {
156
+ res.writeHead(400).end();
157
+ return;
158
+ }
159
+ const resolved = path.resolve(rootDir, decodedRel);
160
+ if (resolved !== rootDir && !resolved.startsWith(rootDir + path.sep)) {
161
+ res.writeHead(403).end();
162
+ return;
163
+ }
164
+ // トークンを cookie にも載せる。HTML 内の**絶対パス参照**(<img src="/Users/..."> 等)は
165
+ // トークン接頭辞を持たない URL になるため、後続要求はこの cookie で認可する。
166
+ await PreviewServer.serveFile(resolved, res, {
167
+ "set-cookie": `${COOKIE_PREFIX}${token}=1; Path=/; SameSite=Lax`,
168
+ });
169
+ return;
170
+ }
171
+ if (PreviewServer.hasTokenCookie(req, token)) {
172
+ // 有効な cookie 持ちの絶対パス要求: HTML 内の絶対参照を解決する。
173
+ // 認可主体はトークン保持者=SSH トンネル越しの本人のみ(cookie は最初の
174
+ // トークン付き応答でしか配られない)。root 制限は課さない(本人の Mac の
175
+ // 本人が読めるファイルであり、エージェント生成 HTML は uploads 等
176
+ // ディレクトリ外の絶対パスを普通に参照するため)。
177
+ let decoded;
178
+ try {
179
+ decoded = decodeURIComponent(rawPath);
180
+ }
181
+ catch {
182
+ res.writeHead(400).end();
183
+ return;
184
+ }
185
+ const resolved = path.normalize(decoded);
186
+ if (!path.isAbsolute(resolved)) {
187
+ res.writeHead(404).end();
188
+ return;
189
+ }
190
+ await PreviewServer.serveFile(resolved, res);
191
+ return;
192
+ }
193
+ res.writeHead(404).end();
194
+ }
195
+ catch {
196
+ if (!res.headersSent)
197
+ res.writeHead(500);
198
+ res.end();
199
+ }
200
+ }
201
+ /** ファイル 1 件を MIME 付きで応答する(ディレクトリは index.html へフォールバック)。 */
202
+ static async serveFile(requestedPath, res, extraHeaders = {}) {
203
+ let filePath = requestedPath;
204
+ let info = await stat(filePath).catch(() => null);
205
+ if (info?.isDirectory()) {
206
+ filePath = path.join(filePath, "index.html");
207
+ info = await stat(filePath).catch(() => null);
208
+ }
209
+ if (info === null || !info.isFile()) {
210
+ res.writeHead(404).end();
211
+ return;
212
+ }
213
+ const mime = MIME_TYPES[path.extname(filePath).toLowerCase()] ?? "application/octet-stream";
214
+ res.writeHead(200, { "content-type": mime, "content-length": info.size, ...extraHeaders });
215
+ const stream = createReadStream(filePath);
216
+ stream.on("error", () => res.destroy());
217
+ stream.pipe(res);
218
+ }
219
+ static hasTokenCookie(req, token) {
220
+ const header = req.headers.cookie;
221
+ if (header === undefined)
222
+ return false;
223
+ return header
224
+ .split(";")
225
+ .some((part) => part.trim().startsWith(`${COOKIE_PREFIX}${token}=`));
226
+ }
227
+ static async shutdown(site) {
228
+ for (const socket of site.sockets)
229
+ socket.destroy();
230
+ await new Promise((resolve) => site.server.close(() => resolve()));
231
+ }
232
+ }
233
+ //# sourceMappingURL=previewServer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"previewServer.js","sourceRoot":"","sources":["../../src/services/previewServer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,143 @@
1
+ /** launchd ジョブのラベル(plist ファイル名と対)。 */
2
+ export declare const QUIC_GW_LAUNCHD_LABEL = "com.tailii.quic-gw";
3
+ /** ゲートウェイの既定 UDP ポート(凍結定数、Rust 側 DEFAULT_PORT と一致)。 */
4
+ export declare const QUIC_GW_DEFAULT_PORT = 46853;
5
+ /** `tailii-quic-gw credentials --json` の出力。 */
6
+ export interface QuicCredentials {
7
+ dir: string;
8
+ /** SPKI SHA-256(base64)。iOS がピン検証に使う(payload v3 の quicPin)。 */
9
+ spkiPin: string;
10
+ /** 証明書 DER SHA-256(base64)。Rust 自己検証クライアント用。 */
11
+ certPin: string;
12
+ /** 32byte トークン(base64、payload v3 の quicToken)。 */
13
+ token: string;
14
+ port: number;
15
+ }
16
+ /** 資格情報ディレクトリ(Rust 側 default_credentials_dir と対)。 */
17
+ export declare function quicCredentialsDir(): string;
18
+ /** ゲートウェイの監査ログパス(launchd が stdout/stderr をここへ向ける)。 */
19
+ export declare function quicGatewayLogPath(): string;
20
+ /**
21
+ * launchd が起動する gateway バイナリの設置先(`~/.tailii/bin/tailii-quic-gw`)。
22
+ *
23
+ * 重要(実機で判明した罠): launchd の LaunchAgent は `~/Documents` `~/Desktop`
24
+ * `~/Downloads` 等の **TCC 保護フォルダにアクセスできない**。ビルド成果物や npm 配布物が
25
+ * そうした場所にあると、launchd 起動時に dyld がバイナリを map できず **dyld 段階で無限
26
+ * ストール**する(プロセスは生存するが bind に到達せず、ログも出ない)。Terminal 起動は
27
+ * ユーザーの TCC 付与を継承するため成功し、差分に気付きにくい。回避のため、常駐用バイナリは
28
+ * 必ず非 TCC 保護の隠しディレクトリ `~/.tailii/bin` へコピーしてから launchd に渡す。
29
+ */
30
+ export declare function quicGatewayInstalledBinaryPath(): string;
31
+ /**
32
+ * gateway バイナリを非 TCC 保護の `~/.tailii/bin` へコピーして、その設置先パスを返す。
33
+ * 内容が同一なら再コピーしない(mtime/サイズで判定)。常に実行ビットを立てる。
34
+ */
35
+ export declare function installQuicGatewayBinary(sourcePath: string): string;
36
+ /** LaunchAgent plist の設置先。 */
37
+ export declare function quicLaunchAgentPlistPath(): string;
38
+ /**
39
+ * ゲートウェイバイナリを解決する。見つからなければ null(QUIC は任意機能なので
40
+ * 呼び出し側は SSH-only で継続してよい)。
41
+ *
42
+ * 解決順:
43
+ * 1. 環境変数 `TAILII_QUIC_GW`(明示上書き)
44
+ * 2. npm prebuilt(optionalDependencies `@tailii/quic-gw-darwin-{arm64,x64}`)
45
+ * 3. モノレポのローカル cargo ビルド(quic-gw/target/release/tailii-quic-gw)
46
+ * 4. PATH
47
+ */
48
+ export declare function resolveQuicGatewayBinary(env?: NodeJS.ProcessEnv): string | null;
49
+ /** コマンド実行子(テスト注入用)。stdout を返し、失敗は reject。 */
50
+ export type CommandRunner = (file: string, args: string[]) => Promise<string>;
51
+ /**
52
+ * 資格情報を生成(既存なら読込・冪等)して返す。
53
+ * 実体は `tailii-quic-gw credentials --json --dir <dir>`。
54
+ */
55
+ export declare function ensureQuicCredentials(gatewayPath: string, dir?: string, runner?: CommandRunner): Promise<QuicCredentials>;
56
+ /** `quicLaunchAgentPlist` に渡す解決済み絶対パス群。 */
57
+ export interface QuicLaunchAgentConfig {
58
+ gatewayPath: string;
59
+ logPath: string;
60
+ /** 資格情報ディレクトリ(絶対パス)。`--dir` に明示的に渡す。 */
61
+ credentialsDir: string;
62
+ /** exec 子プロセスへ注入する PATH(launch.ts の defaultInjectedPath と同一)。 */
63
+ injectedPath: string;
64
+ /** ユーザーの HOME 絶対パス(EnvironmentVariables に設定)。 */
65
+ home: string;
66
+ }
67
+ /**
68
+ * LaunchAgent plist の内容(KeepAlive 常駐・監査ログは stdout/stderr リダイレクト)。
69
+ *
70
+ * 重要(実機で判明した罠): macOS の GUI LaunchAgent は **HOME を継承しない**。
71
+ * ゲートウェイは `~/.tailii/quic` の展開・`default_injected_path` の両方で HOME を読むため、
72
+ * HOME 空だと資格情報ディレクトリが `/.tailii/quic` に化けて `create_dir_all` が失敗し、
73
+ * serve が即終了 → KeepAlive 再起動ループに陥る。対策として:
74
+ * 1. `EnvironmentVariables` に HOME を明示(gateway 本体 + exec 子プロセス双方に効く)。
75
+ * 2. `--dir` / `--path` を **絶対パスで明示的に渡し**、HOME 展開へ依存しない(防御多重化)。
76
+ */
77
+ export declare function quicLaunchAgentPlist(config: QuicLaunchAgentConfig): string;
78
+ /** launchctl 実行子(テスト注入用)。exit 0 で resolve、非 0 は reject。 */
79
+ export type LaunchctlRunner = (args: string[]) => Promise<void>;
80
+ export interface InstallLaunchAgentOptions {
81
+ /** 解決済み gateway バイナリ(ビルド/配布物の場所。TCC 保護下でも可)。 */
82
+ gatewayPath: string;
83
+ plistPath?: string;
84
+ logPath?: string;
85
+ /** 資格情報ディレクトリ(絶対パス)。省略時 `quicCredentialsDir()`。 */
86
+ credentialsDir?: string;
87
+ /** exec 子プロセスの PATH。省略時 `defaultInjectedPath()`。 */
88
+ injectedPath?: string;
89
+ /** HOME 絶対パス。省略時 `os.homedir()`。 */
90
+ home?: string;
91
+ /**
92
+ * launchd が実際に起動するバイナリパス(`gatewayPath` からのコピー先)。
93
+ * 省略時 `~/.tailii/bin/tailii-quic-gw` へコピーする(TCC 回避)。テストで無効化可。
94
+ */
95
+ installBinary?: (gatewayPath: string) => string;
96
+ uid?: number;
97
+ launchctl?: LaunchctlRunner;
98
+ }
99
+ /**
100
+ * LaunchAgent を設置して(再)起動する(冪等)。
101
+ * 既存ジョブは bootout してから bootstrap し、plist 更新を確実に反映する。
102
+ *
103
+ * gateway バイナリは非 TCC 保護の `~/.tailii/bin` へコピーしてから launchd に渡す
104
+ * (`installQuicGatewayBinary` 参照。TCC 保護フォルダ由来の dyld ストール回避)。
105
+ */
106
+ export declare function installQuicLaunchAgent(options: InstallLaunchAgentOptions): Promise<void>;
107
+ /** launchd ジョブが常駐しているか(doctor / quic-info 用・副作用なし)。 */
108
+ export declare function isQuicGatewayLoaded(uid?: number, launchctl?: LaunchctlRunner): Promise<boolean>;
109
+ /**
110
+ * `tailii-host quic-info` の応答形状。iOS `QUICCredentialCache.parse` と契約整合。
111
+ * mosh の「SSH で鍵を配って以後 UDP」と同じ構図 — SSH(認証済み暗号路)経由で
112
+ * QUIC の接続情報を配布し、iOS が Keychain にキャッシュして次回以降 QUIC 先行する。
113
+ * これにより payload v3 の QR 再ペアリング無しで既存端末が QUIC 化できる。
114
+ */
115
+ export interface QuicInfoResult {
116
+ available: boolean;
117
+ /** available=false の理由(診断用。iOS は available だけ見る)。 */
118
+ reason?: string;
119
+ port?: number;
120
+ pin?: string;
121
+ token?: string;
122
+ }
123
+ /**
124
+ * 証明書 PEM から SPKI SHA-256 ピン(base64)を計算する。
125
+ * Rust 側 `Credentials::spki_pin()`(rcgen public_key_der のハッシュ)と同一値になる
126
+ * (X.509 の SubjectPublicKeyInfo DER は同一バイト列のため)。
127
+ */
128
+ export declare function computeSpkiPinFromCertPem(certPem: string): string;
129
+ /**
130
+ * ディスク上の資格情報(cert.pem / token)から quic-info の中身を読む。
131
+ * ゲートウェイバイナリには依存しない(生成は setup / Rust 側の責務。ここは読むだけ)。
132
+ */
133
+ export declare function readQuicCredentialsFromDisk(dir?: string): {
134
+ pin: string;
135
+ token: string;
136
+ } | null;
137
+ /** quic-info の本体(テスト注入可能な純ロジック)。 */
138
+ export declare function collectQuicInfo(options?: {
139
+ dir?: string;
140
+ isLoaded?: () => Promise<boolean>;
141
+ }): Promise<QuicInfoResult>;
142
+ /** `tailii-host quic-info` エントリポイント。stdout に JSON 1 行を出す(常に exit 0)。 */
143
+ export declare function runQuicInfoCommand(_argv: string[]): Promise<number>;