@tanstack/create 0.49.1 → 0.49.2

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 (155) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE +21 -0
  3. package/dist/file-helpers.js +3 -1
  4. package/dist/special-steps/post-init-script.js +6 -6
  5. package/package.json +11 -12
  6. package/src/file-helpers.ts +4 -1
  7. package/src/special-steps/post-init-script.ts +6 -6
  8. package/tests/file-helper.test.ts +19 -0
  9. package/tests/special-steps.test.ts +12 -12
  10. package/dist/frameworks/react/add-ons/ai/assets/src/data/demo-guitars.js +0 -67
  11. package/dist/frameworks/react/add-ons/ai/assets/src/hooks/demo-useAudioRecorder.js +0 -70
  12. package/dist/frameworks/react/add-ons/ai/assets/src/hooks/demo-useTTS.js +0 -66
  13. package/dist/frameworks/react/add-ons/ai/assets/src/lib/demo-ai-hook.js +0 -11
  14. package/dist/frameworks/react/add-ons/ai/assets/src/lib/demo-guitar-tools.js +0 -32
  15. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.chat.js +0 -87
  16. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.image.js +0 -55
  17. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.structured.js +0 -116
  18. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.transcription.js +0 -73
  19. package/dist/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.tts.js +0 -58
  20. package/dist/frameworks/react/add-ons/better-auth/assets/src/lib/auth-client.js +0 -2
  21. package/dist/frameworks/react/add-ons/better-auth/assets/src/lib/auth.js +0 -8
  22. package/dist/frameworks/react/add-ons/better-auth/assets/src/routes/api/auth/$.js +0 -10
  23. package/dist/frameworks/react/add-ons/convex/assets/convex/schema.js +0 -13
  24. package/dist/frameworks/react/add-ons/convex/assets/convex/todos.js +0 -39
  25. package/dist/frameworks/react/add-ons/db/assets/src/db-collections/index.js +0 -11
  26. package/dist/frameworks/react/add-ons/db/assets/src/hooks/demo.useChat.js +0 -47
  27. package/dist/frameworks/react/add-ons/db/assets/src/routes/demo/db-chat-api.js +0 -68
  28. package/dist/frameworks/react/add-ons/form/assets/src/hooks/demo.form-context.js +0 -2
  29. package/dist/frameworks/react/add-ons/form/assets/src/hooks/demo.form.js +0 -15
  30. package/dist/frameworks/react/add-ons/mcp/assets/src/mcp-todos.js +0 -40
  31. package/dist/frameworks/react/add-ons/mcp/assets/src/routes/demo/api.mcp-todos.js +0 -36
  32. package/dist/frameworks/react/add-ons/mcp/assets/src/routes/mcp.js +0 -43
  33. package/dist/frameworks/react/add-ons/mcp/assets/src/utils/mcp-handler.js +0 -41
  34. package/dist/frameworks/react/add-ons/neon/assets/neon-vite-plugin.js +0 -9
  35. package/dist/frameworks/react/add-ons/neon/assets/src/db.js +0 -11
  36. package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/client.js +0 -21
  37. package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/router/index.js +0 -5
  38. package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/router/todos.js +0 -17
  39. package/dist/frameworks/react/add-ons/oRPC/assets/src/orpc/schema.js +0 -5
  40. package/dist/frameworks/react/add-ons/oRPC/assets/src/polyfill.js +0 -18
  41. package/dist/frameworks/react/add-ons/oRPC/assets/src/routes/api.$.js +0 -71
  42. package/dist/frameworks/react/add-ons/oRPC/assets/src/routes/api.rpc.$.js +0 -24
  43. package/dist/frameworks/react/add-ons/shadcn/assets/src/lib/utils.js +0 -5
  44. package/dist/frameworks/react/add-ons/start/assets/src/data/demo.punk-songs.js +0 -12
  45. package/dist/frameworks/react/add-ons/start/assets/src/routes/demo/api.names.js +0 -9
  46. package/dist/frameworks/react/add-ons/store/assets/src/lib/demo-store.js +0 -10
  47. package/dist/frameworks/react/add-ons/storybook/assets/_dot_storybook/main.js +0 -15
  48. package/dist/frameworks/react/add-ons/storybook/assets/_dot_storybook/preview.js +0 -12
  49. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/button.stories.js +0 -55
  50. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/index.js +0 -5
  51. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/input.stories.js +0 -35
  52. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/radio-group.stories.js +0 -45
  53. package/dist/frameworks/react/add-ons/storybook/assets/src/components/storybook/slider.stories.js +0 -46
  54. package/dist/frameworks/react/add-ons/strapi/assets/src/lib/strapiClient.js +0 -5
  55. package/dist/frameworks/react/add-ons/t3env/assets/src/env.js +0 -34
  56. package/dist/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/init.js +0 -7
  57. package/dist/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/react.js +0 -2
  58. package/dist/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/router.js +0 -20
  59. package/dist/frameworks/react/add-ons/table/assets/src/data/demo-table-data.js +0 -35
  60. package/dist/frameworks/react/examples/events/assets/content-collections.js +0 -53
  61. package/dist/frameworks/react/examples/events/assets/src/lib/conference-ai-hook.js +0 -16
  62. package/dist/frameworks/react/examples/events/assets/src/lib/conference-tools.js +0 -177
  63. package/dist/frameworks/react/examples/events/assets/src/lib/utils.js +0 -5
  64. package/dist/frameworks/react/examples/events/assets/src/routes/api.remy-chat.js +0 -103
  65. package/dist/frameworks/react/examples/resume/assets/content-collections.js +0 -33
  66. package/dist/frameworks/react/examples/resume/assets/src/lib/resume-ai-hook.js +0 -11
  67. package/dist/frameworks/react/examples/resume/assets/src/lib/resume-tools.js +0 -135
  68. package/dist/frameworks/react/examples/resume/assets/src/lib/utils.js +0 -5
  69. package/dist/frameworks/react/examples/resume/assets/src/routes/api.resume-chat.js +0 -92
  70. package/dist/frameworks/solid/add-ons/better-auth/assets/src/lib/auth-client.js +0 -2
  71. package/dist/frameworks/solid/add-ons/better-auth/assets/src/lib/auth.js +0 -8
  72. package/dist/frameworks/solid/add-ons/better-auth/assets/src/routes/api/auth/$.js +0 -10
  73. package/dist/frameworks/solid/add-ons/convex/assets/convex/schema.js +0 -13
  74. package/dist/frameworks/solid/add-ons/convex/assets/convex/todos.js +0 -39
  75. package/dist/frameworks/solid/add-ons/solid-ui/assets/src/lib/utils.js +0 -5
  76. package/dist/frameworks/solid/add-ons/store/assets/src/lib/demo-store.js +0 -10
  77. package/dist/frameworks/solid/add-ons/strapi/assets/src/lib/strapiClient.js +0 -5
  78. package/dist/frameworks/solid/add-ons/t3env/assets/src/env.js +0 -34
  79. package/dist/frameworks/solid/examples/tanchat/assets/ai-streaming-server/src/index.js +0 -73
  80. package/dist/frameworks/solid/examples/tanchat/assets/src/lib/demo-store.js +0 -10
  81. package/dist/frameworks/solid/examples/tanchat/assets/src/store/demo.hooks.js +0 -12
  82. package/dist/frameworks/solid/examples/tanchat/assets/src/store/demo.store.js +0 -92
  83. package/dist/types/frameworks/react/add-ons/ai/assets/src/data/demo-guitars.d.ts +0 -10
  84. package/dist/types/frameworks/react/add-ons/ai/assets/src/hooks/demo-useAudioRecorder.d.ts +0 -9
  85. package/dist/types/frameworks/react/add-ons/ai/assets/src/hooks/demo-useTTS.d.ts +0 -8
  86. package/dist/types/frameworks/react/add-ons/ai/assets/src/lib/demo-ai-hook.d.ts +0 -5
  87. package/dist/types/frameworks/react/add-ons/ai/assets/src/lib/demo-guitar-tools.d.ts +0 -3
  88. package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.chat.d.ts +0 -1
  89. package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.image.d.ts +0 -1
  90. package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.structured.d.ts +0 -83
  91. package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.transcription.d.ts +0 -1
  92. package/dist/types/frameworks/react/add-ons/ai/assets/src/routes/demo/api.ai.tts.d.ts +0 -1
  93. package/dist/types/frameworks/react/add-ons/better-auth/assets/src/lib/auth-client.d.ts +0 -1
  94. package/dist/types/frameworks/react/add-ons/better-auth/assets/src/lib/auth.d.ts +0 -1
  95. package/dist/types/frameworks/react/add-ons/better-auth/assets/src/routes/api/auth/$.d.ts +0 -1
  96. package/dist/types/frameworks/react/add-ons/convex/assets/convex/schema.d.ts +0 -2
  97. package/dist/types/frameworks/react/add-ons/convex/assets/convex/todos.d.ts +0 -4
  98. package/dist/types/frameworks/react/add-ons/db/assets/src/db-collections/index.d.ts +0 -17
  99. package/dist/types/frameworks/react/add-ons/db/assets/src/hooks/demo.useChat.d.ts +0 -5
  100. package/dist/types/frameworks/react/add-ons/db/assets/src/routes/demo/db-chat-api.d.ts +0 -19
  101. package/dist/types/frameworks/react/add-ons/form/assets/src/hooks/demo.form-context.d.ts +0 -1
  102. package/dist/types/frameworks/react/add-ons/form/assets/src/hooks/demo.form.d.ts +0 -1
  103. package/dist/types/frameworks/react/add-ons/mcp/assets/src/mcp-todos.d.ts +0 -7
  104. package/dist/types/frameworks/react/add-ons/mcp/assets/src/routes/demo/api.mcp-todos.d.ts +0 -1
  105. package/dist/types/frameworks/react/add-ons/mcp/assets/src/routes/mcp.d.ts +0 -1
  106. package/dist/types/frameworks/react/add-ons/mcp/assets/src/utils/mcp-handler.d.ts +0 -2
  107. package/dist/types/frameworks/react/add-ons/neon/assets/neon-vite-plugin.d.ts +0 -2
  108. package/dist/types/frameworks/react/add-ons/neon/assets/src/db.d.ts +0 -1
  109. package/dist/types/frameworks/react/add-ons/oRPC/assets/src/orpc/client.d.ts +0 -4
  110. package/dist/types/frameworks/react/add-ons/oRPC/assets/src/orpc/router/index.d.ts +0 -5
  111. package/dist/types/frameworks/react/add-ons/oRPC/assets/src/orpc/router/todos.d.ts +0 -2
  112. package/dist/types/frameworks/react/add-ons/oRPC/assets/src/orpc/schema.d.ts +0 -11
  113. package/dist/types/frameworks/react/add-ons/oRPC/assets/src/polyfill.d.ts +0 -1
  114. package/dist/types/frameworks/react/add-ons/oRPC/assets/src/routes/api.$.d.ts +0 -2
  115. package/dist/types/frameworks/react/add-ons/oRPC/assets/src/routes/api.rpc.$.d.ts +0 -2
  116. package/dist/types/frameworks/react/add-ons/shadcn/assets/src/lib/utils.d.ts +0 -2
  117. package/dist/types/frameworks/react/add-ons/start/assets/src/data/demo.punk-songs.d.ts +0 -1
  118. package/dist/types/frameworks/react/add-ons/start/assets/src/routes/demo/api.names.d.ts +0 -1
  119. package/dist/types/frameworks/react/add-ons/store/assets/src/lib/demo-store.d.ts +0 -2
  120. package/dist/types/frameworks/react/add-ons/storybook/assets/_dot_storybook/main.d.ts +0 -3
  121. package/dist/types/frameworks/react/add-ons/storybook/assets/_dot_storybook/preview.d.ts +0 -4
  122. package/dist/types/frameworks/react/add-ons/storybook/assets/src/components/storybook/button.stories.d.ts +0 -11
  123. package/dist/types/frameworks/react/add-ons/storybook/assets/src/components/storybook/index.d.ts +0 -10
  124. package/dist/types/frameworks/react/add-ons/storybook/assets/src/components/storybook/input.stories.d.ts +0 -7
  125. package/dist/types/frameworks/react/add-ons/storybook/assets/src/components/storybook/radio-group.stories.d.ts +0 -7
  126. package/dist/types/frameworks/react/add-ons/storybook/assets/src/components/storybook/slider.stories.d.ts +0 -8
  127. package/dist/types/frameworks/react/add-ons/strapi/assets/src/lib/strapiClient.d.ts +0 -2
  128. package/dist/types/frameworks/react/add-ons/t3env/assets/src/env.d.ts +0 -1
  129. package/dist/types/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/init.d.ts +0 -2
  130. package/dist/types/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/react.d.ts +0 -1
  131. package/dist/types/frameworks/react/add-ons/tRPC/assets/src/integrations/trpc/router.d.ts +0 -2
  132. package/dist/types/frameworks/react/add-ons/table/assets/src/data/demo-table-data.d.ts +0 -11
  133. package/dist/types/frameworks/react/examples/events/assets/content-collections.d.ts +0 -2
  134. package/dist/types/frameworks/react/examples/events/assets/src/lib/conference-ai-hook.d.ts +0 -5
  135. package/dist/types/frameworks/react/examples/events/assets/src/lib/conference-tools.d.ts +0 -10
  136. package/dist/types/frameworks/react/examples/events/assets/src/lib/utils.d.ts +0 -2
  137. package/dist/types/frameworks/react/examples/events/assets/src/routes/api.remy-chat.d.ts +0 -1
  138. package/dist/types/frameworks/react/examples/resume/assets/content-collections.d.ts +0 -2
  139. package/dist/types/frameworks/react/examples/resume/assets/src/lib/resume-ai-hook.d.ts +0 -5
  140. package/dist/types/frameworks/react/examples/resume/assets/src/lib/resume-tools.d.ts +0 -8
  141. package/dist/types/frameworks/react/examples/resume/assets/src/lib/utils.d.ts +0 -2
  142. package/dist/types/frameworks/react/examples/resume/assets/src/routes/api.resume-chat.d.ts +0 -1
  143. package/dist/types/frameworks/solid/add-ons/better-auth/assets/src/lib/auth-client.d.ts +0 -1
  144. package/dist/types/frameworks/solid/add-ons/better-auth/assets/src/lib/auth.d.ts +0 -1
  145. package/dist/types/frameworks/solid/add-ons/better-auth/assets/src/routes/api/auth/$.d.ts +0 -1
  146. package/dist/types/frameworks/solid/add-ons/convex/assets/convex/schema.d.ts +0 -2
  147. package/dist/types/frameworks/solid/add-ons/convex/assets/convex/todos.d.ts +0 -4
  148. package/dist/types/frameworks/solid/add-ons/solid-ui/assets/src/lib/utils.d.ts +0 -2
  149. package/dist/types/frameworks/solid/add-ons/store/assets/src/lib/demo-store.d.ts +0 -2
  150. package/dist/types/frameworks/solid/add-ons/strapi/assets/src/lib/strapiClient.d.ts +0 -2
  151. package/dist/types/frameworks/solid/add-ons/t3env/assets/src/env.d.ts +0 -1
  152. package/dist/types/frameworks/solid/examples/tanchat/assets/ai-streaming-server/src/index.d.ts +0 -1
  153. package/dist/types/frameworks/solid/examples/tanchat/assets/src/lib/demo-store.d.ts +0 -2
  154. package/dist/types/frameworks/solid/examples/tanchat/assets/src/store/demo.hooks.d.ts +0 -23
  155. package/dist/types/frameworks/solid/examples/tanchat/assets/src/store/demo.store.d.ts +0 -40
