@greppleai/grip 0.1.4 → 0.1.6

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 (569) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/README.md +2 -2
  3. package/dist/bun/cli.d.ts.map +1 -1
  4. package/dist/bun/cli.js.map +1 -1
  5. package/dist/bun/embedded-assets.d.ts.map +1 -1
  6. package/dist/bun/embedded-assets.js.map +1 -1
  7. package/dist/bun/register-bedrock.d.ts.map +1 -1
  8. package/dist/bun/restore-sandbox-env.d.ts.map +1 -1
  9. package/dist/bun/restore-sandbox-env.js.map +1 -1
  10. package/dist/cli/args.d.ts.map +1 -1
  11. package/dist/cli/args.js.map +1 -1
  12. package/dist/cli/config-selector.d.ts.map +1 -1
  13. package/dist/cli/config-selector.js.map +1 -1
  14. package/dist/cli/file-processor.d.ts.map +1 -1
  15. package/dist/cli/file-processor.js.map +1 -1
  16. package/dist/cli/initial-message.d.ts +1 -1
  17. package/dist/cli/initial-message.d.ts.map +1 -1
  18. package/dist/cli/initial-message.js.map +1 -1
  19. package/dist/cli/list-models.d.ts.map +1 -1
  20. package/dist/cli/list-models.js.map +1 -1
  21. package/dist/cli/session-picker.d.ts.map +1 -1
  22. package/dist/cli/session-picker.js.map +1 -1
  23. package/dist/cli.d.ts.map +1 -1
  24. package/dist/cli.js.map +1 -1
  25. package/dist/config.d.ts.map +1 -1
  26. package/dist/config.js.map +1 -1
  27. package/dist/core/agent-session.d.ts +27 -0
  28. package/dist/core/agent-session.d.ts.map +1 -1
  29. package/dist/core/agent-session.js +117 -152
  30. package/dist/core/agent-session.js.map +1 -1
  31. package/dist/core/auth-guidance.d.ts.map +1 -1
  32. package/dist/core/auth-guidance.js.map +1 -1
  33. package/dist/core/auth-storage.d.ts +4 -0
  34. package/dist/core/auth-storage.d.ts.map +1 -1
  35. package/dist/core/auth-storage.js +6 -11
  36. package/dist/core/auth-storage.js.map +1 -1
  37. package/dist/core/bash-executor.d.ts.map +1 -1
  38. package/dist/core/bash-executor.js +19 -23
  39. package/dist/core/bash-executor.js.map +1 -1
  40. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  41. package/dist/core/compaction/branch-summarization.js.map +1 -1
  42. package/dist/core/compaction/compaction.d.ts.map +1 -1
  43. package/dist/core/compaction/compaction.js.map +1 -1
  44. package/dist/core/compaction/compression-detection-ledger.d.ts.map +1 -1
  45. package/dist/core/compaction/compression-detection-ledger.js.map +1 -1
  46. package/dist/core/compaction/compression-detector.d.ts +1 -0
  47. package/dist/core/compaction/compression-detector.d.ts.map +1 -1
  48. package/dist/core/compaction/compression-detector.js +10 -21
  49. package/dist/core/compaction/compression-detector.js.map +1 -1
  50. package/dist/core/compaction/compression-economics.d.ts.map +1 -1
  51. package/dist/core/compaction/compression-economics.js.map +1 -1
  52. package/dist/core/compaction/utils.d.ts.map +1 -1
  53. package/dist/core/compaction/utils.js.map +1 -1
  54. package/dist/core/defaults.d.ts.map +1 -1
  55. package/dist/core/diagnostics.d.ts.map +1 -1
  56. package/dist/core/event-bus.d.ts.map +1 -1
  57. package/dist/core/event-bus.js.map +1 -1
  58. package/dist/core/exec.d.ts.map +1 -1
  59. package/dist/core/exec.js.map +1 -1
  60. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  61. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  62. package/dist/core/export-html/index.d.ts.map +1 -1
  63. package/dist/core/export-html/index.js.map +1 -1
  64. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  65. package/dist/core/export-html/tool-renderer.js.map +1 -1
  66. package/dist/core/extensions/loader.d.ts.map +1 -1
  67. package/dist/core/extensions/loader.js.map +1 -1
  68. package/dist/core/extensions/runner.d.ts.map +1 -1
  69. package/dist/core/extensions/runner.js +18 -30
  70. package/dist/core/extensions/runner.js.map +1 -1
  71. package/dist/core/extensions/types.d.ts.map +1 -1
  72. package/dist/core/extensions/types.js.map +1 -1
  73. package/dist/core/extensions/wrapper.d.ts.map +1 -1
  74. package/dist/core/extensions/wrapper.js.map +1 -1
  75. package/dist/core/footer-data-provider.d.ts.map +1 -1
  76. package/dist/core/footer-data-provider.js +15 -16
  77. package/dist/core/footer-data-provider.js.map +1 -1
  78. package/dist/core/grip-agent.d.ts.map +1 -1
  79. package/dist/core/grip-agent.js +11 -23
  80. package/dist/core/grip-agent.js.map +1 -1
  81. package/dist/core/grip-manifest.d.ts.map +1 -1
  82. package/dist/core/grip-manifest.js.map +1 -1
  83. package/dist/core/hooks/aggregate.d.ts.map +1 -1
  84. package/dist/core/hooks/aggregate.js.map +1 -1
  85. package/dist/core/hooks/config.d.ts.map +1 -1
  86. package/dist/core/hooks/config.js.map +1 -1
  87. package/dist/core/hooks/executor.d.ts.map +1 -1
  88. package/dist/core/hooks/executor.js.map +1 -1
  89. package/dist/core/hooks/index.d.ts.map +1 -1
  90. package/dist/core/hooks/index.js.map +1 -1
  91. package/dist/core/hooks/matcher.d.ts.map +1 -1
  92. package/dist/core/hooks/matcher.js.map +1 -1
  93. package/dist/core/hooks/trust-store.d.ts.map +1 -1
  94. package/dist/core/hooks/trust-store.js +0 -3
  95. package/dist/core/hooks/trust-store.js.map +1 -1
  96. package/dist/core/hooks/types.d.ts.map +1 -1
  97. package/dist/core/hooks/types.js.map +1 -1
  98. package/dist/core/http-dispatcher.d.ts.map +1 -1
  99. package/dist/core/http-dispatcher.js.map +1 -1
  100. package/dist/core/instruction-resource-loader.d.ts.map +1 -1
  101. package/dist/core/instruction-resource-loader.js +0 -3
  102. package/dist/core/instruction-resource-loader.js.map +1 -1
  103. package/dist/core/keybindings.d.ts.map +1 -1
  104. package/dist/core/keybindings.js +0 -1
  105. package/dist/core/keybindings.js.map +1 -1
  106. package/dist/core/lsp/abort.d.ts.map +1 -1
  107. package/dist/core/lsp/abort.js.map +1 -1
  108. package/dist/core/lsp/client.d.ts.map +1 -1
  109. package/dist/core/lsp/client.js +8 -22
  110. package/dist/core/lsp/client.js.map +1 -1
  111. package/dist/core/lsp/config-loader.d.ts.map +1 -1
  112. package/dist/core/lsp/config-loader.js.map +1 -1
  113. package/dist/core/lsp/config.d.ts.map +1 -1
  114. package/dist/core/lsp/config.js.map +1 -1
  115. package/dist/core/lsp/diagnostics.d.ts.map +1 -1
  116. package/dist/core/lsp/diagnostics.js.map +1 -1
  117. package/dist/core/lsp/file-sync.d.ts.map +1 -1
  118. package/dist/core/lsp/file-sync.js +7 -9
  119. package/dist/core/lsp/file-sync.js.map +1 -1
  120. package/dist/core/lsp/integration.d.ts.map +1 -1
  121. package/dist/core/lsp/integration.js.map +1 -1
  122. package/dist/core/lsp/language-map.d.ts.map +1 -1
  123. package/dist/core/lsp/language-map.js +2 -7
  124. package/dist/core/lsp/language-map.js.map +1 -1
  125. package/dist/core/lsp/manager.d.ts.map +1 -1
  126. package/dist/core/lsp/manager.js +18 -29
  127. package/dist/core/lsp/manager.js.map +1 -1
  128. package/dist/core/lsp/navigation.d.ts.map +1 -1
  129. package/dist/core/lsp/navigation.js.map +1 -1
  130. package/dist/core/lsp/portable-path.d.ts.map +1 -1
  131. package/dist/core/lsp/portable-path.js.map +1 -1
  132. package/dist/core/lsp/refactor.d.ts.map +1 -1
  133. package/dist/core/lsp/refactor.js.map +1 -1
  134. package/dist/core/lsp/transport.d.ts.map +1 -1
  135. package/dist/core/lsp/transport.js.map +1 -1
  136. package/dist/core/messages.d.ts.map +1 -1
  137. package/dist/core/messages.js.map +1 -1
  138. package/dist/core/model-registry.d.ts.map +1 -1
  139. package/dist/core/model-registry.js +5 -7
  140. package/dist/core/model-registry.js.map +1 -1
  141. package/dist/core/model-resolver.d.ts.map +1 -1
  142. package/dist/core/model-resolver.js.map +1 -1
  143. package/dist/core/output-guard.d.ts.map +1 -1
  144. package/dist/core/output-guard.js.map +1 -1
  145. package/dist/core/package-manager.d.ts.map +1 -1
  146. package/dist/core/package-manager.js +0 -6
  147. package/dist/core/package-manager.js.map +1 -1
  148. package/dist/core/prompt-templates.d.ts.map +1 -1
  149. package/dist/core/prompt-templates.js.map +1 -1
  150. package/dist/core/provider-display-names.d.ts.map +1 -1
  151. package/dist/core/remote-workspace-protocol/contract.d.ts.map +1 -1
  152. package/dist/core/remote-workspace-protocol/contract.js +4 -2
  153. package/dist/core/remote-workspace-protocol/contract.js.map +1 -1
  154. package/dist/core/remote-workspace-protocol/guest-shared-client.d.ts.map +1 -1
  155. package/dist/core/remote-workspace-protocol/guest-shared-client.js +1 -5
  156. package/dist/core/remote-workspace-protocol/guest-shared-client.js.map +1 -1
  157. package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.d.ts.map +1 -1
  158. package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.js +5 -10
  159. package/dist/core/remote-workspace-protocol/guest-shared-outbound-scheduler.js.map +1 -1
  160. package/dist/core/remote-workspace-protocol/guest-shared-uplink.d.ts.map +1 -1
  161. package/dist/core/remote-workspace-protocol/guest-shared-uplink.js +2 -9
  162. package/dist/core/remote-workspace-protocol/guest-shared-uplink.js.map +1 -1
  163. package/dist/core/remote-workspace-protocol/lima-owner-directory.d.ts.map +1 -1
  164. package/dist/core/remote-workspace-protocol/lima-owner-directory.js.map +1 -1
  165. package/dist/core/remote-workspace-protocol/lima-owner-lock.d.ts.map +1 -1
  166. package/dist/core/remote-workspace-protocol/lima-owner-lock.js.map +1 -1
  167. package/dist/core/remote-workspace-protocol/session.d.ts.map +1 -1
  168. package/dist/core/remote-workspace-protocol/session.js +27 -65
  169. package/dist/core/remote-workspace-protocol/session.js.map +1 -1
  170. package/dist/core/remote-workspace-protocol/shared-transport.d.ts.map +1 -1
  171. package/dist/core/remote-workspace-protocol/shared-transport.js.map +1 -1
  172. package/dist/core/resolve-config-value.d.ts.map +1 -1
  173. package/dist/core/resolve-config-value.js.map +1 -1
  174. package/dist/core/resource-loader.d.ts.map +1 -1
  175. package/dist/core/resource-loader.js +0 -48
  176. package/dist/core/resource-loader.js.map +1 -1
  177. package/dist/core/rules.d.ts.map +1 -1
  178. package/dist/core/rules.js.map +1 -1
  179. package/dist/core/sandbox/command.d.ts.map +1 -1
  180. package/dist/core/sandbox/command.js.map +1 -1
  181. package/dist/core/sandbox/config.d.ts.map +1 -1
  182. package/dist/core/sandbox/config.js.map +1 -1
  183. package/dist/core/sandbox/lima-guest-binary.d.ts.map +1 -1
  184. package/dist/core/sandbox/lima-guest-binary.js.map +1 -1
  185. package/dist/core/sandbox/lima.d.ts +2 -0
  186. package/dist/core/sandbox/lima.d.ts.map +1 -1
  187. package/dist/core/sandbox/lima.js +9 -15
  188. package/dist/core/sandbox/lima.js.map +1 -1
  189. package/dist/core/sandbox/shared-lima-roots.d.ts.map +1 -1
  190. package/dist/core/sandbox/shared-lima-roots.js.map +1 -1
  191. package/dist/core/sandbox/update-shared-guest-binary.d.ts.map +1 -1
  192. package/dist/core/sandbox/update-shared-guest-binary.js.map +1 -1
  193. package/dist/core/session/constants.d.ts.map +1 -1
  194. package/dist/core/session/context-metadata.d.ts.map +1 -1
  195. package/dist/core/session/context-metadata.js.map +1 -1
  196. package/dist/core/session/context.d.ts.map +1 -1
  197. package/dist/core/session/context.js.map +1 -1
  198. package/dist/core/session/ids.d.ts.map +1 -1
  199. package/dist/core/session/ids.js.map +1 -1
  200. package/dist/core/session/in-memory-session-manager.d.ts.map +1 -1
  201. package/dist/core/session/in-memory-session-manager.js +0 -1
  202. package/dist/core/session/in-memory-session-manager.js.map +1 -1
  203. package/dist/core/session/in-memory-session.d.ts.map +1 -1
  204. package/dist/core/session/in-memory-session.js.map +1 -1
  205. package/dist/core/session/jsonl-errors.d.ts.map +1 -1
  206. package/dist/core/session/jsonl-errors.js +0 -11
  207. package/dist/core/session/jsonl-errors.js.map +1 -1
  208. package/dist/core/session/jsonl-helpers.d.ts.map +1 -1
  209. package/dist/core/session/jsonl-helpers.js.map +1 -1
  210. package/dist/core/session/local-session-manager.d.ts.map +1 -1
  211. package/dist/core/session/local-session-manager.js +4 -6
  212. package/dist/core/session/local-session-manager.js.map +1 -1
  213. package/dist/core/session/local-session.d.ts.map +1 -1
  214. package/dist/core/session/local-session.js.map +1 -1
  215. package/dist/core/session/migrations.d.ts.map +1 -1
  216. package/dist/core/session/migrations.js.map +1 -1
  217. package/dist/core/session/remote-session-client.d.ts.map +1 -1
  218. package/dist/core/session/remote-session-client.js +0 -6
  219. package/dist/core/session/remote-session-client.js.map +1 -1
  220. package/dist/core/session/remote-session-manager.d.ts.map +1 -1
  221. package/dist/core/session/remote-session-manager.js +0 -3
  222. package/dist/core/session/remote-session-manager.js.map +1 -1
  223. package/dist/core/session/remote-session.d.ts.map +1 -1
  224. package/dist/core/session/remote-session.js +0 -1
  225. package/dist/core/session/remote-session.js.map +1 -1
  226. package/dist/core/session/session-manager.d.ts.map +1 -1
  227. package/dist/core/session/session.d.ts.map +1 -1
  228. package/dist/core/session/session.js +1 -5
  229. package/dist/core/session/session.js.map +1 -1
  230. package/dist/core/session/stores/in-memory-session-store.d.ts.map +1 -1
  231. package/dist/core/session/stores/in-memory-session-store.js +7 -6
  232. package/dist/core/session/stores/in-memory-session-store.js.map +1 -1
  233. package/dist/core/session/stores/jsonl-session-store.d.ts.map +1 -1
  234. package/dist/core/session/stores/jsonl-session-store.js +6 -14
  235. package/dist/core/session/stores/jsonl-session-store.js.map +1 -1
  236. package/dist/core/session/stores/remote-session-store.d.ts.map +1 -1
  237. package/dist/core/session/stores/remote-session-store.js +3 -8
  238. package/dist/core/session/stores/remote-session-store.js.map +1 -1
  239. package/dist/core/session/stores/session-store.d.ts.map +1 -1
  240. package/dist/core/session/types.d.ts.map +1 -1
  241. package/dist/core/session/usage-ledger.d.ts.map +1 -1
  242. package/dist/core/session/usage-ledger.js.map +1 -1
  243. package/dist/core/session-cwd.d.ts.map +1 -1
  244. package/dist/core/session-cwd.js +0 -1
  245. package/dist/core/session-cwd.js.map +1 -1
  246. package/dist/core/settings-manager.d.ts.map +1 -1
  247. package/dist/core/settings-manager.js +9 -17
  248. package/dist/core/settings-manager.js.map +1 -1
  249. package/dist/core/skills.d.ts.map +1 -1
  250. package/dist/core/skills.js.map +1 -1
  251. package/dist/core/slash-commands.d.ts.map +1 -1
  252. package/dist/core/source-info.d.ts.map +1 -1
  253. package/dist/core/source-info.js.map +1 -1
  254. package/dist/core/system-prompt.d.ts.map +1 -1
  255. package/dist/core/system-prompt.js.map +1 -1
  256. package/dist/core/telemetry.d.ts.map +1 -1
  257. package/dist/core/telemetry.js.map +1 -1
  258. package/dist/core/timings.d.ts.map +1 -1
  259. package/dist/core/timings.js.map +1 -1
  260. package/dist/core/tools/bash.d.ts.map +1 -1
  261. package/dist/core/tools/bash.js +8 -5
  262. package/dist/core/tools/bash.js.map +1 -1
  263. package/dist/core/tools/compress-context.d.ts.map +1 -1
  264. package/dist/core/tools/compress-context.js.map +1 -1
  265. package/dist/core/tools/edit-diff.d.ts.map +1 -1
  266. package/dist/core/tools/edit-diff.js.map +1 -1
  267. package/dist/core/tools/edit.d.ts.map +1 -1
  268. package/dist/core/tools/edit.js.map +1 -1
  269. package/dist/core/tools/file-mutation-queue.d.ts.map +1 -1
  270. package/dist/core/tools/file-mutation-queue.js.map +1 -1
  271. package/dist/core/tools/find.d.ts.map +1 -1
  272. package/dist/core/tools/find.js.map +1 -1
  273. package/dist/core/tools/grep.d.ts.map +1 -1
  274. package/dist/core/tools/grep.js.map +1 -1
  275. package/dist/core/tools/hash-store.d.ts.map +1 -1
  276. package/dist/core/tools/hash-store.js.map +1 -1
  277. package/dist/core/tools/hashline/apply.d.ts.map +1 -1
  278. package/dist/core/tools/hashline/apply.js.map +1 -1
  279. package/dist/core/tools/hashline/hash.d.ts.map +1 -1
  280. package/dist/core/tools/hashline/hash.js.map +1 -1
  281. package/dist/core/tools/hashline/parse.d.ts.map +1 -1
  282. package/dist/core/tools/hashline/parse.js.map +1 -1
  283. package/dist/core/tools/hashline/resolve.d.ts.map +1 -1
  284. package/dist/core/tools/hashline/resolve.js.map +1 -1
  285. package/dist/core/tools/hashline-utils.d.ts.map +1 -1
  286. package/dist/core/tools/hashline-utils.js.map +1 -1
  287. package/dist/core/tools/index.d.ts.map +1 -1
  288. package/dist/core/tools/index.js.map +1 -1
  289. package/dist/core/tools/ls.d.ts.map +1 -1
  290. package/dist/core/tools/ls.js.map +1 -1
  291. package/dist/core/tools/operations.d.ts +5 -0
  292. package/dist/core/tools/operations.d.ts.map +1 -1
  293. package/dist/core/tools/operations.js +26 -24
  294. package/dist/core/tools/operations.js.map +1 -1
  295. package/dist/core/tools/output-accumulator.d.ts.map +1 -1
  296. package/dist/core/tools/output-accumulator.js +12 -18
  297. package/dist/core/tools/output-accumulator.js.map +1 -1
  298. package/dist/core/tools/path-utils.d.ts.map +1 -1
  299. package/dist/core/tools/path-utils.js.map +1 -1
  300. package/dist/core/tools/read.d.ts.map +1 -1
  301. package/dist/core/tools/read.js.map +1 -1
  302. package/dist/core/tools/render-utils.d.ts.map +1 -1
  303. package/dist/core/tools/render-utils.js.map +1 -1
  304. package/dist/core/tools/replace-diff.d.ts.map +1 -1
  305. package/dist/core/tools/replace-diff.js.map +1 -1
  306. package/dist/core/tools/replace-normalize.d.ts.map +1 -1
  307. package/dist/core/tools/replace-normalize.js.map +1 -1
  308. package/dist/core/tools/replace-render.d.ts +1 -1
  309. package/dist/core/tools/replace-render.d.ts.map +1 -1
  310. package/dist/core/tools/replace-render.js.map +1 -1
  311. package/dist/core/tools/runtime.d.ts.map +1 -1
  312. package/dist/core/tools/runtime.js.map +1 -1
  313. package/dist/core/tools/session-history.d.ts.map +1 -1
  314. package/dist/core/tools/session-history.js.map +1 -1
  315. package/dist/core/tools/subagent-agents.d.ts.map +1 -1
  316. package/dist/core/tools/subagent-agents.js.map +1 -1
  317. package/dist/core/tools/subagent.d.ts.map +1 -1
  318. package/dist/core/tools/subagent.js.map +1 -1
  319. package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
  320. package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
  321. package/dist/core/tools/truncate.d.ts.map +1 -1
  322. package/dist/core/tools/truncate.js.map +1 -1
  323. package/dist/core/tools/websearch.d.ts.map +1 -1
  324. package/dist/core/tools/websearch.js.map +1 -1
  325. package/dist/core/tools/workspace-tool-host.d.ts +1 -0
  326. package/dist/core/tools/workspace-tool-host.d.ts.map +1 -1
  327. package/dist/core/tools/workspace-tool-host.js +36 -22
  328. package/dist/core/tools/workspace-tool-host.js.map +1 -1
  329. package/dist/core/tools/write.d.ts.map +1 -1
  330. package/dist/core/tools/write.js +0 -1
  331. package/dist/core/tools/write.js.map +1 -1
  332. package/dist/core/workspace-identity.d.ts.map +1 -1
  333. package/dist/daemon/activity-budget.d.ts.map +1 -1
  334. package/dist/daemon/activity-budget.js +2 -3
  335. package/dist/daemon/activity-budget.js.map +1 -1
  336. package/dist/daemon/command.d.ts.map +1 -1
  337. package/dist/daemon/command.js.map +1 -1
  338. package/dist/daemon/config.d.ts +2 -0
  339. package/dist/daemon/config.d.ts.map +1 -1
  340. package/dist/daemon/config.js +4 -0
  341. package/dist/daemon/config.js.map +1 -1
  342. package/dist/daemon/help.d.ts.map +1 -1
  343. package/dist/daemon/help.js +4 -3
  344. package/dist/daemon/help.js.map +1 -1
  345. package/dist/daemon/lsp-config.d.ts.map +1 -1
  346. package/dist/daemon/lsp-config.js.map +1 -1
  347. package/dist/daemon/outbound-budget.d.ts.map +1 -1
  348. package/dist/daemon/outbound-budget.js +2 -4
  349. package/dist/daemon/outbound-budget.js.map +1 -1
  350. package/dist/daemon/security.d.ts.map +1 -1
  351. package/dist/daemon/security.js.map +1 -1
  352. package/dist/daemon/server.d.ts.map +1 -1
  353. package/dist/daemon/server.js.map +1 -1
  354. package/dist/daemon/shared-connection.d.ts.map +1 -1
  355. package/dist/daemon/shared-connection.js +10 -15
  356. package/dist/daemon/shared-connection.js.map +1 -1
  357. package/dist/daemon/shared-revision.d.ts.map +1 -1
  358. package/dist/daemon/shared-revision.js +2 -1
  359. package/dist/daemon/shared-revision.js.map +1 -1
  360. package/dist/daemon/shared-roots.d.ts.map +1 -1
  361. package/dist/daemon/shared-roots.js +0 -1
  362. package/dist/daemon/shared-roots.js.map +1 -1
  363. package/dist/daemon/workspace-runtime.d.ts +2 -0
  364. package/dist/daemon/workspace-runtime.d.ts.map +1 -1
  365. package/dist/daemon/workspace-runtime.js +43 -15
  366. package/dist/daemon/workspace-runtime.js.map +1 -1
  367. package/dist/index.d.ts.map +1 -1
  368. package/dist/main.d.ts.map +1 -1
  369. package/dist/main.js.map +1 -1
  370. package/dist/migrations.d.ts.map +1 -1
  371. package/dist/migrations.js.map +1 -1
  372. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  373. package/dist/modes/interactive/components/assistant-message.js +21 -17
  374. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  375. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  376. package/dist/modes/interactive/components/bash-execution.js +4 -9
  377. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  378. package/dist/modes/interactive/components/bordered-loader.d.ts.map +1 -1
  379. package/dist/modes/interactive/components/bordered-loader.js +0 -3
  380. package/dist/modes/interactive/components/bordered-loader.js.map +1 -1
  381. package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
  382. package/dist/modes/interactive/components/branch-summary-message.js +1 -3
  383. package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
  384. package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
  385. package/dist/modes/interactive/components/compaction-summary-message.js +1 -3
  386. package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
  387. package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
  388. package/dist/modes/interactive/components/config-selector.js +6 -16
  389. package/dist/modes/interactive/components/config-selector.js.map +1 -1
  390. package/dist/modes/interactive/components/countdown-timer.d.ts.map +1 -1
  391. package/dist/modes/interactive/components/countdown-timer.js +0 -5
  392. package/dist/modes/interactive/components/countdown-timer.js.map +1 -1
  393. package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
  394. package/dist/modes/interactive/components/custom-editor.js +1 -8
  395. package/dist/modes/interactive/components/custom-editor.js.map +1 -1
  396. package/dist/modes/interactive/components/custom-message.d.ts.map +1 -1
  397. package/dist/modes/interactive/components/custom-message.js +1 -6
  398. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  399. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  400. package/dist/modes/interactive/components/diff.js.map +1 -1
  401. package/dist/modes/interactive/components/dynamic-border.d.ts.map +1 -1
  402. package/dist/modes/interactive/components/dynamic-border.js +0 -1
  403. package/dist/modes/interactive/components/dynamic-border.js.map +1 -1
  404. package/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  405. package/dist/modes/interactive/components/extension-editor.js +1 -7
  406. package/dist/modes/interactive/components/extension-editor.js.map +1 -1
  407. package/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
  408. package/dist/modes/interactive/components/extension-input.js +2 -8
  409. package/dist/modes/interactive/components/extension-input.js.map +1 -1
  410. package/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
  411. package/dist/modes/interactive/components/extension-selector.js +1 -9
  412. package/dist/modes/interactive/components/extension-selector.js.map +1 -1
  413. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  414. package/dist/modes/interactive/components/footer.js +1 -3
  415. package/dist/modes/interactive/components/footer.js.map +1 -1
  416. package/dist/modes/interactive/components/hook-execution.d.ts.map +1 -1
  417. package/dist/modes/interactive/components/hook-execution.js +2 -5
  418. package/dist/modes/interactive/components/hook-execution.js.map +1 -1
  419. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  420. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  421. package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  422. package/dist/modes/interactive/components/login-dialog.js +3 -9
  423. package/dist/modes/interactive/components/login-dialog.js.map +1 -1
  424. package/dist/modes/interactive/components/markdown-transform.d.ts.map +1 -1
  425. package/dist/modes/interactive/components/markdown-transform.js.map +1 -1
  426. package/dist/modes/interactive/components/mermaid.d.ts.map +1 -1
  427. package/dist/modes/interactive/components/mermaid.js.map +1 -1
  428. package/dist/modes/interactive/components/message-card.d.ts.map +1 -1
  429. package/dist/modes/interactive/components/message-card.js +0 -1
  430. package/dist/modes/interactive/components/message-card.js.map +1 -1
  431. package/dist/modes/interactive/components/model-selector.d.ts +26 -18
  432. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  433. package/dist/modes/interactive/components/model-selector.js +223 -210
  434. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  435. package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
  436. package/dist/modes/interactive/components/oauth-selector.js +3 -12
  437. package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
  438. package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
  439. package/dist/modes/interactive/components/scoped-models-selector.js +9 -13
  440. package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
  441. package/dist/modes/interactive/components/session-selector-search.d.ts.map +1 -1
  442. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  443. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  444. package/dist/modes/interactive/components/session-selector.js +33 -58
  445. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  446. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  447. package/dist/modes/interactive/components/settings-selector.js +0 -4
  448. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  449. package/dist/modes/interactive/components/show-images-selector.d.ts.map +1 -1
  450. package/dist/modes/interactive/components/show-images-selector.js +0 -1
  451. package/dist/modes/interactive/components/show-images-selector.js.map +1 -1
  452. package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
  453. package/dist/modes/interactive/components/skill-invocation-message.js +1 -3
  454. package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
  455. package/dist/modes/interactive/components/theme-selector.d.ts.map +1 -1
  456. package/dist/modes/interactive/components/theme-selector.js +0 -2
  457. package/dist/modes/interactive/components/theme-selector.js.map +1 -1
  458. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  459. package/dist/modes/interactive/components/thinking-selector.js +0 -1
  460. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  461. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  462. package/dist/modes/interactive/components/tool-execution.js +9 -24
  463. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  464. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  465. package/dist/modes/interactive/components/tree-selector.js +18 -34
  466. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  467. package/dist/modes/interactive/components/user-message-selector.d.ts.map +1 -1
  468. package/dist/modes/interactive/components/user-message-selector.js +3 -6
  469. package/dist/modes/interactive/components/user-message-selector.js.map +1 -1
  470. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  471. package/dist/modes/interactive/components/user-message.js +0 -4
  472. package/dist/modes/interactive/components/user-message.js.map +1 -1
  473. package/dist/modes/interactive/components/visual-truncate.d.ts.map +1 -1
  474. package/dist/modes/interactive/components/visual-truncate.js.map +1 -1
  475. package/dist/modes/interactive/interactive-mode.d.ts +14 -0
  476. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  477. package/dist/modes/interactive/interactive-mode.js +223 -137
  478. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  479. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  480. package/dist/modes/interactive/theme/theme.js +0 -7
  481. package/dist/modes/interactive/theme/theme.js.map +1 -1
  482. package/dist/modes/json-event.d.ts.map +1 -1
  483. package/dist/modes/json-event.js.map +1 -1
  484. package/dist/modes/print-mode.d.ts.map +1 -1
  485. package/dist/modes/print-mode.js.map +1 -1
  486. package/dist/modes/rpc/jsonl.d.ts.map +1 -1
  487. package/dist/modes/rpc/jsonl.js.map +1 -1
  488. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  489. package/dist/modes/rpc/rpc-client.js +10 -11
  490. package/dist/modes/rpc/rpc-client.js.map +1 -1
  491. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  492. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  493. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  494. package/dist/package-manager-cli.d.ts.map +1 -1
  495. package/dist/package-manager-cli.js.map +1 -1
  496. package/dist/utils/ansi.d.ts.map +1 -1
  497. package/dist/utils/ansi.js.map +1 -1
  498. package/dist/utils/changelog.d.ts.map +1 -1
  499. package/dist/utils/changelog.js.map +1 -1
  500. package/dist/utils/child-process.d.ts.map +1 -1
  501. package/dist/utils/child-process.js.map +1 -1
  502. package/dist/utils/clipboard-image.d.ts.map +1 -1
  503. package/dist/utils/clipboard-image.js.map +1 -1
  504. package/dist/utils/clipboard-native.d.ts.map +1 -1
  505. package/dist/utils/clipboard-native.js.map +1 -1
  506. package/dist/utils/clipboard.d.ts.map +1 -1
  507. package/dist/utils/clipboard.js.map +1 -1
  508. package/dist/utils/deprecation.d.ts.map +1 -1
  509. package/dist/utils/deprecation.js.map +1 -1
  510. package/dist/utils/directory-completions.d.ts.map +1 -1
  511. package/dist/utils/directory-completions.js.map +1 -1
  512. package/dist/utils/exif-orientation.d.ts.map +1 -1
  513. package/dist/utils/exif-orientation.js.map +1 -1
  514. package/dist/utils/frontmatter.d.ts.map +1 -1
  515. package/dist/utils/frontmatter.js.map +1 -1
  516. package/dist/utils/fs-watch.d.ts.map +1 -1
  517. package/dist/utils/fs-watch.js.map +1 -1
  518. package/dist/utils/git.d.ts.map +1 -1
  519. package/dist/utils/git.js.map +1 -1
  520. package/dist/utils/grip-user-agent.d.ts.map +1 -1
  521. package/dist/utils/grip-user-agent.js +1 -1
  522. package/dist/utils/grip-user-agent.js.map +1 -1
  523. package/dist/utils/html.d.ts.map +1 -1
  524. package/dist/utils/html.js.map +1 -1
  525. package/dist/utils/image-convert.d.ts.map +1 -1
  526. package/dist/utils/image-convert.js.map +1 -1
  527. package/dist/utils/image-process.d.ts.map +1 -1
  528. package/dist/utils/image-process.js.map +1 -1
  529. package/dist/utils/image-resize-core.d.ts.map +1 -1
  530. package/dist/utils/image-resize-core.js.map +1 -1
  531. package/dist/utils/image-resize-worker.d.ts.map +1 -1
  532. package/dist/utils/image-resize-worker.js.map +1 -1
  533. package/dist/utils/image-resize.d.ts.map +1 -1
  534. package/dist/utils/image-resize.js.map +1 -1
  535. package/dist/utils/json.d.ts.map +1 -1
  536. package/dist/utils/json.js.map +1 -1
  537. package/dist/utils/mime.d.ts.map +1 -1
  538. package/dist/utils/mime.js.map +1 -1
  539. package/dist/utils/open-browser.d.ts.map +1 -1
  540. package/dist/utils/open-browser.js.map +1 -1
  541. package/dist/utils/paths.d.ts.map +1 -1
  542. package/dist/utils/paths.js.map +1 -1
  543. package/dist/utils/photon.d.ts.map +1 -1
  544. package/dist/utils/photon.js +10 -5
  545. package/dist/utils/photon.js.map +1 -1
  546. package/dist/utils/shell.d.ts.map +1 -1
  547. package/dist/utils/shell.js.map +1 -1
  548. package/dist/utils/sleep.d.ts.map +1 -1
  549. package/dist/utils/sleep.js.map +1 -1
  550. package/dist/utils/syntax-highlight.d.ts.map +1 -1
  551. package/dist/utils/syntax-highlight.js +1 -1
  552. package/dist/utils/syntax-highlight.js.map +1 -1
  553. package/dist/utils/tools-manager.d.ts.map +1 -1
  554. package/dist/utils/tools-manager.js.map +1 -1
  555. package/dist/utils/version-check.d.ts.map +1 -1
  556. package/dist/utils/version-check.js.map +1 -1
  557. package/dist/utils/windows-self-update.d.ts.map +1 -1
  558. package/dist/utils/windows-self-update.js.map +1 -1
  559. package/docs/keybindings.md +3 -1
  560. package/docs/providers.md +3 -1
  561. package/docs/sandbox.md +7 -1
  562. package/docs/sessions.md +1 -1
  563. package/docs/usage.md +39 -2
  564. package/examples/extensions/custom-provider-anthropic/package.json +2 -2
  565. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  566. package/examples/extensions/sandbox/package.json +2 -2
  567. package/examples/extensions/with-deps/package.json +1 -1
  568. package/npm-shrinkwrap.json +601 -833
  569. package/package.json +20 -21
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/daemon/config.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile, realpath, stat } from \"node:fs/promises\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport {\n\tDEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS,\n\ttype RemoteWorkspaceProtocolLimits,\n\tvalidateRemoteWorkspaceProtocolLimits,\n} from \"../core/remote-workspace-protocol/contract.ts\";\n\nexport const DAEMON_WEBSOCKET_PATH = \"/grip/workspace\";\nexport const DAEMON_WEBSOCKET_PROTOCOL = \"grip.workspace.v1\";\n\nexport interface DaemonTlsConfiguration {\n\treadonly cert: Buffer;\n\treadonly key: Buffer;\n\treadonly passphrase?: string;\n}\n\nexport interface DaemonConfiguration {\n\treadonly host: string;\n\treadonly port: number;\n\treadonly workspaceRoot: string;\n\t/** Canonical fixed parent mount for explicitly enabled shared-channel mode. */\n\treadonly sharedParentRoot?: string;\n\treadonly temporaryRoot?: string;\n\treadonly token?: string;\n\treadonly allowedOrigins: readonly string[];\n\treadonly tls?: DaemonTlsConfiguration;\n\treadonly allowInsecureTransport: boolean;\n\treadonly allowProcessExec: boolean;\n\treadonly allowRoot: boolean;\n\treadonly forwardedEnvironment: readonly string[];\n\treadonly lspConfigPath?: string;\n\treadonly sandboxInstructionsPath?: string;\n\treadonly userAgentsPath?: string;\n\treadonly trustProjectLsp: boolean;\n\treadonly maxConnections: number;\n\treadonly maxGlobalRequests: number;\n\treadonly maxGlobalTransfers: number;\n\treadonly maxBufferedOutputBytes: number;\n\treadonly maxPendingConnections: number;\n\treadonly handshakeTimeoutMs: number;\n\treadonly shutdownTimeoutMs: number;\n\treadonly protocolLimits: RemoteWorkspaceProtocolLimits;\n}\n\nexport interface DaemonCommand {\n\treadonly help: boolean;\n\treadonly configuration?: DaemonConfiguration;\n}\n\nexport class DaemonConfigurationError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"DaemonConfigurationError\";\n\t}\n}\n\ninterface ParsedDaemonInputs {\n\thelp: boolean;\n\thost?: string;\n\tport?: string;\n\tcwd?: string;\n\tsharedParent?: string;\n\torigins: string[];\n\ttlsCertPath?: string;\n\ttlsKeyPath?: string;\n\tallowInsecureTransport?: boolean;\n\tallowProcessExec?: boolean;\n\tallowRoot?: boolean;\n\tforwardedEnvironment: string[];\n\tlspConfigPath?: string;\n\ttrustProjectLsp?: boolean;\n\tmaxConnections?: string;\n\tmaxPendingConnections?: string;\n\thandshakeTimeoutMs?: string;\n\tshutdownTimeoutMs?: string;\n}\n\nconst BOOLEAN_VALUES = new Map<string, boolean>([\n\t[\"1\", true],\n\t[\"true\", true],\n\t[\"yes\", true],\n\t[\"0\", false],\n\t[\"false\", false],\n\t[\"no\", false],\n]);\n\nconst VALUE_FLAGS = new Map<string, keyof ParsedDaemonInputs>([\n\t[\"--daemon-host\", \"host\"],\n\t[\"--daemon-port\", \"port\"],\n\t[\"--daemon-cwd\", \"cwd\"],\n\t[\"--daemon-shared-parent\", \"sharedParent\"],\n\t[\"--daemon-tls-cert\", \"tlsCertPath\"],\n\t[\"--daemon-tls-key\", \"tlsKeyPath\"],\n\t[\"--daemon-lsp-config\", \"lspConfigPath\"],\n\t[\"--daemon-max-connections\", \"maxConnections\"],\n\t[\"--daemon-max-pending-connections\", \"maxPendingConnections\"],\n\t[\"--daemon-handshake-timeout-ms\", \"handshakeTimeoutMs\"],\n\t[\"--daemon-shutdown-timeout-ms\", \"shutdownTimeoutMs\"],\n]);\n\nconst BOOLEAN_FLAGS = new Map<string, keyof ParsedDaemonInputs>([\n\t[\"--daemon-allow-insecure-transport\", \"allowInsecureTransport\"],\n\t[\"--daemon-allow-process-exec\", \"allowProcessExec\"],\n\t[\"--daemon-allow-root\", \"allowRoot\"],\n\t[\"--daemon-trust-project-lsp\", \"trustProjectLsp\"],\n]);\n\nfunction parseBoolean(value: string | undefined, name: string, fallback = false): boolean {\n\tif (value === undefined) return fallback;\n\tconst parsed = BOOLEAN_VALUES.get(value.toLowerCase());\n\tif (parsed === undefined) throw new DaemonConfigurationError(`${name} must be one of 1, 0, true, false, yes, or no`);\n\treturn parsed;\n}\n\nfunction parseInteger(\n\tvalue: string | undefined,\n\tname: string,\n\tminimum: number,\n\tmaximum: number,\n\tfallback: number,\n): number {\n\tif (value === undefined) return fallback;\n\tif (!/^(0|[1-9][0-9]*)$/.test(value)) {\n\t\tthrow new DaemonConfigurationError(`${name} must be a decimal integer from ${minimum} to ${maximum}`);\n\t}\n\tconst parsed = Number(value);\n\tif (!Number.isSafeInteger(parsed) || parsed < minimum || parsed > maximum) {\n\t\tthrow new DaemonConfigurationError(`${name} must be a decimal integer from ${minimum} to ${maximum}`);\n\t}\n\treturn parsed;\n}\n\nfunction setSingleton(\n\tinputs: ParsedDaemonInputs,\n\tkey: keyof ParsedDaemonInputs,\n\tvalue: string | boolean,\n\tflag: string,\n): void {\n\tif (inputs[key] !== undefined) throw new DaemonConfigurationError(`${flag} may only be specified once`);\n\t(inputs as Record<keyof ParsedDaemonInputs, unknown>)[key] = value;\n}\n\nfunction requireFlagValue(args: readonly string[], index: number, flag: string): string {\n\tconst value = args[index + 1];\n\tif (value === undefined || value.startsWith(\"-\")) throw new DaemonConfigurationError(`${flag} requires a value`);\n\treturn value;\n}\n\nfunction parseInputs(args: readonly string[]): ParsedDaemonInputs {\n\tif (args[0] !== \"--daemon\") throw new DaemonConfigurationError(\"Daemon command must start with --daemon\");\n\tconst inputs: ParsedDaemonInputs = { help: false, origins: [], forwardedEnvironment: [] };\n\tfor (let index = 1; index < args.length; index++) {\n\t\tconst argument = args[index];\n\t\tif (argument === \"--help\" || argument === \"-h\") {\n\t\t\tinputs.help = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--daemon-origin\" || argument === \"--daemon-env\") {\n\t\t\tconst value = requireFlagValue(args, index, argument);\n\t\t\tif (argument === \"--daemon-origin\") inputs.origins.push(value);\n\t\t\telse inputs.forwardedEnvironment.push(value);\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tconst valueKey = VALUE_FLAGS.get(argument);\n\t\tif (valueKey) {\n\t\t\tsetSingleton(inputs, valueKey, requireFlagValue(args, index, argument), argument);\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tconst booleanKey = BOOLEAN_FLAGS.get(argument);\n\t\tif (booleanKey) {\n\t\t\tsetSingleton(inputs, booleanKey, true, argument);\n\t\t\tcontinue;\n\t\t}\n\t\tthrow new DaemonConfigurationError(\n\t\t\targument.startsWith(\"-\")\n\t\t\t\t? `Unknown or incompatible option in daemon mode: ${argument}`\n\t\t\t\t: `Daemon mode does not accept positional arguments: ${argument}`,\n\t\t);\n\t}\n\treturn inputs;\n}\n\nfunction parseOrigin(value: string): string {\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(value);\n\t} catch {\n\t\tthrow new DaemonConfigurationError(`Invalid daemon Origin: ${value}`);\n\t}\n\tif (\n\t\t(url.protocol !== \"http:\" && url.protocol !== \"https:\") ||\n\t\turl.username !== \"\" ||\n\t\turl.password !== \"\" ||\n\t\turl.pathname !== \"/\" ||\n\t\turl.search !== \"\" ||\n\t\turl.hash !== \"\" ||\n\t\tvalue !== url.origin\n\t) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Daemon origins must be exact HTTP(S) origins without paths or wildcards: ${value}`,\n\t\t);\n\t}\n\treturn url.origin;\n}\n\nfunction parseEnvironmentNames(values: readonly string[]): string[] {\n\tconst names = values\n\t\t.flatMap((value) => value.split(\",\"))\n\t\t.map((value) => value.trim())\n\t\t.filter(Boolean);\n\tconst seen = new Set<string>();\n\tfor (const name of names) {\n\t\tif (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))\n\t\t\tthrow new DaemonConfigurationError(`Invalid daemon environment name: ${name}`);\n\t\tconst identity = process.platform === \"win32\" ? name.toLowerCase() : name;\n\t\tif (seen.has(identity)) throw new DaemonConfigurationError(`Duplicate daemon environment name: ${name}`);\n\t\tseen.add(identity);\n\t}\n\treturn names;\n}\n\nasync function resolveConfinedRoot(value: string, startupCwd: string, label: string): Promise<string> {\n\tconst candidate = isAbsolute(value) ? value : resolve(startupCwd, value);\n\tlet canonical: string;\n\ttry {\n\t\tcanonical = await realpath(candidate);\n\t\tif (!(await stat(canonical)).isDirectory()) throw new Error(\"not a directory\");\n\t} catch (error) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Daemon ${label} must be an existing directory: ${candidate} (${error instanceof Error ? error.message : String(error)})`,\n\t\t);\n\t}\n\treturn canonical;\n}\n\nasync function readTlsFile(path: string, label: string, startupCwd: string): Promise<Buffer> {\n\tconst resolvedPath = isAbsolute(path) ? path : resolve(startupCwd, path);\n\ttry {\n\t\tconst content = await readFile(resolvedPath);\n\t\tif (content.byteLength === 0) throw new Error(\"file is empty\");\n\t\treturn content;\n\t} catch (error) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Unable to read daemon TLS ${label} file ${resolvedPath}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n}\n\nfunction validateToken(token: string | undefined): string | undefined {\n\tif (token === undefined) return undefined;\n\tconst bytes = Buffer.byteLength(token, \"utf8\");\n\tif (bytes < 32 || bytes > 1024 || !/\\S/u.test(token) || /[\\r\\n]/u.test(token)) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t\"GRIP_DAEMON_TOKEN must contain 32 to 1024 UTF-8 bytes, include a non-whitespace character, and contain no line breaks\",\n\t\t);\n\t}\n\treturn token;\n}\n\nfunction isRootProcess(): boolean {\n\treturn process.platform !== \"win32\" && typeof process.getuid === \"function\" && process.getuid() === 0;\n}\n\nexport function isDaemonCommand(args: readonly string[]): boolean {\n\treturn args[0] === \"--daemon\";\n}\ninterface DaemonEndpointConfiguration {\n\thost: string;\n\tport: number;\n}\n\ninterface DaemonWorkspaceRootsConfiguration {\n\tallowRoot: boolean;\n\tworkspaceRoot: string;\n\ttemporaryRoot: string | undefined;\n}\n\ninterface DaemonTransportSecurityConfiguration {\n\ttoken: string | undefined;\n\tallowedOrigins: string[];\n\ttls: DaemonTlsConfiguration | undefined;\n}\n\ninterface DaemonCapacityConfiguration {\n\tmaxGlobalRequests: number;\n\tmaxGlobalTransfers: number;\n\tmaxBufferedOutputBytes: number;\n\tprotocolLimits: RemoteWorkspaceProtocolLimits;\n}\n\nfunction resolveDaemonEndpoint(\n\tinputs: ParsedDaemonInputs,\n\tenvironment: NodeJS.ProcessEnv,\n): DaemonEndpointConfiguration {\n\tconst host = inputs.host ?? environment.GRIP_DAEMON_HOST ?? \"127.0.0.1\";\n\tif (host.length === 0 || /\\s/u.test(host)) {\n\t\tthrow new DaemonConfigurationError(\"Daemon host must be a non-empty IP address\");\n\t}\n\tconst port = parseInteger(\n\t\tinputs.port ?? environment.GRIP_DAEMON_PORT,\n\t\t\"GRIP_DAEMON_PORT/--daemon-port\",\n\t\t1,\n\t\t65535,\n\t\t8787,\n\t);\n\treturn { host, port };\n}\n\nasync function resolveDaemonWorkspaceRoots(\n\tinputs: ParsedDaemonInputs,\n\tenvironment: NodeJS.ProcessEnv,\n\tstartupCwd: string,\n): Promise<DaemonWorkspaceRootsConfiguration> {\n\tconst allowRoot = inputs.allowRoot ?? parseBoolean(environment.GRIP_DAEMON_ALLOW_ROOT, \"GRIP_DAEMON_ALLOW_ROOT\");\n\tif (isRootProcess() && !allowRoot) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t\"Refusing to run the workspace daemon as root; use --daemon-allow-root only inside an intentional OS sandbox\",\n\t\t);\n\t}\n\tconst workspaceRoot = await resolveConfinedRoot(\n\t\tinputs.cwd ?? environment.GRIP_DAEMON_CWD ?? startupCwd,\n\t\tstartupCwd,\n\t\t\"workspace root\",\n\t);\n\tconst temporaryRoot = environment.GRIP_DAEMON_TEMP_ROOT\n\t\t? await resolveConfinedRoot(environment.GRIP_DAEMON_TEMP_ROOT, startupCwd, \"temporary root\")\n\t\t: undefined;\n\treturn { allowRoot, workspaceRoot, temporaryRoot };\n}\n\nasync function resolveSharedParentRoot(\n\tinputs: ParsedDaemonInputs,\n\tenvironment: NodeJS.ProcessEnv,\n\tstartupCwd: string,\n\tworkspaceRoot: string,\n): Promise<string | undefined> {\n\tconst value = inputs.sharedParent ?? environment.GRIP_DAEMON_SHARED_PARENT;\n\tif (value === undefined) return undefined;\n\tif (value === \"\") throw new DaemonConfigurationError(\"Shared parent mount must not be empty\");\n\tconst root = await resolveConfinedRoot(value, startupCwd, \"shared parent mount\");\n\tif (root !== workspaceRoot) {\n\t\tthrow new DaemonConfigurationError(\"Shared parent mount must equal --daemon-cwd (the fixed mounted parent)\");\n\t}\n\treturn root;\n}\n\nasync function resolveDaemonTransportSecurity(\n\tinputs: ParsedDaemonInputs,\n\tenvironment: NodeJS.ProcessEnv,\n\tstartupCwd: string,\n): Promise<DaemonTransportSecurityConfiguration> {\n\tconst token = validateToken(environment.GRIP_DAEMON_TOKEN);\n\tconst allowedOrigins = [\n\t\t...(environment.GRIP_DAEMON_ORIGINS?.split(\",\")\n\t\t\t.map((value) => value.trim())\n\t\t\t.filter(Boolean) ?? []),\n\t\t...inputs.origins,\n\t].map(parseOrigin);\n\tif (new Set(allowedOrigins).size !== allowedOrigins.length) {\n\t\tthrow new DaemonConfigurationError(\"Daemon origins must be unique\");\n\t}\n\tconst tlsCertPath = inputs.tlsCertPath ?? environment.GRIP_DAEMON_TLS_CERT;\n\tconst tlsKeyPath = inputs.tlsKeyPath ?? environment.GRIP_DAEMON_TLS_KEY;\n\tif ((tlsCertPath === undefined) !== (tlsKeyPath === undefined)) {\n\t\tthrow new DaemonConfigurationError(\"Daemon TLS requires both a certificate and private key\");\n\t}\n\tconst tls =\n\t\ttlsCertPath && tlsKeyPath\n\t\t\t? Object.freeze({\n\t\t\t\t\tcert: await readTlsFile(tlsCertPath, \"certificate\", startupCwd),\n\t\t\t\t\tkey: await readTlsFile(tlsKeyPath, \"private key\", startupCwd),\n\t\t\t\t\tpassphrase: environment.GRIP_DAEMON_TLS_PASSPHRASE,\n\t\t\t\t})\n\t\t\t: undefined;\n\treturn { token, allowedOrigins, tls };\n}\n\nfunction resolveDaemonCapacity(environment: NodeJS.ProcessEnv): DaemonCapacityConfiguration {\n\tconst maxConnectionRequests = parseInteger(\n\t\tenvironment.GRIP_DAEMON_MAX_CONNECTION_REQUESTS,\n\t\t\"GRIP_DAEMON_MAX_CONNECTION_REQUESTS\",\n\t\t1,\n\t\t10_000_000,\n\t\tDEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS.maxActiveRequests,\n\t);\n\tconst maxGlobalRequests = parseInteger(\n\t\tenvironment.GRIP_DAEMON_MAX_GLOBAL_REQUESTS,\n\t\t\"GRIP_DAEMON_MAX_GLOBAL_REQUESTS\",\n\t\t1,\n\t\t10_000_000,\n\t\tmaxConnectionRequests,\n\t);\n\tif (maxGlobalRequests < maxConnectionRequests) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t\"GRIP_DAEMON_MAX_GLOBAL_REQUESTS must be at least GRIP_DAEMON_MAX_CONNECTION_REQUESTS\",\n\t\t);\n\t}\n\tconst maxConnectionTransfers = parseInteger(\n\t\tenvironment.GRIP_DAEMON_MAX_CONNECTION_UPLOADS,\n\t\t\"GRIP_DAEMON_MAX_CONNECTION_UPLOADS\",\n\t\t1,\n\t\t10_000,\n\t\tDEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS.maxActiveTransfers,\n\t);\n\tconst maxGlobalTransfers = parseInteger(\n\t\tenvironment.GRIP_DAEMON_MAX_GLOBAL_UPLOADS,\n\t\t\"GRIP_DAEMON_MAX_GLOBAL_UPLOADS\",\n\t\t1,\n\t\t10_000,\n\t\tmaxConnectionTransfers,\n\t);\n\tif (maxGlobalTransfers < maxConnectionTransfers) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t\"GRIP_DAEMON_MAX_GLOBAL_UPLOADS must be at least GRIP_DAEMON_MAX_CONNECTION_UPLOADS\",\n\t\t);\n\t}\n\tconst maxMessageBytes = parseInteger(\n\t\tenvironment.GRIP_DAEMON_MAX_FRAME_BYTES,\n\t\t\"GRIP_DAEMON_MAX_FRAME_BYTES\",\n\t\t1024,\n\t\t64 * 1024 * 1024,\n\t\tDEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS.maxMessageBytes,\n\t);\n\tconst maxTransferBytes = parseInteger(\n\t\tenvironment.GRIP_DAEMON_MAX_UPLOAD_BYTES,\n\t\t\"GRIP_DAEMON_MAX_UPLOAD_BYTES\",\n\t\t1,\n\t\tNumber.MAX_SAFE_INTEGER,\n\t\tDEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS.maxTransferBytes,\n\t);\n\tconst maxBufferedOutputBytes = parseInteger(\n\t\tenvironment.GRIP_DAEMON_MAX_BUFFERED_OUTPUT_BYTES,\n\t\t\"GRIP_DAEMON_MAX_BUFFERED_OUTPUT_BYTES\",\n\t\t1024,\n\t\t64 * 1024 * 1024,\n\t\t8 * 1024 * 1024,\n\t);\n\tconst protocolLimits = validateRemoteWorkspaceProtocolLimits({\n\t\t...DEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS,\n\t\tmaxMessageBytes,\n\t\tmaxStringBytes: Math.min(DEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS.maxStringBytes, maxMessageBytes),\n\t\tmaxPendingInboundBytes: Math.max(\n\t\t\tDEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS.maxPendingInboundBytes,\n\t\t\tmaxMessageBytes,\n\t\t),\n\t\tmaxTransferBytes,\n\t\tmaxActiveRequests: maxConnectionRequests,\n\t\tmaxActiveTransfers: Math.min(maxConnectionTransfers, maxGlobalTransfers),\n\t});\n\treturn { maxGlobalRequests, maxGlobalTransfers, maxBufferedOutputBytes, protocolLimits };\n}\n\nexport async function parseDaemonCommand(\n\targs: readonly string[],\n\tenvironment: NodeJS.ProcessEnv = process.env,\n\tstartupCwd = process.cwd(),\n): Promise<DaemonCommand> {\n\tconst inputs = parseInputs(args);\n\tif (inputs.help) return { help: true };\n\n\tconst { host, port } = resolveDaemonEndpoint(inputs, environment);\n\tconst { allowRoot, workspaceRoot, temporaryRoot } = await resolveDaemonWorkspaceRoots(\n\t\tinputs,\n\t\tenvironment,\n\t\tstartupCwd,\n\t);\n\tconst sharedParentRoot = await resolveSharedParentRoot(inputs, environment, startupCwd, workspaceRoot);\n\tconst { token, allowedOrigins, tls } = await resolveDaemonTransportSecurity(inputs, environment, startupCwd);\n\tconst { maxGlobalRequests, maxGlobalTransfers, maxBufferedOutputBytes, protocolLimits } =\n\t\tresolveDaemonCapacity(environment);\n\n\tconst allowInsecureTransport =\n\t\tinputs.allowInsecureTransport ??\n\t\tparseBoolean(environment.GRIP_DAEMON_ALLOW_INSECURE_TRANSPORT, \"GRIP_DAEMON_ALLOW_INSECURE_TRANSPORT\");\n\tconst allowProcessExec =\n\t\tinputs.allowProcessExec ??\n\t\tparseBoolean(environment.GRIP_DAEMON_ALLOW_PROCESS_EXEC, \"GRIP_DAEMON_ALLOW_PROCESS_EXEC\");\n\tconst trustProjectLsp =\n\t\tinputs.trustProjectLsp ??\n\t\tparseBoolean(environment.GRIP_DAEMON_TRUST_PROJECT_LSP, \"GRIP_DAEMON_TRUST_PROJECT_LSP\");\n\tconst forwardedEnvironment = parseEnvironmentNames([\n\t\t...(environment.GRIP_DAEMON_ENV?.split(\",\") ?? []),\n\t\t...inputs.forwardedEnvironment,\n\t]);\n\tconst maxConnections = parseInteger(\n\t\tinputs.maxConnections ?? environment.GRIP_DAEMON_MAX_CONNECTIONS,\n\t\t\"GRIP_DAEMON_MAX_CONNECTIONS/--daemon-max-connections\",\n\t\t1,\n\t\t100_000,\n\t\t64,\n\t);\n\tconst maxPendingConnections = parseInteger(\n\t\tinputs.maxPendingConnections ?? environment.GRIP_DAEMON_MAX_PENDING_CONNECTIONS,\n\t\t\"GRIP_DAEMON_MAX_PENDING_CONNECTIONS/--daemon-max-pending-connections\",\n\t\t1,\n\t\t100_000,\n\t\t64,\n\t);\n\tconst handshakeTimeoutMs = parseInteger(\n\t\tinputs.handshakeTimeoutMs ?? environment.GRIP_DAEMON_HANDSHAKE_TIMEOUT_MS,\n\t\t\"GRIP_DAEMON_HANDSHAKE_TIMEOUT_MS/--daemon-handshake-timeout-ms\",\n\t\t100,\n\t\t5 * 60_000,\n\t\t10_000,\n\t);\n\tconst shutdownTimeoutMs = parseInteger(\n\t\tinputs.shutdownTimeoutMs ?? environment.GRIP_DAEMON_SHUTDOWN_TIMEOUT_MS,\n\t\t\"GRIP_DAEMON_SHUTDOWN_TIMEOUT_MS/--daemon-shutdown-timeout-ms\",\n\t\t100,\n\t\t5 * 60_000,\n\t\t10_000,\n\t);\n\n\treturn {\n\t\thelp: false,\n\t\tconfiguration: Object.freeze({\n\t\t\thost,\n\t\t\tport,\n\t\t\tworkspaceRoot,\n\t\t\tsharedParentRoot,\n\t\t\ttemporaryRoot,\n\t\t\ttoken,\n\t\t\tallowedOrigins: Object.freeze(allowedOrigins),\n\t\t\ttls,\n\t\t\tallowInsecureTransport,\n\t\t\tallowProcessExec,\n\t\t\tallowRoot,\n\t\t\tforwardedEnvironment: Object.freeze(forwardedEnvironment),\n\t\t\tlspConfigPath:\n\t\t\t\tinputs.lspConfigPath || environment.GRIP_DAEMON_LSP_CONFIG\n\t\t\t\t\t? resolve(startupCwd, inputs.lspConfigPath ?? environment.GRIP_DAEMON_LSP_CONFIG!)\n\t\t\t\t\t: undefined,\n\t\t\ttrustProjectLsp,\n\t\t\tsandboxInstructionsPath: environment.GRIP_DAEMON_SANDBOX_INSTRUCTIONS\n\t\t\t\t? resolve(startupCwd, environment.GRIP_DAEMON_SANDBOX_INSTRUCTIONS)\n\t\t\t\t: undefined,\n\t\t\tuserAgentsPath: environment.HOME ? join(environment.HOME, \".grip\", \"AGENTS.md\") : undefined,\n\t\t\tmaxConnections,\n\t\t\tmaxGlobalRequests,\n\t\t\tmaxGlobalTransfers,\n\t\t\tmaxBufferedOutputBytes,\n\t\t\tmaxPendingConnections,\n\t\t\thandshakeTimeoutMs,\n\t\t\tshutdownTimeoutMs,\n\t\t\tprotocolLimits: Object.freeze({ ...protocolLimits }),\n\t\t}),\n\t};\n}\n"]}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/daemon/config.ts"],"names":[],"mappings":"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","sourcesContent":["import { readFile, realpath, stat } from \"node:fs/promises\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport {\n\tDEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS,\n\ttype RemoteWorkspaceProtocolLimits,\n\tvalidateRemoteWorkspaceProtocolLimits,\n} from \"../core/remote-workspace-protocol/contract.ts\";\n\nexport const DAEMON_WEBSOCKET_PATH = \"/grip/workspace\";\nexport const DAEMON_WEBSOCKET_PROTOCOL = \"grip.workspace.v1\";\n\nexport interface DaemonTlsConfiguration {\n\treadonly cert: Buffer;\n\treadonly key: Buffer;\n\treadonly passphrase?: string;\n}\n\nexport interface DaemonConfiguration {\n\treadonly host: string;\n\treadonly port: number;\n\treadonly workspaceRoot: string;\n\t/** Canonical fixed parent mount for explicitly enabled shared-channel mode. */\n\treadonly sharedParentRoot?: string;\n\treadonly temporaryRoot?: string;\n\t/** Explicit opt-in for daemons running inside an isolated guest; never enabled by default for attached daemons. */\n\treadonly allowFullFilesystem: boolean;\n\treadonly token?: string;\n\treadonly allowedOrigins: readonly string[];\n\treadonly tls?: DaemonTlsConfiguration;\n\treadonly allowInsecureTransport: boolean;\n\treadonly allowProcessExec: boolean;\n\treadonly allowRoot: boolean;\n\treadonly forwardedEnvironment: readonly string[];\n\treadonly lspConfigPath?: string;\n\treadonly sandboxInstructionsPath?: string;\n\treadonly userAgentsPath?: string;\n\treadonly trustProjectLsp: boolean;\n\treadonly maxConnections: number;\n\treadonly maxGlobalRequests: number;\n\treadonly maxGlobalTransfers: number;\n\treadonly maxBufferedOutputBytes: number;\n\treadonly maxPendingConnections: number;\n\treadonly handshakeTimeoutMs: number;\n\treadonly shutdownTimeoutMs: number;\n\treadonly protocolLimits: RemoteWorkspaceProtocolLimits;\n}\n\nexport interface DaemonCommand {\n\treadonly help: boolean;\n\treadonly configuration?: DaemonConfiguration;\n}\n\nexport class DaemonConfigurationError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"DaemonConfigurationError\";\n\t}\n}\n\ninterface ParsedDaemonInputs {\n\thelp: boolean;\n\thost?: string;\n\tport?: string;\n\tcwd?: string;\n\tsharedParent?: string;\n\torigins: string[];\n\ttlsCertPath?: string;\n\ttlsKeyPath?: string;\n\tallowInsecureTransport?: boolean;\n\tallowFullFilesystem?: boolean;\n\tallowProcessExec?: boolean;\n\tallowRoot?: boolean;\n\tforwardedEnvironment: string[];\n\tlspConfigPath?: string;\n\ttrustProjectLsp?: boolean;\n\tmaxConnections?: string;\n\tmaxPendingConnections?: string;\n\thandshakeTimeoutMs?: string;\n\tshutdownTimeoutMs?: string;\n}\n\nconst BOOLEAN_VALUES = new Map<string, boolean>([\n\t[\"1\", true],\n\t[\"true\", true],\n\t[\"yes\", true],\n\t[\"0\", false],\n\t[\"false\", false],\n\t[\"no\", false],\n]);\n\nconst VALUE_FLAGS = new Map<string, keyof ParsedDaemonInputs>([\n\t[\"--daemon-host\", \"host\"],\n\t[\"--daemon-port\", \"port\"],\n\t[\"--daemon-cwd\", \"cwd\"],\n\t[\"--daemon-shared-parent\", \"sharedParent\"],\n\t[\"--daemon-tls-cert\", \"tlsCertPath\"],\n\t[\"--daemon-tls-key\", \"tlsKeyPath\"],\n\t[\"--daemon-lsp-config\", \"lspConfigPath\"],\n\t[\"--daemon-max-connections\", \"maxConnections\"],\n\t[\"--daemon-max-pending-connections\", \"maxPendingConnections\"],\n\t[\"--daemon-handshake-timeout-ms\", \"handshakeTimeoutMs\"],\n\t[\"--daemon-shutdown-timeout-ms\", \"shutdownTimeoutMs\"],\n]);\n\nconst BOOLEAN_FLAGS = new Map<string, keyof ParsedDaemonInputs>([\n\t[\"--daemon-allow-insecure-transport\", \"allowInsecureTransport\"],\n\t[\"--daemon-allow-process-exec\", \"allowProcessExec\"],\n\t[\"--daemon-allow-root\", \"allowRoot\"],\n\t[\"--daemon-allow-full-filesystem\", \"allowFullFilesystem\"],\n\t[\"--daemon-trust-project-lsp\", \"trustProjectLsp\"],\n]);\n\nfunction parseBoolean(value: string | undefined, name: string, fallback = false): boolean {\n\tif (value === undefined) return fallback;\n\tconst parsed = BOOLEAN_VALUES.get(value.toLowerCase());\n\tif (parsed === undefined) throw new DaemonConfigurationError(`${name} must be one of 1, 0, true, false, yes, or no`);\n\treturn parsed;\n}\n\nfunction parseInteger(\n\tvalue: string | undefined,\n\tname: string,\n\tminimum: number,\n\tmaximum: number,\n\tfallback: number,\n): number {\n\tif (value === undefined) return fallback;\n\tif (!/^(0|[1-9][0-9]*)$/.test(value)) {\n\t\tthrow new DaemonConfigurationError(`${name} must be a decimal integer from ${minimum} to ${maximum}`);\n\t}\n\tconst parsed = Number(value);\n\tif (!Number.isSafeInteger(parsed) || parsed < minimum || parsed > maximum) {\n\t\tthrow new DaemonConfigurationError(`${name} must be a decimal integer from ${minimum} to ${maximum}`);\n\t}\n\treturn parsed;\n}\n\nfunction setSingleton(\n\tinputs: ParsedDaemonInputs,\n\tkey: keyof ParsedDaemonInputs,\n\tvalue: string | boolean,\n\tflag: string,\n): void {\n\tif (inputs[key] !== undefined) throw new DaemonConfigurationError(`${flag} may only be specified once`);\n\t(inputs as Record<keyof ParsedDaemonInputs, unknown>)[key] = value;\n}\n\nfunction requireFlagValue(args: readonly string[], index: number, flag: string): string {\n\tconst value = args[index + 1];\n\tif (value === undefined || value.startsWith(\"-\")) throw new DaemonConfigurationError(`${flag} requires a value`);\n\treturn value;\n}\n\nfunction parseInputs(args: readonly string[]): ParsedDaemonInputs {\n\tif (args[0] !== \"--daemon\") throw new DaemonConfigurationError(\"Daemon command must start with --daemon\");\n\tconst inputs: ParsedDaemonInputs = { help: false, origins: [], forwardedEnvironment: [] };\n\tfor (let index = 1; index < args.length; index++) {\n\t\tconst argument = args[index];\n\t\tif (argument === \"--help\" || argument === \"-h\") {\n\t\t\tinputs.help = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (argument === \"--daemon-origin\" || argument === \"--daemon-env\") {\n\t\t\tconst value = requireFlagValue(args, index, argument);\n\t\t\tif (argument === \"--daemon-origin\") inputs.origins.push(value);\n\t\t\telse inputs.forwardedEnvironment.push(value);\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tconst valueKey = VALUE_FLAGS.get(argument);\n\t\tif (valueKey) {\n\t\t\tsetSingleton(inputs, valueKey, requireFlagValue(args, index, argument), argument);\n\t\t\tindex++;\n\t\t\tcontinue;\n\t\t}\n\t\tconst booleanKey = BOOLEAN_FLAGS.get(argument);\n\t\tif (booleanKey) {\n\t\t\tsetSingleton(inputs, booleanKey, true, argument);\n\t\t\tcontinue;\n\t\t}\n\t\tthrow new DaemonConfigurationError(\n\t\t\targument.startsWith(\"-\")\n\t\t\t\t? `Unknown or incompatible option in daemon mode: ${argument}`\n\t\t\t\t: `Daemon mode does not accept positional arguments: ${argument}`,\n\t\t);\n\t}\n\treturn inputs;\n}\n\nfunction parseOrigin(value: string): string {\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(value);\n\t} catch {\n\t\tthrow new DaemonConfigurationError(`Invalid daemon Origin: ${value}`);\n\t}\n\tif (\n\t\t(url.protocol !== \"http:\" && url.protocol !== \"https:\") ||\n\t\turl.username !== \"\" ||\n\t\turl.password !== \"\" ||\n\t\turl.pathname !== \"/\" ||\n\t\turl.search !== \"\" ||\n\t\turl.hash !== \"\" ||\n\t\tvalue !== url.origin\n\t) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Daemon origins must be exact HTTP(S) origins without paths or wildcards: ${value}`,\n\t\t);\n\t}\n\treturn url.origin;\n}\n\nfunction parseEnvironmentNames(values: readonly string[]): string[] {\n\tconst names = values\n\t\t.flatMap((value) => value.split(\",\"))\n\t\t.map((value) => value.trim())\n\t\t.filter(Boolean);\n\tconst seen = new Set<string>();\n\tfor (const name of names) {\n\t\tif (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name))\n\t\t\tthrow new DaemonConfigurationError(`Invalid daemon environment name: ${name}`);\n\t\tconst identity = process.platform === \"win32\" ? name.toLowerCase() : name;\n\t\tif (seen.has(identity)) throw new DaemonConfigurationError(`Duplicate daemon environment name: ${name}`);\n\t\tseen.add(identity);\n\t}\n\treturn names;\n}\n\nasync function resolveConfinedRoot(value: string, startupCwd: string, label: string): Promise<string> {\n\tconst candidate = isAbsolute(value) ? value : resolve(startupCwd, value);\n\tlet canonical: string;\n\ttry {\n\t\tcanonical = await realpath(candidate);\n\t\tif (!(await stat(canonical)).isDirectory()) throw new Error(\"not a directory\");\n\t} catch (error) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Daemon ${label} must be an existing directory: ${candidate} (${error instanceof Error ? error.message : String(error)})`,\n\t\t);\n\t}\n\treturn canonical;\n}\n\nasync function readTlsFile(path: string, label: string, startupCwd: string): Promise<Buffer> {\n\tconst resolvedPath = isAbsolute(path) ? path : resolve(startupCwd, path);\n\ttry {\n\t\tconst content = await readFile(resolvedPath);\n\t\tif (content.byteLength === 0) throw new Error(\"file is empty\");\n\t\treturn content;\n\t} catch (error) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Unable to read daemon TLS ${label} file ${resolvedPath}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n}\n\nfunction validateToken(token: string | undefined): string | undefined {\n\tif (token === undefined) return undefined;\n\tconst bytes = Buffer.byteLength(token, \"utf8\");\n\tif (bytes < 32 || bytes > 1024 || !/\\S/u.test(token) || /[\\r\\n]/u.test(token)) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t\"GRIP_DAEMON_TOKEN must contain 32 to 1024 UTF-8 bytes, include a non-whitespace character, and contain no line breaks\",\n\t\t);\n\t}\n\treturn token;\n}\n\nfunction isRootProcess(): boolean {\n\treturn process.platform !== \"win32\" && typeof process.getuid === \"function\" && process.getuid() === 0;\n}\n\nexport function isDaemonCommand(args: readonly string[]): boolean {\n\treturn args[0] === \"--daemon\";\n}\ninterface DaemonEndpointConfiguration {\n\thost: string;\n\tport: number;\n}\n\ninterface DaemonWorkspaceRootsConfiguration {\n\tallowRoot: boolean;\n\tworkspaceRoot: string;\n\ttemporaryRoot: string | undefined;\n}\n\ninterface DaemonTransportSecurityConfiguration {\n\ttoken: string | undefined;\n\tallowedOrigins: string[];\n\ttls: DaemonTlsConfiguration | undefined;\n}\n\ninterface DaemonCapacityConfiguration {\n\tmaxGlobalRequests: number;\n\tmaxGlobalTransfers: number;\n\tmaxBufferedOutputBytes: number;\n\tprotocolLimits: RemoteWorkspaceProtocolLimits;\n}\n\nfunction resolveDaemonEndpoint(\n\tinputs: ParsedDaemonInputs,\n\tenvironment: NodeJS.ProcessEnv,\n): DaemonEndpointConfiguration {\n\tconst host = inputs.host ?? environment.GRIP_DAEMON_HOST ?? \"127.0.0.1\";\n\tif (host.length === 0 || /\\s/u.test(host)) {\n\t\tthrow new DaemonConfigurationError(\"Daemon host must be a non-empty IP address\");\n\t}\n\tconst port = parseInteger(\n\t\tinputs.port ?? environment.GRIP_DAEMON_PORT,\n\t\t\"GRIP_DAEMON_PORT/--daemon-port\",\n\t\t1,\n\t\t65535,\n\t\t8787,\n\t);\n\treturn { host, port };\n}\n\nasync function resolveDaemonWorkspaceRoots(\n\tinputs: ParsedDaemonInputs,\n\tenvironment: NodeJS.ProcessEnv,\n\tstartupCwd: string,\n): Promise<DaemonWorkspaceRootsConfiguration> {\n\tconst allowRoot = inputs.allowRoot ?? parseBoolean(environment.GRIP_DAEMON_ALLOW_ROOT, \"GRIP_DAEMON_ALLOW_ROOT\");\n\tif (isRootProcess() && !allowRoot) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t\"Refusing to run the workspace daemon as root; use --daemon-allow-root only inside an intentional OS sandbox\",\n\t\t);\n\t}\n\tconst workspaceRoot = await resolveConfinedRoot(\n\t\tinputs.cwd ?? environment.GRIP_DAEMON_CWD ?? startupCwd,\n\t\tstartupCwd,\n\t\t\"workspace root\",\n\t);\n\tconst temporaryRoot = environment.GRIP_DAEMON_TEMP_ROOT\n\t\t? await resolveConfinedRoot(environment.GRIP_DAEMON_TEMP_ROOT, startupCwd, \"temporary root\")\n\t\t: undefined;\n\treturn { allowRoot, workspaceRoot, temporaryRoot };\n}\n\nasync function resolveSharedParentRoot(\n\tinputs: ParsedDaemonInputs,\n\tenvironment: NodeJS.ProcessEnv,\n\tstartupCwd: string,\n\tworkspaceRoot: string,\n): Promise<string | undefined> {\n\tconst value = inputs.sharedParent ?? environment.GRIP_DAEMON_SHARED_PARENT;\n\tif (value === undefined) return undefined;\n\tif (value === \"\") throw new DaemonConfigurationError(\"Shared parent mount must not be empty\");\n\tconst root = await resolveConfinedRoot(value, startupCwd, \"shared parent mount\");\n\tif (root !== workspaceRoot) {\n\t\tthrow new DaemonConfigurationError(\"Shared parent mount must equal --daemon-cwd (the fixed mounted parent)\");\n\t}\n\treturn root;\n}\n\nasync function resolveDaemonTransportSecurity(\n\tinputs: ParsedDaemonInputs,\n\tenvironment: NodeJS.ProcessEnv,\n\tstartupCwd: string,\n): Promise<DaemonTransportSecurityConfiguration> {\n\tconst token = validateToken(environment.GRIP_DAEMON_TOKEN);\n\tconst allowedOrigins = [\n\t\t...(environment.GRIP_DAEMON_ORIGINS?.split(\",\")\n\t\t\t.map((value) => value.trim())\n\t\t\t.filter(Boolean) ?? []),\n\t\t...inputs.origins,\n\t].map(parseOrigin);\n\tif (new Set(allowedOrigins).size !== allowedOrigins.length) {\n\t\tthrow new DaemonConfigurationError(\"Daemon origins must be unique\");\n\t}\n\tconst tlsCertPath = inputs.tlsCertPath ?? environment.GRIP_DAEMON_TLS_CERT;\n\tconst tlsKeyPath = inputs.tlsKeyPath ?? environment.GRIP_DAEMON_TLS_KEY;\n\tif ((tlsCertPath === undefined) !== (tlsKeyPath === undefined)) {\n\t\tthrow new DaemonConfigurationError(\"Daemon TLS requires both a certificate and private key\");\n\t}\n\tconst tls =\n\t\ttlsCertPath && tlsKeyPath\n\t\t\t? Object.freeze({\n\t\t\t\t\tcert: await readTlsFile(tlsCertPath, \"certificate\", startupCwd),\n\t\t\t\t\tkey: await readTlsFile(tlsKeyPath, \"private key\", startupCwd),\n\t\t\t\t\tpassphrase: environment.GRIP_DAEMON_TLS_PASSPHRASE,\n\t\t\t\t})\n\t\t\t: undefined;\n\treturn { token, allowedOrigins, tls };\n}\n\nfunction resolveDaemonCapacity(environment: NodeJS.ProcessEnv): DaemonCapacityConfiguration {\n\tconst maxConnectionRequests = parseInteger(\n\t\tenvironment.GRIP_DAEMON_MAX_CONNECTION_REQUESTS,\n\t\t\"GRIP_DAEMON_MAX_CONNECTION_REQUESTS\",\n\t\t1,\n\t\t10_000_000,\n\t\tDEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS.maxActiveRequests,\n\t);\n\tconst maxGlobalRequests = parseInteger(\n\t\tenvironment.GRIP_DAEMON_MAX_GLOBAL_REQUESTS,\n\t\t\"GRIP_DAEMON_MAX_GLOBAL_REQUESTS\",\n\t\t1,\n\t\t10_000_000,\n\t\tmaxConnectionRequests,\n\t);\n\tif (maxGlobalRequests < maxConnectionRequests) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t\"GRIP_DAEMON_MAX_GLOBAL_REQUESTS must be at least GRIP_DAEMON_MAX_CONNECTION_REQUESTS\",\n\t\t);\n\t}\n\tconst maxConnectionTransfers = parseInteger(\n\t\tenvironment.GRIP_DAEMON_MAX_CONNECTION_UPLOADS,\n\t\t\"GRIP_DAEMON_MAX_CONNECTION_UPLOADS\",\n\t\t1,\n\t\t10_000,\n\t\tDEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS.maxActiveTransfers,\n\t);\n\tconst maxGlobalTransfers = parseInteger(\n\t\tenvironment.GRIP_DAEMON_MAX_GLOBAL_UPLOADS,\n\t\t\"GRIP_DAEMON_MAX_GLOBAL_UPLOADS\",\n\t\t1,\n\t\t10_000,\n\t\tmaxConnectionTransfers,\n\t);\n\tif (maxGlobalTransfers < maxConnectionTransfers) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t\"GRIP_DAEMON_MAX_GLOBAL_UPLOADS must be at least GRIP_DAEMON_MAX_CONNECTION_UPLOADS\",\n\t\t);\n\t}\n\tconst maxMessageBytes = parseInteger(\n\t\tenvironment.GRIP_DAEMON_MAX_FRAME_BYTES,\n\t\t\"GRIP_DAEMON_MAX_FRAME_BYTES\",\n\t\t1024,\n\t\t64 * 1024 * 1024,\n\t\tDEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS.maxMessageBytes,\n\t);\n\tconst maxTransferBytes = parseInteger(\n\t\tenvironment.GRIP_DAEMON_MAX_UPLOAD_BYTES,\n\t\t\"GRIP_DAEMON_MAX_UPLOAD_BYTES\",\n\t\t1,\n\t\tNumber.MAX_SAFE_INTEGER,\n\t\tDEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS.maxTransferBytes,\n\t);\n\tconst maxBufferedOutputBytes = parseInteger(\n\t\tenvironment.GRIP_DAEMON_MAX_BUFFERED_OUTPUT_BYTES,\n\t\t\"GRIP_DAEMON_MAX_BUFFERED_OUTPUT_BYTES\",\n\t\t1024,\n\t\t64 * 1024 * 1024,\n\t\t8 * 1024 * 1024,\n\t);\n\tconst protocolLimits = validateRemoteWorkspaceProtocolLimits({\n\t\t...DEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS,\n\t\tmaxMessageBytes,\n\t\tmaxStringBytes: Math.min(DEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS.maxStringBytes, maxMessageBytes),\n\t\tmaxPendingInboundBytes: Math.max(\n\t\t\tDEFAULT_REMOTE_WORKSPACE_PROTOCOL_LIMITS.maxPendingInboundBytes,\n\t\t\tmaxMessageBytes,\n\t\t),\n\t\tmaxTransferBytes,\n\t\tmaxActiveRequests: maxConnectionRequests,\n\t\tmaxActiveTransfers: Math.min(maxConnectionTransfers, maxGlobalTransfers),\n\t});\n\treturn { maxGlobalRequests, maxGlobalTransfers, maxBufferedOutputBytes, protocolLimits };\n}\n\nexport async function parseDaemonCommand(\n\targs: readonly string[],\n\tenvironment: NodeJS.ProcessEnv = process.env,\n\tstartupCwd = process.cwd(),\n): Promise<DaemonCommand> {\n\tconst inputs = parseInputs(args);\n\tif (inputs.help) return { help: true };\n\n\tconst { host, port } = resolveDaemonEndpoint(inputs, environment);\n\tconst { allowRoot, workspaceRoot, temporaryRoot } = await resolveDaemonWorkspaceRoots(\n\t\tinputs,\n\t\tenvironment,\n\t\tstartupCwd,\n\t);\n\tconst sharedParentRoot = await resolveSharedParentRoot(inputs, environment, startupCwd, workspaceRoot);\n\tconst { token, allowedOrigins, tls } = await resolveDaemonTransportSecurity(inputs, environment, startupCwd);\n\tconst { maxGlobalRequests, maxGlobalTransfers, maxBufferedOutputBytes, protocolLimits } =\n\t\tresolveDaemonCapacity(environment);\n\n\tconst allowInsecureTransport =\n\t\tinputs.allowInsecureTransport ??\n\t\tparseBoolean(environment.GRIP_DAEMON_ALLOW_INSECURE_TRANSPORT, \"GRIP_DAEMON_ALLOW_INSECURE_TRANSPORT\");\n\tconst allowProcessExec =\n\t\tinputs.allowProcessExec ??\n\t\tparseBoolean(environment.GRIP_DAEMON_ALLOW_PROCESS_EXEC, \"GRIP_DAEMON_ALLOW_PROCESS_EXEC\");\n\tconst allowFullFilesystem =\n\t\tinputs.allowFullFilesystem ??\n\t\tparseBoolean(environment.GRIP_DAEMON_ALLOW_FULL_FILESYSTEM, \"GRIP_DAEMON_ALLOW_FULL_FILESYSTEM\");\n\tconst trustProjectLsp =\n\t\tinputs.trustProjectLsp ??\n\t\tparseBoolean(environment.GRIP_DAEMON_TRUST_PROJECT_LSP, \"GRIP_DAEMON_TRUST_PROJECT_LSP\");\n\tconst forwardedEnvironment = parseEnvironmentNames([\n\t\t...(environment.GRIP_DAEMON_ENV?.split(\",\") ?? []),\n\t\t...inputs.forwardedEnvironment,\n\t]);\n\tconst maxConnections = parseInteger(\n\t\tinputs.maxConnections ?? environment.GRIP_DAEMON_MAX_CONNECTIONS,\n\t\t\"GRIP_DAEMON_MAX_CONNECTIONS/--daemon-max-connections\",\n\t\t1,\n\t\t100_000,\n\t\t64,\n\t);\n\tconst maxPendingConnections = parseInteger(\n\t\tinputs.maxPendingConnections ?? environment.GRIP_DAEMON_MAX_PENDING_CONNECTIONS,\n\t\t\"GRIP_DAEMON_MAX_PENDING_CONNECTIONS/--daemon-max-pending-connections\",\n\t\t1,\n\t\t100_000,\n\t\t64,\n\t);\n\tconst handshakeTimeoutMs = parseInteger(\n\t\tinputs.handshakeTimeoutMs ?? environment.GRIP_DAEMON_HANDSHAKE_TIMEOUT_MS,\n\t\t\"GRIP_DAEMON_HANDSHAKE_TIMEOUT_MS/--daemon-handshake-timeout-ms\",\n\t\t100,\n\t\t5 * 60_000,\n\t\t10_000,\n\t);\n\tconst shutdownTimeoutMs = parseInteger(\n\t\tinputs.shutdownTimeoutMs ?? environment.GRIP_DAEMON_SHUTDOWN_TIMEOUT_MS,\n\t\t\"GRIP_DAEMON_SHUTDOWN_TIMEOUT_MS/--daemon-shutdown-timeout-ms\",\n\t\t100,\n\t\t5 * 60_000,\n\t\t10_000,\n\t);\n\n\treturn {\n\t\thelp: false,\n\t\tconfiguration: Object.freeze({\n\t\t\thost,\n\t\t\tport,\n\t\t\tworkspaceRoot,\n\t\t\tsharedParentRoot,\n\t\t\ttemporaryRoot,\n\t\t\tallowFullFilesystem,\n\t\t\ttoken,\n\t\t\tallowedOrigins: Object.freeze(allowedOrigins),\n\t\t\ttls,\n\t\t\tallowInsecureTransport,\n\t\t\tallowProcessExec,\n\t\t\tallowRoot,\n\t\t\tforwardedEnvironment: Object.freeze(forwardedEnvironment),\n\t\t\tlspConfigPath:\n\t\t\t\tinputs.lspConfigPath || environment.GRIP_DAEMON_LSP_CONFIG\n\t\t\t\t\t? resolve(startupCwd, inputs.lspConfigPath ?? environment.GRIP_DAEMON_LSP_CONFIG!)\n\t\t\t\t\t: undefined,\n\t\t\ttrustProjectLsp,\n\t\t\tsandboxInstructionsPath: environment.GRIP_DAEMON_SANDBOX_INSTRUCTIONS\n\t\t\t\t? resolve(startupCwd, environment.GRIP_DAEMON_SANDBOX_INSTRUCTIONS)\n\t\t\t\t: undefined,\n\t\t\tuserAgentsPath: environment.HOME ? join(environment.HOME, \".grip\", \"AGENTS.md\") : undefined,\n\t\t\tmaxConnections,\n\t\t\tmaxGlobalRequests,\n\t\t\tmaxGlobalTransfers,\n\t\t\tmaxBufferedOutputBytes,\n\t\t\tmaxPendingConnections,\n\t\t\thandshakeTimeoutMs,\n\t\t\tshutdownTimeoutMs,\n\t\t\tprotocolLimits: Object.freeze({ ...protocolLimits }),\n\t\t}),\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/daemon/help.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe,CAAC,KAAK,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAkB,GAAG,IAAI,CAuCpF","sourcesContent":["import { APP_NAME } from \"../config.ts\";\n\nexport function printDaemonHelp(write: (message: string) => void = console.log): void {\n\twrite(`${APP_NAME} --daemon - remote workspace runtime\n\nUsage:\n ${APP_NAME} --daemon [options]\n\nOptions:\n --daemon-host <ip> Bind IP (default: 127.0.0.1)\n --daemon-port <port> Bind port (default: 8787)\n --daemon-cwd <directory> Confined workspace root (default: current directory)\n --daemon-origin <origin> Allow an exact browser Origin (repeatable)\n --daemon-tls-cert <file> Native TLS certificate\n --daemon-tls-key <file> Native TLS private key\n --daemon-allow-insecure-transport Acknowledge non-loopback transport without native TLS\n --daemon-allow-process-exec Enable the unsafe process-execution capability\n --daemon-allow-root Allow running as root inside an intentional OS sandbox\n --daemon-env <NAME> Forward an approved environment name (repeatable)\n --daemon-lsp-config <file> Operator-owned daemon LSP configuration\n --daemon-trust-project-lsp Trust the confined project LSP layer\n --daemon-max-connections <count> Maximum authenticated clients\n --daemon-max-pending-connections <n> Maximum incomplete HTTP/WebSocket handshakes\n --daemon-handshake-timeout-ms <ms> Protocol handshake deadline\n --daemon-shutdown-timeout-ms <ms> Graceful shutdown deadline\n --help, -h Show daemon help\n\nEnvironment:\n GRIP_DAEMON_HOST, GRIP_DAEMON_PORT, GRIP_DAEMON_CWD\n GRIP_DAEMON_TEMP_ROOT Optional additional confined temporary directory\n GRIP_DAEMON_TOKEN Server bearer token (32-1024 UTF-8 bytes)\n GRIP_DAEMON_ORIGINS Comma-separated exact browser origins\n GRIP_DAEMON_TLS_CERT, GRIP_DAEMON_TLS_KEY, GRIP_DAEMON_TLS_PASSPHRASE\n GRIP_DAEMON_ALLOW_INSECURE_TRANSPORT, GRIP_DAEMON_ALLOW_PROCESS_EXEC, GRIP_DAEMON_ALLOW_ROOT\n GRIP_DAEMON_ENV, GRIP_DAEMON_LSP_CONFIG, GRIP_DAEMON_TRUST_PROJECT_LSP\n GRIP_DAEMON_MAX_CONNECTIONS, GRIP_DAEMON_MAX_PENDING_CONNECTIONS\n GRIP_DAEMON_HANDSHAKE_TIMEOUT_MS, GRIP_DAEMON_SHUTDOWN_TIMEOUT_MS\n\nSecurity:\n Non-loopback binds require GRIP_DAEMON_TOKEN and TLS unless insecure transport is explicitly acknowledged.\n Process execution is an RCE capability and requires OS-level isolation.`);\n}\n"]}
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../src/daemon/help.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe,CAAC,KAAK,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAkB,GAAG,IAAI,CAwCpF"}
@@ -8,12 +8,13 @@ Usage:
8
8
  Options:
