vibefast-cli 0.1.1

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 (250) hide show
  1. package/FINAL-STATUS.md +144 -0
  2. package/HOW-IT-WORKS.md +559 -0
  3. package/PLAN.md +453 -0
  4. package/README.md +129 -0
  5. package/RECIPES-READY.md +172 -0
  6. package/STATUS.md +199 -0
  7. package/SUCCESS.md +259 -0
  8. package/TESTING-CHECKLIST.md +450 -0
  9. package/cloudflare-worker/.wrangler/state/v3/kv/64907821e2634080acce34618d2f3d4c/blobs/11f2769953c717e188062bc644da97c1fd1e4d6d0813a226ce7567dba759afab0000019a736fb8d4 +1 -0
  10. package/cloudflare-worker/.wrangler/state/v3/kv/miniflare-KVNamespaceObject/0b03767237c0408301af51ca35d4b09470cbc479c7e5f23cc9de774749d23c59.sqlite +0 -0
  11. package/cloudflare-worker/.wrangler/state/v3/kv/miniflare-KVNamespaceObject/0b03767237c0408301af51ca35d4b09470cbc479c7e5f23cc9de774749d23c59.sqlite-shm +0 -0
  12. package/cloudflare-worker/.wrangler/state/v3/kv/miniflare-KVNamespaceObject/0b03767237c0408301af51ca35d4b09470cbc479c7e5f23cc9de774749d23c59.sqlite-wal +0 -0
  13. package/cloudflare-worker/.wrangler/state/v3/r2/miniflare-R2BucketObject/d1cc388a1a0ef44dd5669fd1a165d168b61362136c8b5fa50aefd96c72688e54.sqlite +0 -0
  14. package/cloudflare-worker/.wrangler/state/v3/r2/miniflare-R2BucketObject/d1cc388a1a0ef44dd5669fd1a165d168b61362136c8b5fa50aefd96c72688e54.sqlite-shm +0 -0
  15. package/cloudflare-worker/.wrangler/state/v3/r2/miniflare-R2BucketObject/d1cc388a1a0ef44dd5669fd1a165d168b61362136c8b5fa50aefd96c72688e54.sqlite-wal +0 -0
  16. package/cloudflare-worker/.wrangler/state/v3/r2/vibefast-recipes/blobs/620e8cf7c35d9806da25dee237e1d7e8b2432bd98f755b60e2c7f08a48d2c7b90000019a73736484 +0 -0
  17. package/cloudflare-worker/MIGRATION.md +160 -0
  18. package/cloudflare-worker/QUICKSTART.md +200 -0
  19. package/cloudflare-worker/README.md +242 -0
  20. package/cloudflare-worker/generate-token.js +32 -0
  21. package/cloudflare-worker/mini-native@latest.zip +0 -0
  22. package/cloudflare-worker/setup.sh +143 -0
  23. package/cloudflare-worker/test-recipe/apps/native/src/app/mini/index.tsx +15 -0
  24. package/cloudflare-worker/test-recipe/recipe.json +16 -0
  25. package/cloudflare-worker/worker.js +308 -0
  26. package/cloudflare-worker/wrangler.toml +13 -0
  27. package/dist/commands/add.d.ts +3 -0
  28. package/dist/commands/add.d.ts.map +1 -0
  29. package/dist/commands/add.js +149 -0
  30. package/dist/commands/add.js.map +1 -0
  31. package/dist/commands/devices.d.ts +3 -0
  32. package/dist/commands/devices.d.ts.map +1 -0
  33. package/dist/commands/devices.js +35 -0
  34. package/dist/commands/devices.js.map +1 -0
  35. package/dist/commands/doctor.d.ts +3 -0
  36. package/dist/commands/doctor.d.ts.map +1 -0
  37. package/dist/commands/doctor.js +67 -0
  38. package/dist/commands/doctor.js.map +1 -0
  39. package/dist/commands/list.d.ts +3 -0
  40. package/dist/commands/list.d.ts.map +1 -0
  41. package/dist/commands/list.js +40 -0
  42. package/dist/commands/list.js.map +1 -0
  43. package/dist/commands/login.d.ts +3 -0
  44. package/dist/commands/login.d.ts.map +1 -0
  45. package/dist/commands/login.js +23 -0
  46. package/dist/commands/login.js.map +1 -0
  47. package/dist/commands/logout.d.ts +3 -0
  48. package/dist/commands/logout.d.ts.map +1 -0
  49. package/dist/commands/logout.js +16 -0
  50. package/dist/commands/logout.js.map +1 -0
  51. package/dist/commands/remove.d.ts +3 -0
  52. package/dist/commands/remove.d.ts.map +1 -0
  53. package/dist/commands/remove.js +67 -0
  54. package/dist/commands/remove.js.map +1 -0
  55. package/dist/core/__tests__/journal.test.d.ts +2 -0
  56. package/dist/core/__tests__/journal.test.d.ts.map +1 -0
  57. package/dist/core/__tests__/journal.test.js +101 -0
  58. package/dist/core/__tests__/journal.test.js.map +1 -0
  59. package/dist/core/__tests__/validate.test.d.ts +2 -0
  60. package/dist/core/__tests__/validate.test.d.ts.map +1 -0
  61. package/dist/core/__tests__/validate.test.js +53 -0
  62. package/dist/core/__tests__/validate.test.js.map +1 -0
  63. package/dist/core/archive.d.ts +2 -0
  64. package/dist/core/archive.d.ts.map +1 -0
  65. package/dist/core/archive.js +59 -0
  66. package/dist/core/archive.js.map +1 -0
  67. package/dist/core/auth.d.ts +15 -0
  68. package/dist/core/auth.d.ts.map +1 -0
  69. package/dist/core/auth.js +76 -0
  70. package/dist/core/auth.js.map +1 -0
  71. package/dist/core/codemod.d.ts +20 -0
  72. package/dist/core/codemod.d.ts.map +1 -0
  73. package/dist/core/codemod.js +150 -0
  74. package/dist/core/codemod.js.map +1 -0
  75. package/dist/core/fsx.d.ts +12 -0
  76. package/dist/core/fsx.d.ts.map +1 -0
  77. package/dist/core/fsx.js +70 -0
  78. package/dist/core/fsx.js.map +1 -0
  79. package/dist/core/http.d.ts +30 -0
  80. package/dist/core/http.d.ts.map +1 -0
  81. package/dist/core/http.js +95 -0
  82. package/dist/core/http.js.map +1 -0
  83. package/dist/core/journal.d.ts +18 -0
  84. package/dist/core/journal.d.ts.map +1 -0
  85. package/dist/core/journal.js +34 -0
  86. package/dist/core/journal.js.map +1 -0
  87. package/dist/core/log.d.ts +8 -0
  88. package/dist/core/log.d.ts.map +1 -0
  89. package/dist/core/log.js +9 -0
  90. package/dist/core/log.js.map +1 -0
  91. package/dist/core/pathGuard.d.ts +3 -0
  92. package/dist/core/pathGuard.d.ts.map +1 -0
  93. package/dist/core/pathGuard.js +18 -0
  94. package/dist/core/pathGuard.js.map +1 -0
  95. package/dist/core/paths.d.ts +11 -0
  96. package/dist/core/paths.d.ts.map +1 -0
  97. package/dist/core/paths.js +22 -0
  98. package/dist/core/paths.js.map +1 -0
  99. package/dist/core/validate.d.ts +8 -0
  100. package/dist/core/validate.d.ts.map +1 -0
  101. package/dist/core/validate.js +27 -0
  102. package/dist/core/validate.js.map +1 -0
  103. package/dist/index.d.ts +3 -0
  104. package/dist/index.d.ts.map +1 -0
  105. package/dist/index.js +23 -0
  106. package/dist/index.js.map +1 -0
  107. package/docs/decisions.md +55 -0
  108. package/package.json +39 -0
  109. package/recipes/audio-recorder/apps/native/src/app/audio-recorder/index.tsx +5 -0
  110. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-player.tsx +301 -0
  111. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-recorder.tsx +373 -0
  112. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/audio-waveform.tsx +270 -0
  113. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/index.ts +4 -0
  114. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/components/recording-list.tsx +89 -0
  115. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/audio-player-demo.tsx +66 -0
  116. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/audio-recorder-cloud.tsx +68 -0
  117. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/audio-recorder-interview.tsx +102 -0
  118. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/basic.tsx +27 -0
  119. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/index.ts +5 -0
  120. package/recipes/audio-recorder/apps/native/src/features/audio-recorder/demo/with-recording-list-demo.tsx +82 -0
  121. package/recipes/audio-recorder/recipe.json +22 -0
  122. package/recipes/audio-recorder@latest.zip +0 -0
  123. package/recipes/charts/apps/native/src/app/charts/index.tsx +3 -0
  124. package/recipes/charts/apps/native/src/features/charts/README.md +185 -0
  125. package/recipes/charts/apps/native/src/features/charts/app/preview.tsx +223 -0
  126. package/recipes/charts/apps/native/src/features/charts/components/area-chart.tsx +40 -0
  127. package/recipes/charts/apps/native/src/features/charts/components/bar-chart.tsx +143 -0
  128. package/recipes/charts/apps/native/src/features/charts/components/candlestick-chart.tsx +196 -0
  129. package/recipes/charts/apps/native/src/features/charts/components/chart-card.tsx +65 -0
  130. package/recipes/charts/apps/native/src/features/charts/components/column-chart.tsx +143 -0
  131. package/recipes/charts/apps/native/src/features/charts/components/doughnut-chart.tsx +246 -0
  132. package/recipes/charts/apps/native/src/features/charts/components/index.ts +10 -0
  133. package/recipes/charts/apps/native/src/features/charts/components/line-chart.tsx +308 -0
  134. package/recipes/charts/apps/native/src/features/charts/components/radar-chart.tsx +180 -0
  135. package/recipes/charts/apps/native/src/features/charts/components/radial-bar-chart.tsx +188 -0
  136. package/recipes/charts/apps/native/src/features/charts/components/stacked-area-chart.tsx +265 -0
  137. package/recipes/charts/apps/native/src/features/charts/components/stacked-bar-chart.tsx +322 -0
  138. package/recipes/charts/apps/native/src/features/charts/data/mock-data.ts +183 -0
  139. package/recipes/charts/apps/native/src/features/charts/types/index.ts +66 -0
  140. package/recipes/charts/recipe.json +22 -0
  141. package/recipes/charts@latest.zip +0 -0
  142. package/recipes/chatbot/apps/native/src/app/chatbot/index.tsx +1 -0
  143. package/recipes/chatbot/apps/native/src/features/chatbot/app/index.tsx +302 -0
  144. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-header-buttons.tsx +59 -0
  145. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-input-bar.tsx +469 -0
  146. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-markdown.tsx +575 -0
  147. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-message-bubble.tsx +246 -0
  148. package/recipes/chatbot/apps/native/src/features/chatbot/components/chat-settings-modal.tsx +161 -0
  149. package/recipes/chatbot/apps/native/src/features/chatbot/components/image-preview-list.tsx +115 -0
  150. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/code-block.tsx +165 -0
  151. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/index.ts +10 -0
  152. package/recipes/chatbot/apps/native/src/features/chatbot/components/markdown/table-renderer.tsx +129 -0
  153. package/recipes/chatbot/apps/native/src/features/chatbot/components/message-error-boundary.tsx +78 -0
  154. package/recipes/chatbot/apps/native/src/features/chatbot/components/message-list.tsx +173 -0
  155. package/recipes/chatbot/apps/native/src/features/chatbot/components/model-selector.tsx +283 -0
  156. package/recipes/chatbot/apps/native/src/features/chatbot/components/report-content-modal.tsx +188 -0
  157. package/recipes/chatbot/apps/native/src/features/chatbot/components/suggested-messages.tsx +67 -0
  158. package/recipes/chatbot/apps/native/src/features/chatbot/constants/models.ts +20 -0
  159. package/recipes/chatbot/apps/native/src/features/chatbot/constants/report-reasons.ts +9 -0
  160. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-attachment-cache.ts +143 -0
  161. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chat-config.ts +664 -0
  162. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chat-handlers.ts +359 -0
  163. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-chatbot-settings.ts +89 -0
  164. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-conversation.ts +79 -0
  165. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-image-picker.ts +122 -0
  166. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-keyboard-coordinator.ts +161 -0
  167. package/recipes/chatbot/apps/native/src/features/chatbot/hooks/use-smart-scroll-manager.ts +207 -0
  168. package/recipes/chatbot/apps/native/src/features/chatbot/models/index.ts +86 -0
  169. package/recipes/chatbot/apps/native/src/features/chatbot/models/models.ts +162 -0
  170. package/recipes/chatbot/apps/native/src/features/chatbot/models/providers.ts +62 -0
  171. package/recipes/chatbot/apps/native/src/features/chatbot/models/types.ts +40 -0
  172. package/recipes/chatbot/apps/native/src/features/chatbot/services/file-uploader.ts +238 -0
  173. package/recipes/chatbot/apps/native/src/features/chatbot/services/message-handler-service.ts +180 -0
  174. package/recipes/chatbot/apps/native/src/features/chatbot/types/index.ts +60 -0
  175. package/recipes/chatbot/apps/native/src/features/chatbot/utils/chat-telemetry.ts +91 -0
  176. package/recipes/chatbot/recipe.json +22 -0
  177. package/recipes/chatbot@latest.zip +0 -0
  178. package/recipes/image-generator/apps/native/src/app/image-generator/gallery.tsx +3 -0
  179. package/recipes/image-generator/apps/native/src/app/image-generator/index.tsx +3 -0
  180. package/recipes/image-generator/apps/native/src/features/image-generator/app/_layout.tsx +25 -0
  181. package/recipes/image-generator/apps/native/src/features/image-generator/app/gallery.tsx +217 -0
  182. package/recipes/image-generator/apps/native/src/features/image-generator/app/index.tsx +237 -0
  183. package/recipes/image-generator/apps/native/src/features/image-generator/components/gallery-image.tsx +26 -0
  184. package/recipes/image-generator/apps/native/src/features/image-generator/components/image-detail-modal.tsx +215 -0
  185. package/recipes/image-generator/apps/native/src/features/image-generator/components/image-model-selector.tsx +210 -0
  186. package/recipes/image-generator/apps/native/src/features/image-generator/components/image-placeholder.tsx +26 -0
  187. package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-gallery.ts +71 -0
  188. package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-generator-settings.ts +152 -0
  189. package/recipes/image-generator/apps/native/src/features/image-generator/hooks/use-image-generator.ts +93 -0
  190. package/recipes/image-generator/apps/native/src/features/image-generator/models/models.ts +66 -0
  191. package/recipes/image-generator/apps/native/src/features/image-generator/services/image-gallery-service.ts +98 -0
  192. package/recipes/image-generator/apps/native/src/features/image-generator/services/image-save-service.ts +121 -0
  193. package/recipes/image-generator/recipe.json +22 -0
  194. package/recipes/image-generator@latest.zip +0 -0
  195. package/recipes/quiz/apps/native/src/app/quiz/index.tsx +47 -0
  196. package/recipes/quiz/apps/native/src/features/quiz/components/question.tsx +67 -0
  197. package/recipes/quiz/apps/native/src/features/quiz/config.ts +11 -0
  198. package/recipes/quiz/apps/native/src/features/quiz/index.tsx +133 -0
  199. package/recipes/quiz/recipe.json +22 -0
  200. package/recipes/quiz@latest.zip +0 -0
  201. package/recipes/tracker-app/apps/native/src/app/tracker-app/index.tsx +1 -0
  202. package/recipes/tracker-app/apps/native/src/features/tracker-app/app/index.tsx +108 -0
  203. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/animated-number.tsx +102 -0
  204. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/calorie-card.tsx +66 -0
  205. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/circular-progress.tsx +97 -0
  206. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/floating-add-button.tsx +27 -0
  207. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/macro-card.tsx +80 -0
  208. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/promo-banner.tsx +98 -0
  209. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/recently-logged.tsx +64 -0
  210. package/recipes/tracker-app/apps/native/src/features/tracker-app/components/week-calendar.tsx +68 -0
  211. package/recipes/tracker-app/recipe.json +22 -0
  212. package/recipes/tracker-app@latest.zip +0 -0
  213. package/recipes/upload-all.sh +32 -0
  214. package/recipes/voice-bot/apps/native/src/app/voice-bot/index.tsx +27 -0
  215. package/recipes/voice-bot/apps/native/src/features/voice-bot/README.md +185 -0
  216. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/conversation-status.tsx +76 -0
  217. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/index.ts +4 -0
  218. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/message-input.tsx +98 -0
  219. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/voice-bot-screen.tsx +173 -0
  220. package/recipes/voice-bot/apps/native/src/features/voice-bot/components/voice-controls.tsx +73 -0
  221. package/recipes/voice-bot/apps/native/src/features/voice-bot/index.ts +3 -0
  222. package/recipes/voice-bot/apps/native/src/features/voice-bot/services/index.ts +1 -0
  223. package/recipes/voice-bot/apps/native/src/features/voice-bot/services/use-voice-bot.ts +161 -0
  224. package/recipes/voice-bot/apps/native/src/features/voice-bot/types.ts +29 -0
  225. package/recipes/voice-bot/recipe.json +22 -0
  226. package/recipes/voice-bot@latest.zip +0 -0
  227. package/scripts/create-recipes.mjs +189 -0
  228. package/src/commands/add.ts +183 -0
  229. package/src/commands/devices.ts +38 -0
  230. package/src/commands/doctor.ts +67 -0
  231. package/src/commands/list.ts +45 -0
  232. package/src/commands/login.ts +24 -0
  233. package/src/commands/logout.ts +15 -0
  234. package/src/commands/remove.ts +78 -0
  235. package/src/core/__tests__/journal.test.ts +119 -0
  236. package/src/core/__tests__/validate.test.ts +64 -0
  237. package/src/core/archive.ts +69 -0
  238. package/src/core/auth.ts +103 -0
  239. package/src/core/codemod.ts +211 -0
  240. package/src/core/fsx.ts +80 -0
  241. package/src/core/http.ts +136 -0
  242. package/src/core/journal.ts +64 -0
  243. package/src/core/log.ts +9 -0
  244. package/src/core/pathGuard.ts +22 -0
  245. package/src/core/paths.ts +33 -0
  246. package/src/core/validate.ts +44 -0
  247. package/src/index.ts +27 -0
  248. package/test-critical-cases.mjs +258 -0
  249. package/tsconfig.json +21 -0
  250. package/vitest.config.mts +12 -0
