sunpeak 0.9.12 → 0.10.3

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/README.md +2 -2
  2. package/bin/commands/build.mjs +56 -30
  3. package/bin/commands/deploy.mjs +17 -17
  4. package/bin/commands/push.mjs +115 -64
  5. package/bin/lib/patterns.mjs +40 -0
  6. package/bin/sunpeak.js +50 -106
  7. package/dist/index.cjs +149 -11
  8. package/dist/index.cjs.map +1 -1
  9. package/dist/index.js +165 -27
  10. package/dist/index.js.map +1 -1
  11. package/dist/lib/discovery.d.ts +76 -13
  12. package/dist/mcp/entry.cjs +24 -27
  13. package/dist/mcp/entry.cjs.map +1 -1
  14. package/dist/mcp/entry.js +25 -28
  15. package/dist/mcp/entry.js.map +1 -1
  16. package/package.json +1 -1
  17. package/template/.sunpeak/dev.tsx +5 -5
  18. package/template/README.md +54 -50
  19. package/template/dist/{albums.json → albums/albums.json} +1 -1
  20. package/template/dist/{carousel.json → carousel/carousel.json} +1 -1
  21. package/template/dist/{map.json → map/map.json} +1 -1
  22. package/template/dist/{review.json → review/review.json} +1 -1
  23. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Button.js +3 -3
  24. package/template/node_modules/.vite/deps/@openai_apps-sdk-ui_components_Select.js +11 -11
  25. package/template/node_modules/.vite/deps/_metadata.json +26 -26
  26. package/template/node_modules/.vite/deps/{chunk-N6DVYEXK.js → chunk-LVZJNEGE.js} +7 -7
  27. package/template/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  28. package/template/src/resources/{albums-resource.test.tsx → albums/albums-resource.test.tsx} +1 -1
  29. package/template/src/resources/{albums-resource.tsx → albums/albums-resource.tsx} +1 -1
  30. package/template/src/resources/albums/albums-show-simulation.json +131 -0
  31. package/template/src/{components/album → resources/albums/components}/album-card.tsx +1 -1
  32. package/template/src/{components/album → resources/albums/components}/album-carousel.tsx +1 -1
  33. package/template/src/{components/album → resources/albums/components}/film-strip.tsx +1 -1
  34. package/template/src/{components/album → resources/albums/components}/fullscreen-viewer.tsx +1 -1
  35. package/template/src/resources/{carousel-resource.test.tsx → carousel/carousel-resource.test.tsx} +1 -1
  36. package/template/src/resources/{carousel-resource.tsx → carousel/carousel-resource.tsx} +1 -1
  37. package/template/src/resources/carousel/carousel-show-simulation.json +68 -0
  38. package/template/src/{components/carousel → resources/carousel/components}/card.tsx +1 -1
  39. package/template/src/{components/carousel → resources/carousel/components}/carousel.tsx +1 -1
  40. package/template/src/resources/index.ts +5 -5
  41. package/template/src/{components/map → resources/map/components}/map-view.tsx +1 -1
  42. package/template/src/{components/map → resources/map/components}/map.tsx +1 -1
  43. package/template/src/{components/map → resources/map/components}/place-card.tsx +1 -1
  44. package/template/src/{components/map → resources/map/components}/place-carousel.tsx +1 -1
  45. package/template/src/{components/map → resources/map/components}/place-inspector.tsx +1 -1
  46. package/template/src/{components/map → resources/map/components}/place-list.tsx +1 -1
  47. package/template/src/resources/{map-resource.test.tsx → map/map-resource.test.tsx} +1 -1
  48. package/template/src/resources/{map-resource.tsx → map/map-resource.tsx} +1 -1
  49. package/template/src/resources/map/map-show-simulation.json +123 -0
  50. package/template/src/resources/review/review-diff-simulation.json +80 -0
  51. package/template/src/resources/review/review-post-simulation.json +56 -0
  52. package/template/src/resources/review/review-purchase-simulation.json +88 -0
  53. package/dist/discovery-a4WId9PC.cjs +0 -125
  54. package/dist/discovery-a4WId9PC.cjs.map +0 -1
  55. package/dist/discovery-ft3cd2dW.js +0 -126
  56. package/dist/discovery-ft3cd2dW.js.map +0 -1
  57. package/template/src/components/index.ts +0 -3
  58. package/template/src/simulations/index.ts +0 -16
  59. /package/template/{src/simulations → dist/albums}/albums-show-simulation.json +0 -0
  60. /package/template/dist/{albums.js → albums/albums.js} +0 -0
  61. /package/template/{src/simulations → dist/carousel}/carousel-show-simulation.json +0 -0
  62. /package/template/dist/{carousel.js → carousel/carousel.js} +0 -0
  63. /package/template/{src/simulations → dist/map}/map-show-simulation.json +0 -0
  64. /package/template/dist/{map.js → map/map.js} +0 -0
  65. /package/template/{src/simulations → dist/review}/review-diff-simulation.json +0 -0
  66. /package/template/{src/simulations → dist/review}/review-post-simulation.json +0 -0
  67. /package/template/{src/simulations → dist/review}/review-purchase-simulation.json +0 -0
  68. /package/template/dist/{review.js → review/review.js} +0 -0
  69. /package/template/node_modules/.vite/deps/{chunk-N6DVYEXK.js.map → chunk-LVZJNEGE.js.map} +0 -0
  70. /package/template/src/resources/{albums-resource.json → albums/albums-resource.json} +0 -0
  71. /package/template/src/{components/album → resources/albums/components}/album-card.test.tsx +0 -0
  72. /package/template/src/{components/album → resources/albums/components}/album-carousel.test.tsx +0 -0
  73. /package/template/src/{components/album → resources/albums/components}/albums.test.tsx +0 -0
  74. /package/template/src/{components/album → resources/albums/components}/albums.tsx +0 -0
  75. /package/template/src/{components/album → resources/albums/components}/film-strip.test.tsx +0 -0
  76. /package/template/src/{components/album → resources/albums/components}/fullscreen-viewer.test.tsx +0 -0
  77. /package/template/src/{components/album → resources/albums/components}/index.ts +0 -0
  78. /package/template/src/resources/{carousel-resource.json → carousel/carousel-resource.json} +0 -0
  79. /package/template/src/{components/carousel → resources/carousel/components}/card.test.tsx +0 -0
  80. /package/template/src/{components/carousel → resources/carousel/components}/carousel.test.tsx +0 -0
  81. /package/template/src/{components/carousel → resources/carousel/components}/index.ts +0 -0
  82. /package/template/src/{components/map → resources/map/components}/index.ts +0 -0
  83. /package/template/src/{components/map → resources/map/components}/map-view.test.tsx +0 -0
  84. /package/template/src/{components/map → resources/map/components}/place-card.test.tsx +0 -0
  85. /package/template/src/{components/map → resources/map/components}/place-carousel.test.tsx +0 -0
  86. /package/template/src/{components/map → resources/map/components}/place-inspector.test.tsx +0 -0
  87. /package/template/src/{components/map → resources/map/components}/place-list.test.tsx +0 -0
  88. /package/template/src/{components/map → resources/map/components}/types.ts +0 -0
  89. /package/template/src/resources/{map-resource.json → map/map-resource.json} +0 -0
  90. /package/template/src/resources/{review-resource.json → review/review-resource.json} +0 -0
  91. /package/template/src/resources/{review-resource.test.tsx → review/review-resource.test.tsx} +0 -0
  92. /package/template/src/resources/{review-resource.tsx → review/review-resource.tsx} +0 -0
