@shivaedev/work-board 0.15.0 → 0.17.0

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 (303) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +4 -4
  3. package/assets/react.css +1 -1
  4. package/assets/react.js +52 -39
  5. package/dist/browser/views/remaining.d.ts +0 -240
  6. package/dist/browser/views/remaining.d.ts.map +1 -1
  7. package/dist/browser/views/remaining.js +0 -2
  8. package/dist/browser/views/remaining.js.map +1 -1
  9. package/dist/client/document/Mermaid.d.ts.map +1 -1
  10. package/dist/client/document/Mermaid.js +4 -10
  11. package/dist/client/document/Mermaid.js.map +1 -1
  12. package/dist/client/document/View.js +1 -1
  13. package/dist/client/document/View.js.map +1 -1
  14. package/dist/client/react/BoardShell.d.ts.map +1 -1
  15. package/dist/client/react/BoardShell.js +28 -23
  16. package/dist/client/react/BoardShell.js.map +1 -1
  17. package/dist/client/react/DocumentAttention.d.ts.map +1 -1
  18. package/dist/client/react/DocumentAttention.js +2 -3
  19. package/dist/client/react/DocumentAttention.js.map +1 -1
  20. package/dist/client/react/DocumentContext.d.ts.map +1 -1
  21. package/dist/client/react/DocumentContext.js +6 -4
  22. package/dist/client/react/DocumentContext.js.map +1 -1
  23. package/dist/client/react/LiveControls.d.ts.map +1 -1
  24. package/dist/client/react/LiveControls.js +1 -6
  25. package/dist/client/react/LiveControls.js.map +1 -1
  26. package/dist/client/react/PhoneNavigation.d.ts +3 -1
  27. package/dist/client/react/PhoneNavigation.d.ts.map +1 -1
  28. package/dist/client/react/PhoneNavigation.js +8 -13
  29. package/dist/client/react/PhoneNavigation.js.map +1 -1
  30. package/dist/client/react/ProjectionFrame.js +1 -1
  31. package/dist/client/react/ProjectionFrame.js.map +1 -1
  32. package/dist/client/react/ReadingLibrary.d.ts.map +1 -1
  33. package/dist/client/react/ReadingLibrary.js +2 -6
  34. package/dist/client/react/ReadingLibrary.js.map +1 -1
  35. package/dist/client/react/ReadingReadyContext.d.ts +6 -0
  36. package/dist/client/react/ReadingReadyContext.d.ts.map +1 -0
  37. package/dist/client/react/ReadingReadyContext.js +7 -0
  38. package/dist/client/react/ReadingReadyContext.js.map +1 -0
  39. package/dist/client/react/RemainingMain.d.ts.map +1 -1
  40. package/dist/client/react/RemainingMain.js +0 -3
  41. package/dist/client/react/RemainingMain.js.map +1 -1
  42. package/dist/client/react/ResultPage.d.ts.map +1 -1
  43. package/dist/client/react/ResultPage.js +2 -1
  44. package/dist/client/react/ResultPage.js.map +1 -1
  45. package/dist/client/react/SessionContext.d.ts +3 -0
  46. package/dist/client/react/SessionContext.d.ts.map +1 -0
  47. package/dist/client/react/SessionContext.js +3 -0
  48. package/dist/client/react/SessionContext.js.map +1 -0
  49. package/dist/client/react/ShellApi.d.ts +0 -1
  50. package/dist/client/react/ShellApi.d.ts.map +1 -1
  51. package/dist/client/react/SystemMain.d.ts.map +1 -1
  52. package/dist/client/react/SystemMain.js +3 -1
  53. package/dist/client/react/SystemMain.js.map +1 -1
  54. package/dist/client/react/ThemeContext.d.ts +2 -0
  55. package/dist/client/react/ThemeContext.d.ts.map +1 -0
  56. package/dist/client/react/ThemeContext.js +3 -0
  57. package/dist/client/react/ThemeContext.js.map +1 -0
  58. package/dist/client/react/TodayOptions.d.ts.map +1 -1
  59. package/dist/client/react/TodayOptions.js +2 -2
  60. package/dist/client/react/TodayOptions.js.map +1 -1
  61. package/dist/client/react/entry.js +1 -1
  62. package/dist/client/react/entry.js.map +1 -1
  63. package/dist/client/react/loadBoardPage.d.ts.map +1 -1
  64. package/dist/client/react/loadBoardPage.js +5 -13
  65. package/dist/client/react/loadBoardPage.js.map +1 -1
  66. package/dist/client/react/loadRemaining.d.ts +124 -364
  67. package/dist/client/react/loadRemaining.d.ts.map +1 -1
  68. package/dist/client/react/loadRemaining.js +0 -2
  69. package/dist/client/react/loadRemaining.js.map +1 -1
  70. package/dist/client/react/navigationLocation.d.ts +2 -0
  71. package/dist/client/react/navigationLocation.d.ts.map +1 -1
  72. package/dist/client/react/navigationLocation.js +10 -0
  73. package/dist/client/react/navigationLocation.js.map +1 -1
  74. package/dist/client/react/pageQueries.d.ts.map +1 -1
  75. package/dist/client/react/pageQueries.js +0 -3
  76. package/dist/client/react/pageQueries.js.map +1 -1
  77. package/dist/client/react/readerLink.js +1 -1
  78. package/dist/client/react/readerLink.js.map +1 -1
  79. package/dist/client/react/remainingRoute.d.ts +1 -1
  80. package/dist/client/react/remainingRoute.d.ts.map +1 -1
  81. package/dist/client/react/remainingRoute.js +0 -2
  82. package/dist/client/react/remainingRoute.js.map +1 -1
  83. package/dist/client/react/scheduleReading.d.ts.map +1 -1
  84. package/dist/client/react/scheduleReading.js +1 -10
  85. package/dist/client/react/scheduleReading.js.map +1 -1
  86. package/dist/client/react/useAppearance.d.ts +2 -1
  87. package/dist/client/react/useAppearance.d.ts.map +1 -1
  88. package/dist/client/react/useAppearance.js +1 -2
  89. package/dist/client/react/useAppearance.js.map +1 -1
  90. package/dist/client/react/useBoardNavigation.d.ts +1 -1
  91. package/dist/client/react/useBoardNavigation.d.ts.map +1 -1
  92. package/dist/client/react/useBoardNavigation.js +13 -17
  93. package/dist/client/react/useBoardNavigation.js.map +1 -1
  94. package/dist/client/react/useDiagnosticsPolling.d.ts +4 -1
  95. package/dist/client/react/useDiagnosticsPolling.d.ts.map +1 -1
  96. package/dist/client/react/useDiagnosticsPolling.js +9 -7
  97. package/dist/client/react/useDiagnosticsPolling.js.map +1 -1
  98. package/dist/client/react/useSidebar.d.ts.map +1 -1
  99. package/dist/client/react/useSidebar.js +5 -3
  100. package/dist/client/react/useSidebar.js.map +1 -1
  101. package/dist/render/{failed.d.ts → Failed.d.ts} +1 -1
  102. package/dist/render/Failed.d.ts.map +1 -0
  103. package/dist/render/{failed.js → Failed.js} +1 -1
  104. package/dist/render/Failed.js.map +1 -0
  105. package/dist/render/code.d.ts +2 -2
  106. package/dist/render/code.d.ts.map +1 -1
  107. package/dist/render/code.js +15 -13
  108. package/dist/render/code.js.map +1 -1
  109. package/dist/render/footnoteIds.d.ts +3 -0
  110. package/dist/render/footnoteIds.d.ts.map +1 -0
  111. package/dist/render/{footnotes.js → footnoteIds.js} +11 -9
  112. package/dist/render/footnoteIds.js.map +1 -0
  113. package/dist/responses/url.js +1 -1
  114. package/dist/responses/url.js.map +1 -1
  115. package/dist/rpc/PageUrl.d.ts.map +1 -1
  116. package/dist/rpc/PageUrl.js +0 -1
  117. package/dist/rpc/PageUrl.js.map +1 -1
  118. package/dist/rpc/contract.d.ts +25 -748
  119. package/dist/rpc/contract.d.ts.map +1 -1
  120. package/dist/rpc/contract.js +6 -9
  121. package/dist/rpc/contract.js.map +1 -1
  122. package/dist/rpc/handoffContract.d.ts +33 -33
  123. package/dist/server/{responses/service.d.ts → Responses.d.ts} +9 -21
  124. package/dist/server/Responses.d.ts.map +1 -0
  125. package/dist/server/{responses/service.js → Responses.js} +22 -22
  126. package/dist/server/Responses.js.map +1 -0
  127. package/dist/server/attention/inbox.d.ts +2 -0
  128. package/dist/server/attention/inbox.d.ts.map +1 -1
  129. package/dist/server/attention/inbox.js +1 -0
  130. package/dist/server/attention/inbox.js.map +1 -1
  131. package/dist/server/attention/projection.js +1 -1
  132. package/dist/server/attention/projection.js.map +1 -1
  133. package/dist/server/attention/requestInbox.d.ts +3 -0
  134. package/dist/server/attention/requestInbox.d.ts.map +1 -1
  135. package/dist/server/attention/requestInbox.js +1 -0
  136. package/dist/server/attention/requestInbox.js.map +1 -1
  137. package/dist/server/board.d.ts +1 -1
  138. package/dist/server/boardRuntime.d.ts +2 -2
  139. package/dist/server/boardRuntime.d.ts.map +1 -1
  140. package/dist/server/boardRuntime.js +12 -16
  141. package/dist/server/boardRuntime.js.map +1 -1
  142. package/dist/server/boardServices.d.ts +3 -4
  143. package/dist/server/boardServices.d.ts.map +1 -1
  144. package/dist/server/boardServices.js +5 -4
  145. package/dist/server/boardServices.js.map +1 -1
  146. package/dist/server/boardSocket.d.ts +1 -1
  147. package/dist/server/boardSocket.d.ts.map +1 -1
  148. package/dist/server/document/read.d.ts +4 -10
  149. package/dist/server/document/read.d.ts.map +1 -1
  150. package/dist/server/document/read.js +5 -5
  151. package/dist/server/document/read.js.map +1 -1
  152. package/dist/server/document/requests.d.ts.map +1 -1
  153. package/dist/server/document/requests.js +1 -2
  154. package/dist/server/document/requests.js.map +1 -1
  155. package/dist/server/handoffs/Service.d.ts +1 -2
  156. package/dist/server/handoffs/Service.d.ts.map +1 -1
  157. package/dist/server/handoffs/Service.js +14 -13
  158. package/dist/server/handoffs/Service.js.map +1 -1
  159. package/dist/server/http/assets.d.ts +0 -3
  160. package/dist/server/http/assets.d.ts.map +1 -1
  161. package/dist/server/http/assets.js +1 -7
  162. package/dist/server/http/assets.js.map +1 -1
  163. package/dist/server/http/boardRoutes.d.ts.map +1 -1
  164. package/dist/server/http/boardRoutes.js +3 -3
  165. package/dist/server/http/boardRoutes.js.map +1 -1
  166. package/dist/server/integration/responses.d.ts +207 -4
  167. package/dist/server/integration/responses.d.ts.map +1 -1
  168. package/dist/server/integration/responses.js +4 -2
  169. package/dist/server/integration/responses.js.map +1 -1
  170. package/dist/server/mcp/client.d.ts +1060 -1300
  171. package/dist/server/mcp/client.d.ts.map +1 -1
  172. package/dist/server/mcp/queries.d.ts +24 -744
  173. package/dist/server/mcp/queries.d.ts.map +1 -1
  174. package/dist/server/mcp/queries.js +3 -3
  175. package/dist/server/mcp/queries.js.map +1 -1
  176. package/dist/server/packageInfo.d.ts +1 -1
  177. package/dist/server/packageInfo.js +1 -1
  178. package/dist/server/render/Highlighter.d.ts +1 -1
  179. package/dist/server/render/Highlighter.js +1 -1
  180. package/dist/server/render/markdown.d.ts +1 -1
  181. package/dist/server/render/markdown.js +2 -2
  182. package/dist/server/render/markdown.js.map +1 -1
  183. package/dist/server/responses/readingActions.d.ts +10 -1
  184. package/dist/server/responses/readingActions.d.ts.map +1 -1
  185. package/dist/server/responses/readingActions.js +2 -4
  186. package/dist/server/responses/readingActions.js.map +1 -1
  187. package/dist/server/responses/registerQuestion.d.ts +2 -2
  188. package/dist/server/responses/registerQuestion.d.ts.map +1 -1
  189. package/dist/server/responses/registerQuestion.js +3 -3
  190. package/dist/server/responses/registerQuestion.js.map +1 -1
  191. package/dist/server/responses/retry.d.ts +2 -2
  192. package/dist/server/responses/retry.d.ts.map +1 -1
  193. package/dist/server/responses/retry.js +1 -1
  194. package/dist/server/responses/retry.js.map +1 -1
  195. package/dist/server/rpc/HandlerOptions.d.ts +0 -8
  196. package/dist/server/rpc/HandlerOptions.d.ts.map +1 -1
  197. package/dist/server/rpc/handlers.d.ts +1 -1
  198. package/dist/server/rpc/handlers.d.ts.map +1 -1
  199. package/dist/server/rpc/handlers.js +14 -13
  200. package/dist/server/rpc/handlers.js.map +1 -1
  201. package/dist/server/rpc/hints.d.ts +3 -5
  202. package/dist/server/rpc/hints.d.ts.map +1 -1
  203. package/dist/server/rpc/hints.js +5 -1
  204. package/dist/server/rpc/hints.js.map +1 -1
  205. package/dist/server/serve.d.ts +1 -1
  206. package/dist/server/views/fleetItems.d.ts +2 -2
  207. package/dist/server/views/fleetItems.d.ts.map +1 -1
  208. package/dist/server/views/fleetItems.js +8 -3
  209. package/dist/server/views/fleetItems.js.map +1 -1
  210. package/dist/server/views/projectionQueries.d.ts +5 -9
  211. package/dist/server/views/projectionQueries.d.ts.map +1 -1
  212. package/dist/server/views/projectionQueries.js +6 -6
  213. package/dist/server/views/projectionQueries.js.map +1 -1
  214. package/dist/server/views/remainingQueries.d.ts +4 -252
  215. package/dist/server/views/remainingQueries.d.ts.map +1 -1
  216. package/dist/server/views/remainingQueries.js +11 -19
  217. package/dist/server/views/remainingQueries.js.map +1 -1
  218. package/dist/server/workspace.d.ts +222 -0
  219. package/dist/server/workspace.d.ts.map +1 -0
  220. package/dist/server/workspace.js +25 -0
  221. package/dist/server/workspace.js.map +1 -0
  222. package/package.json +6 -37
  223. package/src/browser/views/remaining.ts +0 -3
  224. package/src/client/document/Mermaid.ts +4 -10
  225. package/src/client/document/View.ts +1 -1
  226. package/src/client/react/BoardShell.tsx +37 -24
  227. package/src/client/react/DocumentAttention.tsx +2 -3
  228. package/src/client/react/DocumentContext.tsx +6 -4
  229. package/src/client/react/LiveControls.tsx +1 -14
  230. package/src/client/react/PhoneNavigation.tsx +20 -15
  231. package/src/client/react/ProjectionFrame.tsx +1 -1
  232. package/src/client/react/ReadingLibrary.tsx +2 -6
  233. package/src/client/react/ReadingReadyContext.ts +11 -0
  234. package/src/client/react/RemainingMain.tsx +0 -10
  235. package/src/client/react/ResultPage.tsx +2 -2
  236. package/src/client/react/SessionContext.ts +4 -0
  237. package/src/client/react/ShellApi.ts +0 -1
  238. package/src/client/react/SystemMain.tsx +3 -1
  239. package/src/client/react/ThemeContext.ts +3 -0
  240. package/src/client/react/TodayOptions.tsx +2 -2
  241. package/src/client/react/entry.tsx +1 -1
  242. package/src/client/react/loadBoardPage.ts +5 -14
  243. package/src/client/react/loadRemaining.ts +0 -2
  244. package/src/client/react/navigationLocation.ts +12 -0
  245. package/src/client/react/pageQueries.ts +0 -3
  246. package/src/client/react/readerLink.ts +1 -1
  247. package/src/client/react/remainingRoute.ts +0 -2
  248. package/src/client/react/scheduleReading.ts +1 -10
  249. package/src/client/react/useAppearance.ts +2 -3
  250. package/src/client/react/useBoardNavigation.ts +13 -18
  251. package/src/client/react/useDiagnosticsPolling.ts +14 -7
  252. package/src/client/react/useSidebar.ts +5 -3
  253. package/src/render/code.ts +3 -4
  254. package/src/render/{footnotes.ts → footnoteIds.ts} +12 -10
  255. package/src/responses/url.ts +1 -1
  256. package/src/rpc/PageUrl.ts +0 -1
  257. package/src/rpc/contract.ts +6 -9
  258. package/src/server/{responses/service.ts → Responses.ts} +21 -29
  259. package/src/server/attention/inbox.ts +1 -0
  260. package/src/server/attention/projection.ts +1 -1
  261. package/src/server/attention/requestInbox.ts +1 -0
  262. package/src/server/board.ts +1 -1
  263. package/src/server/boardRuntime.ts +20 -25
  264. package/src/server/boardServices.ts +7 -7
  265. package/src/server/document/read.ts +6 -14
  266. package/src/server/document/requests.ts +1 -2
  267. package/src/server/handoffs/Service.ts +16 -19
  268. package/src/server/http/assets.ts +1 -7
  269. package/src/server/http/boardRoutes.ts +3 -3
  270. package/src/server/integration/responses.ts +5 -3
  271. package/src/server/mcp/queries.ts +3 -3
  272. package/src/server/packageInfo.ts +1 -1
  273. package/src/server/render/Highlighter.ts +1 -1
  274. package/src/server/render/markdown.ts +2 -2
  275. package/src/server/responses/readingActions.ts +3 -3
  276. package/src/server/responses/registerQuestion.ts +5 -5
  277. package/src/server/responses/retry.ts +3 -3
  278. package/src/server/rpc/HandlerOptions.ts +0 -8
  279. package/src/server/rpc/handlers.ts +17 -15
  280. package/src/server/rpc/hints.ts +6 -3
  281. package/src/server/views/fleetItems.ts +8 -4
  282. package/src/server/views/projectionQueries.ts +6 -7
  283. package/src/server/views/remainingQueries.ts +11 -31
  284. package/src/server/workspace.ts +41 -0
  285. package/assets/native.js +0 -37
  286. package/dist/client/entry.d.ts +0 -3
  287. package/dist/client/entry.d.ts.map +0 -1
  288. package/dist/client/entry.js +0 -3
  289. package/dist/client/entry.js.map +0 -1
  290. package/dist/client/react/RespondPage.d.ts +0 -5
  291. package/dist/client/react/RespondPage.d.ts.map +0 -1
  292. package/dist/client/react/RespondPage.js +0 -5
  293. package/dist/client/react/RespondPage.js.map +0 -1
  294. package/dist/render/failed.d.ts.map +0 -1
  295. package/dist/render/failed.js.map +0 -1
  296. package/dist/render/footnotes.d.ts +0 -3
  297. package/dist/render/footnotes.d.ts.map +0 -1
  298. package/dist/render/footnotes.js.map +0 -1
  299. package/dist/server/responses/service.d.ts.map +0 -1
  300. package/dist/server/responses/service.js.map +0 -1
  301. package/src/client/entry.ts +0 -3
  302. package/src/client/react/RespondPage.tsx +0 -8
  303. /package/src/render/{failed.ts → Failed.ts} +0 -0
