toolroll 0.9.62 → 0.9.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +80 -0
- package/README.md +66 -8
- 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 +203 -10
- package/dist/agent-fence.js +623 -41
- 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 +36 -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/browser/THIRD_PARTY_NOTICES.txt +48 -0
- package/dist/browser/terminal.css +37 -0
- package/dist/browser/terminal.js +117 -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 +263 -1
- package/dist/browser-workspace.js +60 -0
- package/dist/builder.d.ts +6 -1
- package/dist/builder.js +34 -13
- package/dist/chat-actions.d.ts +13 -1
- package/dist/chat-actions.js +199 -17
- 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/check-levels.js +3 -0
- 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 +20 -1
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.js +5 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +24 -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/cli.d.ts +8 -0
- package/dist/contracts/cli.js +3 -1
- package/dist/contracts/console-api.d.ts +30 -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/integration-metadata.d.ts +2 -1
- package/dist/contracts/integration-metadata.js +2 -1
- 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/discord-chat.js +4 -1
- package/dist/dispatch.js +7 -4
- package/dist/doctor.d.ts +53 -0
- package/dist/doctor.js +427 -0
- 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/evidence-pack.d.ts +1 -1
- package/dist/evidence-pack.js +2 -2
- package/dist/exec.d.ts +81 -0
- package/dist/exec.js +368 -9
- package/dist/export-ui.js +2 -2
- package/dist/flow-code.d.ts +2 -2
- package/dist/flow-code.js +4 -15
- package/dist/flow-engine.js +35 -11
- 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 +84 -11
- package/dist/flow-triggers.js +554 -87
- package/dist/flow-unattended-words.d.ts +28 -0
- package/dist/flow-unattended-words.js +50 -0
- package/dist/flow-unattended.d.ts +227 -0
- package/dist/flow-unattended.js +776 -0
- package/dist/flows-cli.d.ts +28 -1
- package/dist/flows-cli.js +63 -12
- package/dist/flows-ui.d.ts +2 -3
- package/dist/flows-ui.js +56 -5
- package/dist/flows.d.ts +4 -0
- package/dist/flows.js +9 -1
- package/dist/google-mail.d.ts +1 -0
- package/dist/google-mail.js +61 -18
- package/dist/html.d.ts +9 -0
- package/dist/html.js +11 -0
- package/dist/integrations-ui.d.ts +2 -1
- package/dist/integrations-ui.js +6 -3
- package/dist/integrations.d.ts +17 -3
- package/dist/integrations.js +38 -18
- package/dist/invoke.d.ts +17 -0
- package/dist/invoke.js +510 -182
- package/dist/keys.d.ts +18 -14
- package/dist/keys.js +5 -0
- package/dist/landed-cleanup.d.ts +3 -2
- package/dist/landed-cleanup.js +12 -5
- 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 +163 -4
- 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 +258 -0
- package/dist/live-terminal.js +649 -0
- package/dist/live.d.ts +38 -27
- package/dist/live.js +142 -124
- package/dist/mcp-connect.d.ts +8 -7
- package/dist/mcp-connect.js +49 -51
- 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/oauth-run-token.d.ts +51 -0
- package/dist/oauth-run-token.js +127 -0
- package/dist/operate.d.ts +2 -0
- package/dist/operate.js +282 -18
- 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/plan-auto.d.ts +11 -0
- package/dist/plan-auto.js +62 -11
- 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/process-recovery-eligibility.d.ts +1 -1
- package/dist/project-access.d.ts +3 -0
- package/dist/project-access.js +3 -0
- package/dist/project-delete-ui.d.ts +12 -0
- package/dist/project-delete-ui.js +41 -9
- package/dist/project-delete.d.ts +3 -1
- package/dist/project-delete.js +12 -6
- package/dist/project-file.d.ts +3 -0
- package/dist/project-file.js +16 -0
- package/dist/project-memory.d.ts +3 -1
- package/dist/project-memory.js +57 -25
- package/dist/project-tools.d.ts +103 -27
- package/dist/project-tools.js +399 -100
- 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-home.d.ts +22 -0
- package/dist/provider-home.js +99 -0
- package/dist/provider.d.ts +42 -5
- package/dist/provider.js +97 -19
- 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.d.ts +3 -0
- package/dist/release.js +14 -8
- package/dist/remote-main.d.ts +4 -0
- package/dist/remote-main.js +3 -3
- package/dist/request-budget-ui.js +2 -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 +171 -6
- package/dist/scope.js +251 -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 +258 -43
- package/dist/server/chat.d.ts +1 -1
- package/dist/server/chat.js +122 -31
- package/dist/server/chrome.d.ts +6 -1
- package/dist/server/chrome.js +18 -7
- package/dist/server/console.css +52 -38
- package/dist/server/flows.js +65 -13
- 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 +4 -1
- package/dist/server/render-pages.js +5 -4
- 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 +110 -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 +49 -5
- package/dist/server/runtime.d.ts +34 -3
- package/dist/server/session.d.ts +25 -1
- package/dist/server/session.js +18 -4
- package/dist/server/settings.js +132 -13
- 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 +320 -74
- 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-sweep-child.js +3 -1
- package/dist/storage-sweep-process.d.ts +12 -5
- package/dist/storage-sweep-process.js +23 -6
- 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 +466 -19
- package/dist/store.js +1185 -63
- package/dist/subagent-desk.js +1 -1
- package/dist/subagent-tools.d.ts +1 -1
- package/dist/summary.js +3 -0
- package/dist/surface.js +6 -4
- 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 +14 -0
- package/dist/teardown-git.js +119 -0
- 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 +39 -0
- package/dist/tool-broker.js +370 -0
- package/dist/tool-launcher.js +5 -4
- package/dist/tool-secret-store.d.ts +170 -0
- package/dist/tool-secret-store.js +834 -0
- package/dist/toolroll-update-ui.js +2 -2
- package/dist/toolroll-update.js +14 -3
- package/dist/tools-ui.d.ts +7 -1
- package/dist/tools-ui.js +19 -10
- 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 +21 -5
- package/dist/workspace-revision.js +3 -1
- package/dist/worktree.d.ts +10 -4
- package/dist/worktree.js +70 -29
- package/package.json +13 -2
- package/scripts/provider-canary.mjs +210 -31
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
/** Task pages: approval, agents, plans, controls, decisions and the task body. */
|
|
2
1
|
import { type Html } from "../html.js";
|
|
3
2
|
import { type RunActivity } from "../activity-line.js";
|
|
4
3
|
import { type AgentChoice } from "../agentconfig.js";
|
|
5
4
|
import { type AssignmentSnapshot } from "../assignment.js";
|
|
6
5
|
import { type TaskBaseView } from "../task-base.js";
|
|
7
|
-
import { type BrowserTaskView } from "../browser-workspace.js";
|
|
6
|
+
import { type BrowserAgentControls, type BrowserTaskView } from "../browser-workspace.js";
|
|
8
7
|
import { type FormView } from "../contracts/console-api.js";
|
|
9
8
|
import { type DispatchDiagnosis } from "../dispatch.js";
|
|
10
9
|
import { type ReportView } from "../evidence.js";
|
|
@@ -23,6 +22,7 @@ import { type DisplayStatus, type PublicationFacts, type ReviewFacts, type WorkS
|
|
|
23
22
|
import { type Chrome, type Screen } from "./chrome.js";
|
|
24
23
|
import { type CompletionReceiptView, type EvidenceLinkMap, type TaskPullRequest } from "./render-results.js";
|
|
25
24
|
import { type Who } from "./session.js";
|
|
25
|
+
import { type TaskOrigin } from "../task-source.js";
|
|
26
26
|
/** What the task and approval views show about a drafted plan's contract
|
|
27
27
|
* (contract handoff, task 1). A problem is a named problem, never a blank. */
|
|
28
28
|
export type PlanContractView = {
|
|
@@ -74,14 +74,6 @@ export declare function revisionSentence(revision: Extract<RevisionView, {
|
|
|
74
74
|
/** A planner's amendment, said plainly and kept in view: approving binds
|
|
75
75
|
* the amended terms, so this is never folded away. */
|
|
76
76
|
export declare function approvalAmendmentHtml(view: PlanContractView | null | undefined): Html;
|
|
77
|
-
/**
|
|
78
|
-
* The approval sheet (approval critique, Oct 2): the plan open, in plain
|
|
79
|
-
* rows — Goal, Changes, Won't touch, Done when — one line of who builds,
|
|
80
|
-
* one Approve & start beside the password, and every remaining signed
|
|
81
|
-
* term (lineage, routing, runtime limits, the seal) in one Details fold.
|
|
82
|
-
* Presentation only: the same hidden fields, nonce, digest and password
|
|
83
|
-
* post to the same route, and the task page and chat card share it.
|
|
84
|
-
*/
|
|
85
77
|
export declare function approvalSheetHtml(input: {
|
|
86
78
|
surface: "task" | "chat";
|
|
87
79
|
action: string;
|
|
@@ -103,7 +95,11 @@ export declare function approvalSheetHtml(input: {
|
|
|
103
95
|
label: string;
|
|
104
96
|
filedAgo: string | null;
|
|
105
97
|
} | null;
|
|
98
|
+
/** v126: where the work came from: an outside event's one line of context (never a term the approval agrees to). */
|
|
99
|
+
origin?: TaskOrigin | null;
|
|
106
100
|
deliverable: "branch" | "report";
|
|
101
|
+
/** The plan was rewritten after this build: the yes builds again to it (the approve POST requeues). */
|
|
102
|
+
rebuild?: number | null;
|
|
107
103
|
editHref: string;
|
|
108
104
|
notNowHref: string;
|
|
109
105
|
sticky: boolean;
|
|
@@ -121,6 +117,8 @@ export declare function approvalSheetHtml(input: {
|
|
|
121
117
|
open: boolean;
|
|
122
118
|
stepsHref: string | null;
|
|
123
119
|
} | null;
|
|
120
|
+
/** Cockpit B2: this person's password is remembered (when, ISO) and these terms may stand on it. */
|
|
121
|
+
freshSince?: string | null;
|
|
124
122
|
}): Html;
|
|
125
123
|
/** Earlier versions of a task still in flight, in plain words: queued
|
|
126
124
|
* while they only wait, running once one has started; null when none. */
|
|
@@ -233,6 +231,11 @@ export declare function agentsStripHtml(view: RouteView | null, taskId: string):
|
|
|
233
231
|
/** A ceremony nonce as stored: the sha256 hex of the value the form carried. */
|
|
234
232
|
export declare function nonceHashOf(value: string): string;
|
|
235
233
|
/** The approve POST's refusal, in words a person can act on. */
|
|
234
|
+
/** " (password remembered from 10:42)" when the approval stood on a remembered password or sign-in; nothing otherwise. */
|
|
235
|
+
export declare function approvalProofWords(proof: {
|
|
236
|
+
method: string;
|
|
237
|
+
at: string;
|
|
238
|
+
} | null | undefined): string;
|
|
236
239
|
export declare function approveRefusalWords(reason: string): string;
|
|
237
240
|
/** The browser's one-click approval binds not only the signed scope but the
|
|
238
241
|
* exact advisory plan revision shown beside it. The scope digest remains the
|
|
@@ -473,6 +476,8 @@ export declare function taskBodyParts(data: {
|
|
|
473
476
|
/** Immutable filing provenance (v12) — the approver sees which door
|
|
474
477
|
* filed this (console, cli, intake, template:<name>) at the yes. */
|
|
475
478
|
filedVia?: string | null;
|
|
479
|
+
/** v126: where the work came from — the flow and the outside event — in words; null for everything else. */
|
|
480
|
+
origin?: TaskOrigin | null;
|
|
476
481
|
/** Coordinator provenance when an agent filed this; null otherwise. */
|
|
477
482
|
coordinator?: {
|
|
478
483
|
label: string;
|
|
@@ -500,6 +505,23 @@ export declare function taskBodyParts(data: {
|
|
|
500
505
|
activity?: RunActivity | null;
|
|
501
506
|
/** Live steering: the Claude build that takes Pause right now, and its latest pause (null: none, or it continued). */
|
|
502
507
|
livePause?: LivePauseFact | null;
|
|
508
|
+
/** The running attempt's composer facts (steer-controls.ts), for this reader. */
|
|
509
|
+
steerComposer?: {
|
|
510
|
+
controls: BrowserAgentControls;
|
|
511
|
+
steer: {
|
|
512
|
+
action: string;
|
|
513
|
+
run: number;
|
|
514
|
+
} | null;
|
|
515
|
+
} | null;
|
|
516
|
+
/** This task's latest attempts, newest first (a tab's unsent draft for one that ended is offered on). */
|
|
517
|
+
steerRecent?: number[];
|
|
518
|
+
/** Cockpit B2: when this person's remembered password was given, when it may approve these terms. */
|
|
519
|
+
approvalFresh?: string | null;
|
|
520
|
+
/** Cockpit B2: how the current approval's person was proved (approval proved ledger), when it was a remembered one. */
|
|
521
|
+
approvalProof?: {
|
|
522
|
+
method: string;
|
|
523
|
+
at: string;
|
|
524
|
+
} | null;
|
|
503
525
|
/** Workers that are both alive and authorized for this task's project. */
|
|
504
526
|
worker?: {
|
|
505
527
|
answering: number;
|
|
@@ -583,6 +605,9 @@ export declare function taskBodyParts(data: {
|
|
|
583
605
|
steering?: SteerNote[];
|
|
584
606
|
/** A build's agent is running now and reads new notes when it next checks for them (v120). */
|
|
585
607
|
steeringLive?: boolean;
|
|
608
|
+
/** The running build a note from this page is bound to (cockpit §4): the exact attempt, so a stale page's note is
|
|
609
|
+
* refused rather than filed for whatever runs later. Null: no build reads notes now (the note waits for the next). */
|
|
610
|
+
steeringRun?: number | null;
|
|
586
611
|
/** The publication grant the publisher would act under — from
|
|
587
612
|
* publicationGrantFor(repo) only; null when none, or no project. */
|
|
588
613
|
grant?: PublicationGrant | null;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/** Task pages: approval, agents, plans, controls, decisions and the task body. */
|
|
2
|
-
import {
|
|
2
|
+
import { networkWords } from "../egress.js";
|
|
3
|
+
import { ACP_AGENTS, isAcpProfile } from "../acp-agents.js";
|
|
4
|
+
import { html, htmlString, joinHtml, postForm, replaceMarkup, reauth } from "../html.js";
|
|
3
5
|
import { closedQuestionReason, closedQuestionWords } from "../decision.js";
|
|
4
6
|
import {} from "../activity-line.js";
|
|
5
7
|
import {} from "../agentconfig.js";
|
|
@@ -43,6 +45,7 @@ import { reviewHref, taskChatHref, taskHref } from "./http.js";
|
|
|
43
45
|
import { coordinatorProposalsSection } from "./render-chat.js";
|
|
44
46
|
import { completionReceiptCard, criterionMatrixHtml, evidenceWords, homePhaseWords, incidentWords, needsCheck, pullRequestCardHtml, reasonWords, receiptStatusOf, repairChainHtml, reportItemsHtml, reviewRetryPanel, runNoun, runOutcomeBadge, semanticCoverageHtml, terminalDiffCard, verificationExplanation, verificationRecovered } from "./render-results.js";
|
|
45
47
|
import {} from "./session.js";
|
|
48
|
+
import { linkWords, originNote } from "../task-source.js";
|
|
46
49
|
export function contractChangeHtml(change) {
|
|
47
50
|
const tag = html `<span class="contract-change-kind contract-change-${change.kind}">${change.kind}</span>`;
|
|
48
51
|
switch (change.field) {
|
|
@@ -147,7 +150,8 @@ export function permissionWordsOf(profile) {
|
|
|
147
150
|
? profile.permissionArgv === "bypassPermissions" ? "Full access" : "Auto permissions"
|
|
148
151
|
: profile.provider === "gemini"
|
|
149
152
|
? profile.approvalArgv === "yolo" ? "Full access" : "Auto permissions"
|
|
150
|
-
: profile
|
|
153
|
+
: isAcpProfile(profile) ? "Full access"
|
|
154
|
+
: profile.sandboxMode === "danger-full-access" ? "Full access" : "Workspace sandbox";
|
|
151
155
|
}
|
|
152
156
|
/** One plain sentence for a revision (approval critique, Oct 2):
|
|
153
157
|
* "Fixes what build #9 missed: <criterion>." The notes, paths and lineage
|
|
@@ -200,6 +204,28 @@ const fragmentString = (fragment) => fragment === "" ? "" : htmlString(fragment)
|
|
|
200
204
|
* Presentation only: the same hidden fields, nonce, digest and password
|
|
201
205
|
* post to the same route, and the task page and chat card share it.
|
|
202
206
|
*/
|
|
207
|
+
/** v126: a task's origin as a line of words (the identity line). */
|
|
208
|
+
function originWords(origin) {
|
|
209
|
+
const flow = origin.flow === null ? null : origin.flow === "hidden" ? "from a flow" : origin.flow === "removed" ? "from a flow (removed)" : `from flow “${origin.flow.name}”`;
|
|
210
|
+
const source = origin.source === null ? null : `${origin.source.label} (${origin.source.proved})`;
|
|
211
|
+
return [flow, source].filter(one => one !== null).join(" · ");
|
|
212
|
+
}
|
|
213
|
+
/** v126: a task's origin as a fact: the flow, linked for those who may open it, and the outside event, linked to where
|
|
214
|
+
* it lives, with that link's host always shown. */
|
|
215
|
+
function originParts(origin) {
|
|
216
|
+
const parts = [];
|
|
217
|
+
if (origin.flow !== null)
|
|
218
|
+
parts.push(origin.flow === "hidden" ? "A flow" : origin.flow === "removed" ? "A flow (removed)" : { label: `Flow “${origin.flow.name}”`, href: origin.flow.href });
|
|
219
|
+
if (origin.source !== null) {
|
|
220
|
+
if (parts.length > 0)
|
|
221
|
+
parts.push(" · ");
|
|
222
|
+
// The link shows where it goes (host and path), beside what it is.
|
|
223
|
+
parts.push(origin.source.label, ` (${origin.source.proved})`);
|
|
224
|
+
if (origin.source.url !== null)
|
|
225
|
+
parts.push(" · ", { label: linkWords(origin.source.url), href: origin.source.url });
|
|
226
|
+
}
|
|
227
|
+
return parts;
|
|
228
|
+
}
|
|
203
229
|
export function approvalSheetHtml(input) {
|
|
204
230
|
const { scope, route } = input;
|
|
205
231
|
// A machine-drafted repair appends its brief to the signed goal; the row
|
|
@@ -261,10 +287,13 @@ export function approvalSheetHtml(input) {
|
|
|
261
287
|
allowing.length === 0 ? "" : html `<p class="approval-allowing" data-approval-allowing>You’re allowing: ${allowing.join(" · ")}</p>`,
|
|
262
288
|
yoursToCheck.length === 0 ? "" : html `<p class="approval-you-check" data-approval-you-check>You’ll check: ${yoursToCheck.join("; ")}</p>`,
|
|
263
289
|
]);
|
|
264
|
-
const
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
290
|
+
const rebuild = input.rebuild ?? null;
|
|
291
|
+
const after = rebuild !== null
|
|
292
|
+
? html `Build #${rebuild} was made to the earlier plan. Approving builds it again to this one.`
|
|
293
|
+
: input.deliverable === "report"
|
|
294
|
+
? html `An agent investigates without changing the repository. You'll hear when its report is ready.`
|
|
295
|
+
: html `An agent starts in its own branch. You'll hear when it's ready to review.`;
|
|
296
|
+
const submit = rebuild !== null ? html `Approve & build again` : html `Approve & start`;
|
|
268
297
|
// Everything else the digest binds, one tap away.
|
|
269
298
|
const detail = (title, body, attrs = html ``) => isEmptyHtml(body) ? html `` : html `<section class="approval-detail"${attrs}><h3>${title}</h3>${body}</section>`;
|
|
270
299
|
const revisionDetail = input.revision === null ? "" : detail("Earlier build", joinHtml([
|
|
@@ -366,6 +395,7 @@ export function approvalSheetHtml(input) {
|
|
|
366
395
|
sentence === null ? "" : html `<p class="approval-revision">${sentence}</p>`,
|
|
367
396
|
input.coordinator === null ? "" : html `<p class="approval-note">An agent filed this: <span class="mono">${input.coordinator.label}</span>${input.coordinator.filedAgo === null ? "" : html `, ${input.coordinator.filedAgo}`}. Nothing runs until you approve, and approving runs its request.</p>`,
|
|
368
397
|
input.deliverable === "report" ? html `<p class="approval-note">Read-only: it reports back and changes nothing in the repository.</p>` : "",
|
|
398
|
+
originNote(input.origin) === null ? "" : html `<p class="approval-note" data-approval-origin>${originNote(input.origin)}</p>`,
|
|
369
399
|
html `<dl class="approval-rows">`,
|
|
370
400
|
row("Goal", html `<p class="approval-goal">${goalShown}</p>`),
|
|
371
401
|
row("Changes", changes),
|
|
@@ -378,15 +408,16 @@ export function approvalSheetHtml(input) {
|
|
|
378
408
|
who.length === 0 ? "" : html `<p class="approval-who">${who.join(" · ")}</p>`,
|
|
379
409
|
consent,
|
|
380
410
|
html `<div class="approval-act" id="${input.surface === "task" ? "approval-confirm" : "chat-approval-confirm"}">`,
|
|
381
|
-
html `<label class="approval-password"><span class="visually-hidden">Your password</span><input type="password" name="token" autocomplete="current-password" placeholder="Your password" aria-describedby="${passwordNote}"></label
|
|
382
|
-
html `<p class="approval-password-note" id="${passwordNote}">Your password signs this approval.</p
|
|
411
|
+
html `${reauth(html `<label class="approval-password"><span class="visually-hidden">Your password</span><input type="password" name="token" autocomplete="current-password" placeholder="Your password" aria-describedby="${passwordNote}"></label>`)}`,
|
|
412
|
+
input.freshSince == null ? html `<p class="approval-password-note" id="${passwordNote}">Your password signs this approval.</p>`
|
|
413
|
+
: html `<p class="approval-password-note" id="${passwordNote}" data-approval-fresh>Your password from ${whenTime(input.freshSince)} is remembered on this computer — leave this blank to approve with it, or type it again.</p>`,
|
|
383
414
|
html `<button type="submit" data-primary-action>${submit}</button></div>`,
|
|
384
415
|
html `<p class="approval-after">${after}</p>`,
|
|
385
416
|
html `<div class="approval-secondary">${editor ?? html `<a class="approval-link" href="${input.editHref}">Edit plan</a>`}<a class="approval-link" href="${input.notNowHref}">Not now</a></div>`,
|
|
386
417
|
details,
|
|
387
418
|
]), {
|
|
388
419
|
attrs: { class: "approve-form approval-sheet", id: input.surface === "task" ? "approve" : null, "data-sticky": input.sticky },
|
|
389
|
-
hidden: { nonce: input.nonce, digest: input.digest },
|
|
420
|
+
hidden: { nonce: input.nonce, digest: input.digest, ...(rebuild === null ? {} : { rebuild: String(rebuild) }) },
|
|
390
421
|
returnTo: input.returnTo,
|
|
391
422
|
}),
|
|
392
423
|
editorForm,
|
|
@@ -413,7 +444,8 @@ export function permissionModeOfProfile(profile) {
|
|
|
413
444
|
? profile.permissionArgv === "bypassPermissions" ? "bypassPermissions" : "auto"
|
|
414
445
|
: profile.provider === "gemini"
|
|
415
446
|
? profile.approvalArgv === "yolo" ? "bypassPermissions" : "auto"
|
|
416
|
-
: profile
|
|
447
|
+
: isAcpProfile(profile) ? "bypassPermissions"
|
|
448
|
+
: profile.sandboxMode === "danger-full-access" ? "bypassPermissions" : "auto";
|
|
417
449
|
}
|
|
418
450
|
/** Done when, from the in-place editor: each line keeps its requirement's
|
|
419
451
|
* id by position, and its evidence and guidance while its words stand; a
|
|
@@ -505,8 +537,11 @@ export function profileWords(scope) {
|
|
|
505
537
|
: "legacy acceptEdits; edits proceed, commands that ask are denied unattended"}, stops after ${profile.maxTurns} turns, ${Math.round(profile.timeoutSeconds / 60)} min ${profile.timeoutKind === "idle" ? "without progress" : "per attempt"}; repairs on ${repair}, ${profile.repairMaxTurns} turns / ${Math.round(profile.repairTimeoutSeconds / 60)} min</p>`
|
|
506
538
|
: profile.provider === "gemini"
|
|
507
539
|
? html `<p class="meta">Runs on <span class="mono">gemini · ${profile.model}</span> — ${profile.approvalArgv === "yolo" ? "Full access via --approval-mode yolo; every tool auto-approved" : "Auto via --approval-mode auto_edit; edits auto-approved, other tools refused"}, no turn limit (${Math.round(profile.timeoutSeconds / 60)} min ${profile.timeoutKind === "idle" ? "without progress" : "per attempt"}), spend reported in tokens only; repairs on ${repair}, ${Math.round(profile.repairTimeoutSeconds / 60)} min</p>`
|
|
508
|
-
:
|
|
509
|
-
|
|
540
|
+
: isAcpProfile(profile)
|
|
541
|
+
? html `<p class="meta">Runs on <span class="mono">${ACP_AGENTS[profile.provider].name} (via ACP) · ${profile.model}</span> — full access inside the OS fence; the agent runs any tool it chooses and nothing asks. No turn limit: stops after ${Math.round(profile.timeoutSeconds / 60)} min, or ${Math.round(profile.idleTimeoutSeconds / 60)} min silent; repairs on ${repair}, ${Math.round(profile.repairTimeoutSeconds / 60)} min, or ${Math.round(profile.repairIdleTimeoutSeconds / 60)} min silent.</p>`
|
|
542
|
+
: html `<p class="meta">Runs on <span class="mono">${profile.provider} · ${profile.model}</span> — ${profile.sandboxMode === "danger-full-access" ? "FULL permissions via --dangerously-bypass-approvals-and-sandbox; nothing asks" : "workspace-write sandbox"}, no turn limit (${Math.round(profile.timeoutSeconds / 60)} min ${profile.timeoutKind === "idle" ? "without progress" : "per attempt"}); repairs on ${repair}, ${Math.round(profile.repairTimeoutSeconds / 60)} min</p>`;
|
|
543
|
+
// What the build may reach is part of what is approved (egress.ts): said on every approval form.
|
|
544
|
+
return html `${base}<p class="meta" data-scope-network>${networkWords(profile.network ?? null)}</p>`;
|
|
510
545
|
}
|
|
511
546
|
export const ROLE_NOUN = { plan: "Planner", build: "Builder", repair: "Repair", review: "Reviewer" };
|
|
512
547
|
export function agentsStandingWords(view) {
|
|
@@ -706,6 +741,21 @@ export function nonceHashOf(value) {
|
|
|
706
741
|
return createHash("sha256").update(value).digest("hex");
|
|
707
742
|
}
|
|
708
743
|
/** The approve POST's refusal, in words a person can act on. */
|
|
744
|
+
/** " (password remembered from 10:42)" when the approval stood on a remembered password or sign-in; nothing otherwise. */
|
|
745
|
+
export function approvalProofWords(proof) {
|
|
746
|
+
if (proof == null)
|
|
747
|
+
return "";
|
|
748
|
+
if (proof.method === "fresh-password")
|
|
749
|
+
return ` (password remembered from ${whenText(proof.at)})`;
|
|
750
|
+
if (proof.method === "fresh-sso")
|
|
751
|
+
return ` (sign-in remembered from ${whenText(proof.at)})`;
|
|
752
|
+
if (proof.method === "session")
|
|
753
|
+
return " (passwordless: your signed-in session)";
|
|
754
|
+
if (proof.method === "cli-login")
|
|
755
|
+
return " (passwordless: this computer's remembered login)";
|
|
756
|
+
return "";
|
|
757
|
+
}
|
|
758
|
+
const whenText = (iso) => new Intl.DateTimeFormat("en-US", { hour: "numeric", minute: "2-digit" }).format(new Date(iso));
|
|
709
759
|
export function approveRefusalWords(reason) {
|
|
710
760
|
if (reason === "requester" || reason === "person-required")
|
|
711
761
|
return gateWords({ verdict: "refuse", reason });
|
|
@@ -713,6 +763,8 @@ export function approveRefusalWords(reason) {
|
|
|
713
763
|
return "not approved: this scope predates agent routing and its old approval no longer stands — edit and re-file the scope so it is routed under today’s agents, then approve it";
|
|
714
764
|
if (reason === "profile-unresolved")
|
|
715
765
|
return "not approved: the scope cannot name an exact agent for every role — fix the agent setup and re-file it";
|
|
766
|
+
if (reason === "password-now")
|
|
767
|
+
return "not approved: this needs your password typed now — protected work, raised permissions, or a plan an agent wrote can't use a remembered one";
|
|
716
768
|
return `not approved: ${reason}`;
|
|
717
769
|
}
|
|
718
770
|
/** The browser's one-click approval binds not only the signed scope but the
|
|
@@ -897,7 +949,7 @@ export function resumeCeremonyPage(chrome, data) {
|
|
|
897
949
|
data.gate === null ? "" : html `<p class="row"><strong>Before work starts:</strong> ${data.gate.summary} — ${data.gate.detail}</p>`,
|
|
898
950
|
html `</div>`,
|
|
899
951
|
postForm(`${taskHref(data.taskId)}/resume`, joinHtml([
|
|
900
|
-
html `<label>Confirm with your password<input type="password" name="token" autocomplete="current-password"></label
|
|
952
|
+
html `${reauth(html `<label>Confirm with your password<input type="password" name="token" autocomplete="current-password"></label>`)}`,
|
|
901
953
|
html `<button type="submit">Resume task</button>`,
|
|
902
954
|
], "\n"), { attrs: { class: "card resume-form" }, returnTo: data.returnTo, hidden: { nonce: data.nonceValue, run: control.run } }),
|
|
903
955
|
back,
|
|
@@ -1067,7 +1119,7 @@ export function planRevisionLedgerHtml(ledger, taskId, csrf) {
|
|
|
1067
1119
|
: joinHtml([
|
|
1068
1120
|
postForm(`${taskHref(taskId)}/accept-revision`, joinHtml([
|
|
1069
1121
|
pendingRevision.authorityKind === "authority-change"
|
|
1070
|
-
? html `<input type="password" name="token" placeholder="approval password" required autocomplete="current-password">`
|
|
1122
|
+
? html `${reauth(html `<input type="password" name="token" placeholder="approval password" required autocomplete="current-password">`)}`
|
|
1071
1123
|
: "",
|
|
1072
1124
|
html `<button type="submit">${pendingRevision.authorityKind === "authority-change" ? html `Approve changes & continue` : html `Use revised plan & continue`}</button>`,
|
|
1073
1125
|
]), { attrs: { class: "inline" }, hidden: { "revision-id": pendingRevision.id } }),
|
|
@@ -1399,7 +1451,7 @@ export function taskBodyParts(data) {
|
|
|
1399
1451
|
const steerForm = data.csrf === "" || task.state === "done" || task.state === "cancelled"
|
|
1400
1452
|
? ""
|
|
1401
1453
|
: joinHtml([
|
|
1402
|
-
postForm(`${taskHref(task.id)}/steer`, html `<input type="text" name="note" placeholder="guidance for the agent" aria-label="steering note" style="width:100%;max-width:28rem"><button type="submit"
|
|
1454
|
+
postForm(`${taskHref(task.id)}/steer`, html `<input type="text" name="note" placeholder="guidance for the agent" aria-label="steering note" style="width:100%;max-width:28rem">${data.steeringRun == null ? "" : html `<input type="hidden" name="run" value="${String(data.steeringRun)}"><input type="hidden" name="key" value="${randomUUID()}"><input type="hidden" name="return" value="task">`}<button type="submit">${data.steeringRun == null ? "Save for the next attempt" : "Steer"}</button>`, { attrs: { class: "row" } }),
|
|
1403
1455
|
html `<p class="meta">${steerDestinationWords(steeringLive)} A note can't widen the approved scope.</p>`,
|
|
1404
1456
|
]);
|
|
1405
1457
|
const steeringCard = steerRows === "" && steerForm === "" ? "" : html `<h2>Steering</h2>${steerRows}${steerForm}`;
|
|
@@ -1425,7 +1477,7 @@ export function taskBodyParts(data) {
|
|
|
1425
1477
|
html `<p><strong>Quality</strong> ${qualityModeTitle(scope.qualityMode ?? "default")}</p>`,
|
|
1426
1478
|
acceptanceCeremonyHtml(scope.acceptance),
|
|
1427
1479
|
approval.approved
|
|
1428
|
-
? html `<p class="meta scope-seal">Approved by ${approval.by} · ${whenTime(approval.at)} · <span class="seal">signs ${shortDigest(scope.digest)}</span><span class="so-sr-only"> — approval binds to this exact wording</span></p>`
|
|
1480
|
+
? html `<p class="meta scope-seal">Approved by ${approval.by}${approvalProofWords(data.approvalProof)} · ${whenTime(approval.at)} · <span class="seal">signs ${shortDigest(scope.digest)}</span><span class="so-sr-only"> — approval binds to this exact wording</span></p>`
|
|
1429
1481
|
: html `<p class="meta"><span class="seal">signs ${shortDigest(scope.digest)}</span> — approval binds to this exact wording</p><p class="meta">Not approved${approval.reason === "changed" ? " — approved once, then rewritten" : ""}</p>`,
|
|
1430
1482
|
html `</div>`,
|
|
1431
1483
|
], "\n");
|
|
@@ -1533,6 +1585,10 @@ export function taskBodyParts(data) {
|
|
|
1533
1585
|
const revisionInApproval = scope !== null && !approval.approved && data.plan !== "requested" &&
|
|
1534
1586
|
scope.profileState !== "unresolved" && consentDoor.open && data.dispatch?.action !== "repair-dependency" &&
|
|
1535
1587
|
(data.revision == null || !("problem" in data.revision));
|
|
1588
|
+
// The approval is the next step when dispatch waits on it, or when the plan was rewritten after a build (the
|
|
1589
|
+
// assignment's one action): then it is shown open under the status, never folded.
|
|
1590
|
+
const approvalLeads = data.dispatch?.action === "approve-scope" ||
|
|
1591
|
+
(data.assignment?.primaryAction?.code === "approve-scope" && data.assignment.primaryAction.target.taskId === task.id);
|
|
1536
1592
|
const approveForm = scope === null || approval.approved || data.plan === "requested"
|
|
1537
1593
|
? ""
|
|
1538
1594
|
: data.revision !== null && data.revision !== undefined && "problem" in data.revision
|
|
@@ -1547,6 +1603,7 @@ export function taskBodyParts(data) {
|
|
|
1547
1603
|
csrf: data.csrf,
|
|
1548
1604
|
nonce: data.nonce,
|
|
1549
1605
|
digest: data.approvalDigest ?? scope.digest,
|
|
1606
|
+
freshSince: data.approvalFresh ?? null,
|
|
1550
1607
|
returnTo: null,
|
|
1551
1608
|
scope,
|
|
1552
1609
|
planDocument: data.plan === "drafted" ? data.planDocument : null,
|
|
@@ -1556,10 +1613,12 @@ export function taskBodyParts(data) {
|
|
|
1556
1613
|
repairChain: data.repairChain ?? null,
|
|
1557
1614
|
route: data.route,
|
|
1558
1615
|
coordinator: data.coordinator ?? null,
|
|
1616
|
+
origin: data.origin ?? null,
|
|
1559
1617
|
deliverable: data.deliverable ?? "branch",
|
|
1618
|
+
rebuild: data.assignment?.need != null && "key" in data.assignment.need && data.assignment.need.key === "replan" ? data.assignment.need.build : null,
|
|
1560
1619
|
editHref: data.csrf !== "" && data.planSha != null && data.planDocument !== null ? "#plan-edit" : "#scope",
|
|
1561
1620
|
notNowHref: "/work",
|
|
1562
|
-
sticky:
|
|
1621
|
+
sticky: approvalLeads,
|
|
1563
1622
|
earlier: { active: data.assignment?.earlierActive ?? 0, running: data.assignment?.earlierRunning ?? 0 },
|
|
1564
1623
|
edit: data.csrf === "" ? null
|
|
1565
1624
|
: { action: `${taskHref(task.id)}/scope`, draft: inlineScopeDraft ? data.scopeDraft ?? null : null, problem: inlineScopeDraft ? data.problem : null,
|
|
@@ -1711,7 +1770,7 @@ export function taskBodyParts(data) {
|
|
|
1711
1770
|
const scopeRow = scope === null
|
|
1712
1771
|
? prop("scope", "none yet")
|
|
1713
1772
|
: approval.approved
|
|
1714
|
-
? prop("approved scope", html `<span class="seal">signs ${shortDigest(scope.digest)}</span> · ${qualityModeTitle(scope.qualityMode ?? "default")} · approved by ${approval.by} · ${whenTime(approval.at)}`)
|
|
1773
|
+
? prop("approved scope", html `<span class="seal">signs ${shortDigest(scope.digest)}</span> · ${qualityModeTitle(scope.qualityMode ?? "default")} · approved by ${approval.by}${approvalProofWords(data.approvalProof)} · ${whenTime(approval.at)}`)
|
|
1715
1774
|
: prop("scope", approval.reason === "changed" ? "rewritten since its approval — needs a new yes" : "not approved");
|
|
1716
1775
|
const strikesRow = data.strikes > 0 ? prop("strikes", `${data.strikes} failed attempt(s)`) : "";
|
|
1717
1776
|
const propsCard = html `<div class="card props">${workerRow}${queueRow}${scopeRow}${publishesRow}${economics}${strikesRow}</div>`;
|
|
@@ -1727,7 +1786,7 @@ export function taskBodyParts(data) {
|
|
|
1727
1786
|
facts.push({ label: "Queue", parts: [`${data.position.position} of ${data.position.total}${data.position.column === null ? " in the shared queue" : ` in ${data.position.column}'s queue`} · `, { label: "Reorder", href: "/board?view=order" }] });
|
|
1728
1787
|
}
|
|
1729
1788
|
facts.push(scope === null ? { label: "Scope", parts: ["none yet"] }
|
|
1730
|
-
: approval.approved ? { label: "Approved scope", parts: [{ seal: `signs ${scope.digest.length <= 12 ? scope.digest : `${scope.digest.slice(0, 12)}…`}` }, ` · ${qualityModeTitle(scope.qualityMode ?? "default")} · approved by ${approval.by}`, ...(approval.at === null ? [] : [" · ", { at: approval.at }])] }
|
|
1789
|
+
: approval.approved ? { label: "Approved scope", parts: [{ seal: `signs ${scope.digest.length <= 12 ? scope.digest : `${scope.digest.slice(0, 12)}…`}` }, ` · ${qualityModeTitle(scope.qualityMode ?? "default")} · approved by ${approval.by}${approvalProofWords(data.approvalProof)}`, ...(approval.at === null ? [] : [" · ", { at: approval.at }])] }
|
|
1731
1790
|
: { label: "Scope", parts: [approval.reason === "changed" ? "rewritten since its approval — needs a new yes" : "not approved"] });
|
|
1732
1791
|
facts.push({ label: "Publishes as", parts: [publishesAs] });
|
|
1733
1792
|
// v102: who asked for it, and what the project's approval rules need.
|
|
@@ -1893,20 +1952,22 @@ export function taskBodyParts(data) {
|
|
|
1893
1952
|
// status and property rail, and approval provenance stays in the ceremony.
|
|
1894
1953
|
const identity = html `<p class="meta task-identity">Task ID <span class="mono">${task.id}</span>${data.rootTitle !== undefined && data.rootTitle !== task.title ? ` · Execution: ${task.title}` : ""}${data.repo === null ? "" : ` · ${projectName(data.repo)}`}${data.coordinator !== null && data.coordinator !== undefined
|
|
1895
1954
|
? html ` · filed by <span class="mono">${data.coordinator.label}</span>${data.coordinator.filedAgo === null ? "" : ` ${data.coordinator.filedAgo}`}`
|
|
1896
|
-
: data.
|
|
1897
|
-
?
|
|
1898
|
-
:
|
|
1955
|
+
: data.origin != null
|
|
1956
|
+
? ` · ${originWords(data.origin)}`
|
|
1957
|
+
: data.filedVia === null || data.filedVia === undefined
|
|
1958
|
+
? ""
|
|
1959
|
+
: ` · filed via ${data.filedVia}`}${data.deliverable === "report" ? html ` · <span class="badge">Scout</span>` : ""}</p>`;
|
|
1899
1960
|
// A pull request that can be merged (or opened) owns the one primary action; the result stays in its section.
|
|
1900
1961
|
const pullRequestActs = data.csrf !== "" && (data.pullRequest?.view?.canMerge === true || (data.pullRequest?.view == null && data.pullRequest?.offer != null));
|
|
1901
1962
|
const pullRequestFact = data.pullRequest?.fact != null && data.pullRequest.view?.runId === data.assignment?.receipt?.runId ? data.pullRequest.fact : undefined;
|
|
1902
|
-
const assignmentOptions = data.assignment == null ? null : { workStatus: status, hideAction: (approveForm !== "" &&
|
|
1963
|
+
const assignmentOptions = data.assignment == null ? null : { workStatus: status, hideAction: (approveForm !== "" && approvalLeads) || pullRequestActs, problem: status.tone === "problem",
|
|
1903
1964
|
planning: data.dispatch?.code === "running" && data.dispatch.role === "planner", ...(pullRequestFact === undefined ? {} : { pullRequest: pullRequestFact }),
|
|
1904
1965
|
diagnostics: [...(status.diagnostics ?? []), ...(status.tone === "problem" && status.detail !== data.assignment.detail ? [status] : [])] };
|
|
1905
1966
|
// Say it once: a pull request that couldn't open, or merged, is the status
|
|
1906
1967
|
// card's own row (its reason or merge commit under Details), not a second card.
|
|
1907
1968
|
const pullRequestCard = data.pullRequest == null || (pullRequestFact !== undefined && (data.pullRequest.view?.state === "failed" || data.pullRequest.view?.state === "merged")) ? "" : pullRequestCardHtml(data.pullRequest, data.csrf);
|
|
1908
1969
|
// The result takes over from the task status as soon as it is ready.
|
|
1909
|
-
const statusHtml = html `${data.assignment != null && assignmentOptions !== null ? assignmentSummaryHtml(data.assignment, assignmentOptions) : receiptLeads ? completionReceiptCard(data.completion.receipt, task.id, "task", status) : taskStatusCard(status, task.id, data.dispatch ?? null, liveRunId, approveForm !== "" &&
|
|
1970
|
+
const statusHtml = html `${data.assignment != null && assignmentOptions !== null ? assignmentSummaryHtml(data.assignment, assignmentOptions) : receiptLeads ? completionReceiptCard(data.completion.receipt, task.id, "task", status) : taskStatusCard(status, task.id, data.dispatch ?? null, liveRunId, approveForm !== "" && approvalLeads)}${checkProgressHtml(data.checkProgress ?? null)}`;
|
|
1910
1971
|
// The exact-run control (v52), directly under the scheduler's answer:
|
|
1911
1972
|
// the one place a person stops or resumes THIS attempt.
|
|
1912
1973
|
const controlHtml = taskControlDetailsHtml(data.control ?? { kind: "none" }, task.id, data.csrf, "task", false, false, data.livePause ?? null);
|
|
@@ -1939,7 +2000,7 @@ export function taskBodyParts(data) {
|
|
|
1939
2000
|
return joinHtml([
|
|
1940
2001
|
html `<div class="card"><p><strong>External work</strong> <span class="meta">${link} · ${state}</span></p>`,
|
|
1941
2002
|
reopenable
|
|
1942
|
-
? postForm(`${taskHref(task.id)}/reopen`, html `<input type="password" name="token" placeholder="your password" aria-label="your password" autocomplete="current-password"
|
|
2003
|
+
? postForm(`${taskHref(task.id)}/reopen`, html `${reauth(html `<input type="password" name="token" placeholder="your password" aria-label="your password" autocomplete="current-password">`)}<button type="submit">Reopen — the approved scope stands</button>`, { attrs: { class: "row" } })
|
|
1943
2004
|
: "",
|
|
1944
2005
|
html `</div>`,
|
|
1945
2006
|
]);
|
|
@@ -1956,7 +2017,7 @@ export function taskBodyParts(data) {
|
|
|
1956
2017
|
? html `<div class="card"><p><strong>This task is waiting on you: an agent filed it, and it has no scope.</strong></p><p class="meta">Filed by <span class="mono">${data.coordinator.label}</span> — nothing plans, claims, or runs until you write a scope below and sign it. Your signature runs their request.</p></div>`
|
|
1957
2018
|
: html `<div class="card task-scope-needed"><p><strong>No approved scope yet</strong></p><p class="meta"><strong>Plan first</strong> drafts it from the repository, or <a href="#scope">write it yourself</a>.</p></div>`
|
|
1958
2019
|
: "";
|
|
1959
|
-
const approvalHtml = dependencyChoiceNeeded || approveForm === "" ? "" :
|
|
2020
|
+
const approvalHtml = dependencyChoiceNeeded || approveForm === "" ? "" : approvalLeads
|
|
1960
2021
|
? html `<section class="task-plan-review" aria-label="Approve the plan">${approveForm}</section>`
|
|
1961
2022
|
: html `<details class="task-secondary-approval"><summary>Updated approval terms</summary>${approveForm}</details>`;
|
|
1962
2023
|
const optionsHtml = html `${identity}${dispatchStatus}${dependencyChoiceNeeded ? "" : actsBar}`;
|
|
@@ -2145,7 +2206,10 @@ export function taskBodyParts(data) {
|
|
|
2145
2206
|
review.push({ label: "Publishes as", parts: [publishesAs] });
|
|
2146
2207
|
const about = [];
|
|
2147
2208
|
const filedFact = facts.find(one => one.label === "Filed by");
|
|
2148
|
-
about.push(filedFact ?? { label: "Filed by", parts: [filedBy ?? (data.filedVia == null ? "Not recorded" : `via ${data.filedVia}`)] });
|
|
2209
|
+
about.push(filedFact ?? { label: "Filed by", parts: [filedBy ?? (data.origin != null ? "An automation" : data.filedVia == null ? "Not recorded" : `via ${data.filedVia}`)] });
|
|
2210
|
+
// v126: where it came from — the flow (linked only for those who can see it) and the outside event, with its host.
|
|
2211
|
+
if (data.origin != null)
|
|
2212
|
+
about.push({ label: "From", parts: originParts(data.origin) });
|
|
2149
2213
|
about.push({ label: "Filed", parts: [{ at: rootFiled }] });
|
|
2150
2214
|
about.push({ label: "Updated", parts: [{ at: task.updatedAt }] });
|
|
2151
2215
|
for (const label of ["Audit", "This attempt", "Task total"]) {
|
|
@@ -2204,6 +2268,21 @@ export function taskBodyParts(data) {
|
|
|
2204
2268
|
attempts: [...earlierStopped].sort((a, b) => a.id - b.id).map(run => ({ label: `${runNoun(run)[0].toUpperCase()}${runNoun(run).slice(1)} #${run.id}`, href: `/r/${run.id}`,
|
|
2205
2269
|
text: run.outcome === null ? "Never finished." : run.outcome === "failed" ? failedAttemptSentence(run.reason) : run.reason === null ? null : (words => `${words.charAt(0).toUpperCase()}${words.slice(1)}.`)(reasonWords(run.reason)) })),
|
|
2206
2270
|
};
|
|
2271
|
+
// ⋯ More actions (docs/plans/one-page-task-and-agent.md): each secondary act once, in one place — Work, Share & reuse,
|
|
2272
|
+
// then Danger last. A ceremony is never cloned here: its item goes to the tab that holds its one form.
|
|
2273
|
+
const sectionIds = new Set(sectionParts.map(one => one.id));
|
|
2274
|
+
const rootOf = data.rootId ?? task.id;
|
|
2275
|
+
const more = [
|
|
2276
|
+
...(runChecks !== null && data.csrf !== "" ? [{ group: "work", label: "Run checks", kind: "post", action: runChecks.action, fields: { level: runChecks.level, return: runChecks.returnTo } }] : []),
|
|
2277
|
+
...(sectionIds.has("scope") && data.csrf !== "" ? [{ group: "work", label: approval.approved || finished ? "Plan and agents" : "Edit plan", kind: "goto", tab: "plan", target: "scope" }] : []),
|
|
2278
|
+
...(sectionIds.has("waits-for") ? [{ group: "work", label: "Dependencies", kind: "goto", tab: "plan", target: "waits-for" }] : []),
|
|
2279
|
+
...(sectionIds.has("holds") ? [{ group: "work", label: "Holds", kind: "goto", tab: "plan", target: "holds" }] : []),
|
|
2280
|
+
...(data.csrf !== "" ? [{ group: "work", label: "Task options", kind: "goto", tab: "plan", target: "task-diagnostics" }] : []),
|
|
2281
|
+
{ group: "share", label: "Copy link", kind: "copy" },
|
|
2282
|
+
...(facts.some(one => one.label === "Audit") ? [{ group: "share", label: "Evidence pack", kind: "link", href: `${taskHref(rootOf)}/evidence` }] : []),
|
|
2283
|
+
...(data.repo !== null && data.scope !== null ? [{ group: "share", label: "Reuse as recipe", kind: "link", href: `/recipes/from-task?task=${encodeURIComponent(task.id)}` }] : []),
|
|
2284
|
+
...(cancelForm !== "" ? [{ group: "danger", label: "Cancel task", kind: "goto", tab: "plan", target: "cancel-task" }] : []),
|
|
2285
|
+
];
|
|
2207
2286
|
const view = {
|
|
2208
2287
|
kind: "task",
|
|
2209
2288
|
id: task.id,
|
|
@@ -2227,9 +2306,13 @@ export function taskBodyParts(data) {
|
|
|
2227
2306
|
activity: liveRun === undefined ? null : data.activity ?? null,
|
|
2228
2307
|
stop,
|
|
2229
2308
|
pause,
|
|
2309
|
+
steering: data.csrf !== "" ? data.steerComposer ?? null : null,
|
|
2310
|
+
...(data.csrf !== "" && (data.steerRecent?.length ?? 0) > 0 ? { steerRecent: data.steerRecent } : {}),
|
|
2230
2311
|
record,
|
|
2231
2312
|
earlier,
|
|
2232
2313
|
approval: fragmentString(approvalHtml),
|
|
2314
|
+
approvalPlacement: approvalLeads ? "lead" : "plan",
|
|
2315
|
+
more,
|
|
2233
2316
|
confirmStopped: data.csrf !== "" && data.assignment?.primaryAction?.code === "confirm-stopped" && data.assignment.primaryAction.target.runId !== null
|
|
2234
2317
|
? { action: `${taskHref(data.assignment.rootId)}/confirm-stopped`, run: data.assignment.primaryAction.target.runId, checked: needsCheck(data.assignment) } : null,
|
|
2235
2318
|
rebuild,
|
|
@@ -33,6 +33,8 @@ export type RequestFacts = {
|
|
|
33
33
|
expiresAt: number;
|
|
34
34
|
etag: string;
|
|
35
35
|
};
|
|
36
|
+
/** Passwordless is on and this is a signed-in browser: ceremony password fields render as nothing (html.ts reauth). */
|
|
37
|
+
passwordless?: boolean;
|
|
36
38
|
};
|
|
37
39
|
/**
|
|
38
40
|
* The request's own session facts, readable from anywhere below the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/** What one console request knows about itself, readable anywhere below its handler. */
|
|
2
2
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
3
|
-
import { provideFormToken } from "../html.js";
|
|
3
|
+
import { provideFormToken, providePasswordless } from "../html.js";
|
|
4
4
|
/**
|
|
5
5
|
* The request's own session facts, readable from anywhere below the
|
|
6
6
|
* dispatcher without threading them through forty call sites: the csrf
|
|
@@ -10,6 +10,7 @@ import { provideFormToken } from "../html.js";
|
|
|
10
10
|
*/
|
|
11
11
|
export const requestContext = new AsyncLocalStorage();
|
|
12
12
|
provideFormToken(() => requestContext.getStore()?.csrf);
|
|
13
|
+
providePasswordless(() => requestContext.getStore()?.passwordless === true);
|
|
13
14
|
/** Run a render outside a live request (a test, a background render) as if a browser session with this token asked. */
|
|
14
15
|
export function withFormToken(csrf, render) {
|
|
15
16
|
const facts = requestContext.getStore();
|
|
@@ -83,6 +83,9 @@ export interface RouteDeclaration {
|
|
|
83
83
|
readonly roleRefusal?: RouteRefusal;
|
|
84
84
|
/** The largest form body a POST here reads (else the console's default). */
|
|
85
85
|
readonly bodyCap?: number;
|
|
86
|
+
/** Cockpit B2: whether a password remembered on this session may stand in here (`allowlist`), or never. Only the
|
|
87
|
+
* allowlisted acts run their check inside `withFreshness` (scope.ts); every other step-up is `never`. */
|
|
88
|
+
readonly freshness: "never" | "allowlist";
|
|
86
89
|
}
|
|
87
90
|
/** The sole route table, in match order. */
|
|
88
91
|
export declare const ROUTES: readonly RouteDeclaration[];
|