spine-framework 0.3.125 → 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 +169 -97
- package/.framework/cli/commands/generate.ts +82 -160
- 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} +147 -54
- package/.framework/functions/_shared/db.ts +80 -126
- package/.framework/functions/_shared/hash-api-key.ts +63 -0
- package/.framework/functions/_shared/index.ts +222 -347
- 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 +162 -14
- 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 +687 -533
- 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 +173 -145
- 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 +192 -115
- 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 +3 -3
- 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,1402 @@
|
|
|
1
|
+
// CIL[BEGIN chunk_id="cilingestionpage_module_header_1784193942" type="module_header" identity="module_header" parent="none"]
|
|
2
|
+
// CIL[DOC-MACRO purpose="Import dependencies and icons for the CIL ingestion page"]
|
|
3
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Provides React hooks, router, apiFetch, app path hook, UI components, and lucide icons used by the page"]
|
|
4
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\"custom/apps/portal/pages/ContentPage.tsx\",\".framework/src/pages/admin/TypeDetailPage.tsx\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\".framework/functions/_shared/principal.ts\",\"\\\"]"]
|
|
5
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="module imports" errors="none" side_effects="none"]
|
|
6
|
+
// CIL[DOC-MICRO logic_summary="Sets up external dependencies and icon imports required by CILIngestionPage and child functions" 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, custom/apps/cortex/functions/custom_cil-embeddings.ts, .framework/functions/_shared/principal.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"]
|
|
16
|
+
import { useEffect, useState, useCallback } from 'react'
|
|
17
|
+
import { useParams } 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 { Tooltip, TooltipContent, TooltipTrigger } from '@core/components/ui/tooltip'
|
|
24
|
+
import { Input } from '@core/components/ui/input'
|
|
25
|
+
import { Label } from '@core/components/ui/label'
|
|
26
|
+
import { Progress } from '@core/components/ui/progress'
|
|
27
|
+
import {
|
|
28
|
+
CheckCircle2,
|
|
29
|
+
ChevronRight,
|
|
30
|
+
ChevronDown,
|
|
31
|
+
Folder,
|
|
32
|
+
FolderOpen,
|
|
33
|
+
FileText,
|
|
34
|
+
RefreshCw,
|
|
35
|
+
Play,
|
|
36
|
+
FileCode2,
|
|
37
|
+
MousePointerClick,
|
|
38
|
+
Code2,
|
|
39
|
+
BookOpen,
|
|
40
|
+
Zap,
|
|
41
|
+
GitGraph,
|
|
42
|
+
Sparkles,
|
|
43
|
+
Layers,
|
|
44
|
+
Network,
|
|
45
|
+
Info,
|
|
46
|
+
Save,
|
|
47
|
+
Settings2,
|
|
48
|
+
Copy,
|
|
49
|
+
Check,
|
|
50
|
+
} from 'lucide-react'
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
import { PageInstructions } from '../../../components/admin/PageInstructions'
|
|
55
|
+
// CIL[END chunk_id="cilingestionpage_module_header_1784193942"]
|
|
56
|
+
// CIL[BEGIN chunk_id="cilingestionpage_cilfilestatus_1784193942" type="type" identity="CilFileStatus" parent="none"]
|
|
57
|
+
// CIL[DOC-MACRO purpose="Define the union of possible CIL file pipeline statuses"]
|
|
58
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Declares the string-literal type for file ingestion pipeline stages"]
|
|
59
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
|
|
60
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="CilFileStatus type alias" errors="none" side_effects="none"]
|
|
61
|
+
// CIL[DOC-MICRO logic_summary="Lists ordered statuses from 2-discovered through 10-mapped" notable_decisions="[]"]
|
|
62
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
63
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
64
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: custom/apps/cortex/functions/custom_cil-embeddings.ts, .framework/functions/_shared/principal.ts, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/schema-utils.ts, \."]
|
|
65
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
66
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
67
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
68
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
69
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
70
|
+
type CilFileStatus =
|
|
71
|
+
| '2-discovered'
|
|
72
|
+
| '3-selected'
|
|
73
|
+
| '4-chunked'
|
|
74
|
+
| '5-documented'
|
|
75
|
+
| '6-embedded'
|
|
76
|
+
| '7-mapped'
|
|
77
|
+
| '8-enriched'
|
|
78
|
+
| '9-embedded'
|
|
79
|
+
| '10-mapped'
|
|
80
|
+
|
|
81
|
+
// CIL[END chunk_id="cilingestionpage_cilfilestatus_1784193942"]
|
|
82
|
+
// CIL[BEGIN chunk_id="cilingestionpage_filetreenode_1784193942" type="interface" identity="FileTreeNode" parent="none"]
|
|
83
|
+
// CIL[DOC-MACRO purpose="Define the recursive file tree node data shape"]
|
|
84
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Provides a TypeScript contract for files and directories in the project tree"]
|
|
85
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
|
|
86
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="FileTreeNode interface definition" errors="none" side_effects="none"]
|
|
87
|
+
// CIL[DOC-MICRO logic_summary="Describes id, name, path, type, extension, optional status, and children array" notable_decisions="[]"]
|
|
88
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
89
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
90
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/principal.ts, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/functions/_shared/schema-utils.ts, \."]
|
|
91
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
92
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
93
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
94
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
95
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
96
|
+
interface FileTreeNode {
|
|
97
|
+
id?: string | null
|
|
98
|
+
name: string
|
|
99
|
+
path: string
|
|
100
|
+
type: 'file' | 'directory'
|
|
101
|
+
extension?: string
|
|
102
|
+
status?: CilFileStatus
|
|
103
|
+
children?: FileTreeNode[]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// CIL[END chunk_id="cilingestionpage_filetreenode_1784193942"]
|
|
107
|
+
// CIL[BEGIN chunk_id="cilingestionpage_project_1784193942" type="interface" identity="Project" parent="none"]
|
|
108
|
+
// CIL[DOC-MACRO purpose="Define the CIL project record data shape"]
|
|
109
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Declares the TypeScript contract for a project including repo path, globs, file tree, and statuses"]
|
|
110
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[\".framework/src/pages/admin/IntegrationsPage.tsx\",\"custom/apps/cortex/functions/custom_cil-embeddings.ts\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
|
|
111
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="Project interface definition" errors="none" side_effects="none"]
|
|
112
|
+
// CIL[DOC-MICRO logic_summary="Contains id, title, and data object with repo_path, ingestion_status, counts, globs, file_tree, selected_paths, and file_statuses" notable_decisions="[]"]
|
|
113
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
114
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
115
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/IntegrationsPage.tsx, custom/apps/cortex/functions/custom_cil-embeddings.ts, .framework/functions/_shared/principal.ts, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/functions/_shared/schema-utils.ts, \."]
|
|
116
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
117
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
118
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
119
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
120
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
121
|
+
interface Project {
|
|
122
|
+
id: string
|
|
123
|
+
title: string
|
|
124
|
+
data: {
|
|
125
|
+
repo_path: string
|
|
126
|
+
ingestion_status?: string
|
|
127
|
+
file_count?: number
|
|
128
|
+
chunk_count?: number
|
|
129
|
+
total_ingestion_cost_usd?: number
|
|
130
|
+
last_ingested_at?: string | null
|
|
131
|
+
globs?: string[]
|
|
132
|
+
exclude_globs?: string[]
|
|
133
|
+
file_tree?: FileTreeNode
|
|
134
|
+
selected_paths?: string[]
|
|
135
|
+
file_statuses?: Record<string, string>
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// CIL[END chunk_id="cilingestionpage_project_1784193942"]
|
|
140
|
+
// CIL[BEGIN chunk_id="cilingestionpage_projectconfig_1784193942" type="interface" identity="ProjectConfig" parent="none"]
|
|
141
|
+
// CIL[DOC-MACRO purpose="Define the editable project configuration data shape"]
|
|
142
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Provides a TypeScript contract for repo path, include/exclude globs, and force reprocess flag"]
|
|
143
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[\".framework/src/pages/admin/IntegrationsPage.tsx\",\".framework/functions/_shared/principal.ts\",\"custom/apps/cortex/pages/operations/OperationsDashboard.tsx\",\".framework/functions/_shared/schema-utils.ts\",\"\\\"]"]
|
|
144
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="ProjectConfig interface definition" errors="none" side_effects="none"]
|
|
145
|
+
// CIL[DOC-MICRO logic_summary="Declares repo_path, globs, exclude_globs, and force_reprocess fields" notable_decisions="[]"]
|
|
146
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
147
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
148
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: .framework/src/pages/admin/IntegrationsPage.tsx, .framework/functions/_shared/principal.ts, custom/apps/cortex/pages/operations/OperationsDashboard.tsx, .framework/functions/_shared/schema-utils.ts, \."]
|
|
149
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
150
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
151
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
152
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
153
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
154
|
+
interface ProjectConfig {
|
|
155
|
+
repo_path: string
|
|
156
|
+
globs: string
|
|
157
|
+
exclude_globs: string
|
|
158
|
+
force_reprocess: boolean
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// CIL[END chunk_id="cilingestionpage_projectconfig_1784193942"]
|
|
162
|
+
// CIL[BEGIN chunk_id="cilingestionpage_pipelineprogress_1784193942" type="interface" identity="PipelineProgress" parent="none"]
|
|
163
|
+
// CIL[DOC-MACRO purpose="Define the pipeline progress summary data shape"]
|
|
164
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Provides a TypeScript contract for total selected files, status counts, and total chunks"]
|
|
165
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[]"]
|
|
166
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="PipelineProgress interface definition" errors="none" side_effects="none"]
|
|
167
|
+
// CIL[DOC-MICRO logic_summary="Declares total_selected, by_status record, and total_chunks" notable_decisions="[]"]
|
|
168
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
169
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
170
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
171
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
172
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
173
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
174
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
175
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
176
|
+
interface PipelineProgress {
|
|
177
|
+
total_selected: number
|
|
178
|
+
by_status: Record<string, number>
|
|
179
|
+
total_chunks: number
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
// CIL[END chunk_id="cilingestionpage_pipelineprogress_1784193942"]
|
|
187
|
+
// CIL[BEGIN chunk_id="cilingestionpage_status_color_1784193942" type="constant" identity="STATUS_COLOR" parent="none"]
|
|
188
|
+
// CIL[DOC-MACRO purpose="Map each CIL file status to a Tailwind CSS color class string"]
|
|
189
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Supplies visual badge color classes for pipeline status labels"]
|
|
190
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[]"]
|
|
191
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="STATUS_COLOR record" errors="none" side_effects="none"]
|
|
192
|
+
// CIL[DOC-MICRO logic_summary="Maps each CilFileStatus value to a background/text color combination used by status badges" notable_decisions="[]"]
|
|
193
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
194
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
195
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
196
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
197
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
198
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
199
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
200
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
201
|
+
const STATUS_COLOR: Record<CilFileStatus, string> = {
|
|
202
|
+
'2-discovered': 'bg-gray-100 text-gray-600',
|
|
203
|
+
'3-selected': 'bg-indigo-100 text-indigo-700',
|
|
204
|
+
'4-chunked': 'bg-blue-100 text-blue-700',
|
|
205
|
+
'5-documented': 'bg-purple-100 text-purple-700',
|
|
206
|
+
'6-embedded': 'bg-green-100 text-green-700',
|
|
207
|
+
'7-mapped': 'bg-teal-100 text-teal-700',
|
|
208
|
+
'8-enriched': 'bg-violet-100 text-violet-700',
|
|
209
|
+
'9-embedded': 'bg-emerald-100 text-emerald-700',
|
|
210
|
+
'10-mapped': 'bg-amber-100 text-amber-700',
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// CIL[END chunk_id="cilingestionpage_status_color_1784193942"]
|
|
214
|
+
// CIL[BEGIN chunk_id="cilingestionpage_pipelinestep_1784193942" type="interface" identity="PipelineStep" parent="none"]
|
|
215
|
+
// CIL[DOC-MACRO purpose="Define the pipeline step descriptor data shape"]
|
|
216
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Provides a TypeScript contract for a single CIL pipeline step"]
|
|
217
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[]"]
|
|
218
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="PipelineStep interface definition" errors="none" side_effects="none"]
|
|
219
|
+
// CIL[DOC-MICRO logic_summary="Declares number, key, label, description, icon, agentInstruction, optional command, targetStatus, and optional sourceStatus" notable_decisions="[]"]
|
|
220
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
221
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
222
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
223
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
224
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
225
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
226
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
227
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
228
|
+
interface PipelineStep {
|
|
229
|
+
number: number
|
|
230
|
+
key: string
|
|
231
|
+
label: string
|
|
232
|
+
description: string
|
|
233
|
+
icon: React.ElementType
|
|
234
|
+
agentInstruction: string
|
|
235
|
+
command?: string
|
|
236
|
+
targetStatus: CilFileStatus
|
|
237
|
+
sourceStatus?: CilFileStatus
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// CIL[END chunk_id="cilingestionpage_pipelinestep_1784193942"]
|
|
241
|
+
// CIL[BEGIN chunk_id="cilingestionpage_pipeline_steps_1784193942" type="constant" identity="PIPELINE_STEPS" parent="none"]
|
|
242
|
+
// CIL[DOC-MACRO purpose="List all pipeline steps in order for the CIL ingestion UI"]
|
|
243
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Supplies step definitions, icons, labels, instructions, and target statuses used by the pipeline view"]
|
|
244
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[]"]
|
|
245
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="PIPELINE_STEPS array" errors="none" side_effects="none"]
|
|
246
|
+
// CIL[DOC-MICRO logic_summary="Defines 10 steps from project creation through second-pass mapping with associated icons, commands, and target statuses" notable_decisions="[]"]
|
|
247
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
248
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
249
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
250
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
251
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
252
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
253
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
254
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
255
|
+
const PIPELINE_STEPS: PipelineStep[] = [
|
|
256
|
+
{
|
|
257
|
+
number: 1,
|
|
258
|
+
key: 'create',
|
|
259
|
+
label: 'Create Project',
|
|
260
|
+
description: 'Project and repo path configured',
|
|
261
|
+
icon: FileCode2,
|
|
262
|
+
agentInstruction: 'Create a new CIL project in Cortex with the repository path set.',
|
|
263
|
+
targetStatus: '0-discovered',
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
number: 2,
|
|
267
|
+
key: 'build_tree',
|
|
268
|
+
label: 'Build File Tree',
|
|
269
|
+
description: 'Scan repository, build complete file structure',
|
|
270
|
+
icon: Folder,
|
|
271
|
+
agentInstruction: 'Run Pass 1 to walk the repository and discover all files. Use the "Run Pass 1" button or tell Devin: "Scan the repo and build the file tree."',
|
|
272
|
+
targetStatus: '0-discovered',
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
number: 3,
|
|
276
|
+
key: 'select',
|
|
277
|
+
label: 'Select Files',
|
|
278
|
+
description: 'Choose which files to process',
|
|
279
|
+
icon: MousePointerClick,
|
|
280
|
+
agentInstruction: 'Select files in the tree on the right. Click individual files, directories, or use Devin: "Select all TypeScript files in .framework/cli/".',
|
|
281
|
+
targetStatus: '3-selected',
|
|
282
|
+
sourceStatus: '2-discovered',
|
|
283
|
+
},
|
|
284
|
+
{
|
|
285
|
+
number: 4,
|
|
286
|
+
key: 'chunk',
|
|
287
|
+
label: 'Chunk',
|
|
288
|
+
description: 'Strip comments, apply fresh CIL markers',
|
|
289
|
+
icon: Code2,
|
|
290
|
+
agentInstruction: 'Tell Devin: "Chunk the selected files." Devin will strip all existing comments, analyze the code structure, and apply clean CIL[BEGIN]/CIL[END] markers ensuring 100% line coverage.',
|
|
291
|
+
command: '/cil-chunk',
|
|
292
|
+
targetStatus: '4-chunked',
|
|
293
|
+
sourceStatus: '3-selected',
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
number: 5,
|
|
297
|
+
key: 'document',
|
|
298
|
+
label: 'Document',
|
|
299
|
+
description: 'Generate single-file context documentation',
|
|
300
|
+
icon: BookOpen,
|
|
301
|
+
agentInstruction: 'Tell Devin: "Document the chunked files." Devin will generate standardized inline documentation for each chunk using only single-file context.',
|
|
302
|
+
command: '/cil-document',
|
|
303
|
+
targetStatus: '5-documented',
|
|
304
|
+
sourceStatus: '4-chunked',
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
number: 6,
|
|
308
|
+
key: 'first_pass_embed',
|
|
309
|
+
label: 'Embed (1st pass)',
|
|
310
|
+
description: 'Generate 3 basic vectors per chunk',
|
|
311
|
+
icon: Zap,
|
|
312
|
+
agentInstruction: 'Run from the pipeline UI — this step is not Devin-triggered. Click the Run button on Step 6.',
|
|
313
|
+
targetStatus: '6-embedded',
|
|
314
|
+
sourceStatus: '5-documented',
|
|
315
|
+
},
|
|
316
|
+
{
|
|
317
|
+
number: 7,
|
|
318
|
+
key: 'first_pass_map',
|
|
319
|
+
label: 'Map (1st pass)',
|
|
320
|
+
description: 'Create basic relationship mappings',
|
|
321
|
+
icon: GitGraph,
|
|
322
|
+
agentInstruction: 'Run from the pipeline UI — this step is not Devin-triggered. Click the Run button on Step 7.',
|
|
323
|
+
targetStatus: '7-mapped',
|
|
324
|
+
sourceStatus: '6-embedded',
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
number: 8,
|
|
328
|
+
key: 'enrich',
|
|
329
|
+
label: 'Enrich',
|
|
330
|
+
description: 'RAG enrichment with multi-file context',
|
|
331
|
+
icon: Sparkles,
|
|
332
|
+
agentInstruction: 'Tell Devin: "Enrich the documented files." Devin will perform RAG queries to discover cross-file relationships and enrich documentation with multi-file context. Requires Steps 6 and 7 to be complete.',
|
|
333
|
+
command: '/cil-enrich',
|
|
334
|
+
targetStatus: '8-enriched',
|
|
335
|
+
sourceStatus: '7-mapped',
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
number: 9,
|
|
339
|
+
key: 'second_pass_embed',
|
|
340
|
+
label: 'Embed (2nd pass)',
|
|
341
|
+
description: 'Generate 9 specialized vectors per chunk',
|
|
342
|
+
icon: Layers,
|
|
343
|
+
agentInstruction: 'Run from the pipeline UI — this step is not Devin-triggered. Click the Run button on Step 9.',
|
|
344
|
+
targetStatus: '9-embedded',
|
|
345
|
+
sourceStatus: '8-enriched',
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
number: 10,
|
|
349
|
+
key: 'second_pass_map',
|
|
350
|
+
label: 'Map (2nd pass)',
|
|
351
|
+
description: 'Enhanced relationship mapping',
|
|
352
|
+
icon: Network,
|
|
353
|
+
agentInstruction: 'Run from the pipeline UI — this step is not Devin-triggered. Click the Run button on Step 10.',
|
|
354
|
+
targetStatus: '10-mapped',
|
|
355
|
+
sourceStatus: '9-embedded',
|
|
356
|
+
},
|
|
357
|
+
]
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
// CIL[END chunk_id="cilingestionpage_pipeline_steps_1784193942"]
|
|
362
|
+
// CIL[BEGIN chunk_id="cilingestionpage_collectalldirpaths_1784193942" type="function" identity="collectAllDirPaths" parent="none"]
|
|
363
|
+
// CIL[DOC-MACRO purpose="Recursively collect the paths of all directories in the file tree"]
|
|
364
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Returns a flat array of directory paths for initial expansion"]
|
|
365
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[]"]
|
|
366
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="string[]" errors="none" side_effects="none"]
|
|
367
|
+
// CIL[DOC-MICRO logic_summary="If node is a directory, include its path, then recurse through children" notable_decisions="[]"]
|
|
368
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
369
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
370
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
371
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
372
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
373
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
374
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
375
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
376
|
+
function collectAllDirPaths(node: FileTreeNode): string[] {
|
|
377
|
+
const paths: string[] = node.type === 'directory' ? [node.path] : []
|
|
378
|
+
if (node.children) {
|
|
379
|
+
for (const child of node.children) paths.push(...collectAllDirPaths(child))
|
|
380
|
+
}
|
|
381
|
+
return paths
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// CIL[END chunk_id="cilingestionpage_collectalldirpaths_1784193942"]
|
|
385
|
+
// CIL[BEGIN chunk_id="cilingestionpage_countfilesintree_1784193942" type="function" identity="countFilesInTree" parent="none"]
|
|
386
|
+
// CIL[DOC-MACRO purpose="Count all file leaves in a file tree recursively"]
|
|
387
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Returns the total number of file nodes under the given tree node"]
|
|
388
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[]"]
|
|
389
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="number" errors="none" side_effects="none"]
|
|
390
|
+
// CIL[DOC-MICRO logic_summary="Returns 1 for files and sums counts of children for directories" notable_decisions="[]"]
|
|
391
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
392
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
393
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
394
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
395
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
396
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
397
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
398
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
399
|
+
function countFilesInTree(node: FileTreeNode): number {
|
|
400
|
+
if (node.type === 'file') return 1
|
|
401
|
+
return (node.children || []).reduce((acc, c) => acc + countFilesInTree(c), 0)
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// CIL[END chunk_id="cilingestionpage_countfilesintree_1784193942"]
|
|
405
|
+
// CIL[BEGIN chunk_id="cilingestionpage_getfilestatus_1784193942" type="function" identity="getFileStatus" parent="none"]
|
|
406
|
+
// CIL[DOC-MACRO purpose="Resolve the pipeline status for a single file path"]
|
|
407
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Maps a file path to its explicit status, selected status, or discovered status"]
|
|
408
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[]"]
|
|
409
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="CilFileStatus" errors="none" side_effects="none"]
|
|
410
|
+
// CIL[DOC-MICRO logic_summary="Returns explicit status if present, '3-selected' if path is selected, otherwise '2-discovered'" notable_decisions="[]"]
|
|
411
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
412
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
413
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
414
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
415
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
416
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
417
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
418
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
419
|
+
function getFileStatus(path: string, fileStatuses: Record<string, string>, selectedPaths: string[]): CilFileStatus {
|
|
420
|
+
const explicit = fileStatuses[path] as CilFileStatus | undefined
|
|
421
|
+
if (explicit) return explicit
|
|
422
|
+
|
|
423
|
+
if (selectedPaths.includes(path)) return '3-selected'
|
|
424
|
+
return '2-discovered'
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
|
|
428
|
+
// CIL[END chunk_id="cilingestionpage_getfilestatus_1784193942"]
|
|
429
|
+
// CIL[BEGIN chunk_id="cilingestionpage_countselectedleaves_1784193942" type="function" identity="countSelectedLeaves" parent="none"]
|
|
430
|
+
// CIL[DOC-MACRO purpose="Count selected file leaves under a tree node"]
|
|
431
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Returns the number of selected file nodes in the subtree"]
|
|
432
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[]"]
|
|
433
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="number" errors="none" side_effects="none"]
|
|
434
|
+
// CIL[DOC-MICRO logic_summary="For files checks inclusion in selectedPaths; for directories sums child counts" notable_decisions="[]"]
|
|
435
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
436
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
437
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
438
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
439
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
440
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
441
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
442
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
443
|
+
function countSelectedLeaves(node: FileTreeNode, selectedPaths: string[]): number {
|
|
444
|
+
if (node.type === 'file') return selectedPaths.includes(node.path) ? 1 : 0
|
|
445
|
+
return (node.children || []).reduce((sum, c) => sum + countSelectedLeaves(c, selectedPaths), 0)
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
// CIL[END chunk_id="cilingestionpage_countselectedleaves_1784193942"]
|
|
450
|
+
// CIL[BEGIN chunk_id="cilingestionpage_countleaves_1784193942" type="function" identity="countLeaves" parent="none"]
|
|
451
|
+
// CIL[DOC-MACRO purpose="Count all file leaves under a tree node"]
|
|
452
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Returns the total number of file nodes in the subtree"]
|
|
453
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[]"]
|
|
454
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="number" errors="none" side_effects="none"]
|
|
455
|
+
// CIL[DOC-MICRO logic_summary="Returns 1 for files and recursively sums child leaf counts for directories" notable_decisions="[]"]
|
|
456
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
457
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
458
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
459
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
460
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
461
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
462
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
463
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
464
|
+
function countLeaves(node: FileTreeNode): number {
|
|
465
|
+
if (node.type === 'file') return 1
|
|
466
|
+
return (node.children || []).reduce((sum, c) => sum + countLeaves(c), 0)
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
// CIL[END chunk_id="cilingestionpage_countleaves_1784193942"]
|
|
472
|
+
// CIL[BEGIN chunk_id="cilingestionpage_treenode_1784193942" type="function" identity="TreeNode" parent="none"]
|
|
473
|
+
// CIL[DOC-MACRO purpose="Render a single file tree node with selection, expansion, and status"]
|
|
474
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Displays a directory or file row, handles expand/collapse, selection toggling, and status badges"]
|
|
475
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[]"]
|
|
476
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="JSX.Element" errors="none" side_effects="Updates UI state via parent callbacks"]
|
|
477
|
+
// CIL[DOC-MICRO logic_summary="Computes selection and expansion state, renders folder/file icons, checkbox, name, status badge, and recursively renders children" notable_decisions="[]"]
|
|
478
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
479
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
480
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
481
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
482
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
483
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
484
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
485
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
486
|
+
function TreeNode({
|
|
487
|
+
node,
|
|
488
|
+
selectedPaths,
|
|
489
|
+
expandedPaths,
|
|
490
|
+
fileStatuses,
|
|
491
|
+
onToggleSelect,
|
|
492
|
+
onToggleExpand,
|
|
493
|
+
depth = 0,
|
|
494
|
+
}: {
|
|
495
|
+
node: FileTreeNode
|
|
496
|
+
selectedPaths: string[]
|
|
497
|
+
expandedPaths: Set<string>
|
|
498
|
+
fileStatuses: Record<string, string>
|
|
499
|
+
onToggleSelect: (path: string, isDir: boolean, children?: FileTreeNode[]) => void
|
|
500
|
+
onToggleExpand: (path: string) => void
|
|
501
|
+
depth?: number
|
|
502
|
+
}) {
|
|
503
|
+
const isDir = node.type === 'directory'
|
|
504
|
+
const isExpanded = expandedPaths.has(node.path)
|
|
505
|
+
const isSelected = selectedPaths.includes(node.path)
|
|
506
|
+
const hasChildren = isDir && (node.children?.length || 0) > 0
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
const selectedLeafCount = isDir ? countSelectedLeaves(node, selectedPaths) : 0
|
|
510
|
+
const totalLeafCount = isDir ? countLeaves(node) : 0
|
|
511
|
+
const isIndeterminate = isDir && !isSelected && selectedLeafCount > 0 && selectedLeafCount < totalLeafCount
|
|
512
|
+
const isAllSelected = isDir && !isSelected && totalLeafCount > 0 && selectedLeafCount === totalLeafCount
|
|
513
|
+
|
|
514
|
+
const fileStatus = !isDir ? getFileStatus(node.path, fileStatuses, selectedPaths) : undefined
|
|
515
|
+
const statusLabel = fileStatus && fileStatus !== '2-discovered' ? fileStatus : undefined
|
|
516
|
+
const statusColor = fileStatus ? STATUS_COLOR[fileStatus] : undefined
|
|
517
|
+
|
|
518
|
+
return (
|
|
519
|
+
<div>
|
|
520
|
+
<div
|
|
521
|
+
className="flex items-center gap-1 py-0.5 px-1 rounded hover:bg-muted/50"
|
|
522
|
+
style={{ paddingLeft: `${depth * 16 + 4}px` }}
|
|
523
|
+
>
|
|
524
|
+
{}
|
|
525
|
+
{hasChildren ? (
|
|
526
|
+
<button
|
|
527
|
+
onClick={e => { e.stopPropagation(); onToggleExpand(node.path) }}
|
|
528
|
+
className="p-0.5 rounded hover:bg-muted shrink-0"
|
|
529
|
+
>
|
|
530
|
+
{isExpanded ? <ChevronDown className="h-3 w-3" /> : <ChevronRight className="h-3 w-3" />}
|
|
531
|
+
</button>
|
|
532
|
+
) : (
|
|
533
|
+
<span className="w-4 shrink-0" />
|
|
534
|
+
)}
|
|
535
|
+
|
|
536
|
+
{}
|
|
537
|
+
<div
|
|
538
|
+
className="flex items-center gap-1.5 flex-1 min-w-0 cursor-pointer"
|
|
539
|
+
onClick={() => onToggleSelect(node.path, isDir, node.children)}
|
|
540
|
+
>
|
|
541
|
+
{}
|
|
542
|
+
<div className={`h-3.5 w-3.5 rounded border flex items-center justify-center shrink-0 ${
|
|
543
|
+
isSelected || isAllSelected
|
|
544
|
+
? 'bg-indigo-500 border-indigo-500'
|
|
545
|
+
: isIndeterminate
|
|
546
|
+
? 'border-indigo-500 bg-indigo-50'
|
|
547
|
+
: 'border-muted-foreground'
|
|
548
|
+
}`}>
|
|
549
|
+
{(isSelected || isAllSelected) && <CheckCircle2 className="h-2.5 w-2.5 text-white" />}
|
|
550
|
+
{isIndeterminate && <div className="h-1.5 w-1.5 bg-indigo-500 rounded-sm" />}
|
|
551
|
+
</div>
|
|
552
|
+
|
|
553
|
+
{}
|
|
554
|
+
{isDir
|
|
555
|
+
? isExpanded
|
|
556
|
+
? <FolderOpen className={`h-3.5 w-3.5 shrink-0 ${isSelected || isAllSelected || isIndeterminate ? 'text-indigo-500' : 'text-amber-500'}`} />
|
|
557
|
+
: <Folder className={`h-3.5 w-3.5 shrink-0 ${isSelected || isAllSelected || isIndeterminate ? 'text-indigo-500' : 'text-amber-500'}`} />
|
|
558
|
+
: <FileText className="h-3.5 w-3.5 text-slate-400 shrink-0" />
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
{}
|
|
562
|
+
<span className={`text-xs truncate ${isSelected || isAllSelected || isIndeterminate ? 'text-indigo-700 dark:text-indigo-300 font-medium' : ''}`}>
|
|
563
|
+
{node.name}
|
|
564
|
+
</span>
|
|
565
|
+
|
|
566
|
+
{}
|
|
567
|
+
{statusLabel && statusColor && (
|
|
568
|
+
<span className={`shrink-0 text-[10px] px-1.5 py-0.5 rounded-full ${statusColor}`}>
|
|
569
|
+
{statusLabel}
|
|
570
|
+
</span>
|
|
571
|
+
)}
|
|
572
|
+
</div>
|
|
573
|
+
</div>
|
|
574
|
+
|
|
575
|
+
{isExpanded && node.children?.map(child => (
|
|
576
|
+
<TreeNode
|
|
577
|
+
key={child.path}
|
|
578
|
+
node={child}
|
|
579
|
+
selectedPaths={selectedPaths}
|
|
580
|
+
expandedPaths={expandedPaths}
|
|
581
|
+
fileStatuses={fileStatuses}
|
|
582
|
+
onToggleSelect={onToggleSelect}
|
|
583
|
+
onToggleExpand={onToggleExpand}
|
|
584
|
+
depth={depth + 1}
|
|
585
|
+
/>
|
|
586
|
+
))}
|
|
587
|
+
</div>
|
|
588
|
+
)
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
// CIL[END chunk_id="cilingestionpage_treenode_1784193942"]
|
|
594
|
+
// CIL[BEGIN chunk_id="cilingestionpage_steprow_1784193942" type="function" identity="StepRow" parent="none"]
|
|
595
|
+
// CIL[DOC-MACRO purpose="Render a pipeline step row with status, command copy, and run action"]
|
|
596
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Displays step metadata, completion/partial state, command copy button, and run button"]
|
|
597
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[]"]
|
|
598
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="JSX.Element" errors="none" side_effects="Writes command text to clipboard and triggers onRun callback"]
|
|
599
|
+
// CIL[DOC-MICRO logic_summary="Determines done and partial states, renders step icon, label, progress badge, description, copyable command, info tooltip, and run button" notable_decisions="[]"]
|
|
600
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
601
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
602
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
603
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
604
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
605
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
606
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
607
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
608
|
+
function StepRow({
|
|
609
|
+
step,
|
|
610
|
+
fileCount,
|
|
611
|
+
activeCount,
|
|
612
|
+
isActive,
|
|
613
|
+
done,
|
|
614
|
+
onRun,
|
|
615
|
+
running,
|
|
616
|
+
byStatus,
|
|
617
|
+
totalChunks,
|
|
618
|
+
}: {
|
|
619
|
+
step: PipelineStep
|
|
620
|
+
fileCount: number
|
|
621
|
+
activeCount: number
|
|
622
|
+
isActive: boolean
|
|
623
|
+
done?: boolean
|
|
624
|
+
onRun?: () => void
|
|
625
|
+
running: boolean
|
|
626
|
+
byStatus?: Record<string, number>
|
|
627
|
+
totalChunks?: number
|
|
628
|
+
}) {
|
|
629
|
+
const Icon = step.icon
|
|
630
|
+
const [copied, setCopied] = useState(false)
|
|
631
|
+
|
|
632
|
+
const stepDone = done !== undefined ? done : (activeCount >= fileCount && fileCount > 0)
|
|
633
|
+
const partial = activeCount > 0 && activeCount < fileCount
|
|
634
|
+
|
|
635
|
+
const handleCopy = () => {
|
|
636
|
+
if (!step.command) return
|
|
637
|
+
navigator.clipboard.writeText(step.command)
|
|
638
|
+
setCopied(true)
|
|
639
|
+
setTimeout(() => setCopied(false), 1500)
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
return (
|
|
643
|
+
<div className={`flex items-start gap-3 p-3 rounded-lg border transition-colors ${
|
|
644
|
+
isActive
|
|
645
|
+
? 'bg-indigo-50 border-indigo-200 dark:bg-indigo-950/20 dark:border-indigo-800'
|
|
646
|
+
: stepDone
|
|
647
|
+
? 'bg-green-50/50 border-green-100'
|
|
648
|
+
: 'border-border bg-card'
|
|
649
|
+
}`}>
|
|
650
|
+
{}
|
|
651
|
+
<div className={`h-6 w-6 rounded-full flex items-center justify-center text-xs font-bold shrink-0 mt-0.5 ${
|
|
652
|
+
stepDone
|
|
653
|
+
? 'bg-green-100 text-green-700'
|
|
654
|
+
: isActive
|
|
655
|
+
? 'bg-indigo-100 text-indigo-700'
|
|
656
|
+
: 'bg-muted text-muted-foreground'
|
|
657
|
+
}`}>
|
|
658
|
+
{stepDone ? <CheckCircle2 className="h-3.5 w-3.5 text-green-600" /> : step.number}
|
|
659
|
+
</div>
|
|
660
|
+
|
|
661
|
+
{}
|
|
662
|
+
<div className="flex-1 min-w-0">
|
|
663
|
+
<div className="flex items-center gap-2">
|
|
664
|
+
<Icon className={`h-3.5 w-3.5 shrink-0 ${done ? 'text-green-600' : isActive ? 'text-indigo-600' : 'text-muted-foreground'}`} />
|
|
665
|
+
<span className="text-sm font-medium">
|
|
666
|
+
{step.label.includes('(')
|
|
667
|
+
? <>{step.label.split('(')[0]}<span className="text-xs font-normal text-muted-foreground">({step.label.split('(')[1]}</span></>
|
|
668
|
+
: step.label}
|
|
669
|
+
</span>
|
|
670
|
+
{(isActive || partial || done) && fileCount > 0 && !(step.number === 2) && (
|
|
671
|
+
<Badge variant={partial ? "secondary" : done ? "secondary" : "outline"} className="text-[10px] h-4 px-1.5">
|
|
672
|
+
{partial
|
|
673
|
+
? `${activeCount}/${fileCount}`
|
|
674
|
+
: step.number === 3
|
|
675
|
+
? `${fileCount}`
|
|
676
|
+
: (step.number === 4 || step.number === 5)
|
|
677
|
+
? `${totalChunks || 0} chunks`
|
|
678
|
+
: (step.number === 6 || step.number === 9)
|
|
679
|
+
? `${(totalChunks || 0) * 3} vectors`
|
|
680
|
+
: `${fileCount} done`}
|
|
681
|
+
</Badge>
|
|
682
|
+
)}
|
|
683
|
+
</div>
|
|
684
|
+
<p className="text-xs text-muted-foreground mt-0.5">{step.description}</p>
|
|
685
|
+
{step.command && (
|
|
686
|
+
<button
|
|
687
|
+
onClick={handleCopy}
|
|
688
|
+
className="mt-1.5 flex items-center gap-1.5 w-fit rounded px-2 py-0.5 bg-muted hover:bg-muted/80 transition-colors group"
|
|
689
|
+
>
|
|
690
|
+
<code className="text-[10px] font-mono text-foreground/70">{step.command}</code>
|
|
691
|
+
{copied
|
|
692
|
+
? <Check className="h-3 w-3 text-green-600 shrink-0" />
|
|
693
|
+
: <Copy className="h-3 w-3 text-muted-foreground shrink-0 opacity-0 group-hover:opacity-100 transition-opacity" />
|
|
694
|
+
}
|
|
695
|
+
</button>
|
|
696
|
+
)}
|
|
697
|
+
</div>
|
|
698
|
+
|
|
699
|
+
{}
|
|
700
|
+
<div className="flex items-center gap-1 shrink-0">
|
|
701
|
+
<Tooltip>
|
|
702
|
+
<TooltipTrigger asChild>
|
|
703
|
+
<button className="p-1 rounded hover:bg-muted">
|
|
704
|
+
<Info className="h-3.5 w-3.5 text-muted-foreground" />
|
|
705
|
+
</button>
|
|
706
|
+
</TooltipTrigger>
|
|
707
|
+
<TooltipContent side="left" className="max-w-xs text-xs">
|
|
708
|
+
<p className="font-semibold mb-1">Devin instruction:</p>
|
|
709
|
+
<p>{step.agentInstruction}</p>
|
|
710
|
+
</TooltipContent>
|
|
711
|
+
</Tooltip>
|
|
712
|
+
{onRun && (
|
|
713
|
+
<Button size="sm" variant={isActive ? 'default' : 'outline'} onClick={onRun} disabled={running} className="h-7 text-xs">
|
|
714
|
+
{running ? <RefreshCw className="h-3 w-3 animate-spin" /> : <Play className="h-3 w-3" />}
|
|
715
|
+
</Button>
|
|
716
|
+
)}
|
|
717
|
+
</div>
|
|
718
|
+
</div>
|
|
719
|
+
)
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
// CIL[END chunk_id="cilingestionpage_steprow_1784193942"]
|
|
725
|
+
// CIL[BEGIN chunk_id="cilingestionpage_cilingestionpage_1784193942" type="component" identity="CILIngestionPage" parent="none"]
|
|
726
|
+
// CIL[DOC-MACRO purpose="Render the CIL ingestion pipeline page for a project"]
|
|
727
|
+
// CIL[DOC-RESPONSIBILITY responsibility="Manage project config, file tree selection, pipeline progress, and run ingestion passes"]
|
|
728
|
+
// CIL[DOC-CONTEXT module="cortex:cil-ingestion" layer="presentation" related_files="[]"]
|
|
729
|
+
// CIL[DOC-CONTRACT inputs="none" outputs="JSX.Element" errors="Displays loading, not-found, and API error states" side_effects="Calls /api/cil-project, /api/cil-ingest, /api/cil-embeddings, and /api/cil-callmap endpoints; updates local state"]
|
|
730
|
+
// CIL[DOC-MICRO logic_summary="Loads project and progress, renders stats, settings, pipeline steps, and file tree; provides handlers to save config/selection and run pass 1, embed, and map passes" notable_decisions="[]"]
|
|
731
|
+
// CIL[DOC-CONFIDENCE pass="second" score="0.95" flags="none"]
|
|
732
|
+
// CIL[DOC-STABILITY stability="stable"]
|
|
733
|
+
// CIL[DOC-VECTOR type="context" content="Layer: presentation. Direct callers: 0. Direct calls: 0. Related files: none."]
|
|
734
|
+
// CIL[DOC-VECTOR type="blast_radius" content="Direct callers: 0. Total affected: 0."]
|
|
735
|
+
// CIL[DOC-VECTOR type="configuration" content="No configuration dependencies."]
|
|
736
|
+
// CIL[DOC-VECTOR type="constraint" content="No test paths identified."]
|
|
737
|
+
// CIL[DOC-VECTOR type="implementation_pattern" content="" status="pending_human_input"]
|
|
738
|
+
// CIL[DOC-VECTOR type="user_journey" content="" status="pending_human_input"]
|
|
739
|
+
export default function CILIngestionPage() {
|
|
740
|
+
const { id: projectId } = useParams<{ id: string }>()
|
|
741
|
+
const appPath = (path: string) => '/spine-framework/admin' + (path.startsWith('/') ? path : '/' + path)
|
|
742
|
+
|
|
743
|
+
const [project, setProject] = useState<Project | null>(null)
|
|
744
|
+
const [loadingProject, setLoadingProject] = useState(true)
|
|
745
|
+
|
|
746
|
+
const [projectConfig, setProjectConfig] = useState<ProjectConfig>({
|
|
747
|
+
repo_path: '',
|
|
748
|
+
globs: '**/*.ts,**/*.tsx,**/*.sql',
|
|
749
|
+
exclude_globs: 'node_modules/**,.git/**,dist/**,build/**,.netlify/**,**/*.min.js,**/*.d.ts',
|
|
750
|
+
force_reprocess: false,
|
|
751
|
+
})
|
|
752
|
+
const [configOpen, setConfigOpen] = useState(false)
|
|
753
|
+
const [savingConfig, setSavingConfig] = useState(false)
|
|
754
|
+
const [configSaved, setConfigSaved] = useState(false)
|
|
755
|
+
|
|
756
|
+
const [fileTree, setFileTree] = useState<FileTreeNode | null>(null)
|
|
757
|
+
const [selectedPaths, setSelectedPaths] = useState<string[]>([])
|
|
758
|
+
const [expandedPaths, setExpandedPaths] = useState<Set<string>>(new Set())
|
|
759
|
+
const [fileStatuses, setFileStatuses] = useState<Record<string, string>>({})
|
|
760
|
+
const [savingSelection, setSavingSelection] = useState(false)
|
|
761
|
+
|
|
762
|
+
const [pipelineProgress, setPipelineProgress] = useState<PipelineProgress | null>(null)
|
|
763
|
+
const [loadingProgress, setLoadingProgress] = useState(false)
|
|
764
|
+
const [runningPass, setRunningPass] = useState<string | null>(null)
|
|
765
|
+
|
|
766
|
+
|
|
767
|
+
useEffect(() => {
|
|
768
|
+
if (!projectId) return
|
|
769
|
+
setLoadingProject(true)
|
|
770
|
+
apiFetch(`/api/cil-project?action=get&id=${projectId}`)
|
|
771
|
+
.then(r => r.json())
|
|
772
|
+
.then(data => {
|
|
773
|
+
const p: Project = data?.project || data?.data?.project || null
|
|
774
|
+
setProject(p)
|
|
775
|
+
if (p?.data?.file_tree) {
|
|
776
|
+
setFileTree(p.data.file_tree)
|
|
777
|
+
setExpandedPaths(new Set(collectAllDirPaths(p.data.file_tree)))
|
|
778
|
+
}
|
|
779
|
+
setSelectedPaths(p?.data?.selected_paths || [])
|
|
780
|
+
setFileStatuses(p?.data?.file_statuses || {})
|
|
781
|
+
|
|
782
|
+
if (p?.data) {
|
|
783
|
+
setProjectConfig(c => ({
|
|
784
|
+
...c,
|
|
785
|
+
repo_path: p.data.repo_path || '',
|
|
786
|
+
globs: p.data.globs?.join(',') || c.globs,
|
|
787
|
+
exclude_globs: p.data.exclude_globs?.join(',') || c.exclude_globs,
|
|
788
|
+
}))
|
|
789
|
+
}
|
|
790
|
+
})
|
|
791
|
+
.catch(() => {})
|
|
792
|
+
.finally(() => setLoadingProject(false))
|
|
793
|
+
}, [projectId])
|
|
794
|
+
|
|
795
|
+
|
|
796
|
+
const fetchProgress = useCallback(() => {
|
|
797
|
+
if (!projectId) return
|
|
798
|
+
setLoadingProgress(true)
|
|
799
|
+
apiFetch(`/api/cil-project?action=pipeline_progress&id=${projectId}`)
|
|
800
|
+
.then(r => r.json())
|
|
801
|
+
.then(data => {
|
|
802
|
+
const d = data?.data || data
|
|
803
|
+
const progress = d?.progress || null
|
|
804
|
+
setPipelineProgress(progress)
|
|
805
|
+
|
|
806
|
+
if (progress?.file_statuses) setFileStatuses(progress.file_statuses)
|
|
807
|
+
|
|
808
|
+
return apiFetch(`/api/cil-project?action=get&id=${projectId}`)
|
|
809
|
+
})
|
|
810
|
+
.then(r => r.json())
|
|
811
|
+
.then(projectData => {
|
|
812
|
+
const p = projectData?.project || projectData?.data?.project || null
|
|
813
|
+
if (p?.data?.file_statuses) {
|
|
814
|
+
setFileStatuses(p.data.file_statuses)
|
|
815
|
+
}
|
|
816
|
+
})
|
|
817
|
+
.catch(() => {})
|
|
818
|
+
.finally(() => setLoadingProgress(false))
|
|
819
|
+
}, [projectId])
|
|
820
|
+
|
|
821
|
+
useEffect(() => { fetchProgress() }, [fetchProgress])
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
const saveSelection = useCallback(async (paths: string[]) => {
|
|
825
|
+
if (!projectId) return
|
|
826
|
+
setSavingSelection(true)
|
|
827
|
+
try {
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
|
|
831
|
+
const updatedStatuses = { ...fileStatuses }
|
|
832
|
+
for (const p of paths) {
|
|
833
|
+
if (!updatedStatuses[p]) updatedStatuses[p] = '3-selected'
|
|
834
|
+
}
|
|
835
|
+
for (const p of Object.keys(updatedStatuses)) {
|
|
836
|
+
if (!paths.includes(p) && updatedStatuses[p] === '3-selected') {
|
|
837
|
+
delete updatedStatuses[p]
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
await apiFetch(`/api/cil-project?action=update&id=${projectId}`, {
|
|
841
|
+
method: 'PATCH',
|
|
842
|
+
headers: { 'Content-Type': 'application/json' },
|
|
843
|
+
body: JSON.stringify({ id: projectId, data: { selected_paths: paths, file_statuses: updatedStatuses } }),
|
|
844
|
+
})
|
|
845
|
+
setFileStatuses(updatedStatuses)
|
|
846
|
+
setProject(p => p ? { ...p, data: { ...p.data, selected_paths: paths, file_statuses: updatedStatuses } } : p)
|
|
847
|
+
} catch {
|
|
848
|
+
|
|
849
|
+
} finally {
|
|
850
|
+
setSavingSelection(false)
|
|
851
|
+
}
|
|
852
|
+
}, [projectId, fileStatuses])
|
|
853
|
+
|
|
854
|
+
|
|
855
|
+
const saveConfig = useCallback(async () => {
|
|
856
|
+
if (!projectId) return
|
|
857
|
+
setSavingConfig(true)
|
|
858
|
+
setConfigSaved(false)
|
|
859
|
+
try {
|
|
860
|
+
await apiFetch(`/api/cil-project?action=update&id=${projectId}`, {
|
|
861
|
+
method: 'PATCH',
|
|
862
|
+
headers: { 'Content-Type': 'application/json' },
|
|
863
|
+
body: JSON.stringify({
|
|
864
|
+
id: projectId,
|
|
865
|
+
data: {
|
|
866
|
+
repo_path: projectConfig.repo_path,
|
|
867
|
+
globs: projectConfig.globs.split(',').map(s => s.trim()).filter(Boolean),
|
|
868
|
+
exclude_globs: projectConfig.exclude_globs.split(',').map(s => s.trim()).filter(Boolean),
|
|
869
|
+
},
|
|
870
|
+
}),
|
|
871
|
+
})
|
|
872
|
+
setProject(p => p ? {
|
|
873
|
+
...p,
|
|
874
|
+
data: {
|
|
875
|
+
...p.data,
|
|
876
|
+
repo_path: projectConfig.repo_path,
|
|
877
|
+
globs: projectConfig.globs.split(',').map(s => s.trim()).filter(Boolean),
|
|
878
|
+
exclude_globs: projectConfig.exclude_globs.split(',').map(s => s.trim()).filter(Boolean),
|
|
879
|
+
},
|
|
880
|
+
} : p)
|
|
881
|
+
setConfigSaved(true)
|
|
882
|
+
setTimeout(() => setConfigSaved(false), 2000)
|
|
883
|
+
} catch {
|
|
884
|
+
|
|
885
|
+
} finally {
|
|
886
|
+
setSavingConfig(false)
|
|
887
|
+
}
|
|
888
|
+
}, [projectId, projectConfig])
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
const togglePath = useCallback((path: string, isDir: boolean, children?: FileTreeNode[]) => {
|
|
892
|
+
setSelectedPaths(prev => {
|
|
893
|
+
let next: string[]
|
|
894
|
+
if (isDir && children) {
|
|
895
|
+
|
|
896
|
+
const childPaths = children.map(c => c.path)
|
|
897
|
+
const allSelected = childPaths.every(cp => prev.includes(cp))
|
|
898
|
+
if (allSelected) {
|
|
899
|
+
next = prev.filter(p => !childPaths.includes(p))
|
|
900
|
+
} else {
|
|
901
|
+
next = [...new Set([...prev, ...childPaths])]
|
|
902
|
+
}
|
|
903
|
+
} else {
|
|
904
|
+
next = prev.includes(path) ? prev.filter(p => p !== path) : [...prev, path]
|
|
905
|
+
}
|
|
906
|
+
saveSelection(next)
|
|
907
|
+
return next
|
|
908
|
+
})
|
|
909
|
+
}, [saveSelection])
|
|
910
|
+
|
|
911
|
+
const toggleExpand = (path: string) => {
|
|
912
|
+
setExpandedPaths(prev => {
|
|
913
|
+
const next = new Set(prev)
|
|
914
|
+
if (next.has(path)) { next.delete(path) } else { next.add(path) }
|
|
915
|
+
return next
|
|
916
|
+
})
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
|
|
920
|
+
const runPass1 = async () => {
|
|
921
|
+
if (!projectId) return
|
|
922
|
+
setRunningPass('build_tree')
|
|
923
|
+
try {
|
|
924
|
+
const res = await apiFetch('/api/cil-ingest?action=pass1', {
|
|
925
|
+
method: 'POST',
|
|
926
|
+
headers: { 'Content-Type': 'application/json' },
|
|
927
|
+
body: JSON.stringify({
|
|
928
|
+
project_id: projectId,
|
|
929
|
+
globs: projectConfig.globs.split(',').map(s => s.trim()).filter(Boolean),
|
|
930
|
+
exclude_globs: projectConfig.exclude_globs.split(',').map(s => s.trim()).filter(Boolean),
|
|
931
|
+
force_reprocess: projectConfig.force_reprocess,
|
|
932
|
+
}),
|
|
933
|
+
})
|
|
934
|
+
const data = await res.json()
|
|
935
|
+
const d = data?.data || data
|
|
936
|
+
if (d?.file_tree) {
|
|
937
|
+
setFileTree(d.file_tree)
|
|
938
|
+
setExpandedPaths(new Set(collectAllDirPaths(d.file_tree)))
|
|
939
|
+
setProject(p => p ? { ...p, data: { ...p.data, file_tree: d.file_tree } } : p)
|
|
940
|
+
}
|
|
941
|
+
fetchProgress()
|
|
942
|
+
} catch {
|
|
943
|
+
|
|
944
|
+
} finally {
|
|
945
|
+
setRunningPass(null)
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
|
|
950
|
+
const runEmbedFirstPass = async () => {
|
|
951
|
+
if (!projectId) return
|
|
952
|
+
setRunningPass('first_pass_embed')
|
|
953
|
+
try {
|
|
954
|
+
let offset: number | null = 0
|
|
955
|
+
while (offset !== null) {
|
|
956
|
+
const res = await apiFetch('/api/cil-embeddings?action=embed_project', {
|
|
957
|
+
method: 'POST',
|
|
958
|
+
headers: { 'Content-Type': 'application/json' },
|
|
959
|
+
body: JSON.stringify({
|
|
960
|
+
project_id: projectId,
|
|
961
|
+
force_regenerate: projectConfig.force_reprocess,
|
|
962
|
+
offset,
|
|
963
|
+
}),
|
|
964
|
+
})
|
|
965
|
+
const data = await res.json()
|
|
966
|
+
const d = data?.data || data
|
|
967
|
+
offset = d?.next_offset ?? null
|
|
968
|
+
await fetchProgress()
|
|
969
|
+
}
|
|
970
|
+
} catch {
|
|
971
|
+
|
|
972
|
+
} finally {
|
|
973
|
+
setRunningPass(null)
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
|
|
977
|
+
|
|
978
|
+
const runMapFirstPass = async () => {
|
|
979
|
+
if (!projectId) return
|
|
980
|
+
setRunningPass('first_pass_map')
|
|
981
|
+
try {
|
|
982
|
+
let offset: number | null = 0
|
|
983
|
+
while (offset !== null) {
|
|
984
|
+
const res = await apiFetch('/api/cil-callmap?action=map_project', {
|
|
985
|
+
method: 'POST',
|
|
986
|
+
headers: { 'Content-Type': 'application/json' },
|
|
987
|
+
body: JSON.stringify({
|
|
988
|
+
project_id: projectId,
|
|
989
|
+
force_regenerate: projectConfig.force_reprocess,
|
|
990
|
+
offset,
|
|
991
|
+
}),
|
|
992
|
+
})
|
|
993
|
+
const data = await res.json()
|
|
994
|
+
const d = data?.data || data
|
|
995
|
+
offset = d?.next_offset ?? null
|
|
996
|
+
await fetchProgress()
|
|
997
|
+
}
|
|
998
|
+
} catch {
|
|
999
|
+
|
|
1000
|
+
} finally {
|
|
1001
|
+
setRunningPass(null)
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
const runEmbedSecondPass = async () => {
|
|
1007
|
+
if (!projectId) return
|
|
1008
|
+
setRunningPass('second_pass_embed')
|
|
1009
|
+
try {
|
|
1010
|
+
let offset: number | null = 0
|
|
1011
|
+
while (offset !== null) {
|
|
1012
|
+
const res = await apiFetch('/api/cil-embeddings?action=embed_project', {
|
|
1013
|
+
method: 'POST',
|
|
1014
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1015
|
+
body: JSON.stringify({
|
|
1016
|
+
project_id: projectId,
|
|
1017
|
+
force_regenerate: projectConfig.force_reprocess,
|
|
1018
|
+
second_pass: true,
|
|
1019
|
+
offset,
|
|
1020
|
+
}),
|
|
1021
|
+
})
|
|
1022
|
+
const data = await res.json()
|
|
1023
|
+
const d = data?.data || data
|
|
1024
|
+
offset = d?.next_offset ?? null
|
|
1025
|
+
await fetchProgress()
|
|
1026
|
+
}
|
|
1027
|
+
} catch {
|
|
1028
|
+
|
|
1029
|
+
} finally {
|
|
1030
|
+
setRunningPass(null)
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
|
|
1035
|
+
const runMapSecondPass = async () => {
|
|
1036
|
+
if (!projectId) return
|
|
1037
|
+
setRunningPass('second_pass_map')
|
|
1038
|
+
try {
|
|
1039
|
+
let offset: number | null = 0
|
|
1040
|
+
while (offset !== null) {
|
|
1041
|
+
const res = await apiFetch('/api/cil-callmap?action=map_project', {
|
|
1042
|
+
method: 'POST',
|
|
1043
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1044
|
+
body: JSON.stringify({
|
|
1045
|
+
project_id: projectId,
|
|
1046
|
+
force_regenerate: projectConfig.force_reprocess,
|
|
1047
|
+
second_pass: true,
|
|
1048
|
+
offset,
|
|
1049
|
+
}),
|
|
1050
|
+
})
|
|
1051
|
+
const data = await res.json()
|
|
1052
|
+
const d = data?.data || data
|
|
1053
|
+
offset = d?.next_offset ?? null
|
|
1054
|
+
await fetchProgress()
|
|
1055
|
+
}
|
|
1056
|
+
} catch {
|
|
1057
|
+
|
|
1058
|
+
} finally {
|
|
1059
|
+
setRunningPass(null)
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
|
|
1064
|
+
const totalFiles = fileTree ? countFilesInTree(fileTree) : 0
|
|
1065
|
+
const selectedCount = selectedPaths.length
|
|
1066
|
+
const byStatus = pipelineProgress?.by_status || {}
|
|
1067
|
+
const totalChunks = pipelineProgress?.total_chunks || 0
|
|
1068
|
+
|
|
1069
|
+
|
|
1070
|
+
|
|
1071
|
+
|
|
1072
|
+
const statusOrder = ['3-selected','4-chunked','5-documented','6-embedded','7-mapped','8-enriched','9-embedded','10-mapped']
|
|
1073
|
+
const filesAtOrPast = (minStatus: string) => {
|
|
1074
|
+
const minIdx = statusOrder.indexOf(minStatus)
|
|
1075
|
+
return statusOrder.slice(minIdx).reduce((sum, s) => sum + (byStatus[s] || 0), 0)
|
|
1076
|
+
}
|
|
1077
|
+
|
|
1078
|
+
const activeStep = (() => {
|
|
1079
|
+
|
|
1080
|
+
if (!project?.data?.repo_path) return 1
|
|
1081
|
+
|
|
1082
|
+
|
|
1083
|
+
if (!fileTree) return 2
|
|
1084
|
+
|
|
1085
|
+
|
|
1086
|
+
if (selectedCount === 0) return 3
|
|
1087
|
+
|
|
1088
|
+
|
|
1089
|
+
if (filesAtOrPast('4-chunked') < selectedCount) return 4
|
|
1090
|
+
|
|
1091
|
+
|
|
1092
|
+
if (filesAtOrPast('5-documented') < selectedCount) return 5
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
if (filesAtOrPast('6-embedded') < selectedCount) return 6
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
if (filesAtOrPast('7-mapped') < selectedCount) return 7
|
|
1099
|
+
|
|
1100
|
+
|
|
1101
|
+
if (filesAtOrPast('8-enriched') < selectedCount) return 8
|
|
1102
|
+
|
|
1103
|
+
|
|
1104
|
+
if (filesAtOrPast('9-embedded') < selectedCount) return 9
|
|
1105
|
+
|
|
1106
|
+
|
|
1107
|
+
if (filesAtOrPast('10-mapped') < selectedCount) return 10
|
|
1108
|
+
|
|
1109
|
+
return 10
|
|
1110
|
+
})()
|
|
1111
|
+
|
|
1112
|
+
if (loadingProject) {
|
|
1113
|
+
return (
|
|
1114
|
+
<div className="max-w-6xl mx-auto p-6 space-y-4">
|
|
1115
|
+
<Skeleton className="h-8 w-64" />
|
|
1116
|
+
<div className="grid grid-cols-4 gap-3">
|
|
1117
|
+
{[1,2,3,4].map(i => <Skeleton key={i} className="h-20" />)}
|
|
1118
|
+
</div>
|
|
1119
|
+
<div className="grid grid-cols-3 gap-4">
|
|
1120
|
+
<Skeleton className="h-[500px]" />
|
|
1121
|
+
<Skeleton className="h-[500px] col-span-2" />
|
|
1122
|
+
</div>
|
|
1123
|
+
</div>
|
|
1124
|
+
)
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
if (!project) {
|
|
1128
|
+
return (
|
|
1129
|
+
<div className="max-w-6xl mx-auto p-6">
|
|
1130
|
+
<p className="text-muted-foreground">Project not found.</p>
|
|
1131
|
+
</div>
|
|
1132
|
+
)
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
return (
|
|
1136
|
+
<div className="max-w-6xl mx-auto p-6 space-y-5">
|
|
1137
|
+
|
|
1138
|
+
{}
|
|
1139
|
+
<div className="flex items-center justify-between">
|
|
1140
|
+
<div>
|
|
1141
|
+
<div className="flex items-center gap-2 text-xs text-muted-foreground mb-1">
|
|
1142
|
+
<a href={appPath('/cil')} className="hover:text-foreground">CIL</a>
|
|
1143
|
+
<ChevronRight className="h-3 w-3" />
|
|
1144
|
+
<a href={appPath(`/cil/${projectId}/dashboard`)} className="hover:text-foreground">{project.title}</a>
|
|
1145
|
+
<ChevronRight className="h-3 w-3" />
|
|
1146
|
+
<span className="text-foreground">Pipeline</span>
|
|
1147
|
+
</div>
|
|
1148
|
+
<h1 className="text-xl font-bold">{project.title}</h1>
|
|
1149
|
+
<p className="text-xs text-muted-foreground mt-0.5 font-mono">{project.data.repo_path}</p>
|
|
1150
|
+
</div>
|
|
1151
|
+
<div className="flex items-center gap-2">
|
|
1152
|
+
<Button size="sm" variant="outline" onClick={fetchProgress} disabled={loadingProgress} className="h-8">
|
|
1153
|
+
<RefreshCw className={`h-3.5 w-3.5 ${loadingProgress ? 'animate-spin' : ''}`} />
|
|
1154
|
+
</Button>
|
|
1155
|
+
<a href={appPath(`/cil/${projectId}/dashboard`)}>
|
|
1156
|
+
<Button size="sm" variant="outline" className="h-8 text-xs">Dashboard</Button>
|
|
1157
|
+
</a>
|
|
1158
|
+
<a href={appPath(`/cil/${projectId}/agent`)}>
|
|
1159
|
+
<Button size="sm" className="h-8 text-xs">Open Agent</Button>
|
|
1160
|
+
</a>
|
|
1161
|
+
</div>
|
|
1162
|
+
</div>
|
|
1163
|
+
|
|
1164
|
+
<PageInstructions
|
|
1165
|
+
description="Run and monitor the CIL ingestion pipeline for a project."
|
|
1166
|
+
sections={[
|
|
1167
|
+
{ title: 'What this page is for', content: 'This page controls the multi-pass ingestion process that discovers files, chunks code, generates embeddings, documents contracts, maps calls, and extracts config.' },
|
|
1168
|
+
{ title: 'How to read this page', content: 'The top cards show files discovered, files selected, first-pass complete, and fully ingested counts. The steps list shows which pass is active and how many files are done.' },
|
|
1169
|
+
{ title: 'How to use this page', content: 'Expand Project Settings to set the repository path, include globs, exclude globs, and Force Reprocess. Save settings, then run the pipeline steps in order. Refresh the progress bar to track status.' },
|
|
1170
|
+
{ title: 'Important notes', content: 'Ingestion can be expensive because it uses LLMs. Excluding node_modules, .git, and dist is strongly recommended. Force Reprocess re-runs passes even on already-processed files.' },
|
|
1171
|
+
]}
|
|
1172
|
+
/>
|
|
1173
|
+
|
|
1174
|
+
{}
|
|
1175
|
+
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
|
|
1176
|
+
<div className="rounded-lg border bg-card p-3">
|
|
1177
|
+
<div className="text-2xl font-bold tabular-nums">{totalFiles}</div>
|
|
1178
|
+
<div className="text-xs text-muted-foreground mt-0.5">Files discovered</div>
|
|
1179
|
+
</div>
|
|
1180
|
+
<div className="rounded-lg border bg-card p-3">
|
|
1181
|
+
<div className="text-2xl font-bold tabular-nums text-indigo-700">{selectedCount}</div>
|
|
1182
|
+
<div className="text-xs text-muted-foreground mt-0.5">Files selected</div>
|
|
1183
|
+
</div>
|
|
1184
|
+
<div className="rounded-lg border bg-card p-3">
|
|
1185
|
+
<div className="text-2xl font-bold tabular-nums text-green-700">
|
|
1186
|
+
{byStatus['7-mapped'] || 0}
|
|
1187
|
+
</div>
|
|
1188
|
+
<div className="text-xs text-muted-foreground mt-0.5">First pass complete</div>
|
|
1189
|
+
</div>
|
|
1190
|
+
<div className="rounded-lg border bg-card p-3">
|
|
1191
|
+
<div className="text-2xl font-bold tabular-nums text-amber-700">
|
|
1192
|
+
{byStatus['10-mapped'] || 0}
|
|
1193
|
+
</div>
|
|
1194
|
+
<div className="text-xs text-muted-foreground mt-0.5">Fully ingested</div>
|
|
1195
|
+
</div>
|
|
1196
|
+
</div>
|
|
1197
|
+
|
|
1198
|
+
{}
|
|
1199
|
+
<div className="rounded-lg border bg-card overflow-hidden">
|
|
1200
|
+
<button
|
|
1201
|
+
className="w-full flex items-center justify-between px-4 py-3 hover:bg-muted/40 transition-colors"
|
|
1202
|
+
onClick={() => setConfigOpen(o => !o)}
|
|
1203
|
+
>
|
|
1204
|
+
<div className="flex items-center gap-2">
|
|
1205
|
+
<Settings2 className="h-4 w-4 text-muted-foreground" />
|
|
1206
|
+
<span className="text-sm font-medium">Project Settings</span>
|
|
1207
|
+
<span className="text-xs text-muted-foreground">— repo path, globs, exclusions</span>
|
|
1208
|
+
</div>
|
|
1209
|
+
<ChevronDown className={`h-4 w-4 text-muted-foreground transition-transform ${configOpen ? 'rotate-180' : ''}`} />
|
|
1210
|
+
</button>
|
|
1211
|
+
|
|
1212
|
+
{configOpen && (
|
|
1213
|
+
<div className="px-4 pb-4 border-t pt-4 space-y-4">
|
|
1214
|
+
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2">
|
|
1215
|
+
{}
|
|
1216
|
+
<div className="sm:col-span-2 space-y-1.5">
|
|
1217
|
+
<Label className="text-xs font-semibold">Repository Path</Label>
|
|
1218
|
+
<Input
|
|
1219
|
+
value={projectConfig.repo_path}
|
|
1220
|
+
onChange={e => setProjectConfig(c => ({ ...c, repo_path: e.target.value }))}
|
|
1221
|
+
placeholder="/path/to/repo"
|
|
1222
|
+
className="font-mono text-xs"
|
|
1223
|
+
/>
|
|
1224
|
+
<p className="text-xs text-muted-foreground">Absolute path to the repository root on disk.</p>
|
|
1225
|
+
</div>
|
|
1226
|
+
|
|
1227
|
+
{}
|
|
1228
|
+
<div className="space-y-1.5">
|
|
1229
|
+
<Label className="text-xs font-semibold">Include Globs</Label>
|
|
1230
|
+
<Input
|
|
1231
|
+
value={projectConfig.globs}
|
|
1232
|
+
onChange={e => setProjectConfig(c => ({ ...c, globs: e.target.value }))}
|
|
1233
|
+
placeholder="**/*.ts,**/*.tsx,**/*.sql"
|
|
1234
|
+
className="font-mono text-xs"
|
|
1235
|
+
/>
|
|
1236
|
+
<p className="text-xs text-muted-foreground">Comma-separated glob patterns for files to include.</p>
|
|
1237
|
+
</div>
|
|
1238
|
+
|
|
1239
|
+
{}
|
|
1240
|
+
<div className="space-y-1.5">
|
|
1241
|
+
<Label className="text-xs font-semibold">Exclude Globs</Label>
|
|
1242
|
+
<Input
|
|
1243
|
+
value={projectConfig.exclude_globs}
|
|
1244
|
+
onChange={e => setProjectConfig(c => ({ ...c, exclude_globs: e.target.value }))}
|
|
1245
|
+
placeholder="node_modules/**,.git/**,dist/**"
|
|
1246
|
+
className="font-mono text-xs"
|
|
1247
|
+
/>
|
|
1248
|
+
<p className="text-xs text-muted-foreground">Comma-separated patterns to exclude from all passes.</p>
|
|
1249
|
+
</div>
|
|
1250
|
+
</div>
|
|
1251
|
+
|
|
1252
|
+
{}
|
|
1253
|
+
<div className="flex items-center justify-between gap-4 pt-3 border-t">
|
|
1254
|
+
<div className="flex items-center gap-3">
|
|
1255
|
+
<input
|
|
1256
|
+
type="checkbox"
|
|
1257
|
+
id="force-reprocess"
|
|
1258
|
+
checked={projectConfig.force_reprocess}
|
|
1259
|
+
onChange={e => setProjectConfig(c => ({ ...c, force_reprocess: e.target.checked }))}
|
|
1260
|
+
className="h-4 w-4 rounded border-slate-300 accent-indigo-600 cursor-pointer"
|
|
1261
|
+
/>
|
|
1262
|
+
<label htmlFor="force-reprocess" className="cursor-pointer select-none">
|
|
1263
|
+
<p className="text-xs font-semibold">Force Reprocess</p>
|
|
1264
|
+
<p className="text-xs text-muted-foreground">Re-run passes even if files are already processed.</p>
|
|
1265
|
+
</label>
|
|
1266
|
+
</div>
|
|
1267
|
+
<Button size="sm" onClick={saveConfig} disabled={savingConfig} className="h-8 text-xs shrink-0">
|
|
1268
|
+
{savingConfig
|
|
1269
|
+
? <><RefreshCw className="h-3 w-3 mr-1.5 animate-spin" />Saving…</>
|
|
1270
|
+
: configSaved
|
|
1271
|
+
? <><CheckCircle2 className="h-3 w-3 mr-1.5 text-green-600" />Saved</>
|
|
1272
|
+
: <><Save className="h-3 w-3 mr-1.5" />Save Settings</>
|
|
1273
|
+
}
|
|
1274
|
+
</Button>
|
|
1275
|
+
</div>
|
|
1276
|
+
</div>
|
|
1277
|
+
)}
|
|
1278
|
+
</div>
|
|
1279
|
+
|
|
1280
|
+
{}
|
|
1281
|
+
<div className="grid grid-cols-3 gap-4">
|
|
1282
|
+
|
|
1283
|
+
{}
|
|
1284
|
+
<div className="col-span-1 space-y-2">
|
|
1285
|
+
<div className="flex items-center justify-between mb-1">
|
|
1286
|
+
<h2 className="text-sm font-semibold">Pipeline Steps</h2>
|
|
1287
|
+
<Badge variant="outline" className="text-xs">
|
|
1288
|
+
Step {activeStep} active
|
|
1289
|
+
</Badge>
|
|
1290
|
+
</div>
|
|
1291
|
+
|
|
1292
|
+
{PIPELINE_STEPS.map(step => {
|
|
1293
|
+
const isActive = step.number === activeStep
|
|
1294
|
+
let activeCount = 0
|
|
1295
|
+
let fileCount = selectedCount
|
|
1296
|
+
let done = false
|
|
1297
|
+
|
|
1298
|
+
|
|
1299
|
+
if (step.number === 1) {
|
|
1300
|
+
done = !!(project?.data?.repo_path)
|
|
1301
|
+
activeCount = done ? 1 : 0
|
|
1302
|
+
fileCount = 1
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
else if (step.number === 2) {
|
|
1306
|
+
done = !!fileTree
|
|
1307
|
+
activeCount = done ? 1 : 0
|
|
1308
|
+
fileCount = 1
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
else if (step.number === 3) {
|
|
1312
|
+
done = selectedCount > 0
|
|
1313
|
+
activeCount = selectedCount
|
|
1314
|
+
fileCount = totalFiles
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
|
|
1318
|
+
else if (step.targetStatus) {
|
|
1319
|
+
activeCount = filesAtOrPast(step.targetStatus)
|
|
1320
|
+
fileCount = selectedCount
|
|
1321
|
+
done = activeCount >= fileCount && fileCount > 0
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
|
|
1325
|
+
let onRun: (() => void) | undefined
|
|
1326
|
+
if (step.number === 2) onRun = runPass1
|
|
1327
|
+
else if (step.number === 6) onRun = runEmbedFirstPass
|
|
1328
|
+
else if (step.number === 7) onRun = runMapFirstPass
|
|
1329
|
+
else if (step.number === 9) onRun = runEmbedSecondPass
|
|
1330
|
+
else if (step.number === 10) onRun = runMapSecondPass
|
|
1331
|
+
|
|
1332
|
+
return (
|
|
1333
|
+
<StepRow
|
|
1334
|
+
key={step.key}
|
|
1335
|
+
step={step}
|
|
1336
|
+
fileCount={fileCount}
|
|
1337
|
+
activeCount={activeCount}
|
|
1338
|
+
isActive={isActive}
|
|
1339
|
+
done={done}
|
|
1340
|
+
onRun={onRun}
|
|
1341
|
+
running={runningPass === step.key}
|
|
1342
|
+
byStatus={byStatus}
|
|
1343
|
+
totalChunks={totalChunks}
|
|
1344
|
+
/>
|
|
1345
|
+
)
|
|
1346
|
+
})}
|
|
1347
|
+
</div>
|
|
1348
|
+
|
|
1349
|
+
{}
|
|
1350
|
+
<div className="col-span-2">
|
|
1351
|
+
<Card className="h-full">
|
|
1352
|
+
<CardHeader className="pb-2 border-b">
|
|
1353
|
+
<div className="flex items-center justify-between">
|
|
1354
|
+
<CardTitle className="text-sm">File Tree</CardTitle>
|
|
1355
|
+
<div className="flex items-center gap-2">
|
|
1356
|
+
{savingSelection && (
|
|
1357
|
+
<span className="flex items-center gap-1 text-xs text-muted-foreground">
|
|
1358
|
+
<Save className="h-3 w-3 animate-pulse" /> Saving…
|
|
1359
|
+
</span>
|
|
1360
|
+
)}
|
|
1361
|
+
{selectedCount > 0 && (
|
|
1362
|
+
<Badge variant="secondary" className="text-xs">
|
|
1363
|
+
{selectedCount} selected
|
|
1364
|
+
</Badge>
|
|
1365
|
+
)}
|
|
1366
|
+
</div>
|
|
1367
|
+
</div>
|
|
1368
|
+
</CardHeader>
|
|
1369
|
+
<CardContent className="pt-2 pb-3">
|
|
1370
|
+
{!fileTree ? (
|
|
1371
|
+
<div className="py-8 text-center">
|
|
1372
|
+
<Folder className="h-8 w-8 text-muted-foreground/30 mx-auto mb-2" />
|
|
1373
|
+
<p className="text-sm text-muted-foreground">No file tree yet.</p>
|
|
1374
|
+
<p className="text-xs text-muted-foreground mt-1">Run Step 2 to scan the repository.</p>
|
|
1375
|
+
<Button size="sm" className="mt-3" onClick={runPass1} disabled={runningPass === 'build_tree'}>
|
|
1376
|
+
{runningPass === 'build_tree'
|
|
1377
|
+
? <><RefreshCw className="h-3 w-3 mr-1.5 animate-spin" />Scanning…</>
|
|
1378
|
+
: <><Play className="h-3 w-3 mr-1.5" />Scan Repository</>
|
|
1379
|
+
}
|
|
1380
|
+
</Button>
|
|
1381
|
+
</div>
|
|
1382
|
+
) : (
|
|
1383
|
+
<div className="overflow-y-auto max-h-[calc(100vh-340px)]">
|
|
1384
|
+
<TreeNode
|
|
1385
|
+
node={fileTree}
|
|
1386
|
+
selectedPaths={selectedPaths}
|
|
1387
|
+
expandedPaths={expandedPaths}
|
|
1388
|
+
fileStatuses={fileStatuses}
|
|
1389
|
+
onToggleSelect={togglePath}
|
|
1390
|
+
onToggleExpand={toggleExpand}
|
|
1391
|
+
/>
|
|
1392
|
+
</div>
|
|
1393
|
+
)}
|
|
1394
|
+
</CardContent>
|
|
1395
|
+
</Card>
|
|
1396
|
+
</div>
|
|
1397
|
+
</div>
|
|
1398
|
+
</div>
|
|
1399
|
+
)
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
// CIL[END chunk_id="cilingestionpage_cilingestionpage_1784193942"]
|