@shivaedev/work-board 0.14.2 → 0.16.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 (279) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +1 -1
  3. package/assets/agent.js +1 -1
  4. package/assets/native.js +25 -25
  5. package/assets/react.css +1 -1
  6. package/assets/react.js +37 -36
  7. package/dist/browser/diagnostics/schema.d.ts +15 -12
  8. package/dist/browser/diagnostics/schema.d.ts.map +1 -1
  9. package/dist/browser/diagnostics/schema.js +12 -2
  10. package/dist/browser/diagnostics/schema.js.map +1 -1
  11. package/dist/browser/views/remaining.d.ts +20 -12
  12. package/dist/browser/views/remaining.d.ts.map +1 -1
  13. package/dist/client/client.d.ts +1 -0
  14. package/dist/client/client.d.ts.map +1 -1
  15. package/dist/client/client.js +1 -1
  16. package/dist/client/client.js.map +1 -1
  17. package/dist/client/document/Mermaid.d.ts.map +1 -1
  18. package/dist/client/document/Mermaid.js +4 -10
  19. package/dist/client/document/Mermaid.js.map +1 -1
  20. package/dist/client/document/View.js +1 -1
  21. package/dist/client/document/View.js.map +1 -1
  22. package/dist/client/formStatus.d.ts +12 -0
  23. package/dist/client/formStatus.d.ts.map +1 -0
  24. package/dist/client/formStatus.js +27 -0
  25. package/dist/client/formStatus.js.map +1 -0
  26. package/dist/client/react/BoardShell.d.ts.map +1 -1
  27. package/dist/client/react/BoardShell.js +36 -37
  28. package/dist/client/react/BoardShell.js.map +1 -1
  29. package/dist/client/react/DocumentContext.d.ts.map +1 -1
  30. package/dist/client/react/DocumentContext.js +12 -7
  31. package/dist/client/react/DocumentContext.js.map +1 -1
  32. package/dist/client/react/FormContext.d.ts +5 -0
  33. package/dist/client/react/FormContext.d.ts.map +1 -0
  34. package/dist/client/react/FormContext.js +10 -0
  35. package/dist/client/react/FormContext.js.map +1 -0
  36. package/dist/client/react/LiveControls.d.ts +4 -3
  37. package/dist/client/react/LiveControls.d.ts.map +1 -1
  38. package/dist/client/react/LiveControls.js +5 -24
  39. package/dist/client/react/LiveControls.js.map +1 -1
  40. package/dist/client/react/MainLocationContext.d.ts +3 -0
  41. package/dist/client/react/MainLocationContext.d.ts.map +1 -0
  42. package/dist/client/react/MainLocationContext.js +7 -0
  43. package/dist/client/react/MainLocationContext.js.map +1 -0
  44. package/dist/client/react/PhoneNavigation.d.ts +3 -1
  45. package/dist/client/react/PhoneNavigation.d.ts.map +1 -1
  46. package/dist/client/react/PhoneNavigation.js +8 -13
  47. package/dist/client/react/PhoneNavigation.js.map +1 -1
  48. package/dist/client/react/ProjectionFrame.d.ts +1 -2
  49. package/dist/client/react/ProjectionFrame.d.ts.map +1 -1
  50. package/dist/client/react/ProjectionFrame.js +10 -4
  51. package/dist/client/react/ProjectionFrame.js.map +1 -1
  52. package/dist/client/react/ReadingLibrary.d.ts.map +1 -1
  53. package/dist/client/react/ReadingLibrary.js +9 -14
  54. package/dist/client/react/ReadingLibrary.js.map +1 -1
  55. package/dist/client/react/ReadingReadyContext.d.ts +6 -0
  56. package/dist/client/react/ReadingReadyContext.d.ts.map +1 -0
  57. package/dist/client/react/ReadingReadyContext.js +7 -0
  58. package/dist/client/react/ReadingReadyContext.js.map +1 -0
  59. package/dist/client/react/SessionContext.d.ts +3 -0
  60. package/dist/client/react/SessionContext.d.ts.map +1 -0
  61. package/dist/client/react/SessionContext.js +3 -0
  62. package/dist/client/react/SessionContext.js.map +1 -0
  63. package/dist/client/react/SystemMain.d.ts.map +1 -1
  64. package/dist/client/react/SystemMain.js +3 -1
  65. package/dist/client/react/SystemMain.js.map +1 -1
  66. package/dist/client/react/SystemPage.d.ts.map +1 -1
  67. package/dist/client/react/SystemPage.js +2 -1
  68. package/dist/client/react/SystemPage.js.map +1 -1
  69. package/dist/client/react/ThemeContext.d.ts +2 -0
  70. package/dist/client/react/ThemeContext.d.ts.map +1 -0
  71. package/dist/client/react/ThemeContext.js +3 -0
  72. package/dist/client/react/ThemeContext.js.map +1 -0
  73. package/dist/client/react/TodayOptions.d.ts.map +1 -1
  74. package/dist/client/react/TodayOptions.js +23 -14
  75. package/dist/client/react/TodayOptions.js.map +1 -1
  76. package/dist/client/react/VisualViewer.d.ts.map +1 -1
  77. package/dist/client/react/VisualViewer.js +6 -5
  78. package/dist/client/react/VisualViewer.js.map +1 -1
  79. package/dist/client/react/boardRouter.d.ts +3 -2
  80. package/dist/client/react/boardRouter.d.ts.map +1 -1
  81. package/dist/client/react/boardRouter.js +2 -1
  82. package/dist/client/react/boardRouter.js.map +1 -1
  83. package/dist/client/react/createResponse.d.ts +32 -4
  84. package/dist/client/react/createResponse.d.ts.map +1 -1
  85. package/dist/client/react/createResponse.js +7 -28
  86. package/dist/client/react/createResponse.js.map +1 -1
  87. package/dist/client/react/diagnosticsValues.d.ts.map +1 -1
  88. package/dist/client/react/diagnosticsValues.js +5 -7
  89. package/dist/client/react/diagnosticsValues.js.map +1 -1
  90. package/dist/client/react/entry.d.ts.map +1 -1
  91. package/dist/client/react/entry.js +2 -34
  92. package/dist/client/react/entry.js.map +1 -1
  93. package/dist/client/react/githubLimited.d.ts +3 -0
  94. package/dist/client/react/githubLimited.d.ts.map +1 -0
  95. package/dist/client/react/githubLimited.js +4 -0
  96. package/dist/client/react/githubLimited.js.map +1 -0
  97. package/dist/client/react/loadProjection.d.ts +135 -135
  98. package/dist/client/react/loadRemaining.d.ts +20 -12
  99. package/dist/client/react/loadRemaining.d.ts.map +1 -1
  100. package/dist/client/react/mainLocation.d.ts +4 -2
  101. package/dist/client/react/mainLocation.d.ts.map +1 -1
  102. package/dist/client/react/mainLocation.js +1 -8
  103. package/dist/client/react/mainLocation.js.map +1 -1
  104. package/dist/client/react/mountBoard.d.ts +3 -0
  105. package/dist/client/react/mountBoard.d.ts.map +1 -0
  106. package/dist/client/react/mountBoard.js +45 -0
  107. package/dist/client/react/mountBoard.js.map +1 -0
  108. package/dist/client/react/navigationLocation.d.ts +3 -1
  109. package/dist/client/react/navigationLocation.d.ts.map +1 -1
  110. package/dist/client/react/navigationLocation.js +11 -1
  111. package/dist/client/react/navigationLocation.js.map +1 -1
  112. package/dist/client/react/retryPage.d.ts +2 -1
  113. package/dist/client/react/retryPage.d.ts.map +1 -1
  114. package/dist/client/react/retryPage.js +3 -4
  115. package/dist/client/react/retryPage.js.map +1 -1
  116. package/dist/client/react/scheduleReading.d.ts.map +1 -1
  117. package/dist/client/react/scheduleReading.js +1 -10
  118. package/dist/client/react/scheduleReading.js.map +1 -1
  119. package/dist/client/react/useAppearance.d.ts +2 -1
  120. package/dist/client/react/useAppearance.d.ts.map +1 -1
  121. package/dist/client/react/useAppearance.js +1 -2
  122. package/dist/client/react/useAppearance.js.map +1 -1
  123. package/dist/client/react/useBoardNavigation.d.ts +1 -1
  124. package/dist/client/react/useBoardNavigation.d.ts.map +1 -1
  125. package/dist/client/react/useBoardNavigation.js +28 -22
  126. package/dist/client/react/useBoardNavigation.js.map +1 -1
  127. package/dist/client/react/useDiagnosticsPolling.d.ts +4 -1
  128. package/dist/client/react/useDiagnosticsPolling.d.ts.map +1 -1
  129. package/dist/client/react/useDiagnosticsPolling.js +9 -7
  130. package/dist/client/react/useDiagnosticsPolling.js.map +1 -1
  131. package/dist/client/react/useDocumentPage.d.ts +1 -1
  132. package/dist/client/react/useDocumentPage.d.ts.map +1 -1
  133. package/dist/client/react/useDocumentPage.js +9 -6
  134. package/dist/client/react/useDocumentPage.js.map +1 -1
  135. package/dist/client/react/useHandoffForm.d.ts +56 -30
  136. package/dist/client/react/useHandoffForm.d.ts.map +1 -1
  137. package/dist/client/react/useHandoffForm.js +19 -30
  138. package/dist/client/react/useHandoffForm.js.map +1 -1
  139. package/dist/client/react/useResponseForm.d.ts +72 -43
  140. package/dist/client/react/useResponseForm.d.ts.map +1 -1
  141. package/dist/client/react/useResponseForm.js +20 -17
  142. package/dist/client/react/useResponseForm.js.map +1 -1
  143. package/dist/client/react/useSidebar.d.ts.map +1 -1
  144. package/dist/client/react/useSidebar.js +5 -3
  145. package/dist/client/react/useSidebar.js.map +1 -1
  146. package/dist/client/react/visualSources.d.ts.map +1 -1
  147. package/dist/client/react/visualSources.js +10 -8
  148. package/dist/client/react/visualSources.js.map +1 -1
  149. package/dist/client/saveFailure.d.ts +8 -0
  150. package/dist/client/saveFailure.d.ts.map +1 -0
  151. package/dist/client/saveFailure.js +8 -0
  152. package/dist/client/saveFailure.js.map +1 -0
  153. package/dist/diagnostics/daemonContract.d.ts +65 -38
  154. package/dist/diagnostics/daemonContract.d.ts.map +1 -1
  155. package/dist/diagnostics/daemonContract.js +2 -1
  156. package/dist/diagnostics/daemonContract.js.map +1 -1
  157. package/dist/diagnostics/health.d.ts +10 -0
  158. package/dist/diagnostics/health.d.ts.map +1 -1
  159. package/dist/diagnostics/health.js +2 -0
  160. package/dist/diagnostics/health.js.map +1 -1
  161. package/dist/diagnostics/source.d.ts +55 -36
  162. package/dist/diagnostics/source.d.ts.map +1 -1
  163. package/dist/diagnostics/source.js +1 -2
  164. package/dist/diagnostics/source.js.map +1 -1
  165. package/dist/render/{failed.d.ts → Failed.d.ts} +1 -1
  166. package/dist/render/Failed.d.ts.map +1 -0
  167. package/dist/render/{failed.js → Failed.js} +1 -1
  168. package/dist/render/Failed.js.map +1 -0
  169. package/dist/render/code.d.ts +2 -2
  170. package/dist/render/code.d.ts.map +1 -1
  171. package/dist/render/code.js +15 -13
  172. package/dist/render/code.js.map +1 -1
  173. package/dist/render/footnoteIds.d.ts +3 -0
  174. package/dist/render/footnoteIds.d.ts.map +1 -0
  175. package/dist/render/{footnotes.js → footnoteIds.js} +11 -9
  176. package/dist/render/footnoteIds.js.map +1 -0
  177. package/dist/rpc/contract.d.ts +2346 -2322
  178. package/dist/rpc/contract.d.ts.map +1 -1
  179. package/dist/rpc/handoffContract.d.ts +33 -33
  180. package/dist/rpc/responseContract.d.ts +56 -56
  181. package/dist/server/board.d.ts +1 -1
  182. package/dist/server/diagnostics/daemon.d.ts +41 -25
  183. package/dist/server/diagnostics/daemon.d.ts.map +1 -1
  184. package/dist/server/diagnostics/fleetHealth.d.ts +10 -0
  185. package/dist/server/diagnostics/fleetHealth.d.ts.map +1 -1
  186. package/dist/server/diagnostics/githubLimits.d.ts +12 -13
  187. package/dist/server/diagnostics/githubLimits.d.ts.map +1 -1
  188. package/dist/server/diagnostics/githubLimits.js +6 -6
  189. package/dist/server/diagnostics/githubLimits.js.map +1 -1
  190. package/dist/server/integration/diagnostics.d.ts +74 -38
  191. package/dist/server/integration/diagnostics.d.ts.map +1 -1
  192. package/dist/server/mcp/client.d.ts +1155 -1147
  193. package/dist/server/mcp/client.d.ts.map +1 -1
  194. package/dist/server/mcp/queries.d.ts +60 -36
  195. package/dist/server/mcp/queries.d.ts.map +1 -1
  196. package/dist/server/metadata/fields.js +1 -1
  197. package/dist/server/metadata/fields.js.map +1 -1
  198. package/dist/server/packageInfo.d.ts +1 -1
  199. package/dist/server/packageInfo.js +1 -1
  200. package/dist/server/render/Highlighter.d.ts +1 -1
  201. package/dist/server/render/Highlighter.js +1 -1
  202. package/dist/server/render/markdown.d.ts +1 -1
  203. package/dist/server/render/markdown.js +2 -2
  204. package/dist/server/render/markdown.js.map +1 -1
  205. package/dist/server/serve.d.ts +1 -1
  206. package/dist/server/views/remainingQueries.d.ts +20 -12
  207. package/dist/server/views/remainingQueries.d.ts.map +1 -1
  208. package/package.json +9 -39
  209. package/src/browser/diagnostics/schema.ts +12 -2
  210. package/src/client/client.ts +2 -1
  211. package/src/client/document/Mermaid.ts +4 -10
  212. package/src/client/document/View.ts +1 -1
  213. package/src/client/formStatus.ts +35 -0
  214. package/src/client/react/BoardShell.tsx +49 -43
  215. package/src/client/react/DocumentContext.tsx +12 -7
  216. package/src/client/react/FormContext.ts +13 -0
  217. package/src/client/react/LiveControls.tsx +5 -38
  218. package/src/client/react/MainLocationContext.ts +8 -0
  219. package/src/client/react/PhoneNavigation.tsx +20 -15
  220. package/src/client/react/ProjectionFrame.tsx +13 -5
  221. package/src/client/react/ReadingLibrary.tsx +9 -14
  222. package/src/client/react/ReadingReadyContext.ts +11 -0
  223. package/src/client/react/SessionContext.ts +4 -0
  224. package/src/client/react/SystemMain.tsx +3 -1
  225. package/src/client/react/SystemPage.tsx +2 -1
  226. package/src/client/react/ThemeContext.ts +3 -0
  227. package/src/client/react/TodayOptions.tsx +40 -33
  228. package/src/client/react/VisualViewer.tsx +6 -6
  229. package/src/client/react/boardRouter.ts +3 -2
  230. package/src/client/react/createResponse.ts +10 -35
  231. package/src/client/react/diagnosticsValues.tsx +20 -12
  232. package/src/client/react/entry.tsx +2 -37
  233. package/src/client/react/githubLimited.ts +5 -0
  234. package/src/client/react/mainLocation.ts +5 -8
  235. package/src/client/react/mountBoard.tsx +49 -0
  236. package/src/client/react/navigationLocation.ts +14 -2
  237. package/src/client/react/retryPage.ts +4 -4
  238. package/src/client/react/scheduleReading.ts +1 -10
  239. package/src/client/react/useAppearance.ts +2 -3
  240. package/src/client/react/useBoardNavigation.ts +30 -23
  241. package/src/client/react/useDiagnosticsPolling.ts +14 -7
  242. package/src/client/react/useDocumentPage.ts +12 -6
  243. package/src/client/react/useHandoffForm.ts +25 -33
  244. package/src/client/react/useResponseForm.ts +20 -18
  245. package/src/client/react/useSidebar.ts +5 -3
  246. package/src/client/react/visualSources.ts +10 -8
  247. package/src/client/saveFailure.ts +14 -0
  248. package/src/diagnostics/daemonContract.ts +2 -1
  249. package/src/diagnostics/health.ts +2 -0
  250. package/src/diagnostics/source.ts +1 -2
  251. package/src/render/code.ts +3 -4
  252. package/src/render/{footnotes.ts → footnoteIds.ts} +12 -10
  253. package/src/server/board.ts +1 -1
  254. package/src/server/diagnostics/githubLimits.ts +9 -11
  255. package/src/server/metadata/fields.ts +1 -1
  256. package/src/server/packageInfo.ts +1 -1
  257. package/src/server/render/Highlighter.ts +1 -1
  258. package/src/server/render/markdown.ts +2 -2
  259. package/dist/client/handoffs/failureStatus.d.ts +0 -2
  260. package/dist/client/handoffs/failureStatus.d.ts.map +0 -1
  261. package/dist/client/handoffs/failureStatus.js +0 -7
  262. package/dist/client/handoffs/failureStatus.js.map +0 -1
  263. package/dist/client/responses/failure.d.ts +0 -5
  264. package/dist/client/responses/failure.d.ts.map +0 -1
  265. package/dist/client/responses/failure.js +0 -13
  266. package/dist/client/responses/failure.js.map +0 -1
  267. package/dist/render/failed.d.ts.map +0 -1
  268. package/dist/render/failed.js.map +0 -1
  269. package/dist/render/footnotes.d.ts +0 -3
  270. package/dist/render/footnotes.d.ts.map +0 -1
  271. package/dist/render/footnotes.js.map +0 -1
  272. package/dist/server/diagnostics/readCommand.d.ts +0 -4
  273. package/dist/server/diagnostics/readCommand.d.ts.map +0 -1
  274. package/dist/server/diagnostics/readCommand.js +0 -20
  275. package/dist/server/diagnostics/readCommand.js.map +0 -1
  276. package/src/client/handoffs/failureStatus.ts +0 -6
  277. package/src/client/responses/failure.ts +0 -13
  278. package/src/server/diagnostics/readCommand.ts +0 -24
  279. /package/src/render/{failed.ts → Failed.ts} +0 -0