9
9
  --daemon-host <ip> Bind IP (default: 127.0.0.1)
10
10
  --daemon-port <port> Bind port (default: 8787)
11
- --daemon-cwd <directory> Confined workspace root (default: current directory)
11
+ --daemon-cwd <directory> Workspace root and default filesystem boundary (default: current directory)
12
12
  --daemon-origin <origin> Allow an exact browser Origin (repeatable)
13
13
  --daemon-tls-cert <file> Native TLS certificate
14
14
  --daemon-tls-key <file> Native TLS private key
15
15
  --daemon-allow-insecure-transport Acknowledge non-loopback transport without native TLS
16
16
  --daemon-allow-process-exec Enable the unsafe process-execution capability
17
+ --daemon-allow-full-filesystem Allow workspace tools to access the entire daemon filesystem (isolated guests only)
17
18
  --daemon-allow-root Allow running as root inside an intentional OS sandbox
18
19
  --daemon-env <NAME> Forward an approved environment name (repeatable)
19
20
  --daemon-lsp-config <file> Operator-owned daemon LSP configuration
@@ -31,12 +32,12 @@ Environment:
31
32
  GRIP_DAEMON_ORIGINS Comma-separated exact browser origins
32
33
  GRIP_DAEMON_TLS_CERT, GRIP_DAEMON_TLS_KEY, GRIP_DAEMON_TLS_PASSPHRASE
