things-api 0.17.0 → 0.19.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 (277) hide show
  1. package/README.md +16 -9
  2. package/deputy/AppIcon.icns +0 -0
  3. package/deputy/VERSION +1 -0
  4. package/deputy/helpers-Info.plist +27 -0
  5. package/deputy/prebuilt/Things API Helper.app/Contents/CodeResources +0 -0
  6. package/deputy/prebuilt/Things API Helper.app/Contents/Helpers/things-reader.app/Contents/Info.plist +22 -0
  7. package/deputy/prebuilt/Things API Helper.app/Contents/Helpers/things-reader.app/Contents/MacOS/things-reader +0 -0
  8. package/deputy/prebuilt/Things API Helper.app/Contents/Helpers/things-reader.app/Contents/Resources/AppIcon.icns +0 -0
  9. package/deputy/prebuilt/Things API Helper.app/Contents/Helpers/things-reader.app/Contents/_CodeSignature/CodeResources +128 -0
  10. package/deputy/prebuilt/Things API Helper.app/Contents/Info.plist +27 -0
  11. package/deputy/prebuilt/Things API Helper.app/Contents/MacOS/things-deputy +0 -0
  12. package/deputy/prebuilt/Things API Helper.app/Contents/Resources/AppIcon.icns +0 -0
  13. package/deputy/prebuilt/Things API Helper.app/Contents/_CodeSignature/CodeResources +137 -0
  14. package/deputy/reader/Info.plist +22 -0
  15. package/deputy/reader/entitlements.plist +45 -0
  16. package/deputy/reader/main.swift +580 -0
  17. package/deputy/src/main.swift +133 -0
  18. package/deputy/src/osascript.swift +102 -0
  19. package/deputy/src/server.swift +373 -0
  20. package/deputy/src/sqlite.swift +121 -0
  21. package/deputy/src/tcc.swift +58 -0
  22. package/dist/audit/schema.d.ts +13 -1
  23. package/dist/audit/schema.js.map +1 -1
  24. package/dist/capability.d.ts +160 -0
  25. package/dist/capability.js +416 -0
  26. package/dist/capability.js.map +1 -0
  27. package/dist/cli/commands/doctor.js +181 -2
  28. package/dist/cli/commands/doctor.js.map +1 -1
  29. package/dist/cli/commands/helpers.d.ts +17 -0
  30. package/dist/cli/commands/helpers.js +275 -0
  31. package/dist/cli/commands/helpers.js.map +1 -0
  32. package/dist/cli/commands/op-result.d.ts +15 -0
  33. package/dist/cli/commands/op-result.js +45 -0
  34. package/dist/cli/commands/op-result.js.map +1 -0
  35. package/dist/cli/commands/reads.js +47 -1
  36. package/dist/cli/commands/reads.js.map +1 -1
  37. package/dist/cli/commands/setup.d.ts +9 -0
  38. package/dist/cli/commands/setup.js +63 -83
  39. package/dist/cli/commands/setup.js.map +1 -1
  40. package/dist/cli/commands/writes.d.ts +1 -1
  41. package/dist/cli/commands/writes.js +262 -109
  42. package/dist/cli/commands/writes.js.map +1 -1
  43. package/dist/cli/dry-run.d.ts +1 -1
  44. package/dist/cli/dry-run.js +1 -1
  45. package/dist/cli/glyphs.d.ts +23 -4
  46. package/dist/cli/glyphs.js +46 -19
  47. package/dist/cli/glyphs.js.map +1 -1
  48. package/dist/cli/help.d.ts +1 -1
  49. package/dist/cli/help.js +53 -27
  50. package/dist/cli/help.js.map +1 -1
  51. package/dist/cli/helpers-check.d.ts +10 -0
  52. package/dist/cli/helpers-check.js +59 -0
  53. package/dist/cli/helpers-check.js.map +1 -0
  54. package/dist/cli/main.js +22 -1
  55. package/dist/cli/main.js.map +1 -1
  56. package/dist/cli/period.d.ts +3 -1
  57. package/dist/cli/period.js +1 -1
  58. package/dist/cli/period.js.map +1 -1
  59. package/dist/cli/read-driver.js +26 -1
  60. package/dist/cli/read-driver.js.map +1 -1
  61. package/dist/cli/render.d.ts +31 -4
  62. package/dist/cli/render.js +127 -15
  63. package/dist/cli/render.js.map +1 -1
  64. package/dist/client.d.ts +22 -2
  65. package/dist/client.js +52 -15
  66. package/dist/client.js.map +1 -1
  67. package/dist/config.d.ts +31 -0
  68. package/dist/config.js +9 -0
  69. package/dist/config.js.map +1 -1
  70. package/dist/contracts.d.ts +6 -2
  71. package/dist/contracts.js +1 -1
  72. package/dist/contracts.js.map +1 -1
  73. package/dist/db/baselines/db-v26.js +8 -4
  74. package/dist/db/baselines/db-v26.js.map +1 -1
  75. package/dist/db/baselines/db-v27.d.ts +42 -0
  76. package/dist/db/baselines/db-v27.js +47 -0
  77. package/dist/db/baselines/db-v27.js.map +1 -0
  78. package/dist/db/baselines/index.js +2 -1
  79. package/dist/db/baselines/index.js.map +1 -1
  80. package/dist/db/locate.d.ts +4 -1
  81. package/dist/db/locate.js +3 -1
  82. package/dist/db/locate.js.map +1 -1
  83. package/dist/db/schema.d.ts +1 -1
  84. package/dist/db/schema.js +9 -0
  85. package/dist/db/schema.js.map +1 -1
  86. package/dist/deputy/bridge-worker.d.ts +1 -0
  87. package/dist/deputy/bridge-worker.js +79 -0
  88. package/dist/deputy/bridge-worker.js.map +1 -0
  89. package/dist/deputy/bridge.d.ts +14 -0
  90. package/dist/deputy/bridge.js +70 -0
  91. package/dist/deputy/bridge.js.map +1 -0
  92. package/dist/deputy/client.d.ts +19 -0
  93. package/dist/deputy/client.js +104 -0
  94. package/dist/deputy/client.js.map +1 -0
  95. package/dist/deputy/db-facade.d.ts +18 -0
  96. package/dist/deputy/db-facade.js +71 -0
  97. package/dist/deputy/db-facade.js.map +1 -0
  98. package/dist/deputy/files.d.ts +1 -0
  99. package/dist/deputy/files.js +16 -0
  100. package/dist/deputy/files.js.map +1 -0
  101. package/dist/deputy/install.d.ts +319 -0
  102. package/dist/deputy/install.js +1239 -0
  103. package/dist/deputy/install.js.map +1 -0
  104. package/dist/deputy/notice.d.ts +6 -0
  105. package/dist/deputy/notice.js +28 -0
  106. package/dist/deputy/notice.js.map +1 -0
  107. package/dist/deputy/notices.d.ts +31 -0
  108. package/dist/deputy/notices.js +94 -0
  109. package/dist/deputy/notices.js.map +1 -0
  110. package/dist/deputy/osa.d.ts +21 -0
  111. package/dist/deputy/osa.js +72 -0
  112. package/dist/deputy/osa.js.map +1 -0
  113. package/dist/deputy/protocol.d.ts +140 -0
  114. package/dist/deputy/protocol.js +143 -0
  115. package/dist/deputy/protocol.js.map +1 -0
  116. package/dist/deputy/routing.d.ts +84 -0
  117. package/dist/deputy/routing.js +422 -0
  118. package/dist/deputy/routing.js.map +1 -0
  119. package/dist/deputy/shortcuts-exec.d.ts +10 -0
  120. package/dist/deputy/shortcuts-exec.js +50 -0
  121. package/dist/deputy/shortcuts-exec.js.map +1 -0
  122. package/dist/diagnose.d.ts +57 -2
  123. package/dist/diagnose.js +105 -3
  124. package/dist/diagnose.js.map +1 -1
  125. package/dist/direct-setup.d.ts +78 -0
  126. package/dist/direct-setup.js +484 -0
  127. package/dist/direct-setup.js.map +1 -0
  128. package/dist/host-access.d.ts +63 -0
  129. package/dist/host-access.js +165 -0
  130. package/dist/host-access.js.map +1 -0
  131. package/dist/index.d.ts +31 -5
  132. package/dist/index.js +23 -1
  133. package/dist/index.js.map +1 -1
  134. package/dist/mcp/server.d.ts +27 -1
  135. package/dist/mcp/server.js +300 -97
  136. package/dist/mcp/server.js.map +1 -1
  137. package/dist/model/mappers.d.ts +12 -3
  138. package/dist/model/mappers.js +6 -1
  139. package/dist/model/mappers.js.map +1 -1
  140. package/dist/model/recurrence.d.ts +5 -1
  141. package/dist/model/recurrence.js +19 -1
  142. package/dist/model/recurrence.js.map +1 -1
  143. package/dist/model/template-projection.d.ts +26 -0
  144. package/dist/model/template-projection.js +113 -0
  145. package/dist/model/template-projection.js.map +1 -0
  146. package/dist/op-result.d.ts +55 -0
  147. package/dist/op-result.js +161 -0
  148. package/dist/op-result.js.map +1 -0
  149. package/dist/read/detail.js +7 -1
  150. package/dist/read/detail.js.map +1 -1
  151. package/dist/read/filter-contract.d.ts +1 -1
  152. package/dist/read/filter-contract.js +4 -0
  153. package/dist/read/filter-contract.js.map +1 -1
  154. package/dist/read/queries.js +8 -1
  155. package/dist/read/queries.js.map +1 -1
  156. package/dist/read/shape.js +4 -0
  157. package/dist/read/shape.js.map +1 -1
  158. package/dist/read/views.d.ts +35 -4
  159. package/dist/read/views.js +120 -18
  160. package/dist/read/views.js.map +1 -1
  161. package/dist/session-grant.d.ts +48 -0
  162. package/dist/session-grant.js +170 -0
  163. package/dist/session-grant.js.map +1 -0
  164. package/dist/surface-copy.d.ts +8 -0
  165. package/dist/surface-copy.js +8 -0
  166. package/dist/surface-copy.js.map +1 -1
  167. package/dist/sync-health.js +6 -2
  168. package/dist/sync-health.js.map +1 -1
  169. package/dist/wizard.d.ts +58 -0
  170. package/dist/wizard.js +167 -0
  171. package/dist/wizard.js.map +1 -0
  172. package/dist/write/accessibility-probe.js +4 -2
  173. package/dist/write/accessibility-probe.js.map +1 -1
  174. package/dist/write/automation-probe.js +5 -1
  175. package/dist/write/automation-probe.js.map +1 -1
  176. package/dist/write/availability.d.ts +1 -1
  177. package/dist/write/availability.js +10 -6
  178. package/dist/write/availability.js.map +1 -1
  179. package/dist/write/batch.d.ts +20 -0
  180. package/dist/write/batch.js +94 -15
  181. package/dist/write/batch.js.map +1 -1
  182. package/dist/write/capabilities.d.ts +9 -0
  183. package/dist/write/capabilities.js +2 -0
  184. package/dist/write/capabilities.js.map +1 -1
  185. package/dist/write/clear-reminder.js +1 -1
  186. package/dist/write/clear-reminder.js.map +1 -1
  187. package/dist/write/commands.d.ts +12 -1
  188. package/dist/write/commands.js +170 -237
  189. package/dist/write/commands.js.map +1 -1
  190. package/dist/write/experimental.d.ts +19 -0
  191. package/dist/write/experimental.js +50 -0
  192. package/dist/write/experimental.js.map +1 -1
  193. package/dist/write/failure-hints.d.ts +3 -1
  194. package/dist/write/failure-hints.js.map +1 -1
  195. package/dist/write/guards.js +19 -2
  196. package/dist/write/guards.js.map +1 -1
  197. package/dist/write/lock.d.ts +16 -13
  198. package/dist/write/lock.js +55 -0
  199. package/dist/write/lock.js.map +1 -1
  200. package/dist/write/make-repeating-project.js +9 -13
  201. package/dist/write/make-repeating-project.js.map +1 -1
  202. package/dist/write/move.js +14 -6
  203. package/dist/write/move.js.map +1 -1
  204. package/dist/write/operations.d.ts +64 -25
  205. package/dist/write/operations.js +7 -0
  206. package/dist/write/operations.js.map +1 -1
  207. package/dist/write/opid.d.ts +14 -0
  208. package/dist/write/opid.js +22 -0
  209. package/dist/write/opid.js.map +1 -1
  210. package/dist/write/param-schema.d.ts +124 -0
  211. package/dist/write/param-schema.js +747 -0
  212. package/dist/write/param-schema.js.map +1 -0
  213. package/dist/write/pipeline.d.ts +78 -2
  214. package/dist/write/pipeline.js +249 -4
  215. package/dist/write/pipeline.js.map +1 -1
  216. package/dist/write/pre-state.d.ts +8 -0
  217. package/dist/write/pre-state.js +62 -17
  218. package/dist/write/pre-state.js.map +1 -1
  219. package/dist/write/promote-clone.js +635 -367
  220. package/dist/write/promote-clone.js.map +1 -1
  221. package/dist/write/reorder.js +95 -29
  222. package/dist/write/reorder.js.map +1 -1
  223. package/dist/write/repeat-anchor.d.ts +30 -0
  224. package/dist/write/repeat-anchor.js +166 -1
  225. package/dist/write/repeat-anchor.js.map +1 -1
  226. package/dist/write/repeat-rule.d.ts +28 -1
  227. package/dist/write/repeat-rule.js +64 -4
  228. package/dist/write/repeat-rule.js.map +1 -1
  229. package/dist/write/resolution-timestamps.d.ts +11 -0
  230. package/dist/write/resolution-timestamps.js +83 -38
  231. package/dist/write/resolution-timestamps.js.map +1 -1
  232. package/dist/write/reversibility.js +4 -0
  233. package/dist/write/reversibility.js.map +1 -1
  234. package/dist/write/template-mutation.d.ts +137 -0
  235. package/dist/write/template-mutation.js +451 -0
  236. package/dist/write/template-mutation.js.map +1 -0
  237. package/dist/write/undo.js +10 -20
  238. package/dist/write/undo.js.map +1 -1
  239. package/dist/write/update-fields.d.ts +151 -0
  240. package/dist/write/update-fields.js +427 -0
  241. package/dist/write/update-fields.js.map +1 -0
  242. package/dist/write/vectors/applescript.js +10 -16
  243. package/dist/write/vectors/applescript.js.map +1 -1
  244. package/dist/write/vectors/registry.d.ts +1 -1
  245. package/dist/write/vectors/registry.js +10 -2
  246. package/dist/write/vectors/registry.js.map +1 -1
  247. package/dist/write/vectors/session-reachability.d.ts +55 -0
  248. package/dist/write/vectors/session-reachability.js +56 -8
  249. package/dist/write/vectors/session-reachability.js.map +1 -1
  250. package/dist/write/vectors/shortcuts.js +7 -16
  251. package/dist/write/vectors/shortcuts.js.map +1 -1
  252. package/dist/write/vectors/simulator.d.ts +16 -1
  253. package/dist/write/vectors/simulator.js +68 -12
  254. package/dist/write/vectors/simulator.js.map +1 -1
  255. package/dist/write/vectors/types.d.ts +124 -1
  256. package/dist/write/vectors/ui-recipes.d.ts +19 -0
  257. package/dist/write/vectors/ui-recipes.js +158 -38
  258. package/dist/write/vectors/ui-recipes.js.map +1 -1
  259. package/dist/write/vectors/ui.d.ts +89 -0
  260. package/dist/write/vectors/ui.js +504 -49
  261. package/dist/write/vectors/ui.js.map +1 -1
  262. package/dist/write/verify/delta.d.ts +21 -0
  263. package/dist/write/verify/delta.js.map +1 -1
  264. package/dist/write/verify/poller.d.ts +13 -0
  265. package/dist/write/verify/poller.js +38 -0
  266. package/dist/write/verify/poller.js.map +1 -1
  267. package/package.json +9 -1
  268. package/schema/envelope.schema.json +5 -3
  269. package/scripts/build-helpers.sh +109 -0
  270. package/scripts/deputy-cert-setup.sh +60 -0
  271. package/skills/things-cli/SKILL.md +12 -5
  272. package/skills/things-cli/references/contracts.md +1 -0
  273. package/skills/things-cli/references/data-model.md +3 -0
  274. package/skills/things-cli/references/errors.md +5 -1
  275. package/skills/things-cli/references/gui.md +1 -0
  276. package/skills/things-cli/references/repeating.md +75 -0
  277. package/skills/things-cli/references/tag-cleanup.md +64 -0
