@buoy-gg/agent-core 7.0.41 → 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 (201) 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 -4556
  6. package/lib/commonjs/catalog/catalog.source.json +249 -0
  7. package/lib/commonjs/catalog/catalog.types.g.js +1 -46
  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 -345
  16. package/lib/commonjs/engine/askGate.js +1 -287
  17. package/lib/commonjs/engine/effectFor.js +1 -223
  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 -1836
  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 -4552
  46. package/lib/module/catalog/catalog.source.json +249 -0
  47. package/lib/module/catalog/catalog.types.g.js +1 -42
  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 -339
  56. package/lib/module/engine/askGate.js +1 -280
  57. package/lib/module/engine/effectFor.js +1 -220
  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 -1827
  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 +3 -2
  83. package/lib/typescript/providers/problem.d.ts +0 -20
  84. package/lib/typescript/providers/streamTimer.d.ts +0 -24
  85. package/lib/typescript/realNow.d.ts +18 -0
  86. package/lib/web/index.mjs +52 -53
  87. package/package.json +1 -1
  88. package/lib/commonjs/blocks/receipts.js.map +0 -1
  89. package/lib/commonjs/blocks/runId.js.map +0 -1
  90. package/lib/commonjs/blocks/types.js.map +0 -1
  91. package/lib/commonjs/blocks/uiTool.js.map +0 -1
  92. package/lib/commonjs/catalog/catalog.g.js.map +0 -1
  93. package/lib/commonjs/catalog/catalog.types.g.js.map +0 -1
  94. package/lib/commonjs/catalog/normalizeParams.js.map +0 -1
  95. package/lib/commonjs/catalog/signature.js.map +0 -1
  96. package/lib/commonjs/catalog/snapshotReads.js.map +0 -1
  97. package/lib/commonjs/catalog/toProviderTools.js.map +0 -1
  98. package/lib/commonjs/catalog/validateParams.js.map +0 -1
  99. package/lib/commonjs/context/buildContextPack.js.map +0 -1
  100. package/lib/commonjs/effects/digest.js.map +0 -1
  101. package/lib/commonjs/effects/ledger.js.map +0 -1
  102. package/lib/commonjs/engine/askGate.js.map +0 -1
  103. package/lib/commonjs/engine/effectFor.js.map +0 -1
  104. package/lib/commonjs/engine/evidence.js.map +0 -1
  105. package/lib/commonjs/engine/historyBudget.js.map +0 -1
  106. package/lib/commonjs/engine/retrieve.js.map +0 -1
  107. package/lib/commonjs/engine/runAgentTurn.js.map +0 -1
  108. package/lib/commonjs/engine/systemPrompt.js.map +0 -1
  109. package/lib/commonjs/engine/textToolCalls.js.map +0 -1
  110. package/lib/commonjs/engine/tokenCalibration.js.map +0 -1
  111. package/lib/commonjs/engine/verify.js.map +0 -1
  112. package/lib/commonjs/index.js.map +0 -1
  113. package/lib/commonjs/policy/labels.js.map +0 -1
  114. package/lib/commonjs/policy/policy.js.map +0 -1
  115. package/lib/commonjs/policy/redact.js.map +0 -1
  116. package/lib/commonjs/providers/anthropic.js.map +0 -1
  117. package/lib/commonjs/providers/openai.js.map +0 -1
  118. package/lib/commonjs/providers/problem.js.map +0 -1
  119. package/lib/commonjs/providers/sse.js.map +0 -1
  120. package/lib/commonjs/providers/streamTimer.js.map +0 -1
  121. package/lib/commonjs/providers/transport.js.map +0 -1
  122. package/lib/commonjs/providers/types.js.map +0 -1
  123. package/lib/commonjs/providers/xhrStream.js.map +0 -1
  124. package/lib/commonjs/session.js.map +0 -1
  125. package/lib/commonjs/types.js.map +0 -1
  126. package/lib/module/blocks/receipts.js.map +0 -1
  127. package/lib/module/blocks/runId.js.map +0 -1
  128. package/lib/module/blocks/types.js.map +0 -1
  129. package/lib/module/blocks/uiTool.js.map +0 -1
  130. package/lib/module/catalog/catalog.g.js.map +0 -1
  131. package/lib/module/catalog/catalog.types.g.js.map +0 -1
  132. package/lib/module/catalog/normalizeParams.js.map +0 -1
  133. package/lib/module/catalog/signature.js.map +0 -1
  134. package/lib/module/catalog/snapshotReads.js.map +0 -1
  135. package/lib/module/catalog/toProviderTools.js.map +0 -1
  136. package/lib/module/catalog/validateParams.js.map +0 -1
  137. package/lib/module/context/buildContextPack.js.map +0 -1
  138. package/lib/module/effects/digest.js.map +0 -1
  139. package/lib/module/effects/ledger.js.map +0 -1
  140. package/lib/module/engine/askGate.js.map +0 -1
  141. package/lib/module/engine/effectFor.js.map +0 -1
  142. package/lib/module/engine/evidence.js.map +0 -1
  143. package/lib/module/engine/historyBudget.js.map +0 -1
  144. package/lib/module/engine/retrieve.js.map +0 -1
  145. package/lib/module/engine/runAgentTurn.js.map +0 -1
  146. package/lib/module/engine/systemPrompt.js.map +0 -1
  147. package/lib/module/engine/textToolCalls.js.map +0 -1
  148. package/lib/module/engine/tokenCalibration.js.map +0 -1
  149. package/lib/module/engine/verify.js.map +0 -1
  150. package/lib/module/index.js.map +0 -1
  151. package/lib/module/policy/labels.js.map +0 -1
  152. package/lib/module/policy/policy.js.map +0 -1
  153. package/lib/module/policy/redact.js.map +0 -1
  154. package/lib/module/providers/anthropic.js.map +0 -1
  155. package/lib/module/providers/openai.js.map +0 -1
  156. package/lib/module/providers/problem.js.map +0 -1
  157. package/lib/module/providers/sse.js.map +0 -1
  158. package/lib/module/providers/streamTimer.js.map +0 -1
  159. package/lib/module/providers/transport.js.map +0 -1
  160. package/lib/module/providers/types.js.map +0 -1
  161. package/lib/module/providers/xhrStream.js.map +0 -1
  162. package/lib/module/session.js.map +0 -1
  163. package/lib/module/types.js.map +0 -1
  164. package/lib/typescript/blocks/receipts.d.ts.map +0 -1
  165. package/lib/typescript/blocks/runId.d.ts.map +0 -1
  166. package/lib/typescript/blocks/types.d.ts.map +0 -1
  167. package/lib/typescript/blocks/uiTool.d.ts.map +0 -1
  168. package/lib/typescript/catalog/catalog.g.d.ts.map +0 -1
  169. package/lib/typescript/catalog/catalog.types.g.d.ts.map +0 -1
  170. package/lib/typescript/catalog/normalizeParams.d.ts.map +0 -1
  171. package/lib/typescript/catalog/signature.d.ts.map +0 -1
  172. package/lib/typescript/catalog/snapshotReads.d.ts.map +0 -1
  173. package/lib/typescript/catalog/toProviderTools.d.ts.map +0 -1
  174. package/lib/typescript/catalog/validateParams.d.ts.map +0 -1
  175. package/lib/typescript/context/buildContextPack.d.ts.map +0 -1
  176. package/lib/typescript/effects/digest.d.ts.map +0 -1
  177. package/lib/typescript/effects/ledger.d.ts.map +0 -1
  178. package/lib/typescript/engine/askGate.d.ts.map +0 -1
  179. package/lib/typescript/engine/effectFor.d.ts.map +0 -1
  180. package/lib/typescript/engine/evidence.d.ts.map +0 -1
  181. package/lib/typescript/engine/historyBudget.d.ts.map +0 -1
  182. package/lib/typescript/engine/retrieve.d.ts.map +0 -1
  183. package/lib/typescript/engine/runAgentTurn.d.ts.map +0 -1
  184. package/lib/typescript/engine/systemPrompt.d.ts.map +0 -1
  185. package/lib/typescript/engine/textToolCalls.d.ts.map +0 -1
  186. package/lib/typescript/engine/tokenCalibration.d.ts.map +0 -1
  187. package/lib/typescript/engine/verify.d.ts.map +0 -1
  188. package/lib/typescript/index.d.ts.map +0 -1
  189. package/lib/typescript/policy/labels.d.ts.map +0 -1
  190. package/lib/typescript/policy/policy.d.ts.map +0 -1
  191. package/lib/typescript/policy/redact.d.ts.map +0 -1
  192. package/lib/typescript/providers/anthropic.d.ts.map +0 -1
  193. package/lib/typescript/providers/openai.d.ts.map +0 -1
  194. package/lib/typescript/providers/problem.d.ts.map +0 -1
  195. package/lib/typescript/providers/sse.d.ts.map +0 -1
  196. package/lib/typescript/providers/streamTimer.d.ts.map +0 -1
  197. package/lib/typescript/providers/transport.d.ts.map +0 -1
  198. package/lib/typescript/providers/types.d.ts.map +0 -1
  199. package/lib/typescript/providers/xhrStream.d.ts.map +0 -1
  200. package/lib/typescript/session.d.ts.map +0 -1
  201. package/lib/typescript/types.d.ts.map +0 -1
