[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-81648":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":9,"language":10,"languages":9,"totalLinesOfCode":9,"stars":11,"forks":12,"watchers":13,"openIssues":14,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":13,"stars7d":13,"stars30d":13,"stars90d":14,"forks30d":14,"starsTrendScore":15,"compositeScore":16,"rankGlobal":9,"rankLanguage":9,"license":17,"archived":18,"fork":18,"defaultBranch":19,"hasWiki":20,"hasPages":18,"topics":21,"createdAt":9,"pushedAt":9,"updatedAt":22,"readmeContent":23,"aiSummary":24,"trendingCount":14,"starSnapshotCount":14,"syncStatus":12,"lastSyncTime":25,"discoverSource":26},81648,"toll-free-harness","WeZZard\u002Ftoll-free-harness","WeZZard","Interactive PTY harness for local coding agents.",null,"TypeScript",22,2,1,0,3,44.03,"Apache License 2.0",false,"main",true,[],"2026-06-12 04:01:34","# toll-free-harness\n\nFull-featured user interaction simulator for terminal-based coding agents.\n\n`toll-free-harness` models the complete user interaction surface of a coding agent CLI — prompting, answering questions, reviewing plans — as typed APIs. It spawns the agent in a local PTY, observes events through read-only hooks, and responds through the same keystroke channel a real user would.\n\nCurrently supports **Claude Code**. The framework is designed to add support for other coding agents whose headless modes do not fully expose the interactive user experience.\n\nThe name is a joke about toll booths around developer workflows.\n\n## What this project is not\n\nNot an API proxy, credential-sharing service, or billing workaround. Users run their own local tools with their own accounts and must comply with those tools' terms.\n\n## Migrating from claude -p\n\nCopy the migration guide and paste it to your coding agent:\n\n```bash\n# macOS\ncurl -s https:\u002F\u002Fraw.githubusercontent.com\u002FWeZZard\u002Ftoll-free-harness\u002Fmain\u002FMIGRATION.md | pbcopy\n\n# Linux\ncurl -s https:\u002F\u002Fraw.githubusercontent.com\u002FWeZZard\u002Ftoll-free-harness\u002Fmain\u002FMIGRATION.md | xclip -selection clipboard\n```\n\nAsk your agent to convert your `claude -p` scripts to use toll-free-harness.\n\n## Quick start — CLI\n\nNo install needed. Replace `claude -p` with:\n\n```bash\nnpx toll-free-harness claude -- -p \"fix the failing tests\"\nnpx toll-free-harness claude -- -p \"explain this error\" --allowedTools \"Read\"\ncat build.log | npx toll-free-harness claude -- -p \"what went wrong?\"\n```\n\nWhen `-p` is detected, the tool routes the session through an interactive PTY harness. Without `-p`, it passes through to `claude` directly.\n\n## Quick start — Library API\n\n```bash\npnpm add toll-free-harness\n```\n\n```typescript\nimport { ClaudeCodeSession } from \"toll-free-harness\";\n\nconst session = new ClaudeCodeSession({\n  args: [\"--model\", \"opus\"],\n  cwd: \"\u002Fpath\u002Fto\u002Fproject\",\n  prompt: \"Fix the failing tests\",\n});\n\n\u002F\u002F Handle the agent's questions — return which option to select\nsession.onAskUserQuestion(async (event) => {\n  console.log(event.text);\n  console.log(event.questions[0]?.options.map((o, i) => `${i}: ${o.label}`));\n  return { selectedIndex: 0 };\n});\n\n\u002F\u002F Handle plan review — approve or reject with feedback\nsession.onExitPlanMode(async (event) => {\n  console.log(event.planText.slice(0, 200));\n  return { decision: \"approve\" };\n});\n\nconst result = await session.run();\n\n\u002F\u002F Send a follow-up prompt (with optional images)\nsession.sendPrompt(\"Now add tests for the fix\", {\n  images: [\"\u002Ftmp\u002Fscreenshot.png\"],\n});\n```\n\n### User interactions\n\nThe framework models three user interactions as dedicated typed APIs:\n\n| Interaction | API | You provide | Library does |\n|---|---|---|---|\n| **Prompting** | `sendPrompt(text, options?)` | Text + optional image paths | Injects keystrokes into PTY |\n| **Answering questions** | `onAskUserQuestion(handler)` | `{ selectedIndex }` | Navigates and selects the option |\n| **Reviewing plans** | `onExitPlanMode(handler)` | `{ decision: \"approve\" }` or `{ decision: \"reject\", feedback }` | Approves or rejects via keystrokes |\n\nThere is no raw `write()` — the library translates your typed decisions into the correct keystrokes internally.\n\n### Hook listeners (read-only)\n\nObserve agent events without sending data back:\n\n```typescript\nsession.onPreToolUse(\"Bash\", (event) => {\n  console.log(`Running: ${event.toolInput?.command}`);\n});\n\nsession.onPostToolUse(\"*\", (event) => {\n  console.log(`Tool ${event.toolName} completed`);\n});\n\nsession.onStop(() => {\n  console.log(\"Session ended\");\n});\n```\n\nAvailable: `onPreToolUse`, `onPostToolUse`, `onPermissionRequest`, `onStop`, `onUserPromptSubmit`. All are read-only — hooks return `{}` internally and never send data back to the agent.\n\n### Event guardrail\n\nWait for specific events with timeouts for deterministic test flows:\n\n```typescript\nconst event = await session.guardrail.expect(\n  { kind: \"pre_tool_use\", toolName: \"Bash\" },\n  10_000,\n);\n```\n\n### Timing model\n\n`PreToolUse` and `Stop` hooks are **blocking** — the agent waits for them. Keystrokes injected during a blocking hook callback buffer in PTY stdin and are consumed by the UI after the hook returns. `PermissionRequest` is **non-blocking** — the dialog renders in parallel.\n\n## How it works\n\n1. `run()` generates a temporary plugin in `\u002Ftmp\u002Ftoll-free-plugin-\u003Cuuid>\u002F` containing a manifest, hook definitions, and a bundled hook client\n2. Starts an HTTP server on a Unix domain socket (`\u002Ftmp\u002Ftoll-free-\u003Cuuid>.sock`)\n3. Spawns the agent in a PTY with `--plugin-dir \u002Ftmp\u002Ftoll-free-plugin-\u003Cuuid>\u002F` plus your args and prompt\n4. The agent loads the plugin and fires hooks as it runs. The hook client posts events to the socket.\n5. Your interaction handlers and listeners receive events; responses go through PTY keystrokes\n6. On exit, the socket and plugin directory are cleaned up\n\nNo user-scope settings are modified. The plugin is self-contained and session-scoped.\n\n## Cross-platform\n\nUses Node.js `http.request({ socketPath })` for IPC — works on macOS, Linux, and Windows 10 1803+.\n\n## License\n\nApache-2.0\n","toll-free-harness 是一个用于本地编码代理的交互式 PTY 模拟器。它通过类型化的 API 模拟完整的用户交互界面，包括提示、回答问题和审查计划等功能，并在本地 PTY 中启动代理，通过只读钩子观察事件并通过相同的按键通道响应。目前支持 Claude Code 代理，框架设计上也便于扩展支持其他类似的编码代理。适用于需要模拟终端编码代理完整交互体验的开发场景，如自动化测试、代码审查等。无需安装，直接使用 npx 即可快速开始，同时也提供了 TypeScript 库 API 方便集成到现有项目中。","2026-06-11 04:05:50","CREATED_QUERY"]