42 Commits

Author SHA1 Message Date
teamchong af41ce6e41 chore(release): 0.9.0
Mainly ships the subagent env-relocation fix: the relocated environment
block was landing in the last user message every turn, steering Agent
subagent calls to fable instead of haiku. Diff-based static/volatile env
split (splitEnvByVolatility) fixes it. Also includes Sol opt-in default
removal, per-model render profiles, and dashboard total scoping already
in the Unreleased log.
2026-07-14 09:33:20 -04:00
Steven Chong cd4c9efddd feat: add model-specific render profiles and recall evidence 2026-07-09 22:25:06 -04:00
teamchong 7dd54d395d release: v0.8.0 2026-07-03 22:47:19 -04:00
teamchong 2070c9697e release: v0.7.2 2026-07-03 09:02:00 -04:00
teamchong 0dce007d4c release: v0.7.1 2026-07-03 01:50:27 -04:00
teamchong bb7aaa9fec release: v0.7.0 2026-07-03 00:40:59 -04:00
teamchong f472566cc1 release: v0.6.10
Claude-Session: https://claude.ai/code/session_014gJXMzmULNmtuNhbhSdjVo
2026-06-30 12:45:08 -04:00
teamchong ec43bf5370 release: v0.6.9 2026-06-27 23:41:11 -04:00
teamchong 873cbaf94f release: v0.6.8 2026-06-26 00:17:10 -04:00
teamchong 6ca72260e8 chore: release 0.6.7 2026-06-25 22:15:20 -04:00
teamchong 7d15271587 chore: release 0.6.6 2026-06-25 19:59:37 -04:00
teamchong f1cc22b8b6 chore: release 0.6.5 2026-06-25 17:23:54 -04:00
teamchong c75179b50f chore: release 0.6.4
Anthropic-path recency anchor for collapsed history (commit 9eb66f5): banner now
warns against reopening low-N turns, plus a bounded ~300-char text pointer to the
most-recent collapsed user turn after the images. Patch — a guardrail fix on the
visible path; cache-safe (pointer sits after the cache_control breakpoint).

Adversarially reviewed: 8 findings, all low/nit — 6 are positive confirmations
(cache-safe, matcher in sync via shared constant, relocation robust to the trailing
block, GPT path unaffected, no off-by-one); 2 benign (tool-result-only user falls
back to an earlier user turn with a correct t-index; mid-word preview truncation).

474 tests pass; tsc + build clean.
2026-06-23 06:45:39 -04:00
teamchong 85f8536b67 chore: release 0.6.3
GPT autonomous agents (OpenCode/gpt-5.5) no longer lose the live request to
history imaging — the most-recent user turn is pinned as legible text between
before/after history images, with the guard echoing it. Fixes snap/confabulation
/off-task drift; validated on gpt-5.5 (stays on task, no off-task edits).

Patch, not minor: GPT is opt-in/WIP and hidden in the dashboard, and the visible
Anthropic path is byte-identical (pin commit 08a2b0a touched only the GPT path).

Also: clarifying comment on the minCollapseTokens gate (counts imageable work
only; sub-floor histories stay fully text by design — request stays legible).

473 tests pass; tsc + build clean.
2026-06-22 16:25:02 -04:00
teamchong 681f40fd5b chore: release 0.6.2 2026-06-22 11:07:24 -04:00
teamchong 023669dec4 chore: release 0.6.1 2026-06-21 17:43:03 -04:00
teamchong 62b9c872ac chore: release 0.6.0 2026-06-21 17:17:56 -04:00
teamchong dbc6d895f2 chore: release 0.5.0 2026-06-20 21:16:47 -04:00
Steven Chong 47b5e412b3 feat: cache-stable history-collapse imaging for GPT (OpenAI) + Anthropic
Collapse old conversation history into rendered PNG sections so the model
reads a compact image instead of re-billed text, while preserving prompt
caching and tool-call behavior. Measures real vs compressed token/cost.

Core:
- GPT history collapse (openai-history.ts): append-only, o200k token-length
  sectioning. Sections seal only at a tool-closed boundary (open call-id set
  empty), so a function_call and its function_call_output never split across
  the collapse cut. Fixes the OpenAI 400 "No tool call found for function
  call output with call_id ..." that hit long Responses-API sessions.
- Anthropic cache contract (history.ts): append-only per-chunk rendering;
  cache_control markers are preserved/moved, never added; chunk boundaries
  align with caller marker seams for byte-stable prefix caching.
- GPT image budget (openai.ts): detail:'original' for gpt-5.x, flagship
  vision-multiplier fix, patch cap; schema-strip preserves real descriptions.
