@buoy-gg/agent-core 7.0.33

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 (138) hide show
  1. package/LICENSE +58 -0
  2. package/README.md +42 -0
  3. package/lib/commonjs/blocks/receipts.js +702 -0
  4. package/lib/commonjs/blocks/receipts.js.map +1 -0
  5. package/lib/commonjs/blocks/types.js +119 -0
  6. package/lib/commonjs/blocks/types.js.map +1 -0
  7. package/lib/commonjs/blocks/uiTool.js +994 -0
  8. package/lib/commonjs/blocks/uiTool.js.map +1 -0
  9. package/lib/commonjs/catalog/catalog.g.js +4044 -0
  10. package/lib/commonjs/catalog/catalog.g.js.map +1 -0
  11. package/lib/commonjs/catalog/catalog.source.json +4956 -0
  12. package/lib/commonjs/catalog/snapshotReads.js +256 -0
  13. package/lib/commonjs/catalog/snapshotReads.js.map +1 -0
  14. package/lib/commonjs/catalog/toProviderTools.js +107 -0
  15. package/lib/commonjs/catalog/toProviderTools.js.map +1 -0
  16. package/lib/commonjs/catalog/validateParams.js +129 -0
  17. package/lib/commonjs/catalog/validateParams.js.map +1 -0
  18. package/lib/commonjs/context/buildContextPack.js +141 -0
  19. package/lib/commonjs/context/buildContextPack.js.map +1 -0
  20. package/lib/commonjs/effects/ledger.js +229 -0
  21. package/lib/commonjs/effects/ledger.js.map +1 -0
  22. package/lib/commonjs/engine/effectFor.js +95 -0
  23. package/lib/commonjs/engine/effectFor.js.map +1 -0
  24. package/lib/commonjs/engine/runAgentTurn.js +667 -0
  25. package/lib/commonjs/engine/runAgentTurn.js.map +1 -0
  26. package/lib/commonjs/engine/systemPrompt.js +86 -0
  27. package/lib/commonjs/engine/systemPrompt.js.map +1 -0
  28. package/lib/commonjs/index.js +288 -0
  29. package/lib/commonjs/index.js.map +1 -0
  30. package/lib/commonjs/package.json +1 -0
  31. package/lib/commonjs/policy/labels.js +303 -0
  32. package/lib/commonjs/policy/labels.js.map +1 -0
  33. package/lib/commonjs/policy/policy.js +143 -0
  34. package/lib/commonjs/policy/policy.js.map +1 -0
  35. package/lib/commonjs/policy/redact.js +135 -0
  36. package/lib/commonjs/policy/redact.js.map +1 -0
  37. package/lib/commonjs/providers/anthropic.js +272 -0
  38. package/lib/commonjs/providers/anthropic.js.map +1 -0
  39. package/lib/commonjs/providers/openai.js +193 -0
  40. package/lib/commonjs/providers/openai.js.map +1 -0
  41. package/lib/commonjs/providers/sse.js +104 -0
  42. package/lib/commonjs/providers/sse.js.map +1 -0
  43. package/lib/commonjs/providers/types.js +6 -0
  44. package/lib/commonjs/providers/types.js.map +1 -0
  45. package/lib/commonjs/session.js +173 -0
  46. package/lib/commonjs/session.js.map +1 -0
  47. package/lib/commonjs/types.js +2 -0
  48. package/lib/commonjs/types.js.map +1 -0
  49. package/lib/module/blocks/receipts.js +696 -0
  50. package/lib/module/blocks/receipts.js.map +1 -0
  51. package/lib/module/blocks/types.js +113 -0
  52. package/lib/module/blocks/types.js.map +1 -0
  53. package/lib/module/blocks/uiTool.js +987 -0
  54. package/lib/module/blocks/uiTool.js.map +1 -0
  55. package/lib/module/catalog/catalog.g.js +4040 -0
  56. package/lib/module/catalog/catalog.g.js.map +1 -0
  57. package/lib/module/catalog/catalog.source.json +4956 -0
  58. package/lib/module/catalog/snapshotReads.js +252 -0
  59. package/lib/module/catalog/snapshotReads.js.map +1 -0
  60. package/lib/module/catalog/toProviderTools.js +101 -0
  61. package/lib/module/catalog/toProviderTools.js.map +1 -0
  62. package/lib/module/catalog/validateParams.js +124 -0
  63. package/lib/module/catalog/validateParams.js.map +1 -0
  64. package/lib/module/context/buildContextPack.js +138 -0
  65. package/lib/module/context/buildContextPack.js.map +1 -0
  66. package/lib/module/effects/ledger.js +223 -0
  67. package/lib/module/effects/ledger.js.map +1 -0
  68. package/lib/module/engine/effectFor.js +91 -0
  69. package/lib/module/engine/effectFor.js.map +1 -0
  70. package/lib/module/engine/runAgentTurn.js +663 -0
  71. package/lib/module/engine/runAgentTurn.js.map +1 -0
  72. package/lib/module/engine/systemPrompt.js +82 -0
  73. package/lib/module/engine/systemPrompt.js.map +1 -0
  74. package/lib/module/index.js +30 -0
  75. package/lib/module/index.js.map +1 -0
  76. package/lib/module/policy/labels.js +296 -0
  77. package/lib/module/policy/labels.js.map +1 -0
  78. package/lib/module/policy/policy.js +137 -0
  79. package/lib/module/policy/policy.js.map +1 -0
  80. package/lib/module/policy/redact.js +128 -0
  81. package/lib/module/policy/redact.js.map +1 -0
  82. package/lib/module/providers/anthropic.js +268 -0
  83. package/lib/module/providers/anthropic.js.map +1 -0
  84. package/lib/module/providers/openai.js +189 -0
  85. package/lib/module/providers/openai.js.map +1 -0
  86. package/lib/module/providers/sse.js +99 -0
  87. package/lib/module/providers/sse.js.map +1 -0
  88. package/lib/module/providers/types.js +4 -0
  89. package/lib/module/providers/types.js.map +1 -0
  90. package/lib/module/session.js +168 -0
  91. package/lib/module/session.js.map +1 -0
  92. package/lib/module/types.js +2 -0
  93. package/lib/module/types.js.map +1 -0
  94. package/lib/typescript/blocks/receipts.d.ts +32 -0
  95. package/lib/typescript/blocks/receipts.d.ts.map +1 -0
  96. package/lib/typescript/blocks/types.d.ts +576 -0
  97. package/lib/typescript/blocks/types.d.ts.map +1 -0
  98. package/lib/typescript/blocks/uiTool.d.ts +15 -0
  99. package/lib/typescript/blocks/uiTool.d.ts.map +1 -0
  100. package/lib/typescript/catalog/catalog.g.d.ts +11 -0
  101. package/lib/typescript/catalog/catalog.g.d.ts.map +1 -0
  102. package/lib/typescript/catalog/snapshotReads.d.ts +37 -0
  103. package/lib/typescript/catalog/snapshotReads.d.ts.map +1 -0
  104. package/lib/typescript/catalog/toProviderTools.d.ts +52 -0
  105. package/lib/typescript/catalog/toProviderTools.d.ts.map +1 -0
  106. package/lib/typescript/catalog/validateParams.d.ts +33 -0
  107. package/lib/typescript/catalog/validateParams.d.ts.map +1 -0
  108. package/lib/typescript/context/buildContextPack.d.ts +32 -0
  109. package/lib/typescript/context/buildContextPack.d.ts.map +1 -0
  110. package/lib/typescript/effects/ledger.d.ts +119 -0
  111. package/lib/typescript/effects/ledger.d.ts.map +1 -0
  112. package/lib/typescript/engine/effectFor.d.ts +21 -0
  113. package/lib/typescript/engine/effectFor.d.ts.map +1 -0
  114. package/lib/typescript/engine/runAgentTurn.d.ts +140 -0
  115. package/lib/typescript/engine/runAgentTurn.d.ts.map +1 -0
  116. package/lib/typescript/engine/systemPrompt.d.ts +49 -0
  117. package/lib/typescript/engine/systemPrompt.d.ts.map +1 -0
  118. package/lib/typescript/index.d.ts +29 -0
  119. package/lib/typescript/index.d.ts.map +1 -0
  120. package/lib/typescript/policy/labels.d.ts +10 -0
  121. package/lib/typescript/policy/labels.d.ts.map +1 -0
  122. package/lib/typescript/policy/policy.d.ts +106 -0
  123. package/lib/typescript/policy/policy.d.ts.map +1 -0
  124. package/lib/typescript/policy/redact.d.ts +37 -0
  125. package/lib/typescript/policy/redact.d.ts.map +1 -0
  126. package/lib/typescript/providers/anthropic.d.ts +22 -0
  127. package/lib/typescript/providers/anthropic.d.ts.map +1 -0
  128. package/lib/typescript/providers/openai.d.ts +19 -0
  129. package/lib/typescript/providers/openai.d.ts.map +1 -0
  130. package/lib/typescript/providers/sse.d.ts +18 -0
  131. package/lib/typescript/providers/sse.d.ts.map +1 -0
  132. package/lib/typescript/providers/types.d.ts +129 -0
  133. package/lib/typescript/providers/types.d.ts.map +1 -0
  134. package/lib/typescript/session.d.ts +58 -0
  135. package/lib/typescript/session.d.ts.map +1 -0
  136. package/lib/typescript/types.d.ts +119 -0
  137. package/lib/typescript/types.d.ts.map +1 -0
  138. package/package.json +58 -0
