toolroll 0.9.54 → 0.9.55

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 (199) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/README.md +5 -4
  3. package/dist/agent-onboard.js +4 -1
  4. package/dist/approval-rules-ui.d.ts +3 -2
  5. package/dist/approval-rules-ui.js +15 -20
  6. package/dist/assignment-ui.d.ts +3 -2
  7. package/dist/assignment-ui.js +4 -11
  8. package/dist/backup-ui.d.ts +2 -1
  9. package/dist/backup-ui.js +16 -27
  10. package/dist/brand-mark.d.ts +3 -2
  11. package/dist/brand-mark.js +4 -4
  12. package/dist/browser/workspace.css +1 -1
  13. package/dist/browser/workspace.js +25 -25
  14. package/dist/browser-shell.d.ts +2 -1
  15. package/dist/browser-shell.js +9 -9
  16. package/dist/browser-workspace.d.ts +2 -3
  17. package/dist/browser-workspace.js +0 -3
  18. package/dist/chat-polish.d.ts +5 -4
  19. package/dist/chat-polish.js +9 -10
  20. package/dist/check-levels-ui.d.ts +2 -1
  21. package/dist/check-levels-ui.js +26 -53
  22. package/dist/cli.d.ts +3 -1
  23. package/dist/cli.js +9 -3
  24. package/dist/coding-shipping-ui.d.ts +2 -1
  25. package/dist/coding-shipping-ui.js +6 -6
  26. package/dist/coding-ui.d.ts +3 -1
  27. package/dist/coding-ui.js +30 -29
  28. package/dist/contracts/cli.d.ts +1 -3
  29. package/dist/contracts/console-api.d.ts +1 -1
  30. package/dist/contracts/console-api.js +6 -5
  31. package/dist/contracts/health.d.ts +1 -3
  32. package/dist/control-ui.d.ts +5 -4
  33. package/dist/control-ui.js +9 -34
  34. package/dist/credentials-ui.d.ts +5 -4
  35. package/dist/credentials-ui.js +23 -24
  36. package/dist/demo-chat.d.ts +3 -3
  37. package/dist/demo-chat.js +29 -76
  38. package/dist/discord-settings.d.ts +3 -2
  39. package/dist/discord-settings.js +17 -42
  40. package/dist/envelope.js +10 -0
  41. package/dist/evidence-pack.d.ts +2 -1
  42. package/dist/evidence-pack.js +45 -49
  43. package/dist/export-ui.d.ts +7 -2
  44. package/dist/export-ui.js +4 -10
  45. package/dist/flow-gallery-ui.d.ts +4 -3
  46. package/dist/flow-gallery-ui.js +28 -43
  47. package/dist/flow-starters-ui.d.ts +2 -1
  48. package/dist/flow-starters-ui.js +12 -15
  49. package/dist/flow-triggers.d.ts +1 -0
  50. package/dist/flow-triggers.js +16 -14
  51. package/dist/flows-ui.d.ts +4 -3
  52. package/dist/flows-ui.js +19 -30
  53. package/dist/flows.js +2 -1
  54. package/dist/guides.js +108 -3
  55. package/dist/html.d.ts +76 -0
  56. package/dist/html.js +173 -0
  57. package/dist/integrations-ui.d.ts +2 -1
  58. package/dist/integrations-ui.js +19 -23
  59. package/dist/kits-ui.d.ts +5 -4
  60. package/dist/kits-ui.js +18 -20
  61. package/dist/knowledge-ui.d.ts +6 -5
  62. package/dist/knowledge-ui.js +26 -25
  63. package/dist/lead-context.d.ts +11 -1
  64. package/dist/lead-context.js +6 -8
  65. package/dist/ledger-view.d.ts +2 -1
  66. package/dist/ledger-view.js +27 -29
  67. package/dist/limits-ui.d.ts +2 -1
  68. package/dist/limits-ui.js +7 -7
  69. package/dist/live-bus.d.ts +50 -8
  70. package/dist/live-bus.js +133 -50
  71. package/dist/mcp-oauth.js +35 -36
  72. package/dist/models-ui.d.ts +2 -1
  73. package/dist/models-ui.js +25 -35
  74. package/dist/monitoring-ui.d.ts +4 -3
  75. package/dist/monitoring-ui.js +13 -26
  76. package/dist/openrouter-models.d.ts +2 -1
  77. package/dist/openrouter-models.js +5 -9
  78. package/dist/operate.js +11 -7
  79. package/dist/people-audit-ui.d.ts +2 -1
  80. package/dist/people-audit-ui.js +13 -13
  81. package/dist/policy-ui.d.ts +3 -2
  82. package/dist/policy-ui.js +17 -23
  83. package/dist/project-delete-ui.d.ts +4 -3
  84. package/dist/project-delete-ui.js +15 -27
  85. package/dist/pull-request-ui.d.ts +2 -1
  86. package/dist/pull-request-ui.js +17 -32
  87. package/dist/recipe-ui.d.ts +8 -7
  88. package/dist/recipe-ui.js +39 -32
  89. package/dist/release-adapters.d.ts +60 -0
  90. package/dist/release-adapters.js +435 -0
  91. package/dist/release-cli.d.ts +24 -0
  92. package/dist/release-cli.js +181 -0
  93. package/dist/release-gate.d.ts +80 -0
  94. package/dist/release-gate.js +150 -0
  95. package/dist/release-links.d.ts +29 -0
  96. package/dist/release-links.js +102 -0
  97. package/dist/release.d.ts +331 -0
  98. package/dist/release.js +550 -0
  99. package/dist/reply-shape.d.ts +2 -1
  100. package/dist/reply-shape.js +5 -5
  101. package/dist/repository-context-ui.d.ts +2 -1
  102. package/dist/repository-context-ui.js +2 -7
  103. package/dist/request-budget-ui.d.ts +2 -1
  104. package/dist/request-budget-ui.js +16 -16
  105. package/dist/result-review.d.ts +2 -3
  106. package/dist/result-review.js +3 -9
  107. package/dist/retention-ui.d.ts +7 -1
  108. package/dist/retention-ui.js +7 -11
  109. package/dist/serve.d.ts +11 -2
  110. package/dist/serve.js +69 -58
  111. package/dist/server/chat.d.ts +3 -6
  112. package/dist/server/chat.js +969 -1006
  113. package/dist/server/chrome.d.ts +291 -0
  114. package/dist/server/chrome.js +747 -0
  115. package/dist/server/console.css +2819 -0
  116. package/dist/server/flows.d.ts +2 -6
  117. package/dist/server/flows.js +840 -766
  118. package/dist/server/guards.d.ts +1 -1
  119. package/dist/server/guards.js +5 -2
  120. package/dist/server/handler-context.d.ts +1 -1
  121. package/dist/server/handler-context.js +1 -1
  122. package/dist/server/handler-registry.d.ts +8 -6
  123. package/dist/server/handler-registry.js +14 -2
  124. package/dist/server/http.d.ts +274 -0
  125. package/dist/server/http.js +239 -0
  126. package/dist/server/live.d.ts +34 -0
  127. package/dist/server/live.js +309 -0
  128. package/dist/server/pages.d.ts +2 -6
  129. package/dist/server/pages.js +808 -789
  130. package/dist/server/people-tokens.d.ts +1 -6
  131. package/dist/server/people-tokens.js +580 -572
  132. package/dist/server/remote.d.ts +4 -7
  133. package/dist/server/remote.js +37 -70
  134. package/dist/server/render-chat.d.ts +402 -0
  135. package/dist/server/render-chat.js +927 -0
  136. package/dist/server/render-pages.d.ts +535 -0
  137. package/dist/server/render-pages.js +1277 -0
  138. package/dist/server/render-people.d.ts +32 -0
  139. package/dist/server/render-people.js +121 -0
  140. package/dist/server/render-results.d.ts +744 -0
  141. package/dist/server/render-results.js +2237 -0
  142. package/dist/server/render-settings.d.ts +147 -0
  143. package/dist/server/render-settings.js +577 -0
  144. package/dist/server/render-tasks.d.ts +632 -0
  145. package/dist/server/render-tasks.js +2345 -0
  146. package/dist/server/request-context.d.ts +46 -0
  147. package/dist/server/request-context.js +17 -0
  148. package/dist/server/route-table.d.ts +25 -3
  149. package/dist/server/route-table.js +163 -75
  150. package/dist/server/runtime.d.ts +15 -7
  151. package/dist/server/runtime.js +7 -1
  152. package/dist/server/session.d.ts +138 -0
  153. package/dist/server/session.js +94 -0
  154. package/dist/server/settings.d.ts +1 -5
  155. package/dist/server/settings.js +2181 -2117
  156. package/dist/server/task-views.d.ts +11 -4
  157. package/dist/server/task-views.js +26 -22
  158. package/dist/server/tasks.d.ts +9 -9
  159. package/dist/server/tasks.js +1486 -1418
  160. package/dist/server-telemetry.d.ts +4 -3
  161. package/dist/server-telemetry.js +4 -8
  162. package/dist/skills-ui.d.ts +4 -3
  163. package/dist/skills-ui.js +14 -17
  164. package/dist/skills.d.ts +1 -1
  165. package/dist/skills.js +2 -1
  166. package/dist/slack-settings.d.ts +3 -2
  167. package/dist/slack-settings.js +17 -42
  168. package/dist/spend-ui.d.ts +2 -1
  169. package/dist/spend-ui.js +9 -32
  170. package/dist/sso-ui.d.ts +3 -2
  171. package/dist/sso-ui.js +26 -27
  172. package/dist/storage-ui.d.ts +2 -1
  173. package/dist/storage-ui.js +14 -33
  174. package/dist/surface.js +14 -3
  175. package/dist/task-composer.d.ts +2 -1
  176. package/dist/task-composer.js +7 -7
  177. package/dist/task-status.d.ts +4 -3
  178. package/dist/task-status.js +15 -16
  179. package/dist/team-http.d.ts +5 -9
  180. package/dist/team-http.js +5 -63
  181. package/dist/team-ui.d.ts +2 -1
  182. package/dist/team-ui.js +2 -5
  183. package/dist/teammates-ui.d.ts +5 -4
  184. package/dist/teammates-ui.js +61 -90
  185. package/dist/teams-settings.d.ts +3 -2
  186. package/dist/teams-settings.js +20 -31
  187. package/dist/telegram-settings.d.ts +3 -2
  188. package/dist/telegram-settings.js +14 -25
  189. package/dist/toolroll-update-ui.d.ts +3 -2
  190. package/dist/toolroll-update-ui.js +35 -39
  191. package/dist/tools-ui.d.ts +5 -2
  192. package/dist/tools-ui.js +31 -31
  193. package/dist/when-html.d.ts +11 -3
  194. package/dist/when-html.js +5 -6
  195. package/dist/workspace-ui.d.ts +4 -2
  196. package/dist/workspace-ui.js +10 -10
  197. package/package.json +1 -1
  198. package/dist/server/shared.d.ts +0 -3151
  199. package/dist/server/shared.js +0 -12001
