things-api 0.17.0 → 0.18.0

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 (172) hide show
  1. package/README.md +1 -1
  2. package/deputy/VERSION +1 -0
  3. package/deputy/helpers-Info.plist +23 -0
  4. package/deputy/prebuilt/Things API Helper.app/Contents/CodeResources +0 -0
  5. package/deputy/prebuilt/Things API Helper.app/Contents/Helpers/things-reader.app/Contents/Info.plist +20 -0
  6. package/deputy/prebuilt/Things API Helper.app/Contents/Helpers/things-reader.app/Contents/MacOS/things-reader +0 -0
  7. package/deputy/prebuilt/Things API Helper.app/Contents/Helpers/things-reader.app/Contents/_CodeSignature/CodeResources +115 -0
  8. package/deputy/prebuilt/Things API Helper.app/Contents/Info.plist +23 -0
  9. package/deputy/prebuilt/Things API Helper.app/Contents/MacOS/things-deputy +0 -0
  10. package/deputy/prebuilt/Things API Helper.app/Contents/_CodeSignature/CodeResources +125 -0
  11. package/deputy/reader/Info.plist +20 -0
  12. package/deputy/reader/entitlements.plist +15 -0
  13. package/deputy/reader/main.swift +491 -0
  14. package/deputy/src/main.swift +133 -0
  15. package/deputy/src/osascript.swift +102 -0
  16. package/deputy/src/server.swift +350 -0
  17. package/deputy/src/sqlite.swift +121 -0
  18. package/dist/cli/commands/doctor.js +55 -2
  19. package/dist/cli/commands/doctor.js.map +1 -1
  20. package/dist/cli/commands/helpers.d.ts +17 -0
  21. package/dist/cli/commands/helpers.js +148 -0
  22. package/dist/cli/commands/helpers.js.map +1 -0
  23. package/dist/cli/commands/op-result.d.ts +15 -0
  24. package/dist/cli/commands/op-result.js +39 -0
  25. package/dist/cli/commands/op-result.js.map +1 -0
  26. package/dist/cli/commands/writes.js +22 -3
  27. package/dist/cli/commands/writes.js.map +1 -1
  28. package/dist/cli/help.js +4 -0
  29. package/dist/cli/help.js.map +1 -1
  30. package/dist/cli/helpers-check.d.ts +10 -0
  31. package/dist/cli/helpers-check.js +59 -0
  32. package/dist/cli/helpers-check.js.map +1 -0
  33. package/dist/cli/main.js +22 -1
  34. package/dist/cli/main.js.map +1 -1
  35. package/dist/client.js +16 -2
  36. package/dist/client.js.map +1 -1
  37. package/dist/config.d.ts +31 -0
  38. package/dist/config.js +9 -0
  39. package/dist/config.js.map +1 -1
  40. package/dist/contracts.d.ts +1 -1
  41. package/dist/contracts.js +1 -1
  42. package/dist/db/baselines/db-v26.js +8 -4
  43. package/dist/db/baselines/db-v26.js.map +1 -1
  44. package/dist/db/baselines/db-v27.d.ts +42 -0
  45. package/dist/db/baselines/db-v27.js +47 -0
  46. package/dist/db/baselines/db-v27.js.map +1 -0
  47. package/dist/db/baselines/index.js +2 -1
  48. package/dist/db/baselines/index.js.map +1 -1
  49. package/dist/db/locate.d.ts +4 -1
  50. package/dist/db/locate.js +3 -1
  51. package/dist/db/locate.js.map +1 -1
  52. package/dist/db/schema.d.ts +1 -1
  53. package/dist/db/schema.js +9 -0
  54. package/dist/db/schema.js.map +1 -1
  55. package/dist/deputy/bridge-worker.d.ts +1 -0
  56. package/dist/deputy/bridge-worker.js +79 -0
  57. package/dist/deputy/bridge-worker.js.map +1 -0
  58. package/dist/deputy/bridge.d.ts +14 -0
  59. package/dist/deputy/bridge.js +70 -0
  60. package/dist/deputy/bridge.js.map +1 -0
  61. package/dist/deputy/client.d.ts +19 -0
  62. package/dist/deputy/client.js +104 -0
  63. package/dist/deputy/client.js.map +1 -0
  64. package/dist/deputy/db-facade.d.ts +18 -0
  65. package/dist/deputy/db-facade.js +71 -0
  66. package/dist/deputy/db-facade.js.map +1 -0
  67. package/dist/deputy/files.d.ts +1 -0
  68. package/dist/deputy/files.js +16 -0
  69. package/dist/deputy/files.js.map +1 -0
  70. package/dist/deputy/install.d.ts +105 -0
  71. package/dist/deputy/install.js +467 -0
  72. package/dist/deputy/install.js.map +1 -0
  73. package/dist/deputy/notice.d.ts +6 -0
  74. package/dist/deputy/notice.js +28 -0
  75. package/dist/deputy/notice.js.map +1 -0
  76. package/dist/deputy/notices.d.ts +31 -0
  77. package/dist/deputy/notices.js +94 -0
  78. package/dist/deputy/notices.js.map +1 -0
  79. package/dist/deputy/osa.d.ts +21 -0
  80. package/dist/deputy/osa.js +72 -0
  81. package/dist/deputy/osa.js.map +1 -0
  82. package/dist/deputy/protocol.d.ts +86 -0
  83. package/dist/deputy/protocol.js +106 -0
  84. package/dist/deputy/protocol.js.map +1 -0
  85. package/dist/deputy/routing.d.ts +63 -0
  86. package/dist/deputy/routing.js +338 -0
  87. package/dist/deputy/routing.js.map +1 -0
  88. package/dist/deputy/shortcuts-exec.d.ts +10 -0
  89. package/dist/deputy/shortcuts-exec.js +50 -0
  90. package/dist/deputy/shortcuts-exec.js.map +1 -0
  91. package/dist/diagnose.d.ts +43 -1
  92. package/dist/diagnose.js +64 -2
  93. package/dist/diagnose.js.map +1 -1
  94. package/dist/index.d.ts +13 -2
  95. package/dist/index.js +10 -1
  96. package/dist/index.js.map +1 -1
  97. package/dist/mcp/server.js +25 -7
  98. package/dist/mcp/server.js.map +1 -1
  99. package/dist/model/mappers.d.ts +12 -3
  100. package/dist/model/mappers.js +6 -1
  101. package/dist/model/mappers.js.map +1 -1
  102. package/dist/model/recurrence.d.ts +5 -1
  103. package/dist/model/recurrence.js +19 -1
  104. package/dist/model/recurrence.js.map +1 -1
  105. package/dist/model/template-projection.d.ts +26 -0
  106. package/dist/model/template-projection.js +113 -0
  107. package/dist/model/template-projection.js.map +1 -0
  108. package/dist/op-result.d.ts +46 -0
  109. package/dist/op-result.js +156 -0
  110. package/dist/op-result.js.map +1 -0
  111. package/dist/read/detail.js +7 -1
  112. package/dist/read/detail.js.map +1 -1
  113. package/dist/read/queries.js +8 -1
  114. package/dist/read/queries.js.map +1 -1
  115. package/dist/read/views.d.ts +6 -4
  116. package/dist/read/views.js +60 -18
  117. package/dist/read/views.js.map +1 -1
  118. package/dist/sync-health.js +6 -2
  119. package/dist/sync-health.js.map +1 -1
  120. package/dist/write/accessibility-probe.js +4 -2
  121. package/dist/write/accessibility-probe.js.map +1 -1
  122. package/dist/write/automation-probe.js +5 -1
  123. package/dist/write/automation-probe.js.map +1 -1
  124. package/dist/write/availability.js +7 -3
  125. package/dist/write/availability.js.map +1 -1
  126. package/dist/write/commands.js +58 -13
  127. package/dist/write/commands.js.map +1 -1
  128. package/dist/write/experimental.d.ts +19 -0
  129. package/dist/write/experimental.js +50 -0
  130. package/dist/write/experimental.js.map +1 -1
  131. package/dist/write/move.js +14 -6
  132. package/dist/write/move.js.map +1 -1
  133. package/dist/write/operations.d.ts +28 -4
  134. package/dist/write/pipeline.d.ts +2 -0
  135. package/dist/write/pipeline.js +59 -2
  136. package/dist/write/pipeline.js.map +1 -1
  137. package/dist/write/pre-state.js +33 -15
  138. package/dist/write/pre-state.js.map +1 -1
  139. package/dist/write/promote-clone.js +187 -19
  140. package/dist/write/promote-clone.js.map +1 -1
  141. package/dist/write/reorder.js +76 -27
  142. package/dist/write/reorder.js.map +1 -1
  143. package/dist/write/repeat-anchor.d.ts +30 -0
  144. package/dist/write/repeat-anchor.js +166 -1
  145. package/dist/write/repeat-anchor.js.map +1 -1
  146. package/dist/write/repeat-rule.js +10 -0
  147. package/dist/write/repeat-rule.js.map +1 -1
  148. package/dist/write/vectors/applescript.js +7 -16
  149. package/dist/write/vectors/applescript.js.map +1 -1
  150. package/dist/write/vectors/session-reachability.d.ts +55 -0
  151. package/dist/write/vectors/session-reachability.js +56 -8
  152. package/dist/write/vectors/session-reachability.js.map +1 -1
  153. package/dist/write/vectors/shortcuts.js +5 -14
  154. package/dist/write/vectors/shortcuts.js.map +1 -1
  155. package/dist/write/vectors/simulator.d.ts +16 -1
  156. package/dist/write/vectors/simulator.js +61 -10
  157. package/dist/write/vectors/simulator.js.map +1 -1
  158. package/dist/write/vectors/types.d.ts +67 -1
  159. package/dist/write/vectors/ui-recipes.js +128 -38
  160. package/dist/write/vectors/ui-recipes.js.map +1 -1
  161. package/dist/write/vectors/ui.d.ts +76 -0
  162. package/dist/write/vectors/ui.js +443 -37
  163. package/dist/write/vectors/ui.js.map +1 -1
  164. package/dist/write/verify/poller.d.ts +13 -0
  165. package/dist/write/verify/poller.js +38 -0
  166. package/dist/write/verify/poller.js.map +1 -1
  167. package/package.json +8 -1
  168. package/scripts/build-helpers.sh +104 -0
  169. package/scripts/deputy-cert-setup.sh +60 -0
  170. package/skills/things-cli/SKILL.md +8 -3
  171. package/skills/things-cli/references/errors.md +4 -0
  172. package/skills/things-cli/references/repeating.md +69 -0
