@buoy-gg/scenarios 0.0.0-stage → 7.0.76

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 (92) hide show
  1. package/LICENSE +58 -0
  2. package/README.md +78 -2
  3. package/lib/commonjs/catalog.js +1 -0
  4. package/lib/commonjs/components/ActiveCard.js +1 -0
  5. package/lib/commonjs/components/DeactivateReportCard.js +1 -0
  6. package/lib/commonjs/components/FolderPickerScreen.js +1 -0
  7. package/lib/commonjs/components/MacroReviewScreen.js +1 -0
  8. package/lib/commonjs/components/PreviewScreen.js +1 -0
  9. package/lib/commonjs/components/RecordingBanner.js +1 -0
  10. package/lib/commonjs/components/RunProgressScreen.js +1 -0
  11. package/lib/commonjs/components/ScenarioBanner.js +1 -0
  12. package/lib/commonjs/components/ScenarioDetailScreen.js +1 -0
  13. package/lib/commonjs/components/ScenarioFolderBar.js +1 -0
  14. package/lib/commonjs/components/ScenarioRow.js +1 -0
  15. package/lib/commonjs/components/ScenariosBody.js +1 -0
  16. package/lib/commonjs/components/ScenariosToolView.js +1 -0
  17. package/lib/commonjs/defineScenario.js +1 -0
  18. package/lib/commonjs/engine.js +1 -0
  19. package/lib/commonjs/folders.js +1 -0
  20. package/lib/commonjs/hooks/useScenarios.js +1 -0
  21. package/lib/commonjs/index.js +1 -0
  22. package/lib/commonjs/interpolate.js +1 -0
  23. package/lib/commonjs/package.json +1 -0
  24. package/lib/commonjs/preset.js +1 -0
  25. package/lib/commonjs/record/condense.js +1 -0
  26. package/lib/commonjs/record/recorderStore.js +1 -0
  27. package/lib/commonjs/record/types.js +1 -0
  28. package/lib/commonjs/store/scenariosStore.js +1 -0
  29. package/lib/commonjs/sync/scenariosSyncAdapter.js +1 -0
  30. package/lib/commonjs/types.js +1 -0
  31. package/lib/commonjs/ui/primitives.js +1 -0
  32. package/lib/commonjs/ui/scnTheme.js +1 -0
  33. package/lib/module/catalog.js +1 -0
  34. package/lib/module/components/ActiveCard.js +1 -0
  35. package/lib/module/components/DeactivateReportCard.js +1 -0
  36. package/lib/module/components/FolderPickerScreen.js +1 -0
  37. package/lib/module/components/MacroReviewScreen.js +1 -0
  38. package/lib/module/components/PreviewScreen.js +1 -0
  39. package/lib/module/components/RecordingBanner.js +1 -0
  40. package/lib/module/components/RunProgressScreen.js +1 -0
  41. package/lib/module/components/ScenarioBanner.js +1 -0
  42. package/lib/module/components/ScenarioDetailScreen.js +1 -0
  43. package/lib/module/components/ScenarioFolderBar.js +1 -0
  44. package/lib/module/components/ScenarioRow.js +1 -0
  45. package/lib/module/components/ScenariosBody.js +1 -0
  46. package/lib/module/components/ScenariosToolView.js +1 -0
  47. package/lib/module/defineScenario.js +1 -0
  48. package/lib/module/engine.js +1 -0
  49. package/lib/module/folders.js +1 -0
  50. package/lib/module/hooks/useScenarios.js +1 -0
  51. package/lib/module/index.js +1 -0
  52. package/lib/module/interpolate.js +1 -0
  53. package/lib/module/preset.js +1 -0
  54. package/lib/module/record/condense.js +1 -0
  55. package/lib/module/record/recorderStore.js +1 -0
  56. package/lib/module/record/types.js +1 -0
  57. package/lib/module/store/scenariosStore.js +1 -0
  58. package/lib/module/sync/scenariosSyncAdapter.js +1 -0
  59. package/lib/module/types.js +1 -0
  60. package/lib/module/ui/primitives.js +1 -0
  61. package/lib/module/ui/scnTheme.js +1 -0
  62. package/lib/typescript/catalog.d.ts +81 -0
  63. package/lib/typescript/components/ActiveCard.d.ts +24 -0
  64. package/lib/typescript/components/DeactivateReportCard.d.ts +15 -0
  65. package/lib/typescript/components/FolderPickerScreen.d.ts +23 -0
  66. package/lib/typescript/components/MacroReviewScreen.d.ts +46 -0
  67. package/lib/typescript/components/PreviewScreen.d.ts +30 -0
  68. package/lib/typescript/components/RecordingBanner.d.ts +30 -0
  69. package/lib/typescript/components/RunProgressScreen.d.ts +21 -0
  70. package/lib/typescript/components/ScenarioBanner.d.ts +33 -0
  71. package/lib/typescript/components/ScenarioDetailScreen.d.ts +20 -0
  72. package/lib/typescript/components/ScenarioFolderBar.d.ts +34 -0
  73. package/lib/typescript/components/ScenarioRow.d.ts +32 -0
  74. package/lib/typescript/components/ScenariosBody.d.ts +26 -0
  75. package/lib/typescript/components/ScenariosToolView.d.ts +13 -0
  76. package/lib/typescript/defineScenario.d.ts +48 -0
  77. package/lib/typescript/engine.d.ts +76 -0
  78. package/lib/typescript/folders.d.ts +51 -0
  79. package/lib/typescript/hooks/useScenarios.d.ts +15 -0
  80. package/lib/typescript/index.d.ts +32 -0
  81. package/lib/typescript/interpolate.d.ts +29 -0
  82. package/lib/typescript/preset.d.ts +56 -0
  83. package/lib/typescript/record/condense.d.ts +131 -0
  84. package/lib/typescript/record/recorderStore.d.ts +63 -0
  85. package/lib/typescript/record/types.d.ts +140 -0
  86. package/lib/typescript/store/scenariosStore.d.ts +166 -0
  87. package/lib/typescript/sync/scenariosSyncAdapter.d.ts +342 -0
  88. package/lib/typescript/types.d.ts +196 -0
  89. package/lib/typescript/ui/primitives.d.ts +74 -0
  90. package/lib/typescript/ui/scnTheme.d.ts +68 -0
  91. package/lib/web/index.mjs +2 -0
  92. package/package.json +100 -3
