spine-framework 0.3.17 → 0.3.19

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 (270) hide show
  1. package/.framework/cli/bin.mjs +16 -0
  2. package/.framework/cli/commands/create-app.ts +1 -1
  3. package/.framework/cli/commands/dev.ts +215 -33
  4. package/.framework/cli/index.ts +37 -75
  5. package/.framework/functions/_shared/app-manifest.ts +8 -15
  6. package/.framework/functions/_shared/db.ts +11 -15
  7. package/.framework/functions/_shared/index.ts +7 -16
  8. package/.framework/functions/_shared/principal.ts +4 -62
  9. package/.framework/functions/_shared/resolve-ids.ts +6 -6
  10. package/.framework/functions/_shared/webhook-registry.ts +43 -1
  11. package/.framework/functions/admin-funnel.ts +104 -0
  12. package/.framework/functions/admin-install-funnel.ts +225 -0
  13. package/.framework/functions/admin-signals.ts +241 -0
  14. package/.framework/functions/integration-routes.ts +4 -8
  15. package/.framework/migrations/001_schema.sql +406 -0
  16. package/.framework/migrations/002_rls_and_functions.sql +710 -0
  17. package/.framework/migrations/003_system_data.sql +520 -0
  18. package/.framework/migrations/004_enhancements.sql +43 -0
  19. package/.framework/public/_redirects +3 -0
  20. package/.framework/public/spine-logo.jpg +0 -0
  21. package/.framework/public/spine-logo.svg +3 -0
  22. package/{scripts → .framework/scripts}/assemble-frontend.sh +8 -5
  23. package/{scripts → .framework/scripts}/assemble-functions.sh +4 -47
  24. package/{scripts → .framework/scripts}/assemble.sh +2 -8
  25. package/{scripts → .framework/scripts}/boundary-check.sh +5 -9
  26. package/{scripts → .framework/scripts}/check-core-integrity.sh +0 -0
  27. package/.framework/seeds/link_types/account_cli_instances.json +9 -0
  28. package/.framework/seeds/types/funnel_signal_use.json +98 -0
  29. package/.framework/seeds/types/spine_instance.json +109 -0
  30. package/.framework/src/App.tsx +11 -21
  31. package/.framework/src/components/CustomAppLoader.tsx +2 -19
  32. package/.framework/src/components/ui/accordion.tsx +1 -1
  33. package/.framework/src/components/ui/alert-dialog.tsx +1 -1
  34. package/.framework/src/components/ui/aspect-ratio.tsx +1 -1
  35. package/.framework/src/components/ui/avatar.tsx +1 -1
  36. package/.framework/src/components/ui/badge.tsx +2 -2
  37. package/.framework/src/components/ui/breadcrumb.tsx +2 -2
  38. package/.framework/src/components/ui/button-group.tsx +2 -2
  39. package/.framework/src/components/ui/button.tsx +2 -2
  40. package/.framework/src/components/ui/chart.tsx +6 -1
  41. package/.framework/src/components/ui/checkbox.tsx +1 -1
  42. package/.framework/src/components/ui/collapsible.tsx +1 -1
  43. package/.framework/src/components/ui/context-menu.tsx +1 -1
  44. package/.framework/src/components/ui/dialog.tsx +1 -1
  45. package/.framework/src/components/ui/direction.tsx +17 -1
  46. package/.framework/src/components/ui/dropdown-menu.tsx +1 -1
  47. package/.framework/src/components/ui/hover-card.tsx +1 -1
  48. package/.framework/src/components/ui/item.tsx +2 -2
  49. package/.framework/src/components/ui/label.tsx +1 -1
  50. package/.framework/src/components/ui/menubar.tsx +1 -1
  51. package/.framework/src/components/ui/navigation-menu.tsx +1 -1
  52. package/.framework/src/components/ui/popover.tsx +1 -1
  53. package/.framework/src/components/ui/progress.tsx +1 -1
  54. package/.framework/src/components/ui/radio-group.tsx +1 -1
  55. package/.framework/src/components/ui/scroll-area.tsx +1 -1
  56. package/.framework/src/components/ui/select.tsx +1 -1
  57. package/.framework/src/components/ui/separator.tsx +1 -1
  58. package/.framework/src/components/ui/sheet.tsx +1 -1
  59. package/.framework/src/components/ui/sidebar.tsx +6 -6
  60. package/.framework/src/components/ui/slider.tsx +1 -1
  61. package/.framework/src/components/ui/switch.tsx +1 -1
  62. package/.framework/src/components/ui/tabs.tsx +1 -1
  63. package/.framework/src/components/ui/toggle-group.tsx +1 -1
  64. package/.framework/src/components/ui/toggle.tsx +1 -1
  65. package/.framework/src/components/ui/tooltip.tsx +1 -1
  66. package/.framework/src/pages/auth/LoginPage.tsx +10 -9
  67. package/LICENSE.md +63 -93
  68. package/README.md +254 -129
  69. package/custom/.devin/skills/install-app/SKILL.md +39 -0
  70. package/custom/.devin/workflows/app-install.yaml +83 -0
  71. package/custom/README.md +79 -0
  72. package/docs/APPS.md +232 -0
  73. package/docs/ARCHITECTURE.md +246 -0
  74. package/docs/INSTALL.md +155 -0
  75. package/docs/README.md +170 -0
  76. package/docs/design-schema-spec.md +1837 -0
  77. package/docs/dev-guides/01-create-an-app.md +183 -0
  78. package/docs/dev-guides/02-create-a-function.md +178 -0
  79. package/docs/dev-guides/03-create-a-component.md +178 -0
  80. package/docs/dev-guides/04-webhook-handlers.md +129 -0
  81. package/docs/dev-guides/05-testing.md +168 -0
  82. package/docs/dev-guides/README.md +40 -0
  83. package/docs/npm-packages-plan.md +288 -0
  84. package/docs/spine-core--api-reference.md +822 -0
  85. package/package.json +79 -150
  86. package/.framework/cli/bin.cjs +0 -14
  87. package/.framework/cli/commands/claim.ts +0 -430
  88. package/.framework/cli/commands/init.ts +0 -219
  89. package/.framework/cli/commands/install-app.ts +0 -685
  90. package/.framework/cli/commands/migrate.ts +0 -178
  91. package/.framework/cli/commands/publish.ts +0 -191
  92. package/.framework/cli/commands/status.ts +0 -268
  93. package/.framework/cli/commands/uninstall-app.ts +0 -166
  94. package/.framework/cli/commands/update-app.ts +0 -397
  95. package/.framework/cli/welcome.cjs +0 -45
  96. package/.framework/config/signal-client.ts +0 -147
  97. package/.framework/config/signals.ts +0 -70
  98. package/.framework/docs/STABILITY.md +0 -52
  99. package/.framework/docs/examples/custom-app/README.md +0 -77
  100. package/.framework/docs/examples/custom-function/README.md +0 -27
  101. package/.framework/docs/examples/custom-function/handler.ts +0 -48
  102. package/.framework/docs/examples/custom-webhook/README.md +0 -68
  103. package/.framework/functions/handler-registry.ts +0 -22
  104. package/.framework/functions/signal.ts +0 -168
  105. package/.framework/migrations/000_foundation.sql +0 -1302
  106. package/.framework/migrations/001_seed.sql +0 -163
  107. package/.framework/migrations/002_seed_constraints.sql +0 -19
  108. package/.framework/migrations/003_auth_user_trigger.sql +0 -67
  109. package/.framework/migrations/004_app_version_tracking.sql +0 -8
  110. package/.framework/migrations/005_pipelines_slug_stages.sql +0 -21
  111. package/.framework/src/pages/auth/RegisterPage.tsx +0 -163
  112. package/CHANGELOG.md +0 -71
  113. package/STRUCTURE.md +0 -150
  114. package/bin/spine-framework.cjs +0 -62
  115. package/bin/welcome.cjs +0 -58
  116. package/bin/ws-shim.ts +0 -10
  117. package/config/components.json +0 -25
  118. package/config/deno.lock +0 -108
  119. package/config/package-lock.json +0 -17183
  120. package/config/postcss.config.cjs +0 -10
  121. package/config/tailwind.config.cjs +0 -78
  122. package/config/tsconfig.build.json +0 -32
  123. package/config/tsconfig.cli.json +0 -18
  124. package/config/tsconfig.json +0 -41
  125. package/config/tsconfig.node.json +0 -17
  126. package/config/tsconfig.node.tsbuildinfo +0 -1
  127. package/config/tsconfig.tsbuildinfo +0 -1
  128. package/config/typedoc.json +0 -16
  129. package/config/vite.config.d.ts +0 -2
  130. package/config/vite.config.ts +0 -71
  131. package/dist/cli/commands/agents.d.ts +0 -39
  132. package/dist/cli/commands/agents.d.ts.map +0 -1
  133. package/dist/cli/commands/auth.d.ts +0 -36
  134. package/dist/cli/commands/auth.d.ts.map +0 -1
  135. package/dist/cli/commands/claim.d.ts +0 -38
  136. package/dist/cli/commands/claim.d.ts.map +0 -1
  137. package/dist/cli/commands/create-app.d.ts +0 -23
  138. package/dist/cli/commands/create-app.d.ts.map +0 -1
  139. package/dist/cli/commands/dev.d.ts +0 -24
  140. package/dist/cli/commands/dev.d.ts.map +0 -1
  141. package/dist/cli/commands/doctor.d.ts +0 -42
  142. package/dist/cli/commands/doctor.d.ts.map +0 -1
  143. package/dist/cli/commands/generate.d.ts +0 -36
  144. package/dist/cli/commands/generate.d.ts.map +0 -1
  145. package/dist/cli/commands/init.d.ts +0 -20
  146. package/dist/cli/commands/init.d.ts.map +0 -1
  147. package/dist/cli/commands/install-app.d.ts +0 -30
  148. package/dist/cli/commands/install-app.d.ts.map +0 -1
  149. package/dist/cli/commands/items.d.ts +0 -45
  150. package/dist/cli/commands/items.d.ts.map +0 -1
  151. package/dist/cli/commands/migrate.d.ts +0 -21
  152. package/dist/cli/commands/migrate.d.ts.map +0 -1
  153. package/dist/cli/commands/migrations.d.ts +0 -41
  154. package/dist/cli/commands/migrations.d.ts.map +0 -1
  155. package/dist/cli/commands/pipelines.d.ts +0 -40
  156. package/dist/cli/commands/pipelines.d.ts.map +0 -1
  157. package/dist/cli/commands/publish.d.ts +0 -23
  158. package/dist/cli/commands/publish.d.ts.map +0 -1
  159. package/dist/cli/commands/status.d.ts +0 -23
  160. package/dist/cli/commands/status.d.ts.map +0 -1
  161. package/dist/cli/commands/system.d.ts +0 -29
  162. package/dist/cli/commands/system.d.ts.map +0 -1
  163. package/dist/cli/commands/test.d.ts +0 -46
  164. package/dist/cli/commands/test.d.ts.map +0 -1
  165. package/dist/cli/commands/uninstall-app.d.ts +0 -23
  166. package/dist/cli/commands/uninstall-app.d.ts.map +0 -1
  167. package/dist/cli/commands/update-app.d.ts +0 -24
  168. package/dist/cli/commands/update-app.d.ts.map +0 -1
  169. package/dist/cli/context.d.ts +0 -88
  170. package/dist/cli/context.d.ts.map +0 -1
  171. package/dist/cli/env-loader.d.ts +0 -14
  172. package/dist/cli/env-loader.d.ts.map +0 -1
  173. package/dist/cli/index.d.ts +0 -44
  174. package/dist/cli/index.d.ts.map +0 -1
  175. package/dist/config/signals.d.ts +0 -82
  176. package/dist/config/signals.d.ts.map +0 -1
  177. package/dist/functions/_shared/agent-runner.d.ts +0 -156
  178. package/dist/functions/_shared/agent-runner.d.ts.map +0 -1
  179. package/dist/functions/_shared/app-manifest.d.ts +0 -68
  180. package/dist/functions/_shared/app-manifest.d.ts.map +0 -1
  181. package/dist/functions/_shared/audit.d.ts +0 -91
  182. package/dist/functions/_shared/audit.d.ts.map +0 -1
  183. package/dist/functions/_shared/db.d.ts +0 -125
  184. package/dist/functions/_shared/db.d.ts.map +0 -1
  185. package/dist/functions/_shared/index.d.ts +0 -299
  186. package/dist/functions/_shared/index.d.ts.map +0 -1
  187. package/dist/functions/_shared/middleware.d.ts +0 -315
  188. package/dist/functions/_shared/middleware.d.ts.map +0 -1
  189. package/dist/functions/_shared/permissions.d.ts +0 -626
  190. package/dist/functions/_shared/permissions.d.ts.map +0 -1
  191. package/dist/functions/_shared/pipeline-runner.d.ts +0 -124
  192. package/dist/functions/_shared/pipeline-runner.d.ts.map +0 -1
  193. package/dist/functions/_shared/principal.d.ts +0 -284
  194. package/dist/functions/_shared/principal.d.ts.map +0 -1
  195. package/dist/functions/_shared/resolve-ids.d.ts +0 -10
  196. package/dist/functions/_shared/resolve-ids.d.ts.map +0 -1
  197. package/dist/functions/_shared/schema-utils.d.ts +0 -181
  198. package/dist/functions/_shared/schema-utils.d.ts.map +0 -1
  199. package/dist/functions/_shared/testing.d.ts +0 -172
  200. package/dist/functions/_shared/testing.d.ts.map +0 -1
  201. package/dist/functions/_shared/trigger-engine.d.ts +0 -140
  202. package/dist/functions/_shared/trigger-engine.d.ts.map +0 -1
  203. package/dist/functions/_shared/webhook-registration.d.ts +0 -81
  204. package/dist/functions/_shared/webhook-registration.d.ts.map +0 -1
  205. package/dist/functions/_shared/webhook-registry.d.ts +0 -41
  206. package/dist/functions/_shared/webhook-registry.d.ts.map +0 -1
  207. package/dist/functions/account-nodes.d.ts +0 -48
  208. package/dist/functions/account-nodes.d.ts.map +0 -1
  209. package/dist/functions/admin-data.d.ts +0 -178
  210. package/dist/functions/admin-data.d.ts.map +0 -1
  211. package/dist/functions/ai-agents.d.ts +0 -125
  212. package/dist/functions/ai-agents.d.ts.map +0 -1
  213. package/dist/functions/api-keys.d.ts +0 -140
  214. package/dist/functions/api-keys.d.ts.map +0 -1
  215. package/dist/functions/apps.d.ts +0 -163
  216. package/dist/functions/apps.d.ts.map +0 -1
  217. package/dist/functions/auth.d.ts +0 -74
  218. package/dist/functions/auth.d.ts.map +0 -1
  219. package/dist/functions/debug-auth.d.ts +0 -33
  220. package/dist/functions/debug-auth.d.ts.map +0 -1
  221. package/dist/functions/embeddings.d.ts +0 -205
  222. package/dist/functions/embeddings.d.ts.map +0 -1
  223. package/dist/functions/handler-registry.d.ts +0 -22
  224. package/dist/functions/handler-registry.d.ts.map +0 -1
  225. package/dist/functions/integration-routes.d.ts +0 -45
  226. package/dist/functions/integration-routes.d.ts.map +0 -1
  227. package/dist/functions/integrations.d.ts +0 -124
  228. package/dist/functions/integrations.d.ts.map +0 -1
  229. package/dist/functions/item-progress.d.ts +0 -41
  230. package/dist/functions/item-progress.d.ts.map +0 -1
  231. package/dist/functions/logs.d.ts +0 -162
  232. package/dist/functions/logs.d.ts.map +0 -1
  233. package/dist/functions/observability.d.ts +0 -123
  234. package/dist/functions/observability.d.ts.map +0 -1
  235. package/dist/functions/pipeline-executions.d.ts +0 -190
  236. package/dist/functions/pipeline-executions.d.ts.map +0 -1
  237. package/dist/functions/pipelines.d.ts +0 -171
  238. package/dist/functions/pipelines.d.ts.map +0 -1
  239. package/dist/functions/prompt-configs.d.ts +0 -125
  240. package/dist/functions/prompt-configs.d.ts.map +0 -1
  241. package/dist/functions/roles.d.ts +0 -118
  242. package/dist/functions/roles.d.ts.map +0 -1
  243. package/dist/functions/signal.d.ts +0 -73
  244. package/dist/functions/signal.d.ts.map +0 -1
  245. package/dist/functions/system-cron.d.ts +0 -65
  246. package/dist/functions/system-cron.d.ts.map +0 -1
  247. package/dist/functions/system.d.ts +0 -29
  248. package/dist/functions/system.d.ts.map +0 -1
  249. package/dist/functions/tests.d.ts +0 -28
  250. package/dist/functions/tests.d.ts.map +0 -1
  251. package/dist/functions/timers.d.ts +0 -139
  252. package/dist/functions/timers.d.ts.map +0 -1
  253. package/dist/functions/triggers.d.ts +0 -203
  254. package/dist/functions/triggers.d.ts.map +0 -1
  255. package/dist/functions/types.d.ts +0 -151
  256. package/dist/functions/types.d.ts.map +0 -1
  257. package/dist/src/types/types.d.ts +0 -364
  258. package/dist/src/types/types.d.ts.map +0 -1
  259. package/index.html +0 -13
  260. package/netlify.toml +0 -36
  261. package/package-project.json +0 -71
  262. package/scripts/ingest-chunks.cjs +0 -202
  263. package/scripts/kb-chunk-parser.cjs +0 -312
  264. package/scripts/kb-chunk-parser.ts +0 -330
  265. package/scripts/load-test-app-install.ts +0 -484
  266. package/scripts/netlify-dev-wrapper.sh +0 -22
  267. package/vitest.config.ts +0 -45
  268. /package/{scripts → .framework/scripts}/app-install-cli.ts +0 -0
  269. /package/{scripts → .framework/scripts}/build-manifest.sh +0 -0
  270. /package/{scripts → .framework/scripts}/verify-integrity.sh +0 -0
