toolroll 0.9.52 → 0.9.54

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 (187) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +55 -80
  3. package/dist/agentconfig.d.ts +11 -36
  4. package/dist/agentconfig.js +3 -62
  5. package/dist/approval-policy.d.ts +1 -1
  6. package/dist/approval-policy.js +1 -1
  7. package/dist/board.d.ts +3 -19
  8. package/dist/board.js +4 -42
  9. package/dist/browser/workspace.js +18 -18
  10. package/dist/browser-workspace.d.ts +2 -1
  11. package/dist/builder.d.ts +9 -40
  12. package/dist/builder.js +50 -257
  13. package/dist/chat-actions.js +3 -14
  14. package/dist/chat-ask.js +8 -8
  15. package/dist/chat-controls.d.ts +0 -4
  16. package/dist/chat-controls.js +0 -1
  17. package/dist/chat-core.d.ts +171 -0
  18. package/dist/chat-core.js +288 -0
  19. package/dist/chat-decide.d.ts +10 -8
  20. package/dist/chat-decide.js +27 -24
  21. package/dist/chat-delivery-state.d.ts +51 -75
  22. package/dist/chat-delivery-state.js +140 -170
  23. package/dist/chat-delivery.d.ts +21 -4
  24. package/dist/chat-delivery.js +313 -195
  25. package/dist/chat-flow.d.ts +29 -1
  26. package/dist/chat-flow.js +24 -50
  27. package/dist/chat-messages.d.ts +319 -0
  28. package/dist/chat-messages.js +841 -0
  29. package/dist/chat-migration.d.ts +30 -0
  30. package/dist/chat-migration.js +802 -0
  31. package/dist/chat-quiet.d.ts +3 -0
  32. package/dist/chat-quiet.js +7 -2
  33. package/dist/chat-task-actions.d.ts +1 -1
  34. package/dist/chat-task-actions.js +0 -2
  35. package/dist/claim.d.ts +79 -244
  36. package/dist/claim.js +688 -1023
  37. package/dist/cli.d.ts +2 -0
  38. package/dist/cli.js +10 -2
  39. package/dist/contracts/chat-content.d.ts +71 -2
  40. package/dist/contracts/chat-content.js +22 -3
  41. package/dist/contracts/chat-tables.d.ts +11 -4
  42. package/dist/contracts/chat-tables.js +165 -87
  43. package/dist/contracts/cli.d.ts +0 -13
  44. package/dist/contracts/cli.js +0 -2
  45. package/dist/contracts/console-api.d.ts +5 -10
  46. package/dist/contracts/console-api.js +4 -10
  47. package/dist/contracts/discord-callback.js +2 -1
  48. package/dist/contracts/flow.d.ts +50 -0
  49. package/dist/contracts/flow.js +26 -1
  50. package/dist/contracts/lead-tools.d.ts +0 -13
  51. package/dist/contracts/lead-tools.js +3 -3
  52. package/dist/contracts/slack-callback.js +3 -2
  53. package/dist/contracts/store-json.d.ts +1 -29
  54. package/dist/contracts/store-json.js +4 -17
  55. package/dist/contracts/teams-callback.js +2 -1
  56. package/dist/converse.d.ts +1 -11
  57. package/dist/converse.js +6 -38
  58. package/dist/coordinator.d.ts +0 -1
  59. package/dist/coordinator.js +3 -5
  60. package/dist/demo.js +16 -26
  61. package/dist/desktop-update-gate.js +0 -1
  62. package/dist/desktop-update.js +1 -3
  63. package/dist/discord-chat.js +19 -38
  64. package/dist/discord-settings.js +4 -13
  65. package/dist/discord.js +4 -14
  66. package/dist/dispatch.d.ts +1 -1
  67. package/dist/dispatch.js +1 -1
  68. package/dist/dispose.d.ts +2 -3
  69. package/dist/dispose.js +17 -92
  70. package/dist/envelope.js +0 -3
  71. package/dist/exec.d.ts +0 -64
  72. package/dist/exec.js +3 -356
  73. package/dist/exhaustion.d.ts +22 -76
  74. package/dist/exhaustion.js +14 -140
  75. package/dist/export.js +8 -8
  76. package/dist/flow-engine.js +1 -1
  77. package/dist/flow-schedule.d.ts +154 -0
  78. package/dist/flow-schedule.js +321 -0
  79. package/dist/flow-share.js +1 -1
  80. package/dist/flow-triggers.d.ts +6 -1
  81. package/dist/flow-triggers.js +65 -10
  82. package/dist/flows-cli.js +8 -4
  83. package/dist/flows-ui.js +2 -0
  84. package/dist/flows.js +1 -1
  85. package/dist/guides.js +9 -29
  86. package/dist/invoke.d.ts +1 -24
  87. package/dist/invoke.js +17 -259
  88. package/dist/lead-status.js +2 -4
  89. package/dist/lead-voice.js +1 -1
  90. package/dist/mate-doors.d.ts +1 -2
  91. package/dist/mate-doors.js +12 -25
  92. package/dist/mate-tools.d.ts +2 -2
  93. package/dist/mate-tools.js +13 -24
  94. package/dist/modes.d.ts +19 -8
  95. package/dist/modes.js +24 -14
  96. package/dist/notification-rows.d.ts +30 -0
  97. package/dist/notification-rows.js +102 -0
  98. package/dist/operate-remote-arguments.js +2 -6
  99. package/dist/operate-remote.js +6 -7
  100. package/dist/operate.d.ts +0 -6
  101. package/dist/operate.js +226 -2248
  102. package/dist/phase-routing.d.ts +13 -23
  103. package/dist/phase-routing.js +13 -35
  104. package/dist/plan-auto.js +2 -2
  105. package/dist/plane-review.js +5 -11
  106. package/dist/planner-source.js +2 -1
  107. package/dist/policy.d.ts +1 -4
  108. package/dist/policy.js +0 -8
  109. package/dist/process-recovery-eligibility.js +2 -3
  110. package/dist/project-delete.js +24 -41
  111. package/dist/proposal.d.ts +4 -24
  112. package/dist/proposal.js +3 -88
  113. package/dist/provider-auth.d.ts +3 -3
  114. package/dist/provider-auth.js +4 -6
  115. package/dist/provider.d.ts +11 -25
  116. package/dist/provider.js +4 -36
  117. package/dist/push.js +1 -1
  118. package/dist/recipe-ui.js +6 -6
  119. package/dist/recipes.d.ts +3 -3
  120. package/dist/recipes.js +27 -23
  121. package/dist/result-shots.js +2 -2
  122. package/dist/retention.js +1 -1
  123. package/dist/run-closeout.d.ts +1 -1
  124. package/dist/run-closeout.js +1 -4
  125. package/dist/scope.d.ts +11 -65
  126. package/dist/scope.js +17 -82
  127. package/dist/serve.js +15 -24
  128. package/dist/server/chat.js +7 -30
  129. package/dist/server/flows.js +11 -10
  130. package/dist/server/guards.js +0 -1
  131. package/dist/server/pages-assets.js +1 -1
  132. package/dist/server/pages.js +0 -2
  133. package/dist/server/people-tokens.js +0 -4
  134. package/dist/server/route-table.d.ts +1 -1
  135. package/dist/server/route-table.js +2 -17
  136. package/dist/server/settings.js +6 -12
  137. package/dist/server/shared.d.ts +28 -212
  138. package/dist/server/shared.js +71 -780
  139. package/dist/server/task-views.js +9 -76
  140. package/dist/server/tasks.d.ts +1 -50
  141. package/dist/server/tasks.js +36 -946
  142. package/dist/setup-guide.d.ts +2 -2
  143. package/dist/slack-api.d.ts +5 -1
  144. package/dist/slack-api.js +2 -2
  145. package/dist/slack-chat.d.ts +9 -6
  146. package/dist/slack-chat.js +29 -53
  147. package/dist/slack-settings.js +6 -15
  148. package/dist/slack.js +6 -16
  149. package/dist/store.d.ts +200 -1702
  150. package/dist/store.js +811 -5439
  151. package/dist/surface.js +10 -24
  152. package/dist/task-composer.d.ts +1 -1
  153. package/dist/task-composer.js +1 -1
  154. package/dist/task-control.d.ts +3 -10
  155. package/dist/task-control.js +2 -7
  156. package/dist/teammate-desk.js +1 -1
  157. package/dist/teammate-question.js +12 -12
  158. package/dist/teammates-ui.js +1 -1
  159. package/dist/teams-chat.js +12 -9
  160. package/dist/teams-settings.js +2 -2
  161. package/dist/teams.js +4 -5
  162. package/dist/telegram-flow.js +5 -5
  163. package/dist/telegram-mate.d.ts +0 -3
  164. package/dist/telegram-mate.js +0 -1
  165. package/dist/telegram.js +4 -4
  166. package/dist/templates.d.ts +11 -7
  167. package/dist/templates.js +12 -9
  168. package/dist/toolroll-update.d.ts +20 -0
  169. package/dist/toolroll-update.js +104 -5
  170. package/dist/work-index.js +2 -6
  171. package/dist/workspace-revision.js +3 -1
  172. package/dist/workspace-ui.js +1 -1
  173. package/package.json +1 -1
  174. package/scripts/recovery-canary.mjs +3 -3
  175. package/dist/contest.d.ts +0 -318
  176. package/dist/contest.js +0 -753
  177. package/dist/held.d.ts +0 -150
  178. package/dist/held.js +0 -799
  179. package/dist/liveness.d.ts +0 -30
  180. package/dist/liveness.js +0 -42
  181. package/dist/pricing.d.ts +0 -45
  182. package/dist/pricing.js +0 -77
  183. package/dist/routine.d.ts +0 -228
  184. package/dist/routine.js +0 -764
  185. package/dist/slack-state.d.ts +0 -13
  186. package/dist/slack-state.js +0 -10
  187. package/dist/supervisor.mjs +0 -297