@@ -7,115 +7,115 @@
7
7
  "react": {
8
8
  "src": "../../../../node_modules/.pnpm/react@19.2.3/node_modules/react/index.js",
9
9
  "file": "react.js",
10
- "fileHash": "5b44c43c",
10
+ "fileHash": "fb3e79b3",
11
11
  "needsInterop": true
12
12
  },
13
13
  "react-dom": {
14
14
  "src": "../../../../node_modules/.pnpm/react-dom@19.2.3_react@19.2.3/node_modules/react-dom/index.js",
15
15
  "file": "react-dom.js",
16
- "fileHash": "eb0f27ea",
16
+ "fileHash": "d6a664e5",
17
17
  "needsInterop": true
18
18
  },
19
19
  "react/jsx-dev-runtime": {
20
20
  "src": "../../../../node_modules/.pnpm/react@19.2.3/node_modules/react/jsx-dev-runtime.js",
21
21
  "file": "react_jsx-dev-runtime.js",
22
- "fileHash": "47864517",
22
+ "fileHash": "9e8e545b",
23
23
  "needsInterop": true
24
24
  },
25
25
  "react/jsx-runtime": {
26
26
  "src": "../../../../node_modules/.pnpm/react@19.2.3/node_modules/react/jsx-runtime.js",
27
27
  "file": "react_jsx-runtime.js",
28
- "fileHash": "56bb8d36",
28
+ "fileHash": "0c193a8a",
29
29
  "needsInterop": true
30
30
  },