@@ -0,0 +1,222 @@
1
+ import { Context, Effect, FileSystem, Path, type PlatformError } from "effect";
2
+ import type { Changes } from "#server/files/changes.ts";
3
+ import type { Snapshot } from "#server/search/snapshot.ts";
4
+ export interface WorkspaceOptions {
5
+ readonly changes: Changes;
6
+ readonly home?: string | undefined;
7
+ readonly index: Effect.Effect<Snapshot, PlatformError.PlatformError>;
8
+ readonly root: string;
9
+ readonly writable: boolean;
10
+ }
11
+ export interface WorkspaceSettings extends Omit<WorkspaceOptions, "index"> {
12
+ readonly realRoot: string;
13
+ }
14
+ declare const WorkspaceConfig_base: Context.ServiceClass<WorkspaceConfig, "WorkBoard/WorkspaceConfig", WorkspaceOptions>;
15
+ export declare class WorkspaceConfig extends WorkspaceConfig_base {
16
+ }
17
+ export declare const Workspace: Context.Service<"WorkBoard/Workspace", Readonly<{
18
+ readonly document: (url: string) => Effect.Effect<{
19
+ readonly diagnostics: readonly {
20
+ readonly field?: string | undefined;
21
+ readonly line: number;
22
+ readonly message: string;
23
+ }[];
24
+ readonly file: string;
25
+ readonly identity?: string | undefined;
26
+ readonly links: {
27
+ readonly [x: string]: string;
28
+ };
29
+ readonly metadata: {
30
+ readonly areas?: readonly string[] | undefined;
31
+ readonly attention?: readonly {
32
+ readonly id: string;
33
+ readonly kind: "blocker" | "decision" | "review";
34
+ readonly managed?: boolean | undefined;
35
+ readonly reason: string;
36
+ readonly responseFrom: readonly string[];
37
+ readonly state: "closed" | "open";
38
+ readonly unblocks: readonly string[];
39
+ }[] | undefined;
40
+ readonly criteria?: readonly {
41
+ readonly id: string;
42
+ readonly text: string;
43
+ }[] | undefined;
44
+ readonly evidence?: readonly {
45
+ readonly checkedRevision?: string | undefined;
46
+ readonly criterion?: string | undefined;
47
+ readonly method?: string | undefined;
48
+ readonly observedAt?: string | undefined;
49
+ readonly outcome?: string | undefined;
50
+ readonly source: string;
51
+ }[] | undefined;
52
+ readonly handoff?: {
53
+ readonly by?: string | undefined;
54
+ readonly constraints: string;
55
+ readonly goal: string;
56
+ readonly item: string;
57
+ readonly nextAction: string;
58
+ readonly note?: string | undefined;
59
+ readonly preparedAt: number;
60
+ readonly recipient: string;
61
+ readonly reviewedRevision: string;
62
+ readonly source: string;
63
+ readonly state: "acknowledged" | "rejected" | "requested" | "unavailable";
64
+ } | undefined;
65
+ readonly id?: string | undefined;
66
+ readonly items?: readonly string[] | undefined;
67
+ readonly kind?: "board" | "decision" | "goal" | "handoff" | "investigation" | "project" | "question" | "report" | "response" | "result" | "task" | undefined;
68
+ readonly nextAction?: string | undefined;
69
+ readonly options?: readonly {
70
+ readonly description: string;
71
+ readonly label: string;
72
+ }[] | undefined;
73
+ readonly owner?: string | undefined;
74
+ readonly question?: {
75
+ readonly deadline: number;
76
+ readonly item: string;
77
+ readonly reason: string;
78
+ readonly registeredAt: number;
79
+ readonly request: string;
80
+ readonly reviewedRevision: string;
81
+ readonly source: string;
82
+ } | undefined;
83
+ readonly recommended?: string | undefined;
84
+ readonly relationships?: readonly {
85
+ readonly kind: "depends_on" | "implements" | "informs" | "relates_to";
86
+ readonly target: string;
87
+ }[] | undefined;
88
+ readonly requestReceipt?: {
89
+ readonly disposition: "applied" | "superseded";
90
+ readonly question: string;
91
+ readonly recordedAt: number;
92
+ readonly response?: string | undefined;
93
+ readonly reviewedRevision: string;
94
+ } | undefined;
95
+ readonly response?: {
96
+ readonly answers?: readonly {
97
+ readonly prompt: string;
98
+ readonly selected: readonly string[];
99
+ readonly text: string;
100
+ }[] | undefined;
101
+ readonly author: string;
102
+ readonly question: string;
103
+ readonly recordedAt: number;
104
+ readonly reviewedRevision: string;
105
+ readonly supersedes?: string | undefined;
106
+ readonly type: "answer" | "clarify" | "not_now";
107
+ } | undefined;
108
+ readonly status?: string | undefined;
109
+ };
110
+ readonly modified: number;
111
+ readonly questionActions: {
112
+ readonly [x: string]: string;
113
+ };
114
+ readonly reading?: {
115
+ readonly backlinks: readonly {
116
+ readonly href: string;
117
+ readonly kind: string;
118
+ readonly label: string;
119
+ readonly status?: string | undefined;
120
+ readonly title?: string | undefined;
121
+ }[];
122
+ readonly board: boolean;
123
+ readonly claims: {
124
+ readonly [x: string]: readonly {
125
+ readonly href?: string | undefined;
126
+ readonly label: string;
127
+ }[];
128
+ };
129
+ readonly evidenceSources: readonly {
130
+ readonly href?: string | undefined;
131
+ readonly problem: string;
132
+ }[];
133
+ readonly lines: {
134
+ readonly [x: string]: number;
135
+ };
136
+ readonly proseLine: number;
137
+ readonly raw?: string | undefined;
138
+ readonly receipts: {
139
+ readonly [x: string]: {
140
+ readonly disposition: "applied" | "superseded";
141
+ readonly question: string;
142
+ readonly recordedAt: number;
143
+ readonly response?: string | undefined;
144
+ readonly reviewedRevision: string;
145
+ };
146
+ };
147
+ } | undefined;
148
+ readonly referenceDetails?: {
149
+ readonly [x: string]: {
150
+ readonly status?: string | undefined;
151
+ readonly title: string;
152
+ };
153
+ } | undefined;
154
+ readonly references: {
155
+ readonly [x: string]: string;
156
+ };
157
+ readonly requests: readonly {
158
+ readonly id: string;
159
+ readonly open: boolean;
160
+ readonly options?: readonly {
161
+ readonly description: string;
162
+ readonly label: string;
163
+ }[] | undefined;
164
+ readonly preview?: {
165
+ readonly context: string;
166
+ readonly id: string;
167
+ readonly item: string;
168
+ readonly reason: string;
169
+ readonly request: string;
170
+ readonly reviewedRevision: string;
171
+ readonly source: string;
172
+ } | undefined;
173
+ readonly prompts?: readonly {
174
+ readonly id: string;
175
+ readonly mode: "many" | "one" | "text";
176
+ readonly options: readonly {
177
+ readonly id: string;
178
+ readonly source: string;
179
+ }[];
180
+ readonly source: string;
181
+ }[] | undefined;
182
+ readonly promptUnavailable?: string | undefined;
183
+ readonly recommended?: string | undefined;
184
+ readonly responses?: readonly {
185
+ readonly body: string;
186
+ readonly id: string;
187
+ readonly response: {
188
+ readonly answers?: readonly {
189
+ readonly prompt: string;
190
+ readonly selected: readonly string[];
191
+ readonly text: string;
192
+ }[] | undefined;
193
+ readonly author: string;
194
+ readonly question: string;
195
+ readonly recordedAt: number;
196
+ readonly reviewedRevision: string;
197
+ readonly supersedes?: string | undefined;
198
+ readonly type: "answer" | "clarify" | "not_now";
199
+ };
200
+ }[] | undefined;
201
+ readonly sourceOpen?: boolean | undefined;
202
+ readonly title?: string | undefined;
203
+ readonly unavailable?: string | undefined;
204
+ }[];
205
+ readonly source: string;
206
+ readonly unavailable: readonly string[];
207
+ readonly writable: boolean;
208
+ }, import("@shivaedev/platform/errors/taxonomy.ts").Conflict | import("@shivaedev/platform/errors/taxonomy.ts").NotFound | PlatformError.PlatformError | import("@shivaedev/platform/errors/taxonomy.ts").ServiceUnavailable, never>;
209
+ readonly index: () => Effect.Effect<Snapshot, PlatformError.PlatformError, never>;
210
+ readonly settings: () => Effect.Effect<{
211
+ changes: Changes;
212
+ home?: string | undefined;
213
+ root: string;
214
+ writable: boolean;
215
+ realRoot: string;
216
+ }, never, never>;
217
+ }>> & {
218
+ readonly layer: import("effect/Layer").Layer<"WorkBoard/Workspace", never, FileSystem.FileSystem | Path.Path | WorkspaceConfig>;
219
+ };
220
+ export type Workspace = typeof Workspace.Identifier;
221
+ export {};
222
+ //# sourceMappingURL=workspace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/server/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,KAAK,aAAa,EAAE,MAAM,QAAQ,CAAC;AAI/E,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACxD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,4BAA4B,CAAC;AAE3D,MAAM,WAAW,gBAAgB;IAChC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,aAAa,CAAC,aAAa,CAAC,CAAC;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAkB,SAAQ,IAAI,CAAC,gBAAgB,EAAE,OAAO,CAAC;IACzE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC1B;;AAED,qBAAa,eAAgB,SAAQ,oBAAiF;CAAG;AAEzH,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAbH,OAAO;eACT,MAAM,GAAG,SAAS;cAEnB,MAAM;kBACF,OAAO;;;;;CA2BzB,CAAC;AACH,MAAM,MAAM,SAAS,GAAG,OAAO,SAAS,CAAC,UAAU,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { Context, Effect, FileSystem, Path } from "effect";
2
+ import { defineService } from "@shivaedev/effect-service/define-service.ts";
3
+ import { readDocument } from "#server/document/read.ts";
4
+ export class WorkspaceConfig extends Context.Service()("WorkBoard/WorkspaceConfig") {
5
+ }
6
+ export const Workspace = defineService({
7
+ id: "WorkBoard/Workspace",
8
+ initialize: Effect.gen(function* () {
9
+ return yield* WorkspaceConfig;
10
+ }),
11
+ methods: ({ index, ...options }) => {
12
+ const settings = { ...options, realRoot: options.changes.realRoot };
13
+ const read = readDocument(settings);
14
+ function document(url) {
15
+ return Effect.flatMap(index, (snapshot) => read(url, snapshot));
16
+ }
17
+ return {
18
+ document,
19
+ index: () => index,
20
+ settings: () => Effect.succeed(settings),
21
+ };
22
+ },
23
+ requires: [WorkspaceConfig, FileSystem.FileSystem, Path.Path],
24
+ });
25
+ //# sourceMappingURL=workspace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/server/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAsB,MAAM,QAAQ,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAE5E,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAgBxD,MAAM,OAAO,eAAgB,SAAQ,OAAO,CAAC,OAAO,EAAqC,CAAC,2BAA2B,CAAC;CAAG;AAEzH,MAAM,CAAC,MAAM,SAAS,GAAG,aAAa,CAAC;IACtC,EAAE,EAAE,qBAAqB;IACzB,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC/B,OAAO,KAAK,CAAC,CAAC,eAAe,CAAC;IAC/B,CAAC,CAAC;IACF,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,OAAO,EAAE,EAAE,EAAE;QAClC,MAAM,QAAQ,GAAG,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QACpE,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QACpC,SAAS,QAAQ,CAAC,GAAW;YAC5B,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;QACjE,CAAC;QACD,OAAO;YACN,QAAQ;YACR,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK;YAClB,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;SACxC,CAAC;IACH,CAAC;IACD,QAAQ,EAAE,CAAC,eAAe,EAAE,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC;CAC7D,CAAC,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/work-board",
3
- "version": "0.15.0",
3
+ "version": "0.17.0",
4
4
  "description": "Serve a folder of markdown files as a live local page that updates in place when a file changes",
