toolroll 0.9.63 → 0.9.65

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 (292) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/README.md +15 -5
  3. package/dist/acp-agents.d.ts +43 -0
  4. package/dist/acp-agents.js +62 -0
  5. package/dist/acp-attest.d.ts +44 -0
  6. package/dist/acp-attest.js +269 -0
  7. package/dist/acp-check.d.ts +28 -0
  8. package/dist/acp-check.js +410 -0
  9. package/dist/acp-client.d.ts +163 -0
  10. package/dist/acp-client.js +738 -0
  11. package/dist/acp-inspect.d.ts +23 -0
  12. package/dist/acp-inspect.js +109 -0
  13. package/dist/agent-board.d.ts +19 -6
  14. package/dist/agent-board.js +30 -9
  15. package/dist/agent-fence.d.ts +50 -2
  16. package/dist/agent-fence.js +157 -10
  17. package/dist/agent-pulse.js +9 -2
  18. package/dist/agent-state-words.d.ts +19 -0
  19. package/dist/agent-state-words.js +20 -0
  20. package/dist/agent-state.d.ts +65 -0
  21. package/dist/agent-state.js +229 -0
  22. package/dist/agentconfig.js +36 -13
  23. package/dist/agents-board.d.ts +34 -2
  24. package/dist/agents-board.js +110 -1
  25. package/dist/approval-rules-ui.js +2 -2
  26. package/dist/assignment-delivery.d.ts +14 -0
  27. package/dist/assignment-delivery.js +13 -0
  28. package/dist/assignment.js +13 -0
  29. package/dist/attest.js +7 -0
  30. package/dist/backup-ui.js +2 -2
  31. package/dist/browser/THIRD_PARTY_NOTICES.txt +48 -0
  32. package/dist/browser/terminal.css +37 -0
  33. package/dist/browser/terminal.js +117 -0
  34. package/dist/browser/workspace.css +2 -2
  35. package/dist/browser/workspace.js +42 -38
  36. package/dist/browser-shell.js +6 -3
  37. package/dist/browser-workspace.d.ts +235 -1
  38. package/dist/browser-workspace.js +60 -0
  39. package/dist/builder.d.ts +6 -1
  40. package/dist/builder.js +34 -13
  41. package/dist/chat-actions.d.ts +13 -1
  42. package/dist/chat-actions.js +197 -15
  43. package/dist/chat-ask.d.ts +4 -0
  44. package/dist/chat-ask.js +14 -0
  45. package/dist/chat-channel.js +20 -0
  46. package/dist/chat-continuity.js +5 -4
  47. package/dist/chat-decide.d.ts +0 -14
  48. package/dist/chat-decide.js +4 -1
  49. package/dist/chat-delivery.d.ts +9 -0
  50. package/dist/chat-delivery.js +45 -6
  51. package/dist/chat-messages.d.ts +8 -0
  52. package/dist/chat-messages.js +36 -4
  53. package/dist/check-levels-ui.js +2 -2
  54. package/dist/checkout-proof.d.ts +28 -0
  55. package/dist/checkout-proof.js +62 -0
  56. package/dist/claim.d.ts +12 -0
  57. package/dist/claim.js +19 -0
  58. package/dist/cli-help.d.ts +1 -1
  59. package/dist/cli-help.js +4 -1
  60. package/dist/cli.d.ts +3 -0
  61. package/dist/cli.js +21 -2
  62. package/dist/coding-ui.js +6 -4
  63. package/dist/console-instance.d.ts +124 -0
  64. package/dist/console-instance.js +337 -0
  65. package/dist/contracts/chat-actions.d.ts +16 -0
  66. package/dist/contracts/chat-actions.js +4 -0
  67. package/dist/contracts/chat-content.d.ts +19 -0
  68. package/dist/contracts/chat-content.js +6 -0
  69. package/dist/contracts/console-api.d.ts +12 -4
  70. package/dist/contracts/console-api.js +12 -4
  71. package/dist/contracts/flow-card.d.ts +4 -0
  72. package/dist/contracts/flow-card.js +3 -0
  73. package/dist/contracts/flow.d.ts +46 -0
  74. package/dist/contracts/flow.js +11 -2
  75. package/dist/contracts/lead-tools.d.ts +92 -0
  76. package/dist/contracts/lead-tools.js +13 -0
  77. package/dist/contracts/provider.d.ts +11 -1
  78. package/dist/contracts/provider.js +1 -1
  79. package/dist/contracts/route.d.ts +76 -1
  80. package/dist/contracts/route.js +1 -1
  81. package/dist/contracts/store-json.d.ts +2 -0
  82. package/dist/control-setup.d.ts +1 -1
  83. package/dist/control-ui.js +2 -2
  84. package/dist/converse.d.ts +16 -0
  85. package/dist/converse.js +32 -4
  86. package/dist/demo-chat.js +4 -4
  87. package/dist/demo.js +2 -2
  88. package/dist/desktop-update-gate.js +6 -0
  89. package/dist/desktop-update.d.ts +1 -1
  90. package/dist/discord-chat.js +4 -1
  91. package/dist/doctor.js +1 -1
  92. package/dist/egress-bridge.d.ts +17 -0
  93. package/dist/egress-bridge.js +111 -0
  94. package/dist/egress.d.ts +119 -0
  95. package/dist/egress.js +423 -0
  96. package/dist/exec.d.ts +78 -0
  97. package/dist/exec.js +367 -9
  98. package/dist/export-ui.js +2 -2
  99. package/dist/flow-engine.js +24 -5
  100. package/dist/flow-gallery-ui.js +2 -2
  101. package/dist/flow-gallery.js +27 -8
  102. package/dist/flow-share.js +16 -5
  103. package/dist/flow-triggers.d.ts +77 -8
  104. package/dist/flow-triggers.js +517 -70
  105. package/dist/flows-cli.js +8 -2
  106. package/dist/flows-ui.d.ts +0 -2
  107. package/dist/flows-ui.js +52 -4
  108. package/dist/flows.d.ts +4 -0
  109. package/dist/flows.js +9 -1
  110. package/dist/html.d.ts +9 -0
  111. package/dist/html.js +11 -0
  112. package/dist/invoke.d.ts +17 -0
  113. package/dist/invoke.js +217 -21
  114. package/dist/keys.d.ts +18 -14
  115. package/dist/keys.js +5 -0
  116. package/dist/lead-capabilities.js +3 -2
  117. package/dist/lead-contract.js +2 -0
  118. package/dist/lead-doors.d.ts +2 -0
  119. package/dist/lead-doors.js +7 -0
  120. package/dist/lead-follow.d.ts +2 -0
  121. package/dist/lead-follow.js +58 -2
  122. package/dist/lead-progress.js +1 -0
  123. package/dist/lead-queue-runtime.d.ts +46 -0
  124. package/dist/lead-queue-runtime.js +191 -0
  125. package/dist/lead-queue.d.ts +104 -0
  126. package/dist/lead-queue.js +187 -0
  127. package/dist/lead-sweep.d.ts +67 -0
  128. package/dist/lead-sweep.js +99 -0
  129. package/dist/lead-tools.d.ts +22 -0
  130. package/dist/lead-tools.js +152 -1
  131. package/dist/lead.d.ts +13 -5
  132. package/dist/lead.js +89 -29
  133. package/dist/limits-ui.d.ts +8 -1
  134. package/dist/limits-ui.js +26 -0
  135. package/dist/live-bus.d.ts +8 -0
  136. package/dist/live-bus.js +40 -4
  137. package/dist/live-detail.d.ts +27 -0
  138. package/dist/live-detail.js +57 -0
  139. package/dist/live-notes.d.ts +20 -0
  140. package/dist/live-notes.js +47 -0
  141. package/dist/live-records.d.ts +140 -0
  142. package/dist/live-records.js +935 -0
  143. package/dist/live-terminal.d.ts +258 -0
  144. package/dist/live-terminal.js +649 -0
  145. package/dist/live.d.ts +38 -27
  146. package/dist/live.js +142 -124
  147. package/dist/mcp-oauth.d.ts +6 -3
  148. package/dist/mcp-oauth.js +8 -4
  149. package/dist/memory-pass.js +2 -2
  150. package/dist/mobile-viewport.d.ts +5 -1
  151. package/dist/mobile-viewport.js +18 -2
  152. package/dist/model-catalog.js +4 -0
  153. package/dist/monitoring-ui.js +2 -2
  154. package/dist/needs-you.d.ts +1 -1
  155. package/dist/needs-you.js +11 -4
  156. package/dist/operate.d.ts +2 -0
  157. package/dist/operate.js +275 -17
  158. package/dist/passwordless.d.ts +23 -0
  159. package/dist/passwordless.js +26 -0
  160. package/dist/peek-cli.d.ts +12 -4
  161. package/dist/peek-cli.js +19 -11
  162. package/dist/phase-routing.js +10 -3
  163. package/dist/planner-source.d.ts +3 -0
  164. package/dist/planner-source.js +14 -0
  165. package/dist/planner.d.ts +2 -1
  166. package/dist/planner.js +7 -1
  167. package/dist/policy-ui.js +2 -2
  168. package/dist/policy.d.ts +1 -20
  169. package/dist/policy.js +29 -2
  170. package/dist/project-delete-ui.d.ts +12 -0
  171. package/dist/project-delete-ui.js +41 -9
  172. package/dist/project-delete.js +2 -2
  173. package/dist/project-memory.d.ts +3 -1
  174. package/dist/project-memory.js +57 -25
  175. package/dist/project-tools.d.ts +5 -3
  176. package/dist/project-tools.js +12 -9
  177. package/dist/provider-auth.d.ts +4 -3
  178. package/dist/provider-auth.js +5 -4
  179. package/dist/provider-connection.d.ts +2 -1
  180. package/dist/provider-connection.js +5 -0
  181. package/dist/provider.d.ts +25 -2
  182. package/dist/provider.js +63 -9
  183. package/dist/pull-request-ui.js +2 -2
  184. package/dist/push.js +1 -1
  185. package/dist/quick-start.d.ts +24 -0
  186. package/dist/quick-start.js +127 -0
  187. package/dist/release.d.ts +3 -0
  188. package/dist/release.js +14 -8
  189. package/dist/request-budget-ui.js +2 -2
  190. package/dist/result-review.d.ts +1 -1
  191. package/dist/result-review.js +9 -3
  192. package/dist/retention-ui.js +2 -2
  193. package/dist/retention.js +10 -1
  194. package/dist/run-efficiency.d.ts +73 -0
  195. package/dist/run-efficiency.js +228 -0
  196. package/dist/runner.d.ts +5 -1
  197. package/dist/runner.js +22 -1
  198. package/dist/scope.d.ts +170 -5
  199. package/dist/scope.js +251 -31
  200. package/dist/scout-net.d.ts +4 -1
  201. package/dist/scout-net.js +37 -12
  202. package/dist/scout.d.ts +20 -6
  203. package/dist/scout.js +27 -3
  204. package/dist/serve.js +247 -40
  205. package/dist/server/chat.d.ts +1 -1
  206. package/dist/server/chat.js +122 -31
  207. package/dist/server/chrome.d.ts +6 -1
  208. package/dist/server/chrome.js +18 -7
  209. package/dist/server/console.css +52 -38
  210. package/dist/server/flows.js +38 -8
  211. package/dist/server/guards.d.ts +1 -0
  212. package/dist/server/guards.js +23 -9
  213. package/dist/server/http.d.ts +7 -0
  214. package/dist/server/http.js +3 -2
  215. package/dist/server/live.d.ts +34 -1
  216. package/dist/server/live.js +39 -17
  217. package/dist/server/pages-assets.js +5 -0
  218. package/dist/server/pages.js +90 -13
  219. package/dist/server/people-tokens.d.ts +3 -0
  220. package/dist/server/people-tokens.js +55 -17
  221. package/dist/server/remote-hooks.js +12 -6
  222. package/dist/server/remote.d.ts +2 -1
  223. package/dist/server/remote.js +14 -5
  224. package/dist/server/render-chat.d.ts +12 -3
  225. package/dist/server/render-chat.js +47 -16
  226. package/dist/server/render-pages.d.ts +4 -1
  227. package/dist/server/render-pages.js +5 -4
  228. package/dist/server/render-people.d.ts +3 -2
  229. package/dist/server/render-people.js +3 -2
  230. package/dist/server/render-results.d.ts +18 -2
  231. package/dist/server/render-results.js +37 -28
  232. package/dist/server/render-settings.js +6 -5
  233. package/dist/server/render-tasks.d.ts +35 -10
  234. package/dist/server/render-tasks.js +110 -27
  235. package/dist/server/request-context.d.ts +2 -0
  236. package/dist/server/request-context.js +2 -1
  237. package/dist/server/route-table.d.ts +3 -0
  238. package/dist/server/route-table.js +46 -5
  239. package/dist/server/runtime.d.ts +33 -2
  240. package/dist/server/session.d.ts +25 -1
  241. package/dist/server/session.js +18 -4
  242. package/dist/server/settings.js +121 -10
  243. package/dist/server/sweeps.d.ts +4 -0
  244. package/dist/server/sweeps.js +58 -0
  245. package/dist/server/task-views.d.ts +2 -1
  246. package/dist/server/task-views.js +96 -6
  247. package/dist/server/tasks.js +320 -74
  248. package/dist/server/terminals.d.ts +31 -0
  249. package/dist/server/terminals.js +365 -0
  250. package/dist/setup-guide.js +3 -2
  251. package/dist/slack-chat.js +4 -1
  252. package/dist/spend-ui.js +3 -3
  253. package/dist/spend.js +2 -1
  254. package/dist/steer-capabilities.d.ts +32 -0
  255. package/dist/steer-capabilities.js +60 -0
  256. package/dist/steer-controls.d.ts +14 -0
  257. package/dist/steer-controls.js +36 -0
  258. package/dist/steer-status.js +2 -2
  259. package/dist/storage-ui.js +4 -4
  260. package/dist/store-baseline.d.ts +1 -1
  261. package/dist/store-baseline.js +1 -1
  262. package/dist/store.d.ts +430 -15
  263. package/dist/store.js +1041 -52
  264. package/dist/subagent-desk.js +1 -1
  265. package/dist/summary.js +3 -0
  266. package/dist/task-source.d.ts +58 -0
  267. package/dist/task-source.js +93 -0
  268. package/dist/team-leads.js +1 -1
  269. package/dist/teams-chat.js +4 -1
  270. package/dist/telegram-lead.d.ts +3 -0
  271. package/dist/telegram-lead.js +44 -7
  272. package/dist/telegram.d.ts +11 -2
  273. package/dist/telegram.js +51 -17
  274. package/dist/terminal-catalog.d.ts +11 -0
  275. package/dist/terminal-catalog.js +129 -0
  276. package/dist/text-limits.d.ts +2 -0
  277. package/dist/text-limits.js +2 -0
  278. package/dist/tool-broker.d.ts +2 -0
  279. package/dist/tool-broker.js +1 -0
  280. package/dist/toolroll-update-ui.js +2 -2
  281. package/dist/toolroll-update.js +13 -3
  282. package/dist/tools-ui.js +2 -2
  283. package/dist/webhook-limits.d.ts +23 -0
  284. package/dist/webhook-limits.js +30 -0
  285. package/dist/webhook-readers.d.ts +56 -0
  286. package/dist/webhook-readers.js +138 -0
  287. package/dist/webhook-signing.d.ts +27 -0
  288. package/dist/webhook-signing.js +119 -0
  289. package/dist/work-index.d.ts +29 -0
  290. package/dist/work-index.js +16 -2
  291. package/dist/workspace-revision.js +3 -1
  292. package/package.json +11 -2