33
34
  GRIP_DAEMON_ALLOW_INSECURE_TRANSPORT, GRIP_DAEMON_ALLOW_PROCESS_EXEC, GRIP_DAEMON_ALLOW_ROOT
34
- GRIP_DAEMON_ENV, GRIP_DAEMON_LSP_CONFIG, GRIP_DAEMON_TRUST_PROJECT_LSP
35
+ GRIP_DAEMON_ENV, GRIP_DAEMON_LSP_CONFIG, GRIP_DAEMON_TRUST_PROJECT_LSP, GRIP_DAEMON_ALLOW_FULL_FILESYSTEM
35
36
  GRIP_DAEMON_MAX_CONNECTIONS, GRIP_DAEMON_MAX_PENDING_CONNECTIONS
36
37
  GRIP_DAEMON_HANDSHAKE_TIMEOUT_MS, GRIP_DAEMON_SHUTDOWN_TIMEOUT_MS
37
38
 
38
39
  Security:
39
40
  Non-loopback binds require GRIP_DAEMON_TOKEN and TLS unless insecure transport is explicitly acknowledged.
40
- Process execution is an RCE capability and requires OS-level isolation.`);
41
+ Process execution and full-filesystem access require OS-level isolation.`);
41
42
  }
42
43
  //# sourceMappingURL=help.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/daemon/help.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,MAAM,UAAU,eAAe,CAAC,KAAK,GAA8B,OAAO,CAAC,GAAG,EAAQ;IACrF,KAAK,CAAC,GAAG,QAAQ;;;IAGd,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;0EAkC8D,CAAC,CAAC;AAAA,CAC3E","sourcesContent":["import { APP_NAME } from \"../config.ts\";\n\nexport function printDaemonHelp(write: (message: string) => void = console.log): void {\n\twrite(`${APP_NAME} --daemon - remote workspace runtime\n\nUsage:\n ${APP_NAME} --daemon [options]\n\nOptions:\n --daemon-host <ip> Bind IP (default: 127.0.0.1)\n --daemon-port <port> Bind port (default: 8787)\n --daemon-cwd <directory> Confined workspace root (default: current directory)\n --daemon-origin <origin> Allow an exact browser Origin (repeatable)\n --daemon-tls-cert <file> Native TLS certificate\n --daemon-tls-key <file> Native TLS private key\n --daemon-allow-insecure-transport Acknowledge non-loopback transport without native TLS\n --daemon-allow-process-exec Enable the unsafe process-execution capability\n --daemon-allow-root Allow running as root inside an intentional OS sandbox\n --daemon-env <NAME> Forward an approved environment name (repeatable)\n --daemon-lsp-config <file> Operator-owned daemon LSP configuration\n --daemon-trust-project-lsp Trust the confined project LSP layer\n --daemon-max-connections <count> Maximum authenticated clients\n --daemon-max-pending-connections <n> Maximum incomplete HTTP/WebSocket handshakes\n --daemon-handshake-timeout-ms <ms> Protocol handshake deadline\n --daemon-shutdown-timeout-ms <ms> Graceful shutdown deadline\n --help, -h Show daemon help\n\nEnvironment:\n GRIP_DAEMON_HOST, GRIP_DAEMON_PORT, GRIP_DAEMON_CWD\n GRIP_DAEMON_TEMP_ROOT Optional additional confined temporary directory\n GRIP_DAEMON_TOKEN Server bearer token (32-1024 UTF-8 bytes)\n GRIP_DAEMON_ORIGINS Comma-separated exact browser origins\n GRIP_DAEMON_TLS_CERT, GRIP_DAEMON_TLS_KEY, GRIP_DAEMON_TLS_PASSPHRASE\n GRIP_DAEMON_ALLOW_INSECURE_TRANSPORT, GRIP_DAEMON_ALLOW_PROCESS_EXEC, GRIP_DAEMON_ALLOW_ROOT\n GRIP_DAEMON_ENV, GRIP_DAEMON_LSP_CONFIG, GRIP_DAEMON_TRUST_PROJECT_LSP\n GRIP_DAEMON_MAX_CONNECTIONS, GRIP_DAEMON_MAX_PENDING_CONNECTIONS\n GRIP_DAEMON_HANDSHAKE_TIMEOUT_MS, GRIP_DAEMON_SHUTDOWN_TIMEOUT_MS\n\nSecurity:\n Non-loopback binds require GRIP_DAEMON_TOKEN and TLS unless insecure transport is explicitly acknowledged.\n Process execution is an RCE capability and requires OS-level isolation.`);\n}\n"]}
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/daemon/help.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAExC,MAAM,UAAU,eAAe,CAAC,KAAK,GAA8B,OAAO,CAAC,GAAG;IAC7E,KAAK,CAAC,GAAG,QAAQ;;;IAGd,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2EAmC+D,CAAC,CAAC;AAC7E,CAAC","sourcesContent":["import { APP_NAME } from \"../config.ts\";\n\nexport function printDaemonHelp(write: (message: string) => void = console.log): void {\n\twrite(`${APP_NAME} --daemon - remote workspace runtime\n\nUsage:\n ${APP_NAME} --daemon [options]\n\nOptions:\n --daemon-host <ip> Bind IP (default: 127.0.0.1)\n --daemon-port <port> Bind port (default: 8787)\n --daemon-cwd <directory> Workspace root and default filesystem boundary (default: current directory)\n --daemon-origin <origin> Allow an exact browser Origin (repeatable)\n --daemon-tls-cert <file> Native TLS certificate\n --daemon-tls-key <file> Native TLS private key\n --daemon-allow-insecure-transport Acknowledge non-loopback transport without native TLS\n --daemon-allow-process-exec Enable the unsafe process-execution capability\n --daemon-allow-full-filesystem Allow workspace tools to access the entire daemon filesystem (isolated guests only)\n --daemon-allow-root Allow running as root inside an intentional OS sandbox\n --daemon-env <NAME> Forward an approved environment name (repeatable)\n --daemon-lsp-config <file> Operator-owned daemon LSP configuration\n --daemon-trust-project-lsp Trust the confined project LSP layer\n --daemon-max-connections <count> Maximum authenticated clients\n --daemon-max-pending-connections <n> Maximum incomplete HTTP/WebSocket handshakes\n --daemon-handshake-timeout-ms <ms> Protocol handshake deadline\n --daemon-shutdown-timeout-ms <ms> Graceful shutdown deadline\n --help, -h Show daemon help\n\nEnvironment:\n GRIP_DAEMON_HOST, GRIP_DAEMON_PORT, GRIP_DAEMON_CWD\n GRIP_DAEMON_TEMP_ROOT Optional additional confined temporary directory\n GRIP_DAEMON_TOKEN Server bearer token (32-1024 UTF-8 bytes)\n GRIP_DAEMON_ORIGINS Comma-separated exact browser origins\n GRIP_DAEMON_TLS_CERT, GRIP_DAEMON_TLS_KEY, GRIP_DAEMON_TLS_PASSPHRASE\n GRIP_DAEMON_ALLOW_INSECURE_TRANSPORT, GRIP_DAEMON_ALLOW_PROCESS_EXEC, GRIP_DAEMON_ALLOW_ROOT\n GRIP_DAEMON_ENV, GRIP_DAEMON_LSP_CONFIG, GRIP_DAEMON_TRUST_PROJECT_LSP, GRIP_DAEMON_ALLOW_FULL_FILESYSTEM\n GRIP_DAEMON_MAX_CONNECTIONS, GRIP_DAEMON_MAX_PENDING_CONNECTIONS\n GRIP_DAEMON_HANDSHAKE_TIMEOUT_MS, GRIP_DAEMON_SHUTDOWN_TIMEOUT_MS\n\nSecurity:\n Non-loopback binds require GRIP_DAEMON_TOKEN and TLS unless insecure transport is explicitly acknowledged.\n Process execution and full-filesystem access require OS-level isolation.`);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"lsp-config.d.ts","sourceRoot":"","sources":["../../src/daemon/lsp-config.ts"],"names":[],"mappings":"AAEA,OAAO,EAMN,KAAK,wBAAwB,EAE7B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,KAAK,mBAAmB,EAA4B,MAAM,aAAa,CAAC;AA+JjF,wBAAgB,0BAA0B,CAAC,aAAa,EAAE,mBAAmB,GAAG,wBAAwB,CAoBvG","sourcesContent":["import { lstatSync, readFileSync, realpathSync } from \"node:fs\";\nimport { dirname, isAbsolute, relative, resolve } from \"node:path\";\nimport {\n\ttype LspConfigurationLayer,\n\ttype LspConfiguredServer,\n\ttype LspTransport,\n\ttype LspWorkspaceRoot,\n\tparseLspConfiguration,\n\ttype ResolvedLspConfiguration,\n\tresolveLspConfiguration,\n} from \"../core/lsp/config.ts\";\nimport { resolveLspConfigurationLayerPaths } from \"../core/lsp/config-loader.ts\";\nimport { relativeWithin } from \"../core/lsp/portable-path.ts\";\nimport { type DaemonConfiguration, DaemonConfigurationError } from \"./config.ts\";\n\nconst DISABLED_LSP_CONFIGURATION: ResolvedLspConfiguration = { enabled: false, servers: [] };\n\nfunction readJson(path: string, optional = false): unknown | undefined {\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, \"utf8\")) as unknown;\n\t} catch (error) {\n\t\tif (optional && error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return undefined;\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Unable to load daemon LSP configuration ${path}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n}\n\nfunction parseLayer(value: unknown, source: string, baseDir: string): LspConfigurationLayer {\n\tconst parsed = parseLspConfiguration(value);\n\tif (!parsed.configuration) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Invalid daemon LSP configuration ${source}: ${parsed.diagnostics.map((item) => `${item.path}: ${item.message}`).join(\"; \")}`,\n\t\t);\n\t}\n\tconst resolved = parseLspConfiguration(resolveLspConfigurationLayerPaths(parsed.configuration, baseDir));\n\tif (!resolved.configuration) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Invalid resolved daemon LSP configuration ${source}: ${resolved.diagnostics.map((item) => `${item.path}: ${item.message}`).join(\"; \")}`,\n\t\t);\n\t}\n\treturn resolved.configuration;\n}\n\nfunction isMissingPathError(error: unknown): boolean {\n\treturn error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\n\nfunction validateExistingLspPath(path: string, requestedPath: string, label: string): boolean {\n\tlet isSymbolicLink: boolean;\n\ttry {\n\t\tisSymbolicLink = lstatSync(path).isSymbolicLink();\n\t} catch (error) {\n\t\tif (isMissingPathError(error)) return false;\n\t\tthrow error;\n\t}\n\tif (!isSymbolicLink) return true;\n\ttry {\n\t\trealpathSync(path);\n\t} catch {\n\t\tthrow new DaemonConfigurationError(`${label} uses a broken symbolic link: ${requestedPath}`);\n\t}\n\treturn true;\n}\n\nfunction findExistingLspPathAncestor(path: string, label: string): string {\n\tlet existing = path;\n\twhile (!validateExistingLspPath(existing, path, label)) {\n\t\tconst parent = dirname(existing);\n\t\tif (parent === existing) break;\n\t\texisting = parent;\n\t}\n\treturn existing;\n}\n\nfunction requireConfinedPath(path: string, configuration: DaemonConfiguration, label: string): string {\n\tconst existing = findExistingLspPathAncestor(path, label);\n\tconst canonicalExisting = realpathSync(existing);\n\tif (relativeWithin(configuration.workspaceRoot, canonicalExisting) === undefined) {\n\t\tthrow new DaemonConfigurationError(`${label} escapes the daemon workspace: ${path}`);\n\t}\n\tif (existing === path) return canonicalExisting;\n\treturn resolve(canonicalExisting, relative(existing, path));\n}\n\nfunction canonicalizeDaemonLspServer(\n\tserver: LspConfiguredServer,\n\tconfiguration: DaemonConfiguration,\n\ttransport: LspTransport,\n\tworkspace: LspWorkspaceRoot,\n): LspConfiguredServer {\n\treturn {\n\t\t...server,\n\t\ttransport,\n\t\tworkspace,\n\t\t...(server.pathMappings\n\t\t\t? {\n\t\t\t\t\tpathMappings: server.pathMappings.map((mapping) => ({\n\t\t\t\t\t\t...mapping,\n\t\t\t\t\t\tagentRoot: requireConfinedPath(mapping.agentRoot, configuration, `LSP path mapping for ${server.id}`),\n\t\t\t\t\t})),\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n}\nfunction canonicalizeDaemonLspTransport(server: LspConfiguredServer, configuration: DaemonConfiguration): LspTransport {\n\tif (server.transport.type === \"connection\") {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Daemon LSP server ${JSON.stringify(server.id)} cannot use a host-provided connection transport`,\n\t\t);\n\t}\n\tif (server.transport.type === \"spawn\") {\n\t\tif (!configuration.allowProcessExec) {\n\t\t\tthrow new DaemonConfigurationError(\n\t\t\t\t`Daemon LSP server ${JSON.stringify(server.id)} requires --daemon-allow-process-exec`,\n\t\t\t);\n\t\t}\n\t\treturn {\n\t\t\t...server.transport,\n\t\t\t...(server.transport.cwd\n\t\t\t\t? { cwd: requireConfinedPath(server.transport.cwd, configuration, `LSP cwd for ${server.id}`) }\n\t\t\t\t: {}),\n\t\t\t...(isAbsolute(server.transport.command)\n\t\t\t\t? {\n\t\t\t\t\t\tcommand: requireConfinedPath(server.transport.command, configuration, `LSP command for ${server.id}`),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t};\n\t}\n\tif (server.transport.type === \"unix\") {\n\t\treturn {\n\t\t\t...server.transport,\n\t\t\tpath: requireConfinedPath(server.transport.path, configuration, `LSP socket for ${server.id}`),\n\t\t};\n\t}\n\treturn server.transport;\n}\n\nfunction canonicalizeDaemonLspWorkspace(\n\tserver: LspConfiguredServer,\n\tconfiguration: DaemonConfiguration,\n): LspWorkspaceRoot {\n\tif (server.workspace.type === \"fixed\") {\n\t\treturn {\n\t\t\t...server.workspace,\n\t\t\tpath: requireConfinedPath(server.workspace.path, configuration, `LSP workspace for ${server.id}`),\n\t\t};\n\t}\n\tif (server.workspace.type === \"markers\" && server.workspace.stopAt) {\n\t\treturn {\n\t\t\t...server.workspace,\n\t\t\tstopAt: requireConfinedPath(server.workspace.stopAt, configuration, `LSP marker boundary for ${server.id}`),\n\t\t};\n\t}\n\treturn server.workspace;\n}\n\nfunction canonicalizeDaemonPolicy(\n\tconfiguration: DaemonConfiguration,\n\tresolved: ResolvedLspConfiguration,\n): ResolvedLspConfiguration {\n\tconst servers = resolved.servers.map((server) =>\n\t\tcanonicalizeDaemonLspServer(\n\t\t\tserver,\n\t\t\tconfiguration,\n\t\t\tcanonicalizeDaemonLspTransport(server, configuration),\n\t\t\tcanonicalizeDaemonLspWorkspace(server, configuration),\n\t\t),\n\t);\n\treturn { enabled: resolved.enabled, servers };\n}\n\nexport function loadDaemonLspConfiguration(configuration: DaemonConfiguration): ResolvedLspConfiguration {\n\tconst layers: LspConfigurationLayer[] = [];\n\tif (configuration.trustProjectLsp) {\n\t\tconst projectSettingsPath = resolve(configuration.workspaceRoot, \".grip\", \"settings.json\");\n\t\tconst settings = readJson(projectSettingsPath, true);\n\t\tif (settings !== undefined) {\n\t\t\tif (typeof settings !== \"object\" || settings === null || Array.isArray(settings)) {\n\t\t\t\tthrow new DaemonConfigurationError(`Invalid project settings for daemon LSP: ${projectSettingsPath}`);\n\t\t\t}\n\t\t\tconst lsp = (settings as { lsp?: unknown }).lsp;\n\t\t\tif (lsp !== undefined)\n\t\t\t\tlayers.push(parseLayer(lsp, projectSettingsPath, resolve(configuration.workspaceRoot, \".grip\")));\n\t\t}\n\t}\n\tif (configuration.lspConfigPath) {\n\t\tconst value = readJson(configuration.lspConfigPath);\n\t\tlayers.push(parseLayer(value, configuration.lspConfigPath, resolve(configuration.lspConfigPath, \"..\")));\n\t}\n\tconst resolved = layers.length === 0 ? DISABLED_LSP_CONFIGURATION : resolveLspConfiguration(layers);\n\treturn canonicalizeDaemonPolicy(configuration, resolved);\n}\n"]}
1
+ {"version":3,"file":"lsp-config.d.ts","sourceRoot":"","sources":["../../src/daemon/lsp-config.ts"],"names":[],"mappings":"AAEA,OAAO,EAMN,KAAK,wBAAwB,EAE7B,MAAM,uBAAuB,CAAC;AAG/B,OAAO,EAAE,KAAK,mBAAmB,EAA4B,MAAM,aAAa,CAAC;AA+JjF,wBAAgB,0BAA0B,CAAC,aAAa,EAAE,mBAAmB,GAAG,wBAAwB,CAoBvG"}
@@ -1 +1 @@
1
- {"version":3,"file":"lsp-config.js","sourceRoot":"","sources":["../../src/daemon/lsp-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { lstatSync, readFileSync, realpathSync } from \"node:fs\";\nimport { dirname, isAbsolute, relative, resolve } from \"node:path\";\nimport {\n\ttype LspConfigurationLayer,\n\ttype LspConfiguredServer,\n\ttype LspTransport,\n\ttype LspWorkspaceRoot,\n\tparseLspConfiguration,\n\ttype ResolvedLspConfiguration,\n\tresolveLspConfiguration,\n} from \"../core/lsp/config.ts\";\nimport { resolveLspConfigurationLayerPaths } from \"../core/lsp/config-loader.ts\";\nimport { relativeWithin } from \"../core/lsp/portable-path.ts\";\nimport { type DaemonConfiguration, DaemonConfigurationError } from \"./config.ts\";\n\nconst DISABLED_LSP_CONFIGURATION: ResolvedLspConfiguration = { enabled: false, servers: [] };\n\nfunction readJson(path: string, optional = false): unknown | undefined {\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, \"utf8\")) as unknown;\n\t} catch (error) {\n\t\tif (optional && error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return undefined;\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Unable to load daemon LSP configuration ${path}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n}\n\nfunction parseLayer(value: unknown, source: string, baseDir: string): LspConfigurationLayer {\n\tconst parsed = parseLspConfiguration(value);\n\tif (!parsed.configuration) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Invalid daemon LSP configuration ${source}: ${parsed.diagnostics.map((item) => `${item.path}: ${item.message}`).join(\"; \")}`,\n\t\t);\n\t}\n\tconst resolved = parseLspConfiguration(resolveLspConfigurationLayerPaths(parsed.configuration, baseDir));\n\tif (!resolved.configuration) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Invalid resolved daemon LSP configuration ${source}: ${resolved.diagnostics.map((item) => `${item.path}: ${item.message}`).join(\"; \")}`,\n\t\t);\n\t}\n\treturn resolved.configuration;\n}\n\nfunction isMissingPathError(error: unknown): boolean {\n\treturn error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\n\nfunction validateExistingLspPath(path: string, requestedPath: string, label: string): boolean {\n\tlet isSymbolicLink: boolean;\n\ttry {\n\t\tisSymbolicLink = lstatSync(path).isSymbolicLink();\n\t} catch (error) {\n\t\tif (isMissingPathError(error)) return false;\n\t\tthrow error;\n\t}\n\tif (!isSymbolicLink) return true;\n\ttry {\n\t\trealpathSync(path);\n\t} catch {\n\t\tthrow new DaemonConfigurationError(`${label} uses a broken symbolic link: ${requestedPath}`);\n\t}\n\treturn true;\n}\n\nfunction findExistingLspPathAncestor(path: string, label: string): string {\n\tlet existing = path;\n\twhile (!validateExistingLspPath(existing, path, label)) {\n\t\tconst parent = dirname(existing);\n\t\tif (parent === existing) break;\n\t\texisting = parent;\n\t}\n\treturn existing;\n}\n\nfunction requireConfinedPath(path: string, configuration: DaemonConfiguration, label: string): string {\n\tconst existing = findExistingLspPathAncestor(path, label);\n\tconst canonicalExisting = realpathSync(existing);\n\tif (relativeWithin(configuration.workspaceRoot, canonicalExisting) === undefined) {\n\t\tthrow new DaemonConfigurationError(`${label} escapes the daemon workspace: ${path}`);\n\t}\n\tif (existing === path) return canonicalExisting;\n\treturn resolve(canonicalExisting, relative(existing, path));\n}\n\nfunction canonicalizeDaemonLspServer(\n\tserver: LspConfiguredServer,\n\tconfiguration: DaemonConfiguration,\n\ttransport: LspTransport,\n\tworkspace: LspWorkspaceRoot,\n): LspConfiguredServer {\n\treturn {\n\t\t...server,\n\t\ttransport,\n\t\tworkspace,\n\t\t...(server.pathMappings\n\t\t\t? {\n\t\t\t\t\tpathMappings: server.pathMappings.map((mapping) => ({\n\t\t\t\t\t\t...mapping,\n\t\t\t\t\t\tagentRoot: requireConfinedPath(mapping.agentRoot, configuration, `LSP path mapping for ${server.id}`),\n\t\t\t\t\t})),\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n}\nfunction canonicalizeDaemonLspTransport(server: LspConfiguredServer, configuration: DaemonConfiguration): LspTransport {\n\tif (server.transport.type === \"connection\") {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Daemon LSP server ${JSON.stringify(server.id)} cannot use a host-provided connection transport`,\n\t\t);\n\t}\n\tif (server.transport.type === \"spawn\") {\n\t\tif (!configuration.allowProcessExec) {\n\t\t\tthrow new DaemonConfigurationError(\n\t\t\t\t`Daemon LSP server ${JSON.stringify(server.id)} requires --daemon-allow-process-exec`,\n\t\t\t);\n\t\t}\n\t\treturn {\n\t\t\t...server.transport,\n\t\t\t...(server.transport.cwd\n\t\t\t\t? { cwd: requireConfinedPath(server.transport.cwd, configuration, `LSP cwd for ${server.id}`) }\n\t\t\t\t: {}),\n\t\t\t...(isAbsolute(server.transport.command)\n\t\t\t\t? {\n\t\t\t\t\t\tcommand: requireConfinedPath(server.transport.command, configuration, `LSP command for ${server.id}`),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t};\n\t}\n\tif (server.transport.type === \"unix\") {\n\t\treturn {\n\t\t\t...server.transport,\n\t\t\tpath: requireConfinedPath(server.transport.path, configuration, `LSP socket for ${server.id}`),\n\t\t};\n\t}\n\treturn server.transport;\n}\n\nfunction canonicalizeDaemonLspWorkspace(\n\tserver: LspConfiguredServer,\n\tconfiguration: DaemonConfiguration,\n): LspWorkspaceRoot {\n\tif (server.workspace.type === \"fixed\") {\n\t\treturn {\n\t\t\t...server.workspace,\n\t\t\tpath: requireConfinedPath(server.workspace.path, configuration, `LSP workspace for ${server.id}`),\n\t\t};\n\t}\n\tif (server.workspace.type === \"markers\" && server.workspace.stopAt) {\n\t\treturn {\n\t\t\t...server.workspace,\n\t\t\tstopAt: requireConfinedPath(server.workspace.stopAt, configuration, `LSP marker boundary for ${server.id}`),\n\t\t};\n\t}\n\treturn server.workspace;\n}\n\nfunction canonicalizeDaemonPolicy(\n\tconfiguration: DaemonConfiguration,\n\tresolved: ResolvedLspConfiguration,\n): ResolvedLspConfiguration {\n\tconst servers = resolved.servers.map((server) =>\n\t\tcanonicalizeDaemonLspServer(\n\t\t\tserver,\n\t\t\tconfiguration,\n\t\t\tcanonicalizeDaemonLspTransport(server, configuration),\n\t\t\tcanonicalizeDaemonLspWorkspace(server, configuration),\n\t\t),\n\t);\n\treturn { enabled: resolved.enabled, servers };\n}\n\nexport function loadDaemonLspConfiguration(configuration: DaemonConfiguration): ResolvedLspConfiguration {\n\tconst layers: LspConfigurationLayer[] = [];\n\tif (configuration.trustProjectLsp) {\n\t\tconst projectSettingsPath = resolve(configuration.workspaceRoot, \".grip\", \"settings.json\");\n\t\tconst settings = readJson(projectSettingsPath, true);\n\t\tif (settings !== undefined) {\n\t\t\tif (typeof settings !== \"object\" || settings === null || Array.isArray(settings)) {\n\t\t\t\tthrow new DaemonConfigurationError(`Invalid project settings for daemon LSP: ${projectSettingsPath}`);\n\t\t\t}\n\t\t\tconst lsp = (settings as { lsp?: unknown }).lsp;\n\t\t\tif (lsp !== undefined)\n\t\t\t\tlayers.push(parseLayer(lsp, projectSettingsPath, resolve(configuration.workspaceRoot, \".grip\")));\n\t\t}\n\t}\n\tif (configuration.lspConfigPath) {\n\t\tconst value = readJson(configuration.lspConfigPath);\n\t\tlayers.push(parseLayer(value, configuration.lspConfigPath, resolve(configuration.lspConfigPath, \"..\")));\n\t}\n\tconst resolved = layers.length === 0 ? DISABLED_LSP_CONFIGURATION : resolveLspConfiguration(layers);\n\treturn canonicalizeDaemonPolicy(configuration, resolved);\n}\n"]}
1
+ {"version":3,"file":"lsp-config.js","sourceRoot":"","sources":["../../src/daemon/lsp-config.ts"],"names":[],"mappings":"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","sourcesContent":["import { lstatSync, readFileSync, realpathSync } from \"node:fs\";\nimport { dirname, isAbsolute, relative, resolve } from \"node:path\";\nimport {\n\ttype LspConfigurationLayer,\n\ttype LspConfiguredServer,\n\ttype LspTransport,\n\ttype LspWorkspaceRoot,\n\tparseLspConfiguration,\n\ttype ResolvedLspConfiguration,\n\tresolveLspConfiguration,\n} from \"../core/lsp/config.ts\";\nimport { resolveLspConfigurationLayerPaths } from \"../core/lsp/config-loader.ts\";\nimport { relativeWithin } from \"../core/lsp/portable-path.ts\";\nimport { type DaemonConfiguration, DaemonConfigurationError } from \"./config.ts\";\n\nconst DISABLED_LSP_CONFIGURATION: ResolvedLspConfiguration = { enabled: false, servers: [] };\n\nfunction readJson(path: string, optional = false): unknown | undefined {\n\ttry {\n\t\treturn JSON.parse(readFileSync(path, \"utf8\")) as unknown;\n\t} catch (error) {\n\t\tif (optional && error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return undefined;\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Unable to load daemon LSP configuration ${path}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n}\n\nfunction parseLayer(value: unknown, source: string, baseDir: string): LspConfigurationLayer {\n\tconst parsed = parseLspConfiguration(value);\n\tif (!parsed.configuration) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Invalid daemon LSP configuration ${source}: ${parsed.diagnostics.map((item) => `${item.path}: ${item.message}`).join(\"; \")}`,\n\t\t);\n\t}\n\tconst resolved = parseLspConfiguration(resolveLspConfigurationLayerPaths(parsed.configuration, baseDir));\n\tif (!resolved.configuration) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Invalid resolved daemon LSP configuration ${source}: ${resolved.diagnostics.map((item) => `${item.path}: ${item.message}`).join(\"; \")}`,\n\t\t);\n\t}\n\treturn resolved.configuration;\n}\n\nfunction isMissingPathError(error: unknown): boolean {\n\treturn error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n}\n\nfunction validateExistingLspPath(path: string, requestedPath: string, label: string): boolean {\n\tlet isSymbolicLink: boolean;\n\ttry {\n\t\tisSymbolicLink = lstatSync(path).isSymbolicLink();\n\t} catch (error) {\n\t\tif (isMissingPathError(error)) return false;\n\t\tthrow error;\n\t}\n\tif (!isSymbolicLink) return true;\n\ttry {\n\t\trealpathSync(path);\n\t} catch {\n\t\tthrow new DaemonConfigurationError(`${label} uses a broken symbolic link: ${requestedPath}`);\n\t}\n\treturn true;\n}\n\nfunction findExistingLspPathAncestor(path: string, label: string): string {\n\tlet existing = path;\n\twhile (!validateExistingLspPath(existing, path, label)) {\n\t\tconst parent = dirname(existing);\n\t\tif (parent === existing) break;\n\t\texisting = parent;\n\t}\n\treturn existing;\n}\n\nfunction requireConfinedPath(path: string, configuration: DaemonConfiguration, label: string): string {\n\tconst existing = findExistingLspPathAncestor(path, label);\n\tconst canonicalExisting = realpathSync(existing);\n\tif (relativeWithin(configuration.workspaceRoot, canonicalExisting) === undefined) {\n\t\tthrow new DaemonConfigurationError(`${label} escapes the daemon workspace: ${path}`);\n\t}\n\tif (existing === path) return canonicalExisting;\n\treturn resolve(canonicalExisting, relative(existing, path));\n}\n\nfunction canonicalizeDaemonLspServer(\n\tserver: LspConfiguredServer,\n\tconfiguration: DaemonConfiguration,\n\ttransport: LspTransport,\n\tworkspace: LspWorkspaceRoot,\n): LspConfiguredServer {\n\treturn {\n\t\t...server,\n\t\ttransport,\n\t\tworkspace,\n\t\t...(server.pathMappings\n\t\t\t? {\n\t\t\t\t\tpathMappings: server.pathMappings.map((mapping) => ({\n\t\t\t\t\t\t...mapping,\n\t\t\t\t\t\tagentRoot: requireConfinedPath(mapping.agentRoot, configuration, `LSP path mapping for ${server.id}`),\n\t\t\t\t\t})),\n\t\t\t\t}\n\t\t\t: {}),\n\t};\n}\nfunction canonicalizeDaemonLspTransport(server: LspConfiguredServer, configuration: DaemonConfiguration): LspTransport {\n\tif (server.transport.type === \"connection\") {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t`Daemon LSP server ${JSON.stringify(server.id)} cannot use a host-provided connection transport`,\n\t\t);\n\t}\n\tif (server.transport.type === \"spawn\") {\n\t\tif (!configuration.allowProcessExec) {\n\t\t\tthrow new DaemonConfigurationError(\n\t\t\t\t`Daemon LSP server ${JSON.stringify(server.id)} requires --daemon-allow-process-exec`,\n\t\t\t);\n\t\t}\n\t\treturn {\n\t\t\t...server.transport,\n\t\t\t...(server.transport.cwd\n\t\t\t\t? { cwd: requireConfinedPath(server.transport.cwd, configuration, `LSP cwd for ${server.id}`) }\n\t\t\t\t: {}),\n\t\t\t...(isAbsolute(server.transport.command)\n\t\t\t\t? {\n\t\t\t\t\t\tcommand: requireConfinedPath(server.transport.command, configuration, `LSP command for ${server.id}`),\n\t\t\t\t\t}\n\t\t\t\t: {}),\n\t\t};\n\t}\n\tif (server.transport.type === \"unix\") {\n\t\treturn {\n\t\t\t...server.transport,\n\t\t\tpath: requireConfinedPath(server.transport.path, configuration, `LSP socket for ${server.id}`),\n\t\t};\n\t}\n\treturn server.transport;\n}\n\nfunction canonicalizeDaemonLspWorkspace(\n\tserver: LspConfiguredServer,\n\tconfiguration: DaemonConfiguration,\n): LspWorkspaceRoot {\n\tif (server.workspace.type === \"fixed\") {\n\t\treturn {\n\t\t\t...server.workspace,\n\t\t\tpath: requireConfinedPath(server.workspace.path, configuration, `LSP workspace for ${server.id}`),\n\t\t};\n\t}\n\tif (server.workspace.type === \"markers\" && server.workspace.stopAt) {\n\t\treturn {\n\t\t\t...server.workspace,\n\t\t\tstopAt: requireConfinedPath(server.workspace.stopAt, configuration, `LSP marker boundary for ${server.id}`),\n\t\t};\n\t}\n\treturn server.workspace;\n}\n\nfunction canonicalizeDaemonPolicy(\n\tconfiguration: DaemonConfiguration,\n\tresolved: ResolvedLspConfiguration,\n): ResolvedLspConfiguration {\n\tconst servers = resolved.servers.map((server) =>\n\t\tcanonicalizeDaemonLspServer(\n\t\t\tserver,\n\t\t\tconfiguration,\n\t\t\tcanonicalizeDaemonLspTransport(server, configuration),\n\t\t\tcanonicalizeDaemonLspWorkspace(server, configuration),\n\t\t),\n\t);\n\treturn { enabled: resolved.enabled, servers };\n}\n\nexport function loadDaemonLspConfiguration(configuration: DaemonConfiguration): ResolvedLspConfiguration {\n\tconst layers: LspConfigurationLayer[] = [];\n\tif (configuration.trustProjectLsp) {\n\t\tconst projectSettingsPath = resolve(configuration.workspaceRoot, \".grip\", \"settings.json\");\n\t\tconst settings = readJson(projectSettingsPath, true);\n\t\tif (settings !== undefined) {\n\t\t\tif (typeof settings !== \"object\" || settings === null || Array.isArray(settings)) {\n\t\t\t\tthrow new DaemonConfigurationError(`Invalid project settings for daemon LSP: ${projectSettingsPath}`);\n\t\t\t}\n\t\t\tconst lsp = (settings as { lsp?: unknown }).lsp;\n\t\t\tif (lsp !== undefined)\n\t\t\t\tlayers.push(parseLayer(lsp, projectSettingsPath, resolve(configuration.workspaceRoot, \".grip\")));\n\t\t}\n\t}\n\tif (configuration.lspConfigPath) {\n\t\tconst value = readJson(configuration.lspConfigPath);\n\t\tlayers.push(parseLayer(value, configuration.lspConfigPath, resolve(configuration.lspConfigPath, \"..\")));\n\t}\n\tconst resolved = layers.length === 0 ? DISABLED_LSP_CONFIGURATION : resolveLspConfiguration(layers);\n\treturn canonicalizeDaemonPolicy(configuration, resolved);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"outbound-budget.d.ts","sourceRoot":"","sources":["../../src/daemon/outbound-budget.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,qBAAa,oBAAoB;IAChC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC,YAAY,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAGhD;IAED,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,IAAI,CAkBzD;CACD","sourcesContent":["/** Aggregate outstanding sends on one physical WebSocket (v1 or v2). */\nexport class DaemonOutboundBudget {\n\tprivate pendingBytes = 0;\n\tprivate pendingMessages = 0;\n\tprivate readonly maxBytes: number;\n\tprivate readonly maxMessages: number;\n\n\tconstructor(maxBytes: number, maxMessages: number) {\n\t\tthis.maxBytes = maxBytes;\n\t\tthis.maxMessages = maxMessages;\n\t}\n\n\treserve(bytes: number, bufferedAmount: number): () => void {\n\t\t// ws.bufferedAmount measures socket-queued data; a callback can also stall after\n\t\t// the socket accepts data. Bound both views without double-counting overlap.\n\t\tif (\n\t\t\tthis.pendingMessages >= this.maxMessages ||\n\t\t\tMath.max(this.pendingBytes, bufferedAmount) + bytes > this.maxBytes\n\t\t) {\n\t\t\tthrow new Error(\"WebSocket outbound buffer exceeds daemon limits\");\n\t\t}\n\t\tthis.pendingMessages++;\n\t\tthis.pendingBytes += bytes;\n\t\tlet released = false;\n\t\treturn () => {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tthis.pendingMessages--;\n\t\t\tthis.pendingBytes -= bytes;\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"outbound-budget.d.ts","sourceRoot":"","sources":["../../src/daemon/outbound-budget.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,qBAAa,oBAAoB;IAChC,OAAO,CAAC,YAAY,CAAK;IACzB,OAAO,CAAC,eAAe,CAAK;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC,YAAY,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAGhD;IAED,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,MAAM,IAAI,CAkBzD;CACD"}
@@ -1,10 +1,8 @@
1
1
  /** Aggregate outstanding sends on one physical WebSocket (v1 or v2). */
2
2
  export class DaemonOutboundBudget {
3
- pendingBytes = 0;
4
- pendingMessages = 0;
5
- maxBytes;
6
- maxMessages;
7
3
  constructor(maxBytes, maxMessages) {
4
+ this.pendingBytes = 0;
5
+ this.pendingMessages = 0;
8
6
  this.maxBytes = maxBytes;
9
7
  this.maxMessages = maxMessages;
10
8
  }
@@ -1 +1 @@
1
- {"version":3,"file":"outbound-budget.js","sourceRoot":"","sources":["../../src/daemon/outbound-budget.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,MAAM,OAAO,oBAAoB;IACxB,YAAY,GAAG,CAAC,CAAC;IACjB,eAAe,GAAG,CAAC,CAAC;IACX,QAAQ,CAAS;IACjB,WAAW,CAAS;IAErC,YAAY,QAAgB,EAAE,WAAmB,EAAE;QAClD,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IAAA,CAC/B;IAED,OAAO,CAAC,KAAa,EAAE,cAAsB,EAAc;QAC1D,iFAAiF;QACjF,6EAA6E;QAC7E,IACC,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,WAAW;YACxC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,QAAQ,EAClE,CAAC;YACF,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACpE,CAAC;QACD,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,YAAY,IAAI,KAAK,CAAC;QAC3B,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,OAAO,GAAG,EAAE,CAAC;YACZ,IAAI,QAAQ;gBAAE,OAAO;YACrB,QAAQ,GAAG,IAAI,CAAC;YAChB,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,IAAI,CAAC,YAAY,IAAI,KAAK,CAAC;QAAA,CAC3B,CAAC;IAAA,CACF;CACD","sourcesContent":["/** Aggregate outstanding sends on one physical WebSocket (v1 or v2). */\nexport class DaemonOutboundBudget {\n\tprivate pendingBytes = 0;\n\tprivate pendingMessages = 0;\n\tprivate readonly maxBytes: number;\n\tprivate readonly maxMessages: number;\n\n\tconstructor(maxBytes: number, maxMessages: number) {\n\t\tthis.maxBytes = maxBytes;\n\t\tthis.maxMessages = maxMessages;\n\t}\n\n\treserve(bytes: number, bufferedAmount: number): () => void {\n\t\t// ws.bufferedAmount measures socket-queued data; a callback can also stall after\n\t\t// the socket accepts data. Bound both views without double-counting overlap.\n\t\tif (\n\t\t\tthis.pendingMessages >= this.maxMessages ||\n\t\t\tMath.max(this.pendingBytes, bufferedAmount) + bytes > this.maxBytes\n\t\t) {\n\t\t\tthrow new Error(\"WebSocket outbound buffer exceeds daemon limits\");\n\t\t}\n\t\tthis.pendingMessages++;\n\t\tthis.pendingBytes += bytes;\n\t\tlet released = false;\n\t\treturn () => {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tthis.pendingMessages--;\n\t\t\tthis.pendingBytes -= bytes;\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"outbound-budget.js","sourceRoot":"","sources":["../../src/daemon/outbound-budget.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,MAAM,OAAO,oBAAoB;IAMhC,YAAY,QAAgB,EAAE,WAAmB;QALzC,iBAAY,GAAG,CAAC,CAAC;QACjB,oBAAe,GAAG,CAAC,CAAC;QAK3B,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAC;IAChC,CAAC;IAED,OAAO,CAAC,KAAa,EAAE,cAAsB;QAC5C,iFAAiF;QACjF,6EAA6E;QAC7E,IACC,IAAI,CAAC,eAAe,IAAI,IAAI,CAAC,WAAW;YACxC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,QAAQ,EAClE,CAAC;YACF,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACpE,CAAC;QACD,IAAI,CAAC,eAAe,EAAE,CAAC;QACvB,IAAI,CAAC,YAAY,IAAI,KAAK,CAAC;QAC3B,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,OAAO,GAAG,EAAE;YACX,IAAI,QAAQ;gBAAE,OAAO;YACrB,QAAQ,GAAG,IAAI,CAAC;YAChB,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,IAAI,CAAC,YAAY,IAAI,KAAK,CAAC;QAC5B,CAAC,CAAC;IACH,CAAC;CACD","sourcesContent":["/** Aggregate outstanding sends on one physical WebSocket (v1 or v2). */\nexport class DaemonOutboundBudget {\n\tprivate pendingBytes = 0;\n\tprivate pendingMessages = 0;\n\tprivate readonly maxBytes: number;\n\tprivate readonly maxMessages: number;\n\n\tconstructor(maxBytes: number, maxMessages: number) {\n\t\tthis.maxBytes = maxBytes;\n\t\tthis.maxMessages = maxMessages;\n\t}\n\n\treserve(bytes: number, bufferedAmount: number): () => void {\n\t\t// ws.bufferedAmount measures socket-queued data; a callback can also stall after\n\t\t// the socket accepts data. Bound both views without double-counting overlap.\n\t\tif (\n\t\t\tthis.pendingMessages >= this.maxMessages ||\n\t\t\tMath.max(this.pendingBytes, bufferedAmount) + bytes > this.maxBytes\n\t\t) {\n\t\t\tthrow new Error(\"WebSocket outbound buffer exceeds daemon limits\");\n\t\t}\n\t\tthis.pendingMessages++;\n\t\tthis.pendingBytes += bytes;\n\t\tlet released = false;\n\t\treturn () => {\n\t\t\tif (released) return;\n\t\t\treleased = true;\n\t\t\tthis.pendingMessages--;\n\t\t\tthis.pendingBytes -= bytes;\n\t\t};\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/daemon/security.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAGN,KAAK,mBAAmB,EAExB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AA2BD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMpD;AA6ED,wBAAgB,2BAA2B,CAAC,aAAa,EAAE,mBAAmB,GAAG,IAAI,CAMpF;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,mBAAmB,GAAG,SAAS,CAIpG;AAaD,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,eAAe,EACxB,aAAa,EAAE,mBAAmB,EAClC,aAAa,EAAE,mBAAmB,GAAG,SAAS,GAC5C,qBAAqB,CA+BvB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,qBAAqB,GAAG,IAAI,CAazF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GAAG,MAAM,CAOhG","sourcesContent":["import { createHash, timingSafeEqual } from \"node:crypto\";\nimport type { IncomingMessage } from \"node:http\";\nimport { isIP } from \"node:net\";\nimport type { Duplex } from \"node:stream\";\nimport { SHARED_WORKSPACE_WEBSOCKET_PROTOCOL } from \"../core/remote-workspace-protocol/shared-transport.ts\";\nimport {\n\tDAEMON_WEBSOCKET_PATH,\n\tDAEMON_WEBSOCKET_PROTOCOL,\n\ttype DaemonConfiguration,\n\tDaemonConfigurationError,\n} from \"./config.ts\";\n\nexport interface DaemonAuthorization {\n\treadonly configuredBytes: number;\n\treadonly digest: Buffer;\n}\n\nexport interface DaemonUpgradeDecision {\n\treadonly accepted: boolean;\n\treadonly status: number;\n\treadonly message: string;\n}\n\nfunction headerValues(request: IncomingMessage, name: string): string[] {\n\tconst values: string[] = [];\n\tfor (let index = 0; index < request.rawHeaders.length; index += 2) {\n\t\tif (request.rawHeaders[index]?.toLowerCase() === name) values.push(request.rawHeaders[index + 1] ?? \"\");\n\t}\n\treturn values;\n}\n\nfunction singleHeader(request: IncomingMessage, name: string): string | undefined {\n\tconst values = headerValues(request, name);\n\treturn values.length === 1 ? values[0] : undefined;\n}\n\nfunction hasToken(value: string, token: string): boolean {\n\treturn value\n\t\t.split(\",\")\n\t\t.map((entry) => entry.trim().toLowerCase())\n\t\t.includes(token);\n}\n\nfunction isValidWebSocketKey(value: string): boolean {\n\tif (!/^[A-Za-z0-9+/]{22}==$/.test(value)) return false;\n\treturn Buffer.from(value, \"base64\").byteLength === 16;\n}\n\nexport function isLoopbackBind(host: string): boolean {\n\tconst normalized = host.startsWith(\"[\") && host.endsWith(\"]\") ? host.slice(1, -1) : host;\n\tif (isIP(normalized) === 4) return normalized.split(\".\")[0] === \"127\";\n\tif (isIP(normalized) !== 6) return false;\n\tconst lower = normalized.toLowerCase();\n\treturn lower === \"::1\" || /^::ffff:127(?:\\.[0-9]{1,3}){3}$/.test(lower);\n}\nfunction validateDaemonRuntimeLimits(configuration: DaemonConfiguration): void {\n\tif (!Number.isSafeInteger(configuration.port) || configuration.port < 0 || configuration.port > 65535) {\n\t\tthrow new DaemonConfigurationError(\"Daemon server port must be an integer from 0 to 65535\");\n\t}\n\tif (!Number.isSafeInteger(configuration.maxConnections) || configuration.maxConnections < 1) {\n\t\tthrow new DaemonConfigurationError(\"Daemon maxConnections must be a positive integer\");\n\t}\n\tif (!Number.isSafeInteger(configuration.maxPendingConnections) || configuration.maxPendingConnections < 1) {\n\t\tthrow new DaemonConfigurationError(\"Daemon maxPendingConnections must be a positive integer\");\n\t}\n\tif (\n\t\t!Number.isSafeInteger(configuration.handshakeTimeoutMs) ||\n\t\tconfiguration.handshakeTimeoutMs < 100 ||\n\t\tconfiguration.handshakeTimeoutMs > 5 * 60_000\n\t) {\n\t\tthrow new DaemonConfigurationError(\"Daemon handshakeTimeoutMs must be an integer from 100 to 300000\");\n\t}\n\tif (\n\t\t!Number.isSafeInteger(configuration.shutdownTimeoutMs) ||\n\t\tconfiguration.shutdownTimeoutMs < 100 ||\n\t\tconfiguration.shutdownTimeoutMs > 5 * 60_000\n\t) {\n\t\tthrow new DaemonConfigurationError(\"Daemon shutdownTimeoutMs must be an integer from 100 to 300000\");\n\t}\n}\n\nfunction validateDaemonCredentials(configuration: DaemonConfiguration): void {\n\tif (process.platform !== \"win32\" && process.getuid?.() === 0 && !configuration.allowRoot) {\n\t\tthrow new DaemonConfigurationError(\"Refusing to run the workspace daemon as root without allowRoot\");\n\t}\n\tif (configuration.token === undefined) return;\n\tconst tokenBytes = Buffer.byteLength(configuration.token, \"utf8\");\n\tif (\n\t\ttokenBytes < 32 ||\n\t\ttokenBytes > 1024 ||\n\t\t!/\\S/u.test(configuration.token) ||\n\t\t/[\\r\\n]/u.test(configuration.token)\n\t) {\n\t\tthrow new DaemonConfigurationError(\"Daemon token must contain 32 to 1024 UTF-8 bytes and no line breaks\");\n\t}\n}\n\nfunction validateDaemonOrigins(origins: readonly string[]): void {\n\tfor (const origin of origins) {\n\t\tlet parsed: URL;\n\t\ttry {\n\t\t\tparsed = new URL(origin);\n\t\t} catch {\n\t\t\tthrow new DaemonConfigurationError(`Invalid daemon Origin: ${origin}`);\n\t\t}\n\t\tif ((parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") || origin !== parsed.origin) {\n\t\t\tthrow new DaemonConfigurationError(`Invalid daemon Origin: ${origin}`);\n\t\t}\n\t}\n}\n\nfunction validateDaemonTls(configuration: DaemonConfiguration): void {\n\tif (configuration.tls && (configuration.tls.cert.byteLength === 0 || configuration.tls.key.byteLength === 0)) {\n\t\tthrow new DaemonConfigurationError(\"Daemon TLS certificate and private key must not be empty\");\n\t}\n}\n\nfunction validateDaemonBindExposure(configuration: DaemonConfiguration): void {\n\tif (isIP(configuration.host.replace(/^\\[|\\]$/g, \"\")) === 0) {\n\t\tthrow new DaemonConfigurationError(\"Daemon host must be a literal IPv4 or IPv6 address\");\n\t}\n\tif (isLoopbackBind(configuration.host)) return;\n\tif (!configuration.token)\n\t\tthrow new DaemonConfigurationError(\"A non-loopback daemon bind requires GRIP_DAEMON_TOKEN\");\n\tif (!configuration.tls && !configuration.allowInsecureTransport) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t\"A non-loopback daemon bind requires TLS or explicit --daemon-allow-insecure-transport acknowledgement\",\n\t\t);\n\t}\n}\n\nexport function validateDaemonNetworkPolicy(configuration: DaemonConfiguration): void {\n\tvalidateDaemonRuntimeLimits(configuration);\n\tvalidateDaemonCredentials(configuration);\n\tvalidateDaemonOrigins(configuration.allowedOrigins);\n\tvalidateDaemonTls(configuration);\n\tvalidateDaemonBindExposure(configuration);\n}\n\nexport function createDaemonAuthorization(token: string | undefined): DaemonAuthorization | undefined {\n\tif (token === undefined) return undefined;\n\tconst bytes = Buffer.from(token, \"utf8\");\n\treturn Object.freeze({ configuredBytes: bytes.byteLength, digest: createHash(\"sha256\").update(bytes).digest() });\n}\n\nfunction authenticateAuthorizationHeader(\n\tvalue: string | undefined,\n\tauthorization: DaemonAuthorization | undefined,\n): boolean {\n\tif (!authorization) return value === undefined;\n\tif (!value?.startsWith(\"Bearer \")) return false;\n\tconst presented = Buffer.from(value.slice(\"Bearer \".length), \"utf8\");\n\tconst digest = createHash(\"sha256\").update(presented).digest();\n\treturn presented.byteLength === authorization.configuredBytes && timingSafeEqual(digest, authorization.digest);\n}\n\nexport function validateDaemonUpgrade(\n\trequest: IncomingMessage,\n\tconfiguration: DaemonConfiguration,\n\tauthorization: DaemonAuthorization | undefined,\n): DaemonUpgradeDecision {\n\tif (request.method !== \"GET\" || request.url !== DAEMON_WEBSOCKET_PATH) {\n\t\treturn { accepted: false, status: 404, message: \"Not found\" };\n\t}\n\tconst upgrade = singleHeader(request, \"upgrade\");\n\tconst connection = singleHeader(request, \"connection\");\n\tconst version = singleHeader(request, \"sec-websocket-version\");\n\tconst key = singleHeader(request, \"sec-websocket-key\");\n\tconst protocol = singleHeader(request, \"sec-websocket-protocol\");\n\tif (\n\t\tupgrade?.toLowerCase() !== \"websocket\" ||\n\t\t!connection ||\n\t\t!hasToken(connection, \"upgrade\") ||\n\t\tversion !== \"13\" ||\n\t\t!key ||\n\t\t!isValidWebSocketKey(key) ||\n\t\t(protocol !== DAEMON_WEBSOCKET_PROTOCOL &&\n\t\t\t(protocol !== SHARED_WORKSPACE_WEBSOCKET_PROTOCOL || !configuration.sharedParentRoot))\n\t) {\n\t\treturn { accepted: false, status: 400, message: \"Invalid WebSocket upgrade\" };\n\t}\n\tconst originValues = headerValues(request, \"origin\");\n\tif (originValues.length > 1) return { accepted: false, status: 403, message: \"Origin not allowed\" };\n\tif (originValues.length === 1 && !configuration.allowedOrigins.includes(originValues[0])) {\n\t\treturn { accepted: false, status: 403, message: \"Origin not allowed\" };\n\t}\n\tconst authorizationValues = headerValues(request, \"authorization\");\n\tif (authorizationValues.length > 1 || !authenticateAuthorizationHeader(authorizationValues[0], authorization)) {\n\t\treturn { accepted: false, status: 401, message: \"Unauthorized\" };\n\t}\n\treturn { accepted: true, status: 101, message: \"Switching Protocols\" };\n}\n\nexport function rejectDaemonUpgrade(socket: Duplex, decision: DaemonUpgradeDecision): void {\n\tconst statusText =\n\t\tnew Map([\n\t\t\t[400, \"Bad Request\"],\n\t\t\t[401, \"Unauthorized\"],\n\t\t\t[403, \"Forbidden\"],\n\t\t\t[404, \"Not Found\"],\n\t\t\t[503, \"Service Unavailable\"],\n\t\t]).get(decision.status) ?? \"Rejected\";\n\tconst body = `${decision.message}\\n`;\n\tsocket.end(\n\t\t`HTTP/1.1 ${decision.status} ${statusText}\\r\\nConnection: close\\r\\nContent-Type: text/plain\\r\\nContent-Length: ${Buffer.byteLength(body)}\\r\\n\\r\\n${body}`,\n\t);\n}\n\nexport function redactDaemonText(value: string, secrets: readonly (string | undefined)[]): string {\n\tlet result = value\n\t\t.replace(/(authorization\\s*:\\s*bearer\\s+)[^\\s,;]+/giu, \"$1[REDACTED]\")\n\t\t.replace(/([?&](?:token|key|secret|password|credential)=)[^&#\\s]*/giu, \"$1[REDACTED]\")\n\t\t.replace(/(\\/\\/)[^/@\\s]+:[^/@\\s]+@/gu, \"$1[REDACTED]@\");\n\tfor (const secret of secrets) if (secret) result = result.split(secret).join(\"[REDACTED]\");\n\treturn result;\n}\n"]}
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/daemon/security.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,OAAO,EAGN,KAAK,mBAAmB,EAExB,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACrC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CACzB;AA2BD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAMpD;AA6ED,wBAAgB,2BAA2B,CAAC,aAAa,EAAE,mBAAmB,GAAG,IAAI,CAMpF;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,mBAAmB,GAAG,SAAS,CAIpG;AAaD,wBAAgB,qBAAqB,CACpC,OAAO,EAAE,eAAe,EACxB,aAAa,EAAE,mBAAmB,EAClC,aAAa,EAAE,mBAAmB,GAAG,SAAS,GAC5C,qBAAqB,CA+BvB;AAED,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,qBAAqB,GAAG,IAAI,CAazF;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,MAAM,GAAG,SAAS,CAAC,EAAE,GAAG,MAAM,CAOhG"}
@@ -1 +1 @@
1
- {"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/daemon/security.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, timingSafeEqual } from \"node:crypto\";\nimport type { IncomingMessage } from \"node:http\";\nimport { isIP } from \"node:net\";\nimport type { Duplex } from \"node:stream\";\nimport { SHARED_WORKSPACE_WEBSOCKET_PROTOCOL } from \"../core/remote-workspace-protocol/shared-transport.ts\";\nimport {\n\tDAEMON_WEBSOCKET_PATH,\n\tDAEMON_WEBSOCKET_PROTOCOL,\n\ttype DaemonConfiguration,\n\tDaemonConfigurationError,\n} from \"./config.ts\";\n\nexport interface DaemonAuthorization {\n\treadonly configuredBytes: number;\n\treadonly digest: Buffer;\n}\n\nexport interface DaemonUpgradeDecision {\n\treadonly accepted: boolean;\n\treadonly status: number;\n\treadonly message: string;\n}\n\nfunction headerValues(request: IncomingMessage, name: string): string[] {\n\tconst values: string[] = [];\n\tfor (let index = 0; index < request.rawHeaders.length; index += 2) {\n\t\tif (request.rawHeaders[index]?.toLowerCase() === name) values.push(request.rawHeaders[index + 1] ?? \"\");\n\t}\n\treturn values;\n}\n\nfunction singleHeader(request: IncomingMessage, name: string): string | undefined {\n\tconst values = headerValues(request, name);\n\treturn values.length === 1 ? values[0] : undefined;\n}\n\nfunction hasToken(value: string, token: string): boolean {\n\treturn value\n\t\t.split(\",\")\n\t\t.map((entry) => entry.trim().toLowerCase())\n\t\t.includes(token);\n}\n\nfunction isValidWebSocketKey(value: string): boolean {\n\tif (!/^[A-Za-z0-9+/]{22}==$/.test(value)) return false;\n\treturn Buffer.from(value, \"base64\").byteLength === 16;\n}\n\nexport function isLoopbackBind(host: string): boolean {\n\tconst normalized = host.startsWith(\"[\") && host.endsWith(\"]\") ? host.slice(1, -1) : host;\n\tif (isIP(normalized) === 4) return normalized.split(\".\")[0] === \"127\";\n\tif (isIP(normalized) !== 6) return false;\n\tconst lower = normalized.toLowerCase();\n\treturn lower === \"::1\" || /^::ffff:127(?:\\.[0-9]{1,3}){3}$/.test(lower);\n}\nfunction validateDaemonRuntimeLimits(configuration: DaemonConfiguration): void {\n\tif (!Number.isSafeInteger(configuration.port) || configuration.port < 0 || configuration.port > 65535) {\n\t\tthrow new DaemonConfigurationError(\"Daemon server port must be an integer from 0 to 65535\");\n\t}\n\tif (!Number.isSafeInteger(configuration.maxConnections) || configuration.maxConnections < 1) {\n\t\tthrow new DaemonConfigurationError(\"Daemon maxConnections must be a positive integer\");\n\t}\n\tif (!Number.isSafeInteger(configuration.maxPendingConnections) || configuration.maxPendingConnections < 1) {\n\t\tthrow new DaemonConfigurationError(\"Daemon maxPendingConnections must be a positive integer\");\n\t}\n\tif (\n\t\t!Number.isSafeInteger(configuration.handshakeTimeoutMs) ||\n\t\tconfiguration.handshakeTimeoutMs < 100 ||\n\t\tconfiguration.handshakeTimeoutMs > 5 * 60_000\n\t) {\n\t\tthrow new DaemonConfigurationError(\"Daemon handshakeTimeoutMs must be an integer from 100 to 300000\");\n\t}\n\tif (\n\t\t!Number.isSafeInteger(configuration.shutdownTimeoutMs) ||\n\t\tconfiguration.shutdownTimeoutMs < 100 ||\n\t\tconfiguration.shutdownTimeoutMs > 5 * 60_000\n\t) {\n\t\tthrow new DaemonConfigurationError(\"Daemon shutdownTimeoutMs must be an integer from 100 to 300000\");\n\t}\n}\n\nfunction validateDaemonCredentials(configuration: DaemonConfiguration): void {\n\tif (process.platform !== \"win32\" && process.getuid?.() === 0 && !configuration.allowRoot) {\n\t\tthrow new DaemonConfigurationError(\"Refusing to run the workspace daemon as root without allowRoot\");\n\t}\n\tif (configuration.token === undefined) return;\n\tconst tokenBytes = Buffer.byteLength(configuration.token, \"utf8\");\n\tif (\n\t\ttokenBytes < 32 ||\n\t\ttokenBytes > 1024 ||\n\t\t!/\\S/u.test(configuration.token) ||\n\t\t/[\\r\\n]/u.test(configuration.token)\n\t) {\n\t\tthrow new DaemonConfigurationError(\"Daemon token must contain 32 to 1024 UTF-8 bytes and no line breaks\");\n\t}\n}\n\nfunction validateDaemonOrigins(origins: readonly string[]): void {\n\tfor (const origin of origins) {\n\t\tlet parsed: URL;\n\t\ttry {\n\t\t\tparsed = new URL(origin);\n\t\t} catch {\n\t\t\tthrow new DaemonConfigurationError(`Invalid daemon Origin: ${origin}`);\n\t\t}\n\t\tif ((parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") || origin !== parsed.origin) {\n\t\t\tthrow new DaemonConfigurationError(`Invalid daemon Origin: ${origin}`);\n\t\t}\n\t}\n}\n\nfunction validateDaemonTls(configuration: DaemonConfiguration): void {\n\tif (configuration.tls && (configuration.tls.cert.byteLength === 0 || configuration.tls.key.byteLength === 0)) {\n\t\tthrow new DaemonConfigurationError(\"Daemon TLS certificate and private key must not be empty\");\n\t}\n}\n\nfunction validateDaemonBindExposure(configuration: DaemonConfiguration): void {\n\tif (isIP(configuration.host.replace(/^\\[|\\]$/g, \"\")) === 0) {\n\t\tthrow new DaemonConfigurationError(\"Daemon host must be a literal IPv4 or IPv6 address\");\n\t}\n\tif (isLoopbackBind(configuration.host)) return;\n\tif (!configuration.token)\n\t\tthrow new DaemonConfigurationError(\"A non-loopback daemon bind requires GRIP_DAEMON_TOKEN\");\n\tif (!configuration.tls && !configuration.allowInsecureTransport) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t\"A non-loopback daemon bind requires TLS or explicit --daemon-allow-insecure-transport acknowledgement\",\n\t\t);\n\t}\n}\n\nexport function validateDaemonNetworkPolicy(configuration: DaemonConfiguration): void {\n\tvalidateDaemonRuntimeLimits(configuration);\n\tvalidateDaemonCredentials(configuration);\n\tvalidateDaemonOrigins(configuration.allowedOrigins);\n\tvalidateDaemonTls(configuration);\n\tvalidateDaemonBindExposure(configuration);\n}\n\nexport function createDaemonAuthorization(token: string | undefined): DaemonAuthorization | undefined {\n\tif (token === undefined) return undefined;\n\tconst bytes = Buffer.from(token, \"utf8\");\n\treturn Object.freeze({ configuredBytes: bytes.byteLength, digest: createHash(\"sha256\").update(bytes).digest() });\n}\n\nfunction authenticateAuthorizationHeader(\n\tvalue: string | undefined,\n\tauthorization: DaemonAuthorization | undefined,\n): boolean {\n\tif (!authorization) return value === undefined;\n\tif (!value?.startsWith(\"Bearer \")) return false;\n\tconst presented = Buffer.from(value.slice(\"Bearer \".length), \"utf8\");\n\tconst digest = createHash(\"sha256\").update(presented).digest();\n\treturn presented.byteLength === authorization.configuredBytes && timingSafeEqual(digest, authorization.digest);\n}\n\nexport function validateDaemonUpgrade(\n\trequest: IncomingMessage,\n\tconfiguration: DaemonConfiguration,\n\tauthorization: DaemonAuthorization | undefined,\n): DaemonUpgradeDecision {\n\tif (request.method !== \"GET\" || request.url !== DAEMON_WEBSOCKET_PATH) {\n\t\treturn { accepted: false, status: 404, message: \"Not found\" };\n\t}\n\tconst upgrade = singleHeader(request, \"upgrade\");\n\tconst connection = singleHeader(request, \"connection\");\n\tconst version = singleHeader(request, \"sec-websocket-version\");\n\tconst key = singleHeader(request, \"sec-websocket-key\");\n\tconst protocol = singleHeader(request, \"sec-websocket-protocol\");\n\tif (\n\t\tupgrade?.toLowerCase() !== \"websocket\" ||\n\t\t!connection ||\n\t\t!hasToken(connection, \"upgrade\") ||\n\t\tversion !== \"13\" ||\n\t\t!key ||\n\t\t!isValidWebSocketKey(key) ||\n\t\t(protocol !== DAEMON_WEBSOCKET_PROTOCOL &&\n\t\t\t(protocol !== SHARED_WORKSPACE_WEBSOCKET_PROTOCOL || !configuration.sharedParentRoot))\n\t) {\n\t\treturn { accepted: false, status: 400, message: \"Invalid WebSocket upgrade\" };\n\t}\n\tconst originValues = headerValues(request, \"origin\");\n\tif (originValues.length > 1) return { accepted: false, status: 403, message: \"Origin not allowed\" };\n\tif (originValues.length === 1 && !configuration.allowedOrigins.includes(originValues[0])) {\n\t\treturn { accepted: false, status: 403, message: \"Origin not allowed\" };\n\t}\n\tconst authorizationValues = headerValues(request, \"authorization\");\n\tif (authorizationValues.length > 1 || !authenticateAuthorizationHeader(authorizationValues[0], authorization)) {\n\t\treturn { accepted: false, status: 401, message: \"Unauthorized\" };\n\t}\n\treturn { accepted: true, status: 101, message: \"Switching Protocols\" };\n}\n\nexport function rejectDaemonUpgrade(socket: Duplex, decision: DaemonUpgradeDecision): void {\n\tconst statusText =\n\t\tnew Map([\n\t\t\t[400, \"Bad Request\"],\n\t\t\t[401, \"Unauthorized\"],\n\t\t\t[403, \"Forbidden\"],\n\t\t\t[404, \"Not Found\"],\n\t\t\t[503, \"Service Unavailable\"],\n\t\t]).get(decision.status) ?? \"Rejected\";\n\tconst body = `${decision.message}\\n`;\n\tsocket.end(\n\t\t`HTTP/1.1 ${decision.status} ${statusText}\\r\\nConnection: close\\r\\nContent-Type: text/plain\\r\\nContent-Length: ${Buffer.byteLength(body)}\\r\\n\\r\\n${body}`,\n\t);\n}\n\nexport function redactDaemonText(value: string, secrets: readonly (string | undefined)[]): string {\n\tlet result = value\n\t\t.replace(/(authorization\\s*:\\s*bearer\\s+)[^\\s,;]+/giu, \"$1[REDACTED]\")\n\t\t.replace(/([?&](?:token|key|secret|password|credential)=)[^&#\\s]*/giu, \"$1[REDACTED]\")\n\t\t.replace(/(\\/\\/)[^/@\\s]+:[^/@\\s]+@/gu, \"$1[REDACTED]@\");\n\tfor (const secret of secrets) if (secret) result = result.split(secret).join(\"[REDACTED]\");\n\treturn result;\n}\n"]}
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/daemon/security.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash, timingSafeEqual } from \"node:crypto\";\nimport type { IncomingMessage } from \"node:http\";\nimport { isIP } from \"node:net\";\nimport type { Duplex } from \"node:stream\";\nimport { SHARED_WORKSPACE_WEBSOCKET_PROTOCOL } from \"../core/remote-workspace-protocol/shared-transport.ts\";\nimport {\n\tDAEMON_WEBSOCKET_PATH,\n\tDAEMON_WEBSOCKET_PROTOCOL,\n\ttype DaemonConfiguration,\n\tDaemonConfigurationError,\n} from \"./config.ts\";\n\nexport interface DaemonAuthorization {\n\treadonly configuredBytes: number;\n\treadonly digest: Buffer;\n}\n\nexport interface DaemonUpgradeDecision {\n\treadonly accepted: boolean;\n\treadonly status: number;\n\treadonly message: string;\n}\n\nfunction headerValues(request: IncomingMessage, name: string): string[] {\n\tconst values: string[] = [];\n\tfor (let index = 0; index < request.rawHeaders.length; index += 2) {\n\t\tif (request.rawHeaders[index]?.toLowerCase() === name) values.push(request.rawHeaders[index + 1] ?? \"\");\n\t}\n\treturn values;\n}\n\nfunction singleHeader(request: IncomingMessage, name: string): string | undefined {\n\tconst values = headerValues(request, name);\n\treturn values.length === 1 ? values[0] : undefined;\n}\n\nfunction hasToken(value: string, token: string): boolean {\n\treturn value\n\t\t.split(\",\")\n\t\t.map((entry) => entry.trim().toLowerCase())\n\t\t.includes(token);\n}\n\nfunction isValidWebSocketKey(value: string): boolean {\n\tif (!/^[A-Za-z0-9+/]{22}==$/.test(value)) return false;\n\treturn Buffer.from(value, \"base64\").byteLength === 16;\n}\n\nexport function isLoopbackBind(host: string): boolean {\n\tconst normalized = host.startsWith(\"[\") && host.endsWith(\"]\") ? host.slice(1, -1) : host;\n\tif (isIP(normalized) === 4) return normalized.split(\".\")[0] === \"127\";\n\tif (isIP(normalized) !== 6) return false;\n\tconst lower = normalized.toLowerCase();\n\treturn lower === \"::1\" || /^::ffff:127(?:\\.[0-9]{1,3}){3}$/.test(lower);\n}\nfunction validateDaemonRuntimeLimits(configuration: DaemonConfiguration): void {\n\tif (!Number.isSafeInteger(configuration.port) || configuration.port < 0 || configuration.port > 65535) {\n\t\tthrow new DaemonConfigurationError(\"Daemon server port must be an integer from 0 to 65535\");\n\t}\n\tif (!Number.isSafeInteger(configuration.maxConnections) || configuration.maxConnections < 1) {\n\t\tthrow new DaemonConfigurationError(\"Daemon maxConnections must be a positive integer\");\n\t}\n\tif (!Number.isSafeInteger(configuration.maxPendingConnections) || configuration.maxPendingConnections < 1) {\n\t\tthrow new DaemonConfigurationError(\"Daemon maxPendingConnections must be a positive integer\");\n\t}\n\tif (\n\t\t!Number.isSafeInteger(configuration.handshakeTimeoutMs) ||\n\t\tconfiguration.handshakeTimeoutMs < 100 ||\n\t\tconfiguration.handshakeTimeoutMs > 5 * 60_000\n\t) {\n\t\tthrow new DaemonConfigurationError(\"Daemon handshakeTimeoutMs must be an integer from 100 to 300000\");\n\t}\n\tif (\n\t\t!Number.isSafeInteger(configuration.shutdownTimeoutMs) ||\n\t\tconfiguration.shutdownTimeoutMs < 100 ||\n\t\tconfiguration.shutdownTimeoutMs > 5 * 60_000\n\t) {\n\t\tthrow new DaemonConfigurationError(\"Daemon shutdownTimeoutMs must be an integer from 100 to 300000\");\n\t}\n}\n\nfunction validateDaemonCredentials(configuration: DaemonConfiguration): void {\n\tif (process.platform !== \"win32\" && process.getuid?.() === 0 && !configuration.allowRoot) {\n\t\tthrow new DaemonConfigurationError(\"Refusing to run the workspace daemon as root without allowRoot\");\n\t}\n\tif (configuration.token === undefined) return;\n\tconst tokenBytes = Buffer.byteLength(configuration.token, \"utf8\");\n\tif (\n\t\ttokenBytes < 32 ||\n\t\ttokenBytes > 1024 ||\n\t\t!/\\S/u.test(configuration.token) ||\n\t\t/[\\r\\n]/u.test(configuration.token)\n\t) {\n\t\tthrow new DaemonConfigurationError(\"Daemon token must contain 32 to 1024 UTF-8 bytes and no line breaks\");\n\t}\n}\n\nfunction validateDaemonOrigins(origins: readonly string[]): void {\n\tfor (const origin of origins) {\n\t\tlet parsed: URL;\n\t\ttry {\n\t\t\tparsed = new URL(origin);\n\t\t} catch {\n\t\t\tthrow new DaemonConfigurationError(`Invalid daemon Origin: ${origin}`);\n\t\t}\n\t\tif ((parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") || origin !== parsed.origin) {\n\t\t\tthrow new DaemonConfigurationError(`Invalid daemon Origin: ${origin}`);\n\t\t}\n\t}\n}\n\nfunction validateDaemonTls(configuration: DaemonConfiguration): void {\n\tif (configuration.tls && (configuration.tls.cert.byteLength === 0 || configuration.tls.key.byteLength === 0)) {\n\t\tthrow new DaemonConfigurationError(\"Daemon TLS certificate and private key must not be empty\");\n\t}\n}\n\nfunction validateDaemonBindExposure(configuration: DaemonConfiguration): void {\n\tif (isIP(configuration.host.replace(/^\\[|\\]$/g, \"\")) === 0) {\n\t\tthrow new DaemonConfigurationError(\"Daemon host must be a literal IPv4 or IPv6 address\");\n\t}\n\tif (isLoopbackBind(configuration.host)) return;\n\tif (!configuration.token)\n\t\tthrow new DaemonConfigurationError(\"A non-loopback daemon bind requires GRIP_DAEMON_TOKEN\");\n\tif (!configuration.tls && !configuration.allowInsecureTransport) {\n\t\tthrow new DaemonConfigurationError(\n\t\t\t\"A non-loopback daemon bind requires TLS or explicit --daemon-allow-insecure-transport acknowledgement\",\n\t\t);\n\t}\n}\n\nexport function validateDaemonNetworkPolicy(configuration: DaemonConfiguration): void {\n\tvalidateDaemonRuntimeLimits(configuration);\n\tvalidateDaemonCredentials(configuration);\n\tvalidateDaemonOrigins(configuration.allowedOrigins);\n\tvalidateDaemonTls(configuration);\n\tvalidateDaemonBindExposure(configuration);\n}\n\nexport function createDaemonAuthorization(token: string | undefined): DaemonAuthorization | undefined {\n\tif (token === undefined) return undefined;\n\tconst bytes = Buffer.from(token, \"utf8\");\n\treturn Object.freeze({ configuredBytes: bytes.byteLength, digest: createHash(\"sha256\").update(bytes).digest() });\n}\n\nfunction authenticateAuthorizationHeader(\n\tvalue: string | undefined,\n\tauthorization: DaemonAuthorization | undefined,\n): boolean {\n\tif (!authorization) return value === undefined;\n\tif (!value?.startsWith(\"Bearer \")) return false;\n\tconst presented = Buffer.from(value.slice(\"Bearer \".length), \"utf8\");\n\tconst digest = createHash(\"sha256\").update(presented).digest();\n\treturn presented.byteLength === authorization.configuredBytes && timingSafeEqual(digest, authorization.digest);\n}\n\nexport function validateDaemonUpgrade(\n\trequest: IncomingMessage,\n\tconfiguration: DaemonConfiguration,\n\tauthorization: DaemonAuthorization | undefined,\n): DaemonUpgradeDecision {\n\tif (request.method !== \"GET\" || request.url !== DAEMON_WEBSOCKET_PATH) {\n\t\treturn { accepted: false, status: 404, message: \"Not found\" };\n\t}\n\tconst upgrade = singleHeader(request, \"upgrade\");\n\tconst connection = singleHeader(request, \"connection\");\n\tconst version = singleHeader(request, \"sec-websocket-version\");\n\tconst key = singleHeader(request, \"sec-websocket-key\");\n\tconst protocol = singleHeader(request, \"sec-websocket-protocol\");\n\tif (\n\t\tupgrade?.toLowerCase() !== \"websocket\" ||\n\t\t!connection ||\n\t\t!hasToken(connection, \"upgrade\") ||\n\t\tversion !== \"13\" ||\n\t\t!key ||\n\t\t!isValidWebSocketKey(key) ||\n\t\t(protocol !== DAEMON_WEBSOCKET_PROTOCOL &&\n\t\t\t(protocol !== SHARED_WORKSPACE_WEBSOCKET_PROTOCOL || !configuration.sharedParentRoot))\n\t) {\n\t\treturn { accepted: false, status: 400, message: \"Invalid WebSocket upgrade\" };\n\t}\n\tconst originValues = headerValues(request, \"origin\");\n\tif (originValues.length > 1) return { accepted: false, status: 403, message: \"Origin not allowed\" };\n\tif (originValues.length === 1 && !configuration.allowedOrigins.includes(originValues[0])) {\n\t\treturn { accepted: false, status: 403, message: \"Origin not allowed\" };\n\t}\n\tconst authorizationValues = headerValues(request, \"authorization\");\n\tif (authorizationValues.length > 1 || !authenticateAuthorizationHeader(authorizationValues[0], authorization)) {\n\t\treturn { accepted: false, status: 401, message: \"Unauthorized\" };\n\t}\n\treturn { accepted: true, status: 101, message: \"Switching Protocols\" };\n}\n\nexport function rejectDaemonUpgrade(socket: Duplex, decision: DaemonUpgradeDecision): void {\n\tconst statusText =\n\t\tnew Map([\n\t\t\t[400, \"Bad Request\"],\n\t\t\t[401, \"Unauthorized\"],\n\t\t\t[403, \"Forbidden\"],\n\t\t\t[404, \"Not Found\"],\n\t\t\t[503, \"Service Unavailable\"],\n\t\t]).get(decision.status) ?? \"Rejected\";\n\tconst body = `${decision.message}\\n`;\n\tsocket.end(\n\t\t`HTTP/1.1 ${decision.status} ${statusText}\\r\\nConnection: close\\r\\nContent-Type: text/plain\\r\\nContent-Length: ${Buffer.byteLength(body)}\\r\\n\\r\\n${body}`,\n\t);\n}\n\nexport function redactDaemonText(value: string, secrets: readonly (string | undefined)[]): string {\n\tlet result = value\n\t\t.replace(/(authorization\\s*:\\s*bearer\\s+)[^\\s,;]+/giu, \"$1[REDACTED]\")\n\t\t.replace(/([?&](?:token|key|secret|password|credential)=)[^&#\\s]*/giu, \"$1[REDACTED]\")\n\t\t.replace(/(\\/\\/)[^/@\\s]+:[^/@\\s]+@/gu, \"$1[REDACTED]@\");\n\tfor (const secret of secrets) if (secret) result = result.split(secret).join(\"[REDACTED]\");\n\treturn result;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/daemon/server.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAyB,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAY9E,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE/E,MAAM,WAAW,YAAY;IAC5B,MAAM,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACvC,OAAO,IAAI,mBAAmB,GAAG,SAAS,CAAC;IAC3C,KAAK,IAAI,iBAAiB,CAAC;IAC3B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AA2FD,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,mBAAmB,GAAG,YAAY,CA4YnF","sourcesContent":["import { randomBytes } from \"node:crypto\";\nimport {\n\tcreateServer as createHttpServer,\n\ttype Server as HttpServer,\n\ttype IncomingMessage,\n\ttype ServerResponse,\n} from \"node:http\";\nimport { createServer as createHttpsServer } from \"node:https\";\nimport type { AddressInfo, Socket } from \"node:net\";\nimport WebSocket, { type RawData, WebSocketServer } from \"ws\";\nimport type { RemoteWorkspaceServerMessage } from \"../core/remote-workspace-protocol/contract.ts\";\nimport {\n\ttype RemoteWorkspaceProtocolCloseCode,\n\ttype RemoteWorkspaceProtocolCloseReason,\n\tRemoteWorkspaceRequestError,\n\ttype RemoteWorkspaceServerHandler,\n\tRemoteWorkspaceServerProtocol,\n} from \"../core/remote-workspace-protocol/session.ts\";\nimport {\n\tSHARED_WORKSPACE_WEBSOCKET_PROTOCOL,\n\ttype SharedWorkspaceServerFrame,\n} from \"../core/remote-workspace-protocol/shared-transport.ts\";\nimport { DaemonActivityBudget } from \"./activity-budget.ts\";\nimport { DAEMON_WEBSOCKET_PATH, type DaemonConfiguration } from \"./config.ts\";\nimport { DaemonOutboundBudget } from \"./outbound-budget.ts\";\nimport {\n\tcreateDaemonAuthorization,\n\trejectDaemonUpgrade,\n\tvalidateDaemonNetworkPolicy,\n\tvalidateDaemonUpgrade,\n} from \"./security.ts\";\nimport { SharedDaemonConnection } from \"./shared-connection.ts\";\nimport { SharedWorkspaceRoots } from \"./shared-roots.ts\";\nimport { createDaemonWorkspaceRuntime } from \"./workspace-runtime.ts\";\n\nexport interface DaemonServerAddress {\n\treadonly host: string;\n\treadonly port: number;\n\treadonly secure: boolean;\n\treadonly url: string;\n\treadonly workspaceRoot: string;\n\treadonly workspaceId: string;\n}\n\nexport type DaemonServerState = \"created\" | \"listening\" | \"closing\" | \"closed\";\n\nexport interface DaemonServer {\n\tlisten(): Promise<DaemonServerAddress>;\n\taddress(): DaemonServerAddress | undefined;\n\tstate(): DaemonServerState;\n\treload(): Promise<void>;\n\tclose(): Promise<void>;\n\tforceClose(): Promise<void>;\n}\n\ninterface DaemonConnection {\n\treadonly websocket: WebSocket;\n\treadonly protocol: RemoteWorkspaceServerProtocol | SharedDaemonConnection;\n\tclosed: Promise<void>;\n}\n\nfunction websocketPayload(data: RawData): Uint8Array {\n\tif (Buffer.isBuffer(data)) return Uint8Array.from(data);\n\tif (Array.isArray(data)) return Uint8Array.from(Buffer.concat(data));\n\treturn Uint8Array.from(new Uint8Array(data));\n}\n\nfunction websocketCloseCode(code: RemoteWorkspaceProtocolCloseCode): number {\n\tswitch (code) {\n\t\tcase \"normal\":\n\t\t\treturn 1000;\n\t\tcase \"protocol_error\":\n\t\t\treturn 1002;\n\t\tcase \"invalid_payload\":\n\t\t\treturn 1007;\n\t\tcase \"policy_violation\":\n\t\t\treturn 1008;\n\t\tcase \"message_too_large\":\n\t\t\treturn 1009;\n\t}\n}\n\nfunction waitForWebSocketClose(websocket: WebSocket): Promise<void> {\n\tif (websocket.readyState === WebSocket.CLOSED) return Promise.resolve();\n\treturn new Promise((resolve) => websocket.once(\"close\", () => resolve()));\n}\n\nfunction waitWithin(promise: Promise<unknown>, timeoutMs: number, forceSignal: AbortSignal): Promise<boolean> {\n\tif (forceSignal.aborted) return Promise.resolve(false);\n\treturn new Promise((resolve) => {\n\t\tlet settled = false;\n\t\tconst finish = (value: boolean) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tclearTimeout(timer);\n\t\t\tforceSignal.removeEventListener(\"abort\", onForce);\n\t\t\tresolve(value);\n\t\t};\n\t\tconst timer = setTimeout(() => finish(false), timeoutMs);\n\t\tconst onForce = () => finish(false);\n\t\tforceSignal.addEventListener(\"abort\", onForce, { once: true });\n\t\tpromise.then(\n\t\t\t() => finish(true),\n\t\t\t() => finish(false),\n\t\t);\n\t});\n}\nfunction terminateDaemonConnections(connections: Iterable<DaemonConnection>): void {\n\tfor (const connection of connections) connection.websocket.terminate();\n}\n\nfunction beginDaemonConnectionDrain(\n\tconnections: readonly DaemonConnection[],\n\thostDisposal: Promise<void>,\n): Promise<void> {\n\treturn Promise.allSettled([...connections.map((connection) => connection.protocol.beginDrain()), hostDisposal]).then(\n\t\t() => undefined,\n\t);\n}\n\nfunction disconnectDaemonConnections(connections: readonly DaemonConnection[]): Promise<void> {\n\treturn Promise.allSettled(connections.map((connection) => connection.protocol.disconnect())).then(() => undefined);\n}\n\nfunction requestDaemonConnectionClose(connections: readonly DaemonConnection[]): void {\n\tfor (const connection of connections) {\n\t\tif (connection.websocket.readyState === WebSocket.OPEN) {\n\t\t\tconnection.websocket.close(1001, \"Daemon shutting down\");\n\t\t}\n\t}\n}\n\nfunction waitForDaemonConnectionsClosed(connections: readonly DaemonConnection[]): Promise<void> {\n\treturn Promise.allSettled(connections.map((connection) => connection.closed)).then(() => undefined);\n}\n\nfunction destroyDaemonSockets(sockets: ReadonlySet<Socket>): void {\n\tfor (const socket of sockets) socket.destroy();\n}\n\nfunction formatHostForUrl(host: string): string {\n\treturn host.includes(\":\") && !host.startsWith(\"[\") ? `[${host}]` : host;\n}\n\nexport function createDaemonServer(configuration: DaemonConfiguration): DaemonServer {\n\tvalidateDaemonNetworkPolicy(configuration);\n\tconst authorization = createDaemonAuthorization(configuration.token);\n\tconst activityBudget = new DaemonActivityBudget(configuration);\n\tconst workspaceId = randomBytes(18).toString(\"base64url\");\n\tconst workspace = Object.freeze({\n\t\tid: workspaceId,\n\t\troot: configuration.workspaceRoot,\n\t\tpathFlavor: process.platform === \"win32\" ? (\"windows\" as const) : (\"posix\" as const),\n\t});\n\tlet runtime = createDaemonWorkspaceRuntime(configuration);\n\tlet runtimeHandler = runtime.createHandler(workspace);\n\tconst handler: RemoteWorkspaceServerHandler = {\n\t\thandleRequest: (request, context) => {\n\t\t\tif (typeof request.params === \"object\" && request.params !== null && \"expectedRevision\" in request.params) {\n\t\t\t\tthrow new RemoteWorkspaceRequestError({\n\t\t\t\t\tcode: \"invalid_request\",\n\t\t\t\t\tmessage: \"Revision preconditions require the v2 shared workspace protocol\",\n\t\t\t\t\texecutionState: \"not_started\",\n\t\t\t\t\tretryable: false,\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn activityBudget.run(request.method, () => runtimeHandler.handleRequest(request, context));\n\t\t},\n\t\tvalidateToolArguments: (toolName, value) => runtimeHandler.validateToolArguments(toolName, value),\n\t};\n\tconst requestListener = (_request: IncomingMessage, response: ServerResponse) => {\n\t\tresponse.writeHead(404, { \"content-type\": \"text/plain\" });\n\t\tresponse.end(\"Not found\\n\");\n\t};\n\tconst server: HttpServer = configuration.tls\n\t\t? createHttpsServer(\n\t\t\t\t{\n\t\t\t\t\tcert: configuration.tls.cert,\n\t\t\t\t\tkey: configuration.tls.key,\n\t\t\t\t\tpassphrase: configuration.tls.passphrase,\n\t\t\t\t\tminVersion: \"TLSv1.2\",\n\t\t\t\t},\n\t\t\t\trequestListener,\n\t\t\t)\n\t\t: createHttpServer(requestListener);\n\tconst websocketServer = new WebSocketServer({\n\t\tnoServer: true,\n\t\tclientTracking: false,\n\t\tmaxPayload: configuration.protocolLimits.maxMessageBytes,\n\t\tperMessageDeflate: false,\n\t\tallowSynchronousEvents: false,\n\t\tskipUTF8Validation: false,\n\t});\n\tconst sockets = new Set<Socket>();\n\tconst pendingSockets = new Set<Socket>();\n\tconst pendingSocketTimers = new Map<Socket, NodeJS.Timeout>();\n\tconst pendingSocketDeadlines = new Map<Socket, number>();\n\tconst connections = new Set<DaemonConnection>();\n\tlet sharedRoots: SharedWorkspaceRoots | undefined;\n\tlet catalog = runtime.catalog;\n\tlet reloadQueue: Promise<void> = Promise.resolve();\n\tconst forceController = new AbortController();\n\tlet currentAddress: DaemonServerAddress | undefined;\n\tlet listenPromise: Promise<DaemonServerAddress> | undefined;\n\tlet rejectListen: ((error: Error) => void) | undefined;\n\tlet closePromise: Promise<void> | undefined;\n\tlet serverState: DaemonServerState = \"created\";\n\n\tconst stopListener = (): Promise<void> => {\n\t\tif (!server.listening && !listenPromise) return Promise.resolve();\n\t\treturn new Promise((resolve) => {\n\t\t\tlet settled = false;\n\t\t\tconst cleanup = () => {\n\t\t\t\tserver.off(\"listening\", onListening);\n\t\t\t\tserver.off(\"error\", onError);\n\t\t\t\tserver.off(\"close\", onClose);\n\t\t\t};\n\t\t\tconst finish = () => {\n\t\t\t\tif (settled) return;\n\t\t\t\tsettled = true;\n\t\t\t\tcleanup();\n\t\t\t\tresolve();\n\t\t\t};\n\t\t\tconst closeListener = () => server.close(() => finish());\n\t\t\tconst onListening = () => closeListener();\n\t\t\tconst onError = () => finish();\n\t\t\tconst onClose = () => finish();\n\t\t\tserver.once(\"error\", onError);\n\t\t\tserver.once(\"close\", onClose);\n\t\t\tif (server.listening) closeListener();\n\t\t\telse server.once(\"listening\", onListening);\n\t\t});\n\t};\n\n\tserver.on(\"connection\", (socket: Socket) => {\n\t\tif (serverState !== \"listening\" || pendingSockets.size >= configuration.maxPendingConnections) {\n\t\t\tsocket.destroy();\n\t\t\treturn;\n\t\t}\n\t\tsockets.add(socket);\n\t\tpendingSockets.add(socket);\n\t\tconst pendingTimer = setTimeout(() => socket.destroy(), configuration.handshakeTimeoutMs);\n\t\tpendingTimer.unref?.();\n\t\tpendingSocketTimers.set(socket, pendingTimer);\n\t\tpendingSocketDeadlines.set(socket, performance.now() + configuration.handshakeTimeoutMs);\n\t\tsocket.once(\"close\", () => {\n\t\t\tsockets.delete(socket);\n\t\t\tpendingSockets.delete(socket);\n\t\t\tconst timer = pendingSocketTimers.get(socket);\n\t\t\tif (timer) clearTimeout(timer);\n\t\t\tpendingSocketTimers.delete(socket);\n\t\t\tpendingSocketDeadlines.delete(socket);\n\t\t});\n\t});\n\n\tserver.on(\"upgrade\", (request, socket, head) => {\n\t\tconst netSocket = socket as Socket;\n\t\tconst decision = validateDaemonUpgrade(request, configuration, authorization);\n\t\tif (!decision.accepted) {\n\t\t\trejectDaemonUpgrade(netSocket, decision);\n\t\t\treturn;\n\t\t}\n\t\tif (serverState !== \"listening\" || connections.size >= configuration.maxConnections) {\n\t\t\trejectDaemonUpgrade(netSocket, { accepted: false, status: 503, message: \"Service unavailable\" });\n\t\t\treturn;\n\t\t}\n\t\tconst handshakeDeadline = pendingSocketDeadlines.get(netSocket) ?? performance.now();\n\t\tpendingSockets.delete(netSocket);\n\t\tconst pendingTimer = pendingSocketTimers.get(netSocket);\n\t\tif (pendingTimer) clearTimeout(pendingTimer);\n\t\tpendingSocketTimers.delete(netSocket);\n\t\tpendingSocketDeadlines.delete(netSocket);\n\t\twebsocketServer.handleUpgrade(request, socket, head, (websocket) => {\n\t\t\tif (serverState !== \"listening\") {\n\t\t\t\twebsocket.terminate();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst remainingHandshakeMs = Math.max(0, handshakeDeadline - performance.now());\n\t\t\tconst handshakeTimer = setTimeout(() => {\n\t\t\t\twebsocket.terminate();\n\t\t\t}, remainingHandshakeMs);\n\t\t\thandshakeTimer.unref?.();\n\t\t\tlet protocol: RemoteWorkspaceServerProtocol;\n\t\t\tconst outboundBudget = new DaemonOutboundBudget(\n\t\t\t\tconfiguration.protocolLimits.maxPendingOutboundBytes,\n\t\t\t\tconfiguration.protocolLimits.maxPendingOutboundMessages,\n\t\t\t);\n\t\t\tconst transport = {\n\t\t\t\tsend(message: RemoteWorkspaceServerMessage | SharedWorkspaceServerFrame): Promise<void> {\n\t\t\t\t\tif (websocket.readyState !== WebSocket.OPEN) return Promise.reject(new Error(\"WebSocket is not open\"));\n\t\t\t\t\tconst serialized = JSON.stringify(message);\n\t\t\t\t\tconst bytes = Buffer.byteLength(serialized, \"utf8\");\n\t\t\t\t\tlet release: () => void;\n\t\t\t\t\ttry {\n\t\t\t\t\t\trelease = outboundBudget.reserve(bytes, websocket.bufferedAmount);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t// No channel can safely continue after a physical send is dropped.\n\t\t\t\t\t\twebsocket.terminate();\n\t\t\t\t\t\treturn Promise.reject(error);\n\t\t\t\t\t}\n\t\t\t\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\t\t\t\t// A stalled callback must not pin physical reservations indefinitely. A\n\t\t\t\t\t\t// timed-out send makes the entire uplink uncertain, not just its channel.\n\t\t\t\t\t\tconst deadline = setTimeout(() => {\n\t\t\t\t\t\t\twebsocket.terminate();\n\t\t\t\t\t\t\treject(new Error(\"WebSocket outbound send timed out\"));\n\t\t\t\t\t\t}, configuration.protocolLimits.maxTransportSendMs);\n\t\t\t\t\t\tdeadline.unref?.();\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\twebsocket.send(serialized, { binary: false, compress: false }, (error) => {\n\t\t\t\t\t\t\t\tclearTimeout(deadline);\n\t\t\t\t\t\t\t\tif (error) {\n\t\t\t\t\t\t\t\t\twebsocket.terminate();\n\t\t\t\t\t\t\t\t\treject(error);\n\t\t\t\t\t\t\t\t} else resolve();\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\tclearTimeout(deadline);\n\t\t\t\t\t\t\twebsocket.terminate();\n\t\t\t\t\t\t\treject(error);\n\t\t\t\t\t\t}\n\t\t\t\t\t}).finally(release);\n\t\t\t\t},\n\t\t\t\tclose(reason: RemoteWorkspaceProtocolCloseReason): Promise<void> {\n\t\t\t\t\tif (websocket.readyState === WebSocket.CLOSED) return Promise.resolve();\n\t\t\t\t\twebsocket.close(websocketCloseCode(reason.code), reason.message);\n\t\t\t\t\treturn waitForWebSocketClose(websocket);\n\t\t\t\t},\n\t\t\t};\n\t\t\tif (websocket.protocol === SHARED_WORKSPACE_WEBSOCKET_PROTOCOL) {\n\t\t\t\tif (!sharedRoots) {\n\t\t\t\t\twebsocket.close(1008, \"Shared parent unavailable\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst shared = new SharedDaemonConnection(\n\t\t\t\t\tconfiguration,\n\t\t\t\t\tsharedRoots,\n\t\t\t\t\ttransport.send,\n\t\t\t\t\t(code, reason) => {\n\t\t\t\t\t\tif (websocket.readyState === WebSocket.OPEN) websocket.close(code, reason);\n\t\t\t\t\t},\n\t\t\t\t\tactivityBudget,\n\t\t\t\t);\n\t\t\t\tconst connection: DaemonConnection = { websocket, protocol: shared, closed: Promise.resolve() };\n\t\t\t\tconnection.closed = waitForWebSocketClose(websocket).then(async () => {\n\t\t\t\t\tclearTimeout(handshakeTimer);\n\t\t\t\t\tconnections.delete(connection);\n\t\t\t\t\tawait shared.disconnect().catch(() => undefined);\n\t\t\t\t});\n\t\t\t\tconnections.add(connection);\n\t\t\t\twebsocket.on(\"message\", (data, isBinary) => {\n\t\t\t\t\tif (isBinary) {\n\t\t\t\t\t\twebsocket.close(1003, \"Text protocol required\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tvoid shared.receive(websocketPayload(data)).then(() => {\n\t\t\t\t\t\tif (shared.handshakeComplete) clearTimeout(handshakeTimer);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t\twebsocket.on(\"error\", () => undefined);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tprotocol = new RemoteWorkspaceServerProtocol(transport, handler, {\n\t\t\t\tworkspace,\n\t\t\t\tcatalog,\n\t\t\t\tcapabilities: runtime.capabilities,\n\t\t\t\tlimits: configuration.protocolLimits,\n\t\t\t\tbackendLabel: \"grip-workspace-daemon\",\n\t\t\t});\n\t\t\tconst connection: DaemonConnection = {\n\t\t\t\twebsocket,\n\t\t\t\tprotocol,\n\t\t\t\tclosed: Promise.resolve(),\n\t\t\t};\n\t\t\tconnection.closed = waitForWebSocketClose(websocket).then(async () => {\n\t\t\t\tclearTimeout(handshakeTimer);\n\t\t\t\tconnections.delete(connection);\n\t\t\t\tawait protocol.disconnect().catch(() => undefined);\n\t\t\t});\n\t\t\tconnections.add(connection);\n\t\t\twebsocket.on(\"message\", (data, isBinary) => {\n\t\t\t\tif (isBinary) {\n\t\t\t\t\twebsocket.close(1003, \"Text protocol required\");\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tvoid protocol\n\t\t\t\t\t.receive(websocketPayload(data))\n\t\t\t\t\t.then(() => {\n\t\t\t\t\t\tif (protocol.handshakeComplete) clearTimeout(handshakeTimer);\n\t\t\t\t\t})\n\t\t\t\t\t.catch(() => undefined);\n\t\t\t});\n\t\t\twebsocket.on(\"error\", () => undefined);\n\t\t});\n\t});\n\n\tconst api: DaemonServer = {\n\t\tlisten(): Promise<DaemonServerAddress> {\n\t\t\tif (serverState === \"closing\" || serverState === \"closed\")\n\t\t\t\treturn Promise.reject(new Error(\"Daemon server is closing\"));\n\t\t\tif (currentAddress) return Promise.resolve(currentAddress);\n\t\t\tif (listenPromise) return listenPromise;\n\t\t\tif (configuration.sharedParentRoot && !sharedRoots) {\n\t\t\t\treturn SharedWorkspaceRoots.fromParent(configuration.sharedParentRoot).then((roots) => {\n\t\t\t\t\tsharedRoots = roots;\n\t\t\t\t\treturn api.listen();\n\t\t\t\t});\n\t\t\t}\n\t\t\tlistenPromise = new Promise((resolve, reject) => {\n\t\t\t\trejectListen = reject;\n\t\t\t\tconst onError = (error: Error) => {\n\t\t\t\t\tserver.off(\"listening\", onListening);\n\t\t\t\t\tlistenPromise = undefined;\n\t\t\t\t\trejectListen = undefined;\n\t\t\t\t\treject(error);\n\t\t\t\t};\n\t\t\t\tconst onListening = () => {\n\t\t\t\t\tserver.off(\"error\", onError);\n\t\t\t\t\tif (serverState !== \"created\") {\n\t\t\t\t\t\trejectListen = undefined;\n\t\t\t\t\t\treject(new Error(\"Daemon server closed before listening completed\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst address = server.address();\n\t\t\t\t\tif (!address || typeof address === \"string\") {\n\t\t\t\t\t\trejectListen = undefined;\n\t\t\t\t\t\treject(new Error(\"Daemon listener did not return a TCP address\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tserverState = \"listening\";\n\t\t\t\t\tconst port = (address as AddressInfo).port;\n\t\t\t\t\tcurrentAddress = Object.freeze({\n\t\t\t\t\t\thost: configuration.host,\n\t\t\t\t\t\tport,\n\t\t\t\t\t\tsecure: configuration.tls !== undefined,\n\t\t\t\t\t\turl: `${configuration.tls ? \"wss\" : \"ws\"}://${formatHostForUrl(configuration.host)}:${port}${DAEMON_WEBSOCKET_PATH}`,\n\t\t\t\t\t\tworkspaceRoot: configuration.workspaceRoot,\n\t\t\t\t\t\tworkspaceId,\n\t\t\t\t\t});\n\t\t\t\t\trejectListen = undefined;\n\t\t\t\t\tresolve(currentAddress);\n\t\t\t\t};\n\t\t\t\tserver.once(\"error\", onError);\n\t\t\t\tserver.once(\"listening\", onListening);\n\t\t\t\tserver.listen(configuration.port, configuration.host);\n\t\t\t});\n\t\t\treturn listenPromise;\n\t\t},\n\t\taddress(): DaemonServerAddress | undefined {\n\t\t\treturn currentAddress ? { ...currentAddress } : undefined;\n\t\t},\n\t\tstate(): DaemonServerState {\n\t\t\treturn serverState;\n\t\t},\n\t\treload(): Promise<void> {\n\t\t\tif (serverState !== \"listening\") return Promise.reject(new Error(\"Daemon server is not listening\"));\n\t\t\treloadQueue = reloadQueue\n\t\t\t\t.catch(() => undefined)\n\t\t\t\t.then(async () => {\n\t\t\t\t\tif (serverState !== \"listening\") throw new Error(\"Daemon server is not listening\");\n\t\t\t\t\tconst candidate = createDaemonWorkspaceRuntime(configuration);\n\t\t\t\t\tconst candidateCatalog = { ...candidate.catalog, generation: catalog.generation + 1 };\n\t\t\t\t\tconst previous = runtime;\n\t\t\t\t\truntime = candidate;\n\t\t\t\t\truntimeHandler = candidate.createHandler(workspace);\n\t\t\t\t\tcatalog = candidateCatalog;\n\t\t\t\t\tconst snapshot = [...connections];\n\t\t\t\t\tconst outcomes = await Promise.allSettled(\n\t\t\t\t\t\tsnapshot.map(async (connection) => {\n\t\t\t\t\t\t\tif (connection.protocol instanceof SharedDaemonConnection) await connection.protocol.reload();\n\t\t\t\t\t\t\telse await connection.protocol.publishCatalog(catalog);\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t\tconst failed = snapshot.filter((_connection, index) => outcomes[index]?.status === \"rejected\");\n\t\t\t\t\t// A failed publication may have been sent already. Do not roll back successful peers\n\t\t\t\t\t// to an older generation: close only transports whose catalog is uncertain.\n\t\t\t\t\tfor (const connection of failed) connection.websocket.terminate();\n\t\t\t\t\tawait previous.retire();\n\t\t\t\t\tif (failed.length > 0)\n\t\t\t\t\t\tthrow new Error(`Daemon catalog reload failed for ${failed.length} connection(s)`);\n\t\t\t\t});\n\t\t\treturn reloadQueue;\n\t\t},\n\t\tclose(): Promise<void> {\n\t\t\tif (closePromise) return closePromise;\n\t\t\tserverState = \"closing\";\n\t\t\trejectListen?.(new Error(\"Daemon server closed before listening completed\"));\n\t\t\trejectListen = undefined;\n\t\t\tconst deadline = performance.now() + configuration.shutdownTimeoutMs;\n\t\t\tconst remainingMs = () => Math.max(0, deadline - performance.now());\n\t\t\tclosePromise = (async () => {\n\t\t\t\tconst listenerClose = stopListener();\n\t\t\t\tconst snapshot = [...connections];\n\t\t\t\tawait waitWithin(\n\t\t\t\t\treloadQueue.catch(() => undefined),\n\t\t\t\t\tremainingMs(),\n\t\t\t\t\tforceController.signal,\n\t\t\t\t);\n\t\t\t\tconst hostDisposal = runtime.dispose();\n\t\t\t\tconst drained = await waitWithin(\n\t\t\t\t\tbeginDaemonConnectionDrain(snapshot, hostDisposal),\n\t\t\t\t\tremainingMs(),\n\t\t\t\t\tforceController.signal,\n\t\t\t\t);\n\t\t\t\tif (!drained) terminateDaemonConnections(snapshot);\n\t\t\t\tawait waitWithin(disconnectDaemonConnections(snapshot), remainingMs(), forceController.signal);\n\t\t\t\trequestDaemonConnectionClose(snapshot);\n\t\t\t\tconst socketsClosed = await waitWithin(\n\t\t\t\t\twaitForDaemonConnectionsClosed(snapshot),\n\t\t\t\t\tremainingMs(),\n\t\t\t\t\tforceController.signal,\n\t\t\t\t);\n\t\t\t\tif (!socketsClosed) terminateDaemonConnections(snapshot);\n\t\t\t\tdestroyDaemonSockets(sockets);\n\t\t\t\tawait listenerClose;\n\t\t\t\tconnections.clear();\n\t\t\t})().finally(() => {\n\t\t\t\tterminateDaemonConnections(connections);\n\t\t\t\tdestroyDaemonSockets(sockets);\n\t\t\t\tfor (const timer of pendingSocketTimers.values()) clearTimeout(timer);\n\t\t\t\tpendingSocketTimers.clear();\n\t\t\t\tpendingSocketDeadlines.clear();\n\t\t\t\tpendingSockets.clear();\n\t\t\t\tconnections.clear();\n\t\t\t\tcurrentAddress = undefined;\n\t\t\t\tserverState = \"closed\";\n\t\t\t});\n\t\t\treturn closePromise;\n\t\t},\n\t\tforceClose(): Promise<void> {\n\t\t\tif (serverState === \"closed\") return closePromise ?? Promise.resolve();\n\t\t\tserverState = \"closing\";\n\t\t\tforceController.abort();\n\t\t\tcurrentAddress = undefined;\n\t\t\tterminateDaemonConnections(connections);\n\t\t\tdestroyDaemonSockets(sockets);\n\t\t\treturn api.close();\n\t\t},\n\t};\n\treturn api;\n}\n"]}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/daemon/server.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAyB,KAAK,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAY9E,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,MAAM,iBAAiB,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE/E,MAAM,WAAW,YAAY;IAC5B,MAAM,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACvC,OAAO,IAAI,mBAAmB,GAAG,SAAS,CAAC;IAC3C,KAAK,IAAI,iBAAiB,CAAC;IAC3B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AA2FD,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,mBAAmB,GAAG,YAAY,CA4YnF"}