Work>review and tool panes; panes re-sync their size; the Work pane follows the Board again
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
---
|
||||
type: context
|
||||
id: context.paperclip-harness.both-defects-fixed-and-the-settings-editor-is-in
|
||||
title: both-defects-fixed-and-the-settings-editor-is-in
|
||||
status: active
|
||||
source_of_truth: false
|
||||
freshness: current
|
||||
last_reviewed: 2026-11-10
|
||||
tags:
|
||||
- pack/paperclip-harness
|
||||
- agent-memory/context
|
||||
- autolearn
|
||||
- rich-discovery
|
||||
- repo/both-defects-fixed-and-the-settings-editor-is-in
|
||||
---
|
||||
|
||||
# both-defects-fixed-and-the-settings-editor-is-in
|
||||
|
||||
## Rich discovery update (2026-11-10 06:23:51)
|
||||
|
||||
Both defects fixed, and the settings editor is in.
|
||||
|
||||
## The three things you reported
|
||||
|
||||
**Runs were every run in Paperclip.** Correct — 281 company-wide. They are now scoped to this project's tasks, resolved through each run's own task reference, and the task column shows `AUD-166` instead of a bare identifier. `A` toggles between "this project" and "everything in the company", because both are legitimate questions but not the same one.
|
||||
|
||||
**Scrolling instead of selecting.** The run list had no cursor at all — arrows only moved the viewport. There is now one cursor per tab, the selected row is highlighted, and the list scrolls only to keep the cursor visible. `enter` opens that run's log. Tested: picked the second run, its log opened.
|
||||
|
||||
**Roster could not be walked.** Same cause, same fix. The roster is sorted by name so the cursor stays on the same agent after a reload, and `▸` marks the row.
|
||||
|
||||
The log itself also became readable: it is a stream of token deltas, so deltas are gathered back into paragraphs while tool calls, prompts and turn markers become single lines:
|
||||
|
||||
```
|
||||
15:55:57 toolcall_start
|
||||
15:55:57 {"command": "pwd && ls -la && git log --oneline -10 2>/dev/null"}
|
||||
15:55:58 toolcall_end
|
||||
15:55:58 assistant: I'll start by inspecting the workspace…
|
||||
```
|
||||
|
||||
## Agents>settings is built
|
||||
|
||||
Fourth tab. Role, job title, model, monthly budget, heartbeat. `enter` edits the chosen field inline, `esc` cancels; heartbeat is a toggle. Every save is one `PATCH /api/agents/{id}` that merges into that agent's existing configuration, so a model change does not wipe its working folder or instructions — verified by reading the record back after a save.
|
||||
|
||||
`p`, `P`, `w` pause, resume and wake, acting on the agent chosen on that tab.
|
||||
|
||||
**One thing you should know:** `Builder` was paused at 16:56 with `pauseReason: manual`, from the board key — that was my keystroke test, not you. I have resumed it and it is idle again. Sorry for the scare.
|
||||
|
||||
## Still missing, in order
|
||||
|
||||
1. **Work>review** — the ocr verdict beside the diff. That is now the only missing panel.
|
||||
2. **Tool panes** — `t` opens Lazygit, Hunk, Yazi, Neovim, fzf or ocr in the current workspace; `esc` closes it.
|
||||
|
||||
`docs/WORKSPACES.md` is updated: 22 panels built across 8 workspaces, one panel missing, six tool panes to wire. Committed as `ec7e907`.
|
||||
|
||||
Which of those two next?
|
||||
|
||||
## Source paths observed
|
||||
|
||||
- `omni/deepseek/deepseek-v4-flash`
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 84%
|
||||
- Reason: Update component/repository context with detailed discovered structure and configuration
|
||||
|
||||
## Related
|
||||
|
||||
- [[packs/paperclip-harness/00-system/pi-agent/memory-manifest|Memory Manifest]]
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-10 06:23:51 -->
|
||||
|
||||
- context: [[packs/paperclip-harness/20-context/tmp|Paperclip TUI Agents pane]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tui-workspaces-panels-and-tools-status|Paperclip TUI workspaces/panels and tools status]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Agents pane defect causes: missing cursors, unscoped runs]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/editing-agent-settings-and-pausing-resuming-in-tui|Editing agent settings and pausing/resuming in TUI]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Agents pane: scoped runs, cursors, settings editor]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-both-defects-fixed-and-the-settings-editor-is|Rich discovery: both-defects-fixed-and-the-settings-editor-is-in 2026-11-10 06:23:51]]
|
||||
- context: [[packs/paperclip-harness/20-context/both-defects-fixed-and-the-settings-editor-is-in|both-defects-fixed-and-the-settings-editor-is-in]]
|
||||
@@ -0,0 +1,85 @@
|
||||
---
|
||||
type: context
|
||||
id: context.paperclip-harness.paperclip-tui-workspaces-panels-and-tools-status
|
||||
title: Paperclip TUI workspaces/panels and tools status
|
||||
status: active
|
||||
source_of_truth: false
|
||||
freshness: current
|
||||
last_reviewed: 2026-11-10
|
||||
tags:
|
||||
- pack/paperclip-harness
|
||||
- agent-memory/context
|
||||
- paperclip
|
||||
- tui
|
||||
- workspaces
|
||||
- panels
|
||||
- docs
|
||||
- ocr
|
||||
---
|
||||
|
||||
# Paperclip TUI workspaces/panels and tools status
|
||||
|
||||
Paperclip TUI organizes UI into workspaces containing panels. As of commit `ec7e907` (`docs/WORKSPACES.md`): **22 panels built across 8 workspaces**, with **one panel missing** and **six tool panes** still to wire.
|
||||
|
||||
Remaining work:
|
||||
1. **Work>review** — the ocr verdict shown beside the diff. This is the only missing panel.
|
||||
2. **Tool panes** — `t` opens Lazygit, Hunk, Yazi, Neovim, fzf, or ocr in the current workspace; `esc` closes it. The six tools: Lazygit, Hunk, Yazi, Neovim, fzf, ocr.
|
||||
|
||||
`docs/WORKSPACES.md` is the tracking doc for panel/tool-workspace status and should be updated as panels are built.
|
||||
|
||||
## Detailed context from completed turn
|
||||
|
||||
Both defects fixed, and the settings editor is in.
|
||||
|
||||
## The three things you reported
|
||||
|
||||
**Runs were every run in Paperclip.** Correct — 281 company-wide. They are now scoped to this project's tasks, resolved through each run's own task reference, and the task column shows `AUD-166` instead of a bare identifier. `A` toggles between "this project" and "everything in the company", because both are legitimate questions but not the same one.
|
||||
|
||||
**Scrolling instead of selecting.** The run list had no cursor at all — arrows only moved the viewport. There is now one cursor per tab, the selected row is highlighted, and the list scrolls only to keep the cursor visible. `enter` opens that run's log. Tested: picked the second run, its log opened.
|
||||
|
||||
**Roster could not be walked.** Same cause, same fix. The roster is sorted by name so the cursor stays on the same agent after a reload, and `▸` marks the row.
|
||||
|
||||
The log itself also became readable: it is a stream of token deltas, so deltas are gathered back into paragraphs while tool calls, prompts and turn markers become single lines:
|
||||
|
||||
```
|
||||
15:55:57 toolcall_start
|
||||
15:55:57 {"command": "pwd && ls -la && git log --oneline -10 2>/dev/null"}
|
||||
15:55:58 toolcall_end
|
||||
15:55:58 assistant: I'll start by inspecting the workspace…
|
||||
```
|
||||
|
||||
## Agents>settings is built
|
||||
|
||||
Fourth tab. Role, job title, model, monthly budget, heartbeat. `enter` edits the chosen field inline, `esc` cancels; heartbeat is a toggle. Every save is one `PATCH /api/agents/{id}` that merges into that agent's existing configuration, so a model change does not wipe its working folder or instructions — verified by reading the record back after a save.
|
||||
|
||||
`p`, `P`, `w` pause, resume and wake, acting on the agent chosen on that tab.
|
||||
|
||||
**One thing you should know:** `Builder` was paused at 16:56 with `pauseReason: manual`, from the board key — that was my keystroke test, not you. I have resumed it and it is idle again. Sorry for the scare.
|
||||
|
||||
## Still missing, in order
|
||||
|
||||
1. **Work>review** — the ocr verdict beside the diff. That is now the only missing panel.
|
||||
2. **Tool panes** — `t` opens Lazygit, Hunk, Yazi, Neovim, fzf or ocr in the current workspace; `esc` closes it.
|
||||
|
||||
`docs/WORKSPACES.md` is updated: 22 panels built across 8 workspaces, one panel missing, six tool panes to wire. Committed as `ec7e907`.
|
||||
|
||||
Which of those two next?
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 80%
|
||||
- Reason: Architecture/status details from final summary and commit reference; useful for future work on remaining panels.; enriched with final-answer detail because persistence should be reusable
|
||||
|
||||
## Related
|
||||
|
||||
- [[packs/paperclip-harness/00-system/pi-agent/memory-manifest|Memory Manifest]]
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-10 06:23:51 -->
|
||||
|
||||
- context: [[packs/paperclip-harness/20-context/tmp|Paperclip TUI Agents pane]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tui-workspaces-panels-and-tools-status|Paperclip TUI workspaces/panels and tools status]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Agents pane defect causes: missing cursors, unscoped runs]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/editing-agent-settings-and-pausing-resuming-in-tui|Editing agent settings and pausing/resuming in TUI]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Agents pane: scoped runs, cursors, settings editor]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-both-defects-fixed-and-the-settings-editor-is|Rich discovery: both-defects-fixed-and-the-settings-editor-is-in 2026-11-10 06:23:51]]
|
||||
- context: [[packs/paperclip-harness/20-context/both-defects-fixed-and-the-settings-editor-is-in|both-defects-fixed-and-the-settings-editor-is-in]]
|
||||
@@ -466,3 +466,33 @@ Say which of the three you want next, and I will build only that.
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-the-full-list-at-the-end-of-the-project-with-|Rich discovery: the-full-list-at-the-end-of-the-project-with-what-exists-tod 2026-11-10 05:59:07]]
|
||||
- context: [[packs/paperclip-harness/20-context/tmp|the-full-list-at-the-end-of-the-project-with-what-exists-tod]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|the-full-list-at-the-end-of-the-project-with-what-exists-tod repository structure and configuration patterns]]
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-10 06:23:51)
|
||||
|
||||
The Paperclip terminal UI (TUI) has an "Agents" pane with four tabs: roster, runs, log, and settings. It tracks agents (researcher, System, Hub, Chief of Staff, Builder, Documenter), their states (idle/paused), spend vs. budget, and run history.
|
||||
|
||||
Key behaviors:
|
||||
- **runs tab**: project-scoped to the current project's tasks by default (resolved through each run's task reference, shown as e.g. `AUD-166`). `A` toggles between "this project" and company-wide runs. Company-wide total at time of work: 281 runs.
|
||||
- **log tab**: renders run logs. Logs are a stream of token deltas; the viewer merges deltas into paragraphs while tool calls, prompts, and turn markers each become single lines (e.g. `toolcall_start`, `toolcall_end`, `assistant:` lines).
|
||||
- **settings tab**: editable fields for each agent — role, job title, model, monthly budget, heartbeat. `enter` edits a field inline, `esc` cancels, heartbeat is a toggle. Saves go through one `PATCH /api/agents/{id}` that merges into the agent's existing config (does not wipe working folder or instructions). `p`/`P`/`w` pause/resume/wake the selected agent.
|
||||
- **Navigation**: each tab has its own cursor; `enter` opens detail (e.g. run log). Roster is sorted by name so cursor stays on the same agent after reload; `▸` marks the selected row.
|
||||
|
||||
The pause control writes `pausedAt` and `pauseReason` (e.g. `manual` from a board key) to the agent status.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 85%
|
||||
- Reason: Evidence-backed overview of the Agents pane architecture and behaviors from the turn's tool output and final summary.
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-10 06:23:51 -->
|
||||
|
||||
- context: [[packs/paperclip-harness/20-context/tmp|Paperclip TUI Agents pane]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tui-workspaces-panels-and-tools-status|Paperclip TUI workspaces/panels and tools status]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Agents pane defect causes: missing cursors, unscoped runs]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/editing-agent-settings-and-pausing-resuming-in-tui|Editing agent settings and pausing/resuming in TUI]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Agents pane: scoped runs, cursors, settings editor]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-both-defects-fixed-and-the-settings-editor-is|Rich discovery: both-defects-fixed-and-the-settings-editor-is-in 2026-11-10 06:23:51]]
|
||||
- context: [[packs/paperclip-harness/20-context/both-defects-fixed-and-the-settings-editor-is-in|both-defects-fixed-and-the-settings-editor-is-in]]
|
||||
|
||||
@@ -280,3 +280,35 @@ Follow-up: user asked to pick item 1..5; only build the chosen item.
|
||||
- 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]]
|
||||
- context: [[packs/paperclip-harness/20-context/home|home]]
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-10 06:23:51)
|
||||
|
||||
Delivered and committed (`ec7e907`: "Agents pane: project-scoped runs with selection, roster cursor, editable settings").
|
||||
|
||||
Changes:
|
||||
- Runs tab now project-scoped by default with task column, `A` toggles company-wide.
|
||||
- Added per-tab cursors for runs and roster; `enter` opens the selected run's log; selection highlighted, scroll-follows-cursor.
|
||||
- Log viewer now merges token deltas into paragraphs; tool calls/prompts/turn markers as single lines.
|
||||
- New settings tab (4th tab): edit role, job title, model, monthly budget, heartbeat via inline edit (`enter` saves, `esc` cancels, heartbeat toggle). Saves are single `PATCH /api/agents/{id}` merging into existing config; verified config preserved after save.
|
||||
- `p`/`P`/`w` pause/resume/wake act on the selected agent.
|
||||
- Updated `docs/WORKSPACES.md` (22 panels across 8 workspaces, 1 missing panel, 6 tool panes to wire).
|
||||
|
||||
Validation: build passed (`build=0`); manual tests of run selection/open, settings edit/save, and pause/resume round-trip.
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 90%
|
||||
- Reason: Completed, verified deliverable with commit hash, artifacts, and validation.
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-10 06:23:51 -->
|
||||
|
||||
- context: [[packs/paperclip-harness/20-context/tmp|Paperclip TUI Agents pane]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tui-workspaces-panels-and-tools-status|Paperclip TUI workspaces/panels and tools status]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Agents pane defect causes: missing cursors, unscoped runs]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/editing-agent-settings-and-pausing-resuming-in-tui|Editing agent settings and pausing/resuming in TUI]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Agents pane: scoped runs, cursors, settings editor]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-both-defects-fixed-and-the-settings-editor-is|Rich discovery: both-defects-fixed-and-the-settings-editor-is-in 2026-11-10 06:23:51]]
|
||||
- context: [[packs/paperclip-harness/20-context/both-defects-fixed-and-the-settings-editor-is-in|both-defects-fixed-and-the-settings-editor-is-in]]
|
||||
|
||||
@@ -979,3 +979,172 @@ Say which of the three you want next, and I will build only that.
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-the-full-list-at-the-end-of-the-project-with-|Rich discovery: the-full-list-at-the-end-of-the-project-with-what-exists-tod 2026-11-10 05:59:07]]
|
||||
- context: [[packs/paperclip-harness/20-context/tmp|the-full-list-at-the-end-of-the-project-with-what-exists-tod]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|the-full-list-at-the-end-of-the-project-with-what-exists-tod repository structure and configuration patterns]]
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-10 06:23:51)
|
||||
|
||||
Three defects were diagnosed in the Paperclip TUI Agents pane:
|
||||
- **Runs list was company-wide** (281 runs) instead of project-scoped; fixed by resolving each run's task reference to the current project and showing the task ID (e.g. `AUD-166`). Added `A` to toggle project/all scope.
|
||||
- **Scrolling instead of selecting** (runs tab): the list had no cursor, so arrow keys only moved the viewport. Fix: per-tab cursor, highlighted selection row, scroll only to keep cursor visible. `enter` opens the selected run's log.
|
||||
- **Roster could not be walked**: same root cause (no cursor); fixed with per-tab cursor and name-sorted roster so selection is stable across reloads.
|
||||
|
||||
Also fixed log readability: raw token-delta stream was gathered into paragraphs while tool calls/prompts/turn markers became single lines.
|
||||
|
||||
## Detailed observations from completed turn
|
||||
|
||||
Both defects fixed, and the settings editor is in.
|
||||
|
||||
## The three things you reported
|
||||
|
||||
**Runs were every run in Paperclip.** Correct — 281 company-wide. They are now scoped to this project's tasks, resolved through each run's own task reference, and the task column shows `AUD-166` instead of a bare identifier. `A` toggles between "this project" and "everything in the company", because both are legitimate questions but not the same one.
|
||||
|
||||
**Scrolling instead of selecting.** The run list had no cursor at all — arrows only moved the viewport. There is now one cursor per tab, the selected row is highlighted, and the list scrolls only to keep the cursor visible. `enter` opens that run's log. Tested: picked the second run, its log opened.
|
||||
|
||||
**Roster could not be walked.** Same cause, same fix. The roster is sorted by name so the cursor stays on the same agent after a reload, and `▸` marks the row.
|
||||
|
||||
The log itself also became readable: it is a stream of token deltas, so deltas are gathered back into paragraphs while tool calls, prompts and turn markers become single lines:
|
||||
|
||||
```
|
||||
15:55:57 toolcall_start
|
||||
15:55:57 {"command": "pwd && ls -la && git log --oneline -10 2>/dev/null"}
|
||||
15:55:58 toolcall_end
|
||||
15:55:58 assistant: I'll start by inspecting the workspace…
|
||||
```
|
||||
|
||||
## Agents>settings is built
|
||||
|
||||
Fourth tab. Role, job title, model, monthly budget, heartbeat. `enter` edits the chosen field inline, `esc` cancels; heartbeat is a toggle. Every save is one `PATCH /api/agents/{id}` that merges into that agent's existing configuration, so a model change does not wipe its working folder or instructions — verified by reading the record back after a save.
|
||||
|
||||
`p`, `P`, `w` pause, resume and wake, acting on the agent chosen on that tab.
|
||||
|
||||
**One thing you should know:** `Builder` was paused at 16:56 with `pauseReason: manual`, from the board key — that was my keystroke test, not you. I have resumed it and it is idle again. Sorry for the scare.
|
||||
|
||||
## Still missing, in order
|
||||
|
||||
1. **Work>review** — the ocr verdict beside the diff. That is now the only missing panel.
|
||||
2. **Tool panes** — `t` opens Lazygit, Hunk, Yazi, Neovim, fzf or ocr in the current workspace; `esc` closes it.
|
||||
|
||||
`docs/WORKSPACES.md` is updated: 22 panels built across 8 workspaces, one panel missing, six tool panes to wire. Committed as `ec7e907`.
|
||||
|
||||
Which of those two next?
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 85%
|
||||
- Reason: Diagnosis and root-cause findings from tool output and summary; valuable for future Agents pane work.; enriched with final-answer detail because persistence should be reusable
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-10 06:23:51)
|
||||
|
||||
The Builder agent was observed paused with `status: paused pausedAt: 2026-11-10T05:56:47.518Z reason: manual`, caused by a keystroke test on the board key (not the user). Resuming via the pause/resume control returned HTTP 200 and the agent returned to `status: idle`.
|
||||
|
||||
Caveat for future agents: pause/resume/wake keys (`p`/`P`/`w`) act on the currently selected agent and can unintentionally pause a live agent; always confirm the selection before keying. Pause state persists in agent status and can be resumed via the same control.
|
||||
|
||||
## Detailed observations from completed turn
|
||||
|
||||
Both defects fixed, and the settings editor is in.
|
||||
|
||||
## The three things you reported
|
||||
|
||||
**Runs were every run in Paperclip.** Correct — 281 company-wide. They are now scoped to this project's tasks, resolved through each run's own task reference, and the task column shows `AUD-166` instead of a bare identifier. `A` toggles between "this project" and "everything in the company", because both are legitimate questions but not the same one.
|
||||
|
||||
**Scrolling instead of selecting.** The run list had no cursor at all — arrows only moved the viewport. There is now one cursor per tab, the selected row is highlighted, and the list scrolls only to keep the cursor visible. `enter` opens that run's log. Tested: picked the second run, its log opened.
|
||||
|
||||
**Roster could not be walked.** Same cause, same fix. The roster is sorted by name so the cursor stays on the same agent after a reload, and `▸` marks the row.
|
||||
|
||||
The log itself also became readable: it is a stream of token deltas, so deltas are gathered back into paragraphs while tool calls, prompts and turn markers become single lines:
|
||||
|
||||
```
|
||||
15:55:57 toolcall_start
|
||||
15:55:57 {"command": "pwd && ls -la && git log --oneline -10 2>/dev/null"}
|
||||
15:55:58 toolcall_end
|
||||
15:55:58 assistant: I'll start by inspecting the workspace…
|
||||
```
|
||||
|
||||
## Agents>settings is built
|
||||
|
||||
Fourth tab. Role, job title, model, monthly budget, heartbeat. `enter` edits the chosen field inline, `esc` cancels; heartbeat is a toggle. Every save is one `PATCH /api/agents/{id}` that merges into that agent's existing configuration, so a model change does not wipe its working folder or instructions — verified by reading the record back after a save.
|
||||
|
||||
`p`, `P`, `w` pause, resume and wake, acting on the agent chosen on that tab.
|
||||
|
||||
**One thing you should know:** `Builder` was paused at 16:56 with `pauseReason: manual`, from the board key — that was my keystroke test, not you. I have resumed it and it is idle again. Sorry for the scare.
|
||||
|
||||
## Still missing, in order
|
||||
|
||||
1. **Work>review** — the ocr verdict beside the diff. That is now the only missing panel.
|
||||
2. **Tool panes** — `t` opens Lazygit, Hunk, Yazi, Neovim, fzf or ocr in the current workspace; `esc` closes it.
|
||||
|
||||
`docs/WORKSPACES.md` is updated: 22 panels built across 8 workspaces, one panel missing, six tool panes to wire. Committed as `ec7e907`.
|
||||
|
||||
Which of those two next?
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 80%
|
||||
- Reason: Concrete observed state, API behavior, and operational caveat.; enriched with final-answer detail because persistence should be reusable
|
||||
|
||||
|
||||
---
|
||||
|
||||
## Update (2026-11-10 06:23:51)
|
||||
|
||||
## Structural/configuration observations (2026-11-10 06:23:51)
|
||||
|
||||
Both defects fixed, and the settings editor is in.
|
||||
|
||||
## The three things you reported
|
||||
|
||||
**Runs were every run in Paperclip.** Correct — 281 company-wide. They are now scoped to this project's tasks, resolved through each run's own task reference, and the task column shows `AUD-166` instead of a bare identifier. `A` toggles between "this project" and "everything in the company", because both are legitimate questions but not the same one.
|
||||
|
||||
**Scrolling instead of selecting.** The run list had no cursor at all — arrows only moved the viewport. There is now one cursor per tab, the selected row is highlighted, and the list scrolls only to keep the cursor visible. `enter` opens that run's log. Tested: picked the second run, its log opened.
|
||||
|
||||
**Roster could not be walked.** Same cause, same fix. The roster is sorted by name so the cursor stays on the same agent after a reload, and `▸` marks the row.
|
||||
|
||||
The log itself also became readable: it is a stream of token deltas, so deltas are gathered back into paragraphs while tool calls, prompts and turn markers become single lines:
|
||||
|
||||
```
|
||||
15:55:57 toolcall_start
|
||||
15:55:57 {"command": "pwd && ls -la && git log --oneline -10 2>/dev/null"}
|
||||
15:55:58 toolcall_end
|
||||
15:55:58 assistant: I'll start by inspecting the workspace…
|
||||
```
|
||||
|
||||
## Agents>settings is built
|
||||
|
||||
Fourth tab. Role, job title, model, monthly budget, heartbeat. `enter` edits the chosen field inline, `esc` cancels; heartbeat is a toggle. Every save is one `PATCH /api/agents/{id}` that merges into that agent's existing configuration, so a model change does not wipe its working folder or instructions — verified by reading the record back after a save.
|
||||
|
||||
`p`, `P`, `w` pause, resume and wake, acting on the agent chosen on that tab.
|
||||
|
||||
**One thing you should know:** `Builder` was paused at 16:56 with `pauseReason: manual`, from the board key — that was my keystroke test, not you. I have resumed it and it is idle again. Sorry for the scare.
|
||||
|
||||
## Still missing, in order
|
||||
|
||||
1. **Work>review** — the ocr verdict beside the diff. That is now the only missing panel.
|
||||
2. **Tool panes** — `t` opens Lazygit, Hunk, Yazi, Neovim, fzf or ocr in the current workspace; `esc` closes it.
|
||||
|
||||
`docs/WORKSPACES.md` is updated: 22 panels built across 8 workspaces, one panel missing, six tool panes to wire. Committed as `ec7e907`.
|
||||
|
||||
Which of those two next?
|
||||
|
||||
## Source paths observed
|
||||
|
||||
- `omni/deepseek/deepseek-v4-flash`
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 82%
|
||||
- Reason: Captured factual repo structure/configuration patterns from rich discovery
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-10 06:23:51 -->
|
||||
|
||||
- context: [[packs/paperclip-harness/20-context/tmp|Paperclip TUI Agents pane]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tui-workspaces-panels-and-tools-status|Paperclip TUI workspaces/panels and tools status]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Agents pane defect causes: missing cursors, unscoped runs]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/editing-agent-settings-and-pausing-resuming-in-tui|Editing agent settings and pausing/resuming in TUI]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Agents pane: scoped runs, cursors, settings editor]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-both-defects-fixed-and-the-settings-editor-is|Rich discovery: both-defects-fixed-and-the-settings-editor-is-in 2026-11-10 06:23:51]]
|
||||
- context: [[packs/paperclip-harness/20-context/both-defects-fixed-and-the-settings-editor-is-in|both-defects-fixed-and-the-settings-editor-is-in]]
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
---
|
||||
type: runbook
|
||||
id: runbook.paperclip-harness.editing-agent-settings-and-pausing-resuming-in-tui
|
||||
title: Editing agent settings and pausing/resuming in TUI
|
||||
status: active
|
||||
source_of_truth: false
|
||||
freshness: current
|
||||
last_reviewed: 2026-11-10
|
||||
tags:
|
||||
- pack/paperclip-harness
|
||||
- agent-memory/runbook
|
||||
- paperclip
|
||||
- tui
|
||||
- runbook
|
||||
- agents
|
||||
- settings
|
||||
- pause
|
||||
---
|
||||
|
||||
# Editing agent settings and pausing/resuming in TUI
|
||||
|
||||
Trigger: need to change an agent's role/job title/model/budget/heartbeat, or pause/resume/wake an agent via the Paperclip TUI.
|
||||
|
||||
Prerequisites: TUI running, Agents pane available.
|
||||
|
||||
Procedure:
|
||||
1. Navigate to Agents>settings tab.
|
||||
2. Move cursor to the target agent on the roster; confirm `▸` is on the intended row (pause keys act on the selected agent — misselection can pause a live agent).
|
||||
3. `enter` on a field to edit inline; type value; `enter` saves, `esc` cancels. Heartbeat is a toggle.
|
||||
4. Save issues a single `PATCH /api/agents/{id}` that merges into existing config (does not wipe working folder/instructions). Model change applies to the agent's next run, not an in-flight run.
|
||||
5. To pause/resume/wake the selected agent press `p` / `P` / `w` respectively.
|
||||
|
||||
Verification / rollback: read the agent record back after saving to confirm fields persisted. If you accidentally pause an agent, resume with `P`; expect resume to return HTTP 200 and status to return to idle.
|
||||
|
||||
## Detailed procedure from completed turn
|
||||
|
||||
Both defects fixed, and the settings editor is in.
|
||||
|
||||
## The three things you reported
|
||||
|
||||
**Runs were every run in Paperclip.** Correct — 281 company-wide. They are now scoped to this project's tasks, resolved through each run's own task reference, and the task column shows `AUD-166` instead of a bare identifier. `A` toggles between "this project" and "everything in the company", because both are legitimate questions but not the same one.
|
||||
|
||||
**Scrolling instead of selecting.** The run list had no cursor at all — arrows only moved the viewport. There is now one cursor per tab, the selected row is highlighted, and the list scrolls only to keep the cursor visible. `enter` opens that run's log. Tested: picked the second run, its log opened.
|
||||
|
||||
**Roster could not be walked.** Same cause, same fix. The roster is sorted by name so the cursor stays on the same agent after a reload, and `▸` marks the row.
|
||||
|
||||
The log itself also became readable: it is a stream of token deltas, so deltas are gathered back into paragraphs while tool calls, prompts and turn markers become single lines:
|
||||
|
||||
```
|
||||
15:55:57 toolcall_start
|
||||
15:55:57 {"command": "pwd && ls -la && git log --oneline -10 2>/dev/null"}
|
||||
15:55:58 toolcall_end
|
||||
15:55:58 assistant: I'll start by inspecting the workspace…
|
||||
```
|
||||
|
||||
## Agents>settings is built
|
||||
|
||||
Fourth tab. Role, job title, model, monthly budget, heartbeat. `enter` edits the chosen field inline, `esc` cancels; heartbeat is a toggle. Every save is one `PATCH /api/agents/{id}` that merges into that agent's existing configuration, so a model change does not wipe its working folder or instructions — verified by reading the record back after a save.
|
||||
|
||||
`p`, `P`, `w` pause, resume and wake, acting on the agent chosen on that tab.
|
||||
|
||||
**One thing you should know:** `Builder` was paused at 16:56 with `pauseReason: manual`, from the board key — that was my keystroke test, not you. I have resumed it and it is idle again. Sorry for the scare.
|
||||
|
||||
## Still missing, in order
|
||||
|
||||
1. **Work>review** — the ocr verdict beside the diff. That is now the only missing panel.
|
||||
2. **Tool panes** — `t` opens Lazygit, Hunk, Yazi, Neovim, fzf or ocr in the current workspace; `esc` closes it.
|
||||
|
||||
`docs/WORKSPACES.md` is updated: 22 panels built across 8 workspaces, one panel missing, six tool panes to wire. Committed as `ec7e907`.
|
||||
|
||||
Which of those two next?
|
||||
|
||||
## Evidence
|
||||
|
||||
- Confidence: 80%
|
||||
- Reason: Repeatable procedure with a safety caveat learned during the turn.; enriched with final-answer detail because persistence should be reusable
|
||||
|
||||
## Related
|
||||
|
||||
- [[packs/paperclip-harness/00-system/pi-agent/memory-manifest|Memory Manifest]]
|
||||
|
||||
## Related learned memories <!-- same-turn-2026-11-10 06:23:51 -->
|
||||
|
||||
- context: [[packs/paperclip-harness/20-context/tmp|Paperclip TUI Agents pane]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tui-workspaces-panels-and-tools-status|Paperclip TUI workspaces/panels and tools status]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Agents pane defect causes: missing cursors, unscoped runs]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/editing-agent-settings-and-pausing-resuming-in-tui|Editing agent settings and pausing/resuming in TUI]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Agents pane: scoped runs, cursors, settings editor]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-both-defects-fixed-and-the-settings-editor-is|Rich discovery: both-defects-fixed-and-the-settings-editor-is-in 2026-11-10 06:23:51]]
|
||||
- context: [[packs/paperclip-harness/20-context/both-defects-fixed-and-the-settings-editor-is-in|both-defects-fixed-and-the-settings-editor-is-in]]
|
||||
@@ -0,0 +1,81 @@
|
||||
---
|
||||
type: session
|
||||
id: session.paperclip-harness.rich-discovery-both-defects-fixed-and-the-settings-editor-is
|
||||
title: Rich discovery: both-defects-fixed-and-the-settings-editor-is-in 2026-11-10 06:23:51
|
||||
status: active
|
||||
source_of_truth: false
|
||||
freshness: current
|
||||
last_reviewed: 2026-11-10
|
||||
tags:
|
||||
- pack/paperclip-harness
|
||||
- agent-memory/session
|
||||
- autolearn
|
||||
- rich-discovery
|
||||
- repo/both-defects-fixed-and-the-settings-editor-is-in
|
||||
---
|
||||
|
||||
# Rich discovery: both-defects-fixed-and-the-settings-editor-is-in 2026-11-10 06:23:51
|
||||
|
||||
Sanitized rich discovery snapshot captured automatically from the completed turn.
|
||||
|
||||
|
||||
## Source paths observed
|
||||
|
||||
- `omni/deepseek/deepseek-v4-flash`
|
||||
|
||||
## Final answer snapshot
|
||||
|
||||
Both defects fixed, and the settings editor is in.
|
||||
|
||||
## The three things you reported
|
||||
|
||||
**Runs were every run in Paperclip.** Correct — 281 company-wide. They are now scoped to this project's tasks, resolved through each run's own task reference, and the task column shows `AUD-166` instead of a bare identifier. `A` toggles between "this project" and "everything in the company", because both are legitimate questions but not the same one.
|
||||
|
||||
**Scrolling instead of selecting.** The run list had no cursor at all — arrows only moved the viewport. There is now one cursor per tab, the selected row is highlighted, and the list scrolls only to keep the cursor visible. `enter` opens that run's log. Tested: picked the second run, its log opened.
|
||||
|
||||
**Roster could not be walked.** Same cause, same fix. The roster is sorted by name so the cursor stays on the same agent after a reload, and `▸` marks the row.
|
||||
|
||||
The log itself also became readable: it is a stream of token deltas, so deltas are gathered back into paragraphs while tool calls, prompts and turn markers become single lines:
|
||||
|
||||
```
|
||||
15:55:57 toolcall_start
|
||||
15:55:57 {"command": "pwd && ls -la && git log --oneline -10 2>/dev/null"}
|
||||
15:55:58 toolcall_end
|
||||
15:55:58 assistant: I'll start by inspecting the workspace…
|
||||
```
|
||||
|
||||
## Agents>settings is built
|
||||
|
||||
Fourth tab. Role, job title, model, monthly budget, heartbeat. `enter` edits the chosen field inline, `esc` cancels; heartbeat is a toggle. Every save is one `PATCH /api/agents/{id}` that merges into that agent's existing configuration, so a model change does not wipe its working folder or instructions — verified by reading the record back after a save.
|
||||
|
||||
`p`, `P`, `w` pause, resume and wake, acting on the agent chosen on that tab.
|
||||
|
||||
**One thing you should know:** `Builder` was paused at 16:56 with `pauseReason: manual`, from the board key — that was my keystroke test, not you. I have resumed it and it is idle again. Sorry for the scare.
|
||||
|
||||
## Still missing, in order
|
||||
|
||||
1. **Work>review** — the ocr verdict beside the diff. That is now the only missing panel.
|
||||
2. **Tool panes** — `t` opens Lazygit, Hunk, Yazi, Neovim, fzf or ocr in the current workspace; `esc` closes it.
|
||||
|
||||
`docs/WORKSPACES.md` is updated: 22 panels built across 8 workspaces, one panel missing, six tool panes to wire. Committed as `ec7e907`.
|
||||
|
||||
Which of those two next?
|
||||
|
||||
## 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-10 06:23:51 -->
|
||||
|
||||
- context: [[packs/paperclip-harness/20-context/tmp|Paperclip TUI Agents pane]]
|
||||
- context: [[packs/paperclip-harness/20-context/paperclip-tui-workspaces-panels-and-tools-status|Paperclip TUI workspaces/panels and tools status]]
|
||||
- observation: [[packs/paperclip-harness/60-observations/tmp-repository-structure-and-configuration-patterns|Agents pane defect causes: missing cursors, unscoped runs]]
|
||||
- runbook: [[packs/paperclip-harness/70-runbooks/editing-agent-settings-and-pausing-resuming-in-tui|Editing agent settings and pausing/resuming in TUI]]
|
||||
- action: [[packs/paperclip-harness/40-actions/2026-11-10-wrote-docs-ui-layout-md-and-three-live-layout-mockups|Agents pane: scoped runs, cursors, settings editor]]
|
||||
- session: [[packs/paperclip-harness/80-sessions/rich-discovery-both-defects-fixed-and-the-settings-editor-is|Rich discovery: both-defects-fixed-and-the-settings-editor-is-in 2026-11-10 06:23:51]]
|
||||
- context: [[packs/paperclip-harness/20-context/both-defects-fixed-and-the-settings-editor-is-in|both-defects-fixed-and-the-settings-editor-is-in]]
|
||||
12
README.md
12
README.md
@@ -59,16 +59,24 @@ program running in the Board workspace.
|
||||
| Workspace>pane | shows | keys |
|
||||
|---|---|---|
|
||||
| Shell>shell | a prompt in the project folder | — |
|
||||
| Board>board | tasks by group · the chosen task · needs you | ↑↓ j k · enter · a · u · / · tab |
|
||||
| Work>work | runs · change · facts | [ ] tab · ↑↓ j k · g G |
|
||||
| Board>board | tasks by group · the chosen task · needs you | ↑↓ j k · enter · a · u · / · t (tools) · tab |
|
||||
| Work>work | runs · change · facts · review | [ ] tab · ↑↓ j k · g G · t (tools) |
|
||||
| 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 |
|
||||
| Project>project | facts · costs · settings | [ ] tab · ↑↓ j k |
|
||||
| Repair>repair | health · layout · rebuild log | [ ] tab · ↑↓ j k · R · B |
|
||||
| Agents>agents | roster · runs · log · settings | [ ] tab · ↑↓ j k · enter · p P w · A |
|
||||
|
||||
Choosing a task on the board and pressing Enter writes it into the project's
|
||||
`.harness/harness.toml`, and every other workspace follows within a second.
|
||||
|
||||
### Tool panes
|
||||
|
||||
`t` in `Board>board` or `Work>work` opens a chooser: shell, Lazygit, Hunk, Yazi, Neovim,
|
||||
fzf, ocr. The tool opens as a pane beside the one you are in, in the same workspace, and
|
||||
`esc` closes the chooser. Quitting the tool (its own key) closes its pane. Nothing is added
|
||||
to the layout, so the eight workspaces stay as they are.
|
||||
|
||||
### Refresh and rebuild
|
||||
|
||||
- **`r`** — read the data again in this panel. Nothing closes, nothing moves, the
|
||||
|
||||
BIN
bin/harness
BIN
bin/harness
Binary file not shown.
@@ -27,7 +27,7 @@ written yet.
|
||||
| `Work>runs` | run timeline and activity, with cost per run | built |
|
||||
| `Work>change` | worktree, branch, base, commits, changed files, the diff | built |
|
||||
| `Work>facts` | task, state, worktree path, branch, base, cost | built |
|
||||
| `Work>review` | the last ocr verdict for this task: findings, blocking ones in red, and whether a merge would be refused | **missing** |
|
||||
| `Work>review` | the verdicts recorded on this task: review findings, refused merges, merged results, blocking ones in red | built |
|
||||
|
||||
## 4. Reply
|
||||
|
||||
@@ -78,19 +78,20 @@ Yazi, fzf, Neovim, Lazygit, Hunk and anything else fits without being rebuilt by
|
||||
|
||||
| Tool | What it is for | Status |
|
||||
|---|---|---|
|
||||
| Lazygit | branches, commits, staging, history | installed, **not wired** |
|
||||
| Hunk | reading a change as a review | installed, **not wired** |
|
||||
| Yazi | files | installed, **not wired** |
|
||||
| Neovim | editing a file the task touched | installed, **not wired** |
|
||||
| fzf | picking anything | installed, **not wired** |
|
||||
| Lazygit | branches, commits, staging, history | wired: `t` in Board>board or Work>work |
|
||||
| Hunk | reading a change as a review | wired the same way |
|
||||
| Yazi | files | wired the same way |
|
||||
| Neovim | editing a file the task touched | wired the same way |
|
||||
| fzf | picking anything | wired the same way |
|
||||
| shell | any command the interface does not cover | built (`Shell>shell`) |
|
||||
| ocr | the review of the current change | installed, behind `bin/review` |
|
||||
|
||||
## Count
|
||||
|
||||
- **22 panels built**, across 8 workspaces.
|
||||
- **1 panel missing**: `Work>review`.
|
||||
- **6 tool panes** to wire: Lazygit, Hunk, Yazi, Neovim, fzf, ocr.
|
||||
- **23 panels built**, across 8 workspaces. Nothing is missing from the list above.
|
||||
- **tool panes wired** in Board>board and Work>work: `t` opens the chooser, `enter` opens
|
||||
the tool beside the pane, `esc` closes it, and the tool's own quit key closes its pane.
|
||||
The other workspaces can get the same key whenever it is wanted.
|
||||
|
||||
Nothing in the missing list changes the layout: each is one more panel inside a pane that
|
||||
already exists, or one pane-opener for a tool.
|
||||
|
||||
@@ -84,7 +84,7 @@ func newAgentsModel(c *paperclip.Client, folder string) agentsModel {
|
||||
}
|
||||
|
||||
func (m agentsModel) Init() tea.Cmd {
|
||||
return tea.Batch(m.load(), tickEvery(5*time.Second))
|
||||
return tea.Batch(m.load(), tickEvery(5*time.Second), tea.WindowSize())
|
||||
}
|
||||
|
||||
func (m agentsModel) load() tea.Cmd {
|
||||
|
||||
29
tui/board.go
29
tui/board.go
@@ -49,6 +49,8 @@ type boardModel struct {
|
||||
activity []paperclip.Activity
|
||||
needsTab int
|
||||
|
||||
tools bool
|
||||
toolAt int
|
||||
zones *zone.Manager
|
||||
filter string
|
||||
typing bool
|
||||
@@ -71,7 +73,7 @@ func newBoardModel(c *paperclip.Client, proj paperclip.Project, folder string) b
|
||||
}
|
||||
|
||||
func (m boardModel) Init() tea.Cmd {
|
||||
return tea.Batch(m.reload(), tickEvery(5*time.Second))
|
||||
return tea.Batch(m.reload(), tickEvery(5*time.Second), tea.WindowSize())
|
||||
}
|
||||
|
||||
func (m boardModel) reload() tea.Cmd {
|
||||
@@ -157,6 +159,27 @@ func (m boardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return m, nil
|
||||
|
||||
case tea.KeyMsg:
|
||||
if m.tools {
|
||||
switch msg.String() {
|
||||
case "esc", "q", "t":
|
||||
m.tools = false
|
||||
return m, nil
|
||||
case "up", "k":
|
||||
m.toolAt = max(0, m.toolAt-1)
|
||||
return m, nil
|
||||
case "down", "j":
|
||||
m.toolAt = min(len(tools)-1, m.toolAt+1)
|
||||
return m, nil
|
||||
case "enter":
|
||||
t := tools[m.toolAt]
|
||||
m.tools = false
|
||||
if err := openTool(m.folder, t.name); err != nil {
|
||||
m.err = err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
if m.showHelp {
|
||||
m.showHelp = false
|
||||
return m, nil
|
||||
@@ -192,6 +215,9 @@ func (m boardModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
case "?":
|
||||
m.showHelp = true
|
||||
return m, nil
|
||||
case "t":
|
||||
m.tools = true
|
||||
return m, nil
|
||||
case "/":
|
||||
m.typing = true
|
||||
return m, nil
|
||||
@@ -424,6 +450,7 @@ func (m boardModel) footerLine() string {
|
||||
keyHint("enter", "show it everywhere"),
|
||||
keyHint("a", "assign"),
|
||||
keyHint("u", "unblock"),
|
||||
keyHint("t", "tools"),
|
||||
keyHint("/", "filter"),
|
||||
keyHint("?", "keys"),
|
||||
keyHint("tab", "next panel"),
|
||||
|
||||
@@ -80,11 +80,9 @@ func main() {
|
||||
if dir == "" {
|
||||
dir, _ = os.Getwd()
|
||||
}
|
||||
issue := *issue
|
||||
if issue == "" {
|
||||
issue = watchedTask(dir)
|
||||
}
|
||||
m = newWorkModel(client, dir, issue)
|
||||
// Pass the flag, not a resolved task: an empty flag means "follow the
|
||||
// task chosen on the Board", and resolving it here would pin the pane.
|
||||
m = newWorkModel(client, dir, *issue)
|
||||
|
||||
case "tree":
|
||||
proj, err := client.ResolveProject(*project)
|
||||
|
||||
@@ -60,7 +60,7 @@ func newProjectModel(c *paperclip.Client, folder string) projectModel {
|
||||
}
|
||||
|
||||
func (m projectModel) Init() tea.Cmd {
|
||||
return tea.Batch(m.load(), tickEvery(10*time.Second))
|
||||
return tea.Batch(m.load(), tickEvery(10*time.Second), tea.WindowSize())
|
||||
}
|
||||
|
||||
func (m projectModel) load() tea.Cmd {
|
||||
|
||||
@@ -63,7 +63,7 @@ func newRepairModel(c *paperclip.Client, folder string) repairModel {
|
||||
}
|
||||
|
||||
func (m repairModel) Init() tea.Cmd {
|
||||
return tea.Batch(m.load(), tickEvery(8*time.Second))
|
||||
return tea.Batch(m.load(), tickEvery(8*time.Second), tea.WindowSize())
|
||||
}
|
||||
|
||||
func (m repairModel) load() tea.Cmd {
|
||||
@@ -194,7 +194,7 @@ func (m repairModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return m, nil
|
||||
|
||||
case tickMsg:
|
||||
return m, tea.Batch(m.load(), tickEvery(8*time.Second))
|
||||
return m, tea.Batch(m.load(), tickEvery(8*time.Second), tea.WindowSize())
|
||||
|
||||
case tea.KeyMsg:
|
||||
if m.showHelp {
|
||||
|
||||
@@ -55,7 +55,7 @@ func newReplyModel(c *paperclip.Client, folder, issueID string) replyModel {
|
||||
}
|
||||
|
||||
func (m replyModel) Init() tea.Cmd {
|
||||
return tea.Batch(m.load(), tickEvery(5*time.Second))
|
||||
return tea.Batch(m.load(), tickEvery(5*time.Second), tea.WindowSize())
|
||||
}
|
||||
|
||||
func (m replyModel) load() tea.Cmd {
|
||||
|
||||
180
tui/toolpane.go
Normal file
180
tui/toolpane.go
Normal file
@@ -0,0 +1,180 @@
|
||||
package main
|
||||
|
||||
// Tool panes: any terminal program this interface does not cover, opened beside
|
||||
// what you were reading and closed when you are done with it.
|
||||
//
|
||||
// Nothing is rebuilt. Lazygit, Hunk, Yazi, Neovim, fzf and ocr are the tools
|
||||
// people already use, and a pane is the correct place for them: they keep their
|
||||
// own keys, their own colours and their own way of working.
|
||||
//
|
||||
// A tool pane is not part of the layout. It is created on demand in the
|
||||
// workspace you are in and it disappears when the program exits, so the eight
|
||||
// workspaces stay as they are.
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
type tool struct {
|
||||
name string
|
||||
command string
|
||||
about string
|
||||
}
|
||||
|
||||
// tools are offered in this order: the shell first because it can reach
|
||||
// anything, then the three that read code, then the review.
|
||||
var tools = []tool{
|
||||
{"shell", "exec zsh -i", "a prompt in the project folder"},
|
||||
{"lazygit", "lazygit", "branches, commits, staging, history"},
|
||||
{"hunk", "hunk", "a change read as a review"},
|
||||
{"yazi", "yazi", "files"},
|
||||
{"nvim", "nvim", "editing one file"},
|
||||
{"fzf", "fzf", "picking anything"},
|
||||
{"ocr", "ocr review", "the review of the current change, in the terminal"},
|
||||
}
|
||||
|
||||
// currentWorkspace finds the workspace this program is drawn in. TUIOS knows;
|
||||
// the environment names the pane, and the pane's window says which workspace.
|
||||
func currentWorkspace() (string, string, error) {
|
||||
session := os.Getenv("TUIOS_SESSION")
|
||||
pane := os.Getenv("TUIOS_PANE_ID")
|
||||
if session == "" || pane == "" {
|
||||
return "", "", fmt.Errorf("this is not running inside a TUIOS pane")
|
||||
}
|
||||
out, err := exec.Command("tuios", "list-windows", "-s", session, "--json").Output()
|
||||
if err != nil {
|
||||
return "", "", fmt.Errorf("cannot ask TUIOS where this pane is: %w", err)
|
||||
}
|
||||
ws := workspaceOf(string(out), pane)
|
||||
if ws == "" {
|
||||
return "", "", fmt.Errorf("this pane is not in the layout TUIOS reports")
|
||||
}
|
||||
return session, ws, nil
|
||||
}
|
||||
|
||||
// workspaceOf finds the workspace number of one window in the JSON TUIOS
|
||||
// prints. It decodes properly rather than scanning text: a pane id appears in
|
||||
// more than one place, and the first match is not always the window.
|
||||
func workspaceOf(raw, paneID string) string {
|
||||
var doc struct {
|
||||
Windows []struct {
|
||||
WindowID string `json:"window_id"`
|
||||
Workspace int `json:"workspace"`
|
||||
} `json:"windows"`
|
||||
}
|
||||
if err := json.Unmarshal([]byte(raw), &doc); err != nil {
|
||||
return ""
|
||||
}
|
||||
for _, w := range doc.Windows {
|
||||
if w.WindowID == paneID {
|
||||
return strconv.Itoa(w.Workspace)
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
// openTool starts a program as a new pane in the current workspace.
|
||||
func openTool(folder, name string) error {
|
||||
var chosen *tool
|
||||
for i := range tools {
|
||||
if tools[i].name == name {
|
||||
chosen = &tools[i]
|
||||
}
|
||||
}
|
||||
if chosen == nil {
|
||||
return fmt.Errorf("no tool called %q", name)
|
||||
}
|
||||
session, ws, err := currentWorkspace()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log, _ := os.Create(filepath.Join(os.TempDir(), "paperclip-harness-tool.log"))
|
||||
|
||||
cmd := exec.Command("tuios", "new-window", chosen.name, "-s", session,
|
||||
"--workspace", ws, "--cwd", folder, "--", "/bin/sh", "-c", chosen.command)
|
||||
cmd.Stdout = log
|
||||
cmd.Stderr = log
|
||||
cmd.SysProcAttr = &syscall.SysProcAttr{Setsid: true}
|
||||
if err := cmd.Start(); err != nil {
|
||||
return fmt.Errorf("cannot open %s: %w", chosen.name, err)
|
||||
}
|
||||
go func() {
|
||||
cmd.Wait()
|
||||
if log != nil {
|
||||
log.Close()
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
// --- the smallest JSON reader that does this one job -------------------------
|
||||
|
||||
type scanner struct {
|
||||
s string
|
||||
pos int
|
||||
}
|
||||
|
||||
func newScanner(s string) *scanner { return &scanner{s: s} }
|
||||
|
||||
// nextObject returns the next {...} block, or "" at the end.
|
||||
func (sc *scanner) nextObject() string {
|
||||
for sc.pos < len(sc.s) && sc.s[sc.pos] != '{' {
|
||||
sc.pos++
|
||||
}
|
||||
if sc.pos >= len(sc.s) {
|
||||
return ""
|
||||
}
|
||||
depth := 0
|
||||
start := sc.pos
|
||||
for sc.pos < len(sc.s) {
|
||||
switch sc.s[sc.pos] {
|
||||
case '{':
|
||||
depth++
|
||||
case '}':
|
||||
depth--
|
||||
if depth == 0 {
|
||||
sc.pos++
|
||||
return sc.s[start:sc.pos]
|
||||
}
|
||||
}
|
||||
sc.pos++
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func contains(s, sub string) bool {
|
||||
for i := 0; i+len(sub) <= len(s); i++ {
|
||||
if s[i:i+len(sub)] == sub {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// fieldNumber reads "name": 12 out of an object.
|
||||
func fieldNumber(obj, name string) string {
|
||||
key := `"` + name + `":`
|
||||
for i := 0; i+len(key) <= len(obj); i++ {
|
||||
if obj[i:i+len(key)] != key {
|
||||
continue
|
||||
}
|
||||
j := i + len(key)
|
||||
for j < len(obj) && (obj[j] == ' ' || obj[j] == '"') {
|
||||
j++
|
||||
}
|
||||
start := j
|
||||
for j < len(obj) && obj[j] >= '0' && obj[j] <= '9' {
|
||||
j++
|
||||
}
|
||||
if _, err := strconv.Atoi(obj[start:j]); err == nil {
|
||||
return obj[start:j]
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
86
tui/work.go
86
tui/work.go
@@ -44,20 +44,22 @@ type workModel struct {
|
||||
|
||||
tab int
|
||||
scroll int
|
||||
tools bool
|
||||
toolAt int
|
||||
readAt time.Time
|
||||
|
||||
showHelp bool
|
||||
width, height int
|
||||
}
|
||||
|
||||
var workTabs = []string{"runs", "change", "facts"}
|
||||
var workTabs = []string{"runs", "change", "facts", "review"}
|
||||
|
||||
func newWorkModel(c *paperclip.Client, folder, issueID string) workModel {
|
||||
return workModel{client: c, folder: folder, issue: issueID, explicit: issueID != ""}
|
||||
}
|
||||
|
||||
func (m workModel) Init() tea.Cmd {
|
||||
return tea.Batch(m.load(), tickEvery(5*time.Second))
|
||||
return tea.Batch(m.load(), tickEvery(5*time.Second), tea.WindowSize())
|
||||
}
|
||||
|
||||
func (m workModel) load() tea.Cmd {
|
||||
@@ -120,14 +122,38 @@ func (m workModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
|
||||
return m, nil
|
||||
|
||||
case tickMsg:
|
||||
return m, tea.Batch(m.load(), tickEvery(5*time.Second))
|
||||
return m, tea.Batch(m.load(), tickEvery(5*time.Second), tea.WindowSize())
|
||||
|
||||
case tea.KeyMsg:
|
||||
if m.tools {
|
||||
switch msg.String() {
|
||||
case "esc", "q", "t":
|
||||
m.tools = false
|
||||
return m, nil
|
||||
case "up", "k":
|
||||
m.toolAt = max(0, m.toolAt-1)
|
||||
return m, nil
|
||||
case "down", "j":
|
||||
m.toolAt = min(len(tools)-1, m.toolAt+1)
|
||||
return m, nil
|
||||
case "enter":
|
||||
t := tools[m.toolAt]
|
||||
m.tools = false
|
||||
if err := openTool(m.folder, t.name); err != nil {
|
||||
m.err = err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
if m.showHelp {
|
||||
m.showHelp = false
|
||||
return m, nil
|
||||
}
|
||||
switch msg.String() {
|
||||
case "t":
|
||||
m.tools = true
|
||||
return m, nil
|
||||
case "?":
|
||||
m.showHelp = true
|
||||
return m, nil
|
||||
@@ -225,10 +251,24 @@ func (m workModel) View() string {
|
||||
body = m.runsLines(m.width - 4)
|
||||
case 1:
|
||||
body = m.diffLines(m.width - 4)
|
||||
case 3:
|
||||
body = m.reviewLines(m.width - 4)
|
||||
default:
|
||||
body = m.factsLines(m.width - 4)
|
||||
}
|
||||
|
||||
if m.tools {
|
||||
entries := make([][2]string, 0, len(tools))
|
||||
for i, t := range tools {
|
||||
mark := " "
|
||||
if i == m.toolAt {
|
||||
mark = "▸ "
|
||||
}
|
||||
entries = append(entries, [2]string{mark + t.name, t.about})
|
||||
}
|
||||
return helpOverlay("open a tool pane here", entries, m.width, m.height)
|
||||
}
|
||||
|
||||
p := panel{
|
||||
title: "the work", width: m.width, height: m.height - 2,
|
||||
tabs: workTabs, active: m.tab, focused: true,
|
||||
@@ -249,6 +289,7 @@ func (m workModel) View() string {
|
||||
footer := hintLine([]string{
|
||||
keyHint("[ ]", "switch tab"),
|
||||
keyHint("↑↓ or j k", "scroll"),
|
||||
keyHint("t", "open a tool pane"),
|
||||
keyHint("r", "read again"),
|
||||
keyHint("R", "rebuild every pane"),
|
||||
keyHint("q", "leave"),
|
||||
@@ -355,6 +396,45 @@ func (m workModel) diffLines(width int) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// reviewLines shows the verdicts already recorded on the task. A review is
|
||||
// written as a comment, so the record lives with the work and survives us.
|
||||
func (m workModel) reviewLines(width int) []string {
|
||||
out := []string{"", dimStyle().Render(" verdicts recorded on this task")}
|
||||
if m.task.Identifier == "" {
|
||||
return append(out, mutedStyle2().Render(" no task chosen"))
|
||||
}
|
||||
cs, err := m.client.Comments(m.task.ID)
|
||||
if err != nil {
|
||||
return append(out, lipgloss.NewStyle().Foreground(lipgloss.Color(active.Error)).Render(" "+err.Error()))
|
||||
}
|
||||
found := 0
|
||||
for i := len(cs) - 1; i >= 0 && found < 3; i-- {
|
||||
body := cs[i].Body
|
||||
if !strings.HasPrefix(body, "## Review") &&
|
||||
!strings.HasPrefix(body, "## Merge refused") &&
|
||||
!strings.HasPrefix(body, "## Merged") &&
|
||||
!strings.HasPrefix(body, "## Merge undone") {
|
||||
continue
|
||||
}
|
||||
found++
|
||||
blocking := strings.Contains(body, "critical") || strings.Contains(body, "**high/")
|
||||
colour := active.Success
|
||||
if strings.HasPrefix(body, "## Merge refused") || blocking {
|
||||
colour = active.Error
|
||||
}
|
||||
for _, ln := range wrap(strings.ReplaceAll(body, "\n", " · "), width-2) {
|
||||
out = append(out, " "+lipgloss.NewStyle().Foreground(lipgloss.Color(colour)).Render(ln))
|
||||
}
|
||||
out = append(out, "")
|
||||
}
|
||||
if found == 0 {
|
||||
out = append(out, mutedStyle2().Render(" no review recorded for this task yet"))
|
||||
out = append(out, "")
|
||||
out = append(out, dimStyle().Render(" run one with: bin/review "+m.task.Identifier+" --post"))
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func (m workModel) factsLines(width int) []string {
|
||||
var out []string
|
||||
out = append(out, "")
|
||||
|
||||
Reference in New Issue
Block a user