toolroll 0.9.61 → 0.9.63

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 (117) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/README.md +51 -3
  3. package/dist/agent-fence.d.ts +155 -10
  4. package/dist/agent-fence.js +473 -38
  5. package/dist/browser/workspace.css +1 -1
  6. package/dist/browser/workspace.js +21 -21
  7. package/dist/browser-workspace.d.ts +28 -0
  8. package/dist/chat-actions.js +2 -2
  9. package/dist/check-levels.js +3 -0
  10. package/dist/claim.js +1 -1
  11. package/dist/cli-help.d.ts +1 -1
  12. package/dist/cli-help.js +1 -0
  13. package/dist/cli.js +31 -11
  14. package/dist/contracts/cli.d.ts +8 -0
  15. package/dist/contracts/cli.js +3 -1
  16. package/dist/contracts/console-api.d.ts +19 -1
  17. package/dist/contracts/console-api.js +2 -1
  18. package/dist/contracts/integration-metadata.d.ts +2 -1
  19. package/dist/contracts/integration-metadata.js +2 -1
  20. package/dist/desktop-update.d.ts +1 -1
  21. package/dist/dispatch.js +7 -4
  22. package/dist/doctor.d.ts +53 -0
  23. package/dist/doctor.js +427 -0
  24. package/dist/evidence-pack.d.ts +1 -1
  25. package/dist/evidence-pack.js +2 -2
  26. package/dist/exec.d.ts +3 -0
  27. package/dist/exec.js +5 -4
  28. package/dist/flow-code.d.ts +2 -2
  29. package/dist/flow-code.js +4 -15
  30. package/dist/flow-engine.js +11 -6
  31. package/dist/flow-triggers.d.ts +8 -4
  32. package/dist/flow-triggers.js +45 -25
  33. package/dist/flow-unattended-words.d.ts +28 -0
  34. package/dist/flow-unattended-words.js +50 -0
  35. package/dist/flow-unattended.d.ts +227 -0
  36. package/dist/flow-unattended.js +776 -0
  37. package/dist/flows-cli.d.ts +28 -1
  38. package/dist/flows-cli.js +55 -10
  39. package/dist/flows-ui.d.ts +2 -1
  40. package/dist/flows-ui.js +4 -1
  41. package/dist/google-mail.d.ts +1 -0
  42. package/dist/google-mail.js +61 -18
  43. package/dist/integrations-ui.d.ts +2 -1
  44. package/dist/integrations-ui.js +6 -3
  45. package/dist/integrations.d.ts +17 -3
  46. package/dist/integrations.js +38 -18
  47. package/dist/invoke.js +300 -168
  48. package/dist/landed-cleanup.d.ts +26 -12
  49. package/dist/landed-cleanup.js +199 -85
  50. package/dist/lead-contract.d.ts +1 -1
  51. package/dist/lead-contract.js +3 -3
  52. package/dist/lead-tools.js +11 -3
  53. package/dist/mcp-connect.d.ts +8 -7
  54. package/dist/mcp-connect.js +49 -51
  55. package/dist/oauth-run-token.d.ts +51 -0
  56. package/dist/oauth-run-token.js +127 -0
  57. package/dist/operate.js +74 -17
  58. package/dist/plan-auto.d.ts +11 -0
  59. package/dist/plan-auto.js +62 -11
  60. package/dist/process-recovery-eligibility.d.ts +1 -1
  61. package/dist/project-access.d.ts +3 -0
  62. package/dist/project-access.js +3 -0
  63. package/dist/project-admission.d.ts +10 -6
  64. package/dist/project-admission.js +33 -11
  65. package/dist/project-delete-ui.d.ts +1 -0
  66. package/dist/project-delete-ui.js +4 -1
  67. package/dist/project-delete.d.ts +3 -1
  68. package/dist/project-delete.js +10 -4
  69. package/dist/project-file.d.ts +3 -0
  70. package/dist/project-file.js +16 -0
  71. package/dist/project-tools.d.ts +99 -25
  72. package/dist/project-tools.js +394 -98
  73. package/dist/provider-home.d.ts +22 -0
  74. package/dist/provider-home.js +99 -0
  75. package/dist/provider.d.ts +17 -3
  76. package/dist/provider.js +34 -10
  77. package/dist/remote-main.d.ts +61 -0
  78. package/dist/remote-main.js +179 -0
  79. package/dist/scope.d.ts +1 -1
  80. package/dist/serve.js +11 -3
  81. package/dist/server/flows.js +27 -5
  82. package/dist/server/render-tasks.d.ts +3 -0
  83. package/dist/server/render-tasks.js +3 -0
  84. package/dist/server/route-table.js +3 -0
  85. package/dist/server/runtime.d.ts +1 -1
  86. package/dist/server/settings.js +14 -5
  87. package/dist/server/task-views.js +2 -0
  88. package/dist/storage-sweep-child.js +3 -1
  89. package/dist/storage-sweep-process.d.ts +14 -0
  90. package/dist/storage-sweep-process.js +37 -3
  91. package/dist/storage-sweep-schedule.d.ts +30 -0
  92. package/dist/storage-sweep-schedule.js +164 -0
  93. package/dist/storage-sweep.d.ts +6 -5
  94. package/dist/storage-sweep.js +10 -70
  95. package/dist/storage-ui.d.ts +2 -0
  96. package/dist/storage-ui.js +7 -4
  97. package/dist/store.d.ts +75 -7
  98. package/dist/store.js +241 -17
  99. package/dist/subagent-tools.d.ts +1 -1
  100. package/dist/surface.js +10 -6
  101. package/dist/task-base.d.ts +35 -0
  102. package/dist/task-base.js +51 -0
  103. package/dist/teardown-git.d.ts +14 -0
  104. package/dist/teardown-git.js +119 -0
  105. package/dist/tool-broker.d.ts +37 -0
  106. package/dist/tool-broker.js +369 -0
  107. package/dist/tool-launcher.js +5 -4
  108. package/dist/tool-secret-store.d.ts +170 -0
  109. package/dist/tool-secret-store.js +834 -0
  110. package/dist/toolroll-update.js +4 -2
  111. package/dist/tools-ui.d.ts +7 -1
  112. package/dist/tools-ui.js +17 -8
  113. package/dist/work-index.js +5 -3
  114. package/dist/worktree.d.ts +64 -6
  115. package/dist/worktree.js +171 -35
  116. package/package.json +3 -1
  117. package/scripts/provider-canary.mjs +210 -31
