@superblocksteam/vite-plugin-file-sync 2.0.83 → 2.0.84-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (315) hide show
  1. package/dist/ai-service/agent/middleware.d.ts +36 -0
  2. package/dist/ai-service/agent/middleware.d.ts.map +1 -1
  3. package/dist/ai-service/agent/middleware.js +65 -1
  4. package/dist/ai-service/agent/middleware.js.map +1 -1
  5. package/dist/ai-service/agent/prompts/build-base-system-prompt.d.ts +1 -1
  6. package/dist/ai-service/agent/prompts/build-base-system-prompt.d.ts.map +1 -1
  7. package/dist/ai-service/agent/prompts/build-base-system-prompt.js +101 -57
  8. package/dist/ai-service/agent/prompts/build-base-system-prompt.js.map +1 -1
  9. package/dist/ai-service/agent/tool-message-utils.js +1 -1
  10. package/dist/ai-service/agent/tool-message-utils.js.map +1 -1
  11. package/dist/ai-service/agent/tools/apis/api-executor.js +1 -1
  12. package/dist/ai-service/agent/tools/apis/api-executor.js.map +1 -1
  13. package/dist/ai-service/agent/tools/apis/api-validation-orchestrator.d.ts.map +1 -1
  14. package/dist/ai-service/agent/tools/apis/api-validation-orchestrator.js +1 -1
  15. package/dist/ai-service/agent/tools/apis/api-validation-orchestrator.js.map +1 -1
  16. package/dist/ai-service/agent/tools/apis/build-api-artifact.d.ts.map +1 -1
  17. package/dist/ai-service/agent/tools/apis/build-api-artifact.js +23 -7
  18. package/dist/ai-service/agent/tools/apis/build-api-artifact.js.map +1 -1
  19. package/dist/ai-service/agent/tools/apis/build-api.d.ts.map +1 -1
  20. package/dist/ai-service/agent/tools/apis/build-api.js +36 -19
  21. package/dist/ai-service/agent/tools/apis/build-api.js.map +1 -1
  22. package/dist/ai-service/agent/tools/apis/get-api-docs.d.ts +1 -1
  23. package/dist/ai-service/agent/tools/apis/sample-json.js +1 -1
  24. package/dist/ai-service/agent/tools/apis/sample-json.js.map +1 -1
  25. package/dist/ai-service/agent/tools/apis/test-api.d.ts +11 -1
  26. package/dist/ai-service/agent/tools/apis/test-api.d.ts.map +1 -1
  27. package/dist/ai-service/agent/tools/apis/test-api.js +95 -54
  28. package/dist/ai-service/agent/tools/apis/test-api.js.map +1 -1
  29. package/dist/ai-service/agent/tools/build-capture-screenshot.d.ts +6 -1
  30. package/dist/ai-service/agent/tools/build-capture-screenshot.d.ts.map +1 -1
  31. package/dist/ai-service/agent/tools/build-capture-screenshot.js +26 -12
  32. package/dist/ai-service/agent/tools/build-capture-screenshot.js.map +1 -1
  33. package/dist/ai-service/agent/tools/build-debug.d.ts.map +1 -1
  34. package/dist/ai-service/agent/tools/build-debug.js +30 -10
  35. package/dist/ai-service/agent/tools/build-debug.js.map +1 -1
  36. package/dist/ai-service/agent/tools/build-delete-file.d.ts.map +1 -1
  37. package/dist/ai-service/agent/tools/build-delete-file.js +6 -2
  38. package/dist/ai-service/agent/tools/build-delete-file.js.map +1 -1
  39. package/dist/ai-service/agent/tools/build-edit-file.d.ts.map +1 -1
  40. package/dist/ai-service/agent/tools/build-edit-file.js +20 -5
  41. package/dist/ai-service/agent/tools/build-edit-file.js.map +1 -1
  42. package/dist/ai-service/agent/tools/build-finalize.d.ts.map +1 -1
  43. package/dist/ai-service/agent/tools/build-finalize.js +30 -4
  44. package/dist/ai-service/agent/tools/build-finalize.js.map +1 -1
  45. package/dist/ai-service/agent/tools/build-manage-checklist.d.ts +1 -1
  46. package/dist/ai-service/agent/tools/build-multi-edit-file.d.ts.map +1 -1
  47. package/dist/ai-service/agent/tools/build-multi-edit-file.js +14 -4
  48. package/dist/ai-service/agent/tools/build-multi-edit-file.js.map +1 -1
  49. package/dist/ai-service/agent/tools/build-read-file.d.ts.map +1 -1
  50. package/dist/ai-service/agent/tools/build-read-file.js +23 -11
  51. package/dist/ai-service/agent/tools/build-read-file.js.map +1 -1
  52. package/dist/ai-service/agent/tools/debug-cache.js +1 -1
  53. package/dist/ai-service/agent/tools/debug-cache.js.map +1 -1
  54. package/dist/ai-service/agent/tools/get-logs.d.ts +72 -0
  55. package/dist/ai-service/agent/tools/get-logs.d.ts.map +1 -0
  56. package/dist/ai-service/agent/tools/get-logs.js +343 -0
  57. package/dist/ai-service/agent/tools/get-logs.js.map +1 -0
  58. package/dist/ai-service/agent/tools/index.d.ts +1 -1
  59. package/dist/ai-service/agent/tools/index.d.ts.map +1 -1
  60. package/dist/ai-service/agent/tools/index.js +1 -1
  61. package/dist/ai-service/agent/tools/index.js.map +1 -1
  62. package/dist/ai-service/agent/tools/integrations/errors.d.ts +9 -0
  63. package/dist/ai-service/agent/tools/integrations/errors.d.ts.map +1 -0
  64. package/dist/ai-service/agent/tools/integrations/errors.js +35 -0
  65. package/dist/ai-service/agent/tools/integrations/errors.js.map +1 -0
  66. package/dist/ai-service/agent/tools/integrations/execute-request.d.ts.map +1 -1
  67. package/dist/ai-service/agent/tools/integrations/execute-request.js +20 -5
  68. package/dist/ai-service/agent/tools/integrations/execute-request.js.map +1 -1
  69. package/dist/ai-service/agent/tools/integrations/internal.d.ts.map +1 -1
  70. package/dist/ai-service/agent/tools/integrations/internal.js +12 -3
  71. package/dist/ai-service/agent/tools/integrations/internal.js.map +1 -1
  72. package/dist/ai-service/agent/tools.d.ts.map +1 -1
  73. package/dist/ai-service/agent/tools.js +19 -28
  74. package/dist/ai-service/agent/tools.js.map +1 -1
  75. package/dist/ai-service/agent/tools2/registry.d.ts.map +1 -1
  76. package/dist/ai-service/agent/tools2/registry.js +37 -15
  77. package/dist/ai-service/agent/tools2/registry.js.map +1 -1
  78. package/dist/ai-service/agent/tools2/tools/bash.d.ts +1 -1
  79. package/dist/ai-service/agent/tools2/tools/edit.d.ts.map +1 -1
  80. package/dist/ai-service/agent/tools2/tools/edit.js +9 -4
  81. package/dist/ai-service/agent/tools2/tools/edit.js.map +1 -1
  82. package/dist/ai-service/agent/tools2/tools/grep.d.ts.map +1 -1
  83. package/dist/ai-service/agent/tools2/tools/grep.js +73 -7
  84. package/dist/ai-service/agent/tools2/tools/grep.js.map +1 -1
  85. package/dist/ai-service/agent/tools2/tools/read.d.ts.map +1 -1
  86. package/dist/ai-service/agent/tools2/tools/read.js +9 -4
  87. package/dist/ai-service/agent/tools2/tools/read.js.map +1 -1
  88. package/dist/ai-service/agent/tools2/types.d.ts +40 -8
  89. package/dist/ai-service/agent/tools2/types.d.ts.map +1 -1
  90. package/dist/ai-service/agent/tools2/types.js +41 -3
  91. package/dist/ai-service/agent/tools2/types.js.map +1 -1
  92. package/dist/ai-service/app-interface/filesystem/handlers/skill-handler.d.ts +0 -1
  93. package/dist/ai-service/app-interface/filesystem/handlers/skill-handler.d.ts.map +1 -1
  94. package/dist/ai-service/app-interface/filesystem/handlers/skill-handler.js +60 -54
  95. package/dist/ai-service/app-interface/filesystem/handlers/skill-handler.js.map +1 -1
  96. package/dist/ai-service/chat/chat-session-store.d.ts +6 -0
  97. package/dist/ai-service/chat/chat-session-store.d.ts.map +1 -1
  98. package/dist/ai-service/chat/chat-session-store.js +44 -0
  99. package/dist/ai-service/chat/chat-session-store.js.map +1 -1
  100. package/dist/ai-service/facts/helpers.d.ts +9 -0
  101. package/dist/ai-service/facts/helpers.d.ts.map +1 -0
  102. package/dist/ai-service/facts/helpers.js +72 -0
  103. package/dist/ai-service/facts/helpers.js.map +1 -0
  104. package/dist/ai-service/facts/index.d.ts +4 -0
  105. package/dist/ai-service/facts/index.d.ts.map +1 -0
  106. package/dist/ai-service/facts/index.js +3 -0
  107. package/dist/ai-service/facts/index.js.map +1 -0
  108. package/dist/ai-service/facts/knowledge-manager.d.ts +50 -0
  109. package/dist/ai-service/facts/knowledge-manager.d.ts.map +1 -0
  110. package/dist/ai-service/facts/knowledge-manager.js +195 -0
  111. package/dist/ai-service/facts/knowledge-manager.js.map +1 -0
  112. package/dist/ai-service/features.d.ts +8 -0
  113. package/dist/ai-service/features.d.ts.map +1 -1
  114. package/dist/ai-service/features.js +8 -0
  115. package/dist/ai-service/features.js.map +1 -1
  116. package/dist/ai-service/index.d.ts +34 -2
  117. package/dist/ai-service/index.d.ts.map +1 -1
  118. package/dist/ai-service/index.js +112 -18
  119. package/dist/ai-service/index.js.map +1 -1
  120. package/dist/ai-service/integrations/metadata-storage/local.d.ts.map +1 -1
  121. package/dist/ai-service/integrations/metadata-storage/local.js +4 -2
  122. package/dist/ai-service/integrations/metadata-storage/local.js.map +1 -1
  123. package/dist/ai-service/integrations/store.d.ts +6 -3
  124. package/dist/ai-service/integrations/store.d.ts.map +1 -1
  125. package/dist/ai-service/integrations/store.js +96 -6
  126. package/dist/ai-service/integrations/store.js.map +1 -1
  127. package/dist/ai-service/judge/judge-executor.js +1 -1
  128. package/dist/ai-service/judge/judge-executor.js.map +1 -1
  129. package/dist/ai-service/judge/tools/playwright-action.d.ts +1 -1
  130. package/dist/ai-service/llm/client.d.ts.map +1 -1
  131. package/dist/ai-service/llm/client.js +26 -13
  132. package/dist/ai-service/llm/client.js.map +1 -1
  133. package/dist/ai-service/llm/context-v2/adapter.d.ts +2 -0
  134. package/dist/ai-service/llm/context-v2/adapter.d.ts.map +1 -1
  135. package/dist/ai-service/llm/context-v2/adapter.js +6 -0
  136. package/dist/ai-service/llm/context-v2/adapter.js.map +1 -1
  137. package/dist/ai-service/llm/context-v2/context.d.ts +19 -0
  138. package/dist/ai-service/llm/context-v2/context.d.ts.map +1 -1
  139. package/dist/ai-service/llm/context-v2/context.js +64 -1
  140. package/dist/ai-service/llm/context-v2/context.js.map +1 -1
  141. package/dist/ai-service/llm/context-v2/conversation-context.d.ts +11 -1
  142. package/dist/ai-service/llm/context-v2/conversation-context.d.ts.map +1 -1
  143. package/dist/ai-service/llm/context-v2/manager.d.ts.map +1 -1
  144. package/dist/ai-service/llm/context-v2/manager.js +5 -0
  145. package/dist/ai-service/llm/context-v2/manager.js.map +1 -1
  146. package/dist/ai-service/llm/context-v2/phase1-tool-summarizer.d.ts +1 -1
  147. package/dist/ai-service/llm/context-v2/phase1-tool-summarizer.d.ts.map +1 -1
  148. package/dist/ai-service/llm/context-v2/phase1-tool-summarizer.js +42 -6
  149. package/dist/ai-service/llm/context-v2/phase1-tool-summarizer.js.map +1 -1
  150. package/dist/ai-service/llm/context-v2/types.d.ts +4 -0
  151. package/dist/ai-service/llm/context-v2/types.d.ts.map +1 -1
  152. package/dist/ai-service/llm/context-v2/types.js.map +1 -1
  153. package/dist/ai-service/llm/error.js +1 -1
  154. package/dist/ai-service/llm/error.js.map +1 -1
  155. package/dist/ai-service/llm/interaction/adapters/vercel.js +5 -5
  156. package/dist/ai-service/llm/stream/config.d.ts +1 -1
  157. package/dist/ai-service/llm/stream/config.d.ts.map +1 -1
  158. package/dist/ai-service/llm/stream/config.js.map +1 -1
  159. package/dist/ai-service/llm/stream/observers/llmobs.js +1 -1
  160. package/dist/ai-service/llm/stream/observers/llmobs.js.map +1 -1
  161. package/dist/ai-service/llm/stream/observers/logging.d.ts +20 -0
  162. package/dist/ai-service/llm/stream/observers/logging.d.ts.map +1 -1
  163. package/dist/ai-service/llm/stream/observers/logging.js +115 -18
  164. package/dist/ai-service/llm/stream/observers/logging.js.map +1 -1
  165. package/dist/ai-service/llm/stream/observers/retry-notification.d.ts.map +1 -1
  166. package/dist/ai-service/llm/stream/observers/retry-notification.js +2 -1
  167. package/dist/ai-service/llm/stream/observers/retry-notification.js.map +1 -1
  168. package/dist/ai-service/llm/stream/orchestrator.js +4 -4
  169. package/dist/ai-service/llm/stream/orchestrator.js.map +1 -1
  170. package/dist/ai-service/llm/stream/retry-engine.d.ts.map +1 -1
  171. package/dist/ai-service/llm/stream/retry-engine.js +1 -1
  172. package/dist/ai-service/llm/stream/retry-engine.js.map +1 -1
  173. package/dist/ai-service/llmobs/otel-exporter.d.ts +111 -14
  174. package/dist/ai-service/llmobs/otel-exporter.d.ts.map +1 -1
  175. package/dist/ai-service/llmobs/otel-exporter.js +441 -66
  176. package/dist/ai-service/llmobs/otel-exporter.js.map +1 -1
  177. package/dist/ai-service/llmobs/tracer.d.ts.map +1 -1
  178. package/dist/ai-service/llmobs/tracer.js +40 -4
  179. package/dist/ai-service/llmobs/tracer.js.map +1 -1
  180. package/dist/ai-service/mcp/playwright-server.d.ts.map +1 -1
  181. package/dist/ai-service/mcp/playwright-server.js +11 -2
  182. package/dist/ai-service/mcp/playwright-server.js.map +1 -1
  183. package/dist/ai-service/recording/index.d.ts +25 -0
  184. package/dist/ai-service/recording/index.d.ts.map +1 -0
  185. package/dist/ai-service/recording/index.js +27 -0
  186. package/dist/ai-service/recording/index.js.map +1 -0
  187. package/dist/ai-service/recording/recorders/llm-recorder.d.ts +35 -0
  188. package/dist/ai-service/recording/recorders/llm-recorder.d.ts.map +1 -0
  189. package/dist/ai-service/recording/recorders/llm-recorder.js +221 -0
  190. package/dist/ai-service/recording/recorders/llm-recorder.js.map +1 -0
  191. package/dist/ai-service/recording/recorders/socket-recorder.d.ts +38 -0
  192. package/dist/ai-service/recording/recorders/socket-recorder.d.ts.map +1 -0
  193. package/dist/ai-service/recording/recorders/socket-recorder.js +44 -0
  194. package/dist/ai-service/recording/recorders/socket-recorder.js.map +1 -0
  195. package/dist/ai-service/recording/recorders/tool-recorder.d.ts +25 -0
  196. package/dist/ai-service/recording/recorders/tool-recorder.d.ts.map +1 -0
  197. package/dist/ai-service/recording/recorders/tool-recorder.js +58 -0
  198. package/dist/ai-service/recording/recorders/tool-recorder.js.map +1 -0
  199. package/dist/ai-service/recording/recording-manager.d.ts +104 -0
  200. package/dist/ai-service/recording/recording-manager.d.ts.map +1 -0
  201. package/dist/ai-service/recording/recording-manager.js +308 -0
  202. package/dist/ai-service/recording/recording-manager.js.map +1 -0
  203. package/dist/ai-service/recording/storage/session-recording-storage.d.ts +143 -0
  204. package/dist/ai-service/recording/storage/session-recording-storage.d.ts.map +1 -0
  205. package/dist/ai-service/recording/storage/session-recording-storage.js +374 -0
  206. package/dist/ai-service/recording/storage/session-recording-storage.js.map +1 -0
  207. package/dist/ai-service/recording/types.d.ts +148 -0
  208. package/dist/ai-service/recording/types.d.ts.map +1 -0
  209. package/dist/ai-service/recording/types.js +8 -0
  210. package/dist/ai-service/recording/types.js.map +1 -0
  211. package/dist/ai-service/security/safety-classifier.d.ts.map +1 -1
  212. package/dist/ai-service/security/safety-classifier.js +9 -3
  213. package/dist/ai-service/security/safety-classifier.js.map +1 -1
  214. package/dist/ai-service/skills/index.d.ts +23 -11
  215. package/dist/ai-service/skills/index.d.ts.map +1 -1
  216. package/dist/ai-service/skills/index.js +86 -21
  217. package/dist/ai-service/skills/index.js.map +1 -1
  218. package/dist/ai-service/skills/system/_registry.generated.d.ts +6 -0
  219. package/dist/ai-service/skills/system/_registry.generated.d.ts.map +1 -0
  220. package/dist/ai-service/skills/system/_registry.generated.js +24 -0
  221. package/dist/ai-service/skills/system/_registry.generated.js.map +1 -0
  222. package/dist/ai-service/skills/system/superblocks-api/references/code-blocks.generated.d.ts +1 -1
  223. package/dist/ai-service/skills/system/superblocks-api/references/code-blocks.generated.d.ts.map +1 -1
  224. package/dist/ai-service/skills/system/superblocks-api/references/code-blocks.generated.js +56 -0
  225. package/dist/ai-service/skills/system/superblocks-api/references/code-blocks.generated.js.map +1 -1
  226. package/dist/ai-service/skills/system/superblocks-api/references/sql-databases.generated.d.ts +1 -1
  227. package/dist/ai-service/skills/system/superblocks-api/references/sql-databases.generated.d.ts.map +1 -1
  228. package/dist/ai-service/skills/system/superblocks-api/references/sql-databases.generated.js +143 -11
  229. package/dist/ai-service/skills/system/superblocks-api/references/sql-databases.generated.js.map +1 -1
  230. package/dist/ai-service/skills/system/superblocks-api/skill.generated.d.ts +1 -1
  231. package/dist/ai-service/skills/system/superblocks-api/skill.generated.d.ts.map +1 -1
  232. package/dist/ai-service/skills/system/superblocks-api/skill.generated.js +130 -3
  233. package/dist/ai-service/skills/system/superblocks-api/skill.generated.js.map +1 -1
  234. package/dist/ai-service/skills/system/superblocks-frontend/references/embedding.generated.d.ts +2 -0
  235. package/dist/ai-service/skills/system/superblocks-frontend/references/embedding.generated.d.ts.map +1 -0
  236. package/dist/ai-service/skills/system/superblocks-frontend/references/embedding.generated.js +155 -0
  237. package/dist/ai-service/skills/system/superblocks-frontend/references/embedding.generated.js.map +1 -0
  238. package/dist/ai-service/skills/system/superblocks-frontend/skill.generated.d.ts +1 -1
  239. package/dist/ai-service/skills/system/superblocks-frontend/skill.generated.d.ts.map +1 -1
  240. package/dist/ai-service/skills/system/superblocks-frontend/skill.generated.js +97 -17
  241. package/dist/ai-service/skills/system/superblocks-frontend/skill.generated.js.map +1 -1
  242. package/dist/ai-service/skills/types.d.ts +24 -0
  243. package/dist/ai-service/skills/types.d.ts.map +1 -1
  244. package/dist/ai-service/skills/types.js +45 -0
  245. package/dist/ai-service/skills/types.js.map +1 -1
  246. package/dist/ai-service/state-machine/clark-fsm.d.ts +33 -2
  247. package/dist/ai-service/state-machine/clark-fsm.d.ts.map +1 -1
  248. package/dist/ai-service/state-machine/clark-fsm.js +6 -1
  249. package/dist/ai-service/state-machine/clark-fsm.js.map +1 -1
  250. package/dist/ai-service/state-machine/handlers/agent-planning.d.ts.map +1 -1
  251. package/dist/ai-service/state-machine/handlers/agent-planning.js +24 -21
  252. package/dist/ai-service/state-machine/handlers/agent-planning.js.map +1 -1
  253. package/dist/ai-service/state-machine/handlers/llm-generating.d.ts.map +1 -1
  254. package/dist/ai-service/state-machine/handlers/llm-generating.js +120 -5
  255. package/dist/ai-service/state-machine/handlers/llm-generating.js.map +1 -1
  256. package/dist/ai-service/state-machine/mocks.d.ts.map +1 -1
  257. package/dist/ai-service/state-machine/mocks.js +23 -0
  258. package/dist/ai-service/state-machine/mocks.js.map +1 -1
  259. package/dist/ai-service/state-machine/traced-fsm.d.ts.map +1 -1
  260. package/dist/ai-service/state-machine/traced-fsm.js +1 -1
  261. package/dist/ai-service/state-machine/traced-fsm.js.map +1 -1
  262. package/dist/file-sync-vite-plugin.d.ts.map +1 -1
  263. package/dist/file-sync-vite-plugin.js +52 -22
  264. package/dist/file-sync-vite-plugin.js.map +1 -1
  265. package/dist/ids.d.ts +1 -0
  266. package/dist/ids.d.ts.map +1 -1
  267. package/dist/ids.js +3 -0
  268. package/dist/ids.js.map +1 -1
  269. package/dist/refactor/entities.d.ts.map +1 -1
  270. package/dist/refactor/entities.js +0 -1
  271. package/dist/refactor/entities.js.map +1 -1
  272. package/dist/socket-manager.d.ts.map +1 -1
  273. package/dist/socket-manager.js +26 -4
  274. package/dist/socket-manager.js.map +1 -1
  275. package/dist/sync-service/index.d.ts +4 -0
  276. package/dist/sync-service/index.d.ts.map +1 -1
  277. package/dist/sync-service/index.js +6 -0
  278. package/dist/sync-service/index.js.map +1 -1
  279. package/dist/util/log-sanitizer.d.ts +42 -0
  280. package/dist/util/log-sanitizer.d.ts.map +1 -0
  281. package/dist/util/log-sanitizer.js +177 -0
  282. package/dist/util/log-sanitizer.js.map +1 -0
  283. package/dist/util/logger.d.ts +4 -0
  284. package/dist/util/logger.d.ts.map +1 -1
  285. package/dist/util/logger.js +77 -19
  286. package/dist/util/logger.js.map +1 -1
  287. package/package.json +17 -14
  288. package/dist/ai-service/agent/tools/get-console-logs.d.ts +0 -29
  289. package/dist/ai-service/agent/tools/get-console-logs.d.ts.map +0 -1
  290. package/dist/ai-service/agent/tools/get-console-logs.js +0 -171
  291. package/dist/ai-service/agent/tools/get-console-logs.js.map +0 -1
  292. package/dist/ai-service/test-utils/anthropic-service-mock.d.ts +0 -2
  293. package/dist/ai-service/test-utils/anthropic-service-mock.d.ts.map +0 -1
  294. package/dist/ai-service/test-utils/anthropic-service-mock.js +0 -91
  295. package/dist/ai-service/test-utils/anthropic-service-mock.js.map +0 -1
  296. package/dist/ai-service/test-utils/app-generation-mocks/orders-app.d.ts +0 -3
  297. package/dist/ai-service/test-utils/app-generation-mocks/orders-app.d.ts.map +0 -1
  298. package/dist/ai-service/test-utils/app-generation-mocks/orders-app.js +0 -886
  299. package/dist/ai-service/test-utils/app-generation-mocks/orders-app.js.map +0 -1
  300. package/dist/ai-service/test-utils/app-generation-mocks/reprompt.d.ts +0 -3
  301. package/dist/ai-service/test-utils/app-generation-mocks/reprompt.d.ts.map +0 -1
  302. package/dist/ai-service/test-utils/app-generation-mocks/reprompt.js +0 -70
  303. package/dist/ai-service/test-utils/app-generation-mocks/reprompt.js.map +0 -1
  304. package/dist/ai-service/test-utils/app-generation-mocks/smoketest.d.ts +0 -3
  305. package/dist/ai-service/test-utils/app-generation-mocks/smoketest.d.ts.map +0 -1
  306. package/dist/ai-service/test-utils/app-generation-mocks/smoketest.js +0 -109
  307. package/dist/ai-service/test-utils/app-generation-mocks/smoketest.js.map +0 -1
  308. package/dist/ai-service/test-utils/mock-utils.d.ts +0 -12
  309. package/dist/ai-service/test-utils/mock-utils.d.ts.map +0 -1
  310. package/dist/ai-service/test-utils/mock-utils.js +0 -70
  311. package/dist/ai-service/test-utils/mock-utils.js.map +0 -1
  312. package/dist/ai-service/util/safe-stringify.d.ts +0 -2
  313. package/dist/ai-service/util/safe-stringify.d.ts.map +0 -1
  314. package/dist/ai-service/util/safe-stringify.js +0 -75
  315. package/dist/ai-service/util/safe-stringify.js.map +0 -1
