spine-framework 0.3.124 → 0.3.126
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/.framework/cli/commands/agents.ts +35 -37
- package/.framework/cli/commands/auth.ts +35 -34
- package/.framework/cli/commands/create-app.ts +104 -40
- package/.framework/cli/commands/dev.ts +104 -69
- package/.framework/cli/commands/doctor.ts +179 -69
- package/.framework/cli/commands/generate.ts +83 -143
- package/.framework/cli/commands/init.ts +72 -34
- package/.framework/cli/commands/install-app.ts +260 -125
- package/.framework/cli/commands/items.ts +33 -44
- package/.framework/cli/commands/migrate.ts +122 -40
- package/.framework/cli/commands/migrations.ts +33 -40
- package/.framework/cli/commands/pipelines.ts +31 -39
- package/.framework/cli/commands/status.ts +47 -23
- package/.framework/cli/commands/system.ts +47 -37
- package/.framework/cli/commands/test.ts +112 -68
- package/.framework/cli/commands/validate-app.ts +215 -121
- package/.framework/cli/context.ts +112 -130
- package/.framework/cli/env-loader.ts +47 -18
- package/.framework/cli/index.ts +81 -42
- package/.framework/docs/runtime-types.md +1024 -0
- package/.framework/functions/_shared/agent-runner.ts +1296 -961
- package/.framework/functions/_shared/app-manifest.ts +82 -68
- package/.framework/functions/_shared/audit.ts +135 -83
- package/.framework/functions/_shared/{cil-state.ts → cil.ts} +158 -56
- package/.framework/functions/_shared/db.ts +80 -126
- package/.framework/functions/_shared/hash-api-key.ts +63 -0
- package/.framework/functions/_shared/index.ts +224 -335
- package/.framework/functions/_shared/kb.ts +319 -0
- package/.framework/functions/_shared/llm.ts +92 -0
- package/.framework/functions/_shared/logging.ts +288 -0
- package/.framework/functions/_shared/middleware.ts +329 -365
- package/.framework/functions/_shared/outcomes.ts +36 -0
- package/.framework/functions/_shared/permissions.ts +359 -643
- package/.framework/functions/_shared/pipeline-runner.ts +243 -316
- package/.framework/functions/_shared/principal.ts +376 -468
- package/.framework/functions/_shared/resolve-credentials.ts +102 -0
- package/.framework/functions/_shared/resolve-ids.ts +188 -16
- package/.framework/functions/_shared/retry-deliveries.ts +104 -0
- package/.framework/functions/_shared/schema-utils.ts +611 -373
- package/.framework/functions/_shared/testing.ts +207 -137
- package/.framework/functions/_shared/tracing.ts +276 -0
- package/.framework/functions/_shared/trigger-engine.ts +159 -211
- package/.framework/functions/_shared/webhook-registration.ts +95 -81
- package/.framework/functions/_shared/webhook-registry.ts +153 -75
- package/.framework/functions/account-nodes.ts +31 -53
- package/.framework/functions/adapters/generic-webhook-inbound.ts +56 -0
- package/.framework/functions/adapters/generic-webhook-outbound.ts +43 -0
- package/.framework/functions/adapters/openai-outbound.ts +40 -0
- package/.framework/functions/admin-data.ts +685 -537
- package/.framework/functions/admin-funnel.ts +31 -20
- package/.framework/functions/admin-install-funnel.ts +47 -28
- package/.framework/functions/admin-signals.ts +47 -29
- package/.framework/functions/ai-agents.ts +122 -147
- package/.framework/functions/ai-interactions.ts +180 -90
- package/.framework/functions/api-keys.ts +250 -192
- package/.framework/functions/apps.ts +203 -197
- package/.framework/functions/auth.ts +98 -91
- package/.framework/functions/cil-agent-ingest.ts +773 -0
- package/.framework/functions/cil-agent.ts +592 -0
- package/.framework/functions/cil-callmap.ts +1227 -0
- package/.framework/functions/cil-config.ts +583 -0
- package/.framework/functions/cil-context.ts +445 -0
- package/.framework/functions/cil-doc.ts +1752 -0
- package/.framework/functions/cil-embeddings.ts +1202 -0
- package/.framework/functions/cil-graph.ts +585 -0
- package/.framework/functions/cil-ingest.ts +2416 -0
- package/.framework/functions/cil-pipeline.ts +318 -0
- package/.framework/functions/cil-project.ts +499 -0
- package/.framework/functions/cil-validate.ts +469 -0
- package/.framework/functions/debug-auth.ts +73 -53
- package/.framework/functions/deliveries.ts +117 -0
- package/.framework/functions/embeddings.ts +528 -516
- package/.framework/functions/eval-harness.ts +158 -106
- package/.framework/functions/integration-outbound.ts +311 -0
- package/.framework/functions/integration-routes.ts +240 -466
- package/.framework/functions/integrations.ts +132 -140
- package/.framework/functions/invites.ts +401 -201
- package/.framework/functions/item-progress.ts +113 -53
- package/.framework/functions/kb.ts +28 -0
- package/.framework/functions/logs.ts +239 -222
- package/.framework/functions/observability.ts +308 -259
- package/.framework/functions/pipeline-executions.ts +179 -235
- package/.framework/functions/pipelines.ts +163 -205
- package/.framework/functions/prompt-configs.ts +109 -156
- package/.framework/functions/roles.ts +97 -147
- package/.framework/functions/system-cron.ts +132 -218
- package/.framework/functions/system.ts +112 -52
- package/.framework/functions/tests.ts +32 -28
- package/.framework/functions/timers.ts +162 -210
- package/.framework/functions/triggers.ts +282 -346
- package/.framework/functions/types.ts +283 -400
- package/.framework/migrations/001_core_schema.sql +630 -0
- package/.framework/migrations/002_core_rls_and_functions.sql +532 -0
- package/.framework/migrations/{003_system_data.sql → 003_core_system_data.sql} +26 -153
- package/.framework/migrations/004_core_rpc_and_broker.sql +421 -0
- package/.framework/migrations/005_core_observability.sql +598 -0
- package/.framework/migrations/006_security_hardening_rls.sql +97 -0
- package/.framework/migrations/007_kb_article_list.sql +237 -0
- package/.framework/migrations/008_items_target.sql +8 -0
- package/.framework/migrations/009_roles_slug_unique.sql +11 -0
- package/.framework/public/spine.config.json +91 -0
- package/.framework/scripts/app-install-cli.ts +112 -98
- package/.framework/src/App.tsx +67 -20
- package/.framework/src/apps/admin/index.tsx +97 -27
- package/.framework/src/components/AppWrapper.tsx +50 -11
- package/.framework/src/components/CustomAppLoader.tsx +131 -22
- package/.framework/src/components/admin/AdminListPage.tsx +75 -8
- package/.framework/src/components/admin/AdminSidebar.tsx +148 -36
- package/.framework/src/components/admin/AdminStatsCard.tsx +48 -29
- package/.framework/src/components/admin/PageInstructions.tsx +49 -0
- package/.framework/src/components/admin/SortableTableHeader.tsx +49 -2
- package/.framework/src/components/app-shell/GenericAppShell.tsx +69 -11
- package/.framework/src/components/app-shell/GenericDetailPage.tsx +55 -10
- package/.framework/src/components/app-shell/GenericListPage.tsx +76 -9
- package/.framework/src/components/app-sidebar.tsx +50 -3
- package/.framework/src/components/auth/ProtectedRoute.tsx +53 -45
- package/.framework/src/components/kb/KBArticleEditor.tsx +409 -0
- package/.framework/src/components/kb/KBArticleList.tsx +557 -0
- package/.framework/src/components/layout/AppShell.tsx +54 -16
- package/.framework/src/components/layout/Header.tsx +50 -38
- package/.framework/src/components/layout/Layout.tsx +48 -32
- package/.framework/src/components/layout/Sidebar.tsx +167 -16
- package/.framework/src/components/runtime/DataDetailHeader.tsx +33 -1
- package/.framework/src/components/runtime/DataDetailPage.tsx +289 -4
- package/.framework/src/components/runtime/DataFilters.tsx +78 -1
- package/.framework/src/components/runtime/DataHeader.tsx +32 -29
- package/.framework/src/components/runtime/DataListPage.tsx +161 -2
- package/.framework/src/components/runtime/DataStats.tsx +48 -1
- package/.framework/src/components/runtime/DataTable.tsx +153 -1
- package/.framework/src/components/runtime/SchemaDetailForm.tsx +77 -46
- package/.framework/src/components/runtime/index.ts +16 -9
- package/.framework/src/components/search-form.tsx +33 -1
- package/.framework/src/components/shared/AgentView.tsx +48 -51
- package/.framework/src/components/shared/FieldRenderer.tsx +84 -67
- package/.framework/src/components/shared/InviteManager.tsx +113 -52
- package/.framework/src/components/shared/MemberList.tsx +182 -0
- package/.framework/src/components/shared/SchemaFields.tsx +96 -78
- package/.framework/src/components/ui/DataTable.tsx +86 -56
- package/.framework/src/components/ui/Form.tsx +188 -109
- package/.framework/src/components/ui/ItemCard.tsx +86 -58
- package/.framework/src/components/ui/ItemListView.tsx +88 -61
- package/.framework/src/components/ui/LoadingSpinner.tsx +52 -27
- package/.framework/src/components/ui/Modal.tsx +81 -4
- package/.framework/src/components/ui/RichTextEditor.tsx +101 -9
- package/.framework/src/components/ui/accordion.tsx +97 -5
- package/.framework/src/components/ui/alert-dialog.tsx +225 -13
- package/.framework/src/components/ui/alert.tsx +113 -6
- package/.framework/src/components/ui/aspect-ratio.tsx +49 -2
- package/.framework/src/components/ui/avatar.tsx +129 -7
- package/.framework/src/components/ui/badge.tsx +65 -3
- package/.framework/src/components/ui/breadcrumb.tsx +145 -8
- package/.framework/src/components/ui/button-group.tsx +81 -4
- package/.framework/src/components/ui/button.tsx +49 -2
- package/.framework/src/components/ui/calendar.tsx +65 -3
- package/.framework/src/components/ui/card.tsx +145 -8
- package/.framework/src/components/ui/carousel.tsx +129 -7
- package/.framework/src/components/ui/chart.tsx +161 -10
- package/.framework/src/components/ui/checkbox.tsx +49 -2
- package/.framework/src/components/ui/collapsible.tsx +81 -5
- package/.framework/src/components/ui/combobox.tsx +305 -20
- package/.framework/src/components/ui/command.tsx +177 -11
- package/.framework/src/components/ui/context-menu.tsx +273 -17
- package/.framework/src/components/ui/dialog.tsx +209 -27
- package/.framework/src/components/ui/direction.tsx +64 -4
- package/.framework/src/components/ui/drawer.tsx +193 -12
- package/.framework/src/components/ui/dropdown-menu.tsx +273 -18
- package/.framework/src/components/ui/empty.tsx +145 -9
- package/.framework/src/components/ui/field.tsx +209 -14
- package/.framework/src/components/ui/hover-card.tsx +81 -4
- package/.framework/src/components/ui/input-group.tsx +162 -10
- package/.framework/src/components/ui/input-otp.tsx +98 -5
- package/.framework/src/components/ui/input.tsx +49 -2
- package/.framework/src/components/ui/item.tsx +225 -13
- package/.framework/src/components/ui/kbd.tsx +65 -3
- package/.framework/src/components/ui/label.tsx +49 -2
- package/.framework/src/components/ui/menubar.tsx +289 -17
- package/.framework/src/components/ui/native-select.tsx +97 -5
- package/.framework/src/components/ui/navigation-menu.tsx +177 -10
- package/.framework/src/components/ui/pagination.tsx +161 -9
- package/.framework/src/components/ui/popover.tsx +145 -8
- package/.framework/src/components/ui/progress.tsx +49 -2
- package/.framework/src/components/ui/radio-group.tsx +65 -3
- package/.framework/src/components/ui/resizable.tsx +82 -4
- package/.framework/src/components/ui/scroll-area.tsx +65 -3
- package/.framework/src/components/ui/select.tsx +193 -11
- package/.framework/src/components/ui/separator.tsx +49 -2
- package/.framework/src/components/ui/sheet.tsx +193 -11
- package/.framework/src/components/ui/sidebar.tsx +481 -38
- package/.framework/src/components/ui/skeleton.tsx +49 -2
- package/.framework/src/components/ui/slider.tsx +49 -2
- package/.framework/src/components/ui/sonner.tsx +49 -2
- package/.framework/src/components/ui/spinner.tsx +49 -2
- package/.framework/src/components/ui/switch.tsx +49 -2
- package/.framework/src/components/ui/table-primitives.tsx +160 -33
- package/.framework/src/components/ui/table.tsx +161 -9
- package/.framework/src/components/ui/tabs.tsx +113 -6
- package/.framework/src/components/ui/textarea.tsx +49 -2
- package/.framework/src/components/ui/toggle-group.tsx +81 -4
- package/.framework/src/components/ui/toggle.tsx +65 -3
- package/.framework/src/components/ui/tooltip.tsx +97 -5
- package/.framework/src/contexts/AppContext.tsx +129 -45
- package/.framework/src/contexts/AuthContext.tsx +187 -144
- package/.framework/src/hooks/use-mobile.ts +48 -2
- package/.framework/src/hooks/useApi.ts +208 -159
- package/.framework/src/hooks/useAppPath.ts +32 -23
- package/.framework/src/hooks/useApps.ts +51 -20
- package/.framework/src/hooks/useEntityList.ts +32 -78
- package/.framework/src/hooks/useEntityRecord.ts +35 -96
- package/.framework/src/hooks/useForm.ts +32 -92
- package/.framework/src/hooks/useListSchema.ts +49 -78
- package/.framework/src/hooks/useSchemaRecord.ts +114 -105
- package/.framework/src/lib/api.ts +195 -116
- package/.framework/src/lib/supabase.ts +98 -64
- package/.framework/src/lib/utils.ts +287 -151
- package/.framework/src/main.tsx +49 -3
- package/.framework/src/pages/DashboardPage.tsx +52 -29
- package/.framework/src/pages/NotFoundPage.tsx +32 -10
- package/.framework/src/pages/SetupPage.tsx +32 -12
- package/.framework/src/pages/admin/AIAgentDetailPage.tsx +119 -10
- package/.framework/src/pages/admin/AIAgentsPage.tsx +48 -19
- package/.framework/src/pages/admin/APIKeyDetailPage.tsx +187 -17
- package/.framework/src/pages/admin/APIKeysPage.tsx +98 -22
- package/.framework/src/pages/admin/AlertsConfigPage.tsx +113 -26
- package/.framework/src/pages/admin/AppDetailPage.tsx +125 -8
- package/.framework/src/pages/admin/AppsPage.tsx +49 -2
- package/.framework/src/pages/admin/DeliveriesPage.tsx +196 -0
- package/.framework/src/pages/admin/DesignedPage.tsx +32 -18
- package/.framework/src/pages/admin/EmbeddingDetailPage.tsx +215 -484
- package/.framework/src/pages/admin/EmbeddingsPage.tsx +116 -319
- package/.framework/src/pages/admin/ExtendedShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/IncrementalShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/IntegratedDashboard.tsx +32 -16
- package/.framework/src/pages/admin/IntegrationDetailPage.tsx +183 -26
- package/.framework/src/pages/admin/IntegrationsPage.tsx +48 -19
- package/.framework/src/pages/admin/InvitesPage.tsx +48 -14
- package/.framework/src/pages/admin/LogsPage.tsx +422 -75
- package/.framework/src/pages/admin/MinimalShadcnTestPage.tsx +34 -9
- package/.framework/src/pages/admin/ObservabilityDashboard.tsx +113 -24
- package/.framework/src/pages/admin/PipelineDetailPage.tsx +206 -34
- package/.framework/src/pages/admin/PipelineExecutionsPage.tsx +50 -17
- package/.framework/src/pages/admin/PipelinesPage.tsx +160 -21
- package/.framework/src/pages/admin/PromptConfigDetailPage.tsx +378 -88
- package/.framework/src/pages/admin/PromptConfigsPage.tsx +125 -16
- package/.framework/src/pages/admin/ProperlyDesignedPage.tsx +49 -10
- package/.framework/src/pages/admin/RoleDetailPage.tsx +130 -10
- package/.framework/src/pages/admin/RolesPage.tsx +171 -18
- package/.framework/src/pages/admin/SelectTestPage.tsx +34 -9
- package/.framework/src/pages/admin/ShadcnTestPage.tsx +49 -11
- package/.framework/src/pages/admin/SimpleDashboard.tsx +49 -10
- package/.framework/src/pages/admin/TestRunDetailPage.tsx +49 -4
- package/.framework/src/pages/admin/TestingDashboard.tsx +98 -28
- package/.framework/src/pages/admin/TimerDetailPage.tsx +143 -33
- package/.framework/src/pages/admin/TimersPage.tsx +48 -20
- package/.framework/src/pages/admin/TriggerDetailPage.tsx +118 -30
- package/.framework/src/pages/admin/TriggersPage.tsx +64 -19
- package/.framework/src/pages/admin/TypeDetailPage.tsx +138 -15
- package/.framework/src/pages/admin/TypesPage.tsx +48 -20
- package/.framework/src/pages/admin/cil/CILAgentPage.tsx +465 -0
- package/.framework/src/pages/admin/cil/CILChunkDetailPage.tsx +787 -0
- package/.framework/src/pages/admin/cil/CILDashboardPage.tsx +699 -0
- package/.framework/src/pages/admin/cil/CILFileListPage.tsx +647 -0
- package/.framework/src/pages/admin/cil/CILGraphPage.tsx +616 -0
- package/.framework/src/pages/admin/cil/CILIngestionPage.tsx +1402 -0
- package/.framework/src/pages/admin/cil/CILProjectsPage.tsx +614 -0
- package/.framework/src/pages/admin/cil/CILSearchPage.tsx +571 -0
- package/.framework/src/pages/admin/cil/FlexiblePipelinePage.tsx +731 -0
- package/.framework/src/pages/admin/kb/KBAdminPage.tsx +64 -0
- package/.framework/src/pages/auth/AuthConfirmPage.tsx +52 -51
- package/.framework/src/pages/auth/ForgotPasswordPage.tsx +31 -22
- package/.framework/src/pages/auth/LoginPage.tsx +50 -23
- package/.framework/src/pages/auth/PendingApprovalPage.tsx +31 -15
- package/.framework/src/pages/auth/RegisterPage.tsx +281 -317
- package/.framework/src/pages/spine-framework/APIPage.tsx +33 -0
- package/.framework/src/pages/spine-framework/CLIPage.tsx +33 -0
- package/.framework/src/types/auth.ts +128 -71
- package/.framework/src/types/types.ts +373 -157
- package/custom/.devin/skills/spine-workbench-discovery/SKILL.md +39 -0
- package/custom/.devin/skills/spine-workbench-idea/SKILL.md +36 -0
- package/custom/.devin/skills/spine-workbench-implement/SKILL.md +46 -0
- package/custom/.devin/skills/spine-workbench-initiative/SKILL.md +28 -0
- package/custom/.devin/skills/spine-workbench-plan/SKILL.md +38 -0
- package/docs/README.md +9 -130
- package/netlify.toml +5 -2
- package/package.json +13 -25
- package/scripts/kb-ingest-docs.ts +203 -0
- package/spine.config.json +65 -4
- package/.framework/migrations/001_schema.sql +0 -425
- package/.framework/migrations/002_rls_and_functions.sql +0 -763
- package/.framework/migrations/004_enhancements.sql +0 -43
- package/.framework/migrations/005_auth_user_trigger.sql +0 -105
- package/.framework/migrations/006_fix_current_actor_id.sql +0 -21
- package/.framework/migrations/016_invites.sql +0 -27
- package/.framework/migrations/017_fix_get_account_apps.sql +0 -78
- package/.framework/migrations/018_apps_required_roles.sql +0 -17
- package/.framework/migrations/019_triggers_unique_constraint.sql +0 -13
- package/.framework/migrations/020_get_account_apps_role_filter.sql +0 -117
- package/.framework/migrations/021_app_domains.sql +0 -112
- package/.framework/migrations/022_route_prefix_domain_unique.sql +0 -21
- package/.framework/migrations/023_match_embeddings_rpc.sql +0 -78
- package/.framework/migrations/024_messages_account_id.sql +0 -9
- package/.framework/migrations/025_retype_threads_messages.sql +0 -240
- package/.framework/migrations/026_fix_rls_policies.sql +0 -47
- package/.framework/migrations/027_embedding_lifecycle.sql +0 -176
- package/.framework/migrations/028_fix_message_data_permissions.sql +0 -49
- package/.framework/migrations/029_tighten_support_triage_prompt.sql +0 -41
- package/.framework/migrations/030_messages_updated_by.sql +0 -6
- package/.framework/migrations/031_seed_upsert_constraints.sql +0 -35
- package/docs/APPS.md +0 -232
- package/docs/ARCHITECTURE.md +0 -246
- package/docs/INSTALL.md +0 -155
- package/docs/design-schema-spec.md +0 -1837
- package/docs/dev-guides/01-create-an-app.md +0 -183
- package/docs/dev-guides/02-create-a-function.md +0 -178
- package/docs/dev-guides/03-create-a-component.md +0 -178
- package/docs/dev-guides/04-webhook-handlers.md +0 -129
- package/docs/dev-guides/05-testing.md +0 -168
- package/docs/dev-guides/README.md +0 -40
- package/docs/npm-packages-plan.md +0 -288
- package/docs/spine-core--api-reference.md +0 -822
|
@@ -0,0 +1,614 @@
|
|
|
1
|
+
// CIL[BEGIN chunk_id="cilprojectspage_module_header_1784193942" type="module_header" identity="module_header" parent="none"]
|
|
2
|
+
// CIL[DOC-MACRO purpose="Import dependencies and icons for the CIL projects page"]
|
|
3
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Provides module imports and icon references used by CILProjectsPage"]
|
|
4
|
+
// CIL[DOC-CONTEXT module="cortex:cil-projects" layer="presentation" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/pages/admin/RolesPage.tsx\",\"\\\"]"]
|
|
5
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="none" errors="none" side_effects="none"]
|
|
6
|
+
// CIL[DOC-MICRO logic_summary="Imports React hooks, router, apiFetch, useAppPath, shadcn UI components, and lucide icons" notable_decisions="[]"]
|
|
7
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
8
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
9
|
+
// CIL[DOC-AUDIENCE audience="developer"]
|
|
10
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. 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/src/pages/admin/RolesPage.tsx, \."]
|
|
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"]
|
|
16
|
+
import { useEffect, useState } from 'react'
|
|
17
|
+
import { useNavigate } from 'react-router-dom'
|
|
18
|
+
import { apiFetch } from '@core/lib/api'
|
|
19
|
+
import { Card, CardContent, CardHeader, CardTitle } from '@core/components/ui/card'
|
|
20
|
+
import { Button } from '@core/components/ui/button'
|
|
21
|
+
import { Badge } from '@core/components/ui/badge'
|
|
22
|
+
import { Skeleton } from '@core/components/ui/skeleton'
|
|
23
|
+
import {
|
|
24
|
+
Dialog,
|
|
25
|
+
DialogContent,
|
|
26
|
+
DialogHeader,
|
|
27
|
+
DialogTitle,
|
|
28
|
+
DialogFooter,
|
|
29
|
+
} from '@core/components/ui/dialog'
|
|
30
|
+
import { Input } from '@core/components/ui/input'
|
|
31
|
+
import { Label } from '@core/components/ui/label'
|
|
32
|
+
import { Textarea } from '@core/components/ui/textarea'
|
|
33
|
+
import { NativeSelect, NativeSelectOption } from '@core/components/ui/native-select'
|
|
34
|
+
import { FolderGit2, Plus, Play, CheckCircle2, Clock, AlertCircle, GitGraph, LayoutDashboard, Trash2, Layers, Pencil, X } from 'lucide-react'
|
|
35
|
+
|
|
36
|
+
import { PageInstructions } from '../../../components/admin/PageInstructions'
|
|
37
|
+
// CIL[END chunk_id="cilprojectspage_module_header_1784193942"]
|
|
38
|
+
// CIL[BEGIN chunk_id="cilprojectspage_sourceset_1784193942" type="interface" identity="SourceSet" parent="none"]
|
|
39
|
+
// CIL[DOC-MACRO purpose="Declare the SourceSet data shape for ingestion configuration"]
|
|
40
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Provides the TypeScript contract for a named source set within a CIL project"]
|
|
41
|
+
// CIL[DOC-CONTEXT module="cortex:cil-projects" layer="presentation" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
|
|
42
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="SourceSet type definition" errors="none" side_effects="none"]
|
|
43
|
+
// CIL[DOC-MICRO logic_summary="Defines id, name, base_path, and optional globs, exclude_globs, and layer fields" notable_decisions="[]"]
|
|
44
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
45
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
46
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/schema-utils.ts, \."]
|
|
47
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
48
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
49
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
50
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
51
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
52
|
+
interface SourceSet {
|
|
53
|
+
id: string
|
|
54
|
+
name: string
|
|
55
|
+
base_path: string
|
|
56
|
+
globs?: string
|
|
57
|
+
exclude_globs?: string
|
|
58
|
+
layer?: string
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// CIL[END chunk_id="cilprojectspage_sourceset_1784193942"]
|
|
62
|
+
// CIL[BEGIN chunk_id="cilprojectspage_cilproject_1784193942" type="interface" identity="CILProject" parent="none"]
|
|
63
|
+
// CIL[DOC-MACRO purpose="Declare the CILProject data shape for project listing and management"]
|
|
64
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Provides the TypeScript contract for CIL project records including ingestion metadata"]
|
|
65
|
+
// CIL[DOC-CONTEXT module="cortex:cil-projects" layer="presentation" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/functions/_shared/principal.ts\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\"\\\"]"]
|
|
66
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="CILProject type definition" errors="none" side_effects="none"]
|
|
67
|
+
// CIL[DOC-MICRO logic_summary="Defines id, title, description, status, and nested data with repo, language mix, status, counts, cost, timestamps, source sets, and dependencies" notable_decisions="[]"]
|
|
68
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
69
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
70
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/pages/operations/OperationsDashboard.tsx, custom/apps/portal/pages/ContentPage.tsx, .framework/functions/_shared/principal.ts, .framework/src/pages/admin/TypeDetailPage.tsx, .framework/src/pages/admin/IntegrationsPage.tsx, \."]
|
|
71
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
72
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
73
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
74
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
75
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
76
|
+
interface CILProject {
|
|
77
|
+
id: string
|
|
78
|
+
title: string
|
|
79
|
+
description: string
|
|
80
|
+
status: string
|
|
81
|
+
data: {
|
|
82
|
+
repo_path: string
|
|
83
|
+
language_mix: string
|
|
84
|
+
ingestion_status: 'not_started' | 'in_progress' | 'complete'
|
|
85
|
+
file_count: number
|
|
86
|
+
chunk_count: number
|
|
87
|
+
total_ingestion_cost_usd: number
|
|
88
|
+
last_ingested_at: string | null
|
|
89
|
+
source_sets?: SourceSet[]
|
|
90
|
+
dependencies?: string[]
|
|
91
|
+
}
|
|
92
|
+
created_at: string
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// CIL[END chunk_id="cilprojectspage_cilproject_1784193942"]
|
|
96
|
+
// CIL[BEGIN chunk_id="cilprojectspage_status_badge_1784193942" type="constant" identity="STATUS_BADGE" parent="none"]
|
|
97
|
+
// CIL[DOC-MACRO purpose="Map ingestion status strings to badge labels and variants"]
|
|
98
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Supplies visual badge configuration for project ingestion status"]
|
|
99
|
+
// CIL[DOC-CONTEXT module="cortex:cil-projects" layer="presentation" related_files="[\".framework/src/pages/admin/RolesPage.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"\\\"]"]
|
|
100
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="STATUS_BADGE mapping" errors="none" side_effects="none"]
|
|
101
|
+
// CIL[DOC-MICRO logic_summary="Maps not_started, in_progress, and complete to label text and shadcn Badge variant values" notable_decisions="[]"]
|
|
102
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
103
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
104
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/RolesPage.tsx, custom/apps/portal/pages/ContentPage.tsx, custom/apps/cortex/functions/custom_cil-embeddings.ts, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, \."]
|
|
105
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
106
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
107
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
108
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
109
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
110
|
+
const STATUS_BADGE: Record<string, { label: string; variant: 'default' | 'secondary' | 'outline' }> = {
|
|
111
|
+
not_started: { label: 'Not Started', variant: 'outline' },
|
|
112
|
+
in_progress: { label: 'In Progress', variant: 'secondary' },
|
|
113
|
+
complete: { label: 'Complete', variant: 'default' },
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// CIL[END chunk_id="cilprojectspage_status_badge_1784193942"]
|
|
117
|
+
// CIL[BEGIN chunk_id="cilprojectspage_status_icon_1784193942" type="constant" identity="STATUS_ICON" parent="none"]
|
|
118
|
+
// CIL[DOC-MACRO purpose="Map ingestion status strings to icon components"]
|
|
119
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Supplies the icon component used for each project ingestion status"]
|
|
120
|
+
// CIL[DOC-CONTEXT module="cortex:cil-projects" layer="presentation" related_files="[]"]
|
|
121
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="STATUS_ICON mapping of React.ElementType" errors="none" side_effects="none"]
|
|
122
|
+
// CIL[DOC-MICRO logic_summary="Maps not_started to Clock, in_progress to AlertCircle, and complete to CheckCircle2" notable_decisions="[]"]
|
|
123
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
124
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
125
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
126
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
127
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
128
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
129
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
130
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
131
|
+
const STATUS_ICON: Record<string, React.ElementType> = {
|
|
132
|
+
not_started: Clock,
|
|
133
|
+
in_progress: AlertCircle,
|
|
134
|
+
complete: CheckCircle2,
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// CIL[END chunk_id="cilprojectspage_status_icon_1784193942"]
|
|
138
|
+
// CIL[BEGIN chunk_id="cilprojectspage_cilprojectspage_1784193942" type="component" identity="CILProjectsPage" parent="none"]
|
|
139
|
+
// CIL[DOC-MACRO purpose="Render the CIL projects list with creation, editing, and deletion workflows"]
|
|
140
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Manage CIL project list state and render project cards, dialogs, and navigation"]
|
|
141
|
+
// CIL[DOC-CONTEXT module="cortex:cil-projects" layer="presentation" related_files="[]"]
|
|
142
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="JSX.Element" errors="API errors are silently caught; required fields block save" side_effects="Calls /api/cil-project actions and navigates to /cil/:id routes"]
|
|
143
|
+
// CIL[DOC-MICRO logic_summary="Fetches projects on mount, displays loading/empty/card states, manages create/edit form with source sets, and navigates to ingest, dashboard, files, and graph pages" notable_decisions="[]"]
|
|
144
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
145
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
146
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
147
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
148
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
149
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
150
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
151
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
152
|
+
export default function CILProjectsPage() {
|
|
153
|
+
const navigate = useNavigate()
|
|
154
|
+
const appPath = (path: string) => '/spine-framework/admin' + (path.startsWith('/') ? path : '/' + path)
|
|
155
|
+
const [projects, setProjects] = useState<CILProject[]>([])
|
|
156
|
+
const [loading, setLoading] = useState(true)
|
|
157
|
+
const [showCreate, setShowCreate] = useState(false)
|
|
158
|
+
const [creating, setCreating] = useState(false)
|
|
159
|
+
const [confirmDeleteId, setConfirmDeleteId] = useState<string | null>(null)
|
|
160
|
+
const [deleting, setDeleting] = useState(false)
|
|
161
|
+
const [form, setForm] = useState({ name: '', description: '', repo_path: '', language_mix: '', source_sets: [] as SourceSet[] })
|
|
162
|
+
const [editingProjectId, setEditingProjectId] = useState<string | null>(null)
|
|
163
|
+
|
|
164
|
+
const fetchProjects = () => {
|
|
165
|
+
setLoading(true)
|
|
166
|
+
apiFetch('/api/cil-project?action=list')
|
|
167
|
+
.then(r => r.json())
|
|
168
|
+
.then(data => setProjects(data?.projects || data?.data?.projects || []))
|
|
169
|
+
.catch(() => {})
|
|
170
|
+
.finally(() => setLoading(false))
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
useEffect(() => { fetchProjects() }, [])
|
|
174
|
+
|
|
175
|
+
const handleSave = async () => {
|
|
176
|
+
if (!form.name || !form.repo_path) return
|
|
177
|
+
setCreating(true)
|
|
178
|
+
try {
|
|
179
|
+
const payload: Record<string, any> = {
|
|
180
|
+
name: form.name,
|
|
181
|
+
description: form.description,
|
|
182
|
+
repo_path: form.repo_path,
|
|
183
|
+
language_mix: form.language_mix,
|
|
184
|
+
}
|
|
185
|
+
if (form.source_sets && form.source_sets.length > 0) {
|
|
186
|
+
payload.source_sets = form.source_sets.map(ss => ({
|
|
187
|
+
...ss,
|
|
188
|
+
globs: ss.globs ? ss.globs.split(',').map(s => s.trim()).filter(Boolean) : undefined,
|
|
189
|
+
exclude_globs: ss.exclude_globs ? ss.exclude_globs.split(',').map(s => s.trim()).filter(Boolean) : undefined,
|
|
190
|
+
}))
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
let res: Response
|
|
194
|
+
if (editingProjectId) {
|
|
195
|
+
res = await apiFetch(`/api/cil-project?action=update&id=${editingProjectId}`, {
|
|
196
|
+
method: 'PATCH',
|
|
197
|
+
headers: { 'Content-Type': 'application/json' },
|
|
198
|
+
body: JSON.stringify({ data: payload }),
|
|
199
|
+
})
|
|
200
|
+
} else {
|
|
201
|
+
res = await apiFetch('/api/cil-project?action=create', {
|
|
202
|
+
method: 'POST',
|
|
203
|
+
headers: { 'Content-Type': 'application/json' },
|
|
204
|
+
body: JSON.stringify(payload),
|
|
205
|
+
})
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
const data = await res.json()
|
|
209
|
+
const newId = data?.project?.id || data?.data?.project?.id
|
|
210
|
+
setShowCreate(false)
|
|
211
|
+
setEditingProjectId(null)
|
|
212
|
+
setForm({ name: '', description: '', repo_path: '', language_mix: '', source_sets: [] })
|
|
213
|
+
if (newId && !editingProjectId) {
|
|
214
|
+
navigate(appPath(`/cil/${newId}/ingest`))
|
|
215
|
+
} else {
|
|
216
|
+
fetchProjects()
|
|
217
|
+
}
|
|
218
|
+
} catch {
|
|
219
|
+
} finally {
|
|
220
|
+
setCreating(false)
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const openCreate = () => {
|
|
225
|
+
setEditingProjectId(null)
|
|
226
|
+
setForm({ name: '', description: '', repo_path: '', language_mix: '', source_sets: [] })
|
|
227
|
+
setShowCreate(true)
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
const openEdit = (project: CILProject) => {
|
|
231
|
+
setEditingProjectId(project.id)
|
|
232
|
+
setForm({
|
|
233
|
+
name: project.title,
|
|
234
|
+
description: project.description,
|
|
235
|
+
repo_path: project.data?.repo_path || '',
|
|
236
|
+
language_mix: project.data?.language_mix || '',
|
|
237
|
+
source_sets: (project.data?.source_sets || []).map(ss => ({
|
|
238
|
+
...ss,
|
|
239
|
+
globs: Array.isArray(ss.globs) ? ss.globs.join(', ') : ss.globs || '',
|
|
240
|
+
exclude_globs: Array.isArray(ss.exclude_globs) ? ss.exclude_globs.join(', ') : ss.exclude_globs || '',
|
|
241
|
+
})),
|
|
242
|
+
})
|
|
243
|
+
openCreate()
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const handleDeleteProject = async () => {
|
|
247
|
+
if (!confirmDeleteId) return
|
|
248
|
+
setDeleting(true)
|
|
249
|
+
try {
|
|
250
|
+
await apiFetch(`/api/cil-project?action=delete&id=${confirmDeleteId}`, {
|
|
251
|
+
method: 'DELETE',
|
|
252
|
+
})
|
|
253
|
+
setConfirmDeleteId(null)
|
|
254
|
+
fetchProjects()
|
|
255
|
+
} catch {
|
|
256
|
+
} finally {
|
|
257
|
+
setDeleting(false)
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return (
|
|
262
|
+
<div className="p-6 space-y-6">
|
|
263
|
+
<div className="flex items-center justify-between">
|
|
264
|
+
<div>
|
|
265
|
+
<h1 className="text-2xl font-bold flex items-center gap-2">
|
|
266
|
+
<FolderGit2 className="h-6 w-6 text-indigo-500" />
|
|
267
|
+
Code Intelligence Layer
|
|
268
|
+
</h1>
|
|
269
|
+
<p className="text-muted-foreground text-sm mt-1">
|
|
270
|
+
Register codebases, run ingestion passes, and query the code graph
|
|
271
|
+
</p>
|
|
272
|
+
</div>
|
|
273
|
+
<Button onClick={() => openCreate()}>
|
|
274
|
+
<Plus className="h-4 w-4 mr-2" />
|
|
275
|
+
New Project
|
|
276
|
+
</Button>
|
|
277
|
+
</div>
|
|
278
|
+
|
|
279
|
+
<PageInstructions
|
|
280
|
+
description="Manage CIL projects and registered codebases."
|
|
281
|
+
sections={[
|
|
282
|
+
{ title: 'What this page is for', content: 'Projects represent codebases that the CIL has indexed. This page lists all projects, their ingestion status, and quick stats.' },
|
|
283
|
+
{ title: 'How to read this page', content: 'Each card shows the project title, repository path, status badge, and counts for files, chunks, and cumulative ingestion cost. Click a card to open the project.' },
|
|
284
|
+
{ title: 'How to create / manage', content: 'Click New Project to register a codebase. Open a project to run ingestion, inspect the graph, or use the agent. Use the dashboard or ingestion tabs for detailed status.' },
|
|
285
|
+
{ title: 'Important notes', content: 'The status badge reflects the latest ingestion pass. Costs are cumulative across all runs and include embedding and documentation generation.' },
|
|
286
|
+
]}
|
|
287
|
+
/>
|
|
288
|
+
|
|
289
|
+
{loading ? (
|
|
290
|
+
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
|
291
|
+
{[1, 2, 3].map(i => <Skeleton key={i} className="h-44 rounded-xl" />)}
|
|
292
|
+
</div>
|
|
293
|
+
) : projects.length === 0 ? (
|
|
294
|
+
<div className="flex flex-col items-center justify-center py-24 text-center space-y-3">
|
|
295
|
+
<FolderGit2 className="h-12 w-12 text-muted-foreground/40" />
|
|
296
|
+
<p className="text-muted-foreground">No projects yet. Register a codebase to get started.</p>
|
|
297
|
+
<Button variant="outline" onClick={() => openCreate()}>
|
|
298
|
+
<Plus className="h-4 w-4 mr-2" />
|
|
299
|
+
New Project
|
|
300
|
+
</Button>
|
|
301
|
+
</div>
|
|
302
|
+
) : (
|
|
303
|
+
<div className="grid grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
|
304
|
+
{projects.map(project => {
|
|
305
|
+
const ingestionStatus = project.data?.ingestion_status || 'not_started'
|
|
306
|
+
const { label, variant } = STATUS_BADGE[ingestionStatus] || STATUS_BADGE.not_started
|
|
307
|
+
const StatusIcon = STATUS_ICON[ingestionStatus] || Clock
|
|
308
|
+
|
|
309
|
+
return (
|
|
310
|
+
<Card
|
|
311
|
+
key={project.id}
|
|
312
|
+
className="cursor-pointer hover:shadow-md transition-shadow"
|
|
313
|
+
onClick={() => navigate(appPath(`/cil/${project.id}/ingest`))}
|
|
314
|
+
>
|
|
315
|
+
<CardHeader className="pb-2">
|
|
316
|
+
<div className="flex items-start justify-between gap-2">
|
|
317
|
+
<CardTitle className="text-base">{project.title}</CardTitle>
|
|
318
|
+
<Badge variant={variant} className="shrink-0 flex items-center gap-1">
|
|
319
|
+
<StatusIcon className="h-3 w-3" />
|
|
320
|
+
{label}
|
|
321
|
+
</Badge>
|
|
322
|
+
</div>
|
|
323
|
+
<p className="text-xs text-muted-foreground font-mono truncate">
|
|
324
|
+
{project.data?.repo_path || '—'}
|
|
325
|
+
</p>
|
|
326
|
+
</CardHeader>
|
|
327
|
+
<CardContent className="space-y-3">
|
|
328
|
+
{project.description && (
|
|
329
|
+
<p className="text-sm text-muted-foreground line-clamp-2">{project.description}</p>
|
|
330
|
+
)}
|
|
331
|
+
<div className="grid grid-cols-3 gap-2 pt-1">
|
|
332
|
+
<div className="text-center">
|
|
333
|
+
<div className="text-xl font-bold">{project.data?.file_count ?? 0}</div>
|
|
334
|
+
<div className="text-xs text-muted-foreground">Files</div>
|
|
335
|
+
</div>
|
|
336
|
+
<div className="text-center">
|
|
337
|
+
<div className="text-xl font-bold">{project.data?.chunk_count ?? 0}</div>
|
|
338
|
+
<div className="text-xs text-muted-foreground">Chunks</div>
|
|
339
|
+
</div>
|
|
340
|
+
<div className="text-center">
|
|
341
|
+
<div className="text-xl font-bold">
|
|
342
|
+
${(project.data?.total_ingestion_cost_usd ?? 0).toFixed(2)}
|
|
343
|
+
</div>
|
|
344
|
+
<div className="text-xs text-muted-foreground">Cost</div>
|
|
345
|
+
</div>
|
|
346
|
+
</div>
|
|
347
|
+
{project.data?.language_mix && (
|
|
348
|
+
<p className="text-xs text-muted-foreground">{project.data.language_mix}</p>
|
|
349
|
+
)}
|
|
350
|
+
<div className="flex gap-2">
|
|
351
|
+
<Button
|
|
352
|
+
size="sm"
|
|
353
|
+
variant="outline"
|
|
354
|
+
className="flex-1"
|
|
355
|
+
onClick={e => {
|
|
356
|
+
e.stopPropagation()
|
|
357
|
+
navigate(appPath(`/cil/${project.id}/ingest`))
|
|
358
|
+
}}
|
|
359
|
+
>
|
|
360
|
+
<Play className="h-3 w-3 mr-1" />
|
|
361
|
+
Run Pipeline
|
|
362
|
+
</Button>
|
|
363
|
+
<Button
|
|
364
|
+
size="sm"
|
|
365
|
+
variant="ghost"
|
|
366
|
+
className="px-2"
|
|
367
|
+
onClick={e => {
|
|
368
|
+
e.stopPropagation()
|
|
369
|
+
navigate(appPath(`/cil/${project.id}/dashboard`))
|
|
370
|
+
}}
|
|
371
|
+
title="Dashboard"
|
|
372
|
+
>
|
|
373
|
+
<LayoutDashboard className="h-3.5 w-3.5" />
|
|
374
|
+
</Button>
|
|
375
|
+
<Button
|
|
376
|
+
size="sm"
|
|
377
|
+
variant="ghost"
|
|
378
|
+
className="px-2"
|
|
379
|
+
onClick={e => {
|
|
380
|
+
e.stopPropagation()
|
|
381
|
+
navigate(appPath(`/cil/${project.id}/files`))
|
|
382
|
+
}}
|
|
383
|
+
title="Browse Files"
|
|
384
|
+
>
|
|
385
|
+
<Layers className="h-3.5 w-3.5" />
|
|
386
|
+
</Button>
|
|
387
|
+
<Button
|
|
388
|
+
size="sm"
|
|
389
|
+
variant="ghost"
|
|
390
|
+
className="px-2"
|
|
391
|
+
onClick={e => {
|
|
392
|
+
e.stopPropagation()
|
|
393
|
+
navigate(appPath(`/cil/${project.id}/graph`))
|
|
394
|
+
}}
|
|
395
|
+
title="View Graph"
|
|
396
|
+
>
|
|
397
|
+
<GitGraph className="h-3.5 w-3.5" />
|
|
398
|
+
</Button>
|
|
399
|
+
<Button
|
|
400
|
+
size="sm"
|
|
401
|
+
variant="ghost"
|
|
402
|
+
className="px-2"
|
|
403
|
+
onClick={e => {
|
|
404
|
+
e.stopPropagation()
|
|
405
|
+
openEdit(project)
|
|
406
|
+
}}
|
|
407
|
+
title="Edit project"
|
|
408
|
+
>
|
|
409
|
+
<Pencil className="h-3.5 w-3.5" />
|
|
410
|
+
</Button>
|
|
411
|
+
<Button
|
|
412
|
+
size="sm"
|
|
413
|
+
variant="ghost"
|
|
414
|
+
className="px-2 text-destructive hover:text-destructive hover:bg-destructive/10"
|
|
415
|
+
onClick={e => {
|
|
416
|
+
e.stopPropagation()
|
|
417
|
+
setConfirmDeleteId(project.id)
|
|
418
|
+
}}
|
|
419
|
+
title="Delete project"
|
|
420
|
+
>
|
|
421
|
+
<Trash2 className="h-3.5 w-3.5" />
|
|
422
|
+
</Button>
|
|
423
|
+
</div>
|
|
424
|
+
</CardContent>
|
|
425
|
+
</Card>
|
|
426
|
+
)
|
|
427
|
+
})}
|
|
428
|
+
</div>
|
|
429
|
+
)}
|
|
430
|
+
|
|
431
|
+
{}
|
|
432
|
+
<Dialog open={showCreate} onOpenChange={open => { if (!open) { setEditingProjectId(null); setForm({ name: '', description: '', repo_path: '', language_mix: '', source_sets: [] }) } setShowCreate(open) }}>
|
|
433
|
+
<DialogContent className="max-w-2xl max-h-[85vh] overflow-y-auto">
|
|
434
|
+
<DialogHeader>
|
|
435
|
+
<DialogTitle>{editingProjectId ? 'Edit CIL Project' : 'Register New CIL Project'}</DialogTitle>
|
|
436
|
+
</DialogHeader>
|
|
437
|
+
<div className="space-y-4 py-2">
|
|
438
|
+
<div className="space-y-1.5">
|
|
439
|
+
<Label htmlFor="name">Project Name *</Label>
|
|
440
|
+
<Input
|
|
441
|
+
id="name"
|
|
442
|
+
placeholder="spine-ia"
|
|
443
|
+
value={form.name}
|
|
444
|
+
onChange={e => setForm(f => ({ ...f, name: e.target.value }))}
|
|
445
|
+
/>
|
|
446
|
+
</div>
|
|
447
|
+
<div className="space-y-1.5">
|
|
448
|
+
<Label htmlFor="repo_path">Repository Path *</Label>
|
|
449
|
+
<Input
|
|
450
|
+
id="repo_path"
|
|
451
|
+
placeholder="/Users/thistle/CascadeProjects/spine-ia"
|
|
452
|
+
value={form.repo_path}
|
|
453
|
+
onChange={e => setForm(f => ({ ...f, repo_path: e.target.value }))}
|
|
454
|
+
/>
|
|
455
|
+
<p className="text-xs text-muted-foreground">Absolute path to the repository root on the agent's filesystem</p>
|
|
456
|
+
</div>
|
|
457
|
+
{editingProjectId && (
|
|
458
|
+
<>
|
|
459
|
+
<div className="space-y-1.5">
|
|
460
|
+
<Label htmlFor="language_mix">Languages</Label>
|
|
461
|
+
<Input
|
|
462
|
+
id="language_mix"
|
|
463
|
+
placeholder="TypeScript, SQL"
|
|
464
|
+
value={form.language_mix}
|
|
465
|
+
onChange={e => setForm(f => ({ ...f, language_mix: e.target.value }))}
|
|
466
|
+
/>
|
|
467
|
+
</div>
|
|
468
|
+
<div className="space-y-1.5">
|
|
469
|
+
<Label htmlFor="description">Description</Label>
|
|
470
|
+
<Textarea
|
|
471
|
+
id="description"
|
|
472
|
+
placeholder="Spine framework — multi-tenant SaaS platform"
|
|
473
|
+
value={form.description}
|
|
474
|
+
onChange={e => setForm(f => ({ ...f, description: e.target.value }))}
|
|
475
|
+
rows={3}
|
|
476
|
+
/>
|
|
477
|
+
</div>
|
|
478
|
+
</>
|
|
479
|
+
)}
|
|
480
|
+
|
|
481
|
+
{}
|
|
482
|
+
{editingProjectId && <div className="space-y-2 pt-2 border-t">
|
|
483
|
+
<div className="flex items-center justify-between">
|
|
484
|
+
<Label>Source Sets</Label>
|
|
485
|
+
<Button
|
|
486
|
+
type="button"
|
|
487
|
+
size="sm"
|
|
488
|
+
variant="outline"
|
|
489
|
+
onClick={() => setForm(f => ({
|
|
490
|
+
...f,
|
|
491
|
+
source_sets: [...f.source_sets, { id: crypto.randomUUID(), name: '', base_path: '', globs: '', exclude_globs: '', layer: 'app-specific' }],
|
|
492
|
+
}))}
|
|
493
|
+
>
|
|
494
|
+
<Plus className="h-3 w-3 mr-1" /> Add Source Set
|
|
495
|
+
</Button>
|
|
496
|
+
</div>
|
|
497
|
+
<p className="text-xs text-muted-foreground">
|
|
498
|
+
Optional. Leave empty to use the default globs. Each source set defines a base path relative to the repo root, its own globs/excludes, and an architectural layer.
|
|
499
|
+
</p>
|
|
500
|
+
{form.source_sets.length === 0 && (
|
|
501
|
+
<p className="text-xs text-muted-foreground italic">No source sets — default globs will be used.</p>
|
|
502
|
+
)}
|
|
503
|
+
{form.source_sets.map((ss, idx) => (
|
|
504
|
+
<div key={ss.id} className="border rounded-md p-3 space-y-2 bg-muted/30">
|
|
505
|
+
<div className="flex items-center justify-between gap-2">
|
|
506
|
+
<Input
|
|
507
|
+
placeholder="Set name"
|
|
508
|
+
value={ss.name}
|
|
509
|
+
onChange={e => setForm(f => {
|
|
510
|
+
const next = [...f.source_sets]
|
|
511
|
+
next[idx] = { ...next[idx], name: e.target.value }
|
|
512
|
+
return { ...f, source_sets: next }
|
|
513
|
+
})}
|
|
514
|
+
className="text-sm"
|
|
515
|
+
/>
|
|
516
|
+
<Button
|
|
517
|
+
type="button"
|
|
518
|
+
size="sm"
|
|
519
|
+
variant="ghost"
|
|
520
|
+
className="text-destructive hover:text-destructive hover:bg-destructive/10 shrink-0"
|
|
521
|
+
onClick={() => setForm(f => ({ ...f, source_sets: f.source_sets.filter((_, i) => i !== idx) }))}
|
|
522
|
+
>
|
|
523
|
+
<X className="h-3.5 w-3.5" />
|
|
524
|
+
</Button>
|
|
525
|
+
</div>
|
|
526
|
+
<div className="grid grid-cols-2 gap-2">
|
|
527
|
+
<Input
|
|
528
|
+
placeholder="Base path (relative to repo)"
|
|
529
|
+
value={ss.base_path}
|
|
530
|
+
onChange={e => setForm(f => {
|
|
531
|
+
const next = [...f.source_sets]
|
|
532
|
+
next[idx] = { ...next[idx], base_path: e.target.value }
|
|
533
|
+
return { ...f, source_sets: next }
|
|
534
|
+
})}
|
|
535
|
+
className="text-xs font-mono"
|
|
536
|
+
/>
|
|
537
|
+
<NativeSelect
|
|
538
|
+
value={ss.layer || 'app-specific'}
|
|
539
|
+
onChange={e => setForm(f => {
|
|
540
|
+
const next = [...f.source_sets]
|
|
541
|
+
next[idx] = { ...next[idx], layer: e.target.value }
|
|
542
|
+
return { ...f, source_sets: next }
|
|
543
|
+
})}
|
|
544
|
+
className="text-xs"
|
|
545
|
+
>
|
|
546
|
+
<NativeSelectOption value="shared-core">shared-core</NativeSelectOption>
|
|
547
|
+
<NativeSelectOption value="app-specific">app-specific</NativeSelectOption>
|
|
548
|
+
<NativeSelectOption value="infrastructure">infrastructure</NativeSelectOption>
|
|
549
|
+
<NativeSelectOption value="test">test</NativeSelectOption>
|
|
550
|
+
</NativeSelect>
|
|
551
|
+
</div>
|
|
552
|
+
<Input
|
|
553
|
+
placeholder="Globs, comma-separated (e.g. **/*.ts, **/*.tsx)"
|
|
554
|
+
value={ss.globs || ''}
|
|
555
|
+
onChange={e => setForm(f => {
|
|
556
|
+
const next = [...f.source_sets]
|
|
557
|
+
next[idx] = { ...next[idx], globs: e.target.value }
|
|
558
|
+
return { ...f, source_sets: next }
|
|
559
|
+
})}
|
|
560
|
+
className="text-xs font-mono"
|
|
561
|
+
/>
|
|
562
|
+
<Input
|
|
563
|
+
placeholder="Exclude globs, comma-separated (optional)"
|
|
564
|
+
value={ss.exclude_globs || ''}
|
|
565
|
+
onChange={e => setForm(f => {
|
|
566
|
+
const next = [...f.source_sets]
|
|
567
|
+
next[idx] = { ...next[idx], exclude_globs: e.target.value }
|
|
568
|
+
return { ...f, source_sets: next }
|
|
569
|
+
})}
|
|
570
|
+
className="text-xs font-mono"
|
|
571
|
+
/>
|
|
572
|
+
</div>
|
|
573
|
+
))}
|
|
574
|
+
</div>}
|
|
575
|
+
</div>
|
|
576
|
+
<DialogFooter>
|
|
577
|
+
<Button variant="outline" onClick={() => setShowCreate(false)}>Cancel</Button>
|
|
578
|
+
<Button
|
|
579
|
+
onClick={handleSave}
|
|
580
|
+
disabled={creating || !form.name || !form.repo_path}
|
|
581
|
+
>
|
|
582
|
+
{creating ? 'Saving…' : (editingProjectId ? 'Save Project' : 'Create Project')}
|
|
583
|
+
</Button>
|
|
584
|
+
</DialogFooter>
|
|
585
|
+
</DialogContent>
|
|
586
|
+
</Dialog>
|
|
587
|
+
|
|
588
|
+
{}
|
|
589
|
+
<Dialog open={!!confirmDeleteId} onOpenChange={open => { if (!open) setConfirmDeleteId(null) }}>
|
|
590
|
+
<DialogContent>
|
|
591
|
+
<DialogHeader>
|
|
592
|
+
<DialogTitle className="text-destructive flex items-center gap-2">
|
|
593
|
+
<Trash2 className="h-4 w-4" /> Delete Project
|
|
594
|
+
</DialogTitle>
|
|
595
|
+
</DialogHeader>
|
|
596
|
+
<p className="text-sm text-muted-foreground">
|
|
597
|
+
This will permanently delete the project and <strong>all associated files, chunks, proposals, embeddings, and graph links</strong>. This action cannot be undone.
|
|
598
|
+
</p>
|
|
599
|
+
<p className="text-sm font-medium">
|
|
600
|
+
Project: <span className="font-mono">{projects.find(p => p.id === confirmDeleteId)?.title || confirmDeleteId}</span>
|
|
601
|
+
</p>
|
|
602
|
+
<DialogFooter>
|
|
603
|
+
<Button variant="outline" onClick={() => setConfirmDeleteId(null)} disabled={deleting}>Cancel</Button>
|
|
604
|
+
<Button variant="destructive" onClick={handleDeleteProject} disabled={deleting}>
|
|
605
|
+
{deleting ? 'Deleting…' : 'Delete Project'}
|
|
606
|
+
</Button>
|
|
607
|
+
</DialogFooter>
|
|
608
|
+
</DialogContent>
|
|
609
|
+
</Dialog>
|
|
610
|
+
</div>
|
|
611
|
+
)
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
// CIL[END chunk_id="cilprojectspage_cilprojectspage_1784193942"]
|