@jspg-ai/coding-bb 0.0.1

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 (183) hide show
  1. package/README.md +41 -0
  2. package/cbb/dev-standards/rules/cbb-ai-behavior.md +104 -0
  3. package/cbb/dev-standards/rules/cbb-coding-rule.md +50 -0
  4. package/cbb/dev-standards/rules/cbb-priority.md +56 -0
  5. package/cbb/dev-standards/skills/architecture-specs/SKILL.md +129 -0
  6. package/cbb/dev-standards/skills/coding-specs/SKILL.md +376 -0
  7. package/cbb/dev-standards/skills/coding-specs/references/concurrency.md +53 -0
  8. package/cbb/dev-standards/skills/coding-specs/references/config-center.md +16 -0
  9. package/cbb/dev-standards/skills/coding-specs/references/distributed.md +42 -0
  10. package/cbb/dev-standards/skills/coding-specs/references/es-coding.md +60 -0
  11. package/cbb/dev-standards/skills/coding-specs/references/scheduled-task.md +25 -0
  12. package/cbb/dev-standards/skills/coding-specs/references/security.md +11 -0
  13. package/cbb/dev-standards/skills/coding-specs/references/unit-testing.md +43 -0
  14. package/cbb/dev-standards/skills/es-design-specs/SKILL.md +104 -0
  15. package/cbb/dev-standards/skills/mysql-design-specs/SKILL.md +89 -0
  16. package/cbb/lib/install/claude-code.js +20 -0
  17. package/cbb/lib/install/cleanup.js +64 -0
  18. package/cbb/lib/install/init.js +1875 -0
  19. package/cbb/lib/install/qoder.js +20 -0
  20. package/cbb/lib/install/workspaces.js +232 -0
  21. package/cbb/lib/openspec/index.js +554 -0
  22. package/cbb/lib/superpowers/index.js +265 -0
  23. package/cbb/lib/utils/check-update.js +147 -0
  24. package/cbb/lib/utils/checkbox.js +383 -0
  25. package/cbb/lib/utils/gitignore.js +69 -0
  26. package/cbb/lib/utils/output.js +64 -0
  27. package/cbb/lib/utils/settings.js +119 -0
  28. package/cbb/lib/utils/version.js +135 -0
  29. package/cbb/lib/wiki/api-client.js +358 -0
  30. package/cbb/lib/wiki/cli.js +427 -0
  31. package/cbb/lib/wiki/convert.js +464 -0
  32. package/cbb/lib/wiki/index.js +218 -0
  33. package/cbb/lib/wiki/mermaid-guard.js +103 -0
  34. package/cbb/lib/wiki/split.js +131 -0
  35. package/cbb/tools/cbb-decompile-jar/SKILL.md +220 -0
  36. package/cbb/tools/cbb-decompile-jar/scripts/decompile.py +863 -0
  37. package/cbb/tools/cbb-design-to-wiki/SKILL.md +180 -0
  38. package/cbb/tools/cbb-mvn-guide/SKILL.md +281 -0
  39. package/cbb/tools/cbb-mvn-guide/scripts/mvn_jdk_manager.py +378 -0
  40. package/cbb/tools/cbb-mvn-guide/scripts/mvn_pom_jdk_reader.py +197 -0
  41. package/cbb/tools/cbb-plantuml-authoring/SKILL.md +448 -0
  42. package/cbb/tools/cbb-plantuml-authoring/references/drawing-templates.md +479 -0
  43. package/cbb/tools/cbb-wiki-ops/SKILL.md +134 -0
  44. package/cbb/tools/cbb-wiki-ops/scripts/check-auth.js +44 -0
  45. package/cbb/worktrees/_shared/scripts/find-target-worktree.js +96 -0
  46. package/cbb/worktrees/_shared/scripts/find-workspace-root.js +67 -0
  47. package/cbb/worktrees/_shared/scripts/push-core.js +136 -0
  48. package/cbb/worktrees/_shared/scripts/silence-popup.js +23 -0
  49. package/cbb/worktrees/commands/close.md +64 -0
  50. package/cbb/worktrees/commands/extend.md +65 -0
  51. package/cbb/worktrees/commands/init.md +55 -0
  52. package/cbb/worktrees/commands/push.md +42 -0
  53. package/cbb/worktrees/skills/openspec-close-worktree/SKILL.md +449 -0
  54. package/cbb/worktrees/skills/openspec-close-worktree/scripts/check-env.js +76 -0
  55. package/cbb/worktrees/skills/openspec-close-worktree/scripts/check-unarchived.js +48 -0
  56. package/cbb/worktrees/skills/openspec-close-worktree/scripts/delete-branches.js +136 -0
  57. package/cbb/worktrees/skills/openspec-close-worktree/scripts/discover-apps.js +76 -0
  58. package/cbb/worktrees/skills/openspec-close-worktree/scripts/find-target-worktree.js +96 -0
  59. package/cbb/worktrees/skills/openspec-close-worktree/scripts/find-workspace-root.js +67 -0
  60. package/cbb/worktrees/skills/openspec-close-worktree/scripts/remove-worktrees.js +124 -0
  61. package/cbb/worktrees/skills/openspec-close-worktree/scripts/safety-check.js +174 -0
  62. package/cbb/worktrees/skills/openspec-close-worktree/scripts/silence-popup.js +23 -0
  63. package/cbb/worktrees/skills/openspec-extend-worktree/SKILL.md +390 -0
  64. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-env.js +95 -0
  65. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/check-repos.js +98 -0
  66. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/create-branches-and-worktrees.js +135 -0
  67. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/find-target-worktree.js +96 -0
  68. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/find-workspace-root.js +67 -0
  69. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/install-ai.js +150 -0
  70. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/list-available-apps.js +88 -0
  71. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/push-core.js +136 -0
  72. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/silence-popup.js +23 -0
  73. package/cbb/worktrees/skills/openspec-extend-worktree/scripts/sync-repos.js +93 -0
  74. package/cbb/worktrees/skills/openspec-init-worktree/SKILL.md +539 -0
  75. package/cbb/worktrees/skills/openspec-init-worktree/scripts/auto-open.js +136 -0
  76. package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-env-deep.js +87 -0
  77. package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-env.js +90 -0
  78. package/cbb/worktrees/skills/openspec-init-worktree/scripts/check-repos.js +171 -0
  79. package/cbb/worktrees/skills/openspec-init-worktree/scripts/create-branches.js +103 -0
  80. package/cbb/worktrees/skills/openspec-init-worktree/scripts/create-worktrees.js +154 -0
  81. package/cbb/worktrees/skills/openspec-init-worktree/scripts/find-workspace-root.js +67 -0
  82. package/cbb/worktrees/skills/openspec-init-worktree/scripts/generate-app-options.js +93 -0
  83. package/cbb/worktrees/skills/openspec-init-worktree/scripts/install-ai.js +177 -0
  84. package/cbb/worktrees/skills/openspec-init-worktree/scripts/parse-config.js +67 -0
  85. package/cbb/worktrees/skills/openspec-init-worktree/scripts/push-branches.js +101 -0
  86. package/cbb/worktrees/skills/openspec-init-worktree/scripts/push-core.js +136 -0
  87. package/cbb/worktrees/skills/openspec-init-worktree/scripts/silence-popup.js +23 -0
  88. package/cbb/worktrees/skills/openspec-init-worktree/scripts/sync-repos.js +95 -0
  89. package/cbb/worktrees/skills/openspec-init-worktree/scripts/update-gitignore.js +134 -0
  90. package/cbb/worktrees/skills/openspec-push-worktrees/SKILL.md +307 -0
  91. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/commit-worktrees.js +269 -0
  92. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/find-target-worktree.js +96 -0
  93. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/find-workspace-root.js +67 -0
  94. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/push-core.js +136 -0
  95. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/push-worktrees.js +159 -0
  96. package/cbb/worktrees/skills/openspec-push-worktrees/scripts/silence-popup.js +23 -0
  97. package/config/cbb.yaml +6 -0
  98. package/config/config.sample.json +16 -0
  99. package/config/openspec/config.yaml +28 -0
  100. package/config/openspec/schemas/spec-driven/schema.yaml +247 -0
  101. package/config/openspec/schemas/spec-driven/templates/design.md +475 -0
  102. package/config/openspec/schemas/spec-driven/templates/proposal.md +58 -0
  103. package/config/openspec/schemas/spec-driven/templates/spec.md +8 -0
  104. package/config/openspec/schemas/spec-driven/templates/tasks.md +9 -0
  105. package/config/workspaces.json +15 -0
  106. package/openspec/.version +6 -0
  107. package/openspec/commands/apply.md +182 -0
  108. package/openspec/commands/archive.md +223 -0
  109. package/openspec/commands/bulk-archive.md +334 -0
  110. package/openspec/commands/continue.md +112 -0
  111. package/openspec/commands/explore.md +206 -0
  112. package/openspec/commands/ff.md +111 -0
  113. package/openspec/commands/new.md +70 -0
  114. package/openspec/commands/onboard.md +555 -0
  115. package/openspec/commands/propose.md +157 -0
  116. package/openspec/commands/sync.md +256 -0
  117. package/openspec/commands/update.md +85 -0
  118. package/openspec/commands/verify.md +169 -0
  119. package/openspec/skills/openspec-apply-change/SKILL.md +187 -0
  120. package/openspec/skills/openspec-archive-change/SKILL.md +181 -0
  121. package/openspec/skills/openspec-bulk-archive-change/SKILL.md +338 -0
  122. package/openspec/skills/openspec-continue-change/SKILL.md +117 -0
  123. package/openspec/skills/openspec-explore/SKILL.md +342 -0
  124. package/openspec/skills/openspec-ff-change/SKILL.md +116 -0
  125. package/openspec/skills/openspec-new-change/SKILL.md +76 -0
  126. package/openspec/skills/openspec-onboard/SKILL.md +560 -0
  127. package/openspec/skills/openspec-propose/SKILL.md +162 -0
  128. package/openspec/skills/openspec-sync-specs/SKILL.md +261 -0
  129. package/openspec/skills/openspec-update-change/SKILL.md +90 -0
  130. package/openspec/skills/openspec-verify-change/SKILL.md +174 -0
  131. package/package.json +46 -0
  132. package/superpowers/.version +6 -0
  133. package/superpowers/skills/brainstorming/SKILL.md +250 -0
  134. package/superpowers/skills/brainstorming/scripts/frame-template.html +213 -0
  135. package/superpowers/skills/brainstorming/scripts/helper.js +167 -0
  136. package/superpowers/skills/brainstorming/scripts/server.cjs +723 -0
  137. package/superpowers/skills/brainstorming/scripts/start-server.sh +209 -0
  138. package/superpowers/skills/brainstorming/scripts/stop-server.sh +120 -0
  139. package/superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +49 -0
  140. package/superpowers/skills/brainstorming/visual-companion.md +299 -0
  141. package/superpowers/skills/dispatching-parallel-agents/SKILL.md +167 -0
  142. package/superpowers/skills/executing-plans/SKILL.md +64 -0
  143. package/superpowers/skills/finishing-a-development-branch/SKILL.md +225 -0
  144. package/superpowers/skills/receiving-code-review/SKILL.md +205 -0
  145. package/superpowers/skills/requesting-code-review/SKILL.md +95 -0
  146. package/superpowers/skills/requesting-code-review/code-reviewer.md +181 -0
  147. package/superpowers/skills/subagent-driven-development/SKILL.md +568 -0
  148. package/superpowers/skills/subagent-driven-development/implementer-prompt.md +154 -0
  149. package/superpowers/skills/subagent-driven-development/re-review-prompt.md +115 -0
  150. package/superpowers/skills/subagent-driven-development/scripts/review-package +46 -0
  151. package/superpowers/skills/subagent-driven-development/scripts/sdd-workspace +40 -0
  152. package/superpowers/skills/subagent-driven-development/scripts/task-brief +41 -0
  153. package/superpowers/skills/subagent-driven-development/task-reviewer-prompt.md +207 -0
  154. package/superpowers/skills/systematic-debugging/CREATION-LOG.md +119 -0
  155. package/superpowers/skills/systematic-debugging/SKILL.md +283 -0
  156. package/superpowers/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  157. package/superpowers/skills/systematic-debugging/condition-based-waiting.md +115 -0
  158. package/superpowers/skills/systematic-debugging/defense-in-depth.md +122 -0
  159. package/superpowers/skills/systematic-debugging/find-polluter.sh +72 -0
  160. package/superpowers/skills/systematic-debugging/root-cause-tracing.md +169 -0
  161. package/superpowers/skills/systematic-debugging/test-academic.md +14 -0
  162. package/superpowers/skills/systematic-debugging/test-pressure-1.md +58 -0
  163. package/superpowers/skills/systematic-debugging/test-pressure-2.md +68 -0
  164. package/superpowers/skills/systematic-debugging/test-pressure-3.md +69 -0
  165. package/superpowers/skills/test-driven-development/SKILL.md +320 -0
  166. package/superpowers/skills/test-driven-development/writing-good-tests.md +198 -0
  167. package/superpowers/skills/using-git-worktrees/SKILL.md +167 -0
  168. package/superpowers/skills/using-superpowers/SKILL.md +63 -0
  169. package/superpowers/skills/using-superpowers/references/antigravity-tools.md +23 -0
  170. package/superpowers/skills/using-superpowers/references/codex-tools.md +108 -0
  171. package/superpowers/skills/using-superpowers/references/gemini-tools.md +63 -0
  172. package/superpowers/skills/using-superpowers/references/hermes-tools.md +56 -0
  173. package/superpowers/skills/using-superpowers/references/pi-tools.md +16 -0
  174. package/superpowers/skills/verification-before-completion/SKILL.md +120 -0
  175. package/superpowers/skills/writing-plans/SKILL.md +171 -0
  176. package/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +49 -0
  177. package/superpowers/skills/writing-skills/SKILL.md +679 -0
  178. package/superpowers/skills/writing-skills/anthropic-best-practices.md +1150 -0
  179. package/superpowers/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
  180. package/superpowers/skills/writing-skills/graphviz-conventions.dot +172 -0
  181. package/superpowers/skills/writing-skills/persuasion-principles.md +187 -0
  182. package/superpowers/skills/writing-skills/render-graphs.js +169 -0
  183. package/superpowers/skills/writing-skills/testing-skills-with-subagents.md +384 -0
