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
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  A typed TypeScript library + CLI (`things`) for programmatic interaction with [Things 3](https://culturedcode.com/things/) by Cultured Code.
4
4
 
5
- **Status: read + write + MCP layers live and published to npm (v0.17.0 — see [CHANGELOG.md](CHANGELOG.md)).** Reads go straight to the local SQLite database (UI-exact Today ordering, sidebar-grouped Anytime/Someday with container-status cascade, decoded repeat rules, occurrence projections); writes run a verified pipeline over four write vectors — two lab-validated headless surfaces (the URL scheme + AppleScript) and two opt-in surfaces (Apple Shortcuts and an Accessibility-driven GUI vector) — with hazard guards, disruption-tier policy, a JSONL audit trail, batch mode, audit-replay undo (transactional across compound operations), full project lifecycle (complete/cancel/reopen/restore), heading rename/archive/unarchive with children policies, container detach, granular stateful checklists, tag hierarchy management incl. un-nesting, completion/creation backdating, Logbook imports, tiered fuzzy name resolution (uuid prefixes, `things:///show?id=` share links), and kind-neutral in-place reordering within any container or view (one `things reorder <refs…> [--start|--end|--before|--after] --in <target>` verb — Today/Evening, a project, an area, a heading's children, someday, inbox — plus `project move-heading` for the headings themselves and `area reorder` for the sidebar). The Apple Shortcuts surface is wired for the two headless capabilities nothing else can do: creating a heading in an existing project (`things project add-heading`) and clearing a reminder from a date-scheduled item (`things todo clear-reminder`). Both run through bundled proxy shortcuts (`things setup shortcuts`) and are gated on their presence. The fourth vector — the Accessibility-driven GUI vector — is off by default and drives the local Things app to reach transforms that exist on no scriptable surface (repeat-rule editing on existing to-dos and projects, convert-to-project, sidebar area reorder); see [Accessibility GUI vector](#accessibility-gui-vector-optional-off-by-default) below. Single-item permanent delete stays interactive-only (its macOS consent has no always-allow) and is out of the headless pipeline. See [docs/design/](docs/design/) for the architecture and VM-lab design, [docs/lab/](docs/lab/harness.md) for the probe harness and campaign results the write layer is grounded in, and [docs/atlas/](docs/atlas/schema-v26.md) for the database↔UI map.
5
+ **Status: read + write + MCP layers live and published to npm (v0.19.0 — see [CHANGELOG.md](CHANGELOG.md)).** Reads go straight to the local SQLite database (UI-exact Today ordering, sidebar-grouped Anytime/Someday with container-status cascade, decoded repeat rules, occurrence projections); writes run a verified pipeline over four write vectors — two lab-validated headless surfaces (the URL scheme + AppleScript) and two opt-in surfaces (Apple Shortcuts and an Accessibility-driven GUI vector) — with hazard guards, disruption-tier policy, a JSONL audit trail, batch mode, audit-replay undo (transactional across compound operations), full project lifecycle (complete/cancel/reopen/restore), heading rename/archive/unarchive with children policies, container detach, granular stateful checklists, tag hierarchy management incl. un-nesting, completion/creation backdating, Logbook imports, tiered fuzzy name resolution (uuid prefixes, `things:///show?id=` share links), and kind-neutral in-place reordering within any container or view (one `things reorder <refs…> [--start|--end|--before|--after] --in <target>` verb — Today/Evening, a project, an area, a heading's children, someday, inbox — plus `project move-heading` for the headings themselves and `area reorder` for the sidebar). The Apple Shortcuts surface is wired for the two headless capabilities nothing else can do: creating a heading in an existing project (`things project add-heading`) and clearing a reminder from a date-scheduled item (`things todo clear-reminder`). Both run through bundled proxy shortcuts (`things setup`) and are gated on their presence. The fourth vector — the Accessibility-driven GUI vector — is off by default and drives the local Things app to reach transforms that exist on no scriptable surface (repeat-rule editing on existing to-dos and projects, convert-to-project, sidebar area reorder); see [Accessibility GUI vector](#accessibility-gui-vector-optional-off-by-default) below. Single-item permanent delete stays interactive-only (its macOS consent has no always-allow) and is out of the headless pipeline. See [docs/design/](docs/design/) for the architecture and VM-lab design, [docs/lab/](docs/lab/harness.md) for the probe harness and campaign results the write layer is grounded in, and [docs/atlas/](docs/atlas/schema-v26.md) for the database↔UI map.
6
6
 
7
7
  ```sh
8
8
  things today --json # read: your Today list, Evening split, UI order
@@ -24,19 +24,26 @@ Most ways to script Things fire a URL or an AppleScript command and hope. This p
24
24
 
25
25
  ## Requirements & first-run setup
26
26
 
27
- Things 3 installed and launched once, Node ≥ 24, and a handful of one-time macOS consents / Things settings depending on what you use (file-access consent for reads; "Enable Things URLs" + Automation consents for writes; an Accessibility grant for the optional GUI vector). **See [docs/setup.md](docs/setup.md)** — including the dedicated-automation-Mac checklist. `things doctor` validates your setup and prints remediation for anything missing.
27
+ Things 3 installed and launched once, Node ≥ 24, and a handful of one-time macOS consents / Things settings depending on what you use. **See [docs/setup.md](docs/setup.md)** — including the dedicated-automation-Mac checklist.
28
28
 
29
- ### Shortcuts setup (optional)
30
-
31
- A few operations exist on no other app surface: creating a heading in an **existing** project, clearing a reminder from a date-scheduled item, and permanently deleting a single item. These run through six bundled Apple Shortcuts (signed `.shortcut` files shipped with the package). Install them with:
29
+ Run **one** of the two setup ceremonies and you are done:
32
30
 
33
31
  ```sh
34
- things setup shortcuts # opens an install sheet per missing shortcut — click "Add Shortcut"
32
+ things setup # grants attach to this terminal (or agent harness)
33
+ things helpers setup # grants attach to a signed helper pair instead
35
34
  ```
36
35
 
37
- On each shortcut's first run macOS asks for permission choose **Always Allow** so later runs are unattended (the two delete shortcuts re-ask on every run by design; Apple offers no always-allow for deletion). `things setup shortcuts --check` and `things doctor` report installation state.
36
+ Both settle everything in one sitting read access to the Things data folder, permission to control the Things app, and the bundled shortcuts skipping anything already granted, resuming exactly where they left off, and exiting nonzero while anything is outstanding. `things setup` is the quick path; `things helpers setup` is the durable one, because the grants stop being re-requested every time your terminal updates. Which one you have is reported by `things doctor` and summarized in `things --help`.
37
+
38
+ Outside those two commands **nothing in this package will ever put a macOS permission dialog on your screen**: every entry point works out what it is allowed to do using checks that cannot prompt, and refuses with the exact remediation instead. That is a hard contract, described in [docs/design/permissions-doctrine.md](docs/design/permissions-doctrine.md) — a dialog raised anywhere else is a bug. Handing an explicit `--db <path>` (a Desktop copy, a backup) opts out of all of it: plain file semantics, ordinary errors.
39
+
40
+ ### The bundled Shortcuts
41
+
42
+ A few operations exist on no other app surface: creating a heading in an **existing** project, clearing a reminder from a date-scheduled item, and permanently deleting a single item. These run through six bundled Apple Shortcuts (signed `.shortcut` files shipped with the package), installed as one leg of `things setup` — it opens an install sheet per missing shortcut; click "Add Shortcut" on each.
43
+
44
+ On each shortcut's first run macOS asks for permission — choose **Always Allow** so later runs are unattended (the two delete shortcuts re-ask on every run by design; Apple offers no always-allow for deletion). `things setup --dry-run` and `things doctor` report installation state without asking for anything.
38
45
 
39
- Once installed, these Shortcuts-only operations become available as ordinary commands: `things project add-heading <project> <title>` (create a heading in an existing project) and `things todo clear-reminder <uuid>` (clear a date-scheduled to-do's reminder while keeping its date). Both are also exposed over MCP (the `heading` tool's add-heading action, and `clear_reminder`). If a required shortcut is missing, the command is blocked up front with a pointer back to `things setup shortcuts` — nothing is dispatched.
46
+ Once installed, these Shortcuts-only operations become available as ordinary commands: `things project add-heading <project> <title>` (create a heading in an existing project) and `things todo clear-reminder <uuid>` (clear a date-scheduled to-do's reminder while keeping its date). Both are also exposed over MCP (the `heading` tool's add-heading action, and `clear_reminder`). If a required shortcut is missing, the command is blocked up front with a pointer back to `things setup` — nothing is dispatched.
40
47
 
41
48
  ### Accessibility GUI vector (optional, off by default)
42
49
 
@@ -141,6 +148,6 @@ The catalog is consolidated around a few verb-parameterized tools (a discriminat
141
148
  - **Create**: `add_area`, `add_tag`.
142
149
  - **Headings & reminders** (Shortcuts-backed where headless-impossible): `heading` (`action` create / rename / archive / unarchive / convert_to_project), `clear_reminder`.
143
150
  - **Recurrence via the Accessibility GUI ("ui") vector** (two-key gated — `ui-enabled` config + `dangerously_drive_gui` per call): `repeat` (`scope` todo / project; `action` start / reschedule / pause / resume / create). The `heading` convert_to_project action and the `reorder` areas scope ride the same gated GUI surface.
144
- - **Generic & discovery**: `run_operation` (the full 56-op catalog), `batch`, `reorder` (item ordering across scopes, plus `scope=areas` for the sidebar area order), `undo`, `capabilities`, `doctor`.
151
+ - **Generic & discovery**: `run_operation` (the full 57-op catalog), `batch`, `reorder` (item ordering across scopes, plus `scope=areas` for the sidebar area order), `undo`, `capabilities`, `doctor`.
145
152
 
146
153
  Every write tool takes `dry_run`; the GUI-driven variants additionally require `dangerously_drive_gui`; tools carry read-only/destructive annotations; hazard blocks come back as structured tool errors carrying the same remediation text the CLI prints. Tool descriptions follow the consumer-voice contract in [docs/design/surface-copy.md](docs/design/surface-copy.md).
Binary file
package/deputy/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.3.0
@@ -0,0 +1,27 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <!-- The outer helpers bundle: things-deputy (automation, unsandboxed) is the
6
+ main executable; the sandboxed things-reader.app nests under
7
+ Contents/Helpers with its own identity + entitlements. TCC keys the
8
+ deputy by THIS bundle identifier, so it must stay stable across
9
+ releases. LSUIElement keeps it out of the Dock. -->
10
+ <key>CFBundleIdentifier</key>
11
+ <string>com.pixelcog.things-api-helper</string>
12
+ <key>CFBundleName</key>
13
+ <string>Things API Helper</string>
14
+ <key>CFBundleExecutable</key>
15
+ <string>things-deputy</string>
16
+ <key>CFBundlePackageType</key>
17
+ <string>APPL</string>
18
+ <key>CFBundleShortVersionString</key>
19
+ <string>0.0.0</string>
20
+ <!-- Original artwork, drawn by scripts/generate-helper-icon.jxa — the icon
21
+ System Settings shows next to the Automation/Accessibility toggles. -->
22
+ <key>CFBundleIconFile</key>
23
+ <string>AppIcon</string>
24
+ <key>LSUIElement</key>
25
+ <true/>
26
+ </dict>
27
+ </plist>
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <!-- A real bundle is mandatory: secinit refuses to sandbox a bare
6
+ executable (SANDBOX1). LSUIElement keeps it out of the Dock. -->
7
+ <key>CFBundleIdentifier</key>
8
+ <string>com.pixelcog.things-reader</string>
9
+ <key>CFBundleName</key>
10
+ <string>things-reader</string>
11
+ <key>CFBundleExecutable</key>
12
+ <string>things-reader</string>
13
+ <key>CFBundlePackageType</key>
14
+ <string>APPL</string>
15
+ <key>CFBundleIconFile</key>
16
+ <string>AppIcon</string>
17
+ <key>CFBundleShortVersionString</key>
18
+ <string>1.3.0</string>
19
+ <key>LSUIElement</key>
20
+ <true/>
21
+ </dict>
22
+ </plist>
@@ -0,0 +1,128 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>files</key>
6
+ <dict>
7
+ <key>Resources/AppIcon.icns</key>
8
+ <data>
9
+ 9VX5ZsSdgBEnhGRQvzKyEjHvzeM=
10
+ </data>
11
+ </dict>
12
+ <key>files2</key>
13
+ <dict>
14
+ <key>Resources/AppIcon.icns</key>
15
+ <dict>
16
+ <key>hash2</key>
17
+ <data>
18
+ li4eVDJT2l1+UncvB0nWNrYjSQliN87HTz3w1j2kG3A=
19
+ </data>
20
+ </dict>
21
+ </dict>
22
+ <key>rules</key>
23
+ <dict>
24
+ <key>^Resources/</key>
25
+ <true/>
26
+ <key>^Resources/.*\.lproj/</key>
27
+ <dict>
28
+ <key>optional</key>
29
+ <true/>
30
+ <key>weight</key>
31
+ <real>1000</real>
32
+ </dict>
33
+ <key>^Resources/.*\.lproj/locversion.plist$</key>
34
+ <dict>
35
+ <key>omit</key>
36
+ <true/>
37
+ <key>weight</key>
38
+ <real>1100</real>
39
+ </dict>
40
+ <key>^Resources/Base\.lproj/</key>
41
+ <dict>
42
+ <key>weight</key>
43
+ <real>1010</real>
44
+ </dict>
45
+ <key>^version.plist$</key>
46
+ <true/>
47
+ </dict>
48
+ <key>rules2</key>
49
+ <dict>
50
+ <key>.*\.dSYM($|/)</key>
51
+ <dict>
52
+ <key>weight</key>
53
+ <real>11</real>
54
+ </dict>
55
+ <key>^(.*/)?\.DS_Store$</key>
56
+ <dict>
57
+ <key>omit</key>
58
+ <true/>
59
+ <key>weight</key>
60
+ <real>2000</real>
61
+ </dict>
62
+ <key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
63
+ <dict>
64
+ <key>nested</key>
65
+ <true/>
66
+ <key>weight</key>
67
+ <real>10</real>
68
+ </dict>
69
+ <key>^.*</key>
70
+ <true/>
71
+ <key>^Info\.plist$</key>
72
+ <dict>
73
+ <key>omit</key>
74
+ <true/>
75
+ <key>weight</key>
76
+ <real>20</real>
77
+ </dict>
78
+ <key>^PkgInfo$</key>
79
+ <dict>
80
+ <key>omit</key>
81
+ <true/>
82
+ <key>weight</key>
83
+ <real>20</real>
84
+ </dict>
85
+ <key>^Resources/</key>
86
+ <dict>
87
+ <key>weight</key>
88
+ <real>20</real>
89
+ </dict>
90
+ <key>^Resources/.*\.lproj/</key>
91
+ <dict>
92
+ <key>optional</key>
93
+ <true/>
94
+ <key>weight</key>
95
+ <real>1000</real>
96
+ </dict>
97
+ <key>^Resources/.*\.lproj/locversion.plist$</key>
98
+ <dict>
99
+ <key>omit</key>
100
+ <true/>
101
+ <key>weight</key>
102
+ <real>1100</real>
103
+ </dict>
104
+ <key>^Resources/Base\.lproj/</key>
105
+ <dict>
106
+ <key>weight</key>
107
+ <real>1010</real>
108
+ </dict>
109
+ <key>^[^/]+$</key>
110
+ <dict>
111
+ <key>nested</key>
112
+ <true/>
113
+ <key>weight</key>
114
+ <real>10</real>
115
+ </dict>
116
+ <key>^embedded\.provisionprofile$</key>
117
+ <dict>
118
+ <key>weight</key>
119
+ <real>20</real>
120
+ </dict>
121
+ <key>^version\.plist$</key>
122
+ <dict>
123
+ <key>weight</key>
124
+ <real>20</real>
125
+ </dict>
126
+ </dict>
127
+ </dict>
128
+ </plist>
@@ -0,0 +1,27 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <!-- The outer helpers bundle: things-deputy (automation, unsandboxed) is the
6
+ main executable; the sandboxed things-reader.app nests under
7
+ Contents/Helpers with its own identity + entitlements. TCC keys the
8
+ deputy by THIS bundle identifier, so it must stay stable across
9
+ releases. LSUIElement keeps it out of the Dock. -->
10
+ <key>CFBundleIdentifier</key>
11
+ <string>com.pixelcog.things-api-helper</string>
12
+ <key>CFBundleName</key>
13
+ <string>Things API Helper</string>
14
+ <key>CFBundleExecutable</key>
15
+ <string>things-deputy</string>
16
+ <key>CFBundlePackageType</key>
17
+ <string>APPL</string>
18
+ <key>CFBundleShortVersionString</key>
19
+ <string>1.3.0</string>
20
+ <!-- Original artwork, drawn by scripts/generate-helper-icon.jxa — the icon
21
+ System Settings shows next to the Automation/Accessibility toggles. -->
22
+ <key>CFBundleIconFile</key>
23
+ <string>AppIcon</string>
24
+ <key>LSUIElement</key>
25
+ <true/>
26
+ </dict>
27
+ </plist>
@@ -0,0 +1,137 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <key>files</key>
6
+ <dict>
7
+ <key>Resources/AppIcon.icns</key>
8
+ <data>
9
+ 9VX5ZsSdgBEnhGRQvzKyEjHvzeM=
10
+ </data>
11
+ </dict>
12
+ <key>files2</key>
13
+ <dict>
14
+ <key>Helpers/things-reader.app</key>
15
+ <dict>
16
+ <key>cdhash</key>
17
+ <data>
18
+ DCwtQKeK2+xh4Jh2U4b6UU9KZv4=
19
+ </data>
20
+ <key>requirement</key>
21
+ <string>identifier "com.pixelcog.things-reader" and anchor apple generic and certificate 1[field.1.2.840.113635.100.6.2.6] /* exists */ and certificate leaf[field.1.2.840.113635.100.6.1.13] /* exists */ and certificate leaf[subject.OU] = VNJWARH2W7</string>
22
+ </dict>
23
+ <key>Resources/AppIcon.icns</key>
24
+ <dict>
25
+ <key>hash2</key>
26
+ <data>
27
+ li4eVDJT2l1+UncvB0nWNrYjSQliN87HTz3w1j2kG3A=
28
+ </data>
29
+ </dict>
30
+ </dict>
31
+ <key>rules</key>
32
+ <dict>
33
+ <key>^Resources/</key>
34
+ <true/>
35
+ <key>^Resources/.*\.lproj/</key>
36
+ <dict>
37
+ <key>optional</key>
38
+ <true/>
39
+ <key>weight</key>
40
+ <real>1000</real>
41
+ </dict>
42
+ <key>^Resources/.*\.lproj/locversion.plist$</key>
43
+ <dict>
44
+ <key>omit</key>
45
+ <true/>
46
+ <key>weight</key>
47
+ <real>1100</real>
48
+ </dict>
49
+ <key>^Resources/Base\.lproj/</key>
50
+ <dict>
51
+ <key>weight</key>
52
+ <real>1010</real>
53
+ </dict>
54
+ <key>^version.plist$</key>
55
+ <true/>
56
+ </dict>
57
+ <key>rules2</key>
58
+ <dict>
59
+ <key>.*\.dSYM($|/)</key>
60
+ <dict>
61
+ <key>weight</key>
62
+ <real>11</real>
63
+ </dict>
64
+ <key>^(.*/)?\.DS_Store$</key>
65
+ <dict>
66
+ <key>omit</key>
67
+ <true/>
68
+ <key>weight</key>
69
+ <real>2000</real>
70
+ </dict>
71
+ <key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
72
+ <dict>
73
+ <key>nested</key>
74
+ <true/>
75
+ <key>weight</key>
76
+ <real>10</real>
77
+ </dict>
78
+ <key>^.*</key>
79
+ <true/>
80
+ <key>^Info\.plist$</key>
81
+ <dict>
82
+ <key>omit</key>
83
+ <true/>
84
+ <key>weight</key>
85
+ <real>20</real>
86
+ </dict>
87
+ <key>^PkgInfo$</key>
88
+ <dict>
89
+ <key>omit</key>
90
+ <true/>
91
+ <key>weight</key>
92
+ <real>20</real>
93
+ </dict>
94
+ <key>^Resources/</key>
95
+ <dict>
96
+ <key>weight</key>
97
+ <real>20</real>
98
+ </dict>
99
+ <key>^Resources/.*\.lproj/</key>
100
+ <dict>
101
+ <key>optional</key>
102
+ <true/>
103
+ <key>weight</key>
104
+ <real>1000</real>
105
+ </dict>
106
+ <key>^Resources/.*\.lproj/locversion.plist$</key>
107
+ <dict>
108
+ <key>omit</key>
109
+ <true/>
110
+ <key>weight</key>
111
+ <real>1100</real>
112
+ </dict>
113
+ <key>^Resources/Base\.lproj/</key>
114
+ <dict>
115
+ <key>weight</key>
116
+ <real>1010</real>
117
+ </dict>
118
+ <key>^[^/]+$</key>
119
+ <dict>
120
+ <key>nested</key>
121
+ <true/>
122
+ <key>weight</key>
123
+ <real>10</real>
124
+ </dict>
125
+ <key>^embedded\.provisionprofile$</key>
126
+ <dict>
127
+ <key>weight</key>
128
+ <real>20</real>
129
+ </dict>
130
+ <key>^version\.plist$</key>
131
+ <dict>
132
+ <key>weight</key>
133
+ <real>20</real>
134
+ </dict>
135
+ </dict>
136
+ </dict>
137
+ </plist>
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <!-- A real bundle is mandatory: secinit refuses to sandbox a bare
6
+ executable (SANDBOX1). LSUIElement keeps it out of the Dock. -->
7
+ <key>CFBundleIdentifier</key>
8
+ <string>com.pixelcog.things-reader</string>
9
+ <key>CFBundleName</key>
10
+ <string>things-reader</string>
11
+ <key>CFBundleExecutable</key>
12
+ <string>things-reader</string>
13
+ <key>CFBundlePackageType</key>
14
+ <string>APPL</string>
15
+ <key>CFBundleIconFile</key>
16
+ <string>AppIcon</string>
17
+ <key>CFBundleShortVersionString</key>
18
+ <string>0.0.0</string>
19
+ <key>LSUIElement</key>
20
+ <true/>
21
+ </dict>
22
+ </plist>
@@ -0,0 +1,45 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3
+ <plist version="1.0">
4
+ <dict>
5
+ <!-- The reader's entire privilege model: App Sandbox + the powerbox grant.
6
+ user-selected admits the one-time panel selection; bookmarks.app-scope
7
+ makes it durable across processes, reboots, and rebuilds (SANDBOX1). -->
8
+ <key>com.apple.security.app-sandbox</key>
9
+ <true/>
10
+ <key>com.apple.security.files.user-selected.read-only</key>
11
+ <true/>
12
+ <key>com.apple.security.files.bookmarks.app-scope</key>
13
+ <true/>
14
+ <!-- The ONE path outside the container the reader may touch: its rendezvous
15
+ directory, where it binds the client-facing socket. launchd Sockets
16
+ activation is unusable from inside the sandbox (error 159, measured
17
+ 2026-08-24), so the reader binds the socket itself under this exception.
18
+ Scoped to a single dot-directory subtree; notarization accepts
19
+ temporary-exceptions on Developer ID builds. -->
20
+ <!-- MEASURED 2026-08-24: with the file exception alone, plain file writes in
21
+ the rendezvous dir SUCCEED while bind(2) is denied EPERM — unix-socket
22
+ binding is the sandbox's network-bind operation class, path-filtered to
23
+ the container, and network.server does not extend it. The raw-SBPL
24
+ temporary exception below is the one public lever that does. -->
25
+ <!-- Unix-socket bind is the sandbox's network-bind operation class, path-
26
+ filtered to the container — MEASURED 2026-08-24: with the file exception
27
+ alone, file writes in the rendezvous dir succeed while bind(2) is EPERM,
28
+ and `network.server` does not extend it. This raw-SBPL exception is the
29
+ one public lever that does. Grammar is picky (also measured): a
30
+ `(subpath ...)` filter compiles; a regex filter and the bare
31
+ `(allow network-bind network-listen)` form both make sandbox
32
+ initialization TRAP at spawn (SIGTRAP, and launchd bootstrap fails 5).
33
+ "/Users" because entitlements are baked at signing and must serve any
34
+ user's home; the reader's practical reach stays scoped by the file
35
+ exception above (it can only create the socket where it can write). -->
36
+ <key>com.apple.security.temporary-exception.sbpl</key>
37
+ <array>
38
+ <string>(allow network-bind (subpath "/Users"))</string>
39
+ </array>
40
+ <key>com.apple.security.temporary-exception.files.home-relative-path.read-write</key>
41
+ <array>
42
+ <string>/.local/state/things-api/reader/</string>
43
+ </array>
44
+ </dict>
45
+ </plist>