@@ -1,41 +1,20 @@
1
1
  import { useAtomRef } from "@effect/atom-react";
2
- import { Effect, Equal, Layer, Option, Schema } from "effect";
3
- import * as Atom from "effect/reactivity/Atom";
4
- import { useEffect, useRef, useState } from "react";
2
+ import { Equal, Option, Schema } from "effect";
3
+ import { useEffect, useState } from "react";
5
4
  import { useCreate } from "@shivaedev/effect-react/create.ts";
6
5
  import { HandoffInput, type HandoffPreview } from "#browser/handoffs/schema.ts";
7
6
  import type { HandoffProjection } from "#browser/views/remaining.ts";
8
- import { session } from "#client/entry.ts";
9
7
  import { formDraft } from "#client/formDraft.ts";
10
- import { failureStatus } from "#client/handoffs/failureStatus.ts";
8
+ import { type DraftInteraction, formStatus } from "#client/formStatus.ts";
11
9
  import { sourceChanged } from "#client/sourceChanged.ts";
12
-
13
- const runtime = Atom.runtime(Layer.empty);
10
+ import { useFormClient } from "./FormContext.ts";
14
11
  export function useHandoffForm(data: HandoffProjection, source: HandoffPreview) {
12
+ const client = useFormClient();
15
13
  const [preview, setPreview] = useState<HandoffInput>();
16
- const [status, setStatus] = useState("Draft ready. Review and preview before preparing the file.");
17
- const modelRef = useRef<HandoffInput | undefined>(undefined);
14
+ const [interaction, setInteraction] = useState<DraftInteraction>("draft");
18
15
  const draft = formDraft("handoff", source.item);
19
16
  const created = useCreate({
20
- create: (input) =>
21
- Effect.tryPromise({
22
- catch: (error) => error,
23
- try: async () => {
24
- const native = session(window);
25
- setStatus("Pending: preparing the local handoff file…");
26
- try {
27
- const saved = await native.mutate(native.handoffs.prepareHandoff.run(input));
28
- const newer = !Equal.equals(modelRef.current, input);
29
- setStatus(
30
- `Prepared: ${saved.file}. Receipt: ${saved.handoff.state}; execution and acceptance remain separate.${newer ? " Your newer draft remains unsaved." : ""}`,
31
- );
32
- return saved;
33
- } catch (error) {
34
- setStatus(failureStatus(error));
35
- throw error;
36
- }
37
- },
38
- }),
17
+ create: client.handoffs.prepareHandoff.run,
39
18
  fields: HandoffInput,
40
19
  initialValues: {
41
20
  constraints: "",
@@ -48,7 +27,8 @@ export function useHandoffForm(data: HandoffProjection, source: HandoffPreview)
48
27
  source: source.source,
49
28
  },
50
29
  persistedDraft: draft,
51
- runtime,
30
+ rejectField: () => undefined,
31
+ runtime: client.runtime,
52
32
  });
53
33
  const form = created.form;
54
34
  const values = useAtomRef(form.values);
@@ -59,7 +39,6 @@ export function useHandoffForm(data: HandoffProjection, source: HandoffPreview)
59
39
  form.change("source", created.created.value.handoff.source);
60
40
  }
