toolroll 0.8.2 → 0.9.1

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.
Files changed (68) hide show
  1. package/CHANGELOG.md +49 -0
  2. package/dist/agent-onboard.d.ts +24 -1
  3. package/dist/agent-onboard.js +53 -1
  4. package/dist/backup-ui.js +4 -2
  5. package/dist/browser/workspace.css +2 -2
  6. package/dist/browser/workspace.js +33 -32
  7. package/dist/browser-workspace.d.ts +22 -2
  8. package/dist/chat-actions.d.ts +5 -0
  9. package/dist/chat-actions.js +43 -3
  10. package/dist/chat-delivery.js +51 -3
  11. package/dist/chat-quiet.d.ts +28 -0
  12. package/dist/chat-quiet.js +161 -0
  13. package/dist/cli.d.ts +1 -1
  14. package/dist/cli.js +4 -1
  15. package/dist/desktop-update.d.ts +1 -1
  16. package/dist/digest-times.d.ts +3 -0
  17. package/dist/digest-times.js +7 -0
  18. package/dist/dispose.js +2 -0
  19. package/dist/export.js +1 -1
  20. package/dist/flow-engine.js +13 -1
  21. package/dist/flow-pull-request.d.ts +11 -0
  22. package/dist/flow-pull-request.js +123 -0
  23. package/dist/flow-starters-ui.d.ts +20 -0
  24. package/dist/flow-starters-ui.js +35 -0
  25. package/dist/flow-starters.d.ts +55 -0
  26. package/dist/flow-starters.js +104 -0
  27. package/dist/flow-steps.js +14 -0
  28. package/dist/flows-ui.d.ts +1 -1
  29. package/dist/flows-ui.js +4 -3
  30. package/dist/flows.d.ts +30 -6
  31. package/dist/flows.js +110 -6
  32. package/dist/integrations-ui.d.ts +13 -0
  33. package/dist/integrations-ui.js +70 -0
  34. package/dist/integrations.d.ts +113 -0
  35. package/dist/integrations.js +526 -0
  36. package/dist/lead-context.d.ts +1 -1
  37. package/dist/lead-context.js +1 -1
  38. package/dist/mate-contract.js +1 -1
  39. package/dist/mate-tools.js +18 -5
  40. package/dist/models-ui.js +3 -2
  41. package/dist/monitoring-ui.js +2 -1
  42. package/dist/operate.d.ts +5 -2
  43. package/dist/operate.js +169 -4
  44. package/dist/policy-ui.js +2 -1
  45. package/dist/project-delete.js +1 -0
  46. package/dist/publish.d.ts +11 -0
  47. package/dist/publish.js +9 -2
  48. package/dist/pull-request-flow.d.ts +172 -0
  49. package/dist/pull-request-flow.js +475 -0
  50. package/dist/pull-request-schema.d.ts +5 -0
  51. package/dist/pull-request-schema.js +21 -0
  52. package/dist/pull-request-ui.d.ts +23 -0
  53. package/dist/pull-request-ui.js +55 -0
  54. package/dist/pulls.d.ts +5 -0
  55. package/dist/pulls.js +11 -0
  56. package/dist/serve.d.ts +6 -0
  57. package/dist/serve.js +371 -58
  58. package/dist/setup-guide.d.ts +2 -2
  59. package/dist/skills-ui.js +2 -1
  60. package/dist/store.d.ts +61 -0
  61. package/dist/store.js +144 -3
  62. package/dist/surface.js +3 -1
  63. package/dist/telegram-progress.d.ts +1 -0
  64. package/dist/telegram-progress.js +1 -1
  65. package/dist/telegram.js +95 -15
  66. package/dist/when-html.d.ts +8 -0
  67. package/dist/when-html.js +36 -0
  68. package/package.json +1 -1
