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
@@ -0,0 +1,170 @@
1
+ export type SecretStoreKind = "macos-keychain" | "secret-service" | "files";
2
+ /** One item's address: what the store lists, never a secret (a folder's or project's hash, a tool's name). */
3
+ export type SecretItem = {
4
+ service: string;
5
+ account: string;
6
+ };
7
+ export type SecretBackend = {
8
+ kind: Exclude<SecretStoreKind, "files">;
9
+ /** Values are [A-Za-z0-9._-] only, at most `limit` characters. */
10
+ limit: number;
11
+ get(item: SecretItem): string | null;
12
+ /** `create`: only when no item is there yet ("exists" when one is). */
13
+ set(item: SecretItem, value: string, options?: {
14
+ create?: boolean;
15
+ }): "ok" | "exists";
16
+ remove(item: SecretItem): void;
17
+ };
18
+ export declare class SecretStoreError extends Error {
19
+ }
20
+ /** The words Settings and `toolroll integrations` use for where secrets rest. */
21
+ export declare const STORE_WORDS: Readonly<Record<SecretStoreKind, string>>;
22
+ /** Said instead when a keyring is installed but doesn't answer, so files are all there is. */
23
+ export declare const UNANSWERED_WORDS = "Secrets are protected by owner-only files on this computer: its keyring isn't answering.";
24
+ /** The macOS Keychain, through `security -i` (`keychain`: a keychain file instead of the user's own, for tests). */
25
+ export declare function macosKeychain(options?: {
26
+ keychain?: string;
27
+ binary?: string;
28
+ }): SecretBackend;
29
+ /** The Secret Service (GNOME Keyring, KWallet), through `secret-tool` at `binary`, an absolute path; the value goes on its stdin. */
30
+ export declare function secretService(options: {
31
+ binary: string;
32
+ }): SecretBackend;
33
+ /**
34
+ * `path` when it is a program only the system (or, for a test's stand-in, one of `owners`) can have put there: a real
35
+ * executable file nobody else can change, in folders nobody else can either. Null otherwise.
36
+ */
37
+ export declare function trustedProgram(path: string, owners?: readonly number[]): string | null;
38
+ /** Where `secret-tool` may be: the system's own folders, never the PATH a process was given. */
39
+ export declare const SECRET_TOOL_PATHS: readonly string[];
40
+ /** This computer's store as found: a backend, or none, and when none, whether one is installed but not answering. */
41
+ export type DetectedStore = {
42
+ backend: SecretBackend | null;
43
+ unanswered: boolean;
44
+ };
45
+ /**
46
+ * Find this computer's store: the macOS Keychain where the system's `security` is; a Secret Service where the system's
47
+ * `secret-tool` is and answers; else none (files). A `secret-tool` that is there but can't reach a keyring (no session
48
+ * bus) is none too, and says so.
49
+ */
50
+ export declare function detectSecretStore(options?: {
51
+ platform?: NodeJS.Platform;
52
+ secretTools?: readonly string[];
53
+ owners?: readonly number[];
54
+ }): DetectedStore;
55
+ /** Tests choose the store (a keychain file of their own, files, or what detection found); null goes back to this computer's. */
56
+ export declare function chooseSecretStore(store: SecretBackend | "files" | DetectedStore | null): void;
57
+ /** This computer's store (found once), or null for owner-only files. */
58
+ export declare function secretBackend(env?: NodeJS.ProcessEnv): SecretBackend | null;
59
+ export declare const secretStoreKind: () => SecretStoreKind;
60
+ /** Where secrets rest, in the words Settings and `toolroll integrations` share; `problem` when Toolroll's folder can't be used. */
61
+ export declare function secretStorage(): {
62
+ kind: SecretStoreKind;
63
+ words: string;
64
+ filesOnly: boolean;
65
+ problem?: string;
66
+ };
67
+ /** The text stored at `item`, or null when nothing is. A head read while a writer replaces it is read again. */
68
+ export declare function readValue(backend: SecretBackend, item: SecretItem): string | null;
69
+ /**
70
+ * Store `text` at `item`: the chunks of a new generation first, then the head that names them, then the old
71
+ * generation's chunks are removed. `create`: only when nothing is stored there yet.
72
+ */
73
+ export declare function writeValue(backend: SecretBackend, item: SecretItem, text: string, options?: {
74
+ create?: boolean;
75
+ }): "ok" | "exists";
76
+ /** Remove what is stored at `item`, every chunk with it. */
77
+ export declare function removeValue(backend: SecretBackend, item: SecretItem): void;
78
+ /** The folder's name, beside the database. */
79
+ export declare const SECRET_FOLDER = "tool-secrets";
80
+ /** Where Toolroll records which sealing key it made: the database, which no build can write. */
81
+ export type KeyAnchor = {
82
+ read(): string | null;
83
+ swap(expected: string | null, next: string): boolean;
84
+ };
85
+ /** An anchor kept in this process alone: a test's own folder. */
86
+ export declare function memoryAnchor(): KeyAnchor;
87
+ /** Toolroll's folder for secrets, checked: its key in hand, and where the files kept before it are (`legacy`). */
88
+ export type SecretFolder = {
89
+ readonly root: string;
90
+ readonly dir: string;
91
+ readonly legacy: string | null;
92
+ dev: number;
93
+ ino: number;
94
+ key: Buffer;
95
+ digest: string;
96
+ anchor: KeyAnchor;
97
+ };
98
+ /**
99
+ * Prepare Toolroll's folder for secrets beside `stateDir` (the folder holding the database), checked against what
100
+ * `anchor` recorded: made with its sealing key when it isn't there yet (`create`), refused when something else put a
101
+ * folder, key or link there. `standing`: the folder this process uses by default (Toolroll's own start).
102
+ */
103
+ export declare function prepareSecretFolder(stateDir: string, anchor: KeyAnchor, options?: {
104
+ create?: boolean;
105
+ legacy?: string | null;
106
+ standing?: boolean;
107
+ }): {
108
+ ok: true;
109
+ dir: string;
110
+ } | {
111
+ ok: false;
112
+ problem: string;
113
+ };
114
+ /**
115
+ * Name Toolroll's folder for secrets (beside `stateDir`, the database's folder) and the record to check it against,
116
+ * without touching it yet: it is prepared the first time a secret is used. `standing`: this process's default.
117
+ */
118
+ export declare function registerSecretFolder(stateDir: string, anchor: KeyAnchor, options?: {
119
+ legacy?: string | null;
120
+ }): void;
121
+ /**
122
+ * Toolroll's folder for secrets, checked again now: the one prepared at start when `state` is absent, else the one
123
+ * beside `state` (a test's own folder is prepared the first time it is used, against an anchor in this process).
124
+ */
125
+ export declare function secretFolder(state?: string): SecretFolder;
126
+ /** Forget every prepared folder (tests). */
127
+ export declare function forgetSecretFolders(): void;
128
+ /** The keychain service for everything kept for this folder's Toolroll: its folder, hashed. Never a secret. */
129
+ export declare const serviceOf: (folder: SecretFolder) => string;
130
+ /**
131
+ * A path inside `base` (the folder, or Toolroll's own folder above it), each folder on the way checked: a real folder
132
+ * of this user's that nobody else can write, never a link. Made owner-only when `make` (else a missing one ends the
133
+ * walk: nothing is there).
134
+ */
135
+ export declare function pathIn(base: string, parts: readonly string[], options?: {
136
+ make?: boolean;
137
+ }): string;
138
+ /** A file's text, read without following a link; null when there is none. Anything not plainly Toolroll's is refused. */
139
+ export declare function readOwnFile(path: string): string | null;
140
+ /** Write a file whole and owner-only: a new file beside it, then renamed over it, so a link or second name planted there is replaced, never written through. */
141
+ export declare function writeOwnFile(path: string, text: string): void;
142
+ /** A file's bytes overwritten, then the file removed (a link is only removed, never followed). */
143
+ export declare function destroyOwnFile(path: string): void;
144
+ /** One change at a time to what `name` keeps, across Toolroll's processes (a lock file in the folder), re-entrant within one. */
145
+ export declare function withSecretLock<T>(folder: SecretFolder, name: string, work: () => T): T;
146
+ /** The same, for work that waits on the network (renewing a sign-in): other processes wait for it, up to `waitMs`. */
147
+ export declare function withSecretLockAsync<T>(folder: SecretFolder, name: string, work: () => Promise<T>, options?: {
148
+ staleMs?: number;
149
+ waitMs?: number;
150
+ }): Promise<T>;
151
+ /** `text` sealed for `item` with the folder's key. */
152
+ export declare function seal(text: string, item: SecretItem, folder: SecretFolder): string;
153
+ /** What `seal` sealed for `item`; refused when it was sealed for another item, with another key, or changed. */
154
+ export declare function unseal(sealed: string, item: SecretItem, folder: SecretFolder): string;
155
+ /** The sealed text kept at `item`, opened; null when nothing is. */
156
+ export declare function readSealed(backend: SecretBackend, folder: SecretFolder, item: SecretItem): string | null;
157
+ /** Keep `text` at `item`, sealed. */
158
+ export declare function writeSealed(backend: SecretBackend, folder: SecretFolder, item: SecretItem, text: string, options?: {
159
+ create?: boolean;
160
+ }): "ok" | "exists";
161
+ /**
162
+ * A secret Toolroll holds for an integration, by `name` ("linear-key", "google-mail", "flow-hook.12"), for the
163
+ * Toolroll whose folder is `state`. `file` (inside `state`) is where it was kept before, and still is where there's no
164
+ * keychain. The first read or write with a keychain moves the file in.
165
+ */
166
+ export declare function readHeldSecret(state: string, name: string, file: readonly string[]): string | null;
167
+ /** Keep (or, with null, remove) a held secret: see readHeldSecret. */
168
+ export declare function writeHeldSecret(state: string, name: string, file: readonly string[], value: string | null): void;
169
+ /** Whether a held secret has a value, without reading it where that can be helped. */
170
+ export declare function heldSecretSet(state: string, name: string, file: readonly string[]): boolean;