package/LICENSE ADDED
@@ -0,0 +1,58 @@
1
+ PROPRIETARY SOFTWARE LICENSE
2
+
3
+ Copyright (c) 2024-present Buoy. All rights reserved.
4
+
5
+ This software and its source code are proprietary and confidential.
6
+
7
+ NOTICE: This is NOT open source software. This software is licensed,
8
+ not sold, and is protected by copyright laws and international treaties.
9
+
10
+ TERMS AND CONDITIONS:
11
+
12
+ 1. LICENSE GRANT
13
+ Subject to the terms of this Agreement and payment of applicable fees,
14
+ Buoy grants you a limited, non-exclusive, non-transferable license
15
+ to use the compiled software packages in your applications.
16
+
17
+ 2. RESTRICTIONS
18
+ You may NOT:
19
+ - Copy, modify, or distribute the source code
20
+ - Reverse engineer, decompile, or disassemble the software
21
+ - Remove or alter any proprietary notices or labels
22
+ - Sublicense, rent, lease, or lend the software
23
+ - Use the software to create competing products
24
+ - Share access credentials with unauthorized parties
25
+
26
+ 3. OWNERSHIP
27
+ React Buoy retains all right, title, and interest in the software,
28
+ including all intellectual property rights. This license does not
29
+ grant you any rights to trademarks or service marks.
30
+
31
+ 4. TERMINATION
32
+ This license is effective until terminated. Your rights under this
33
+ license will terminate automatically without notice if you fail to
34
+ comply with any of its terms. Upon termination, you must cease all
35
+ use and destroy all copies of the software.
36
+
37
+ 5. DISCLAIMER OF WARRANTIES
38
+ THE SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
39
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
40
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
41
+
42
+ 6. LIMITATION OF LIABILITY
43
+ IN NO EVENT SHALL BUOY BE LIABLE FOR ANY INDIRECT, INCIDENTAL,
44
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN
45
+ CONNECTION WITH THIS LICENSE OR THE USE OF THE SOFTWARE.
46
+
47
+ 7. GOVERNING LAW
48
+ This Agreement shall be governed by and construed in accordance with
49
+ the laws of the United States, without regard to its conflict of
50
+ law provisions.
51
+
52
+ For licensing inquiries and subscription information:
53
+ - Website: https://buoy.gg
54
+ - Email: AustinLovesWorking@gmail.com
55
+
56
+ Unauthorized reproduction or distribution of this software, or any
57
+ portion of it, may result in severe civil and criminal penalties,
58
+ and will be prosecuted to the maximum extent possible under the law.
package/README.md CHANGED
@@ -1,3 +1,79 @@
1
- # Temporary Holding Version
1
+ # @buoy-gg/scenarios
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Define repeatable test setups using actions from installed Buoy tools. A scenario can configure response overrides, edit storage, select a test user, or navigate. Review its steps and expected outcome before running it.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @buoy-gg/core @buoy-gg/scenarios @buoy-gg/network @buoy-gg/route-events
9
+ ```
10
+
11
+ ## Account setup
12
+
13
+ Start in a development build with a Free or Pro Buoy account key. From the app directory:
14
+
15
+ ```bash
16
+ npx --package=@buoy-gg/core buoy login
17
+ ```
18
+
19
+ For Expo, initialize Buoy with the key written to `.env.local`:
20
+
21
+ ```tsx
22
+ import { Buoy } from "@buoy-gg/core";
23
+
24
+ Buoy.init({ licenseKey: process.env.EXPO_PUBLIC_BUOY_KEY });
25
+ ```
26
+
27
+ For React Native CLI, pass the key through your app's environment configuration; `.env.local` is not loaded automatically. Keep the menu inside the providers used by your app. Restart the development server after installing packages. See the [Quick Start](https://buoy.gg/buoy/latest/docs/quick-start) for the complete root component.
28
+
29
+ ## Define a scenario
30
+
31
+ This integration fragment assumes your app has a matching menu endpoint and `/cart` route. Adapt the URL pattern, response body, route, and build label to your app, then render this menu inside your existing providers:
32
+
33
+ ```tsx
34
+ import { FloatingDevTools } from "@buoy-gg/core";
35
+ import { defineScenario, createScenariosTool } from "@buoy-gg/scenarios";
36
+
37
+ const outOfStock = defineScenario({
38
+ id: "oos-item",
39
+ name: "Out-of-stock item at store {{storeId}}",
40
+ expectedOutcome: "Cart shows the item sold out; checkout is blocked.",
41
+ authoredAgainst: "5.4.0",
42
+ vars: [
43
+ { key: "storeId", type: "enum", options: ["100", "220"], default: "100" },
44
+ ],
45
+ steps: [
46
+ { tool: "network", action: "upsertOverrideRule",
47
+ params: { rule: {
48
+ urlPattern: "*/menu/{{storeId}}*", methods: ["GET"],
49
+ kind: "respond", status: 200, body: '{"items":[{"id":"dbl","inStock":false}]}',
50
+ } } },
51
+ { tool: "route-events", action: "navigate", params: { path: "/cart" } },
52
+ ],
53
+ });
54
+
55
+ <FloatingDevTools
56
+ apps={[createScenariosTool({ scenarios: [outOfStock], currentBuild: "5.4.0" })]}
57
+ />
58
+ ```
59
+ Code-defined scenarios are read-only on the device. Install and configure every tool referenced by a step; declaring a step does not implement that tool's app integration.
60
+
61
+ ## Check activation and deactivation
62
+
63
+ Preview the scenario, supply its variables, and resolve any preflight errors. Run it in a development build, trigger the affected app request, and check the expected screen. Deactivate it and confirm that normal behavior returns.
64
+
65
+ Preflight validates known requirements before execution. Runtime failures can still leave partial effects; it is not a transaction across your app and backend. Review the result of each step.
66
+
67
+ The runner removes supported active overrides and impersonation effects during deactivation. Storage writes need explicit undo steps to restore prior values. Inspect reported irreversible effects and test cleanup as carefully as activation. Conflicting scenarios may require replacing the active setup; do not assume arbitrary scenarios can run together.
68
+
69
+ Remote drafts require acceptance on the device before they can run. The runner refuses release builds, including with Pro. See the [Scenarios guide](https://buoy.gg/buoy/latest/docs/tools/scenarios) for variables, drafts, previews, and undo steps.
70
+
71
+ ## Desktop and MCP
72
+
73
+ React Native connections require `@buoy-gg/external-sync`. Follow the [Desktop connection guide](https://buoy.gg/buoy/latest/docs/desktop), sign in to Desktop separately, and confirm the selected device. [MCP](https://buoy.gg/buoy/latest/docs/mcp) also needs a process account and Pro access.
74
+
75
+ Device data can travel over your LAN to the configured broker. Account validation makes network requests. See [Telemetry](https://buoy.gg/buoy/latest/docs/telemetry) for data-flow details.
76
+
77
+ ## Web support (unreleased)
78
+
79
+ Register this package’s /web namespace in FloatingDevTools modules to use its shared panels and actions in a browser app. The browser build is available in this checkout and has not been published yet. See the [web setup guide](https://buoy.gg/buoy/latest/docs/web-preview) for registration, dependencies, and browser boundaries.
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.STEP_CATALOG=exports.SCENARIO_TOOL=exports.DURABILITY_LABEL=void 0;exports.catalogEntry=catalogEntry;exports.conflictKeysOverlap=conflictKeysOverlap;exports.describeStep=describeStep;exports.isAdvancedStep=isAdvancedStep;exports.stepConflictKeys=stepConflictKeys;exports.stepDurability=stepDurability;const SCENARIO_TOOL=exports.SCENARIO_TOOL="scenario";const str=(e,t="")=>typeof e==="string"?e:e==null?t:String(e);function rule(e){const t=e.rule;return t&&typeof t==="object"?t:e}function describeOverride(e){const t=rule(e);const r=Array.isArray(t.methods)?t.methods.join("/"):"any";const o=str(t.urlPattern,"(no pattern)");const i=str(t.kind,"respond");if(i==="fail"){return`${r} ${o} \u2192 fail (${str(t.failKind,"network")})`}if(i==="delay")return`${r} ${o} \u2192 delay ${t.delayMs??0}ms`;const n=typeof t.status==="number"?t.status:200;const s=t.body!=null?", replaced body":"";return`${r} ${o} \u2192 respond ${n}${s}`}const STEP_CATALOG=exports.STEP_CATALOG=[{tool:"network",action:"upsertOverrideRule",title:"Override a request",durability:"durable",describe:describeOverride,conflictKeys:e=>{const t=rule(e);const r=str(t.urlPattern);return r?[`net:${r}`]:[]}},{tool:"network",action:"deleteOverrideRule",title:"Remove an override",durability:"one-shot",describe:e=>`Remove override rule ${str(e.id,"?")}`},{tool:"network",action:"setOverridesEnabled",title:"Toggle all overrides",durability:"session",describe:e=>`Turn overrides ${e.enabled===false?"off":"on"}`},{tool:"storage",action:"async.setItem",title:"Set storage value",durability:"durable",describe:e=>`Set storage ${str(e.key,"?")}`,conflictKeys:e=>e.key?[`storage:${str(e.key)}`]:[]},{tool:"storage",action:"async.removeItem",title:"Remove storage key",durability:"durable",describe:e=>`Remove storage ${str(e.key,"?")}`,conflictKeys:e=>e.key?[`storage:${str(e.key)}`]:[]},{tool:"storage",action:"async.multiSet",title:"Set several storage values",durability:"durable",describe:e=>{const t=Array.isArray(e.pairs)?e.pairs.length:0;return`Set ${t} storage key${t===1?"":"s"}`},conflictKeys:e=>Array.isArray(e.pairs)?e.pairs.map(t=>Array.isArray(t)?`storage:${str(t[0])}`:"").filter(Boolean):[]},{tool:"storage",action:"mmkv.set",title:"Set MMKV value",durability:"durable",describe:e=>`Set MMKV ${str(e.key,"?")}`,conflictKeys:e=>e.key?[`mmkv:${str(e.key)}`]:[]},{tool:"impersonate",action:"startImpersonation",title:"Impersonate a user",durability:"durable",describe:e=>{const t=e.user;const r=str(t?.name)||str(t?.email)||str(t?.id)||"a user";return`Impersonate ${r}`},conflictKeys:()=>["impersonation"]},{tool:"impersonate",action:"stopImpersonation",title:"Stop impersonating",durability:"one-shot",describe:()=>"Stop impersonating",conflictKeys:()=>["impersonation"]},{tool:"route-events",action:"navigate",title:"Go to a screen",durability:"one-shot",describe:e=>`${e.replace?"Replace with":"Go to"} ${str(e.path,"?")}`},{tool:"query",action:"setQueryData",title:"Poke the query cache",durability:"transient",describe:e=>`Poke ${str(e.queryKey,"?")} cache (until next refetch)`},{tool:"query",action:"invalidate",title:"Refetch queries",durability:"one-shot",describe:e=>`Refetch ${str(e.queryKey,"all queries")}`},{tool:"time-machine",action:"restore",title:"Restore a snapshot",durability:"durable",describe:e=>`Restore snapshot ${str(e.id,"?")}`},{tool:SCENARIO_TOOL,action:"wait",title:"Wait",durability:"one-shot",describe:e=>`Wait ${typeof e.ms==="number"?e.ms:0}ms`},{tool:"highlight-updates",action:"tapElement",title:"Tap something on screen",durability:"one-shot",describe:e=>{const t=str(e.testID)||str(e.query)||"an element";if(typeof e.text==="string")return`Type \u201C${e.text}\u201D into ${t}`;if(e.value!==void 0)return`Set ${t} to ${JSON.stringify(e.value)}`;if(e.longPress)return`Press and hold \u201C${t}\u201D`;return`Tap \u201C${t}\u201D`}},{tool:SCENARIO_TOOL,action:"waitFor",title:"Wait for a screen",durability:"one-shot",describe:e=>e.route?`Wait for ${str(e.route)}`:`Wait for \u201C${str(e.element,"?")}\u201D`},{tool:"zustand",action:"setState",title:"Set a store's state",durability:e=>e.persisted?"durable":"session",describe:e=>`Set ${str(e.storeName,"a store")}`,conflictKeys:e=>e.storeName?[`zustand:${str(e.storeName)}`]:[]}];const BY_KEY=new Map(STEP_CATALOG.map(e=>[`${e.tool}.${e.action}`,e]));function catalogEntry(e,t){return BY_KEY.get(`${e}.${t}`)}function describeStep(e,t){if(e.label)return e.label;const r=catalogEntry(e.tool,e.action);const o=t??e.params??{};if(!r)return`${e.tool}.${e.action}`;try{return r.describe(o)}catch{return`${e.tool}.${e.action}`}}function stepDurability(e){const t=catalogEntry(e.tool,e.action);if(!t)return"one-shot";if(typeof t.durability!=="function")return t.durability;try{return t.durability(e.params??{})}catch{return"one-shot"}}function isAdvancedStep(e){return!e.label&&!catalogEntry(e.tool,e.action)}function stepConflictKeys(e,t){const r=catalogEntry(e.tool,e.action);if(!r?.conflictKeys)return[];try{return r.conflictKeys(t??e.params??{})}catch{return[]}}function conflictKeysOverlap(e,t){if(e===t)return true;const r="net:";if(!e.startsWith(r)||!t.startsWith(r))return false;const o=e.slice(r.length);const i=t.slice(r.length);return patternMatchesProbe(o,i)||patternMatchesProbe(i,o)}function patternMatchesProbe(e,t){try{const r=e.replace(/[[\]{}()\\.^$+|\-,?]/g,"\\$&").split("*").join(".*");const o=t.split("*").join("x");return new RegExp(`^${r}$`).test(o)}catch{return false}}const DURABILITY_LABEL=exports.DURABILITY_LABEL={durable:"survives refresh & restart",session:"until the app restarts",transient:"until next refetch","one-shot":"one-shot"};
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ActiveCard=ActiveCard;exports.reproBlock=reproBlock;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _scnTheme=require("../ui/scnTheme");var _primitives=require("../ui/primitives");var _jsxRuntime=require("react/jsx-runtime");function effectDurability(e){switch(e.kind){case"override-rule":return{label:"survives restart",tone:"durable"};case"impersonation":return{label:"survives restart",tone:"durable"};case"storage-write":return{label:"not auto-undone",tone:"transient"};default:return{label:"one-shot",tone:"neutral"}}}function reproBlock(e,t){const n=Object.entries(e.varValues).map(([r,o])=>`${r}=${String(o)}`).join(", ");return["\u2014 Bug report context (Buoy Scenarios) \u2014",`Scenario: ${e.name} (v${e.version}, ${e.source})`,`Variables: ${n||"none"}`,`Active since: ${new Date(e.runAt).toISOString()}`,t?`App build: ${t}`:null,`Effects: ${e.effects.map(r=>r.label).join(" \xB7 ")}`].filter(Boolean).join("\n")}function ActiveCard({active:e,build:t,busy:n,onDeactivate:r,onRerun:o,onCopied:i}){const[l]=(0,_react.useState)(()=>Math.max(1,Math.round((Date.now()-e.runAt)/6e4)));const c=(0,_react.useCallback)(()=>{void(0,_sharedUi.copyToClipboard)(reproBlock(e,t));i?.()},[e,t,i]);return(0,_jsxRuntime.jsxs)(_primitives.Panel,{tone:"sim",testID:"scenario-active-card",children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.head,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.dot}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.headText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.simulated,children:"SIMULATED"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.name,numberOfLines:2,testID:"scenario-active-name",children:e.name})]}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.ago,children:[l,"m ago"]})]}),(0,_jsxRuntime.jsx)(_primitives.PanelSeparator,{}),e.effects.map((s,d)=>{const a=effectDurability(s);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.effect,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.effectText,numberOfLines:1,children:s.label}),(0,_jsxRuntime.jsx)(_primitives.DurabilityChip,{label:a.label,tone:a.tone})]},`${s.kind}-${d}`)}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.actions,children:[(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Deactivate",variant:"warning",size:"small",onPress:r,disabled:n,icon:(0,_jsxRuntime.jsx)(_sharedUi.Power,{size:11,color:_scnTheme.scn.color.sim}),testID:"scenario-deactivate"}),(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Copy repro info",variant:"ghost",size:"small",onPress:c,icon:(0,_jsxRuntime.jsx)(_sharedUi.Copy,{size:11,color:_scnTheme.scn.color.textSecondary}),testID:"scenario-copy-repro"}),(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Re-run",variant:"ghost",size:"small",onPress:o,disabled:n,icon:(0,_jsxRuntime.jsx)(_sharedUi.RefreshCw,{size:11,color:_scnTheme.scn.color.textSecondary}),testID:"scenario-rerun"})]})]})}const styles=_reactNative.StyleSheet.create({head:{flexDirection:"row",alignItems:"flex-start",gap:8,paddingHorizontal:_scnTheme.scn.textInset,paddingTop:10,paddingBottom:10},dot:{width:8,height:8,borderRadius:4,backgroundColor:_scnTheme.scn.color.sim,marginTop:4},headText:{flex:1,minWidth:0},simulated:{color:_scnTheme.scn.color.sim,fontSize:_scnTheme.scn.font.micro,fontWeight:"700",letterSpacing:.8,fontFamily:_scnTheme.SCN_MONO},name:{color:_scnTheme.scn.color.text,fontSize:_scnTheme.scn.font.row,fontWeight:"600",marginTop:2},ago:{color:_scnTheme.scn.color.textTertiary,fontSize:_scnTheme.scn.font.micro,fontFamily:_scnTheme.SCN_MONO,marginTop:2},effect:{flexDirection:"row",alignItems:"center",gap:8,paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:7},effectText:{flex:1,minWidth:0,color:_scnTheme.scn.color.textSecondary,fontSize:_scnTheme.scn.font.control,fontFamily:_scnTheme.SCN_MONO},actions:{flexDirection:"row",flexWrap:"wrap",gap:6,paddingHorizontal:_scnTheme.scn.textInset,paddingTop:8,paddingBottom:10}});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.DeactivateReportCard=DeactivateReportCard;var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _scnTheme=require("../ui/scnTheme");var _primitives=require("../ui/primitives");var _jsxRuntime=require("react/jsx-runtime");function DeactivateReportCard({report:e,onDismiss:o}){const t=[];if(e.removedRules){t.push({tone:"ok",text:`${e.removedRules} override rule${e.removedRules===1?"":"s"} removed \u2014 pull to refresh shows real data`})}if(e.stoppedImpersonation){t.push({tone:"ok",text:"Impersonation ended"})}if(e.clearedTransients){t.push({tone:"ok",text:`${e.clearedTransients} one-shot effect${e.clearedTransients===1?"":"s"} had nothing to remove`})}if(e.undoStepsRan){t.push({tone:"ok",text:`${e.undoStepsRan} undo step${e.undoStepsRan===1?"":"s"} ran`})}if(e.unrestoredStorageKeys.length){t.push({tone:"warn",text:`${e.unrestoredStorageKeys.length} storage key${e.unrestoredStorageKeys.length===1?"":"s"} NOT restored: ${e.unrestoredStorageKeys.join(", ")} \u2014 a storage write has no automatic inverse. Re-run your login flow, or restore a Time Machine snapshot.`})}const n=e.unrestoredState??[];if(n.length){t.push({tone:"warn",text:`${n.length} store${n.length===1?"":"s"} still hold${n.length===1?"s":""} what this scenario wrote: ${n.join(", ")} \u2014 a state write has no automatic inverse. Reset it in its own tool, or restore a Time Machine snapshot.`})}for(const s of e.errors){t.push({tone:"warn",text:s})}if(!t.length){t.push({tone:"ok",text:"Nothing left to undo \u2014 the app is real."})}const r=t.every(s=>s.tone==="ok");return(0,_jsxRuntime.jsx)(_primitives.Panel,{tone:r?"neutral":"sim",children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.body,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.title,testID:"scenario-deactivate-report",children:"DEACTIVATED"}),t.map((s,i)=>(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.line,children:[s.tone==="ok"?(0,_jsxRuntime.jsx)(_sharedUi.Check,{size:12,color:_scnTheme.scn.color.accent}):(0,_jsxRuntime.jsx)(_sharedUi.AlertTriangle,{size:12,color:_scnTheme.scn.color.sim}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.text,children:s.text})]},`${s.tone}-${i}`)),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.actions,children:(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Done",variant:"primary",size:"small",onPress:o,testID:"scenario-dismiss-report"})})]})})}const styles=_reactNative.StyleSheet.create({body:{padding:_scnTheme.scn.textInset,gap:8},title:{color:_scnTheme.scn.color.textSecondary,fontSize:_scnTheme.scn.font.micro,fontWeight:"700",letterSpacing:.8,fontFamily:_scnTheme.SCN_MONO},line:{flexDirection:"row",gap:8,alignItems:"flex-start"},text:{flex:1,color:_scnTheme.scn.color.textSecondary,fontSize:_scnTheme.scn.font.control,lineHeight:17},actions:{flexDirection:"row",marginTop:2}});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.FolderPickerScreen=FolderPickerScreen;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _core=require("@buoy-gg/core");var _folders=require("../folders");var _scnTheme=require("../ui/scnTheme");var _primitives=require("../ui/primitives");var _ScenarioRow=require("./ScenarioRow");var _jsxRuntime=require("react/jsx-runtime");function FolderPickerScreen({scenario:o,folders:n,onPick:e,onBack:s}){const[i,l]=(0,_react.useState)("");(0,_core.useToolHeader)({title:"Move to folder",subtitle:(0,_ScenarioRow.displayName)(o.name),onBack:s,searchable:false},[o.id]);const a=(0,_folders.normalizeFolder)(o.folder);const r=(0,_folders.normalizeFolder)(i);const c=!!r&&!n.some(t=>t.toLowerCase()===r.toLowerCase());return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.fill,contentContainerStyle:styles.content,keyboardShouldPersistTaps:"handled",testID:"scenario-folder-scroll",children:[(0,_jsxRuntime.jsx)(_primitives.SectionLabel,{icon:_sharedUi.Bookmark,count:n.length,children:"Folders"}),(0,_jsxRuntime.jsxs)(_primitives.Panel,{children:[(0,_jsxRuntime.jsx)(FolderRow,{label:"No folder",hint:"Shows under Ungrouped",selected:!a,onPress:()=>e(void 0),testID:"scenario-folder-none"}),n.map(t=>(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[(0,_jsxRuntime.jsx)(_primitives.PanelSeparator,{}),(0,_jsxRuntime.jsx)(FolderRow,{label:t,selected:!!a&&a.toLowerCase()===t.toLowerCase(),onPress:()=>e(t),testID:`scenario-folder-pick-${t.toLowerCase().replace(/\s+/g,"-")}`})]},t))]}),(0,_jsxRuntime.jsx)(_primitives.SectionLabel,{icon:_sharedUi.Plus,children:"New folder"}),(0,_jsxRuntime.jsx)(_primitives.Panel,{children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.newRow,children:[(0,_jsxRuntime.jsx)(_reactNative.TextInput,{style:styles.input,value:i,onChangeText:l,placeholder:"Checkout",placeholderTextColor:_scnTheme.scn.color.textTertiary,maxLength:_folders.MAX_FOLDER_LENGTH,autoCapitalize:"words",autoCorrect:false,returnKeyType:"done",onSubmitEditing:()=>r&&e(r),testID:"scenario-folder-new-input"}),(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:r&&!c?"Use":"Create",variant:"primary",size:"small",disabled:!r,onPress:()=>r&&e(r),testID:"scenario-folder-create"})]})}),(0,_jsxRuntime.jsx)(_primitives.Footnote,{children:"A folder exists as long as something is filed in it \u2014 empty it and it goes away. Typing a name that already exists files it there instead of making a second one."})]})}function FolderRow({label:o,hint:n,selected:e,onPress:s,testID:i}){return(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{style:styles.row,onPress:s,activeOpacity:.7,accessibilityRole:"button",accessibilityState:{selected:e},accessibilityLabel:`File under ${o}`,testID:i,children:[(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.rowLabel,e&&styles.rowLabelSelected],numberOfLines:1,children:o}),n?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.rowHint,children:n}):null]}),e?(0,_jsxRuntime.jsx)(_sharedUi.Check,{size:14,color:_scnTheme.scn.color.accent}):null]})}const styles=_reactNative.StyleSheet.create({fill:{flex:1,backgroundColor:"transparent"},content:{paddingBottom:32},row:{flexDirection:"row",alignItems:"center",gap:12,minHeight:_scnTheme.scn.rowMinHeight,paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:10},rowText:{flex:1,minWidth:0},rowLabel:{color:_scnTheme.scn.color.text,fontSize:_scnTheme.scn.font.row},rowLabelSelected:{color:_scnTheme.scn.color.accent,fontWeight:"600"},rowHint:{color:_scnTheme.scn.color.textTertiary,fontSize:_scnTheme.scn.font.micro,marginTop:2},newRow:{flexDirection:"row",alignItems:"center",gap:8,paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:10},input:{flex:1,backgroundColor:_scnTheme.scn.color.row,borderRadius:_scnTheme.scn.radius.row,borderWidth:1,borderColor:_scnTheme.scn.color.border,color:_scnTheme.scn.color.text,fontSize:_scnTheme.scn.font.row,fontFamily:_scnTheme.SCN_MONO,paddingHorizontal:10,paddingVertical:8}});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.MacroReviewScreen=MacroReviewScreen;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _core=require("@buoy-gg/core");var _condense=require("../record/condense");var _catalog=require("../catalog");var _scnTheme=require("../ui/scnTheme");var _primitives=require("../ui/primitives");var _jsxRuntime=require("react/jsx-runtime");function MacroReviewScreen({draft:e,onChange:n,onSave:a,onDiscard:i,busy:l}){const s=(0,_sharedUi.useSafeAreaInsets)({minBottom:16});const[d,y]=(0,_react.useState)(()=>(0,_condense.suggestMacroName)(e));const m=(0,_react.useRef)(i);m.current=i;const f=(0,_react.useCallback)(()=>m.current(),[]);(0,_core.useToolHeader)({title:"Review recording",onBack:f,searchable:false},[]);const g=(0,_react.useMemo)(()=>e.filter(t=>t.enabled&&!t.noise),[e]);const c=(0,_react.useMemo)(()=>e.filter(t=>t.noise),[e]);const h=(0,_react.useMemo)(()=>(0,_condense.fastForwardIndex)(e),[e]);const b=(0,_react.useMemo)(()=>{let t=0;return e.map(o=>o.precondition?0:++t)},[e]);const w=(0,_react.useCallback)((t,o)=>{n(e.map(x=>x.id===t?{...x,...o}:x))},[e,n]);const r=(0,_react.useMemo)(()=>(0,_condense.macroToSteps)(e),[e]);const u=(0,_react.useMemo)(()=>r.filter(t=>t.tool===_catalog.SCENARIO_TOOL&&t.action==="waitFor").length,[r]);const p=g.length-(r.length-u);return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.fill,contentContainerStyle:[styles.content,{paddingBottom:s.bottom}],keyboardShouldPersistTaps:"handled",testID:"macro-review-scroll",children:[(0,_jsxRuntime.jsx)(_primitives.SectionLabel,{icon:_sharedUi.Bookmark,children:"Name"}),(0,_jsxRuntime.jsx)(_primitives.Panel,{children:(0,_jsxRuntime.jsx)(_reactNative.TextInput,{style:styles.nameInput,value:d,onChangeText:y,placeholder:"Bag with a Charizard in it",placeholderTextColor:_scnTheme.scn.color.textTertiary,maxLength:80,returnKeyType:"done",testID:"macro-name-input"})}),(0,_jsxRuntime.jsx)(_primitives.SectionLabel,{icon:_sharedUi.Zap,count:g.length,children:"Steps"}),h>=0?(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.modeBar,children:(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.reset,onPress:()=>n((0,_condense.replayAll)(e)),activeOpacity:.7,accessibilityRole:"button",accessibilityLabel:"Perform every step instead of starting partway",testID:"macro-replay-all",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.resetText,children:"\u21BA Perform every step"})})}):null,(0,_jsxRuntime.jsxs)(_primitives.Panel,{children:[e.map((t,o)=>(0,_jsxRuntime.jsxs)(_reactNative.View,{children:[o>0?(0,_jsxRuntime.jsx)(_primitives.PanelSeparator,{}):null,(0,_jsxRuntime.jsx)(StepRow,{step:t,index:b[o],before:o<=h,onStartHere:t.lanes.includes("state")&&!t.precondition?()=>n((0,_condense.fastForwardTo)(e,o)):void 0,onToggleEnabled:()=>w(t.id,{enabled:!t.enabled})}),o===h?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.startLine,testID:"macro-start-line",children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.startRule}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.startLabel,children:"the app starts here \xB7 the rest is performed"}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.startRule})]}):null]},t.id)),e.length===0?(0,_jsxRuntime.jsx)(_sharedUi.ToolEmptyState,{testID:"macro-review-empty",otto:"shrug",title:"Nothing was recorded",message:"Taps on Buoy's own controls are ignored on purpose \u2014 drive the app itself and try again."}):null]}),p>0?(0,_jsxRuntime.jsx)(_primitives.Notice,{tone:"info",testID:"macro-review-collapsed",children:(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.noticeText,children:[p," shortcut step",p===1?"":"s"," collapsed \u2014 consecutive writes to the same store save once, at the value they ended on."]})}):null,u>0?(0,_jsxRuntime.jsx)(_primitives.Notice,{tone:"info",testID:"macro-review-waits",children:(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.noticeText,children:["Saves as ",r.length," steps: ",u," of them wait for the screen a tap opened, so the replay never runs ahead of the app."]})}):null,c.length?(0,_jsxRuntime.jsx)(_primitives.Notice,{tone:"sim",testID:"macro-review-unnameable",children:(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.noticeText,children:[c.length," tap",c.length===1?"":"s"," landed on something with no testID, label or text, so it can't be found again. Add a testID to replay ",c.length===1?"it":"them","."]})}):null,(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.actions,children:[(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Discard",variant:"ghost",onPress:i,disabled:l,testID:"macro-discard"}),(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:`Save ${r.length} step${r.length===1?"":"s"}`,variant:"primary",disabled:l||!r.length||!d.trim(),onPress:()=>a(d.trim(),e),testID:"macro-save"})]}),(0,_jsxRuntime.jsx)(_primitives.Footnote,{children:"Every step is performed the way you did it, which keeps working when the app's internals change. Tap \u201CStart here\u201D on the step you actually want to test and everything before it is written instantly instead \u2014 the setup stops costing you a minute a run, and it survives those earlier screens being redesigned."})]})}function StepRow({step:e,index:n,before:a,onStartHere:i,onToggleEnabled:l}){const s=!e.enabled||e.noise;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.row,children:[(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{style:styles.rowMain,onPress:l,disabled:e.noise,activeOpacity:.7,accessibilityRole:"checkbox",accessibilityState:{checked:!s},accessibilityLabel:e.title,testID:`macro-step-${n}`,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.index,s&&styles.dim],children:e.precondition?"\u21B1":n}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.rowText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.title,s&&styles.dim,s&&styles.struck],numberOfLines:2,children:e.title}),e.detail?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.detail,numberOfLines:1,children:e.detail}):null]})]}),i&&!a?(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.startHere,onPress:i,activeOpacity:.7,accessibilityRole:"button",accessibilityLabel:`Start the macro here \u2014 everything up to \u201C${e.title}\u201D is set instantly`,testID:`macro-step-${n}-start-here`,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.startHereText,children:"Start here"})}):(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.laneStatic,a&&styles.laneStaticInstant],testID:`macro-step-${n}-lane`,children:e.precondition?"first":e.noise?"can\u2019t replay":a?e.lane==="state"?"instant":"skipped":"performed"})]})}const styles=_reactNative.StyleSheet.create({fill:{flex:1,backgroundColor:"transparent"},content:{paddingBottom:32},nameInput:{color:_scnTheme.scn.color.text,fontSize:_scnTheme.scn.font.row,paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:12},modeBar:{paddingHorizontal:_scnTheme.scn.gutter,paddingBottom:4},row:{flexDirection:"row",alignItems:"center",gap:8,paddingRight:_scnTheme.scn.textInset,minHeight:_scnTheme.scn.rowMinHeight},rowMain:{flex:1,minWidth:0,flexDirection:"row",alignItems:"center",gap:10,paddingLeft:_scnTheme.scn.textInset,paddingVertical:10},index:{color:_scnTheme.scn.color.textTertiary,fontSize:_scnTheme.scn.font.micro,fontWeight:"700",minWidth:14},rowText:{flex:1,minWidth:0},title:{color:_scnTheme.scn.color.text,fontSize:_scnTheme.scn.font.row,lineHeight:17},detail:{color:_scnTheme.scn.color.textTertiary,fontSize:_scnTheme.scn.font.micro,marginTop:2},dim:{color:_scnTheme.scn.color.textTertiary},struck:{textDecorationLine:"line-through"},startHere:{paddingHorizontal:8,paddingVertical:5,borderRadius:_scnTheme.scn.radius.pill,borderWidth:1,borderColor:_scnTheme.scn.color.border,backgroundColor:_scnTheme.scn.color.chip},startHereText:{color:_scnTheme.scn.color.textSecondary,fontSize:_scnTheme.scn.font.micro,fontWeight:"700"},laneStatic:{color:_scnTheme.scn.color.textTertiary,fontSize:_scnTheme.scn.font.micro},laneStaticInstant:{color:_scnTheme.scn.color.sim},startLine:{flexDirection:"row",alignItems:"center",gap:8,paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:8,backgroundColor:_scnTheme.scn.color.simSoft},startRule:{flex:1,height:1,backgroundColor:_scnTheme.scn.color.simBorder},startLabel:{color:_scnTheme.scn.color.sim,fontSize:_scnTheme.scn.font.micro,fontWeight:"700",letterSpacing:.3},reset:{alignSelf:"flex-start",paddingVertical:4},resetText:{color:_scnTheme.scn.color.textSecondary,fontSize:_scnTheme.scn.font.footnote,fontWeight:"600"},noticeText:{color:_scnTheme.scn.color.textSecondary,fontSize:_scnTheme.scn.font.footnote,lineHeight:16},actions:{flexDirection:"row",justifyContent:"flex-end",gap:8,paddingHorizontal:_scnTheme.scn.gutter,paddingTop:12},empty:{color:_scnTheme.scn.color.textTertiary,fontSize:_scnTheme.scn.font.control,lineHeight:18,paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:14}});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.PreviewScreen=PreviewScreen;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _core=require("@buoy-gg/core");var _catalog=require("../catalog");var _interpolate=require("../interpolate");var _scnTheme=require("../ui/scnTheme");var _primitives=require("../ui/primitives");var _jsxRuntime=require("react/jsx-runtime");function durabilityTone(e){if(e==="durable")return"durable";if(e==="transient")return"transient";return"neutral"}const DURABILITY_TEXT={durable:"survives restart",session:"until restart",transient:"until refetch \u26A0","one-shot":"one-shot"};function VarControl({variable:e,value:l,onChange:i}){const o=e.label??e.key;const s=`scenario-var-${e.key}`;if(e.type==="enum"&&e.options?.length){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.field,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.fieldLabel,children:o}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.segs,children:e.options.map(r=>{const d=String(l)===String(r);return(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:[styles.seg,d?styles.segOn:null],onPress:()=>i(r),accessibilityRole:"button",accessibilityState:{selected:d},testID:`${s}-${String(r)}`,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.segText,d?styles.segTextOn:null],children:String(r)})},String(r))})})]})}if(e.type==="boolean"){return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.field,styles.fieldRow],children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.fieldLabel,children:o}),(0,_jsxRuntime.jsx)(_reactNative.Switch,{value:l===true,onValueChange:r=>i(r),testID:s})]})}return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.field,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.fieldLabel,children:o}),(0,_jsxRuntime.jsx)(_reactNative.TextInput,{style:styles.input,value:l===void 0?"":String(l),onChangeText:r=>i((0,_interpolate.coerceVarValue)(e,r)),keyboardType:e.type==="number"?"numeric":"default",placeholder:e.type==="number"?"0":"value",placeholderTextColor:_scnTheme.scn.color.textTertiary,autoCapitalize:"none",autoCorrect:false,testID:s})]})}function PreviewScreen({scenario:e,initialValues:l,check:i,currentBuild:o,mode:s,onRun:r,onAcceptDraft:d,onDiscardDraft:p,onBack:g}){const[c,h]=(0,_react.useState)(l);(0,_core.useToolHeader)({title:s==="review-draft"?"Review draft":"Before you run",subtitle:(0,_interpolate.interpolateString)(e.name,c),onBack:g,searchable:false},[e.id,s]);const n=(0,_react.useMemo)(()=>i(c),[i,c]);const f=(0,_react.useCallback)((t,a)=>{h(u=>({...u,[t]:a}))},[]);const y=!!e.authoredAgainst&&!!o&&e.authoredAgainst!==o&&e.verifiedAt?.build!==o;const T=!n.ok;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.fill,children:[(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.fill,contentContainerStyle:styles.content,keyboardShouldPersistTaps:"handled",testID:"scenario-preview-scroll",children:[e.description?(0,_jsxRuntime.jsx)(_primitives.Footnote,{testID:"scenario-preview-description",children:e.description}):null,e.vars.length?(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_primitives.SectionLabel,{icon:_sharedUi.Hash,count:e.vars.length,children:"Variables"}),(0,_jsxRuntime.jsx)(_primitives.Panel,{children:e.vars.map((t,a)=>(0,_jsxRuntime.jsxs)(_react.Fragment,{children:[a>0?(0,_jsxRuntime.jsx)(_primitives.PanelSeparator,{}):null,(0,_jsxRuntime.jsx)(VarControl,{variable:t,value:c[t.key],onChange:u=>f(t.key,u)})]},t.key))})]}):null,(0,_jsxRuntime.jsx)(_primitives.SectionLabel,{icon:_sharedUi.Layers,count:e.steps.length,children:"What this will do"}),(0,_jsxRuntime.jsx)(_primitives.Panel,{children:e.steps.map((t,a)=>{const u=(0,_interpolate.interpolate)(t.params??{},c);const x=(0,_catalog.stepDurability)(t);return(0,_jsxRuntime.jsxs)(_react.Fragment,{children:[a>0?(0,_jsxRuntime.jsx)(_primitives.PanelSeparator,{}):null,(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.step,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.stepIndex,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stepIndexText,children:a+1})}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stepBody,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stepLabel,children:(0,_catalog.describeStep)(t,u)}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.stepTool,children:[t.tool,".",t.action]})]}),(0,_jsxRuntime.jsx)(_primitives.DurabilityChip,{label:DURABILITY_TEXT[x],tone:durabilityTone(x)})]})]},t.id)})}),y?(0,_jsxRuntime.jsx)(_primitives.Notice,{tone:"sim",testID:"scenario-preview-stale",children:(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.warnText,children:["Authored against app ",e.authoredAgainst," \u2014 unverified on this build. The response shape it overrides may have drifted."]})}):null,n.conflict?(0,_jsxRuntime.jsx)(_primitives.Notice,{tone:"sim",testID:"scenario-preview-conflict",children:(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.warnText,children:["Conflict: \u201C",n.conflict.activeName,"\u201D is active and touches the same ",n.conflict.overlaps.length===1?"target":"targets",". Running will swap \u2014 it deactivates first, so the two can never overlap silently."]})}):null,n.errors.length?(0,_jsxRuntime.jsx)(_primitives.Notice,{tone:"danger",testID:"scenario-preview-errors",children:n.errors.map(t=>(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.errorText,children:["\u2022 ",t]},t))}):null,n.warnings.length?(0,_jsxRuntime.jsx)(_primitives.Notice,{tone:"sim",children:n.warnings.map(t=>(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.warnText,children:["\u2022 ",t]},t))}):null,e.expectedOutcome?(0,_jsxRuntime.jsx)(_primitives.Notice,{tone:"info",testID:"scenario-preview-expected",children:(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.infoText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.infoStrong,children:"Expected outcome: "}),e.expectedOutcome]})}):null]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.footer,children:s==="review-draft"?(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Discard",variant:"ghost",onPress:()=>p?.(),style:styles.grow,testID:"scenario-discard-draft"}),(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Accept to library",variant:"primary",onPress:()=>d?.(),style:styles.grow,testID:"scenario-accept-draft"})]}):(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:n.conflict?"Swap & run":"Run",variant:"primary",onPress:()=>r(c),disabled:T,icon:(0,_jsxRuntime.jsx)(_sharedUi.Play,{size:12,color:_scnTheme.scn.color.accent}),style:styles.grow,testID:"scenario-confirm-run"})})]})}const styles=_reactNative.StyleSheet.create({fill:{flex:1,backgroundColor:"transparent"},content:{paddingBottom:24},field:{paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:10,gap:6},fieldRow:{flexDirection:"row",alignItems:"center",justifyContent:"space-between"},fieldLabel:{color:_scnTheme.scn.color.textTertiary,fontSize:_scnTheme.scn.font.micro,fontWeight:"600",letterSpacing:.6,textTransform:"uppercase"},segs:{flexDirection:"row",flexWrap:"wrap",gap:6},seg:{borderRadius:_scnTheme.scn.radius.row,borderWidth:1,borderColor:_scnTheme.scn.color.border,backgroundColor:_scnTheme.scn.color.chip,paddingHorizontal:12,paddingVertical:6},segOn:{backgroundColor:_scnTheme.scn.color.accentSoft,borderColor:_scnTheme.scn.color.accentBorderStrong},segText:{color:_scnTheme.scn.color.textSecondary,fontSize:_scnTheme.scn.font.control,fontFamily:_scnTheme.SCN_MONO},segTextOn:{color:_scnTheme.scn.color.accent,fontWeight:"700"},input:{backgroundColor:_scnTheme.scn.color.row,borderRadius:_scnTheme.scn.radius.row,borderWidth:1,borderColor:_scnTheme.scn.color.border,color:_scnTheme.scn.color.text,fontSize:_scnTheme.scn.font.row,fontFamily:_scnTheme.SCN_MONO,paddingHorizontal:10,paddingVertical:8},step:{flexDirection:"row",alignItems:"flex-start",gap:9,paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:10},stepIndex:{width:18,height:18,borderRadius:_scnTheme.scn.radius.badge,backgroundColor:_scnTheme.scn.color.fill,alignItems:"center",justifyContent:"center",marginTop:1},stepIndexText:{color:_scnTheme.scn.color.textTertiary,fontSize:10,fontWeight:"700",fontFamily:_scnTheme.SCN_MONO},stepBody:{flex:1,minWidth:0},stepLabel:{color:_scnTheme.scn.color.text,fontSize:_scnTheme.scn.font.control},stepTool:{color:_scnTheme.scn.color.textTertiary,fontSize:_scnTheme.scn.font.mono,fontFamily:_scnTheme.SCN_MONO,marginTop:2},warnText:{color:_scnTheme.scn.color.sim,fontSize:_scnTheme.scn.font.control,lineHeight:17},errorText:{color:_scnTheme.scn.color.danger,fontSize:_scnTheme.scn.font.control,lineHeight:17},infoText:{color:"#7FA9FF",fontSize:_scnTheme.scn.font.control,lineHeight:17},infoStrong:{fontWeight:"700"},footer:{flexDirection:"row",gap:8,paddingHorizontal:_scnTheme.scn.gutter,paddingTop:10,paddingBottom:14,borderTopWidth:1,borderTopColor:_scnTheme.scn.color.border,backgroundColor:_scnTheme.scn.color.surface},grow:{flex:1}});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.BANNER_TOP_GAP=void 0;exports.RecordingBanner=RecordingBanner;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _recorderStore=require("../record/recorderStore");var _useScenarios=require("../hooks/useScenarios");var _scnTheme=require("../ui/scnTheme");var _jsxRuntime=require("react/jsx-runtime");const BANNER_TOP_GAP=exports.BANNER_TOP_GAP=52;const STACK_OFFSET=54;function RecordingBanner(){const e=(0,_useScenarios.useRecording)();const l=(0,_useScenarios.useActiveScenario)();const d=(0,_sharedUi.useSafeAreaInsets)({minBottom:0});const[o]=(0,_react.useState)(()=>new _reactNative.Animated.ValueXY({x:0,y:0}));const[s,i]=(0,_react.useState)(false);const[a,u]=(0,_react.useState)(false);const h=(0,_react.useCallback)(async()=>{i(true);try{await _recorderStore.recorderStore.stop()}finally{i(false)}},[]);const g=(0,_react.useCallback)(()=>{if(!(0,_sharedUi.openBuoyTool)("scenarios"))u(true)},[]);const[b]=(0,_react.useState)(()=>_reactNative.PanResponder.create({onMoveShouldSetPanResponder:(n,p)=>Math.abs(p.dy)>6,onPanResponderMove:_reactNative.Animated.event([null,{dy:o.y}],{useNativeDriver:false}),onPanResponderRelease:()=>o.extractOffset()}));const t=e.status==="review";if(e.status!=="recording"&&!t)return null;const r=t?(e.draft??[]).filter(n=>n.enabled&&!n.noise).length:e.actions.length;const c=e.actions[e.actions.length-1];return(0,_jsxRuntime.jsx)(_reactNative.Animated.View,{style:[styles.wrap,{top:d.top+BANNER_TOP_GAP+(l?STACK_OFFSET:0)},{transform:o.getTranslateTransform()}],pointerEvents:"box-none",...b.panHandlers,children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:[styles.banner,t&&styles.bannerReview],testID:"recording-banner",accessible:false,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.dot,t&&styles.dotReview]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.text,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.title,t&&styles.titleReview],children:t?`RECORDED \xB7 ${r} step${r===1?"":"s"}`:`\u25CF RECORDING \xB7 ${r} step${r===1?"":"s"}`}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.subtitle,numberOfLines:1,children:t?a?"Open Scenarios to review and save it.":"Review the steps, then save.":c?describeLast(c.touch.target):"Drive the app \u2014 taps on Buoy itself are ignored."})]}),t?(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.discard,onPress:()=>void _recorderStore.recorderStore.cancel(),accessibilityRole:"button",accessibilityLabel:"Discard the recording",testID:"recording-discard",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.discardText,children:"Discard"})}),a?null:(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.review,onPress:g,accessibilityRole:"button",accessibilityLabel:"Review the recorded steps",testID:"recording-review",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.reviewText,children:"Review"})})]}):(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.stop,onPress:h,disabled:s,accessibilityRole:"button",accessibilityLabel:"Stop recording and review the steps",testID:"recording-stop",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stopText,children:s?"\u2026":"Stop"})})]})})}function describeLast(e){return e.label??e.text??e.testID??e.name}const styles=_reactNative.StyleSheet.create({wrap:{position:"absolute",left:12,right:12,zIndex:10001,alignItems:"center"},banner:{flexDirection:"row",alignItems:"center",gap:8,maxWidth:520,width:"100%",paddingLeft:14,paddingRight:8,paddingVertical:8,borderRadius:22,backgroundColor:"rgba(20, 20, 20, 0.94)",borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_scnTheme.scn.color.dangerBorder,..._reactNative.Platform.select({ios:{shadowColor:"#000",shadowOpacity:.35,shadowRadius:12,shadowOffset:{width:0,height:6}},android:{elevation:8},default:{}})},dot:{width:8,height:8,borderRadius:4,backgroundColor:_scnTheme.scn.color.danger},text:{flex:1,minWidth:0},title:{color:_scnTheme.scn.color.danger,fontSize:10,fontWeight:"800",letterSpacing:.8},subtitle:{color:"rgba(255,255,255,0.85)",fontSize:11.5,marginTop:1},stop:{paddingHorizontal:12,height:28,borderRadius:14,alignItems:"center",justifyContent:"center",backgroundColor:"rgba(255, 59, 48, 0.15)"},stopText:{color:_scnTheme.scn.color.danger,fontSize:12,fontWeight:"700"},bannerReview:{borderColor:_scnTheme.scn.color.simBorder},dotReview:{backgroundColor:_scnTheme.scn.color.sim},titleReview:{color:_scnTheme.scn.color.sim},discard:{paddingHorizontal:12,height:28,borderRadius:14,alignItems:"center",justifyContent:"center",backgroundColor:"rgba(255,255,255,0.08)"},discardText:{color:"rgba(255,255,255,0.75)",fontSize:12,fontWeight:"600"},review:{paddingHorizontal:12,height:28,borderRadius:14,alignItems:"center",justifyContent:"center",backgroundColor:_scnTheme.scn.color.simSoft,borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_scnTheme.scn.color.simBorder},reviewText:{color:_scnTheme.scn.color.sim,fontSize:12,fontWeight:"700"}});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.RunProgressScreen=RunProgressScreen;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _core=require("@buoy-gg/core");var _scnTheme=require("../ui/scnTheme");var _primitives=require("../ui/primitives");var _jsxRuntime=require("react/jsx-runtime");function RunProgressScreen({runState:r,busy:l,onUndoPartial:i,onKeepPartial:c,onRetry:a,onDone:d,onBack:p}){const t=r.report;const o=!!t&&!t.ok;(0,_core.useToolHeader)({title:o?"Run failed":r.done?"Run complete":"Running\u2026",subtitle:r.name,onBack:r.done?p:void 0,searchable:false},[r.done,o,r.name]);const n=t?.steps??r.steps;return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.fill,children:[(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.fill,contentContainerStyle:styles.content,testID:"scenario-run-scroll",children:[(0,_jsxRuntime.jsx)(_primitives.SectionLabel,{icon:_sharedUi.Layers,color:o?_scnTheme.scn.color.danger:_scnTheme.scn.color.accent,children:"Steps"}),(0,_jsxRuntime.jsxs)(_primitives.Panel,{tone:o?"danger":"neutral",children:[n.length===0?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.step,children:[(0,_jsxRuntime.jsx)(_reactNative.ActivityIndicator,{size:"small",color:_scnTheme.scn.color.accent}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stepLabel,children:"Starting\u2026"})]}):null,n.map((e,s)=>(0,_jsxRuntime.jsxs)(_react.Fragment,{children:[s>0?(0,_jsxRuntime.jsx)(_primitives.PanelSeparator,{}):null,(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.step,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.mark,children:e.skipped?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.skipped,children:"\u2013"}):e.ok?(0,_jsxRuntime.jsx)(_sharedUi.Check,{size:13,color:_scnTheme.scn.color.accent}):(0,_jsxRuntime.jsx)(_sharedUi.X,{size:13,color:_scnTheme.scn.color.danger})}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stepBody,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.stepLabel,e.skipped?styles.dim:null],testID:`scenario-step-${s}`,children:e.label}),e.error?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.error,testID:`scenario-step-${s}-error`,children:e.error}):null,e.skipped?(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.dimSmall,children:"skipped"}):null]}),e.ms?(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.ms,children:[e.ms,"ms"]}):null]})]},e.id)),!r.done&&n.length?(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_primitives.PanelSeparator,{}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.step,children:[(0,_jsxRuntime.jsx)(_reactNative.ActivityIndicator,{size:"small",color:_scnTheme.scn.color.accent}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stepLabel,children:"Working\u2026"})]})]}):null]}),o?(0,_jsxRuntime.jsx)(_primitives.Notice,{tone:"danger",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.errorText,children:"The run stopped at the failing step. Nothing after it ran \u2014 but the steps before it did, so choose what happens to them."})}):null]}),o?(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.footer,children:[(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Undo applied steps",variant:"primary",onPress:i,disabled:l,style:styles.grow,testID:"scenario-undo-partial"}),(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Keep",variant:"ghost",onPress:c,testID:"scenario-keep-partial"}),(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Retry",variant:"ghost",onPress:a,disabled:l,icon:(0,_jsxRuntime.jsx)(_sharedUi.RefreshCw,{size:12,color:_scnTheme.scn.color.textSecondary}),testID:"scenario-retry"})]}):r.done?(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.footer,children:(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Done",variant:"primary",onPress:d,style:styles.grow,testID:"scenario-run-done"})}):null]})}const styles=_reactNative.StyleSheet.create({fill:{flex:1,backgroundColor:"transparent"},content:{paddingBottom:24},step:{flexDirection:"row",alignItems:"flex-start",gap:9,paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:10},mark:{width:18,alignItems:"center",marginTop:1},skipped:{color:_scnTheme.scn.color.textTertiary,fontSize:13,fontFamily:_scnTheme.SCN_MONO},stepBody:{flex:1,minWidth:0},stepLabel:{color:_scnTheme.scn.color.text,fontSize:_scnTheme.scn.font.control},dim:{color:_scnTheme.scn.color.textTertiary},dimSmall:{color:_scnTheme.scn.color.textTertiary,fontSize:_scnTheme.scn.font.mono,marginTop:2,fontFamily:_scnTheme.SCN_MONO},error:{color:_scnTheme.scn.color.danger,fontSize:_scnTheme.scn.font.mono,marginTop:3,fontFamily:_scnTheme.SCN_MONO},ms:{color:_scnTheme.scn.color.textTertiary,fontSize:_scnTheme.scn.font.micro,fontFamily:_scnTheme.SCN_MONO,marginTop:3},errorText:{color:_scnTheme.scn.color.danger,fontSize:_scnTheme.scn.font.control,lineHeight:17},footer:{flexDirection:"row",gap:8,paddingHorizontal:_scnTheme.scn.gutter,paddingTop:10,paddingBottom:14,borderTopWidth:1,borderTopColor:_scnTheme.scn.color.border,backgroundColor:_scnTheme.scn.color.surface},grow:{flex:1}});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ScenarioBanner=ScenarioBanner;exports.ScenariosOverlay=ScenariosOverlay;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _useScenarios=require("../hooks/useScenarios");var _RecordingBanner=require("./RecordingBanner");var _scenariosStore=require("../store/scenariosStore");var _scnTheme=require("../ui/scnTheme");var _jsxRuntime=require("react/jsx-runtime");function countdown(e){if(!e)return null;const t=e-Date.now();if(t<=0)return"expiring";const r=Math.floor(t/36e5);const o=Math.round(t%36e5/6e4);return r?`auto-off ${r}h`:`auto-off ${o}m`}function ScenarioBanner(){const e=(0,_useScenarios.useActiveScenario)();const t=(0,_sharedUi.useSafeAreaInsets)({minBottom:0});const[r,o]=(0,_react.useState)(false);const[n]=(0,_react.useState)(()=>new _reactNative.Animated.ValueXY({x:0,y:0}));const i=(0,_react.useCallback)(()=>{void _scenariosStore.scenariosStore.deactivate()},[]);const[f,a]=(0,_react.useState)(false);const[s,l]=(0,_react.useState)(false);(0,_react.useEffect)(()=>{if(!s)return;const u=setTimeout(()=>l(false),2200);return()=>clearTimeout(u)},[s]);const[c]=(0,_react.useState)(()=>_reactNative.PanResponder.create({onMoveShouldSetPanResponder:(u,h)=>Math.abs(h.dy)>6,onPanResponderMove:_reactNative.Animated.event([null,{dy:n.y}],{useNativeDriver:false}),onPanResponderRelease:()=>{n.extractOffset()}}));if(!e)return null;const d=countdown(e.expiresAt);if(r){return(0,_jsxRuntime.jsx)(_reactNative.Animated.View,{style:[styles.wrap,{top:t.top+_RecordingBanner.BANNER_TOP_GAP},{transform:n.getTranslateTransform()}],pointerEvents:"box-none",...c.panHandlers,children:(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{style:styles.pill,onPress:()=>o(false),accessibilityRole:"button",accessibilityLabel:"Simulation active. Expand for details.",testID:"scenario-banner-pill",children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.dot}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.pillText,children:"SIMULATED"})]})})}return(0,_jsxRuntime.jsx)(_reactNative.Animated.View,{style:[styles.wrap,{top:t.top+_RecordingBanner.BANNER_TOP_GAP},{transform:n.getTranslateTransform()}],pointerEvents:"box-none",...c.panHandlers,children:(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.banner,testID:"scenario-banner",accessible:false,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.dot}),(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{style:styles.text,onPress:()=>o(true),accessibilityRole:"button",accessibilityLabel:`Simulated: ${e.name}. ${e.effects.length} changes.`,testID:"scenario-banner-body",children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.title,children:"\u25B2 SIMULATED"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.subtitle,s&&styles.hint],numberOfLines:1,children:s?"Hold \u23FB to stop the scenario":`${e.name} \xB7 ${e.effects.length} ${e.effects.length===1?"change":"changes"}`})]}),d?(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.expiry,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.expiryText,children:d})}):null,(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:[styles.off,f&&styles.offHolding],onPress:()=>l(true),onLongPress:i,delayLongPress:600,onPressIn:()=>a(true),onPressOut:()=>a(false),accessibilityActions:[{name:"activate"},{name:"longpress"}],onAccessibilityAction:i,accessibilityHint:"Hold to stop",accessibilityRole:"button",accessibilityLabel:"Deactivate the scenario",testID:"scenario-stop-simulation",children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.offText,children:"\u23FB"})})]})})}const styles=_reactNative.StyleSheet.create({wrap:{position:"absolute",left:12,right:12,zIndex:9998,alignItems:"center"},banner:{flexDirection:"row",alignItems:"center",gap:8,maxWidth:520,width:"100%",paddingLeft:14,paddingRight:8,paddingVertical:8,borderRadius:22,backgroundColor:"rgba(20, 20, 20, 0.94)",borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_scnTheme.scn.color.simBorder,..._reactNative.Platform.select({ios:{shadowColor:"#000",shadowOpacity:.35,shadowRadius:12,shadowOffset:{width:0,height:6}},android:{elevation:8},default:{}})},pill:{flexDirection:"row",alignItems:"center",gap:6,paddingHorizontal:12,paddingVertical:6,borderRadius:22,backgroundColor:"rgba(20, 20, 20, 0.94)",borderWidth:_reactNative.StyleSheet.hairlineWidth,borderColor:_scnTheme.scn.color.simBorder},pillText:{color:_scnTheme.scn.color.sim,fontSize:10,fontWeight:"800",letterSpacing:.8},dot:{width:7,height:7,borderRadius:2,backgroundColor:_scnTheme.scn.color.sim},text:{flex:1,minWidth:0},title:{color:_scnTheme.scn.color.sim,fontSize:10,fontWeight:"800",letterSpacing:.8},subtitle:{color:"rgba(255,255,255,0.85)",fontSize:11.5,marginTop:1},expiry:{paddingHorizontal:6,paddingVertical:2,borderRadius:6,backgroundColor:_scnTheme.scn.color.simSoft},expiryText:{color:_scnTheme.scn.color.sim,fontSize:10,fontWeight:"600"},off:{width:28,height:28,borderRadius:14,alignItems:"center",justifyContent:"center",backgroundColor:"rgba(255, 131, 41, 0.15)"},offHolding:{backgroundColor:_scnTheme.scn.color.sim},offText:{color:_scnTheme.scn.color.sim,fontSize:13},hint:{color:_scnTheme.scn.color.sim}});function ScenariosOverlay(){return(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(ScenarioBanner,{}),(0,_jsxRuntime.jsx)(_RecordingBanner.RecordingBanner,{})]})}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ScenarioDetailScreen=ScenarioDetailScreen;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _core=require("@buoy-gg/core");var _catalog=require("../catalog");var _folders=require("../folders");var _scnTheme=require("../ui/scnTheme");var _primitives=require("../ui/primitives");var _ScenarioRow=require("./ScenarioRow");var _jsxRuntime=require("react/jsx-runtime");const DURABILITY_TEXT={durable:"survives restart",session:"until restart",transient:"until refetch \u26A0","one-shot":"one-shot"};function tone(e){if(e==="durable")return"durable";if(e==="transient")return"transient";return"neutral"}function ScenarioDetailScreen({scenario:e,onRun:r,onDelete:i,onDuplicate:t,onExported:n,onMoveToFolder:o,onBack:u}){(0,_core.useToolHeader)({title:(0,_ScenarioRow.displayName)(e.name),subtitle:e.source==="code"?"shipped with this app":"saved on this device",onBack:u,searchable:false},[e.id]);const a=e.source==="device";const s=(0,_folders.normalizeFolder)(e.folder);return(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.fill,contentContainerStyle:styles.content,testID:"scenario-detail-scroll",children:[e.description?(0,_jsxRuntime.jsx)(_primitives.Footnote,{children:e.description}):null,(0,_jsxRuntime.jsx)(_primitives.SectionLabel,{icon:_sharedUi.Layers,count:e.steps.length,children:"Steps"}),(0,_jsxRuntime.jsx)(_primitives.Panel,{children:e.steps.map((l,c)=>{const d=(0,_catalog.stepDurability)(l);return(0,_jsxRuntime.jsxs)(_react.Fragment,{children:[c>0?(0,_jsxRuntime.jsx)(_primitives.PanelSeparator,{}):null,(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.step,children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.stepIndex,children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stepIndexText,children:c+1})}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.stepBody,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.stepLabel,children:(0,_catalog.describeStep)(l)}),(0,_jsxRuntime.jsxs)(_reactNative.Text,{style:styles.stepTool,children:[l.tool,".",l.action,(0,_catalog.isAdvancedStep)(l)?" \xB7 advanced":""]})]}),(0,_jsxRuntime.jsx)(_primitives.DurabilityChip,{label:DURABILITY_TEXT[d],tone:tone(d)})]})]},l.id)})}),e.expectedOutcome?(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_primitives.SectionLabel,{icon:_sharedUi.CheckCircle,children:"Expected outcome"}),(0,_jsxRuntime.jsx)(_primitives.Panel,{children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.expected,children:e.expectedOutcome})})]}):null,(0,_jsxRuntime.jsx)(_primitives.SectionLabel,{icon:_sharedUi.FileText,children:"Details"}),(0,_jsxRuntime.jsxs)(_primitives.Panel,{children:[(0,_jsxRuntime.jsx)(Detail,{label:"Folder",value:s??"No folder",muted:!s,onPress:a?o:void 0,testID:"scenario-detail-folder"}),(0,_jsxRuntime.jsx)(_primitives.PanelSeparator,{}),(0,_jsxRuntime.jsx)(Detail,{label:"Source",value:e.source==="code"?"shipped with this app":"saved on this device"}),(0,_jsxRuntime.jsx)(_primitives.PanelSeparator,{}),(0,_jsxRuntime.jsx)(Detail,{label:"Version",value:`v${e.version}`}),e.author?(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_primitives.PanelSeparator,{}),(0,_jsxRuntime.jsx)(Detail,{label:"Author",value:e.author})]}):null,e.authoredAgainst?(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_primitives.PanelSeparator,{}),(0,_jsxRuntime.jsx)(Detail,{label:"Authored against",value:e.authoredAgainst})]}):null,(0,_jsxRuntime.jsx)(_primitives.PanelSeparator,{}),(0,_jsxRuntime.jsx)(Detail,{label:"Runs",value:String(e.usage?.runs??0)}),e.tags?.length?(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_primitives.PanelSeparator,{}),(0,_jsxRuntime.jsx)(Detail,{label:"Tags",value:e.tags.join(", ")})]}):null]}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.footer,children:[(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Run",variant:"primary",onPress:r,icon:(0,_jsxRuntime.jsx)(_sharedUi.Play,{size:12,color:_scnTheme.scn.color.accent}),style:styles.grow,testID:"scenario-detail-run"}),(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Export",variant:"ghost",onPress:()=>{void(0,_sharedUi.copyToClipboard)(JSON.stringify(e,null,2));n?.()},icon:(0,_jsxRuntime.jsx)(_sharedUi.Copy,{size:12,color:_scnTheme.scn.color.textSecondary}),style:styles.grow,testID:"scenario-detail-export"})]}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.footer,children:a?(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Delete",variant:"danger",onPress:i,icon:(0,_jsxRuntime.jsx)(_sharedUi.Trash,{size:12,color:_scnTheme.scn.color.danger}),style:styles.grow,testID:"scenario-detail-delete"}):(0,_jsxRuntime.jsx)(_sharedUi.ToolButton,{label:"Make an editable copy",variant:"ghost",onPress:t,style:styles.grow,testID:"scenario-detail-duplicate"})}),e.source==="code"?(0,_jsxRuntime.jsx)(_primitives.Footnote,{children:"Shipped scenarios are read-only on the device \u2014 they change in a pull request, with the code they bend."}):null]})}function Detail({label:e,value:r,muted:i,onPress:t,testID:n}){const o=(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.detailLabel,children:e}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.detailValue,i&&styles.detailValueMuted,t&&styles.detailValueAction],numberOfLines:2,children:r}),t?(0,_jsxRuntime.jsx)(_sharedUi.ChevronRight,{size:13,color:_scnTheme.scn.color.textTertiary}):null]});if(!t){return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.detail,testID:n,children:o})}return(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{style:styles.detail,onPress:t,activeOpacity:.7,accessibilityRole:"button",accessibilityLabel:`${e}: ${r}. Change it.`,testID:n,children:o})}const styles=_reactNative.StyleSheet.create({fill:{flex:1,backgroundColor:"transparent"},content:{paddingBottom:32},step:{flexDirection:"row",alignItems:"flex-start",gap:9,paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:10},stepIndex:{width:18,height:18,borderRadius:_scnTheme.scn.radius.badge,backgroundColor:_scnTheme.scn.color.fill,alignItems:"center",justifyContent:"center",marginTop:1},stepIndexText:{color:_scnTheme.scn.color.textTertiary,fontSize:10,fontWeight:"700",fontFamily:_scnTheme.SCN_MONO},stepBody:{flex:1,minWidth:0},stepLabel:{color:_scnTheme.scn.color.text,fontSize:_scnTheme.scn.font.control},stepTool:{color:_scnTheme.scn.color.textTertiary,fontSize:_scnTheme.scn.font.mono,fontFamily:_scnTheme.SCN_MONO,marginTop:2},expected:{color:_scnTheme.scn.color.textSecondary,fontSize:_scnTheme.scn.font.control,lineHeight:18,paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:12},detail:{flexDirection:"row",alignItems:"center",justifyContent:"space-between",gap:8,minHeight:40,paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:10},detailLabel:{color:_scnTheme.scn.color.textTertiary,fontSize:_scnTheme.scn.font.control},detailValue:{flex:1,textAlign:"right",color:_scnTheme.scn.color.textSecondary,fontSize:_scnTheme.scn.font.control,fontFamily:_scnTheme.SCN_MONO},detailValueMuted:{color:_scnTheme.scn.color.textTertiary},detailValueAction:{color:_scnTheme.scn.color.accent},footer:{flexDirection:"row",gap:8,paddingHorizontal:_scnTheme.scn.gutter,paddingTop:12},grow:{flex:1}});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ScenarioFolderBar=ScenarioFolderBar;exports.folderMatches=folderMatches;var _reactNative=require("react-native");var _folders=require("../folders");var _scnTheme=require("../ui/scnTheme");var _jsxRuntime=require("react/jsx-runtime");function folderMatches(o,t){if(t===null)return true;return(0,_folders.inFolder)(o,t)}function keyFor(o){if(o===null)return"__all__";if(o===void 0)return"__ungrouped__";return o}function ScenarioFolderBar({folders:o,active:t,onChange:i,scenarios:n}){const l=(0,_folders.countInFolder)(n,void 0);const c=[{filter:null,label:"All",count:n.length},...o.map(e=>({filter:e,label:e,count:(0,_folders.countInFolder)(n,e)}))];if(l){c.push({filter:void 0,label:_folders.UNGROUPED,count:l})}return(0,_jsxRuntime.jsx)(_reactNative.ScrollView,{horizontal:true,showsHorizontalScrollIndicator:false,style:styles.scroll,contentContainerStyle:styles.row,testID:"scenarios-folder-bar",children:c.map(e=>{const r=t===e.filter||typeof t==="string"&&typeof e.filter==="string"&&t.toLowerCase()===e.filter.toLowerCase();return(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{testID:`scenarios-folder-${keyFor(e.filter)}`,accessibilityRole:"button",accessibilityLabel:`Show ${e.label} scenarios`,accessibilityState:{selected:r},activeOpacity:.8,onPress:()=>i(e.filter),style:[styles.chip,r&&styles.chipActive],children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.label,r&&styles.labelActive],numberOfLines:1,children:e.label}),(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.countPill,r&&styles.countPillActive],children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.count,r&&styles.countActive],testID:`scenarios-folder-${keyFor(e.filter)}-count`,children:e.count})})]},keyFor(e.filter))})})}const styles=_reactNative.StyleSheet.create({scroll:{flexGrow:0},row:{flexDirection:"row",gap:8,paddingHorizontal:_scnTheme.scn.gutter,paddingTop:10,paddingBottom:2},chip:{flexDirection:"row",alignItems:"center",gap:6,backgroundColor:_scnTheme.scn.color.chip,borderRadius:_scnTheme.scn.radius.card,borderWidth:1,borderColor:_scnTheme.scn.color.border,paddingVertical:6,paddingHorizontal:10,minHeight:32,maxWidth:200},chipActive:{backgroundColor:_scnTheme.scn.color.accentSoft,borderColor:_scnTheme.scn.color.accentBorderStrong},label:{fontSize:_scnTheme.scn.font.footnote,color:_scnTheme.scn.color.textSecondary,fontWeight:"500",flexShrink:1},labelActive:{color:_scnTheme.scn.color.accent,fontWeight:"600"},countPill:{minWidth:18,alignItems:"center",borderRadius:_scnTheme.scn.radius.badge,backgroundColor:_scnTheme.scn.color.fill,paddingHorizontal:4,paddingVertical:1},countPillActive:{backgroundColor:_scnTheme.scn.color.accentSoft},count:{fontSize:_scnTheme.scn.font.micro,fontWeight:"600",fontFamily:_scnTheme.SCN_MONO,color:_scnTheme.scn.color.textTertiary},countActive:{color:_scnTheme.scn.color.accent}});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ScenarioRow=void 0;exports.displayName=displayName;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _folders=require("../folders");var _scnTheme=require("../ui/scnTheme");var _primitives=require("../ui/primitives");var _jsxRuntime=require("react/jsx-runtime");function displayName(e){return e.replace(/\{\{\s*(\w+)\s*\}\}/g,"\u27E8$1\u27E9")}function metaLine(e){const t=[`v${e.version}`];if(e.author)t.push(e.author);const s=e.usage?.runs??0;if(s)t.push(`${s}\xD7`);if(e.unsavedToRepo)t.push("unsaved to repo");if(e.source==="draft")t.push("inert until you accept");return t.join(" \xB7 ")}function origin(e){if(e.source==="code")return{label:"Shipped",color:_scnTheme.scn.color.accent};if(e.source==="draft")return{label:"Draft",color:_scnTheme.scn.color.sim};return{label:"Saved",color:_scnTheme.scn.color.info}}function ScenarioRowInner({scenario:e,currentBuild:t,disabled:s,showFolder:i,onOpen:n,onRun:u,testID:c}){const r=c??`scenario-row-${e.id}`;const l=origin(e);const a=(0,_folders.normalizeFolder)(e.folder);const d=e.source==="draft";const o=d?{label:"Review",color:_scnTheme.scn.color.sim}:{label:"Run",color:_scnTheme.scn.color.accent};const p=!!e.authoredAgainst&&!!t&&e.authoredAgainst!==t&&e.verifiedAt?.build!==t;return(0,_jsxRuntime.jsx)(_sharedUi.CompactRow,{statusDotColor:l.color,statusLabel:l.label,statusSublabel:`${e.steps.length} step${e.steps.length===1?"":"s"}`,primaryText:displayName(e.name),primaryTestID:`${r}-name`,secondaryText:metaLine(e),secondaryTestID:`${r}-meta`,secondaryAccessory:(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[i&&a?(0,_jsxRuntime.jsx)(_primitives.DurabilityChip,{label:a,tone:"neutral",testID:`${r}-folder`}):null,p?(0,_jsxRuntime.jsx)(_primitives.DurabilityChip,{label:`stale \xB7 ${e.authoredAgainst}`,tone:"transient",testID:`${r}-stale`}):null]}),trailingAction:(0,_jsxRuntime.jsx)(_reactNative.TouchableOpacity,{onPress:u,disabled:s,style:s?styles.disabled:null,hitSlop:HIT_SLOP,accessibilityRole:"button",accessibilityLabel:`${o.label} ${displayName(e.name)}`,testID:`${r}-run`,children:(0,_jsxRuntime.jsx)(_reactNative.View,{children:(0,_jsxRuntime.jsx)(_primitives.PillLabel,{label:o.label,color:o.color})})}),showChevron:true,onPress:n,testID:r,accessibilityLabel:`${displayName(e.name)}. ${l.label}, ${e.steps.length} step${e.steps.length===1?"":"s"}, ${metaLine(e)}. Open details.`})}const ScenarioRow=exports.ScenarioRow=(0,_react.memo)(ScenarioRowInner);const HIT_SLOP={top:8,bottom:8,left:8,right:8};const styles=_reactNative.StyleSheet.create({disabled:{opacity:.4}});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ScenariosBody=ScenariosBody;var _react=require("react");var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _core=require("@buoy-gg/core");var _interpolate=require("../interpolate");var _scenariosStore=require("../store/scenariosStore");var _useScenarios=require("../hooks/useScenarios");var _recorderStore=require("../record/recorderStore");var _condense=require("../record/condense");var _MacroReviewScreen=require("./MacroReviewScreen");var _scnTheme=require("../ui/scnTheme");var _primitives=require("../ui/primitives");var _ActiveCard=require("./ActiveCard");var _DeactivateReportCard=require("./DeactivateReportCard");var _PreviewScreen=require("./PreviewScreen");var _RunProgressScreen=require("./RunProgressScreen");var _ScenarioDetailScreen=require("./ScenarioDetailScreen");var _ScenarioRow=require("./ScenarioRow");var _ScenarioFolderBar=require("./ScenarioFolderBar");var _FolderPickerScreen=require("./FolderPickerScreen");var _jsxRuntime=require("react/jsx-runtime");function macroId(r){const l=r.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"").slice(0,40);return`macro-${l||"recording"}-${Date.now().toString(36)}`}function ScenariosBody({currentBuild:r}){const l=(0,_useScenarios.useScenariosState)();const S=(0,_useScenarios.useScenariosRunState)();const c=(0,_useScenarios.useRecording)();const o=(0,_core.useToolHost)();const f=(0,_sharedUi.useSafeAreaInsets)({minBottom:16});const y=(0,_sharedUi.useLimit)("scenarios.saved");const[d,a]=(0,_react.useState)({name:"list"});const[g,u]=(0,_react.useState)(false);const i=(0,_react.useCallback)(()=>a({name:"list"}),[]);const x=(0,_react.useCallback)(e=>t=>{return _scenariosStore.scenariosStore.checkBeforeRun(e,t)},[]);const m=(0,_react.useCallback)(async(e,t)=>{u(true);a({name:"run"});try{const n=await _scenariosStore.scenariosStore.run(e,t);if(n.ok){o.showToast(`Scenario active \u2014 ${n.effects.length} change${n.effects.length===1?"":"s"}`,"success");_scenariosStore.scenariosStore.clearRunState();a({name:"list"});o.minimize()}}catch(n){o.showToast(n instanceof Error?n.message:String(n),"error");a({name:"list"})}finally{u(false)}},[o]);const p=(0,_react.useCallback)(async()=>{u(true);try{await _scenariosStore.scenariosStore.deactivate()}finally{u(false)}},[]);const b=(0,_react.useCallback)(async()=>{await _recorderStore.recorderStore.start();const{status:e,reason:t}=_recorderStore.recorderStore.getState();if(e!=="recording"){o.showToast(t??"Recording isn't available in this app.","error");return}o.minimize()},[o]);const h=(0,_react.useCallback)(async(e,t)=>{u(true);try{const n=(0,_condense.macroToSteps)(t);const w=Date.now();await _scenariosStore.scenariosStore.saveScenario({id:macroId(e),name:e,version:1,source:"device",author:"recorded here",vars:[],steps:n,authoredAgainst:r,unsavedToRepo:true,createdAt:w,updatedAt:w,usage:{runs:0}});await _recorderStore.recorderStore.cancel();o.showToast(`Saved \u201C${e}\u201D`,"success");i()}catch(n){o.showToast(n instanceof Error?n.message:String(n),"error")}finally{u(false)}},[r,i,o]);if(c.status==="review"&&c.draft){return(0,_jsxRuntime.jsx)(_MacroReviewScreen.MacroReviewScreen,{draft:c.draft,busy:g,onChange:e=>_recorderStore.recorderStore.setDraft(e),onSave:h,onDiscard:()=>{_reactNative.Alert.alert("Discard this recording?","The steps you just recorded will be thrown away.",[{text:"Keep",style:"cancel"},{text:"Discard",style:"destructive",onPress:()=>{void _recorderStore.recorderStore.cancel();i()}}])}})}if(d.name==="run"&&S){return(0,_jsxRuntime.jsx)(_RunProgressScreen.RunProgressScreen,{runState:S,busy:g,onUndoPartial:async()=>{u(true);try{await _scenariosStore.scenariosStore.undoPartialRun();o.showToast("Applied steps undone","success")}finally{u(false);i()}},onKeepPartial:()=>{_scenariosStore.scenariosStore.clearRunState();i()},onRetry:()=>{const e=S.scenarioId;const t=_scenariosStore.scenariosStore.find(e);if(t){void m(e,_scenariosStore.scenariosStore.lastValuesFor(e))}},onDone:()=>{_scenariosStore.scenariosStore.clearRunState();i()},onBack:()=>{_scenariosStore.scenariosStore.clearRunState();i()}})}if(d.name==="preview"){const e=_scenariosStore.scenariosStore.find(d.scenarioId);if(!e)return(0,_jsxRuntime.jsx)(ScenariosList,{...v()});const t={...(0,_interpolate.resolveVarValues)(e.vars),..._scenariosStore.scenariosStore.lastValuesFor(e.id)};return(0,_jsxRuntime.jsx)(_PreviewScreen.PreviewScreen,{scenario:e,initialValues:t,check:x(e),currentBuild:r,mode:d.mode,onRun:n=>{_scenariosStore.scenariosStore.rememberVarValues(e.id,n);void m(e.id,n)},onAcceptDraft:async()=>{await _scenariosStore.scenariosStore.acceptDraft(e.id);o.showToast("Accepted \u2014 it's now in your library","success");i()},onDiscardDraft:async()=>{await _scenariosStore.scenariosStore.discardDraft(e.id);o.showToast("Draft discarded","info");i()},onBack:i})}if(d.name==="detail"){const e=_scenariosStore.scenariosStore.find(d.scenarioId);if(!e)return(0,_jsxRuntime.jsx)(ScenariosList,{...v()});return(0,_jsxRuntime.jsx)(_ScenarioDetailScreen.ScenarioDetailScreen,{scenario:e,onRun:()=>a({name:"preview",scenarioId:e.id,mode:"run"}),onDelete:()=>{_reactNative.Alert.alert("Delete scenario?",`\u201C${(0,_ScenarioRow.displayName)(e.name)}\u201D will be removed from this device.`,[{text:"Cancel",style:"cancel"},{text:"Delete",style:"destructive",onPress:()=>{void _scenariosStore.scenariosStore.deleteScenario(e.id);i()}}])},onDuplicate:async()=>{const t={...e,id:`${e.id}-copy-${Date.now().toString(36)}`,name:`${e.name} (copy)`,source:"device",version:1,unsavedToRepo:true};await _scenariosStore.scenariosStore.saveScenario(t);o.showToast("Copied to this device","success");i()},onExported:()=>o.showToast("Scenario JSON copied","success"),onMoveToFolder:()=>a({name:"folder",scenarioId:e.id}),onBack:i})}if(d.name==="folder"){const e=_scenariosStore.scenariosStore.find(d.scenarioId);if(!e)return(0,_jsxRuntime.jsx)(ScenariosList,{...v()});return(0,_jsxRuntime.jsx)(_FolderPickerScreen.FolderPickerScreen,{scenario:e,folders:_scenariosStore.scenariosStore.folders(),onPick:async t=>{try{await _scenariosStore.scenariosStore.setFolder(e.id,t);o.showToast(t?`Filed under ${t}`:"Removed from its folder","success")}catch(n){o.showToast(n instanceof Error?n.message:String(n),"error")}a({name:"detail",scenarioId:e.id})},onBack:()=>a({name:"detail",scenarioId:e.id})})}function v(){return{state:l,insets:f,host:o,busy:g,savedLimit:y,currentBuild:r,onOpen:e=>a({name:"detail",scenarioId:e}),onRun:e=>a({name:"preview",scenarioId:e,mode:"run"}),onReviewDraft:e=>a({name:"preview",scenarioId:e,mode:"review-draft"}),onDeactivate:p,onRerun:()=>{const e=l.active;if(e)void m(e.scenarioId,e.varValues)},onStartRecording:b,canRecord:_recorderStore.recorderStore.canRecord(),recordUnavailable:c.status==="unavailable"?c.reason:null}}return(0,_jsxRuntime.jsx)(ScenariosList,{...v()})}function emptyText(r,l,S){if(r)return"No matches.";if(l===void 0)return"Nothing unfiled here.";if(l!==null)return`Nothing in ${l}.`;return S}function ScenariosList({state:r,insets:l,host:S,busy:c,savedLimit:o,currentBuild:f,onOpen:y,onRun:d,onReviewDraft:a,onDeactivate:g,onRerun:u,onStartRecording:i,canRecord:x,recordUnavailable:m}){const[p,b]=(0,_react.useState)(null);const h=S.search.trim().toLowerCase();const v=s=>!h||s.name.toLowerCase().includes(h)||(s.folder??"").toLowerCase().includes(h)||(s.tags??[]).some(_=>_.toLowerCase().includes(h))||(s.author??"").toLowerCase().includes(h);const e={code:r.code.filter(v),device:r.device.filter(v),drafts:r.drafts.filter(v)};const t=_scenariosStore.scenariosStore.folders();const n=[...e.code,...e.device,...e.drafts];const w=s=>(0,_ScenarioFolderBar.folderMatches)(s,p);const R=e.code.filter(w);const D=e.device.filter(w);const j=e.drafts.filter(w);const k=r.device.length>=o;const F=_scenariosStore.scenariosStore.isLongRunning();const T=p===null&&t.length>0;const C=(0,_react.useCallback)(()=>({shipped:r.code,saved:r.device,drafts:r.drafts,active:r.active??null}),[r.code,r.device,r.drafts,r.active]);const I=(0,_react.useMemo)(()=>(0,_jsxRuntime.jsx)(_sharedUi.ToolbarCopyButton,{value:C,buttonStyle:styles.headerButton,testID:"scenarios-copy-library",accessibilityLabel:"Copy the scenario library as JSON"}),[C]);(0,_core.useToolHeader)({actions:I},[I]);return(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.fill,children:[t.length?(0,_jsxRuntime.jsx)(_ScenarioFolderBar.ScenarioFolderBar,{folders:t,active:p,onChange:b,scenarios:n}):null,(0,_jsxRuntime.jsxs)(_reactNative.ScrollView,{style:styles.fill,contentContainerStyle:[styles.content,{paddingBottom:l.bottom}],keyboardShouldPersistTaps:"handled",testID:"scenarios-scroll",children:[x?(0,_jsxRuntime.jsxs)(_reactNative.TouchableOpacity,{style:styles.record,onPress:i,disabled:c,activeOpacity:.75,accessibilityRole:"button",accessibilityLabel:"Record what you do next as a macro",testID:"scenarios-record",children:[(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.recordDot}),(0,_jsxRuntime.jsxs)(_reactNative.View,{style:styles.recordText,children:[(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.recordTitle,children:"Record a macro"}),(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.recordHint,children:"Do the flow once. Buoy writes down the steps."})]})]}):null,m?(0,_jsxRuntime.jsx)(_primitives.Footnote,{tone:"warning",testID:"scenarios-record-unavailable",children:m}):null,r.lastDeactivateReport?(0,_jsxRuntime.jsx)(_DeactivateReportCard.DeactivateReportCard,{report:r.lastDeactivateReport,onDismiss:()=>_scenariosStore.scenariosStore.dismissDeactivateReport()}):null,r.active?(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_primitives.SectionLabel,{icon:_sharedUi.Zap,color:_scnTheme.scn.color.sim,testID:"scenarios-active-label",children:"Active now"}),(0,_jsxRuntime.jsx)(_ActiveCard.ActiveCard,{active:r.active,build:f,busy:c,onDeactivate:g,onRerun:u,onCopied:()=>S.showToast("Repro info copied \u2014 paste into the ticket","success")}),F?(0,_jsxRuntime.jsx)(_primitives.Footnote,{tone:"warning",testID:"scenarios-long-running",children:"This scenario has been active for a while. If you have moved on to something else, deactivate it before you test anything real."}):null]}):null,j.length?(0,_jsxRuntime.jsxs)(_jsxRuntime.Fragment,{children:[(0,_jsxRuntime.jsx)(_primitives.SectionLabel,{icon:_sharedUi.FileText,color:_scnTheme.scn.color.sim,count:j.length,testID:"scenarios-drafts-label",children:"Awaiting review"}),j.map(s=>(0,_jsxRuntime.jsx)(_ScenarioRow.ScenarioRow,{scenario:s,currentBuild:f,disabled:c,showFolder:T,onOpen:()=>a(s.id),onRun:()=>a(s.id),testID:`scenario-draft-${s.id}`},s.id)),(0,_jsxRuntime.jsx)(_primitives.Footnote,{children:"A scenario sent from chat or the desktop never runs on its own. You review what it will do, then accept it."})]}):null,(0,_jsxRuntime.jsx)(_primitives.SectionLabel,{icon:_sharedUi.Box,count:R.length,testID:"scenarios-code-label",children:"Shipped with this app"}),R.length?R.map(s=>(0,_jsxRuntime.jsx)(_ScenarioRow.ScenarioRow,{scenario:s,currentBuild:f,disabled:c,showFolder:T,onOpen:()=>y(s.id),onRun:()=>d(s.id)},s.id)):(0,_jsxRuntime.jsx)(_primitives.Panel,{children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.empty,testID:"scenarios-code-empty",children:emptyText(h,p,"None yet \u2014 your developers can ship a QA menu with the app using defineScenario().")})}),(0,_jsxRuntime.jsx)(_primitives.SectionLabel,{icon:_sharedUi.Smartphone,color:_scnTheme.scn.color.info,count:D.length,testID:"scenarios-device-label",children:"Saved on this device"}),D.length?D.map(s=>(0,_jsxRuntime.jsx)(_ScenarioRow.ScenarioRow,{scenario:s,currentBuild:f,disabled:c,showFolder:T,onOpen:()=>y(s.id),onRun:()=>d(s.id)},s.id)):(0,_jsxRuntime.jsx)(_primitives.Panel,{children:(0,_jsxRuntime.jsx)(_reactNative.Text,{style:styles.empty,testID:"scenarios-device-empty",children:emptyText(h,p,"Nothing saved here yet. Ask your AI assistant to save the state you just set up as a scenario.")})}),k?(0,_jsxRuntime.jsxs)(_primitives.Footnote,{tone:"warning",testID:"scenarios-limit",children:["Your plan keeps ",o," saved scenario",o===1?"":"s"," on a device. Scenarios shipped in code don't count toward it."]}):null,(0,_jsxRuntime.jsx)(_primitives.Footnote,{children:t.length?"Scenarios only run in development builds. Tap a row to see exactly what it will do before you run it.":"Scenarios only run in development builds. Open one and tap its Folder row to group it by flow \u2014 Checkout, Login \u2014 and a folder bar appears up here."})]})]})}const styles=_reactNative.StyleSheet.create({fill:{flex:1,backgroundColor:"transparent"},content:{paddingBottom:24},record:{flexDirection:"row",alignItems:"center",gap:10,marginHorizontal:_scnTheme.scn.gutter,marginTop:8,marginBottom:4,paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:12,borderRadius:_scnTheme.scn.radius.card,borderWidth:1,borderColor:_scnTheme.scn.color.simBorder,backgroundColor:_scnTheme.scn.color.simSoft},recordDot:{width:10,height:10,borderRadius:5,backgroundColor:_scnTheme.scn.color.sim},recordText:{flex:1,minWidth:0},recordTitle:{color:_scnTheme.scn.color.sim,fontSize:_scnTheme.scn.font.row,fontWeight:"700"},recordHint:{color:_scnTheme.scn.color.textSecondary,fontSize:_scnTheme.scn.font.micro,marginTop:2},headerButton:{width:32,height:32,borderRadius:8,backgroundColor:_scnTheme.scn.color.chip,borderWidth:1,borderColor:_scnTheme.scn.color.border,alignItems:"center",justifyContent:"center"},empty:{color:_scnTheme.scn.color.textTertiary,fontSize:_scnTheme.scn.font.control,lineHeight:18,paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:14}});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.ScenariosToolView=ScenariosToolView;var _ScenariosBody=require("./ScenariosBody");var _jsxRuntime=require("react/jsx-runtime");function ScenariosToolView({currentBuild:e}){return(0,_jsxRuntime.jsx)(_ScenariosBody.ScenariosBody,{currentBuild:e})}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.defineScenario=defineScenario;exports.withStepIds=withStepIds;var _folders=require("./folders");function withStepIds(e=[],r){return e.map((s,t)=>({...s,id:s.id??`${r}${t+1}`}))}function defineScenario(e){const r=Date.now();return{id:e.id,name:e.name,description:e.description,version:e.version??1,source:"code",author:e.author,vars:e.vars??[],steps:withStepIds(e.steps,"s"),undoSteps:e.undoSteps?withStepIds(e.undoSteps,"u"):void 0,tags:e.tags,folder:(0,_folders.normalizeFolder)(e.folder),expectedOutcome:e.expectedOutcome,authoredAgainst:e.authoredAgainst,createdAt:r,updatedAt:r,usage:{runs:0}}}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.WAIT_FOR_TIMEOUT_MS=exports.STEP_TIMEOUT_MS=exports.SCENARIO_TIMEOUT_MS=void 0;exports.preflight=preflight;exports.revertEffects=revertEffects;exports.runScenario=runScenario;var _catalog=require("./catalog");var _interpolate=require("./interpolate");const STEP_TIMEOUT_MS=exports.STEP_TIMEOUT_MS=1e4;const SCENARIO_TIMEOUT_MS=exports.SCENARIO_TIMEOUT_MS=6e4;const WAIT_FOR_TIMEOUT_MS=exports.WAIT_FOR_TIMEOUT_MS=6e3;const WAIT_FOR_POLL_MS=150;const FORBIDDEN_TOOLS=new Set(["scenarios"]);function isReloadStep(e){return e.action==="reloadApp"||e.action==="reload"}function preflight(e,n,i){const t=[];const c=[];if(e.source==="draft"){t.push("This scenario is still a draft \u2014 review and accept it before running.")}if(!e.steps.length)t.push("This scenario has no steps.");const s=new Set(e.vars.map(r=>r.key));const l=new Set;for(const r of e.steps)(0,_interpolate.collectPlaceholders)(r.params,l);(0,_interpolate.collectPlaceholders)(e.name,l);for(const r of l){if(!s.has(r)){t.push(`{{${r}}} is used but never declared as a variable.`)}else if(!(r in n)){t.push(`Variable "${r}" needs a value.`)}}for(const r of s){if(!l.has(r))c.push(`Variable "${r}" is never used.`)}const u=new Set(i.availableTools);e.steps.forEach((r,p)=>{const d=`Step ${p+1}`;if(FORBIDDEN_TOOLS.has(r.tool)){t.push(`${d}: a scenario cannot run another scenario.`);return}if(r.tool===_catalog.SCENARIO_TOOL)return;if(!u.has(r.tool)){t.push(`${d}: "${r.tool}" is not installed in this app, so this step cannot run.`);return}const m=i.availableActions?.[r.tool];if(m&&!m.includes(r.action)){t.push(`${d}: "${r.tool}" has no action "${r.action}".`)}if(isReloadStep(r)&&p!==e.steps.length-1){t.push(`${d}: reloading the app is only allowed as the last step.`)}if(!(0,_catalog.catalogEntry)(r.tool,r.action)){c.push(`${d}: ${r.tool}.${r.action} is an advanced step \u2014 its effects are not described or automatically undone.`)}});const o=new Set;for(const r of e.steps){for(const p of(0,_catalog.stepConflictKeys)(r,(0,_interpolate.interpolate)(r.params,n))){o.add(p)}}let a=null;const f=i.activeScenario;if(f&&f.scenarioId!==e.id){const r=f.conflictKeys.filter(p=>[...o].some(d=>(0,_catalog.conflictKeysOverlap)(p,d)));if(r.length){a={activeScenarioId:f.scenarioId,activeName:f.name,overlaps:r}}}if(i.extraErrors?.length)t.push(...i.extraErrors);return{ok:t.length===0,errors:t,warnings:c,conflict:a,conflictKeys:[...o]}}function withTimeout(e,n,i,t){return new Promise((c,s)=>{const l=()=>{clearTimeout(u);s(new Error("Scenario cancelled"))};const u=setTimeout(()=>{t?.removeEventListener("abort",l);s(new Error(`${i} timed out after ${n}ms`))},n);if(t?.aborted)l();else t?.addEventListener("abort",l,{once:true});e.then(o=>{clearTimeout(u);t?.removeEventListener("abort",l);c(o)},o=>{clearTimeout(u);t?.removeEventListener("abort",l);s(o)})})}function delay(e,n){return new Promise((i,t)=>{const c=()=>{clearTimeout(s);t(new Error("Scenario cancelled"))};const s=setTimeout(()=>{n?.removeEventListener("abort",c);i()},e);if(n?.aborted)c();else n?.addEventListener("abort",c,{once:true})})}async function waitFor(e,n,i,t){const c=typeof e.route==="string"?e.route:null;const s=typeof e.element==="string"?e.element:null;if(!c&&!s)return;const l=Date.now()+i;let u="nothing";while(Date.now()<l){if(t?.aborted)throw new Error("Scenario cancelled");if(c){const o=await n("route-events","getCurrentRoute").catch(()=>null);if(o?.path===c)return;if(typeof o?.path==="string")u=o.path}else if(s){const o=await n("highlight-updates","describeScreen").catch(()=>null);const a=s.toLowerCase();const f=(o?.elements??[]).some(r=>[r.testID,r.text,r.label].some(p=>typeof p==="string"&&p.toLowerCase().includes(a)));if(f)return;u=`${o?.elements?.length??0} elements`}await delay(WAIT_FOR_POLL_MS,t)}throw new Error(c?`Still on ${u} after ${i}ms \u2014 expected ${c}`:`\u201C${s}\u201D never appeared within ${i}ms`)}function resultError(e){if(e&&typeof e==="object"&&"ok"in e){const n=e;if(n.ok===false){return typeof n.error==="string"?n.error:"The step was rejected."}}return null}function extractEffect(e,n,i,t){if(e.tool==="network"&&e.action==="upsertOverrideRule"){const s=i;const l=s?.rule?.id;if(typeof l==="string"){return{kind:"override-rule",label:t,ruleId:l}}return null}if(e.tool==="impersonate"&&e.action==="startImpersonation"){const s=n.user;const l=typeof s?.id==="string"?s.id:void 0;return{kind:"impersonation",label:t,userId:l}}if(e.tool==="storage"){const[s,l=""]=e.action.split(".");const u=/^(setItem|removeItem|multiSet|multiRemove|clear|set|remove)$/.test(l);if(u){let o=typeof n.key==="string"?n.key:"";if(!o&&Array.isArray(n.pairs)){const a=n.pairs[0];o=Array.isArray(a)?String(a[0]??""):""}if(!o&&Array.isArray(n.keys))o=String(n.keys[0]??"");if(!o&&l==="clear")o="(all keys)";return{kind:"storage-write",label:t,backend:s,key:o}}}const c=stateWriteTarget(e,n);if(c!==null){return{kind:"state-write",label:t,tool:e.tool,store:c}}if(e.tool===_catalog.SCENARIO_TOOL)return null;return{kind:"transient",label:t,tool:e.tool,action:e.action}}function stateWriteTarget(e,n){const i=t=>typeof n[t]==="string"?n[t]:"";if(e.tool==="zustand"&&e.action==="setState"){return i("storeName")||"a store"}if(e.tool==="jotai"&&e.action==="setAtom"){return i("atom")||i("atomName")||"an atom"}if(e.tool==="redux"&&e.action==="dispatch"){const t=n.action;return typeof t?.type==="string"?t.type:"the redux store"}return null}async function withDirectoryUser(e,n){const i=e.user;const t=i?.id;if(!i||typeof t!=="string"&&typeof t!=="number")return e;const c=[i.email,i.name,i.displayName,t].filter(s=>typeof s==="string"||typeof s==="number");for(const s of c){try{const l=await n("impersonate","searchUsers",{query:String(s)});const u=Array.isArray(l)?l.find(o=>String(o?.id)===String(t)):void 0;if(u)return{...e,user:u}}catch{}}return e}async function runScenario(e,n,i,t){const c=[];const s=[];const l=Date.now();let u=false;for(let o=0;o<e.steps.length;o++){const a=e.steps[o];const f=(0,_interpolate.interpolate)(a.params??{},n);const r=(0,_catalog.describeStep)(a,f);if(u){c.push({id:a.id,label:r,ok:false,skipped:true,ms:0});continue}t?.onStep?.(o,"start");const p=Date.now();try{if(t?.signal?.aborted)throw new Error("Scenario cancelled");if(Date.now()-l>SCENARIO_TIMEOUT_MS){throw new Error("Scenario exceeded its overall time budget")}let d;if(a.tool===_catalog.SCENARIO_TOOL&&a.action==="wait"){const y=typeof f.ms==="number"?f.ms:0;await delay(Math.min(y,STEP_TIMEOUT_MS),t?.signal)}else if(a.tool===_catalog.SCENARIO_TOOL&&a.action==="waitFor"){await withTimeout(waitFor(f,i,a.timeoutMs??WAIT_FOR_TIMEOUT_MS,t?.signal),a.timeoutMs??WAIT_FOR_TIMEOUT_MS,r,t?.signal)}else{const y=a.tool==="impersonate"&&a.action==="startImpersonation"?await withDirectoryUser(f,i):f;d=await withTimeout(Promise.resolve(i(a.tool,a.action,y)),a.timeoutMs??STEP_TIMEOUT_MS,r,t?.signal);const S=resultError(d);if(S)throw new Error(S)}const m=Date.now()-p;c.push({id:a.id,label:r,ok:true,ms:m});const h=extractEffect(a,f,d,r);if(h)s.push(h);t?.onStep?.(o,"ok")}catch(d){const m=Date.now()-p;const h=d instanceof Error?d.message:String(d);c.push({id:a.id,label:r,ok:false,error:h,ms:m});t?.onStep?.(o,"error",h);u=true}}return{ok:!u,scenarioId:e.id,name:String((0,_interpolate.interpolateString)(e.name,n)),steps:c,effects:s}}async function revertEffects(e,n){let i=0;let t=false;let c=0;const s=[];const l=[];const u=[];for(const o of e){try{if(o.kind==="override-rule"){await n("network","deleteOverrideRule",{id:o.ruleId});i++}else if(o.kind==="impersonation"){await n("impersonate","stopImpersonation",{});t=true}else if(o.kind==="storage-write"){if(o.key)s.push(o.key)}else if(o.kind==="state-write"){if(o.store)l.push(o.store)}else{c++}}catch(a){u.push(a instanceof Error?a.message:String(a))}}return{removedRules:i,stoppedImpersonation:t,clearedTransients:c,unrestoredStorageKeys:s,unrestoredState:l,errors:u}}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.UNGROUPED=exports.MAX_FOLDER_LENGTH=void 0;exports.countInFolder=countInFolder;exports.inFolder=inFolder;exports.listFolders=listFolders;exports.normalizeFolder=normalizeFolder;exports.resolveFolder=resolveFolder;const UNGROUPED=exports.UNGROUPED="Ungrouped";const MAX_FOLDER_LENGTH=exports.MAX_FOLDER_LENGTH=32;function normalizeFolder(r){if(typeof r!=="string")return void 0;const o=r.replace(/\s+/g," ").trim().slice(0,MAX_FOLDER_LENGTH);return o||void 0}function resolveFolder(r,o){const e=normalizeFolder(r);if(!e)return void 0;const n=o.find(t=>t.toLowerCase()===e.toLowerCase());return n??e}function listFolders(r){const o=new Map;for(const e of r){const n=normalizeFolder(e.folder);if(!n)continue;const t=n.toLowerCase();if(!o.has(t))o.set(t,n)}return[...o.values()].sort((e,n)=>e.localeCompare(n,void 0,{sensitivity:"base"}))}function inFolder(r,o){const e=normalizeFolder(r.folder);if(o===void 0)return!e;return!!e&&e.toLowerCase()===o.toLowerCase()}function countInFolder(r,o){return r.reduce((e,n)=>inFolder(n,o)?e+1:e,0)}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.useActiveScenario=useActiveScenario;exports.useRecording=useRecording;exports.useScenariosRunState=useScenariosRunState;exports.useScenariosState=useScenariosState;var _react=require("react");var _recorderStore=require("../record/recorderStore");var _scenariosStore=require("../store/scenariosStore");function useScenariosState(){return(0,_react.useSyncExternalStore)(_scenariosStore.scenariosStore.subscribe,_scenariosStore.scenariosStore.getState)}function useActiveScenario(){return(0,_react.useSyncExternalStore)(_scenariosStore.scenariosStore.subscribe,()=>_scenariosStore.scenariosStore.getState().active)}function useScenariosRunState(){return(0,_react.useSyncExternalStore)(_scenariosStore.scenariosStore.subscribe,()=>_scenariosStore.scenariosStore.getState().runState)}function useRecording(){return(0,_react.useSyncExternalStore)(_recorderStore.recorderStore.subscribe,_recorderStore.recorderStore.getState)}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"DURABILITY_LABEL",{enumerable:true,get:function(){return _catalog.DURABILITY_LABEL}});Object.defineProperty(exports,"MAX_DEVICE_SCENARIOS",{enumerable:true,get:function(){return _scenariosStore.MAX_DEVICE_SCENARIOS}});Object.defineProperty(exports,"MAX_FOLDER_LENGTH",{enumerable:true,get:function(){return _folders.MAX_FOLDER_LENGTH}});Object.defineProperty(exports,"MacroReviewScreen",{enumerable:true,get:function(){return _MacroReviewScreen.MacroReviewScreen}});Object.defineProperty(exports,"RecordingBanner",{enumerable:true,get:function(){return _RecordingBanner.RecordingBanner}});Object.defineProperty(exports,"SCENARIOS_ICON_COLOR",{enumerable:true,get:function(){return _preset.SCENARIOS_ICON_COLOR}});Object.defineProperty(exports,"SCENARIO_TIMEOUT_MS",{enumerable:true,get:function(){return _engine.SCENARIO_TIMEOUT_MS}});Object.defineProperty(exports,"STEP_CATALOG",{enumerable:true,get:function(){return _catalog.STEP_CATALOG}});Object.defineProperty(exports,"STEP_TIMEOUT_MS",{enumerable:true,get:function(){return _engine.STEP_TIMEOUT_MS}});Object.defineProperty(exports,"ScenarioBanner",{enumerable:true,get:function(){return _ScenarioBanner.ScenarioBanner}});Object.defineProperty(exports,"ScenariosBody",{enumerable:true,get:function(){return _ScenariosBody.ScenariosBody}});Object.defineProperty(exports,"ScenariosIcon",{enumerable:true,get:function(){return _preset.ScenariosIcon}});Object.defineProperty(exports,"ScenariosOverlay",{enumerable:true,get:function(){return _ScenarioBanner.ScenariosOverlay}});Object.defineProperty(exports,"ScenariosToolView",{enumerable:true,get:function(){return _ScenariosToolView.ScenariosToolView}});Object.defineProperty(exports,"UNGROUPED",{enumerable:true,get:function(){return _folders.UNGROUPED}});Object.defineProperty(exports,"catalogEntry",{enumerable:true,get:function(){return _catalog.catalogEntry}});Object.defineProperty(exports,"coerceVarValue",{enumerable:true,get:function(){return _interpolate.coerceVarValue}});Object.defineProperty(exports,"collectPlaceholders",{enumerable:true,get:function(){return _interpolate.collectPlaceholders}});Object.defineProperty(exports,"condense",{enumerable:true,get:function(){return _condense.condense}});Object.defineProperty(exports,"conflictKeysOverlap",{enumerable:true,get:function(){return _catalog.conflictKeysOverlap}});Object.defineProperty(exports,"countInFolder",{enumerable:true,get:function(){return _folders.countInFolder}});Object.defineProperty(exports,"createScenariosTool",{enumerable:true,get:function(){return _preset.createScenariosTool}});Object.defineProperty(exports,"defineScenario",{enumerable:true,get:function(){return _defineScenario.defineScenario}});Object.defineProperty(exports,"describeStep",{enumerable:true,get:function(){return _catalog.describeStep}});Object.defineProperty(exports,"describeTarget",{enumerable:true,get:function(){return _condense.describeTarget}});Object.defineProperty(exports,"humanizeTestID",{enumerable:true,get:function(){return _condense.humanizeTestID}});Object.defineProperty(exports,"inFolder",{enumerable:true,get:function(){return _folders.inFolder}});Object.defineProperty(exports,"interpolate",{enumerable:true,get:function(){return _interpolate.interpolate}});Object.defineProperty(exports,"interpolateString",{enumerable:true,get:function(){return _interpolate.interpolateString}});Object.defineProperty(exports,"isAdvancedStep",{enumerable:true,get:function(){return _catalog.isAdvancedStep}});Object.defineProperty(exports,"listFolders",{enumerable:true,get:function(){return _folders.listFolders}});Object.defineProperty(exports,"macroToSteps",{enumerable:true,get:function(){return _condense.macroToSteps}});Object.defineProperty(exports,"missingVarKeys",{enumerable:true,get:function(){return _interpolate.missingVarKeys}});Object.defineProperty(exports,"normalizeFolder",{enumerable:true,get:function(){return _folders.normalizeFolder}});Object.defineProperty(exports,"preflight",{enumerable:true,get:function(){return _engine.preflight}});Object.defineProperty(exports,"recorderStore",{enumerable:true,get:function(){return _recorderStore.recorderStore}});Object.defineProperty(exports,"replaceScenariosFromSnapshot",{enumerable:true,get:function(){return _scenariosStore.replaceScenariosFromSnapshot}});Object.defineProperty(exports,"resolveFolder",{enumerable:true,get:function(){return _folders.resolveFolder}});Object.defineProperty(exports,"resolveVarValues",{enumerable:true,get:function(){return _interpolate.resolveVarValues}});Object.defineProperty(exports,"revertEffects",{enumerable:true,get:function(){return _engine.revertEffects}});Object.defineProperty(exports,"runScenario",{enumerable:true,get:function(){return _engine.runScenario}});Object.defineProperty(exports,"scenariosStore",{enumerable:true,get:function(){return _scenariosStore.scenariosStore}});Object.defineProperty(exports,"scenariosSyncAdapter",{enumerable:true,get:function(){return _scenariosSyncAdapter.scenariosSyncAdapter}});Object.defineProperty(exports,"scenariosToolPreset",{enumerable:true,get:function(){return _preset.scenariosToolPreset}});Object.defineProperty(exports,"selectorFor",{enumerable:true,get:function(){return _condense.selectorFor}});Object.defineProperty(exports,"setRemoteScenariosHandler",{enumerable:true,get:function(){return _scenariosStore.setRemoteScenariosHandler}});Object.defineProperty(exports,"stepConflictKeys",{enumerable:true,get:function(){return _catalog.stepConflictKeys}});Object.defineProperty(exports,"stepDurability",{enumerable:true,get:function(){return _catalog.stepDurability}});Object.defineProperty(exports,"titleFor",{enumerable:true,get:function(){return _condense.titleFor}});Object.defineProperty(exports,"useActiveScenario",{enumerable:true,get:function(){return _useScenarios.useActiveScenario}});Object.defineProperty(exports,"useScenariosRunState",{enumerable:true,get:function(){return _useScenarios.useScenariosRunState}});Object.defineProperty(exports,"useScenariosState",{enumerable:true,get:function(){return _useScenarios.useScenariosState}});var _preset=require("./preset");var _ScenariosBody=require("./components/ScenariosBody");var _ScenarioBanner=require("./components/ScenarioBanner");var _RecordingBanner=require("./components/RecordingBanner");var _MacroReviewScreen=require("./components/MacroReviewScreen");var _recorderStore=require("./record/recorderStore");var _condense=require("./record/condense");var _scenariosSyncAdapter=require("./sync/scenariosSyncAdapter");var _ScenariosToolView=require("./components/ScenariosToolView");var _scenariosStore=require("./store/scenariosStore");var _useScenarios=require("./hooks/useScenarios");var _defineScenario=require("./defineScenario");var _engine=require("./engine");var _catalog=require("./catalog");var _folders=require("./folders");var _interpolate=require("./interpolate");void _scenariosStore.scenariosStore.ensureLoaded();
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.coerceVarValue=coerceVarValue;exports.collectPlaceholders=collectPlaceholders;exports.interpolate=interpolate;exports.interpolateString=interpolateString;exports.missingVarKeys=missingVarKeys;exports.resolveVarValues=resolveVarValues;const PLACEHOLDER=/\{\{\s*(\w+)\s*\}\}/g;const EXACT_PLACEHOLDER=/^\{\{\s*(\w+)\s*\}\}$/;function collectPlaceholders(t,e=new Set){if(typeof t==="string"){for(const r of t.matchAll(PLACEHOLDER))e.add(r[1]);return e}if(Array.isArray(t)){for(const r of t)collectPlaceholders(r,e);return e}if(t&&typeof t==="object"){for(const r of Object.values(t))collectPlaceholders(r,e)}return e}function interpolateString(t,e){const r=t.match(EXACT_PLACEHOLDER);if(r&&r[1]in e)return e[r[1]];return t.replace(PLACEHOLDER,(n,o)=>o in e?String(e[o]):n)}function interpolate(t,e){if(typeof t==="string")return interpolateString(t,e);if(Array.isArray(t))return t.map(r=>interpolate(r,e));if(t&&typeof t==="object"){const r={};for(const[n,o]of Object.entries(t))r[n]=interpolate(o,e);return r}return t}function resolveVarValues(t,e={}){const r={};for(const n of t)if(n.default!==void 0)r[n.key]=n.default;for(const[n,o]of Object.entries(e)){if(o!==void 0)r[n]=o}return r}function missingVarKeys(t,e){return t.filter(r=>!(r.key in e)).map(r=>r.key)}function coerceVarValue(t,e){if(t.type==="number"){const r=typeof e==="number"?e:Number(e);return Number.isFinite(r)?r:0}if(t.type==="boolean"){return typeof e==="boolean"?e:e==="true"||e===1}return e}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});Object.defineProperty(exports,"SCENARIOS_ICON_COLOR",{enumerable:true,get:function(){return _floatingToolsCore.SCENARIOS_ICON_COLOR}});Object.defineProperty(exports,"ScenariosIcon",{enumerable:true,get:function(){return _floatingToolsCore.ScenariosIcon}});exports.createScenariosTool=createScenariosTool;exports.scenariosToolPreset=void 0;var _floatingToolsCore=require("@buoy-gg/floating-tools-core");var _ScenariosBody=require("./components/ScenariosBody");var _scenariosStore=require("./store/scenariosStore");var _jsxRuntime=require("react/jsx-runtime");const scenariosToolPreset=exports.scenariosToolPreset={id:"scenarios",name:"SCENARIOS",description:"One-tap app states for QA, support and demos",slot:"both",icon:({size:e,color:r})=>(0,_jsxRuntime.jsx)(_floatingToolsCore.ScenariosIcon,{size:e,color:r||_floatingToolsCore.SCENARIOS_ICON_COLOR}),component:_ScenariosBody.ScenariosBody,modal:{subtitle:"saved one-tap app states",searchable:true,searchPlaceholder:"Search name, tag, author\u2026"}};function createScenariosTool(e={}){if(e.scenarios?.length){_scenariosStore.scenariosStore.registerCodeScenarios(e.scenarios)}return{...scenariosToolPreset,name:e.name??scenariosToolPreset.name,description:e.description??scenariosToolPreset.description,component:()=>(0,_jsxRuntime.jsx)(_ScenariosBody.ScenariosBody,{currentBuild:e.currentBuild})}}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.UI_TOOL=exports.STATE_TOOL=exports.ROUTE_TOOL=void 0;exports.condense=condense;exports.describeTarget=describeTarget;exports.detailFor=detailFor;exports.fastForwardIndex=fastForwardIndex;exports.fastForwardTo=fastForwardTo;exports.humanizeTestID=humanizeTestID;exports.macroToSteps=macroToSteps;exports.replayAll=replayAll;exports.selectorFor=selectorFor;exports.suggestMacroName=suggestMacroName;exports.summarizeState=summarizeState;exports.titleFor=titleFor;const UI_TOOL=exports.UI_TOOL="highlight-updates";const ROUTE_TOOL=exports.ROUTE_TOOL="route-events";const STATE_TOOL=exports.STATE_TOOL="zustand";const TESTID_NOISE=new Set(["item","row","card","btn","button","cta","link","cell","tile","popular","open","tap","press","go"]);function humanizeTestID(e){const t=e.split(/[-_.]/).filter(Boolean);const n=t.length>=3?t.slice(1):t;const o=n.filter(s=>!TESTID_NOISE.has(s.toLowerCase()));const i=o.length?o:n;const r=i.join(" ").trim();if(!r)return e;return r.charAt(0).toUpperCase()+r.slice(1)}const NAME_MAX=28;function describeTarget(e){const t=e.testID?humanizeTestID(e.testID):void 0;const n=e.control==="text";const o=n?[e.label,t,e.text]:[e.label,e.text,t];const i=o.filter(s=>typeof s==="string"&&s.trim().length>0);const r=i.find(s=>s.trim().length<=NAME_MAX);if(r)return r.trim();if(i.length)return truncate(i[0].trim(),NAME_MAX);return e.name}function selectorFor(e){if(e.testID)return{testID:e.testID};const t=e.label??e.text;if(t&&t.trim())return{query:t.trim()};return null}function truncate(e,t=32){const n=typeof e==="string"?e:JSON.stringify(e);if(typeof n!=="string")return"";return n.length>t?`${n.slice(0,t)}\u2026`:n}function titleFor(e){const{touch:t}=e;const n=describeTarget(t.target);switch(t.kind){case"text":return`Type \u201C${truncate(t.value)}\u201D into ${n}`;case"toggle":return`${t.value===false?"Turn off":"Turn on"} ${n}`;case"slider":return`Set ${n} to ${truncate(t.value)}`;case"longPress":return`Press and hold \u201C${n}\u201D`;default:return`Tap \u201C${n}\u201D`}}function summarizeState(e){if(e==null||typeof e!=="object")return void 0;const t=[];for(const[n,o]of Object.entries(e)){if(typeof o==="function")continue;if(Array.isArray(o)){t.push(`${o.length} ${n}`)}else if(o==null||typeof o!=="object"){if(o===null||o===""||o===false||o===0)continue;t.push(`${n} ${truncate(o,16)}`)}if(t.length>=3)break}return t.length?t.join(", "):void 0}function detailFor(e){const t=[];if(e.effects.route&&e.effects.route!==e.routeBefore){t.push(`went to ${e.effects.route}`)}for(const n of e.effects.stores??[]){const o=summarizeState(n.state);t.push(o?`${n.name} \u2192 ${o}`:`changed ${n.name}`)}return t.length?t.join(" \xB7 "):void 0}let uid=0;const nextId=e=>`${e}-${Date.now().toString(36)}-${(uid++).toString(36)}`;function uiStepsFor(e){const t=selectorFor(e.touch.target);if(!t)return[];const n={...t};const{touch:o}=e;if(o.kind==="longPress")n.longPress=true;if(o.kind==="text")n.text=o.value;if(o.kind==="toggle"||o.kind==="slider")n.value=o.value;const i=[{id:nextId("ui"),tool:UI_TOOL,action:"tapElement",params:n,label:titleFor(e)}];const r=e.effects.route;if(r&&r!==e.routeBefore){i.push({id:nextId("wait"),tool:"scenario",action:"waitFor",params:{route:r},label:`Wait for ${r}`})}return i}function stateStepsFor(e){const t=[];for(const o of e.effects.stores??[]){t.push({id:nextId("state"),tool:STATE_TOOL,action:"setState",params:{storeName:o.name,state:o.state,replace:true,persisted:o.persisted??false},label:`Set ${o.name}`})}const n=e.effects.route;if(n&&n!==e.routeBefore){t.push({id:nextId("nav"),tool:ROUTE_TOOL,action:"navigate",params:{path:n},label:`Go to ${n}`})}return t}function preconditionRow(e){const t={id:nextId("start"),tool:ROUTE_TOOL,action:"navigate",params:{path:e,reset:true},label:`Go to ${e}`};return{id:nextId("pre"),precondition:true,title:`Start from ${e}`,detail:"so it can run from anywhere",lane:"state",lanes:["state"],enabled:true,noise:false,ui:[],state:[t]}}function condense(e,t){const n=e.map(o=>{const i=uiStepsFor(o);const r=stateStepsFor(o);const s=[];if(i.length)s.push("ui");if(r.length)s.push("state");return{id:o.id,title:titleFor(o),detail:detailFor(o),lane:s.includes("ui")?"ui":"state",lanes:s,enabled:s.length>0,noise:s.length===0,ui:i,state:r}});if(t&&n.length)return[preconditionRow(t),...n];return n}function collapseKey(e){if(e.tool===STATE_TOOL&&e.action==="setState"){const t=e.params?.storeName;return t?`${STATE_TOOL}:${t}`:null}if(e.tool===ROUTE_TOOL&&e.action==="navigate")return"route";return null}function macroToSteps(e){const t=[];let n=new Map;let o=0;const i=()=>{for(const r of n.values())t.push(r);n=new Map;o=0};for(const r of e){if(!r.enabled||r.noise)continue;const s=r.lane==="state"?r.state:r.ui;if(!s.length)continue;if(r.lane!=="state"){i();t.push(...s);continue}for(const a of s){const l=collapseKey(a);if(l==null){n.set(`\0${o++}`,a);continue}n.delete(l);n.set(l,a)}}i();return t}function fastForwardTo(e,t){return e.map((n,o)=>{if(n.precondition)return n;if(o>t){return{...n,lane:"ui",enabled:!n.noise&&n.lanes.length>0}}if(n.lanes.includes("state")){return{...n,lane:"state",enabled:true}}return{...n,enabled:false}})}function replayAll(e){return e.map(t=>t.precondition?t:{...t,lane:t.lanes.includes("ui")?"ui":"state",enabled:t.lanes.length>0&&!t.noise})}function fastForwardIndex(e){let t=-1;for(let n=0;n<e.length;n++){const o=e[n];if(o.precondition)continue;if(o.enabled&&o.lane==="state"){t=n;continue}if(!o.enabled)continue;break}return t}const GENERIC_TAPS=/^(continue|next|ok|done|submit|save|confirm|apply|back|close|cancel|open|add\b|view\b|go to\b|place order|checkout|check out)/i;function suggestMacroName(e){const t=e.filter(s=>s.enabled&&!s.noise);let n;for(const s of t){for(const a of s.state??[]){const l=a.params?.path;if(a.tool===ROUTE_TOOL&&a.action==="navigate"&&typeof l==="string")n=l}}const o=n?.split("?")[0].split("/").filter(Boolean).pop();const i=n===void 0?"":o?titleCase(o.replace(/[-_]/g," ")):"Home";let r="";for(const s of[...t].reverse()){if(s.precondition)continue;const a=s.title.match(/“([^”]+)”/)?.[1]?.split(",")[0].trim();if(a&&!GENERIC_TAPS.test(a)){r=a;break}}if(i&&r)return`${i} \xB7 ${r}`;if(i||r)return i||r;return t.length?`${t.length} recorded step${t.length===1?"":"s"}`:""}function titleCase(e){return e.replace(/\b\w/g,t=>t.toUpperCase())}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.recorderStore=void 0;var _sharedUi=require("@buoy-gg/shared-ui");var _condense=require("./condense");const POLL_MS=250;const SETTLE_MS=1200;const EMPTY={status:"idle",reason:null,startedAt:null,startRoute:void 0,actions:[],draft:null};let uid=0;const nextId=()=>`act-${Date.now().toString(36)}-${(uid++).toString(36)}`;class RecorderStore{state=EMPTY;listeners=new Set;timer=null;sinceSeq=0;storeChanges=new Map;holds=[];ticking=false;getState=()=>this.state;subscribe=t=>{this.listeners.add(t);return()=>{this.listeners.delete(t)}};setState(t){this.state={...this.state,...t};this.listeners.forEach(e=>{try{e()}catch{}})}canRecord(){const t=(0,_sharedUi.getToolAdapters)();return typeof t[_condense.UI_TOOL]?.actions?.startTouchCapture==="function"}async start(){if(this.state.status==="recording")return;if(!this.canRecord()){this.setState({status:"unavailable",reason:"Recording needs the Highlight Updates tool installed \u2014 it owns the screen reader this uses to name what you tap."});return}this.holds=[];for(const e of[_condense.ROUTE_TOOL,_condense.STATE_TOOL]){const s=(0,_sharedUi.getToolAdapters)()[e]?.subscribe;if(s){try{this.holds.push(s(()=>{}))}catch{}}}await this.call(_condense.UI_TOOL,"clearTouchCapture");const t=await this.call(_condense.UI_TOOL,"startTouchCapture");if(t?.status!=="capturing"){this.releaseHolds();this.setState({status:"unavailable",reason:t?.reason??"This build of React Native doesn't expose the touch stream Buoy records from."});return}this.sinceSeq=0;this.route=await this.readRoute();this.storeChanges=await this.readStoreChanges();this.setState({status:"recording",reason:null,startedAt:Date.now(),startRoute:this.route,actions:[],draft:null});this.timer=setInterval(()=>void this.tick(),POLL_MS)}async stop(){if(this.state.status!=="recording")return;this.clearTimer();await new Promise(t=>setTimeout(t,SETTLE_MS));await this.tick();await this.call(_condense.UI_TOOL,"stopTouchCapture");this.releaseHolds();this.setState({status:"review",draft:(0,_condense.condense)(this.state.actions,this.state.startRoute)})}async cancel(){this.clearTimer();if(this.state.status==="recording"){await this.call(_condense.UI_TOOL,"stopTouchCapture")}this.releaseHolds();this.setState({...EMPTY})}setDraft(t){if(this.state.status!=="review")return;this.setState({draft:t})}clearTimer(){if(this.timer){clearInterval(this.timer);this.timer=null}}releaseHolds(){this.holds.forEach(t=>{try{t()}catch{}});this.holds=[]}async tick(){if(this.ticking)return;this.ticking=true;try{const t=await this.call(_condense.UI_TOOL,"readTouchCapture",{sinceSeq:this.sinceSeq});const e=[...this.state.actions];let s=false;for(const a of t?.records??[]){e.push({id:nextId(),touch:a,routeBefore:this.route,effects:{}});s=true}if(t?.seq)this.sinceSeq=t.seq;const r=e[e.length-1];const o=await this.readRoute();if(o!==void 0&&o!==this.route){this.route=o;if(r){r.effects={...r.effects,route:o};s=true}}const u=await this.readStoreChanges();const c=[];for(const[a,i]of u){const n=this.storeChanges.get(a);if(n!==void 0&&n.changes!==i.changes){c.push({name:a,persisted:i.persisted})}}this.storeChanges=u;if(r&&c.length){const a=[...r.effects.stores??[]];for(const{name:i,persisted:n}of c){const h=await this.readStoreState(i);if(h===void 0)continue;const l=a.findIndex(d=>d.name===i);if(l>=0)a[l]={name:i,state:h,persisted:n};else a.push({name:i,state:h,persisted:n})}if(a.length){r.effects={...r.effects,stores:a};s=true}}if(s)this.setState({actions:e})}finally{this.ticking=false}}async call(t,e,s){try{return await(0,_sharedUi.dispatchToolAction)(t,e,s)}catch{return null}}async readRoute(){const t=await this.call(_condense.ROUTE_TOOL,"getCurrentRoute");const e=t?.path;return typeof e==="string"?e:void 0}async readStoreChanges(){const t=await this.call(_condense.STATE_TOOL,"listStores",{});const e=new Map;for(const s of t?.stores??[]){if(!s?.name)continue;e.set(s.name,{changes:s.changes??0,persisted:s.isPersisted===true})}return e}async readStoreState(t){const e=await this.call(_condense.STATE_TOOL,"getStoreState",{storeName:t});if(!e?.found)return void 0;return e.currentState}}const recorderStore=exports.recorderStore=new RecorderStore;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.MAX_DEVICE_SCENARIOS=void 0;exports.installedToolIds=installedToolIds;exports.replaceScenariosFromSnapshot=replaceScenariosFromSnapshot;exports.scenariosStore=void 0;exports.setRemoteScenariosHandler=setRemoteScenariosHandler;var _sharedUi=require("@buoy-gg/shared-ui");var _engine=require("../engine");var _catalog=require("../catalog");var _defineScenario=require("../defineScenario");var _folders=require("../folders");var _interpolate=require("../interpolate");const LIBRARY_KEY=_sharedUi.devToolsStorageKeys.scenarios.library();const ACTIVE_KEY=_sharedUi.devToolsStorageKeys.scenarios.active();const MAX_DEVICE_SCENARIOS=exports.MAX_DEVICE_SCENARIOS=100;let remoteHandler=null;function setRemoteScenariosHandler(d){remoteHandler=d}function isRunnableInThisBuild(){return!(typeof __DEV__!=="undefined"&&!__DEV__)}class ScenariosStore{state={code:[],device:[],drafts:[],active:null,runState:null,lastDeactivateReport:null,hasLoaded:false,lastVarValues:{}};listeners=new Set;loadPromise=null;expiryTimer=null;runController=null;getState=()=>this.state;subscribe=t=>{this.listeners.add(t);void this.ensureLoaded();return()=>{this.listeners.delete(t)}};setState(t){this.state={...this.state,...t};this.listeners.forEach(e=>{try{e()}catch{}})}allScenarios(){const t=new Set(this.state.code.map(e=>e.id));return[...this.state.code,...this.state.device.filter(e=>!t.has(e.id))]}find(t){return this.allScenarios().find(e=>e.id===t)??this.state.drafts.find(e=>e.id===t)}folders(){return(0,_folders.listFolders)([...this.state.code,...this.state.device,...this.state.drafts])}registerCodeScenarios(t){const e=new Map(this.state.code.map(r=>[r.id,r]));for(const r of t)e.set(r.id,{...r,source:"code"});this.setState({code:[...e.values()]})}ensureLoaded(){if(remoteHandler)return Promise.resolve();if(!this.loadPromise){this.loadPromise=this.load()}return this.loadPromise}async load(){let t=[];let e=[];let r={};try{const a=await _sharedUi.persistentStorage.getItem(LIBRARY_KEY);if(a){const i=JSON.parse(a);t=Array.isArray(i.device)?i.device:[];e=Array.isArray(i.drafts)?i.drafts:[];r=i.lastVarValues&&typeof i.lastVarValues==="object"?i.lastVarValues:{}}}catch{}let s=null;try{const a=await _sharedUi.persistentStorage.getItem(ACTIVE_KEY);if(a)s=JSON.parse(a)}catch{s=null}this.setState({device:t,drafts:e,lastVarValues:r,active:s,hasLoaded:true});if(s)await this.reconcileActive()}async persistLibrary(){if(remoteHandler)return;const t={version:1,device:this.state.device,drafts:this.state.drafts,lastVarValues:this.state.lastVarValues};try{await _sharedUi.persistentStorage.setItem(LIBRARY_KEY,JSON.stringify(t))}catch{}}async persistActive(){if(remoteHandler)return;try{if(this.state.active){await _sharedUi.persistentStorage.setItem(ACTIVE_KEY,JSON.stringify(this.state.active))}else{await _sharedUi.persistentStorage.removeItem(ACTIVE_KEY)}}catch{}}async reconcileActive(){const t=this.state.active;if(!t)return;const e=t.effects.filter(r=>r.kind==="override-rule");if(!e.length)return;if(!(0,_sharedUi.listToolIds)().includes("network"))return;try{const r=await(0,_sharedUi.dispatchToolAction)("network","listOverrideRules",{});const s=new Set((r?.rules??[]).map(i=>i.id));const a=t.effects.filter(i=>i.kind!=="override-rule"||s.has(i.ruleId));if(a.length===t.effects.length)return;if(!a.length){this.setState({active:null})}else{this.setState({active:{...t,effects:a}})}await this.persistActive()}catch{}}checkBeforeRun(t,e,r=[]){const s=this.state.active;const a=[...r];if(!isRunnableInThisBuild()){a.push("Scenarios cannot run in a production build.")}const i=(0,_interpolate.resolveVarValues)(t.vars,e);return(0,_engine.preflight)(t,i,{availableTools:(0,_sharedUi.listToolIds)(),availableActions:(0,_sharedUi.listToolActions)(),activeScenario:s?{scenarioId:s.scenarioId,name:s.name,conflictKeys:this.activeConflictKeys()}:null,extraErrors:a})}holdObservers(t){const e=[];const r=(0,_sharedUi.getToolAdapters)();for(const s of t){const a=r[s]?.subscribe;if(!a)continue;try{e.push(a(()=>{}))}catch{}}return e}activeConflictKeys(){const t=this.state.active;if(!t)return[];const e=this.find(t.scenarioId);if(!e)return[];const r=new Set;for(const s of e.steps){for(const a of(0,_catalog.stepConflictKeys)(s,(0,_interpolate.interpolate)(s.params,t.varValues))){r.add(a)}}return[...r]}async run(t,e={},r={}){(0,_sharedUi.assertAccountAccess)();if(remoteHandler){return await remoteHandler("run",{id:t,params:e})}await this.ensureLoaded();(0,_sharedUi.assertAccountAccess)();const s=this.find(t);if(!s)throw new Error(`No scenario "${t}"`);if(s.source==="draft"){throw new Error("Drafts must be accepted before they can run.")}if(!isRunnableInThisBuild()){throw new Error("Scenarios cannot run in a production build.")}if(!await(0,_sharedUi.waitForToolRegistry)()){throw new Error("Buoy tools are still starting up \u2014 try again in a moment.")}const a=(0,_interpolate.resolveVarValues)(s.vars,e);if(this.state.active&&this.state.active.scenarioId!==t){await this.deactivate()}else if(this.state.active){const o=this.state.active;await(0,_engine.revertEffects)(o.effects.filter(l=>l.kind==="override-rule"),_sharedUi.dispatchToolAction);this.setState({active:{...o,effects:o.effects.filter(l=>l.kind!=="override-rule")}})}(0,_sharedUi.assertAccountAccess)();this.setState({runState:{scenarioId:t,name:(0,_interpolate.interpolateString)(s.name,a),steps:[],current:0,done:false}});const i=this.holdObservers(["route-events"]);let c;this.runController?.abort();const n=new AbortController;this.runController=n;try{c=await(0,_engine.runScenario)(s,a,_sharedUi.dispatchToolAction,{signal:n.signal,onStep:o=>{const l=this.state.runState;if(l)this.setState({runState:{...l,current:o}})}})}finally{if(this.runController===n)this.runController=null;i.forEach(o=>{try{o()}catch{}})}this.setState({runState:{scenarioId:t,name:(0,_interpolate.interpolateString)(s.name,a),steps:c.steps,current:-1,done:true,report:c}});if(c.ok&&(0,_sharedUi.hasAccountAccess)()){const o={scenarioId:t,name:(0,_interpolate.interpolateString)(s.name,a),version:s.version,source:s.source,runAt:Date.now(),varValues:a,effects:c.effects,expiresAt:r.expiresInMs?Date.now()+r.expiresInMs:void 0};this.setState({active:o,lastDeactivateReport:null,lastVarValues:{...this.state.lastVarValues,[t]:a}});this.bumpUsage(t);this.armExpiry();await this.persistActive();await this.persistLibrary()}return c}async undoPartialRun(){const t=this.state.runState?.report;if(!t){return{removedRules:0,stoppedImpersonation:false,clearedTransients:0,unrestoredStorageKeys:[],unrestoredState:[],undoStepsRan:0,errors:[]}}const e=await(0,_engine.revertEffects)(t.effects,_sharedUi.dispatchToolAction);const r={...e,undoStepsRan:0};this.setState({runState:null,lastDeactivateReport:r});return r}clearRunState(){this.setState({runState:null})}bumpUsage(t){const e=r=>r.map(s=>s.id===t?{...s,usage:{runs:(s.usage?.runs??0)+1,lastRunAt:Date.now()}}:s);this.setState({code:e(this.state.code),device:e(this.state.device)})}async deactivate(){if(remoteHandler){return await remoteHandler("deactivate",{})}const t=this.state.active;if(!t){const n={removedRules:0,stoppedImpersonation:false,clearedTransients:0,unrestoredStorageKeys:[],unrestoredState:[],undoStepsRan:0,errors:[]};return n}const e=await(0,_engine.revertEffects)(t.effects,_sharedUi.dispatchToolAction);const r=[...e.errors];let s=0;const a=this.find(t.scenarioId);const i=a?.undoSteps??[];if(i.length){const n=await(0,_engine.runScenario)({...a,steps:i},t.varValues,_sharedUi.dispatchToolAction);s=n.steps.filter(o=>o.ok).length;for(const o of n.steps){if(!o.ok&&o.error)r.push(o.error)}}const c={removedRules:e.removedRules,stoppedImpersonation:e.stoppedImpersonation,clearedTransients:e.clearedTransients,unrestoredStorageKeys:s?[]:e.unrestoredStorageKeys,unrestoredState:s?[]:e.unrestoredState,undoStepsRan:s,errors:r};this.clearExpiry();this.setState({active:null,lastDeactivateReport:c});await this.persistActive();return c}async disposeAccountSession(t){this.runController?.abort();this.runController=null;if((0,_sharedUi.hasAccountAccess)())return;this.clearExpiry();const e=this.state.active;if(!e||remoteHandler)return;const r=await(0,_engine.revertEffects)(e.effects.filter(s=>s.kind==="override-rule"),t);this.setState({active:null});await this.persistActive();if(r.errors.length)throw new Error(r.errors.join("; "))}dismissDeactivateReport(){this.setState({lastDeactivateReport:null})}armExpiry(){this.clearExpiry();const t=this.state.active?.expiresAt;if(!t)return;const e=Math.max(0,t-Date.now());this.expiryTimer=setTimeout(()=>{void this.deactivate()},e)}clearExpiry(){if(this.expiryTimer){clearTimeout(this.expiryTimer);this.expiryTimer=null}}isLongRunning(t=8*60*60*1e3){const e=this.state.active;return!!e&&Date.now()-e.runAt>t}async saveScenario(t,e={}){await this.ensureLoaded();const r=Date.now();const s=e.asDraft??false;const a=s?this.state.drafts:this.state.device;const i=a.findIndex(o=>o.id===t.id);const c={...t,steps:(0,_defineScenario.withStepIds)(t.steps,"s"),undoSteps:t.undoSteps?(0,_defineScenario.withStepIds)(t.undoSteps,"u"):void 0,folder:(0,_folders.resolveFolder)(t.folder,this.folders()),source:s?"draft":"device",version:i>=0?(a[i].version??1)+1:t.version||1,createdAt:i>=0?a[i].createdAt:r,updatedAt:r,usage:i>=0?a[i].usage:{runs:0}};if(!s&&i<0&&this.state.device.length>=MAX_DEVICE_SCENARIOS){throw new Error(`This device already holds ${MAX_DEVICE_SCENARIOS} scenarios \u2014 delete one first.`)}const n=[...a];if(i>=0)n[i]=c;else n.unshift(c);this.setState(s?{drafts:n}:{device:n});await this.persistLibrary();return c}async acceptDraft(t){await this.ensureLoaded();const e=this.state.drafts.find(s=>s.id===t);if(!e)throw new Error(`No draft "${t}"`);const r={...e,source:"device",unsavedToRepo:true,updatedAt:Date.now()};this.setState({drafts:this.state.drafts.filter(s=>s.id!==t),device:[r,...this.state.device]});await this.persistLibrary();return r}async discardDraft(t){await this.ensureLoaded();this.setState({drafts:this.state.drafts.filter(e=>e.id!==t)});await this.persistLibrary()}async setFolder(t,e){await this.ensureLoaded();if(remoteHandler){const n=await remoteHandler("setFolder",{id:t,folder:e});return n.scenario}if(this.state.code.some(n=>n.id===t)){throw new Error("Scenarios shipped with the app are filed in code \u2014 change `folder` in defineScenario().")}const r=(0,_folders.resolveFolder)(e,this.folders());let s;const a=n=>n.map(o=>{if(o.id!==t)return o;s={...o,folder:r,updatedAt:Date.now()};return s});const i=a(this.state.device);const c=s?this.state.drafts:a(this.state.drafts);if(!s)throw new Error(`No scenario "${t}"`);this.setState({device:i,drafts:c});await this.persistLibrary();return s}async deleteScenario(t){await this.ensureLoaded();if(this.state.active?.scenarioId===t)await this.deactivate();this.setState({device:this.state.device.filter(e=>e.id!==t)});await this.persistLibrary()}rememberVarValues(t,e){this.setState({lastVarValues:{...this.state.lastVarValues,[t]:e}});void this.persistLibrary()}lastValuesFor(t){return this.state.lastVarValues[t]??{}}replaceFromSnapshot(t){this.setState({code:t.code??[],device:t.device??[],drafts:t.drafts??[],active:t.active??null,runState:t.runState??null,hasLoaded:true})}}const scenariosStore=exports.scenariosStore=new ScenariosStore;function replaceScenariosFromSnapshot(d){scenariosStore.replaceFromSnapshot(d)}function installedToolIds(){return Object.keys((0,_sharedUi.getToolAdapters)())}
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.scenariosSyncAdapter=void 0;var _catalog=require("../catalog");var _interpolate=require("../interpolate");var _scenariosStore=require("../store/scenariosStore");const MAX_STEP_BYTES=64*1024;const MAX_SCENARIO_BYTES=256*1024;function readString(e,r){const t=e?.[r];return typeof t==="string"&&t.trim()?t.trim():void 0}function readValues(e){const r=e?.params;if(!r||typeof r!=="object")return{};const t={};for(const[o,s]of Object.entries(r)){if(typeof s==="string"||typeof s==="number"||typeof s==="boolean"){t[o]=s}}return t}const WIRE_STEP_LIMIT=8*1024;function summarize(e){return{id:e.id,name:e.name,description:e.description,version:e.version,source:e.source,author:e.author,folder:e.folder,tags:e.tags,vars:e.vars,stepCount:e.steps.length,expectedOutcome:e.expectedOutcome,authoredAgainst:e.authoredAgainst,verifiedAt:e.verifiedAt,unsavedToRepo:e.unsavedToRepo,usage:e.usage,createdAt:e.createdAt,updatedAt:e.updatedAt,steps:e.steps.map(r=>{const t=JSON.stringify(r.params??{}).length;return t>WIRE_STEP_LIMIT?{...r,params:void 0,paramsOmitted:true}:r}),stepLines:e.steps.map(r=>({label:(0,_catalog.describeStep)(r),durability:(0,_catalog.stepDurability)(r)}))}}function validateIncoming(e){const r=[];if(!e.id||typeof e.id!=="string"){r.push("A scenario needs a string `id`.")}if(!e.name||typeof e.name!=="string"){r.push("A scenario needs a `name`.")}if(!Array.isArray(e.steps)||!e.steps.length){r.push("A scenario needs at least one step.")}else{e.steps.forEach((o,s)=>{if(!o||typeof o!=="object"){r.push(`Step ${s+1} is not an object.`);return}if(!o.tool||!o.action){r.push(`Step ${s+1} needs both \`tool\` and \`action\`.`)}const n=JSON.stringify(o.params??{}).length;if(n>MAX_STEP_BYTES){r.push(`Step ${s+1} is ${Math.round(n/1024)}KB \u2014 over the 64KB limit. Use a smaller response body.`)}})}if(e.vars&&!Array.isArray(e.vars)){r.push("`vars` must be an array.")}const t=JSON.stringify(e).length;if(t>MAX_SCENARIO_BYTES){r.push(`The scenario is ${Math.round(t/1024)}KB \u2014 over the 256KB limit.`)}return r}function snapshot(){const e=_scenariosStore.scenariosStore.getState();return{code:e.code.map(summarize),device:e.device.map(summarize),drafts:e.drafts.map(summarize),active:e.active,runState:e.runState,hasLoaded:e.hasLoaded,folders:_scenariosStore.scenariosStore.folders()}}const scenariosSyncAdapter=exports.scenariosSyncAdapter={dispose:e=>_scenariosStore.scenariosStore.disposeAccountSession(e),version:1,getSnapshot:()=>snapshot(),subscribe:e=>_scenariosStore.scenariosStore.subscribe(e),actions:{listScenarios:()=>snapshot(),getScenario:e=>{const r=readString(e,"id");if(!r)throw new Error("getScenario requires an `id`");const t=_scenariosStore.scenariosStore.find(r);if(!t)throw new Error(`No scenario "${r}"`);return{scenario:t}},save:async e=>{const r=e??{};const t=r.scenario;if(!t)return{ok:false,error:"save requires a `scenario`."};const o=validateIncoming(t);if(o.length)return{ok:false,errors:o};const s=Date.now();const n={id:t.id,name:t.name,description:t.description,version:t.version??1,source:"draft",author:t.author??"remote",vars:t.vars??[],steps:t.steps,undoSteps:t.undoSteps,folder:t.folder,tags:t.tags,expectedOutcome:t.expectedOutcome,authoredAgainst:t.authoredAgainst,unsavedToRepo:true,createdAt:s,updatedAt:s,usage:{runs:0}};const i=await _scenariosStore.scenariosStore.saveScenario(n,{asDraft:true});return{ok:true,savedAsDraft:true,id:i.id,message:"Saved as a draft. Open Scenarios on the device to review and accept it."}},acceptDraft:async e=>{const r=readString(e,"id");if(!r)throw new Error("acceptDraft requires an `id`");const t=await _scenariosStore.scenariosStore.acceptDraft(r);return{ok:true,id:t.id}},discardDraft:async e=>{const r=readString(e,"id");if(!r)throw new Error("discardDraft requires an `id`");await _scenariosStore.scenariosStore.discardDraft(r);return{ok:true,id:r}},preview:e=>{const r=readString(e,"id");if(!r)throw new Error("preview requires an `id`");const t=_scenariosStore.scenariosStore.find(r);if(!t)throw new Error(`No scenario "${r}"`);const o=(0,_interpolate.resolveVarValues)(t.vars,readValues(e));const s=_scenariosStore.scenariosStore.checkBeforeRun(t,o);return{willDo:t.steps.map(n=>({label:(0,_catalog.describeStep)(n,(0,_interpolate.interpolate)(n.params??{},o)),durability:(0,_catalog.stepDurability)(n)})),values:o,ok:s.ok,errors:s.errors,warnings:s.warnings,conflict:s.conflict,expectedOutcome:t.expectedOutcome}},run:async e=>{const r=readString(e,"id");if(!r)throw new Error("run requires an `id`");const t=readValues(e);const o=_scenariosStore.scenariosStore.find(r);if(!o)throw new Error(`No scenario "${r}"`);const s=_scenariosStore.scenariosStore.checkBeforeRun(o,t);if(!s.ok){return{ok:false,preflightErrors:s.errors,conflict:s.conflict}}return await _scenariosStore.scenariosStore.run(r,t)},deactivate:async()=>{const e=await _scenariosStore.scenariosStore.deactivate();return{ok:true,report:e}},delete:async e=>{const r=readString(e,"id");if(!r)throw new Error("delete requires an `id`");await _scenariosStore.scenariosStore.deleteScenario(r);return{ok:true,id:r}},listFolders:()=>({folders:_scenariosStore.scenariosStore.folders()}),setFolder:async e=>{const r=readString(e,"id");if(!r)throw new Error("setFolder requires an `id`");const t=readString(e,"folder");const o=await _scenariosStore.scenariosStore.setFolder(r,t);return{ok:true,id:o.id,folder:o.folder??null}},getActive:()=>({active:_scenariosStore.scenariosStore.getState().active}),export:e=>{const r=readString(e,"id");if(!r)throw new Error("export requires an `id`");const t=_scenariosStore.scenariosStore.find(r);if(!t)throw new Error(`No scenario "${r}"`);return{json:JSON.stringify(t,null,2)}}}};
@@ -0,0 +1 @@
1
+ "use strict";
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.DurabilityChip=DurabilityChip;exports.Footnote=Footnote;exports.Notice=Notice;exports.Panel=Panel;exports.PanelSeparator=PanelSeparator;exports.PillLabel=PillLabel;exports.SectionLabel=SectionLabel;var _reactNative=require("react-native");var _sharedUi=require("@buoy-gg/shared-ui");var _scnTheme=require("./scnTheme");var _jsxRuntime=require("react/jsx-runtime");function SectionLabel({children:r,icon:e,count:o,color:n=_scnTheme.scn.color.accent,testID:t,countTestID:l}){return(0,_jsxRuntime.jsx)(_reactNative.View,{testID:t,collapsable:false,children:(0,_jsxRuntime.jsxs)(_sharedUi.SectionHeader,{children:[e?(0,_jsxRuntime.jsx)(_sharedUi.SectionHeader.Icon,{icon:e,color:n,size:14}):null,(0,_jsxRuntime.jsx)(_sharedUi.SectionHeader.Title,{children:r}),o!==void 0?(0,_jsxRuntime.jsx)(_sharedUi.SectionHeader.Badge,{count:o,color:n,testID:l}):null]})})}function Footnote({children:r,centered:e,tone:o="secondary",testID:n}){return(0,_jsxRuntime.jsx)(_reactNative.Text,{style:[styles.footnote,e?styles.footnoteCentered:null,o==="warning"?styles.footnoteWarning:null,o==="danger"?styles.footnoteDanger:null],testID:n,children:r})}function Panel({children:r,tone:e="neutral",style:o,testID:n}){return(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.panel,e==="sim"?styles.panelSim:null,e==="danger"?styles.panelDanger:null,e==="info"?styles.panelInfo:null,o],testID:n,children:r})}function PanelSeparator(){return(0,_jsxRuntime.jsx)(_reactNative.View,{style:styles.panelSeparator})}function Notice({children:r,tone:e,testID:o}){return(0,_jsxRuntime.jsx)(_reactNative.View,{style:[styles.notice,e==="sim"?styles.noticeSim:null,e==="danger"?styles.noticeDanger:null,e==="info"?styles.noticeInfo:null],testID:o,children:r})}function PillLabel({label:r,color:e,testID:o}){return(0,_jsxRuntime.jsx)(_sharedUi.Pill,{label:r,color:e,variant:"tinted",style:{height:26,paddingHorizontal:10,borderRadius:_scnTheme.scn.radius.pill,justifyContent:"center"},testID:o})}function DurabilityChip({label:r,tone:e,testID:o}){const n=e==="durable"?_scnTheme.scn.color.accent:e==="transient"?_scnTheme.scn.color.sim:_scnTheme.scn.color.textTertiary;return(0,_jsxRuntime.jsx)(_sharedUi.Pill,{label:r,color:n,variant:"tinted",mono:true,uppercase:false,testID:o})}const styles=_reactNative.StyleSheet.create({footnote:{color:_scnTheme.scn.color.textTertiary,fontSize:_scnTheme.scn.font.footnote,lineHeight:_scnTheme.scn.font.footnote*1.45,paddingHorizontal:_scnTheme.scn.gutter+4,paddingTop:8},footnoteCentered:{textAlign:"center"},footnoteWarning:{color:_scnTheme.scn.color.sim},footnoteDanger:{color:_scnTheme.scn.color.danger},panel:{marginHorizontal:_scnTheme.scn.gutter,marginVertical:4,backgroundColor:_scnTheme.scn.color.surface,borderRadius:_scnTheme.scn.radius.card,borderWidth:1,borderColor:_scnTheme.scn.color.border,overflow:"hidden"},panelSim:{borderColor:_scnTheme.scn.color.simBorder},panelDanger:{borderColor:_scnTheme.scn.color.dangerBorder},panelInfo:{borderColor:_scnTheme.scn.color.infoBorder},panelSeparator:{height:_reactNative.StyleSheet.hairlineWidth,marginLeft:_scnTheme.scn.textInset,backgroundColor:_scnTheme.scn.color.separator},notice:{marginHorizontal:_scnTheme.scn.gutter,marginTop:8,borderRadius:_scnTheme.scn.radius.card,borderWidth:1,paddingHorizontal:_scnTheme.scn.textInset,paddingVertical:10,gap:3},noticeSim:{backgroundColor:_scnTheme.scn.color.simSoft,borderColor:_scnTheme.scn.color.simBorder},noticeDanger:{backgroundColor:_scnTheme.scn.color.dangerSoft,borderColor:_scnTheme.scn.color.dangerBorder},noticeInfo:{backgroundColor:_scnTheme.scn.color.infoSoft,borderColor:_scnTheme.scn.color.infoBorder}});
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.scn=exports.SCN_MONO=void 0;var _sharedUi=require("@buoy-gg/shared-ui");const scn=exports.scn={color:{bg:_sharedUi.night.color.bg,surface:"rgba(12, 12, 12, 0.9)",row:_sharedUi.night.color.surfaceElevated,chip:_sharedUi.night.color.buttonSurface,border:_sharedUi.night.color.border,separator:_sharedUi.night.color.separator,fill:_sharedUi.night.color.fill,text:_sharedUi.night.color.text,textSecondary:_sharedUi.night.color.textSecondary,textTertiary:_sharedUi.night.color.textTertiary,accent:_sharedUi.night.color.accent,accentSoft:_sharedUi.night.color.accentSoft,accentBorder:_sharedUi.night.color.accentBorder,accentBorderStrong:_sharedUi.night.color.accentBorderStrong,onAccent:_sharedUi.night.color.onAccent,sim:_sharedUi.night.color.warning,simSoft:_sharedUi.night.color.warningSoft,simBorder:"rgba(255, 131, 41, 0.35)",onSim:"#000000",danger:_sharedUi.night.color.danger,dangerSoft:_sharedUi.night.color.dangerSoft,dangerBorder:"rgba(255, 59, 48, 0.30)",info:_sharedUi.night.color.info,infoSoft:_sharedUi.night.color.infoSoft,infoBorder:"rgba(30, 109, 255, 0.25)"},radius:{card:8,row:6,badge:4,pill:6},gutter:12,textInset:12,rowMinHeight:44,font:{row:13,control:12,label:11,footnote:11,mono:11,micro:9}};const SCN_MONO=exports.SCN_MONO=_sharedUi.monoFont;
@@ -0,0 +1 @@
1
+ "use strict";export const SCENARIO_TOOL="scenario";const r=(e,t="")=>typeof e==="string"?e:e==null?t:String(e);function s(e){const t=e.rule;return t&&typeof t==="object"?t:e}function u(e){const t=s(e);const o=Array.isArray(t.methods)?t.methods.join("/"):"any";const i=r(t.urlPattern,"(no pattern)");const n=r(t.kind,"respond");if(n==="fail"){return`${o} ${i} \u2192 fail (${r(t.failKind,"network")})`}if(n==="delay")return`${o} ${i} \u2192 delay ${t.delayMs??0}ms`;const l=typeof t.status==="number"?t.status:200;const c=t.body!=null?", replaced body":"";return`${o} ${i} \u2192 respond ${l}${c}`}export const STEP_CATALOG=[{tool:"network",action:"upsertOverrideRule",title:"Override a request",durability:"durable",describe:u,conflictKeys:e=>{const t=s(e);const o=r(t.urlPattern);return o?[`net:${o}`]:[]}},{tool:"network",action:"deleteOverrideRule",title:"Remove an override",durability:"one-shot",describe:e=>`Remove override rule ${r(e.id,"?")}`},{tool:"network",action:"setOverridesEnabled",title:"Toggle all overrides",durability:"session",describe:e=>`Turn overrides ${e.enabled===false?"off":"on"}`},{tool:"storage",action:"async.setItem",title:"Set storage value",durability:"durable",describe:e=>`Set storage ${r(e.key,"?")}`,conflictKeys:e=>e.key?[`storage:${r(e.key)}`]:[]},{tool:"storage",action:"async.removeItem",title:"Remove storage key",durability:"durable",describe:e=>`Remove storage ${r(e.key,"?")}`,conflictKeys:e=>e.key?[`storage:${r(e.key)}`]:[]},{tool:"storage",action:"async.multiSet",title:"Set several storage values",durability:"durable",describe:e=>{const t=Array.isArray(e.pairs)?e.pairs.length:0;return`Set ${t} storage key${t===1?"":"s"}`},conflictKeys:e=>Array.isArray(e.pairs)?e.pairs.map(t=>Array.isArray(t)?`storage:${r(t[0])}`:"").filter(Boolean):[]},{tool:"storage",action:"mmkv.set",title:"Set MMKV value",durability:"durable",describe:e=>`Set MMKV ${r(e.key,"?")}`,conflictKeys:e=>e.key?[`mmkv:${r(e.key)}`]:[]},{tool:"impersonate",action:"startImpersonation",title:"Impersonate a user",durability:"durable",describe:e=>{const t=e.user;const o=r(t?.name)||r(t?.email)||r(t?.id)||"a user";return`Impersonate ${o}`},conflictKeys:()=>["impersonation"]},{tool:"impersonate",action:"stopImpersonation",title:"Stop impersonating",durability:"one-shot",describe:()=>"Stop impersonating",conflictKeys:()=>["impersonation"]},{tool:"route-events",action:"navigate",title:"Go to a screen",durability:"one-shot",describe:e=>`${e.replace?"Replace with":"Go to"} ${r(e.path,"?")}`},{tool:"query",action:"setQueryData",title:"Poke the query cache",durability:"transient",describe:e=>`Poke ${r(e.queryKey,"?")} cache (until next refetch)`},{tool:"query",action:"invalidate",title:"Refetch queries",durability:"one-shot",describe:e=>`Refetch ${r(e.queryKey,"all queries")}`},{tool:"time-machine",action:"restore",title:"Restore a snapshot",durability:"durable",describe:e=>`Restore snapshot ${r(e.id,"?")}`},{tool:SCENARIO_TOOL,action:"wait",title:"Wait",durability:"one-shot",describe:e=>`Wait ${typeof e.ms==="number"?e.ms:0}ms`},{tool:"highlight-updates",action:"tapElement",title:"Tap something on screen",durability:"one-shot",describe:e=>{const t=r(e.testID)||r(e.query)||"an element";if(typeof e.text==="string")return`Type \u201C${e.text}\u201D into ${t}`;if(e.value!==void 0)return`Set ${t} to ${JSON.stringify(e.value)}`;if(e.longPress)return`Press and hold \u201C${t}\u201D`;return`Tap \u201C${t}\u201D`}},{tool:SCENARIO_TOOL,action:"waitFor",title:"Wait for a screen",durability:"one-shot",describe:e=>e.route?`Wait for ${r(e.route)}`:`Wait for \u201C${r(e.element,"?")}\u201D`},{tool:"zustand",action:"setState",title:"Set a store's state",durability:e=>e.persisted?"durable":"session",describe:e=>`Set ${r(e.storeName,"a store")}`,conflictKeys:e=>e.storeName?[`zustand:${r(e.storeName)}`]:[]}];const d=new Map(STEP_CATALOG.map(e=>[`${e.tool}.${e.action}`,e]));export function catalogEntry(e,t){return d.get(`${e}.${t}`)}export function describeStep(e,t){if(e.label)return e.label;const o=catalogEntry(e.tool,e.action);const i=t??e.params??{};if(!o)return`${e.tool}.${e.action}`;try{return o.describe(i)}catch{return`${e.tool}.${e.action}`}}export function stepDurability(e){const t=catalogEntry(e.tool,e.action);if(!t)return"one-shot";if(typeof t.durability!=="function")return t.durability;try{return t.durability(e.params??{})}catch{return"one-shot"}}export function isAdvancedStep(e){return!e.label&&!catalogEntry(e.tool,e.action)}export function stepConflictKeys(e,t){const o=catalogEntry(e.tool,e.action);if(!o?.conflictKeys)return[];try{return o.conflictKeys(t??e.params??{})}catch{return[]}}export function conflictKeysOverlap(e,t){if(e===t)return true;const o="net:";if(!e.startsWith(o)||!t.startsWith(o))return false;const i=e.slice(o.length);const n=t.slice(o.length);return a(i,n)||a(n,i)}function a(e,t){try{const o=e.replace(/[[\]{}()\\.^$+|\-,?]/g,"\\$&").split("*").join(".*");const i=t.split("*").join("x");return new RegExp(`^${o}$`).test(i)}catch{return false}}export const DURABILITY_LABEL={durable:"survives refresh & restart",session:"until the app restarts",transient:"until next refetch","one-shot":"one-shot"};
@@ -0,0 +1 @@
1
+ "use strict";import{useCallback as b,useState as S}from"react";import{StyleSheet as w,Text as c,View as l}from"react-native";import{Copy as D,Power as T,RefreshCw as z,ToolButton as f,copyToClipboard as I}from"@buoy-gg/shared-ui";import{scn as e,SCN_MONO as p}from"../ui/scnTheme";import{DurabilityChip as $,Panel as v,PanelSeparator as C}from"../ui/primitives";import{jsx as o,jsxs as n}from"react/jsx-runtime";function j(t){switch(t.kind){case"override-rule":return{label:"survives restart",tone:"durable"};case"impersonation":return{label:"survives restart",tone:"durable"};case"storage-write":return{label:"not auto-undone",tone:"transient"};default:return{label:"one-shot",tone:"neutral"}}}export function reproBlock(t,i){const s=Object.entries(t.varValues).map(([a,d])=>`${a}=${String(d)}`).join(", ");return["\u2014 Bug report context (Buoy Scenarios) \u2014",`Scenario: ${t.name} (v${t.version}, ${t.source})`,`Variables: ${s||"none"}`,`Active since: ${new Date(t.runAt).toISOString()}`,i?`App build: ${i}`:null,`Effects: ${t.effects.map(a=>a.label).join(" \xB7 ")}`].filter(Boolean).join("\n")}export function ActiveCard({active:t,build:i,busy:s,onDeactivate:a,onRerun:d,onCopied:u}){const[h]=S(()=>Math.max(1,Math.round((Date.now()-t.runAt)/6e4)));const x=b(()=>{void I(reproBlock(t,i));u?.()},[t,i,u]);return n(v,{tone:"sim",testID:"scenario-active-card",children:[n(l,{style:r.head,children:[o(l,{style:r.dot}),n(l,{style:r.headText,children:[o(c,{style:r.simulated,children:"SIMULATED"}),o(c,{style:r.name,numberOfLines:2,testID:"scenario-active-name",children:t.name})]}),n(c,{style:r.ago,children:[h,"m ago"]})]}),o(C,{}),t.effects.map((m,y)=>{const g=j(m);return n(l,{style:r.effect,children:[o(c,{style:r.effectText,numberOfLines:1,children:m.label}),o($,{label:g.label,tone:g.tone})]},`${m.kind}-${y}`)}),n(l,{style:r.actions,children:[o(f,{label:"Deactivate",variant:"warning",size:"small",onPress:a,disabled:s,icon:o(T,{size:11,color:e.color.sim}),testID:"scenario-deactivate"}),o(f,{label:"Copy repro info",variant:"ghost",size:"small",onPress:x,icon:o(D,{size:11,color:e.color.textSecondary}),testID:"scenario-copy-repro"}),o(f,{label:"Re-run",variant:"ghost",size:"small",onPress:d,disabled:s,icon:o(z,{size:11,color:e.color.textSecondary}),testID:"scenario-rerun"})]})]})}const r=w.create({head:{flexDirection:"row",alignItems:"flex-start",gap:8,paddingHorizontal:e.textInset,paddingTop:10,paddingBottom:10},dot:{width:8,height:8,borderRadius:4,backgroundColor:e.color.sim,marginTop:4},headText:{flex:1,minWidth:0},simulated:{color:e.color.sim,fontSize:e.font.micro,fontWeight:"700",letterSpacing:.8,fontFamily:p},name:{color:e.color.text,fontSize:e.font.row,fontWeight:"600",marginTop:2},ago:{color:e.color.textTertiary,fontSize:e.font.micro,fontFamily:p,marginTop:2},effect:{flexDirection:"row",alignItems:"center",gap:8,paddingHorizontal:e.textInset,paddingVertical:7},effectText:{flex:1,minWidth:0,color:e.color.textSecondary,fontSize:e.font.control,fontFamily:p},actions:{flexDirection:"row",flexWrap:"wrap",gap:6,paddingHorizontal:e.textInset,paddingTop:8,paddingBottom:10}});