Skip to content

Commit 8b8b671

Browse files
feat: DocCommands registry and tool-use preview (#46)
* feat: DocCommands registry and tool-use preview Ask AI can return targeted edits (replace_range, insert_after_block, table_add_row, table_update_cell) as a Proposed edits list. Apply N edits commits the batch as one undo step. Anthropic tool-use when a key is set; CLI fallback is a doccommands JSON fence. No second Rust LLM loop. 01M18R79ZM3BMYZ56C7P874YN1 * chore: link DocCommands work item to PR 46 01M18R79ZM3BMYZ56C7P874YN1 * chore: file sidecar, nested-table, and DocCommands locator follow-ups 01M19Z6Z3XQZ03EYNXKKBG5WK7
1 parent f596edb commit 8b8b671

30 files changed

Lines changed: 1641 additions & 128 deletions

.work/todo.jsonl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,3 +227,8 @@
227227
{"actor":"unknown","ev":"01M19SW6929ZW4PD39M8JJBH4F","item":"01M18R79ZMKBXK2PGWR6911MJQ","op":"close","set":{"resolution":"Shared TS AI service streams via POST /api/ai/stream; Anthropic SDK with prompt cache, CLI fallback, no second Rust loop","status":"done"},"ts":"2026-08-30T17:01:05Z"}
228228
{"actor":"unknown","ev":"01M19TM4NVS07H4654THD7RXZ3","item":"01M18R79ZMK0DX0PE2DPWMZ60D","op":"update","set":{"milestone":"v0.6.0","status":"in_progress"},"ts":"2026-08-30T17:14:09Z"}
229229
{"actor":"unknown","ev":"01M19VA1P5RXTPHHJ5XWVHM77X","item":"01M18R79ZMK0DX0PE2DPWMZ60D","op":"close","set":{"resolution":"Tiptap TableKit, GFM pipe round-trip, slash /tab and toolbar insert, in-table row/col chrome.","status":"done"},"ts":"2026-08-30T17:26:07Z"}
230+
{"actor":"unknown","ev":"01M19VXH75GQCPJEV3D4BHDS05","item":"01M18R79ZM3BMYZ56C7P874YN1","op":"update","set":{"milestone":"v0.6.0","status":"in_progress"},"ts":"2026-08-30T17:36:46Z"}
231+
{"actor":"unknown","ev":"01M19WMMFWTPFGQFEWMWFXEP40","item":"01M18R79ZM3BMYZ56C7P874YN1","op":"close","set":{"resolution":"DocCommands registry (replace_range, insert_after_block, table_add_row, table_update_cell), Anthropic tools + CLI fence, preview list, Apply N edits.","status":"done"},"ts":"2026-08-30T17:49:23Z"}
232+
{"actor":"unknown","ev":"01M19Z6Z3XTY3GZMZEG33THEPF","item":"01M19Z6Z3XQZ03EYNXKKBG5WK7","op":"create","set":{"body":"Packaged Tauri still one-shots Ask AI via run_llm_cli. The shared TS service (Anthropic SDK, streaming, DocCommands tools) only runs in the Bun dev server. Ship a Bun sidecar that hosts that same service so the packaged app streams and uses tools. Do not add a second Rust LLM loop.","discovered_during":"01M18R79ZMKBXK2PGWR6911MJQ","kind":"feature","level":"task","milestone":"v0.6.0","parent":"01M18R79ZMN53CMV76JFHKVEFN","priority":"P2","status":"todo","title":"Bun sidecar so packaged Tauri streams Ask AI","unplanned":true},"ts":"2026-08-30T18:34:21Z"}
233+
{"actor":"unknown","ev":"01M19Z6Z5DGR9D6DKAHJEFFYT6","item":"01M19Z6Z5DJ54227R1WYVVX2GF","op":"create","set":{"body":"Insert Table (toolbar or /tab) while the caret is already in a table can nest a table, because cells allow block+. E2E always starts from a heading so this is untested. If the caret is in a table, insert after that table instead of nesting. Column resize stays off.","discovered_during":"01M18R79ZMK0DX0PE2DPWMZ60D","kind":"bug","level":"task","milestone":"v0.6.0","parent":"01M18R79ZMN53CMV76JFHKVEFN","priority":"P2","status":"todo","title":"Insert Table nests when the caret is already in a table","unplanned":true},"ts":"2026-08-30T18:34:21Z"}
234+
{"actor":"unknown","ev":"01M19Z6Z6XHW247EMVAF5JFZ9H","item":"01M19Z6Z6X06VRZM95741Y2748","op":"create","set":{"body":"DocCommands apply sequentially against the updated markdown. A model that emits two replace_ranges whose old_text only exists in the original document can fail the second. Plan every command against the original snapshot (or remap locators) so a batch of tools from one turn all resolve. Try again remains the recovery until this lands.","discovered_during":"01M18R79ZM3BMYZ56C7P874YN1","kind":"bug","level":"task","milestone":"v0.6.0","parent":"01M18R79ZMN53CMV76JFHKVEFN","priority":"P2","status":"todo","title":"DocCommands batch should resolve against the original document","unplanned":true},"ts":"2026-08-30T18:34:21Z"}

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ round-trip, and the demo Query join were fixed on `main` before this work.
1111

1212
### Added
1313

14+
- **DocCommands.** Ask AI can propose targeted edits (`replace_range`,
15+
`insert_after_block`, `table_add_row`, `table_update_cell`) as a preview list.
16+
**Apply N edits** commits the batch as one undo step. Text-only rewrites still
17+
use Replace / Insert below. Anthropic tool-use when a key is set; CLI fallback
18+
is a `doccommands` JSON fence.
1419
- **GFM tables.** Toolbar **Insert Table** (or `/tab`) drops a 3×3 with a header
1520
row. Cells are editable; while the caret is in a table the toolbar shows Add
1621
/ Delete row and column, and Delete table. Pipe tables round-trip through

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ natural-language prompts using CLI tools you already have installed.
3232
- **Ask AI** — select text for a floating **Ask AI**, type `/ai` at the start of
3333
a line, or use toolbar **Refine** for the whole document. Replies stream into
3434
a preview (Replace / Insert below / Try again / Discard) before anything is
35-
committed. Uses the Anthropic API when `ANTHROPIC_API_KEY` is set, otherwise
36-
`claude` on `PATH`.
35+
committed. Targeted edits (`replace_range`, insert after a block, table row /
36+
cell) preview as a list; **Apply N edits** commits the batch. Uses the
37+
Anthropic API when `ANTHROPIC_API_KEY` is set, otherwise `claude` on `PATH`.
3738

3839
### Content blocks
3940

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
code:
2+
- {commit: c66ed4a, pr: 46}

docs/designs/current_code_walkthrough.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ filesystem cores to behave identically.
5656
| `src-tauri/src/fs_core.rs` | The same core in Rust | Runs in the desktop app's Rust process |
5757
| `src-tauri/src/lib.rs` | `#[tauri::command]` wrappers + `WorkspaceState` | Thin: state lookup, then delegate to `fs_core` |
5858
| `src/lib/{llmClient,imageClient}.ts` | Browser-safe entry points that fork on `isTauri()` | The only sanctioned way UI code reaches a CLI |
59+
| `src/lib/ai/` | Ask AI pipeline: context, session, SSE client, DocCommands registry | `commands.ts` is browser-safe; `service.ts` is server-only |
5960
| `src/lib/{cliWrappers,imageGen}.ts` | `Bun.spawn` CLI wrappers | Server/desktop-side only; must stay unreachable from `main.tsx` |
6061
| `src/lib/data/{duckdb,sqlSafety}.ts` | DuckDB-WASM lifecycle + SQL validation | Document-supplied SQL is untrusted input |
6162
| `src/server.ts` | The Bun dev server: build, watch, HTML, `/api/*` | Also the browser's filesystem backend |

docs/designs/current_design_doc.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ immediately after exposed product and process gaps; plan
5252
| Welcome demo datasets outside Motion workspace | Welcome HTML hardcodes `sample-data.csv` / `sample-events.jsonl`. Works when those files are in the open folder (`public/demo` or E2E seed); fails in Tauri when the folder is an unrelated project. |
5353
| Sidebar tree, sort by date, in-file search | **Tree + content search shipped.** Sort-by-date is still open. |
5454
| Finder Open With / Share / native chrome | **Shipped in v0.6.0 work** (`docs/plans/2026-08-30-native-mac-app.md`). |
55-
| Ask AI (selection, `/ai`, preview) | **P1 + streaming shipped** (`docs/plans/2026-08-30-ai-editor.md`). Tables shipping in this slice. DocCommands and dictation remain P2/P3. |
55+
| Ask AI (selection, `/ai`, preview) | **P1 + streaming + tables + DocCommands shipped** (`docs/plans/2026-08-30-ai-editor.md`). Dictation remains P3. |
5656
| Agent-browser final pass in DoD | Optional dogfood; Playwright remains the CI gate. |
5757
| Branch protection on `main` | CI exists; GitHub does not yet require `verify` / `rust` checks. |
5858
| Full line-number re-audit of §7–§27 | This amendment corrects product status; a full line re-citation is deferred. |
@@ -88,9 +88,11 @@ unit → E2E).
8888
8. **Ask AI** — selection bubble, `/ai`, or toolbar Refine. One pipeline
8989
(`src/lib/ai`). Browser/`bun tauri dev` streams `POST /api/ai/stream`
9090
(Anthropic SDK when `ANTHROPIC_API_KEY` is set, else `claude` CLI; prompt
91-
cache on system + packed context). Packaged Tauri one-shots `run_llm_cli`
92-
until the sidecar. Preview before commit. Refine is document-scoped (no
93-
Insert below). `ContentInjector.generateSummary` still backs Synthesize.
91+
cache on system + packed context; DocCommands as SDK tools / `doccommands`
92+
fence). Packaged Tauri one-shots `run_llm_cli` until the sidecar. Preview
93+
before commit: markdown blob (Replace / Insert below) or a Proposed edits
94+
list (Apply N edits). Refine is document-scoped (no Insert below).
95+
`ContentInjector.generateSummary` still backs Synthesize.
9496
9. **Synthesize** — workspace-level topic clustering; writes `TOC.md` and `SKILL.md`
9597
(cap 40 notes; excludes its own outputs from the next run).
9698
10. **Share** — current buffer to a GitHub Gist or Notion page. Tokens in

