@shivaedev/work-board 0.8.0 → 0.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (166) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +20 -1
  3. package/assets/agent.js +14 -14
  4. package/assets/native.js +49 -27
  5. package/dist/browser/responses/Prompt.d.ts +10 -0
  6. package/dist/browser/responses/Prompt.d.ts.map +1 -0
  7. package/dist/browser/responses/Prompt.js +2 -0
  8. package/dist/browser/responses/Prompt.js.map +1 -0
  9. package/dist/browser/responses/answerBody.d.ts +4 -0
  10. package/dist/browser/responses/answerBody.d.ts.map +1 -0
  11. package/dist/browser/responses/answerBody.js +9 -0
  12. package/dist/browser/responses/answerBody.js.map +1 -0
  13. package/dist/browser/responses/draftSession.d.ts.map +1 -1
  14. package/dist/browser/responses/draftSession.js +23 -10
  15. package/dist/browser/responses/draftSession.js.map +1 -1
  16. package/dist/browser/responses/drafts.d.ts +5 -0
  17. package/dist/browser/responses/drafts.d.ts.map +1 -1
  18. package/dist/browser/responses/drafts.js +20 -1
  19. package/dist/browser/responses/drafts.js.map +1 -1
  20. package/dist/browser/responses/preview.d.ts +2 -1
  21. package/dist/browser/responses/preview.d.ts.map +1 -1
  22. package/dist/browser/responses/preview.js +3 -2
  23. package/dist/browser/responses/preview.js.map +1 -1
  24. package/dist/browser/responses/questionnaireControls.d.ts +10 -0
  25. package/dist/browser/responses/questionnaireControls.d.ts.map +1 -0
  26. package/dist/browser/responses/questionnaireControls.js +68 -0
  27. package/dist/browser/responses/questionnaireControls.js.map +1 -0
  28. package/dist/browser/responses/schema.d.ts +41 -0
  29. package/dist/browser/responses/schema.d.ts.map +1 -1
  30. package/dist/browser/responses/schema.js +11 -1
  31. package/dist/browser/responses/schema.js.map +1 -1
  32. package/dist/browser/responses/setup.d.ts.map +1 -1
  33. package/dist/browser/responses/setup.js +34 -4
  34. package/dist/browser/responses/setup.js.map +1 -1
  35. package/dist/browser/responses/submissionFields.d.ts +15 -0
  36. package/dist/browser/responses/submissionFields.d.ts.map +1 -0
  37. package/dist/browser/responses/submissionFields.js +14 -0
  38. package/dist/browser/responses/submissionFields.js.map +1 -0
  39. package/dist/browser/responses/submit.d.ts.map +1 -1
  40. package/dist/browser/responses/submit.js +3 -9
  41. package/dist/browser/responses/submit.js.map +1 -1
  42. package/dist/metadata/backlinks.d.ts.map +1 -1
  43. package/dist/metadata/backlinks.js +3 -0
  44. package/dist/metadata/backlinks.js.map +1 -1
  45. package/dist/metadata/fields.d.ts +6 -0
  46. package/dist/metadata/fields.d.ts.map +1 -1
  47. package/dist/metadata/problems.d.ts.map +1 -1
  48. package/dist/metadata/problems.js +1 -0
  49. package/dist/metadata/problems.js.map +1 -1
  50. package/dist/metadata/schema.d.ts +6 -0
  51. package/dist/metadata/schema.d.ts.map +1 -1
  52. package/dist/page/metadataDetails.js +1 -1
  53. package/dist/page/metadataDetails.js.map +1 -1
  54. package/dist/page/style.d.ts.map +1 -1
  55. package/dist/page/style.js +1 -0
  56. package/dist/page/style.js.map +1 -1
  57. package/dist/render/markdown.d.ts +1 -0
  58. package/dist/render/markdown.d.ts.map +1 -1
  59. package/dist/render/markdown.js +4 -2
  60. package/dist/render/markdown.js.map +1 -1
  61. package/dist/render/questionnaireDocuments.d.ts +3 -0
  62. package/dist/render/questionnaireDocuments.d.ts.map +1 -0
  63. package/dist/render/questionnaireDocuments.js +11 -0
  64. package/dist/render/questionnaireDocuments.js.map +1 -0
  65. package/dist/render/visualDocuments.d.ts.map +1 -1
  66. package/dist/render/visualDocuments.js +3 -0
  67. package/dist/render/visualDocuments.js.map +1 -1
  68. package/dist/responses/agent.d.ts +12 -0
  69. package/dist/responses/agent.d.ts.map +1 -1
  70. package/dist/responses/await.d.ts +6 -0
  71. package/dist/responses/await.d.ts.map +1 -1
  72. package/dist/responses/composerHtml.d.ts +27 -0
  73. package/dist/responses/composerHtml.d.ts.map +1 -0
  74. package/dist/responses/composerHtml.js +14 -0
  75. package/dist/responses/composerHtml.js.map +1 -0
  76. package/dist/responses/history.d.ts +20 -0
  77. package/dist/responses/history.d.ts.map +1 -0
  78. package/dist/responses/history.js +16 -0
  79. package/dist/responses/history.js.map +1 -0
  80. package/dist/responses/locate.d.ts.map +1 -1
  81. package/dist/responses/locate.js +5 -0
  82. package/dist/responses/locate.js.map +1 -1
  83. package/dist/responses/make.d.ts +3 -0
  84. package/dist/responses/make.d.ts.map +1 -0
  85. package/dist/responses/make.js +16 -0
  86. package/dist/responses/make.js.map +1 -0
  87. package/dist/responses/outcome.d.ts +6 -0
  88. package/dist/responses/outcome.d.ts.map +1 -1
  89. package/dist/responses/page.d.ts +1 -1
  90. package/dist/responses/page.d.ts.map +1 -1
  91. package/dist/responses/page.js +7 -10
  92. package/dist/responses/page.js.map +1 -1
  93. package/dist/responses/read.d.ts +6 -0
  94. package/dist/responses/read.d.ts.map +1 -1
  95. package/dist/responses/records.d.ts.map +1 -1
  96. package/dist/responses/records.js +4 -1
  97. package/dist/responses/records.js.map +1 -1
  98. package/dist/responses/retry.d.ts +12 -0
  99. package/dist/responses/retry.d.ts.map +1 -1
  100. package/dist/responses/service.d.ts +37 -1
  101. package/dist/responses/service.d.ts.map +1 -1
  102. package/dist/responses/service.js +19 -14
  103. package/dist/responses/service.js.map +1 -1
  104. package/dist/responses/template.d.ts +7 -0
  105. package/dist/responses/template.d.ts.map +1 -0
  106. package/dist/responses/template.js +58 -0
  107. package/dist/responses/template.js.map +1 -0
  108. package/dist/responses/templateHtml.d.ts +7 -0
  109. package/dist/responses/templateHtml.d.ts.map +1 -0
  110. package/dist/responses/templateHtml.js +18 -0
  111. package/dist/responses/templateHtml.js.map +1 -0
  112. package/dist/responses/templateLinks.d.ts +3 -0
  113. package/dist/responses/templateLinks.d.ts.map +1 -0
  114. package/dist/responses/templateLinks.js +45 -0
  115. package/dist/responses/templateLinks.js.map +1 -0
  116. package/dist/responses/templateNodes.d.ts +17 -0
  117. package/dist/responses/templateNodes.d.ts.map +1 -0
  118. package/dist/responses/templateNodes.js +47 -0
  119. package/dist/responses/templateNodes.js.map +1 -0
  120. package/dist/responses/validateSupersedes.d.ts +5 -0
  121. package/dist/responses/validateSupersedes.d.ts.map +1 -0
  122. package/dist/responses/validateSupersedes.js +21 -0
  123. package/dist/responses/validateSupersedes.js.map +1 -0
  124. package/dist/responses/validatedInput.d.ts +3 -0
  125. package/dist/responses/validatedInput.d.ts.map +1 -0
  126. package/dist/responses/validatedInput.js +43 -0
  127. package/dist/responses/validatedInput.js.map +1 -0
  128. package/dist/responses/waitFor.d.ts +6 -0
  129. package/dist/responses/waitFor.d.ts.map +1 -1
  130. package/dist/rpc/contract.d.ts +24 -0
  131. package/dist/rpc/contract.d.ts.map +1 -1
  132. package/dist/rpc/responseContract.d.ts +48 -0
  133. package/dist/rpc/responseContract.d.ts.map +1 -1
  134. package/dist/serve-cli.js +1 -1
  135. package/package.json +2 -2
  136. package/src/browser/responses/Prompt.ts +6 -0
  137. package/src/browser/responses/answerBody.ts +11 -0
  138. package/src/browser/responses/draftSession.ts +23 -10
  139. package/src/browser/responses/drafts.ts +25 -1
  140. package/src/browser/responses/preview.ts +4 -2
  141. package/src/browser/responses/questionnaireControls.ts +74 -0
  142. package/src/browser/responses/schema.ts +12 -1
  143. package/src/browser/responses/setup.ts +34 -4
  144. package/src/browser/responses/submissionFields.ts +15 -0
  145. package/src/browser/responses/submit.ts +3 -11
  146. package/src/metadata/backlinks.ts +3 -0
  147. package/src/metadata/problems.ts +1 -0
  148. package/src/page/metadataDetails.ts +1 -1
  149. package/src/page/style.ts +1 -0
  150. package/src/render/markdown.ts +5 -2
  151. package/src/render/questionnaireDocuments.ts +12 -0
  152. package/src/render/visualDocuments.ts +3 -0
  153. package/src/responses/composerHtml.ts +28 -0
  154. package/src/responses/history.ts +18 -0
  155. package/src/responses/locate.ts +5 -0
  156. package/src/responses/make.ts +17 -0
  157. package/src/responses/page.ts +7 -18
  158. package/src/responses/records.ts +6 -1
  159. package/src/responses/service.ts +26 -15
  160. package/src/responses/template.ts +72 -0
  161. package/src/responses/templateHtml.ts +26 -0
  162. package/src/responses/templateLinks.ts +43 -0
  163. package/src/responses/templateNodes.ts +55 -0
  164. package/src/responses/validateSupersedes.ts +24 -0
  165. package/src/responses/validatedInput.ts +45 -0
  166. package/src/serve-cli.ts +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templateLinks.js","sourceRoot":"","sources":["../../src/responses/templateLinks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { RootContent } from "mdast";
