toolroll 0.9.3 → 0.9.5
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 +26 -0
- package/README.md +5 -4
- package/dist/assignment-presentation.js +4 -2
- package/dist/assignment-ui.js +2 -1
- package/dist/browser/workspace.css +1 -1
- package/dist/browser/workspace.js +9 -9
- package/dist/browser-workspace.d.ts +10 -0
- package/dist/cli.js +6 -6
- package/dist/containment.d.ts +5 -0
- package/dist/containment.js +9 -0
- package/dist/demo-chat.d.ts +37 -0
- package/dist/demo-chat.js +150 -0
- package/dist/demo.d.ts +98 -0
- package/dist/demo.js +525 -21
- package/dist/flow-engine.js +22 -11
- package/dist/flow-pull-request.js +26 -3
- package/dist/flow-steps.js +12 -2
- package/dist/guides.js +17 -0
- package/dist/operate.d.ts +1 -1
- package/dist/operate.js +40 -13
- package/dist/proof.d.ts +9 -0
- package/dist/proof.js +25 -1
- package/dist/publish.d.ts +15 -0
- package/dist/publish.js +41 -1
- package/dist/pull-request-flow.d.ts +2 -0
- package/dist/pull-request-flow.js +17 -3
- package/dist/serve.d.ts +2 -0
- package/dist/serve.js +201 -28
- package/dist/store.d.ts +2 -0
- package/dist/store.js +9 -5
- package/dist/surface.js +7 -1
- package/dist/task-outcome-cli.d.ts +18 -0
- package/dist/task-outcome-cli.js +75 -2
- package/dist/workspace-ui.js +1 -1
- package/package.json +1 -1
package/dist/serve.js
CHANGED
|
@@ -58,8 +58,9 @@ import { prepareWorkspaceRevision, WorkspaceValidatorCache } from "./workspace-r
|
|
|
58
58
|
import { workIndexPage, workCountsByProject, WorkIndexCursorError } from "./work-index.js";
|
|
59
59
|
import { openWorkDecisionOf } from "./work-summary.js";
|
|
60
60
|
import { assignmentOf, checkAssignmentAsOperator } from './assignment.js';
|
|
61
|
+
import { demoChatHtml, demoThreadHtml, DEMO_CHAT_SCRIPT } from "./demo-chat.js";
|
|
61
62
|
import { pullRequestSettingsHtml, PULL_REQUEST_SETTINGS_CSS } from './pull-request-ui.js';
|
|
62
|
-
import { checkPublishing, completeAndOpenPullRequest, mergeAsPerson, pullRequestBlocker,
|
|
63
|
+
import { checkPublishing, completeAndOpenPullRequest, mergeAsPerson, pullRequestBlocker, publishingOf, saveMergeSettings, savePublishing, newestPullRequestOf, MERGE_METHODS } from './pull-request-flow.js';
|
|
63
64
|
import { leadBriefHtml, LEAD_CONTEXT_CSS } from './lead-context.js';
|
|
64
65
|
import { assignmentCatchUp } from './assignment-brief.js';
|
|
65
66
|
import { assignmentCardOf, assignmentStatusOf, assignmentSummaryHtml, assignmentWithEvidence, ASSIGNMENT_CSS } from './assignment-ui.js';
|
|
@@ -150,7 +151,7 @@ import { TEMPLATES, templateByName } from "./templates.js";
|
|
|
150
151
|
import { starterRecipes, savedRecipes, findRecipe, importRecipe, exportRecipe, createWorkflowPreview, workflowPreview, launchWorkflow, saveWorkflowRecipe, RecipeError, prepareRecipeRun } from "./recipes.js";
|
|
151
152
|
import { recipeFromForm, recipeLibraryHtml, recipeEditorHtml, workflowPreviewHtml, recipeScript, RECIPE_CSS, recipeDefinitionPreviewHtml, recipeRunHtml, recipeAnswersFromForm } from "./recipe-ui.js";
|
|
152
153
|
import { EVIDENCE_CAPS, readVerifiedArtifact, readVerifiedReport, readVerifiedProofForRun, storeEvidence, writeEvidenceFile, scanForSecrets } from "./evidence.js";
|
|
153
|
-
import { GOAL_ASSESSMENT_PENDING, reviewConflict, manualReviewOnly, dispatchStatusToken, passFraction, semanticCoverage, coverageWords, coverageStateWords } from "./proof.js";
|
|
154
|
+
import { GOAL_ASSESSMENT_PENDING, reviewConflict, manualReviewOnly, manualReviewCriterionOf, personCheckWords, plainReasonWords, dispatchStatusToken, passFraction, semanticCoverage, coverageWords, coverageStateWords } from "./proof.js";
|
|
154
155
|
import { WORK_VIEWS, REVIEW_TOKENS, parseWorkView, resultStatusOf, receiptHeadingOf, receiptPublicationWords, reviewFactsOf, workStatusOf, primaryDestinationOf, needsPerson, dispatchActionLabel, } from "./workspace-ui.js";
|
|
155
156
|
import { PRICED_BUILD_MODELS } from "./pricing.js";
|
|
156
157
|
import { RESULT_TABS, RESULT_REVIEW_SCRIPT, isRevisionFeedback, evidenceResultStatusOf, evidenceShortenedWords, parseResultTab, resultLeadOf, evidenceProblemDetailsOf, evidenceHealthOf, resultFactsAttributes, resultFactsAttributeMap, resultReturnTarget, commentSourceKey, REQUEST_TOKEN, revisionBatchOf, parseRevisionBatch, revisionSourceOf, } from "./result-review.js";
|
|
@@ -1727,6 +1728,7 @@ export function createDecisionServer(options) {
|
|
|
1727
1728
|
url.pathname !== "/projects/browse" && url.pathname !== "/projects/github" && url.pathname !== "/workbench" &&
|
|
1728
1729
|
url.pathname !== "/fleet" &&
|
|
1729
1730
|
url.pathname !== "/chat" && url.pathname !== "/chat/mate/status" && url.pathname !== "/chat/task-status" && url.pathname !== "/chat/stream" &&
|
|
1731
|
+
!url.pathname.startsWith("/chat/demo/") &&
|
|
1730
1732
|
!/^\/chat\/action\/[0-9]{1,15}$/.test(url.pathname) &&
|
|
1731
1733
|
!url.pathname.startsWith("/settings") && url.pathname !== "/logout" && url.pathname !== "/people" && url.pathname !== "/ledger" && url.pathname !== "/ledger/export" && url.pathname !== "/metrics" && url.pathname !== "/spend" && url.pathname !== "/spend/budget" &&
|
|
1732
1734
|
!(url.pathname === "/board" && url.searchParams.get("scope") === "all");
|
|
@@ -3237,6 +3239,26 @@ export function createDecisionServer(options) {
|
|
|
3237
3239
|
...(fragments === null ? {} : { fragments }),
|
|
3238
3240
|
}));
|
|
3239
3241
|
}
|
|
3242
|
+
// `toolroll demo`: Chat is the scripted lead, never a model.
|
|
3243
|
+
if (url.pathname === "/chat/demo/live") {
|
|
3244
|
+
const lead = demoLeadHere();
|
|
3245
|
+
if (lead === null || who.via !== "cookie")
|
|
3246
|
+
return respond(response, 404, "application/json", JSON.stringify({ ok: false }));
|
|
3247
|
+
const exchanges = lead.exchanges();
|
|
3248
|
+
return respond(response, 200, "application/json", JSON.stringify({
|
|
3249
|
+
version: lead.version(), working: exchanges.some(one => one.state === "working"),
|
|
3250
|
+
html: demoThreadHtml(exchanges, who.session.csrf, demoResultView),
|
|
3251
|
+
}));
|
|
3252
|
+
}
|
|
3253
|
+
if (url.pathname === "/chat" && demoLeadHere() !== null && who.via === "cookie" &&
|
|
3254
|
+
!["task", "result", "project", "conversation", "team", "proposal"].some(name => url.searchParams.has(name))) {
|
|
3255
|
+
const lead = demoLeadHere();
|
|
3256
|
+
const said = url.searchParams.get("said")?.slice(0, 300) ?? null;
|
|
3257
|
+
return sendScreen(response, 200, screen("Chat", demoChatHtml({ exchanges: lead.exchanges(), csrf: who.session.csrf, version: lead.version(), problem: said, resultOf: demoResultView }), {
|
|
3258
|
+
chrome: chromeFor(null, "chat", undefined, "all"),
|
|
3259
|
+
functional: { script: DEMO_CHAT_SCRIPT, fetches: true },
|
|
3260
|
+
}));
|
|
3261
|
+
}
|
|
3240
3262
|
if (url.pathname === "/chat") {
|
|
3241
3263
|
// Cookie sessions only (Codex v3 review, change 7): drafts live in
|
|
3242
3264
|
// THIS session's memory; a bearer caller has nowhere to keep them.
|
|
@@ -4146,6 +4168,42 @@ export function createDecisionServer(options) {
|
|
|
4146
4168
|
/** The frozen explicit repo list, digested canonically (sorted) — every
|
|
4147
4169
|
* candidate binds to it and filing re-proves it (v2 new finding 5). */
|
|
4148
4170
|
const chatCeilingDigest = (repos = managedRepos()) => createHash("sha256").update([...repos].sort().join("\n")).digest("hex");
|
|
4171
|
+
/** The scripted lead answers only inside a demo database. */
|
|
4172
|
+
function demoLeadHere() {
|
|
4173
|
+
return options.demoLead !== undefined && store.isDemo() ? options.demoLead : null;
|
|
4174
|
+
}
|
|
4175
|
+
/** A finished demo exchange's result, read back from the evidence its run actually stored. */
|
|
4176
|
+
function demoResultView(exchange) {
|
|
4177
|
+
if (exchange.runId === null || exchange.taskId === null)
|
|
4178
|
+
return null;
|
|
4179
|
+
const artifacts = store.artifactsFor(exchange.runId);
|
|
4180
|
+
const text = (kind) => {
|
|
4181
|
+
const artifact = artifacts.find(one => one.kind === kind);
|
|
4182
|
+
if (artifact === undefined)
|
|
4183
|
+
return null;
|
|
4184
|
+
const read = readVerifiedArtifact(evidenceRoot, artifact);
|
|
4185
|
+
return read.ok ? read.content.toString("utf8") : null;
|
|
4186
|
+
};
|
|
4187
|
+
const shot = artifacts.find(one => one.kind === "screenshot");
|
|
4188
|
+
const stat = (() => { try {
|
|
4189
|
+
return JSON.parse(text("diff-stat") ?? "null");
|
|
4190
|
+
}
|
|
4191
|
+
catch {
|
|
4192
|
+
return null;
|
|
4193
|
+
} })();
|
|
4194
|
+
const assignment = assignmentOf(store, exchange.taskId, clock(), { principal: "operator", repos: managedRepos() }, evidenceRoot);
|
|
4195
|
+
const log = text("check-log");
|
|
4196
|
+
return {
|
|
4197
|
+
diff: text("terminal-diff"),
|
|
4198
|
+
checkLog: log === null ? null : log.slice(log.indexOf("$ ") === -1 ? 0 : log.indexOf("$ ")),
|
|
4199
|
+
checks: { status: assignment?.receipt?.checks.status ?? "unavailable", detail: assignment?.receipt?.checks.detail ?? "Saved checks are unavailable." },
|
|
4200
|
+
screenshot: shot === undefined ? null : { href: `/r/${exchange.runId}/evidence/${shot.id}`, caption: exchange.plan.screenshot.caption },
|
|
4201
|
+
additions: stat?.additions ?? 0,
|
|
4202
|
+
deletions: stat?.deletions ?? 0,
|
|
4203
|
+
files: stat?.fileCount ?? 0,
|
|
4204
|
+
taskHref: taskHref(exchange.taskId),
|
|
4205
|
+
};
|
|
4206
|
+
}
|
|
4149
4207
|
/** Every condition re-proved per request — the render and the POST each
|
|
4150
4208
|
* ask again; nothing is cached into authority. */
|
|
4151
4209
|
function chatEnablement() {
|
|
@@ -4503,7 +4561,7 @@ export function createDecisionServer(options) {
|
|
|
4503
4561
|
s = { ...s, workspace: { ...s.workspace, view: { ...s.workspace.view, stepUp: { label: ssoFacts.label, fresh: ssoFacts.fresh, confirmHref: `/login/sso?reauth=1&return=${encodeURIComponent(back)}` } } } };
|
|
4504
4562
|
}
|
|
4505
4563
|
const teamEntry = requestContext.getStore()?.returnTo;
|
|
4506
|
-
if (teamEntry?.startsWith('/chat') && !s.workspace?.team && !teamEntry.includes('task=') && !teamEntry.includes('proposal=')) {
|
|
4564
|
+
if (teamEntry?.startsWith('/chat') && !s.workspace?.team && !teamEntry.includes('task=') && !teamEntry.includes('proposal=') && demoLeadHere() === null) {
|
|
4507
4565
|
s.body = '<p class="team-entry"><a href="/chat?team=1">Open team chat</a></p>' + s.body;
|
|
4508
4566
|
if (s.workspace?.conversation)
|
|
4509
4567
|
s.workspace.controlsHtml = '<p><a href="/chat?team=1">Open team chat</a></p>' + (s.workspace.controlsHtml ?? '');
|
|
@@ -4524,7 +4582,7 @@ export function createDecisionServer(options) {
|
|
|
4524
4582
|
const extras = s.workspace ?? {};
|
|
4525
4583
|
const notices = [...(extras.notices ?? [])];
|
|
4526
4584
|
if (s.chrome.demo)
|
|
4527
|
-
notices.unshift(
|
|
4585
|
+
notices.unshift(DEMO_BANNER);
|
|
4528
4586
|
if (s.chrome.modeBanner)
|
|
4529
4587
|
notices.push(s.chrome.modeBanner.words);
|
|
4530
4588
|
let crew = { crew: [], crewTruncated: false };
|
|
@@ -5433,20 +5491,12 @@ export function createDecisionServer(options) {
|
|
|
5433
5491
|
function taskPullRequestOf(taskId, who) {
|
|
5434
5492
|
const family = familyOf(taskId);
|
|
5435
5493
|
const rootId = family?.root.id ?? taskId;
|
|
5436
|
-
const ids = family === null ? [taskId] : [...family.versions.map(one => one.id)].reverse();
|
|
5437
5494
|
const repo = store.lookupRef(taskId)?.repo ?? null;
|
|
5438
5495
|
const publishing = publishingOf(store, repo);
|
|
5439
5496
|
const target = publishing.on ? publishing.base : null;
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
continue;
|
|
5444
|
-
for (const run of store.runsFor(ref.id)) {
|
|
5445
|
-
const view = pullRequestViewOf(store, run.id);
|
|
5446
|
-
if (view !== null)
|
|
5447
|
-
return { taskId: rootId, view: { ...view, canMerge: view.canMerge && who.role === "approver" && who.via === "cookie" }, offer: null, target };
|
|
5448
|
-
}
|
|
5449
|
-
}
|
|
5497
|
+
const view = newestPullRequestOf(store, family === null ? [taskId] : family.versions.map(one => one.id));
|
|
5498
|
+
if (view !== null)
|
|
5499
|
+
return { taskId: rootId, view: { ...view, canMerge: view.canMerge && who.role === "approver" && who.via === "cookie" }, offer: null, target };
|
|
5450
5500
|
if (!publishing.on || who.via !== "cookie" || who.role !== "approver")
|
|
5451
5501
|
return null;
|
|
5452
5502
|
const assignment = assignmentOf(store, taskId, clock(), { principal: "operator", repos: admissionList(), includeUnplaced: visible(null) }, evidenceRoot);
|
|
@@ -5930,6 +5980,43 @@ export function createDecisionServer(options) {
|
|
|
5930
5980
|
const denied = authorizeMutation(request, who, body);
|
|
5931
5981
|
if (denied !== null)
|
|
5932
5982
|
return refuse(response, who, denied.status, denied.message);
|
|
5983
|
+
// The scripted demo lead's acts: ask, approve, change a plan, complete or send back a result.
|
|
5984
|
+
const demoAct = /^\/chat\/demo\/(?:ask|([0-9]{1,9})\/(approve|change|revise|complete))$/.exec(url.pathname);
|
|
5985
|
+
if (demoAct !== null) {
|
|
5986
|
+
const lead = demoLeadHere();
|
|
5987
|
+
if (lead === null || who.via !== "cookie")
|
|
5988
|
+
return refuse(response, who, 404, "There's no page at this address.", "/chat");
|
|
5989
|
+
if (who.role !== "approver")
|
|
5990
|
+
return redirect(response, `/chat?said=${encodeURIComponent("Your login can watch. Approving and completing is an approver's act.")}`);
|
|
5991
|
+
const now = clock();
|
|
5992
|
+
if (demoAct[1] === undefined) {
|
|
5993
|
+
const message = (body.get("message") ?? "").trim();
|
|
5994
|
+
if (message === "")
|
|
5995
|
+
return redirect(response, `/chat?said=${encodeURIComponent("Type a request first.")}`);
|
|
5996
|
+
const asked = lead.ask(message, now);
|
|
5997
|
+
return redirect(response, `/chat#demo-${asked.id}`);
|
|
5998
|
+
}
|
|
5999
|
+
const id = Number(demoAct[1]);
|
|
6000
|
+
const note = body.get("note") ?? "";
|
|
6001
|
+
const done = demoAct[2] === "approve" ? lead.approve(id, now)
|
|
6002
|
+
: demoAct[2] === "change" ? lead.change(id, note, now)
|
|
6003
|
+
: demoAct[2] === "revise" ? lead.requestChanges(id, note, now)
|
|
6004
|
+
: lead.complete(id, now, (taskId, runId) => {
|
|
6005
|
+
const principal = matePrincipal(who);
|
|
6006
|
+
if (principal === null)
|
|
6007
|
+
return { ok: false, message: "Your access changed. Sign in again." };
|
|
6008
|
+
const current = assignmentOf(store, taskId, now, { principal: "operator", repos: principal.repos }, evidenceRoot);
|
|
6009
|
+
if (current?.receipt?.runId !== runId)
|
|
6010
|
+
return { ok: false, message: "This result changed. Reload before marking it complete." };
|
|
6011
|
+
const completed = checkAssignmentAsOperator(store, taskId, current.receipt.digest, principal, now, evidenceRoot);
|
|
6012
|
+
return completed.ok ? { ok: true } : { ok: false, message: completed.message };
|
|
6013
|
+
});
|
|
6014
|
+
bustBadge();
|
|
6015
|
+
if (!done.ok)
|
|
6016
|
+
return redirect(response, `/chat?said=${encodeURIComponent(done.message)}`);
|
|
6017
|
+
const latest = lead.exchanges().at(-1);
|
|
6018
|
+
return redirect(response, demoAct[2] === "change" || demoAct[2] === "revise" ? `/chat#demo-${latest?.id ?? id}` : `/chat#demo-${id}-work`);
|
|
6019
|
+
}
|
|
5933
6020
|
// A person says a provider's sign-in works again: its sign-in pause
|
|
5934
6021
|
// lifts, its tasks may start, and one short message says so.
|
|
5935
6022
|
const resumeProvider = /^\/providers\/([a-z]+)\/resume$/.exec(url.pathname);
|
|
@@ -10228,7 +10315,7 @@ export function createDecisionServer(options) {
|
|
|
10228
10315
|
note = validated.note;
|
|
10229
10316
|
}
|
|
10230
10317
|
store.acceptProof(latest.id, verifiedAuthor(who.name), note, now);
|
|
10231
|
-
return redirect(response, taskHref(taskId));
|
|
10318
|
+
return redirect(response, body.get("return") === null ? taskHref(taskId) : safeReturn(body.get("return")));
|
|
10232
10319
|
}
|
|
10233
10320
|
case "complete": {
|
|
10234
10321
|
if (who.via !== "cookie" || who.role !== "approver")
|
|
@@ -11257,7 +11344,7 @@ function criterionMatrixHtml(matrix, options = {}) {
|
|
|
11257
11344
|
const state = row.state;
|
|
11258
11345
|
const awaitingAssessment = row.assessment?.evidenceState === "pass" && row.review === null;
|
|
11259
11346
|
const confirmed = row.assessment !== undefined && state === "pass";
|
|
11260
|
-
const label = awaitingAssessment ? "Not assessed" : confirmed ? "Confirmed" : state === "pass" ? "
|
|
11347
|
+
const label = awaitingAssessment ? "Not assessed" : confirmed ? "Confirmed" : state === "pass" ? "Met" : state === "manual-review" ? "You check" : state === "missing" ? "Not shown yet" : "Not met";
|
|
11261
11348
|
const cls = awaitingAssessment ? "" : state === "pass" ? "badge-done" : state === "manual-review" ? "badge-manual-review" : "badge-failed";
|
|
11262
11349
|
const warnings = [];
|
|
11263
11350
|
// Only replace the known boilerplate. Other recorded failure details
|
|
@@ -11656,6 +11743,8 @@ function agentsStripHtml(view, taskId) {
|
|
|
11656
11743
|
return `<p class="task-chat-agents">${escape(agentsSummaryWords(view))} <a href="${taskHref(taskId)}#agents">Review agent setup</a></p>`;
|
|
11657
11744
|
return `<details class="task-chat-agents"><summary>Agent setup</summary><p>${escape(agentsSummaryWords(view))}</p><a href="${taskHref(taskId)}#agents">View agents</a></details>`;
|
|
11658
11745
|
}
|
|
11746
|
+
/** The demo's one-line promise, on every page. */
|
|
11747
|
+
const DEMO_BANNER = "Demo: a scripted lead and sample projects. Nothing calls a model, reaches outside or spends.";
|
|
11659
11748
|
/** Every character that could open a tag or an attribute, dead at the sink. */
|
|
11660
11749
|
function escape(text) {
|
|
11661
11750
|
return text
|
|
@@ -12607,6 +12696,66 @@ ${THEME_DARK}
|
|
|
12607
12696
|
padding: .375rem .9rem; font-size: .8125rem; color: var(--muted-foreground);
|
|
12608
12697
|
}
|
|
12609
12698
|
.banner .badge { margin-right: .5rem; }
|
|
12699
|
+
/* Chat in \`toolroll demo\`: the scripted lead's conversation. */
|
|
12700
|
+
.demo-chat { display: flex; flex-direction: column; gap: 1rem; max-width: 46rem; margin: 0 auto; padding-bottom: 1rem; }
|
|
12701
|
+
.demo-thread { display: flex; flex-direction: column; gap: 1.25rem; }
|
|
12702
|
+
.demo-turn { display: flex; flex-direction: column; gap: .75rem; scroll-margin-top: 1rem; }
|
|
12703
|
+
.demo-said p { margin: 0; }
|
|
12704
|
+
.demo-you { align-self: flex-end; max-width: min(34rem, 85%); background: var(--so-ink); color: var(--so-paper); border-radius: .875rem .875rem .25rem .875rem; padding: .55rem .85rem; overflow-wrap: anywhere; }
|
|
12705
|
+
.demo-lead { max-width: 40rem; }
|
|
12706
|
+
.demo-who { font-size: .75rem; font-weight: 600; color: var(--so-muted); margin-bottom: .15rem !important; }
|
|
12707
|
+
.demo-chat .card { margin: 0; padding: 1rem 1.125rem; }
|
|
12708
|
+
.demo-chat .card h2 { font-size: .9375rem; margin: .1rem 0 .4rem; }
|
|
12709
|
+
.demo-chat .card h3 { font-size: .75rem; font-weight: 600; color: var(--so-muted); margin: .75rem 0 .25rem; }
|
|
12710
|
+
.demo-chat .card ul { margin: 0; padding-left: 1.1rem; }
|
|
12711
|
+
.demo-chat .card li { margin: .15rem 0; }
|
|
12712
|
+
.demo-chat .card > p { margin: .25rem 0; }
|
|
12713
|
+
.demo-kicker { font-size: .75rem; color: var(--so-muted); margin: 0 !important; }
|
|
12714
|
+
.demo-actions { display: flex; flex-wrap: wrap; align-items: flex-start; gap: .5rem; margin-top: .9rem; }
|
|
12715
|
+
.demo-actions form { margin: 0; }
|
|
12716
|
+
.demo-actions button, .demo-more > summary { min-height: 2.5rem; }
|
|
12717
|
+
.demo-chat button.demo-primary { background: var(--primary); color: var(--primary-foreground); border-color: var(--primary); font-weight: 600; }
|
|
12718
|
+
.demo-chat details.demo-more { flex: 1 1 12rem; margin: 0; padding: 0; border: 0; border-radius: 0; background: none; }
|
|
12719
|
+
.demo-chat details.demo-more[open] { padding-bottom: 0; }
|
|
12720
|
+
.demo-chat .demo-more > summary { display: inline-flex; align-items: center; color: var(--so-ink); padding: .35rem .85rem; border: 1px solid var(--so-input-line); border-radius: calc(var(--radius) - 3px); background: var(--so-paper); font-weight: 500; font-size: .8125rem; cursor: pointer; list-style: none; }
|
|
12721
|
+
.demo-more > summary::-webkit-details-marker { display: none; }
|
|
12722
|
+
.demo-more[open] > summary { margin-bottom: .5rem; }
|
|
12723
|
+
.demo-more form, .demo-composer { display: flex; flex-direction: column; gap: .4rem; }
|
|
12724
|
+
.demo-more label { font-size: .8125rem; font-weight: 500; }
|
|
12725
|
+
.demo-more textarea, .demo-composer textarea { width: 100%; font: inherit; font-size: 1rem; resize: vertical; }
|
|
12726
|
+
.demo-more form button { align-self: flex-start; }
|
|
12727
|
+
.demo-steps { display: flex; flex-wrap: wrap; gap: .4rem 1rem; list-style: none; padding: 0 !important; margin: .4rem 0 !important; }
|
|
12728
|
+
.demo-steps li { display: inline-flex; align-items: center; gap: .4rem; color: var(--so-muted); font-size: .8125rem; margin: 0 !important; }
|
|
12729
|
+
.demo-steps li::before { content: ""; width: .55rem; height: .55rem; border-radius: 50%; border: 1.5px solid currentColor; }
|
|
12730
|
+
.demo-steps li.done { color: var(--so-ink); }
|
|
12731
|
+
.demo-steps li.done::before { background: var(--so-success); border-color: var(--so-success); }
|
|
12732
|
+
.demo-steps li.now { color: var(--so-ink); font-weight: 600; }
|
|
12733
|
+
.demo-steps li.now::before { border-color: var(--so-info); background: var(--so-info); animation: demo-pulse 1.2s ease-in-out infinite; }
|
|
12734
|
+
@keyframes demo-pulse { 50% { opacity: .35; } }
|
|
12735
|
+
@media (prefers-reduced-motion: reduce) { .demo-steps li.now::before { animation: none; } }
|
|
12736
|
+
.demo-state { display: flex; align-items: center; gap: .5rem; margin: 0 !important; }
|
|
12737
|
+
.demo-chat .badge.demo-ready { background: var(--so-info-soft); color: var(--so-info); }
|
|
12738
|
+
.demo-chat .badge.demo-complete { background: var(--so-success-soft); color: var(--so-success); }
|
|
12739
|
+
.demo-pass { color: var(--so-success); font-weight: 500; }
|
|
12740
|
+
.demo-fail { color: var(--so-danger); font-weight: 500; }
|
|
12741
|
+
.demo-chat details.demo-evidence { margin: .5rem 0 0; padding: 0; border: 0; border-top: 1px solid var(--so-line); border-radius: 0; background: none; box-shadow: none; }
|
|
12742
|
+
.demo-evidence > summary { min-height: 2.5rem; display: list-item; padding-block: .55rem; cursor: pointer; font-weight: 500; font-size: .8125rem; }
|
|
12743
|
+
.demo-evidence pre { margin: 0 0 .5rem; max-height: 22rem; overflow: auto; padding: .6rem .75rem; border-radius: .5rem; background: var(--so-raised); font: 400 .75rem/1.55 var(--font-mono); white-space: pre; overflow-wrap: normal; }
|
|
12744
|
+
.demo-diff span { display: block; min-width: max-content; }
|
|
12745
|
+
.demo-diff-add { background: var(--so-success-soft); color: var(--so-success); }
|
|
12746
|
+
.demo-diff-del { background: var(--so-danger-soft); color: var(--so-danger); }
|
|
12747
|
+
.demo-diff-hunk, .demo-diff-meta { color: var(--so-muted); }
|
|
12748
|
+
.demo-diff-file { font-weight: 600; }
|
|
12749
|
+
.demo-evidence figure { margin: 0 0 .5rem; }
|
|
12750
|
+
.demo-evidence img { display: block; width: 100%; height: auto; border: 1px solid var(--so-line); border-radius: .5rem; }
|
|
12751
|
+
.demo-evidence figcaption { margin-top: .35rem; }
|
|
12752
|
+
.demo-hint { padding: 1.25rem 0 .25rem; }
|
|
12753
|
+
.demo-hint-title { font-size: .9375rem; font-weight: 600; margin: 0 0 .75rem; }
|
|
12754
|
+
.demo-suggestions { display: flex; flex-wrap: wrap; gap: .5rem; margin: 0; }
|
|
12755
|
+
.demo-suggestions button { min-height: 2.5rem; border-radius: 999px; padding: .35rem .95rem; }
|
|
12756
|
+
.demo-composer { position: sticky; bottom: 0; padding: .75rem 0 .25rem; background: var(--so-paper); flex-direction: row; align-items: flex-end; }
|
|
12757
|
+
.demo-chat .demo-composer textarea { flex: 1 1 auto; width: auto; min-width: 0; min-height: 2.75rem; }
|
|
12758
|
+
.demo-chat .demo-composer button { flex: none; width: auto; min-height: 2.75rem; padding-inline: 1.1rem; }
|
|
12610
12759
|
.banner a { color: var(--muted-foreground); }
|
|
12611
12760
|
.sign-in-banner form { display: inline; margin: 0 0 0 .5rem; padding: 0; border: 0; background: transparent; }
|
|
12612
12761
|
|
|
@@ -13032,6 +13181,9 @@ ${THEME_DARK}
|
|
|
13032
13181
|
.result-notes .recap { margin: .25rem 0 .4rem; font-size: .875rem; }
|
|
13033
13182
|
.result-attention { margin: .75rem 0 .25rem; padding: .7rem .85rem; border-left: 1px solid var(--warning); border-radius: 0 calc(var(--radius) - 3px) calc(var(--radius) - 3px) 0; background: var(--warning-soft); font-size: .8125rem; }
|
|
13034
13183
|
.result-attention strong { display: block; font-size: .78rem; }
|
|
13184
|
+
.result-you-check { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem .75rem; margin: .75rem 0; padding: .65rem .85rem; border-radius: calc(var(--radius) - 3px); background: var(--muted); font-size: .8125rem; }
|
|
13185
|
+
.result-you-check ul { flex: 1 1 14rem; min-width: 0; margin: 0; padding: 0; list-style: none; }
|
|
13186
|
+
.result-you-check form { margin: 0; }
|
|
13035
13187
|
.result-attention ul { margin: .3rem 0 0; padding-left: 1.15rem; }
|
|
13036
13188
|
.result-attention li { margin: .15rem 0; overflow-wrap: anywhere; }
|
|
13037
13189
|
.result-tabs { display: flex; gap: .25rem; margin: .9rem 0 .75rem; border-bottom: 1px solid var(--border); overflow-x: auto; scrollbar-width: none; }
|
|
@@ -14762,7 +14914,7 @@ function shell(title, body, options = {}) {
|
|
|
14762
14914
|
// must not pass as production (adoption review, finding 8; the FENCE is
|
|
14763
14915
|
// the refuseDemo gate in operate.ts, this is the honest label).
|
|
14764
14916
|
const demoBanner = (chrome.demo === true
|
|
14765
|
-
? `<div class="banner"><span class="badge">
|
|
14917
|
+
? `<div class="banner"><span class="badge">demo</span>${escape(DEMO_BANNER.replace(/^Demo: /, ""))}</div>`
|
|
14766
14918
|
: "") +
|
|
14767
14919
|
(chrome.modeBanner === undefined
|
|
14768
14920
|
? ""
|
|
@@ -18457,7 +18609,7 @@ function milestoneProgressHtml(milestones) {
|
|
|
18457
18609
|
.map(one => `<li class="milestone milestone-${one.state}"><span class="milestone-badge">${milestoneStateWord(one.state)}</span> ` +
|
|
18458
18610
|
`${escape(one.description)}${one.note === null ? "" : ` <span class="meta">— ${escape(one.note)}</span>`}</li>`)
|
|
18459
18611
|
.join("\n") +
|
|
18460
|
-
`</ul><p class="meta milestone-progress-note">Live checkpoints from the agent
|
|
18612
|
+
`</ul><p class="meta milestone-progress-note">Live checkpoints from the agent.</p></section>`);
|
|
18461
18613
|
}
|
|
18462
18614
|
/** Adaptive execution plans (v44): the current plan revision's own reason
|
|
18463
18615
|
* and evidence, any revision still awaiting an operator's accept/reject,
|
|
@@ -18734,7 +18886,7 @@ function taskBodyParts(data) {
|
|
|
18734
18886
|
return `<details class="dispatch-proof-details"><summary>Previous assessment</summary><div class="dispatch-proof-body">` +
|
|
18735
18887
|
`<p class="meta">Saved assessment history. Current task status and checks are shown above.</p>` +
|
|
18736
18888
|
(accepted === null ? "" : `<p class="meta">Accepted with an exception by ${escape(accepted.approver)}. Check results are unchanged.${accepted.note === null ? "" : ` ${escape(accepted.note)}`}</p>`) +
|
|
18737
|
-
(proof.proofReasons.length === 0 ? "" : `<ul>${proof.proofReasons.map(reason => `<li>${escape(reason)}</li>`).join("")}</ul>`) +
|
|
18889
|
+
(proof.proofReasons.length === 0 ? "" : `<ul>${[...new Set(proof.proofReasons.map(plainReasonWords))].map(reason => `<li>${escape(reason)}</li>`).join("")}</ul>`) +
|
|
18738
18890
|
criterionMatrixHtml(proof.proofMatrix, { compact: true, runId: proof.runId, links: proof.proofMatrixLinks }) +
|
|
18739
18891
|
semanticCoverageHtml(proof.proofMatrix, proof.qualityMode ?? "default") + `</div></details>`;
|
|
18740
18892
|
}
|
|
@@ -19989,11 +20141,14 @@ function verificationExplanation(verdict, reasons) {
|
|
|
19989
20141
|
if (reason === "the sealed diff is unavailable or truncated; the claimed changed paths cannot be verified against it") {
|
|
19990
20142
|
return "The recorded changes were incomplete, so they could not be verified.";
|
|
19991
20143
|
}
|
|
20144
|
+
const plainWords = plainReasonWords(reason);
|
|
20145
|
+
if (plainWords !== reason)
|
|
20146
|
+
return plainWords;
|
|
19992
20147
|
const sentence = reason.trim();
|
|
19993
20148
|
return sentence === "" ? "" : `${sentence[0]?.toUpperCase() ?? ""}${sentence.slice(1)}${/[.!?]$/.test(sentence) ? "" : "."}`;
|
|
19994
20149
|
}).filter(Boolean);
|
|
19995
20150
|
if (plain.length > 0)
|
|
19996
|
-
return plain.join(" ");
|
|
20151
|
+
return [...new Set(plain)].join(" ");
|
|
19997
20152
|
if (verdict === "verified")
|
|
19998
20153
|
return "Toolroll independently verified this result.";
|
|
19999
20154
|
if (verdict === "attested")
|
|
@@ -20948,8 +21103,8 @@ function completionReceiptCard(view, taskId, place, standing = receiptStatusOf(v
|
|
|
20948
21103
|
(view.diff.binaryCount > 0 ? ` · ${view.diff.binaryCount} binary` : "") +
|
|
20949
21104
|
(view.diff.filesTruncated ? " · list shortened" : "");
|
|
20950
21105
|
const criteria = facts.checks === null
|
|
20951
|
-
? "No
|
|
20952
|
-
: `${facts.checks.passed}/${facts.checks.total}
|
|
21106
|
+
? "No requirements set"
|
|
21107
|
+
: `${facts.checks.passed}/${facts.checks.total} requirements met`;
|
|
20953
21108
|
// The deliverable leads (package 3): a scout's report by its title, UI
|
|
20954
21109
|
// work by its validated screenshots. Unverifiable shots are counted as
|
|
20955
21110
|
// unavailable, never shown, never called validated.
|
|
@@ -20970,7 +21125,7 @@ function completionReceiptCard(view, taskId, place, standing = receiptStatusOf(v
|
|
|
20970
21125
|
const attention = current === null ? [...facts.evidenceProblems, ...view.caveats] : [];
|
|
20971
21126
|
const caveats = attention.length === 0
|
|
20972
21127
|
? ""
|
|
20973
|
-
: `<div class="receipt-caveats" data-result-attention="${attention.length}"><strong>Before you move on</strong><ul>${attention.map(one => `<li>${escape(one)}</li>`).join("")}</ul></div>`;
|
|
21128
|
+
: `<div class="receipt-caveats" data-result-attention="${attention.length}"><strong>Before you move on</strong><ul>${attention.map(one => `<li>${escape(plainReasonWords(one))}</li>`).join("")}</ul></div>`;
|
|
20974
21129
|
// v51: semantic coverage, distinct from the machine proof word above —
|
|
20975
21130
|
// the same lines the CLI prints, so chat and terminal cannot disagree.
|
|
20976
21131
|
// Nothing owed (optional and unsettled, or satisfied) folds behind a
|
|
@@ -21002,7 +21157,7 @@ function completionReceiptCard(view, taskId, place, standing = receiptStatusOf(v
|
|
|
21002
21157
|
(inReview ? `<details class="receipt-history"><summary>Review history</summary><p class="receipt-review meta" data-receipt-review="${escape(status.token)}">${escape(status.detail)}</p></details>` : "") +
|
|
21003
21158
|
// The matrix count is the proof's own citation; it reads as verified
|
|
21004
21159
|
// only when the machine verified the result (workspace package 1).
|
|
21005
|
-
`<div class="receipt-facts"><span><strong>${escape(criteria)}</strong><small>${stored.tone === "problem" ? "
|
|
21160
|
+
`<div class="receipt-facts"><span><strong>${escape(criteria)}</strong><small>${stored.tone === "problem" ? "the agent's own claim — not checked" : stored.token === "agent-attested" ? "the agent's own claim, no project check" : "against the approved scope"}</small></span>` +
|
|
21006
21161
|
`<span><strong>${escape(diff)}</strong><small>${facts.head === null ? "no commit recorded" : `head ${escape(facts.head.slice(0, 12))} · ${escape(facts.headSource ?? "")}`}</small></span>` +
|
|
21007
21162
|
`<span><strong>${view.screenshots.length} screenshot${view.screenshots.length === 1 ? "" : "s"}</strong><small>${view.screenshots.length === 0 ? "none required or captured" : unavailable === 0 ? "validated visual proof" : `${unavailable} unavailable — not validated`}</small></span></div>` +
|
|
21008
21163
|
`<div class="receipt-actions">` +
|
|
@@ -21088,9 +21243,25 @@ function resultPanelParts(detail, o) {
|
|
|
21088
21243
|
}
|
|
21089
21244
|
if (detail.ciFailing && publication !== null)
|
|
21090
21245
|
attention.push(`CI is failing on PR #${publication.prNumber} at the last check.`);
|
|
21246
|
+
// Requirements only a person can confirm: plain words and one Accept,
|
|
21247
|
+
// in neutral ink — nothing failed. Accepting records the person's
|
|
21248
|
+
// decision and leaves the recorded checks as they are.
|
|
21249
|
+
const personChecks = proof === null || proof.accepted !== null ? [] : [
|
|
21250
|
+
...proof.matrix.filter(row => row.state === "manual-review").map(row => personCheckWords(row.statement)),
|
|
21251
|
+
...(proof.matrix.length > 0 ? [] : proof.reasons.filter(reason => manualReviewCriterionOf(reason) !== null).map(() => personCheckWords(null))),
|
|
21252
|
+
];
|
|
21253
|
+
const acceptable = personChecks.length > 0 && humanReview && o.csrf !== "" && (current != null || detail.assignment == null);
|
|
21254
|
+
const youCheck = personChecks.length === 0 ? null : {
|
|
21255
|
+
lines: [...new Set(personChecks)],
|
|
21256
|
+
accept: acceptable ? { action: `${taskHref(detail.taskId)}/accept-proof`, run: run.id, returnTo: o.returnTo } : null,
|
|
21257
|
+
};
|
|
21258
|
+
const youCheckHtml = youCheck === null ? "" :
|
|
21259
|
+
`<div class="result-you-check" data-result-you-check="${youCheck.lines.length}"><ul>${youCheck.lines.map(one => `<li>${escape(one)}</li>`).join("")}</ul>` +
|
|
21260
|
+
(youCheck.accept === null ? "" : `<form method="post" action="${escape(youCheck.accept.action)}"><input type="hidden" name="csrf" value="${escape(o.csrf)}"><input type="hidden" name="run" value="${youCheck.accept.run}"><input type="hidden" name="return" value="${escape(youCheck.accept.returnTo)}"><button type="submit" data-accept-result>Accept</button></form>`) +
|
|
21261
|
+
`</div>`;
|
|
21091
21262
|
const attentionHtml = attention.length === 0
|
|
21092
21263
|
? ""
|
|
21093
|
-
: `<div class="result-attention" data-result-attention="${attention.length}"><ul>${attention.map(one => `<li>${escape(one)}</li>`).join("")}</ul></div>`;
|
|
21264
|
+
: `<div class="result-attention" data-result-attention="${attention.length}"><ul>${attention.map(one => `<li>${escape(plainReasonWords(one))}</li>`).join("")}</ul></div>`;
|
|
21094
21265
|
// ---- one outcome, one action (repair 2026-09-14) ------------------------
|
|
21095
21266
|
// The outcome is the handoff's first sentence, bounded; the agent's full
|
|
21096
21267
|
// account waits behind a disclosure in Summary so nothing is said twice.
|
|
@@ -21351,9 +21522,10 @@ function resultPanelParts(detail, o) {
|
|
|
21351
21522
|
(current == null || o.place === "review" && (current.state === "ready-to-check" || current.state === "complete") ? "" :
|
|
21352
21523
|
`<div class="verdict" data-current-outcome>${verdictChipsHtml(current, facts)}` +
|
|
21353
21524
|
(current.receipt?.checks.status === "failed" || current.receipt?.checks.status === "unavailable" ? `<p class="problem">${escape(current.detail)}</p>` : "") + `</div>`) +
|
|
21525
|
+
attentionHtml +
|
|
21526
|
+
youCheckHtml +
|
|
21354
21527
|
action +
|
|
21355
21528
|
(REVIEW_TOKENS.has(status.token) ? `<details class="receipt-history"><summary>Review history</summary><p class="receipt-review meta" data-receipt-review="${escape(status.token)}">${escape(status.detail)}</p></details>` : "") +
|
|
21356
|
-
attentionHtml +
|
|
21357
21529
|
tabs +
|
|
21358
21530
|
view("summary", summaryParts) +
|
|
21359
21531
|
view("changes", changeParts) +
|
|
@@ -21366,7 +21538,8 @@ function resultPanelParts(detail, o) {
|
|
|
21366
21538
|
heading, outcome,
|
|
21367
21539
|
verdict: current == null ? null : verdictChipsOf(current, facts),
|
|
21368
21540
|
reviewHistory: REVIEW_TOKENS.has(status.token) ? status.detail : null,
|
|
21369
|
-
attention: attention.filter(one => !shortenedMaterialReason(one)),
|
|
21541
|
+
attention: attention.filter(one => !shortenedMaterialReason(one)).map(plainReasonWords),
|
|
21542
|
+
youCheck,
|
|
21370
21543
|
limits: attention.filter(one => shortenedMaterialReason(one)),
|
|
21371
21544
|
tabs: RESULT_TABS.map(tab => ({ key: tab.key, label: tab.key === "checks" && proof?.matrix.some(row => row.assessment !== undefined) ? "Requirements" : tab.label, count: tabCounts[tab.key], href: o.hrefFor(tab.key), active: tab.key === o.tab })),
|
|
21372
21545
|
views: [{ key: "summary", html: summaryParts.join("\n") }, { key: "changes", html: changeParts.join("\n") }, { key: "checks", html: checkParts.join("\n") }],
|
package/dist/store.d.ts
CHANGED
|
@@ -6063,6 +6063,7 @@ export declare class Store {
|
|
|
6063
6063
|
pendingPublications(): Publication[];
|
|
6064
6064
|
publicationForRun(run: number): Publication | null;
|
|
6065
6065
|
markPublicationPushed(id: number, now: Date): void;
|
|
6066
|
+
/** A PR that exists is recorded as opened, even if a concurrent pass gave up on the row meanwhile: it truly opened. */
|
|
6066
6067
|
markPublicationOpened(id: number, prNumber: number, prUrl: string, now: Date): void;
|
|
6067
6068
|
/** One more failed attempt, error kept. Returns the new count; the caller decides when enough is enough. */
|
|
6068
6069
|
recordPublicationError(id: number, error: string, now: Date): number;
|
|
@@ -6188,6 +6189,7 @@ export declare class Store {
|
|
|
6188
6189
|
historyNote?: string;
|
|
6189
6190
|
}, now: Date): boolean;
|
|
6190
6191
|
/** What a card's current zone is doing: its task, the card's main work, what it waits on, what zones reported. */
|
|
6192
|
+
/** Read and written in one transaction, so a pass changing one field never writes back another pass's older task or waiting. */
|
|
6191
6193
|
updateFlowCard(id: number, change: {
|
|
6192
6194
|
task?: string | null;
|
|
6193
6195
|
primaryTask?: string;
|
package/dist/store.js
CHANGED
|
@@ -18509,9 +18509,10 @@ export class Store {
|
|
|
18509
18509
|
.prepare("UPDATE publication SET state = 'pushed', updated_at = ? WHERE id = ? AND state = 'intended'")
|
|
18510
18510
|
.run(now.toISOString(), id);
|
|
18511
18511
|
}
|
|
18512
|
+
/** A PR that exists is recorded as opened, even if a concurrent pass gave up on the row meanwhile: it truly opened. */
|
|
18512
18513
|
markPublicationOpened(id, prNumber, prUrl, now) {
|
|
18513
18514
|
this.db
|
|
18514
|
-
.prepare("UPDATE publication SET state = 'opened', pr_number = ?, pr_url = ?, updated_at = ? WHERE id = ? AND state
|
|
18515
|
+
.prepare("UPDATE publication SET state = 'opened', pr_number = ?, pr_url = ?, updated_at = ? WHERE id = ? AND state IN ('pushed','failed')")
|
|
18515
18516
|
.run(prNumber, prUrl, now.toISOString(), id);
|
|
18516
18517
|
}
|
|
18517
18518
|
/** One more failed attempt, error kept. Returns the new count; the caller decides when enough is enough. */
|
|
@@ -18795,11 +18796,14 @@ export class Store {
|
|
|
18795
18796
|
});
|
|
18796
18797
|
}
|
|
18797
18798
|
/** What a card's current zone is doing: its task, the card's main work, what it waits on, what zones reported. */
|
|
18799
|
+
/** Read and written in one transaction, so a pass changing one field never writes back another pass's older task or waiting. */
|
|
18798
18800
|
updateFlowCard(id, change, now) {
|
|
18799
|
-
|
|
18800
|
-
|
|
18801
|
-
|
|
18802
|
-
|
|
18801
|
+
this.transact(() => {
|
|
18802
|
+
const card = this.getFlowCard(id);
|
|
18803
|
+
if (card === null)
|
|
18804
|
+
return;
|
|
18805
|
+
this.db.prepare("UPDATE flow_card SET task = ?, primary_task = ?, waiting = ?, outputs_json = ?, state = ?, updated_at = ? WHERE id = ?").run(change.task === undefined ? card.task : change.task, change.primaryTask ?? card.primaryTask, change.waiting === undefined ? card.waiting : change.waiting, JSON.stringify(change.outputs ?? card.outputs), change.state ?? card.state, now.toISOString(), id);
|
|
18806
|
+
});
|
|
18803
18807
|
}
|
|
18804
18808
|
flowEvents(card) {
|
|
18805
18809
|
return this.db.prepare("SELECT * FROM flow_event WHERE card = ? ORDER BY id").all(card).map(row => ({
|
package/dist/surface.js
CHANGED
|
@@ -160,10 +160,16 @@ export const COMMAND_GUIDE = [
|
|
|
160
160
|
flags: [jsonFlag, dbFlag,
|
|
161
161
|
{ name: 'token-env', takesValue: true, meaning: 'scoped coordinator credential environment variable' },
|
|
162
162
|
{ name: 'token-file', takesValue: true, meaning: 'scoped coordinator credential file; defaults to selected project reference' },
|
|
163
|
-
...(action === 'complete' ? [{ name: 'digest', takesValue: true, meaning: 'exact receipt from assignment show; required for JSON or scoped agents' }
|
|
163
|
+
...(action === 'complete' ? [{ name: 'digest', takesValue: true, meaning: 'exact receipt from assignment show; required for JSON or scoped agents' },
|
|
164
|
+
{ name: 'pull-request', takesValue: false, meaning: "also open the result's pull request from that commit, as the console's Complete does; an approver's sign-in (--as/--token), never a scoped credential; refuses with pull-requests-off and the setup command" }]
|
|
164
165
|
: [{ name: 'feedback', takesValue: true, meaning: 'specific requested change' }, { name: 'run', takesValue: true, meaning: 'exact result run; defaults to current result' }, { name: 'source', takesValue: true, meaning: 'exact scope digest; defaults to current terms' }, { name: 'key', takesValue: true, meaning: '32 hexadecimal characters for exact replay; defaults to a stable feedback identity' }]),
|
|
165
166
|
],
|
|
166
167
|
})),
|
|
168
|
+
{ invocation: "task merge", synopsis: "merge the task's pull request once its checks pass — the console's Merge, behind the approver's password; the project's method (squash by default), branch deleted, recorded in the ledger",
|
|
169
|
+
audience: "operator", agentMayInvoke: false, mutation: "identity-idempotent",
|
|
170
|
+
positionals: [{ name: "task", required: true, meaning: "any version of the task" }],
|
|
171
|
+
flags: [jsonFlag, dbFlag, { name: "as", takesValue: true, meaning: "the approver merging" }, { name: "token", takesValue: true, meaning: "their password" }],
|
|
172
|
+
notableReasons: ["usage", "not-an-approver"] },
|
|
167
173
|
...["show", "updates", "claim", "check", "brief", "inbox", "ack"].map(action => ({
|
|
168
174
|
invocation: `assignment ${action}`,
|
|
169
175
|
synopsis: action === "show" ? "read the root, current work, owner and exact receipt"
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { type VerifiedApprover } from './principal.js';
|
|
2
|
+
import { type PullRequestView } from './pull-request-flow.js';
|
|
3
|
+
import type { PublishExec } from './publish.js';
|
|
2
4
|
import type { Store } from './store.js';
|
|
3
5
|
export declare function runTaskOutcomeCommand(action: 'complete' | 'revise', positional: readonly string[], flags: Map<string, string | true>, context: {
|
|
4
6
|
store: Store;
|
|
@@ -8,3 +10,19 @@ export declare function runTaskOutcomeCommand(action: 'complete' | 'revise', pos
|
|
|
8
10
|
now: Date;
|
|
9
11
|
operator: () => Promise<VerifiedApprover | null>;
|
|
10
12
|
}): Promise<number>;
|
|
13
|
+
/** `task merge <task>`: the console's Merge — the newest pull request any version of the task opened through
|
|
14
|
+
* Complete, merged behind the approver's password once a fresh read shows its checks passing. */
|
|
15
|
+
export declare function runTaskMergeCommand(positional: readonly string[], flags: Map<string, string | true>, context: {
|
|
16
|
+
store: Store;
|
|
17
|
+
json: boolean;
|
|
18
|
+
write: (line: string) => void;
|
|
19
|
+
clock: () => Date;
|
|
20
|
+
exec?: PublishExec;
|
|
21
|
+
demo: boolean;
|
|
22
|
+
credentials: () => Promise<{
|
|
23
|
+
name: string;
|
|
24
|
+
token: string;
|
|
25
|
+
} | null>;
|
|
26
|
+
}): Promise<number>;
|
|
27
|
+
/** The lines `task show` prints for a task's pull request. */
|
|
28
|
+
export declare function pullRequestLines(view: PullRequestView | null): string[];
|