@@ -0,0 +1,213 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <title>Superpowers Brainstorming</title>
6
+ <style>
7
+ /*
8
+ * BRAINSTORM COMPANION FRAME TEMPLATE
9
+ *
10
+ * This template provides a consistent frame with:
11
+ * - OS-aware light/dark theming
12
+ * - Header branding and connection status
13
+ * - Scrollable main content area
14
+ * - CSS helpers for common UI patterns
15
+ *
16
+ * Content is injected via placeholder comment in #frame-content.
17
+ */
18
+
19
+ * { box-sizing: border-box; margin: 0; padding: 0; }
20
+ html, body { height: 100%; overflow: hidden; }
21
+
22
+ /* ===== THEME VARIABLES ===== */
23
+ :root {
24
+ --bg-primary: #f5f5f7;
25
+ --bg-secondary: #ffffff;
26
+ --bg-tertiary: #e5e5e7;
27
+ --border: #d1d1d6;
28
+ --text-primary: #1d1d1f;
29
+ --text-secondary: #86868b;
30
+ --text-tertiary: #aeaeb2;
31
+ --accent: #0071e3;
32
+ --accent-hover: #0077ed;
33
+ --success: #34c759;
34
+ --warning: #ff9f0a;
35
+ --error: #ff3b30;
36
+ --selected-bg: #e8f4fd;
37
+ --selected-border: #0071e3;
38
+ }
39
+
40
+ @media (prefers-color-scheme: dark) {
41
+ :root {
42
+ --bg-primary: #1d1d1f;
43
+ --bg-secondary: #2d2d2f;
44
+ --bg-tertiary: #3d3d3f;
45
+ --border: #424245;
46
+ --text-primary: #f5f5f7;
47
+ --text-secondary: #86868b;
48
+ --text-tertiary: #636366;
49
+ --accent: #0a84ff;
50
+ --accent-hover: #409cff;
51
+ --selected-bg: rgba(10, 132, 255, 0.15);
52
+ --selected-border: #0a84ff;
53
+ }
54
+ }
55
+
56
+ body {
57
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
58
+ background: var(--bg-primary);
59
+ color: var(--text-primary);
60
+ display: flex;
61
+ flex-direction: column;
62
+ line-height: 1.5;
63
+ }
64
+
65
+ /* ===== FRAME STRUCTURE ===== */
66
+ .brand { display: flex; align-items: center; min-width: 0; overflow: hidden; color: var(--text-secondary); line-height: 1; }
67
+ .brand a { color: inherit; text-decoration: none; display: flex; align-items: center; gap: 0.5rem; min-width: 0; max-width: 100%; line-height: 1; }
68
+ .brand-copy { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; line-height: 1; transform: translateY(-1px); }
69
+ .brand-logo { display: block; height: 1em; width: auto; max-width: 180px; flex-shrink: 0; filter: invert(1); }
70
+ @media (prefers-color-scheme: dark) {
71
+ .brand-logo { filter: none; }
72
+ }
73
+ .status { font-size: 0.7rem; color: var(--status-color, var(--success)); display: flex; align-items: center; gap: 0.4rem; justify-self: end; white-space: nowrap; line-height: 1; }
74
+ .status::before { content: ''; width: 6px; height: 6px; background: var(--status-color, var(--success)); border-radius: 50%; }
75
+
76
+ .main { flex: 1; overflow-y: auto; }
77
+ #frame-content { padding: 2rem; min-height: 100%; }
78
+
79
+ .header {
80
+ background: var(--bg-secondary);
81
+ border-bottom: 1px solid var(--border);
82
+ padding: 0.5rem 1.5rem;
83
+ flex-shrink: 0;
84
+ display: grid;
85
+ grid-template-columns: minmax(0, 1fr) auto;
86
+ align-items: center;
87
+ gap: 1rem;
88
+ min-height: 42px;
89
+ }
90
+ .header .brand { justify-self: start; width: 100%; font-size: 0.75rem; line-height: 1; }
91
+ .header .status { grid-column: 2; line-height: 1; }
92
+ .header span {
93
+ font-size: 0.75rem;
94
+ color: var(--text-secondary);
95
+ }
96
+ .header .selected-text {
97
+ color: var(--accent);
98
+ font-weight: 500;
99
+ }
100
+
101
+ /* ===== TYPOGRAPHY ===== */
102
+ h2 { font-size: 1.5rem; font-weight: 600; margin-bottom: 0.5rem; }
103
+ h3 { font-size: 1.1rem; font-weight: 600; margin-bottom: 0.25rem; }
104
+ .subtitle { color: var(--text-secondary); margin-bottom: 1.5rem; }
105
+ .section { margin-bottom: 2rem; }
106
+ .label { font-size: 0.7rem; color: var(--text-secondary); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.5rem; }
107
+
108
+ /* ===== OPTIONS (for A/B/C choices) ===== */
109
+ .options { display: flex; flex-direction: column; gap: 0.75rem; }
110
+ .option {
111
+ background: var(--bg-secondary);
112
+ border: 2px solid var(--border);
113
+ border-radius: 12px;
114
+ padding: 1rem 1.25rem;
115
+ cursor: pointer;
116
+ transition: all 0.15s ease;
117
+ display: flex;
118
+ align-items: flex-start;
119
+ gap: 1rem;
120
+ }
121
+ .option:hover { border-color: var(--accent); }
122
+ .option.selected { background: var(--selected-bg); border-color: var(--selected-border); }
123
+ .option .letter {
124
+ background: var(--bg-tertiary);
125
+ color: var(--text-secondary);
126
+ width: 1.75rem; height: 1.75rem;
127
+ border-radius: 6px;
128
+ display: flex; align-items: center; justify-content: center;
129
+ font-weight: 600; font-size: 0.85rem; flex-shrink: 0;
130
+ }
131
+ .option.selected .letter { background: var(--accent); color: white; }
132
+ .option .content { flex: 1; }
133
+ .option .content h3 { font-size: 0.95rem; margin-bottom: 0.15rem; }
134
+ .option .content p { color: var(--text-secondary); font-size: 0.85rem; margin: 0; }
135
+
136
+ /* ===== CARDS (for showing designs/mockups) ===== */
137
+ .cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 1rem; }
138
+ .card {
139
+ background: var(--bg-secondary);
140
+ border: 1px solid var(--border);
141
+ border-radius: 12px;
142
+ overflow: hidden;
143
+ cursor: pointer;
144
+ transition: all 0.15s ease;
145
+ }
146
+ .card:hover { border-color: var(--accent); transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0,0,0,0.1); }
147
+ .card.selected { border-color: var(--selected-border); border-width: 2px; }
148
+ .card-image { background: var(--bg-tertiary); aspect-ratio: 16/10; display: flex; align-items: center; justify-content: center; }
149
+ .card-body { padding: 1rem; }
150
+ .card-body h3 { margin-bottom: 0.25rem; }
151
+ .card-body p { color: var(--text-secondary); font-size: 0.85rem; }
152
+
153
+ /* ===== MOCKUP CONTAINER ===== */
154
+ .mockup {
155
+ background: var(--bg-secondary);
156
+ border: 1px solid var(--border);
157
+ border-radius: 12px;
158
+ overflow: hidden;
159
+ margin-bottom: 1.5rem;
160
+ }
161
+ .mockup-header {
162
+ background: var(--bg-tertiary);
163
+ padding: 0.5rem 1rem;
164
+ font-size: 0.75rem;
165
+ color: var(--text-secondary);
166
+ border-bottom: 1px solid var(--border);
167
+ }
168
+ .mockup-body { padding: 1.5rem; }
169
+
170
+ /* ===== SPLIT VIEW (side-by-side comparison) ===== */
171
+ .split { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; }
172
+ @media (max-width: 700px) { .split { grid-template-columns: 1fr; } }
173
+
174
+ /* ===== PROS/CONS ===== */
175
+ .pros-cons { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin: 1rem 0; }
176
+ .pros, .cons { background: var(--bg-secondary); border-radius: 8px; padding: 1rem; }
177
+ .pros h4 { color: var(--success); font-size: 0.85rem; margin-bottom: 0.5rem; }
178
+ .cons h4 { color: var(--error); font-size: 0.85rem; margin-bottom: 0.5rem; }
179
+ .pros ul, .cons ul { margin-left: 1.25rem; font-size: 0.85rem; color: var(--text-secondary); }
180
+ .pros li, .cons li { margin-bottom: 0.25rem; }
181
+
182
+ /* ===== PLACEHOLDER (for mockup areas) ===== */
183
+ .placeholder {
184
+ background: var(--bg-tertiary);
185
+ border: 2px dashed var(--border);
186
+ border-radius: 8px;
187
+ padding: 2rem;
188
+ text-align: center;
189
+ color: var(--text-tertiary);
190
+ }
191
+
192
+ /* ===== INLINE MOCKUP ELEMENTS ===== */
193
+ .mock-nav { background: var(--accent); color: white; padding: 0.75rem 1rem; display: flex; gap: 1.5rem; font-size: 0.9rem; }
194
+ .mock-sidebar { background: var(--bg-tertiary); padding: 1rem; min-width: 180px; }
195
+ .mock-content { padding: 1.5rem; flex: 1; }
196
+ .mock-button { background: var(--accent); color: white; border: none; padding: 0.5rem 1rem; border-radius: 6px; font-size: 0.85rem; }
197
+ .mock-input { background: var(--bg-primary); border: 1px solid var(--border); border-radius: 6px; padding: 0.5rem; width: 100%; }
198
+ </style>
199
+ </head>
200
+ <body>
201
+ <div class="header">
202
+ <!-- BRANDING -->
203
+ <div class="status">Connecting…</div>
204
+ </div>
205
+
206
+ <div class="main">
207
+ <div id="frame-content">
208
+ <!-- CONTENT -->
209
+ </div>
210
+ </div>
211
+
212
+ </body>
213
+ </html>
@@ -0,0 +1,167 @@
1
+ (function() {
2
+ const MIN_RECONNECT_MS = 500;
3
+ const MAX_RECONNECT_MS = 30000;
4
+ const TOMBSTONE_AFTER_MS = 15000; // show the "paused" overlay after this long disconnected
5
+
6
+ // Pure: next backoff delay (doubles, capped). Exported for unit tests.
7
+ function nextReconnectDelay(current, max) {
8
+ return Math.min(current * 2, max);
9
+ }
10
+ if (typeof module !== 'undefined' && module.exports) {
11
+ module.exports = { nextReconnectDelay, MIN_RECONNECT_MS, MAX_RECONNECT_MS, TOMBSTONE_AFTER_MS };
12
+ }
13
+
14
+ // Everything below is browser-only; bail out when loaded in Node (tests).
15
+ if (typeof window === 'undefined') return;
16
+
17
+ let ws = null;
18
+ let eventQueue = [];
19
+ let reconnectDelay = MIN_RECONNECT_MS;
20
+ let reconnectTimer = null;
21
+ let disconnectedSince = null;
22
+ let everConnected = false;
23
+ let tombstoneShown = false;
24
+
25
+ function sessionKey() {
26
+ try {
27
+ return window.sessionStorage && window.sessionStorage.getItem('brainstorm-session-key');
28
+ } catch (e) {}
29
+ return null;
30
+ }
31
+
32
+ function websocketUrl() {
33
+ const key = sessionKey();
34
+ return 'ws://' + window.location.host + (key ? '/?key=' + encodeURIComponent(key) : '');
35
+ }
36
+
37
+ function reloadAfterRecovery() {
38
+ const key = sessionKey();
39
+ if (key) {
40
+ window.location.replace('/?key=' + encodeURIComponent(key));
41
+ } else {
42
+ window.location.reload();
43
+ }
44
+ }
45
+
46
+ // Reflect connection state in the frame's status pill (absent on full-doc screens).
47
+ function setStatus(state) {
48
+ const el = document.querySelector('.status');
49
+ if (!el) return;
50
+ const map = {
51
+ connecting: ['Connecting…', 'var(--text-tertiary)'],
52
+ connected: ['Connected', 'var(--success)'],
53
+ reconnecting: ['Reconnecting…', 'var(--warning)'],
54
+ disconnected: ['Disconnected', 'var(--error)']
55
+ };
56
+ const [text, color] = map[state] || map.disconnected;
57
+ el.textContent = text;
58
+ el.style.setProperty('--status-color', color);
59
+ }
60
+
61
+ // Self-styled so it works on framed and full-document screens alike.
62
+ function showTombstone() {
63
+ if (tombstoneShown) return;
64
+ tombstoneShown = true;
65
+ const el = document.createElement('div');
66
+ el.id = 'bs-tombstone';
67
+ el.style.cssText = 'position:fixed;inset:0;z-index:99999;display:flex;' +
68
+ 'align-items:center;justify-content:center;padding:2rem;text-align:center;' +
69
+ 'background:rgba(20,20,22,0.92);color:#f5f5f7;font-family:system-ui,sans-serif';
70
+ el.innerHTML = '<div style="max-width:480px">' +
71
+ '<h2 style="margin:0 0 .5rem;font-weight:600">Companion paused</h2>' +
72
+ '<p style="margin:0;opacity:.85">This brainstorm companion has stopped. ' +
73
+ 'Ask your coding agent to bring it back — this page reconnects automatically.</p></div>';
74
+ if (document.body) document.body.appendChild(el);
75
+ }
76
+
77
+ function connect() {
78
+ if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }
79
+ setStatus(everConnected ? 'reconnecting' : 'connecting');
80
+ ws = new WebSocket(websocketUrl());
81
+
82
+ ws.onopen = () => {
83
+ const recovered = tombstoneShown;
84
+ everConnected = true;
85
+ disconnectedSince = null;
86
+ reconnectDelay = MIN_RECONNECT_MS;
87
+ tombstoneShown = false;
88
+ setStatus('connected');
89
+ eventQueue.forEach(e => ws.send(JSON.stringify(e)));
90
+ eventQueue = [];
91
+ // Recovered from a tombstoned outage (e.g. the server restarted on the same
92
+ // port) — reload through the keyed bootstrap when possible so the cookie is
93
+ // refreshed before the visible URL returns to bare /.
94
+ if (recovered) reloadAfterRecovery();
95
+ };
96
+
97
+ ws.onmessage = (msg) => {
98
+ let data;
99
+ try { data = JSON.parse(msg.data); } catch (e) { return; }
100
+ if (data.type === 'reload') window.location.reload();
101
+ };
102
+
103
+ ws.onclose = () => {
104
+ ws = null;
105
+ if (disconnectedSince === null) disconnectedSince = Date.now();
106
+ if (Date.now() - disconnectedSince >= TOMBSTONE_AFTER_MS) {
107
+ setStatus('disconnected');
108
+ showTombstone();
109
+ } else {
110
+ setStatus('reconnecting');
111
+ }
112
+ reconnectTimer = setTimeout(connect, reconnectDelay);
113
+ reconnectDelay = nextReconnectDelay(reconnectDelay, MAX_RECONNECT_MS);
114
+ };
115
+
116
+ // Let onclose own reconnection so we don't schedule it twice.
117
+ ws.onerror = () => { try { ws.close(); } catch (e) {} };
118
+ }
119
+
120
+ function sendEvent(event) {
121
+ event.timestamp = Date.now();
122
+ if (ws && ws.readyState === WebSocket.OPEN) {
123
+ ws.send(JSON.stringify(event));
124
+ } else {
125
+ eventQueue.push(event);
126
+ }
127
+ }
128
+
129
+ // Capture clicks on choice elements
130
+ document.addEventListener('click', (e) => {
131
+ const target = e.target.closest('[data-choice]');
132
+ if (!target) return;
133
+
134
+ sendEvent({
135
+ type: 'click',
136
+ text: target.textContent.trim(),
137
+ choice: target.dataset.choice,
138
+ id: target.id || null
139
+ });
140
+
141
+ });
142
+
143
+ // Frame UI: selection tracking
144
+ window.selectedChoice = null;
145
+
146
+ window.toggleSelect = function(el) {
147
+ const container = el.closest('.options') || el.closest('.cards');
148
+ const multi = container && container.dataset.multiselect !== undefined;
149
+ if (container && !multi) {
150
+ container.querySelectorAll('.option, .card').forEach(o => o.classList.remove('selected'));
151
+ }
152
+ if (multi) {
153
+ el.classList.toggle('selected');
154
+ } else {
155
+ el.classList.add('selected');
156
+ }
157
+ window.selectedChoice = el.dataset.choice;
158
+ };
159
+
160
+ // Expose API for explicit use
161
+ window.brainstorm = {
162
+ send: sendEvent,
163
+ choice: (value, metadata = {}) => sendEvent({ type: 'choice', value, ...metadata })
164
+ };
165
+
166
+ connect();
167
+ })();