@leftoff/cli 0.8.9 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,31 @@
2
2
 
3
3
  What changed in Leftoff (called Checkpoints until 0.4.5), newest first. The board's **What's new** page and `leftoff changelog` both read this file.
4
4
 
5
+ ## [0.9.1] - 2026-10-13
6
+
7
+ ### Fixed
8
+ - 0.9.0 added a status line even when yours came from a plugin, hiding it. Upgrades no longer add one when you don't have one in settings, and this upgrade gives yours back.
9
+ - When a session's folder is gone, your own status line still shows, with **leftoff ↗** after it.
10
+
11
+ ## [0.9.0] - 2026-10-13
12
+
13
+ ### Added
14
+ - **Projects**: name a group of repos (an API plus the app that uses it). The board, the PRs page and the digest filter and group by project, each card shows its project, and every Mac sees the same projects. Add a repo from a card's **⋯**, or `leftoff project new|add|rm|rename|delete`.
15
+ - **⌘K palette** (Ctrl K, or the search button on a phone): sessions open and closed, PRs, projects, lists, to-dos and files, plus actions like Go to PRs, Digest, New project and Checkpoint now. Arrows and Enter, recent items when empty.
16
+ - **`/cp-name --auto`** names the session from its latest messages, through your summarizer. The rename on the board has a **↻** that does the same.
17
+
18
+ ### Changed
19
+ - PRs page: Merged and Closed fold to one row each (tap to open), and the counts only count open PRs.
20
+ - PRs show at most two linked sessions, then "+N more", and scripted `claude -p` runs never link to a PR.
21
+ - PR descriptions render as markdown, with the file viewer's styles.
22
+ - Demo data uses neutral names (acme).
23
+
24
+ ### Fixed
25
+ - **Crossed streams**: two sessions started in the same folder, each working in its own worktree, no longer swap branches. A session's branch came from the main checkout, which could be on the other session's branch, and that pulled in the other session's PR and steered its AI checkpoints. Now each session reads its branch from its own worktree. Cards already affected fix themselves, and checkpoints written with the wrong branch are folded away, not deleted.
26
+ - A summarizer reply that repeats its instructions back is no longer saved as a checkpoint.
27
+ - The board's search box keeps its focus and what you typed when a live update repaints the board.
28
+ - Upgrading now adds **leftoff ↗** to your status line once, after your own line if you have one, unless you ran `leftoff uninstall`. `leftoff doctor` warns when a project's own `.claude/settings.json` sets a status line, which hides yours there.
29
+
5
30
  ## [0.8.9] - 2026-10-13
6
31
 
7
32
  ### Added