5
5
  "homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/work-board#readme",
6
6
  "bugs": {
@@ -77,13 +77,7 @@
77
77
  "default": "./dist/integration/metadata.js"
78
78
  },
79
79
  "./package.json": "./package.json",
80
- "./browser/react/*": null,
81
80
  "./browser/views/now.ts": null,
82
- "./browser/entry.ts": null,
83
- "./browser/fieldFeedback.ts": null,
84
- "./browser/reconcile/*": null,
85
- "./browser/legacyRuntime.ts": null,
86
- "./browser/session.ts": null,
87
81
  "./browser/handoffs/*": null,
88
82
  "./browser/responses/*": null,
89
83
  "./browser/handoffs/schema.ts": {
@@ -378,9 +372,7 @@
378
372
  "import": "./dist/client/document/*.js",
379
373
  "default": "./dist/client/document/*.js"
380
374
  },
381
- "./rpc/server.ts": null,
382
375
  "./rpc/HandlerOptions.ts": null,
383
- "./rpc/PageUrl.ts": null,
384
376
  "./http/boardRoutes.ts": null,
385
377
  "./http/rpcPolicy.ts": null,
386
378
  "./page/escape.ts": {
@@ -389,9 +381,6 @@
389
381
  "import": "./dist/browser/escapeHtml.js",
390
382
  "default": "./dist/browser/escapeHtml.js"
391
383
  },
