* wip(rescue): OCP Phase 6c stream-json port + opus 4.8 (uncommitted /tmp work) Rescue commit — preserves the subagent-produced Phase 6c port (claude -p → stream-json + --system-prompt + NDJSON parser) and opus 4.8 model addition done 2026-05-30 in a /tmp clone (volatile). NOT reviewed-for-merge; this is preservation only on a WIP branch so a /tmp reboot does not lose the work. Strategy context: OCP is being made the first-mover for TUI-mode (users are on OCP). Phase 6c here is the DEFAULT-path foundation (stream-json = sdk-cli = the "Max-user stable mode" fallback). TUI-mode (cc_entrypoint=cli subscription bridge) lands on top as an opt-in. Re-review before merging to main. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(phase6c): fold review findings — scrub hostname, README prose, parser tests, version citation P3-1 (binding): scrub private hostname "PI231" from server.mjs comment; replace with role-based term "the test server". Repo is public — no machine-specific hostnames may appear. P3-2: update README.md "How It Works" diagram and prose from stale "claude -p" to "claude --output-format stream-json", matching the Phase 6c spawn change already in server.mjs and CHANGELOG. P2-2: update all five authority citations in server.mjs from bare "claude CLI v2.1.104" to "claude CLI § <flag> (ported from OLP, verified v2.1.104; behavior stable through v2.1.158)" — honest about OLP provenance and version range, without inventing new facts. P2-1: add "Stream-JSON parsers" suite to test-features.mjs (17 new tests, 84 → 101 total). Copies parseStreamJsonLines and parseStreamJsonEvent verbatim from server.mjs with a MIRRORS header comment; logEvent stubbed to avoid live-server side-effects. Covers: content_block_delta deltas, assistant-aggregate fallback, no-double-count guard, aggregate-only short responses, partial-line buffering across two chunks, is_error result variants, malformed/non-JSON lines, system/user/unknown event types. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
17 KiB
Changelog
Unreleased
Model — add claude-opus-4-8
Add claude-opus-4-8 as the newest Opus to models.json (index 0, newest first). Repoint aliases.opus from claude-opus-4-7 to claude-opus-4-8. claude-opus-4-7 remains in the list callable by literal id. legacyAliases.claude-opus-4 left pointing at claude-opus-4-7 (no change — legacy alias tracks the prior generation). README Available Models table and model-count references updated accordingly.
v3.16.4 — 2026-05-13
Refactor — port-literal SPOT + CI guardrail
Closes the structural side of the port-drift cascade addressed by v3.16.2 and v3.16.3. Those two releases reverted plist / plugin / scripts back to 3456 line-by-line, but the underlying invitation to drift — a hardcoded port literal scattered across six source files — was still intact.
Changes:
- New
lib/constants.mjs— single source of truth for shared literals. ExportsDEFAULT_PORT = 3456,LOCAL_HOST = "127.0.0.1",OPENAI_API_BASE = "/v1",LOCAL_PROXY_URL. server.mjs:127,setup.mjs:36,scripts/upgrade.mjs:137,scripts/doctor.mjs:84+:205,scripts/sync-openclaw.mjs:73— all replaced with imports fromlib/constants.mjs. Behavior is identical; the literal3456now exists in exactly one place per language (lib/constants.mjsfor.mjs,ocp+ocp-connectfor bash,test-features.mjsfor pinned historical-port tests)..github/workflows/alignment.yml— extended the path filter tosetup.mjs,scripts/**,lib/**,ocp,ocp-connect. Added a newport-spothard-fail job that greps for any hardcoded3478or3456literal in.mjs/.js/.ts/.jsonoutside the EXEMPT_REGEX (which listslib/constants.mjs,test-features.mjs, the bash CLIs, docs, and the workflow itself). Any future PR re-introducing a hardcoded port literal will be blocked at CI before it can cascade.- Doc comments in
server.mjsenv-var summary andsetup.mjsusage banner reworded so the literal3456no longer appears as documentation text (CI grep is intentionally aggressive — it does not parse comments — so doc strings referenceDEFAULT_PORT from lib/constants.mjsinstead).
No behavior change for any user. CLAUDE_PROXY_PORT env var remains
the runtime override; the only difference is the unset-env fallback
now flows through one shared constant.
ALIGNMENT.md hard-requirements: this PR modifies server.mjs (one-line
import + one literal swap, mechanical). No cli.js operation changed;
the citation requirement does not apply. SPOT principle (Rule 2 spirit)
is the entire motivation.
v3.16.3 — 2026-05-13
Fixes — completes v3.16.2 port-drift revert
v3.16.2 reverted the plugin / openclaw.plugin.json / README / Mac mini
plist back to 3456 (the historical source default since 593d0dc), but
missed three places in scripts/ that still defaulted to 3478. Those
three lines were the residual cascade source: every time ocp doctor or
ocp upgrade ran without CLAUDE_PROXY_PORT in the env, they probed
3478, reported "OCP not responding" against a healthy 3456 instance,
and (in the case of OpenClaw sync follow-ups on the maintainer's host)
re-introduced 3478 into downstream config.
Changes:
scripts/upgrade.mjs:137— default port3478→3456.scripts/doctor.mjs:84— default port3478→3456.scripts/doctor.mjs:205— default port3478→3456.
No behavior change for users who set CLAUDE_PROXY_PORT explicitly; env
still takes precedence. The fix only affects the unset-env fallback,
which now matches server.mjs:126 and the rest of the codebase.
Test plan: existing test-features.mjs cases that pin
CLAUDE_PROXY_PORT=3478 continue to pass — they use the env path, not
the default.
v3.16.2 — 2026-05-12
Fixes — corrects v3.16.1
The v3.16.1 fix was directionally correct (plugin now reads env first, falls back to a hardcoded default) but the narrative and the hardcoded default were both wrong.
What v3.16.1 said: "OCP server moved to 3478 default in v3.14+; plugin lagged at 3456." What is actually true:
- OCP server source default has been
3456since593d0dc(initial release) and has never changed. Every line inserver.mjs,setup.mjs, and theocpCLI still uses3456as the documented and code-level default. - The single OCP installation observed on
3478is the maintainer's Mac mini, whose plist was rewritten with--port 3478during a PR #71 dogfood smoke-test accident on 2026-05-08 (see~/.cc-rules/memory/learnings/subagent_setup_mjs_prod_host_collision.md). The plist drift was never reconciled back to source default, and v3.16.1 incorrectly canonised the post-accident value as if it had been a release decision.
This release:
- Restores the plugin fallback to
http://127.0.0.1:3456to match server source default. - Updates
openclaw.plugin.jsonconfigSchema.proxyUrl.defaultback to3456. - Restores README §"Environment Variables"
CLAUDE_PROXY_PORTdefault to3456. - Plugin reads
OCP_PROXY_URLenv (full URL) first, thenCLAUDE_PROXY_PORTenv (port only), then falls back to3456. Hosts whose OCP plist injects a non-default port must also inject the sameCLAUDE_PROXY_PORTinto the OpenClaw plist for the plugin to follow. - Maintainer's Mac mini plist was reverted from
3478to3456as part of this release deploy (no source change reflects this; it was a one-host correction).
Governance
- No
cli.jscitation needed (noserver.mjschange). ALIGNMENT.md Rule 2 not engaged.
v3.16.1 — 2026-05-12 (superseded — narrative incorrect; see v3.16.2 erratum)
Fixes (as shipped — note erratum above)
- OCP plugin port lag —
ocp-plugin/index.jshard-codedhttp://127.0.0.1:3456.While OCP server moved to 3478 in v3.14+,(corrected v3.16.2: no such move ever happened.) The Mac mini's plist was on3478only as residue from a dogfood accident. Result:/ocpslash commands from the home Telegram bot returned "OCP error: fetch failed". v3.16.1 changed the plugin default to3478(wrong direction; v3.16.2 reverts to3456).
Governance
- No
cli.jscitation needed (noserver.mjschange). ALIGNMENT.md Rule 2 not engaged.
v3.16.0 — 2026-05-10
Features
ocp doctor --check oauth(PR #93) — fast path that runs only the OAuth check, skipping version detection / from-version / git operations / models endpoint. ~50ms vs. full doctor's ~200-500ms. Use cases: AI agent repair loops, post-claude auth loginverify, quick health gates. Help text incmd_doctor_helpnow reflects working behaviour.ocp update --rollback --gc— manually garbage-collect old upgrade snapshots. Retention policy: keep last 5 snapshots OR snapshots newer than 30 days OR the single most recent (always-keep safety net).--dry-runpreviews. Successfulocp updateruns auto-GC at the end of the full path; light path does not (no snapshot created there).
Behavior changes
- After a successful cross-minor
ocp update, the auto-GC emits[gc] removed N old snapshotsto stderr if any were collected. Safe to ignore; manual gc isocp update --rollback --gc.
Governance
- No
cli.jscitation needed (noserver.mjschange). ALIGNMENT.md Rule 2 not engaged. - PR #93 (--check oauth) merged separately; this release bundles it with the GC feature.
v3.15.1 — 2026-05-10
Fixes
- doctor: dynamic
latest_versionfromorigin/main:package.json— v3.15.0 doctor used a hard-codedlatest = "v3.14.0"fallback, which made any v3.15.0+ install reportkind = upgrade(against a stale value).ocp updatewould then attemptgit checkout v3.14.0— a downgrade. Doctor now fetchesgit -C ~/ocp show origin/main:package.jsonto determine the actual latest version; on failure (offline, fresh clone with no remote), falls back tocurrentVersionsokind = noopinstead of recommending a downgrade.
v3.15.0 — 2026-05-10
Features
ocp doctor— health & upgrade-readiness check; primary entry for AI-driven debugging.--jsonmode emits anext_actionwithai_executable[]for agents to run verbatim andhuman_required[]for steps requiring the user (typically only OAuth).ocp updatecross-version path — for cross-minor jumps (e.g. v3.10 → v3.14),ocp updatenow runs doctor → snapshot →setup.mjs(with the plist env-merge from PR #90) → service restart → post-flight/health+/v1/modelsverification. Same-patch updates retain the existing light path; users see no change for routine patch bumps.ocp update --rollback— restore the most recent (or specified) upgrade snapshot. Snapshots are saved to~/.ocp/upgrade-snapshot-<ISO-ts>/and never auto-deleted.- Fresh-install routing —
ocp updateon installations < v3.4.0 routes to a fresh-install flow (with--yesto skip confirmation; AI agents pass this). OAuth survives via Claude Code's credential store; users do not re-OAuth unless their token was independently broken. - AI prompt blocks in README — §Installation, §Upgrading, and §Troubleshooting each start with a copy-paste prompt for Claude Code / Cursor / Copilot, so users can drive install / setup / upgrade through their existing AI assistant.
Behavior changes
ocp updatemay take 10–30s longer when a cross-minor jump triggers the full path (snapshot + post-flight). Patch bumps are unchanged.- Pre-v3.4.0 installs are routed to fresh-install rather than failing silently or half-migrating.
Governance
- No
cli.jscitation needed (noserver.mjschange). ALIGNMENT.md Rule 2 not engaged. - Depends on PR #90 (plist env merge bug fix; merged before this release).
v3.14.0 — 2026-05-10
Features (security hardening)
- Per-key session isolation (PR #86, S1) — the
sessionsMap inserver.mjsis now keyed by${keyName}|${conversationId}instead of bareconversationId. Before this fix, two clients using distinct API keys but the samesession_idvalue (e.g. both defaulting to"default") would share the samecli.jssubprocess and conversation history, creating a cross-tenant leak path. Post-fix each (key, session) pair is isolated end-to-end, extending the per-key cache isolation shipped in v3.13.0 D1 to the session layer. - On-disk credential file modes 0700/0600 (PR #87, S2) —
setup.mjsnow creates~/.ocpat mode 0700 and bothadmin-keyandocp.dbat mode 0600. An idempotentreconcileFileModes()call inserver.mjsstartup tightens any existing installation to these modes automatically on every launch, so existing prod boxes fix themselves without manualchmod. Before this fix, all three files were created at the process's default umask (typically world-readable 0644 / 0755), leaving plaintext credentials readable by other local users. /api/usagedefault scope = self; admin all-keys requires?all=true(PR #88, S3) — the usage endpoint now applies a least-privilege default: anonymous callers receive only their own rows, non-admin authenticated callers receive only their own rows, and admin callers receive only their own rows unless they explicitly pass?all=true. When?all=trueis used, an audit log line is emitted. Before this fix, any admin-token holder could silently enumerate usage data for every key on the server.
Behavior changes
- Breaking change for admin tooling:
/api/usageno longer returns all-keys data by default. Existing cron jobs, dashboards, or scripts that rely on the admin token seeing all-keys output must add?all=trueto their request URL after upgrading to v3.14.0. - File mode reconcile at server startup logs a one-line notice per path when mode is tightened (e.g.
[security] tightened ~/.ocp/ocp.db → 0600). No action is required from the operator; the reconcile is idempotent and silent when modes are already correct. sessionsMap key is now${keyName}|${conversationId}internally. No client-visible wire change — thesession_idfield in request/response is unchanged.
Verification
- Stress-test pass: 11/11 phases including S1/S2/S3 security regression checks (Phase E, I, J). 35-minute sustained run, 60 calls, 0 errors, 0 timeouts. RSS dropped 51→47 MB across the window. Per-key cache isolation, singleflight, cache_control bypass, quota enforcement, file-mode reconcile, and scope guard against escalation all verified against running code.
Governance
- All three PRs (#86, #87, #88) include the explicit
cli.js-citation-not-applicable disclaimer (per PR #75 pattern) since they are OCP-internal access-control, session-state, and file-permission changes with no correspondingcli.jsoperation to cite.
No new env vars / no public API surface change beyond the documented breaking change
This release adds no new env vars or endpoints. The only externally visible change is the /api/usage scope guard (breaking for admin all-keys consumers; see Behavior changes above).
v3.13.0 — 2026-05-07
Features (cache layer hardening)
- Per-key cache isolation (D1) — the cache key now includes the API key id, so distinct keys never share cache entries. Anonymous/unauthenticated callers share one
anonpool. Hash format upgraded tov2; legacy v1-format rows orphan and are reaped by the existing TTL cleanup interval (no migration script). cache_controlbypass (D2) — when a request carries an Anthropiccache_controlannotation (top-level or nested in a content array), OCP skips its own cache entirely. The caller is using Anthropic-side prompt caching deliberately, and OCP must not interfere. Acache_skipped{reason: cache_control_present}log line is emitted on bypass.- Chunked stream replay (D3) — when a streaming request hits the cache, the cached content is now emitted as multiple SSE chunks (80 codepoints/chunk, codepoint-safe via
Array.from()) instead of a single large delta. Multibyte characters (CJK / emoji) stay intact. - Singleflight stampede protection (D4) — concurrent identical cache-miss requests now share one upstream
cli.jsspawn instead of spawning N processes. Followers receive byte-identical responses to what the leader returns. All-or-nothing failure semantics: if the leader errors, all followers receive the same error. Streaming-path singleflight is explicitly out of scope (TODO left for follow-up).
Behavior changes
/cache/statsresponse now includes additive fieldsinflightandrequesters(current in-flight singleflight entries and total waiting callers). Existing fieldsentries,totalHits,sizeBytesare preserved unchanged.
Governance
- New ADR
docs/adr/0005-no-multi-provider.md: OCP stays single-provider (Anthropic viacli.jsspawn). Multi-provider gateway refactor explicitly out of scope; cache improvements are explicitly in scope. - Design spec for this release:
docs/superpowers/specs/2026-05-07-cache-upgrade-design.md.
No new env vars / no public API surface change
This release adds no new env vars or endpoints. All four improvements are internal correctness/concurrency upgrades to the existing CLAUDE_CACHE_TTL-gated cache layer. No client-observable wire shape change.
v3.12.0 — 2026-04-25
Features
- Streaming heartbeat — opt-in SSE comment frame (
: keepalive\n\n) emitted during silent windows on the streaming response. Controlled byCLAUDE_HEARTBEAT_INTERVALenv var (ms;0= disabled, default). Covers both pre-first-byte and mid-stream tool-use pauses. Addresses #47. See design doc. X-Accel-Buffering: noresponse header added to SSE responses so heartbeats survive nginx/Cloudflare default buffering.
Behavior changes
- SSE headers are now sent immediately after the claude CLI spawns successfully, not on first stdout byte. The rare "spawn succeeded but subprocess died before any byte" path now closes the SSE stream cleanly rather than returning a JSON error.
Config additions
| Variable | Default | Description |
|---|---|---|
CLAUDE_HEARTBEAT_INTERVAL |
0 (disabled) |
Interval in ms for SSE keepalive comment frames on streaming path. Resets on every real frame. |
v3.11.1 — 2026-04-21
Fixes
- Concurrency slot leak on subprocess timeout (#37). The request-timeout handler called
proc.kill("SIGTERM")without decrementingstats.activeRequests. A subprocess stuck in a syscall that ignored SIGTERM would hold its slot until (or beyond) the 5s SIGKILL escalation actually reaped it. Slot release is now wired toproc.once("exit", cleanup)so every termination path — normal close, error, SIGTERM, SIGKILL — releases the slot exactly once.
v3.11.0 — 2026-04-20
Features
ocp updatenow automatically syncs OpenClaw's registry with the latest models (scripts/sync-openclaw.mjs)- Server logs warn if OpenClaw registry drifts from models.json
Refactor
- models.json is now the single source of truth for model list
- server.mjs and setup.mjs derive MODEL_MAP/MODELS from models.json
- Adding a new model is now a one-file edit
Fixes
- OpenClaw's model dropdown now shows all 4 current models (opus-4-7, opus-4-6, sonnet-4-6, haiku-4.5) on existing installs after
ocp update. Previously setup.mjs only wrote the registry at install time.