2
+ import type { ContainerDirective } from "mdast-util-directive";
3
+ export declare function sliceNode(source: string, node: RootContent): string;
4
+ export declare function isContainer(node: RootContent): node is ContainerDirective;
5
+ export declare function promptFrom(node: ContainerDirective, source: string): {
6
+ prompt: {
7
+ id: string;
8
+ mode: "many" | "one" | "text";
9
+ options: {
10
+ id: string;
11
+ source: string;
12
+ }[];
13
+ source: string;
14
+ };
15
+ request: string | undefined;
16
+ };
17
+ //# sourceMappingURL=templateNodes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templateNodes.d.ts","sourceRoot":"","sources":["../../src/responses/templateNodes.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAQ/D,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,UAE1D;AACD,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI,IAAI,kBAAkB,CAEzE;AAQD,wBAAgB,UAAU,CAAC,IAAI,EAAE,kBAAkB,EAAE,MAAM,EAAE,MAAM;;;;;;;;;;;EA+BlE"}
@@ -0,0 +1,47 @@
1
+ import { Schema } from "effect";
2
+ import { Identity } from "#path/Identity.ts";
3
+ const Id = Identity.check(Schema.isMaxLength(128));
4
+ const PromptFields = Schema.Struct({ id: Id, request: Schema.optional(Identity), select: Schema.optional(Schema.Literals(["one", "many", "text"])) });
5
+ const OptionFields = Schema.Struct({ id: Id });
6
+ export function sliceNode(source, node) {
7
+ return source.slice(node.position?.start.offset, node.position?.end.offset);
8
+ }
9
+ export function isContainer(node) {
10
+ return node.type === "containerDirective";
11
+ }
12
+ function hasControl(node) {
13
+ return (((node.type === "containerDirective" || node.type === "leafDirective" || node.type === "textDirective")
14
+ && ["question", "option"].includes(node.name))
15
+ || ("children" in node && node.children.some(hasControl)));
16
+ }
17
+ export function promptFrom(node, source) {
18
+ const attrs = Schema.decodeUnknownSync(PromptFields, { onExcessProperty: "error" })(node.attributes ?? {});
19
+ const options = node.children.filter((child) => isContainer(child) && child.name === "option");
20
+ const description = node.children.filter((child) => !(isContainer(child) && child.name === "option"));
21
+ if (description.some(hasControl)
22
+ || description.length === 0
23
+ || options.length > 32
24
+ || (attrs.select === "text" ? options.length > 0 : options.length === 0)) {
25
+ throw new Error("A question needs Markdown context and 1–32 direct options (or select=text without options), without nested questions.");
26
+ }
27
+ const choices = options.map((option) => {
28
+ if (!isContainer(option) || option.children.some(hasControl) || option.children.length === 0) {
29
+ throw new Error("Options need Markdown descriptions and cannot nest response controls.");
30
+ }
31
+ const fields = Schema.decodeUnknownSync(OptionFields, { onExcessProperty: "error" })(option.attributes ?? {});
32
+ return { id: fields.id, source: option.children.map((child) => sliceNode(source, child)).join("\n\n") };
33
+ });
34
+ if (new Set(choices.map((option) => option.id)).size !== choices.length) {
35
+ throw new Error("Option IDs must be unique within each question.");
36
+ }
37
+ return {
38
+ prompt: {
39
+ id: attrs.id,
40
+ mode: attrs.select ?? "one",
41
+ options: choices,
42
+ source: description.map((child) => sliceNode(source, child)).join("\n\n"),
43
+ },
44
+ request: attrs.request,
45
+ };
46
+ }
47
+ //# sourceMappingURL=templateNodes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"templateNodes.js","sourceRoot":"","sources":["../../src/responses/templateNodes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import { Effect } from "effect";
2
+ import { type DraftInput, type Question, ResponseFailed } from "#browser/responses/schema.ts";
3
+ import type { Snapshot } from "#search/snapshot.ts";
4
+ export declare function validateSupersedes(input: DraftInput, question: Question, data: Snapshot): Effect.Effect<void, never, never> | Effect.Effect<never, ResponseFailed, never>;
5
+ //# sourceMappingURL=validateSupersedes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateSupersedes.d.ts","sourceRoot":"","sources":["../../src/responses/validateSupersedes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,KAAK,UAAU,EAAE,KAAK,QAAQ,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAGpD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,mFAkBvF"}
@@ -0,0 +1,21 @@
1
+ import { Effect } from "effect";
2
+ import { ResponseFailed } from "#browser/responses/schema.ts";
3
+ import { questionFrom, responseFrom } from "./records.js";
4
+ export function validateSupersedes(input, question, data) {
5
+ if (input.supersedes === undefined) {
6
+ return Effect.void;
7
+ }
8
+ const matches = data.model.ids.get(input.supersedes);
9
+ const previous = matches?.length === 1 && matches[0] ? responseFrom(matches[0]) : undefined;
10
+ const context = previous && data.model.ids.get(previous.response.question);
11
+ const old = context?.length === 1 && context[0] ? questionFrom(context[0]) : undefined;
12
+ return old
13
+ && previous
14
+ && previous.response.reviewedRevision === old.question.reviewedRevision
15
+ && old.question.item === question.question.item
16
+ && old.question.request === question.question.request
17
+ && input.supersedes !== input.id
18
+ ? Effect.void
19
+ : Effect.fail(new ResponseFailed({ code: "Conflict", message: "Supersedes must identify one recorded response to this item's attention request." }));
20
+ }
21
+ //# sourceMappingURL=validateSupersedes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validateSupersedes.js","sourceRoot":"","sources":["../../src/responses/validateSupersedes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAkC,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9F,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAE1D,MAAM,UAAU,kBAAkB,CAAC,KAAiB,EAAE,QAAkB,EAAE,IAAc;IACvF,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,MAAM,CAAC,IAAI,CAAC;IACpB,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IACrD,MAAM,QAAQ,GAAG,OAAO,EAAE,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5F,MAAM,OAAO,GAAG,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC3E,MAAM,GAAG,GAAG,OAAO,EAAE,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACvF,OAAO,GAAG;WACN,QAAQ;WACR,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,KAAK,GAAG,CAAC,QAAQ,CAAC,gBAAgB;WACpE,GAAG,CAAC,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,QAAQ,CAAC,IAAI;WAC5C,GAAG,CAAC,QAAQ,CAAC,OAAO,KAAK,QAAQ,CAAC,QAAQ,CAAC,OAAO;WAClD,KAAK,CAAC,UAAU,KAAK,KAAK,CAAC,EAAE;QAChC,CAAC,CAAC,MAAM,CAAC,IAAI;QACb,CAAC,CAAC,MAAM,CAAC,IAAI,CACX,IAAI,cAAc,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,kFAAkF,EAAE,CAAC,CACrI,CAAC;AACL,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { DraftInput } from "#browser/responses/schema.ts";
2
+ export declare function validatedInput(input: DraftInput, context: string, request: string, file?: string): DraftInput;
3
+ //# sourceMappingURL=validatedInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validatedInput.d.ts","sourceRoot":"","sources":["../../src/responses/validatedInput.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAgB,MAAM,8BAA8B,CAAC;AAiB7E,wBAAgB,cAAc,CAAC,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,UAAU,CAyB7G"}
@@ -0,0 +1,43 @@
1
+ import { answerBody } from "#browser/responses/answerBody.ts";
2
+ import { questionTemplate } from "./template.js";
3
+ function answerFor(prompt, answer, required) {
4
+ if (!answer || answer.prompt !== prompt.id) {
5
+ throw new Error("Submit one answer per question, in template order.");
6
+ }
7
+ if (new Set(answer.selected).size !== answer.selected.length || (prompt.mode === "one" && answer.selected.length > 1)) {
8
+ throw new Error("The selected options do not match the question's selection mode.");
9
+ }
10
+ if (answer.selected.some((id) => !prompt.options.some((option) => option.id === id))) {
11
+ throw new Error("A selected option is not in the reviewed template.");
12
+ }
13
+ if (required && answer.selected.length === 0 && !answer.text.trim()) {
14
+ throw new Error("Answer every question with a selection or additional text, or use Clarify / Not now.");
15
+ }
16
+ }
17
+ export function validatedInput(input, context, request, file) {
18
+ const template = questionTemplate(context, request, file);
19
+ if (input.answers === undefined) {
20
+ if (template.prompts.length > 0 && input.type === "answer") {
21
+ throw new Error("This question packet requires answers for all prompts.");
22
+ }
23
+ if (!input.body.trim()) {
24
+ throw new Error("A response needs text or answers to the question packet.");
25
+ }
26
+ return input;
27
+ }
28
+ if (input.answers.length !== template.prompts.length || template.prompts.length === 0) {
29
+ throw new Error("The answer packet does not match the reviewed questions.");
30
+ }
31
+ template.prompts.forEach((prompt, index) => {
32
+ answerFor(prompt, input.answers?.[index], input.type === "answer");
33
+ });
34
+ if (input.type !== "answer" && !input.body.trim() && !input.answers.some((answer) => answer.text.trim())) {
35
+ throw new Error("Clarify / Not now needs explanatory text.");
36
+ }
37
+ const body = answerBody(template.prompts, input.answers, input.body);
38
+ if (body.length > 32_768) {
39
+ throw new Error("The complete recorded response exceeds 32768 characters. Shorten the response or split the source request.");
40
+ }
41
+ return { ...input, body };
42
+ }
43
+ //# sourceMappingURL=validatedInput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validatedInput.js","sourceRoot":"","sources":["../../src/responses/validatedInput.ts"],"names":[],"mappings":"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"}
@@ -20,10 +20,16 @@ export declare const waitForResponse: (read: () => Effect.Effect<WaitReading, Re
20
20
  readonly body: string;
21
21
  readonly id: string;
22
22
  readonly response: {
23
+ readonly answers?: readonly {
24
+ readonly prompt: string;
25
+ readonly selected: readonly string[];
26
+ readonly text: string;
27
+ }[] | undefined;
23
28
  readonly author: string;
24
29
  readonly question: string;
25
30
  readonly recordedAt: number;
26
31
  readonly reviewedRevision: string;
32
+ readonly supersedes?: string | undefined;
27
33
  readonly type: "answer" | "clarify" | "not_now";
28
34
  };
29
35
  };
