toolroll 0.9.85 → 0.9.86

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 (79) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/agent-fence.d.ts +6 -2
  3. package/dist/agent-fence.js +3 -2
  4. package/dist/assignment.js +4 -3
  5. package/dist/browser/workspace.css +1 -1
  6. package/dist/browser/workspace.js +31 -29
  7. package/dist/browser-workspace.d.ts +40 -0
  8. package/dist/chat-actions.d.ts +11 -1
  9. package/dist/chat-actions.js +53 -1
  10. package/dist/chat-channel.js +1 -0
  11. package/dist/chat-quiet.js +3 -2
  12. package/dist/claim.d.ts +3 -0
  13. package/dist/claim.js +4 -1
  14. package/dist/contracts/chat-actions.d.ts +9 -0
  15. package/dist/contracts/chat-actions.js +3 -0
  16. package/dist/contracts/console-api.d.ts +4 -1
  17. package/dist/contracts/console-api.js +4 -1
  18. package/dist/contracts/flow-propose.d.ts +4 -1
  19. package/dist/contracts/flow-propose.js +1 -1
  20. package/dist/contracts/flow.d.ts +41 -0
  21. package/dist/contracts/flow.js +4 -2
  22. package/dist/contracts/lead-tools.d.ts +21 -0
  23. package/dist/contracts/lead-tools.js +2 -0
  24. package/dist/contracts/store-json.d.ts +2 -0
  25. package/dist/contracts/trigger-payloads.d.ts +20 -0
  26. package/dist/contracts/trigger-payloads.js +4 -0
  27. package/dist/coordinator.js +1 -0
  28. package/dist/deploy-gate.js +4 -0
  29. package/dist/dispatch.d.ts +3 -0
  30. package/dist/dispatch.js +4 -1
  31. package/dist/flow-browser.d.ts +103 -0
  32. package/dist/flow-browser.js +204 -0
  33. package/dist/flow-code.d.ts +5 -1
  34. package/dist/flow-code.js +4 -1
  35. package/dist/flow-engine.js +16 -0
  36. package/dist/flow-live.js +9 -1
  37. package/dist/flow-pull-request.js +15 -7
  38. package/dist/flow-share.js +3 -1
  39. package/dist/flow-steps.d.ts +9 -1
  40. package/dist/flow-steps.js +55 -5
  41. package/dist/flow-triggers.js +55 -0
  42. package/dist/flows-cli.d.ts +19 -0
  43. package/dist/flows-cli.js +47 -2
  44. package/dist/flows-ui.js +11 -2
  45. package/dist/flows.js +5 -2
  46. package/dist/lead-tools.js +35 -6
  47. package/dist/lead-voice.js +16 -5
  48. package/dist/operate.d.ts +1 -1
  49. package/dist/operate.js +215 -6
  50. package/dist/project-delete.js +7 -3
  51. package/dist/pull-request-flow.js +35 -4
  52. package/dist/result-follow-ups.js +4 -0
  53. package/dist/scope.d.ts +5 -0
  54. package/dist/scope.js +7 -0
  55. package/dist/server/chat.js +4 -2
  56. package/dist/server/console.css +29 -0
  57. package/dist/server/flows.js +15 -0
  58. package/dist/server/render-pages.d.ts +13 -0
  59. package/dist/server/render-pages.js +45 -2
  60. package/dist/server/render-tasks.d.ts +8 -0
  61. package/dist/server/render-tasks.js +17 -6
  62. package/dist/server/route-table.js +11 -0
  63. package/dist/server/task-views.js +5 -0
  64. package/dist/server/tasks.d.ts +10 -0
  65. package/dist/server/tasks.js +54 -2
  66. package/dist/settings-proofs.js +1 -0
  67. package/dist/store.d.ts +71 -3
  68. package/dist/store.js +222 -20
  69. package/dist/surface.js +18 -2
  70. package/dist/task-archive.d.ts +10 -0
  71. package/dist/task-archive.js +16 -0
  72. package/dist/task-control.d.ts +1 -1
  73. package/dist/tidy.d.ts +130 -0
  74. package/dist/tidy.js +503 -0
  75. package/dist/work-index.d.ts +24 -0
  76. package/dist/work-index.js +52 -30
  77. package/dist/workspace-ui.d.ts +1 -1
  78. package/dist/workspace-ui.js +3 -2
  79. package/package.json +1 -1
