toolroll 0.9.36 → 0.9.37

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 (165) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/dist/assignment-adapters.d.ts +12 -48
  3. package/dist/assignment-adapters.js +33 -43
  4. package/dist/build-review.d.ts +1 -1
  5. package/dist/build-review.js +2 -1
  6. package/dist/chat-acceptance.d.ts +1 -1
  7. package/dist/chat-actions.d.ts +18 -12
  8. package/dist/chat-actions.js +15 -65
  9. package/dist/chat-ask.js +5 -5
  10. package/dist/chat-decide.d.ts +14 -1
  11. package/dist/chat-decide.js +12 -6
  12. package/dist/chat-delivery-state.d.ts +12 -70
  13. package/dist/chat-delivery-state.js +17 -135
  14. package/dist/chat-delivery.js +58 -30
  15. package/dist/chat-flow.js +8 -6
  16. package/dist/chat-inbox.js +1 -1
  17. package/dist/coding-context.d.ts +2 -39
  18. package/dist/coding-context.js +2 -1
  19. package/dist/coding-handoff.d.ts +6 -25
  20. package/dist/coding-handoff.js +11 -5
  21. package/dist/coding-types.d.ts +2 -26
  22. package/dist/coding-workspace.d.ts +2 -0
  23. package/dist/coding-workspace.js +50 -14
  24. package/dist/contracts/acceptance-terms.d.ts +14 -0
  25. package/dist/contracts/acceptance-terms.js +16 -0
  26. package/dist/contracts/chat-actions.d.ts +328 -0
  27. package/dist/contracts/chat-actions.js +133 -0
  28. package/dist/contracts/chat-callback-rows.d.ts +59 -0
  29. package/dist/contracts/chat-callback-rows.js +46 -0
  30. package/dist/contracts/chat-content.d.ts +276 -0
  31. package/dist/contracts/chat-content.js +127 -0
  32. package/dist/contracts/chat-tables.d.ts +6 -0
  33. package/dist/contracts/chat-tables.js +136 -0
  34. package/dist/contracts/coding-context.d.ts +97 -0
  35. package/dist/contracts/coding-context.js +60 -0
  36. package/dist/contracts/coding-handoff.d.ts +44 -0
  37. package/dist/contracts/coding-handoff.js +47 -0
  38. package/dist/contracts/coding-workspace.d.ts +165 -0
  39. package/dist/contracts/coding-workspace.js +71 -0
  40. package/dist/contracts/contract.d.ts +7 -2
  41. package/dist/contracts/contract.js +21 -12
  42. package/dist/contracts/decision.d.ts +45 -0
  43. package/dist/contracts/decision.js +45 -0
  44. package/dist/contracts/discord-callback.d.ts +45 -0
  45. package/dist/contracts/discord-callback.js +34 -0
  46. package/dist/contracts/flow-card.d.ts +50 -0
  47. package/dist/contracts/flow-card.js +46 -0
  48. package/dist/contracts/flow-send.d.ts +119 -0
  49. package/dist/contracts/flow-send.js +112 -0
  50. package/dist/contracts/flow.d.ts +5 -0
  51. package/dist/contracts/flow.js +5 -0
  52. package/dist/contracts/gateway-tools.d.ts +374 -0
  53. package/dist/contracts/gateway-tools.js +94 -0
  54. package/dist/contracts/lead-context.d.ts +165 -0
  55. package/dist/contracts/lead-context.js +73 -0
  56. package/dist/contracts/lead-tools.d.ts +1905 -0
  57. package/dist/contracts/lead-tools.js +265 -0
  58. package/dist/contracts/memory-pass.d.ts +158 -0
  59. package/dist/contracts/memory-pass.js +102 -0
  60. package/dist/contracts/project-knowledge.d.ts +126 -0
  61. package/dist/contracts/project-knowledge.js +93 -0
  62. package/dist/contracts/project-memory.d.ts +117 -0
  63. package/dist/contracts/project-memory.js +51 -0
  64. package/dist/contracts/project-skills.d.ts +121 -0
  65. package/dist/contracts/project-skills.js +76 -0
  66. package/dist/contracts/review-findings.d.ts +46 -0
  67. package/dist/contracts/review-findings.js +48 -0
  68. package/dist/contracts/route.d.ts +484 -0
  69. package/dist/contracts/route.js +128 -0
  70. package/dist/contracts/scope.d.ts +105 -0
  71. package/dist/contracts/scope.js +114 -0
  72. package/dist/contracts/scout-report.d.ts +234 -0
  73. package/dist/contracts/scout-report.js +141 -0
  74. package/dist/contracts/slack-callback.d.ts +43 -0
  75. package/dist/contracts/slack-callback.js +35 -0
  76. package/dist/contracts/sort-answer.d.ts +83 -0
  77. package/dist/contracts/sort-answer.js +77 -0
  78. package/dist/contracts/stage-output.d.ts +127 -0
  79. package/dist/contracts/stage-output.js +166 -0
  80. package/dist/contracts/task-sizing.d.ts +24 -0
  81. package/dist/contracts/task-sizing.js +28 -0
  82. package/dist/contracts/teammate-turn.d.ts +43 -0
  83. package/dist/contracts/teammate-turn.js +51 -0
  84. package/dist/contracts/teams-callback.d.ts +14 -0
  85. package/dist/contracts/teams-callback.js +14 -0
  86. package/dist/contracts/telegram-callback.d.ts +120 -0
  87. package/dist/contracts/telegram-callback.js +97 -0
  88. package/dist/decision.d.ts +11 -20
  89. package/dist/decision.js +86 -167
  90. package/dist/desktop-update.d.ts +2 -2
  91. package/dist/discord-chat.js +31 -20
  92. package/dist/flow-engine.js +14 -17
  93. package/dist/flow-items.d.ts +4 -13
  94. package/dist/flow-items.js +1 -15
  95. package/dist/flow-send.d.ts +6 -37
  96. package/dist/flow-send.js +18 -14
  97. package/dist/flow-share.js +7 -1
  98. package/dist/flow-sort.d.ts +7 -26
  99. package/dist/flow-sort.js +25 -20
  100. package/dist/flow-steps.js +3 -2
  101. package/dist/flows.d.ts +2 -4
  102. package/dist/flows.js +9 -5
  103. package/dist/invoke.js +4 -4
  104. package/dist/lead-context.d.ts +4 -2
  105. package/dist/lead-context.js +24 -17
  106. package/dist/mate-tools.d.ts +4 -0
  107. package/dist/mate-tools.js +108 -275
  108. package/dist/mcp-connect.d.ts +24 -4
  109. package/dist/mcp-connect.js +78 -15
  110. package/dist/mcp.js +84 -216
  111. package/dist/memory-pass.d.ts +17 -42
  112. package/dist/memory-pass.js +54 -26
  113. package/dist/phase-routing.d.ts +19 -72
  114. package/dist/phase-routing.js +34 -164
  115. package/dist/project-knowledge.d.ts +16 -35
  116. package/dist/project-knowledge.js +42 -21
  117. package/dist/project-memory.d.ts +2 -28
  118. package/dist/project-memory.js +28 -13
  119. package/dist/project-skills.d.ts +16 -38
  120. package/dist/project-skills.js +41 -32
  121. package/dist/project-tools.d.ts +1 -0
  122. package/dist/project-tools.js +4 -4
  123. package/dist/provider.d.ts +2 -0
  124. package/dist/provider.js +4 -16
  125. package/dist/result-shots.d.ts +1 -1
  126. package/dist/result-shots.js +2 -1
  127. package/dist/review-switch.d.ts +3 -8
  128. package/dist/reviewer.d.ts +8 -12
  129. package/dist/reviewer.js +11 -35
  130. package/dist/scope.d.ts +21 -43
  131. package/dist/scope.js +42 -128
  132. package/dist/scout-report.d.ts +9 -194
  133. package/dist/scout-report.js +113 -264
  134. package/dist/scout.js +15 -11
  135. package/dist/serve.js +9 -2
  136. package/dist/setup-guide.d.ts +2 -2
  137. package/dist/slack-chat.js +26 -20
  138. package/dist/slack-state.js +2 -1
  139. package/dist/store.d.ts +9 -32
  140. package/dist/store.js +18 -15
  141. package/dist/structured-output.js +2 -1
  142. package/dist/subscription-chat.d.ts +4 -0
  143. package/dist/subscription-chat.js +4 -1
  144. package/dist/task-review-brief.d.ts +1 -7
  145. package/dist/task-review-brief.js +6 -6
  146. package/dist/task-sizing.d.ts +3 -27
  147. package/dist/task-sizing.js +11 -26
  148. package/dist/task-text.d.ts +0 -5
  149. package/dist/task-text.js +1 -3
  150. package/dist/teammate-question.js +7 -5
  151. package/dist/teammate-work.js +9 -5
  152. package/dist/teammates.d.ts +13 -64
  153. package/dist/teammates.js +32 -33
  154. package/dist/teams-chat.js +20 -11
  155. package/dist/telegram-flow.js +4 -3
  156. package/dist/telegram-mate.d.ts +4 -14
  157. package/dist/telegram-mate.js +8 -7
  158. package/dist/telegram-team.d.ts +2 -19
  159. package/dist/telegram.d.ts +1 -1
  160. package/dist/telegram.js +52 -42
  161. package/dist/text-limits.d.ts +142 -1
  162. package/dist/text-limits.js +144 -1
  163. package/dist/tools-ui.d.ts +2 -1
  164. package/dist/tools-ui.js +7 -4
  165. package/package.json +1 -1