docs/roadmap.md

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
wiki_key: roadmap
33
doc_type: roadmap
44
truth_state: current
5-
source_hash: be05d8ea
6-
generated_at: 2026-08-30T17:26:07Z
5+
source_hash: 0b1813d7
6+
generated_at: 2026-08-30T18:34:21Z
77
---
88

99
<!-- GENERATED by worklog roadmap-render. DO NOT EDIT. -->
@@ -13,7 +13,7 @@ generated_at: 2026-08-30T17:26:07Z
1313
1414
# Roadmap
1515

16-
_2 epic(s) in flight, 9 open item(s), 0 blocked, 0 unclassified._
16+
_2 epic(s) in flight, 11 open item(s), 0 blocked, 0 unclassified._
1717

1818
## Now
1919

@@ -32,12 +32,14 @@ Make Save findable after New Note, lock create to edit to save to reload in Play
3232
| 01KYQYYN | Sidebar: sort by name or date | task | P2 | todo ||
3333
| 01KYQYYN | Search inside file contents (grep/glob UX) | task | P2 | todo ||
3434

35-
### AI editor: selection, /ai, preview · P1 · 6 of 8 done · → v0.6.0
35+
### AI editor: selection, /ai, preview · P1 · 7 of 11 done · feature 9 / bug 2 · → v0.6.0
3636
Three entry points, one pipeline, preview before commit. Phase 1 on the existing CLI transport.
3737