392
- "./page/boardHtml.ts": null,
393
- "./page/documentHtml.ts": null,
394
- "./rpc/transport.ts": null,
395
384
  "./browser/document/layout.ts": null,
396
385
  "./browser/document/Details.ts": null,
397
386
  "./browser/document/ReadingContext.ts": {
@@ -400,28 +389,8 @@
400
389
  "import": "./dist/browser/document/ReadingContext.js",
401
390
  "default": "./dist/browser/document/ReadingContext.js"
402
391
  },
403
- "./diagnostics/script.ts": null,
404
- "./history/script.ts": null,
405
- "./page/sidebarScript.ts": null,
406
- "./page/searchResultsScript.ts": null,
407
- "./page/swap.ts": null,
408
- "./page/visualViewport.ts": null,
409
- "./page/stateScript.ts": null,
410
- "./page/searchScript.ts": null,
411
- "./page/visualScript.ts": null,
412
- "./page/itemContextScript.ts": null,
413
- "./page/libraryScript.ts": null,
414
- "./page/ageScript.ts": null,
415
- "./page/navigationScript.ts": null,
416
- "./page/readingStateScript.ts": null,
417
- "./page/formReadingScript.ts": null,
418
- "./page/diagrams.ts": null,
419
- "./page/client.ts": null,
420
- "./views/savedScript.ts": null,
421
392
  "./document/answerBody.ts": null,