package/dist/flows-cli.js CHANGED
@@ -16,11 +16,12 @@ import { saveScript } from './flow-scripts.js';
16
16
  import { exportFlow, fetchFlowFile, FLOW_FILE_MAX_BYTES, FlowFileError, importFlow, parseFlowFile, planFlowImport } from './flow-share.js';
17
17
  import { describeStandingOrder } from './flow-schedule.js';
18
18
  import { STARTER_FLOWS, starterFlowOf, starterOf, startersFor, starterTerms, switchOnStarter } from './flow-starters.js';
19
- import { addFlowTriggerTo, checkFlowTriggerNow, describeTrigger, removeFlowTrigger, setFlowTriggerOn, triggerConfigOf, validateTriggerConfig } from './flow-triggers.js';
19
+ import { addFlowTriggerTo, checkFlowTriggerNow, describeTrigger, removeFlowTrigger, setFlowTriggerOn, triggerConfigOf, validateTriggerConfig, rawTakesDeliveries } from './flow-triggers.js';
20
20
  import { deciderOf, FLOW_KIND_WORDS, FLOW_TEMPLATES, flowDigest, flowFromSteps, flowTerms, stepsFor } from './flows.js';
21
21
  import { prepareUnattendedCandidates, activeUnattendedGrant, parseUnattendedAsk, revokeUnattended, signUnattended, unattendedViewOf, unattendedWords, untilWords, UNATTENDED_MAX_RUNS } from './flow-unattended.js';