61
41
  }, [form, created.dirty, created.created]);
62
- modelRef.current = values;
63
42
  const stale = Boolean(values.id) && (values.revision !== source.reviewedRevision || values.source !== source.source);
64
43
  function edit() {
65
44
  if (!form.values.value.id) {
@@ -68,7 +47,7 @@ export function useHandoffForm(data: HandoffProjection, source: HandoffPreview)
68
47
  }
69
48
  setPreview(undefined);
70
49
  if (!created.saving) {
71
- setStatus("Draft ready. Review and preview before preparing the file.");
50
+ setInteraction("draft");
72
51
  }
73
52
  }
74
53
  function showPreview() {
@@ -85,12 +64,25 @@ export function useHandoffForm(data: HandoffProjection, source: HandoffPreview)
85
64
  function clear() {
86
65
  created.revert();
87
66
  setPreview(undefined);
88
- setStatus("Draft cleared. Saved handoffs are unchanged.");
67
+ setInteraction("cleared");
89
68
  }
90
69
  const previewed = preview !== undefined && !stale && Equal.equals(preview, values);
70
+ const { text: status } = formStatus(
71
+ created,
72
+ interaction,
73
+ "handoff",
74
+ (saved) =>
75
+ `Prepared: ${saved.file}. Receipt: ${saved.handoff.state}; execution and acceptance remain separate.${created.dirty ? " Your newer draft remains unsaved." : ""}`,
76
+ );
91
77
  return {
92
78
  clear,
93
- created,
79
+ created: {
80
+ ...created,
81
+ save: () => {
82
+ setInteraction("submitted");
83
+ created.save();
84
+ },
85
+ },
94
86
  draft,
95
87
  edit,
96
88
  form,
@@ -1,11 +1,11 @@
1
1
  import { useAtomRef } from "@effect/atom-react";
2
- import { Equal, Layer, Option, Schema } from "effect";
3
- import * as Atom from "effect/reactivity/Atom";
4
- import { useEffect, useRef, useState } from "react";
2
+ import { Equal, Option, Schema } from "effect";
3
+ import { useEffect, useState } from "react";
5
4
  import { useCreate } from "@shivaedev/effect-react/create.ts";
6
5
  import type { Prompt } from "#browser/responses/Prompt.ts";
7
6
  import type { PromptAnswer, QuestionPreview } from "#browser/responses/schema.ts";
8
7
  import { formDraft } from "#client/formDraft.ts";
8
+ import { type DraftInteraction, formStatus, responseSaved } from "#client/formStatus.ts";
9
9
  import { answerRecovery, recoveryText } from "#client/responses/answerRecovery.ts";
10
10
  import { authorLabel } from "#client/responses/authorLabel.ts";
11
11
  import { type ResponseInput, responseFormSchema } from "#client/responses/formSchema.ts";
@@ -14,14 +14,13 @@ import { retainContext } from "#client/responses/retainContext.ts";
14
14
  import { responseFeedback, responseSummary } from "#client/responses/summary.ts";
15
15
  import { sourceChanged } from "#client/sourceChanged.ts";
16
16
  import { createResponse } from "./createResponse.ts";
17
-
18
- const runtime = Atom.runtime(Layer.empty);
17
+ import { useFormClient } from "./FormContext.ts";
19
18
 
20
19
  export function useResponseForm(source: QuestionPreview, prompts: readonly Prompt[]) {
20
+ const client = useFormClient();
21
21
  const schema = responseFormSchema(prompts.length > 0);
22
22
  const [preview, setPreview] = useState<ResponseInput>();
23
- const [outcome, setOutcome] = useState<string>();
24
- const [status, setStatus] = useState("");
23
+ const [interaction, setInteraction] = useState<DraftInteraction>("draft");
25
24
  const [attempted, setAttempted] = useState(false);
26
25
  const [label] = useState(() =>
27
26
  authorLabel(() => window.localStorage, typeof document === "undefined" ? undefined : document.documentElement.dataset.workspace),
@@ -39,13 +38,13 @@ export function useResponseForm(source: QuestionPreview, prompts: readonly Promp
39
38
  type: "answer",
40
39
  }));
41
40
  const draft = formDraft("response", source.item, source.request);
42
- const modelRef = useRef<ResponseInput | undefined>(undefined);
43
41
  const created = useCreate({
44
- create: (submission) => createResponse(source, submission, () => modelRef.current, setOutcome, setStatus),
42
+ create: (submission) => createResponse(client, source, submission),
45
43
  fields: schema,
46
44
  initialValues: initial,
47
45
  persistedDraft: draft,
48
- runtime,
46
+ rejectField: () => undefined,
47
+ runtime: client.runtime,
49
48
  });
50
49
  const form = created.form;
51
50
  const values = useAtomRef(form.values);
@@ -57,7 +56,6 @@ export function useResponseForm(source: QuestionPreview, prompts: readonly Promp
57
56
  }
58
57
  }
59
58
  }, [form, created.created, created.dirty, initial, label]);
