Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
2efbb3c
Add tools/ refactor plan (WIP)
pruiz May 23, 2026
c98dcf9
Revise tools refactor plan after review
pruiz May 23, 2026
968a7b2
Add testing and acceptance gates to tools refactor plan
pruiz May 23, 2026
811d149
refactor(phase-a1): extract stable core helpers from run-agent.py
pruiz May 24, 2026
cba2471
refactor(phase-a2): add rendering package foundation
pruiz May 24, 2026
5181480
fix(phase-a2): add BaseRenderer, de-duplicate kimi artefacts
pruiz May 24, 2026
ded9f59
fix: address Phase A1/A2 PR review comments + kimi improvements
pruiz May 24, 2026
4a892cf
fix: address PR review comments — de-duplication + explicit registry
pruiz May 24, 2026
3f8cf8c
refactor(phase-a3-batch1): migrate todo/task/skill/permission renderers
pruiz May 24, 2026
55100a9
refactor(phase-a3-batch2): migrate read/write/edit renderers
pruiz May 24, 2026
ec3dc9b
refactor(phase-a3-batch3): migrate apply_patch renderer
pruiz May 24, 2026
57e03fe
refactor(phase-a3-batch4-5): migrate glob, grep, bash renderers
pruiz May 24, 2026
23b4a3d
refactor(phase-a3-batch6): extract bash interceptors
pruiz May 24, 2026
2a15ce4
fix(rendering): pass end parameter in RichConsoleSink.write_text()
pruiz May 24, 2026
a7f49be
test(renderers): add unit tests for read/write/edit/apply_patch/glob/…
pruiz May 24, 2026
6c24317
fix: address Phase A3 PR review comments (6 issues)
pruiz May 24, 2026
2d7d5e8
refactor(phase-a3-batch7): migrate generic event renderers
pruiz May 24, 2026
1c8f1d8
fix(phase-a3-batch7): address review issues - tests, caching, state i…
pruiz May 24, 2026
cf7e11e
fix: address Phase A3 PR review comments (round 3)
pruiz May 24, 2026
8d44091
Fix two rendering issues from Phase A3 review
pruiz May 24, 2026
f8146bd
refactor(phase-a5): extract runner helpers to codecome/runner.py
pruiz May 24, 2026
a3d3bf8
refactor(phase-a4): extract chat TUI to tools/chat/ package
pruiz May 25, 2026
98e7721
refactor(rendering): move _colors import to module level
pruiz May 25, 2026
32fc56b
fix: address Phase A4/A5 review issues and parity test regression
pruiz May 25, 2026
4c9a5a6
fix: resolve NameError in render_event fallback and finish_warning scope
pruiz May 25, 2026
25685d7
refactor(phase-a5): complete CLI extraction — thin wrapper
pruiz May 25, 2026
9f68cde
fix(phase-a5): remove dead code and fix import loop in cli.py
pruiz May 25, 2026
e2cc66a
Fix unknown event fallback in CLI renderer
pruiz May 25, 2026
fdb52b1
Use CLI render helpers from chat harness
pruiz May 25, 2026
bc424c1
Keep chat package init lightweight
pruiz May 25, 2026
b3ee63d
refactor(phase-a6): add BaseEventLoop — deduplicate events package
pruiz May 25, 2026
d525c85
Refactor: complete CLI extraction and migrate interceptor tests
pruiz May 25, 2026
23edfe5
Move phase event loop into dedicated module
pruiz May 25, 2026
1cb8ad7
Slim events package exports
pruiz May 25, 2026
3d34cc4
Add chat reconnect recovery sync
pruiz May 25, 2026
76d4374
Use CLI renderer directly from chat app
pruiz May 25, 2026
c6113a9
Clarify runner render dispatcher dependency
pruiz May 25, 2026
b979ed0
Add event loop unit tests
pruiz May 25, 2026
49714bb
Preserve events SseClient compatibility export
pruiz May 25, 2026
02dfcb9
Use compatibility SseClient export in phase loop
pruiz May 25, 2026
9486088
Patch event loop test through compatibility export
pruiz May 25, 2026
5fe9191
Keep codecome package init lightweight
pruiz May 25, 2026
55e1fb5
Remove legacy events compatibility exports
pruiz May 25, 2026
ced9187
Use direct SseClient dependency in phase loop
pruiz May 25, 2026
102a11e
Patch event loop tests through concrete modules
pruiz May 25, 2026
934b337
Simplify seen part handling in base event loop
pruiz May 25, 2026
8070080
Add tools architecture guide
pruiz May 25, 2026
cf6f3a7
Patch event loop tests through phase loop module
pruiz May 25, 2026
3acc1aa
Remove EventLoop compatibility alias
pruiz May 25, 2026
e403071
Use PhaseEventLoop explicitly in runner
pruiz May 25, 2026
6364d41
Load phase event loop from concrete module in tests
pruiz May 25, 2026
26e9d7a
Use PhaseEventLoop in mock LLM parity tool
pruiz May 25, 2026
96532a0
Use PhaseEventLoop directly in runner tests
pruiz May 25, 2026
fb01808
docs(phase-a7): add tools/AGENTS.md architecture guide
pruiz May 25, 2026
7dc0f1f
refactor(tools): clean up rendering, deduplicate constants, fix sink bug
pruiz May 25, 2026
f59f5fd
refactor(a8-batch1): foundational fixes from PR review
pruiz May 25, 2026
48ee6b5
refactor(a8-batch2): runtime config, log-level, graceful → phases/com…
pruiz May 25, 2026
ddc5a6a
refactor(a8-batch3): Transcript class, unified event writing
pruiz May 25, 2026
df5a58d
refactor(a8-batch4a): split rendering/events.py into rendering/events…
pruiz May 25, 2026
823cabf
refactor(a8-batch4b): rendering dispatch + command/interceptors restr…
pruiz May 25, 2026
6d50998
refactor(a8-batch5): extract phase harness from cli.py
pruiz May 25, 2026
ee96816
fix(a8-batch6): fix tests for API changes, add RenderSettings regress…
pruiz May 25, 2026
f796f95
docs: update tools/AGENTS.md for A8 architecture changes
pruiz May 25, 2026
d54b672
fix(a8.1): cleanup cli_render, deduplicate event pipeline, strengthen…
pruiz May 25, 2026
d23db4b
fix: update stale comment in test_render_settings_propagation.py
pruiz May 25, 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
4 changes: 2 additions & 2 deletions .project/mock-llm-parity-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ Build a deterministic mock LLM **provider** (not replacing OpenCode) that:
### 3.1 Mock LLM Server