@@ -0,0 +1,467 @@
1
+ /**
2
+ * things-helpers lifecycle: install/uninstall the launchd LaunchAgents for
3
+ * both helper halves, restart them, run the reader's grant ceremony, and
4
+ * report status. launchd owns both processes end-to-end (RunAtLoad +
5
+ * KeepAlive) — there is never a detached or self-daemonized process, and a
6
+ * crashed helper relaunches with its identity (and therefore its macOS
7
+ * permission grants) intact.
8
+ *
9
+ * Both halves ship inside ONE bundle (Things API Helper.app): things-deputy
10
+ * (automation, unsandboxed) is the bundle's main executable and the sandboxed
11
+ * things-reader.app nests under Contents/Helpers with its own bundle identity
12
+ * — that identity (com.pixelcog.things-reader) keys the user's security-scoped
13
+ * bookmark grant and must never change.
14
+ */
15
+ import { execFileSync, spawnSync } from "node:child_process";
16
+ import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
17
+ import { homedir } from "node:os";
18
+ import { dirname, join } from "node:path";
19
+ import { fileURLToPath } from "node:url";
20
+ import { THINGS_GROUP_CONTAINER } from "../db/locate.js";
21
+ import { DeputySyncBridge } from "./bridge.js";
22
+ import { DEPUTY_LAUNCHD_LABEL, HELPERS_BUNDLE_ID, READER_LAUNCHD_LABEL, DEPUTY_PROTOCOL_VERSION, deputyInstalledBinaryPath, deputySocketPath, deputyStateDir, deputyTokenPath, helpersInstallDir, helpersInstalledBundlePath, readerInstalledAppPath, readerSocketPath, readerTokenPath, } from "./protocol.js";
23
+ export function deputyPlistPath() {
24
+ return join(homedir(), "Library/LaunchAgents", `${DEPUTY_LAUNCHD_LABEL}.plist`);
25
+ }
26
+ export function readerPlistPath() {
27
+ return join(homedir(), "Library/LaunchAgents", `${READER_LAUNCHD_LABEL}.plist`);
28
+ }
29
+ /**
30
+ * Where an install looks for the bundle when the caller names no path, in
31
+ * preference order: `deputy/prebuilt` — the signed + notarized bundle the
32
+ * release workflow stages into the published tarball, so an npm install needs
33
+ * neither Xcode nor a certificate — then `deputy/build`, the output of
34
+ * scripts/build-helpers.sh in a source checkout.
35
+ */
36
+ export function helpersBundleCandidates() {
37
+ return [
38
+ fileURLToPath(new URL("../../deputy/prebuilt/Things API Helper.app", import.meta.url)),
39
+ fileURLToPath(new URL("../../deputy/build/Things API Helper.app", import.meta.url)),
40
+ ];
41
+ }
42
+ /**
43
+ * The first candidate bundle that carries a deputy executable; null when none
44
+ * does. Both candidates are READ only — nothing in the `things helpers` path
45
+ * ever writes inside the package directory, so the CLI works from a read-only
46
+ * package root (an npx cache); BUILDING a bundle there is the one operation
47
+ * that needs a writable checkout, and `--bundle <path>` covers a prebuilt one.
48
+ */
49
+ export function helpersDefaultBuildPath() {
50
+ return (helpersBundleCandidates().find((path) => existsSync(join(path, "Contents/MacOS/things-deputy"))) ?? null);
51
+ }
52
+ /**
53
+ * The INSTALLED bundle's version, read prompt-free from its Info.plist
54
+ * (CFBundleShortVersionString, stamped from deputy/VERSION at build time).
55
+ * Null when nothing is installed or the plist is unreadable/unstamped. This is
56
+ * the version a passive upgrade notice compares against
57
+ * {@link EXPECTED_HELPERS_VERSION} without needing a running helper.
58
+ */
59
+ export function installedHelpersVersion(env = process.env) {
60
+ const plist = join(helpersInstalledBundlePath(env), "Contents/Info.plist");
61
+ try {
62
+ const xml = readFileSync(plist, "utf8");
63
+ const match = /<key>CFBundleShortVersionString<\/key>\s*<string>([^<]*)<\/string>/.exec(xml);
64
+ const value = match?.[1]?.trim();
65
+ return value !== undefined && value !== "" ? value : null;
66
+ }
67
+ catch {
68
+ return null;
69
+ }
70
+ }
71
+ function readerLaunchTarget() {
72
+ return `gui/${process.getuid?.() ?? 501}/${READER_LAUNCHD_LABEL}`;
73
+ }
74
+ function readerExecPath(appPath) {
75
+ return join(appPath, "Contents/MacOS/things-reader");
76
+ }
77
+ function renderReaderPlist(appPath) {
78
+ return `<?xml version="1.0" encoding="UTF-8"?>
79
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
80
+ <plist version="1.0">
81
+ <dict>
82
+ <key>Label</key>
83
+ <string>${READER_LAUNCHD_LABEL}</string>
84
+ <key>ProgramArguments</key>
85
+ <array>
86
+ <string>${readerExecPath(appPath)}</string>
87
+ <string>--serve</string>
88
+ </array>
89
+ <key>RunAtLoad</key>
90
+ <true/>
91
+ <key>KeepAlive</key>
92
+ <true/>
93
+ <!-- Background Task Management groups the login item under the helper
94
+ bundle's display name ("Things API Helper") instead of the signing
95
+ certificate's personal name. -->
96
+ <key>AssociatedBundleIdentifiers</key>
97
+ <array>
98
+ <string>${HELPERS_BUNDLE_ID}</string>
99
+ </array>
100
+ </dict>
101
+ </plist>
102
+ `;
103
+ }
104
+ function launchTarget() {
105
+ return `gui/${process.getuid?.() ?? 501}/${DEPUTY_LAUNCHD_LABEL}`;
106
+ }
107
+ function launchctl(args) {
108
+ try {
109
+ // stderr must be captured, never inherited: a routine negative probe
110
+ // ("Could not find service … in domain") is a state we REPORT, not noise
111
+ // the child gets to print over our own output.
112
+ //
113
+ // The timeout must clear the helpers' DRAIN bound: `bootout`/`kickstart -k`
114
+ // block until the old process exits, and a helper with a request in flight
115
+ // takes up to HELPERS_DRAIN_TIMEOUT_MS to finish it before exiting.
116
+ const output = execFileSync("launchctl", args, {
117
+ encoding: "utf8",
118
+ stdio: ["ignore", "pipe", "pipe"],
119
+ timeout: 30_000,
120
+ });
121
+ return { ok: true, output };
122
+ }
123
+ catch (err) {
124
+ const e = err;
125
+ return { ok: false, output: `${e.stdout ?? ""}${e.stderr ?? ""}` || (e.message ?? "failed") };
126
+ }
127
+ }
128
+ function renderPlist(binaryPath, stateDir) {
129
+ return `<?xml version="1.0" encoding="UTF-8"?>
130
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
131
+ <plist version="1.0">
132
+ <dict>
133
+ <key>Label</key>
134
+ <string>${DEPUTY_LAUNCHD_LABEL}</string>
135
+ <key>ProgramArguments</key>
136
+ <array>
137
+ <string>${binaryPath}</string>
138
+ <string>--state-dir</string>
139
+ <string>${stateDir}</string>
140
+ </array>
141
+ <key>RunAtLoad</key>
142
+ <true/>
143
+ <key>KeepAlive</key>
144
+ <true/>
145
+ <!-- Interactive: the deputy fronts GUI accessibility work; keep it out of
146
+ background-QoS throttling so drives stay as fast as direct execution. -->
147
+ <key>ProcessType</key>
148
+ <string>Interactive</string>
149
+ <key>StandardErrorPath</key>
150
+ <string>${stateDir}/deputy.stderr.log</string>
151
+ <!-- Background Task Management groups the login item under the helper
152
+ bundle's display name ("Things API Helper") instead of the signing
153
+ certificate's personal name. -->
154
+ <key>AssociatedBundleIdentifiers</key>
155
+ <array>
156
+ <string>${HELPERS_BUNDLE_ID}</string>
157
+ </array>
158
+ </dict>
159
+ </plist>
160
+ `;
161
+ }
162
+ /** codesign facts about a binary (diagnostic output — may name mechanisms). */
163
+ export function deputySigningInfo(binaryPath) {
164
+ // spawnSync, not execFileSync: codesign prints its details on STDERR while
165
+ // exiting 0, and execFileSync only surfaces stderr on the failure path — the
166
+ // success case must read both streams.
167
+ const res = spawnSync("codesign", ["-dvv", binaryPath], { encoding: "utf8", timeout: 10_000 });
168
+ const out = `${res.stdout ?? ""}${res.stderr ?? ""}`;
169
+ if (res.error !== undefined || out === "")
170
+ return { state: "unknown", authority: null };
171
+ if (/not signed at all/i.test(out))
172
+ return { state: "unsigned", authority: null };
173
+ if (/Signature=adhoc/i.test(out))
174
+ return { state: "adhoc", authority: null };
175
+ const authority = /Authority=(.+)/.exec(out)?.[1]?.trim() ?? null;
176
+ return authority !== null
177
+ ? { state: "signed", authority }
178
+ : { state: "unknown", authority: null };
179
+ }
180
+ /** One handshake against the reader's socket; null when it cannot complete. */
181
+ function readerHelloProbe(env) {
182
+ const socketPath = readerSocketPath(env);
183
+ const tokenPath = readerTokenPath(env);
184
+ if (!existsSync(socketPath) || !existsSync(tokenPath))
185
+ return null;
186
+ const token = readFileSync(tokenPath, "utf8").trim();
187
+ const bridge = new DeputySyncBridge(socketPath);
188
+ try {
189
+ const res = bridge.request({ v: DEPUTY_PROTOCOL_VERSION, token, verb: "hello" }, 2000);
190
+ return res["ok"] === true ? res : null;
191
+ }
192
+ catch {
193
+ return null;
194
+ }
195
+ finally {
196
+ bridge.close();
197
+ }
198
+ }
199
+ /**
200
+ * Install (or reinstall) the helpers: copy the built bundle to its stable
201
+ * path, write both LaunchAgent plists, and (re)bootstrap them under launchd.
202
+ */
203
+ export function installHelpers(options = {}, env = process.env) {
204
+ const source = options.bundlePath ?? helpersDefaultBuildPath();
205
+ if (source === null) {
206
+ throw new Error(`helpers bundle not found — looked for ${helpersBundleCandidates().join(" and ")}. ` +
207
+ `Build it first: bash scripts/build-helpers.sh`);
208
+ }
209
+ if (!existsSync(join(source, "Contents/MacOS/things-deputy"))) {
210
+ throw new Error(`helpers bundle not found at ${source} — build it first: bash scripts/build-helpers.sh`);
211
+ }
212
+ const readerInBuild = existsSync(join(source, "Contents/Helpers/things-reader.app"));
213
+ const installDir = helpersInstallDir(env);
214
+ const bundlePath = helpersInstalledBundlePath(env);
215
+ const stateDir = deputyStateDir(env);
216
+ // Stop both halves before replacing the bundle (ignore "not loaded"), then
217
+ // recreate the install dir from scratch: install owns bin/ WHOLESALE — a
218
+ // fresh copy every time erases any previous layout without migration logic
219
+ // and resets the kernel's per-vnode code-signature cache.
220
+ launchctl(["bootout", launchTarget()]);
221
+ launchctl(["bootout", readerLaunchTarget()]);
222
+ rmSync(installDir, { recursive: true, force: true });
223
+ mkdirSync(installDir, { recursive: true, mode: 0o700 });
224
+ cpSync(source, bundlePath, { recursive: true });
225
+ const plistPath = deputyPlistPath();
226
+ mkdirSync(dirname(plistPath), { recursive: true });
227
+ writeFileSync(plistPath, renderPlist(deputyInstalledBinaryPath(env), stateDir));
228
+ const warnings = [];
229
+ const boot = launchctl(["bootstrap", `gui/${process.getuid?.() ?? 501}`, plistPath]);
230
+ if (!boot.ok) {
231
+ warnings.push(`launchctl bootstrap failed: ${boot.output.trim()}`);
232
+ }
233
+ const signing = deputySigningInfo(deputyInstalledBinaryPath(env));
234
+ if (signing.state !== "signed") {
235
+ warnings.push(`bundle is ${signing.state} — macOS permission grants will NOT survive rebuilds. ` +
236
+ `Mint the persistent certificate once (scripts/deputy-cert-setup.sh), rebuild, reinstall.`);
237
+ }
238
+ let readerGranted = null;
239
+ if (readerInBuild) {
240
+ const readerPlist = readerPlistPath();
241
+ writeFileSync(readerPlist, renderReaderPlist(readerInstalledAppPath(env)));
242
+ const readerBoot = launchctl(["bootstrap", `gui/${process.getuid?.() ?? 501}`, readerPlist]);
243
+ if (!readerBoot.ok) {
244
+ warnings.push(`reader launchctl bootstrap failed: ${readerBoot.output.trim()}`);
245
+ }
246
+ else {
247
+ // Report the ACTUAL grant state instead of a "run it if you have not"
248
+ // hedge — the reader knows, so ask it (bounded: it just booted).
249
+ const deadline = Date.now() + 4000;
250
+ while (Date.now() < deadline) {
251
+ const hello = readerHelloProbe(env);
252
+ if (hello !== null) {
253
+ readerGranted = hello.granted === true;
254
+ break;
255
+ }
256
+ syncSleepMs(250);
257
+ }
258
+ }
259
+ }
260
+ else {
261
+ warnings.push("the bundle was built without things-reader (no Apple-issued signing identity?) — file reads run direct. Build with an Apple-chain identity, reinstall, then run `things helpers grant`.");
262
+ }
263
+ return {
264
+ bundlePath,
265
+ plistPath,
266
+ stateDir,
267
+ signing,
268
+ readerInstalled: readerInBuild,
269
+ readerGranted,
270
+ warnings,
271
+ };
272
+ }
273
+ /** Stop both halves and remove LaunchAgents + the installed bundle (state — tokens, logs, the reader's grant — is kept). */
274
+ export function uninstallHelpers(env = process.env) {
275
+ const removed = [];
276
+ launchctl(["bootout", launchTarget()]);
277
+ launchctl(["bootout", readerLaunchTarget()]);
278
+ for (const path of [deputyPlistPath(), readerPlistPath()]) {
279
+ if (existsSync(path)) {
280
+ rmSync(path);
281
+ removed.push(path);
282
+ }
283
+ }
284
+ const installDir = helpersInstallDir(env);
285
+ if (existsSync(installDir)) {
286
+ rmSync(installDir, { recursive: true });
287
+ removed.push(installDir);
288
+ }
289
+ return { removed };
290
+ }
291
+ /** Restart the launchd-managed helpers (picks up a rebuilt installed bundle). */
292
+ export function restartHelpers() {
293
+ const res = launchctl(["kickstart", "-k", launchTarget()]);
294
+ if (!res.ok) {
295
+ throw new Error(`launchctl kickstart failed (${res.output.trim() || "unknown"}) — are the helpers installed? Run: things helpers install`);
296
+ }
297
+ // Reader restart is best-effort: it may legitimately not be installed.
298
+ launchctl(["kickstart", "-k", readerLaunchTarget()]);
299
+ }
300
+ /**
301
+ * The one-time grant ceremony: open the reader in `--grant` mode (the panel
302
+ * must be presented by the SANDBOXED process — that is what makes the grant
303
+ * durable) and wait for the bookmark to land, confirmed via the reader's
304
+ * handshake. The panel opens INSIDE the Things data folder when it exists, so
305
+ * accepting is the only click. Interactive by design; returns when granted or
306
+ * on timeout, and verifies the database actually resolves inside the granted
307
+ * scope so a wrong-folder grant reports loudly instead of half-working.
308
+ */
309
+ export function grantReader(env = process.env) {
310
+ const appPath = readerInstalledAppPath(env);
311
+ if (!existsSync(appPath)) {
312
+ return {
313
+ granted: false,
314
+ detail: "things-reader is not installed — run `things helpers install` first",
315
+ };
316
+ }
317
+ const thingsContainer = join(homedir(), THINGS_GROUP_CONTAINER);
318
+ const startDir = existsSync(thingsContainer)
319
+ ? thingsContainer
320
+ : join(homedir(), "Library/Group Containers");
321
+ try {
322
+ execFileSync("open", ["-W", appPath, "--args", "--grant", startDir], {
323
+ stdio: "ignore",
324
+ timeout: 300_000,
325
+ });
326
+ }
327
+ catch (err) {
328
+ return {
329
+ granted: false,
330
+ detail: `could not open the grant panel: ${err instanceof Error ? err.message : String(err)}`,
331
+ };
332
+ }
333
+ // The serving reader re-checks its bookmark per request — no restart needed.
334
+ const socketPath = readerSocketPath(env);
335
+ const tokenPath = readerTokenPath(env);
336
+ const deadline = Date.now() + 15_000;
337
+ let detail = "the reader is not running — `things helpers status`";
338
+ while (Date.now() < deadline) {
339
+ if (existsSync(socketPath) && existsSync(tokenPath)) {
340
+ const token = readFileSync(tokenPath, "utf8").trim();
341
+ const bridge = new DeputySyncBridge(socketPath);
342
+ try {
343
+ const res = bridge.request({ v: DEPUTY_PROTOCOL_VERSION, token, verb: "hello" }, 2000);
344
+ if (res["ok"] === true && res.granted === true) {
345
+ const locate = bridge.request({ v: DEPUTY_PROTOCOL_VERSION, token, verb: "locate" }, 5000);
346
+ bridge.close();
347
+ if (locate["ok"] === true)
348
+ return { granted: true, detail: "granted" };
349
+ return {
350
+ granted: false,
351
+ detail: "the grant landed, but the Things database was not found inside the granted folder — rerun `things helpers grant` and grant the Things data folder",
352
+ };
353
+ }
354
+ detail = "the panel closed but no grant landed (canceled?) — rerun `things helpers grant`";
355
+ }
356
+ catch {
357
+ detail = "the reader socket is not answering — `things helpers status`";
358
+ }
359
+ finally {
360
+ bridge.close();
361
+ }
362
+ }
363
+ syncSleepMs(500);
364
+ }
365
+ return { granted: false, detail };
366
+ }
367
+ function syncSleepMs(ms) {
368
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
369
+ }
370
+ /**
371
+ * Prompt-free status for both halves: launchd load state, a live handshake
372
+ * when each socket answers, and the installed bundle's signing facts. Works
373
+ * with routing disabled — inspect first, enable after.
374
+ */
375
+ export function helpersStatus(mode, env = process.env) {
376
+ const binaryPath = deputyInstalledBinaryPath(env);
377
+ const binaryInstalled = existsSync(binaryPath);
378
+ const socketPath = deputySocketPath(env);
379
+ let hello = null;
380
+ let detail = "";
381
+ const socketPresent = existsSync(socketPath) && existsSync(deputyTokenPath(env));
382
+ if (socketPresent) {
383
+ const token = readFileSync(deputyTokenPath(env), "utf8").trim();
384
+ const bridge = new DeputySyncBridge(socketPath);
385
+ try {
386
+ const res = bridge.request({ v: DEPUTY_PROTOCOL_VERSION, token, verb: "hello" }, 2000);
387
+ if (res["ok"] === true) {
388
+ hello = res;
389
+ }
390
+ else {
391
+ detail = `handshake refused: ${JSON.stringify(res["error"])}`;
392
+ }
393
+ }
394
+ catch (err) {
395
+ detail = `socket present but not answering: ${err instanceof Error ? err.message : String(err)}`;
396
+ }
397
+ finally {
398
+ bridge.close();
399
+ }
400
+ }
401
+ else {
402
+ detail = "not running (no socket)";
403
+ }
404
+ return {
405
+ mode,
406
+ bundleInstalled: binaryInstalled,
407
+ installedVersion: installedHelpersVersion(env),
408
+ deputy: {
409
+ plistInstalled: existsSync(deputyPlistPath()),
410
+ loaded: launchctl(["print", launchTarget()]).ok,
411
+ running: hello !== null,
412
+ socketPath,
413
+ hungSocket: socketPresent && hello === null,
414
+ hello,
415
+ signing: binaryInstalled ? deputySigningInfo(binaryPath) : null,
416
+ detail: hello !== null ? "running" : detail,
417
+ },
418
+ reader: readerStatus(env),
419
+ };
420
+ }
421
+ function readerStatus(env) {
422
+ const appPath = readerInstalledAppPath(env);
423
+ const installed = existsSync(appPath);
424
+ const loaded = launchctl(["print", readerLaunchTarget()]).ok;
425
+ const socketPath = readerSocketPath(env);
426
+ const tokenPath = readerTokenPath(env);
427
+ let running = false;
428
+ let granted = false;
429
+ let hello = null;
430
+ let detail = "not running (no socket)";
431
+ const socketPresent = existsSync(socketPath) && existsSync(tokenPath);
432
+ if (socketPresent) {
433
+ const token = readFileSync(tokenPath, "utf8").trim();
434
+ const bridge = new DeputySyncBridge(socketPath);
435
+ try {
436
+ const res = bridge.request({ v: DEPUTY_PROTOCOL_VERSION, token, verb: "hello" }, 2000);
437
+ if (res["ok"] === true) {
438
+ running = true;
439
+ hello = res;
440
+ granted = res.granted === true;
441
+ detail = granted ? "running, granted" : "running, NOT granted (things helpers grant)";
442
+ }
443
+ else {
444
+ detail = `handshake refused: ${JSON.stringify(res["error"])}`;
445
+ }
446
+ }
447
+ catch (err) {
448
+ detail = `socket present but not answering: ${err instanceof Error ? err.message : String(err)}`;
449
+ }
450
+ finally {
451
+ bridge.close();
452
+ }
453
+ }
454
+ return {
455
+ installed,
456
+ plistInstalled: existsSync(readerPlistPath()),
457
+ loaded,
458
+ running,
459
+ granted,
460
+ socketPath,
461
+ hungSocket: socketPresent && !running,
462
+ hello,
463
+ signing: installed ? deputySigningInfo(readerExecPath(appPath)) : null,
464
+ detail,
465
+ };
466
+ }
467
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/deputy/install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /** Emit one helpers notice on stderr; later calls this process are dropped. */
2
+ export declare function emitHelpersNotice(message: string, write?: (s: string) => void): void;
3
+ /** True once this process has spent its one notice. */
4
+ export declare function helpersNoticeSpent(): boolean;
5
+ /** Test seam: forget that a notice was emitted. */
6
+ export declare function resetHelpersNoticeForTests(): void;
@@ -0,0 +1,28 @@
1
+ /**
2
+ * The single helpers stderr channel: AT MOST ONE line per process, whichever
3
+ * condition speaks first.
4
+ *
5
+ * Two producers share it — the routing layer (degradation caught at
6
+ * activation, src/deputy/routing.ts) and the CLI's passive install/upgrade
7
+ * check (src/cli/helpers-check.ts). One process can hit both (an installed but
8
+ * stale helper that also fails to answer), and two stacked lines about the same
9
+ * broken helper are noise, not information: the first one already names a
10
+ * remedy that resolves the state.
11
+ */
12
+ let noticed = false;
13
+ /** Emit one helpers notice on stderr; later calls this process are dropped. */
14
+ export function emitHelpersNotice(message, write = (s) => void process.stderr.write(s)) {
15
+ if (noticed)
16
+ return;
17
+ noticed = true;
18
+ write(`things-api helpers: ${message}\n`);
19
+ }
20
+ /** True once this process has spent its one notice. */
21
+ export function helpersNoticeSpent() {
22
+ return noticed;
23
+ }
24
+ /** Test seam: forget that a notice was emitted. */
25
+ export function resetHelpersNoticeForTests() {
26
+ noticed = false;
27
+ }
28
+ //# sourceMappingURL=notice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notice.js","sourceRoot":"","sources":["../../src/deputy/notice.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,IAAI,OAAO,GAAG,KAAK,CAAC;AAEpB,+EAA+E;AAC/E,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,QAA6B,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IAEhE,IAAI,OAAO;QAAE,OAAO;IACpB,OAAO,GAAG,IAAI,CAAC;IACf,KAAK,CAAC,uBAAuB,OAAO,IAAI,CAAC,CAAC;AAC5C,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,kBAAkB;IAChC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,0BAA0B;IACxC,OAAO,GAAG,KAAK,CAAC;AAClB,CAAC"}
@@ -0,0 +1,31 @@
1
+ /** How long the absence hint stays quiet after being shown once. */
2
+ export declare const HELPERS_HINT_INTERVAL_DAYS = 14;
3
+ export type HelpersNoticeKind = "version-skew" | "absent-hint";
4
+ export interface HelpersNotice {
5
+ kind: HelpersNoticeKind;
6
+ /** The one line to print (no prefix — the notice sink adds it). */
7
+ text: string;
8
+ }
9
+ export interface HelpersNoticeOptions {
10
+ env?: NodeJS.ProcessEnv;
11
+ /** Wall clock (ms) for the hint throttle; defaults to now. */
12
+ now?: number;
13
+ /** Host platform; the helpers are macOS-only, so nothing fires elsewhere. */
14
+ platform?: string;
15
+ /**
16
+ * Test seam. Defaults to the real provenance: true when `helpers-enabled` is
17
+ * neither stored nor forced by the environment (nobody has ever answered the
18
+ * routing question on this host).
19
+ */
20
+ modeUntouched?: boolean;
21
+ }
22
+ /** When the absence hint was last shown (ms), or null when never/unreadable. */
23
+ export declare function lastHelpersHintAt(env?: NodeJS.ProcessEnv): number | null;
24
+ /** Record that the absence hint was shown, restarting its throttle window. */
25
+ export declare function markHelpersHintShown(env?: NodeJS.ProcessEnv, now?: number): void;
26
+ /**
27
+ * The notice this machine has earned, or null when it has nothing to say.
28
+ * Skew outranks the hint (they are mutually exclusive anyway: one needs an
29
+ * installed bundle, the other its absence).
30
+ */
31
+ export declare function computeHelpersNotice(options?: HelpersNoticeOptions): HelpersNotice | null;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * The PASSIVE helpers notices — what a human sees on a command they were
3
+ * running anyway, without asking about the helpers at all (the skill-drift
4
+ * precedent, src/cli/skill-check.ts).
5
+ *
6
+ * Two conditions, both computed from disk with no handshake and no prompt:
7
+ *
8
+ * - `version-skew`: routing is on (`auto`/`true`), a bundle IS installed, and
9
+ * its version differs from the one this package expects. The remedy is a
10
+ * rebuild + reinstall — the installed bundle is a COPY, so restarting it
11
+ * would only restart the stale code.
12
+ * - `absent-hint`: nothing is installed, the routing mode has never been set,
13
+ * and the hint has not been shown for {@link HELPERS_HINT_INTERVAL_DAYS}
14
+ * days. This one is a suggestion, not a fault, so it is throttled by a stamp
15
+ * in the state dir and suppressible like the rest.
16
+ *
17
+ * Emission (gating, kill switch, the one-line-per-process budget) belongs to
18
+ * the caller — src/cli/helpers-check.ts. These functions only decide.
19
+ */
20
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
21
+ import { join } from "node:path";
22
+ import { getConfigKey, loadConfig } from "../config.js";
23
+ import { stateDir } from "../paths.js";
24
+ import { installedHelpersVersion } from "./install.js";
25
+ import { EXPECTED_HELPERS_VERSION, helpersInstalledBundlePath } from "./protocol.js";
26
+ /** How long the absence hint stays quiet after being shown once. */
27
+ export const HELPERS_HINT_INTERVAL_DAYS = 14;
28
+ function hintStampPath(env) {
29
+ return join(stateDir(env), "helpers-hint.json");
30
+ }
31
+ /** When the absence hint was last shown (ms), or null when never/unreadable. */
32
+ export function lastHelpersHintAt(env = process.env) {
33
+ try {
34
+ const raw = JSON.parse(readFileSync(hintStampPath(env), "utf8"));
35
+ const parsed = typeof raw.shownAt === "string" ? Date.parse(raw.shownAt) : NaN;
36
+ return Number.isNaN(parsed) ? null : parsed;
37
+ }
38
+ catch {
39
+ return null;
40
+ }
41
+ }
42
+ /** Record that the absence hint was shown, restarting its throttle window. */
43
+ export function markHelpersHintShown(env = process.env, now = Date.now()) {
44
+ try {
45
+ mkdirSync(stateDir(env), { recursive: true });
46
+ writeFileSync(hintStampPath(env), `${JSON.stringify({ shownAt: new Date(now).toISOString() }, null, 2)}\n`);
47
+ }
48
+ catch {
49
+ // A hint that cannot remember itself is still better than a broken command.
50
+ }
51
+ }
52
+ /**
53
+ * The notice this machine has earned, or null when it has nothing to say.
54
+ * Skew outranks the hint (they are mutually exclusive anyway: one needs an
55
+ * installed bundle, the other its absence).
56
+ */
57
+ export function computeHelpersNotice(options = {}) {
58
+ const env = options.env ?? process.env;
59
+ const platform = options.platform ?? process.platform;
60
+ if (platform !== "darwin")
61
+ return null;
62
+ const mode = loadConfig(env).helpersMode;
63
+ if (mode === "false")
64
+ return null;
65
+ const installed = existsSync(helpersInstalledBundlePath(env));
66
+ if (installed) {
67
+ const version = installedHelpersVersion(env);
68
+ if (version === null || version === EXPECTED_HELPERS_VERSION)
69
+ return null;
70
+ return {
71
+ kind: "version-skew",
72
+ text: `helpers v${version} installed, this package expects v${EXPECTED_HELPERS_VERSION} — ` +
73
+ "rebuild with `bash scripts/build-helpers.sh` and rerun `things helpers install` " +
74
+ "(THINGS_API_NO_HELPERS_CHECK=1 silences this)",
75
+ };
76
+ }
77
+ // Nothing installed: a suggestion, and only for a host that has never
78
+ // expressed an opinion — an explicit `auto`/`true` owner is mid-setup, not
79
+ // in need of an introduction.
80
+ const untouched = options.modeUntouched ?? getConfigKey("helpers-enabled", env)?.source === "default";
81
+ if (!untouched)
82
+ return null;
83
+ const last = lastHelpersHintAt(env);
84
+ const now = options.now ?? Date.now();
85
+ if (last !== null && now - last < HELPERS_HINT_INTERVAL_DAYS * 86_400_000)
86
+ return null;
87
+ return {
88
+ kind: "absent-hint",
89
+ text: "database reads and app automation run in THIS process, so macOS permission grants " +
90
+ "follow whichever terminal or agent runtime started it — `things helpers install` moves " +
91
+ "them onto two stable helpers (THINGS_API_NO_HELPERS_CHECK=1 silences this)",
92
+ };
93
+ }
94
+ //# sourceMappingURL=notices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notices.js","sourceRoot":"","sources":["../../src/deputy/notices.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,YAAY,EAAoB,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,wBAAwB,EAAE,0BAA0B,EAAE,MAAM,eAAe,CAAC;AAErF,oEAAoE;AACpE,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,CAAC;AAwB7C,SAAS,aAAa,CAAC,GAAsB;IAC3C,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,mBAAmB,CAAC,CAAC;AAClD,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,iBAAiB,CAAC,MAAyB,OAAO,CAAC,GAAG;IACpE,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,aAAa,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC,CAA0B,CAAC;QAC1F,MAAM,MAAM,GAAG,OAAO,GAAG,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAC/E,OAAO,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,oBAAoB,CAClC,MAAyB,OAAO,CAAC,GAAG,EACpC,MAAc,IAAI,CAAC,GAAG,EAAE;IAExB,IAAI,CAAC;QACH,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,aAAa,CACX,aAAa,CAAC,GAAG,CAAC,EAClB,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CACzE,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,4EAA4E;IAC9E,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,UAAgC,EAAE;IACrE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAC;IACtD,IAAI,QAAQ,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IACvC,MAAM,IAAI,GAAgB,UAAU,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC;IACtD,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,IAAI,CAAC;IAElC,MAAM,SAAS,GAAG,UAAU,CAAC,0BAA0B,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9D,IAAI,SAAS,EAAE,CAAC;QACd,MAAM,OAAO,GAAG,uBAAuB,CAAC,GAAG,CAAC,CAAC;QAC7C,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,KAAK,wBAAwB;YAAE,OAAO,IAAI,CAAC;QAC1E,OAAO;YACL,IAAI,EAAE,cAAc;YACpB,IAAI,EACF,YAAY,OAAO,qCAAqC,wBAAwB,KAAK;gBACrF,kFAAkF;gBAClF,+CAA+C;SAClD,CAAC;IACJ,CAAC;IAED,sEAAsE;IACtE,2EAA2E;IAC3E,8BAA8B;IAC9B,MAAM,SAAS,GACb,OAAO,CAAC,aAAa,IAAI,YAAY,CAAC,iBAAiB,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,SAAS,CAAC;IACtF,IAAI,CAAC,SAAS;QAAE,OAAO,IAAI,CAAC;IAC5B,MAAM,IAAI,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IACtC,IAAI,IAAI,KAAK,IAAI,IAAI,GAAG,GAAG,IAAI,GAAG,0BAA0B,GAAG,UAAU;QAAE,OAAO,IAAI,CAAC;IACvF,OAAO;QACL,IAAI,EAAE,aAAa;QACnB,IAAI,EACF,oFAAoF;YACpF,yFAAyF;YACzF,4EAA4E;KAC/E,CAAC;AACJ,CAAC"}