3838
| # | Item | Type | Priority | Status | Blocked by |
3939
|---|---|---|---|---|---|
40-
| 01M18R79 | DocCommands registry and tool-use loop | task | P2 | todo ||
40+
| 01M19Z6Z | Bun sidecar so packaged Tauri streams Ask AI | task | P2 | todo ||
41+
| 01M19Z6Z | Insert Table nests when the caret is already in a table | task | P2 | todo ||
42+
| 01M19Z6Z | DocCommands batch should resolve against the original document | task | P2 | todo ||
4143

4244
### (no epic)
4345

@@ -54,7 +56,7 @@ Make Save findable after New Note, lock create to edit to save to reload in Play
5456
|---|---|---|---|---|---|
5557
| 01KYQYYN | Require branch protection on main for verify + rust checks | task | P3 | todo ||
5658

57-
### AI editor: selection, /ai, preview · P1 · 6 of 8 done
59+
### AI editor: selection, /ai, preview · P1 · 7 of 11 done · feature 9 / bug 2
5860
Three entry points, one pipeline, preview before commit. Phase 1 on the existing CLI transport.
5961

6062
| # | Item | Type | Priority | Status | Blocked by |
@@ -68,7 +70,9 @@ Three entry points, one pipeline, preview before commit. Phase 1 on the existing
6870
| # | Item | Type | Priority | Status | Blocked by |
6971
|---|---|---|---|---|---|
7072
| 01M18Q56 | Mac dogfood: unsigned .app, Finder Open With, overlay padding | task | P1 | todo ||
71-
| 01M18R79 | DocCommands registry and tool-use loop | task | P2 | todo ||
73+
| 01M19Z6Z | Bun sidecar so packaged Tauri streams Ask AI | task | P2 | todo ||
74+
| 01M19Z6Z | Insert Table nests when the caret is already in a table | task | P2 | todo ||
75+
| 01M19Z6Z | DocCommands batch should resolve against the original document | task | P2 | todo ||
7276
| 01M18R79 | Dictation last | task | P3 | todo ||
7377

