toolroll 0.9.5 → 0.9.7
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 +49 -0
- package/dist/actor.d.ts +21 -0
- package/dist/actor.js +48 -0
- package/dist/assignment-adapters.d.ts +1 -0
- package/dist/assignment-presentation.d.ts +13 -2
- package/dist/assignment-presentation.js +22 -9
- package/dist/assignment-ui.d.ts +10 -15
- package/dist/assignment-ui.js +19 -18
- package/dist/assignment.d.ts +9 -0
- package/dist/assignment.js +62 -13
- package/dist/browser/workspace.css +2 -2
- package/dist/browser/workspace.js +29 -24
- package/dist/browser-workspace.d.ts +120 -12
- package/dist/builder.d.ts +1 -0
- package/dist/builder.js +33 -13
- package/dist/chat-acceptance.js +2 -2
- package/dist/chat-actions.js +2 -1
- package/dist/chat-delivery.js +2 -0
- package/dist/chat-quiet.js +30 -19
- package/dist/chat-task-actions.d.ts +13 -0
- package/dist/chat-task-actions.js +19 -1
- package/dist/check-levels-ui.d.ts +21 -0
- package/dist/check-levels-ui.js +70 -0
- package/dist/check-levels.d.ts +67 -0
- package/dist/check-levels.js +171 -0
- package/dist/claim.d.ts +22 -0
- package/dist/claim.js +43 -0
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +4 -0
- package/dist/demo-chat.d.ts +0 -5
- package/dist/demo-chat.js +14 -3
- package/dist/dispatch.js +7 -2
- package/dist/dispose.d.ts +8 -0
- package/dist/dispose.js +7 -1
- package/dist/export.js +3 -2
- package/dist/first-run.d.ts +34 -0
- package/dist/first-run.js +37 -1
- package/dist/flow-gallery-ui.d.ts +30 -0
- package/dist/flow-gallery-ui.js +85 -0
- package/dist/flow-gallery.d.ts +111 -0
- package/dist/flow-gallery.js +445 -0
- package/dist/flow-share.d.ts +102 -0
- package/dist/flow-share.js +614 -0
- package/dist/flow-starters.d.ts +2 -0
- package/dist/flow-starters.js +1 -1
- package/dist/flow-steps.js +7 -0
- package/dist/flow-triggers.js +2 -0
- package/dist/flows-cli.d.ts +56 -0
- package/dist/flows-cli.js +109 -3
- package/dist/flows-ui.d.ts +15 -1
- package/dist/flows-ui.js +31 -6
- package/dist/guides.js +27 -2
- package/dist/lead-context.js +6 -2
- package/dist/lead-status.d.ts +7 -0
- package/dist/lead-status.js +11 -2
- package/dist/mate-doors.d.ts +0 -15
- package/dist/mate-doors.js +5 -1
- package/dist/mate-tools.js +9 -4
- package/dist/models-ui.js +1 -1
- package/dist/operate.d.ts +4 -1
- package/dist/operate.js +601 -85
- package/dist/project-concurrency.d.ts +62 -0
- package/dist/project-concurrency.js +116 -0
- package/dist/project-delete-ui.d.ts +7 -0
- package/dist/project-delete-ui.js +19 -2
- package/dist/project-delete.js +4 -0
- package/dist/pull-request-flow.d.ts +9 -0
- package/dist/pull-request-flow.js +21 -3
- package/dist/result-follow-ups.d.ts +101 -0
- package/dist/result-follow-ups.js +333 -0
- package/dist/scope.js +11 -0
- package/dist/serve.d.ts +211 -2
- package/dist/serve.js +1070 -204
- package/dist/store.d.ts +76 -3
- package/dist/store.js +311 -22
- package/dist/surface.js +31 -8
- package/dist/tailnet.d.ts +11 -0
- package/dist/tailnet.js +47 -0
- package/dist/task-outcome-cli.js +2 -2
- package/dist/task-status.d.ts +186 -0
- package/dist/task-status.js +335 -0
- package/dist/team-cli.js +3 -0
- package/dist/telegram-progress.js +62 -100
- package/dist/telegram-status.js +21 -8
- package/dist/verification-evidence.js +21 -1
- package/dist/webhooks.js +5 -0
- package/dist/work-index.js +60 -11
- package/dist/work-summary.d.ts +0 -4
- package/dist/work-summary.js +2 -0
- package/dist/workspace-ui.d.ts +10 -0
- package/dist/workspace-ui.js +33 -2
- package/package.json +1 -1
package/dist/surface.js
CHANGED
|
@@ -135,8 +135,27 @@ export const COMMAND_GUIDE = [
|
|
|
135
135
|
flags: [jsonFlag, dbFlag, keyFlag,
|
|
136
136
|
{ name: "id", takesValue: true, meaning: "choose the task id" },
|
|
137
137
|
{ name: "repo", takesValue: true, meaning: "which repository the task belongs to" },
|
|
138
|
-
{ name: "report", takesValue: false, meaning: "a scout task: the deliverable is a report, never a branch" }
|
|
139
|
-
|
|
138
|
+
{ name: "report", takesValue: false, meaning: "a scout task: the deliverable is a report, never a branch" },
|
|
139
|
+
{ name: "replaces", takesValue: true, meaning: "the task this one replaces: it is cancelled and reads \"Replaced by <id>\"" },
|
|
140
|
+
{ name: "token", takesValue: true, meaning: "a lead token: filed as the lead, so it pings nobody" },
|
|
141
|
+
{ name: "checks", takesValue: true, meaning: "quick|full|off: this task's checks, overriding the project's level (\"skip the tests\" is off)" }],
|
|
142
|
+
notableReasons: ["duplicate", "usage", "unknown-task", "unauthenticated"] },
|
|
143
|
+
{ invocation: "task ask", synopsis: "hand a task to a person: one message saying why, and the task is theirs", audience: "agent", agentMayInvoke: true, mutation: "unkeyed",
|
|
144
|
+
positionals: [{ name: "id", required: true, meaning: "the task" }],
|
|
145
|
+
flags: [jsonFlag, dbFlag,
|
|
146
|
+
{ name: "person", takesValue: true, meaning: "who to ask (someone who can see the task's project)" },
|
|
147
|
+
{ name: "why", takesValue: true, meaning: "what they need to do, one line" },
|
|
148
|
+
{ name: "token", takesValue: true, meaning: "the lead token (or TOOLROLL_LEAD_TOKEN)" }],
|
|
149
|
+
notableReasons: ["unknown-task", "unknown-person", "unplaced", "unauthenticated"] },
|
|
150
|
+
{ invocation: "task checks", synopsis: "run checks on the task's latest result, on its exact commit, now; a pass upgrades its status and a failure stays visible",
|
|
151
|
+
audience: "agent", agentMayInvoke: true, mutation: "identity-idempotent",
|
|
152
|
+
positionals: [{ name: "task", required: true, meaning: "any version of the task" }],
|
|
153
|
+
flags: [jsonFlag, dbFlag, { name: "level", takesValue: true, meaning: "quick (default) or full" }],
|
|
154
|
+
notableReasons: ["no-result", "no-check", "checks-failed"] },
|
|
155
|
+
{ invocation: "task add-tests", synopsis: "file a small task to write tests for the task's latest change; it waits for approval like any task",
|
|
156
|
+
audience: "agent", agentMayInvoke: true, mutation: "identity-idempotent",
|
|
157
|
+
positionals: [{ name: "task", required: true, meaning: "any version of the task" }], flags: [jsonFlag, dbFlag],
|
|
158
|
+
notableReasons: ["no-result"] },
|
|
140
159
|
{ invocation: "task list", synopsis: "a page of saved task status", audience: "agent", agentMayInvoke: true, mutation: "none",
|
|
141
160
|
flags: [jsonFlag, dbFlag, { name: "state", takesValue: true, meaning: "queued|running|done|failed|cancelled" },
|
|
142
161
|
{ name: "view", takesValue: true, meaning: "all|needs-you|running|completed" },
|
|
@@ -168,8 +187,9 @@ export const COMMAND_GUIDE = [
|
|
|
168
187
|
{ 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
188
|
audience: "operator", agentMayInvoke: false, mutation: "identity-idempotent",
|
|
170
189
|
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
|
-
|
|
190
|
+
flags: [jsonFlag, dbFlag, { name: "as", takesValue: true, meaning: "the approver merging" }, { name: "token", takesValue: true, meaning: "their password" },
|
|
191
|
+
{ name: "anyway", takesValue: false, meaning: "merge a Quick or Off result without waiting for its full check" }],
|
|
192
|
+
notableReasons: ["usage", "not-an-approver", "full-checks"] },
|
|
173
193
|
...["show", "updates", "claim", "check", "brief", "inbox", "ack"].map(action => ({
|
|
174
194
|
invocation: `assignment ${action}`,
|
|
175
195
|
synopsis: action === "show" ? "read the root, current work, owner and exact receipt"
|
|
@@ -193,7 +213,8 @@ export const COMMAND_GUIDE = [
|
|
|
193
213
|
...(action === "ack" ? [{ name: "batch", takesValue: true, meaning: "exact batch ID returned by assignment inbox" }] : []),
|
|
194
214
|
],
|
|
195
215
|
})),
|
|
196
|
-
operator("task state", "set a task's state by hand — an operator correction, not a workflow step"),
|
|
216
|
+
operator("task state", "set a task's state by hand — an operator correction, not a workflow step (--replaced-by <id> with cancelled)"),
|
|
217
|
+
operator("lead token", "mint the lead's credential behind your password (--revoke ends it): its own work pings nobody"),
|
|
197
218
|
{ invocation: "task block", synopsis: "make one task wait for another", audience: "agent", agentMayInvoke: true, mutation: "keyed",
|
|
198
219
|
positionals: [{ name: "id", required: true, meaning: "the waiting task" }],
|
|
199
220
|
flags: [jsonFlag, dbFlag, keyFlag, { name: "on", takesValue: true, meaning: "the blocker's id" }],
|
|
@@ -289,7 +310,7 @@ export const COMMAND_GUIDE = [
|
|
|
289
310
|
positionals: [{ name: "id", required: true, meaning: "the routine" }], flags: [jsonFlag, dbFlag] },
|
|
290
311
|
{ invocation: "config show", synopsis: "phase and spend configuration", audience: "agent", agentMayInvoke: true, mutation: "none", flags: [jsonFlag, dbFlag, repoFlag] },
|
|
291
312
|
{ invocation: "setup show", synopsis: "installation setup", audience: "agent", agentMayInvoke: true, mutation: "none", flags: [jsonFlag, dbFlag] },
|
|
292
|
-
{ invocation: "verify show", synopsis: "the repository's approved
|
|
313
|
+
{ invocation: "verify show", synopsis: "the repository's check level, its approved full and quick commands, and a suggested quick command", audience: "agent", agentMayInvoke: true, mutation: "none", flags: [jsonFlag, dbFlag, repoFlag] },
|
|
293
314
|
{ invocation: "intake show", synopsis: "intake configuration", audience: "agent", agentMayInvoke: true, mutation: "none", flags: [jsonFlag, dbFlag] },
|
|
294
315
|
{ invocation: "providers", synopsis: "which agent providers this binary can drive, and their transports; --report records this machine's readiness under its runner", audience: "agent", agentMayInvoke: true, mutation: "none",
|
|
295
316
|
flags: [jsonFlag,
|
|
@@ -309,6 +330,7 @@ export const COMMAND_GUIDE = [
|
|
|
309
330
|
operator("runner retire", "retire a worker"),
|
|
310
331
|
operator("runner bind", "replace which repositories a worker may build in"),
|
|
311
332
|
operator("runner capacity", "set how many tasks a worker runs at once; running work carries on, the new number applies at the next claim"),
|
|
333
|
+
operator("project concurrency", "set how many of a project's tasks build at once (default 2, never past the worker's capacity); running work carries on"),
|
|
312
334
|
operator("coordinator mint", "mint the MCP filing credential — repo-bound, rate-limited, token shown once"),
|
|
313
335
|
operator("coordinator revoke", "revoke an MCP filing credential"),
|
|
314
336
|
operator("mcp", "serve the MCP gateway over stdio — the coordinator credential is the only key it accepts"),
|
|
@@ -340,8 +362,9 @@ export const COMMAND_GUIDE = [
|
|
|
340
362
|
operator("config set", "set phase or spend configuration"),
|
|
341
363
|
operator("config clear", "clear phase or spend configuration"),
|
|
342
364
|
operator("setup clear", "clear installation setup"),
|
|
343
|
-
operator("verify set", "approve the one shell command the plane re-runs after every future commit; --self-heal binds one approved-setup replay when a required project executable is missing"),
|
|
344
|
-
operator("verify clear", "revoke a repository's approved verification command"),
|
|
365
|
+
operator("verify set", "approve the one shell command the plane re-runs after every future commit (--quick \"<cmd>\" approves the fast check Quick runs); --self-heal binds one approved-setup replay when a required project executable is missing"),
|
|
366
|
+
operator("verify clear", "revoke a repository's approved verification command; --level quick revokes only the quick command"),
|
|
367
|
+
operator("verify level", "set a project's checks after each build: quick (the approved quick command), full, or off — an approver's act, in the ledger"),
|
|
345
368
|
operator("intake grant", "grant an intake source"),
|
|
346
369
|
operator("intake run", "run intake now"),
|
|
347
370
|
operator("intake preview", "preview what intake would file"),
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
type Runner = (file: string, args: readonly string[], options: {
|
|
2
|
+
timeoutMs: number;
|
|
3
|
+
}) => Promise<{
|
|
4
|
+
code: number | null;
|
|
5
|
+
stdout: string;
|
|
6
|
+
notFound?: boolean;
|
|
7
|
+
}>;
|
|
8
|
+
/** The full MagicDNS name first (machine.tailnet.ts.net), then its short form (machine). Empty when Tailscale isn't running. */
|
|
9
|
+
export declare function tailnetNamesOf(statusJson: string): string[];
|
|
10
|
+
export declare function readTailnetNames(runner?: Runner, platform?: NodeJS.Platform): Promise<string[]>;
|
|
11
|
+
export {};
|
package/dist/tailnet.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This computer's own names on its tailnet, when Tailscale is up: the console
|
|
3
|
+
* answers to them on its port without an --allow-host, and the phone card
|
|
4
|
+
* names the address to type. Read with `tailscale status --json`, which
|
|
5
|
+
* spends nothing and changes nothing; any failure means no tailnet.
|
|
6
|
+
*/
|
|
7
|
+
import { existsSync } from "node:fs";
|
|
8
|
+
import { run } from "./exec.js";
|
|
9
|
+
/** The Mac app ships its command line inside the app bundle. */
|
|
10
|
+
const MAC_APP_CLI = "/Applications/Tailscale.app/Contents/MacOS/Tailscale";
|
|
11
|
+
const NAME = /^[a-z0-9]([a-z0-9-]{0,62})(\.[a-z0-9]([a-z0-9-]{0,62}))*$/;
|
|
12
|
+
/** The full MagicDNS name first (machine.tailnet.ts.net), then its short form (machine). Empty when Tailscale isn't running. */
|
|
13
|
+
export function tailnetNamesOf(statusJson) {
|
|
14
|
+
let status;
|
|
15
|
+
try {
|
|
16
|
+
status = JSON.parse(statusJson);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
if (typeof status !== "object" || status === null)
|
|
22
|
+
return [];
|
|
23
|
+
const body = status;
|
|
24
|
+
if (body.BackendState !== "Running" || typeof body.Self?.DNSName !== "string")
|
|
25
|
+
return [];
|
|
26
|
+
const full = body.Self.DNSName.replace(/\.$/, "").toLowerCase();
|
|
27
|
+
if (!NAME.test(full) || full.length > 253)
|
|
28
|
+
return [];
|
|
29
|
+
const short = full.split(".")[0];
|
|
30
|
+
return short === full ? [full] : [full, short];
|
|
31
|
+
}
|
|
32
|
+
export async function readTailnetNames(runner = run, platform = process.platform) {
|
|
33
|
+
const candidates = ["tailscale", ...(platform === "darwin" && existsSync(MAC_APP_CLI) ? [MAC_APP_CLI] : [])];
|
|
34
|
+
for (const file of candidates) {
|
|
35
|
+
try {
|
|
36
|
+
const answer = await runner(file, ["status", "--json"], { timeoutMs: 3_000 });
|
|
37
|
+
if (answer.notFound === true)
|
|
38
|
+
continue;
|
|
39
|
+
if (answer.code === 0)
|
|
40
|
+
return tailnetNamesOf(answer.stdout);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// No Tailscale here: no tailnet names.
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return [];
|
|
47
|
+
}
|
package/dist/task-outcome-cli.js
CHANGED
|
@@ -126,7 +126,7 @@ export async function runTaskMergeCommand(positional, flags, context) {
|
|
|
126
126
|
return result.ok ? 0 : result.reason === 'usage' ? 2 : 3;
|
|
127
127
|
};
|
|
128
128
|
const fail = (reason, message) => emit({ ok: false, reason, message });
|
|
129
|
-
const allowed = new Set(['json', 'db', 'as', 'token']);
|
|
129
|
+
const allowed = new Set(['json', 'db', 'as', 'token', 'anyway']);
|
|
130
130
|
for (const key of flags.keys())
|
|
131
131
|
if (!allowed.has(key))
|
|
132
132
|
return fail('usage', `--${key} is not a task merge option.`);
|
|
@@ -147,7 +147,7 @@ export async function runTaskMergeCommand(positional, flags, context) {
|
|
|
147
147
|
const view = newestPullRequestOf(store, family.versions.map(one => one.id));
|
|
148
148
|
if (view === null)
|
|
149
149
|
return fail('no-pr', 'This task has no pull request. Open one with task complete --pull-request.');
|
|
150
|
-
const merged = await mergeAsPerson(store, { runId: view.runId, name: acting.name, password: acting.token, ...(context.exec === undefined ? {} : { exec: context.exec }), clock: context.clock });
|
|
150
|
+
const merged = await mergeAsPerson(store, { runId: view.runId, name: acting.name, password: acting.token, ...(flags.get('anyway') === true ? { anyway: true } : {}), ...(context.exec === undefined ? {} : { exec: context.exec }), clock: context.clock });
|
|
151
151
|
if (!merged.ok)
|
|
152
152
|
return emit({ ...merged, reason: merged.reason === 'password' ? 'not-an-approver' : merged.reason, pullRequest: view });
|
|
153
153
|
const after = newestPullRequestOf(store, family.versions.map(one => one.id));
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
/** One answer per task, then the details (docs/design/task-status.md). Every
|
|
2
|
+
* surface — the Tasks list, the task page, the build page, Crew, the Chat
|
|
3
|
+
* result, the Telegram/Slack/Discord/Teams cards and `toolroll status` — reads
|
|
4
|
+
* its headline, sentence, tone and detail rows from `taskStatusOf`, so the
|
|
5
|
+
* words cannot drift apart again. Pure: it reads facts the existing
|
|
6
|
+
* projections already recorded and never changes a check, approval or
|
|
7
|
+
* completion.
|
|
8
|
+
*
|
|
9
|
+
* Severity: red belongs to the Failed headline alone. A detail problem that
|
|
10
|
+
* doesn't undo the outcome (a pull request that couldn't open, shortened
|
|
11
|
+
* output) is an amber note on its own row with one action; the exact
|
|
12
|
+
* technical reason stays one tap away in `why`. */
|
|
13
|
+
import type { AssignmentSnapshot } from "./assignment.js";
|
|
14
|
+
/** A cancelled task with a successor reads "Replaced by <id>" everywhere, never "Cancelled". */
|
|
15
|
+
export declare const replacedWords: (successor: string) => string;
|
|
16
|
+
export declare const HEADLINES: readonly ["Queued", "Planning", "Needs you", "Building", "Ready for review", "Complete", "Failed", "Stopped"];
|
|
17
|
+
export type Headline = (typeof HEADLINES)[number];
|
|
18
|
+
export type HeadlineTone = "neutral" | "live" | "attention" | "ready" | "success" | "danger";
|
|
19
|
+
export declare const HEADLINE_TONE: Readonly<Record<Headline, HeadlineTone>>;
|
|
20
|
+
export type DetailKey = "checks" | "pull-request" | "requirements" | "evidence";
|
|
21
|
+
/** The row's small icon: the only coloured part of a detail. `failed` is red
|
|
22
|
+
* and only ever appears under the Failed headline; `note` is amber. */
|
|
23
|
+
export type DetailMark = "ok" | "running" | "none" | "note" | "failed";
|
|
24
|
+
export type StatusAction = {
|
|
25
|
+
label: string;
|
|
26
|
+
href: string | null;
|
|
27
|
+
};
|
|
28
|
+
export type StatusDetail = {
|
|
29
|
+
key: DetailKey;
|
|
30
|
+
label: string;
|
|
31
|
+
text: string;
|
|
32
|
+
mark: DetailMark;
|
|
33
|
+
href: string | null;
|
|
34
|
+
action: StatusAction | null;
|
|
35
|
+
why: string | null;
|
|
36
|
+
};
|
|
37
|
+
export type TaskStatus = {
|
|
38
|
+
headline: Headline;
|
|
39
|
+
tone: HeadlineTone;
|
|
40
|
+
sentence: string;
|
|
41
|
+
details: StatusDetail[];
|
|
42
|
+
primaryAction: StatusAction | null;
|
|
43
|
+
why: string[];
|
|
44
|
+
};
|
|
45
|
+
export type TaskStage = "queued" | "planning" | "needs-you" | "building" | "checking" | "finished" | "complete" | "failed" | "stopped";
|
|
46
|
+
export type ChecksFact = {
|
|
47
|
+
status: "passed" | "failed" | "running" | "not-run" | "unavailable";
|
|
48
|
+
exitCode: number | null;
|
|
49
|
+
head: string | null;
|
|
50
|
+
/** The check level that ran (check-levels.ts). Off never reads Ready; a quick pass says so. */
|
|
51
|
+
level?: "quick" | "full" | "off" | null;
|
|
52
|
+
/** A follow-up check (Run checks) waiting or running on this commit. */
|
|
53
|
+
running?: "quick" | "full" | null;
|
|
54
|
+
};
|
|
55
|
+
export type PullRequestFact = {
|
|
56
|
+
state: "none" | "opening" | "open" | "merged" | "closed" | "failed";
|
|
57
|
+
number: number | null;
|
|
58
|
+
url: string | null;
|
|
59
|
+
ci: "running" | "passing" | "failing" | null;
|
|
60
|
+
error: string | null;
|
|
61
|
+
/** GitHub's compare page for the pushed branch: where a person opens it by hand. */
|
|
62
|
+
compareUrl?: string | null;
|
|
63
|
+
/** Who merged it and its merge commit, shown on request. */
|
|
64
|
+
note?: string | null;
|
|
65
|
+
};
|
|
66
|
+
export type TaskStatusFacts = {
|
|
67
|
+
stage: TaskStage;
|
|
68
|
+
/** Needs you: what a person is asked for. The sentence names it. */
|
|
69
|
+
need?: "approval" | "answer" | "sign-in" | "other";
|
|
70
|
+
/** The recorded reason in plain words, when the stage has one. */
|
|
71
|
+
reason?: string | null;
|
|
72
|
+
/** A research report rather than a code change. */
|
|
73
|
+
report?: boolean;
|
|
74
|
+
checks?: ChecksFact | null;
|
|
75
|
+
pullRequest?: PullRequestFact | null;
|
|
76
|
+
requirements?: {
|
|
77
|
+
met: number;
|
|
78
|
+
total: number;
|
|
79
|
+
yours: number;
|
|
80
|
+
} | null;
|
|
81
|
+
evidence?: {
|
|
82
|
+
shortened: number;
|
|
83
|
+
missing: number;
|
|
84
|
+
damaged: number;
|
|
85
|
+
} | null;
|
|
86
|
+
completedBy?: string | null;
|
|
87
|
+
action?: StatusAction | null;
|
|
88
|
+
/** Where a row's one action leads: the result (and its Checks tab), the task's pull request, Run checks. */
|
|
89
|
+
links?: {
|
|
90
|
+
result?: string | null;
|
|
91
|
+
checks?: string | null;
|
|
92
|
+
pullRequest?: string | null;
|
|
93
|
+
runChecks?: string | null;
|
|
94
|
+
};
|
|
95
|
+
/** Exact technical reasons, shown only on request. */
|
|
96
|
+
why?: readonly string[];
|
|
97
|
+
};
|
|
98
|
+
export declare function headlineOf(facts: Pick<TaskStatusFacts, "stage" | "checks" | "report">): Headline;
|
|
99
|
+
export declare function taskStatusOf(facts: TaskStatusFacts): TaskStatus;
|
|
100
|
+
export declare function plainReasonOf(stage: TaskStage, code: string, detail: string | null | undefined): string | null;
|
|
101
|
+
export declare function stageOfCode(code: string, options?: {
|
|
102
|
+
needsPerson?: boolean;
|
|
103
|
+
planning?: boolean;
|
|
104
|
+
operatorHold?: boolean;
|
|
105
|
+
}): {
|
|
106
|
+
stage: TaskStage;
|
|
107
|
+
need?: TaskStatusFacts["need"];
|
|
108
|
+
};
|
|
109
|
+
/** The pull request as the task page's follower reports it, or the bare publication row. */
|
|
110
|
+
export declare function pullRequestFactOf(publication: {
|
|
111
|
+
state: string;
|
|
112
|
+
prNumber?: number | null;
|
|
113
|
+
prUrl: string | null;
|
|
114
|
+
remoteState: string | null;
|
|
115
|
+
lastCheckState?: string | null;
|
|
116
|
+
lastError?: string | null;
|
|
117
|
+
merged?: boolean;
|
|
118
|
+
githubRepo?: string;
|
|
119
|
+
base?: string;
|
|
120
|
+
head?: string;
|
|
121
|
+
} | null): PullRequestFact | null;
|
|
122
|
+
/** The assignment's stage. The work status, when the caller read one, names
|
|
123
|
+
* the exact reason (a running planner, a pause, a failed attempt, a sign-in). */
|
|
124
|
+
export declare function assignmentStageOf(assignment: Pick<AssignmentSnapshot, "state" | "primaryAction">, work?: {
|
|
125
|
+
token: string;
|
|
126
|
+
views?: readonly string[];
|
|
127
|
+
} | null, planning?: boolean): {
|
|
128
|
+
stage: TaskStage;
|
|
129
|
+
need?: TaskStatusFacts["need"];
|
|
130
|
+
};
|
|
131
|
+
/** Requirements from the stored matrix: met, the ones only a person confirms, and the total. */
|
|
132
|
+
export declare function requirementsOf(matrix: readonly {
|
|
133
|
+
state: string;
|
|
134
|
+
assessment?: {
|
|
135
|
+
evidenceState?: string;
|
|
136
|
+
} | undefined;
|
|
137
|
+
review?: unknown;
|
|
138
|
+
}[] | null | undefined): NonNullable<TaskStatusFacts["requirements"]> | null;
|
|
139
|
+
/** Saved evidence health from the receipt's artifact list and its caveats. */
|
|
140
|
+
export declare function evidenceOf(receipt: AssignmentSnapshot["receipt"], problems?: readonly string[]): NonNullable<TaskStatusFacts["evidence"]> | null;
|
|
141
|
+
/** The status facts of one assignment, as every surface reads them. */
|
|
142
|
+
export declare function assignmentStatusFacts(assignment: AssignmentSnapshot, options?: {
|
|
143
|
+
work?: {
|
|
144
|
+
token: string;
|
|
145
|
+
views?: readonly string[];
|
|
146
|
+
detail?: string;
|
|
147
|
+
} | null;
|
|
148
|
+
planning?: boolean;
|
|
149
|
+
pullRequest?: PullRequestFact | null;
|
|
150
|
+
action?: StatusAction | null;
|
|
151
|
+
links?: TaskStatusFacts["links"];
|
|
152
|
+
evidence?: TaskStatusFacts["evidence"];
|
|
153
|
+
why?: readonly string[];
|
|
154
|
+
}): TaskStatusFacts;
|
|
155
|
+
/** The legacy work tone each headline wears where a surface still keys off StatusTone. */
|
|
156
|
+
export declare function workToneOf(headline: Headline): "attention" | "problem" | "live" | "ready" | "done" | "muted";
|
|
157
|
+
/** One plain-text line per detail for chat cards: an icon, the label, the words. */
|
|
158
|
+
export declare function statusDetailLines(status: TaskStatus): string[];
|
|
159
|
+
/** The headline's emoji for chat cards (colour is never the only signal: the words follow). */
|
|
160
|
+
export declare function headlineEmoji(headline: Headline): string;
|
|
161
|
+
export declare const statusIconSvg: (mark: DetailMark) => string;
|
|
162
|
+
/** The detail rows as server HTML: quiet rows, colour only on the icon. */
|
|
163
|
+
export declare function statusDetailsHtml(status: TaskStatus): string;
|
|
164
|
+
/** The technical reasons, one tap away. */
|
|
165
|
+
export declare function statusWhyHtml(status: TaskStatus, extra?: readonly string[], diagnostics?: readonly {
|
|
166
|
+
token: string;
|
|
167
|
+
label: string;
|
|
168
|
+
detail: string;
|
|
169
|
+
}[]): string;
|
|
170
|
+
/** Shared CSS for the server-rendered status: neutral rows, coloured icons. */
|
|
171
|
+
export declare const TASK_STATUS_CSS = ".status-headline{display:flex;align-items:center;gap:.6rem;margin:0;font-size:1.125rem;font-weight:600;color:var(--foreground)}.status-headline i{width:.625rem;height:.625rem;border-radius:999px;flex-shrink:0;background:var(--muted-foreground)}[data-headline-tone=live] .status-headline i{background:var(--so-info,#0d74ce)}[data-headline-tone=attention] .status-headline i{background:var(--so-attention,var(--attention))}[data-headline-tone=ready] .status-headline i{background:transparent;box-shadow:inset 0 0 0 2px var(--so-success,#218358)}[data-headline-tone=success] .status-headline i{background:var(--so-success,#218358)}[data-headline-tone=danger] .status-headline i{background:var(--so-danger,#c4320a)}.status-sentence{margin:.35rem 0 0;color:var(--muted-foreground)}.status-details{list-style:none;margin:.75rem 0 0;padding:.25rem 0 0;border-top:1px solid var(--so-line,var(--border))}.status-detail{display:grid;grid-template-columns:14px 7.5rem minmax(0,1fr);align-items:center;gap:.6rem;padding:.4rem 0;font-size:.8125rem;color:var(--foreground)}.status-detail .status-icon{align-self:center;color:var(--muted-foreground)}.status-detail--ok .status-icon{color:var(--so-success,#218358)}.status-detail--running .status-icon{color:var(--so-info,#0d74ce)}.status-detail--note .status-icon{color:var(--so-warning,#ab6400)}.status-detail--failed .status-icon{color:var(--so-danger,#c4320a)}.status-detail-label{color:var(--muted-foreground)}.status-detail-text{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 .6rem;min-width:0;overflow-wrap:anywhere}.status-detail-text a{color:inherit}.status-detail-act{font-weight:600;white-space:nowrap}.status-detail--note .status-detail-act{color:var(--so-warning,#ab6400)}@media(max-width:480px){.status-detail{grid-template-columns:14px 6.5rem minmax(0,1fr);min-height:2.75rem;padding:.25rem 0}.status-detail-text a{display:inline-block;padding:.75rem 0;margin:-.75rem 0}}.status-why{border:0;padding:0;margin:.25rem 0 0;background:transparent;box-shadow:none}.status-why>summary{cursor:pointer;min-height:2.75rem;display:list-item;align-content:center;font-size:.8125rem;color:var(--muted-foreground)}.status-why p{margin:.25rem 0 .5rem}.receipt-note{display:flex;align-items:center;gap:.45rem;font-size:.8125rem;color:var(--foreground)}.receipt-note .status-icon{color:var(--so-warning,#ab6400)}";
|
|
172
|
+
/** A dispatch diagnosis as its stage, for the phone and CLI reads that hold
|
|
173
|
+
* no assignment. A done task is Complete once a person marked its result;
|
|
174
|
+
* a refuted result whose project check failed is Failed. */
|
|
175
|
+
export declare function stageOfDispatch(d: {
|
|
176
|
+
code: string;
|
|
177
|
+
condition: string;
|
|
178
|
+
action: string | null;
|
|
179
|
+
role?: string | null;
|
|
180
|
+
detail?: string;
|
|
181
|
+
}, options?: {
|
|
182
|
+
completed?: boolean;
|
|
183
|
+
}): {
|
|
184
|
+
stage: TaskStage;
|
|
185
|
+
need?: TaskStatusFacts["need"];
|
|
186
|
+
};
|