@shivaedev/work-board 0.8.0 → 0.9.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.
- package/CHANGELOG.md +20 -0
- package/README.md +18 -1
- package/assets/agent.js +14 -14
- package/assets/native.js +49 -27
- package/dist/browser/responses/Prompt.d.ts +10 -0
- package/dist/browser/responses/Prompt.d.ts.map +1 -0
- package/dist/browser/responses/Prompt.js +2 -0
- package/dist/browser/responses/Prompt.js.map +1 -0
- package/dist/browser/responses/answerBody.d.ts +4 -0
- package/dist/browser/responses/answerBody.d.ts.map +1 -0
- package/dist/browser/responses/answerBody.js +9 -0
- package/dist/browser/responses/answerBody.js.map +1 -0
- package/dist/browser/responses/draftSession.d.ts.map +1 -1
- package/dist/browser/responses/draftSession.js +23 -10
- package/dist/browser/responses/draftSession.js.map +1 -1
- package/dist/browser/responses/drafts.d.ts +5 -0
- package/dist/browser/responses/drafts.d.ts.map +1 -1
- package/dist/browser/responses/drafts.js +20 -1
- package/dist/browser/responses/drafts.js.map +1 -1
- package/dist/browser/responses/preview.d.ts +2 -1
- package/dist/browser/responses/preview.d.ts.map +1 -1
- package/dist/browser/responses/preview.js +3 -2
- package/dist/browser/responses/preview.js.map +1 -1
- package/dist/browser/responses/questionnaireControls.d.ts +10 -0
- package/dist/browser/responses/questionnaireControls.d.ts.map +1 -0
- package/dist/browser/responses/questionnaireControls.js +68 -0
- package/dist/browser/responses/questionnaireControls.js.map +1 -0
- package/dist/browser/responses/schema.d.ts +41 -0
- package/dist/browser/responses/schema.d.ts.map +1 -1
- package/dist/browser/responses/schema.js +11 -1
- package/dist/browser/responses/schema.js.map +1 -1
- package/dist/browser/responses/setup.d.ts.map +1 -1
- package/dist/browser/responses/setup.js +34 -4
- package/dist/browser/responses/setup.js.map +1 -1
- package/dist/browser/responses/submissionFields.d.ts +15 -0
- package/dist/browser/responses/submissionFields.d.ts.map +1 -0
- package/dist/browser/responses/submissionFields.js +14 -0
- package/dist/browser/responses/submissionFields.js.map +1 -0
- package/dist/browser/responses/submit.d.ts.map +1 -1
- package/dist/browser/responses/submit.js +3 -9
- package/dist/browser/responses/submit.js.map +1 -1
- package/dist/metadata/backlinks.d.ts.map +1 -1
- package/dist/metadata/backlinks.js +3 -0
- package/dist/metadata/backlinks.js.map +1 -1
- package/dist/metadata/fields.d.ts +6 -0
- package/dist/metadata/fields.d.ts.map +1 -1
- package/dist/metadata/problems.d.ts.map +1 -1
- package/dist/metadata/problems.js +1 -0
- package/dist/metadata/problems.js.map +1 -1
- package/dist/metadata/schema.d.ts +6 -0
- package/dist/metadata/schema.d.ts.map +1 -1
- package/dist/page/metadataDetails.js +1 -1
- package/dist/page/metadataDetails.js.map +1 -1
- package/dist/page/style.d.ts.map +1 -1
- package/dist/page/style.js +1 -0
- package/dist/page/style.js.map +1 -1
- package/dist/render/markdown.d.ts +1 -0
- package/dist/render/markdown.d.ts.map +1 -1
- package/dist/render/markdown.js +4 -2
- package/dist/render/markdown.js.map +1 -1
- package/dist/render/questionnaireDocuments.d.ts +3 -0
- package/dist/render/questionnaireDocuments.d.ts.map +1 -0
- package/dist/render/questionnaireDocuments.js +11 -0
- package/dist/render/questionnaireDocuments.js.map +1 -0
- package/dist/render/visualDocuments.d.ts.map +1 -1
- package/dist/render/visualDocuments.js +3 -0
- package/dist/render/visualDocuments.js.map +1 -1
- package/dist/responses/agent.d.ts +12 -0
- package/dist/responses/agent.d.ts.map +1 -1
- package/dist/responses/await.d.ts +6 -0
- package/dist/responses/await.d.ts.map +1 -1
- package/dist/responses/composerHtml.d.ts +27 -0
- package/dist/responses/composerHtml.d.ts.map +1 -0
- package/dist/responses/composerHtml.js +14 -0
- package/dist/responses/composerHtml.js.map +1 -0
- package/dist/responses/history.d.ts +20 -0
- package/dist/responses/history.d.ts.map +1 -0
- package/dist/responses/history.js +16 -0
- package/dist/responses/history.js.map +1 -0
- package/dist/responses/locate.d.ts.map +1 -1
- package/dist/responses/locate.js +5 -0
- package/dist/responses/locate.js.map +1 -1
- package/dist/responses/make.d.ts +3 -0
- package/dist/responses/make.d.ts.map +1 -0
- package/dist/responses/make.js +16 -0
- package/dist/responses/make.js.map +1 -0
- package/dist/responses/outcome.d.ts +6 -0
- package/dist/responses/outcome.d.ts.map +1 -1
- package/dist/responses/page.d.ts +1 -1
- package/dist/responses/page.d.ts.map +1 -1
- package/dist/responses/page.js +7 -10
- package/dist/responses/page.js.map +1 -1
- package/dist/responses/read.d.ts +6 -0
- package/dist/responses/read.d.ts.map +1 -1
- package/dist/responses/records.d.ts.map +1 -1
- package/dist/responses/records.js +2 -0
- package/dist/responses/records.js.map +1 -1
- package/dist/responses/retry.d.ts +12 -0
- package/dist/responses/retry.d.ts.map +1 -1
- package/dist/responses/service.d.ts +37 -1
- package/dist/responses/service.d.ts.map +1 -1
- package/dist/responses/service.js +19 -14
- package/dist/responses/service.js.map +1 -1
- package/dist/responses/template.d.ts +7 -0
- package/dist/responses/template.d.ts.map +1 -0
- package/dist/responses/template.js +58 -0
- package/dist/responses/template.js.map +1 -0
- package/dist/responses/templateHtml.d.ts +7 -0
- package/dist/responses/templateHtml.d.ts.map +1 -0
- package/dist/responses/templateHtml.js +18 -0
- package/dist/responses/templateHtml.js.map +1 -0
- package/dist/responses/templateLinks.d.ts +3 -0
- package/dist/responses/templateLinks.d.ts.map +1 -0
- package/dist/responses/templateLinks.js +45 -0
- package/dist/responses/templateLinks.js.map +1 -0
- package/dist/responses/templateNodes.d.ts +17 -0
- package/dist/responses/templateNodes.d.ts.map +1 -0
- package/dist/responses/templateNodes.js +47 -0
- package/dist/responses/templateNodes.js.map +1 -0
- package/dist/responses/validateSupersedes.d.ts +5 -0
- package/dist/responses/validateSupersedes.d.ts.map +1 -0
- package/dist/responses/validateSupersedes.js +21 -0
- package/dist/responses/validateSupersedes.js.map +1 -0
- package/dist/responses/validatedInput.d.ts +3 -0
- package/dist/responses/validatedInput.d.ts.map +1 -0
- package/dist/responses/validatedInput.js +43 -0
- package/dist/responses/validatedInput.js.map +1 -0
- package/dist/responses/waitFor.d.ts +6 -0
- package/dist/responses/waitFor.d.ts.map +1 -1
- package/dist/rpc/contract.d.ts +24 -0
- package/dist/rpc/contract.d.ts.map +1 -1
- package/dist/rpc/responseContract.d.ts +48 -0
- package/dist/rpc/responseContract.d.ts.map +1 -1
- package/dist/serve-cli.js +1 -1
- package/package.json +2 -2
- package/src/browser/responses/Prompt.ts +6 -0
- package/src/browser/responses/answerBody.ts +11 -0
- package/src/browser/responses/draftSession.ts +23 -10
- package/src/browser/responses/drafts.ts +25 -1
- package/src/browser/responses/preview.ts +4 -2
- package/src/browser/responses/questionnaireControls.ts +74 -0
- package/src/browser/responses/schema.ts +12 -1
- package/src/browser/responses/setup.ts +34 -4
- package/src/browser/responses/submissionFields.ts +15 -0
- package/src/browser/responses/submit.ts +3 -11
- package/src/metadata/backlinks.ts +3 -0
- package/src/metadata/problems.ts +1 -0
- package/src/page/metadataDetails.ts +1 -1
- package/src/page/style.ts +1 -0
- package/src/render/markdown.ts +5 -2
- package/src/render/questionnaireDocuments.ts +12 -0
- package/src/render/visualDocuments.ts +3 -0
- package/src/responses/composerHtml.ts +28 -0
- package/src/responses/history.ts +18 -0
- package/src/responses/locate.ts +5 -0
- package/src/responses/make.ts +17 -0
- package/src/responses/page.ts +7 -18
- package/src/responses/records.ts +2 -0
- package/src/responses/service.ts +26 -15
- package/src/responses/template.ts +72 -0
- package/src/responses/templateHtml.ts +26 -0
- package/src/responses/templateLinks.ts +43 -0
- package/src/responses/templateNodes.ts +55 -0
- package/src/responses/validateSupersedes.ts +24 -0
- package/src/responses/validatedInput.ts +45 -0
- package/src/serve-cli.ts +1 -1
|
@@ -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 @@
|
|
|
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
|
|
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"}
|
package/dist/rpc/contract.d.ts
CHANGED
|
@@ -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
|
|
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
|
|
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.
|
|
6
|
+
const VERSION = "0.9.0";
|
|
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.
|
|
3
|
+
"version": "0.9.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": {
|
|
@@ -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.
|
|
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,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(
|
|
26
|
+
const memory = states.get(stateKey);
|
|
26
27
|
if (memory && Effect.runSync(Clock.currentTimeMillis) - memory.updatedAt >= DRAFT_AGE) {
|
|
27
|
-
states.delete(
|
|
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(
|
|
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(
|
|
44
|
-
states.set(
|
|
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.
|
|
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(
|
|
68
|
-
const live = states.get(
|
|
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(
|
|
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 = {
|
|
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] = {
|
|
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
|
}
|