7478
## Visual roadmap
@@ -85,19 +89,23 @@ graph TD
8589
01KYQYYN3TA69K8848E483HC82["📦 Sidebar sort by name or date"]
8690
01KYQYYN3TKW93D9SVW07VKFZY["📦 Search inside file contents (g"]
8791
01M18Q560MPAYQJTA0W6F4DAW3["🔧 Mac dogfood unsigned .app Find"]
88-
01M18R79ZM3BMYZ56C7P874YN1["📦 DocCommands registry and tool-"]
8992
01M18R79ZM90HJ0MBG3CX6VW7E["📦 Dictation last"]
9093
01M18R79ZMN53CMV76JFHKVEFN["📦 AI editor selection /ai previe"]
94+
01M19Z6Z3XQZ03EYNXKKBG5WK7["📦 Bun sidecar so packaged Tauri"]
95+
01M19Z6Z5DJ54227R1WYVVX2GF["🐛 Insert Table nests when the ca"]
96+
01M19Z6Z6X06VRZM95741Y2748["🐛 DocCommands batch should resol"]
9197
01KYQYYN3SBWDT25TC6H3G4EAA --> 01KYQYYN3T2SSGG33ESEWPXKH8
9298
01KYQYYN3SBWDT25TC6H3G4EAA --> 01KYQYYN3T3VB8RCTMJJ13FK2H
9399
01KYQYYN3SBWDT25TC6H3G4EAA --> 01KYQYYN3T5W49QH05WCCYX7CE
94100
01KYQYYN3SBWDT25TC6H3G4EAA --> 01KYQYYN3T731B57N8NXQ8C0FQ
95101
01KYQYYN3SBWDT25TC6H3G4EAA --> 01KYQYYN3TA69K8848E483HC82
96102
01KYQYYN3SBWDT25TC6H3G4EAA --> 01KYQYYN3TKW93D9SVW07VKFZY
97-
01M18R79ZMN53CMV76JFHKVEFN --> 01M18R79ZM3BMYZ56C7P874YN1
98103
01M18R79ZMN53CMV76JFHKVEFN --> 01M18R79ZM90HJ0MBG3CX6VW7E
104+
01M18R79ZMN53CMV76JFHKVEFN --> 01M19Z6Z3XQZ03EYNXKKBG5WK7
105+
01M18R79ZMN53CMV76JFHKVEFN --> 01M19Z6Z5DJ54227R1WYVVX2GF
106+
01M18R79ZMN53CMV76JFHKVEFN --> 01M19Z6Z6X06VRZM95741Y2748
99107
classDef todo fill:#f4f4f4,stroke:#999999
100-
class 01KYQYYN3SBWDT25TC6H3G4EAA,01KYQYYN3T2SSGG33ESEWPXKH8,01KYQYYN3T3VB8RCTMJJ13FK2H,01KYQYYN3T5W49QH05WCCYX7CE,01KYQYYN3T731B57N8NXQ8C0FQ,01KYQYYN3TA69K8848E483HC82,01KYQYYN3TKW93D9SVW07VKFZY,01M18Q560MPAYQJTA0W6F4DAW3,01M18R79ZM3BMYZ56C7P874YN1,01M18R79ZM90HJ0MBG3CX6VW7E,01M18R79ZMN53CMV76JFHKVEFN todo
108+
class 01KYQYYN3SBWDT25TC6H3G4EAA,01KYQYYN3T2SSGG33ESEWPXKH8,01KYQYYN3T3VB8RCTMJJ13FK2H,01KYQYYN3T5W49QH05WCCYX7CE,01KYQYYN3T731B57N8NXQ8C0FQ,01KYQYYN3TA69K8848E483HC82,01KYQYYN3TKW93D9SVW07VKFZY,01M18Q560MPAYQJTA0W6F4DAW3,01M18R79ZM90HJ0MBG3CX6VW7E,01M18R79ZMN53CMV76JFHKVEFN,01M19Z6Z3XQZ03EYNXKKBG5WK7,01M19Z6Z5DJ54227R1WYVVX2GF,01M19Z6Z6X06VRZM95741Y2748 todo
101109
```
102110

103111
### Hierarchy
@@ -112,15 +120,19 @@ graph TD
112120
01KYQYYN3TA69K8848E483HC82["📦 Sidebar sort by name or date"]
113121
01KYQYYN3TKW93D9SVW07VKFZY["📦 Search inside file contents (g"]
114122
01M18Q560MPAYQJTA0W6F4DAW3["🔧 Mac dogfood unsigned .app Find"]
115-
01M18R79ZM3BMYZ56C7P874YN1["📦 DocCommands registry and tool-"]
116123
01M18R79ZM90HJ0MBG3CX6VW7E["📦 Dictation last"]
117124
01M18R79ZMN53CMV76JFHKVEFN["📦 AI editor selection /ai previe"]
125+
01M19Z6Z3XQZ03EYNXKKBG5WK7["📦 Bun sidecar so packaged Tauri"]
126+
01M19Z6Z5DJ54227R1WYVVX2GF["🐛 Insert Table nests when the ca"]
127+
01M19Z6Z6X06VRZM95741Y2748["🐛 DocCommands batch should resol"]
118128
01KYQYYN3SBWDT25TC6H3G4EAA --> 01KYQYYN3T2SSGG33ESEWPXKH8
119129
01KYQYYN3SBWDT25TC6H3G4EAA --> 01KYQYYN3T3VB8RCTMJJ13FK2H
120130
01KYQYYN3SBWDT25TC6H3G4EAA --> 01KYQYYN3T5W49QH05WCCYX7CE
121131
01KYQYYN3SBWDT25TC6H3G4EAA --> 01KYQYYN3T731B57N8NXQ8C0FQ
122132
01KYQYYN3SBWDT25TC6H3G4EAA --> 01KYQYYN3TA69K8848E483HC82
123133
01KYQYYN3SBWDT25TC6H3G4EAA --> 01KYQYYN3TKW93D9SVW07VKFZY
124-
01M18R79ZMN53CMV76JFHKVEFN --> 01M18R79ZM3BMYZ56C7P874YN1
125134
01M18R79ZMN53CMV76JFHKVEFN --> 01M18R79ZM90HJ0MBG3CX6VW7E
135+
01M18R79ZMN53CMV76JFHKVEFN --> 01M19Z6Z3XQZ03EYNXKKBG5WK7
136+
01M18R79ZMN53CMV76JFHKVEFN --> 01M19Z6Z5DJ54227R1WYVVX2GF
137+
01M18R79ZMN53CMV76JFHKVEFN --> 01M19Z6Z6X06VRZM95741Y2748
126138
```

docs/user_guide/user-guide.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ grammar, Continue). Tokens stream into the preview as they arrive.
107107
**Try again** re-runs; **Discard** (or Escape) applies nothing and cancels an
108108
in-flight stream. Failures show in the panel, not an alert.
109109

110+
When the model proposes targeted edits (replace a unique span, insert after a
111+
heading, add a table row, update a cell) the preview is a **Proposed edits**
112+
list instead. **Apply N edits** commits the whole list as one undo step.
113+
110114
Markdown mode has no bubble and no slash menu; Refine still works.
111115

112116
Set `ANTHROPIC_API_KEY` to use the Anthropic API (with prompt caching on the

0 commit comments

Comments
 (0)