spine-framework 0.3.145 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +76 -0
- package/.framework/.spine-manifest.json +19 -0
- package/.framework/cli/commands/agents.ts +61 -33
- package/.framework/cli/commands/auth.ts +60 -28
- package/.framework/cli/commands/create-app.ts +212 -80
- package/.framework/cli/commands/dev.ts +184 -68
- package/.framework/cli/commands/doctor.ts +324 -152
- package/.framework/cli/commands/generate.ts +119 -68
- package/.framework/cli/commands/init.ts +141 -242
- package/.framework/cli/commands/install-app.ts +1336 -314
- package/.framework/cli/commands/items.ts +31 -29
- package/.framework/cli/commands/migrate.ts +299 -156
- package/.framework/cli/commands/migrations.ts +62 -30
- package/.framework/cli/commands/pipelines.ts +31 -29
- package/.framework/cli/commands/status.ts +105 -45
- package/.framework/cli/commands/system.ts +47 -42
- package/.framework/cli/commands/test.ts +161 -102
- package/.framework/cli/commands/upgrade.ts +260 -0
- package/.framework/cli/commands/validate-app.ts +517 -161
- package/.framework/cli/context.ts +117 -85
- package/.framework/cli/env-loader.ts +74 -43
- package/.framework/cli/index.ts +70 -46
- package/.framework/cli/lib/project-files.ts +404 -0
- package/.framework/docs/guides/testing-guide.md +1 -1
- package/.framework/docs/runtime-types.md +72 -72
- package/.framework/functions/_shared/access.ts +84 -0
- package/.framework/functions/_shared/agent-runner.ts +5051 -1026
- package/.framework/functions/_shared/app-manifest.ts +214 -94
- package/.framework/functions/_shared/ast.ts +214 -0
- package/.framework/functions/_shared/audit.ts +91 -55
- package/.framework/functions/_shared/cil.ts +368 -127
- package/.framework/functions/_shared/db.ts +337 -68
- package/.framework/functions/_shared/funnel.ts +228 -0
- package/.framework/functions/_shared/geo.ts +105 -0
- package/.framework/functions/_shared/hash-api-key.ts +94 -17
- package/.framework/functions/_shared/index.ts +22 -224
- package/.framework/functions/_shared/kb.ts +832 -58
- package/.framework/functions/_shared/llm.ts +118 -18
- package/.framework/functions/_shared/logging.ts +317 -19
- package/.framework/functions/_shared/middleware.ts +701 -131
- package/.framework/functions/_shared/notify.ts +70 -0
- package/.framework/functions/_shared/outcomes.ts +34 -19
- package/.framework/functions/_shared/permissions.ts +501 -315
- package/.framework/functions/_shared/pipeline-runner.ts +704 -155
- package/.framework/functions/_shared/principal.ts +436 -263
- package/.framework/functions/_shared/rate-limit.ts +233 -0
- package/.framework/functions/_shared/resolve-credentials.ts +86 -19
- package/.framework/functions/_shared/resolve-ids.ts +203 -139
- package/.framework/functions/_shared/retry-deliveries.ts +51 -16
- package/.framework/functions/_shared/schema-utils.ts +602 -521
- package/.framework/functions/_shared/security.ts +345 -0
- package/.framework/functions/_shared/testing.ts +197 -172
- package/.framework/functions/_shared/tracing.ts +351 -21
- package/.framework/functions/_shared/trigger-engine.ts +425 -136
- package/.framework/functions/_shared/webhook-registration.ts +71 -70
- package/.framework/functions/_shared/webhook-registry.ts +126 -83
- package/.framework/functions/account-nodes.ts +30 -30
- package/.framework/functions/adapters/generic-webhook-inbound.ts +49 -16
- package/.framework/functions/adapters/generic-webhook-outbound.ts +17 -17
- package/.framework/functions/adapters/openai-outbound.ts +15 -16
- package/.framework/functions/admin-data.ts +596 -173
- package/.framework/functions/admin-funnel.ts +64 -60
- package/.framework/functions/admin-install-funnel.ts +84 -66
- package/.framework/functions/admin-signals.ts +69 -51
- package/.framework/functions/ai-agents.ts +431 -106
- package/.framework/functions/ai-interactions.ts +186 -112
- package/.framework/functions/api-keys.ts +107 -107
- package/.framework/functions/apps.ts +154 -136
- package/.framework/functions/auth.ts +83 -65
- package/.framework/functions/cil-agent-ingest.ts +189 -232
- package/.framework/functions/cil-agent.ts +433 -177
- package/.framework/functions/cil-callmap.ts +642 -430
- package/.framework/functions/cil-config.ts +139 -135
- package/.framework/functions/cil-context.ts +214 -127
- package/.framework/functions/cil-doc.ts +587 -458
- package/.framework/functions/cil-embeddings.ts +453 -364
- package/.framework/functions/cil-graph.ts +427 -142
- package/.framework/functions/cil-ingest.ts +1418 -1154
- package/.framework/functions/cil-pipeline.ts +276 -21
- package/.framework/functions/cil-project.ts +659 -132
- package/.framework/functions/cil-validate.ts +198 -164
- package/.framework/functions/debug-auth.ts +57 -55
- package/.framework/functions/deliveries.ts +80 -21
- package/.framework/functions/embeddings.ts +1023 -318
- package/.framework/functions/eval-harness.ts +146 -108
- package/.framework/functions/integration-outbound.ts +205 -75
- package/.framework/functions/integration-routes.ts +128 -23
- package/.framework/functions/integrations.ts +125 -100
- package/.framework/functions/invites.ts +1095 -460
- package/.framework/functions/item-progress.ts +158 -102
- package/.framework/functions/kb.ts +34 -10
- package/.framework/functions/logs.ts +133 -133
- package/.framework/functions/observability.ts +152 -122
- package/.framework/functions/pipeline-executions.ts +147 -132
- package/.framework/functions/pipelines.ts +134 -119
- package/.framework/functions/prompt-configs.ts +96 -80
- package/.framework/functions/roles.ts +112 -82
- package/.framework/functions/security.ts +450 -0
- package/.framework/functions/system-cron.ts +117 -80
- package/.framework/functions/system.ts +158 -98
- package/.framework/functions/tests.ts +29 -29
- package/.framework/functions/timers.ts +94 -95
- package/.framework/functions/trigger-scheduler.ts +10 -0
- package/.framework/functions/triggers.ts +179 -149
- package/.framework/functions/types.ts +137 -125
- package/.framework/mcp/index.ts +133 -0
- package/.framework/mcp/load-env.ts +60 -0
- package/.framework/mcp/shared/app-manifest.ts +275 -0
- package/.framework/mcp/shared/db.ts +477 -0
- package/.framework/mcp/shared/kb.ts +118 -0
- package/.framework/mcp/tools/architect.ts +431 -0
- package/.framework/mcp/tools/cil/context.ts +345 -0
- package/.framework/mcp/tools/cil/graph.ts +242 -0
- package/.framework/mcp/tools/cil/ingest.ts +1217 -0
- package/.framework/mcp/tools/cil/pipeline-orchestrator.ts +693 -0
- package/.framework/mcp/tools/cil/pipeline.ts +767 -0
- package/.framework/mcp/tools/cil/project.ts +791 -0
- package/.framework/mcp/tools/cil/retrieval.ts +336 -0
- package/.framework/mcp/tools/cil/search-core.ts +454 -0
- package/.framework/mcp/tools/cil/search.ts +97 -0
- package/.framework/mcp/tools/cil/suggest.ts +186 -0
- package/.framework/mcp/tools/cil/validate.ts +1369 -0
- package/.framework/mcp/tools/kb/delete.ts +139 -0
- package/.framework/mcp/tools/kb/index.ts +52 -0
- package/.framework/mcp/tools/kb/ingest.ts +84 -0
- package/.framework/mcp/tools/kb/list-types.ts +102 -0
- package/.framework/mcp/tools/kb/publish.ts +100 -0
- package/.framework/mcp/tools/kb/reindex.ts +86 -0
- package/.framework/mcp/tools/kb/revoke.ts +85 -0
- package/.framework/mcp/tools/kb/search.ts +101 -0
- package/.framework/mcp/tools/kb/upsert.ts +125 -0
- package/.framework/mcp/tools/observability.ts +510 -0
- package/.framework/migrations/001_core_schema.sql +15 -0
- package/.framework/migrations/002_core_rls_and_functions.sql +15 -0
- package/.framework/migrations/003_core_system_data.sql +16 -1
- package/.framework/migrations/004_core_rpc_and_broker.sql +17 -1
- package/.framework/migrations/005_core_observability.sql +17 -1
- package/.framework/migrations/006_security_hardening_rls.sql +15 -0
- package/.framework/migrations/007_kb_article_list.sql +17 -1
- package/.framework/migrations/008_items_target.sql +15 -0
- package/.framework/migrations/009_roles_slug_unique.sql +15 -0
- package/.framework/migrations/010_auth_user_trigger.sql +15 -0
- package/.framework/migrations/011_spine_system_account.sql +16 -0
- package/.framework/migrations/012_service_role_grants.sql +16 -0
- package/.framework/migrations/013_get_account_apps_role_filter.sql +15 -0
- package/.framework/migrations/014_apps_required_roles.sql +16 -0
- package/.framework/migrations/015_types_kind_slug_unique.sql +15 -0
- package/.framework/migrations/016_cil_types.sql +281 -0
- package/.framework/migrations/017_cil_stable_ids.sql +37 -0
- package/.framework/migrations/018_runtime_tables.sql +129 -0
- package/.framework/migrations/019_agent_prompt_columns.sql +56 -0
- package/.framework/migrations/020_schema_reconciliation.sql +67 -0
- package/.framework/migrations/021_kb_embedding_lifecycle.sql +31 -0
- package/.framework/migrations/032_cil_status_migration.sql +73 -0
- package/.framework/migrations/033_cil_versioning.sql +73 -0
- package/.framework/migrations/034_match_embeddings_knn.sql +115 -0
- package/.framework/migrations/035_rate_limits.sql +55 -0
- package/.framework/migrations/036_demo_record_flags.sql +72 -0
- package/.framework/migrations/037_kb_types_canonical.sql +244 -0
- package/.framework/migrations/038_drop_demo_record_flags.sql +38 -0
- package/.framework/migrations/042_registration_hierarchy.sql +309 -0
- package/.framework/migrations/043_policy_actor_cleanup.sql +39 -0
- package/.framework/migrations/044_match_embeddings_filtered_knn.sql +151 -0
- package/.framework/migrations/045_security_critical_rls.sql +139 -0
- package/.framework/migrations/046_security_missing_rls.sql +79 -0
- package/.framework/migrations/047_people_updated_by.sql +27 -0
- package/.framework/migrations/048_watcher_last_seen_at.sql +24 -0
- package/.framework/migrations/049_security_blocklist.sql +148 -0
- package/.framework/migrations/050_notifications.sql +49 -0
- package/.framework/migrations/051_message_agent_fields.sql +74 -0
- package/.framework/migrations/052_registration_security.sql +421 -0
- package/.framework/migrations/053_builtin_action_seeds.sql +66 -0
- package/.framework/migrations/054_kb_ingest_lease.sql +157 -0
- package/.framework/migrations/055_type_id_drift_reconciliation.sql +33 -0
- package/.framework/migrations/056_slug_column_reconciliation.sql +38 -0
- package/.framework/migrations/057_pipelines_slug_identity.sql +14 -0
- package/.framework/migrations/058_account_data_field_declarations.sql +53 -0
- package/.framework/migrations/059_registration_placement_fixes.sql +269 -0
- package/.framework/migrations/060_account_person_record_permissions.sql +38 -0
- package/.framework/migrations/061_fk_dedup.sql +32 -0
- package/.framework/public/spine-logo.svg +10 -3
- package/.framework/scripts/app-install-cli.ts +190 -93
- package/.framework/scripts/assemble-frontend.sh +127 -44
- package/.framework/scripts/assemble-functions.sh +128 -30
- package/.framework/scripts/boundary-check.sh +6 -2
- package/.framework/scripts/build-manifest.sh +24 -68
- package/.framework/scripts/check-core-integrity.sh +15 -76
- package/.framework/scripts/checksum-manifest.mts +343 -0
- package/.framework/scripts/cil-migrate-markers.ts +403 -0
- package/.framework/scripts/fix-cil-markers.mjs +176 -0
- package/.framework/scripts/verify-integrity.sh +21 -57
- package/.framework/scripts/verify-manifest.mts +305 -0
- package/.framework/seeds/types/funnel_signal_use.json +74 -21
- package/.framework/seeds/types/spine_instance.json +73 -21
- package/.framework/src/App.tsx +118 -72
- package/.framework/src/apps/admin/index.tsx +855 -58
- package/.framework/src/components/AppWrapper.tsx +43 -45
- package/.framework/src/components/CustomAppLoader.tsx +160 -116
- package/.framework/src/components/admin/AdminListPage.tsx +46 -44
- package/.framework/src/components/admin/AdminSidebar.tsx +57 -47
- package/.framework/src/components/admin/AdminStatsCard.tsx +46 -44
- package/.framework/src/components/admin/PageInstructions.tsx +98 -2
- package/.framework/src/components/admin/SortableTableHeader.tsx +44 -45
- package/.framework/src/components/app-shell/GenericAppShell.tsx +64 -65
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +44 -47
- package/.framework/src/components/app-shell/GenericListPage.tsx +45 -49
- package/.framework/src/components/app-sidebar.tsx +42 -45
- package/.framework/src/components/auth/ProtectedRoute.tsx +48 -41
- package/.framework/src/components/auth/TurnstileWidget.tsx +27 -0
- package/.framework/src/components/kb/KBArticleEditor.tsx +231 -22
- package/.framework/src/components/kb/KBArticleList.tsx +251 -10
- package/.framework/src/components/layout/AppShell.tsx +51 -45
- package/.framework/src/components/layout/Header.tsx +42 -43
- package/.framework/src/components/layout/Layout.tsx +46 -46
- package/.framework/src/components/layout/Sidebar.tsx +196 -96
- package/.framework/src/components/runtime/DataDetailHeader.tsx +55 -30
- package/.framework/src/components/runtime/DataDetailPage.tsx +31 -269
- package/.framework/src/components/runtime/DataFilters.tsx +49 -74
- package/.framework/src/components/runtime/DataHeader.tsx +53 -32
- package/.framework/src/components/runtime/DataListPage.tsx +51 -155
- package/.framework/src/components/runtime/DataStats.tsx +66 -44
- package/.framework/src/components/runtime/DataTable.tsx +49 -149
- package/.framework/src/components/runtime/SchemaDetailForm.tsx +45 -75
- package/.framework/src/components/runtime/index.ts +119 -16
- package/.framework/src/components/search-form.tsx +46 -29
- package/.framework/src/components/shared/AgentView.tsx +65 -48
- package/.framework/src/components/shared/FieldRenderer.tsx +144 -50
- package/.framework/src/components/shared/InviteManager.tsx +207 -97
- package/.framework/src/components/shared/MemberList.tsx +97 -0
- package/.framework/src/components/shared/SchemaFields.tsx +107 -86
- package/.framework/src/components/ui/DataTable.tsx +80 -68
- package/.framework/src/components/ui/Form.tsx +157 -146
- package/.framework/src/components/ui/ItemCard.tsx +74 -67
- package/.framework/src/components/ui/ItemListView.tsx +73 -68
- package/.framework/src/components/ui/LoadingSpinner.tsx +43 -48
- package/.framework/src/components/ui/Modal.tsx +78 -68
- package/.framework/src/components/ui/RichTextEditor.tsx +89 -69
- package/.framework/src/components/ui/accordion.tsx +85 -86
- package/.framework/src/components/ui/alert-dialog.tsx +197 -184
- package/.framework/src/components/ui/alert.tsx +105 -94
- package/.framework/src/components/ui/aspect-ratio.tsx +57 -43
- package/.framework/src/components/ui/avatar.tsx +122 -107
- package/.framework/src/components/ui/badge.tsx +60 -55
- package/.framework/src/components/ui/breadcrumb.tsx +127 -128
- package/.framework/src/components/ui/button-group.tsx +86 -72
- package/.framework/src/components/ui/button.tsx +71 -50
- package/.framework/src/components/ui/calendar.tsx +72 -57
- package/.framework/src/components/ui/card.tsx +136 -129
- package/.framework/src/components/ui/carousel.tsx +226 -107
- package/.framework/src/components/ui/chart.tsx +252 -147
- package/.framework/src/components/ui/checkbox.tsx +43 -44
- package/.framework/src/components/ui/collapsible.tsx +86 -71
- package/.framework/src/components/ui/combobox.tsx +282 -249
- package/.framework/src/components/ui/command.tsx +158 -146
- package/.framework/src/components/ui/context-menu.tsx +239 -240
- package/.framework/src/components/ui/dialog.tsx +174 -157
- package/.framework/src/components/ui/direction.tsx +72 -56
- package/.framework/src/components/ui/drawer.tsx +168 -169
- package/.framework/src/components/ui/dropdown-menu.tsx +254 -223
- package/.framework/src/components/ui/empty.tsx +131 -120
- package/.framework/src/components/ui/field.tsx +205 -173
- package/.framework/src/components/ui/hover-card.tsx +71 -72
- package/.framework/src/components/ui/input-group.tsx +148 -133
- package/.framework/src/components/ui/input-otp.tsx +99 -86
- package/.framework/src/components/ui/input.tsx +43 -41
- package/.framework/src/components/ui/item.tsx +207 -185
- package/.framework/src/components/ui/kbd.tsx +57 -56
- package/.framework/src/components/ui/label.tsx +45 -41
- package/.framework/src/components/ui/menubar.tsx +268 -236
- package/.framework/src/components/ui/native-select.tsx +85 -86
- package/.framework/src/components/ui/navigation-menu.tsx +166 -156
- package/.framework/src/components/ui/pagination.tsx +131 -141
- package/.framework/src/components/ui/popover.tsx +125 -128
- package/.framework/src/components/ui/progress.tsx +47 -44
- package/.framework/src/components/ui/radio-group.tsx +60 -55
- package/.framework/src/components/ui/resizable.tsx +85 -72
- package/.framework/src/components/ui/scroll-area.tsx +57 -58
- package/.framework/src/components/ui/select.tsx +182 -169
- package/.framework/src/components/ui/separator.tsx +42 -43
- package/.framework/src/components/ui/sheet.tsx +170 -159
- package/.framework/src/components/ui/sidebar.tsx +395 -398
- package/.framework/src/components/ui/skeleton.tsx +42 -43
- package/.framework/src/components/ui/slider.tsx +61 -44
- package/.framework/src/components/ui/sonner.tsx +44 -44
- package/.framework/src/components/ui/spinner.tsx +47 -42
- package/.framework/src/components/ui/switch.tsx +56 -42
- package/.framework/src/components/ui/table-primitives.tsx +272 -132
- package/.framework/src/components/ui/table.tsx +140 -142
- package/.framework/src/components/ui/tabs.tsx +110 -93
- package/.framework/src/components/ui/textarea.tsx +43 -44
- package/.framework/src/components/ui/toggle-group.tsx +87 -71
- package/.framework/src/components/ui/toggle.tsx +56 -56
- package/.framework/src/components/ui/tooltip.tsx +99 -85
- package/.framework/src/contexts/AppContext.tsx +166 -114
- package/.framework/src/contexts/AuthContext.tsx +232 -137
- package/.framework/src/hooks/use-mobile.ts +43 -44
- package/.framework/src/hooks/useApi.ts +185 -172
- package/.framework/src/hooks/useAppPath.ts +31 -29
- package/.framework/src/hooks/useApps.ts +77 -42
- package/.framework/src/hooks/useEntityList.ts +66 -29
- package/.framework/src/hooks/useEntityRecord.ts +76 -32
- package/.framework/src/hooks/useForm.ts +62 -30
- package/.framework/src/hooks/useListSchema.ts +60 -43
- package/.framework/src/hooks/useSchemaRecord.ts +115 -95
- package/.framework/src/lib/api.ts +258 -134
- package/.framework/src/lib/registration.ts +181 -0
- package/.framework/src/lib/supabase.ts +118 -81
- package/.framework/src/lib/utils.ts +266 -266
- package/.framework/src/main.tsx +43 -44
- package/.framework/src/pages/DashboardPage.tsx +44 -43
- package/.framework/src/pages/NoAppPage.tsx +50 -0
- package/.framework/src/pages/NotFoundPage.tsx +32 -29
- package/.framework/src/pages/SetupPage.tsx +34 -33
- package/.framework/src/pages/admin/AIAgentDetailPage.tsx +69 -58
- package/.framework/src/pages/admin/AIAgentsPage.tsx +43 -40
- package/.framework/src/pages/admin/APIKeyDetailPage.tsx +63 -55
- package/.framework/src/pages/admin/APIKeysPage.tsx +44 -42
- package/.framework/src/pages/admin/AlertsConfigPage.tsx +117 -94
- package/.framework/src/pages/admin/AppDetailPage.tsx +48 -42
- package/.framework/src/pages/admin/AppsPage.tsx +45 -42
- package/.framework/src/pages/admin/DeliveriesPage.tsx +49 -17
- package/.framework/src/pages/admin/DesignedPage.tsx +31 -30
- package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +58 -0
- package/.framework/src/pages/admin/EmbeddingsPage.tsx +49 -0
- package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +31 -29
- package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +46 -29
- package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -29
- package/.framework/src/pages/admin/IntegrationDetailPage.tsx +68 -55
- package/.framework/src/pages/admin/IntegrationsPage.tsx +45 -42
- package/.framework/src/pages/admin/InvitesPage.tsx +60 -44
- package/.framework/src/pages/admin/LogsPage.tsx +87 -137
- package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +31 -29
- package/.framework/src/pages/admin/ObservabilityDashboard.tsx +150 -89
- package/.framework/src/pages/admin/PipelineDetailPage.tsx +77 -104
- package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +44 -43
- package/.framework/src/pages/admin/PipelinesPage.tsx +59 -145
- package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +53 -42
- package/.framework/src/pages/admin/PromptConfigsPage.tsx +47 -117
- package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +31 -44
- package/.framework/src/pages/admin/RoleDetailPage.tsx +49 -92
- package/.framework/src/pages/admin/RolesPage.tsx +47 -164
- package/.framework/src/pages/admin/SecurityPage.tsx +310 -0
- package/.framework/src/pages/admin/SelectTestPage.tsx +30 -32
- package/.framework/src/pages/admin/ShadcnTestPage.tsx +37 -44
- package/.framework/src/pages/admin/SimpleDashboard.tsx +32 -44
- package/.framework/src/pages/admin/TestRunDetailPage.tsx +97 -44
- package/.framework/src/pages/admin/TestingDashboard.tsx +126 -71
- package/.framework/src/pages/admin/TimerDetailPage.tsx +67 -55
- package/.framework/src/pages/admin/TimersPage.tsx +44 -42
- package/.framework/src/pages/admin/TriggerDetailPage.tsx +47 -42
- package/.framework/src/pages/admin/TriggersPage.tsx +58 -57
- package/.framework/src/pages/admin/TypeDetailPage.tsx +91 -55
- package/.framework/src/pages/admin/TypesPage.tsx +45 -42
- package/.framework/src/pages/admin/cil/CILAgentPage.tsx +258 -128
- package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +127 -123
- package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +308 -235
- package/.framework/src/pages/admin/cil/CILFileListPage.tsx +159 -110
- package/.framework/src/pages/admin/cil/CILFileSelectPage.tsx +432 -0
- package/.framework/src/pages/admin/cil/CILGraphPage.tsx +200 -178
- package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +286 -239
- package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +211 -90
- package/.framework/src/pages/admin/cil/CILSearchPage.tsx +156 -143
- package/.framework/src/pages/admin/cil/CILSuggestionsPage.tsx +379 -0
- package/.framework/src/pages/admin/cil/CILVersionsPage.tsx +337 -0
- package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +219 -214
- package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
- package/.framework/src/pages/auth/AuthConfirmPage.tsx +135 -65
- package/.framework/src/pages/auth/ForgotPasswordPage.tsx +39 -31
- package/.framework/src/pages/auth/LoginPage.tsx +38 -32
- package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -28
- package/.framework/src/pages/auth/RegisterPage.tsx +429 -155
- package/.framework/src/pages/spine-framework/APIPage.tsx +33 -30
- package/.framework/src/pages/spine-framework/CLIPage.tsx +32 -30
- package/.framework/src/types/auth.ts +101 -93
- package/.framework/src/types/types.ts +283 -262
- package/.framework/templates/project.json +87 -0
- package/.framework/templates/spine.config.neutral.json +7 -0
- package/.framework/tests/api/api-surface.test.ts +381 -0
- package/.framework/tests/fixtures/seed.ts +427 -0
- package/.framework/tests/fixtures/teardown.ts +228 -0
- package/.framework/tests/reporter.ts +351 -0
- package/.framework/tests/setup.ts +135 -0
- package/.framework/tests/ui/ui-sweep.ts +278 -0
- package/.framework/tests/unit/admin-data-logger.test.ts +310 -0
- package/.framework/tests/unit/agent-runner.test.ts +2389 -0
- package/.framework/tests/unit/ai-interactions.test.ts +81 -0
- package/.framework/tests/unit/app-manifest.test.ts +359 -0
- package/.framework/tests/unit/assembly-scripts.test.ts +172 -0
- package/.framework/tests/unit/cil-determinism.test.ts +85 -0
- package/.framework/tests/unit/core-isolation.test.ts +153 -0
- package/.framework/tests/unit/funnel-signals.test.ts +135 -0
- package/.framework/tests/unit/install-app.test.ts +1759 -0
- package/.framework/tests/unit/invites-security.test.ts +572 -0
- package/.framework/tests/unit/kb-ingest-lease.test.ts +287 -0
- package/.framework/tests/unit/kb-search.test.ts +119 -0
- package/.framework/tests/unit/migrate.test.ts +509 -0
- package/.framework/tests/unit/notify.test.ts +136 -0
- package/.framework/tests/unit/permissions.test.ts +269 -0
- package/.framework/tests/unit/pipeline-runner.test.ts +755 -0
- package/.framework/tests/unit/principal-cache.test.ts +138 -0
- package/.framework/tests/unit/retrieval-golden.test.ts +520 -0
- package/.framework/tests/unit/runtime-isolation.test.ts +642 -0
- package/.framework/tests/unit/schema-utils.test.ts +225 -0
- package/.framework/tests/unit/trigger-engine.test.ts +513 -0
- package/.framework/tests/unit/validate-app.test.ts +527 -0
- package/README.md +34 -3
- package/bin/spine-framework.cjs +1 -0
- package/config/tailwind.config.cjs +7 -0
- package/config/tsconfig.functions.json +42 -0
- package/config/tsconfig.json +37 -9
- package/config/vite.config.ts +31 -2
- package/netlify.toml +31 -3
- package/package.json +46 -29
- package/scripts/assemble-frontend.sh +127 -44
- package/scripts/assemble-functions.sh +127 -29
- package/scripts/boundary-check.sh +6 -2
- package/scripts/build-manifest.sh +24 -68
- package/scripts/checksum-manifest.mts +345 -0
- package/scripts/dev-clean.sh +86 -0
- package/scripts/dev-netlify.sh +49 -0
- package/scripts/netlify-dev-wrapper.sh +2 -0
- package/scripts/verify-install.ts +358 -0
- package/scripts/verify-integrity.sh +21 -57
- package/scripts/verify-manifest.mts +305 -0
- package/templates/project/gitignore +45 -0
- package/{config → templates/project}/package-lock.json +22335 -9366
- package/vitest.config.ts +46 -0
- package/.framework/public/spine.config.json +0 -91
- package/config/deno.lock +0 -108
- package/config/tsconfig.node.tsbuildinfo +0 -1
- package/config/tsconfig.tsbuildinfo +0 -1
- package/config/vite.config.d.ts +0 -2
- package/custom/.devin/AGENT.md +0 -357
- package/custom/.devin/skills/install-app/SKILL.md +0 -39
- package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +0 -39
- package/custom/.devin/skills/spine-workbench-idea/SKILL.md +0 -36
- package/custom/.devin/skills/spine-workbench-implement/SKILL.md +0 -46
- package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +0 -28
- package/custom/.devin/skills/spine-workbench-plan/SKILL.md +0 -38
- package/custom/.devin/workflows/app-install.yaml +0 -83
- package/custom/README.md +0 -79
- package/docs/README.md +0 -15
- package/scripts/app-install-cli.ts +0 -286
- package/scripts/check-core-integrity.sh +0 -82
- package/scripts/ingest-chunks.cjs +0 -202
- package/scripts/kb-chunk-parser.cjs +0 -312
- package/scripts/kb-chunk-parser.ts +0 -330
- package/scripts/kb-ingest-docs.ts +0 -203
- package/scripts/load-test-app-install.ts +0 -484
- package/scripts/test-login.js +0 -33
- package/spine.config.json +0 -91
|
@@ -1,69 +1,33 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
|
-
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
#
|
|
2
|
+
# CIL[BEGIN stable_id="~/.framework/scripts/verify-integrity.sh:module:script" type="script" identity="verify-integrity" parent="~/.framework/scripts/verify-integrity.sh"]
|
|
3
|
+
# CIL[DOC-MACRO purpose="Thin wrapper that verifies protected trees against .spine-manifest.json via scripts/verify-manifest.mts"]
|
|
4
|
+
# CIL[DOC-RESPONSIBILITY responsibility="Map SPINE_INTEGRITY to verifier flags and invoke the Node verifier; fail closed by default"]
|
|
5
|
+
# CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/verify-manifest.mts,scripts/build-manifest.sh,scripts/check-core-integrity.sh,package.json"]
|
|
6
|
+
# CIL[DOC-CONTRACT inputs="SPINE_INTEGRITY=warn|enforce (default enforce); passthrough args" outputs="exit 0 pass / exit 1 integrity failure" errors="exit 1 on missing tsx or verifier failure" side_effects="stdout/stderr report"]
|
|
7
|
+
# CIL[DOC-MICRO logic_summary="SPINE_INTEGRITY=warn passes --warn; the verifier itself ignores --warn when the manifest is frozen" notable_decisions="default is enforce — fail-closed — unlike the legacy warn-by-default script"]
|
|
8
|
+
# CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
|
|
9
|
+
# CIL[DOC-STABILITY stability="stable"]
|
|
10
|
+
# CIL[DOC-AUDIENCE audience="system-admin"]
|
|
11
|
+
# CIL[DOC-VECTOR type="context" content="Invoked by npm run verify and the retired check-core-integrity.sh shim"]
|
|
12
|
+
# CIL[DOC-VECTOR type="implementation_pattern" content="Sibling thin wrapper of build-manifest.sh; real logic in scripts/verify-manifest.mts" status="ready"]
|
|
13
|
+
# CIL[END stable_id="~/.framework/scripts/verify-integrity.sh:module:script"]
|
|
6
14
|
|
|
7
15
|
set -euo pipefail
|
|
8
16
|
|
|
9
17
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
10
18
|
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
11
|
-
MANIFEST_FILE="$PROJECT_ROOT/.spine-manifest.json"
|
|
12
19
|
|
|
13
|
-
INTEGRITY_MODE="${SPINE_INTEGRITY:-
|
|
20
|
+
INTEGRITY_MODE="${SPINE_INTEGRITY:-enforce}"
|
|
21
|
+
echo "🔒 Verifying spine integrity (mode: $INTEGRITY_MODE)"
|
|
14
22
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
exit
|
|
19
|
-
fi
|
|
20
|
-
|
|
21
|
-
echo "🔒 Verifying core integrity (mode: $INTEGRITY_MODE)"
|
|
22
|
-
|
|
23
|
-
MISMATCHES=0
|
|
24
|
-
MISSING=0
|
|
25
|
-
|
|
26
|
-
# Parse each file:hash pair from manifest
|
|
27
|
-
while IFS=: read -r file_path expected_hash; do
|
|
28
|
-
# Strip quotes and whitespace
|
|
29
|
-
file_path=$(echo "$file_path" | tr -d '"' | xargs)
|
|
30
|
-
expected_hash=$(echo "$expected_hash" | tr -d '"' | xargs)
|
|
31
|
-
|
|
32
|
-
FULL_PATH="$PROJECT_ROOT/$file_path"
|
|
33
|
-
|
|
34
|
-
if [ ! -f "$FULL_PATH" ]; then
|
|
35
|
-
echo " ✗ MISSING: $file_path"
|
|
36
|
-
MISSING=$((MISSING + 1))
|
|
37
|
-
continue
|
|
38
|
-
fi
|
|
39
|
-
|
|
40
|
-
ACTUAL_HASH=$(shasum -a 256 "$FULL_PATH" | cut -d' ' -f1)
|
|
41
|
-
|
|
42
|
-
if [ "$ACTUAL_HASH" != "$expected_hash" ]; then
|
|
43
|
-
echo " ✗ MODIFIED: $file_path"
|
|
44
|
-
MISMATCHES=$((MISMATCHES + 1))
|
|
45
|
-
fi
|
|
46
|
-
done < <(cat "$MANIFEST_FILE" | python3 -c "
|
|
47
|
-
import json, sys
|
|
48
|
-
data = json.load(sys.stdin)
|
|
49
|
-
for k, v in data.get('hashes', {}).items():
|
|
50
|
-
print(f'{k}:{v}')
|
|
51
|
-
" 2>/dev/null || echo "")
|
|
52
|
-
|
|
53
|
-
TOTAL=$((MISMATCHES + MISSING))
|
|
54
|
-
|
|
55
|
-
if [ "$TOTAL" -eq 0 ]; then
|
|
56
|
-
echo "✅ All core files match manifest"
|
|
57
|
-
exit 0
|
|
23
|
+
TSX="$PROJECT_ROOT/node_modules/.bin/tsx"
|
|
24
|
+
if [ ! -x "$TSX" ]; then
|
|
25
|
+
echo "❌ tsx not found at $TSX — run 'npm install' first" >&2
|
|
26
|
+
exit 1
|
|
58
27
|
fi
|
|
59
28
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
if [ "$INTEGRITY_MODE" = "enforce" ]; then
|
|
64
|
-
echo "❌ Build failed: core integrity check failed (SPINE_INTEGRITY=enforce)"
|
|
65
|
-
exit 1
|
|
29
|
+
if [ "$INTEGRITY_MODE" = "warn" ]; then
|
|
30
|
+
"$TSX" "$SCRIPT_DIR/verify-manifest.mts" "$PROJECT_ROOT" --warn "$@"
|
|
66
31
|
else
|
|
67
|
-
|
|
68
|
-
exit 0
|
|
32
|
+
"$TSX" "$SCRIPT_DIR/verify-manifest.mts" "$PROJECT_ROOT" "$@"
|
|
69
33
|
fi
|
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
// CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/scripts/verify-manifest.mts"]
|
|
2
|
+
// CIL[DOC-MACRO purpose="Fail-closed verifier for .spine-manifest.json — detects missing, modified, and extra files in protected trees"]
|
|
3
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Parse the manifest, re-hash every listed path, confine symlinks to the root, and flag unlisted additions; exit 1 with an itemized failure list"]
|
|
4
|
+
// CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/checksum-manifest.mts,scripts/verify-integrity.sh,scripts/check-core-integrity.sh"]
|
|
5
|
+
// CIL[DOC-CONTRACT inputs="argv: <root> [--warn]" outputs="exit 0 pass / exit 1 with itemized failures (or 0 when --warn and manifest is not frozen)" errors="exit 1 on missing/malformed/empty manifest" side_effects="stdout/stderr report"]
|
|
6
|
+
// CIL[DOC-MICRO logic_summary="Shares enumeration and hashing with checksum-manifest.mts so generated and verified views can never drift" notable_decisions="frozen manifests ignore --warn entirely — warn mode is for dev regeneration only, never for frozen exports"]
|
|
7
|
+
// CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
|
|
8
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
9
|
+
// CIL[DOC-AUDIENCE audience="system-admin"]
|
|
10
|
+
// CIL[DOC-NOTE type="design" content="Extra-file check unions PROTECTED_DIRS with the top-level dirs actually present in the manifest so manifests generated with --include-dir still verify correctly"]
|
|
11
|
+
// CIL[DOC-VECTOR type="context" content="Invoked by npm run verify (scripts/verify-integrity.sh) and the retired scripts/check-core-integrity.sh shim"]
|
|
12
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="Imports collectProtectedFiles/hashEntry/topLevelDir from ./checksum-manifest.mts" status="ready"]
|
|
13
|
+
// CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:module_header:module_header"]
|
|
14
|
+
|
|
15
|
+
import * as fs from 'node:fs'
|
|
16
|
+
import * as path from 'node:path'
|
|
17
|
+
import {
|
|
18
|
+
PROTECTED_DIRS,
|
|
19
|
+
collectProtectedFiles,
|
|
20
|
+
computeTreeDigest,
|
|
21
|
+
hashEntry,
|
|
22
|
+
topLevelDir,
|
|
23
|
+
} from './checksum-manifest.mts'
|
|
24
|
+
|
|
25
|
+
// CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:Failure:interface" type="interface" identity="Failure" parent="~/.framework/scripts/verify-manifest.mts"]
|
|
26
|
+
// CIL[DOC-MACRO purpose="One itemized integrity failure"]
|
|
27
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Carry a failure kind plus the manifest-relative path it concerns"]
|
|
28
|
+
// CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/verify-manifest.mts"]
|
|
29
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
|
|
30
|
+
// CIL[DOC-MICRO logic_summary="kind is one of MISSING, MODIFIED, EXTRA, UNSAFE_SYMLINK, TYPE_CHANGED, MALFORMED_ENTRY, MANIFEST_DIGEST_MISMATCH" notable_decisions="kept as a tagged union string so printing stays trivially itemizable"]
|
|
31
|
+
// CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
|
|
32
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
33
|
+
interface Failure {
|
|
34
|
+
kind:
|
|
35
|
+
| 'MISSING'
|
|
36
|
+
| 'MODIFIED'
|
|
37
|
+
| 'EXTRA'
|
|
38
|
+
| 'UNSAFE_SYMLINK'
|
|
39
|
+
| 'TYPE_CHANGED'
|
|
40
|
+
| 'MALFORMED_ENTRY'
|
|
41
|
+
| 'MANIFEST_DIGEST_MISMATCH'
|
|
42
|
+
rel: string
|
|
43
|
+
}
|
|
44
|
+
// CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:Failure:interface"]
|
|
45
|
+
|
|
46
|
+
// CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:HASH_RE:constant" type="constant" identity="HASH_RE" parent="~/.framework/scripts/verify-manifest.mts"]
|
|
47
|
+
// CIL[DOC-MACRO purpose="Strict shape for manifest hash values"]
|
|
48
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Reject malformed 'sha256:<64 hex>' entries before comparing"]
|
|
49
|
+
// CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/checksum-manifest.mts"]
|
|
50
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="RegExp" errors="none" side_effects="none"]
|
|
51
|
+
// CIL[DOC-MICRO logic_summary="Lowercase hex only — matches what node:crypto sha256 digest produces" notable_decisions="manifest is machine-generated; strictness catches hand edits"]
|
|
52
|
+
// CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
|
|
53
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
54
|
+
const HASH_RE = /^sha256:[0-9a-f]{64}$/
|
|
55
|
+
// CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:HASH_RE:constant"]
|
|
56
|
+
|
|
57
|
+
// CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:isInsideRoot:function" type="function" identity="isInsideRoot" parent="~/.framework/scripts/verify-manifest.mts"]
|
|
58
|
+
// CIL[DOC-MACRO purpose="Confinement check — is a resolved path still inside the root?"]
|
|
59
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Return true when the resolved real path equals the root or sits beneath it"]
|
|
60
|
+
// CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/verify-manifest.mts"]
|
|
61
|
+
// CIL[DOC-CONTRACT inputs="rootAbs, resolved absolute path" outputs="boolean" errors="none" side_effects="none"]
|
|
62
|
+
// CIL[DOC-MICRO logic_summary="path.relative trick: outside paths yield '..' prefixes or absolute results" notable_decisions="boundary-safe — a sibling dir sharing a prefix like /root-evil does not pass"]
|
|
63
|
+
// CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
|
|
64
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
65
|
+
function isInsideRoot(rootAbs: string, resolved: string): boolean {
|
|
66
|
+
const rel = path.relative(rootAbs, resolved)
|
|
67
|
+
return rel === '' || (!rel.startsWith('..') && !path.isAbsolute(rel))
|
|
68
|
+
}
|
|
69
|
+
// CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:isInsideRoot:function"]
|
|
70
|
+
|
|
71
|
+
// CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:loadManifest:function" type="function" identity="loadManifest" parent="~/.framework/scripts/verify-manifest.mts"]
|
|
72
|
+
// CIL[DOC-MACRO purpose="Read and structurally validate .spine-manifest.json"]
|
|
73
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Fail closed on missing, unreadable, non-JSON, empty, or wrong-format manifest; return the parsed files map"]
|
|
74
|
+
// CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/checksum-manifest.mts"]
|
|
75
|
+
// CIL[DOC-CONTRACT inputs="manifestPath: absolute path" outputs="{ manifest, files } — parsed manifest plus its files record" errors="prints reason and exits 1 on any defect" side_effects="reads manifest file"]
|
|
76
|
+
// CIL[DOC-MICRO logic_summary="Structural checks: object root, format_version === 1, files is a non-empty object" notable_decisions="an empty files map is treated as malformed — a manifest that protects nothing is not a manifest"]
|
|
77
|
+
// CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
|
|
78
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
79
|
+
function loadManifest(manifestPath: string): { manifest: Record<string, unknown>; files: Record<string, string> } {
|
|
80
|
+
if (!fs.existsSync(manifestPath)) {
|
|
81
|
+
console.error(`❌ manifest not found: ${manifestPath}`)
|
|
82
|
+
console.error(' run npm run manifest to generate it')
|
|
83
|
+
process.exit(1)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
let raw: string
|
|
87
|
+
try {
|
|
88
|
+
raw = fs.readFileSync(manifestPath, 'utf8')
|
|
89
|
+
} catch (err) {
|
|
90
|
+
console.error(`❌ manifest unreadable: ${(err as Error).message}`)
|
|
91
|
+
process.exit(1)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (raw.trim() === '') {
|
|
95
|
+
console.error(`❌ manifest is empty: ${manifestPath}`)
|
|
96
|
+
process.exit(1)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let manifest: Record<string, unknown>
|
|
100
|
+
try {
|
|
101
|
+
manifest = JSON.parse(raw)
|
|
102
|
+
} catch (err) {
|
|
103
|
+
console.error(`❌ manifest is not valid JSON: ${(err as Error).message}`)
|
|
104
|
+
process.exit(1)
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (manifest === null || typeof manifest !== 'object' || Array.isArray(manifest)) {
|
|
108
|
+
console.error('❌ manifest root is not an object')
|
|
109
|
+
process.exit(1)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (manifest.format_version !== 1) {
|
|
113
|
+
console.error(`❌ unknown manifest format_version: ${JSON.stringify(manifest.format_version)} (expected 1)`)
|
|
114
|
+
process.exit(1)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const files = manifest.files
|
|
118
|
+
if (files === null || typeof files !== 'object' || Array.isArray(files) || Object.keys(files).length === 0) {
|
|
119
|
+
console.error('❌ manifest declares no files — nothing to verify')
|
|
120
|
+
process.exit(1)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return { manifest, files: files as Record<string, string> }
|
|
124
|
+
}
|
|
125
|
+
// CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:loadManifest:function"]
|
|
126
|
+
|
|
127
|
+
// CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:verifyListedFiles:function" type="function" identity="verifyListedFiles" parent="~/.framework/scripts/verify-manifest.mts"]
|
|
128
|
+
// CIL[DOC-MACRO purpose="Re-hash every manifest-listed path and classify failures"]
|
|
129
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Check each listed path exists, is confined to the root when a symlink, and still matches its stored sha256"]
|
|
130
|
+
// CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/checksum-manifest.mts"]
|
|
131
|
+
// CIL[DOC-CONTRACT inputs="rootAbs, files map" outputs="Failure[]" errors="none — failures collected, not thrown" side_effects="reads every listed file"]
|
|
132
|
+
// CIL[DOC-MICRO logic_summary="lstat distinguishes symlink/file/dir; symlink targets are realpath'd and confined; type changes count as failures" notable_decisions="hash order follows byte-sorted keys for a stable, greppable report"]
|
|
133
|
+
// CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
|
|
134
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
135
|
+
function verifyListedFiles(rootAbs: string, files: Record<string, string>): Failure[] {
|
|
136
|
+
const failures: Failure[] = []
|
|
137
|
+
const rels = Object.keys(files).sort((a, b) =>
|
|
138
|
+
Buffer.compare(Buffer.from(a, 'utf8'), Buffer.from(b, 'utf8')),
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
for (const rel of rels) {
|
|
142
|
+
const expected = files[rel]
|
|
143
|
+
const abs = path.join(rootAbs, rel)
|
|
144
|
+
|
|
145
|
+
if (!HASH_RE.test(expected)) {
|
|
146
|
+
failures.push({ kind: 'MALFORMED_ENTRY', rel })
|
|
147
|
+
continue
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
let st: fs.Stats
|
|
151
|
+
try {
|
|
152
|
+
st = fs.lstatSync(abs)
|
|
153
|
+
} catch {
|
|
154
|
+
failures.push({ kind: 'MISSING', rel })
|
|
155
|
+
continue
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (st.isSymbolicLink()) {
|
|
159
|
+
let resolved: string
|
|
160
|
+
try {
|
|
161
|
+
resolved = fs.realpathSync(abs)
|
|
162
|
+
} catch {
|
|
163
|
+
failures.push({ kind: 'UNSAFE_SYMLINK', rel })
|
|
164
|
+
continue
|
|
165
|
+
}
|
|
166
|
+
if (!isInsideRoot(rootAbs, resolved)) {
|
|
167
|
+
failures.push({ kind: 'UNSAFE_SYMLINK', rel })
|
|
168
|
+
continue
|
|
169
|
+
}
|
|
170
|
+
if (hashEntry({ rel, abs, symlink: true }) !== expected) {
|
|
171
|
+
failures.push({ kind: 'MODIFIED', rel })
|
|
172
|
+
}
|
|
173
|
+
continue
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
if (!st.isFile()) {
|
|
177
|
+
failures.push({ kind: 'TYPE_CHANGED', rel })
|
|
178
|
+
continue
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (hashEntry({ rel, abs, symlink: false }) !== expected) {
|
|
182
|
+
failures.push({ kind: 'MODIFIED', rel })
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return failures
|
|
187
|
+
}
|
|
188
|
+
// CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:verifyListedFiles:function"]
|
|
189
|
+
|
|
190
|
+
// CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:findExtraFiles:function" type="function" identity="findExtraFiles" parent="~/.framework/scripts/verify-manifest.mts"]
|
|
191
|
+
// CIL[DOC-MACRO purpose="Reject unlisted additions inside protected trees"]
|
|
192
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Enumerate the same trees the generator covered (defaults plus any top-level dirs present in the manifest) and flag anything not in the files map"]
|
|
193
|
+
// CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/checksum-manifest.mts"]
|
|
194
|
+
// CIL[DOC-CONTRACT inputs="rootAbs, manifestRel, files map" outputs="Failure[]" errors="none" side_effects="reads filesystem"]
|
|
195
|
+
// CIL[DOC-MICRO logic_summary="Shared collectProtectedFiles keeps exclusion rules identical between generate and verify; the manifest's own path is excluded" notable_decisions="manifest top-level dirs are unioned in so --include-dir manifests verify without extra flags"]
|
|
196
|
+
// CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
|
|
197
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
198
|
+
function findExtraFiles(rootAbs: string, manifestRel: string, files: Record<string, string>): Failure[] {
|
|
199
|
+
const trees = new Set<string>(PROTECTED_DIRS)
|
|
200
|
+
for (const rel of Object.keys(files)) {
|
|
201
|
+
const top = topLevelDir(rel)
|
|
202
|
+
if (top) trees.add(top)
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const extraDirs = [...trees].filter((d) => !PROTECTED_DIRS.includes(d))
|
|
206
|
+
const present = collectProtectedFiles(rootAbs, extraDirs, new Set([manifestRel]))
|
|
207
|
+
|
|
208
|
+
const failures: Failure[] = []
|
|
209
|
+
for (const entry of present) {
|
|
210
|
+
if (!(entry.rel in files)) failures.push({ kind: 'EXTRA', rel: entry.rel })
|
|
211
|
+
}
|
|
212
|
+
return failures
|
|
213
|
+
}
|
|
214
|
+
// CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:findExtraFiles:function"]
|
|
215
|
+
|
|
216
|
+
// CIL[BEGIN stable_id="~/.framework/scripts/verify-manifest.mts:main:function" type="function" identity="main" parent="~/.framework/scripts/verify-manifest.mts"]
|
|
217
|
+
// CIL[DOC-MACRO purpose="CLI entry — load manifest, run all checks, print itemized report"]
|
|
218
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Wire parsing, digest consistency, listed-file verification, and extra-file detection; map --warn vs frozen to exit codes"]
|
|
219
|
+
// CIL[DOC-CONTEXT module="spine-integrity" layer="build" related_files="scripts/verify-integrity.sh,package.json"]
|
|
220
|
+
// CIL[DOC-CONTRACT inputs="argv: <root> [--warn]" outputs="exit 0 pass; exit 1 on failures (exit 0 with warnings only when --warn AND frozen !== true)" errors="exit 1 hard on manifest defects" side_effects="stdout report"]
|
|
221
|
+
// CIL[DOC-MICRO logic_summary="frozen:true ignores --warn entirely per plan G15 — frozen exports may never downgrade a failure to a warning" notable_decisions="tree_digest is recomputed for self-consistency; mismatch means the files map was edited after generation"]
|
|
222
|
+
// CIL[DOC-CONFIDENCE pass="first" score="0.9" flags="none"]
|
|
223
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
224
|
+
function main(): void {
|
|
225
|
+
const args = process.argv.slice(2)
|
|
226
|
+
const positional: string[] = []
|
|
227
|
+
let warnRequested = false
|
|
228
|
+
|
|
229
|
+
for (const arg of args) {
|
|
230
|
+
if (arg === '--warn') {
|
|
231
|
+
warnRequested = true
|
|
232
|
+
} else if (arg.startsWith('--')) {
|
|
233
|
+
console.error(`verify-manifest: unknown flag ${arg}`)
|
|
234
|
+
process.exit(2)
|
|
235
|
+
} else {
|
|
236
|
+
positional.push(arg)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (positional.length !== 1) {
|
|
241
|
+
console.error('usage: verify-manifest.mts <root> [--warn]')
|
|
242
|
+
process.exit(2)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
const root = path.resolve(positional[0])
|
|
246
|
+
const manifestRel = '.spine-manifest.json'
|
|
247
|
+
const { manifest, files } = loadManifest(path.join(root, manifestRel))
|
|
248
|
+
const frozen = manifest.frozen === true
|
|
249
|
+
const warnEffective = warnRequested && !frozen
|
|
250
|
+
|
|
251
|
+
console.log(`🔒 Verifying spine integrity (frozen: ${frozen}, warn: ${warnEffective})`)
|
|
252
|
+
|
|
253
|
+
const failures: Failure[] = []
|
|
254
|
+
|
|
255
|
+
// Self-consistency: tree_digest must match a recompute over the files map.
|
|
256
|
+
if (typeof manifest.tree_digest === 'string') {
|
|
257
|
+
const pairs = Object.keys(files)
|
|
258
|
+
.sort((a, b) => Buffer.compare(Buffer.from(a, 'utf8'), Buffer.from(b, 'utf8')))
|
|
259
|
+
.map((rel) => [rel, files[rel]] as const)
|
|
260
|
+
if (computeTreeDigest(pairs) !== manifest.tree_digest) {
|
|
261
|
+
failures.push({ kind: 'MANIFEST_DIGEST_MISMATCH', rel: manifestRel })
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const rootAbs = path.resolve(root)
|
|
266
|
+
failures.push(...verifyListedFiles(rootAbs, files))
|
|
267
|
+
failures.push(...findExtraFiles(rootAbs, manifestRel, files))
|
|
268
|
+
|
|
269
|
+
if (failures.length === 0) {
|
|
270
|
+
console.log(`✅ All ${Object.keys(files).length} protected files match manifest`)
|
|
271
|
+
process.exit(0)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
for (const f of failures) {
|
|
275
|
+
const detail =
|
|
276
|
+
f.kind === 'MISSING'
|
|
277
|
+
? 'listed in manifest but not on disk'
|
|
278
|
+
: f.kind === 'MODIFIED'
|
|
279
|
+
? 'hash mismatch — file changed since manifest was generated'
|
|
280
|
+
: f.kind === 'EXTRA'
|
|
281
|
+
? 'present in protected tree but not listed in manifest'
|
|
282
|
+
: f.kind === 'UNSAFE_SYMLINK'
|
|
283
|
+
? 'symlink target escapes the project root'
|
|
284
|
+
: f.kind === 'TYPE_CHANGED'
|
|
285
|
+
? 'path exists but is no longer a regular file'
|
|
286
|
+
: f.kind === 'MALFORMED_ENTRY'
|
|
287
|
+
? 'manifest hash value is not sha256:<64 hex>'
|
|
288
|
+
: 'tree_digest does not match the files map'
|
|
289
|
+
console.error(` ✗ ${f.kind}: ${f.rel} — ${detail}`)
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
console.error(`\n❌ ${failures.length} integrity failure(s)`)
|
|
293
|
+
|
|
294
|
+
if (warnEffective) {
|
|
295
|
+
console.error('⚠️ continuing with warnings (SPINE_INTEGRITY=warn, manifest not frozen)')
|
|
296
|
+
process.exit(0)
|
|
297
|
+
}
|
|
298
|
+
if (warnRequested && frozen) {
|
|
299
|
+
console.error(' (frozen manifest — --warn ignored)')
|
|
300
|
+
}
|
|
301
|
+
process.exit(1)
|
|
302
|
+
}
|
|
303
|
+
// CIL[END stable_id="~/.framework/scripts/verify-manifest.mts:main:function"]
|
|
304
|
+
|
|
305
|
+
main()
|
|
@@ -15,13 +15,19 @@
|
|
|
15
15
|
"data_type": "select",
|
|
16
16
|
"label": "Source",
|
|
17
17
|
"required": true,
|
|
18
|
-
"options": [
|
|
18
|
+
"options": [
|
|
19
|
+
"use"
|
|
20
|
+
]
|
|
19
21
|
},
|
|
20
22
|
"stage": {
|
|
21
23
|
"data_type": "select",
|
|
22
24
|
"label": "Stage",
|
|
23
25
|
"required": true,
|
|
24
|
-
"options": [
|
|
26
|
+
"options": [
|
|
27
|
+
"installed",
|
|
28
|
+
"claimed",
|
|
29
|
+
"active"
|
|
30
|
+
]
|
|
25
31
|
},
|
|
26
32
|
"action_type": {
|
|
27
33
|
"data_type": "text",
|
|
@@ -39,10 +45,9 @@
|
|
|
39
45
|
"required": true
|
|
40
46
|
},
|
|
41
47
|
"app_slug": {
|
|
42
|
-
"data_type": "
|
|
48
|
+
"data_type": "text",
|
|
43
49
|
"label": "App",
|
|
44
|
-
"required": false
|
|
45
|
-
"options": ["framework", "cortex", "portal"]
|
|
50
|
+
"required": false
|
|
46
51
|
},
|
|
47
52
|
"app_version": {
|
|
48
53
|
"data_type": "text",
|
|
@@ -56,11 +61,26 @@
|
|
|
56
61
|
"display": "table",
|
|
57
62
|
"label": "Usage Signals",
|
|
58
63
|
"fields": {
|
|
59
|
-
"title": {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
+
"title": {
|
|
65
|
+
"sortable": true,
|
|
66
|
+
"display_type": "text"
|
|
67
|
+
},
|
|
68
|
+
"action_type": {
|
|
69
|
+
"sortable": true,
|
|
70
|
+
"display_type": "badge"
|
|
71
|
+
},
|
|
72
|
+
"stage": {
|
|
73
|
+
"sortable": true,
|
|
74
|
+
"display_type": "badge"
|
|
75
|
+
},
|
|
76
|
+
"serial": {
|
|
77
|
+
"sortable": true,
|
|
78
|
+
"display_type": "text"
|
|
79
|
+
},
|
|
80
|
+
"created_at": {
|
|
81
|
+
"sortable": true,
|
|
82
|
+
"display_type": "timestamp"
|
|
83
|
+
}
|
|
64
84
|
}
|
|
65
85
|
},
|
|
66
86
|
"default_detail": {
|
|
@@ -70,28 +90,61 @@
|
|
|
70
90
|
{
|
|
71
91
|
"title": "Signal",
|
|
72
92
|
"fields": {
|
|
73
|
-
"action_type": {
|
|
74
|
-
|
|
75
|
-
|
|
93
|
+
"action_type": {
|
|
94
|
+
"display_type": "input"
|
|
95
|
+
},
|
|
96
|
+
"action_value": {
|
|
97
|
+
"display_type": "input"
|
|
98
|
+
},
|
|
99
|
+
"stage": {
|
|
100
|
+
"display_type": "select"
|
|
101
|
+
}
|
|
76
102
|
}
|
|
77
103
|
},
|
|
78
104
|
{
|
|
79
105
|
"title": "Instance",
|
|
80
106
|
"fields": {
|
|
81
|
-
"serial": {
|
|
82
|
-
|
|
83
|
-
|
|
107
|
+
"serial": {
|
|
108
|
+
"display_type": "input"
|
|
109
|
+
},
|
|
110
|
+
"app_slug": {
|
|
111
|
+
"display_type": "select"
|
|
112
|
+
},
|
|
113
|
+
"app_version": {
|
|
114
|
+
"display_type": "input"
|
|
115
|
+
}
|
|
84
116
|
}
|
|
85
117
|
}
|
|
86
118
|
]
|
|
87
119
|
}
|
|
88
120
|
},
|
|
89
121
|
"record_permissions": {
|
|
90
|
-
"system_admin": [
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
122
|
+
"system_admin": [
|
|
123
|
+
"create",
|
|
124
|
+
"read",
|
|
125
|
+
"update",
|
|
126
|
+
"delete"
|
|
127
|
+
],
|
|
128
|
+
"support_admin": [
|
|
129
|
+
"create",
|
|
130
|
+
"read",
|
|
131
|
+
"update"
|
|
132
|
+
],
|
|
133
|
+
"support": [
|
|
134
|
+
"create",
|
|
135
|
+
"read",
|
|
136
|
+
"update"
|
|
137
|
+
],
|
|
138
|
+
"member_admin": [
|
|
139
|
+
"create",
|
|
140
|
+
"read",
|
|
141
|
+
"update"
|
|
142
|
+
],
|
|
143
|
+
"member": [
|
|
144
|
+
"create",
|
|
145
|
+
"read",
|
|
146
|
+
"update"
|
|
147
|
+
]
|
|
95
148
|
}
|
|
96
149
|
},
|
|
97
150
|
"validation_schema": {},
|