@@ -0,0 +1,21 @@
1
+ /** A pull request opened by "Complete and open a pull request" is followed until it merges: how many CI
2
+ * revisions it has filed (counted across the revisions of one task, at most two), the failing head each
3
+ * answered, when a person was asked instead, the green head announced as ready, and the merge itself. One row
4
+ * per publication; the publication row stays the record of the push and the PR. */
5
+ export const PULL_REQUEST_SCHEMA = `
6
+ CREATE TABLE IF NOT EXISTS pull_request_follow (
7
+ publication INTEGER PRIMARY KEY REFERENCES publication(id) ON DELETE CASCADE,
8
+ revisions INTEGER NOT NULL DEFAULT 0 CHECK (revisions >= 0),
9
+ red_head TEXT,
10
+ revision_task TEXT,
11
+ asked_head TEXT,
12
+ ready_head TEXT,
13
+ merge_commit TEXT,
14
+ merge_method TEXT CHECK (merge_method IS NULL OR merge_method IN ('squash','merge','rebase')),
15
+ merged_by TEXT,
16
+ merged_at TEXT,
17
+ merge_error TEXT,
18
+ created_at TEXT NOT NULL,
19
+ updated_at TEXT NOT NULL
20
+ );
21
+ `;
@@ -0,0 +1,23 @@
1
+ /** Settings → Projects → Pull requests: one project's pull-request setup, in plain words. Off shows what setup
2
+ * found (or what to fix) and one Turn on; on shows where pull requests go and how they merge. Every change takes
3
+ * the password; turning on restates the exact repository and branch that were checked. */
4
+ import type { Publishing, PublishingPlan } from "./pull-request-flow.js";
5
+ export type PullRequestSettingsView = {
6
+ repo: string;
7
+ name: string;
8
+ csrf: string;
9
+ canChange: boolean;
10
+ publishing: Publishing;
11
+ /** When off: what setup found — the plan to confirm, or what to fix first. */
12
+ check: {
13
+ ok: true;
14
+ plan: PublishingPlan;
15
+ } | {
16
+ ok: false;
17
+ message: string;
18
+ } | null;
19
+ said: string | null;
20
+ problem: string | null;
21
+ };
22
+ export declare function pullRequestSettingsHtml(view: PullRequestSettingsView): string;
23
+ export declare const PULL_REQUEST_SETTINGS_CSS = "\n .pr-settings { display: grid; gap: .6rem; max-width: 40rem; }\n .pr-settings p, .pr-settings h2 { margin: 0; }\n .pr-settings label { display: grid; gap: .25rem; }\n .pr-settings label input[type=password], .pr-settings select { min-height: 44px; box-sizing: border-box; width: 100%; }\n .pr-settings .pr-check { display: flex; align-items: center; gap: .5rem; min-height: 44px; }\n .pr-settings button { min-height: 44px; justify-self: start; }\n .pr-terms { margin: 0; padding-left: 1.1rem; display: grid; gap: .25rem; }\n @media (max-width: 480px) { .pr-settings button { justify-self: stretch; } }\n";
@@ -0,0 +1,55 @@
1
+ const escape = (text) => text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
2
+ const METHOD_WORDS = { squash: "Squash and merge", merge: "Merge commit", rebase: "Rebase and merge" };
3
+ export function pullRequestSettingsHtml(view) {
4
+ const hidden = (act) => `<input type="hidden" name="csrf" value="${escape(view.csrf)}"><input type="hidden" name="repo" value="${escape(view.repo)}"><input type="hidden" name="act" value="${act}">`;
5
+ const password = `<label>Password<input type="password" name="password" autocomplete="current-password" required></label>`;
6
+ const notes = [
7
+ view.said === null ? "" : `<p class="notice" role="status">${escape(view.said)}</p>`,
8
+ view.problem === null ? "" : `<p class="problem" role="alert">${escape(view.problem)}</p>`,
9
+ ].join("");
10
+ const head = `<p class="meta">${escape(view.name)} · <span class="mono">${escape(view.repo)}</span></p>${notes}`;
11
+ const publishing = view.publishing;
12
+ if (publishing.on) {
13
+ const status = `<section class="card pr-settings"><p><strong>On</strong> · <span class="mono">${escape(publishing.githubRepo)}</span> into <span class="mono">${escape(publishing.base)}</span></p>` +
14
+ `<p class="meta">${publishing.legacy ? "Every finished build opens a pull request (set up with publish grant)." : "Complete offers “Complete and open a pull request”."} Set up by ${escape(publishing.grantedBy)}.</p></section>`;
15
+ if (!view.canChange)
16
+ return head + status;
17
+ const methods = ["squash", "merge", "rebase"].map(method => `<option value="${method}"${publishing.mergeMethod === method ? " selected" : ""}>${METHOD_WORDS[method]}${method === "squash" ? " (default)" : ""}</option>`).join("");
18
+ return head + status +
19
+ `<form method="post" action="/settings/pull-requests" class="card pr-settings">${hidden("settings")}` +
20
+ `<h2>Merging</h2>` +
21
+ `<label>Merge method<select name="method">${methods}</select></label>` +
22
+ `<label class="row pr-check"><input type="checkbox" name="when-green" value="1"${publishing.mergeWhenGreen ? " checked" : ""}> Merge when checks pass</label>` +
23
+ `<p class="meta">Off by default. When on, a pull request merges by itself once its checks pass on the completed commit. Branches are deleted after merging.</p>` +
24
+ `${password}<button type="submit">Save</button></form>` +
25
+ `<details class="settings-more"><summary>Turn off pull requests</summary>` +
26
+ `<form method="post" action="/settings/pull-requests" class="card pr-settings">${hidden("off")}` +
27
+ `<p class="meta">Nothing more is pushed. Open pull requests stay on GitHub.</p>${password}<button type="submit" class="danger">Turn off</button></form></details>`;
28
+ }
29
+ const check = view.check;
30
+ if (check === null)
31
+ return head + `<section class="card pr-settings"><p><strong>Off</strong></p><p class="meta">An approver can turn on pull requests.</p></section>`;
32
+ if (!check.ok) {
33
+ return head + `<section class="card pr-settings"><p><strong>Can’t turn on yet</strong></p><p>${escape(check.message)}</p>` +
34
+ `<p><a class="button-link" href="/settings/pull-requests?repo=${encodeURIComponent(view.repo)}">Check again</a></p></section>`;
35
+ }
36
+ const plan = check.plan;
37
+ return head +
38
+ `<form method="post" action="/settings/pull-requests" class="card pr-settings">${hidden("on")}` +
39
+ `<input type="hidden" name="github" value="${escape(plan.githubRepo)}"><input type="hidden" name="base" value="${escape(plan.base)}">` +
40
+ `<p><strong>Ready to turn on</strong></p>` +
41
+ `<ul class="pr-terms"><li>Pull requests open on <span class="mono">${escape(plan.githubRepo)}</span> into <span class="mono">${escape(plan.base)}</span>${plan.account === null ? "" : `, as ${escape(plan.account)}`}.</li>` +
42
+ `<li>Complete offers “Complete and open a pull request”, from the exact completed commit. A flow's Pull request zone can open one too.</li>` +
43
+ `<li>Merging squashes and deletes the branch. A person merges with their password; a flow merges only when its zone says so, after a person approved the card.</li></ul>` +
44
+ `${password}<button type="submit">Turn on pull requests</button></form>`;
45
+ }
46
+ export const PULL_REQUEST_SETTINGS_CSS = `
47
+ .pr-settings { display: grid; gap: .6rem; max-width: 40rem; }
48
+ .pr-settings p, .pr-settings h2 { margin: 0; }
49
+ .pr-settings label { display: grid; gap: .25rem; }
50
+ .pr-settings label input[type=password], .pr-settings select { min-height: 44px; box-sizing: border-box; width: 100%; }
51
+ .pr-settings .pr-check { display: flex; align-items: center; gap: .5rem; min-height: 44px; }
52
+ .pr-settings button { min-height: 44px; justify-self: start; }
53
+ .pr-terms { margin: 0; padding-left: 1.1rem; display: grid; gap: .25rem; }
54
+ @media (max-width: 480px) { .pr-settings button { justify-self: stretch; } }
55
+ `;
package/dist/pulls.d.ts CHANGED
@@ -92,6 +92,11 @@ export declare function parsePulls(json: string): Pull[] | null;
92
92
  * guard excluded it did exactly what it was written to do.
