@vpxa/kb 0.1.12 → 0.1.15

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 (383) hide show
  1. package/README.md +56 -39
  2. package/package.json +10 -7
  3. package/packages/analyzers/dist/blast-radius-analyzer.d.ts +17 -20
  4. package/packages/analyzers/dist/blast-radius-analyzer.js +6 -12
  5. package/packages/analyzers/dist/dependency-analyzer.d.ts +31 -27
  6. package/packages/analyzers/dist/dependency-analyzer.js +7 -9
  7. package/packages/analyzers/dist/diagram-generator.d.ts +12 -8
  8. package/packages/analyzers/dist/diagram-generator.js +3 -4
  9. package/packages/analyzers/dist/entry-point-analyzer.d.ts +39 -17
  10. package/packages/analyzers/dist/entry-point-analyzer.js +5 -5
  11. package/packages/analyzers/dist/index.d.ts +12 -14
  12. package/packages/analyzers/dist/index.js +1 -1
  13. package/packages/analyzers/dist/knowledge-producer.d.ts +29 -25
  14. package/packages/analyzers/dist/knowledge-producer.js +16 -15
  15. package/packages/analyzers/dist/pattern-analyzer.d.ts +14 -10
  16. package/packages/analyzers/dist/pattern-analyzer.js +3 -5
  17. package/packages/analyzers/dist/regex-call-graph.d.ts +6 -12
  18. package/packages/analyzers/dist/regex-call-graph.js +2 -1
  19. package/packages/analyzers/dist/structure-analyzer.d.ts +13 -9
  20. package/packages/analyzers/dist/structure-analyzer.js +3 -4
  21. package/packages/analyzers/dist/symbol-analyzer.d.ts +12 -8
  22. package/packages/analyzers/dist/symbol-analyzer.js +8 -13
  23. package/packages/analyzers/dist/ts-call-graph.d.ts +16 -13
  24. package/packages/analyzers/dist/ts-call-graph.js +2 -1
  25. package/packages/analyzers/dist/types.d.ts +82 -79
  26. package/packages/analyzers/dist/types.js +1 -0
  27. package/packages/chunker/dist/call-graph-extractor.d.ts +13 -10
  28. package/packages/chunker/dist/call-graph-extractor.js +2 -1
  29. package/packages/chunker/dist/chunker-factory.d.ts +6 -2
  30. package/packages/chunker/dist/chunker-factory.js +2 -1
  31. package/packages/chunker/dist/chunker.interface.d.ts +8 -4
  32. package/packages/chunker/dist/chunker.interface.js +1 -0
  33. package/packages/chunker/dist/code-chunker.d.ts +16 -12
  34. package/packages/chunker/dist/code-chunker.js +12 -14
  35. package/packages/chunker/dist/generic-chunker.d.ts +14 -10
  36. package/packages/chunker/dist/generic-chunker.js +6 -5
  37. package/packages/chunker/dist/index.d.ts +8 -8
  38. package/packages/chunker/dist/index.js +1 -1
  39. package/packages/chunker/dist/markdown-chunker.d.ts +16 -12
  40. package/packages/chunker/dist/markdown-chunker.js +4 -10
  41. package/packages/chunker/dist/treesitter-chunker.d.ts +28 -31
  42. package/packages/chunker/dist/treesitter-chunker.js +7 -8
  43. package/packages/cli/dist/commands/analyze.d.ts +6 -2
  44. package/packages/cli/dist/commands/analyze.js +3 -3
  45. package/packages/cli/dist/commands/context-cmds.d.ts +6 -2
  46. package/packages/cli/dist/commands/context-cmds.js +2 -1
  47. package/packages/cli/dist/commands/environment.d.ts +6 -2
  48. package/packages/cli/dist/commands/environment.js +2 -2
  49. package/packages/cli/dist/commands/execution.d.ts +6 -2
  50. package/packages/cli/dist/commands/execution.js +2 -1
  51. package/packages/cli/dist/commands/graph.d.ts +6 -2
  52. package/packages/cli/dist/commands/graph.js +6 -6
  53. package/packages/cli/dist/commands/init/adapters.d.ts +27 -0
  54. package/packages/cli/dist/commands/init/adapters.js +2 -0
  55. package/packages/cli/dist/commands/init/config.d.ts +11 -0
  56. package/packages/cli/dist/commands/init/config.js +4 -0
  57. package/packages/cli/dist/commands/init/curated.d.ts +8 -0
  58. package/packages/cli/dist/commands/init/curated.js +2 -0
  59. package/packages/cli/dist/commands/init/index.d.ts +23 -0
  60. package/packages/cli/dist/commands/init/index.js +3 -0
  61. package/packages/cli/dist/commands/init/scaffold.d.ts +24 -0
  62. package/packages/cli/dist/commands/init/scaffold.js +2 -0
  63. package/packages/cli/dist/commands/init/templates.d.ts +10 -0
  64. package/packages/cli/dist/commands/init/templates.js +302 -0
  65. package/packages/cli/dist/commands/init.d.ts +9 -3
  66. package/packages/cli/dist/commands/init.js +253 -197
  67. package/packages/cli/dist/commands/knowledge.d.ts +6 -2
  68. package/packages/cli/dist/commands/knowledge.js +2 -1
  69. package/packages/cli/dist/commands/search.d.ts +6 -2
  70. package/packages/cli/dist/commands/search.js +2 -8
  71. package/packages/cli/dist/commands/system.d.ts +6 -2
  72. package/packages/cli/dist/commands/system.js +5 -4
  73. package/packages/cli/dist/commands/workspace.d.ts +6 -2
  74. package/packages/cli/dist/commands/workspace.js +2 -2
  75. package/packages/cli/dist/context.d.ts +7 -4
  76. package/packages/cli/dist/context.js +2 -1
  77. package/packages/cli/dist/helpers.d.ts +51 -47
  78. package/packages/cli/dist/helpers.js +6 -3
  79. package/packages/cli/dist/index.d.ts +4 -1
  80. package/packages/cli/dist/index.js +3 -2
  81. package/packages/cli/dist/kb-init.d.ts +48 -50
  82. package/packages/cli/dist/kb-init.js +2 -1
  83. package/packages/cli/dist/types.d.ts +8 -5
  84. package/packages/cli/dist/types.js +1 -0
  85. package/packages/core/dist/constants.d.ts +36 -33
  86. package/packages/core/dist/constants.js +2 -1
  87. package/packages/core/dist/content-detector.d.ts +10 -5
  88. package/packages/core/dist/content-detector.js +2 -1
  89. package/packages/core/dist/errors.d.ts +15 -12
  90. package/packages/core/dist/errors.js +2 -1
  91. package/packages/core/dist/index.d.ts +6 -6
  92. package/packages/core/dist/index.js +1 -1
  93. package/packages/core/dist/logger.d.ts +16 -7
  94. package/packages/core/dist/logger.js +2 -1
  95. package/packages/core/dist/types.d.ts +108 -90
  96. package/packages/core/dist/types.js +2 -0
  97. package/packages/embeddings/dist/embedder.interface.d.ts +22 -19
  98. package/packages/embeddings/dist/embedder.interface.js +1 -0
  99. package/packages/embeddings/dist/index.d.ts +3 -3
  100. package/packages/embeddings/dist/index.js +1 -1
  101. package/packages/embeddings/dist/onnx-embedder.d.ts +21 -22
  102. package/packages/embeddings/dist/onnx-embedder.js +2 -1
  103. package/packages/enterprise-bridge/dist/cache.d.ts +29 -0
  104. package/packages/enterprise-bridge/dist/cache.js +2 -0
  105. package/packages/enterprise-bridge/dist/er-client.d.ts +38 -0
  106. package/packages/enterprise-bridge/dist/er-client.js +2 -0
  107. package/packages/enterprise-bridge/dist/evolution-collector.d.ts +63 -0
  108. package/packages/enterprise-bridge/dist/evolution-collector.js +2 -0
  109. package/packages/enterprise-bridge/dist/index.d.ts +8 -0
  110. package/packages/enterprise-bridge/dist/index.js +1 -0
  111. package/packages/enterprise-bridge/dist/policy-store.d.ts +46 -0
  112. package/packages/enterprise-bridge/dist/policy-store.js +2 -0
  113. package/packages/enterprise-bridge/dist/push-adapter.d.ts +24 -0
  114. package/packages/enterprise-bridge/dist/push-adapter.js +2 -0
  115. package/packages/enterprise-bridge/dist/result-merger.d.ts +15 -0
  116. package/packages/enterprise-bridge/dist/result-merger.js +2 -0
  117. package/packages/enterprise-bridge/dist/types.d.ts +82 -0
  118. package/packages/enterprise-bridge/dist/types.js +2 -0
  119. package/packages/indexer/dist/file-hasher.d.ts +5 -2
  120. package/packages/indexer/dist/file-hasher.js +2 -1
  121. package/packages/indexer/dist/filesystem-crawler.d.ts +23 -20
  122. package/packages/indexer/dist/filesystem-crawler.js +2 -1
  123. package/packages/indexer/dist/graph-extractor.d.ts +9 -12
  124. package/packages/indexer/dist/graph-extractor.js +2 -1
  125. package/packages/indexer/dist/incremental-indexer.d.ts +49 -43
  126. package/packages/indexer/dist/incremental-indexer.js +2 -1
  127. package/packages/indexer/dist/index.d.ts +5 -5
  128. package/packages/indexer/dist/index.js +1 -1
  129. package/packages/server/dist/api.d.ts +3 -8
  130. package/packages/server/dist/api.js +1 -1
  131. package/packages/server/dist/config.d.ts +6 -2
  132. package/packages/server/dist/config.js +2 -1
  133. package/packages/server/dist/curated-manager.d.ts +79 -76
  134. package/packages/server/dist/curated-manager.js +6 -10
  135. package/packages/server/dist/index.d.ts +1 -2
  136. package/packages/server/dist/index.js +2 -1
  137. package/packages/server/dist/replay-interceptor.d.ts +6 -6
  138. package/packages/server/dist/replay-interceptor.js +2 -1
  139. package/packages/server/dist/resources/resources.d.ts +7 -3
  140. package/packages/server/dist/resources/resources.js +3 -2
  141. package/packages/server/dist/server.d.ts +34 -24
  142. package/packages/server/dist/server.js +2 -1
  143. package/packages/server/dist/tools/analyze.tools.d.ts +14 -10
  144. package/packages/server/dist/tools/analyze.tools.js +2 -1
  145. package/packages/server/dist/tools/audit.tool.d.ts +9 -0
  146. package/packages/server/dist/tools/audit.tool.js +2 -0
  147. package/packages/server/dist/tools/bridge.tools.d.ts +35 -0
  148. package/packages/server/dist/tools/bridge.tools.js +16 -0
  149. package/packages/server/dist/tools/evolution.tools.d.ts +8 -0
  150. package/packages/server/dist/tools/evolution.tools.js +6 -0
  151. package/packages/server/dist/tools/forge.tools.d.ts +13 -11
  152. package/packages/server/dist/tools/forge.tools.js +11 -13
  153. package/packages/server/dist/tools/forget.tool.d.ts +7 -3
  154. package/packages/server/dist/tools/forget.tool.js +2 -7
  155. package/packages/server/dist/tools/graph.tool.d.ts +7 -3
  156. package/packages/server/dist/tools/graph.tool.js +5 -5
  157. package/packages/server/dist/tools/list.tool.d.ts +7 -3
  158. package/packages/server/dist/tools/list.tool.js +3 -8
  159. package/packages/server/dist/tools/lookup.tool.d.ts +7 -3
  160. package/packages/server/dist/tools/lookup.tool.js +3 -9
  161. package/packages/server/dist/tools/onboard.tool.d.ts +8 -4
  162. package/packages/server/dist/tools/onboard.tool.js +3 -2
  163. package/packages/server/dist/tools/policy.tools.d.ts +8 -0
  164. package/packages/server/dist/tools/policy.tools.js +3 -0
  165. package/packages/server/dist/tools/produce.tool.d.ts +6 -2
  166. package/packages/server/dist/tools/produce.tool.js +3 -2
  167. package/packages/server/dist/tools/read.tool.d.ts +7 -3
  168. package/packages/server/dist/tools/read.tool.js +3 -6
  169. package/packages/server/dist/tools/reindex.tool.d.ts +10 -6
  170. package/packages/server/dist/tools/reindex.tool.js +3 -2
  171. package/packages/server/dist/tools/remember.tool.d.ts +8 -3
  172. package/packages/server/dist/tools/remember.tool.js +4 -5
  173. package/packages/server/dist/tools/replay.tool.d.ts +6 -2
  174. package/packages/server/dist/tools/replay.tool.js +3 -6
  175. package/packages/server/dist/tools/search.tool.d.ts +10 -4
  176. package/packages/server/dist/tools/search.tool.js +7 -18
  177. package/packages/server/dist/tools/status.tool.d.ts +7 -3
  178. package/packages/server/dist/tools/status.tool.js +3 -3
  179. package/packages/server/dist/tools/toolkit.tools.d.ts +36 -34
  180. package/packages/server/dist/tools/toolkit.tools.js +20 -21
  181. package/packages/server/dist/tools/update.tool.d.ts +7 -3
  182. package/packages/server/dist/tools/update.tool.js +2 -6
  183. package/packages/server/dist/tools/utility.tools.d.ts +15 -14
  184. package/packages/server/dist/tools/utility.tools.js +11 -23
  185. package/packages/server/dist/version-check.d.ts +5 -1
  186. package/packages/server/dist/version-check.js +2 -1
  187. package/packages/store/dist/graph-store.interface.d.ts +89 -86
  188. package/packages/store/dist/graph-store.interface.js +1 -0
  189. package/packages/store/dist/index.d.ts +6 -6
  190. package/packages/store/dist/index.js +1 -1
  191. package/packages/store/dist/lance-store.d.ts +37 -30
  192. package/packages/store/dist/lance-store.js +2 -1
  193. package/packages/store/dist/sqlite-graph-store.d.ts +43 -46
  194. package/packages/store/dist/sqlite-graph-store.js +14 -13
  195. package/packages/store/dist/store-factory.d.ts +11 -7
  196. package/packages/store/dist/store-factory.js +2 -1
  197. package/packages/store/dist/store.interface.d.ts +47 -44
  198. package/packages/store/dist/store.interface.js +1 -0
  199. package/packages/tools/dist/audit.d.ts +66 -0
  200. package/packages/tools/dist/audit.js +7 -0
  201. package/packages/tools/dist/batch.d.ts +20 -17
  202. package/packages/tools/dist/batch.js +2 -1
  203. package/packages/tools/dist/changelog.d.ts +29 -26
  204. package/packages/tools/dist/changelog.js +3 -2
  205. package/packages/tools/dist/check.d.ts +45 -22
  206. package/packages/tools/dist/check.js +3 -2
  207. package/packages/tools/dist/checkpoint.d.ts +17 -14
  208. package/packages/tools/dist/checkpoint.js +2 -2
  209. package/packages/tools/dist/codemod.d.ts +35 -32
  210. package/packages/tools/dist/codemod.js +3 -2
  211. package/packages/tools/dist/compact.d.ts +34 -35
  212. package/packages/tools/dist/compact.js +3 -2
  213. package/packages/tools/dist/data-transform.d.ts +10 -7
  214. package/packages/tools/dist/data-transform.js +2 -1
  215. package/packages/tools/dist/dead-symbols.d.ts +29 -17
  216. package/packages/tools/dist/dead-symbols.js +3 -2
  217. package/packages/tools/dist/delegate.d.ts +26 -23
  218. package/packages/tools/dist/delegate.js +2 -5
  219. package/packages/tools/dist/diff-parse.d.ts +24 -21
  220. package/packages/tools/dist/diff-parse.js +4 -3
  221. package/packages/tools/dist/digest.d.ts +43 -45
  222. package/packages/tools/dist/digest.js +5 -5
  223. package/packages/tools/dist/encode.d.ts +11 -8
  224. package/packages/tools/dist/encode.js +2 -1
  225. package/packages/tools/dist/env-info.d.ts +25 -22
  226. package/packages/tools/dist/env-info.js +2 -1
  227. package/packages/tools/dist/eval.d.ts +13 -10
  228. package/packages/tools/dist/eval.js +3 -3
  229. package/packages/tools/dist/evidence-map.d.ts +64 -61
  230. package/packages/tools/dist/evidence-map.js +3 -3
  231. package/packages/tools/dist/file-cache.d.ts +42 -0
  232. package/packages/tools/dist/file-cache.js +4 -0
  233. package/packages/tools/dist/file-summary.d.ts +34 -29
  234. package/packages/tools/dist/file-summary.js +3 -2
  235. package/packages/tools/dist/file-walk.d.ts +6 -3
  236. package/packages/tools/dist/file-walk.js +2 -1
  237. package/packages/tools/dist/find-examples.d.ts +26 -21
  238. package/packages/tools/dist/find-examples.js +4 -3
  239. package/packages/tools/dist/find.d.ts +39 -40
  240. package/packages/tools/dist/find.js +2 -1
  241. package/packages/tools/dist/forge-classify.d.ts +35 -38
  242. package/packages/tools/dist/forge-classify.js +3 -2
  243. package/packages/tools/dist/forge-ground.d.ts +58 -60
  244. package/packages/tools/dist/forge-ground.js +2 -1
  245. package/packages/tools/dist/git-context.d.ts +22 -19
  246. package/packages/tools/dist/git-context.js +4 -3
  247. package/packages/tools/dist/graph-query.d.ts +75 -78
  248. package/packages/tools/dist/graph-query.js +2 -1
  249. package/packages/tools/dist/guide.d.ts +26 -0
  250. package/packages/tools/dist/guide.js +2 -0
  251. package/packages/tools/dist/health.d.ts +13 -10
  252. package/packages/tools/dist/health.js +3 -1
  253. package/packages/tools/dist/http-request.d.ts +20 -17
  254. package/packages/tools/dist/http-request.js +2 -1
  255. package/packages/tools/dist/index.d.ts +54 -49
  256. package/packages/tools/dist/index.js +1 -1
  257. package/packages/tools/dist/lane.d.ts +28 -25
  258. package/packages/tools/dist/lane.js +7 -7
  259. package/packages/tools/dist/measure.d.ts +32 -29
  260. package/packages/tools/dist/measure.js +3 -2
  261. package/packages/tools/dist/onboard.d.ts +29 -26
  262. package/packages/tools/dist/onboard.js +18 -41
  263. package/packages/tools/dist/parse-output.d.ts +48 -45
  264. package/packages/tools/dist/parse-output.js +3 -2
  265. package/packages/tools/dist/path-resolver.d.ts +15 -0
  266. package/packages/tools/dist/path-resolver.js +2 -0
  267. package/packages/tools/dist/process-manager.d.ts +18 -15
  268. package/packages/tools/dist/process-manager.js +2 -1
  269. package/packages/tools/dist/queue.d.ts +28 -25
  270. package/packages/tools/dist/queue.js +2 -2
  271. package/packages/tools/dist/regex-test.d.ts +26 -23
  272. package/packages/tools/dist/regex-test.js +2 -1
  273. package/packages/tools/dist/rename.d.ts +28 -25
  274. package/packages/tools/dist/rename.js +3 -2
  275. package/packages/tools/dist/replay.d.ts +33 -30
  276. package/packages/tools/dist/replay.js +5 -6
  277. package/packages/tools/dist/response-envelope.d.ts +44 -0
  278. package/packages/tools/dist/response-envelope.js +2 -0
  279. package/packages/tools/dist/schema-validate.d.ts +15 -12
  280. package/packages/tools/dist/schema-validate.js +2 -1
  281. package/packages/tools/dist/scope-map.d.ts +45 -45
  282. package/packages/tools/dist/scope-map.js +2 -1
  283. package/packages/tools/dist/snippet.d.ts +26 -24
  284. package/packages/tools/dist/snippet.js +2 -1
  285. package/packages/tools/dist/stash.d.ts +13 -10
  286. package/packages/tools/dist/stash.js +2 -2
  287. package/packages/tools/dist/stratum-card.d.ts +27 -27
  288. package/packages/tools/dist/stratum-card.js +4 -5
  289. package/packages/tools/dist/symbol.d.ts +29 -25
  290. package/packages/tools/dist/symbol.js +4 -3
  291. package/packages/tools/dist/test-run.d.ts +19 -15
  292. package/packages/tools/dist/test-run.js +3 -2
  293. package/packages/tools/dist/text-utils.d.ts +6 -3
  294. package/packages/tools/dist/text-utils.js +3 -2
  295. package/packages/tools/dist/time-utils.d.ts +15 -12
  296. package/packages/tools/dist/time-utils.js +2 -1
  297. package/packages/tools/dist/trace.d.ts +24 -20
  298. package/packages/tools/dist/trace.js +3 -2
  299. package/packages/tools/dist/truncation.d.ts +14 -2
  300. package/packages/tools/dist/truncation.js +8 -14
  301. package/packages/tools/dist/watch.d.ts +28 -25
  302. package/packages/tools/dist/watch.js +2 -1
  303. package/packages/tools/dist/web-fetch.d.ts +35 -32
  304. package/packages/tools/dist/web-fetch.js +7 -12
  305. package/packages/tools/dist/web-search.d.ts +16 -13
  306. package/packages/tools/dist/web-search.js +2 -1
  307. package/packages/tools/dist/workset.d.ts +19 -16
  308. package/packages/tools/dist/workset.js +2 -2
  309. package/packages/tui/dist/App-BAlmxCCw.js +3 -0
  310. package/packages/tui/dist/App.d.ts +11 -5
  311. package/packages/tui/dist/App.js +1 -450
  312. package/packages/tui/dist/CuratedPanel-sYdZAICX.js +3 -0
  313. package/packages/tui/dist/LogPanel-DVB8Sv46.js +4 -0
  314. package/packages/tui/dist/SearchPanel-DREo6zgt.js +3 -0
  315. package/packages/tui/dist/StatusPanel-2ex8fLOO.js +3 -0
  316. package/packages/tui/dist/chunk-D6axbAb-.js +2 -0
  317. package/packages/tui/dist/devtools-DUyj952l.js +8 -0
  318. package/packages/tui/dist/embedder.interface-D4ew0HPW.d.ts +29 -0
  319. package/packages/tui/dist/index-B9VpfVPP.d.ts +14 -0
  320. package/packages/tui/dist/index.d.ts +3 -19
  321. package/packages/tui/dist/index.js +2 -476
  322. package/packages/tui/dist/jsx-runtime-Cof-kwFn.js +317 -0
  323. package/packages/tui/dist/panels/CuratedPanel.d.ts +11 -5
  324. package/packages/tui/dist/panels/CuratedPanel.js +1 -371
  325. package/packages/tui/dist/panels/LogPanel.d.ts +7 -2
  326. package/packages/tui/dist/panels/LogPanel.js +1 -449
  327. package/packages/tui/dist/panels/SearchPanel.d.ts +14 -7
  328. package/packages/tui/dist/panels/SearchPanel.js +1 -372
  329. package/packages/tui/dist/panels/StatusPanel.d.ts +11 -5
  330. package/packages/tui/dist/panels/StatusPanel.js +1 -371
  331. package/packages/tui/dist/store.interface-CnY6SPOH.d.ts +151 -0
  332. package/scaffold/adapters/claude-code.mjs +20 -0
  333. package/scaffold/adapters/copilot.mjs +320 -0
  334. package/scaffold/copilot/agents/Architect-Reviewer-Alpha.agent.md +14 -0
  335. package/scaffold/copilot/agents/Architect-Reviewer-Beta.agent.md +14 -0
  336. package/scaffold/copilot/agents/Code-Reviewer-Alpha.agent.md +12 -0
  337. package/scaffold/copilot/agents/Code-Reviewer-Beta.agent.md +12 -0
  338. package/scaffold/copilot/agents/Debugger.agent.md +31 -0
  339. package/scaffold/copilot/agents/Documenter.agent.md +35 -0
  340. package/scaffold/copilot/agents/Explorer.agent.md +50 -0
  341. package/scaffold/copilot/agents/Frontend.agent.md +29 -0
  342. package/scaffold/copilot/agents/Implementer.agent.md +31 -0
  343. package/scaffold/copilot/agents/Orchestrator.agent.md +96 -0
  344. package/scaffold/copilot/agents/Planner.agent.md +45 -0
  345. package/scaffold/copilot/agents/README.md +57 -0
  346. package/scaffold/copilot/agents/Refactor.agent.md +30 -0
  347. package/scaffold/copilot/agents/Researcher-Alpha.agent.md +12 -0
  348. package/scaffold/copilot/agents/Researcher-Beta.agent.md +12 -0
  349. package/scaffold/copilot/agents/Researcher-Delta.agent.md +12 -0
  350. package/scaffold/copilot/agents/Researcher-Gamma.agent.md +12 -0
  351. package/scaffold/copilot/agents/Security.agent.md +42 -0
  352. package/scaffold/copilot/agents/_shared/adr-protocol.md +91 -0
  353. package/scaffold/copilot/agents/_shared/architect-reviewer-base.md +50 -0
  354. package/scaffold/copilot/agents/_shared/code-agent-base.md +70 -0
  355. package/scaffold/copilot/agents/_shared/code-reviewer-base.md +54 -0
  356. package/scaffold/copilot/agents/_shared/decision-protocol.md +27 -0
  357. package/scaffold/copilot/agents/_shared/forge-protocol.md +46 -0
  358. package/scaffold/copilot/agents/_shared/researcher-base.md +61 -0
  359. package/scaffold/copilot/agents/templates/adr-template.md +27 -0
  360. package/scaffold/copilot/agents/templates/execution-state.md +25 -0
  361. package/scaffold/copilot/prompts/ask.prompt.md +20 -0
  362. package/scaffold/copilot/prompts/debug.prompt.md +25 -0
  363. package/scaffold/copilot/prompts/design.prompt.md +22 -0
  364. package/scaffold/copilot/prompts/implement.prompt.md +26 -0
  365. package/scaffold/copilot/prompts/plan.prompt.md +24 -0
  366. package/scaffold/copilot/prompts/review.prompt.md +31 -0
  367. package/scaffold/definitions/agents.mjs +165 -0
  368. package/scaffold/definitions/bodies.mjs +292 -0
  369. package/scaffold/definitions/hooks.mjs +43 -0
  370. package/scaffold/definitions/models.mjs +56 -0
  371. package/scaffold/definitions/plugins.mjs +24 -0
  372. package/scaffold/definitions/prompts.mjs +145 -0
  373. package/scaffold/definitions/protocols.mjs +322 -0
  374. package/scaffold/definitions/tools.mjs +176 -0
  375. package/scaffold/generate.mjs +74 -0
  376. package/skills/brainstorming/SKILL.md +259 -0
  377. package/skills/brainstorming/scripts/frame-template.html +365 -0
  378. package/skills/brainstorming/scripts/helper.js +216 -0
  379. package/skills/brainstorming/scripts/server.cjs +9 -0
  380. package/skills/brainstorming/scripts/server.src.cjs +249 -0
  381. package/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
  382. package/skills/brainstorming/visual-companion.md +430 -0
  383. package/skills/knowledge-base/SKILL.md +34 -21
