spine-framework 0.4.4 → 0.5.0-rc.4

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 (283) hide show
  1. package/.env.example +13 -3
  2. package/.framework/cli/commands/bootstrap.ts +392 -0
  3. package/.framework/cli/commands/dev.ts +91 -218
  4. package/.framework/cli/commands/doctor.ts +132 -26
  5. package/.framework/cli/commands/generate.ts +38 -298
  6. package/.framework/cli/commands/init.ts +20 -1
  7. package/.framework/cli/commands/migrate.ts +36 -30
  8. package/.framework/cli/commands/migrations.ts +16 -56
  9. package/.framework/cli/commands/upgrade.ts +35 -0
  10. package/.framework/cli/commands/validate-schema.ts +147 -0
  11. package/.framework/cli/context.ts +223 -110
  12. package/.framework/cli/index.ts +6 -0
  13. package/.framework/cli/lib/project-files.ts +241 -1
  14. package/.framework/functions/_shared/hash-api-key.ts +183 -79
  15. package/.framework/functions/_shared/logging.ts +562 -224
  16. package/.framework/functions/_shared/middleware.ts +47 -44
  17. package/.framework/functions/admin-data.ts +39 -28
  18. package/.framework/functions/ai-agents.ts +10 -6
  19. package/.framework/functions/api-keys.ts +301 -122
  20. package/.framework/functions/apps.ts +43 -26
  21. package/.framework/functions/cil-ingest.ts +48 -15
  22. package/.framework/functions/debug-auth.ts +14 -8
  23. package/.framework/functions/deliveries.ts +39 -12
  24. package/.framework/functions/embeddings.ts +145 -76
  25. package/.framework/functions/integration-outbound.ts +67 -27
  26. package/.framework/functions/integrations.ts +254 -127
  27. package/.framework/functions/logs.ts +273 -133
  28. package/.framework/functions/observability.ts +277 -147
  29. package/.framework/functions/pipeline-executions.ts +1 -1
  30. package/.framework/functions/pipelines.ts +14 -9
  31. package/.framework/functions/prompt-configs.ts +7 -4
  32. package/.framework/functions/roles.ts +8 -5
  33. package/.framework/functions/security.ts +30 -17
  34. package/.framework/functions/system-cron.ts +240 -127
  35. package/.framework/functions/tests.ts +7 -6
  36. package/.framework/functions/timers.ts +310 -107
  37. package/.framework/functions/triggers.ts +28 -13
  38. package/.framework/functions/types.ts +13 -10
  39. package/.framework/migrations/069_log_stats_window.sql +54 -0
  40. package/.framework/migrations/070_app_type_schema_rpcs.sql +166 -0
  41. package/.framework/migrations/071_timer_interval_keys.sql +96 -0
  42. package/.framework/migrations/072_slug_autofill.sql +77 -0
  43. package/.framework/migrations/073_seed_member_roles.sql +26 -0
  44. package/.framework/src/apps/admin/index.tsx +1141 -775
  45. package/.framework/src/components/ErrorBoundary.tsx +136 -0
  46. package/.framework/src/components/admin/AdminListPage.tsx +81 -73
  47. package/.framework/src/components/admin/AdminSidebar.tsx +88 -79
  48. package/.framework/src/components/admin/EntitySelect.tsx +181 -0
  49. package/.framework/src/components/admin/PageInstructions.tsx +86 -127
  50. package/.framework/src/components/app-shell/GenericDetailPage.tsx +37 -13
  51. package/.framework/src/components/app-shell/GenericListPage.tsx +28 -32
  52. package/.framework/src/components/layout/Sidebar.tsx +300 -177
  53. package/.framework/src/components/runtime/DataDetailPage.tsx +67 -35
  54. package/.framework/src/components/runtime/DataHeader.tsx +96 -48
  55. package/.framework/src/components/runtime/DataListPage.tsx +3 -26
  56. package/.framework/src/components/runtime/DataStats.tsx +10 -10
  57. package/.framework/src/components/runtime/DataTable.tsx +12 -10
  58. package/.framework/src/components/ui/sheet.tsx +24 -26
  59. package/.framework/src/components/ui/textarea.tsx +74 -48
  60. package/.framework/src/hooks/useEntityList.ts +12 -9
  61. package/.framework/src/hooks/useListSchema.ts +108 -58
  62. package/.framework/src/instructions/README.md +57 -0
  63. package/.framework/src/instructions/ai-agents.md +69 -0
  64. package/.framework/src/instructions/alerts.md +80 -0
  65. package/.framework/src/instructions/api-keys.md +87 -0
  66. package/.framework/src/instructions/apps.md +77 -0
  67. package/.framework/src/instructions/concepts/ai-and-prompts.md +150 -0
  68. package/.framework/src/instructions/concepts/apps-and-renderers.md +162 -0
  69. package/.framework/src/instructions/concepts/auth-and-api-keys.md +133 -0
  70. package/.framework/src/instructions/concepts/automation.md +186 -0
  71. package/.framework/src/instructions/concepts/concurrency-and-idempotency.md +125 -0
  72. package/.framework/src/instructions/concepts/core-vs-custom.md +124 -0
  73. package/.framework/src/instructions/concepts/design-schema.md +152 -0
  74. package/.framework/src/instructions/concepts/integrations-and-webhooks.md +127 -0
  75. package/.framework/src/instructions/concepts/observability.md +116 -0
  76. package/.framework/src/instructions/concepts/permissions.md +150 -0
  77. package/.framework/src/instructions/concepts/runtime-records.md +111 -0
  78. package/.framework/src/instructions/concepts/scope-and-accounts.md +112 -0
  79. package/.framework/src/instructions/concepts/spine-way.md +172 -0
  80. package/.framework/src/instructions/deliveries.md +59 -0
  81. package/.framework/src/instructions/guide/00-orientation.md +106 -0
  82. package/.framework/src/instructions/guide/01-install-and-first-run.md +253 -0
  83. package/.framework/src/instructions/guide/02-project-map.md +147 -0
  84. package/.framework/src/instructions/guide/03-domain-model.md +223 -0
  85. package/.framework/src/instructions/guide/04-first-app.md +227 -0
  86. package/.framework/src/instructions/guide/05-glossary.md +183 -0
  87. package/.framework/src/instructions/integrations.md +96 -0
  88. package/.framework/src/instructions/internal/cil-markers.md +83 -0
  89. package/.framework/src/instructions/invites.md +60 -0
  90. package/.framework/src/instructions/kb.md +80 -0
  91. package/.framework/src/instructions/logs.md +77 -0
  92. package/.framework/src/instructions/observability.md +61 -0
  93. package/.framework/src/instructions/operations/deployment.md +115 -0
  94. package/.framework/src/instructions/operations/migrations.md +125 -0
  95. package/.framework/src/instructions/operations/security-checklist.md +148 -0
  96. package/.framework/src/instructions/operations/troubleshooting.md +170 -0
  97. package/.framework/src/instructions/operations/upgrade.md +116 -0
  98. package/.framework/src/instructions/pipeline-executions.md +62 -0
  99. package/.framework/src/instructions/pipelines.md +78 -0
  100. package/.framework/src/instructions/prompts.md +95 -0
  101. package/.framework/src/instructions/reference/api/admin-data.md +162 -0
  102. package/.framework/src/instructions/reference/api/auth.md +113 -0
  103. package/.framework/src/instructions/reference/api/errors-and-envelopes.md +113 -0
  104. package/.framework/src/instructions/reference/app-manifest.md +150 -0
  105. package/.framework/src/instructions/reference/cli.md +124 -0
  106. package/.framework/src/instructions/reference/database.md +132 -0
  107. package/.framework/src/instructions/reference/design-schema.md +280 -0
  108. package/.framework/src/instructions/reference/env-vars.md +133 -0
  109. package/.framework/src/instructions/reference/functions/account-nodes.md +75 -0
  110. package/.framework/src/instructions/reference/functions/admin-data.md +195 -0
  111. package/.framework/src/instructions/reference/functions/admin-funnel.md +90 -0
  112. package/.framework/src/instructions/reference/functions/admin-install-funnel.md +107 -0
  113. package/.framework/src/instructions/reference/functions/admin-signals.md +102 -0
  114. package/.framework/src/instructions/reference/functions/ai-agents.md +148 -0
  115. package/.framework/src/instructions/reference/functions/ai-interactions.md +156 -0
  116. package/.framework/src/instructions/reference/functions/api-keys.md +130 -0
  117. package/.framework/src/instructions/reference/functions/apps.md +140 -0
  118. package/.framework/src/instructions/reference/functions/auth.md +99 -0
  119. package/.framework/src/instructions/reference/functions/debug-auth.md +91 -0
  120. package/.framework/src/instructions/reference/functions/deliveries.md +110 -0
  121. package/.framework/src/instructions/reference/functions/embeddings.md +166 -0
  122. package/.framework/src/instructions/reference/functions/eval-harness.md +149 -0
  123. package/.framework/src/instructions/reference/functions/index.md +103 -0
  124. package/.framework/src/instructions/reference/functions/integration-outbound.md +200 -0
  125. package/.framework/src/instructions/reference/functions/integration-routes.md +151 -0
  126. package/.framework/src/instructions/reference/functions/integrations.md +130 -0
  127. package/.framework/src/instructions/reference/functions/invites.md +182 -0
  128. package/.framework/src/instructions/reference/functions/item-progress.md +107 -0
  129. package/.framework/src/instructions/reference/functions/kb.md +166 -0
  130. package/.framework/src/instructions/reference/functions/logs.md +141 -0
  131. package/.framework/src/instructions/reference/functions/observability.md +105 -0
  132. package/.framework/src/instructions/reference/functions/pipeline-executions.md +132 -0
  133. package/.framework/src/instructions/reference/functions/pipeline-runner-background.md +121 -0
  134. package/.framework/src/instructions/reference/functions/pipelines.md +136 -0
  135. package/.framework/src/instructions/reference/functions/prompt-configs.md +121 -0
  136. package/.framework/src/instructions/reference/functions/roles.md +121 -0
  137. package/.framework/src/instructions/reference/functions/security.md +140 -0
  138. package/.framework/src/instructions/reference/functions/system-cron.md +136 -0
  139. package/.framework/src/instructions/reference/functions/system.md +106 -0
  140. package/.framework/src/instructions/reference/functions/tests.md +97 -0
  141. package/.framework/src/instructions/reference/functions/timers.md +117 -0
  142. package/.framework/src/instructions/reference/functions/trigger-scheduler.md +102 -0
  143. package/.framework/src/instructions/reference/functions/triggers.md +140 -0
  144. package/.framework/src/instructions/reference/functions/types.md +146 -0
  145. package/.framework/src/instructions/reference/seeds.md +126 -0
  146. package/.framework/src/instructions/reference/shared-modules.md +127 -0
  147. package/.framework/src/instructions/reference/spine-config.md +114 -0
  148. package/.framework/src/instructions/roles.md +80 -0
  149. package/.framework/src/instructions/runtime-detail.md +70 -0
  150. package/.framework/src/instructions/runtime-list.md +77 -0
  151. package/.framework/src/instructions/security.md +67 -0
  152. package/.framework/src/instructions/tasks/add-a-pipeline.md +110 -0
  153. package/.framework/src/instructions/tasks/add-a-role.md +96 -0
  154. package/.framework/src/instructions/tasks/add-a-timer.md +114 -0
  155. package/.framework/src/instructions/tasks/add-a-trigger.md +106 -0
  156. package/.framework/src/instructions/tasks/add-a-type.md +151 -0
  157. package/.framework/src/instructions/tasks/add-a-webhook.md +108 -0
  158. package/.framework/src/instructions/tasks/add-an-ai-agent.md +108 -0
  159. package/.framework/src/instructions/tasks/add-an-integration.md +124 -0
  160. package/.framework/src/instructions/tasks/build-a-custom-page.md +118 -0
  161. package/.framework/src/instructions/tasks/package-and-install-an-app.md +127 -0
  162. package/.framework/src/instructions/tasks/test-your-code.md +108 -0
  163. package/.framework/src/instructions/tasks/write-a-function.md +132 -0
  164. package/.framework/src/instructions/tasks/write-a-migration.md +110 -0
  165. package/.framework/src/instructions/testing.md +59 -0
  166. package/.framework/src/instructions/timers.md +82 -0
  167. package/.framework/src/instructions/triggers.md +69 -0
  168. package/.framework/src/instructions/types.md +93 -0
  169. package/.framework/src/pages/NotFoundPage.tsx +62 -31
  170. package/.framework/src/pages/admin/AIAgentDetailPage.tsx +117 -106
  171. package/.framework/src/pages/admin/AIAgentsPage.tsx +86 -48
  172. package/.framework/src/pages/admin/APIKeyDetailPage.tsx +153 -152
  173. package/.framework/src/pages/admin/APIKeysPage.tsx +91 -90
  174. package/.framework/src/pages/admin/AlertsConfigPage.tsx +29 -18
  175. package/.framework/src/pages/admin/AppDetailPage.tsx +6 -60
  176. package/.framework/src/pages/admin/AppsPage.tsx +104 -66
  177. package/.framework/src/pages/admin/DeliveriesPage.tsx +5 -5
  178. package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +5 -23
  179. package/.framework/src/pages/admin/EmbeddingsPage.tsx +5 -26
  180. package/.framework/src/pages/admin/IntegrationDetailPage.tsx +7 -7
  181. package/.framework/src/pages/admin/IntegrationsPage.tsx +85 -43
  182. package/.framework/src/pages/admin/LogsPage.tsx +144 -76
  183. package/.framework/src/pages/admin/ObservabilityDashboard.tsx +223 -140
  184. package/.framework/src/pages/admin/PipelineDetailPage.tsx +134 -113
  185. package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +108 -45
  186. package/.framework/src/pages/admin/PipelinesPage.tsx +160 -115
  187. package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +96 -98
  188. package/.framework/src/pages/admin/PromptConfigsPage.tsx +101 -59
  189. package/.framework/src/pages/admin/RoleDetailPage.tsx +90 -79
  190. package/.framework/src/pages/admin/RolesPage.tsx +86 -43
  191. package/.framework/src/pages/admin/SecurityPage.tsx +1 -1
  192. package/.framework/src/pages/admin/TestingDashboard.tsx +16 -28
  193. package/.framework/src/pages/admin/TimerDetailPage.tsx +117 -100
  194. package/.framework/src/pages/admin/TimersPage.tsx +90 -62
  195. package/.framework/src/pages/admin/TriggerDetailPage.tsx +90 -83
  196. package/.framework/src/pages/admin/TriggersPage.tsx +124 -99
  197. package/.framework/src/pages/admin/TypeDetailPage.tsx +152 -138
  198. package/.framework/src/pages/admin/TypesPage.tsx +90 -48
  199. package/.framework/src/pages/admin/cil/CILAgentPage.tsx +17 -25
  200. package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +17 -27
  201. package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +72 -40
  202. package/.framework/src/pages/admin/cil/CILFileListPage.tsx +321 -129
  203. package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +18 -29
  204. package/.framework/src/pages/admin/cil/CILGraphPage.tsx +26 -38
  205. package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +34 -46
  206. package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +189 -103
  207. package/.framework/src/pages/admin/cil/CILSearchPage.tsx +246 -136
  208. package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +11 -22
  209. package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +9 -20
  210. package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +26 -38
  211. package/.framework/src/pages/admin/kb/KBAdminPage.tsx +7 -26
  212. package/.framework/templates/agent/AGENTS.md +150 -0
  213. package/.framework/templates/agent/skills/spine-add-ai-agent/SKILL.md +58 -0
  214. package/.framework/templates/agent/skills/spine-add-automation/SKILL.md +62 -0
  215. package/.framework/templates/agent/skills/spine-add-integration/SKILL.md +63 -0
  216. package/.framework/templates/agent/skills/spine-architect/SKILL.md +86 -0
  217. package/.framework/templates/agent/skills/spine-install-app/SKILL.md +72 -0
  218. package/.framework/templates/agent/skills/spine-migration/SKILL.md +75 -0
  219. package/.framework/templates/agent/skills/spine-new-app/SKILL.md +67 -0
  220. package/.framework/templates/agent/skills/spine-new-function/SKILL.md +65 -0
  221. package/.framework/templates/agent/skills/spine-new-type/SKILL.md +65 -0
  222. package/.framework/templates/agent/skills/spine-schema/SKILL.md +77 -0
  223. package/.framework/templates/agent/skills/spine-test/SKILL.md +67 -0
  224. package/.framework/templates/agent/skills/spine-troubleshoot/SKILL.md +74 -0
  225. package/.framework/templates/agent/skills/spine-upgrade/SKILL.md +69 -0
  226. package/.framework/templates/project.json +4 -1
  227. package/.framework/tests/unit/account-scoping-gates.test.ts +392 -0
  228. package/.framework/tests/unit/agent-files.test.ts +355 -0
  229. package/.framework/tests/unit/agent-runner.test.ts +479 -44
  230. package/.framework/tests/unit/api-keys-create-scope-gate.test.ts +160 -0
  231. package/.framework/tests/unit/api-keys-omit-secret-fields.test.ts +38 -0
  232. package/.framework/tests/unit/bootstrap.test.ts +242 -0
  233. package/.framework/tests/unit/cli-context-api-key.test.ts +114 -0
  234. package/.framework/tests/unit/debug-auth.test.ts +38 -0
  235. package/.framework/tests/unit/deliveries-account-scoping.test.ts +185 -0
  236. package/.framework/tests/unit/integration-outbound-credentials.test.ts +167 -0
  237. package/.framework/tests/unit/integrations-audit-redaction.test.ts +130 -0
  238. package/.framework/tests/unit/logging-app-id.test.ts +75 -0
  239. package/.framework/tests/unit/system-context-denial.test.ts +145 -0
  240. package/.framework/tests/unit/system-cron.test.ts +240 -0
  241. package/.framework/tests/unit/timers.test.ts +159 -0
  242. package/README.md +125 -166
  243. package/config/tsconfig.cli.json +2 -2
  244. package/package.json +15 -4
  245. package/templates/project/package-lock.json +2 -2
  246. package/.framework/docs/admin-routes.md +0 -76
  247. package/.framework/docs/api-docs-progress.md +0 -38
  248. package/.framework/docs/api-governance.md +0 -146
  249. package/.framework/docs/api-testing-results.md +0 -212
  250. package/.framework/docs/assembly-launch-guide.md +0 -138
  251. package/.framework/docs/audit-results.md +0 -590
  252. package/.framework/docs/db-api-inventory.md +0 -95
  253. package/.framework/docs/gap-remediation-backlog.md +0 -103
  254. package/.framework/docs/ui-adoption-verification.md +0 -111
  255. package/.framework/docs/ui-api-coverage.md +0 -84
  256. package/.framework/docs/v2-compatibility-audit.md +0 -228
  257. package/.framework/mcp/index.ts +0 -133
  258. package/.framework/mcp/load-env.ts +0 -60
  259. package/.framework/mcp/shared/app-manifest.ts +0 -275
  260. package/.framework/mcp/shared/db.ts +0 -477
  261. package/.framework/mcp/shared/kb.ts +0 -118
  262. package/.framework/mcp/tools/architect.ts +0 -431
  263. package/.framework/mcp/tools/cil/context.ts +0 -345
  264. package/.framework/mcp/tools/cil/graph.ts +0 -242
  265. package/.framework/mcp/tools/cil/ingest.ts +0 -1217
  266. package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +0 -693
  267. package/.framework/mcp/tools/cil/pipeline.ts +0 -767
  268. package/.framework/mcp/tools/cil/project.ts +0 -791
  269. package/.framework/mcp/tools/cil/retrieval.ts +0 -336
  270. package/.framework/mcp/tools/cil/search-core.ts +0 -454
  271. package/.framework/mcp/tools/cil/search.ts +0 -97
  272. package/.framework/mcp/tools/cil/suggest.ts +0 -186
  273. package/.framework/mcp/tools/cil/validate.ts +0 -1369
  274. package/.framework/mcp/tools/kb/delete.ts +0 -139
  275. package/.framework/mcp/tools/kb/index.ts +0 -52
  276. package/.framework/mcp/tools/kb/ingest.ts +0 -84
  277. package/.framework/mcp/tools/kb/list-types.ts +0 -102
  278. package/.framework/mcp/tools/kb/publish.ts +0 -100
  279. package/.framework/mcp/tools/kb/reindex.ts +0 -86
  280. package/.framework/mcp/tools/kb/revoke.ts +0 -85
  281. package/.framework/mcp/tools/kb/search.ts +0 -101
  282. package/.framework/mcp/tools/kb/upsert.ts +0 -125
  283. package/.framework/mcp/tools/observability.ts +0 -510