@@ -0,0 +1,291 @@
1
+ import { type BrowserSignIn, type BrowserUpdateNotice, type BrowserWorkspace } from "../browser-workspace.js";
2
+ import { type Decision, type Run } from "../store.js";
3
+ import { type tally } from "../summary.js";
4
+ import { type ServerResponse } from "node:http";
5
+ import { type Html } from "../html.js";
6
+ import { type ProjectPeek } from "./render-pages.js";
7
+ import { type Who } from "./session.js";
8
+ /** The spend line for a 7am reader: whole cents, "runs", the gap still named. */
9
+ export declare function consoleSpend(summary: ReturnType<typeof tally<Run & {
10
+ taskId: string;
11
+ }>>): string;
12
+ /** ISO to the minute — "2026-08-12 17:56" — for anywhere a person reads a time. */
13
+ export declare function when(iso: string | null): string;
14
+ /** The same minute as a `<time>`: the full stamp on a desk, "16:39" / "Yesterday 16:39" / "Sep 28" on a phone. */
15
+ export declare function whenTime(iso: string | null): Html;
16
+ /** Overdue is derived at render — display never writes. */
17
+ export declare function isOverdue(decision: Decision, now: Date): boolean;
18
+ /**
19
+ * A refusal that stays inside the console: same shell, a problem banner, and
20
+ * a way back — the error path is the one place a console must not stop
21
+ * being a console. Bearer callers still get plain text; they parse, not read.
22
+ */
23
+ export declare function refuse(response: ServerResponse, who: Who | null, status: number, message: string, backHref?: string): void;
24
+ /** The demo's one-line promise, on every page. */
25
+ export declare const DEMO_BANNER = "Demo: a scripted lead and sample projects. Nothing calls a model, reaches outside or spends. For your own project, run npx toolroll up in its folder.";
26
+ /** The demo notice on a phone: one line. */
27
+ export declare const DEMO_BANNER_SHORT = "Demo: sample projects. Nothing calls a model or spends.";
28
+ /**
29
+ * The Operations Ledger: the design system Alex approved in Figma and the
30
+ * design/ shadcn package, carried as pure CSS on server-rendered HTML.
31
+ * Deliberately not the React library: the console ships zero dependencies
32
+ * and zero page JavaScript under a CSP that forbids scripts, and a look is
33
+ * not worth that posture. The same semantic tokens render both system light
34
+ * and dark themes.
35
+ */
36
+ /** The shared palette, light and dark (2026-09-27, "Signal"): neutral grey
37
+ * grounds, ink for every act a person can take, and one chart magenta, the
38
+ * colour nautical charts print lights and cautions in, for what needs a
39
+ * person (the needs-you count, the act that resolves a screen, focus and
40
+ * selection). Status keeps its own four hues; magenta never means "failed".
41
+ * The frame is the ground the sidebar sits on; work sits on paper sheets
42
+ * inset into it. Semantic names only; every surface (server pages, the
43
+ * React workspace, the pre-script fallback) reads these.
44
+ *
45
+ * The console's stylesheet lives in console.css, shipped beside this module:
46
+ * the palette above in light, dark and pinned themes, then the page rules.
47
+ * Its bytes are the served sheet's (WORKSPACE_STYLE hashes them). */
48
+ export declare const STYLE: string;
49
+ /** Appearance: a three-way segmented switch, one tap per choice. */
50
+ export declare const THEME_CONTROLS_CSS = ".task-repo select{width:100%;min-height:2.75rem;font-size:1rem}.task-repo-add{margin:.35rem .1rem .5rem}.task-repo-add a{display:inline-flex;align-items:center;min-height:2.25rem}details.result-request-open.result-request-form>summary{border:0;background:transparent;padding:.5rem 0;min-height:2.75rem;font-weight:600;display:list-item;list-style:revert}details.result-request-open.result-request-form>summary::-webkit-details-marker{display:revert}form.js-autosave button[type=submit]{display:none}.provider-row{border-bottom:1px solid var(--so-line);padding:.35rem 0}.provider-row:first-of-type{border-top:1px solid var(--so-line)}.provider-head{display:flex;align-items:center;gap:.75rem;margin:.4rem 0 0}.provider-status{display:inline-flex;align-items:center;gap:.4rem;color:var(--so-muted);font-size:.875rem}.provider-status i{width:.5rem;height:.5rem;border-radius:50%;background:var(--so-muted)}.provider-status--ok i{background:var(--so-success)}.provider-status--warn i{background:var(--so-attention)}.provider-status--off i{background:transparent;border:1.5px solid var(--so-muted)}details.provider-manage>summary{cursor:pointer;color:var(--so-accent-text);font-size:.875rem;min-height:2.5rem;display:list-item;padding-block:.5rem}.card.props .row{display:grid;gap:.1rem;margin:0 0 .75rem}.card.props .row>.meta{display:block;font-size:.75rem}.card.props .row>.meta::first-letter{text-transform:uppercase}.card.props .row>.mono{font-family:var(--font-sans);font-size:.875rem}.card.props .row>.mono .seal{font-family:var(--font-mono);font-size:.8125rem}details.evidence-files{margin:1rem 0}details.evidence-files>summary{cursor:pointer;min-height:2.75rem;display:list-item;padding-block:.7rem;font-weight:600}details.evidence-files ul{list-style:none;margin:0;padding:0}details.evidence-files li{display:flex;justify-content:space-between;gap:1rem;padding:.5rem 0;border-bottom:1px solid var(--so-line)}.result-action .result-feedback-link{display:inline-flex;align-items:center;min-height:2.5rem;padding:.5rem 1rem;border:1px solid var(--so-input-line);border-radius:.5rem;background:var(--so-paper);color:var(--so-ink);font-weight:600;text-decoration:none}@media(hover:hover) and (pointer:fine){.result-action .result-feedback-link:hover{background:var(--so-raised)}}.so-sr-only{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}.verdict{margin:.5rem 0 .75rem}.verdict-chips{display:flex;flex-wrap:wrap;gap:.4rem;list-style:none;padding:0;margin:0}.verdict-chip{display:inline-flex;align-items:center;gap:.3rem;min-height:1.75rem;padding:.2rem .65rem;border-radius:999px;font-size:.8125rem;font-weight:600;background:var(--so-neutral-soft);color:var(--so-neutral-ink)}.verdict-chip svg{width:.9rem;height:.9rem}.verdict-chip--success{background:var(--so-success-soft);color:var(--so-success)}.verdict-chip--danger{background:var(--so-danger-soft);color:var(--so-danger)}.verdict-chip--warning{background:var(--so-warning-soft);color:var(--so-warning)}.verdict-chip--info{background:var(--so-info-soft);color:var(--so-info)}.verdict-by{margin:.4rem 0 0}details.result-request-open{margin:.5rem 0}details.result-request-open>summary{display:inline-flex;align-items:center;min-height:2.5rem;padding:.5rem 1rem;border:1px solid var(--so-input-line);border-radius:.5rem;background:var(--so-paper);color:var(--so-ink);font-weight:600;cursor:pointer;list-style:none}details.result-request-open>summary::-webkit-details-marker{display:none}details.result-request-open[open]>summary{margin-bottom:.75rem}.settings-tiles{display:grid;gap:1.25rem;margin:0 0 2rem}.settings-tiles h2{margin:0 0 .5rem;font-size:.875rem;font-weight:600;color:var(--so-muted)}.settings-tiles section>div{display:grid;grid-template-columns:repeat(auto-fill,minmax(8.5rem,1fr));gap:.5rem}.settings-tiles a>span{display:grid;gap:.1rem;min-width:0}.settings-tiles .provider-status{font-weight:400;font-size:.8125rem}.settings-tiles a{display:flex;align-items:center;gap:.6rem;min-height:3rem;padding:.65rem .8rem;border:1px solid var(--so-line);border-radius:.625rem;background:var(--so-paper);color:var(--so-ink);text-decoration:none;font-weight:550;font-size:.875rem}@media(hover:hover) and (pointer:fine){.settings-tiles a:hover{border-color:var(--so-input-line);background:var(--so-raised)}}.settings-tiles a>svg{width:1.1rem;height:1.1rem;flex-shrink:0;color:var(--so-accent-text)}details.settings-more{margin:.25rem 0 1.25rem}details.settings-more>summary{cursor:pointer;min-height:2.75rem;display:list-item;padding-block:.7rem;font-weight:550}details.settings-more>summary .meta{font-weight:400;margin-left:.35rem}.settings-changed{margin-top:-.25rem}.appearance{margin:0 0 28px}.appearance h2{margin:0 0 10px}.theme-switch{display:inline-flex;flex-wrap:nowrap;max-width:100%;gap:4px;padding:4px;margin:0;border:1px solid var(--so-line);border-radius:10px;background:var(--so-raised)}.theme-switch .theme-choice,.so-native-region .theme-switch .theme-choice{flex:1 1 0;width:auto;white-space:nowrap;min-height:40px;padding:8px 16px;border:0;border-radius:7px;background:transparent;color:var(--so-muted);font:inherit;font-weight:550;box-shadow:none;cursor:pointer}@media(hover:hover) and (pointer:fine){.theme-switch .theme-choice:hover{color:var(--so-ink)}}.theme-switch .theme-choice[aria-pressed=\"true\"]{background:var(--so-paper);color:var(--so-ink);box-shadow:0 1px 2px rgb(0 0 0 / .1)}.appearance .meta{margin:8px 0 0}@media(max-width:600px){.theme-switch .theme-choice{min-height:44px}}.update-notes{white-space:pre-wrap;overflow-wrap:anywhere;font:inherit;max-height:18rem;overflow:auto}";
51
+ /** The page CSS this module writes itself (not the imported modules'), for the stylesheet contract tests. */
52
+ export declare const PAGE_CSS: string;
53
+ /** The Inbox tabs (console v2): a segmented track of real links; the dot marks a tab with something new, on phones only. */
54
+ export declare const INBOX_TABS_CSS: string;
55
+ export declare const WORKSPACE_STYLE: {
56
+ path: string;
57
+ serve(request: import("node:http").IncomingMessage, response: ServerResponse): void;
58
+ };
59
+ /** Everything the sidebar needs to draw itself for one request. */
60
+ export type Chrome = {
61
+ projectScoped?: boolean;
62
+ active: "code" | "inbox" | "board" | "queue" | "fleet" | "workbench" | "work" | "done" | "activity" | "review" | "system" | "tasks" | "runs" | "caps" | "recipes" | "projects" | "flows" | "settings" | "chat" | "people" | "ledger" | "spend" | "mode" | "menu" | "none";
63
+ project: string | null;
64
+ /** The surface's scope for the scope bar — which rows this screen can
65
+ * show. Derived from the ROUTE, not the session: portfolio and fleet are
66
+ * all-project even while a project is open; the board says which of its
67
+ * two modes it is in. Absent = the session default (open project, else
68
+ * all projects). Display only — switching stays POST + CSRF. */
69
+ scope?: "all" | "project" | "board-all";
70
+ /** The saturated inbox count — never a sum of unbounded list reads. */
71
+ inboxCount: number;
72
+ /** The project the Tasks count covers: the request's own project view
73
+ * (the open project, or /work's ?project=), null for every admitted project. */
74
+ inboxProject?: string | null;
75
+ /** The Tasks badge's words, naming what it covers: "3 need you in shop". */
76
+ inboxLabel?: string;
77
+ inboxSaturated: boolean;
78
+ settings: boolean;
79
+ /** This database is a demo sandbox: banner every page, spend fenced. */
80
+ demo?: boolean;
81
+ /** The active operating mode's banner (M1): rides every page scoped to
82
+ * a repo with a live mode — a signed posture is never invisible. */
83
+ modeBanner?: {
84
+ words: string;
85
+ name: string;
86
+ };
87
+ /** Providers whose sign-in stopped working: every page says so, once. */
88
+ signIn?: BrowserSignIn[];
89
+ /** A newer Toolroll: a quiet notice for an operator until they dismiss this version. */
90
+ update?: BrowserUpdateNotice;
91
+ /** An update waiting on something, what, and the action that clears it: every page, for an operator. */
92
+ updateWaiting?: {
93
+ words: string;
94
+ };
95
+ /** The chat tab renders only where chat could ever be allowed. */
96
+ chat?: boolean;
97
+ code?: boolean;
98
+ /** A rendered list pane makes the page master-detail. */
99
+ listPane?: Html;
100
+ /** A compact pulse for the currently open workspace. Null in the
101
+ * cross-workspace view; absent only when the store could not answer. */
102
+ projectPeek?: ProjectPeek | null;
103
+ /** The switcher (board pass): every enrolled project inside the ceiling,
104
+ * most recently opened first — the one-tap switch on any screen. */
105
+ projects?: {
106
+ path: string;
107
+ name: string;
108
+ }[];
109
+ /** The session's csrf token, for the switcher's forms; "" when the
110
+ * request has no cookie session (bearer), which renders the switcher
111
+ * inert. */
112
+ csrf?: string;
113
+ /** Where a switch made on this screen returns to. */
114
+ returnTo?: string;
115
+ };
116
+ /**
117
+ * A server-rendered region that stays current: when the page's live stream
118
+ * says something changed (GET /live, live-bus.ts), fetch this page's own
119
+ * fragment and swap it in place — no flicker, no scroll reset. Inside the
120
+ * workspace the page's one stream is already open (browser/live.ts) and
121
+ * announces each event on `window`; a page without it opens its own stream
122
+ * to the workspace room. A redirect or auth failure navigates to /login
123
+ * instead of ever inserting the login page into the region (finding 4). The
124
+ * swapped markup is this server's own rendering of the same route — escaped
125
+ * at the sink like every page, fetched same-origin — and the nonce'd CSP
126
+ * refuses to execute anything the region could smuggle. Nothing reads on a timer.
127
+ */
128
+ export declare function regionScript(regionId: string, fragmentName: string, path?: string): string;
129
+ /**
130
+ * The live transcript's DEDICATED poller (arc 1 §4): a JSON byte-offset
131
+ * protocol, not an HTML fragment — the response is raw sanitized text and
132
+ * the ONLY sink is textContent, so nothing here can become markup. One
133
+ * request in flight, visibility-paused, stops on `final`, and a `replaced`
134
+ * answer restarts from zero with a visible line — never a silent re-read.
135
+ */
136
+ export declare function transcriptScript(path?: string, elementId?: string): string;
137
+ /**
138
+ * The chrome layer: the jump palette and elapsed tickers. Pure
139
+ * navigation — no key ever posts, so the palette cannot approve anything;
140
+ * ceremonies stay POST + password + CSRF, untouched. Reads its index from
141
+ * a non-executable JSON script tag rendered by the same authorized page.
142
+ */
143
+ /** The rail's presentation-only state is safe beside a password ceremony:
144
+ * it never reads a field or sends a request, and keeps the chat collapsible
145
+ * from its very first screen while the palette and global keys remain absent. */
146
+ export declare function sidebarScript(): string;
147
+ export declare function chromeScript(): string;
148
+ /**
149
+ * A page described, not yet rendered (arc 4): every chromed HTML route
150
+ * returns one of these and ONE helper (sendScreen, inside the server)
151
+ * owns the nonce, the palette index, the shortcuts overlay, script
152
+ * composition, and the CSP. Renderers stopped calling shell() themselves
153
+ * so those five things cannot drift apart per route.
154
+ */
155
+ export type Screen = {
156
+ title: string;
157
+ body: Html;
158
+ chrome?: Chrome;
159
+ /** The page's own executable behavior (a region poller, the push
160
+ * enrollment script). fetches: true when it calls fetch — connect-src
161
+ * is granted only then. */
162
+ functional?: {
163
+ script: string;
164
+ fetches?: boolean;
165
+ };
166
+ refreshSeconds?: number;
167
+ /** Render sensitive even when no password field is visible — one-time
168
+ * secrets and judgment calls the classifier cannot see. */
169
+ forceSensitive?: boolean;
170
+ /** Structured conversation; complex guarded forms stay native islands. */
171
+ workspace?: Partial<Pick<BrowserWorkspace, 'conversation' | 'team' | 'focus' | 'result' | 'notices' | 'view' | 'firstRun' | 'phone' | 'home'>> & {
172
+ /** Markup the workspace shows in place; it becomes bytes where the page's JSON is written (sendScreen). */
173
+ catchUpHtml?: Html;
174
+ controlsHtml?: Html;
175
+ pageHtml?: Html | null;
176
+ };
177
+ };
178
+ export declare const ROLE_TITLES: Record<"plan" | "build" | "review" | "repair", string>;
179
+ export declare function screen(title: string, body: Html, options?: Omit<Screen, "title" | "body">): Screen;
180
+ /**
181
+ * The sensitivity classifier (arc 4, findings 3/17): a body showing a
182
+ * password input renders WITHOUT the chrome additions (palette, overlay,
183
+ * global keys) — the page's own functional script still ships. Tolerant
184
+ * of quoting, casing, and whitespace; `data-type="password"` and prose
185
+ * mentioning passwords do not match. This is defense-in-depth over a
186
+ * file whose only HTML producer is its own double-quoted template
187
+ * convention — forceSensitive is the escape hatch for what a regex
188
+ * cannot judge.
189
+ */
190
+ export declare const SENSITIVE_INPUT: RegExp;
191
+ /** The design contract every page carries (impeccable direction, 2026-09-27). */
192
+ export declare const DESIGN_CONTRACT: Html;
193
+ /** The shortcuts overlay: display-only, toggled by the chrome layer,
194
+ * absent from sensitive pages. Navigation help in plain words — no key
195
+ * ever posts. */
196
+ export declare const KBD_HELP: Html;
197
+ export declare function shell(title: string, body: Html, options?: {
198
+ nav?: boolean;
199
+ chrome?: Chrome;
200
+ /** A password ceremony is on this page: the chrome gains no forms, so
201
+ * the switcher renders inert — the name, and the one /projects link. */
202
+ sensitive?: boolean;
203
+ /** Whether the presentation-only desktop rail control has a nonce'd
204
+ * handler. Sensitive pages may opt in; one-time-secret pages do not. */
205
+ sidebarToggle?: boolean;
206
+ refreshSeconds?: number;
207
+ /** The page's one nonce'd script: region pollers + the chrome layer,
208
+ * composed by sendScreen. Read-only regions only; one nonce per
209
+ * response. fallbackRefresh marks a page whose script POLLS — only
210
+ * those earn the noscript meta-refresh (a chrome-layer-only page with
211
+ * forms must never re-render what someone was typing). */
212
+ live?: {
213
+ nonce: string;
214
+ script: string;
215
+ fallbackRefresh?: boolean;
216
+ };
217
+ }): Html;
218
+ /** ONE way a person is named on any surface (U3): the same chip everywhere. */
219
+ export declare function personChip(name: string): Html;
220
+ /** The brand, as the workspace sidebar shows it. */
221
+ export declare const BRAND_HTML: Html;
222
+ /** A page on its own, in the workspace's look but with no script: the brand, then the page. */
223
+ export declare function focusDocument(title: string, body: Html): Html;
224
+ export declare function chatMoney(microusd: number | null): string;
225
+ export declare function relativeAge(iso: string, now: Date): string;
226
+ /** The project chip every all-scope row wears: null is UNPLACED, said so. */
227
+ export declare function projectChip(repo: string | null | undefined): Html;
228
+ /**
229
+ * Creating work is the product's first verb, so it gets a whole calm page:
230
+ * a title, the goal that becomes the scope draft, and the project it lands
231
+ * in — then straight to the approve card, which is the aha the flow serves.
232
+ */
233
+ /** One queue card. Taken work renders pinned — visible, never draggable. */
234
+ /** The person's pinned theme from their own cookie; null follows the device. */
235
+ export declare function pinnedTheme(cookieHeader: string | undefined): "light" | "dark" | null;
236
+ export declare function themeAttribute(): Html;
237
+ /** A chosen accent (Settings → Appearance) re-pigments the signal tokens only, after the shared stylesheet. */
238
+ export declare function accentHead(): Html;
239
+ /** Drawn, one stroke weight, like the tab bar's icons — never a glyph. */
240
+ export declare const GRIP_ICON: Html;
241
+ export declare const TO_FRONT_ICON: Html;
242
+ /** One stroke weight, from the tab bar's set: the sidebar's primary rows
243
+ * wear an icon each; the foot's list stays text, the way Linear's does. */
244
+ export declare const strokeIcon: (paths: Html | string) => Html;
245
+ /** Where the queue lives now: the board, flipped to dispatch order. */
246
+ export declare const QUEUE_VIEW = "/board?view=order";
247
+ export declare const FOLDER_PATHS: Html;
248
+ export declare const CHAT_PATHS: Html;
249
+ export declare const WORK_PATHS: Html;
250
+ export declare const NAV_ICONS: Partial<Record<Chrome["active"], Html>>;
251
+ /** One grouped destination inside an accordion group or the /menu overflow. */
252
+ export type NavRow = {
253
+ key: Chrome["active"];
254
+ href: string;
255
+ label: string;
256
+ hint: string;
257
+ };
258
+ /**
259
+ * The workspace shell (package 1): three primary rows (chat, work,
260
+ * projects) above two accordion groups. Work tools is where work is
261
+ * arranged, planned, and scheduled — the board, its order view, the
262
+ * flat task list, recipes, the portfolio, and the action
263
+ * ledger. Settings is who and what the fleet runs on — fleet,
264
+ * requirements, people, operating mode, system — plus the agent-defaults
265
+ * page where the console offers it. Both draw from the same two lists on
266
+ * a desk (accordion groups) and on a phone (/menu sections), so the two
267
+ * never disagree, and a project-scoped login sees exactly the rows it
268
+ * saw before: moving a link never widens role or project visibility.
269
+ */
270
+ export declare function workToolRows(scoped?: boolean, _offersChat?: boolean, offersCode?: boolean): NavRow[];
271
+ export declare function settingsRows(scoped?: boolean, offersSettings?: boolean): NavRow[];
272
+ /** Which accordion group opens by default for a given active page. */
273
+ export declare const TOOL_KEYS: Set<"activity" | "board" | "caps" | "chat" | "code" | "done" | "fleet" | "flows" | "inbox" | "ledger" | "menu" | "mode" | "none" | "people" | "projects" | "queue" | "recipes" | "review" | "runs" | "settings" | "spend" | "system" | "tasks" | "work" | "workbench">;
274
+ export declare const SETTINGS_KEYS: Set<"activity" | "board" | "caps" | "chat" | "code" | "done" | "fleet" | "flows" | "inbox" | "ledger" | "menu" | "mode" | "none" | "people" | "projects" | "queue" | "recipes" | "review" | "runs" | "settings" | "spend" | "system" | "tasks" | "work" | "workbench">;
275
+ /** The builds screen's views (reduction pass §1): done, the review queue,
276
+ * and activity are ways of looking at builds, not destinations. */
277
+ export declare function buildsViews(current: "builds" | "done" | "review" | "activity"): Html;
278
+ export declare const CHEVRON_ICON: Html;
279
+ /** The drag grip: a 2rem touch-sized handle that owns its touches
280
+ * (touch-action: none), so a finger on it drags instead of scrolling. */
281
+ export declare const GRIP_HANDLE: Html;
282
+ /** Badges, labels and buttons read in sentence case, whatever word a record stores. */
283
+ export declare const sentenceCase: (word: string) => string;
284
+ /** Only an https github.com pull URL earns an anchor (audit IV-11) — a
285
+ * corrupted row renders as text, never as navigation. */
286
+ export declare function safePrUrl(url: string | null): string | null;
287
+ /** A shortened fingerprint for display — enough to compare by eye; the
288
+ * full value rides in the title attribute and in every form field. */
289
+ export declare function shortDigest(digest: string): Html;
290
+ /** One display line, bounded — turn text is data, never layout. */
291
+ export declare function oneLineOf(text: string, cap: number): string;