@@ -1,2 +1,2 @@
1
- export declare const content = "---\nname: superblocks-api\ndescription: |\n Build backend APIs using Superblocks workflow blocks.\n Use when creating or modifying APIs, working with integrations, explaining API patterns, or troubleshooting API issues.\nreadOnly: true\nmetadata:\n author: superblocks\n version: \"1.0\"\n---\n\n# Superblocks API Development\n\nThis skill covers building backend APIs using Superblocks workflow blocks, integrations, and control flow patterns.\n\n## Mental Model\n\nAPIs in Superblocks are backend logic blocks that run in a secure server environment. They:\n- Execute integrations (database queries, API calls, etc.)\n- Process data with JavaScript or Python\n- Return data to the frontend\n- **Cannot** directly modify UI state\n\n**Superblocks APIs are NOT traditional backend services.** They are frontend-coupled workflow builders that:\n- Build declarative workflows using a chain of blocks\n- Receive input parameters passed from the frontend\n- Are visualized in the Superblocks editor\n\n## API File Structure\n\n```typescript\n// Path: /apis/apiName.ts\n\n// \u2705 ALWAYS import required types from the library\nimport {\n Api,\n JavaScript,\n Python,\n PostgreSQL,\n Snowflake,\n RestApi,\n OpenApi,\n GraphQL,\n S3,\n Email,\n Conditional,\n TryCatch,\n Loop,\n Parallel,\n Variables,\n Throw,\n Return,\n Break,\n} from \"@superblocksteam/library\";\n\n// \u274C NEVER define constants here - they won't be serialized!\n\n// \u2705 ALL logic must be inside new Api()\nexport default new Api(\"apiName\", [\n // Workflow blocks here\n]);\n```\n\n**\uD83D\uDEA8 CRITICAL:** Only code inside `new Api()` is serialized. Constants/helpers defined outside cause `ReferenceError` at runtime.\n\n## \uD83D\uDD0D Integration Exploration Workflow (CRITICAL)\n\nWhen exploring integrations and data sources, use `grepMetadata` to understand schema before querying:\n\n### 1. Start with metadata exploration\n\nUse `grepMetadata` to understand:\n- What tables/endpoints exist\n- Schema structure and organization\n- Available fields and data types\n\n**\uD83D\uDCA1 KEY PRINCIPLE:** For \"tell me about the data\" questions, metadata exploration is usually sufficient and more efficient.\n\n### 2. NEVER use SQL/API queries for metadata exploration\n\n\u274C **WRONG**: `SHOW COLUMNS FROM users`, `DESCRIBE table`, `SELECT * FROM INFORMATION_SCHEMA`\n\u2705 **CORRECT**: `grepMetadata({ grepPattern: \"\\\\.columns\\\\[\\\\d+\\\\]\\\\.name\" })` to find all columns\n\n### 3. Database vs OpenAPI key formats\n\n**DATABASE integrations** (Postgres, MySQL, Snowflake, Databricks):\n- Use **numeric array indices**: `[0]`, `[1]`, `[2]`, etc.\n- Pattern: Use `\\\\d+` to match any number\n- Structure: All databases use `json.dbSchema.schemas[]` and `json.dbSchema.tables[]`\n- **\u26A0\uFE0F CRITICAL**: It's `dbSchema` (NOT `schema`!) - the field name is `dbSchema`\n- Examples:\n - \u2705 `\"\\\\.dbSchema\\\\.schemas\\\\[\\\\d+\\\\]\\\\.name\"` - Find schema names\n - \u2705 `\"\\\\.tables\\\\[\\\\d+\\\\]\\\\.name = \\\\\".*user.*\\\\\"\"` - Find tables\n - \u274C `\"\\\\.schema\\\\.tables\"` - WRONG! It's `dbSchema` not `schema`\n\n**OPENAPI integrations** (REST APIs with OpenAPI specs):\n- Use **string object keys**: `[\"/users\"]`, `[\"/repos\"]`\n- Pattern: Use `.*` to match any key (NOT `\\\\d+`!)\n- Examples:\n - \u2705 `\"\\\\.paths\\\\[\\\\\".*repos.*\\\\\"\\\\]\"` - Find paths with \"repos\"\n - \u274C `\"\\\\.paths\\\\[\\\\d+\\\\]\"` - WRONG! OpenAPI doesn't use numeric indices\n\n### 4. REST API vs OpenAPI Selection\n\n**\uD83D\uDEA8 CRITICAL: When working with REST API integrations:**\n1. ALWAYS call `grepMetadata` first to determine if the REST API is OpenAPI-backed\n2. If metadata shows it's an OpenAPI-backed API, you MUST use the `OpenApi` class with `openapi.path`\n3. Only use `RestApi` class for non-OpenAPI REST integrations\n\n## Core Type Definitions\n\n```typescript\nexport type JsonValue = any;\nexport type State = { [key: string]: JsonValue };\nexport type Binding<T> = T | ((state: State) => T);\n\n// Control Flow Blocks\nexport declare class Conditional extends Block {\n constructor(name: string, config: {\n if: { when: Binding<boolean>; then: Block[] };\n elif?: { when: Binding<boolean>; then: Block[] }[];\n else?: Block[];\n });\n}\n\nexport declare class Loop extends Block {\n constructor(name: string, config:\n | { type?: \"TYPE_FOREACH\"; over: Binding<JsonValue[]>; variables: { item: string; index: string }; blocks: Block[] }\n | { type: \"TYPE_WHILE\"; condition: Binding<boolean>; blocks: Block[] }\n );\n}\n\nexport declare class Parallel extends Block {\n constructor(name: string, config:\n | { mode: \"dynamic\"; over: Binding<JsonValue[]>; blocks: Block[] }\n | { mode: \"static\"; paths: Record<string, Block[]> }\n );\n}\n\nexport declare class Variables extends Block {\n constructor(name: string, variables: { key: string; value: Binding<JsonValue> }[]);\n}\n\nexport declare class TryCatch extends Block {\n constructor(name: string, config: {\n try: Block[];\n catch: Block[];\n finally?: Block[];\n variables: { error: string };\n });\n}\n\nexport declare class Throw extends Block {\n constructor(name: string, config: { error: Binding<JsonValue> });\n}\n\nexport declare class Return extends Block {\n constructor(name: string, config: { data: Binding<JsonValue> });\n}\n\nexport declare class Break extends Block {\n constructor(name: string, config: { condition: Binding<JsonValue> });\n}\n\n// API Authorization\nexport type Authorization =\n | { type: \"AUTHORIZATION_TYPE_APP_USERS\" }\n | { type: \"AUTHORIZATION_TYPE_JS_EXPRESSION\"; expression: Binding<boolean> };\n\nexport declare class Api {\n constructor(name: string, blocks?: Block[], authorization?: Authorization);\n}\n```\n\n## Block Output Scoping Rules\n\n**CRITICAL: Blocks can only access outputs from specific scopes.**\n\n### What blocks CAN access:\n1. **Previous sibling blocks** at the same level (executed before them)\n2. **ALL ancestor block outputs** (parent, grandparent, etc.)\n3. **Parent control flow variables** (e.g., `item` and `index` in Loop)\n4. **Control flow block outputs** (equals output of their last child block)\n\n### What blocks CANNOT access:\n- \u274C Outputs from blocks nested inside other control flow blocks\n- \u274C Outputs from blocks in other Conditional branches\n- \u274C Outputs from blocks that come after them\n\n### Variable Access Patterns\n\n```typescript\n// \u2705 CORRECT: Destructure variables/blocks you need\nwhen: ({ hasMore }) => !hasMore.value\nover: ({ items }) => items.output\ncondition: ({ counter }) => counter.value < 10\n\n// \u2705 Multiple variables in one function\nfn: ({ results, page, hasMore }) => {\n results.set([...results.value, ...newItems]);\n page.set(page.value + 1);\n}\n\n// \u274C WRONG: Single param pattern causes runtime error!\nwhen: (p) => !p.hasMore.value // TypeError!\n```\n\n**Access patterns by type:**\n- **API Inputs**: Access directly (no `.value`)\n- **Step Outputs**: Use `.output`\n- **Loop Variables**: Use `.value`\n- **TryCatch Error Variables**: Use `.value`\n- **GraphQL Outputs**: Use `.output.data` (GraphQL returns `{ data: {...}, errors?: [...] }`)\n\n## Input Discovery Rules\n\n**You do NOT need to explicitly declare API inputs.** They are automatically discovered when:\n1. Destructured in block functions but not defined elsewhere\n2. Referenced but not produced by any previous block\n\n### \uD83D\uDEA8 CRITICAL: Always Type Your Input Parameters\n\n```typescript\n// \u2705 CORRECT - Typed parameters\nnew JavaScript(\"validate_email\", {\n fn: ({ email }: { email: string }) => email.includes(\"@\")\n})\n\nnew PostgreSQL(\"search_users\", \"postgres-id\", {\n statement: ({ searchTerm, limit }: { searchTerm: string; limit: number }) =>\n `SELECT * FROM users WHERE name ILIKE '%${searchTerm}%' LIMIT ${limit}`\n})\n\n// \u274C WRONG - Untyped parameters\nnew JavaScript(\"validate_email\", {\n fn: ({ email }) => email.includes(\"@\") // \u274C No type!\n})\n```\n\n## SQL Best Practices\n\n### 1. ONE Query Per Block Rule\n\nEach SQL block can execute **ONLY ONE SQL query**.\n\n\u274C **WRONG:**\n```sql\nUPDATE users SET status = 'active';\nDELETE FROM logs WHERE created < '2023-01-01';\n```\n\n\u2705 **CORRECT:**\n```typescript\nnew PostgreSQL(\"update_status\", \"pg-id\", {\n statement: \"UPDATE users SET status = 'active'\"\n}),\nnew PostgreSQL(\"clean_logs\", \"pg-id\", {\n statement: \"DELETE FROM logs WHERE created < '2023-01-01'\"\n})\n```\n\n### 2. Sort, Don't Filter by Date (Default)\n\nDo NOT add automatic date filters unless explicitly requested.\n\n\u2705 **Default:** `SELECT * FROM orders ORDER BY created_at DESC LIMIT 100`\n\u274C **Avoid:** `SELECT * FROM orders WHERE created_at >= CURRENT_DATE - INTERVAL '90 days'`\n\n### 3. Always Add Defensive Row Limits\n\nAlways include a row limit (default 100) to prevent runaway queries.\n\n## Database Naming Conventions\n\n### Databricks Three-Part Naming\n\nDatabricks uses: `catalog.schema.table`\n\n```sql\n-- Metadata shows: uber.default.orders\nSELECT * FROM uber.default.orders -- \u2705 Full path\nSELECT * FROM uber.orders -- \u274C Missing schema part\n```\n\n**Note:** The word \"default\" in Databricks paths is NOT optional - it's the actual schema name.\n\n### Snowflake Two-Part Naming\n\nSnowflake uses: `schema.table`\n\n```sql\n-- If table has schema property \"MASTERDATA\"\nSELECT * FROM MASTERDATA.PRODUCTLINE -- \u2705 Fully qualified\nSELECT * FROM PRODUCTLINE -- \u274C Will fail if no default schema\n```\n\n## Runtime Safety and Defensive Coding\n\n- Use optional chaining and nullish coalescing when producing outputs\n- For REST/OpenAPI/GraphQL responses, treat non-required fields as optional\n- Default to empty arrays/objects when inputs are absent\n\n```typescript\n// \u2705 Defensive transformation\nnew JavaScript(\"normalize_users\", {\n fn: ({ fetch_users }) => (Array.isArray(fetch_users.output) ? fetch_users.output : []).map(u => ({\n id: u.id,\n name: (u.name ?? \"Unknown\").toString()\n }))\n})\n```\n\n## Common API Patterns\n\n### Simple Data Retrieval\n\n```typescript\nexport default new Api(\"getUsersApi\", [\n new PostgreSQL(\"fetch_users\", \"postgres-id\", {\n statement: \"SELECT * FROM users LIMIT 100\"\n })\n]);\n```\n\n### Input Validation + Processing\n\n```typescript\nexport default new Api(\"createUserApi\", [\n new Conditional(\"validate_inputs\", {\n if: {\n when: ({ FirstNameInput, EmailInput }: { FirstNameInput: string; EmailInput: string }) =>\n !FirstNameInput || !EmailInput,\n then: [\n new Throw(\"validation_error\", { error: \"First name and email are required\" })\n ]\n }\n }),\n new JavaScript(\"create_user\", {\n fn: ({ FirstNameInput, EmailInput }: { FirstNameInput: string; EmailInput: string }) => ({\n id: Math.floor(Math.random() * 1000),\n name: FirstNameInput,\n email: EmailInput,\n created_at: new Date().toISOString()\n })\n })\n]);\n```\n\n### Loop with Data Processing\n\n```typescript\nexport default new Api(\"processOrdersApi\", [\n new JavaScript(\"get_orders\", {\n fn: () => [\n { id: 1, status: \"pending\", amount: 100 },\n { id: 2, status: \"pending\", amount: 200 }\n ]\n }),\n new Loop(\"process_each_order\", {\n over: ({ get_orders }) => get_orders.output,\n variables: { item: \"order\", index: \"i\" },\n blocks: [\n new JavaScript(\"calculate_tax\", {\n fn: ({ order, i }) => ({\n ...order.value,\n tax: order.value.amount * 0.1,\n total: order.value.amount * 1.1,\n position: i.value\n })\n })\n ]\n })\n]);\n```\n\n### Variables for Pagination State\n\n```typescript\nexport default new Api(\"paginatedFetchApi\", [\n new Variables(\"pagination_state\", [\n { key: \"allResults\", value: () => [] },\n { key: \"cursor\", value: () => null },\n { key: \"hasMore\", value: () => true },\n ]),\n \n new Loop(\"fetch_all_pages\", {\n type: \"TYPE_FOREACH\",\n over: () => [...Array(100).keys()], // Max iterations safety\n variables: { item: \"_\", index: \"i\" },\n blocks: [\n new Conditional(\"check_done\", {\n if: {\n when: ({ hasMore }) => !hasMore.value,\n then: [new Break(\"exit_loop\", { condition: () => true })]\n }\n }),\n new RestApi(\"fetch_page\", \"rest-api-id\", {\n method: \"GET\",\n url: ({ cursor }) => `https://api.example.com/items${cursor.value ? `?cursor=${cursor.value}` : \"\"}`,\n }),\n new JavaScript(\"accumulate\", {\n fn: ({ fetch_page, allResults, cursor, hasMore }) => {\n const response = fetch_page.output;\n allResults.set([...allResults.value, ...response.items]);\n cursor.set(response.nextCursor);\n hasMore.set(response.hasMore);\n return allResults.value;\n }\n })\n ]\n }),\n \n new JavaScript(\"return_results\", {\n fn: ({ allResults }) => allResults.value\n })\n]);\n```\n\n### File Uploads to S3/GCS\n\n**Frontend wraps files in `{ files: [...] }` format:**\n```typescript\nconst response = await runUploadApi({ userFiles: { files: selectedFiles } });\n```\n\n**Backend API - pass files directly:**\n```typescript\nexport default new Api(\"uploadFilesApi\", [\n new S3(\"upload_files\", \"your-s3-integration-id\", {\n action: \"UPLOAD_MULTIPLE_OBJECTS\",\n resource: ({ bucketName }) => bucketName,\n fileObjects: ({ userFiles }) => userFiles.files // Direct pass-through\n })\n]);\n```\n\n### Reading File Content in JavaScript\n\n```typescript\nnew JavaScript(\"parse_csv\", {\n fn: async ({ csvFile }) => {\n const file = csvFile.files[0];\n const content = await file.readContentsAsync();\n const headers = content.split(\"\\n\")[0].split(\",\").map(h => h.trim());\n return { fileName: file.name, headers };\n }\n})\n```\n\n## Error Handling Guidelines\n\n**IMPORTANT: Do NOT use TryCatch blocks by default.** Only use when truly necessary.\n\n### \u274C DO NOT use TryCatch for:\n- Standard database queries\n- Simple data transformations\n\n### \u2705 DO use TryCatch when:\n- User explicitly requests error handling\n- Continuing execution after failure is business-critical\n- Partial failure recovery in loops\n- Graceful degradation with fallback data\n\n## Permissions (Global Object)\n\nFor user-specific operations, use the `Global` object (injected by backend):\n\n```typescript\nnew JavaScript(\"check_groups\", {\n fn: ({ Global }) => {\n const isAdmin = Global.groups.some(group => group.name === \"Admin\");\n return { isAdmin, userId: Global.user.id };\n }\n})\n```\n\n**NEVER rely on frontend data for security-critical operations.**\n\n## Critical Mistakes to Avoid\n\n### 1. Defining Constants Outside the API\n\n```typescript\n// \u274C WRONG - Not serialized!\nconst MAX_BATCHES = 100;\nexport default new Api(\"MyApi\", [\n new Loop(\"loop\", {\n condition: ({ count }) => count.value < MAX_BATCHES, // ReferenceError!\n blocks: [...]\n })\n]);\n\n// \u2705 CORRECT - Use Variables block\nexport default new Api(\"MyApi\", [\n new Variables(\"state\", [\n { key: \"maxBatches\", value: () => 100 },\n ]),\n new Loop(\"loop\", {\n condition: ({ count, maxBatches }) => count.value < maxBatches.value,\n blocks: [...]\n })\n]);\n```\n\n### 2. Wrong Language for Integration Type\n\n```typescript\n// \u274C WRONG - JavaScript in SQL block\nnew PostgreSQL(\"bad\", \"id\", {\n statement: ({ userId }) => `SELECT * FROM users WHERE id = ${userId}`\n})\n\n// \u274C WRONG - SQL in JavaScript block\nnew JavaScript(\"bad\", {\n fn: \"SELECT * FROM users\" // This is SQL!\n})\n\n// \u2705 CORRECT\nnew PostgreSQL(\"good\", \"id\", {\n statement: ({ userId }: { userId: string }) => `SELECT * FROM users WHERE id = '${userId}'`\n})\n```\n\n### 3. Fake Integration IDs\n\n```typescript\n// \u274C NEVER make up integration IDs\nnew PostgreSQL(\"query\", \"fake-postgres-id\", { ... })\n```\n\n### 4. APIs Cannot Set Frontend State\n\n```typescript\n// \u274C WRONG - Cannot set state in APIs\nnew JavaScript(\"update\", {\n fn: ({ userData }) => {\n userNameVar.value = userData.name; // \u274C Cannot do this!\n return userData;\n }\n})\n\n// \u2705 CORRECT - Return data, frontend handles state\nnew JavaScript(\"update\", {\n fn: ({ userData }) => ({\n ...userData,\n fullName: `${userData.firstName} ${userData.lastName}`\n })\n})\n```\n\n### 5. Return Blocks Cannot Contain Statements\n\n```typescript\n// \u2705 CORRECT - Returns data immediately\nnew Return(\"test_return\", {\n data: (({ records }) => ({ records, totalCount: records.length }))()\n})\n\n// \u274C WRONG - Contains statements\nnew Return(\"test_return\", {\n data: (({ records }) => {\n const totalCount = records.length; // \u274C Statement not allowed\n return { records, totalCount };\n })()\n})\n```\n\n## When to Load References\n\nFor integration-specific guidance, load the appropriate reference file:\n\n- SQL databases (PostgreSQL, MySQL, Snowflake, etc.) \u2192 `references/sql-databases.md`\n- REST APIs and OpenAPI \u2192 `references/rest-apis.md`\n- GraphQL \u2192 `references/graphql.md`\n- JavaScript/Python blocks \u2192 `references/code-blocks.md`\n\n## API Checklist\n\nWhen creating APIs:\n\n1. \u2705 Correct language for each integration type\n2. \u2705 Use `OpenApi` class when `grepMetadata` shows OpenAPI spec\n3. \u2705 All imports included\n4. \u2705 Correct variable access patterns (`.value`, `.output`, `.output.data` for GraphQL)\n5. \u2705 No fake integration IDs\n6. \u2705 No placeholder logic\n7. \u2705 Descriptive block names\n8. \u2705 Error handling only where appropriate\n9. \u2705 NEVER change API name when editing existing API\n10. \u2705 ALWAYS test after building\n";
1
+ export declare const content = "---\nname: superblocks-api\ndescription: |\n Build backend APIs using Superblocks workflow blocks.\n Use when creating or modifying APIs, working with integrations, explaining API patterns, or troubleshooting API issues.\nreadOnly: true\nmetadata:\n author: superblocks\n version: \"1.0\"\n---\n\n# Superblocks API Development\n\nThis skill covers building backend APIs using Superblocks workflow blocks, integrations, and control flow patterns.\n\n## Mental Model\n\nAPIs in Superblocks are backend logic blocks that run in a secure server environment. They:\n- Execute integrations (database queries, API calls, etc.)\n- Process data with JavaScript or Python\n- Return data to the frontend\n- **Cannot** directly modify UI state\n\n**Superblocks APIs are NOT traditional backend services.** They are frontend-coupled workflow builders that:\n- Build declarative workflows using a chain of blocks\n- Receive input parameters passed from the frontend\n- Are visualized in the Superblocks editor\n\n## API File Structure\n\n```typescript\n// Path: /apis/apiName.ts\n\n// \u2705 ALWAYS import required types from the library\nimport {\n Api,\n JavaScript,\n Python,\n PostgreSQL,\n Snowflake,\n RestApi,\n OpenApi,\n GraphQL,\n S3,\n Email,\n Conditional,\n TryCatch,\n Loop,\n Parallel,\n Variables,\n Throw,\n Return,\n Break,\n} from \"@superblocksteam/library\";\n\n// \u274C NEVER define constants here - they won't be serialized!\n\n// \u2705 ALL logic must be inside new Api()\nexport default new Api(\"apiName\", [\n // Workflow blocks here\n]);\n```\n\n**\uD83D\uDEA8 CRITICAL:** Only code inside `new Api()` is serialized. Constants/helpers defined outside cause `ReferenceError` at runtime.\n\n## \uD83D\uDD0D Integration Exploration Workflow (CRITICAL)\n\nWhen exploring integrations and data sources, use `grepMetadata` to understand schema before querying:\n\n### 1. Start with metadata exploration\n\nUse `grepMetadata` to understand:\n- What tables/endpoints exist\n- Schema structure and\n- Available fields and data types\n\n**\uD83D\uDCA1 KEY PRINCIPLE:** For \"tell me about the data\" questions, metadata exploration is usually sufficient and more efficient.\n\n### 2. NEVER use SQL/API queries for metadata exploration\n\n\u274C **WRONG**: `SHOW COLUMNS FROM users`, `DESCRIBE table`, `SELECT * FROM INFORMATION_SCHEMA`\n\u2705 **CORRECT**: `grepMetadata({ grepPattern: \"\\\\.columns\\\\[\\\\d+\\\\]\\\\.name\" })` to find all columns\n\n### 3. Database vs OpenAPI key formats\n\n**DATABASE integrations** (Postgres, MySQL, Snowflake, Databricks):\n- Use **numeric array indices**: `[0]`, `[1]`, `[2]`, etc.\n- Pattern: Use `\\\\d+` to match any number\n- Structure: All databases use `json.dbSchema.schemas[]` and `json.dbSchema.tables[]`\n- **\u26A0\uFE0F CRITICAL**: It's `dbSchema` (NOT `schema`!) - the field name is `dbSchema`\n- Examples:\n - \u2705 `\"\\\\.dbSchema\\\\.schemas\\\\[\\\\d+\\\\]\\\\.name\"` - Find schema names\n - \u2705 `\"\\\\.tables\\\\[\\\\d+\\\\]\\\\.name = \\\\\".*user.*\\\\\"\"` - Find tables\n - \u274C `\"\\\\.schema\\\\.tables\"` - WRONG! It's `dbSchema` not `schema`\n\n**OPENAPI integrations** (REST APIs with OpenAPI specs):\n- Use **string object keys**: `[\"/users\"]`, `[\"/repos\"]`\n- Pattern: Use `.*` to match any key (NOT `\\\\d+`!)\n- Examples:\n - \u2705 `\"\\\\.paths\\\\[\\\\\".*repos.*\\\\\"\\\\]\"` - Find paths with \"repos\"\n - \u274C `\"\\\\.paths\\\\[\\\\d+\\\\]\"` - WRONG! OpenAPI doesn't use numeric indices\n\n### 4. REST API vs OpenAPI Selection\n\n**\uD83D\uDEA8 CRITICAL: When working with REST API integrations:**\n1. ALWAYS call `grepMetadata` first to determine if the REST API is OpenAPI-backed\n2. If metadata shows it's an OpenAPI-backed API, you MUST use the `OpenApi` class with `openapi.path`\n3. Only use `RestApi` class for non-OpenAPI REST integrations\n\n## Core Type Definitions\n\n```typescript\nexport type JsonValue = any;\nexport type State = { [key: string]: JsonValue };\nexport type Binding<T> = T | ((state: State) => T);\n\n// Control Flow Blocks\nexport declare class Conditional extends Block {\n constructor(name: string, config: {\n if: { when: Binding<boolean>; then: Block[] };\n elif?: { when: Binding<boolean>; then: Block[] }[];\n else?: Block[];\n });\n}\n\nexport declare class Loop extends Block {\n constructor(name: string, config:\n | { type?: \"TYPE_FOREACH\"; over: Binding<JsonValue[]>; variables: { item: string; index: string }; blocks: Block[] }\n | { type: \"TYPE_WHILE\"; condition: Binding<boolean>; blocks: Block[] }\n );\n}\n\nexport declare class Parallel extends Block {\n constructor(name: string, config:\n | { mode: \"dynamic\"; over: Binding<JsonValue[]>; blocks: Block[] }\n | { mode: \"static\"; paths: Record<string, Block[]> }\n );\n}\n\nexport declare class Variables extends Block {\n constructor(name: string, variables: { key: string; value: Binding<JsonValue> }[]);\n}\n\nexport declare class TryCatch extends Block {\n constructor(name: string, config: {\n try: Block[];\n catch: Block[];\n finally?: Block[];\n variables: { error: string };\n });\n}\n\nexport declare class Throw extends Block {\n constructor(name: string, config: { error: Binding<JsonValue> });\n}\n\nexport declare class Return extends Block {\n constructor(name: string, config: { data: Binding<JsonValue> });\n}\n\nexport declare class Break extends Block {\n constructor(name: string, config: { condition: Binding<JsonValue> });\n}\n\n// API Authorization\nexport type Authorization =\n | { type: \"AUTHORIZATION_TYPE_APP_USERS\" }\n | { type: \"AUTHORIZATION_TYPE_JS_EXPRESSION\"; expression: Binding<boolean> };\n\nexport declare class Api {\n constructor(name: string, blocks?: Block[], authorization?: Authorization);\n}\n```\n\n## Block Output Scoping Rules\n\n**CRITICAL: Blocks can only access outputs from specific scopes.**\n\n### What blocks CAN access:\n1. **Previous sibling blocks** at the same level (executed before them)\n2. **ALL ancestor block outputs** (parent, grandparent, etc.)\n3. **Parent control flow variables** (e.g., `item` and `index` in Loop)\n4. **Control flow block outputs** (equals output of their last child block)\n\n### What blocks CANNOT access:\n- \u274C Outputs from blocks nested inside other control flow blocks\n- \u274C Outputs from blocks in other Conditional branches\n- \u274C Outputs from blocks that come after them\n\n### Variable Access Patterns\n\n```typescript\n// \u2705 CORRECT: Destructure variables/blocks you need\nwhen: ({ hasMore }) => !hasMore.value\nover: ({ items }) => items.output\ncondition: ({ counter }) => counter.value < 10\n\n// \u2705 Multiple variables in one function\nfn: ({ results, page, hasMore }) => {\n results.set([...results.value, ...newItems]);\n page.set(page.value + 1);\n}\n\n// \u274C WRONG: Single param pattern causes runtime error!\nwhen: (p) => !p.hasMore.value // TypeError!\n```\n\n**Access patterns by type:**\n- **API Inputs**: Access directly (no `.value`)\n- **Step Outputs**: Use `.output`\n- **Loop Variables**: Use `.value`\n- **TryCatch Error Variables**: Use `.value`\n- **GraphQL Outputs**: Use `.output.data` (GraphQL returns `{ data: {...}, errors?: [...] }`)\n\n## Input Discovery Rules\n\n**You do NOT need to explicitly declare API inputs.** They are automatically discovered when:\n1. Destructured in block functions but not defined elsewhere\n2. Referenced but not produced by any previous block\n\n### \uD83D\uDEA8 CRITICAL: Always Type Your Input Parameters\n\n```typescript\n// \u2705 CORRECT - Typed parameters\nnew JavaScript(\"validate_email\", {\n fn: ({ email }: { email: string }) => email.includes(\"@\")\n})\n\nnew PostgreSQL(\"search_users\", \"postgres-id\", {\n statement: ({ searchTerm, limit }: { searchTerm: string; limit: number }) =>\n `SELECT * FROM users WHERE name ILIKE '%${searchTerm}%' LIMIT ${limit}`\n})\n\n// \u274C WRONG - Untyped parameters\nnew JavaScript(\"validate_email\", {\n fn: ({ email }) => email.includes(\"@\") // \u274C No type!\n})\n```\n\n## SQL Best Practices\n\n### 1. ONE Query Per Block Rule\n\nEach SQL block can execute **ONLY ONE SQL query**.\n\n\u274C **WRONG:**\n```sql\nUPDATE users SET status = 'active';\nDELETE FROM logs WHERE created < '2023-01-01';\n```\n\n\u2705 **CORRECT:**\n```typescript\nnew PostgreSQL(\"update_status\", \"pg-id\", {\n statement: \"UPDATE users SET status = 'active'\"\n}),\nnew PostgreSQL(\"clean_logs\", \"pg-id\", {\n statement: \"DELETE FROM logs WHERE created < '2023-01-01'\"\n})\n```\n\n### 2. Sort, Don't Filter by Date (Default)\n\nDo NOT add automatic date filters unless explicitly requested.\n\n\u2705 **Default:** `SELECT * FROM orders ORDER BY created_at DESC LIMIT 100`\n\u274C **Avoid:** `SELECT * FROM orders WHERE created_at >= CURRENT_DATE - INTERVAL '90 days'`\n\n### 3. Always Add Defensive Row Limits\n\nAlways include a row limit (default 100) to prevent runaway queries.\n\n## Database Naming Conventions\n\n### Databricks Three-Part Naming\n\nDatabricks uses: `catalog.schema.table`\n\n```sql\n-- Metadata shows: uber.default.orders\nSELECT * FROM uber.default.orders -- \u2705 Full path\nSELECT * FROM uber.orders -- \u274C Missing schema part\n```\n\n**Note:** The word \"default\" in Databricks paths is NOT optional - it's the actual schema name.\n\n### Snowflake Two-Part Naming\n\nSnowflake uses: `schema.table`\n\n```sql\n-- If table has schema property \"MASTERDATA\"\nSELECT * FROM MASTERDATA.PRODUCTLINE -- \u2705 Fully qualified\nSELECT * FROM PRODUCTLINE -- \u274C Will fail if no default schema\n```\n\n## Runtime Safety and Defensive Coding\n\n- Use optional chaining and nullish coalescing when producing outputs\n- For REST/OpenAPI/GraphQL responses, treat non-required fields as optional\n- Default to empty arrays/objects when inputs are absent\n\n```typescript\n// \u2705 Defensive transformation\nnew JavaScript(\"normalize_users\", {\n fn: ({ fetch_users }) => (Array.isArray(fetch_users.output) ? fetch_users.output : []).map(u => ({\n id: u.id,\n name: (u.name ?? \"Unknown\").toString()\n }))\n})\n```\n\n## Common API Patterns\n\n### Simple Data Retrieval\n\n```typescript\nexport default new Api(\"getUsersApi\", [\n new PostgreSQL(\"fetch_users\", \"postgres-id\", {\n statement: \"SELECT * FROM users LIMIT 100\"\n })\n]);\n```\n\n### Input Validation + Processing\n\n```typescript\nexport default new Api(\"createUserApi\", [\n new Conditional(\"validate_inputs\", {\n if: {\n when: ({ FirstNameInput, EmailInput }: { FirstNameInput: string; EmailInput: string }) =>\n !FirstNameInput || !EmailInput,\n then: [\n new Throw(\"validation_error\", { error: \"First name and email are required\" })\n ]\n }\n }),\n new JavaScript(\"create_user\", {\n fn: ({ FirstNameInput, EmailInput }: { FirstNameInput: string; EmailInput: string }) => ({\n id: Math.floor(Math.random() * 1000),\n name: FirstNameInput,\n email: EmailInput,\n created_at: new Date().toISOString()\n })\n })\n]);\n```\n\n### Loop with Data Processing\n\n```typescript\nexport default new Api(\"processOrdersApi\", [\n new JavaScript(\"get_orders\", {\n fn: () => [\n { id: 1, status: \"pending\", amount: 100 },\n { id: 2, status: \"pending\", amount: 200 }\n ]\n }),\n new Loop(\"process_each_order\", {\n over: ({ get_orders }) => get_orders.output,\n variables: { item: \"order\", index: \"i\" },\n blocks: [\n new JavaScript(\"calculate_tax\", {\n fn: ({ order, i }) => ({\n ...order.value,\n tax: order.value.amount * 0.1,\n total: order.value.amount * 1.1,\n position: i.value\n })\n })\n ]\n })\n]);\n```\n\n### Variables for Pagination State\n\n```typescript\nexport default new Api(\"paginatedFetchApi\", [\n new Variables(\"pagination_state\", [\n { key: \"allResults\", value: () => [] },\n { key: \"cursor\", value: () => null },\n { key: \"hasMore\", value: () => true },\n ]),\n \n new Loop(\"fetch_all_pages\", {\n type: \"TYPE_FOREACH\",\n over: () => [...Array(100).keys()], // Max iterations safety\n variables: { item: \"_\", index: \"i\" },\n blocks: [\n new Conditional(\"check_done\", {\n if: {\n when: ({ hasMore }) => !hasMore.value,\n then: [new Break(\"exit_loop\", { condition: () => true })]\n }\n }),\n new RestApi(\"fetch_page\", \"rest-api-id\", {\n method: \"GET\",\n url: ({ cursor }) => `https://api.example.com/items${cursor.value ? `?cursor=${cursor.value}` : \"\"}`,\n }),\n new JavaScript(\"accumulate\", {\n fn: ({ fetch_page, allResults, cursor, hasMore }) => {\n const response = fetch_page.output;\n allResults.set([...allResults.value, ...response.items]);\n cursor.set(response.nextCursor);\n hasMore.set(response.hasMore);\n return allResults.value;\n }\n })\n ]\n }),\n \n new JavaScript(\"return_results\", {\n fn: ({ allResults }) => allResults.value\n })\n]);\n```\n\n### File Uploads to S3/GCS\n\n**Frontend wraps files in `{ files: [...] }` format:**\n```typescript\nconst response = await runUploadApi({ userFiles: { files: selectedFiles } });\n```\n\n**Backend API - pass files directly:**\n```typescript\nexport default new Api(\"uploadFilesApi\", [\n new S3(\"upload_files\", \"your-s3-integration-id\", {\n action: \"UPLOAD_MULTIPLE_OBJECTS\",\n resource: ({ bucketName }) => bucketName,\n fileObjects: ({ userFiles }) => userFiles.files // Direct pass-through\n })\n]);\n```\n\n### Reading File Content in JavaScript\n\n```typescript\nnew JavaScript(\"parse_csv\", {\n fn: async ({ csvFile }) => {\n const file = csvFile.files[0];\n const content = await file.readContentsAsync();\n const headers = content.split(\"\\n\")[0].split(\",\").map(h => h.trim());\n return { fileName: file.name, headers };\n }\n})\n```\n\n## Error Handling Guidelines\n\n**IMPORTANT: Do NOT use TryCatch blocks by default.** Only use when truly necessary.\n\n### \u274C DO NOT use TryCatch for:\n- Standard database queries\n- Simple data transformations\n\n### \u2705 DO use TryCatch when:\n- User explicitly requests error handling\n- Continuing execution after failure is business-critical\n- Partial failure recovery in loops\n- Graceful degradation with fallback data\n\n## Error Recovery Strategies\n\nWhen you encounter errors while building APIs:\n\n### Read Error Messages Carefully\n\nError messages contain specific guidance on how to fix the problem. Pay close attention to:\n- What operation failed (compilation, validation, execution)\n- Suggestions for how to resolve the issue\n- Whether metadata is missing\n\n### When to Check Integration Metadata\n\nIf you encounter errors mentioning:\n- \"unknown column\", \"table not found\", \"invalid field\"\n- \"check integration metadata\"\n- Integration type mismatches\n\nYou MUST call `grepMetadata` to get the correct schema/table structure before retrying.\n\n## Loop Control\n\n### Loop Types\n\n- **TYPE_FOREACH** (default): Iterates over an array using `over`. Provides `item` and `index` variables.\n- **TYPE_WHILE**: Repeats while `condition` is true. Provides only `index` variable.\n\n**Breaking out of loops:**\n```typescript\nnew Loop(\"process_until_complete\", {\n over: ({ items }) => items.output,\n variables: { item: \"current\", index: \"i\" },\n blocks: [\n new Conditional(\"check_stop_condition\", {\n if: {\n when: ({ current }) => current.value.status === \"complete\",\n then: [\n new Break(\"exit_loop\", { condition: () => true }) // \u2705 Only way to exit\n ]\n }\n }),\n new JavaScript(\"process_item\", {\n fn: ({ current, i }) => ({\n processed: current.value,\n position: i.value\n })\n })\n ]\n})\n```\n\n## Response Interface Guidelines\n\nThe `responseInterface` describes what external code gets from `apiName.response`. Internal blocks/steps are NOT visible externally.\n\n### Direct Response Types\n\n\u2705 **CORRECT**: Direct array response\n```typescript\ninterface GetUsersApiResponse {\n id: number;\n name: string;\n email: string;\n}[]\n```\n\n\u2705 **CORRECT**: Direct data structure\n```typescript\ninterface GetOrdersApiResponse {\n orders: Order[];\n totalCount: number;\n}\n```\n\n\u274C **WRONG**: Exposing internal steps\n```typescript\ninterface GetOrdersApiResponse {\n fetchStep: { output: Order[] }; // \u274C Steps are internal\n countStep: { output: number }; // \u274C Not visible outside\n}\n```\n\n### Type Safety for API Response Interfaces\n\n**CRITICAL: When defining response interfaces, consider runtime reality, not just happy-path data.**\n\nWhen uncertain if an API field will always be present, mark it optional:\n\n```typescript\n// \u2705 CORRECT - Accounts for real-world API behavior\ninterface GitHubPRResponse {\n id: number;\n title: string;\n user?: { // \u2190 Optional, can be null for deleted users\n login: string;\n avatar_url: string;\n } | null;\n labels?: Label[]; // \u2190 Optional, might be omitted in response\n}\n```\n\nMark fields optional when:\n1. **User/account references** - Can be null for deleted/deactivated accounts\n2. **Nested objects** - May be omitted in partial responses\n3. **Third-party APIs** - GitHub, Stripe, etc. often have nullable fields\n4. **Loading states** - Data may not be available during initial render\n5. **Uncertain API behavior** - When in doubt, mark optional\n\n## Permissions (Global Object)\n\nFor user-specific operations, use the `Global` object (injected by backend):\n\n```typescript\ntype Global = {\n user: {\n email: string;\n username: string;\n id: string;\n name: string;\n groups: Group[]\n };\n};\n```\n\n### Groups Check Pattern\n\n```typescript\nnew JavaScript(\"check_groups\", {\n fn: ({ Global }) => {\n const isFieldEngUser = Global.groups.some(group => group.name === \"FieldEngineer\");\n if (isFieldEngUser) {\n // Perform actions for FieldEngineer\n } else {\n // Perform actions for non-FieldEngineer\n }\n return { isAdmin: Global.groups.some(g => g.name === \"Admin\"), userId: Global.user.id };\n }\n})\n```\n\n**NEVER rely on frontend data for security-critical operations.**\n\n## Critical Mistakes to Avoid\n\n### 1. Defining Constants Outside the API\n\n```typescript\n// \u274C WRONG - Not serialized!\nconst MAX_BATCHES = 100;\nexport default new Api(\"MyApi\", [\n new Loop(\"loop\", {\n condition: ({ count }) => count.value < MAX_BATCHES, // ReferenceError!\n blocks: [...]\n })\n]);\n\n// \u2705 CORRECT - Use Variables block\nexport default new Api(\"MyApi\", [\n new Variables(\"state\", [\n { key: \"maxBatches\", value: () => 100 },\n ]),\n new Loop(\"loop\", {\n condition: ({ count, maxBatches }) => count.value < maxBatches.value,\n blocks: [...]\n })\n]);\n```\n\n### 2. Wrong Language for Integration Type\n\n```typescript\n// \u274C WRONG - JavaScript in SQL block\nnew PostgreSQL(\"bad\", \"id\", {\n statement: ({ userId }) => `SELECT * FROM users WHERE id = ${userId}`\n})\n\n// \u274C WRONG - SQL in JavaScript block\nnew JavaScript(\"bad\", {\n fn: \"SELECT * FROM users\" // This is SQL!\n})\n\n// \u2705 CORRECT\nnew PostgreSQL(\"good\", \"id\", {\n statement: ({ userId }: { userId: string }) => `SELECT * FROM users WHERE id = '${userId}'`\n})\n```\n\n### 3. Fake Integration IDs\n\n```typescript\n// \u274C NEVER make up integration IDs\nnew PostgreSQL(\"query\", \"fake-postgres-id\", { ... })\n```\n\n### 4. APIs Cannot Set Frontend State\n\n```typescript\n// \u274C WRONG - Cannot set state in APIs\nnew JavaScript(\"update\", {\n fn: ({ userData }) => {\n userNameVar.value = userData.name; // \u274C Cannot do this!\n return userData;\n }\n})\n\n// \u2705 CORRECT - Return data, frontend handles state\nnew JavaScript(\"update\", {\n fn: ({ userData }) => ({\n ...userData,\n fullName: `${userData.firstName} ${userData.lastName}`\n })\n})\n```\n\n### 5. Return Blocks Cannot Contain Statements\n\n```typescript\n// \u2705 CORRECT - Returns data immediately\nnew Return(\"test_return\", {\n data: (({ records }) => ({ records, totalCount: records.length }))()\n})\n\n// \u274C WRONG - Contains statements\nnew Return(\"test_return\", {\n data: (({ records }) => {\n const totalCount = records.length; // \u274C Statement not allowed\n return { records, totalCount };\n })()\n})\n```\n\n## When to Load References\n\nFor integration-specific guidance, load the appropriate reference file:\n\n- SQL databases (PostgreSQL, MySQL, Snowflake, etc.) \u2192 `references/sql-databases.md`\n- REST APIs and OpenAPI \u2192 `references/rest-apis.md`\n- GraphQL \u2192 `references/graphql.md`\n- JavaScript/Python blocks \u2192 `references/code-blocks.md`\n\n## API Checklist\n\nWhen creating APIs:\n\n1. \u2705 Correct language for each integration type\n2. \u2705 Use `OpenApi` class when `grepMetadata` shows OpenAPI spec\n3. \u2705 All imports included\n4. \u2705 Correct variable access patterns (`.value`, `.output`, `.output.data` for GraphQL)\n5. \u2705 No fake integration IDs\n6. \u2705 No placeholder logic\n7. \u2705 Descriptive block names\n8. \u2705 Error handling only where appropriate\n9. \u2705 NEVER change API name when editing existing API\n10. \u2705 ALWAYS test after building\n";
2
2
  //# sourceMappingURL=skill.generated.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"skill.generated.d.ts","sourceRoot":"","sources":["../../../../../src/ai-service/skills/system/superblocks-api/skill.generated.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,6njBA8kBnB,CAAC"}