@@ -123,15 +123,13 @@ export declare const CONSOLE_FORMS: {
123
123
  readonly tasksAdd: FormContract<"acceptance" | "after" | "goal" | "id" | "not" | "permission-mode" | "plan-first" | "planning-policy" | "projectRevision" | "quality-mode" | "repo" | "scout" | "title" | "touches">;
124
124
  readonly queue: FormContract<"before" | "column" | "from" | "note" | "projectRevision" | "queueRevision" | "respond" | "runner" | "task">;
125
125
  readonly runnerRegister: FormContract<"capacity" | "name" | "token">;
126
- readonly mode: FormContract<"allow-paid-fallback" | "auto-approve" | "chat-approve" | "days" | "digest" | "expiry" | "name" | "nonce" | "plan-auto" | "publication" | "repair-auto" | "review-auto" | "review-retry-auto" | "token">;
126
+ readonly mode: FormContract<"auto-approve" | "chat-approve" | "days" | "digest" | "expiry" | "name" | "nonce" | "plan-auto" | "publication" | "repair-auto" | "review-auto" | "review-retry-auto" | "token">;
127
127
  readonly peopleProjects: FormContract<"access" | "name" | "projects" | "token">;
128
128
  readonly peopleInvite: FormContract<"access" | "projects" | "role" | "token">;
129
129
  readonly peopleInviteRevoke: FormContract<"id" | "token">;
130
130
  readonly peopleRevoke: FormContract<"name" | "token">;
131
131
  readonly runnerRetire: FormContract<"name" | "token">;
132
132
  readonly decisionAnswer: FormContract<"choice" | "confirm" | "note" | "return">;
133
- readonly contest: FormContract<"act" | "choice" | "nonce" | "token">;
134
- readonly attend: FormContract<"budget" | "digest" | "expiry" | "followup" | "minutes" | "model" | "nonce" | "parent" | "posture" | "token" | "turns">;
135
133
  readonly confirmStopped: FormContract<"checked" | "return" | "run" | "token">;
136
134
  readonly merge: FormContract<"anyway" | "run" | "token">;
137
135
  readonly onboard: FormContract<"big-ok" | "nonce" | "repo" | "root" | "token">;
@@ -152,12 +150,9 @@ export declare const CONSOLE_FORMS: {
152
150
  readonly chatFile: FormContract<"token">;
153
151
  readonly chatAck: FormContract<"nonce" | "token">;
154
152
  readonly recipes: FormContract<"document" | "next" | "preview" | "projectRevision" | "purpose" | "recipe" | "recipeRevision" | "repo" | "source" | "sourceRevision">;
155
- readonly routinesAdd: FormContract<"acceptance" | "ceiling" | "goal" | "interval" | "interval-unit" | "name" | "not" | "projectRevision" | "repeat" | "schedule" | "time" | "timezone" | "touches" | "weekday">;
156
- readonly routine: FormContract<"digest" | "nonce" | "token">;
157
153
  readonly runNote: FormContract<"note">;
158
154
  readonly diffComment: FormContract<"batch" | "intent" | "line" | "note" | "path" | "request" | "return" | "source" | "tab">;
159
155
  readonly editorLinks: FormContract<"on" | "return">;
160
- readonly turn: FormContract<"text">;
161
156
  readonly revise: FormContract<"batch" | "return" | "source">;
162
157
  readonly followUp: FormContract<"level" | "return">;
163
158
  readonly resolveIncident: FormContract<"return">;
@@ -172,8 +167,8 @@ export declare const CONSOLE_FORMS: {
172
167
  readonly taskPlanEdit: FormContract<"plan-document" | "saw-plan">;
173
168
  readonly taskRevision: FormContract<"revision-id" | "token">;
174
169
  readonly taskCancel: FormContract<"reason">;
175
- readonly taskRoute: FormContract<"agent" | "clear-phase" | "model" | "phase" | "provider" | "return" | "risk" | "risky" | "sawDigest" | "size">;
176
- readonly taskScope: FormContract<"acceptance" | "budget-microusd" | "budget-usd" | "goal" | "goal-brief" | "not" | "permission-mode" | "quality-mode" | "race-count" | "race-model" | "race-per-usd" | "race-total-usd" | "requirement" | "requirement-new" | "sawDigest" | "touches" | `compare-model-${string}` | `compare-provider-${string}`>;
170
+ readonly taskRoute: FormContract<"agent" | "clear-phase" | "model" | "phase" | "provider" | "return" | "risky" | "sawDigest" | "size">;
171
+ readonly taskScope: FormContract<"acceptance" | "budget-microusd" | "budget-usd" | "goal" | "goal-brief" | "not" | "permission-mode" | "quality-mode" | "requirement" | "requirement-new" | "sawDigest" | "touches">;
177
172
  readonly taskApprove: FormContract<"digest" | "nonce" | "return" | "token">;
178
173
  readonly taskAcceptProof: FormContract<"note" | "return" | "run">;
179
174
  readonly taskComplete: FormContract<"accept" | "note" | "publish" | "receipt" | "return" | "run">;
@@ -181,8 +176,8 @@ export declare const CONSOLE_FORMS: {
181
176
  readonly taskResume: FormContract<"nonce" | "return" | "run" | "token">;
182
177
  };
183
178
  export type ConsoleFormName = keyof typeof CONSOLE_FORMS;
184
- /** The console POSTs whose handlers read no field (sign-out and the attended beat not even the shared guard): their contract is the empty form. */
185
- export declare const BODILESS_POSTS: readonly ["POST /settings/lead/on", "POST /r/<run>/draft-repair", "POST /ledger/checkpoint", "POST /settings/backups/now", "POST /mode/revoke", "POST /settings/telegram/retry", "POST /providers/<provider>/resume", "POST /session/attended-beats", "POST /logout", "POST /t/<task>/unhold", "POST /t/<task>/plan", "POST /t/<task>/retry-review"];
179
+ /** The console POSTs whose handlers read no field (sign-out not even the shared guard): their contract is the empty form. */
180
+ export declare const BODILESS_POSTS: readonly ["POST /settings/lead/on", "POST /r/<run>/draft-repair", "POST /ledger/checkpoint", "POST /settings/backups/now", "POST /mode/revoke", "POST /settings/telegram/retry", "POST /providers/<provider>/resume", "POST /logout", "POST /t/<task>/unhold", "POST /t/<task>/plan", "POST /t/<task>/retry-review"];
186
181
  /** The field names a console form's handler may read. */
187
182
  export type FormFieldOf<N extends ConsoleFormName> = (typeof CONSOLE_FORMS)[N] extends FormContract<infer K> ? K : never;
188
183
  /** `GET /ledger?format=json`: the chain's state, a page of entries (newest first) and the cursor for the next. */
@@ -132,15 +132,13 @@ export const CONSOLE_FORMS = {
132
132
  tasksAdd: formContract("POST /tasks/add", ["projectRevision", "id", "title", "repo", "goal", "not", "touches", "scout", "permission-mode", "quality-mode", "after", "acceptance", "planning-policy", "plan-first"]),
133
133
  queue: formContract("POST /queue/move, /queue/note", ["runner", "note", "from", "projectRevision", "respond", "task", "column", "before", "queueRevision"]),
134
134
  runnerRegister: formContract("POST /fleet/runner/register", ["token", "name", "capacity"]),
135
- mode: formContract("POST /mode/confirm, /mode/sign", ["name", "days", "auto-approve", "plan-auto", "allow-paid-fallback", "chat-approve", "publication", "expiry", "nonce", "digest", "token", "review-auto", "review-retry-auto", "repair-auto"]),
135
+ mode: formContract("POST /mode/confirm, /mode/sign", ["name", "days", "auto-approve", "plan-auto", "chat-approve", "publication", "expiry", "nonce", "digest", "token", "review-auto", "review-retry-auto", "repair-auto"]),
136
136
  peopleProjects: formContract("POST /people/projects", ["token", "name", "access", "projects"]),
137
137
  peopleInvite: formContract("POST /people/invite", ["token", "role", "access", "projects"]),
138
138
  peopleInviteRevoke: formContract("POST /people/invite-revoke", ["token", "id"]),
139
139
  peopleRevoke: formContract("POST /people/revoke", ["token", "name"]),
140
140
  runnerRetire: formContract("POST /fleet/runner/retire", ["token", "name"]),
141
141
  decisionAnswer: formContract("POST /d/<id>/answer", ["return", "choice", "confirm", "note"]),
142
- contest: formContract("POST /contest/<id>/arm|pick|abandon", ["act", "choice", "token", "nonce"]),
143
- attend: formContract("POST /t/<task>/attend|attend-preview|attend-revoke", ["parent", "followup", "minutes", "turns", "budget", "expiry", "model", "posture", "nonce", "digest", "token"]),
144
142
  confirmStopped: formContract("POST /t/<task>/confirm-stopped", ["run", "token", "checked", "return"]),
145
143
  merge: formContract("POST /t/<task>/merge", ["run", "token", "anyway"]),
146
144
  onboard: formContract("POST /projects/onboard-preview, /projects/onboard-confirm", ["repo", "root", "token", "nonce", "big-ok"]),
@@ -162,12 +160,9 @@ export const CONSOLE_FORMS = {
162
160
  chatAck: formContract("POST /chat/ack/<id>", ["token", "nonce"]),
163
161
  // A recipe's own answers and editor fields are read by recipes.ts from the whole form (`sent`; item 17).
164
162
  recipes: formContract("POST /recipes/prepare, /recipes/preview, /recipes/import, /recipes/launch, /recipes/save", ["repo", "projectRevision", "recipe", "recipeRevision", "document", "purpose", "source", "sourceRevision", "preview", "next"]),
165
- routinesAdd: formContract("POST /routines/add", ["projectRevision", "name", "ceiling", "repeat", "interval", "interval-unit", "time", "timezone", "weekday", "schedule", "goal", "not", "touches", "acceptance"]),
166
- routine: formContract("POST /routines/<id>/approve|refresh|pause|resume|run-now", ["digest", "nonce", "token"]),
167
163
  runNote: formContract("POST /r/<run>/note", ["note"]),
168
164
  diffComment: formContract("POST /r/<run>/comment", ["return", "tab", "intent", "batch", "source", "note", "path", "line", "request"]),
169
165
  editorLinks: formContract("POST /session/editor-links", ["on", "return"]),
170
- turn: formContract("POST /r/<run>/turn", ["text"]),
171
166
  revise: formContract("POST /r/<run>/revise", ["return", "batch", "source"]),
172
167
  followUp: formContract("POST /r/<run>/checks|add-tests", ["return", "level"]),
173
168
  resolveIncident: formContract("POST /i/<id>/resolve", ["return"]),
@@ -183,15 +178,15 @@ export const CONSOLE_FORMS = {
183
178
  taskPlanEdit: formContract("POST /t/<task>/plan-edit", ["saw-plan", "plan-document"]),
184
179
  taskRevision: formContract("POST /t/<task>/accept-revision|reject-revision", ["revision-id", "token"]),
185
180
  taskCancel: formContract("POST /t/<task>/cancel", ["reason"]),
186
- taskRoute: formContract("POST /t/<task>/route", ["risk", "size", "risky", "phase", "clear-phase", "agent", "provider", "model", "sawDigest", "return"]),
187
- taskScope: formContract("POST /t/<task>/scope", ["sawDigest", "permission-mode", "quality-mode", "budget-usd", "budget-microusd", "requirement", "requirement-new", "race-count", "race-model", "race-per-usd", "race-total-usd", "goal-brief", "goal", "not", "touches", "acceptance"], { prefixes: ["compare-provider-", "compare-model-"] }),
181
+ taskRoute: formContract("POST /t/<task>/route", ["size", "risky", "phase", "clear-phase", "agent", "provider", "model", "sawDigest", "return"]),
182
+ taskScope: formContract("POST /t/<task>/scope", ["sawDigest", "permission-mode", "quality-mode", "budget-usd", "budget-microusd", "requirement", "requirement-new", "goal-brief", "goal", "not", "touches", "acceptance"]),
188
183
  taskApprove: formContract("POST /t/<task>/approve", ["return", "digest", "token", "nonce"]),
189
184
  taskAcceptProof: formContract("POST /t/<task>/accept-proof", ["run", "note", "return"]),
190
185
  taskComplete: formContract("POST /t/<task>/complete", ["receipt", "run", "accept", "note", "publish", "return"]),
191
186
  taskStop: formContract("POST /t/<task>/stop", ["run", "return"]),
192
187
  taskResume: formContract("POST /t/<task>/resume|resume-arm", ["run", "token", "nonce", "return"]),
193
188
  };
194
- /** The console POSTs whose handlers read no field (sign-out and the attended beat not even the shared guard): their contract is the empty form. */
189
+ /** The console POSTs whose handlers read no field (sign-out not even the shared guard): their contract is the empty form. */
195
190
  export const BODILESS_POSTS = [
196
191
  "POST /settings/lead/on",
197
192
  "POST /r/<run>/draft-repair",
@@ -200,7 +195,6 @@ export const BODILESS_POSTS = [
200
195
  "POST /mode/revoke",
201
196
  "POST /settings/telegram/retry",
202
197
  "POST /providers/<provider>/resume",
203
- "POST /session/attended-beats",
204
198
  "POST /logout",
205
199
  "POST /t/<task>/unhold",
206
200
  "POST /t/<task>/plan",
@@ -5,6 +5,7 @@
5
5
  * message whose button can't be read is answered with why (`data.custom_id: not a Toolroll button`), and nothing is done.
6
6
  */
7
7
  import { z } from "zod";
8
+ import { CHAT_BUTTON_TOKEN } from "./chat-content.js";
8
9
  import { parseContract } from "./contract.js";
9
10
  const user = z.object({ id: z.string() });
10
11
  /** The interaction around a tap (type 3: a message component): the app, the person, the channel, the message. */
@@ -22,7 +23,7 @@ export const discordComponentInteractionSchema = z.object({
22
23
  });
23
24
  /** Toolroll's button data: `so_` and a one-time token. */
24
25
  export const discordButtonSchema = z.object({
25
- custom_id: z.string().regex(/^so_[a-f0-9]{32}$/, { error: "not a Toolroll button" }),
26
+ custom_id: z.string().regex(new RegExp(`^so_${CHAT_BUTTON_TOKEN.source.slice(1)}`), { error: "not a Toolroll button" }),
26
27
  });
27
28
  export function readDiscordComponentInteraction(body) {
28
29
  return parseContract(discordComponentInteractionSchema, body);
@@ -10964,6 +10964,36 @@ export declare const leadTriggerSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
10964
10964
  at: z.ZodOptional<z.ZodString>;
10965
10965
  timeZone: z.ZodOptional<z.ZodString>;
10966
10966
  }, z.core.$strict>], "kind">;
10967
+ /**
10968
+ * v115: the exact task a schedule files each time — what a routine was before routines became scheduled flows. Its
10969
+ * terms are copied into each firing's scope unchanged; `costCeilingUsd` caps what its tasks spend in a rolling 7 days
10970
+ * and a firing waits while the last task is unfinished. `approval` is a routine's approval carried over whole (the
10971
+ * digest the approver signed over these terms, this schedule and project, and the agents it froze): while it still
10972
+ * verifies, each firing is approved as the routine's were; otherwise each firing is an ordinary proposal under the
10973
+ * project's approval rules. Only the v115 migration carries an approval; a template or a recipe makes one with none
10974
+ * (createScheduledFlow), and no trigger settings a person or a flow file gives can carry one.
10975
+ */
10976
+ export declare const standingOrderSchema: z.ZodObject<{
10977
+ stem: z.ZodString;
10978
+ goal: z.ZodString;
10979
+ outOfScope: z.ZodNullable<z.ZodString>;
10980
+ touches: z.ZodArray<z.ZodString>;
10981
+ requirements: z.ZodArray<z.ZodString>;
10982
+ acceptance: z.ZodArray<z.ZodUnknown>;
10983
+ budgetPerRunMicrousd: z.ZodNullable<z.ZodInt>;
10984
+ costCeilingUsd: z.ZodNullable<z.ZodNumber>;
10985
+ singleFlight: z.ZodLiteral<true>;
10986
+ filedBy: z.ZodNullable<z.ZodString>;
10987
+ routine: z.ZodNullable<z.ZodInt>;
10988
+ approval: z.ZodNullable<z.ZodObject<{
10989
+ digest: z.ZodString;
10990
+ by: z.ZodNullable<z.ZodString>;
10991
+ at: z.ZodString;
10992
+ profileJson: z.ZodString;
10993
+ routeJson: z.ZodString;
10994
+ }, z.core.$strict>>;
10995
+ }, z.core.$strict>;
10996
+ export type StandingOrder = z.infer<typeof standingOrderSchema>;
10967
10997
  /** A trigger as it is saved (`configJson`), one schema per kind. */
10968
10998
  export declare const triggerConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
10969
10999
  zone: z.ZodNullable<z.ZodString>;
@@ -10978,6 +11008,26 @@ export declare const triggerConfigSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
10978
11008
  description: z.ZodNullable<z.ZodString>;
10979
11009
  script: z.ZodOptional<z.ZodString>;
10980
11010
  secrets: z.ZodOptional<z.ZodArray<z.ZodString>>;
11011
+ order: z.ZodOptional<z.ZodObject<{
11012
+ stem: z.ZodString;
11013
+ goal: z.ZodString;
11014
+ outOfScope: z.ZodNullable<z.ZodString>;
11015
+ touches: z.ZodArray<z.ZodString>;
11016
+ requirements: z.ZodArray<z.ZodString>;
11017
+ acceptance: z.ZodArray<z.ZodUnknown>;
11018
+ budgetPerRunMicrousd: z.ZodNullable<z.ZodInt>;
11019
+ costCeilingUsd: z.ZodNullable<z.ZodNumber>;
11020
+ singleFlight: z.ZodLiteral<true>;
11021
+ filedBy: z.ZodNullable<z.ZodString>;
11022
+ routine: z.ZodNullable<z.ZodInt>;
11023
+ approval: z.ZodNullable<z.ZodObject<{
11024
+ digest: z.ZodString;
11025
+ by: z.ZodNullable<z.ZodString>;
11026
+ at: z.ZodString;
11027
+ profileJson: z.ZodString;
11028
+ routeJson: z.ZodString;
11029
+ }, z.core.$strict>>;
11030
+ }, z.core.$strict>>;
10981
11031
  }, z.core.$strict>, z.ZodObject<{
10982
11032
  zone: z.ZodNullable<z.ZodString>;
10983
11033
  kind: z.ZodLiteral<"github">;
@@ -309,11 +309,36 @@ export const leadTriggerSchema = z.discriminatedUnion("kind", [
309
309
  TRIGGER_INPUTS.flow.omit({ flow: true }).extend({ follow: z.int().min(1).describe("The other flow's id (get_flows).") }), TRIGGER_INPUTS.email, TRIGGER_INPUTS["plane-review"],
310
310
  ]);
311
311
  const ZONE_OR_NULL = { zone: zoneId.nullable() };
312
+ /**
313
+ * v115: the exact task a schedule files each time — what a routine was before routines became scheduled flows. Its
314
+ * terms are copied into each firing's scope unchanged; `costCeilingUsd` caps what its tasks spend in a rolling 7 days
315
+ * and a firing waits while the last task is unfinished. `approval` is a routine's approval carried over whole (the
316
+ * digest the approver signed over these terms, this schedule and project, and the agents it froze): while it still
317
+ * verifies, each firing is approved as the routine's were; otherwise each firing is an ordinary proposal under the
318
+ * project's approval rules. Only the v115 migration carries an approval; a template or a recipe makes one with none
319
+ * (createScheduledFlow), and no trigger settings a person or a flow file gives can carry one.
320
+ */
321
+ export const standingOrderSchema = z.strictObject({
322
+ stem: z.string().regex(/^[a-z0-9][a-z0-9-]{0,40}$/),
323
+ // The terms exactly as they were approved: each firing's filing checks them again, as every filing is checked.
324
+ goal: z.string().max(8_000),
325
+ outOfScope: z.string().max(8_000).nullable(),
326
+ touches: z.array(z.string().max(800)).max(200),
327
+ requirements: z.array(z.string().max(400)).max(100),
328
+ acceptance: z.array(z.unknown()),
329
+ budgetPerRunMicrousd: z.int().nullable(),
330
+ costCeilingUsd: z.number().nullable(),
331
+ singleFlight: z.literal(true),
332
+ filedBy: z.string().min(1).nullable(),
333
+ /** The routine it came from: that routine's earlier tasks still count toward one-at-a-time and the ceiling. */
334
+ routine: z.int().nullable(),
335
+ approval: z.strictObject({ digest: z.string().min(1), by: z.string().nullable(), at: z.string().min(1), profileJson: z.string().min(1), routeJson: z.string().min(1) }).nullable(),
336
+ });
312
337
  /** A trigger as it is saved (`configJson`), one schema per kind. */
313
338
  export const triggerConfigSchema = z.discriminatedUnion("kind", [
314
339
  z.strictObject({ kind: z.literal("button"), label: z.string().min(1).max(TEXT_LIMITS.triggerButton), questions: z.array(z.string().min(1).max(TEXT_LIMITS.triggerQuestion)).min(1).max(6), ...ZONE_OR_NULL }),
315
340
  /** `script`: run this project script on the schedule and make a card of each item it prints, instead of one card titled `title`. */
316
- z.strictObject({ kind: z.literal("schedule"), schedule: z.string().min(1), title: z.string().min(1).max(TEXT_LIMITS.triggerTitle), description: z.string().max(TEXT_LIMITS.triggerDescription).nullable(), ...ZONE_OR_NULL, script: scriptName.optional(), secrets: z.array(secretName).min(1).max(SECRETS_MAX).optional() }),
341
+ z.strictObject({ kind: z.literal("schedule"), schedule: z.string().min(1), title: z.string().min(1).max(TEXT_LIMITS.triggerTitle), description: z.string().max(TEXT_LIMITS.triggerDescription).nullable(), ...ZONE_OR_NULL, script: scriptName.optional(), secrets: z.array(secretName).min(1).max(SECRETS_MAX).optional(), order: standingOrderSchema.optional() }),
317
342
  z.strictObject({ kind: z.literal("github"), repo: z.string().min(1).max(TEXT_LIMITS.triggerGithubRepo), watch: z.enum(["issues", "pulls", "checks"]), label: z.string().max(TEXT_LIMITS.triggerLabel).nullable(), branch: z.string().max(TEXT_LIMITS.triggerBranch).nullable(), from: z.enum(["team", "anyone"]), delivery, ...ZONE_OR_NULL }),
318
343
  z.strictObject({ kind: z.literal("linear"), team: z.string().max(TEXT_LIMITS.triggerTeam).nullable(), state: z.string().max(TEXT_LIMITS.triggerState).nullable(), label: z.string().max(TEXT_LIMITS.triggerLabel).nullable(), delivery, ...ZONE_OR_NULL }),
319
344
  z.strictObject({ kind: z.literal("flow"), flow: z.int().min(1), when: zoneId, ...ZONE_OR_NULL }),
@@ -686,11 +686,6 @@ export declare const LEAD_TOOL_INPUTS: {
686
686
  }, z.core.$strict>;
687
687
  readonly propose_agents: z.ZodObject<{
688
688
  task: z.ZodString;
689
- risk: z.ZodOptional<z.ZodEnum<{
690
- elevated: "elevated";
691
- high: "high";
692
- routine: "routine";
693
- }>>;
694
689
  size: z.ZodOptional<z.ZodEnum<{
695
690
  large: "large";
696
691
  medium: "medium";
@@ -1388,11 +1383,6 @@ export declare const LEAD_TOOL_READ_INPUTS: {
1388
1383
  }, z.core.$strict>;
1389
1384
  readonly propose_agents: z.ZodObject<{
1390
1385
  task: z.ZodString;
1391
- risk: z.ZodOptional<z.ZodEnum<{
1392
- elevated: "elevated";
1393
- high: "high";
1394
- routine: "routine";
1395
- }>>;
1396
1386
  size: z.ZodOptional<z.ZodEnum<{
1397
1387
  large: "large";
1398
1388
  medium: "medium";
@@ -1811,9 +1801,6 @@ export declare const LEAD_TOOL_OUTPUTS: {
1811
1801
  readonly get_agents: z.ZodObject<{
1812
1802
  repo: z.ZodString;
1813
1803
  task: z.ZodString;
1814
- risk: z.ZodObject<{
1815
- level: z.ZodString;
1816
- }, z.core.$loose>;
1817
1804
  standing: z.ZodString;
1818
1805
  agents: z.ZodArray<z.ZodUnknown>;
1819
1806
  choices: z.ZodObject<{}, z.core.$loose>;
@@ -16,7 +16,7 @@ import { CHAT_TASK_ACTIONS } from "../chat-task-actions.js";
16
16
  import { LIMITS } from "../decision.js";
17
17
  import { CHECK_RESULTS, RUN_OUTCOMES, TASK_STATES } from "../lead-commitments.js";
18
18
  import { PERSON_ID } from "../lead-people.js";
19
- import { RISK_LEVELS, TASK_SIZES } from "../phase-routing.js";
19
+ import { TASK_SIZES } from "../phase-routing.js";
20
20
  import { ACCEPTANCE_LIMITS } from "../scope.js";
21
21
  import { TEAMMATE_TEMPLATES } from "../teammates.js";
22
22
  import { TEXT_LIMITS } from "../text-limits.js";
@@ -134,7 +134,7 @@ export const LEAD_TOOL_INPUTS = {
134
134
  propose_dependency_repair: z.strictObject({ task: taskRef, blocker: taskRef, operation: z.enum(["retry", "unlink", "replace"]), replacement: taskRef.optional() }),
135
135
  propose_scope: z.strictObject({ task: taskRef, goal: scopeText, not: scopeText.nullable().optional(), touches: touches.optional(), acceptance }),
136
136
  propose_agents: z.strictObject({
137
- task: taskRef, risk: z.enum(RISK_LEVELS).optional(),
137
+ task: taskRef,
138
138
  size: z.enum(TASK_SIZES).optional(), risky: z.boolean().optional(),
139
139
  role: z.enum(["planner", "builder", "repair"]).optional(),
140
140
  agent: z.strictObject({ provider: text("agentProvider"), model: text("agentModel") }).optional(),
@@ -238,7 +238,7 @@ export const LEAD_TOOL_OUTPUTS = {
238
238
  repo: str, task: str, root: str, currentExecution: str, title: str, state: str, deliverable: str, scope: str,
239
239
  queue: nullable(z.looseObject({ position: int, of: int, column: str })), holds: list, attempts: int, decisionsOpen: int, dependencies: list,
240
240
  }),
241
- get_agents: z.looseObject({ repo: str, task: str, risk: z.looseObject({ level: str }), standing: str, agents: list, choices: z.looseObject({}), approval: str, organisationPolicy: z.looseObject({}) }),
241
+ get_agents: z.looseObject({ repo: str, task: str, standing: str, agents: list, choices: z.looseObject({}), approval: str, organisationPolicy: z.looseObject({}) }),
242
242
  list_decisions: decisionsOutput,
243
243
  get_decision: decisionOutput,
244
244
  queue: z.looseObject({ repo: str, queueRevision: int, ...queueColumnsOutput }),
@@ -6,11 +6,12 @@
6
6
  */
7
7
  import { z } from "zod";
8
8
  import { parseContract } from "./contract.js";
9
+ import { CHAT_BUTTON_TOKEN } from "./chat-content.js";
9
10
  /** Toolroll's buttons: toolroll_* since the rename; standing_orders_* buttons on older messages still work. */
10
- export const SLACK_BUTTON_ACTION = /^(?:toolroll|standing_orders)_(?:confirm|dismiss|yes|cancel|flow_approve|flow_edit|flow_send_back|flow_choose_[0-3]|flow_note_(?:yes|no)|question_choice|question_words)$/;
11
+ export const SLACK_BUTTON_ACTION = /^(?:toolroll|standing_orders)_(?:confirm|dismiss|yes|cancel|flow_approve|flow_edit|flow_send_back|flow_choose_[0-3]|flow_note_(?:yes|no)|question_choice|question_words|decide_[0-9]{1,2})$/;
11
12
  /** A link button opens its page in Slack's own client; Slack still reports the tap, and there is nothing to do. */
12
13
  export const SLACK_LINK_ACTION = /^(?:toolroll|standing_orders)_link(?:_[0-9]+)?$/;
13
- const token = z.string().regex(/^[a-f0-9]{32}$/, { error: "must be a Toolroll button token" });
14
+ const token = z.string().regex(CHAT_BUTTON_TOKEN, { error: "must be a Toolroll button token" });
14
15
  /** The interaction around a tap: who, and the message the button is on. */
15
16
  export const slackBlockActionsSchema = z.object({
16
17
  type: z.literal("block_actions"),
@@ -115,11 +115,7 @@ declare const STORE_COLUMN_VALUES: {
115
115
  quickMint: z.ZodOptional<z.ZodBoolean>;
116
116
  publication: z.ZodOptional<z.ZodString>;
117
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
118
  readonly "approval_policy.protected_paths": z.ZodArray<z.ZodUnknown>;
122
- readonly "fallback_config.entries_json": z.ZodArray<z.ZodUnknown>;
123
119
  readonly "runner.repos": z.ZodArray<z.ZodUnknown>;
124
120
  readonly "runner.agents": z.ZodArray<z.ZodUnknown>;
125
121
  readonly "decision.options": z.ZodArray<z.ZodObject<{
@@ -159,36 +155,12 @@ declare const STORE_COLUMN_VALUES: {
159
155
  note: z.ZodOptional<z.ZodNullable<z.ZodString>>;
160
156
  }, z.core.$loose>>;
161
157
  }, 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
158
  readonly "publication_grant.capabilities": z.ZodArray<z.ZodEnum<{
167
159
  "open-pr": "open-pr";
168
160
  "push-branch": "push-branch";
169
161
  }>>;
170
162
  readonly "task_ref.zones": z.ZodArray<z.ZodUnknown>;
171
163
  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
164
  readonly "coordinator_proposal.payload_json": z.ZodObject<{}, z.core.$loose>;
193
165
  readonly "coordinator_proposal.outcome_json": z.ZodObject<{}, z.core.$loose>;
194
166
  readonly "mate_proposal.payload_json": z.ZodUnion<readonly [z.ZodObject<{
@@ -278,7 +250,7 @@ declare const STORE_COLUMN_VALUES: {
278
250
  export type StoreColumn = keyof typeof STORE_COLUMN_VALUES;
279
251
  export type StoreColumnValue<C extends StoreColumn> = z.infer<(typeof STORE_COLUMN_VALUES)[C]>;
280
252
  /** 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")[];
253
+ export declare const STORE_COLUMNS: ("approval_policy.protected_paths" | "backend_grant.mutations" | "backend_grant.paths" | "coordinator_proposal.outcome_json" | "coordinator_proposal.payload_json" | "criterion_review.screenshots_json" | "decision.options" | "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" | "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" | "tool_seal.tools_json")[];
282
254
  /** A SQL projection, not a physical column; replay it separately after its owning column. */
283
255
  export declare const STORE_PROJECTIONS: readonly ["run_tool.tools_json.fence"];
284
256
  /** These readers historically only parsed JSON. Shape errors must not change their values or catch boundaries. */
@@ -16,7 +16,6 @@ import { decisionOptionSchema } from "./decision.js";
16
16
  import { scopeTermsSchema, storedRubricSchema } from "./scope.js";
17
17
  import { criterionEvidenceSchema, proofCriterionSchema } from "./proof.js";
18
18
  import { sharedActionSchema } from "./chat-actions.js";
19
- import { telegramCallbackButtonSchema } from "./telegram-callback.js";
20
19
  import { readVersioned, versioned } from "./contract.js";
21
20
  /** Dynamic tool arguments, event details and operation results have no common field contract. */
22
21
  const savedObject = z.looseObject({});
@@ -53,10 +52,6 @@ const savedProgressSchema = z.looseObject({
53
52
  id: z.string(), state: z.enum(["pending", "current", "completed", "blocked"]), note: z.string().nullable().optional(),
54
53
  })),
55
54
  });
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
55
  const savedMatrixRowSchema = proofCriterionSchema.pick({ id: true, statement: true }).extend({
61
56
  id: z.string(), statement: z.string(), requiredEvidence: savedList, state: z.string(), detail: savedList,
62
57
  answered: z.array(criterionEvidenceSchema.extend({ ref: z.string() }).loose()).optional(),
@@ -78,9 +73,7 @@ const STORE_COLUMN_VALUES = {
78
73
  /** Read by the scope contract's `parseAcceptanceCriteria` (`scope.ts`), which owns the criterion's shape. */
79
74
  "task_scope.acceptance_json": storedRubricSchema,
80
75
  "operating_mode.terms_json": savedModeTermsSchema,
81
- "attended_authorization.terms_json": z.looseObject({ profileJson: z.string().nullable().optional() }),
82
76
  "approval_policy.protected_paths": savedList,
83
- "fallback_config.entries_json": savedList,
84
77
  "runner.repos": savedList,
85
78
  "runner.agents": savedList,
86
79
  "decision.options": z.array(savedDecisionOptionSchema),
@@ -93,15 +86,9 @@ const STORE_COLUMN_VALUES = {
93
86
  "mutation.result": z.unknown(),
94
87
  "plan_revision.changed_fields": z.array(z.string()),
95
88
  "run_checkpoint.snapshot_json": savedProgressSchema,
96
- "telegram_conversation_part.keyboard_json": savedKeyboardSchema,
97
89
  "publication_grant.capabilities": z.array(z.enum(["push-branch", "open-pr"])),
98
90
  "task_ref.zones": savedList,
99
91
  "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
92
  "coordinator_proposal.payload_json": savedObject,
106
93
  "coordinator_proposal.outcome_json": savedObject,
107
94
  // Other proposal kinds have operation-specific fields; the action variant already has a canonical contract.
@@ -122,11 +109,11 @@ export const STORE_PROJECTIONS = ["run_tool.tools_json.fence"];
122
109
  export const LEGACY_JSON_COLUMNS = [
123
110
  "teammate_suggestion.rule_json", "teammate_suggestion.was_json", "teammate_suggestion.evidence_json",
124
111
  "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",
112
+ "teammate_event.detail_json", "task_scope.touches", "task_scope.acceptance_json",
113
+ "operating_mode.terms_json", "decision.options", "run_tool.tools_json",
127
114
  "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",
115
+ "run_checkpoint.snapshot_json", "publication_grant.capabilities",
116
+ "coordinator_proposal.payload_json", "coordinator_proposal.outcome_json",
130
117
  "mate_proposal.payload_json", "mate_proposal.outcome_json",
131
118
  ];
132
119
  /** One column's versioned envelope: `{ version: 1, value }`, built in memory around the saved bare value. */
@@ -5,8 +5,9 @@
5
5
  * is answered with why (`value.so: must be a Toolroll button token`), and nothing is done.
6
6
  */
7
7
  import { z } from "zod";
8
+ import { CHAT_BUTTON_TOKEN } from "./chat-content.js";
8
9
  import { parseContract } from "./contract.js";
9
- export const teamsSubmitSchema = z.object({ so: z.string().regex(/^[a-f0-9]{32}$/, { error: "must be a Toolroll button token" }) });
10
+ export const teamsSubmitSchema = z.object({ so: z.string().regex(CHAT_BUTTON_TOKEN, { error: "must be a Toolroll button token" }) });
10
11
  /** A submit's one-time token. */
11
12
  export function readTeamsSubmit(value) {
12
13
  const read = parseContract(z.object({ value: teamsSubmitSchema }), { value });
@@ -110,17 +110,7 @@ export type ChatTaskDraft = {
110
110
  * password before it becomes a real, unapproved scope. */
111
111
  acceptance: AcceptanceCriterion[];
112
112
  };
113
- export type ChatRoutineDraft = {
114
- kind: "routine";
115
- repoId: string;
116
- name: string;
117
- goal: string;
118
- outOfScope: string | null;
119
- touches: string[];
120
- acceptance: AcceptanceCriterion[];
121
- schedule: string;
122
- };
123
- export type ChatDraft = ChatTaskDraft | ChatRoutineDraft;
113
+ export type ChatDraft = ChatTaskDraft;
124
114
  export type ParsedEnvelope = {
125
115
  reply: string;
126
116
  proposals: ChatDraft[];
package/dist/converse.js CHANGED
@@ -22,7 +22,6 @@
22
22
  import { TASK_TEXT_LIMITS } from "./task-text.js";
23
23
  import { createHash } from "node:crypto";
24
24
  import { hasForbiddenControls, hasDisguisedText } from "./decision.js";
25
- import { ROUTINE_NAME, parseSchedule } from "./routine.js";
26
25
  import { parseAcceptanceCriteria } from "./scope.js";
27
26
  // ---------------------------------------------------------------- limits
28
27
  export const WRAPPER_CAP_BYTES = 262_144; // the provider response body
@@ -285,17 +284,8 @@ function readDraft(raw) {
285
284
  return null;
286
285
  const body = raw;
287
286
  const kind = body["kind"];
288
- if (kind === "task") {
289
- if (!exactKeys(body, ["kind", "repoId", "title", "goal", "outOfScope", "touches", "acceptance"]))
290
- return null;
291
- }
292
- else if (kind === "routine") {
293
- if (!exactKeys(body, ["kind", "repoId", "name", "goal", "outOfScope", "touches", "schedule", "acceptance"]))
294
- return null;
295
- }
296
- else {
287
+ if (kind !== "task" || !exactKeys(body, ["kind", "repoId", "title", "goal", "outOfScope", "touches", "acceptance"]))
297
288
  return null;
298
- }
299
289
  const repoId = body["repoId"];
300
290
  const goal = body["goal"];
301
291
  const outOfScope = body["outOfScope"];
@@ -318,28 +308,10 @@ function readDraft(raw) {
318
308
  if (acceptanceParse.problems.length > 0 || acceptanceParse.criteria.length === 0)
319
309
  return null;
320
310
  const acceptance = acceptanceParse.criteria;
321
- if (kind === "task") {
322
- const title = body["title"];
323
- if (typeof title !== "string" || title.trim() === "" || !honest(title, 200, 800))
324
- return null;
325
- return { kind, repoId, title, goal, outOfScope: outOfScope, touches: touches, acceptance };
326
- }
327
- const name = body["name"];
328
- const schedule = body["schedule"];
329
- if (typeof name !== "string" || !ROUTINE_NAME.test(name))
330
- return null;
331
- if (typeof schedule !== "string" || parseSchedule(schedule) === null)
311
+ const title = body["title"];
312
+ if (typeof title !== "string" || title.trim() === "" || !honest(title, 200, 800))
332
313
  return null;
333
- return {
334
- kind,
335
- repoId,
336
- name,
337
- goal,
338
- outOfScope: outOfScope,
339
- touches: touches,
340
- acceptance,
341
- schedule,
342
- };
314
+ return { kind, repoId, title, goal, outOfScope: outOfScope, touches: touches, acceptance };
343
315
  }
344
316
  /**
345
317
  * The assistant envelope: exactly {chatEnvelope: 1, reply, proposals}.
@@ -716,14 +688,12 @@ export function buildDataDocument(snapshot, budgetBytes = DATA_DOCUMENT_BUDGET_B
716
688
  })),
717
689
  decisions: snapshot.decisions.map(one => ({ repo: id(one.repoIndex), id: one.id, question: one.question, optionLabels: one.optionLabels })),
718
690
  incidents: snapshot.incidents.map(one => ({ repo: id(one.repoIndex), kind: one.kind, ageHours: one.ageHours })),
719
- routines: snapshot.routines.map(one => ({ repo: id(one.repoIndex), name: one.name, schedule: one.schedule, status: one.status, lastFire: one.lastFire })),
720
691
  publications: snapshot.publications.map(one => ({ repo: id(one.repoIndex), pr: one.pr, checkState: one.checkState })),
721
692
  };
722
693
  const notShown = {
723
694
  tasks: snapshot.tasksSaturated ? "more exist" : "",
724
695
  decisions: snapshot.decisionsSaturated ? "more exist" : "",
725
696
  incidents: snapshot.incidentsSaturated ? "more exist" : "",
726
- routines: snapshot.routinesSaturated ? "more exist" : "",
727
697
  publications: snapshot.publicationsSaturated ? "more exist" : "",
728
698
  };
729
699
  let shed = 0;
@@ -756,10 +726,8 @@ const SYSTEM_RULES = [
756
726
  "Never recommend which option a pending decision should take.",
757
727
  "Answer with EXACTLY one JSON document and nothing else:",
758
728
  '{"chatEnvelope": 1, "reply": "<markdown-free plain text>", "proposals": []}',
759
- "A proposal is either",
760
- '{"kind":"task","repoId":"r1","title":"…","goal":"…","outOfScope":null,"touches":[],"acceptance":[…]}',
761
- "or",
762
- '{"kind":"routine","repoId":"r1","name":"lowercase-dashes","goal":"…","outOfScope":null,"touches":[],"schedule":"daily:03:30[@Zone], weekly:<0-6>:<HH:MM>[@Zone], or every:<minutes>","acceptance":[…]}.',
729
+ "A proposal is",
730
+ '{"kind":"task","repoId":"r1","title":"…","goal":"…","outOfScope":null,"touches":[],"acceptance":[…]}.',
763
731
  'acceptance is REQUIRED and non-empty: [{"id":"c1","statement":"<one testable outcome>","evidence":["check"|"screenshot"|"changed-path"|"manual-review",…],"how":"<optional guidance, or null>"}]. A proposal with no acceptance criterion is dropped, whole.',
764
732
  "At most 3 proposals. repoId must be one of the ids in the data document.",
765
733
  ].join("\n");
@@ -107,7 +107,6 @@ export declare function statusFor(store: Store, who: VerifiedCoordinator, now: D
107
107
  approvals: number;
108
108
  questions: number;
109
109
  incidents: number;
110
- picks: number;
111
110
  };
112
111
  running: number;
113
112
  builtToday: number;
@@ -300,8 +300,6 @@ export function statusFor(store, who, now) {
300
300
  const incidents = one(`SELECT COUNT(*) AS n FROM incident JOIN run ON run.id = incident.run
301
301
  JOIN task_ref ON task_ref.id = run.task_ref AND task_ref.backend = 'built-in'
302
302
  WHERE task_ref.repo IN (${sql}) AND incident.resolved_at IS NULL`);
303
- const picks = one(`SELECT COUNT(*) AS n FROM contest JOIN task_ref ON task_ref.id = contest.task_ref AND task_ref.backend = 'built-in'
304
- WHERE task_ref.repo IN (${sql}) AND contest.state = 'pick-wait'`);
305
303
  const builtToday = one(`SELECT COUNT(*) AS n FROM run JOIN task_ref ON task_ref.id = run.task_ref AND task_ref.backend = 'built-in'
306
304
  WHERE task_ref.repo IN (${sql}) AND run.outcome = 'built' AND run.finished_at > ?`, [dayAgo]);
307
305
  const failedToday = one(`SELECT COUNT(*) AS n FROM run JOIN task_ref ON task_ref.id = run.task_ref AND task_ref.backend = 'built-in'
@@ -315,8 +313,8 @@ export function statusFor(store, who, now) {
315
313
  .all(...args)
316
314
  .map(row => ({ repo: String(row["repo"]), queued: Number(row["queued"]), running: Number(row["running"]) }));
317
315
  return {
318
- waitsOnYou: unsealed + questions + incidents + picks,
319
- waits: { approvals: unsealed, questions, incidents, picks },
316
+ waitsOnYou: unsealed + questions + incidents,
317
+ waits: { approvals: unsealed, questions, incidents },
320
318
  running,
321
319
  builtToday,
322
320
  failedToday,
@@ -432,7 +430,7 @@ export function taskDetailFor(store, who, taskId, evidenceRoot, now = new Date()
432
430
  scope: {
433
431
  sealed: store.scopeSealed(taskId),
434
432
  goal: scope?.goal ?? null,
435
- // The scope in the console's own words — fallback chain included.
433
+ // The scope in the console's own words.
436
434
  words: scope === null ? [] : describeScope(scope),
437
435
  },
438
436
  waits,