toolroll 0.9.41 → 0.9.43

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 (89) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/chat-actions.js +1 -1
  3. package/dist/chat-approval.d.ts +45 -0
  4. package/dist/chat-approval.js +81 -0
  5. package/dist/chat-channel.js +5 -0
  6. package/dist/chat-decide.d.ts +18 -6
  7. package/dist/chat-decide.js +54 -20
  8. package/dist/chat-flow.js +2 -2
  9. package/dist/cli.js +4 -2
  10. package/dist/coding-types.d.ts +2 -24
  11. package/dist/coding-workspace.js +12 -11
  12. package/dist/contracts/cli.d.ts +736 -0
  13. package/dist/contracts/cli.js +223 -0
  14. package/dist/contracts/coding-activity.d.ts +64 -0
  15. package/dist/contracts/coding-activity.js +58 -0
  16. package/dist/contracts/console-api.d.ts +484 -0
  17. package/dist/contracts/console-api.js +274 -0
  18. package/dist/contracts/diff-stat.d.ts +58 -0
  19. package/dist/contracts/diff-stat.js +59 -0
  20. package/dist/contracts/integration-metadata.d.ts +99 -0
  21. package/dist/contracts/integration-metadata.js +101 -0
  22. package/dist/contracts/lead-tools.d.ts +11 -0
  23. package/dist/contracts/lead-tools.js +2 -0
  24. package/dist/contracts/model-catalog.d.ts +21 -0
  25. package/dist/contracts/model-catalog.js +14 -0
  26. package/dist/contracts/native-census.d.ts +42 -0
  27. package/dist/contracts/native-census.js +36 -0
  28. package/dist/contracts/observation-request.d.ts +37 -0
  29. package/dist/contracts/observation-request.js +25 -0
  30. package/dist/contracts/provider.d.ts +30 -0
  31. package/dist/contracts/provider.js +15 -0
  32. package/dist/contracts/recipes.d.ts +166 -0
  33. package/dist/contracts/recipes.js +52 -0
  34. package/dist/contracts/retention.d.ts +42 -0
  35. package/dist/contracts/retention.js +24 -0
  36. package/dist/contracts/storage.d.ts +23 -0
  37. package/dist/contracts/storage.js +10 -0
  38. package/dist/contracts/store-json.d.ts +315 -0
  39. package/dist/contracts/store-json.js +196 -0
  40. package/dist/contracts/trigger-payloads.d.ts +369 -0
  41. package/dist/contracts/trigger-payloads.js +144 -0
  42. package/dist/contracts/update-journal.d.ts +254 -0
  43. package/dist/contracts/update-journal.js +155 -0
  44. package/dist/contracts/verification-view.d.ts +93 -0
  45. package/dist/contracts/verification-view.js +43 -0
  46. package/dist/control-setup.d.ts +1 -1
  47. package/dist/desktop-update.d.ts +7 -40
  48. package/dist/desktop-update.js +36 -8
  49. package/dist/evidence.d.ts +3 -19
  50. package/dist/flow-engine.d.ts +2 -0
  51. package/dist/flow-engine.js +10 -2
  52. package/dist/flow-triggers.js +61 -60
  53. package/dist/flows-cli.d.ts +28 -0
  54. package/dist/flows-cli.js +43 -1
  55. package/dist/guides.js +2 -0
  56. package/dist/mate-contract.js +1 -1
  57. package/dist/mate-tools.js +43 -1
  58. package/dist/mcp-connect.js +37 -22
  59. package/dist/model-catalog.js +8 -6
  60. package/dist/observations.d.ts +2 -6
  61. package/dist/observations.js +13 -9
  62. package/dist/operate.js +55 -4
  63. package/dist/process-recovery-eligibility.d.ts +1 -1
  64. package/dist/process-recovery-native.d.ts +2 -13
  65. package/dist/process-recovery-native.js +8 -5
  66. package/dist/project-tools.d.ts +6 -24
  67. package/dist/project-tools.js +22 -18
  68. package/dist/provider.d.ts +3 -8
  69. package/dist/provider.js +15 -11
  70. package/dist/recipes.d.ts +3 -28
  71. package/dist/recipes.js +79 -52
  72. package/dist/retention.d.ts +4 -5
  73. package/dist/retention.js +5 -4
  74. package/dist/scope.d.ts +4 -2
  75. package/dist/serve.js +193 -30
  76. package/dist/storage.d.ts +2 -1
  77. package/dist/storage.js +12 -9
  78. package/dist/store.d.ts +11 -16
  79. package/dist/store.js +122 -160
  80. package/dist/surface.d.ts +6 -54
  81. package/dist/surface.js +10 -2
  82. package/dist/teammate-work.js +1 -1
  83. package/dist/telegram-flow.d.ts +41 -1
  84. package/dist/telegram-flow.js +96 -12
  85. package/dist/telegram.js +27 -3
  86. package/dist/toolroll-update.d.ts +8 -99
  87. package/dist/toolroll-update.js +28 -18
  88. package/dist/verification-evidence.js +27 -12
  89. package/package.json +1 -1
