merge: main into P11c (P11b's dock and books homes, the macOS harness root fix)
One conflict, ledger-host commands.rs: main moved the agent-program lookup into find_agent_in; kept that and carried the Windows parts into it (.exe/.cmd/.bat, npm's global folder). The harness already used default_root, so main's fix and ours agree. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HS8WZziDnyxunC23MUxrLp
This commit is contained in:
commit
84cbe0359c
23 files changed
+3398
-91
No files matched your search
+27
-2
@@ -36,8 +36,8 @@ the specification in `bookspec/` (which never depends on the engine).
|
||||
| `ledger-import` | formats: QuickBooks CSV in; IIF, XLSX, Typst PDFs (statements, the invoice, labels, the audit workpaper) out | `ledger-core`, `ledger-reader` |
|
||||
| `ledger-package` | the shared read-only view over `Store` or `Snapshot` (`PackageBooks`): the CPA package, the 1099 worksheet, the invoice document, Needs attention | `ledger-core`, `ledger-store`, `ledger-config`, `ledger-import`, `ledger-vault` |
|
||||
| `ledger-mcp` | the books server: the MCP tools (122), resources, the handbook, scopes, the door and the access log, backups' scheduling | all of the above |
|
||||
| `ledger-host` | the host and its leases, the agent bridge (`wanderbooks mcp`), tokens in 0600 files under the data root (D-63), the owner's commands, uploads and downloads, `update` and `rollback` (P11a) | `ledger-store`, `ledger-mcp`, `ledger-config` |
|
||||
| `ledger-gui` | the viewer: read-only, live, egui; the Books menu hands work to the server | `ledger-core`, `ledger-store`, `ledger-config`, `ledger-import`, `ledger-package`, `ledger-vault`, `ledger-host` |
|
||||
| `ledger-host` | the host and its leases, the agent bridge (`wanderbooks mcp`), tokens in 0600 files under the data root (D-63), the owner's commands, uploads and downloads, `update` and `rollback` (P11a), books homes and how to start an agent in one (P11b) | `ledger-store`, `ledger-mcp`, `ledger-config` |
|
||||
| `ledger-gui` | the viewer: read-only, live, egui; the Books menu hands work to the server; the agent dock and the first-run page (P11b) | `ledger-core`, `ledger-store`, `ledger-config`, `ledger-import`, `ledger-package`, `ledger-vault`, `ledger-host` |
|
||||
| `ledger-cli` | `wanderbooks`, the one executable: every mode (`serve`, `server`, `host`, `mcp`, `gui`, `setup`, `books`, `token`, `connect`, `doctor`, …) and the over-the-wire test suites | everything |
|
||||
| `bookspec/checker`, `bookspec/runner` | the example schema and parser, the rule catalogue, the `Engine` trait; the per-rule runner | nothing of ours (the adapter in `ledger-core`'s tests depends on them) |
|
||||
|
||||
@@ -116,6 +116,31 @@ appended journal lines; the UI renders an immutable view model rebuilt per
|
||||
change. Statements and series come from `ledger-core` (`reports`,
|
||||
`analysis`); the GUI only arranges them. See `plan/gui.md`.
|
||||
|
||||
Two things sit beside the read-only view, both through the `Owner` the
|
||||
program gives the viewer (never a write of the books by the viewer):
|
||||
|
||||
- **The agent dock** (`dock.rs`, P11b, D-27): a terminal panel along the
|
||||
bottom of the window (`alacritty_terminal` over a PTY; ConPTY on Windows,
|
||||
not offered until its four checks are recorded) that runs Claude Code or
|
||||
Codex in the book's **books home**. The agent is an ordinary child process
|
||||
of the viewer's program (D-32: no helper, no confinement) and writes the
|
||||
books through the server like any other agent. The CLIs are found or
|
||||
offered through their vendors' installers, never bundled; the app marks
|
||||
no folder trusted (Q-7). Never required: any agent, anywhere, reaches the
|
||||
same books through the MCP.
|
||||
- **The first-run page** (`welcome.rs`): with no books and an owner to ask,
|
||||
`wanderbooks gui` shows a page that sets up the private folder, the owner
|
||||
passphrase, the first books and an agent, then opens the books, so an
|
||||
installed app onboards with no terminal.
|
||||
|
||||
A **books home** (`ledger_host::commands::books_home`) is a visible folder,
|
||||
`<Documents>/Wanderbooks/<book id>`, made by the viewer's "New books…" and by
|
||||
`wanderbooks connect` (and again whenever the dock starts an agent). It holds
|
||||
exactly `AGENTS.md`, `CLAUDE.md` (three lines), `.mcp.json` (the
|
||||
project-level entry, `wanderbooks mcp --book ID`) and `.claude/settings.json`
|
||||
(allowing `mcp__wanderbooks-ID__*`): no books data, key, token or path into
|
||||
the data root (I-1 stays: the books are hidden, not here).
|
||||
|
||||
## Shared read-only views (`ledger-package`)
|
||||
|
||||
`ledger-package` is the shared read-only view: packages, the invoice PDF,
|
||||
|
||||
@@ -247,3 +247,11 @@ Three new rows, none above changed status, and the floor stands.
|
||||
| Audit run: one programme of checks over the statements, the control accounts, closes, schedules, assets, evidence, drafts, tax categories, 1099 decisions, settings and the store's integrity (`books.audit`, `books.workpaper`) | An auditor's workpaper; QBO "Audit log"/"Review" and Xero's "Reports review" are a cross-check only | partial | rules.md B-45; `ledger_core::audit`, `ledger_store::audit`; tests `audit_detects_each_seeded_defect` (every code seeded), `audit_is_deterministic`, `workpaper_pdf_is_deterministic`; the fixture `p8_before` was written by the version before; `partial` until a hand-verified golden covers a workpaper |
|
||||
| Attestations of receipts, entries and periods, weighed against `policy.attestation_bar` when asked (`books.attest_receipt`, `books.review_entry`, `books.attest_period`, `books.attestations`) | An accountant's sign-off on a month | partial | `below_bar_not_counted`, `amount_mismatch_never_counts`, `stale_head_period_attestation_refused`; the method is the client's own claim, and the books say so |
|
||||
| The CPA package waits for a counted audit (`policy.cpa_package_requires_audit`) | A close checklist before handoff | partial | `cpa_package_refuses_without_a_counted_audit_unless_a_reason_is_given`; behind the feature `audits` |
|
||||
|
||||
## P11b: the agent dock, books homes, first run (2026-10-29)
|
||||
|
||||
| Area | Counterpart (a cross-check, not the spec) | Status | Notes |
|
||||
|---|---|---|---|
|
||||
| Books home: a visible folder per book, `<Documents>/Wanderbooks/<id>`, holding `AGENTS.md`, `CLAUDE.md`, `.mcp.json` and `.claude/settings.json` and nothing of the books | A QBO/Xero company has no counterpart; the point is the agent's workplace (D-27) | partial | `books_home_holds_no_books_data`, `a_books_home_made_again_keeps_what_a_person_kept` (`crates/ledger-host/tests/books_home.rs`); `partial` until the macOS home is tried |
|
||||
| Agent dock: Claude Code or Codex in a terminal along the bottom of the viewer, started in the books home; never required | QBO's assistant panel is a cross-check only | partial | `dock_runs_the_chosen_agent`, `agent_missing_offers_the_installer` (`crates/ledger-gui/tests/dock.rs`); Linux checked; macOS by the CI run; Windows not offered (ConPTY unchecked) |
|
||||
| First run with no terminal: the viewer sets up the private folder, the owner passphrase, the first books and an agent | QBO's "set up your company" flow | partial | `first_run_onboards_with_no_terminal` (`crates/ledger-gui/tests/welcome.rs`); the AppImage's whole path is the EM's to try on a clean machine |
|
||||
@@ -4045,3 +4045,83 @@ this repository's files live in `tests/bookspec.rs`: `every_vendored_pin_is_verb
|
||||
`rules_md_carries_every_id`. The examples named `bookspec/examples/...` in the
|
||||
older sections above are files of that repository. The checker's, the
|
||||
runner's and the derivation tests run in its own CI.
|
||||
|
||||
## P11b: books homes, the agent dock, the first run (2026-10-29)
|
||||
|
||||
Three layers, none touching the owner's books or data root: a home is made
|
||||
under a scratch "documents" folder the test gives (`make_books_home_in`
|
||||
takes it as an argument, so no test writes in an account's real
|
||||
`~/Documents`); the dock runs a stand-in `claude` (a bash script) on a real
|
||||
PTY under the viewer's harness; the first run is driven page by page
|
||||
against an owner over a real scratch data root.
|
||||
|
||||
`crates/ledger-host/tests/books_home.rs`:
|
||||
|
||||
- `books_home_holds_no_books_data`: exactly four files
|
||||
(`.claude/settings.json`, `.mcp.json`, `AGENTS.md`, `CLAUDE.md`); none
|
||||
names the data root (a root with a journal sits beside the home), a token,
|
||||
a key, a vault or a journal; `AGENTS.md` is three lines and names the
|
||||
company and `books.start`; `.mcp.json` holds `wanderbooks-acme` running
|
||||
`<exe> mcp --book acme` and no `--root`; the settings allow
|
||||
`mcp__wanderbooks-acme__*`.
|
||||
- `a_books_home_made_again_keeps_what_a_person_kept`: a person's
|
||||
`AGENTS.md`, their other MCP server and their other settings stay; the
|
||||
entry and the rule are refreshed and appear once.
|
||||
- `a_books_home_is_never_made_for_a_name_that_is_not_an_id`: `../x`,
|
||||
`a/b`, the empty id and `A B` make nothing; a relative documents folder is
|
||||
refused.
|
||||
- `an_agent_is_found_on_the_path_or_where_its_installer_puts_it`
|
||||
(`agent_missing_offers_the_installer`'s host half): not found gives the
|
||||
vendor's installer; found on the PATH, a file that cannot be run is not
|
||||
the agent, `~/.local/bin` is searched; `start_agent_in` returns the books
|
||||
home as the directory and marks nothing trusted (Q-7).
|
||||
- `a_first_run_reads_where_it_stands_and_sets_the_first_passphrase_once`.
|
||||
|
||||
`crates/ledger-gui/tests/dock.rs` (Linux and macOS; a PTY):
|
||||
|
||||
- `dock_runs_the_chosen_agent`: closed, nothing runs; opened, the owner is
|
||||
asked for Claude Code on book `acme`, the program starts in the books
|
||||
home (its own `pwd`), its output reaches the panel, typed text and Enter
|
||||
reach it, a Ctrl-C key reaches it as an interrupt (`got-interrupt`; the
|
||||
agent goes on), narrowing the window resizes the terminal and the program
|
||||
is told the new size (`stty size` on its `WINCH` matches `Dock::cells`);
|
||||
the journal is byte for byte as it was.
|
||||
- `agent_missing_offers_the_installer`: the page names the agent, shows the
|
||||
vendor's install command with a Copy button and starts nothing.
|
||||
- `a_chosen_agent_and_an_open_dock_are_kept`: the preferences round trip,
|
||||
Claude Code the default.
|
||||
- Unit tests in `dock.rs`: `keys_become_what_a_terminal_sends`,
|
||||
`colors_follow_the_terminals_palette`.
|
||||
|
||||
`crates/ledger-gui/tests/welcome.rs`:
|
||||
|
||||
- `first_run_onboards_with_no_terminal`: from nothing, "Set it up" makes the
|
||||
private folder, two matching passphrase fields set the passphrase (the
|
||||
owner is handed 20 characters, once), "Make the books" makes `acme` and
|
||||
holds it, Codex is refused with its reason and Claude Code connects,
|
||||
"Open the books" shows the books (Needs attention) and the page is gone;
|
||||
the owner was asked exactly: set up, passphrase, new, hold, connect
|
||||
Codex, connect Claude.
|
||||
- `first_run_starts_at_the_first_step_missing_and_asks_nothing_done_again`.
|
||||
- `a_passphrase_too_short_or_not_repeated_is_not_sent_and_can_wait`.
|
||||
|
||||
Existing tests that cover the unchanged parts: `owner_menu.rs` (the menu
|
||||
still hands each action to the owner), `read_only.rs`, `sidenav.rs` (the
|
||||
sidebar's shape golden is unchanged: the dock sits right of the sidebar).
|
||||
|
||||
**Not tested here:** macOS and Windows (no machine); the real `claude` and
|
||||
`codex` (not installed on CI); the real `wanderbooks gui` first run
|
||||
through the AppImage on a clean machine (the EM's).
|
||||
|
||||
**For P12 (mutation targets):** `commands::make_books_home_in` (the
|
||||
`!path.exists()` test that keeps a person's `AGENTS.md`; the merge that
|
||||
dedupes the allow rule; `BookId::parse` before any path is joined);
|
||||
`find_agent_in` (the order PATH then the installer folders; `is_program`'s
|
||||
mode test); `start_agent_in` (the `Missing` arm); `first_run_state`'s three
|
||||
fields; `set_first_passphrase`'s already-set refusal; `dock::key_bytes` (the
|
||||
modifier parameter's arithmetic, the Ctrl-letter byte, the app-cursor
|
||||
switch, the Alt escape); `dock::color`'s cube and gray ramps and its bold
|
||||
brightening; `Session::resize`'s equality early return; the panel's
|
||||
open/closed ids (a remembered size must not leak between them);
|
||||
`Welcome::steps`' choice of `now` (each arm), the passphrase length and
|
||||
equality gates, the `agent_later` flag.
|
||||
Reference in new issue
Block a user