appduct 0.9.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 (190) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +274 -0
  3. package/bin.js +2 -0
  4. package/dist/artifact-inspect.d.ts +110 -0
  5. package/dist/artifact-inspect.d.ts.map +1 -0
  6. package/dist/artifact-inspect.js +315 -0
  7. package/dist/bin.d.ts +3 -0
  8. package/dist/bin.d.ts.map +1 -0
  9. package/dist/bin.js +4 -0
  10. package/dist/cli/command-options.d.ts +44 -0
  11. package/dist/cli/command-options.d.ts.map +1 -0
  12. package/dist/cli/command-options.js +95 -0
  13. package/dist/cli/create-cli.d.ts +2 -0
  14. package/dist/cli/create-cli.d.ts.map +1 -0
  15. package/dist/cli/create-cli.js +56 -0
  16. package/dist/cli/dispatch.d.ts +3 -0
  17. package/dist/cli/dispatch.d.ts.map +1 -0
  18. package/dist/cli/dispatch.js +275 -0
  19. package/dist/cli/open-target.d.ts +112 -0
  20. package/dist/cli/open-target.d.ts.map +1 -0
  21. package/dist/cli/open-target.js +438 -0
  22. package/dist/cli/result-types.d.ts +194 -0
  23. package/dist/cli/result-types.d.ts.map +1 -0
  24. package/dist/cli/result-types.js +6 -0
  25. package/dist/cli/runner.d.ts +35 -0
  26. package/dist/cli/runner.d.ts.map +1 -0
  27. package/dist/cli/runner.js +111 -0
  28. package/dist/cli/types.d.ts +20 -0
  29. package/dist/cli/types.d.ts.map +1 -0
  30. package/dist/cli/types.js +10 -0
  31. package/dist/cli.d.ts +4 -0
  32. package/dist/cli.d.ts.map +1 -0
  33. package/dist/cli.js +2 -0
  34. package/dist/client/app-client.d.ts +126 -0
  35. package/dist/client/app-client.d.ts.map +1 -0
  36. package/dist/client/app-client.js +223 -0
  37. package/dist/client/bootstrap.d.ts +48 -0
  38. package/dist/client/bootstrap.d.ts.map +1 -0
  39. package/dist/client/bootstrap.js +108 -0
  40. package/dist/client/connect.d.ts +17 -0
  41. package/dist/client/connect.d.ts.map +1 -0
  42. package/dist/client/connect.js +38 -0
  43. package/dist/client/errors.d.ts +26 -0
  44. package/dist/client/errors.d.ts.map +1 -0
  45. package/dist/client/errors.js +40 -0
  46. package/dist/client/index.d.ts +19 -0
  47. package/dist/client/index.d.ts.map +1 -0
  48. package/dist/client/index.js +16 -0
  49. package/dist/commands/daemon.d.ts +22 -0
  50. package/dist/commands/daemon.d.ts.map +1 -0
  51. package/dist/commands/daemon.js +128 -0
  52. package/dist/commands/doctor.d.ts +23 -0
  53. package/dist/commands/doctor.d.ts.map +1 -0
  54. package/dist/commands/doctor.js +42 -0
  55. package/dist/commands/events.d.ts +37 -0
  56. package/dist/commands/events.d.ts.map +1 -0
  57. package/dist/commands/events.js +76 -0
  58. package/dist/commands/init.d.ts +51 -0
  59. package/dist/commands/init.d.ts.map +1 -0
  60. package/dist/commands/init.js +231 -0
  61. package/dist/commands/invoke.d.ts +22 -0
  62. package/dist/commands/invoke.d.ts.map +1 -0
  63. package/dist/commands/invoke.js +54 -0
  64. package/dist/commands/keygen.d.ts +23 -0
  65. package/dist/commands/keygen.d.ts.map +1 -0
  66. package/dist/commands/keygen.js +46 -0
  67. package/dist/commands/link.d.ts +30 -0
  68. package/dist/commands/link.d.ts.map +1 -0
  69. package/dist/commands/link.js +43 -0
  70. package/dist/commands/ls.d.ts +9 -0
  71. package/dist/commands/ls.d.ts.map +1 -0
  72. package/dist/commands/ls.js +7 -0
  73. package/dist/commands/mcp.d.ts +49 -0
  74. package/dist/commands/mcp.d.ts.map +1 -0
  75. package/dist/commands/mcp.js +98 -0
  76. package/dist/commands/revoke.d.ts +12 -0
  77. package/dist/commands/revoke.d.ts.map +1 -0
  78. package/dist/commands/revoke.js +7 -0
  79. package/dist/commands/tools.d.ts +23 -0
  80. package/dist/commands/tools.d.ts.map +1 -0
  81. package/dist/commands/tools.js +52 -0
  82. package/dist/daemon/address.d.ts +30 -0
  83. package/dist/daemon/address.d.ts.map +1 -0
  84. package/dist/daemon/address.js +71 -0
  85. package/dist/daemon/audit.d.ts +107 -0
  86. package/dist/daemon/audit.d.ts.map +1 -0
  87. package/dist/daemon/audit.js +237 -0
  88. package/dist/daemon/calls.d.ts +84 -0
  89. package/dist/daemon/calls.d.ts.map +1 -0
  90. package/dist/daemon/calls.js +158 -0
  91. package/dist/daemon/config.d.ts +79 -0
  92. package/dist/daemon/config.d.ts.map +1 -0
  93. package/dist/daemon/config.js +170 -0
  94. package/dist/daemon/daemon.d.ts +43 -0
  95. package/dist/daemon/daemon.d.ts.map +1 -0
  96. package/dist/daemon/daemon.js +560 -0
  97. package/dist/daemon/event-bus.d.ts +49 -0
  98. package/dist/daemon/event-bus.d.ts.map +1 -0
  99. package/dist/daemon/event-bus.js +111 -0
  100. package/dist/daemon/links.d.ts +54 -0
  101. package/dist/daemon/links.d.ts.map +1 -0
  102. package/dist/daemon/links.js +118 -0
  103. package/dist/daemon/listener.d.ts +34 -0
  104. package/dist/daemon/listener.d.ts.map +1 -0
  105. package/dist/daemon/listener.js +132 -0
  106. package/dist/daemon/log-rotation.d.ts +82 -0
  107. package/dist/daemon/log-rotation.d.ts.map +1 -0
  108. package/dist/daemon/log-rotation.js +136 -0
  109. package/dist/daemon/pidfile.d.ts +38 -0
  110. package/dist/daemon/pidfile.d.ts.map +1 -0
  111. package/dist/daemon/pidfile.js +90 -0
  112. package/dist/daemon/policy.d.ts +22 -0
  113. package/dist/daemon/policy.d.ts.map +1 -0
  114. package/dist/daemon/policy.js +24 -0
  115. package/dist/daemon/registry.d.ts +19 -0
  116. package/dist/daemon/registry.d.ts.map +1 -0
  117. package/dist/daemon/registry.js +31 -0
  118. package/dist/daemon/rpc-server.d.ts +54 -0
  119. package/dist/daemon/rpc-server.d.ts.map +1 -0
  120. package/dist/daemon/rpc-server.js +203 -0
  121. package/dist/daemon/sessions.d.ts +86 -0
  122. package/dist/daemon/sessions.d.ts.map +1 -0
  123. package/dist/daemon/sessions.js +429 -0
  124. package/dist/daemon/socket-probe.d.ts +16 -0
  125. package/dist/daemon/socket-probe.d.ts.map +1 -0
  126. package/dist/daemon/socket-probe.js +28 -0
  127. package/dist/daemon/state-dir.d.ts +31 -0
  128. package/dist/daemon/state-dir.d.ts.map +1 -0
  129. package/dist/daemon/state-dir.js +43 -0
  130. package/dist/daemon/timers.d.ts +16 -0
  131. package/dist/daemon/timers.d.ts.map +1 -0
  132. package/dist/daemon/timers.js +12 -0
  133. package/dist/daemon/tls.d.ts +58 -0
  134. package/dist/daemon/tls.d.ts.map +1 -0
  135. package/dist/daemon/tls.js +79 -0
  136. package/dist/errors.d.ts +28 -0
  137. package/dist/errors.d.ts.map +1 -0
  138. package/dist/errors.js +162 -0
  139. package/dist/host-certificate.d.ts +8 -0
  140. package/dist/host-certificate.d.ts.map +1 -0
  141. package/dist/host-certificate.js +111 -0
  142. package/dist/index.d.ts +4 -0
  143. package/dist/index.d.ts.map +1 -0
  144. package/dist/index.js +3 -0
  145. package/dist/key-material.d.ts +14 -0
  146. package/dist/key-material.d.ts.map +1 -0
  147. package/dist/key-material.js +42 -0
  148. package/dist/link.d.ts +76 -0
  149. package/dist/link.d.ts.map +1 -0
  150. package/dist/link.js +117 -0
  151. package/dist/mcp/connect-tool.d.ts +115 -0
  152. package/dist/mcp/connect-tool.d.ts.map +1 -0
  153. package/dist/mcp/connect-tool.js +396 -0
  154. package/dist/mcp/daemon-tools.d.ts +13 -0
  155. package/dist/mcp/daemon-tools.d.ts.map +1 -0
  156. package/dist/mcp/daemon-tools.js +29 -0
  157. package/dist/mcp/events-tool.d.ts +111 -0
  158. package/dist/mcp/events-tool.d.ts.map +1 -0
  159. package/dist/mcp/events-tool.js +322 -0
  160. package/dist/mcp/server.d.ts +58 -0
  161. package/dist/mcp/server.d.ts.map +1 -0
  162. package/dist/mcp/server.js +538 -0
  163. package/dist/mcp/tool-mapping.d.ts +58 -0
  164. package/dist/mcp/tool-mapping.d.ts.map +1 -0
  165. package/dist/mcp/tool-mapping.js +143 -0
  166. package/dist/mcp/tool-namespace.d.ts +40 -0
  167. package/dist/mcp/tool-namespace.d.ts.map +1 -0
  168. package/dist/mcp/tool-namespace.js +65 -0
  169. package/dist/native-scheme.d.ts +59 -0
  170. package/dist/native-scheme.d.ts.map +1 -0
  171. package/dist/native-scheme.js +465 -0
  172. package/dist/output.d.ts +28 -0
  173. package/dist/output.d.ts.map +1 -0
  174. package/dist/output.js +342 -0
  175. package/dist/package-version.d.ts +30 -0
  176. package/dist/package-version.d.ts.map +1 -0
  177. package/dist/package-version.js +47 -0
  178. package/dist/qr-terminal.d.ts +13 -0
  179. package/dist/qr-terminal.d.ts.map +1 -0
  180. package/dist/qr-terminal.js +45 -0
  181. package/dist/rpc/client.d.ts +137 -0
  182. package/dist/rpc/client.d.ts.map +1 -0
  183. package/dist/rpc/client.js +819 -0
  184. package/dist/scheme.d.ts +181 -0
  185. package/dist/scheme.d.ts.map +1 -0
  186. package/dist/scheme.js +321 -0
  187. package/dist/spki-pin.d.ts +3 -0
  188. package/dist/spki-pin.d.ts.map +1 -0
  189. package/dist/spki-pin.js +14 -0
  190. package/package.json +65 -0