@@ -18,7 +18,7 @@
18
18
  set -euo pipefail
19
19
 
20
20
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
21
- PROJECT_ROOT="${PROJECT_ROOT:-$(dirname "$SCRIPT_DIR")}"
21
+ PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
22
22
 
23
23
  CORE_DIR="$PROJECT_ROOT/.framework/functions"
24
24
  CUSTOM_DIR="$PROJECT_ROOT/custom"
@@ -42,23 +42,12 @@ fi
42
42
 
43
43
  # 3. Overlay custom functions (overrides + additions), excluding test files
44
44
  CUSTOM_COUNT=0
45
-
46
- # 3a. Top-level custom/functions/ (project-level overrides)
47
45
  if [ -d "$CUSTOM_DIR/functions" ]; then
46
+ # Copy all files except test files (*-test.ts, *.test.ts)
48
47
  find "$CUSTOM_DIR/functions" -maxdepth 1 -name '*.ts' ! -name '*-test.ts' ! -name '*.test.ts' -exec cp {} "$TMP_DIR"/ \; 2>/dev/null || true
48
+ # Copy subdirectories if any
49
49
  find "$CUSTOM_DIR/functions" -mindepth 1 -type d -exec sh -c 'dir="$1"; base=$(basename "$dir"); mkdir -p "'"$TMP_DIR"'/$base" && cp -r "$dir"/* "'"$TMP_DIR"'/$base/"' _ {} \; 2>/dev/null || true