- Savings accounting (openai-savings.ts): cached_tokens + vision-token basis.

Model scope (applicability.ts):
- Default imaged scope = claude-fable-5 + gpt-5.6.
- gpt-5.5 and claude-opus-4-8 stay opt-in: same pipeline, but they degrade
  reading dense imaged history (gist drift), so silently imaging them by
  default is wrong. Promotion is gated on an OCR/recall threshold.

Dashboard: GPT + Anthropic rendering, per-family model toggles, persisted
metrics, thumbnail-expired session UI, reflow/newline handling.

Tests: cache-alignment (GPT + Anthropic), history sectioning + tool-boundary
invariants, savings, dashboard, sessions/restart-restore. 452 passing.
2026-06-20 21:11:24 -04:00
teamchong c44cdf4258 chore: release 0.4.0 2026-06-19 16:53:11 -04:00
teamchong ef9ddac58a feat(library): caller fidelity + recoverable channel, edge-safe; trim comments
- keepSharp: caller predicate pins exact-match-critical blocks (IDs, hashes,
  paths) as text, overriding the chars/token heuristic. Reported via
  info.keptSharpBlocks. Never forces imaging; throwing predicate = false.
- emitRecoverable: optional recovery map (block -> original text + provenance)
  so a stateful caller can re-inject or re-fetch imaged content. The recover
  half of the fidelity contract; documented mitigation for lossy recall.
- edge/Workers-safe: process.env read is typeof-guarded; @napi-rs/canvas moved
  to devDependencies (atlas is build-time only, runtime PNG encoder is pure-JS).
- comments: trimmed ~1,640 lines of essay/derivation/changelog narration across
  src/ (transform.ts -73%), keeping one-line rationale; deep math points to docs/.
- New exports/types in index.ts + library.ts; +12 tests (keep-sharp, recoverable).

Build clean; 354/354 tests pass.
2026-06-19 13:02:30 -04:00
teamchong de3f756f16 deps: patch 6 dependabot advisories (vite, undici, esbuild)
Bump dev/build tooling to patched versions and add pnpm overrides
for transitive deps. All advisories are Windows-specific or
dev-server issues; none touch the runtime proxy path.

- vite    8.0.13 -> ^8.0.16   (GHSA-fx2h-pf6j-xcff high, GHSA-v6wh-9g99-6wx3 moderate)
- esbuild 0.28.0 -> ^0.28.1   (GHSA-g7r4-m6w7-qqqr low)
- undici  override ^7.28.0    (GHSA-vmh5-mc38-953g high, GHSA-pr7r-676h-xcf6 moderate; via wrangler>miniflare)
- esbuild override ^0.28.1    (via wrangler>esbuild)

