toolroll 0.9.63 → 0.9.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/README.md +15 -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 +50 -2
- package/dist/agent-fence.js +157 -10
- 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 +235 -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 +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 +12 -4
- package/dist/contracts/console-api.js +12 -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 +17 -0
- package/dist/invoke.js +217 -21
- 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 +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-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 +2 -0
- package/dist/operate.js +275 -17
- 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 +12 -0
- package/dist/project-delete-ui.js +41 -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.d.ts +3 -0
- package/dist/release.js +14 -8
- 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 +170 -5
- 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 +247 -40
- 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 +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 +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 +46 -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 +121 -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 +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-ui.js +4 -4
- package/dist/store-baseline.d.ts +1 -1
- package/dist/store-baseline.js +1 -1
- package/dist/store.d.ts +430 -15
- package/dist/store.js +1041 -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/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 +2 -0
- package/dist/tool-broker.js +1 -0
- package/dist/toolroll-update-ui.js +2 -2
- package/dist/toolroll-update.js +13 -3
- package/dist/tools-ui.js +2 -2
- 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/package.json +11 -2
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A lead sweep's table (docs/plans/lead-fan-out.md): every child with its state, its verdict and its result, read from
|
|
3
|
+
* facts on each look (the page follows the console's live beat). The only sweep-wide act is "cancel the rest"; steer,
|
|
4
|
+
* cancel or retry one child is that task's own page.
|
|
5
|
+
*/
|
|
6
|
+
import { CONSOLE_FORMS, readForm } from "../contracts/console-api.js";
|
|
7
|
+
import { html, postForm } from "../html.js";
|
|
8
|
+
import { cancelSweepRest, sweepLine, sweepOpen, sweepOpenDigest, sweepTable } from "../lead-sweep.js";
|
|
9
|
+
import { refuse, screen } from "./chrome.js";
|
|
10
|
+
import { handlersOf } from "./handler-registry.js";
|
|
11
|
+
import { redirect } from "./http.js";
|
|
12
|
+
const SWEEP_PATH = /^\/sweeps\/([1-9][0-9]{0,9})(?:\/cancel-rest)?$/;
|
|
13
|
+
const STATE_WORDS = {
|
|
14
|
+
working: "Working", checking: "Checking", "needs-decision": "Needs you", "ready-to-check": "Ready", complete: "Complete", cancelled: "Cancelled", missing: "Gone",
|
|
15
|
+
};
|
|
16
|
+
export function createSweepHandlers(runtime) {
|
|
17
|
+
const { store, clock, sendScreen, chromeFor, evidenceRoot, consoleProjects, liveRefreshSeconds } = runtime;
|
|
18
|
+
const readable = () => runtime.workAccess().repos ?? consoleProjects();
|
|
19
|
+
async function page(ctx) {
|
|
20
|
+
const { url, who, response } = ctx;
|
|
21
|
+
const id = Number(SWEEP_PATH.exec(url.pathname)?.[1]);
|
|
22
|
+
const table = sweepTable(store, id, clock(), readable(), evidenceRoot);
|
|
23
|
+
if (table === null)
|
|
24
|
+
return refuse(response, who, 404, "There's no sweep at this address you can see.", "/chat");
|
|
25
|
+
const said = url.searchParams.get("said");
|
|
26
|
+
const rows = table.rows.map(row => html `<tr data-sweep-row="${row.ordinal}">
|
|
27
|
+
<td>${row.ordinal + 1}</td>
|
|
28
|
+
<td><a href="/t/${encodeURIComponent(row.task)}">${row.label}</a></td>
|
|
29
|
+
<td><span class="chip">${STATE_WORDS[row.state]}</span></td>
|
|
30
|
+
<td>${row.verdict === null ? html `<span class="meta">—</span>` : html `<strong>${row.verdict.verdict}</strong> <span class="meta">${row.verdict.why}</span>`}</td>
|
|
31
|
+
<td>${row.result === null ? "" : html `<a href="/t/${encodeURIComponent(row.result.taskId)}">Result →</a>`}</td>
|
|
32
|
+
</tr>`);
|
|
33
|
+
// The form names exactly what it would act on (each item's active task, state and attempt): a change is refused.
|
|
34
|
+
const open = sweepOpen(store, table, clock());
|
|
35
|
+
const running = open.filter(one => one.run !== null).length;
|
|
36
|
+
const cancel = who.role !== "approver" || open.length === 0 ? "" : html `<details class="card"><summary>Cancel the rest (${open.length})</summary>${postForm(`/sweeps/${id}/cancel-rest`, html `<p>Cancels ${open.length - running} unfinished item${open.length - running === 1 ? "" : "s"}${running === 0 ? "" : ` and stops ${running} running build${running === 1 ? "" : "s"}`}: ${open.map(one => one.label).join(", ")}. Finished results stay.</p><label class="arm"><input type="checkbox" name="confirm" value="yes" required> Cancel the rest</label><button class="danger">Cancel the rest</button>`, { hidden: { snapshot: sweepOpenDigest(open) } })}</details>`;
|
|
37
|
+
const body = html `<h1>${table.title}</h1>${said === null ? "" : html `<p role="status">${said}</p>`}
|
|
38
|
+
<p class="meta">${sweepLine(table)} · at most ${table.maxParallel} at once · each item is its own task in its own worktree</p>
|
|
39
|
+
<table class="sweep-table"><thead><tr><th>#</th><th>Item</th><th>State</th><th>Verdict</th><th></th></tr></thead><tbody>${rows}</tbody></table>${cancel}`;
|
|
40
|
+
return sendScreen(response, 200, screen(table.title, body, { chrome: chromeFor(table.repo, "work"), refreshSeconds: liveRefreshSeconds() }));
|
|
41
|
+
}
|
|
42
|
+
async function cancelRest(ctx) {
|
|
43
|
+
const { url, who, response, posted } = ctx;
|
|
44
|
+
const id = Number(SWEEP_PATH.exec(url.pathname)?.[1]);
|
|
45
|
+
const body = readForm(posted, CONSOLE_FORMS.sweep);
|
|
46
|
+
const table = sweepTable(store, id, clock(), readable(), evidenceRoot);
|
|
47
|
+
if (table === null)
|
|
48
|
+
return refuse(response, who, 404, "There's no sweep at this address you can see.", "/chat");
|
|
49
|
+
if (body.get("confirm") !== "yes")
|
|
50
|
+
return redirect(response, `/sweeps/${id}?said=${encodeURIComponent("Tick the box to cancel the rest.")}`);
|
|
51
|
+
const now = clock();
|
|
52
|
+
const open = sweepOpen(store, table, now);
|
|
53
|
+
if (body.get("snapshot") !== sweepOpenDigest(open))
|
|
54
|
+
return redirect(response, `/sweeps/${id}?said=${encodeURIComponent("The sweep changed while you were reading. Look again, then cancel.")}`);
|
|
55
|
+
return redirect(response, `/sweeps/${id}?said=${encodeURIComponent(cancelSweepRest(store, who.name, open, now, "web"))}`);
|
|
56
|
+
}
|
|
57
|
+
return { registrations: handlersOf("tasks", { "sweep.page": page, "sweep.cancel-rest": cancelRest }) };
|
|
58
|
+
}
|
|
@@ -11,6 +11,7 @@ import { type ProjectPeek, type WorkRow } from "./render-pages.js";
|
|
|
11
11
|
import { type CompletionReceiptView, type ResultDetail, type TaskPullRequest } from "./render-results.js";
|
|
12
12
|
import { taskBody, type MilestoneProgressView, type PlanContractView, type PlanRevisionLedgerView, type RevisionDocView, type RevisionView, type RouteView } from "./render-tasks.js";
|
|
13
13
|
import { type Who } from "./session.js";
|
|
14
|
+
import type { TaskPageExtras } from "./runtime.js";
|
|
14
15
|
import type { PlanRevision, TaskRef } from "../store.js";
|
|
15
16
|
import { type Run, type Store, type Task, type TaskState } from "../store.js";
|
|
16
17
|
import { type ReviewFacts } from "../workspace-ui.js";
|
|
@@ -74,7 +75,7 @@ export declare function createTaskViews(runtime: TaskViewsRuntime): {
|
|
|
74
75
|
level: "quick" | "full";
|
|
75
76
|
returnTo: string;
|
|
76
77
|
} | null;
|
|
77
|
-
taskScreen: (response: ServerResponse, who: Who, taskId: string, problem: string | null, status: number, scopeDraft?: URLSearchParams, cancelDraft?: string, editPlan?: boolean) => void;
|
|
78
|
+
taskScreen: (response: ServerResponse, who: Who, taskId: string, problem: string | null, status: number, scopeDraft?: URLSearchParams, cancelDraft?: string, editPlan?: boolean, extras?: TaskPageExtras) => void;
|
|
78
79
|
armTaskResume: (response: ServerResponse, who: Who, taskId: string, named: string, returnTo: "chat" | "task", now: Date) => void;
|
|
79
80
|
planViewOf: (taskRef: number) => {
|
|
80
81
|
document: string;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { approvalProofOf, freshlyApprovable, freshnessFor, withFreshness } from "../scope.js";
|
|
2
|
+
import { liveAttemptOf, steerControlsFor } from "../steer-controls.js";
|
|
3
|
+
import { originOf } from "../task-source.js";
|
|
1
4
|
import { taskBaseOf } from "../task-base.js";
|
|
2
5
|
import { assignmentPresentationOf, historicalAssessmentReason } from '../assignment-presentation.js';
|
|
3
|
-
import { html, joinHtml } from "../html.js";
|
|
6
|
+
import { html, htmlString, joinHtml } from "../html.js";
|
|
4
7
|
import { assignmentStatusOf, assignmentWithEvidence } from '../assignment-ui.js';
|
|
5
8
|
import { assignmentOf } from '../assignment.js';
|
|
6
9
|
import { knowledgeContextHtml } from "../knowledge-ui.js";
|
|
@@ -18,7 +21,7 @@ import { taskFingerprint } from "../task-live.js";
|
|
|
18
21
|
import { pullRequestFactOf } from '../task-status.js';
|
|
19
22
|
import { openWorkDecisionOf } from "../work-summary.js";
|
|
20
23
|
import { learningHtml } from "../workspace-ui.js";
|
|
21
|
-
import { randomBytes } from "node:crypto";
|
|
24
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
22
25
|
import {} from "node:http";
|
|
23
26
|
import { agentChoicesFor, routeOfTask } from "../agentconfig.js";
|
|
24
27
|
import { rulesSummary } from "../approval-rules-ui.js";
|
|
@@ -41,6 +44,8 @@ import {} from "./render-pages.js";
|
|
|
41
44
|
import { completionReceiptView, diffFileAnchor, evidenceLinksFor, followUpsFor, orderChangedFiles, parseReviewDiff, proofBundleView, receiptStatusOf, withinSignedTouches } from "./render-results.js";
|
|
42
45
|
import { approvalFormDigest, consentDoorOf, nonceHashOf, publicationFactsOf, resumeCeremonyPage, resumeDigestOf, taskBody, taskPage } from "./render-tasks.js";
|
|
43
46
|
import {} from "./session.js";
|
|
47
|
+
import { RESULT_REVIEW_SCRIPT } from "../result-review.js";
|
|
48
|
+
import { reviewEvidenceScript } from "./render-results.js";
|
|
44
49
|
import { budgetHoldWords, budgetLabel, monthOf } from "../spend.js";
|
|
45
50
|
import {} from "../store.js";
|
|
46
51
|
import { taskControlOf } from "../task-control.js";
|
|
@@ -367,6 +372,8 @@ export function createTaskViews(runtime) {
|
|
|
367
372
|
repairChain: completion !== null ? null : runtime.store.repairChainForDraft(taskId),
|
|
368
373
|
repo: ref?.repo ?? null,
|
|
369
374
|
filedVia: runtime.store.filedViaOf(taskId),
|
|
375
|
+
// v126: where the work came from (a flow, an outside event), from what was kept when it was filed.
|
|
376
|
+
origin: (() => { const repos = runtime.workAccess().repos; return originOf(runtime.store, taskId, repo => repos === null || repos.includes(repo)); })(),
|
|
370
377
|
coordinator: (() => {
|
|
371
378
|
const who = runtime.store.coordinatorProvenanceOf(taskId);
|
|
372
379
|
if (who === null)
|
|
@@ -485,6 +492,31 @@ export function createTaskViews(runtime) {
|
|
|
485
492
|
steering: ref === null ? [] : runtime.store.listSteerNotes(ref.id),
|
|
486
493
|
base: taskBaseOf(runtime.store, taskId),
|
|
487
494
|
steeringLive: ref !== null && runtime.store.steeringLiveBuild(ref.id, now) !== null,
|
|
495
|
+
steeringRun: ref === null ? null : runtime.store.steeringLiveBuild(ref.id, now),
|
|
496
|
+
approvalProof: (() => {
|
|
497
|
+
// The proof of the approval shown: its approver, its exact sealed digest (approvedDigest === digest when approved).
|
|
498
|
+
const scope = ref === null ? null : runtime.store.getScope(ref.externalId);
|
|
499
|
+
return scope === null || scope.approvedBy === null || scope.approvedDigest === null ? null
|
|
500
|
+
: approvalProofOf(runtime.store, ref.externalId, scope.approvedBy, scope.approvedDigest);
|
|
501
|
+
})(),
|
|
502
|
+
// Cockpit B2: whether this person's remembered password may approve these exact terms (the same rule approve()
|
|
503
|
+
// applies), and since when.
|
|
504
|
+
approvalFresh: (() => {
|
|
505
|
+
const scope = ref === null ? null : runtime.store.getScope(ref.externalId);
|
|
506
|
+
if (scope === null || who?.via !== "cookie")
|
|
507
|
+
return null;
|
|
508
|
+
const fresh = withFreshness("approve-standard", () => freshnessFor(who.name, Date.now(), true));
|
|
509
|
+
if (fresh === null)
|
|
510
|
+
return null;
|
|
511
|
+
const gate = runtime.store.approvalGate(ref.externalId, who.name, "person");
|
|
512
|
+
return freshlyApprovable(runtime.store, ref.externalId, scope, gate.verdict === "seal" && !gate.protectedWork) ? new Date(fresh.at).toISOString() : null;
|
|
513
|
+
})(),
|
|
514
|
+
steerRecent: ref === null ? [] : runtime.store.runsFor(ref.id).filter(one => one.outcome !== null).map(one => one.id).sort((a, b) => b - a).slice(0, 5),
|
|
515
|
+
// The running attempt's composer, for an approver on a browser session (steer-controls.ts).
|
|
516
|
+
steerComposer: (() => {
|
|
517
|
+
const run = ref === null ? null : liveAttemptOf(runtime.store, ref.id, now);
|
|
518
|
+
return run === null ? null : steerControlsFor(runtime.store, ref.externalId, run, now, who?.role === "approver");
|
|
519
|
+
})(),
|
|
488
520
|
// "publishes as" reads ONLY publicationGrantFor(repo) — the grant
|
|
489
521
|
// the publisher would act under — never listGrants(), which is
|
|
490
522
|
// dispatch authority (slice 1c).
|
|
@@ -584,6 +616,7 @@ export function createTaskViews(runtime) {
|
|
|
584
616
|
deliverable: view.deliverable ?? "branch",
|
|
585
617
|
revision: view.revision ?? null,
|
|
586
618
|
coordinator: view.coordinator ?? null,
|
|
619
|
+
origin: view.origin ?? null,
|
|
587
620
|
repairChain: view.repairChain ?? null,
|
|
588
621
|
},
|
|
589
622
|
decisions: (view?.decisions ?? runtime.store.decisionsForTask(ref.id))
|
|
@@ -690,7 +723,53 @@ export function createTaskViews(runtime) {
|
|
|
690
723
|
return null;
|
|
691
724
|
return { action: `/r/${runId}/checks`, level: followUps.full ? "full" : "quick", returnTo };
|
|
692
725
|
}
|
|
693
|
-
|
|
726
|
+
/**
|
|
727
|
+
* One page per task (docs/plans/one-page-task-and-agent.md): the tab the address named, the Result tab's result with
|
|
728
|
+
* every result attempt to pick from, and every link that would open a result page of this family (its /review deep
|
|
729
|
+
* link, a build's /r/<n>) pointed at this page's Result tab instead — the person stays on the task.
|
|
730
|
+
*/
|
|
731
|
+
function onePageView(view, family, runs, extras) {
|
|
732
|
+
const root = family?.root.id ?? view.id;
|
|
733
|
+
const current = family?.current.id ?? view.id;
|
|
734
|
+
const versions = new Set(family?.versions.map(one => one.id) ?? [view.id]);
|
|
735
|
+
const results = new Map(runs.filter(run => runIsTaskResult(run) && (extras.admissible === undefined || extras.admissible.has(run.id))).map(run => [run.id, run.taskId]));
|
|
736
|
+
const tabHref = (taskId, run, section, hash) => `${taskHref(root)}?${taskId !== current ? `version=${encodeURIComponent(taskId)}&` : ""}tab=result${run === null ? "" : `&run=${run}`}${section === null || section === "summary" ? "" : `§ion=${section}`}${hash}`;
|
|
737
|
+
const toTab = (href) => {
|
|
738
|
+
const review = /^\/review\?result=([A-Za-z0-9._~%-]{1,200})(?:&run=([0-9]{1,15}))?(?:&tab=(summary|changes|checks))?(#[A-Za-z0-9_-]{1,120})?$/.exec(href);
|
|
739
|
+
if (review !== null) {
|
|
740
|
+
const taskId = decodeURIComponent(review[1]);
|
|
741
|
+
if (versions.has(taskId))
|
|
742
|
+
return tabHref(taskId, review[2] === undefined ? null : Number(review[2]), review[3] ?? null, review[4] ?? "");
|
|
743
|
+
}
|
|
744
|
+
const record = /^\/r\/([0-9]{1,15})$/.exec(href);
|
|
745
|
+
if (record !== null && results.has(Number(record[1])))
|
|
746
|
+
return tabHref(results.get(Number(record[1])), Number(record[1]), null, "");
|
|
747
|
+
return href;
|
|
748
|
+
};
|
|
749
|
+
const link = (one) => one === null ? null : { ...one, href: one.href === null ? null : toTab(one.href) };
|
|
750
|
+
const status = view.status === null ? null : { ...view.status, action: view.status.action === null ? null : link(view.status.action),
|
|
751
|
+
status: { ...view.status.status, details: view.status.status.details.map(one => ({ ...one, href: one.href === null ? null : toTab(one.href), action: one.action === null ? null : link(one.action) })) } };
|
|
752
|
+
const selected = extras.result?.selected ?? null;
|
|
753
|
+
const attempts = [...results.entries()].sort((a, b) => b[0] - a[0]).map(([id, taskId]) => {
|
|
754
|
+
const run = runs.find(one => one.id === id);
|
|
755
|
+
const outcome = run.outcome === "built" ? "result" : run.outcome === "no-change" ? "no change" : run.outcome === null ? "never finished" : run.outcome;
|
|
756
|
+
return { label: `${run.role === "scout" ? "Report" : "Build"} #${id} · ${outcome}`, href: tabHref(taskId, id, null, ""), current: selected?.build === id };
|
|
757
|
+
});
|
|
758
|
+
return {
|
|
759
|
+
...view,
|
|
760
|
+
status,
|
|
761
|
+
...(view.failure == null ? {} : { failure: { ...view.failure, link: link(view.failure.link) } }),
|
|
762
|
+
...(view.earlier == null ? {} : { earlier: { ...view.earlier, attempts: view.earlier.attempts.map(one => ({ ...one, href: toTab(one.href) })) } }),
|
|
763
|
+
...(view.thread === undefined ? {} : { thread: view.thread.map(one => ({ ...one, link: link(one.link) })) }),
|
|
764
|
+
// The previous result's fold moves to the Result tab when there is one.
|
|
765
|
+
sections: selected === null ? view.sections : view.sections.filter(one => one.id !== "result"),
|
|
766
|
+
tab: extras.tab ?? "activity",
|
|
767
|
+
result: selected === null ? null : { selected, current: extras.result.current, attempts,
|
|
768
|
+
// Fresh per-render request tokens (32 hex) are not what it shows: left out, so an unchanged result keeps its stamp.
|
|
769
|
+
revision: createHash("sha256").update(JSON.stringify(selected).replace(/\b[a-f0-9]{32}\b/g, "")).digest("hex").slice(0, 16) },
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
function taskScreen(response, who, taskId, problem, status, scopeDraft, cancelDraft, editPlan = false, extras = {}) {
|
|
694
773
|
const admittedFamily = runtime.familyOf(taskId);
|
|
695
774
|
if (admittedFamily?.problem != null)
|
|
696
775
|
return runtime.sendScreen(response, status, screen(admittedFamily.root.title, html `<h1>${admittedFamily.root.title}</h1><p>${admittedFamily.current.state}</p><p class="problem" data-history-problem>${admittedFamily.problem}</p>`, { chrome: runtime.chromeFor(admittedFamily.root.repo, "tasks") }));
|
|
@@ -738,10 +817,21 @@ export function createTaskViews(runtime) {
|
|
|
738
817
|
catch {
|
|
739
818
|
return null;
|
|
740
819
|
} })() } } : {}) } : page.workspace?.view;
|
|
820
|
+
// A refusal that keeps a draft (a scope edit, an armed cancel) or asks for the plan editor reopens on Plan, where the
|
|
821
|
+
// draft and its error are; anything else on Activity unless the address named a tab.
|
|
822
|
+
const tab = extras.tab ?? (scopeDraft !== undefined || cancelDraft !== undefined || editPlan ? "plan" : "activity");
|
|
823
|
+
const oneTaskView = taskView?.kind === "task" ? onePageView(taskView, family, presentedData.family?.runs ?? data.runs.map(run => ({ ...run, taskId: data.task.id })), { ...extras, tab }) : taskView;
|
|
824
|
+
// The Result tab's no-script page, under the task's own (the same HTML its result page serves), and its script.
|
|
825
|
+
if (extras.result != null) {
|
|
826
|
+
page.body = html `${page.body}<section class="task-result-tab" id="task-result" aria-label="Result">${extras.result.html}</section>`;
|
|
827
|
+
// The result's own script, as its result page ships it (a password form there keeps it too: Request changes and
|
|
828
|
+
// the line notes need it).
|
|
829
|
+
page.functional = { script: `${page.functional?.script ?? ""}${reviewEvidenceScript()}${RESULT_REVIEW_SCRIPT}`, fetches: page.functional?.fetches ?? false };
|
|
830
|
+
}
|
|
741
831
|
if (docked !== null)
|
|
742
|
-
page.workspace = { ...page.workspace, ...(
|
|
743
|
-
else if (
|
|
744
|
-
page.workspace = { ...page.workspace, view:
|
|
832
|
+
page.workspace = { ...page.workspace, ...(oneTaskView === undefined ? {} : { view: oneTaskView }), conversation: docked, pageHtml: page.body };
|
|
833
|
+
else if (oneTaskView !== undefined && page.workspace !== undefined)
|
|
834
|
+
page.workspace = { ...page.workspace, view: oneTaskView };
|
|
745
835
|
page.refreshSeconds = runtime.liveRefreshSeconds();
|
|
746
836
|
return runtime.sendScreen(response, status, page);
|
|
747
837
|
}
|