@@ -0,0 +1,484 @@
1
+ /**
2
+ * `things setup` — the DIRECT-path onboarding ceremony
3
+ * (docs/design/permissions-doctrine.md, Article V).
4
+ *
5
+ * One of exactly two places in the package allowed to put a macOS consent
6
+ * dialog on screen (the other is `things helpers setup`). Everywhere else
7
+ * detects capability prompt-free and refuses; here we deliberately raise what
8
+ * has to be raised, while a human is sitting at the machine, and report where
9
+ * each grant landed.
10
+ *
11
+ * The legs, in order:
12
+ *
13
+ * a. READ ACCESS. An explicit two-way choice, because the two answers differ in
14
+ * kind rather than in quality. The DEFAULT — a bare Enter — is the session
15
+ * grant: one deliberate container open, which raises the "would like to
16
+ * access data from other apps" modal, and if the open then succeeds the
17
+ * grant is witnessed (./session-grant.ts). It lasts only while the host app
18
+ * stays open, and the copy says so. Typing `f` takes Full Disk Access
19
+ * instead: durable, but it hands the whole disk to a general-purpose host
20
+ * app, so it is offered, never assumed.
21
+ *
22
+ * MEASURED: FDA does NOT take effect for a running app. macOS says so in
23
+ * the Settings sheet itself — "…will not have full disk access until it is
24
+ * quit", with Later / Quit & Reopen — and the responsible process keeps its
25
+ * old answer for its whole life, so every child it spawns, including a
26
+ * rerun of `things` in the same window, still sees no FDA. There is
27
+ * therefore nothing for this leg to wait for: it deep-links Settings, says
28
+ * what to flip and that the app must relaunch, leaves the leg PENDING, and
29
+ * lets the remaining legs run — Automation and the shortcuts land fine in
30
+ * this session, so the rerun after the relaunch has only this leg left.
31
+ * b. APP CONTROL. When macOS has no Automation record for the host app, the
32
+ * only way to mint one is to send a real Apple Event, which is what raises
33
+ * the dialog. Inside a ceremony that is exactly right. A recorded refusal
34
+ * is NOT re-asked (macOS will not show it again); the copy names both the
35
+ * Settings toggle and the `tccutil` re-arm and leaves the choice to the human.
36
+ * c. SHORTCUTS. The bundled proxies that carry the operations no other surface
37
+ * can perform. An install sheet per missing shortcut; no macOS consent.
38
+ *
39
+ * There is deliberately NO Accessibility leg: GUI-driving is helpers-only
40
+ * (Article IV), so when `ui.enabled` is set this ceremony says so and points at
41
+ * `things helpers setup --gui` rather than raising an AX prompt against the
42
+ * terminal.
43
+ *
44
+ * Every leg is IDEMPOTENT and RESUMABLE: an already-satisfied leg is detected
45
+ * prompt-free and skipped, so a rerun on a settled machine raises nothing and
46
+ * reports all-green. A leg left outstanding exits nonzero naming what remains.
47
+ *
48
+ * Mode-aware (Article V): off a TTY this is STRICT mode — an upfront banner
49
+ * counting the dialogs, bounded waits, and an unanswered leg failing the run.
50
+ * At a TTY the same legs run as a guided WIZARD: each dialog is explained in
51
+ * the words macOS will use before it is raised, and the ceremony waits for the
52
+ * human between legs (./wizard.ts). TTY-ness is the only signal, and it is read
53
+ * inside this ceremony only.
54
+ */
55
+ import { execFileSync } from "node:child_process";
56
+ import { existsSync, openSync, closeSync } from "node:fs";
57
+ import { join } from "node:path";
58
+ import { fileURLToPath } from "node:url";
59
+ import { hostApp, hostDisplayName, readCapability, writeCapability, } from "./capability.js";
60
+ import { loadConfig } from "./config.js";
61
+ import { locateThingsDb } from "./db/locate.js";
62
+ import { clearSessionGrant, witnessSessionGrant } from "./session-grant.js";
63
+ import { createWizard, withDefaultInterrupts } from "./wizard.js";
64
+ import { readShortcutProxies } from "./write/availability.js";
65
+ /** Deep link to the Full Disk Access pane. */
66
+ const FDA_SETTINGS_URL = "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles";
67
+ /** Deep link to the Automation pane. */
68
+ const AUTOMATION_SETTINGS_URL = "x-apple.systempreferences:com.apple.preference.security?Privacy_Automation";
69
+ /** Package root — one level above src/ AND dist/, so both layouts resolve. */
70
+ const SHORTCUTS_DIR = fileURLToPath(new URL("../shortcuts", import.meta.url));
71
+ const AUTOMATION_TIMEOUT_MS = 60_000;
72
+ /** The key that picks Full Disk Access over the session grant at the read leg. */
73
+ const FDA_CHOICE_KEY = "f";
74
+ function openUrlBestEffort(url) {
75
+ try {
76
+ execFileSync("open", [url], { stdio: "ignore", timeout: 10_000 });
77
+ }
78
+ catch {
79
+ // The deep link is a convenience; the written path works without it.
80
+ }
81
+ }
82
+ /**
83
+ * The container open the ceremony performs on purpose. This is the ONE place
84
+ * in the package permitted to do it blind — everywhere else the doctrine's
85
+ * Article I corollary forbids it, because the open is what raises the modal.
86
+ */
87
+ function openContainerDefault() {
88
+ const fd = openSync(locateThingsDb().path, "r");
89
+ closeSync(fd);
90
+ }
91
+ function sendAutomationProbeDefault(timeoutMs) {
92
+ // `count of areas` dispatches a REAL Apple event. Properties like `version`
93
+ // are answered locally from the target's bundle, mint no grant, and still
94
+ // exit 0 — a false positive that has shipped here before (see the helpers'
95
+ // automationLeg). Never weaken this script.
96
+ execFileSync("osascript", ["-e", 'tell application "Things3" to count of areas'], {
97
+ stdio: ["ignore", "ignore", "pipe"],
98
+ timeout: timeoutMs,
99
+ });
100
+ }
101
+ // ── Leg (a): read access ─────────────────────────────────────────────────────
102
+ /**
103
+ * The two ways to read, offered as a choice rather than a ranking. Enter takes
104
+ * the session grant; `f` takes Full Disk Access, which is the wider grant and
105
+ * the one that costs the human a relaunch.
106
+ */
107
+ function readAccessChoice(hostName) {
108
+ return [
109
+ "Next: read access to your Things data — two ways:",
110
+ ` Enter allow this session only: a dialog asks now; access ends when ${hostName} quits`,
111
+ ` f Full Disk Access: durable, but grants ${hostName} broad file access —`,
112
+ ` flip it in System Settings, then ${hostName} must quit and reopen`,
113
+ ];
114
+ }
115
+ /**
116
+ * The `f` branch. Nothing here waits: FDA reaches a process only through a
117
+ * relaunch, so the leg hands over the three steps and goes pending. The
118
+ * remaining legs still run — their grants land in THIS session — so the rerun
119
+ * after the relaunch has only this one left.
120
+ */
121
+ function fdaBranch(base, hostName, deps) {
122
+ const progress = deps.progress ?? (() => { });
123
+ (deps.openUrl ?? openUrlBestEffort)(FDA_SETTINGS_URL);
124
+ progress(`read access: 1. turn on ${hostName} under System Settings ▸ Privacy & Security ▸ Full Disk Access`);
125
+ progress(`read access: 2. click "Quit & Reopen" when macOS offers it, or quit ${hostName} yourself`);
126
+ progress("read access: 3. run `things setup` again in the new window to confirm it");
127
+ progress("read access: the rest of the setup continues now — those grants land in this session");
128
+ return {
129
+ ...base,
130
+ state: "pending",
131
+ alreadySatisfied: false,
132
+ detail: `Full Disk Access takes effect after ${hostName} relaunches — turn it on, quit and ` +
133
+ `reopen ${hostName}, then rerun \`things setup\``,
134
+ };
135
+ }
136
+ /**
137
+ * The default branch: provoke the app-data modal on purpose and record the
138
+ * grant only if the open then actually succeeded. The wait is the modal's own —
139
+ * macOS holds the open until someone answers it, which is the premise of a
140
+ * ceremony.
141
+ */
142
+ function sessionGrantBranch(base, hostName, deps) {
143
+ const progress = deps.progress ?? (() => { });
144
+ progress(`read access: asking now — a dialog asks whether ${hostName} may access data from ` +
145
+ "other apps; click Allow");
146
+ const host = hostApp(deps);
147
+ try {
148
+ (deps.openContainer ?? openContainerDefault)();
149
+ }
150
+ catch (err) {
151
+ clearSessionGrant(deps.env ?? process.env);
152
+ const why = err instanceof Error ? err.message : String(err);
153
+ progress(`read access: still no access — ${why}`);
154
+ return {
155
+ ...base,
156
+ state: "pending",
157
+ alreadySatisfied: false,
158
+ detail: "no read access yet — rerun and answer the dialog, choose Full Disk Access at the " +
159
+ "read step instead, or run `things helpers setup` to let a helper hold the grant",
160
+ };
161
+ }
162
+ const witnessed = witnessSessionGrant(host.bundleId ?? "", deps);
163
+ if (witnessed === null) {
164
+ return {
165
+ ...base,
166
+ state: "pending",
167
+ alreadySatisfied: false,
168
+ detail: "the folder opened, but this process has no host application whose lifetime the " +
169
+ "grant could be tied to — choose Full Disk Access instead, or run `things helpers setup`",
170
+ };
171
+ }
172
+ progress("read access: granted for as long as this app stays open");
173
+ return {
174
+ ...base,
175
+ state: "granted",
176
+ alreadySatisfied: false,
177
+ detail: `${hostName} may read the Things data folder until it quits. Full Disk Access makes ` +
178
+ "it permanent; `things helpers setup` moves it onto a helper that keeps it across restarts",
179
+ };
180
+ }
181
+ function readAccessLeg(capability, choice, deps) {
182
+ const base = { leg: "read-access", label: "read access" };
183
+ const progress = deps.progress ?? (() => { });
184
+ const hostName = hostDisplayName(deps);
185
+ if (capability.mode === "helpers") {
186
+ progress("read access: already served by the helpers");
187
+ return {
188
+ ...base,
189
+ state: "granted",
190
+ alreadySatisfied: true,
191
+ detail: "the helpers' reader holds the read grant",
192
+ };
193
+ }
194
+ if (capability.mode === "direct-fda") {
195
+ progress("read access: already granted (Full Disk Access)");
196
+ return { ...base, state: "granted", alreadySatisfied: true, detail: capability.detail };
197
+ }
198
+ if (capability.mode === "session-grant") {
199
+ progress("read access: already granted for as long as this app stays open");
200
+ return { ...base, state: "granted", alreadySatisfied: true, detail: capability.detail };
201
+ }
202
+ // Nothing on record: the human's choice decides which grant this leg gathers.
203
+ return choice === FDA_CHOICE_KEY
204
+ ? fdaBranch(base, hostName, deps)
205
+ : sessionGrantBranch(base, hostName, deps);
206
+ }
207
+ // ── Leg (b): app control ─────────────────────────────────────────────────────
208
+ function appControlLeg(deps) {
209
+ const base = { leg: "app-control", label: "app control" };
210
+ const progress = deps.progress ?? (() => { });
211
+ const capability = writeCapability(deps);
212
+ const hostName = hostDisplayName(deps);
213
+ if (capability.mode === "deputy") {
214
+ progress("app control: already held by the helpers");
215
+ return {
216
+ ...base,
217
+ state: "granted",
218
+ alreadySatisfied: true,
219
+ detail: "the deputy holds app control for Things",
220
+ };
221
+ }
222
+ if (capability.mode === "direct-granted") {
223
+ progress("app control: already granted");
224
+ return { ...base, state: "granted", alreadySatisfied: true, detail: capability.detail };
225
+ }
226
+ if (capability.mode === "direct-denied") {
227
+ // macOS will not show this dialog again — re-asking is not an option, so
228
+ // the leg reports the two things a human can actually do.
229
+ progress("app control: refused earlier — macOS will not ask again");
230
+ return {
231
+ ...base,
232
+ state: "denied",
233
+ alreadySatisfied: false,
234
+ detail: capability.remediation.join("; "),
235
+ };
236
+ }
237
+ progress("app control: asking now — answer the dialog if one appears");
238
+ try {
239
+ (deps.sendAutomationProbe ?? sendAutomationProbeDefault)(deps.automationTimeoutMs ?? AUTOMATION_TIMEOUT_MS);
240
+ }
241
+ catch (err) {
242
+ const e = err;
243
+ const stderr = typeof e.stderr === "string"
244
+ ? e.stderr
245
+ : Buffer.isBuffer(e.stderr)
246
+ ? e.stderr.toString("utf8")
247
+ : err instanceof Error
248
+ ? err.message
249
+ : String(err);
250
+ if (/-1743/.test(stderr)) {
251
+ progress("app control: refused");
252
+ (deps.openUrl ?? openUrlBestEffort)(AUTOMATION_SETTINGS_URL);
253
+ return {
254
+ ...base,
255
+ state: "denied",
256
+ alreadySatisfied: false,
257
+ detail: `turn on Things3 for ${hostName} under System Settings ▸ Privacy & Security ▸ ` +
258
+ `Automation, or re-arm the request with \`tccutil reset AppleEvents ${hostApp(deps).bundleId ?? "<host app>"}\`, then rerun`,
259
+ };
260
+ }
261
+ if (e.killed === true || /-1712|event timed out/i.test(stderr)) {
262
+ progress("app control: still waiting on the dialog");
263
+ return {
264
+ ...base,
265
+ state: "pending",
266
+ alreadySatisfied: false,
267
+ detail: "the dialog was not answered — answer it and rerun",
268
+ };
269
+ }
270
+ progress(`app control: no grant yet (${stderr.trim().split("\n")[0] ?? "unknown error"})`);
271
+ return {
272
+ ...base,
273
+ state: "pending",
274
+ alreadySatisfied: false,
275
+ detail: stderr.trim().split("\n")[0] ?? "the request did not complete",
276
+ };
277
+ }
278
+ // A zero exit is not believed on its own: re-read what macOS actually records.
279
+ const after = writeCapability(deps);
280
+ if (after.mode === "direct-granted" || after.mode === "deputy") {
281
+ progress("app control: granted");
282
+ return { ...base, state: "granted", alreadySatisfied: false, detail: "granted" };
283
+ }
284
+ progress("app control: the request ran but macOS records no grant yet");
285
+ return {
286
+ ...base,
287
+ state: "pending",
288
+ alreadySatisfied: false,
289
+ detail: `${after.detail} — rerun, or turn Things3 on for ${hostName} under System Settings ▸ Privacy & Security ▸ Automation`,
290
+ };
291
+ }
292
+ // ── Leg (c): shortcuts ───────────────────────────────────────────────────────
293
+ function shortcutsLeg(deps) {
294
+ const base = { leg: "shortcuts", label: "shortcuts" };
295
+ const progress = deps.progress ?? (() => { });
296
+ const state = (deps.shortcutProxies ?? readShortcutProxies)();
297
+ if (state.missing.length === 0) {
298
+ progress("shortcuts: all installed");
299
+ return {
300
+ ...base,
301
+ state: "granted",
302
+ alreadySatisfied: true,
303
+ detail: `${state.present.length} installed`,
304
+ };
305
+ }
306
+ const opened = [];
307
+ const failures = [];
308
+ for (const name of state.missing) {
309
+ const file = join(SHORTCUTS_DIR, `${name}.shortcut`);
310
+ if (!existsSync(file)) {
311
+ failures.push(`${name} (file missing from the package)`);
312
+ continue;
313
+ }
314
+ try {
315
+ (deps.openShortcut ?? ((f) => execFileSync("open", [f], { timeout: 10_000 })))(file);
316
+ opened.push(name);
317
+ }
318
+ catch {
319
+ failures.push(name);
320
+ }
321
+ }
322
+ if (opened.length > 0) {
323
+ progress(`shortcuts: opened ${opened.length} install sheet${opened.length === 1 ? "" : "s"} — ` +
324
+ 'click "Add Shortcut" on each, then "Always Allow" the first time each one runs');
325
+ }
326
+ if (failures.length > 0)
327
+ progress(`shortcuts: could not open ${failures.join(", ")}`);
328
+ return {
329
+ ...base,
330
+ state: "pending",
331
+ alreadySatisfied: false,
332
+ detail: opened.length > 0
333
+ ? `${opened.length} install sheet${opened.length === 1 ? "" : "s"} opened — click “Add Shortcut” on each, then rerun`
334
+ : `could not open: ${failures.join(", ")}`,
335
+ };
336
+ }
337
+ // ── The ceremony ─────────────────────────────────────────────────────────────
338
+ /**
339
+ * What each leg puts on screen, for the upfront banner. Named flatly, in the
340
+ * order the ceremony raises them — one clause each, no parenthetical asides.
341
+ */
342
+ function promptLabel(leg, hostName) {
343
+ switch (leg) {
344
+ case "read-access":
345
+ return `data access for ${hostName}`;
346
+ case "app-control":
347
+ return "app control of Things";
348
+ case "shortcuts":
349
+ return "one install sheet per missing shortcut";
350
+ }
351
+ }
352
+ /** "a", "a and b", "a, b, and c" — the banner reads as a sentence. */
353
+ function listPhrase(items) {
354
+ if (items.length <= 1)
355
+ return items[0] ?? "";
356
+ if (items.length === 2)
357
+ return `${items[0]} and ${items[1]}`;
358
+ return `${items.slice(0, -1).join(", ")}, and ${items.at(-1)}`;
359
+ }
360
+ /**
361
+ * What the human is about to see, in the words macOS will actually use — the
362
+ * wizard prints these one leg ahead of the dialog (Article V, mode-aware). In
363
+ * strict mode they are never printed; the upfront banner's count stands alone.
364
+ * `{host}` is filled with the detected host app's display name. The read leg is
365
+ * absent because it is a CHOICE rather than an announcement — see
366
+ * {@link readAccessChoice}.
367
+ */
368
+ const PROMPT_EXPLAINERS = {
369
+ "app-control": [
370
+ "Next: permission to control the Things app.",
371
+ ' A macOS dialog will appear: "{host}" wants access to control "Things" — click Allow.',
372
+ " Things opens if it was closed; that is expected.",
373
+ ],
374
+ shortcuts: [
375
+ "Next: the bundled shortcuts.",
376
+ ' One Shortcuts install sheet opens per missing shortcut — click "Add Shortcut" on each.',
377
+ ' The first time each one runs, Shortcuts asks once more; choose "Always Allow".',
378
+ ],
379
+ };
380
+ function closingLine(steps, uiEnabled) {
381
+ const denied = steps.filter((s) => s.state === "denied");
382
+ const pending = steps.filter((s) => s.state === "pending");
383
+ const guiHint = uiEnabled
384
+ ? " Some features drive the Things window; that needs the helpers — `things helpers setup --gui`."
385
+ : "";
386
+ if (denied.length > 0) {
387
+ return (`${denied.map((s) => s.label).join(", ")} ${denied.length === 1 ? "was" : "were"} refused — ` +
388
+ `macOS will not ask again, so the remedy above has to be done by hand.${guiHint}`);
389
+ }
390
+ if (pending.length > 0) {
391
+ return `still outstanding: ${pending.map((s) => s.label).join(", ")}. Finish those and rerun \`things setup\` — it resumes exactly here.${guiHint}`;
392
+ }
393
+ return `Everything this machine needs is in place.${guiHint}`;
394
+ }
395
+ /**
396
+ * What the ceremony would do, established entirely prompt-free. This is the
397
+ * idempotence check (Article V): it is what lets a rerun skip settled legs, and
398
+ * it is what `--dry-run` reports. Raises nothing, ever.
399
+ */
400
+ export function surveySetup(deps = {}) {
401
+ const host = hostApp(deps);
402
+ const read = readCapability({}, deps);
403
+ const write = writeCapability(deps);
404
+ const shortcuts = (deps.shortcutProxies ?? readShortcutProxies)();
405
+ const outstanding = [];
406
+ if (read.mode !== "direct-fda" && read.mode !== "session-grant" && read.mode !== "helpers") {
407
+ outstanding.push("read-access");
408
+ }
409
+ // A recorded refusal raises nothing (the dialog is spent), so it is not counted.
410
+ if (write.mode === "direct-unknown")
411
+ outstanding.push("app-control");
412
+ if (shortcuts.missing.length > 0)
413
+ outstanding.push("shortcuts");
414
+ return {
415
+ host: { bundleId: host.bundleId, name: hostDisplayName(deps) },
416
+ read,
417
+ write,
418
+ shortcutsMissing: [...shortcuts.missing],
419
+ outstanding,
420
+ };
421
+ }
422
+ /**
423
+ * Run the direct-path ceremony. Strict mode: the banner counts what is about
424
+ * to appear, waits are bounded, and an unanswered leg leaves the run nonzero.
425
+ *
426
+ * Runs under {@link withDefaultInterrupts} for its whole synchronous span, so
427
+ * a Ctrl-C at a gate — or during a leg's bounded wait — actually stops it
428
+ * (./wizard.ts, "Why a ceremony runs with the DEFAULT signal disposition").
429
+ * Throws {@link CeremonyStopped} when the human stops at a gate.
430
+ */
431
+ export function directSetup(deps = {}) {
432
+ return withDefaultInterrupts(() => runCeremony(deps));
433
+ }
434
+ function runCeremony(deps) {
435
+ const progress = deps.progress ?? ((line) => process.stdout.write(`${line}\n`));
436
+ const withProgress = { ...deps, progress };
437
+ const env = deps.env ?? process.env;
438
+ const host = hostApp(withProgress);
439
+ const hostName = hostDisplayName(withProgress);
440
+ // Survey prompt-free BEFORE raising anything, so whoever started this knows
441
+ // whether they must stay at the screen (Article V).
442
+ const survey = surveySetup(withProgress);
443
+ const readBefore = survey.read;
444
+ const outstanding = survey.outstanding;
445
+ progress(`setting up direct access for ${hostName}${host.bundleId !== null ? ` (${host.bundleId})` : ""}`);
446
+ progress(outstanding.length === 0
447
+ ? "nothing to raise — every permission this machine needs is already on record"
448
+ : `about to raise ${outstanding.length} dialog${outstanding.length === 1 ? "" : "s"} — ` +
449
+ `${listPhrase(outstanding.map((leg) => promptLabel(leg, hostName)))}. ` +
450
+ "Someone must be at the screen.");
451
+ const wizard = deps.wizard ?? createWizard();
452
+ const willRaise = new Set(outstanding);
453
+ /** Explain a leg's dialog and let the human pace it — wizard mode only. */
454
+ const brief = (leg) => {
455
+ if (willRaise.has(leg)) {
456
+ wizard.explain(PROMPT_EXPLAINERS[leg].map((line) => line.replaceAll("{host}", hostName)));
457
+ }
458
+ };
459
+ // The read leg is the one CHOICE in the ceremony: Enter takes the session
460
+ // grant, `f` takes Full Disk Access. Strict mode answers "" without asking,
461
+ // which is the session grant — the only one an absent human can still get.
462
+ const readChoice = willRaise.has("read-access")
463
+ ? wizard.choose(readAccessChoice(hostName), [FDA_CHOICE_KEY])
464
+ : "";
465
+ const readStep = readAccessLeg(readBefore, readChoice, withProgress);
466
+ brief("app-control");
467
+ const appControlStep = appControlLeg(withProgress);
468
+ brief("shortcuts");
469
+ const steps = [readStep, appControlStep, shortcutsLeg(withProgress)];
470
+ const uiEnabled = loadConfig(env).ui.enabled;
471
+ if (uiEnabled) {
472
+ progress("note: GUI-driving is enabled in config, and it is granted only to the helpers — " +
473
+ "run `things helpers setup --gui` to onboard it");
474
+ }
475
+ return {
476
+ host: { bundleId: host.bundleId, name: hostName },
477
+ steps,
478
+ outstanding,
479
+ denied: steps.some((s) => s.state === "denied"),
480
+ pending: steps.some((s) => s.state === "pending"),
481
+ closing: closingLine(steps, uiEnabled),
482
+ };
483
+ }
484
+ //# sourceMappingURL=direct-setup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct-setup.js","sourceRoot":"","sources":["../src/direct-setup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ import { type SessionGrantDeps } from "./session-grant.ts";
2
+ /** The host app that macOS attributes this process's grants to (Article III). */
3
+ export interface HostApp {
4
+ /**
5
+ * The responsible process's bundle identifier when the environment names one
6
+ * (`__CFBundleIdentifier`), else null. This is the TCC *client* identity —
7
+ * the string a grant is recorded against.
8
+ */
9
+ bundleId: string | null;
10
+ /** A display name for copy ("Ghostty", "Terminal"), or "this terminal". */
11
+ name: string;
12
+ }
13
+ /** Seams for the host-identity and file-access probes; tests replace them all. */
14
+ export interface HostAccessDeps extends SessionGrantDeps {
15
+ env?: NodeJS.ProcessEnv;
16
+ /**
17
+ * Attempt the FDA-class read-open. Returns normally when the host holds Full
18
+ * Disk Access; throws a Node fs error (EPERM when it does not) otherwise.
19
+ */
20
+ fdaProbe?: () => void;
21
+ /** Resolve a running app's display name from its bundle id (LaunchServices). */
22
+ lookupAppName?: (bundleId: string) => string | null;
23
+ }
24
+ /**
25
+ * The host app, resolved from the environment alone — no subprocess, so this is
26
+ * safe on the hot path. `__CFBundleIdentifier` is set by macOS when a process
27
+ * descends from an app bundle, which is how a terminal's shell (and everything
28
+ * it spawns) carries its emulator's identity.
29
+ */
30
+ export declare function hostApp(deps?: HostAccessDeps): HostApp;
31
+ /**
32
+ * The host app's display name for COPY. Identical to {@link hostApp}'s name
33
+ * except for an unlisted bundle id, where LaunchServices is asked once per
34
+ * process. Only call this from a path that is about to print.
35
+ */
36
+ export declare function hostDisplayName(deps?: HostAccessDeps): string;
37
+ /** Test seam: forget the one memo this module keeps (the host's display name). */
38
+ export declare function resetHostAccessForTests(): void;
39
+ /** Where the FDA probe reads. Exported so `doctor` and the ceremony can name it. */
40
+ export declare function tccDbPath(env?: NodeJS.ProcessEnv): string;
41
+ export interface FdaVerdict {
42
+ granted: boolean;
43
+ /** The errno when the open failed, for honest reporting of the unexpected. */
44
+ code: string | null;
45
+ }
46
+ /**
47
+ * Does the host app hold Full Disk Access? Prompt-free by construction. An
48
+ * EPERM (or the sandbox's EACCES) is the ordinary "no"; any other errno is
49
+ * reported as itself rather than folded into a false negative.
50
+ */
51
+ export declare function fdaGranted(deps?: HostAccessDeps): FdaVerdict;
52
+ /**
53
+ * `existsSync` for a rendezvous path. It already swallows errno, but it is
54
+ * wrapped anyway so no future refactor can turn a denial into a throw, and so
55
+ * every rendezvous touch reads the same at the call site.
56
+ */
57
+ export declare function rendezvousExists(path: string): boolean;
58
+ /**
59
+ * Read the reader's access token. Returns null instead of throwing when the
60
+ * read fails (ENOENT before the first install; EPERM if something outside our
61
+ * flows re-permissioned the file).
62
+ */
63
+ export declare function readRendezvousToken(path: string): string | null;