22
22
  import { MODE_MAX_DAYS } from './modes.js';
23
23
  import { verifyApproverByPassword } from './principal.js';
24
+ import { proveCredential } from './scope.js';
24
25
  import { projectName } from './project.js';
25
26
  const EXIT = { ok: 0, failed: 1, usage: 2, refused: 3 };
26
27
  const json = { name: 'json', takesValue: false, meaning: 'answer with one machine envelope on stdout' };
@@ -502,7 +503,12 @@ export async function runFlowsCommand(positional, flags, context) {
502
503
  const zone = definition.stages.find(one => one.id === (config.zone ?? definition.start))?.title ?? 'the first zone';
503
504
  return preview(flow.repo, `Add a trigger to ${flow.name}`, [words, `Cards start in ${zone}.`, 'Work a card starts still waits for your usual approvals.'], { flowId: flow.id, trigger: config });
504
505
  }
505
- const made = addFlowTriggerTo(store, flow, input.value, who, now, context.configDir);
506
+ // A trigger that takes deliveries mints an address: a credential act, a password typed for this command (never the
507
+ // remembered login under Passwordless) (docs/plans/passwordless.md).
508
+ const ingress = rawTakesDeliveries(input.value);
509
+ if (ingress && !proveCredential(store, acting.name, acting.token).ok)
510
+ return refuse(flow.repo, 'unauthenticated', 'Making a webhook address takes your password, typed: pass --token.');
511
+ const made = addFlowTriggerTo(store, flow, input.value, who, now, context.configDir, ingress ? { ingress: 'proved' } : {});
506
512
  if (!made.ok)