@@ -0,0 +1,34 @@
1
+ /**
2
+ * A Discord button tap (discord-chat.ts `receiveDiscord`): the component interaction Discord sends over the gateway,
3
+ * and the button data Toolroll put on it. The interaction is Discord's, so fields Toolroll doesn't read are ignored;
4
+ * the button's `custom_id` (`so_` and a one-time token) is Toolroll's. A tap from the paired person on Toolroll's own
5
+ * message whose button can't be read is answered with why (`data.custom_id: not a Toolroll button`), and nothing is done.
6
+ */
7
+ import { z } from "zod";
8
+ import { parseContract } from "./contract.js";
9
+ const user = z.object({ id: z.string() });
10
+ /** The interaction around a tap (type 3: a message component): the app, the person, the channel, the message. */
11
+ export const discordComponentInteractionSchema = z.object({
12
+ type: z.literal(3),
13
+ id: z.string(),
14
+ application_id: z.string(),
15
+ channel_id: z.string(),
16
+ guild_id: z.string().optional(),
17
+ channel: z.object({ type: z.int() }),
18
+ member: z.object({ user }).optional(),
19
+ user: user.optional(),
20
+ message: z.object({ id: z.string(), channel_id: z.string(), author: user }),
21
+ data: z.object({ custom_id: z.unknown().optional() }),
22
+ });
23
+ /** Toolroll's button data: `so_` and a one-time token. */
24
+ export const discordButtonSchema = z.object({
25
+ custom_id: z.string().regex(/^so_[a-f0-9]{32}$/, { error: "not a Toolroll button" }),
26
+ });
27
+ export function readDiscordComponentInteraction(body) {
28
+ return parseContract(discordComponentInteractionSchema, body);
29
+ }
30
+ /** The tapped button's one-time token. */
31
+ export function readDiscordButtonToken(interaction) {
32
+ const read = parseContract(z.object({ data: discordButtonSchema }), { data: interaction.data });
33
+ return read.ok ? { ok: true, value: read.value.data.custom_id.slice(3) } : read;
34
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * A flow card's state (docs/plans/zod-revamp.md, item 8): what the flow engine, its steps and its Send to me and
3
+ * Person chooses zones read and write (flow-engine.ts, flow-steps.ts, flow-send.ts), as the store keeps it in
4
+ * `flow_card`. Its columns are versioned by the database's own schema version; the one payload in it, what finished
5
+ * zones handed on (`outputs_json`), carries its own version (stage-output.ts).
6
+ *
7
+ * `flowCardSchema` is the card as read; `flowCardChangeSchema` what one update may change. Where it came from
8
+ * (`source_json`, written by triggers) keeps its own type in the store.
9
+ */
10
+ import { z } from "zod";
11
+ export declare const FLOW_CARD_STATES: readonly ["active", "done", "cancelled"];
12
+ export type FlowCardState = (typeof FLOW_CARD_STATES)[number];
13
+ export declare const flowCardSchema: z.ZodObject<{
14
+ id: z.ZodInt;
15
+ flow: z.ZodInt;
16
+ title: z.ZodString;
17
+ description: z.ZodNullable<z.ZodString>;
18
+ stage: z.ZodString;
19
+ entry: z.ZodInt;
20
+ state: z.ZodEnum<{
21
+ active: "active";
22
+ cancelled: "cancelled";
23
+ done: "done";
24
+ }>;
25
+ task: z.ZodNullable<z.ZodString>;
26
+ primaryTask: z.ZodNullable<z.ZodString>;
27
+ note: z.ZodNullable<z.ZodString>;
28
+ waiting: z.ZodNullable<z.ZodString>;
29
+ outputs: z.ZodObject<{}, z.core.$catchall<z.ZodString>>;
30
+ attached: z.ZodObject<{}, z.core.$catchall<z.ZodString>>;
31
+ createdBy: z.ZodString;
32
+ createdAt: z.ZodString;
33
+ updatedAt: z.ZodString;
34
+ owner: z.ZodNullable<z.ZodString>;
35
+ }, z.core.$strict>;
36
+ export type FlowCardFields = z.infer<typeof flowCardSchema>;
37
+ /** What one update of a card may change; whatever is left out stays as it is. Outputs replace the card's whole;
38
+ * an attachment goes with the output it belongs to. */
39
+ export declare const flowCardChangeSchema: z.ZodObject<{
40
+ task: z.ZodOptional<z.ZodNullable<z.ZodString>>;
41
+ primaryTask: z.ZodOptional<z.ZodString>;
42
+ waiting: z.ZodOptional<z.ZodNullable<z.ZodString>>;
43
+ outputs: z.ZodOptional<z.ZodObject<{}, z.core.$catchall<z.ZodString>>>;
44
+ attached: z.ZodOptional<z.ZodObject<{}, z.core.$catchall<z.ZodString>>>;
45
+ state: z.ZodOptional<z.ZodEnum<{
46
+ cancelled: "cancelled";
47
+ done: "done";
48
+ }>>;
49
+ }, z.core.$strict>;
50
+ export type FlowCardChange = z.infer<typeof flowCardChangeSchema>;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * A flow card's state (docs/plans/zod-revamp.md, item 8): what the flow engine, its steps and its Send to me and
3
+ * Person chooses zones read and write (flow-engine.ts, flow-steps.ts, flow-send.ts), as the store keeps it in
4
+ * `flow_card`. Its columns are versioned by the database's own schema version; the one payload in it, what finished
5
+ * zones handed on (`outputs_json`), carries its own version (stage-output.ts).
6
+ *
7
+ * `flowCardSchema` is the card as read; `flowCardChangeSchema` what one update may change. Where it came from
8
+ * (`source_json`, written by triggers) keeps its own type in the store.
9
+ */
10
+ import { z } from "zod";
11
+ import { cardOutputsSchema } from "./stage-output.js";
12
+ export const FLOW_CARD_STATES = ["active", "done", "cancelled"];
13
+ export const flowCardSchema = z.strictObject({
14
+ id: z.int().min(1),
15
+ flow: z.int().min(1),
16
+ title: z.string(),
17
+ description: z.string().nullable(),
18
+ /** The zone it is in, and which visit to that zone this is (each move is a fresh one). */
19
+ stage: z.string(),
20
+ entry: z.int().min(1),
21
+ state: z.enum(FLOW_CARD_STATES),
22
+ /** The task its zone filed this visit, and the card's main build. */
23
+ task: z.string().nullable(),
24
+ primaryTask: z.string().nullable(),
25
+ /** The latest note it was sent back or replied to with ({{note}}). */
26
+ note: z.string().nullable(),
27
+ /** What it waits for, in words. */
28
+ waiting: z.string().nullable(),
29
+ /** What finished zones handed on ({{stage.…}}), and any too long to pass on, whole. */
30
+ outputs: cardOutputsSchema.shape.outputs,
31
+ attached: cardOutputsSchema.shape.attached,
32
+ createdBy: z.string(),
33
+ createdAt: z.string(),
34
+ updatedAt: z.string(),
35
+ owner: z.string().nullable(),
36
+ });
37
+ /** What one update of a card may change; whatever is left out stays as it is. Outputs replace the card's whole;
38
+ * an attachment goes with the output it belongs to. */
39
+ export const flowCardChangeSchema = z.strictObject({
40
+ task: flowCardSchema.shape.task.optional(),
41
+ primaryTask: z.string().optional(),
42
+ waiting: flowCardSchema.shape.waiting.optional(),
43
+ outputs: flowCardSchema.shape.outputs.optional(),
44
+ attached: flowCardSchema.shape.attached.optional(),
45
+ state: z.enum(["done", "cancelled"]).optional(),
46
+ });
@@ -0,0 +1,119 @@
1
+ /**
2
+ * What a "Send to me" or "Person chooses" visit sends its person (docs/plans/zod-revamp.md, item 8): worked out once
3
+ * per visit and kept (`flow_send.content_json`), so every chat app and the card show the same (src/flow-send.ts).
4
+ *
5
+ * - `flowSendPayloadSchema`: a send's — the title, summary, links, screenshots and a research report's items.
6
+ * - `flowChoosePayloadSchema`: a choice's — the same, with the options as they were offered and whether a reply is taken.
7
+ * - `flowChoiceAnswerSchema`: the person's answer to a choice, by whichever door it comes (chooseFlowCard).
8
+ *
9
+ * Kept before this contract (version 0), a visit's content had no `version`; it reads as the 0.9.36 reader read it:
10
+ * a title, a summary and a list of links make it readable, items that can't be shown are left out, and a link or
11
+ * option that isn't one is skipped.
12
+ */
13
+ import { z } from "zod";
14
+ import { type ContractResult } from "./contract.js";
15
+ /** A link the message carries: a page of Toolroll's (a button) or the one outside page, a pull request. */
16
+ export declare const flowSendLinkSchema: z.ZodUnion<readonly [z.ZodObject<{
17
+ label: z.ZodString;
18
+ path: z.ZodString;
19
+ }, z.core.$strict>, z.ZodObject<{
20
+ label: z.ZodString;
21
+ url: z.ZodString;
22
+ }, z.core.$strict>]>;
23
+ /** One item of a research report, as the message lists it (flow-items.ts). */
24
+ export declare const flowSendItemSchema: z.ZodObject<{
25
+ title: z.ZodString;
26
+ why: z.ZodString;
27
+ url: z.ZodString;
28
+ source: z.ZodString;
29
+ plug: z.ZodString;
30
+ shot: z.ZodNullable<z.ZodInt>;
31
+ }, z.core.$strict>;
32
+ export type FlowSendLink = z.infer<typeof flowSendLinkSchema>;
33
+ export type FlowSendItem = z.infer<typeof flowSendItemSchema>;
34
+ export declare const FLOW_SEND_VERSION = 1;
35
+ export declare const flowChoiceOptionSchema: z.ZodObject<{
36
+ choice: z.ZodInt;
37
+ label: z.ZodString;
38
+ }, z.core.$strict>;
39
+ export declare const flowSendPayloadSchema: z.ZodObject<{
40
+ version: z.ZodLiteral<1>;
41
+ title: z.ZodString;
42
+ from: z.ZodOptional<z.ZodString>;
43
+ summary: z.ZodString;
44
+ links: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
45
+ label: z.ZodString;
46
+ path: z.ZodString;
47
+ }, z.core.$strict>, z.ZodObject<{
48
+ label: z.ZodString;
49
+ url: z.ZodString;
50
+ }, z.core.$strict>]>>;
51
+ shots: z.ZodNullable<z.ZodObject<{
52
+ taskId: z.ZodString;
53
+ run: z.ZodInt;
54
+ }, z.core.$strict>>;
55
+ items: z.ZodOptional<z.ZodArray<z.ZodObject<{
56
+ title: z.ZodString;
57
+ why: z.ZodString;
58
+ url: z.ZodString;
59
+ source: z.ZodString;
60
+ plug: z.ZodString;
61
+ shot: z.ZodNullable<z.ZodInt>;
62
+ }, z.core.$strict>>>;
63
+ }, z.core.$strict>;
64
+ export declare const flowChoosePayloadSchema: z.ZodObject<{
65
+ version: z.ZodLiteral<1>;
66
+ title: z.ZodString;
67
+ from: z.ZodOptional<z.ZodString>;
68
+ summary: z.ZodString;
69
+ links: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
70
+ label: z.ZodString;
71
+ path: z.ZodString;
72
+ }, z.core.$strict>, z.ZodObject<{
73
+ label: z.ZodString;
74
+ url: z.ZodString;
75
+ }, z.core.$strict>]>>;
76
+ shots: z.ZodNullable<z.ZodObject<{
77
+ taskId: z.ZodString;
78
+ run: z.ZodInt;
79
+ }, z.core.$strict>>;
80
+ items: z.ZodOptional<z.ZodArray<z.ZodObject<{
81
+ title: z.ZodString;
82
+ why: z.ZodString;
83
+ url: z.ZodString;
84
+ source: z.ZodString;
85
+ plug: z.ZodString;
86
+ shot: z.ZodNullable<z.ZodInt>;
87
+ }, z.core.$strict>>>;
88
+ options: z.ZodArray<z.ZodObject<{
89
+ choice: z.ZodInt;
90
+ label: z.ZodString;
91
+ }, z.core.$strict>>;
92
+ reply: z.ZodBoolean;
93
+ }, z.core.$strict>;
94
+ export type FlowSendPayload = z.infer<typeof flowSendPayloadSchema>;
95
+ export type FlowChoosePayload = z.infer<typeof flowChoosePayloadSchema>;
96
+ /** A visit's content as the console and chat apps read it: a send's, or a choice's with its options. */
97
+ export type FlowSendContent = Omit<FlowSendPayload, "version"> & {
98
+ options?: FlowChoosePayload["options"];
99
+ reply?: boolean;
100
+ };
101
+ export declare function readFlowItems(raw: unknown): FlowSendItem[];
102
+ /** Version 0: content kept before it carried `version`, in this contract's shape (what can't be read is left for the schema to refuse by path). */
103
+ export declare function upgradeSavedSend(body: Record<string, unknown>): Record<string, unknown>;
104
+ /** Read a visit's kept content: a choice's when it carries options, else a send's; version 0 upgraded, newer refused. */
105
+ export declare function readFlowSendPayload(input: unknown): ContractResult<FlowSendContent>;
106
+ /** A visit's content as it is kept: the payload of its kind, with the current version. */
107
+ export declare function flowSendForStore(content: FlowSendContent): string;
108
+ /** A person's answer to a choice: an option by its place (and the words and zone they saw), or a reply (`choice` null)
109
+ * that becomes the note for where replies go. `entry` is the visit they saw; without it, the card's current one. */
110
+ export declare const flowChoiceAnswerSchema: z.ZodObject<{
111
+ card: z.ZodInt;
112
+ entry: z.ZodOptional<z.ZodInt>;
113
+ choice: z.ZodNullable<z.ZodInt>;
114
+ label: z.ZodOptional<z.ZodString>;
115
+ to: z.ZodOptional<z.ZodString>;
116
+ note: z.ZodNullable<z.ZodString>;
117
+ }, z.core.$strict>;
118
+ export type FlowChoiceAnswer = z.infer<typeof flowChoiceAnswerSchema>;
119
+ export declare function readFlowChoiceAnswer(input: unknown): ContractResult<FlowChoiceAnswer>;
@@ -0,0 +1,112 @@
1
+ /**
2
+ * What a "Send to me" or "Person chooses" visit sends its person (docs/plans/zod-revamp.md, item 8): worked out once
3
+ * per visit and kept (`flow_send.content_json`), so every chat app and the card show the same (src/flow-send.ts).
4
+ *
5
+ * - `flowSendPayloadSchema`: a send's — the title, summary, links, screenshots and a research report's items.
6
+ * - `flowChoosePayloadSchema`: a choice's — the same, with the options as they were offered and whether a reply is taken.
7
+ * - `flowChoiceAnswerSchema`: the person's answer to a choice, by whichever door it comes (chooseFlowCard).
8
+ *
9
+ * Kept before this contract (version 0), a visit's content had no `version`; it reads as the 0.9.36 reader read it:
10
+ * a title, a summary and a list of links make it readable, items that can't be shown are left out, and a link or
11
+ * option that isn't one is skipped.
12
+ */
13
+ import { z } from "zod";
14
+ import { parseContract, readVersioned, versioned } from "./contract.js";
15
+ /** A link the message carries: a page of Toolroll's (a button) or the one outside page, a pull request. */
16
+ export const flowSendLinkSchema = z.union([
17
+ z.strictObject({ label: z.string(), path: z.string().regex(/^\//, { error: "must be a path in Toolroll, starting with /" }) }),
18
+ z.strictObject({ label: z.string(), url: z.string().regex(/^https:\/\/[^\s<>"]+$/, { error: "must be an https:// address" }) }),
19
+ ]);
20
+ /** One item of a research report, as the message lists it (flow-items.ts). */
21
+ export const flowSendItemSchema = z.strictObject({
22
+ title: z.string(),
23
+ why: z.string(),
24
+ url: z.string().regex(/^https?:\/\//, { error: "must be a web address" }),
25
+ /** Where the link goes, by name: "Mobbin", "Linear", "Apple". */
26
+ source: z.string(),
27
+ /** One line: how it plugs in (from the why, else the image's own caption). */
28
+ plug: z.string(),
29
+ /** The item's screenshot (its evidence id in the report's run), when it has one. */
30
+ shot: z.int().nullable(),
31
+ });
32
+ export const FLOW_SEND_VERSION = 1;
33
+ const sendShape = {
34
+ /** The card's title and the step it comes from. */
35
+ title: z.string(),
36
+ /** The step it comes from, when known. */
37
+ from: z.string().optional(),
38
+ summary: z.string(),
39
+ links: z.array(flowSendLinkSchema),
40
+ /** The build's result whose screenshots go with it, when it saved any. */
41
+ shots: z.strictObject({ taskId: z.string(), run: z.int() }).nullable(),
42
+ /** After research: the report's items, numbered in this order in every message and screenshot caption. */
43
+ items: z.array(flowSendItemSchema).min(1).optional(),
44
+ };
45
+ export const flowChoiceOptionSchema = z.strictObject({ choice: z.int().min(0), label: z.string() });
46
+ export const flowSendPayloadSchema = versioned(FLOW_SEND_VERSION, sendShape);
47
+ export const flowChoosePayloadSchema = versioned(FLOW_SEND_VERSION, {
48
+ ...sendShape,
49
+ /** The options as they were offered, by place. */
50
+ options: z.array(flowChoiceOptionSchema),
51
+ /** Whether a reply is taken instead (the zone has somewhere replies go). */
52
+ reply: z.boolean(),
53
+ });
54
+ const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
55
+ /** A kept item as 0.9.36 read it: its five words (a web link), and a screenshot id only when it is a whole number. */
56
+ const savedItemSchema = z.object({ ...flowSendItemSchema.shape, shot: z.unknown() });
57
+ export function readFlowItems(raw) {
58
+ if (!Array.isArray(raw))
59
+ return [];
60
+ return raw.flatMap(one => {
61
+ const read = savedItemSchema.safeParse(one);
62
+ if (!read.success)
63
+ return [];
64
+ const shot = read.data.shot;
65
+ return [{ ...read.data, shot: typeof shot === "number" && Number.isSafeInteger(shot) ? shot : null }];
66
+ });
67
+ }
68
+ /** Version 0: content kept before it carried `version`, in this contract's shape (what can't be read is left for the schema to refuse by path). */
69
+ export function upgradeSavedSend(body) {
70
+ if (typeof body["title"] !== "string" || typeof body["summary"] !== "string" || !Array.isArray(body["links"]))
71
+ return body;
72
+ const items = readFlowItems(body["items"]);
73
+ const shots = sendShape.shots.safeParse(body["shots"]);
74
+ const out = {
75
+ version: FLOW_SEND_VERSION, title: body["title"], ...(typeof body["from"] === "string" ? { from: body["from"] } : {}), summary: body["summary"],
76
+ links: body["links"].filter(one => flowSendLinkSchema.safeParse(one).success), shots: shots.success ? shots.data : null,
77
+ ...(body["items"] === undefined || items.length === 0 ? {} : { items }),
78
+ };
79
+ if (Array.isArray(body["options"])) {
80
+ out["options"] = body["options"].filter(one => flowChoiceOptionSchema.safeParse(one).success);
81
+ out["reply"] = body["reply"] === true;
82
+ }
83
+ return out;
84
+ }
85
+ /** Read a visit's kept content: a choice's when it carries options, else a send's; version 0 upgraded, newer refused. */
86
+ export function readFlowSendPayload(input) {
87
+ const choose = isRecord(input) && Object.prototype.hasOwnProperty.call(input, "options");
88
+ const read = choose ? readVersioned(flowChoosePayloadSchema, input, { 0: upgradeSavedSend }) : readVersioned(flowSendPayloadSchema, input, { 0: upgradeSavedSend });
89
+ if (!read.ok)
90
+ return read;
91
+ const { version: _version, ...content } = read.value;
92
+ return { ok: true, value: content };
93
+ }
94
+ /** A visit's content as it is kept: the payload of its kind, with the current version. */
95
+ export function flowSendForStore(content) {
96
+ const payload = { version: FLOW_SEND_VERSION, ...content };
97
+ return JSON.stringify(content.options === undefined ? flowSendPayloadSchema.parse(payload) : flowChoosePayloadSchema.parse(payload));
98
+ }
99
+ // ------------------------------------------------------------------ the person's choice
100
+ /** A person's answer to a choice: an option by its place (and the words and zone they saw), or a reply (`choice` null)
101
+ * that becomes the note for where replies go. `entry` is the visit they saw; without it, the card's current one. */
102
+ export const flowChoiceAnswerSchema = z.strictObject({
103
+ card: z.int().min(1),
104
+ entry: z.int().min(1).optional(),
105
+ choice: z.int().min(0).nullable(),
106
+ label: z.string().optional(),
107
+ to: z.string().optional(),
108
+ note: z.string().nullable(),
109
+ });
110
+ export function readFlowChoiceAnswer(input) {
111
+ return parseContract(flowChoiceAnswerSchema, input);
112
+ }
@@ -85,6 +85,11 @@ export declare const flowSortNoteSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
85
85
  question: z.ZodString;
86
86
  levels: z.ZodNull;
87
87
  }, z.core.$strict>], "kind">;
88
+ /** How a sort answer is named to Jev: its words as a short key (the request's criteria, and the choice Jev returns). */
89
+ export declare const sortKeyOf: (answer: string) => string;
90
+ /** The key of a sort zone's question in its Jev request (a choice over its answers), and of each thing it also notes. */
91
+ export declare const SORT_ROUTE_KEY = "route";
92
+ export declare const sortNoteKeyOf: (noteId: string) => string;
88
93
  /** sort: the question, its answers, how sure Jev must be to act alone (0.5–0.99), and what else it notes. */
89
94
  export declare const flowSortSchema: z.ZodObject<{
90
95
  question: z.ZodString;
@@ -72,6 +72,11 @@ export const flowSortNoteSchema = z.discriminatedUnion("kind", [
72
72
  z.strictObject({ id: zoneId, kind: z.literal("score"), question: words("question", "flowSortQuestion").min(1), levels: z.array(words("level", "flowSortLevel").min(1)).min(SORT_LEVELS_MIN).max(SORT_LEVELS_MAX) }),
73
73
  z.strictObject({ id: zoneId, kind: z.literal("yes-no"), question: words("question", "flowSortQuestion").min(1), levels: z.null() }),
74
74
  ]);
75
+ /** How a sort answer is named to Jev: its words as a short key (the request's criteria, and the choice Jev returns). */
76
+ export const sortKeyOf = (answer) => answer.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "answer";
77
+ /** The key of a sort zone's question in its Jev request (a choice over its answers), and of each thing it also notes. */
78
+ export const SORT_ROUTE_KEY = "route";
79
+ export const sortNoteKeyOf = (noteId) => `note_${noteId.replace(/-/g, "_")}`;
75
80
  /** sort: the question, its answers, how sure Jev must be to act alone (0.5–0.99), and what else it notes. */
76
81
  export const flowSortSchema = z.strictObject({
77
82
  question: words("question", "flowSortQuestion").min(1),