[#232] Bare agentgather launches the local dashboard#236
Conversation
Make bare `agentgather` open the device-local dashboard on 127.0.0.1:8788 and keep a freshly started server foreground-owned until Ctrl-C. Add root flags --port <1..65535> and --no-open. Before binding, probe GET /version: reuse a same-version dashboard (open once, exit 0, no second listener); refuse an occupied/incompatible port without touching that process, pointing at the --port recovery path; otherwise start our own dashboard. Browser opening is shell-free (platform opener, URL as a lone argv element) and non-fatal. Help/version stay side-effect free; top-level help surfaces the bare launcher and advanced `room launch [--detach]`. Loopback-only, token-free output; no room/tunnel/remote action; no new deps. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Epic Alignment: FAIL
The #232 contract limits the root launcher to bare agentgather plus its two documented flags; the diff accepts additional root arguments after either launcher flag.
Checked (evidence)
- Structural gate: PR body includes filled EPIC Alignment, Self-Verification, Design Fidelity, and Security sections.
- Ticket/epic context: gh issue view 232; gh api repos//issues/77.
- Root-routing and argument parsing: src/cli/index.ts:35; src/cli/commands/launch/index.ts:47.
- Riskiest part of this diff: root CLI dispatch; it currently bypasses the side-effect-free help guarantee for trailing help flags.
- Kill-list: scanned all items - unsupported root arguments are silently ignored.
- CI: gh pr checks 236 -> Release gates pending.
Findings
- [blocking] Launcher accepts unsupported root flags/positionals and may start the dashboard despite a trailing help flag.
- File: src/cli/commands/launch/index.ts:47
- Why it fails: parseArgs results are never validated. Thus agentgather --no-open --allow-remote and agentgather --port 8788 --help enter the launcher; the latter starts/probes/listens instead of keeping help side-effect free. This contradicts #232's exactly-bare root path and its help/version safety contract. The current help test covers only --help as argv[0].
- Do instead: permit only --port <1..65535> and flag-only --no-open, reject any positional or unknown flag before probing, and short-circuit --help/-h anywhere in the root launcher argv. Add end-to-end tests for trailing help and an unsupported flag.
Decision
The implementation otherwise follows the local-only launcher direction, but this root-argument gap violates explicit scope and can create side effects for what should be a help invocation.
|
RE2 — APPROVE ✅ (#232 bare local dashboard launcher) Reviewed head Checked (evidence)
Independently verified (fresh worktree @
|
…anywhere The root launcher now rejects any argument outside its contract before probing or binding: no positionals, no flags other than --port/--no-open, and --no-open must be value-less. --help/-h and --version/-v short-circuit anywhere on the launcher line (e.g. `agentgather --port 8788 --help`), printing help/version with no probe, listener, or browser open. Adds in-process + E2E coverage (help-after-port leaves no listener; out-of-contract args never probe/listen). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: REQUEST CHANGES
Epic Alignment: PASS
The re-review delta preserves #232's local-only launcher contract and resolves the prior root-argument safety finding.
Checked (evidence)
- Delta reviewed: 4e54a8f..0c2f4e4 via gh api repos/realproject7/agentgather/compare/4e54a8f46082689b99c58ebda18d73599a6aaed4...0c2f4e4.
- Prior finding resolved: help/version short-circuit before probe/bind; unsupported flags and positionals reject before side effects.
- Regression coverage: test/cli-launch.test.ts:197 and :222, including E2E trailing-help behavior at :240.
- Riskiest part of this diff: root argument validation; its behavior now matches the ticket, but the added wrapper conflicts with the code-quality rule below.
- Kill-list: scanned new ranges - one single-call-site abstraction.
- CI: gh pr checks 236 -> Release gates pending.
Findings
- [blocking] New one-call-site validation helper must be inlined.
- File: src/cli/commands/launch/index.ts:136
- Why it fails: rejectUnsupportedArgs has exactly one caller (runLaunchCommand at :62). The project kill-list requires a new helper with one call site to be inlined; this function is not a shared boundary or independently reused abstraction.
- Do instead: move the positional/flag validation loop directly into runLaunchCommand before resolvePort, retaining the current tests and error text.
Decision
The original argument-handling defect is fixed. Inline the single-use validator, then I can re-review that narrow delta; CI must also finish green before approval.
|
RE2 — APPROVE ✅ (re-review on Re-reviewed the delta Checked (delta)
Independently verified (fresh worktree @
|
Fold the single-caller rejectUnsupportedArgs helper directly into runLaunchCommand; error text and behavior are byte-identical, so the arg-contract and help-anywhere tests are unchanged and still pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
RE2 — APPROVE ✅ (re-review on Re-reviewed the delta Behavior-neutral confirmed: the inline conditions are logically identical to the helper — Verified fresh @ |
project7-interns
left a comment
There was a problem hiding this comment.
Verdict: APPROVE
Epic Alignment: PASS
The reviewed launcher delta preserves #232's loopback-only, explicit-runtime contract and corrects the root argument boundary without touching #233 browser UI.
Checked (evidence)
- Re-review range: 0c2f4e4..334ca2c.
- Prior findings resolved: validation is inline in src/cli/commands/launch/index.ts:61; the single-use helper is removed.
- Exact root contract: positional/unknown flags and valued --no-open reject before probe/bind at src/cli/commands/launch/index.ts:61.
- Help/version remain side-effect-free before parsing/probing at src/cli/commands/launch/index.ts:47; regression coverage remains in test/cli-launch.test.ts:197 and :222.
- Riskiest part of this diff: root dispatch validation; the inline guard preserves the tested behavior while preventing ignored arguments from starting a listener.
- Kill-list: scanned the new range - clean.
- CI: gh pr checks 236 -> Release gates pass (2m29s, run 29235879879).
Findings
- None.
Decision
All prior RE1 findings are resolved on live head 334ca2c. The delta is behavior-preserving aside from enforcing the specified root argument contract.
Closes #232
Parent: #77 — Agent Gather Platform Pivot. Depends on: none. Enables: #233, #234.
Bare
agentgatherbecomes the everyday Local Workspace Launcher: it opens the device-local dashboard on127.0.0.1:8788and keeps a freshly started server foreground-owned until Ctrl-C. Advanced room/runtime operations stay explicit.EPIC Alignment
agentgatherowns only loopback dashboard launch/reuse; compatibility isGET /version({ ok, name: "agentgather", version });platform serveand explicitroom/runtime commands keep their existing contracts (only two symbols wereexported from the platform command — no behavior change).agentgatherreuses/starts the localhost dashboard only. It never creates a room, token, tunnel, or remote listener;#233's dashboard browser-shell/left-rail UI is not implemented here. The reused/started page is the existing owner shell, unchanged.createPlatformHttpServerand shares the platform command'sDEFAULT_PLATFORM_PORT+defaultWaitForShutdown(exported, not duplicated) so both keep-alive paths behave identically.Self-Verification
Diff re-read adversarially; kill-list scanned; acceptance criteria matched 1:1.
Acceptance criteria → evidence (tests in
test/cli-launch.test.ts,test/browser-launch.test.ts):bare launch starts the local dashboard, opens it once, and keeps it alive+ e2eroutes --no-open to a real, reachable dashboard that stops on SIGINT.--allow-remote/ starts a room/tunnel → token-free assertions across tests; launcher only callscreatePlatformHttpServer({ root })(localhost-only,allowInsecureRemotenever set).--no-open --port <port>starts without the opener and prints a stable token-free URL →launch --no-open ... without opening a browser.launch reuses a same-version dashboard already serving the port(asserts keep-alive loop not entered; original stays sole listener).--portrecovery →launch refuses an occupied/incompatible port without touching that process(foreign server still answers after).agentgather --helpexits 0 with no browser/listener/network →help/version stay side-effect free(spawned CLI, exits 0, no hang).platform servebehavior unchanged → full platform suite green.room launch→ asserted in the help test.launch treats a browser-opener failure as non-fatal.--portrejected token-free →launch rejects an out-of-range or non-numeric --port.Verification suite (all green):
pnpm build,pnpm lint,pnpm typecheck,pnpm kit-guard(4 panes clean),pnpm no-stub.Tests: 11 new #232 tests pass (10 CLI/launcher + 1 browser smoke). Full suite: 402 pass / 3 fail — the 3 failures (
active-session,cli-brief-file,cli-room: "participant token is not allowed") reproduce identically on the clean base9e15000in a fresh worktree, so they are pre-existing/environmental and unrelated to this change.Design Fidelity
Per #232 this changes interaction + CLI copy only; it does not redesign the dashboard visual system.
agentgatheropens the local dashboardagentgather Open the local dashboard in your browser (Ctrl-C to stop)--port/--no-openroom launch [--detach]under advanced host runtime operations.platform-shell[data-view="rooms"],v{VERSION}, no horizontal overflow at 1280src/browser/*untouched; kit-guard greenSecurity
tgl_token / Bearer / invite/card URL / message body in output, errors, opener args, or testshttp://127.0.0.1:<port>+ port numbersTOKEN_LEAK(/tgl_|Bearer|token=|#token=/i) asserted absent across launch/reuse/refuse testsdashboardquery paramhttp://127.0.0.1:${port}with no query/hash; server bound to127.0.0.1;--allow-remoteunreachable from this pathplatform serveremote-enforcement suite unchangedspawn(opener, [url], { shell:false })— URL is a lone argv element (open/xdg-open/cmd /c start "" url)src/cli/commands/launch/index.tsopenernode:*built-ins usedpackage.jsonunchangedDeviations
--no-openblocks until Ctrl-C (like a freshplatform serve): a started server must stay up to remain reachable.--no-open's "headless escape hatch" role is that it skips the browser opener (which would hang/fail headless), not that it detaches — only a reused dashboard exits 0 immediately. Documented and covered by the SIGINT e2e test.--portaccepts1..65535(not0/ephemeral): an ephemeral port is not a meaningful target for an everyday launcher and can't be probed for reuse; matches the ticket's--port <1..65535>.AGENTS.md,CLAUDE.md,DESIGN-GUIDE.md,.gitignore) present before this task were left uncommitted.