507
513
  return refuse(flow.repo, 'invalid-trigger', made.message);
508
514
  await prepareUnattendedCandidates(store, flow.id);
@@ -1,5 +1,3 @@
1
- /** Flows in the console: the list of a person's flows, and one flow's canvas
2
- * (the React view's data, plus a plain fallback page the view replaces). */
3
1
  import type { BrowserFlowView } from "./browser-workspace.js";
4
2
  import type { FlowRow, Store } from "./store.js";
5
3
  import { type FlowFile, type FlowImportPlan } from "./flow-share.js";
package/dist/flows-ui.js CHANGED
@@ -1,6 +1,12 @@
1
+ /** Flows in the console: the list of a person's flows, and one flow's canvas
2
+ * (the React view's data, plus a plain fallback page the view replaces). */
3
+ import { liveAttemptOf, steerControlsFor } from "./steer-controls.js";
1
4
  import { draftFor, flowDefinitionOf } from "./flow-engine.js";
2
5
  import { describeStandingOrder } from "./flow-schedule.js";
3
- import { describeTrigger, triggerHeadline, FLOW_TRIGGER_KINDS, FLOW_TRIGGER_WORDS, githubRepoOf, HOOK_PATH, hookReady, planeStatusLink, readHooksBase, readLinearKey, takesDeliveries, triggerConfigOf } from "./flow-triggers.js";
6
+ import { describeTrigger, triggerHeadline, FLOW_TRIGGER_KINDS, FLOW_TRIGGER_WORDS, githubRepoOf, HOOK_PATH, hookReady, planeStatusLink, readHooksBase, readLinearKey, senderOf, takesDeliveries, triggerConfigOf } from "./flow-triggers.js";
7
+ import { SENDER_WORDS } from "./webhook-signing.js";
8
+ import { READER_CAPTURED } from "./webhook-readers.js";
9
+ import { hostOf, linkWords, provedWords, snapshotOf } from "./task-source.js";
4
10
  import { deciderOf, FLOW_COLORS, FLOW_KIND_WORDS, FLOW_STAGE_KINDS } from "./flows.js";
5
11
  import { flowInsights, troubleWords } from "./flow-insights.js";
6
12
  import { parseSortDecision, sortChip } from "./flow-sort.js";
@@ -20,6 +26,40 @@ import { unattendedViewOf } from "./flow-unattended.js";
20
26
  import { readFlowSecrets } from "./flow-secrets.js";
21
27
  import { html, joinHtml, postForm } from "./html.js";