93
93
  */
94
94
  export declare function summarizeChecks(rollup: unknown): ChecksState;
95
+ /** The checks that finished and did not succeed, by the name GitHub shows, with their details page when one is given. */
96
+ export declare function failingChecks(rollup: unknown): {
97
+ name: string;
98
+ url: string | null;
99
+ }[];
95
100
  /**
96
101
  * Whose move it is.
97
102
  *
package/dist/pulls.js CHANGED
@@ -155,6 +155,17 @@ export function summarizeChecks(rollup) {
155
155
  return "running";
156
156
  return "passing";
157
157
  }
158
+ /** The checks that finished and did not succeed, by the name GitHub shows, with their details page when one is given. */
159
+ export function failingChecks(rollup) {
160
+ if (!Array.isArray(rollup))
161
+ return [];
162
+ return rollup.filter(entry => readCheckState(entry) === "failing").map(entry => {
163
+ const raw = entry;
164
+ const name = readString(raw["name"]) || readString(raw["context"]) || "a check";
165
+ const url = readString(raw["detailsUrl"]) || readString(raw["targetUrl"]);
166
+ return { name, url: url === "" ? null : url };
167
+ });
168
+ }
158
169
  function readCheckState(entry) {
159
170
  if (typeof entry !== "object" || entry === null)
160
171
  return "none";
package/dist/serve.d.ts CHANGED
@@ -2,6 +2,7 @@ import { CodingWorkspace } from './coding-workspace.js';
2
2
  import { type MailSender } from "./flow-actions.js";
3
3
  import { type TriggerIo } from "./flow-triggers.js";
4
4
  import { type AssignmentSnapshot } from './assignment.js';
5
+ import type { PublishExec } from './publish.js';
5
6
  import { type VersionRunner } from "./model-catalog.js";
6
7
  import { type Server } from "node:http";
7
8
  import { type ProofVerdict, type CriterionMatrixRow } from "./proof.js";
@@ -11,6 +12,7 @@ import { run as execRun } from "./exec.js";
11
12
  import { type AgentChoice } from "./agentconfig.js";
12
13
  import { type RouteProjection, type RouteOverride, type RouteStamp, type RiskLevel } from "./phase-routing.js";
13
14
  import { type Phase } from "./provider.js";
15
+ import { type IntegrationIo } from "./integrations.js";
14
16
  import { launchRuntimeUpdate } from "./toolroll-update.js";
15
17
  import type { RevisionLineage } from "./store.js";
16
18
  import type { SubscriptionMateRunner } from "./subscription-chat.js";
@@ -123,6 +125,8 @@ export type ServeOptions = {
123
125
  connectionHome?: string;
124
126
  /** Test seam for Chat's first tasks: the `gh` and `git grep` reads. */
125
127
  firstTaskRunner?: typeof execRun;
128
+ /** Test seam for Settings → Integrations: how its checks reach services (fetch, gh, mail servers). */
129
+ integrationIo?: Partial<IntegrationIo>;
126
130
  modelCatalogFetcher?: typeof fetch;
127
131
  /** Test seams for Settings → Models: CLI version probes and the PATH they search. */
128
132
  modelRunner?: VersionRunner;
@@ -155,6 +159,8 @@ export type ServeOptions = {
155
159
  ghPreview?: typeof previewGithubRepo;
156
160
  ghClone?: typeof cloneGithubRepo;
157
161
  ghList?: typeof listGithubRepos;
162
+ /** Injected by tests: the git and gh calls pull-request setup and Merge make. */
163
+ publishExec?: PublishExec;
158
164
  };
159
165
  export declare function createDecisionServer(options: ServeOptions): Server;
160
166
  /**