appduct 0.10.0 → 0.11.1

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 (230) hide show
  1. package/README.md +122 -52
  2. package/dist/artifact-inspect.d.ts +0 -1
  3. package/dist/bin.d.ts +0 -1
  4. package/dist/bin.js +1250 -2
  5. package/dist/cli/command-options.d.ts +8 -1
  6. package/dist/cli/create-cli.d.ts +0 -1
  7. package/dist/cli/dispatch.d.ts +10 -1
  8. package/dist/cli/envelope.d.ts +19 -0
  9. package/dist/cli/global-flags.d.ts +30 -0
  10. package/dist/cli/open-target.d.ts +25 -8
  11. package/dist/cli/result-types.d.ts +31 -5
  12. package/dist/cli/router.d.ts +78 -0
  13. package/dist/cli/routes/daemon/index.d.ts +9 -0
  14. package/dist/cli/routes/daemon/index.js +848 -0
  15. package/dist/cli/routes/daemon/run.d.ts +3 -0
  16. package/dist/cli/routes/daemon/run.js +3246 -0
  17. package/dist/cli/routes/daemon/start.d.ts +3 -0
  18. package/dist/cli/routes/daemon/start.js +1677 -0
  19. package/dist/cli/routes/daemon/status.d.ts +4 -0
  20. package/dist/cli/routes/daemon/status.js +1685 -0
  21. package/dist/cli/routes/daemon/stop.d.ts +4 -0
  22. package/dist/cli/routes/daemon/stop.js +1655 -0
  23. package/dist/cli/routes/doctor.d.ts +3 -0
  24. package/dist/cli/routes/doctor.js +1075 -0
  25. package/dist/cli/routes/events.d.ts +3 -0
  26. package/dist/cli/routes/events.js +1915 -0
  27. package/dist/cli/routes/init.d.ts +3 -0
  28. package/dist/cli/routes/init.js +1486 -0
  29. package/dist/cli/routes/invoke.d.ts +3 -0
  30. package/dist/cli/routes/invoke.js +1893 -0
  31. package/dist/cli/routes/keygen.d.ts +3 -0
  32. package/dist/cli/routes/keygen.js +928 -0
  33. package/dist/cli/routes/link.d.ts +3 -0
  34. package/dist/cli/routes/link.js +2714 -0
  35. package/dist/cli/routes/ls.d.ts +3 -0
  36. package/dist/cli/routes/ls.js +1668 -0
  37. package/dist/cli/routes/mcp.d.ts +5 -0
  38. package/dist/cli/routes/mcp.js +3929 -0
  39. package/dist/cli/routes/revoke.d.ts +3 -0
  40. package/dist/cli/routes/revoke.js +1684 -0
  41. package/dist/cli/routes/tools.d.ts +3 -0
  42. package/dist/cli/routes/tools.js +1860 -0
  43. package/dist/cli/runner.d.ts +3 -11
  44. package/dist/cli/types.d.ts +9 -6
  45. package/dist/cli/version-guard.d.ts +20 -0
  46. package/dist/cli.d.ts +0 -1
  47. package/dist/client/app-client.d.ts +4 -4
  48. package/dist/client/bootstrap.d.ts +4 -4
  49. package/dist/client/connect.d.ts +0 -1
  50. package/dist/client/errors.d.ts +0 -1
  51. package/dist/client/index.d.ts +1 -2
  52. package/dist/client/index.js +2389 -16
  53. package/dist/commands/daemon/context.d.ts +14 -0
  54. package/dist/commands/daemon/run.d.ts +11 -0
  55. package/dist/commands/daemon/start.d.ts +5 -0
  56. package/dist/commands/daemon/status.d.ts +5 -0
  57. package/dist/commands/daemon/stop.d.ts +5 -0
  58. package/dist/commands/doctor.d.ts +0 -1
  59. package/dist/commands/events.d.ts +0 -1
  60. package/dist/commands/init.d.ts +17 -4
  61. package/dist/commands/invoke.d.ts +0 -1
  62. package/dist/commands/keygen.d.ts +0 -1
  63. package/dist/commands/link.d.ts +1 -2
  64. package/dist/commands/ls.d.ts +0 -1
  65. package/dist/commands/mcp.d.ts +2 -4
  66. package/dist/commands/revoke.d.ts +0 -1
  67. package/dist/commands/tools.d.ts +19 -3
  68. package/dist/daemon/address.d.ts +0 -1
  69. package/dist/daemon/audit.d.ts +6 -11
  70. package/dist/daemon/calls.d.ts +0 -1
  71. package/dist/daemon/config.d.ts +13 -16
  72. package/dist/daemon/daemon.d.ts +0 -1
  73. package/dist/daemon/event-bus.d.ts +0 -1
  74. package/dist/daemon/links.d.ts +0 -1
  75. package/dist/daemon/listener.d.ts +0 -1
  76. package/dist/daemon/log-rotation.d.ts +0 -1
  77. package/dist/daemon/pidfile.d.ts +14 -8
  78. package/dist/daemon/policy.d.ts +0 -1
  79. package/dist/daemon/registry.d.ts +0 -1
  80. package/dist/daemon/rpc-errors.d.ts +16 -0
  81. package/dist/daemon/rpc-server.d.ts +0 -11
  82. package/dist/daemon/sessions.d.ts +0 -1
  83. package/dist/daemon/socket-probe.d.ts +0 -1
  84. package/dist/daemon/state-dir.d.ts +0 -1
  85. package/dist/daemon/timers.d.ts +0 -1
  86. package/dist/daemon/tls.d.ts +0 -1
  87. package/dist/errors.d.ts +0 -1
  88. package/dist/host-certificate.d.ts +0 -1
  89. package/dist/index.d.ts +0 -1
  90. package/dist/index.js +1307 -3
  91. package/dist/key-material.d.ts +0 -1
  92. package/dist/link.d.ts +8 -7
  93. package/dist/mcp/app-tools.d.ts +153 -0
  94. package/dist/mcp/connect-tool.d.ts +14 -8
  95. package/dist/mcp/daemon-tools.d.ts +2 -11
  96. package/dist/mcp/events-tool.d.ts +0 -1
  97. package/dist/mcp/server.d.ts +33 -14
  98. package/dist/native-scheme.d.ts +0 -1
  99. package/dist/output.d.ts +8 -11
  100. package/dist/package-root.d.ts +11 -0
  101. package/dist/package-version.d.ts +0 -1
  102. package/dist/qr-terminal.d.ts +0 -1
  103. package/dist/rpc/client.d.ts +3 -3
  104. package/dist/scheme.d.ts +60 -2
  105. package/dist/spki-pin.d.ts +0 -1
  106. package/package.json +6 -3
  107. package/dist/artifact-inspect.d.ts.map +0 -1
  108. package/dist/artifact-inspect.js +0 -334
  109. package/dist/bin.d.ts.map +0 -1
  110. package/dist/cli/command-options.d.ts.map +0 -1
  111. package/dist/cli/command-options.js +0 -95
  112. package/dist/cli/create-cli.d.ts.map +0 -1
  113. package/dist/cli/create-cli.js +0 -56
  114. package/dist/cli/dispatch.d.ts.map +0 -1
  115. package/dist/cli/dispatch.js +0 -275
  116. package/dist/cli/open-target.d.ts.map +0 -1
  117. package/dist/cli/open-target.js +0 -438
  118. package/dist/cli/result-types.d.ts.map +0 -1
  119. package/dist/cli/result-types.js +0 -6
  120. package/dist/cli/runner.d.ts.map +0 -1
  121. package/dist/cli/runner.js +0 -111
  122. package/dist/cli/types.d.ts.map +0 -1
  123. package/dist/cli/types.js +0 -10
  124. package/dist/cli.d.ts.map +0 -1
  125. package/dist/cli.js +0 -2
  126. package/dist/client/app-client.d.ts.map +0 -1
  127. package/dist/client/app-client.js +0 -223
  128. package/dist/client/bootstrap.d.ts.map +0 -1
  129. package/dist/client/bootstrap.js +0 -108
  130. package/dist/client/connect.d.ts.map +0 -1
  131. package/dist/client/connect.js +0 -38
  132. package/dist/client/errors.d.ts.map +0 -1
  133. package/dist/client/errors.js +0 -40
  134. package/dist/client/index.d.ts.map +0 -1
  135. package/dist/commands/daemon.d.ts +0 -22
  136. package/dist/commands/daemon.d.ts.map +0 -1
  137. package/dist/commands/daemon.js +0 -128
  138. package/dist/commands/doctor.d.ts.map +0 -1
  139. package/dist/commands/doctor.js +0 -42
  140. package/dist/commands/events.d.ts.map +0 -1
  141. package/dist/commands/events.js +0 -76
  142. package/dist/commands/init.d.ts.map +0 -1
  143. package/dist/commands/init.js +0 -231
  144. package/dist/commands/invoke.d.ts.map +0 -1
  145. package/dist/commands/invoke.js +0 -54
  146. package/dist/commands/keygen.d.ts.map +0 -1
  147. package/dist/commands/keygen.js +0 -46
  148. package/dist/commands/link.d.ts.map +0 -1
  149. package/dist/commands/link.js +0 -43
  150. package/dist/commands/ls.d.ts.map +0 -1
  151. package/dist/commands/ls.js +0 -7
  152. package/dist/commands/mcp.d.ts.map +0 -1
  153. package/dist/commands/mcp.js +0 -98
  154. package/dist/commands/revoke.d.ts.map +0 -1
  155. package/dist/commands/revoke.js +0 -7
  156. package/dist/commands/tools.d.ts.map +0 -1
  157. package/dist/commands/tools.js +0 -52
  158. package/dist/daemon/address.d.ts.map +0 -1
  159. package/dist/daemon/address.js +0 -71
  160. package/dist/daemon/audit.d.ts.map +0 -1
  161. package/dist/daemon/audit.js +0 -237
  162. package/dist/daemon/calls.d.ts.map +0 -1
  163. package/dist/daemon/calls.js +0 -158
  164. package/dist/daemon/config.d.ts.map +0 -1
  165. package/dist/daemon/config.js +0 -170
  166. package/dist/daemon/daemon.d.ts.map +0 -1
  167. package/dist/daemon/daemon.js +0 -560
  168. package/dist/daemon/event-bus.d.ts.map +0 -1
  169. package/dist/daemon/event-bus.js +0 -111
  170. package/dist/daemon/links.d.ts.map +0 -1
  171. package/dist/daemon/links.js +0 -118
  172. package/dist/daemon/listener.d.ts.map +0 -1
  173. package/dist/daemon/listener.js +0 -132
  174. package/dist/daemon/log-rotation.d.ts.map +0 -1
  175. package/dist/daemon/log-rotation.js +0 -136
  176. package/dist/daemon/pidfile.d.ts.map +0 -1
  177. package/dist/daemon/pidfile.js +0 -90
  178. package/dist/daemon/policy.d.ts.map +0 -1
  179. package/dist/daemon/policy.js +0 -24
  180. package/dist/daemon/registry.d.ts.map +0 -1
  181. package/dist/daemon/registry.js +0 -31
  182. package/dist/daemon/rpc-server.d.ts.map +0 -1
  183. package/dist/daemon/rpc-server.js +0 -203
  184. package/dist/daemon/sessions.d.ts.map +0 -1
  185. package/dist/daemon/sessions.js +0 -429
  186. package/dist/daemon/socket-probe.d.ts.map +0 -1
  187. package/dist/daemon/socket-probe.js +0 -28
  188. package/dist/daemon/state-dir.d.ts.map +0 -1
  189. package/dist/daemon/state-dir.js +0 -43
  190. package/dist/daemon/timers.d.ts.map +0 -1
  191. package/dist/daemon/timers.js +0 -12
  192. package/dist/daemon/tls.d.ts.map +0 -1
  193. package/dist/daemon/tls.js +0 -79
  194. package/dist/errors.d.ts.map +0 -1
  195. package/dist/errors.js +0 -162
  196. package/dist/host-certificate.d.ts.map +0 -1
  197. package/dist/host-certificate.js +0 -111
  198. package/dist/index.d.ts.map +0 -1
  199. package/dist/key-material.d.ts.map +0 -1
  200. package/dist/key-material.js +0 -42
  201. package/dist/link.d.ts.map +0 -1
  202. package/dist/link.js +0 -117
  203. package/dist/mcp/connect-tool.d.ts.map +0 -1
  204. package/dist/mcp/connect-tool.js +0 -396
  205. package/dist/mcp/daemon-tools.d.ts.map +0 -1
  206. package/dist/mcp/daemon-tools.js +0 -29
  207. package/dist/mcp/events-tool.d.ts.map +0 -1
  208. package/dist/mcp/events-tool.js +0 -322
  209. package/dist/mcp/server.d.ts.map +0 -1
  210. package/dist/mcp/server.js +0 -538
  211. package/dist/mcp/tool-mapping.d.ts +0 -58
  212. package/dist/mcp/tool-mapping.d.ts.map +0 -1
  213. package/dist/mcp/tool-mapping.js +0 -143
  214. package/dist/mcp/tool-namespace.d.ts +0 -40
  215. package/dist/mcp/tool-namespace.d.ts.map +0 -1
  216. package/dist/mcp/tool-namespace.js +0 -65
  217. package/dist/native-scheme.d.ts.map +0 -1
  218. package/dist/native-scheme.js +0 -465
  219. package/dist/output.d.ts.map +0 -1
  220. package/dist/output.js +0 -342
  221. package/dist/package-version.d.ts.map +0 -1
  222. package/dist/package-version.js +0 -47
  223. package/dist/qr-terminal.d.ts.map +0 -1
  224. package/dist/qr-terminal.js +0 -45
  225. package/dist/rpc/client.d.ts.map +0 -1
  226. package/dist/rpc/client.js +0 -819
  227. package/dist/scheme.d.ts.map +0 -1
  228. package/dist/scheme.js +0 -321
  229. package/dist/spki-pin.d.ts.map +0 -1
  230. package/dist/spki-pin.js +0 -14