@@ -1,7 +1,7 @@
1
1
  /**
2
- * The daily storage sweep: the plane cleans up after itself without anyone running a command. Once a day (one worker
3
- * takes the day: the cursor moves in the same transaction) it removes test temp folders nothing touched for a day
4
- * (test-temp.ts), stops orphans Toolroll left running (orphan-sweep.ts), removes finished checkouts the cleanup
2
+ * The storage sweep: the plane cleans up after itself without anyone running a command. About once a day, when nothing
3
+ * is running or waiting (storage-sweep-schedule.ts: one service takes it, the cursor moves in the same transaction),
4
+ * it removes test temp folders nothing touched for a day (test-temp.ts), stops orphans Toolroll left running (orphan-sweep.ts), removes finished checkouts the cleanup
5
5
  * setting lets go (checkout-cleanup.ts), keeps the current, previous and newest staged runtimes (staged-runtimes.ts)
6
6
  * and removes shared dependency installs no checkout has used for a week (shared-deps.ts).
7
7
  *
@@ -17,8 +17,9 @@
17
17
  *
18
18
  * What each sweep did is saved (the latest few) and in the ledger: `toolroll storage` and Settings → Storage show it.
19
19
  * A clean-up by hand (`storage clean --yes`) is saved the same way. A part that failed, or had more than one pass
20
- * takes, brings the next sweep forward to an hour later. `TOOLROLL_STORAGE_SWEEP=off` turns the automatic sweep off
21
- * (the unit tests do, so a test never sweeps the machine it runs on).
20
+ * takes, brings the next sweep forward to an hour later; it still waits for nothing to be running.
21
+ * `TOOLROLL_STORAGE_SWEEP=off` turns the automatic sweep off (the unit tests do, so a test never sweeps the machine
22
+ * it runs on).
22
23
  */
23
24
  import { realpathSync } from "node:fs";
24
25
  import { hostname } from "node:os";
