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
@@ -1 +1 @@
1
- {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,MAAM,EAAE;QACN,MAAM;QACN,MAAM;QACN,QAAQ;QACR,UAAU;QACV,SAAS;QACT,OAAO;QACP,OAAO;QACP,cAAc;QACd,sBAAsB;QACtB,OAAO;QACP,WAAW;QACX,aAAa;QACb,cAAc;QACd,UAAU;QACV,yBAAyB;QACzB,OAAO;QACP,YAAY;QACZ,yBAAyB;QACzB,MAAM;QACN,SAAS;QACT,SAAS;QACT,2BAA2B;QAC3B,+BAA+B;QAC/B,qBAAqB;QACrB,yBAAyB;QACzB,uBAAuB;QACvB,oBAAoB;QACpB,2BAA2B;QAC3B,4BAA4B;QAC5B,UAAU;KACX;IACD,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC;IAC7C,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,CAAC;IACnE,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE;QACf,MAAM;QACN,OAAO;QACP,QAAQ;QACR,UAAU;QACV,OAAO;QACP,MAAM;QACN,cAAc;QACd,sBAAsB;KACvB;IACD,UAAU,EAAE;QACV,MAAM;QACN,8BAA8B;QAC9B,oBAAoB;QACpB,aAAa;QACb,eAAe;KAChB;IACD,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC;CACd,CAAC;AAIX,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,eAAe,CAAoB,CAAC;AAE3E;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,aAAa,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,4BAA4B;IACtD,eAAe,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,8BAA8B;IAC1D,cAAc,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,2BAA2B;IACtD,oBAAoB,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,kBAAkB;IAChD,gBAAgB,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IACxB,wBAAwB,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;CAC3B,CAAC;AAEX,iFAAiF;AACjF,MAAM,UAAU,CAAC,CAAC,UAAkB;IAClC,OAAO,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;AACjD,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,UAAU,CAAC,KAAoB;IAC7C,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAClD,CAAC"}
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG;IAC7B,MAAM,EAAE;QACN,MAAM;QACN,MAAM;QACN,QAAQ;QACR,UAAU;QACV,SAAS;QACT,OAAO;QACP,OAAO;QACP,cAAc;QACd,sBAAsB;QACtB,OAAO;QACP,WAAW;QACX,aAAa;QACb,cAAc;QACd,UAAU;QACV,yBAAyB;QACzB,OAAO;QACP,YAAY;QACZ,yBAAyB;QACzB,MAAM;QACN,SAAS;QACT,SAAS;QACT,2BAA2B;QAC3B,+BAA+B;QAC/B,qBAAqB;QACrB,yBAAyB;QACzB,uBAAuB;QACvB,oBAAoB;QACpB,2BAA2B;QAC3B,4BAA4B;QAC5B,0EAA0E;QAC1E,sEAAsE;QACtE,2EAA2E;QAC3E,4EAA4E;QAC5E,sEAAsE;QACtE,wEAAwE;QACxE,iEAAiE;QACjE,+BAA+B;QAC/B,2BAA2B;QAC3B,UAAU;KACX;IACD,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC;IAC7C,KAAK,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,CAAC;IACnE,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC;IAC5B,eAAe,EAAE;QACf,MAAM;QACN,OAAO;QACP,QAAQ;QACR,UAAU;QACV,OAAO;QACP,MAAM;QACN,cAAc;QACd,sBAAsB;KACvB;IACD,UAAU,EAAE;QACV,MAAM;QACN,8BAA8B;QAC9B,oBAAoB;QACpB,aAAa;QACb,eAAe;KAChB;IACD,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC;CACd,CAAC;AAIX,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,eAAe,CAAoB,CAAC;AAE3E;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG;IAC1B,aAAa,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,4BAA4B;IACtD,eAAe,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,8BAA8B;IAC1D,cAAc,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,2BAA2B;IACtD,oBAAoB,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,kBAAkB;IAChD,gBAAgB,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;IACxB,wBAAwB,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;CAC3B,CAAC;AAEX,iFAAiF;AACjF,MAAM,UAAU,CAAC,CAAC,UAAkB;IAClC,OAAO,IAAI,UAAU,CAAC,UAAU,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC;AACjD,CAAC;AAED,oEAAoE;AACpE,MAAM,UAAU,UAAU,CAAC,KAAoB;IAC7C,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Worker half of the synchronous deputy bridge (see bridge.ts). Owns the
3
+ * long-lived socket to the deputy and services one request at a time: the main
4
+ * thread posts a request on the message port and blocks in Atomics.wait; this
5
+ * worker performs the socket round-trip, posts the response back, and bumps the
6
+ * shared counter to wake the main thread.
7
+ */
8
+ import { connect } from "node:net";
9
+ import { workerData } from "node:worker_threads";
10
+ const { socketPath, sab, port } = workerData;
11
+ const flag = new Int32Array(sab);
12
+ let socket = null;
13
+ let buffer = "";
14
+ let pendingLine = null;
15
+ let pendingError = null;
16
+ function resetSocket(err) {
17
+ socket = null;
18
+ buffer = "";
19
+ const reject = pendingError;
20
+ pendingLine = null;
21
+ pendingError = null;
22
+ reject?.(err);
23
+ }
24
+ function ensureSocket() {
25
+ if (socket !== null)
26
+ return Promise.resolve(socket);
27
+ return new Promise((resolve, reject) => {
28
+ const sock = connect(socketPath);
29
+ sock.setEncoding("utf8");
30
+ sock.once("connect", () => {
31
+ socket = sock;
32
+ resolve(sock);
33
+ });
34
+ sock.on("data", (chunk) => {
35
+ buffer += chunk;
36
+ const nl = buffer.indexOf("\n");
37
+ if (nl < 0)
38
+ return;
39
+ const line = buffer.slice(0, nl);
40
+ buffer = buffer.slice(nl + 1);
41
+ const deliver = pendingLine;
42
+ pendingLine = null;
43
+ pendingError = null;
44
+ deliver?.(line);
45
+ });
46
+ sock.on("error", (err) => {
47
+ if (socket === null)
48
+ reject(err);
49
+ resetSocket(err);
50
+ });
51
+ sock.on("close", () => {
52
+ resetSocket(new Error("deputy closed the connection"));
53
+ });
54
+ });
55
+ }
56
+ async function roundTrip(request) {
57
+ const sock = await ensureSocket();
58
+ const line = await new Promise((resolve, reject) => {
59
+ pendingLine = resolve;
60
+ pendingError = reject;
61
+ sock.write(`${JSON.stringify(request)}\n`);
62
+ });
63
+ return JSON.parse(line);
64
+ }
65
+ port.on("message", ({ bridgeId, request }) => {
66
+ void roundTrip(request)
67
+ .then((response) => ({ bridgeId, response: response }))
68
+ .catch((err) => ({
69
+ bridgeId,
70
+ error: err instanceof Error ? err.message : String(err),
71
+ }))
72
+ .then((envelope) => {
73
+ port.postMessage(envelope);
74
+ Atomics.add(flag, 0, 1);
75
+ Atomics.notify(flag, 0);
76
+ });
77
+ });
78
+ port.start();
79
+ //# sourceMappingURL=bridge-worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge-worker.js","sourceRoot":"","sources":["../../src/deputy/bridge-worker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ export declare class DeputySyncBridge {
2
+ private readonly worker;
3
+ private readonly flag;
4
+ private readonly port;
5
+ private seq;
6
+ constructor(socketPath: string);
7
+ /**
8
+ * Send one request and block until its response (or the deadline). Late
9
+ * responses from a previously timed-out request are drained and discarded by
10
+ * the id match, so one timeout never poisons the next call.
11
+ */
12
+ request(payload: Record<string, unknown>, timeoutMs: number): Record<string, unknown>;
13
+ close(): void;
14
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Synchronous bridge to the deputy for callers that cannot await — the
3
+ * DatabaseSync-shaped read facade and the sync consent probes. A dedicated
4
+ * worker thread owns the socket; the main thread posts a request, blocks in
5
+ * Atomics.wait on a shared counter, then drains the port with
6
+ * receiveMessageOnPort. One request is in flight at a time by construction
7
+ * (the main thread is blocked while it waits).
8
+ *
9
+ * The bridge must NOT be used for long-running osascript drives — blocking the
10
+ * event loop would suspend the drive watchdog and signal handlers. Async
11
+ * dispatch rides client.ts instead.
12
+ */
13
+ import { MessageChannel, receiveMessageOnPort, Worker, } from "node:worker_threads";
14
+ import { DeputyRequestError } from "./protocol.js";
15
+ export class DeputySyncBridge {
16
+ worker;
17
+ flag;
18
+ port;
19
+ seq = 0;
20
+ constructor(socketPath) {
21
+ const sab = new SharedArrayBuffer(4);
22
+ this.flag = new Int32Array(sab);
23
+ const channel = new MessageChannel();
24
+ this.port = channel.port1;
25
+ // Live TS source runs the .ts twin; the published build runs the emitted
26
+ // .js next to this module (same trick as src/cli/version.ts).
27
+ const ext = import.meta.url.endsWith(".ts") ? "ts" : "js";
28
+ this.worker = new Worker(new URL(`./bridge-worker.${ext}`, import.meta.url), {
29
+ workerData: { socketPath, sab, port: channel.port2 },
30
+ transferList: [channel.port2],
31
+ });
32
+ // The bridge must never keep the CLI process alive on its own.
33
+ this.worker.unref();
34
+ }
35
+ /**
36
+ * Send one request and block until its response (or the deadline). Late
37
+ * responses from a previously timed-out request are drained and discarded by
38
+ * the id match, so one timeout never poisons the next call.
39
+ */
40
+ request(payload, timeoutMs) {
41
+ const id = `s${++this.seq}`;
42
+ let seen = Atomics.load(this.flag, 0);
43
+ // oxlint-disable-next-line require-post-message-target-origin -- worker_threads port, no targetOrigin
44
+ this.port.postMessage({ bridgeId: id, request: payload });
45
+ const deadline = Date.now() + timeoutMs;
46
+ for (;;) {
47
+ let received = receiveMessageOnPort(this.port);
48
+ while (received !== undefined) {
49
+ const message = received.message;
50
+ if (message.bridgeId === id) {
51
+ if (message.error !== undefined) {
52
+ throw new DeputyRequestError("bridge-io", message.error);
53
+ }
54
+ return message.response ?? {};
55
+ }
56
+ received = receiveMessageOnPort(this.port);
57
+ }
58
+ const remaining = deadline - Date.now();
59
+ if (remaining <= 0) {
60
+ throw new DeputyRequestError("bridge-timeout", `the deputy did not answer within ${timeoutMs}ms`);
61
+ }
62
+ Atomics.wait(this.flag, 0, seen, remaining);
63
+ seen = Atomics.load(this.flag, 0);
64
+ }
65
+ }
66
+ close() {
67
+ void this.worker.terminate();
68
+ }
69
+ }
70
+ //# sourceMappingURL=bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bridge.js","sourceRoot":"","sources":["../../src/deputy/bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,EACL,cAAc,EAEd,oBAAoB,EACpB,MAAM,GACP,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,OAAO,gBAAgB;IACV,MAAM,CAAS;IACf,IAAI,CAAa;IACjB,IAAI,CAAc;IAC3B,GAAG,GAAG,CAAC,CAAC;IAEhB,YAAY,UAAkB;QAC5B,MAAM,GAAG,GAAG,IAAI,iBAAiB,CAAC,CAAC,CAAC,CAAC;QACrC,IAAI,CAAC,IAAI,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,OAAO,GAAG,IAAI,cAAc,EAAE,CAAC;QACrC,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC;QAC1B,yEAAyE;QACzE,8DAA8D;QAC9D,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAC1D,IAAI,CAAC,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,GAAG,CAAC,mBAAmB,GAAG,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE;YAC3E,UAAU,EAAE,EAAE,UAAU,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,CAAC,KAAK,EAAE;YACpD,YAAY,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;SAC9B,CAAC,CAAC;QACH,+DAA+D;QAC/D,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,OAAgC,EAAE,SAAiB;QACzD,MAAM,EAAE,GAAG,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,CAAC;QAC5B,IAAI,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACtC,sGAAsG;QACtG,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;QACxC,SAAS,CAAC;YACR,IAAI,QAAQ,GAAG,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC/C,OAAO,QAAQ,KAAK,SAAS,EAAE,CAAC;gBAC9B,MAAM,OAAO,GAAG,QAAQ,CAAC,OAIxB,CAAC;gBACF,IAAI,OAAO,CAAC,QAAQ,KAAK,EAAE,EAAE,CAAC;oBAC5B,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;wBAChC,MAAM,IAAI,kBAAkB,CAAC,WAAW,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;oBAC3D,CAAC;oBACD,OAAO,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC;gBAChC,CAAC;gBACD,QAAQ,GAAG,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC7C,CAAC;YACD,MAAM,SAAS,GAAG,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACxC,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;gBACnB,MAAM,IAAI,kBAAkB,CAC1B,gBAAgB,EAChB,oCAAoC,SAAS,IAAI,CAClD,CAAC;YACJ,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC;YAC5C,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,KAAK;QACH,KAAK,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC;IAC/B,CAAC;CACF"}
@@ -0,0 +1,19 @@
1
+ export declare class DeputyAsyncClient {
2
+ private socket;
3
+ private buffer;
4
+ private seq;
5
+ private readonly pending;
6
+ private readonly socketPath;
7
+ constructor(socketPath: string);
8
+ private ensureSocket;
9
+ private onData;
10
+ private failAll;
11
+ /**
12
+ * Send one request; resolves with the raw response object (protocol errors
13
+ * included — the caller inspects `ok`). Rejects only on transport failure or
14
+ * client-side deadline (`timeoutMs` should exceed any deputy-side timeout so
15
+ * the deputy's own honest answer wins).
16
+ */
17
+ request(payload: Record<string, unknown>, timeoutMs: number): Promise<Record<string, unknown>>;
18
+ close(): void;
19
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Async deputy client for event-loop-friendly callers: the applescript vector
3
+ * and the ui vector's step runner. Long osascript drives ride this client so
4
+ * timers (drive watchdog) and signal handlers keep running; synchronous
5
+ * callers ride bridge.ts instead. One shared socket, requests matched by id.
6
+ */
7
+ import { connect } from "node:net";
8
+ import { DeputyRequestError } from "./protocol.js";
9
+ export class DeputyAsyncClient {
10
+ socket = null;
11
+ buffer = "";
12
+ seq = 0;
13
+ pending = new Map();
14
+ socketPath;
15
+ constructor(socketPath) {
16
+ this.socketPath = socketPath;
17
+ }
18
+ ensureSocket() {
19
+ if (this.socket !== null)
20
+ return Promise.resolve(this.socket);
21
+ return new Promise((resolve, reject) => {
22
+ const sock = connect(this.socketPath);
23
+ sock.setEncoding("utf8");
24
+ sock.once("connect", () => {
25
+ this.socket = sock;
26
+ // An idle deputy connection must never keep the CLI process alive.
27
+ sock.unref();
28
+ resolve(sock);
29
+ });
30
+ sock.on("data", (chunk) => this.onData(chunk));
31
+ sock.on("error", (err) => {
32
+ if (this.socket === null)
33
+ reject(err);
34
+ this.failAll(err);
35
+ });
36
+ sock.on("close", () => this.failAll(new Error("deputy closed the connection")));
37
+ });
38
+ }
39
+ onData(chunk) {
40
+ this.buffer += chunk;
41
+ for (;;) {
42
+ const nl = this.buffer.indexOf("\n");
43
+ if (nl < 0)
44
+ return;
45
+ const line = this.buffer.slice(0, nl);
46
+ this.buffer = this.buffer.slice(nl + 1);
47
+ let parsed;
48
+ try {
49
+ parsed = JSON.parse(line);
50
+ }
51
+ catch {
52
+ continue;
53
+ }
54
+ const id = typeof parsed["id"] === "string" ? parsed["id"] : null;
55
+ const entry = id !== null ? this.pending.get(id) : undefined;
56
+ if (id === null || entry === undefined)
57
+ continue;
58
+ this.pending.delete(id);
59
+ clearTimeout(entry.timer);
60
+ entry.resolve(parsed);
61
+ }
62
+ }
63
+ failAll(err) {
64
+ this.socket = null;
65
+ this.buffer = "";
66
+ const waiting = [...this.pending.values()];
67
+ this.pending.clear();
68
+ for (const entry of waiting) {
69
+ clearTimeout(entry.timer);
70
+ entry.reject(err);
71
+ }
72
+ }
73
+ /**
74
+ * Send one request; resolves with the raw response object (protocol errors
75
+ * included — the caller inspects `ok`). Rejects only on transport failure or
76
+ * client-side deadline (`timeoutMs` should exceed any deputy-side timeout so
77
+ * the deputy's own honest answer wins).
78
+ */
79
+ async request(payload, timeoutMs) {
80
+ const sock = await this.ensureSocket();
81
+ const id = `a${++this.seq}`;
82
+ // Wake the socket handle while a request is in flight (see unref above).
83
+ sock.ref();
84
+ try {
85
+ return await new Promise((resolve, reject) => {
86
+ const timer = setTimeout(() => {
87
+ this.pending.delete(id);
88
+ reject(new DeputyRequestError("client-timeout", `the deputy did not answer within ${timeoutMs}ms`));
89
+ }, timeoutMs);
90
+ this.pending.set(id, { resolve, reject, timer });
91
+ sock.write(`${JSON.stringify({ ...payload, id })}\n`);
92
+ });
93
+ }
94
+ finally {
95
+ if (this.pending.size === 0)
96
+ sock.unref();
97
+ }
98
+ }
99
+ close() {
100
+ this.socket?.destroy();
101
+ this.socket = null;
102
+ }
103
+ }
104
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/deputy/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * A DatabaseSync-shaped READ facade over the deputy's `sql` verb. The read
3
+ * layer types against node:sqlite's DatabaseSync and only ever prepares
4
+ * SELECT/PRAGMA statements consumed via `.all()` / `.get()`; this facade
5
+ * implements exactly that surface synchronously (through the bridge) and
6
+ * throws a teaching error on anything else — never a silent no-op. WAL
7
+ * freshness is preserved: the deputy holds one read-only connection outside
8
+ * any transaction, so every statement sees a fresh snapshot exactly like a
9
+ * local connection (docs/design/architecture.md §0).
10
+ */
11
+ import type { DatabaseSync } from "node:sqlite";
12
+ /**
13
+ * Build the facade. The cast is confined to this one construction site: the
14
+ * object structurally implements the read subset, a Proxy turns any other
15
+ * member access into a teaching error, and symbol probes (inspect, iterators)
16
+ * stay undefined so logging never explodes.
17
+ */
18
+ export declare function createDeputyDbFacade(env?: NodeJS.ProcessEnv): DatabaseSync;
@@ -0,0 +1,71 @@
1
+ import { reviveRow } from "./protocol.js";
2
+ import { fileSyncRequest } from "./routing.js";
3
+ const SQL_TIMEOUT_MS = 15_000;
4
+ function normalizeParams(params, sql) {
5
+ return params.map((param, index) => {
6
+ if (param === null || typeof param === "string" || typeof param === "number")
7
+ return param;
8
+ if (typeof param === "bigint") {
9
+ if (param > BigInt(Number.MAX_SAFE_INTEGER) || param < BigInt(Number.MIN_SAFE_INTEGER)) {
10
+ throw new TypeError(`deputy sql: bigint parameter ${index} exceeds JSON-safe range`);
11
+ }
12
+ return Number(param);
13
+ }
14
+ throw new TypeError(`deputy sql: unsupported ${typeof param} parameter at index ${index} for: ${sql.slice(0, 80)}`);
15
+ });
16
+ }
17
+ function queryRows(sql, params, env) {
18
+ // Rides the granted reader when present, else the deputy (routing.ts).
19
+ const res = fileSyncRequest({ verb: "sql", sql, params: normalizeParams(params, sql) }, SQL_TIMEOUT_MS, env);
20
+ return res["rows"].map(reviveRow);
21
+ }
22
+ function unsupported(member) {
23
+ return () => {
24
+ throw new Error(`DatabaseSync.${member} is not available on a deputy-routed connection — the deputy brokers read-only prepare/all/get only. Disable the helpers (THINGS_API_HELPERS=false) for local access.`);
25
+ };
26
+ }
27
+ /**
28
+ * Build the facade. The cast is confined to this one construction site: the
29
+ * object structurally implements the read subset, a Proxy turns any other
30
+ * member access into a teaching error, and symbol probes (inspect, iterators)
31
+ * stay undefined so logging never explodes.
32
+ */
33
+ export function createDeputyDbFacade(env = process.env) {
34
+ const base = {
35
+ prepare(sql) {
36
+ const statement = {
37
+ all(...params) {
38
+ return queryRows(sql, params, env);
39
+ },
40
+ get(...params) {
41
+ return queryRows(sql, params, env)[0];
42
+ },
43
+ run: unsupported("prepare(...).run (writes never touch the database directly)"),
44
+ iterate: unsupported("prepare(...).iterate"),
45
+ expandedSQL: sql,
46
+ sourceSQL: sql,
47
+ };
48
+ return new Proxy(statement, {
49
+ get(target, prop, receiver) {
50
+ if (typeof prop === "symbol" || prop in target)
51
+ return Reflect.get(target, prop, receiver);
52
+ return unsupported(`prepare(...).${String(prop)}`)();
53
+ },
54
+ });
55
+ },
56
+ exec: unsupported("exec"),
57
+ close() {
58
+ // The bridge outlives individual connections; nothing to release here.
59
+ },
60
+ isOpen: true,
61
+ isTransaction: false,
62
+ };
63
+ return new Proxy(base, {
64
+ get(target, prop, receiver) {
65
+ if (typeof prop === "symbol" || prop in target)
66
+ return Reflect.get(target, prop, receiver);
67
+ return unsupported(String(prop))();
68
+ },
69
+ });
70
+ }
71
+ //# sourceMappingURL=db-facade.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-facade.js","sourceRoot":"","sources":["../../src/deputy/db-facade.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function readContainerFileSync(path: string): Buffer;
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Container-scoped file reads (Things prefs plists for sync-health and URL-
3
+ * scheme availability). The group container is TCC-protected like the
4
+ * database, so in deputy mode these reads ride the deputy's `read-file` verb —
5
+ * which the deputy confines to the container subtree. Direct mode is a plain
6
+ * readFileSync, byte-identical to the pre-deputy behavior.
7
+ */
8
+ import { readFileSync } from "node:fs";
9
+ import { deputyFilesActive, fileSyncRequest } from "./routing.js";
10
+ export function readContainerFileSync(path) {
11
+ if (!deputyFilesActive())
12
+ return readFileSync(path);
13
+ const res = fileSyncRequest({ verb: "read-file", path }, 10_000);
14
+ return Buffer.from(res["b64"], "base64");
15
+ }
16
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/deputy/files.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAElE,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,IAAI,CAAC,iBAAiB,EAAE;QAAE,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;IACpD,MAAM,GAAG,GAAG,eAAe,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,EAAE,MAAM,CAAC,CAAC;IACjE,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAW,EAAE,QAAQ,CAAC,CAAC;AACrD,CAAC"}
@@ -0,0 +1,105 @@
1
+ import type { HelpersMode } from "../config.ts";
2
+ import { type DeputyHello } from "./protocol.ts";
3
+ export declare function deputyPlistPath(): string;
4
+ export declare function readerPlistPath(): string;
5
+ /**
6
+ * Where an install looks for the bundle when the caller names no path, in
7
+ * preference order: `deputy/prebuilt` — the signed + notarized bundle the
8
+ * release workflow stages into the published tarball, so an npm install needs
9
+ * neither Xcode nor a certificate — then `deputy/build`, the output of
10
+ * scripts/build-helpers.sh in a source checkout.
11
+ */
12
+ export declare function helpersBundleCandidates(): string[];
13
+ /**
14
+ * The first candidate bundle that carries a deputy executable; null when none
15
+ * does. Both candidates are READ only — nothing in the `things helpers` path
16
+ * ever writes inside the package directory, so the CLI works from a read-only
17
+ * package root (an npx cache); BUILDING a bundle there is the one operation
18
+ * that needs a writable checkout, and `--bundle <path>` covers a prebuilt one.
19
+ */
20
+ export declare function helpersDefaultBuildPath(): string | null;
21
+ /**
22
+ * The INSTALLED bundle's version, read prompt-free from its Info.plist
23
+ * (CFBundleShortVersionString, stamped from deputy/VERSION at build time).
24
+ * Null when nothing is installed or the plist is unreadable/unstamped. This is
25
+ * the version a passive upgrade notice compares against
26
+ * {@link EXPECTED_HELPERS_VERSION} without needing a running helper.
27
+ */
28
+ export declare function installedHelpersVersion(env?: NodeJS.ProcessEnv): string | null;
29
+ export interface DeputySigning {
30
+ state: "signed" | "adhoc" | "unsigned" | "unknown";
31
+ authority: string | null;
32
+ }
33
+ /** codesign facts about a binary (diagnostic output — may name mechanisms). */
34
+ export declare function deputySigningInfo(binaryPath: string): DeputySigning;
35
+ export interface HelpersInstallResult {
36
+ bundlePath: string;
37
+ plistPath: string;
38
+ stateDir: string;
39
+ signing: DeputySigning;
40
+ readerInstalled: boolean;
41
+ /** Reader grant state after install: null when the reader is absent or never answered. */
42
+ readerGranted: boolean | null;
43
+ warnings: string[];
44
+ }
45
+ /**
46
+ * Install (or reinstall) the helpers: copy the built bundle to its stable
47
+ * path, write both LaunchAgent plists, and (re)bootstrap them under launchd.
48
+ */
49
+ export declare function installHelpers(options?: {
50
+ bundlePath?: string;
51
+ }, env?: NodeJS.ProcessEnv): HelpersInstallResult;
52
+ export interface HelpersUninstallResult {
53
+ removed: string[];
54
+ }
55
+ /** Stop both halves and remove LaunchAgents + the installed bundle (state — tokens, logs, the reader's grant — is kept). */
56
+ export declare function uninstallHelpers(env?: NodeJS.ProcessEnv): HelpersUninstallResult;
57
+ /** Restart the launchd-managed helpers (picks up a rebuilt installed bundle). */
58
+ export declare function restartHelpers(): void;
59
+ /**
60
+ * The one-time grant ceremony: open the reader in `--grant` mode (the panel
61
+ * must be presented by the SANDBOXED process — that is what makes the grant
62
+ * durable) and wait for the bookmark to land, confirmed via the reader's
63
+ * handshake. The panel opens INSIDE the Things data folder when it exists, so
64
+ * accepting is the only click. Interactive by design; returns when granted or
65
+ * on timeout, and verifies the database actually resolves inside the granted
66
+ * scope so a wrong-folder grant reports loudly instead of half-working.
67
+ */
68
+ export declare function grantReader(env?: NodeJS.ProcessEnv): {
69
+ granted: boolean;
70
+ detail: string;
71
+ };
72
+ export interface DeputyHalfStatus {
73
+ plistInstalled: boolean;
74
+ loaded: boolean;
75
+ running: boolean;
76
+ socketPath: string;
77
+ /**
78
+ * The socket file exists but no handshake came back (a dead process that
79
+ * left its socket behind, or one wedged mid-request). Distinct from plain
80
+ * "not running": the remedy is `things helpers restart`, not an install.
81
+ */
82
+ hungSocket: boolean;
83
+ hello: DeputyHello | null;
84
+ signing: DeputySigning | null;
85
+ detail: string;
86
+ }
87
+ export interface ReaderHalfStatus extends DeputyHalfStatus {
88
+ installed: boolean;
89
+ granted: boolean;
90
+ }
91
+ export interface HelpersStatus {
92
+ /** The configured routing mode (`helpers-enabled`), not what it resolved to. */
93
+ mode: HelpersMode;
94
+ bundleInstalled: boolean;
95
+ /** The installed bundle's version (Info.plist), null when nothing is installed. */
96
+ installedVersion: string | null;
97
+ deputy: DeputyHalfStatus;
98
+ reader: ReaderHalfStatus;
99
+ }
100
+ /**
101
+ * Prompt-free status for both halves: launchd load state, a live handshake
102
+ * when each socket answers, and the installed bundle's signing facts. Works
103
+ * with routing disabled — inspect first, enable after.
104
+ */
105
+ export declare function helpersStatus(mode: HelpersMode, env?: NodeJS.ProcessEnv): HelpersStatus;