spine-framework 0.1.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 (385) hide show
  1. package/.framework/README.md +129 -0
  2. package/.framework/cli/bin.cjs +14 -0
  3. package/.framework/cli/commands/agents.ts +153 -0
  4. package/.framework/cli/commands/auth.ts +94 -0
  5. package/.framework/cli/commands/create-app.ts +185 -0
  6. package/.framework/cli/commands/dev.ts +295 -0
  7. package/.framework/cli/commands/doctor.ts +442 -0
  8. package/.framework/cli/commands/generate.ts +332 -0
  9. package/.framework/cli/commands/init.ts +272 -0
  10. package/.framework/cli/commands/install-app.ts +391 -0
  11. package/.framework/cli/commands/items.ts +253 -0
  12. package/.framework/cli/commands/migrations.ts +141 -0
  13. package/.framework/cli/commands/pipelines.ts +166 -0
  14. package/.framework/cli/commands/status.ts +197 -0
  15. package/.framework/cli/commands/system.ts +184 -0
  16. package/.framework/cli/commands/test.ts +227 -0
  17. package/.framework/cli/commands/uninstall-app.ts +166 -0
  18. package/.framework/cli/context.ts +268 -0
  19. package/.framework/cli/env-loader.ts +36 -0
  20. package/.framework/cli/index.ts +106 -0
  21. package/.framework/cli/welcome.cjs +45 -0
  22. package/.framework/docs/API.md +384 -0
  23. package/.framework/docs/STABILITY.md +52 -0
  24. package/.framework/docs/admin-routes.md +76 -0
  25. package/.framework/docs/api-docs-progress.md +38 -0
  26. package/.framework/docs/api-governance.md +146 -0
  27. package/.framework/docs/api-testing-results.md +212 -0
  28. package/.framework/docs/apis/admin-configs.md +567 -0
  29. package/.framework/docs/apis/admin-data.md +272 -0
  30. package/.framework/docs/apis/index.md +231 -0
  31. package/.framework/docs/apis/internal.md +295 -0
  32. package/.framework/docs/apis/runtime.md +537 -0
  33. package/.framework/docs/assembly-launch-guide.md +138 -0
  34. package/.framework/docs/audit-results.md +590 -0
  35. package/.framework/docs/authorization-model.md +170 -0
  36. package/.framework/docs/db-api-inventory.md +95 -0
  37. package/.framework/docs/examples/custom-app/README.md +77 -0
  38. package/.framework/docs/examples/custom-function/README.md +27 -0
  39. package/.framework/docs/examples/custom-function/handler.ts +48 -0
  40. package/.framework/docs/examples/custom-webhook/README.md +68 -0
  41. package/.framework/docs/gap-remediation-backlog.md +103 -0
  42. package/.framework/docs/guides/cli-guide.md +224 -0
  43. package/.framework/docs/guides/getting-started.md +103 -0
  44. package/.framework/docs/guides/import-guide.md +193 -0
  45. package/.framework/docs/guides/testing-guide.md +229 -0
  46. package/.framework/docs/permission-examples.md +326 -0
  47. package/.framework/docs/ui-adoption-verification.md +111 -0
  48. package/.framework/docs/ui-api-coverage.md +84 -0
  49. package/.framework/docs/v2-compatibility-audit.md +228 -0
  50. package/.framework/functions/.gitkeep +1 -0
  51. package/.framework/functions/_shared/agent-runner.ts +1097 -0
  52. package/.framework/functions/_shared/app-manifest.ts +184 -0
  53. package/.framework/functions/_shared/audit.ts +150 -0
  54. package/.framework/functions/_shared/db.ts +174 -0
  55. package/.framework/functions/_shared/index.ts +382 -0
  56. package/.framework/functions/_shared/middleware.ts +490 -0
  57. package/.framework/functions/_shared/permissions.ts +1325 -0
  58. package/.framework/functions/_shared/pipeline-runner.ts +731 -0
  59. package/.framework/functions/_shared/principal.ts +760 -0
  60. package/.framework/functions/_shared/schema-utils.ts +967 -0
  61. package/.framework/functions/_shared/testing.ts +258 -0
  62. package/.framework/functions/_shared/trigger-engine.ts +425 -0
  63. package/.framework/functions/_shared/webhook-registration.ts +168 -0
  64. package/.framework/functions/_shared/webhook-registry.ts +129 -0
  65. package/.framework/functions/account-nodes.ts +111 -0
  66. package/.framework/functions/admin-data.ts +606 -0
  67. package/.framework/functions/ai-agents.ts +323 -0
  68. package/.framework/functions/api-keys.ts +376 -0
  69. package/.framework/functions/apps.ts +483 -0
  70. package/.framework/functions/auth.ts +196 -0
  71. package/.framework/functions/debug-auth.ts +107 -0
  72. package/.framework/functions/embeddings.ts +556 -0
  73. package/.framework/functions/integration-routes.ts +523 -0
  74. package/.framework/functions/integrations.ts +319 -0
  75. package/.framework/functions/item-progress.ts +272 -0
  76. package/.framework/functions/logs.ts +438 -0
  77. package/.framework/functions/observability.ts +275 -0
  78. package/.framework/functions/pipeline-executions.ts +494 -0
  79. package/.framework/functions/pipelines.ts +485 -0
  80. package/.framework/functions/prompt-configs.ts +339 -0
  81. package/.framework/functions/roles.ts +387 -0
  82. package/.framework/functions/system-cron.ts +742 -0
  83. package/.framework/functions/system.ts +323 -0
  84. package/.framework/functions/tests.ts +119 -0
  85. package/.framework/functions/timers.ts +357 -0
  86. package/.framework/functions/triggers.ts +563 -0
  87. package/.framework/functions/types.ts +604 -0
  88. package/.framework/migrations/000_foundation.sql +1256 -0
  89. package/.framework/migrations/001_seed.sql +92 -0
  90. package/.framework/migrations/002_seed_constraints.sql +13 -0
  91. package/.framework/migrations/003_auth_user_trigger.sql +59 -0
  92. package/.framework/src/App.tsx +126 -0
  93. package/.framework/src/apps/admin/index.tsx +173 -0
  94. package/.framework/src/components/AppWrapper.tsx +56 -0
  95. package/.framework/src/components/CustomAppLoader.tsx +116 -0
  96. package/.framework/src/components/admin/AdminListPage.tsx +151 -0
  97. package/.framework/src/components/admin/AdminSidebar.tsx +166 -0
  98. package/.framework/src/components/admin/AdminStatsCard.tsx +62 -0
  99. package/.framework/src/components/admin/SortableTableHeader.tsx +42 -0
  100. package/.framework/src/components/app-shell/GenericAppShell.tsx +181 -0
  101. package/.framework/src/components/app-shell/GenericDetailPage.tsx +200 -0
  102. package/.framework/src/components/app-shell/GenericListPage.tsx +116 -0
  103. package/.framework/src/components/app-sidebar.tsx +228 -0
  104. package/.framework/src/components/auth/ProtectedRoute.tsx +88 -0
  105. package/.framework/src/components/layout/AppShell.tsx +91 -0
  106. package/.framework/src/components/layout/Header.tsx +88 -0
  107. package/.framework/src/components/layout/Layout.tsx +95 -0
  108. package/.framework/src/components/layout/Sidebar.tsx +329 -0
  109. package/.framework/src/components/runtime/DataDetailHeader.tsx +77 -0
  110. package/.framework/src/components/runtime/DataDetailPage.tsx +171 -0
  111. package/.framework/src/components/runtime/DataFilters.tsx +91 -0
  112. package/.framework/src/components/runtime/DataHeader.tsx +68 -0
  113. package/.framework/src/components/runtime/DataListPage.tsx +124 -0
  114. package/.framework/src/components/runtime/DataStats.tsx +70 -0
  115. package/.framework/src/components/runtime/DataTable.tsx +174 -0
  116. package/.framework/src/components/runtime/SchemaDetailForm.tsx +134 -0
  117. package/.framework/src/components/runtime/index.ts +18 -0
  118. package/.framework/src/components/search-form.tsx +29 -0
  119. package/.framework/src/components/shared/AgentView.tsx +213 -0
  120. package/.framework/src/components/shared/FieldRenderer.tsx +478 -0
  121. package/.framework/src/components/shared/SchemaFields.tsx +226 -0
  122. package/.framework/src/components/ui/DataTable.tsx +343 -0
  123. package/.framework/src/components/ui/Form.tsx +281 -0
  124. package/.framework/src/components/ui/ItemCard.tsx +296 -0
  125. package/.framework/src/components/ui/ItemListView.tsx +308 -0
  126. package/.framework/src/components/ui/LoadingSpinner.tsx +52 -0
  127. package/.framework/src/components/ui/Modal.tsx +61 -0
  128. package/.framework/src/components/ui/RichTextEditor.tsx +210 -0
  129. package/.framework/src/components/ui/accordion.tsx +82 -0
  130. package/.framework/src/components/ui/alert-dialog.tsx +197 -0
  131. package/.framework/src/components/ui/alert.tsx +76 -0
  132. package/.framework/src/components/ui/aspect-ratio.tsx +11 -0
  133. package/.framework/src/components/ui/avatar.tsx +110 -0
  134. package/.framework/src/components/ui/badge.tsx +49 -0
  135. package/.framework/src/components/ui/breadcrumb.tsx +122 -0
  136. package/.framework/src/components/ui/button-group.tsx +83 -0
  137. package/.framework/src/components/ui/button.tsx +65 -0
  138. package/.framework/src/components/ui/calendar.tsx +222 -0
  139. package/.framework/src/components/ui/card.tsx +100 -0
  140. package/.framework/src/components/ui/carousel.tsx +240 -0
  141. package/.framework/src/components/ui/chart.tsx +373 -0
  142. package/.framework/src/components/ui/checkbox.tsx +31 -0
  143. package/.framework/src/components/ui/collapsible.tsx +33 -0
  144. package/.framework/src/components/ui/combobox.tsx +299 -0
  145. package/.framework/src/components/ui/command.tsx +193 -0
  146. package/.framework/src/components/ui/context-menu.tsx +261 -0
  147. package/.framework/src/components/ui/dialog.tsx +165 -0
  148. package/.framework/src/components/ui/direction.tsx +22 -0
  149. package/.framework/src/components/ui/drawer.tsx +132 -0
  150. package/.framework/src/components/ui/dropdown-menu.tsx +269 -0
  151. package/.framework/src/components/ui/empty.tsx +104 -0
  152. package/.framework/src/components/ui/field.tsx +238 -0
  153. package/.framework/src/components/ui/hover-card.tsx +42 -0
  154. package/.framework/src/components/ui/input-group.tsx +153 -0
  155. package/.framework/src/components/ui/input-otp.tsx +87 -0
  156. package/.framework/src/components/ui/input.tsx +19 -0
  157. package/.framework/src/components/ui/item.tsx +196 -0
  158. package/.framework/src/components/ui/kbd.tsx +26 -0
  159. package/.framework/src/components/ui/label.tsx +22 -0
  160. package/.framework/src/components/ui/menubar.tsx +277 -0
  161. package/.framework/src/components/ui/native-select.tsx +61 -0
  162. package/.framework/src/components/ui/navigation-menu.tsx +164 -0
  163. package/.framework/src/components/ui/pagination.tsx +129 -0
  164. package/.framework/src/components/ui/popover.tsx +87 -0
  165. package/.framework/src/components/ui/progress.tsx +31 -0
  166. package/.framework/src/components/ui/radio-group.tsx +42 -0
  167. package/.framework/src/components/ui/resizable.tsx +50 -0
  168. package/.framework/src/components/ui/scroll-area.tsx +53 -0
  169. package/.framework/src/components/ui/select.tsx +195 -0
  170. package/.framework/src/components/ui/separator.tsx +26 -0
  171. package/.framework/src/components/ui/sheet.tsx +145 -0
  172. package/.framework/src/components/ui/sidebar.tsx +706 -0
  173. package/.framework/src/components/ui/skeleton.tsx +13 -0
  174. package/.framework/src/components/ui/slider.tsx +59 -0
  175. package/.framework/src/components/ui/sonner.tsx +47 -0
  176. package/.framework/src/components/ui/spinner.tsx +10 -0
  177. package/.framework/src/components/ui/switch.tsx +33 -0
  178. package/.framework/src/components/ui/table-primitives.tsx +141 -0
  179. package/.framework/src/components/ui/table.tsx +114 -0
  180. package/.framework/src/components/ui/tabs.tsx +90 -0
  181. package/.framework/src/components/ui/textarea.tsx +18 -0
  182. package/.framework/src/components/ui/toggle-group.tsx +89 -0
  183. package/.framework/src/components/ui/toggle.tsx +45 -0
  184. package/.framework/src/components/ui/tooltip.tsx +57 -0
  185. package/.framework/src/contexts/AppContext.tsx +133 -0
  186. package/.framework/src/contexts/AuthContext.tsx +371 -0
  187. package/.framework/src/hooks/use-mobile.ts +19 -0
  188. package/.framework/src/hooks/useApi.ts +526 -0
  189. package/.framework/src/hooks/useApps.ts +114 -0
  190. package/.framework/src/hooks/useEntityList.ts +190 -0
  191. package/.framework/src/hooks/useEntityRecord.ts +308 -0
  192. package/.framework/src/hooks/useForm.ts +307 -0
  193. package/.framework/src/hooks/useListSchema.ts +264 -0
  194. package/.framework/src/hooks/useSchemaRecord.ts +223 -0
  195. package/.framework/src/index.css +128 -0
  196. package/.framework/src/lib/api.ts +156 -0
  197. package/.framework/src/lib/supabase.ts +94 -0
  198. package/.framework/src/lib/utils.ts +317 -0
  199. package/.framework/src/main.tsx +27 -0
  200. package/.framework/src/pages/DashboardPage.tsx +181 -0
  201. package/.framework/src/pages/NotFoundPage.tsx +39 -0
  202. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +161 -0
  203. package/.framework/src/pages/admin/AIAgentsPage.tsx +318 -0
  204. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +199 -0
  205. package/.framework/src/pages/admin/APIKeysPage.tsx +303 -0
  206. package/.framework/src/pages/admin/AlertsConfigPage.tsx +523 -0
  207. package/.framework/src/pages/admin/AppDetailPage.tsx +493 -0
  208. package/.framework/src/pages/admin/AppsPage.tsx +355 -0
  209. package/.framework/src/pages/admin/DesignedPage.tsx +491 -0
  210. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +534 -0
  211. package/.framework/src/pages/admin/EmbeddingsPage.tsx +424 -0
  212. package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +176 -0
  213. package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +109 -0
  214. package/.framework/src/pages/admin/IntegratedDashboard.tsx +402 -0
  215. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +187 -0
  216. package/.framework/src/pages/admin/IntegrationsPage.tsx +301 -0
  217. package/.framework/src/pages/admin/LogsPage.tsx +283 -0
  218. package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +85 -0
  219. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +470 -0
  220. package/.framework/src/pages/admin/PipelineDetailPage.tsx +183 -0
  221. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +279 -0
  222. package/.framework/src/pages/admin/PipelinesPage.tsx +390 -0
  223. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +299 -0
  224. package/.framework/src/pages/admin/PromptConfigsPage.tsx +292 -0
  225. package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +434 -0
  226. package/.framework/src/pages/admin/RoleDetailPage.tsx +273 -0
  227. package/.framework/src/pages/admin/RolesPage.tsx +292 -0
  228. package/.framework/src/pages/admin/SelectTestPage.tsx +61 -0
  229. package/.framework/src/pages/admin/ShadcnTestPage.tsx +588 -0
  230. package/.framework/src/pages/admin/SimpleDashboard.tsx +387 -0
  231. package/.framework/src/pages/admin/TestRunDetailPage.tsx +172 -0
  232. package/.framework/src/pages/admin/TestingDashboard.tsx +257 -0
  233. package/.framework/src/pages/admin/TimerDetailPage.tsx +151 -0
  234. package/.framework/src/pages/admin/TimersPage.tsx +376 -0
  235. package/.framework/src/pages/admin/TriggerDetailPage.tsx +149 -0
  236. package/.framework/src/pages/admin/TriggersPage.tsx +381 -0
  237. package/.framework/src/pages/admin/TypeDetailPage.tsx +694 -0
  238. package/.framework/src/pages/admin/TypesPage.tsx +295 -0
  239. package/.framework/src/pages/auth/LoginPage.tsx +188 -0
  240. package/.framework/src/pages/auth/RegisterPage.tsx +163 -0
  241. package/.framework/src/pages/spine-framework/APIPage.tsx +17 -0
  242. package/.framework/src/pages/spine-framework/CLIPage.tsx +25 -0
  243. package/.framework/src/types/auth.ts +125 -0
  244. package/.framework/src/types/types.ts +407 -0
  245. package/STRUCTURE.md +150 -0
  246. package/config/components.json +25 -0
  247. package/config/deno.lock +108 -0
  248. package/config/package-lock.json +17183 -0
  249. package/config/postcss.config.cjs +10 -0
  250. package/config/tailwind.config.cjs +78 -0
  251. package/config/tsconfig.build.json +32 -0
  252. package/config/tsconfig.cli.json +18 -0
  253. package/config/tsconfig.json +41 -0
  254. package/config/tsconfig.node.json +17 -0
  255. package/config/tsconfig.node.tsbuildinfo +1 -0
  256. package/config/tsconfig.tsbuildinfo +1 -0
  257. package/config/typedoc.json +16 -0
  258. package/config/vite.config.d.ts +2 -0
  259. package/config/vite.config.ts +72 -0
  260. package/dist/cli/commands/agents.d.ts +39 -0
  261. package/dist/cli/commands/agents.d.ts.map +1 -0
  262. package/dist/cli/commands/auth.d.ts +36 -0
  263. package/dist/cli/commands/auth.d.ts.map +1 -0
  264. package/dist/cli/commands/create-app.d.ts +23 -0
  265. package/dist/cli/commands/create-app.d.ts.map +1 -0
  266. package/dist/cli/commands/dev.d.ts +39 -0
  267. package/dist/cli/commands/dev.d.ts.map +1 -0
  268. package/dist/cli/commands/doctor.d.ts +42 -0
  269. package/dist/cli/commands/doctor.d.ts.map +1 -0
  270. package/dist/cli/commands/generate.d.ts +36 -0
  271. package/dist/cli/commands/generate.d.ts.map +1 -0
  272. package/dist/cli/commands/init.d.ts +30 -0
  273. package/dist/cli/commands/init.d.ts.map +1 -0
  274. package/dist/cli/commands/install-app.d.ts +30 -0
  275. package/dist/cli/commands/install-app.d.ts.map +1 -0
  276. package/dist/cli/commands/items.d.ts +45 -0
  277. package/dist/cli/commands/items.d.ts.map +1 -0
  278. package/dist/cli/commands/migrations.d.ts +41 -0
  279. package/dist/cli/commands/migrations.d.ts.map +1 -0
  280. package/dist/cli/commands/pipelines.d.ts +40 -0
  281. package/dist/cli/commands/pipelines.d.ts.map +1 -0
  282. package/dist/cli/commands/status.d.ts +23 -0
  283. package/dist/cli/commands/status.d.ts.map +1 -0
  284. package/dist/cli/commands/system.d.ts +29 -0
  285. package/dist/cli/commands/system.d.ts.map +1 -0
  286. package/dist/cli/commands/test.d.ts +46 -0
  287. package/dist/cli/commands/test.d.ts.map +1 -0
  288. package/dist/cli/commands/uninstall-app.d.ts +23 -0
  289. package/dist/cli/commands/uninstall-app.d.ts.map +1 -0
  290. package/dist/cli/context.d.ts +88 -0
  291. package/dist/cli/context.d.ts.map +1 -0
  292. package/dist/cli/env-loader.d.ts +14 -0
  293. package/dist/cli/env-loader.d.ts.map +1 -0
  294. package/dist/cli/index.d.ts +41 -0
  295. package/dist/cli/index.d.ts.map +1 -0
  296. package/dist/functions/_shared/agent-runner.d.ts +156 -0
  297. package/dist/functions/_shared/agent-runner.d.ts.map +1 -0
  298. package/dist/functions/_shared/app-manifest.d.ts +68 -0
  299. package/dist/functions/_shared/app-manifest.d.ts.map +1 -0
  300. package/dist/functions/_shared/audit.d.ts +91 -0
  301. package/dist/functions/_shared/audit.d.ts.map +1 -0
  302. package/dist/functions/_shared/db.d.ts +125 -0
  303. package/dist/functions/_shared/db.d.ts.map +1 -0
  304. package/dist/functions/_shared/index.d.ts +298 -0
  305. package/dist/functions/_shared/index.d.ts.map +1 -0
  306. package/dist/functions/_shared/middleware.d.ts +315 -0
  307. package/dist/functions/_shared/middleware.d.ts.map +1 -0
  308. package/dist/functions/_shared/permissions.d.ts +626 -0
  309. package/dist/functions/_shared/permissions.d.ts.map +1 -0
  310. package/dist/functions/_shared/pipeline-runner.d.ts +124 -0
  311. package/dist/functions/_shared/pipeline-runner.d.ts.map +1 -0
  312. package/dist/functions/_shared/principal.d.ts +284 -0
  313. package/dist/functions/_shared/principal.d.ts.map +1 -0
  314. package/dist/functions/_shared/schema-utils.d.ts +181 -0
  315. package/dist/functions/_shared/schema-utils.d.ts.map +1 -0
  316. package/dist/functions/_shared/testing.d.ts +172 -0
  317. package/dist/functions/_shared/testing.d.ts.map +1 -0
  318. package/dist/functions/_shared/trigger-engine.d.ts +140 -0
  319. package/dist/functions/_shared/trigger-engine.d.ts.map +1 -0
  320. package/dist/functions/_shared/webhook-registration.d.ts +81 -0
  321. package/dist/functions/_shared/webhook-registration.d.ts.map +1 -0
  322. package/dist/functions/_shared/webhook-registry.d.ts +57 -0
  323. package/dist/functions/_shared/webhook-registry.d.ts.map +1 -0
  324. package/dist/functions/account-nodes.d.ts +48 -0
  325. package/dist/functions/account-nodes.d.ts.map +1 -0
  326. package/dist/functions/admin-data.d.ts +178 -0
  327. package/dist/functions/admin-data.d.ts.map +1 -0
  328. package/dist/functions/ai-agents.d.ts +125 -0
  329. package/dist/functions/ai-agents.d.ts.map +1 -0
  330. package/dist/functions/api-keys.d.ts +140 -0
  331. package/dist/functions/api-keys.d.ts.map +1 -0
  332. package/dist/functions/apps.d.ts +163 -0
  333. package/dist/functions/apps.d.ts.map +1 -0
  334. package/dist/functions/auth.d.ts +74 -0
  335. package/dist/functions/auth.d.ts.map +1 -0
  336. package/dist/functions/debug-auth.d.ts +33 -0
  337. package/dist/functions/debug-auth.d.ts.map +1 -0
  338. package/dist/functions/embeddings.d.ts +205 -0
  339. package/dist/functions/embeddings.d.ts.map +1 -0
  340. package/dist/functions/integration-routes.d.ts +45 -0
  341. package/dist/functions/integration-routes.d.ts.map +1 -0
  342. package/dist/functions/integrations.d.ts +124 -0
  343. package/dist/functions/integrations.d.ts.map +1 -0
  344. package/dist/functions/item-progress.d.ts +41 -0
  345. package/dist/functions/item-progress.d.ts.map +1 -0
  346. package/dist/functions/logs.d.ts +162 -0
  347. package/dist/functions/logs.d.ts.map +1 -0
  348. package/dist/functions/observability.d.ts +123 -0
  349. package/dist/functions/observability.d.ts.map +1 -0
  350. package/dist/functions/pipeline-executions.d.ts +190 -0
  351. package/dist/functions/pipeline-executions.d.ts.map +1 -0
  352. package/dist/functions/pipelines.d.ts +171 -0
  353. package/dist/functions/pipelines.d.ts.map +1 -0
  354. package/dist/functions/prompt-configs.d.ts +125 -0
  355. package/dist/functions/prompt-configs.d.ts.map +1 -0
  356. package/dist/functions/roles.d.ts +118 -0
  357. package/dist/functions/roles.d.ts.map +1 -0
  358. package/dist/functions/system-cron.d.ts +65 -0
  359. package/dist/functions/system-cron.d.ts.map +1 -0
  360. package/dist/functions/system.d.ts +29 -0
  361. package/dist/functions/system.d.ts.map +1 -0
  362. package/dist/functions/tests.d.ts +28 -0
  363. package/dist/functions/tests.d.ts.map +1 -0
  364. package/dist/functions/timers.d.ts +139 -0
  365. package/dist/functions/timers.d.ts.map +1 -0
  366. package/dist/functions/triggers.d.ts +203 -0
  367. package/dist/functions/triggers.d.ts.map +1 -0
  368. package/dist/functions/types.d.ts +151 -0
  369. package/dist/functions/types.d.ts.map +1 -0
  370. package/dist/src/types/types.d.ts +364 -0
  371. package/dist/src/types/types.d.ts.map +1 -0
  372. package/package.json +192 -0
  373. package/scripts/app-install-cli.ts +286 -0
  374. package/scripts/assemble-frontend.sh +79 -0
  375. package/scripts/assemble-functions.sh +62 -0
  376. package/scripts/assemble.sh +35 -0
  377. package/scripts/boundary-check.sh +106 -0
  378. package/scripts/build-manifest.sh +80 -0
  379. package/scripts/check-core-integrity.sh +82 -0
  380. package/scripts/ingest-chunks.cjs +202 -0
  381. package/scripts/kb-chunk-parser.cjs +312 -0
  382. package/scripts/kb-chunk-parser.ts +330 -0
  383. package/scripts/load-test-app-install.ts +484 -0
  384. package/scripts/netlify-dev-wrapper.sh +22 -0
  385. package/scripts/verify-integrity.sh +69 -0
