@rozenite/controls-plugin 1.4.0 → 1.5.0

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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # @rozenite/controls-plugin
2
+
3
+ ## 1.5.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#190](https://github.com/callstackincubator/rozenite/pull/190) [`5ae53a4`](https://github.com/callstackincubator/rozenite/commit/5ae53a4b509adbd8536ea24812f7ca523a95b625) Thanks [@V3RON](https://github.com/V3RON)! - Added Rozenite for Agents support to the Controls, MMKV, React Navigation, and Storage plugins.
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [[`5ae53a4`](https://github.com/callstackincubator/rozenite/commit/5ae53a4b509adbd8536ea24812f7ca523a95b625)]:
12
+ - @rozenite/agent-bridge@1.5.0
13
+ - @rozenite/plugin-bridge@1.5.0
@@ -1 +1 @@
1
- {"name":"@rozenite/controls-plugin","version":"0.0.0","description":"Device-owned controls for Rozenite.","panels":[{"name":"Controls","source":"/panel.html"}]}
1
+ {"name":"@rozenite/controls-plugin","version":"1.5.0","description":"A Rozenite plugin for exposing app-defined controls directly in React Native DevTools.","panels":[{"name":"Controls","source":"/panel.html"}]}
@@ -0,0 +1,2 @@
1
+ import { ControlsSection } from '../shared/types';
2
+ export declare const useControlsAgentTools: (sections: ControlsSection[]) => void;
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const $=require("@rozenite/plugin-bridge"),i=require("react"),g=(e,t)=>e?e(t):{valid:!0},R=e=>e.type==="text"?e:e.type==="toggle"?{id:e.id,type:e.type,title:e.title,value:e.value,description:e.description,disabled:e.disabled}:e.type==="button"?{id:e.id,type:e.type,title:e.title,actionLabel:e.actionLabel,description:e.description,disabled:e.disabled}:e.type==="select"?{id:e.id,type:e.type,title:e.title,value:e.value,options:e.options,description:e.description,disabled:e.disabled}:{id:e.id,type:e.type,title:e.title,value:e.value,placeholder:e.placeholder,applyLabel:e.applyLabel,description:e.description,disabled:e.disabled},U=e=>e.map(t=>({id:t.id,title:t.title,description:t.description,items:t.items.map(R)})),P=e=>{const t=new Map;return e.forEach(u=>{u.items.forEach(n=>{const l=`${u.id}:${n.id}`;n.type==="toggle"&&t.set(l,{type:"toggle",validate:n.validate,onUpdate:n.onUpdate}),n.type==="button"&&t.set(l,{type:"button",onPress:n.onPress}),n.type==="select"&&t.set(l,{type:"select",validate:n.validate,onUpdate:n.onUpdate}),n.type==="input"&&t.set(l,{type:"input",validate:n.validate,onUpdate:n.onUpdate})})}),t},f=(e,t)=>`${e}:${t}`,z=({sections:e})=>{const t=$.useRozeniteDevToolsClient({pluginId:"@rozenite/controls-plugin"}),u=i.useMemo(()=>U(e),[e]),n=i.useMemo(()=>P(e),[e]),l=i.useRef(n);return i.useEffect(()=>{l.current=n},[n]),i.useEffect(()=>{t&&t.send("snapshot",{type:"snapshot",sections:u})},[t,u]),i.useEffect(()=>{if(!t)return;const v=async({requestId:s,sectionId:r,itemId:o,value:p})=>{const d=f(r,o),a=l.current.get(d);if(!a||a.type==="button"){t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"error",message:"Update target not found."});return}try{if(a.type==="toggle"){if(typeof p!="boolean"){t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"error",message:"Invalid toggle value."});return}const y=g(a.validate,p);if(!y.valid){t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"error",message:y.message});return}await a.onUpdate(p),t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"ok"});return}if(typeof p!="string"){t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"error",message:`Invalid ${a.type} value.`});return}const c=g(a.validate,p);if(!c.valid){t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"error",message:c.message});return}await a.onUpdate(p),t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"ok"})}catch(c){console.warn(`[Rozenite] Controls Plugin: Update failed for ${r}/${o}.`,c),t.send("update-result",{type:"update-result",requestId:s,sectionId:r,itemId:o,status:"error",message:"Update failed on the device."})}},b=async({sectionId:s,itemId:r,action:o})=>{if(o!=="press"){console.warn(`[Rozenite] Controls Plugin: Unsupported action "${o}" for ${s}/${r}.`);return}const p=f(s,r),d=l.current.get(p);if(!d){console.warn(`[Rozenite] Controls Plugin: Action target not found for ${s}/${r}.`);return}try{if(d.type!=="button"){console.warn(`[Rozenite] Controls Plugin: Invalid press action payload for ${s}/${r}.`);return}await d.onPress()}catch(a){console.warn(`[Rozenite] Controls Plugin: Action failed for ${s}/${r}.`,a)}},h=[t.onMessage("get-snapshot",()=>{t.send("snapshot",{type:"snapshot",sections:u})}),t.onMessage("update-request",s=>{v(s)}),t.onMessage("invoke-action",s=>{b(s)})];return()=>{h.forEach(s=>s.remove())}},[t,u]),t};exports.useRozeniteControlsPlugin=z;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const R=require("@rozenite/plugin-bridge"),c=require("react"),f=require("@rozenite/agent-bridge"),w=(o,t)=>o?o(t):{valid:!0},U=o=>o.type==="text"?o:o.type==="toggle"?{id:o.id,type:o.type,title:o.title,value:o.value,description:o.description,disabled:o.disabled}:o.type==="button"?{id:o.id,type:o.type,title:o.title,actionLabel:o.actionLabel,description:o.description,disabled:o.disabled}:o.type==="select"?{id:o.id,type:o.type,title:o.title,value:o.value,options:o.options,description:o.description,disabled:o.disabled}:{id:o.id,type:o.type,title:o.title,value:o.value,placeholder:o.placeholder,applyLabel:o.applyLabel,description:o.description,disabled:o.disabled},P=o=>o.map(t=>({id:t.id,title:t.title,description:t.description,items:t.items.map(U)})),z=o=>{const t=new Map;return o.forEach(n=>{n.items.forEach(e=>{const i=`${n.id}:${e.id}`;e.type==="toggle"&&t.set(i,{type:"toggle",validate:e.validate,onUpdate:e.onUpdate}),e.type==="button"&&t.set(i,{type:"button",onPress:e.onPress}),e.type==="select"&&t.set(i,{type:"select",validate:e.validate,onUpdate:e.onUpdate}),e.type==="input"&&t.set(i,{type:"input",validate:e.validate,onUpdate:e.onUpdate})})}),t},$=(o,t)=>`${o}:${t}`,b="@rozenite/controls-plugin",S={name:"list-sections",description:"List all controls sections with their item IDs, types, and titles. Does not include values — call get-item for that.",inputSchema:{type:"object",properties:{}}},A={name:"get-item",description:"Get full details of a single controls item including its current value. For select items this includes available options.",inputSchema:{type:"object",properties:{sectionId:{type:"string",description:"Section ID."},itemId:{type:"string",description:"Item ID."}},required:["sectionId","itemId"]}},T={name:"set-value",description:"Update the value of a toggle, select, or input item. Runs the validate callback when present. Fails for text (read-only) and button items.",inputSchema:{type:"object",properties:{sectionId:{type:"string",description:"Section ID."},itemId:{type:"string",description:"Item ID."},value:{description:"New value. Boolean for toggle items, string for select/input items."}},required:["sectionId","itemId","value"]}},C={name:"press-button",description:"Trigger a button item's action. Fails if the item is not a button or is disabled.",inputSchema:{type:"object",properties:{sectionId:{type:"string",description:"Section ID."},itemId:{type:"string",description:"Item ID."}},required:["sectionId","itemId"]}},v=(o,t,n)=>{const e=o.find(s=>s.id===t);if(!e){const s=o.map(u=>u.id).join(", ");throw new Error(`Section "${t}" not found. Available: ${s||"(none)"}`)}const i=e.items.find(s=>s.id===n);if(!i){const s=e.items.map(u=>u.id).join(", ");throw new Error(`Item "${n}" not found in section "${t}". Available: ${s||"(none)"}`)}return{section:e,item:i}},D=o=>{f.useRozenitePluginAgentTool({pluginId:b,tool:S,handler:()=>({sections:o.map(t=>({id:t.id,title:t.title,description:t.description,items:t.items.map(n=>({id:n.id,type:n.type,title:n.title,disabled:"disabled"in n?n.disabled:void 0}))}))})}),f.useRozenitePluginAgentTool({pluginId:b,tool:A,handler:({sectionId:t,itemId:n})=>{const{item:e}=v(o,t,n);return e.type==="text"?{sectionId:t,item:{id:e.id,type:e.type,title:e.title,value:e.value,description:e.description}}:e.type==="toggle"?{sectionId:t,item:{id:e.id,type:e.type,title:e.title,value:e.value,description:e.description,disabled:e.disabled}}:e.type==="button"?{sectionId:t,item:{id:e.id,type:e.type,title:e.title,actionLabel:e.actionLabel,description:e.description,disabled:e.disabled}}:e.type==="select"?{sectionId:t,item:{id:e.id,type:e.type,title:e.title,value:e.value,options:e.options,description:e.description,disabled:e.disabled}}:{sectionId:t,item:{id:e.id,type:e.type,title:e.title,value:e.value,placeholder:e.placeholder,applyLabel:e.applyLabel,description:e.description,disabled:e.disabled}}}}),f.useRozenitePluginAgentTool({pluginId:b,tool:T,handler:async({sectionId:t,itemId:n,value:e})=>{const{item:i}=v(o,t,n);if(i.type==="text")throw new Error(`Item "${n}" is a read-only text item and cannot be updated.`);if(i.type==="button")throw new Error(`Item "${n}" is a button. Use press-button to trigger its action.`);if(i.disabled)throw new Error(`Item "${n}" is disabled.`);if(i.type==="toggle"){if(typeof e!="boolean")throw new Error(`Expected boolean value for toggle item "${n}".`);if(i.validate){const s=i.validate(e);if(!s.valid)throw new Error(s.message)}return await i.onUpdate(e),{applied:!0,sectionId:t,itemId:n}}if(typeof e!="string")throw new Error(`Expected string value for ${i.type} item "${n}".`);if(i.type==="select"){const s=i.options.map(u=>u.value);if(!s.includes(e))throw new Error(`Invalid option "${e}" for item "${n}". Valid options: ${s.join(", ")}`)}if(i.validate){const s=i.validate(e);if(!s.valid)throw new Error(s.message)}return await i.onUpdate(e),{applied:!0,sectionId:t,itemId:n}}}),f.useRozenitePluginAgentTool({pluginId:b,tool:C,handler:async({sectionId:t,itemId:n})=>{const{item:e}=v(o,t,n);if(e.type!=="button")throw new Error(`Item "${n}" is not a button (type: ${e.type}). Use set-value to update its value.`);if(e.disabled)throw new Error(`Button "${n}" is disabled.`);return await e.onPress(),{pressed:!0,sectionId:t,itemId:n}}})},L=({sections:o})=>{const t=R.useRozeniteDevToolsClient({pluginId:"@rozenite/controls-plugin"});D(o);const n=c.useMemo(()=>P(o),[o]),e=c.useMemo(()=>z(o),[o]),i=c.useRef(e);return c.useEffect(()=>{i.current=e},[e]),c.useEffect(()=>{t&&t.send("snapshot",{type:"snapshot",sections:n})},[t,n]),c.useEffect(()=>{if(!t)return;const s=async({requestId:r,sectionId:a,itemId:l,value:d})=>{const y=$(a,l),p=i.current.get(y);if(!p||p.type==="button"){t.send("update-result",{type:"update-result",requestId:r,sectionId:a,itemId:l,status:"error",message:"Update target not found."});return}try{if(p.type==="toggle"){if(typeof d!="boolean"){t.send("update-result",{type:"update-result",requestId:r,sectionId:a,itemId:l,status:"error",message:"Invalid toggle value."});return}const h=w(p.validate,d);if(!h.valid){t.send("update-result",{type:"update-result",requestId:r,sectionId:a,itemId:l,status:"error",message:h.message});return}await p.onUpdate(d),t.send("update-result",{type:"update-result",requestId:r,sectionId:a,itemId:l,status:"ok"});return}if(typeof d!="string"){t.send("update-result",{type:"update-result",requestId:r,sectionId:a,itemId:l,status:"error",message:`Invalid ${p.type} value.`});return}const g=w(p.validate,d);if(!g.valid){t.send("update-result",{type:"update-result",requestId:r,sectionId:a,itemId:l,status:"error",message:g.message});return}await p.onUpdate(d),t.send("update-result",{type:"update-result",requestId:r,sectionId:a,itemId:l,status:"ok"})}catch(g){console.warn(`[Rozenite] Controls Plugin: Update failed for ${a}/${l}.`,g),t.send("update-result",{type:"update-result",requestId:r,sectionId:a,itemId:l,status:"error",message:"Update failed on the device."})}},u=async({sectionId:r,itemId:a,action:l})=>{if(l!=="press"){console.warn(`[Rozenite] Controls Plugin: Unsupported action "${l}" for ${r}/${a}.`);return}const d=$(r,a),y=i.current.get(d);if(!y){console.warn(`[Rozenite] Controls Plugin: Action target not found for ${r}/${a}.`);return}try{if(y.type!=="button"){console.warn(`[Rozenite] Controls Plugin: Invalid press action payload for ${r}/${a}.`);return}await y.onPress()}catch(p){console.warn(`[Rozenite] Controls Plugin: Action failed for ${r}/${a}.`,p)}},E=[t.onMessage("get-snapshot",()=>{t.send("snapshot",{type:"snapshot",sections:n})}),t.onMessage("update-request",r=>{s(r)}),t.onMessage("invoke-action",r=>{u(r)})];return()=>{E.forEach(r=>r.remove())}},[t,n]),t};exports.useRozeniteControlsPlugin=L;
@@ -1,226 +1,420 @@
1
1
  import { useRozeniteDevToolsClient as R } from "@rozenite/plugin-bridge";