60
- modelRef.current = values;
61
59
  const same = values.question === source.id && values.revision === source.reviewedRevision;
62
60
  const stale = Boolean(values.id) && !same;
63
61
  const recovery = answerRecovery(values, !stale || values.answerContext === JSON.stringify([source.id, source.reviewedRevision]));
@@ -86,7 +84,7 @@ export function useResponseForm(source: QuestionPreview, prompts: readonly Promp
86
84
  edit();
87
85
  }
88
86
  function showPreview() {
89
- setOutcome(undefined);
87
+ setInteraction("draft");
90
88
  if (!form.values.value.id || form.values.value.question !== source.id || form.values.value.revision !== source.reviewedRevision) {
91
89
  form.change("id", `response.${crypto.randomUUID()}`);
92
90
  }
@@ -98,7 +96,6 @@ export function useResponseForm(source: QuestionPreview, prompts: readonly Promp
98
96
  form.blur(name);
99
97
  }
100
98
  setPreview(form.values.value);
101
- setStatus("");
102
99
  }
103
100
  function edit() {
104
101
  if (!form.values.value.id) {
@@ -109,18 +106,17 @@ export function useResponseForm(source: QuestionPreview, prompts: readonly Promp
109
106
  label.save(form.values.value.author);
110
107
  setPreview(undefined);
111
108
  if (!created.saving) {
112
- setOutcome(undefined);
113
- setStatus("");
109
+ setInteraction("draft");
114
110
  }
115
111
  }
116
112
  function clear() {
117
113
  setAttempted(false);
118
- setOutcome(undefined);
119
114
  created.revert();
120
115
  setPreview(undefined);
121
- setStatus("Draft cleared. Saved responses are unchanged.");
116
+ setInteraction("cleared");
122
117
  }
123
118
  const previewed = preview !== undefined && same && Equal.equals(preview, values);
119
+ const { outcome, text: status } = formStatus(created, interaction, "response", (saved) => responseSaved(saved.id, created.dirty));
124
120
  const summary = responseSummary(values, prompts, answers(values), attempted);
125
121
  return {
126
122
  answers: answers(values),
@@ -131,7 +127,13 @@ export function useResponseForm(source: QuestionPreview, prompts: readonly Promp
131
127
  },
132
128
  attempted,
133
129
  clear,
134
- created,
130
+ created: {
131
+ ...created,
132
+ save: () => {
133
+ setInteraction("submitted");
134
+ created.save();
135
+ },
136
+ },
135
137
  draft,
136
138
  edit,
137
139
  editAnswers,
@@ -1,8 +1,10 @@
1
+ import { useRouter } from "@tanstack/react-router";
1
2
  import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
2
3
  import type { AppearanceControls } from "./useAppearance.ts";
3
4
  import { useMedia } from "./useMedia.ts";
4
5
 
5
6
  export function useSidebar(appearance: AppearanceControls) {
7
+ const router = useRouter();
6
8
  const narrow = useMedia("(max-width: 767px)");
7
9
  const [drawer, setDrawer] = useState(false);
8
10
  const open = narrow ? drawer : !appearance.closed;
@@ -55,12 +57,12 @@ export function useSidebar(appearance: AppearanceControls) {
55
57
  trapTab(event);
56
58
  }
57
59
  document.addEventListener("keydown", key);
58
- document.addEventListener("board-navigate", close);
60
+ const unsubscribe = router.subscribe("onBeforeNavigate", close);
59
61
  return () => {
60
62
  document.removeEventListener("keydown", key);
61
- document.removeEventListener("board-navigate", close);
63
+ unsubscribe();
62
64
  };
63
- }, [narrow, open, close]);
65
+ }, [narrow, open, close, router]);
64
66
  return { close, narrow, open, toggle };