package/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @tanstack/create
2
+
3
+ ## 0.49.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixed windows \\ delimiter stripping ([`7940300`](https://github.com/TanStack/cli/commit/79403004689817339ec6f6e03c20fb25e841ddb0))
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021-present Tanner Linsley
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -34,8 +34,10 @@ export function getBinaryFile(content) {
34
34
  */
35
35
  export function toCleanPath(absolutePath, baseDir) {
36
36
  let cleanPath = absolutePath.replace(baseDir, '');
37
- if (cleanPath.startsWith('/'))
37
+ // Handle both Unix (/) and Windows (\) path separators
38
+ if (cleanPath.startsWith('/') || cleanPath.startsWith('\\')) {
38
39
  cleanPath = cleanPath.slice(1);
40
+ }
39
41
  return cleanPath;
40
42
  }
41
43
  export function relativePath(from, to, stripExtension = false) {
@@ -4,28 +4,28 @@ import { getPackageManagerScriptCommand } from '../package-manager.js';
4
4
  export async function postInitScript(environment, options) {
5
5
  const packageJsonPath = resolve(options.targetDir, 'package.json');
6
6
  if (!environment.exists(packageJsonPath)) {
7
- environment.warn('Warning', 'No package.json found, skipping post-cta-init script');
7
+ environment.warn('Warning', 'No package.json found, skipping post-create-init script');
8
8
  return;
9
9
  }
10
10
  try {
11
11
  const packageJsonContent = readFileSync(packageJsonPath, 'utf-8');
12
12
  const packageJson = JSON.parse(packageJsonContent);
13
- if (!packageJson.scripts || !packageJson.scripts['post-cta-init']) {
14
- // No post-cta-init script found, skip silently
13
+ if (!packageJson.scripts || !packageJson.scripts['post-create-init']) {
14
+ // No post-create-init script found, skip silently
15
15
  return;
16
16
  }
17
17
  environment.startStep({
18
18
  id: 'post-init-script',
19
19
  type: 'command',
20
- message: 'Running post-cta-init script...',
20
+ message: 'Running post-create-init script...',
21
21
  });
22
- const { command, args } = getPackageManagerScriptCommand(options.packageManager, ['post-cta-init']);
22
+ const { command, args } = getPackageManagerScriptCommand(options.packageManager, ['post-create-init']);
23
23
  await environment.execute(command, args, options.targetDir, {
24
24
  inherit: true,
25
25
  });
26
26
  environment.finishStep('post-init-script', 'Post-cta-init script complete');
27
27
  }
28
28
  catch (error) {
29
- environment.error(`Failed to run post-cta-init script: ${error instanceof Error ? error.message : String(error)}`);
29
+ environment.error(`Failed to run post-create-init script: ${error instanceof Error ? error.message : String(error)}`);
30
30
  }
31
31
  }
package/package.json CHANGED
@@ -1,21 +1,13 @@
1
1
  {
2
2
  "name": "@tanstack/create",
3
- "version": "0.49.1",
3
+ "version": "0.49.2",
4
4
  "description": "TanStack Application Builder Engine",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/types/index.d.ts",
8
- "scripts": {
9
- "build": "tsc && npm run copy-assets",
10
- "copy-assets": "node -e \"const fs=require('fs');const path=require('path');function copyDir(src,dest){if(!fs.existsSync(dest))fs.mkdirSync(dest,{recursive:true});for(const entry of fs.readdirSync(src,{withFileTypes:true})){const srcPath=path.join(src,entry.name);const destPath=path.join(dest,entry.name);if(entry.isDirectory())copyDir(srcPath,destPath);else if(!entry.name.endsWith('.ts')||entry.name.endsWith('.d.ts'))fs.copyFileSync(srcPath,destPath)}}['react','solid'].forEach(fw=>{['add-ons','toolchains','hosts','examples','project'].forEach(dir=>{const src='src/frameworks/'+fw+'/'+dir;const dest='dist/frameworks/'+fw+'/'+dir;if(fs.existsSync(src))copyDir(src,dest)})})\"",
11
- "dev": "tsc --watch",
12
- "test": "eslint ./src && vitest run",
13
- "test:watch": "vitest",
14
- "test:coverage": "vitest run --coverage"
15
- },
16
8
  "repository": {
17
9
  "type": "git",
18
- "url": "git+https://github.com/TanStack/create-tsrouter-app.git",
10
+ "url": "git+https://github.com/TanStack/cli.git",
19
11
  "directory": "packages/create"
20
12
  },
21
13
  "homepage": "https://tanstack.com/router",
@@ -30,7 +22,6 @@
30
22
  ],
31
23
  "author": "Jack Herrington <jherr@pobox.com>",
32
24
  "license": "MIT",
33
- "packageManager": "pnpm@9.15.5",
34
25
  "dependencies": {
35
26
  "ejs": "^3.1.10",
36
27
  "execa": "^9.5.2",
@@ -50,5 +41,13 @@
50
41
  "typescript": "^5.6.3",
51
42
  "vitest": "^3.0.8",
52
43
  "vitest-fetch-mock": "^0.4.5"
44
+ },
45
+ "scripts": {
46
+ "build": "tsc && npm run copy-assets",
47
+ "copy-assets": "node -e \"const fs=require('fs');const path=require('path');function copyDir(src,dest){if(!fs.existsSync(dest))fs.mkdirSync(dest,{recursive:true});for(const entry of fs.readdirSync(src,{withFileTypes:true})){const srcPath=path.join(src,entry.name);const destPath=path.join(dest,entry.name);if(entry.isDirectory())copyDir(srcPath,destPath);else if(!entry.name.endsWith('.ts')||entry.name.endsWith('.d.ts'))fs.copyFileSync(srcPath,destPath)}}['react','solid'].forEach(fw=>{['add-ons','toolchains','hosts','examples','project'].forEach(dir=>{const src='src/frameworks/'+fw+'/'+dir;const dest='dist/frameworks/'+fw+'/'+dir;if(fs.existsSync(src))copyDir(src,dest)})})\"",
48
+ "dev": "tsc --watch",
49
+ "test": "eslint ./src && vitest run",
50
+ "test:watch": "vitest",
51
+ "test:coverage": "vitest run --coverage"
53
52
  }
54
- }
53
+ }
@@ -42,7 +42,10 @@ export function getBinaryFile(content: string): string | null {
42
42
  */
43
43
  export function toCleanPath(absolutePath: string, baseDir: string): string {
44
44
  let cleanPath = absolutePath.replace(baseDir, '')
45
- if (cleanPath.startsWith('/')) cleanPath = cleanPath.slice(1)
45
+ // Handle both Unix (/) and Windows (\) path separators
46
+ if (cleanPath.startsWith('/') || cleanPath.startsWith('\\')) {
47
+ cleanPath = cleanPath.slice(1)
48
+ }
46
49
  return cleanPath
47
50
  }
48
51
 
@@ -14,7 +14,7 @@ export async function postInitScript(
14
14
  if (!environment.exists(packageJsonPath)) {
15
15
  environment.warn(
16
16
  'Warning',
17
- 'No package.json found, skipping post-cta-init script',
17
+ 'No package.json found, skipping post-create-init script',
18
18
  )
19
19
  return
20
20
  }
@@ -23,20 +23,20 @@ export async function postInitScript(
23
23
  const packageJsonContent = readFileSync(packageJsonPath, 'utf-8')
24
24
  const packageJson = JSON.parse(packageJsonContent)
25
25
 
26
- if (!packageJson.scripts || !packageJson.scripts['post-cta-init']) {
27
- // No post-cta-init script found, skip silently
26
+ if (!packageJson.scripts || !packageJson.scripts['post-create-init']) {
27
+ // No post-create-init script found, skip silently
28
28
  return
29
29
  }
30
30
 
31
31
  environment.startStep({
32
32
  id: 'post-init-script',
33
33
  type: 'command',
34
- message: 'Running post-cta-init script...',
34
+ message: 'Running post-create-init script...',
35
35
  })
36
36
 
37
37
  const { command, args } = getPackageManagerScriptCommand(
38
38
  options.packageManager,
39
- ['post-cta-init'],
39
+ ['post-create-init'],
40
40
  )
41
41
 
42
42
  await environment.execute(command, args, options.targetDir, {
@@ -46,7 +46,7 @@ export async function postInitScript(
46
46
  environment.finishStep('post-init-script', 'Post-cta-init script complete')
47
47
  } catch (error) {
48
48
  environment.error(
49
- `Failed to run post-cta-init script: ${error instanceof Error ? error.message : String(error)}`,
49
+ `Failed to run post-create-init script: ${error instanceof Error ? error.message : String(error)}`,
50
50
  )
51
51
  }
52
52
  }
@@ -6,6 +6,7 @@ import {
6
6
  isDirectory,
7
7
  readFileHelper,
8
8
  relativePath,
9
+ toCleanPath,
9
10
  } from '../src/file-helpers.js'
10
11
 
11
12
  vi.mock('node:fs', () => fs)
@@ -15,6 +16,24 @@ beforeEach(() => {
15
16
  vol.reset()
16
17
  })
17
18
 
19
+ describe('toCleanPath', () => {
20
+ it('should strip Unix-style leading slash', () => {
21
+ expect(toCleanPath('/projects/my-app/src/file.ts', '/projects/my-app')).toBe(
22
+ 'src/file.ts',
23
+ )
24
+ })
25
+
26
+ it('should strip Windows-style leading backslash', () => {
27
+ expect(
28
+ toCleanPath('C:\\Projects\\my-app\\src\\file.ts', 'C:\\Projects\\my-app'),
29
+ ).toBe('src\\file.ts')
30
+ })
31
+
32
+ it('should handle paths without leading separator', () => {
33
+ expect(toCleanPath('/projects/my-app', '/projects/my-app')).toBe('')
34
+ })
35
+ })
36
+
18
37
  describe('relativePath', () => {
19
38
  it('relative path with the same directory and strip extension', () => {
20
39
  expect(relativePath('src/utils.ts', 'src/index.ts', true)).toBe('./index')
@@ -34,10 +34,10 @@ describe('Special Steps', () => {
34
34
  })
35
35
 
36
36
  describe('postInitScript', () => {
37
- it('should run post-cta-init script when it exists', async () => {
37
+ it('should run post-create-init script when it exists', async () => {
38
38
  const mockPackageJson = {
39
39
  scripts: {
40
- 'post-cta-init': 'echo "Running post-cta-init"',
40
+ 'post-create-init': 'echo "Running post-create-init"',
41
41
  },
42
42
  }
43
43
 
@@ -51,12 +51,12 @@ describe('Special Steps', () => {
51
51
  expect(mockEnvironment.startStep).toHaveBeenCalledWith({
52
52
  id: 'post-init-script',
53
53
  type: 'command',
54
- message: 'Running post-cta-init script...',
54
+ message: 'Running post-create-init script...',
55
55
  })
56
56
 
57
57
  expect(mockEnvironment.execute).toHaveBeenCalledWith(
58
58
  'npm',
59
- ['run', 'post-cta-init'],
59
+ ['run', 'post-create-init'],
60
60
  '/test/project',
61
61
  { inherit: true },
62
62
  )
@@ -74,12 +74,12 @@ describe('Special Steps', () => {
74
74
 
75
75
  expect(mockEnvironment.warn).toHaveBeenCalledWith(
76
76
  'Warning',
77
- 'No package.json found, skipping post-cta-init script',
77
+ 'No package.json found, skipping post-create-init script',
78
78
  )
79
79
  expect(mockEnvironment.execute).not.toHaveBeenCalled()
80
80
  })
81
81
 
82
- it('should skip when post-cta-init script does not exist', async () => {
82
+ it('should skip when post-create-init script does not exist', async () => {
83
83
  const mockPackageJson = {
84
84
  scripts: {
85
85
  build: 'echo "Building"',
@@ -100,10 +100,10 @@ describe('Special Steps', () => {
100
100
  it('should handle different package managers', async () => {
101
101
  const packageManagers = ['yarn', 'pnpm', 'bun', 'deno'] as const
102
102
  const expectedCommands = {
103
- yarn: { command: 'yarn', args: ['run', 'post-cta-init'] },
104
- pnpm: { command: 'pnpm', args: ['post-cta-init'] },
105
- bun: { command: 'bun', args: ['--bun', 'run', 'post-cta-init'] },
106
- deno: { command: 'deno', args: ['task', 'post-cta-init'] },
103
+ yarn: { command: 'yarn', args: ['run', 'post-create-init'] },
104
+ pnpm: { command: 'pnpm', args: ['post-create-init'] },
105
+ bun: { command: 'bun', args: ['--bun', 'run', 'post-create-init'] },
106
+ deno: { command: 'deno', args: ['task', 'post-create-init'] },
107
107
  }
108
108
 
109
109
  for (const pm of packageManagers) {
@@ -111,7 +111,7 @@ describe('Special Steps', () => {
111
111
  vi.clearAllMocks()
112
112
  vi.spyOn(mockEnvironment, 'exists').mockReturnValue(true)
113
113
  vi.mocked(fs.readFileSync).mockReturnValue(
114
- JSON.stringify({ scripts: { 'post-cta-init': 'test' } }),
114
+ JSON.stringify({ scripts: { 'post-create-init': 'test' } }),
115
115
  )
116
116
 
117
117
  await postInitScript(mockEnvironment, mockOptions)
@@ -133,7 +133,7 @@ describe('Special Steps', () => {
133
133
 
134
134
  vi.spyOn(mockEnvironment, 'exists').mockReturnValue(true)
135
135
  vi.mocked(fs.readFileSync).mockReturnValue(
136
- JSON.stringify({ scripts: { 'post-cta-init': 'test' } }),
136
+ JSON.stringify({ scripts: { 'post-create-init': 'test' } }),
137
137
  )
138
138
 
139
139
  await runSpecialSteps(mockEnvironment, mockOptions, specialSteps)
@@ -1,67 +0,0 @@
1
- const guitars = [
2
- {
3
- id: 1,
4
- name: 'TanStack Ukelele',
5
- image: '/example-ukelele-tanstack.jpg',
6
- description: "Introducing the TanStack Signature Ukulele—a beautifully handcrafted concert ukulele that combines exceptional sound quality with distinctive style. Featuring a warm, resonant koa-wood body with natural grain patterns, this instrument delivers the rich, mellow tones Hawaii is famous for. The exclusive TanStack palm tree inlay on the soundhole adds a unique touch of island flair, while the matching branded headstock makes this a true collector's piece for developers and musicians alike. Whether you're a beginner looking for a quality starter instrument or an experienced player wanting something special, the TanStack Ukulele brings together craftsmanship, character, and that unmistakable tropical spirit.",
7
- shortDescription: 'Premium koa-wood ukulele featuring exclusive TanStack branding, perfect for beach vibes and island-inspired melodies.',
8
- price: 299,
9
- },
10
- {
11
- id: 2,
12
- name: 'Video Game Guitar',
13
- image: '/example-guitar-video-games.jpg',
14
- description: "The Video Game Guitar is a unique acoustic guitar that features a design inspired by video games. It has a sleek, high-gloss finish and a comfortable playability. The guitar's ergonomic body and fast neck profile ensure comfortable playability for hours on end.",
15
- shortDescription: 'A unique electric guitar with a video game design, high-gloss finish, and comfortable playability.',
16
- price: 699,
17
- },
18
- {
19
- id: 3,
20
- name: 'Superhero Guitar',
21
- image: '/example-guitar-superhero.jpg',
22
- description: "The Superhero Guitar is a bold black electric guitar that stands out with its unique superhero logo design. Its sleek, high-gloss finish and powerful pickups make it perfect for high-energy performances. The guitar's ergonomic body and fast neck profile ensure comfortable playability for hours on end.",
23
- shortDescription: 'A bold black electric guitar with a unique superhero logo, high-gloss finish, and powerful pickups.',
24
- price: 699,
25
- },
26
- {
27
- id: 4,
28
- name: 'Motherboard Guitar',
29
- image: '/example-guitar-motherboard.jpg',
30
- description: "This guitar is a tribute to the motherboard of a computer. It's a unique and stylish instrument that will make you feel like a hacker. The intricate circuit-inspired design features actual LED lights that pulse with your playing intensity, while the neck is inlaid with binary code patterns that glow under stage lights. Each pickup has been custom-wound to produce tones ranging from clean digital precision to glitched-out distortion, perfect for electronic music fusion. The Motherboard Guitar seamlessly bridges the gap between traditional craftsmanship and cutting-edge technology, making it the ultimate instrument for the digital age musician.",
31
- shortDescription: 'A tech-inspired electric guitar featuring LED lights and binary code inlays that glow under stage lights.',
32
- price: 649,
33
- },
34
- {
35
- id: 5,
36
- name: 'Racing Guitar',
37
- image: '/example-guitar-racing.jpg',
38
- description: "Engineered for speed and precision, the Racing Guitar embodies the spirit of motorsport in every curve and contour. Its aerodynamic body, painted in classic racing stripes and high-gloss finish, is crafted from lightweight materials that allow for effortless play during extended performances. The custom low-action setup and streamlined neck profile enable lightning-fast fretwork, while specially designed pickups deliver a high-octane tone that cuts through any mix. Built with performance-grade hardware including racing-inspired control knobs and checkered flag inlays, this guitar isn't just played—it's driven to the limits of musical possibility.",
39
- shortDescription: 'A lightweight, aerodynamic guitar with racing stripes and a low-action setup designed for speed and precision.',
40
- price: 679,
41
- },
42
- {
43
- id: 6,
44
- name: 'Steamer Trunk Guitar',
45
- image: '/example-guitar-steamer-trunk.jpg',
46
- description: 'The Steamer Trunk Guitar is a semi-hollow body instrument that exudes vintage charm and character. Crafted from reclaimed antique luggage wood, it features brass hardware that adds a touch of elegance and durability. The fretboard is adorned with a world map inlay, making it a unique piece that tells a story of travel and adventure.',
47
- shortDescription: 'A semi-hollow body guitar with brass hardware and a world map inlay, crafted from reclaimed antique luggage wood.',
48
- price: 629,
49
- },
50
- {
51
- id: 7,
52
- name: "Travelin' Man Guitar",
53
- image: '/example-guitar-traveling.jpg',
54
- description: "The Travelin' Man Guitar is an acoustic masterpiece adorned with vintage postcards from around the world. Each postcard tells a story of adventure and wanderlust, making this guitar a unique piece of art. Its rich, resonant tones and comfortable playability make it perfect for musicians who love to travel and perform.",
55
- shortDescription: 'An acoustic guitar with vintage postcards, rich tones, and comfortable playability.',
56
- price: 499,
57
- },
58
- {
59
- id: 8,
60
- name: 'Flowerly Love Guitar',
61
- image: '/example-guitar-flowers.jpg',
62
- description: "The Flowerly Love Guitar is an acoustic masterpiece adorned with intricate floral designs on its body. Each flower is hand-painted, adding a touch of nature's beauty to the instrument. Its warm, resonant tones make it perfect for both intimate performances and larger gatherings.",
63
- shortDescription: 'An acoustic guitar with hand-painted floral designs and warm, resonant tones.',
64
- price: 599,
65
- },
66
- ];
67
- export default guitars;
@@ -1,70 +0,0 @@
1
- import { useCallback, useRef, useState } from 'react';
2
- /**
3
- * Hook for recording audio and transcribing it via the transcription API.
4
- */
5
- export function useAudioRecorder() {
6
- const [isRecording, setIsRecording] = useState(false);
7
- const [isTranscribing, setIsTranscribing] = useState(false);
8
- const mediaRecorderRef = useRef(null);
9
- const chunksRef = useRef([]);
10
- const startRecording = useCallback(async () => {
11
- try {
12
- const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
13
- const mediaRecorder = new MediaRecorder(stream, {
14
- mimeType: 'audio/webm;codecs=opus',
15
- });
16
- mediaRecorderRef.current = mediaRecorder;
17
- chunksRef.current = [];
18
- mediaRecorder.ondataavailable = (e) => {
19
- if (e.data.size > 0) {
20
- chunksRef.current.push(e.data);
21
- }
22
- };
23
- mediaRecorder.start();
24
- setIsRecording(true);
25
- }
26
- catch (error) {
27
- console.error('Failed to start recording:', error);
28
- alert('Could not access microphone. Please check permissions.');
29
- }
30
- }, []);
31
- const stopRecording = useCallback(async () => {
32
- return new Promise((resolve) => {
33
- const mediaRecorder = mediaRecorderRef.current;
34
- if (!mediaRecorder) {
35
- resolve(null);
36
- return;
37
- }
38
- mediaRecorder.onstop = async () => {
39
- setIsRecording(false);
40
- setIsTranscribing(true);
41
- const audioBlob = new Blob(chunksRef.current, { type: 'audio/webm' });
42
- // Stop all tracks
43
- mediaRecorder.stream.getTracks().forEach((track) => track.stop());
44
- try {
45
- const formData = new FormData();
46
- formData.append('audio', new File([audioBlob], 'recording.webm', { type: 'audio/webm' }));
47
- formData.append('model', 'whisper-1');
48
- const response = await fetch('/demo/api/transcription', {
49
- method: 'POST',
50
- body: formData,
51
- });
52
- if (!response.ok) {
53
- const errorData = await response.json();
54
- throw new Error(errorData.error || 'Transcription failed');
55
- }
56
- const result = await response.json();
57
- setIsTranscribing(false);
58
- resolve(result.text || null);
59
- }
60
- catch (error) {
61
- console.error('Transcription error:', error);
62
- setIsTranscribing(false);
63
- resolve(null);
64
- }
65
- };
66
- mediaRecorder.stop();
67
- });
68
- }, []);
69
- return { isRecording, isTranscribing, startRecording, stopRecording };
70
- }
@@ -1,66 +0,0 @@
1
- import { useCallback, useRef, useState } from 'react';
2
- /**
3
- * Hook for text-to-speech playback via the TTS API.
4
- */
5
- export function useTTS() {
6
- const [playingId, setPlayingId] = useState(null);
7
- const audioRef = useRef(null);
8
- const speak = useCallback(async (text, id) => {
9
- // Stop any currently playing audio
10
- if (audioRef.current) {
11
- audioRef.current.pause();
12
- audioRef.current = null;
13
- }
14
- setPlayingId(id);
15
- try {
16
- const response = await fetch('/demo/api/tts', {
17
- method: 'POST',
18
- headers: { 'Content-Type': 'application/json' },
19
- body: JSON.stringify({
20
- text,
21
- voice: 'nova',
22
- model: 'tts-1',
23
- format: 'mp3',
24
- }),
25
- });
26
- if (!response.ok) {
27
- const errorData = await response.json();
28
- throw new Error(errorData.error || 'TTS failed');
29
- }
30
- const result = await response.json();
31
- // Convert base64 to audio and play
32
- const audioData = atob(result.audio);
33
- const bytes = new Uint8Array(audioData.length);
34
- for (let i = 0; i < audioData.length; i++) {
35
- bytes[i] = audioData.charCodeAt(i);
36
- }
37
- const blob = new Blob([bytes], { type: result.contentType });
38
- const url = URL.createObjectURL(blob);
39
- const audio = new Audio(url);
40
- audioRef.current = audio;
41
- audio.onended = () => {
42
- URL.revokeObjectURL(url);
43
- setPlayingId(null);
44
- audioRef.current = null;
45
- };
46
- audio.onerror = () => {
47
- URL.revokeObjectURL(url);
48
- setPlayingId(null);
49
- audioRef.current = null;
50
- };
51
- await audio.play();
52
- }
53
- catch (error) {
54
- console.error('TTS error:', error);
55
- setPlayingId(null);
56
- }
57
- }, []);
58
- const stop = useCallback(() => {
59
- if (audioRef.current) {
60
- audioRef.current.pause();
61
- audioRef.current = null;
62
- }
63
- setPlayingId(null);
64
- }, []);
65
- return { playingId, speak, stop };
66
- }
@@ -1,11 +0,0 @@
1
- import { fetchServerSentEvents, useChat, createChatClientOptions, } from '@tanstack/ai-react';
2
- import { clientTools } from '@tanstack/ai-client';
3
- import { recommendGuitarToolDef } from '@/lib/demo-guitar-tools';
4
- const recommendGuitarToolClient = recommendGuitarToolDef.client(({ id }) => ({
5
- id: +id,
6
- }));
7
- const chatOptions = createChatClientOptions({
8
- connection: fetchServerSentEvents('/demo/api/ai/chat'),
9
- tools: clientTools(recommendGuitarToolClient),
10
- });
11
- export const useGuitarRecommendationChat = () => useChat(chatOptions);
@@ -1,32 +0,0 @@
1
- import { toolDefinition } from '@tanstack/ai';
2
- import { z } from 'zod';
3
- import guitars from '@/data/demo-guitars';
4
- // Tool definition for getting guitars
5
- export const getGuitarsToolDef = toolDefinition({
6
- name: 'getGuitars',
7
- description: 'Get all products from the database',
8
- inputSchema: z.object({}),
9
- outputSchema: z.array(z.object({
10
- id: z.number(),
11
- name: z.string(),
12
- image: z.string(),
13
- description: z.string(),
14
- shortDescription: z.string(),
15
- price: z.number(),
16
- })),
17
- });
18
- // Server implementation
19
- export const getGuitars = getGuitarsToolDef.server(() => guitars);
20
- // Tool definition for guitar recommendation
21
- export const recommendGuitarToolDef = toolDefinition({
22
- name: 'recommendGuitar',
23
- description: 'REQUIRED tool to display a guitar recommendation to the user. This tool MUST be used whenever recommending a guitar - do NOT write recommendations yourself. This displays the guitar in a special appealing format with a buy button.',
24
- inputSchema: z.object({
25
- id: z
26
- .union([z.string(), z.number()])
27
- .describe('The ID of the guitar to recommend (from the getGuitars results)'),
28
- }),
29
- outputSchema: z.object({
30
- id: z.number(),
31
- }),
32
- });
@@ -1,87 +0,0 @@
1
- import { createFileRoute } from '@tanstack/react-router';
2
- import { chat, maxIterations, toServerSentEventsResponse } from '@tanstack/ai';
3
- import { anthropicText } from '@tanstack/ai-anthropic';
4
- import { openaiText } from '@tanstack/ai-openai';
5
- import { geminiText } from '@tanstack/ai-gemini';
6
- import { ollamaText } from '@tanstack/ai-ollama';
7
- import { getGuitars, recommendGuitarToolDef } from '@/lib/demo-guitar-tools';
8
- const SYSTEM_PROMPT = `You are a helpful assistant for a store that sells guitars.
9
-
10
- CRITICAL INSTRUCTIONS - YOU MUST FOLLOW THIS EXACT WORKFLOW:
11
-
12
- When a user asks for a guitar recommendation:
13
- 1. FIRST: Use the getGuitars tool (no parameters needed)
14
- 2. SECOND: Use the recommendGuitar tool with the ID of the guitar you want to recommend
15
- 3. NEVER write a recommendation directly - ALWAYS use the recommendGuitar tool
16
-
17
- IMPORTANT:
18
- - The recommendGuitar tool will display the guitar in a special, appealing format
19
- - You MUST use recommendGuitar for ANY guitar recommendation
20
- - ONLY recommend guitars from our inventory (use getGuitars first)
21
- - The recommendGuitar tool has a buy button - this is how customers purchase
22
- - Do NOT describe the guitar yourself - let the recommendGuitar tool do it
23
- `;
24
- export const Route = createFileRoute('/demo/api/ai/chat')({
25
- server: {
26
- handlers: {
27
- POST: async ({ request }) => {
28
- // Capture request signal before reading body (it may be aborted after body is consumed)
29
- const requestSignal = request.signal;
30
- // If request is already aborted, return early
31
- if (requestSignal.aborted) {
32
- return new Response(null, { status: 499 }); // 499 = Client Closed Request
33
- }
34
- const abortController = new AbortController();
35
- try {
36
- const body = await request.json();
37
- const { messages } = body;
38
- // Determine the best available provider
39
- let provider = 'ollama';
40
- let model = 'mistral:7b';
41
- if (process.env.ANTHROPIC_API_KEY) {
42
- provider = 'anthropic';
43
- model = 'claude-haiku-4-5';
44
- }
45
- else if (process.env.OPENAI_API_KEY) {
46
- provider = 'openai';
47
- model = 'gpt-4o';
48
- }
49
- else if (process.env.GEMINI_API_KEY) {
50
- provider = 'gemini';
51
- model = 'gemini-2.0-flash-exp';
52
- }
53
- // Adapter factory pattern for multi-vendor support
54
- const adapterConfig = {
55
- anthropic: () => anthropicText((model || 'claude-haiku-4-5')),
56
- openai: () => openaiText((model || 'gpt-4o')),
57
- gemini: () => geminiText((model || 'gemini-2.0-flash-exp')),
58
- ollama: () => ollamaText((model || 'mistral:7b')),
59
- };
60
- const adapter = adapterConfig[provider]();
61
- const stream = chat({
62
- adapter,
63
- tools: [
64
- getGuitars, // Server tool
65
- recommendGuitarToolDef, // No server execute - client will handle
66
- ],
67
- systemPrompts: [SYSTEM_PROMPT],
68
- agentLoopStrategy: maxIterations(5),
69
- messages,
70
- abortController,
71
- });
72
- return toServerSentEventsResponse(stream, { abortController });
73
- }
74
- catch (error) {
75
- // If request was aborted, return early (don't send error response)
76
- if (error.name === 'AbortError' || abortController.signal.aborted) {
77
- return new Response(null, { status: 499 }); // 499 = Client Closed Request
78
- }
79
- return new Response(JSON.stringify({ error: 'Failed to process chat request' }), {
80
- status: 500,
81
- headers: { 'Content-Type': 'application/json' },
82
- });
83
- }
84
- },
85
- },
86
- },
87
- });