@@ -0,0 +1,35 @@
1
+ import type { CliResult } from "./result-types.js";
2
+ import { type RenderOptions } from "../output.js";
3
+ import { type Clock, type CliIoWriters } from "./types.js";
4
+ /**
5
+ * Long-lived command result shape shared by any CLI command that keeps a process alive
6
+ * until completion/cancellation (e.g. a foreground daemon run). Not tied to any specific
7
+ * command's data type.
8
+ */
9
+ type HostedCommandResult = {
10
+ result: CliResult<unknown>;
11
+ completion: Promise<void>;
12
+ stop: () => void;
13
+ };
14
+ /**
15
+ * Minimal reporter contract for {@link executeHostedCommand}: an optional live-rendering
16
+ * reporter that receives lifecycle events and must be disposed once the hosted command
17
+ * completes. `kind: "plain"` reporters render their own bootstrap output instead of the
18
+ * default `renderResult` output.
19
+ */
20
+ export type HostedCommandReporter = {
21
+ kind: "interactive" | "plain";
22
+ onEvent: (event: unknown) => void | Promise<void>;
23
+ dispose: () => void;
24
+ };
25
+ export declare const executeCommand: (command: string, handler: () => CliResult<unknown> | Promise<CliResult<unknown>>, options: CliIoWriters & Pick<RenderOptions, "json" | "color"> & Partial<Pick<RenderOptions, "qr" | "full">> & {
26
+ clock: Clock;
27
+ }) => Promise<number>;
28
+ export declare const executeHostedCommand: (command: string, handler: () => Promise<HostedCommandResult>, options: CliIoWriters & {
29
+ json: boolean;
30
+ color: boolean;
31
+ clock: Clock;
32
+ reporter?: HostedCommandReporter;
33
+ }) => Promise<number>;
34
+ export {};
35
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/cli/runner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAGnD,OAAO,EAAgB,KAAK,aAAa,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAqB,KAAK,KAAK,EAAE,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC;AAE9E;;;;GAIG;AACH,KAAK,mBAAmB,GAAG;IACzB,MAAM,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC;IAC9B,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAClD,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAeF,eAAO,MAAM,cAAc,GACzB,SAAS,MAAM,EACf,SAAS,MAAM,SAAS,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,EAC/D,SAAS,YAAY,GACnB,IAAI,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,GACrC,OAAO,CAAC,IAAI,CAAC,aAAa,EAAE,IAAI,GAAG,MAAM,CAAC,CAAC,GAAG;IAC5C,KAAK,EAAE,KAAK,CAAC;CACd,KACF,OAAO,CAAC,MAAM,CAkChB,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,MAAM,EACf,SAAS,MAAM,OAAO,CAAC,mBAAmB,CAAC,EAC3C,SAAS,YAAY,GAAG;IACtB,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,KAAK,CAAC;IACb,QAAQ,CAAC,EAAE,qBAAqB,CAAC;CAClC,KACA,OAAO,CAAC,MAAM,CAoFhB,CAAC"}
@@ -0,0 +1,111 @@
1
+ import { getExitCodeForError, toCliError } from "../errors.js";
2
+ import { renderResult } from "../output.js";
3
+ import { createCommandMeta } from "./types.js";
4
+ const writeRenderedOutput = (rendered, writers) => {
5
+ if (rendered.stdout) {
6
+ writers.stdout.write(rendered.stdout);
7
+ }
8
+ if (rendered.stderr) {
9
+ writers.stderr.write(rendered.stderr);
10
+ }
11
+ };
12
+ export const executeCommand = async (command, handler, options) => {
13
+ const startedAt = options.clock.now();
14
+ const renderOptions = {
15
+ command,
16
+ json: options.json,
17
+ color: options.color,
18
+ qr: options.qr,
19
+ full: options.full,
20
+ };
21
+ try {
22
+ const result = await handler();
23
+ const finishedAt = options.clock.now();
24
+ const withMeta = {
25
+ ...result,
26
+ meta: createCommandMeta(command, startedAt, finishedAt),
27
+ };
28
+ writeRenderedOutput(renderResult(withMeta, renderOptions), options);
29
+ return 0;
30
+ }
31
+ catch (error) {
32
+ const finishedAt = options.clock.now();
33
+ const cliError = toCliError(error);
34
+ const result = {
35
+ ok: false,
36
+ error: cliError,
37
+ meta: createCommandMeta(command, startedAt, finishedAt),
38
+ };
39
+ writeRenderedOutput(renderResult(result, renderOptions), options);
40
+ return getExitCodeForError(error);
41
+ }
42
+ };
43
+ export const executeHostedCommand = async (command, handler, options) => {
44
+ const startedAt = options.clock.now();
45
+ let renderedSuccess = false;
46
+ try {
47
+ const hosted = await handler();
48
+ const finishedAt = options.clock.now();
49
+ const withMeta = {
50
+ ...hosted.result,
51
+ meta: createCommandMeta(command, startedAt, finishedAt),
52
+ };
53
+ // A live reporter (e.g. `events`'s streaming NDJSON/human lines) renders its own output as it
54
+ // goes; only the absence of a reporter (or an explicit "plain" one) falls back to the default
55
+ // one-shot `renderResult` bootstrap rendering.
56
+ const liveReporter = options.reporter;
57
+ const shouldRenderBootstrap = !liveReporter || liveReporter.kind === "plain";
58
+ if (shouldRenderBootstrap) {
59
+ writeRenderedOutput(renderResult(withMeta, {
60
+ command,
61
+ json: options.json,
62
+ color: options.color,
63
+ }), options);
64
+ renderedSuccess = true;
65
+ }
66
+ let resolved = false;
67
+ const stop = () => {
68
+ if (resolved) {
69
+ return;
70
+ }
71
+ resolved = true;
72
+ hosted.stop();
73
+ };
74
+ process.once("SIGINT", stop);
75
+ process.once("SIGTERM", stop);
76
+ try {
77
+ await hosted.completion;
78
+ }
79
+ finally {
80
+ resolved = true;
81
+ process.off("SIGINT", stop);
82
+ process.off("SIGTERM", stop);
83
+ options.reporter?.dispose();
84
+ }
85
+ return 0;
86
+ }
87
+ catch (error) {
88
+ options.reporter?.dispose();
89
+ const finishedAt = options.clock.now();
90
+ const cliError = toCliError(error);
91
+ const result = {
92
+ ok: false,
93
+ error: cliError,
94
+ meta: createCommandMeta(command, startedAt, finishedAt),
95
+ };
96
+ if (renderedSuccess && options.json) {
97
+ // The single-JSON-object-on-stdout contract was already fulfilled by the bootstrap render
98
+ // above; a failure that happens later (e.g. during a long-running `completion`) must still
99
+ // be a JSON object, just on stderr instead — bare text here was v1's defect (leaked
100
+ // unparseable output onto stderr in `--json` mode).
101
+ options.stderr.write(`${JSON.stringify(result)}\n`);
102
+ return getExitCodeForError(error);
103
+ }
104
+ writeRenderedOutput(renderResult(result, {
105
+ command,
106
+ json: options.json,
107
+ color: options.color,
108
+ }), options);
109
+ return getExitCodeForError(error);
110
+ }
111
+ };
@@ -0,0 +1,20 @@
1
+ import type { CommandMeta } from "./result-types.js";
2
+ export type Clock = {
3
+ now: () => Date;
4
+ };
5
+ export declare const systemClock: Clock;
6
+ export declare const createCommandMeta: (command: string, startedAt: Date, finishedAt: Date) => CommandMeta;
7
+ export type RunCliOptions = {
8
+ stdout?: Pick<typeof process.stdout, "write" | "isTTY">;
9
+ stderr?: Pick<typeof process.stderr, "write">;
10
+ clock?: Clock;
11
+ };
12
+ export type CliIoWriters = Required<Pick<RunCliOptions, "stdout" | "stderr">>;
13
+ export type CliRenderContext = {
14
+ json: boolean;
15
+ color: boolean;
16
+ stdout: CliIoWriters["stdout"];
17
+ stderr: CliIoWriters["stderr"];
18
+ clock: Clock;
19
+ };
20
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/cli/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,MAAM,KAAK,GAAG;IAClB,GAAG,EAAE,MAAM,IAAI,CAAC;CACjB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,KAEzB,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAC5B,SAAS,MAAM,EACf,WAAW,IAAI,EACf,YAAY,IAAI,KACf,WAMF,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,OAAO,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC;IACxD,MAAM,CAAC,EAAE,IAAI,CAAC,OAAO,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,IAAI,CAAC,aAAa,EAAE,QAAQ,GAAG,QAAQ,CAAC,CAAC,CAAC;AAE9E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC/B,MAAM,EAAE,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC/B,KAAK,EAAE,KAAK,CAAC;CACd,CAAC"}
@@ -0,0 +1,10 @@
1
+ export const systemClock = {
2
+ now: () => new Date(),
3
+ };
4
+ export const createCommandMeta = (command, startedAt, finishedAt) => {
5
+ return {
6
+ command,
7
+ timestamp: finishedAt.toISOString(),
8
+ duration_ms: finishedAt.getTime() - startedAt.getTime(),
9
+ };
10
+ };
package/dist/cli.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export { createCli } from "./cli/create-cli.js";
2
+ export { runCli } from "./cli/dispatch.js";
3
+ export type { RunCliOptions } from "./cli/types.js";
4
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/cli.js ADDED
@@ -0,0 +1,2 @@
1
+ export { createCli } from "./cli/create-cli.js";
2
+ export { runCli } from "./cli/dispatch.js";
@@ -0,0 +1,126 @@
1
+ /**
2
+ * The typed client handle (issue #8) returned by {@link connect}/{@link waitForSession}: a thin
3
+ * wrapper over the same `tools.list`/`tools.call`/`events.subscribe`/`events.since` RPC the CLI and
4
+ * MCP server use (`rpc/client.ts`'s `DaemonStream`), bound to one resolved session. No new privilege
5
+ * or transport — every call is attributed `caller: "client"` for the audit log (ARCHITECTURE.md
6
+ * §12). {@link AppClient.waitForEvent}'s drain-then-live pattern mirrors the built-in
7
+ * `appduct_wait_for_event` MCP tool (`mcp/events-tool.ts`) — see that module's doc comment for
8
+ * why the notification listener has to be registered before the `events.since` drain call is sent.
9
+ */
10
+ import { type ToolDescriptor } from "@appduct/shared";
11
+ import type { DaemonStream } from "../rpc/client.js";
12
+ /** A project's own tool map — declared once, e.g. `type Tools = { sum: { args: { a: number; b:
13
+ * number }; result: { total: number } } }` — to get typed {@link AppClient.call} throughout a test
14
+ * suite. Tool names and arg/result types can't be statically known here (they're registered by the
15
+ * connected app at runtime): the default `result` is `any` so the untyped form (`connect()` with no
16
+ * generic) still lets a caller destructure a call's result without a cast, e.g. `const { total } =
17
+ * await app.call("sum", { a: 2, b: 3 })`. `AppClient` itself is deliberately unconstrained (no
18
+ * `extends Record<string, ...>`) so both `type` aliases and plain `interface`s work here — TS only
19
+ * infers an implicit index signature for the former, so a constrained generic would silently reject
20
+ * the latter. */
21
+ export type ToolMap = Record<string, {
22
+ args: Record<string, unknown>;
23
+ result: any;
24
+ }>;
25
+ type ToolArgs<TTools, K extends keyof TTools> = TTools[K] extends {
26
+ args: infer TArgs;
27
+ } ? TArgs : Record<string, unknown>;
28
+ type ToolResult<TTools, K extends keyof TTools> = TTools[K] extends {
29
+ result: infer TResult;
30
+ } ? TResult : unknown;
31
+ export type CallOptions = {
32
+ /** Forwarded to the daemon as this call's deadline, clamped server-side to [1s, 600s]. Omitted,
33
+ * the daemon falls back to the tool's own declared `timeoutMs` (`registerTool`), and to 10s for a
34
+ * tool that declares none. Either way this is NOT the call's transport timeout, which is derived
35
+ * automatically so a `tool_timeout` from the daemon always arrives before this client's own
36
+ * transport timeout would otherwise fire and misreport it as `connection_error`. */
37
+ timeoutMs?: number;
38
+ };
39
+ export type WaitForEventOptions = {
40
+ /** Defaults to 30s. */
41
+ timeoutMs?: number;
42
+ /** Extra filter over the event's payload; the event still must match `name` first. A predicate
43
+ * that throws rejects the wait with that error rather than crashing the connection. */
44
+ match?: (payload: unknown) => boolean;
45
+ /**
46
+ * Exclusive lower bound on `AppEvent.seq` (a cursor from a previous {@link AppClient.events} or
47
+ * {@link AppClient.waitForEvent} call) — skips already-retained events at/before it instead of
48
+ * resolving with an old match instantly. Omitted, the retained buffer is searched from its start,
49
+ * so a matching event that already fired before this call still resolves immediately.
50
+ */
51
+ since?: number;
52
+ };
53
+ export type EventsOptions = {
54
+ /** Exclusive lower bound on `AppEvent.seq`; omitted returns the whole retained buffer (oldest
55
+ * first, subject to `limit`). */
56
+ since?: number;
57
+ /** Caps the number of events returned (oldest-first truncation); omitted returns everything
58
+ * matching `since` up to the buffer's own retention limit. */
59
+ limit?: number;
60
+ };
61
+ export type EventsResult = {
62
+ events: AppEvent[];
63
+ /** The highest `seq` currently retained for this session (not just among the returned events) —
64
+ * pass it back as `since`/`since` on the next {@link AppClient.events}/{@link
65
+ * AppClient.waitForEvent} call to resume after it. */
66
+ cursor: number;
67
+ };
68
+ /** An app-pushed event (`postEvent(name, payload)`), narrowed from the daemon's generic
69
+ * `EventNotification` envelope to the shape a `waitForEvent`/`events` caller actually wants. */
70
+ export type AppEvent<TPayload = unknown> = {
71
+ name: string;
72
+ payload: TPayload;
73
+ /** Unix ms. */
74
+ ts: number;
75
+ sessionId: string;
76
+ alias?: string;
77
+ /** Monotonically increasing per-session cursor (ARCHITECTURE.md §5) assigned by the daemon's
78
+ * retention buffer at emit time — pass back into `since` to resume after this event. */
79
+ seq: number;
80
+ };
81
+ export type AppClient<TTools = ToolMap> = {
82
+ readonly sessionId: string;
83
+ /** `tools.list` for this session. */
84
+ tools(): Promise<ToolDescriptor[]>;
85
+ /** `tools.call`; rejects with a {@link AppductError} whose `type` preserves the wire error
86
+ * type verbatim (e.g. `"tool_timeout"`, `"policy_denied"`, `"session_suspended"`). */
87
+ call<K extends keyof TTools & string>(name: K, args: ToolArgs<TTools, K>, options?: CallOptions): Promise<ToolResult<TTools, K>>;
88
+ /** Drains `app_event`s retained in the daemon's per-session ring buffer since a cursor — the pull
89
+ * counterpart to {@link AppClient.waitForEvent}, for checking what already happened instead of
90
+ * waiting for the next one. Pass `cursor` from the result back as `since` on the next call to
91
+ * avoid re-reading events already seen. */
92
+ events(options?: EventsOptions): Promise<EventsResult>;
93
+ /**
94
+ * Waits for the next `app_event` (as pushed by the connected app's `postEvent(name, payload)`)
95
+ * matching `name`. Checks the daemon's retained buffer for an already-arrived match first, then
96
+ * falls back to a live wait — so an event emitted between "the caller decides to wait" and "the
97
+ * subscription lands" is never missed; pass `since` (a cursor from a previous {@link
98
+ * AppClient.events}/`waitForEvent` call) to skip events already handled and wait only for a new
99
+ * one, since omitting it can return an old match instantly on every call.
100
+ *
101
+ * This shares the connection's single `events.subscribe` filter (the daemon keeps one per
102
+ * connection, replaced — not merged — on each call); concurrent `waitForEvent` calls on the same
103
+ * `AppClient` all see every `app_event`, so this is safe today, but it means the connection stays
104
+ * subscribed to `app_event` for its lifetime once any `waitForEvent` has run.
105
+ */
106
+ waitForEvent<TPayload = unknown>(name: string, options?: WaitForEventOptions): Promise<AppEvent<TPayload>>;
107
+ /** Closes the underlying connection. Safe to call more than once. */
108
+ close(): void;
109
+ };
110
+ /**
111
+ * Transport timeout for one `tools.call`. With an explicit `timeoutMs` the daemon-side deadline is
112
+ * known exactly, so this is that clamped value plus slack.
113
+ *
114
+ * Without one the daemon defaults to the *tool's own* declared `timeoutMs` (issue #25), which this
115
+ * client does not know at call time and would need an extra `tools.list` round trip (racy against
116
+ * re-registration) to learn — so it falls back to the largest deadline the daemon could possibly
117
+ * enforce. That is deliberately generous: this watchdog only exists for a daemon that accepts the
118
+ * request and then never answers, since a daemon that dies or drops the socket already rejects
119
+ * every pending call immediately (`rpc/client.ts`'s `close` handler). Sizing it off the 10 s
120
+ * default instead would make this client the thing that fails a long tool call, reporting a
121
+ * generic transport error in place of the daemon's real one.
122
+ */
123
+ export declare const transportTimeoutForToolCall: (timeoutMs: number | undefined) => number;
124
+ export declare const makeAppClient: <TTools = ToolMap>(stream: DaemonStream, sessionId: string) => AppClient<TTools>;
125
+ export {};
126
+ //# sourceMappingURL=app-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-client.d.ts","sourceRoot":"","sources":["../../src/client/app-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAML,KAAK,cAAc,EAGpB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD;;;;;;;;iBAQiB;AACjB,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,MAAM,EAAE,GAAG,CAAA;CAAE,CAAC,CAAC;AAErF,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC,SAAS,MAAM,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,SAAS;IAAE,IAAI,EAAE,MAAM,KAAK,CAAA;CAAE,GAAG,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC1H,KAAK,UAAU,CAAC,MAAM,EAAE,CAAC,SAAS,MAAM,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,SAAS;IAAE,MAAM,EAAE,MAAM,OAAO,CAAA;CAAE,GAAG,OAAO,GAAG,OAAO,CAAC;AAElH,MAAM,MAAM,WAAW,GAAG;IACxB;;;;wFAIoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;2FACuF;IACvF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC;IACtC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG;IAC1B;qCACiC;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;kEAC8D;IAC9D,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,MAAM,EAAE,QAAQ,EAAE,CAAC;IACnB;;0DAEsD;IACtD,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;gGACgG;AAChG,MAAM,MAAM,QAAQ,CAAC,QAAQ,GAAG,OAAO,IAAI;IACzC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,QAAQ,CAAC;IAClB,eAAe;IACf,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;4FACwF;IACxF,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEF,MAAM,MAAM,SAAS,CAAC,MAAM,GAAG,OAAO,IAAI;IACxC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,qCAAqC;IACrC,KAAK,IAAI,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAEnC;0FACsF;IACtF,IAAI,CAAC,CAAC,SAAS,MAAM,MAAM,GAAG,MAAM,EAClC,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,EACzB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC;IAElC;;;+CAG2C;IAC3C,MAAM,CAAC,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;IAEvD;;;;;;;;;;;;OAYG;IACH,YAAY,CAAC,QAAQ,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,mBAAmB,GAAG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAE3G,qEAAqE;IACrE,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAWF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,2BAA2B,GAAI,WAAW,MAAM,GAAG,SAAS,KAAG,MAO3E,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,GAAG,OAAO,EAAE,QAAQ,YAAY,EAAE,WAAW,MAAM,KAAG,SAAS,CAAC,MAAM,CAiNzG,CAAC"}
@@ -0,0 +1,223 @@
1
+ /**
2
+ * The typed client handle (issue #8) returned by {@link connect}/{@link waitForSession}: a thin
3
+ * wrapper over the same `tools.list`/`tools.call`/`events.subscribe`/`events.since` RPC the CLI and
4
+ * MCP server use (`rpc/client.ts`'s `DaemonStream`), bound to one resolved session. No new privilege
5
+ * or transport — every call is attributed `caller: "client"` for the audit log (ARCHITECTURE.md
6
+ * §12). {@link AppClient.waitForEvent}'s drain-then-live pattern mirrors the built-in
7
+ * `appduct_wait_for_event` MCP tool (`mcp/events-tool.ts`) — see that module's doc comment for
8
+ * why the notification listener has to be registered before the `events.since` drain call is sent.
9
+ */
10
+ import { clampToolTimeoutMs, MAX_TOOL_TIMEOUT_MS, RPC_METHODS, } from "@appduct/shared";
11
+ import { AppductError, toAppductError } from "./errors.js";
12
+ const DEFAULT_WAIT_FOR_EVENT_TIMEOUT_MS = 30_000;
13
+ /** Extra headroom so the daemon's own `tool_timeout` always wins the race against this client's
14
+ * transport timeout, even accounting for RPC round-trip and event-loop scheduling delay. Kept
15
+ * local because it is a property of this transport, not of the protocol; the *bounds* it is added
16
+ * to come from `@appduct/shared`, so this client and the daemon cannot disagree about the
17
+ * deadline itself. */
18
+ const CALL_TRANSPORT_TIMEOUT_SLACK_MS = 5_000;
19
+ /**
20
+ * Transport timeout for one `tools.call`. With an explicit `timeoutMs` the daemon-side deadline is
21
+ * known exactly, so this is that clamped value plus slack.
22
+ *
23
+ * Without one the daemon defaults to the *tool's own* declared `timeoutMs` (issue #25), which this
24
+ * client does not know at call time and would need an extra `tools.list` round trip (racy against
25
+ * re-registration) to learn — so it falls back to the largest deadline the daemon could possibly
26
+ * enforce. That is deliberately generous: this watchdog only exists for a daemon that accepts the
27
+ * request and then never answers, since a daemon that dies or drops the socket already rejects
28
+ * every pending call immediately (`rpc/client.ts`'s `close` handler). Sizing it off the 10 s
29
+ * default instead would make this client the thing that fails a long tool call, reporting a
30
+ * generic transport error in place of the daemon's real one.
31
+ */
32
+ export const transportTimeoutForToolCall = (timeoutMs) => {
33
+ const clamped = timeoutMs === undefined || !Number.isFinite(timeoutMs)
34
+ ? MAX_TOOL_TIMEOUT_MS
35
+ : clampToolTimeoutMs(timeoutMs);
36
+ return clamped + CALL_TRANSPORT_TIMEOUT_SLACK_MS;
37
+ };
38
+ export const makeAppClient = (stream, sessionId) => {
39
+ const client = {
40
+ sessionId,
41
+ tools: async () => {
42
+ try {
43
+ return await stream.call(RPC_METHODS.toolsList, { selector: sessionId });
44
+ }
45
+ catch (error) {
46
+ throw toAppductError(error);
47
+ }
48
+ },
49
+ call: async (name, args, options) => {
50
+ try {
51
+ const result = await stream.call(RPC_METHODS.toolsCall, {
52
+ selector: sessionId,
53
+ name,
54
+ args,
55
+ timeoutMs: options?.timeoutMs,
56
+ caller: "client",
57
+ }, transportTimeoutForToolCall(options?.timeoutMs));
58
+ return result.result;
59
+ }
60
+ catch (error) {
61
+ throw toAppductError(error);
62
+ }
63
+ },
64
+ events: async (options = {}) => {
65
+ try {
66
+ const result = await stream.call(RPC_METHODS.eventsSince, {
67
+ selector: sessionId,
68
+ since: options.since,
69
+ limit: options.limit,
70
+ kinds: ["app_event"],
71
+ });
72
+ return {
73
+ events: result.events
74
+ .map((event) => appEventFrom(event, sessionId))
75
+ .filter((event) => event !== undefined),
76
+ cursor: result.cursor,
77
+ };
78
+ }
79
+ catch (error) {
80
+ throw toAppductError(error);
81
+ }
82
+ },
83
+ waitForEvent: (name, options = {}) => {
84
+ const timeoutMs = options.timeoutMs ?? DEFAULT_WAIT_FOR_EVENT_TIMEOUT_MS;
85
+ const toMatch = (event) => {
86
+ const appEvent = appEventFrom(event, sessionId);
87
+ if (!appEvent || appEvent.name !== name) {
88
+ return undefined;
89
+ }
90
+ if (options.match && !options.match(appEvent.payload)) {
91
+ return undefined;
92
+ }
93
+ return appEvent;
94
+ };
95
+ return new Promise((resolve, reject) => {
96
+ let settled = false;
97
+ const settle = (fn) => {
98
+ if (settled) {
99
+ return;
100
+ }
101
+ settled = true;
102
+ clearTimeout(timer);
103
+ unsubscribeClose();
104
+ liveHandler = null;
105
+ fn();
106
+ };
107
+ const timer = setTimeout(() => {
108
+ settle(() => reject(new AppductError("timeout", `Timed out after ${timeoutMs}ms waiting for event "${name}".`)));
109
+ }, timeoutMs);
110
+ // Registered before `events.since` is even sent (not merely before it resolves): the
111
+ // daemon's response to that call and a `notify()` for a brand-new event can arrive in the
112
+ // same socket chunk, and a listener added only after awaiting that response could miss a
113
+ // notification from that same chunk. Buffers into `earlyEvents` until the drain below has
114
+ // merged its own backlog and switched this to `liveHandler`.
115
+ let liveHandler = null;
116
+ const earlyEvents = [];
117
+ const unsubscribeNotification = stream.onNotification((payload) => {
118
+ const event = payload;
119
+ if (liveHandler) {
120
+ liveHandler(event);
121
+ }
122
+ else {
123
+ earlyEvents.push(event);
124
+ }
125
+ });
126
+ let unsubscribeClose = () => { };
127
+ const fail = (error) => {
128
+ settle(() => reject(toAppductError(error)));
129
+ unsubscribeNotification();
130
+ };
131
+ (async () => {
132
+ await stream.call(RPC_METHODS.eventsSubscribe, { sessionSelector: sessionId, kinds: ["app_event"] });
133
+ const sinceResult = await stream.call(RPC_METHODS.eventsSince, {
134
+ selector: sessionId,
135
+ since: options.since,
136
+ kinds: ["app_event"],
137
+ });
138
+ // Merge the retained backlog with whatever arrived on the live channel while the two
139
+ // calls above were in flight, deduped by `seq` — the same event can legitimately show up
140
+ // in both (the daemon buffers before it fans out). Everything from here to `liveHandler =
141
+ // …` below is synchronous — no `await` — so nothing can arrive on the socket and be missed
142
+ // in the gap.
143
+ const seenSeqs = new Set();
144
+ const backlog = [];
145
+ for (const event of [...sinceResult.events, ...earlyEvents]) {
146
+ if (event.sessionId === sessionId && !seenSeqs.has(event.seq)) {
147
+ seenSeqs.add(event.seq);
148
+ backlog.push(event);
149
+ }
150
+ }
151
+ backlog.sort((a, b) => a.seq - b.seq);
152
+ for (const event of backlog) {
153
+ try {
154
+ const matched = toMatch(event);
155
+ if (matched) {
156
+ settle(() => resolve(matched));
157
+ unsubscribeNotification();
158
+ return;
159
+ }
160
+ }
161
+ catch (error) {
162
+ fail(error);
163
+ return;
164
+ }
165
+ }
166
+ // Nothing matched yet: resume live from the last event actually considered, or — if
167
+ // nothing was retained/arrived at all — `events.since`'s own cursor, which already
168
+ // reflects the session's true high-water mark even when the `kinds` filter matched
169
+ // nothing.
170
+ const highestConsideredSeq = backlog.length > 0 ? backlog[backlog.length - 1].seq : sinceResult.cursor;
171
+ unsubscribeClose = stream.onClose(() => {
172
+ settle(() => reject(new AppductError("connection_error", `The connection to the Appduct daemon closed while waiting for event "${name}".`)));
173
+ unsubscribeNotification();
174
+ });
175
+ // From here on, every notification goes straight to this handler instead of
176
+ // `earlyEvents` — assigned synchronously (no `await` since the backlog scan above), so
177
+ // nothing is missed.
178
+ liveHandler = (event) => {
179
+ if (settled) {
180
+ return;
181
+ }
182
+ if (event.sessionId === sessionId && event.seq <= highestConsideredSeq) {
183
+ return;
184
+ }
185
+ try {
186
+ const matched = toMatch(event);
187
+ if (matched) {
188
+ settle(() => resolve(matched));
189
+ unsubscribeNotification();
190
+ }
191
+ }
192
+ catch (error) {
193
+ fail(error);
194
+ }
195
+ };
196
+ })().catch((error) => {
197
+ fail(error);
198
+ });
199
+ });
200
+ },
201
+ close: () => {
202
+ stream.close();
203
+ },
204
+ };
205
+ return client;
206
+ };
207
+ const appEventFrom = (event, sessionId) => {
208
+ if (event.kind !== "app_event" || event.sessionId !== sessionId) {
209
+ return undefined;
210
+ }
211
+ const data = event.data;
212
+ if (typeof data.name !== "string") {
213
+ return undefined;
214
+ }
215
+ return {
216
+ name: data.name,
217
+ payload: data.payload,
218
+ ts: event.ts,
219
+ sessionId: event.sessionId,
220
+ alias: event.alias,
221
+ seq: event.seq,
222
+ };
223
+ };
@@ -0,0 +1,48 @@
1
+ import { type ExecFn, type OpenTarget } from "../cli/open-target.js";
2
+ import { type MintLinkResult } from "../link.js";
3
+ import { type SpawnFn } from "../rpc/client.js";
4
+ import { type AppClient, type ToolMap } from "./app-client.js";
5
+ export type LinkOptions = {
6
+ stateDir?: string;
7
+ spawn?: SpawnFn;
8
+ /** Auto-spawn a daemon on a missing connection. Defaults to `true`. */
9
+ autoSpawn?: boolean;
10
+ ttlSeconds?: number;
11
+ /** Delivers the link directly to a booted Android emulator/device or iOS simulator instead of
12
+ * just minting it (the CI/agent path — no human needed to scan a QR). */
13
+ target?: OpenTarget;
14
+ /** `--device` equivalent: an adb serial, a simulator udid, or a paired-device udid. */
15
+ device?: string;
16
+ /** `--bundle-id` equivalent; only valid with `target: "ios-device"`, where it overrides
17
+ * `config.json`'s `iosBundleId`. */
18
+ bundleId?: string;
19
+ /** `--relaunch` equivalent; only valid with `target: "ios-device"`. */
20
+ relaunch?: boolean;
21
+ /** Highest-precedence scheme source, ahead of `APPDUCT_SCHEME`, a project
22
+ * `.appduct/config.json`, the state dir's `config.json` and `app.json` (see `scheme.ts`). */
23
+ scheme?: string;
24
+ /** Where scheme discovery starts; defaults to `process.cwd()`. */
25
+ cwd?: string;
26
+ exec?: ExecFn;
27
+ /** The environment handed to `adb`/`simctl`, *not* the one `APPDUCT_SCHEME` is read from
28
+ * (see {@link schemeEnv}) — narrowing this must not change scheme resolution. */
29
+ env?: NodeJS.ProcessEnv;
30
+ /** The environment `APPDUCT_SCHEME` is read from; defaults to `process.env`. */
31
+ schemeEnv?: NodeJS.ProcessEnv;
32
+ };
33
+ export type LinkResult = MintLinkResult;
34
+ /** Mints a session link via `link.create` and composes the deep link. With `target` set, delivers
35
+ * it directly to a booted emulator/simulator instead of leaving delivery to the caller. */
36
+ export declare const link: (options?: LinkOptions) => Promise<LinkResult>;
37
+ export type WaitForSessionOptions = {
38
+ stateDir?: string;
39
+ spawn?: SpawnFn;
40
+ /** Auto-spawn a daemon on a missing connection. Defaults to `true`. */
41
+ autoSpawn?: boolean;
42
+ /** Defaults to 120s. */
43
+ timeoutMs?: number;
44
+ };
45
+ /** Waits for `sessionId` (from {@link link}) to be claimed by a device, then returns a connected
46
+ * {@link AppClient} for it — resolves immediately if it's already claimed. */
47
+ export declare const waitForSession: <TTools = ToolMap>(sessionId: string, options?: WaitForSessionOptions) => Promise<AppClient<TTools>>;
48
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../src/client/bootstrap.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,KAAK,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAErE,OAAO,EAAY,KAAK,cAAc,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAuD,KAAK,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACrG,OAAO,EAAiB,KAAK,SAAS,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAK9E,MAAM,MAAM,WAAW,GAAG;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;6EACyE;IACzE,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB,uFAAuF;IACvF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;wCACoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uEAAuE;IACvE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;iGAC6F;IAC7F,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;qFACiF;IACjF,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,gFAAgF;IAChF,SAAS,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,cAAc,CAAC;AAExC;2FAC2F;AAC3F,eAAO,MAAM,IAAI,GAAU,UAAS,WAAgB,KAAG,OAAO,CAAC,UAAU,CAoBxE,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,wBAAwB;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;8EAC8E;AAC9E,eAAO,MAAM,cAAc,GAAU,MAAM,GAAG,OAAO,EACnD,WAAW,MAAM,EACjB,UAAS,qBAA0B,KAClC,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CA0F3B,CAAC"}