@@ -1 +1 @@
1
- {"version":3,"file":"waitFor.d.ts","sourceRoot":"","sources":["../../src/responses/waitFor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAsBhF,eAAO,MAAM,eAAe,eACf,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,cAAc,GAAG,cAAc,CAAC,qBACpD,MAAM,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;iCA8BjC,CAAC"}
1
+ {"version":3,"file":"waitFor.d.ts","sourceRoot":"","sources":["../../src/responses/waitFor.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AACxC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAsBhF,eAAO,MAAM,eAAe,eACf,MAAM,CAAC,MAAM,CAAC,WAAW,EAAE,cAAc,GAAG,cAAc,CAAC,qBACpD,MAAM,KAAK,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iCA8BjC,CAAC"}
@@ -89,19 +89,31 @@ export declare const Subscribe: Rpc.Rpc<"work-board.subscribe", Schema.Void, imp
89
89
  readonly _tag: Schema.Literal<"Resync">;
90
90
  }>]>, typeof ReadFailed>, Schema.Never, never, never>;
91
91
  export declare const workRpcs: import("effect/unstable/rpc/RpcGroup").RpcGroup<Rpc.Rpc<"work-board.recordResponse", Schema.Struct<{
92
+ readonly answers: Schema.optional<Schema.$Array<Schema.Struct<{
93
+ readonly prompt: Schema.String;
94
+ readonly selected: Schema.$Array<Schema.String>;
95
+ readonly text: Schema.String;
96
+ }>>>;
92
97
  readonly author: Schema.String;
93
98
  readonly body: Schema.String;
94
99
  readonly id: Schema.String;
95
100
  readonly question: Schema.String;
101
+ readonly supersedes: Schema.optional<Schema.String>;
96
102
  readonly type: Schema.Literals<readonly ["answer", "clarify", "not_now"]>;
97
103
  }>, Schema.Struct<{
98
104
  readonly body: Schema.String;
99
105
  readonly id: Schema.String;
100
106
  readonly response: Schema.Struct<{
107
+ readonly answers: Schema.optional<Schema.$Array<Schema.Struct<{
108
+ readonly prompt: Schema.String;
109
+ readonly selected: Schema.$Array<Schema.String>;
110
+ readonly text: Schema.String;
111
+ }>>>;
101
112
  readonly author: Schema.String;
102
113
  readonly question: Schema.String;
103
114
  readonly recordedAt: Schema.Number;
104
115
  readonly reviewedRevision: Schema.String;
116
+ readonly supersedes: Schema.optional<Schema.String>;
105
117
  readonly type: Schema.Literals<readonly ["answer", "clarify", "not_now"]>;
106
118
  }>;
107
119
  }>, Schema.Union<readonly typeof import("../browser/responses/schema.ts").ResponseFailed[]>, never, never> | Rpc.Rpc<"work-board.registerQuestion", Schema.Struct<{
@@ -142,10 +154,16 @@ export declare const workRpcs: import("effect/unstable/rpc/RpcGroup").RpcGroup<R
142
154
  readonly body: Schema.String;
143
155
  readonly id: Schema.String;
144
156
  readonly response: Schema.Struct<{
157
+ readonly answers: Schema.optional<Schema.$Array<Schema.Struct<{
158
+ readonly prompt: Schema.String;
159
+ readonly selected: Schema.$Array<Schema.String>;
160
+ readonly text: Schema.String;
161
+ }>>>;
145
162
  readonly author: Schema.String;
146
163
  readonly question: Schema.String;
147
164
  readonly recordedAt: Schema.Number;
148
165
  readonly reviewedRevision: Schema.String;
166
+ readonly supersedes: Schema.optional<Schema.String>;
149
167
  readonly type: Schema.Literals<readonly ["answer", "clarify", "not_now"]>;
150
168
  }>;
151
169
  }>>;