1
+ {"version":3,"file":"skill.generated.d.ts","sourceRoot":"","sources":["../../../../../src/ai-service/skills/system/superblocks-api/skill.generated.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,qmqBA6sBnB,CAAC"}
@@ -73,7 +73,7 @@ When exploring integrations and data sources, use \`grepMetadata\` to understand
73
73
 
74
74
  Use \`grepMetadata\` to understand:
75
75
  - What tables/endpoints exist
76
- - Schema structure and organization
76
+ - Schema structure and
77
77
  - Available fields and data types
78
78
 
79
79
  **💡 KEY PRINCIPLE:** For "tell me about the data" questions, metadata exploration is usually sufficient and more efficient.
@@ -463,15 +463,142 @@ new JavaScript("parse_csv", {
463
463
  - Partial failure recovery in loops
464
464
  - Graceful degradation with fallback data
465
465
 
466
+ ## Error Recovery Strategies
467
+
468
+ When you encounter errors while building APIs:
469
+
470
+ ### Read Error Messages Carefully
471
+
472
+ Error messages contain specific guidance on how to fix the problem. Pay close attention to:
473
+ - What operation failed (compilation, validation, execution)
474
+ - Suggestions for how to resolve the issue
475
+ - Whether metadata is missing
476
+
477
+ ### When to Check Integration Metadata
478
+
479
+ If you encounter errors mentioning:
480
+ - "unknown column", "table not found", "invalid field"
481
+ - "check integration metadata"
482
+ - Integration type mismatches
483
+
484
+ You MUST call \`grepMetadata\` to get the correct schema/table structure before retrying.
485
+
486
+ ## Loop Control
487
+
488
+ ### Loop Types
489
+
490
+ - **TYPE_FOREACH** (default): Iterates over an array using \`over\`. Provides \`item\` and \`index\` variables.
491
+ - **TYPE_WHILE**: Repeats while \`condition\` is true. Provides only \`index\` variable.
492
+
493
+ **Breaking out of loops:**
494
+ \`\`\`typescript
495
+ new Loop("process_until_complete", {
496
+ over: ({ items }) => items.output,
497
+ variables: { item: "current", index: "i" },
498
+ blocks: [
499
+ new Conditional("check_stop_condition", {
500
+ if: {
501
+ when: ({ current }) => current.value.status === "complete",
502
+ then: [
503
+ new Break("exit_loop", { condition: () => true }) // ✅ Only way to exit
504
+ ]
505
+ }
506
+ }),
507
+ new JavaScript("process_item", {
508
+ fn: ({ current, i }) => ({
509
+ processed: current.value,
510
+ position: i.value
511
+ })
512
+ })
513
+ ]
514
+ })
515
+ \`\`\`
516
+
517
+ ## Response Interface Guidelines
518
+
519
+ The \`responseInterface\` describes what external code gets from \`apiName.response\`. Internal blocks/steps are NOT visible externally.
520
+
521
+ ### Direct Response Types
522
+
523
+ ✅ **CORRECT**: Direct array response
524
+ \`\`\`typescript
525
+ interface GetUsersApiResponse {
526
+ id: number;
527
+ name: string;
528
+ email: string;
529
+ }[]
530
+ \`\`\`
531
+
532
+ ✅ **CORRECT**: Direct data structure
533
+ \`\`\`typescript
534
+ interface GetOrdersApiResponse {
535
+ orders: Order[];
536
+ totalCount: number;
537
+ }
538
+ \`\`\`
539
+
540
+ ❌ **WRONG**: Exposing internal steps
541
+ \`\`\`typescript
542
+ interface GetOrdersApiResponse {
543
+ fetchStep: { output: Order[] }; // ❌ Steps are internal
544
+ countStep: { output: number }; // ❌ Not visible outside
545
+ }
546
+ \`\`\`
547
+
548
+ ### Type Safety for API Response Interfaces
549
+
550
+ **CRITICAL: When defining response interfaces, consider runtime reality, not just happy-path data.**
551
+
552
+ When uncertain if an API field will always be present, mark it optional:
553
+
554
+ \`\`\`typescript
555
+ // ✅ CORRECT - Accounts for real-world API behavior
556
+ interface GitHubPRResponse {
557
+ id: number;
558
+ title: string;
559
+ user?: { // ← Optional, can be null for deleted users
560
+ login: string;
561
+ avatar_url: string;
562
+ } | null;
563
+ labels?: Label[]; // ← Optional, might be omitted in response
564
+ }
565
+ \`\`\`
566
+
567
+ Mark fields optional when:
568
+ 1. **User/account references** - Can be null for deleted/deactivated accounts
569
+ 2. **Nested objects** - May be omitted in partial responses
570
+ 3. **Third-party APIs** - GitHub, Stripe, etc. often have nullable fields
571
+ 4. **Loading states** - Data may not be available during initial render
572
+ 5. **Uncertain API behavior** - When in doubt, mark optional
573
+
466
574
  ## Permissions (Global Object)
467
575
 
468
576
  For user-specific operations, use the \`Global\` object (injected by backend):
469
577
 
578
+ \`\`\`typescript
579
+ type Global = {
580
+ user: {
581
+ email: string;
582
+ username: string;
583
+ id: string;
584
+ name: string;
585
+ groups: Group[]
586
+ };
587
+ };
588
+ \`\`\`
589
+
590
+ ### Groups Check Pattern
591
+
470
592
  \`\`\`typescript
471
593
  new JavaScript("check_groups", {
472
594
  fn: ({ Global }) => {
473
- const isAdmin = Global.groups.some(group => group.name === "Admin");
474
- return { isAdmin, userId: Global.user.id };
595
+ const isFieldEngUser = Global.groups.some(group => group.name === "FieldEngineer");
596
+ if (isFieldEngUser) {
597
+ // Perform actions for FieldEngineer
598
+ } else {
599
+ // Perform actions for non-FieldEngineer
600
+ }
601
+ return { isAdmin: Global.groups.some(g => g.name === "Admin"), userId: Global.user.id };
475
602
  }
476
603
  })
477
604
  \`\`\`
@@ -1 +1 @@
1
- {"version":3,"file":"skill.generated.js","sourceRoot":"","sources":["../../../../../src/ai-service/skills/system/superblocks-api/skill.generated.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,mDAAmD;AAEnD,MAAM,CAAC,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8kBtB,CAAC"}
1
+ {"version":3,"file":"skill.generated.js","sourceRoot":"","sources":["../../../../../src/ai-service/skills/system/superblocks-api/skill.generated.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,mDAAmD;AAEnD,MAAM,CAAC,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6sBtB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const content = "# Embedding Superblocks Applications\n\nThis reference covers embedding Superblocks applications in external websites or portals.\n\n## Embed Hooks\n\nAvailable hooks from `@superblocksteam/library` for embedded applications:\n\n```typescript\nimport { \n useEmbedProperties,\n useEmbedEvent,\n useEmitEmbedEvent,\n} from \"@superblocksteam/library\";\n```\n\n### useEmbedProperties\n\nRead properties passed from the embedder (parent application):\n\n```typescript\nconst properties = useEmbedProperties();\n\n// Access custom properties defined in the embed configuration\nconst { userId, theme, locale } = properties;\n```\n\n### useEmbedEvent\n\nListen to events emitted from the embedder:\n\n```typescript\nuseEmbedEvent(\"refreshData\", (payload) => {\n // Handle refresh request from parent\n refetchData();\n});\n\nuseEmbedEvent(\"userChanged\", (payload) => {\n // Handle user context change\n setCurrentUser(payload.user);\n});\n\nuseEmbedEvent(\"themeChanged\", (payload) => {\n // Handle theme updates\n setTheme(payload.theme);\n});\n```\n\n### useEmitEmbedEvent\n\nEmit events to the embedder (parent application):\n\n```typescript\nconst emitEvent = useEmitEmbedEvent();\n\n// Notify parent when form is submitted\nconst handleSubmit = async (data) => {\n await saveData(data);\n emitEvent(\"formSubmitted\", { \n timestamp: Date.now(), \n data,\n success: true \n });\n};\n\n// Notify parent of navigation\nconst handleNavigate = (route) => {\n emitEvent(\"navigationChanged\", { route });\n navigate(route);\n};\n\n// Notify parent of errors\nconst handleError = (error) => {\n emitEvent(\"errorOccurred\", { \n message: error.message,\n code: error.code \n });\n};\n```\n\n## Common Embedding Patterns\n\n### Bidirectional Communication\n\n```typescript\nfunction EmbeddedDashboard() {\n const properties = useEmbedProperties();\n const emitEvent = useEmitEmbedEvent();\n const [data, setData] = useState(null);\n\n // Listen for refresh commands from parent\n useEmbedEvent(\"refresh\", () => {\n fetchData();\n });\n\n // Notify parent when data changes\n const handleDataUpdate = async (newData) => {\n await saveData(newData);\n setData(newData);\n emitEvent(\"dataUpdated\", { data: newData });\n };\n\n return (\n <Dashboard \n userId={properties.userId}\n data={data}\n onUpdate={handleDataUpdate}\n />\n );\n}\n```\n\n### Synchronized State\n\n```typescript\nfunction EmbeddedForm() {\n const properties = useEmbedProperties();\n const emitEvent = useEmitEmbedEvent();\n const [formState, setFormState] = useState(properties.initialData || {});\n\n // Sync form state changes to parent\n useEffect(() => {\n emitEvent(\"formStateChanged\", { state: formState });\n }, [formState, emitEvent]);\n\n // Listen for external state updates\n useEmbedEvent(\"updateFormState\", (payload) => {\n setFormState(prev => ({ ...prev, ...payload }));\n });\n\n return <Form value={formState} onChange={setFormState} />;\n}\n```\n\n### Loading External Context\n\n```typescript\nfunction EmbeddedApp() {\n const properties = useEmbedProperties();\n const { customerId, permissions, branding } = properties;\n\n // Use embed properties to customize the app\n return (\n <ThemeProvider theme={branding}>\n <CustomerContext.Provider value={{ customerId, permissions }}>\n <AppContent />\n </CustomerContext.Provider>\n </ThemeProvider>\n );\n}\n```\n";
2
+ //# sourceMappingURL=embedding.generated.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedding.generated.d.ts","sourceRoot":"","sources":["../../../../../../src/ai-service/skills/system/superblocks-frontend/references/embedding.generated.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,05GAuJnB,CAAC"}
@@ -0,0 +1,155 @@
1
+ // Auto-generated from src/ai-service/skills/system/superblocks-frontend/references/embedding.md
2
+ // Do not edit directly - edit the .md file instead
3
+ export const content = `# Embedding Superblocks Applications
4
+
5
+ This reference covers embedding Superblocks applications in external websites or portals.
6
+
7
+ ## Embed Hooks
8
+
9
+ Available hooks from \`@superblocksteam/library\` for embedded applications:
10
+
11
+ \`\`\`typescript
12
+ import {
13
+ useEmbedProperties,
14
+ useEmbedEvent,
15
+ useEmitEmbedEvent,
16
+ } from "@superblocksteam/library";
17
+ \`\`\`
18
+
19
+ ### useEmbedProperties
20
+
21
+ Read properties passed from the embedder (parent application):
22
+
23
+ \`\`\`typescript
24
+ const properties = useEmbedProperties();
25
+
26
+ // Access custom properties defined in the embed configuration
27
+ const { userId, theme, locale } = properties;
28
+ \`\`\`
29
+
30
+ ### useEmbedEvent
31
+
32
+ Listen to events emitted from the embedder:
33
+
34
+ \`\`\`typescript
35
+ useEmbedEvent("refreshData", (payload) => {
36
+ // Handle refresh request from parent
37
+ refetchData();
38
+ });
39
+
40
+ useEmbedEvent("userChanged", (payload) => {
41
+ // Handle user context change
42
+ setCurrentUser(payload.user);
43
+ });
44
+
45
+ useEmbedEvent("themeChanged", (payload) => {
46
+ // Handle theme updates
47
+ setTheme(payload.theme);
48
+ });
49
+ \`\`\`
50
+
51
+ ### useEmitEmbedEvent
52
+
53
+ Emit events to the embedder (parent application):
54
+
55
+ \`\`\`typescript
56
+ const emitEvent = useEmitEmbedEvent();
57
+
58
+ // Notify parent when form is submitted
59
+ const handleSubmit = async (data) => {
60
+ await saveData(data);
61
+ emitEvent("formSubmitted", {
62
+ timestamp: Date.now(),
63
+ data,
64
+ success: true
65
+ });
66
+ };
67
+
68
+ // Notify parent of navigation
69
+ const handleNavigate = (route) => {
70
+ emitEvent("navigationChanged", { route });
71
+ navigate(route);
72
+ };
73
+
74
+ // Notify parent of errors
75
+ const handleError = (error) => {
76
+ emitEvent("errorOccurred", {
77
+ message: error.message,
78
+ code: error.code
79
+ });
80
+ };
81
+ \`\`\`
82
+
83
+ ## Common Embedding Patterns
84
+
85
+ ### Bidirectional Communication
86
+
87
+ \`\`\`typescript
88
+ function EmbeddedDashboard() {
89
+ const properties = useEmbedProperties();
90
+ const emitEvent = useEmitEmbedEvent();
91
+ const [data, setData] = useState(null);
92
+
93
+ // Listen for refresh commands from parent
94
+ useEmbedEvent("refresh", () => {
95
+ fetchData();
96
+ });
97
+
98
+ // Notify parent when data changes
99
+ const handleDataUpdate = async (newData) => {
100
+ await saveData(newData);
101
+ setData(newData);
102
+ emitEvent("dataUpdated", { data: newData });
103
+ };
104
+
105
+ return (
106
+ <Dashboard
107
+ userId={properties.userId}
108
+ data={data}
109
+ onUpdate={handleDataUpdate}
110
+ />
111
+ );
112
+ }
113
+ \`\`\`
114
+
115
+ ### Synchronized State
116
+
117
+ \`\`\`typescript
118
+ function EmbeddedForm() {
119
+ const properties = useEmbedProperties();
120
+ const emitEvent = useEmitEmbedEvent();
121
+ const [formState, setFormState] = useState(properties.initialData || {});
122
+
123
+ // Sync form state changes to parent
124
+ useEffect(() => {
125
+ emitEvent("formStateChanged", { state: formState });
126
+ }, [formState, emitEvent]);
127
+
128
+ // Listen for external state updates
129
+ useEmbedEvent("updateFormState", (payload) => {
130
+ setFormState(prev => ({ ...prev, ...payload }));
131
+ });
132
+
133
+ return <Form value={formState} onChange={setFormState} />;
134
+ }
135
+ \`\`\`
136
+
137
+ ### Loading External Context
138
+
139
+ \`\`\`typescript
140
+ function EmbeddedApp() {
141
+ const properties = useEmbedProperties();
142
+ const { customerId, permissions, branding } = properties;
143
+
144
+ // Use embed properties to customize the app
145
+ return (
146
+ <ThemeProvider theme={branding}>
147
+ <CustomerContext.Provider value={{ customerId, permissions }}>
148
+ <AppContent />
149
+ </CustomerContext.Provider>
150
+ </ThemeProvider>
151
+ );
152
+ }
153
+ \`\`\`
154
+ `;
155
+ //# sourceMappingURL=embedding.generated.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedding.generated.js","sourceRoot":"","sources":["../../../../../../src/ai-service/skills/system/superblocks-frontend/references/embedding.generated.ts"],"names":[],"mappings":"AAAA,gGAAgG;AAChG,mDAAmD;AAEnD,MAAM,CAAC,MAAM,OAAO,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuJtB,CAAC"}
@@ -1,2 +1,2 @@
1
- export declare const content = "---\nname: superblocks-frontend\ndescription: |\n Build frontend UI using React, Tailwind CSS, and Superblocks components. Essential for connecting Superblocks UIs with APIs.\n Use when creating pages, components, handling user interactions, or working with the design system.\nreadOnly: true\nmetadata:\n author: superblocks\n version: \"1.0\"\n---\n\n# Superblocks Frontend Development\n\nThis skill covers building frontend UI for Superblocks applications using React, Tailwind CSS v4, and the Superblocks component library.\n\n## Platform Overview\n\nThis is a React-based web application platform. Use standard React patterns:\n- `useState`, `useEffect`, `useCallback`, `useMemo`\n- Event handlers and controlled components\n- JSX with Tailwind CSS classes\n\n## Using APIs from Frontend\n\nYou **must** use the `useApi` hook for calling backend APIs:\n\n```typescript\nimport { useApi } from \"@superblocksteam/library\";\nimport { toast } from \"sonner\";\n\nexport default function useGetUsers({ email, name }: { email: string | undefined, name: string | undefined }) {\n const { run: runGetUsers } = useApi(\"GetUsers\"); // matches folder apis/GetUsers/api.yaml\n const [loading, setLoading] = useState(false);\n const [users, setUsers] = useState<User[]>([]);\n\n const getUsers = useCallback(async () => {\n setLoading(true);\n try {\n // ALWAYS include ALL inputs, even if they are empty\n const response = await runGetUsers({ email: email ?? null, name: name ?? null });\n setUsers(response?.users ?? []);\n } catch (error) {\n console.error(error);\n toast.error(\"Error fetching users: \" + (error as Error).message);\n } finally {\n setLoading(false);\n }\n }, [email, name, runGetUsers]);\n\n return { getUsers, loading, users };\n}\n```\n\n### Critical API Rules\n\n1. **MUST call API by exact name**: Format is `<ApiName>` matching folder `apis/<ApiName>/api.yaml`\n2. **Always pass parameters**: `await api({ param1: value1, param2: value2 })`\n3. **Store response in React state**: Use `useState`, `useReducer`, etc.\n4. **Use async/await pattern**: APIs are async functions\n5. **Track loading and error states**: Always show visual feedback\n6. **ALWAYS check API interfaces**: NEVER guess the response structure\n7. **Include all parameters**: Even optional ones should be passed as `null`\n8. **Handle errors**: Always show error messages to the user\n9. **Prevent HMR loops**: Guard `useEffect` with a ref:\n\n```tsx\nconst hasLoadedRef = useRef(false);\nuseEffect(() => {\n if (hasLoadedRef.current) return;\n hasLoadedRef.current = true;\n fetchData();\n}, []);\n```\n\n### File Handling\n\n**CRITICAL: Files must be wrapped in `{ files: [...] }` format:**\n\n```tsx\n// \u2705 CORRECT - Frontend: wrap files in { files: [...] }\nconst response = await runUploadApi({ userFile: { files: selectedFiles } });\n\n// \u274C WRONG - backend cannot process unwrapped files\nconst response = await runUploadApi({ userFile: selectedFiles });\n```\n\n## Platform Hooks\n\nAvailable hooks from `@superblocksteam/library`:\n\n```typescript\nimport { \n useSuperblocksUser,\n useSuperblocksGroups,\n useSuperblocksProfiles,\n useEmbedProperties,\n useEmbedEvent,\n useEmitEmbedEvent,\n} from \"@superblocksteam/library\";\n\n// Get current user info\nconst user = useSuperblocksUser();\n// user.name, user.email, user.id, user.groups, user.username, user.metadata\n\n// Get organization groups\nconst groups = useSuperblocksGroups();\n\n// Manage profiles\nconst { profiles, setProfile } = useSuperblocksProfiles();\n\n// For embedded apps - read properties from embedder\nconst properties = useEmbedProperties();\n\n// Listen to events from embedder\nuseEmbedEvent(\"refreshData\", (payload) => {\n refetchData();\n});\n\n// Emit events to embedder\nconst emitEvent = useEmitEmbedEvent();\nemitEvent(\"formSubmitted\", { timestamp: Date.now(), data });\n```\n\n## Application Architecture\n\n### App.tsx Layout Structure\n\n**For single-page applications:**\n- Put all content in `pages/<pageName>/index.tsx`\n- Use components to compose and build the page\n- Keep `App.tsx` minimal with just `<AppProvider>` and `<Outlet />`\n\n**For multi-page applications:**\n- Put shared navigation/layout in `App.tsx` (sidebars, headers, footers)\n- Always include `<Outlet />` for page content\n- Always include `<AppProvider />` wrapper\n- Individual pages focus on content, not layout\n\n```tsx\n// \u2705 CORRECT - Multi-page App.tsx layout\n<AppProvider>\n <div className=\"flex flex-row size-screen\">\n {/* Sidebar - persistent across all pages */}\n <div className=\"flex bg-sidebar border-r w-[250px]\">\n <Navigation />\n </div>\n\n {/* Main content area */}\n <div className=\"flex flex-1 h-full flex-col\">\n {/* Header - persistent across all pages */}\n <div className=\"flex bg-header border-b h-[60px]\">\n <Header />\n </div>\n\n {/* Page content area */}\n <div className=\"flex p-4 flex-1 overflow-auto\">\n <Outlet />\n </div>\n </div>\n </div>\n</AppProvider>\n```\n\n**PROTECTED: NEVER remove `<AppProvider>` or `<Outlet />` from App.tsx!**\n\n### Page Structure\n\n```tsx\n// \u2705 CORRECT - Page focuses on content only\n<div className=\"flex flex-col gap-4 size-screen overflow-auto\">\n <h1 className=\"text-3xl font-bold\">Dashboard Content</h1>\n <Card>\n {/* Page-specific content */}\n </Card>\n</div>\n```\n\n**IMPORTANT**: The first div on the page must have `overflow-auto` so the user's page can scroll.\n\n## Routing\n\nUse `react-router@7` in data mode. Standard patterns apply:\n- `useNavigate()` for programmatic navigation\n- `useParams()` for route parameters\n- `useSearchParams()` for query strings\n\n**If you add new pages or rename files, you MUST update the router.**\n\n## Design System (Tailwind CSS v4)\n\n**All design tokens are defined in `index.css`**. Apps come with a professional black-and-white theme by default.\n\n### Semantic Tokens Rule\n\n**ALWAYS use semantic tokens** \u2014 NEVER raw Tailwind utilities:\n\n```tsx\n// \u2705 CORRECT\n<Card className=\"bg-background text-foreground border border-border\" />\n\n// \u274C WRONG\n<Card className=\"bg-white text-black border-gray-200\" />\n```\n\n### When to Modify index.css\n\nOnly modify when:\n- User explicitly requests branding/theme changes\n- Replicating a specific brand look (e.g., Yelp, Instacart)\n- Feature requests (lists, filters, CRUD) do NOT require changes\n\n**Modification Rules:**\n- All colors must be in OKLCH format\n- Use semantic names (`--color-warning`, `--shadow-elevated`)\n- Do not remove or rename existing tokens\n- Limit color palette to 5 colors max\n- Avoid gradients unless explicitly requested\n- Minimal font sizes (3 max: body, section heading, main heading)\n\n### Component Variants\n\nUse or create variants instead of one-off styles:\n\n```tsx\n// \u274C WRONG - Hacky inline overrides\n<Button className=\"text-white border-white hover:bg-white\" />\n\n// \u2705 CORRECT - Use a variant\n<Button variant=\"secondary\" />\n```\n\n## Icons\n\nUse icons from Lucide React library:\n\n```tsx\nimport { Icon } from \"@/components/ui/icon\";\n<Icon icon=\"heart\" />\n\nimport { Button } from \"@/components/ui/button\";\n<Button><Icon icon=\"plus\" /> Add Item</Button>\n```\n\n**Always use icons rather than emojis unless explicitly requested.**\n\n## Custom Components\n\n**CRITICAL: Component composition is MANDATORY. DO NOT create monolithic pages.**\n\n### The Composition Rule\n\nWhen building ANY feature:\n1. **First**, identify reusable parts (list items, cards, forms, filters, headers)\n2. **Then**, create separate component files\n3. **Finally**, compose them together in the page\n\n### When to Create Components\n\n- **Rendering any list** - Extract to a component\n- **Building cards/complex UI** - Each card type is a component\n- **Creating forms** - Form sections are components\n- **Adding filters/headers** - These are components\n- **Page has >50 lines JSX** - Break it down\n\n### Component Boundary Rules\n\n**Inside a custom component:**\n- \u2705 Use React hooks (useState, useReducer, useEffect, etc.)\n- \u2705 Use local React state\n- \u2705 Use internal helper components\n- \u2705 Use other registered components\n- \u274C CANNOT call APIs - must pass data into the component\n\n### Example: Proper Component Structure\n\n```tsx\n// components/ProductCard/index.tsx - Extract to component\nimport { Card } from \"@/components/ui/card\";\nimport { Button } from \"@/components/ui/button\";\n\ntype ProductCardProps = {\n product: {\n id: string;\n name: string;\n image: string;\n };\n};\n\nexport default function ProductCard(props: ProductCardProps) {\n return (\n <Card>\n <img src={props.product.image} />\n <h3 className=\"text-lg font-semibold\">{props.product.name}</h3>\n <Button>Add</Button>\n </Card>\n );\n}\n\n// pages/Products/index.tsx - Clean composition\nimport ProductCard from \"@/components/ProductCard\";\n\nconst ProductsPage = () => {\n const [products, setProducts] = useState([]);\n\n return (\n <div className=\"grid grid-cols-3 gap-4\">\n {products.map(p => <ProductCard key={p.id} product={p} />)}\n </div>\n );\n};\n```\n\n## Visual Excellence\n\n**Prioritize visual excellence from the start:**\n\n1. **Design System Enhancement**: Start by enhancing `index.css` with app-specific colors that match the target aesthetic\n2. **Professional Layout Architecture**: Use sophisticated layouts with proper spacing, responsive design\n3. **Rich Interactive Components**: Leverage advanced components with proper variants and states\n4. **Visual Polish**: Add shadows, smooth transitions, skeleton loaders, hover effects, typography hierarchy\n5. **Real-World UI Patterns**: Create layouts that feel like professional applications\n\n**Make applications that look and feel like real, polished products - not basic wireframes.**\n\n### Loading States\n\n**Always represent loading with skeletons (shimmers), not spinners or empty screens.**\n\n### Efficient Loading Patterns\n\n1. **Default to Smart Loading**: Check for existing data before showing loading states\n2. **Loading State Hierarchy**:\n - Empty state \u2192 Full loading\n - Has data \u2192 Keep showing data during refetch\n - Error state \u2192 Show error with retry option\n3. **Debounce Rapid Requests**: Prevent multiple API calls in short succession\n4. **Use hooks to encapsulate API logic**: Avoid repeating code\n";
1
+ export declare const content = "---\nname: superblocks-frontend\ndescription: |\n Build frontend UI using React, Tailwind CSS, and Superblocks components. Essential for connecting Superblocks UIs with APIs.\n Use when creating pages, components, handling user interactions, or working with the design system.\nreadOnly: true\nmetadata:\n author: superblocks\n version: \"1.0\"\n---\n\n# Superblocks Frontend Development\n\nThis skill covers building frontend UI for Superblocks applications using React, Tailwind CSS v4, and the Superblocks component library.\n\n## Platform Overview\n\nThis is a React-based web application platform. Use standard React patterns:\n- `useState`, `useEffect`, `useCallback`, `useMemo`\n- Event handlers and controlled components\n- JSX with Tailwind CSS classes\n\n## Using APIs from Frontend\n\nYou **must** use the `useApi` hook for calling backend APIs:\n\n```typescript\nimport { useApi } from \"@superblocksteam/library\";\nimport { toast } from \"sonner\";\n\nexport default function useGetUsers({ email, name }: { email: string | undefined, name: string | undefined }) {\n const { run: runGetUsers } = useApi(\"GetUsers\"); // matches folder apis/GetUsers/api.yaml\n const [loading, setLoading] = useState(false);\n const [users, setUsers] = useState<User[]>([]);\n\n const getUsers = useCallback(async () => {\n setLoading(true);\n try {\n // ALWAYS include ALL inputs, even if they are empty\n const response = await runGetUsers({ email: email ?? null, name: name ?? null });\n setUsers(response?.users ?? []);\n } catch (error) {\n // API errors are thrown as strings, not Error objects\n console.error(error);\n toast.error(\"Error fetching users: \" + error);\n } finally {\n setLoading(false);\n }\n }, [email, name, runGetUsers]);\n\n return { getUsers, loading, users };\n}\n```\n\n### Critical API Rules\n\n1. **MUST call API by exact name**: Format is `<ApiName>` matching folder `apis/<ApiName>/api.yaml`\n2. **Always pass parameters**: `await api({ param1: value1, param2: value2 })`\n3. **Store response in React state**: Use `useState`, `useReducer`, etc.\n4. **Use async/await pattern**: APIs are async functions\n5. **Track loading and error states**: Always show visual feedback\n6. **ALWAYS check API interfaces**: NEVER guess the response structure\n7. **Include all parameters**: Even optional ones should be passed as `null`\n8. **ALWAYS use try/catch**: APIs throw string errors when they fail - wrap ALL API calls in try/catch blocks\n9. **Prevent HMR loops**: Guard `useEffect` with a ref:\n\n```tsx\nconst hasLoadedRef = useRef(false);\nuseEffect(() => {\n if (hasLoadedRef.current) return;\n hasLoadedRef.current = true;\n fetchData();\n}, []);\n```\n\n### File Handling\n\n**CRITICAL: Files must be wrapped in `{ files: [...] }` format:**\n\n```tsx\n// \u2705 CORRECT - Frontend: wrap files in { files: [...] }\nconst response = await runUploadApi({ userFile: { files: selectedFiles } });\n\n// \u274C WRONG - backend cannot process unwrapped files\nconst response = await runUploadApi({ userFile: selectedFiles });\n```\n\n## Platform Hooks\n\nAvailable hooks from `@superblocksteam/library`:\n\n```typescript\nimport { \n useSuperblocksUser,\n useSuperblocksGroups,\n useSuperblocksProfiles,\n} from \"@superblocksteam/library\";\n\n// Get current user info\nconst user = useSuperblocksUser();\n// user.name, user.email, user.id, user.groups, user.username, user.metadata\n\n// Get organization groups\nconst groups = useSuperblocksGroups();\n\n// Manage profiles\nconst { profiles, setProfile } = useSuperblocksProfiles();\n```\n\n**For embedded applications**, see the `references/embedding.md` file for `useEmbedProperties`, `useEmbedEvent`, and `useEmitEmbedEvent` hooks.\n\n## Application Architecture\n\n### App.tsx Layout Structure\n\n**For single-page applications:**\n- Put all content in `pages/<pageName>/index.tsx`\n- Use components to compose and build the page\n- Keep `App.tsx` minimal with just `<AppProvider>` and `<Outlet />`\n\n**For multi-page applications:**\n- Put shared navigation/layout in `App.tsx` (sidebars, headers, footers)\n- Always include `<Outlet />` for page content\n- Always include `<AppProvider />` wrapper\n- Individual pages focus on content, not layout\n\n```tsx\n// \u2705 CORRECT - Multi-page App.tsx layout\n<AppProvider>\n <div className=\"flex flex-row size-screen\">\n {/* Sidebar - persistent across all pages */}\n <div className=\"flex bg-sidebar border-r w-[250px]\">\n <Navigation />\n </div>\n\n {/* Main content area */}\n <div className=\"flex flex-1 h-full flex-col\">\n {/* Header - persistent across all pages */}\n <div className=\"flex bg-header border-b h-[60px]\">\n <Header />\n </div>\n\n {/* Page content area */}\n <div className=\"flex p-4 flex-1 overflow-auto\">\n <Outlet />\n </div>\n </div>\n </div>\n</AppProvider>\n```\n\n**PROTECTED: NEVER remove `<AppProvider>` or `<Outlet />` from App.tsx!**\n\n### Page Structure\n\n```tsx\n// \u2705 CORRECT - Page focuses on content only\n<div className=\"flex flex-col gap-4 size-screen overflow-auto\">\n <h1 className=\"text-3xl font-bold\">Dashboard Content</h1>\n <Card>\n {/* Page-specific content */}\n </Card>\n</div>\n```\n\n**IMPORTANT**: The first div on the page must have `overflow-auto` so the user's page can scroll.\n\n## Routing\n\nUse `react-router@7` in data mode. Standard patterns apply:\n- `useNavigate()` for programmatic navigation\n- `useParams()` for route parameters\n- `useSearchParams()` for query strings\n\n**If you add new pages or rename files, you MUST update the router.**\n\n## Design System (Tailwind CSS v4)\n\n**All design tokens are defined in `index.css`**. Apps come with a professional black-and-white theme by default.\n\n### Semantic Tokens Rule\n\n**ALWAYS use semantic tokens** \u2014 NEVER raw Tailwind utilities:\n\n```tsx\n// \u2705 CORRECT\n<Card className=\"bg-background text-foreground border border-border\" />\n\n// \u274C WRONG\n<Card className=\"bg-white text-black border-gray-200\" />\n```\n\n### When to Modify index.css\n\nOnly modify when:\n- User explicitly requests branding/theme changes\n- Replicating a specific brand look (e.g., Yelp, Instacart)\n- Feature requests (lists, filters, CRUD) do NOT require changes\n\n**Modification Rules:**\n- All colors must be in OKLCH format\n- Use semantic names (`--color-warning`, `--shadow-elevated`)\n- Do not remove or rename existing tokens\n- Limit color palette to 5 colors max\n- Avoid gradients unless explicitly requested\n- Minimal font sizes (3 max: body, section heading, main heading)\n\n### Component Variants\n\nUse or create variants instead of one-off styles:\n\n```tsx\n// \u274C WRONG - Hacky inline overrides\n<Button className=\"text-white border-white hover:bg-white\" />\n\n// \u2705 CORRECT - Use a variant\n<Button variant=\"secondary\" />\n```\n\n## Icons\n\nUse icons from Lucide React library:\n\n```tsx\nimport { Icon } from \"@/components/ui/icon\";\n<Icon icon=\"heart\" />\n\nimport { Button } from \"@/components/ui/button\";\n<Button><Icon icon=\"plus\" /> Add Item</Button>\n```\n\n**Always use icons rather than emojis unless explicitly requested.**\n\n## Custom Components\n\n**CRITICAL: Component composition is MANDATORY. DO NOT create monolithic pages.**\n\n### The Composition Rule\n\nWhen building ANY feature:\n1. **First**, identify reusable parts (list items, cards, forms, filters, headers)\n2. **Then**, create separate component files\n3. **Finally**, compose them together in the page\n\n### When to Create Components\n\n- **Rendering any list** - Extract to a component\n- **Building cards/complex UI** - Each card type is a component\n- **Creating forms** - Form sections are components\n- **Adding filters/headers** - These are components\n- **Page has >50 lines JSX** - Break it down\n\n### Component Boundary Rules\n\n**Inside a custom component:**\n- \u2705 Use React hooks (useState, useReducer, useEffect, etc.)\n- \u2705 Use local React state\n- \u2705 Use internal helper components\n- \u2705 Use other registered components\n- \u274C CANNOT call APIs - must pass data into the component\n\n### Example: Proper Component Structure\n\n```tsx\n// components/ProductCard/index.tsx - Extract to component\nimport { Card } from \"@/components/ui/card\";\nimport { Button } from \"@/components/ui/button\";\n\ntype ProductCardProps = {\n product: {\n id: string;\n name: string;\n image: string;\n };\n};\n\nexport default function ProductCard(props: ProductCardProps) {\n return (\n <Card>\n <img src={props.product.image} />\n <h3 className=\"text-lg font-semibold\">{props.product.name}</h3>\n <Button>Add</Button>\n </Card>\n );\n}\n\n// pages/Products/index.tsx - Clean composition\nimport ProductCard from \"@/components/ProductCard\";\n\nconst ProductsPage = () => {\n const [products, setProducts] = useState([]);\n\n return (\n <div className=\"grid grid-cols-3 gap-4\">\n {products.map(p => <ProductCard key={p.id} product={p} />)}\n </div>\n );\n};\n```\n\n## Visual Excellence\n\n**Prioritize visual excellence from the start:**\n\n1. **Design System Enhancement**: Start by enhancing `index.css` with app-specific colors that match the target aesthetic\n2. **Professional Layout Architecture**: Use sophisticated layouts with proper spacing, responsive design\n3. **Rich Interactive Components**: Leverage advanced components with proper variants and states\n4. **Visual Polish**: Add shadows, smooth transitions, skeleton loaders, hover effects, typography hierarchy\n5. **Real-World UI Patterns**: Create layouts that feel like professional applications\n\n**Make applications that look and feel like real, polished products - not basic wireframes.**\n\n### Loading States\n\n**Always represent loading with skeletons (shimmers), not spinners or empty screens.**\n\n### Efficient Loading Patterns\n\n1. **Default to Smart Loading**: Check for existing data before showing loading states\n2. **Loading State Hierarchy**:\n - Empty state \u2192 Full loading\n - Has data \u2192 Keep showing data during refetch\n - Error state \u2192 Show error with retry option\n3. **Debounce Rapid Requests**: Prevent multiple API calls in short succession\n4. **Use hooks to encapsulate API logic**: Avoid repeating code\n\n## Performance Rules\n\n### 1. ALWAYS Paginate Tables and Lists\n\n**NEVER render more than 50 rows without pagination.** Always add client-side pagination:\n\n```tsx\nfunction PaginatedTable({ data }: { data: any[] }) {\n const PAGE_SIZE = 20;\n const [page, setPage] = useState(0);\n const totalPages = Math.ceil(data.length / PAGE_SIZE);\n const pageData = useMemo(() => data.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE), [data, page]);\n\n useEffect(() => { setPage(0); }, [data.length]);\n\n return (<>\n <Table>{/* render pageData rows */}</Table>\n <span>Page {page + 1} of {totalPages} ({data.length} total rows)</span>\n <Button onClick={() => setPage((p) => Math.max(0, p - 1))} disabled={page === 0}>Previous</Button>\n <Button onClick={() => setPage((p) => Math.min(totalPages - 1, p + 1))} disabled={page >= totalPages - 1}>Next</Button>\n </>);\n}\n```\n\nFor 200+ rows, prefer **server-side pagination**; use cursor/keyset pagination for high offsets instead of `LIMIT`/`OFFSET`.\n\nFor 500+ item lists where pagination doesn't fit the UX (chat messages, infinite scroll feeds, large dropdowns), use **virtualization** (`react-virtuoso` or `@tanstack/react-virtual`) to render only the items visible in the viewport.\n\n### 2. ALWAYS Debounce Input-Driven API Calls\n\n**NEVER call an API directly from onChange.** Debounce search/filter inputs with a 300ms timer:\n\n```tsx\nfunction DebouncedSearch({ onSearch }: { onSearch: (query: string) => void }) {\n const [localValue, setLocalValue] = useState(\"\");\n const timerRef = useRef<ReturnType<typeof setTimeout>>();\n const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {\n setLocalValue(e.target.value);\n clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => onSearch(e.target.value), 300);\n }, [onSearch]);\n useEffect(() => () => clearTimeout(timerRef.current), []);\n\n return <Input value={localValue} onChange={handleChange} placeholder=\"Search...\" />;\n}\n```\n\n### 3. Memoize Expensive Renders\n\nUse memoization (`memo()`, `useMemo`, `useCallback`) when it prevents measurable re-renders or expensive recomputation:\n\n```tsx\nconst OrderRow = memo(function OrderRow({ order, onSelect }: { order: Order; onSelect: (id: string) => void }) {\n return <TableRow onClick={() => onSelect(order.id)}><TableCell>{order.id}</TableCell>...</TableRow>;\n});\n\nconst handleSelect = useCallback((id: string) => {\n setSelectedId(id);\n}, []);\n\nconst filtered = useMemo(\n () => orders.filter(o => o.status === status).sort((a, b) => b.total - a.total),\n [orders, status],\n);\n```\n\n### 4. ALWAYS Clean Up Side Effects\n\nClean up timers, event listeners, and subscriptions in `useEffect` return functions:\n\n```tsx\nuseEffect(() => {\n const handler = (e: KeyboardEvent) => { /* ... */ };\n window.addEventListener(\"keydown\", handler);\n return () => window.removeEventListener(\"keydown\", handler);\n}, []);\n```\n\n### 5. Cancel In-Flight API Requests on Unmount\n\nWhen debouncing or fetching data, use the `cancel()` function from `useApi` to cancel in-flight requests when the component unmounts or a newer request supersedes the previous one:\n\n```tsx\nconst { run, cancel } = useApi(\"SearchProducts\");\n\nuseEffect(() => {\n if (!query) return;\n run({ query }).then(res => setResults(res?.products ?? [])).catch(console.error);\n return () => { void cancel(); };\n}, [query, run, cancel]);\n```\n";
2
2
  //# sourceMappingURL=skill.generated.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"skill.generated.d.ts","sourceRoot":"","sources":["../../../../../src/ai-service/skills/system/superblocks-frontend/skill.generated.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,m2UAiVnB,CAAC"}
1
+ {"version":3,"file":"skill.generated.d.ts","sourceRoot":"","sources":["../../../../../src/ai-service/skills/system/superblocks-frontend/skill.generated.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,OAAO,slbAianB,CAAC"}