50
- fi
51
-
52
- # 3b. App functions from custom/apps/*/functions/ (installed app handlers)
53
- for APP_FUNCTIONS_DIR in "$CUSTOM_DIR"/apps/*/functions; do
54
- if [ -d "$APP_FUNCTIONS_DIR" ]; then
55
- find "$APP_FUNCTIONS_DIR" -maxdepth 1 -name '*.ts' ! -name '*-test.ts' ! -name '*.test.ts' -exec cp {} "$TMP_DIR"/ \; 2>/dev/null || true
56
- find "$APP_FUNCTIONS_DIR" -mindepth 1 -type d -exec sh -c 'dir="$1"; base=$(basename "$dir"); mkdir -p "'"$TMP_DIR"'/$base" && cp -r "$dir"/* "'"$TMP_DIR"'/$base/"' _ {} \; 2>/dev/null || true
57
- fi
58
- done
59
-
60
- CUSTOM_COUNT=$(find "$CUSTOM_DIR" -path '*/functions/*.ts' ! -name '*-test.ts' ! -name '*.test.ts' 2>/dev/null | wc -l | tr -d ' ')
61
- if [ "$CUSTOM_COUNT" -gt 0 ]; then
50
+ CUSTOM_COUNT=$(find "$CUSTOM_DIR/functions" -name '*.ts' ! -name '*-test.ts' ! -name '*.test.ts' 2>/dev/null | wc -l | tr -d ' ')
62
51
  echo " ✓ Custom: $CUSTOM_COUNT files"
63
52
  else
64
53
  echo " ○ Custom: (empty)"
@@ -69,37 +58,5 @@ rm -rf "$TARGET_DIR"
69
58
  mkdir -p "$(dirname "$TARGET_DIR")"
70
59
  mv "$TMP_DIR" "$TARGET_DIR"
71
60
 
72
- # 5. Generate handler-registry.ts — static imports of all custom_* handlers
73
- # This replaces the stub in handler-registry.ts so esbuild can bundle all
74
- # handlers into integration-routes at build time (no runtime dynamic imports).
75
- REGISTRY_FILE="$TARGET_DIR/handler-registry.ts"
76
- {
77
- echo "// AUTO-GENERATED by assemble-functions.sh — do not edit manually"
78
- echo "// Overrides the stub in .framework/functions/handler-registry.ts"
79
- echo ""
80
-
81
- # Collect all custom_*.ts handler files
82
- HANDLER_NAMES=()
83
- for f in "$TARGET_DIR"/custom_*.ts; do
84
- [ -f "$f" ] || continue
85
- name=$(basename "$f" .ts)
86
- HANDLER_NAMES+=("$name")
87
- var=$(echo "$name" | tr '-' '_')
88
- echo "import * as ${var} from './${name}'"
89
- done
90
-
91
- echo ""
92
- echo "export const HANDLER_REGISTRY: Record<string, any> = {"
93
-
94
- for name in "${HANDLER_NAMES[@]}"; do
95
- var=$(echo "$name" | tr '-' '_')
96
- stripped="${name#custom_}"
97
- echo " '${name}': ${var},"
98
- echo " '${stripped}': ${var},"
99
- done
100
-
101
- echo "}"
102
- } > "$REGISTRY_FILE"
103
-
104
61
  echo " ✓ Assembled: $(find "$TARGET_DIR" -name '*.ts' ! -name '*-test.ts' ! -name '*.test.ts' | wc -l | tr -d ' ') total functions"
105
62
  echo "✅ Done"
@@ -19,12 +19,6 @@ set -euo pipefail
19
19
  SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
20
20
  PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
21
21
 
22
- # Detect if running inside node_modules (consumer project install)
23
- # If so, output to actual project root (3 levels up from scripts/)
24
- if [[ "$SCRIPT_DIR" == *"/node_modules/spine-framework/"* ]]; then
25
- PROJECT_ROOT="$(dirname "$(dirname "$(dirname "$SCRIPT_DIR")")")"
26
- fi
27
-
28
22
  echo "Assembling Spine..."
29
23
 
30
24
  # Remove stale dist/ so Netlify CLI never reads its _redirects during dev
@@ -32,10 +26,10 @@ rm -rf "$PROJECT_ROOT/dist"
32
26
 
33
27
  # Step 1: Assemble functions
34
28
  echo "Assembling functions..."
35
- PROJECT_ROOT="$PROJECT_ROOT" bash "$SCRIPT_DIR/assemble-functions.sh"
29
+ bash "$SCRIPT_DIR/assemble-functions.sh"
36
30
 
37
31
  # Step 2: Assemble frontend
38
32
  echo "Assembling frontend..."
39
- PROJECT_ROOT="$PROJECT_ROOT" bash "$SCRIPT_DIR/assemble-frontend.sh"
33
+ bash "$SCRIPT_DIR/assemble-frontend.sh"
40
34
 
41
35
  echo "Spine assembly complete"
@@ -28,12 +28,8 @@ fi
28
28
  echo ""
29
29
 
30
30
  # Check 2: Core importing custom_ prefixed modules
31
- # signal.ts is excluded: it uses a guarded dynamic import to optionally load a custom handler at runtime.
32
- # handler-registry.ts is excluded: it's a core stub that gets generated at assembly time.
33
31
  echo "2. Checking for custom_ module imports in core..."
34
- if grep -r "from.*custom_\|import.*custom_" .framework/ --include="*.ts" --include="*.tsx" 2>/dev/null \
35
- | grep -v "signal\.ts:" \
36
- | grep -v "handler-registry\.ts:"; then
32
+ if grep -r "from.*custom_\|import.*custom_" .framework/ --include="*.ts" --include="*.tsx" 2>/dev/null; then
37
33
  echo " ❌ FAIL: Core files import custom_ modules"
38
34
  VIOLATIONS=$((VIOLATIONS + 1))
39
35
  else
@@ -76,13 +72,13 @@ else
76
72
  fi
77
73
  echo ""
78
74
 
79
- # Check 5: Verify webhook registry pattern is used (dynamic lookup + static HANDLER_REGISTRY)
80
- echo "5. Checking integration-routes uses registry pattern..."
75
+ # Check 5: Verify webhook registry is used (not static imports)
76
+ echo "5. Checking integration-routes uses dynamic registry..."
81
77
  if grep -q "webhookHandlers\|custom_webhook-handlers" .framework/functions/integration-routes.ts 2>/dev/null; then
82
- echo " ❌ FAIL: integration-routes uses old static imports"
78
+ echo " ❌ FAIL: integration-routes still uses static imports"
83
79
  VIOLATIONS=$((VIOLATIONS + 1))
84
80
  else
85
- echo " ✅ PASS: integration-routes uses registry pattern"
81
+ echo " ✅ PASS: integration-routes uses dynamic registry"
86
82
  fi
87
83
  echo ""
88
84
 
@@ -0,0 +1,9 @@
1
+ {
2
+ "slug": "account_cli_instances",
3
+ "source_kind": "account",
4
+ "target_kind": "item",
5
+ "target_type_slug": "spine_instance",
6
+ "name": "Account CLI Instances",
7
+ "description": "Links accounts to their CLI installations",
8
+ "is_active": true
9
+ }
@@ -0,0 +1,98 @@
1
+ {
2
+ "slug": "funnel_signal_use",
3
+ "kind": "item",
4
+ "name": "Usage Signal",
5
+ "description": "Tracks CLI and app usage signals from npm installations",
6
+ "design_schema": {
7
+ "fields": {
8
+ "title": {
9
+ "data_type": "text",
10
+ "label": "Title",
11
+ "required": true,
12
+ "system": true
13
+ },
14
+ "source": {
15
+ "data_type": "select",
16
+ "label": "Source",
17
+ "required": true,
18
+ "options": ["use"]
19
+ },
20
+ "stage": {
21
+ "data_type": "select",
22
+ "label": "Stage",
23
+ "required": true,
24
+ "options": ["installed", "claimed", "active"]
25
+ },
26
+ "action_type": {
27
+ "data_type": "text",
28
+ "label": "Action Type",
29
+ "required": true
30
+ },
31
+ "action_value": {
32
+ "data_type": "number",
33
+ "label": "Action Value",
34
+ "required": true
35
+ },
36
+ "serial": {
37
+ "data_type": "text",
38
+ "label": "Install Serial",
39
+ "required": true
40
+ },
41
+ "app_slug": {
42
+ "data_type": "select",
43
+ "label": "App",
44
+ "required": false,
45
+ "options": ["framework", "cortex", "portal"]
46
+ },
47
+ "app_version": {
48
+ "data_type": "text",
49
+ "label": "App Version",
50
+ "required": false
51
+ }
52
+ },
53
+ "views": {
54
+ "default_list": {
55
+ "type": "list",
56
+ "display": "table",
57
+ "label": "Usage Signals",
58
+ "fields": {
59
+ "title": { "sortable": true, "display_type": "text" },
60
+ "action_type": { "sortable": true, "display_type": "badge" },
61
+ "stage": { "sortable": true, "display_type": "badge" },
62
+ "serial": { "sortable": true, "display_type": "text" },
63
+ "created_at": { "sortable": true, "display_type": "timestamp" }
64
+ }
65
+ },
66
+ "default_detail": {
67
+ "type": "detail",
68
+ "label": "Signal Detail",
69
+ "sections": [
70
+ {
71
+ "title": "Signal",
72
+ "fields": {
73
+ "action_type": { "display_type": "input" },
74
+ "action_value": { "display_type": "input" },
75
+ "stage": { "display_type": "select" }
76
+ }
77
+ },
78
+ {
79
+ "title": "Instance",
80
+ "fields": {
81
+ "serial": { "display_type": "input" },
82
+ "app_slug": { "display_type": "select" },
83
+ "app_version": { "display_type": "input" }
84
+ }
85
+ }
86
+ ]
87
+ }
88
+ },
89
+ "record_permissions": {
90
+ "system-admin": ["create", "read", "update", "delete"],
91
+ "support": ["create", "read", "update"],
92
+ "member": ["create", "read"]
93
+ }
94
+ },
95
+ "validation_schema": {},
96
+ "ownership": "pack",
97
+ "is_active": true
98
+ }
@@ -0,0 +1,109 @@
1
+ {
2
+ "slug": "spine_instance",
3
+ "kind": "item",
4
+ "name": "CLI Instance",
5
+ "description": "Tracks npm package installations per device",
6
+ "design_schema": {
7
+ "fields": {
8
+ "title": {
9
+ "data_type": "text",
10
+ "label": "Title",
11
+ "required": true,
12
+ "system": true
13
+ },
14
+ "serial": {
15
+ "data_type": "text",
16
+ "label": "Install Serial",
17
+ "required": true,
18
+ "validation": {
19
+ "pattern": "^sf_inst_[a-z0-9-]+$"
20
+ }
21
+ },
22
+ "app_slug": {
23
+ "data_type": "select",
24
+ "label": "App",
25
+ "required": true,
26
+ "options": ["framework", "cortex", "portal"]
27
+ },
28
+ "version": {
29
+ "data_type": "text",
30
+ "label": "Version",
31
+ "required": true
32
+ },
33
+ "claimed_by_person_id": {
34
+ "data_type": "reference",
35
+ "label": "Claimed By",
36
+ "required": false,
37
+ "validation": {
38
+ "reference_kind": "person"
39
+ }
40
+ },
41
+ "claimed_at": {
42
+ "data_type": "datetime",
43
+ "label": "Claimed At",
44
+ "required": false
45
+ },
46
+ "first_seen_at": {
47
+ "data_type": "datetime",
48
+ "label": "First Seen",
49
+ "required": true
50
+ },
51
+ "last_signal_at": {
52
+ "data_type": "datetime",
53
+ "label": "Last Signal",
54
+ "required": false
55
+ }
56
+ },
57
+ "views": {
58
+ "default_list": {
59
+ "type": "list",
60
+ "display": "table",
61
+ "label": "CLI Instances",
62
+ "fields": {
63
+ "title": { "sortable": true, "display_type": "text" },
64
+ "app_slug": { "sortable": true, "display_type": "badge" },
65
+ "version": { "sortable": true, "display_type": "text" },
66
+ "claimed_at": { "sortable": true, "display_type": "timestamp" },
67
+ "last_signal_at": { "sortable": true, "display_type": "timestamp" }
68
+ },
69
+ "default_sort": { "field": "created_at", "direction": "desc" }
70
+ },
71
+ "default_detail": {
72
+ "type": "detail",
73
+ "label": "Instance Detail",
74
+ "sections": [
75
+ {
76
+ "title": "Instance",
77
+ "fields": {
78
+ "serial": { "display_type": "input" },
79
+ "app_slug": { "display_type": "select" },
80
+ "version": { "display_type": "input" }
81
+ }
82
+ },
83
+ {
84
+ "title": "Claim",
85
+ "fields": {
86
+ "claimed_by_person_id": { "display_type": "reference_picker" },
87
+ "claimed_at": { "display_type": "timestamp" }
88
+ }
89
+ },
90
+ {
91
+ "title": "Activity",
92
+ "fields": {
93
+ "first_seen_at": { "display_type": "timestamp" },
94
+ "last_signal_at": { "display_type": "timestamp" }
95
+ }
96
+ }
97
+ ]
98
+ }
99
+ },
100
+ "record_permissions": {
101
+ "system-admin": ["create", "read", "update", "delete"],
102
+ "support": ["create", "read", "update"],
103
+ "member": ["create", "read", "update"]
104
+ }
105
+ },
106
+ "validation_schema": {},
107
+ "ownership": "pack",
108
+ "is_active": true
109
+ }
@@ -3,12 +3,11 @@ import { Routes, Route, Navigate } from 'react-router-dom'
3
3
  import { useAuth } from './contexts/AuthContext'
4
4
  import { LoadingSpinner } from './components/ui/LoadingSpinner'
5
5
  import { LoginPage } from './pages/auth/LoginPage'
6
- import { RegisterPage } from './pages/auth/RegisterPage'
7
6
  import { NotFoundPage } from './pages/NotFoundPage'
8
7
  import { DashboardPage } from './pages/DashboardPage'
9
8
  import { AppWrapper } from './components/AppWrapper'
10
9
  import { AppsRegistryProvider, useAppsRegistry } from './contexts/AppContext'
11
- import { CustomAppLoader, getInstalledAppSlugs } from './components/CustomAppLoader'
10
+ import { CustomAppLoader } from './components/CustomAppLoader'
12
11
  import { GenericAppShell } from './components/app-shell/GenericAppShell'
13
12
  import { APIPage } from './pages/spine-framework/APIPage'
14
13
  import { CLIPage } from './pages/spine-framework/CLIPage'
@@ -34,7 +33,6 @@ function App() {
34
33
  {!user ? (
35
34
  <Routes>
36
35
  <Route path="/login" element={<LoginPage />} />
37
- <Route path="/register" element={<RegisterPage />} />
38
36
  <Route path="*" element={<Navigate to="/login" replace />} />
39
37
  </Routes>
40
38
  ) : (
@@ -58,31 +56,26 @@ function AuthenticatedRouter() {
58
56
  )
59
57
  }
60
58
 
61
- // Filter to apps that are physically present in this build (custom renderer only —
62
- // generic apps have no module to load so they're always allowed through).
63
- const installedSlugs = getInstalledAppSlugs()
64
-
65
59
  // Sort: explicit prefixes first, root (/) last
66
60
  const sorted = [...apps]
67
61
  .filter(app => app.slug !== 'spine-framework' && !app.route_prefix?.startsWith('/spine-framework'))
68
- .filter(app => app.renderer !== 'custom' || installedSlugs.has(app.slug))
69
62
  .sort((a, b) => {
70
63
  if (a.route_prefix === '/') return 1
71
64
  if (b.route_prefix === '/') return -1
72
65
  return (b.route_prefix?.length || 0) - (a.route_prefix?.length || 0)
73
66
  })
74
67
 
75
- // When an app is mounted at root it owns all routes — suppress the
76
- // framework's own /dashboard and catch-all 404 to avoid conflicts.
77
- const hasRootApp = sorted.some(app => app.route_prefix === '/')
68
+ // Determine default redirect: first app with a route_prefix, or fall back to dashboard
69
+ const defaultApp = sorted.find(app => app.route_prefix && app.route_prefix !== '/')
70
+ const defaultRedirect = defaultApp?.route_prefix || '/dashboard'
78
71
 
79
72
  return (
80
73
  <Suspense fallback={<div className="min-h-screen flex items-center justify-center"><LoadingSpinner /></div>}>
81
74
  <Routes>
82
- {/* Default redirect — suppressed when a root app is installed */}
83
- {!hasRootApp && <Route path="/" element={<Navigate to="/dashboard" replace />} />}
84
- {!hasRootApp && <Route path="/dashboard" element={<DashboardPage />} />}
85
-
75
+ {/* Default redirect to first available app, or dashboard if no apps */}
76
+ <Route path="/" element={<Navigate to={defaultRedirect} replace />} />
77
+ <Route path="/dashboard" element={<DashboardPage />} />
78
+
86
79
  {/* Login route for authenticated users (redirects to qualified app) */}
