toolroll 0.9.34 → 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.
- package/CHANGELOG.md +102 -0
- package/README.md +7 -0
- package/dist/assignment-adapters.d.ts +12 -48
- package/dist/assignment-adapters.js +33 -43
- package/dist/assignment.d.ts +1 -0
- package/dist/assignment.js +2 -2
- package/dist/browser-workspace.d.ts +3 -3
- package/dist/build-review.d.ts +1 -1
- package/dist/build-review.js +2 -1
- package/dist/builder.js +4 -7
- package/dist/chat-acceptance.d.ts +2 -2
- package/dist/chat-actions.d.ts +18 -12
- package/dist/chat-actions.js +15 -65
- package/dist/chat-ask.js +5 -5
- package/dist/chat-decide.d.ts +14 -1
- package/dist/chat-decide.js +12 -6
- package/dist/chat-delivery-state.d.ts +12 -70
- package/dist/chat-delivery-state.js +17 -135
- package/dist/chat-delivery.js +58 -30
- package/dist/chat-flow.js +8 -6
- package/dist/chat-inbox.js +1 -1
- package/dist/coding-context.d.ts +2 -39
- package/dist/coding-context.js +2 -1
- package/dist/coding-handoff.d.ts +6 -25
- package/dist/coding-handoff.js +11 -5
- package/dist/coding-types.d.ts +2 -26
- package/dist/coding-workspace.d.ts +2 -0
- package/dist/coding-workspace.js +50 -14
- package/dist/contracts/acceptance-terms.d.ts +14 -0
- package/dist/contracts/acceptance-terms.js +16 -0
- package/dist/contracts/chat-actions.d.ts +328 -0
- package/dist/contracts/chat-actions.js +133 -0
- package/dist/contracts/chat-callback-rows.d.ts +59 -0
- package/dist/contracts/chat-callback-rows.js +46 -0
- package/dist/contracts/chat-content.d.ts +276 -0
- package/dist/contracts/chat-content.js +127 -0
- package/dist/contracts/chat-tables.d.ts +6 -0
- package/dist/contracts/chat-tables.js +136 -0
- package/dist/contracts/coding-context.d.ts +97 -0
- package/dist/contracts/coding-context.js +60 -0
- package/dist/contracts/coding-handoff.d.ts +44 -0
- package/dist/contracts/coding-handoff.js +47 -0
- package/dist/contracts/coding-workspace.d.ts +165 -0
- package/dist/contracts/coding-workspace.js +71 -0
- package/dist/contracts/contract.d.ts +40 -7
- package/dist/contracts/contract.js +155 -19
- package/dist/contracts/decision.d.ts +45 -0
- package/dist/contracts/decision.js +45 -0
- package/dist/contracts/discord-callback.d.ts +45 -0
- package/dist/contracts/discord-callback.js +34 -0
- package/dist/contracts/flow-card.d.ts +50 -0
- package/dist/contracts/flow-card.js +46 -0
- package/dist/contracts/flow-propose.d.ts +325 -0
- package/dist/contracts/flow-propose.js +41 -0
- package/dist/contracts/flow-send.d.ts +119 -0
- package/dist/contracts/flow-send.js +112 -0
- package/dist/contracts/flow.d.ts +19405 -0
- package/dist/contracts/flow.js +364 -0
- package/dist/contracts/gateway-tools.d.ts +374 -0
- package/dist/contracts/gateway-tools.js +94 -0
- package/dist/contracts/handoff.d.ts +91 -0
- package/dist/contracts/handoff.js +82 -0
- package/dist/contracts/lead-context.d.ts +165 -0
- package/dist/contracts/lead-context.js +73 -0
- package/dist/contracts/lead-tools.d.ts +1905 -0
- package/dist/contracts/lead-tools.js +265 -0
- package/dist/contracts/memory-pass.d.ts +158 -0
- package/dist/contracts/memory-pass.js +102 -0
- package/dist/contracts/project-knowledge.d.ts +126 -0
- package/dist/contracts/project-knowledge.js +93 -0
- package/dist/contracts/project-memory.d.ts +117 -0
- package/dist/contracts/project-memory.js +51 -0
- package/dist/contracts/project-skills.d.ts +121 -0
- package/dist/contracts/project-skills.js +76 -0
- package/dist/contracts/proof.d.ts +136 -0
- package/dist/contracts/proof.js +110 -0
- package/dist/contracts/review-findings.d.ts +46 -0
- package/dist/contracts/review-findings.js +48 -0
- package/dist/contracts/route.d.ts +484 -0
- package/dist/contracts/route.js +128 -0
- package/dist/contracts/scope.d.ts +105 -0
- package/dist/contracts/scope.js +114 -0
- package/dist/contracts/scout-report.d.ts +234 -0
- package/dist/contracts/scout-report.js +141 -0
- package/dist/contracts/slack-callback.d.ts +43 -0
- package/dist/contracts/slack-callback.js +35 -0
- package/dist/contracts/sort-answer.d.ts +83 -0
- package/dist/contracts/sort-answer.js +77 -0
- package/dist/contracts/stage-output.d.ts +127 -0
- package/dist/contracts/stage-output.js +166 -0
- package/dist/contracts/task-sizing.d.ts +24 -0
- package/dist/contracts/task-sizing.js +28 -0
- package/dist/contracts/teammate-turn.d.ts +43 -0
- package/dist/contracts/teammate-turn.js +51 -0
- package/dist/contracts/teams-callback.d.ts +14 -0
- package/dist/contracts/teams-callback.js +14 -0
- package/dist/contracts/telegram-callback.d.ts +120 -0
- package/dist/contracts/telegram-callback.js +97 -0
- package/dist/contracts/verification-receipt.d.ts +148 -0
- package/dist/contracts/verification-receipt.js +87 -0
- package/dist/decision.d.ts +11 -20
- package/dist/decision.js +86 -167
- package/dist/demo.js +28 -11
- package/dist/discord-chat.js +31 -20
- package/dist/evidence.d.ts +3 -40
- package/dist/evidence.js +5 -1
- package/dist/flow-engine.js +14 -17
- package/dist/flow-gallery.d.ts +3 -2
- package/dist/flow-items.d.ts +4 -13
- package/dist/flow-items.js +1 -15
- package/dist/flow-send.d.ts +6 -37
- package/dist/flow-send.js +18 -14
- package/dist/flow-share.d.ts +10 -32
- package/dist/flow-share.js +72 -84
- package/dist/flow-sort.d.ts +7 -26
- package/dist/flow-sort.js +25 -20
- package/dist/flow-starters.d.ts +2 -1
- package/dist/flow-steps.js +3 -2
- package/dist/flow-triggers.d.ts +15 -72
- package/dist/flow-triggers.js +94 -83
- package/dist/flows.d.ts +37 -220
- package/dist/flows.js +356 -387
- package/dist/invoke.js +4 -4
- package/dist/lead-context.d.ts +4 -2
- package/dist/lead-context.js +24 -17
- package/dist/mate-tools.d.ts +4 -0
- package/dist/mate-tools.js +111 -308
- package/dist/mcp-connect.d.ts +27 -4
- package/dist/mcp-connect.js +92 -17
- package/dist/mcp.js +84 -216
- package/dist/memory-pass.d.ts +17 -42
- package/dist/memory-pass.js +54 -26
- package/dist/operate.js +31 -2
- package/dist/phase-routing.d.ts +19 -72
- package/dist/phase-routing.js +34 -164
- package/dist/plan.d.ts +5 -5
- package/dist/plan.js +5 -25
- package/dist/process-recovery-eligibility.d.ts +2 -2
- package/dist/process-recovery-eligibility.js +13 -8
- package/dist/project-knowledge.d.ts +16 -35
- package/dist/project-knowledge.js +42 -21
- package/dist/project-memory.d.ts +2 -28
- package/dist/project-memory.js +28 -13
- package/dist/project-skills.d.ts +16 -38
- package/dist/project-skills.js +41 -32
- package/dist/project-tools.d.ts +1 -0
- package/dist/project-tools.js +4 -4
- package/dist/proof.d.ts +15 -91
- package/dist/proof.js +90 -249
- package/dist/provider.d.ts +2 -0
- package/dist/provider.js +4 -16
- package/dist/result-evidence-readers.d.ts +42 -0
- package/dist/result-evidence-readers.js +91 -0
- package/dist/result-shots.d.ts +1 -1
- package/dist/result-shots.js +2 -1
- package/dist/review-switch.d.ts +3 -8
- package/dist/reviewer.d.ts +8 -12
- package/dist/reviewer.js +11 -35
- package/dist/scope.d.ts +21 -43
- package/dist/scope.js +42 -128
- package/dist/scout-report.d.ts +9 -194
- package/dist/scout-report.js +113 -264
- package/dist/scout.js +15 -11
- package/dist/serve.js +17 -101
- package/dist/slack-chat.js +26 -20
- package/dist/slack-state.js +2 -1
- package/dist/store.d.ts +9 -32
- package/dist/store.js +18 -15
- package/dist/structured-output.js +2 -1
- package/dist/subscription-chat.d.ts +4 -0
- package/dist/subscription-chat.js +4 -1
- package/dist/surface.js +8 -1
- package/dist/task-review-brief.d.ts +69 -0
- package/dist/task-review-brief.js +179 -0
- package/dist/task-sizing.d.ts +3 -27
- package/dist/task-sizing.js +11 -26
- package/dist/task-text.d.ts +0 -5
- package/dist/task-text.js +1 -3
- package/dist/teammate-question.js +7 -5
- package/dist/teammate-work.js +9 -5
- package/dist/teammates.d.ts +13 -64
- package/dist/teammates.js +32 -33
- package/dist/teams-chat.js +20 -11
- package/dist/telegram-flow.js +4 -3
- package/dist/telegram-mate.d.ts +4 -14
- package/dist/telegram-mate.js +8 -7
- package/dist/telegram-team.d.ts +2 -19
- package/dist/telegram.d.ts +1 -1
- package/dist/telegram.js +52 -42
- package/dist/text-limits.d.ts +212 -1
- package/dist/text-limits.js +214 -1
- package/dist/tools-ui.d.ts +2 -1
- package/dist/tools-ui.js +7 -4
- package/dist/verification-evidence.js +24 -12
- package/package.json +1 -1
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The saved side of a chat button: the row its one-time token names. A proposal card's buttons in Slack, Discord and
|
|
3
|
+
* Teams (`chat_action`, read with the part and event it rides) and a result's, plan's, failure's or pull request's own
|
|
4
|
+
* buttons (`chat_decide_action`, chat-decide.ts). SQLite's own CHECKs bound them when written; these say what a
|
|
5
|
+
* reader may rely on, so a row that isn't that is refused by column, never read as a guess.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { type ContractResult } from "./contract.js";
|
|
9
|
+
/** A proposal card's button (chat-delivery.ts), with the part's message and the event's binding, channel and thread. */
|
|
10
|
+
export declare const proposalActionRowSchema: z.ZodObject<{
|
|
11
|
+
token: z.ZodString;
|
|
12
|
+
part: z.ZodInt;
|
|
13
|
+
proposal: z.ZodInt;
|
|
14
|
+
phase: z.ZodEnum<{
|
|
15
|
+
cancel: "cancel";
|
|
16
|
+
confirm: "confirm";
|
|
17
|
+
dismiss: "dismiss";
|
|
18
|
+
yes: "yes";
|
|
19
|
+
}>;
|
|
20
|
+
expires: z.ZodString;
|
|
21
|
+
consumed: z.ZodNullable<z.ZodString>;
|
|
22
|
+
message: z.ZodNullable<z.ZodString>;
|
|
23
|
+
binding: z.ZodNullable<z.ZodInt>;
|
|
24
|
+
channel: z.ZodString;
|
|
25
|
+
thread: z.ZodString;
|
|
26
|
+
}, z.core.$strict>;
|
|
27
|
+
export type ProposalActionRow = z.infer<typeof proposalActionRowSchema>;
|
|
28
|
+
export declare function readProposalActionRow(row: unknown): ContractResult<ProposalActionRow>;
|
|
29
|
+
export declare const DECIDE_ACTS: readonly ["accept", "changes", "retry", "approve", "not-now", "merge"];
|
|
30
|
+
export declare const DECIDE_PHASES: readonly ["offer", "yes", "cancel"];
|
|
31
|
+
/** A decide button (chat-decide.ts): who and where it was sent, what it does to which task and run, and the stamp it holds. */
|
|
32
|
+
export declare const decideActionRowSchema: z.ZodObject<{
|
|
33
|
+
token: z.ZodString;
|
|
34
|
+
channel: z.ZodString;
|
|
35
|
+
binding: z.ZodInt;
|
|
36
|
+
chat: z.ZodString;
|
|
37
|
+
message: z.ZodNullable<z.ZodString>;
|
|
38
|
+
act: z.ZodEnum<{
|
|
39
|
+
accept: "accept";
|
|
40
|
+
approve: "approve";
|
|
41
|
+
changes: "changes";
|
|
42
|
+
merge: "merge";
|
|
43
|
+
"not-now": "not-now";
|
|
44
|
+
retry: "retry";
|
|
45
|
+
}>;
|
|
46
|
+
phase: z.ZodEnum<{
|
|
47
|
+
cancel: "cancel";
|
|
48
|
+
offer: "offer";
|
|
49
|
+
yes: "yes";
|
|
50
|
+
}>;
|
|
51
|
+
task_id: z.ZodString;
|
|
52
|
+
run: z.ZodNullable<z.ZodInt>;
|
|
53
|
+
digest: z.ZodString;
|
|
54
|
+
created_at: z.ZodString;
|
|
55
|
+
expires_at: z.ZodString;
|
|
56
|
+
consumed_at: z.ZodNullable<z.ZodString>;
|
|
57
|
+
}, z.core.$strict>;
|
|
58
|
+
export type DecideActionRow = z.infer<typeof decideActionRowSchema>;
|
|
59
|
+
export declare function readDecideActionRow(row: unknown): ContractResult<DecideActionRow>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The saved side of a chat button: the row its one-time token names. A proposal card's buttons in Slack, Discord and
|
|
3
|
+
* Teams (`chat_action`, read with the part and event it rides) and a result's, plan's, failure's or pull request's own
|
|
4
|
+
* buttons (`chat_decide_action`, chat-decide.ts). SQLite's own CHECKs bound them when written; these say what a
|
|
5
|
+
* reader may rely on, so a row that isn't that is refused by column, never read as a guess.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import { parseContract } from "./contract.js";
|
|
9
|
+
const when = z.string();
|
|
10
|
+
/** A proposal card's button (chat-delivery.ts), with the part's message and the event's binding, channel and thread. */
|
|
11
|
+
export const proposalActionRowSchema = z.strictObject({
|
|
12
|
+
token: z.string(),
|
|
13
|
+
part: z.int(),
|
|
14
|
+
proposal: z.int(),
|
|
15
|
+
phase: z.enum(["confirm", "dismiss", "yes", "cancel"]),
|
|
16
|
+
expires: when,
|
|
17
|
+
consumed: when.nullable(),
|
|
18
|
+
message: z.string().nullable(),
|
|
19
|
+
binding: z.int().nullable(),
|
|
20
|
+
channel: z.string(),
|
|
21
|
+
thread: z.string(),
|
|
22
|
+
});
|
|
23
|
+
export function readProposalActionRow(row) {
|
|
24
|
+
return parseContract(proposalActionRowSchema, row);
|
|
25
|
+
}
|
|
26
|
+
export const DECIDE_ACTS = ["accept", "changes", "retry", "approve", "not-now", "merge"];
|
|
27
|
+
export const DECIDE_PHASES = ["offer", "yes", "cancel"];
|
|
28
|
+
/** A decide button (chat-decide.ts): who and where it was sent, what it does to which task and run, and the stamp it holds. */
|
|
29
|
+
export const decideActionRowSchema = z.strictObject({
|
|
30
|
+
token: z.string().regex(/^d:[a-f0-9]{24}$/),
|
|
31
|
+
channel: z.string(),
|
|
32
|
+
binding: z.int(),
|
|
33
|
+
chat: z.string(),
|
|
34
|
+
message: z.string().nullable(),
|
|
35
|
+
act: z.enum(DECIDE_ACTS),
|
|
36
|
+
phase: z.enum(DECIDE_PHASES),
|
|
37
|
+
task_id: z.string(),
|
|
38
|
+
run: z.int().nullable(),
|
|
39
|
+
digest: z.string(),
|
|
40
|
+
created_at: when,
|
|
41
|
+
expires_at: when,
|
|
42
|
+
consumed_at: when.nullable(),
|
|
43
|
+
});
|
|
44
|
+
export function readDecideActionRow(row) {
|
|
45
|
+
return parseContract(decideActionRowSchema, row);
|
|
46
|
+
}
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What Slack, Discord and Teams keep between steps (chat-delivery-state.ts): one schema for a received event's body
|
|
3
|
+
* (`chat_event.payload`, by the event's kind) and one for a planned message part (`chat_part.payload`), the message a
|
|
4
|
+
* button rides and the content a delivery repaints. Both are saved with `version`; a body or part saved before they
|
|
5
|
+
* carried one reads as it did then (its known fields; a reader then passed any others by unread).
|
|
6
|
+
*
|
|
7
|
+
* An event body lives only until the event is handled (then it is `{}`); a part lives as long as its message.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
import { type ContractResult } from "./contract.js";
|
|
11
|
+
/** One planned message part, as delivery reads it. */
|
|
12
|
+
export declare const chatContentShape: {
|
|
13
|
+
text: z.ZodString;
|
|
14
|
+
/** Where the part is sent when not the binding's own DM: a room's channel. */
|
|
15
|
+
channel: z.ZodOptional<z.ZodString>;
|
|
16
|
+
proposal: z.ZodOptional<z.ZodInt>;
|
|
17
|
+
image: z.ZodOptional<z.ZodObject<{
|
|
18
|
+
taskId: z.ZodString;
|
|
19
|
+
run: z.ZodInt;
|
|
20
|
+
artifact: z.ZodInt;
|
|
21
|
+
sha256: z.ZodString;
|
|
22
|
+
}, z.core.$strict>>;
|
|
23
|
+
/** A screenshot sent with a result (result-shots.ts): it follows that result's message part, in its thread when
|
|
24
|
+
* the app allows; a refused upload becomes one plain line, and one removed by retention goes quietly. */
|
|
25
|
+
shot: z.ZodOptional<z.ZodObject<{
|
|
26
|
+
follows: z.ZodNullable<z.ZodInt>;
|
|
27
|
+
}, z.core.$strict>>;
|
|
28
|
+
task: z.ZodOptional<z.ZodString>;
|
|
29
|
+
run: z.ZodOptional<z.ZodInt>;
|
|
30
|
+
edit: z.ZodOptional<z.ZodString>;
|
|
31
|
+
phase: z.ZodOptional<z.ZodLiteral<"armed">>;
|
|
32
|
+
link: z.ZodOptional<z.ZodObject<{
|
|
33
|
+
label: z.ZodString;
|
|
34
|
+
path: z.ZodString;
|
|
35
|
+
}, z.core.$strict>>;
|
|
36
|
+
/** More link buttons after `link`: [Look first] beside [Merge] or [Accept and finish]. */
|
|
37
|
+
also: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
38
|
+
label: z.ZodString;
|
|
39
|
+
path: z.ZodString;
|
|
40
|
+
}, z.core.$strict>>>;
|
|
41
|
+
/** A flow decision's buttons ride this part (v88): minted when it is planned. */
|
|
42
|
+
flow: z.ZodOptional<z.ZodObject<{
|
|
43
|
+
card: z.ZodInt;
|
|
44
|
+
entry: z.ZodInt;
|
|
45
|
+
actions: z.ZodArray<z.ZodEnum<{
|
|
46
|
+
approve: "approve";
|
|
47
|
+
edit: "edit";
|
|
48
|
+
"send-back": "send-back";
|
|
49
|
+
}>>;
|
|
50
|
+
}, z.core.$strict>>;
|
|
51
|
+
/** A flow's "Person chooses" buttons ride this part: minted when it is planned. */
|
|
52
|
+
choose: z.ZodOptional<z.ZodObject<{
|
|
53
|
+
card: z.ZodInt;
|
|
54
|
+
entry: z.ZodInt;
|
|
55
|
+
options: z.ZodArray<z.ZodObject<{
|
|
56
|
+
choice: z.ZodInt;
|
|
57
|
+
label: z.ZodString;
|
|
58
|
+
}, z.core.$strict>>;
|
|
59
|
+
}, z.core.$strict>>;
|
|
60
|
+
/** "Use this as your note?" Yes / No about the person's message `held` (an event id), for one choice's visit. */
|
|
61
|
+
note: z.ZodOptional<z.ZodObject<{
|
|
62
|
+
card: z.ZodInt;
|
|
63
|
+
entry: z.ZodInt;
|
|
64
|
+
held: z.ZodString;
|
|
65
|
+
}, z.core.$strict>>;
|
|
66
|
+
/** A teammate's question's buttons ride this part (v93): each option, then one to answer in words (choice null). */
|
|
67
|
+
question: z.ZodOptional<z.ZodObject<{
|
|
68
|
+
id: z.ZodInt;
|
|
69
|
+
choices: z.ZodArray<z.ZodObject<{
|
|
70
|
+
choice: z.ZodNullable<z.ZodString>;
|
|
71
|
+
label: z.ZodString;
|
|
72
|
+
}, z.core.$strict>>;
|
|
73
|
+
}, z.core.$strict>>;
|
|
74
|
+
/** The lead's question to its owner rides this part: its options, then "Something else". */
|
|
75
|
+
ask: z.ZodOptional<z.ZodObject<{
|
|
76
|
+
turn: z.ZodInt;
|
|
77
|
+
options: z.ZodArray<z.ZodString>;
|
|
78
|
+
}, z.core.$strict>>;
|
|
79
|
+
/** The lead's own reply, already shaped (reply-shape.ts): the channel renders its bold anchors and labelled links in its own format. */
|
|
80
|
+
voice: z.ZodOptional<z.ZodLiteral<true>>;
|
|
81
|
+
};
|
|
82
|
+
export declare const chatContentSchema: z.ZodObject<{
|
|
83
|
+
text: z.ZodString;
|
|
84
|
+
channel: z.ZodOptional<z.ZodString>;
|
|
85
|
+
proposal: z.ZodOptional<z.ZodInt>;
|
|
86
|
+
image: z.ZodOptional<z.ZodObject<{
|
|
87
|
+
taskId: z.ZodString;
|
|
88
|
+
run: z.ZodInt;
|
|
89
|
+
artifact: z.ZodInt;
|
|
90
|
+
sha256: z.ZodString;
|
|
91
|
+
}, z.core.$strict>>;
|
|
92
|
+
shot: z.ZodOptional<z.ZodObject<{
|
|
93
|
+
follows: z.ZodNullable<z.ZodInt>;
|
|
94
|
+
}, z.core.$strict>>;
|
|
95
|
+
task: z.ZodOptional<z.ZodString>;
|
|
96
|
+
run: z.ZodOptional<z.ZodInt>;
|
|
97
|
+
edit: z.ZodOptional<z.ZodString>;
|
|
98
|
+
phase: z.ZodOptional<z.ZodLiteral<"armed">>;
|
|
99
|
+
link: z.ZodOptional<z.ZodObject<{
|
|
100
|
+
label: z.ZodString;
|
|
101
|
+
path: z.ZodString;
|
|
102
|
+
}, z.core.$strict>>;
|
|
103
|
+
also: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
104
|
+
label: z.ZodString;
|
|
105
|
+
path: z.ZodString;
|
|
106
|
+
}, z.core.$strict>>>;
|
|
107
|
+
flow: z.ZodOptional<z.ZodObject<{
|
|
108
|
+
card: z.ZodInt;
|
|
109
|
+
entry: z.ZodInt;
|
|
110
|
+
actions: z.ZodArray<z.ZodEnum<{
|
|
111
|
+
approve: "approve";
|
|
112
|
+
edit: "edit";
|
|
113
|
+
"send-back": "send-back";
|
|
114
|
+
}>>;
|
|
115
|
+
}, z.core.$strict>>;
|
|
116
|
+
choose: z.ZodOptional<z.ZodObject<{
|
|
117
|
+
card: z.ZodInt;
|
|
118
|
+
entry: z.ZodInt;
|
|
119
|
+
options: z.ZodArray<z.ZodObject<{
|
|
120
|
+
choice: z.ZodInt;
|
|
121
|
+
label: z.ZodString;
|
|
122
|
+
}, z.core.$strict>>;
|
|
123
|
+
}, z.core.$strict>>;
|
|
124
|
+
note: z.ZodOptional<z.ZodObject<{
|
|
125
|
+
card: z.ZodInt;
|
|
126
|
+
entry: z.ZodInt;
|
|
127
|
+
held: z.ZodString;
|
|
128
|
+
}, z.core.$strict>>;
|
|
129
|
+
question: z.ZodOptional<z.ZodObject<{
|
|
130
|
+
id: z.ZodInt;
|
|
131
|
+
choices: z.ZodArray<z.ZodObject<{
|
|
132
|
+
choice: z.ZodNullable<z.ZodString>;
|
|
133
|
+
label: z.ZodString;
|
|
134
|
+
}, z.core.$strict>>;
|
|
135
|
+
}, z.core.$strict>>;
|
|
136
|
+
ask: z.ZodOptional<z.ZodObject<{
|
|
137
|
+
turn: z.ZodInt;
|
|
138
|
+
options: z.ZodArray<z.ZodString>;
|
|
139
|
+
}, z.core.$strict>>;
|
|
140
|
+
voice: z.ZodOptional<z.ZodLiteral<true>>;
|
|
141
|
+
}, z.core.$strict>;
|
|
142
|
+
export type ChatContent = z.infer<typeof chatContentSchema>;
|
|
143
|
+
export declare const CHAT_PART_VERSION = 1;
|
|
144
|
+
export declare const savedChatPartSchema: z.ZodObject<{
|
|
145
|
+
version: z.ZodLiteral<1>;
|
|
146
|
+
text: z.ZodString;
|
|
147
|
+
channel: z.ZodOptional<z.ZodString>;
|
|
148
|
+
proposal: z.ZodOptional<z.ZodInt>;
|
|
149
|
+
image: z.ZodOptional<z.ZodObject<{
|
|
150
|
+
taskId: z.ZodString;
|
|
151
|
+
run: z.ZodInt;
|
|
152
|
+
artifact: z.ZodInt;
|
|
153
|
+
sha256: z.ZodString;
|
|
154
|
+
}, z.core.$strict>>;
|
|
155
|
+
shot: z.ZodOptional<z.ZodObject<{
|
|
156
|
+
follows: z.ZodNullable<z.ZodInt>;
|
|
157
|
+
}, z.core.$strict>>;
|
|
158
|
+
task: z.ZodOptional<z.ZodString>;
|
|
159
|
+
run: z.ZodOptional<z.ZodInt>;
|
|
160
|
+
edit: z.ZodOptional<z.ZodString>;
|
|
161
|
+
phase: z.ZodOptional<z.ZodLiteral<"armed">>;
|
|
162
|
+
link: z.ZodOptional<z.ZodObject<{
|
|
163
|
+
label: z.ZodString;
|
|
164
|
+
path: z.ZodString;
|
|
165
|
+
}, z.core.$strict>>;
|
|
166
|
+
also: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
167
|
+
label: z.ZodString;
|
|
168
|
+
path: z.ZodString;
|
|
169
|
+
}, z.core.$strict>>>;
|
|
170
|
+
flow: z.ZodOptional<z.ZodObject<{
|
|
171
|
+
card: z.ZodInt;
|
|
172
|
+
entry: z.ZodInt;
|
|
173
|
+
actions: z.ZodArray<z.ZodEnum<{
|
|
174
|
+
approve: "approve";
|
|
175
|
+
edit: "edit";
|
|
176
|
+
"send-back": "send-back";
|
|
177
|
+
}>>;
|
|
178
|
+
}, z.core.$strict>>;
|
|
179
|
+
choose: z.ZodOptional<z.ZodObject<{
|
|
180
|
+
card: z.ZodInt;
|
|
181
|
+
entry: z.ZodInt;
|
|
182
|
+
options: z.ZodArray<z.ZodObject<{
|
|
183
|
+
choice: z.ZodInt;
|
|
184
|
+
label: z.ZodString;
|
|
185
|
+
}, z.core.$strict>>;
|
|
186
|
+
}, z.core.$strict>>;
|
|
187
|
+
note: z.ZodOptional<z.ZodObject<{
|
|
188
|
+
card: z.ZodInt;
|
|
189
|
+
entry: z.ZodInt;
|
|
190
|
+
held: z.ZodString;
|
|
191
|
+
}, z.core.$strict>>;
|
|
192
|
+
question: z.ZodOptional<z.ZodObject<{
|
|
193
|
+
id: z.ZodInt;
|
|
194
|
+
choices: z.ZodArray<z.ZodObject<{
|
|
195
|
+
choice: z.ZodNullable<z.ZodString>;
|
|
196
|
+
label: z.ZodString;
|
|
197
|
+
}, z.core.$strict>>;
|
|
198
|
+
}, z.core.$strict>>;
|
|
199
|
+
ask: z.ZodOptional<z.ZodObject<{
|
|
200
|
+
turn: z.ZodInt;
|
|
201
|
+
options: z.ZodArray<z.ZodString>;
|
|
202
|
+
}, z.core.$strict>>;
|
|
203
|
+
voice: z.ZodOptional<z.ZodLiteral<true>>;
|
|
204
|
+
}, z.core.$strict>;
|
|
205
|
+
/** A saved part's content (`version` is the saved form's, not the content's). */
|
|
206
|
+
export declare function readChatPart(raw: string): ContractResult<ChatContent>;
|
|
207
|
+
/** A part as it is saved. */
|
|
208
|
+
export declare function savedChatPart(content: ChatContent): string;
|
|
209
|
+
export declare const CHAT_EVENT_VERSION = 1;
|
|
210
|
+
/** `pair <code>`: only the code's hash is kept. */
|
|
211
|
+
export declare const chatPairBodySchema: z.ZodObject<{
|
|
212
|
+
version: z.ZodLiteral<1>;
|
|
213
|
+
hash: z.ZodString;
|
|
214
|
+
}, z.core.$strict>;
|
|
215
|
+
/**
|
|
216
|
+
* A message: its words (cut at the lead's limit, `originalLength` saying how long it was), or a plain line to answer
|
|
217
|
+
* with instead (`unsupported`: a file the app can't take). A room's or notice's carrier event has none. `about` is the
|
|
218
|
+
* task its turn is about, once chosen; `lead` is a held message passed to the lead as it was (chat-flow.ts).
|
|
219
|
+
*/
|
|
220
|
+
export declare const chatMessageBodySchema: z.ZodObject<{
|
|
221
|
+
version: z.ZodLiteral<1>;
|
|
222
|
+
text: z.ZodOptional<z.ZodString>;
|
|
223
|
+
originalLength: z.ZodOptional<z.ZodInt>;
|
|
224
|
+
unsupported: z.ZodOptional<z.ZodString>;
|
|
225
|
+
about: z.ZodOptional<z.ZodObject<{
|
|
226
|
+
task: z.ZodString;
|
|
227
|
+
run: z.ZodNullable<z.ZodInt>;
|
|
228
|
+
}, z.core.$strict>>;
|
|
229
|
+
lead: z.ZodOptional<z.ZodLiteral<true>>;
|
|
230
|
+
}, z.core.$strict>;
|
|
231
|
+
/**
|
|
232
|
+
* A button: the one-time token it carried, or, when the app's callback came from the paired person but its data
|
|
233
|
+
* couldn't be read, the path-named line saying why — answered plainly, and nothing is done.
|
|
234
|
+
*/
|
|
235
|
+
export declare const chatTokenBodySchema: z.ZodObject<{
|
|
236
|
+
version: z.ZodLiteral<1>;
|
|
237
|
+
token: z.ZodString;
|
|
238
|
+
}, z.core.$strict>;
|
|
239
|
+
export declare const chatProblemBodySchema: z.ZodObject<{
|
|
240
|
+
version: z.ZodLiteral<1>;
|
|
241
|
+
problem: z.ZodString;
|
|
242
|
+
}, z.core.$strict>;
|
|
243
|
+
export declare const chatActionBodySchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
244
|
+
version: z.ZodLiteral<1>;
|
|
245
|
+
token: z.ZodString;
|
|
246
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
247
|
+
version: z.ZodLiteral<1>;
|
|
248
|
+
problem: z.ZodString;
|
|
249
|
+
}, z.core.$strict>]>;
|
|
250
|
+
/** A notice carries its parts, not a body. */
|
|
251
|
+
export declare const chatNoticeBodySchema: z.ZodObject<{
|
|
252
|
+
version: z.ZodLiteral<1>;
|
|
253
|
+
}, z.core.$strict>;
|
|
254
|
+
export type ChatPairBody = z.infer<typeof chatPairBodySchema>;
|
|
255
|
+
export type ChatMessageBody = z.infer<typeof chatMessageBodySchema>;
|
|
256
|
+
export type ChatActionBody = z.infer<typeof chatActionBodySchema>;
|
|
257
|
+
/** What a writer hands `ChatState.enqueue`: a body of the event's kind, without `version` (it is stamped on saving). */
|
|
258
|
+
export type ChatEventBody = Omit<ChatPairBody, "version"> | Omit<ChatMessageBody, "version"> | {
|
|
259
|
+
token: string;
|
|
260
|
+
} | {
|
|
261
|
+
problem: string;
|
|
262
|
+
} | Record<string, never>;
|
|
263
|
+
export declare function savedChatEventBody(body: ChatEventBody): string;
|
|
264
|
+
/** A pair event's body. */
|
|
265
|
+
export declare function readChatPairBody(raw: string): ContractResult<ChatPairBody>;
|
|
266
|
+
/** A message event's body. */
|
|
267
|
+
export declare function readChatMessageBody(raw: string): ContractResult<ChatMessageBody>;
|
|
268
|
+
/** An action event's body: a token, or the reason its callback couldn't be read. */
|
|
269
|
+
export declare function readChatActionBody(raw: string): ContractResult<ChatActionBody>;
|
|
270
|
+
/** Words held for "Use this as your note?" (`chat_flow_note.words`): the held message's own text and length. */
|
|
271
|
+
export declare const heldWordsSchema: z.ZodObject<{
|
|
272
|
+
text: z.ZodString;
|
|
273
|
+
originalLength: z.ZodOptional<z.ZodInt>;
|
|
274
|
+
}, z.core.$strict>;
|
|
275
|
+
export type HeldWords = z.infer<typeof heldWordsSchema>;
|
|
276
|
+
export declare function readHeldWords(raw: string): ContractResult<HeldWords>;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What Slack, Discord and Teams keep between steps (chat-delivery-state.ts): one schema for a received event's body
|
|
3
|
+
* (`chat_event.payload`, by the event's kind) and one for a planned message part (`chat_part.payload`), the message a
|
|
4
|
+
* button rides and the content a delivery repaints. Both are saved with `version`; a body or part saved before they
|
|
5
|
+
* carried one reads as it did then (its known fields; a reader then passed any others by unread).
|
|
6
|
+
*
|
|
7
|
+
* An event body lives only until the event is handled (then it is `{}`); a part lives as long as its message.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
import { parseContract, readVersioned, versioned } from "./contract.js";
|
|
11
|
+
const id = z.int().min(1);
|
|
12
|
+
const link = z.strictObject({ label: z.string(), path: z.string() });
|
|
13
|
+
/** One planned message part, as delivery reads it. */
|
|
14
|
+
export const chatContentShape = {
|
|
15
|
+
text: z.string(),
|
|
16
|
+
/** Where the part is sent when not the binding's own DM: a room's channel. */
|
|
17
|
+
channel: z.string().optional(),
|
|
18
|
+
proposal: id.optional(),
|
|
19
|
+
image: z.strictObject({ taskId: z.string(), run: z.int(), artifact: z.int(), sha256: z.string() }).optional(),
|
|
20
|
+
/** A screenshot sent with a result (result-shots.ts): it follows that result's message part, in its thread when
|
|
21
|
+
* the app allows; a refused upload becomes one plain line, and one removed by retention goes quietly. */
|
|
22
|
+
shot: z.strictObject({ follows: z.int().nullable() }).optional(),
|
|
23
|
+
task: z.string().optional(),
|
|
24
|
+
run: z.int().optional(),
|
|
25
|
+
edit: z.string().optional(),
|
|
26
|
+
phase: z.literal("armed").optional(),
|
|
27
|
+
link: link.optional(),
|
|
28
|
+
/** More link buttons after `link`: [Look first] beside [Merge] or [Accept and finish]. */
|
|
29
|
+
also: z.array(link).optional(),
|
|
30
|
+
/** A flow decision's buttons ride this part (v88): minted when it is planned. */
|
|
31
|
+
flow: z.strictObject({ card: id, entry: z.int(), actions: z.array(z.enum(["approve", "edit", "send-back"])) }).optional(),
|
|
32
|
+
/** A flow's "Person chooses" buttons ride this part: minted when it is planned. */
|
|
33
|
+
choose: z.strictObject({ card: id, entry: z.int(), options: z.array(z.strictObject({ choice: z.int(), label: z.string() })) }).optional(),
|
|
34
|
+
/** "Use this as your note?" Yes / No about the person's message `held` (an event id), for one choice's visit. */
|
|
35
|
+
note: z.strictObject({ card: id, entry: z.int(), held: z.string() }).optional(),
|
|
36
|
+
/** A teammate's question's buttons ride this part (v93): each option, then one to answer in words (choice null). */
|
|
37
|
+
question: z.strictObject({ id, choices: z.array(z.strictObject({ choice: z.string().nullable(), label: z.string() })) }).optional(),
|
|
38
|
+
/** The lead's question to its owner rides this part: its options, then "Something else". */
|
|
39
|
+
ask: z.strictObject({ turn: id, options: z.array(z.string()) }).optional(),
|
|
40
|
+
/** The lead's own reply, already shaped (reply-shape.ts): the channel renders its bold anchors and labelled links in its own format. */
|
|
41
|
+
voice: z.literal(true).optional(),
|
|
42
|
+
};
|
|
43
|
+
export const chatContentSchema = z.strictObject(chatContentShape);
|
|
44
|
+
export const CHAT_PART_VERSION = 1;
|
|
45
|
+
export const savedChatPartSchema = versioned(CHAT_PART_VERSION, chatContentShape);
|
|
46
|
+
/** A saved body or part from before `version`, as version `version`: the fields its schema knows, nothing else. */
|
|
47
|
+
function knownFields(version, fields) {
|
|
48
|
+
return (body) => {
|
|
49
|
+
const out = { version };
|
|
50
|
+
for (const field of fields)
|
|
51
|
+
if (Object.hasOwn(body, field))
|
|
52
|
+
out[field] = body[field];
|
|
53
|
+
return out;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const PART_UPGRADES = { 0: knownFields(CHAT_PART_VERSION, Object.keys(chatContentShape)) };
|
|
57
|
+
/** JSON text, then the schema; `payload: not JSON` for bytes that aren't. */
|
|
58
|
+
function fromJson(raw, read) {
|
|
59
|
+
let body;
|
|
60
|
+
try {
|
|
61
|
+
body = JSON.parse(raw);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
return { ok: false, issues: [{ path: "payload", kind: "invalid", line: "payload: not JSON" }] };
|
|
65
|
+
}
|
|
66
|
+
return read(body);
|
|
67
|
+
}
|
|
68
|
+
/** A saved part's content (`version` is the saved form's, not the content's). */
|
|
69
|
+
export function readChatPart(raw) {
|
|
70
|
+
const read = fromJson(raw, body => readVersioned(savedChatPartSchema, body, PART_UPGRADES));
|
|
71
|
+
if (!read.ok)
|
|
72
|
+
return read;
|
|
73
|
+
const { version: _version, ...content } = read.value;
|
|
74
|
+
return { ok: true, value: content };
|
|
75
|
+
}
|
|
76
|
+
/** A part as it is saved. */
|
|
77
|
+
export function savedChatPart(content) {
|
|
78
|
+
return JSON.stringify({ version: CHAT_PART_VERSION, ...content });
|
|
79
|
+
}
|
|
80
|
+
// ---- event bodies ------------------------------------------------------------------------------------------------
|
|
81
|
+
export const CHAT_EVENT_VERSION = 1;
|
|
82
|
+
/** `pair <code>`: only the code's hash is kept. */
|
|
83
|
+
export const chatPairBodySchema = versioned(CHAT_EVENT_VERSION, { hash: z.string() });
|
|
84
|
+
/**
|
|
85
|
+
* A message: its words (cut at the lead's limit, `originalLength` saying how long it was), or a plain line to answer
|
|
86
|
+
* with instead (`unsupported`: a file the app can't take). A room's or notice's carrier event has none. `about` is the
|
|
87
|
+
* task its turn is about, once chosen; `lead` is a held message passed to the lead as it was (chat-flow.ts).
|
|
88
|
+
*/
|
|
89
|
+
export const chatMessageBodySchema = versioned(CHAT_EVENT_VERSION, {
|
|
90
|
+
text: z.string().optional(),
|
|
91
|
+
originalLength: z.int().min(0).optional(),
|
|
92
|
+
unsupported: z.string().optional(),
|
|
93
|
+
about: z.strictObject({ task: z.string(), run: z.int().nullable() }).optional(),
|
|
94
|
+
lead: z.literal(true).optional(),
|
|
95
|
+
});
|
|
96
|
+
/**
|
|
97
|
+
* A button: the one-time token it carried, or, when the app's callback came from the paired person but its data
|
|
98
|
+
* couldn't be read, the path-named line saying why — answered plainly, and nothing is done.
|
|
99
|
+
*/
|
|
100
|
+
export const chatTokenBodySchema = versioned(CHAT_EVENT_VERSION, { token: z.string().regex(/^[a-f0-9]{32}$/, { error: "must be a Toolroll button token" }) });
|
|
101
|
+
export const chatProblemBodySchema = versioned(CHAT_EVENT_VERSION, { problem: z.string().min(1) });
|
|
102
|
+
export const chatActionBodySchema = z.union([chatTokenBodySchema, chatProblemBodySchema]);
|
|
103
|
+
/** A notice carries its parts, not a body. */
|
|
104
|
+
export const chatNoticeBodySchema = versioned(CHAT_EVENT_VERSION, {});
|
|
105
|
+
export function savedChatEventBody(body) {
|
|
106
|
+
return JSON.stringify({ version: CHAT_EVENT_VERSION, ...body });
|
|
107
|
+
}
|
|
108
|
+
const upgradeBody = (fields) => ({ 0: knownFields(CHAT_EVENT_VERSION, fields) });
|
|
109
|
+
/** A pair event's body. */
|
|
110
|
+
export function readChatPairBody(raw) {
|
|
111
|
+
return fromJson(raw, body => readVersioned(chatPairBodySchema, body, upgradeBody(["hash"])));
|
|
112
|
+
}
|
|
113
|
+
/** A message event's body. */
|
|
114
|
+
export function readChatMessageBody(raw) {
|
|
115
|
+
return fromJson(raw, body => readVersioned(chatMessageBodySchema, body, upgradeBody(Object.keys(chatMessageBodySchema.shape))));
|
|
116
|
+
}
|
|
117
|
+
/** An action event's body: a token, or the reason its callback couldn't be read. */
|
|
118
|
+
export function readChatActionBody(raw) {
|
|
119
|
+
return fromJson(raw, (body) => typeof body === "object" && body !== null && !Array.isArray(body) && Object.hasOwn(body, "problem")
|
|
120
|
+
? readVersioned(chatProblemBodySchema, body, upgradeBody(["problem"]))
|
|
121
|
+
: readVersioned(chatTokenBodySchema, body, upgradeBody(["token"])));
|
|
122
|
+
}
|
|
123
|
+
/** Words held for "Use this as your note?" (`chat_flow_note.words`): the held message's own text and length. */
|
|
124
|
+
export const heldWordsSchema = z.strictObject({ text: z.string(), originalLength: z.int().min(0).optional() });
|
|
125
|
+
export function readHeldWords(raw) {
|
|
126
|
+
return fromJson(raw, body => parseContract(heldWordsSchema, body));
|
|
127
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Slack, Discord and Teams receipt tables (chat-delivery-state.ts keeps their rows). A leaf: it imports nothing, so
|
|
3
|
+
* the store can create these tables without loading the chat state modules that themselves import the store.
|
|
4
|
+
*/
|
|
5
|
+
export declare const chatSchema: (channel: "slack" | "discord" | "teams") => string;
|
|
6
|
+
export declare const chatTables: (channel: "slack" | "discord" | "teams") => string[];
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Slack, Discord and Teams receipt tables (chat-delivery-state.ts keeps their rows). A leaf: it imports nothing, so
|
|
3
|
+
* the store can create these tables without loading the chat state modules that themselves import the store.
|
|
4
|
+
*/
|
|
5
|
+
const CHAT_SCHEMA = `
|
|
6
|
+
CREATE TABLE IF NOT EXISTS chat_binding (
|
|
7
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, installation TEXT NOT NULL,
|
|
8
|
+
team TEXT NOT NULL, app TEXT NOT NULL, member TEXT NOT NULL, channel TEXT NOT NULL,
|
|
9
|
+
approver TEXT NOT NULL, generation INTEGER NOT NULL, created TEXT NOT NULL, revoked TEXT
|
|
10
|
+
);
|
|
11
|
+
CREATE UNIQUE INDEX IF NOT EXISTS chat_one_binding_member ON chat_binding(installation, member) WHERE revoked IS NULL;
|
|
12
|
+
CREATE TABLE IF NOT EXISTS chat_pair (
|
|
13
|
+
hash TEXT PRIMARY KEY, installation TEXT NOT NULL, approver TEXT NOT NULL,
|
|
14
|
+
generation INTEGER NOT NULL, expires TEXT NOT NULL, consumed TEXT
|
|
15
|
+
);
|
|
16
|
+
CREATE TABLE IF NOT EXISTS chat_event (
|
|
17
|
+
id TEXT PRIMARY KEY, installation TEXT NOT NULL, binding INTEGER REFERENCES chat_binding(id),
|
|
18
|
+
kind TEXT NOT NULL CHECK(kind IN ('message','action','pair','notice')),
|
|
19
|
+
channel TEXT NOT NULL, member TEXT NOT NULL, ts TEXT NOT NULL, thread TEXT NOT NULL,
|
|
20
|
+
payload TEXT NOT NULL, created TEXT NOT NULL,
|
|
21
|
+
session INTEGER REFERENCES mate_session(id), state TEXT NOT NULL DEFAULT 'queued' CHECK(state IN ('queued','done','dropped')),
|
|
22
|
+
next_at TEXT, problem TEXT
|
|
23
|
+
);
|
|
24
|
+
CREATE INDEX IF NOT EXISTS chat_pending_event ON chat_event(installation,state,next_at);
|
|
25
|
+
CREATE TABLE IF NOT EXISTS chat_part (
|
|
26
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, event TEXT NOT NULL REFERENCES chat_event(id), ordinal INTEGER NOT NULL,
|
|
27
|
+
payload TEXT NOT NULL, state TEXT NOT NULL DEFAULT 'pending' CHECK(state IN ('pending','sent','dropped')),
|
|
28
|
+
message TEXT, file TEXT, uploaded INTEGER NOT NULL DEFAULT 0, attempts INTEGER NOT NULL DEFAULT 0,
|
|
29
|
+
uncertain INTEGER NOT NULL DEFAULT 0, next_at TEXT, problem TEXT, created TEXT NOT NULL,
|
|
30
|
+
UNIQUE(event,ordinal)
|
|
31
|
+
);
|
|
32
|
+
CREATE TABLE IF NOT EXISTS chat_action (
|
|
33
|
+
token TEXT PRIMARY KEY, part INTEGER NOT NULL REFERENCES chat_part(id),
|
|
34
|
+
proposal INTEGER NOT NULL REFERENCES mate_proposal(id), phase TEXT NOT NULL CHECK(phase IN ('confirm','dismiss','yes','cancel')),
|
|
35
|
+
expires TEXT NOT NULL, consumed TEXT
|
|
36
|
+
);
|
|
37
|
+
CREATE TABLE IF NOT EXISTS chat_progress (
|
|
38
|
+
binding INTEGER NOT NULL REFERENCES chat_binding(id), run INTEGER NOT NULL REFERENCES run(id),
|
|
39
|
+
part INTEGER NOT NULL REFERENCES chat_part(id), digest TEXT NOT NULL,
|
|
40
|
+
PRIMARY KEY(binding,run)
|
|
41
|
+
);
|
|
42
|
+
CREATE TABLE IF NOT EXISTS chat_runtime (
|
|
43
|
+
installation TEXT PRIMARY KEY, owner TEXT, lease_until TEXT, connected TEXT,
|
|
44
|
+
problem TEXT, retry_at TEXT, notification INTEGER NOT NULL DEFAULT 0
|
|
45
|
+
);
|
|
46
|
+
`;
|
|
47
|
+
/** v73: a chat's place in the shared team conversations — a channel follows one
|
|
48
|
+
* conversation, a DM may select one. Rows are revoked, never deleted. */
|
|
49
|
+
const CHAT_ROOM_SCHEMA = `
|
|
50
|
+
CREATE TABLE IF NOT EXISTS chat_room (
|
|
51
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, installation TEXT NOT NULL, chat TEXT NOT NULL,
|
|
52
|
+
kind TEXT NOT NULL CHECK(kind IN ('group','private')), conversation TEXT NOT NULL,
|
|
53
|
+
binding INTEGER NOT NULL REFERENCES chat_binding(id),
|
|
54
|
+
bound_by TEXT NOT NULL, bound TEXT NOT NULL, cursor INTEGER NOT NULL DEFAULT 0,
|
|
55
|
+
revoked TEXT, revoked_by TEXT
|
|
56
|
+
);
|
|
57
|
+
CREATE UNIQUE INDEX IF NOT EXISTS chat_room_live ON chat_room(installation, chat) WHERE revoked IS NULL;
|
|
58
|
+
CREATE UNIQUE INDEX IF NOT EXISTS chat_room_group ON chat_room(conversation) WHERE revoked IS NULL AND kind='group';
|
|
59
|
+
CREATE TABLE IF NOT EXISTS chat_meta (
|
|
60
|
+
installation TEXT NOT NULL, key TEXT NOT NULL, value TEXT NOT NULL, updated TEXT NOT NULL,
|
|
61
|
+
PRIMARY KEY(installation, key)
|
|
62
|
+
);
|
|
63
|
+
`;
|
|
64
|
+
/** v88: flow decisions in the chat app, as on Telegram (telegram-flow.ts).
|
|
65
|
+
* A button is one opaque token for one visit (card, entry) of one card, on
|
|
66
|
+
* the part it rides; Edit and Send back open a prompt the person's next
|
|
67
|
+
* message in their DM answers. */
|
|
68
|
+
const CHAT_FLOW_SCHEMA = `
|
|
69
|
+
CREATE TABLE IF NOT EXISTS chat_flow_action (
|
|
70
|
+
token TEXT PRIMARY KEY, part INTEGER NOT NULL REFERENCES chat_part(id),
|
|
71
|
+
card INTEGER NOT NULL REFERENCES flow_card(id), entry INTEGER NOT NULL,
|
|
72
|
+
action TEXT NOT NULL CHECK(action IN ('approve','edit','send-back')), expires TEXT NOT NULL, consumed TEXT
|
|
73
|
+
);
|
|
74
|
+
CREATE INDEX IF NOT EXISTS chat_flow_action_visit ON chat_flow_action(card, entry);
|
|
75
|
+
CREATE TABLE IF NOT EXISTS chat_flow_prompt (
|
|
76
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, binding INTEGER NOT NULL REFERENCES chat_binding(id),
|
|
77
|
+
card INTEGER NOT NULL REFERENCES flow_card(id), entry INTEGER NOT NULL,
|
|
78
|
+
mode TEXT NOT NULL CHECK(mode IN ('edit','send-back')), created TEXT NOT NULL, expires TEXT NOT NULL, consumed TEXT
|
|
79
|
+
);
|
|
80
|
+
CREATE INDEX IF NOT EXISTS chat_flow_prompt_open ON chat_flow_prompt(binding, consumed);
|
|
81
|
+
`;
|
|
82
|
+
/** A flow's "Person chooses" zone in the chat app (flow-send.ts): one button per option (choice is its index, label its words
|
|
83
|
+
* when sent) for one visit of one card, on the part it rides. A reply in that notice's thread is the note; chat_flow_note
|
|
84
|
+
* is "Use this as your note?" Yes / No about one other message (held: its event; words: what it said, kept only until
|
|
85
|
+
* answered, as an event's own payload is cleared once it is handled), asked once per visit.
|
|
86
|
+
* Never in CHAT_TABLES: an older database has no such table until this schema creates it. */
|
|
87
|
+
const CHAT_FLOW_CHOICE_SCHEMA = `
|
|
88
|
+
CREATE TABLE IF NOT EXISTS chat_flow_choice (
|
|
89
|
+
token TEXT PRIMARY KEY, part INTEGER NOT NULL REFERENCES chat_part(id),
|
|
90
|
+
card INTEGER NOT NULL REFERENCES flow_card(id), entry INTEGER NOT NULL,
|
|
91
|
+
choice INTEGER NOT NULL, label TEXT NOT NULL, expires TEXT NOT NULL, consumed TEXT
|
|
92
|
+
);
|
|
93
|
+
CREATE INDEX IF NOT EXISTS chat_flow_choice_visit ON chat_flow_choice(card, entry);
|
|
94
|
+
CREATE TABLE IF NOT EXISTS chat_flow_note (
|
|
95
|
+
token TEXT PRIMARY KEY, part INTEGER NOT NULL REFERENCES chat_part(id),
|
|
96
|
+
card INTEGER NOT NULL REFERENCES flow_card(id), entry INTEGER NOT NULL,
|
|
97
|
+
held TEXT NOT NULL, words TEXT, answer TEXT NOT NULL CHECK(answer IN ('yes','no')), expires TEXT NOT NULL, consumed TEXT
|
|
98
|
+
);
|
|
99
|
+
CREATE INDEX IF NOT EXISTS chat_flow_note_visit ON chat_flow_note(card, entry);
|
|
100
|
+
`;
|
|
101
|
+
/** v93: a teammate's question in the chat app. One button per option (choice)
|
|
102
|
+
* and one to answer in words (choice NULL); that one opens a prompt the
|
|
103
|
+
* person's next message in their DM answers. Never in CHAT_TABLES: an older
|
|
104
|
+
* database has no such tables until this schema creates them. */
|
|
105
|
+
const CHAT_QUESTION_SCHEMA = `
|
|
106
|
+
CREATE TABLE IF NOT EXISTS chat_question_action (
|
|
107
|
+
token TEXT PRIMARY KEY, part INTEGER NOT NULL REFERENCES chat_part(id),
|
|
108
|
+
question INTEGER NOT NULL REFERENCES teammate_question(id), choice TEXT, expires TEXT NOT NULL, consumed TEXT
|
|
109
|
+
);
|
|
110
|
+
CREATE INDEX IF NOT EXISTS chat_question_action_question ON chat_question_action(question);
|
|
111
|
+
CREATE TABLE IF NOT EXISTS chat_question_prompt (
|
|
112
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT, binding INTEGER NOT NULL REFERENCES chat_binding(id),
|
|
113
|
+
question INTEGER NOT NULL REFERENCES teammate_question(id), created TEXT NOT NULL, expires TEXT NOT NULL, consumed TEXT
|
|
114
|
+
);
|
|
115
|
+
CREATE INDEX IF NOT EXISTS chat_question_prompt_open ON chat_question_prompt(binding, consumed);
|
|
116
|
+
`;
|
|
117
|
+
/** The lead's question to its owner (ask_owner) in the chat app: one button per option (choice is its index) and one for
|
|
118
|
+
* "Something else" (choice NULL). A tap sends the option as the owner's next message. Never in CHAT_TABLES. */
|
|
119
|
+
const CHAT_ASK_SCHEMA = `
|
|
120
|
+
CREATE TABLE IF NOT EXISTS chat_ask_action (
|
|
121
|
+
token TEXT PRIMARY KEY, part INTEGER NOT NULL REFERENCES chat_part(id) ON DELETE CASCADE,
|
|
122
|
+
turn INTEGER NOT NULL, choice INTEGER, expires TEXT NOT NULL, consumed TEXT
|
|
123
|
+
);
|
|
124
|
+
CREATE INDEX IF NOT EXISTS chat_ask_action_turn ON chat_ask_action(turn);
|
|
125
|
+
`;
|
|
126
|
+
const CHAT_TABLES = [
|
|
127
|
+
"chat_binding",
|
|
128
|
+
"chat_pair",
|
|
129
|
+
"chat_event",
|
|
130
|
+
"chat_part",
|
|
131
|
+
"chat_action",
|
|
132
|
+
"chat_progress",
|
|
133
|
+
"chat_runtime",
|
|
134
|
+
];
|
|
135
|
+
export const chatSchema = (channel) => (CHAT_SCHEMA + CHAT_ROOM_SCHEMA + CHAT_FLOW_SCHEMA + CHAT_FLOW_CHOICE_SCHEMA + CHAT_QUESTION_SCHEMA + CHAT_ASK_SCHEMA).replaceAll("chat_", `${channel}_`);
|
|
136
|
+
export const chatTables = (channel) => CHAT_TABLES.map((name) => name.replace("chat_", `${channel}_`));
|