@@ -0,0 +1,702 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.projectReceipt = projectReceipt;
7
+ exports.shallowDiff = shallowDiff;
8
+ var _types = require("./types");
9
+ /**
10
+ * Receipts — blocks the engine builds from tool results, deterministically.
11
+ *
12
+ * The model never authors these, so they cannot hallucinate, and a weak model
13
+ * cannot fail to produce them. They render the SAME redacted result the model
14
+ * gets, so what the user sees and what the model reasons about are one thing.
15
+ *
16
+ * Every projector is small and honest about caps: it truncates and records
17
+ * `total` so the renderer can say "+38 more" truthfully.
18
+ */
19
+
20
+ let seq = 0;
21
+ const id = () => `rc${++seq}`;
22
+ const rec = v => v && typeof v === "object" && !Array.isArray(v) ? v : undefined;
23
+ const arr = v => Array.isArray(v) ? v : [];
24
+ const str = v => typeof v === "string" ? v : undefined;
25
+ const num = v => typeof v === "number" ? v : undefined;
26
+ function pathOf(url) {
27
+ try {
28
+ const u = new URL(url);
29
+ return u.pathname + (u.search.length > 1 ? "?…" : "");
30
+ } catch {
31
+ return url;
32
+ }
33
+ }
34
+ function requestSummary(r) {
35
+ const rid = str(r.id);
36
+ const url = str(r.url);
37
+ if (!rid || !url) return undefined;
38
+ return {
39
+ id: rid,
40
+ method: str(r.method) ?? "GET",
41
+ url,
42
+ status: num(r.status),
43
+ durationMs: num(r.durationMs),
44
+ // Both spellings: the snapshot projection says `overridden`, a raw event
45
+ // carries the `override` mark object.
46
+ mocked: r.overridden === true || r.override != null && typeof r.override === "object" || undefined
47
+ };
48
+ }
49
+
50
+ /** Shallow diff of two plain objects: top-level keys that differ. */
51
+ function shallowDiff(before, after) {
52
+ const a = rec(before) ?? {};
53
+ const b = rec(after) ?? {};
54
+ const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
55
+ const out = [];
56
+ for (const k of keys) {
57
+ if (typeof a[k] === "function" || typeof b[k] === "function") continue;
58
+ if (JSON.stringify(a[k]) !== JSON.stringify(b[k])) {
59
+ out.push({
60
+ path: k,
61
+ before: a[k],
62
+ after: b[k]
63
+ });
64
+ }
65
+ }
66
+ return out;
67
+ }
68
+
69
+ /** Group console entries by message, newest first, counting repeats. */
70
+ function groupLogs(entries) {
71
+ const map = new Map();
72
+ for (const e of entries) {
73
+ const r = rec(e);
74
+ if (!r) continue;
75
+ const message = str(r.message) ?? "";
76
+ const level = str(r.level) ?? "log";
77
+ const key = `${level}:${message}`;
78
+ const cur = map.get(key);
79
+ if (cur) cur.count += 1;else map.set(key, {
80
+ level,
81
+ message,
82
+ count: 1
83
+ });
84
+ }
85
+ return [...map.values()];
86
+ }
87
+
88
+ /** A bag-line / product heuristic: an array of objects with a name and a price/qty/image. */
89
+ function looksLikeItems(v) {
90
+ const items = arr(v).map(rec).filter(Boolean);
91
+ if (items.length < 2) return undefined;
92
+ const ok = items.every(i => str(i.name) && (i.image !== undefined || i.qty !== undefined || i.price !== undefined || i.unitPrice !== undefined));
93
+ return ok ? items : undefined;
94
+ }
95
+ function money(cents) {
96
+ const n = num(cents);
97
+ return n === undefined ? undefined : `$${(n / 100).toFixed(2)}`;
98
+ }
99
+ /**
100
+ * The receipt for one successful call, or nothing. Adding a projector is the
101
+ * whole job of making a tool's result visible — no UI change needed.
102
+ */
103
+ function projectReceipt(input) {
104
+ const {
105
+ toolId,
106
+ action,
107
+ params,
108
+ result
109
+ } = input;
110
+ const r = rec(result);
111
+ const source = input.effect === "read" ? "live" : "changed";
112
+
113
+ // ---- network --------------------------------------------------------
114
+ if (toolId === "network" && action === "getSnapshot" && r) {
115
+ const requests = arr(r.requests).map(rec).filter(Boolean).map(x => requestSummary(x)).filter(Boolean);
116
+ if (requests.length === 0) return undefined;
117
+ return {
118
+ id: id(),
119
+ kind: "requestList",
120
+ requests: requests.slice(0, _types.CAPS.listItems * 2),
121
+ total: num(r.totalCaptured) ?? requests.length,
122
+ source
123
+ };
124
+ }
125
+ if (toolId === "network" && action === "getEventBody" && r) {
126
+ const reqId = str(params.id) ?? "";
127
+ const wasMocked = r.override != null && typeof r.override === "object";
128
+ return {
129
+ id: id(),
130
+ kind: "requestCard",
131
+ request: {
132
+ id: reqId,
133
+ method: str(r.method) ?? "",
134
+ url: str(r.url) ?? reqId,
135
+ status: num(r.status),
136
+ mocked: wasMocked || undefined
137
+ },
138
+ requestBody: r.requestData ?? undefined,
139
+ responseBody: r.responseData ?? undefined,
140
+ // A body an override rule synthesized must never render as "live".
141
+ source: wasMocked ? "mocked" : source
142
+ };
143
+ }
144
+ if (toolId === "network" && (action === "upsertOverrideRule" || action === "getOverrideRuleBody") && r) {
145
+ const rule = rec(r.rule) ?? r;
146
+ const ruleId = str(rule.id);
147
+ const pattern = str(rule.urlPattern);
148
+ if (!ruleId || !pattern) return undefined;
149
+ const kind = str(rule.kind) ?? "respond";
150
+ const asked = rec(params.rule) ?? {};
151
+ return {
152
+ id: id(),
153
+ kind: "ruleCard",
154
+ rule: {
155
+ id: ruleId,
156
+ name: str(rule.name) ?? str(asked.name),
157
+ urlPattern: pattern,
158
+ methods: arr(rule.methods ?? asked.methods).map(String),
159
+ kind,
160
+ status: num(rule.status) ?? num(asked.status),
161
+ delayMs: num(rule.delayMs) ?? num(asked.delayMs),
162
+ times: num(rule.times) ?? num(asked.times),
163
+ enabled: rule.enabled !== false,
164
+ hits: num(rule.hits)
165
+ },
166
+ source: action === "upsertOverrideRule" ? "changed" : "live"
167
+ };
168
+ }
169
+ if (toolId === "network" && action === "listOverrideRules" && r) {
170
+ const rules = arr(r.rules).map(rec).filter(Boolean);
171
+ if (rules.length === 0) return undefined;
172
+ return {
173
+ id: id(),
174
+ kind: "list",
175
+ title: `${rules.length} network override${rules.length === 1 ? "" : "s"}`,
176
+ items: rules.slice(0, _types.CAPS.listItems).map(x => ({
177
+ id: str(x.id),
178
+ title: str(x.name) ?? str(x.urlPattern) ?? "rule",
179
+ subtitle: `${arr(x.methods).join("/") || "ANY"} ${str(x.urlPattern) ?? ""} → ${str(x.kind) ?? ""}${x.status ? ` ${String(x.status)}` : ""}`,
180
+ trailing: x.enabled === false ? "off" : `on · ${num(x.hits) ?? 0} hit${num(x.hits) === 1 ? "" : "s"}`,
181
+ tone: x.enabled === false ? "muted" : "warning"
182
+ })),
183
+ total: rules.length,
184
+ source: "live"
185
+ };
186
+ }
187
+
188
+ // ---- routes ---------------------------------------------------------
189
+ if (toolId === "route-events" && action === "getSnapshot" && r) {
190
+ const routes = [...new Set(arr(r.routes).map(String))];
191
+ if (routes.length === 0) return undefined;
192
+ const current = rec(r.currentRoute);
193
+ return {
194
+ id: id(),
195
+ kind: "routeChips",
196
+ routes: routes.map(p => ({
197
+ path: p,
198
+ dynamic: /\[.+\]/.test(p)
199
+ })),
200
+ current: str(current?.path),
201
+ total: routes.length,
202
+ source: "live"
203
+ };
204
+ }
205
+ if (toolId === "route-events" && action === "navigate" && r) {
206
+ const path = str(r.navigated) ?? str(params.path);
207
+ return path ? {
208
+ id: id(),
209
+ kind: "peek",
210
+ label: `Opened ${path}`,
211
+ path
212
+ } : undefined;
213
+ }
214
+ if (toolId === "route-events" && (action === "stackGoBack" || action === "stackPopToTop")) {
215
+ return {
216
+ id: id(),
217
+ kind: "peek",
218
+ label: action === "stackPopToTop" ? "Went back to the first screen" : "Went back"
219
+ };
220
+ }
221
+
222
+ // ---- screen ---------------------------------------------------------
223
+ if (toolId === "highlight-updates" && action === "describeScreen" && r) {
224
+ const els = arr(r.elements).map(rec).filter(Boolean);
225
+ const interactive = els.filter(e => e.interactive === true && !String(str(e.testID) ?? "").startsWith("buoy-"));
226
+ if (interactive.length === 0) return undefined;
227
+ return {
228
+ id: id(),
229
+ kind: "screenElements",
230
+ elements: interactive.slice(0, _types.CAPS.chips).map(e => ({
231
+ nativeTag: num(e.nativeTag) ?? 0,
232
+ name: str(e.name) ?? "",
233
+ label: str(e.label) ?? str(e.text),
234
+ testID: str(e.testID),
235
+ interactive: true
236
+ })),
237
+ total: interactive.length,
238
+ source: "live"
239
+ };
240
+ }
241
+ if (toolId === "highlight-updates" && action === "tapElement" && r?.tapped === true) {
242
+ const m = rec(r.matched);
243
+ const what = str(m?.label) ?? str(m?.text) ?? str(m?.testID) ?? "element";
244
+ return {
245
+ id: id(),
246
+ kind: "peek",
247
+ label: `Tapped ${what}`
248
+ };
249
+ }
250
+
251
+ // ---- console --------------------------------------------------------
252
+ if (toolId === "console" && action === "getSnapshot" && r) {
253
+ const entries = arr(r.entries);
254
+ if (entries.length === 0) return undefined;
255
+ const grouped = groupLogs(entries);
256
+ return {
257
+ id: id(),
258
+ kind: "logList",
259
+ entries: grouped.slice(0, _types.CAPS.listItems * 2),
260
+ total: num(r.totalCaptured) ?? entries.length,
261
+ source: "live"
262
+ };
263
+ }
264
+
265
+ // ---- state stores ---------------------------------------------------
266
+ if (toolId === "zustand" && action === "getStoreState" && r?.found !== false) {
267
+ const state = rec(r?.currentState);
268
+ if (!state) return undefined;
269
+ const items = looksLikeItems(state.lines ?? state.items);
270
+ if (items) {
271
+ return {
272
+ id: id(),
273
+ kind: "list",
274
+ title: str(params.storeName),
275
+ items: items.slice(0, _types.CAPS.listItems).map(i => ({
276
+ id: str(i.lineId) ?? str(i.id),
277
+ title: str(i.name) ?? "",
278
+ subtitle: [str(i.sizeName), i.qty !== undefined ? `×${String(i.qty)}` : undefined].filter(Boolean).join(" · "),
279
+ trailing: money(i.unitPrice ?? i.price),
280
+ image: str(i.image)
281
+ })),
282
+ total: items.length,
283
+ source: "live"
284
+ };
285
+ }
286
+ const pairs = Object.entries(state).filter(([, v]) => typeof v !== "function").slice(0, _types.CAPS.keyValuePairs).map(([key, value]) => ({
287
+ key,
288
+ value
289
+ }));
290
+ return {
291
+ id: id(),
292
+ kind: "keyValue",
293
+ title: str(params.storeName),
294
+ pairs,
295
+ source: "live"
296
+ };
297
+ }
298
+ if (toolId === "zustand" && action === "setState" && r?.ok !== false) {
299
+ const changes = shallowDiff(rec(input.before)?.currentState ?? input.before, params.state);
300
+ if (changes.length === 0) return undefined;
301
+ return {
302
+ id: id(),
303
+ kind: "diff",
304
+ title: `${str(params.storeName) ?? "store"} — what changed`,
305
+ changes,
306
+ source: "changed"
307
+ };
308
+ }
309
+ if (toolId === "zustand" && action === "listStores" && r) {
310
+ const stores = arr(r.stores).map(rec).filter(Boolean);
311
+ if (stores.length === 0) return undefined;
312
+ return {
313
+ id: id(),
314
+ kind: "list",
315
+ title: `${stores.length} store${stores.length === 1 ? "" : "s"}`,
316
+ items: stores.slice(0, _types.CAPS.listItems * 2).map(s => ({
317
+ id: str(s.name),
318
+ title: str(s.name) ?? "",
319
+ subtitle: arr(s.keys).slice(0, 6).join(", "),
320
+ trailing: s.isPersisted ? "persisted" : undefined
321
+ })),
322
+ total: stores.length,
323
+ source: "live"
324
+ };
325
+ }
326
+ if (toolId === "redux" && action === "getState" && r?.available !== false) {
327
+ const state = rec(r?.state) ?? r;
328
+ if (!state) return undefined;
329
+ const pairs = Object.entries(state).slice(0, _types.CAPS.keyValuePairs).map(([key, value]) => ({
330
+ key,
331
+ value
332
+ }));
333
+ return {
334
+ id: id(),
335
+ kind: "keyValue",
336
+ title: "Redux state",
337
+ pairs,
338
+ source: "live"
339
+ };
340
+ }
341
+
342
+ // ---- storage --------------------------------------------------------
343
+ if (toolId === "storage" && (action === "async.getItem" || action === "mmkv.get" || action === "secure.get")) {
344
+ const key = str(params.key) ?? "";
345
+ let value = r && "value" in r ? r.value : result;
346
+ if (r?.found === false || value === null || value === undefined) return undefined;
347
+ if (typeof value === "string") {
348
+ try {
349
+ value = JSON.parse(value);
350
+ } catch {
351
+ /* plain string */
352
+ }
353
+ }
354
+ const obj = rec(value);
355
+ const items = looksLikeItems(rec(obj?.state)?.lines ?? obj?.lines ?? obj?.items);
356
+ if (items) {
357
+ return {
358
+ id: id(),
359
+ kind: "list",
360
+ title: key,
361
+ items: items.slice(0, _types.CAPS.listItems).map(i => ({
362
+ id: str(i.lineId) ?? str(i.id),
363
+ title: str(i.name) ?? "",
364
+ subtitle: [str(i.sizeName), i.qty !== undefined ? `×${String(i.qty)}` : undefined].filter(Boolean).join(" · "),
365
+ trailing: money(i.unitPrice ?? i.price),
366
+ image: str(i.image)
367
+ })),
368
+ total: items.length,
369
+ source: "live"
370
+ };
371
+ }
372
+ if (obj) {
373
+ const pairs = Object.entries(obj).slice(0, _types.CAPS.keyValuePairs).map(([k, v]) => ({
374
+ key: k,
375
+ value: v
376
+ }));
377
+ return {
378
+ id: id(),
379
+ kind: "keyValue",
380
+ title: key,
381
+ pairs,
382
+ source: "live"
383
+ };
384
+ }
385
+ return {
386
+ id: id(),
387
+ kind: "keyValue",
388
+ title: key,
389
+ pairs: [{
390
+ key: "value",
391
+ value
392
+ }],
393
+ source: "live"
394
+ };
395
+ }
396
+ if (toolId === "storage" && action === "async.getAllKeys") {
397
+ const keys = arr(result).map(String);
398
+ if (keys.length === 0) return undefined;
399
+ return {
400
+ id: id(),
401
+ kind: "list",
402
+ title: `${keys.length} stored key${keys.length === 1 ? "" : "s"}`,
403
+ items: keys.slice(0, _types.CAPS.listItems * 2).map(k => ({
404
+ id: k,
405
+ title: k,
406
+ action: {
407
+ label: "Read",
408
+ dispatch: {
409
+ toolId: "storage",
410
+ action: "async.getItem",
411
+ params: {
412
+ key: k
413
+ }
414
+ }
415
+ }
416
+ })),
417
+ total: keys.length,
418
+ source: "live"
419
+ };
420
+ }
421
+ if (toolId === "storage" && (action === "async.setItem" || action === "mmkv.set" || action === "secure.set")) {
422
+ const key = str(params.key) ?? "";
423
+ const b = rec(input.before);
424
+ const beforeVal = b?.had ? b.value : undefined;
425
+ return {
426
+ id: id(),
427
+ kind: "diff",
428
+ title: `${key} — saved`,
429
+ changes: [{
430
+ path: key,
431
+ before: beforeVal,
432
+ after: params.value
433
+ }],
434
+ source: "changed"
435
+ };
436
+ }
437
+
438
+ // ---- env ------------------------------------------------------------
439
+ if (toolId === "env" && action === "getSnapshot" && r) {
440
+ const env = rec(r.env);
441
+ if (!env || Object.keys(env).length === 0) return undefined;
442
+ const pairs = Object.entries(env).slice(0, _types.CAPS.keyValuePairs).map(([key, value]) => ({
443
+ key,
444
+ value
445
+ }));
446
+ return {
447
+ id: id(),
448
+ kind: "keyValue",
449
+ title: `Environment — ${Object.keys(env).length} var${Object.keys(env).length === 1 ? "" : "s"}`,
450
+ pairs,
451
+ source: "live"
452
+ };
453
+ }
454
+
455
+ // ---- sentry ---------------------------------------------------------
456
+ if (toolId === "sentry" && action === "getSnapshot" && r) {
457
+ const envelopes = arr(r.envelopes).map(rec).filter(Boolean);
458
+ const status = str(r.status);
459
+ if (envelopes.length === 0) {
460
+ // The status IS the answer when nothing was captured: "no client" and
461
+ // "nothing errored" are different findings and must not look alike.
462
+ if (status === "sdk-not-found" || status === "no-client") {
463
+ return {
464
+ id: id(),
465
+ kind: "notice",
466
+ tone: "warning",
467
+ text: "This app has no live Sentry client, so nothing can ever be captured here — that's different from \"nothing was sent\"."
468
+ };
469
+ }
470
+ return undefined;
471
+ }
472
+ return {
473
+ id: id(),
474
+ kind: "list",
475
+ title: `${num(r.totalCaptured) ?? envelopes.length} envelope${(num(r.totalCaptured) ?? envelopes.length) === 1 ? "" : "s"} sent to Sentry`,
476
+ items: envelopes.slice(0, _types.CAPS.listItems * 2).map(e => {
477
+ const items = arr(e.items).map(rec).filter(Boolean);
478
+ const first = items[0];
479
+ const isError = items.some(i => i.type === "event");
480
+ return {
481
+ id: e.id !== undefined ? String(e.id) : undefined,
482
+ title: str(first?.summary) ?? str(first?.type) ?? "envelope",
483
+ subtitle: items.map(i => str(i.type)).filter(Boolean).join(" · "),
484
+ trailing: str(e.origin),
485
+ tone: isError ? "danger" : undefined
486
+ };
487
+ }),
488
+ total: num(r.totalCaptured) ?? envelopes.length,
489
+ source: "live"
490
+ };
491
+ }
492
+
493
+ // ---- impersonate ----------------------------------------------------
494
+ if (toolId === "impersonate" && action === "searchUsers") {
495
+ const users = arr(result).map(rec).filter(Boolean);
496
+ if (users.length === 0) return undefined;
497
+ return {
498
+ id: id(),
499
+ kind: "list",
500
+ title: `${users.length} user${users.length === 1 ? "" : "s"} found`,
501
+ items: users.slice(0, _types.CAPS.listItems).map(u => ({
502
+ id: str(u.id),
503
+ title: str(u.displayName) ?? str(u.email) ?? str(u.id) ?? "user",
504
+ subtitle: [str(u.email), str(rec(u.metadata)?.role)].filter(Boolean).join(" · "),
505
+ image: str(u.avatarUrl),
506
+ // The tap goes through runGatedAction, so it carries the same policy,
507
+ // approval and ledger path a model call would.
508
+ action: {
509
+ label: "Impersonate",
510
+ dispatch: {
511
+ toolId: "impersonate",
512
+ action: "startImpersonation",
513
+ params: {
514
+ user: u
515
+ }
516
+ }
517
+ }
518
+ })),
519
+ total: users.length,
520
+ source: "live"
521
+ };
522
+ }
523
+ if (toolId === "impersonate" && action === "startImpersonation" && r?.ok !== false) {
524
+ const u = rec(params.user);
525
+ const who = str(u?.displayName) ?? str(u?.email) ?? str(u?.id) ?? "that user";
526
+ return {
527
+ id: id(),
528
+ kind: "notice",
529
+ tone: "warning",
530
+ text: `Now viewing the app as ${who}. Cached data was cleared so everything refetches as them — stopping clears caches again.`
531
+ };
532
+ }
533
+ if (toolId === "impersonate" && action === "stopImpersonation") {
534
+ return {
535
+ id: id(),
536
+ kind: "notice",
537
+ tone: "info",
538
+ text: "Stopped impersonating — back to the real account. Cached app data was cleared again."
539
+ };
540
+ }
541
+
542
+ // ---- scenarios ------------------------------------------------------
543
+ if (toolId === "scenarios" && action === "listScenarios" && r) {
544
+ const all = [...arr(r.code), ...arr(r.device), ...arr(r.drafts)].map(rec).filter(Boolean);
545
+ if (all.length === 0) return undefined;
546
+ return {
547
+ id: id(),
548
+ kind: "list",
549
+ title: `${all.length} scenario${all.length === 1 ? "" : "s"}`,
550
+ items: all.slice(0, _types.CAPS.listItems * 2).map(s => ({
551
+ id: str(s.id),
552
+ title: str(s.name) ?? str(s.id) ?? "scenario",
553
+ subtitle: str(s.description),
554
+ trailing: str(s.source) === "draft" ? "draft — needs accepting" : num(s.stepCount) !== undefined ? `${String(num(s.stepCount))} step${num(s.stepCount) === 1 ? "" : "s"}` : undefined,
555
+ tone: str(s.source) === "draft" ? "muted" : undefined
556
+ })),
557
+ total: all.length,
558
+ source: "live"
559
+ };
560
+ }
561
+ if (toolId === "scenarios" && action === "run" && r) {
562
+ if (r.ok === false) {
563
+ const errs = arr(r.preflightErrors).map(String).join("; ");
564
+ return {
565
+ id: id(),
566
+ kind: "notice",
567
+ tone: "warning",
568
+ text: `The scenario did not run — pre-flight failed${errs ? `: ${errs}` : ""}. Nothing was applied.`
569
+ };
570
+ }
571
+ const steps = arr(r.steps).map(rec).filter(Boolean);
572
+ if (steps.length === 0) return undefined;
573
+ return {
574
+ id: id(),
575
+ kind: "steps",
576
+ title: `Ran ${str(r.name) ?? "the scenario"}`,
577
+ steps: steps.slice(0, _types.CAPS.listItems * 2).map(s => ({
578
+ text: str(s.label) ?? "step",
579
+ state: s.skipped === true ? "todo" : s.ok === false ? "failed" : "done"
580
+ }))
581
+ };
582
+ }
583
+
584
+ // ---- time machine ---------------------------------------------------
585
+ if (toolId === "time-machine" && action === "list" && r) {
586
+ const snaps = arr(r.snapshots).map(rec).filter(Boolean);
587
+ if (snaps.length === 0) return undefined;
588
+ return {
589
+ id: id(),
590
+ kind: "list",
591
+ title: `${snaps.length} restore point${snaps.length === 1 ? "" : "s"}`,
592
+ items: snaps.slice(0, _types.CAPS.listItems * 2).map(s => ({
593
+ id: str(s.id),
594
+ title: str(s.name) ?? str(s.id) ?? "snapshot",
595
+ subtitle: str(rec(s.route)?.pathname),
596
+ trailing: s.baseline === true ? "baseline" : undefined
597
+ })),
598
+ total: snaps.length,
599
+ source: "live"
600
+ };
601
+ }
602
+ if (toolId === "time-machine" && action === "capture" && r) {
603
+ return {
604
+ id: id(),
605
+ kind: "notice",
606
+ tone: "info",
607
+ text: `Saved a restore point${typeof params.name === "string" ? ` — "${params.name}"` : ""}. The app can be brought back to this exact state any time.`
608
+ };
609
+ }
610
+ if (toolId === "time-machine" && action === "restore" && r) {
611
+ return {
612
+ id: id(),
613
+ kind: "notice",
614
+ tone: "warning",
615
+ text: "Restored the snapshot — the app's state just jumped back. What's on screen now reflects the restore point, not what happened since."
616
+ };
617
+ }
618
+
619
+ // ---- jotai ----------------------------------------------------------
620
+ if (toolId === "jotai" && action === "listAtoms" && r) {
621
+ const atoms = arr(r.atoms).map(rec).filter(Boolean);
622
+ if (atoms.length === 0) return undefined;
623
+ return {
624
+ id: id(),
625
+ kind: "list",
626
+ title: `${num(r.total) ?? atoms.length} atom${(num(r.total) ?? atoms.length) === 1 ? "" : "s"}`,
627
+ items: atoms.slice(0, _types.CAPS.listItems * 2).map(a => ({
628
+ id: str(a.label),
629
+ title: str(a.label) ?? "atom",
630
+ subtitle: a.writable === true ? "writable" : "read-only (derived)",
631
+ trailing: num(a.changes) !== undefined ? `${String(num(a.changes))} change${num(a.changes) === 1 ? "" : "s"}` : undefined
632
+ })),
633
+ total: num(r.total) ?? atoms.length,
634
+ source: "live"
635
+ };
636
+ }
637
+
638
+ // ---- images ---------------------------------------------------------
639
+ if (toolId === "images" && action === "list" && r) {
640
+ const records = arr(r.records).map(rec).filter(Boolean);
641
+ const images = records.map(x => ({
642
+ url: str(x.uri) ?? "",
643
+ alt: str(x.uri)?.split("/").pop() ?? "image",
644
+ caption: x.ms !== undefined ? `${String(x.ms)} ms · ${str(x.cache) ?? ""}` : undefined
645
+ })).filter(i => i.url);
646
+ if (images.length === 0) return undefined;
647
+ return {
648
+ id: id(),
649
+ kind: "imageGrid",
650
+ title: "Images the app has loaded",
651
+ images: images.slice(0, _types.CAPS.gridMax),
652
+ total: num(r.total) ?? images.length,
653
+ source: "live"
654
+ };
655
+ }
656
+
657
+ // ---- react-query ----------------------------------------------------
658
+ if (toolId === "query" && action === "listQueries" && r) {
659
+ const qs = arr(r.queries).map(rec).filter(Boolean);
660
+ if (qs.length === 0) return undefined;
661
+ return {
662
+ id: id(),
663
+ kind: "list",
664
+ title: `${qs.length} cached quer${qs.length === 1 ? "y" : "ies"}`,
665
+ items: qs.slice(0, _types.CAPS.listItems * 2).map(q => {
666
+ const key = arr(q.queryKey).filter(k => typeof k === "string").join(" › ") || str(q.queryHash) || "query";
667
+ const stale = q.isStale === true;
668
+ return {
669
+ id: str(q.queryHash),
670
+ title: key,
671
+ subtitle: `${str(q.status) ?? ""}${q.fetchStatus && q.fetchStatus !== "idle" ? ` · ${String(q.fetchStatus)}` : ""}`,
672
+ trailing: stale ? "stale" : "fresh",
673
+ tone: stale ? "warning" : "accent"
674
+ };
675
+ }),
676
+ total: qs.length,
677
+ source: "live"
678
+ };
679
+ }
680
+
681
+ // ---- render measurement → chart --------------------------------------
682
+ if (toolId === "highlight-updates" && action === "endMeasurement" && r) {
683
+ const comps = arr(r.components ?? r.renders).map(rec).filter(Boolean);
684
+ const bars = comps.map(c => ({
685
+ label: str(c.name) ?? str(c.componentName) ?? "?",
686
+ value: num(c.renders) ?? num(c.count) ?? 0
687
+ })).filter(b => b.value > 0).sort((a, b) => b.value - a.value).slice(0, _types.CAPS.chartBars);
688
+ if (bars.length === 0) return undefined;
689
+ return {
690
+ id: id(),
691
+ kind: "chart",
692
+ title: "Renders during the measurement",
693
+ bars: bars.map(b => ({
694
+ ...b,
695
+ unit: "renders"
696
+ })),
697
+ source: "live"
698
+ };
699
+ }
700
+ return undefined;
701
+ }
702
+ //# sourceMappingURL=receipts.js.map