31
31
  "@openai/apps-sdk-ui/components/Avatar": {
32
32
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.1_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._90324f97b7190ccfdbe40a9e8bef3385/node_modules/@openai/apps-sdk-ui/dist/es/components/Avatar/index.js",
33
33
  "file": "@openai_apps-sdk-ui_components_Avatar.js",
34
- "fileHash": "0228dba4",
34
+ "fileHash": "f9dfeee4",
35
35
  "needsInterop": false
36
36
  },
37
37
  "@openai/apps-sdk-ui/components/Button": {
38
38
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.1_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._90324f97b7190ccfdbe40a9e8bef3385/node_modules/@openai/apps-sdk-ui/dist/es/components/Button/index.js",
39
39
  "file": "@openai_apps-sdk-ui_components_Button.js",
40
- "fileHash": "666242ff",
40
+ "fileHash": "ba413346",
41
41
  "needsInterop": false
42
42
  },
43
43
  "@openai/apps-sdk-ui/components/Checkbox": {
44
44
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.1_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._90324f97b7190ccfdbe40a9e8bef3385/node_modules/@openai/apps-sdk-ui/dist/es/components/Checkbox/index.js",
45
45
  "file": "@openai_apps-sdk-ui_components_Checkbox.js",
46
- "fileHash": "5c9fd6a4",
46
+ "fileHash": "c1ffdf3d",
47
47
  "needsInterop": false
48
48
  },
49
49
  "@openai/apps-sdk-ui/components/Icon": {
50
50
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.1_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._90324f97b7190ccfdbe40a9e8bef3385/node_modules/@openai/apps-sdk-ui/dist/es/components/Icon/index.js",
51
51
  "file": "@openai_apps-sdk-ui_components_Icon.js",
52
- "fileHash": "a1dd50de",
52
+ "fileHash": "6e08ea68",
53
53
  "needsInterop": false
54
54
  },
55
55
  "@openai/apps-sdk-ui/components/Input": {
56
56
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.1_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._90324f97b7190ccfdbe40a9e8bef3385/node_modules/@openai/apps-sdk-ui/dist/es/components/Input/index.js",
57
57
  "file": "@openai_apps-sdk-ui_components_Input.js",
58
- "fileHash": "127cbf1c",
58
+ "fileHash": "03cf3a2d",
59
59
  "needsInterop": false
60
60
  },
61
61
  "@openai/apps-sdk-ui/components/SegmentedControl": {
62
62
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.1_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._90324f97b7190ccfdbe40a9e8bef3385/node_modules/@openai/apps-sdk-ui/dist/es/components/SegmentedControl/index.js",
63
63
  "file": "@openai_apps-sdk-ui_components_SegmentedControl.js",
64
- "fileHash": "64469fac",
64
+ "fileHash": "d534dd11",
65
65
  "needsInterop": false
66
66
  },
67
67
  "@openai/apps-sdk-ui/components/Select": {
68
68
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.1_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._90324f97b7190ccfdbe40a9e8bef3385/node_modules/@openai/apps-sdk-ui/dist/es/components/Select/index.js",
69
69
  "file": "@openai_apps-sdk-ui_components_Select.js",
70
- "fileHash": "fd54defb",
70
+ "fileHash": "dcb8661c",
71
71
  "needsInterop": false
72
72
  },
73
73
  "@openai/apps-sdk-ui/components/Textarea": {
74
74
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.1_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._90324f97b7190ccfdbe40a9e8bef3385/node_modules/@openai/apps-sdk-ui/dist/es/components/Textarea/index.js",
75
75
  "file": "@openai_apps-sdk-ui_components_Textarea.js",
76
- "fileHash": "5a05b879",
76
+ "fileHash": "94fda091",
77
77
  "needsInterop": false
78
78
  },
79
79
  "@openai/apps-sdk-ui/theme": {
80
80
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.1_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._90324f97b7190ccfdbe40a9e8bef3385/node_modules/@openai/apps-sdk-ui/dist/es/lib/theme.js",
81
81
  "file": "@openai_apps-sdk-ui_theme.js",
82
- "fileHash": "058ce1d0",
82
+ "fileHash": "8ff1f511",
83
83
  "needsInterop": false
84
84
  },
85
85
  "clsx": {
86
86
  "src": "../../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs",
87
87
  "file": "clsx.js",
88
- "fileHash": "1984836f",
88
+ "fileHash": "4d883f36",
89
89
  "needsInterop": false
90
90
  },