@@ -11,9 +11,12 @@
11
11
  import type { Command } from 'commander'
12
12
  import { buildCliContext, handleError } from '../context.ts'
13
13
  import { adminDb } from '../../functions/_shared/index.ts'
14
- import { readFileSync, existsSync, readdirSync } from 'fs'
15
- import { resolve, dirname } from 'path'
14
+ import { collectMigrations } from './migrate.ts'
15
+ import { readFileSync, existsSync } from 'fs'
16
+ import { resolve, dirname, join } from 'path'
16
17
  import { fileURLToPath } from 'url'
18
+ import { findAgentsBlock, agentsBlockVersion } from '../lib/project-files.ts'
19
+ import { hashEntry } from '../../../scripts/checksum-manifest.mts'
17
20
 
18
21
  // CIL[DOC-VECTOR type="context" content="purpose='Provides CLI commands for the doctor (system health) functionality, integrating with CLI context and shared database functions.'; No verified external callers; imports: .framework/cli/context.ts,.framework/functions/_shared/index.ts"]
19
22
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
@@ -131,7 +134,27 @@ async function checkEnvironment(): Promise<CheckResult> {
131
134
  }
132
135
  }
133
136
 
134
-
137
+ const bad = required.filter(v => /your[-_]|placeholder|change-?me|^<[^>]*>|^xxx/i.test(process.env[v]!))
138
+ if (bad.length > 0) {
139
+ return {
140
+ name: 'environment',
141
+ status: 'fail',
142
+ message: `Placeholder values still set: ${bad.join(', ')} — replace with real Supabase credentials`,
143
+ details: { bad },
144
+ fixable: true
145
+ }
146
+ }
147
+
148
+ if (!/^https:\/\/[a-z0-9-]+\.supabase\.co/.test(process.env.SUPABASE_URL || '')) {
149
+ return {
150
+ name: 'environment',
151
+ status: 'fail',
152
+ message: 'SUPABASE_URL must look like https://<project-ref>.supabase.co',
153
+ details: {},
154
+ fixable: true
155
+ }
156
+ }
157
+
135
158
  const xenvPath = resolve(__dirname, '../../.xenv')