@@ -0,0 +1,150 @@
1
+ import { readFileContent, writeFileContent } from './fsx.js';
2
+ const NATIVE_START = '// --- @vibefast:features:start ---';
3
+ const NATIVE_END = '// --- @vibefast:features:end ---';
4
+ const WEB_START = '{/* @vibefast:nav:start */}';
5
+ const WEB_END = '{/* @vibefast:nav:end */}';
6
+ function escapeTsLiteral(value) {
7
+ return value
8
+ .replace(/\\/g, '\\\\')
9
+ .replace(/'/g, "\\'")
10
+ .replace(/\r/g, '\\r')
11
+ .replace(/\n/g, '\\n')
12
+ .replace(/\u2028/g, '\\u2028')
13
+ .replace(/\u2029/g, '\\u2029');
14
+ }
15
+ function escapeHtmlAttribute(value) {
16
+ return value
17
+ .replace(/&/g, '&')
18
+ .replace(/"/g, '"')
19
+ .replace(/'/g, ''')
20
+ .replace(/</g, '&lt;')
21
+ .replace(/>/g, '&gt;');
22
+ }
23
+ function escapeForRegex(value) {
24
+ return value.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
25
+ }
26
+ function safeNavId(value) {
27
+ const sanitized = value.replace(/[^a-zA-Z0-9_-]/g, '');
28
+ return sanitized || 'feature';
29
+ }
30
+ export async function insertNavLinkNative(filePath, link, options) {
31
+ const content = await readFileContent(filePath);
32
+ if (!content.includes(NATIVE_START) || !content.includes(NATIVE_END)) {
33
+ throw new Error(`Missing navigation markers in ${filePath}`);
34
+ }
35
+ // Check if link already exists by route
36
+ const routeCheck = link.href.replace('/(root)/(protected)/', '/');
37
+ const safeRoute = escapeTsLiteral(routeCheck);
38
+ if (content.includes(`route: '${safeRoute}'`)) {
39
+ return false; // Already exists, idempotent
40
+ }
41
+ // Create feature object for the vibefast-features.ts file
42
+ const featureId = safeNavId(link.href.split('/').pop() || 'feature');
43
+ const navItem = ` {
44
+ id: '${featureId}',
45
+ title: '${escapeTsLiteral(link.label)}',
46
+ icon: '${escapeTsLiteral(link.icon || '📦')}',
47
+ color: '${escapeTsLiteral(link.color || '#6366F1')}',
48
+ description: '${escapeTsLiteral(`${link.label} feature`)}',
49
+ route: '${safeRoute}',
50
+ testID: '${featureId}-button',
51
+ }`;
52
+ const startIdx = content.indexOf(NATIVE_START) + NATIVE_START.length;
53
+ const endIdx = content.indexOf(NATIVE_END);
54
+ const before = content.slice(0, startIdx);
55
+ const after = content.slice(endIdx);
56
+ const between = content.slice(startIdx, endIdx);
57
+ // Check if there are existing features (look for opening brace)
58
+ const hasExistingFeatures = between.includes('{');
59
+ let newContent;
60
+ if (hasExistingFeatures) {
61
+ // Add comma after new item since there are more items
62
+ newContent = `${before}\n${navItem},${between}${after}`;
63
+ }
64
+ else {
65
+ // First item, no comma needed
66
+ newContent = `${before}\n${navItem}\n ${after}`;
67
+ }
68
+ if (!options?.dryRun) {
69
+ await writeFileContent(filePath, newContent, { force: true });
70
+ }
71
+ return true;
72
+ }
73
+ export async function removeNavLinkNative(filePath, href, options) {
74
+ const content = await readFileContent(filePath);
75
+ const routeCheck = href.replace('/(root)/(protected)/', '/');
76
+ const safeRoute = escapeTsLiteral(routeCheck);
77
+ if (!content.includes(`route: '${safeRoute}'`)) {
78
+ return false; // Not found
79
+ }
80
+ // Use regex to remove the entire feature object including trailing comma
81
+ // Match: { ... route: '/charts' ... }, or { ... route: '/charts' ... }
82
+ const featureObjectRegex = new RegExp(`\\s*\\{[^}]*route:\\s*'${escapeForRegex(safeRoute)}'[^}]*\\},?\\s*`, 'gs');
83
+ const newContent = content.replace(featureObjectRegex, '');
84
+ if (!options?.dryRun) {
85
+ await writeFileContent(filePath, newContent, { force: true });
86
+ }
87
+ return true;
88
+ }
89
+ export async function insertNavLinkWeb(filePath, link, options) {
90
+ const content = await readFileContent(filePath);
91
+ if (!content.includes(WEB_START) || !content.includes(WEB_END)) {
92
+ throw new Error(`Missing navigation markers in ${filePath}`);
93
+ }
94
+ // Check if link already exists
95
+ const safeHref = escapeHtmlAttribute(link.href);
96
+ if (content.includes(`href="${safeHref}"`)) {
97
+ return false; // Already exists
98
+ }
99
+ const navCard = ` <Link href="${safeHref}" className="card">
100
+ <h3>{${JSON.stringify(link.label)}}</h3>
101
+ </Link>`;
102
+ const startIdx = content.indexOf(WEB_START) + WEB_START.length;
103
+ const endIdx = content.indexOf(WEB_END);
104
+ const before = content.slice(0, startIdx);
105
+ const after = content.slice(endIdx);
106
+ const existing = content.slice(startIdx, endIdx).trim();
107
+ const newContent = existing
108
+ ? `${before}\n${existing}\n${navCard}\n${after}`
109
+ : `${before}\n${navCard}\n${after}`;
110
+ if (!options?.dryRun) {
111
+ await writeFileContent(filePath, newContent, { force: true });
112
+ }
113
+ return true;
114
+ }
115
+ export async function removeNavLinkWeb(filePath, href, options) {
116
+ const content = await readFileContent(filePath);
117
+ const safeHref = escapeHtmlAttribute(href);
118
+ if (!content.includes(`href="${safeHref}"`)) {
119
+ return false;
120
+ }
121
+ const lines = content.split('\n');
122
+ const filtered = [];
123
+ let skipCount = 0;
124
+ for (let i = 0; i < lines.length; i++) {
125
+ const line = lines[i];
126
+ if (line.includes(`href="${safeHref}"`)) {
127
+ let start = i;
128
+ while (start > 0 && !lines[start].trim().startsWith('<Link')) {
129
+ start--;
130
+ }
131
+ let end = i;
132
+ while (end < lines.length && !lines[end].trim().startsWith('</Link>')) {
133
+ end++;
134
+ }
135
+ skipCount = end - start + 1;
136
+ i = end;
137
+ continue;
138
+ }
139
+ if (skipCount > 0) {
140
+ skipCount--;
141
+ continue;
142
+ }
143
+ filtered.push(line);
144
+ }
145
+ if (!options?.dryRun) {
146
+ await writeFileContent(filePath, filtered.join('\n'), { force: true });
147
+ }
148
+ return true;
149
+ }
150
+ //# sourceMappingURL=codemod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codemod.js","sourceRoot":"","sources":["../../src/core/codemod.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export declare function ensureDir(path: string): Promise<void>;
2
+ export declare function exists(path: string): Promise<boolean>;
3
+ export declare function readFileContent(path: string): Promise<string>;
4
+ export declare function writeFileContent(path: string, content: string, options?: {
5
+ force?: boolean;
6
+ }): Promise<void>;
7
+ export declare function deleteFile(path: string): Promise<void>;
8
+ export declare function copyTree(src: string, dest: string, options?: {
9
+ dryRun?: boolean;
10
+ force?: boolean;
11
+ }): Promise<string[]>;
12
+ //# sourceMappingURL=fsx.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fsx.d.ts","sourceRoot":"","sources":["../../src/core/fsx.ts"],"names":[],"mappings":"AAIA,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM3D;AAED,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO3D;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAEnE;AAED,wBAAsB,gBAAgB,CACpC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAC5B,OAAO,CAAC,IAAI,CAAC,CAOf;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAM5D;AAED,wBAAsB,QAAQ,CAC5B,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAC9C,OAAO,CAAC,MAAM,EAAE,CAAC,CA6BnB"}
@@ -0,0 +1,70 @@
1
+ import { mkdir, writeFile, readFile, rm, access, readdir, stat, copyFile } from 'fs/promises';
2
+ import { dirname, join } from 'path';
3
+ import { constants } from 'fs';
4
+ export async function ensureDir(path) {
5
+ try {
6
+ await mkdir(path, { recursive: true });
7
+ }
8
+ catch (err) {
9
+ if (err.code !== 'EEXIST')
10
+ throw err;
11
+ }
12
+ }
13
+ export async function exists(path) {
14
+ try {
15
+ await access(path, constants.F_OK);
16
+ return true;
17
+ }
18
+ catch {
19
+ return false;
20
+ }
21
+ }
22
+ export async function readFileContent(path) {
23
+ return readFile(path, 'utf-8');
24
+ }
25
+ export async function writeFileContent(path, content, options) {
26
+ const fileExists = await exists(path);
27
+ if (fileExists && !options?.force) {
28
+ throw new Error(`File already exists: ${path}. Use --force to overwrite.`);
29
+ }
30
+ await ensureDir(dirname(path));
31
+ await writeFile(path, content, 'utf-8');
32
+ }
33
+ export async function deleteFile(path) {
34
+ try {
35
+ await rm(path, { recursive: true, force: true });
36
+ }
37
+ catch (err) {
38
+ if (err.code !== 'ENOENT')
39
+ throw err;
40
+ }
41
+ }
42
+ export async function copyTree(src, dest, options) {
43
+ const copied = [];
44
+ async function copyRecursive(srcPath, destPath) {
45
+ const stats = await stat(srcPath);
46
+ if (stats.isDirectory()) {
47
+ if (!options?.dryRun) {
48
+ await ensureDir(destPath);
49
+ }
50
+ const entries = await readdir(srcPath);
51
+ for (const entry of entries) {
52
+ await copyRecursive(join(srcPath, entry), join(destPath, entry));
53
+ }
54
+ }
55
+ else {
56
+ const destExists = await exists(destPath);
57
+ if (destExists && !options?.force) {
58
+ throw new Error(`File exists: ${destPath}. Use --force to overwrite.`);
59
+ }
60
+ if (!options?.dryRun) {
61
+ await ensureDir(dirname(destPath));
62
+ await copyFile(srcPath, destPath);
63
+ }
64
+ copied.push(destPath);
65
+ }
66
+ }
67
+ await copyRecursive(src, dest);
68
+ return copied;
69
+ }
70
+ //# sourceMappingURL=fsx.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fsx.js","sourceRoot":"","sources":["../../src/core/fsx.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ export interface RecipeFetchRequest {
2
+ token: string;
3
+ device: {
4
+ id: string;
5
+ os: string;
6
+ arch: string;
7
+ version: string;
8
+ };
9
+ feature: string;
10
+ target: string;
11
+ starter: {
12
+ name: string;
13
+ version: string;
14
+ };
15
+ }
16
+ export interface RecipeFetchResponse {
17
+ ok: boolean;
18
+ signedUrl?: string;
19
+ zipData?: string;
20
+ expiresIn?: number;
21
+ watermark?: string;
22
+ error?: string;
23
+ message?: string;
24
+ }
25
+ export declare function fetchRecipe(request: RecipeFetchRequest): Promise<RecipeFetchResponse>;
26
+ export declare function downloadZip(signedUrlOrBase64: string, isBase64?: boolean): Promise<string>;
27
+ export declare function listRecipes(token: string): Promise<any>;
28
+ export declare function listDevices(token: string): Promise<any>;
29
+ export declare function deactivateDevice(token: string, deviceId: string): Promise<void>;
30
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/core/http.ts"],"names":[],"mappings":"AAKA,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE;QACN,EAAE,EAAE,MAAM,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH;AAED,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAID,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA0B3F;AAED,wBAAsB,WAAW,CAAC,iBAAiB,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,OAAO,CAAC,MAAM,CAAC,CAyB9F;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAiB7D;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAa7D;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAarF"}
@@ -0,0 +1,95 @@
1
+ import { writeFile, mkdir } from 'fs/promises';
2
+ import { join } from 'path';
3
+ import { tmpdir } from 'os';
4
+ import { randomUUID } from 'crypto';
5
+ const WORKER_URL = process.env.VIBEFAST_WORKER_URL || 'https://vibefast-cli-worker.mzafar611.workers.dev';
6
+ export async function fetchRecipe(request) {
7
+ try {
8
+ const response = await fetch(`${WORKER_URL}/api/recipe/fetch`, {
9
+ method: 'POST',
10
+ headers: {
11
+ 'Content-Type': 'application/json',
12
+ },
13
+ body: JSON.stringify(request),
14
+ });
15
+ if (!response.ok) {
16
+ const error = await response.json().catch(() => ({ message: response.statusText }));
17
+ return {
18
+ ok: false,
19
+ error: error.message || `HTTP ${response.status}`,
20
+ };
21
+ }
22
+ return response.json();
23
+ }
24
+ catch (err) {
25
+ return {
26
+ ok: false,
27
+ error: 'Network error',
28
+ message: `Failed to connect to ${WORKER_URL}: ${err.message}`,
29
+ };
30
+ }
31
+ }
32
+ export async function downloadZip(signedUrlOrBase64, isBase64 = false) {
33
+ let buffer;
34
+ if (isBase64) {
35
+ // Decode base64 data
36
+ buffer = Buffer.from(signedUrlOrBase64, 'base64');
37
+ }
38
+ else {
39
+ // Download from URL
40
+ const response = await fetch(signedUrlOrBase64);
41
+ if (!response.ok) {
42
+ throw new Error(`Failed to download recipe: ${response.statusText}`);
43
+ }
44
+ const arrayBuffer = await response.arrayBuffer();
45
+ buffer = Buffer.from(arrayBuffer);
46
+ }
47
+ const tempDir = join(tmpdir(), 'vibefast', randomUUID());
48
+ await mkdir(tempDir, { recursive: true });
49
+ const zipPath = join(tempDir, 'recipe.zip');
50
+ await writeFile(zipPath, buffer);
51
+ return zipPath;
52
+ }
53
+ export async function listRecipes(token) {
54
+ try {
55
+ const response = await fetch(`${WORKER_URL}/api/recipes/list`, {
56
+ method: 'GET',
57
+ headers: {
58
+ 'Authorization': `Bearer ${token}`,
59
+ },
60
+ });
61
+ if (!response.ok) {
62
+ throw new Error(`Failed to fetch recipes: ${response.statusText}`);
63
+ }
64
+ return response.json();
65
+ }
66
+ catch (err) {
67
+ throw new Error(`Failed to connect to ${WORKER_URL}: ${err.message}`);
68
+ }
69
+ }
70
+ export async function listDevices(token) {
71
+ const response = await fetch(`${WORKER_URL}/api/devices/list`, {
72
+ method: 'GET',
73
+ headers: {
74
+ 'Authorization': `Bearer ${token}`,
75
+ },
76
+ });
77
+ if (!response.ok) {
78
+ throw new Error(`Failed to fetch devices: ${response.statusText}`);
79
+ }
80
+ return response.json();
81
+ }
82
+ export async function deactivateDevice(token, deviceId) {
83
+ const response = await fetch(`${WORKER_URL}/api/devices/deactivate`, {
84
+ method: 'POST',
85
+ headers: {
86
+ 'Authorization': `Bearer ${token}`,
87
+ 'Content-Type': 'application/json',
88
+ },
89
+ body: JSON.stringify({ deviceId }),
90
+ });
91
+ if (!response.ok) {
92
+ throw new Error(`Failed to deactivate device: ${response.statusText}`);
93
+ }
94
+ }
95
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/core/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAC5B,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AA4BpC,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,mDAAmD,CAAC;AAE1G,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA2B;IAC3D,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,mBAAmB,EAAE;YAC7D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;SAC9B,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,KAAK,GAAQ,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC;YACzF,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,KAAK,EAAE,KAAK,CAAC,OAAO,IAAI,QAAQ,QAAQ,CAAC,MAAM,EAAE;aAClD,CAAC;QACJ,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,EAAkC,CAAC;IACzD,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,eAAe;YACtB,OAAO,EAAE,wBAAwB,UAAU,KAAK,GAAG,CAAC,OAAO,EAAE;SAC9D,CAAC;IACJ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,iBAAyB,EAAE,QAAQ,GAAG,KAAK;IAC3E,IAAI,MAAc,CAAC;IAEnB,IAAI,QAAQ,EAAE,CAAC;QACb,qBAAqB;QACrB,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC;IACpD,CAAC;SAAM,CAAC;QACN,oBAAoB;QACpB,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAEhD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,8BAA8B,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC;QACjD,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACpC,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CAAC;IACzD,MAAM,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC5C,MAAM,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAEjC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAa;IAC7C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,mBAAmB,EAAE;YAC7D,MAAM,EAAE,KAAK;YACb,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,KAAK,EAAE;aACnC;SACF,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;QACrE,CAAC;QAED,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;IACzB,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,MAAM,IAAI,KAAK,CAAC,wBAAwB,UAAU,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;IACxE,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAa;IAC7C,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,mBAAmB,EAAE;QAC7D,MAAM,EAAE,KAAK;QACb,OAAO,EAAE;YACP,eAAe,EAAE,UAAU,KAAK,EAAE;SACnC;KACF,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,4BAA4B,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IACrE,CAAC;IAED,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAa,EAAE,QAAgB;IACpE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,UAAU,yBAAyB,EAAE;QACnE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,eAAe,EAAE,UAAU,KAAK,EAAE;YAClC,cAAc,EAAE,kBAAkB;SACnC;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;KACnC,CAAC,CAAC;IAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,gCAAgC,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;IACzE,CAAC;AACH,CAAC"}
@@ -0,0 +1,18 @@
1
+ export interface JournalEntry {
2
+ feature: string;
3
+ target: 'native' | 'web';
4
+ files: string[];
5
+ insertedNav: boolean;
6
+ ts: number;
7
+ navHref?: string;
8
+ navLabel?: string;
9
+ }
10
+ export interface Journal {
11
+ entries: JournalEntry[];
12
+ }
13
+ export declare function readJournal(journalPath: string): Promise<Journal>;
14
+ export declare function writeJournal(journalPath: string, journal: Journal): Promise<void>;
15
+ export declare function addEntry(journalPath: string, entry: JournalEntry): Promise<void>;
16
+ export declare function removeEntry(journalPath: string, feature: string, target: 'native' | 'web'): Promise<JournalEntry | null>;
17
+ export declare function getEntry(journalPath: string, feature: string, target: 'native' | 'web'): Promise<JournalEntry | null>;
18
+ //# sourceMappingURL=journal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal.d.ts","sourceRoot":"","sources":["../../src/core/journal.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,QAAQ,GAAG,KAAK,CAAC;IACzB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,WAAW,EAAE,OAAO,CAAC;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,OAAO;IACtB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AAED,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAMvE;AAED,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAGvF;AAED,wBAAsB,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAQtF;AAED,wBAAsB,WAAW,CAC/B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,QAAQ,GAAG,KAAK,GACvB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAU9B;AAED,wBAAsB,QAAQ,CAC5B,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,QAAQ,GAAG,KAAK,GACvB,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAG9B"}
@@ -0,0 +1,34 @@
1
+ import { readFileContent, writeFileContent, exists, ensureDir } from './fsx.js';
2
+ import { dirname } from 'path';
3
+ export async function readJournal(journalPath) {
4
+ if (!(await exists(journalPath))) {
5
+ return { entries: [] };
6
+ }
7
+ const content = await readFileContent(journalPath);
8
+ return JSON.parse(content);
9
+ }
10
+ export async function writeJournal(journalPath, journal) {
11
+ await ensureDir(dirname(journalPath));
12
+ await writeFileContent(journalPath, JSON.stringify(journal, null, 2), { force: true });
13
+ }
14
+ export async function addEntry(journalPath, entry) {
15
+ const journal = await readJournal(journalPath);
16
+ // Remove existing entry for same feature+target
17
+ journal.entries = journal.entries.filter(e => !(e.feature === entry.feature && e.target === entry.target));
18
+ journal.entries.push(entry);
19
+ await writeJournal(journalPath, journal);
20
+ }
21
+ export async function removeEntry(journalPath, feature, target) {
22
+ const journal = await readJournal(journalPath);
23
+ const entry = journal.entries.find(e => e.feature === feature && e.target === target);
24
+ if (!entry)
25
+ return null;
26
+ journal.entries = journal.entries.filter(e => !(e.feature === feature && e.target === target));
27
+ await writeJournal(journalPath, journal);
28
+ return entry;
29
+ }
30
+ export async function getEntry(journalPath, feature, target) {
31
+ const journal = await readJournal(journalPath);
32
+ return journal.entries.find(e => e.feature === feature && e.target === target) || null;
33
+ }
34
+ //# sourceMappingURL=journal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"journal.js","sourceRoot":"","sources":["../../src/core/journal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAChF,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAgB/B,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,WAAmB;IACnD,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC,EAAE,CAAC;QACjC,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC;IACzB,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,WAAW,CAAC,CAAC;IACnD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,WAAmB,EAAE,OAAgB;IACtE,MAAM,SAAS,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC;IACtC,MAAM,gBAAgB,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACzF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,WAAmB,EAAE,KAAmB;IACrE,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC;IAC/C,gDAAgD;IAChD,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CACtC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,CAAC,CACjE,CAAC;IACF,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5B,MAAM,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,WAAmB,EACnB,OAAe,EACf,MAAwB;IAExB,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IACtF,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IAExB,OAAO,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CACtC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CACrD,CAAC;IACF,MAAM,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IACzC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,WAAmB,EACnB,OAAe,EACf,MAAwB;IAExB,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,WAAW,CAAC,CAAC;IAC/C,OAAO,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,KAAK,OAAO,IAAI,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC;AACzF,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare const log: {
2
+ success: (msg: string) => void;
3
+ info: (msg: string) => void;
4
+ warn: (msg: string) => void;
5
+ error: (msg: string) => void;
6
+ plain: (msg: string) => void;
7
+ };
8
+ //# sourceMappingURL=log.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../../src/core/log.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,GAAG;mBACC,MAAM;gBACT,MAAM;gBACN,MAAM;iBACL,MAAM;iBACN,MAAM;CACpB,CAAC"}
@@ -0,0 +1,9 @@
1
+ import pc from 'picocolors';
2
+ export const log = {
3
+ success: (msg) => console.log(pc.green('✓'), msg),
4
+ info: (msg) => console.log(pc.blue('ℹ'), msg),
5
+ warn: (msg) => console.log(pc.yellow('⚠'), msg),
6
+ error: (msg) => console.error(pc.red('✗'), msg),
7
+ plain: (msg) => console.log(msg),
8
+ };
9
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/core/log.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,OAAO,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IACzD,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IACrD,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IACvD,KAAK,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IACvD,KAAK,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;CACzC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare function isSubPath(basePath: string, targetPath: string): boolean;
2
+ export declare function ensureWithinBase(basePath: string, targetPath: string, label: string): string;
3
+ //# sourceMappingURL=pathGuard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pathGuard.d.ts","sourceRoot":"","sources":["../../src/core/pathGuard.ts"],"names":[],"mappings":"AAMA,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAIvE;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAS5F"}
@@ -0,0 +1,18 @@
1
+ import { resolve, sep } from 'path';
2
+ function withTrailingSep(path) {
3
+ return path.endsWith(sep) ? path : `${path}${sep}`;
4
+ }
5
+ export function isSubPath(basePath, targetPath) {
6
+ const base = withTrailingSep(resolve(basePath));
7
+ const target = resolve(targetPath);
8
+ return target === base.slice(0, -1) || target.startsWith(base);
9
+ }
10
+ export function ensureWithinBase(basePath, targetPath, label) {
11
+ const base = resolve(basePath);
12
+ const target = resolve(targetPath);
13
+ if (!isSubPath(base, target)) {
14
+ throw new Error(`${label} must stay within ${base}`);
15
+ }
16
+ return target;
17
+ }
18
+ //# sourceMappingURL=pathGuard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pathGuard.js","sourceRoot":"","sources":["../../src/core/pathGuard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,MAAM,CAAC;AAEpC,SAAS,eAAe,CAAC,IAAY;IACnC,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,GAAG,EAAE,CAAC;AACrD,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAgB,EAAE,UAAkB;IAC5D,MAAM,IAAI,GAAG,eAAe,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IACnC,OAAO,MAAM,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,UAAkB,EAAE,KAAa;IAClF,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAEnC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,qBAAqB,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,11 @@
1
+ export interface PathsConfig {
2
+ cwd: string;
3
+ signatureFile: string;
4
+ journalFile: string;
5
+ configDir: string;
6
+ nativeNavFile: string;
7
+ webNavFile: string;
8
+ }
9
+ export declare function getPaths(cwd?: string): PathsConfig;
10
+ export declare function getConfigPath(): string;
11
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAgB,QAAQ,CAAC,GAAG,GAAE,MAAsB,GAAG,WAAW,CASjE;AAED,wBAAgB,aAAa,IAAI,MAAM,CAStC"}
@@ -0,0 +1,22 @@
1
+ import { join, resolve } from 'path';
2
+ import { homedir } from 'os';
3
+ export function getPaths(cwd = process.cwd()) {
4
+ return {
5
+ cwd,
6
+ signatureFile: join(cwd, '.vibefast', 'starter.json'),
7
+ journalFile: join(cwd, '.vibefast', 'journal.json'),
8
+ configDir: join(homedir(), '.vibefast'),
9
+ nativeNavFile: join(cwd, 'apps', 'native', 'src', 'features', 'vibefast-features.ts'),
10
+ webNavFile: join(cwd, 'apps', 'web', 'app', 'page.tsx'),
11
+ };
12
+ }
13
+ export function getConfigPath() {
14
+ const directPath = process.env.VIBEFAST_CONFIG_PATH;
15
+ if (directPath) {
16
+ return resolve(directPath);
17
+ }
18
+ const customDir = process.env.VIBEFAST_CONFIG_DIR;
19
+ const baseDir = customDir ? resolve(customDir) : join(homedir(), '.vibefast');
20
+ return join(baseDir, 'config.json');
21
+ }
22
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../src/core/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAW7B,MAAM,UAAU,QAAQ,CAAC,MAAc,OAAO,CAAC,GAAG,EAAE;IAClD,OAAO;QACL,GAAG;QACH,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,cAAc,CAAC;QACrD,WAAW,EAAE,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,cAAc,CAAC;QACnD,SAAS,EAAE,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC;QACvC,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,UAAU,EAAE,sBAAsB,CAAC;QACrF,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC;KACxD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;IACpD,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC;IAC7B,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;IAClD,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,WAAW,CAAC,CAAC;IAC9E,OAAO,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,8 @@
1
+ export interface StarterConfig {
2
+ name: string;
3
+ version: string;
4
+ targets: string[];
5
+ }
6
+ export declare function validateSignature(signaturePath: string): Promise<StarterConfig>;
7
+ export declare function validateTarget(target: string, availableTargets: string[]): void;
8
+ //# sourceMappingURL=validate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/core/validate.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,wBAAsB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CA2BrF;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,GAAG,IAAI,CAM/E"}
@@ -0,0 +1,27 @@
1
+ import { readFileContent, exists } from './fsx.js';
2
+ export async function validateSignature(signaturePath) {
3
+ if (!(await exists(signaturePath))) {
4
+ throw new Error('Not a VibeFast repo. Missing .vibefast/starter.json. Run this command from your VibeFast monorepo root.');
5
+ }
6
+ const content = await readFileContent(signaturePath);
7
+ let config;
8
+ try {
9
+ config = JSON.parse(content);
10
+ }
11
+ catch {
12
+ throw new Error('Invalid .vibefast/starter.json: not valid JSON');
13
+ }
14
+ if (config.name !== 'vibefast') {
15
+ throw new Error(`Invalid starter name: expected "vibefast", got "${config.name}"`);
16
+ }
17
+ if (!Array.isArray(config.targets) || config.targets.length === 0) {
18
+ throw new Error('Invalid .vibefast/starter.json: targets must be a non-empty array');
19
+ }
20
+ return config;
21
+ }
22
+ export function validateTarget(target, availableTargets) {
23
+ if (!availableTargets.includes(target)) {
24
+ throw new Error(`Invalid target "${target}". Available: ${availableTargets.join(', ')}`);
25
+ }
26
+ }
27
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/core/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAQnD,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,aAAqB;IAC3D,IAAI,CAAC,CAAC,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CACb,yGAAyG,CAC1G,CAAC;IACJ,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,aAAa,CAAC,CAAC;IACrD,IAAI,MAAqB,CAAC;IAE1B,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CACb,mDAAmD,MAAM,CAAC,IAAI,GAAG,CAClE,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClE,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAC;IACvF,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAc,EAAE,gBAA0B;IACvE,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CACb,mBAAmB,MAAM,iBAAiB,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACxE,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}