@rozenite/controls-plugin 2.0.0 → 2.1.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 +10 -0
- package/dist/devtools/assets/panel-BvIa5kqW.css +1 -0
- package/dist/devtools/assets/panel-H7O6Qof-.js +18 -0
- package/dist/devtools/panel.html +2 -2
- package/dist/react-native/chunks/useRozeniteControlsPlugin.require.js +12 -36
- package/dist/rozenite.json +1 -1
- package/package.json +28 -28
- package/sdk.ts +1 -4
- package/src/__tests__/serialization.test.ts +3 -9
- package/src/react-native/__tests__/controlsRegistry.test.ts +3 -11
- package/src/react-native/__tests__/useRozeniteControlsPlugin.test.tsx +4 -14
- package/src/react-native/controlsRegistry.ts +2 -6
- package/src/react-native/useControlsAgentTools.ts +8 -28
- package/src/react-native/useRozeniteControlsPlugin.ts +8 -24
- package/src/shared/agent-tools.ts +5 -18
- package/src/shared/serialization.ts +2 -5
- package/src/shared/types.ts +6 -18
- package/src/ui/panel.tsx +58 -143
- package/dist/devtools/assets/panel-DOPs3JU-.css +0 -1
- package/dist/devtools/assets/panel-bqV0H3UX.js +0 -18
package/dist/devtools/panel.html
CHANGED
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
<script>
|
|
23
23
|
var __ROZENITE_PANEL__ = true;
|
|
24
24
|
</script>
|
|
25
|
-
<script type="module" crossorigin src="../devtools/assets/panel-
|
|
26
|
-
<link rel="stylesheet" crossorigin href="../devtools/assets/panel-
|
|
25
|
+
<script type="module" crossorigin src="../devtools/assets/panel-H7O6Qof-.js"></script>
|
|
26
|
+
<link rel="stylesheet" crossorigin href="../devtools/assets/panel-BvIa5kqW.css">
|
|
27
27
|
</head>
|
|
28
28
|
<body>
|
|
29
29
|
<div id="root"></div>
|
|
@@ -110,9 +110,7 @@ const U = (t, n) => t ? t(n) : { valid: !0 }, D = (t) => t.type === "text" ? t :
|
|
|
110
110
|
const s = t.find((i) => i.id === n);
|
|
111
111
|
if (!s) {
|
|
112
112
|
const i = t.map((o) => o.id).join(", ");
|
|
113
|
-
throw new Error(
|
|
114
|
-
`Section "${n}" not found. Available: ${i || "(none)"}`
|
|
115
|
-
);
|
|
113
|
+
throw new Error(`Section "${n}" not found. Available: ${i || "(none)"}`);
|
|
116
114
|
}
|
|
117
115
|
const e = s.items.find((i) => i.id === r);
|
|
118
116
|
if (!e) {
|
|
@@ -207,20 +205,14 @@ const U = (t, n) => t ? t(n) : { valid: !0 }, D = (t) => t.type === "text" ? t :
|
|
|
207
205
|
handler: async ({ sectionId: r, itemId: s, value: e }) => {
|
|
208
206
|
const { item: i } = R(t(), r, s);
|
|
209
207
|
if (i.type === "text")
|
|
210
|
-
throw new Error(
|
|
211
|
-
`Item "${s}" is a read-only text item and cannot be updated.`
|
|
212
|
-
);
|
|
208
|
+
throw new Error(`Item "${s}" is a read-only text item and cannot be updated.`);
|
|
213
209
|
if (i.type === "button")
|
|
214
|
-
throw new Error(
|
|
215
|
-
`Item "${s}" is a button. Use press-button to trigger its action.`
|
|
216
|
-
);
|
|
210
|
+
throw new Error(`Item "${s}" is a button. Use press-button to trigger its action.`);
|
|
217
211
|
if (i.disabled)
|
|
218
212
|
throw new Error(`Item "${s}" is disabled.`);
|
|
219
213
|
if (i.type === "toggle") {
|
|
220
214
|
if (typeof e != "boolean")
|
|
221
|
-
throw new Error(
|
|
222
|
-
`Expected boolean value for toggle item "${s}".`
|
|
223
|
-
);
|
|
215
|
+
throw new Error(`Expected boolean value for toggle item "${s}".`);
|
|
224
216
|
if (i.validate) {
|
|
225
217
|
const o = i.validate(e);
|
|
226
218
|
if (!o.valid)
|
|
@@ -229,9 +221,7 @@ const U = (t, n) => t ? t(n) : { valid: !0 }, D = (t) => t.type === "text" ? t :
|
|
|
229
221
|
return await i.onUpdate(e), { applied: !0, sectionId: r, itemId: s };
|
|
230
222
|
}
|
|
231
223
|
if (typeof e != "string")
|
|
232
|
-
throw new Error(
|
|
233
|
-
`Expected string value for ${i.type} item "${s}".`
|
|
234
|
-
);
|
|
224
|
+
throw new Error(`Expected string value for ${i.type} item "${s}".`);
|
|
235
225
|
if (i.type === "select") {
|
|
236
226
|
const o = i.options.map((p) => p.value);
|
|
237
227
|
if (!o.includes(e))
|
|
@@ -321,10 +311,7 @@ const U = (t, n) => t ? t(n) : { valid: !0 }, D = (t) => t.type === "text" ? t :
|
|
|
321
311
|
}),
|
|
322
312
|
[t, e, s]
|
|
323
313
|
);
|
|
324
|
-
return L(
|
|
325
|
-
() => u.getOptions().sections,
|
|
326
|
-
i
|
|
327
|
-
), h(() => {
|
|
314
|
+
return L(() => u.getOptions().sections, i), h(() => {
|
|
328
315
|
n && n.send("snapshot", {
|
|
329
316
|
type: "snapshot",
|
|
330
317
|
sections: m(u.getOptions().sections)
|
|
@@ -338,9 +325,7 @@ const U = (t, n) => t ? t(n) : { valid: !0 }, D = (t) => t.type === "text" ? t :
|
|
|
338
325
|
itemId: d,
|
|
339
326
|
value: y
|
|
340
327
|
}) => {
|
|
341
|
-
const f = P(l, d), c = O(
|
|
342
|
-
u.getOptions().sections
|
|
343
|
-
).get(f);
|
|
328
|
+
const f = P(l, d), c = O(u.getOptions().sections).get(f);
|
|
344
329
|
if (!c || c.type === "button") {
|
|
345
330
|
n.send("update-result", {
|
|
346
331
|
type: "update-result",
|
|
@@ -429,20 +414,14 @@ const U = (t, n) => t ? t(n) : { valid: !0 }, D = (t) => t.type === "text" ? t :
|
|
|
429
414
|
message: "Update failed on the device."
|
|
430
415
|
});
|
|
431
416
|
}
|
|
432
|
-
}, p = async ({
|
|
433
|
-
sectionId: a,
|
|
434
|
-
itemId: l,
|
|
435
|
-
action: d
|
|
436
|
-
}) => {
|
|
417
|
+
}, p = async ({ sectionId: a, itemId: l, action: d }) => {
|
|
437
418
|
if (d !== "press") {
|
|
438
419
|
console.warn(
|
|
439
420
|
`[Rozenite] Controls Plugin: Unsupported action "${d}" for ${a}/${l}.`
|
|
440
421
|
);
|
|
441
422
|
return;
|
|
442
423
|
}
|
|
443
|
-
const y = P(a, l), f = O(
|
|
444
|
-
u.getOptions().sections
|
|
445
|
-
).get(y);
|
|
424
|
+
const y = P(a, l), f = O(u.getOptions().sections).get(y);
|
|
446
425
|
if (!f) {
|
|
447
426
|
console.warn(
|
|
448
427
|
`[Rozenite] Controls Plugin: Action target not found for ${a}/${l}.`
|
|
@@ -470,12 +449,9 @@ const U = (t, n) => t ? t(n) : { valid: !0 }, D = (t) => t.type === "text" ? t :
|
|
|
470
449
|
sections: m(u.getOptions().sections)
|
|
471
450
|
});
|
|
472
451
|
}),
|
|
473
|
-
n.onMessage(
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
o(a);
|
|
477
|
-
}
|
|
478
|
-
),
|
|
452
|
+
n.onMessage("update-request", (a) => {
|
|
453
|
+
o(a);
|
|
454
|
+
}),
|
|
479
455
|
n.onMessage("invoke-action", (a) => {
|
|
480
456
|
p(a);
|
|
481
457
|
})
|
package/dist/rozenite.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@rozenite/controls-plugin","version":"2.
|
|
1
|
+
{"name":"@rozenite/controls-plugin","version":"2.1.0","description":"A Rozenite plugin for exposing app-defined controls directly in React Native DevTools.","panels":[{"name":"Controls","source":"/devtools/panel.html"}]}
|
package/package.json
CHANGED
|
@@ -1,42 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rozenite/controls-plugin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "A Rozenite plugin for exposing app-defined controls directly in React Native DevTools.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/react-native/index.cjs",
|
|
7
|
-
"module": "./dist/react-native/index.js",
|
|
8
|
-
"types": "./dist/react-native/index.d.ts",
|
|
9
5
|
"homepage": "https://github.com/callstackincubator/rozenite#readme",
|
|
10
6
|
"bugs": {
|
|
11
7
|
"url": "https://github.com/callstackincubator/rozenite/issues"
|
|
12
8
|
},
|
|
9
|
+
"license": "MIT",
|
|
13
10
|
"repository": {
|
|
14
11
|
"type": "git",
|
|
15
12
|
"url": "https://github.com/callstackincubator/rozenite.git"
|
|
16
13
|
},
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"@rozenite/ui": "2.0.0"
|
|
22
|
-
},
|
|
23
|
-
"devDependencies": {
|
|
24
|
-
"@types/react": "~19.2.3",
|
|
25
|
-
"@types/react-dom": "~19.2.3",
|
|
26
|
-
"react": "19.2.3",
|
|
27
|
-
"react-dom": "19.2.3",
|
|
28
|
-
"react-native": "0.86.0",
|
|
29
|
-
"react-native-web": "^0.21.2",
|
|
30
|
-
"typescript": "~5.9.3",
|
|
31
|
-
"vite": "^7.3.1",
|
|
32
|
-
"@rozenite/vite-plugin": "2.0.0",
|
|
33
|
-
"rozenite": "2.0.0"
|
|
34
|
-
},
|
|
35
|
-
"peerDependencies": {
|
|
36
|
-
"react": "*",
|
|
37
|
-
"react-native": "*"
|
|
38
|
-
},
|
|
39
|
-
"license": "MIT",
|
|
14
|
+
"type": "module",
|
|
15
|
+
"main": "./dist/react-native/index.cjs",
|
|
16
|
+
"module": "./dist/react-native/index.js",
|
|
17
|
+
"types": "./dist/react-native/index.d.ts",
|
|
40
18
|
"exports": {
|
|
41
19
|
".": {
|
|
42
20
|
"types": "./dist/react-native/index.d.ts",
|
|
@@ -54,6 +32,28 @@
|
|
|
54
32
|
"publishConfig": {
|
|
55
33
|
"access": "public"
|
|
56
34
|
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@rozenite/agent-bridge": "2.1.0",
|
|
37
|
+
"@rozenite/agent-shared": "2.1.0",
|
|
38
|
+
"@rozenite/plugin-bridge": "2.1.0",
|
|
39
|
+
"@rozenite/ui": "2.1.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/react": "~19.2.3",
|
|
43
|
+
"@types/react-dom": "~19.2.3",
|
|
44
|
+
"react": "19.2.3",
|
|
45
|
+
"react-dom": "19.2.3",
|
|
46
|
+
"react-native": "0.86.0",
|
|
47
|
+
"react-native-web": "^0.21.2",
|
|
48
|
+
"typescript": "~5.9.3",
|
|
49
|
+
"vite": "^7.3.1",
|
|
50
|
+
"@rozenite/vite-plugin": "2.1.0",
|
|
51
|
+
"rozenite": "2.1.0"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"react": "*",
|
|
55
|
+
"react-native": "*"
|
|
56
|
+
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "rozenite build",
|
|
59
59
|
"dev": "rozenite dev",
|
package/sdk.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { defineAgentToolDescriptors } from '@rozenite/agent-shared';
|
|
2
|
-
import {
|
|
3
|
-
CONTROLS_AGENT_PLUGIN_ID,
|
|
4
|
-
controlsToolDefinitions,
|
|
5
|
-
} from './src/shared/agent-tools.js';
|
|
2
|
+
import { CONTROLS_AGENT_PLUGIN_ID, controlsToolDefinitions } from './src/shared/agent-tools.js';
|
|
6
3
|
|
|
7
4
|
export { CONTROLS_AGENT_PLUGIN_ID, controlsToolDefinitions };
|
|
8
5
|
|
|
@@ -171,15 +171,9 @@ describe('controls serialization', () => {
|
|
|
171
171
|
const registry = buildActionRegistry(sections);
|
|
172
172
|
|
|
173
173
|
const toggleEntry = registry.get(getActionRegistryKey('controls', 'flag'));
|
|
174
|
-
const buttonEntry = registry.get(
|
|
175
|
-
|
|
176
|
-
);
|
|
177
|
-
const selectEntry = registry.get(
|
|
178
|
-
getActionRegistryKey('controls', 'environment'),
|
|
179
|
-
);
|
|
180
|
-
const inputEntry = registry.get(
|
|
181
|
-
getActionRegistryKey('controls', 'release-label'),
|
|
182
|
-
);
|
|
174
|
+
const buttonEntry = registry.get(getActionRegistryKey('controls', 'refresh'));
|
|
175
|
+
const selectEntry = registry.get(getActionRegistryKey('controls', 'environment'));
|
|
176
|
+
const inputEntry = registry.get(getActionRegistryKey('controls', 'release-label'));
|
|
183
177
|
|
|
184
178
|
expect(toggleEntry?.type).toBe('toggle');
|
|
185
179
|
expect(buttonEntry?.type).toBe('button');
|
|
@@ -17,10 +17,7 @@ describe('controlsRegistry', () => {
|
|
|
17
17
|
registry.set(first, { sections: [section('app')] });
|
|
18
18
|
registry.set(second, { sections: [section('locale')] });
|
|
19
19
|
|
|
20
|
-
expect(registry.getOptions().sections.map(({ id }) => id)).toEqual([
|
|
21
|
-
'app',
|
|
22
|
-
'locale',
|
|
23
|
-
]);
|
|
20
|
+
expect(registry.getOptions().sections.map(({ id }) => id)).toEqual(['app', 'locale']);
|
|
24
21
|
});
|
|
25
22
|
|
|
26
23
|
it('lets updater registrations derive from previous options', () => {
|
|
@@ -33,10 +30,7 @@ describe('controlsRegistry', () => {
|
|
|
33
30
|
sections: [...previousOptions.sections, section('locale')],
|
|
34
31
|
}));
|
|
35
32
|
|
|
36
|
-
expect(registry.getOptions().sections.map(({ id }) => id)).toEqual([
|
|
37
|
-
'app',
|
|
38
|
-
'locale',
|
|
39
|
-
]);
|
|
33
|
+
expect(registry.getOptions().sections.map(({ id }) => id)).toEqual(['app', 'locale']);
|
|
40
34
|
});
|
|
41
35
|
|
|
42
36
|
it('lets updater registrations replace previous options when needed', () => {
|
|
@@ -49,9 +43,7 @@ describe('controlsRegistry', () => {
|
|
|
49
43
|
sections: [section('replacement')],
|
|
50
44
|
}));
|
|
51
45
|
|
|
52
|
-
expect(registry.getOptions().sections.map(({ id }) => id)).toEqual([
|
|
53
|
-
'replacement',
|
|
54
|
-
]);
|
|
46
|
+
expect(registry.getOptions().sections.map(({ id }) => id)).toEqual(['replacement']);
|
|
55
47
|
});
|
|
56
48
|
|
|
57
49
|
it('can include the current render input before the effect registers it', () => {
|
|
@@ -88,11 +88,7 @@ function AppControls() {
|
|
|
88
88
|
return null;
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
-
function LocaleControls({
|
|
92
|
-
onUpdate = vi.fn(),
|
|
93
|
-
}: {
|
|
94
|
-
onUpdate?: (value: string) => void;
|
|
95
|
-
}) {
|
|
91
|
+
function LocaleControls({ onUpdate = vi.fn() }: { onUpdate?: (value: string) => void }) {
|
|
96
92
|
useRozeniteControlsPlugin((previousOptions) => ({
|
|
97
93
|
sections: [...previousOptions.sections, localeSection(onUpdate)],
|
|
98
94
|
}));
|
|
@@ -140,12 +136,8 @@ const unmountControls = async (root: Root, container: HTMLDivElement) => {
|
|
|
140
136
|
};
|
|
141
137
|
|
|
142
138
|
const getLastSnapshotSectionIds = () => {
|
|
143
|
-
const snapshots = mocks.client.send.mock.calls.filter(
|
|
144
|
-
|
|
145
|
-
);
|
|
146
|
-
const lastSnapshot = snapshots.at(-1)?.[1] as
|
|
147
|
-
| ControlsEventMap['snapshot']
|
|
148
|
-
| undefined;
|
|
139
|
+
const snapshots = mocks.client.send.mock.calls.filter(([type]) => type === 'snapshot');
|
|
140
|
+
const lastSnapshot = snapshots.at(-1)?.[1] as ControlsEventMap['snapshot'] | undefined;
|
|
149
141
|
|
|
150
142
|
return lastSnapshot?.sections.map((section) => section.id);
|
|
151
143
|
};
|
|
@@ -183,9 +175,7 @@ describe('useRozeniteControlsPlugin', () => {
|
|
|
183
175
|
|
|
184
176
|
it('routes updates to sections registered by another hook instance', async () => {
|
|
185
177
|
const onUpdate = vi.fn();
|
|
186
|
-
const { root, container } = await renderControls(
|
|
187
|
-
<TestApp onUpdate={onUpdate} />,
|
|
188
|
-
);
|
|
178
|
+
const { root, container } = await renderControls(<TestApp onUpdate={onUpdate} />);
|
|
189
179
|
|
|
190
180
|
await act(async () => {
|
|
191
181
|
mocks.emit('update-request', {
|
|
@@ -54,9 +54,7 @@ export const createControlsRegistry = () => {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
return entries.map(([id, input]) =>
|
|
57
|
-
id === override.id
|
|
58
|
-
? ([id, override.input] as const)
|
|
59
|
-
: ([id, input] as const),
|
|
57
|
+
id === override.id ? ([id, override.input] as const) : ([id, input] as const),
|
|
60
58
|
);
|
|
61
59
|
};
|
|
62
60
|
|
|
@@ -73,9 +71,7 @@ export const createControlsRegistry = () => {
|
|
|
73
71
|
registrations.delete(id);
|
|
74
72
|
notify();
|
|
75
73
|
},
|
|
76
|
-
getOptions(
|
|
77
|
-
override?: ControlsRegistryOverride,
|
|
78
|
-
): RozeniteControlsPluginOptions {
|
|
74
|
+
getOptions(override?: ControlsRegistryOverride): RozeniteControlsPluginOptions {
|
|
79
75
|
return getRegistrationEntries(override)
|
|
80
76
|
.map(([, input]) => input)
|
|
81
77
|
.reduce(resolveOptionsInput, EMPTY_OPTIONS);
|
|
@@ -1,22 +1,13 @@
|
|
|
1
1
|
import { useRozenitePluginAgentTool } from '@rozenite/agent-bridge';
|
|
2
|
-
import {
|
|
3
|
-
CONTROLS_AGENT_PLUGIN_ID,
|
|
4
|
-
controlsToolDefinitions,
|
|
5
|
-
} from '../shared/agent-tools';
|
|
2
|
+
import { CONTROLS_AGENT_PLUGIN_ID, controlsToolDefinitions } from '../shared/agent-tools';
|
|
6
3
|
import type { ControlsSection } from '../shared/types';
|
|
7
4
|
|
|
8
|
-
const resolveItem = (
|
|
9
|
-
sections: ControlsSection[],
|
|
10
|
-
sectionId: string,
|
|
11
|
-
itemId: string,
|
|
12
|
-
) => {
|
|
5
|
+
const resolveItem = (sections: ControlsSection[], sectionId: string, itemId: string) => {
|
|
13
6
|
const section = sections.find((s) => s.id === sectionId);
|
|
14
7
|
|
|
15
8
|
if (!section) {
|
|
16
9
|
const available = sections.map((s) => s.id).join(', ');
|
|
17
|
-
throw new Error(
|
|
18
|
-
`Section "${sectionId}" not found. Available: ${available || '(none)'}`,
|
|
19
|
-
);
|
|
10
|
+
throw new Error(`Section "${sectionId}" not found. Available: ${available || '(none)'}`);
|
|
20
11
|
}
|
|
21
12
|
|
|
22
13
|
const item = section.items.find((i) => i.id === itemId);
|
|
@@ -31,10 +22,7 @@ const resolveItem = (
|
|
|
31
22
|
return { section, item };
|
|
32
23
|
};
|
|
33
24
|
|
|
34
|
-
export const useControlsAgentTools = (
|
|
35
|
-
getSections: () => ControlsSection[],
|
|
36
|
-
enabled = true,
|
|
37
|
-
) => {
|
|
25
|
+
export const useControlsAgentTools = (getSections: () => ControlsSection[], enabled = true) => {
|
|
38
26
|
useRozenitePluginAgentTool({
|
|
39
27
|
pluginId: CONTROLS_AGENT_PLUGIN_ID,
|
|
40
28
|
tool: controlsToolDefinitions.listSections,
|
|
@@ -141,15 +129,11 @@ export const useControlsAgentTools = (
|
|
|
141
129
|
const { item } = resolveItem(getSections(), sectionId, itemId);
|
|
142
130
|
|
|
143
131
|
if (item.type === 'text') {
|
|
144
|
-
throw new Error(
|
|
145
|
-
`Item "${itemId}" is a read-only text item and cannot be updated.`,
|
|
146
|
-
);
|
|
132
|
+
throw new Error(`Item "${itemId}" is a read-only text item and cannot be updated.`);
|
|
147
133
|
}
|
|
148
134
|
|
|
149
135
|
if (item.type === 'button') {
|
|
150
|
-
throw new Error(
|
|
151
|
-
`Item "${itemId}" is a button. Use press-button to trigger its action.`,
|
|
152
|
-
);
|
|
136
|
+
throw new Error(`Item "${itemId}" is a button. Use press-button to trigger its action.`);
|
|
153
137
|
}
|
|
154
138
|
|
|
155
139
|
if (item.disabled) {
|
|
@@ -158,9 +142,7 @@ export const useControlsAgentTools = (
|
|
|
158
142
|
|
|
159
143
|
if (item.type === 'toggle') {
|
|
160
144
|
if (typeof value !== 'boolean') {
|
|
161
|
-
throw new Error(
|
|
162
|
-
`Expected boolean value for toggle item "${itemId}".`,
|
|
163
|
-
);
|
|
145
|
+
throw new Error(`Expected boolean value for toggle item "${itemId}".`);
|
|
164
146
|
}
|
|
165
147
|
|
|
166
148
|
if (item.validate) {
|
|
@@ -175,9 +157,7 @@ export const useControlsAgentTools = (
|
|
|
175
157
|
}
|
|
176
158
|
|
|
177
159
|
if (typeof value !== 'string') {
|
|
178
|
-
throw new Error(
|
|
179
|
-
`Expected string value for ${item.type} item "${itemId}".`,
|
|
180
|
-
);
|
|
160
|
+
throw new Error(`Expected string value for ${item.type} item "${itemId}".`);
|
|
181
161
|
}
|
|
182
162
|
|
|
183
163
|
if (item.type === 'select') {
|
|
@@ -15,9 +15,7 @@ import {
|
|
|
15
15
|
import { useControlsAgentTools } from './useControlsAgentTools';
|
|
16
16
|
import { controlsRegistry } from './controlsRegistry';
|
|
17
17
|
|
|
18
|
-
export const useRozeniteControlsPlugin = (
|
|
19
|
-
optionsInput: RozeniteControlsPluginOptionsInput,
|
|
20
|
-
) => {
|
|
18
|
+
export const useRozeniteControlsPlugin = (optionsInput: RozeniteControlsPluginOptionsInput) => {
|
|
21
19
|
const client = useRozeniteDevToolsClient<ControlsEventMap>({
|
|
22
20
|
pluginId: '@rozenite/controls-plugin',
|
|
23
21
|
});
|
|
@@ -48,10 +46,7 @@ export const useRozeniteControlsPlugin = (
|
|
|
48
46
|
[optionsInput, registrySnapshot, registrationId],
|
|
49
47
|
);
|
|
50
48
|
|
|
51
|
-
useControlsAgentTools(
|
|
52
|
-
() => controlsRegistry.getOptions().sections,
|
|
53
|
-
isRegistryOwner,
|
|
54
|
-
);
|
|
49
|
+
useControlsAgentTools(() => controlsRegistry.getOptions().sections, isRegistryOwner);
|
|
55
50
|
|
|
56
51
|
useEffect(() => {
|
|
57
52
|
if (!client) {
|
|
@@ -76,9 +71,7 @@ export const useRozeniteControlsPlugin = (
|
|
|
76
71
|
value,
|
|
77
72
|
}: ControlsUpdateRequestEvent) => {
|
|
78
73
|
const key = getActionRegistryKey(sectionId, itemId);
|
|
79
|
-
const entry = buildActionRegistry(
|
|
80
|
-
controlsRegistry.getOptions().sections,
|
|
81
|
-
).get(key);
|
|
74
|
+
const entry = buildActionRegistry(controlsRegistry.getOptions().sections).get(key);
|
|
82
75
|
|
|
83
76
|
if (!entry || entry.type === 'button') {
|
|
84
77
|
client.send('update-result', {
|
|
@@ -179,11 +172,7 @@ export const useRozeniteControlsPlugin = (
|
|
|
179
172
|
}
|
|
180
173
|
};
|
|
181
174
|
|
|
182
|
-
const handleInvokeAction = async ({
|
|
183
|
-
sectionId,
|
|
184
|
-
itemId,
|
|
185
|
-
action,
|
|
186
|
-
}: ControlsInvokeActionEvent) => {
|
|
175
|
+
const handleInvokeAction = async ({ sectionId, itemId, action }: ControlsInvokeActionEvent) => {
|
|
187
176
|
if (action !== 'press') {
|
|
188
177
|
console.warn(
|
|
189
178
|
`[Rozenite] Controls Plugin: Unsupported action "${action}" for ${sectionId}/${itemId}.`,
|
|
@@ -192,9 +181,7 @@ export const useRozeniteControlsPlugin = (
|
|
|
192
181
|
}
|
|
193
182
|
|
|
194
183
|
const key = getActionRegistryKey(sectionId, itemId);
|
|
195
|
-
const entry = buildActionRegistry(
|
|
196
|
-
controlsRegistry.getOptions().sections,
|
|
197
|
-
).get(key);
|
|
184
|
+
const entry = buildActionRegistry(controlsRegistry.getOptions().sections).get(key);
|
|
198
185
|
|
|
199
186
|
if (!entry) {
|
|
200
187
|
console.warn(
|
|
@@ -227,12 +214,9 @@ export const useRozeniteControlsPlugin = (
|
|
|
227
214
|
sections: serializeSections(controlsRegistry.getOptions().sections),
|
|
228
215
|
});
|
|
229
216
|
}),
|
|
230
|
-
client.onMessage(
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
void handleUpdateRequest(event);
|
|
234
|
-
},
|
|
235
|
-
),
|
|
217
|
+
client.onMessage('update-request', (event: ControlsUpdateRequestEvent) => {
|
|
218
|
+
void handleUpdateRequest(event);
|
|
219
|
+
}),
|
|
236
220
|
client.onMessage('invoke-action', (event: ControlsInvokeActionEvent) => {
|
|
237
221
|
void handleInvokeAction(event);
|
|
238
222
|
}),
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
defineAgentToolContract,
|
|
3
|
-
type AgentToolContract,
|
|
4
|
-
} from '@rozenite/agent-shared';
|
|
1
|
+
import { defineAgentToolContract, type AgentToolContract } from '@rozenite/agent-shared';
|
|
5
2
|
import type { ControlsItem, ControlsItemSnapshot } from './types';
|
|
6
3
|
|
|
7
4
|
export const CONTROLS_AGENT_PLUGIN_ID = '@rozenite/controls-plugin';
|
|
@@ -57,10 +54,7 @@ export type ControlsPressButtonResult = {
|
|
|
57
54
|
};
|
|
58
55
|
|
|
59
56
|
export const controlsToolDefinitions = {
|
|
60
|
-
listSections: defineAgentToolContract<
|
|
61
|
-
ControlsListSectionsArgs,
|
|
62
|
-
ControlsListSectionsResult
|
|
63
|
-
>({
|
|
57
|
+
listSections: defineAgentToolContract<ControlsListSectionsArgs, ControlsListSectionsResult>({
|
|
64
58
|
name: 'list-sections',
|
|
65
59
|
description:
|
|
66
60
|
'List all controls sections with their item IDs, types, and titles. Does not include values — call get-item for that.',
|
|
@@ -79,10 +73,7 @@ export const controlsToolDefinitions = {
|
|
|
79
73
|
required: ['sectionId', 'itemId'],
|
|
80
74
|
},
|
|
81
75
|
}),
|
|
82
|
-
setValue: defineAgentToolContract<
|
|
83
|
-
ControlsSetValueArgs,
|
|
84
|
-
ControlsSetValueResult
|
|
85
|
-
>({
|
|
76
|
+
setValue: defineAgentToolContract<ControlsSetValueArgs, ControlsSetValueResult>({
|
|
86
77
|
name: 'set-value',
|
|
87
78
|
description:
|
|
88
79
|
'Update the value of a toggle, select, or input item. Runs the validate callback when present. Fails for text (read-only) and button items.',
|
|
@@ -92,17 +83,13 @@ export const controlsToolDefinitions = {
|
|
|
92
83
|
sectionId: { type: 'string', description: 'Section ID.' },
|
|
93
84
|
itemId: { type: 'string', description: 'Item ID.' },
|
|
94
85
|
value: {
|
|
95
|
-
description:
|
|
96
|
-
'New value. Boolean for toggle items, string for select/input items.',
|
|
86
|
+
description: 'New value. Boolean for toggle items, string for select/input items.',
|
|
97
87
|
},
|
|
98
88
|
},
|
|
99
89
|
required: ['sectionId', 'itemId', 'value'],
|
|
100
90
|
},
|
|
101
91
|
}),
|
|
102
|
-
pressButton: defineAgentToolContract<
|
|
103
|
-
ControlsPressButtonArgs,
|
|
104
|
-
ControlsPressButtonResult
|
|
105
|
-
>({
|
|
92
|
+
pressButton: defineAgentToolContract<ControlsPressButtonArgs, ControlsPressButtonResult>({
|
|
106
93
|
name: 'press-button',
|
|
107
94
|
description:
|
|
108
95
|
"Trigger a button item's action. Fails if the item is not a button or is disabled.",
|
|
@@ -94,9 +94,7 @@ const toSnapshotItem = (item: ControlsItem): ControlsItemSnapshot => {
|
|
|
94
94
|
};
|
|
95
95
|
};
|
|
96
96
|
|
|
97
|
-
export const serializeSections = (
|
|
98
|
-
sections: ControlsSection[],
|
|
99
|
-
): ControlsSectionSnapshot[] =>
|
|
97
|
+
export const serializeSections = (sections: ControlsSection[]): ControlsSectionSnapshot[] =>
|
|
100
98
|
sections.map((section) => ({
|
|
101
99
|
id: section.id,
|
|
102
100
|
title: section.title,
|
|
@@ -147,7 +145,6 @@ export const buildActionRegistry = (sections: ControlsSection[]) => {
|
|
|
147
145
|
return registry;
|
|
148
146
|
};
|
|
149
147
|
|
|
150
|
-
export const getActionRegistryKey = (sectionId: string, itemId: string) =>
|
|
151
|
-
`${sectionId}:${itemId}`;
|
|
148
|
+
export const getActionRegistryKey = (sectionId: string, itemId: string) => `${sectionId}:${itemId}`;
|
|
152
149
|
|
|
153
150
|
export { validateValue };
|
package/src/shared/types.ts
CHANGED
|
@@ -6,9 +6,7 @@ export type ControlsTextItem = {
|
|
|
6
6
|
description?: string;
|
|
7
7
|
};
|
|
8
8
|
|
|
9
|
-
export type ControlsValidationResult =
|
|
10
|
-
| { valid: true }
|
|
11
|
-
| { valid: false; message: string };
|
|
9
|
+
export type ControlsValidationResult = { valid: true } | { valid: false; message: string };
|
|
12
10
|
|
|
13
11
|
export type ControlsMutableItemBase<TValue> = {
|
|
14
12
|
id: string;
|
|
@@ -66,22 +64,13 @@ export type ControlsSection = {
|
|
|
66
64
|
|
|
67
65
|
export type ControlsTextItemSnapshot = Omit<ControlsTextItem, never>;
|
|
68
66
|
|
|
69
|
-
export type ControlsToggleItemSnapshot = Omit<
|
|
70
|
-
ControlsToggleItem,
|
|
71
|
-
'validate' | 'onUpdate'
|
|
72
|
-
>;
|
|
67
|
+
export type ControlsToggleItemSnapshot = Omit<ControlsToggleItem, 'validate' | 'onUpdate'>;
|
|
73
68
|
|
|
74
69
|
export type ControlsButtonItemSnapshot = Omit<ControlsButtonItem, 'onPress'>;
|
|
75
70
|
|
|
76
|
-
export type ControlsSelectItemSnapshot = Omit<
|
|
77
|
-
ControlsSelectItem,
|
|
78
|
-
'validate' | 'onUpdate'
|
|
79
|
-
>;
|
|
71
|
+
export type ControlsSelectItemSnapshot = Omit<ControlsSelectItem, 'validate' | 'onUpdate'>;
|
|
80
72
|
|
|
81
|
-
export type ControlsInputItemSnapshot = Omit<
|
|
82
|
-
ControlsInputItem,
|
|
83
|
-
'validate' | 'onUpdate'
|
|
84
|
-
>;
|
|
73
|
+
export type ControlsInputItemSnapshot = Omit<ControlsInputItem, 'validate' | 'onUpdate'>;
|
|
85
74
|
|
|
86
75
|
export type ControlsItemSnapshot =
|
|
87
76
|
| ControlsTextItemSnapshot
|
|
@@ -106,6 +95,5 @@ export type RozeniteControlsPluginOptionsInput =
|
|
|
106
95
|
| RozeniteControlsPluginOptions
|
|
107
96
|
| RozeniteControlsPluginOptionsUpdater;
|
|
108
97
|
|
|
109
|
-
export const createSection = <TSection extends ControlsSection>(
|
|
110
|
-
section
|
|
111
|
-
): TSection => section;
|
|
98
|
+
export const createSection = <TSection extends ControlsSection>(section: TSection): TSection =>
|
|
99
|
+
section;
|