91
91
  "embla-carousel-react": {
92
92
  "src": "../../../../node_modules/.pnpm/embla-carousel-react@8.6.0_react@19.2.3/node_modules/embla-carousel-react/esm/embla-carousel-react.esm.js",
93
93
  "file": "embla-carousel-react.js",
94
- "fileHash": "b19b3602",
94
+ "fileHash": "111f3da3",
95
95
  "needsInterop": false
96
96
  },
97
97
  "embla-carousel-wheel-gestures": {
98
98
  "src": "../../../../node_modules/.pnpm/embla-carousel-wheel-gestures@8.1.0_embla-carousel@8.6.0/node_modules/embla-carousel-wheel-gestures/dist/embla-carousel-wheel-gestures.esm.js",
99
99
  "file": "embla-carousel-wheel-gestures.js",
100
- "fileHash": "60f6c493",
100
+ "fileHash": "efd9860f",
101
101
  "needsInterop": false
102
102
  },
103
103
  "mapbox-gl": {
104
104
  "src": "../../../../node_modules/.pnpm/mapbox-gl@3.17.0/node_modules/mapbox-gl/dist/mapbox-gl.js",
105
105
  "file": "mapbox-gl.js",
106
- "fileHash": "ce2fe792",
106
+ "fileHash": "f6794d9d",
107
107
  "needsInterop": true
108
108
  },
109
109
  "react-dom/client": {
110
110
  "src": "../../../../node_modules/.pnpm/react-dom@19.2.3_react@19.2.3/node_modules/react-dom/client.js",
111
111
  "file": "react-dom_client.js",
112
- "fileHash": "b8065239",
112
+ "fileHash": "fde7f647",
113
113
  "needsInterop": true
114
114
  },
115
115
  "tailwind-merge": {
116
116
  "src": "../../../../node_modules/.pnpm/tailwind-merge@3.4.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs",
117
117
  "file": "tailwind-merge.js",
118
- "fileHash": "ca0609d8",
118
+ "fileHash": "657d10b8",
119
119
  "needsInterop": false
120
120
  }
121
121
  },
@@ -123,15 +123,18 @@
123
123
  "chunk-2DZGWGIP": {
124
124
  "file": "chunk-2DZGWGIP.js"
125
125
  },
