@unifedev/thread-pages 0.3.2 → 1.0.3

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 (90) hide show
  1. package/README.md +77 -129
  2. package/dist/server.js +11426 -11802
  3. package/dist/server.meta.json +2 -2
  4. package/package.json +25 -18
  5. package/server.ts +3 -2175
  6. package/src/agent/cli.ts +193 -0
  7. package/src/agent/guide.ts +355 -0
  8. package/src/agent/instruction.ts +59 -0
  9. package/src/agent/seed/seed.ts +69 -0
  10. package/{theme.ts → src/agent/seed/theme-css.ts} +4 -11
  11. package/src/agent/starter-hub.ts +217 -0
  12. package/src/bb/activity.ts +59 -0
  13. package/src/bb/bb-host.ts +280 -0
  14. package/src/bb/public-origin.ts +45 -0
  15. package/src/config/settings.ts +82 -0
  16. package/src/domain/capabilities/contract.ts +48 -0
  17. package/src/domain/capabilities/index.ts +10 -0
  18. package/src/domain/capabilities/protocol.ts +112 -0
  19. package/src/domain/capabilities/registry.ts +48 -0
  20. package/src/domain/capabilities/schema.ts +198 -0
  21. package/src/domain/capabilities/specs.ts +479 -0
  22. package/src/domain/eligibility.ts +43 -0
  23. package/src/domain/errors.ts +116 -0
  24. package/src/domain/html/document.ts +109 -0
  25. package/src/domain/html/escape.ts +16 -0
  26. package/src/domain/ids.ts +37 -0
  27. package/src/domain/json/canonical.ts +19 -0
  28. package/src/domain/json/strict-json.ts +139 -0
  29. package/src/domain/limits.ts +88 -0
  30. package/src/domain/rate-limit.ts +64 -0
  31. package/src/domain/revision.ts +27 -0
  32. package/src/domain/submissions/idempotency.ts +59 -0
  33. package/src/domain/submissions/message.ts +42 -0
  34. package/src/domain/submissions/parse.ts +105 -0
  35. package/src/domain/tokens/action-token.ts +52 -0
  36. package/src/domain/tokens/confirmation.ts +99 -0
  37. package/src/domain/tokens/mac.ts +50 -0
  38. package/src/generated/kernel-runtime.ts +3 -0
  39. package/src/generated/shell-runtime.ts +3 -0
  40. package/src/host/contract.ts +65 -0
  41. package/src/host/types.ts +89 -0
  42. package/src/pages/layout.ts +65 -0
  43. package/src/pages/page-store.ts +136 -0
  44. package/src/pages/site.ts +36 -0
  45. package/src/plugin.ts +71 -0
  46. package/src/runtime/kernel/anchors.ts +45 -0
  47. package/src/runtime/kernel/api.ts +15 -0
  48. package/src/runtime/kernel/bridge-client.ts +148 -0
  49. package/src/runtime/kernel/dirty.ts +51 -0
  50. package/src/runtime/kernel/forms.ts +114 -0
  51. package/src/runtime/kernel/install.ts +156 -0
  52. package/src/runtime/kernel/labels.ts +98 -0
  53. package/src/runtime/kernel/main.ts +6 -0
  54. package/src/runtime/kernel/readonly.ts +75 -0
  55. package/src/runtime/shared/protocol.ts +125 -0
  56. package/src/runtime/shell/confirm.ts +70 -0
  57. package/src/runtime/shell/install.ts +79 -0
  58. package/src/runtime/shell/main.ts +12 -0
  59. package/src/runtime/shell/navigate.ts +64 -0
  60. package/src/runtime/shell/poll.ts +125 -0
  61. package/src/runtime/shell/relay.ts +185 -0
  62. package/src/serving/action-request.ts +32 -0
  63. package/src/serving/bridge/dispatcher.ts +112 -0
  64. package/src/serving/bridge/handler.ts +37 -0
  65. package/src/serving/bridge/handlers/index.ts +26 -0
  66. package/src/serving/bridge/handlers/navigation.ts +43 -0
  67. package/src/serving/bridge/handlers/reads.ts +186 -0
  68. package/src/serving/bridge/handlers/writes.ts +175 -0
  69. package/src/serving/bridge/selection-store.ts +58 -0
  70. package/src/serving/bridge-route.ts +23 -0
  71. package/src/serving/context.ts +34 -0
  72. package/src/serving/document-route.ts +37 -0
  73. package/src/serving/home-route.ts +23 -0
  74. package/src/serving/responses.ts +81 -0
  75. package/src/serving/routes.ts +26 -0
  76. package/src/serving/session-access.ts +22 -0
  77. package/src/serving/shell-html.ts +77 -0
  78. package/src/serving/shell-route.ts +51 -0
  79. package/src/serving/signing-key.ts +25 -0
  80. package/src/serving/submit-route.ts +47 -0
  81. package/src/serving/upload-route.ts +46 -0
  82. package/tsconfig.json +10 -6
  83. package/ARCHITECTURE.md +0 -230
  84. package/PLUGIN_OVERVIEW.md +0 -83
  85. package/authoring.ts +0 -368
  86. package/bridge.ts +0 -1721
  87. package/docs/MODEL.md +0 -211
  88. package/docs/ROADMAP.md +0 -96
  89. package/home.ts +0 -419
  90. package/page.ts +0 -782