@@ -198,6 +198,12 @@ export type BrowserTasksView = {
198
198
  detail: string | null;
199
199
  problem: string | null;
200
200
  notes: string[];
201
+ /** Put away, or Restore in Archived (task-tidy.md): a POST to the task's own route; null for a viewer or live work. */
202
+ tidy?: {
203
+ action: string;
204
+ label: 'Put away' | 'Restore';
205
+ returnTo: string;
206
+ } | null;
201
207
  }[];
202
208
  empty: {
203
209
  text: string;
@@ -209,6 +215,8 @@ export type BrowserTasksView = {
209
215
  };
210
216
  tools: BrowserLink[];
211
217
  newTask: BrowserLink;
218
+ /** Put away old tasks (an approver's): the preview page. */
219
+ putAway?: BrowserLink | null;
212
220
  /** v105: subscription windows and monthly budgets, one tile each (an instance operator's; null when there are none). */
213
221
  limits: BrowserLimits | null;
214
222
  /** The stored-state filter (Any state, Queued, Running, Done, Failed, Cancelled), each a real link starting on page one. */
@@ -449,6 +457,15 @@ export type BrowserTaskView = {
449
457
  label: string;
450
458
  current: BrowserLink;
451
459
  } | null;
460
+ /** Put away (task-tidy.md): "Archived by tidy: <why>", when, and Restore for an approver. */
461
+ archived?: {
462
+ words: string;
463
+ at: string;
464
+ restore: {
465
+ action: string;
466
+ returnTo: string;
467
+ } | null;
468
+ } | null;
452
469
  /** The status card; `statusHtml` stands in when no assignment projection exists. */
453
470
  status: AssignmentCard | null;
454
471
  statusHtml: string;
@@ -977,6 +994,8 @@ export type BrowserFlowStage = {
977
994
  }[] | undefined;
978
995
  /** A Build zone in another project: its path. */
979
996
  repo?: string | undefined;
997
+ /** v144: a script zone that starts a browser (Playwright's Chromium); it runs only once a person allows browser use for the flow. */
998
+ browser?: true | undefined;
980
999
  next: string | null;
981
1000
  onFail: string | null;
982
1001
  };