@@ -193,10 +211,16 @@ export declare const workRpcs: import("effect/unstable/rpc/RpcGroup").RpcGroup<R
193
211
  readonly body: Schema.String;
194
212
  readonly id: Schema.String;
195
213
  readonly response: Schema.Struct<{
214
+ readonly answers: Schema.optional<Schema.$Array<Schema.Struct<{
215
+ readonly prompt: Schema.String;
216
+ readonly selected: Schema.$Array<Schema.String>;
217
+ readonly text: Schema.String;
218
+ }>>>;
196
219
  readonly author: Schema.String;
197
220
  readonly question: Schema.String;
198
221
  readonly recordedAt: Schema.Number;
199
222
  readonly reviewedRevision: Schema.String;
223
+ readonly supersedes: Schema.optional<Schema.String>;
200
224
  readonly type: Schema.Literals<readonly ["answer", "clarify", "not_now"]>;
201
225
  }>;
202
226
  }>>;
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/rpc/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;;;;;AAS1C,qBAAa,UAAW,SAAQ,eAAmG;CAAG;AAkDtI,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gEAAwG,CAAC;AAClI,eAAO,MAAM,SAAS;;;;;;;;;;;;qDAA2F,CAAC;AAClH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sDAAsD,CAAC"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/rpc/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAChC,OAAO,EAAE,GAAG,EAAE,MAAM,qBAAqB,CAAC;;;;;AAS1C,qBAAa,UAAW,SAAQ,eAAmG;CAAG;AAkDtI,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;gEAAwG,CAAC;AAClI,eAAO,MAAM,SAAS;;;;;;;;;;;;qDAA2F,CAAC;AAClH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sDAAsD,CAAC"}
@@ -33,10 +33,16 @@ export declare const responseContract: import("@shivaedev/effect-contract/contra
33
33
  readonly body: Schema.String;
34
34
  readonly id: Schema.String;
35
35
  readonly response: Schema.Struct<{
36
+ readonly answers: Schema.optional<Schema.$Array<Schema.Struct<{
37
+ readonly prompt: Schema.String;
38
+ readonly selected: Schema.$Array<Schema.String>;
39
+ readonly text: Schema.String;
40
+ }>>>;
36
41
  readonly author: Schema.String;
37
42
  readonly question: Schema.String;
38
43
  readonly recordedAt: Schema.Number;
39
44
  readonly reviewedRevision: Schema.String;
45
+ readonly supersedes: Schema.optional<Schema.String>;
40
46
  readonly type: Schema.Literals<readonly ["answer", "clarify", "not_now"]>;
41
47
  }>;
42
48
  }>>;