@@ -29,11 +30,10 @@ import { processCensus } from "./run-closeout.js";
29
30
  import { linkedKey, pruneUnusedShared, sharedDepsRoot, sharedUse, SHARED_UNUSED_MS } from "./shared-deps.js";
30
31
  import { pruneStagedRuntimes, runtimesInUse, runtimeScriptPaths, stagePlan } from "./staged-runtimes.js";
31
32
  import { bytesWords, diskBytes } from "./storage.js";
32
- import { openStoreNoMigrate } from "./store.js";
33
33
  import { removeStaleTestTemp } from "./test-temp.js";
34
34
  import { worktreeProcessOccupancy } from "./worktree.js";
35
- import { runSweepChild, storageSweepSupervisor } from "./storage-sweep-process.js";
36
- const CURSOR = "storage-sweep";
35
+ import { runSweepChild } from "./storage-sweep-process.js";
36
+ export const SWEEP_CURSOR = "storage-sweep";
37
37
  export const SWEEP_EVERY_MS = 86_400_000;
38
38
  /** A sweep that failed somewhere, or left work for later, runs again this soon. */
39
39
  export const RETRY_MS = 60 * 60_000;
@@ -46,67 +46,7 @@ const ITEMS_MAX = 20;
46
46
  export function storageSweepOff(env = process.env) {
47
47
  return (env["TOOLROLL_STORAGE_SWEEP"] ?? "").trim().toLowerCase() === "off";
48
48
  }