@@ -1,223 +0,0 @@
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
- };
@@ -1 +0,0 @@
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"}
@@ -1,108 +0,0 @@
1
- /**
2
- * `link()`/`waitForSession()` (issue #8): the bootstrap half of the client, so a test's
3
- * `globalSetup` can pair a simulator/emulator without shelling out to `appduct link --open`.
4
- * `link()` delegates to the same `mintLink` core `commands/link.ts` uses (`../link.js`) so the
5
- * deep-link shape can't drift between the CLI and this package; `waitForSession()` mirrors
6
- * `mcp/connect-tool.ts`'s `handleWaitForSessionTool`.
7
- */
8
- import { RPC_METHODS } from "@appduct/shared";
9
- import {} from "../cli/open-target.js";
10
- import { resolveStateDir } from "../daemon/state-dir.js";
11
- import { mintLink } from "../link.js";
12
- import { openDaemonStream, DaemonRpcError } from "../rpc/client.js";
13
- import { makeAppClient } from "./app-client.js";
14
- import { AppductError, toAppductError } from "./errors.js";
15
- const DEFAULT_WAIT_FOR_SESSION_TIMEOUT_MS = 120_000;
16
- /** Mints a session link via `link.create` and composes the deep link. With `target` set, delivers
17
- * it directly to a booted emulator/simulator instead of leaving delivery to the caller. */
18
- export const link = async (options = {}) => {
19
- try {
20
- return await mintLink({
21
- stateDir: resolveStateDir(options.stateDir),
22
- spawn: options.spawn,
23
- autoSpawn: options.autoSpawn,
24
- ttlSeconds: options.ttlSeconds,
25
- target: options.target,
26
- device: options.device,
27
- bundleId: options.bundleId,
28
- relaunch: options.relaunch,
29
- scheme: options.scheme,
30
- cwd: options.cwd,
31
- exec: options.exec,
32
- env: options.env,
33
- schemeEnv: options.schemeEnv,
34
- });
35
- }
36
- catch (error) {
37
- throw toAppductError(error);
38
- }
39
- };
40
- /** Waits for `sessionId` (from {@link link}) to be claimed by a device, then returns a connected
41
- * {@link AppClient} for it — resolves immediately if it's already claimed. */
42
- export const waitForSession = async (sessionId, options = {}) => {
43
- const stateDir = resolveStateDir(options.stateDir);
44
- const timeoutMs = options.timeoutMs ?? DEFAULT_WAIT_FOR_SESSION_TIMEOUT_MS;
45
- let stream;
46
- try {
47
- stream = await openDaemonStream({ stateDir, spawn: options.spawn, autoSpawn: options.autoSpawn });
48
- }
49
- catch (error) {
50
- throw toAppductError(error);
51
- }
52
- try {
53
- // The session may already be claimed by the time this runs — resolve immediately rather than
54
- // waiting for an event that already happened.
55
- try {
56
- await stream.call(RPC_METHODS.sessionsDescribe, { selector: sessionId });
57
- return makeAppClient(stream, sessionId);
58
- }
59
- catch (error) {
60
- if (!(error instanceof DaemonRpcError) || error.data?.type !== "unknown_session") {
61
- throw error;
62
- }
63
- }
64
- await new Promise((resolve, reject) => {
65
- let settled = false;
66
- const settle = (fn) => {
67
- if (settled) {
68
- return;
69
- }
70
- settled = true;
71
- clearTimeout(timer);
72
- unsubscribeNotification();
73
- unsubscribeClose();
74
- fn();
75
- };
76
- const timer = setTimeout(() => {
77
- settle(() => reject(new AppductError("timeout", `Timed out after ${timeoutMs}ms waiting for session "${sessionId}" to be claimed.`)));
78
- }, timeoutMs);
79
- const unsubscribeClose = stream.onClose(() => {
80
- settle(() => reject(new AppductError("connection_error", `The connection to the Appduct daemon closed while waiting for session "${sessionId}" to be claimed.`)));
81
- });
82
- // Registered *before* `events.subscribe` is sent (not after awaiting it) — a
83
- // `session_claimed` notification that arrives in the same TCP chunk as the subscribe
84
- // response is dispatched synchronously within that chunk's processing, before an `await`
85
- // continuation below would get a chance to run; registering the listener first means it's
86
- // always in place in time to see it.
87
- const unsubscribeNotification = stream.onNotification((payload) => {
88
- if (settled) {
89
- return;
90
- }
91
- const event = payload;
92
- if (event.kind === "session_claimed" && event.sessionId === sessionId) {
93
- settle(resolve);
94
- }
95
- });
96
- stream
97
- .call(RPC_METHODS.eventsSubscribe, { sessionSelector: sessionId, kinds: ["session_claimed"] })
98
- .catch((error) => {
99
- settle(() => reject(toAppductError(error)));
100
- });
101
- });
102
- return makeAppClient(stream, sessionId);
103
- }
104
- catch (error) {
105
- stream.close();
106
- throw toAppductError(error);
107
- }
108
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/client/connect.ts"],"names":[],"mappings":"AAUA,OAAO,EAAuC,KAAK,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACrF,OAAO,EAAiB,KAAK,SAAS,EAAE,KAAK,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAG9E,MAAM,MAAM,cAAc,GAAG;IAC3B;mGAC+F;IAC/F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6FAA6F;IAC7F,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,uEAAuE;IACvE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B,CAAC;AAEF,kGAAkG;AAClG,eAAO,MAAM,OAAO,GAAU,MAAM,GAAG,OAAO,EAC5C,UAAS,cAAmB,KAC3B,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,CA0B3B,CAAC"}
@@ -1,38 +0,0 @@
1
- /**
2
- * `connect()` (issue #8): the entry point for a test runner that wants to drive an already-claimed
3
- * session without shelling out to the CLI. Auto-spawns the daemon (same seam `rpc/client.ts` gives
4
- * the CLI/MCP server) and resolves `selector` up front via `sessions.describe` so a bad/ambiguous
5
- * selector fails fast with a typed {@link AppductError} rather than surfacing on the first
6
- * `call()`.
7
- */
8
- import { RPC_METHODS } from "@appduct/shared";
9
- import { resolveStateDir } from "../daemon/state-dir.js";
10
- import { openDaemonStream } from "../rpc/client.js";
11
- import { makeAppClient } from "./app-client.js";
12
- import { toAppductError } from "./errors.js";
13
- /** Opens a persistent connection to the daemon and resolves `options.selector` to one session. */
14
- export const connect = async (options = {}) => {
15
- const stateDir = resolveStateDir(options.stateDir);
16
- let stream;
17
- try {
18
- stream = await openDaemonStream({
19
- stateDir,
20
- spawn: options.spawn,
21
- autoSpawn: options.autoSpawn,
22
- requestTimeoutMs: options.requestTimeoutMs,
23
- });
24
- }
25
- catch (error) {
26
- throw toAppductError(error);
27
- }
28
- try {
29
- const detail = await stream.call(RPC_METHODS.sessionsDescribe, {
30
- selector: options.selector,
31
- });
32
- return makeAppClient(stream, detail.sessionId);
33
- }
34
- catch (error) {
35
- stream.close();
36
- throw toAppductError(error);
37
- }
38
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/client/errors.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAKjD;;;;;uEAKuE;AACvE,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,kBAAkB,GAAG,SAAS,GAAG,cAAc,CAAC;AAE3F,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,gBAAgB,CAAC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,mEAAmE;IACnE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;gBAEX,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM;CAOtF;AAED;kFACkF;AAClF,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,KAAG,YAiC/C,CAAC"}
@@ -1,40 +0,0 @@
1
- import { isAppductCliError } from "../errors.js";
2
- import { DaemonRpcError, isDaemonUnreachableError } from "../rpc/client.js";
3
- export class AppductError extends Error {
4
- type;
5
- details;
6
- /** The JSON-RPC error code, when this wraps a `DaemonRpcError`. */
7
- code;
8
- constructor(type, message, details, code) {
9
- super(message);
10
- this.name = "AppductError";
11
- this.type = type;
12
- this.details = details;
13
- this.code = code;
14
- }
15
- }
16
- /** Converts any error thrown by the RPC layer into a {@link AppductError}, preserving the wire
17
- * `data.type` verbatim when present. Idempotent on an already-converted error. */
18
- export const toAppductError = (error) => {
19
- if (error instanceof AppductError) {
20
- return error;
21
- }
22
- const withCause = (result) => {
23
- result.cause = error;
24
- return result;
25
- };
26
- if (error instanceof DaemonRpcError) {
27
- const type = error.data?.type ?? "client_error";
28
- return withCause(new AppductError(type, error.message, error.data?.details, error.code));
29
- }
30
- if (isDaemonUnreachableError(error)) {
31
- return withCause(new AppductError("connection_error", error instanceof Error ? error.message : "The Appduct daemon is unreachable."));
32
- }
33
- if (isAppductCliError(error)) {
34
- return withCause(new AppductError("client_error", error.message, error.details));
35
- }
36
- if (error instanceof Error) {
37
- return withCause(new AppductError("client_error", error.message));
38
- }
39
- return new AppductError("client_error", "An unexpected error occurred.", error);
40
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACrH,OAAO,EAAE,YAAY,EAAE,KAAK,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAClE,YAAY,EACV,SAAS,EACT,QAAQ,EACR,WAAW,EACX,aAAa,EACb,YAAY,EACZ,OAAO,EACP,mBAAmB,GACpB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
@@ -1,22 +0,0 @@
1
- import type { CliResult, DaemonRunCommandData, DaemonStartCommandData, DaemonStatusCommandData, DaemonStopCommandData } from "../cli/result-types.js";
2
- import type { Clock } from "../cli/types.js";
3
- import { type SpawnFn } from "../rpc/client.js";
4
- export type DaemonCommandContext = {
5
- stateDir: string;
6
- clock?: Clock;
7
- spawn?: SpawnFn;
8
- warn?: (message: string) => void;
9
- /** Test seam: the version `daemon status` compares the daemon against; defaults to this
10
- * package's own version. */
11
- clientVersion?: string;
12
- };
13
- export type DaemonRunHostedResult = {
14
- result: CliResult<DaemonRunCommandData>;
15
- completion: Promise<void>;
16
- stop: () => void;
17
- };
18
- export declare const handleDaemonRunCommand: (context: DaemonCommandContext) => Promise<DaemonRunHostedResult>;
19
- export declare const handleDaemonStartCommand: (context: DaemonCommandContext) => Promise<CliResult<DaemonStartCommandData>>;
20
- export declare const handleDaemonStopCommand: (context: DaemonCommandContext) => Promise<CliResult<DaemonStopCommandData>>;
21
- export declare const handleDaemonStatusCommand: (context: DaemonCommandContext) => Promise<CliResult<DaemonStatusCommandData>>;
22
- //# sourceMappingURL=daemon.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,SAAS,EACT,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,qBAAqB,EACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAC;AAM7C,OAAO,EAAuD,KAAK,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAErG,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC;gCAC4B;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,SAAS,CAAC,oBAAoB,CAAC,CAAC;IACxC,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,sBAAsB,GACjC,SAAS,oBAAoB,KAC5B,OAAO,CAAC,qBAAqB,CAiC/B,CAAC;AAEF,eAAO,MAAM,wBAAwB,GACnC,SAAS,oBAAoB,KAC5B,OAAO,CAAC,SAAS,CAAC,sBAAsB,CAAC,CAiB3C,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAClC,SAAS,oBAAoB,KAC5B,OAAO,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAyB1C,CAAC;AAQF,eAAO,MAAM,yBAAyB,GACpC,SAAS,oBAAoB,KAC5B,OAAO,CAAC,SAAS,CAAC,uBAAuB,CAAC,CA2D5C,CAAC"}
@@ -1,128 +0,0 @@
1
- import { RPC_METHODS } from "@appduct/shared";
2
- import { startDaemon } from "../daemon/daemon.js";
3
- import { DaemonAlreadyRunningError, readPidFromFile } from "../daemon/pidfile.js";
4
- import { getStateDirPaths } from "../daemon/state-dir.js";
5
- import { connectionError } from "../errors.js";
6
- import { getPackageVersion } from "../package-version.js";
7
- import { callDaemon, isDaemonUnreachableError, isSameVersion } from "../rpc/client.js";
8
- export const handleDaemonRunCommand = async (context) => {
9
- let daemon;
10
- try {
11
- daemon = await startDaemon({
12
- stateDir: context.stateDir,
13
- clock: context.clock,
14
- warn: context.warn,
15
- });
16
- }
17
- catch (error) {
18
- if (error instanceof DaemonAlreadyRunningError) {
19
- throw connectionError(error.message, { pid: error.pid });
20
- }
21
- throw error;
22
- }
23
- return {
24
- result: {
25
- ok: true,
26
- data: {
27
- daemon: {
28
- pid: process.pid,
29
- state_dir: daemon.paths.root,
30
- socket_path: daemon.paths.socketPath,
31
- },
32
- },
33
- },
34
- completion: daemon.exited,
35
- stop: () => {
36
- void daemon.shutdown();
37
- },
38
- };
39
- };
40
- export const handleDaemonStartCommand = async (context) => {
41
- const status = await callDaemon(RPC_METHODS.daemonStatus, {}, { stateDir: context.stateDir, autoSpawn: true, spawn: context.spawn });
42
- return {
43
- ok: true,
44
- data: {
45
- daemon: {
46
- pid: status.pid,
47
- wss_port: status.wssPort,
48
- started_at: status.startedAt,
49
- },
50
- },
51
- };
52
- };
53
- export const handleDaemonStopCommand = async (context) => {
54
- try {
55
- await callDaemon(RPC_METHODS.daemonShutdown, {}, { stateDir: context.stateDir, autoSpawn: false });
56
- return { ok: true, data: { daemon: { ok: true, method: "rpc" } } };
57
- }
58
- catch (error) {
59
- if (!isDaemonUnreachableError(error)) {
60
- throw error;
61
- }
62
- const paths = getStateDirPaths(context.stateDir);
63
- const pid = await readPidFromFile(paths.pidFilePath);
64
- if (pid === undefined) {
65
- throw connectionError("No Appduct daemon is running.");
66
- }
67
- process.kill(pid, "SIGTERM");
68
- return { ok: true, data: { daemon: { ok: true, method: "sigterm" } } };
69
- }
70
- };
71
- /** Drops the entries whose value is `undefined`, so spreading the result adds only keys that
72
- * carry an actual answer. */
73
- const definedOnly = (fields) => {
74
- return Object.fromEntries(Object.entries(fields).filter(([, value]) => value !== undefined));
75
- };
76
- export const handleDaemonStatusCommand = async (context) => {
77
- const status = await callDaemon(RPC_METHODS.daemonStatus, {}, { stateDir: context.stateDir, autoSpawn: true, spawn: context.spawn });
78
- // The wire type declares the retention fields required, as it must for any daemon built from
79
- // this tree — but the daemon on the other end of the socket may predate them, and a running
80
- // daemon outlives the CLI upgrade that would replace it. Reading them through a partial view
81
- // keeps that possibility in the types instead of in a comment, and leaves each one `undefined`
82
- // rather than `0` when it was never reported.
83
- const retention = status.audit;
84
- const clientVersion = context.clientVersion ?? getPackageVersion();
85
- // Guarded the same way the version check guards it (`rpc/client.ts`): a `daemon.status` without
86
- // `sessions` would otherwise throw from the middle of the command that exists to diagnose a
87
- // daemon — the one command that must keep working against a daemon it does not fully understand.
88
- const sessionCount = Array.isArray(status.sessions) ? status.sessions.length : 0;
89
- const pendingLinkCount = typeof status.pendingLinks === "number" ? status.pendingLinks : 0;
90
- // Names the same cost the restart path names (`rpc/client.ts`), so the diagnosis an operator
91
- // reads here and the error they hit on the next command tell one consistent story: an unclaimed
92
- // link is destroyed by a restart just as surely as a session is.
93
- const atStake = `${sessionCount} session(s) and ${pendingLinkCount} unclaimed link(s)`;
94
- const warning = isSameVersion(status.version, clientVersion)
95
- ? undefined
96
- : `Version drift: this daemon is ${status.version} but the CLI is ${clientVersion}. ` +
97
- `Newer RPC methods will fail against it — run "appduct daemon stop" (this drops ${atStake}) ` +
98
- `and the next command will start a matching daemon, or pass "--daemon-restart" to any command to replace it in place.`;
99
- return {
100
- ok: true,
101
- data: {
102
- warning,
103
- daemon: {
104
- version: status.version,
105
- pid: status.pid,
106
- started_at: status.startedAt,
107
- wss_port: status.wssPort,
108
- pinned_keys: status.pinnedKeys,
109
- session_count: sessionCount,
110
- },
111
- policy: status.policy,
112
- audit: {
113
- path: status.audit.path,
114
- failed_writes: status.audit.failedWrites,
115
- // Spread so an unreported field is a *missing key*, not a key holding `undefined`. The two
116
- // serialize identically, but only the first is honestly shaped: a caller can ask whether
117
- // the daemon answered, and `--json` consumers see the same absence in-process as on the
118
- // wire.
119
- ...definedOnly({
120
- failed_prunes: retention.failedPrunes,
121
- retention_days: retention.retentionDays,
122
- files: retention.files,
123
- bytes: retention.bytes,
124
- }),
125
- },
126
- },
127
- };
128
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE3E,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAG5E,MAAM,MAAM,oBAAoB,GAAG;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,CAAC,EAAE,YAAY,CAAC;CACrB,CAAC;AAEF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,oBAAoB,EAC7B,UAAS,oBAAyB,KACjC,OAAO,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAyCtC,CAAC"}
@@ -1,42 +0,0 @@
1
- /**
2
- * `appduct doctor <artifact>` (docs/tasks/08-appduct-doctor.md): the release-gate replacement
3
- * for the runtime `debuggable` check removed elsewhere in opt-in hardening — see
4
- * `artifact-inspect.ts`'s doc comment for the detection strategy and why it never collapses a
5
- * missing-tool or unreadable-artifact case into "absent".
6
- *
7
- * This handler owns only the CLI-facing concerns: option validation (mutually exclusive
8
- * `--assert-present`/`--assert-absent`) and turning a failed assertion into a distinct
9
- * {@link assertionError} exit, separate from `inspectionError`'s "couldn't tell" exit. All artifact
10
- * inspection itself lives in `artifact-inspect.ts`, unit-testable without going through the CLI.
11
- */
12
- import { inspectArtifact } from "../artifact-inspect.js";
13
- import { assertionError, usageError } from "../errors.js";
14
- export const handleDoctorCommand = async (options, context = {}) => {
15
- if (!options.artifactPath) {
16
- throw usageError("Usage: appduct doctor <path-to-artifact> [--assert-present | --assert-absent]");
17
- }
18
- if (options.assertPresent && options.assertAbsent) {
19
- throw usageError("--assert-present and --assert-absent are mutually exclusive.");
20
- }
21
- const inspection = await inspectArtifact(options.artifactPath, { exec: context.exec });
22
- const data = {
23
- artifact: options.artifactPath,
24
- platform: inspection.platform,
25
- format: inspection.format,
26
- present: inspection.present,
27
- signals: inspection.signals,
28
- };
29
- if (options.assertPresent && !inspection.present) {
30
- throw assertionError(`Expected Appduct to be present in "${options.artifactPath}", but no inclusion signal was found.`, data);
31
- }
32
- if (options.assertAbsent && inspection.present) {
33
- throw assertionError(`Expected Appduct to be absent from "${options.artifactPath}", but found: ${inspection.signals.join(", ")}.`, data);
34
- }
35
- if (options.assertPresent || options.assertAbsent) {
36
- data.assertion = {
37
- expected: options.assertPresent ? "present" : "absent",
38
- holds: true,
39
- };
40
- }
41
- return { ok: true, data };
42
- };
@@ -1 +0,0 @@
1
- {"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/commands/events.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAe,KAAK,iBAAiB,EAAsD,MAAM,iBAAiB,CAAC;AAE1H,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAoB,KAAK,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAElE,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;0EACsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC5C;;sGAEkG;IAClG,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,IAAI,EAAE,MAAM,IAAI,CAAC;CAClB,CAAC;AA4BF,eAAO,MAAM,mBAAmB,GAC9B,SAAS,oBAAoB,EAC7B,SAAS,oBAAoB,KAC5B,OAAO,CAAC,kBAAkB,CAkD5B,CAAC"}