2
- import { useMemo as f, useRef as U, useEffect as y } from "react";
3
- const g = (e, t) => e ? e(t) : { valid: !0 }, w = (e) => e.type === "text" ? e : e.type === "toggle" ? {
4
- id: e.id,
5
- type: e.type,
6
- title: e.title,
7
- value: e.value,
8
- description: e.description,
9
- disabled: e.disabled
10
- } : e.type === "button" ? {
11
- id: e.id,
12
- type: e.type,
13
- title: e.title,
14
- actionLabel: e.actionLabel,
15
- description: e.description,
16
- disabled: e.disabled
17
- } : e.type === "select" ? {
18
- id: e.id,
19
- type: e.type,
20
- title: e.title,
21
- value: e.value,
22
- options: e.options,
23
- description: e.description,
24
- disabled: e.disabled
2
+ import { useMemo as w, useRef as z, useEffect as b } from "react";
3
+ import { useRozenitePluginAgentTool as f } from "@rozenite/agent-bridge";
4
+ const $ = (o, e) => o ? o(e) : { valid: !0 }, P = (o) => o.type === "text" ? o : o.type === "toggle" ? {
5
+ id: o.id,
6
+ type: o.type,
7
+ title: o.title,
8
+ value: o.value,
9
+ description: o.description,
10
+ disabled: o.disabled
11
+ } : o.type === "button" ? {
12
+ id: o.id,
13
+ type: o.type,
14
+ title: o.title,
15
+ actionLabel: o.actionLabel,
16
+ description: o.description,
17
+ disabled: o.disabled
18
+ } : o.type === "select" ? {
19
+ id: o.id,
20
+ type: o.type,
21
+ title: o.title,
22
+ value: o.value,
23
+ options: o.options,
24
+ description: o.description,
25
+ disabled: o.disabled
25
26
  } : {
27
+ id: o.id,
28
+ type: o.type,
29
+ title: o.title,
30
+ value: o.value,
31
+ placeholder: o.placeholder,
32
+ applyLabel: o.applyLabel,
33
+ description: o.description,
34
+ disabled: o.disabled
35
+ }, S = (o) => o.map((e) => ({
26
36
  id: e.id,
27
- type: e.type,
28
37
  title: e.title,
29
- value: e.value,
30
- placeholder: e.placeholder,
31
- applyLabel: e.applyLabel,
32
38
  description: e.description,
33
- disabled: e.disabled
34
- }, z = (e) => e.map((t) => ({
35
- id: t.id,
36
- title: t.title,
37
- description: t.description,
38
- items: t.items.map(w)
39
- })), P = (e) => {
40
- const t = /* @__PURE__ */ new Map();
41
- return e.forEach((u) => {
42
- u.items.forEach((n) => {
43
- const p = `${u.id}:${n.id}`;
44
- n.type === "toggle" && t.set(p, {
39
+ items: e.items.map(P)
40
+ })), m = (o) => {
41
+ const e = /* @__PURE__ */ new Map();
42
+ return o.forEach((n) => {
43
+ n.items.forEach((t) => {
44
+ const r = `${n.id}:${t.id}`;
45
+ t.type === "toggle" && e.set(r, {
45
46
  type: "toggle",
46
- validate: n.validate,
47
- onUpdate: n.onUpdate
48
- }), n.type === "button" && t.set(p, {
47
+ validate: t.validate,
48
+ onUpdate: t.onUpdate
49
+ }), t.type === "button" && e.set(r, {
49
50
  type: "button",
50
- onPress: n.onPress
51
- }), n.type === "select" && t.set(p, {
51
+ onPress: t.onPress
52
+ }), t.type === "select" && e.set(r, {
52
53
  type: "select",
53
- validate: n.validate,
54
- onUpdate: n.onUpdate
55
- }), n.type === "input" && t.set(p, {
54
+ validate: t.validate,
55
+ onUpdate: t.onUpdate
56
+ }), t.type === "input" && e.set(r, {
56
57
  type: "input",
57
- validate: n.validate,
58
- onUpdate: n.onUpdate
58
+ validate: t.validate,
59
+ onUpdate: t.onUpdate
59
60
  });
60
61
  });
61
- }), t;
62
- }, v = (e, t) => `${e}:${t}`, A = ({
63
- sections: e
62
+ }), e;
63
+ }, E = (o, e) => `${o}:${e}`, g = "@rozenite/controls-plugin", A = {
64
+ name: "list-sections",
65
+ description: "List all controls sections with their item IDs, types, and titles. Does not include values — call get-item for that.",
66
+ inputSchema: { type: "object", properties: {} }
67
+ }, D = {
68
+ name: "get-item",
69
+ description: "Get full details of a single controls item including its current value. For select items this includes available options.",
70
+ inputSchema: {
71
+ type: "object",
72
+ properties: {
73
+ sectionId: { type: "string", description: "Section ID." },
74
+ itemId: { type: "string", description: "Item ID." }
75
+ },
76
+ required: ["sectionId", "itemId"]
77
+ }
78
+ }, L = {
79
+ name: "set-value",
80
+ description: "Update the value of a toggle, select, or input item. Runs the validate callback when present. Fails for text (read-only) and button items.",
81
+ inputSchema: {
82
+ type: "object",
83
+ properties: {
84
+ sectionId: { type: "string", description: "Section ID." },
85
+ itemId: { type: "string", description: "Item ID." },
86
+ value: {
87
+ description: "New value. Boolean for toggle items, string for select/input items."
88
+ }
89
+ },
90
+ required: ["sectionId", "itemId", "value"]
91
+ }
92
+ }, k = {
93
+ name: "press-button",
94
+ description: "Trigger a button item's action. Fails if the item is not a button or is disabled.",
95
+ inputSchema: {
96
+ type: "object",
97
+ properties: {
98
+ sectionId: { type: "string", description: "Section ID." },
99
+ itemId: { type: "string", description: "Item ID." }
100
+ },
101
+ required: ["sectionId", "itemId"]
102
+ }
103
+ }, v = (o, e, n) => {
104
+ const t = o.find((s) => s.id === e);
105
+ if (!t) {
106
+ const s = o.map((u) => u.id).join(", ");
107
+ throw new Error(
108
+ `Section "${e}" not found. Available: ${s || "(none)"}`
109
+ );
110
+ }
111
+ const r = t.items.find((s) => s.id === n);
112
+ if (!r) {
113
+ const s = t.items.map((u) => u.id).join(", ");
114
+ throw new Error(
115
+ `Item "${n}" not found in section "${e}". Available: ${s || "(none)"}`
116
+ );
117
+ }
118
+ return { section: t, item: r };
119
+ }, x = (o) => {
120
+ f({
121
+ pluginId: g,
122
+ tool: A,
123
+ handler: () => ({
124
+ sections: o.map((e) => ({
125
+ id: e.id,
126
+ title: e.title,
127
+ description: e.description,
128
+ items: e.items.map((n) => ({
129
+ id: n.id,
130
+ type: n.type,
131
+ title: n.title,
132
+ disabled: "disabled" in n ? n.disabled : void 0
133
+ }))
134
+ }))
135
+ })
136
+ }), f({
137
+ pluginId: g,
138
+ tool: D,
139
+ handler: ({ sectionId: e, itemId: n }) => {
140
+ const { item: t } = v(o, e, n);
141
+ return t.type === "text" ? {
142
+ sectionId: e,
143
+ item: {
144
+ id: t.id,
145
+ type: t.type,
146
+ title: t.title,
147
+ value: t.value,
148
+ description: t.description
149
+ }
150
+ } : t.type === "toggle" ? {
151
+ sectionId: e,
152
+ item: {
153
+ id: t.id,
154
+ type: t.type,
155
+ title: t.title,
156
+ value: t.value,
157
+ description: t.description,
158
+ disabled: t.disabled
159
+ }
160
+ } : t.type === "button" ? {
161
+ sectionId: e,
162
+ item: {
163
+ id: t.id,
164
+ type: t.type,
165
+ title: t.title,
166
+ actionLabel: t.actionLabel,
167
+ description: t.description,
168
+ disabled: t.disabled
169
+ }
170
+ } : t.type === "select" ? {
171
+ sectionId: e,
172
+ item: {
173
+ id: t.id,
174
+ type: t.type,
175
+ title: t.title,
176
+ value: t.value,
177
+ options: t.options,
178
+ description: t.description,
179
+ disabled: t.disabled
180
+ }
181
+ } : {
182
+ sectionId: e,
183
+ item: {
184
+ id: t.id,
185
+ type: t.type,
186
+ title: t.title,
187
+ value: t.value,
188
+ placeholder: t.placeholder,
189
+ applyLabel: t.applyLabel,
190
+ description: t.description,
191
+ disabled: t.disabled
192
+ }
193
+ };
194
+ }
195
+ }), f({
196
+ pluginId: g,
197
+ tool: L,
198
+ handler: async ({ sectionId: e, itemId: n, value: t }) => {
199
+ const { item: r } = v(o, e, n);
200
+ if (r.type === "text")
201
+ throw new Error(
202
+ `Item "${n}" is a read-only text item and cannot be updated.`
203
+ );
204
+ if (r.type === "button")
205
+ throw new Error(
206
+ `Item "${n}" is a button. Use press-button to trigger its action.`
207
+ );
208
+ if (r.disabled)
209
+ throw new Error(`Item "${n}" is disabled.`);
210
+ if (r.type === "toggle") {
211
+ if (typeof t != "boolean")
212
+ throw new Error(
213
+ `Expected boolean value for toggle item "${n}".`
214
+ );
215
+ if (r.validate) {
216
+ const s = r.validate(t);
217
+ if (!s.valid)
218
+ throw new Error(s.message);
219
+ }
220
+ return await r.onUpdate(t), { applied: !0, sectionId: e, itemId: n };
221
+ }
222
+ if (typeof t != "string")
223
+ throw new Error(
224
+ `Expected string value for ${r.type} item "${n}".`
225
+ );
226
+ if (r.type === "select") {
227
+ const s = r.options.map((u) => u.value);
228
+ if (!s.includes(t))
229
+ throw new Error(
230
+ `Invalid option "${t}" for item "${n}". Valid options: ${s.join(", ")}`
231
+ );
232
+ }
233
+ if (r.validate) {
234
+ const s = r.validate(t);
235
+ if (!s.valid)
236
+ throw new Error(s.message);
237
+ }
238
+ return await r.onUpdate(t), { applied: !0, sectionId: e, itemId: n };
239
+ }
240
+ }), f({
241
+ pluginId: g,
242
+ tool: k,
243
+ handler: async ({ sectionId: e, itemId: n }) => {
244
+ const { item: t } = v(o, e, n);
245
+ if (t.type !== "button")
246
+ throw new Error(
247
+ `Item "${n}" is not a button (type: ${t.type}). Use set-value to update its value.`
248
+ );
249
+ if (t.disabled)
250
+ throw new Error(`Button "${n}" is disabled.`);
251
+ return await t.onPress(), { pressed: !0, sectionId: e, itemId: n };
252
+ }
253
+ });
254
+ }, M = ({
255
+ sections: o
64
256
  }) => {
65
- const t = R({
257
+ const e = R({
66
258
  pluginId: "@rozenite/controls-plugin"
67
- }), u = f(() => z(e), [e]), n = f(() => P(e), [e]), p = U(n);
68
- return y(() => {
69
- p.current = n;
70
- }, [n]), y(() => {
71
- t && t.send("snapshot", {
259
+ });
260
+ x(o);
261
+ const n = w(() => S(o), [o]), t = w(() => m(o), [o]), r = z(t);
262
+ return b(() => {
263
+ r.current = t;
264
+ }, [t]), b(() => {
265
+ e && e.send("snapshot", {
72
266
  type: "snapshot",
73
- sections: u
267
+ sections: n
74
268
  });
75
- }, [t, u]), y(() => {
76
- if (!t)
269
+ }, [e, n]), b(() => {
270
+ if (!e)
77
271
  return;
78
- const b = async ({
79
- requestId: s,
80
- sectionId: r,
81
- itemId: o,
82
- value: l
272
+ const s = async ({
273
+ requestId: i,
274
+ sectionId: a,
275
+ itemId: l,
276
+ value: d
83
277
  }) => {
84
- const d = v(r, o), a = p.current.get(d);
85
- if (!a || a.type === "button") {
86
- t.send("update-result", {
278
+ const c = E(a, l), p = r.current.get(c);
279
+ if (!p || p.type === "button") {
280
+ e.send("update-result", {
87
281
  type: "update-result",
88
- requestId: s,
89
- sectionId: r,
90
- itemId: o,
282
+ requestId: i,
283
+ sectionId: a,
284
+ itemId: l,
91
285
  status: "error",
92
286
  message: "Update target not found."
93
287
  });
94
288
  return;
95
289
  }
96
290
  try {
97
- if (a.type === "toggle") {
98
- if (typeof l != "boolean") {
99
- t.send("update-result", {
291
+ if (p.type === "toggle") {
292
+ if (typeof d != "boolean") {
293
+ e.send("update-result", {
100
294
  type: "update-result",
101
- requestId: s,
102
- sectionId: r,
103
- itemId: o,
295
+ requestId: i,
296
+ sectionId: a,
297
+ itemId: l,
104
298
  status: "error",
105
299
  message: "Invalid toggle value."
106
300
  });
107
301
  return;
108
302
  }
109
- const c = g(a.validate, l);
110
- if (!c.valid) {
111
- t.send("update-result", {
303
+ const h = $(p.validate, d);
304
+ if (!h.valid) {
305
+ e.send("update-result", {
112
306
  type: "update-result",
113
- requestId: s,
114
- sectionId: r,
115
- itemId: o,
307
+ requestId: i,
308
+ sectionId: a,
309
+ itemId: l,
116
310
  status: "error",
117
- message: c.message
311
+ message: h.message
118
312
  });
119
313
  return;
120
314
  }
121
- await a.onUpdate(l), t.send("update-result", {
315
+ await p.onUpdate(d), e.send("update-result", {
122
316
  type: "update-result",
123
- requestId: s,
124
- sectionId: r,
125
- itemId: o,
317
+ requestId: i,
318
+ sectionId: a,
319
+ itemId: l,
126
320
  status: "ok"
127
321
  });
128
322
  return;
129
323
  }
130
- if (typeof l != "string") {
131
- t.send("update-result", {
324
+ if (typeof d != "string") {
325
+ e.send("update-result", {
132
326
  type: "update-result",
133
- requestId: s,
134
- sectionId: r,
135
- itemId: o,
327
+ requestId: i,
328
+ sectionId: a,
329
+ itemId: l,
136
330
  status: "error",
137
- message: `Invalid ${a.type} value.`
331
+ message: `Invalid ${p.type} value.`
138
332
  });
139
333
  return;
140
334
  }
141
- const i = g(a.validate, l);
142
- if (!i.valid) {
143
- t.send("update-result", {
335
+ const y = $(p.validate, d);
336
+ if (!y.valid) {
337
+ e.send("update-result", {
144
338
  type: "update-result",
145
- requestId: s,
146
- sectionId: r,
147
- itemId: o,
339
+ requestId: i,
340
+ sectionId: a,
341
+ itemId: l,
148
342
  status: "error",
149
- message: i.message
343
+ message: y.message
150
344
  });
151
345
  return;
152
346
  }
153
- await a.onUpdate(l), t.send("update-result", {
347
+ await p.onUpdate(d), e.send("update-result", {
154
348
  type: "update-result",
155
- requestId: s,
156
- sectionId: r,
157
- itemId: o,
349
+ requestId: i,
350
+ sectionId: a,
351
+ itemId: l,
158
352
  status: "ok"
159
353
  });
160
- } catch (i) {
354
+ } catch (y) {
161
355
  console.warn(
162
- `[Rozenite] Controls Plugin: Update failed for ${r}/${o}.`,
163
- i
164
- ), t.send("update-result", {
356
+ `[Rozenite] Controls Plugin: Update failed for ${a}/${l}.`,
357
+ y
358
+ ), e.send("update-result", {
165
359
  type: "update-result",
166
- requestId: s,
167
- sectionId: r,
168
- itemId: o,
360
+ requestId: i,
361
+ sectionId: a,
362
+ itemId: l,
169
363
  status: "error",
170
364
  message: "Update failed on the device."
171
365
  });
172
366
  }
173
- }, h = async ({
174
- sectionId: s,
175
- itemId: r,
176
- action: o
367
+ }, u = async ({
368
+ sectionId: i,
369
+ itemId: a,
370
+ action: l
177
371
  }) => {
178
- if (o !== "press") {
372
+ if (l !== "press") {
179
373
  console.warn(
180
- `[Rozenite] Controls Plugin: Unsupported action "${o}" for ${s}/${r}.`
374
+ `[Rozenite] Controls Plugin: Unsupported action "${l}" for ${i}/${a}.`
181
375
  );
182
376
  return;
183
377
  }
184
- const l = v(s, r), d = p.current.get(l);
185
- if (!d) {
378
+ const d = E(i, a), c = r.current.get(d);
379
+ if (!c) {
186
380
  console.warn(
187
- `[Rozenite] Controls Plugin: Action target not found for ${s}/${r}.`
381
+ `[Rozenite] Controls Plugin: Action target not found for ${i}/${a}.`
188
382
  );
189
383
  return;
190
384
  }
191
385
  try {
192
- if (d.type !== "button") {
386
+ if (c.type !== "button") {
193
387
  console.warn(
194
- `[Rozenite] Controls Plugin: Invalid press action payload for ${s}/${r}.`
388
+ `[Rozenite] Controls Plugin: Invalid press action payload for ${i}/${a}.`
195
389
  );
196
390
  return;
197
391
  }
198
- await d.onPress();
199
- } catch (a) {
392
+ await c.onPress();
393
+ } catch (p) {
200
394
  console.warn(
201
- `[Rozenite] Controls Plugin: Action failed for ${s}/${r}.`,
202
- a
395
+ `[Rozenite] Controls Plugin: Action failed for ${i}/${a}.`,
396
+ p
203
397
  );
204
398
  }
205
- }, $ = [
206
- t.onMessage("get-snapshot", () => {
207
- t.send("snapshot", {
399
+ }, U = [
400
+ e.onMessage("get-snapshot", () => {
401
+ e.send("snapshot", {
208
402
  type: "snapshot",
209
- sections: u
403
+ sections: n
210
404
  });
211
405
  }),
212
- t.onMessage("update-request", (s) => {
213
- b(s);
406
+ e.onMessage("update-request", (i) => {
407
+ s(i);
214
408
  }),
215
- t.onMessage("invoke-action", (s) => {
216
- h(s);
409
+ e.onMessage("invoke-action", (i) => {
410
+ u(i);
217
411
  })
218
412
  ];
219
413
  return () => {
220
- $.forEach((s) => s.remove());
414
+ U.forEach((i) => i.remove());
221
415
  };
222
- }, [t, u]), t;
416
+ }, [e, n]), e;
223
417
  };
224
418
  export {
225
- A as useRozeniteControlsPlugin
419
+ M as useRozeniteControlsPlugin
226
420
  };
package/package.json CHANGED
@@ -1,16 +1,18 @@
1
1
  {
2
2
  "name": "@rozenite/controls-plugin",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "A Rozenite plugin for exposing app-defined controls directly in React Native DevTools.",
5
5
  "type": "module",
6
6
  "main": "./dist/react-native.cjs",
7
7
  "module": "./dist/react-native.js",
8
8
  "types": "./dist/react-native.d.ts",
9
9
  "dependencies": {
10
- "@rozenite/plugin-bridge": "1.4.0"
10
+ "@rozenite/agent-bridge": "1.5.0",
11
+ "@rozenite/plugin-bridge": "1.5.0"
11
12
  },
12
13
  "devDependencies": {
13
14
  "@types/react": "~19.2.2",
15
+ "@types/react-dom": "~19.1.7",
14
16
  "autoprefixer": "^10.4.21",
15
17
  "postcss": "^8.5.6",
16
18
  "react": "19.2.0",
@@ -21,8 +23,8 @@
21
23
  "tailwindcss-animate": "^1.0.7",
22
24
  "typescript": "~5.9.3",
23
25
  "vite": "^7.3.1",
24
- "@rozenite/vite-plugin": "1.4.0",
25
- "rozenite": "1.4.0"
26
+ "rozenite": "1.5.0",
27
+ "@rozenite/vite-plugin": "1.5.0"
26
28
  },
27
29
  "peerDependencies": {
28
30
  "react": "*",
@@ -0,0 +1,277 @@
1
+ import { useRozenitePluginAgentTool, type AgentTool } from '@rozenite/agent-bridge';
2
+ import type { ControlsSection } from '../shared/types';
3
+
4
+ type SectionItemInput = {
5
+ sectionId: string;
6
+ itemId: string;
7
+ };
8
+
9
+ type SetValueInput = SectionItemInput & {
10
+ value: boolean | string;
11
+ };
12
+
13
+ const pluginId = '@rozenite/controls-plugin';
14
+
15
+ const listSectionsTool: AgentTool = {
16
+ name: 'list-sections',
17
+ description:
18
+ 'List all controls sections with their item IDs, types, and titles. Does not include values — call get-item for that.',
19
+ inputSchema: { type: 'object', properties: {} },
20
+ };
21
+
22
+ const getItemTool: AgentTool = {
23
+ name: 'get-item',
24
+ description:
25
+ 'Get full details of a single controls item including its current value. For select items this includes available options.',
26
+ inputSchema: {
27
+ type: 'object',
28
+ properties: {
29
+ sectionId: { type: 'string', description: 'Section ID.' },
30
+ itemId: { type: 'string', description: 'Item ID.' },
31
+ },
32
+ required: ['sectionId', 'itemId'],
33
+ },
34
+ };
35
+
36
+ const setValueTool: AgentTool = {
37
+ name: 'set-value',
38
+ description:
39
+ 'Update the value of a toggle, select, or input item. Runs the validate callback when present. Fails for text (read-only) and button items.',
40
+ inputSchema: {
41
+ type: 'object',
42
+ properties: {
43
+ sectionId: { type: 'string', description: 'Section ID.' },
44
+ itemId: { type: 'string', description: 'Item ID.' },
45
+ value: {
46
+ description:
47
+ 'New value. Boolean for toggle items, string for select/input items.',
48
+ },
49
+ },
50
+ required: ['sectionId', 'itemId', 'value'],
51
+ },
52
+ };
53
+
54
+ const pressButtonTool: AgentTool = {
55
+ name: 'press-button',
56
+ description: "Trigger a button item's action. Fails if the item is not a button or is disabled.",
57
+ inputSchema: {
58
+ type: 'object',
59
+ properties: {
60
+ sectionId: { type: 'string', description: 'Section ID.' },
61
+ itemId: { type: 'string', description: 'Item ID.' },
62
+ },
63
+ required: ['sectionId', 'itemId'],
64
+ },
65
+ };
66
+
67
+ const resolveItem = (
68
+ sections: ControlsSection[],
69
+ sectionId: string,
70
+ itemId: string
71
+ ) => {
72
+ const section = sections.find((s) => s.id === sectionId);
73
+
74
+ if (!section) {
75
+ const available = sections.map((s) => s.id).join(', ');
76
+ throw new Error(
77
+ `Section "${sectionId}" not found. Available: ${available || '(none)'}`
78
+ );
79
+ }
80
+
81
+ const item = section.items.find((i) => i.id === itemId);
82
+
83
+ if (!item) {
84
+ const available = section.items.map((i) => i.id).join(', ');
85
+ throw new Error(
86
+ `Item "${itemId}" not found in section "${sectionId}". Available: ${available || '(none)'}`
87
+ );
88
+ }
89
+
90
+ return { section, item };
91
+ };
92
+
93
+ export const useControlsAgentTools = (sections: ControlsSection[]) => {
94
+ useRozenitePluginAgentTool({
95
+ pluginId,
96
+ tool: listSectionsTool,
97
+ handler: () => ({
98
+ sections: sections.map((section) => ({
99
+ id: section.id,
100
+ title: section.title,
101
+ description: section.description,
102
+ items: section.items.map((item) => ({
103
+ id: item.id,
104
+ type: item.type,
105
+ title: item.title,
106
+ disabled: 'disabled' in item ? item.disabled : undefined,
107
+ })),
108
+ })),
109
+ }),
110
+ });
111
+
112
+ useRozenitePluginAgentTool<SectionItemInput>({
113
+ pluginId,
114
+ tool: getItemTool,
115
+ handler: ({ sectionId, itemId }) => {
116
+ const { item } = resolveItem(sections, sectionId, itemId);
117
+
118
+ if (item.type === 'text') {
119
+ return {
120
+ sectionId,
121
+ item: {
122
+ id: item.id,
123
+ type: item.type,
124
+ title: item.title,
125
+ value: item.value,
126
+ description: item.description,
127
+ },
128
+ };
129
+ }
130
+
131
+ if (item.type === 'toggle') {
132
+ return {
133
+ sectionId,
134
+ item: {
135
+ id: item.id,
136
+ type: item.type,
137
+ title: item.title,
138
+ value: item.value,
139
+ description: item.description,
140
+ disabled: item.disabled,
141
+ },
142
+ };
143
+ }
144
+
145
+ if (item.type === 'button') {
146
+ return {
147
+ sectionId,
148
+ item: {
149
+ id: item.id,
150
+ type: item.type,
151
+ title: item.title,
152
+ actionLabel: item.actionLabel,
153
+ description: item.description,
154
+ disabled: item.disabled,
155
+ },
156
+ };
157
+ }
158
+
159
+ if (item.type === 'select') {
160
+ return {
161
+ sectionId,
162
+ item: {
163
+ id: item.id,
164
+ type: item.type,
165
+ title: item.title,
166
+ value: item.value,
167
+ options: item.options,
168
+ description: item.description,
169
+ disabled: item.disabled,
170
+ },
171
+ };
172
+ }
173
+
174
+ return {
175
+ sectionId,
176
+ item: {
177
+ id: item.id,
178
+ type: item.type,
179
+ title: item.title,
180
+ value: item.value,
181
+ placeholder: item.placeholder,
182
+ applyLabel: item.applyLabel,
183
+ description: item.description,
184
+ disabled: item.disabled,
185
+ },
186
+ };
187
+ },
188
+ });
189
+
190
+ useRozenitePluginAgentTool<SetValueInput>({
191
+ pluginId,
192
+ tool: setValueTool,
193
+ handler: async ({ sectionId, itemId, value }) => {
194
+ const { item } = resolveItem(sections, sectionId, itemId);
195
+
196
+ if (item.type === 'text') {
197
+ throw new Error(
198
+ `Item "${itemId}" is a read-only text item and cannot be updated.`
199
+ );
200
+ }
201
+
202
+ if (item.type === 'button') {
203
+ throw new Error(
204
+ `Item "${itemId}" is a button. Use press-button to trigger its action.`
205
+ );
206
+ }
207
+
208
+ if (item.disabled) {
209
+ throw new Error(`Item "${itemId}" is disabled.`);
210
+ }
211
+
212
+ if (item.type === 'toggle') {
213
+ if (typeof value !== 'boolean') {
214
+ throw new Error(
215
+ `Expected boolean value for toggle item "${itemId}".`
216
+ );
217
+ }
218
+
219
+ if (item.validate) {
220
+ const result = item.validate(value);
221
+ if (!result.valid) {
222
+ throw new Error(result.message);
223
+ }
224
+ }
225
+
226
+ await item.onUpdate(value);
227
+ return { applied: true, sectionId, itemId };
228
+ }
229
+
230
+ if (typeof value !== 'string') {
231
+ throw new Error(
232
+ `Expected string value for ${item.type} item "${itemId}".`
233
+ );
234
+ }
235
+
236
+ if (item.type === 'select') {
237
+ const validOptions = item.options.map((o) => o.value);
238
+ if (!validOptions.includes(value)) {
239
+ throw new Error(
240
+ `Invalid option "${value}" for item "${itemId}". Valid options: ${validOptions.join(', ')}`
241
+ );
242
+ }
243
+ }
244
+
245
+ if (item.validate) {
246
+ const result = item.validate(value);
247
+ if (!result.valid) {
248
+ throw new Error(result.message);
249
+ }
250
+ }
251
+
252
+ await item.onUpdate(value);
253
+ return { applied: true, sectionId, itemId };
254
+ },
255
+ });
256
+
257
+ useRozenitePluginAgentTool<SectionItemInput>({
258
+ pluginId,
259
+ tool: pressButtonTool,
260
+ handler: async ({ sectionId, itemId }) => {
261
+ const { item } = resolveItem(sections, sectionId, itemId);
262
+
263
+ if (item.type !== 'button') {
264
+ throw new Error(
265
+ `Item "${itemId}" is not a button (type: ${item.type}). Use set-value to update its value.`
266
+ );
267
+ }
268
+
269
+ if (item.disabled) {
270
+ throw new Error(`Button "${itemId}" is disabled.`);
271
+ }
272
+
273
+ await item.onPress();
274
+ return { pressed: true, sectionId, itemId };
275
+ },
276
+ });
277
+ };
@@ -12,6 +12,7 @@ import {
12
12
  serializeSections,
13
13
  validateValue,
14
14
  } from '../shared/serialization';
15
+ import { useControlsAgentTools } from './useControlsAgentTools';
15
16
 
16
17
  export const useRozeniteControlsPlugin = ({
17
18
  sections,
@@ -20,6 +21,8 @@ export const useRozeniteControlsPlugin = ({
20
21
  pluginId: '@rozenite/controls-plugin',
21
22
  });
22
23
 
24
+ useControlsAgentTools(sections);
25
+
23
26
  const snapshot = useMemo(() => serializeSections(sections), [sections]);
24
27
  const actionRegistry = useMemo(() => buildActionRegistry(sections), [sections]);
25
28
  const actionRegistryRef = useRef(actionRegistry);
@@ -1,16 +0,0 @@
1
-
2
- 
3
- > @rozenite/controls-plugin@0.0.0 build /Users/szymon.chmal/Projects/rn-devtools/packages/controls-plugin
4
- > rozenite build
5
-
6
- ┌ Rozenite
7
- [?25l│
8
-
9
- ◒ Cleaning output directory◐ Cleaning output directory◇ Output directory cleaned
10
- [?25h[?25l│
11
- ◒ Building panels◐ Building panels◓ Building panels◑ Building panels◒ Building panels◐ Building panels◓ Building panels◑ Building panels◒ Building panels.◐ Building panels.◓ Building panels.◑ Building panels.◒ Building panels.◐ Building panels.◓ Building panels.◑ Building panels.◒ Building panels..◐ Building panels..◓ Building panels..◑ Building panels..◒ Building panels..◐ Building panels..◓ Building panels..◑ Building panels..◒ Building panels...◐ Building panels...◓ Building panels...◑ Building panels...◒ Building panels...◐ Building panels...◓ Building panels...◑ Building panels...◒ Building panels...◐ Building panels◓ Building panels◑ Building panels◒ Building panels◐ Building panels◓ Building panels◑ Building panels◒ Building panels◐ Building panels.◓ Building panels.◑ Building panels.◒ Building panels.◐ Building panels.◓ Building panels.◑ Building panels.◒ Building panels.◐ Building panels..◓ Building panels..◑ Building panels..◒ Building panels..◐ Building panels..◓ Building panels..◑ Building panels..◒ Building panels..◐ Building panels...◓ Building panels...◑ Building panels...◒ Building panels...◐ Building panels...◓ Building panels...◑ Building panels...◒ Building panels...◐ Building panels...◓ Building panels◑ Building panels◒ Building panels◐ Building panels◓ Building panels◑ Building panels◒ Building panels◐ Building panels◓ Building panels.◑ Building panels.◒ Building panels.◐ Building panels.◓ Building panels.◑ Building panels.◒ Building panels.◐ Building panels.◓ Building panels..◑ Building panels..◒ Building panels..◐ Building panels..◓ Building panels..◑ Building panels..◒ Building panels..◐ Building panels..◓ Building panels...◑ Building panels...◒ Building panels...◐ Building panels...◓ Building panels...◑ Building panels...◒ Building panels...◐ Building panels...◓ Building panels...◑ Building panels◒ Building panels◐ Building panels◓ Building panels◑ Building panels◒ Building panels◐ Building panels◓ Building panels◑ Building panels.◒ Building panels.◐ Building panels.◓ Building panels.◑ Building panels.◒ Building panels.◐ Building panels.◓ Building panels.◑ Building panels..◒ Building panels..◐ Building panels..◓ Building panels..◑ Building panels..◒ Building panels..◐ Building panels..◓ Building panels..◑ Building panels...◒ Building panels...◐ Building panels...◓ Building panels...◑ Building panels...◒ Building panels...◐ Building panels...◓ Building panels...◑ Building panels...◒ Building panels◐ Building panels◓ Building panels◑ Building panels◒ Building panels◐ Building panels◓ Building panels◑ Building panels◒ Building panels.◐ Building panels.◓ Building panels.◑ Building panels.◒ Building panels.◐ Building panels.◓ Building panels.◑ Building panels.◒ Building panels..◐ Building panels..◓ Building panels..◑ Building panels..◒ Building panels..◐ Building panels..◓ Building panels..◑ Building panels..◒ Building panels...◐ Building panels...◓ Building panels...◑ Building panels...◒ Building panels...◐ Building panels...◓ Building panels...◑ Building panels...◒ Building panels...◐ Building panels◓ Building panels◑ Building panels◒ Building panels◐ Building panels◓ Building panels◑ Building panels◒ Building panels◐ Building panels.◓ Building panels.◑ Building panels.◒ Building panels.◐ Building panels.◓ Building panels.◑ Building panels.◒ Building panels.◐ Building panels..◓ Building panels..◑ Building panels..◒ Building panels..◐ Building panels..◓ Building panels..◑ Building panels..◒ Building panels..◐ Building panels...◓ Building panels...◑ Building panels...◒ Building panels...◐ Building panels...◓ Building panels...◑ Building panels...◒ Building panels...◐ Building panels...◓ Building panels◇ Panels built
12
- [?25h[?25l│
13
- ◒ Building React Native entry point◐ Building React Native entry point◓ Building React Native entry point◑ Building React Native entry point◒ Building React Native entry point◐ Building React Native entry point◓ Building React Native entry point◑ Building React Native entry point◒ Building React Native entry point.◐ Building React Native entry point.◓ Building React Native entry point.◑ Building React Native entry point.◒ Building React Native entry point.◐ Building React Native entry point.◓ Building React Native entry point.◑ Building React Native entry point.◒ Building React Native entry point..◐ Building React Native entry point..◓ Building React Native entry point..◑ Building React Native entry point..◒ Building React Native entry point..◐ Building React Native entry point..◓ Building React Native entry point..◑ Building React Native entry point..◒ Building React Native entry point...◐ Building React Native entry point...◓ Building React Native entry point...◑ Building React Native entry point...◒ Building React Native entry point...◐ Building React Native entry point...◓ Building React Native entry point...◑ Building React Native entry point...◒ Building React Native entry point...◐ Building React Native entry point◓ Building React Native entry point◑ Building React Native entry point◒ Building React Native entry point◐ Building React Native entry point◓ Building React Native entry point◑ Building React Native entry point◒ Building React Native entry point◐ Building React Native entry point.◓ Building React Native entry point.◑ Building React Native entry point.◒ Building React Native entry point.◐ Building React Native entry point.◓ Building React Native entry point.◑ Building React Native entry point.◒ Building React Native entry point.◐ Building React Native entry point..◓ Building React Native entry point..◑ Building React Native entry point..◒ Building React Native entry point..◐ Building React Native entry point..◓ Building React Native entry point..◑ Building React Native entry point..◒ Building React Native entry point..◐ Building React Native entry point...◓ Building React Native entry point...◑ Building React Native entry point...◒ Building React Native entry point...◐ Building React Native entry point...◓ Building React Native entry point...◑ Building React Native entry point...◒ Building React Native entry point...◐ Building React Native entry point...◓ Building React Native entry point◑ Building React Native entry point◒ Building React Native entry point◐ Building React Native entry point◓ Building React Native entry point◑ Building React Native entry point◒ Building React Native entry point◐ Building React Native entry point◓ Building React Native entry point.◑ Building React Native entry point.◒ Building React Native entry point.◐ Building React Native entry point.◓ Building React Native entry point.◑ Building React Native entry point.◒ Building React Native entry point.◐ Building React Native entry point.◓ Building React Native entry point..◑ Building React Native entry point..◒ Building React Native entry point..◐ Building React Native entry point..◓ Building React Native entry point..◑ Building React Native entry point..◒ Building React Native entry point..◐ Building React Native entry point..◓ Building React Native entry point...◑ Building React Native entry point...◒ Building React Native entry point...◐ Building React Native entry point...◓ Building React Native entry point...◑ Building React Native entry point...◒ Building React Native entry point...◐ Building React Native entry point...◓ Building React Native entry point...◑ Building React Native entry point◒ Building React Native entry point◐ Building React Native entry point◓ Building React Native entry point◑ Building React Native entry point◒ Building React Native entry point◐ Building React Native entry point◓ Building React Native entry point◑ Building React Native entry point.◒ Building React Native entry point.◐ Building React Native entry point.◓ Building React Native entry point.◑ Building React Native entry point.◒ Building React Native entry point.◐ Building React Native entry point.◓ Building React Native entry point.◑ Building React Native entry point..◒ Building React Native entry point..◐ Building React Native entry point..◓ Building React Native entry point..◑ Building React Native entry point..◒ Building React Native entry point..◐ Building React Native entry point..◓ Building React Native entry point..◑ Building React Native entry point...◒ Building React Native entry point...◐ Building React Native entry point...◓ Building React Native entry point...◑ Building React Native entry point...◒ Building React Native entry point...◐ Building React Native entry point...◓ Building React Native entry point...◑ Building React Native entry point...◒ Building React Native entry point◐ Building React Native entry point◓ Building React Native entry point◑ Building React Native entry point◒ Building React Native entry point◐ Building React Native entry point◓ Building React Native entry point◑ Building React Native entry point◒ Building React Native entry point.◐ Building React Native entry point.◓ Building React Native entry point.◑ Building React Native entry point.◒ Building React Native entry point.◐ Building React Native entry point.◓ Building React Native entry point.◑ Building React Native entry point.◒ Building React Native entry point..◐ Building React Native entry point..◓ Building React Native entry point..◑ Building React Native entry point..◒ Building React Native entry point..◐ Building React Native entry point..◇ React Native entry point built
14
- [?25h│
15
- └ Plugin built successfully
16
-
@@ -1,4 +0,0 @@
1
-
2
- > @rozenite/controls-plugin@0.0.0 lint /Users/szymon.chmal/Projects/rn-devtools/packages/controls-plugin
3
- > eslint .
4
-
@@ -1,4 +0,0 @@
1
-
2
- > @rozenite/controls-plugin@0.0.0 typecheck /Users/szymon.chmal/Projects/rn-devtools/packages/controls-plugin
3
- > tsc -p tsconfig.json --noEmit
4
-