superpowers-mcp 5.1.2 → 6.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 (38) hide show
  1. package/README.md +25 -14
  2. package/README.zh-TW.md +30 -14
  3. package/out/server.js +2 -2
  4. package/package.json +1 -1
  5. package/skills/brainstorming/SKILL.md +5 -10
  6. package/skills/brainstorming/scripts/frame-template.html +25 -26
  7. package/skills/brainstorming/scripts/helper.js +107 -35
  8. package/skills/brainstorming/scripts/server.cjs +377 -30
  9. package/skills/brainstorming/scripts/start-server.sh +70 -9
  10. package/skills/brainstorming/scripts/stop-server.sh +66 -2
  11. package/skills/brainstorming/spec-document-reviewer-prompt.md +1 -1
  12. package/skills/brainstorming/visual-companion.md +29 -25
  13. package/skills/dispatching-parallel-agents/SKILL.md +9 -6
  14. package/skills/executing-plans/SKILL.md +2 -2
  15. package/skills/finishing-a-development-branch/SKILL.md +2 -12
  16. package/skills/receiving-code-review/SKILL.md +2 -2
  17. package/skills/requesting-code-review/SKILL.md +2 -2
  18. package/skills/requesting-code-review/code-reviewer.md +15 -11
  19. package/skills/subagent-driven-development/SKILL.md +206 -67
  20. package/skills/subagent-driven-development/implementer-prompt.md +30 -4
  21. package/skills/subagent-driven-development/scripts/review-package +44 -0
  22. package/skills/subagent-driven-development/scripts/sdd-workspace +22 -0
  23. package/skills/subagent-driven-development/scripts/task-brief +40 -0
  24. package/skills/subagent-driven-development/task-reviewer-prompt.md +188 -0
  25. package/skills/systematic-debugging/SKILL.md +1 -1
  26. package/skills/test-driven-development/SKILL.md +2 -2
  27. package/skills/using-git-worktrees/SKILL.md +9 -22
  28. package/skills/using-superpowers/SKILL.md +17 -72
  29. package/skills/using-superpowers/references/antigravity-tools.md +23 -0
  30. package/skills/using-superpowers/references/codex-tools.md +1 -21
  31. package/skills/using-superpowers/references/pi-tools.md +16 -0
  32. package/skills/writing-plans/SKILL.md +22 -0
  33. package/skills/writing-plans/plan-document-reviewer-prompt.md +1 -1
  34. package/skills/writing-skills/SKILL.md +52 -18
  35. package/skills/writing-skills/anthropic-best-practices.md +91 -91
  36. package/skills/writing-skills/persuasion-principles.md +3 -3
  37. package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +0 -25
  38. package/skills/subagent-driven-development/spec-reviewer-prompt.md +0 -61