package/docs/MODEL.md DELETED
@@ -1,211 +0,0 @@
1
- # How Thread Pages works
2
-
3
- This answers four questions: what instructions exist and where they live, where
4
- the HTML lives, where the template lives, and how you reach a page from a phone.
5
-
6
- ## The one-paragraph version
7
-
8
- Each bb thread gets one HTML file in its own thread storage. The agent edits that
9
- file directly; saving it *is* publishing. A plugin route serves the file inside a
10
- sandboxed iframe on the bb origin you are already logged into, so the same URL
11
- works on your laptop and your phone with no extra port, tunnel, or password.
12
- Forms in the page post back to the thread as your next message.
13
-
14
- ## Every instruction, and where it lives
15
-
16
- There are three, and only the first is loaded into every session.
17
-
18
- | # | What | Where it is stored | Loaded when |
19
- | --- | --- | --- | --- |
20
- | 1 | **The contract** — the page is the conversation, how to ask well, what belongs on a page | `authoring.ts` → `DEFAULT_AGENT_INSTRUCTION`, overridable in the `agentInstructionText` setting (stored in bb's settings DB) | Injected into every eligible root thread, if `agentInstructions` is on |
21
- | 2 | **The seed comment** — the three class names, the theme attributes, the escape-hatch rule | Inside each page's own HTML, put there by the seed | Read by the agent when it opens the file |
22
- | 3 | **The authoring guide** — charts, branching, swipe decks, files, assets, the bridge | `authoring.ts` → `AUTHORING_GUIDE`, printed by `bb thread-page guide` | Only when an agent runs that command |
23
-
24
- The split is deliberate. #1 is paid for by every session, so it holds only what
25
- changes behaviour. #2 costs nothing because the agent is already reading the
26
- file. #3 is unbounded and free to the sessions that never need it.
27
-
28
- There is **no** skill, no agent tool, and no `CLAUDE.md` entry. Check what is
29
- live with:
30
-
31
- ```sh
32
- bb plugin config thread-pages # all three settings and their values
33
- bb thread-page guide # print #3
34
- bb instructions get # bb-wide instructions (empty; not us)
35
- ```
36
-
37
- To change the contract for all future sessions, edit `agentInstructionText`. To
38
- change what new pages start from, edit `pageSeedHtml`. Neither touches a page
39
- that already exists.
40
-
41
- ## Where the HTML lives
42
-
43
- ```
44
- ~/.bb/thread-storage/<threadId>/
45
- thread-page.html the page — one file, ~28 KB seeded
46
- thread-page-assets/ optional: images, css, fonts, json you show
47
- thread-page-uploads/ files the user attached, named by the plugin
48
- ```
49
-
50
- That is the whole storage model. The page is a normal file: read it, diff it,
51
- edit it with any tool. There is no database of pages, no revision history, and
52
- no separate publish step.
53
-
54
- The plugin also keeps two small things in bb's existing `plugin_kv` table:
55
-
56
- - `page-signing-key:v2` — 32 bytes, so open browser sessions survive a reload;
57
- - `cache:<threadId>` — a best-effort last-good copy, so a page still opens
58
- read-only when its source machine is offline.
59
-
60
- No plugin-owned SQLite database, no background service.
61
-
62
- ## Where the template lives
63
-
64
- There is no template file on disk. The seed is a string in the plugin:
65
-
66
- - `theme.ts` → `THEME_CSS` — the design system: five worlds, one resolver.
67
- - `authoring.ts` → `DEFAULT_PAGE_SEED` — the document that wraps it.
68
-
69
- `bb thread-page init` writes that seed **only when the file does not exist**. It
70
- never overwrites. The consequence worth understanding: **each page carries its
71
- own copy of the stylesheet.** The agent can therefore change any rule for one
72
- page, and a plugin update can never restyle a page you have already read. The
73
- cost is that improving the design system only affects pages created afterwards.
74
-
75
- Five worlds are available; pick one with `data-theme` on `<html>`:
76
- `paper`, `terminal`, `atrium`, `volume` (default), `bloom`. Also
77
- `data-mode` (`system`/`light`/`dark`) and `data-atmos` (`on`/`off`).
78
-
79
- ## How a turn flows
80
-
81
- 1. Agent runs `bb thread-page init` → path, link, and `NEW`/`EXISTING`/`SKIP`.
82
- 2. Agent edits `thread-page.html`.
83
- 3. Your open tab notices the changed ETag and reloads itself.
84
- 4. You answer a form. The page posts to `/submit`.
85
- 5. The plugin turns the answers into a message and sends it to the thread.
86
- 6. It arrives as the agent's next turn.
87
-
88
- `SKIP` means the thread is a helper — a child, a fork, or a hidden worker. Only
89
- threads you started get a page, because those are the ones you talk to.
90
-
91
- ## Reaching it from your phone
92
-
93
- **Nothing to expose.** Thread Pages has no server of its own — its routes are
94
- part of the bb server:
95
-
96
- ```
97
- https://<your-handle>.getbb.app/api/v1/plugins/thread-pages/http/page?threadId=<id>
98
- ```
99
-
100
- Whatever origin reaches bb reaches your pages, behind the **same getbb.app
101
- login**, with no second port and no separate share. Verified: an unauthenticated
102
- request to that URL returns the getbb.app sign-in wall and leaks no page content.
103
-
104
- `bb thread-page init` now prints that absolute URL when this bb is connected, so
105
- the link an agent hands you is already the one you can open on a phone. When bb
106
- is local-only it prints a relative path instead, which resolves against whatever
107
- you are browsing from.
108
-
109
- If you are not paired: `bb connect` once, from the dashboard. After that every
110
- page is remote automatically — there is no per-page or per-port step, and
111
- nothing for a new user to configure.
112
-
113
- For a private alternative, point Tailscale Serve at the whole bb loopback origin.
114
- Never Funnel it and never wildcard-bind bb.
115
-
116
- ## The security model
117
-
118
- The page is written by an agent, so it is treated as untrusted code.
119
-
120
- **Inside the iframe** (`sandbox="allow-scripts allow-forms"`, opaque origin):
121
- your page's HTML, CSS and JavaScript. It has no bb cookie, no mutation token, no
122
- parent DOM, no `localStorage`, no raw bb API, no CLI, no arbitrary file access,
123
- and CSP blocks ordinary `fetch` and subresources.
124
-
125
- **Outside the iframe**, plugin-authored code on the bb origin holds the action
126
- token, performs same-origin calls, and renders confirmations.
127
-
128
- **The bridge.** `window.threadPage.invoke(method, params)` reaches a fixed list
129
- of named capabilities, each with its own validator, size limit, and effect class.
130
- There is no generic "call bb" escape.
131
-
132
- Anything that mutates state outside this thread requires a confirmation the page
133
- cannot fake: the server answers once with a signed challenge carrying **its own**
134
- summary, the trusted shell shows that summary in a dialog, and the server
135
- re-verifies the signature before acting. The challenge is bound to one request
136
- id, method, parameter fingerprint, page revision and thread, and expires in two
137
- minutes — so it cannot be forged, replayed, or reused to approve different
138
- parameters.
139
-
140
- All capabilities are enabled except voice: `context.get`, `thread.activity`,
141
- `thread.reply`, `threads.snapshot`, `threads.continue`, `threads.spawn`,
142
- `threads.archive`, `threads.stop`, `threads.openPage`, `threads.openBb`,
143
- `navigation.openExternal`, `projects.list`, `projects.browse`,
144
- `projects.create`, `providers.list`, `storage.get`, `storage.set`.
145
- `voice.captureAndTranscribe` has a contract but no handler, by your decision.
146
-
147
- `projects.browse` opens the host's native folder picker and returns an **opaque,
148
- single-use token** plus a display string — never a filesystem path the page could
149
- reuse or leak. `projects.create` redeems that token.
150
-
151
- **The honest limitation.** Page JavaScript can navigate its own frame and put
152
- data in that URL. Browsers cannot prevent this while still allowing page scripts.
153
- It grants no bb authority, but a page is code you are choosing to run.
154
-
155
- ## The home page, and the Sessions link
156
-
157
- One thread's page is designated home:
158
-
159
- ```sh
160
- bb thread-page home # in the thread that should own it
161
- bb thread-page home --clear # remove the link everywhere
162
- bb plugin config thread-pages # shows homeThreadId
163
- ```
164
-
165
- `/home` then redirects there, and **every other page shows a "← Sessions" link
166
- back to it automatically**. That link is chrome in the trusted shell, so no page
167
- authors it and no agent spends instruction budget on it. Home does not link to
168
- itself.
169
-
170
- `bb thread-page home` writes a real session hub when that thread has no page
171
- yet, and never touches one that exists. The default groups sessions by project,
172
- gives each group its own look, and offers filter, open, prompt, spawn, stop and
173
- archive per row.
174
-
175
- **Groups are not projects.** A group is a label, a look, and a *set* of project
176
- ids, stored in the page's own scoped storage under `home.groups`. One group per
177
- project is only the default. Ask the owning agent for "Work" and "Side projects",
178
- or to put one project in two groups, and it edits the page — no schema, no plugin
179
- change. Each group carries `data-world`, which re-resolves the design tokens for
180
- that subtree, so a project genuinely looks different without a second document.
181
-
182
- Home is an ordinary Thread Page: it calls `threads.snapshot`, `projects.list` and
183
- `providers.list` and renders what it likes. You can ask the owning agent to
184
- redesign it like any other page.
185
-
186
- ## The working indicator
187
-
188
- While the owning thread is mid-turn, the page header shows a pulsing dot and
189
- wording you control:
190
-
191
- ```sh
192
- bb plugin config thread-pages set workingLabel "Thinking…"
193
- bb plugin config thread-pages set workingLabel "" # hides it
194
- ```
195
-
196
- The point is the sentence: what you are reading is the last *saved* version, and
197
- another one is coming. It costs nothing to run — the state rides on the
198
- `x-thread-page-activity` header of the revision poll the shell already makes
199
- every 10 seconds, so there is no extra request, nothing for a page to implement,
200
- and nothing in any agent's instructions.
201
-
202
- ## Files in this repository
203
-
204
- | File | Role |
205
- | --- | --- |
206
- | `server.ts` | Settings, CLI, HTTP routes, capability handlers, caching |
207
- | `page.ts` | Token signing, HTML parsing/injection, both browser runtimes, form and upload serialization |
208
- | `bridge.ts` | The capability contract and validators. No SDK, DOM, fetch, or filesystem imports |
209
- | `authoring.ts` | The instruction, the seed, the guide |
210
- | `home.ts` | The default home page: markup, styles, and script |
211
- | `theme.ts` | The design system |
package/docs/ROADMAP.md DELETED
@@ -1,96 +0,0 @@
1
- # Roadmap
2
-
3
- Version 0.3.0 · September 2026
4
-
5
- ## Done
6
-
7
- Everything needed for daily use is implemented and verified in a browser.
8
-
9
- **The page.** Complete HTML/CSS/JS mini-apps in an opaque sandbox, parsed with
10
- parse5 and kernel-injected before authored scripts. Five-world design system
11
- carried in each page. Automatic semantic forms with independent per-form state,
12
- blank-safe answers, manual opt-out, and update protection. File attachments in a
13
- confined upload directory. A confined asset directory with a matching CSP.
14
-
15
- **The chrome.** Title bar, Sessions link, working indicator — all outside the
16
- sandbox, none of it costing an agent anything.
17
-
18
- **The home page.** `bb thread-page home` designates any thread's page and writes
19
- a session hub grouped by project, with a look per group and grouping stored in
20
- the page rather than hard-wired.
21
-
22
- **The bridge.** Seventeen of eighteen capabilities, with trusted confirmation for
23
- every cross-thread, destructive, device and external-navigation effect.
24
-
25
- **Access.** Remote by default through the existing bb origin, with no port share.
26
-
27
- ## Left
28
-
29
- ### Before wide release
30
-
31
- **A hostile-page corpus.** The only item I would call blocking for a public
32
- audience. The confirmation flow is tested against forgery, replay and
33
- parameter-swapping, but no test yet plays an attacker: trying to read the bb
34
- cookie, reach `parent`/`top`, forge another thread's action, or reach the network.
35
- The design says these are impossible; a test should prove it, and should also
36
- demonstrate the self-frame navigation limitation rather than leave it as prose.
37
-
38
- ### Capabilities
39
-
40
- **`voice.captureAndTranscribe`** has a contract and validators but no handler.
41
- Recording happens in trusted chrome and transcription goes through bb's own voice
42
- service. Deferred as unused; the contract is there when it is wanted.
43
-
44
- ### Worth doing
45
-
46
- - **Asset and upload cleanup.** Neither directory is ever pruned. A page that
47
- receives many attachments grows without bound.
48
- - **`threads.snapshot` paging.** `nextCursor` is always `null`; the limit is 200.
49
- Fine for now, wrong eventually.
50
- - **Design-system updates for existing pages.** Each page carries its own
51
- stylesheet, which is what makes per-page restyling safe and plugin updates
52
- harmless. The cost is that improvements only reach new pages. If that becomes
53
- annoying, the answer is a command that re-splices the current stylesheet into a
54
- page on request — not injection at render time, which would take the property
55
- away.
56
- - **A second reference page.** The home page is the only worked example. One
57
- more — a diagram or a multi-screen flow — would show the range better than the
58
- guide's prose.
59
-
60
- ## Non-goals
61
-
62
- - **A component library or theme picker.** The plugin hosts pages; it does not
63
- design them. Five worlds exist so a page has a coherent starting point, not so
64
- it has a menu.
65
- - **A fixed dashboard.** Home is an ordinary page. Anything the plugin renders
66
- itself is one thing an agent cannot adapt to the task.
67
- - **General network access from a page.** When a task needs a remote service it
68
- should get a named, reviewed capability, not a fetch proxy.
69
- - **Strict no-exfiltration.** Would require forbidding authored JavaScript, which
70
- is the product. See ARCHITECTURE.md.
71
-
72
- ## Release
73
-
74
- 1. `npm ci && bb plugin types --check . && npm test && npm run typecheck && npm run build`
75
- 2. Tag `vX.Y.Z` and push. bb records the tag with the commit it pointed at and
76
- **refuses a tag that later moves** — so publish a fix as a new version rather
77
- than retagging. If a tag has to move, everyone on it must remove and reinstall.
78
- 3. Verify `bb plugin install git:<url>@^X.Y.0` on a clean machine.
79
- 4. Publish to npm (see below).
80
- 5. Submit to the marketplace with the `submit-a-plugin` skill, which reads the
81
- current contract from `github.com/get-bb/marketplace` rather than assuming one.
82
-
83
- ### Publishing to npm
84
-
85
- The scope has to exist and you have to be logged in as a member:
86
-
87
- ```sh
88
- npm login # as the account that owns @unifedev
89
- npm publish --access public
90
- ```
91
-
92
- `dist/` is committed and also packed, so neither a git nor an npm install needs a
93
- build step. `package-lock.json` is committed for the git path — npm strips it from
94
- tarballs by design, which is fine because npm resolves `parse5` itself.
95
-
96
- Verify afterwards with `bb plugin install npm:@unifedev/thread-pages@^0.3.0`.