quadwork 1.6.1 → 1.6.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.
Files changed (76) hide show
  1. package/bridges/discord/discord_bridge.py +480 -0
  2. package/bridges/discord/requirements.txt +2 -0
  3. package/out/404.html +1 -1
  4. package/out/__next.__PAGE__.txt +1 -1
  5. package/out/__next._full.txt +1 -1
  6. package/out/__next._head.txt +1 -1
  7. package/out/__next._index.txt +1 -1
  8. package/out/__next._tree.txt +1 -1
  9. package/out/_not-found/__next._full.txt +1 -1
  10. package/out/_not-found/__next._head.txt +1 -1
  11. package/out/_not-found/__next._index.txt +1 -1
  12. package/out/_not-found/__next._not-found.__PAGE__.txt +1 -1
  13. package/out/_not-found/__next._not-found.txt +1 -1
  14. package/out/_not-found/__next._tree.txt +1 -1
  15. package/out/_not-found.html +1 -1
  16. package/out/_not-found.txt +1 -1
  17. package/out/app-shell/__next._full.txt +1 -1
  18. package/out/app-shell/__next._head.txt +1 -1
  19. package/out/app-shell/__next._index.txt +1 -1
  20. package/out/app-shell/__next._tree.txt +1 -1
  21. package/out/app-shell/__next.app-shell.__PAGE__.txt +1 -1
  22. package/out/app-shell/__next.app-shell.txt +1 -1
  23. package/out/app-shell.html +1 -1
  24. package/out/app-shell.txt +1 -1
  25. package/out/icon.svg +9 -0
  26. package/out/index.html +1 -1
  27. package/out/index.txt +1 -1
  28. package/out/project/_/__next._full.txt +1 -1
  29. package/out/project/_/__next._head.txt +1 -1
  30. package/out/project/_/__next._index.txt +1 -1
  31. package/out/project/_/__next._tree.txt +1 -1
  32. package/out/project/_/__next.project.$d$id.__PAGE__.txt +1 -1
  33. package/out/project/_/__next.project.$d$id.txt +1 -1
  34. package/out/project/_/__next.project.txt +1 -1
  35. package/out/project/_/memory/__next._full.txt +1 -1
  36. package/out/project/_/memory/__next._head.txt +1 -1
  37. package/out/project/_/memory/__next._index.txt +1 -1
  38. package/out/project/_/memory/__next._tree.txt +1 -1
  39. package/out/project/_/memory/__next.project.$d$id.memory.__PAGE__.txt +1 -1
  40. package/out/project/_/memory/__next.project.$d$id.memory.txt +1 -1
  41. package/out/project/_/memory/__next.project.$d$id.txt +1 -1
  42. package/out/project/_/memory/__next.project.txt +1 -1
  43. package/out/project/_/memory.html +1 -1
  44. package/out/project/_/memory.txt +1 -1
  45. package/out/project/_/queue/__next._full.txt +1 -1
  46. package/out/project/_/queue/__next._head.txt +1 -1
  47. package/out/project/_/queue/__next._index.txt +1 -1
  48. package/out/project/_/queue/__next._tree.txt +1 -1
  49. package/out/project/_/queue/__next.project.$d$id.queue.__PAGE__.txt +1 -1
  50. package/out/project/_/queue/__next.project.$d$id.queue.txt +1 -1
  51. package/out/project/_/queue/__next.project.$d$id.txt +1 -1
  52. package/out/project/_/queue/__next.project.txt +1 -1
  53. package/out/project/_/queue.html +1 -1
  54. package/out/project/_/queue.txt +1 -1
  55. package/out/project/_.html +1 -1
  56. package/out/project/_.txt +1 -1
  57. package/out/settings/__next._full.txt +1 -1
  58. package/out/settings/__next._head.txt +1 -1
  59. package/out/settings/__next._index.txt +1 -1
  60. package/out/settings/__next._tree.txt +1 -1
  61. package/out/settings/__next.settings.__PAGE__.txt +1 -1
  62. package/out/settings/__next.settings.txt +1 -1
  63. package/out/settings.html +1 -1
  64. package/out/settings.txt +1 -1
  65. package/out/setup/__next._full.txt +1 -1
  66. package/out/setup/__next._head.txt +1 -1
  67. package/out/setup/__next._index.txt +1 -1
  68. package/out/setup/__next._tree.txt +1 -1
  69. package/out/setup/__next.setup.__PAGE__.txt +1 -1
  70. package/out/setup/__next.setup.txt +1 -1
  71. package/out/setup.html +1 -1
  72. package/out/setup.txt +1 -1
  73. package/package.json +2 -1
  74. /package/out/_next/static/{BHDF9NWAl5FhHwuakKgwK → AQ0US7_Pm9gOOelb-ks5q}/_buildManifest.js +0 -0
  75. /package/out/_next/static/{BHDF9NWAl5FhHwuakKgwK → AQ0US7_Pm9gOOelb-ks5q}/_clientMiddlewareManifest.js +0 -0
  76. /package/out/_next/static/{BHDF9NWAl5FhHwuakKgwK → AQ0US7_Pm9gOOelb-ks5q}/_ssgManifest.js +0 -0