@@ -1,26 +1,126 @@
1
1
  (function() {
2
- const WS_URL = 'ws://' + window.location.host;
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
+ function nextReconnectDelay(current, max) {
7
+ return Math.min(current * 2, max);
8
+ }
9
+ if (typeof module !== 'undefined' && module.exports) {
10
+ module.exports = { nextReconnectDelay, MIN_RECONNECT_MS, MAX_RECONNECT_MS, TOMBSTONE_AFTER_MS };
11
+ }
12
+
13
+ // Everything below is browser-only; bail out when loaded in Node (tests).
14
+ if (typeof window === 'undefined') return;
15
+
3
16
  let ws = null;
4
17
  let eventQueue = [];
18
+ let reconnectDelay = MIN_RECONNECT_MS;
19
+ let reconnectTimer = null;
20
+ let disconnectedSince = null;
21
+ let everConnected = false;
22
+ let tombstoneShown = false;
23
+
24
+ function sessionKey() {
25
+ try {
26
+ return window.sessionStorage && window.sessionStorage.getItem('brainstorm-session-key');
27
+ } catch (e) {}
28
+ return null;
29
+ }
30
+
31
+ function websocketUrl() {
32
+ const key = sessionKey();
33
+ return 'ws://' + window.location.host + (key ? '/?key=' + encodeURIComponent(key) : '');
34
+ }
35
+
36
+ function reloadAfterRecovery() {
37
+ const key = sessionKey();
38
+ if (key) {
39
+ window.location.replace('/?key=' + encodeURIComponent(key));
40
+ } else {
41
+ window.location.reload();
42
+ }
43
+ }
44
+
45
+ // Reflect connection state in the frame's status pill (absent on full-doc screens).
46
+ function setStatus(state) {
47
+ const el = document.querySelector('.status');
48
+ if (!el) return;
49
+ const map = {
50
+ connecting: ['Connecting…', 'var(--text-tertiary)'],
51
+ connected: ['Connected', 'var(--success)'],
52
+ reconnecting: ['Reconnecting…', 'var(--warning)'],
53
+ disconnected: ['Disconnected', 'var(--error)']
54
+ };
55
+ const [text, color] = map[state] || map.disconnected;
56
+ el.textContent = text;
57
+ el.style.setProperty('--status-color', color);
58
+ }
59
+
60
+ function showTombstone() {
61
+ if (tombstoneShown) return;
62
+ tombstoneShown = true;
63
+ const el = document.createElement('div');
64
+ el.id = 'bs-tombstone';
65
+ el.style.cssText = 'position:fixed;inset:0;z-index:99999;display:flex;' +
66
+ 'align-items:center;justify-content:center;padding:2rem;text-align:center;' +
67
+ 'background:rgba(20,20,22,0.92);color:#f5f5f7;font-family:system-ui,sans-serif';
68
+ const inner = document.createElement('div');
69
+ inner.style.cssText = 'max-width:480px';
70
+ const h2 = document.createElement('h2');
71
+ h2.style.cssText = 'margin:0 0 .5rem;font-weight:600';
72
+ h2.textContent = 'Companion paused';
73
+ inner.appendChild(h2);
74
+ const p = document.createElement('p');
75
+ p.style.cssText = 'margin:0;opacity:.85';
76
+ p.textContent = 'This brainstorm companion has stopped. ' +
77
+ 'Ask your coding agent to bring it back — this page reconnects automatically.';
78
+ inner.appendChild(p);
79
+ el.appendChild(inner);
80
+ if (document.body) document.body.appendChild(el);
81
+ }
5
82
 
6
83
  function connect() {
7
- ws = new WebSocket(WS_URL);
84
+ if (reconnectTimer) { clearTimeout(reconnectTimer); reconnectTimer = null; }
85
+ setStatus(everConnected ? 'reconnecting' : 'connecting');
86
+ ws = new WebSocket(websocketUrl());
8
87
 
9
88
  ws.onopen = () => {
89
+ const recovered = tombstoneShown;
90
+ everConnected = true;
91
+ disconnectedSince = null;
92
+ reconnectDelay = MIN_RECONNECT_MS;
93
+ tombstoneShown = false;
94
+ setStatus('connected');
10
95
  eventQueue.forEach(e => ws.send(JSON.stringify(e)));
11
96
  eventQueue = [];
97
+ // Recovered from a tombstoned outage (e.g. the server restarted on the same
98
+ // port) — reload through the keyed bootstrap when possible so the cookie is
99
+ // refreshed before the visible URL returns to bare /.
100
+ if (recovered) reloadAfterRecovery();
12
101
  };
13
102
 
14
103
  ws.onmessage = (msg) => {
15
- const data = JSON.parse(msg.data);
16
- if (data.type === 'reload') {
17
- window.location.reload();
18
- }
104
+ let data;
105
+ try { data = JSON.parse(msg.data); } catch (e) { return; }
106
+ if (data.type === 'reload') window.location.reload();
19
107
  };
20
108
 
21
109
  ws.onclose = () => {
22
- setTimeout(connect, 1000);
110
+ ws = null;
111
+ if (disconnectedSince === null) disconnectedSince = Date.now();
112
+ if (Date.now() - disconnectedSince >= TOMBSTONE_AFTER_MS) {
113
+ setStatus('disconnected');
114
+ showTombstone();
115
+ } else {
116
+ setStatus('reconnecting');
117
+ }
118
+ reconnectTimer = setTimeout(connect, reconnectDelay);
119
+ reconnectDelay = nextReconnectDelay(reconnectDelay, MAX_RECONNECT_MS);
23
120
  };
121
+
122
+ // Let onclose own reconnection so we don't schedule it twice.
123
+ ws.onerror = () => { try { ws.close(); } catch (e) {} };
24
124
  }
25
125
 
26
126
  function sendEvent(event) {
@@ -32,7 +132,6 @@
32
132
  }
33
133
  }
34
134
 
35
- // Capture clicks on choice elements
36
135
  document.addEventListener('click', (e) => {
37
136
  const target = e.target.closest('[data-choice]');
38
137
  if (!target) return;
@@ -44,34 +143,8 @@
44
143
  id: target.id || null
45
144
  });
46
145
 
47
- // Update indicator bar (defer so toggleSelect runs first)
48
- setTimeout(() => {
49
- const indicator = document.getElementById('indicator-text');
50
- if (!indicator) return;
51
- const container = target.closest('.options') || target.closest('.cards');
52
- const selected = container ? container.querySelectorAll('.selected') : [];
53
- if (selected.length === 0) {
54
- indicator.textContent = 'Click an option above, then return to the terminal';
55
- } else if (selected.length === 1) {
56
- const label = selected[0].querySelector('h3, .content h3, .card-body h3')?.textContent?.trim() || selected[0].dataset.choice;
57
- const selectedText = document.createElement('span');
58
- selectedText.className = 'selected-text';
59
- selectedText.textContent = label + ' selected';
60
- indicator.textContent = '';
61
- indicator.appendChild(selectedText);
62
- indicator.append(' — return to terminal to continue');
63
- } else {
64
- const countText = document.createElement('span');
65
- countText.className = 'selected-text';
66
- countText.textContent = selected.length + ' selected';
67
- indicator.textContent = '';
68
- indicator.appendChild(countText);
69
- indicator.append(' — return to terminal to continue');
70
- }
71
- }, 0);
72
146
  });
73
147
 
74
- // Frame UI: selection tracking
75
148
  window.selectedChoice = null;
76
149
 
77
150
  window.toggleSelect = function(el) {
@@ -88,7 +161,6 @@
88
161
  window.selectedChoice = el.dataset.choice;
89
162
  };
90
163
 
91
- // Expose API for explicit use
92
164
  window.brainstorm = {
93
165
  send: sendEvent,
94
166
  choice: (value, metadata = {}) => sendEvent({ type: 'choice', value, ...metadata })