87
80
  <Route path="/login" element={<LoginPage />} />
88
81
 
@@ -94,14 +87,12 @@ function AuthenticatedRouter() {
94
87
  {/* Dynamic app routes */}
95
88
  {sorted.map(app => {
96
89
  const prefix = app.route_prefix!
97
- // React Router v6: path="/*" does NOT work for root — must use path="*"
98
- const routePath = prefix === '/' ? '*' : `${prefix}/*`
99
90
 
100
91
  if (app.renderer === 'custom') {
101
92
  return (
102
93
  <Route
103
94
  key={app.slug}
104
- path={routePath}
95
+ path={`${prefix}/*`}
105
96
  element={
106
97
  <AppWrapper app={app}>
107
98
  <CustomAppLoader slug={app.slug} />
@@ -115,7 +106,7 @@ function AuthenticatedRouter() {
115
106
  return (
116
107
  <Route
117
108
  key={app.slug}
118
- path={routePath}
109
+ path={`${prefix}/*`}
119
110
  element={
120
111
  <AppWrapper app={app}>
121
112
  <GenericAppShell app={app} />
@@ -128,8 +119,7 @@ function AuthenticatedRouter() {
128
119
  return null
129
120
  })}
130
121
 
131
- {/* 404 — suppressed when a root app is installed (it handles its own not-found) */}
132
- {!hasRootApp && <Route path="*" element={<NotFoundPage />} />}
122
+ <Route path="*" element={<NotFoundPage />} />
133
123
  </Routes>
134
124
  </Suspense>
135
125
  )
@@ -57,33 +57,16 @@ class AppErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState>
57
57
  // Static glob maps — Vite analyzes these at build time and builds a complete
58
58
  // module map. Runtime lookup is just a map key lookup, no dynamic string eval.
59
59
  // Custom apps take precedence over core apps with the same slug.
60
- const customAppModules = import.meta.glob('../../custom/apps/*/index.tsx')
60
+ const customAppModules = import.meta.glob('../../../custom/apps/*/index.tsx')
61
61
  const coreAppModules = import.meta.glob('../apps/*/index.tsx')
62
62
 
63
- // Extract app slug from glob key path (e.g., '.../apps/xyz/index.tsx' → 'xyz')
64
- function slugFromKey(key: string): string {
65
- return key.split('/').slice(-2)[0]
66
- }
67
-
68
- /**
69
- * Returns the set of app slugs that are physically present in this build.
70
- * Used by App.tsx to filter DB app records down to only what's actually installed,
71
- * preventing route registration for apps that exist in the DB but not this deployment.
72
- */
73
- export function getInstalledAppSlugs(): Set<string> {
74
- const slugs = new Set<string>()
75
- Object.keys(customAppModules).forEach(k => slugs.add(slugFromKey(k)))
76
- Object.keys(coreAppModules).forEach(k => slugs.add(slugFromKey(k)))
77
- return slugs
78
- }
79
-
80
63
  // Module-level cache for lazy components to avoid re-creating on each render
81
64
  const appModuleCache = new Map<string, React.LazyExoticComponent<React.ComponentType>>()
82
65
 
83
66
  // Resolve the glob key for a given slug from the custom or core map.
84
67
  function resolveAppLoader(slug: string): (() => Promise<{ default: React.ComponentType }>) | null {
85
68
  // Check custom first (custom/apps/{slug}/index.tsx)
86
- const customKey = `../../custom/apps/${slug}/index.tsx`
69
+ const customKey = `../../../custom/apps/${slug}/index.tsx`
87
70
  if (customAppModules[customKey]) {
88
71
  return customAppModules[customKey] as () => Promise<{ default: React.ComponentType }>
89
72
  }
@@ -1,5 +1,5 @@
1
1
  import * as React from "react"
2
- import * as AccordionPrimitive from "@radix-ui/react-accordion"
2
+ import { Accordion as AccordionPrimitive } from "radix-ui"
3
3
 
4
4
  import { cn } from "@/lib/utils"
5
5
  import { ChevronDownIcon, ChevronUpIcon } from "lucide-react"
@@ -1,5 +1,5 @@
1
1
  import * as React from "react"
2
- import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"
2
+ import { AlertDialog as AlertDialogPrimitive } from "radix-ui"
3
3
 
4
4
  import { cn } from "@/lib/utils"
5
5
  import { Button } from "@/components/ui/button"
@@ -1,6 +1,6 @@
1
1
  "use client"
2
2
 
3
- import * as AspectRatioPrimitive from "@radix-ui/react-aspect-ratio"
3
+ import { AspectRatio as AspectRatioPrimitive } from "radix-ui"
4
4
 
5
5
  function AspectRatio({
6
6
  ...props
@@ -1,5 +1,5 @@
1
1
  import * as React from "react"
2
- import * as AvatarPrimitive from "@radix-ui/react-avatar"
2
+ import { Avatar as AvatarPrimitive } from "radix-ui"
3
3
 
4
4
  import { cn } from "@/lib/utils"
5
5
 
@@ -1,6 +1,6 @@
1
1
  import * as React from "react"
2
2
  import { cva, type VariantProps } from "class-variance-authority"
3
- import { Slot } from "@radix-ui/react-slot"
3
+ import { Slot } from "radix-ui"
4
4
 
5
5
  import { cn } from "@/lib/utils"
6
6
 
@@ -34,7 +34,7 @@ function Badge({
34
34
  ...props
35
35
  }: React.ComponentProps<"span"> &
36
36
  VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
37
- const Comp = asChild ? Slot : "span"
37
+ const Comp = asChild ? Slot.Root : "span"
38
38
 
39
39
  return (
40
40
  <Comp
@@ -1,5 +1,5 @@
1
1
  import * as React from "react"
2
- import { Slot } from "@radix-ui/react-slot"
2
+ import { Slot } from "radix-ui"
3
3
 
4
4
  import { cn } from "@/lib/utils"
5
5
  import { ChevronRightIcon, MoreHorizontalIcon } from "lucide-react"
@@ -45,7 +45,7 @@ function BreadcrumbLink({
45
45
  }: React.ComponentProps<"a"> & {
46
46
  asChild?: boolean
47
47
  }) {
48
- const Comp = asChild ? Slot : "a"
48
+ const Comp = asChild ? Slot.Root : "a"
49
49
 
50
50
  return (
51
51
  <Comp
@@ -1,5 +1,5 @@
1
1
  import { cva, type VariantProps } from "class-variance-authority"
2
- import { Slot } from "@radix-ui/react-slot"
2
+ import { Slot } from "radix-ui"
3
3
 
4
4
  import { cn } from "@/lib/utils"
5
5
  import { Separator } from "@/components/ui/separator"
@@ -44,7 +44,7 @@ function ButtonGroupText({
44
44
  }: React.ComponentProps<"div"> & {
45
45
  asChild?: boolean
46
46
  }) {
47
- const Comp = asChild ? Slot : "div"
47
+ const Comp = asChild ? Slot.Root : "div"
48
48
 
49
49
  return (
50
50
  <Comp
@@ -1,6 +1,6 @@
1
1
  import * as React from "react"
2
2
  import { cva, type VariantProps } from "class-variance-authority"
3
- import { Slot } from "@radix-ui/react-slot"
3
+ import { Slot } from "radix-ui"
4
4
 
5
5
  import { cn } from "@/lib/utils"
6
6
 
@@ -49,7 +49,7 @@ function Button({
49
49
  VariantProps<typeof buttonVariants> & {
50
50
  asChild?: boolean
51
51
  }) {
52
- const Comp = asChild ? Slot : "button"
52
+ const Comp = asChild ? Slot.Root : "button"
53
53
 
54
54
  return (
55
55
  <Comp
@@ -2,6 +2,7 @@
2
2
 
3
3
  import * as React from "react"
4
4
  import * as RechartsPrimitive from "recharts"
5
+ import type { TooltipValueType } from "recharts"
5
6
 
6
7
  import { cn } from "@/lib/utils"
7
8
 
@@ -9,6 +10,7 @@ import { cn } from "@/lib/utils"
9
10
  const THEMES = { light: "", dark: ".dark" } as const
10
11
 
11
12
  const INITIAL_DIMENSION = { width: 320, height: 200 } as const
13
+ type TooltipNameType = number | string
12
14
 
13
15
  export type ChartConfig = Record<
14
16
  string,
@@ -136,7 +138,10 @@ function ChartTooltipContent({
136
138
  nameKey?: string
137
139
  labelKey?: string
138
140
  } & Omit<
139
- RechartsPrimitive.TooltipContentProps,
141
+ RechartsPrimitive.DefaultTooltipContentProps<
142
+ TooltipValueType,
143
+ TooltipNameType
144
+ >,
140
145
  "accessibilityLayer"
141
146
  >) {
142
147
  const { config } = useChart()
@@ -1,5 +1,5 @@
1
1
  import * as React from "react"
2
- import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
2
+ import { Checkbox as CheckboxPrimitive } from "radix-ui"
3
3
 
4
4
  import { cn } from "@/lib/utils"
5
5
  import { CheckIcon } from "lucide-react"
@@ -1,6 +1,6 @@
1
1
  "use client"
2
2
 
3
- import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
3
+ import { Collapsible as CollapsiblePrimitive } from "radix-ui"
4
4
 
5
5
  function Collapsible({
6
6
  ...props
@@ -1,5 +1,5 @@
1
1
  import * as React from "react"
2
- import * as ContextMenuPrimitive from "@radix-ui/react-context-menu"
2
+ import { ContextMenu as ContextMenuPrimitive } from "radix-ui"
3
3
 
4
4
  import { cn } from "@/lib/utils"
5
5
  import { ChevronRightIcon, CheckIcon } from "lucide-react"
@@ -1,7 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from "react"
4
- import * as DialogPrimitive from "@radix-ui/react-dialog"
4
+ import { Dialog as DialogPrimitive } from "radix-ui"
5
5
 
6
6
  import { cn } from "@/lib/utils"
7
7
  import { Button } from "@/components/ui/button"