@@ -1,327 +1,3 @@
1
- "use strict";
1
+ "use strict";const f=i=>!!i&&typeof i==="object"&&!Array.isArray(i);export function hashQueryKey(i){return JSON.stringify(i,(e,t)=>f(t)?Object.keys(t).sort().reduce((a,r)=>{a[r]=t[r];return a},{}):t)}function n(i,e,t,a){if(i[t]!==void 0||i[e]===void 0)return false;i[t]=i[e];delete i[e];a.push(`Accepted \`${e}\` as \`${t}\` \u2014 the parameter is named \`${t}\`.`);return true}const o=new Set(["getQueryData","refetch","invalidate","reset","remove","triggerError","restoreError","triggerLoading","restoreLoading"]);const l=["id","urlPattern","enabled","name","methods","kind","status","statusText","headers","body","bodyPatch","bodyPath","bodyValue","failKind","delayMs","times","alternate","force","bodyOmitted"];function h(i,e,t){if(o.has(i)&&e.queryHash===void 0){const a=f(e.filters)?e.filters:void 0;const r=e.queryKey??e.key??e.hash??a?.queryKey??a?.queryHash;if(Array.isArray(r)){e.queryHash=hashQueryKey(r);t.push(`Accepted the queryKey array as the query's hash (${e.queryHash}) \u2014 the parameter is \`queryHash\`, the string from listQueries.`)}else if(typeof r==="string"){e.queryHash=r;t.push(`Accepted it as \`queryHash\` \u2014 that is the parameter name.`)}delete e.queryKey;delete e.key;delete e.hash;delete e.filters}if(i==="setQueryData"){if(f(e.data)){for(const a of["merge","force"]){if(typeof e.data[a]==="boolean"&&e[a]===void 0){e[a]=e.data[a];delete e.data[a];t.push(`Moved \`${a}\` out of \`data\` to the top level \u2014 it is a write flag, not part of the value.`)}}}n(e,"newData","data",t)||e.path===void 0&&n(e,"value","data",t)||n(e,"patch","data",t);if(e.queryKey===void 0&&typeof e.queryHash==="string"){try{const a=JSON.parse(e.queryHash);if(Array.isArray(a)){e.queryKey=a;t.push("Accepted the queryHash as the key \u2014 setQueryData takes `queryKey`, the array.")}}catch{}}if(e.patch!==void 0||e.merge===void 0){if(t.some(a=>a.includes("`patch`")))e.merge=true}}}function c(i,e,t){if(i==="getEventBody"||i==="setPinned"||i==="setSaved"){n(e,"requestId","id",t)||n(e,"eventId","id",t)}if(i==="deleteOverrideRule"||i==="setOverrideRuleEnabled"||i==="getOverrideRuleBody"){n(e,"ruleId","id",t)}if(i==="upsertOverrideRule"){const a=f(e.rule)?{...e.rule}:{};if(e.fromRequestId===void 0&&typeof a.fromRequestId==="string"){e.fromRequestId=a.fromRequestId;t.push("Accepted `rule.fromRequestId` \u2014 it is a top-level parameter, beside `rule`.")}delete a.fromRequestId;y(a,t);m(e,a,t);const r=[];for(const d of l){if(e[d]!==void 0&&a[d]===void 0){a[d]=e[d];r.push(d)}delete e[d]}if(r.length)t.push(`Accepted ${r.map(d=>`\`${d}\``).join(", ")} at the top level \u2014 rule fields belong inside \`rule\`.`);if(Object.keys(a).length)e.rule=a}}function y(i,e){for(const[t,a]of[["match",["urlPattern","methods","method","url","pattern","urlContains","contains"]],["response",["status","statusText","body","headers","bodyPatch"]]]){const r=i[t];if(!f(r))continue;const d=[];for(const s of a){if(r[s]===void 0)continue;const u=s==="method"?"methods":s==="url"||s==="pattern"||s==="urlContains"||s==="contains"?"urlPattern":s;if(i[u]!==void 0)continue;i[u]=u==="methods"&&!Array.isArray(r[s])?[r[s]]:r[s];delete r[s];d.push(s)}if(!d.length)continue;if(!Object.keys(r).length)delete i[t];e.push(`Read \`rule.${t}.{${d.join(", ")}}\` as top-level rule fields \u2014 this rule is flat, unlike msw/nock-style mocks.`)}}function m(i,e,t){if(e.bodyPath===void 0&&typeof e.path==="string"){e.bodyPath=e.path;if(e.bodyValue===void 0&&e.value!==void 0)e.bodyValue=e.value;delete e.path;delete e.value;t.push("Read `path`/`value` as `bodyPath`/`bodyValue` \u2014 on a rule they address the response body.")}const a=s=>e[s]!==void 0?e[s]:i[s];const r=s=>{delete e[s];delete i[s]};const d=a("mode");if(typeof d==="string"&&["respond","fail","delay"].includes(d)&&e.kind===void 0){e.kind=d;t.push(`Read \`mode: "${d}"\` as \`kind: "${d}"\`.`)}r("mode");if(a("fail")===true&&e.kind===void 0){e.kind="fail";t.push('Read `fail: true` as `kind: "fail"` \u2014 a transport failure, as if offline.')}r("fail");if(a("failOnce")===true){if(e.kind===void 0)e.kind="fail";if(e.times===void 0)e.times=1;t.push('Read `failOnce: true` as `kind: "fail"` with `times: 1` \u2014 it fires once, then the rule disables itself.')}r("failOnce");if(a("once")===true&&e.times===void 0){e.times=1;t.push("Read `once: true` as `times: 1` \u2014 the rule auto-disables after one match.")}r("once");for(const s of["maxHits","hits","count","maxTimes","applyTimes"]){const u=a(s);if(typeof u==="number"&&Number.isFinite(u)&&u>0&&e.times===void 0){e.times=u;t.push(`Read \`${s}: ${u}\` as \`times: ${u}\` \u2014 the rule auto-disables after ${u} match(es).`)}r(s)}}function b(i,e,t){n(e,"name","storeName",t)||n(e,"store","storeName",t);if(i==="setState"){n(e,"statePatch","state",t)||n(e,"partial","state",t)||n(e,"patch","state",t)||n(e,"newState","state",t)||n(e,"nextState","state",t)||e.path===void 0&&n(e,"value","state",t);if(e.replace===void 0){e.replace=false;t.push("Applied replace:false (merge) \u2014 a store keeps action functions that can't be re-sent, and replacing would wipe them (the buttons that call them would then crash). Send replace:true only to deliberately reset the whole store.")}}}function g(i,e,t){if(i==="navigate"){n(e,"route","path",t)||n(e,"to","path",t)||n(e,"url","path",t)||n(e,"pathname","path",t)}}export function normalizeParams(i,e,t){const a={...t};const r=[];switch(i){case"query":h(e,a,r);break;case"network":c(e,a,r);break;case"zustand":b(e,a,r);break;case"route-events":g(e,a,r);break;default:break}return{params:a,notes:r}}export function aliasNote(i){return i.length?`
2
2
 
3
- /**
4
- * Parameter aliases — accept what models actually send.
5
- *
6
- * The provider sees ONE tool per Buoy tool with `params` as an open object
7
- * (see toProviderTools.ts), so the per-action parameter names live in prose
8
- * and every model has to reproduce them from memory. A sweep of 18 models
9
- * against the live app showed the same handful of misses over and over, on
10
- * cheap models AND on gpt-5 and Gemini 2.5 Pro:
11
- *
12
- * queryKey: [...] where the action wants queryHash (by far the #1 miss —
13
- * the RIGHT NOW block shows keys as arrays, and
14
- * setQueryData takes queryKey, so the model reuses it)
15
- * requestId where network.getEventBody wants id
16
- * newState/patch where zustand.setState wants state
17
- * name where zustand wants storeName
18
- * bodyPatch/body/… at the top level of upsertOverrideRule instead of inside `rule`
19
- *
20
- * A validation error names the right field, but a cheap model repeats the same
21
- * wrong call or gives up, and the user sees "nothing happened". Every one of
22
- * these is mechanically unambiguous, so it is fixed HERE, before validation,
23
- * and the result carries a one-line note so the model learns the real name
24
- * without failing the call. Nothing here guesses: an alias only fires when the
25
- * canonical field is absent and the alias is present.
26
- */
27
-
28
- const isPlainObject = v => !!v && typeof v === "object" && !Array.isArray(v);
29
-
30
- /**
31
- * TanStack's default `hashKey`: JSON.stringify with plain-object keys sorted,
32
- * so `["todos", {page:1, sort:"a"}]` hashes the same whatever order the model
33
- * wrote the object in.
34
- */
35
- export function hashQueryKey(key) {
36
- return JSON.stringify(key, (_, val) => isPlainObject(val) ? Object.keys(val).sort().reduce((acc, k) => {
37
- acc[k] = val[k];
38
- return acc;
39
- }, {}) : val);
40
- }
41
-
42
- /** Rename `from` to `to` when `to` is absent and `from` is present. */
43
- function alias(p, from, to, notes) {
44
- if (p[to] !== undefined || p[from] === undefined) return false;
45
- p[to] = p[from];
46
- delete p[from];
47
- notes.push(`Accepted \`${from}\` as \`${to}\` — the parameter is named \`${to}\`.`);
48
- return true;
49
- }
50
- const QUERY_HASH_ACTIONS = new Set(["getQueryData", "refetch", "invalidate", "reset", "remove", "triggerError", "restoreError", "triggerLoading", "restoreLoading"]);
51
-
52
- /** Fields that belong inside `rule` for network.upsertOverrideRule. */
53
- const RULE_FIELDS = ["id", "urlPattern", "enabled", "name", "methods", "kind", "status", "statusText", "headers", "body", "bodyPatch", "bodyPath", "bodyValue", "failKind", "delayMs", "times", "alternate", "force", "bodyOmitted"];
54
- function normalizeQuery(action, p, notes) {
55
- if (QUERY_HASH_ACTIONS.has(action) && p.queryHash === undefined) {
56
- // `filters: { queryKey }` — the TanStack client-API shape.
57
- const filters = isPlainObject(p.filters) ? p.filters : undefined;
58
- const key = p.queryKey ?? p.key ?? p.hash ?? filters?.queryKey ?? filters?.queryHash;
59
- if (Array.isArray(key)) {
60
- p.queryHash = hashQueryKey(key);
61
- notes.push(`Accepted the queryKey array as the query's hash (${p.queryHash}) — the parameter is \`queryHash\`, the string from listQueries.`);
62
- } else if (typeof key === "string") {
63
- // A hash string under another name, or a loose "a,b,c" spelling the
64
- // adapter resolves against the live cache.
65
- p.queryHash = key;
66
- notes.push(`Accepted it as \`queryHash\` — that is the parameter name.`);
67
- }
68
- delete p.queryKey;
69
- delete p.key;
70
- delete p.hash;
71
- delete p.filters;
72
- }
73
- if (action === "setQueryData") {
74
- // Models routinely tuck the write FLAGS inside `data` — `data: {item:{…},
75
- // merge:true}` — which turns a merge into a replace and leaves a junk
76
- // `merge`/`force` key in the cache. Lift a boolean flag out of `data` to
77
- // the top level when the top level doesn't already set it. Guarded to
78
- // booleans so a real data field named "merge" is never disturbed.
79
- if (isPlainObject(p.data)) {
80
- for (const flag of ["merge", "force"]) {
81
- if (typeof p.data[flag] === "boolean" && p[flag] === undefined) {
82
- p[flag] = p.data[flag];
83
- delete p.data[flag];
84
- notes.push(`Moved \`${flag}\` out of \`data\` to the top level — it is a write flag, not part of the value.`);
85
- }
86
- }
87
- }
88
- // `value` normally means "the patch, spelled differently". But alongside
89
- // `path` it means the OPPOSITE — the single value that path is set to — so
90
- // rewriting it there would turn `path:"item.name", value:"x"` into a
91
- // top-level patch of `"x"`, silently. Only the path form reserves it.
92
- alias(p, "newData", "data", notes) || p.path === undefined && alias(p, "value", "data", notes) || alias(p, "patch", "data", notes);
93
- if (p.queryKey === undefined && typeof p.queryHash === "string") {
94
- try {
95
- const parsed = JSON.parse(p.queryHash);
96
- if (Array.isArray(parsed)) {
97
- p.queryKey = parsed;
98
- notes.push("Accepted the queryHash as the key — setQueryData takes `queryKey`, the array.");
99
- }
100
- } catch {
101
- /* leave it; validation will say what is missing */
102
- }
103
- }
104
- if (p.patch !== undefined || p.merge === undefined) {
105
- // A caller that said "patch" meant merge.
106
- if (notes.some(n => n.includes("`patch`"))) p.merge = true;
107
- }
108
- }
109
- }
110
- function normalizeNetwork(action, p, notes) {
111
- if (action === "getEventBody" || action === "setPinned" || action === "setSaved") {
112
- alias(p, "requestId", "id", notes) || alias(p, "eventId", "id", notes);
113
- }
114
- if (action === "deleteOverrideRule" || action === "setOverrideRuleEnabled" || action === "getOverrideRuleBody") {
115
- alias(p, "ruleId", "id", notes);
116
- }
117
- if (action === "upsertOverrideRule") {
118
- const rule = isPlainObject(p.rule) ? {
119
- ...p.rule
120
- } : {};
121
- // fromRequestId is a TOP-LEVEL field; models tuck it into the rule.
122
- if (p.fromRequestId === undefined && typeof rule.fromRequestId === "string") {
123
- p.fromRequestId = rule.fromRequestId;
124
- notes.push("Accepted `rule.fromRequestId` — it is a top-level parameter, beside `rule`.");
125
- }
126
- delete rule.fromRequestId;
127
- unwrapRuleSections(rule, notes);
128
- ruleIntentWords(p, rule, notes);
129
- // Rule fields sent flat at the top level move inside `rule`.
130
- const moved = [];
131
- for (const f of RULE_FIELDS) {
132
- if (p[f] !== undefined && rule[f] === undefined) {
133
- rule[f] = p[f];
134
- moved.push(f);
135
- }
136
- delete p[f];
137
- }
138
- if (moved.length) notes.push(`Accepted ${moved.map(f => `\`${f}\``).join(", ")} at the top level — rule fields belong inside \`rule\`.`);
139
- if (Object.keys(rule).length) p.rule = rule;
140
- }
141
- }
142
-
143
- /**
144
- * Flatten the `match` / `response` wrappers models borrow from other mocking
145
- * libraries.
146
- *
147
- * Our rule is flat — `{urlPattern, methods, status, body, times}`. Nearly every
148
- * HTTP-mocking library a model has read is not: msw, nock and WireMock all group
149
- * the matcher and the reply into separate objects. So a model that has never
150
- * seen our schema (and it has not — `params` is an unconstrained object) writes
151
- * the convention it knows. Measured: Claude sent
152
- * `{times: 1, match: {method, urlPattern}, response: {status, body}}` — every
153
- * value correct, in the shape the rest of the world uses.
154
- *
155
- * Only these two wrapper names, and only fields that are really ours: an
156
- * unrecognised key inside one is left where it is rather than hoisted, so this
157
- * cannot quietly invent a rule field that does not exist.
158
- */
159
- function unwrapRuleSections(rule, notes) {
160
- for (const [wrapper, fields] of [["match", ["urlPattern", "methods", "method", "url", "pattern", "urlContains", "contains"]], ["response", ["status", "statusText", "body", "headers", "bodyPatch"]]]) {
161
- const inner = rule[wrapper];
162
- if (!isPlainObject(inner)) continue;
163
- const moved = [];
164
- for (const f of fields) {
165
- if (inner[f] === undefined) continue;
166
- // `method` and `url` are that library's spelling of ours.
167
- const target = f === "method" ? "methods" : f === "url" || f === "pattern" || f === "urlContains" || f === "contains" ? "urlPattern" : f;
168
- if (rule[target] !== undefined) continue;
169
- rule[target] = target === "methods" && !Array.isArray(inner[f]) ? [inner[f]] : inner[f];
170
- delete inner[f];
171
- moved.push(f);
172
- }
173
- if (!moved.length) continue;
174
- // Everything recognised moved out; drop the wrapper only if nothing is left,
175
- // so a leftover key still surfaces as a schema error rather than vanishing.
176
- if (!Object.keys(inner).length) delete rule[wrapper];
177
- notes.push(`Read \`rule.${wrapper}.{${moved.join(", ")}}\` as top-level rule fields — this rule is flat, unlike msw/nock-style mocks.`);
178
- }
179
- }
180
-
181
- /**
182
- * The words models reach for when describing an override rule, mapped to the
183
- * fields the rule actually has.
184
- *
185
- * MEASURED, not invented. On `api-sim/next-call-fails-once` — "make the next
186
- * menu request fail, just the next one" — every model that acted picked the
187
- * right tool and explained the right reason, then wrote the rule like this:
188
- *
189
- * grok ×3 {fail: true, once: true}
190
- * composer {fail: true} and {maxHits: 1, fail: true}
191
- * opus {status: 500, enabled: true}
192
- *
193
- * The schema wants `{kind: "fail", times: 1}`. Ten of fourteen attempts on that
194
- * case graded `acceptable` rather than `best` for no reason except this — the
195
- * budget was expressed as `once`/`maxHits` and silently dropped, leaving a rule
196
- * that never expires.
197
- *
198
- * It is NOT a missing instruction. `times` is documented as "Use 1 for 'make the
199
- * next call fail' so it cannot linger" — very nearly the user's own sentence —
200
- * and every model read past it. That is the same finding as the nesting-depth
201
- * work: the fix has to be structural, not a better sentence.
202
- *
203
- * Each mapping only ever makes a rule NARROWER (a budget where there was none,
204
- * a transport failure where the kind was unstated), so a misread costs a rule
205
- * that stops too early rather than one that runs forever.
206
- */
207
- function ruleIntentWords(p, rule, notes) {
208
- // `path`/`value` is what the state tools call this, and a model that learned
209
- // it on `zustand.setState` or `query.setQueryData` writes the same words here.
210
- // A rule has no other meaning for either name, so accept them.
211
- if (rule.bodyPath === undefined && typeof rule.path === "string") {
212
- rule.bodyPath = rule.path;
213
- if (rule.bodyValue === undefined && rule.value !== undefined) rule.bodyValue = rule.value;
214
- delete rule.path;
215
- delete rule.value;
216
- notes.push("Read `path`/`value` as `bodyPath`/`bodyValue` — on a rule they address the response body.");
217
- }
218
- const read = key => rule[key] !== undefined ? rule[key] : p[key];
219
- const drop = key => {
220
- delete rule[key];
221
- delete p[key];
222
- };
223
-
224
- // `mode` is the other library's name for `kind`, and models use it verbatim:
225
- // measured on `api-sim/api-down`, alongside `match.urlContains`.
226
- const mode = read("mode");
227
- if (typeof mode === "string" && ["respond", "fail", "delay"].includes(mode) && rule.kind === undefined) {
228
- rule.kind = mode;
229
- notes.push(`Read \`mode: "${mode}"\` as \`kind: "${mode}"\`.`);
230
- }
231
- drop("mode");
232
-
233
- // "fail" as a flag, rather than kind:"fail".
234
- if (read("fail") === true && rule.kind === undefined) {
235
- rule.kind = "fail";
236
- notes.push("Read `fail: true` as `kind: \"fail\"` — a transport failure, as if offline.");
237
- }
238
- drop("fail");
239
-
240
- // "just once" / "only the next one", in the several ways it gets written.
241
- if (read("failOnce") === true) {
242
- if (rule.kind === undefined) rule.kind = "fail";
243
- if (rule.times === undefined) rule.times = 1;
244
- notes.push("Read `failOnce: true` as `kind: \"fail\"` with `times: 1` — it fires once, then the rule disables itself.");
245
- }
246
- drop("failOnce");
247
- if (read("once") === true && rule.times === undefined) {
248
- rule.times = 1;
249
- notes.push("Read `once: true` as `times: 1` — the rule auto-disables after one match.");
250
- }
251
- drop("once");
252
-
253
- // A numeric budget under any of its other names. `limit` is deliberately NOT
254
- // here: it means "how many to list" on half the actions in this catalog, and
255
- // a wrong guess about a budget is a rule that stops early on a request the
256
- // caller still needed.
257
- for (const key of ["maxHits", "hits", "count", "maxTimes", "applyTimes"]) {
258
- const v = read(key);
259
- if (typeof v === "number" && Number.isFinite(v) && v > 0 && rule.times === undefined) {
260
- rule.times = v;
261
- notes.push(`Read \`${key}: ${v}\` as \`times: ${v}\` — the rule auto-disables after ${v} match(es).`);
262
- }
263
- drop(key);
264
- }
265
- }
266
- function normalizeZustand(action, p, notes) {
267
- alias(p, "name", "storeName", notes) || alias(p, "store", "storeName", notes);
268
- if (action === "setState") {
269
- alias(p, "statePatch", "state", notes) || alias(p, "partial", "state", notes) || alias(p, "patch", "state", notes) || alias(p, "newState", "state", notes) || alias(p, "nextState", "state", notes) ||
270
- // See the same guard on setQueryData: with `path`, `value` is the value
271
- // being set, not another spelling of the patch.
272
- p.path === undefined && alias(p, "value", "state", notes);
273
- // ALWAYS merge, never replace, unless the caller explicitly said replace.
274
- // The adapter defaults replace:true, which throws away everything not sent
275
- // — including the store's ACTION FUNCTIONS (setQty, removeLine, …), which
276
- // can't cross the JSON wire, so a remote caller never has them to re-send.
277
- // The data then looks right but the buttons that call those methods crash.
278
- // A merge (replace:false) shallow-merges the fields sent and keeps the
279
- // functions and untouched keys intact.
280
- if (p.replace === undefined) {
281
- p.replace = false;
282
- notes.push("Applied replace:false (merge) — a store keeps action functions that can't be re-sent, and replacing would wipe them (the buttons that call them would then crash). Send replace:true only to deliberately reset the whole store.");
283
- }
284
- }
285
- }
286
- function normalizeRoutes(action, p, notes) {
287
- if (action === "navigate") {
288
- alias(p, "route", "path", notes) || alias(p, "to", "path", notes) || alias(p, "url", "path", notes) || alias(p, "pathname", "path", notes);
289
- }
290
- }
291
-
292
- /**
293
- * Fix the unambiguous parameter-name misses before validation. Returns the
294
- * same object shape validation expects plus the notes to append to the result.
295
- */
296
- export function normalizeParams(toolId, action, raw) {
297
- const p = {
298
- ...raw
299
- };
300
- const notes = [];
301
- switch (toolId) {
302
- case "query":
303
- normalizeQuery(action, p, notes);
304
- break;
305
- case "network":
306
- normalizeNetwork(action, p, notes);
307
- break;
308
- case "zustand":
309
- normalizeZustand(action, p, notes);
310
- break;
311
- case "route-events":
312
- normalizeRoutes(action, p, notes);
313
- break;
314
- default:
315
- break;
316
- }
317
- return {
318
- params: p,
319
- notes
320
- };
321
- }
322
-
323
- /** The one-line trailer appended to a tool result when aliases fired. */
324
- export function aliasNote(notes) {
325
- return notes.length ? `\n\n[Buoy] ${notes.join(" ")}` : "";
326
- }
327
- //# sourceMappingURL=normalizeParams.js.map
3
+ [Buoy] ${i.join(" ")}`:""}
@@ -1,63 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * Rendering a JSON Schema as the one-line signature a model reads.
5
- *
6
- * Lifted out of `blocks/uiTool.ts`, where it was written for `buoy_ui` and
7
- * where its own comment records the result that justifies using it everywhere:
8
- *
9
- * > `uiProviderTool` used to send `params: { type: "object" }` and 26 lines
10
- * > of prose about what each kind is FOR — and not one field name. The model
11
- * > was being asked to guess `images` vs `items` and `chips` vs `options`,
12
- * > and it guessed wrong three rounds running.
13
- *
14
- * The other 24 tools still send exactly that: an open `params` object and a
15
- * sentence promising the error will explain the shape. `normalizeParams.ts`
16
- * exists to catch the five misses that produced most often. This renders the
17
- * field names instead, from the SAME schema `validateParams` enforces, so what
18
- * the model reads can never drift from what the validator accepts.
19
- */
20
-
21
- /** `{ url*, alt?, caption? }` — `*` marks required. */
22
- export function signature(schema, depth = 0) {
23
- if (!schema || typeof schema !== "object") return "any";
24
- const s = schema;
25
- if (Array.isArray(s.anyOf)) {
26
- return s.anyOf.map(b => signature(b, depth)).join(" | ");
27
- }
28
- if (s.type === "array") {
29
- const cap = typeof s.maxItems === "number" ? ` ≤${s.maxItems}` : "";
30
- return `[${signature(s.items, depth + 1)}${cap}]`;
31
- }
32
- if (s.type === "object" || s.properties) {
33
- const props = s.properties ?? {};
34
- const names = Object.keys(props);
35
- if (!names.length) return "{…}";
36
- // Three levels is every field a model has to name; below that lives the
37
- // action's `dispatch`, which the prose already describes.
38
- if (depth >= 3) return "{…}";
39
- const required = new Set(s.required ?? []);
40
- const fields = names.map(name => {
41
- const inner = signature(props[name], depth + 1);
42
- const mark = required.has(name) ? "*" : "";
43
- return inner === "any" ? `${name}${mark}` : `${name}${mark}: ${inner}`;
44
- });
45
- return `{ ${fields.join(", ")} }`;
46
- }
47
- if (Array.isArray(s.enum)) return s.enum.map(v => `"${String(v)}"`).join("|");
48
- return typeof s.type === "string" ? s.type : "any";
49
- }
50
-
51
- /**
52
- * The `params:` line under an action, or "" when the action takes none.
53
- *
54
- * Actions with no declared properties (71 of 192) get nothing rather than an
55
- * empty `{}` — a line that says the action takes no arguments is already said
56
- * by its absence, and 71 of them would be pure noise.
57
- */
58
- export function paramsLine(schema) {
59
- const props = schema?.properties;
60
- if (!props || Object.keys(props).length === 0) return "";
61
- return `params: ${signature(schema)}`;
62
- }
63
- //# sourceMappingURL=signature.js.map
1
+ "use strict";export function signature(n,e=0){if(!n||typeof n!=="object")return"any";const r=n;if(Array.isArray(r.anyOf)){return r.anyOf.map(t=>signature(t,e)).join(" | ")}if(r.type==="array"){const t=typeof r.maxItems==="number"?` \u2264${r.maxItems}`:"";return`[${signature(r.items,e+1)}${t}]`}if(r.type==="object"||r.properties){const t=r.properties??{};const s=Object.keys(t);if(!s.length)return"{\u2026}";if(e>=3)return"{\u2026}";const u=new Set(r.required??[]);const a=s.map(i=>{const o=signature(t[i],e+1);const p=u.has(i)?"*":"";return o==="any"?`${i}${p}`:`${i}${p}: ${o}`});return`{ ${a.join(", ")} }`}if(Array.isArray(r.enum))return r.enum.map(t=>`"${String(t)}"`).join("|");return typeof r.type==="string"?r.type:"any"}export function paramsLine(n){const e=n?.properties;if(!e||Object.keys(e).length===0)return"";return`params: ${signature(n)}`}
@@ -1,259 +1 @@
1
- "use strict";
2
-
3
- /**
4
- * The other half of Buoy's read surface.
5
- *
6
- * Every Buoy adapter answers in two ways, and only one of them is an action.
7
- * `listQueries`, `async.getAllKeys` and `getState` are actions; console
8
- * entries, network events, the route sitemap and the env table are NOT — they
9
- * exist only inside the adapter's `getSnapshot`, which the sync layer polls and
10
- * puts on the wire for MCP's `get_snapshot` / `get_console` /
11
- * `get_network_requests` / `get_routes`.
12
- *
13
- * `dispatchToolAction` reaches only the first half. So an agent driving tools
14
- * on the device could read storage, stores and the query cache, and was blind
15
- * to the app's logs, its HTTP traffic, its routes and its environment — the
16
- * four things a QA person is most likely to ask about, and two of which the
17
- * empty state advertises as suggestions. The catalog even tells the model to
18
- * "use get_console", which is an MCP tool that does not exist on this path.
19
- *
20
- * This module closes that half. `getSnapshot` is a RESERVED action name: the
21
- * engine intercepts it before dispatch and routes it to the registry's
22
- * snapshot reader instead.
23
- *
24
- * WHY THE PROJECTIONS. A raw snapshot is the heaviest payload in the system —
25
- * measured at ~1.1KB per console entry with up to 1000 retained, and network
26
- * events carry bodies. Handing that to a token-metered model truncated at 24K
27
- * chars produces a torn JSON object and a wasted turn. Each projector here
28
- * does what the matching MCP tool does: newest-first, filtered, and only the
29
- * fields worth spending tokens on. Bodies stay behind `network.getEventBody`,
30
- * which already exists.
31
- */
32
-
33
- import { isSelfTraffic } from "../policy/redact";
34
-
35
- /** Reserved action name. Not a real adapter action anywhere. */
36
- export const SNAPSHOT_ACTION = "getSnapshot";
37
- const SEVERITY = {
38
- verbose: 0,
39
- debug: 0,
40
- trace: 0,
41
- log: 1,
42
- info: 1,
43
- warn: 2,
44
- warning: 2,
45
- error: 3
46
- };
47
- function asArray(value) {
48
- return Array.isArray(value) ? value : [];
49
- }
50
- function rec(value) {
51
- return value && typeof value === "object" ? value : {};
52
- }
53
- function num(value, fallback) {
54
- return typeof value === "number" && value > 0 ? value : fallback;
55
- }
56
-
57
- /**
58
- * The newest N. Every Buoy event store (BaseEventStore, which network,
59
- * console, sentry and route events all sit on) PREPENDS, so the list arrives
60
- * newest-FIRST and the newest N are the first N. An earlier version took the
61
- * LAST N here — the oldest — so once more than N were captured, RIGHT NOW
62
- * showed the stalest requests and a crash that had just happened fell out of
63
- * the console projection. Order is preserved: newest first.
64
- */
65
- function newest(items, limit) {
66
- return items.length <= limit ? items : items.slice(0, limit);
67
- }
68
- function projectConsole(payload, params) {
69
- const entries = asArray(rec(payload).entries);
70
- const minSeverity = typeof params.level === "string" ? SEVERITY[params.level] ?? 0 : 0;
71
- const pattern = typeof params.pattern === "string" ? params.pattern.toLowerCase() : undefined;
72
- const matched = entries.filter(raw => {
73
- const e = rec(raw);
74
- const level = String(e.level ?? "log");
75
- if ((SEVERITY[level] ?? 1) < minSeverity) return false;
76
- if (!pattern) return true;
77
- return String(e.message ?? "").toLowerCase().includes(pattern);
78
- });
79
- const shown = newest(matched, num(params.limit, 40));
80
- return {
81
- totalCaptured: entries.length,
82
- shown: shown.length,
83
- // Pre-rendered message only. Full args and stacks stay on the device;
84
- // `get_snapshot('console')` is the MCP escape hatch and has no equivalent
85
- // here on purpose — it is the payload that blows the prompt.
86
- entries: shown.map(raw => {
87
- const e = rec(raw);
88
- return {
89
- at: e.timestamp,
90
- level: e.level,
91
- message: e.message
92
- };
93
- })
94
- };
95
- }
96
- function projectNetwork(payload, params) {
97
- const p = rec(payload);
98
- // The agent's own POSTs to the model endpoint are dropped HERE, not only by
99
- // the engine's later pass, so the counts the model is given match the rows
100
- // it is given. Reporting "4 requests" above a list of 3 is its own small lie.
101
- const events = asArray(p.events).filter(raw => !isSelfTraffic(rec(raw).url));
102
- const failedOnly = params.failedOnly === true;
103
- const pattern = typeof params.pattern === "string" ? params.pattern.toLowerCase() : undefined;
104
- const matched = events.filter(raw => {
105
- const e = rec(raw);
106
- const status = typeof e.status === "number" ? e.status : undefined;
107
- if (failedOnly && !(e.error || status !== undefined && status >= 400)) return false;
108
- if (!pattern) return true;
109
- return String(e.url ?? "").toLowerCase().includes(pattern);
110
- });
111
- const shown = newest(matched, num(params.limit, 25));
112
- return {
113
- totalCaptured: events.length,
114
- shown: shown.length,
115
- // No bodies. `network.getEventBody` fetches one on demand, which is the
116
- // difference between a readable list and a truncated blob.
117
- requests: shown.map(raw => {
118
- const e = rec(raw);
119
- return {
120
- id: e.id,
121
- method: e.method,
122
- url: e.url,
123
- status: e.status,
124
- durationMs: e.duration,
125
- error: e.error,
126
- // An override rule served this response. Carried through so neither
127
- // the model nor the receipt can present mocked data as live.
128
- overridden: e.override ? true : undefined
129
- };
130
- }),
131
- hint: "Read one response with network.getEventBody({ id })."
132
- };
133
- }
134
-
135
- /**
136
- * The sitemap arrives as a NESTED RouteInfo tree, not a list. A model asked
137
- * "what screens exist" needs the leaf paths, so flatten and keep the paths.
138
- */
139
- function flattenRoutes(nodes, out = [], cap = 80) {
140
- for (const raw of asArray(nodes)) {
141
- if (out.length >= cap) break;
142
- const node = rec(raw);
143
- if (node.isInternal !== true && typeof node.path === "string") out.push(node.path);
144
- flattenRoutes(node.children, out, cap);
145
- }
146
- return out;
147
- }
148
- function projectRoutes(payload, params) {
149
- const p = rec(payload);
150
- const sitemap = rec(p.sitemap);
151
-
152
- // Route events are stored newest-FIRST, and a stack item's screen path is
153
- // `pathname` (`path` does not exist on it). Getting either wrong is not a
154
- // crash, it is a confident wrong answer: an early version of this read told
155
- // the user they were on the Pokedex while the shop was on screen.
156
- const stackRaw = asArray(p.stack).map(rec);
157
- const eventsRaw = asArray(p.events).map(rec);
158
- const stack = stackRaw.map(s => ({
159
- name: s.name,
160
- path: s.pathname,
161
- focused: s.isFocused === true ? true : undefined
162
- }));
163
- const recentNavigations = eventsRaw.slice(0, num(params.limit, 15)).map(e => ({
164
- at: e.timestamp,
165
- from: e.previousPathname,
166
- to: e.pathname
167
- }));
168
-
169
- // Mirrors the adapter's own `getCurrentRoute`: the newest navigation event
170
- // wins, and with no history yet — a freshly launched app — the FOCUSED stack
171
- // item does, which is not always the last one in the array.
172
- const focused = stackRaw.find(s => s.isFocused === true) ?? stackRaw[stackRaw.length - 1];
173
- const currentRoute = eventsRaw.length ? {
174
- path: eventsRaw[0].pathname,
175
- source: "event"
176
- } : typeof focused?.pathname === "string" ? {
177
- path: focused.pathname,
178
- source: "stack"
179
- } : undefined;
180
- return {
181
- currentRoute,
182
- stack,
183
- routes: flattenRoutes(sitemap.routes),
184
- sitemapSource: sitemap.source,
185
- recentNavigations
186
- };
187
- }
188
- function projectEnv(payload) {
189
- const p = rec(payload);
190
- return {
191
- env: p.env ?? p.variables,
192
- requiredEnvVars: p.requiredEnvVars
193
- };
194
- }
195
-
196
- /**
197
- * Sentry envelopes are the fattest payloads any Buoy tool captures (a single
198
- * event with breadcrumbs is tens of KB), so only the item SUMMARIES travel —
199
- * the one-line human read the adapter already computes. The status field is
200
- * load-bearing: an empty list with "sdk-not-found" means the app has no
201
- * Sentry client, which is a different answer from "nothing errored".
202
- */
203
- function projectSentry(payload, params) {
204
- const p = rec(payload);
205
- const envelopes = asArray(p.envelopes).map(rec);
206
- const typeFilter = typeof params.type === "string" ? params.type : undefined;
207
- const pattern = typeof params.pattern === "string" ? params.pattern.toLowerCase() : undefined;
208
- const matched = envelopes.filter(e => {
209
- const items = asArray(e.items).map(rec);
210
- if (typeFilter && !items.some(i => i.type === typeFilter)) return false;
211
- if (!pattern) return true;
212
- return items.some(i => String(i.summary ?? "").toLowerCase().includes(pattern));
213
- });
214
- const shown = newest(matched, num(params.limit, 10));
215
- return {
216
- status: p.status,
217
- totalCaptured: envelopes.length,
218
- shown: shown.length,
219
- envelopes: shown.map(e => ({
220
- id: e.id,
221
- at: e.timestamp,
222
- origin: e.origin,
223
- eventId: e.eventId,
224
- totalBytes: e.totalBytes,
225
- items: asArray(e.items).map(raw => {
226
- const i = rec(raw);
227
- return {
228
- type: i.type,
229
- summary: i.summary,
230
- spanCount: i.spanCount,
231
- bytes: i.bytes
232
- };
233
- })
234
- })),
235
- hint: "For crash stack traces, console's [FATAL] entries carry the component stacks."
236
- };
237
- }
238
-
239
- /**
240
- * Trim one snapshot to something worth sending. Unknown tools pass through —
241
- * the engine's 24K truncation is still the backstop.
242
- */
243
- export function projectSnapshot(toolId, payload, params = {}) {
244
- switch (toolId) {
245
- case "console":
246
- return projectConsole(payload, params);
247
- case "network":
248
- return projectNetwork(payload, params);
249
- case "route-events":
250
- return projectRoutes(payload, params);
251
- case "env":
252
- return projectEnv(payload);
253
- case "sentry":
254
- return projectSentry(payload, params);
255
- default:
256
- return payload;
257
- }
258
- }
259
- //# sourceMappingURL=snapshotReads.js.map
1
+ "use strict";import{isSelfTraffic as y}from"../policy/redact";export const SNAPSHOT_ACTION="getSnapshot";const m={verbose:0,debug:0,trace:0,log:1,info:1,warn:2,warning:2,error:3};function l(e){return Array.isArray(e)?e:[]}function u(e){return e&&typeof e==="object"?e:{}}function d(e,t){return typeof e==="number"&&e>0?e:t}function h(e,t){return e.length<=t?e:e.slice(0,t)}function v(e,t){const o=l(u(e).entries);const c=typeof t.level==="string"?m[t.level]??0:0;const i=typeof t.pattern==="string"?t.pattern.toLowerCase():void 0;const a=o.filter(f=>{const n=u(f);const r=String(n.level??"log");if((m[r]??1)<c)return false;if(!i)return true;return String(n.message??"").toLowerCase().includes(i)});const p=h(a,d(t.limit,40));return{totalCaptured:o.length,shown:p.length,entries:p.map(f=>{const n=u(f);return{at:n.timestamp,level:n.level,message:n.message}})}}function w(e,t){const o=u(e);const c=l(o.events).filter(n=>!y(u(n).url));const i=t.failedOnly===true;const a=typeof t.pattern==="string"?t.pattern.toLowerCase():void 0;const p=c.filter(n=>{const r=u(n);const s=typeof r.status==="number"?r.status:void 0;if(i&&!(r.error||s!==void 0&&s>=400))return false;if(!a)return true;return String(r.url??"").toLowerCase().includes(a)});const f=h(p,d(t.limit,25));return{totalCaptured:c.length,shown:f.length,requests:f.map(n=>{const r=u(n);return{id:r.id,method:r.method,url:r.url,status:r.status,durationMs:r.duration,error:r.error,overridden:r.override?true:void 0}}),hint:"Read one response with network.getEventBody({ id })."}}function g(e,t=[],o=80){for(const c of l(e)){if(t.length>=o)break;const i=u(c);if(i.isInternal!==true&&typeof i.path==="string")t.push(i.path);g(i.children,t,o)}return t}function C(e,t){const o=u(e);const c=u(o.sitemap);const i=l(o.stack).map(u);const a=l(o.events).map(u);const p=i.map(s=>({name:s.name,path:s.pathname,focused:s.isFocused===true?true:void 0}));const f=a.slice(0,d(t.limit,15)).map(s=>({at:s.timestamp,from:s.previousPathname,to:s.pathname}));const n=i.find(s=>s.isFocused===true)??i[i.length-1];const r=a.length?{path:a[0].pathname,source:"event"}:typeof n?.pathname==="string"?{path:n.pathname,source:"stack"}:void 0;return{currentRoute:r,stack:p,routes:g(c.routes),sitemapSource:c.source,recentNavigations:f}}function S(e){const t=u(e);return{env:t.env??t.variables,requiredEnvVars:t.requiredEnvVars}}function k(e,t){const o=u(e);const c=l(o.envelopes).map(u);const i=typeof t.type==="string"?t.type:void 0;const a=typeof t.pattern==="string"?t.pattern.toLowerCase():void 0;const p=c.filter(n=>{const r=l(n.items).map(u);if(i&&!r.some(s=>s.type===i))return false;if(!a)return true;return r.some(s=>String(s.summary??"").toLowerCase().includes(a))});const f=h(p,d(t.limit,10));return{status:o.status,totalCaptured:c.length,shown:f.length,envelopes:f.map(n=>({id:n.id,at:n.timestamp,origin:n.origin,eventId:n.eventId,totalBytes:n.totalBytes,items:l(n.items).map(r=>{const s=u(r);return{type:s.type,summary:s.summary,spanCount:s.spanCount,bytes:s.bytes}})})),hint:"For crash stack traces, console's [FATAL] entries carry the component stacks."}}export function projectSnapshot(e,t,o={}){switch(e){case"console":return v(t,o);case"network":return w(t,o);case"route-events":return C(t,o);case"env":return S(t);case"sentry":return k(t,o);default:return t}}