@buoy-gg/agent-core 7.0.40 → 7.0.42

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