@@ -1000,6 +1019,8 @@ export type BrowserFlowCard = {
1000
1019
  stage: string;
1001
1020
  state: "active" | "done" | "cancelled";
1002
1021
  waiting: string | null;
1022
+ /** It waits because browser use isn't allowed for the flow (flow-browser.ts): the card offers Allow browser. */
1023
+ browserWait?: true;
1003
1024
  task: {
1004
1025
  id: string;
1005
1026
  href: string;
@@ -1294,6 +1315,25 @@ export type BrowserFlowView = {
1294
1315
  }[];
1295
1316
  schedulesDigest: string;
1296
1317
  };
1318
+ /** Browser use (flow-browser.ts browserViewOf): null when no zone says it starts a browser. */
1319
+ browser: {
1320
+ status: "allowed" | "ended" | "none";
1321
+ words: string;
1322
+ signedBy: string | null;
1323
+ signedAt: string | null;
1324
+ zones: {
1325
+ zone: string;
1326
+ title: string;
1327
+ script: string;
1328
+ version: number;
1329
+ digest: string;
1330
+ }[];
1331
+ terms: string[];
1332
+ digest: string | null;
1333
+ problem: string | null;
1334
+ /** Whether this person may allow it here: an approver whose account reaches every project (as the route requires). */
1335
+ canApprove: boolean;
1336
+ } | null;
1297
1337
  approvers: string[];
1298
1338
  /** The projects a Build zone may work in: the flow's own first, then others the viewer can reach. */
1299
1339
  projects?: {
@@ -153,6 +153,16 @@ export declare const CHAT_ACTIONS: {
153
153
  readonly protected: false;
154
154
  readonly password: false;
155
155
  };
156
+ readonly flow_browser: {
157
+ readonly label: "Allow browser";
158
+ readonly protected: true;
159
+ readonly password: true;
160
+ };
161
+ readonly flow_browser_off: {
162
+ readonly label: "Turn off browser";
163
+ readonly protected: false;
164
+ readonly password: false;
165
+ };
156
166
  readonly subagent_create: {
157
167
  readonly label: "Add subagent";
158
168
  readonly protected: false;
@@ -266,7 +276,7 @@ export declare function sharedActionReviewPath(id: number): string;
266
276
  export declare function mintSharedActionReview(store: Store, who: VerifiedApprover, id: number, root: string, now: Date): {
267
277
  payload: {
268
278
  version: 1;
269
- operation: "decision_record" | "decision_retire" | "flow_card_add" | "flow_card_approve" | "flow_card_assign" | "flow_card_cancel" | "flow_card_choose" | "flow_card_comment" | "flow_card_move" | "flow_card_send_back" | "flow_card_watch" | "flow_create" | "flow_edit" | "flow_script_save" | "flow_starter" | "flow_trigger_add" | "flow_trigger_pause" | "flow_trigger_remove" | "flow_trigger_resume" | "kit_setup" | "knowledge_instructions" | "knowledge_remove" | "knowledge_restore" | "knowledge_save" | "lead_about_you" | "result_accept" | "scope_approve" | "skill_disable" | "skill_enable" | "skill_import" | "skill_restore" | "skill_test" | "subagent_answer" | "subagent_ask" | "subagent_create" | "subagent_memory" | "subagent_note" | "subagent_routine" | "subagent_soul" | "subagent_state" | "subagent_tools" | "subagent_undo" | "sweep_cancel_rest" | "sweep_file" | "task_cancel" | "task_resume" | "tool_add" | "tool_remove";
279
+ operation: "decision_record" | "decision_retire" | "flow_browser" | "flow_browser_off" | "flow_card_add" | "flow_card_approve" | "flow_card_assign" | "flow_card_cancel" | "flow_card_choose" | "flow_card_comment" | "flow_card_move" | "flow_card_send_back" | "flow_card_watch" | "flow_create" | "flow_edit" | "flow_script_save" | "flow_starter" | "flow_trigger_add" | "flow_trigger_pause" | "flow_trigger_remove" | "flow_trigger_resume" | "kit_setup" | "knowledge_instructions" | "knowledge_remove" | "knowledge_restore" | "knowledge_save" | "lead_about_you" | "result_accept" | "scope_approve" | "skill_disable" | "skill_enable" | "skill_import" | "skill_restore" | "skill_test" | "subagent_answer" | "subagent_ask" | "subagent_create" | "subagent_memory" | "subagent_note" | "subagent_routine" | "subagent_soul" | "subagent_state" | "subagent_tools" | "subagent_undo" | "sweep_cancel_rest" | "sweep_file" | "task_cancel" | "task_resume" | "tool_add" | "tool_remove";
270
280
  request: {
271
281
  [x: string]: unknown;
272
282
  };
@@ -25,6 +25,7 @@ import { saveScript, scriptDigest, validateScript } from "./flow-scripts.js";
25
25
  import { addCardToFlow, advanceFlows, cancelFlowCard, crossProjectProblem, decideFlowCard, flowCardHref, flowCardText, flowDefinitionOf, moveCardInFlow } from "./flow-engine.js";
26
26
  import { chooseFlowCard, flowPersonOf } from "./flow-send.js";
27
27
  import { assignFlowCard, commentOnFlowCard, flowPeople, mentionsIn, watchFlowCard } from "./flow-people.js";
28
+ import { browserViewOf, liveBrowserGrant, revokeFlowBrowser, signFlowBrowser } from "./flow-browser.js";
28
29
  import { addFlowTriggerTo, describeTrigger, readLinearKey, removeFlowTrigger, takesDeliveries, triggerConfigOf, validateTriggerConfig } from "./flow-triggers.js";
29
30
  import { describeSchedule, parseSchedule } from "./flow-schedule.js";
30
31
  import { dirname } from "node:path";
@@ -109,6 +110,10 @@ export const CHAT_ACTIONS = {
109
110
  flow_trigger_pause: { label: "Pause trigger", protected: false, password: false },
110
111
  flow_trigger_resume: { label: "Turn trigger on", protected: false, password: false },
111
112
  flow_trigger_remove: { label: "Remove trigger", protected: false, password: false },
113
+ // Browser use widens a flow's sandbox (flow-browser.ts): the lead may only propose it; a person allows it with their
114
+ // own password on the secure screen, never on a chat card or a paired phone's tap. Turning it off lowers authority.
115
+ flow_browser: { label: "Allow browser", protected: true, password: true },
116
+ flow_browser_off: { label: "Turn off browser", protected: false, password: false },
112
117
  subagent_create: { label: "Add subagent", protected: false, password: false },
113
118
  subagent_soul: { label: "Update soul file", protected: false, password: false },
114
119
  subagent_state: { label: "Change subagent", protected: false, password: false },
@@ -710,6 +715,32 @@ export function prepareSharedAction(store, who, operation, input, root, now = ne
710
715
  terms.push("Only what happens from now on counts; nothing already there is added.");
711
716
  terms.push("Work a card starts still waits for your usual approvals.");
712
717
  }
718
+ else if (operation === "flow_browser" || operation === "flow_browser_off") {
719
+ const { flow } = flowTarget;
720
+ const view = browserViewOf(store, flow);
721
+ if (view === null)
722
+ throw Error(`No zone in ${flow.name} says it starts a browser. Mark its script zone first (edit the flow), then propose this.`);
723
+ // As on the flow page (route table: instance access), a project-limited account can't allow browser use.
724
+ if (operation === "flow_browser" && store.accountOf(who.name)?.projects !== null)
725
+ throw Error("Allowing browser use needs an account with access to every project.");
726
+ if (operation === "flow_browser_off") {
727
+ if (liveBrowserGrant(store, flow.id) === null)
728
+ throw Error(`Browser use isn't allowed for ${flow.name}.`);
729
+ state = { flow: flow.id, grant: liveBrowserGrant(store, flow.id).id };
730
+ title = `Turn off browser use in ${flow.name}`;
731
+ terms.push(`${flow.name}'s browser zones stop and wait until a person allows browser use again.`);
732
+ }
733
+ else {
734
+ if (view.status === "allowed")
735
+ throw Error(`${view.words}.`);
736
+ if (view.digest === null)
737
+ throw Error(view.problem ?? "This flow's browser zones can't be approved as they are.");
738
+ // The approval the person reads and the one their password signs: the digest is re-derived when they confirm.
739
+ state = { flow: flow.id, revision: flow.revision, digest: view.digest };
740
+ title = `Allow browser use in ${flow.name}`;
741
+ terms.push(`Flow: ${flow.name} · project ${project}`, ...view.zones.map(zone => `${zone.title} runs ${zone.script} v${zone.version}\nScript digest ${zone.digest}`), "Each run of these zones starts a headless Chromium.", ...view.terms, `Approval digest ${view.digest}`);
742
+ }
743
+ }
713
744
  else if (operation === "flow_trigger_pause" || operation === "flow_trigger_resume" || operation === "flow_trigger_remove") {
714
745
  const { flow, trigger } = flowTarget;
715
746
  const config = trigger === null ? null : triggerConfigOf(trigger);
@@ -1099,6 +1130,7 @@ export function executeSharedAction(store, who, id, payload, now, options) {
1099
1130
  }
1100
1131
  // The review nonce was minted against the saved proposal's stamp: it is checked against that, whoever reviews.
1101
1132
  const savedStamp = payload.stamp;
1133
+ let personProved = null;
1102
1134
  payload = live;
1103
1135
  const config = CHAT_ACTIONS[live.operation], req = live.request;
1104
1136
  const challenged = options.via !== "web" &&
@@ -1113,10 +1145,14 @@ export function executeSharedAction(store, who, id, payload, now, options) {
1113
1145
  // A scope approval proves its person inside approve() (one transaction with the seal, under the same freshness
1114
1146
  // rule as the task page); here an empty field is only looked at, never spent (an explicit re-check is one-use).
1115
1147
  const emptyApproval = payload.operation === "scope_approve" && options.review.password === "";
1148
+ const proved = config.password && !emptyApproval ? authenticateApprover(store, who.name, options.review.password, payload.repo) : null;
1149
+ // How the person was proved, for an approval that records it (browser use: flow-browser.ts refuses any but a person's).
1150
+ if (proved?.ok === true)
1151
+ personProved = proved.method;
1116
1152
  if (config.password &&
1117
1153
  (emptyApproval
1118
1154
  ? !passwordlessSessionFor(store, who.name) && !ssoNowAvailable(who.name) && withFreshness("approve-standard", () => freshnessFor(who.name)) === null
1119
- : !authenticateApprover(store, who.name, options.review.password, payload.repo).ok))
1155
+ : proved?.ok !== true))
1120
1156
  return refuse("needs-confirm", "Confirm with your password in the secure screen.");
1121
1157
  }
1122
1158
  try {
@@ -1156,6 +1192,22 @@ export function executeSharedAction(store, who, id, payload, now, options) {
1156
1192
  ? {}
1157
1193
  : { restore: Number(req["restore"]) }),
1158
1194
  }, now);
1195
+ else if (payload.operation === "flow_browser") {
1196
+ // Only through the secure screen with the person's own password (protected + password above); signFlowBrowser
1197
+ // re-reads the flow, its zones and scripts in this transaction and refuses unless they are what the card showed.
1198
+ const flow = Number(payload.state["flow"]);
1199
+ // signFlowBrowser re-reads the account's generation and reach in its transaction (it may have narrowed since).
1200
+ const signed = signFlowBrowser(store, { flow, signer: actor, proof: personProved, sawDigest: String(payload.state["digest"] ?? ""), console: { generation: who.generation } }, now);
1201
+ if (!signed.ok)
1202
+ throw Error(signed.message);
1203
+ return { ok: true, taskId: null, said: "Browser allowed. Its browser zones can start Chromium now.", href: `/flows/${flow}` };
1204
+ }
1205
+ else if (payload.operation === "flow_browser_off") {
1206
+ const flow = Number(payload.state["flow"]);
1207
+ if (!revokeFlowBrowser(store, flow, actor, now))
1208
+ throw Error("Browser use was already off.");
1209
+ return { ok: true, taskId: null, said: "Browser turned off. Its browser zones wait until someone allows it again.", href: `/flows/${flow}` };
1210
+ }
1159
1211
  else if (payload.operation.startsWith("flow_")) {
1160
1212
  const done = runFlowAction(store, payload, actor, who.repos, options.root, now);
1161
1213
  return { ok: true, taskId: null, said: done.said, href: done.href };
@@ -578,6 +578,7 @@ export const CHAT_ACTION_PARITY = {
578
578
  ask_owner: { support: "direct", how: "One question with 2-4 options and Something else, drawn as buttons under the reply; the tapped option is sent as the person's next message.", gap: null },
579
579
  search_project_memory: { support: "direct", how: "Read during a turn: one search over decisions, references, lessons and the conversations the person may read.", gap: null },
580
580
  list_tasks: { support: "direct", how: "Read during a turn.", gap: null },
581
+ tidy_preview: { support: "direct", how: "Read during a turn: what Put away old tasks would put away now and why. Only a person puts tasks away, on the console or with the CLI command it names.", gap: null },
581
582
  get_task: {
582
583
  support: "direct",
583
584
  how: "Read during a turn; a reply to a result message pins the exact execution.",
@@ -10,7 +10,7 @@ import { telegramProgressCard } from "./telegram-progress.js";
10
10
  import { assignmentStatusFacts, headlineEmoji, taskStatusOf } from "./task-status.js";
11
11
  import { asksToFinish, batchLine, chatText, chatTitle, factLinkLabel, mentions, READY_ACTIONS } from "./chat-voice.js";
12
12
  import { phoneText, projectLabel } from "./telegram-status.js";
13
- import { isLifecycleNotification } from "./store.js";
13
+ import { isLifecycleNotification, taskArchived } from "./store.js";
14
14
  import { leadSubjectOf } from "./lead-voice.js";
15
15
  import { decideFallbackLink, decideTargetOf } from "./chat-decide.js";
16
16
  import { YOUIYOUX_CARD_KIND } from "./contracts/youiyoux-request.js";
@@ -199,7 +199,8 @@ export function eveningDigestText(store, account, now, root) {
199
199
  const visible = (row) => row.project !== null && store.accountCanAccess(account, row.project);
200
200
  const title = (taskId) => chatTitle(store, taskId);
201
201
  const finished = new Map(), failed = new Map(), waits = new Map();
202
- const facts = store.taskFactsSince(recent).filter(visible);
202
+ // A put-away task (v145) is out of the digest too: nothing about it waits, finished or failed for anyone now.
203
+ const facts = store.taskFactsSince(recent).filter(visible).filter(row => row.taskId === null || !taskArchived(store, row.taskId));
203
204
  for (const row of facts) {
204
205
  if (row.createdAt < since || row.taskId === null)
205
206
  continue;
package/dist/claim.d.ts CHANGED
@@ -103,6 +103,9 @@ export type AcquireResult = {
103
103
  | {
104
104
  ok: false;
105
105
  reason: "coordinator-filed";
106
+ } | {
107
+ ok: false;
108
+ reason: "archived";
106
109
  } | {
107
110
  ok: false;
108
111
  reason: "watch-custody";
package/dist/claim.js CHANGED
@@ -31,7 +31,7 @@ import { randomUUID } from "node:crypto";
31
31
  import { authenticate, drainOf } from "./runner.js";
32
32
  import { pauseForAuth } from "./provider-auth.js";
33
33
  import { DEFAULT_MAX_OPEN_DECISIONS, missingCapability, scopeApprovedForDispatch, taskReadinessBlocker, } from "./dispatch.js";
34
- import { BUILT_IN, } from "./store.js";
34
+ import { BUILT_IN, refArchived, } from "./store.js";
35
35
  import { digestOf } from "./scope.js";
36
36
  import { parseExecutionPlanDocument } from "./plan.js";
37
37
  import { sealUnchangedPlanUnderMode } from "./plan-auto.js";
@@ -109,6 +109,9 @@ function acquireLocked(store, taskRef, runner, options) {
109
109
  if (placedRef !== null && placedRef.coordinatorCid !== null && !store.scopeSealed(placedRef.externalId)) {
110
110
  return { ok: false, reason: "coordinator-filed" };
111
111
  }
112
+ // A PUT-AWAY TASK (v145, task-tidy.md) claims for nobody, on every road: restore it first.
113
+ if (refArchived(store, taskRef))
114
+ return { ok: false, reason: "archived" };
112
115
  // The reservation gate lives HERE, in the one primitive every
113
116
  // acquisition path shares (queue-columns review, finding 1): tick's
114
117
  // acquireIfReady and the raw CLI claim both
@@ -160,6 +160,13 @@ export declare const chatActionRequestSchemas: {
160
160
  readonly flow_trigger_remove: z.ZodObject<{
161
161
  trigger: z.ZodInt;
162
162
  }, z.core.$strict>;
163
+ /** Browser use in the flow's script zones (flow-browser.ts): allowing it takes the person's own password in the secure screen. */
164
+ readonly flow_browser: z.ZodObject<{
165
+ flow: z.ZodInt;
166
+ }, z.core.$strict>;
167
+ readonly flow_browser_off: z.ZodObject<{
168
+ flow: z.ZodInt;
169
+ }, z.core.$strict>;
163
170
  readonly subagent_create: z.ZodObject<{
164
171
  repo: z.ZodString;
165
172
  template: z.ZodOptional<z.ZodUnknown>;
@@ -282,6 +289,8 @@ export declare const sharedActionSchema: z.ZodObject<{
282
289
  operation: z.ZodEnum<{
283
290
  decision_record: "decision_record";
284
291
  decision_retire: "decision_retire";
292
+ flow_browser: "flow_browser";
293
+ flow_browser_off: "flow_browser_off";
285
294
  flow_card_add: "flow_card_add";
286
295
  flow_card_approve: "flow_card_approve";
287
296
  flow_card_assign: "flow_card_assign";
@@ -61,6 +61,9 @@ export const chatActionRequestSchemas = {
61
61
  flow_trigger_pause: z.strictObject({ trigger: id }),
62
62
  flow_trigger_resume: z.strictObject({ trigger: id }),
63
63
  flow_trigger_remove: z.strictObject({ trigger: id }),
64
+ /** Browser use in the flow's script zones (flow-browser.ts): allowing it takes the person's own password in the secure screen. */
65
+ flow_browser: z.strictObject({ flow: id }),
66
+ flow_browser_off: z.strictObject({ flow: id }),
64
67
  subagent_create: z.strictObject({ repo: words, template: z.unknown().optional(), name: z.unknown().optional(), soul: z.unknown().optional() }),
65
68
  subagent_soul: z.strictObject({ subagent: id, soul: words }),
66
69
  subagent_state: z.strictObject({ subagent: id, state: z.enum(["active", "paused", "removed"]) }),
@@ -79,7 +79,7 @@ export declare const CONSOLE_FORMS: {
79
79
  readonly kit: FormContract<"password" | "repo">;
80
80
  readonly subagents: FormContract<"choice" | "dailyTurns" | "id" | "manager" | "model" | "name" | "note" | "op" | "password" | "repo" | "schedule" | "soul" | "state" | "template" | "text" | "tool" | `field.${string}` | `over.${string}` | `undo.${string}` | `use.${string}`>;
81
81
  readonly galleryUse: FormContract<string>;
82
- readonly flows: FormContract<"about" | "address" | "answers" | "approve" | "body" | "budget" | "choice" | "confirm" | "days" | "decision" | "definition" | "description" | "document" | "draft" | "entry" | "file" | "include" | "key" | "label" | "language" | "name" | "note" | "owner" | "password" | "previewed" | "project" | "remove" | "repo" | "revision" | "runs" | "schedules" | "secret" | "sender" | "stage" | "team" | "template" | "timeoutMinutes" | "title" | "trigger" | "url" | "value" | "watching" | `param.${string}`>;
82
+ readonly flows: FormContract<"about" | "address" | "answers" | "approve" | "body" | "budget" | "choice" | "confirm" | "days" | "decision" | "definition" | "description" | "digest" | "document" | "draft" | "entry" | "file" | "include" | "key" | "label" | "language" | "name" | "note" | "owner" | "password" | "previewed" | "project" | "remove" | "repo" | "revision" | "runs" | "schedules" | "secret" | "sender" | "stage" | "team" | "template" | "timeoutMinutes" | "title" | "trigger" | "url" | "value" | "watching" | `param.${string}`>;
83
83
  readonly spendBudget: FormContract<"action" | "password" | "stop" | "target" | "usd">;
84
84
  readonly projectConcurrency: FormContract<"concurrency" | "repo">;
85
85
  readonly projectLiveView: FormContract<"act" | "nonce" | "password" | "repo">;
@@ -174,6 +174,9 @@ export declare const CONSOLE_FORMS: {
174
174
  readonly revise: FormContract<"batch" | "return" | "source">;
175
175
  readonly followUp: FormContract<"level" | "return">;
176
176
  readonly resolveIncident: FormContract<"return">;
177
+ readonly taskArchive: FormContract<"reason" | "return">;
178
+ readonly taskRestore: FormContract<"return">;
179
+ readonly tasksPutAway: FormContract<"days" | "digest" | "password" | "task">;
177
180
  readonly taskSteer: FormContract<"after" | "key" | "note" | "request" | "return" | "run">;
178
181
  readonly taskReply: FormContract<"answer" | "question">;
179
182
  readonly taskHold: FormContract<"reason">;
@@ -88,7 +88,7 @@ export const CONSOLE_FORMS = {
88
88
  kit: formContract("POST /kits/<kit>/<act>", ["repo", "password"]),
89
89
  subagents: formContract("POST /settings/lead/subagents/new, /settings/lead/subagents/<id>/<part>, /settings/lead/subagents/questions/<id>/answer", ["choice", "text", "repo", "template", "name", "soul", "op", "id", "schedule", "tool", "state", "note", "model", "dailyTurns", "manager", "password"], { prefixes: ["use.", "undo.", "field.", "over."] }),
90
90
  galleryUse: formContract("POST /flows/new/<template>", ["repo", "send-result", "name", "intent", "previewed", "password"], { dynamic: true }),
91
- flows: formContract("POST /flows/new, /flows/example, /flows/import, /flows/<id>/<act>, /flows/<id>/cards/<card>/<act>, /flows/<id>/triggers/<trigger>/<act>", ["repo", "document", "url", "confirm", "previewed", "template", "name", "answers", "password", "secret", "sender", "project", "team", "trigger", "approve", "remove", "about", "body", "timeoutMinutes", "language", "file", "address", "key", "definition", "owner", "revision", "value", "title", "description", "stage", "decision", "note", "draft", "choice", "entry", "label", "watching", "days", "budget", "runs", "include", "schedules"], { prefixes: ["param."] }),
91
+ flows: formContract("POST /flows/new, /flows/example, /flows/import, /flows/<id>/<act>, /flows/<id>/cards/<card>/<act>, /flows/<id>/triggers/<trigger>/<act>", ["repo", "document", "url", "confirm", "previewed", "template", "name", "answers", "password", "secret", "sender", "project", "team", "trigger", "approve", "remove", "about", "body", "timeoutMinutes", "language", "file", "address", "key", "definition", "owner", "revision", "value", "title", "description", "stage", "decision", "note", "draft", "choice", "entry", "label", "watching", "days", "budget", "runs", "include", "schedules", "digest"], { prefixes: ["param."] }),
92
92
  spendBudget: formContract("POST /spend/budget", ["password", "target", "action", "usd", "stop"]),
93
93
  projectConcurrency: formContract("POST /settings/project/concurrency", ["repo", "concurrency"]),
94
94
  projectLiveView: formContract("POST /settings/project/live-view", ["repo", "act", "password", "nonce"]),
@@ -188,6 +188,9 @@ export const CONSOLE_FORMS = {
188
188
  revise: formContract("POST /r/<run>/revise", ["return", "batch", "source"]),
189
189
  followUp: formContract("POST /r/<run>/checks|add-tests", ["return", "level"]),
190
190
  resolveIncident: formContract("POST /i/<id>/resolve", ["return"]),
191
+ taskArchive: formContract("POST /t/<task>/archive", ["reason", "return"]),
192
+ taskRestore: formContract("POST /t/<task>/restore", ["return"]),
193
+ tasksPutAway: formContract("POST /work/put-away", ["digest", "days", "task", "password"]),
191
194
  // A task's verbs (/t/<task>/<verb>), one body each.
192
195
  taskSteer: formContract("POST /t/<task>/steer", ["note", "return", "run", "key", "after", "request"]),
193
196
  taskReply: formContract("POST /t/<task>/reply", ["question", "answer"]),
@@ -4,11 +4,12 @@
4
4
  * (mate-tools.ts). The lead-tools contract (item 5) imports it from here rather than restating it.
5
5
  */
6
6
  import { z } from "zod";
7
- export declare const PROPOSE_FLOW_OPERATIONS: readonly ["create", "edit", "add_card", "move_card", "approve", "send_back", "choose", "cancel_card", "comment", "assign", "follow", "unfollow", "save_script", "add_trigger", "pause_trigger", "resume_trigger", "remove_trigger", "kit", "starter"];
7
+ export declare const PROPOSE_FLOW_OPERATIONS: readonly ["create", "edit", "add_card", "move_card", "approve", "send_back", "choose", "cancel_card", "comment", "assign", "follow", "unfollow", "save_script", "add_trigger", "pause_trigger", "resume_trigger", "remove_trigger", "kit", "starter", "allow_browser", "turn_off_browser"];
8
8
  export declare const proposeFlowInputSchema: z.ZodObject<{
9
9
  operation: z.ZodEnum<{
10
10
  add_card: "add_card";
11
11
  add_trigger: "add_trigger";
12
+ allow_browser: "allow_browser";
12
13
  approve: "approve";
13
14
  assign: "assign";
14
15
  cancel_card: "cancel_card";
@@ -25,6 +26,7 @@ export declare const proposeFlowInputSchema: z.ZodObject<{
25
26
  save_script: "save_script";
26
27
  send_back: "send_back";
27
28
  starter: "starter";
29
+ turn_off_browser: "turn_off_browser";
28
30
  unfollow: "unfollow";
29
31
  }>;
30
32
  repo: z.ZodOptional<z.ZodString>;
@@ -87,6 +89,7 @@ export declare const proposeFlowInputSchema: z.ZodObject<{
87
89
  id: z.ZodOptional<z.ZodString>;
88
90
  title: z.ZodString;
89
91
  kind: z.ZodLiteral<"check">;
92
+ browser: z.ZodOptional<z.ZodBoolean>;
90
93
  ifFails: z.ZodOptional<z.ZodString>;
91
94
  next: z.ZodOptional<z.ZodString>;
92
95
  remindAfter: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodInt]>>;
@@ -11,7 +11,7 @@ import { KITS } from "../kits.js";
11
11
  import { TEXT_LIMITS } from "../text-limits.js";
12
12
  import { toModelSchema } from "./contract.js";
13
13
  import { flowStepsSchema, leadTriggerSchema, SCRIPT_LANGUAGES, SCRIPT_NAME } from "./flow.js";
14
- export const PROPOSE_FLOW_OPERATIONS = ["create", "edit", "add_card", "move_card", "approve", "send_back", "choose", "cancel_card", "comment", "assign", "follow", "unfollow", "save_script", "add_trigger", "pause_trigger", "resume_trigger", "remove_trigger", "kit", "starter"];
14
+ export const PROPOSE_FLOW_OPERATIONS = ["create", "edit", "add_card", "move_card", "approve", "send_back", "choose", "cancel_card", "comment", "assign", "follow", "unfollow", "save_script", "add_trigger", "pause_trigger", "resume_trigger", "remove_trigger", "kit", "starter", "allow_browser", "turn_off_browser"];
15
15
  const id = z.int().min(1);
16
16
  const enumOf = (values) => z.enum(values);
17
17
  export const proposeFlowInputSchema = z.strictObject({