**Approach:** Small custom stdlib-only OpenAI-compatible mock server (`tools/mock-llm-server.py`).
- Reads a JSON script file at startup (e.g., `--script tools/mock_llm_scripts/basic.json`).
- Reads a JSON script file at startup (e.g., `--script tools/mock-llm-scripts/basic.json`).
- Serves standard OpenAI-compatible endpoints:
- `POST /v1/chat/completions` — streaming SSE with deterministic deltas.
- `GET /v1/models` — returns `[{"id":"mockmodel"}]`.
Expand Down Expand Up @@ -141,7 +141,7 @@ Add a new test class `TestMockLLMParity` that:
## 6. Acceptance Criteria

- [x] `tools/mock-llm-server.py` exists and serves deterministic OpenAI-compatible SSE streams from JSON script files.
- [x] `tools/mock_llm_scripts/` contains `basic.json`, `with_tool.json`, and `with_permission.json`.
- [x] `tools/mock-llm-scripts/` contains `basic.json`, `with_tool.json`, and `with_permission.json`.
- [x] `opencode.json` contains `provider.test` block.
- [x] `tools/mock-llm-parity.py` exists and can be invoked manually.
- [x] `tests/test_mock_llm_parity.py` exists and passes in CI.
Expand Down
198 changes: 198 additions & 0 deletions .project/tools-refactor-a8-plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
# Plan: Phase A8 — PR Review Fixes and Architectural Cleanup

**Status:** Implemented (A8 + A8.1 cleanup complete)
**Date:** 2026-05-25
**Parent:** [tools-refactor-plan.md](tools-refactor-plan.md)
**PR:** #21 (`wip/tools-refactor`)
**Scope:** Address all unresolved PR review comments from the A1–A5 implementation

---

## 1. Summary

PR #21 accumulated 20 unresolved review threads during the A1–A5 implementation.
This plan addresses all of them in a single phase (A8), grouped into an ordered
execution sequence that respects dependency chains.

Two items are deferred:
- **Unify run-agent.py + codecome.py** → deferred to Phase 2 (Epic B).
- **Legacy globals in cli.py** → already resolved in the last commit.

---

## 2. Execution Order

Tasks are ordered to minimise rework: foundational changes (ROOT, colors, naming)
come first, then structural moves, then the larger splits/extractions.

### Batch 1 — Foundational fixes (no structural moves)