@@ -64,10 +70,16 @@ export declare const responseContract: import("@shivaedev/effect-contract/contra
64
70
  readonly body: Schema.String;
65
71
  readonly id: Schema.String;
66
72
  readonly response: Schema.Struct<{
73
+ readonly answers: Schema.optional<Schema.$Array<Schema.Struct<{
74
+ readonly prompt: Schema.String;
75
+ readonly selected: Schema.$Array<Schema.String>;
76
+ readonly text: Schema.String;
77
+ }>>>;
67
78
  readonly author: Schema.String;
68
79
  readonly question: Schema.String;
69
80
  readonly recordedAt: Schema.Number;
70
81
  readonly reviewedRevision: Schema.String;
82
+ readonly supersedes: Schema.optional<Schema.String>;
71
83
  readonly type: Schema.Literals<readonly ["answer", "clarify", "not_now"]>;
72
84
  }>;
73
85
  }>>;
@@ -92,37 +104,61 @@ export declare const responseContract: import("@shivaedev/effect-contract/contra
92
104
  }>, {
93
105
  readonly ResponseFailed: typeof ResponseFailed;
94
106
  }>, import("@shivaedev/effect-contract/operation.ts").Command<"recordResponse", Schema.Struct<{
107
+ readonly answers: Schema.optional<Schema.$Array<Schema.Struct<{
108
+ readonly prompt: Schema.String;
109
+ readonly selected: Schema.$Array<Schema.String>;
110
+ readonly text: Schema.String;
111
+ }>>>;
95
112
  readonly author: Schema.String;
96
113
  readonly body: Schema.String;
97
114
  readonly id: Schema.String;
98
115
  readonly question: Schema.String;
116
+ readonly supersedes: Schema.optional<Schema.String>;
99
117
  readonly type: Schema.Literals<readonly ["answer", "clarify", "not_now"]>;
100
118
  }>, Schema.Struct<{
101
119
  readonly body: Schema.String;
102
120
  readonly id: Schema.String;
103
121
  readonly response: Schema.Struct<{
122
+ readonly answers: Schema.optional<Schema.$Array<Schema.Struct<{
123
+ readonly prompt: Schema.String;
124
+ readonly selected: Schema.$Array<Schema.String>;
125
+ readonly text: Schema.String;
126
+ }>>>;
104
127
  readonly author: Schema.String;
105
128
  readonly question: Schema.String;
106
129
  readonly recordedAt: Schema.Number;
107
130
  readonly reviewedRevision: Schema.String;
131
+ readonly supersedes: Schema.optional<Schema.String>;
108
132
  readonly type: Schema.Literals<readonly ["answer", "clarify", "not_now"]>;
109
133
  }>;
110
134
  }>, {
111
135
  readonly ResponseFailed: typeof ResponseFailed;
112
136
  }>], import("effect/unstable/rpc/Rpc").Rpc<"work-board.recordResponse", Schema.Struct<{
137
+ readonly answers: Schema.optional<Schema.$Array<Schema.Struct<{
138
+ readonly prompt: Schema.String;
139
+ readonly selected: Schema.$Array<Schema.String>;
140
+ readonly text: Schema.String;
141
+ }>>>;
113
142
  readonly author: Schema.String;
114
143
  readonly body: Schema.String;
115
144
  readonly id: Schema.String;
116
145
  readonly question: Schema.String;
146
+ readonly supersedes: Schema.optional<Schema.String>;
117
147
  readonly type: Schema.Literals<readonly ["answer", "clarify", "not_now"]>;
118
148
  }>, Schema.Struct<{
119
149
  readonly body: Schema.String;
120
150
  readonly id: Schema.String;
121
151
  readonly response: Schema.Struct<{
152
+ readonly answers: Schema.optional<Schema.$Array<Schema.Struct<{
153
+ readonly prompt: Schema.String;
154
+ readonly selected: Schema.$Array<Schema.String>;
155
+ readonly text: Schema.String;
156
+ }>>>;
122
157
  readonly author: Schema.String;
123
158
  readonly question: Schema.String;
124
159
  readonly recordedAt: Schema.Number;
125
160
  readonly reviewedRevision: Schema.String;
161
+ readonly supersedes: Schema.optional<Schema.String>;
126
162
  readonly type: Schema.Literals<readonly ["answer", "clarify", "not_now"]>;
127
163
  }>;
128
164
  }>, Schema.Union<readonly (typeof ResponseFailed)[]>, never, never> | import("effect/unstable/rpc/Rpc").Rpc<"work-board.registerQuestion", Schema.Struct<{
@@ -163,10 +199,16 @@ export declare const responseContract: import("@shivaedev/effect-contract/contra
163
199
  readonly body: Schema.String;
164
200
  readonly id: Schema.String;
165
201
  readonly response: Schema.Struct<{
202
+ readonly answers: Schema.optional<Schema.$Array<Schema.Struct<{
203
+ readonly prompt: Schema.String;
204
+ readonly selected: Schema.$Array<Schema.String>;
205
+ readonly text: Schema.String;
206
+ }>>>;
166
207
  readonly author: Schema.String;
167
208
  readonly question: Schema.String;
168
209
  readonly recordedAt: Schema.Number;
169
210
  readonly reviewedRevision: Schema.String;
211
+ readonly supersedes: Schema.optional<Schema.String>;
170
212
  readonly type: Schema.Literals<readonly ["answer", "clarify", "not_now"]>;
171
213
  }>;
172
214
  }>>;
@@ -201,10 +243,16 @@ export declare const responseContract: import("@shivaedev/effect-contract/contra
201
243
  readonly body: Schema.String;
202
244
  readonly id: Schema.String;
203
245
  readonly response: Schema.Struct<{
246
+ readonly answers: Schema.optional<Schema.$Array<Schema.Struct<{
247
+ readonly prompt: Schema.String;
248
+ readonly selected: Schema.$Array<Schema.String>;
249
+ readonly text: Schema.String;
250
+ }>>>;
204
251
  readonly author: Schema.String;
205
252
  readonly question: Schema.String;
206
253
  readonly recordedAt: Schema.Number;
207
254
  readonly reviewedRevision: Schema.String;
255
+ readonly supersedes: Schema.optional<Schema.String>;
208
256
  readonly type: Schema.Literals<readonly ["answer", "clarify", "not_now"]>;
209
257
  }>;
210
258
  }>>;
@@ -1 +1 @@
1
- {"version":3,"file":"responseContract.d.ts","sourceRoot":"","sources":["../../src/rpc/responseContract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,OAAO,EAMN,cAAc,EAGd,MAAM,8BAA8B,CAAC;AAiCtC,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEAAoG,CAAC"}
1
+ {"version":3,"file":"responseContract.d.ts","sourceRoot":"","sources":["../../src/rpc/responseContract.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAGhC,OAAO,EAMN,cAAc,EAGd,MAAM,8BAA8B,CAAC;AAiCtC,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oEAAoG,CAAC"}
package/dist/serve-cli.js CHANGED
@@ -3,7 +3,7 @@ import { NodeRuntime, NodeServices } from "@effect/platform-node";
3
3
  import { Effect, Layer, Option, Path } from "effect";
4
4
  import { Argument, Command, Flag } from "effect/unstable/cli";
5
5
  import { HOST, serveBoard } from "./serve.js";
6
- const VERSION = "0.8.0";
6
+ const VERSION = "0.9.1";
7
7
  const serve = Effect.fn("WorkBoard.serve")(function* (input) {
8
8
  const path = yield* Path.Path;
9
9
  return yield* Layer.launch(serveBoard({ home: Option.getOrUndefined(input.home), port: input.port, responses: input.responses, root: path.resolve(input.dir) }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/work-board",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
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": {
@@ -63,7 +63,7 @@
63
63
  "devDependencies": {
64
64
  "@effect/platform-node": "4.0.0-rc.112",
65
65
  "@effect/platform-node-shared": "4.0.0-rc.112",
66
- "@shivaedev/quality": "0.16.0",
66
+ "@shivaedev/quality": "0.17.0",
67
67
  "@types/hast": "3.0.5",
68
68
  "@types/mdast": "4.0.4",
69
69
  "@types/node": "24.10.1",
@@ -0,0 +1,6 @@
1
+ export interface Prompt {
2
+ readonly id: string;
3
+ readonly mode: "one" | "many" | "text";
4
+ readonly options: readonly { readonly id: string; readonly source: string }[];
5
+ readonly source: string;
6
+ }
@@ -0,0 +1,11 @@
1
+ import type { Prompt } from "./Prompt.ts";
2
+ import type { PromptAnswer } from "./schema.ts";
3
+
4
+ export function answerBody(prompts: readonly Prompt[], answers: readonly PromptAnswer[], note: string) {
5
+ const sections = prompts.map((prompt, index) => {
6
+ const answer = answers[index];
7
+ const chosen = prompt.options.filter((option) => answer?.selected.includes(option.id));
8
+ return `## Question: ${prompt.id}\n\n${prompt.source}\n\nSelected: ${chosen.map((option) => option.id).join(", ") || "No supplied option"}\n\n${chosen.map((option) => option.source).join("\n\n")}\n\n${answer?.text.trim() ? `Additional text:\n\n${answer.text}` : ""}`;
9
+ });
10
+ return `# Recorded response\n\n${sections.join("\n\n")}\n\n${note.trim() ? `## Overall response\n\n${note}` : ""}`.trim();
11
+ }
@@ -3,6 +3,7 @@ import { DRAFT_AGE, type Draft, encodeDrafts, readDrafts } from "./drafts.ts";
3
3
 
4
4
  const states = new Map<string, Draft>();
5
5
  export function draftSession(key: string, revision: string, storage: Storage | undefined, storageKey: string, report: (message: string) => void) {
6
+ const stateKey = `${JSON.stringify(storageKey)}:${key}`;
6
7
  function local() {
7
8
  if (!storage) {
8
9
  throw new Error("Draft storage unavailable");
@@ -22,12 +23,12 @@ export function draftSession(key: string, revision: string, storage: Storage | u
22
23
  blocked = true;
23
24
  report("Draft history is unavailable or malformed. Keep a copy; edits remain in this window.");
24
25
  }
25
- const memory = states.get(key);
26
+ const memory = states.get(stateKey);
26
27
  if (memory && Effect.runSync(Clock.currentTimeMillis) - memory.updatedAt >= DRAFT_AGE) {
27
- states.delete(key);
28
+ states.delete(stateKey);
28
29
  report("A window draft expired after 30 days. Saved responses are unaffected.");
29
30
  }
30
- let current = states.get(key)
31
+ let current = states.get(stateKey)
31
32
  ?? drafts[key] ?? {
32
33
  author: "",
33
34
  body: "",
@@ -40,8 +41,8 @@ export function draftSession(key: string, revision: string, storage: Storage | u
40
41
  report("Source changed since this draft. Your text is retained; review the new source and preview to bind it to this revision.");
41
42
  }
42
43
  function update(patch: Partial<Draft>) {
43
- current = { ...(states.get(key) ?? current), ...patch, updatedAt: Effect.runSync(Clock.currentTimeMillis) };
44
- states.set(key, current);
44
+ current = { ...(states.get(stateKey) ?? current), ...patch, updatedAt: Effect.runSync(Clock.currentTimeMillis) };
45
+ states.set(stateKey, current);
45
46
  try {
46
47
  if (blocked) {
47
48
  throw new Error("Unknown draft history");
@@ -57,21 +58,25 @@ export function draftSession(key: string, revision: string, storage: Storage | u
57
58
  try {
58
59
  local().removeItem(storageKey);
59
60
  blocked = false;
60
- states.clear();
61
+ for (const storedKey of states.keys()) {
62
+ if (storedKey.startsWith(`${JSON.stringify(storageKey)}:`)) {
63
+ states.delete(storedKey);
64
+ }
65
+ }
61
66
  report("Workspace drafts cleared. Saved responses are unchanged; this visible text remains until you navigate away.");
62
67
  } catch {
63
68
  report("Draft storage could not be cleared.");
64
69
  }
65
70
  }
66
71
  function saved(pending: Draft) {
67
- if (states.get(key) !== pending) {
68
- const live = states.get(key);
72
+ if (states.get(stateKey) !== pending) {
73
+ const live = states.get(stateKey);
69
74
  if (live?.id === pending.id) {
70
75
  update({ id: `response.${crypto.randomUUID()}` });
71
76
  }
72
77
  return false;
73
78
  }
74
- states.delete(key);
79
+ states.delete(stateKey);
75
80
  try {
76
81
  const latest = readDrafts(local().getItem(storageKey), Effect.runSync(Clock.currentTimeMillis)).drafts;
77
82
  if (latest[key]?.id === pending.id) {
@@ -81,7 +86,15 @@ export function draftSession(key: string, revision: string, storage: Storage | u
81
86
  } catch {
82
87
  report("Saved response confirmed, but its browser draft could not be cleared.");
83
88
  }
84
- current = { ...current, body: "", id: `response.${crypto.randomUUID()}`, updatedAt: Effect.runSync(Clock.currentTimeMillis) };
89
+ current = {
90
+ ...current,
91
+ answers: undefined,
92
+ body: "",
93
+ id: `response.${crypto.randomUUID()}`,
94
+ recovery: undefined,
95
+ supersedes: undefined,
96
+ updatedAt: Effect.runSync(Clock.currentTimeMillis),
97
+ };
85
98
  return true;
86
99
  }
87
100
  return { clear, current: () => current, saved, update };
@@ -1,13 +1,29 @@
1
+ import { Schema } from "effect";
2
+ import { Identity } from "#path/Identity.ts";
3
+ import { Answers, type PromptAnswer } from "./schema.ts";
4
+
1
5
  export const DRAFT_BYTES = 2 * 1024 * 1024;
2
6
  export const DRAFT_AGE = 30 * 24 * 60 * 60 * 1000;
3
7
  export interface Draft {
8
+ readonly answers?: readonly PromptAnswer[] | undefined;
4
9
  readonly author: string;
5
10
  readonly body: string;
6
11
  readonly id: string;
12
+ readonly question?: string | undefined;
13
+ readonly recovery?: string | undefined;
7
14
  readonly revision: string;
15
+ readonly supersedes?: string | undefined;
8
16
  readonly type: string;
9
17
  readonly updatedAt: number;
10
18
  }
19
+ function extraFields(entry: object) {
20
+ return {
21
+ ...("question" in entry ? { question: Schema.decodeUnknownSync(Identity)(entry.question) } : {}),
22
+ ...("recovery" in entry ? { recovery: Schema.decodeUnknownSync(Schema.String)(entry.recovery) } : {}),
23
+ ...("answers" in entry ? { answers: Schema.decodeUnknownSync(Answers, { onExcessProperty: "error" })(entry.answers) } : {}),
24
+ ...("supersedes" in entry ? { supersedes: Schema.decodeUnknownSync(Identity)(entry.supersedes) } : {}),
25
+ };
26
+ }
11
27
  export function readDrafts(raw: string | null, now: number): { drafts: Record<string, Draft>; expired: boolean } {
12
28
  if (raw === null) {
13
29
  return { drafts: {}, expired: false };
@@ -45,7 +61,15 @@ export function readDrafts(raw: string | null, now: number): { drafts: Record<st
45
61
  expired = true;
46
62
  continue;
47
63
  }
48
- drafts[key] = { author: entry.author, body: entry.body, id: entry.id, revision: entry.revision, type: entry.type, updatedAt: entry.updatedAt };
64
+ drafts[key] = {
65
+ ...extraFields(entry),
66
+ author: entry.author,
67
+ body: entry.body,
68
+ id: entry.id,
69
+ revision: entry.revision,
70
+ type: entry.type,
71
+ updatedAt: entry.updatedAt,
72
+ };
49
73
  }
50
74
  return { drafts, expired };
51
75
  }
@@ -1,5 +1,7 @@
1
+ import { answerBody } from "./answerBody.ts";
1
2
  import type { Draft } from "./drafts.ts";
3
+ import type { Prompt } from "./Prompt.ts";
2
4
 
3
- export function responsePreview(draft: Draft, question: string): string {
4
- return `New file: responses/${draft.id}.md\nRegistration (if needed): responses/${question}.md\nRecorded time is assigned by the server when saving.\n\n---\n${JSON.stringify({ id: draft.id, kind: "response", response: { author: draft.author, question, reviewedRevision: draft.revision, type: draft.type } }, null, 2)}\n---\n${draft.body}`;
5
+ export function responsePreview(draft: Draft, question: string, prompts: readonly Prompt[] = []): string {
6
+ return `New file: responses/${draft.id}.md\nRegistration (if needed): responses/${question}.md\nRecorded time is assigned by the server when saving.\n\n---\n${JSON.stringify({ id: draft.id, kind: "response", response: { answers: draft.answers, author: draft.author, question, reviewedRevision: draft.revision, supersedes: draft.supersedes, type: draft.type } }, null, 2)}\n---\n${draft.answers ? answerBody(prompts, draft.answers, draft.body) : draft.body}`;
5
7
  }