@vpxa/kb 0.1.13 → 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.
- package/README.md +8 -2
- package/package.json +10 -7
- package/packages/analyzers/dist/blast-radius-analyzer.d.ts +17 -20
- package/packages/analyzers/dist/blast-radius-analyzer.js +6 -12
- package/packages/analyzers/dist/dependency-analyzer.d.ts +31 -27
- package/packages/analyzers/dist/dependency-analyzer.js +7 -9
- package/packages/analyzers/dist/diagram-generator.d.ts +12 -8
- package/packages/analyzers/dist/diagram-generator.js +3 -4
- package/packages/analyzers/dist/entry-point-analyzer.d.ts +39 -35
- package/packages/analyzers/dist/entry-point-analyzer.js +5 -6
- package/packages/analyzers/dist/index.d.ts +12 -14
- package/packages/analyzers/dist/index.js +1 -1
- package/packages/analyzers/dist/knowledge-producer.d.ts +29 -25
- package/packages/analyzers/dist/knowledge-producer.js +16 -15
- package/packages/analyzers/dist/pattern-analyzer.d.ts +14 -10
- package/packages/analyzers/dist/pattern-analyzer.js +3 -5
- package/packages/analyzers/dist/regex-call-graph.d.ts +6 -12
- package/packages/analyzers/dist/regex-call-graph.js +2 -1
- package/packages/analyzers/dist/structure-analyzer.d.ts +13 -9
- package/packages/analyzers/dist/structure-analyzer.js +3 -4
- package/packages/analyzers/dist/symbol-analyzer.d.ts +12 -8
- package/packages/analyzers/dist/symbol-analyzer.js +8 -13
- package/packages/analyzers/dist/ts-call-graph.d.ts +16 -13
- package/packages/analyzers/dist/ts-call-graph.js +2 -1
- package/packages/analyzers/dist/types.d.ts +82 -79
- package/packages/analyzers/dist/types.js +1 -0
- package/packages/chunker/dist/call-graph-extractor.d.ts +13 -10
- package/packages/chunker/dist/call-graph-extractor.js +2 -1
- package/packages/chunker/dist/chunker-factory.d.ts +6 -2
- package/packages/chunker/dist/chunker-factory.js +2 -1
- package/packages/chunker/dist/chunker.interface.d.ts +8 -4
- package/packages/chunker/dist/chunker.interface.js +1 -0
- package/packages/chunker/dist/code-chunker.d.ts +16 -12
- package/packages/chunker/dist/code-chunker.js +12 -14
- package/packages/chunker/dist/generic-chunker.d.ts +14 -10
- package/packages/chunker/dist/generic-chunker.js +6 -5
- package/packages/chunker/dist/index.d.ts +8 -8
- package/packages/chunker/dist/index.js +1 -1
- package/packages/chunker/dist/markdown-chunker.d.ts +16 -12
- package/packages/chunker/dist/markdown-chunker.js +4 -10
- package/packages/chunker/dist/treesitter-chunker.d.ts +28 -31
- package/packages/chunker/dist/treesitter-chunker.js +7 -8
- package/packages/cli/dist/commands/analyze.d.ts +6 -2
- package/packages/cli/dist/commands/analyze.js +3 -3
- package/packages/cli/dist/commands/context-cmds.d.ts +6 -2
- package/packages/cli/dist/commands/context-cmds.js +2 -1
- package/packages/cli/dist/commands/environment.d.ts +6 -2
- package/packages/cli/dist/commands/environment.js +2 -2
- package/packages/cli/dist/commands/execution.d.ts +6 -2
- package/packages/cli/dist/commands/execution.js +2 -1
- package/packages/cli/dist/commands/graph.d.ts +6 -2
- package/packages/cli/dist/commands/graph.js +6 -6
- package/packages/cli/dist/commands/init/adapters.d.ts +27 -0
- package/packages/cli/dist/commands/init/adapters.js +2 -0
- package/packages/cli/dist/commands/init/config.d.ts +11 -0
- package/packages/cli/dist/commands/init/config.js +4 -0
- package/packages/cli/dist/commands/init/curated.d.ts +8 -0
- package/packages/cli/dist/commands/init/curated.js +2 -0
- package/packages/cli/dist/commands/init/index.d.ts +23 -0
- package/packages/cli/dist/commands/init/index.js +3 -0
- package/packages/cli/dist/commands/init/scaffold.d.ts +24 -0
- package/packages/cli/dist/commands/init/scaffold.js +2 -0
- package/packages/cli/dist/commands/init/templates.d.ts +10 -0
- package/packages/cli/dist/commands/init/templates.js +302 -0
- package/packages/cli/dist/commands/init.d.ts +8 -3
- package/packages/cli/dist/commands/init.js +120 -123
- package/packages/cli/dist/commands/knowledge.d.ts +6 -2
- package/packages/cli/dist/commands/knowledge.js +2 -1
- package/packages/cli/dist/commands/search.d.ts +6 -2
- package/packages/cli/dist/commands/search.js +2 -8
- package/packages/cli/dist/commands/system.d.ts +6 -2
- package/packages/cli/dist/commands/system.js +5 -7
- package/packages/cli/dist/commands/workspace.d.ts +6 -2
- package/packages/cli/dist/commands/workspace.js +2 -2
- package/packages/cli/dist/context.d.ts +7 -4
- package/packages/cli/dist/context.js +2 -1
- package/packages/cli/dist/helpers.d.ts +51 -47
- package/packages/cli/dist/helpers.js +6 -5
- package/packages/cli/dist/index.d.ts +4 -1
- package/packages/cli/dist/index.js +3 -2
- package/packages/cli/dist/kb-init.d.ts +48 -50
- package/packages/cli/dist/kb-init.js +2 -1
- package/packages/cli/dist/types.d.ts +8 -5
- package/packages/cli/dist/types.js +1 -0
- package/packages/core/dist/constants.d.ts +36 -33
- package/packages/core/dist/constants.js +2 -1
- package/packages/core/dist/content-detector.d.ts +8 -7
- package/packages/core/dist/content-detector.js +2 -1
- package/packages/core/dist/errors.d.ts +15 -12
- package/packages/core/dist/errors.js +2 -1
- package/packages/core/dist/index.d.ts +6 -6
- package/packages/core/dist/index.js +1 -1
- package/packages/core/dist/logger.d.ts +16 -7
- package/packages/core/dist/logger.js +2 -1
- package/packages/core/dist/types.d.ts +107 -91
- package/packages/core/dist/types.js +2 -0
- package/packages/embeddings/dist/embedder.interface.d.ts +22 -19
- package/packages/embeddings/dist/embedder.interface.js +1 -0
- package/packages/embeddings/dist/index.d.ts +3 -3
- package/packages/embeddings/dist/index.js +1 -1
- package/packages/embeddings/dist/onnx-embedder.d.ts +21 -22
- package/packages/embeddings/dist/onnx-embedder.js +2 -1
- package/packages/enterprise-bridge/dist/cache.d.ts +29 -0
- package/packages/enterprise-bridge/dist/cache.js +2 -0
- package/packages/enterprise-bridge/dist/er-client.d.ts +38 -0
- package/packages/enterprise-bridge/dist/er-client.js +2 -0
- package/packages/enterprise-bridge/dist/evolution-collector.d.ts +63 -0
- package/packages/enterprise-bridge/dist/evolution-collector.js +2 -0
- package/packages/enterprise-bridge/dist/index.d.ts +8 -0
- package/packages/enterprise-bridge/dist/index.js +1 -0
- package/packages/enterprise-bridge/dist/policy-store.d.ts +46 -0
- package/packages/enterprise-bridge/dist/policy-store.js +2 -0
- package/packages/enterprise-bridge/dist/push-adapter.d.ts +24 -0
- package/packages/enterprise-bridge/dist/push-adapter.js +2 -0
- package/packages/enterprise-bridge/dist/result-merger.d.ts +15 -0
- package/packages/enterprise-bridge/dist/result-merger.js +2 -0
- package/packages/enterprise-bridge/dist/types.d.ts +82 -0
- package/packages/enterprise-bridge/dist/types.js +2 -0
- package/packages/indexer/dist/file-hasher.d.ts +5 -2
- package/packages/indexer/dist/file-hasher.js +2 -1
- package/packages/indexer/dist/filesystem-crawler.d.ts +23 -20
- package/packages/indexer/dist/filesystem-crawler.js +2 -1
- package/packages/indexer/dist/graph-extractor.d.ts +9 -12
- package/packages/indexer/dist/graph-extractor.js +2 -1
- package/packages/indexer/dist/incremental-indexer.d.ts +49 -43
- package/packages/indexer/dist/incremental-indexer.js +2 -1
- package/packages/indexer/dist/index.d.ts +5 -5
- package/packages/indexer/dist/index.js +1 -1
- package/packages/server/dist/api.d.ts +3 -8
- package/packages/server/dist/api.js +1 -1
- package/packages/server/dist/config.d.ts +6 -2
- package/packages/server/dist/config.js +2 -1
- package/packages/server/dist/curated-manager.d.ts +79 -76
- package/packages/server/dist/curated-manager.js +6 -10
- package/packages/server/dist/index.d.ts +1 -2
- package/packages/server/dist/index.js +2 -1
- package/packages/server/dist/replay-interceptor.d.ts +6 -6
- package/packages/server/dist/replay-interceptor.js +2 -1
- package/packages/server/dist/resources/resources.d.ts +7 -3
- package/packages/server/dist/resources/resources.js +3 -2
- package/packages/server/dist/server.d.ts +34 -24
- package/packages/server/dist/server.js +2 -1
- package/packages/server/dist/tools/analyze.tools.d.ts +14 -10
- package/packages/server/dist/tools/analyze.tools.js +2 -3
- package/packages/server/dist/tools/audit.tool.d.ts +8 -4
- package/packages/server/dist/tools/audit.tool.js +2 -4
- package/packages/server/dist/tools/bridge.tools.d.ts +35 -0
- package/packages/server/dist/tools/bridge.tools.js +16 -0
- package/packages/server/dist/tools/evolution.tools.d.ts +8 -0
- package/packages/server/dist/tools/evolution.tools.js +6 -0
- package/packages/server/dist/tools/forge.tools.d.ts +13 -11
- package/packages/server/dist/tools/forge.tools.js +11 -13
- package/packages/server/dist/tools/forget.tool.d.ts +7 -3
- package/packages/server/dist/tools/forget.tool.js +2 -7
- package/packages/server/dist/tools/graph.tool.d.ts +7 -3
- package/packages/server/dist/tools/graph.tool.js +5 -5
- package/packages/server/dist/tools/list.tool.d.ts +7 -3
- package/packages/server/dist/tools/list.tool.js +3 -8
- package/packages/server/dist/tools/lookup.tool.d.ts +7 -3
- package/packages/server/dist/tools/lookup.tool.js +3 -9
- package/packages/server/dist/tools/onboard.tool.d.ts +8 -4
- package/packages/server/dist/tools/onboard.tool.js +3 -2
- package/packages/server/dist/tools/policy.tools.d.ts +8 -0
- package/packages/server/dist/tools/policy.tools.js +3 -0
- package/packages/server/dist/tools/produce.tool.d.ts +6 -2
- package/packages/server/dist/tools/produce.tool.js +3 -2
- package/packages/server/dist/tools/read.tool.d.ts +7 -3
- package/packages/server/dist/tools/read.tool.js +3 -6
- package/packages/server/dist/tools/reindex.tool.d.ts +10 -6
- package/packages/server/dist/tools/reindex.tool.js +3 -2
- package/packages/server/dist/tools/remember.tool.d.ts +8 -3
- package/packages/server/dist/tools/remember.tool.js +4 -5
- package/packages/server/dist/tools/replay.tool.d.ts +6 -2
- package/packages/server/dist/tools/replay.tool.js +3 -6
- package/packages/server/dist/tools/search.tool.d.ts +10 -4
- package/packages/server/dist/tools/search.tool.js +7 -22
- package/packages/server/dist/tools/status.tool.d.ts +7 -3
- package/packages/server/dist/tools/status.tool.js +3 -3
- package/packages/server/dist/tools/toolkit.tools.d.ts +36 -34
- package/packages/server/dist/tools/toolkit.tools.js +20 -24
- package/packages/server/dist/tools/update.tool.d.ts +7 -3
- package/packages/server/dist/tools/update.tool.js +2 -6
- package/packages/server/dist/tools/utility.tools.d.ts +15 -14
- package/packages/server/dist/tools/utility.tools.js +11 -23
- package/packages/server/dist/version-check.d.ts +5 -1
- package/packages/server/dist/version-check.js +2 -1
- package/packages/store/dist/graph-store.interface.d.ts +89 -86
- package/packages/store/dist/graph-store.interface.js +1 -0
- package/packages/store/dist/index.d.ts +6 -6
- package/packages/store/dist/index.js +1 -1
- package/packages/store/dist/lance-store.d.ts +37 -30
- package/packages/store/dist/lance-store.js +2 -1
- package/packages/store/dist/sqlite-graph-store.d.ts +43 -46
- package/packages/store/dist/sqlite-graph-store.js +14 -13
- package/packages/store/dist/store-factory.d.ts +11 -7
- package/packages/store/dist/store-factory.js +2 -1
- package/packages/store/dist/store.interface.d.ts +47 -46
- package/packages/store/dist/store.interface.js +1 -0
- package/packages/tools/dist/audit.d.ts +61 -61
- package/packages/tools/dist/audit.js +5 -5
- package/packages/tools/dist/batch.d.ts +20 -17
- package/packages/tools/dist/batch.js +2 -1
- package/packages/tools/dist/changelog.d.ts +29 -26
- package/packages/tools/dist/changelog.js +3 -2
- package/packages/tools/dist/check.d.ts +42 -38
- package/packages/tools/dist/check.js +3 -2
- package/packages/tools/dist/checkpoint.d.ts +17 -14
- package/packages/tools/dist/checkpoint.js +2 -2
- package/packages/tools/dist/codemod.d.ts +35 -32
- package/packages/tools/dist/codemod.js +3 -2
- package/packages/tools/dist/compact.d.ts +34 -37
- package/packages/tools/dist/compact.js +3 -2
- package/packages/tools/dist/data-transform.d.ts +10 -7
- package/packages/tools/dist/data-transform.js +2 -1
- package/packages/tools/dist/dead-symbols.d.ts +29 -25
- package/packages/tools/dist/dead-symbols.js +3 -2
- package/packages/tools/dist/delegate.d.ts +26 -23
- package/packages/tools/dist/delegate.js +2 -5
- package/packages/tools/dist/diff-parse.d.ts +24 -21
- package/packages/tools/dist/diff-parse.js +4 -3
- package/packages/tools/dist/digest.d.ts +43 -45
- package/packages/tools/dist/digest.js +5 -5
- package/packages/tools/dist/encode.d.ts +11 -8
- package/packages/tools/dist/encode.js +2 -1
- package/packages/tools/dist/env-info.d.ts +25 -22
- package/packages/tools/dist/env-info.js +2 -1
- package/packages/tools/dist/eval.d.ts +13 -10
- package/packages/tools/dist/eval.js +3 -3
- package/packages/tools/dist/evidence-map.d.ts +64 -61
- package/packages/tools/dist/evidence-map.js +3 -3
- package/packages/tools/dist/file-cache.d.ts +42 -0
- package/packages/tools/dist/file-cache.js +4 -0
- package/packages/tools/dist/file-summary.d.ts +34 -29
- package/packages/tools/dist/file-summary.js +3 -2
- package/packages/tools/dist/file-walk.d.ts +6 -3
- package/packages/tools/dist/file-walk.js +2 -1
- package/packages/tools/dist/find-examples.d.ts +26 -21
- package/packages/tools/dist/find-examples.js +4 -3
- package/packages/tools/dist/find.d.ts +39 -40
- package/packages/tools/dist/find.js +2 -1
- package/packages/tools/dist/forge-classify.d.ts +35 -38
- package/packages/tools/dist/forge-classify.js +3 -2
- package/packages/tools/dist/forge-ground.d.ts +58 -60
- package/packages/tools/dist/forge-ground.js +2 -1
- package/packages/tools/dist/git-context.d.ts +22 -19
- package/packages/tools/dist/git-context.js +4 -3
- package/packages/tools/dist/graph-query.d.ts +75 -78
- package/packages/tools/dist/graph-query.js +2 -1
- package/packages/tools/dist/guide.d.ts +14 -11
- package/packages/tools/dist/guide.js +2 -1
- package/packages/tools/dist/health.d.ts +13 -10
- package/packages/tools/dist/health.js +3 -2
- package/packages/tools/dist/http-request.d.ts +20 -17
- package/packages/tools/dist/http-request.js +2 -1
- package/packages/tools/dist/index.d.ts +54 -53
- package/packages/tools/dist/index.js +1 -1
- package/packages/tools/dist/lane.d.ts +28 -25
- package/packages/tools/dist/lane.js +7 -7
- package/packages/tools/dist/measure.d.ts +32 -29
- package/packages/tools/dist/measure.js +3 -2
- package/packages/tools/dist/onboard.d.ts +29 -26
- package/packages/tools/dist/onboard.js +18 -41
- package/packages/tools/dist/parse-output.d.ts +48 -45
- package/packages/tools/dist/parse-output.js +3 -2
- package/packages/tools/dist/path-resolver.d.ts +4 -1
- package/packages/tools/dist/path-resolver.js +2 -1
- package/packages/tools/dist/process-manager.d.ts +18 -15
- package/packages/tools/dist/process-manager.js +2 -1
- package/packages/tools/dist/queue.d.ts +28 -25
- package/packages/tools/dist/queue.js +2 -2
- package/packages/tools/dist/regex-test.d.ts +26 -23
- package/packages/tools/dist/regex-test.js +2 -1
- package/packages/tools/dist/rename.d.ts +28 -25
- package/packages/tools/dist/rename.js +3 -2
- package/packages/tools/dist/replay.d.ts +32 -29
- package/packages/tools/dist/replay.js +5 -6
- package/packages/tools/dist/response-envelope.d.ts +32 -29
- package/packages/tools/dist/response-envelope.js +2 -1
- package/packages/tools/dist/schema-validate.d.ts +15 -12
- package/packages/tools/dist/schema-validate.js +2 -1
- package/packages/tools/dist/scope-map.d.ts +45 -47
- package/packages/tools/dist/scope-map.js +2 -1
- package/packages/tools/dist/snippet.d.ts +26 -24
- package/packages/tools/dist/snippet.js +2 -1
- package/packages/tools/dist/stash.d.ts +13 -10
- package/packages/tools/dist/stash.js +2 -2
- package/packages/tools/dist/stratum-card.d.ts +27 -27
- package/packages/tools/dist/stratum-card.js +4 -5
- package/packages/tools/dist/symbol.d.ts +29 -25
- package/packages/tools/dist/symbol.js +4 -3
- package/packages/tools/dist/test-run.d.ts +19 -15
- package/packages/tools/dist/test-run.js +3 -2
- package/packages/tools/dist/text-utils.d.ts +6 -3
- package/packages/tools/dist/text-utils.js +3 -2
- package/packages/tools/dist/time-utils.d.ts +15 -12
- package/packages/tools/dist/time-utils.js +2 -1
- package/packages/tools/dist/trace.d.ts +24 -20
- package/packages/tools/dist/trace.js +3 -2
- package/packages/tools/dist/truncation.d.ts +6 -3
- package/packages/tools/dist/truncation.js +8 -14
- package/packages/tools/dist/watch.d.ts +28 -25
- package/packages/tools/dist/watch.js +2 -1
- package/packages/tools/dist/web-fetch.d.ts +35 -32
- package/packages/tools/dist/web-fetch.js +7 -12
- package/packages/tools/dist/web-search.d.ts +16 -13
- package/packages/tools/dist/web-search.js +2 -1
- package/packages/tools/dist/workset.d.ts +19 -16
- package/packages/tools/dist/workset.js +2 -2
- package/packages/tui/dist/App-BAlmxCCw.js +3 -0
- package/packages/tui/dist/App.d.ts +11 -5
- package/packages/tui/dist/App.js +1 -450
- package/packages/tui/dist/CuratedPanel-sYdZAICX.js +3 -0
- package/packages/tui/dist/LogPanel-DVB8Sv46.js +4 -0
- package/packages/tui/dist/SearchPanel-DREo6zgt.js +3 -0
- package/packages/tui/dist/StatusPanel-2ex8fLOO.js +3 -0
- package/packages/tui/dist/chunk-D6axbAb-.js +2 -0
- package/packages/tui/dist/devtools-DUyj952l.js +8 -0
- package/packages/tui/dist/embedder.interface-D4ew0HPW.d.ts +29 -0
- package/packages/tui/dist/index-B9VpfVPP.d.ts +14 -0
- package/packages/tui/dist/index.d.ts +3 -19
- package/packages/tui/dist/index.js +2 -476
- package/packages/tui/dist/jsx-runtime-Cof-kwFn.js +317 -0
- package/packages/tui/dist/panels/CuratedPanel.d.ts +11 -5
- package/packages/tui/dist/panels/CuratedPanel.js +1 -371
- package/packages/tui/dist/panels/LogPanel.d.ts +7 -2
- package/packages/tui/dist/panels/LogPanel.js +1 -449
- package/packages/tui/dist/panels/SearchPanel.d.ts +14 -7
- package/packages/tui/dist/panels/SearchPanel.js +1 -372
- package/packages/tui/dist/panels/StatusPanel.d.ts +11 -5
- package/packages/tui/dist/panels/StatusPanel.js +1 -371
- package/packages/tui/dist/store.interface-CnY6SPOH.d.ts +151 -0
- package/scaffold/adapters/claude-code.mjs +20 -0
- package/scaffold/adapters/copilot.mjs +320 -0
- package/scaffold/copilot/agents/Architect-Reviewer-Alpha.agent.md +14 -0
- package/scaffold/copilot/agents/Architect-Reviewer-Beta.agent.md +14 -0
- package/scaffold/copilot/agents/Code-Reviewer-Alpha.agent.md +12 -0
- package/scaffold/copilot/agents/Code-Reviewer-Beta.agent.md +12 -0
- package/scaffold/copilot/agents/Debugger.agent.md +31 -0
- package/scaffold/copilot/agents/Documenter.agent.md +35 -0
- package/scaffold/copilot/agents/Explorer.agent.md +50 -0
- package/scaffold/copilot/agents/Frontend.agent.md +29 -0
- package/scaffold/copilot/agents/Implementer.agent.md +31 -0
- package/scaffold/copilot/agents/Orchestrator.agent.md +96 -0
- package/scaffold/copilot/agents/Planner.agent.md +45 -0
- package/scaffold/copilot/agents/README.md +57 -0
- package/scaffold/copilot/agents/Refactor.agent.md +30 -0
- package/scaffold/copilot/agents/Researcher-Alpha.agent.md +12 -0
- package/scaffold/copilot/agents/Researcher-Beta.agent.md +12 -0
- package/scaffold/copilot/agents/Researcher-Delta.agent.md +12 -0
- package/scaffold/copilot/agents/Researcher-Gamma.agent.md +12 -0
- package/scaffold/copilot/agents/Security.agent.md +42 -0
- package/scaffold/copilot/agents/_shared/adr-protocol.md +91 -0
- package/scaffold/copilot/agents/_shared/architect-reviewer-base.md +50 -0
- package/scaffold/copilot/agents/_shared/code-agent-base.md +70 -0
- package/scaffold/copilot/agents/_shared/code-reviewer-base.md +54 -0
- package/scaffold/copilot/agents/_shared/decision-protocol.md +27 -0
- package/scaffold/copilot/agents/_shared/forge-protocol.md +46 -0
- package/scaffold/copilot/agents/_shared/researcher-base.md +61 -0
- package/scaffold/copilot/agents/templates/adr-template.md +27 -0
- package/scaffold/copilot/agents/templates/execution-state.md +25 -0
- package/scaffold/copilot/prompts/ask.prompt.md +20 -0
- package/scaffold/copilot/prompts/debug.prompt.md +25 -0
- package/scaffold/copilot/prompts/design.prompt.md +22 -0
- package/scaffold/copilot/prompts/implement.prompt.md +26 -0
- package/scaffold/copilot/prompts/plan.prompt.md +24 -0
- package/scaffold/copilot/prompts/review.prompt.md +31 -0
- package/scaffold/definitions/agents.mjs +165 -0
- package/scaffold/definitions/bodies.mjs +292 -0
- package/scaffold/definitions/hooks.mjs +43 -0
- package/scaffold/definitions/models.mjs +56 -0
- package/scaffold/definitions/plugins.mjs +24 -0
- package/scaffold/definitions/prompts.mjs +145 -0
- package/scaffold/definitions/protocols.mjs +322 -0
- package/scaffold/definitions/tools.mjs +176 -0
- package/scaffold/generate.mjs +74 -0
- package/skills/brainstorming/SKILL.md +259 -0
- package/skills/brainstorming/scripts/frame-template.html +365 -0
- package/skills/brainstorming/scripts/helper.js +216 -0
- package/skills/brainstorming/scripts/server.cjs +9 -0
- package/skills/brainstorming/scripts/server.src.cjs +249 -0
- package/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
- package/skills/brainstorming/visual-companion.md +430 -0
- package/skills/knowledge-base/SKILL.md +22 -9
|
@@ -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
|