@@ -0,0 +1,216 @@
1
+ /* helper.js — injected into every page served by the visual companion */
2
+
3
+ (() => {
4
+ let currentFile = null;
5
+ let pollTimer = null;
6
+
7
+ // --- Selection ---
8
+
9
+ function toggleSelect(el) {
10
+ const parent = el.closest('.options, .cards');
11
+ const isMulti = parent?.hasAttribute('data-multiselect');
12
+
13
+ if (!isMulti && parent) {
14
+ for (const sib of parent.querySelectorAll('.selected')) {
15
+ if (sib !== el) sib.classList.remove('selected');
16
+ }
17
+ }
18
+
19
+ el.classList.toggle('selected');
20
+ updateIndicator();
21
+ postEvent(el);
22
+ }
23
+
24
+ function updateIndicator() {
25
+ const selected = document.querySelectorAll('.selected');
26
+ const bar = document.getElementById('selection-indicator');
27
+ const text = document.getElementById('selection-text');
28
+ if (!bar || !text) return;
29
+
30
+ if (selected.length === 0) {
31
+ bar.classList.remove('visible');
32
+ return;
33
+ }
34
+
35
+ const labels = [];
36
+ for (const el of selected) {
37
+ const letter = el.querySelector('.letter');
38
+ const heading = el.querySelector('h3, h4');
39
+ labels.push(letter ? letter.textContent.trim() : heading ? heading.textContent.trim() : '?');
40
+ }
41
+ text.textContent = `Selected: ${labels.join(', ')}`;
42
+ bar.classList.add('visible');
43
+ }
44
+
45
+ // --- Events ---
46
+
47
+ function postEvent(el) {
48
+ const letter = el.querySelector('.letter');
49
+ const heading = el.querySelector('h3, h4');
50
+
51
+ const data = {
52
+ type: 'click',
53
+ choice: letter ? letter.textContent.trim() : '',
54
+ text: heading ? heading.textContent.trim() : el.textContent.trim().slice(0, 80),
55
+ selected: el.classList.contains('selected'),
56
+ timestamp: Date.now(),
57
+ };
58
+
59
+ fetch('/events', {
60
+ method: 'POST',
61
+ headers: { 'Content-Type': 'application/json' },
62
+ body: JSON.stringify(data),
63
+ }).catch(() => {
64
+ /* server may have stopped */
65
+ });
66
+ }
67
+
68
+ // --- Transport: WebSocket with polling fallback ---
69
+
70
+ function startTransport() {
71
+ if (!tryWebSocket()) {
72
+ startPolling();
73
+ }
74
+ }
75
+
76
+ function tryWebSocket() {
77
+ const protocol = location.protocol === 'https:' ? 'wss:' : 'ws:';
78
+ const url = `${protocol}//${location.host}`;
79
+ let ws;
80
+ try {
81
+ ws = new WebSocket(url);
82
+ } catch (_e) {
83
+ return false;
84
+ }
85
+
86
+ ws.onopen = () => {
87
+ // Connected — stop polling if it was running
88
+ if (pollTimer) {
89
+ clearInterval(pollTimer);
90
+ pollTimer = null;
91
+ }
92
+ };
93
+
94
+ ws.onmessage = (e) => {
95
+ try {
96
+ const msg = JSON.parse(e.data);
97
+ if (msg.type === 'new-file') {
98
+ if (currentFile === null) {
99
+ // First file arrived while showing "Waiting for content..." — reload
100
+ currentFile = msg.name;
101
+ location.reload();
102
+ } else if (msg.name !== currentFile) {
103
+ currentFile = msg.name;
104
+ location.reload();
105
+ }
106
+ }
107
+ // 'event' messages are echoes — browser doesn't need to act on them
108
+ } catch (_err) {
109
+ /* ignore malformed */
110
+ }
111
+ };
112
+
113
+ ws.onclose = () => {
114
+ // WebSocket lost — fall back to polling
115
+ startPolling();
116
+ };
117
+
118
+ ws.onerror = () => {
119
+ // Will trigger onclose → polling fallback
120
+ };
121
+
122
+ return true;
123
+ }
124
+
125
+ function startPolling() {
126
+ if (pollTimer) return;
127
+ pollTimer = setInterval(poll, 1500);
128
+ }
129
+
130
+ function poll() {
131
+ fetch('/poll')
132
+ .then((r) => (r.ok ? r.json() : null))
133
+ .then((data) => {
134
+ if (!data?.file) return;
135
+ if (currentFile === null) {
136
+ // First file arrived while showing "Waiting for content..." — reload
137
+ currentFile = data.file;
138
+ location.reload();
139
+ return;
140
+ }
141
+ if (data.file !== currentFile) {
142
+ currentFile = data.file;
143
+ location.reload();
144
+ }
145
+ })
146
+ .catch(() => {
147
+ /* ignore */
148
+ });
149
+ }
150
+
151
+ // --- Session state restoration ---
152
+
153
+ function restoreSelections() {
154
+ fetch('/state')
155
+ .then((r) => (r.ok ? r.json() : null))
156
+ .then((state) => {
157
+ if (!state?.currentScreen || !state.selections) return;
158
+ const screenSelections = state.selections[state.currentScreen];
159
+ if (!screenSelections || screenSelections.length === 0) return;
160
+
161
+ // Build a map of choice → selected
162
+ const choiceMap = {};
163
+ for (let i = 0; i < screenSelections.length; i++) {
164
+ if (screenSelections[i].selected !== false) {
165
+ choiceMap[screenSelections[i].choice] = true;
166
+ }
167
+ }
168
+
169
+ // Apply to DOM
170
+ const options = document.querySelectorAll('.option, .card');
171
+ for (let j = 0; j < options.length; j++) {
172
+ const letter = options[j].querySelector('.letter');
173
+ const key = letter ? letter.textContent.trim() : '';
174
+ if (choiceMap[key]) {
175
+ options[j].classList.add('selected');
176
+ }
177
+ }
178
+ updateIndicator();
179
+ })
180
+ .catch(() => {
181
+ /* no state yet, that's fine */
182
+ });
183
+ }
184
+
185
+ // --- Wire up ---
186
+
187
+ function init() {
188
+ // Attach click handlers to all options and cards
189
+ document.addEventListener('click', (e) => {
190
+ const option = e.target.closest('.option');
191
+ if (option) {
192
+ toggleSelect(option);
193
+ return;
194
+ }
195
+
196
+ const card = e.target.closest('.card');
197
+ if (card) {
198
+ toggleSelect(card);
199
+ return;
200
+ }
201
+ });
202
+
203
+ updateIndicator();
204
+ restoreSelections();
205
+ startTransport();
206
+ }
207
+
208
+ // Expose for inline onclick if needed
209
+ window.toggleSelect = toggleSelect;
210
+
211
+ if (document.readyState === 'loading') {
212
+ document.addEventListener('DOMContentLoaded', init);
213
+ } else {
214
+ init();
215
+ }
216
+ })();
@@ -0,0 +1,9 @@
1
+ var e=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),t=e(((e,t)=>{let n=[`nodebuffer`,`arraybuffer`,`fragments`],r=typeof Blob<`u`;r&&n.push(`blob`),t.exports={BINARY_TYPES:n,CLOSE_TIMEOUT:3e4,EMPTY_BUFFER:Buffer.alloc(0),GUID:`258EAFA5-E914-47DA-95CA-C5AB0DC85B11`,hasBlob:r,kForOnEventAttribute:Symbol(`kIsForOnEventAttribute`),kListener:Symbol(`kListener`),kStatusCode:Symbol(`status-code`),kWebSocket:Symbol(`websocket`),NOOP:()=>{}}})),n=e(((e,n)=>{let{EMPTY_BUFFER:r}=t(),i=Buffer[Symbol.species];function a(e,t){if(e.length===0)return r;if(e.length===1)return e[0];let n=Buffer.allocUnsafe(t),a=0;for(let t=0;t<e.length;t++){let r=e[t];n.set(r,a),a+=r.length}return a<t?new i(n.buffer,n.byteOffset,a):n}function o(e,t,n,r,i){for(let a=0;a<i;a++)n[r+a]=e[a]^t[a&3]}function s(e,t){for(let n=0;n<e.length;n++)e[n]^=t[n&3]}function c(e){return e.length===e.buffer.byteLength?e.buffer:e.buffer.slice(e.byteOffset,e.byteOffset+e.length)}function l(e){if(l.readOnly=!0,Buffer.isBuffer(e))return e;let t;return e instanceof ArrayBuffer?t=new i(e):ArrayBuffer.isView(e)?t=new i(e.buffer,e.byteOffset,e.byteLength):(t=Buffer.from(e),l.readOnly=!1),t}if(n.exports={concat:a,mask:o,toArrayBuffer:c,toBuffer:l,unmask:s},!process.env.WS_NO_BUFFER_UTIL)try{let e=require(`bufferutil`);n.exports.mask=function(t,n,r,i,a){a<48?o(t,n,r,i,a):e.mask(t,n,r,i,a)},n.exports.unmask=function(t,n){t.length<32?s(t,n):e.unmask(t,n)}}catch{}})),r=e(((e,t)=>{let n=Symbol(`kDone`),r=Symbol(`kRun`);t.exports=class{constructor(e){this[n]=()=>{this.pending--,this[r]()},this.concurrency=e||1/0,this.jobs=[],this.pending=0}add(e){this.jobs.push(e),this[r]()}[r](){if(this.pending!==this.concurrency&&this.jobs.length){let e=this.jobs.shift();this.pending++,e(this[n])}}}})),i=e(((e,i)=>{let a=require(`zlib`),o=n(),s=r(),{kStatusCode:c}=t(),l=Buffer[Symbol.species],u=Buffer.from([0,0,255,255]),d=Symbol(`permessage-deflate`),f=Symbol(`total-length`),p=Symbol(`callback`),m=Symbol(`buffers`),h=Symbol(`error`),g;i.exports=class{constructor(e){this._options=e||{},this._threshold=this._options.threshold===void 0?1024:this._options.threshold,this._maxPayload=this._options.maxPayload|0,this._isServer=!!this._options.isServer,this._deflate=null,this._inflate=null,this.params=null,g||=new s(this._options.concurrencyLimit===void 0?10:this._options.concurrencyLimit)}static get extensionName(){return`permessage-deflate`}offer(){let e={};return this._options.serverNoContextTakeover&&(e.server_no_context_takeover=!0),this._options.clientNoContextTakeover&&(e.client_no_context_takeover=!0),this._options.serverMaxWindowBits&&(e.server_max_window_bits=this._options.serverMaxWindowBits),this._options.clientMaxWindowBits?e.client_max_window_bits=this._options.clientMaxWindowBits:this._options.clientMaxWindowBits??(e.client_max_window_bits=!0),e}accept(e){return e=this.normalizeParams(e),this.params=this._isServer?this.acceptAsServer(e):this.acceptAsClient(e),this.params}cleanup(){if(this._inflate&&=(this._inflate.close(),null),this._deflate){let e=this._deflate[p];this._deflate.close(),this._deflate=null,e&&e(Error(`The deflate stream was closed while data was being processed`))}}acceptAsServer(e){let t=this._options,n=e.find(e=>!(t.serverNoContextTakeover===!1&&e.server_no_context_takeover||e.server_max_window_bits&&(t.serverMaxWindowBits===!1||typeof t.serverMaxWindowBits==`number`&&t.serverMaxWindowBits>e.server_max_window_bits)||typeof t.clientMaxWindowBits==`number`&&!e.client_max_window_bits));if(!n)throw Error(`None of the extension offers can be accepted`);return t.serverNoContextTakeover&&(n.server_no_context_takeover=!0),t.clientNoContextTakeover&&(n.client_no_context_takeover=!0),typeof t.serverMaxWindowBits==`number`&&(n.server_max_window_bits=t.serverMaxWindowBits),typeof t.clientMaxWindowBits==`number`?n.client_max_window_bits=t.clientMaxWindowBits:(n.client_max_window_bits===!0||t.clientMaxWindowBits===!1)&&delete n.client_max_window_bits,n}acceptAsClient(e){let t=e[0];if(this._options.clientNoContextTakeover===!1&&t.client_no_context_takeover)throw Error(`Unexpected parameter "client_no_context_takeover"`);if(!t.client_max_window_bits)typeof this._options.clientMaxWindowBits==`number`&&(t.client_max_window_bits=this._options.clientMaxWindowBits);else if(this._options.clientMaxWindowBits===!1||typeof this._options.clientMaxWindowBits==`number`&&t.client_max_window_bits>this._options.clientMaxWindowBits)throw Error(`Unexpected or invalid parameter "client_max_window_bits"`);return t}normalizeParams(e){return e.forEach(e=>{Object.keys(e).forEach(t=>{let n=e[t];if(n.length>1)throw Error(`Parameter "${t}" must have only a single value`);if(n=n[0],t===`client_max_window_bits`){if(n!==!0){let e=+n;if(!Number.isInteger(e)||e<8||e>15)throw TypeError(`Invalid value for parameter "${t}": ${n}`);n=e}else if(!this._isServer)throw TypeError(`Invalid value for parameter "${t}": ${n}`)}else if(t===`server_max_window_bits`){let e=+n;if(!Number.isInteger(e)||e<8||e>15)throw TypeError(`Invalid value for parameter "${t}": ${n}`);n=e}else if(t===`client_no_context_takeover`||t===`server_no_context_takeover`){if(n!==!0)throw TypeError(`Invalid value for parameter "${t}": ${n}`)}else throw Error(`Unknown parameter "${t}"`);e[t]=n})}),e}decompress(e,t,n){g.add(r=>{this._decompress(e,t,(e,t)=>{r(),n(e,t)})})}compress(e,t,n){g.add(r=>{this._compress(e,t,(e,t)=>{r(),n(e,t)})})}_decompress(e,t,n){let r=this._isServer?`client`:`server`;if(!this._inflate){let e=`${r}_max_window_bits`,t=typeof this.params[e]==`number`?this.params[e]:a.Z_DEFAULT_WINDOWBITS;this._inflate=a.createInflateRaw({...this._options.zlibInflateOptions,windowBits:t}),this._inflate[d]=this,this._inflate[f]=0,this._inflate[m]=[],this._inflate.on(`error`,y),this._inflate.on(`data`,v)}this._inflate[p]=n,this._inflate.write(e),t&&this._inflate.write(u),this._inflate.flush(()=>{let e=this._inflate[h];if(e){this._inflate.close(),this._inflate=null,n(e);return}let i=o.concat(this._inflate[m],this._inflate[f]);this._inflate._readableState.endEmitted?(this._inflate.close(),this._inflate=null):(this._inflate[f]=0,this._inflate[m]=[],t&&this.params[`${r}_no_context_takeover`]&&this._inflate.reset()),n(null,i)})}_compress(e,t,n){let r=this._isServer?`server`:`client`;if(!this._deflate){let e=`${r}_max_window_bits`,t=typeof this.params[e]==`number`?this.params[e]:a.Z_DEFAULT_WINDOWBITS;this._deflate=a.createDeflateRaw({...this._options.zlibDeflateOptions,windowBits:t}),this._deflate[f]=0,this._deflate[m]=[],this._deflate.on(`data`,_)}this._deflate[p]=n,this._deflate.write(e),this._deflate.flush(a.Z_SYNC_FLUSH,()=>{if(!this._deflate)return;let e=o.concat(this._deflate[m],this._deflate[f]);t&&(e=new l(e.buffer,e.byteOffset,e.length-4)),this._deflate[p]=null,this._deflate[f]=0,this._deflate[m]=[],t&&this.params[`${r}_no_context_takeover`]&&this._deflate.reset(),n(null,e)})}};function _(e){this[m].push(e),this[f]+=e.length}function v(e){if(this[f]+=e.length,this[d]._maxPayload<1||this[f]<=this[d]._maxPayload){this[m].push(e);return}this[h]=RangeError(`Max payload size exceeded`),this[h].code=`WS_ERR_UNSUPPORTED_MESSAGE_LENGTH`,this[h][c]=1009,this.removeListener(`data`,v),this.reset()}function y(e){if(this[d]._inflate=null,this[h]){this[p](this[h]);return}e[c]=1007,this[p](e)}})),a=e(((e,n)=>{let{isUtf8:r}=require(`buffer`),{hasBlob:i}=t(),a=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0];function o(e){return e>=1e3&&e<=1014&&e!==1004&&e!==1005&&e!==1006||e>=3e3&&e<=4999}function s(e){let t=e.length,n=0;for(;n<t;)if(!(e[n]&128))n++;else if((e[n]&224)==192){if(n+1===t||(e[n+1]&192)!=128||(e[n]&254)==192)return!1;n+=2}else if((e[n]&240)==224){if(n+2>=t||(e[n+1]&192)!=128||(e[n+2]&192)!=128||e[n]===224&&(e[n+1]&224)==128||e[n]===237&&(e[n+1]&224)==160)return!1;n+=3}else if((e[n]&248)==240){if(n+3>=t||(e[n+1]&192)!=128||(e[n+2]&192)!=128||(e[n+3]&192)!=128||e[n]===240&&(e[n+1]&240)==128||e[n]===244&&e[n+1]>143||e[n]>244)return!1;n+=4}else return!1;return!0}function c(e){return i&&typeof e==`object`&&typeof e.arrayBuffer==`function`&&typeof e.type==`string`&&typeof e.stream==`function`&&(e[Symbol.toStringTag]===`Blob`||e[Symbol.toStringTag]===`File`)}if(n.exports={isBlob:c,isValidStatusCode:o,isValidUTF8:s,tokenChars:a},r)n.exports.isValidUTF8=function(e){return e.length<24?s(e):r(e)};else if(!process.env.WS_NO_UTF_8_VALIDATE)try{let e=require(`utf-8-validate`);n.exports.isValidUTF8=function(t){return t.length<32?s(t):e(t)}}catch{}})),o=e(((e,r)=>{let{Writable:o}=require(`stream`),s=i(),{BINARY_TYPES:c,EMPTY_BUFFER:l,kStatusCode:u,kWebSocket:d}=t(),{concat:f,toArrayBuffer:p,unmask:m}=n(),{isValidStatusCode:h,isValidUTF8:g}=a(),_=Buffer[Symbol.species];r.exports=class extends o{constructor(e={}){super(),this._allowSynchronousEvents=e.allowSynchronousEvents===void 0?!0:e.allowSynchronousEvents,this._binaryType=e.binaryType||c[0],this._extensions=e.extensions||{},this._isServer=!!e.isServer,this._maxPayload=e.maxPayload|0,this._skipUTF8Validation=!!e.skipUTF8Validation,this[d]=void 0,this._bufferedBytes=0,this._buffers=[],this._compressed=!1,this._payloadLength=0,this._mask=void 0,this._fragmented=0,this._masked=!1,this._fin=!1,this._opcode=0,this._totalPayloadLength=0,this._messageLength=0,this._fragments=[],this._errored=!1,this._loop=!1,this._state=0}_write(e,t,n){if(this._opcode===8&&this._state==0)return n();this._bufferedBytes+=e.length,this._buffers.push(e),this.startLoop(n)}consume(e){if(this._bufferedBytes-=e,e===this._buffers[0].length)return this._buffers.shift();if(e<this._buffers[0].length){let t=this._buffers[0];return this._buffers[0]=new _(t.buffer,t.byteOffset+e,t.length-e),new _(t.buffer,t.byteOffset,e)}let t=Buffer.allocUnsafe(e);do{let n=this._buffers[0],r=t.length-e;e>=n.length?t.set(this._buffers.shift(),r):(t.set(new Uint8Array(n.buffer,n.byteOffset,e),r),this._buffers[0]=new _(n.buffer,n.byteOffset+e,n.length-e)),e-=n.length}while(e>0);return t}startLoop(e){this._loop=!0;do switch(this._state){case 0:this.getInfo(e);break;case 1:this.getPayloadLength16(e);break;case 2:this.getPayloadLength64(e);break;case 3:this.getMask();break;case 4:this.getData(e);break;case 5:case 6:this._loop=!1;return}while(this._loop);this._errored||e()}getInfo(e){if(this._bufferedBytes<2){this._loop=!1;return}let t=this.consume(2);if(t[0]&48){e(this.createError(RangeError,`RSV2 and RSV3 must be clear`,!0,1002,`WS_ERR_UNEXPECTED_RSV_2_3`));return}let n=(t[0]&64)==64;if(n&&!this._extensions[s.extensionName]){e(this.createError(RangeError,`RSV1 must be clear`,!0,1002,`WS_ERR_UNEXPECTED_RSV_1`));return}if(this._fin=(t[0]&128)==128,this._opcode=t[0]&15,this._payloadLength=t[1]&127,this._opcode===0){if(n){e(this.createError(RangeError,`RSV1 must be clear`,!0,1002,`WS_ERR_UNEXPECTED_RSV_1`));return}if(!this._fragmented){e(this.createError(RangeError,`invalid opcode 0`,!0,1002,`WS_ERR_INVALID_OPCODE`));return}this._opcode=this._fragmented}else if(this._opcode===1||this._opcode===2){if(this._fragmented){e(this.createError(RangeError,`invalid opcode ${this._opcode}`,!0,1002,`WS_ERR_INVALID_OPCODE`));return}this._compressed=n}else if(this._opcode>7&&this._opcode<11){if(!this._fin){e(this.createError(RangeError,`FIN must be set`,!0,1002,`WS_ERR_EXPECTED_FIN`));return}if(n){e(this.createError(RangeError,`RSV1 must be clear`,!0,1002,`WS_ERR_UNEXPECTED_RSV_1`));return}if(this._payloadLength>125||this._opcode===8&&this._payloadLength===1){e(this.createError(RangeError,`invalid payload length ${this._payloadLength}`,!0,1002,`WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH`));return}}else{e(this.createError(RangeError,`invalid opcode ${this._opcode}`,!0,1002,`WS_ERR_INVALID_OPCODE`));return}if(!this._fin&&!this._fragmented&&(this._fragmented=this._opcode),this._masked=(t[1]&128)==128,this._isServer){if(!this._masked){e(this.createError(RangeError,`MASK must be set`,!0,1002,`WS_ERR_EXPECTED_MASK`));return}}else if(this._masked){e(this.createError(RangeError,`MASK must be clear`,!0,1002,`WS_ERR_UNEXPECTED_MASK`));return}this._payloadLength===126?this._state=1:this._payloadLength===127?this._state=2:this.haveLength(e)}getPayloadLength16(e){if(this._bufferedBytes<2){this._loop=!1;return}this._payloadLength=this.consume(2).readUInt16BE(0),this.haveLength(e)}getPayloadLength64(e){if(this._bufferedBytes<8){this._loop=!1;return}let t=this.consume(8),n=t.readUInt32BE(0);if(n>2**21-1){e(this.createError(RangeError,`Unsupported WebSocket frame: payload length > 2^53 - 1`,!1,1009,`WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH`));return}this._payloadLength=n*2**32+t.readUInt32BE(4),this.haveLength(e)}haveLength(e){if(this._payloadLength&&this._opcode<8&&(this._totalPayloadLength+=this._payloadLength,this._totalPayloadLength>this._maxPayload&&this._maxPayload>0)){e(this.createError(RangeError,`Max payload size exceeded`,!1,1009,`WS_ERR_UNSUPPORTED_MESSAGE_LENGTH`));return}this._masked?this._state=3:this._state=4}getMask(){if(this._bufferedBytes<4){this._loop=!1;return}this._mask=this.consume(4),this._state=4}getData(e){let t=l;if(this._payloadLength){if(this._bufferedBytes<this._payloadLength){this._loop=!1;return}t=this.consume(this._payloadLength),this._masked&&(this._mask[0]|this._mask[1]|this._mask[2]|this._mask[3])!==0&&m(t,this._mask)}if(this._opcode>7){this.controlMessage(t,e);return}if(this._compressed){this._state=5,this.decompress(t,e);return}t.length&&(this._messageLength=this._totalPayloadLength,this._fragments.push(t)),this.dataMessage(e)}decompress(e,t){this._extensions[s.extensionName].decompress(e,this._fin,(e,n)=>{if(e)return t(e);if(n.length){if(this._messageLength+=n.length,this._messageLength>this._maxPayload&&this._maxPayload>0){t(this.createError(RangeError,`Max payload size exceeded`,!1,1009,`WS_ERR_UNSUPPORTED_MESSAGE_LENGTH`));return}this._fragments.push(n)}this.dataMessage(t),this._state===0&&this.startLoop(t)})}dataMessage(e){if(!this._fin){this._state=0;return}let t=this._messageLength,n=this._fragments;if(this._totalPayloadLength=0,this._messageLength=0,this._fragmented=0,this._fragments=[],this._opcode===2){let r;r=this._binaryType===`nodebuffer`?f(n,t):this._binaryType===`arraybuffer`?p(f(n,t)):this._binaryType===`blob`?new Blob(n):n,this._allowSynchronousEvents?(this.emit(`message`,r,!0),this._state=0):(this._state=6,setImmediate(()=>{this.emit(`message`,r,!0),this._state=0,this.startLoop(e)}))}else{let r=f(n,t);if(!this._skipUTF8Validation&&!g(r)){e(this.createError(Error,`invalid UTF-8 sequence`,!0,1007,`WS_ERR_INVALID_UTF8`));return}this._state===5||this._allowSynchronousEvents?(this.emit(`message`,r,!1),this._state=0):(this._state=6,setImmediate(()=>{this.emit(`message`,r,!1),this._state=0,this.startLoop(e)}))}}controlMessage(e,t){if(this._opcode===8){if(e.length===0)this._loop=!1,this.emit(`conclude`,1005,l),this.end();else{let n=e.readUInt16BE(0);if(!h(n)){t(this.createError(RangeError,`invalid status code ${n}`,!0,1002,`WS_ERR_INVALID_CLOSE_CODE`));return}let r=new _(e.buffer,e.byteOffset+2,e.length-2);if(!this._skipUTF8Validation&&!g(r)){t(this.createError(Error,`invalid UTF-8 sequence`,!0,1007,`WS_ERR_INVALID_UTF8`));return}this._loop=!1,this.emit(`conclude`,n,r),this.end()}this._state=0;return}this._allowSynchronousEvents?(this.emit(this._opcode===9?`ping`:`pong`,e),this._state=0):(this._state=6,setImmediate(()=>{this.emit(this._opcode===9?`ping`:`pong`,e),this._state=0,this.startLoop(t)}))}createError(e,t,n,r,i){this._loop=!1,this._errored=!0;let a=new e(n?`Invalid WebSocket frame: ${t}`:t);return Error.captureStackTrace(a,this.createError),a.code=i,a[u]=r,a}}})),s=e(((e,r)=>{let{Duplex:o}=require(`stream`),{randomFillSync:s}=require(`crypto`),c=i(),{EMPTY_BUFFER:l,kWebSocket:u,NOOP:d}=t(),{isBlob:f,isValidStatusCode:p}=a(),{mask:m,toBuffer:h}=n(),g=Symbol(`kByteLength`),_=Buffer.alloc(4),v=8*1024,y,b=v;r.exports=class e{constructor(e,t,n){this._extensions=t||{},n&&(this._generateMask=n,this._maskBuffer=Buffer.alloc(4)),this._socket=e,this._firstFragment=!0,this._compress=!1,this._bufferedBytes=0,this._queue=[],this._state=0,this.onerror=d,this[u]=void 0}static frame(e,t){let n,r=!1,i=2,a=!1;t.mask&&(n=t.maskBuffer||_,t.generateMask?t.generateMask(n):(b===v&&(y===void 0&&(y=Buffer.alloc(v)),s(y,0,v),b=0),n[0]=y[b++],n[1]=y[b++],n[2]=y[b++],n[3]=y[b++]),a=(n[0]|n[1]|n[2]|n[3])===0,i=6);let o;typeof e==`string`?(!t.mask||a)&&t[g]!==void 0?o=t[g]:(e=Buffer.from(e),o=e.length):(o=e.length,r=t.mask&&t.readOnly&&!a);let c=o;o>=65536?(i+=8,c=127):o>125&&(i+=2,c=126);let l=Buffer.allocUnsafe(r?o+i:i);return l[0]=t.fin?t.opcode|128:t.opcode,t.rsv1&&(l[0]|=64),l[1]=c,c===126?l.writeUInt16BE(o,2):c===127&&(l[2]=l[3]=0,l.writeUIntBE(o,4,6)),!t.mask||(l[1]|=128,l[i-4]=n[0],l[i-3]=n[1],l[i-2]=n[2],l[i-1]=n[3],a)?[l,e]:r?(m(e,n,l,i,o),[l]):(m(e,n,e,0,o),[l,e])}close(t,n,r,i){let a;if(t===void 0)a=l;else if(typeof t!=`number`||!p(t))throw TypeError(`First argument must be a valid error code number`);else if(n===void 0||!n.length)a=Buffer.allocUnsafe(2),a.writeUInt16BE(t,0);else{let e=Buffer.byteLength(n);if(e>123)throw RangeError(`The message must not be greater than 123 bytes`);a=Buffer.allocUnsafe(2+e),a.writeUInt16BE(t,0),typeof n==`string`?a.write(n,2):a.set(n,2)}let o={[g]:a.length,fin:!0,generateMask:this._generateMask,mask:r,maskBuffer:this._maskBuffer,opcode:8,readOnly:!1,rsv1:!1};this._state===0?this.sendFrame(e.frame(a,o),i):this.enqueue([this.dispatch,a,!1,o,i])}ping(t,n,r){let i,a;if(typeof t==`string`?(i=Buffer.byteLength(t),a=!1):f(t)?(i=t.size,a=!1):(t=h(t),i=t.length,a=h.readOnly),i>125)throw RangeError(`The data size must not be greater than 125 bytes`);let o={[g]:i,fin:!0,generateMask:this._generateMask,mask:n,maskBuffer:this._maskBuffer,opcode:9,readOnly:a,rsv1:!1};f(t)?this._state===0?this.getBlobData(t,!1,o,r):this.enqueue([this.getBlobData,t,!1,o,r]):this._state===0?this.sendFrame(e.frame(t,o),r):this.enqueue([this.dispatch,t,!1,o,r])}pong(t,n,r){let i,a;if(typeof t==`string`?(i=Buffer.byteLength(t),a=!1):f(t)?(i=t.size,a=!1):(t=h(t),i=t.length,a=h.readOnly),i>125)throw RangeError(`The data size must not be greater than 125 bytes`);let o={[g]:i,fin:!0,generateMask:this._generateMask,mask:n,maskBuffer:this._maskBuffer,opcode:10,readOnly:a,rsv1:!1};f(t)?this._state===0?this.getBlobData(t,!1,o,r):this.enqueue([this.getBlobData,t,!1,o,r]):this._state===0?this.sendFrame(e.frame(t,o),r):this.enqueue([this.dispatch,t,!1,o,r])}send(e,t,n){let r=this._extensions[c.extensionName],i=t.binary?2:1,a=t.compress,o,s;typeof e==`string`?(o=Buffer.byteLength(e),s=!1):f(e)?(o=e.size,s=!1):(e=h(e),o=e.length,s=h.readOnly),this._firstFragment?(this._firstFragment=!1,a&&r&&r.params[r._isServer?`server_no_context_takeover`:`client_no_context_takeover`]&&(a=o>=r._threshold),this._compress=a):(a=!1,i=0),t.fin&&(this._firstFragment=!0);let l={[g]:o,fin:t.fin,generateMask:this._generateMask,mask:t.mask,maskBuffer:this._maskBuffer,opcode:i,readOnly:s,rsv1:a};f(e)?this._state===0?this.getBlobData(e,this._compress,l,n):this.enqueue([this.getBlobData,e,this._compress,l,n]):this._state===0?this.dispatch(e,this._compress,l,n):this.enqueue([this.dispatch,e,this._compress,l,n])}getBlobData(t,n,r,i){this._bufferedBytes+=r[g],this._state=2,t.arrayBuffer().then(t=>{if(this._socket.destroyed){let e=Error(`The socket was closed while the blob was being read`);process.nextTick(x,this,e,i);return}this._bufferedBytes-=r[g];let a=h(t);n?this.dispatch(a,n,r,i):(this._state=0,this.sendFrame(e.frame(a,r),i),this.dequeue())}).catch(e=>{process.nextTick(S,this,e,i)})}dispatch(t,n,r,i){if(!n){this.sendFrame(e.frame(t,r),i);return}let a=this._extensions[c.extensionName];this._bufferedBytes+=r[g],this._state=1,a.compress(t,r.fin,(t,n)=>{if(this._socket.destroyed){x(this,Error(`The socket was closed while data was being compressed`),i);return}this._bufferedBytes-=r[g],this._state=0,r.readOnly=!1,this.sendFrame(e.frame(n,r),i),this.dequeue()})}dequeue(){for(;this._state===0&&this._queue.length;){let e=this._queue.shift();this._bufferedBytes-=e[3][g],Reflect.apply(e[0],this,e.slice(1))}}enqueue(e){this._bufferedBytes+=e[3][g],this._queue.push(e)}sendFrame(e,t){e.length===2?(this._socket.cork(),this._socket.write(e[0]),this._socket.write(e[1],t),this._socket.uncork()):this._socket.write(e[0],t)}};function x(e,t,n){typeof n==`function`&&n(t);for(let n=0;n<e._queue.length;n++){let r=e._queue[n],i=r[r.length-1];typeof i==`function`&&i(t)}}function S(e,t,n){x(e,t,n),e.onerror(t)}})),c=e(((e,n)=>{let{kForOnEventAttribute:r,kListener:i}=t(),a=Symbol(`kCode`),o=Symbol(`kData`),s=Symbol(`kError`),c=Symbol(`kMessage`),l=Symbol(`kReason`),u=Symbol(`kTarget`),d=Symbol(`kType`),f=Symbol(`kWasClean`);var p=class{constructor(e){this[u]=null,this[d]=e}get target(){return this[u]}get type(){return this[d]}};Object.defineProperty(p.prototype,`target`,{enumerable:!0}),Object.defineProperty(p.prototype,`type`,{enumerable:!0});var m=class extends p{constructor(e,t={}){super(e),this[a]=t.code===void 0?0:t.code,this[l]=t.reason===void 0?``:t.reason,this[f]=t.wasClean===void 0?!1:t.wasClean}get code(){return this[a]}get reason(){return this[l]}get wasClean(){return this[f]}};Object.defineProperty(m.prototype,`code`,{enumerable:!0}),Object.defineProperty(m.prototype,`reason`,{enumerable:!0}),Object.defineProperty(m.prototype,`wasClean`,{enumerable:!0});var h=class extends p{constructor(e,t={}){super(e),this[s]=t.error===void 0?null:t.error,this[c]=t.message===void 0?``:t.message}get error(){return this[s]}get message(){return this[c]}};Object.defineProperty(h.prototype,`error`,{enumerable:!0}),Object.defineProperty(h.prototype,`message`,{enumerable:!0});var g=class extends p{constructor(e,t={}){super(e),this[o]=t.data===void 0?null:t.data}get data(){return this[o]}};Object.defineProperty(g.prototype,`data`,{enumerable:!0}),n.exports={CloseEvent:m,ErrorEvent:h,Event:p,EventTarget:{addEventListener(e,t,n={}){for(let a of this.listeners(e))if(!n[r]&&a[i]===t&&!a[r])return;let a;if(e===`message`)a=function(e,n){let r=new g(`message`,{data:n?e:e.toString()});r[u]=this,_(t,this,r)};else if(e===`close`)a=function(e,n){let r=new m(`close`,{code:e,reason:n.toString(),wasClean:this._closeFrameReceived&&this._closeFrameSent});r[u]=this,_(t,this,r)};else if(e===`error`)a=function(e){let n=new h(`error`,{error:e,message:e.message});n[u]=this,_(t,this,n)};else if(e===`open`)a=function(){let e=new p(`open`);e[u]=this,_(t,this,e)};else return;a[r]=!!n[r],a[i]=t,n.once?this.once(e,a):this.on(e,a)},removeEventListener(e,t){for(let n of this.listeners(e))if(n[i]===t&&!n[r]){this.removeListener(e,n);break}}},MessageEvent:g};function _(e,t,n){typeof e==`object`&&e.handleEvent?e.handleEvent.call(e,n):e.call(t,n)}})),l=e(((e,t)=>{let{tokenChars:n}=a();function r(e,t,n){e[t]===void 0?e[t]=[n]:e[t].push(n)}function i(e){let t=Object.create(null),i=Object.create(null),a=!1,o=!1,s=!1,c,l,u=-1,d=-1,f=-1,p=0;for(;p<e.length;p++)if(d=e.charCodeAt(p),c===void 0)if(f===-1&&n[d]===1)u===-1&&(u=p);else if(p!==0&&(d===32||d===9))f===-1&&u!==-1&&(f=p);else if(d===59||d===44){if(u===-1)throw SyntaxError(`Unexpected character at index ${p}`);f===-1&&(f=p);let n=e.slice(u,f);d===44?(r(t,n,i),i=Object.create(null)):c=n,u=f=-1}else throw SyntaxError(`Unexpected character at index ${p}`);else if(l===void 0)if(f===-1&&n[d]===1)u===-1&&(u=p);else if(d===32||d===9)f===-1&&u!==-1&&(f=p);else if(d===59||d===44){if(u===-1)throw SyntaxError(`Unexpected character at index ${p}`);f===-1&&(f=p),r(i,e.slice(u,f),!0),d===44&&(r(t,c,i),i=Object.create(null),c=void 0),u=f=-1}else if(d===61&&u!==-1&&f===-1)l=e.slice(u,p),u=f=-1;else throw SyntaxError(`Unexpected character at index ${p}`);else if(o){if(n[d]!==1)throw SyntaxError(`Unexpected character at index ${p}`);u===-1?u=p:a||=!0,o=!1}else if(s)if(n[d]===1)u===-1&&(u=p);else if(d===34&&u!==-1)s=!1,f=p;else if(d===92)o=!0;else throw SyntaxError(`Unexpected character at index ${p}`);else if(d===34&&e.charCodeAt(p-1)===61)s=!0;else if(f===-1&&n[d]===1)u===-1&&(u=p);else if(u!==-1&&(d===32||d===9))f===-1&&(f=p);else if(d===59||d===44){if(u===-1)throw SyntaxError(`Unexpected character at index ${p}`);f===-1&&(f=p);let n=e.slice(u,f);a&&=(n=n.replace(/\\/g,``),!1),r(i,l,n),d===44&&(r(t,c,i),i=Object.create(null),c=void 0),l=void 0,u=f=-1}else throw SyntaxError(`Unexpected character at index ${p}`);if(u===-1||s||d===32||d===9)throw SyntaxError(`Unexpected end of input`);f===-1&&(f=p);let m=e.slice(u,f);return c===void 0?r(t,m,i):(l===void 0?r(i,m,!0):a?r(i,l,m.replace(/\\/g,``)):r(i,l,m),r(t,c,i)),t}function o(e){return Object.keys(e).map(t=>{let n=e[t];return Array.isArray(n)||(n=[n]),n.map(e=>[t].concat(Object.keys(e).map(t=>{let n=e[t];return Array.isArray(n)||(n=[n]),n.map(e=>e===!0?t:`${t}=${e}`).join(`; `)})).join(`; `)).join(`, `)}).join(`, `)}t.exports={format:o,parse:i}})),u=e(((e,r)=>{let u=require(`events`),d=require(`https`),f=require(`http`),p=require(`net`),m=require(`tls`),{randomBytes:h,createHash:g}=require(`crypto`),{Duplex:_,Readable:v}=require(`stream`),{URL:y}=require(`url`),b=i(),x=o(),S=s(),{isBlob:C}=a(),{BINARY_TYPES:w,CLOSE_TIMEOUT:T,EMPTY_BUFFER:E,GUID:D,kForOnEventAttribute:O,kListener:k,kStatusCode:A,kWebSocket:j,NOOP:M}=t(),{EventTarget:{addEventListener:N,removeEventListener:P}}=c(),{format:F,parse:I}=l(),{toBuffer:L}=n(),R=Symbol(`kAborted`),z=[8,13],B=[`CONNECTING`,`OPEN`,`CLOSING`,`CLOSED`],ee=/^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;var V=class e extends u{constructor(t,n,r){super(),this._binaryType=w[0],this._closeCode=1006,this._closeFrameReceived=!1,this._closeFrameSent=!1,this._closeMessage=E,this._closeTimer=null,this._errorEmitted=!1,this._extensions={},this._paused=!1,this._protocol=``,this._readyState=e.CONNECTING,this._receiver=null,this._sender=null,this._socket=null,t===null?(this._autoPong=r.autoPong,this._closeTimeout=r.closeTimeout,this._isServer=!0):(this._bufferedAmount=0,this._isServer=!1,this._redirects=0,n===void 0?n=[]:Array.isArray(n)||(typeof n==`object`&&n?(r=n,n=[]):n=[n]),H(this,t,n,r))}get binaryType(){return this._binaryType}set binaryType(e){w.includes(e)&&(this._binaryType=e,this._receiver&&(this._receiver._binaryType=e))}get bufferedAmount(){return this._socket?this._socket._writableState.length+this._sender._bufferedBytes:this._bufferedAmount}get extensions(){return Object.keys(this._extensions).join()}get isPaused(){return this._paused}get onclose(){return null}get onerror(){return null}get onopen(){return null}get onmessage(){return null}get protocol(){return this._protocol}get readyState(){return this._readyState}get url(){return this._url}setSocket(t,n,r){let i=new x({allowSynchronousEvents:r.allowSynchronousEvents,binaryType:this.binaryType,extensions:this._extensions,isServer:this._isServer,maxPayload:r.maxPayload,skipUTF8Validation:r.skipUTF8Validation}),a=new S(t,this._extensions,r.generateMask);this._receiver=i,this._sender=a,this._socket=t,i[j]=this,a[j]=this,t[j]=this,i.on(`conclude`,re),i.on(`drain`,ie),i.on(`error`,ae),i.on(`message`,oe),i.on(`ping`,se),i.on(`pong`,ce),a.onerror=J,t.setTimeout&&t.setTimeout(0),t.setNoDelay&&t.setNoDelay(),n.length>0&&t.unshift(n),t.on(`close`,X),t.on(`data`,Z),t.on(`end`,Q),t.on(`error`,$),this._readyState=e.OPEN,this.emit(`open`)}emitClose(){if(!this._socket){this._readyState=e.CLOSED,this.emit(`close`,this._closeCode,this._closeMessage);return}this._extensions[b.extensionName]&&this._extensions[b.extensionName].cleanup(),this._receiver.removeAllListeners(),this._readyState=e.CLOSED,this.emit(`close`,this._closeCode,this._closeMessage)}close(t,n){if(this.readyState!==e.CLOSED){if(this.readyState===e.CONNECTING){W(this,this._req,`WebSocket was closed before the connection was established`);return}if(this.readyState===e.CLOSING){this._closeFrameSent&&(this._closeFrameReceived||this._receiver._writableState.errorEmitted)&&this._socket.end();return}this._readyState=e.CLOSING,this._sender.close(t,n,!this._isServer,e=>{e||(this._closeFrameSent=!0,(this._closeFrameReceived||this._receiver._writableState.errorEmitted)&&this._socket.end())}),Y(this)}}pause(){this.readyState===e.CONNECTING||this.readyState===e.CLOSED||(this._paused=!0,this._socket.pause())}ping(t,n,r){if(this.readyState===e.CONNECTING)throw Error(`WebSocket is not open: readyState 0 (CONNECTING)`);if(typeof t==`function`?(r=t,t=n=void 0):typeof n==`function`&&(r=n,n=void 0),typeof t==`number`&&(t=t.toString()),this.readyState!==e.OPEN){G(this,t,r);return}n===void 0&&(n=!this._isServer),this._sender.ping(t||E,n,r)}pong(t,n,r){if(this.readyState===e.CONNECTING)throw Error(`WebSocket is not open: readyState 0 (CONNECTING)`);if(typeof t==`function`?(r=t,t=n=void 0):typeof n==`function`&&(r=n,n=void 0),typeof t==`number`&&(t=t.toString()),this.readyState!==e.OPEN){G(this,t,r);return}n===void 0&&(n=!this._isServer),this._sender.pong(t||E,n,r)}resume(){this.readyState===e.CONNECTING||this.readyState===e.CLOSED||(this._paused=!1,this._receiver._writableState.needDrain||this._socket.resume())}send(t,n,r){if(this.readyState===e.CONNECTING)throw Error(`WebSocket is not open: readyState 0 (CONNECTING)`);if(typeof n==`function`&&(r=n,n={}),typeof t==`number`&&(t=t.toString()),this.readyState!==e.OPEN){G(this,t,r);return}let i={binary:typeof t!=`string`,mask:!this._isServer,compress:!0,fin:!0,...n};this._extensions[b.extensionName]||(i.compress=!1),this._sender.send(t||E,i,r)}terminate(){if(this.readyState!==e.CLOSED){if(this.readyState===e.CONNECTING){W(this,this._req,`WebSocket was closed before the connection was established`);return}this._socket&&(this._readyState=e.CLOSING,this._socket.destroy())}}};Object.defineProperty(V,`CONNECTING`,{enumerable:!0,value:B.indexOf(`CONNECTING`)}),Object.defineProperty(V.prototype,`CONNECTING`,{enumerable:!0,value:B.indexOf(`CONNECTING`)}),Object.defineProperty(V,`OPEN`,{enumerable:!0,value:B.indexOf(`OPEN`)}),Object.defineProperty(V.prototype,`OPEN`,{enumerable:!0,value:B.indexOf(`OPEN`)}),Object.defineProperty(V,`CLOSING`,{enumerable:!0,value:B.indexOf(`CLOSING`)}),Object.defineProperty(V.prototype,`CLOSING`,{enumerable:!0,value:B.indexOf(`CLOSING`)}),Object.defineProperty(V,`CLOSED`,{enumerable:!0,value:B.indexOf(`CLOSED`)}),Object.defineProperty(V.prototype,`CLOSED`,{enumerable:!0,value:B.indexOf(`CLOSED`)}),[`binaryType`,`bufferedAmount`,`extensions`,`isPaused`,`protocol`,`readyState`,`url`].forEach(e=>{Object.defineProperty(V.prototype,e,{enumerable:!0})}),[`open`,`error`,`close`,`message`].forEach(e=>{Object.defineProperty(V.prototype,`on${e}`,{enumerable:!0,get(){for(let t of this.listeners(e))if(t[O])return t[k];return null},set(t){for(let t of this.listeners(e))if(t[O]){this.removeListener(e,t);break}typeof t==`function`&&this.addEventListener(e,t,{[O]:!0})}})}),V.prototype.addEventListener=N,V.prototype.removeEventListener=P,r.exports=V;function H(e,t,n,r){let i={allowSynchronousEvents:!0,autoPong:!0,closeTimeout:T,protocolVersion:z[1],maxPayload:100*1024*1024,skipUTF8Validation:!1,perMessageDeflate:!0,followRedirects:!1,maxRedirects:10,...r,socketPath:void 0,hostname:void 0,protocol:void 0,timeout:void 0,method:`GET`,host:void 0,path:void 0,port:void 0};if(e._autoPong=i.autoPong,e._closeTimeout=i.closeTimeout,!z.includes(i.protocolVersion))throw RangeError(`Unsupported protocol version: ${i.protocolVersion} (supported versions: ${z.join(`, `)})`);let a;if(t instanceof y)a=t;else try{a=new y(t)}catch{throw SyntaxError(`Invalid URL: ${t}`)}a.protocol===`http:`?a.protocol=`ws:`:a.protocol===`https:`&&(a.protocol=`wss:`),e._url=a.href;let o=a.protocol===`wss:`,s=a.protocol===`ws+unix:`,c;if(a.protocol!==`ws:`&&!o&&!s?c=`The URL's protocol must be one of "ws:", "wss:", "http:", "https:", or "ws+unix:"`:s&&!a.pathname?c=`The URL's pathname is empty`:a.hash&&(c=`The URL contains a fragment identifier`),c){let t=SyntaxError(c);if(e._redirects===0)throw t;U(e,t);return}let l=o?443:80,u=h(16).toString(`base64`),p=o?d.request:f.request,m=new Set,_;if(i.createConnection=i.createConnection||(o?ne:te),i.defaultPort=i.defaultPort||l,i.port=a.port||l,i.host=a.hostname.startsWith(`[`)?a.hostname.slice(1,-1):a.hostname,i.headers={...i.headers,"Sec-WebSocket-Version":i.protocolVersion,"Sec-WebSocket-Key":u,Connection:`Upgrade`,Upgrade:`websocket`},i.path=a.pathname+a.search,i.timeout=i.handshakeTimeout,i.perMessageDeflate&&(_=new b({...i.perMessageDeflate,isServer:!1,maxPayload:i.maxPayload}),i.headers[`Sec-WebSocket-Extensions`]=F({[b.extensionName]:_.offer()})),n.length){for(let e of n){if(typeof e!=`string`||!ee.test(e)||m.has(e))throw SyntaxError(`An invalid or duplicated subprotocol was specified`);m.add(e)}i.headers[`Sec-WebSocket-Protocol`]=n.join(`,`)}if(i.origin&&(i.protocolVersion<13?i.headers[`Sec-WebSocket-Origin`]=i.origin:i.headers.Origin=i.origin),(a.username||a.password)&&(i.auth=`${a.username}:${a.password}`),s){let e=i.path.split(`:`);i.socketPath=e[0],i.path=e[1]}let v;if(i.followRedirects){if(e._redirects===0){e._originalIpc=s,e._originalSecure=o,e._originalHostOrSocketPath=s?i.socketPath:a.host;let t=r&&r.headers;if(r={...r,headers:{}},t)for(let[e,n]of Object.entries(t))r.headers[e.toLowerCase()]=n}else if(e.listenerCount(`redirect`)===0){let t=s?e._originalIpc?i.socketPath===e._originalHostOrSocketPath:!1:e._originalIpc?!1:a.host===e._originalHostOrSocketPath;(!t||e._originalSecure&&!o)&&(delete i.headers.authorization,delete i.headers.cookie,t||delete i.headers.host,i.auth=void 0)}i.auth&&!r.headers.authorization&&(r.headers.authorization=`Basic `+Buffer.from(i.auth).toString(`base64`)),v=e._req=p(i),e._redirects&&e.emit(`redirect`,e.url,v)}else v=e._req=p(i);i.timeout&&v.on(`timeout`,()=>{W(e,v,`Opening handshake has timed out`)}),v.on(`error`,t=>{v===null||v[R]||(v=e._req=null,U(e,t))}),v.on(`response`,a=>{let o=a.headers.location,s=a.statusCode;if(o&&i.followRedirects&&s>=300&&s<400){if(++e._redirects>i.maxRedirects){W(e,v,`Maximum redirects exceeded`);return}v.abort();let a;try{a=new y(o,t)}catch{U(e,SyntaxError(`Invalid URL: ${o}`));return}H(e,a,n,r)}else e.emit(`unexpected-response`,v,a)||W(e,v,`Unexpected server response: ${a.statusCode}`)}),v.on(`upgrade`,(t,n,r)=>{if(e.emit(`upgrade`,t),e.readyState!==V.CONNECTING)return;v=e._req=null;let a=t.headers.upgrade;if(a===void 0||a.toLowerCase()!==`websocket`){W(e,n,`Invalid Upgrade header`);return}let o=g(`sha1`).update(u+D).digest(`base64`);if(t.headers[`sec-websocket-accept`]!==o){W(e,n,`Invalid Sec-WebSocket-Accept header`);return}let s=t.headers[`sec-websocket-protocol`],c;if(s===void 0?m.size&&(c=`Server sent no subprotocol`):m.size?m.has(s)||(c=`Server sent an invalid subprotocol`):c=`Server sent a subprotocol but none was requested`,c){W(e,n,c);return}s&&(e._protocol=s);let l=t.headers[`sec-websocket-extensions`];if(l!==void 0){if(!_){W(e,n,`Server sent a Sec-WebSocket-Extensions header but no extension was requested`);return}let t;try{t=I(l)}catch{W(e,n,`Invalid Sec-WebSocket-Extensions header`);return}let r=Object.keys(t);if(r.length!==1||r[0]!==b.extensionName){W(e,n,`Server indicated an extension that was not requested`);return}try{_.accept(t[b.extensionName])}catch{W(e,n,`Invalid Sec-WebSocket-Extensions header`);return}e._extensions[b.extensionName]=_}e.setSocket(n,r,{allowSynchronousEvents:i.allowSynchronousEvents,generateMask:i.generateMask,maxPayload:i.maxPayload,skipUTF8Validation:i.skipUTF8Validation})}),i.finishRequest?i.finishRequest(v,e):v.end()}function U(e,t){e._readyState=V.CLOSING,e._errorEmitted=!0,e.emit(`error`,t),e.emitClose()}function te(e){return e.path=e.socketPath,p.connect(e)}function ne(e){return e.path=void 0,!e.servername&&e.servername!==``&&(e.servername=p.isIP(e.host)?``:e.host),m.connect(e)}function W(e,t,n){e._readyState=V.CLOSING;let r=Error(n);Error.captureStackTrace(r,W),t.setHeader?(t[R]=!0,t.abort(),t.socket&&!t.socket.destroyed&&t.socket.destroy(),process.nextTick(U,e,r)):(t.destroy(r),t.once(`error`,e.emit.bind(e,`error`)),t.once(`close`,e.emitClose.bind(e)))}function G(e,t,n){if(t){let n=C(t)?t.size:L(t).length;e._socket?e._sender._bufferedBytes+=n:e._bufferedAmount+=n}if(n){let t=Error(`WebSocket is not open: readyState ${e.readyState} (${B[e.readyState]})`);process.nextTick(n,t)}}function re(e,t){let n=this[j];n._closeFrameReceived=!0,n._closeMessage=t,n._closeCode=e,n._socket[j]!==void 0&&(n._socket.removeListener(`data`,Z),process.nextTick(q,n._socket),e===1005?n.close():n.close(e,t))}function ie(){let e=this[j];e.isPaused||e._socket.resume()}function ae(e){let t=this[j];t._socket[j]!==void 0&&(t._socket.removeListener(`data`,Z),process.nextTick(q,t._socket),t.close(e[A])),t._errorEmitted||(t._errorEmitted=!0,t.emit(`error`,e))}function K(){this[j].emitClose()}function oe(e,t){this[j].emit(`message`,e,t)}function se(e){let t=this[j];t._autoPong&&t.pong(e,!this._isServer,M),t.emit(`ping`,e)}function ce(e){this[j].emit(`pong`,e)}function q(e){e.resume()}function J(e){let t=this[j];t.readyState!==V.CLOSED&&(t.readyState===V.OPEN&&(t._readyState=V.CLOSING,Y(t)),this._socket.end(),t._errorEmitted||(t._errorEmitted=!0,t.emit(`error`,e)))}function Y(e){e._closeTimer=setTimeout(e._socket.destroy.bind(e._socket),e._closeTimeout)}function X(){let e=this[j];if(this.removeListener(`close`,X),this.removeListener(`data`,Z),this.removeListener(`end`,Q),e._readyState=V.CLOSING,!this._readableState.endEmitted&&!e._closeFrameReceived&&!e._receiver._writableState.errorEmitted&&this._readableState.length!==0){let t=this.read(this._readableState.length);e._receiver.write(t)}e._receiver.end(),this[j]=void 0,clearTimeout(e._closeTimer),e._receiver._writableState.finished||e._receiver._writableState.errorEmitted?e.emitClose():(e._receiver.on(`error`,K),e._receiver.on(`finish`,K))}function Z(e){this[j]._receiver.write(e)||this.pause()}function Q(){let e=this[j];e._readyState=V.CLOSING,e._receiver.end(),this.end()}function $(){let e=this[j];this.removeListener(`error`,$),this.on(`error`,M),e&&(e._readyState=V.CLOSING,this.destroy())}})),d=e(((e,t)=>{u();let{Duplex:n}=require(`stream`);function r(e){e.emit(`close`)}function i(){!this.destroyed&&this._writableState.finished&&this.destroy()}function a(e){this.removeListener(`error`,a),this.destroy(),this.listenerCount(`error`)===0&&this.emit(`error`,e)}function o(e,t){let o=!0,s=new n({...t,autoDestroy:!1,emitClose:!1,objectMode:!1,writableObjectMode:!1});return e.on(`message`,function(t,n){let r=!n&&s._readableState.objectMode?t.toString():t;s.push(r)||e.pause()}),e.once(`error`,function(e){s.destroyed||(o=!1,s.destroy(e))}),e.once(`close`,function(){s.destroyed||s.push(null)}),s._destroy=function(t,n){if(e.readyState===e.CLOSED){n(t),process.nextTick(r,s);return}let i=!1;e.once(`error`,function(e){i=!0,n(e)}),e.once(`close`,function(){i||n(t),process.nextTick(r,s)}),o&&e.terminate()},s._final=function(t){if(e.readyState===e.CONNECTING){e.once(`open`,function(){s._final(t)});return}e._socket!==null&&(e._socket._writableState.finished?(t(),s._readableState.endEmitted&&s.destroy()):(e._socket.once(`finish`,function(){t()}),e.close()))},s._read=function(){e.isPaused&&e.resume()},s._write=function(t,n,r){if(e.readyState===e.CONNECTING){e.once(`open`,function(){s._write(t,n,r)});return}e.send(t,r)},s.on(`end`,i),s.on(`error`,a),s}t.exports=o})),f=e(((e,t)=>{let{tokenChars:n}=a();function r(e){let t=new Set,r=-1,i=-1,a=0;for(;a<e.length;a++){let o=e.charCodeAt(a);if(i===-1&&n[o]===1)r===-1&&(r=a);else if(a!==0&&(o===32||o===9))i===-1&&r!==-1&&(i=a);else if(o===44){if(r===-1)throw SyntaxError(`Unexpected character at index ${a}`);i===-1&&(i=a);let n=e.slice(r,i);if(t.has(n))throw SyntaxError(`The "${n}" subprotocol is duplicated`);t.add(n),r=i=-1}else throw SyntaxError(`Unexpected character at index ${a}`)}if(r===-1||i!==-1)throw SyntaxError(`Unexpected end of input`);let o=e.slice(r,a);if(t.has(o))throw SyntaxError(`The "${o}" subprotocol is duplicated`);return t.add(o),t}t.exports={parse:r}})),p=e(((e,n)=>{let r=require(`events`),a=require(`http`),{Duplex:o}=require(`stream`),{createHash:s}=require(`crypto`),c=l(),d=i(),p=f(),m=u(),{CLOSE_TIMEOUT:h,GUID:g,kWebSocket:_}=t(),v=/^[+/0-9A-Za-z]{22}==$/;n.exports=class extends r{constructor(e,t){if(super(),e={allowSynchronousEvents:!0,autoPong:!0,maxPayload:100*1024*1024,skipUTF8Validation:!1,perMessageDeflate:!1,handleProtocols:null,clientTracking:!0,closeTimeout:h,verifyClient:null,noServer:!1,backlog:null,server:null,host:null,path:null,port:null,WebSocket:m,...e},e.port==null&&!e.server&&!e.noServer||e.port!=null&&(e.server||e.noServer)||e.server&&e.noServer)throw TypeError(`One and only one of the "port", "server", or "noServer" options must be specified`);if(e.port==null?e.server&&(this._server=e.server):(this._server=a.createServer((e,t)=>{let n=a.STATUS_CODES[426];t.writeHead(426,{"Content-Length":n.length,"Content-Type":`text/plain`}),t.end(n)}),this._server.listen(e.port,e.host,e.backlog,t)),this._server){let e=this.emit.bind(this,`connection`);this._removeListeners=y(this._server,{listening:this.emit.bind(this,`listening`),error:this.emit.bind(this,`error`),upgrade:(t,n,r)=>{this.handleUpgrade(t,n,r,e)}})}e.perMessageDeflate===!0&&(e.perMessageDeflate={}),e.clientTracking&&(this.clients=new Set,this._shouldEmitClose=!1),this.options=e,this._state=0}address(){if(this.options.noServer)throw Error(`The server is operating in "noServer" mode`);return this._server?this._server.address():null}close(e){if(this._state===2){e&&this.once(`close`,()=>{e(Error(`The server is not running`))}),process.nextTick(b,this);return}if(e&&this.once(`close`,e),this._state!==1)if(this._state=1,this.options.noServer||this.options.server)this._server&&(this._removeListeners(),this._removeListeners=this._server=null),this.clients&&this.clients.size?this._shouldEmitClose=!0:process.nextTick(b,this);else{let e=this._server;this._removeListeners(),this._removeListeners=this._server=null,e.close(()=>{b(this)})}}shouldHandle(e){if(this.options.path){let t=e.url.indexOf(`?`);if((t===-1?e.url:e.url.slice(0,t))!==this.options.path)return!1}return!0}handleUpgrade(e,t,n,r){t.on(`error`,x);let i=e.headers[`sec-websocket-key`],a=e.headers.upgrade,o=+e.headers[`sec-websocket-version`];if(e.method!==`GET`){C(this,e,t,405,`Invalid HTTP method`);return}if(a===void 0||a.toLowerCase()!==`websocket`){C(this,e,t,400,`Invalid Upgrade header`);return}if(i===void 0||!v.test(i)){C(this,e,t,400,`Missing or invalid Sec-WebSocket-Key header`);return}if(o!==13&&o!==8){C(this,e,t,400,`Missing or invalid Sec-WebSocket-Version header`,{"Sec-WebSocket-Version":`13, 8`});return}if(!this.shouldHandle(e)){S(t,400);return}let s=e.headers[`sec-websocket-protocol`],l=new Set;if(s!==void 0)try{l=p.parse(s)}catch{C(this,e,t,400,`Invalid Sec-WebSocket-Protocol header`);return}let u=e.headers[`sec-websocket-extensions`],f={};if(this.options.perMessageDeflate&&u!==void 0){let n=new d({...this.options.perMessageDeflate,isServer:!0,maxPayload:this.options.maxPayload});try{let e=c.parse(u);e[d.extensionName]&&(n.accept(e[d.extensionName]),f[d.extensionName]=n)}catch{C(this,e,t,400,`Invalid or unacceptable Sec-WebSocket-Extensions header`);return}}if(this.options.verifyClient){let a={origin:e.headers[`${o===8?`sec-websocket-origin`:`origin`}`],secure:!!(e.socket.authorized||e.socket.encrypted),req:e};if(this.options.verifyClient.length===2){this.options.verifyClient(a,(a,o,s,c)=>{if(!a)return S(t,o||401,s,c);this.completeUpgrade(f,i,l,e,t,n,r)});return}if(!this.options.verifyClient(a))return S(t,401)}this.completeUpgrade(f,i,l,e,t,n,r)}completeUpgrade(e,t,n,r,i,a,o){if(!i.readable||!i.writable)return i.destroy();if(i[_])throw Error(`server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration`);if(this._state>0)return S(i,503);let l=[`HTTP/1.1 101 Switching Protocols`,`Upgrade: websocket`,`Connection: Upgrade`,`Sec-WebSocket-Accept: ${s(`sha1`).update(t+g).digest(`base64`)}`],u=new this.options.WebSocket(null,void 0,this.options);if(n.size){let e=this.options.handleProtocols?this.options.handleProtocols(n,r):n.values().next().value;e&&(l.push(`Sec-WebSocket-Protocol: ${e}`),u._protocol=e)}if(e[d.extensionName]){let t=e[d.extensionName].params,n=c.format({[d.extensionName]:[t]});l.push(`Sec-WebSocket-Extensions: ${n}`),u._extensions=e}this.emit(`headers`,l,r),i.write(l.concat(`\r
2
+ `).join(`\r
3
+ `)),i.removeListener(`error`,x),u.setSocket(i,a,{allowSynchronousEvents:this.options.allowSynchronousEvents,maxPayload:this.options.maxPayload,skipUTF8Validation:this.options.skipUTF8Validation}),this.clients&&(this.clients.add(u),u.on(`close`,()=>{this.clients.delete(u),this._shouldEmitClose&&!this.clients.size&&process.nextTick(b,this)})),o(u,r)}};function y(e,t){for(let n of Object.keys(t))e.on(n,t[n]);return function(){for(let n of Object.keys(t))e.removeListener(n,t[n])}}function b(e){e._state=2,e.emit(`close`)}function x(){this.destroy()}function S(e,t,n,r){n||=a.STATUS_CODES[t],r={Connection:`close`,"Content-Type":`text/html`,"Content-Length":Buffer.byteLength(n),...r},e.once(`finish`,e.destroy),e.end(`HTTP/1.1 ${t} ${a.STATUS_CODES[t]}\r\n`+Object.keys(r).map(e=>`${e}: ${r[e]}`).join(`\r
4
+ `)+`\r
5
+ \r
6
+ `+n)}function C(e,t,n,r,i,a){if(e.listenerCount(`wsClientError`)){let r=Error(i);Error.captureStackTrace(r,C),e.emit(`wsClientError`,r,n,t)}else S(n,r,i,a)}})),m=e(((e,t)=>{let n=d(),r=l(),a=i(),c=o(),m=s(),h=f(),g=u(),_=p();g.createWebSocketStream=n,g.extension=r,g.PerMessageDeflate=a,g.Receiver=c,g.Sender=m,g.Server=_,g.subprotocol=h,g.WebSocket=g,g.WebSocketServer=_,t.exports=g}));const h=require(`node:http`),g=require(`node:fs`),_=require(`node:path`),{WebSocketServer:v}=m(),y=process.env.BRAINSTORM_DIR||_.join(require(`node:os`).tmpdir(),`brainstorm`),b=process.env.BRAINSTORM_HOST||`127.0.0.1`,x=process.env.BRAINSTORM_URL_HOST||`localhost`,S=process.env.BRAINSTORM_PORT?Number(process.env.BRAINSTORM_PORT):0;g.mkdirSync(y,{recursive:!0});let C=null;function w(){C&&clearTimeout(C),C=setTimeout(()=>{console.log(`Idle timeout reached, shutting down.`),g.writeFileSync(_.join(y,`.server-stopped`),JSON.stringify({reason:`idle-timeout`,timestamp:Date.now()})),process.exit(0)},18e5)}const T=new Set;function E(e){let t=JSON.stringify(e);for(let e of T)if(e.readyState===1)try{e.send(t)}catch{T.delete(e)}}const D=_.join(y,`.session-state.json`);function O(){try{return JSON.parse(g.readFileSync(D,`utf8`))}catch{return{screens:[],selections:{},currentScreen:null,updatedAt:0}}}function k(e){e.updatedAt=Date.now(),g.writeFileSync(D,JSON.stringify(e,null,2))}function A(){let e=null,t=0;try{for(let n of g.readdirSync(y)){if(!n.endsWith(`.html`))continue;let r=_.join(y,n),i=g.statSync(r);i.mtimeMs>t&&(t=i.mtimeMs,e=r)}}catch{}return e}const j=g.readFileSync(_.join(__dirname,`frame-template.html`),`utf8`),M=g.readFileSync(_.join(__dirname,`helper.js`),`utf8`);function N(e){if(/^\s*(<\!DOCTYPE|<html)/i.test(e)){let t=`<script>\nconst BRAINSTORM_DIR = ${JSON.stringify(y)};\n${M}\n<\/script>`;return e.includes(`</body>`)?e.replace(`</body>`,t+`
7
+ </body>`):e+`
8
+ `+t}return j.replace(`<!-- CONTENT -->`,e).replace(`<!-- HELPER_SCRIPT -->`,M).replace(`__BRAINSTORM_DIR__`,JSON.stringify(y))}let P=null,F=A()?_.basename(A()):null;setInterval(()=>{let e=A(),t=e?_.basename(e):null;t&&t!==F&&(F=t,E({type:`new-file`,name:t}))},500);const I=h.createServer((e,t)=>{if(w(),e.method===`POST`&&e.url===`/events`){let n=``;e.on(`data`,e=>{n+=e}),e.on(`end`,()=>{try{let e=JSON.parse(n);e.timestamp=Date.now(),g.appendFileSync(_.join(y,`.events`),JSON.stringify(e)+`
9
+ `),E({type:`event`,...e});let t=O(),r=P||`unknown`;t.screens.includes(r)||t.screens.push(r),t.currentScreen=r,t.selections[r]||(t.selections[r]=[]);let i=t.selections[r].findIndex(t=>t.choice===e.choice);i>=0?t.selections[r][i]=e:t.selections[r].push(e),t.selections[r]=t.selections[r].filter(e=>e.selected!==!1),k(t)}catch{}t.writeHead(200,{"Content-Type":`application/json`,"Access-Control-Allow-Origin":`*`}),t.end(`{"ok":true}`)});return}if(e.method===`OPTIONS`){t.writeHead(204,{"Access-Control-Allow-Origin":`*`,"Access-Control-Allow-Methods":`GET, POST, OPTIONS`,"Access-Control-Allow-Headers":`Content-Type`}),t.end();return}if(e.url===`/poll`){let e=A(),n=e?_.basename(e):null;t.writeHead(200,{"Content-Type":`application/json`,"Access-Control-Allow-Origin":`*`}),t.end(JSON.stringify({file:n}));return}if(e.url===`/state`){let e=O();t.writeHead(200,{"Content-Type":`application/json`,"Access-Control-Allow-Origin":`*`}),t.end(JSON.stringify(e));return}let n=A();if(!n){let e=N(`<div style="display:flex;align-items:center;justify-content:center;min-height:60vh"><p class="subtitle">Waiting for content...</p></div>`);t.writeHead(200,{"Content-Type":`text/html; charset=utf-8`}),t.end(e);return}let r=_.basename(n);if(P&&P!==r)try{g.unlinkSync(_.join(y,`.events`))}catch{}P=r;let i=O();i.screens.includes(r)||i.screens.push(r),i.currentScreen=r,k(i);let a=N(g.readFileSync(n,`utf8`));t.writeHead(200,{"Content-Type":`text/html; charset=utf-8`}),t.end(a)});function L(e){if(process.argv.includes(`--no-auto-open`))return;let{exec:t}=require(`node:child_process`),n=process.platform;t(n===`win32`?`start "" "${e}"`:n===`darwin`?`open "${e}"`:`xdg-open "${e}"`,t=>{t&&console.log(`Auto-open failed (use browser manually):`,e)})}I.listen(S,b,()=>{let e=I.address(),t=`http://${x}:${e.port}`,n={type:`server-started`,port:e.port,url:t,screen_dir:y};g.writeFileSync(_.join(y,`.server-info`),JSON.stringify(n,null,2));try{g.unlinkSync(_.join(y,`.server-stopped`))}catch{}console.log(`Visual companion running at ${t}`),console.log(`Serving from: ${y}`),w(),new v({server:I}).on(`connection`,e=>{T.add(e),e.on(`close`,()=>T.delete(e)),e.on(`error`,()=>T.delete(e))}),L(t)}),process.on(`SIGINT`,()=>{g.writeFileSync(_.join(y,`.server-stopped`),JSON.stringify({reason:`sigint`,timestamp:Date.now()})),process.exit(0)}),process.on(`SIGTERM`,()=>{g.writeFileSync(_.join(y,`.server-stopped`),JSON.stringify({reason:`sigterm`,timestamp:Date.now()})),process.exit(0)});
@@ -0,0 +1,249 @@
1
+ // Brainstorming Visual Companion — file watcher + HTTP server
2
+ // Watches BRAINSTORM_DIR for HTML files, serves the newest one to the browser.
3
+ // User clicks are recorded to .events file for the agent to read.
4
+
5
+ const http = require('node:http');
6
+ const fs = require('node:fs');
7
+ const path = require('node:path');
8
+ const { WebSocketServer } = require('ws');
9
+
10
+ const DIR = process.env.BRAINSTORM_DIR || path.join(require('node:os').tmpdir(), 'brainstorm');
11
+ const HOST = process.env.BRAINSTORM_HOST || '127.0.0.1';
12
+ const URL_HOST = process.env.BRAINSTORM_URL_HOST || 'localhost';
13
+ const PORT = process.env.BRAINSTORM_PORT ? Number(process.env.BRAINSTORM_PORT) : 0; // 0 = random
14
+
15
+ const IDLE_TIMEOUT_MS = 30 * 60 * 1000; // 30 minutes
16
+ const POLL_INTERVAL_MS = 500;
17
+
18
+ fs.mkdirSync(DIR, { recursive: true });
19
+
20
+ // Track idle timeout
21
+ let idleTimer = null;
22
+ function resetIdleTimer() {
23
+ if (idleTimer) clearTimeout(idleTimer);
24
+ idleTimer = setTimeout(() => {
25
+ console.log('Idle timeout reached, shutting down.');
26
+ fs.writeFileSync(path.join(DIR, '.server-stopped'), JSON.stringify({ reason: 'idle-timeout', timestamp: Date.now() }));
27
+ process.exit(0);
28
+ }, IDLE_TIMEOUT_MS);
29
+ }
30
+
31
+ // --- WebSocket ---
32
+ const wsClients = new Set();
33
+
34
+ function wsBroadcast(obj) {
35
+ const msg = JSON.stringify(obj);
36
+ for (const ws of wsClients) {
37
+ if (ws.readyState === 1) {
38
+ try { ws.send(msg); } catch { wsClients.delete(ws); }
39
+ }
40
+ }
41
+ }
42
+
43
+ // --- Session state ---
44
+ const STATE_FILE = path.join(DIR, '.session-state.json');
45
+
46
+ function readState() {
47
+ try { return JSON.parse(fs.readFileSync(STATE_FILE, 'utf8')); }
48
+ catch { return { screens: [], selections: {}, currentScreen: null, updatedAt: 0 }; }
49
+ }
50
+
51
+ function writeState(state) {
52
+ state.updatedAt = Date.now();
53
+ fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
54
+ }
55
+
56
+ // Find the newest .html file in DIR by mtime
57
+ function getNewestHtml() {
58
+ let newest = null;
59
+ let newestMtime = 0;
60
+ try {
61
+ for (const entry of fs.readdirSync(DIR)) {
62
+ if (!entry.endsWith('.html')) continue;
63
+ const full = path.join(DIR, entry);
64
+ const stat = fs.statSync(full);
65
+ if (stat.mtimeMs > newestMtime) {
66
+ newestMtime = stat.mtimeMs;
67
+ newest = full;
68
+ }
69
+ }
70
+ } catch { /* ignore read errors */ }
71
+ return newest;
72
+ }
73
+
74
+ // Read frame template
75
+ const FRAME_TEMPLATE = fs.readFileSync(path.join(__dirname, 'frame-template.html'), 'utf8');
76
+ const HELPER_SCRIPT = fs.readFileSync(path.join(__dirname, 'helper.js'), 'utf8');
77
+
78
+ // Build the full page from content
79
+ function buildPage(content) {
80
+ const isFullDoc = /^\s*(<\!DOCTYPE|<html)/i.test(content);
81
+ if (isFullDoc) {
82
+ // Inject helper script before </body> or at end
83
+ const helperTag = `<script>\nconst BRAINSTORM_DIR = ${JSON.stringify(DIR)};\n${HELPER_SCRIPT}\n</script>`;
84
+ if (content.includes('</body>')) {
85
+ return content.replace('</body>', helperTag + '\n</body>');
86
+ }
87
+ return content + '\n' + helperTag;
88
+ }
89
+ // Fragment mode — wrap in frame template
90
+ return FRAME_TEMPLATE
91
+ .replace('<!-- CONTENT -->', content)
92
+ .replace('<!-- HELPER_SCRIPT -->', HELPER_SCRIPT)
93
+ .replace('__BRAINSTORM_DIR__', JSON.stringify(DIR));
94
+ }
95
+
96
+ // Track which file we last served so we know when to clear .events
97
+ let lastServedFile = null;
98
+
99
+ // Watch for new HTML files -> broadcast to WebSocket clients
100
+ let lastKnownNewest = getNewestHtml() ? path.basename(getNewestHtml()) : null;
101
+ setInterval(() => {
102
+ const newest = getNewestHtml();
103
+ const name = newest ? path.basename(newest) : null;
104
+ if (name && name !== lastKnownNewest) {
105
+ lastKnownNewest = name;
106
+ wsBroadcast({ type: 'new-file', name });
107
+ }
108
+ }, POLL_INTERVAL_MS);
109
+
110
+ const server = http.createServer((req, res) => {
111
+ resetIdleTimer();
112
+
113
+ // POST /events — browser sends click events
114
+ if (req.method === 'POST' && req.url === '/events') {
115
+ let body = '';
116
+ req.on('data', (chunk) => { body += chunk; });
117
+ req.on('end', () => {
118
+ try {
119
+ const event = JSON.parse(body);
120
+ event.timestamp = Date.now();
121
+ fs.appendFileSync(path.join(DIR, '.events'), JSON.stringify(event) + '\n');
122
+ wsBroadcast({ type: 'event', ...event });
123
+
124
+ const state = readState();
125
+ const screen = lastServedFile || 'unknown';
126
+ if (!state.screens.includes(screen)) state.screens.push(screen);
127
+ state.currentScreen = screen;
128
+ if (!state.selections[screen]) state.selections[screen] = [];
129
+ const existingIdx = state.selections[screen].findIndex((s) => s.choice === event.choice);
130
+ if (existingIdx >= 0) {
131
+ state.selections[screen][existingIdx] = event;
132
+ } else {
133
+ state.selections[screen].push(event);
134
+ }
135
+ state.selections[screen] = state.selections[screen].filter((s) => s.selected !== false);
136
+ writeState(state);
137
+ } catch { /* ignore malformed */ }
138
+ res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
139
+ res.end('{"ok":true}');
140
+ });
141
+ return;
142
+ }
143
+
144
+ // OPTIONS for CORS preflight
145
+ if (req.method === 'OPTIONS') {
146
+ res.writeHead(204, {
147
+ 'Access-Control-Allow-Origin': '*',
148
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
149
+ 'Access-Control-Allow-Headers': 'Content-Type',
150
+ });
151
+ res.end();
152
+ return;
153
+ }
154
+
155
+ // GET /poll — long-poll for file changes (browser checks for new content)
156
+ if (req.url === '/poll') {
157
+ const newest = getNewestHtml();
158
+ const newestName = newest ? path.basename(newest) : null;
159
+ res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
160
+ res.end(JSON.stringify({ file: newestName }));
161
+ return;
162
+ }
163
+
164
+ // GET /state — return session state
165
+ if (req.url === '/state') {
166
+ const state = readState();
167
+ res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
168
+ res.end(JSON.stringify(state));
169
+ return;
170
+ }
171
+
172
+ // GET / — serve the newest HTML file
173
+ const htmlFile = getNewestHtml();
174
+ if (!htmlFile) {
175
+ const waiting = buildPage('<div style="display:flex;align-items:center;justify-content:center;min-height:60vh"><p class="subtitle">Waiting for content...</p></div>');
176
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
177
+ res.end(waiting);
178
+ return;
179
+ }
180
+
181
+ // Clear .events when we serve a new file
182
+ const currentFile = path.basename(htmlFile);
183
+ if (lastServedFile && lastServedFile !== currentFile) {
184
+ try { fs.unlinkSync(path.join(DIR, '.events')); } catch { /* ok */ }
185
+ }
186
+ lastServedFile = currentFile;
187
+
188
+ const state = readState();
189
+ if (!state.screens.includes(currentFile)) state.screens.push(currentFile);
190
+ state.currentScreen = currentFile;
191
+ writeState(state);
192
+
193
+ const content = fs.readFileSync(htmlFile, 'utf8');
194
+ const page = buildPage(content);
195
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
196
+ res.end(page);
197
+ });
198
+
199
+ // --- Auto-open browser ---
200
+ function autoOpen(url) {
201
+ if (process.argv.includes('--no-auto-open')) return;
202
+ const { exec } = require('node:child_process');
203
+ const platform = process.platform;
204
+ const cmd = platform === 'win32' ? `start "" "${url}"`
205
+ : platform === 'darwin' ? `open "${url}"`
206
+ : `xdg-open "${url}"`;
207
+ exec(cmd, (err) => {
208
+ if (err) console.log('Auto-open failed (use browser manually):', url);
209
+ });
210
+ }
211
+
212
+ server.listen(PORT, HOST, () => {
213
+ const addr = server.address();
214
+ const url = `http://${URL_HOST}:${addr.port}`;
215
+ const info = {
216
+ type: 'server-started',
217
+ port: addr.port,
218
+ url,
219
+ screen_dir: DIR,
220
+ };
221
+
222
+ // Write .server-info for agent to read
223
+ fs.writeFileSync(path.join(DIR, '.server-info'), JSON.stringify(info, null, 2));
224
+ // Remove stale stop marker
225
+ try { fs.unlinkSync(path.join(DIR, '.server-stopped')); } catch { /* ok */ }
226
+
227
+ console.log(`Visual companion running at ${url}`);
228
+ console.log(`Serving from: ${DIR}`);
229
+ resetIdleTimer();
230
+
231
+ const wss = new WebSocketServer({ server });
232
+ wss.on('connection', (ws) => {
233
+ wsClients.add(ws);
234
+ ws.on('close', () => wsClients.delete(ws));
235
+ ws.on('error', () => wsClients.delete(ws));
236
+ });
237
+
238
+ autoOpen(url);
239
+ });
240
+
241
+ // Graceful shutdown
242
+ process.on('SIGINT', () => {
243
+ fs.writeFileSync(path.join(DIR, '.server-stopped'), JSON.stringify({ reason: 'sigint', timestamp: Date.now() }));
244
+ process.exit(0);
245
+ });
246
+ process.on('SIGTERM', () => {
247
+ fs.writeFileSync(path.join(DIR, '.server-stopped'), JSON.stringify({ reason: 'sigterm', timestamp: Date.now() }));
248
+ process.exit(0);
249
+ });
@@ -0,0 +1,49 @@
1
+ # Spec Document Reviewer Prompt Template
2
+
3
+ Use this template when dispatching a spec document reviewer subagent.
4
+
5
+ **Purpose:** Verify the spec is complete, consistent, and ready for implementation planning.
6
+
7
+ **Dispatch after:** Spec document is written to docs/specs/
8
+
9
+ ```
10
+ Task tool (general-purpose):
11
+ description: "Review spec document"
12
+ prompt: |
13
+ You are a spec document reviewer. Verify this spec is complete and ready for planning.
14
+
15
+ **Spec to review:** [SPEC_FILE_PATH]
16
+
17
+ ## What to Check
18
+
19
+ | Category | What to Look For |
20
+ |----------|------------------|
21
+ | Completeness | TODOs, placeholders, "TBD", incomplete sections |
22
+ | Consistency | Internal contradictions, conflicting requirements |
23
+ | Clarity | Requirements ambiguous enough to cause someone to build the wrong thing |
24
+ | Scope | Focused enough for a single plan — not covering multiple independent subsystems |
25
+ | YAGNI | Unrequested features, over-engineering |
26
+
27
+ ## Calibration
28
+
29
+ **Only flag issues that would cause real problems during implementation planning.**
30
+ A missing section, a contradiction, or a requirement so ambiguous it could be
31
+ interpreted two different ways — those are issues. Minor wording improvements,
32
+ stylistic preferences, and "sections less detailed than others" are not.
33
+
34
+ Approve unless there are serious gaps that would lead to a flawed plan.
35
+
36
+ ## Output Format
37
+
38
+ ## Spec Review
39
+
40
+ **Status:** Approved | Issues Found
41
+
42
+ **Issues (if any):**
43
+ - [Section X]: [specific issue] - [why it matters for planning]
44
+
45
+ **Recommendations (advisory, do not block approval):**
46
+ - [suggestions for improvement]
47
+ ```
48
+
49
+ **Reviewer returns:** Status, Issues (if any), Recommendations