@@ -0,0 +1,480 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Discord ↔ AgentChattr bridge.
4
+
5
+ Bidirectional relay: messages from a Discord channel appear in
6
+ AgentChattr, and agent messages from AC appear in Discord.
7
+
8
+ Mirrors the Telegram bridge (agentchattr-telegram/telegram_bridge.py)
9
+ as closely as possible. Bundled inside the quadwork npm package at
10
+ bridges/discord/ instead of a separate repo.
11
+
12
+ Config: read from TOML [discord] section, env var overrides win.
13
+ """
14
+
15
+ import argparse
16
+ import asyncio
17
+ import atexit
18
+ import json
19
+ import logging
20
+ import os
21
+ import signal
22
+ import sys
23
+ import threading
24
+ import time
25
+ from pathlib import Path
26
+
27
+ try:
28
+ import tomllib # Python 3.11+
29
+ except ModuleNotFoundError:
30
+ try:
31
+ import tomli as tomllib # type: ignore[no-redef]
32
+ except ModuleNotFoundError:
33
+ tomllib = None # type: ignore[assignment]
34
+
35
+ import discord
36
+ import requests
37
+
38
+ log = logging.getLogger("discord-bridge")
39
+
40
+ # ---------------------------------------------------------------------------
41
+ # Config
42
+ # ---------------------------------------------------------------------------
43
+
44
+ DEFAULT_CONFIG = {
45
+ "bot_token": "",
46
+ "channel_id": "",
47
+ "agentchattr_url": "http://127.0.0.1:8300",
48
+ "poll_interval": 2,
49
+ "bridge_sender": "discord-bridge",
50
+ "cursor_file": "",
51
+ }
52
+
53
+ ENV_MAP = {
54
+ "DISCORD_BOT_TOKEN": "bot_token",
55
+ "DISCORD_CHANNEL_ID": "channel_id",
56
+ "AGENTCHATTR_URL": "agentchattr_url",
57
+ "CURSOR_FILE": "cursor_file",
58
+ }
59
+
60
+
61
+ def load_config(toml_path=None):
62
+ """Load config: defaults → TOML [discord] → env vars."""
63
+ cfg = dict(DEFAULT_CONFIG)
64
+
65
+ if toml_path and os.path.isfile(toml_path):
66
+ if tomllib is None:
67
+ log.warning("tomli not installed and Python < 3.11; skipping TOML config")
68
+ else:
69
+ with open(toml_path, "rb") as f:
70
+ data = tomllib.load(f)
71
+ section = data.get("discord", {})
72
+ for key in cfg:
73
+ if key in section:
74
+ cfg[key] = section[key]
75
+ # Resolve cursor_file relative to TOML directory
76
+ if cfg["cursor_file"] and not os.path.isabs(cfg["cursor_file"]):
77
+ cfg["cursor_file"] = os.path.join(
78
+ os.path.dirname(os.path.abspath(toml_path)),
79
+ cfg["cursor_file"],
80
+ )
81
+
82
+ # Env vars always override
83
+ for env_key, cfg_key in ENV_MAP.items():
84
+ val = os.environ.get(env_key)
85
+ if val:
86
+ cfg[cfg_key] = val
87
+
88
+ # bot_token may use "env:VAR" indirection (same as TG bridge)
89
+ if cfg["bot_token"].startswith("env:"):
90
+ env_name = cfg["bot_token"][4:]
91
+ cfg["bot_token"] = os.environ.get(env_name, "")
92
+
93
+ # channel_id must be an integer for discord.py comparisons
94
+ if cfg["channel_id"]:
95
+ cfg["channel_id"] = int(cfg["channel_id"])
96
+
97
+ return cfg
98
+
99
+
100
+ def validate_config(cfg):
101
+ """Raise on missing required fields."""
102
+ if not cfg["bot_token"]:
103
+ raise SystemExit("bot_token is required (TOML [discord] or DISCORD_BOT_TOKEN env)")
104
+ if not cfg["channel_id"]:
105
+ raise SystemExit("channel_id is required (TOML [discord] or DISCORD_CHANNEL_ID env)")
106
+
107
+
108
+ # ---------------------------------------------------------------------------
109
+ # Cursor persistence
110
+ # ---------------------------------------------------------------------------
111
+
112
+ _cursor = {"last_seen_id": 0}
113
+
114
+
115
+ def load_cursor(path):
116
+ """Load cursor from JSON file. Non-fatal on error."""
117
+ global _cursor
118
+ if not path or not os.path.isfile(path):
119
+ return
120
+ try:
121
+ with open(path) as f:
122
+ data = json.load(f)
123
+ if isinstance(data, dict) and "last_seen_id" in data:
124
+ _cursor["last_seen_id"] = int(data["last_seen_id"])
125
+ log.info("Loaded cursor: last_seen_id=%d", _cursor["last_seen_id"])
126
+ except Exception as exc:
127
+ log.warning("Failed to load cursor from %s: %s", path, exc)
128
+
129
+
130
+ def save_cursor(path):
131
+ """Save cursor to JSON file. Non-fatal on error."""
132
+ if not path:
133
+ return
134
+ try:
135
+ os.makedirs(os.path.dirname(path), exist_ok=True)
136
+ with open(path, "w") as f:
137
+ json.dump(_cursor, f)
138
+ except Exception as exc:
139
+ log.warning("Failed to save cursor to %s: %s", path, exc)
140
+
141
+
142
+ # ---------------------------------------------------------------------------
143
+ # AgentChattr registration + heartbeat
144
+ # ---------------------------------------------------------------------------
145
+
146
+ # Mutable dict so heartbeat thread sees re-registration updates.
147
+ # bridge_sender is set from cfg during main() so all callers can read it.
148
+ ac = {"token": "", "name": "", "bridge_sender": "discord-bridge", "known_names": set()}
149
+
150
+
151
+ def ac_register(url, base=None, label="Discord Bridge"):
152
+ """Register with AgentChattr. Returns {name, token} or raises."""
153
+ if base is None:
154
+ base = ac["bridge_sender"]
155
+ resp = requests.post(
156
+ f"{url}/api/register",
157
+ json={"base": base, "label": label},
158
+ timeout=10,
159
+ )
160
+ resp.raise_for_status()
161
+ data = resp.json()
162
+ ac["name"] = data["name"]
163
+ ac["token"] = data["token"]
164
+ ac["known_names"].add(data["name"])
165
+ log.info("Registered with AC as %s (known: %s)", ac["name"], ac["known_names"])
166
+ return data
167
+
168
+
169
+ def ac_deregister(url):
170
+ """Best-effort deregister from AC."""
171
+ if not ac["name"]:
172
+ return
173
+ try:
174
+ requests.post(
175
+ f"{url}/api/deregister/{ac['name']}",
176
+ headers={"Authorization": f"Bearer {ac['token']}"},
177
+ timeout=5,
178
+ )
179
+ log.info("Deregistered %s from AC", ac["name"])
180
+ except Exception:
181
+ pass
182
+
183
+
184
+ def _heartbeat_loop(url):
185
+ """Daemon thread: POST /api/heartbeat/{name} every 5s."""
186
+ while True:
187
+ name = ac["name"]
188
+ token = ac["token"]
189
+ if name:
190
+ try:
191
+ resp = requests.post(
192
+ f"{url}/api/heartbeat/{name}",
193
+ headers={"Authorization": f"Bearer {token}"} if token else {},
194
+ timeout=5,
195
+ )
196
+ if resp.status_code == 409:
197
+ # AC restarted — re-register
198
+ log.warning("Heartbeat 409 — AC restarted, re-registering")
199
+ try:
200
+ ac_register(url)
201
+ except Exception as exc:
202
+ log.error("Re-register failed: %s", exc)
203
+ except Exception:
204
+ pass
205
+ time.sleep(5)
206
+
207
+
208
+ def start_heartbeat(url):
209
+ """Start the heartbeat daemon thread."""
210
+ t = threading.Thread(target=_heartbeat_loop, args=(url,), daemon=True)
211
+ t.start()
212
+ return t
213
+
214
+
215
+ # ---------------------------------------------------------------------------
216
+ # AC → Discord polling
217
+ # ---------------------------------------------------------------------------
218
+
219
+ async def poll_ac_to_discord(cfg, channel):
220
+ """Poll AC for new messages and forward to Discord channel."""
221
+ url = cfg["agentchattr_url"]
222
+ bridge_sender = cfg["bridge_sender"]
223
+ interval = cfg["poll_interval"]
224
+
225
+ while True:
226
+ try:
227
+ # Drain all available messages before sleeping. When AC
228
+ # returns a full batch (limit messages), immediately
229
+ # re-fetch with the updated cursor to avoid dropping
230
+ # overflow under high volume.
231
+ while True:
232
+ params = {"limit": 50}
233
+ if _cursor["last_seen_id"]:
234
+ params["since_id"] = _cursor["last_seen_id"]
235
+ headers = {}
236
+ if ac["token"]:
237
+ headers["Authorization"] = f"Bearer {ac['token']}"
238
+
239
+ resp = requests.get(
240
+ f"{url}/api/messages",
241
+ params=params,
242
+ headers=headers,
243
+ timeout=10,
244
+ )
245
+
246
+ if resp.status_code in (401, 403):
247
+ log.warning("AC poll %d — re-registering", resp.status_code)
248
+ try:
249
+ ac_register(url)
250
+ except Exception as exc:
251
+ log.error("Re-register failed: %s", exc)
252
+ break
253
+
254
+ resp.raise_for_status()
255
+ messages = resp.json()
256
+
257
+ if not isinstance(messages, list):
258
+ break
259
+
260
+ for msg in messages:
261
+ msg_id = msg.get("id", 0)
262
+ sender = msg.get("sender", "")
263
+ text = msg.get("text", "")
264
+
265
+ # Echo prevention: skip our own messages (any name
266
+ # the bridge has ever registered as this session)
267
+ if sender in ac["known_names"] or sender == bridge_sender:
268
+ if msg_id > _cursor["last_seen_id"]:
269
+ _cursor["last_seen_id"] = msg_id
270
+ continue
271
+
272
+ # Skip system auto-recovery messages
273
+ if sender == "system":
274
+ if msg_id > _cursor["last_seen_id"]:
275
+ _cursor["last_seen_id"] = msg_id
276
+ continue
277
+
278
+ if not text:
279
+ if msg_id > _cursor["last_seen_id"]:
280
+ _cursor["last_seen_id"] = msg_id
281
+ continue
282
+
283
+ # Forward to Discord
284
+ try:
285
+ discord_text = f"**{sender}**: {text}"
286
+ # Discord message limit is 2000 chars
287
+ if len(discord_text) > 2000:
288
+ discord_text = discord_text[:1997] + "..."
289
+ await channel.send(discord_text)
290
+ except Exception as exc:
291
+ log.error("Failed to send to Discord: %s", exc)
292
+
293
+ if msg_id > _cursor["last_seen_id"]:
294
+ _cursor["last_seen_id"] = msg_id
295
+
296
+ # Persist cursor after each page
297
+ save_cursor(cfg["cursor_file"])
298
+
299
+ # If we got a full batch, there may be more — drain immediately
300
+ if len(messages) >= 50:
301
+ continue
302
+ break
303
+
304
+ except requests.RequestException as exc:
305
+ log.warning("AC poll error: %s", exc)
306
+ except Exception as exc:
307
+ log.error("Unexpected AC poll error: %s", exc)
308
+
309
+ await asyncio.sleep(interval)
310
+
311
+
312
+ # ---------------------------------------------------------------------------
313
+ # Discord → AC path
314
+ # ---------------------------------------------------------------------------
315
+
316
+ def send_to_ac(cfg, text, channel_name="general"):
317
+ """Forward a message from Discord to AgentChattr."""
318
+ url = cfg["agentchattr_url"]
319
+ headers = {}
320
+ if ac["token"]:
321
+ headers["Authorization"] = f"Bearer {ac['token']}"
322
+
323
+ try:
324
+ resp = requests.post(
325
+ f"{url}/api/send",
326
+ json={
327
+ "text": text,
328
+ "channel": channel_name,
329
+ "sender": cfg["bridge_sender"],
330
+ },
331
+ headers=headers,
332
+ timeout=10,
333
+ )
334
+ if resp.status_code in (401, 403):
335
+ log.warning("AC send %d — re-registering", resp.status_code)
336
+ ac_register(url)
337
+ # Retry once after re-register
338
+ headers["Authorization"] = f"Bearer {ac['token']}"
339
+ resp = requests.post(
340
+ f"{url}/api/send",
341
+ json={
342
+ "text": text,
343
+ "channel": channel_name,
344
+ "sender": cfg["bridge_sender"],
345
+ },
346
+ headers=headers,
347
+ timeout=10,
348
+ )
349
+ resp.raise_for_status()
350
+ except requests.RequestException as exc:
351
+ log.error("Failed to send to AC: %s", exc)
352
+
353
+
354
+ # ---------------------------------------------------------------------------
355
+ # Discord client
356
+ # ---------------------------------------------------------------------------
357
+
358
+ def create_client(cfg):
359
+ """Create and configure the Discord client."""
360
+ intents = discord.Intents.default()
361
+ intents.message_content = True # Privileged — must be enabled in Developer Portal
362
+ client = discord.Client(intents=intents)
363
+ target_channel_id = cfg["channel_id"]
364
+
365
+ @client.event
366
+ async def on_ready():
367
+ log.info("Discord bot logged in as %s (id=%s)", client.user, client.user.id)
368
+ channel = client.get_channel(target_channel_id)
369
+ if not channel:
370
+ log.error(
371
+ "Cannot find channel %s — check channel_id and bot permissions",
372
+ target_channel_id,
373
+ )
374
+ return
375
+ log.info("Monitoring Discord channel: #%s (%s)", channel.name, channel.id)
376
+ # Start the AC → Discord poll loop
377
+ client.loop.create_task(poll_ac_to_discord(cfg, channel))
378
+
379
+ @client.event
380
+ async def on_message(message):
381
+ # Ignore own messages
382
+ if message.author == client.user:
383
+ return
384
+ # Ignore other bots
385
+ if message.author.bot:
386
+ return
387
+ # Only relay from the configured channel
388
+ if message.channel.id != target_channel_id:
389
+ return
390
+
391
+ text = message.content
392
+ if not text:
393
+ # Warn about missing MESSAGE_CONTENT intent
394
+ if not message.flags.value and not message.embeds and not message.attachments:
395
+ log.warning(
396
+ "Received message with empty content from %s — "
397
+ "MESSAGE_CONTENT intent may not be enabled in the Developer Portal",
398
+ message.author,
399
+ )
400
+ return
401
+
402
+ # Prefix with Discord username for attribution
403
+ ac_text = f"[discord:{message.author.display_name}] {text}"
404
+ log.debug("Discord → AC: %s", ac_text[:100])
405
+ send_to_ac(cfg, ac_text)
406
+
407
+ return client
408
+
409
+
410
+ # ---------------------------------------------------------------------------
411
+ # Shutdown
412
+ # ---------------------------------------------------------------------------
413
+
414
+ _shutdown_done = []
415
+
416
+
417
+ def shutdown(cfg):
418
+ """Graceful shutdown: deregister from AC, save cursor."""
419
+ if _shutdown_done:
420
+ return
421
+ _shutdown_done.append(True)
422
+ log.info("Shutting down...")
423
+ ac_deregister(cfg["agentchattr_url"])
424
+ save_cursor(cfg["cursor_file"])
425
+
426
+
427
+ # ---------------------------------------------------------------------------
428
+ # Main
429
+ # ---------------------------------------------------------------------------
430
+
431
+ def main():
432
+ parser = argparse.ArgumentParser(description="Discord ↔ AgentChattr bridge")
433
+ parser.add_argument(
434
+ "-c", "--config",
435
+ help="Path to TOML config file (reads [discord] section)",
436
+ )
437
+ parser.add_argument(
438
+ "-v", "--verbose",
439
+ action="store_true",
440
+ help="Enable debug logging",
441
+ )
442
+ args = parser.parse_args()
443
+
444
+ logging.basicConfig(
445
+ level=logging.DEBUG if args.verbose else logging.INFO,
446
+ format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
447
+ )
448
+
449
+ cfg = load_config(args.config)
450
+ validate_config(cfg)
451
+
452
+ # Set bridge_sender so ac_register uses the configured base name
453
+ ac["bridge_sender"] = cfg["bridge_sender"]
454
+
455
+ # Load cursor
456
+ load_cursor(cfg["cursor_file"])
457
+
458
+ # Register with AgentChattr
459
+ try:
460
+ ac_register(cfg["agentchattr_url"])
461
+ except Exception as exc:
462
+ log.error("Initial AC registration failed: %s", exc)
463
+ log.info("Will retry on first message send")
464
+
465
+ # Start heartbeat
466
+ start_heartbeat(cfg["agentchattr_url"])
467
+
468
+ # Register shutdown handlers
469
+ atexit.register(shutdown, cfg)
470
+ for sig in (signal.SIGINT, signal.SIGTERM):
471
+ signal.signal(sig, lambda *_: (shutdown(cfg), sys.exit(0)))
472
+
473
+ # Start Discord client
474
+ client = create_client(cfg)
475
+ log.info("Starting Discord bridge (channel_id=%s)", cfg["channel_id"])
476
+ client.run(cfg["bot_token"], log_handler=None)
477
+
478
+
479
+ if __name__ == "__main__":
480
+ main()
@@ -0,0 +1,2 @@
1
+ discord.py>=2.3
2
+ requests>=2.28
package/out/404.html CHANGED
@@ -1 +1 @@
1
- <!DOCTYPE html><html lang="en" class="geist_mono_8d43a2aa-module__8Li5zG__variable h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/chunks/0j-zyy6.adwtl.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/0ze4gu236oq96.js"/><script src="/_next/static/chunks/0.bbxho1vnxin.js" async=""></script><script src="/_next/static/chunks/16g.ca89g7fib.js" async=""></script><script src="/_next/static/chunks/0zfotsowwll1x.js" async=""></script><script src="/_next/static/chunks/0pqt~8bl3ukh4.js" async=""></script><script src="/_next/static/chunks/turbopack-0lcwh84lrj9gi.js" async=""></script><script src="/_next/static/chunks/0o3_.p5ivp5sp.js" async=""></script><script src="/_next/static/chunks/0d3shmwh5_nmn.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><title>QuadWork</title><meta name="description" content="Unified dashboard for multi-agent coding teams"/><link rel="icon" href="/favicon.ico?favicon.0x3dzn~oxb6tn.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/03~yq9q893hmn.js" noModule=""></script></head><body class="h-full flex flex-col"><div hidden=""><!--$--><!--/$--></div><header class="sticky top-0 z-40 flex h-12 items-center justify-between border-b border-white/10 bg-neutral-950/90 px-4 backdrop-blur" aria-hidden="true"></header><div class="flex flex-1 min-h-0"><aside class="w-16 shrink-0 h-full border-r border-border bg-bg-surface flex flex-col items-center py-3"><a class="w-10 h-10 flex items-center justify-center rounded-sm transition-colors text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Home" href="/"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 10L10 3l7 7"></path><path d="M5 8.5V16h3.5v-4h3v4H15V8.5"></path></svg></a><div class="w-6 h-px bg-border my-2"></div><div class="flex-1 flex flex-col items-center gap-2 overflow-y-auto min-h-0"><a class="w-10 h-10 flex items-center justify-center rounded-full border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a] transition-colors" title="Add project" href="/setup"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 3v10M3 8h10"></path></svg></a></div><div class="w-6 h-px bg-border my-2"></div><a class="w-10 h-10 flex items-center justify-center rounded-sm transition-colors text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Settings" href="/settings"><svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="9" r="2.5"></circle><path d="M7.5 1.5h3l.4 2.1a5.5 5.5 0 011.3.7l2-.8 1.5 2.6-1.6 1.3a5.5 5.5 0 010 1.5l1.6 1.3-1.5 2.6-2-.8a5.5 5.5 0 01-1.3.7l-.4 2.1h-3l-.4-2.1a5.5 5.5 0 01-1.3-.7l-2 .8-1.5-2.6 1.6-1.3a5.5 5.5 0 010-1.5L2.3 6.1l1.5-2.6 2 .8a5.5 5.5 0 011.3-.7z"></path></svg></a></aside><main class="flex-1 min-w-0 overflow-auto"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--></main></div><script src="/_next/static/chunks/0ze4gu236oq96.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[43688,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n3:I[26704,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n4:I[22140,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n5:I[39756,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n6:I[37457,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n7:I[97367,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"OutletBoundary\"]\n8:\"$Sreact.suspense\"\nb:I[97367,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"ViewportBoundary\"]\nd:I[97367,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"MetadataBoundary\"]\nf:I[68027,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/0j-zyy6.adwtl.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"c\":[\"\",\"_not-found\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",16],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0j-zyy6.adwtl.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/0d3shmwh5_nmn.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"geist_mono_8d43a2aa-module__8Li5zG__variable h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"h-full flex flex-col\",\"children\":[[\"$\",\"$L2\",null,{}],[\"$\",\"$L3\",null,{}],[\"$\",\"div\",null,{\"className\":\"flex flex-1 min-h-0\",\"children\":[[\"$\",\"$L4\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 min-w-0 overflow-auto\",\"children\":[\"$\",\"$L5\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L6\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]]}]]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L5\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L6\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:2:props:children:1:props:children:props:notFound:0:1:props:style\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:2:props:children:1:props:children:props:notFound:0:1:props:children:props:children:1:props:style\",\"children\":404}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:2:props:children:1:props:children:props:notFound:0:1:props:children:props:children:2:props:style\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:2:props:children:1:props:children:props:notFound:0:1:props:children:props:children:2:props:children:props:style\",\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L7\",null,{\"children\":[\"$\",\"$8\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@9\"}]}]]}],{},null,false,null]},null,false,\"$@a\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[\"$\",\"$Lb\",null,{\"children\":\"$Lc\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Ld\",null,{\"children\":[\"$\",\"$8\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Le\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$f\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0j-zyy6.adwtl.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"BHDF9NWAl5FhHwuakKgwK\"}\n"])</script><script>self.__next_f.push([1,"10:[]\na:\"$W10\"\n"])</script><script>self.__next_f.push([1,"c:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"11:I[27201,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"IconMark\"]\n9:null\ne:[[\"$\",\"title\",\"0\",{\"children\":\"QuadWork\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Unified dashboard for multi-agent coding teams\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0x3dzn~oxb6tn.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$L11\",\"3\",{}]]\n"])</script></body></html>
1
+ <!DOCTYPE html><html lang="en" class="geist_mono_8d43a2aa-module__8Li5zG__variable h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="/_next/static/chunks/0j-zyy6.adwtl.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/0ze4gu236oq96.js"/><script src="/_next/static/chunks/0.bbxho1vnxin.js" async=""></script><script src="/_next/static/chunks/16g.ca89g7fib.js" async=""></script><script src="/_next/static/chunks/0zfotsowwll1x.js" async=""></script><script src="/_next/static/chunks/0pqt~8bl3ukh4.js" async=""></script><script src="/_next/static/chunks/turbopack-0lcwh84lrj9gi.js" async=""></script><script src="/_next/static/chunks/0o3_.p5ivp5sp.js" async=""></script><script src="/_next/static/chunks/0d3shmwh5_nmn.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><title>QuadWork</title><meta name="description" content="Unified dashboard for multi-agent coding teams"/><link rel="icon" href="/favicon.ico?favicon.0x3dzn~oxb6tn.ico" sizes="256x256" type="image/x-icon"/><script src="/_next/static/chunks/03~yq9q893hmn.js" noModule=""></script></head><body class="h-full flex flex-col"><div hidden=""><!--$--><!--/$--></div><header class="sticky top-0 z-40 flex h-12 items-center justify-between border-b border-white/10 bg-neutral-950/90 px-4 backdrop-blur" aria-hidden="true"></header><div class="flex flex-1 min-h-0"><aside class="w-16 shrink-0 h-full border-r border-border bg-bg-surface flex flex-col items-center py-3"><a class="w-10 h-10 flex items-center justify-center rounded-sm transition-colors text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Home" href="/"><svg width="20" height="20" viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 10L10 3l7 7"></path><path d="M5 8.5V16h3.5v-4h3v4H15V8.5"></path></svg></a><div class="w-6 h-px bg-border my-2"></div><div class="flex-1 flex flex-col items-center gap-2 overflow-y-auto min-h-0"><a class="w-10 h-10 flex items-center justify-center rounded-full border border-dashed border-border text-text-muted hover:text-text hover:bg-[#1a1a1a] transition-colors" title="Add project" href="/setup"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"><path d="M8 3v10M3 8h10"></path></svg></a></div><div class="w-6 h-px bg-border my-2"></div><a class="w-10 h-10 flex items-center justify-center rounded-sm transition-colors text-text-muted hover:text-text hover:bg-[#1a1a1a]" title="Settings" href="/settings"><svg width="18" height="18" viewBox="0 0 18 18" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="9" r="2.5"></circle><path d="M7.5 1.5h3l.4 2.1a5.5 5.5 0 011.3.7l2-.8 1.5 2.6-1.6 1.3a5.5 5.5 0 010 1.5l1.6 1.3-1.5 2.6-2-.8a5.5 5.5 0 01-1.3.7l-.4 2.1h-3l-.4-2.1a5.5 5.5 0 01-1.3-.7l-2 .8-1.5-2.6 1.6-1.3a5.5 5.5 0 010-1.5L2.3 6.1l1.5-2.6 2 .8a5.5 5.5 0 011.3-.7z"></path></svg></a></aside><main class="flex-1 min-w-0 overflow-auto"><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--></main></div><script src="/_next/static/chunks/0ze4gu236oq96.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[43688,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n3:I[26704,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n4:I[22140,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n5:I[39756,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n6:I[37457,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\"]\n7:I[97367,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"OutletBoundary\"]\n8:\"$Sreact.suspense\"\nb:I[97367,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"ViewportBoundary\"]\nd:I[97367,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"MetadataBoundary\"]\nf:I[68027,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"default\",1]\n:HL[\"/_next/static/chunks/0j-zyy6.adwtl.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"c\":[\"\",\"_not-found\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",16],[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0j-zyy6.adwtl.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-0\",{\"src\":\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"async\":true,\"nonce\":\"$undefined\"}],[\"$\",\"script\",\"script-1\",{\"src\":\"/_next/static/chunks/0d3shmwh5_nmn.js\",\"async\":true,\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"geist_mono_8d43a2aa-module__8Li5zG__variable h-full\",\"children\":[\"$\",\"body\",null,{\"className\":\"h-full flex flex-col\",\"children\":[[\"$\",\"$L2\",null,{}],[\"$\",\"$L3\",null,{}],[\"$\",\"div\",null,{\"className\":\"flex flex-1 min-h-0\",\"children\":[[\"$\",\"$L4\",null,{}],[\"$\",\"main\",null,{\"className\":\"flex-1 min-w-0 overflow-auto\",\"children\":[\"$\",\"$L5\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L6\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],[]],\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]]}]]}]}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L5\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L6\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:2:props:children:1:props:children:props:notFound:0:1:props:style\",\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:2:props:children:1:props:children:props:notFound:0:1:props:children:props:children:1:props:style\",\"children\":404}],[\"$\",\"div\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:2:props:children:1:props:children:props:notFound:0:1:props:children:props:children:2:props:style\",\"children\":[\"$\",\"h2\",null,{\"style\":\"$0:f:0:1:0:props:children:1:props:children:props:children:2:props:children:1:props:children:props:notFound:0:1:props:children:props:children:2:props:children:props:style\",\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L7\",null,{\"children\":[\"$\",\"$8\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@9\"}]}]]}],{},null,false,null]},null,false,\"$@a\"]},null,false,null],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[\"$\",\"$Lb\",null,{\"children\":\"$Lc\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$Ld\",null,{\"children\":[\"$\",\"$8\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Le\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$f\",[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/chunks/0j-zyy6.adwtl.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"AQ0US7_Pm9gOOelb-ks5q\"}\n"])</script><script>self.__next_f.push([1,"10:[]\na:\"$W10\"\n"])</script><script>self.__next_f.push([1,"c:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n"])</script><script>self.__next_f.push([1,"11:I[27201,[\"/_next/static/chunks/0o3_.p5ivp5sp.js\",\"/_next/static/chunks/0d3shmwh5_nmn.js\"],\"IconMark\"]\n9:null\ne:[[\"$\",\"title\",\"0\",{\"children\":\"QuadWork\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Unified dashboard for multi-agent coding teams\"}],[\"$\",\"link\",\"2\",{\"rel\":\"icon\",\"href\":\"/favicon.ico?favicon.0x3dzn~oxb6tn.ico\",\"sizes\":\"256x256\",\"type\":\"image/x-icon\"}],[\"$\",\"$L11\",\"3\",{}]]\n"])</script></body></html>
@@ -2,5 +2,5 @@
2
2
  2:I[54338,["/_next/static/chunks/0o3_.p5ivp5sp.js","/_next/static/chunks/0d3shmwh5_nmn.js","/_next/static/chunks/0n7b.b.q4nmo..js"],"default"]
3
3
  3:I[97367,["/_next/static/chunks/0o3_.p5ivp5sp.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"OutletBoundary"]
4
4
  4:"$Sreact.suspense"
5
- 0:{"rsc":["$","$1","c",{"children":[["$","$L2",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/0n7b.b.q4nmo..js","async":true}]],["$","$L3",null,{"children":["$","$4",null,{"name":"Next.MetadataOutlet","children":"$@5"}]}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"BHDF9NWAl5FhHwuakKgwK"}
5
+ 0:{"rsc":["$","$1","c",{"children":[["$","$L2",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/0n7b.b.q4nmo..js","async":true}]],["$","$L3",null,{"children":["$","$4",null,{"name":"Next.MetadataOutlet","children":"$@5"}]}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"AQ0US7_Pm9gOOelb-ks5q"}
6
6
  5:null
@@ -12,7 +12,7 @@ d:I[97367,["/_next/static/chunks/0o3_.p5ivp5sp.js","/_next/static/chunks/0d3shmw
12
12
  f:I[68027,["/_next/static/chunks/0o3_.p5ivp5sp.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default",1]
13
13
  :HL["/_next/static/chunks/0j-zyy6.adwtl.css","style"]
14
14
  :HL["/_next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
15
- 0:{"P":null,"c":["",""],"q":"","i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",16],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0j-zyy6.adwtl.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/0o3_.p5ivp5sp.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/_next/static/chunks/0d3shmwh5_nmn.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"en","className":"geist_mono_8d43a2aa-module__8Li5zG__variable h-full","children":["$","body",null,{"className":"h-full flex flex-col","children":[["$","$L2",null,{}],["$","$L3",null,{}],["$","div",null,{"className":"flex flex-1 min-h-0","children":[["$","$L4",null,{}],["$","main",null,{"className":"flex-1 min-w-0 overflow-auto","children":["$","$L5",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]]}]]}]}]]}],{"children":[["$","$1","c",{"children":[["$","$L7",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/0n7b.b.q4nmo..js","async":true,"nonce":"$undefined"}]],["$","$L8",null,{"children":["$","$9",null,{"name":"Next.MetadataOutlet","children":"$@a"}]}]]}],{},null,false,null]},null,false,null],["$","$1","h",{"children":[null,["$","$Lb",null,{"children":"$Lc"}],["$","div",null,{"hidden":true,"children":["$","$Ld",null,{"children":["$","$9",null,{"name":"Next.Metadata","children":"$Le"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$f",[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0j-zyy6.adwtl.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"BHDF9NWAl5FhHwuakKgwK"}
15
+ 0:{"P":null,"c":["",""],"q":"","i":false,"f":[[["",{"children":["__PAGE__",{}]},"$undefined","$undefined",16],[["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0j-zyy6.adwtl.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}],["$","script","script-0",{"src":"/_next/static/chunks/0o3_.p5ivp5sp.js","async":true,"nonce":"$undefined"}],["$","script","script-1",{"src":"/_next/static/chunks/0d3shmwh5_nmn.js","async":true,"nonce":"$undefined"}]],["$","html",null,{"lang":"en","className":"geist_mono_8d43a2aa-module__8Li5zG__variable h-full","children":["$","body",null,{"className":"h-full flex flex-col","children":[["$","$L2",null,{}],["$","$L3",null,{}],["$","div",null,{"className":"flex flex-1 min-h-0","children":[["$","$L4",null,{}],["$","main",null,{"className":"flex-1 min-w-0 overflow-auto","children":["$","$L5",null,{"parallelRouterKey":"children","error":"$undefined","errorStyles":"$undefined","errorScripts":"$undefined","template":["$","$L6",null,{}],"templateStyles":"$undefined","templateScripts":"$undefined","notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]],"forbidden":"$undefined","unauthorized":"$undefined"}]}]]}]]}]}]]}],{"children":[["$","$1","c",{"children":[["$","$L7",null,{}],[["$","script","script-0",{"src":"/_next/static/chunks/0n7b.b.q4nmo..js","async":true,"nonce":"$undefined"}]],["$","$L8",null,{"children":["$","$9",null,{"name":"Next.MetadataOutlet","children":"$@a"}]}]]}],{},null,false,null]},null,false,null],["$","$1","h",{"children":[null,["$","$Lb",null,{"children":"$Lc"}],["$","div",null,{"hidden":true,"children":["$","$Ld",null,{"children":["$","$9",null,{"name":"Next.Metadata","children":"$Le"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$f",[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0j-zyy6.adwtl.css","precedence":"next","crossOrigin":"$undefined","nonce":"$undefined"}]]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"AQ0US7_Pm9gOOelb-ks5q"}
16
16
  c:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
17
17
  10:I[27201,["/_next/static/chunks/0o3_.p5ivp5sp.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"IconMark"]
18
18
  a:null
@@ -3,4 +3,4 @@
3
3
  3:I[97367,["/_next/static/chunks/0o3_.p5ivp5sp.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"MetadataBoundary"]
4
4
  4:"$Sreact.suspense"
5
5
  5:I[27201,["/_next/static/chunks/0o3_.p5ivp5sp.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"IconMark"]
6
- 0:{"rsc":["$","$1","h",{"children":[null,["$","$L2",null,{"children":[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]}],["$","div",null,{"hidden":true,"children":["$","$L3",null,{"children":["$","$4",null,{"name":"Next.Metadata","children":[["$","title","0",{"children":"QuadWork"}],["$","meta","1",{"name":"description","content":"Unified dashboard for multi-agent coding teams"}],["$","link","2",{"rel":"icon","href":"/favicon.ico?favicon.0x3dzn~oxb6tn.ico","sizes":"256x256","type":"image/x-icon"}],["$","$L5","3",{}]]}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"BHDF9NWAl5FhHwuakKgwK"}
6
+ 0:{"rsc":["$","$1","h",{"children":[null,["$","$L2",null,{"children":[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]}],["$","div",null,{"hidden":true,"children":["$","$L3",null,{"children":["$","$4",null,{"name":"Next.Metadata","children":[["$","title","0",{"children":"QuadWork"}],["$","meta","1",{"name":"description","content":"Unified dashboard for multi-agent coding teams"}],["$","link","2",{"rel":"icon","href":"/favicon.ico?favicon.0x3dzn~oxb6tn.ico","sizes":"256x256","type":"image/x-icon"}],["$","$L5","3",{}]]}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"AQ0US7_Pm9gOOelb-ks5q"}
@@ -5,4 +5,4 @@
5
5
  5:I[39756,["/_next/static/chunks/0o3_.p5ivp5sp.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default"]
6
6
  6:I[37457,["/_next/static/chunks/0o3_.p5ivp5sp.js","/_next/static/chunks/0d3shmwh5_nmn.js"],"default"]
7
7
  :HL["/_next/static/chunks/0j-zyy6.adwtl.css","style"]
8
- 0:{"rsc":["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0j-zyy6.adwtl.css","precedence":"next"}],["$","script","script-0",{"src":"/_next/static/chunks/0o3_.p5ivp5sp.js","async":true}],["$","script","script-1",{"src":"/_next/static/chunks/0d3shmwh5_nmn.js","async":true}]],["$","html",null,{"lang":"en","className":"geist_mono_8d43a2aa-module__8Li5zG__variable h-full","children":["$","body",null,{"className":"h-full flex flex-col","children":[["$","$L2",null,{}],["$","$L3",null,{}],["$","div",null,{"className":"flex flex-1 min-h-0","children":[["$","$L4",null,{}],["$","main",null,{"className":"flex-1 min-w-0 overflow-auto","children":["$","$L5",null,{"parallelRouterKey":"children","template":["$","$L6",null,{}],"notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]]}]}]]}]]}]}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"BHDF9NWAl5FhHwuakKgwK"}
8
+ 0:{"rsc":["$","$1","c",{"children":[[["$","link","0",{"rel":"stylesheet","href":"/_next/static/chunks/0j-zyy6.adwtl.css","precedence":"next"}],["$","script","script-0",{"src":"/_next/static/chunks/0o3_.p5ivp5sp.js","async":true}],["$","script","script-1",{"src":"/_next/static/chunks/0d3shmwh5_nmn.js","async":true}]],["$","html",null,{"lang":"en","className":"geist_mono_8d43a2aa-module__8Li5zG__variable h-full","children":["$","body",null,{"className":"h-full flex flex-col","children":[["$","$L2",null,{}],["$","$L3",null,{}],["$","div",null,{"className":"flex flex-1 min-h-0","children":[["$","$L4",null,{}],["$","main",null,{"className":"flex-1 min-w-0 overflow-auto","children":["$","$L5",null,{"parallelRouterKey":"children","template":["$","$L6",null,{}],"notFound":[[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":404}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],[]]}]}]]}]]}]}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"AQ0US7_Pm9gOOelb-ks5q"}
@@ -1,3 +1,3 @@
1
1
  :HL["/_next/static/chunks/0j-zyy6.adwtl.css","style"]
2
2
  :HL["/_next/static/media/797e433ab948586e-s.p.0.q-h669a_dqa.woff2","font",{"crossOrigin":"","type":"font/woff2"}]
3
- 0:{"tree":{"name":"","param":null,"prefetchHints":16,"slots":{"children":{"name":"__PAGE__","param":null,"prefetchHints":0,"slots":null}}},"staleTime":300,"buildId":"BHDF9NWAl5FhHwuakKgwK"}
3
+ 0:{"tree":{"name":"","param":null,"prefetchHints":16,"slots":{"children":{"name":"__PAGE__","param":null,"prefetchHints":0,"slots":null}}},"staleTime":300,"buildId":"AQ0US7_Pm9gOOelb-ks5q"}