Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
20b8102
feat(cli): add oclite UI components for task panel (#19, #20, #21)
randomm Jan 26, 2026
e511c33
fix(cli): resolve context error and harden security in oclite UI
randomm Jan 26, 2026
8b4b111
fix(cli): suppress verbose logging in oclite TUI
randomm Jan 26, 2026
025f95e
fix(cli): fix response rendering and add Escape cancellation in oclite
randomm Jan 26, 2026
75ddfd0
fix(tui): remove async race condition in prompt exit handler
randomm Jan 26, 2026
50ff042
feat(tool): add cancel_task for stopping background tasks (#54)
randomm Jan 26, 2026
dcf3f84
fix(cli): fix response streaming and Escape buffer clearing in oclite
randomm Jan 26, 2026
764e485
fix(cli): use SDK event stream for real-time response streaming in oc…
randomm Jan 26, 2026
f6bd7d4
fix(cli): stream response chunks in real-time instead of buffering
randomm Jan 27, 2026
2ace645
fix(cli): revert to Bus.subscribe with debug logging for streaming di…
randomm Jan 27, 2026
c78e1e5
fix(cli): fix Promise.race early exit in streaming wake/yield loop
randomm Jan 27, 2026
119053e
chore(cli): remove debug logging from oclite session
randomm Jan 27, 2026
1fd1128
fix(tool): fix cancel_task to abort subagent session instead of paren…
randomm Jan 27, 2026
39a5c91
feat(cli): add oclite commands, agent switching, custom commands, and…
randomm Jan 27, 2026
2b3a209
fix(cli): fix shift-tab inline prompt update and custom command crash…
randomm Jan 27, 2026
3db9349
fix(cli): fix custom command crash and select UI cursor positioning i…
randomm Jan 27, 2026
83658c8
fix(cli): add error handling and debug logging for custom command cra…
randomm Jan 27, 2026
082b8fc
fix(cli): dynamic WASM discovery in oclite build and fix check_task p…
randomm Jan 27, 2026
14244a5
fix(cli): oclite UX improvements — remove debug noise, compact tools,…
randomm Jan 27, 2026
0a96085
feat(cli): add markdown rendering, rich tool display, and spinner ela…
randomm Jan 27, 2026
07548cb
fix(cli): add WASM fallback in oclite build when bundler omits assets
randomm Jan 27, 2026
4659b6c
feat(cli): scroll region layout with fixed bottom panel (#72)
randomm Jan 27, 2026
95e5e7f
revert(cli): remove scroll region layout — adopt append-only output m…
randomm Jan 27, 2026
1a20287
fix(cli): preserve session across REPL turns — stop resetting current…
randomm Jan 27, 2026
0e2ebde
fix(cli): improve oclite output formatting, spinner timing, and tool …
randomm Jan 27, 2026
d9b2d66
fix(cli): render spinner immediately on Enter and clean up cursor/too…
randomm Jan 27, 2026
a0338d1
docs: add QA workflow section to AGENTS.md
randomm Jan 27, 2026
1fef395
fix(cli): pass input in tool_end chunks and simplify overwrite logic …
randomm Jan 27, 2026
85c396e
feat(cli): add Live Block rendering for parallel tool display (#82)
randomm Jan 27, 2026
ab9fad5
fix(cli): fix double tool name and add dedup for repeated tools (#83,…
randomm Jan 27, 2026
369a296
fix(cli): clear screen on boot, show bootstrap spinner, fix orphaned …
randomm Jan 27, 2026
41e280d
test(cli): add test suites for liveblock, summarizeInput, and markdow…
randomm Jan 27, 2026
1ac50cd
feat(cli): add word wrap with margins and force eager bootstrap init …
randomm Jan 27, 2026
1923c5e
fix(cli): force MCP eager init during bootstrap spinner (#57)
randomm Jan 27, 2026
03506c5
feat(cli): add todo list display in Live Block (#82)
randomm Jan 27, 2026
d3fb35d
feat(cli): improve /models with recent models sorting and screen-pres…
randomm Jan 27, 2026
f325255
feat(cli): add subagent output panel with Ctrl+X navigation (#88)
randomm Jan 27, 2026
ea5296e
fix(session): remove Claude Code references to prevent path hallucina…
randomm Jan 27, 2026
126240a
fix(session): add authorization and race condition guards to cancelBa…
randomm Jan 27, 2026
e10bca2
docs(agents): add mandatory style guide compliance section (#91)
randomm Jan 27, 2026
4367b36
test(cli): add comprehensive test suites for wrap, input, panel, and …
randomm Jan 27, 2026
0ce8c74
fix(cli): fix justified text spacing by using comprehensive ANSI rege…
randomm Jan 27, 2026
5982d0f
fix(cli): buffer streaming text to prevent per-chunk padding (#92)
randomm Jan 27, 2026
51540b1
fix(cli): preload commands at bootstrap and fix tool_end ID fallback …
randomm Jan 28, 2026
ce74e69
feat(cli): improve UX with spinner, task progress, and theme colors (…
randomm Jan 28, 2026
cdada7a
fix(project): prevent AsyncLocalStorage context escape in Instance.pr…
randomm Jan 28, 2026
eff73a8
fix(project): defer State.create root() evaluation to prevent module-…
randomm Jan 28, 2026
9c4ad06
fix(cli): combine dim style with gray color for visible tool text
randomm Jan 28, 2026
3b00ad6
fix(cli): tools on new lines and deduplicate repeated tool calls (#10…
randomm Jan 28, 2026
d9348a5
feat(cli): implement todo toggle visibility with ctrl+t (#97)
randomm Jan 28, 2026
082078e
feat(memory): deep remory integration with auto-search and auto-store…
randomm Jan 28, 2026
450bee8
fix(cli): task rendering and init progress improvements (#103, #105)
randomm Jan 29, 2026
a7e013a
fix(cli): filter /models to show only authenticated providers (#106)
randomm Jan 29, 2026
9e6f688
fix(cli): permission-denied visual, subagent output, and test fixes (…
randomm Jan 29, 2026
1b44b9c
refactor(tool): simplify rg permission to single 'rg' permission (#107)
randomm Jan 29, 2026
d6f0886
fix(cli): task visual feedback, child session linking, and auto-wakeu…
randomm Jan 29, 2026
df8448a
fix(tool): prevent shell injection and path hallucination (#98)
randomm Jan 29, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,26 @@ If the type system complains, fix the underlying issue.

If work must be deferred, create a GitHub issue. The issue IS the TODO.

### Style Guide Compliance

**MANDATORY: `STYLE_GUIDE.md` is not advisory — it is a blocking requirement.**

All code must comply with style rules. Violations are **blocking** and will fail adversarial review. No exceptions.

**Common violation categories:**

- No else statements — use early returns
- No destructuring — preserve context
- No let statements — use const with ternary operators
- No semicolons in code
- No type bypasses (`as any`, `@ts-ignore`, `@ts-expect-error`)
- Prefer single-word variable names
- Use Bun APIs (`Bun.file()`, `Bun.write()`)
- No `try`/`catch` where early returns suffice
- Keep functions flat and composable

**Reference:** See the "TypeScript Style Guide" section below for detailed code examples, and `STYLE_GUIDE.md` for complete rules and rationale.

---

## Pre-Push Verification
Expand Down Expand Up @@ -260,10 +280,17 @@ function process(data: unknown): Result {
### No semicolons, minimal trailing commas

```typescript
// Good
const config = {
name: "opencode",
version: "1.0.0",
}

// Bad
const config = {
name: "opencode",
version: "1.0.0",
};
```

---
Expand Down Expand Up @@ -328,6 +355,59 @@ gh pr create --base dev

---

## QA Workflow

### Binary Build & Test Loop

All feature work is validated by building and manually testing binaries. The cycle:

```
implement → build binary → manual QA → file bugs → fix → rebuild
```

### Build Commands

```bash
# oclite (auto-installs to ~/bin/oclite with codesign)
cd packages/opencode
bun run build:lite

# Full opencode binary
cd packages/opencode
bun run build --single
cp dist/opencode-darwin-arm64/bin/opencode ~/bin/opencode
codesign --force --deep --sign - ~/bin/opencode
xattr -cr ~/bin/opencode
```

### Agent Pipeline

Every code change follows this pipeline — no exceptions:

```
@developer → @adversarial-developer → fix loop → @git-agent (commit+push) → rebuild binary
```

Never skip adversarial review. Never commit before adversarial passes.

### Research First

For non-trivial features, dispatch `@explore` to research how existing open-source projects solve the same problem. Clone repos to `/tmp` and analyze actual source code — don't rely on documentation alone.

### QA Bug Tracking

- All bugs found during QA get GitHub issues immediately
- Issues reference the specific commit and include reproduction steps
- Screenshots when applicable

### Feature Branch Discipline

- All work stays on the feature branch until manual QA is complete
- Push frequently — the PR is already open
- Don't merge to dev until QA passes

---

## Auto-Merge Policy

After code-review-specialist approval AND CI passes:
Expand Down
125 changes: 125 additions & 0 deletions BUG_FIXES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Bug Fixes #101 and #102

## Summary

Fixed two display bugs in the oclite TUI:

1. Tools appearing inline with prose text
2. check_task tool spamming the output with repeated identical calls

## Bug #101: Tools Render Inline with Prose

### Problem

Tools appeared on the same line as prose text, making output hard to read:

```
most impactful ones first. ◇ bash gh issue create...
```

### Root Cause

When `flushLineBuffer()` was called before rendering a tool, it wrote prose text directly to stdout without ensuring the tool appeared on a new line. The `logUpdate` from liveblock would then overlay the tool on the same line.

### Fix

Modified `flushLineBuffer()` to accept an optional `addNewline` parameter. When flushing prose before a tool starts, a newline is added to ensure tools render on their own line.

**File:** `packages/opencode/src/cli/lite/index.ts`

```typescript
function flushLineBuffer(addNewline = false) {
if (!lineBuffer) return
const rendered = md.render(lineBuffer)
const wrapped = wrap(rendered, MAX_WIDTH)
write(padLines(wrapped))
if (addNewline) write("\n")
lineBuffer = ""
}

// Usage before tool_start
if (chunk.type === "tool_start" && chunk.tool?.trim()) {
flushLineBuffer(true) // Add newline before tool
// ... tool rendering
}
```

### Testing

- Verified tools now render on separate lines from prose
- Text rendering still works correctly for regular prose chunks
- Multiple tools render on separate lines as expected

## Bug #102: check_task Spam

### Problem

When a task is polled repeatedly (e.g., checking status every few seconds), the output showed the same tool ID 20+ times:

```
◇ check_task Checking task abc123
◇ check_task Checking task abc123 (×2)
◇ check_task Checking task abc123 (×3)
...
```

### Root Cause

The deduplication logic tracked tool names + summaries, but created new tool IDs each time (via `++toolCounter`). When polling the same task, each poll generated:

- Same tool name (`"check_task"`)
- Same summary (task ID string)
- Same `lastToolKey`
- Different tool IDs (`check_task-1`, `check_task-2`, ...)

Each new tool ID created a new entry in the live block, causing spam and wasting re-renders.

### Fix

Simplified the deduplication to maintain a single tool ID across updates. When `tool_start` is called with the same `callID` or tool key, the existing tool ID is reused and only the label is updated.

**File:** `packages/opencode/src/cli/lite/index.ts`

```typescript
if (chunk.type === "tool_start" && chunk.tool?.trim()) {
flushLineBuffer(true)
const tool = chunk.tool.trim()
const arg = summarizeInput(tool, chunk.input)
const summary = arg || ""
const key = `${tool}:${summary}`

// Increment dedup count or reset for new tools
if (key === lastToolKey) {
dedupCount++
} else {
dedupCount = 1
lastToolKey = key
lastToolId = chunk.callID || `${tool}-${++toolCounter}`
}

// Always update the same tool ID
const label = dedupCount > 1 ? `${summary} (×${dedupCount})` : summary
block.toolStart(lastToolId, tool, label)
// ...
}
```

### Testing

- Repeated `check_task` calls for same task now show single entry
- Label increments show polling activity: `Checking task abc123 (×3)`
- Different task IDs create separate tool entries
- Non-polling tools (bash, read, etc.) unaffected

## Verification

All tests pass:

```bash
cd packages/opencode
bun run typecheck # 0 errors
bun test # 1334 tests pass
bun run build:lite # Binary built and installed
```

Binary rebuilt and installed to `~/bin/oclite` with fixes applied.
90 changes: 90 additions & 0 deletions RENDERING_FIXES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
## oclite Terminal UI Rendering Fixes

### Changes Made to `/Users/janni/git/opencode/packages/opencode/src/cli/lite/liveblock.ts`

#### Fix 1: Prevent Duplicate Task Tool Rendering (Line 46)

**Before:**

```typescript
for (const tool of tools.values()) {
const sep = tool.summary ? " " : ""
const isTask = tool.name === "task"
// ... conditional logic with isTask
}
```

**After:**

```typescript
for (const tool of tools.values()) {
if (tool.name === "task") continue // Skip task tools - they're rendered separately
const sep = tool.summary ? " " : ""
// ... simplified logic without isTask
}
```

**Why:** Task tools were being added to both `tools` and `tasks` Maps, causing them to render twice - once in the tools loop (with ◇ icon) and once in the tasks loop (with spinner).

#### Fix 2: Correct Multi-line Animation (Line 113)

**Before:**

```typescript
logUpdate(lines.join("\n") + "\n")
```

**After:**

```typescript
logUpdate(lines.join("\n"))
```

**Why:** The `log-update` library internally adds a trailing newline (see line 140 of `node_modules/log-update/index.js`). Adding one ourselves caused incorrect line counting, making cursor positioning fail during animated updates. This resulted in only the last line being visible during animation.

### Verification Steps

1. **Rebuild the binary:**

```bash
cd /Users/janni/git/opencode/packages/opencode
bun run build:lite
```

2. **Test in a real terminal (requires TTY):**

```bash
~/bin/oclite 'Write hello.txt with Hello World'
```

3. **Expected improvements:**
- ✅ No duplicate task tool rendering
- ✅ All lines visible during animation (not just the last one)
- ✅ Theme colors applied (green ✓, yellow spinners, dimmed gray tool names)
- ✅ Elapsed time showing on tasks: `(5s)`
- ✅ Nested child tools with indentation: ` └─ ◇ child-tool`

### Code Details

**Theme colors are applied in the render logic:**

- Completed tools: `theme.tool.done.icon` = green + `theme.tool.done.text` = dim gray
- Running tools: `theme.tool.running.icon` = yellow + `theme.tool.running.text` = dim gray
- Error tools: `theme.tool.error.icon` = red + `theme.tool.error.text` = red
- Tasks: `theme.task.running.icon` = yellow + `theme.task.running.text` = cyan
- Elapsed time: `fg.gray` for the `(Xs)` text

**Elapsed time logic (line 76):**

```typescript
const elapsed = task.status === "running" ? Math.floor((Date.now() - task.startTime) / 1000) : task.elapsed
```

**Nested child tool rendering (lines 81-88):**
Only rendered when task is running and has a childTool attached, with proper indentation.

### Testing Status

- Binary rebuilt: ✅
- Changes verified in code: ✅
- Manual testing required: ⏳ (needs TTY environment)
Loading