22
28
  const projectName = (repo) => repo.split(/[\\/]/).filter(Boolean).pop() ?? repo;
29
+ /** v126: what happens to deliveries turned away (refused with 503), as far as each sender is known to say: nothing
30
+ * here claims a loss that a sender's own retries may still make good. */
31
+ function resendWords(config) {
32
+ if (config.kind === "github")
33
+ return "GitHub doesn't retry on its own: resend them from the repository's Settings → Webhooks → this webhook → Recent Deliveries → Redeliver.";
34
+ if (config.kind === "linear")
35
+ return "Linear may retry a refused delivery. Look in the webhook's settings in Linear for its recent deliveries; any it doesn't resend can't be recovered here.";
36
+ const sender = config.kind === "webhook" ? senderOf(config) : "none";
37
+ return sender === "vercel" ? "Vercel retries refused deliveries for up to a day, so some may still arrive. Its webhook's delivery attempts are listed in Vercel's webhook settings; any it gives up on are lost."
38
+ : sender === "sentry" ? "Sentry may retry a refused delivery. Your Internal Integration's Dashboard in Sentry (Developer Settings) shows its request log; any it doesn't resend are lost, though new alerts for the same issues still arrive."
39
+ : "The sender may retry. Look in its webhook delivery log and resend from there if it offers it; any it doesn't resend are lost.";
40
+ }
41
+ /** v126: what a webhook trigger's row says about how its deliveries are proved. */
42
+ function hookView(trigger, config, dir) {
43
+ const ready = hookReady(trigger, dir);
44
+ const dropped = trigger.droppedCount > 0 && trigger.droppedSince !== null ? { count: trigger.droppedCount, since: trigger.droppedSince, resend: resendWords(config) } : null;
45
+ if (config.kind !== "webhook")
46
+ return { ready, needsSecret: config.kind === "linear", sender: null, makesSecret: false, warning: null, readerNote: null, dropped, scope: null };
47
+ const sender = senderOf(config);
48
+ // What it needs first, first: an unset secret refuses everything, so that is said before any narrowing.
49
+ const warning = trigger.hookHash === null && (sender === "none" || ready) ? "No address yet: choose New address to make one and give it to the sender."
50
+ : sender === "none" ? "Unsigned: anyone with its address can add cards. Choose who signs its deliveries to close that."
51
+ : !ready ? `Not set up: its deliveries are refused until ${sender === "sentry" || sender === "vercel" ? `${SENDER_WORDS[sender]}'s secret is pasted (with New address for the address to give it)` : "it is set up"}.`
52
+ : (sender === "sentry" || sender === "vercel") && config.project == null ? `Any ${SENDER_WORDS[sender]} project this secret covers can add cards. Name the project to narrow it.`
53
+ : null;
54
+ // A sender that signs only the body: byte-identical requests are one delivery (§3).
55
+ const repeats = sender === "github-style" ? "Identical requests count once. If the sender must send the same request again and have it count, use Standard Webhooks." : null;
56
+ // A reader written from its sender's documentation, not yet from a captured delivery, says so on its own line,
57
+ // whatever else the row says (webhook-readers.ts).
58
+ const readerNote = (sender === "sentry" || sender === "vercel") && !READER_CAPTURED[sender]
59
+ ? `Reader unverified: Toolroll reads ${SENDER_WORDS[sender]} deliveries from ${SENDER_WORDS[sender]}'s documented examples; no real delivery has been checked yet.` : null;
60
+ return { ready, needsSecret: sender === "sentry" || sender === "vercel", sender, makesSecret: sender === "standard" || sender === "github-style", warning, readerNote: [readerNote, repeats].filter(one => one !== null).join(" ") || null, dropped,
61
+ scope: sender === "sentry" || sender === "vercel" ? { project: config.project ?? null, team: config.team ?? null } : null };
62
+ }
23
63
  export const FLOWS_CSS = `.flows{max-width:880px;min-width:0}.flows .card{padding:16px 18px;margin:12px 0}.flows .flow-row{display:flex;justify-content:space-between;align-items:baseline;gap:12px;flex-wrap:wrap}.flows .flow-row h2{font-size:1.05rem;margin:0}.flows .flow-counts{font-size:.85rem;color:var(--so-muted)}.flows form{display:grid;gap:10px;margin:0}.flows label{display:grid;gap:6px}.flows input,.flows select{box-sizing:border-box;width:100%;max-width:100%}.flows button{justify-self:start;min-height:44px}.flows .flow-fallback ol{padding-left:20px}.flows summary{cursor:pointer;min-height:44px;display:flex;align-items:center;font-weight:600}.flows .flow-buttons{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin:10px 0 0}.flows .flow-import{margin-top:18px;padding-top:14px;border-top:1px solid var(--so-line)}.flows .flow-import h3{font-size:.95rem;margin:0}.flows .flow-terms{list-style:none;padding:0;margin:8px 0 16px;display:grid;gap:10px}.flows .flow-terms li{white-space:pre-line;overflow-wrap:anywhere}.flows .flow-terms pre{white-space:pre-wrap;overflow-wrap:anywhere;font-size:.8rem;margin:6px 0 0}.flows .flow-import-preview h2{font-size:1rem;margin:20px 0 4px}.flows .flow-untrusted{font-weight:600}.flows button.primary{background:var(--primary);color:var(--primary-foreground);border-color:var(--primary)}.flows fieldset{border:0;padding:0;margin:0;display:grid;gap:10px;min-width:0}.flows legend{font-weight:600;padding:0;margin-bottom:6px}.flows textarea[hidden]{display:none}.flows button.secondary{background:transparent;color:var(--foreground);border:1px solid var(--border)}@media(max-width:600px){.flows input,.flows select{font-size:16px}}@media(max-width:760px){.flows .card{padding:10px 12px;margin:8px 0;position:relative}.flows .flow-row{row-gap:2px}.flows .flow-row h2 a::after{content:"";position:absolute;inset:0;border-radius:inherit}.flows .flow-counts{line-height:1.35}}`;
