mirror of
https://github.com/dtzp555-max/ocp.git
synced 2026-07-21 21:15:09 +00:00
885f62addfc95cf324bf1d03070a64a5683bb8e9
14
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
885f62addf |
feat: Phase 6c — claude stream-json port + --system-prompt + opus 4.8 (#103)
* 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> |
||
|
|
9e25160527 |
refactor: hoist port literal to lib/constants.mjs + CI gate (v3.16.4) (#98)
Closes the structural side of the port-drift cascade addressed by
v3.16.2/v3.16.3. Those releases reverted the literal line-by-line; this
one removes the invitation to drift.
Changes:
* NEW lib/constants.mjs — exports DEFAULT_PORT=3456, LOCAL_HOST,
OPENAI_API_BASE, LOCAL_PROXY_URL.
* server.mjs / setup.mjs / scripts/upgrade.mjs / scripts/doctor.mjs
(x2) / scripts/sync-openclaw.mjs all import DEFAULT_PORT from
lib/constants.mjs instead of hardcoding "3456".
* .github/workflows/alignment.yml:
- path filter extended to setup.mjs, scripts/**, lib/**,
ocp, ocp-connect.
- NEW job port-spot hard-fails any PR that introduces a hardcoded
"3478" or "3456" literal outside EXEMPT_REGEX (lib/constants.mjs,
test-features.mjs, ocp/ocp-connect bash CLIs, docs, the workflow
itself).
* Doc-comment rewording so CI grep finds zero hits.
No behavior change for any user. CLAUDE_PROXY_PORT env var still wins
at runtime; only the unset-env fallback now flows through one constant.
ALIGNMENT.md note: server.mjs change is one import + one literal swap,
mechanical. No cli.js operation changed; the citation requirement does
not apply.
cli.js: not applicable — mechanical refactor, no behavior change.
Co-authored-by: dtzp555 <dtzp555@gmail.com>
|
||
|
|
49c6d32e3b |
fix(scripts): default CLAUDE_PROXY_PORT to 3456 (completes v3.16.2 revert) (#97)
Three places in scripts/ still defaulted to 3478 after v3.16.2's plugin / manifest / README / plist revert: scripts/upgrade.mjs:137 scripts/doctor.mjs:84 scripts/doctor.mjs:205 These were the residual cascade source for the port-drift bug originally caused by the PR #71 dogfood accident on 2026-05-08 (see ~/.cc-rules/memory/learnings/subagent_setup_mjs_prod_host_collision.md and v3.16.2 CHANGELOG entry). Every `ocp doctor` / `ocp upgrade` invocation without an explicit `CLAUDE_PROXY_PORT` in env probed port 3478 — got "OCP not responding" against a healthy 3456 instance — and on the maintainer's host this cascaded into wrong baseUrl writes for the OpenClaw `claude-local` provider, taking out the OpenClaw Telegram agent ("大内总管") on 2026-05-13. This change is the smallest possible: three string literals `"3478"` → `"3456"`, aligning unset-env defaults with `server.mjs:126`. Env-set users are unaffected (env precedence is unchanged). cli.js: not applicable — this is a scripts/ change, not server.mjs. ALIGNMENT.md hard-requirements (cli.js citation, blacklist CI, independent reviewer) target server.mjs; this PR honors the SPOT spirit by ending the literal-port drift across the codebase. Bumps to v3.16.3. CHANGELOG entry added. Co-authored-by: dtzp555 <dtzp555@gmail.com> |
||
|
|
7766fa0868 |
fix(plugin): revert default to 3456 + correct v3.16.1 narrative; v3.16.2 (#96)
v3.16.1's narrative ("OCP server moved to 3478 default in v3.14+") was
incorrect. OCP source default has been 3456 since
|
||
|
|
70faeff067 |
fix(plugin): default OCP plugin port to 3478 + env-overridable (v3.16.1) (#95)
* fix(plugin): default OCP plugin port to 3478 + env-overridable; v3.16.1 ocp-plugin/index.js hard-coded http://127.0.0.1:3456 since the plugin was created. OCP server moved to 3478 default in v3.14+ as part of the same wave that renamed the launchd label (dev.ocp.proxy). The plugin never got the memo. Result: `/ocp usage` from OpenClaw bots (e.g. the home Telegram bot 大内总管) hit the dead port 3456 and returned "OCP error: fetch failed". Fix: - Default PROXY → http://127.0.0.1:3478 - Read OCP_PROXY_URL env (full URL) first - Else read CLAUDE_PROXY_PORT env (port only, localhost assumed) - Else fall back to the 3478 default openclaw.plugin.json bumped (3.12.0 → 3.16.1) and configSchema default updated. Plugin version now matches OCP version. Top-level package.json bumped 3.16.0 → 3.16.1. CHANGELOG entry added. Diagnostic trail: caught 2026-05-12 when home Telegram bot reported "OCP error: fetch failed" against `/ocp usage`. Mac mini OCP service was healthy on port 3478; lsof -iTCP:3456 had no listener; plugin index.js had hardcoded 3456. No cli.js citation needed: this is OCP-internal plugin code with no corresponding cli.js operation. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> * docs(readme): document OCP_PROXY_URL + CLAUDE_PROXY_PORT plugin reuse (per release_kit 5.5) --------- Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
7a69d72886 |
feat(snapshot): gcSnapshots + ocp update --rollback --gc + auto-GC; v3.16.0 (#94)
Adds snapshot garbage collection with retention policy: keep last 5, keep snapshots within 30 days, always keep the most recent. Configurable via keepCount / keepDays opts. Wire-up: - ocp update --rollback --gc (manual trigger; --dry-run supported) - runFullUpgrade auto-GC after successful upgrade (best-effort, swallows errors) 4 unit tests: keepCount enforcement, keepDays override, never-delete- most-recent safety, dry-run mode. Bumps to v3.16.0 (bundles PR #93 --check oauth + this GC feature). No cli.js citation needed: this is OCP-internal snapshot lifecycle with no corresponding cli.js operation. Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
cd6ec2a212 |
fix(doctor): dynamic latest_version from origin/main; release v3.15.1 (#92)
v3.15.0 doctor used a hard-coded `latest = "v3.14.0"` fallback, causing any v3.15.0+ install to report kind=upgrade against a stale value. `ocp update` would then attempt `git checkout v3.14.0` — a downgrade. Doctor now fetches `git -C ~/ocp show origin/main:package.json` to determine the actual latest. On failure (offline, fresh clone, no remote), falls back to currentVersion so kind=noop instead of recommending a downgrade. Regression test added: doctor with unreachable ocpDir falls back to currentVersion as latest (not the old hardcoded v3.14.0). Caught during v3.15.0 post-deploy verification on home-mac: ./ocp doctor reported `kind=upgrade` immediately after v3.15.0 install, which would have been a critical user-facing bug. No cli.js citation needed: this is OCP-internal doctor logic with no corresponding cli.js operation. Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
ab03c13332 |
feat(upgrade): ocp doctor + cross-version ocp update + rollback + AI prompts (#91)
* feat(doctor): add ocp doctor with --json + next_action contract Implements scripts/doctor.mjs with semver-aware path selection (noop/update/upgrade/fresh_install/fix_oauth/fix_service) and the JSON contract documented in the design spec. Service health + OAuth checks integrated; mockable via opts.mockHealth for unit tests. 8 unit tests cover the kind dispatch tree and the next_action shape for each kind. No cli.js citation needed: this is OCP-internal tooling with no corresponding cli.js operation. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(ocp): wire cmd_doctor into bash CLI; dispatch to scripts/doctor.mjs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(doctor): handle unparseable version + empty health body Three issues raised by code-quality reviewer on |
||
|
|
750b25ba77 |
chore(release): v3.14.0 — security hardening (sessions namespacing + file modes + /api/usage scope) (#89)
Bump version 3.13.0 → 3.14.0. No functional code change in this PR; all three security fixes are already merged in main via PRs #86, #87, #88. This PR covers only metadata + docs: - package.json: version bump to 3.14.0 - CHANGELOG.md: v3.14.0 entry with Features / Behavior changes / Verification / Governance sections - README.md: /api/usage self-scope note in Auth Modes §, API Endpoints table row update, file-mode bullet in Important Notes § cli.js citation N/A: this release PR modifies no server.mjs / setup.mjs / keys.mjs. The three underlying security PRs (#86, #87, #88) each carry their own cli.js-citation-not-applicable disclaimer per PR #75 pattern, as they are OCP-internal access-control, session-state, and file-permission changes with no corresponding cli.js operation. Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> |
||
|
|
9494fd6c69 |
chore(release): v3.13.0 — cache layer hardening (per-key isolation + bypass + chunked replay + singleflight) (#67)
Per release_kit overlay (CLAUDE.md § Iron Rule 5.5): - package.json bumped 3.12.0 → 3.13.0 - CHANGELOG.md updated with v3.13.0 entry - README.md § Response Cache updated to document the four hardening features This is a release preparation commit. Tag push to v3.13.0 will trigger .github/workflows/release.yml which auto-creates the GitHub Release. cli.js does not perform proxy-layer response caching, stampede protection, or replay; this release only ships internal cache-layer correctness and concurrency improvements that do not change the OpenAI-compatible wire surface visible to clients. No client-observable wire shape change. Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
5be369ed68 |
docs(changelog): normalize version heading format to ## vX.Y.Z — YYYY-MM-DD (#63)
Audit side-finding: heading style drift in CHANGELOG.md. Before: ## v3.12.0 (2026-04-25) ← parens style (1 entry) ## v3.11.1 — 2026-04-21 ← em-dash style (canonical, majority) ## v3.11.0 — 2026-04-20 ← em-dash style (canonical, majority) After: all 3 entries use the em-dash form (2 of 3 entries already used it, so it's the canonical pattern by majority). Only the v3.12.0 heading line changed. The body content under each heading is untouched — only the date-format separator changes from parens to em-dash. Verification: - `grep "^## " CHANGELOG.md` after the edit → all entries match `## vX.Y.Z — YYYY-MM-DD`. - `git diff CHANGELOG.md` shows exactly one line changed. Refs: audit side-finding 3 of 4. Co-authored-by: dtzp555 <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
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> |
||
|
|
cdd6b41261 |
fix(concurrency): release slot on subprocess SIGTERM failure (#40)
Per forensic analysis in #37, the timeout handler at server.mjs:471 called `proc.kill('SIGTERM')` without decrementing the concurrency counter (`stats.activeRequests`). If the subprocess was stuck in a syscall (e.g. MCP I/O) and ignored SIGTERM, its slot was not freed until — and only if — the `proc.on('close')` handler eventually fired after the 5s SIGKILL escalation successfully reaped the child. Real-world observation (#37) shows 3 stuck claude subprocesses running 20 minutes to 2h 45m, exhausting the 8-slot pool and returning `500 concurrency limit reached (8/8)` on every subsequent request. Fix: attach `cleanup` to `proc.once('exit', ...)`. The 'exit' event fires before 'close' and runs on every termination path — normal completion, error, SIGTERM, SIGKILL, crash — even if stdio pipes stay open. `cleanup()` is already idempotent (guarded by `cleaned` flag), so this listener is safe alongside the existing 'close' and 'error' paths that also call it. ALIGNMENT: cli.js has no equivalent subprocess-pool / concurrency- limit logic — cli.js is a single-user CLI, the process being pooled, not the pool itself. Per ALIGNMENT.md Rule 2, this fix is proxy- internal (subprocess lifecycle management) with no cli.js equivalent to cite; documented here instead. No wire-protocol, HTTP surface, or response shape change (Rule 3 preserved). Release kit: bumps version to 3.11.1 and adds CHANGELOG entry so the auto-release workflow tags v3.11.1 on merge. README version refs are feature-gate markers for v3.11.0 (models.json SPOT / auto-sync) and remain historically accurate — no README change needed. Fixes #37. Co-authored-by: dtzp555 <dtzp555@gmail.com> |
||
|
|
ab9e0c656b |
chore(release): v3.11.0 — models.json SPOT + OpenClaw auto-sync (#32)
- Bumps version 3.10.0 → 3.11.0. - Adds CHANGELOG.md with v3.11.0 entry. Rolls up PR #30 (refactor: models.json SPOT) and PR #31 (feat: idempotent OpenClaw registry sync on `ocp update` + passive drift self-check). No server.mjs changes in this PR. Co-authored-by: Tao Deng <dtzp555@gmail.com> Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com> |