toolroll 0.9.85 → 0.9.87
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 +83 -0
- package/dist/agent-fence.d.ts +6 -2
- package/dist/agent-fence.js +3 -2
- package/dist/agents-board.d.ts +12 -0
- package/dist/agents-board.js +26 -0
- package/dist/approval-rules-ui.d.ts +4 -1
- package/dist/approval-rules-ui.js +31 -15
- package/dist/assignment-ui.js +1 -1
- package/dist/assignment.js +4 -3
- package/dist/backup-ui.d.ts +5 -4
- package/dist/backup-ui.js +65 -32
- package/dist/browser/terminal.css +1 -1
- package/dist/browser/terminal.js +57 -54
- package/dist/browser/workspace.css +2 -2
- package/dist/browser/workspace.js +35 -68
- package/dist/browser-crew.js +1 -1
- package/dist/browser-workspace.d.ts +363 -177
- package/dist/browser-workspace.js +10 -9
- package/dist/chat-actions.d.ts +11 -1
- package/dist/chat-actions.js +53 -1
- package/dist/chat-channel.js +1 -0
- package/dist/chat-controls.d.ts +1 -1
- package/dist/chat-controls.js +1 -1
- package/dist/chat-quiet.js +3 -2
- package/dist/chat-settings-page.d.ts +29 -9
- package/dist/chat-settings-page.js +59 -28
- package/dist/check-levels-ui.d.ts +2 -1
- package/dist/check-levels-ui.js +67 -58
- package/dist/claim.d.ts +3 -0
- package/dist/claim.js +4 -1
- package/dist/contracts/chat-actions.d.ts +9 -0
- package/dist/contracts/chat-actions.js +3 -0
- package/dist/contracts/cli.d.ts +43 -0
- package/dist/contracts/cli.js +4 -0
- package/dist/contracts/console-api.d.ts +4 -1
- package/dist/contracts/console-api.js +4 -1
- package/dist/contracts/flow-propose.d.ts +4 -1
- package/dist/contracts/flow-propose.js +1 -1
- package/dist/contracts/flow.d.ts +41 -0
- package/dist/contracts/flow.js +4 -2
- package/dist/contracts/lead-tools.d.ts +21 -0
- package/dist/contracts/lead-tools.js +2 -0
- package/dist/contracts/store-json.d.ts +2 -0
- package/dist/contracts/trigger-payloads.d.ts +20 -0
- package/dist/contracts/trigger-payloads.js +4 -0
- package/dist/coordinator.js +1 -0
- package/dist/credentials-ui.d.ts +5 -3
- package/dist/credentials-ui.js +58 -31
- package/dist/deploy-gate.js +4 -0
- package/dist/design/kit.css +685 -0
- package/dist/design/kit.d.ts +208 -0
- package/dist/design/kit.js +177 -0
- package/dist/design/tokens.css +19 -1
- package/dist/discord-settings.js +8 -4
- package/dist/dispatch.d.ts +3 -0
- package/dist/dispatch.js +4 -1
- package/dist/export-ui.d.ts +6 -4
- package/dist/export-ui.js +18 -8
- package/dist/flow-browser.d.ts +103 -0
- package/dist/flow-browser.js +204 -0
- package/dist/flow-changed.d.ts +14 -0
- package/dist/flow-changed.js +53 -0
- package/dist/flow-code.d.ts +5 -1
- package/dist/flow-code.js +4 -1
- package/dist/flow-engine.js +16 -0
- package/dist/flow-gallery-ui.d.ts +41 -4
- package/dist/flow-gallery-ui.js +95 -63
- package/dist/flow-live.js +9 -1
- package/dist/flow-pull-request.js +15 -7
- package/dist/flow-share.js +3 -1
- package/dist/flow-starters-ui.d.ts +3 -9
- package/dist/flow-starters-ui.js +12 -23
- package/dist/flow-steps.d.ts +9 -1
- package/dist/flow-steps.js +55 -5
- package/dist/flow-triggers.js +55 -0
- package/dist/flow-unattended-words.d.ts +20 -0
- package/dist/flow-unattended-words.js +24 -0
- package/dist/flow-unattended.d.ts +9 -5
- package/dist/flow-unattended.js +45 -23
- package/dist/flows-cli.d.ts +19 -0
- package/dist/flows-cli.js +54 -5
- package/dist/flows-ui.d.ts +12 -6
- package/dist/flows-ui.js +152 -32
- package/dist/flows.js +5 -2
- package/dist/integrations-ui.d.ts +6 -4
- package/dist/integrations-ui.js +34 -40
- package/dist/integrations.d.ts +2 -2
- package/dist/integrations.js +4 -4
- package/dist/kits-ui.d.ts +8 -10
- package/dist/kits-ui.js +29 -33
- package/dist/kits.js +1 -1
- package/dist/knowledge-ui.js +76 -19
- package/dist/lead-tools.js +35 -6
- package/dist/lead-voice.js +16 -5
- package/dist/ledger-view.d.ts +2 -0
- package/dist/ledger-view.js +41 -38
- package/dist/models-ui.d.ts +8 -3
- package/dist/models-ui.js +82 -59
- package/dist/monitoring-ui.d.ts +4 -2
- package/dist/monitoring-ui.js +44 -13
- package/dist/needs-you.d.ts +1 -1
- package/dist/needs-you.js +8 -0
- package/dist/operate-remote-arguments.js +1 -0
- package/dist/operate-remote.js +1 -1
- package/dist/operate.d.ts +1 -1
- package/dist/operate.js +249 -6
- package/dist/passwordless.d.ts +1 -1
- package/dist/passwordless.js +1 -1
- package/dist/people-audit-ui.d.ts +2 -1
- package/dist/people-audit-ui.js +25 -23
- package/dist/policy-ui.d.ts +3 -2
- package/dist/policy-ui.js +27 -21
- package/dist/policy.d.ts +3 -0
- package/dist/policy.js +14 -1
- package/dist/project-delete-ui.d.ts +4 -2
- package/dist/project-delete-ui.js +135 -126
- package/dist/project-delete.js +7 -3
- package/dist/project-knowledge.d.ts +10 -10
- package/dist/publish.d.ts +11 -0
- package/dist/publish.js +16 -3
- package/dist/pull-request-flow.js +35 -4
- package/dist/pull-request-ui.d.ts +2 -1
- package/dist/pull-request-ui.js +39 -28
- package/dist/recipe-ui.d.ts +4 -2
- package/dist/recipe-ui.js +14 -4
- package/dist/release-adapters.d.ts +3 -0
- package/dist/release-adapters.js +22 -2
- package/dist/release-cli.js +81 -9
- package/dist/release.d.ts +21 -0
- package/dist/release.js +40 -4
- package/dist/releases.js +1 -1
- package/dist/request-budget-ui.d.ts +4 -2
- package/dist/request-budget-ui.js +30 -19
- package/dist/result-follow-ups.js +4 -0
- package/dist/retention-ui.d.ts +4 -3
- package/dist/retention-ui.js +15 -12
- package/dist/scope.d.ts +8 -0
- package/dist/scope.js +13 -0
- package/dist/serve.d.ts +0 -1
- package/dist/serve.js +51 -7
- package/dist/server/agents-computers.d.ts +9 -0
- package/dist/server/agents-computers.js +67 -0
- package/dist/server/chat.js +20 -18
- package/dist/server/chrome.d.ts +1 -1
- package/dist/server/chrome.js +19 -9
- package/dist/server/console.css +31 -2
- package/dist/server/flows.js +79 -36
- package/dist/server/home.d.ts +35 -0
- package/dist/server/home.js +104 -0
- package/dist/server/http.d.ts +3 -0
- package/dist/server/http.js +5 -0
- package/dist/server/kit-standalone.d.ts +22 -0
- package/dist/server/kit-standalone.js +69 -0
- package/dist/server/kit.d.ts +405 -0
- package/dist/server/kit.js +361 -0
- package/dist/server/pages.d.ts +2 -1
- package/dist/server/pages.js +213 -174
- package/dist/server/people-tokens.js +26 -85
- package/dist/server/render-history.d.ts +51 -0
- package/dist/server/render-history.js +228 -0
- package/dist/server/render-new-task.d.ts +29 -0
- package/dist/server/render-new-task.js +96 -0
- package/dist/server/render-next.d.ts +63 -0
- package/dist/server/render-next.js +109 -0
- package/dist/server/render-pages.d.ts +35 -190
- package/dist/server/render-pages.js +154 -563
- package/dist/server/render-people.d.ts +24 -3
- package/dist/server/render-people.js +93 -72
- package/dist/server/render-projects.d.ts +103 -0
- package/dist/server/render-projects.js +247 -0
- package/dist/server/render-results.d.ts +5 -24
- package/dist/server/render-results.js +48 -185
- package/dist/server/render-settings.d.ts +5 -74
- package/dist/server/render-settings.js +102 -493
- package/dist/server/render-tasks.d.ts +43 -5
- package/dist/server/render-tasks.js +131 -91
- package/dist/server/route-table.js +31 -5
- package/dist/server/settings.js +276 -255
- package/dist/server/task-views.d.ts +8 -0
- package/dist/server/task-views.js +90 -2
- package/dist/server/tasks.d.ts +18 -0
- package/dist/server/tasks.js +148 -41
- package/dist/server/terminals.js +1 -1
- package/dist/server/welcome.d.ts +22 -0
- package/dist/server/welcome.js +69 -0
- package/dist/settings-groups-ui.d.ts +279 -0
- package/dist/settings-groups-ui.js +615 -0
- package/dist/settings-kit.d.ts +42 -6
- package/dist/settings-kit.js +69 -7
- package/dist/settings-proofs.js +1 -0
- package/dist/setup-guide.d.ts +2 -2
- package/dist/skills-ui.js +59 -7
- package/dist/slack-settings.js +12 -5
- package/dist/spend-ui.d.ts +45 -26
- package/dist/spend-ui.js +124 -56
- package/dist/sso-ui.d.ts +5 -2
- package/dist/sso-ui.js +63 -31
- package/dist/storage-ui.d.ts +3 -2
- package/dist/storage-ui.js +56 -50
- package/dist/store.d.ts +182 -5
- package/dist/store.js +512 -38
- package/dist/surface.js +23 -3
- package/dist/task-archive.d.ts +10 -0
- package/dist/task-archive.js +16 -0
- package/dist/task-control.d.ts +1 -1
- package/dist/teams-settings.d.ts +2 -1
- package/dist/teams-settings.js +24 -41
- package/dist/telegram-settings.d.ts +0 -4
- package/dist/telegram-settings.js +52 -25
- package/dist/tidy.d.ts +130 -0
- package/dist/tidy.js +503 -0
- package/dist/toolroll-update-ui.d.ts +8 -4
- package/dist/toolroll-update-ui.js +55 -45
- package/dist/tools-ui.d.ts +5 -3
- package/dist/tools-ui.js +107 -42
- package/dist/work-index.d.ts +24 -0
- package/dist/work-index.js +56 -30
- package/dist/workspace-ui.d.ts +1 -1
- package/dist/workspace-ui.js +8 -4
- package/package.json +1 -1
package/dist/storage-ui.js
CHANGED
|
@@ -1,42 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Settings → Storage: how much space task checkouts use, what a clean-up would free now,
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* one-time command for older work), and when a finished task's clean checkout goes by itself. An
|
|
2
|
+
* Settings → Storage: how much space task checkouts use, what a clean-up would free now, the clean-up's preview (what
|
|
3
|
+
* goes, what stays and why, with paths) and its Remove behind the password, what the last storage sweep removed and
|
|
4
|
+
* when (its paths in a disclosure) and why the next one waits, what landed work's teardown did and still waits on (in a
|
|
5
|
+
* disclosure, with the one-time command for older work), and when a finished task's clean checkout goes by itself. An
|
|
6
|
+
* instance operator's page, built from the revamp kit; the Settings frame adds the title.
|
|
6
7
|
*/
|
|
7
8
|
import { homedir } from "node:os";
|
|
8
9
|
import { basename } from "node:path";
|
|
9
|
-
import { html,
|
|
10
|
+
import { html, joinHtml } from "./html.js";
|
|
10
11
|
import { previewDigest, whyWords } from "./checkout-cleanup.js";
|
|
11
12
|
import { CLEANUP_CHOICES, bytesWords } from "./storage.js";
|
|
12
13
|
import { sweepDetails, sweepWords } from "./storage-sweep.js";
|
|
13
14
|
import { sweepScheduleWords } from "./storage-sweep-schedule.js";
|
|
15
|
+
import { codeLine, disclose, formRow, icon, infoLine, note, notice, select, settingsRecord, settingsSection } from "./server/kit.js";
|
|
16
|
+
import { kitSectionForm } from "./settings-kit.js";
|
|
14
17
|
const plural = (count, one, many = `${one}s`) => `${count} ${count === 1 ? one : many}`;
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
`.storage ul.checkouts li{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:2px 12px;padding:8px 0;border-top:1px solid var(--border);font-size:.8125rem}` +
|
|
24
|
-
`.storage ul.checkouts .name{font-weight:500;min-width:0}.storage ul.checkouts .size{font-variant-numeric:tabular-nums;white-space:nowrap}` +
|
|
25
|
-
`.storage ul.checkouts .path{grid-column:1/-1;font-family:var(--font-mono, ui-monospace, monospace);font-size:.6875rem;color:var(--muted-foreground);word-break:break-all}` +
|
|
26
|
-
`.storage ul.checkouts .why{grid-column:1/-1}` +
|
|
27
|
-
`.storage details.discard{grid-column:1/-1}.storage details.discard>summary{cursor:pointer;color:var(--destructive);min-height:2.25rem;display:inline-flex;align-items:center}` +
|
|
28
|
-
`.storage form{display:grid;gap:10px;margin:0}.storage label{display:grid;gap:4px;font-size:.8125rem;font-weight:500;max-width:20rem}` +
|
|
29
|
-
`.storage select,.storage input[type=password]{width:100%;box-sizing:border-box;min-height:2.125rem}.storage form button{justify-self:start;white-space:nowrap}` +
|
|
30
|
-
`.storage form.setting button[type=submit],.storage .preview form.remove button[type=submit]{background:var(--primary);color:var(--primary-foreground);border-color:var(--primary);font-weight:600}` +
|
|
31
|
-
`.storage .sweep{display:grid;gap:4px}.storage .sweep p{margin:0}.storage .sweep .problem{color:var(--destructive)}` +
|
|
32
|
-
`.storage details.sweep-details>summary{cursor:pointer;min-height:2.25rem;display:inline-flex;align-items:center;font-size:.8125rem;color:var(--muted-foreground)}` +
|
|
33
|
-
`.storage details.landed>summary{cursor:pointer;min-height:2.25rem;display:inline-flex;align-items:center;font-size:.8125rem;color:var(--muted-foreground)}` +
|
|
34
|
-
`.storage details.landed .landed-body{display:grid;gap:6px;margin-top:4px;font-size:.8125rem}.storage details.landed p{margin:0}` +
|
|
35
|
-
`.storage details.landed ul{margin:0;padding-left:18px;overflow-wrap:anywhere}.storage details.landed .target{font-family:var(--font-mono, ui-monospace, monospace);font-size:.6875rem}` +
|
|
36
|
-
`.storage details.landed code{font-family:var(--font-mono, ui-monospace, monospace);font-size:.75rem;overflow-wrap:anywhere}` +
|
|
37
|
-
`.storage details.sweep-details ul{margin:4px 0 0;padding-left:18px;font-family:var(--font-mono, ui-monospace, monospace);font-size:.6875rem;color:var(--muted-foreground);overflow-wrap:anywhere}` +
|
|
38
|
-
`@media (max-width:900px){.storage details.sweep-details>summary,.storage details.landed>summary{min-height:44px}.storage details.clean-up>summary,.storage form button{min-height:44px}.storage label{max-width:none}.storage select,.storage input[type=password]{min-height:44px;font-size:16px}.storage .preview form.remove button{width:100%}}`;
|
|
39
|
-
/** Paths under the home folder as ~/…, as the checkout list shows them. */
|
|
18
|
+
/** The page is kit pieces now; nothing of the old look is left. Kept as an export for the shared stylesheet. */
|
|
19
|
+
export const STORAGE_CSS = "";
|
|
20
|
+
/** A path under the home folder as ~/…. */
|
|
21
|
+
function tilde(path) {
|
|
22
|
+
const home = homedir();
|
|
23
|
+
return home !== "" && home !== "/" && path.startsWith(`${home}/`) ? `~${path.slice(home.length)}` : path;
|
|
24
|
+
}
|
|
25
|
+
/** Paths under the home folder as ~/… anywhere in a line, as the checkout list shows them. */
|
|
40
26
|
function homeAsTilde(line) {
|
|
41
27
|
const home = homedir();
|
|
42
28
|
return home === "" || home === "/" ? line : line.split(`${home}/`).join("~/");
|
|
@@ -49,41 +35,61 @@ function whenWords(at) {
|
|
|
49
35
|
/** When the last sweep ran and what it did, then why the next one waits or when it is due; paths and problems behind Details. */
|
|
50
36
|
function sweepHtml(sweep) {
|
|
51
37
|
const last = sweep.last;
|
|
52
|
-
const schedule = sweep.schedule === undefined ? (sweep.off ? html `<p class="
|
|
53
|
-
: html `<p class="
|
|
38
|
+
const schedule = sweep.schedule === undefined ? (sweep.off ? html `<p class="k-note" data-sweep-state="off">Automatic sweep: off.</p>` : "")
|
|
39
|
+
: html `<p class="k-note" data-sweep-state="${sweep.schedule.state}">Automatic sweep: ${sweepScheduleWords(sweep.schedule, whenWords)}</p>`;
|
|
54
40
|
if (last === null)
|
|
55
|
-
return html `<div
|
|
41
|
+
return html `<div data-last-sweep="">${note("Not swept yet.")}${schedule}</div>`;
|
|
56
42
|
const who = last.source === "manual" ? `Cleaned up by ${last.actor}` : "Swept";
|
|
57
43
|
const details = sweepDetails(last.parts);
|
|
58
44
|
const problem = last.parts.some(one => one.failed > 0 || one.problem !== undefined);
|
|
59
|
-
|
|
45
|
+
const said = html `${who} <time datetime="${last.at}">${whenWords(last.at)}</time>. ${sweepWords(last.parts)}`;
|
|
46
|
+
return html `<div data-last-sweep="${last.at}">${problem ? html `<p class="k-notice" role="alert">${icon("alert", true)}<span>${said}</span></p>` : note(said)}${schedule}${details.length === 0 ? "" : disclose("Details", joinHtml(details.map(line => codeLine(homeAsTilde(line)))))}</div>`;
|
|
60
47
|
}
|
|
61
48
|
/** Landed work, on demand: what its teardown did, what it waits on and why, and the one-time command for older work. */
|
|
62
49
|
function landedHtml(landed) {
|
|
63
|
-
const home = homedir();
|
|
64
50
|
const done = landed.completed + landed.checkouts + landed.branches === 0 ? "No landed work cleaned up yet."
|
|
65
51
|
: `${plural(landed.completed, "task")} marked complete; ${plural(landed.checkouts, "checkout")} and ${plural(landed.branches, "local branch", "local branches")} removed.`;
|
|
66
|
-
const waiting = landed.waiting.length === 0 ? "" : html `<
|
|
67
|
-
return html `<
|
|
52
|
+
const waiting = landed.waiting.length === 0 ? "" : html `<div data-landed-waiting>${note(`Waiting (${landed.waiting.length}):`)}${landed.waiting.map(one => settingsRecord({ title: html `<span class="k-mono">${tilde(one.target)}</span>`, sub: one.why ?? "" }))}</div>`;
|
|
53
|
+
return html `<div data-landed>${disclose("Landed work", joinHtml([note(done), waiting,
|
|
54
|
+
note(html `For work that landed before this: <code class="k-mono">toolroll storage clean --landed</code> shows what would go; add <code class="k-mono">--yes</code> to do it.`)]))}</div>`;
|
|
68
55
|
}
|
|
56
|
+
/** One checkout: the task it was for, its size, where it is (the home folder as ~), why it stays, and Discard when it has changes. */
|
|
69
57
|
function item(one) {
|
|
58
|
+
const why = one.why === null ? "" : `${whyWords(one)[0].toUpperCase()}${whyWords(one).slice(1)}`;
|
|
70
59
|
const discard = one.why === "has changes"
|
|
71
|
-
?
|
|
60
|
+
? disclose("Discard", kitSectionForm({ proof: "storage-discard", action: "/settings/storage/discard", id: `discard-${previewId(one.path)}`, hidden: { path: one.path },
|
|
61
|
+
save: { label: "Discard changes", variant: "danger" }, body: note("Throws away this checkout and its uncommitted changes. Its branch stays.") }))
|
|
72
62
|
: "";
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
const where = home !== "" && one.path.startsWith(`${home}/`) ? `~${one.path.slice(home.length)}` : one.path;
|
|
76
|
-
return html `<li data-checkout="${one.path}"><span class="name">${one.taskId ?? basename(one.path)}</span><span class="size">${bytesWords(one.bytes)}</span><span class="path">${where}</span>${one.why === null ? "" : html `<span class="why">${whyWords(one)[0].toUpperCase() + whyWords(one).slice(1)}</span>`}${discard}</li>`;
|
|
63
|
+
return settingsRecord({ title: one.taskId ?? basename(one.path), attrs: { "data-checkout": one.path }, when: bytesWords(one.bytes),
|
|
64
|
+
sub: html `<span class="k-mono">${tilde(one.path)}</span>${why === "" ? "" : ` · ${why}`}`, more: discard });
|
|
77
65
|
}
|
|
78
|
-
|
|
66
|
+
/** A short id for a checkout's form, from its path. */
|
|
67
|
+
const previewId = (path) => path.replace(/[^a-z0-9]+/gi, "-").replace(/^-|-$/g, "").slice(-48) || "checkout";
|
|
68
|
+
export function storageHtml(view, said) {
|
|
79
69
|
const { plan } = view;
|
|
80
|
-
const note = notice.problem ? html `<p class="problem" role="alert">${notice.problem}</p>` : notice.said ? html `<p role="status">${notice.said}</p>` : "";
|
|
81
70
|
const facts = [plural(plan.count, "checkout"), `${plan.waitingReview} waiting for review`, `${plan.withChanges} kept for their changes`].join(" · ");
|
|
82
71
|
const frees = plan.go.length === 0 ? "Nothing to clean up now." : `Cleaning up now frees about ${bytesWords(plan.freeBytes)}.`;
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
72
|
+
const checkouts = settingsSection({ id: "checkouts", title: `Checkouts use ${bytesWords(plan.totalBytes)}`,
|
|
73
|
+
body: joinHtml([
|
|
74
|
+
said.problem ? notice(said.problem) : said.said ? infoLine(said.said) : "",
|
|
75
|
+
html `<p class="k-note" data-checkout-bytes="${plan.totalBytes}">${facts}</p>`,
|
|
76
|
+
view.measured ?? "",
|
|
77
|
+
html `<p class="k-note" data-clean-bytes="${plan.freeBytes}">${frees}</p>`,
|
|
78
|
+
view.sweep === undefined ? "" : sweepHtml(view.sweep),
|
|
79
|
+
view.landed === undefined ? "" : landedHtml(view.landed),
|
|
80
|
+
]) });
|
|
81
|
+
const remove = plan.go.length === 0 ? "" : kitSectionForm({ proof: "storage-clean", action: "/settings/storage/clean", id: "clean-form", hidden: { preview: previewDigest(plan) },
|
|
82
|
+
save: { label: `Remove ${plural(plan.go.length, "checkout")}`, variant: "danger" }, body: html `` });
|
|
83
|
+
const goes = plan.go.length === 0 ? note("Nothing to remove now.")
|
|
84
|
+
: html `<div data-goes>${plan.go.map(one => item(one))}</div>`;
|
|
85
|
+
const stays = plan.stay.length === 0 ? "" : disclose(`Stays (${plan.stay.length})`, html `<div data-stays>${plan.stay.map(one => item(one))}</div>`);
|
|
86
|
+
const cleanUp = settingsSection({ id: "clean-up", title: "Clean up now",
|
|
87
|
+
lead: plan.go.length === 0 ? "Nothing to remove now." : `Removes ${plural(plan.go.length, "checkout")}, about ${bytesWords(plan.freeBytes)}. Their branches stay, so nothing committed is lost.`,
|
|
88
|
+
body: html `<div data-clean-up>${joinHtml([plan.go.length === 0 ? "" : goes, remove, stays])}</div>` });
|
|
89
|
+
const automatic = settingsSection({ id: "automatic-cleanup", title: "Automatic cleanup",
|
|
90
|
+
lead: "Its branch stays. Checkouts with changes, commits on no branch, in use, or waiting for review are kept. When a task's work is already in main, Toolroll marks it complete and removes its checkout and local branches.",
|
|
91
|
+
body: kitSectionForm({ proof: "storage-cleanup", action: "/settings/storage", id: "cleanup-form", gate: true,
|
|
92
|
+
body: formRow("Remove a finished task's clean checkout", null, select({ id: "storage-cleanup", name: "cleanup", label: "Remove a finished task's clean checkout", current: plan.cleanup,
|
|
93
|
+
items: CLEANUP_CHOICES.map(one => [one.value, one.label]) }), "inline") }) });
|
|
94
|
+
return joinHtml([checkouts, cleanUp, automatic]);
|
|
89
95
|
}
|
package/dist/store.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { type ProjectSandbox } from "./project-sandbox.js";
|
|
|
5
5
|
import type { FencePolicy } from "./agent-fence.js";
|
|
6
6
|
import { type NetworkProfile, type ProjectNetwork, type RunNetworkRecord } from "./egress.js";
|
|
7
7
|
import { type AcpLaunch } from "./acp-attest.js";
|
|
8
|
+
export { refArchived, taskArchived } from "./task-archive.js";
|
|
8
9
|
import { type ChatBinding } from "./chat-core.js";
|
|
9
10
|
import { ChatMessages, TELEGRAM_HOLD_REASONS, TELEGRAM_SKIPPED_ELSEWHERE, TELEGRAM_SKIPPED_OTHER_CHAT, TELEGRAM_SKIPPED_QUIET } from "./chat-messages.js";
|
|
10
11
|
import { isLifecycleNotification, isTelegramProgressNotification, LIFECYCLE_KEY_PREFIX, LIFECYCLE_KINDS, proposalTaskOf, type LifecycleKind } from "./notification-rows.js";
|
|
@@ -232,7 +233,7 @@ export type SealedLedgerEntry = LedgerEntry & {
|
|
|
232
233
|
hash: string;
|
|
233
234
|
} | null;
|
|
234
235
|
};
|
|
235
|
-
export declare const SCHEMA_VERSION =
|
|
236
|
+
export declare const SCHEMA_VERSION = 146;
|
|
236
237
|
/** v118: the tables merged into `credential`, in the order they move (a person's API tokens keep their ids first). */
|
|
237
238
|
export declare const V118_MERGED_TABLES: Readonly<Record<string, CredentialKind>>;
|
|
238
239
|
/**
|
|
@@ -394,6 +395,22 @@ export declare const V143_ADDED_COLUMNS: Readonly<Record<string, Readonly<Record
|
|
|
394
395
|
definition: string;
|
|
395
396
|
saved: string;
|
|
396
397
|
}>>>>;
|
|
398
|
+
/** v145 (docs/plans/task-tidy.md): `task_archive` is a put-away task version. A row hides it from every list and count
|
|
399
|
+
* and refuses every door that would dispatch, claim or approve it; restore deletes the row. Its history, results,
|
|
400
|
+
* approvals and ledger stay exactly as they were. `merge_in_flight` is a direct merge between its last check and GitHub's
|
|
401
|
+
* answer, owned by its token: a task can't be put away under it (a row older than 15 minutes is a crash, and no
|
|
402
|
+
* longer counts). `deploy_in_flight` is a deployment whose candidate passed its gate (30 minutes, refreshed by every
|
|
403
|
+
* phase that proves it again). `flow_step_task` is the tasks a flow step was admitted for, kept whatever the card does
|
|
404
|
+
* next, so a step still running holds them. `branch_check_run` keeps each completed GitHub workflow run (pushed to
|
|
405
|
+
* the watched branch of the watched repository) the "checks failed" trigger saw, green or red, so tidy can tell a
|
|
406
|
+
* failure notice was fixed by a later commit. */
|
|
407
|
+
export declare const V145_SCHEMA = "\nCREATE TABLE IF NOT EXISTS task_archive (\n task_ref INTEGER PRIMARY KEY REFERENCES task_ref(id),\n by TEXT NOT NULL,\n by_kind TEXT NOT NULL CHECK (by_kind IN ('person','tidy')),\n rule TEXT,\n reason TEXT NOT NULL,\n at TEXT NOT NULL\n);\nCREATE TABLE IF NOT EXISTS branch_check_run (\n repo TEXT NOT NULL,\n run_id INTEGER NOT NULL,\n branch TEXT NOT NULL,\n workflow TEXT NOT NULL,\n head_sha TEXT NOT NULL,\n conclusion TEXT NOT NULL CHECK (conclusion IN ('success','failure')),\n run_created_at TEXT NOT NULL,\n observed_at TEXT NOT NULL,\n PRIMARY KEY (repo, run_id)\n);\nCREATE INDEX IF NOT EXISTS branch_check_run_by_workflow ON branch_check_run (repo, branch, workflow, run_created_at);\nCREATE TABLE IF NOT EXISTS merge_in_flight (\n publication INTEGER PRIMARY KEY REFERENCES publication(id),\n task_ref INTEGER NOT NULL REFERENCES task_ref(id),\n token TEXT NOT NULL,\n by TEXT NOT NULL,\n at TEXT NOT NULL\n);\nCREATE TABLE IF NOT EXISTS deploy_in_flight (\n task_ref INTEGER PRIMARY KEY REFERENCES task_ref(id),\n run INTEGER NOT NULL,\n at TEXT NOT NULL\n);\nCREATE TABLE IF NOT EXISTS flow_step_task (\n card INTEGER NOT NULL,\n entry INTEGER NOT NULL,\n task_id TEXT NOT NULL,\n PRIMARY KEY (card, entry, task_id)\n);\n";
|
|
408
|
+
/** v146: `ci_check` is one pull request check (a GitHub check run or commit status) as the plane's winning observation of
|
|
409
|
+
* that head read it: written only with the observation that won its generation, replacing that head's rows wholesale.
|
|
410
|
+
* `release_step` is one step of a release (release.ts RELEASE_STEPS) as `toolroll release` moved through it: when it
|
|
411
|
+
* started, when it ended and how; recording it never changes the release. Both are read-only history for the Ship and
|
|
412
|
+
* Release views and their CLI twins. */
|
|
413
|
+
export declare const V146_SCHEMA = "\nCREATE TABLE IF NOT EXISTS ci_check (\n github_repo TEXT NOT NULL,\n pr_number INTEGER NOT NULL,\n head_sha TEXT NOT NULL,\n -- A check's identity: its kind (check run or commit status), its workflow and its name, so two workflows' checks\n -- with the same name stay two rows (a failing one never hides behind a passing namesake).\n ident TEXT NOT NULL,\n name TEXT NOT NULL,\n workflow TEXT,\n state TEXT NOT NULL CHECK (state IN ('queued','running','passed','failed','skipped','cancelled','neutral')),\n started_at TEXT,\n completed_at TEXT,\n url TEXT,\n observed_at TEXT NOT NULL,\n PRIMARY KEY (github_repo, pr_number, head_sha, ident)\n);\nCREATE TABLE IF NOT EXISTS release_step (\n task_id TEXT NOT NULL,\n tag TEXT NOT NULL,\n version TEXT NOT NULL,\n pr INTEGER,\n step TEXT NOT NULL,\n state TEXT NOT NULL CHECK (state IN ('running','done','failed','waiting')),\n started_at TEXT NOT NULL,\n ended_at TEXT,\n detail TEXT,\n updated_at TEXT NOT NULL,\n PRIMARY KEY (task_id, tag, step)\n);\nCREATE INDEX IF NOT EXISTS release_step_by_task ON release_step (task_id, updated_at);\n";
|
|
397
414
|
/**
|
|
398
415
|
* v135: one approval per release (docs/plans/release-once.md). `release_authority` is the single source of truth for a
|
|
399
416
|
* release a person approved: one row per generation, changed only by compare-and-swap on `rev`, with a lease whose
|
|
@@ -3745,7 +3762,7 @@ export declare class Store {
|
|
|
3745
3762
|
rejectedRun: number | null;
|
|
3746
3763
|
} | {
|
|
3747
3764
|
ok: false;
|
|
3748
|
-
reason: "unknown-task" | "not-stalled" | "claimed" | "accepted-result" | "published" | "moved";
|
|
3765
|
+
reason: "unknown-task" | "not-stalled" | "claimed" | "accepted-result" | "published" | "moved" | "archived";
|
|
3749
3766
|
};
|
|
3750
3767
|
/**
|
|
3751
3768
|
* Cancel, aware of who might be building right now. A live claim wins:
|
|
@@ -6072,8 +6089,13 @@ export declare class Store {
|
|
|
6072
6089
|
file?: string | null;
|
|
6073
6090
|
held?: string | null;
|
|
6074
6091
|
}, now: Date): number;
|
|
6075
|
-
/** A person approves a held script (one an imported flow brought): from now on it runs.
|
|
6076
|
-
|
|
6092
|
+
/** A person approves a held script (one an imported flow brought): from now on it runs. The approval covers exactly
|
|
6093
|
+
* the version and content the person read (`seen`): the check and the release of the hold are one statement in one
|
|
6094
|
+
* transaction, so a script removed and brought back under the same name is never approved unseen. */
|
|
6095
|
+
approveFlowScript(repo: string, name: string, seen: {
|
|
6096
|
+
version: number;
|
|
6097
|
+
digest: string;
|
|
6098
|
+
}): "approved" | "changed" | "not-held";
|
|
6077
6099
|
removeFlowScript(repo: string, name: string, by?: string, now?: Date): boolean;
|
|
6078
6100
|
/** Claim a card's visit to a step zone. False when another pass holds it or it already finished. */
|
|
6079
6101
|
claimFlowStep(step: {
|
|
@@ -6892,7 +6914,7 @@ export declare class Store {
|
|
|
6892
6914
|
stop: RunStop;
|
|
6893
6915
|
} | {
|
|
6894
6916
|
ok: false;
|
|
6895
|
-
reason: "no-stop" | "wrong-task" | "stopping" | "already-resumed" | "superseded" | "busy" | "review";
|
|
6917
|
+
reason: "no-stop" | "wrong-task" | "stopping" | "already-resumed" | "superseded" | "busy" | "review" | "archived";
|
|
6896
6918
|
detail: string;
|
|
6897
6919
|
};
|
|
6898
6920
|
/** Every stop recorded on a task, newest request first. */
|
|
@@ -8064,3 +8086,158 @@ export declare function dropFeedbackImage(store: Store, runId: number, commentId
|
|
|
8064
8086
|
ok: false;
|
|
8065
8087
|
reason: "not-found" | "image-usable" | "not-authorized";
|
|
8066
8088
|
};
|
|
8089
|
+
/** A put-away task version (v145, docs/plans/task-tidy.md). */
|
|
8090
|
+
export type TaskArchive = {
|
|
8091
|
+
taskRef: number;
|
|
8092
|
+
taskId: string;
|
|
8093
|
+
by: string;
|
|
8094
|
+
byKind: "person" | "tidy";
|
|
8095
|
+
rule: string | null;
|
|
8096
|
+
reason: string;
|
|
8097
|
+
at: string;
|
|
8098
|
+
};
|
|
8099
|
+
/** Who put a task away, and why: a person by name, or tidy by its rule. */
|
|
8100
|
+
export type ArchiveBy = {
|
|
8101
|
+
by: string;
|
|
8102
|
+
byKind: "person" | "tidy";
|
|
8103
|
+
rule: string | null;
|
|
8104
|
+
reason: string;
|
|
8105
|
+
};
|
|
8106
|
+
export type ArchiveRefusal = "unknown-task" | "live" | "archived" | "not-archived" | "blocked";
|
|
8107
|
+
/** The put-away record of this task, or null when it is not put away. */
|
|
8108
|
+
export declare function archiveOf(store: Store, taskId: string): TaskArchive | null;
|
|
8109
|
+
/** Every version of a task's family, by the same proven lineage the task page reads (`taskFamilyOf`: same project, each
|
|
8110
|
+
* revision bound to its parent's own run by its brief). A family whose lineage doesn't prove is just this task. */
|
|
8111
|
+
export declare function taskFamilyRefs(store: Store, taskId: string): {
|
|
8112
|
+
id: number;
|
|
8113
|
+
taskId: string;
|
|
8114
|
+
}[];
|
|
8115
|
+
/** The first family version with something still going on, or null: running, a live newest claim, an unfinished run,
|
|
8116
|
+
* a process Toolroll hasn't seen exit, a build whose processes were never recorded, a stop still settling, a follow-up
|
|
8117
|
+
* check asked for and not finished, a flow step running for its card, a release in flight (a live release approval
|
|
8118
|
+
* that names it, or a deploy or merge reserved, running or unknown), or a pull request merging (an intent claimed or
|
|
8119
|
+
* firing, or a person's merge between its last check and GitHub's answer). */
|
|
8120
|
+
export declare function liveFamilyAttempt(store: Store, refs: readonly number[], now: Date): string | null;
|
|
8121
|
+
/** Puts a task away (v145): every version of its family, in one write transaction that re-checks it has no live
|
|
8122
|
+
* attempt, that its versions are exactly `expect` when the caller showed a person a family (a preview), and that
|
|
8123
|
+
* `guard` (the caller's own rule, re-read under the lock) still allows it. Its state, history, results, approvals and
|
|
8124
|
+
* ledger are untouched; its open notifications are resolved; one ledger row records who and why. */
|
|
8125
|
+
export declare function archiveTaskFamily(store: Store, taskId: string, by: ArchiveBy, now: Date, options?: {
|
|
8126
|
+
expect?: readonly number[];
|
|
8127
|
+
guard?: (refs: readonly number[]) => string | null;
|
|
8128
|
+
}): {
|
|
8129
|
+
ok: true;
|
|
8130
|
+
refs: number[];
|
|
8131
|
+
} | {
|
|
8132
|
+
ok: false;
|
|
8133
|
+
reason: ArchiveRefusal;
|
|
8134
|
+
message: string;
|
|
8135
|
+
};
|
|
8136
|
+
/** Brings a put-away task back (v145): every version of its family, with a ledger row. Tidy never puts a restored
|
|
8137
|
+
* task away again (tidy.ts reads the `task restored` row). */
|
|
8138
|
+
export declare function restoreTaskFamily(store: Store, taskId: string, by: string, now: Date, guard?: (refs: readonly number[]) => string | null): {
|
|
8139
|
+
ok: true;
|
|
8140
|
+
refs: number[];
|
|
8141
|
+
} | {
|
|
8142
|
+
ok: false;
|
|
8143
|
+
reason: ArchiveRefusal;
|
|
8144
|
+
message: string;
|
|
8145
|
+
};
|
|
8146
|
+
/**
|
|
8147
|
+
* What a LIVE invite grants, for its own join page (Wave E, "Your access"): the role, who invited, the projects and
|
|
8148
|
+
* when it expires. Read without spending an attempt and under exactly inviteIsLive's predicate, so every dead shape
|
|
8149
|
+
* reads as null and still gets the one indistinguishable page (D6). Only a holder of the live token sees it.
|
|
8150
|
+
*/
|
|
8151
|
+
export declare function liveInviteTerms(store: Store, tokenValue: string, now: Date): {
|
|
8152
|
+
role: "approver" | "viewer";
|
|
8153
|
+
mintedBy: string;
|
|
8154
|
+
expiresAt: string;
|
|
8155
|
+
projects: ProjectAccess;
|
|
8156
|
+
} | null;
|
|
8157
|
+
/** One pull request check as GitHub last reported it for the observed head (v146 ci_check). */
|
|
8158
|
+
/** `kind`: a check run or a commit status (part of the check's identity); a row built without it reads as a run when it
|
|
8159
|
+
* names a workflow, else as a status. */
|
|
8160
|
+
export type CiCheckRow = {
|
|
8161
|
+
name: string;
|
|
8162
|
+
workflow: string | null;
|
|
8163
|
+
state: "queued" | "running" | "passed" | "failed" | "skipped" | "cancelled" | "neutral";
|
|
8164
|
+
startedAt: string | null;
|
|
8165
|
+
completedAt: string | null;
|
|
8166
|
+
url: string | null;
|
|
8167
|
+
kind?: "run" | "status";
|
|
8168
|
+
};
|
|
8169
|
+
/** `observed`: the authoritative state of the same winning observation (ci_observation), which the overall status
|
|
8170
|
+
* always comes from; the rows only show each check's own timing. */
|
|
8171
|
+
export type ShipChecks = {
|
|
8172
|
+
githubRepo: string;
|
|
8173
|
+
prNumber: number;
|
|
8174
|
+
headSha: string;
|
|
8175
|
+
observedAt: string;
|
|
8176
|
+
observed: "passing" | "failing" | "running" | "none";
|
|
8177
|
+
checks: CiCheckRow[];
|
|
8178
|
+
};
|
|
8179
|
+
/** At most this many checks are kept for one head; GitHub's rollup is far smaller in practice. */
|
|
8180
|
+
export declare const CI_CHECKS_MAX = 200;
|
|
8181
|
+
/**
|
|
8182
|
+
* GitHub's statusCheckRollup (gh pr view --json statusCheckRollup) as check rows: CheckRun items (name, workflowName,
|
|
8183
|
+
* status, conclusion, startedAt, completedAt, detailsUrl) and StatusContext items (context, state, startedAt, targetUrl).
|
|
8184
|
+
* Strict: an item that is not one of those shapes, has no usable name, or names a state it doesn't know is dropped; one
|
|
8185
|
+
* row per identity (kind, workflow and name), and when one identity appears twice (a re-run) the worse state stands;
|
|
8186
|
+
* at most CI_CHECKS_MAX.
|
|
8187
|
+
*/
|
|
8188
|
+
export declare function parseCiRollup(rollup: unknown): CiCheckRow[];
|
|
8189
|
+
/**
|
|
8190
|
+
* Replace one head's checks wholesale (v146). Call ONLY with an observation that won its generation (publish.ts settles
|
|
8191
|
+
* and records in one transaction): a losing, stale answer never writes here.
|
|
8192
|
+
*/
|
|
8193
|
+
export declare function recordCiChecks(store: Store, githubRepo: string, prNumber: number, headSha: string, rows: readonly CiCheckRow[], now: Date): void;
|
|
8194
|
+
/** A pull request's checks for the head the plane's last winning observation recorded, or null when none was. */
|
|
8195
|
+
export declare function ciChecksFor(store: Store, githubRepo: string, prNumber: number): ShipChecks | null;
|
|
8196
|
+
/** A task's pull request checks: its family's newest publication that has a pull request number, and that pull
|
|
8197
|
+
* request's checks (ciChecksFor). Null: no pull request, or none observed yet. */
|
|
8198
|
+
export declare function shipChecksForTask(store: Store, taskId: string): ShipChecks | null;
|
|
8199
|
+
/** One release step as `toolroll release` moved through it (v146 release_step). */
|
|
8200
|
+
export type ReleaseStepRow = {
|
|
8201
|
+
step: string;
|
|
8202
|
+
state: "running" | "done" | "failed" | "waiting";
|
|
8203
|
+
startedAt: string;
|
|
8204
|
+
endedAt: string | null;
|
|
8205
|
+
detail: string | null;
|
|
8206
|
+
};
|
|
8207
|
+
export type ReleaseProgress = {
|
|
8208
|
+
tag: string;
|
|
8209
|
+
version: string;
|
|
8210
|
+
pr: number | null;
|
|
8211
|
+
startedAt: string;
|
|
8212
|
+
updatedAt: string;
|
|
8213
|
+
steps: ReleaseStepRow[];
|
|
8214
|
+
stopped: {
|
|
8215
|
+
step: string;
|
|
8216
|
+
message: string;
|
|
8217
|
+
at: string;
|
|
8218
|
+
} | null;
|
|
8219
|
+
};
|
|
8220
|
+
/** What a release coordinator says about one step. */
|
|
8221
|
+
export type ReleaseStepEntry = {
|
|
8222
|
+
taskId: string;
|
|
8223
|
+
tag: string;
|
|
8224
|
+
version: string;
|
|
8225
|
+
pr: number | null;
|
|
8226
|
+
step: string;
|
|
8227
|
+
state: ReleaseStepRow["state"];
|
|
8228
|
+
at: Date;
|
|
8229
|
+
detail?: string | null;
|
|
8230
|
+
};
|
|
8231
|
+
/**
|
|
8232
|
+
* Record a release step (v146): `running` or `waiting` opens it (its first start is kept), `done` or `failed` ends it.
|
|
8233
|
+
* A step that runs again after a stop starts its row again. A failed write throws here; the release's adapter swallows
|
|
8234
|
+
* it, so recording never changes a release.
|
|
8235
|
+
*/
|
|
8236
|
+
export declare function recordReleaseStep(store: Store, entry: ReleaseStepEntry): void;
|
|
8237
|
+
/** A release's steps, for the release task: the newest tag recorded for it, its steps in the order they ran, and the
|
|
8238
|
+
* step it stopped at when the last thing recorded was a failure. Null: no step recorded. */
|
|
8239
|
+
export declare function releaseProgressFor(store: Store, taskId: string): ReleaseProgress | null;
|
|
8240
|
+
/** The release task whose steps were recorded most recently (v146), or null when none was. */
|
|
8241
|
+
export declare function latestReleaseStepTask(store: Store): string | null;
|
|
8242
|
+
/** Seconds a step or check took (to its end, or to `now` while it runs); null without a start. */
|
|
8243
|
+
export declare function elapsedSeconds(startedAt: string | null, endedAt: string | null, now: Date): number | null;
|