24
64
  /** The flows a person can open, with how many cards wait in each, and the new-flow form. */
25
65
  export function flowsListHtml(store, flows, projects, canCreate, problem) {
@@ -142,14 +182,22 @@ export function flowView(store, flow, viewer, selectedCard, setup = { dir: null,
142
182
  id: card.id, title: card.title, description: card.description, stage: card.stage, state: card.state,
143
183
  waiting: card.state === "active" && card.task !== null && (stage?.kind === "task" || stage?.kind === "report")
144
184
  ? canReadTask ? flowCardTaskLine(store, card.task, taskRepo, now, secretsFor(taskRepo)) : "Task unavailable" : card.waiting,
145
- task: task === null ? null : { id: task, href: `/t/${encodeURIComponent(task)}` },
185
+ task: task === null ? null : { id: task, href: `/t/${encodeURIComponent(task)}`,
186
+ // Its running attempt's composer, for an approver who may read the task (steer-controls.ts).
187
+ ...(() => {
188
+ const ref = card.state === "active" && canReadTask && viewer.approver ? store.lookupRef(task) : null;
189
+ const run = ref === null ? null : liveAttemptOf(store, ref.id, now);
190
+ const composer = run === null ? null : steerControlsFor(store, task, run, now, viewer.approver);
191
+ return composer === null ? {} : { composer };
192
+ })() },
146
193
  createdBy: card.createdBy, updatedAt: card.updatedAt,
147
194
  canDecide,
148
195
  // What a "Send to me" sent shows once, in its own box (sent), not again here; a report zone's items and full report
149
196
  // (`<id>.items`, `<id>.report`) are for later zones, and its summary is shown.
150
197
  outputs: Object.entries(card.outputs).filter(([id]) => !id.includes(".") && stages.find(one => one.id === id)?.kind !== "send").map(([id, text]) => ({ stage: id, title: title(id), text })),
151
198
  history: [...moves, ...owned].sort((a, b) => b.at.localeCompare(a.at)).slice(0, 30),
152
- source: card.source,
199
+ // v126: an outside event's card says how it was proved and where its link goes, from what was kept at receipt.
200
+ source: card.source === null ? null : (() => { const snapshot = snapshotOf(card.source); return snapshot === null ? card.source : { ...card.source, proved: provedWords(snapshot), host: hostOf(card.source.url), shown: card.source.url === null ? null : linkWords(card.source.url) }; })(),
153
201
  owner: card.owner, watchers, watching: watchers.includes(viewer.name),
154
202
  mine: card.owner === viewer.name || watchers.includes(viewer.name) || canDecide || choosing?.person === viewer.name,
155
203
  comments: discussion.filter(one => one.kind === "comment").map(one => ({ id: one.id, author: one.author, body: one.body, mentions: one.mentions, at: one.at })),
@@ -178,7 +226,7 @@ export function flowView(store, flow, viewer, selectedCard, setup = { dir: null,
178
226
  ...(config === null ? { name: "Trigger", detail: "Can't be read" } : triggerHeadline(config, store)),
179
227
  zone: title(config?.zone ?? definition?.start ?? ""), zoneId: config?.zone ?? definition?.start ?? "", state: trigger.state, status: trigger.lastOutcome, statusLink: planeStatusLink(config, trigger.lastOutcome), statusAt: trigger.lastAt, failing: trigger.failures > 0,
180
228
  button: config?.kind === "button" ? { label: config.label, questions: config.questions } : null,
181
- hook: config !== null && takesDeliveries(config) ? { ready: hookReady(trigger, setup.dir), needsSecret: config.kind === "linear" } : null,
229
+ hook: config !== null && takesDeliveries(config) ? hookView(trigger, config, setup.dir) : null,
182
230
  checkable: ((config?.kind === "github" || config?.kind === "linear") && config.delivery === "poll") || config?.kind === "email" || (config?.kind === "schedule" && config.script !== undefined) || config?.kind === "plane-review",
183
231
  shared: config?.kind === "button" && trigger.hookHash !== null,
184
232
  ...(config?.kind === "schedule" && config.order !== undefined ? { order: describeStandingOrder(config.order, flow.repo, config.schedule) } : {}),
package/dist/flows.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type SourceLike } from "./task-source.js";
1
2
  import { type ContractIssue, type ContractResult } from "./contracts/contract.js";
2
3
  import { CHOICES_MAX, CHOICES_MIN, FLOW_COLORS, FLOW_END, FLOW_MERGE_METHODS, FLOW_STAGE_KINDS, LONGEST_WAIT_MINUTES, SCRIPT_LANGUAGES, SCRIPT_NAME, sortKeyOf, type FlowDefinition, type FlowStage, type FlowStageKind, type FlowStepFields, type FlowWait, type ScriptLanguage, type TriggerInput } from "./contracts/flow.js";
3
4
  export { CHOICES_MAX, CHOICES_MIN, FLOW_COLORS, FLOW_END, FLOW_MERGE_METHODS, FLOW_STAGE_KINDS, LONGEST_WAIT_MINUTES, SCRIPT_LANGUAGES, SCRIPT_NAME, sortKeyOf };
@@ -66,11 +67,13 @@ export declare function choiceTargets(stage: Pick<FlowStage, "options">): string
66
67
  export declare function replyTarget(stage: Pick<FlowStage, "options" | "onFail">): string | null;
67
68
  /** What a card's work is held to: the zones' steps and paths, never where they sit on the canvas. */
68
69
  export declare function flowDigest(definition: FlowDefinition): string;
70
+ /** `source` (v126): where the card came from, when an outside event's delivery made it ({{card.source}}). */
69
71
  type FlowFillCard = {
70
72
  title: string;
71
73
  description: string | null;
72
74
  note: string | null;
73
75
  outputs: Record<string, string>;
76
+ source?: SourceLike | null;
74
77
  };
75
78
  /** Fill a zone's text from the card: title, description, the latest note and earlier zones' reports. */
76
79
  export declare function fillFlowText(template: string, card: FlowFillCard, encode?: (value: string) => string): string;
@@ -83,6 +86,7 @@ export declare const flowAttachedMark: (label: string) => string;
83
86
  export declare function flowWorkTemplate(instructions: string, card: {
84
87
  description: string | null;
85
88
  note: string | null;
89
+ source?: SourceLike | null;
86
90
  }): string;
87
91
  /** How a filled-in value is named where it is attached: the same words flowGoalCuts labels it with. */
88
92
  export declare function flowValueLabel(key: string, stageTitle?: (id: string) => string): string;
package/dist/flows.js CHANGED
@@ -50,6 +50,7 @@
50
50
  import { TEXT_LIMITS } from "./text-limits.js";
51
51
  import { createHash } from "node:crypto";
52
52
  import { projectName } from "./project.js";
53
+ import { cardReference } from "./task-source.js";
53
54
  import { parseContract, readVersioned } from "./contracts/contract.js";
54
55
  import { stageReferenceProblems } from "./contracts/stage-output.js";
55
56
  import { CHOICES_MAX, CHOICES_MIN, FLOW_ALIASES, FLOW_COLORS, FLOW_DEFINITION_VERSION, FLOW_END, FLOW_MERGE_METHODS, FLOW_STAGE_KINDS, flowDefinitionSchema, flowStepsSchema, HEADERS_MAX, legacySubagentStep, LONGEST_WAIT_MINUTES, savedFlowDefinitionSchema, SCRIPT_LANGUAGES, SCRIPT_NAME, sortKeyOf, SURE_AT_MAX, SURE_AT_MIN, ZONE_ID, } from "./contracts/flow.js";
@@ -477,7 +478,7 @@ export function flowDigest(definition) {
477
478
  return createHash("sha256").update(JSON.stringify({ start: definition.start, terms })).digest("hex").slice(0, 32);
478
479
  }
479
480
  /** {{stage.<id>}} is an earlier zone's output; a report zone also fills {{stage.<id>.items}} and {{stage.<id>.report}}. */
480
- const FILLED = /\{\{\s*(card\.title|card\.description|card\.email|note|stage\.([a-z0-9-]+(?:\.(?:items|report))?))\s*\}\}/g;
481
+ const FILLED = /\{\{\s*(card\.title|card\.description|card\.email|card\.source|note|stage\.([a-z0-9-]+(?:\.(?:items|report))?))\s*\}\}/g;
481
482
  /** Fill a zone's text from the card: title, description, the latest note and earlier zones' reports. */
482
483
  export function fillFlowText(template, card, encode = value => value) {
483
484
  return template.replace(FILLED, (_match, key, stage) => encode(fillOne(key, stage, card))).trim();
@@ -494,6 +495,9 @@ export function flowWorkTemplate(instructions, card) {
494
495
  ...(names("card.title") || names("card.description") ? [] : [`The card: {{card.title}}${card.description ? "\n\n{{card.description}}" : ""}`]),
495
496
  ...(names("card.title") && !names("card.description") && card.description ? ["Details on the card:\n{{card.description}}"] : []),
496
497
  ...(names("note") || !card.note ? [] : ["Changes asked for: {{note}}"]),
498
+ // v126: an outside event's card says where it came from — a filled value like the others, so it is fitted into the
499
+ // goal with them (whole when it fits, attached when it doesn't), never at the cost of the zone's own words.
500
+ ...(names("card.source") || cardReference(card.source) === "" ? [] : ["{{card.source}}"]),
497
501
  ];
498
502
  return [instructions, ...extra].join("\n\n");
499
503
  }
@@ -507,6 +511,8 @@ export function flowValueLabel(key, stageTitle = id => id) {
507
511
  return "The card's description";
508
512
  if (key === "card.email")
509
513
  return "The card's email address";
514
+ if (key === "card.source")
515
+ return "Where the card came from";
510
516
  if (key === "note")
511
517
  return "The note it was sent back with";
512
518
  const match = /^stage\.([a-z0-9-]+)(?:\.(items|report))?$/.exec(key);
@@ -556,6 +562,8 @@ function fillOne(key, stage, card) {
556
562
  {
557
563
  if (key === "card.title")
558
564
  return card.title;
565
+ if (key === "card.source")
566
+ return cardReference(card.source);
559
567
  if (key === "card.description")
560
568
  return card.description ?? "";
561
569
  if (key === "card.email")
package/dist/html.d.ts CHANGED
@@ -55,6 +55,15 @@ export type PostFormOptions = {
55
55
  };
56
56
  /** The server's request context supplies the request's CSRF token (server/request-context.ts). */
57
57
  export declare function provideFormToken(source: () => string | undefined): void;
58
+ export declare function providePasswordless(source: () => boolean): void;
59
+ /**
60
+ * A ceremony's re-authentication field: rendered as given, or — with Passwordless on for this signed-in browser —
61
+ * nothing at all (the form posts an empty password; the act proves the session). Never used for credential acts,
62
+ * the sign-in form, a new password, or a secret or API key field.
63
+ */
64
+ export declare function reauth(field: Html): Html;
65
+ /** The same question for a page's own script that builds a re-authentication field itself. */
66
+ export declare const passwordlessRendering: () => boolean;
58
67
  /**
59
68
  * A POST form: the action, the request's one CSRF field, the optional
60
69
  * project revision and return fields, other hidden fields, then the body.
package/dist/html.js CHANGED
@@ -111,6 +111,17 @@ export function attributes(values) {
111
111
  let formToken = () => undefined;
112
112
  /** The server's request context supplies the request's CSRF token (server/request-context.ts). */
113
113
  export function provideFormToken(source) { formToken = source; }
114
+ /** Passwordless (docs/plans/passwordless.md), as the request sees it: the request context provides it. */
115
+ let passwordlessNow = () => false;
116
+ export function providePasswordless(source) { passwordlessNow = source; }
117
+ /**
118
+ * A ceremony's re-authentication field: rendered as given, or — with Passwordless on for this signed-in browser —
119
+ * nothing at all (the form posts an empty password; the act proves the session). Never used for credential acts,
120
+ * the sign-in form, a new password, or a secret or API key field.
121
+ */
122
+ export function reauth(field) { return passwordlessNow() ? html `` : field; }
123
+ /** The same question for a page's own script that builds a re-authentication field itself. */
124
+ export const passwordlessRendering = () => passwordlessNow();
114
125
  /**
115
126
  * A POST form: the action, the request's one CSRF field, the optional
116
127
  * project revision and return fields, other hidden fields, then the body.
package/dist/invoke.d.ts CHANGED
@@ -20,6 +20,7 @@ import { type AgentSpec, type Invocation, type ProviderRunner, type AgentEnding
20
20
  import { type VersionProbe } from "./attest.js";
21
21
  import type { Store } from "./store.js";
22
22
  import type { RunOptions } from "./exec.js";
23
+ import { type NetworkProfile } from "./egress.js";
23
24
  export type { ProviderRunner } from "./provider.js";
24
25
  /** The claude binary name — kept for the legacy quota rows and tests that
25
26
  * describe history; new code carries a resolved AgentSpec instead. */
@@ -53,6 +54,8 @@ export type AgentOutcome = {
53
54
  * strikes of bad agent work).
54
55
  */
55
56
  initFailed: boolean;
57
+ /** An ACP conversation's facts (provider.ts ParsedEnvelope.acp): read by the conformance check only. */
58
+ acp?: NonNullable<import("./provider.js").ParsedEnvelope["acp"]>;
56
59
  };
57
60
  /**
58
61
  * The value-shaped gateway result (Phase 3 B5): a refusal is a VALUE, so
@@ -78,6 +81,8 @@ export type InvokeResult = {
78
81
  /** Bounded agent reply when a spawned turn later failed a protocol
79
82
  * gate. Pre-spawn refusals omit it because no reply can exist. */
80
83
  finalMessage?: string | null;
84
+ /** An ACP conversation's facts, when the refusal came after a spawn (the conformance check grades a cancel). */
85
+ acp?: NonNullable<import("./provider.js").ParsedEnvelope["acp"]>;
81
86
  };
82
87
  /**
83
88
  * Spend money, on the record. Throws — never refuses quietly — when the run
@@ -86,10 +91,22 @@ export type InvokeResult = {
86
91
  * bug, not a case. Attestation and protocol refusals are VALUES (above),
87
92
  * not throws — those are cases, and they must dispose cleanly.
88
93
  */
94
+ /**
95
+ * What a launch may reach on the network (egress.ts, docs/plans/agent-baseline-hardening.md arc 1). `policy`: the
96
+ * network a build's approval sealed (or the narrowed legacy one), enforced through the run's own proxy. `via`: the
97
+ * caller already runs the proxy (a scout's public-web proxy, its browser): only those loopback ports are reachable.
98
+ * Absent: the provider's own hosts only (a planner, a check — nothing that installs or browses).
99
+ */
100
+ export type LaunchNetwork = {
101
+ policy: NetworkProfile;
102
+ } | {
103
+ via: number[];
104
+ };
89
105
  export declare function invokeAgent(store: Store, runId: number, spec: AgentSpec, invocation: Omit<Invocation, "model">, options: RunOptions & {
90
106
  runner?: ProviderRunner;
91
107
  clock?: () => Date;
92
108
  versionProbe?: VersionProbe;
93
109
  keyHome?: string;
94
110
  accumulateUsage?: boolean;
111
+ network?: LaunchNetwork;
95
112
  }): Promise<InvokeResult>;