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/server/console.css
CHANGED
|
@@ -182,7 +182,7 @@
|
|
|
182
182
|
the act that resolves the screen. Cards, frames, and seals are neutral. */
|
|
183
183
|
.badge-open, .badge-parked { color: var(--foreground); }
|
|
184
184
|
.count {
|
|
185
|
-
min-width: 1.25rem; padding-inline: .35rem; border-radius:
|
|
185
|
+
min-width: 1.25rem; padding-inline: .35rem; border-radius: var(--so-radius-full);
|
|
186
186
|
}
|
|
187
187
|
.count.badge-open {
|
|
188
188
|
background: var(--brand-soft); color: var(--brand);
|
|
@@ -627,7 +627,7 @@
|
|
|
627
627
|
.requirement-heading .badge { margin: 0; white-space: normal; }
|
|
628
628
|
.requirement-statement { margin: .5rem 0; line-height: 1.55; white-space: pre-wrap; }
|
|
629
629
|
.requirement-review { margin: .4rem 0; font-size: .78rem; color: var(--muted-foreground); }
|
|
630
|
-
.requirement-warning { margin: .65rem 0; padding: .6rem .75rem; border: 1px solid color-mix(in srgb, var(--warning) 35%, var(--border)); border-radius:
|
|
630
|
+
.requirement-warning { margin: .65rem 0; padding: .6rem .75rem; border: 1px solid color-mix(in srgb, var(--warning) 35%, var(--border)); border-radius: var(--so-radius-md); background: var(--warning-soft); font-size: .8125rem; }
|
|
631
631
|
.requirement-warning strong { font-size: .78rem; }
|
|
632
632
|
.requirement-warning p { margin: .3rem 0 0; }
|
|
633
633
|
.requirement-issues { font-size: .8125rem; }
|
|
@@ -663,7 +663,7 @@
|
|
|
663
663
|
|
|
664
664
|
.filters { font-size: 0.8125rem; color: var(--muted-foreground); }
|
|
665
665
|
.filters a, .filters strong {
|
|
666
|
-
display: inline-block; padding: .25rem .625rem; border-radius:
|
|
666
|
+
display: inline-block; padding: .25rem .625rem; border-radius: var(--so-radius-full); text-decoration: none;
|
|
667
667
|
color: var(--muted-foreground); font-weight: 500;
|
|
668
668
|
}
|
|
669
669
|
.filters strong { background: var(--muted); color: var(--foreground); }
|
|
@@ -884,13 +884,18 @@
|
|
|
884
884
|
}
|
|
885
885
|
.banner .badge { margin-right: .5rem; }
|
|
886
886
|
/* Chat in `toolroll demo`: the scripted lead's conversation. */
|
|
887
|
-
.demo-chat { display: flex; flex-direction: column; gap: 1rem; max-width: 46rem; margin: 0 auto;
|
|
887
|
+
.demo-chat { display: flex; flex-direction: column; gap: 1rem; max-width: 46rem; min-height: 100%; margin: 0 auto; }
|
|
888
|
+
.demo-thread { flex: 1 0 auto; }
|
|
889
|
+
/* Empty: the greeting, the suggestions and the composer sit together in the middle, as in any modern chat. */
|
|
890
|
+
.demo-chat--empty { justify-content: center; min-height: min(70vh, 40rem); }
|
|
891
|
+
.demo-chat--empty .demo-thread { flex: 0 0 auto; }
|
|
888
892
|
.demo-thread { display: flex; flex-direction: column; gap: 1.25rem; }
|
|
889
893
|
.demo-turn { display: flex; flex-direction: column; gap: .75rem; scroll-margin-top: 1rem; }
|
|
890
894
|
.demo-said p { margin: 0; }
|
|
891
|
-
.demo-you { align-self: flex-end; max-width: min(34rem, 85%); background: var(--so-
|
|
895
|
+
.demo-you { align-self: flex-end; max-width: min(34rem, 85%); background: var(--so-soft); color: var(--so-ink); border: 1px solid var(--so-line); border-radius: 1rem 1rem .3rem 1rem; padding: .5rem .85rem; overflow-wrap: anywhere; }
|
|
892
896
|
.demo-lead { max-width: 40rem; }
|
|
893
|
-
.demo-who { font-size: .
|
|
897
|
+
.demo-who { display: flex; align-items: center; gap: .45rem; font-size: .8125rem; font-weight: 600; color: var(--so-ink); margin-bottom: .3rem !important; }
|
|
898
|
+
.demo-avatar { display: inline-grid; place-items: center; width: 1.25rem; height: 1.25rem; border-radius: 50%; background: var(--so-ink); color: var(--so-paper); font-size: .6875rem; font-weight: 700; }
|
|
894
899
|
.demo-chat .card { margin: 0; padding: 1rem 1.125rem; }
|
|
895
900
|
.demo-chat .card h2 { font-size: .9375rem; margin: .1rem 0 .4rem; }
|
|
896
901
|
.demo-chat .card h3 { font-size: .75rem; font-weight: 600; color: var(--so-muted); margin: .75rem 0 .25rem; }
|
|
@@ -938,13 +943,22 @@
|
|
|
938
943
|
.demo-evidence figure { margin: 0 0 .5rem; }
|
|
939
944
|
.demo-evidence img { display: block; width: 100%; height: auto; border: 1px solid var(--so-line); border-radius: .5rem; }
|
|
940
945
|
.demo-evidence figcaption { margin-top: .35rem; }
|
|
941
|
-
.demo-hint { padding:
|
|
942
|
-
.demo-hint-title { font-size: .
|
|
943
|
-
.demo-
|
|
944
|
-
.demo-suggestions
|
|
945
|
-
.demo-
|
|
946
|
-
.demo-chat .demo-
|
|
947
|
-
|
|
946
|
+
.demo-hint { text-align: center; padding: 0 0 .5rem; }
|
|
947
|
+
.demo-hint-title { font-size: 1.375rem; font-weight: 600; letter-spacing: -.01em; margin: 0 0 .35rem; }
|
|
948
|
+
.demo-hint-sub { color: var(--so-muted); font-size: .875rem; margin: 0 0 1rem; }
|
|
949
|
+
.demo-suggestions { display: flex; flex-wrap: wrap; justify-content: center; gap: .5rem; margin: 0; padding: 0; border: 0; background: none; }
|
|
950
|
+
.demo-chat .demo-suggestions button { min-height: 2.25rem; border-radius: 999px; padding: .3rem .9rem; border: 1px solid var(--so-line); background: var(--so-paper); color: var(--so-muted); font-weight: 500; box-shadow: none; }
|
|
951
|
+
@media (hover: hover) and (pointer: fine) { .demo-chat .demo-suggestions button:hover { color: var(--so-ink); border-color: var(--so-input-line); background: var(--so-soft); } }
|
|
952
|
+
/* The composer: one card docked at the bottom, a borderless box that grows, the hint and a round send inside. */
|
|
953
|
+
.demo-composer { position: sticky; bottom: 0; margin: 0; padding: .75rem 0 1rem; border: 0; border-radius: 0; box-shadow: none; background: linear-gradient(to bottom, transparent, var(--so-paper) 1.25rem); }
|
|
954
|
+
.demo-composer-card { display: flex; flex-direction: column; gap: .35rem; padding: .7rem .7rem .55rem .9rem; border: 1px solid var(--so-input-line); border-radius: 1rem; background: var(--so-paper); box-shadow: 0 1px 2px rgba(0,0,0,.04), 0 4px 16px rgba(0,0,0,.04); transition: border-color .12s var(--so-ease-out), box-shadow .12s var(--so-ease-out); }
|
|
955
|
+
.demo-composer-card:focus-within { border-color: var(--so-muted); box-shadow: 0 0 0 3px var(--so-soft); }
|
|
956
|
+
.demo-chat .demo-composer textarea { width: 100%; min-height: 1.6rem; max-height: 12rem; field-sizing: content; padding: .15rem 0; border: 0; border-radius: 0; background: none; box-shadow: none; resize: none; font-size: .9375rem; line-height: 1.55; }
|
|
957
|
+
.demo-chat .demo-composer textarea:focus-visible { outline: 0; }
|
|
958
|
+
.demo-composer-bar { display: flex; align-items: center; justify-content: space-between; gap: .75rem; }
|
|
959
|
+
.demo-composer-bar > span { color: var(--so-muted); font-size: .75rem; }
|
|
960
|
+
.demo-chat .demo-composer .demo-send { display: inline-grid; place-items: center; flex: none; width: 2rem; min-height: 2rem; height: 2rem; padding: 0; border-radius: 50%; }
|
|
961
|
+
.demo-composer-card:has(textarea:placeholder-shown) .demo-send { opacity: .35; }
|
|
948
962
|
.banner a { color: var(--muted-foreground); }
|
|
949
963
|
.sign-in-banner form { display: inline; margin: 0 0 0 .5rem; padding: 0; border: 0; background: transparent; }
|
|
950
964
|
|
|
@@ -1190,26 +1204,26 @@
|
|
|
1190
1204
|
rows, who builds in one line, one Approve & start beside the password,
|
|
1191
1205
|
and every other signed term in one Details fold at the end. Sentence
|
|
1192
1206
|
case, Geist, 12px and up; prose capped at 75ch. */
|
|
1193
|
-
.approval-sheet { display: grid; gap:
|
|
1207
|
+
.approval-sheet { display: grid; gap: var(--so-space-lg); margin: 0; padding: var(--so-space-xl); border: 1px solid var(--border); border-radius: var(--so-radius-card); background: var(--card); }
|
|
1194
1208
|
.approval-sheet.approve-form > :not(input) { margin: 0; }
|
|
1195
1209
|
.approval-sheet-title { margin: 0; font-size: 15px; font-weight: 600; line-height: 1.4; letter-spacing: -.01em; }
|
|
1196
1210
|
.approval-revision, .approval-note { max-width: 75ch; font-size: 14px; line-height: 1.6; overflow-wrap: anywhere; }
|
|
1197
1211
|
.approval-note { color: var(--muted-foreground); }
|
|
1198
1212
|
.approval-rows { display: grid; gap: 14px; margin: 0; }
|
|
1199
|
-
.approval-row { display: grid; grid-template-columns: 7.5rem minmax(0, 1fr); gap:
|
|
1213
|
+
.approval-row { display: grid; grid-template-columns: 7.5rem minmax(0, 1fr); gap: var(--so-space-lg); }
|
|
1200
1214
|
.approval-row dt { margin: 0; color: var(--muted-foreground); font-size: 13px; font-weight: 500; line-height: 1.6; }
|
|
1201
1215
|
.approval-row dd { min-width: 0; max-width: 75ch; margin: 0; font-size: 14px; line-height: 1.6; overflow-wrap: anywhere; }
|
|
1202
1216
|
.approval-row dd p, .approval-sheet .approval-goal { margin: 0; font-size: 14px; line-height: 1.6; }
|
|
1203
|
-
.approval-row dd :is(ol, ul) { display: grid; gap:
|
|
1217
|
+
.approval-row dd :is(ol, ul) { display: grid; gap: var(--so-space-xs); margin: 0; padding-left: 1.25rem; }
|
|
1204
1218
|
.approval-row dd ol + p { margin-top: 6px; }
|
|
1205
1219
|
.approval-row dd .approval-paths { margin-top: 2px; padding-left: 0; }
|
|
1206
1220
|
.approval-row dd .approval-paths li { font-size: 13px; }
|
|
1207
|
-
.approval-amendment { max-width: 75ch; padding:
|
|
1221
|
+
.approval-amendment { max-width: 75ch; padding: var(--so-space-md) 14px; border-radius: var(--so-radius-md); background: var(--muted); font-size: 14px; line-height: 1.55; overflow-wrap: anywhere; }
|
|
1208
1222
|
.approval-amendment p { margin: 0; }
|
|
1209
|
-
.approval-amendment ul { display: grid; gap:
|
|
1223
|
+
.approval-amendment ul { display: grid; gap: var(--so-space-xs); margin: 6px 0; padding-left: 1.25rem; }
|
|
1210
1224
|
.agents-size { margin: 0; font-size: 13px; line-height: 1.5; }
|
|
1211
1225
|
.approval-who { max-width: 75ch; color: var(--muted-foreground); font-size: 13px; line-height: 1.5; }
|
|
1212
|
-
.approval-act { display: grid; grid-template-columns: minmax(0, 20rem) auto; justify-content: start; align-items: center; gap:
|
|
1226
|
+
.approval-act { display: grid; grid-template-columns: minmax(0, 20rem) auto; justify-content: start; align-items: center; gap: var(--so-space-sm); }
|
|
1213
1227
|
.approval-password { margin: 0; }
|
|
1214
1228
|
.approval-act input[type=password] { margin: 0; font-family: var(--font-sans); }
|
|
1215
1229
|
.approval-act button { margin: 0; min-height: 2.125rem; white-space: nowrap; }
|
|
@@ -1218,7 +1232,7 @@
|
|
|
1218
1232
|
.approval-sheet .approval-allowing + .approval-you-check { margin-top: -10px; }
|
|
1219
1233
|
.approval-act > button { grid-column: 2; grid-row: 1; }
|
|
1220
1234
|
.approval-password-note { grid-column: 1; grid-row: 2; margin: 0; color: var(--muted-foreground); font-size: 13px; line-height: 1.5; }
|
|
1221
|
-
.approval-secondary { display: flex; flex-wrap: wrap; align-items: center; gap:
|
|
1235
|
+
.approval-secondary { display: flex; flex-wrap: wrap; align-items: center; gap: var(--so-space-sm); }
|
|
1222
1236
|
details.approval-edit, details.approval-edit[open] { margin: 0; padding: 0; border: 0; border-radius: 0; background: none; }
|
|
1223
1237
|
/* Edit plan, in place: the rows become fields where they stood; the
|
|
1224
1238
|
approval act and Details step aside until it is saved or cancelled. */
|
|
@@ -1233,32 +1247,32 @@
|
|
|
1233
1247
|
.approval-secondary:has(> .approval-edit[open]) > a { display: none; }
|
|
1234
1248
|
.approval-editor { display: grid; gap: 14px; }
|
|
1235
1249
|
.approval-editor .problem { margin: 0; }
|
|
1236
|
-
.approval-field { display: grid; gap:
|
|
1250
|
+
.approval-field { display: grid; gap: var(--so-space-xs); min-width: 0; margin: 0; padding: 0; border: 0; }
|
|
1237
1251
|
.approval-field-label { padding: 0; color: var(--muted-foreground); font-size: 13px; font-weight: 500; line-height: 1.6; }
|
|
1238
1252
|
.approval-field-hint { color: var(--muted-foreground); font-size: 12px; line-height: 1.5; }
|
|
1239
1253
|
.approval-field textarea, .approval-field input[type=text] { width: 100%; max-width: 75ch; margin: 0; font-family: var(--font-sans); font-size: 14px; line-height: 1.55; }
|
|
1240
1254
|
.approval-requirements { display: grid; gap: 6px; margin: 2px 0 0; padding: 0; list-style: none; }
|
|
1241
|
-
.approval-edit-act { display: flex; flex-wrap: wrap; align-items: center; gap:
|
|
1255
|
+
.approval-edit-act { display: flex; flex-wrap: wrap; align-items: center; gap: var(--so-space-sm); }
|
|
1242
1256
|
.approval-edit-act button { margin: 0; min-height: 2.125rem; white-space: nowrap; }
|
|
1243
|
-
.approval-link { display: inline-flex; align-items: center; min-height: 32px; padding: 0
|
|
1257
|
+
.approval-link { display: inline-flex; align-items: center; min-height: 32px; padding: 0 var(--so-space-md); border: 1px solid var(--border); border-radius: var(--so-radius-md); background: var(--card); color: var(--foreground); font-size: 13px; font-weight: 500; text-decoration: none; }
|
|
1244
1258
|
.approval-secondary > .approval-link:not(:first-child) { border-color: transparent; background: none; color: var(--muted-foreground); }
|
|
1245
1259
|
@media (hover: hover) and (pointer: fine) { .approval-link:hover { background: var(--muted); color: var(--foreground); } }
|
|
1246
1260
|
details.approval-details { margin: 0; padding: 0; border: 0; border-top: 1px solid var(--border); border-radius: 0; background: none; }
|
|
1247
1261
|
details.approval-details[open] { padding-bottom: 0; }
|
|
1248
|
-
.approval-details > summary { display: flex; align-items: center; min-height: 40px; padding:
|
|
1249
|
-
.approval-detail { max-width: 75ch; margin:
|
|
1250
|
-
.approval-detail h3 { margin: 0 0
|
|
1251
|
-
.approval-detail p, .approval-detail ul, .approval-detail dl { margin:
|
|
1262
|
+
.approval-details > summary { display: flex; align-items: center; min-height: 40px; padding: var(--so-space-xs) 0 0; font-size: 13px; }
|
|
1263
|
+
.approval-detail { max-width: 75ch; margin: var(--so-space-md) 0 0; font-size: 13px; line-height: 1.55; overflow-wrap: anywhere; }
|
|
1264
|
+
.approval-detail h3 { margin: 0 0 var(--so-space-xs); font-size: 13px; font-weight: 600; letter-spacing: 0; text-transform: none; }
|
|
1265
|
+
.approval-detail p, .approval-detail ul, .approval-detail dl { margin: var(--so-space-xs) 0; }
|
|
1252
1266
|
.approval-detail ul { padding-left: 1.25rem; }
|
|
1253
1267
|
.approval-detail .revision-card { margin: 0; padding: 0; border: 0; background: none; }
|
|
1254
|
-
.approval-roles { display: grid; gap:
|
|
1255
|
-
.approval-roles > div { display: grid; grid-template-columns: 6rem minmax(0, 1fr); gap:
|
|
1268
|
+
.approval-roles { display: grid; gap: var(--so-space-sm); }
|
|
1269
|
+
.approval-roles > div { display: grid; grid-template-columns: 6rem minmax(0, 1fr); gap: var(--so-space-md); }
|
|
1256
1270
|
.approval-roles dt { color: var(--muted-foreground); font-weight: 500; }
|
|
1257
1271
|
.approval-roles dd { margin: 0; }
|
|
1258
1272
|
.approval-roles dd ul { margin: 2px 0 0; color: var(--muted-foreground); }
|
|
1259
1273
|
.chat-plan .approval-sheet { padding: 0; border: 0; background: none; }
|
|
1260
1274
|
@media (max-width: 760px) {
|
|
1261
|
-
.approval-sheet { gap:
|
|
1275
|
+
.approval-sheet { gap: var(--so-space-md); padding: 14px; }
|
|
1262
1276
|
.approval-row { grid-template-columns: 1fr; gap: 2px; }
|
|
1263
1277
|
.approval-act { grid-template-columns: 1fr; }
|
|
1264
1278
|
.approval-act > button, .approval-password-note { grid-column: auto; grid-row: auto; }
|
|
@@ -1269,7 +1283,7 @@
|
|
|
1269
1283
|
position: sticky; bottom: 0; z-index: 20; margin: 0 -14px; padding: 10px 14px calc(10px + env(safe-area-inset-bottom, 0px));
|
|
1270
1284
|
border-top: 1px solid var(--border); background: var(--card);
|
|
1271
1285
|
}
|
|
1272
|
-
.approval-link { min-height: 44px; padding: 0
|
|
1286
|
+
.approval-link { min-height: 44px; padding: 0 var(--so-space-lg); }
|
|
1273
1287
|
.approval-edit[open] > summary { top: 6px; right: 6px; }
|
|
1274
1288
|
.approval-field textarea, .approval-field input[type=text] { font-size: 16px; }
|
|
1275
1289
|
.approval-edit-act button { width: 100%; min-height: 44px; font-size: 16px; }
|
|
@@ -1719,7 +1733,7 @@
|
|
|
1719
1733
|
.tabbar a { position: relative; }
|
|
1720
1734
|
.tabbar a .dot-badge {
|
|
1721
1735
|
position: absolute; top: .3125rem; left: calc(50% + .375rem);
|
|
1722
|
-
width: .375rem; height: .375rem; border-radius:
|
|
1736
|
+
width: .375rem; height: .375rem; border-radius: var(--so-radius-full); background: var(--brand);
|
|
1723
1737
|
}
|
|
1724
1738
|
.content > main { padding: 1rem 1rem calc(4.5rem + env(safe-area-inset-bottom, 0rem)); }
|
|
1725
1739
|
.project-add-card { padding: 1rem; }
|
|
@@ -1752,7 +1766,7 @@
|
|
|
1752
1766
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
1753
1767
|
.stat-card .v { font-size: .75rem; color: var(--muted-foreground); margin-top: .25rem;
|
|
1754
1768
|
white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
1755
|
-
.dot { display: inline-block; width: .5rem; height: .5rem; border-radius:
|
|
1769
|
+
.dot { display: inline-block; width: .5rem; height: .5rem; border-radius: var(--so-radius-full); flex: none; }
|
|
1756
1770
|
.dot-ok { background: var(--success); }
|
|
1757
1771
|
/* Caution without a claim on the operator: quiet, not magenta. */
|
|
1758
1772
|
.dot-warn { background: var(--muted-foreground); }
|
|
@@ -1787,13 +1801,13 @@
|
|
|
1787
1801
|
.sso-step-up { display: inline-flex; align-items: center; min-height: 36px; font-size: .9rem; }
|
|
1788
1802
|
.sso-step-up[data-sso-step-up="confirmed"] { color: var(--so-success); }
|
|
1789
1803
|
.sso-step-up[data-sso-step-up="confirmed"]::before { content: "✓"; margin-right: 6px; }
|
|
1790
|
-
.login-shell .login-sso { display: flex; justify-content: center; align-items: center; min-height: 44px; border-radius:
|
|
1804
|
+
.login-shell .login-sso { display: flex; justify-content: center; align-items: center; min-height: 44px; border-radius: var(--so-radius-md); background: var(--so-accent); color: var(--so-on-accent); font-weight: 600; text-decoration: none; margin: 0 0 1rem; }
|
|
1791
1805
|
@media (hover: hover) and (pointer: fine) { .login-shell .login-sso:hover { background: var(--so-accent-hover); } }
|
|
1792
1806
|
.login-shell .login-password > summary { text-align: center; font-size: .875rem; color: var(--muted-foreground); cursor: pointer; margin: 0 0 .75rem; }
|
|
1793
1807
|
.focus-page { max-width: 40rem; margin: 0 auto; padding: 2rem 1.25rem 3rem; }
|
|
1794
1808
|
.focus-page .focus-brand { display: inline-flex; margin: 0 0 2.5rem; }
|
|
1795
1809
|
.focus-page h1 { margin: 0 0 1rem; }
|
|
1796
|
-
.secret-value { overflow-wrap: anywhere; font-size: .95rem; padding: .75rem .875rem; margin: .75rem 0; border: 1px solid var(--border); border-radius:
|
|
1810
|
+
.secret-value { overflow-wrap: anywhere; font-size: .95rem; padding: .75rem .875rem; margin: .75rem 0; border: 1px solid var(--border); border-radius: var(--so-radius-md); background: var(--background); user-select: all; }
|
|
1797
1811
|
|
|
1798
1812
|
@media (max-width: 640px) {
|
|
1799
1813
|
button, form.option button { min-height: 2.75rem; }
|
|
@@ -1811,7 +1825,7 @@
|
|
|
1811
1825
|
building, then the rest. A header is a 2.75rem tap; a drawn chevron
|
|
1812
1826
|
says which way it folds. */
|
|
1813
1827
|
@media (max-width: 760px) {
|
|
1814
|
-
.board { display: flex; flex-direction: column; gap: .5rem; padding-bottom: 0; }
|
|
1828
|
+
.board { display: flex; flex-direction: column; align-items: stretch; gap: .5rem; padding-bottom: 0; }
|
|
1815
1829
|
.board .lane { min-height: 0; padding: 0 .625rem .125rem; }
|
|
1816
1830
|
.board .lane > summary {
|
|
1817
1831
|
cursor: pointer; display: flex; align-items: center; min-height: 2.75rem; margin: 0;
|
|
@@ -1845,12 +1859,12 @@
|
|
|
1845
1859
|
.lane .hint { margin-top: 0; }
|
|
1846
1860
|
.lane-count { color: var(--muted-foreground); font-weight: 400; font-variant-numeric: tabular-nums; }
|
|
1847
1861
|
.lane h2::before {
|
|
1848
|
-
content: ""; width: .375rem; height: .375rem; border-radius:
|
|
1862
|
+
content: ""; width: .375rem; height: .375rem; border-radius: var(--so-radius-full); flex: none;
|
|
1849
1863
|
background: var(--muted-foreground); opacity: .55;
|
|
1850
1864
|
}
|
|
1851
1865
|
.lane-attention h2::before { background: var(--brand); opacity: 1; }
|
|
1852
1866
|
.lane-building h2::before { background: var(--running); opacity: 1; }
|
|
1853
|
-
.lane-done h2::before { background: var(--
|
|
1867
|
+
.lane-done h2::before { background: var(--muted-foreground); opacity: 1; }
|
|
1854
1868
|
.lane-card {
|
|
1855
1869
|
display: block; text-decoration: none; color: inherit;
|
|
1856
1870
|
background: var(--card); border: 1px solid var(--border);
|
|
@@ -1877,6 +1891,37 @@
|
|
|
1877
1891
|
font-family: var(--font-mono); font-size: .6875rem; color: var(--running); font-variant-numeric: tabular-nums;
|
|
1878
1892
|
}
|
|
1879
1893
|
.lane-card .live-line .clock { color: var(--muted-foreground); }
|
|
1894
|
+
/* The build's steps — set up, writing, checking and committing: three quiet
|
|
1895
|
+
ticks, the current one in the running hue. A stage, never a percent. */
|
|
1896
|
+
.lane-card .steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .1875rem; margin-top: .5rem; }
|
|
1897
|
+
.lane-card .steps i { height: .1875rem; border-radius: 999px; background: var(--border); }
|
|
1898
|
+
.lane-card .steps i.on { background: color-mix(in srgb, var(--running) 45%, var(--border)); }
|
|
1899
|
+
.lane-card .steps i.now { background: var(--running); }
|
|
1900
|
+
|
|
1901
|
+
/* The worker strip: one quiet tile per worker above the lanes — what it is
|
|
1902
|
+
building here, the stage, the clock. Ink and lines only; the running dot
|
|
1903
|
+
is the one hue. */
|
|
1904
|
+
.crew { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: .625rem; margin: .25rem 0 .875rem; }
|
|
1905
|
+
.crew-empty { margin: .25rem 0 .875rem; }
|
|
1906
|
+
.worker {
|
|
1907
|
+
border: 1px solid var(--border); border-radius: var(--radius); background: var(--card);
|
|
1908
|
+
padding: .625rem .75rem; min-width: 0; display: flex; flex-direction: column; gap: .375rem;
|
|
1909
|
+
}
|
|
1910
|
+
.worker-busy { border-color: color-mix(in srgb, var(--running) 30%, var(--border)); }
|
|
1911
|
+
.worker-offline { opacity: .6; }
|
|
1912
|
+
.worker-head { display: flex; align-items: center; gap: .5rem; min-width: 0; }
|
|
1913
|
+
.worker-head .name { font-family: var(--font-mono); font-size: .75rem; font-weight: 500; }
|
|
1914
|
+
.worker-head .kind { font-size: .6875rem; color: var(--muted-foreground); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 1; min-width: 0; }
|
|
1915
|
+
.worker-head .slots { font-family: var(--font-mono); font-size: .6875rem; color: var(--muted-foreground); font-variant-numeric: tabular-nums; }
|
|
1916
|
+
.worker-job { display: flex; flex-direction: column; gap: .0625rem; text-decoration: none; color: inherit; min-width: 0; margin: 0; }
|
|
1917
|
+
.worker-job .t { font-size: .8125rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
1918
|
+
.worker-job .sub { display: flex; justify-content: space-between; gap: .5rem; font-family: var(--font-mono); font-size: .6875rem; color: var(--muted-foreground); font-variant-numeric: tabular-nums; }
|
|
1919
|
+
.worker-job.idle { font-size: .75rem; color: var(--muted-foreground); }
|
|
1920
|
+
@media (hover: hover) and (pointer: fine) { a.worker-job:hover .t { text-decoration: underline; } }
|
|
1921
|
+
@media (max-width: 760px) {
|
|
1922
|
+
.crew { grid-template-columns: minmax(0, 1fr); gap: .375rem; }
|
|
1923
|
+
.worker { padding: .5rem .625rem; }
|
|
1924
|
+
}
|
|
1880
1925
|
.lane-empty { margin: .75rem 0 .25rem; }
|
|
1881
1926
|
.plan-doc { white-space: pre-wrap; overflow-wrap: anywhere; font-size: .8125rem; max-height: 24rem; overflow-y: auto; }
|
|
1882
1927
|
.lane-more { display: block; margin-top: .5rem; font-size: .75rem; }
|
|
@@ -1901,7 +1946,7 @@
|
|
|
1901
1946
|
.command-metric .value { display: block; margin-top: .25rem; font-size: 1.5rem; font-weight: 600; line-height: 1.15; font-variant-numeric: tabular-nums; font-family: var(--font-mono); }
|
|
1902
1947
|
.command-metric .label { display: flex; align-items: center; gap: .4rem; font-weight: 500; font-size: .8125rem; }
|
|
1903
1948
|
.command-metric .label::before {
|
|
1904
|
-
content: ""; width: .375rem; height: .375rem; border-radius:
|
|
1949
|
+
content: ""; width: .375rem; height: .375rem; border-radius: var(--so-radius-full);
|
|
1905
1950
|
background: var(--muted-foreground); flex: none;
|
|
1906
1951
|
}
|
|
1907
1952
|
.command-metric .detail { display: block; color: var(--muted-foreground); font-size: .6875rem; margin-top: .18rem; }
|
|
@@ -2433,7 +2478,7 @@
|
|
|
2433
2478
|
}
|
|
2434
2479
|
.workspace-stats .pulse-stat b { display: block; color: var(--foreground); font-weight: 600; font-family: var(--font-mono); font-size: 1.125rem; line-height: 1.2; font-variant-numeric: tabular-nums; }
|
|
2435
2480
|
.workspace-stats .pulse-stat.hot b { color: var(--brand); }
|
|
2436
|
-
.workspace-bar { display: flex; gap: 2px; height: .375rem; margin-top: .625rem; border-radius:
|
|
2481
|
+
.workspace-bar { display: flex; gap: 2px; height: .375rem; margin-top: .625rem; border-radius: var(--so-radius-full); overflow: hidden; background: var(--muted); }
|
|
2437
2482
|
.workspace-bar .seg { flex: 1 1 0; }
|
|
2438
2483
|
.workspace-bar .seg.attention { background: var(--brand); }
|
|
2439
2484
|
.workspace-bar .seg.building { background: var(--running); }
|
|
@@ -2660,8 +2705,10 @@ button { min-height: 44px; }
|
|
|
2660
2705
|
@media (hover: hover) and (pointer: fine) { .next-pager .skip:hover { border-color: color-mix(in srgb, var(--border) 60%, var(--muted-foreground)); } }
|
|
2661
2706
|
|
|
2662
2707
|
/* Motion: only where a human caused the change — navigation, presses,
|
|
2663
|
-
overlays
|
|
2664
|
-
|
|
2708
|
+
overlays — and one exception, the live board: a card that changes lane
|
|
2709
|
+
slides there and a worker that picks up work flashes once (the board's
|
|
2710
|
+
swap, html.so-swap, below). Every other liveness swap stays instant; the
|
|
2711
|
+
pulse dot is the one "alive" signal. Everything dies under prefers-reduced-motion; auto-refresh pages
|
|
2665
2712
|
opt out of the navigation cross-fade separately (see shell()). */
|
|
2666
2713
|
@view-transition { navigation: auto; }
|
|
2667
2714
|
/* A page change fades THROUGH, not across: the old page leaves before the new
|
|
@@ -2762,3 +2809,21 @@ button.pick-file { min-height: 1.75rem; padding: 0 .55rem; font-size: .75rem; }
|
|
|
2762
2809
|
.meta, .hint { line-height: 1.35; }
|
|
2763
2810
|
details { margin: var(--so-phone-row) 0; }
|
|
2764
2811
|
}
|
|
2812
|
+
|
|
2813
|
+
/* The live board's swap (regionScript animate): only cards move — the page
|
|
2814
|
+
itself does not fade — a short slide for a card that changed lane, a drop
|
|
2815
|
+
for a new one, a fade for one that left. Transform and opacity only, and
|
|
2816
|
+
the reduce block kills it with everything else (the script also skips the
|
|
2817
|
+
transition under reduced motion). */
|
|
2818
|
+
html.so-swap::view-transition-old(root), html.so-swap::view-transition-new(root) { animation: none; }
|
|
2819
|
+
html.so-swap::view-transition-group(*) { animation-duration: 320ms; animation-timing-function: cubic-bezier(.2, .8, .2, 1); }
|
|
2820
|
+
html.so-swap::view-transition-new(*):only-child { animation: so-card-in 240ms ease-out both; }
|
|
2821
|
+
html.so-swap::view-transition-old(*):only-child { animation: so-card-out 160ms ease-in both; }
|
|
2822
|
+
@keyframes so-card-in { from { opacity: 0; transform: translateY(-.375rem); } }
|
|
2823
|
+
@keyframes so-card-out { to { opacity: 0; } }
|
|
2824
|
+
.worker.flash { animation: so-worker-claim 900ms ease-out; }
|
|
2825
|
+
@keyframes so-worker-claim { from { background: color-mix(in srgb, var(--running) 14%, var(--card)); } }
|
|
2826
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2827
|
+
html.so-swap::view-transition-group(*), html.so-swap::view-transition-new(*), html.so-swap::view-transition-old(*) { animation: none !important; }
|
|
2828
|
+
.worker.flash { animation: none; }
|
|
2829
|
+
}
|
package/dist/server/flows.js
CHANGED
|
@@ -18,7 +18,7 @@ import { assignFlowCard, commentOnFlowCard, watchFlowCard } from "../flow-people
|
|
|
18
18
|
import { saveScript } from "../flow-scripts.js";
|
|
19
19
|
import { chooseFlowCard } from "../flow-send.js";
|
|
20
20
|
import { exportFlow, fetchFlowFile, FlowFileError, importFlow, parseFlowFile, planFlowImport } from "../flow-share.js";
|
|
21
|
-
import { addFlowTriggerTo, checkFlowTriggerNow, pressFlowButton, removeFlowTrigger, removeLinearKey, setFlowTriggerOn, renewFlowHook, saveHooksBase, saveLinearKey,
|
|
21
|
+
import { addFlowTriggerTo, checkFlowTriggerNow, pressFlowButton, removeFlowTrigger, removeLinearKey, setFlowTriggerOn, renewFlowHook, saveHooksBase, saveLinearKey, saveSigningSecret, setUpFlowHook, changeFlowHookSender, setFlowHookScope, shareFlowButton, stopSharingFlowButton, rawTakesDeliveries } from "../flow-triggers.js";
|
|
22
22
|
import { FLOW_IMPORT_SCRIPT, flowFallbackHtml, flowImportHtml, flowsListHtml, flowView } from "../flows-ui.js";
|
|
23
23
|
import { FLOW_TEMPLATES, FlowContractError, validateFlowDefinition, withZoneNames } from "../flows.js";
|
|
24
24
|
import { prepareUnattendedCandidates, parseUnattendedAsk, revokeUnattended, signUnattended, untilWords } from "../flow-unattended.js";
|
|
@@ -43,7 +43,7 @@ import { redirect, respond, SAFETY, taskHref } from "./http.js";
|
|
|
43
43
|
import { html } from "../html.js";
|
|
44
44
|
import {} from "./session.js";
|
|
45
45
|
export function createFlowsHandlers(runtime) {
|
|
46
|
-
const { store, clock, sendScreen, chromeFor, consoleProjects, options, visible, flowRooms, identify, liveCeiling, providerHome, toolHome, restricted, evidenceRoot, authenticateApprover, projectOf, unscopedMode, ceiling, authorizeMutation } = runtime;
|
|
46
|
+
const { store, clock, sendScreen, chromeFor, consoleProjects, options, visible, flowRooms, identify, liveCeiling, providerHome, toolHome, restricted, evidenceRoot, authenticateApprover, authenticateCredential, projectOf, unscopedMode, ceiling, authorizeMutation } = runtime;
|
|
47
47
|
// ---- reads ---------------------------------------------------------------
|
|
48
48
|
/** A gallery template's page (Flows → New → Use this): its questions, the preview of these answers, and Create. */
|
|
49
49
|
function sendGalleryUse(response, who, template, projects, repo, given, name, notice, said = null) {
|
|
@@ -572,7 +572,11 @@ export function createFlowsHandlers(runtime) {
|
|
|
572
572
|
catch {
|
|
573
573
|
return answer(400, { ok: false, said: "That trigger couldn't be read." });
|
|
574
574
|
}
|
|
575
|
-
|
|
575
|
+
// A trigger that takes deliveries mints an address: a credential act (docs/plans/passwordless.md).
|
|
576
|
+
const ingress = rawTakesDeliveries(raw);
|
|
577
|
+
if (ingress && !authenticateCredential(who, body.get("password") ?? "").ok)
|
|
578
|
+
return answer(403, { ok: false, said: "Enter your Toolroll password to make a webhook address." });
|
|
579
|
+
const made = addFlowTriggerTo(store, flow, raw, who.name, now, dir, ingress ? { ingress: "proved" } : {});
|
|
576
580
|
if (made.ok)
|
|
577
581
|
await prepareUnattendedCandidates(store, flow.id);
|
|
578
582
|
return made.ok ? settle(made.said, made.reveal === null ? {} : { reveal: made.reveal }) : answer(400, { ok: false, said: made.message });
|
|
@@ -729,6 +733,10 @@ export function createFlowsHandlers(runtime) {
|
|
|
729
733
|
removeFlowTrigger(store, trigger, now, dir, who.name);
|
|
730
734
|
return settle("Trigger removed.");
|
|
731
735
|
}
|
|
736
|
+
// A public form link and a new webhook address each open a way in: credential acts, a password typed now.
|
|
737
|
+
if ((verb === "share" || verb === "renew") && !authenticateCredential(who, body.get("password") ?? "").ok) {
|
|
738
|
+
return answer(403, { ok: false, said: verb === "share" ? "Enter your Toolroll password to share a form link." : "Enter your Toolroll password to make a new address." });
|
|
739
|
+
}
|
|
732
740
|
if (verb === "share") {
|
|
733
741
|
const shared = shareFlowButton(store, trigger, now, dir);
|
|
734
742
|
return shared.ok ? settle(shared.said, { reveal: shared.reveal }) : answer(409, { ok: false, said: shared.message });
|
|
@@ -737,6 +745,11 @@ export function createFlowsHandlers(runtime) {
|
|
|
737
745
|
stopSharingFlowButton(store, trigger, now);
|
|
738
746
|
return settle("The form link no longer works.");
|
|
739
747
|
}
|
|
748
|
+
// v126: a person has seen that deliveries were turned away (the banner stays until then).
|
|
749
|
+
if (verb === "dropped") {
|
|
750
|
+
store.clearFlowDeliveriesDropped(trigger.id);
|
|
751
|
+
return settle("Cleared.");
|
|
752
|
+
}
|
|
740
753
|
if (verb === "press") {
|
|
741
754
|
let answers;
|
|
742
755
|
try {
|
|
@@ -764,11 +777,24 @@ export function createFlowsHandlers(runtime) {
|
|
|
764
777
|
const renewed = renewFlowHook(store, trigger, now, dir);
|
|
765
778
|
return renewed.ok ? settle(renewed.said, { reveal: renewed.reveal }) : answer(409, { ok: false, said: renewed.message });
|
|
766
779
|
}
|
|
767
|
-
//
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
780
|
+
// A webhook's credentials change only on this secure panel, behind the password — never in chat (v126): a secret
|
|
781
|
+
// pasted (Linear's, Sentry's, Vercel's), one made and shown once with a new address, or who signs its deliveries.
|
|
782
|
+
if (!authenticateCredential(who, body.get("password") ?? "").ok)
|
|
783
|
+
return answer(403, { ok: false, said: verb === "secret" ? "Enter your Toolroll password to save a secret." : "Enter your Toolroll password to change how this webhook is proved." });
|
|
784
|
+
if (verb === "setup") {
|
|
785
|
+
const made = setUpFlowHook(store, trigger, now, dir);
|
|
786
|
+
return made.ok ? settle(made.said, { reveal: made.reveal }) : answer(409, { ok: false, said: made.message });
|
|
787
|
+
}
|
|
788
|
+
if (verb === "scope") {
|
|
789
|
+
const scoped = setFlowHookScope(store, trigger, { project: body.get("project"), team: body.get("team") }, who.name, now);
|
|
790
|
+
return scoped.ok ? settle(scoped.said) : answer(400, { ok: false, said: scoped.message });
|
|
791
|
+
}
|
|
792
|
+
if (verb === "sender") {
|
|
793
|
+
const changed = changeFlowHookSender(store, trigger, body.get("sender"), who.name, now, dir);
|
|
794
|
+
return changed.ok ? settle(changed.said) : answer(400, { ok: false, said: changed.message });
|
|
795
|
+
}
|
|
796
|
+
const saved = saveSigningSecret(store, trigger, body.get("secret") ?? "", now, dir);
|
|
797
|
+
return saved.ok ? settle(saved.said) : answer(400, { ok: false, said: saved.message });
|
|
772
798
|
};
|
|
773
799
|
const recipeAct = (step) => async (ctx) => {
|
|
774
800
|
const { who, request, response, now, posted } = ctx;
|
|
@@ -924,6 +950,10 @@ export function createFlowsHandlers(runtime) {
|
|
|
924
950
|
"flow.trigger.press": triggerAct("press"),
|
|
925
951
|
"flow.trigger.renew": triggerAct("renew"),
|
|
926
952
|
"flow.trigger.secret": triggerAct("secret"),
|
|
953
|
+
"flow.trigger.setup": triggerAct("setup"),
|
|
954
|
+
"flow.trigger.sender": triggerAct("sender"),
|
|
955
|
+
"flow.trigger.scope": triggerAct("scope"),
|
|
956
|
+
"flow.trigger.dropped": triggerAct("dropped"),
|
|
927
957
|
"flow.trigger.share": triggerAct("share"),
|
|
928
958
|
"flow.trigger.unshare": triggerAct("unshare"),
|
|
929
959
|
"recipes.prepare-send": recipeAct("prepare"),
|
package/dist/server/guards.d.ts
CHANGED
|
@@ -41,6 +41,7 @@ export interface GuardsRuntime {
|
|
|
41
41
|
}
|
|
42
42
|
export declare function createSharedGuards(runtime: GuardsRuntime): {
|
|
43
43
|
authenticateApprover: (who: Who, token: string, repo?: string | null) => ReturnType<typeof checkApproverPassword>;
|
|
44
|
+
authenticateCredential: (who: Who, token: string, repo?: string | null) => ReturnType<typeof checkApproverPassword>;
|
|
44
45
|
authorizeMutation: (request: IncomingMessage, who: Who, body: FormView<FormFieldOf<"mutationGuard">>) => {
|
|
45
46
|
status: number;
|
|
46
47
|
message: string;
|
package/dist/server/guards.js
CHANGED
|
@@ -6,23 +6,29 @@ import { tokenLive, tokenProjects } from "../api-tokens.js";
|
|
|
6
6
|
import { oauthProjects, oauthTokenAllowed } from "../mcp-oauth.js";
|
|
7
7
|
import { REMOTE_MESSAGES, reproveRemote } from "../operate-remote.js";
|
|
8
8
|
import { canonicalProject, rowVisible } from "../project.js";
|
|
9
|
-
import { authenticateAccount, authenticateApprover as checkApproverPassword } from "../scope.js";
|
|
9
|
+
import { authenticateAccount, authenticateApprover as checkApproverPassword, credentialProof } from "../scope.js";
|
|
10
10
|
import { SourceBudget } from "../sign-in-guard.js";
|
|
11
11
|
import {} from "../store.js";
|
|
12
12
|
import { requestContext } from "./request-context.js";
|
|
13
13
|
import { refuse } from "./chrome.js";
|
|
14
14
|
import { matchTaskPath } from "./http.js";
|
|
15
|
-
import { PersistentSessions,
|
|
15
|
+
import { PersistentSessions, SESSION_COOKIE, sessionWithinLifetime } from "./session.js";
|
|
16
16
|
export function createSharedGuards(runtime) {
|
|
17
17
|
// v99: wrong passwords. One address guessing across names runs out of tries here; each name
|
|
18
18
|
// locks on its own (sign-in-guard.ts), and every lock, whatever road it came by, is kept.
|
|
19
19
|
/**
|
|
20
|
-
* Every step-up in the console (
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
20
|
+
* Every step-up in the console: a password typed now, or (an empty field) an explicit identity-provider re-check
|
|
21
|
+
* made on request and not yet spent, or — inside an allowlisted act only — a remembered password (cockpit B2,
|
|
22
|
+
* scope.ts proveAccountNow / freshnessFor, reading the request's live facts). Standing (an approver, with access to
|
|
23
|
+
* the project) is checked either way.
|
|
24
24
|
*/
|
|
25
|
-
|
|
25
|
+
/** A credential act (docs/plans/passwordless.md): only a password typed now (or a one-use provider re-check) proves it. */
|
|
26
|
+
function authenticateCredential(who, token, repo) {
|
|
27
|
+
if (who.via !== "cookie")
|
|
28
|
+
return { ok: false, reason: "not-an-approver" };
|
|
29
|
+
const proved = checkApproverPassword(runtime.store, who.name, token, repo, { credential: true });
|
|
30
|
+
return !proved.ok || credentialProof(proved.method) ? proved : { ok: false, reason: "not-an-approver" };
|
|
31
|
+
}
|
|
26
32
|
function authenticateApprover(who, token, repo) {
|
|
27
33
|
// Re-entering a password never upgrades a machine credential into a browser ceremony.
|
|
28
34
|
if (who.via !== "cookie")
|
|
@@ -332,7 +338,7 @@ export function createSharedGuards(runtime) {
|
|
|
332
338
|
}
|
|
333
339
|
for (const [id, session] of found === null ? [] : [found]) {
|
|
334
340
|
const now = Date.now();
|
|
335
|
-
if (
|
|
341
|
+
if (!sessionWithinLifetime(session, now)) {
|
|
336
342
|
runtime.sessions.delete(id);
|
|
337
343
|
return null;
|
|
338
344
|
}
|
|
@@ -340,10 +346,18 @@ export function createSharedGuards(runtime) {
|
|
|
340
346
|
runtime.sessions.delete(id);
|
|
341
347
|
return null;
|
|
342
348
|
}
|
|
349
|
+
// Ended in another process (or from Sessions): the cached copy is dropped, never used.
|
|
350
|
+
if (!runtime.sessions.stillSaved(id)) {
|
|
351
|
+
Map.prototype.delete.call(runtime.sessions, id);
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
343
354
|
if (touch) {
|
|
344
355
|
session.lastSeen = now;
|
|
345
356
|
runtime.sessions.persist(session, true);
|
|
346
357
|
}
|
|
358
|
+
// A touch that found the session ended elsewhere dropped it: this request is not signed in by it.
|
|
359
|
+
if (touch && !runtime.sessions.holds(session))
|
|
360
|
+
return null;
|
|
347
361
|
return session;
|
|
348
362
|
}
|
|
349
363
|
return null;
|
|
@@ -356,5 +370,5 @@ export function createSharedGuards(runtime) {
|
|
|
356
370
|
function runVisible(run) {
|
|
357
371
|
return visible(taskRepoOf(run.taskRef));
|
|
358
372
|
}
|
|
359
|
-
return { authenticateApprover, authorizeMutation, projectOf, resolveRouteProject, projectRequestAllowed, identify, lookupSession, restricted, visible, admissionList, codingActorAllowed, codingProjectAllowed, workAccess, familyOf, taskRepoOf, runVisible };
|
|
373
|
+
return { authenticateApprover, authenticateCredential, authorizeMutation, projectOf, resolveRouteProject, projectRequestAllowed, identify, lookupSession, restricted, visible, admissionList, codingActorAllowed, codingProjectAllowed, workAccess, familyOf, taskRepoOf, runVisible };
|
|
360
374
|
}
|
package/dist/server/http.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
/** HTTP answers every console route shares: server options, body limits, safe responses, redirects and return paths. */
|
|
2
|
+
import type { TerminalHost } from "../live-terminal.js";
|
|
2
3
|
import { type Html } from "../html.js";
|
|
3
4
|
import { type CliHttpOptions, type RunOperateAs } from "../cli-http.js";
|
|
4
5
|
import { type CodingWorkspace } from "../coding-workspace.js";
|
|
@@ -25,6 +26,8 @@ export type ServeOptions = {
|
|
|
25
26
|
installBin?: string;
|
|
26
27
|
/** Native coding workspace injection for isolated integration tests. */
|
|
27
28
|
codingWorkspace?: CodingWorkspace;
|
|
29
|
+
/** Live terminals (tests stand their own in; null turns them off). Default: one on a machine that runs agents. */
|
|
30
|
+
terminalHost?: TerminalHost | null;
|
|
28
31
|
/** Read-only worker connections for heavy reads (read-executor.ts); 0 reads in-process. Default: off under tests. */
|
|
29
32
|
readWorkers?: number;
|
|
30
33
|
store: Store;
|
|
@@ -141,6 +144,10 @@ export type ServeOptions = {
|
|
|
141
144
|
connectFetch?: typeof fetch;
|
|
142
145
|
/** Tests: every request sign-in with the identity provider makes (discovery, keys, tokens). */
|
|
143
146
|
ssoFetch?: typeof fetch;
|
|
147
|
+
/** Cockpit B1: this `up` console's instance secret (null: none — the instance route answers 404). */
|
|
148
|
+
instanceSecret?: () => string | null;
|
|
149
|
+
/** Cockpit E: how Finder is asked to reveal a proved checkout (tests pass their own; never a launch). True: shown. */
|
|
150
|
+
revealPath?: (path: string) => Promise<boolean> | boolean;
|
|
144
151
|
chatEnv?: Record<string, string | undefined>;
|
|
145
152
|
/**
|
|
146
153
|
* The live peek's locality ASSERTION (live-peek v3 §3): the administrator
|
package/dist/server/http.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** HTTP answers every console route shares: server options, body limits, safe responses, redirects and return paths. */
|
|
2
1
|
import { html, htmlString, isHtml } from "../html.js";
|
|
3
2
|
import { chatResultHref as sharedResultHref } from "../chat-controls.js";
|
|
4
3
|
import {} from "../cli-http.js";
|
|
@@ -117,7 +116,9 @@ export function goOutside(response, to, words, bind) {
|
|
|
117
116
|
response.end(htmlString(html `<!doctype html><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta http-equiv="refresh" content="0;url=${to}"><title>Toolroll</title>${HANDOFF_STYLE}<p>${words} <a href="${to}">Continue</a></p>`));
|
|
118
117
|
}
|
|
119
118
|
export function redirect(response, to) {
|
|
120
|
-
|
|
119
|
+
// Set as a header (not only in writeHead) so the answer can be read back after: a refused act's redirect names it.
|
|
120
|
+
response.setHeader("Location", to);
|
|
121
|
+
response.writeHead(303, { ...SAFETY });
|
|
121
122
|
response.end();
|
|
122
123
|
}
|
|
123
124
|
export const taskChatHref = (taskId) => `/chat?task=${encodeURIComponent(taskId)}`;
|
package/dist/server/live.d.ts
CHANGED
|
@@ -1,10 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GET /live: one stream per page, joined to every room the page shows.
|
|
3
|
+
*
|
|
4
|
+
* room=workspace the reader's workspace may have changed (any meaningful write, or a lapse)
|
|
5
|
+
* room=task:<id> the task family changed; who else has it open
|
|
6
|
+
* room=flow:<id>?card=&editing= the flow changed; who else is on it, and on which card
|
|
7
|
+
* room=chat[?task=|?project=] the reader's own lead reply, as it runs (the only room that carries content)
|
|
8
|
+
* room=team[?conversation=] the team conversation's cursor moved
|
|
9
|
+
* room=agent:<run> one agent on the Agents board changed; while open, this person watches it (no pings)
|
|
10
|
+
* room=summary the reader's project states (the sidebar): each change carries the snapshot; never watching or seeing
|
|
11
|
+
*
|
|
12
|
+
* Every room is validated before anything is looked up, and admitted with
|
|
13
|
+
* the same checks and answers as the page it belongs to, before the stream
|
|
14
|
+
* opens; each is re-proved on every signal and its safety-net check, and a
|
|
15
|
+
* viewer who no longer passes hears `gone`. Events name their room. A page
|
|
16
|
+
* that falls behind gets one `reload` and the stream ends, so its
|
|
17
|
+
* EventSource reconnects (live-bus.ts).
|
|
18
|
+
*/
|
|
19
|
+
import type { IncomingMessage } from "node:http";
|
|
1
20
|
import { type LiveBus } from "../live-bus.js";
|
|
2
21
|
import type { WorkspaceRevision } from "../workspace-revision.js";
|
|
3
22
|
import type { ServerRuntime } from "./runtime.js";
|
|
23
|
+
import type { Who } from "./session.js";
|
|
4
24
|
/** A page asks for a few rooms at once: its workspace, what it shows, its conversation. */
|
|
5
|
-
export declare const LIVE_ROOMS_PER_PAGE =
|
|
25
|
+
export declare const LIVE_ROOMS_PER_PAGE = 6;
|
|
6
26
|
export type LiveRoom = {
|
|
7
27
|
kind: "workspace";
|
|
28
|
+
} | {
|
|
29
|
+
kind: "summary";
|
|
8
30
|
} | {
|
|
9
31
|
kind: "task";
|
|
10
32
|
task: string;
|
|
@@ -26,10 +48,21 @@ export type LiveRoom = {
|
|
|
26
48
|
};
|
|
27
49
|
/** A room's name, read strictly: anything else is not a room. */
|
|
28
50
|
export declare function parseLiveRoom(name: string): LiveRoom | null;
|
|
51
|
+
/** The same session, still signed in, from the cookie and the account (never this request's context): a live room's and
|
|
52
|
+
* a live terminal's re-proof. Null when it was signed out, ended elsewhere, revoked, rotated or re-roled. */
|
|
53
|
+
export declare function rereadBrowser(runtime: Pick<ServerRuntime, "identify" | "sessions" | "store">, request: IncomingMessage, who: Who & {
|
|
54
|
+
via: "cookie";
|
|
55
|
+
}): (Who & {
|
|
56
|
+
via: "cookie";
|
|
57
|
+
}) | null;
|
|
29
58
|
export declare function createLiveHandlers(runtime: ServerRuntime, live: {
|
|
30
59
|
bus: LiveBus;
|
|
31
60
|
workspaceRevision: WorkspaceRevision;
|
|
32
61
|
chatProjectOf: (projects: string[]) => string | null | undefined;
|
|
62
|
+
/** One account's sidebar snapshot for one scope (serve.ts projectSummaryFor); null: gone, or the scope moved. */
|
|
63
|
+
projectSummaryFor: (account: string, scope: string) => string | null;
|
|
64
|
+
/** What one account may see now (serve.ts projectScopeFor); null: no such account. */
|
|
65
|
+
projectScopeFor: (account: string) => string | null;
|
|
33
66
|
}): {
|
|
34
67
|
registrations: import("./handler-registry.js").Registration[];
|
|
35
68
|
turnStarted: (thread: number) => void;
|