126
- "chunk-N6DVYEXK": {
127
- "file": "chunk-N6DVYEXK.js"
126
+ "chunk-LVZJNEGE": {
127
+ "file": "chunk-LVZJNEGE.js"
128
128
  },
129
- "chunk-JAGHY6H6": {
130
- "file": "chunk-JAGHY6H6.js"
129
+ "chunk-UM3ZGDFR": {
130
+ "file": "chunk-UM3ZGDFR.js"
131
131
  },
132
132
  "chunk-QPJAV452": {
133
133
  "file": "chunk-QPJAV452.js"
134
134
  },
135
+ "chunk-JAGHY6H6": {
136
+ "file": "chunk-JAGHY6H6.js"
137
+ },
135
138
  "chunk-DYQDWJMS": {
136
139
  "file": "chunk-DYQDWJMS.js"
137
140
  },
@@ -147,9 +150,6 @@
147
150
  "chunk-CNYJBM5F": {
148
151
  "file": "chunk-CNYJBM5F.js"
149
152
  },
150
- "chunk-UM3ZGDFR": {
151
- "file": "chunk-UM3ZGDFR.js"
152
- },
153
153
  "chunk-JGVISENQ": {
154
154
  "file": "chunk-JGVISENQ.js"
155
155
  },
@@ -1,9 +1,13 @@
1
1
  import {
2
- useTimeout
3
- } from "./chunk-JAGHY6H6.js";
2
+ Check_default,
3
+ Copy_default
4
+ } from "./chunk-UM3ZGDFR.js";
4
5
  import {
5
6
  o
6
7
  } from "./chunk-QPJAV452.js";
8
+ import {
9
+ useTimeout
10
+ } from "./chunk-JAGHY6H6.js";
7
11
  import {
8
12
  handlePressableMouseEnter,
9
13
  isDev,
@@ -18,10 +22,6 @@ import {
18
22
  import {
19
23
  clsx_default
20
24
  } from "./chunk-CNYJBM5F.js";
21
- import {
22
- Check_default,
23
- Copy_default
24
- } from "./chunk-UM3ZGDFR.js";
25
25
  import {
26
26
  require_jsx_runtime
27
27
  } from "./chunk-JGVISENQ.js";
@@ -625,4 +625,4 @@ export {
625
625
  ButtonLink,
626
626
  CopyButton
627
627
  };
628
- //# sourceMappingURL=chunk-N6DVYEXK.js.map
628
+ //# sourceMappingURL=chunk-LVZJNEGE.js.map
@@ -1 +1 @@
1
- {"version":"4.0.16","results":[[":src/resources/carousel-resource.test.tsx",{"duration":243.94740899999988,"failed":false}],[":src/resources/review-resource.test.tsx",{"duration":567.3163099999999,"failed":false}],[":src/components/album/albums.test.tsx",{"duration":313.3769259999999,"failed":false}],[":src/components/map/map-view.test.tsx",{"duration":77.97338500000001,"failed":false}],[":src/components/map/place-inspector.test.tsx",{"duration":428.7963219999997,"failed":false}],[":src/components/album/fullscreen-viewer.test.tsx",{"duration":242.1137319999998,"failed":false}],[":src/components/map/place-list.test.tsx",{"duration":126.20956799999976,"failed":false}],[":src/components/map/place-card.test.tsx",{"duration":348.28797099999974,"failed":false}],[":src/components/map/place-carousel.test.tsx",{"duration":430.4756219999997,"failed":false}],[":src/components/album/album-carousel.test.tsx",{"duration":88.96449000000007,"failed":false}],[":src/components/carousel/carousel.test.tsx",{"duration":87.16689200000019,"failed":false}],[":src/resources/map-resource.test.tsx",{"duration":273.31644100000017,"failed":false}],[":src/resources/albums-resource.test.tsx",{"duration":260.8579480000001,"failed":false}],[":src/components/album/film-strip.test.tsx",{"duration":447.70624799999973,"failed":false}],[":src/components/album/album-card.test.tsx",{"duration":340.815521,"failed":false}],[":src/components/carousel/card.test.tsx",{"duration":68.25215899999989,"failed":false}]]}
1
+ {"version":"4.0.16","results":[[":src/resources/review/review-resource.test.tsx",{"duration":530.608798,"failed":false}],[":src/resources/albums/components/albums.test.tsx",{"duration":348.1831809999999,"failed":false}],[":src/resources/carousel/carousel-resource.test.tsx",{"duration":272.94627400000013,"failed":false}],[":src/resources/map/components/map-view.test.tsx",{"duration":98.39371499999993,"failed":false}],[":src/resources/map/components/place-inspector.test.tsx",{"duration":417.9068080000002,"failed":false}],[":src/resources/albums/components/fullscreen-viewer.test.tsx",{"duration":274.64311,"failed":false}],[":src/resources/map/components/place-list.test.tsx",{"duration":130.8710030000002,"failed":false}],[":src/resources/map/components/place-card.test.tsx",{"duration":352.6335079999999,"failed":false}],[":src/resources/map/components/place-carousel.test.tsx",{"duration":393.43498999999997,"failed":false}],[":src/resources/albums/components/album-carousel.test.tsx",{"duration":90.04754600000001,"failed":false}],[":src/resources/carousel/components/carousel.test.tsx",{"duration":66.88647399999991,"failed":false}],[":src/resources/map/map-resource.test.tsx",{"duration":233.14745900000003,"failed":false}],[":src/resources/albums/albums-resource.test.tsx",{"duration":240.6847640000001,"failed":false}],[":src/resources/albums/components/film-strip.test.tsx",{"duration":466.9771660000001,"failed":false}],[":src/resources/albums/components/album-card.test.tsx",{"duration":293.65612699999974,"failed":false}],[":src/resources/carousel/components/card.test.tsx",{"duration":66.668365,"failed":false}]]}
@@ -12,7 +12,7 @@ vi.mock('sunpeak', () => ({
12
12
  }));
13
13
 
14
14
  // Mock Albums component
15
- vi.mock('../components/album/albums', () => ({
15
+ vi.mock('./components/albums', () => ({
16
16
  Albums: () => <div data-testid="albums-component">Albums Component</div>,
17
17
  }));
18
18
 
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { useSafeArea, useMaxHeight } from 'sunpeak';
3
- import { Albums } from '../components/album/albums';
3
+ import { Albums } from './components/albums';
4
4
 
5
5
  /**
6
6
  * Production-ready Albums Resource
@@ -0,0 +1,131 @@
1
+ {
2
+ "userMessage": "Pizza time",
3
+ "tool": {
4
+ "name": "show-albums",
5
+ "description": "Show photo albums",
6
+ "inputSchema": { "type": "object", "properties": {}, "additionalProperties": false },
7
+ "title": "Show Albums",
8
+ "annotations": { "readOnlyHint": true },
9
+ "_meta": {
10
+ "openai/toolInvocation/invoking": "Loading albums",
11
+ "openai/toolInvocation/invoked": "Album loaded",
12
+ "openai/widgetAccessible": true,
13
+ "openai/resultCanProduceWidget": true
14
+ }
15
+ },
16
+ "callToolResult": {
17
+ "structuredContent": {
18
+ "albums": [
19
+ {
20
+ "id": "summer-escape",
21
+ "title": "Summer Slice",
22
+ "cover": "https://persistent.oaistatic.com/pizzaz/pizzaz-1.png",
23
+ "photos": [
24
+ {
25
+ "id": "s1",
26
+ "title": "Waves",
27
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-2.png"
28
+ },
29
+ {
30
+ "id": "s2",
31
+ "title": "Palm trees",
32
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-3.png"
33
+ },
34
+ {
35
+ "id": "s3",
36
+ "title": "Sunset",
37
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-6.png"
38
+ }
39
+ ]
40
+ },
41
+ {
42
+ "id": "city-lights",
43
+ "title": "Pepperoni Nights",
44
+ "cover": "https://persistent.oaistatic.com/pizzaz/pizzaz-4.png",
45
+ "photos": [
46
+ {
47
+ "id": "c1",
48
+ "title": "Downtown",
49
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-5.png"
50
+ },
51
+ {
52
+ "id": "c2",
53
+ "title": "Neon",
54
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-1.png"
55
+ },
56
+ {
57
+ "id": "c3",
58
+ "title": "Streets",
59
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-2.png"
60
+ }
61
+ ]
62
+ },
63
+ {
64
+ "id": "into-the-woods",
65
+ "title": "Truffle Forest",
66
+ "cover": "https://persistent.oaistatic.com/pizzaz/pizzaz-3.png",
67
+ "photos": [
68
+ {
69
+ "id": "n1",
70
+ "title": "Forest path",
71
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-6.png"
72
+ },
73
+ {
74
+ "id": "n2",
75
+ "title": "Misty",
76
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-4.png"
77
+ },
78
+ {
79
+ "id": "n3",
80
+ "title": "Waterfall",
81
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-5.png"
82
+ }
83
+ ]
84
+ },
85
+ {
86
+ "id": "pizza-tour",
87
+ "title": "Pizza tour",
88
+ "cover": "https://persistent.oaistatic.com/pizzaz/pizzaz-1.png",
89
+ "photos": [
90
+ {
91
+ "id": "tonys-pizza-napoletana",
92
+ "title": "Tony's Pizza Napoletana",
93
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-2.png"
94
+ },
95
+ {
96
+ "id": "golden-boy-pizza",
97
+ "title": "Golden Boy Pizza",
98
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-3.png"
99
+ },
100
+ {
101
+ "id": "pizzeria-delfina-mission",
102
+ "title": "Pizzeria Delfina (Mission)",
103
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-6.png"
104
+ },
105
+ {
106
+ "id": "ragazza",
107
+ "title": "Ragazza",
108
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-4.png"
109
+ },
110
+ {
111
+ "id": "del-popolo",
112
+ "title": "Del Popolo",
113
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-5.png"
114
+ },
115
+ {
116
+ "id": "square-pie-guys",
117
+ "title": "Square Pie Guys",
118
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-1.png"
119
+ },
120
+ {
121
+ "id": "zero-zero",
122
+ "title": "Zero Zero",
123
+ "url": "https://persistent.oaistatic.com/pizzaz/pizzaz-2.png"
124
+ }
125
+ ]
126
+ }
127
+ ]
128
+ },
129
+ "_meta": {}
130
+ }
131
+ }
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { Button } from '@openai/apps-sdk-ui/components/Button';
3
- import { cn } from '../../lib/index';
3
+ import { cn } from '../../../lib/index';
4
4
  import type { Album } from './albums';
5
5
 
6
6
  export type AlbumCardProps = {
@@ -4,7 +4,7 @@ import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures';
4
4
  import { ArrowLeft, ArrowRight } from '@openai/apps-sdk-ui/components/Icon';
5
5
  import { useWidgetState, useDisplayMode } from 'sunpeak';
6
6
  import { Button } from '@openai/apps-sdk-ui/components/Button';
7
- import { cn } from '../../lib/index';
7
+ import { cn } from '../../../lib/index';
8
8
 
9
9
  export interface AlbumCarouselState extends Record<string, unknown> {
10
10
  currentIndex?: number;
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { Button } from '@openai/apps-sdk-ui/components/Button';
3
- import { cn } from '../../lib/index';
3
+ import { cn } from '../../../lib/index';
4
4
  import type { Album } from './albums';
5
5
 
6
6
  export type FilmStripProps = {
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { useSafeArea } from 'sunpeak';
3
- import { cn } from '../../lib/index';
3
+ import { cn } from '../../../lib/index';
4
4
  import { FilmStrip } from './film-strip';
5
5
  import type { Album } from './albums';
6
6
 
@@ -32,7 +32,7 @@ vi.mock('sunpeak', () => ({
32
32
  }));
33
33
 
34
34
  // Mock child components
35
- vi.mock('../components/carousel', () => ({
35
+ vi.mock('./components', () => ({
36
36
  Carousel: ({ children }: { children: React.ReactNode }) => (
37
37
  <div data-testid="carousel">{children}</div>
38
38
  ),
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { useWidgetProps, useSafeArea, useMaxHeight, useUserAgent } from 'sunpeak';
3
- import { Carousel, Card } from '../components/carousel';
3
+ import { Carousel, Card } from './components';
4
4
 
5
5
  /**
6
6
  * Production-ready Carousel Resource
@@ -0,0 +1,68 @@
1
+ {
2
+ "userMessage": "Show me popular places to visit in Austin Texas",
3
+ "tool": {
4
+ "name": "show-carousel",
5
+ "description": "Show popular places to visit",
6
+ "inputSchema": { "type": "object", "properties": {}, "additionalProperties": false },
7
+ "title": "Show Carousel",
8
+ "annotations": { "readOnlyHint": true },
9
+ "_meta": {
10
+ "openai/toolInvocation/invoking": "Loading carousel",
11
+ "openai/toolInvocation/invoked": "Carousel loaded",
12
+ "openai/widgetAccessible": true,
13
+ "openai/resultCanProduceWidget": true
14
+ }
15
+ },
16
+ "callToolResult": {
17
+ "structuredContent": {
18
+ "places": [
19
+ {
20
+ "id": "1",
21
+ "name": "Lady Bird Lake",
22
+ "rating": 4.5,
23
+ "category": "Waterfront",
24
+ "location": "Austin",
25
+ "image": "https://images.unsplash.com/photo-1520950237264-dfe336995c34?w=400&h=400&fit=crop",
26
+ "description": "Scenic lake perfect for kayaking, paddleboarding, and trails."
27
+ },
28
+ {
29
+ "id": "2",
30
+ "name": "Texas State Capitol",
31
+ "rating": 4.8,
32
+ "category": "Historic Site",
33
+ "location": "Austin",
34
+ "image": "https://images.unsplash.com/photo-1664231978322-4d0b45c7027b?w=400&h=400&fit=crop",
35
+ "description": "Stunning capitol building with free tours and beautiful grounds."
36
+ },
37
+ {
38
+ "id": "3",
39
+ "name": "The Paramount Theatre",
40
+ "rating": 4.7,
41
+ "category": "Architecture",
42
+ "location": "Austin",
43
+ "image": "https://images.unsplash.com/photo-1583097090970-4d3b940ea1a0?w=400&h=400&fit=crop",
44
+ "description": "Century-old performance and movie theatre in the heart of downtown Austin."
45
+ },
46
+ {
47
+ "id": "4",
48
+ "name": "Zilker Park",
49
+ "rating": 4.7,
50
+ "category": "Park",
51
+ "location": "Austin",
52
+ "image": "https://images.unsplash.com/photo-1563828568124-f800803ba13c?w=400&h=400&fit=crop",
53
+ "description": "Popular park with trails, sports fields, and Barton Springs Pool."
54
+ },
55
+ {
56
+ "id": "5",
57
+ "name": "South Congress Avenue",
58
+ "rating": 4.6,
59
+ "category": "Landmark",
60
+ "location": "Austin",
61
+ "image": "https://images.unsplash.com/photo-1588993608283-7f0eda4438be?w=400&h=400&fit=crop",
62
+ "description": "Vibrant street with unique shops, restaurants, and live music."
63
+ }
64
+ ]
65
+ },
66
+ "_meta": {}
67
+ }
68
+ }
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { Button } from '@openai/apps-sdk-ui/components/Button';
3
- import { cn } from '../../lib/index';
3
+ import { cn } from '../../../lib/index';
4
4
 
5
5
  export interface CardButtonProps {
6
6
  isPrimary?: boolean;
@@ -4,7 +4,7 @@ import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures';
4
4
  import { ArrowLeft, ArrowRight } from '@openai/apps-sdk-ui/components/Icon';
5
5
  import { useWidgetState, useDisplayMode } from 'sunpeak';
6
6
  import { Button } from '@openai/apps-sdk-ui/components/Button';
7
- import { cn } from '../../lib/index';
7
+ import { cn } from '../../../lib/index';
8
8
 
9
9
  export interface CarouselState extends Record<string, unknown> {
10
10
  currentIndex?: number;
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * Auto-discovers and re-exports all resource components.
3
3
  *
4
- * Discovers all *-resource.tsx files and exports their component
5
- * with a PascalCase name (e.g., review-resource.tsx -> ReviewResource).
4
+ * Discovers all {resource}/{resource}-resource.tsx files and exports their component
5
+ * with a PascalCase name (e.g., albums/albums-resource.tsx -> AlbumsResource).
6
6
  *
7
7
  * Supports both export styles:
8
8
  * - Default export: export default MyComponent
9
- * - Named export: export const ReviewResource = ...
9
+ * - Named export: export const AlbumsResource = ...
10
10
  */
11
11
  import { createResourceExports } from 'sunpeak';
12
12
 
13
- // Auto-discover all resource component files
14
- const resourceModules = import.meta.glob('./*-resource.tsx', { eager: true });
13
+ // Auto-discover all resource component files in subdirectories
14
+ const resourceModules = import.meta.glob('./*/*-resource.tsx', { eager: true });
15
15
 
16
16
  // Build exports object from discovered files using library helper
17
17
  export default createResourceExports(resourceModules);
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
  import mapboxgl from 'mapbox-gl';
3
3
  import 'mapbox-gl/dist/mapbox-gl.css';
4
4
  import { useMaxHeight } from 'sunpeak';
5
- import { cn } from '../../lib/index';
5
+ import { cn } from '../../../lib/index';
6
6
  import type { Place } from './types';
7
7
 
8
8
  // Public Mapbox token for demo purposes
@@ -8,7 +8,7 @@ import {
8
8
  } from 'sunpeak';
9
9
  import { Button } from '@openai/apps-sdk-ui/components/Button';
10
10
  import { ExpandLg } from '@openai/apps-sdk-ui/components/Icon';
11
- import { cn } from '../../lib/index';
11
+ import { cn } from '../../../lib/index';
12
12
  import { PlaceList } from './place-list';
13
13
  import { PlaceCarousel } from './place-carousel';
14
14
  import { PlaceInspector } from './place-inspector';
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { Star } from '@openai/apps-sdk-ui/components/Icon';
3
- import { cn } from '../../lib/index';
3
+ import { cn } from '../../../lib/index';
4
4
  import type { Place } from './types';
5
5
 
6
6
  export type PlaceCardProps = {
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import useEmblaCarousel from 'embla-carousel-react';
3
- import { cn } from '../../lib/index';
3
+ import { cn } from '../../../lib/index';
4
4
  import { PlaceCard } from './place-card';
5
5
  import type { Place } from './types';
6
6
 
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
  import { Button } from '@openai/apps-sdk-ui/components/Button';
3
3
  import { Avatar } from '@openai/apps-sdk-ui/components/Avatar';
4
4
  import { X, Star } from '@openai/apps-sdk-ui/components/Icon';
5
- import { cn } from '../../lib/index';
5
+ import { cn } from '../../../lib/index';
6
6
  import type { Place } from './types';
7
7
 
8
8
  export type PlaceInspectorProps = {
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { Settings } from '@openai/apps-sdk-ui/components/Icon';
3
- import { cn } from '../../lib/index';
3
+ import { cn } from '../../../lib/index';
4
4
  import { PlaceCard } from './place-card';
5
5
  import type { Place } from './types';
6
6
 
@@ -15,7 +15,7 @@ vi.mock('sunpeak', () => ({
15
15
  }));
16
16
 
17
17
  // Mock the Map component
18
- vi.mock('../components/map/map', () => ({
18
+ vi.mock('./components/map', () => ({
19
19
  Map: () => <div data-testid="map">Map Component</div>,
20
20
  }));
21
21
 
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { useSafeArea, useMaxHeight } from 'sunpeak';
3
- import { Map } from '../components/map/map';
3
+ import { Map } from './components/map';
4
4
 
5
5
  /**
6
6
  * Production-ready Map Resource