CodeOpen Chat — VS Code ExtensionA VS Code extension that adds an OpenCode CLI chat panel to the sidebar — no Copilot Chat What's New in v1.1.0
Official docs: opencode.ai/docs | VS Code WebviewView API Quick StartPrerequisites: Node.js >=18 and OpenCode CLI installed.
FeaturesChat Panel (
|
| Command | Title |
|---|---|
freecli.selectModel |
CodeOpen: Select Free Model |
freecli.newSession |
CodeOpen: New Conversation |
freecli.showHistory |
CodeOpen: Conversation History |
freecli.retryDetection |
CodeOpen: Retry CLI Detection |
freecli.showDiagnostics |
CodeOpen: Show Diagnostics |
freecli.reviewPatch |
CodeOpen: Review Proposed Changes |
freecli.applyPatch |
CodeOpen: Apply Approved Changes |
freecli.rejectPatch |
CodeOpen: Reject Proposed Changes |
Title-bar buttons (when view == freecli.main): New Chat, Retry CLI Detection, Conversation History
Settings (freecli.*)
| Setting | Default | Description |
|---|---|---|
opencodePath |
"" |
Custom OpenCode executable path; empty = auto-detect via PATH |
patchMode |
reviewBeforeApply |
Or directEdit (warns; review after) |
requirePatchApproval |
true |
Confirm before apply |
autoDetectInstallation |
true |
Detect CLI on activation |
modelCatalogCacheDuration |
3600 |
Model catalog cache lifetime (seconds) |
requestTimeoutSec |
300 |
Stop stalled run after N sec; 0 disables |
firstByteNoticeSec |
30 |
"Still waiting" notice after N sec; 0 disables |
maxContextCharacters |
8000 |
Selection truncation limit |
includeSurroundingCode |
true |
Include enclosing function/imports when available |
showToolActivity |
true |
Show tool progress in chat |
preserveSessions |
true |
Save minimal metadata (model, session id, workspace) in globalState |
debugLogging |
false |
Verbose output channel; never logs secrets |
The free-only policy is not user-configurable (cannot relabel paid models as free).
Free-Model Policy
A model is included only when all conditions hold:
input == 0 && output == 0(plus zero cache prices)- Provider is accessible
- No paid auth/subscription required
- Fresh cache
Excluded (fail closed): paid, input-free-output-paid, unknown, stale, conflicting, quota-then-charge, and locked entries.
Verified 1.18.18: 49 eligible / 397 excluded on test machine. Re-validated before every session.
Supported OpenCode capabilities: detection (--version/--help), catalog (models --verbose + costs), programmatic --model, sessions/resume (--session/--continue), NDJSON streaming, cancellation, patch capture with native diff. serve REST and ACP are intentionally unused in v1 (run --format json one-shot per message).
Troubleshooting
| Issue | Solution |
|---|---|
| CLI not found | Run CodeOpen: Retry CLI Detection, then CodeOpen: Show Diagnostics for versions, PATH, and install hints. Or set freecli.opencodePath to the full executable path. |
| No free models listed | Check Debug log / output channel for catalog refreshStatus and expiry. Stale or conflicting costs are excluded by design — retry after opencode models --verbose works. |
| "Still waiting" for minutes | Free-model queues during OpenCode inference incidents are normal — see status.opencode.ai. Adjust freecli.firstByteNoticeSec / freecli.requestTimeoutSec as needed. |
| No patch / can't undo | Review lists only files the agent touched on the current run. Reject restores pre-run state in git workspaces (agent-touched files only) and non-git workspaces (snapshot restore). |
Known Limitations
- WebviewView replica — not the built-in Chat view; cannot reuse Copilot's
@participants, variables, oreditor:pasteactions. Selection context attaches automatically at send time. - One-shot per message — cold start each turn (
run --format json); no persistentserveconnection or ACP session loop. - Model switching starts a new conversation (history is preserved, not silently dropped).
- "Free" = verified
$0/$0at catalog time — quotas/capacity can change; re-validated before every session, fail closed. Zen-freemodels are "free for a limited time" per OpenCode docs, not permanent. - Rollback scope — restores only files the agent touched (
git checkout HEAD -- path,git cleanfor new files); unrelated files untouched; unsafe paths refused. Non-git workspaces restore file contents from pre-run snapshot.
Tests
npm test # node:test — 96 tests, 30 suites, no network/paid API required
npm run lint # node --check src/extension.js
Coverage:
- Detection (installed/missing/bad-exit)
- Eligibility (zero-cost in; paid/input-free-output-paid/unknown/stale/subscription/locked/quota out)
- Selection (single/multiline/none/unsaved/languages)
- Patches (valid/traversal/stale/empty/conflict/approval/numstat, staged fallback on unborn HEAD, request-scoped review)
- OpenCode streaming (deltas, split chunks, malformed tolerance, non-zero exit, arg-array safety, workspace gate)
- Sessions (isolation, minimal persistence)
- Chat panel (XSS escaping, layout regions, CSP/offline, provider routing, stable thinking gutter, brand icons)
Security
- No shell execution —
spawn(exe, argsArray)only; user text stays a single argv element - Zero external resources — inline CSS/JS, nonce CSP; all AI text HTML-escaped and rendered by minimal local markdown formatter
- Workspace-contained patches —
path.relativecontainment,..rejection, absolute-escape block; symlinks resolved viapath.resolve - No secrets stored —
globalStatekeeps only model/session-id/workspace; logs redact*_KEY/SECRET/TOKEN/PASSWORDandBearervalues - AI output treated as untrusted — never executed; tool activity shown only from real CLI events
File Map
src/
├── extension.js # Entry point
├── views/chatPanel.js # WebviewView panel
├── chat/contextBuilder.js # Editor context → prompt
├── adapters/
│ ├── cliAdapter.js # Generic CLI wrapper
│ └── openCodeAdapter.js # OpenCode-specific logic
├── discovery/
│ ├── cliDetector.js # CLI detection
│ ├── modelCatalog.js # Model catalog loading/caching
│ └── freeModelPolicy.js # Free-model eligibility
├── process/
│ ├── processManager.js # Process lifecycle
│ └── cancellationManager.js # SIGTERM/SIGKILL handling
├── sessions/
│ ├── sessionManager.js # Session state
│ └── chatHistory.js # Conversation persistence
├── patches/
│ ├── patchManager.js # Patch orchestration
│ ├── diffProvider.js # Native diff integration
│ ├── patchValidator.js # Path safety validation
│ ├── applyPatch.js # Apply changes
│ └── rollbackManager.js # Reject/restore
├── security/approvalManager.js # User confirmations
└── utils/
├── logging.js # Output channel logging
└── platform.js # OS-specific helpers
test/*.test.js # 96 tests, 30 suites