spine-framework 0.3.144 → 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 +20 -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,24 +1,26 @@
|
|
|
1
|
-
// CIL[BEGIN
|
|
2
|
-
// CIL[DOC-MACRO purpose="
|
|
3
|
-
// CIL[DOC-RESPONSIBILITY responsibility="
|
|
4
|
-
// CIL[DOC-CONTEXT module="
|
|
5
|
-
// CIL[DOC-CONTRACT inputs="
|
|
6
|
-
// CIL[DOC-MICRO logic_summary="
|
|
7
|
-
// CIL[DOC-CONFIDENCE pass="second" score="0.
|
|
1
|
+
// CIL[BEGIN stable_id="~/.framework/functions/cil-graph.ts:module_header:module_header" type="module_header" identity="module_header" parent="~/.framework/functions/cil-graph.ts"]
|
|
2
|
+
// CIL[DOC-MACRO purpose="Netlify function that exposes CIL chunk graph queries and search over the spine CIL index"]
|
|
3
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Serve callers, blast radius, file chunks, project graph, search, and graph diff for CIL"]
|
|
4
|
+
// CIL[DOC-CONTEXT module=".framework/functions" layer="functions" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/llm.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts"]
|
|
5
|
+
// CIL[DOC-CONTRACT inputs="HTTP action query parameter" outputs="JSON contract, graph, search results, or diff" errors="Unknown action or missing parameters" side_effects="Queries adminDb and link tables"]
|
|
6
|
+
// CIL[DOC-MICRO logic_summary="Creates a handler that dispatches to graph and search actions" notable_decisions="Uses Supabase RPC for vector search and link tables for edges"]
|
|
7
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
8
8
|
// CIL[DOC-STABILITY stability="stable"]
|
|
9
|
-
// CIL[DOC-AUDIENCE audience="
|
|
10
|
-
// CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, .framework/functions/_shared/schema-utils.ts, \."]
|
|
11
|
-
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
12
|
-
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
13
|
-
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
14
|
-
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
15
|
-
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
9
|
+
// CIL[DOC-AUDIENCE audience="spine-ia CIL pipeline and web UI"]
|
|
16
10
|
|
|
17
11
|
|
|
18
12
|
import { createHandler } from './_shared/middleware'
|
|
19
13
|
import { adminDb } from './_shared/db'
|
|
20
14
|
import { resolveLinkTypeId } from './_shared/resolve-ids'
|
|
21
15
|
import { callOpenAIEmbeddings } from './_shared/llm'
|
|
16
|
+
import { parseStableId } from './_shared/cil'
|
|
17
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Netlify function that exposes CIL chunk graph queries and search over the spine CIL index'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
|
|
18
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
19
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
20
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
21
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
22
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
23
|
+
// CIL[END stable_id="~/.framework/functions/cil-graph.ts:module_header:module_header"]
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
|
|
@@ -26,21 +28,70 @@ import { callOpenAIEmbeddings } from './_shared/llm'
|
|
|
26
28
|
|
|
27
29
|
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
// CIL[BEGIN
|
|
31
|
-
// CIL[DOC-MACRO purpose="
|
|
32
|
-
// CIL[DOC-RESPONSIBILITY responsibility="
|
|
33
|
-
// CIL[DOC-CONTEXT module="
|
|
34
|
-
// CIL[DOC-CONTRACT inputs="
|
|
35
|
-
// CIL[DOC-MICRO logic_summary="
|
|
36
|
-
// CIL[DOC-CONFIDENCE pass="second" score="0.
|
|
31
|
+
|
|
32
|
+
// CIL[BEGIN stable_id="~/.framework/functions/cil-graph.ts:resolveChunkByStableId:function" type="function" identity="resolveChunkByStableId" parent="~/.framework/functions/cil-graph.ts"]
|
|
33
|
+
// CIL[DOC-MACRO purpose="Resolve a CIL chunk record from the database by its stable_id and optional version"]
|
|
34
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Lookup chunk by stable_id, fallback to project active version when version_id omitted"]
|
|
35
|
+
// CIL[DOC-CONTEXT module=".framework/functions" layer="functions" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/llm.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/cil-graph.ts"]
|
|
36
|
+
// CIL[DOC-CONTRACT inputs="stableId: string, versionId?: string" outputs="chunk data or null" errors="Returns null when not found" side_effects="Reads items table via adminDb"]
|
|
37
|
+
// CIL[DOC-MICRO logic_summary="Parse stable_id, query any matching chunk, derive active version from project if needed, then query exact version" notable_decisions="Returns first match when no version supplied"]
|
|
38
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
37
39
|
// CIL[DOC-STABILITY stability="stable"]
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
async function resolveChunkByStableId(stableId: string, versionId?: string): Promise<any | null> {
|
|
41
|
+
const parsed = parseStableId(stableId)
|
|
42
|
+
if (!parsed) return null
|
|
43
|
+
|
|
44
|
+
let effectiveVersionId = versionId
|
|
45
|
+
if (!effectiveVersionId) {
|
|
46
|
+
const { data: anyChunk } = await adminDb
|
|
47
|
+
.from('items')
|
|
48
|
+
.select('id, data')
|
|
49
|
+
.filter('data->>kb_type', 'eq', 'cil_chunk')
|
|
50
|
+
.filter('data->>stable_id', 'eq', stableId)
|
|
51
|
+
.maybeSingle()
|
|
52
|
+
|
|
53
|
+
if (!anyChunk) return null
|
|
54
|
+
const projectId = anyChunk.data?.project_id
|
|
55
|
+
if (projectId) {
|
|
56
|
+
const { data: project } = await adminDb
|
|
57
|
+
.from('items')
|
|
58
|
+
.select('id, data')
|
|
59
|
+
.eq('id', projectId)
|
|
60
|
+
.filter('data->>kb_type', 'eq', 'cil_project')
|
|
61
|
+
.maybeSingle()
|
|
62
|
+
|
|
63
|
+
effectiveVersionId = project?.data?.active_version_id
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let q = adminDb
|
|
68
|
+
.from('items')
|
|
69
|
+
.select('id, title, data')
|
|
70
|
+
.filter('data->>kb_type', 'eq', 'cil_chunk')
|
|
71
|
+
.filter('data->>stable_id', 'eq', stableId)
|
|
72
|
+
|
|
73
|
+
if (effectiveVersionId) {
|
|
74
|
+
q = q.filter('data->>version_id', 'eq', effectiveVersionId)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const { data } = await q.maybeSingle()
|
|
78
|
+
return data
|
|
79
|
+
}
|
|
80
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Resolve a CIL chunk record from the database by its stable_id and optional version'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
|
|
81
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
82
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
83
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
42
84
|
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
43
85
|
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
86
|
+
// CIL[END stable_id="~/.framework/functions/cil-graph.ts:resolveChunkByStableId:function"]
|
|
87
|
+
// CIL[BEGIN stable_id="~/.framework/functions/cil-graph.ts:ChunkContract:interface" type="interface" identity="ChunkContract" parent="~/.framework/functions/cil-graph.ts"]
|
|
88
|
+
// CIL[DOC-MACRO purpose="TypeScript contract describing a CIL chunk record for the graph API"]
|
|
89
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Define the shape and field set returned by get_chunk_contract"]
|
|
90
|
+
// CIL[DOC-CONTEXT module=".framework/functions" layer="types" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/llm.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/cil-graph.ts"]
|
|
91
|
+
// CIL[DOC-CONTRACT inputs="N/A" outputs="Interface fields for chunk metadata and edges" errors="N/A" side_effects="N/A"]
|
|
92
|
+
// CIL[DOC-MICRO logic_summary="Declares all scalar and edge fields for a CIL chunk" notable_decisions="Uses string or null types for optional paths and version"]
|
|
93
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
94
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
44
95
|
interface ChunkContract {
|
|
45
96
|
id: string
|
|
46
97
|
chunk_name: string
|
|
@@ -60,10 +111,19 @@ interface ChunkContract {
|
|
|
60
111
|
boundary_confidence: string
|
|
61
112
|
stored_hash: string | null
|
|
62
113
|
hash_status: 'current' | 'drift_detected' | 'unknown'
|
|
114
|
+
content_hash: string | null
|
|
115
|
+
version_id: string | null
|
|
63
116
|
callers: { chunk_id: string; chunk_name: string; file_path: string }[]
|
|
64
117
|
callees: { chunk_id: string; chunk_name: string; file_path: string }[]
|
|
65
118
|
is_dead_code: boolean
|
|
66
119
|
}
|
|
120
|
+
// CIL[DOC-VECTOR type="context" content="purpose='TypeScript contract describing a CIL chunk record for the graph API'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
|
|
121
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
122
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
123
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
124
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
125
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
126
|
+
// CIL[END stable_id="~/.framework/functions/cil-graph.ts:ChunkContract:interface"]
|
|
67
127
|
|
|
68
128
|
|
|
69
129
|
|
|
@@ -71,22 +131,21 @@ interface ChunkContract {
|
|
|
71
131
|
|
|
72
132
|
|
|
73
133
|
|
|
74
|
-
// CIL[
|
|
75
|
-
// CIL[
|
|
76
|
-
// CIL[DOC-
|
|
77
|
-
// CIL[DOC-
|
|
78
|
-
// CIL[DOC-
|
|
79
|
-
// CIL[DOC-
|
|
80
|
-
// CIL[DOC-
|
|
81
|
-
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
134
|
+
// CIL[BEGIN stable_id="~/.framework/functions/cil-graph.ts:getChunkById:function" type="function" identity="getChunkById" parent="~/.framework/functions/cil-graph.ts"]
|
|
135
|
+
// CIL[DOC-MACRO purpose="Fetch a single chunk by id, title, or chunk_name, with optional stable_id and version fallback"]
|
|
136
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Resolve chunk identifier to record using multiple lookup strategies"]
|
|
137
|
+
// CIL[DOC-CONTEXT module=".framework/functions" layer="functions" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/llm.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/cil-graph.ts"]
|
|
138
|
+
// CIL[DOC-CONTRACT inputs="chunkId: string, stableId?: string, versionId?: string" outputs="chunk data or null" errors="Returns null when not found" side_effects="Reads active items table"]
|
|
139
|
+
// CIL[DOC-MICRO logic_summary="Try stable_id resolution, then id, title, and chunk_name lookups" notable_decisions="Short-circuits on stable_id before trying other keys"]
|
|
140
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
82
141
|
// CIL[DOC-STABILITY stability="stable"]
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
142
|
+
async function getChunkById(chunkId: string, stableId?: string, versionId?: string): Promise<any | null> {
|
|
143
|
+
if (stableId) {
|
|
144
|
+
const chunk = await resolveChunkByStableId(stableId, versionId)
|
|
145
|
+
if (chunk) return chunk
|
|
146
|
+
return null
|
|
147
|
+
}
|
|
148
|
+
|
|
90
149
|
const { data: byId } = await adminDb
|
|
91
150
|
.from('items')
|
|
92
151
|
.select('id, title, data')
|
|
@@ -112,37 +171,42 @@ async function getChunkById(chunkId: string): Promise<any | null> {
|
|
|
112
171
|
.maybeSingle()
|
|
113
172
|
return byChunkName
|
|
114
173
|
}
|
|
174
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Fetch a single chunk by id, title, or chunk_name, with optional stable_id and version fallback'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
|
|
175
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
176
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
177
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
178
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
179
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
180
|
+
// CIL[END stable_id="~/.framework/functions/cil-graph.ts:getChunkById:function"]
|
|
115
181
|
|
|
116
182
|
|
|
117
183
|
|
|
118
184
|
|
|
119
185
|
|
|
120
|
-
// CIL[
|
|
121
|
-
// CIL[
|
|
122
|
-
// CIL[DOC-
|
|
123
|
-
// CIL[DOC-
|
|
124
|
-
// CIL[DOC-
|
|
125
|
-
// CIL[DOC-
|
|
126
|
-
// CIL[DOC-
|
|
127
|
-
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
186
|
+
// CIL[BEGIN stable_id="~/.framework/functions/cil-graph.ts:getLinkedChunks:function" type="function" identity="getLinkedChunks" parent="~/.framework/functions/cil-graph.ts"]
|
|
187
|
+
// CIL[DOC-MACRO purpose="Retrieve caller or callee chunks for a given chunk via the cil_calls link type"]
|
|
188
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Resolve link type, query links, then map target/source ids to chunk metadata"]
|
|
189
|
+
// CIL[DOC-CONTEXT module=".framework/functions" layer="functions" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/llm.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/cil-graph.ts"]
|
|
190
|
+
// CIL[DOC-CONTRACT inputs="chunkId: string, linkTypeSlug: string, direction: callers|callees, versionId?: string" outputs="Array of chunk_id, chunk_name, file_path" errors="Returns empty array on link-type resolution failure" side_effects="Reads links and items tables"]
|
|
191
|
+
// CIL[DOC-MICRO logic_summary="Resolve link type, filter by version, collect ids, then map linked chunks" notable_decisions="Swallows exceptions and returns empty list on errors"]
|
|
192
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
128
193
|
// CIL[DOC-STABILITY stability="stable"]
|
|
129
|
-
// CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/functions/custom_cil-embeddings.ts, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/pages/admin/IntegrationsPage.tsx, \."]
|
|
130
|
-
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
131
|
-
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
132
|
-
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
133
|
-
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
134
|
-
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
135
194
|
async function getLinkedChunks(
|
|
136
195
|
chunkId: string,
|
|
137
196
|
linkTypeSlug: string,
|
|
138
|
-
direction: 'callers' | 'callees'
|
|
197
|
+
direction: 'callers' | 'callees',
|
|
198
|
+
versionId?: string
|
|
139
199
|
): Promise<{ chunk_id: string; chunk_name: string; file_path: string }[]> {
|
|
140
200
|
try {
|
|
141
201
|
const linkTypeId = await resolveLinkTypeId(linkTypeSlug)
|
|
142
202
|
|
|
143
|
-
|
|
144
|
-
? adminDb.from('links').select('target_id').eq('source_id', chunkId).eq('link_type_id', linkTypeId)
|
|
145
|
-
: adminDb.from('links').select('source_id').eq('target_id', chunkId).eq('link_type_id', linkTypeId)
|
|
203
|
+
let query = direction === 'callees'
|
|
204
|
+
? adminDb.from('links').select('target_id, metadata').eq('source_id', chunkId).eq('link_type_id', linkTypeId)
|
|
205
|
+
: adminDb.from('links').select('source_id, metadata').eq('target_id', chunkId).eq('link_type_id', linkTypeId)
|
|
206
|
+
|
|
207
|
+
if (versionId) {
|
|
208
|
+
query = query.filter('metadata->>version_id', 'eq', versionId)
|
|
209
|
+
}
|
|
146
210
|
|
|
147
211
|
const { data: links } = await query
|
|
148
212
|
if (!links || links.length === 0) return []
|
|
@@ -165,6 +229,13 @@ async function getLinkedChunks(
|
|
|
165
229
|
return []
|
|
166
230
|
}
|
|
167
231
|
}
|
|
232
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Retrieve caller or callee chunks for a given chunk via the cil_calls link type'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
|
|
233
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
234
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
235
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
236
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
237
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
238
|
+
// CIL[END stable_id="~/.framework/functions/cil-graph.ts:getLinkedChunks:function"]
|
|
168
239
|
|
|
169
240
|
|
|
170
241
|
|
|
@@ -172,36 +243,34 @@ async function getLinkedChunks(
|
|
|
172
243
|
|
|
173
244
|
|
|
174
245
|
|
|
175
|
-
// CIL[
|
|
176
|
-
// CIL[
|
|
177
|
-
// CIL[DOC-
|
|
178
|
-
// CIL[DOC-
|
|
179
|
-
// CIL[DOC-
|
|
180
|
-
// CIL[DOC-
|
|
181
|
-
// CIL[DOC-
|
|
182
|
-
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
246
|
+
// CIL[BEGIN stable_id="~/.framework/functions/cil-graph.ts:handler:constant" type="constant" identity="handler" parent="~/.framework/functions/cil-graph.ts"]
|
|
247
|
+
// CIL[DOC-MACRO purpose="Main request handler for the cil-graph function dispatching graph and search actions"]
|
|
248
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Validate query parameters, route to the correct action, and return JSON results"]
|
|
249
|
+
// CIL[DOC-CONTEXT module=".framework/functions" layer="functions" related_files=".framework/functions/_shared/cil.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/llm.ts,.framework/functions/_shared/middleware.ts,.framework/functions/_shared/resolve-ids.ts,.framework/functions/cil-graph.ts"]
|
|
250
|
+
// CIL[DOC-CONTRACT inputs="ctx, body, action via ctx.query.action, versionId via ctx.query.version_id or body" outputs="JSON response per action" errors="Throws Error for missing/invalid action or parameters" side_effects="Queries adminDb and calls embeddings"]
|
|
251
|
+
// CIL[DOC-MICRO logic_summary="Create handler that branches on action, runs db queries and vector search, then serializes results" notable_decisions="Vector search falls through to text search on failure; graph diff loads two versions and compares edge sets"]
|
|
252
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.90" flags="none"]
|
|
183
253
|
// CIL[DOC-STABILITY stability="stable"]
|
|
184
|
-
// CIL[DOC-VECTOR type="context" content="Layer: function. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/functions/custom_cil-embeddings.ts, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/IntegrationsPage.tsx, \."]
|
|
185
|
-
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
186
|
-
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
187
|
-
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
188
|
-
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
189
|
-
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
190
254
|
export const handler = createHandler(async (ctx, body) => {
|
|
191
255
|
const action = ctx.query?.action
|
|
192
256
|
|
|
193
257
|
|
|
194
258
|
if (action === 'get_chunk_contract') {
|
|
195
259
|
const chunkId = ctx.query?.chunk_id
|
|
196
|
-
|
|
260
|
+
const stableId = ctx.query?.stable_id
|
|
261
|
+
const versionId = ctx.query?.version_id
|
|
262
|
+
if (!chunkId && !stableId) throw new Error('chunk_id or stable_id is required')
|
|
197
263
|
|
|
198
|
-
const chunk = await getChunkById(chunkId)
|
|
199
|
-
if (!chunk)
|
|
264
|
+
const chunk = await getChunkById(chunkId || '', stableId, versionId)
|
|
265
|
+
if (!chunk) {
|
|
266
|
+
throw new Error(stableId ? `Chunk not found for stable_id: ${stableId}` : `Chunk not found: ${chunkId}`)
|
|
267
|
+
}
|
|
200
268
|
const resolvedChunkId = chunk.id
|
|
269
|
+
const effectiveVersionId = versionId || chunk.data?.version_id
|
|
201
270
|
|
|
202
271
|
const [callers, callees] = await Promise.all([
|
|
203
|
-
getLinkedChunks(resolvedChunkId, 'cil_calls', 'callers'),
|
|
204
|
-
getLinkedChunks(resolvedChunkId, 'cil_calls', 'callees'),
|
|
272
|
+
getLinkedChunks(resolvedChunkId, 'cil_calls', 'callers', effectiveVersionId),
|
|
273
|
+
getLinkedChunks(resolvedChunkId, 'cil_calls', 'callees', effectiveVersionId),
|
|
205
274
|
])
|
|
206
275
|
|
|
207
276
|
const d = chunk.data || {}
|
|
@@ -224,6 +293,8 @@ export const handler = createHandler(async (ctx, body) => {
|
|
|
224
293
|
boundary_confidence: d.boundary_confidence || 'unknown',
|
|
225
294
|
stored_hash: d.stored_hash || null,
|
|
226
295
|
hash_status: 'unknown', // validated on demand via custom_cil-validate
|
|
296
|
+
content_hash: d.content_hash || null,
|
|
297
|
+
version_id: d.version_id || null,
|
|
227
298
|
callers,
|
|
228
299
|
callees,
|
|
229
300
|
is_dead_code: d.is_dead_code || false,
|
|
@@ -235,22 +306,32 @@ export const handler = createHandler(async (ctx, body) => {
|
|
|
235
306
|
|
|
236
307
|
if (action === 'get_callers') {
|
|
237
308
|
const chunkId = ctx.query?.chunk_id
|
|
238
|
-
|
|
239
|
-
const
|
|
240
|
-
if (!
|
|
241
|
-
const
|
|
309
|
+
const stableId = ctx.query?.stable_id
|
|
310
|
+
const versionId = ctx.query?.version_id
|
|
311
|
+
if (!chunkId && !stableId) throw new Error('chunk_id or stable_id is required')
|
|
312
|
+
const chunk = await getChunkById(chunkId || '', stableId, versionId)
|
|
313
|
+
if (!chunk) {
|
|
314
|
+
throw new Error(stableId ? `Chunk not found for stable_id: ${stableId}` : `Chunk not found: ${chunkId}`)
|
|
315
|
+
}
|
|
316
|
+
const effectiveVersionId = versionId || chunk.data?.version_id
|
|
317
|
+
const callers = await getLinkedChunks(chunk.id, 'cil_calls', 'callers', effectiveVersionId)
|
|
242
318
|
return { chunk_id: chunk.id, callers }
|
|
243
319
|
}
|
|
244
320
|
|
|
245
321
|
|
|
246
322
|
if (action === 'get_blast_radius') {
|
|
247
323
|
const chunkId = ctx.query?.chunk_id
|
|
324
|
+
const stableId = ctx.query?.stable_id
|
|
325
|
+
const versionId = ctx.query?.version_id
|
|
248
326
|
const maxDepth = parseInt(ctx.query?.max_depth || '3')
|
|
249
|
-
if (!chunkId) throw new Error('chunk_id is required')
|
|
327
|
+
if (!chunkId && !stableId) throw new Error('chunk_id or stable_id is required')
|
|
250
328
|
|
|
251
|
-
const rootChunk = await getChunkById(chunkId)
|
|
252
|
-
if (!rootChunk)
|
|
329
|
+
const rootChunk = await getChunkById(chunkId || '', stableId, versionId)
|
|
330
|
+
if (!rootChunk) {
|
|
331
|
+
throw new Error(stableId ? `Chunk not found for stable_id: ${stableId}` : `Chunk not found: ${chunkId}`)
|
|
332
|
+
}
|
|
253
333
|
const resolvedChunkId = rootChunk.id
|
|
334
|
+
const effectiveVersionId = versionId || rootChunk.data?.version_id
|
|
254
335
|
|
|
255
336
|
const visited = new Set<string>()
|
|
256
337
|
const queue: { id: string; depth: number }[] = [{ id: resolvedChunkId, depth: 0 }]
|
|
@@ -274,7 +355,7 @@ export const handler = createHandler(async (ctx, body) => {
|
|
|
274
355
|
}
|
|
275
356
|
|
|
276
357
|
if (depth < maxDepth) {
|
|
277
|
-
const callers = await getLinkedChunks(id, 'cil_calls', 'callers')
|
|
358
|
+
const callers = await getLinkedChunks(id, 'cil_calls', 'callers', effectiveVersionId)
|
|
278
359
|
for (const caller of callers) {
|
|
279
360
|
if (!visited.has(caller.chunk_id)) {
|
|
280
361
|
queue.push({ id: caller.chunk_id, depth: depth + 1 })
|
|
@@ -370,6 +451,7 @@ export const handler = createHandler(async (ctx, body) => {
|
|
|
370
451
|
if (action === 'search') {
|
|
371
452
|
const query = ctx.query?.q || body?.q
|
|
372
453
|
const projectId = ctx.query?.project_id || body?.project_id
|
|
454
|
+
const versionId = ctx.query?.version_id || body?.version_id
|
|
373
455
|
const limit = parseInt(ctx.query?.limit || '20')
|
|
374
456
|
const mode = ctx.query?.mode || body?.mode || 'hybrid'
|
|
375
457
|
if (!query) throw new Error('q is required')
|
|
@@ -386,9 +468,9 @@ export const handler = createHandler(async (ctx, body) => {
|
|
|
386
468
|
const vectorLiteral = `[${vec.join(',')}]`
|
|
387
469
|
const { data: matches } = await adminDb.rpc('match_embeddings', {
|
|
388
470
|
query_embedding: vectorLiteral,
|
|
389
|
-
match_count: limit,
|
|
390
|
-
filter_vector_type:
|
|
391
|
-
similarity_threshold: 0.
|
|
471
|
+
match_count: limit * 3,
|
|
472
|
+
filter_vector_type: null,
|
|
473
|
+
similarity_threshold: 0.15,
|
|
392
474
|
filter_item_types: ['cil_chunk'],
|
|
393
475
|
})
|
|
394
476
|
|
|
@@ -397,27 +479,42 @@ export const handler = createHandler(async (ctx, body) => {
|
|
|
397
479
|
let chunkQuery = adminDb
|
|
398
480
|
.from('items')
|
|
399
481
|
.select('id, title, data')
|
|
400
|
-
.in('
|
|
482
|
+
.in('data->>stable_id', matchIds)
|
|
401
483
|
.eq('is_active', true)
|
|
402
484
|
|
|
403
485
|
if (projectId) {
|
|
404
486
|
chunkQuery = chunkQuery.filter('data->>project_id', 'eq', projectId)
|
|
405
487
|
}
|
|
488
|
+
if (versionId) {
|
|
489
|
+
chunkQuery = chunkQuery.filter('data->>version_id', 'eq', versionId)
|
|
490
|
+
}
|
|
406
491
|
|
|
407
492
|
const { data: chunks } = await chunkQuery
|
|
408
|
-
const chunkMap = new Map((chunks || []).map((c: any) => [c.
|
|
493
|
+
const chunkMap = new Map((chunks || []).map((c: any) => [c.data?.stable_id, c]))
|
|
409
494
|
|
|
410
495
|
for (const m of (matches || [])) {
|
|
411
496
|
const chunk = chunkMap.get(m.document_id)
|
|
412
497
|
if (!chunk || seenIds.has(chunk.id)) continue
|
|
413
498
|
seenIds.add(chunk.id)
|
|
499
|
+
const d = chunk.data || {}
|
|
414
500
|
results.push({
|
|
415
501
|
id: chunk.id,
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
502
|
+
stable_id: d.stable_id || '',
|
|
503
|
+
version_id: d.version_id || null,
|
|
504
|
+
chunk_name: d.chunk_name || chunk.title,
|
|
505
|
+
file_path: d.file_path || '',
|
|
506
|
+
chunk_type: d.chunk_type || '',
|
|
507
|
+
source_set_id: d.source_set_id || null,
|
|
508
|
+
layer: d.layer || null,
|
|
509
|
+
macro: d.macro || '',
|
|
510
|
+
micro: d.micro || '',
|
|
511
|
+
input_spec: d.input_spec || '',
|
|
512
|
+
output_spec: d.output_spec || '',
|
|
513
|
+
side_effects: d.side_effects || '',
|
|
514
|
+
stability: d.stability || 'unknown',
|
|
515
|
+
tags: d.tags || '',
|
|
516
|
+
complexity: d.complexity || '',
|
|
517
|
+
doc_confidence: d.doc_confidence || 'unverified_legacy',
|
|
421
518
|
similarity: m.similarity,
|
|
422
519
|
match_type: 'semantic',
|
|
423
520
|
})
|
|
@@ -434,23 +531,68 @@ export const handler = createHandler(async (ctx, body) => {
|
|
|
434
531
|
.select('id, title, data')
|
|
435
532
|
.filter('data->>kb_type', 'eq', 'cil_chunk')
|
|
436
533
|
.eq('is_active', true)
|
|
437
|
-
.limit(
|
|
534
|
+
.limit(5000)
|
|
438
535
|
|
|
439
536
|
if (projectId) dbQuery = dbQuery.filter('data->>project_id', 'eq', projectId)
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
537
|
+
if (versionId) dbQuery = dbQuery.filter('data->>version_id', 'eq', versionId)
|
|
538
|
+
const { data: textResults } = await dbQuery
|
|
539
|
+
|
|
540
|
+
const normalizedQuery = query.toLowerCase().replace(/[^a-z0-9]/g, '')
|
|
541
|
+
const terms = query.toLowerCase().split(/[^a-z0-9]+/).filter((t: string) => t.length >= 2)
|
|
542
|
+
const phrase = query.toLowerCase()
|
|
543
|
+
|
|
544
|
+
const scored = (textResults || []).map((r: any) => {
|
|
545
|
+
const d = r.data || {}
|
|
546
|
+
const title = (r.title || '').toLowerCase()
|
|
547
|
+
const macro = (d.macro || '').toLowerCase()
|
|
548
|
+
const micro = (d.micro || '').toLowerCase()
|
|
549
|
+
const tags = (d.tags || '').toLowerCase()
|
|
550
|
+
const codeContent = (d.code_content || '').toLowerCase()
|
|
551
|
+
const normTitle = title.replace(/[^a-z0-9]/g, '')
|
|
552
|
+
const normMacro = macro.replace(/[^a-z0-9]/g, '')
|
|
553
|
+
const normMicro = micro.replace(/[^a-z0-9]/g, '')
|
|
554
|
+
const normTags = tags.replace(/[^a-z0-9]/g, '')
|
|
555
|
+
const normCode = codeContent.replace(/[^a-z0-9]/g, '')
|
|
556
|
+
let score = 0
|
|
557
|
+
for (const term of terms) {
|
|
558
|
+
if (normTitle.includes(term)) score += 3
|
|
559
|
+
if (normMacro.includes(term)) score += 2
|
|
560
|
+
if (normMicro.includes(term)) score += 1
|
|
561
|
+
if (normTags.includes(term)) score += 1
|
|
562
|
+
const codeCount = normCode.split(term).length - 1
|
|
563
|
+
score += Math.min(codeCount, 3)
|
|
564
|
+
}
|
|
565
|
+
if (codeContent.includes(phrase) || normCode.includes(normalizedQuery)) score += 5
|
|
566
|
+
return { chunk: r, score }
|
|
567
|
+
})
|
|
568
|
+
.filter(({ score }: any) => score > 0)
|
|
569
|
+
.sort((a: any, b: any) => b.score - a.score)
|
|
570
|
+
.slice(0, limit - results.length)
|
|
571
|
+
|
|
572
|
+
for (const { chunk: r, score } of scored) {
|
|
443
573
|
if (seenIds.has(r.id)) continue
|
|
444
574
|
seenIds.add(r.id)
|
|
575
|
+
const d = r.data || {}
|
|
445
576
|
results.push({
|
|
446
577
|
id: r.id,
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
578
|
+
stable_id: d.stable_id || '',
|
|
579
|
+
version_id: d.version_id || null,
|
|
580
|
+
chunk_name: d.chunk_name || r.title,
|
|
581
|
+
file_path: d.file_path || '',
|
|
582
|
+
chunk_type: d.chunk_type || '',
|
|
583
|
+
source_set_id: d.source_set_id || null,
|
|
584
|
+
layer: d.layer || null,
|
|
585
|
+
macro: d.macro || '',
|
|
586
|
+
micro: d.micro || '',
|
|
587
|
+
input_spec: d.input_spec || '',
|
|
588
|
+
output_spec: d.output_spec || '',
|
|
589
|
+
side_effects: d.side_effects || '',
|
|
590
|
+
stability: d.stability || 'unknown',
|
|
591
|
+
tags: d.tags || '',
|
|
592
|
+
complexity: d.complexity || '',
|
|
593
|
+
doc_confidence: d.doc_confidence || 'unverified_legacy',
|
|
594
|
+
similarity: score / maxScore,
|
|
595
|
+
match_type: 'content',
|
|
454
596
|
})
|
|
455
597
|
}
|
|
456
598
|
}
|
|
@@ -467,14 +609,33 @@ export const handler = createHandler(async (ctx, body) => {
|
|
|
467
609
|
.eq('id', fileId).maybeSingle()
|
|
468
610
|
if (!fileItem) throw new Error(`File not found: ${fileId}`)
|
|
469
611
|
|
|
470
|
-
|
|
612
|
+
let versionId = ctx.query?.version_id
|
|
613
|
+
if (!versionId) {
|
|
614
|
+
const projectId = fileItem.data?.project_id
|
|
615
|
+
if (projectId) {
|
|
616
|
+
const { data: project } = await adminDb
|
|
617
|
+
.from('items')
|
|
618
|
+
.select('id, data')
|
|
619
|
+
.eq('id', projectId)
|
|
620
|
+
.filter('data->>kb_type', 'eq', 'cil_project')
|
|
621
|
+
.maybeSingle()
|
|
622
|
+
versionId = project?.data?.active_version_id
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
let chunksQuery = adminDb.from('items').select('id, title, data')
|
|
471
627
|
.filter('data->>kb_type', 'eq', 'cil_chunk')
|
|
472
628
|
.filter('data->>file_id', 'eq', fileId)
|
|
473
629
|
.eq('is_active', true)
|
|
474
630
|
|
|
631
|
+
if (versionId) chunksQuery = chunksQuery.filter('data->>version_id', 'eq', versionId)
|
|
632
|
+
|
|
633
|
+
const { data: chunks } = await chunksQuery
|
|
634
|
+
|
|
475
635
|
const sorted = (chunks || [])
|
|
476
636
|
.map((c: any) => ({
|
|
477
637
|
id: c.id,
|
|
638
|
+
stable_id: c.data?.stable_id || '',
|
|
478
639
|
chunk_name: c.data?.chunk_name || '',
|
|
479
640
|
chunk_type: c.data?.chunk_type || '',
|
|
480
641
|
line_start: c.data?.line_start || 0,
|
|
@@ -503,54 +664,79 @@ export const handler = createHandler(async (ctx, body) => {
|
|
|
503
664
|
|
|
504
665
|
if (action === 'get_project_graph') {
|
|
505
666
|
const projectId = ctx.query?.project_id
|
|
667
|
+
const versionId = ctx.query?.version_id
|
|
506
668
|
if (!projectId) throw new Error('project_id is required')
|
|
507
669
|
|
|
508
|
-
const
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
.
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
670
|
+
const PAGE_SIZE = 1000
|
|
671
|
+
|
|
672
|
+
async function fetchAllItems(kbType: string) {
|
|
673
|
+
const out: any[] = []
|
|
674
|
+
let offset = 0
|
|
675
|
+
while (true) {
|
|
676
|
+
let q = adminDb.from('items').select('id, title, data')
|
|
677
|
+
.filter('data->>kb_type', 'eq', kbType)
|
|
678
|
+
.filter('data->>project_id', 'eq', projectId)
|
|
679
|
+
.eq('is_active', true)
|
|
680
|
+
.range(offset, offset + PAGE_SIZE - 1)
|
|
681
|
+
if (versionId) q = q.filter('data->>version_id', 'eq', versionId)
|
|
682
|
+
const { data } = await q
|
|
683
|
+
const rows = data || []
|
|
684
|
+
out.push(...rows)
|
|
685
|
+
if (rows.length < PAGE_SIZE) break
|
|
686
|
+
offset += PAGE_SIZE
|
|
687
|
+
}
|
|
688
|
+
return out
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
async function fetchAllLinks(linkTypeId: string) {
|
|
692
|
+
const out: any[] = []
|
|
693
|
+
let offset = 0
|
|
694
|
+
while (true) {
|
|
695
|
+
let q = adminDb.from('links')
|
|
696
|
+
.select('source_id, target_id, source_type, target_type, metadata')
|
|
697
|
+
.eq('link_type_id', linkTypeId)
|
|
698
|
+
.range(offset, offset + PAGE_SIZE - 1)
|
|
699
|
+
if (versionId) q = q.filter('metadata->>version_id', 'eq', versionId)
|
|
700
|
+
const { data } = await q
|
|
701
|
+
const rows = data || []
|
|
702
|
+
out.push(...rows)
|
|
703
|
+
if (rows.length < PAGE_SIZE) break
|
|
704
|
+
offset += PAGE_SIZE
|
|
705
|
+
}
|
|
706
|
+
return out
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
const [fileItems, chunkItems] = await Promise.all([
|
|
710
|
+
fetchAllItems('cil_file'),
|
|
711
|
+
fetchAllItems('cil_chunk'),
|
|
518
712
|
])
|
|
519
713
|
|
|
520
|
-
|
|
714
|
+
const fileIdSet = new Set(fileItems.map((f: any) => f.id))
|
|
715
|
+
const chunkIdSet = new Set(chunkItems.map((c: any) => c.id))
|
|
716
|
+
|
|
521
717
|
let importEdges: any[] = []
|
|
522
718
|
try {
|
|
523
719
|
const importLinkTypeId = await resolveLinkTypeId('cil_imports')
|
|
524
|
-
const
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
.eq('link_type_id', importLinkTypeId)
|
|
530
|
-
.in('source_id', fileIds)
|
|
531
|
-
importEdges = edges || []
|
|
532
|
-
}
|
|
720
|
+
const edges = await fetchAllLinks(importLinkTypeId)
|
|
721
|
+
importEdges = edges.filter((e: any) =>
|
|
722
|
+
chunkIdSet.has(e.source_id) &&
|
|
723
|
+
(fileIdSet.has(e.target_id) || chunkIdSet.has(e.target_id))
|
|
724
|
+
)
|
|
533
725
|
} catch { /* link type may not exist yet */ }
|
|
534
726
|
|
|
535
|
-
|
|
536
727
|
let callEdges: any[] = []
|
|
537
728
|
try {
|
|
538
729
|
const callLinkTypeId = await resolveLinkTypeId('cil_calls')
|
|
539
|
-
const
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
.select('source_id, target_id, metadata')
|
|
544
|
-
.eq('link_type_id', callLinkTypeId)
|
|
545
|
-
.in('source_id', chunkIds)
|
|
546
|
-
callEdges = edges || []
|
|
547
|
-
}
|
|
730
|
+
const edges = await fetchAllLinks(callLinkTypeId)
|
|
731
|
+
callEdges = edges.filter((e: any) =>
|
|
732
|
+
chunkIdSet.has(e.source_id) && chunkIdSet.has(e.target_id)
|
|
733
|
+
)
|
|
548
734
|
} catch { /* link type may not exist yet */ }
|
|
549
735
|
|
|
550
736
|
return {
|
|
551
737
|
project_id: projectId,
|
|
552
738
|
nodes: {
|
|
553
|
-
files:
|
|
739
|
+
files: fileItems.map((f: any) => ({
|
|
554
740
|
id: f.id,
|
|
555
741
|
file_path: f.data?.file_path || '',
|
|
556
742
|
language: f.data?.language || '',
|
|
@@ -558,7 +744,7 @@ export const handler = createHandler(async (ctx, body) => {
|
|
|
558
744
|
is_dead_code: f.data?.is_dead_code || false,
|
|
559
745
|
chunk_count: f.data?.chunk_count || 0,
|
|
560
746
|
})),
|
|
561
|
-
chunks:
|
|
747
|
+
chunks: chunkItems.map((c: any) => ({
|
|
562
748
|
id: c.id,
|
|
563
749
|
chunk_name: c.data?.chunk_name || '',
|
|
564
750
|
file_id: c.data?.file_id || '',
|
|
@@ -577,9 +763,108 @@ export const handler = createHandler(async (ctx, body) => {
|
|
|
577
763
|
}
|
|
578
764
|
}
|
|
579
765
|
|
|
766
|
+
if (action === 'graph_diff') {
|
|
767
|
+
const projectId = ctx.query?.project_id
|
|
768
|
+
const fromVersionId = ctx.query?.from_version_id
|
|
769
|
+
const toVersionId = ctx.query?.to_version_id
|
|
770
|
+
if (!projectId) throw new Error('project_id is required')
|
|
771
|
+
if (!fromVersionId) throw new Error('from_version_id is required')
|
|
772
|
+
if (!toVersionId) throw new Error('to_version_id is required')
|
|
773
|
+
|
|
774
|
+
const items: any[] = []
|
|
775
|
+
for (const versionId of [fromVersionId, toVersionId]) {
|
|
776
|
+
for (const kbType of ['cil_chunk', 'cil_file']) {
|
|
777
|
+
const { data: rows } = await adminDb
|
|
778
|
+
.from('items')
|
|
779
|
+
.select('id, data')
|
|
780
|
+
.filter('data->>kb_type', 'eq', kbType)
|
|
781
|
+
.filter('data->>project_id', 'eq', projectId)
|
|
782
|
+
.filter('data->>version_id', 'eq', versionId)
|
|
783
|
+
.eq('is_active', true)
|
|
784
|
+
if (rows) items.push(...rows)
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
const stableMap = new Map<string, string>()
|
|
789
|
+
const pathMap = new Map<string, string>()
|
|
790
|
+
for (const item of items) {
|
|
791
|
+
stableMap.set(item.id, item.data?.stable_id || item.id)
|
|
792
|
+
pathMap.set(item.id, item.data?.file_path || '')
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
const [callsId, importsId] = await Promise.all([
|
|
796
|
+
resolveLinkTypeId('cil_calls'),
|
|
797
|
+
resolveLinkTypeId('cil_imports'),
|
|
798
|
+
])
|
|
799
|
+
const edgeTypeById: Record<string, string> = {
|
|
800
|
+
[callsId]: 'cil_calls',
|
|
801
|
+
[importsId]: 'cil_imports',
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
async function getEdgesForVersion(versionId: string) {
|
|
805
|
+
const { data: edges } = await adminDb
|
|
806
|
+
.from('links')
|
|
807
|
+
.select('source_id, target_id, link_type_id, metadata')
|
|
808
|
+
.in('link_type_id', [callsId, importsId])
|
|
809
|
+
.filter('metadata->>version_id', 'eq', versionId)
|
|
810
|
+
|
|
811
|
+
const seen = new Map<string, { edge_type: string; from_stable_id: string; to_stable_id: string; from_file_path: string; to_file_path: string }>()
|
|
812
|
+
for (const edge of edges || []) {
|
|
813
|
+
const edgeType = edgeTypeById[edge.link_type_id]
|
|
814
|
+
if (!edgeType) continue
|
|
815
|
+
if (!stableMap.has(edge.source_id) || !stableMap.has(edge.target_id)) continue
|
|
816
|
+
|
|
817
|
+
const fromStable = stableMap.get(edge.source_id)!
|
|
818
|
+
const toStable = stableMap.get(edge.target_id)!
|
|
819
|
+
const key = `${edgeType}|${fromStable}|${toStable}`
|
|
820
|
+
if (seen.has(key)) continue
|
|
821
|
+
|
|
822
|
+
seen.set(key, {
|
|
823
|
+
edge_type: edgeType,
|
|
824
|
+
from_stable_id: fromStable,
|
|
825
|
+
to_stable_id: toStable,
|
|
826
|
+
from_file_path: pathMap.get(edge.source_id) || '',
|
|
827
|
+
to_file_path: pathMap.get(edge.target_id) || '',
|
|
828
|
+
})
|
|
829
|
+
}
|
|
830
|
+
return seen
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
const [fromEdges, toEdges] = await Promise.all([
|
|
834
|
+
getEdgesForVersion(fromVersionId),
|
|
835
|
+
getEdgesForVersion(toVersionId),
|
|
836
|
+
])
|
|
837
|
+
|
|
838
|
+
const added: any[] = []
|
|
839
|
+
const removed: any[] = []
|
|
840
|
+
const unchanged: any[] = []
|
|
841
|
+
|
|
842
|
+
for (const [key, entry] of toEdges) {
|
|
843
|
+
if (fromEdges.has(key)) unchanged.push(entry)
|
|
844
|
+
else added.push(entry)
|
|
845
|
+
}
|
|
846
|
+
for (const [key, entry] of fromEdges) {
|
|
847
|
+
if (!toEdges.has(key)) removed.push(entry)
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
return {
|
|
851
|
+
project_id: projectId,
|
|
852
|
+
from_version_id: fromVersionId,
|
|
853
|
+
to_version_id: toVersionId,
|
|
854
|
+
added,
|
|
855
|
+
removed,
|
|
856
|
+
unchanged,
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
580
860
|
throw new Error(`Unknown action: ${action}. Valid: get_chunk_contract, get_callers, get_blast_radius, get_test_paths, get_file_graph, get_file_chunks, search, get_project_graph`)
|
|
581
861
|
})
|
|
862
|
+
// CIL[DOC-VECTOR type="context" content="purpose='Main request handler for the cil-graph function dispatching graph and search actions'; No verified external callers; imports: .framework/functions/_shared/middleware.ts,.framework/functions/_shared/db.ts,.framework/functions/_shared/resolve-ids.ts"]
|
|
863
|
+
// CIL[DOC-VECTOR type="blast_radius" content="No direct caller data from CIL graph; local impact only"]
|
|
864
|
+
// CIL[DOC-VECTOR type="configuration" content="No environment or build configuration dependencies identified"]
|
|
865
|
+
// CIL[DOC-VECTOR type="constraint" content="Standard runtime; no special invariants documented"]
|
|
866
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
867
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
868
|
+
// CIL[END stable_id="~/.framework/functions/cil-graph.ts:handler:constant"]
|
|
582
869
|
|
|
583
870
|
|
|
584
|
-
|
|
585
|
-
// CIL[END chunk_id="custom_apps_cortex_functions_custom_cil_graph_handler_1784235266"]
|