@@ -0,0 +1,376 @@
1
+ /**
2
+ * @module src/pages/admin/TimersPage
3
+ * @audience installer
4
+ * @layer frontend-page
5
+ * @stability stable
6
+ *
7
+ * Admin list page for scheduled timers. Fetches all timers via
8
+ * `/api/timers?action=list`, applies client-side search, type filter
9
+ * (`schedule` | `delay` | `recurring` | `cron`), and sort. Renders
10
+ * inside `AdminListPage` with stat cards and a sortable table. Row
11
+ * clicks navigate to `/spine-framework/admin/configs/timers/:id`.
12
+ *
13
+ * @seeAlso src/pages/admin/TimerDetailPage.tsx
14
+ */
15
+
16
+ import React, { useState } from 'react'
17
+ import { useNavigate } from 'react-router-dom'
18
+ import { useApi } from '../../hooks/useApi'
19
+ import { apiFetch } from '../../lib/api'
20
+ import { Plus, Clock, CheckCircle, Calendar, RefreshCw, Settings } from 'lucide-react';
21
+ import { LoadingSpinner } from '../../components/ui/LoadingSpinner'
22
+ import { Button } from '../../components/ui/button'
23
+ import { Badge } from '../../components/ui/badge'
24
+ import { formatDateTime } from '../../lib/utils'
25
+ import { AdminListPage } from '../../components/admin/AdminListPage'
26
+ import { SortableTableHeader } from '../../components/admin/SortableTableHeader'
27
+
28
+ interface Timer {
29
+ id: string
30
+ name: string
31
+ description?: string
32
+ timer_type: 'schedule' | 'delay' | 'recurring' | 'cron'
33
+ config: {
34
+ schedule?: string
35
+ delay_minutes?: number
36
+ interval_minutes?: number
37
+ cron_expression?: string
38
+ timezone?: string
39
+ }
40
+ pipeline_id?: string
41
+ pipeline_name?: string
42
+ is_active: boolean
43
+ created_at: string
44
+ updated_at: string
45
+ created_by: string
46
+ account_id: string
47
+ last_execution?: string
48
+ next_execution?: string
49
+ execution_count: number
50
+ success_count: number
51
+ failure_count: number
52
+ }
53
+
54
+ export function TimersPage() {
55
+ const navigate = useNavigate()
56
+ const [searchTerm, setSearchTerm] = useState('')
57
+ const [selectedType, setSelectedType] = useState('all')
58
+ const [selectedStatus, setSelectedStatus] = useState('all')
59
+ const [sortKey, setSortKey] = useState('name')
60
+ const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('asc')
61
+
62
+ // Fetch timers from API
63
+ const { data: timers, loading, error, refetch } = useApi<Timer[]>(
64
+ async ({ signal }: { signal?: AbortSignal }) => {
65
+ try {
66
+ console.log('Fetching timers...')
67
+ const response = await apiFetch('/api/timers?action=list', { signal })
68
+ console.log('Response status:', response.status)
69
+
70
+ if (!response.ok) {
71
+ console.error('Response not ok:', response.statusText)
72
+ throw new Error(`Failed to fetch timers: ${response.statusText}`)
73
+ }
74
+
75
+ const result = await response.json()
76
+ console.log('Raw API result:', result)
77
+
78
+ // Handle both nested and direct responses
79
+ const timers = result.data || result
80
+ console.log('Timers after processing:', timers)
81
+
82
+ return timers
83
+ } catch (error) {
84
+ console.error('Error in TimersPage:', error)
85
+ throw error
86
+ }
87
+ },
88
+ { immediate: true }
89
+ )
90
+
91
+ const timerTypes = [
92
+ { value: 'all', label: 'All Types' },
93
+ { value: 'schedule', label: 'Schedule' },
94
+ { value: 'delay', label: 'Delay' },
95
+ { value: 'recurring', label: 'Recurring' },
96
+ { value: 'cron', label: 'Cron' }
97
+ ]
98
+
99
+ const statusOptions = [
100
+ { value: 'all', label: 'All Statuses' },
101
+ { value: 'active', label: 'Active' },
102
+ { value: 'inactive', label: 'Inactive' }
103
+ ]
104
+
105
+ const filteredTimers = (timers || []).filter(timer => {
106
+ const matchesSearch = timer.name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
107
+ (timer.description && timer.description.toLowerCase().includes(searchTerm.toLowerCase()))
108
+ const matchesType = selectedType === 'all' || timer.timer_type === selectedType
109
+ const matchesStatus = selectedStatus === 'all' ||
110
+ (selectedStatus === 'active' && timer.is_active) ||
111
+ (selectedStatus === 'inactive' && !timer.is_active)
112
+ return matchesSearch && matchesType && matchesStatus
113
+ })
114
+
115
+ const getTimerIcon = (timerType: string) => {
116
+ switch (timerType) {
117
+ case 'schedule':
118
+ return <Calendar className="h-5 w-5 text-blue-500" />
119
+ case 'delay':
120
+ return <Clock className="h-5 w-5 text-green-500" />
121
+ case 'recurring':
122
+ return <RefreshCw className="h-5 w-5 text-purple-500" />
123
+ case 'cron':
124
+ return <Settings className="h-5 w-5 text-orange-500" />
125
+ default:
126
+ return <Clock className="h-5 w-5 text-slate-500" />
127
+ }
128
+ }
129
+
130
+ const getTimerBadgeColor = (timerType: string) => {
131
+ switch (timerType) {
132
+ case 'schedule':
133
+ return 'bg-blue-100 text-blue-800'
134
+ case 'delay':
135
+ return 'bg-green-100 text-green-800'
136
+ case 'recurring':
137
+ return 'bg-purple-100 text-purple-800'
138
+ case 'cron':
139
+ return 'bg-orange-100 text-orange-800'
140
+ default:
141
+ return 'bg-slate-100 text-slate-800'
142
+ }
143
+ }
144
+
145
+ const getStatusBadgeColor = (isActive: boolean) => {
146
+ return isActive ? 'bg-green-100 text-green-800' : 'bg-slate-100 text-slate-800'
147
+ }
148
+
149
+ const getSuccessRate = (timer: Timer) => {
150
+ if (timer.execution_count === 0) return 0
151
+ return Math.round((timer.success_count / timer.execution_count) * 100)
152
+ }
153
+
154
+ // Sorting logic
155
+ const sortedTimers = [...filteredTimers].sort((a, b) => {
156
+ const aValue = a[sortKey as keyof Timer]
157
+ const bValue = b[sortKey as keyof Timer]
158
+
159
+ if (aValue === undefined || aValue === null) return 1
160
+ if (bValue === undefined || bValue === null) return -1
161
+
162
+ if (typeof aValue === 'string' && typeof bValue === 'string') {
163
+ return sortDirection === 'asc'
164
+ ? aValue.localeCompare(bValue)
165
+ : bValue.localeCompare(aValue)
166
+ }
167
+
168
+ if (typeof aValue === 'number' && typeof bValue === 'number') {
169
+ return sortDirection === 'asc' ? aValue - bValue : bValue - aValue
170
+ }
171
+
172
+ if (typeof aValue === 'boolean' && typeof bValue === 'boolean') {
173
+ return sortDirection === 'asc'
174
+ ? (aValue ? 1 : 0) - (bValue ? 1 : 0)
175
+ : (bValue ? 1 : 0) - (aValue ? 1 : 0)
176
+ }
177
+
178
+ return 0
179
+ })
180
+
181
+ const handleSort = (key: string) => {
182
+ if (sortKey === key) {
183
+ setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc')
184
+ } else {
185
+ setSortKey(key)
186
+ setSortDirection('asc')
187
+ }
188
+ }
189
+
190
+ const handleRowClick = (timer: Timer) => {
191
+ navigate(`/spine-framework/admin/configs/timers/${timer.id}`)
192
+ }
193
+
194
+ // Stats cards
195
+ const statsCards = [
196
+ {
197
+ title: 'Total Timers',
198
+ value: (timers || []).length,
199
+ icon: Clock,
200
+ iconColor: 'text-blue-500'
201
+ },
202
+ {
203
+ title: 'Active',
204
+ value: (timers || []).filter(t => t.is_active).length,
205
+ icon: CheckCircle,
206
+ iconColor: 'text-green-500'
207
+ },
208
+ {
209
+ title: 'Total Executions',
210
+ value: (timers || []).reduce((sum, t) => sum + t.execution_count, 0),
211
+ icon: Calendar,
212
+ iconColor: 'text-orange-500'
213
+ },
214
+ {
215
+ title: 'Success Rate',
216
+ value: `${Math.round((timers || []).reduce((sum, t) => sum + getSuccessRate(t), 0) / Math.max((timers || []).length, 1))}%`,
217
+ icon: CheckCircle,
218
+ iconColor: 'text-purple-500'
219
+ }
220
+ ]
221
+
222
+ const filters = [
223
+ {
224
+ label: 'Type',
225
+ value: selectedType,
226
+ options: timerTypes,
227
+ onChange: setSelectedType
228
+ },
229
+ {
230
+ label: 'Status',
231
+ value: selectedStatus,
232
+ options: statusOptions,
233
+ onChange: setSelectedStatus
234
+ }
235
+ ]
236
+
237
+ return (
238
+ <AdminListPage
239
+ title="Timers"
240
+ description="Manage scheduled and recurring tasks"
241
+ newButtonText="New Timer"
242
+ newButtonHref="/spine-framework/admin/configs/timers/new"
243
+ statsCards={statsCards}
244
+ searchPlaceholder="Search timers..."
245
+ searchValue={searchTerm}
246
+ onSearchChange={setSearchTerm}
247
+ filters={filters}
248
+ loading={loading}
249
+ emptyMessage="No timers found"
250
+ emptyIcon={Clock}
251
+ >
252
+ {sortedTimers.length === 0 ? (
253
+ <div className="p-8 text-center">
254
+ <Clock className="mx-auto h-12 w-12 text-slate-400" />
255
+ <h3 className="mt-2 text-sm font-medium text-slate-900">No timers found</h3>
256
+ <p className="mt-1 text-sm text-slate-500">
257
+ Try adjusting your search or filters
258
+ </p>
259
+ </div>
260
+ ) : (
261
+ <table className="min-w-full divide-y divide-slate-200">
262
+ <thead className="bg-slate-50">
263
+ <tr>
264
+ <SortableTableHeader
265
+ title="Timer"
266
+ sortKey="name"
267
+ currentSortKey={sortKey}
268
+ currentSortDirection={sortDirection}
269
+ onSort={handleSort}
270
+ />
271
+ <SortableTableHeader
272
+ title="Type"
273
+ sortKey="timer_type"
274
+ currentSortKey={sortKey}
275
+ currentSortDirection={sortDirection}
276
+ onSort={handleSort}
277
+ />
278
+ <SortableTableHeader
279
+ title="Status"
280
+ sortKey="is_active"
281
+ currentSortKey={sortKey}
282
+ currentSortDirection={sortDirection}
283
+ onSort={handleSort}
284
+ />
285
+ <SortableTableHeader
286
+ title="Next Execution"
287
+ sortKey="next_execution"
288
+ currentSortKey={sortKey}
289
+ currentSortDirection={sortDirection}
290
+ onSort={handleSort}
291
+ />
292
+ <SortableTableHeader
293
+ title="Executions"
294
+ sortKey="execution_count"
295
+ currentSortKey={sortKey}
296
+ currentSortDirection={sortDirection}
297
+ onSort={handleSort}
298
+ />
299
+ <SortableTableHeader
300
+ title="Success Rate"
301
+ sortKey="success_count"
302
+ currentSortKey={sortKey}
303
+ currentSortDirection={sortDirection}
304
+ onSort={handleSort}
305
+ />
306
+ <SortableTableHeader
307
+ title="Created"
308
+ sortKey="created_at"
309
+ currentSortKey={sortKey}
310
+ currentSortDirection={sortDirection}
311
+ onSort={handleSort}
312
+ />
313
+ </tr>
314
+ </thead>
315
+ <tbody className="bg-white divide-y divide-slate-200">
316
+ {sortedTimers.map((timer) => (
317
+ <tr
318
+ key={timer.id}
319
+ className="hover:bg-slate-50 cursor-pointer transition-colors"
320
+ onClick={() => handleRowClick(timer)}
321
+ >
322
+ <td className="px-6 py-4 whitespace-nowrap">
323
+ <div>
324
+ <div className="font-medium text-slate-900">
325
+ <span className="text-accent-blue hover:text-navy">
326
+ {timer.name}
327
+ </span>
328
+ </div>
329
+ {timer.description && (
330
+ <div className="text-sm text-slate-500">{timer.description}</div>
331
+ )}
332
+ </div>
333
+ </td>
334
+ <td className="px-6 py-4 whitespace-nowrap">
335
+ <div className="space-y-1">
336
+ <Badge variant={getTimerBadgeColor(timer.timer_type) as any}>
337
+ {timer.timer_type}
338
+ </Badge>
339
+ <div className="text-sm text-slate-500">
340
+ {timer.config.schedule || timer.config.cron_expression ||
341
+ `${timer.config.delay_minutes}min delay` ||
342
+ `${timer.config.interval_minutes}min interval`}
343
+ </div>
344
+ </div>
345
+ </td>
346
+ <td className="px-6 py-4 whitespace-nowrap">
347
+ <Badge variant={getStatusBadgeColor(timer.is_active) as any}>
348
+ {timer.is_active ? 'Active' : 'Inactive'}
349
+ </Badge>
350
+ </td>
351
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-slate-500">
352
+ {timer.next_execution ? formatDateTime(timer.next_execution) : 'Not scheduled'}
353
+ </td>
354
+ <td className="px-6 py-4 whitespace-nowrap">
355
+ <div className="text-sm text-slate-900">{timer.execution_count}</div>
356
+ <div className="text-xs text-slate-500">
357
+ {timer.success_count} success, {timer.failure_count} failed
358
+ </div>
359
+ </td>
360
+ <td className="px-6 py-4 whitespace-nowrap">
361
+ <div className="text-sm text-slate-900">{getSuccessRate(timer)}%</div>
362
+ <div className="text-xs text-slate-500">
363
+ {timer.execution_count > 0 ? 'success rate' : 'no executions'}
364
+ </div>
365
+ </td>
366
+ <td className="px-6 py-4 whitespace-nowrap text-sm text-slate-500">
367
+ {formatDateTime(timer.created_at)}
368
+ </td>
369
+ </tr>
370
+ ))}
371
+ </tbody>
372
+ </table>
373
+ )}
374
+ </AdminListPage>
375
+ )
376
+ }
@@ -0,0 +1,149 @@
1
+ /**
2
+ * @module src/pages/admin/TriggerDetailPage
3
+ */
4
+ import { useState, useEffect } from 'react'
5
+ import { useParams, useNavigate } from 'react-router-dom'
6
+ import { apiFetch } from '../../lib/api'
7
+ import { Button } from '../../components/ui/button'
8
+ import { Input } from '../../components/ui/input'
9
+ import { Textarea } from '../../components/ui/textarea'
10
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../components/ui/select'
11
+ import { Checkbox } from '../../components/ui/checkbox'
12
+ import { Label } from '../../components/ui/label'
13
+ import { Card, CardContent, CardHeader, CardTitle } from '../../components/ui/card'
14
+ import { Skeleton } from '../../components/ui/skeleton'
15
+ import { Alert, AlertDescription, AlertTitle } from '../../components/ui/alert'
16
+ import { Badge } from '../../components/ui/badge'
17
+ import { ArrowLeft, Zap, AlertCircle } from 'lucide-react'
18
+ import { formatDateTime } from '../../lib/utils'
19
+
20
+ interface Trigger {
21
+ id: string
22
+ name: string
23
+ description?: string
24
+ event_type: string
25
+ entity_type?: string
26
+ condition?: Record<string, any>
27
+ action_type: string
28
+ action_config: Record<string, any>
29
+ is_active: boolean
30
+ priority: number
31
+ debounce_ms?: number
32
+ rate_limit_per_minute?: number
33
+ created_at: string
34
+ updated_at: string
35
+ }
36
+
37
+ export function TriggerDetailPage() {
38
+ const { id } = useParams<{ id: string }>()
39
+ const navigate = useNavigate()
40
+ const isCreateMode = !id || id === 'new'
41
+ const [trigger, setTrigger] = useState<Trigger | null>(null)
42
+ const [loading, setLoading] = useState(true)
43
+ const [error, setError] = useState<string | null>(null)
44
+ const [isEditing, setIsEditing] = useState(isCreateMode)
45
+ const [formData, setFormData] = useState({
46
+ name: '', description: '', event_type: '', entity_type: '', condition: '{}', action_type: '',
47
+ action_config: '{}', is_active: true, priority: 0, debounce_ms: 0, rate_limit_per_minute: 0
48
+ })
49
+
50
+ useEffect(() => {
51
+ if (isCreateMode) {
52
+ setLoading(false)
53
+ return
54
+ }
55
+ setLoading(true)
56
+ const fetchTrigger = async () => {
57
+ try {
58
+ const response = await apiFetch(`/api/triggers?action=get&id=${id}`)
59
+ if (!response.ok) throw new Error('Failed to fetch trigger')
60
+ const result = await response.json()
61
+ const data = result.data
62
+ setTrigger(data)
63
+ setFormData({
64
+ name: data.name, description: data.description || '', event_type: data.event_type, entity_type: data.entity_type || '',
65
+ condition: JSON.stringify(data.condition || {}, null, 2), action_type: data.action_type,
66
+ action_config: JSON.stringify(data.action_config || {}, null, 2), is_active: data.is_active, priority: data.priority || 0,
67
+ debounce_ms: data.debounce_ms || 0, rate_limit_per_minute: data.rate_limit_per_minute || 0
68
+ })
69
+ } catch (err) {
70
+ setError(err instanceof Error ? err.message : 'Failed to load trigger')
71
+ } finally {
72
+ setLoading(false)
73
+ }
74
+ }
75
+ fetchTrigger()
76
+ }, [id, isCreateMode])
77
+
78
+ const handleSave = async () => {
79
+ try {
80
+ let parsedCondition = {}, parsedActionConfig = {}
81
+ try { parsedCondition = JSON.parse(formData.condition) } catch {}
82
+ try { parsedActionConfig = JSON.parse(formData.action_config) } catch {}
83
+ const url = isCreateMode ? '/api/triggers?action=create' : `/api/triggers?action=update&id=${id}`
84
+ const method = isCreateMode ? 'POST' : 'PATCH'
85
+ const response = await apiFetch(url, {
86
+ method, headers: { 'Content-Type': 'application/json' },
87
+ body: JSON.stringify({ ...formData, condition: parsedCondition, action_config: parsedActionConfig })
88
+ })
89
+ if (!response.ok) throw new Error('Failed to save trigger')
90
+ if (isCreateMode) {
91
+ const result = await response.json()
92
+ navigate(`/spine-framework/admin/configs/triggers/${result.data?.id || result.id}`)
93
+ } else setIsEditing(false)
94
+ } catch (err) {
95
+ setError(err instanceof Error ? err.message : 'Failed to save')
96
+ }
97
+ }
98
+
99
+ if (loading) return (
100
+ <div className="space-y-6">
101
+ <Skeleton className="h-8 w-48" />
102
+ <Card><CardHeader><Skeleton className="h-6 w-32" /></CardHeader><CardContent className="space-y-4"><Skeleton className="h-4 w-full" /><Skeleton className="h-4 w-2/3" /></CardContent></Card>
103
+ </div>
104
+ )
105
+
106
+ if (error && !isCreateMode) return (
107
+ <Alert variant="destructive"><AlertCircle className="h-4 w-4" /><AlertTitle>Error</AlertTitle><AlertDescription>{error}</AlertDescription></Alert>
108
+ )
109
+
110
+ return (
111
+ <div className="space-y-6">
112
+ <div className="flex items-center justify-between">
113
+ <div className="flex items-center gap-4">
114
+ <Button variant="ghost" onClick={() => isCreateMode ? navigate('/spine-framework/admin/configs/triggers') : navigate(-1)}><ArrowLeft className="h-5 w-5" /></Button>
115
+ <h1 className="text-2xl font-bold">{isCreateMode ? 'Create Trigger' : trigger?.name}</h1>
116
+ </div>
117
+ <div className="flex gap-2">
118
+ {isEditing ? (
119
+ <><Button variant="outline" onClick={() => isCreateMode ? navigate(-1) : setIsEditing(false)}>Cancel</Button><Button onClick={handleSave}>{isCreateMode ? 'Create' : 'Save'}</Button></>
120
+ ) : !isCreateMode && <Button onClick={() => setIsEditing(true)}>Edit</Button>}
121
+ </div>
122
+ </div>
123
+
124
+ <Card><CardContent className="p-6">
125
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-6">
126
+ <div className="space-y-4">
127
+ <h3 className="text-sm font-medium text-muted-foreground">Trigger</h3>
128
+ <div className="space-y-2"><Label>Name</Label>{isEditing ? <Input value={formData.name} onChange={e => setFormData({...formData, name: e.target.value})} /> : <div className="text-sm">{trigger?.name}</div>}</div>
129
+ <div className="space-y-2"><Label>Event Type</Label>{isEditing ? <Input value={formData.event_type} onChange={e => setFormData({...formData, event_type: e.target.value})} placeholder="e.g., item.created" /> : <Badge>{trigger?.event_type}</Badge>}</div>
130
+ <div className="space-y-2"><Label>Entity Type</Label>{isEditing ? <Input value={formData.entity_type} onChange={e => setFormData({...formData, entity_type: e.target.value})} placeholder="e.g., item" /> : <div className="text-sm">{trigger?.entity_type || '—'}</div>}</div>
131
+ <div className="space-y-2"><Label>Active</Label>{isEditing ? <div className="flex items-center gap-2"><Checkbox id="active" checked={formData.is_active} onCheckedChange={c => setFormData({...formData, is_active: c === true})} /><Label htmlFor="active">Enabled</Label></div> : <div className="text-sm">{trigger?.is_active ? 'Yes' : 'No'}</div>}</div>
132
+ </div>
133
+ <div className="space-y-4">
134
+ <h3 className="text-sm font-medium text-muted-foreground">Action</h3>
135
+ <div className="space-y-2"><Label>Action Type</Label>{isEditing ? <Input value={formData.action_type} onChange={e => setFormData({...formData, action_type: e.target.value})} placeholder="e.g., function.execute" /> : <Badge variant="secondary">{trigger?.action_type}</Badge>}</div>
136
+ <div className="space-y-2"><Label>Priority</Label>{isEditing ? <Input type="number" value={formData.priority} onChange={e => setFormData({...formData, priority: parseInt(e.target.value)})} /> : <div className="text-sm">{trigger?.priority}</div>}</div>
137
+ <div className="space-y-2"><Label>Debounce (ms)</Label>{isEditing ? <Input type="number" value={formData.debounce_ms} onChange={e => setFormData({...formData, debounce_ms: parseInt(e.target.value)})} /> : <div className="text-sm">{trigger?.debounce_ms}ms</div>}</div>
138
+ <div className="space-y-2"><Label>Rate Limit (/min)</Label>{isEditing ? <Input type="number" value={formData.rate_limit_per_minute} onChange={e => setFormData({...formData, rate_limit_per_minute: parseInt(e.target.value)})} /> : <div className="text-sm">{trigger?.rate_limit_per_minute}</div>}</div>
139
+ </div>
140
+ </div>
141
+ <div className="mt-6 space-y-2"><Label>Description</Label>{isEditing ? <Textarea value={formData.description} onChange={e => setFormData({...formData, description: e.target.value})} rows={2} /> : <div className="text-sm">{trigger?.description || '—'}</div>}</div>
142
+ <div className="mt-6 grid grid-cols-1 md:grid-cols-2 gap-4">
143
+ <div className="space-y-2"><Label>Condition (JSON)</Label>{isEditing ? <Textarea value={formData.condition} onChange={e => setFormData({...formData, condition: e.target.value})} rows={6} className="font-mono text-sm" /> : <pre className="text-sm bg-muted p-3 rounded">{JSON.stringify(trigger?.condition || {}, null, 2)}</pre>}</div>
144
+ <div className="space-y-2"><Label>Action Config (JSON)</Label>{isEditing ? <Textarea value={formData.action_config} onChange={e => setFormData({...formData, action_config: e.target.value})} rows={6} className="font-mono text-sm" /> : <pre className="text-sm bg-muted p-3 rounded">{JSON.stringify(trigger?.action_config || {}, null, 2)}</pre>}</div>
145
+ </div>
146
+ </CardContent></Card>
147
+ </div>
148
+ )
149
+ }