| ID | Thread | File | Action |
|----|--------|------|--------|
| T3 | plan:266 | `tools/mock_llm_scripts/` | `git mv` to `mock-llm-scripts`, update all 16 path-based references across 6 files. |
| T4 | harness:50 | `chat/harness.py` | Remove redundant `check_opencode_version()` call and its import; `cli.py:76` already covers both modes. |
| T5 | harness:56 | multiple | Define `ROOT` once in `codecome/config.py` (already has it at line 24). Remove duplicate `ROOT =` definitions from `cli_render.py`, `transcript.py`, `graceful.py`, and `chat/harness.py`; import from `codecome.config` instead. |
| T12 | config:36 | `codecome/config.py` | Replace inline `_COLOR_ENABLED`/`_RESET`/`_BOLD`/`_DIM` with `import _colors as C` and use `C.RESET`, `C.BOLD`, `C.DIM`. |
| T15 | events/__init__:10 | `events/__init__.py` | Add `ChatEventLoop` to exports. |
| T2 | plan:260 | `.project/tools-refactor-plan.md` | Add note that run-agent.py + codecome.py unification is deferred to Phase 2. |

### Batch 2 — Naming and small structural changes

| ID | Thread | File | Action |
|----|--------|------|--------|
| T7 | harness:83 | multiple | Make `log_level` configurable: read from `--log-level` CLI arg or `OPENCODE_LOG_LEVEL` env var (default `"WARN"`). Both phase and chat paths use the same source. |
| T6 | harness:66 | `codecome/config.py` | Extract `resolve_runtime_config(agent, extra_args) -> RuntimeConfig` that bundles model, variant, thinking resolution into a single call. Both `cli.py` and `chat/harness.py` call this instead of duplicating three separate calls. |
| T13 | graceful:1 | `codecome/graceful.py` | Create `tools/phases/` package. Move `graceful.py` to `phases/completion.py`. Update all imports (`codecome.graceful` → `phases.completion`). |

### Batch 3 — Transcript class

| ID | Thread | File | Action |
|----|--------|------|--------|
| T8 | transcript:1, app:107, harness:109 | `codecome/transcript.py` | Convert to `Transcript` class with `for_phase()` / `for_chat()` class methods, `write_event()`, and `close()`. Remove old free functions entirely (no backward-compat wrappers). Update `runner.py` and `chat/app.py` to use `transcript.write_event(event)`. |

### Batch 4 — Rendering architecture

| ID | Thread | File | Action |
|----|--------|------|--------|
| T16 | events.py:42 | `rendering/events.py` | Split into `rendering/events/` package: `base.py` (EventRenderer + constants + subagent state), then one file per renderer class. `rendering/events/__init__.py` re-exports everything so existing imports continue to work. |
| T11 | cli_render:1 | `codecome/cli_render.py` | Move rendering-related parts (`HAVE_RICH`, Rich stubs, `_get_rendering_ctx`, `render_event`) into `rendering/dispatch.py`. Keep CLI-only parts (`build_console`, `_emit_fatal_error`) in `codecome/cli_render.py`. Update imports. |
| T1 | plan:207 | `rendering/tools/` | Restructure: move `command.py` → `command/__init__.py`, move `interceptors/` → `command/interceptors/`. Update all import paths from `rendering.tools.interceptors.*` to `rendering.tools.command.interceptors.*`. Update plan document. |

### Batch 5 — Phase harness extraction

| ID | Thread | File | Action |
|----|--------|------|--------|
| T10 | cli:198 | `codecome/cli.py` | Extract the phase retry/resume loop (lines ~160–395) into `codecome/harness.py` as `run_phase_mode(args, console, ...)`. `cli.py` becomes: parse args → check version → dispatch to `run_phase_mode()` or `_run_chat_mode()`. |

### Batch 6 — Testing and PR hygiene

| ID | Thread | File | Action |
|----|--------|------|--------|
| T17 | run-agent.py | `tests/` | Add regression test verifying `--read-display-lines`, `--write-content-lines`, `--write-diff-limit`, `--edit-diff-lines` flags propagate into `RenderSettings`. |
| — | PR body | GitHub | Update PR #21 description to reflect A1–A8 implementation status. |
| — | Verify | — | Run `make tests` to confirm all changes pass. |

---

## 3. New Directory Structure (after A8)

Changes from the current structure are marked with `← NEW` or `← MOVED`.

