beads-ui 0.2.0 → 0.3.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.
Files changed (58) hide show
  1. package/CHANGES.md +14 -0
  2. package/README.md +4 -4
  3. package/app/data/list-selectors.js +103 -0
  4. package/app/data/providers.js +7 -138
  5. package/app/data/sort.js +47 -0
  6. package/app/data/subscription-issue-store.js +161 -0
  7. package/app/data/subscription-issue-stores.js +128 -0
  8. package/app/data/subscriptions-store.js +227 -0
  9. package/app/main.js +346 -66
  10. package/app/protocol.js +23 -17
  11. package/app/protocol.md +18 -15
  12. package/app/router.js +3 -0
  13. package/app/state.js +2 -0
  14. package/app/styles.css +222 -197
  15. package/app/utils/issue-id-renderer.js +2 -1
  16. package/app/utils/issue-id.js +1 -0
  17. package/app/utils/issue-type.js +2 -0
  18. package/app/utils/issue-url.js +1 -0
  19. package/app/utils/markdown.js +13 -198
  20. package/app/utils/priority-badge.js +1 -2
  21. package/app/utils/status-badge.js +1 -1
  22. package/app/utils/status.js +2 -0
  23. package/app/utils/toast.js +1 -1
  24. package/app/utils/type-badge.js +1 -3
  25. package/app/views/board.js +172 -148
  26. package/app/views/detail.js +79 -66
  27. package/app/views/epics.js +127 -74
  28. package/app/views/issue-dialog.js +9 -15
  29. package/app/views/issue-row.js +2 -3
  30. package/app/views/list.js +105 -104
  31. package/app/views/nav.js +1 -0
  32. package/app/views/new-issue-dialog.js +30 -34
  33. package/app/ws.js +10 -10
  34. package/bin/bdui.js +1 -1
  35. package/docs/adr/001-push-only-lists.md +134 -0
  36. package/docs/adr/002-per-subscription-stores-and-full-issue-push.md +200 -0
  37. package/docs/architecture.md +34 -84
  38. package/docs/data-exchange-subscription-plan.md +198 -0
  39. package/docs/db-watching.md +2 -1
  40. package/docs/migration-v2.md +54 -0
  41. package/docs/protocol/issues-push-v2.md +179 -0
  42. package/docs/subscription-issue-store.md +112 -0
  43. package/package.json +5 -4
  44. package/server/app.js +2 -0
  45. package/server/bd.js +4 -2
  46. package/server/cli/commands.js +5 -2
  47. package/server/cli/daemon.js +19 -5
  48. package/server/cli/index.js +2 -2
  49. package/server/cli/open.js +3 -0
  50. package/server/cli/usage.js +2 -1
  51. package/server/config.js +13 -6
  52. package/server/db.js +3 -1
  53. package/server/index.js +9 -5
  54. package/server/list-adapters.js +224 -0
  55. package/server/subscriptions.js +289 -0
  56. package/server/validators.js +113 -0
  57. package/server/watcher.js +8 -8
  58. package/server/ws.js +457 -229
package/app/protocol.md CHANGED
@@ -1,4 +1,12 @@
1
- # beads-ui WebSocket Protocol (v1.0.0)
1
+ # beads-ui WebSocket Protocol (v2.0.0)
2
+
3
+ Note (2025-10-26)
4
+
5
+ - The server no longer implements legacy read RPCs `list-issues` and
6
+ `epic-status`. Clients must use the push-only protocol described in
7
+ `docs/protocol/issues-push-v2.md` (subscribe-list with per-subscription events
8
+ snapshot/upsert/delete). The shapes below are retained for historical
9
+ reference of v1.
2
10
 
3
11
  This document defines the JSON messages exchanged between the browser client and
4
12
  the local server.
@@ -13,13 +21,13 @@ the local server.
13
21
  - ReplyEnvelope:
14
22
  `{ id: string, ok: boolean, type: string, payload?: any, error?: { code: string, message: string, details?: any } }`
15
23
 
16
- Server may send unsolicited events (e.g., `issues-changed`) using the
17
- ReplyEnvelope shape with `ok: true` and a generated `id`.
24
+ Server may send unsolicited events (e.g., subscription
25
+ `snapshot`/`upsert`/`delete`) using the ReplyEnvelope shape with `ok: true` and
26
+ a generated `id`.
18
27
 
19
28
  ## Message Types
20
29
 