@@ -336,7 +361,7 @@ What changed in Leftoff (called Checkpoints until 0.4.5), newest first. The boar
336
361
  Before a device is accepted, Syncthing passes on only what's in its Hello: ID, name and version. A folder label can't carry the proof, because folder offers only travel after both sides have added each other. The details are in [docs/SECURITY.md](docs/SECURITY.md#pairing-a-second-mac).
337
362
 
338
363
  ### Tests
339
- - The fake osascript now decodes its arguments the way osascript does without a UTF-8 locale. Against 0.5.4 the restore e2e reproduces the mojibake (`café`); with 0.5.5 a title like “colorGenie · réglages ✨” and a folder like `larry-db café` arrive intact. New unit and e2e cases cover titles without the marker, Go matching by name (and by name and folder), when the daemon asks for the marker, and the old default format.
364
+ - The fake osascript now decodes its arguments the way osascript does without a UTF-8 locale. Against 0.5.4 the restore e2e reproduces the mojibake (`café`); with 0.5.5 a title like “colorGenie · réglages ✨” and a folder like `acme-db café` arrive intact. New unit and e2e cases cover titles without the marker, Go matching by name (and by name and folder), when the daemon asks for the marker, and the old default format.
340
365
  - The fake Syncthing now behaves like v2.1.6 where it matters: it dials a new or unpaused device before the API call returns (so a later rename misses the first Hello), lists a refused connection as connected for a moment, reports `remoteState` only from what the peer really shares, and supports pause/resume and dismissing pending devices. With `FAKE_ST_PENDING_NAME=first` it keeps the name from the first Hello until the record is dismissed.
341
366
  - New `test/syncthing-pairing-e2e.mjs` replays the real failure. Against 0.5.4 it hangs exactly as on real Macs ("Connected to studio. Syncing…", then "Waiting for the first files…" forever). With 0.5.5 it passes in both pending-name modes: laptop's first Hello carries the proof, the stale record is cleared once, laptop is accepted by proof and syncs; a Mac with an unverifiable proof is never accepted, gets the stuck steps, is accepted by the explicit click, and a dropped connection mid-sync is reported honestly.
342
367
 
@@ -1,12 +1,12 @@
1
- {"type": "summary", "summary": "Larry sync retry", "leafUuid": "x"}
2
- {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/larry", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u2", "timestamp": "2026-10-09T13:02:00.000Z", "type": "user", "message": {"role": "user", "content": "The Larry sync worker retries forever when the API is down. Add exponential backoff with jitter and cap it at 5 attempts."}}
3
- {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/larry", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u3", "timestamp": "2026-10-09T13:03:00.000Z", "type": "assistant", "message": {"id": "msg_1", "role": "assistant", "model": "claude-opus-5", "content": [{"type": "text", "text": "Reading the worker and the retry helper first."}]}}
4
- {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/larry", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u4", "timestamp": "2026-10-09T13:04:00.000Z", "type": "assistant", "message": {"id": "msg_1", "role": "assistant", "model": "claude-opus-5", "content": [{"type": "tool_use", "id": "tu1", "name": "Read", "input": {"file_path": "/Users/yourname/code/larry/src/sync/worker.ts"}}]}}
5
- {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/larry", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u5", "timestamp": "2026-10-09T13:05:00.000Z", "type": "assistant", "message": {"id": "msg_1", "role": "assistant", "model": "claude-opus-5", "content": [{"type": "tool_use", "id": "tu2", "name": "Read", "input": {"file_path": "/Users/yourname/code/larry/src/sync/retry.ts"}}]}}
6
- {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/larry", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u6", "timestamp": "2026-10-09T13:06:00.000Z", "type": "user", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "tu1", "content": "export async function syncWorker() {...}"}, {"type": "tool_result", "tool_use_id": "tu2", "content": "export function retry() {...}"}]}}
7
- {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/larry", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u7", "timestamp": "2026-10-09T13:07:00.000Z", "type": "assistant", "message": {"id": "msg_2", "role": "assistant", "model": "claude-opus-5", "content": [{"type": "text", "text": "Rewriting retry() with exponential backoff and full jitter, capped at 5 attempts."}, {"type": "tool_use", "id": "tu3", "name": "Edit", "input": {"file_path": "/Users/yourname/code/larry/src/sync/retry.ts", "old_string": "a", "new_string": "b"}}, {"type": "tool_use", "id": "tu4", "name": "Edit", "input": {"file_path": "/Users/yourname/code/larry/src/sync/worker.ts", "old_string": "a", "new_string": "b"}}]}}
8
- {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/larry", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u8", "timestamp": "2026-10-09T13:08:00.000Z", "type": "user", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "tu3", "content": "ok"}, {"type": "tool_result", "tool_use_id": "tu4", "content": "ok"}]}}
9
- {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/larry", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u9", "timestamp": "2026-10-09T13:09:00.000Z", "type": "assistant", "message": {"id": "msg_3", "role": "assistant", "model": "claude-opus-5", "content": [{"type": "tool_use", "id": "tu5", "name": "Bash", "input": {"command": "npm test -- sync"}}]}}
10
- {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/larry", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u10", "timestamp": "2026-10-09T13:10:00.000Z", "type": "user", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "tu5", "content": "PASS test/sync.unit.test.ts\nFAIL test/sync.int.test.ts\n staging request timed out after 30000 ms", "is_error": true}]}}
11
- {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/larry", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u11", "timestamp": "2026-10-09T13:11:00.000Z", "type": "user", "message": {"role": "user", "content": "<local-command-stdout>Set model to opus</local-command-stdout>"}}
12
- {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/larry", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u12", "timestamp": "2026-10-09T13:12:00.000Z", "type": "assistant", "message": {"id": "msg_4", "role": "assistant", "model": "claude-opus-5", "content": [{"type": "text", "text": "Unit tests pass with the new backoff. The integration test against staging still times out after 30s because the staging endpoint is slow. Do you want me to bump the integration timeout to 90s, or mock the slow endpoint?"}]}}
1
+ {"type": "summary", "summary": "Acme sync retry", "leafUuid": "x"}
2
+ {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/acme", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u2", "timestamp": "2026-10-09T13:02:00.000Z", "type": "user", "message": {"role": "user", "content": "The Acme sync worker retries forever when the API is down. Add exponential backoff with jitter and cap it at 5 attempts."}}
3
+ {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/acme", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u3", "timestamp": "2026-10-09T13:03:00.000Z", "type": "assistant", "message": {"id": "msg_1", "role": "assistant", "model": "claude-opus-5", "content": [{"type": "text", "text": "Reading the worker and the retry helper first."}]}}
4
+ {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/acme", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u4", "timestamp": "2026-10-09T13:04:00.000Z", "type": "assistant", "message": {"id": "msg_1", "role": "assistant", "model": "claude-opus-5", "content": [{"type": "tool_use", "id": "tu1", "name": "Read", "input": {"file_path": "/Users/yourname/code/acme/src/sync/worker.ts"}}]}}
5
+ {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/acme", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u5", "timestamp": "2026-10-09T13:05:00.000Z", "type": "assistant", "message": {"id": "msg_1", "role": "assistant", "model": "claude-opus-5", "content": [{"type": "tool_use", "id": "tu2", "name": "Read", "input": {"file_path": "/Users/yourname/code/acme/src/sync/retry.ts"}}]}}
6
+ {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/acme", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u6", "timestamp": "2026-10-09T13:06:00.000Z", "type": "user", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "tu1", "content": "export async function syncWorker() {...}"}, {"type": "tool_result", "tool_use_id": "tu2", "content": "export function retry() {...}"}]}}
7
+ {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/acme", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u7", "timestamp": "2026-10-09T13:07:00.000Z", "type": "assistant", "message": {"id": "msg_2", "role": "assistant", "model": "claude-opus-5", "content": [{"type": "text", "text": "Rewriting retry() with exponential backoff and full jitter, capped at 5 attempts."}, {"type": "tool_use", "id": "tu3", "name": "Edit", "input": {"file_path": "/Users/yourname/code/acme/src/sync/retry.ts", "old_string": "a", "new_string": "b"}}, {"type": "tool_use", "id": "tu4", "name": "Edit", "input": {"file_path": "/Users/yourname/code/acme/src/sync/worker.ts", "old_string": "a", "new_string": "b"}}]}}
8
+ {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/acme", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u8", "timestamp": "2026-10-09T13:08:00.000Z", "type": "user", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "tu3", "content": "ok"}, {"type": "tool_result", "tool_use_id": "tu4", "content": "ok"}]}}
9
+ {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/acme", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u9", "timestamp": "2026-10-09T13:09:00.000Z", "type": "assistant", "message": {"id": "msg_3", "role": "assistant", "model": "claude-opus-5", "content": [{"type": "tool_use", "id": "tu5", "name": "Bash", "input": {"command": "npm test -- sync"}}]}}
10
+ {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/acme", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u10", "timestamp": "2026-10-09T13:10:00.000Z", "type": "user", "message": {"role": "user", "content": [{"type": "tool_result", "tool_use_id": "tu5", "content": "PASS test/sync.unit.test.ts\nFAIL test/sync.int.test.ts\n staging request timed out after 30000 ms", "is_error": true}]}}
11
+ {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/acme", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u11", "timestamp": "2026-10-09T13:11:00.000Z", "type": "user", "message": {"role": "user", "content": "<local-command-stdout>Set model to opus</local-command-stdout>"}}
12
+ {"parentUuid": null, "isSidechain": false, "userType": "external", "cwd": "/Users/yourname/code/acme", "sessionId": "00893aaf-19fa-41d2-8238-13269b9b3ca0", "version": "2.1.290", "gitBranch": "fix/sync-retry", "uuid": "u12", "timestamp": "2026-10-09T13:12:00.000Z", "type": "assistant", "message": {"id": "msg_4", "role": "assistant", "model": "claude-opus-5", "content": [{"type": "text", "text": "Unit tests pass with the new backoff. The integration test against staging still times out after 30s because the staging endpoint is slow. Do you want me to bump the integration timeout to 90s, or mock the slow endpoint?"}]}}