Files
wpide-server/CHANGELOG.md
T

255 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Changelog
All notable changes to wpide-server will be documented in this file. Format
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning
is [SemVer](https://semver.org/spec/v2.0.0.html).
## [0.7.0] — 2026-05-26
### Added
- **Marketing landing page at `/`** (`src/routes/landing.ts`). Dark-theme,
single-file HTML/CSS (same self-contained pattern as `/app`). Sections:
sticky nav, hero with value-prop + CTAs to `/app`, model trust-strip
(DeepSeek/Anthropic/OpenAI/xAI), 6-card features grid, 3-step "how it
works" with an inline chat preview, final CTA, footer.
- **Quick docs page at `/docs`** — setup steps, brain-split explainer,
model-routing tiers, minimal API surface reference.
- **Brand name read from `BRAND_NAME` env** (default `WP IDE Server`) so
the customer-facing name can be changed without touching code.
- No `/pricing` yet — deliberately deferred until tiers are finalised.
### Notes
- `/app` (the existing dashboard) is unchanged and reachable from the new
nav. The landing nav links: Docs · Sign in · Get started.
## [0.6.3] — 2026-05-26
### Changed
- **Request logging back to `!isDev` (silent in prod).** Was temporarily
forced on to debug the live browser-direct tool round-trip with the
plugin on Hostinger (see plugin 56.95/56.96). Now that browser-direct
is verified end-to-end (744 ms tool round-trip from `mersaai.diretenders.com`),
prod logs go quiet again — every 30s `/v1/health` from Docker's
healthcheck no longer fills the log file.
### Kept
- The targeted diagnostic lines added in 0.6.2 stay in for future
support work:
- `browser-direct: awaiting tool result from browser` (orchestrator)
- `browser-direct: tool result TIMED OUT after 90s` (orchestrator)
- `tool_result POST received … matched:true|false` (runs route)
These are low-volume and useful for diagnosing future host quirks.
## [0.6.2] — 2026-05-26
### Fixed
- **`z.coerce.boolean()` read every boolean env var as `true`.** `Boolean("false")`
is `true` in JS, so `ALLOW_INSECURE_TLS=false`, `REQUIRE_LICENSE=false`, and
`FREE_TIER_ACTIVE=false` were all silently `true`. Replaced with a `boolish()`
parser that treats `0/false/no/off` as false and `1/true/yes/on` as true.
This bit on the first real VPS deploy: TLS verification stayed disabled and
license gating would have switched on unexpectedly.
### Added
- **Production deploy artifacts (`deploy/`).** `vps-bootstrap.sh` (Ubuntu prep:
update, ufw, base tools) and `docker-compose.coolify.yml` (runs the container
behind Coolify's existing Traefik proxy on the external `coolify` network, with
Let's Encrypt labels). First live deploy: Contabo VPS → Coolify/Traefik →
`https://api.qbirr.com`.
## [0.6.1] — 2026-05-26
### Fixed
- **SSE stream endpoint now sends CORS headers.** The `/v1/runs/:id/stream`
reply is hijacked (raw), so the cors plugin didn't run on it. Added
`access-control-allow-origin` (echoes request origin) so the plugin's
browser-direct `EventSource` can open the stream cross-origin (browser
on the WP site → server on another domain). Without this the browser
blocked the stream.
## [0.6.0] — 2026-05-25 — Memory, teams, browser-direct tools
### Added
- **Server-side conversation memory (`orchestrator/memory.ts`).** Persists
each run's user goal + final answer per `session_id`; recalls the last
~12 turns and merges (de-duplicated) into context on the next run. Runs
now have continuity even when the plugin sends little history. (DB
migration v3: `conversation_turns`.)
- **Multi-tenant teams (`accounts/teams.ts`, `routes/teams.ts`).** Orgs +
members + roles; `POST/GET /v1/teams`, member add/remove. A member
**inherits the org owner's subscription tier** (team owner pays once,
seats share the tier) — wired into `resolveAccess`. (Migration v3:
`orgs`, `org_members`, `subscriptions.org_id`.)
- **Browser-direct tool execution (cap-immune transport, server side).**
`browser_tools: true` on a run makes the loop emit `tool_call` SSE
events and await `POST /v1/runs/:id/tool_result` from the browser,
instead of calling back into the plugin. Removes the long-lived request
from the WP host entirely → works on any shared host. Relay mode
(plugin callback) remains the default; this is additive. Proven
end-to-end via test (tool_call emitted → result posted → run completed
using the posted data).
### Notes
- The browser-direct **plugin JS** (browser opens EventSource + runs the
tool via admin-ajax + POSTs the result) is the remaining client-side
step; the server fully supports it now.
## [0.5.0] — 2026-05-25 — SaaS platform foundation
### Added
- **Accounts & auth.** Email+password (scrypt, no native deps), Google +
GitHub OAuth (authorization-code flow), session JWT in an httpOnly
cookie. `/v1/auth/{register,login,logout,me,set-password}` and
`/v1/auth/oauth/:provider/{start,callback}`.
- **Licensing & subscriptions (no credits).** Each account gets a license
key + a subscription row (tier `basic|pro|max`, status). The run path
resolves the license → tier and gates on an active subscription
(`REQUIRE_LICENSE`, default off in dev so local testing needs no
account; `DEV_DEFAULT_TIER` applies when off).
- **Model routing by tier** (`routing/policy.ts`): tier sets the model
ceiling — basic→flash, pro→+thinking, max→+pro-max — combined with
mode/complexity. Explicit model picks are honored only within the tier,
else downgraded. DeepSeek `thinking` param wired through.
- **Stripe billing** (`fetch`, no SDK): `/v1/billing/{checkout,portal,webhook}`
with manual webhook signature verification; subscription state mirrored
into the DB. Disabled cleanly when keys absent.
- **Dashboard** at `/app`: signup/login (email + Google + GitHub),
license key with copy, plan + tier picker + manage-billing. Single
inline HTML page, no build step.
- **DB migration v2:** users, oauth_identities, licenses, subscriptions,
sites (site registry); runs gain user_id/tier/model.
- **Deploy:** `SETUP.md` operator checklist, `docker-compose.prod.yml` +
`Caddyfile.prod` for a plain VPS (Coolify uses the Dockerfile directly).
SQLite on a persistent volume for v1; Postgres is the documented
scale-up path.
### Notes
- Credits/metering intentionally deferred — access is subscription-gated,
tier gates models. Multi-tenant teams, server-side memory, and the
browser-direct SSE transport remain as later sub-projects.
## [0.4.1] — 2026-05-25
### Fixed
- **Reasoning rendered one token per line in the chat.** The agentic loop
was emitting a `thinking` event per reasoning token; the plugin relays
each as a `thought` event, and the browser appends one list item per
thought — so each reasoning token landed on its own line. Now the loop
accumulates `reasoning_content` per step and emits a single `thinking`
event when the step's LLM call finishes (matches the local
orchestrator's one-thought-per-step model). Content tokens still stream
individually into the live bubble.
## [0.4.0] — 2026-05-25
### Added
- **SSE token streaming.** `GET /v1/runs/:run_id/stream` streams a run's
live events (`token`, `thinking`, `tool_call`, `tool_result`, `status`,
`done`, `error`, `end`) with `?since=<seq>` resume. Backed by a per-run
event buffer in the registry (`addEvent`).
- `OpenAIClient.chatStream()` — streaming chat completions over fetch:
parses SSE token deltas, accumulates `content` / `reasoning_content` /
`tool_calls`, returns the same shape as `chat()`. Connect-only retry
(safe to retry before any token; never mid-stream).
- The agentic loop now uses `chatStream` and emits token/tool events into
the run's buffer as they happen.
### Fixed
- **DeepSeek v4 thinking mode HTTP 400** — the loop now echoes the
assistant message's `reasoning_content` back on the next turn after a
tool call, as DeepSeek v4 requires. (`chat()` and `chatStream()` both
capture the field; the loop re-sends it.)
## [0.3.0] — 2026-05-25
### Added
- **Async run model — removes the synchronous timeout ceiling.**
- `POST /v1/runs/start` registers a run, kicks off the orchestrator in
the background, and returns `{ run_id, session_id }` immediately.
- `GET /v1/runs/:run_id/status` reports live progress
(`status`, `steps_done`, `tools_used`, `elapsed_ms`, `partial_content`)
and the full PHP-shape `response` once finished.
- In-memory run registry (`src/orchestrator/registry.ts`) with a 30-min
TTL for finished runs. `process_request` shares its step/tool arrays
with the registry so status reflects progress as it happens.
- Old synchronous `POST /v1/runs` retained for non-browser callers.
- **Built-in server-side `wait` tool** — lets agents pace long-running
diagnostics without a DB `SLEEP()` (SQLite has none). Handled in-loop,
never calls back to the plugin. Max 30s per call.
- LLM chat retry hardened: 6 attempts, 20s per-attempt timeout (fails
fast on a hung VPN connection and retries), abort/timeout treated as
retryable. Step cap raised 25 → 40.
- `AGENT_STEP tool_call → <name>` logged at info level for live flow
visibility.
## [0.2.1] — 2026-05-25
### Added
- xAI (Grok) provider client — OpenAI-compatible base URL `https://api.x.ai/v1`.
- DeepSeek provider client — base URL `https://api.deepseek.com/v1`.
- Provider auto-routing in `pickProvider()`: explicit override → model-name
prefix (`deepseek*`, `grok*`, `gpt-*`) → first configured key
(deepseek → xai → openai). `defaultModelFor()` picks a sane model per
provider.
- `ALLOW_INSECURE_TLS` (default on in dev) — skips outbound TLS
verification for machines behind a VPN/MITM whose root CA Node doesn't
trust. Set off in prod.
- Tool-manifest sanitizer (`src/tools/manifest.ts`) — coerces PHP's empty
`[]` to `{}` where objects are required and strips null values, so
strict validators (DeepSeek) stop rejecting the plugin's 95 tool
schemas with HTTP 400.
- LLM chat calls now retry up to 3× with backoff on network errors
(connect timeout, DNS, TLS) and 5xx/429 — rides through flaky-VPN
blips. 4xx are treated as real errors and not retried.
- Detailed logging on tool-exec callback failures (URL, status, headers,
body length) to diagnose cross-machine / rewrite issues.
### Changed
- Server binds to `0.0.0.0` by default (was `127.0.0.1`) so other LAN
machines can reach it. Default port `3017`.
- Default model is now `deepseek-chat`.
## [0.2.0] — 2026-05-21
### Added
- `GET /` root route returns an API directory (name, version, endpoint
hints) — friendlier than the previous 404 when poking around in a
browser.
- `POST /v1/runs` — main orchestrator entrypoint. Accepts
`{ goal, context, options, tools_manifest, callback_url, callback_secret, license_key, site_url }`
and returns the exact response shape PHP's `wp_ide_process_agentic()`
uses: `{ success, content, tool_results, execution: { run_id,
session_id, mode, steps, status_messages, ... }, approval_payload }`.
- `GET /v1/runs/:run_id` — fetch a stored run record.
- Greeting + simple paths fully working. Greetings need no LLM call;
simple invokes OpenAI chat/completions (default `gpt-4o-mini`).
Agentic path is a placeholder that returns a "step 5" message.
- Orchestrator router (`src/orchestrator/router.ts`) — port of
`WP_IDE_AI_Router::classify`; cheap regex/keyword heuristics that pick
greeting / simple / agentic without an LLM call.
- OpenAI client over fetch (`src/providers/openai.ts`) — no SDK
dependency. Provider router (`src/providers/index.ts`) dispatches by
model name; Anthropic / xAI plug in here in later steps.
- Runs table CRUD (`src/db/runs.ts`) — persists every run with status
transitions so a future status endpoint can answer "what happened".
### Notes
- `OPENAI_API_KEY` is read from `.env` on boot. Without it the simple
path returns a clear actionable error in the standard response shape;
the greeting path still works because it doesn't call any LLM.
## [0.1.0] — 2026-05-21
### Added
- Initial Fastify scaffold (Node 20, TypeScript, ESM).
- `GET /v1/health` returns name, version, uptime, Node version, timestamp.
- SQLite via `better-sqlite3` as the dev database; WAL mode + foreign keys
enabled. Postgres URL recognised for later Coolify deploy but not yet
wired.
- Initial schema: `schema_version`, `runs` tables (more added per
milestone).
- Zod-validated env loader, pino logger, CORS, graceful shutdown.
- `start-dev.bat` for one-command Windows dev startup.
- `Dockerfile` for future Coolify deployment (not used locally).
- Optional `Caddyfile` for local TLS via `wpide.local`.