pnpm audit: No known vulnerabilities found.
typecheck clean, build ok, 342/342 tests pass.
2026-06-18 23:47:54 -04:00
teamchong af1e838f0f chore: release 0.3.1 — Drive-hosted demo, keep preview thumbnail
Demo clip moved to Google Drive (committed copy was too low-res); README keeps the preview thumbnail linking to the Drive video. Restoring the thumbnail also un-breaks the demo image on the npm 0.3.0 page. Version 0.3.0 -> 0.3.1 + CHANGELOG.
2026-06-17 15:42:42 -04:00
teamchong a64768bc4e chore: release 0.3.0
Version bump 0.2.1 -> 0.3.0 and CHANGELOG for the page-ceiling, dashboard
transparency, honest-savings, and code-review-fix work on this branch.
2026-06-17 10:01:33 -04:00
teamchong 8bc1478406 v0.2.1: README scope corrections (docs-only) 2026-06-12 05:55:28 -04:00
teamchong e57cc07c1b chore(publish): rename npm package to pxpipe-proxy (registry typo-squat filter blocked pxpipe); CLI command stays pxpipe 2026-06-10 07:06:22 -04:00
teamchong 63c1eab83e chore(publish): absolute README image URL, repo/homepage/bugs fields, Fable-scoped description+keywords, drop pnpm engine 2026-06-10 06:59:02 -04:00
teamchong cb522a70fe feat(dashboard): replace Svelte bundle with AHA stack (htmx + Alpine, server-rendered fragments)
- src/dashboard/fragments.ts: server-side HTML fragment renderers reusing the
  same JSON payloads (HTML and JSON surfaces can't drift)
- node.ts/dashboard.ts: /fragments/<name> routes (header, session-summary,
  recent, latest, sessions, stats, toggle) with htmx polling + Alpine for
  local state; toggle is a POST-returning-fragment htmx swap
- vendored htmx 2.0.4 + Alpine 3.14.9 in src/dashboard/vendor.ts (offline,
  single-file npm package, no CDN)
- deleted Svelte components/stores/bundle build step; dropped svelte/vite
  devDeps; build is now just tsc + esbuild
- tests: +5 fragment contract tests (routing, toggle state, HTML escaping of
  source text, 404) - 339 total
2026-06-09 22:17:53 -04:00
teamchong a1c51b3543 feat: publish as pxpipe on npm
- rename package to pxpipe (pixelpipe is an npm security placeholder), bin: pxpipe
- move @napi-rs/canvas to dependencies (runtime dep for npx consumers)
- drop only-allow pnpm preinstall (blocked npm/npx installs)
- add prepublishOnly guard (typecheck + test + build)
- exclude sourcemaps from tarball; README quick start: npx pxpipe
2026-06-09 19:01:22 -04:00
Steven Chong 613ca3bc71 feat(proxy): support gpt 5.5 chat completions 2026-06-05 00:35:26 -04:00
Steven Chong d3992c6bad feat(applicability): enable pixelpipe for opus 4.6 2026-05-26 15:35:12 -04:00
teamchong 68826a9499 fix(build): npm run build now regenerates dashboard-bundle.ts first 2026-05-24 18:58:58 -04:00
Steven Chong 82aa35cf87 chore(deps): enforce 3-day install quarantine + bump ws to patched 8.20.1+
- .npmrc: pin minimum-release-age=4320 (3 days) for supply-chain
  defence; new versions can't be installed until they've been
  on the registry long enough for typo-squat / compromise to be
  caught and yanked.
- minimum-release-age-exclude=@cloudflare/* so first-party
  packages don't block our own iteration.
- pnpm.overrides forces ws>=8.20.1 transitively via miniflare,
  closing GHSA-58qx-3vcg-4xpx (moderate, uninitialized memory
  disclosure in ws). Dev-only chain, no prod runtime impact, but
  worth keeping clean for dependabot.
2026-05-22 23:45:55 -04:00
teamchong 45c83dedb5 feat(dashboard): rewrite dashboard in Svelte (#25)
Replace the hand-rolled dashboard with a Svelte component tree (App +
Sessions / StatsTable / LatestPng / RecentRequests / StatsHeader /
Cleanup / CompressionToggle / ToastTray), move the API layer into
lib/, and split state into stores/.

Add a dedicated dashboard build (`build:dashboard-ui` + a separate
tsconfig.dashboard.json) so dashboard sources typecheck independently
of the proxy core, which previously broke the root `tsc` build.
2026-05-21 21:43:28 -04:00
Steven Chong 0aa2cce88f Expose pixelpipe library API 2026-05-20 23:47:32 -04:00
teamchong d65cc1bf5c chore(deps): bump wrangler 3.114.17 → 4.92.0
Addresses GHSA-vmjp-67rh-pgjc (undici via wrangler <4.x).
Major jump 3 → 4, but wrangler.toml schema unchanged
(compatibility_date, compatibility_flags, vars all still valid)
and build/typecheck/test all clean.

Held at 4.92.0 (4.93.0 is inside the 3-day minimumReleaseAge gate).
2026-05-20 09:28:14 -04:00
teamchong b14a7d981b chore(deps): bump vitest 1.6.1 → 4.1.6 (+ explicit vite 8.0.13)
Addresses GHSA-9crc-q9x8-hgqq, GHSA-jcfh-c3jc-r2q6 (vitest <2.1.9).
Vitest 4 requires Vite 6+, so add vite as an explicit dev dep
(was previously transitive). 273 tests still pass clean.
2026-05-20 09:24:57 -04:00
teamchong d309914d8f chore(deps): bump esbuild 0.21.5 → 0.28.0
Addresses GHSA-67mh-4wv8-2f99 (esbuild dev server allowed any website
to send requests and read responses, patched in ≥0.25.0). Dev-only —
we use esbuild as the bundler in scripts/build.mjs, never as a server.

Build, typecheck, and 273 tests all clean.
2026-05-20 09:22:22 -04:00
teamchong 241cdbb6aa build: pin pnpm@10.21.0 as the package manager
- Add `packageManager` field so corepack uses the pinned version
- Add `preinstall: npx only-allow pnpm` guard to block accidental
  `npm install` (npm exits non-zero with a clear redirect)
- Add `engines.pnpm: >=10` requirement
- Bundles the previously-uncommitted restart + test:restart script
  entries (already in use via the diagnostic-instrumentation slice)
2026-05-18 19:48:05 -04:00
teamchong f91c149d05 Port to TypeScript with dual Node + Cloudflare Workers targets
Runtime is pure Web Standard APIs (fetch, Request, Response, Uint8Array,
CompressionStream, crypto.subtle, btoa) — zero runtime dependencies.

Core (src/core/, runs identically on Node 18+ and Workers):
  - atlas.ts     auto-generated 9x15 JBM glyph atlas, base64-inlined (17KB)
  - png.ts       minimal grayscale PNG encoder via CompressionStream
  - render.ts    text → packed PNG, soft-wraps at 100 cols, ≤1568px tall
  - transform.ts request body rewriter (system + tool docs → image blocks)
  - proxy.ts     fetch-handler that transforms then forwards to Anthropic
  - types.ts     Anthropic Messages API types we touch

Adapters:
  - src/node.ts     node:http server + CLI flag parsing
  - src/worker.ts   export default { fetch } for wrangler dev/deploy

Build tooling:
  - scripts/gen-atlas.ts   @napi-rs/canvas → atlas.ts (build-time only)
  - scripts/build.mjs      esbuild Node bundle; wrangler handles Worker
  - tsconfig.json          strict, ES2022, Workers types

Tests (vitest): 8 passing — PNG signature, base64 round-trip, single +
multi-image renders, transform no-op + compress paths, billing-line strip,
tool fold + stub.

E2E smoke: 16K char system → 2 PNGs (36KB) → mock upstream, 34ms.

Next: replace docs, then verify byte-output parity against legacy/python.
2026-05-18 15:33:23 -04:00
teamchong f20207cd7b Rename: claude-image-proxy -> pixelpipe (Tier 1: code + docs)
Project rename for the Show HN launch with framing:
  'pixelpipe — what if Opus saw a UI instead of just append-only logs?'

Renamed everywhere:
  - kebab-case 'claude-image-proxy' -> 'pixelpipe' (42 occurrences)
  - snake_case 'claude_image_proxy' -> 'pixelpipe'  (5 occurrences)
  - 14 files touched: package.json, Cargo.toml, Cargo.lock, *.md,
    bin/cli.js, scripts/install.js, src/proxy.py, src/rust/src/main.rs,
    src/rust/examples/{render_sample,transform_only,diff_render}.rs,
    src/zig/build.zig

Effects on build artifacts:
  - npm package name -> 'pixelpipe'
  - Rust binary name -> target/release/pixelpipe (was claude-image-proxy)
  - Python cache dir -> ~/.cache/pixelpipe/ (was ~/.cache/claude-image-proxy/)

NOT YET DONE in this commit (Tier 2+3, handled in next commit):
  - Repo on-disk directory still ~/Downloads/repos/claude-image-proxy/
  - Cache dir on disk still ~/.cache/claude-image-proxy/ — Python proxy
    currently writes here. Will be migrated alongside the running services
    in a coordinated stop/move/restart sequence.

Validation: scripts/diff_transform.py still produces exactly 1 structural
diff (the PNG bytes, expected — different fonts Python/Menlo vs
Rust/JetBrains Mono). No regression from the rename.
2026-05-18 14:16:48 -04:00
teamchong 9fddbeb28a Initial commit: working Python proxy
Token-saving HTTP proxy for Claude Code that renders system prompt + tools
as 5pt Menlo monospace images. Achieves 65-73% token reduction with 100%
reasoning quality preserved on Opus 4.7.

Production state at this commit:
- src/proxy.py: 972 lines, battle-tested with 46+ real Claude Code sessions
  observed (~551k tokens saved, ~$8.27 in stats.json as of commit time)
- bin/cli.js: Node wrapper that spawns Python proxy on port 47821
- scripts/gen_atlas.py: generates the bundled Menlo 5pt glyph atlas
- scripts/install.js: postinstall — verifies Python + Pillow + httpx
- src/zig/: earlier Zig 0.16 renderer (kept for reference, not built)
- CLAUDE.md, HANDOFF.md: contributor notes
- package.json: npm entry point, version 0.1.0

Known issue (deferred for separate fix):
  src/proxy.py:125 — `tallest = max(lines_per_col, last_col_lines) if
  c_needed == 1 else lines_per_col` pads every single-column image to
  full MAX_EDGE=1568 height regardless of content, wasting image-token
  budget for small inputs. Tight bounding would improve savings further.

This is the rollback point. Any subsequent changes (Rust port, Python
fixes, etc.) build on this proven baseline.
2026-05-18 11:52:02 -04:00