5 Commits
Author SHA1 Message Date
74260d7f6f feat(tui): opt-in CLAUDE_TUI_MODE — interactive subscription-pool bridge (PR-1..PR-4 squashed) (#104)
Reader + driver + home modes + server wiring + entrypoint hardening. 5 independent
reviews folded; e2e green; default stream-json path byte-identical when flag off.
See PR description + ADR 0007 for the full layer/authority/security detail.

Co-authored-by: dtzp555 <dtzp555@gmail.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 09:21:11 +10:00
313cb13a78 docs: align README + governance docs with current state (uninstall, files, ADR index, ship-archive) (#59)
Multiple documentation polish items rolled into one PR (one layer:
"docs alignment with current state").

### README.md

- **Uninstall section** added between Server Setup and Client Setup
  (was missing — `node uninstall.mjs` exists but went undocumented).
- **OpenClaw definition** added as a footnote on first README mention
  (the architecture diagram and Supported Tools table both reference
  OpenClaw without ever defining it).
- **Repository Layout section** added before Security — table of
  top-level files (server.mjs, setup.mjs, uninstall.mjs, keys.mjs,
  models.json, ocp/ocp-connect, dashboard.html, scripts/, .claude/skills/,
  ocp-plugin/, docs/adr/, ALIGNMENT.md, AGENTS.md, CLAUDE.md) so a new
  contributor knows what each file does.
- **LICENSE link** added to the License section footer.

### docs/adr/README.md (new)

- Index of the three published ADRs (0002, 0003, 0004) with a one-line
  description each.
- Explains the `0001` placeholder (early internal proposal that was
  superseded; numbering deliberately starts at `0002`).
- Guidance on when to write a new ADR vs. when a commit message suffices.

### Spec/plan housekeeping

- `specs/.gitkeep` removed (the empty `specs/` placeholder confused the
  picture; canonical paths are `docs/superpowers/plans/` for active plans
  and `docs/superpowers/specs/` for long-lived design docs that other
  code references).
- Shipped plans moved to `docs/superpowers/plans/shipped/`:
  - `2026-04-10-lan-mode.md` (shipped: README LAN mode section)
  - `2026-04-25-47-sse-heartbeat-plan.md` (shipped: v3.12.0 per CHANGELOG)
- `2026-04-25-47-sse-heartbeat-design.md` left in `docs/superpowers/specs/`
  unchanged because both `server.mjs:565` and `CHANGELOG.md:7` link to
  that exact path; moving it would require a `server.mjs` edit, which
  needs `cli.js` citation per ALIGNMENT.md Rule 1.

### AGENTS.md

- Updated "Key files to know" to add `docs/adr/README.md`,
  `docs/superpowers/plans/`, and `memory/constitution.md`.
- Note explaining `memory/constitution.md` is spec-kit's standard
  location, distinct from `~/.cc-rules/memory/` and `ALIGNMENT.md`.
- Updated "Handoff expectations" item 5 from `docs/superpowers/specs/*/tasks.md`
  (which never matched anything — there were no `tasks.md` files there)
  to `docs/superpowers/plans/` (excluding `shipped/`).

### Coordination with PR #53

PR #53 is open and adds "Why OCP?", "Comparison", and "Governance"
sections to README. This PR deliberately avoids those areas — only edits
the Supported Tools table footnote, inserts Uninstall before Client Setup,
inserts Repository Layout before Security, and updates the License footer.
No expected merge conflict.

Refs: audit findings M6, M8, M9, M11, L2, L3, L6.

Co-authored-by: dtzp555 <dtzp555@gmail.com>
2026-05-05 09:44:49 +10:00
b871b72b6b feat(server): SSE heartbeat on streaming path (#47) (#49)
* docs(spec): design for #47 SSE heartbeat on streaming path

Draft spec for an opt-in idle-watchdog SSE heartbeat covering both
pre-first-byte and mid-stream silent windows. Default disabled,
controlled by CLAUDE_HEARTBEAT_INTERVAL. Targets ~40 LOC.

Decisions captured: D1 whole-stream reset-on-byte; D2 SSE comment
frame; D3 default disabled; D4 relocate ensureHeaders() to post-spawn;
D5 X-Accel-Buffering: no on both SSE header sites; D6 single log line
per affected request.

Scope-locked: does not touch CLAUDE_TIMEOUT semantics, the separate
server.mjs:480-489 dangling-client bug, issues #41/#42, or the
non-streaming path.

Includes privacy preflight and cloud-testing plan per maintainer
feedback.

Refs: #47

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* docs(plan): implementation plan for #47 SSE heartbeat

6 phases: pre-work (file 480-bug), implementation (5 tasks on
feat/47-sse-heartbeat), opus fresh-context review, cloud verification
on Mac rig, privacy preflight, PR+release.

Each implementation task carries concrete code, syntax check, and a
scoped commit message. LOC budget enforced in Task 1.6 gate (~45
server.mjs lines max). Reviewer checklist scopes scope-lock, ALIGNMENT,
privacy, and heartbeat-cannot-abort discipline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(server): add startHeartbeat helper + HEARTBEAT_INTERVAL env var

Per design doc (refs #47). Helper is a per-request idle watchdog that
emits `: keepalive\n\n` SSE comment frames; returns a {reset, stop} handle.
No wiring yet — helper is unused, safe to commit in isolation.

cli.js citation: N/A — SSE response shaping is an OCP-owned translation
layer, not a cli.js operation. See AGENTS.md and ALIGNMENT.md Rule 2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* refactor(server): eagerly send SSE headers post-spawn (D4, refs #47)

Moves the ensureHeaders() call from "on first stdout byte" to
"immediately after successful spawn." This is a prerequisite for the
heartbeat covering the pre-first-byte silent window (the 'processing
large contexts' failure mode in #47).

Behavioral consequence: the narrow "spawn succeeded but subprocess died
before any byte" branch at server.mjs:610-611 becomes effectively dead
in the common case. The post-headers SSE-stop path (612-619) handles
it instead. The branch remains defensively for the client-closed-before-
ensureHeaders race.

Isolated commit per design doc §D4 so reviewer can focus on this one
behavior change.

cli.js citation: N/A — SSE header emission is OCP response-shaping.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(server): wire heartbeat into streaming path (refs #47)

- sendSSE() accepts optional hb handle and calls hb.reset() before write
- callClaudeStreaming starts heartbeat after ensureHeaders() and passes
  hb to the three streaming sendSSE call sites
- All three exit paths (proc close, proc error, res close) call
  hb.stop() to guarantee timer cleanup; no-op handle when disabled
  means zero runtime cost when CLAUDE_HEARTBEAT_INTERVAL=0

Heartbeat never aborts — only writes comment frames and re-arms. Aligns
with v3.3 timeout discipline (single CLAUDE_TIMEOUT, no secondary
client-killing timers).

cli.js citation: N/A — SSE response shaping is OCP translation layer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat(server): add X-Accel-Buffering: no to SSE response headers (refs #47)

nginx (and many LBs / Cloudflare) default to proxy_buffering=on, which
would buffer heartbeat comment frames indefinitely and defeat the
feature silently. This header hints no-buffering; other stacks ignore
it. Applied at both SSE header sites (real streaming + cache-hit).

cli.js citation: N/A — response header shaping is OCP translation layer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore(release): v3.12.0 — streaming heartbeat (refs #47)

Bundles the release-kit companion files per Iron Rule 5.2 / 11 example:
version bump across package.json + ocp-plugin + openclaw.plugin.json,
CHANGELOG v3.12.0 section, README env var row + "Streaming heartbeat"
explainer.

Tag push to v3.12.0 triggers .github/workflows/release.yml to create
the GitHub Release automatically.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(server): ensureHeaders returns true when already sent (refs #47)

Phase 3 smoke test revealed every content chunk was being dropped
after the D4 eager ensureHeaders() call: the stdout.on('data') guard
`if (!ensureHeaders()) return;` early-returned on every chunk because
ensureHeaders returned false for the already-sent case (conflated with
the dead-connection case).

Split the two conditions explicitly: return false only when res is
ended/destroyed; return true when headers are (already or now) sent.
This also fixes a latent multi-chunk bug on main that was masked
because claude CLI typically outputs in one stdout chunk.

Verified: node -c server.mjs; subsequent re-run of Phase 3 smoke test
now sees streaming content chunks + heartbeat frames.

cli.js citation: N/A — SSE response shaping is OCP translation layer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-25 09:09:47 +10:00
1c29f4867f chore(privacy): scrub personal identifiers from public repo (#43)
Removes all occurrences of maintainer's real name and handle from
tracked files in this PUBLIC repository. Replaces with generic terms
like "project maintainer" / "the maintainer".

Files scrubbed:
- CLAUDE.md (2 instances)
- ALIGNMENT.md (Auditor field)
- docs/adr/0002, 0003, 0004 (Authors/Deciders fields + body text)
- memory/constitution.md (1 instance)
- docs/superpowers/plans/2026-04-10-lan-mode.md (Users/taodeng paths → $HOME)

Also:
- Replaces specific machine hostnames (Taos-Mac-mini, Taos-MacBook-Pro)
  with role-based names (home-mac, travel-macbook) in ADR 0001 (if
  committed; currently untracked).
- Replaces /Users/taodeng/ paths with $HOME/ in old plan doc.

NOTE: git history still contains the personal info. See postmortem
(issue TBD) for whether to rewrite history via git-filter-repo.

Co-authored-by: Tao Deng <dtzp555@gmail.com>
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-22 11:01:44 +10:00
taodengandClaude Opus 4.6 3e8ff7a509 docs: add LAN mode implementation plan
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 21:00:22 +10:00