136
159
  const hasXenv = existsSync(xenvPath)
137
160
 
@@ -142,6 +165,7 @@ async function checkEnvironment(): Promise<CheckResult> {
142
165
  details: { has_xenv: hasXenv, vars_present: required.length }
143
166
  }
144
167
  }
168
+
145
169
  // CIL[DOC-VECTOR type="context" content="purpose='Validates required environment variables and optional .xenv file presence.'; No verified external callers; imports: .framework/cli/context.ts,.framework/functions/_shared/index.ts"]
146
170
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
147
171
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
@@ -202,15 +226,15 @@ async function checkDatabase(): Promise<CheckResult> {
202
226
  // CIL[DOC-MACRO purpose="Compares local migration files against applied database migrations."]
203
227
  // CIL[DOC-RESPONSIBILITY responsibility="Identify pending or missing database migrations."]
204
228
  // CIL[DOC-CONTEXT module="doctor" layer="app-specific" related_files=".framework/cli/commands/doctor.ts,.framework/cli/context.ts,.framework/functions/_shared/index.ts"]
205
- // CIL[DOC-CONTRACT inputs="[]" outputs="Promise<CheckResult>" errors="[]" side_effects="Reads migration directory and queries schema_migrations."]
206
- // CIL[DOC-MICRO logic_summary="List local SQL files, query applied migration versions, and report any local files not yet applied." notable_decisions="Returns warn for pending migrations and fail when the directory or query errors."]
229
+ // CIL[DOC-CONTRACT inputs="[]" outputs="Promise<CheckResult>" errors="[]" side_effects="Collects local migration files and queries _spine_migrations."]
230
+ // CIL[DOC-MICRO logic_summary="List local SQL files via collectMigrations (framework + custom), query applied filenames from _spine_migrations, and report any local files not yet applied." notable_decisions="Returns warn for pending migrations — including when the tracking table does not exist yet — and fail only on unexpected query errors."]
207
231
  // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
208
232
  // CIL[DOC-STABILITY stability="stable"]
209
233
 
210
234
  async function checkMigrations(): Promise<CheckResult> {
211
- const migrationsDir = resolve(__dirname, '../../migrations_dayzero')
235
+ const migrationFiles = collectMigrations(false)
212
236
 
213
- if (!existsSync(migrationsDir)) {
237
+ if (migrationFiles.length === 0) {
214
238
  return {
215
239
  name: 'migrations',
216
240
  status: 'fail',
@@ -219,36 +243,37 @@ async function checkMigrations(): Promise<CheckResult> {
219
243
  }
220
244
  }
221
245
 
222
- const localFiles = readdirSync(migrationsDir)
223
- .filter(f => f.endsWith('.sql'))
224
- .sort()
225
-
226
246
  try {
227
247
  const { data, error } = await adminDb
228
- .schema('public' as any)
229
- .from('schema_migrations' as any)
230
- .select('version')
248
+ .from('_spine_migrations' as any)
249
+ .select('filename')
231
250
 
232
251
  if (error) {
233
- return {
234
- name: 'migrations',
235
- status: 'fail',
236
- message: `Cannot query applied migrations: ${error.message}`,
237
- details: { error: error.message },
238
- fixable: false
252
+ // A missing tracking table means `migrate` has never run on this
253
+ // database — every file is pending, which is a warn, not a query error.
254
+ const tableMissing = error.code === '42P01' ||
255
+ /does not exist|schema cache/i.test(error.message)
256
+ if (!tableMissing) {
257
+ return {
258
+ name: 'migrations',
259
+ status: 'fail',
260
+ message: `Cannot query applied migrations: ${error.message}`,
261
+ details: { error: error.message },
262
+ fixable: false
263
+ }
239
264
  }
240
265
  }
241
266
 
242
- const applied = (data || []).map((r: any) => r.version)
267
+ const applied = (data || []).map((r: any) => r.filename)
243
268
  const appliedSet = new Set(applied)
244
- const pending = localFiles.filter(f => !appliedSet.has(f.replace('.sql', '')))
269
+ const pending = migrationFiles.filter(f => !appliedSet.has(f.name))
245
270
 
246
271
  if (pending.length > 0) {
247
272
  return {
248
273
  name: 'migrations',
249
274
  status: 'warn',
250
- message: `${pending.length} pending migrations: ${pending.join(', ')}`,
251
- details: { pending: pending.map(f => f.replace('.sql', '')), applied: applied.length },
275
+ message: `${pending.length} pending migrations: ${pending.map(f => f.name).join(', ')}`,
276
+ details: { pending: pending.map(f => f.name.replace('.sql', '')), applied: applied.length },
252
277
  fixable: true
253
278
  }
254
279
  }
@@ -335,6 +360,83 @@ async function checkIntegrity(): Promise<CheckResult> {
335
360
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
336
361
  // CIL[END stable_id="~/.framework/cli/commands/doctor.ts:checkIntegrity:function"]
337
362
 
363
+ /**
364
+ * Verify the agent assets init/upgrade install: AGENTS.md carries a
365
+ * spine-framework marker block whose version matches the manifest's
366
+ * framework_version, and every spine-* skill file listed under the
367
+ * manifest's `agent_files` map exists and hashes clean.
368
+ *
369
+ * All mismatches are WARNINGS, never failures — agent assets are
370
+ * refreshable state (`npx spine-framework upgrade` re-syncs them), and
371
+ * customer edits outside the markers / non-spine-* skills must never
372
+ * degrade health. Runs from process.cwd() (the project root).
373
+ */
374
+ async function checkAgentFiles(): Promise<CheckResult> {
375
+ const root = process.cwd()
376
+ const manifestPath = join(root, '.spine-manifest.json')
377
+
378
+ let manifest: any = null
379
+ try {
380
+ if (existsSync(manifestPath)) manifest = JSON.parse(readFileSync(manifestPath, 'utf8'))
381
+ } catch {
382
+ manifest = null
383
+ }
384
+ const agentFiles: Record<string, string> = manifest?.agent_files ?? {}
385
+ const expectedVersion: string | null = manifest?.framework_version ?? null
386
+ const problems: string[] = []
387
+
388
+ // AGENTS.md — marker block presence + version agreement.
389
+ const agentsPath = join(root, 'AGENTS.md')
390
+ if ('AGENTS.md' in agentFiles || existsSync(agentsPath)) {
391
+ if (!existsSync(agentsPath)) {
392
+ problems.push('AGENTS.md missing (manifest expects it)')
393
+ } else {
394
+ const text = readFileSync(agentsPath, 'utf8')
395
+ const range = findAgentsBlock(text.split(/\r?\n/))
396
+ if (!range) {
397
+ problems.push('AGENTS.md has no spine-framework marker block')
398
+ } else {
399
+ const blockVersion = agentsBlockVersion(text)
400
+ if (expectedVersion && blockVersion && blockVersion !== expectedVersion) {
401
+ problems.push(`AGENTS.md block is v${blockVersion}, project is v${expectedVersion}`)
402
+ }
403
+ }
404
+ }
405
+ }
406
+
407
+ // spine-* skills — existence + hash vs manifest agent_files entries.
408
+ for (const [rel, hash] of Object.entries(agentFiles)) {
409
+ if (rel === 'AGENTS.md') continue
410
+ const abs = join(root, rel)
411
+ if (!existsSync(abs)) { problems.push(`${rel} missing`); continue }
412
+ try {
413
+ if (hashEntry({ rel, abs, symlink: false }) !== hash) {
414
+ problems.push(`${rel} modified`)
415
+ }
416
+ } catch {
417
+ problems.push(`${rel} unreadable`)
418
+ }
419
+ }
420
+
421
+ if (problems.length) {
422
+ return {
423
+ name: 'agent_files',
424
+ status: 'warn',
425
+ message: `Agent asset drift: ${problems.join('; ')}`,
426
+ details: { problems },
427
+ fixable: true,
428
+ }
429
+ }
430
+ const count = Object.keys(agentFiles).length
431
+ return {
432
+ name: 'agent_files',
433
+ status: 'pass',
434
+ message: count
435
+ ? `Agent assets in sync (${count} manifest entries)`
436
+ : 'No agent assets tracked — this framework version predates agent_files',
437
+ }
438
+ }
439
+
338
440
  // CIL[BEGIN stable_id="~/.framework/cli/commands/doctor.ts:checkTestRuns:function" type="function" identity="checkTestRuns" parent="~/.framework/cli/commands/doctor.ts"]
339
441
  // CIL[DOC-MACRO purpose="Fetches the latest test run from the database."]
340
442
  // CIL[DOC-RESPONSIBILITY responsibility="Report the status of the most recent test suite execution."]
@@ -351,7 +453,7 @@ async function checkTestRuns(): Promise<CheckResult> {
351
453
  .select('suite, status, started_at')
352
454
  .order('started_at', { ascending: false })
353
455
  .limit(1)
354
- .single()
456
+ .maybeSingle()
355
457
 
356
458
  if (error) {
357
459
  return {
@@ -502,7 +604,7 @@ async function tryFix(check: CheckResult): Promise<string> {
502
604
  return 'Please set missing environment variables in .xenv or export them'
503
605
 
504
606
  case 'migrations':
505
- return 'Run `npx spine migrations apply` or use Supabase CLI to apply pending migrations'
607
+ return 'Run `npx spine-framework migrate` to apply pending migrations'
506
608
 
507
609
  case 'integrity':
508
610
  return 'Run `npm run manifest` to regenerate the integrity manifest'
@@ -513,6 +615,9 @@ async function tryFix(check: CheckResult): Promise<string> {
513
615
  case 'runtime_wiring':
514
616
  return 'Fix the dangling trigger/pipeline references listed in details (re-install the owning app or correct the type_slug / pipeline reference)'
515
617
 
618
+ case 'agent_files':
619
+ return 'Run `npx spine-framework upgrade` to re-sync AGENTS.md and .devin/skills/spine-*'
620
+
516
621
  default:
517
622
  return 'No automatic fix available'
518
623
  }
@@ -613,6 +718,7 @@ export function registerDoctorCommands(program: Command) {
613
718
  }
614
719
 
615
720
  checks.push(await checkIntegrity())
721
+ checks.push(await checkAgentFiles())
616
722
 
617
723
 
618
724
  const failed = checks.filter(c => c.status === 'fail').length
@@ -1,322 +1,62 @@
1
1
  // CIL[BEGIN stable_id="~/.framework/cli/commands/generate.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/cli/commands/generate.ts"]
2
2
  // CIL[DOC-AUDIENCE audience="internal, cli-users"]
3
- // CIL[DOC-MACRO purpose="Provide CLI commands for generating database types, handler stubs, and UI page stubs"]
4
- // CIL[DOC-RESPONSIBILITY responsibility="Import dependencies and expose module-level constants for the generate command"]
5
- // CIL[DOC-CONTEXT module=".framework/cli/commands/generate" layer="app-specific" related_files=".framework/cli/context.ts,.framework/functions/_shared/index.ts"]
6
- // CIL[DOC-CONTRACT inputs="none" outputs="module-level imports and constants" errors="none" side_effects="none"]
7
- // CIL[DOC-MICRO logic_summary="Imports Commander, CLI context helpers, adminDb, fs/path, url utilities and module constants" notable_decisions="ESM-compatible __filename and __dirname constants"]
8
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
9
- // CIL[DOC-STABILITY stable]
10
-
3
+ // CIL[DOC-MACRO purpose="Deprecated stub: the legacy 'generate' scaffold was removed; the command stays registered so callers get a clear migration message instead of writes to a dead v2-custom/ tree"]
4
+ // CIL[DOC-RESPONSIBILITY responsibility="Register the 'generate' command and fail fast with guidance"]
5
+ // CIL[DOC-CONTEXT module=".framework/cli/commands/generate" layer="app-specific" related_files=".framework/cli/commands/create-app.ts,.framework/cli/commands/validate-schema.ts"]
6
+ // CIL[DOC-CONTRACT inputs="none" outputs="registered deprecated command" errors="always exits non-zero when invoked" side_effects="prints removal notice to stderr"]
7
+ // CIL[DOC-MICRO logic_summary="Prints a removal notice pointing at create-app, the admin UI, and validate-schema, then exits with code 1" notable_decisions="Not aliased to create-app: generate created a type record + v2-custom stubs, create-app scaffolds custom/apps/<slug>/ — different semantics"]
8
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
9
+ // CIL[DOC-STABILITY deprecated]
11
10
 
12
11
  import type { Command } from 'commander'
13
- import { buildCliContext, handleError } from '../context.ts'
14
- import { adminDb } from '../../functions/_shared/index.ts'
15
- import { existsSync, mkdirSync, writeFileSync } from 'fs'
16
- import { resolve, dirname } from 'path'
17
- import { fileURLToPath } from 'url'
18
-
19
- // CIL[DOC-VECTOR type="context" content="purpose='Provide CLI commands for generating database types, handler stubs, and UI page stubs'; No verified external callers; imports: .framework/cli/context.ts,.framework/functions/_shared/index.ts"]
20
- // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
21
- // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
22
- // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
23
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
24
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
25
12
  // CIL[END stable_id="~/.framework/cli/commands/generate.ts:module_header:module_header"]
26
- // CIL[BEGIN stable_id="~/.framework/cli/commands/generate.ts:__filename:constant" type="constant" identity="__filename" parent="~/.framework/cli/commands/generate.ts"]
27
- // CIL[DOC-MACRO purpose="Derive the current module's file path for ESM modules"]
28
- // CIL[DOC-RESPONSIBILITY responsibility="Hold the resolved __filename for path operations"]
29
- // CIL[DOC-STABILITY stability="internal"]
30
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
31
- // CIL[DOC-CONTEXT module=".framework/cli/commands/generate" layer="app-specific" related_files=".framework/cli/commands/generate.ts,.framework/cli/context.ts,.framework/functions/_shared/index.ts"]
32
- // CIL[DOC-CONTRACT inputs="none" outputs="string __filename" errors="none" side_effects="none"]
33
- // CIL[DOC-MICRO logic_summary="Calls fileURLToPath on import.meta.url" notable_decisions=""]
34
- const __filename = fileURLToPath(import.meta.url)
35
- // CIL[END stable_id="~/.framework/cli/commands/generate.ts:__filename:constant"]
36
- // CIL[BEGIN stable_id="~/.framework/cli/commands/generate.ts:__dirname:constant" type="constant" identity="__dirname" parent="~/.framework/cli/commands/generate.ts"]
37
- // CIL[DOC-VECTOR type="context" content="purpose='Derive the current module's file path for ESM modules'; No verified external callers; imports: .framework/cli/context.ts,.framework/functions/_shared/index.ts"]
38
- // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
39
- // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
40
- // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
41
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
42
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
43
- // CIL[DOC-MACRO purpose="Derive the current module's directory name for relative path resolution"]
44
- // CIL[DOC-RESPONSIBILITY responsibility="Hold the resolved __dirname for directory operations"]
45
- // CIL[DOC-CONTEXT module=".framework/cli/commands/generate" layer="app-specific" related_files=".framework/cli/commands/generate.ts,.framework/cli/context.ts,.framework/functions/_shared/index.ts"]
46
- // CIL[DOC-STABILITY stability="internal"]
47
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
48
- // CIL[DOC-CONTRACT inputs="none" outputs="string __dirname" errors="none" side_effects="none"]
49
- // CIL[DOC-MICRO logic_summary="Applies dirname to the resolved __filename" notable_decisions=""]
50
- const __dirname = dirname(__filename)
51
- // CIL[END stable_id="~/.framework/cli/commands/generate.ts:__dirname:constant"]
52
- // CIL[BEGIN stable_id="~/.framework/cli/commands/generate.ts:PROJECT_ROOT:constant" type="constant" identity="PROJECT_ROOT" parent="~/.framework/cli/commands/generate.ts"]
53
- // CIL[DOC-VECTOR type="context" content="purpose='Derive the current module's directory name for relative path resolution'; No verified external callers; imports: .framework/cli/context.ts,.framework/functions/_shared/index.ts"]
54
- // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
55
- // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
56
- // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
57
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
58
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
59
- // CIL[DOC-MACRO purpose="Resolve the absolute project root directory for file operations"]
60
- // CIL[DOC-RESPONSIBILITY responsibility="Hold the resolved project root path for stub generation"]
61
- // CIL[DOC-CONTEXT module=".framework/cli/commands/generate" layer="app-specific" related_files=".framework/cli/commands/generate.ts,.framework/cli/context.ts,.framework/functions/_shared/index.ts"]
62
- // CIL[DOC-CONTRACT inputs="none" outputs="string PROJECT_ROOT" errors="none" side_effects="none"]
63
- // CIL[DOC-MICRO logic_summary="Resolves __dirname three levels up to reach project root" notable_decisions=""]
64
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
65
- // CIL[DOC-STABILITY stable]
66
- const PROJECT_ROOT = resolve(__dirname, '../../../')
67
- // CIL[DOC-VECTOR type="context" content="purpose='Resolve the absolute project root directory for file operations'; No verified external callers; imports: .framework/cli/context.ts,.framework/functions/_shared/index.ts"]
68
- // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
69
- // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
70
- // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
71
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
72
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
73
- // CIL[END stable_id="~/.framework/cli/commands/generate.ts:PROJECT_ROOT:constant"]
74
-
75
- // CIL[BEGIN stable_id="~/.framework/cli/commands/generate.ts:generateType:function" type="function" identity="generateType" parent="~/.framework/cli/commands/generate.ts"]
76
- // CIL[DOC-MACRO purpose="Generate a new database type and create handler and UI page stubs"]
77
- // CIL[DOC-RESPONSIBILITY responsibility="Check for existing type, insert a new record, and write handler and page stub files"]
78
- // CIL[DOC-CONTEXT module=".framework/cli/commands/generate" layer="app-specific" related_files=".framework/cli/commands/generate.ts,.framework/cli/context.ts,.framework/functions/_shared/index.ts"]
79
- // CIL[DOC-CONTRACT inputs="ctx: any, slug: string, options: any" outputs="Promise<void>" errors="Error on DB check/insert failure; skip if type exists" side_effects="Writes to the database and filesystem"]
80
- // CIL[DOC-MICRO logic_summary="Builds name/kind/description, checks for an existing type, inserts the design schema, and writes handler and page files unless present or force=true" notable_decisions="Defaults kind to 'item' and status options to open/in_progress/closed"]
81
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
82
- // CIL[DOC-STABILITY stable]
83
- async function generateType(ctx: any, slug: string, options: any): Promise<void> {
84
- const name = options.name || slug.split('-').map(s => s.charAt(0).toUpperCase() + s.slice(1)).join(' ')
85
- const kind = options.kind || 'item'
86
- const description = options.description || `${name} type generated by spine CLI`
87
-
88
- console.log(`\n🔧 Generating type '${slug}'...`)
89
-
90
- const { data: existing, error: checkErr } = await adminDb
91
- .from('types')
92
- .select('id')
93
- .eq('slug', slug)
94
- .eq('kind', kind)
95
- .single()
96
-
97
- if (checkErr && checkErr.code !== 'PGRST116') {
98
- throw new Error(`Failed to check existing type: ${checkErr.message}`)
99
- }
100
-
101
- if (existing) {
102
- console.log(` ⚠️ Type '${slug}' already exists (skipping DB creation)`)
103
- } else {
104
- const designSchema = {
105
- fields: {
106
- title: {
107
- type: 'string',
108
- required: true,
109
- label: 'Title',
110
- description: `Title for this ${name}`
111
- },
112
- status: {
113
- type: 'select',
114
- options: ['open', 'in_progress', 'closed'],
115
- default: 'open',
116
- label: 'Status'
117
- }
118
- },
119
- layout: {
120
- detail: ['title', 'status'],
121
- list: ['title', 'status']
122
- }
123
- }
124
-
125
- const { error: insertErr } = await adminDb
126
- .from('types')
127
- .insert({
128
- kind,
129
- slug,
130
- name,
131
- description,
132
- design_schema: designSchema,
133
- validation_schema: {},
134
- ownership: 'system',
135
- is_active: true
136
- })
137
-
138
- if (insertErr) {
139
- throw new Error(`Failed to create type: ${insertErr.message}`)
140
- }
141
-
142
- console.log(' ✓ Type record created')
143
- }
144
-
145
- const handlerPath = resolve(PROJECT_ROOT, `v2-custom/functions/${slug}.ts`)
146
-
147
- if (existsSync(handlerPath) && !options.force) {
148
- console.log(` ⚠️ Handler stub already exists: ${handlerPath}`)
149
- } else {
150
- const handlerCode = generateHandlerStub(slug, kind, name)
151
- writeFileSync(handlerPath, handlerCode)
152
- console.log(` ✓ Handler stub created: v2-custom/functions/${slug}.ts`)
153
- }
154
13
 
155
- const pageDir = resolve(PROJECT_ROOT, `v2-custom/src/pages/${slug}`)
156
- const pagePath = resolve(pageDir, 'index.tsx')
157
-
158
- if (existsSync(pagePath) && !options.force) {
159
- console.log(` ⚠️ UI page stub already exists: ${pagePath}`)
160
- } else {
161
- mkdirSync(pageDir, { recursive: true })
162
- const pageCode = generatePageStub(slug, name, kind)
163
- writeFileSync(pagePath, pageCode)
164
- console.log(` ✓ UI page stub created: v2-custom/src/pages/${slug}/index.tsx`)
165
- }
166
-
167
- console.log(`\n✅ Type '${slug}' generation complete!`)
168
- console.log(` Next steps:`)
169
- console.log(` 1. Edit v2-custom/functions/${slug}.ts to implement custom logic`)
170
- console.log(` 2. Edit v2-custom/src/pages/${slug}/index.tsx to customize the UI`)
171
- console.log(` 3. Run 'spine dev' to see your changes`)
172
- }
173
- // CIL[DOC-VECTOR type="context" content="purpose='Generate a new database type and create handler and UI page stubs'; No verified external callers; imports: .framework/cli/context.ts,.framework/functions/_shared/index.ts"]
14
+ // CIL[DOC-VECTOR type="context" content="purpose='Deprecated stub for the removed generate scaffold'; No verified external callers; imports: none"]
174
15
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
175
16
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
176
17
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
177
18
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
178
19
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
179
- // CIL[END stable_id="~/.framework/cli/commands/generate.ts:generateType:function"]
180
-
181
- // CIL[BEGIN stable_id="~/.framework/cli/commands/generate.ts:generateHandlerStub:function" type="function" identity="generateHandlerStub" parent="~/.framework/cli/commands/generate.ts"]
182
- // CIL[DOC-MACRO purpose="Generate a custom API handler stub string for a type"]
183
- // CIL[DOC-RESPONSIBILITY responsibility="Return a templated handler function using createHandler"]
184
- // CIL[DOC-CONTEXT module=".framework/cli/commands/generate" layer="app-specific" related_files=".framework/cli/commands/generate.ts,.framework/cli/context.ts,.framework/functions/_shared/index.ts"]
185
- // CIL[DOC-CONTRACT inputs="slug: string, kind: string, name: string" outputs="string handler code" errors="Error for unsupported HTTP method at runtime" side_effects="none"]
186
- // CIL[DOC-MICRO logic_summary="Builds a handler template with a switch for GET/POST/PATCH/DELETE methods" notable_decisions="Uses new Date().toISOString() in the generated header comment"]
187
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
188
- // CIL[DOC-STABILITY experimental]
189
- function generateHandlerStub(slug: string, kind: string, name: string): string {
190
- return `/**
191
- * @module ${slug}
192
- * @audience custom
193
- * @layer api-handler
194
- * @stability experimental
195
- *
196
- * Custom handler for ${name} (${kind} type).
197
- * Generated by spine CLI on ${new Date().toISOString()}.
198
- *
199
- * Extend this handler to add custom logic for your type.
200
- */
201
-
202
- import { createHandler } from '../v2-core/functions/_shared/middleware'
203
-
204
- export const handler = createHandler(async (ctx) => {
205
- const method = ctx.query?.method || 'GET'
206
-
207
- switch (method) {
208
- case 'GET':
209
- return { message: '${name} handler - GET not implemented' }
210
-
211
- case 'POST':
212
- return { message: '${name} handler - POST not implemented' }
213
20
 
214
- case 'PATCH':
215
- return { message: '${name} handler - PATCH not implemented' }
216
-
217
- case 'DELETE':
218
- return { message: '${name} handler - DELETE not implemented' }
219
-
220
- default:
221
- throw new Error('Unsupported method: ' + method)
222
- }
223
- })
224
- `
225
- }
226
- // CIL[DOC-VECTOR type="context" content="purpose='Generate a custom API handler stub string for a type'; No verified external callers; imports: .framework/cli/context.ts,.framework/functions/_shared/index.ts"]
227
- // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
228
- // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
229
- // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
230
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
231
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
232
- // CIL[END stable_id="~/.framework/cli/commands/generate.ts:generateHandlerStub:function"]
233
-
234
- // CIL[BEGIN stable_id="~/.framework/cli/commands/generate.ts:generatePageStub:function" type="function" identity="generatePageStub" parent="~/.framework/cli/commands/generate.ts"]
235
- // CIL[DOC-MACRO purpose="Generate a React page stub string for a type"]
236
- // CIL[DOC-RESPONSIBILITY responsibility="Return a React component template that fetches and displays record data"]
237
- // CIL[DOC-CONTEXT module=".framework/cli/commands/generate" layer="app-specific" related_files=".framework/cli/commands/generate.ts,.framework/cli/context.ts,.framework/functions/_shared/index.ts"]
238
- // CIL[DOC-CONTRACT inputs="slug: string, name: string, kind: string" outputs="string React component code" errors="Error on failed API fetch at runtime" side_effects="none (generated string only)"]
239
- // CIL[DOC-MICRO logic_summary="Builds a React page template using useParams, useApi, and apiFetch" notable_decisions="Uses new Date().toISOString() in the generated header comment"]
240
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
241
- // CIL[DOC-STABILITY experimental]
242
- function generatePageStub(slug: string, name: string, kind: string): string {
243
- return `/**
244
- * @page ${slug}/index
245
- * @audience custom
246
- * @layer page
247
- * @stability experimental
248
- *
249
- * UI page for ${name} (${kind} type).
250
- * Generated by spine CLI on ${new Date().toISOString()}.
251
- */
252
-
253
- import React from 'react'
254
- import { useParams } from 'react-router-dom'
255
- import { useApi } from '../../v2-core/src/hooks/useApi'
256
- import { apiFetch } from '../../v2-core/src/lib/api'
21
+ // CIL[DOC-MACRO purpose="Register the deprecated 'generate' command so invocations fail with a clear removal notice"]
22
+ // CIL[DOC-RESPONSIBILITY responsibility="Wire the deprecated generate command into the program"]
23
+ // CIL[DOC-CONTEXT module=".framework/cli/commands/generate" layer="app-specific" related_files=".framework/cli/commands/create-app.ts"]
24
+ // CIL[DOC-CONTRACT inputs="program: Command" outputs="void" errors="always exits 1 on invocation" side_effects="Registers a command and prints guidance to stderr"]
25
+ // CIL[DOC-MICRO logic_summary="Defines 'generate [slug]' whose action prints the removal notice and exits 1" notable_decisions="Exit 1 (non-zero) so scripts fail loudly rather than silently writing nothing"]
26
+ // CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
27
+ // CIL[DOC-STABILITY deprecated]
28
+ // CIL[BEGIN stable_id="~/.framework/cli/commands/generate.ts:registerGenerateCommands:function" type="function" identity="registerGenerateCommands" parent="~/.framework/cli/commands/generate.ts"]
29
+ export function registerGenerateCommands(program: Command) {
30
+ program
31
+ .command('generate [slug]')
32
+ .description('Removed — legacy v2 scaffold no longer exists (prints migration guidance)')
33
+ .action(() => {
34
+ console.error(`
35
+ ❌ 'spine-framework generate' was removed.
257
36
 
258
- export default function ${name.replace(/\s+/g, '')}Page() {
259
- const { id } = useParams()
37
+ The old scaffold wrote type/handler/page stubs into a 'v2-custom/' tree
38
+ and emitted a legacy design_schema shape — neither exists in this layout.
260
39
 
261
- const { data, loading, error } = useApi(
262
- () => apiFetch('/.netlify/functions/${slug}' + (id ? '?id=' + id : '')),
263
- { immediate: true }
264
- )
40
+ To get the same outcome today:
265
41
 
266
- if (loading) return <div>Loading...</div>
267
- if (error) return <div>Error: {error.message}</div>
42
+ • New app: spine-framework create-app <slug>
43
+ (scaffolds custom/apps/<slug>/ + registers the app)
268
44
 
269
- return (
270
- <div className="p-6">
271
- <h1 className="text-2xl font-bold mb-4">${name}</h1>
272
- <pre className="bg-gray-100 p-4 rounded">
273
- {JSON.stringify(data, null, 2)}
274
- </pre>
275
- <p className="mt-4 text-gray-600">
276
- Edit v2-custom/src/pages/${slug}/index.tsx to customize this page.
277
- </p>
278
- </div>
279
- )
280
- }
281
- `
282
- }
283
- // CIL[END stable_id="~/.framework/cli/commands/generate.ts:generatePageStub:function"]
45
+ • New type: author design_schema JSON, then either
46
+ - create it in the admin UI (Spine Admin → Types), or
47
+ - POST it to /api/types
48
+ Validate first: spine-framework validate-schema <file.json>
284
49
 
285
- // CIL[BEGIN stable_id="~/.framework/cli/commands/generate.ts:registerGenerateCommands:function" type="function" identity="registerGenerateCommands" parent="~/.framework/cli/commands/generate.ts"]
286
- // CIL[DOC-VECTOR type="context" content="purpose='Generate a React page stub string for a type'; No verified external callers; imports: .framework/cli/context.ts,.framework/functions/_shared/index.ts"]
287
- // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
288
- // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
289
- // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
290
- // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
291
- // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
292
- // CIL[DOC-MACRO purpose="Register the generate CLI command with the Commander program"]
293
- // CIL[DOC-RESPONSIBILITY responsibility="Wire the generate command, options, and action into the program"]
294
- // CIL[DOC-CONTEXT module=".framework/cli/commands/generate" layer="app-specific" related_files=".framework/cli/commands/generate.ts,.framework/cli/context.ts,.framework/functions/_shared/index.ts"]
295
- // CIL[DOC-CONTRACT inputs="program: Command" outputs="void" errors="none (handled by handleError)" side_effects="Adds command and action to the program"]
296
- // CIL[DOC-MICRO logic_summary="Attaches the 'generate <slug>' command with options and an async action that builds context and calls generateType" notable_decisions="Defaults kind to 'item' and passes parsed options to generateType"]
297
- // CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
298
- // CIL[DOC-STABILITY stable]
299
- export function registerGenerateCommands(program: Command) {
300
- program
301
- .command('generate <slug>')
302
- .description('Generate type, handler, and UI stubs')
303
- .option('--name <name>', 'Human-readable name')
304
- .option('--kind <kind>', 'Type kind', 'item')
305
- .option('--description <description>', 'Type description')
306
- .option('--force', 'Overwrite existing files', false)
307
- .action(async (slug, opts) => {
308
- try {
309
- const ctx = await buildCliContext()
310
- await generateType(ctx, slug, opts)
311
- } catch (err: any) {
312
- handleError(err)
313
- }
50
+ • Custom logic: put functions in custom/apps/<slug>/functions/ — they are
51
+ picked up by 'npm run assemble' automatically.
52
+ `)
53
+ process.exit(1)
314
54
  })
315
55
  }
316
- // CIL[DOC-VECTOR type="context" content="purpose='Register the generate CLI command with the Commander program'; No verified external callers; imports: .framework/cli/context.ts,.framework/functions/_shared/index.ts"]
56
+ // CIL[END stable_id="~/.framework/cli/commands/generate.ts:registerGenerateCommands:function"]
57
+ // CIL[DOC-VECTOR type="context" content="purpose='Register the deprecated generate command'; No verified external callers; imports: none"]
317
58
  // CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
318
59
  // CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
319
60
  // CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
320
61
  // CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
321
62
  // CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
322
- // CIL[END stable_id="~/.framework/cli/commands/generate.ts:registerGenerateCommands:function"]