setup-cc-room 0.2.0 → 0.2.2
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/dist/chunk-6SYATEI6.js +108 -0
- package/dist/chunk-AVDOC76K.js +116 -0
- package/dist/chunk-ETJNYBPF.js +116 -0
- package/dist/chunk-KEFBOTQD.js +22 -0
- package/dist/chunk-LMBNCW4L.js +142 -0
- package/dist/chunk-MSQUTURC.js +119 -0
- package/dist/chunk-MVD6RIS2.js +120 -0
- package/dist/chunk-OYW7MM4W.js +278 -0
- package/dist/chunk-RYVZHEHF.js +169 -0
- package/dist/chunk-SMSDMP5O.js +125 -0
- package/dist/chunk-ZDOKJ4KX.js +132 -0
- package/dist/daemon-resolver.d.ts +1 -1
- package/dist/daemon-resolver.js +1 -1
- package/dist/i18n.d.ts +7 -0
- package/dist/i18n.js +12 -0
- package/dist/index.js +73 -38
- package/dist/installer.d.ts +5 -2
- package/dist/installer.js +9 -6
- package/dist/register-service.js +2 -1
- package/dist/settings-merger.d.ts +4 -1
- package/dist/settings-merger.js +8 -3
- package/dist/uninstaller.d.ts +10 -0
- package/dist/uninstaller.js +23 -0
- package/dist/validators.js +2 -1
- package/package.json +2 -2
- package/vendor/commands/room/en/private.md +75 -0
- package/vendor/commands/room/en/room.md +475 -0
- package/vendor/commands/room/en/show.md +149 -0
- /package/vendor/commands/room/{private.md → ja/private.md} +0 -0
- /package/vendor/commands/room/{room.md → ja/room.md} +0 -0
- /package/vendor/commands/room/{show.md → ja/show.md} +0 -0
|
@@ -0,0 +1,475 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: room
|
|
3
|
+
description: Unified command for creating, joining, leaving, and switching Primary rooms, viewing status, and managing notes.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Unified command for all room-related operations.
|
|
7
|
+
|
|
8
|
+
## Getting the port
|
|
9
|
+
|
|
10
|
+
Before every HTTP request, obtain the port as follows:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
CC_ROOM_HOME="${CC_ROOM_HOME:-$HOME/.cc-room}"
|
|
14
|
+
HTTP_PORT=$(grep 'http_port:' "$CC_ROOM_HOME/config.yaml" 2>/dev/null | awk '{print $2}' | tr -d '[:space:]')
|
|
15
|
+
HTTP_PORT="${HTTP_PORT:-7332}"
|
|
16
|
+
BASE_URL="http://127.0.0.1:$HTTP_PORT"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
In all subsequent steps, replace every occurrence of `http://127.0.0.1:7332` with `$BASE_URL`.
|
|
20
|
+
|
|
21
|
+
## Subcommands
|
|
22
|
+
|
|
23
|
+
### `/room` (no arguments) — View the whiteboard
|
|
24
|
+
|
|
25
|
+
1. Obtain `BASE_URL` (see above).
|
|
26
|
+
2. Check unread notifications, display them, and mark them as read:
|
|
27
|
+
```bash
|
|
28
|
+
NOTIF_FILE="$CC_ROOM_HOME/notifications.jsonl"
|
|
29
|
+
LAST_READ_FILE="$CC_ROOM_HOME/notifications_last_read"
|
|
30
|
+
LAST_READ=$(cat "$LAST_READ_FILE" 2>/dev/null || echo "")
|
|
31
|
+
if [ -f "$NOTIF_FILE" ]; then
|
|
32
|
+
# Extract and display lines newer than LAST_READ (unread)
|
|
33
|
+
UNREAD=$(awk -v last="$LAST_READ" '
|
|
34
|
+
{ ts = substr($0, 8, 24); if (ts > last) print }
|
|
35
|
+
' "$NOTIF_FILE")
|
|
36
|
+
if [ -n "$UNREAD" ]; then
|
|
37
|
+
echo "🔔 Unread notifications:"
|
|
38
|
+
echo "$UNREAD" | python3 -c '
|
|
39
|
+
import sys, json
|
|
40
|
+
for line in sys.stdin:
|
|
41
|
+
line = line.strip()
|
|
42
|
+
if not line: continue
|
|
43
|
+
try:
|
|
44
|
+
d = json.loads(line)
|
|
45
|
+
t = d.get("type")
|
|
46
|
+
if t == "join":
|
|
47
|
+
print(f" 👋 {d.get(\"identity\", \"\")} joined {d.get(\"room\", \"\")}")
|
|
48
|
+
elif t == "leave":
|
|
49
|
+
print(f" 🚪 {d.get(\"identity\", \"\")} left {d.get(\"room\", \"\")}")
|
|
50
|
+
elif t == "message":
|
|
51
|
+
print(f" 💬 {d.get(\"from\", \"\")}: {d.get(\"content\", \"\")[:80]}")
|
|
52
|
+
elif t == "room_closed":
|
|
53
|
+
print(f" 🔒 Room {d.get(\"room\", \"\")} was closed")
|
|
54
|
+
elif t == "file_received":
|
|
55
|
+
print(f" 📎 {d.get(\"from\", \"\")} shared {d.get(\"filename\", \"\")}")
|
|
56
|
+
elif t == "dream_proposals":
|
|
57
|
+
print(f" 📋 {d.get(\"count\", 0)} proposal(s) for the team ({d.get(\"room\", \"\")})")
|
|
58
|
+
elif t == "dream_merged":
|
|
59
|
+
print(f" 🧠 Team memory was updated ({d.get(\"room\", \"\")})")
|
|
60
|
+
except Exception:
|
|
61
|
+
pass
|
|
62
|
+
'
|
|
63
|
+
echo ""
|
|
64
|
+
fi
|
|
65
|
+
# Mark as read: save the ts of the last line
|
|
66
|
+
LATEST_TS=$(tail -1 "$NOTIF_FILE" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('ts',''))" 2>/dev/null)
|
|
67
|
+
[ -n "$LATEST_TS" ] && echo "$LATEST_TS" > "$LAST_READ_FILE"
|
|
68
|
+
fi
|
|
69
|
+
```
|
|
70
|
+
3. Fetch the room list with `GET $BASE_URL/status`.
|
|
71
|
+
4. Fetch all member summaries with `GET $BASE_URL/context`.
|
|
72
|
+
5. Fetch the message list with `GET $BASE_URL/messages`.
|
|
73
|
+
6. Display in the following format:
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
🏠 <room_name> ★ Primary / 👀 Watch 🔒 Private ON / 📡 Live
|
|
77
|
+
Members: <member1>, <member2>, ...
|
|
78
|
+
Notifications: ON (🔔) / OFF (🔕)
|
|
79
|
+
|
|
80
|
+
📋 Whiteboard:
|
|
81
|
+
(display summaries from context if present)
|
|
82
|
+
<member1>: <summary>
|
|
83
|
+
|
|
84
|
+
💬 Messages:
|
|
85
|
+
(display messages newest-first if present)
|
|
86
|
+
[time] <from>: <content>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Display each room's role / Private state from `rooms[]` in `GET $BASE_URL/status`:
|
|
90
|
+
```bash
|
|
91
|
+
curl -s "$BASE_URL/status" | python3 -c '
|
|
92
|
+
import sys, json
|
|
93
|
+
d = json.load(sys.stdin)
|
|
94
|
+
primary = d.get("primary_room_name") or "(none)"
|
|
95
|
+
priv = "🔒 Private ON" if d.get("private") else "📡 Live"
|
|
96
|
+
print(f"Primary: {primary} {priv}")
|
|
97
|
+
for r in d.get("rooms", []):
|
|
98
|
+
mark = "★" if r.get("role") == "primary" else "👀"
|
|
99
|
+
print(f" {mark} {r[\"name\"]} ({r.get(\"role\", \"watch\")})")
|
|
100
|
+
'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Display notification state by reading `notifications.enabled` from `~/.cc-room/config.yaml`:
|
|
104
|
+
```bash
|
|
105
|
+
CC_ROOM_HOME="${CC_ROOM_HOME:-$HOME/.cc-room}"
|
|
106
|
+
NOTIFY_ENABLED=$(python3 -c "
|
|
107
|
+
import sys
|
|
108
|
+
enabled = True
|
|
109
|
+
try:
|
|
110
|
+
with open('$CC_ROOM_HOME/config.yaml') as f:
|
|
111
|
+
in_sect = False
|
|
112
|
+
for line in f:
|
|
113
|
+
if line.startswith('notifications:'):
|
|
114
|
+
in_sect = True
|
|
115
|
+
elif in_sect and line.strip().startswith('enabled:'):
|
|
116
|
+
enabled = 'false' not in line.lower()
|
|
117
|
+
break
|
|
118
|
+
elif in_sect and line.strip() and not line.startswith(' '):
|
|
119
|
+
in_sect = False
|
|
120
|
+
except Exception:
|
|
121
|
+
pass
|
|
122
|
+
print('ON' if enabled else 'OFF')
|
|
123
|
+
" 2>/dev/null || echo "ON")
|
|
124
|
+
[ "$NOTIFY_ENABLED" = "ON" ] && echo "Notifications: ON 🔔" || echo "Notifications: OFF 🔕"
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
7. If not joined to any room:
|
|
128
|
+
"You are not in a room. Create one with `/room open <name>` or join with `/room join`."
|
|
129
|
+
|
|
130
|
+
### `/room open <name> [--quiet] [--dream-mine=...] [--dream-threshold=N] [--dream-silent=on|off]` — Open a room
|
|
131
|
+
|
|
132
|
+
1. If `--quiet` is present, set `"quiet": true`; otherwise `false`.
|
|
133
|
+
2. If dream options are present, include a `dream` object in the body (configurable only at room creation):
|
|
134
|
+
- `--dream-mine=every_stop|threshold|manual_only` → `"mine_trigger"`
|
|
135
|
+
- `--dream-threshold=N` → `"session_threshold": N` (when using threshold)
|
|
136
|
+
- `--dream-silent=on|off` → `"silent_merge": true/false`
|
|
137
|
+
3. Send the following to `POST $BASE_URL/room/create`:
|
|
138
|
+
```json
|
|
139
|
+
{ "name": "<name>", "quiet": false, "dream": { "mine_trigger": "every_stop" } }
|
|
140
|
+
```
|
|
141
|
+
`dream` is optional (global default is used if omitted).
|
|
142
|
+
4. On success:
|
|
143
|
+
```
|
|
144
|
+
✅ Opened room '<name>'
|
|
145
|
+
PIN: <6-digit number>
|
|
146
|
+
|
|
147
|
+
Share the room name and PIN with your teammates.
|
|
148
|
+
They can join with /room join <name> <PIN>.
|
|
149
|
+
|
|
150
|
+
★ This room becomes Primary (the room you write to)
|
|
151
|
+
📡 Live / 🔒 Private ON (follow the private field in the response)
|
|
152
|
+
|
|
153
|
+
Team memory settings:
|
|
154
|
+
<dream_summary>
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
Options:
|
|
158
|
+
- `--quiet`: Private ON from the moment you join (local mode)
|
|
159
|
+
- `--dream-mine=...`: Mine trigger (every_stop / threshold / manual_only)
|
|
160
|
+
- `--dream-threshold=N`: Number of Stop events when using threshold
|
|
161
|
+
- `--dream-silent=on|off`: 72h silent merge ON/OFF
|
|
162
|
+
|
|
163
|
+
※ `--keep session|ttl|permanent` is planned for a future release
|
|
164
|
+
|
|
165
|
+
### `/room join [name] [pin] [--quiet]` — Join a room
|
|
166
|
+
|
|
167
|
+
When called with no arguments:
|
|
168
|
+
1. Fetch the list of rooms on the LAN with `GET $BASE_URL/room/discover`.
|
|
169
|
+
2. Display the list:
|
|
170
|
+
```
|
|
171
|
+
📡 Rooms on the LAN:
|
|
172
|
+
• <room_name> (hosted by <identity>, <N> members)
|
|
173
|
+
|
|
174
|
+
Join with /room join <name> <PIN>
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
When called with arguments:
|
|
178
|
+
1. Send `{ "name": "<name>", "pin": "<pin>", "quiet": false }` to `POST $BASE_URL/room/join` (set `true` when `--quiet` is used).
|
|
179
|
+
2. On success, display according to the `role` in the response:
|
|
180
|
+
- `role: "primary"` (first room):
|
|
181
|
+
```
|
|
182
|
+
✅ Joined '<name>'
|
|
183
|
+
★ This room becomes Primary (the room you write to)
|
|
184
|
+
Receiving whiteboard content...
|
|
185
|
+
```
|
|
186
|
+
- `role: "watch"` (second room and beyond):
|
|
187
|
+
```
|
|
188
|
+
✅ Joined '<name>' as Watch (read-only)
|
|
189
|
+
Switch Primary with /room switch <name> to write
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### `/room leave` — Leave a room
|
|
193
|
+
|
|
194
|
+
1. Fetch the room list with `GET $BASE_URL/status`.
|
|
195
|
+
2. If you are the host and other members are connected:
|
|
196
|
+
"Guests are connected. [Hand off and leave / Close room for everyone]"
|
|
197
|
+
3. Send `{ "room_id": "<id>" }` to `POST $BASE_URL/leave`.
|
|
198
|
+
4. On success: "Left the room."
|
|
199
|
+
|
|
200
|
+
### `/room pending` — List files awaiting approval
|
|
201
|
+
|
|
202
|
+
Display files received for sharing that have not yet been approved.
|
|
203
|
+
|
|
204
|
+
1. Fetch `GET $BASE_URL/room/pending`.
|
|
205
|
+
2. Display in the following format:
|
|
206
|
+
```
|
|
207
|
+
📥 Files awaiting approval:
|
|
208
|
+
[<id>] <type>: <filename>
|
|
209
|
+
from: <sender>
|
|
210
|
+
save path: <save_path (full path)>
|
|
211
|
+
```
|
|
212
|
+
If the list is empty: "No files awaiting approval"
|
|
213
|
+
|
|
214
|
+
### `/room accept <id>` — Approve a shared file
|
|
215
|
+
|
|
216
|
+
Accept a pending file and write it to the specified save path.
|
|
217
|
+
|
|
218
|
+
1. Send the following to `POST $BASE_URL/room/accept`:
|
|
219
|
+
```json
|
|
220
|
+
{ "pending_id": "<id>" }
|
|
221
|
+
```
|
|
222
|
+
2. On success:
|
|
223
|
+
```
|
|
224
|
+
✅ Approved <filename>
|
|
225
|
+
Save path: <save_path (full path)>
|
|
226
|
+
```
|
|
227
|
+
For `claude_md` type: "Saved as room-scoped. Run /room adopt to add it globally"
|
|
228
|
+
|
|
229
|
+
### `/room reject <id>` — Reject a shared file
|
|
230
|
+
|
|
231
|
+
Discard a pending file.
|
|
232
|
+
|
|
233
|
+
1. Send the following to `POST $BASE_URL/room/reject`:
|
|
234
|
+
```json
|
|
235
|
+
{ "pending_id": "<id>" }
|
|
236
|
+
```
|
|
237
|
+
2. On success: "🗑 Discarded <id>"
|
|
238
|
+
|
|
239
|
+
### `/room adopt` — Promote room-scoped CLAUDE.md to global
|
|
240
|
+
|
|
241
|
+
Append the current room's CLAUDE.md to `~/.claude/CLAUDE.md`.
|
|
242
|
+
|
|
243
|
+
1. Fetch the current room_id with `GET $BASE_URL/status`.
|
|
244
|
+
2. Send the following to `POST $BASE_URL/room/adopt`:
|
|
245
|
+
```json
|
|
246
|
+
{ "room_id": "<room_id>" }
|
|
247
|
+
```
|
|
248
|
+
3. On success:
|
|
249
|
+
```
|
|
250
|
+
✅ Appended room-scoped CLAUDE.md to ~/.claude/CLAUDE.md
|
|
251
|
+
Path: <path>
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
### `/room notify on` / `/room notify off` — Toggle notifications
|
|
255
|
+
|
|
256
|
+
Enable or disable OS notifications for yourself. Settings are persisted in `~/.cc-room/config.yaml`.
|
|
257
|
+
|
|
258
|
+
1. Send the following to `POST $BASE_URL/notify/toggle`:
|
|
259
|
+
- For `on`: `{ "enabled": true }`
|
|
260
|
+
- For `off`: `{ "enabled": false }`
|
|
261
|
+
2. On success:
|
|
262
|
+
- `on`: "🔔 Notifications enabled"
|
|
263
|
+
- `off`: "🔕 Notifications disabled"
|
|
264
|
+
|
|
265
|
+
### `/room switch <name>` — Switch Primary (the room you write to)
|
|
266
|
+
|
|
267
|
+
Switch the room targeted for summaries, artifacts, and Dream. The previous Primary is demoted to Watch.
|
|
268
|
+
|
|
269
|
+
1. Send the following to `POST $BASE_URL/room/switch`:
|
|
270
|
+
```json
|
|
271
|
+
{ "name": "<name>" }
|
|
272
|
+
```
|
|
273
|
+
2. On success:
|
|
274
|
+
```
|
|
275
|
+
★ Primary: <name> (previous Primary is now Watch)
|
|
276
|
+
```
|
|
277
|
+
3. On failure (room name not joined): "Room '<name>' not found"
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
curl -s -X POST "$BASE_URL/room/switch" \
|
|
281
|
+
-H "Content-Type: application/json" \
|
|
282
|
+
-d "{\"name\":\"<name>\"}" | python3 -m json.tool
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### `/room status` — Check Primary / Private / team memory settings
|
|
286
|
+
|
|
287
|
+
List each room's role (Primary/Watch), Private state, and effective dream settings.
|
|
288
|
+
|
|
289
|
+
1. Fetch `GET $BASE_URL/status`.
|
|
290
|
+
2. Display in the following format:
|
|
291
|
+
|
|
292
|
+
```
|
|
293
|
+
Primary: <primary_room_name> 📡 Live / 🔒 Private ON
|
|
294
|
+
|
|
295
|
+
★ auth-feature (primary)
|
|
296
|
+
mine: threshold (every 20 sessions) / silent ON / Mine only when live
|
|
297
|
+
👀 side-project (watch)
|
|
298
|
+
mine: every_stop / silent OFF / Mine only when live
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
`rooms[].dream` is the effective configuration (global default + room override resolved). Key fields:
|
|
302
|
+
- `mine_trigger` — `every_stop` / `threshold` / `manual_only`
|
|
303
|
+
- `session_threshold` — number of Stop events when using threshold
|
|
304
|
+
- `silent_merge` — 72h silent merge ON/OFF
|
|
305
|
+
- `require_show_on` — Mine only when live
|
|
306
|
+
|
|
307
|
+
Example implementation:
|
|
308
|
+
```bash
|
|
309
|
+
curl -s "$BASE_URL/status" | python3 -c '
|
|
310
|
+
import sys, json
|
|
311
|
+
d = json.load(sys.stdin)
|
|
312
|
+
if not d.get("rooms"):
|
|
313
|
+
print("Not joined to any room")
|
|
314
|
+
sys.exit(0)
|
|
315
|
+
primary = d.get("primary_room_name") or "(unset — /room switch <name>)"
|
|
316
|
+
priv = "🔒 Private ON" if d.get("private") else "📡 Live"
|
|
317
|
+
print(f"Primary: {primary} {priv}\n")
|
|
318
|
+
|
|
319
|
+
def dream_line(cfg):
|
|
320
|
+
if not cfg:
|
|
321
|
+
return ""
|
|
322
|
+
mine = cfg.get("mine_trigger", "?")
|
|
323
|
+
if mine == "threshold":
|
|
324
|
+
threshold = cfg.get("session_threshold", "?")
|
|
325
|
+
mine = f"threshold (every {threshold} sessions)"
|
|
326
|
+
silent = "ON" if cfg.get("silent_merge") else "OFF"
|
|
327
|
+
show_req = "Mine only when live" if cfg.get("require_show_on") else "Mine always"
|
|
328
|
+
return f" mine: {mine} / silent {silent} / {show_req}"
|
|
329
|
+
|
|
330
|
+
for r in d.get("rooms", []):
|
|
331
|
+
mark = "★" if r.get("role") == "primary" else "👀"
|
|
332
|
+
print(f" {mark} {r[\"name\"]} ({r.get(\"role\", \"watch\")})")
|
|
333
|
+
line = dream_line(r.get("dream"))
|
|
334
|
+
if line:
|
|
335
|
+
print(line)
|
|
336
|
+
'
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
### `@name <message>` / `@here <message>` / `@all <message>` — Mention teammates
|
|
340
|
+
|
|
341
|
+
When you send a message starting with `@` in the normal Claude Code input field, it reaches humans—not Claude. **This is not a command for Claude; the user types it directly.**
|
|
342
|
+
|
|
343
|
+
| Syntax | Recipients |
|
|
344
|
+
|---|---|
|
|
345
|
+
| `@akira JWT is done` | Only akira |
|
|
346
|
+
| `@here Anyone up for lunch?` | All members who are live (Private OFF)—everyone here right now |
|
|
347
|
+
| `@all Deploy is complete` | Everyone in the room (regardless of Private ON/OFF) |
|
|
348
|
+
|
|
349
|
+
For everyday chat, `@here` feels natural. Use `@all` for urgent interruptions since it reaches everyone forcefully.
|
|
350
|
+
|
|
351
|
+
**Internal behavior (handled by the UserPromptSubmit Hook)**:
|
|
352
|
+
1. Detect the `@` prefix
|
|
353
|
+
2. Match against the room member list:
|
|
354
|
+
- `@name` → send mention only if the member exists. Unknown names (`@dataclass`, etc.) are passed to Claude as normal input
|
|
355
|
+
- `@here` / `@all` → reserved words, so mention is always sent
|
|
356
|
+
- Case-insensitive (`@Akira` = `@akira`)
|
|
357
|
+
3. Determine `context_summary` based on your public state:
|
|
358
|
+
- Live (Primary and Private OFF) → include the latest summary as `context_summary`
|
|
359
|
+
- Private ON or Watch room → omit `context_summary`
|
|
360
|
+
4. Send a `mention` message to the destination daemon over WebSocket
|
|
361
|
+
5. The prompt is still passed to Claude as-is (Claude can interpret the text with `@name`)
|
|
362
|
+
|
|
363
|
+
**On the receiving side**:
|
|
364
|
+
- Mentions are appended to `mentions.jsonl`
|
|
365
|
+
- The status line shows `📬 N`
|
|
366
|
+
- The next time you talk to Claude, a banner is inserted at the top of the prompt inside `<cc-room-context>` tags and marked as read at that point
|
|
367
|
+
|
|
368
|
+
To check unread mentions right now:
|
|
369
|
+
1. Fetch the unread mention list with `GET $BASE_URL/unread`.
|
|
370
|
+
2. Display in the following format:
|
|
371
|
+
```
|
|
372
|
+
📬 Unread mentions (<N>):
|
|
373
|
+
[<time>] <from>: <content>
|
|
374
|
+
context: <context_summary> ← shown only when the sender was live (Private OFF)
|
|
375
|
+
```
|
|
376
|
+
If none: "📭 No unread mentions"
|
|
377
|
+
|
|
378
|
+
### `/room remember <content>` — Post a sticky note (team memory)
|
|
379
|
+
|
|
380
|
+
Share to team memory immediately (always delivered instantly regardless of Private state). From v0.1 onward, generates `.md` files under `room-memory/` and updates the `MEMORY.md` index. Currently appends to `memory.md` (backward compatible).
|
|
381
|
+
|
|
382
|
+
1. Send `{ "content": "<content>" }` to `POST $BASE_URL/memory`.
|
|
383
|
+
2. Display the `message` field from the response to the user as-is (confirmation message with count).
|
|
384
|
+
|
|
385
|
+
### `/room dream` — Team memory (auto-organize, propose, merge)
|
|
386
|
+
|
|
387
|
+
Refer to this as **"team memory"** with users—not "Dream". Operate it via subcommands.
|
|
388
|
+
|
|
389
|
+
#### `/room dream status` — Check settings and pending proposals
|
|
390
|
+
|
|
391
|
+
1. Fetch effective settings with `GET $BASE_URL/dream/config` (add `?room_id=` if needed).
|
|
392
|
+
2. Fetch your pending proposals with `GET $BASE_URL/dream/pending`.
|
|
393
|
+
3. Display in the following format:
|
|
394
|
+
|
|
395
|
+
```
|
|
396
|
+
📋 Team memory settings (<room_name>):
|
|
397
|
+
mine_trigger: threshold (every 20 sessions)
|
|
398
|
+
silent_merge: ON (72h objection window)
|
|
399
|
+
require_show_on: ON (Mine only when live)
|
|
400
|
+
|
|
401
|
+
Your pending proposals: <N>
|
|
402
|
+
1. [decision] Shorten JWT TTL to 1 day (deadline: <objection_deadline>)
|
|
403
|
+
2. ...
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
#### `/room dream objection [number|slug]` — Hold your proposal (stop merge)
|
|
407
|
+
|
|
408
|
+
1. With no argument: if there is exactly one pending proposal, use it; if multiple, show the list and ask the user to choose.
|
|
409
|
+
2. Specify number `N` or `slug`.
|
|
410
|
+
3. Send to `POST $BASE_URL/dream/objection`:
|
|
411
|
+
```json
|
|
412
|
+
{ "proposal_slug": "<slug>", "reason": "まだ早い" }
|
|
413
|
+
```
|
|
414
|
+
4. Display the `message` from the response (e.g., ⏸ Proposal held).
|
|
415
|
+
|
|
416
|
+
#### `/room dream hold [number|slug]` — Extend the objection deadline by 72h
|
|
417
|
+
|
|
418
|
+
1. Identify the target proposal (same as status).
|
|
419
|
+
2. Send `{ "proposal_slug": "<slug>" }` to `POST $BASE_URL/dream/hold`.
|
|
420
|
+
3. Display the `message` from the response.
|
|
421
|
+
|
|
422
|
+
#### `/room dream revert` — Undo the most recent silent merge
|
|
423
|
+
|
|
424
|
+
1. Send `{}` or `{ "room_id": "<id>" }` to `POST $BASE_URL/dream/revert`.
|
|
425
|
+
2. Display the `message` from the response (only the most recent merge within 72h).
|
|
426
|
+
|
|
427
|
+
#### `/room dream mine` — Manually extract knowledge candidates (v0.2 manual accept flow)
|
|
428
|
+
|
|
429
|
+
Extract candidates from the recent session; the user selects items to apply immediately (no silent merge).
|
|
430
|
+
|
|
431
|
+
1. Run `POST $BASE_URL/dream`.
|
|
432
|
+
2. Display `candidates` from the response as a numbered list.
|
|
433
|
+
3. After choosing items to adopt, send `POST $BASE_URL/dream/accept` with `{ "indices": [0, 2] }` (use `{}` for all).
|
|
434
|
+
4. Display the `message` from the response.
|
|
435
|
+
|
|
436
|
+
MCP: detailed search `room_memory_search(query)`, L2 source `room_memory_trace(entry_name)`.
|
|
437
|
+
|
|
438
|
+
### `/room config dream [key=value ...]` — Room Mine/merge settings (host only)
|
|
439
|
+
|
|
440
|
+
Change dream settings for the Primary room. Non-hosts receive an error.
|
|
441
|
+
|
|
442
|
+
1. Display current values with `GET $BASE_URL/dream/config`.
|
|
443
|
+
2. If changes are requested, send a patch to `POST $BASE_URL/dream/config`:
|
|
444
|
+
|
|
445
|
+
| User input | JSON field | Value |
|
|
446
|
+
|---|---|---|
|
|
447
|
+
| `mine=every_stop` | `mine_trigger` | `every_stop` |
|
|
448
|
+
| `mine=threshold` | `mine_trigger` | `threshold` |
|
|
449
|
+
| `mine=manual` | `mine_trigger` | `manual_only` |
|
|
450
|
+
| `threshold=10` | `session_threshold` | `10` |
|
|
451
|
+
| `silent=on` | `silent_merge` | `true` |
|
|
452
|
+
| `silent=off` | `silent_merge` | `false` |
|
|
453
|
+
| `public=on` | `require_show_on` | `true` (Mine only when live) |
|
|
454
|
+
| `public=off` | `require_show_on` | `false` (Mine always) |
|
|
455
|
+
|
|
456
|
+
Example: `POST $BASE_URL/dream/config` `{ "mine_trigger": "every_stop", "silent_merge": false }`
|
|
457
|
+
|
|
458
|
+
3. Display `summary` and `message` from the response.
|
|
459
|
+
|
|
460
|
+
**Example dialogue:**
|
|
461
|
+
|
|
462
|
+
```
|
|
463
|
+
Current settings (auth-feature):
|
|
464
|
+
mine_trigger: threshold (every 20 sessions)
|
|
465
|
+
silent_merge: ON (72h objection window)
|
|
466
|
+
require_show_on: ON (Mine only when live)
|
|
467
|
+
|
|
468
|
+
/room config dream mine=every_stop
|
|
469
|
+
→ ✅ Updated team memory settings for auth-feature
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
## Error handling
|
|
473
|
+
|
|
474
|
+
- If the daemon is not running:
|
|
475
|
+
"cc-room daemon is not running. Start `cc-room-daemon`."
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: show
|
|
3
|
+
description: Explicit whiteboard posts and sharing of skills, commands, or CLAUDE.md. Use /private for local/public toggle.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Write explicitly to the room whiteboard. **Use `/private` to toggle local/public** (the old `/show` toggle is removed).
|
|
7
|
+
|
|
8
|
+
## Resolve the port
|
|
9
|
+
|
|
10
|
+
Before every HTTP request, resolve the port:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
CC_ROOM_HOME="${CC_ROOM_HOME:-$HOME/.cc-room}"
|
|
14
|
+
HTTP_PORT=$(grep 'http_port:' "$CC_ROOM_HOME/config.yaml" 2>/dev/null | awk '{print $2}' | tr -d '[:space:]')
|
|
15
|
+
HTTP_PORT="${HTTP_PORT:-7332}"
|
|
16
|
+
BASE_URL="http://127.0.0.1:$HTTP_PORT"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Subcommands
|
|
20
|
+
|
|
21
|
+
### `/show` (no args) — deprecated
|
|
22
|
+
|
|
23
|
+
The old toggle is removed. Guide the user:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
Use /private to toggle local/public:
|
|
27
|
+
/private on — local mode (hide work)
|
|
28
|
+
/private off — back to public (choose share/drop for pending work)
|
|
29
|
+
To post a message, use /show "message".
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### `/show <message>` — post a message
|
|
33
|
+
|
|
34
|
+
Post to the **Primary** room whiteboard.
|
|
35
|
+
|
|
36
|
+
1. Check `private` via `GET $BASE_URL/status`.
|
|
37
|
+
2. If Private ON, always confirm with the user:
|
|
38
|
+
"You are in local mode. This message will be posted to Primary (<primary_room_name>). Send it?"
|
|
39
|
+
→ Continue only if they accept.
|
|
40
|
+
3. `POST $BASE_URL/share` with:
|
|
41
|
+
```json
|
|
42
|
+
{ "message": "<message>" }
|
|
43
|
+
```
|
|
44
|
+
(Posted to Primary only.)
|
|
45
|
+
4. On success:
|
|
46
|
+
```
|
|
47
|
+
📡 [<room_name>] <message>
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### `/show skill <name>` — share a skill
|
|
51
|
+
|
|
52
|
+
Share your skill file with everyone in the room (recipients must accept).
|
|
53
|
+
|
|
54
|
+
1. Resolve the port (above).
|
|
55
|
+
2. Load the skill file:
|
|
56
|
+
```bash
|
|
57
|
+
SKILL_NAME="<name>"
|
|
58
|
+
SKILL_BASE="${SKILL_NAME%.md}"
|
|
59
|
+
SKILL_FILE=""
|
|
60
|
+
CC_CLAUDE_HOME="${CC_CLAUDE_HOME:-$HOME/.claude}"
|
|
61
|
+
for dir in "$CC_CLAUDE_HOME/skills" "$CC_CLAUDE_HOME/commands"; do
|
|
62
|
+
if [ -f "$dir/$SKILL_BASE.md" ]; then
|
|
63
|
+
SKILL_FILE="$dir/$SKILL_BASE.md"
|
|
64
|
+
break
|
|
65
|
+
elif [ -f "$dir/$SKILL_BASE" ]; then
|
|
66
|
+
SKILL_FILE="$dir/$SKILL_BASE"
|
|
67
|
+
break
|
|
68
|
+
fi
|
|
69
|
+
done
|
|
70
|
+
if [ -z "$SKILL_FILE" ]; then
|
|
71
|
+
echo "Error: skill '$SKILL_NAME' not found"
|
|
72
|
+
exit 1
|
|
73
|
+
fi
|
|
74
|
+
SKILL_CONTENT=$(cat "$SKILL_FILE")
|
|
75
|
+
```
|
|
76
|
+
3. `POST $BASE_URL/show/file` with:
|
|
77
|
+
```json
|
|
78
|
+
{ "share_type": "skill", "filename": "<name>.md", "content": "<file_content>" }
|
|
79
|
+
```
|
|
80
|
+
4. On success:
|
|
81
|
+
```
|
|
82
|
+
📤 Shared skill '<name>' (recipients must approve with /room accept)
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### `/show command <name>` — share a command
|
|
86
|
+
|
|
87
|
+
Share your command file with everyone in the room (recipients must accept).
|
|
88
|
+
|
|
89
|
+
1. Resolve the port (above).
|
|
90
|
+
2. Load the command file:
|
|
91
|
+
```bash
|
|
92
|
+
CMD_NAME="<name>"
|
|
93
|
+
CMD_BASE="${CMD_NAME%.md}"
|
|
94
|
+
CMD_FILE=""
|
|
95
|
+
for dir in "$HOME/.claude/commands"; do
|
|
96
|
+
if [ -f "$dir/$CMD_BASE.md" ]; then CMD_FILE="$dir/$CMD_BASE.md"; break; fi
|
|
97
|
+
done
|
|
98
|
+
if [ -z "$CMD_FILE" ]; then
|
|
99
|
+
echo "Error: command '$CMD_NAME' not found"
|
|
100
|
+
exit 1
|
|
101
|
+
fi
|
|
102
|
+
CMD_CONTENT=$(cat "$CMD_FILE")
|
|
103
|
+
```
|
|
104
|
+
3. `POST $BASE_URL/show/file` with:
|
|
105
|
+
```json
|
|
106
|
+
{ "share_type": "command", "filename": "<name>.md", "content": "<file_content>" }
|
|
107
|
+
```
|
|
108
|
+
4. On success:
|
|
109
|
+
```
|
|
110
|
+
📤 Shared command '<name>' (recipients must approve with /room accept)
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### `/show claude-md` — share CLAUDE.md
|
|
114
|
+
|
|
115
|
+
Share this project's CLAUDE.md with the room (after accept it is saved room-scoped; promote globally with `/room adopt`).
|
|
116
|
+
|
|
117
|
+
1. Resolve the port (above).
|
|
118
|
+
2. Load CLAUDE.md from the current directory:
|
|
119
|
+
```bash
|
|
120
|
+
CLAUDE_MD_FILE="$(pwd)/CLAUDE.md"
|
|
121
|
+
if [ ! -f "$CLAUDE_MD_FILE" ]; then
|
|
122
|
+
GIT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
|
|
123
|
+
if [ -n "$GIT_ROOT" ] && [ -f "$GIT_ROOT/CLAUDE.md" ]; then
|
|
124
|
+
CLAUDE_MD_FILE="$GIT_ROOT/CLAUDE.md"
|
|
125
|
+
else
|
|
126
|
+
echo "Error: CLAUDE.md not found"
|
|
127
|
+
exit 1
|
|
128
|
+
fi
|
|
129
|
+
fi
|
|
130
|
+
CLAUDE_MD_CONTENT=$(cat "$CLAUDE_MD_FILE")
|
|
131
|
+
```
|
|
132
|
+
3. `POST $BASE_URL/show/file` with:
|
|
133
|
+
```json
|
|
134
|
+
{ "share_type": "claude_md", "filename": "CLAUDE.md", "content": "<file_content>" }
|
|
135
|
+
```
|
|
136
|
+
4. On success:
|
|
137
|
+
```
|
|
138
|
+
📤 Shared CLAUDE.md (recipients approve with /room accept; saved room-scoped)
|
|
139
|
+
Use /room adopt to promote to ~/.claude/CLAUDE.md
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Errors
|
|
143
|
+
|
|
144
|
+
- If the daemon is not running:
|
|
145
|
+
"cc-room daemon is not running."
|
|
146
|
+
- If not in a room:
|
|
147
|
+
"You are not in a room. Use `/room open` or `/room join` first."
|
|
148
|
+
- If there is no Primary room:
|
|
149
|
+
"Pick a room to write with `/room switch <name>`."
|
|
File without changes
|
|
File without changes
|
|
File without changes
|