Persistent multi-turn opencode backend: one `opencode serve` HTTP server per BooCoder process, one opencode session per BooCode session (resumed on switch-back), single SSE read loop demuxed by session id. - backends/opencode-server.ts: AgentBackend implementation — spawn with waitForReady, session.next.* SSE event translation (text/reasoning/tool deltas), Paseo-ported reasoning dedup (streamedPartKeys), promptAsync fire-and-forget settled by session.idle, per-turn inactivity watchdog (180s) + reconnect reconciliation via session.messages, stale-session guard (crashed-not-resumed + config_hash fingerprint on model). - dispatcher.ts: opencode routes to pool backend (ensureSession→prompt); per-session concurrency Map replaces global running boolean (1.9); model coalesce (empty→DEFAULT_MODEL) + llama-swap/ prefix for opencode; diff-supersede (DELETE+INSERT pending_changes by session, stamp agent). - worktrees.ts: ensureSessionWorktree (session-keyed, captures base_commit, persists to session_worktrees); diffWorktree gains optional baseRef. - agent-probe.ts: mergeLlamaSwap branch fetches /v1/models, prefixes with llama-swap/, populates opencode's available_agents.models (was 0). - provider-snapshot.ts: export fetchLlamaSwapModels for probe reuse. - schema.sql: session_worktrees + agent_sessions tables (Phase 0) + config_hash column on agent_sessions, pending_changes.agent column. - package.json: @opencode-ai/sdk ~1.15.0 (resolved 1.15.12). Known Phase 1 limitation: single SSE stream scoped to most-recent session's directory; concurrent opencode sessions in different worktrees collide (warning logged, watchdog prevents hang). Phase 2 moves to per-session SSE. Smoke 1 verified: two turns in one session, both produce real tokens, same agent_session_id reused, same server port, turn 2 is 9x faster (no spawn). goose/qwen/claude paths untouched (runExternalAgent md5 identical). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
36 lines
953 B
JSON
36 lines
953 B
JSON
{
|
|
"name": "@boocode/coder",
|
|
"version": "2.0.0",
|
|
"private": true,
|
|
"type": "module",
|
|
"main": "dist/index.js",
|
|
"scripts": {
|
|
"dev": "tsx watch src/index.ts",
|
|
"build": "tsc && node -e \"import('node:fs').then(fs=>fs.copyFileSync('src/schema.sql','dist/schema.sql'))\"",
|
|
"start": "node dist/index.js",
|
|
"cli": "tsx src/cli.ts",
|
|
"typecheck": "tsc --noEmit",
|
|
"test": "vitest run"
|
|
},
|
|
"dependencies": {
|
|
"@agentclientprotocol/sdk": "^0.22.1",
|
|
"@boocode/server": "workspace:*",
|
|
"@fastify/static": "^7.0.4",
|
|
"@opencode-ai/sdk": "~1.15.0",
|
|
"@fastify/websocket": "^10.0.1",
|
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
"fastify": "^4.28.1",
|
|
"postgres": "^3.4.4",
|
|
"ws": "^8.18.0",
|
|
"zod": "^3.23.8"
|
|
},
|
|
"devDependencies": {
|
|
"@types/node": "^20.14.10",
|
|
"@types/ws": "^8.5.10",
|
|
"tsx": "^4.16.2",
|
|
"typescript": "^5.5.0",
|
|
"vitest": "^3.0.0"
|
|
},
|
|
"license": "AGPL-3.0-only"
|
|
}
|