422
- "./document/answerCardsHtml.ts": null,
423
- "./document/requestTitle.ts": null,
424
- "./browser/document/sourceGroups.ts": null
393
+ "./document/requestTitle.ts": null
425
394
  },
426
395
  "bin": {
427
396
  "work-board": "./dist/server/cli.js"
@@ -442,7 +411,7 @@
442
411
  "dependencies": {
443
412
  "@shivaedev/effect-contract": "0.5.1",
444
413
  "@shivaedev/effect-service": "0.3.0",
445
- "@shivaedev/platform": "0.14.2",
414
+ "@shivaedev/platform": "0.14.4",
446
415
  "mdast-util-directive": "3.1.1",
447
416
  "mermaid": "12.1.0",
448
417
  "react": "19.3.0",
@@ -465,9 +434,9 @@
465
434
  "@shivaedev/effect-react": "0.4.1",
466
435
  "@shivaedev/effect-test": "0.5.0",
467
436
  "@shivaedev/quality": "0.23.0",
468
- "@shivaedev/test-story": "0.5.0",
437
+ "@shivaedev/test-story": "0.6.0",
469
438
  "@tailwindcss/vite": "4.3.3",
470
- "@tanstack/react-router": "1.170.41",
439
+ "@tanstack/react-router": "1.170.42",
471
440
  "@types/hast": "3.0.5",
472
441
  "@types/mdast": "4.0.4",
473
442
  "@types/node": "24.19.2",
@@ -501,7 +470,7 @@
501
470
  },
502
471
  "scripts": {
503
472
  "build": "node --eval \"import('node:fs').then(({ rmSync }) => rmSync('dist', { force: true, recursive: true }))\" && tsc --project tsconfig.build.json && pnpm build:browser",
504
- "build:browser": "esbuild src/client/entry.ts --bundle --platform=browser --format=esm --conditions=source --minify --banner:js='/* @shivaedev/work-board native browser bundle */' --outfile=assets/native.js && esbuild src/server/responses/agent-cli.ts --bundle --platform=node --format=esm --conditions=source --minify --outfile=assets/agent.js && vite build",
473
+ "build:browser": "esbuild src/server/responses/agent-cli.ts --bundle --platform=node --format=esm --conditions=source --minify --outfile=assets/agent.js && vite build",
505
474
  "ready": "pnpm typecheck && pnpm test && pnpm build",
506
475
  "test": "pnpm test:prepare && vitest run",
507
476
  "test:prepare": "pnpm build:browser",
@@ -1,5 +1,4 @@
1
1
  import { Schema } from "effect";
2
- import { Document, DocumentRequest } from "#browser/document/schema.ts";
3
2
  import { HandoffPreview, HandoffReading } from "#browser/handoffs/schema.ts";
4
3
  import { DiagnosticsSnapshot } from "#diagnostics/daemonContract.ts";
5
4
 
@@ -11,8 +10,6 @@ export const StartProjection = Schema.Struct({
11
10
  templates: Schema.Array(Schema.Struct({ file: Schema.String, label: Schema.String, source: Schema.String })),
12
11
  });
13
12
  export type StartProjection = typeof StartProjection.Type;
14
- export const RespondProjection = Schema.Struct({ document: Document, request: DocumentRequest });
15
- export type RespondProjection = typeof RespondProjection.Type;
16
13
  export const HandoffProjection = Schema.Struct({
17
14
  background: Schema.String,
18
15
  goal: Schema.String,
@@ -1,4 +1,5 @@
1
- import { createElement, useCallback, useEffect, useId, useRef, useState } from "react";
1
+ import { createElement, useCallback, useContext, useEffect, useId, useRef, useState } from "react";
2
+ import { ThemeContext } from "#client/react/ThemeContext.ts";
2
3
  import { mermaidColor } from "./mermaidColor.ts";
3
4
 
4
5
  const drawings = new Map<string, { readonly source: string; readonly svg: string }>();
@@ -8,17 +9,10 @@ const MAX_DRAWINGS = 30;
8
9
  type Drawing = { readonly source: string; readonly svg: string } | { readonly source: string; readonly error: string };
9
10
 
10
11
  export function Mermaid({ source }: { readonly source: string }) {
12
+ const theme = useContext(ThemeContext);
11
13
  const id = useId().replace(/[^a-z\d_-]/giu, "");
12
- const [drawing, setDrawing] = useState<Drawing | undefined>(() => drawings.get(`${document.documentElement.dataset.scheme ?? "light"}:${source}`));
14
+ const [drawing, setDrawing] = useState<Drawing | undefined>(() => drawings.get(`${theme}:${source}`));
13
15
  const previousSourceRef = useRef(source);
14
- const [theme, setTheme] = useState(() => document.documentElement.dataset.scheme ?? "light");
15
- useEffect(() => {
16
- function sync() {
17
- setTheme(document.documentElement.dataset.scheme ?? "light");
18
- }
19
- document.addEventListener("board-theme", sync);
20
- return () => document.removeEventListener("board-theme", sync);
21
- }, []);
22
16
  useEffect(() => {
23
17
  if (previousSourceRef.current !== source) {
24
18
  for (const [key, value] of drawings) {
@@ -7,7 +7,7 @@ import { Age } from "#client/react/Age";
7
7
  import { documentHeadings } from "#render/documentHeadings.ts";
8
8
  import { documentLinks } from "#render/documentLinks.ts";
9
9
  import { documentPlugins } from "#render/documentPlugins.ts";
10
- import { footnoteIds } from "#render/footnotes.ts";
10
+ import { footnoteIds } from "#render/footnoteIds.ts";
11
11
  import { boardLayout } from "./boardLayout.ts";
12
12
  import { DetailStatesContext, DocumentDetails } from "./Details.ts";
13
13
  import { highlightDocument } from "./highlight.ts";
@@ -1,7 +1,7 @@
1
1
  import { useRouterState } from "@tanstack/react-router";
2
2
  import { Option } from "effect";
3
3
  import type * as AtomRegistry from "effect/reactivity/AtomRegistry";
4
- import { useEffect, useState } from "react";
4
+ import { useCallback, useContext, useEffect, useState } from "react";
5
5
  import { useQuery } from "@shivaedev/effect-react/result-state.ts";
6
6
  import type { BrowserClient } from "#client/client.ts";
7
7
  import { navigationQuery } from "#client/page/routeQuery.ts";
@@ -14,10 +14,13 @@ import { MainLocationContext, useMainLocation } from "./MainLocationContext.ts";
14
14
  import { emptyMainLocation, type MainLocation } from "./mainLocation.ts";
15
15
  import { PhoneNavigation } from "./PhoneNavigation.tsx";
16
16
  import { ReadingLibrary } from "./ReadingLibrary.tsx";
17
+ import { ReadingReadyContext, readingReady } from "./ReadingReadyContext.ts";
17
18
  import { SearchDialog } from "./SearchDialog.tsx";
19
+ import { SessionContext } from "./SessionContext.ts";
18
20
  import type { ShellApi } from "./ShellApi.ts";
19
21
  import { Sidebar } from "./Sidebar.tsx";
20
22
  import { shellIds } from "./shellIds.ts";
23
+ import { ThemeContext } from "./ThemeContext.ts";
21
24
  import { UpdatesToggle } from "./UpdatesToggle.tsx";
22
25
  import { useAppearance } from "./useAppearance.ts";
23
26
  import { useBoardNavigation } from "./useBoardNavigation.ts";
@@ -33,42 +36,52 @@ export interface ShellOptions {
33
36
  }
34
37
  export function BoardShell(options: ShellOptions) {
35
38
  const [main, onPage] = useState(emptyMainLocation);
39
+ const appearance = useAppearance();
40
+ const [element, setElement] = useState<HTMLElement | null>(null);
41
+ const report = useCallback((next: HTMLElement, ready: boolean) => {
42
+ setElement((current) => {
43
+ if (ready) {
44
+ return next;
45
+ }
46
+ return current === next ? null : current;
47
+ });
48
+ }, []);
36
49
  return (
37
50
  <MainLocationContext.Provider value={main}>
38
- <BoardWorkspace {...options} onPage={onPage} />
51
+ <ReadingReadyContext.Provider value={{ element, report }}>
52
+ <SessionContext.Provider value={options.client}>
53
+ <ThemeContext.Provider value={appearance.scheme}>
54
+ <BoardWorkspace {...options} appearance={appearance} onPage={onPage} />
55
+ </ThemeContext.Provider>
56
+ </SessionContext.Provider>
57
+ </ReadingReadyContext.Provider>
39
58
  </MainLocationContext.Provider>
40
59
  );
41
60
  }
42
- function BoardWorkspace(options: ShellOptions & { readonly onPage: (location: MainLocation) => void }) {
43
- const { api, ready, client, onPage } = options;
61
+ function BoardWorkspace(
62
+ options: ShellOptions & { readonly appearance: ReturnType<typeof useAppearance>; readonly onPage: (location: MainLocation) => void },
63
+ ) {
64
+ const { api, ready, client, onPage, appearance } = options;
44
65
  const main = useMainLocation();
45
- const appearance = useAppearance();
46
66
  const sidebar = useSidebar(appearance);
47
- const status = useBoardNavigation(options);
67
+ const [phoneOpen, setPhoneOpen] = useState(false);
68
+ const closeCurrentDestination = useCallback(() => {
69
+ sidebar.close();
70
+ setPhoneOpen(false);
71
+ }, [sidebar.close]);
72
+ const status = useBoardNavigation(options, closeCurrentDestination);
48
73
  const search = useSearchDialog();
49
74
  const [libraryOpen, setLibraryOpen] = useState(false);
50
75
  const location = useRouterState({ select: (state) => state.location });
51
76
  const query = useQuery(navigationQuery(api), { keepPreviousData: true });
52
77
  const data = Option.getOrUndefined(query.data);
78
+ const { element } = useContext(ReadingReadyContext);
53
79
  useEffect(() => {
54
- function start() {
55
- const doc = document.getElementById("doc");
56
- const context = doc?.querySelector<HTMLElement>(".item-context");
57
- if (data && main.route && (!context || context.dataset.readingReady === "true")) {
58
- ready?.();
59
- }
60
- }
61
- start();
62
- document.addEventListener("board-reading-ready", start);
63
- return () => {
64
- document.removeEventListener("board-reading-ready", start);
65
- };
66
- }, [ready, data, main]);
67
- useEffect(() => {
68
- if (data) {
69
- document.dispatchEvent(new Event("board-index-change"));
80
+ const doc = document.getElementById("doc");
81
+ if (data && main.route && doc && readingReady(doc, element)) {
82
+ ready?.();
70
83
  }
71
- }, [data]);
84
+ }, [ready, data, main, element]);
72
85
  const live = client ? (
73
86
  <LiveControls client={client} navigationFailed={Option.isSome(query.cause)} navigationPending={query.pending} />
74
87
  ) : (
@@ -109,7 +122,7 @@ function BoardWorkspace(options: ShellOptions & { readonly onPage: (location: Ma
109
122
  updates={client ? <UpdatesToggle client={client} /> : null}
110
123
  />
111
124
  <FleetMain api={api} home={data?.home} onPage={onPage} url={location.pathname + location.searchStr} />
112
- <PhoneNavigation main={main} openSearch={search.show} />
125
+ <PhoneNavigation main={main} more={phoneOpen} onMoreChange={setPhoneOpen} openSearch={search.show} />
113
126
  </div>
114
127
  </div>
115
128
  {Option.isSome(query.cause) && <p role="status">Navigation refresh failed. Your displayed files are retained.</p>}
@@ -1,5 +1,6 @@
1
1
  import type { Document } from "#browser/document/schema.ts";
2
2
  import { fileUrl } from "#files/url.ts";
3
+ import { responseUrl } from "#responses/url.ts";
3
4
  import { keyed } from "./keyed.ts";
4
5
  import { Reference } from "./Reference.tsx";
5
6
  export function DocumentAttention({ document }: { readonly document: Document }) {
@@ -28,9 +29,7 @@ function Request({ document, index }: { readonly document: Document; readonly in
28
29
  document.metadata.attention?.filter((entry) => entry.id === request.id).length === 1
29
30
  ? `attention-request-${request.id}`
30
31
  : `attention-record-${index}`;
31
- const respond = document.requests.some((entry) => entry.id === request.id && entry.open)
32
- ? `#answer-card-${request.id}`
33
- : `/_board/respond?item=${encodeURIComponent(document.metadata.id ?? "")}&request=${encodeURIComponent(request.id)}`;
32
+ const respond = responseUrl(document.metadata.id ?? "", request.id);
34
33
  const targets = request.unblocks.map((target, targetIndex) => (
35
34
  <span key={target}>
36
35
  {targetIndex > 0 && ", "}
@@ -1,13 +1,15 @@
1
- import { useEffect, useLayoutEffect, useRef, useState } from "react";
1
+ import { useContext, useEffect, useLayoutEffect, useRef, useState } from "react";
2
2
  import type { Document } from "#browser/document/schema.ts";
3
3
  import { Tabs } from "#client/react/components/ui/Tabs.tsx";
4
4
  import { Age } from "./Age.tsx";
5
5
  import { DocumentMetadata } from "./DocumentMetadata.tsx";
6
6
  import { DocumentSource } from "./DocumentSource.tsx";
7
7
  import { useMainLocation } from "./MainLocationContext.ts";
8
+ import { ReadingReadyContext } from "./ReadingReadyContext.ts";
8
9
 
9
10
  export function DocumentContext({ document: data }: { readonly document: Document }) {
10
11
  const page = useMainLocation();
12
+ const { report } = useContext(ReadingReadyContext);
11
13
  const [headings, setHeadings] = useState<readonly { readonly id: string; readonly title: string; readonly depth: number }[]>([]);
12
14
  const contextRef = useRef<HTMLElement>(null);
13
15
  const [tab, setTab] = useState("details");
@@ -42,9 +44,9 @@ export function DocumentContext({ document: data }: { readonly document: Documen
42
44
  if (count !== headings.length) {
43
45
  return;
44
46
  }
45
- context.dataset.readingReady = "true";
46
- document.dispatchEvent(new Event("board-reading-ready"));
47
- }, [headings]);
47
+ report(context, true);
48
+ return () => report(context, false);
49
+ }, [headings, report]);
48
50
  const tabs = [
49
51
  { content: <Outline headings={headings} />, label: "Details", value: "details" },
50
52
  { content: <SourcePanel document={data} />, label: "Source", value: "source" },
@@ -1,7 +1,7 @@
1
1
  import { useAtomValue } from "@effect/atom-react";
2
2
  import { Option } from "effect";
3
3
  import * as Atom from "effect/reactivity/Atom";
4
- import { useEffect, useMemo } from "react";
4
+ import { useMemo } from "react";
5
5
  import { useQuery } from "@shivaedev/effect-react/result-state.ts";
6
6
  import type { BrowserClient } from "#client/client.ts";
7
7
  import { activeRead } from "./activeRead.ts";
@@ -35,19 +35,6 @@ export function LiveControls({
35
35
  waiting: navigationPending || reading.pending,
36
36
  watching,
37
37
  });
38
- useEffect(
39
- () =>
40
- client.registry.subscribe(
41
- client.updates.paused,
42
- (value) => {
43
- if (!value) {
44
- document.dispatchEvent(new Event("board-updates-resumed"));
45
- }
46
- },
47
- { immediate: true },
48
- ),
49
- [client],
50
- );
51
38
  return (
52
39
  <span
53
40
  className="font-mono text-muted-foreground text-xs data-[state=down]:text-destructive data-[state=stale]:text-destructive"