49
- export function storageSweepDue(store, now) {
50
- return now.getTime() - store.serviceCursor(CURSOR) >= SWEEP_EVERY_MS;
51
- }
52
- /** Claim and launch only. A hung child never holds reconciliation or the caller's store open. */
53
- export function dailyStorageSweep(store, deps, now, supervisor = storageSweepSupervisor(deps.databaseFile)) {
54
- if (storageSweepOff() || supervisor.running || !storageSweepDue(store, now()))
55
- return null;
56
- // This handle belongs to the flight, not to the command that has already returned by the time it finishes.
57
- const connection = openStoreNoMigrate(deps.databaseFile);
58
- if (!connection.ok)
59
- throw new Error("Sweep result store unavailable");
60
- const results = connection.store;
61
- const at = now();
62
- let completed = null;
63
- let owned = false;
64
- try {
65
- const mine = store.transact(() => {
66
- if (!storageSweepDue(store, at))
67
- return false;
68
- store.setServiceCursor(CURSOR, at.getTime(), at);
69
- return true;
70
- });
71
- if (!mine)
72
- return null;
73
- const request = { version: 1, databaseFile: deps.databaseFile, poolRoot: deps.pool?.root ?? null, tempRoots: [...deps.tempRoots], actor: deps.actor ?? "worker", at: at.toISOString() };
74
- owned = supervisor.start(request, result => {
75
- const record = result.ok ? result.record : sweepFailure(request.at, request.actor, deps.pool !== null, result.reason);
76
- try {
77
- results.transact(() => {
78
- if (!results.schemaCurrent())
79
- throw new Error("Sweep result store changed");
80
- saveSweep(results, record);
81
- // Only this claim can reschedule itself. A later claim must never be overwritten by a late callback.
82
- if (record.parts.some(one => one.failed > 0 || one.more === true || one.problem !== undefined) && results.serviceCursor(CURSOR) === at.getTime()) {
83
- results.setServiceCursor(CURSOR, Math.max(0, now().getTime() - SWEEP_EVERY_MS + RETRY_MS), now());
84
- }
85
- });
86
- completed = record;
87
- }
88
- catch {
89
- // No exception/path from a process or database is safe to copy into a log.
90
- console.error("Could not save the storage sweep result.");
91
- }
92
- finally {
93
- results.close();
94
- }
95
- }, deps.owner);
96
- if (!owned) {
97
- store.transact(() => {
98
- if (store.serviceCursor(CURSOR) === at.getTime())
99
- store.setServiceCursor(CURSOR, Math.max(0, at.getTime() - SWEEP_EVERY_MS + RETRY_MS), now());
100
- });
101
- }
102
- return completed;
103
- }
104
- finally {
105
- if (!owned)
106
- results.close();
107
- }
108
- }
109
- function sweepFailure(at, actor, withPool, reason) {
49
+ export function sweepFailure(at, actor, withPool, reason) {
110
50
  const problem = reason === "timeout" ? "The sweep process exceeded its time limit; some cleanup may have completed. Cleanup will retry later."
111
51
  : reason === "stopped" ? "The sweep process was stopped; some cleanup may have completed. Cleanup will retry later."
112
52
  : "The sweep process did not return a valid result; some cleanup may have completed.";
@@ -339,7 +279,7 @@ export function lastSweep(store, source) {
339
279
  export function nextSweepAt(store) {
340
280
  if (storageSweepOff())
341
281
  return null;
342
- const last = store.serviceCursor(CURSOR);
282
+ const last = store.serviceCursor(SWEEP_CURSOR);
343
283
  return last === 0 ? null : new Date(last + SWEEP_EVERY_MS).toISOString();
344
284
  }
345
285
  const NOUNS = {
@@ -1,6 +1,7 @@
1
1
  import { type Html } from "./html.js";
2
2
  import { type CheckoutPlan } from "./checkout-cleanup.js";
3
3
  import { type SweepRecord } from "./storage-sweep.js";
4
+ import { type SweepSchedule } from "./storage-sweep-schedule.js";
4
5
  import type { LandedSummary } from "./landed-cleanup.js";
5
6
  export declare const STORAGE_CSS: string;
6
7
  export type StorageView = {
@@ -9,6 +10,7 @@ export type StorageView = {
9
10
  sweep?: {
10
11
  last: SweepRecord | null;
11
12
  off: boolean;
13
+ schedule?: SweepSchedule;
12
14
  };
13
15
  landed?: LandedSummary;
14
16
  };
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Settings → Storage: how much space task checkouts use, what a clean-up would free now, a Clean up button whose
3
3
  * preview (what goes, what stays and why, with paths) sits behind the password, what the last storage sweep removed
4
- * and when (its paths in a disclosure), what landed work's teardown did and still waits on (in a disclosure, with the
4
+ * and when (its paths in a disclosure) and why the next one waits, what landed work's teardown did and still waits on (in a disclosure, with the
5
5
  * one-time command for older work), and when a finished task's clean checkout goes by itself. An instance operator's page.
6
6
  */
7
7
  import { homedir } from "node:os";
@@ -10,6 +10,7 @@ import { html, postForm } from "./html.js";
10
10
  import { previewDigest, whyWords } from "./checkout-cleanup.js";
11
11
  import { CLEANUP_CHOICES, bytesWords } from "./storage.js";
12
12
  import { sweepDetails, sweepWords } from "./storage-sweep.js";
13
+ import { sweepScheduleWords } from "./storage-sweep-schedule.js";
13
14
  const plural = (count, one, many = `${one}s`) => `${count} ${count === 1 ? one : many}`;
14
15
  export const STORAGE_CSS = `.storage{max-width:720px;min-width:0;overflow-wrap:anywhere}.storage h2{font-size:1.0625rem;margin:24px 0 4px}` +
15
16
  `.storage .storage-state{display:grid;gap:12px}.storage .storage-state h2{margin:0}.storage .storage-state p{margin:0}` +
@@ -45,15 +46,17 @@ function whenWords(at) {
45
46
  const date = new Date(at);
46
47
  return Number.isNaN(date.getTime()) ? at : date.toLocaleString("en-US", { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
47
48
  }
48
- /** One line: when the last sweep ran and what it did; its paths and problems behind Details. */
49
+ /** 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. */
49
50
  function sweepHtml(sweep) {
50
51
  const last = sweep.last;
52
+ const schedule = sweep.schedule === undefined ? (sweep.off ? html `<p class="meta" data-sweep-state="off">Automatic sweep: off.</p>` : "")
53
+ : html `<p class="meta" data-sweep-state="${sweep.schedule.state}">Automatic sweep: ${sweepScheduleWords(sweep.schedule, whenWords)}</p>`;
51
54
  if (last === null)
52
- return html `<p class="meta" data-last-sweep="">${sweep.off ? "Automatic sweep is off." : html `Toolroll sweeps leftovers once a day. It hasn't run yet.`}</p>`;
55
+ return html `<div class="sweep" data-last-sweep=""><p>Not swept yet.</p>${schedule}</div>`;
53
56
  const who = last.source === "manual" ? `Cleaned up by ${last.actor}` : "Swept";
54
57
  const details = sweepDetails(last.parts);
55
58
  const problem = last.parts.some(one => one.failed > 0 || one.problem !== undefined);
56
- return html `<div class="sweep" data-last-sweep="${last.at}"><p${problem ? html ` class="problem"` : ""}>${who} <time datetime="${last.at}">${whenWords(last.at)}</time>. ${sweepWords(last.parts)}</p>${details.length === 0 ? "" : html `<details class="sweep-details"><summary>Details</summary><ul>${details.map(line => html `<li>${homeAsTilde(line)}</li>`)}</ul></details>`}</div>`;
59
+ return html `<div class="sweep" data-last-sweep="${last.at}"><p${problem ? html ` class="problem"` : ""}>${who} <time datetime="${last.at}">${whenWords(last.at)}</time>. ${sweepWords(last.parts)}</p>${schedule}${details.length === 0 ? "" : html `<details class="sweep-details"><summary>Details</summary><ul>${details.map(line => html `<li>${homeAsTilde(line)}</li>`)}</ul></details>`}</div>`;
57
60
  }
58
61
  /** Landed work, on demand: what its teardown did, what it waits on and why, and the one-time command for older work. */
59
62
  function landedHtml(landed) {
package/dist/store.d.ts CHANGED
@@ -78,6 +78,11 @@ export declare const FLOW_SEND_SCHEMA = "\nCREATE TABLE IF NOT EXISTS flow_send
78
78
  * vocabulary and when — never text, tool names or arguments. Display state, not evidence;
79
79
  * a finished run's row goes with the live log's own retention (sweepRunActivity). */
80
80
  export declare const RUN_ACTIVITY_SCHEMA = "\nCREATE TABLE IF NOT EXISTS run_activity (\n run INTEGER PRIMARY KEY REFERENCES run(id) ON DELETE CASCADE,\n kind TEXT NOT NULL CHECK (kind IN ('session','message','edit','command','read','search','lookup','plan','delegate','tool')),\n at TEXT NOT NULL\n);\n";
81
+ /** A task branch moved to current main before an attempt (fresh base; v122, a new table: additive only): the branch
82
+ * had no commits of its own and no changes, so it started over from `to_rev`. `after_run` is the newest run id when it
83
+ * moved: the branch's whole-task diff runs from the first builder base recorded after it (firstBuilderBase), never from
84
+ * the older main it left. */
85
+ export declare const BRANCH_BASE_MOVE_SCHEMA = "\nCREATE TABLE IF NOT EXISTS branch_base_move (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n task_ref INTEGER NOT NULL REFERENCES task_ref(id) ON DELETE CASCADE,\n branch TEXT NOT NULL,\n from_rev TEXT NOT NULL,\n to_rev TEXT NOT NULL,\n after_run INTEGER NOT NULL,\n moved_at TEXT NOT NULL\n);\nCREATE INDEX IF NOT EXISTS branch_base_move_branch ON branch_base_move (task_ref, branch, id);\n";
81
86
  /** Pausing a running Claude build (live steering, v121: additive only). A person's Pause asks the build to
82
87
  * stop its current turn and keep its session: one row per request, bound to the exact run it was asked of, under the
83
88
  * request id the asker chose (a repeated request is the same request). `note` is the steering note a Pause and steer
@@ -105,6 +110,10 @@ export declare const LEAD_FOLLOW_MESSAGE = "Automatic crew update: inspect the s
105
110
  * nothing set up, such as no `gh` sign-in). `ok_at` and `error`/`error_at` keep the last success and the last
106
111
  * failure across checks, so a row can say both. `account` is a display name only, never a credential. */
107
112
  export declare const INTEGRATIONS_SCHEMA = "\nCREATE TABLE IF NOT EXISTS integration_check (\n key TEXT PRIMARY KEY,\n outcome TEXT NOT NULL CHECK (outcome IN ('ok', 'failed', 'absent')),\n account TEXT,\n detail TEXT,\n problem TEXT,\n checked_at TEXT NOT NULL,\n ok_at TEXT,\n error TEXT,\n error_at TEXT\n);\n";
113
+ /** Tool secrets (no version bump): which sealing key Toolroll made for the secrets it keeps in the keychain, as a
114
+ * digest of the key, never the key. A key found beside them that isn't this one was put there by something else and is
115
+ * refused (tool-secret-store.ts). */
116
+ export declare const TOOL_SECRET_KEY_SCHEMA = "\nCREATE TABLE IF NOT EXISTS tool_secret_key (\n id INTEGER PRIMARY KEY CHECK (id = 1),\n digest TEXT NOT NULL CHECK (length(digest) = 64),\n made_at TEXT NOT NULL\n);\n-- Where secrets were kept before Toolroll's folder, decided once at this database's first start (null: none) and never\n-- probed again, so a folder a build makes later under an old name is never migrated in.\nCREATE TABLE IF NOT EXISTS tool_secret_legacy (\n id INTEGER PRIMARY KEY CHECK (id = 1),\n dir TEXT,\n decided_at TEXT NOT NULL\n);\n";
108
117
  export type BackupSettings = {
109
118
  enabled: boolean;
110
119
  everyHours: number;
@@ -161,7 +170,7 @@ export type SealedLedgerEntry = LedgerEntry & {
161
170
  hash: string;
162
171
  } | null;
163
172
  };
164
- export declare const SCHEMA_VERSION = 121;
173
+ export declare const SCHEMA_VERSION = 123;
165
174
  /** v118: the tables merged into `credential`, in the order they move (a person's API tokens keep their ids first). */
166
175
  export declare const V118_MERGED_TABLES: Readonly<Record<string, CredentialKind>>;
167
176
  /**
@@ -220,7 +229,10 @@ export declare const V115_DROPPED_TABLES: readonly string[];
220
229
  * (planning_generation on task_ref, run and plan_revision, defaulting to 0, and decision.superseded_reason, null);
221
230
  * the rehearsal checks every saved row reads the declared default (HISTORY_RULES' added columns). v120 only adds
222
231
  * three nullable task_steer columns (the running build's steering folder), checked the same way. v121 only adds
223
- * new tables and the columns in V121_ADDED_COLUMNS (null, or no sends), checked the same way.
232
+ * new tables and the columns in V121_ADDED_COLUMNS (null, or no sends), checked the same way. v122 only adds a new
233
+ * table (branch_base_move) and the nullable column in V122_ADDED_COLUMNS (a project's recorded remote), checked the
234
+ * same way. v123 only adds new tables (unattended flows, tool secrets) and the columns in V123_ADDED_COLUMNS ('mode',
235
+ * 0 or null), checked the same way.
224
236
  */
225
237
  export declare const UPDATE_SAFE_MIGRATIONS: readonly number[];
226
238
  /** v119: the columns it adds, by table, with the value every row saved before it reads (toolroll-update's HISTORY_RULES). */
@@ -250,6 +262,19 @@ export declare const V121_ADDED_COLUMNS: Readonly<Record<string, Readonly<Record
250
262
  definition: string;
251
263
  saved: string;
252
264
  }>>>>;
265
+ /** v122: the column it adds, with the value every row saved before it reads: the remote URL an owner's project add
266
+ * recorded (projects added before it read none, until `repos add <project> --remote <url>` records one). */
267
+ export declare const V122_ADDED_COLUMNS: Readonly<Record<string, Readonly<Record<string, {
268
+ definition: string;
269
+ saved: string;
270
+ }>>>>;
271
+ /** v123: the columns it adds, with the value every row saved before it reads: which authority armed a plan's
272
+ * unchanged-plan approval (saved rows read the operating mode), whether a trigger's firing was the clock's own (saved
273
+ * firings read not), and what code an on-time script firing a grant signed for ran (saved firings read none). */
274
+ export declare const V123_ADDED_COLUMNS: Readonly<Record<string, Readonly<Record<string, {
275
+ definition: string;
276
+ saved: string;
277
+ }>>>>;
253
278
  /** Whether a database settled at `version` reaches this build's schema through update-safe migrations alone. */
254
279
  export declare function updateSafeSchema(version: number | null): boolean;
255
280
  export type OAuthClientRow = {
@@ -1757,6 +1782,18 @@ export declare class Store {
1757
1782
  /** The database's own file (null in memory): where the agent fence begins. */
1758
1783
  databaseFile(): string | null;
1759
1784
  close(): void;
1785
+ /** The digest of the sealing key Toolroll made for its tool secrets; null before it made one (or in an older database). */
1786
+ toolSecretKeyDigest(): string | null;
1787
+ /**
1788
+ * The folder secrets were kept in before Toolroll's own, as decided at this database's first start of a command that
1789
+ * can start builds (`record`): `probe` runs until then, and its answer (null: none) is kept for every later start.
1790
+ * Other commands never write, so a preview stays read-only and a busy database doesn't stop them.
1791
+ */
1792
+ toolSecretLegacyDir(probe: () => string | null, now: Date, options: {
1793
+ record: boolean;
1794
+ }): string | null;
1795
+ /** Record a new sealing key's digest only if the one recorded is still `expected` (null: none yet). */
1796
+ swapToolSecretKeyDigest(expected: string | null, next: string, now: Date): boolean;
1760
1797
  /**
1761
1798
  * Creating a task also creates its overlay reference, because a task with no
1762
1799
  * `TaskRef` cannot be claimed, held, or scheduled — it would be work the
@@ -2151,7 +2188,7 @@ export declare class Store {
2151
2188
  * exactly what the signed digest was bound to. Returns false when the
2152
2189
  * scope vanished mid-ceremony. */
2153
2190
  sealScopeApproval(taskId: string, by: string, now: Date, mutation?: Mutation, basis?: {
2154
- kind: "mode" | "chat";
2191
+ kind: "mode" | "chat" | "grant";
2155
2192
  modeDigest: string;
2156
2193
  }, approverKind?: ApproverKind): boolean;
2157
2194
  /** Whether this task's scope carries a LIVE seal: approved, and the
@@ -2206,6 +2243,10 @@ export declare class Store {
2206
2243
  * ceremony. Reconciliation drops mode-basis intents to waiting-human;
2207
2244
  * `firing` rows are untouched — an issued call is one-shot (E1). */
2208
2245
  revokeMode(repo: string, by: string, reason: string, now: Date): boolean;
2246
+ /** A flow's "runs on its own" grant ended (revoked, expired, renewed): the undispatched work it sealed falls back
2247
+ * to a person, as a mode's does, and plans it armed lose their pre-authorization. Running and finished work keeps
2248
+ * its history. */
2249
+ withdrawGrantApprovals(digest: string, now: Date): void;
2209
2250
  /** F2/R-REVOKE: the ONE reconciliation road. newMode null = no live
2210
2251
  * automerge authority (revocation, expiry, or a notify posture):
2211
2252
  * mode-basis pending/claimed intents drop to waiting-human, leases
@@ -4350,6 +4391,20 @@ export declare class Store {
4350
4391
  * legacy first-attempt behavior, unchanged byte-for-byte.
4351
4392
  */
4352
4393
  firstBuilderBase(taskRef: number, branch: string): string | null;
4394
+ /** Where a task branch's attempts start now: a builder branch's pinned base, or the newest base any other attempt on
4395
+ * it recorded (a planner never commits). Null before any attempt on the branch recorded one, or after a move to
4396
+ * current main until the next attempt records its base. */
4397
+ recordedBranchBase(taskRef: number, branch: string): string | null;
4398
+ /** Record a task branch's move to current main, before git moves it: a move that then fails leaves the next
4399
+ * attempt's own base (still the old one) as the branch's origin, which is exactly right. */
4400
+ recordBranchBaseMove(taskRef: number, branch: string, from: string, to: string, now: Date): void;
4401
+ /** The newest move of a task branch to current main, or null. */
4402
+ latestBranchBaseMove(taskRef: number, branch: string): {
4403
+ from: string;
4404
+ to: string;
4405
+ afterRun: number;
4406
+ movedAt: string;
4407
+ } | null;
4353
4408
  finishRun(id: number, result: {
4354
4409
  outcome: "built" | "failed" | "refused" | "parked" | "no-change" | "interrupted";
4355
4410
  reason?: string;
@@ -4385,6 +4440,10 @@ export declare class Store {
4385
4440
  * other class is observational.
4386
4441
  */
4387
4442
  stampTerminalClass(id: number, authMode: "subscription" | "api-key", terminalClass: TerminalClass): void;
4443
+ /** A launch refused before any model turn (an installed CLI too old for a
4444
+ * build's flags): the start stamp goes, its version and evidence stay. Only
4445
+ * while the run is open, so a settled run's account never changes. */
4446
+ withdrawProviderStart(id: number): void;
4388
4447
  /** The race-refusal stamp (Phase 3 C5): the version that was REFUSED,
4389
4448
  * recorded without provider_started_at — no provider process started. */
4390
4449
  stampProviderVersion(id: number, providerVersion: string): void;
@@ -5657,7 +5716,7 @@ export declare class Store {
5657
5716
  }, now: Date): number;
5658
5717
  /** A person approves a held script (one an imported flow brought): from now on it runs. False when it wasn't held. */
5659
5718
  approveFlowScript(repo: string, name: string): boolean;
5660
- removeFlowScript(repo: string, name: string): boolean;
5719
+ removeFlowScript(repo: string, name: string, by?: string, now?: Date): boolean;
5661
5720
  /** Claim a card's visit to a step zone. False when another pass holds it or it already finished. */
5662
5721
  claimFlowStep(step: {
5663
5722
  card: number;
@@ -5737,7 +5796,7 @@ export declare class Store {
5737
5796
  lastOutcome?: string;
5738
5797
  failures?: number;
5739
5798
  hookHash?: string | null;
5740
- }, now: Date): void;
5799
+ }, now: Date, by?: string): void;
5741
5800
  /** Whether a trigger already handled this outside thing (an issue, a run, a schedule slot). */
5742
5801
  flowTriggerSaw(trigger: number, key: string): boolean;
5743
5802
  /** The card one outside thing made (v89: a chat message, so replies in its thread find it). */
@@ -5748,7 +5807,7 @@ export declare class Store {
5748
5807
  * Record what a trigger did with one outside thing: the card it made, or why it made none, and (a standing order's
5749
5808
  * firing) the task it filed. False when it was already recorded.
5750
5809
  */
5751
- recordFlowTriggerEvent(trigger: number, key: string, card: number | null, note: string | null, now: Date, task?: string | null): boolean;
5810
+ recordFlowTriggerEvent(trigger: number, key: string, card: number | null, note: string | null, now: Date, task?: string | null, onTime?: boolean, ranScript?: string | null): boolean;
5752
5811
  /** The last card a trigger made, if any. */
5753
5812
  lastFlowTriggerCard(trigger: number): number | null;
5754
5813
  /**
@@ -6004,7 +6063,15 @@ export declare class Store {
6004
6063
  leadStepsOf(leadTurn: number): ChatTurn[];
6005
6064
  /** Remember a project was opened. Upsert keeps added_at; recency always moves.
6006
6065
  * A project added for the first time starts on Quick checks. */
6007
- upsertProject(path: string, name: string, now: Date): void;
6066
+ upsertProject(path: string, name: string, now: Date, admission?: {
6067
+ remoteUrl: string | null;
6068
+ }): void;
6069
+ /** Includes removed/legacy projects, so deleting a row never makes build-writable config authoritative again. */
6070
+ projectAdmissionKnown(path: string): boolean;
6071
+ /** Full structured URL audit, without the generic ledger's display-text truncation. */
6072
+ recordProjectRemote(actor: string, repo: string, previous: string | null, remoteUrl: string, now: Date): void;
6073
+ /** The remote URL captured on admission or explicitly supplied by the owner; null when none was (or the project was removed). */
6074
+ projectRemote(path: string): string | null;
6008
6075
  /** A project removed from the lists (project-admission.ts): only its row goes; its tasks, results and settings stay. */
6009
6076
  forgetProject(path: string): void;
6010
6077
  /** Most recently opened first — the opener page's order. */
@@ -6013,6 +6080,7 @@ export declare class Store {
6013
6080
  name: string;
6014
6081
  addedAt: string;
6015
6082
  lastOpenedAt: string;
6083
+ remoteUrl: string | null;
6016
6084
  }[];
6017
6085
  /**
6018
6086
  * Tasks whose scope waits on a person's yes: proposed, not approved (or