toolroll 0.9.83 → 0.9.85
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 +69 -0
- package/README.md +94 -1192
- package/dist/agent-fence.d.ts +3 -3
- package/dist/agent-fence.js +3 -3
- package/dist/agent-onboard.d.ts +2 -0
- package/dist/agent-onboard.js +3 -0
- package/dist/assignment-ui.js +5 -1
- package/dist/browser/workspace.css +2 -2
- package/dist/browser/workspace.js +31 -31
- package/dist/browser-crew.js +5 -1
- package/dist/browser-workspace.d.ts +12 -0
- package/dist/chat-channel.d.ts +10 -1
- package/dist/chat-channel.js +35 -5
- package/dist/chat-decide.d.ts +16 -4
- package/dist/chat-decide.js +239 -31
- package/dist/chat-messages.d.ts +5 -0
- package/dist/chat-messages.js +1 -1
- package/dist/chat-quiet.js +3 -2
- package/dist/chat-review.d.ts +4 -0
- package/dist/chat-review.js +13 -4
- package/dist/chat-terms.d.ts +9 -0
- package/dist/chat-terms.js +46 -0
- package/dist/contracts/console-api.d.ts +4 -2
- package/dist/contracts/console-api.js +7 -2
- package/dist/contracts/lead-tools.d.ts +30 -0
- package/dist/contracts/lead-tools.js +3 -0
- package/dist/contracts/youiyoux-request.d.ts +248 -0
- package/dist/contracts/youiyoux-request.js +152 -0
- package/dist/control-setup.d.ts +9 -0
- package/dist/control-setup.js +31 -4
- package/dist/control-ui.d.ts +7 -1
- package/dist/control-ui.js +3 -2
- package/dist/desktop-update.d.ts +1 -1
- package/dist/dispatch.d.ts +15 -0
- package/dist/dispatch.js +26 -4
- package/dist/first-run.d.ts +5 -2
- package/dist/first-run.js +13 -2
- package/dist/flow-cadence.d.ts +8 -2
- package/dist/flow-cadence.js +16 -3
- package/dist/flow-card-task.d.ts +9 -0
- package/dist/flow-card-task.js +15 -6
- package/dist/folder-look.d.ts +3 -0
- package/dist/folder-look.js +8 -4
- package/dist/guides.js +4 -3
- package/dist/integrations-ui.js +9 -4
- package/dist/integrations.d.ts +9 -1
- package/dist/integrations.js +43 -2
- package/dist/landed-cleanup.d.ts +4 -0
- package/dist/landed-cleanup.js +3 -2
- package/dist/lead-capabilities.js +2 -1
- package/dist/lead-cli.js +3 -1
- package/dist/lead-tools.d.ts +2 -0
- package/dist/lead-tools.js +30 -4
- package/dist/lead.d.ts +2 -0
- package/dist/lead.js +3 -3
- package/dist/model-catalog.d.ts +5 -0
- package/dist/model-catalog.js +11 -2
- package/dist/model-choices.d.ts +188 -0
- package/dist/model-choices.js +405 -0
- package/dist/model-names.d.ts +6 -0
- package/dist/model-names.js +34 -0
- package/dist/models-ui.d.ts +69 -5
- package/dist/models-ui.js +53 -10
- package/dist/needs-you.d.ts +8 -0
- package/dist/needs-you.js +8 -0
- package/dist/operate.d.ts +22 -2
- package/dist/operate.js +107 -41
- package/dist/project-activity.d.ts +20 -0
- package/dist/project-activity.js +23 -0
- package/dist/project-admission.d.ts +4 -1
- package/dist/project-admission.js +23 -2
- package/dist/project-cli.d.ts +1 -0
- package/dist/project-cli.js +36 -19
- package/dist/project-identity.d.ts +9 -2
- package/dist/project-identity.js +80 -33
- package/dist/project-knowledge.d.ts +9 -9
- package/dist/project-outcomes.d.ts +119 -0
- package/dist/project-outcomes.js +79 -0
- package/dist/result-actions.d.ts +4 -0
- package/dist/result-actions.js +41 -9
- package/dist/result-review.d.ts +9 -0
- package/dist/result-review.js +45 -5
- package/dist/serve.js +60 -13
- package/dist/server/chat.js +5 -4
- package/dist/server/chrome.d.ts +3 -0
- package/dist/server/chrome.js +5 -2
- package/dist/server/console.css +17 -2
- package/dist/server/flows.js +4 -0
- package/dist/server/http.d.ts +1 -0
- package/dist/server/http.js +6 -0
- package/dist/server/pages.js +53 -7
- package/dist/server/people-tokens.js +40 -20
- package/dist/server/render-chat.js +3 -2
- package/dist/server/render-pages.d.ts +12 -2
- package/dist/server/render-pages.js +36 -16
- package/dist/server/render-people.d.ts +14 -2
- package/dist/server/render-people.js +35 -12
- package/dist/server/render-results.d.ts +2 -0
- package/dist/server/render-results.js +20 -7
- package/dist/server/render-settings.js +1 -0
- package/dist/server/render-tasks.d.ts +1 -0
- package/dist/server/render-tasks.js +22 -19
- package/dist/server/request-context.d.ts +2 -0
- package/dist/server/route-table.js +9 -1
- package/dist/server/settings.d.ts +58 -1
- package/dist/server/settings.js +216 -70
- package/dist/server/signup-gate.d.ts +9 -0
- package/dist/server/signup-gate.js +40 -0
- package/dist/server/task-views.js +6 -0
- package/dist/server/tasks.js +54 -8
- package/dist/settings-kit-script.d.ts +21 -0
- package/dist/settings-kit-script.js +67 -0
- package/dist/settings-kit.d.ts +137 -0
- package/dist/settings-kit.js +186 -0
- package/dist/settings-proofs.d.ts +64 -0
- package/dist/settings-proofs.js +101 -0
- package/dist/setup-guide.js +4 -2
- package/dist/spend-report.d.ts +87 -0
- package/dist/spend-report.js +265 -0
- package/dist/spend-ui.d.ts +29 -8
- package/dist/spend-ui.js +74 -39
- package/dist/store.d.ts +46 -3
- package/dist/store.js +165 -6
- package/dist/task-sizing.d.ts +5 -3
- package/dist/task-sizing.js +4 -4
- package/dist/task-source.d.ts +13 -1
- package/dist/task-source.js +17 -1
- package/dist/telegram-lead.js +7 -5
- package/dist/telegram.js +1 -1
- package/dist/toolroll-update.js +2 -2
- package/dist/webhooks.d.ts +6 -0
- package/dist/webhooks.js +25 -0
- package/dist/work-index.d.ts +4 -0
- package/dist/work-index.js +32 -0
- package/dist/youiyoux-intake.d.ts +234 -0
- package/dist/youiyoux-intake.js +908 -0
- package/package.json +11 -8
|
@@ -614,6 +614,8 @@ export type ResultDetail = {
|
|
|
614
614
|
fileAnchors: ReadonlyMap<string, string>;
|
|
615
615
|
comments: DiffComment[];
|
|
616
616
|
pastComments?: DiffComment[];
|
|
617
|
+
/** Live saved notes whose screenshot would be refused now (result-actions.ts feedbackImageProblem). */
|
|
618
|
+
unusableImageNotes?: readonly number[];
|
|
617
619
|
reviewerFindings: DiffComment[];
|
|
618
620
|
/** The build's one automatic review, when its project had review on. */
|
|
619
621
|
automaticReview?: BuildReviewView | null;
|
|
@@ -1068,7 +1068,7 @@ export function proofBundleView(store, run, artifacts, root) {
|
|
|
1068
1068
|
catch {
|
|
1069
1069
|
problem = "the file could not be read";
|
|
1070
1070
|
}
|
|
1071
|
-
return [{ path, caption: captionFor(path), artifactId: artifact.id, problem }];
|
|
1071
|
+
return [{ path, caption: captionFor(path), artifactId: artifact.id, sha256: artifact.sha256, problem }];
|
|
1072
1072
|
});
|
|
1073
1073
|
const stored = new Set(screenshots.map(one => one.path));
|
|
1074
1074
|
const uncapturedScreenshots = (proof?.screenshots ?? []).map(one => one.path).filter(path => !stored.has(path));
|
|
@@ -1598,6 +1598,8 @@ export function resultPanelParts(detail, o) {
|
|
|
1598
1598
|
const physicalReasons = receipt.reasons.filter(reason => !assessmentReasons.has(reason));
|
|
1599
1599
|
const runId = run.id;
|
|
1600
1600
|
const shots = proof?.screenshots ?? [];
|
|
1601
|
+
const picture = (shot) => html `<figure class="result-image"><a class="receipt-shot" href="/r/${runId}/evidence/${shot.artifactId}"><img src="/r/${runId}/evidence/${shot.artifactId}" alt="${shot.caption}"><span>${shot.caption}</span></a>${detail.canAnnotate && o.csrf !== "" && shot.sha256 !== undefined
|
|
1602
|
+
? html `<button type="button" class="quiet" data-comment-image="${JSON.stringify({ run: runId, artifact: shot.artifactId, sha256: shot.sha256 })}" data-image-caption="${shot.caption}">Comment</button>` : ""}</figure>`;
|
|
1601
1603
|
const shown = shots.filter(one => one.problem === null);
|
|
1602
1604
|
const stat = terminal?.stat ?? null;
|
|
1603
1605
|
const statOk = stat !== null && !("problem" in stat);
|
|
@@ -1694,7 +1696,7 @@ export function resultPanelParts(detail, o) {
|
|
|
1694
1696
|
}
|
|
1695
1697
|
else if (lead === "screenshots") {
|
|
1696
1698
|
summaryParts.push(html `<div class="receipt-visuals result-visuals" aria-label="validated screenshots">${shown
|
|
1697
|
-
.map(
|
|
1699
|
+
.map(picture)}</div>`);
|
|
1698
1700
|
}
|
|
1699
1701
|
const unavailableShots = shots.filter(one => one.problem !== null);
|
|
1700
1702
|
if (lead === "changes") {
|
|
@@ -1848,7 +1850,7 @@ export function resultPanelParts(detail, o) {
|
|
|
1848
1850
|
? directAssessment && !screenshotRequired ? html `` : html `<p class="meta" data-cockpit-source="screenshots">No screenshots${screenshotRequired ? " were captured, although one was required" : " were needed"}.</p>`
|
|
1849
1851
|
: lead === "screenshots"
|
|
1850
1852
|
? html `<p class="meta" data-cockpit-source="screenshots">${shown.length} validated screenshot${shown.length === 1 ? "" : "s"} shown in Summary${unavailableShots.length > 0 ? `; ${unavailableShots.length} unavailable` : ""}.</p>`
|
|
1851
|
-
: html `<details class="cockpit-proof-group" data-cockpit-source="screenshots"><summary>Screenshots · ${shown.length}${unavailableShots.length > 0 ? ` (${unavailableShots.length} unavailable)` : ""}</summary><div class="receipt-visuals" aria-label="validated screenshots">${shown.map(
|
|
1853
|
+
: html `<details class="cockpit-proof-group" data-cockpit-source="screenshots"><summary>Screenshots · ${shown.length}${unavailableShots.length > 0 ? ` (${unavailableShots.length} unavailable)` : ""}</summary><div class="receipt-visuals" aria-label="validated screenshots">${shown.map(picture)}</div></details>`);
|
|
1852
1854
|
checkParts.push(receipt.caveats.length === 0
|
|
1853
1855
|
? directAssessment ? html `` : html `<p class="meta" data-cockpit-source="caveats">No caveats were reported.</p>`
|
|
1854
1856
|
: html `<details class="cockpit-proof-group" data-cockpit-source="caveats"><summary>Agent caveats · ${receipt.caveats.length}</summary><ul>${receipt.caveats.map(one => html `<li>${one}</li>`)}</ul></details>`);
|
|
@@ -1863,19 +1865,29 @@ export function resultPanelParts(detail, o) {
|
|
|
1863
1865
|
checkParts.push(o.extraChecks);
|
|
1864
1866
|
// ---- request changes: both feedback styles, one sealed road ------------
|
|
1865
1867
|
const requestParts = [html `<h3 class="so-sr-only">What should change?</h3>`];
|
|
1868
|
+
const imageNote = (one) => {
|
|
1869
|
+
if (one.image == null)
|
|
1870
|
+
return html ``;
|
|
1871
|
+
const shot = shots.find(shot => shot.artifactId === one.image.artifact && shot.sha256 === one.image.sha256 && one.image.run === runId && shot.problem === null);
|
|
1872
|
+
// A live saved note whose screenshot no longer verifies can be kept without it, so it never blocks a revision.
|
|
1873
|
+
const drop = o.csrf === "" || !(detail.unusableImageNotes ?? []).includes(one.id) ? html ``
|
|
1874
|
+
: postForm(`/r/${runId}/comment`, html `<input type="hidden" name="intent" value="drop-image"><input type="hidden" name="comment" value="${String(one.id)}"><button type="submit" class="quiet">Keep note without screenshot</button>`, { attrs: { class: "feedback-image-drop" }, returnTo: o.returnTo, hidden: { tab: o.tab } });
|
|
1875
|
+
return html `<figure class="feedback-image">${shot === undefined ? html `<figcaption>Screenshot ${one.image.artifact} is unavailable.</figcaption>`
|
|
1876
|
+
: html `<a href="/r/${runId}/evidence/${shot.artifactId}"><img src="/r/${runId}/evidence/${shot.artifactId}" alt="${shot.caption}"></a><figcaption>${shot.caption} · Screenshot ${shot.artifactId}</figcaption>`}${drop}</figure>`;
|
|
1877
|
+
};
|
|
1866
1878
|
const pathWords = (path, line) => {
|
|
1867
1879
|
const shownPath = `${path}${line === null ? "" : `:${line}`}`;
|
|
1868
1880
|
const href = detail.editor === null ? null : editorFileHref(detail.editor.worktree, path, line);
|
|
1869
1881
|
return href === null ? html `<span class="mono">${shownPath}</span> ` : html `<a class="mono" href="${href}">${shownPath}</a> `;
|
|
1870
1882
|
};
|
|
1871
1883
|
if (detail.comments.length > 0) {
|
|
1872
|
-
requestParts.push(html `<p class="meta">Saved for later · ${detail.comments.length}</p><div class="diff-comments" data-result-notes="${detail.comments.length}">${detail.comments.map(one => html `<div class="diff-comment"
|
|
1884
|
+
requestParts.push(html `<p class="meta">Saved for later · ${detail.comments.length}</p><div class="diff-comments" data-result-notes="${detail.comments.length}">${detail.comments.map(one => html `<div class="diff-comment">${imageNote(one)}<span class="diff-comment-pin" aria-hidden="true"></span><p>${one.path === null ? "" : pathWords(one.path, one.line)}${one.note}</p><span class="meta">${one.author} · ${whenTime(one.createdAt)}</span></div>`)}</div>`);
|
|
1873
1885
|
if (o.csrf !== "" && !detail.canAnnotate) {
|
|
1874
1886
|
requestParts.push(postForm(`/r/${runId}/revise`, html `${revisionSealFields(detail.comments, detail.sourceDigest)}<div><strong>${detail.comments.length} note${detail.comments.length === 1 ? "" : "s"} ready</strong></div><button type="submit">Request changes</button>`, { attrs: { class: "card revision-from-comments" }, returnTo: o.returnTo }));
|
|
1875
1887
|
}
|
|
1876
1888
|
}
|
|
1877
1889
|
if ((detail.pastComments?.length ?? 0) > 0) {
|
|
1878
|
-
requestParts.push(html `<details class="result-feedback-history"><summary>Earlier feedback</summary><div class="diff-comments" data-past-feedback>${detail.pastComments.map(one => html `<div class="diff-comment"
|
|
1890
|
+
requestParts.push(html `<details class="result-feedback-history"><summary>Earlier feedback</summary><div class="diff-comments" data-past-feedback>${detail.pastComments.map(one => html `<div class="diff-comment">${imageNote(one)}<p>${one.path === null ? "" : pathWords(one.path, one.line)}${one.note}</p><span class="meta">${one.author} · ${whenTime(one.createdAt)}</span></div>`)}</div></details>`);
|
|
1879
1891
|
}
|
|
1880
1892
|
for (const revision of detail.revisions) {
|
|
1881
1893
|
// The child's standing is the shared status projection's own words
|
|
@@ -1892,6 +1904,7 @@ export function resultPanelParts(detail, o) {
|
|
|
1892
1904
|
requestParts.push(html `<details class="result-request-open result-request-form"${detail.comments.length > 0 ? " open" : ""}><summary>What should change?</summary>${postForm(`/r/${runId}/comment`, joinHtml([
|
|
1893
1905
|
revisionSealFields(detail.comments, detail.sourceDigest),
|
|
1894
1906
|
html `<input type="hidden" data-recorded-requests value="${[...detail.comments, ...(detail.pastComments ?? [])].filter(one => one.sourceKey?.startsWith(`review:${o.user}:`)).map(one => one.sourceKey.slice(`review:${o.user}:`.length)).join(",")}">`,
|
|
1907
|
+
html `<input type="hidden" name="image" value=""><figure class="feedback-image" data-feedback-image hidden><img alt="Selected screenshot" hidden><figcaption></figcaption><button type="button" class="quiet" data-remove-image>Remove image</button></figure>`,
|
|
1895
1908
|
html `<textarea name="note" rows="2" maxlength="${LIMITS.note}" placeholder="Describe the change…" aria-label="review comment" aria-describedby="comment-note-limit"${o.noted ? " autofocus" : ""}></textarea>`,
|
|
1896
1909
|
html `<span class="meta diff-comment-limit" id="comment-note-limit">up to ${LIMITS.note} characters</span>`,
|
|
1897
1910
|
html `<details class="result-pin"><summary>Attach to a file or line</summary>`,
|
|
@@ -1980,7 +1993,7 @@ export function personCheckItems(proof, patchText, shots, runId) {
|
|
|
1980
1993
|
return {
|
|
1981
1994
|
id: row.id, statement: row.statement, words: personCheckWords(row.statement), note: notes.length === 0 ? null : notes.join(" "),
|
|
1982
1995
|
excerpts: files.filter(one => one.lines.length > 0).slice(0, 3),
|
|
1983
|
-
shots: pictures.slice(0, 4).map(shot => ({ src: `/r/${runId}/evidence/${shot.artifactId}`, href: `/r/${runId}/evidence/${shot.artifactId}`, caption: shot.caption })),
|
|
1996
|
+
shots: pictures.slice(0, 4).map(shot => ({ src: `/r/${runId}/evidence/${shot.artifactId}`, href: `/r/${runId}/evidence/${shot.artifactId}`, caption: shot.caption, ...(shot.sha256 === undefined ? {} : { image: { run: runId, artifact: shot.artifactId, sha256: shot.sha256 } }) })),
|
|
1984
1997
|
};
|
|
1985
1998
|
});
|
|
1986
1999
|
}
|
|
@@ -2215,7 +2228,7 @@ export function runPage(chrome, run, taskId, artifacts, terminal = null, notes =
|
|
|
2215
2228
|
noted,
|
|
2216
2229
|
requestToken: result.requestToken,
|
|
2217
2230
|
hrefFor: one => (one === "summary" ? `/r/${run.id}` : `/r/${run.id}?tab=${one}`),
|
|
2218
|
-
returnTo: `/r/${run.id}`,
|
|
2231
|
+
returnTo: `/r/${run.id}?record=1`,
|
|
2219
2232
|
back: null,
|
|
2220
2233
|
});
|
|
2221
2234
|
return screen(`build #${run.id}`, joinHtml([
|
|
@@ -511,6 +511,7 @@ export const SETTINGS_GROUPS = [
|
|
|
511
511
|
["Agents", [
|
|
512
512
|
["/settings/lead", "Lead", html `<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/><path d="M8 9h8M8 13h5"/>`],
|
|
513
513
|
["/settings/models", "Models", html `<rect x="4" y="4" width="16" height="16" rx="2"/><rect x="9" y="9" width="6" height="6"/><path d="M9 2v2M15 2v2M9 20v2M15 20v2M2 9h2M2 15h2M20 9h2M20 15h2"/>`],
|
|
514
|
+
["/settings/spend", "Spend", html `<circle cx="12" cy="12" r="9"/><path d="M15 9.5c-.6-.9-1.7-1.5-3-1.5-1.7 0-3 .9-3 2s1.3 1.7 3 2 3 .9 3 2-1.3 2-3 2c-1.3 0-2.4-.6-3-1.5M12 6v2M12 16v2"/>`],
|
|
514
515
|
["/settings/skills", "Skills", html `<path d="m12 3 1.9 5.8L20 10l-5 3.6L16.8 20 12 16.4 7.2 20 9 13.6 4 10l6.1-1.2z"/>`],
|
|
515
516
|
["/settings/tools", "Tools", html `<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/>`],
|
|
516
517
|
["/settings/knowledge", "Knowledge", html `<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20V3H6.5A2.5 2.5 0 0 0 4 5.5z"/><path d="M4 19.5A2.5 2.5 0 0 0 6.5 22H20v-5"/>`],
|
|
@@ -398,6 +398,7 @@ export type RevisionView = {
|
|
|
398
398
|
line: number | null;
|
|
399
399
|
note: string;
|
|
400
400
|
author: string;
|
|
401
|
+
image?: import("../result-review.js").FeedbackImage | null;
|
|
401
402
|
}[];
|
|
402
403
|
/** The lineage and ACTUAL terms (contract handoff task 2), read from
|
|
403
404
|
* the child's own rows — the same projection chat and the approval
|
|
@@ -25,13 +25,14 @@ import { taskRoad } from "../first-run.js";
|
|
|
25
25
|
import { starterForWork } from "../flow-starters.js";
|
|
26
26
|
import {} from "../gaps.js";
|
|
27
27
|
import { readAuthModeStrict } from "../keys.js";
|
|
28
|
-
import { failedAttemptSentence, retryNoteOf } from "../needs-you.js";
|
|
28
|
+
import { failedAttemptSentence, retryNoteOf, START_BUILDER_COMMAND, startBuilderHref } from "../needs-you.js";
|
|
29
29
|
import { chosenWords, makesNoPlan, PHASES as ROUTE_PHASES, TASK_SIZES } from "../phase-routing.js";
|
|
30
30
|
import { parseExecutionPlanDocument } from "../plan.js";
|
|
31
31
|
import {} from "../planner-source.js";
|
|
32
32
|
import { projectName } from "../project.js";
|
|
33
33
|
import { dispatchStatusToken, manualReviewOnly, plainReasonWords, reviewConflict } from "../proof.js";
|
|
34
34
|
import { providerName } from "../provider-auth.js";
|
|
35
|
+
import { agentModelName } from "../model-names.js";
|
|
35
36
|
import {} from "../provider.js";
|
|
36
37
|
import { qualityModeTitle } from "../quality.js";
|
|
37
38
|
import { evidenceShortenedWords } from "../result-review.js";
|
|
@@ -49,7 +50,7 @@ import { reviewHref, taskChatHref, taskHref } from "./http.js";
|
|
|
49
50
|
import { coordinatorProposalsSection } from "./render-chat.js";
|
|
50
51
|
import { completionReceiptCard, criterionMatrixHtml, evidenceWords, homePhaseWords, incidentWords, needsCheck, pullRequestCardHtml, reasonWords, receiptStatusOf, repairChainHtml, reportItemsHtml, reviewRetryPanel, runNoun, runOutcomeBadge, semanticCoverageHtml, verificationExplanation, verificationRecovered } from "./render-results.js";
|
|
51
52
|
import {} from "./session.js";
|
|
52
|
-
import { linkWords, originNote } from "../task-source.js";
|
|
53
|
+
import { linkWords, originNote, requestName, requestWords } from "../task-source.js";
|
|
53
54
|
export function contractChangeHtml(change) {
|
|
54
55
|
const tag = html `<span class="contract-change-kind contract-change-${change.kind}">${change.kind}</span>`;
|
|
55
56
|
switch (change.field) {
|
|
@@ -134,17 +135,7 @@ export function acceptanceCeremonyHtml(criteria) {
|
|
|
134
135
|
}
|
|
135
136
|
/** "claude" + "opus" → "Claude Opus"; "claude-opus-5-5" → "Claude Opus 5.5"; anything else keeps its exact id. */
|
|
136
137
|
export function agentNameWords(provider, model) {
|
|
137
|
-
|
|
138
|
-
if (model === null || model === "" || model === "default")
|
|
139
|
-
return name;
|
|
140
|
-
const bare = model.startsWith(`${provider}-`) ? model.slice(provider.length + 1) : model;
|
|
141
|
-
const title = (word) => `${word[0].toUpperCase()}${word.slice(1)}`;
|
|
142
|
-
if (/^[a-z]+$/.test(bare))
|
|
143
|
-
return `${name} ${title(bare)}`;
|
|
144
|
-
const versioned = /^([a-z]+)-(\d+(?:-\d+)*)$/.exec(bare);
|
|
145
|
-
if (versioned !== null)
|
|
146
|
-
return `${name} ${title(versioned[1])} ${versioned[2].replace(/-/g, ".")}`;
|
|
147
|
-
return `${name} ${model}`;
|
|
138
|
+
return agentModelName(provider, model);
|
|
148
139
|
}
|
|
149
140
|
/** The permission a sealed profile grants, in two or three words. */
|
|
150
141
|
export function permissionWordsOf(profile) {
|
|
@@ -212,7 +203,8 @@ const fragmentString = (fragment) => fragment === "" ? "" : htmlString(fragment)
|
|
|
212
203
|
function originWords(origin) {
|
|
213
204
|
const flow = origin.flow === null ? null : origin.flow === "hidden" ? "from a flow" : origin.flow === "removed" ? "from a flow (removed)" : `from flow “${origin.flow.name}”`;
|
|
214
205
|
const source = origin.source === null ? null : `${origin.source.label} (${origin.source.proved})`;
|
|
215
|
-
|
|
206
|
+
const request = origin.request == null ? null : `from ${requestName(origin.request)}`;
|
|
207
|
+
return [flow, source, request].filter(one => one !== null).join(" · ");
|
|
216
208
|
}
|
|
217
209
|
/** v126: a task's origin as a fact: the flow, linked for those who may open it, and the outside event, linked to where
|
|
218
210
|
* it lives, with that link's host always shown. */
|
|
@@ -228,6 +220,12 @@ function originParts(origin) {
|
|
|
228
220
|
if (origin.source.url !== null)
|
|
229
221
|
parts.push(" · ", { label: linkWords(origin.source.url), href: origin.source.url });
|
|
230
222
|
}
|
|
223
|
+
if (origin.request != null) {
|
|
224
|
+
if (parts.length > 0)
|
|
225
|
+
parts.push(" · ");
|
|
226
|
+
const where = requestWords(origin.request);
|
|
227
|
+
parts.push(`${requestName(origin.request)}${where === "" ? "" : `: ${where}`}`);
|
|
228
|
+
}
|
|
231
229
|
return parts;
|
|
232
230
|
}
|
|
233
231
|
export function approvalSheetHtml(input) {
|
|
@@ -303,7 +301,7 @@ export function approvalSheetHtml(input) {
|
|
|
303
301
|
const revisionDetail = input.revision === null ? "" : detail("Earlier build", joinHtml([
|
|
304
302
|
html `<div class="revision-card" data-revision-feedback>`,
|
|
305
303
|
html `<p><a href="${input.revisionSourceHref}"${input.surface === "chat" ? html ` data-revision-source` : ""}>${input.surface === "chat" ? html `Original result: build #${input.revision.sourceRun} →` : html `build #${input.revision.sourceRun}`}</a></p>`,
|
|
306
|
-
input.revision.comments.length === 0 ? "" : html `<ul>${input.revision.comments.map(one => html `<li>${one.path === null ? "" : html `<span class="mono">${one.path}${one.line === null ? "" : `:${one.line}`}</span> · `}${one.note} <span class="meta">— ${one.author}</span></li>`)}</ul>`,
|
|
304
|
+
input.revision.comments.length === 0 ? "" : html `<ul>${input.revision.comments.map(one => html `<li>${revisionImageLink(one.image)}${one.path === null ? "" : html `<span class="mono">${one.path}${one.line === null ? "" : `:${one.line}`}</span> · `}${one.note} <span class="meta">— ${one.author}</span></li>`)}</ul>`,
|
|
307
305
|
revisionLineageHtml(input.revision.lineage),
|
|
308
306
|
html `</div>`,
|
|
309
307
|
]));
|
|
@@ -815,7 +813,9 @@ export function taskRecoveryHref(taskId, diagnosis) {
|
|
|
815
813
|
return null;
|
|
816
814
|
const task = taskHref(taskId);
|
|
817
815
|
switch (diagnosis.action) {
|
|
816
|
+
// The task page only repeats that no builder is connected: lead to the command that connects one.
|
|
818
817
|
case "start-worker":
|
|
818
|
+
return startBuilderHref(taskId);
|
|
819
819
|
case "repair-dependency":
|
|
820
820
|
return `${task}#run-status`;
|
|
821
821
|
case "retry-task":
|
|
@@ -1179,6 +1179,9 @@ export function executionPlanHtml(document, compact = false) {
|
|
|
1179
1179
|
html `</div>`,
|
|
1180
1180
|
]);
|
|
1181
1181
|
}
|
|
1182
|
+
function revisionImageLink(image) {
|
|
1183
|
+
return image == null ? html `` : html `<a href="/r/${image.run}/evidence/${image.artifact}">Screenshot ${image.artifact} · result #${image.run}</a> · `;
|
|
1184
|
+
}
|
|
1182
1185
|
/**
|
|
1183
1186
|
* A revision's lineage and ACTUAL terms, in the same words on the task
|
|
1184
1187
|
* page, the approval card, and chat (contract handoff task 2): which
|
|
@@ -1350,11 +1353,11 @@ export function taskBodyParts(data) {
|
|
|
1350
1353
|
firstConnection
|
|
1351
1354
|
? html `<p>Toolroll is open, but this project has not been connected to a builder yet.</p><p>On the machine where the project lives, open that folder and run:</p>`
|
|
1352
1355
|
: html `<p>Toolroll is open, but this project's builder stopped checking in. Reopen Toolroll on the machine where the project lives.</p><p>If you normally start it from a terminal, open the project folder and run:</p>`,
|
|
1353
|
-
html `<code class="dispatch-recovery-command"
|
|
1356
|
+
html `<code class="dispatch-recovery-command">${START_BUILDER_COMMAND}</code>`,
|
|
1354
1357
|
firstConnection
|
|
1355
1358
|
? html `<p class="meta">This is the normal start command: it opens the app, connects the project, and starts its builder. Keep Toolroll running; approved tasks begin automatically.</p>`
|
|
1356
1359
|
: html `<p class="meta">This task resumes automatically when the builder reconnects. You do not need to file or approve it again.</p>`,
|
|
1357
|
-
html `<p><a href="
|
|
1360
|
+
html `<p><a href="${startBuilderHref(task.id)}">See connection status →</a></p></div></details>`,
|
|
1358
1361
|
]);
|
|
1359
1362
|
}
|
|
1360
1363
|
// Never a link to this page's own acts: Retry sits on the status card and below.
|
|
@@ -1601,7 +1604,7 @@ export function taskBodyParts(data) {
|
|
|
1601
1604
|
: joinHtml([
|
|
1602
1605
|
html `<div class="revision-card" data-revision-feedback>`,
|
|
1603
1606
|
html `<p><strong>${data.revision.kind === "ci-repair" ? "CI repair" : data.revision.kind === "criterion-repair" ? "Criterion repair" : "Revision feedback"}</strong> <span class="meta">from <a href="/r/${data.revision.sourceRun}">build #${data.revision.sourceRun}</a></span></p>`,
|
|
1604
|
-
...data.revision.comments.map(one => html `<p class="row"><span class="meta">${one.author}</span> ${one.path === null ? "" : html `<span class="mono">${one.path}${one.line === null ? "" : `:${one.line}`}</span> `}${one.note}</p>`),
|
|
1607
|
+
...data.revision.comments.map(one => html `<p class="row"><span class="meta">${one.author}</span> ${revisionImageLink(one.image)}${one.path === null ? "" : html `<span class="mono">${one.path}${one.line === null ? "" : `:${one.line}`}</span> `}${one.note}</p>`),
|
|
1605
1608
|
revisionLineageHtml(data.revision.lineage),
|
|
1606
1609
|
html `</div>`,
|
|
1607
1610
|
], "\n");
|
|
@@ -2177,7 +2180,7 @@ export function taskBodyParts(data) {
|
|
|
2177
2180
|
const feedback = data.revision;
|
|
2178
2181
|
thread.push({ key: "revision", at: task.createdAt, kind: "reply", who: "person", author: feedback.comments[0]?.author ?? "You",
|
|
2179
2182
|
title: feedback.kind === "ci-repair" ? "Asked for a CI repair" : feedback.kind === "criterion-repair" ? "Asked for a repair" : "Asked for changes",
|
|
2180
|
-
text: feedback.comments.map(one => `${one.path === null ? "" : `${one.path}${one.line === null ? "" : `:${one.line}`} — `}${one.note.trim()}`).filter(one => one !== "").join("\n") || null,
|
|
2183
|
+
text: feedback.comments.map(one => `${one.image ? `Screenshot ${one.image.artifact} · result #${one.image.run} — ` : ""}${one.path === null ? "" : `${one.path}${one.line === null ? "" : `:${one.line}`} — `}${one.note.trim()}`).filter(one => one !== "").join("\n") || null,
|
|
2181
2184
|
link: { label: `From build #${feedback.sourceRun}`, href: `/r/${feedback.sourceRun}` }, html: "", more: null });
|
|
2182
2185
|
}
|
|
2183
2186
|
for (const decision of data.decisions) {
|
|
@@ -43,6 +43,8 @@ export type RequestFacts = {
|
|
|
43
43
|
};
|
|
44
44
|
/** Passwordless is on and this is a signed-in browser: ceremony password fields render as nothing (html.ts reauth). */
|
|
45
45
|
passwordless?: boolean;
|
|
46
|
+
/** The browser session's open project (display only: the sidebar's picker names it). */
|
|
47
|
+
openProject?: string | null;
|
|
46
48
|
};
|
|
47
49
|
/**
|
|
48
50
|
* The request's own session facts, readable from anywhere below the
|
|
@@ -133,12 +133,15 @@ get("pages", "workbench", "/workbench", free);
|
|
|
133
133
|
get("tasks", "board", "/board", { limited: "collection" });
|
|
134
134
|
get("tasks", "review", "/review", { limited: "collection" });
|
|
135
135
|
get("settings", "spend", "/spend", { ...free, ...anyOperator("An instance operator sees spend.", "/") });
|
|
136
|
+
get("settings", "settings.spend", "/settings/spend", { ...free, ...anyOperator("An instance operator sets spending limits.", "/settings") });
|
|
136
137
|
get("pages", "ledger", "/ledger", { limited: "unscoped", ...free });
|
|
137
138
|
get("pages", "activity", "/activity");
|
|
138
139
|
get("tasks", "done", "/done", { limited: "collection" });
|
|
139
140
|
get("settings", "mode", "/mode");
|
|
140
141
|
get("people", "people.page", "/people", { limited: "unscoped", ...free });
|
|
141
142
|
get("pages", "system", "/system");
|
|
143
|
+
// Where every "Connect a builder" leads: read-only, open to a project-limited person (the handler shows only a visible project).
|
|
144
|
+
get("pages", "start-builder", "/start-builder", { limited: "unscoped", ...free });
|
|
142
145
|
get("tasks", "tasks", "/tasks", { limited: "collection", ...free }); // a redirect to /work now: never sent to the project opener first
|
|
143
146
|
get("tasks", "queue", "/queue");
|
|
144
147
|
get("pages", "peek", "/peek", free);
|
|
@@ -333,9 +336,14 @@ for (const one of ["policy", "approval", "request-limits", "sessions", "sign-in"
|
|
|
333
336
|
post(one === "sessions" ? "people" : "settings", `settings.${one.replaceAll("/", "-")}-send`, `/settings/${one}`, { ...(["policy", "approval", "request-limits", "sessions", "sign-in", "updates", "updates/seen", "updates/cancel", "retention", "storage", "storage/clean", "storage/discard", "pull-requests", "checks", "backups", "data", "monitoring", "tools/connect", "tools/change"].includes(one) ? { scope: "step-up" } : {}), ...SETTINGS_ACT_ROLES[one] });
|
|
334
337
|
}
|
|
335
338
|
post("settings", "settings.flows-on", "/settings/flows/on", { limited: "collection", ...approver("An approver switches starter flows on.", "/settings/flows") });
|
|
339
|
+
post("settings", "settings.integrations-youiyoux", "/settings/integrations/youiyoux", { limited: "collection", ...approver("An approver turns youiyoux requests on or off.", "/settings/integrations") });
|
|
336
340
|
const MODELS = approver("Sign in as an approver to change models.", "/settings/models");
|
|
337
|
-
for (const one of ["check", "watch", "update"
|
|
341
|
+
for (const one of ["check", "watch", "update"])
|
|
338
342
|
post("settings", `settings.models-${one}`, `/settings/models/${one}`, MODELS);
|
|
343
|
+
// Changing which model a role uses: an instance operator's browser step-up (the handler proves the password, or the
|
|
344
|
+
// Passwordless session; model-choices.ts re-proves the session and standing inside its one transaction).
|
|
345
|
+
for (const one of ["agent", "apply"])
|
|
346
|
+
post("settings", `settings.models-${one}`, `/settings/models/${one}`, { scope: "step-up", ...operator("An instance operator changes models.", "/settings/models") });
|
|
339
347
|
// Any other models action answers the models area's own refusal.
|
|
340
348
|
post("settings", "settings.models-act", "^\\/settings\\/models\\/.*$", { sample: "/settings/models/unknown", ...MODELS });
|
|
341
349
|
post("settings", "settings.knowledge-refresh", "/settings/knowledge/refresh", { project: "form", limited: "unscoped", ...approver("Sign in as an approver to refresh project context.", "/settings/knowledge") });
|
|
@@ -2,7 +2,7 @@ import type { ServerRuntime } from './runtime.js';
|
|
|
2
2
|
import { type RoleView } from "../models-ui.js";
|
|
3
3
|
export declare function createSettingsHandlers(runtime: ServerRuntime): {
|
|
4
4
|
registrations: import("./handler-registry.js").Registration[];
|
|
5
|
-
modelsView: (canManage: boolean, csrf: string, now: Date, said: string | null, problem: string | null) => {
|
|
5
|
+
modelsView: (canManage: boolean, csrf: string, now: Date, said: string | null, problem: string | null, query?: URLSearchParams) => {
|
|
6
6
|
runtimes: import("../model-catalog.js").RuntimeState[];
|
|
7
7
|
watch: import("../model-catalog.js").WatchState;
|
|
8
8
|
roles: RoleView[];
|
|
@@ -14,5 +14,62 @@ export declare function createSettingsHandlers(runtime: ServerRuntime): {
|
|
|
14
14
|
words: string;
|
|
15
15
|
} | null;
|
|
16
16
|
fresh: import("../model-catalog.js").SeenModel[];
|
|
17
|
+
scope: {
|
|
18
|
+
value: string;
|
|
19
|
+
label: string;
|
|
20
|
+
digest: string;
|
|
21
|
+
options: {
|
|
22
|
+
value: string;
|
|
23
|
+
label: string;
|
|
24
|
+
}[];
|
|
25
|
+
};
|
|
26
|
+
inUse: string | null;
|
|
27
|
+
presets: {
|
|
28
|
+
name: "opus" | "sized";
|
|
29
|
+
label: string;
|
|
30
|
+
words: string;
|
|
31
|
+
inUse: boolean;
|
|
32
|
+
recommended: boolean;
|
|
33
|
+
}[];
|
|
34
|
+
newer: {
|
|
35
|
+
from: string;
|
|
36
|
+
to: string;
|
|
37
|
+
name: string;
|
|
38
|
+
roles: string;
|
|
39
|
+
}[];
|
|
40
|
+
preview: {
|
|
41
|
+
title: string;
|
|
42
|
+
rows: {
|
|
43
|
+
role: string;
|
|
44
|
+
before: string;
|
|
45
|
+
after: string;
|
|
46
|
+
notes: string[];
|
|
47
|
+
}[];
|
|
48
|
+
hidden: {
|
|
49
|
+
scope: string;
|
|
50
|
+
digest: string;
|
|
51
|
+
change: string;
|
|
52
|
+
};
|
|
53
|
+
} | null;
|
|
54
|
+
unresolved: string | null;
|
|
55
|
+
sizing: {
|
|
56
|
+
small: string;
|
|
57
|
+
routine: string;
|
|
58
|
+
large: string;
|
|
59
|
+
risky: string;
|
|
60
|
+
classifier: string;
|
|
61
|
+
};
|
|
62
|
+
routing: string;
|
|
63
|
+
recent: {
|
|
64
|
+
taskId: string;
|
|
65
|
+
runId: number;
|
|
66
|
+
role: string;
|
|
67
|
+
chosen: string;
|
|
68
|
+
ranOn: string;
|
|
69
|
+
}[];
|
|
70
|
+
waiting: {
|
|
71
|
+
taskId: string;
|
|
72
|
+
title: string;
|
|
73
|
+
}[];
|
|
17
74
|
};
|
|
18
75
|
};
|