```
tools/
├── run-agent.py # Thin wrapper → codecome.cli.main()
├── codecome.py # Workspace validation CLI (unchanged)
├── codecome/ # Core runner and configuration
│ ├── cli.py # main() → parse args → dispatch to harness
│ ├── cli_render.py # build_console, _emit_fatal_error (CLI-only) ← SLIMMED
│ ├── config.py # ROOT, env, codecome.yml, prompt, model, thinking
│ ├── session.py # OpenCode HTTP: create session, send prompt
│ ├── runner.py # _consume_events, _run_single_attempt
│ ├── harness.py # run_phase_mode() — retry/resume loop ← NEW (from cli.py)
│ ├── transcript.py # Transcript class ← REWRITTEN
│ └── version.py # OpenCode version checks
├── phases/ # Phase-specific logic ← NEW PACKAGE
│ ├── __init__.py
│ └── completion.py # ← MOVED from codecome/graceful.py
├── rendering/ # Rendering infrastructure
│ ├── __init__.py
│ ├── base.py
│ ├── cache.py
│ ├── context.py
│ ├── dispatch.py # HAVE_RICH, _get_rendering_ctx, render_event ← NEW (from cli_render.py)
│ ├── registry.py
│ ├── settings.py
│ ├── sink.py
│ ├── utils.py
│ ├── events/ # ← NEW PACKAGE (split from events.py)
│ │ ├── __init__.py # Re-exports all renderer classes + constants
│ │ ├── base.py # EventRenderer, finish constants, subagent state
│ │ ├── step_start.py
│ │ ├── step_finish.py
│ │ ├── text.py
│ │ ├── reasoning.py
│ │ ├── tool_use.py
│ │ ├── error.py
│ │ ├── session_status.py
│ │ ├── session_diff.py
│ │ ├── server.py # ServerConnectedRenderer + ServerHeartbeatRenderer
│ │ ├── message.py # MessageUpdatedRenderer
│ │ ├── subagent.py
│ │ └── unknown.py
│ └── tools/
│ ├── __init__.py
│ ├── base.py
│ ├── todo.py
│ ├── read.py / write.py / edit.py / glob.py / grep.py
│ ├── apply_patch.py
│ ├── skill.py / task.py / permissions.py
│ └── command/ # ← RESTRUCTURED
│ ├── __init__.py # CommandRenderer (was command.py)
│ └── interceptors/ # ← MOVED from rendering/tools/interceptors/
│ ├── __init__.py
│ ├── base.py
│ ├── sandbox_bootstrap.py
│ ├── rtk_read.py
│ ├── rtk_grep.py
│ └── shell_listing.py
├── mock-llm-scripts/ # ← RENAMED from mock_llm_scripts
│ ├── basic.json
│ ├── comprehensive.json
│ └── ...
├── chat/ # Chat TUI package (unchanged)
├── events/ # Event consumption (ChatEventLoop now exported)
├── opencode/ # opencode serve lifecycle
├── _colors.py # Shared ANSI utilities
└── ... # Other scripts unchanged
```

---

## 4. Dependency Direction (updated)

```
run-agent.py → codecome/ → (none)
chat/ → codecome/, events/, rendering/
codecome/ → events/, rendering/ (lazy), phases/
phases/ → (stdlib only, reads workspace files)
events/ → (stdlib only, except sse_client)
rendering/ → _colors, (no codecome/ dependency)
```

Key change: `rendering/dispatch.py` replaces the dependency that `codecome/cli_render.py`
had on `rendering/`. Now `codecome/` imports `rendering.dispatch` instead of the reverse.

---

## 5. Acceptance Criteria

```
- All 20 unresolved PR threads addressed (18 fixed, 2 deferred with notes).
- `make tests` passes.
- `py_compile` passes for all moved/new files.
- No duplicate ROOT definitions across modules.
- No duplicate color escape definitions in config.py.
- Transcript logic is a class, not scattered free functions.
- Phase retry/resume loop lives in codecome/harness.py, not cli.py.
- Event renderers are individual files under rendering/events/.
- Interceptors live under rendering/tools/command/interceptors/.
- mock-llm-scripts directory uses hyphenated name.
- PR body is updated.
```

---

## 6. Risks

| Risk | Probability | Impact | Mitigation |
|------|:-----------:|:------:|------------|
| Import cycles from ROOT centralisation | Low | Medium | ROOT stays in config.py which has no execution deps |
| Renderer split breaks existing imports | Medium | High | `rendering/events/__init__.py` re-exports all symbols |
| Command interceptor move breaks imports | Medium | Medium | `rendering/tools/command/interceptors/__init__.py` re-exports |
| Phase harness extraction breaks retry logic | Medium | High | Extract verbatim first, refactor later; run tests after |
| Transcript class change breaks chat/phase flow | Medium | Medium | Keep same write semantics; test both paths |
Loading
Loading