toolroll 0.9.63 → 0.9.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +108 -0
- package/README.md +33 -5
- package/dist/acp-agents.d.ts +43 -0
- package/dist/acp-agents.js +62 -0
- package/dist/acp-attest.d.ts +44 -0
- package/dist/acp-attest.js +269 -0
- package/dist/acp-check.d.ts +28 -0
- package/dist/acp-check.js +410 -0
- package/dist/acp-client.d.ts +163 -0
- package/dist/acp-client.js +738 -0
- package/dist/acp-inspect.d.ts +23 -0
- package/dist/acp-inspect.js +109 -0
- package/dist/agent-board.d.ts +19 -6
- package/dist/agent-board.js +30 -9
- package/dist/agent-fence.d.ts +117 -2
- package/dist/agent-fence.js +439 -12
- package/dist/agent-pulse.js +9 -2
- package/dist/agent-state-words.d.ts +19 -0
- package/dist/agent-state-words.js +20 -0
- package/dist/agent-state.d.ts +65 -0
- package/dist/agent-state.js +229 -0
- package/dist/agentconfig.js +39 -13
- package/dist/agents-board.d.ts +34 -2
- package/dist/agents-board.js +110 -1
- package/dist/approval-rules-ui.js +2 -2
- package/dist/assignment-delivery.d.ts +14 -0
- package/dist/assignment-delivery.js +13 -0
- package/dist/assignment.js +13 -0
- package/dist/attest.js +7 -0
- package/dist/backup-ui.js +2 -2
- package/dist/batch-checks.js +3 -2
- package/dist/browser/THIRD_PARTY_NOTICES.txt +94 -0
- package/dist/browser/terminal.css +37 -0
- package/dist/browser/terminal.js +228 -0
- package/dist/browser/workspace.css +2 -2
- package/dist/browser/workspace.js +42 -38
- package/dist/browser-shell.js +6 -3
- package/dist/browser-workspace.d.ts +235 -1
- package/dist/browser-workspace.js +60 -0
- package/dist/builder.d.ts +10 -1
- package/dist/builder.js +87 -24
- package/dist/chat-actions.d.ts +13 -1
- package/dist/chat-actions.js +197 -15
- package/dist/chat-ask.d.ts +4 -0
- package/dist/chat-ask.js +14 -0
- package/dist/chat-channel.js +20 -0
- package/dist/chat-continuity.js +5 -4
- package/dist/chat-decide.d.ts +0 -14
- package/dist/chat-decide.js +4 -1
- package/dist/chat-delivery.d.ts +9 -0
- package/dist/chat-delivery.js +45 -6
- package/dist/chat-messages.d.ts +8 -0
- package/dist/chat-messages.js +36 -4
- package/dist/check-levels-ui.js +2 -2
- package/dist/checkout-proof.d.ts +28 -0
- package/dist/checkout-proof.js +62 -0
- package/dist/claim.d.ts +12 -0
- package/dist/claim.js +19 -0
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +4 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +21 -2
- package/dist/coding-ui.js +6 -4
- package/dist/console-instance.d.ts +124 -0
- package/dist/console-instance.js +337 -0
- package/dist/contracts/chat-actions.d.ts +16 -0
- package/dist/contracts/chat-actions.js +4 -0
- package/dist/contracts/chat-content.d.ts +19 -0
- package/dist/contracts/chat-content.js +6 -0
- package/dist/contracts/console-api.d.ts +13 -4
- package/dist/contracts/console-api.js +13 -4
- package/dist/contracts/flow-card.d.ts +4 -0
- package/dist/contracts/flow-card.js +3 -0
- package/dist/contracts/flow.d.ts +46 -0
- package/dist/contracts/flow.js +11 -2
- package/dist/contracts/lead-tools.d.ts +92 -0
- package/dist/contracts/lead-tools.js +13 -0
- package/dist/contracts/provider.d.ts +11 -1
- package/dist/contracts/provider.js +1 -1
- package/dist/contracts/route.d.ts +76 -1
- package/dist/contracts/route.js +1 -1
- package/dist/contracts/store-json.d.ts +2 -0
- package/dist/control-setup.d.ts +1 -1
- package/dist/control-ui.js +2 -2
- package/dist/converse.d.ts +16 -0
- package/dist/converse.js +32 -4
- package/dist/demo-chat.js +4 -4
- package/dist/demo.js +2 -2
- package/dist/desktop-update-gate.js +6 -0
- package/dist/desktop-update.d.ts +1 -1
- package/dist/discord-chat.js +4 -1
- package/dist/doctor.js +1 -1
- package/dist/egress-bridge.d.ts +17 -0
- package/dist/egress-bridge.js +111 -0
- package/dist/egress.d.ts +119 -0
- package/dist/egress.js +423 -0
- package/dist/exec.d.ts +78 -0
- package/dist/exec.js +367 -9
- package/dist/export-ui.js +2 -2
- package/dist/flow-engine.js +24 -5
- package/dist/flow-gallery-ui.js +2 -2
- package/dist/flow-gallery.js +27 -8
- package/dist/flow-share.js +16 -5
- package/dist/flow-triggers.d.ts +77 -8
- package/dist/flow-triggers.js +517 -70
- package/dist/flows-cli.js +8 -2
- package/dist/flows-ui.d.ts +0 -2
- package/dist/flows-ui.js +52 -4
- package/dist/flows.d.ts +4 -0
- package/dist/flows.js +9 -1
- package/dist/html.d.ts +9 -0
- package/dist/html.js +11 -0
- package/dist/invoke.d.ts +35 -0
- package/dist/invoke.js +347 -28
- package/dist/keys.d.ts +18 -14
- package/dist/keys.js +5 -0
- package/dist/lead-capabilities.js +3 -2
- package/dist/lead-contract.js +2 -0
- package/dist/lead-doors.d.ts +2 -0
- package/dist/lead-doors.js +7 -0
- package/dist/lead-follow.d.ts +2 -0
- package/dist/lead-follow.js +58 -2
- package/dist/lead-progress.js +1 -0
- package/dist/lead-queue-runtime.d.ts +46 -0
- package/dist/lead-queue-runtime.js +191 -0
- package/dist/lead-queue.d.ts +104 -0
- package/dist/lead-queue.js +187 -0
- package/dist/lead-sweep.d.ts +67 -0
- package/dist/lead-sweep.js +99 -0
- package/dist/lead-tools.d.ts +22 -0
- package/dist/lead-tools.js +152 -1
- package/dist/lead.d.ts +13 -5
- package/dist/lead.js +89 -29
- package/dist/limits-ui.d.ts +8 -1
- package/dist/limits-ui.js +26 -0
- package/dist/live-bus.d.ts +8 -0
- package/dist/live-bus.js +40 -4
- package/dist/live-detail.d.ts +27 -0
- package/dist/live-detail.js +57 -0
- package/dist/live-notes.d.ts +20 -0
- package/dist/live-notes.js +47 -0
- package/dist/live-records.d.ts +140 -0
- package/dist/live-records.js +935 -0
- package/dist/live-terminal.d.ts +269 -0
- package/dist/live-terminal.js +686 -0
- package/dist/live.d.ts +38 -27
- package/dist/live.js +142 -124
- package/dist/mcp-oauth.d.ts +6 -3
- package/dist/mcp-oauth.js +8 -4
- package/dist/memory-pass.js +2 -2
- package/dist/mobile-viewport.d.ts +5 -1
- package/dist/mobile-viewport.js +18 -2
- package/dist/model-catalog.js +4 -0
- package/dist/monitoring-ui.js +2 -2
- package/dist/needs-you.d.ts +1 -1
- package/dist/needs-you.js +11 -4
- package/dist/operate.d.ts +4 -0
- package/dist/operate.js +335 -19
- package/dist/passwordless.d.ts +23 -0
- package/dist/passwordless.js +26 -0
- package/dist/peek-cli.d.ts +12 -4
- package/dist/peek-cli.js +19 -11
- package/dist/phase-routing.js +10 -3
- package/dist/planner-source.d.ts +3 -0
- package/dist/planner-source.js +14 -0
- package/dist/planner.d.ts +2 -1
- package/dist/planner.js +7 -1
- package/dist/policy-ui.js +2 -2
- package/dist/policy.d.ts +1 -20
- package/dist/policy.js +29 -2
- package/dist/project-delete-ui.d.ts +18 -0
- package/dist/project-delete-ui.js +60 -9
- package/dist/project-delete.js +2 -2
- package/dist/project-memory.d.ts +3 -1
- package/dist/project-memory.js +57 -25
- package/dist/project-tools.d.ts +5 -3
- package/dist/project-tools.js +12 -9
- package/dist/provider-auth.d.ts +4 -3
- package/dist/provider-auth.js +5 -4
- package/dist/provider-connection.d.ts +2 -1
- package/dist/provider-connection.js +5 -0
- package/dist/provider.d.ts +25 -2
- package/dist/provider.js +63 -9
- package/dist/pull-request-ui.js +2 -2
- package/dist/push.js +1 -1
- package/dist/quick-start.d.ts +24 -0
- package/dist/quick-start.js +127 -0
- package/dist/release-adapters.d.ts +6 -0
- package/dist/release-adapters.js +70 -3
- package/dist/release.d.ts +10 -1
- package/dist/release.js +34 -15
- package/dist/request-budget-ui.js +2 -2
- package/dist/result-follow-ups.js +3 -2
- package/dist/result-review.d.ts +1 -1
- package/dist/result-review.js +9 -3
- package/dist/retention-ui.js +2 -2
- package/dist/retention.js +10 -1
- package/dist/run-efficiency.d.ts +73 -0
- package/dist/run-efficiency.js +228 -0
- package/dist/runner.d.ts +5 -1
- package/dist/runner.js +22 -1
- package/dist/scope.d.ts +183 -5
- package/dist/scope.js +256 -31
- package/dist/scout-net.d.ts +4 -1
- package/dist/scout-net.js +37 -12
- package/dist/scout.d.ts +20 -6
- package/dist/scout.js +27 -3
- package/dist/serve.js +248 -40
- package/dist/server/chat.d.ts +1 -1
- package/dist/server/chat.js +122 -31
- package/dist/server/chrome.d.ts +16 -2
- package/dist/server/chrome.js +63 -11
- package/dist/server/console.css +107 -42
- package/dist/server/flows.js +38 -8
- package/dist/server/guards.d.ts +1 -0
- package/dist/server/guards.js +23 -9
- package/dist/server/http.d.ts +7 -0
- package/dist/server/http.js +3 -2
- package/dist/server/live.d.ts +34 -1
- package/dist/server/live.js +39 -17
- package/dist/server/pages-assets.js +5 -0
- package/dist/server/pages.js +90 -13
- package/dist/server/people-tokens.d.ts +3 -0
- package/dist/server/people-tokens.js +55 -17
- package/dist/server/remote-hooks.js +12 -6
- package/dist/server/remote.d.ts +2 -1
- package/dist/server/remote.js +14 -5
- package/dist/server/render-chat.d.ts +12 -3
- package/dist/server/render-chat.js +47 -16
- package/dist/server/render-pages.d.ts +32 -4
- package/dist/server/render-pages.js +83 -13
- package/dist/server/render-people.d.ts +3 -2
- package/dist/server/render-people.js +3 -2
- package/dist/server/render-results.d.ts +18 -2
- package/dist/server/render-results.js +37 -28
- package/dist/server/render-settings.js +6 -5
- package/dist/server/render-tasks.d.ts +35 -10
- package/dist/server/render-tasks.js +111 -27
- package/dist/server/request-context.d.ts +2 -0
- package/dist/server/request-context.js +2 -1
- package/dist/server/route-table.d.ts +3 -0
- package/dist/server/route-table.js +47 -5
- package/dist/server/runtime.d.ts +33 -2
- package/dist/server/session.d.ts +25 -1
- package/dist/server/session.js +18 -4
- package/dist/server/settings.js +142 -10
- package/dist/server/sweeps.d.ts +4 -0
- package/dist/server/sweeps.js +58 -0
- package/dist/server/task-views.d.ts +2 -1
- package/dist/server/task-views.js +96 -6
- package/dist/server/tasks.js +327 -78
- package/dist/server/terminals.d.ts +31 -0
- package/dist/server/terminals.js +365 -0
- package/dist/setup-guide.js +3 -2
- package/dist/slack-chat.js +4 -1
- package/dist/spend-ui.js +3 -3
- package/dist/spend.js +2 -1
- package/dist/steer-capabilities.d.ts +32 -0
- package/dist/steer-capabilities.js +60 -0
- package/dist/steer-controls.d.ts +14 -0
- package/dist/steer-controls.js +36 -0
- package/dist/steer-status.js +2 -2
- package/dist/storage-ui.js +4 -4
- package/dist/store-baseline.d.ts +1 -1
- package/dist/store-baseline.js +1 -1
- package/dist/store.d.ts +440 -15
- package/dist/store.js +1072 -52
- package/dist/subagent-desk.js +1 -1
- package/dist/summary.js +3 -0
- package/dist/task-source.d.ts +58 -0
- package/dist/task-source.js +93 -0
- package/dist/team-leads.js +1 -1
- package/dist/teams-chat.js +4 -1
- package/dist/teardown-git.d.ts +22 -0
- package/dist/teardown-git.js +136 -2
- package/dist/telegram-lead.d.ts +3 -0
- package/dist/telegram-lead.js +44 -7
- package/dist/telegram.d.ts +11 -2
- package/dist/telegram.js +51 -17
- package/dist/terminal-catalog.d.ts +11 -0
- package/dist/terminal-catalog.js +129 -0
- package/dist/text-limits.d.ts +2 -0
- package/dist/text-limits.js +2 -0
- package/dist/tool-broker.d.ts +14 -0
- package/dist/tool-broker.js +67 -2
- package/dist/toolroll-update-ui.js +2 -2
- package/dist/toolroll-update.js +13 -3
- package/dist/tools-ui.js +2 -2
- package/dist/unfenced-test-support.d.ts +2 -0
- package/dist/unfenced-test-support.js +11 -0
- package/dist/webhook-limits.d.ts +23 -0
- package/dist/webhook-limits.js +30 -0
- package/dist/webhook-readers.d.ts +56 -0
- package/dist/webhook-readers.js +138 -0
- package/dist/webhook-signing.d.ts +27 -0
- package/dist/webhook-signing.js +119 -0
- package/dist/work-index.d.ts +29 -0
- package/dist/work-index.js +16 -2
- package/dist/workspace-revision.js +3 -1
- package/dist/writes-mode.d.ts +9 -0
- package/dist/writes-mode.js +8 -0
- package/package.json +15 -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
|
-
|
|
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);
|
package/dist/flows-ui.d.ts
CHANGED
|
@@ -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
|
-
|
|
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) ?
|
|
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,9 @@ 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 { Runner } from "./worktree.js";
|
|
24
|
+
import { type WritesMode } from "./agent-fence.js";
|
|
25
|
+
import { type NetworkProfile } from "./egress.js";
|
|
23
26
|
export type { ProviderRunner } from "./provider.js";
|
|
24
27
|
/** The claude binary name — kept for the legacy quota rows and tests that
|
|
25
28
|
* describe history; new code carries a resolved AgentSpec instead. */
|
|
@@ -53,6 +56,8 @@ export type AgentOutcome = {
|
|
|
53
56
|
* strikes of bad agent work).
|
|
54
57
|
*/
|
|
55
58
|
initFailed: boolean;
|
|
59
|
+
/** An ACP conversation's facts (provider.ts ParsedEnvelope.acp): read by the conformance check only. */
|
|
60
|
+
acp?: NonNullable<import("./provider.js").ParsedEnvelope["acp"]>;
|
|
56
61
|
};
|
|
57
62
|
/**
|
|
58
63
|
* The value-shaped gateway result (Phase 3 B5): a refusal is a VALUE, so
|
|
@@ -78,6 +83,8 @@ export type InvokeResult = {
|
|
|
78
83
|
/** Bounded agent reply when a spawned turn later failed a protocol
|
|
79
84
|
* gate. Pre-spawn refusals omit it because no reply can exist. */
|
|
80
85
|
finalMessage?: string | null;
|
|
86
|
+
/** An ACP conversation's facts, when the refusal came after a spawn (the conformance check grades a cancel). */
|
|
87
|
+
acp?: NonNullable<import("./provider.js").ParsedEnvelope["acp"]>;
|
|
81
88
|
};
|
|
82
89
|
/**
|
|
83
90
|
* Spend money, on the record. Throws — never refuses quietly — when the run
|
|
@@ -86,10 +93,38 @@ export type InvokeResult = {
|
|
|
86
93
|
* bug, not a case. Attestation and protocol refusals are VALUES (above),
|
|
87
94
|
* not throws — those are cases, and they must dispose cleanly.
|
|
88
95
|
*/
|
|
96
|
+
/**
|
|
97
|
+
* What a launch may reach on the network (egress.ts, docs/plans/agent-baseline-hardening.md arc 1). `policy`: the
|
|
98
|
+
* network a build's approval sealed (or the narrowed legacy one), enforced through the run's own proxy. `via`: the
|
|
99
|
+
* caller already runs the proxy (a scout's public-web proxy, its browser): only those loopback ports are reachable.
|
|
100
|
+
* Absent: the provider's own hosts only (a planner, a check — nothing that installs or browses).
|
|
101
|
+
*/
|
|
102
|
+
export type LaunchNetwork = {
|
|
103
|
+
policy: NetworkProfile;
|
|
104
|
+
} | {
|
|
105
|
+
via: number[];
|
|
106
|
+
};
|
|
89
107
|
export declare function invokeAgent(store: Store, runId: number, spec: AgentSpec, invocation: Omit<Invocation, "model">, options: RunOptions & {
|
|
90
108
|
runner?: ProviderRunner;
|
|
91
109
|
clock?: () => Date;
|
|
92
110
|
versionProbe?: VersionProbe;
|
|
93
111
|
keyHome?: string;
|
|
94
112
|
accumulateUsage?: boolean;
|
|
113
|
+
network?: LaunchNetwork;
|
|
114
|
+
writes?: WritesMode;
|
|
95
115
|
}): Promise<InvokeResult>;
|
|
116
|
+
/**
|
|
117
|
+
* A build's setup and check commands, run in its fence (arc 2): the same denies as its agent's (Toolroll's state,
|
|
118
|
+
* credentials, other projects and runs), its write allowlist when its approval sealed one (its checkout and Git data,
|
|
119
|
+
* its project's caches, and a temp folder of the command's own), and its package managers pointed at those caches.
|
|
120
|
+
* Their network stays as it was. A machine without an OS fence runs them as before; a fence that can't be prepared
|
|
121
|
+
* (a checkout whose binding no longer proves) runs nothing.
|
|
122
|
+
*/
|
|
123
|
+
export declare function fencedCommands(store: Store, runId: number, writes: WritesMode, inner: Runner, available?: () => boolean): Runner;
|
|
124
|
+
/**
|
|
125
|
+
* A project's checks run in a checkout of a result's commit made for them (result-follow-ups.ts, batch-checks.ts), in
|
|
126
|
+
* the same fence as a build's commands: Toolroll's state, credentials, other projects and runs denied; under the
|
|
127
|
+
* project's writes setting, only that checkout, its Git data, its own temp folder, the project's caches and its check
|
|
128
|
+
* database writable. Where nothing can confine them, they run only when an instance operator allowed unconfined agents.
|
|
129
|
+
*/
|
|
130
|
+
export declare function fencedCheckoutCommands(store: Store, repo: string, checkout: string, inner: Runner, available?: () => boolean): Runner;
|