sunpeak 0.5.18 → 0.5.20

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.
@@ -7,12 +7,52 @@ For an initial overview of your new app and the sunpeak API, refer to the [docum
7
7
  ## Quickstart
8
8
 
9
9
  ```bash
10
- pnpm dev
10
+ # Install the sunpeak CLI (if not already installed)
11
+ pnpm add -g sunpeak
12
+
13
+ # Install project dependencies
14
+ pnpm install
15
+
16
+ # Start development server
17
+ sunpeak dev
11
18
  ```
12
19
 
20
+ Alternatively, use `pnpm dlx sunpeak dev` if you prefer not to install globally.
21
+
13
22
  Edit the resource files in [./src/components/resources/](./src/components/resources/) to build your resource UI.
14
23
 
15
- ## Development
24
+ ## CLI Commands
25
+
26
+ The `sunpeak` CLI provides convenient commands for common tasks:
27
+
28
+ ```bash
29
+ sunpeak dev # Start development server (vite)
30
+ sunpeak build # Build all resources for production
31
+ sunpeak mcp # Run MCP server with auto-reload
32
+ sunpeak validate # Run full validation suite
33
+ sunpeak test # Run tests
34
+ sunpeak typecheck # Run TypeScript checks
35
+ sunpeak lint # Run linting
36
+ sunpeak format # Format code
37
+ ```
38
+
39
+ ### Customization
40
+
41
+ **You can customize:**
42
+
43
+ - Package.json scripts (format, lint, typecheck, test are optional)
44
+ - Tooling configuration (ESLint, Prettier, TypeScript, Vite dev server)
45
+ - Component structure within `src/components/`
46
+ - Package manager (pnpm, npm, or yarn auto-detected)
47
+
48
+ **Do not customize (required by `sunpeak build`):**
49
+
50
+ - `src/components/resources/` - Resource files must be here
51
+ - `src/index-resource.tsx` - Build template (must have `// RESOURCE_IMPORT` and `// RESOURCE_MOUNT` comments)
52
+ - `vite.config.build.ts` - Build configuration
53
+ - Resource file naming: `*-resource.tsx` (e.g., `counter-resource.tsx`)
54
+
55
+ If you need to customize these paths, create a custom build script in package.json instead of using `sunpeak build`.
16
56
 
17
57
  ## Testing
18
58
 
@@ -21,7 +61,7 @@ Edit the resource files in [./src/components/resources/](./src/components/resour
21
61
  Run all the checks with the following:
22
62
 
23
63
  ```bash
24
- pnpm validate
64
+ sunpeak validate
25
65
  ```
26
66
 
27
67
  This will:
@@ -33,7 +73,7 @@ This will:
33
73
  For manual QA of the UI, run:
34
74
 
35
75
  ```bash
36
- pnpm dev
76
+ sunpeak dev
37
77
  ```
38
78
 
39
79
  ### Testing in ChatGPT
@@ -42,7 +82,7 @@ Test your app directly in ChatGPT using the built-in MCP server:
42
82
 
43
83
  ```bash
44
84
  # Start the MCP server (rebuilds and restarts on file changes).
45
- pnpm mcp
85
+ sunpeak mcp
46
86
 
47
87
  # In another terminal, run a tunnel. For example:
48
88
  ngrok http 6766
@@ -59,13 +99,17 @@ When you make changes to the UI, refresh your app in ChatGPT after the MCP serve
59
99
  Build your app for production:
60
100
 
61
101
  ```bash
62
- pnpm build
102
+ sunpeak build
63
103
  ```
64
104
 
65
- This creates optimized builds in the `dist/` directory:
105
+ This creates optimized builds in `dist/chatgpt/`:
106
+
107
+ - `dist/chatgpt/counter.js`
108
+ - `dist/chatgpt/albums.js`
109
+ - `dist/chatgpt/carousel.js`
110
+ - _(One .js file per resource in src/components/resources/)_
66
111
 
67
- - `dist/chatgpt/index.js` - ChatGPT iframe component
68
- - Host this file somewhere and reference it as a resource in your production MCP server.
112
+ Each file is a self-contained bundle with CSS inlined. Host these files and reference them as resources in your production MCP server.
69
113
 
70
114
  ## Resources
71
115
 
@@ -2,11 +2,11 @@ import {
2
2
  Button,
3
3
  ButtonLink,
4
4
  CopyButton
5
- } from "./chunk-675LFNY2.js";
6
- import "./chunk-QPJAV452.js";
7
- import "./chunk-XB525PXG.js";
5
+ } from "./chunk-EVJ3DVH5.js";
8
6
  import "./chunk-YOJ6QPGS.js";
9
7
  import "./chunk-BAG6OO6S.js";
8
+ import "./chunk-XB525PXG.js";
9
+ import "./chunk-QPJAV452.js";
10
10
  import "./chunk-EGRHWZRV.js";
11
11
  import "./chunk-CNYJBM5F.js";
12
12
  import "./chunk-PTVT3RFX.js";
@@ -5,11 +5,11 @@ import {
5
5
  handlePressableMouseEnter,
6
6
  waitForAnimationFrame
7
7
  } from "./chunk-BAG6OO6S.js";
8
- import "./chunk-EGRHWZRV.js";
9
8
  import {
10
9
  dist_exports4 as dist_exports
11
10
  } from "./chunk-SGWD4VEU.js";
12
11
  import "./chunk-KFGKZMLK.js";
12
+ import "./chunk-EGRHWZRV.js";
13
13
  import {
14
14
  clsx_default
15
15
  } from "./chunk-CNYJBM5F.js";
@@ -1,22 +1,8 @@
1
- import {
2
- Input
3
- } from "./chunk-CQ3GYAYB.js";
4
1
  import {
5
2
  Button,
6
3
  LoadingIndicator,
7
4
  TransitionGroup
8
- } from "./chunk-675LFNY2.js";
9
- import {
10
- o
11
- } from "./chunk-QPJAV452.js";
12
- import {
13
- Check_default,
14
- ChevronDownVector_default,
15
- DropdownVector_default,
16
- Info_default,
17
- Search_default,
18
- X_default
19
- } from "./chunk-XB525PXG.js";
5
+ } from "./chunk-EVJ3DVH5.js";
20
6
  import {
21
7
  useTimeout
22
8
  } from "./chunk-YOJ6QPGS.js";
@@ -26,13 +12,27 @@ import {
26
12
  toCssVariables,
27
13
  waitForAnimationFrame
28
14
  } from "./chunk-BAG6OO6S.js";
29
- import "./chunk-EGRHWZRV.js";
30
15
  import {
31
16
  dist_exports,
32
17
  dist_exports3 as dist_exports2,
33
18
  dist_exports5 as dist_exports3
34
19
  } from "./chunk-SGWD4VEU.js";
35
20
  import "./chunk-KFGKZMLK.js";
21
+ import {
22
+ Check_default,
23
+ ChevronDownVector_default,
24
+ DropdownVector_default,
25
+ Info_default,
26
+ Search_default,
27
+ X_default
28
+ } from "./chunk-XB525PXG.js";
29
+ import {
30
+ Input
31
+ } from "./chunk-CQ3GYAYB.js";
32
+ import {
33
+ o
34
+ } from "./chunk-QPJAV452.js";
35
+ import "./chunk-EGRHWZRV.js";
36
36
  import {
37
37
  clsx_default
38
38
  } from "./chunk-CNYJBM5F.js";
@@ -1,9 +1,9 @@
1
- import {
2
- o
3
- } from "./chunk-QPJAV452.js";
4
1
  import {
5
2
  toCssVariables
6
3
  } from "./chunk-BAG6OO6S.js";
4
+ import {
5
+ o
6
+ } from "./chunk-QPJAV452.js";
7
7
  import "./chunk-EGRHWZRV.js";
8
8
  import {
9
9
  clsx_default
@@ -7,118 +7,109 @@
7
7
  "react": {
8
8
  "src": "../../../../node_modules/.pnpm/react@19.2.0/node_modules/react/index.js",
9
9
  "file": "react.js",
10
- "fileHash": "06cf141e",
10
+ "fileHash": "e2577cb9",
11
11
  "needsInterop": true
12
12
  },
13
13
  "react-dom": {
14
14
  "src": "../../../../node_modules/.pnpm/react-dom@19.2.0_react@19.2.0/node_modules/react-dom/index.js",
15
15
  "file": "react-dom.js",
16
- "fileHash": "0cf14ea0",
16
+ "fileHash": "38503a63",
17
17
  "needsInterop": true
18
18
  },
19
19
  "react/jsx-dev-runtime": {
20
20
  "src": "../../../../node_modules/.pnpm/react@19.2.0/node_modules/react/jsx-dev-runtime.js",
21
21
  "file": "react_jsx-dev-runtime.js",
22
- "fileHash": "6bb19c1a",
22
+ "fileHash": "7c996318",
23
23
  "needsInterop": true
24
24
  },
25
25
  "react/jsx-runtime": {
26
26
  "src": "../../../../node_modules/.pnpm/react@19.2.0/node_modules/react/jsx-runtime.js",
27
27
  "file": "react_jsx-runtime.js",
28
- "fileHash": "8273a91e",
28
+ "fileHash": "aec1b650",
29
29
  "needsInterop": true
30
30
  },
31
31
  "@openai/apps-sdk-ui/components/Button": {
32
32
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.0_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._60630c8dcc43ec213b3e346c9e26579b/node_modules/@openai/apps-sdk-ui/dist/es/components/Button/index.js",
33
33
  "file": "@openai_apps-sdk-ui_components_Button.js",
34
- "fileHash": "767cbffa",
34
+ "fileHash": "dace3d9f",
35
35
  "needsInterop": false
36
36
  },
37
37
  "@openai/apps-sdk-ui/components/Checkbox": {
38
38
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.0_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._60630c8dcc43ec213b3e346c9e26579b/node_modules/@openai/apps-sdk-ui/dist/es/components/Checkbox/index.js",
39
39
  "file": "@openai_apps-sdk-ui_components_Checkbox.js",
40
- "fileHash": "82589bf3",
40
+ "fileHash": "b32818ca",
41
41
  "needsInterop": false
42
42
  },
43
43
  "@openai/apps-sdk-ui/components/Icon": {
44
44
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.0_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._60630c8dcc43ec213b3e346c9e26579b/node_modules/@openai/apps-sdk-ui/dist/es/components/Icon/index.js",
45
45
  "file": "@openai_apps-sdk-ui_components_Icon.js",
46
- "fileHash": "d70180a9",
46
+ "fileHash": "3a63771d",
47
47
  "needsInterop": false
48
48
  },
49
49
  "@openai/apps-sdk-ui/components/Input": {
50
50
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.0_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._60630c8dcc43ec213b3e346c9e26579b/node_modules/@openai/apps-sdk-ui/dist/es/components/Input/index.js",
51
51
  "file": "@openai_apps-sdk-ui_components_Input.js",
52
- "fileHash": "fcb03085",
52
+ "fileHash": "c4f2373d",
53
53
  "needsInterop": false
54
54
  },
55
55
  "@openai/apps-sdk-ui/components/SegmentedControl": {
56
56
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.0_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._60630c8dcc43ec213b3e346c9e26579b/node_modules/@openai/apps-sdk-ui/dist/es/components/SegmentedControl/index.js",
57
57
  "file": "@openai_apps-sdk-ui_components_SegmentedControl.js",
58
- "fileHash": "b497e6e1",
58
+ "fileHash": "9f29258f",
59
59
  "needsInterop": false
60
60
  },
61
61
  "@openai/apps-sdk-ui/components/Select": {
62
62
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.0_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._60630c8dcc43ec213b3e346c9e26579b/node_modules/@openai/apps-sdk-ui/dist/es/components/Select/index.js",
63
63
  "file": "@openai_apps-sdk-ui_components_Select.js",
64
- "fileHash": "b9c31b46",
64
+ "fileHash": "ba414e88",
65
65
  "needsInterop": false
66
66
  },
67
67
  "@openai/apps-sdk-ui/components/Textarea": {
68
68
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.0_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._60630c8dcc43ec213b3e346c9e26579b/node_modules/@openai/apps-sdk-ui/dist/es/components/Textarea/index.js",
69
69
  "file": "@openai_apps-sdk-ui_components_Textarea.js",
70
- "fileHash": "cb2b489f",
70
+ "fileHash": "fc2482f4",
71
71
  "needsInterop": false
72
72
  },
73
73
  "@openai/apps-sdk-ui/theme": {
74
74
  "src": "../../../../node_modules/.pnpm/@openai+apps-sdk-ui@0.2.0_@types+react-dom@19.2.3_@types+react@19.2.7__@types+react@19._60630c8dcc43ec213b3e346c9e26579b/node_modules/@openai/apps-sdk-ui/dist/es/lib/theme.js",
75
75
  "file": "@openai_apps-sdk-ui_theme.js",
76
- "fileHash": "9d5ce0a8",
76
+ "fileHash": "3444fac3",
77
77
  "needsInterop": false
78
78
  },
79
79
  "clsx": {
80
80
  "src": "../../../../node_modules/.pnpm/clsx@2.1.1/node_modules/clsx/dist/clsx.mjs",
81
81
  "file": "clsx.js",
82
- "fileHash": "339f1acb",
82
+ "fileHash": "9e11e752",
83
83
  "needsInterop": false
84
84
  },
85
85
  "embla-carousel-react": {
86
86
  "src": "../../../../node_modules/.pnpm/embla-carousel-react@8.6.0_react@19.2.0/node_modules/embla-carousel-react/esm/embla-carousel-react.esm.js",
87
87
  "file": "embla-carousel-react.js",
88
- "fileHash": "72884b0a",
88
+ "fileHash": "8184dc6a",
89
89
  "needsInterop": false
90
90
  },
91
91
  "embla-carousel-wheel-gestures": {
92
92
  "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",
93
93
  "file": "embla-carousel-wheel-gestures.js",
94
- "fileHash": "68b0935d",
94
+ "fileHash": "b00dfc62",
95
95
  "needsInterop": false
96
96
  },
97
97
  "react-dom/client": {
98
98
  "src": "../../../../node_modules/.pnpm/react-dom@19.2.0_react@19.2.0/node_modules/react-dom/client.js",
99
99
  "file": "react-dom_client.js",
100
- "fileHash": "cbf4ff1e",
100
+ "fileHash": "7b740e30",
101
101
  "needsInterop": true
102
102
  },
103
103
  "tailwind-merge": {
104
104
  "src": "../../../../node_modules/.pnpm/tailwind-merge@3.4.0/node_modules/tailwind-merge/dist/bundle-mjs.mjs",
105
105
  "file": "tailwind-merge.js",
106
- "fileHash": "5e9a0e0e",
106
+ "fileHash": "f131803a",
107
107
  "needsInterop": false
108
108
  }
109
109
  },
110
110
  "chunks": {
111
- "chunk-CQ3GYAYB": {
112
- "file": "chunk-CQ3GYAYB.js"
113
- },
114
- "chunk-675LFNY2": {
115
- "file": "chunk-675LFNY2.js"
116
- },
117
- "chunk-QPJAV452": {
118
- "file": "chunk-QPJAV452.js"
119
- },
120
- "chunk-XB525PXG": {
121
- "file": "chunk-XB525PXG.js"
111
+ "chunk-EVJ3DVH5": {
112
+ "file": "chunk-EVJ3DVH5.js"
122
113
  },
123
114
  "chunk-YOJ6QPGS": {
124
115
  "file": "chunk-YOJ6QPGS.js"
@@ -126,15 +117,24 @@
126
117
  "chunk-BAG6OO6S": {
127
118
  "file": "chunk-BAG6OO6S.js"
128
119
  },
129
- "chunk-EGRHWZRV": {
130
- "file": "chunk-EGRHWZRV.js"
131
- },
132
120
  "chunk-SGWD4VEU": {
133
121
  "file": "chunk-SGWD4VEU.js"
134
122
  },
135
123
  "chunk-KFGKZMLK": {
136
124
  "file": "chunk-KFGKZMLK.js"
137
125
  },
126
+ "chunk-XB525PXG": {
127
+ "file": "chunk-XB525PXG.js"
128
+ },
129
+ "chunk-CQ3GYAYB": {
130
+ "file": "chunk-CQ3GYAYB.js"
131
+ },
132
+ "chunk-QPJAV452": {
133
+ "file": "chunk-QPJAV452.js"
134
+ },
135
+ "chunk-EGRHWZRV": {
136
+ "file": "chunk-EGRHWZRV.js"
137
+ },
138
138
  "chunk-CNYJBM5F": {
139
139
  "file": "chunk-CNYJBM5F.js"
140
140
  },
@@ -1,10 +1,3 @@
1
- import {
2
- o
3
- } from "./chunk-QPJAV452.js";
4
- import {
5
- Check_default,
6
- Copy_default
7
- } from "./chunk-XB525PXG.js";
8
1
  import {
9
2
  useTimeout
10
3
  } from "./chunk-YOJ6QPGS.js";
@@ -19,6 +12,13 @@ import {
19
12
  toTransformProperty,
20
13
  waitForAnimationFrame
21
14
  } from "./chunk-BAG6OO6S.js";
15
+ import {
16
+ Check_default,
17
+ Copy_default
18
+ } from "./chunk-XB525PXG.js";
19
+ import {
20
+ o
21
+ } from "./chunk-QPJAV452.js";
22
22
  import {
23
23
  clsx_default
24
24
  } from "./chunk-CNYJBM5F.js";
@@ -625,4 +625,4 @@ export {
625
625
  ButtonLink,
626
626
  CopyButton
627
627
  };
628
- //# sourceMappingURL=chunk-675LFNY2.js.map
628
+ //# sourceMappingURL=chunk-EVJ3DVH5.js.map
@@ -1 +1 @@
1
- {"version":"4.0.13","results":[[":src/components/album/albums.test.tsx",{"duration":345.1719760000001,"failed":false}],[":src/components/resources/carousel-resource.test.tsx",{"duration":259.7773770000001,"failed":false}],[":src/components/album/fullscreen-viewer.test.tsx",{"duration":239.07196999999996,"failed":false}],[":src/components/resources/counter-resource.test.tsx",{"duration":366.42872199999965,"failed":false}],[":src/components/carousel/carousel.test.tsx",{"duration":89.68212499999981,"failed":false}],[":src/components/resources/albums-resource.test.tsx",{"duration":276.13348199999996,"failed":false}],[":src/components/album/film-strip.test.tsx",{"duration":516.9409169999999,"failed":false}],[":src/components/album/album-card.test.tsx",{"duration":313.33463800000004,"failed":false}],[":src/components/card/card.test.tsx",{"duration":58.67706799999996,"failed":false}]]}
1
+ {"version":"4.0.13","results":[[":src/components/album/fullscreen-viewer.test.tsx",{"duration":247.92236500000035,"failed":false}],[":src/components/resources/carousel-resource.test.tsx",{"duration":291.96899399999984,"failed":false}],[":src/components/album/albums.test.tsx",{"duration":372.5832929999999,"failed":false}],[":src/components/carousel/carousel.test.tsx",{"duration":75.39571799999976,"failed":false}],[":src/components/resources/counter-resource.test.tsx",{"duration":325.86149399999977,"failed":false}],[":src/components/resources/albums-resource.test.tsx",{"duration":262.963896,"failed":false}],[":src/components/album/album-card.test.tsx",{"duration":342.73505,"failed":false}],[":src/components/album/film-strip.test.tsx",{"duration":404.68787,"failed":false}],[":src/components/card/card.test.tsx",{"duration":54.20477299999993,"failed":false}]]}
@@ -4,7 +4,7 @@
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
- "build": "node scripts/build-all.mjs",
7
+ "build": "sunpeak build",
8
8
  "dev": "vite --port ${PORT:-6767}",
9
9
  "format": "prettier --write --list-different \"**/*.{ts,tsx,js,jsx,json,md}\"",
10
10
  "mcp": "nodemon",
@@ -12,7 +12,7 @@
12
12
  "lint": "eslint . --ext .ts,.tsx --fix",
13
13
  "typecheck": "tsc --noEmit",
14
14
  "test": "vitest run",
15
- "validate": "node scripts/validate.mjs"
15
+ "validate": "sunpeak validate"
16
16
  },
17
17
  "dependencies": {
18
18
  "@openai/apps-sdk-ui": "^0.2.0",
@@ -1,117 +0,0 @@
1
- #!/usr/bin/env node
2
- import { execSync } from 'child_process';
3
- import { existsSync, rmSync, readdirSync, readFileSync, writeFileSync, mkdirSync, copyFileSync } from 'fs';
4
- import path from 'path';
5
- import { fileURLToPath } from 'url';
6
-
7
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
- const distDir = path.join(__dirname, '../dist/chatgpt');
9
- const buildDir = path.join(__dirname, '../dist/build-output');
10
- const tempDir = path.join(__dirname, '../.tmp');
11
- const resourcesDir = path.join(__dirname, '../src/components/resources');
12
- const templateFile = path.join(__dirname, '../src/index-resource.tsx');
13
-
14
- // Clean dist and temp directories
15
- if (existsSync(distDir)) {
16
- rmSync(distDir, { recursive: true });
17
- }
18
- if (existsSync(tempDir)) {
19
- rmSync(tempDir, { recursive: true });
20
- }
21
- mkdirSync(distDir, { recursive: true });
22
- mkdirSync(tempDir, { recursive: true });
23
-
24
- // Auto-discover all resources
25
- const resourceFiles = readdirSync(resourcesDir)
26
- .filter(file => file.endsWith('-resource.tsx'))
27
- .map(file => {
28
- // Extract kebab-case name: 'counter-resource.tsx' -> 'counter'
29
- const kebabName = file.replace('-resource.tsx', '');
30
-
31
- // Convert kebab-case to PascalCase: 'counter' -> 'Counter', 'my-widget' -> 'MyWidget'
32
- const pascalName = kebabName
33
- .split('-')
34
- .map(word => word.charAt(0).toUpperCase() + word.slice(1))
35
- .join('');
36
-
37
- return {
38
- componentName: `${pascalName}Resource`,
39
- componentFile: file.replace('.tsx', ''),
40
- entry: `.tmp/index-${kebabName}.tsx`,
41
- output: `${kebabName}.js`,
42
- buildOutDir: path.join(buildDir, kebabName),
43
- };
44
- });
45
-
46
- console.log('Building all resources...\n');
47
-
48
- // Read the template
49
- const template = readFileSync(templateFile, 'utf-8');
50
-
51
- // Build all resources (but don't copy yet)
52
- resourceFiles.forEach(({ componentName, componentFile, entry, output, buildOutDir }, index) => {
53
- console.log(`[${index + 1}/${resourceFiles.length}] Building ${output}...`);
54
-
55
- try {
56
- // Create build directory if it doesn't exist
57
- if (!existsSync(buildOutDir)) {
58
- mkdirSync(buildOutDir, { recursive: true });
59
- }
60
-
61
- // Create entry file from template in temp directory
62
- const entryContent = template
63
- .replace('// RESOURCE_IMPORT', `import { ${componentName} } from '../src/components/resources/${componentFile}';`)
64
- .replace('// RESOURCE_MOUNT', `createRoot(root).render(<${componentName} />);`);
65
-
66
- const entryPath = path.join(__dirname, '..', entry);
67
- writeFileSync(entryPath, entryContent);
68
-
69
- // Build with vite to build directory
70
- execSync(
71
- `vite build --config vite.config.build.ts`,
72
- {
73
- stdio: 'inherit',
74
- env: {
75
- ...process.env,
76
- ENTRY_FILE: entry,
77
- OUTPUT_FILE: output,
78
- OUT_DIR: buildOutDir,
79
- },
80
- }
81
- );
82
- } catch (error) {
83
- console.error(`Failed to build ${output}`);
84
- process.exit(1);
85
- }
86
- });
87
-
88
- // Now copy all files from build-output to dist/chatgpt
89
- console.log('\nCopying built files to dist/chatgpt...');
90
- resourceFiles.forEach(({ output, buildOutDir }) => {
91
- const builtFile = path.join(buildOutDir, output);
92
- const destFile = path.join(distDir, output);
93
-
94
- if (existsSync(builtFile)) {
95
- copyFileSync(builtFile, destFile);
96
- console.log(`✓ Copied ${output}`);
97
- } else {
98
- console.error(`Built file not found: ${builtFile}`);
99
- if (existsSync(buildOutDir)) {
100
- console.log(` Files in ${buildOutDir}:`, readdirSync(buildOutDir));
101
- } else {
102
- console.log(` Build directory doesn't exist: ${buildOutDir}`);
103
- }
104
- process.exit(1);
105
- }
106
- });
107
-
108
- // Clean up temp and build directories
109
- if (existsSync(tempDir)) {
110
- rmSync(tempDir, { recursive: true });
111
- }
112
- if (existsSync(buildDir)) {
113
- rmSync(buildDir, { recursive: true });
114
- }
115
-
116
- console.log('\n✓ All resources built successfully!');
117
- console.log(`\nBuilt files:`, readdirSync(distDir));