Merge asks first; Work>work lists runs with a log tab; Shell says where everything is
This commit is contained in:
@@ -220,3 +220,80 @@ TUIOS plugin libraries called out: PLOT, LOOM, TML, GO (prefer Go for in-TUI pan
|
|||||||
- context: [[packs/paperclip-harness/20-context/tmp|tmp]]
|
- context: [[packs/paperclip-harness/20-context/tmp|tmp]]
|
||||||
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|tmp deployment operations]]
|
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|tmp deployment operations]]
|
||||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|tmp repository structure and configuration patterns]]
|
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|tmp repository structure and configuration patterns]]
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Update (2026-11-11 01:02:31)
|
||||||
|
|
||||||
|
Repository: paperclip-harness (TUI workspace harness; Go terminal UI plus Python `bin/` tooling).
|
||||||
|
|
||||||
|
Key paths discovered this turn:
|
||||||
|
- `bin/lib/harness.py` — shared harness library; now prepends `~/.local/bin`, `~/.nix-profile/bin`, system profile and per-user profile to PATH before tool lookup (fixes merge pane not finding `ocr`).
|
||||||
|
- `bin/board` — workspace launcher; compares each pane's real working directory with the project folder and recreates (replaces) the `Shell>shell` pane when they differ, announcing it.
|
||||||
|
- `bin/merge` — performs a task merge; uses `ocr` for review; takes a lock so a second concurrent merge is refused.
|
||||||
|
- Go TUI code with `workModel.View()` (min size 80×24), key handling `esc/q/o`, `up/k`, `o`, `t`, `m`, `r`, `R`, `g/G`, help overlay via `helpOverlay`.
|
||||||
|
- `docs/TEST-PLAN.md` — rewritten to be keys-only (nine steps, no terminal commands); `Shell>shell` appears once as escape hatch.
|
||||||
|
|
||||||
|
Pane layout: tab bar `the work | runs | change | facts | review | merge`; workspace navigation uses `Work>work`, `Board>board`, `Shell>shell`, `Repair>cleanup`. Merge logs go to `/tmp/paperclip-harness-merge.log`. Worktrees live under `<project>/.paperclip/worktrees/<TASK-id>-<slug>` with branch `<TASK-id>-<slug>` rebased onto `main`. Issue IDs look like `AUD-###`.
|
||||||
|
|
||||||
|
## Detailed context from completed turn
|
||||||
|
|
||||||
|
Both complaints are fair, and both are now fixed in the program rather than in the instructions.
|
||||||
|
|
||||||
|
## Work>work selects its own task and merges
|
||||||
|
|
||||||
|
- **`o`** in `Work>work` opens a list of the project's tasks. Choose one and the runs, change, facts, review and merge tabs all switch to it. You no longer start in `Board>board`.
|
||||||
|
- **`m`** runs the merge for the task you are looking at, and the new **merge** tab shows it live:
|
||||||
|
|
||||||
|
```
|
||||||
|
merge of AUD-168 started 12:01:39
|
||||||
|
worktree …/worktrees/AUD-168-tidy-the-readme-introduction
|
||||||
|
rebased onto main
|
||||||
|
no verify command: this would pass on the agent's word
|
||||||
|
review saw nothing to review (0 files); recorded, not hidden
|
||||||
|
merged into main at 4a44473
|
||||||
|
merge finished 12:01:43
|
||||||
|
```
|
||||||
|
|
||||||
|
That is a real merge I ran from the pane a minute ago, with no shell. Starting it twice is safe — the merge takes a lock and the second is refused.
|
||||||
|
|
||||||
|
## Why the Shell step failed you
|
||||||
|
|
||||||
|
Two real bugs, not your memory:
|
||||||
|
|
||||||
|
1. The pane that merges inherited the pane's small `PATH`, so `bin/merge` could not find `ocr` and refused with `ocr is not installed`. Fixed at the source: `bin/lib/harness.py` now adds `~/.local/bin`, `~/.nix-profile/bin`, the system profile and your per-user profile before looking for anything.
|
||||||
|
2. `Shell>shell` was created in one folder and later adopted without checking. `bin/board` now compares the pane's real working directory with the project folder and **replaces** the shell pane when they differ, saying so.
|
||||||
|
|
||||||
|
## The principle you are pointing at
|
||||||
|
|
||||||
|
The terminal was creeping in as the normal path. It should not be. From now on:
|
||||||
|
|
||||||
|
- anything you do regularly is a key in a pane;
|
||||||
|
- `Shell>shell` exists for the things we deliberately do not wrap, and for emergencies;
|
||||||
|
- a test plan that needs me to write `git log` is a bad test plan.
|
||||||
|
|
||||||
|
`docs/TEST-PLAN.md` is rewritten accordingly: step 4 is now "press `m` and wait", and the whole plan contains no terminal commands at all. `Shell>shell` appears once, as the escape hatch it is.
|
||||||
|
|
||||||
|
## What I would do next, in your order
|
||||||
|
|
||||||
|
1. You run the plan as written (nine steps, keys only) and tell me where the screen and Paperclip disagree.
|
||||||
|
2. `Repair>cleanup` — sessions listed with age and pane count, kill only what you select, and never touching the Pi session files.
|
||||||
|
3. The Pi session browser — `pi --resume` in a tool pane, or the folder in Yazi.
|
||||||
|
|
||||||
|
Committed as `7198c34`; the eight workspaces are rebuilt and running.
|
||||||
|
|
||||||
|
## Evidence
|
||||||
|
|
||||||
|
- Confidence: 90%
|
||||||
|
- Reason: Concrete architecture and source-path details from the turn that a future agent needs to navigate the repo.; enriched with final-answer detail because persistence should be reusable
|
||||||
|
|
||||||
|
## Related learned memories <!-- same-turn-2026-11-11 01:02:31 -->
|
||||||
|
|
||||||
|
- context: [[packs/paperclip-harness/20-context/paperclip-harness|paperclip-harness]]
|
||||||
|
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Pane-first UX: repeated actions become keys, Shell only as escape hatch]]
|
||||||
|
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Implemented task picker, in-pane merge, PATH and shell-folder fixes (commit 7198c34)]]
|
||||||
|
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Merging a paperclip-harness task from the TUI and diagnosing merge failures]]
|
||||||
|
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-bin-2026-11-11-01-02-31|Rich discovery: bin 2026-11-11 01:02:31]]
|
||||||
|
- context: [[packs/paperclip-harness/20-context/tmp|bin]]
|
||||||
|
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|bin repository structure and configuration patterns]]
|
||||||
|
|||||||
@@ -768,3 +768,74 @@ Committed as `7b12b45`. Say go and I run that list end to end and report each re
|
|||||||
- context: [[packs/paperclip-harness/20-context/tmp|tmp]]
|
- context: [[packs/paperclip-harness/20-context/tmp|tmp]]
|
||||||
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|tmp deployment operations]]
|
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|tmp deployment operations]]
|
||||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|tmp repository structure and configuration patterns]]
|
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|tmp repository structure and configuration patterns]]
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Update (2026-11-11 01:02:31)
|
||||||
|
|
||||||
|
## Rich discovery update (2026-11-11 01:02:31)
|
||||||
|
|
||||||
|
Both complaints are fair, and both are now fixed in the program rather than in the instructions.
|
||||||
|
|
||||||
|
## Work>work selects its own task and merges
|
||||||
|
|
||||||
|
- **`o`** in `Work>work` opens a list of the project's tasks. Choose one and the runs, change, facts, review and merge tabs all switch to it. You no longer start in `Board>board`.
|
||||||
|
- **`m`** runs the merge for the task you are looking at, and the new **merge** tab shows it live:
|
||||||
|
|
||||||
|
```
|
||||||
|
merge of AUD-168 started 12:01:39
|
||||||
|
worktree …/worktrees/AUD-168-tidy-the-readme-introduction
|
||||||
|
rebased onto main
|
||||||
|
no verify command: this would pass on the agent's word
|
||||||
|
review saw nothing to review (0 files); recorded, not hidden
|
||||||
|
merged into main at 4a44473
|
||||||
|
merge finished 12:01:43
|
||||||
|
```
|
||||||
|
|
||||||
|
That is a real merge I ran from the pane a minute ago, with no shell. Starting it twice is safe — the merge takes a lock and the second is refused.
|
||||||
|
|
||||||
|
## Why the Shell step failed you
|
||||||
|
|
||||||
|
Two real bugs, not your memory:
|
||||||
|
|
||||||
|
1. The pane that merges inherited the pane's small `PATH`, so `bin/merge` could not find `ocr` and refused with `ocr is not installed`. Fixed at the source: `bin/lib/harness.py` now adds `~/.local/bin`, `~/.nix-profile/bin`, the system profile and your per-user profile before looking for anything.
|
||||||
|
2. `Shell>shell` was created in one folder and later adopted without checking. `bin/board` now compares the pane's real working directory with the project folder and **replaces** the shell pane when they differ, saying so.
|
||||||
|
|
||||||
|
## The principle you are pointing at
|
||||||
|
|
||||||
|
The terminal was creeping in as the normal path. It should not be. From now on:
|
||||||
|
|
||||||
|
- anything you do regularly is a key in a pane;
|
||||||
|
- `Shell>shell` exists for the things we deliberately do not wrap, and for emergencies;
|
||||||
|
- a test plan that needs me to write `git log` is a bad test plan.
|
||||||
|
|
||||||
|
`docs/TEST-PLAN.md` is rewritten accordingly: step 4 is now "press `m` and wait", and the whole plan contains no terminal commands at all. `Shell>shell` appears once, as the escape hatch it is.
|
||||||
|
|
||||||
|
## What I would do next, in your order
|
||||||
|
|
||||||
|
1. You run the plan as written (nine steps, keys only) and tell me where the screen and Paperclip disagree.
|
||||||
|
2. `Repair>cleanup` — sessions listed with age and pane count, kill only what you select, and never touching the Pi session files.
|
||||||
|
3. The Pi session browser — `pi --resume` in a tool pane, or the folder in Yazi.
|
||||||
|
|
||||||
|
Committed as `7198c34`; the eight workspaces are rebuilt and running.
|
||||||
|
|
||||||
|
## Source paths observed
|
||||||
|
|
||||||
|
- `tmp/pc-sandbox-2026-11-10/.paperclip/worktrees/AUD-168-tidy-the-rea`
|
||||||
|
- `bin/lib/harness.py`
|
||||||
|
|
||||||
|
## Evidence
|
||||||
|
|
||||||
|
- Confidence: 84%
|
||||||
|
- Reason: Update component/repository context with detailed discovered structure and configuration
|
||||||
|
|
||||||
|
## Related learned memories <!-- same-turn-2026-11-11 01:02:31 -->
|
||||||
|
|
||||||
|
- context: [[packs/paperclip-harness/20-context/paperclip-harness|paperclip-harness]]
|
||||||
|
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Pane-first UX: repeated actions become keys, Shell only as escape hatch]]
|
||||||
|
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Implemented task picker, in-pane merge, PATH and shell-folder fixes (commit 7198c34)]]
|
||||||
|
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Merging a paperclip-harness task from the TUI and diagnosing merge failures]]
|
||||||
|
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-bin-2026-11-11-01-02-31|Rich discovery: bin 2026-11-11 01:02:31]]
|
||||||
|
- context: [[packs/paperclip-harness/20-context/tmp|bin]]
|
||||||
|
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|bin repository structure and configuration patterns]]
|
||||||
|
|||||||
@@ -552,3 +552,37 @@ Committed as `77014d0` — documentation only, nothing in the running layout cha
|
|||||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-pi-2026-11-10-21-03-21|Rich discovery: .pi 2026-11-10 21:03:21]]
|
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-pi-2026-11-10-21-03-21|Rich discovery: .pi 2026-11-10 21:03:21]]
|
||||||
- context: [[packs/paperclip-harness/20-context/home|.pi]]
|
- context: [[packs/paperclip-harness/20-context/home|.pi]]
|
||||||
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|.pi deployment operations]]
|
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|.pi deployment operations]]
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Update (2026-11-11 01:02:31)
|
||||||
|
|
||||||
|
Completed work in paperclip-harness, committed as `7198c34` ("Work>work chooses its own task and merges from the interface; panes find their tools; shell follows the project folder"); eight workspaces rebuilt and running.
|
||||||
|
|
||||||
|
Deliverables:
|
||||||
|
- `o` in `Work>work` opens "choose a task to look at" list; selecting a task retargets all five tabs (runs, change, facts, review, merge).
|
||||||
|
- `m` starts merge for the focused task; new merge tab streams live log. Verified real merge of AUD-168 into main at `4a44473` (log: rebased, no verify command warning, "review saw nothing to review (0 files); recorded, not hidden").
|
||||||
|
- Merge is idempotent-safe: takes a lock; second start refused.
|
||||||
|
- `bin/lib/harness.py`: prepends `~/.local/bin`, `~/.nix-profile/bin`, system profile, per-user profile so `ocr` is found (fixes "refused: ocr is not installed", exit status 2).
|
||||||
|
- `bin/board`: replaces mismatched `Shell>shell` pane when its cwd differs from project folder, with a message.
|
||||||
|
- `docs/TEST-PLAN.md` rewritten: step 4 is now "press `m` and wait"; no terminal commands anywhere.
|
||||||
|
|
||||||
|
Validation: `build=0`, `syntax ok`, real merge succeeded.
|
||||||
|
|
||||||
|
Follow-ups proposed (in order): user runs nine-step keys-only plan and reports disagreements; `Repair>cleanup` (list sessions with age and pane count, kill only selected, never touch Pi session files); Pi session browser via `pi --resume` in a tool pane or the folder in Yazi.
|
||||||
|
|
||||||
|
## Evidence
|
||||||
|
|
||||||
|
- Confidence: 90%
|
||||||
|
- Reason: Completed implementation with concrete artifacts, validation and follow-ups.
|
||||||
|
|
||||||
|
## Related learned memories <!-- same-turn-2026-11-11 01:02:31 -->
|
||||||
|
|
||||||
|
- context: [[packs/paperclip-harness/20-context/paperclip-harness|paperclip-harness]]
|
||||||
|
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Pane-first UX: repeated actions become keys, Shell only as escape hatch]]
|
||||||
|
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Implemented task picker, in-pane merge, PATH and shell-folder fixes (commit 7198c34)]]
|
||||||
|
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Merging a paperclip-harness task from the TUI and diagnosing merge failures]]
|
||||||
|
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-bin-2026-11-11-01-02-31|Rich discovery: bin 2026-11-11 01:02:31]]
|
||||||
|
- context: [[packs/paperclip-harness/20-context/tmp|bin]]
|
||||||
|
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|bin repository structure and configuration patterns]]
|
||||||
|
|||||||
@@ -115,3 +115,80 @@ Consequences / review caveats:
|
|||||||
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-reverted-pane-split-interface-gap-discover|Paperclip-harness — reverted pane split, interface gap discovery, and PLAN-INTERFACE roadmap]]
|
- session: [[packs/paperclip-harness/80-sessions/paperclip-harness-reverted-pane-split-interface-gap-discover|Paperclip-harness — reverted pane split, interface gap discovery, and PLAN-INTERFACE roadmap]]
|
||||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-home-2026-11-10-05-41-48|Rich discovery: home 2026-11-10 05:41:48]]
|
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-home-2026-11-10-05-41-48|Rich discovery: home 2026-11-10 05:41:48]]
|
||||||
- context: [[packs/paperclip-harness/20-context/home|home]]
|
- context: [[packs/paperclip-harness/20-context/home|home]]
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Update (2026-11-11 01:02:31)
|
||||||
|
|
||||||
|
Decision (in paperclip-harness): the terminal must not be the normal path for routine work.
|
||||||
|
|
||||||
|
Rules:
|
||||||
|
- Anything done regularly is a key inside a pane (e.g. `o` to pick a task, `m` to merge).
|
||||||
|
- `Shell>shell` exists only for deliberately-unwrapped actions and emergencies.
|
||||||
|
- A test plan that requires the user to type `git log` is considered a bad test plan.
|
||||||
|
|
||||||
|
Context: users were falling back to the shell to pick tasks and merge, and the Shell step failed because of a small inherited `PATH` (missing `ocr`) and a stale shell pane created in a different folder.
|
||||||
|
|
||||||
|
Consequences: `Work>work` gained `o` (task picker switches runs/change/facts/review/merge tabs) and `m` (merge with live merge tab); `docs/TEST-PLAN.md` rewritten keys-only; PATH and shell-folder bugs fixed in `bin/lib/harness.py` and `bin/board`.
|
||||||
|
|
||||||
|
## Detailed decision context from completed turn
|
||||||
|
|
||||||
|
Both complaints are fair, and both are now fixed in the program rather than in the instructions.
|
||||||
|
|
||||||
|
## Work>work selects its own task and merges
|
||||||
|
|
||||||
|
- **`o`** in `Work>work` opens a list of the project's tasks. Choose one and the runs, change, facts, review and merge tabs all switch to it. You no longer start in `Board>board`.
|
||||||
|
- **`m`** runs the merge for the task you are looking at, and the new **merge** tab shows it live:
|
||||||
|
|
||||||
|
```
|
||||||
|
merge of AUD-168 started 12:01:39
|
||||||
|
worktree …/worktrees/AUD-168-tidy-the-readme-introduction
|
||||||
|
rebased onto main
|
||||||
|
no verify command: this would pass on the agent's word
|
||||||
|
review saw nothing to review (0 files); recorded, not hidden
|
||||||
|
merged into main at 4a44473
|
||||||
|
merge finished 12:01:43
|
||||||
|
```
|
||||||
|
|
||||||
|
That is a real merge I ran from the pane a minute ago, with no shell. Starting it twice is safe — the merge takes a lock and the second is refused.
|
||||||
|
|
||||||
|
## Why the Shell step failed you
|
||||||
|
|
||||||
|
Two real bugs, not your memory:
|
||||||
|
|
||||||
|
1. The pane that merges inherited the pane's small `PATH`, so `bin/merge` could not find `ocr` and refused with `ocr is not installed`. Fixed at the source: `bin/lib/harness.py` now adds `~/.local/bin`, `~/.nix-profile/bin`, the system profile and your per-user profile before looking for anything.
|
||||||
|
2. `Shell>shell` was created in one folder and later adopted without checking. `bin/board` now compares the pane's real working directory with the project folder and **replaces** the shell pane when they differ, saying so.
|
||||||
|
|
||||||
|
## The principle you are pointing at
|
||||||
|
|
||||||
|
The terminal was creeping in as the normal path. It should not be. From now on:
|
||||||
|
|
||||||
|
- anything you do regularly is a key in a pane;
|
||||||
|
- `Shell>shell` exists for the things we deliberately do not wrap, and for emergencies;
|
||||||
|
- a test plan that needs me to write `git log` is a bad test plan.
|
||||||
|
|
||||||
|
`docs/TEST-PLAN.md` is rewritten accordingly: step 4 is now "press `m` and wait", and the whole plan contains no terminal commands at all. `Shell>shell` appears once, as the escape hatch it is.
|
||||||
|
|
||||||
|
## What I would do next, in your order
|
||||||
|
|
||||||
|
1. You run the plan as written (nine steps, keys only) and tell me where the screen and Paperclip disagree.
|
||||||
|
2. `Repair>cleanup` — sessions listed with age and pane count, kill only what you select, and never touching the Pi session files.
|
||||||
|
3. The Pi session browser — `pi --resume` in a tool pane, or the folder in Yazi.
|
||||||
|
|
||||||
|
Committed as `7198c34`; the eight workspaces are rebuilt and running.
|
||||||
|
|
||||||
|
## Evidence
|
||||||
|
|
||||||
|
- Confidence: 90%
|
||||||
|
- Reason: Explicit durable product/UX convention chosen by the user/agent, with rationale and consequences.; enriched with final-answer detail because persistence should be reusable
|
||||||
|
|
||||||
|
## Related learned memories <!-- same-turn-2026-11-11 01:02:31 -->
|
||||||
|
|
||||||
|
- context: [[packs/paperclip-harness/20-context/paperclip-harness|paperclip-harness]]
|
||||||
|
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Pane-first UX: repeated actions become keys, Shell only as escape hatch]]
|
||||||
|
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Implemented task picker, in-pane merge, PATH and shell-folder fixes (commit 7198c34)]]
|
||||||
|
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Merging a paperclip-harness task from the TUI and diagnosing merge failures]]
|
||||||
|
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-bin-2026-11-11-01-02-31|Rich discovery: bin 2026-11-11 01:02:31]]
|
||||||
|
- context: [[packs/paperclip-harness/20-context/tmp|bin]]
|
||||||
|
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|bin repository structure and configuration patterns]]
|
||||||
|
|||||||
@@ -2223,3 +2223,74 @@ Committed as `678c497`. `AUD-168` is running now if you want to watch it in `Age
|
|||||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-agents-2026-11-11-00-28-33|Rich discovery: agents 2026-11-11 00:28:33]]
|
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-agents-2026-11-11-00-28-33|Rich discovery: agents 2026-11-11 00:28:33]]
|
||||||
- context: [[packs/paperclip-harness/20-context/agents|agents]]
|
- context: [[packs/paperclip-harness/20-context/agents|agents]]
|
||||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|agents repository structure and configuration patterns]]
|
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|agents repository structure and configuration patterns]]
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Update (2026-11-11 01:02:31)
|
||||||
|
|
||||||
|
## Structural/configuration observations (2026-11-11 01:02:31)
|
||||||
|
|
||||||
|
Both complaints are fair, and both are now fixed in the program rather than in the instructions.
|
||||||
|
|
||||||
|
## Work>work selects its own task and merges
|
||||||
|
|
||||||
|
- **`o`** in `Work>work` opens a list of the project's tasks. Choose one and the runs, change, facts, review and merge tabs all switch to it. You no longer start in `Board>board`.
|
||||||
|
- **`m`** runs the merge for the task you are looking at, and the new **merge** tab shows it live:
|
||||||
|
|
||||||
|
```
|
||||||
|
merge of AUD-168 started 12:01:39
|
||||||
|
worktree …/worktrees/AUD-168-tidy-the-readme-introduction
|
||||||
|
rebased onto main
|
||||||
|
no verify command: this would pass on the agent's word
|
||||||
|
review saw nothing to review (0 files); recorded, not hidden
|
||||||
|
merged into main at 4a44473
|
||||||
|
merge finished 12:01:43
|
||||||
|
```
|
||||||
|
|
||||||
|
That is a real merge I ran from the pane a minute ago, with no shell. Starting it twice is safe — the merge takes a lock and the second is refused.
|
||||||
|
|
||||||
|
## Why the Shell step failed you
|
||||||
|
|
||||||
|
Two real bugs, not your memory:
|
||||||
|
|
||||||
|
1. The pane that merges inherited the pane's small `PATH`, so `bin/merge` could not find `ocr` and refused with `ocr is not installed`. Fixed at the source: `bin/lib/harness.py` now adds `~/.local/bin`, `~/.nix-profile/bin`, the system profile and your per-user profile before looking for anything.
|
||||||
|
2. `Shell>shell` was created in one folder and later adopted without checking. `bin/board` now compares the pane's real working directory with the project folder and **replaces** the shell pane when they differ, saying so.
|
||||||
|
|
||||||
|
## The principle you are pointing at
|
||||||
|
|
||||||
|
The terminal was creeping in as the normal path. It should not be. From now on:
|
||||||
|
|
||||||
|
- anything you do regularly is a key in a pane;
|
||||||
|
- `Shell>shell` exists for the things we deliberately do not wrap, and for emergencies;
|
||||||
|
- a test plan that needs me to write `git log` is a bad test plan.
|
||||||
|
|
||||||
|
`docs/TEST-PLAN.md` is rewritten accordingly: step 4 is now "press `m` and wait", and the whole plan contains no terminal commands at all. `Shell>shell` appears once, as the escape hatch it is.
|
||||||
|
|
||||||
|
## What I would do next, in your order
|
||||||
|
|
||||||
|
1. You run the plan as written (nine steps, keys only) and tell me where the screen and Paperclip disagree.
|
||||||
|
2. `Repair>cleanup` — sessions listed with age and pane count, kill only what you select, and never touching the Pi session files.
|
||||||
|
3. The Pi session browser — `pi --resume` in a tool pane, or the folder in Yazi.
|
||||||
|
|
||||||
|
Committed as `7198c34`; the eight workspaces are rebuilt and running.
|
||||||
|
|
||||||
|
## Source paths observed
|
||||||
|
|
||||||
|
- `tmp/pc-sandbox-2026-11-10/.paperclip/worktrees/AUD-168-tidy-the-rea`
|
||||||
|
- `bin/lib/harness.py`
|
||||||
|
|
||||||
|
## Evidence
|
||||||
|
|
||||||
|
- Confidence: 82%
|
||||||
|
- Reason: Captured factual repo structure/configuration patterns from rich discovery
|
||||||
|
|
||||||
|
## Related learned memories <!-- same-turn-2026-11-11 01:02:31 -->
|
||||||
|
|
||||||
|
- context: [[packs/paperclip-harness/20-context/paperclip-harness|paperclip-harness]]
|
||||||
|
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Pane-first UX: repeated actions become keys, Shell only as escape hatch]]
|
||||||
|
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Implemented task picker, in-pane merge, PATH and shell-folder fixes (commit 7198c34)]]
|
||||||
|
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Merging a paperclip-harness task from the TUI and diagnosing merge failures]]
|
||||||
|
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-bin-2026-11-11-01-02-31|Rich discovery: bin 2026-11-11 01:02:31]]
|
||||||
|
- context: [[packs/paperclip-harness/20-context/tmp|bin]]
|
||||||
|
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|bin repository structure and configuration patterns]]
|
||||||
|
|||||||
@@ -709,3 +709,86 @@ Committed as `e44b0df`, documentation only — the running layout is untouched.
|
|||||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-paperclip-2026-11-10-21-58-38|Rich discovery: .paperclip 2026-11-10 21:58:38]]
|
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-paperclip-2026-11-10-21-58-38|Rich discovery: .paperclip 2026-11-10 21:58:38]]
|
||||||
- context: [[packs/paperclip-harness/20-context/paperclipai|.paperclip]]
|
- context: [[packs/paperclip-harness/20-context/paperclipai|.paperclip]]
|
||||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|.paperclip repository structure and configuration patterns]]
|
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|.paperclip repository structure and configuration patterns]]
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Update (2026-11-11 01:02:31)
|
||||||
|
|
||||||
|
Trigger: need to review or merge a completed task in paperclip-harness.
|
||||||
|
|
||||||
|
Procedure:
|
||||||
|
1. In `Work>work` press `o` and choose the task from the list (IDs like `AUD-168`). All tabs switch to it.
|
||||||
|
2. Check the `review` and `change` tabs.
|
||||||
|
3. Press `m` to merge; watch the `merge` tab for live progress. Log file: `/tmp/paperclip-harness-merge.log`.
|
||||||
|
4. Success line looks like `merged into main at <sha>` then `merge finished <time>`.
|
||||||
|
|
||||||
|
Expected log details: worktree `<project>/.paperclip/worktrees/<TASK-id>-<slug>`, branch `<TASK-id>-<slug>` rebased onto `main`; warnings `no verify command` and `review saw nothing to review (0 files); recorded, not hidden` are informational.
|
||||||
|
|
||||||
|
Troubleshooting:
|
||||||
|
- `refused: ocr is not installed` then `merge stopped: exit status 2` → PATH too small. `bin/lib/harness.py` should add `~/.local/bin`, `~/.nix-profile/bin`, system profile, per-user profile; verify `ocr` resolves in the environment the pane runs in.
|
||||||
|
- Second merge attempt while one is running is refused by the merge lock — expected, not an error.
|
||||||
|
- If `Shell>shell` behaves oddly, `bin/board` should detect cwd ≠ project folder and recreate that pane.
|
||||||
|
|
||||||
|
Rollback: merges land on `main`; revert with git as usual from the recorded sha.
|
||||||
|
|
||||||
|
## Detailed procedure from completed turn
|
||||||
|
|
||||||
|
Both complaints are fair, and both are now fixed in the program rather than in the instructions.
|
||||||
|
|
||||||
|
## Work>work selects its own task and merges
|
||||||
|
|
||||||
|
- **`o`** in `Work>work` opens a list of the project's tasks. Choose one and the runs, change, facts, review and merge tabs all switch to it. You no longer start in `Board>board`.
|
||||||
|
- **`m`** runs the merge for the task you are looking at, and the new **merge** tab shows it live:
|
||||||
|
|
||||||
|
```
|
||||||
|
merge of AUD-168 started 12:01:39
|
||||||
|
worktree …/worktrees/AUD-168-tidy-the-readme-introduction
|
||||||
|
rebased onto main
|
||||||
|
no verify command: this would pass on the agent's word
|
||||||
|
review saw nothing to review (0 files); recorded, not hidden
|
||||||
|
merged into main at 4a44473
|
||||||
|
merge finished 12:01:43
|
||||||
|
```
|
||||||
|
|
||||||
|
That is a real merge I ran from the pane a minute ago, with no shell. Starting it twice is safe — the merge takes a lock and the second is refused.
|
||||||
|
|
||||||
|
## Why the Shell step failed you
|
||||||
|
|
||||||
|
Two real bugs, not your memory:
|
||||||
|
|
||||||
|
1. The pane that merges inherited the pane's small `PATH`, so `bin/merge` could not find `ocr` and refused with `ocr is not installed`. Fixed at the source: `bin/lib/harness.py` now adds `~/.local/bin`, `~/.nix-profile/bin`, the system profile and your per-user profile before looking for anything.
|
||||||
|
2. `Shell>shell` was created in one folder and later adopted without checking. `bin/board` now compares the pane's real working directory with the project folder and **replaces** the shell pane when they differ, saying so.
|
||||||
|
|
||||||
|
## The principle you are pointing at
|
||||||
|
|
||||||
|
The terminal was creeping in as the normal path. It should not be. From now on:
|
||||||
|
|
||||||
|
- anything you do regularly is a key in a pane;
|
||||||
|
- `Shell>shell` exists for the things we deliberately do not wrap, and for emergencies;
|
||||||
|
- a test plan that needs me to write `git log` is a bad test plan.
|
||||||
|
|
||||||
|
`docs/TEST-PLAN.md` is rewritten accordingly: step 4 is now "press `m` and wait", and the whole plan contains no terminal commands at all. `Shell>shell` appears once, as the escape hatch it is.
|
||||||
|
|
||||||
|
## What I would do next, in your order
|
||||||
|
|
||||||
|
1. You run the plan as written (nine steps, keys only) and tell me where the screen and Paperclip disagree.
|
||||||
|
2. `Repair>cleanup` — sessions listed with age and pane count, kill only what you select, and never touching the Pi session files.
|
||||||
|
3. The Pi session browser — `pi --resume` in a tool pane, or the folder in Yazi.
|
||||||
|
|
||||||
|
Committed as `7198c34`; the eight workspaces are rebuilt and running.
|
||||||
|
|
||||||
|
## Evidence
|
||||||
|
|
||||||
|
- Confidence: 85%
|
||||||
|
- Reason: Repeatable procedure plus failure modes with concrete strings a future agent can match.; enriched with final-answer detail because persistence should be reusable
|
||||||
|
|
||||||
|
## Related learned memories <!-- same-turn-2026-11-11 01:02:31 -->
|
||||||
|
|
||||||
|
- context: [[packs/paperclip-harness/20-context/paperclip-harness|paperclip-harness]]
|
||||||
|
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Pane-first UX: repeated actions become keys, Shell only as escape hatch]]
|
||||||
|
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Implemented task picker, in-pane merge, PATH and shell-folder fixes (commit 7198c34)]]
|
||||||
|
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Merging a paperclip-harness task from the TUI and diagnosing merge failures]]
|
||||||
|
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-bin-2026-11-11-01-02-31|Rich discovery: bin 2026-11-11 01:02:31]]
|
||||||
|
- context: [[packs/paperclip-harness/20-context/tmp|bin]]
|
||||||
|
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|bin repository structure and configuration patterns]]
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
---
|
||||||
|
type: session
|
||||||
|
id: session.paperclip-harness.rich-discovery-bin-2026-11-11-01-02-31
|
||||||
|
title: Rich discovery: bin 2026-11-11 01:02:31
|
||||||
|
status: active
|
||||||
|
source_of_truth: false
|
||||||
|
freshness: current
|
||||||
|
last_reviewed: 2026-11-11
|
||||||
|
tags:
|
||||||
|
- pack/paperclip-harness
|
||||||
|
- agent-memory/session
|
||||||
|
- autolearn
|
||||||
|
- rich-discovery
|
||||||
|
- repo/bin
|
||||||
|
---
|
||||||
|
|
||||||
|
# Rich discovery: bin 2026-11-11 01:02:31
|
||||||
|
|
||||||
|
Sanitized rich discovery snapshot captured automatically from the completed turn.
|
||||||
|
|
||||||
|
|
||||||
|
## Source paths observed
|
||||||
|
|
||||||
|
- `tmp/pc-sandbox-2026-11-10/.paperclip/worktrees/AUD-168-tidy-the-rea`
|
||||||
|
- `bin/lib/harness.py`
|
||||||
|
|
||||||
|
## Final answer snapshot
|
||||||
|
|
||||||
|
Both complaints are fair, and both are now fixed in the program rather than in the instructions.
|
||||||
|
|
||||||
|
## Work>work selects its own task and merges
|
||||||
|
|
||||||
|
- **`o`** in `Work>work` opens a list of the project's tasks. Choose one and the runs, change, facts, review and merge tabs all switch to it. You no longer start in `Board>board`.
|
||||||
|
- **`m`** runs the merge for the task you are looking at, and the new **merge** tab shows it live:
|
||||||
|
|
||||||
|
```
|
||||||
|
merge of AUD-168 started 12:01:39
|
||||||
|
worktree …/worktrees/AUD-168-tidy-the-readme-introduction
|
||||||
|
rebased onto main
|
||||||
|
no verify command: this would pass on the agent's word
|
||||||
|
review saw nothing to review (0 files); recorded, not hidden
|
||||||
|
merged into main at 4a44473
|
||||||
|
merge finished 12:01:43
|
||||||
|
```
|
||||||
|
|
||||||
|
That is a real merge I ran from the pane a minute ago, with no shell. Starting it twice is safe — the merge takes a lock and the second is refused.
|
||||||
|
|
||||||
|
## Why the Shell step failed you
|
||||||
|
|
||||||
|
Two real bugs, not your memory:
|
||||||
|
|
||||||
|
1. The pane that merges inherited the pane's small `PATH`, so `bin/merge` could not find `ocr` and refused with `ocr is not installed`. Fixed at the source: `bin/lib/harness.py` now adds `~/.local/bin`, `~/.nix-profile/bin`, the system profile and your per-user profile before looking for anything.
|
||||||
|
2. `Shell>shell` was created in one folder and later adopted without checking. `bin/board` now compares the pane's real working directory with the project folder and **replaces** the shell pane when they differ, saying so.
|
||||||
|
|
||||||
|
## The principle you are pointing at
|
||||||
|
|
||||||
|
The terminal was creeping in as the normal path. It should not be. From now on:
|
||||||
|
|
||||||
|
- anything you do regularly is a key in a pane;
|
||||||
|
- `Shell>shell` exists for the things we deliberately do not wrap, and for emergencies;
|
||||||
|
- a test plan that needs me to write `git log` is a bad test plan.
|
||||||
|
|
||||||
|
`docs/TEST-PLAN.md` is rewritten accordingly: step 4 is now "press `m` and wait", and the whole plan contains no terminal commands at all. `Shell>shell` appears once, as the escape hatch it is.
|
||||||
|
|
||||||
|
## What I would do next, in your order
|
||||||
|
|
||||||
|
1. You run the plan as written (nine steps, keys only) and tell me where the screen and Paperclip disagree.
|
||||||
|
2. `Repair>cleanup` — sessions listed with age and pane count, kill only what you select, and never touching the Pi session files.
|
||||||
|
3. The Pi session browser — `pi --resume` in a tool pane, or the folder in Yazi.
|
||||||
|
|
||||||
|
Committed as `7198c34`; the eight workspaces are rebuilt and running.
|
||||||
|
|
||||||
|
## Evidence
|
||||||
|
|
||||||
|
- Confidence: 86%
|
||||||
|
- Reason: Preserve full sanitized discovery detail from a rich investigation turn
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- [[packs/paperclip-harness/00-system/pi-agent/memory-manifest|Memory Manifest]]
|
||||||
|
|
||||||
|
## Related learned memories <!-- same-turn-2026-11-11 01:02:31 -->
|
||||||
|
|
||||||
|
- context: [[packs/paperclip-harness/20-context/paperclip-harness|paperclip-harness]]
|
||||||
|
- decision: [[packs/paperclip-harness/50-decisions/paperclip-harness-ui-six-workspaces-spec-first-four-panel-li|Pane-first UX: repeated actions become keys, Shell only as escape hatch]]
|
||||||
|
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Implemented task picker, in-pane merge, PATH and shell-folder fixes (commit 7198c34)]]
|
||||||
|
- runbook: [[packs/paperclip-harness/70-runbooks/tmp-deployment-operations|Merging a paperclip-harness task from the TUI and diagnosing merge failures]]
|
||||||
|
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-bin-2026-11-11-01-02-31|Rich discovery: bin 2026-11-11 01:02:31]]
|
||||||
|
- context: [[packs/paperclip-harness/20-context/tmp|bin]]
|
||||||
|
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|bin repository structure and configuration patterns]]
|
||||||
@@ -58,9 +58,9 @@ program running in the Board workspace.
|
|||||||
|
|
||||||
| Workspace>pane | shows | keys |
|
| Workspace>pane | shows | keys |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Shell>shell | a prompt in the project folder: the pane that never exits, and the escape hatch for anything no panel covers | — |
|
| Shell>shell | a prompt in the project folder, with a box saying where the project's files, worktrees and Pi sessions are | — |
|
||||||
| Board>board | tasks by group · the chosen task · needs you | ↑↓ j k · enter · a · u · / · t (tools) · tab |
|
| Board>board | tasks by group · the chosen task · needs you | ↑↓ j k · enter · a · u · / · t (tools) · tab |
|
||||||
| Work>work | runs · change · facts · review · merge | [ ] tab · ↑↓ j k · g G · o (choose task) · m (merge) · t (tools) |
|
| Work>work | runs · change · facts · review · log · merge | [ ] tab · ↑↓ j k · enter (open a run) · o (choose task) · m (merge, asks first) · t (tools) |
|
||||||
| Reply>reply | the task · the thread · the reply box | enter · s · esc |
|
| Reply>reply | the task · the thread · the reply box | enter · s · esc |
|
||||||
| New task>new | the form · what a task needs · what will be sent | tab · enter · ctrl+n |
|
| New task>new | the form · what a task needs · what will be sent | tab · enter · ctrl+n |
|
||||||
| Project>project | overview · facts · costs · settings | [ ] tab · ↑↓ j k |
|
| Project>project | overview · facts · costs · settings | [ ] tab · ↑↓ j k |
|
||||||
|
|||||||
@@ -44,7 +44,8 @@ def pages(cfg, folder):
|
|||||||
# on the rail, so it is capitalised and says what the page is for; the pane
|
# on the rail, so it is capitalised and says what the page is for; the pane
|
||||||
# keeps the program's own name. Written Workspace>pane when talking about it.
|
# keeps the program's own name. Written Workspace>pane when talking about it.
|
||||||
task_pages = [
|
task_pages = [
|
||||||
("shell", "Shell", "exec zsh -i"),
|
("shell", "Shell", "%s %s; exec zsh -i" % (
|
||||||
|
shlex.quote(os.path.join(os.path.dirname(BIN), "shell-banner")), shlex.quote(folder))),
|
||||||
("board", "Board", "%s -screen board -project %s -folder %s" % (shlex.quote(bin_path), proj, shlex.quote(folder))),
|
("board", "Board", "%s -screen board -project %s -folder %s" % (shlex.quote(bin_path), proj, shlex.quote(folder))),
|
||||||
("work", "Work", "%s -screen work -folder %s" % (shlex.quote(bin_path), shlex.quote(folder))),
|
("work", "Work", "%s -screen work -folder %s" % (shlex.quote(bin_path), shlex.quote(folder))),
|
||||||
("agents", "Agents", "%s -screen agents -folder %s" % (shlex.quote(bin_path), shlex.quote(folder))),
|
("agents", "Agents", "%s -screen agents -folder %s" % (shlex.quote(bin_path), shlex.quote(folder))),
|
||||||
|
|||||||
BIN
bin/harness
BIN
bin/harness
Binary file not shown.
53
bin/shell-banner
Executable file
53
bin/shell-banner
Executable file
@@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Print where a project's files are, then the shell takes over.
|
||||||
|
|
||||||
|
Shown in Shell>shell when it opens, because the first question there is always
|
||||||
|
"where am I". It reads the project's own file and nothing else.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "lib"))
|
||||||
|
import project as pj
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
folder = os.path.abspath(sys.argv[1] if len(sys.argv) > 1 else os.getcwd())
|
||||||
|
cfg = pj.load(folder)
|
||||||
|
home = os.path.expanduser("~")
|
||||||
|
rows = [
|
||||||
|
("project folder", folder),
|
||||||
|
("task worktrees", os.path.join(folder, ".paperclip", "worktrees")),
|
||||||
|
("this project's file", pj.path(folder)),
|
||||||
|
("harness commands", os.path.join(os.path.dirname(os.path.abspath(__file__)))),
|
||||||
|
("pi conversations", os.path.join(home, ".pi", "paperclips")),
|
||||||
|
("pi skills you own", os.path.join(home, ".agents", "skills")),
|
||||||
|
("paperclip data", os.path.join(home, ".paperclip", "instances", "default")),
|
||||||
|
("session", cfg.get("session", "")),
|
||||||
|
("watching", cfg.get("watching", "")),
|
||||||
|
]
|
||||||
|
inner = 70
|
||||||
|
label = max(len(k) for k, _ in rows) + 2
|
||||||
|
print("┌─ where things are " + "─" * (inner - 19) + "┐")
|
||||||
|
for k, v in rows:
|
||||||
|
room = inner - label - 2
|
||||||
|
if len(v) > room:
|
||||||
|
v = v[: room - 1] + "…"
|
||||||
|
line = " " + k.ljust(label) + v
|
||||||
|
print("│" + line.ljust(inner) + "│")
|
||||||
|
print("└" + "─" * inner + "┘")
|
||||||
|
print("""
|
||||||
|
the panes are the normal way to work. this shell is for the commands we do not wrap:
|
||||||
|
bin/merge <TASK> checks and merges one task (the Merge tab in Work>work does this)
|
||||||
|
bin/review <TASK> the review on its own
|
||||||
|
bin/board rebuild or repair the panes (or press R in Repair>repair)
|
||||||
|
bin/office <folder> adopt another folder as a project
|
||||||
|
""")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
try:
|
||||||
|
main()
|
||||||
|
except Exception as exc: # a banner must never stop the shell opening
|
||||||
|
print("(no project file here: %s)" % exc)
|
||||||
@@ -88,7 +88,21 @@ Go to `Work>work`. It follows the task you chose on the board.
|
|||||||
|
|
||||||
No terminal. Stay in `Work>work`.
|
No terminal. Stay in `Work>work`.
|
||||||
|
|
||||||
1. Press `m`. The **merge** tab opens by itself and shows what is happening:
|
1. Press `m`. It **asks first**, and tells you what it is about to do:
|
||||||
|
|
||||||
|
```
|
||||||
|
merge AUD-1xx?
|
||||||
|
what happens rebase onto the base branch
|
||||||
|
no verify command: the review decides
|
||||||
|
ocr reviews the change; a critical finding refuses the merge
|
||||||
|
merge, then re-run the checks on the base branch
|
||||||
|
y do it
|
||||||
|
esc or n do nothing
|
||||||
|
```
|
||||||
|
|
||||||
|
That is the approval step. Nothing merges until you press `y`.
|
||||||
|
|
||||||
|
2. Press `y`. The **merge** tab shows what is happening:
|
||||||
|
|
||||||
```
|
```
|
||||||
merge of AUD-1xx started 12:01:39
|
merge of AUD-1xx started 12:01:39
|
||||||
@@ -99,7 +113,7 @@ No terminal. Stay in `Work>work`.
|
|||||||
merge finished 12:01:43
|
merge finished 12:01:43
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Wait for `merged into main at <commit>`. That commit is the task's work, on the project's
|
3. Wait for `merged into main at <commit>`. That commit is the task's work, on the project's
|
||||||
base branch.
|
base branch.
|
||||||
|
|
||||||
**Expected:** a green refusal line, not a red one. If it says `refused: the review found 1
|
**Expected:** a green refusal line, not a red one. If it says `refused: the review found 1
|
||||||
@@ -108,7 +122,13 @@ blocking item(s)`, the gate worked — the findings are on the task and in `Work
|
|||||||
**Starting a merge twice by accident is safe**: the merge takes a lock and the second one is
|
**Starting a merge twice by accident is safe**: the merge takes a lock and the second one is
|
||||||
refused with `another merge is in progress`.
|
refused with `another merge is in progress`.
|
||||||
|
|
||||||
## Step 4b — choose a task without leaving Work
|
## Step 4b — look at one run, without leaving Work
|
||||||
|
|
||||||
|
In `Work>work` the **runs** tab lists every run of the chosen task. `↑`/`↓` to one and press
|
||||||
|
`Enter`: the **log** tab opens with what Pi actually did — the wake payload, its reasoning, its
|
||||||
|
tool calls. `[` goes back.
|
||||||
|
|
||||||
|
## Step 4c — choose a task without leaving Work
|
||||||
|
|
||||||
In `Work>work`, press `o`. A list of this project's tasks appears. `↑`/`↓` to one, `Enter`, and
|
In `Work>work`, press `o`. A list of this project's tasks appears. `↑`/`↓` to one, `Enter`, and
|
||||||
the runs, change, facts, review and merge tabs all switch to it. You never have to go to
|
the runs, change, facts, review and merge tabs all switch to it. You never have to go to
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ what it shows is never a second copy of anything.
|
|||||||
| `Work>change` | worktree, branch, base, commits, changed files, the diff | built |
|
| `Work>change` | worktree, branch, base, commits, changed files, the diff | built |
|
||||||
| `Work>facts` | task, state, worktree path, branch, base, cost | built |
|
| `Work>facts` | task, state, worktree path, branch, base, cost | built |
|
||||||
| `Work>review` | the verdicts recorded on this task: review findings, refused merges, merged results, blocking ones in red | built |
|
| `Work>review` | the verdicts recorded on this task: review findings, refused merges, merged results, blocking ones in red | built |
|
||||||
| `Work>merge` | the last merge this screen ran, live, with `m` to start one — no terminal needed | built |
|
| `Work>log` | the output of the run you picked on the runs tab | built |
|
||||||
|
| `Work>merge` | the last merge this screen ran, live; `m` asks first, then merges — no terminal needed | built |
|
||||||
|
|
||||||
## 4. Reply
|
## 4. Reply
|
||||||
|
|
||||||
|
|||||||
117
tui/work.go
117
tui/work.go
@@ -19,6 +19,12 @@ import (
|
|||||||
"paperclip-harness/tui/paperclip"
|
"paperclip-harness/tui/paperclip"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type runLogMsg2 struct {
|
||||||
|
runID string
|
||||||
|
text string
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
type pickTasksMsg struct {
|
type pickTasksMsg struct {
|
||||||
issues []paperclip.Issue
|
issues []paperclip.Issue
|
||||||
err error
|
err error
|
||||||
@@ -46,9 +52,13 @@ type workModel struct {
|
|||||||
diff string
|
diff string
|
||||||
diffErr error
|
diffErr error
|
||||||
err error
|
err error
|
||||||
|
logRunID string
|
||||||
|
logText string
|
||||||
|
|
||||||
tab int
|
tab int
|
||||||
scroll int
|
scroll int
|
||||||
|
runAt int
|
||||||
|
confirm bool
|
||||||
tools bool
|
tools bool
|
||||||
toolAt int
|
toolAt int
|
||||||
|
|
||||||
@@ -63,7 +73,7 @@ type workModel struct {
|
|||||||
width, height int
|
width, height int
|
||||||
}
|
}
|
||||||
|
|
||||||
var workTabs = []string{"runs", "change", "facts", "review", "merge"}
|
var workTabs = []string{"runs", "change", "facts", "review", "log", "merge"}
|
||||||
|
|
||||||
func newWorkModel(c *paperclip.Client, folder, issueID string) workModel {
|
func newWorkModel(c *paperclip.Client, folder, issueID string) workModel {
|
||||||
return workModel{client: c, folder: folder, issue: issueID, explicit: issueID != ""}
|
return workModel{client: c, folder: folder, issue: issueID, explicit: issueID != ""}
|
||||||
@@ -73,6 +83,15 @@ func (m workModel) Init() tea.Cmd {
|
|||||||
return tea.Batch(m.load(), tickEvery(5*time.Second), tea.WindowSize())
|
return tea.Batch(m.load(), tickEvery(5*time.Second), tea.WindowSize())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// loadRunLog reads one run's output for the log tab.
|
||||||
|
func (m workModel) loadRunLog(runID string) tea.Cmd {
|
||||||
|
c := m.client
|
||||||
|
return func() tea.Msg {
|
||||||
|
text, err := c.RunLog(runID, 8<<20)
|
||||||
|
return runLogMsg2{runID: runID, text: text, err: err}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (m workModel) load() tea.Cmd {
|
func (m workModel) load() tea.Cmd {
|
||||||
c, folder := m.client, m.folder
|
c, folder := m.client, m.folder
|
||||||
fixed, explicit := m.issue, m.explicit
|
fixed, explicit := m.issue, m.explicit
|
||||||
@@ -136,6 +155,22 @@ func (m workModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
return m, tea.Batch(m.load(), tickEvery(5*time.Second), tea.WindowSize())
|
return m, tea.Batch(m.load(), tickEvery(5*time.Second), tea.WindowSize())
|
||||||
|
|
||||||
case tea.KeyMsg:
|
case tea.KeyMsg:
|
||||||
|
if m.confirm {
|
||||||
|
switch msg.String() {
|
||||||
|
case "y":
|
||||||
|
m.confirm = false
|
||||||
|
if err := startMerge(m.folder, m.task.Identifier); err != nil {
|
||||||
|
m.err = err
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
m.tab = 5
|
||||||
|
m.scroll = 1 << 30
|
||||||
|
return m, m.load()
|
||||||
|
case "esc", "n", "q":
|
||||||
|
m.confirm = false
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
if m.picking {
|
if m.picking {
|
||||||
switch msg.String() {
|
switch msg.String() {
|
||||||
case "esc", "q", "o":
|
case "esc", "q", "o":
|
||||||
@@ -220,18 +255,12 @@ func (m workModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
return pickTasksMsg{issues: mine}
|
return pickTasksMsg{issues: mine}
|
||||||
}
|
}
|
||||||
case "m":
|
case "m":
|
||||||
|
// Merging is a decision, so it asks first and shows what it will do.
|
||||||
if m.task.Identifier == "" {
|
if m.task.Identifier == "" {
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
// The merge runs on its own and writes what it does to a log this
|
m.confirm = true
|
||||||
// tab reads, so nobody has to type a command or leave the screen.
|
|
||||||
if err := startMerge(m.folder, m.task.Identifier); err != nil {
|
|
||||||
m.err = err
|
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
|
||||||
m.tab = 4
|
|
||||||
m.scroll = 1 << 30
|
|
||||||
return m, m.load()
|
|
||||||
case "?":
|
case "?":
|
||||||
m.showHelp = true
|
m.showHelp = true
|
||||||
return m, nil
|
return m, nil
|
||||||
@@ -258,9 +287,15 @@ func (m workModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
}
|
}
|
||||||
return m, nil
|
return m, nil
|
||||||
case "up", "k":
|
case "up", "k":
|
||||||
|
if m.tab == 0 && m.runAt > 0 {
|
||||||
|
m.runAt--
|
||||||
|
}
|
||||||
m.scroll--
|
m.scroll--
|
||||||
return m, nil
|
return m, nil
|
||||||
case "down", "j":
|
case "down", "j":
|
||||||
|
if m.tab == 0 && m.runAt < len(m.runs)-1 {
|
||||||
|
m.runAt++
|
||||||
|
}
|
||||||
m.scroll++
|
m.scroll++
|
||||||
return m, nil
|
return m, nil
|
||||||
case "g":
|
case "g":
|
||||||
@@ -269,10 +304,25 @@ func (m workModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
|||||||
case "G":
|
case "G":
|
||||||
m.scroll = 1 << 30
|
m.scroll = 1 << 30
|
||||||
return m, nil
|
return m, nil
|
||||||
|
case "enter":
|
||||||
|
if m.tab == 0 && m.runAt < len(m.runs) {
|
||||||
|
m.tab = 4
|
||||||
|
m.scroll = 1 << 30
|
||||||
|
return m, m.loadRunLog(m.runs[m.runAt].ID)
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
case "esc":
|
case "esc":
|
||||||
return m, nil
|
return m, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case runLogMsg2:
|
||||||
|
m.logRunID = msg.runID
|
||||||
|
m.logText = msg.text
|
||||||
|
if msg.err != nil {
|
||||||
|
m.err = msg.err
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
|
||||||
case pickTasksMsg:
|
case pickTasksMsg:
|
||||||
m.pickList = msg.issues
|
m.pickList = msg.issues
|
||||||
m.pickAt = 0
|
m.pickAt = 0
|
||||||
@@ -341,11 +391,27 @@ func (m workModel) View() string {
|
|||||||
case 3:
|
case 3:
|
||||||
body = m.reviewLines(m.width - 4)
|
body = m.reviewLines(m.width - 4)
|
||||||
case 4:
|
case 4:
|
||||||
|
body = m.logLinesWork(m.width - 4)
|
||||||
|
case 5:
|
||||||
body = m.mergeLines(m.width - 4)
|
body = m.mergeLines(m.width - 4)
|
||||||
default:
|
default:
|
||||||
body = m.factsLines(m.width - 4)
|
body = m.factsLines(m.width - 4)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if m.confirm {
|
||||||
|
verify := "no verify command: the review decides"
|
||||||
|
if cmd := verifyFromDescription(m.task.Description); cmd != "" {
|
||||||
|
verify = "verify command: " + cmd
|
||||||
|
}
|
||||||
|
return helpOverlay("merge "+m.task.Identifier+"?", [][2]string{
|
||||||
|
{"what happens", "rebase onto the base branch"},
|
||||||
|
{"", verify},
|
||||||
|
{"", "ocr reviews the change; a critical finding refuses the merge"},
|
||||||
|
{"", "merge, then re-run the checks on the base branch"},
|
||||||
|
{"y", "do it"},
|
||||||
|
{"esc or n", "do nothing"},
|
||||||
|
}, m.width, m.height)
|
||||||
|
}
|
||||||
if m.picking {
|
if m.picking {
|
||||||
entries := make([][2]string, 0, len(m.pickList))
|
entries := make([][2]string, 0, len(m.pickList))
|
||||||
for i, is := range m.pickList {
|
for i, is := range m.pickList {
|
||||||
@@ -391,7 +457,7 @@ func (m workModel) View() string {
|
|||||||
keyHint("↑↓ or j k", "scroll"),
|
keyHint("↑↓ or j k", "scroll"),
|
||||||
keyHint("t", "open a tool pane"),
|
keyHint("t", "open a tool pane"),
|
||||||
keyHint("o", "choose a task"),
|
keyHint("o", "choose a task"),
|
||||||
keyHint("m", "merge this task"),
|
keyHint("m", "merge this task (asks first)"),
|
||||||
keyHint("]", "tabs"),
|
keyHint("]", "tabs"),
|
||||||
keyHint("r", "read again"),
|
keyHint("r", "read again"),
|
||||||
keyHint("R", "rebuild every pane"),
|
keyHint("R", "rebuild every pane"),
|
||||||
@@ -540,6 +606,37 @@ func (m workModel) reviewLines(width int) []string {
|
|||||||
|
|
||||||
// mergeLines shows the last merge this screen started, read from the log the
|
// mergeLines shows the last merge this screen started, read from the log the
|
||||||
// merge writes. Pressing m again is safe: the merge takes a lock.
|
// merge writes. Pressing m again is safe: the merge takes a lock.
|
||||||
|
// logLinesWork shows the output of the run chosen on the runs tab.
|
||||||
|
func (m workModel) logLinesWork(width int) []string {
|
||||||
|
if m.logRunID == "" {
|
||||||
|
return []string{"", mutedStyle2().Render(" choose a run on the runs tab, then press enter")}
|
||||||
|
}
|
||||||
|
if m.logText == "" {
|
||||||
|
return []string{"", mutedStyle2().Render(" no output recorded for this run")}
|
||||||
|
}
|
||||||
|
out := []string{"", dimStyle().Render(" run " + short(m.logRunID)), ""}
|
||||||
|
entries := decodeRunLog(m.logText)
|
||||||
|
if len(entries) > 2000 {
|
||||||
|
entries = entries[len(entries)-2000:]
|
||||||
|
}
|
||||||
|
for _, e := range entries {
|
||||||
|
colour := active.Text
|
||||||
|
switch e.stream {
|
||||||
|
case "thinking":
|
||||||
|
colour = active.Muted
|
||||||
|
case "prompt":
|
||||||
|
colour = active.Info
|
||||||
|
case "tool":
|
||||||
|
colour = active.Warning
|
||||||
|
case "event":
|
||||||
|
colour = active.Overlay
|
||||||
|
}
|
||||||
|
out = append(out, " "+dimStyle().Render(e.when)+" "+
|
||||||
|
lipgloss.NewStyle().Foreground(lipgloss.Color(colour)).Render(truncateVisible(e.line, width-10)))
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
func (m workModel) mergeLines(width int) []string {
|
func (m workModel) mergeLines(width int) []string {
|
||||||
out := []string{"", dimStyle().Render(" " + mergeLogPath()), ""}
|
out := []string{"", dimStyle().Render(" " + mergeLogPath()), ""}
|
||||||
for _, ln := range mergeLogTail(max(6, m.height-6)) {
|
for _, ln := range mergeLogTail(max(6, m.height-6)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user