claude-comms 1.0.38 → 1.0.40
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/.agents/repo.md +4 -1
- package/.agents/tools/chrome-devtools/browsertools.py +207 -104
- package/.claude/agents/core/uat.md +3 -2
- package/.claude/commands/await-feedback-orchestrator.md +12 -0
- package/.claude/commands/await-feedback.md +21 -0
- package/.claude/commands/cook.md +8 -7
- package/.claude/commands/learn.md +9 -9
- package/.claude/commands/uat-refine.md +122 -0
- package/CLAUDE.md +4 -4
- package/package.json +1 -1
- package/src/orchestrator/installer.js +44 -24
- package/.claude/commands/new-agents.md +0 -11
- /package/.claude/agents/{meta-agent-builder.md → util/meta-agent-builder.md} +0 -0
- /package/.claude/agents/{session-review.md → util/session-review.md} +0 -0
package/.agents/repo.md
CHANGED
|
@@ -12,4 +12,7 @@ VALIDATE by Running required commands — all must pass without warnings or erro
|
|
|
12
12
|
you can access the client on `http://localhost:3000/` using the UAT toolkit
|
|
13
13
|
|
|
14
14
|
## Documentation Protocol
|
|
15
|
-
Guard the doc hierarchy: specs in `docs/project/spec/` remain the source of truth (Businesslogic, data dictionary, data flows, tech guide, industry references); guides in `docs/project/guides/` capture evolving process; phase folders (`docs/project/phases/XX-Name/`) store live work packages and notes. Update whichever doc you rely on as soon as the code diverges.
|
|
15
|
+
Guard the doc hierarchy: specs in `docs/project/spec/` remain the source of truth (Businesslogic, data dictionary, data flows, tech guide, industry references); guides in `docs/project/guides/` capture evolving process; phase folders (`docs/project/phases/XX-Name/`) store live work packages and notes. Update whichever doc you rely on as soon as the code diverges.
|
|
16
|
+
|
|
17
|
+
## PRE Deployment
|
|
18
|
+
`vercel build --yes` must pass otherwise CI/CD will FAIL!
|
|
@@ -21,20 +21,38 @@ import json
|
|
|
21
21
|
import os
|
|
22
22
|
import signal
|
|
23
23
|
import sys
|
|
24
|
+
import time
|
|
25
|
+
import uuid
|
|
24
26
|
from pathlib import Path
|
|
25
27
|
from typing import Any, Dict, Optional
|
|
26
28
|
|
|
27
29
|
# State directory
|
|
28
30
|
STATE_DIR = Path.home() / ".browsertools"
|
|
29
|
-
SOCKET_PATH = STATE_DIR / "daemon.sock"
|
|
30
|
-
PID_FILE = STATE_DIR / "daemon.pid"
|
|
31
31
|
CONFIG_FILE = STATE_DIR / "config.json"
|
|
32
|
+
INACTIVITY_TIMEOUT = 600 # 10 minutes
|
|
32
33
|
|
|
33
34
|
# Global daemon state
|
|
34
35
|
mcp_proc = None
|
|
35
36
|
mcp_reader = None
|
|
36
37
|
mcp_writer = None
|
|
37
38
|
pending_requests = {} # msg_id -> response_future
|
|
39
|
+
last_activity_time = time.time()
|
|
40
|
+
current_instance_id = None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def generate_instance_id() -> str:
|
|
44
|
+
"""Generate 8-char hex instance ID."""
|
|
45
|
+
return uuid.uuid4().hex[:8]
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def get_socket_path(instance_id: str) -> Path:
|
|
49
|
+
"""Get socket path for instance."""
|
|
50
|
+
return STATE_DIR / f"daemon-{instance_id}.sock"
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def get_pid_file(instance_id: str) -> Path:
|
|
54
|
+
"""Get PID file path for instance."""
|
|
55
|
+
return STATE_DIR / f"daemon-{instance_id}.pid"
|
|
38
56
|
|
|
39
57
|
|
|
40
58
|
def ensure_state_dir():
|
|
@@ -42,22 +60,39 @@ def ensure_state_dir():
|
|
|
42
60
|
STATE_DIR.mkdir(exist_ok=True)
|
|
43
61
|
|
|
44
62
|
|
|
45
|
-
def get_daemon_pid() -> Optional[int]:
|
|
46
|
-
"""Get PID of running daemon."""
|
|
47
|
-
|
|
63
|
+
def get_daemon_pid(instance_id: str) -> Optional[int]:
|
|
64
|
+
"""Get PID of running daemon for instance."""
|
|
65
|
+
pid_file = get_pid_file(instance_id)
|
|
66
|
+
if not pid_file.exists():
|
|
48
67
|
return None
|
|
49
68
|
try:
|
|
50
|
-
pid = int(
|
|
69
|
+
pid = int(pid_file.read_text().strip())
|
|
51
70
|
os.kill(pid, 0) # Check if alive
|
|
52
71
|
return pid
|
|
53
72
|
except (ProcessLookupError, ValueError):
|
|
54
|
-
|
|
73
|
+
pid_file.unlink(missing_ok=True)
|
|
55
74
|
return None
|
|
56
75
|
|
|
57
76
|
|
|
58
|
-
def is_daemon_running() -> bool:
|
|
59
|
-
"""Check if daemon is running."""
|
|
60
|
-
return get_daemon_pid() is not None and
|
|
77
|
+
def is_daemon_running(instance_id: str) -> bool:
|
|
78
|
+
"""Check if daemon is running for instance."""
|
|
79
|
+
return get_daemon_pid(instance_id) is not None and get_socket_path(instance_id).exists()
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def get_all_instances() -> list[str]:
|
|
83
|
+
"""Get list of all running instance IDs."""
|
|
84
|
+
instances = []
|
|
85
|
+
if not STATE_DIR.exists():
|
|
86
|
+
return instances
|
|
87
|
+
for pid_file in STATE_DIR.glob("daemon-*.pid"):
|
|
88
|
+
instance_id = pid_file.stem.replace("daemon-", "")
|
|
89
|
+
if is_daemon_running(instance_id):
|
|
90
|
+
instances.append(instance_id)
|
|
91
|
+
else:
|
|
92
|
+
# Clean up stale files
|
|
93
|
+
pid_file.unlink(missing_ok=True)
|
|
94
|
+
get_socket_path(instance_id).unlink(missing_ok=True)
|
|
95
|
+
return instances
|
|
61
96
|
|
|
62
97
|
|
|
63
98
|
def load_config() -> Dict[str, Any]:
|
|
@@ -145,7 +180,10 @@ async def read_mcp_responses():
|
|
|
145
180
|
|
|
146
181
|
async def handle_client(reader: asyncio.StreamReader, writer: asyncio.StreamWriter):
|
|
147
182
|
"""Handle a client connection."""
|
|
148
|
-
global mcp_writer, pending_requests
|
|
183
|
+
global mcp_writer, pending_requests, last_activity_time
|
|
184
|
+
|
|
185
|
+
# Update activity timestamp
|
|
186
|
+
last_activity_time = time.time()
|
|
149
187
|
|
|
150
188
|
try:
|
|
151
189
|
while True:
|
|
@@ -222,15 +260,32 @@ async def shutdown_mcp():
|
|
|
222
260
|
print(f"Error during shutdown: {e}", file=sys.stderr)
|
|
223
261
|
|
|
224
262
|
|
|
225
|
-
async def
|
|
263
|
+
async def inactivity_monitor(shutdown_callback):
|
|
264
|
+
"""Monitor for inactivity and trigger shutdown after timeout."""
|
|
265
|
+
global last_activity_time
|
|
266
|
+
|
|
267
|
+
while True:
|
|
268
|
+
await asyncio.sleep(10) # Check every 10 seconds for responsive timeout
|
|
269
|
+
inactive_time = time.time() - last_activity_time
|
|
270
|
+
if inactive_time > INACTIVITY_TIMEOUT:
|
|
271
|
+
await shutdown_callback()
|
|
272
|
+
return
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
async def run_daemon(instance_id: str):
|
|
226
276
|
"""Run the persistent daemon."""
|
|
227
|
-
global mcp_proc, mcp_reader, mcp_writer
|
|
277
|
+
global mcp_proc, mcp_reader, mcp_writer, current_instance_id, last_activity_time
|
|
228
278
|
|
|
279
|
+
current_instance_id = instance_id
|
|
280
|
+
last_activity_time = time.time()
|
|
229
281
|
ensure_state_dir()
|
|
230
282
|
|
|
283
|
+
socket_path = get_socket_path(instance_id)
|
|
284
|
+
pid_file = get_pid_file(instance_id)
|
|
285
|
+
|
|
231
286
|
# Clean up old socket if exists
|
|
232
|
-
if
|
|
233
|
-
|
|
287
|
+
if socket_path.exists():
|
|
288
|
+
socket_path.unlink()
|
|
234
289
|
|
|
235
290
|
# Load config
|
|
236
291
|
config = load_config()
|
|
@@ -255,29 +310,38 @@ async def run_daemon():
|
|
|
255
310
|
mcp_writer = mcp_proc.stdin
|
|
256
311
|
|
|
257
312
|
# Write PID file
|
|
258
|
-
|
|
313
|
+
pid_file.write_text(str(os.getpid()))
|
|
259
314
|
|
|
260
|
-
print(f"Starting Unix socket server at {
|
|
315
|
+
print(f"Starting Unix socket server at {socket_path}...", file=sys.stderr)
|
|
261
316
|
|
|
262
317
|
# Start Unix socket server
|
|
263
318
|
server = await asyncio.start_unix_server(
|
|
264
319
|
handle_client,
|
|
265
|
-
path=str(
|
|
320
|
+
path=str(socket_path)
|
|
266
321
|
)
|
|
267
322
|
|
|
268
|
-
print(f"Daemon ready. PID: {os.getpid()}", file=sys.stderr)
|
|
323
|
+
print(f"Daemon ready. Instance: {instance_id} PID: {os.getpid()}", file=sys.stderr)
|
|
324
|
+
|
|
325
|
+
# Output instance ID to stdout for capture (all other output goes to stderr)
|
|
326
|
+
print(instance_id)
|
|
269
327
|
|
|
270
328
|
# Setup signal handlers for graceful shutdown
|
|
271
329
|
loop = asyncio.get_event_loop()
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
330
|
+
shutdown_triggered = asyncio.Event()
|
|
331
|
+
|
|
332
|
+
async def handle_shutdown(sig=None):
|
|
333
|
+
if shutdown_triggered.is_set():
|
|
334
|
+
return
|
|
335
|
+
shutdown_triggered.set()
|
|
336
|
+
if sig:
|
|
337
|
+
print(f"\nReceived {sig.name}, shutting down...", file=sys.stderr)
|
|
275
338
|
await shutdown_mcp()
|
|
276
339
|
server.close()
|
|
277
340
|
await server.wait_closed()
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
loop
|
|
341
|
+
socket_path.unlink(missing_ok=True)
|
|
342
|
+
pid_file.unlink(missing_ok=True)
|
|
343
|
+
# Exit cleanly instead of stopping loop (avoids RuntimeError)
|
|
344
|
+
os._exit(0)
|
|
281
345
|
|
|
282
346
|
for sig in (signal.SIGTERM, signal.SIGINT):
|
|
283
347
|
loop.add_signal_handler(
|
|
@@ -285,35 +349,39 @@ async def run_daemon():
|
|
|
285
349
|
lambda s=sig: asyncio.create_task(handle_shutdown(s))
|
|
286
350
|
)
|
|
287
351
|
|
|
288
|
-
# Run
|
|
352
|
+
# Run socket server, MCP response reader, and inactivity monitor
|
|
289
353
|
try:
|
|
290
354
|
await asyncio.gather(
|
|
291
355
|
server.serve_forever(),
|
|
292
356
|
read_mcp_responses(),
|
|
357
|
+
inactivity_monitor(handle_shutdown),
|
|
293
358
|
)
|
|
294
359
|
except KeyboardInterrupt:
|
|
295
360
|
print("\nShutting down daemon...", file=sys.stderr)
|
|
296
361
|
finally:
|
|
297
362
|
# Cleanup
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
363
|
+
if not shutdown_triggered.is_set():
|
|
364
|
+
await shutdown_mcp()
|
|
365
|
+
server.close()
|
|
366
|
+
await server.wait_closed()
|
|
367
|
+
socket_path.unlink(missing_ok=True)
|
|
368
|
+
pid_file.unlink(missing_ok=True)
|
|
303
369
|
|
|
304
370
|
|
|
305
371
|
# ============================================================================
|
|
306
372
|
# CLIENT MODE - Connect to daemon and send commands
|
|
307
373
|
# ============================================================================
|
|
308
374
|
|
|
309
|
-
async def send_command(tool_name: str, args: Dict[str, Any]) -> Any:
|
|
375
|
+
async def send_command(instance_id: str, tool_name: str, args: Dict[str, Any]) -> Any:
|
|
310
376
|
"""Send a command to the daemon via socket."""
|
|
311
|
-
if not is_daemon_running():
|
|
312
|
-
raise RuntimeError("Daemon not running. Start with:
|
|
377
|
+
if not is_daemon_running(instance_id):
|
|
378
|
+
raise RuntimeError(f"Daemon instance '{instance_id}' not running. Start with: browsertools.py daemon start")
|
|
379
|
+
|
|
380
|
+
socket_path = get_socket_path(instance_id)
|
|
313
381
|
|
|
314
382
|
# Connect to daemon's Unix socket with increased limit for large responses
|
|
315
383
|
reader, writer = await asyncio.open_unix_connection(
|
|
316
|
-
str(
|
|
384
|
+
str(socket_path),
|
|
317
385
|
limit=1024 * 1024 * 10 # 10MB limit for large snapshots
|
|
318
386
|
)
|
|
319
387
|
|
|
@@ -372,7 +440,7 @@ def clean_output(result: Any) -> str:
|
|
|
372
440
|
return str(result)
|
|
373
441
|
|
|
374
442
|
|
|
375
|
-
async def execute_command(cmd: str, cmd_args: Dict[str, Any]):
|
|
443
|
+
async def execute_command(instance_id: str, cmd: str, cmd_args: Dict[str, Any]):
|
|
376
444
|
"""Execute a single command via daemon."""
|
|
377
445
|
|
|
378
446
|
# Map commands to MCP tools
|
|
@@ -452,7 +520,7 @@ async def execute_command(cmd: str, cmd_args: Dict[str, Any]):
|
|
|
452
520
|
raise ValueError(f"Unknown command: {cmd}")
|
|
453
521
|
|
|
454
522
|
# Send to daemon
|
|
455
|
-
result = await send_command(tool_name, tool_args)
|
|
523
|
+
result = await send_command(instance_id, tool_name, tool_args)
|
|
456
524
|
return clean_output(result)
|
|
457
525
|
|
|
458
526
|
|
|
@@ -463,22 +531,22 @@ async def execute_command(cmd: str, cmd_args: Dict[str, Any]):
|
|
|
463
531
|
async def main():
|
|
464
532
|
parser = argparse.ArgumentParser(
|
|
465
533
|
prog="browsertools.py",
|
|
466
|
-
description="Chrome DevTools MCP wrapper -
|
|
534
|
+
description="Chrome DevTools MCP wrapper - multi-instance daemon mode",
|
|
467
535
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
468
536
|
epilog=r"""
|
|
469
537
|
browsertools.py - Chrome DevTools automation tool
|
|
470
538
|
|
|
471
|
-
|
|
472
539
|
Usage: uv run .agents/tools/chrome-devtools/browsertools.py <command>
|
|
473
540
|
|
|
474
541
|
DAEMON MANAGEMENT:
|
|
475
|
-
daemon start Start
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
daemon stop Stop daemon, kill Chrome cleanly
|
|
479
|
-
daemon status Check if daemon running
|
|
542
|
+
daemon start Start new daemon instance
|
|
543
|
+
Returns: "browsertools daemon started. Instance ID: <id>"
|
|
544
|
+
daemon stop <id> Stop daemon. kill chrome cleanly.
|
|
480
545
|
daemon config Create config file
|
|
481
546
|
|
|
547
|
+
ALL OTHER COMMANDS REQUIRE --instance <id>:
|
|
548
|
+
--instance <id> Required for all browser commands
|
|
549
|
+
|
|
482
550
|
NAVIGATION:
|
|
483
551
|
nav <url> Navigate to URL
|
|
484
552
|
--timeout <ms> Max wait time in milliseconds
|
|
@@ -491,37 +559,25 @@ INSPECTION:
|
|
|
491
559
|
shot [path] Screenshot viewport (optional: save to path)
|
|
492
560
|
eval <js> Execute JavaScript, returns JSON
|
|
493
561
|
--args <json> JSON array of element references (advanced)
|
|
494
|
-
Simple: "() => document.title"
|
|
495
|
-
Complex: "(el) => el.innerText" --args '[{"uid":"1_23"}]'
|
|
496
562
|
|
|
497
563
|
INTERACTION:
|
|
498
564
|
click <uid> Click element by UID from snapshot
|
|
499
565
|
fill <uid> <value> Fill input/textarea or select option
|
|
500
|
-
key <key> Press key or combo
|
|
501
|
-
Examples: "Enter", "Tab", "Control+A"
|
|
566
|
+
key <key> Press key or combo (e.g., "Enter", "Tab", "Control+A")
|
|
502
567
|
hover <uid> Hover over element
|
|
503
568
|
drag <from> <to> Drag element from UID to target UID
|
|
504
|
-
fillform <json> Fill multiple form fields
|
|
505
|
-
Example: '[{"uid":"1_1","value":"text"}]'
|
|
569
|
+
fillform <json> Fill multiple form fields
|
|
506
570
|
|
|
507
571
|
DEBUGGING:
|
|
508
|
-
conslist List console messages
|
|
509
|
-
--types error warn Filter by type
|
|
510
|
-
--size N Max messages
|
|
511
|
-
|
|
572
|
+
conslist List console messages (--types, --size)
|
|
512
573
|
consget <msgid> Get console message details
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
--types xhr fetch Filter by resource type
|
|
516
|
-
--size N Max requests
|
|
517
|
-
|
|
518
|
-
netget [reqid] Get request details (omit reqid for currently selected)
|
|
574
|
+
netlist List network requests (--types, --size)
|
|
575
|
+
netget [reqid] Get request details
|
|
519
576
|
|
|
520
577
|
PAGE MANIPULATION:
|
|
521
|
-
resize <
|
|
522
|
-
dialog <
|
|
523
|
-
|
|
524
|
-
upload <uid> <file_path> Upload file
|
|
578
|
+
resize <w> <h> Resize viewport
|
|
579
|
+
dialog <action> Handle alert/confirm/prompt (accept|dismiss)
|
|
580
|
+
upload <uid> <path> Upload file
|
|
525
581
|
|
|
526
582
|
USAGE TIPS:
|
|
527
583
|
**Snapshots** are verbose. Always try to pipe grep first
|
|
@@ -535,31 +591,34 @@ Limit output for **debugging** commands
|
|
|
535
591
|
- Console: conslist --size 5 --types error
|
|
536
592
|
|
|
537
593
|
EXAMPLES:
|
|
538
|
-
#
|
|
539
|
-
uv run .agents/tools/chrome-devtools/browsertools.py daemon start
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
uv run .agents/tools/chrome-devtools/browsertools.py
|
|
544
|
-
uv run .agents/tools/chrome-devtools/browsertools.py snap | grep -iC5 "
|
|
545
|
-
uv run .agents/tools/chrome-devtools/browsertools.py
|
|
546
|
-
uv run .agents/tools/chrome-devtools/browsertools.py
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
- Always stop daemon when you are finished to clean up browser resources
|
|
594
|
+
# Start daemon (backgrounds automatically, prints instance ID)
|
|
595
|
+
uv run .agents/tools/chrome-devtools/browsertools.py daemon start
|
|
596
|
+
# Output: browsertools daemon started. Instance ID: a3f7b2c1
|
|
597
|
+
|
|
598
|
+
# Use instance for all commands
|
|
599
|
+
uv run .agents/tools/chrome-devtools/browsertools.py --instance a3f7b2c1 nav http://app.com/login
|
|
600
|
+
uv run .agents/tools/chrome-devtools/browsertools.py --instance a3f7b2c1 snap | grep -iC5 "email\|username\|login"
|
|
601
|
+
uv run .agents/tools/chrome-devtools/browsertools.py --instance a3f7b2c1 fill 1_23 user@example.com
|
|
602
|
+
uv run .agents/tools/chrome-devtools/browsertools.py --instance a3f7b2c1 snap | grep -iC5 "button.*(submit|login|sign.?in)"
|
|
603
|
+
uv run .agents/tools/chrome-devtools/browsertools.py --instance a3f7b2c1 click 1_25 | grep -iC5 "dashboard\|home\|welcome"
|
|
604
|
+
|
|
605
|
+
# Stop when finished to clean up resources
|
|
606
|
+
uv run .agents/tools/chrome-devtools/browsertools.py daemon stop a3f7b2c1
|
|
552
607
|
"""
|
|
553
608
|
)
|
|
554
609
|
|
|
610
|
+
# Global --instance argument
|
|
611
|
+
parser.add_argument("--instance", "-i", help="Daemon instance ID (required for browser commands)")
|
|
612
|
+
|
|
555
613
|
subparsers = parser.add_subparsers(dest="cmd", required=True)
|
|
556
614
|
|
|
557
615
|
# Daemon management
|
|
558
616
|
daemon = subparsers.add_parser("daemon", help="Manage daemon")
|
|
559
617
|
daemon_sub = daemon.add_subparsers(dest="daemon_cmd", required=True)
|
|
560
|
-
daemon_sub.add_parser("start", help="Start daemon")
|
|
561
|
-
daemon_sub.add_parser("stop", help="Stop daemon")
|
|
562
|
-
|
|
618
|
+
daemon_sub.add_parser("start", help="Start new daemon instance (returns instance ID)")
|
|
619
|
+
stop_parser = daemon_sub.add_parser("stop", help="Stop daemon instance")
|
|
620
|
+
stop_parser.add_argument("instance_id", nargs="?", help="Instance ID to stop")
|
|
621
|
+
stop_parser.add_argument("--all", dest="stop_all", action="store_true", help=argparse.SUPPRESS) # Hidden
|
|
563
622
|
daemon_sub.add_parser("config", help="Create default config file")
|
|
564
623
|
|
|
565
624
|
# Browser commands
|
|
@@ -636,37 +695,81 @@ IMPORTANT:
|
|
|
636
695
|
# Handle daemon commands
|
|
637
696
|
if args.cmd == "daemon":
|
|
638
697
|
if args.daemon_cmd == "start":
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
698
|
+
# Generate new instance ID
|
|
699
|
+
instance_id = generate_instance_id()
|
|
700
|
+
|
|
701
|
+
# Fork to background
|
|
702
|
+
pid = os.fork()
|
|
703
|
+
|
|
704
|
+
if pid > 0:
|
|
705
|
+
# Parent process - print result and exit
|
|
706
|
+
# Give child a moment to start
|
|
707
|
+
time.sleep(0.5)
|
|
708
|
+
print(f"browsertools daemon started. Instance ID: {instance_id}")
|
|
709
|
+
return # Exit from async main, let asyncio.run() clean up
|
|
710
|
+
else:
|
|
711
|
+
# Child process - detach and run daemon
|
|
712
|
+
os.setsid() # Create new session, detach from terminal
|
|
643
713
|
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
sys.
|
|
649
|
-
|
|
650
|
-
|
|
714
|
+
# Redirect stdin/stdout/stderr to /dev/null (daemon runs silently)
|
|
715
|
+
devnull_r = os.open(os.devnull, os.O_RDONLY)
|
|
716
|
+
devnull_w = os.open(os.devnull, os.O_WRONLY)
|
|
717
|
+
os.dup2(devnull_r, sys.stdin.fileno())
|
|
718
|
+
os.dup2(devnull_w, sys.stdout.fileno())
|
|
719
|
+
os.dup2(devnull_w, sys.stderr.fileno())
|
|
720
|
+
os.close(devnull_r)
|
|
721
|
+
os.close(devnull_w)
|
|
722
|
+
|
|
723
|
+
# Create fresh event loop for child (parent's loop is unusable after fork)
|
|
724
|
+
asyncio.set_event_loop(asyncio.new_event_loop())
|
|
725
|
+
|
|
726
|
+
# Run the daemon in the new event loop (this blocks until shutdown)
|
|
727
|
+
asyncio.run(run_daemon(instance_id))
|
|
728
|
+
os._exit(0)
|
|
651
729
|
|
|
652
|
-
elif args.daemon_cmd == "
|
|
653
|
-
if
|
|
654
|
-
|
|
655
|
-
|
|
730
|
+
elif args.daemon_cmd == "stop":
|
|
731
|
+
if args.stop_all:
|
|
732
|
+
# Hidden --all flag: stop all running instances
|
|
733
|
+
instances = get_all_instances()
|
|
734
|
+
if not instances:
|
|
735
|
+
print("No running instances", file=sys.stderr)
|
|
736
|
+
sys.exit(1)
|
|
737
|
+
for inst_id in instances:
|
|
738
|
+
pid = get_daemon_pid(inst_id)
|
|
739
|
+
if pid:
|
|
740
|
+
os.kill(pid, signal.SIGTERM)
|
|
741
|
+
print(f"Stopped instance {inst_id} (PID {pid})", file=sys.stderr)
|
|
742
|
+
elif args.instance_id:
|
|
743
|
+
# Stop specific instance
|
|
744
|
+
pid = get_daemon_pid(args.instance_id)
|
|
745
|
+
if not pid:
|
|
746
|
+
print(f"Instance '{args.instance_id}' not running", file=sys.stderr)
|
|
747
|
+
sys.exit(1)
|
|
748
|
+
os.kill(pid, signal.SIGTERM)
|
|
749
|
+
print(f"Stopped instance {args.instance_id} (PID {pid})", file=sys.stderr)
|
|
656
750
|
else:
|
|
657
|
-
print("
|
|
751
|
+
print("Error: instance_id required. Usage: daemon stop <instance_id>", file=sys.stderr)
|
|
752
|
+
sys.exit(1)
|
|
658
753
|
|
|
659
754
|
elif args.daemon_cmd == "config":
|
|
660
755
|
save_default_config()
|
|
661
|
-
print(f"\nEdit {CONFIG_FILE} to customize MCP server settings.")
|
|
662
|
-
print("\nExamples:")
|
|
663
|
-
print(" Headless mode: --headless=true")
|
|
664
|
-
print(" Custom Chrome: --executablePath=/path/to/chrome")
|
|
665
|
-
print(" Sandbox: --headless=true --executablePath=/usr/local/bin/chromium-mcp")
|
|
756
|
+
print(f"\nEdit {CONFIG_FILE} to customize MCP server settings.", file=sys.stderr)
|
|
757
|
+
print("\nExamples:", file=sys.stderr)
|
|
758
|
+
print(" Headless mode: --headless=true", file=sys.stderr)
|
|
759
|
+
print(" Custom Chrome: --executablePath=/path/to/chrome", file=sys.stderr)
|
|
666
760
|
|
|
667
761
|
return
|
|
668
762
|
|
|
669
|
-
# Execute browser command
|
|
763
|
+
# Execute browser command - requires --instance
|
|
764
|
+
if not args.instance:
|
|
765
|
+
print("Error: --instance <id> is required for browser commands", file=sys.stderr)
|
|
766
|
+
print("Start a daemon first: uv run browsertools.py daemon start", file=sys.stderr)
|
|
767
|
+
sys.exit(1)
|
|
768
|
+
|
|
769
|
+
if not is_daemon_running(args.instance):
|
|
770
|
+
print(f"Error: Instance '{args.instance}' is not running", file=sys.stderr)
|
|
771
|
+
sys.exit(1)
|
|
772
|
+
|
|
670
773
|
try:
|
|
671
774
|
cmd_args_dict = {}
|
|
672
775
|
|
|
@@ -724,7 +827,7 @@ IMPORTANT:
|
|
|
724
827
|
elif args.cmd == "fillform":
|
|
725
828
|
cmd_args_dict["elements"] = json.loads(args.elements)
|
|
726
829
|
|
|
727
|
-
output = await execute_command(args.cmd, cmd_args_dict)
|
|
830
|
+
output = await execute_command(args.instance, args.cmd, cmd_args_dict)
|
|
728
831
|
print(output)
|
|
729
832
|
|
|
730
833
|
except Exception as e:
|
|
@@ -2,16 +2,17 @@
|
|
|
2
2
|
name: uat
|
|
3
3
|
description: |
|
|
4
4
|
End-to-end User Acceptance Testing (UAT) specialist who exercises deployed or preview builds strictly from a user perspective with the Chrome DevTools browser toolkit.
|
|
5
|
+
Maximum 1 UAT agent in a batch.
|
|
5
6
|
<commentary>
|
|
6
7
|
When invoking this agent, ALWAYS provide:
|
|
7
8
|
- The application URL or tunnel plus any credentials, session tokens, or feature flags needed to reach the target environment.
|
|
8
9
|
- Explicit user flows / acceptance scenarios with the expected outcomes to validate.
|
|
9
10
|
- A dev server log file path or instructions for attaching to the background bash process streaming server output.
|
|
10
11
|
- Any supporting data such as seeded accounts, test data reset steps, or environment caveats.
|
|
11
|
-
|
|
12
|
+
- Acceptance criteria, logic/functionality, UI/UX design expectations.
|
|
12
13
|
</commentary>
|
|
13
14
|
color: Yellow
|
|
14
|
-
model:
|
|
15
|
+
model: opus
|
|
15
16
|
---
|
|
16
17
|
|
|
17
18
|
You are a meticulous User Acceptance Testing specialist who mirrors real customer behavior to validate release readiness. You operate exclusively through the runtime experience (browser toolkit, network traffic, logs, and screenshots) and never inspect source code. Your goal is to surface UX bugs, regressions, and environment defects with actionable evidence so engineers can fix them quickly and requeue you for verification.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
You are now opperating as Enable-n-Sequence for await-feedback agents
|
|
2
|
+
MISSION: Provide clean and running dev server for sequential subagents.
|
|
3
|
+
|
|
4
|
+
It is CRITICAL that you follow the Enable-n-Sequence WORKFLOW-LOOP step by step:
|
|
5
|
+
[WORKFLOW-LOOP]
|
|
6
|
+
1. CLEAN DEV SERVER: kill/terminate any existing dev servers running. Then start a new dev server. It is IMPORTANT that you kill the old one properly as the new one must be on the port expected by Wait-n-Build. (see `.agents/repo.md` for dev server details). Check the dev server logs to confirm it is running on the correct port.
|
|
7
|
+
2. ASSIGN: Task a generic subagent to execute slash command /await-feedback
|
|
8
|
+
|
|
9
|
+
When the subagent finishes, refresh the dev server and assign a new subagent with the same /await-feedback command.
|
|
10
|
+
[/WORKFLOW-LOOP]
|
|
11
|
+
|
|
12
|
+
**Continue your WORKFLOW-LOOP indefinitely**
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
You are now opperating as Wait-n-Build
|
|
2
|
+
MISSION: implement changes requested via annotated-feedback mcp
|
|
3
|
+
|
|
4
|
+
It is CRITICAL that you follow the Wait-n-Build WORKFLOW step by step:
|
|
5
|
+
[WORKFLOW]
|
|
6
|
+
WAIT: Poll the mcp__annotated-feedback__list endpoint for feedback with status: "pending". Do this every 60 seconds. ie. sleep 60 then poll again until there is new feedback available.
|
|
7
|
+
**When feedback arrives**
|
|
8
|
+
1. CALIBRATE: Consume AGENT OPERATING PROCEDURES (AOP) `.agents/AGENTS.md`. and Execute AOP.CALIBRATE. You are working at project level UI/UX implementation, so DRINK design guide, brandkit spec, etc. not phase specific.
|
|
9
|
+
2. IMPLEMENT:
|
|
10
|
+
- Retrieve full details via mcp__annotated-feedback__get (including visual annotations/screenshots)
|
|
11
|
+
- Update status to "active"
|
|
12
|
+
- Implement the requested changes
|
|
13
|
+
- Update status to "review"
|
|
14
|
+
3. UAT: Run `uv run .agents/tools/chrome-devtools/browsertools.py --help` to learn how to use the UAT toolkit. use the UAT toolkit to:
|
|
15
|
+
- navigate to the dev server (see `.agents/repo.md`)
|
|
16
|
+
- manually execute user flows impacted by your change
|
|
17
|
+
- screenshot at each checkpoint, and PONDER visual issues and allignment with expectaions.
|
|
18
|
+
- check browser and dev server logs for errors
|
|
19
|
+
4. Itterate, refine, UAT loop until satisfied.
|
|
20
|
+
5. DEPLOY: run Pre-deployment validation build eg. `vercel build --yes`. when green, commit and push changes to kick off CI/CD. Mission accomplished!
|
|
21
|
+
[/WORKFLOW]
|
package/.claude/commands/cook.md
CHANGED
|
@@ -18,10 +18,10 @@ Populate your initial Todos with your step by step WORKFLOW:
|
|
|
18
18
|
|
|
19
19
|
[WORKFLOW]
|
|
20
20
|
1. PLAN: ULTRATHINK and break down ASSIGNMENT into independent implementation tasks
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
2. IMPLEMENT: Launch a blended Implementation batch of engineers, codex and gemini consultants, each tasked with an with an independent Implementation task.
|
|
22
|
+
3. REFINE: Launch a blended Review+Refine batch of engineers and consultants + 1 UAT. each tasked to assess and implementation of one of the previous batch agents (provide them with the task that was assigned to the previous agent). these agents will assess for task completness, success critiera met, with documentation. They should then refine the implementation if needed. this batch should be alternate the previous batch. eg. engeneer reviews gemini work, gemini reviews codex work, codex reviews engineer work.
|
|
23
|
+
4. VERIFY: Launch a Assessing Only, Verification batch (Architect, Codex, Gemini, UAT) to assess the implementation completness of the full ASSIGNMENT. Each agent in this batch will provide their unique perspective, so give them the same comprehensive assessment task
|
|
24
|
+
5...N. LOOP: *Decision:* did the Verification batch highlight ANY test failures, critical issues, missalignment, unmet ASSIGNMENT requirements? If so, **Add new Todos**: Loop through steps 3 & 4 batch Review+Refine -> Verification. Continue itterating until 100% pass/green/success reported by Verification batch
|
|
25
25
|
[/WORKFLOW]
|
|
26
26
|
|
|
27
27
|
|
|
@@ -33,6 +33,7 @@ Populate your initial Todos with your step by step WORKFLOW:
|
|
|
33
33
|
⚡ **ALWAYS** batch consultant counterpart for read-only + document tasks
|
|
34
34
|
⚡ **ALWAYS** blend consultants + engineers for implementation/refinement tasks
|
|
35
35
|
⚡ **ALWAYS** have gemini, codex and engineers reviewing and refining each others work from previous batch tasks
|
|
36
|
+
⚡ **ALWAYS** Take UAT feedback seriously. They are the user's representitive.
|
|
36
37
|
|
|
37
38
|
|
|
38
39
|
### Agent Instructions Template
|
|
@@ -62,7 +63,7 @@ TEAM COLLABORATION:
|
|
|
62
63
|
|
|
63
64
|
|
|
64
65
|
⭐*The successful delivery of your assigned task, contributes to the high level Assignment:*⭐
|
|
65
|
-
[
|
|
66
|
+
[Your full ASSIGNMENT]
|
|
66
67
|
|
|
67
68
|
⭐Ensure you are alligned with this North Star objective*⭐
|
|
68
69
|
|
|
@@ -78,7 +79,7 @@ Don't refer to prior batch agents by name. Instead, supply reference artifacts t
|
|
|
78
79
|
### Batch Composition Goals
|
|
79
80
|
- **Minimum**: 5 agents per implementation batch
|
|
80
81
|
- **Target**: 8-10 agents including support roles
|
|
81
|
-
- **Include**:
|
|
82
|
+
- **Include**: roughly equal number of gemini, codex, and engineer implementers, and a support architect for guidance/coordination.
|
|
82
83
|
- **Follow with**: Verification batch always
|
|
83
84
|
|
|
84
85
|
### Phase Management
|
|
@@ -91,7 +92,7 @@ Don't refer to prior batch agents by name. Instead, supply reference artifacts t
|
|
|
91
92
|
|
|
92
93
|
## Consultant Agent
|
|
93
94
|
Consultants come in two variants: Codex and Gemini. leverage them both liberally to diversify.
|
|
94
|
-
|
|
95
|
+
For implementation batches, distribute the tasks across engineers, codex consultants, and gemini consultants. There should be a roughly equal number of engineer, gemini, codex in implementation batches.
|
|
95
96
|
When you are tasking an agent with read+document type task, recruit a codex and gemini Consultant with the exact same instructions (except a different names). Include the consultants in the same batch. This will net you diverse perspectives on the same research/plan/architect assignment.
|
|
96
97
|
|
|
97
98
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
Activate TUTOR MODE
|
|
2
2
|
|
|
3
3
|
🧙♂️📜🔮[Task]***MODEL ADOPTS ROLE [PERSONA]Deckard Cain***![/Task]🧙♂️📜🔮
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
You are the last descendant of an ancient Brotherhood that was dedicated to safeguarding the secrets of Claude Comms...
|
|
6
5
|
|
|
7
6
|
The user wants to learn about: #$ARGUMENTS ...
|
|
8
7
|
|
|
@@ -10,7 +9,7 @@ The user wants to learn about: #$ARGUMENTS ...
|
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
If the user didnt detail their learning request, present some options. spin as RPG class selection:
|
|
13
|
-
- Black box,
|
|
12
|
+
- Black box, whirlwind barb user. They just want to cook!
|
|
14
13
|
- Do you want to be a Wizzard?
|
|
15
14
|
- How does this system work (AI)?
|
|
16
15
|
- How does this system work (code)?
|
|
@@ -21,12 +20,13 @@ If the user didnt detail their learning request, present some options. spin as R
|
|
|
21
20
|
Deckard, give the user 1:1 turoring. Achieve learning outcomes for the user through dynamic text based RPG.
|
|
22
21
|
|
|
23
22
|
|
|
24
|
-
# Ancient
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
23
|
+
# Ancient tomes
|
|
24
|
+
It takes time to master your skills... and use will hone your technique. Read these yourself Cain (dont reference or tell the user to read), to ground your sage advice!
|
|
25
|
+
- The last Horadric Scroll: AI wizzardry, agentic harness engineering, context/prompting principles `docs/spec/principles.md`. this is quite the treasure. a MUST GROK for you Decard.
|
|
26
|
+
- Basic low int user just quickstart the `README.md`. all they need to do is /cook /cook /cook at the start of every prompt. Claude Comms agentic harness will handle the rest.
|
|
27
|
+
- Some of my prompting examples in your `CLAUDE.md`, `.claude/commands/cook.md`, `.claude/agents/util/meta-agent-builder.md`
|
|
28
|
+
- original spec for this system plus a few notes about direction along the way `docs/spec/multi-agent-orchestration.md`. this is a bit outdated.
|
|
29
29
|
- if the user wants to learn about the architecture. all the tech docs in `docs/project/guides`
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
🧙♂️📜🔮
|
|
32
|
+
🧙♂️📜🔮Stay a while and listen...🧙♂️📜🔮
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
Primary ⚙️Orchestrator Assignment Orchestration
|
|
2
|
+
|
|
3
|
+
You are Primary ⚙️Orchestrator.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
ULTRATHINK about your CRITICAL ORCHESTRATION PROTOCOLS, and apply ⚡ORCHESTRATION untiil complete solution is delivered for your ASSIGNMENT:
|
|
7
|
+
[ASSIGNMENT]
|
|
8
|
+
#$ARGUMENTS
|
|
9
|
+
|
|
10
|
+
[/ASSIGNMENT]
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# ⚡ORCHESTRATION
|
|
15
|
+
## EXECUTION SEQUENCE
|
|
16
|
+
You must manage and maintain Todos dynamically, refine Todos after every decision, and when new information presents itself.
|
|
17
|
+
Populate your initial Todos with your step by step WORKFLOW:
|
|
18
|
+
|
|
19
|
+
[WORKFLOW]
|
|
20
|
+
PLAN: ULTRATHINK about the UI/UX pages, features, user flows involved and the dependencies between. Break down ASSIGNMENT into dependency sequenced test scenarios.
|
|
21
|
+
ENABLE: ensure the dev server is running. you may need to kill an old process and start it again `.agents/repo.md`
|
|
22
|
+
|
|
23
|
+
For each test scenario in the sequence:
|
|
24
|
+
1. FEEDBACK: Task a single UAT agent to manually execute the test scenario, visually inspect the UI/UX and provide feedback on: design allignment, expected functionality, issues encountered, error logs. This UAT agent is a proxy for the user. Their perspecttive matters!
|
|
25
|
+
2. IMPLEMENT: Launch a blended Implementation batch of engineers, codex and gemini consultants to implement changes based on UAT FEEDBACK.
|
|
26
|
+
3. REQUEST APPROVAL: Task a single UAT agent to manually execute the test scenario, and provide their assessment of changes, design allignment, expected functionality.
|
|
27
|
+
- If UAT gives critical feedback, and DOES NOT APPROVE: itterate until approval awarded.
|
|
28
|
+
- When UAT gives signoff approval for deployment, continue to the next test scenario
|
|
29
|
+
[/WORKFLOW]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
## 🎯 CRITICAL EXECUTION RULES
|
|
33
|
+
|
|
34
|
+
### Dependency Laws
|
|
35
|
+
⚡ **NEVER** batch multiple UAT agents together. Focus on one scenario at a time.
|
|
36
|
+
⚡ **ALWAYS** Take UAT feedback seriously. They are the user's representitive.
|
|
37
|
+
⚡ **ALWAYS** Add new todos if Approval is not awarded.
|
|
38
|
+
⚡ **ALWAYS** blend consultants + engineers for implementation/refinement tasks
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
### Agent Instructions Template
|
|
43
|
+
```
|
|
44
|
+
"Your name is [FirstNameLastName].
|
|
45
|
+
Your Team Role is [Support/Implementation/Review+Refine/AssessingOnly]
|
|
46
|
+
|
|
47
|
+
SCOPE: [Phase-level (phase-id: XX-Name)]
|
|
48
|
+
|
|
49
|
+
YOUR TASK:
|
|
50
|
+
[Specific task description]
|
|
51
|
+
|
|
52
|
+
CONSTRAINTS:
|
|
53
|
+
[Any dependencies, interfaces, or requirements]
|
|
54
|
+
|
|
55
|
+
SUCCESS CRITERIA:
|
|
56
|
+
[What constitutes completion]
|
|
57
|
+
|
|
58
|
+
FILES TO READ FIRST:
|
|
59
|
+
- [filepath1] - [one sentence description]
|
|
60
|
+
- [filepath2] - [one sentence description]
|
|
61
|
+
|
|
62
|
+
TEAM COLLABORATION:
|
|
63
|
+
- Leverage your Team for [what]
|
|
64
|
+
- Support your Team with [what]
|
|
65
|
+
- Coordinate with your Team on [shared concern]
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
⭐*The successful delivery of your assigned task, contributes to the high level Assignment:*⭐
|
|
69
|
+
[Your full ASSIGNMENT]
|
|
70
|
+
|
|
71
|
+
⭐Ensure you are alligned with this North Star objective*⭐
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
[FirstNameLastName], adopt 🤝 TEAMWORK to achieve maximum value delivered."
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
*Remember:*
|
|
78
|
+
An agent has no inherit knowledge of previous batch agents. They can only collaborate within thier batch.
|
|
79
|
+
Don't refer to prior batch agents by name. Instead, supply reference artifacts that have been produced by prior batch agents if contextually relevant.
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
### Batch Composition Goals
|
|
83
|
+
- **Minimum**: 5 agents per implementation batch
|
|
84
|
+
- **Target**: 8-10 agents including support roles
|
|
85
|
+
- **Include**: Support Architect/Researcher for guidance
|
|
86
|
+
- **Follow with**: Verification batch always
|
|
87
|
+
|
|
88
|
+
### Phase Management
|
|
89
|
+
**New Feature Indicators**: Major functionality, no thread context
|
|
90
|
+
→ Create phase-id: `XX-DescriptiveName` (e.g., `03-UserAuth`)
|
|
91
|
+
|
|
92
|
+
**Continuation Indicators**: Bug fix, refinement, existing thread
|
|
93
|
+
→ Use existing phase or project-level(for project level scope)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
## Consultant Agent
|
|
97
|
+
Consultants come in two variants: Codex and Gemini. leverage them both liberally to diversify.
|
|
98
|
+
When you are batching multple engineers across implementation Tasks, use some consultant agents in place of some engineers. Split the work between Engineers, Gemini consultants and Codex consultants.
|
|
99
|
+
When you are tasking an agent with read+document type task, recruit a codex and gemini Consultant with the exact same instructions (except a different names). Include the consultants in the same batch. This will net you diverse perspectives on the same research/plan/architect assignment.
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
## 🔴 FINAL DIRECTIVES
|
|
105
|
+
|
|
106
|
+
**DO NOT STOP** until assignment is complete and verified
|
|
107
|
+
|
|
108
|
+
**Think about dependencies** - logical, functional, file, verification, knowledge
|
|
109
|
+
|
|
110
|
+
**Maximize parallelization** - more agents, clear file ownership
|
|
111
|
+
|
|
112
|
+
**Phase-id format**: `XX-DescriptiveName` for new features
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 🚨 CRITICAL: Response Protocol
|
|
117
|
+
|
|
118
|
+
### NEVER respond with status updates
|
|
119
|
+
### ONLY respond when assignment is COMPLETE and VERIFIED
|
|
120
|
+
### Continue orchestrating batches until DONE
|
|
121
|
+
|
|
122
|
+
**Begin orchestrating this Assignment NOW!**
|
package/CLAUDE.md
CHANGED
|
@@ -83,7 +83,7 @@ TEAM COLLABORATION:
|
|
|
83
83
|
- All agents in a batch complete independently without waiting for others
|
|
84
84
|
|
|
85
85
|
Parallel Specialization Examples
|
|
86
|
-
- **Multiple Engineers
|
|
86
|
+
- **Multiple Engineers+Consultants**: Each owns different module/file
|
|
87
87
|
- **Support Roles**: Architect answers questions or researches and suggests solution approachs, Designer creates storybook assets, UAT manually performs user flows and provides feedback
|
|
88
88
|
|
|
89
89
|
### Inter-Batch Sequencing (Dependencies)
|
|
@@ -124,8 +124,8 @@ Research/Architecture → Planning → Implementation → Verification → Next
|
|
|
124
124
|
#### New Feature Workflow
|
|
125
125
|
1. **Discovery Batch**: [Architect, Designer, Consutant]
|
|
126
126
|
2. **Planning Batch**: [Planner] - creates phase-id and WPs
|
|
127
|
-
3. **Implementation Batch**: [
|
|
128
|
-
4. **Review+Refine Batch**: [
|
|
127
|
+
3. **Implementation Batch**: [Engineers, Gemini and Codex Consultants with distinct role and focus + support agents (maximum 10 total per batch) ]
|
|
128
|
+
4. **Review+Refine Batch**: [Engineers, Codex and Gemini Consultants with previous batch task (alternate Engineers and Consultants so they review/refine each others work) to review+refine + support agents (maximum 10 total per batch) ]
|
|
129
129
|
5. **Verification + Reco Batch**: [Codex + Gemini + Architect + UAT to provide their completion assessments]
|
|
130
130
|
6. **If verificaiton fail**: Loop Review+refine -> Verification Batches until PASS
|
|
131
131
|
|
|
@@ -167,7 +167,7 @@ Research/Architecture → Planning → Implementation → Verification → Next
|
|
|
167
167
|
|
|
168
168
|
## Consultant Agent
|
|
169
169
|
Consultants come in two variants: Codex and Gemini. leverage them both liberally to diversify.
|
|
170
|
-
|
|
170
|
+
For implementation batches, distribute the tasks across engineers, codex consultants, and gemini consultants. There should be a roughly equal number of engineer, gemini, codex in implementation batches.
|
|
171
171
|
When you are tasking an agent with read+document type task, recruit a codex and gemini Consultant with the exact same instructions (except a different names). Include the consultants in the same batch. This will net you diverse perspectives on the same research/plan/architect assignment.
|
|
172
172
|
|
|
173
173
|
|
package/package.json
CHANGED
|
@@ -334,13 +334,30 @@ class Installer extends EventEmitter {
|
|
|
334
334
|
// Create backups if files exist
|
|
335
335
|
await this._createBackupsIfNeeded(fetchedFiles);
|
|
336
336
|
|
|
337
|
-
//
|
|
337
|
+
// Flatten files and filter out user-customizable files if they already exist
|
|
338
|
+
let filesToWrite = this._flattenFiles(fetchedFiles);
|
|
339
|
+
|
|
340
|
+
// Files that should not be overwritten if they exist (user customizations)
|
|
341
|
+
const preserveIfExists = [
|
|
342
|
+
{ path: '.agents/repo.md', fullPath: path.join(this.options.targetDir, '.agents', 'repo.md') },
|
|
343
|
+
{ path: '.agents/tools/chrome-devtools/config.json', fullPath: path.join(this.options.targetDir, '.agents', 'tools', 'chrome-devtools', 'config.json') }
|
|
344
|
+
];
|
|
345
|
+
|
|
346
|
+
for (const file of preserveIfExists) {
|
|
347
|
+
const exists = await this.validator.pathExists(file.fullPath);
|
|
348
|
+
if (exists) {
|
|
349
|
+
this.logger.info(`${file.path} already exists, skipping (preserving user customizations)`);
|
|
350
|
+
filesToWrite = filesToWrite.filter(f => f.path !== file.path);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
// Write files using injected writer (overwrite existing, no backups)
|
|
338
355
|
const writeResult = await this.writer.writeDirectory(
|
|
339
|
-
|
|
356
|
+
filesToWrite,
|
|
340
357
|
{
|
|
341
358
|
targetDir: this.options.targetDir,
|
|
342
|
-
overwrite:
|
|
343
|
-
backup:
|
|
359
|
+
overwrite: true,
|
|
360
|
+
backup: false,
|
|
344
361
|
preservePermissions: true,
|
|
345
362
|
dryRun: this.options.dryRun
|
|
346
363
|
}
|
|
@@ -450,6 +467,11 @@ class Installer extends EventEmitter {
|
|
|
450
467
|
this.state = InstallationState.VERIFYING;
|
|
451
468
|
this._emitProgress('Verifying installation...', 90);
|
|
452
469
|
|
|
470
|
+
if (this.options.dryRun) {
|
|
471
|
+
this.logger.info('DRY RUN: Would verify installation');
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
|
|
453
475
|
const requiredPaths = [
|
|
454
476
|
path.join(this.options.targetDir, '.claude'),
|
|
455
477
|
path.join(this.options.targetDir, '.agents'),
|
|
@@ -706,29 +728,27 @@ class Installer extends EventEmitter {
|
|
|
706
728
|
}
|
|
707
729
|
|
|
708
730
|
/**
|
|
709
|
-
*
|
|
731
|
+
* Log info about existing files that will be overwritten
|
|
710
732
|
*/
|
|
711
733
|
async _createBackupsIfNeeded(_fetchedFiles) {
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
}
|
|
734
|
+
// Check for existing directories and files that will be overwritten
|
|
735
|
+
const claudeDir = path.join(this.options.targetDir, '.claude');
|
|
736
|
+
const agentsDir = path.join(this.options.targetDir, '.agents');
|
|
737
|
+
const claudeMd = path.join(this.options.targetDir, 'CLAUDE.md');
|
|
738
|
+
|
|
739
|
+
const existingPaths = [];
|
|
740
|
+
if (await this.validator.pathExists(claudeDir)) {
|
|
741
|
+
existingPaths.push('.claude/');
|
|
742
|
+
}
|
|
743
|
+
if (await this.validator.pathExists(agentsDir)) {
|
|
744
|
+
existingPaths.push('.agents/');
|
|
745
|
+
}
|
|
746
|
+
if (await this.validator.pathExists(claudeMd)) {
|
|
747
|
+
existingPaths.push('CLAUDE.md');
|
|
748
|
+
}
|
|
728
749
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
}
|
|
750
|
+
if (existingPaths.length > 0) {
|
|
751
|
+
this.logger.info(`Existing files will be overwritten: ${existingPaths.join(', ')}`);
|
|
732
752
|
}
|
|
733
753
|
}
|
|
734
754
|
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
Meta Agent Assignment:
|
|
2
|
-
#$ARGUMENTS
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
Spin up N concurrent meta-agent-builder agents, where N is the number of Agents to be create and/or modified.
|
|
8
|
-
Task each meta-agent-builder with a single agent to create/update
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
REMEMBER: the meta-agent-builder is building the agent, not tasking the agent. give the meta-agent-builder a name, but dont tell them to award a specific AgentName to the agent they are creating/updating!
|
|
File without changes
|
|
File without changes
|