21
- - `list-issues` payload: `{ filters?: { status?: string, priority?: number } }`
22
- - `show-issue` payload: `{ id: string }`
30
+ - Removed in v2: `list-issues` (use subscriptions + push stores)
23
31
  - `update-status` payload:
24
32
  `{ id: string, status: 'open'|'in_progress'|'closed' }`
25
33
  - `edit-text` payload:
@@ -28,9 +36,9 @@ ReplyEnvelope shape with `ok: true` and a generated `id`.
28
36
  - `create-issue` payload:
29
37
  `{ title: string, type?: 'bug'|'feature'|'task'|'epic'|'chore', priority?: 0|1|2|3|4, description?: string }`
30
38
  - `list-ready` payload: `{}`
31
- - `subscribe-updates` payload: `{}` (server responds with `ok` and begins
32
- emitting events)
33
- - `issues-changed` payload: `{ ts: number, hint?: { ids?: string[] } }`
39
+ - Removed in v2: `subscribe-updates` and the `issues-changed` event. All list
40
+ and detail updates flow via per-subscription push envelopes
41
+ (`snapshot`/`upsert`/`delete`).
34
42
  - `dep-add` payload: `{ a: string, b: string, view_id?: string }` where `a`
35
43
  depends on `b` (i.e., `a` is blocked by `b`). Reply payload is the updated
36
44
  issue for `view_id` (or `a` when omitted).
@@ -40,8 +48,8 @@ ReplyEnvelope shape with `ok: true` and a generated `id`.
40
48
 
41
49
  ## Mapping to `bd` CLI
42
50
 
43
- - `list-issues` → `bd list --json [--status <s>] [--priority <n>]`
44
- - `show-issue` → `bd show <id> --json`
51
+ - Removed in v2: `list-issues` → use subscriptions and push
52
+ (`docs/protocol/issues-push-v2.md`)
45
53
  - `update-status` → `bd update <id> --status <status>`
46
54
  - `edit-text` → `bd update <id> --title <t>` or `--description <d>` or
47
55
  `--acceptance-criteria <a>` or `--notes <n>` or `--design <z>`
@@ -56,8 +64,3 @@ Errors follow the shape `{ code, message, details? }`. Common codes:
56
64
  - `bad_request` – malformed payload or unknown type
57
65
  - `not_found` – entity not found (e.g., issue id)
58
66
  - `bd_error` – underlying `bd` command failed
59
-
60
- ## Versioning
61
-
62
- Breaking changes to shapes or semantics increment `PROTOCOL_VERSION` in
63
- `app/protocol.js`.
package/app/router.js CHANGED
@@ -8,6 +8,7 @@ import { issueHashFor } from './utils/issue-url.js';
8
8
  * Parse an application hash and extract the selected issue id.
9
9
  * Supports canonical form "#/(issues|epics|board)?issue=<id>" and legacy
10
10
  * "#/issue/<id>" which we will rewrite to the canonical form.
11
+ *
11
12
  * @param {string} hash
12
13
  * @returns {string | null}
13
14
  */
@@ -31,6 +32,7 @@ export function parseHash(hash) {
31
32
 
32
33
  /**
33
34
  * Parse the current view from hash.
35
+ *
34
36
  * @param {string} hash
35
37
  * @returns {'issues'|'epics'|'board'}
36
38
  */
@@ -95,6 +97,7 @@ export function createHashRouter(store) {
95
97
  },
96
98
  /**
97
99
  * Navigate to a top-level view.
100
+ *
98
101
  * @param {'issues'|'epics'|'board'} view
99
102
  */
100
103
  /**
package/app/state.js CHANGED
@@ -28,6 +28,7 @@
28
28
 
29
29
  /**
30
30
  * Create a simple store for application state.
31
+ *
31
32
  * @param {Partial<AppState>} [initial]
32
33
  * @returns {{ getState: () => AppState, setState: (patch: { selected_id?: string | null, filters?: Partial<Filters> }) => void, subscribe: (fn: (s: AppState) => void) => () => void }}
33
34
  */
@@ -71,6 +72,7 @@ export function createStore(initial = {}) {
71
72
  },
72
73
  /**
73
74
  * Update state. Nested filters can be partial.
75
+ *
74
76
  * @param {{ selected_id?: string | null, filters?: Partial<Filters>, board?: Partial<BoardState> }} patch
75
77
  */
76
78
  setState(patch) {