65
67
  }
66
68
  export type SidebarControls = ReturnType<typeof useSidebar>;
@@ -1,5 +1,6 @@
1
1
  import { Clock, Effect } from "effect";
2
- import { useEffect } from "react";
2
+ import { useEffect, useRef } from "react";
3
+ import { useMainLocation } from "./MainLocationContext.ts";
3
4
 
4
5
  export interface VisualSource {
5
6
  readonly alt: string;
@@ -13,16 +14,17 @@ export interface VisualSelection {
13
14
  readonly selected: number;
14
15
  }
15
16
  export function useVisualSources(inspect: (selection: VisualSelection) => void) {
17
+ const page = useMainLocation();
18
+ const revisionRef = useRef(0);
16
19
  useEffect(() => {
17
- let revision = 0;
18
20
  function refresh() {
19
- revision += 1;
21
+ revisionRef.current += 1;
20
22
  for (const graphic of document.querySelectorAll<HTMLImageElement>("#doc img[data-local-image]")) {
21
23
  graphic.tabIndex = 0;
22
24
  graphic.setAttribute("role", "button");
23
25
  graphic.setAttribute("aria-label", `Inspect image: ${graphic.alt || "Local image"}`);
24
26
  const url = new URL(graphic.dataset.localImage ?? graphic.src, location.href);
25
- url.searchParams.set("_wb", `${Effect.runSync(Clock.currentTimeMillis)}-${revision}`);
27
+ url.searchParams.set("_wb", `${Effect.runSync(Clock.currentTimeMillis)}-${revisionRef.current}`);
26
28
  graphic.src = url.href;
27
29
  graphic.onerror = () => {
28
30
  if (!graphic.isConnected || graphic.nextElementSibling?.hasAttribute("data-image-error")) {
@@ -94,12 +96,12 @@ export function useVisualSources(inspect: (selection: VisualSelection) => void)
94
96
  }
95
97
  document.addEventListener("click", click);
96
98
  document.addEventListener("keydown", key);
97
- document.addEventListener("board-page", refresh);
98
- refresh();
99
+ if (page.route) {
100
+ refresh();
101
+ }
99
102
  return () => {
100
103
  document.removeEventListener("click", click);
101
104
  document.removeEventListener("keydown", key);
102
- document.removeEventListener("board-page", refresh);
103
105
  };
104
- }, [inspect]);
106
+ }, [inspect, page]);
105
107
  }
@@ -0,0 +1,14 @@
1
+ import type { RpcClientError } from "effect/rpc/RpcClientError";
2
+ import type { ResponseRejection } from "#rpc/rejections.ts";
3
+
4
+ export type SaveFailure = ResponseRejection | RpcClientError;
5
+
6
+ export function saveFailure(error: SaveFailure, kind: "response" | "handoff") {
7
+ const outcome =
8
+ error._tag === "PublicationUncertain" || error._tag === "InternalServerError" || error._tag === "RpcClientError" ? "uncertain" : "rejected";
9
+ const retained =
10
+ kind === "response"
11
+ ? "Draft retained. Preview and retry with the same identity; saved content will be reconciled."
12
+ : "Draft retained; preview and retry.";
13
+ return { outcome, text: `${outcome === "rejected" ? "Rejected" : "Uncertain"}: ${String(error)}. ${retained}` };
14
+ }
@@ -1,6 +1,7 @@
1
1
  import { Schema } from "effect";
2
2
  import { contract } from "@shivaedev/effect-contract/contract.ts";
3
3
  import { query } from "@shivaedev/effect-contract/operation.ts";
4
+ import { ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
4
5
  import { CodexLimits, GithubLimits } from "#browser/diagnostics/schema.ts";
5
6
  import { FleetItems } from "./fleetItems.ts";
6
7
  import { FleetHealth } from "./health.ts";
@@ -24,7 +25,7 @@ export type DiagnosticsSnapshot = typeof DiagnosticsSnapshot.Type;
24
25
  export const DiagnosticsContract = contract("daemon", {
25
26
  queries: [
26
27
  query("diagnostics", { payload: {}, reads: () => [], success: DiagnosticsSnapshot }),
27
- query("fleetItems", { payload: {}, reads: () => [], success: FleetItems }),
28
+ query("fleetItems", { payload: {}, reads: () => [], rejections: { ServiceUnavailable }, success: FleetItems }),
28
29
  ],
29
30
  });
30
31
  export const DAEMON_RPC_PATH = "/_fleet/rpc";
@@ -1,4 +1,5 @@
1
1
  import { Schema } from "effect";
2
+ import { GithubLimits } from "#browser/diagnostics/schema.ts";
2
3
 
3
4
  const Count = Schema.Int.check(Schema.isGreaterThanOrEqualTo(0));
4
5
  const Timestamp = Schema.Number.check(Schema.isFinite(), Schema.isGreaterThanOrEqualTo(0), Schema.isLessThanOrEqualTo(8_640_000_000_000_000));
@@ -9,6 +10,7 @@ export const FLEET_HEALTH_NAME = "health.json";
9
10
  export const FLEET_HEALTH_FILE = `fleet/${FLEET_HEALTH_NAME}`;
10
11
  export const FleetHealth = Schema.Struct({
11
12
  concurrency: Schema.Int.check(Schema.isGreaterThan(0)),
13
+ github: Schema.optional(GithubLimits),
12
14
  lastCapacityRejection: Schema.NullOr(CapacityRejection),
13
15
  lastSchedulerPass: Schema.NullOr(Timestamp),
14
16
  observedAt: Timestamp,
@@ -33,10 +33,9 @@ export const observe = Effect.fn("WorkBoard.observe")(function* <A>(source: Sour
33
33
 
34
34
  export const diagnostics = Effect.fn("WorkBoard.diagnostics")(function* (sources: Sources) {
35
35
  const codex = yield* Effect.cachedWithTTL(observe(sources.codex), "1 minute");
36
- const github = yield* Effect.cachedWithTTL(observe(sources.github), "1 minute");
37
36
  // A bounded shared read must finish caching even if its first tab leaves.
38
37
  return Effect.all(
39
- { codex: Effect.uninterruptible(codex), fleet: observe(sources.fleet), github: Effect.uninterruptible(github) },
38
+ { codex: Effect.uninterruptible(codex), fleet: observe(sources.fleet), github: observe(sources.github) },
40
39
  { concurrency: "unbounded" },
41
40
  );
42
41
  });
@@ -50,10 +50,8 @@ async function renderedCode(highlighter: Shiki, pre: Element, diagrams: boolean)
50
50
  return language === undefined ? undefined : await highlighted(highlighter, source, language);
51
51
  }
52
52
 
53
- export const codeBlocks =
54
- (highlighter: Shiki, { diagrams = true }: { readonly diagrams?: boolean } = {}) =>
55
- () =>
56
- async (tree: Root) => {
53
+ export function codeBlocks(highlighter: Shiki, { diagrams = true }: { readonly diagrams?: boolean } = {}) {
54
+ return () => async (tree: Root) => {
57
55
  const work: Promise<void>[] = [];
58
56
  visitElements(tree, "element", (pre, index, parent) => {
59
57
  if (pre.tagName !== "pre" || index === undefined || parent === undefined) {
@@ -69,3 +67,4 @@ export const codeBlocks =
69
67
  });
70
68
  await Promise.all(work);
71
69
  };
70
+ }
@@ -17,13 +17,15 @@ function scoped(prefix: string, value: Value): Value {
17
17
  return Array.isArray(value) ? value.map((each) => (typeof each === "string" ? String(scoped(prefix, each)) : each)) : value;
18
18
  }
19
19
 
20
- export const footnoteIds = (prefix: string) => () => (tree: Root) => {
21
- visitElements(tree, "element", (element) => {
22
- if (!["a", "h2", "li"].includes(element.tagName)) {
23
- return;
24
- }
25
- element.properties = Object.fromEntries(
26
- Object.entries(element.properties).map(([name, value]) => [name, SCOPED.has(name) ? scoped(prefix, value) : value]),
27
- );
28
- });
29
- };
20
+ export function footnoteIds(prefix: string) {
21
+ return () => (tree: Root) => {
22
+ visitElements(tree, "element", (element) => {
23
+ if (!["a", "h2", "li"].includes(element.tagName)) {
24
+ return;
25
+ }
26
+ element.properties = Object.fromEntries(
27
+ Object.entries(element.properties).map(([name, value]) => [name, SCOPED.has(name) ? scoped(prefix, value) : value]),
28
+ );
29
+ });
30
+ };
31
+ }
@@ -3,7 +3,7 @@ import { HttpRouter } from "effect/http";
3
3
  import { RpcSerialization, RpcServer } from "effect/rpc";
4
4
  import type { InternalServerError } from "@shivaedev/platform/errors/taxonomy.ts";
5
5
  import { localRpcGuard } from "@shivaedev/platform/rpc-server/local.ts";
6
- import type { RenderFailed } from "#render/failed.ts";
6
+ import type { RenderFailed } from "#render/Failed.ts";
7
7
  import { workRpcs } from "#rpc/contract.ts";
8
8
  import { boardRuntime } from "#server/boardRuntime.ts";
9
9
  import type { HomeMissing } from "#server/files/home.ts";
@@ -1,15 +1,13 @@
1
- import { Effect, Schema } from "effect";
2
- import { GithubLimits, SourceFailure } from "#diagnostics/source.ts";
3
- import { readCommand } from "./readCommand.ts";
1
+ import { Effect } from "effect";
2
+ import type { FleetHealth } from "#diagnostics/health.ts";
3
+ import { type Source, SourceFailure } from "#diagnostics/source.ts";
4
4
 
5
- const Response = Schema.Struct({ resources: GithubLimits });
6
-
7
- export function githubLimits(read = readCommand("gh", ["api", "rate_limit"])) {
8
- return read.pipe(
9
- Effect.flatMap(Schema.decodeUnknownEffect(Schema.fromJsonString(Response))),
10
- Effect.map(({ resources }) => resources),
11
- Effect.mapError((error) =>
12
- error instanceof SourceFailure ? error : new SourceFailure({ kind: "error", message: "GitHub returned invalid rate limits" }),
5
+ export function githubLimits(fleet: Source<FleetHealth>) {
6
+ return fleet.pipe(
7
+ Effect.flatMap(({ github }) =>
8
+ github === undefined || github.length === 0
9
+ ? Effect.fail(new SourceFailure({ kind: "not-configured", message: "Fleet has not recorded a GitHub response yet" }))
10
+ : Effect.succeed(github),
13
11
  ),
14
12
  );
15
13
  }
@@ -3,7 +3,7 @@ import { Metadata } from "#metadata/schema.ts";
3
3
  import type { Diagnostic } from "./parse.ts";
4
4
 
5
5
  const addonOwners: Readonly<Record<string, readonly string[]>> = {
6
- fleet: ["fleet", "fleet-launch", "fleet-deliverable"],
6
+ fleet: ["fleet", "fleet-launch", "fleet-deliverable", "fleet-priority"],
7
7
  };
8
8
  const addonFields = new Set(Object.values(addonOwners).flat());
9
9
  const schemas: ReadonlyMap<string, Schema.ConstraintDecoder<unknown, never>> = new Map(Object.entries(Metadata.to.fields));
@@ -1,2 +1,2 @@
1
1
  export const NAME = "work-board";
2
- export const VERSION = "0.14.2";
2
+ export const VERSION = "0.16.0";
@@ -2,7 +2,7 @@ import { Effect } from "effect";
2
2
  import { createHighlighter } from "shiki";
3
3
  import { defineService } from "@shivaedev/effect-service/define-service.ts";
4
4
  import { codeBlocks, THEMES } from "#render/code.ts";
5
- import { RenderFailed } from "#render/failed.ts";
5
+ import { RenderFailed } from "#render/Failed.ts";
6
6
 
7
7
  export const Highlighter = defineService({
8
8
  id: "WorkBoard/Highlighter",
@@ -7,8 +7,8 @@ import type { PluggableList } from "unified";
7
7
  import type { documentHeadings } from "#render/documentHeadings.ts";
8
8
  import { documentLinks } from "#render/documentLinks.ts";
9
9
  import { documentPlugins } from "#render/documentPlugins.ts";
10
- import { RenderFailed } from "#render/failed.ts";
11
- import { footnoteIds } from "#render/footnotes.ts";
10
+ import { RenderFailed } from "#render/Failed.ts";
11
+ import { footnoteIds } from "#render/footnoteIds.ts";
12
12
  import { Highlighter } from "./Highlighter.ts";
13
13
 
14
14
  export interface RenderOptions {
@@ -1,2 +0,0 @@
1
- export declare function failureStatus(error: unknown): string;
2
- //# sourceMappingURL=failureStatus.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"failureStatus.d.ts","sourceRoot":"","sources":["../../../src/client/handoffs/failureStatus.ts"],"names":[],"mappings":"AAGA,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,UAE3C"}
@@ -1,7 +0,0 @@
1
- import { Schema } from "effect";
2
- import { InternalServerError } from "@shivaedev/platform/errors/taxonomy.ts";
3
- import { PublicationUncertain, ResponseRejection } from "#rpc/rejections.ts";
4
- export function failureStatus(error) {
5
- return `${Schema.is(ResponseRejection)(error) && !(error instanceof PublicationUncertain) && !(error instanceof InternalServerError) ? "Rejected" : "Uncertain"}: ${String(error)}. Draft retained; preview and retry.`;
6
- }
7
- //# sourceMappingURL=failureStatus.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"failureStatus.js","sourceRoot":"","sources":["../../../src/client/handoffs/failureStatus.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,MAAM,UAAU,aAAa,CAAC,KAAc;IAC3C,OAAO,GAAG,MAAM,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,YAAY,oBAAoB,CAAC,IAAI,CAAC,CAAC,KAAK,YAAY,mBAAmB,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,KAAK,MAAM,CAAC,KAAK,CAAC,sCAAsC,CAAC;AACzN,CAAC"}
@@ -1,5 +0,0 @@
1
- export declare function responseFailure(error: unknown): {
2
- outcome: string;
3
- text: string;
4
- };
5
- //# sourceMappingURL=failure.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"failure.d.ts","sourceRoot":"","sources":["../../../src/client/responses/failure.ts"],"names":[],"mappings":"AAGA,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO;;;EAS7C"}
@@ -1,13 +0,0 @@
1
- import { Schema } from "effect";
2
- import { InternalServerError } from "@shivaedev/platform/errors/taxonomy.ts";
3
- import { PublicationUncertain, ResponseRejection } from "#rpc/rejections.ts";
4
- export function responseFailure(error) {
5
- const outcome = Schema.is(ResponseRejection)(error) && !(error instanceof PublicationUncertain) && !(error instanceof InternalServerError)
6
- ? "rejected"
7
- : "uncertain";
8
- return {
9
- outcome,
10
- text: `${outcome === "rejected" ? "Rejected" : "Uncertain"}: ${String(error)}. Draft retained. Preview and retry with the same identity; saved content will be reconciled.`,
11
- };
12
- }
13
- //# sourceMappingURL=failure.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"failure.js","sourceRoot":"","sources":["../../../src/client/responses/failure.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,mBAAmB,EAAE,MAAM,wCAAwC,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,MAAM,UAAU,eAAe,CAAC,KAAc;IAC7C,MAAM,OAAO,GACZ,MAAM,CAAC,EAAE,CAAC,iBAAiB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,KAAK,YAAY,oBAAoB,CAAC,IAAI,CAAC,CAAC,KAAK,YAAY,mBAAmB,CAAC;QACzH,CAAC,CAAC,UAAU;QACZ,CAAC,CAAC,WAAW,CAAC;IAChB,OAAO;QACN,OAAO;QACP,IAAI,EAAE,GAAG,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,KAAK,MAAM,CAAC,KAAK,CAAC,+FAA+F;KAC3K,CAAC;AACH,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"failed.d.ts","sourceRoot":"","sources":["../../src/render/failed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;;;;AAEhC,qBAAa,YAAa,SAAQ,iBAA6E;IAC9G,IAAa,OAAO,WAEnB;CACD"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"failed.js","sourceRoot":"","sources":["../../src/render/failed.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAEhC,MAAM,OAAO,YAAa,SAAQ,MAAM,CAAC,WAAW,EAAgB,CAAC,cAAc,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;IAC9G,IAAa,OAAO;QACnB,OAAO,uHAAuH,CAAC;IAChI,CAAC;CACD"}
@@ -1,3 +0,0 @@
1
- import type { Root } from "hast";
2
- export declare const footnoteIds: (prefix: string) => () => (tree: Root) => void;
3
- //# sourceMappingURL=footnotes.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"footnotes.d.ts","sourceRoot":"","sources":["../../src/render/footnotes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAW,IAAI,EAAE,MAAM,MAAM,CAAC;AAmB1C,eAAO,MAAM,WAAW,WAAY,MAAM,kBAAkB,IAAI,SAS/D,CAAC"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"footnotes.js","sourceRoot":"","sources":["../../src/render/footnotes.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,IAAI,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAE1D,MAAM,YAAY,GAAG,sCAAsC,CAAC;AAI5D,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC;AAE1D,SAAS,MAAM,CAAC,MAAc,EAAE,KAAY;IAC3C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3D,OAAO,GAAG,MAAM,GAAG,KAAK,EAAE,CAAC;IAC5B,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7F,OAAO,IAAI,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;IACtC,CAAC;IACD,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AAC7H,CAAC;AAED,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,MAAc,EAAE,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC,IAAU,EAAE,EAAE;IACnE,aAAa,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE;QAC1C,IAAI,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAClD,OAAO;QACR,CAAC;QACD,OAAO,CAAC,UAAU,GAAG,MAAM,CAAC,WAAW,CACtC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CACnH,CAAC;IACH,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC"}
@@ -1,4 +0,0 @@
1
- import { Effect } from "effect";
2
- import { SourceFailure } from "#diagnostics/source.ts";
3
- export declare function readCommand(command: string, args: readonly string[]): Effect.Effect<string, SourceFailure, never>;
4
- //# sourceMappingURL=readCommand.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"readCommand.d.ts","sourceRoot":"","sources":["../../../src/server/diagnostics/readCommand.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,+CAmBnE"}
@@ -1,20 +0,0 @@
1
- import { execFile } from "node:child_process";
2
- import { Effect } from "effect";
3
- import { SourceFailure } from "#diagnostics/source.ts";
4
- export function readCommand(command, args) {
5
- return Effect.callback((resume) => {
6
- const child = execFile(command, args, { maxBuffer: 1024 * 1024, timeout: 30_000 }, (error, stdout, stderr) => {
7
- if (error === null) {
8
- resume(Effect.succeed(stdout));
9
- return;
10
- }
11
- const missing = error.code === "ENOENT" || stderr.includes("gh auth login") || stderr.includes("GH_TOKEN environment variable");
12
- resume(Effect.fail(new SourceFailure({
13
- kind: missing ? "not-configured" : "error",
14
- message: missing ? `${command} is not installed or authenticated` : (stderr.trim() || error.message).slice(0, 500),
15
- })));
16
- });
17
- return Effect.sync(() => child.kill());
18
- });
19
- }
20
- //# sourceMappingURL=readCommand.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"readCommand.js","sourceRoot":"","sources":["../../../src/server/diagnostics/readCommand.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAEvD,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,IAAuB;IACnE,OAAO,MAAM,CAAC,QAAQ,CAAwB,CAAC,MAAM,EAAE,EAAE;QACxD,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;YAC5G,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACpB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;gBAC/B,OAAO;YACR,CAAC;YACD,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,eAAe,CAAC,IAAI,MAAM,CAAC,QAAQ,CAAC,+BAA+B,CAAC,CAAC;YAChI,MAAM,CACL,MAAM,CAAC,IAAI,CACV,IAAI,aAAa,CAAC;gBACjB,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO;gBAC1C,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,oCAAoC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;aAClH,CAAC,CACF,CACD,CAAC;QACH,CAAC,CAAC,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACJ,CAAC"}
@@ -1,6 +0,0 @@
1
- import { Schema } from "effect";
2
- import { InternalServerError } from "@shivaedev/platform/errors/taxonomy.ts";
3
- import { PublicationUncertain, ResponseRejection } from "#rpc/rejections.ts";
4
- export function failureStatus(error: unknown) {
5
- return `${Schema.is(ResponseRejection)(error) && !(error instanceof PublicationUncertain) && !(error instanceof InternalServerError) ? "Rejected" : "Uncertain"}: ${String(error)}. Draft retained; preview and retry.`;
6
- }
@@ -1,13 +0,0 @@
1
- import { Schema } from "effect";
2
- import { InternalServerError } from "@shivaedev/platform/errors/taxonomy.ts";
3
- import { PublicationUncertain, ResponseRejection } from "#rpc/rejections.ts";
4
- export function responseFailure(error: unknown) {
5
- const outcome =
6
- Schema.is(ResponseRejection)(error) && !(error instanceof PublicationUncertain) && !(error instanceof InternalServerError)
7
- ? "rejected"
8
- : "uncertain";
9
- return {
10
- outcome,
11
- text: `${outcome === "rejected" ? "Rejected" : "Uncertain"}: ${String(error)}. Draft retained. Preview and retry with the same identity; saved content will be reconciled.`,
12
- };
13
- }
@@ -1,24 +0,0 @@
1
- import { execFile } from "node:child_process";
2
- import { Effect } from "effect";
3
- import { SourceFailure } from "#diagnostics/source.ts";
4
-
5
- export function readCommand(command: string, args: readonly string[]) {
6
- return Effect.callback<string, SourceFailure>((resume) => {
7
- const child = execFile(command, args, { maxBuffer: 1024 * 1024, timeout: 30_000 }, (error, stdout, stderr) => {
8
- if (error === null) {
9
- resume(Effect.succeed(stdout));
10
- return;
11
- }
12
- const missing = error.code === "ENOENT" || stderr.includes("gh auth login") || stderr.includes("GH_TOKEN environment variable");
13
- resume(
14
- Effect.fail(
15
- new SourceFailure({
16
- kind: missing ? "not-configured" : "error",
17
- message: missing ? `${command} is not installed or authenticated` : (stderr.trim() || error.message).slice(0, 500),
18
- }),
19
- ),
20
- );
21
- });
22
- return Effect.sync(() => child.kill());
23
- });
24
- }
File without changes