@@ -0,0 +1,315 @@
1
+ /**
2
+ * The JSON columns the store reads back (docs/plans/zod-revamp.md, item 18): one schema per `table.column`, read
3
+ * through `readVersioned`. Every writer through 0.9.41 stores the bare value, and writes are unchanged, so a row reads
4
+ * as version 0 and is upgraded in memory only to `{ version: 1, value }`; nothing is rewritten.
5
+ *
6
+ * Existing field contracts describe known shapes, without imposing their write-time limits on old rows.
7
+ * Legacy cast-only readers also accepted null,
8
+ * partial objects and wrong-shaped JSON: LEGACY_JSON_COLUMNS names those compatibility exceptions. Such rows keep
9
+ * their original values and report legacyIssues, rather than newly throwing or taking a different fallback.
10
+ * List readers still filter, coerce, clip and default after parsing. No reader serializes a schema's output back.
11
+ * Contracts owned elsewhere stay there: flow.ts, route.ts, stage-output.ts, flow-send.ts and chat-content.ts
12
+ * (chat-tables.ts only owns DDL). Plan and handoff artifacts are files, not JSON columns in store.ts.
13
+ */
14
+ import { z } from "zod";
15
+ import { type ContractIssue } from "./contract.js";
16
+ /** A teammate's rule for one tool action, as `teammates.ts` writes it. */
17
+ export declare const savedToolRuleSchema: z.ZodObject<{
18
+ use: z.ZodEnum<{
19
+ ask: "ask";
20
+ free: "free";
21
+ never: "never";
22
+ }>;
23
+ limit: z.ZodOptional<z.ZodObject<{
24
+ field: z.ZodString;
25
+ over: z.ZodNumber;
26
+ }, z.core.$loose>>;
27
+ undo: z.ZodOptional<z.ZodString>;
28
+ }, z.core.$loose>;
29
+ export declare const savedToolActionSchema: z.ZodObject<{
30
+ name: z.ZodString;
31
+ about: z.ZodString;
32
+ input: z.ZodNullable<z.ZodObject<{}, z.core.$loose>>;
33
+ readOnly: z.ZodBoolean;
34
+ }, z.core.$loose>;
35
+ export type SavedToolRule = z.infer<typeof savedToolRuleSchema>;
36
+ export type SavedToolAction = z.infer<typeof savedToolActionSchema>;
37
+ export declare const savedDecisionOptionSchema: z.ZodObject<{
38
+ reversible: z.ZodBoolean;
39
+ id: z.ZodString;
40
+ label: z.ZodString;
41
+ consequence: z.ZodString;
42
+ }, z.core.$loose>;
43
+ declare const STORE_COLUMN_VALUES: {
44
+ readonly "run_check.suites_json": z.ZodArray<z.ZodUnknown>;
45
+ readonly "teammate_suggestion.rule_json": z.ZodObject<{
46
+ use: z.ZodEnum<{
47
+ ask: "ask";
48
+ free: "free";
49
+ never: "never";
50
+ }>;
51
+ limit: z.ZodOptional<z.ZodObject<{
52
+ field: z.ZodString;
53
+ over: z.ZodNumber;
54
+ }, z.core.$loose>>;
55
+ undo: z.ZodOptional<z.ZodString>;
56
+ }, z.core.$loose>;
57
+ readonly "teammate_suggestion.was_json": z.ZodObject<{
58
+ use: z.ZodEnum<{
59
+ ask: "ask";
60
+ free: "free";
61
+ never: "never";
62
+ }>;
63
+ limit: z.ZodOptional<z.ZodObject<{
64
+ field: z.ZodString;
65
+ over: z.ZodNumber;
66
+ }, z.core.$loose>>;
67
+ undo: z.ZodOptional<z.ZodString>;
68
+ }, z.core.$loose>;
69
+ readonly "teammate_suggestion.evidence_json": z.ZodArray<z.ZodNumber>;
70
+ readonly "teammate_call.input_json": z.ZodObject<{}, z.core.$loose>;
71
+ readonly "teammate_tool.actions_json": z.ZodArray<z.ZodObject<{
72
+ name: z.ZodString;
73
+ about: z.ZodString;
74
+ input: z.ZodNullable<z.ZodObject<{}, z.core.$loose>>;
75
+ readOnly: z.ZodBoolean;
76
+ }, z.core.$loose>>;
77
+ readonly "teammate_tool.rules_json": z.ZodObject<{}, z.core.$catchall<z.ZodObject<{
78
+ use: z.ZodEnum<{
79
+ ask: "ask";
80
+ free: "free";
81
+ never: "never";
82
+ }>;
83
+ limit: z.ZodOptional<z.ZodObject<{
84
+ field: z.ZodString;
85
+ over: z.ZodNumber;
86
+ }, z.core.$loose>>;
87
+ undo: z.ZodOptional<z.ZodString>;
88
+ }, z.core.$loose>>>;
89
+ readonly "teammate_question.options_json": z.ZodArray<z.ZodObject<{
90
+ id: z.ZodString;
91
+ label: z.ZodString;
92
+ }, z.core.$loose>>;
93
+ readonly "teammate_event.detail_json": z.ZodObject<{}, z.core.$loose>;
94
+ readonly "flow_card.source_json": z.ZodObject<{
95
+ label: z.ZodString;
96
+ }, z.core.$loose>;
97
+ readonly "flow_comment.mentions_json": z.ZodArray<z.ZodUnknown>;
98
+ readonly "task_scope.touches": z.ZodLazy<z.ZodArray<z.ZodString>>;
99
+ /** Read by the scope contract's `parseAcceptanceCriteria` (`scope.ts`), which owns the criterion's shape. */
100
+ readonly "task_scope.acceptance_json": z.ZodLazy<z.ZodArray<z.ZodObject<{
101
+ id: z.ZodString;
102
+ statement: z.ZodString;
103
+ how: z.ZodOptional<z.ZodNullable<z.ZodString>>;
104
+ evidence: z.ZodArray<z.ZodEnum<{
105
+ "changed-path": "changed-path";
106
+ check: "check";
107
+ "manual-review": "manual-review";
108
+ screenshot: "screenshot";
109
+ }>>;
110
+ }, z.core.$strict>>>;
111
+ readonly "operating_mode.terms_json": z.ZodObject<{
112
+ dailyRunCap: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
113
+ dailyMeasuredCapMicrousd: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
114
+ reviewAuto: z.ZodOptional<z.ZodBoolean>;
115
+ quickMint: z.ZodOptional<z.ZodBoolean>;
116
+ publication: z.ZodOptional<z.ZodString>;
117
+ }, z.core.$loose>;
118
+ readonly "attended_authorization.terms_json": z.ZodObject<{
119
+ profileJson: z.ZodOptional<z.ZodNullable<z.ZodString>>;
120
+ }, z.core.$loose>;
121
+ readonly "approval_policy.protected_paths": z.ZodArray<z.ZodUnknown>;
122
+ readonly "fallback_config.entries_json": z.ZodArray<z.ZodUnknown>;
123
+ readonly "runner.repos": z.ZodArray<z.ZodUnknown>;
124
+ readonly "runner.agents": z.ZodArray<z.ZodUnknown>;
125
+ readonly "decision.options": z.ZodArray<z.ZodObject<{
126
+ reversible: z.ZodBoolean;
127
+ id: z.ZodString;
128
+ label: z.ZodString;
129
+ consequence: z.ZodString;
130
+ }, z.core.$loose>>;
131
+ readonly "tool_seal.tools_json": z.ZodArray<z.ZodUnknown>;
132
+ readonly "run_tool.tools_json": z.ZodObject<{
133
+ tools: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
134
+ skipped: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
135
+ fence: z.ZodOptional<z.ZodObject<{
136
+ method: z.ZodString;
137
+ paths: z.ZodNumber;
138
+ }, z.core.$loose>>;
139
+ }, z.core.$loose>;
140
+ /** `json_extract(tools_json, '$.fence')`: the fence an attempt ran with. */
141
+ readonly "run_tool.tools_json.fence": z.ZodObject<{
142
+ method: z.ZodString;
143
+ paths: z.ZodNumber;
144
+ }, z.core.$loose>;
145
+ readonly "mate_ask.options_json": z.ZodArray<z.ZodString>;
146
+ readonly "lead_config.about_json": z.ZodArray<z.ZodUnknown>;
147
+ readonly "mutation.result": z.ZodUnknown;
148
+ readonly "plan_revision.changed_fields": z.ZodArray<z.ZodString>;
149
+ readonly "run_checkpoint.snapshot_json": z.ZodObject<{
150
+ revisionHash: z.ZodString;
151
+ milestones: z.ZodArray<z.ZodObject<{
152
+ id: z.ZodString;
153
+ state: z.ZodEnum<{
154
+ blocked: "blocked";
155
+ completed: "completed";
156
+ current: "current";
157
+ pending: "pending";
158
+ }>;
159
+ note: z.ZodOptional<z.ZodNullable<z.ZodString>>;
160
+ }, z.core.$loose>>;
161
+ }, z.core.$loose>;
162
+ readonly "telegram_conversation_part.keyboard_json": z.ZodArray<z.ZodArray<z.ZodObject<{
163
+ text: z.ZodString;
164
+ callback_data: z.ZodString;
165
+ }, z.core.$loose>>>;
166
+ readonly "publication_grant.capabilities": z.ZodArray<z.ZodEnum<{
167
+ "open-pr": "open-pr";
168
+ "push-branch": "push-branch";
169
+ }>>;
170
+ readonly "task_ref.zones": z.ZodArray<z.ZodUnknown>;
171
+ readonly "task_ref.capability_requirements": z.ZodArray<z.ZodUnknown>;
172
+ readonly "routine.touches": z.ZodArray<z.ZodUnknown>;
173
+ readonly "routine.requirements": z.ZodArray<z.ZodUnknown>;
174
+ /** Read by `parseAcceptanceCriteria`, as `task_scope.acceptance_json`. */
175
+ readonly "routine.acceptance_json": z.ZodLazy<z.ZodArray<z.ZodObject<{
176
+ id: z.ZodString;
177
+ statement: z.ZodString;
178
+ how: z.ZodOptional<z.ZodNullable<z.ZodString>>;
179
+ evidence: z.ZodArray<z.ZodEnum<{
180
+ "changed-path": "changed-path";
181
+ check: "check";
182
+ "manual-review": "manual-review";
183
+ screenshot: "screenshot";
184
+ }>>;
185
+ }, z.core.$strict>>>;
186
+ readonly "tournament_terms.agents": z.ZodArray<z.ZodObject<{
187
+ provider: z.ZodString;
188
+ model: z.ZodString;
189
+ repairModel: z.ZodString;
190
+ permissionMode: z.ZodOptional<z.ZodString>;
191
+ }, z.core.$loose>>;
192
+ readonly "coordinator_proposal.payload_json": z.ZodObject<{}, z.core.$loose>;
193
+ readonly "coordinator_proposal.outcome_json": z.ZodObject<{}, z.core.$loose>;
194
+ readonly "mate_proposal.payload_json": z.ZodUnion<readonly [z.ZodObject<{
195
+ version: z.ZodLiteral<1>;
196
+ operation: z.ZodEnum<{
197
+ decision_record: "decision_record";
198
+ decision_retire: "decision_retire";
199
+ flow_card_add: "flow_card_add";
200
+ flow_card_approve: "flow_card_approve";
201
+ flow_card_assign: "flow_card_assign";
202
+ flow_card_cancel: "flow_card_cancel";
203
+ flow_card_choose: "flow_card_choose";
204
+ flow_card_comment: "flow_card_comment";
205
+ flow_card_move: "flow_card_move";
206
+ flow_card_send_back: "flow_card_send_back";
207
+ flow_card_watch: "flow_card_watch";
208
+ flow_create: "flow_create";
209
+ flow_edit: "flow_edit";
210
+ flow_script_save: "flow_script_save";
211
+ flow_starter: "flow_starter";
212
+ flow_trigger_add: "flow_trigger_add";
213
+ flow_trigger_pause: "flow_trigger_pause";
214
+ flow_trigger_remove: "flow_trigger_remove";
215
+ flow_trigger_resume: "flow_trigger_resume";
216
+ kit_setup: "kit_setup";
217
+ knowledge_instructions: "knowledge_instructions";
218
+ knowledge_remove: "knowledge_remove";
219
+ knowledge_restore: "knowledge_restore";
220
+ knowledge_save: "knowledge_save";
221
+ lead_about_you: "lead_about_you";
222
+ result_accept: "result_accept";
223
+ scope_approve: "scope_approve";
224
+ skill_disable: "skill_disable";
225
+ skill_enable: "skill_enable";
226
+ skill_import: "skill_import";
227
+ skill_restore: "skill_restore";
228
+ skill_test: "skill_test";
229
+ task_cancel: "task_cancel";
230
+ task_resume: "task_resume";
231
+ teammate_answer: "teammate_answer";
232
+ teammate_create: "teammate_create";
233
+ teammate_memory: "teammate_memory";
234
+ teammate_note: "teammate_note";
235
+ teammate_routine: "teammate_routine";
236
+ teammate_soul: "teammate_soul";
237
+ teammate_state: "teammate_state";
238
+ teammate_tools: "teammate_tools";
239
+ teammate_undo: "teammate_undo";
240
+ tool_add: "tool_add";
241
+ tool_remove: "tool_remove";
242
+ }>;
243
+ request: z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>;
244
+ repo: z.ZodString;
245
+ title: z.ZodString;
246
+ terms: z.ZodArray<z.ZodString>;
247
+ stamp: z.ZodString;
248
+ state: z.ZodObject<{}, z.core.$catchall<z.ZodUnknown>>;
249
+ }, z.core.$strict>, z.ZodObject<{}, z.core.$loose>]>;
250
+ readonly "mate_proposal.outcome_json": z.ZodObject<{}, z.core.$loose>;
251
+ readonly "proof_verdict.matrix_json": z.ZodArray<z.ZodObject<{
252
+ id: z.ZodString;
253
+ statement: z.ZodString;
254
+ requiredEvidence: z.ZodArray<z.ZodUnknown>;
255
+ state: z.ZodString;
256
+ detail: z.ZodArray<z.ZodUnknown>;
257
+ answered: z.ZodOptional<z.ZodArray<z.ZodObject<{
258
+ kind: z.ZodEnum<{
259
+ "changed-path": "changed-path";
260
+ check: "check";
261
+ "manual-review": "manual-review";
262
+ screenshot: "screenshot";
263
+ }>;
264
+ ref: z.ZodString;
265
+ }, z.core.$loose>>>;
266
+ review: z.ZodOptional<z.ZodNullable<z.ZodObject<{
267
+ judgement: z.ZodString;
268
+ note: z.ZodString;
269
+ author: z.ZodString;
270
+ }, z.core.$loose>>>;
271
+ }, z.core.$loose>>;
272
+ readonly "proof_verdict.reasons_json": z.ZodArray<z.ZodUnknown>;
273
+ readonly "criterion_review.screenshots_json": z.ZodArray<z.ZodUnknown>;
274
+ readonly "repair_chain.unresolved_json": z.ZodArray<z.ZodUnknown>;
275
+ readonly "backend_grant.paths": z.ZodArray<z.ZodUnknown>;
276
+ readonly "backend_grant.mutations": z.ZodArray<z.ZodUnknown>;
277
+ };
278
+ export type StoreColumn = keyof typeof STORE_COLUMN_VALUES;
279
+ export type StoreColumnValue<C extends StoreColumn> = z.infer<(typeof STORE_COLUMN_VALUES)[C]>;
280
+ /** Every JSON column the store reads itself, by `table.column`. */
281
+ export declare const STORE_COLUMNS: ("approval_policy.protected_paths" | "attended_authorization.terms_json" | "backend_grant.mutations" | "backend_grant.paths" | "coordinator_proposal.outcome_json" | "coordinator_proposal.payload_json" | "criterion_review.screenshots_json" | "decision.options" | "fallback_config.entries_json" | "flow_card.source_json" | "flow_comment.mentions_json" | "lead_config.about_json" | "mate_ask.options_json" | "mate_proposal.outcome_json" | "mate_proposal.payload_json" | "mutation.result" | "operating_mode.terms_json" | "plan_revision.changed_fields" | "proof_verdict.matrix_json" | "proof_verdict.reasons_json" | "publication_grant.capabilities" | "repair_chain.unresolved_json" | "routine.acceptance_json" | "routine.requirements" | "routine.touches" | "run_check.suites_json" | "run_checkpoint.snapshot_json" | "run_tool.tools_json" | "runner.agents" | "runner.repos" | "task_ref.capability_requirements" | "task_ref.zones" | "task_scope.acceptance_json" | "task_scope.touches" | "teammate_call.input_json" | "teammate_event.detail_json" | "teammate_question.options_json" | "teammate_suggestion.evidence_json" | "teammate_suggestion.rule_json" | "teammate_suggestion.was_json" | "teammate_tool.actions_json" | "teammate_tool.rules_json" | "telegram_conversation_part.keyboard_json" | "tool_seal.tools_json" | "tournament_terms.agents")[];
282
+ /** A SQL projection, not a physical column; replay it separately after its owning column. */
283
+ export declare const STORE_PROJECTIONS: readonly ["run_tool.tools_json.fence"];
284
+ /** These readers historically only parsed JSON. Shape errors must not change their values or catch boundaries. */
285
+ export declare const LEGACY_JSON_COLUMNS: readonly StoreColumn[];
286
+ /** One column's versioned envelope: `{ version: 1, value }`, built in memory around the saved bare value. */
287
+ export declare function storeColumnSchema<C extends StoreColumn>(column: C): z.ZodObject<{
288
+ version: z.ZodLiteral<1>;
289
+ value: (typeof STORE_COLUMN_VALUES)[C];
290
+ }, z.core.$strict>;
291
+ /** What a column read finds: its value, or why not — `malformed` when the saved text is not JSON at all. */
292
+ export type StoreColumnRead<T> = {
293
+ ok: true;
294
+ value: T;
295
+ legacyIssues?: ContractIssue[];
296
+ } | {
297
+ ok: false;
298
+ malformed: boolean;
299
+ issues: ContractIssue[];
300
+ };
301
+ /**
302
+ * Read one saved column value (`String(raw)`, as every reader did) through its schema. Never throws: the caller keeps
303
+ * the fallback its reader always had.
304
+ */
305
+ export declare function readStoreColumn<C extends StoreColumn>(column: C, raw: unknown): StoreColumnRead<StoreColumnValue<C>>;
306
+ /**
307
+ * Read one saved column value for a reader that let a bad row throw: unreadable JSON throws the same SyntaxError
308
+ * `JSON.parse` threw. Legacy shape issues are advisory; only a previously enforced shape can throw.
309
+ */
310
+ export declare function parseStoreColumn<C extends StoreColumn>(column: C, raw: unknown): StoreColumnValue<C>;
311
+ /** A list of text, as `readJsonArray` always read one: unreadable or not a list is none; non-text items are dropped. */
312
+ export declare function readStoreTextList(column: StoreColumn, raw: unknown): string[];
313
+ /** A list read with every item as text (`String(item)`), as reasons and unresolved criteria always were; otherwise none. */
314
+ export declare function readStoreStringifiedList(column: StoreColumn, raw: unknown): string[];
315
+ export {};
@@ -0,0 +1,196 @@
1
+ /**
2
+ * The JSON columns the store reads back (docs/plans/zod-revamp.md, item 18): one schema per `table.column`, read
3
+ * through `readVersioned`. Every writer through 0.9.41 stores the bare value, and writes are unchanged, so a row reads
4
+ * as version 0 and is upgraded in memory only to `{ version: 1, value }`; nothing is rewritten.
5
+ *
6
+ * Existing field contracts describe known shapes, without imposing their write-time limits on old rows.
7
+ * Legacy cast-only readers also accepted null,
8
+ * partial objects and wrong-shaped JSON: LEGACY_JSON_COLUMNS names those compatibility exceptions. Such rows keep
9
+ * their original values and report legacyIssues, rather than newly throwing or taking a different fallback.
10
+ * List readers still filter, coerce, clip and default after parsing. No reader serializes a schema's output back.
11
+ * Contracts owned elsewhere stay there: flow.ts, route.ts, stage-output.ts, flow-send.ts and chat-content.ts
12
+ * (chat-tables.ts only owns DDL). Plan and handoff artifacts are files, not JSON columns in store.ts.
13
+ */
14
+ import { z } from "zod";
15
+ import { decisionOptionSchema } from "./decision.js";
16
+ import { scopeTermsSchema, storedRubricSchema } from "./scope.js";
17
+ import { criterionEvidenceSchema, proofCriterionSchema } from "./proof.js";
18
+ import { sharedActionSchema } from "./chat-actions.js";
19
+ import { telegramCallbackButtonSchema } from "./telegram-callback.js";
20
+ import { readVersioned, versioned } from "./contract.js";
21
+ /** Dynamic tool arguments, event details and operation results have no common field contract. */
22
+ const savedObject = z.looseObject({});
23
+ /** A JSON list; its reader filters, coerces and clips the items after parsing, as before. */
24
+ const savedList = z.array(z.unknown());
25
+ /** An object with a text `label`: a card's source (its reader keeps picking the fields it knows). */
26
+ const cardSource = z.looseObject({ label: z.string() });
27
+ /** A teammate's rule for one tool action, as `teammates.ts` writes it. */
28
+ export const savedToolRuleSchema = z.looseObject({
29
+ use: z.enum(["free", "ask", "never"]),
30
+ limit: z.looseObject({ field: z.string(), over: z.number() }).optional(),
31
+ /** Another action of the same tool that undoes this one with the same input. */
32
+ undo: z.string().optional(),
33
+ });
34
+ export const savedToolActionSchema = z.looseObject({
35
+ name: z.string(), about: z.string(), input: savedObject.nullable(), readOnly: z.boolean(),
36
+ });
37
+ // Reuse the option's canonical fields, dropping only write-time text bounds on a saved row.
38
+ export const savedDecisionOptionSchema = decisionOptionSchema.extend({
39
+ id: z.string(), label: z.string(), consequence: z.string(),
40
+ }).loose();
41
+ const savedQuestionOptionSchema = savedDecisionOptionSchema.pick({ id: true, label: true });
42
+ const savedFenceSchema = z.looseObject({ method: z.string(), paths: z.number() });
43
+ const savedToolsSchema = z.looseObject({
44
+ tools: savedList.optional(), skipped: savedList.optional(), fence: savedFenceSchema.optional(),
45
+ });
46
+ const savedModeTermsSchema = z.looseObject({
47
+ dailyRunCap: z.number().nullable().optional(), dailyMeasuredCapMicrousd: z.number().nullable().optional(),
48
+ reviewAuto: z.boolean().optional(), quickMint: z.boolean().optional(), publication: z.string().optional(),
49
+ });
50
+ const savedProgressSchema = z.looseObject({
51
+ revisionHash: z.string(),
52
+ milestones: z.array(z.looseObject({
53
+ id: z.string(), state: z.enum(["pending", "current", "completed", "blocked"]), note: z.string().nullable().optional(),
54
+ })),
55
+ });
56
+ const savedAgentSchema = z.looseObject({
57
+ provider: z.string(), model: z.string(), repairModel: z.string(), permissionMode: z.string().optional(),
58
+ });
59
+ const savedKeyboardSchema = z.array(z.array(telegramCallbackButtonSchema.extend({ callback_data: z.string() }).loose()));
60
+ const savedMatrixRowSchema = proofCriterionSchema.pick({ id: true, statement: true }).extend({
61
+ id: z.string(), statement: z.string(), requiredEvidence: savedList, state: z.string(), detail: savedList,
62
+ answered: z.array(criterionEvidenceSchema.extend({ ref: z.string() }).loose()).optional(),
63
+ review: z.looseObject({ judgement: z.string(), note: z.string(), author: z.string() }).nullable().optional(),
64
+ }).loose();
65
+ const STORE_COLUMN_VALUES = {
66
+ "run_check.suites_json": savedList,
67
+ "teammate_suggestion.rule_json": savedToolRuleSchema,
68
+ "teammate_suggestion.was_json": savedToolRuleSchema,
69
+ "teammate_suggestion.evidence_json": z.array(z.number()),
70
+ "teammate_call.input_json": savedObject,
71
+ "teammate_tool.actions_json": z.array(savedToolActionSchema),
72
+ "teammate_tool.rules_json": z.object({}).catchall(savedToolRuleSchema),
73
+ "teammate_question.options_json": z.array(savedQuestionOptionSchema),
74
+ "teammate_event.detail_json": savedObject,
75
+ "flow_card.source_json": cardSource,
76
+ "flow_comment.mentions_json": savedList,
77
+ "task_scope.touches": z.lazy(() => scopeTermsSchema.unwrap().shape.touches.unwrap()),
78
+ /** Read by the scope contract's `parseAcceptanceCriteria` (`scope.ts`), which owns the criterion's shape. */
79
+ "task_scope.acceptance_json": storedRubricSchema,
80
+ "operating_mode.terms_json": savedModeTermsSchema,
81
+ "attended_authorization.terms_json": z.looseObject({ profileJson: z.string().nullable().optional() }),
82
+ "approval_policy.protected_paths": savedList,
83
+ "fallback_config.entries_json": savedList,
84
+ "runner.repos": savedList,
85
+ "runner.agents": savedList,
86
+ "decision.options": z.array(savedDecisionOptionSchema),
87
+ "tool_seal.tools_json": savedList,
88
+ "run_tool.tools_json": savedToolsSchema,
89
+ /** `json_extract(tools_json, '$.fence')`: the fence an attempt ran with. */
90
+ "run_tool.tools_json.fence": savedFenceSchema,
91
+ "mate_ask.options_json": z.array(z.string()),
92
+ "lead_config.about_json": savedList,
93
+ "mutation.result": z.unknown(),
94
+ "plan_revision.changed_fields": z.array(z.string()),
95
+ "run_checkpoint.snapshot_json": savedProgressSchema,
96
+ "telegram_conversation_part.keyboard_json": savedKeyboardSchema,
97
+ "publication_grant.capabilities": z.array(z.enum(["push-branch", "open-pr"])),
98
+ "task_ref.zones": savedList,
99
+ "task_ref.capability_requirements": savedList,
100
+ "routine.touches": savedList,
101
+ "routine.requirements": savedList,
102
+ /** Read by `parseAcceptanceCriteria`, as `task_scope.acceptance_json`. */
103
+ "routine.acceptance_json": storedRubricSchema,
104
+ "tournament_terms.agents": z.array(savedAgentSchema),
105
+ "coordinator_proposal.payload_json": savedObject,
106
+ "coordinator_proposal.outcome_json": savedObject,
107
+ // Other proposal kinds have operation-specific fields; the action variant already has a canonical contract.
108
+ "mate_proposal.payload_json": z.union([sharedActionSchema, savedObject]),
109
+ "mate_proposal.outcome_json": savedObject,
110
+ "proof_verdict.matrix_json": z.array(savedMatrixRowSchema),
111
+ "proof_verdict.reasons_json": savedList,
112
+ "criterion_review.screenshots_json": savedList,
113
+ "repair_chain.unresolved_json": savedList,
114
+ "backend_grant.paths": savedList,
115
+ "backend_grant.mutations": savedList,
116
+ };
117
+ /** Every JSON column the store reads itself, by `table.column`. */
118
+ export const STORE_COLUMNS = Object.keys(STORE_COLUMN_VALUES).filter(column => column !== "run_tool.tools_json.fence");
119
+ /** A SQL projection, not a physical column; replay it separately after its owning column. */
120
+ export const STORE_PROJECTIONS = ["run_tool.tools_json.fence"];
121
+ /** These readers historically only parsed JSON. Shape errors must not change their values or catch boundaries. */
122
+ export const LEGACY_JSON_COLUMNS = [
123
+ "teammate_suggestion.rule_json", "teammate_suggestion.was_json", "teammate_suggestion.evidence_json",
124
+ "teammate_call.input_json", "teammate_tool.actions_json", "teammate_tool.rules_json", "teammate_question.options_json",
125
+ "teammate_event.detail_json", "task_scope.touches", "task_scope.acceptance_json", "routine.acceptance_json",
126
+ "operating_mode.terms_json", "attended_authorization.terms_json", "decision.options", "run_tool.tools_json",
127
+ "run_tool.tools_json.fence", "mate_ask.options_json", "mutation.result", "plan_revision.changed_fields",
128
+ "run_checkpoint.snapshot_json", "telegram_conversation_part.keyboard_json", "publication_grant.capabilities",
129
+ "tournament_terms.agents", "coordinator_proposal.payload_json", "coordinator_proposal.outcome_json",
130
+ "mate_proposal.payload_json", "mate_proposal.outcome_json",
131
+ ];
132
+ /** One column's versioned envelope: `{ version: 1, value }`, built in memory around the saved bare value. */
133
+ export function storeColumnSchema(column) {
134
+ return versioned(1, { value: STORE_COLUMN_VALUES[column] });
135
+ }
136
+ const SCHEMAS = new Map([...STORE_COLUMNS, ...STORE_PROJECTIONS].map(column => [column, storeColumnSchema(column)]));
137
+ /** A saved bare value is version 0; its upgrade wraps it. */
138
+ const UPGRADES = { 0: (payload) => ({ version: 1, value: payload["value"] }) };
139
+ /**
140
+ * Read one saved column value (`String(raw)`, as every reader did) through its schema. Never throws: the caller keeps
141
+ * the fallback its reader always had.
142
+ */
143
+ export function readStoreColumn(column, raw) {
144
+ let parsed;
145
+ try {
146
+ parsed = JSON.parse(String(raw));
147
+ }
148
+ catch (error) {
149
+ return { ok: false, malformed: true, issues: [{ path: "payload", kind: "invalid", line: `payload: ${column} is not JSON (${error instanceof Error ? error.message : String(error)})` }] };
150
+ }
151
+ return readParsedColumn(column, parsed);
152
+ }
153
+ function readParsedColumn(column, parsed) {
154
+ const read = readVersioned(SCHEMAS.get(column), { value: parsed }, UPGRADES);
155
+ // Return the original JSON, including unknown keys, property order and own __proto__ keys. In particular, never
156
+ // replace old cast-only values with a schema's stripped/defaulted output. A matrix historically accepted any list.
157
+ const legacy = LEGACY_JSON_COLUMNS.includes(column) || (column === "proof_verdict.matrix_json" && Array.isArray(parsed));
158
+ if (read.ok || legacy)
159
+ return {
160
+ ok: true, value: parsed,
161
+ ...(!read.ok ? { legacyIssues: read.issues.map(unwrap) } : {}),
162
+ };
163
+ return { ok: false, malformed: false, issues: read.issues.map(unwrap) };
164
+ }
165
+ /** `value.label: required` reads as `label: required`: the envelope is the reader's, not the row's. */
166
+ function unwrap(issue) {
167
+ const at = issue.path === "value" ? "payload" : issue.path.startsWith("value.") ? issue.path.slice(6) : issue.path.startsWith("value[") ? `payload${issue.path.slice(5)}` : issue.path;
168
+ return { ...issue, path: at, line: issue.line.startsWith(`${issue.path}:`) ? `${at}${issue.line.slice(issue.path.length)}` : issue.line };
169
+ }
170
+ /**
171
+ * Read one saved column value for a reader that let a bad row throw: unreadable JSON throws the same SyntaxError
172
+ * `JSON.parse` threw. Legacy shape issues are advisory; only a previously enforced shape can throw.
173
+ */
174
+ export function parseStoreColumn(column, raw) {
175
+ const parsed = JSON.parse(String(raw));
176
+ const read = readParsedColumn(column, parsed);
177
+ if (!read.ok)
178
+ throw new Error(`${column}: ${read.issues.map(issue => issue.line).join("; ")}`);
179
+ return read.value;
180
+ }
181
+ /** A list of text, as `readJsonArray` always read one: unreadable or not a list is none; non-text items are dropped. */
182
+ export function readStoreTextList(column, raw) {
183
+ const read = readStoreColumn(column, raw);
184
+ return read.ok && Array.isArray(read.value) ? read.value.filter((one) => typeof one === "string") : [];
185
+ }
186
+ /** A list read with every item as text (`String(item)`), as reasons and unresolved criteria always were; otherwise none. */
187
+ export function readStoreStringifiedList(column, raw) {
188
+ const read = readStoreColumn(column, raw);
189
+ try {
190
+ return read.ok && Array.isArray(read.value) ? read.value.map(one => String(one)) : [];
191
+ }
192
+ catch {
193
+ // JSON objects can shadow toString with a non-function. The old readers caught failed coercion too.
194
+ return [];
195
+ }
196
+ }