ai base
This commit is contained in:
@@ -145,6 +145,8 @@
|
||||
- 🏗️ Layer: Unknown
|
||||
- ƒ **openDrawerForTask** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **openDrawer** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **closeDrawer** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **updateResourceTask** (`Function`) `[TRIVIAL]`
|
||||
@@ -172,6 +174,31 @@
|
||||
- 📝 Track active task count for navbar indicator
|
||||
- 🏗️ Layer: UI
|
||||
- 🔗 DEPENDS_ON -> `WebSocket connection, taskDrawer store`
|
||||
- 📦 **frontend.src.lib.stores.__tests__.test_sidebar** (`Module`)
|
||||
- 📝 Unit tests for sidebar store
|
||||
- 🏗️ Layer: UI
|
||||
- 📦 **frontend.src.lib.stores.__tests__.sidebar** (`Module`)
|
||||
- 📝 Unit tests for sidebar store
|
||||
- 🏗️ Layer: Domain (Tests)
|
||||
- ƒ **test_sidebar_initial_state** (`Function`)
|
||||
- ƒ **test_toggleSidebar** (`Function`)
|
||||
- ƒ **test_setActiveItem** (`Function`)
|
||||
- 📦 **frontend.src.lib.stores.__tests__.test_activity** (`Module`)
|
||||
- 📝 Unit tests for activity store
|
||||
- 🏗️ Layer: UI
|
||||
- 🔗 DEPENDS_ON -> `frontend.src.lib.stores.taskDrawer`
|
||||
- 📦 **setupTests** (`Module`)
|
||||
- 📝 Global test setup with mocks for SvelteKit modules
|
||||
- 🏗️ Layer: UI
|
||||
- 📦 **frontend.src.lib.stores.__tests__.test_taskDrawer** (`Module`) `[CRITICAL]`
|
||||
- 📝 Unit tests for task drawer store
|
||||
- 🏗️ Layer: UI
|
||||
- 📦 **navigation** (`Mock`)
|
||||
- 📝 Mock for $app/navigation in tests
|
||||
- 📦 **stores** (`Mock`)
|
||||
- 📝 Mock for $app/stores in tests
|
||||
- 📦 **environment** (`Mock`)
|
||||
- 📝 Mock for $app/environment in tests
|
||||
- 🧩 **Select** (`Component`) `[TRIVIAL]`
|
||||
- 📝 Standardized dropdown selection component.
|
||||
- 🏗️ Layer: Atom
|
||||
@@ -284,6 +311,12 @@
|
||||
- ⬅️ READS_FROM `lib`
|
||||
- ⬅️ READS_FROM `taskDrawerStore`
|
||||
- ➡️ WRITES_TO `taskDrawerStore`
|
||||
- ƒ **loadRecentTasks** (`Function`)
|
||||
- 📝 Load recent tasks for list mode display
|
||||
- ƒ **selectTask** (`Function`)
|
||||
- 📝 Select a task from list to view details
|
||||
- ƒ **goBackToList** (`Function`)
|
||||
- 📝 Return to task list view from task details
|
||||
- 📦 **TaskDrawer** (`Module`) `[TRIVIAL]`
|
||||
- 📝 Auto-generated module for frontend/src/lib/components/layout/TaskDrawer.svelte
|
||||
- 🏗️ Layer: Unknown
|
||||
@@ -674,24 +707,24 @@
|
||||
- 📝 Updates a mapping for a specific source database.
|
||||
- ƒ **getSuggestion** (`Function`)
|
||||
- 📝 Finds a suggestion for a source database.
|
||||
- 🧩 **TaskLogViewer** (`Component`)
|
||||
- 📝 Displays detailed logs for a specific task in a modal or inline using TaskLogPanel.
|
||||
- 🧩 **TaskLogViewer** (`Component`) `[CRITICAL]`
|
||||
- 📝 Displays detailed logs for a specific task inline or in a modal using TaskLogPanel.
|
||||
- 🏗️ Layer: UI
|
||||
- 📥 Props: show: any, inline: any, taskId: any, taskStatus: any
|
||||
- 🔒 Invariant: Real-time logs are always appended without duplicates.
|
||||
- 📥 Props: show: any, inline: any, taskId: any, taskStatus: any, realTimeLogs: any
|
||||
- ⚡ Events: close
|
||||
- ⬅️ READS_FROM `t`
|
||||
- ➡️ WRITES_TO `t`
|
||||
- 📦 **handleRealTimeLogs** (`Action`)
|
||||
- 📝 Append real-time logs as they arrive from WebSocket, preventing duplicates */
|
||||
- ƒ **fetchLogs** (`Function`)
|
||||
- 📝 Fetches logs for the current task.
|
||||
- ƒ **close** (`Function`)
|
||||
- 📝 Closes the log viewer modal.
|
||||
- ƒ **onDestroy** (`Function`)
|
||||
- 📝 Cleans up the polling interval.
|
||||
- 📝 Fetches logs for the current task from API (polling fallback).
|
||||
- 📦 **TaskLogViewer** (`Module`) `[TRIVIAL]`
|
||||
- 📝 Auto-generated module for frontend/src/components/TaskLogViewer.svelte
|
||||
- 🏗️ Layer: Unknown
|
||||
- ƒ **handleFilterChange** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **handleRefresh** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- 🧩 **Footer** (`Component`) `[TRIVIAL]`
|
||||
- 📝 Displays the application footer with copyright information.
|
||||
- 🏗️ Layer: UI
|
||||
@@ -817,21 +850,25 @@
|
||||
- ⬅️ READS_FROM `app`
|
||||
- ⬅️ READS_FROM `auth`
|
||||
- 🧩 **TaskLogPanel** (`Component`)
|
||||
- 📝 Scrolls the log container to the bottom.
|
||||
- 📝 Component properties and state.
|
||||
- 🏗️ Layer: UI
|
||||
- 🔒 Invariant: Must always display logs in chronological order and respect auto-scroll preference.
|
||||
- 📥 Props: taskId: any, logs: any, autoScroll: any
|
||||
- 📥 Props: logs: any, autoScroll: any
|
||||
- ⚡ Events: filterChange
|
||||
- 📦 **TaskLogPanel** (`Module`) `[TRIVIAL]`
|
||||
- 📝 Auto-generated module for frontend/src/components/tasks/TaskLogPanel.svelte
|
||||
- 🏗️ Layer: Unknown
|
||||
- ƒ **filterLogs** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **handleFilterChange** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **scrollToBottom** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **toggleAutoScroll** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- 🧩 **LogFilterBar** (`Component`)
|
||||
- 📝 UI component for filtering logs by level, source, and text search. -->
|
||||
- 🏗️ Layer: UI -->
|
||||
- 📝 Compact filter toolbar for logs — level, source, and text search in a single dense row.
|
||||
- 🏗️ Layer: UI
|
||||
- 📥 Props: availableSources: any, selectedLevel: any, selectedSource: any, searchText: any
|
||||
- 📦 **LogFilterBar** (`Module`) `[TRIVIAL]`
|
||||
- 📝 Auto-generated module for frontend/src/components/tasks/LogFilterBar.svelte
|
||||
@@ -845,14 +882,14 @@
|
||||
- ƒ **clearFilters** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- 🧩 **LogEntryRow** (`Component`)
|
||||
- 📝 Optimized row rendering for a single log entry with color coding and progress bar support. -->
|
||||
- 🏗️ Layer: UI -->
|
||||
- 📝 Renders a single log entry with stacked layout optimized for narrow drawer panels.
|
||||
- 🏗️ Layer: UI
|
||||
- 📥 Props: log: any, showSource: any
|
||||
- ƒ **formatTime** (`Function`)
|
||||
- 📝 Format ISO timestamp to HH:MM:SS */
|
||||
- 📦 **LogEntryRow** (`Module`) `[TRIVIAL]`
|
||||
- 📝 Auto-generated module for frontend/src/components/tasks/LogEntryRow.svelte
|
||||
- 🏗️ Layer: Unknown
|
||||
- ƒ **formatTime** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **getLevelClass** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **getSourceClass** (`Function`) `[TRIVIAL]`
|
||||
@@ -1455,6 +1492,27 @@
|
||||
- 📝 Retrieves a permission by resource and action.
|
||||
- ƒ **list_permissions** (`Function`)
|
||||
- 📝 Lists all available permissions.
|
||||
- 📦 **test_auth** (`Module`)
|
||||
- 📝 Unit tests for authentication module
|
||||
- 🏗️ Layer: Domain
|
||||
- ƒ **db_session** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **auth_service** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **auth_repo** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **test_create_user** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **test_authenticate_user** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **test_create_session** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **test_role_permission_association** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **test_user_role_association** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **test_ad_group_mapping** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- 📦 **backend.core.utils.fileio** (`Module`)
|
||||
- 📝 Предоставляет набор утилит для управления файловыми операциями, включая работу с временными файлами, архивами ZIP, файлами YAML и очистку директорий.
|
||||
- 🏗️ Layer: Infra
|
||||
@@ -1573,6 +1631,25 @@
|
||||
- 🔗 CALLS -> `self.load_excel_mappings`
|
||||
- 🔗 CALLS -> `superset_client.get_dataset`
|
||||
- 🔗 CALLS -> `superset_client.update_dataset`
|
||||
- 📦 **test_logger** (`Module`)
|
||||
- 📝 Unit tests for logger module
|
||||
- 🏗️ Layer: Infra
|
||||
- ƒ **test_belief_scope_logs_entry_action_exit_at_debug** (`Function`)
|
||||
- 📝 Test that belief_scope generates [ID][Entry], [ID][Action], and [ID][Exit] logs at DEBUG level.
|
||||
- ƒ **test_belief_scope_error_handling** (`Function`)
|
||||
- 📝 Test that belief_scope logs Coherence:Failed on exception.
|
||||
- ƒ **test_belief_scope_success_coherence** (`Function`)
|
||||
- 📝 Test that belief_scope logs Coherence:OK on success.
|
||||
- ƒ **test_belief_scope_not_visible_at_info** (`Function`)
|
||||
- 📝 Test that belief_scope Entry/Exit/Coherence logs are NOT visible at INFO level.
|
||||
- ƒ **test_task_log_level_default** (`Function`)
|
||||
- 📝 Test that default task log level is INFO.
|
||||
- ƒ **test_should_log_task_level** (`Function`)
|
||||
- 📝 Test that should_log_task_level correctly filters log levels.
|
||||
- ƒ **test_configure_logger_task_log_level** (`Function`)
|
||||
- 📝 Test that configure_logger updates task_log_level.
|
||||
- ƒ **test_enable_belief_state_flag** (`Function`)
|
||||
- 📝 Test that enable_belief_state flag controls belief_scope logging.
|
||||
- 📦 **TaskLoggerModule** (`Module`) `[CRITICAL]`
|
||||
- 📝 Provides a dedicated logger for tasks with automatic source attribution.
|
||||
- 🏗️ Layer: Core
|
||||
@@ -2022,6 +2099,11 @@
|
||||
- ƒ **download_file** (`Function`)
|
||||
- 📝 Retrieve a file for download.
|
||||
- 🔗 CALLS -> `StoragePlugin.get_file_path`
|
||||
- 📦 **__init__** (`Module`) `[TRIVIAL]`
|
||||
- 📝 Auto-generated module for backend/src/api/routes/__init__.py
|
||||
- 🏗️ Layer: Unknown
|
||||
- ƒ **__getattr__** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- 📦 **TasksRouter** (`Module`)
|
||||
- 📝 Defines the FastAPI router for task-related endpoints, allowing clients to create, list, and get the status of tasks.
|
||||
- 🏗️ Layer: UI (API)
|
||||
@@ -2073,6 +2155,30 @@
|
||||
- ƒ **get_database_mappings** (`Function`)
|
||||
- 📝 Get database mapping suggestions between source and target environments
|
||||
- 🔗 CALLS -> `MappingService.get_suggestions`
|
||||
- 📦 **backend.src.api.routes.__tests__.test_dashboards** (`Module`)
|
||||
- 📝 Unit tests for Dashboards API endpoints
|
||||
- 🏗️ Layer: API
|
||||
- ƒ **test_get_dashboards_success** (`Function`)
|
||||
- ƒ **test_get_dashboards_with_search** (`Function`)
|
||||
- ƒ **test_get_dashboards_env_not_found** (`Function`)
|
||||
- ƒ **test_get_dashboards_invalid_pagination** (`Function`)
|
||||
- ƒ **test_migrate_dashboards_success** (`Function`)
|
||||
- ƒ **test_migrate_dashboards_no_ids** (`Function`)
|
||||
- ƒ **test_backup_dashboards_success** (`Function`)
|
||||
- ƒ **test_get_database_mappings_success** (`Function`)
|
||||
- ƒ **mock_get_dashboards** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **mock_get_dashboards** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- 📦 **backend.src.api.routes.__tests__.test_datasets** (`Module`)
|
||||
- 📝 Unit tests for Datasets API endpoints
|
||||
- 🏗️ Layer: API
|
||||
- ƒ **test_get_datasets_success** (`Function`)
|
||||
- ƒ **test_get_datasets_env_not_found** (`Function`)
|
||||
- ƒ **test_get_datasets_invalid_pagination** (`Function`)
|
||||
- ƒ **test_map_columns_success** (`Function`)
|
||||
- ƒ **test_map_columns_invalid_source_type** (`Function`)
|
||||
- ƒ **test_generate_docs_success** (`Function`)
|
||||
- 📦 **backend.src.models.llm** (`Module`)
|
||||
- 📝 SQLAlchemy models for LLM provider configuration and validation results.
|
||||
- 🏗️ Layer: Domain
|
||||
@@ -2157,6 +2263,11 @@
|
||||
- ℂ **ADGroupMapping** (`Class`)
|
||||
- 📝 Maps an Active Directory group to a local System Role.
|
||||
- 🔗 DEPENDS_ON -> `Role`
|
||||
- 📦 **test_models** (`Module`) `[TRIVIAL]`
|
||||
- 📝 Unit tests for data models
|
||||
- 🏗️ Layer: Domain
|
||||
- ƒ **test_environment_model** (`Function`)
|
||||
- 📝 Tests that Environment model correctly stores values.
|
||||
- 📦 **backend.src.services.resource_service** (`Module`)
|
||||
- 📝 Shared service for fetching resource data with Git status and task status
|
||||
- 🏗️ Layer: Service
|
||||
@@ -2229,6 +2340,8 @@
|
||||
- 📦 **backend.src.services** (`Module`)
|
||||
- 📝 Package initialization for services module
|
||||
- 🏗️ Layer: Core
|
||||
- ƒ **__getattr__** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- 📦 **backend.src.services.auth_service** (`Module`)
|
||||
- 📝 Orchestrates authentication business logic.
|
||||
- 🏗️ Layer: Service
|
||||
@@ -2291,6 +2404,15 @@
|
||||
- 📝 Helper to get an initialized SupersetClient for an environment.
|
||||
- ƒ **get_suggestions** (`Function`)
|
||||
- 📝 Fetches databases from both environments and returns fuzzy matching suggestions.
|
||||
- 📦 **backend.src.services.__tests__.test_resource_service** (`Module`)
|
||||
- 📝 Unit tests for ResourceService
|
||||
- 🏗️ Layer: Service
|
||||
- ƒ **test_get_dashboards_with_status** (`Function`)
|
||||
- ƒ **test_get_datasets_with_status** (`Function`)
|
||||
- ƒ **test_get_activity_summary** (`Function`)
|
||||
- ƒ **test_get_git_status_for_dashboard_no_repo** (`Function`)
|
||||
- ƒ **test_get_last_task_for_resource** (`Function`)
|
||||
- ƒ **test_extract_resource_name_from_task** (`Function`)
|
||||
- 📦 **BackupPlugin** (`Module`)
|
||||
- 📝 A plugin that provides functionality to back up Superset dashboards.
|
||||
- 🏗️ Layer: App
|
||||
@@ -2652,11 +2774,6 @@
|
||||
- 📝 Test sub-context logger uses new source.
|
||||
- ƒ **test_multiple_sub_contexts** (`Function`)
|
||||
- 📝 Test creating multiple sub-contexts.
|
||||
- 📦 **backend.tests.test_resource_service** (`Module`)
|
||||
- 📝 Contract-driven tests for ResourceService
|
||||
- ƒ **test_get_dashboards_with_status** (`Function`)
|
||||
- ƒ **test_get_dashboards_with_status** (`Function`) `[TRIVIAL]`
|
||||
- 📝 Auto-detected function (orphan)
|
||||
- ƒ **test_belief_scope_logs_entry_action_exit_at_debug** (`Function`)
|
||||
- 📝 Test that belief_scope generates [ID][Entry], [ID][Action], and [ID][Exit] logs at DEBUG level.
|
||||
- ƒ **test_belief_scope_error_handling** (`Function`)
|
||||
37
.ai/ROOT.md
Normal file
37
.ai/ROOT.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# [DEF:Project_Knowledge_Map:Root]
|
||||
# @TIER: CRITICAL
|
||||
# @PURPOSE: Global navigation map for AI-Agent (GRACE Knowledge Graph).
|
||||
# @LAST_UPDATE: 2026-02-19
|
||||
|
||||
## 1. SYSTEM STANDARDS (Rules of the Game)
|
||||
Strict policies and formatting rules.
|
||||
* **Constitution:** High-level architectural and business invariants.
|
||||
* Ref: `.ai/standards/constitution.md` -> `[DEF:Std:Constitution]`
|
||||
* **Architecture:** Service boundaries and tech stack decisions.
|
||||
* Ref: `.ai/standards/architecture.md` -> `[DEF:Std:Architecture]`
|
||||
* **Plugin Design:** Rules for building and integrating Plugins.
|
||||
* Ref: `.ai/standards/plugin_design.md` -> `[DEF:Std:Plugin]`
|
||||
* **API Design:** Rules for FastAPI endpoints and Pydantic models.
|
||||
* Ref: `.ai/standards/api_design.md` -> `[DEF:Std:API_FastAPI]`
|
||||
* **UI Design:** SvelteKit and Tailwind CSS component standards.
|
||||
* Ref: `.ai/standards/ui_design.md` -> `[DEF:Std:UI_Svelte]`
|
||||
* **Semantic Mapping:** Using `[DEF:]` and belief scopes.
|
||||
* Ref: `.ai/standards/semantics.md` -> `[DEF:Std:Semantics]`
|
||||
|
||||
## 2. FEW-SHOT EXAMPLES (Patterns)
|
||||
Use these for code generation (Style Transfer).
|
||||
* **FastAPI Route:** Reference implementation of a task-based route.
|
||||
* Ref: `.ai/shots/backend_route.py` -> `[DEF:Shot:FastAPI_Route]`
|
||||
* **Svelte Component:** Reference implementation of a sidebar/navigation component.
|
||||
* Ref: `.ai/shots/frontend_component.svelte` -> `[DEF:Shot:Svelte_Component]`
|
||||
* **Plugin Module:** Reference implementation of a task plugin.
|
||||
* Ref: `.ai/shots/plugin_example.py` -> `[DEF:Shot:Plugin_Example]`
|
||||
|
||||
## 3. DOMAIN MAP (Modules)
|
||||
* **Project Map:** `.ai/PROJECT_MAP.md` -> `[DEF:Project_Map]`
|
||||
* **Backend Core:** `backend/src/core` -> `[DEF:Module:Backend_Core]`
|
||||
* **Backend API:** `backend/src/api` -> `[DEF:Module:Backend_API]`
|
||||
* **Frontend Lib:** `frontend/src/lib` -> `[DEF:Module:Frontend_Lib]`
|
||||
* **Specifications:** `specs/` -> `[DEF:Module:Specs]`
|
||||
|
||||
# [/DEF:Project_Knowledge_Map]
|
||||
57
.ai/shots/backend_route.py
Normal file
57
.ai/shots/backend_route.py
Normal file
@@ -0,0 +1,57 @@
|
||||
# [DEF:Shot:FastAPI_Route:Example]
|
||||
# @PURPOSE: Reference implementation of a task-based route using GRACE-Poly.
|
||||
# @RELATION: IMPLEMENTS -> [DEF:Std:API_FastAPI]
|
||||
|
||||
from typing import List, Dict, Any, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from pydantic import BaseModel
|
||||
from ...core.logger import belief_scope
|
||||
from ...core.task_manager import TaskManager, Task
|
||||
from ...core.config_manager import ConfigManager
|
||||
from ...dependencies import get_task_manager, get_config_manager, has_permission, get_current_user
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
class CreateTaskRequest(BaseModel):
|
||||
plugin_id: str
|
||||
params: Dict[str, Any]
|
||||
|
||||
@router.post("/tasks", response_model=Task, status_code=status.HTTP_201_CREATED)
|
||||
# [DEF:create_task:Function]
|
||||
# @PURPOSE: Create and start a new task using TaskManager. Non-blocking.
|
||||
# @PARAM: request (CreateTaskRequest) - Plugin and params.
|
||||
# @PARAM: task_manager (TaskManager) - Async task executor.
|
||||
# @PARAM: config (ConfigManager) - Centralized configuration.
|
||||
# @PRE: plugin_id must exist; config must be initialized.
|
||||
# @POST: A new task is spawned; Task ID returned immediately.
|
||||
async def create_task(
|
||||
request: CreateTaskRequest,
|
||||
task_manager: TaskManager = Depends(get_task_manager),
|
||||
config: ConfigManager = Depends(get_config_manager),
|
||||
current_user = Depends(get_current_user)
|
||||
):
|
||||
# RBAC: Dynamic permission check
|
||||
has_permission(f"plugin:{request.plugin_id}", "EXECUTE")(current_user)
|
||||
|
||||
with belief_scope("create_task"):
|
||||
try:
|
||||
# 1. Action: Resolve setting using ConfigManager (Example)
|
||||
timeout = config.get("TASKS_DEFAULT_TIMEOUT", 3600)
|
||||
|
||||
# 2. Action: Spawn async task via TaskManager
|
||||
# @RELATION: CALLS -> task_manager.create_task
|
||||
task = await task_manager.create_task(
|
||||
plugin_id=request.plugin_id,
|
||||
params={**request.params, "timeout": timeout}
|
||||
)
|
||||
return task
|
||||
except Exception as e:
|
||||
# Evaluation: Proper error mapping and logging
|
||||
# @UX_STATE: Error feedback to frontend
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||
detail=f"Task creation failed: {str(e)}"
|
||||
)
|
||||
# [/DEF:create_task:Function]
|
||||
|
||||
# [/DEF:Shot:FastAPI_Route]
|
||||
63
.ai/shots/frontend_component.svelte
Normal file
63
.ai/shots/frontend_component.svelte
Normal file
@@ -0,0 +1,63 @@
|
||||
<!-- [DEF:Shot:Svelte_Component:Example] -->
|
||||
# @PURPOSE: Reference implementation of a task-spawning component using Constitution rules.
|
||||
# @RELATION: IMPLEMENTS -> [DEF:Std:UI_Svelte]
|
||||
|
||||
<script>
|
||||
/**
|
||||
* @TIER: STANDARD
|
||||
* @PURPOSE: Action button to spawn a new task.
|
||||
* @LAYER: UI
|
||||
* @SEMANTICS: Task, Creation, Button
|
||||
* @RELATION: CALLS -> postApi
|
||||
*
|
||||
* @UX_STATE: Idle -> Button enabled with primary color.
|
||||
* @UX_STATE: Loading -> Button disabled with spinner while postApi resolves.
|
||||
* @UX_FEEDBACK: toast.success on completion; toast.error on failure.
|
||||
* @UX_TEST: Idle -> {click: spawnTask, expected: loading state then success}
|
||||
*/
|
||||
import { postApi } from "$lib/api.js";
|
||||
import { t } from "$lib/i18n";
|
||||
import { toast } from "$lib/stores/toast";
|
||||
|
||||
export let plugin_id = "";
|
||||
export let params = {};
|
||||
|
||||
let isLoading = false;
|
||||
|
||||
async def spawnTask() {
|
||||
isLoading = true;
|
||||
try {
|
||||
// 1. Action: Constitution Rule - MUST use postApi wrapper
|
||||
const response = await postApi("/api/tasks", {
|
||||
plugin_id,
|
||||
params
|
||||
});
|
||||
|
||||
// 2. Feedback: UX state management
|
||||
if (response.task_id) {
|
||||
toast.success($t.tasks.spawned_success);
|
||||
}
|
||||
} catch (error) {
|
||||
// 3. Recovery: Evaluation & UI reporting
|
||||
toast.error(`${$t.errors.task_failed}: ${error.message}`);
|
||||
} finally {
|
||||
isLoading = false;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<button
|
||||
on:click={spawnTask}
|
||||
disabled={isLoading}
|
||||
class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded-lg flex items-center gap-2"
|
||||
>
|
||||
{#if isLoading}
|
||||
<span class="animate-spin text-sm">🌀</span>
|
||||
{/if}
|
||||
<span>{$t.actions.start_task}</span>
|
||||
</button>
|
||||
|
||||
<style>
|
||||
/* Local styles minimized as per Constitution Rule III */
|
||||
</style>
|
||||
<!-- [/DEF:Shot:Svelte_Component] -->
|
||||
67
.ai/shots/plugin_example.py
Normal file
67
.ai/shots/plugin_example.py
Normal file
@@ -0,0 +1,67 @@
|
||||
# [DEF:Shot:Plugin_Example:Example]
|
||||
# @PURPOSE: Reference implementation of a plugin following GRACE standards.
|
||||
# @RELATION: IMPLEMENTS -> [DEF:Std:Plugin]
|
||||
|
||||
from typing import Dict, Any, Optional
|
||||
from ..core.plugin_base import PluginBase
|
||||
from ..core.task_manager.context import TaskContext
|
||||
|
||||
class ExamplePlugin(PluginBase):
|
||||
@property
|
||||
def id(self) -> str:
|
||||
return "example-plugin"
|
||||
|
||||
@property
|
||||
def name(self) -> str:
|
||||
return "Example Plugin"
|
||||
|
||||
@property
|
||||
def description(self) -> str:
|
||||
return "A simple plugin that demonstrates structured logging and progress tracking."
|
||||
|
||||
@property
|
||||
def version(self) -> str:
|
||||
return "1.0.0"
|
||||
|
||||
# [DEF:get_schema:Function]
|
||||
# @PURPOSE: Defines input validation schema.
|
||||
def get_schema(self) -> Dict[str, Any]:
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"message": {
|
||||
"type": "string",
|
||||
"title": "Message",
|
||||
"description": "A message to log.",
|
||||
"default": "Hello, GRACE!",
|
||||
}
|
||||
},
|
||||
"required": ["message"],
|
||||
}
|
||||
# [/DEF:get_schema:Function]
|
||||
|
||||
# [DEF:execute:Function]
|
||||
# @PURPOSE: Core plugin logic with structured logging and progress reporting.
|
||||
# @PARAM: params (Dict) - Validated input parameters.
|
||||
# @PARAM: context (TaskContext) - Execution context with logging and progress tools.
|
||||
async def execute(self, params: Dict[str, Any], context: Optional[TaskContext] = None):
|
||||
message = params["message"]
|
||||
|
||||
# 1. Action: Structured Logging with Source Attribution
|
||||
if context:
|
||||
log = context.logger.with_source("example_plugin")
|
||||
log.info(f"Starting execution with message: {message}")
|
||||
|
||||
# 2. Action: Progress Reporting
|
||||
log.progress("Processing step 1...", percent=25)
|
||||
# Simulating some async work...
|
||||
# await some_async_op()
|
||||
|
||||
log.progress("Processing step 2...", percent=75)
|
||||
log.info("Execution completed successfully.")
|
||||
else:
|
||||
# Fallback for manual/standalone execution
|
||||
print(f"Standalone execution: {message}")
|
||||
# [/DEF:execute:Function]
|
||||
|
||||
# [/DEF:Shot:Plugin_Example]
|
||||
47
.ai/standards/api_design.md
Normal file
47
.ai/standards/api_design.md
Normal file
@@ -0,0 +1,47 @@
|
||||
# [DEF:Std:API_FastAPI:Standard]
|
||||
# @TIER: CRITICAL
|
||||
# @PURPOSE: Unification of all FastAPI endpoints following GRACE-Poly.
|
||||
# @LAYER: UI (API)
|
||||
# @INVARIANT: All non-trivial route logic must be wrapped in `belief_scope`.
|
||||
# @INVARIANT: Every module and function MUST have `[DEF:]` anchors and metadata.
|
||||
|
||||
## 1. ROUTE MODULE DEFINITION
|
||||
Every API route file must start with a module definition header:
|
||||
```python
|
||||
# [DEF:ModuleName:Module]
|
||||
# @TIER: [CRITICAL | STANDARD | TRIVIAL]
|
||||
# @SEMANTICS: list, of, keywords
|
||||
# @PURPOSE: High-level purpose of the module.
|
||||
# @LAYER: UI (API)
|
||||
# @RELATION: DEPENDS_ON -> [OtherModule]
|
||||
```
|
||||
|
||||
## 2. FUNCTION DEFINITION & CONTRACT
|
||||
Every endpoint handler must be decorated with `[DEF:]` and explicit metadata before the implementation:
|
||||
```python
|
||||
@router.post("/endpoint", response_model=ModelOut)
|
||||
# [DEF:function_name:Function]
|
||||
# @PURPOSE: What it does (brief, high-entropy).
|
||||
# @PARAM: param_name (Type) - Description.
|
||||
# @PRE: Conditions before execution (e.g., auth, existence).
|
||||
# @POST: Expected state after execution.
|
||||
# @RETURN: What it returns.
|
||||
async def function_name(...):
|
||||
with belief_scope("function_name"):
|
||||
# Implementation
|
||||
pass
|
||||
# [/DEF:function_name:Function]
|
||||
```
|
||||
|
||||
## 3. DEPENDENCY INJECTION & CORE SERVICES
|
||||
* **Auth:** `Depends(get_current_user)` for authentication.
|
||||
* **Perms:** `Depends(has_permission("resource", "ACTION"))` for RBAC.
|
||||
* **Config:** Use `Depends(get_config_manager)` for settings. Hardcoding is FORBIDDEN.
|
||||
* **Tasks:** Long-running operations must be executed via `TaskManager`. API routes should return Task ID and be non-blocking.
|
||||
|
||||
## 4. ERROR HANDLING
|
||||
* Raise `HTTPException` from the router layer.
|
||||
* Use `try-except` blocks within `belief_scope` to ensure proper error logging and classification.
|
||||
* Do not leak internal implementation details in error responses.
|
||||
|
||||
# [/DEF:Std:API_FastAPI]
|
||||
25
.ai/standards/architecture.md
Normal file
25
.ai/standards/architecture.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# [DEF:Std:Architecture:Standard]
|
||||
# @TIER: CRITICAL
|
||||
# @PURPOSE: Core architectural decisions and service boundaries.
|
||||
# @LAYER: Infra
|
||||
# @INVARIANT: ss-tools MUST remain a standalone service (Orchestrator).
|
||||
# @INVARIANT: Backend: FastAPI, Frontend: SvelteKit.
|
||||
|
||||
## 1. ORCHESTRATOR VS INSTANCE
|
||||
* **Role:** ss-tools is a "Manager of Managers". It sits ABOVE Superset environments.
|
||||
* **Isolation:** Do not integrate directly into Superset as a plugin to maintain multi-environment management capability.
|
||||
* **Tech Stack:**
|
||||
* Backend: Python 3.9+ with FastAPI (Asynchronous logic).
|
||||
* Frontend: SvelteKit + Tailwind CSS (Reactive UX).
|
||||
|
||||
## 2. COMPONENT BOUNDARIES
|
||||
* **Plugins:** All business logic must be encapsulated in Plugins (`backend/src/plugins/`).
|
||||
* **TaskManager:** All long-running operations MUST be handled by the TaskManager.
|
||||
* **Security:** Independent RBAC system managed in `auth.db`.
|
||||
|
||||
## 3. INTEGRATION STRATEGY
|
||||
* **Superset API:** Communication via REST API.
|
||||
* **Database:** Local SQLite for metadata (`tasks.db`, `auth.db`, `migrations.db`).
|
||||
* **Filesystem:** Local storage for backups and git repositories.
|
||||
|
||||
# [/DEF:Std:Architecture]
|
||||
36
.ai/standards/constitution.md
Normal file
36
.ai/standards/constitution.md
Normal file
@@ -0,0 +1,36 @@
|
||||
# [DEF:Std:Constitution:Standard]
|
||||
# @TIER: CRITICAL
|
||||
# @PURPOSE: Supreme Law of the Repository. High-level architectural and business invariants.
|
||||
# @VERSION: 2.3.0
|
||||
# @LAST_UPDATE: 2026-02-19
|
||||
# @INVARIANT: Any deviation from this Constitution constitutes a build failure.
|
||||
|
||||
## 1. CORE PRINCIPLES
|
||||
|
||||
### I. Semantic Protocol Compliance
|
||||
* **Ref:** `[DEF:Std:Semantics]` (formerly `semantic_protocol.md`)
|
||||
* **Law:** All code must adhere to the Axioms (Meaning First, Contract First, etc.).
|
||||
* **Compliance:** Strict matching of Anchors (`[DEF]`), Tags (`@KEY`), and structures is mandatory.
|
||||
|
||||
### II. Modular Plugin Architecture
|
||||
* **Pattern:** Everything is a Plugin inheriting from `PluginBase`.
|
||||
* **Centralized Config:** Use `ConfigManager` via `get_config_manager()`. Hardcoding is FORBIDDEN.
|
||||
|
||||
### III. Unified Frontend Experience
|
||||
* **Styling:** Tailwind CSS First. Minimize scoped `<style>`.
|
||||
* **i18n:** All user-facing text must be in `src/lib/i18n`.
|
||||
* **API:** Use `requestApi` / `fetchApi` wrappers. Native `fetch` is FORBIDDEN.
|
||||
|
||||
### IV. Security & RBAC
|
||||
* **Permissions:** Every Plugin must define unique permission strings (e.g., `plugin:name:execute`).
|
||||
* **Auth:** Mandatory registration in `auth.db`.
|
||||
|
||||
### V. Independent Testability
|
||||
* **Requirement:** Every feature must define "Independent Tests" for isolated verification.
|
||||
|
||||
### VI. Asynchronous Execution
|
||||
* **TaskManager:** Long-running operations must be async tasks.
|
||||
* **Non-Blocking:** API endpoints return Task ID immediately.
|
||||
* **Observability:** Real-time updates via WebSocket.
|
||||
|
||||
# [/DEF:Std:Constitution]
|
||||
32
.ai/standards/plugin_design.md
Normal file
32
.ai/standards/plugin_design.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# [DEF:Std:Plugin:Standard]
|
||||
# @TIER: CRITICAL
|
||||
# @PURPOSE: Standards for building and integrating Plugins.
|
||||
# @LAYER: Domain (Plugin)
|
||||
# @INVARIANT: All plugins MUST inherit from `PluginBase`.
|
||||
# @INVARIANT: All plugins MUST be located in `backend/src/plugins/`.
|
||||
|
||||
## 1. PLUGIN CONTRACT
|
||||
Every plugin must implement the following properties and methods:
|
||||
* `id`: Unique string (e.g., `"my-plugin"`).
|
||||
* `name`: Human-readable name.
|
||||
* `description`: Brief purpose.
|
||||
* `version`: Semantic version.
|
||||
* `get_schema()`: Returns JSON schema for input validation.
|
||||
* `execute(params: Dict[str, Any], context: TaskContext)`: Core async logic.
|
||||
|
||||
## 2. STRUCTURED LOGGING (TASKCONTEXT)
|
||||
Plugins MUST use `TaskContext` for logging to ensure proper source attribution:
|
||||
* **Source Attribution:** Use `context.logger.with_source("src_name")` for specific operations (e.g., `"superset_api"`, `"git"`, `"llm"`).
|
||||
* **Levels:**
|
||||
* `DEBUG`: Detailed diagnostics (API responses).
|
||||
* `INFO`: Operational milestones (start/end).
|
||||
* `WARNING`: Recoverable issues.
|
||||
* `ERROR`: Failures stopping execution.
|
||||
* **Progress:** Use `context.logger.progress("msg", percent=XX)` for long-running tasks.
|
||||
|
||||
## 3. BEST PRACTICES
|
||||
1. **Asynchronous Execution:** Always use `async/await` for I/O operations.
|
||||
2. **Schema Validation:** Ensure the `get_schema()` precisely matches the `execute()` input expectations.
|
||||
3. **Isolation:** Plugins should be self-contained and not depend on other plugins directly. Use core services (`ConfigManager`, `TaskManager`) via dependency injection or the provided `context`.
|
||||
|
||||
# [/DEF:Std:Plugin]
|
||||
97
.ai/standards/semantics.md
Normal file
97
.ai/standards/semantics.md
Normal file
@@ -0,0 +1,97 @@
|
||||
### **SYSTEM STANDARD: GRACE-Poly (UX Edition)**
|
||||
|
||||
ЗАДАЧА: Генерация кода (Python/Svelte).
|
||||
РЕЖИМ: Строгий. Детерминированный. Без болтовни.
|
||||
|
||||
#### I. ЗАКОН (АКСИОМЫ)
|
||||
1. Смысл первичен. Код вторичен.
|
||||
2. Контракт (@PRE/@POST) — источник истины.
|
||||
**3. UX — это логика, а не декор. Состояния интерфейса — часть контракта.**
|
||||
4. Структура `[DEF]...[/DEF]` — нерушима.
|
||||
5. Архитектура в Header — неизменяема.
|
||||
6. Сложность фрактала ограничена: модуль < 300 строк.
|
||||
|
||||
#### II. СИНТАКСИС (ЖЕСТКИЙ ФОРМАТ)
|
||||
ЯКОРЬ (Контейнер):
|
||||
Начало: `# [DEF:id:Type]` (Python) | `<!-- [DEF:id:Type] -->` (Svelte)
|
||||
Конец: `# [/DEF:id:Type]` (Python) | `<!-- [/DEF:id:Type] -->` (Svelte) (ОБЯЗАТЕЛЬНО для аккумуляции)
|
||||
Типы: Module, Class, Function, Component, Store.
|
||||
|
||||
ТЕГ (Метаданные):
|
||||
Вид: `# @KEY: Value` (внутри DEF, до кода).
|
||||
|
||||
ГРАФ (Связи):
|
||||
Вид: `# @RELATION: PREDICATE -> TARGET_ID`
|
||||
Предикаты: DEPENDS_ON, CALLS, INHERITS, IMPLEMENTS, DISPATCHES, **BINDS_TO**.
|
||||
|
||||
#### III. СТРУКТУРА ФАЙЛА
|
||||
1. HEADER (Всегда первый):
|
||||
[DEF:filename:Module]
|
||||
@TIER: [CRITICAL|STANDARD|TRIVIAL] (Дефолт: STANDARD)
|
||||
@SEMANTICS: [keywords]
|
||||
@PURPOSE: [Главная цель]
|
||||
@LAYER: [Domain/UI/Infra]
|
||||
@RELATION: [Зависимости]
|
||||
@INVARIANT: [Незыблемое правило]
|
||||
|
||||
2. BODY: Импорты -> Реализация.
|
||||
3. FOOTER: [/DEF:filename]
|
||||
|
||||
#### IV. КОНТРАКТ (DBC & UX)
|
||||
Расположение: Внутри [DEF], ПЕРЕД кодом.
|
||||
Стиль Python: Комментарии `# @TAG`.
|
||||
Стиль Svelte: JSDoc `/** @tag */` внутри `<script>`.
|
||||
|
||||
**Базовые Теги:**
|
||||
@PURPOSE: Суть (High Entropy).
|
||||
@PRE: Входные условия.
|
||||
@POST: Гарантии выхода.
|
||||
@SIDE_EFFECT: Мутации, IO.
|
||||
|
||||
**UX Теги (Svelte/Frontend):**
|
||||
**@UX_STATE:** `[StateName] -> Визуальное поведение` (Idle, Loading, Error).
|
||||
**@UX_FEEDBACK:** Реакция системы (Toast, Shake, Red Border).
|
||||
**@UX_RECOVERY:** Механизм исправления ошибки пользователем (Retry, Clear Input).
|
||||
|
||||
**UX Testing Tags (для Tester Agent):**
|
||||
**@UX_TEST:** Спецификация теста для UX состояния.
|
||||
Формат: `@UX_TEST: [state] -> {action, expected}`
|
||||
Пример: `@UX_TEST: Idle -> {click: toggle, expected: isExpanded=true}`
|
||||
|
||||
Правило: Не используй `assert` в коде, используй `if/raise` или `guards`.
|
||||
|
||||
#### V. АДАПТАЦИЯ (TIERS)
|
||||
Определяется тегом `@TIER` в Header.
|
||||
|
||||
1. **CRITICAL** (Core/Security/**Complex UI**):
|
||||
- Требование: Полный контракт (включая **все @UX теги**), Граф, Инварианты, Строгие Логи.
|
||||
- **@TEST_DATA**: Обязательные эталонные данные для тестирования. Формат:
|
||||
```
|
||||
@TEST_DATA: fixture_name -> {JSON_PATH} | {INLINE_DATA}
|
||||
```
|
||||
Примеры:
|
||||
- `@TEST_DATA: valid_user -> {./fixtures/users.json#valid}`
|
||||
- `@TEST_DATA: empty_state -> {"dashboards": [], "total": 0}`
|
||||
- Tester Agent **ОБЯЗАН** использовать @TEST_DATA при написании тестов для CRITICAL модулей.
|
||||
2. **STANDARD** (BizLogic/**Forms**):
|
||||
- Требование: Базовый контракт (@PURPOSE, @UX_STATE), Логи, @RELATION.
|
||||
- @TEST_DATA: Рекомендуется для Complex Forms.
|
||||
3. **TRIVIAL** (DTO/**Atoms**):
|
||||
- Требование: Только Якоря [DEF] и @PURPOSE.
|
||||
|
||||
#### VI. ЛОГИРОВАНИЕ (BELIEF STATE & TASK LOGS)
|
||||
Цель: Трассировка для самокоррекции и пользовательский мониторинг.
|
||||
Python:
|
||||
- Системные логи: Context Manager `with belief_scope("ID"):`.
|
||||
- Логи задач: `context.logger.info("msg", source="component")`.
|
||||
Svelte: `console.log("[ID][STATE] Msg")`.
|
||||
Состояния: Entry -> Action -> Coherence:OK / Failed -> Exit.
|
||||
Инвариант: Каждый лог задачи должен иметь атрибут `source` для фильтрации.
|
||||
|
||||
#### VII. АЛГОРИТМ ГЕНЕРАЦИИ
|
||||
1. АНАЛИЗ. Оцени TIER, слой и UX-требования.
|
||||
2. КАРКАС. Создай `[DEF]`, Header и Контракты.
|
||||
3. РЕАЛИЗАЦИЯ. Напиши логику, удовлетворяющую Контракту (и UX-состояниям).
|
||||
4. ЗАМЫКАНИЕ. Закрой все `[/DEF]`.
|
||||
|
||||
ЕСЛИ ошибка или противоречие -> СТОП. Выведи `[COHERENCE_CHECK_FAILED]`.
|
||||
74
.ai/standards/ui_design.md
Normal file
74
.ai/standards/ui_design.md
Normal file
@@ -0,0 +1,74 @@
|
||||
# [DEF:Std:UI_Svelte:Standard]
|
||||
# @TIER: CRITICAL
|
||||
# @PURPOSE: Unification of all Svelte components following GRACE-Poly (UX Edition).
|
||||
# @LAYER: UI
|
||||
# @INVARIANT: Every component MUST have `<!-- [DEF:] -->` anchors and UX tags.
|
||||
# @INVARIANT: Use Tailwind CSS for all styling (no custom CSS without justification).
|
||||
|
||||
## 1. UX PHILOSOPHY: RESOURCE-CENTRIC
|
||||
* **Definition:** Navigation and actions revolve around Resources (Dashboards, Datasets), not Tools (Migration, Git).
|
||||
* **Discovery:** All actions (Migrate, Backup, Git) for a resource MUST be grouped together (e.g., in a dropdown menu).
|
||||
* **Traceability:** Every action must be linked to a Task ID with visible logs in the Task Drawer.
|
||||
|
||||
## 2. COMPONENT ARCHITECTURE: GLOBAL TASK DRAWER
|
||||
* **Role:** A single, persistent slide-out panel (`GlobalTaskDrawer.svelte`) in `+layout.svelte`.
|
||||
* **Triggering:** Opens automatically when a task starts or when a user clicks a status badge.
|
||||
* **Interaction:** Interactive elements (Password prompts, Mapping tables) MUST be rendered INSIDE the Drawer, not as center-screen modals.
|
||||
|
||||
## 3. COMPONENT STRUCTURE & CORE RULES
|
||||
* **Styling:** Tailwind CSS utility classes are MANDATORY. Minimize scoped `<style>`.
|
||||
* **Localization:** All user-facing text must use `$t` from `src/lib/i18n`.
|
||||
* **API Calls:** Use `requestApi` / `fetchApi` wrappers. Native `fetch` is FORBIDDEN.
|
||||
* **Anchors:** Every component MUST have `<!-- [DEF:] -->` anchors and UX tags.
|
||||
|
||||
## 2. COMPONENT TEMPLATE
|
||||
Each Svelte file must follow this structure:
|
||||
```html
|
||||
<!-- [DEF:ComponentName:Component] -->
|
||||
<script>
|
||||
/**
|
||||
* @TIER: [CRITICAL | STANDARD | TRIVIAL]
|
||||
* @PURPOSE: Brief description of the component purpose.
|
||||
* @LAYER: UI
|
||||
* @SEMANTICS: list, of, keywords
|
||||
* @RELATION: DEPENDS_ON -> [OtherComponent|Store]
|
||||
*
|
||||
* @UX_STATE: [StateName] -> Visual behavior description.
|
||||
* @UX_FEEDBACK: System reaction (e.g., Toast, Shake).
|
||||
* @UX_RECOVERY: Error recovery mechanism.
|
||||
* @UX_TEST: [state] -> {action, expected}
|
||||
*/
|
||||
import { ... } from "...";
|
||||
|
||||
// Exports (Props)
|
||||
export let prop_name = "...";
|
||||
|
||||
// Logic
|
||||
</script>
|
||||
|
||||
<!-- HTML Template -->
|
||||
<div class="...">
|
||||
...
|
||||
</div>
|
||||
|
||||
<style>
|
||||
/* Optional: Local styles using @apply only */
|
||||
</style>
|
||||
<!-- [/DEF:ComponentName:Component] -->
|
||||
```
|
||||
|
||||
## 2. STATE MANAGEMENT & STORES
|
||||
* **Subscription:** Use `$` prefix for reactive store access (e.g., `$sidebarStore`).
|
||||
* **Data Flow:** Mark store interactions in `[DEF:]` metadata:
|
||||
* `# @RELATION: BINDS_TO -> store_id`
|
||||
|
||||
## 3. UI/UX BEST PRACTICES
|
||||
* **Transitions:** Use Svelte built-in transitions for UI state changes.
|
||||
* **Feedback:** Always provide visual feedback for async actions (Loading spinners, skeleton loaders).
|
||||
* **Modularity:** Break down components into "Atoms" (Trivial) and "Orchestrators" (Critical).
|
||||
|
||||
## 4. ACCESSIBILITY (A11Y)
|
||||
* Ensure proper ARIA roles and keyboard navigation for interactive elements.
|
||||
* Use semantic HTML tags (`<nav>`, `<header>`, `<main>`, `<footer>`).
|
||||
|
||||
# [/DEF:Std:UI_Svelte]
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Auto-generated from all feature plans. Last updated: 2025-12-19
|
||||
|
||||
## Knowledge Graph (GRACE)
|
||||
**CRITICAL**: This project uses a GRACE Knowledge Graph for context. Always load the root map first:
|
||||
- **Root Map**: `.ai/ROOT.md` -> `[DEF:Project_Knowledge_Map:Root]`
|
||||
- **Project Map**: `.ai/PROJECT_MAP.md` -> `[DEF:Project_Map]`
|
||||
- **Standards**: Read `.ai/standards/` for architecture and style rules.
|
||||
|
||||
## Active Technologies
|
||||
- Python 3.9+, Node.js 18+ + `uvicorn`, `npm`, `bash` (003-project-launch-script)
|
||||
- Python 3.9+, Node.js 18+ + SvelteKit, FastAPI, Tailwind CSS (inferred from existing frontend) (004-integrate-svelte-kit)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
---
|
||||
description: USE SEMANTIC
|
||||
---
|
||||
Прочитай semantic_protocol.md. ОБЯЗАТЕЛЬНО используй его при разработке
|
||||
Прочитай .ai/standards/semantics.md. ОБЯЗАТЕЛЬНО используй его при разработке
|
||||
@@ -18,7 +18,7 @@ Identify inconsistencies, duplications, ambiguities, and underspecified items ac
|
||||
|
||||
**STRICTLY READ-ONLY**: Do **not** modify any files. Output a structured analysis report. Offer an optional remediation plan (user must explicitly approve before any follow-up editing commands would be invoked manually).
|
||||
|
||||
**Constitution Authority**: The project constitution (`.specify/memory/constitution.md`) is **non-negotiable** within this analysis scope. Constitution conflicts are automatically CRITICAL and require adjustment of the spec, plan, or tasks—not dilution, reinterpretation, or silent ignoring of the principle. If a principle itself needs to change, that must occur in a separate, explicit constitution update outside `/speckit.analyze`.
|
||||
**Constitution Authority**: The project constitution (`.ai/standards/constitution.md`) is **non-negotiable** within this analysis scope. Constitution conflicts are automatically CRITICAL and require adjustment of the spec, plan, or tasks—not dilution, reinterpretation, or silent ignoring of the principle. If a principle itself needs to change, that must occur in a separate, explicit constitution update outside `/speckit.analyze`.
|
||||
|
||||
## Execution Steps
|
||||
|
||||
@@ -62,8 +62,8 @@ Load only the minimal necessary context from each artifact:
|
||||
|
||||
**From constitution:**
|
||||
|
||||
- Load `.specify/memory/constitution.md` for principle validation
|
||||
- Load `semantic_protocol.md` for technical standard validation
|
||||
- Load `.ai/standards/constitution.md` for principle validation
|
||||
- Load `.ai/standards/semantics.md` for technical standard validation
|
||||
|
||||
### 3. Build Semantic Models
|
||||
|
||||
|
||||
@@ -16,11 +16,11 @@ You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
## Outline
|
||||
|
||||
You are updating the project constitution at `.specify/memory/constitution.md`. This file is a TEMPLATE containing placeholder tokens in square brackets (e.g. `[PROJECT_NAME]`, `[PRINCIPLE_1_NAME]`). Your job is to (a) collect/derive concrete values, (b) fill the template precisely, and (c) propagate any amendments across dependent artifacts.
|
||||
You are updating the project constitution at `.ai/standards/constitution.md`. This file is a TEMPLATE containing placeholder tokens in square brackets (e.g. `[PROJECT_NAME]`, `[PRINCIPLE_1_NAME]`). Your job is to (a) collect/derive concrete values, (b) fill the template precisely, and (c) propagate any amendments across dependent artifacts.
|
||||
|
||||
Follow this execution flow:
|
||||
|
||||
1. Load the existing constitution template at `.specify/memory/constitution.md`.
|
||||
1. Load the existing constitution template at `.ai/standards/constitution.md`.
|
||||
- Identify every placeholder token of the form `[ALL_CAPS_IDENTIFIER]`.
|
||||
**IMPORTANT**: The user might require less or more principles than the ones used in the template. If a number is specified, respect that - follow the general template. You will update the doc accordingly.
|
||||
|
||||
@@ -61,7 +61,7 @@ Follow this execution flow:
|
||||
- Dates ISO format YYYY-MM-DD.
|
||||
- Principles are declarative, testable, and free of vague language ("should" → replace with MUST/SHOULD rationale where appropriate).
|
||||
|
||||
7. Write the completed constitution back to `.specify/memory/constitution.md` (overwrite).
|
||||
7. Write the completed constitution back to `.ai/standards/constitution.md` (overwrite).
|
||||
|
||||
8. Output a final summary to the user with:
|
||||
- New version and bump rationale.
|
||||
@@ -79,4 +79,4 @@ If the user supplies partial updates (e.g., only one principle revision), still
|
||||
|
||||
If critical info missing (e.g., ratification date truly unknown), insert `TODO(<FIELD_NAME>): explanation` and include in the Sync Impact Report under deferred items.
|
||||
|
||||
Do not create a new template; always operate on the existing `.specify/memory/constitution.md` file.
|
||||
Do not create a new template; always operate on the existing `.ai/standards/constitution.md` file.
|
||||
|
||||
@@ -51,7 +51,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
||||
- Automatically proceed to step 3
|
||||
|
||||
3. Load and analyze the implementation context:
|
||||
- **REQUIRED**: Read `semantic_protocol.md` for strict coding standards and contract requirements
|
||||
- **REQUIRED**: Read `.ai/standards/semantics.md` for strict coding standards and contract requirements
|
||||
- **REQUIRED**: Read tasks.md for the complete task list and execution plan
|
||||
- **REQUIRED**: Read plan.md for tech stack, architecture, and file structure
|
||||
- **IF EXISTS**: Read data-model.md for entities and relationships
|
||||
@@ -117,7 +117,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
||||
- **Validation checkpoints**: Verify each phase completion before proceeding
|
||||
|
||||
7. Implementation execution rules:
|
||||
- **Strict Adherence**: Apply `semantic_protocol.md` rules - every file must start with [DEF] header, include @TIER, and define contracts.
|
||||
- **Strict Adherence**: Apply `.ai/standards/semantics.md` rules - every file must start with [DEF] header, include @TIER, and define contracts.
|
||||
- **CRITICAL Contracts**: If a task description contains a contract summary (e.g., `CRITICAL: PRE: ..., POST: ...`), these constraints are **MANDATORY** and must be strictly implemented in the code using guards/assertions (if applicable per protocol).
|
||||
- **Setup first**: Initialize project structure, dependencies, configuration
|
||||
- **Tests before code**: If you need to write tests for contracts, entities, and integration scenarios
|
||||
|
||||
@@ -22,7 +22,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
||||
|
||||
1. **Setup**: Run `.specify/scripts/bash/setup-plan.sh --json` from repo root and parse JSON for FEATURE_SPEC, IMPL_PLAN, SPECS_DIR, BRANCH. For single quotes in args like "I'm Groot", use escape syntax: e.g 'I'\''m Groot' (or double-quote if possible: "I'm Groot").
|
||||
|
||||
2. **Load context**: Read FEATURE_SPEC, `ux_reference.md`, `semantic_protocol.md` and `.specify/memory/constitution.md`. Load IMPL_PLAN template (already copied).
|
||||
2. **Load context**: Read `.ai/ROOT.md` and `.ai/PROJECT_MAP.md` to understand the project structure and navigation. Then read required standards: `.ai/standards/constitution.md` and `.ai/standards/semantics.md`. Load IMPL_PLAN template.
|
||||
|
||||
3. **Execute plan workflow**: Follow the structure in IMPL_PLAN template to:
|
||||
- Fill Technical Context (mark unknowns as "NEEDS CLARIFICATION")
|
||||
@@ -73,7 +73,7 @@ You **MUST** consider the user input before proceeding (if not empty).
|
||||
- Entity name, fields, relationships, validation rules.
|
||||
|
||||
2. **Design & Verify Contracts (Semantic Protocol)**:
|
||||
- **Drafting**: Define [DEF] Headers and Contracts for all new modules based on `semantic_protocol.md`.
|
||||
- **Drafting**: Define [DEF] Headers and Contracts for all new modules based on `.ai/standards/semantics.md`.
|
||||
- **TIER Classification**: Explicitly assign `@TIER: [CRITICAL|STANDARD|TRIVIAL]` to each module.
|
||||
- **CRITICAL Requirements**: For all CRITICAL modules, define full `@PRE`, `@POST`, and (if UI) `@UX_STATE` contracts.
|
||||
- **Self-Review**:
|
||||
|
||||
@@ -20,7 +20,7 @@ Execute full testing cycle: analyze code for testable modules, write tests with
|
||||
|
||||
1. **NEVER delete existing tests** - Only update if they fail due to bugs in the test or implementation
|
||||
2. **NEVER duplicate tests** - Check existing tests first before creating new ones
|
||||
3. **Use TEST_DATA fixtures** - For CRITICAL tier modules, read @TEST_DATA from semantic_protocol.md
|
||||
3. **Use TEST_DATA fixtures** - For CRITICAL tier modules, read @TEST_DATA from .ai/standards/semantics.md
|
||||
4. **Co-location required** - Write tests in `__tests__` directories relative to the code being tested
|
||||
|
||||
## Execution Steps
|
||||
@@ -40,7 +40,7 @@ Determine:
|
||||
- Identify completed implementation tasks (not test tasks)
|
||||
- Extract file paths that need tests
|
||||
|
||||
**From semantic_protocol.md:**
|
||||
**From .ai/standards/semantics.md:**
|
||||
- Read @TIER annotations for modules
|
||||
- For CRITICAL modules: Read @TEST_DATA fixtures
|
||||
|
||||
@@ -61,7 +61,7 @@ Create coverage matrix:
|
||||
For each module requiring tests:
|
||||
|
||||
1. **Check existing tests**: Scan `__tests__/` for duplicates
|
||||
2. **Read TEST_DATA**: If CRITICAL tier, read @TEST_DATA from semantic_protocol.md
|
||||
2. **Read TEST_DATA**: If CRITICAL tier, read @TEST_DATA from .ai/standards/semantics.md
|
||||
3. **Write test**: Follow co-location strategy
|
||||
- Python: `src/module/__tests__/test_module.py`
|
||||
- Svelte: `src/lib/components/__tests__/test_component.test.js`
|
||||
|
||||
@@ -6,7 +6,7 @@ customModes:
|
||||
You are Kilo Code, acting as a QA and Test Engineer. Your primary goal is to ensure maximum test coverage, maintain test quality, and preserve existing tests.
|
||||
Your responsibilities include:
|
||||
- WRITING TESTS: Create comprehensive unit tests following TDD principles, using co-location strategy (`__tests__` directories).
|
||||
- TEST DATA: For CRITICAL tier modules, you MUST use @TEST_DATA fixtures defined in semantic_protocol.md. Read and apply them in your tests.
|
||||
- TEST DATA: For CRITICAL tier modules, you MUST use @TEST_DATA fixtures defined in .ai/standards/semantics.md. Read and apply them in your tests.
|
||||
- DOCUMENTATION: Maintain test documentation in `specs/<feature>/tests/` directory with coverage reports and test case specifications.
|
||||
- VERIFICATION: Run tests, analyze results, and ensure all tests pass.
|
||||
- PROTECTION: NEVER delete existing tests. NEVER duplicate tests - check for existing tests first.
|
||||
@@ -18,8 +18,9 @@ customModes:
|
||||
- browser
|
||||
- mcp
|
||||
customInstructions: |
|
||||
1. CO-LOCATION: Write tests in `__tests__` subdirectories relative to the code being tested (Fractal Strategy).
|
||||
2. TEST DATA MANDATORY: For CRITICAL modules, read @TEST_DATA from semantic_protocol.md and use fixtures in tests.
|
||||
1. KNOWLEDGE GRAPH: ALWAYS read .ai/ROOT.md first to understand the project structure and navigation.
|
||||
2. CO-LOCATION: Write tests in `__tests__` subdirectories relative to the code being tested (Fractal Strategy).
|
||||
2. TEST DATA MANDATORY: For CRITICAL modules, read @TEST_DATA from .ai/standards/semantics.md and use fixtures in tests.
|
||||
3. UX CONTRACT TESTING: For Svelte components with @UX_STATE, @UX_FEEDBACK, @UX_RECOVERY tags, create comprehensive UX tests.
|
||||
4. NO DELETION: Never delete existing tests - only update if they fail due to legitimate bugs.
|
||||
5. NO DUPLICATION: Check existing tests in `__tests__/` before creating new ones. Reuse existing test patterns.
|
||||
@@ -29,10 +30,10 @@ customModes:
|
||||
- slug: semantic
|
||||
name: Semantic Agent
|
||||
roleDefinition: |-
|
||||
You are Kilo Code, a Semantic Agent responsible for maintaining the semantic integrity of the codebase. Your primary goal is to ensure that all code entities (Modules, Classes, Functions, Components) are properly annotated with semantic anchors and tags as defined in `semantic_protocol.md`.
|
||||
Your core responsibilities are: 1. **Semantic Mapping**: You run and maintain the `generate_semantic_map.py` script to generate up-to-date semantic maps (`semantics/semantic_map.json`, `specs/project_map.md`) and compliance reports (`semantics/reports/*.md`). 2. **Compliance Auditing**: You analyze the generated compliance reports to identify files with low semantic coverage or parsing errors. 3. **Semantic Enrichment**: You actively edit code files to add missing semantic anchors (`[DEF:...]`, `[/DEF:...]`) and mandatory tags (`@PURPOSE`, `@LAYER`, etc.) to improve the global compliance score. 4. **Protocol Enforcement**: You strictly adhere to the syntax and rules defined in `semantic_protocol.md` when modifying code.
|
||||
You are Kilo Code, a Semantic Agent responsible for maintaining the semantic integrity of the codebase. Your primary goal is to ensure that all code entities (Modules, Classes, Functions, Components) are properly annotated with semantic anchors and tags as defined in `.ai/standards/semantics.md`.
|
||||
Your core responsibilities are: 1. **Semantic Mapping**: You run and maintain the `generate_semantic_map.py` script to generate up-to-date semantic maps (`semantics/semantic_map.json`, `.ai/PROJECT_MAP.md`) and compliance reports (`semantics/reports/*.md`). 2. **Compliance Auditing**: You analyze the generated compliance reports to identify files with low semantic coverage or parsing errors. 3. **Semantic Enrichment**: You actively edit code files to add missing semantic anchors (`[DEF:...]`, `[/DEF:...]`) and mandatory tags (`@PURPOSE`, `@LAYER`, etc.) to improve the global compliance score. 4. **Protocol Enforcement**: You strictly adhere to the syntax and rules defined in `.ai/standards/semantics.md` when modifying code.
|
||||
You have access to the full codebase and tools to read, write, and execute scripts. You should prioritize fixing "Critical Parsing Errors" (unclosed anchors) before addressing missing metadata.
|
||||
whenToUse: Use this mode when you need to update the project's semantic map, fix semantic compliance issues (missing anchors/tags/DbC ), or analyze the codebase structure. This mode is specialized for maintaining the `semantic_protocol.md` standards.
|
||||
whenToUse: Use this mode when you need to update the project's semantic map, fix semantic compliance issues (missing anchors/tags/DbC ), or analyze the codebase structure. This mode is specialized for maintaining the `.ai/standards/semantics.md` standards.
|
||||
description: Codebase semantic mapping and compliance expert
|
||||
customInstructions: Always check `semantics/reports/` for the latest compliance status before starting work. When fixing a file, try to fix all semantic issues in that file at once. After making a batch of fixes, run `python3 generate_semantic_map.py` to verify improvements.
|
||||
groups:
|
||||
@@ -50,7 +51,7 @@ customModes:
|
||||
For each task, you must read the relevant workflow file from `.kilocode/workflows/` and follow its Execution Steps precisely.
|
||||
whenToUse: Use this mode when you need to run any /speckit.* command or when dealing with high-level feature planning, specification writing, or project management tasks.
|
||||
description: Executes SpecKit workflows for feature management
|
||||
customInstructions: 1. Always read the specific workflow file in `.kilocode/workflows/` before executing a command. 2. Adhere strictly to the "Operating Constraints" and "Execution Steps" in the workflow files.
|
||||
customInstructions: 1. Always read `.ai/ROOT.md` first to understand the Knowledge Graph structure. 2. Read the specific workflow file in `.kilocode/workflows/` before executing a command. 3. Adhere strictly to the "Operating Constraints" and "Execution Steps" in the workflow files.
|
||||
groups:
|
||||
- read
|
||||
- edit
|
||||
@@ -59,12 +60,14 @@ customModes:
|
||||
source: project
|
||||
- slug: coder
|
||||
name: Coder
|
||||
roleDefinition: You are Kilo Code, acting as an Implementation Specialist. Your primary goal is to write code that strictly follows the Semantic Protocol defined in `semantic_protocol.md`.
|
||||
roleDefinition: You are Kilo Code, acting as an Implementation Specialist. Your primary goal is to write code that strictly follows the Semantic Protocol defined in `.ai/standards/semantics.md`.
|
||||
whenToUse: Use this mode when you need to implement features, write code, or fix issues based on test reports.
|
||||
description: Implementation Specialist - Semantic Protocol Compliant
|
||||
customInstructions: |
|
||||
1. SEMANTIC PROTOCOL: ALWAYS use semantic_protocol.md as your single source of truth.
|
||||
2. ANCHOR FORMAT: Use #[DEF:filename:Type] at start and #[/DEF:filename] at end.
|
||||
1. KNOWLEDGE GRAPH: ALWAYS read .ai/ROOT.md first to understand the project structure and navigation.
|
||||
2. CONSTITUTION: Strictly follow architectural invariants in .ai/standards/constitution.md.
|
||||
3. SEMANTIC PROTOCOL: ALWAYS use .ai/standards/semantics.md as your source of truth for syntax.
|
||||
4. ANCHOR FORMAT: Use #[DEF:filename:Type] at start and #[/DEF:filename] at end.
|
||||
3. TAGS: Add @PURPOSE, @LAYER, @TIER, @RELATION, @PRE, @POST, @UX_STATE, @UX_FEEDBACK, @UX_RECOVERY.
|
||||
4. TIER COMPLIANCE:
|
||||
- CRITICAL: Full contract + all UX tags + strict logging
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
<!--
|
||||
SYNC IMPACT REPORT
|
||||
Version: 2.3.0 (Tailwind CSS & Scoped CSS Minimization)
|
||||
Changes:
|
||||
- Updated Principle III: Added mandatory requirement for Tailwind CSS usage and minimization of scoped `<style>` blocks in Svelte components.
|
||||
- Version bump: 2.2.0 -> 2.3.0 (Minor: New material guidance added).
|
||||
Templates Status:
|
||||
- .specify/templates/plan-template.md: ✅ Aligned.
|
||||
- .specify/templates/spec-template.md: ✅ Aligned.
|
||||
- .specify/templates/tasks-template.md: ✅ Aligned.
|
||||
-->
|
||||
# Semantic Code Generation Constitution
|
||||
|
||||
## Core Principles
|
||||
|
||||
### I. Semantic Protocol Compliance
|
||||
The file `semantic_protocol.md` is the **sole and authoritative technical standard** for this project.
|
||||
- **Law**: All code must adhere to the Axioms (Meaning First, Contract First, etc.) defined in the Protocol.
|
||||
- **Syntax & Structure**: Anchors (`[DEF]`), Tags (`@KEY`), and File Structures must strictly match the Protocol.
|
||||
- **Compliance**: Any deviation from `semantic_protocol.md` constitutes a build failure.
|
||||
|
||||
### II. Everything is a Plugin & Centralized Config
|
||||
All functional extensions, tools, or major features must be implemented as modular Plugins inheriting from `PluginBase`.
|
||||
- **Modularity**: Logic should not reside in standalone services or scripts unless strictly necessary for core infrastructure. This ensures a unified execution model via the `TaskManager`.
|
||||
- **Configuration Discipline**: All configuration access (environments, settings, paths) MUST use the `ConfigManager`. In the backend, the singleton instance MUST be obtained via dependency injection (`get_config_manager()`). Hardcoding environment IDs (e.g., "1") or paths is STRICTLY FORBIDDEN.
|
||||
|
||||
### III. Unified Frontend Experience
|
||||
To ensure a consistent and accessible user experience, all frontend implementations must strictly adhere to the unified design and localization standards.
|
||||
- **Component Reusability**: All UI elements MUST utilize the standardized Svelte component library (`src/lib/ui`) and centralized design tokens.
|
||||
- **Tailwind CSS First**: All styling MUST be implemented using Tailwind CSS utility classes. The use of scoped `<style>` blocks in Svelte components MUST be minimized and reserved only for complex animations or third-party overrides that cannot be achieved via Tailwind.
|
||||
- **Internationalization (i18n)**: All user-facing text MUST be extracted to the translation system (`src/lib/i18n`).
|
||||
- **Backend Communication**: All API requests MUST use the `requestApi` wrapper (or its derivatives like `fetchApi`, `postApi`) from `src/lib/api.js`. Direct use of the native `fetch` API for backend communication is FORBIDDEN to ensure consistent authentication (JWT) and error handling.
|
||||
|
||||
### IV. Security & Access Control
|
||||
To support the Role-Based Access Control (RBAC) system, all functional components must define explicit permissions.
|
||||
- **Granular Permissions**: Every Plugin MUST define a unique permission string (e.g., `plugin:name:execute`) required for its operation.
|
||||
- **Registration**: These permissions MUST be registered in the system database (`auth.db`) during initialization.
|
||||
|
||||
### V. Independent Testability
|
||||
Every feature specification MUST define "Independent Tests" that allow the feature to be verified in isolation.
|
||||
- **Decoupling**: Features should be designed such that they can be tested without requiring the full application state or external dependencies where possible.
|
||||
- **Verification**: A feature is not complete until its Independent Test scenarios pass.
|
||||
|
||||
### VI. Asynchronous Execution
|
||||
All long-running or resource-intensive operations (migrations, analysis, backups, external API calls) MUST be executed as asynchronous tasks via the `TaskManager`.
|
||||
- **Non-Blocking**: HTTP API endpoints MUST NOT block on these operations; they should spawn a task and return a Task ID.
|
||||
- **Observability**: Tasks MUST emit real-time status updates via the WebSocket infrastructure.
|
||||
|
||||
## Governance
|
||||
This Constitution establishes the "Semantic Code Generation Protocol" as the supreme law of this repository.
|
||||
|
||||
- **Authoritative Source**: `semantic_protocol.md` defines the specific implementation rules for Principle I.
|
||||
- **Amendments**: Changes to core principles require a Constitution amendment. Changes to technical syntax require a Protocol update.
|
||||
- **Compliance**: Failure to adhere to the Protocol constitutes a build failure.
|
||||
|
||||
**Version**: 2.3.0 | **Ratified**: 2025-12-19 | **Last Amended**: 2026-02-18
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
Auto-generated from all feature plans. Last updated: [DATE]
|
||||
|
||||
## Knowledge Graph (GRACE)
|
||||
**CRITICAL**: This project uses a GRACE Knowledge Graph for context. Always load the root map first:
|
||||
- **Root Map**: `.ai/ROOT.md` -> `[DEF:Project_Knowledge_Map:Root]`
|
||||
- **Project Map**: `.ai/PROJECT_MAP.md` -> `[DEF:Project_Map]`
|
||||
- **Standards**: Read `.ai/standards/` for architecture and style rules.
|
||||
|
||||
## Active Technologies
|
||||
|
||||
[EXTRACTED FROM ALL PLAN.MD FILES]
|
||||
|
||||
@@ -112,4 +112,4 @@ directories captured above]
|
||||
| [e.g., DashboardAPI] | CRITICAL | valid_dashboard | spec.md#test-data-fixtures |
|
||||
| [e.g., TaskDrawer] | CRITICAL | task_states | spec.md#test-data-fixtures |
|
||||
|
||||
**Note**: Tester Agent MUST use these fixtures when writing unit tests for CRITICAL modules. See `semantic_protocol.md` for @TEST_DATA syntax.
|
||||
**Note**: Tester Agent MUST use these fixtures when writing unit tests for CRITICAL modules. See `.ai/standards/semantics.md` for @TEST_DATA syntax.
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
|
||||
## Разработка
|
||||
Проект следует строгим правилам разработки:
|
||||
1. **Semantic Code Generation**: Использование протокола `semantic_protocol.md` для обеспечения надежности кода.
|
||||
1. **Semantic Code Generation**: Использование протокола `.ai/standards/semantics.md` для обеспечения надежности кода.
|
||||
2. **Design by Contract (DbC)**: Определение предусловий и постусловий для ключевых функций.
|
||||
3. **Constitution**: Соблюдение правил, описанных в конституции проекта в папке `.specify/`.
|
||||
|
||||
|
||||
@@ -185,33 +185,32 @@
|
||||
<!-- Drawer Overlay -->
|
||||
{#if isOpen}
|
||||
<div
|
||||
class="drawer-overlay"
|
||||
class="fixed inset-0 bg-black/40 backdrop-blur-sm z-50"
|
||||
on:click={handleOverlayClick}
|
||||
on:keydown={(e) => e.key === "Escape" && handleClose()}
|
||||
on:keydown={(e) => e.key === 'Escape' && handleClose()}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
aria-label="Close drawer"
|
||||
>
|
||||
<!-- Drawer Panel -->
|
||||
<div
|
||||
class="drawer"
|
||||
class="fixed right-0 top-0 h-full w-full max-w-[560px] bg-slate-900 shadow-[-8px_0_30px_rgba(0,0,0,0.3)] flex flex-col z-50 transition-transform duration-300 ease-out"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-label="Task drawer"
|
||||
>
|
||||
<!-- Header -->
|
||||
<div class="drawer-header">
|
||||
<div class="header-left">
|
||||
<div class="flex items-center justify-between px-5 py-3.5 border-b border-slate-800 bg-slate-900">
|
||||
<div class="flex items-center gap-2.5">
|
||||
{#if !activeTaskId && recentTasks.length > 0}
|
||||
<!-- Показываем индикатор что это режим списка -->
|
||||
<span class="list-indicator">
|
||||
<span class="flex items-center justify-center p-1.5 mr-1 text-cyan-400">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01"/>
|
||||
</svg>
|
||||
</span>
|
||||
{:else if activeTaskId}
|
||||
<button
|
||||
class="back-btn"
|
||||
class="flex items-center justify-center p-1.5 rounded-md text-slate-500 bg-transparent border-none cursor-pointer transition-all hover:text-slate-100 hover:bg-slate-800"
|
||||
on:click={goBackToList}
|
||||
aria-label="Back to task list"
|
||||
>
|
||||
@@ -228,20 +227,20 @@
|
||||
</svg>
|
||||
</button>
|
||||
{/if}
|
||||
<h2 class="drawer-title">
|
||||
{activeTaskId ? ($t.tasks?.details_logs || "Task Details & Logs") : "Recent Tasks"}
|
||||
<h2 class="text-sm font-semibold text-slate-100 tracking-tight">
|
||||
{activeTaskId ? ($t.tasks?.details_logs || 'Task Details & Logs') : 'Recent Tasks'}
|
||||
</h2>
|
||||
{#if shortTaskId}
|
||||
<span class="task-id-badge">{shortTaskId}…</span>
|
||||
<span class="text-xs font-mono text-slate-500 bg-slate-800 px-2 py-0.5 rounded">{shortTaskId}…</span>
|
||||
{/if}
|
||||
{#if taskStatus}
|
||||
<span class="status-badge {taskStatus.toLowerCase()}"
|
||||
<span class="text-xs font-semibold uppercase tracking-wider px-2 py-0.5 rounded-full {taskStatus.toLowerCase() === 'running' ? 'text-cyan-400 bg-cyan-400/10 border border-cyan-400/20' : taskStatus.toLowerCase() === 'success' ? 'text-green-400 bg-green-400/10 border border-green-400/20' : 'text-red-400 bg-red-400/10 border border-red-400/20'}"
|
||||
>{taskStatus}</span
|
||||
>
|
||||
{/if}
|
||||
</div>
|
||||
<button
|
||||
class="close-btn"
|
||||
class="p-1.5 rounded-md text-slate-500 bg-transparent border-none cursor-pointer transition-all hover:text-slate-100 hover:bg-slate-800"
|
||||
on:click={handleClose}
|
||||
aria-label="Close drawer"
|
||||
>
|
||||
@@ -260,7 +259,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Content -->
|
||||
<div class="drawer-content">
|
||||
<div class="flex-1 overflow-hidden flex flex-col">
|
||||
{#if activeTaskId}
|
||||
<TaskLogViewer
|
||||
inline={true}
|
||||
@@ -269,31 +268,28 @@
|
||||
{realTimeLogs}
|
||||
/>
|
||||
{:else if loadingTasks}
|
||||
<!-- Loading State -->
|
||||
<div class="loading-state">
|
||||
<div class="spinner"></div>
|
||||
<div class="flex flex-col items-center justify-center p-12 text-slate-500">
|
||||
<div class="w-8 h-8 border-2 border-slate-200 border-t-blue-500 rounded-full animate-spin mb-4"></div>
|
||||
<p>Loading tasks...</p>
|
||||
</div>
|
||||
{:else if recentTasks.length > 0}
|
||||
<!-- Task List -->
|
||||
<div class="task-list">
|
||||
<h3 class="task-list-title">Recent Tasks</h3>
|
||||
<div class="p-4">
|
||||
<h3 class="text-sm font-semibold text-slate-100 mb-4 pb-2 border-b border-slate-800">Recent Tasks</h3>
|
||||
{#each recentTasks as task}
|
||||
<button
|
||||
class="task-item"
|
||||
class="flex items-center gap-3 w-full p-3 mb-2 bg-slate-800 border border-slate-700 rounded-lg cursor-pointer transition-all hover:bg-slate-700 hover:border-slate-600 text-left"
|
||||
on:click={() => selectTask(task)}
|
||||
>
|
||||
<span class="task-item-id">{task.id?.substring(0, 8) || 'N/A'}...</span>
|
||||
<span class="task-item-plugin">{task.plugin_id || 'Unknown'}</span>
|
||||
<span class="task-item-status {task.status?.toLowerCase()}">{task.status || 'UNKNOWN'}</span>
|
||||
<span class="font-mono text-xs text-slate-500">{task.id?.substring(0, 8) || 'N/A'}...</span>
|
||||
<span class="flex-1 text-sm text-slate-100 font-medium">{task.plugin_id || 'Unknown'}</span>
|
||||
<span class="text-xs font-semibold uppercase px-2 py-1 rounded-full {task.status?.toLowerCase() === 'running' || task.status?.toLowerCase() === 'pending' ? 'bg-cyan-500/15 text-cyan-400' : task.status?.toLowerCase() === 'completed' || task.status?.toLowerCase() === 'success' ? 'bg-green-500/15 text-green-400' : task.status?.toLowerCase() === 'failed' || task.status?.toLowerCase() === 'error' ? 'bg-red-500/15 text-red-400' : 'bg-slate-500/15 text-slate-400'}">{task.status || 'UNKNOWN'}</span>
|
||||
</button>
|
||||
{/each}
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Empty State -->
|
||||
<div class="empty-state">
|
||||
<div class="flex flex-col items-center justify-center h-full text-slate-500">
|
||||
<svg
|
||||
class="empty-icon"
|
||||
class="w-12 h-12 mb-3 text-slate-700"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
@@ -304,16 +300,16 @@
|
||||
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"
|
||||
/>
|
||||
</svg>
|
||||
<p>{$t.tasks?.select_task || "No recent tasks"}</p>
|
||||
<p>{$t.tasks?.select_task || 'No recent tasks'}</p>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<!-- Footer -->
|
||||
<div class="drawer-footer">
|
||||
<div class="footer-pulse"></div>
|
||||
<p class="drawer-footer-text">
|
||||
{$t.tasks?.footer_text || "Task continues running in background"}
|
||||
<div class="flex items-center gap-2 justify-center px-4 py-2.5 border-t border-slate-800 bg-slate-900">
|
||||
<div class="w-1.5 h-1.5 rounded-full bg-cyan-400 animate-pulse"></div>
|
||||
<p class="text-xs text-slate-500">
|
||||
{$t.tasks?.footer_text || 'Task continues running in background'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -322,292 +318,4 @@
|
||||
|
||||
<!-- [/DEF:TaskDrawer:Component] -->
|
||||
|
||||
<style>
|
||||
.drawer-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background-color: rgba(0, 0, 0, 0.4);
|
||||
backdrop-filter: blur(2px);
|
||||
z-index: 50;
|
||||
}
|
||||
|
||||
.drawer {
|
||||
position: fixed;
|
||||
right: 0;
|
||||
top: 0;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
max-width: 560px;
|
||||
background-color: #0f172a;
|
||||
box-shadow: -8px 0 30px rgba(0, 0, 0, 0.3);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
z-index: 50;
|
||||
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.drawer-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 0.875rem 1.25rem;
|
||||
border-bottom: 1px solid #1e293b;
|
||||
background-color: #0f172a;
|
||||
}
|
||||
|
||||
.header-left {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.625rem;
|
||||
}
|
||||
|
||||
.drawer-title {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: #f1f5f9;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.task-id-badge {
|
||||
font-size: 0.6875rem;
|
||||
font-family: "JetBrains Mono", "Fira Code", monospace;
|
||||
color: #64748b;
|
||||
background-color: #1e293b;
|
||||
padding: 0.125rem 0.5rem;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
font-size: 0.625rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.05em;
|
||||
padding: 0.125rem 0.5rem;
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
.status-badge.running {
|
||||
color: #22d3ee;
|
||||
background-color: rgba(34, 211, 238, 0.1);
|
||||
border: 1px solid rgba(34, 211, 238, 0.2);
|
||||
}
|
||||
|
||||
.status-badge.success {
|
||||
color: #4ade80;
|
||||
background-color: rgba(74, 222, 128, 0.1);
|
||||
border: 1px solid rgba(74, 222, 128, 0.2);
|
||||
}
|
||||
|
||||
.status-badge.failed,
|
||||
.status-badge.error {
|
||||
color: #f87171;
|
||||
background-color: rgba(248, 113, 113, 0.1);
|
||||
border: 1px solid rgba(248, 113, 113, 0.2);
|
||||
}
|
||||
|
||||
.close-btn {
|
||||
padding: 0.375rem;
|
||||
border-radius: 0.375rem;
|
||||
color: #64748b;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s;
|
||||
}
|
||||
|
||||
.close-btn:hover {
|
||||
color: #f1f5f9;
|
||||
background-color: #1e293b;
|
||||
}
|
||||
|
||||
.back-btn {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.375rem;
|
||||
border-radius: 0.375rem;
|
||||
color: #64748b;
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s;
|
||||
margin-right: 0.25rem;
|
||||
}
|
||||
|
||||
.back-btn:hover {
|
||||
color: #f1f5f9;
|
||||
background-color: #1e293b;
|
||||
}
|
||||
|
||||
.list-indicator {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.375rem;
|
||||
margin-right: 0.25rem;
|
||||
color: #22d3ee;
|
||||
}
|
||||
|
||||
.drawer-content {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.drawer-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
justify-content: center;
|
||||
padding: 0.625rem 1rem;
|
||||
border-top: 1px solid #1e293b;
|
||||
background-color: #0f172a;
|
||||
}
|
||||
|
||||
.footer-pulse {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
border-radius: 50%;
|
||||
background-color: #22d3ee;
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.3;
|
||||
}
|
||||
}
|
||||
|
||||
.drawer-footer-text {
|
||||
font-size: 0.75rem;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.loading-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 3rem;
|
||||
color: #6b7280;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border: 3px solid #e5e7eb;
|
||||
border-top-color: #3b82f6;
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.task-list {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.task-list-title {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: #f1f5f9;
|
||||
margin-bottom: 1rem;
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 1px solid #1e293b;
|
||||
}
|
||||
|
||||
.task-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
width: 100%;
|
||||
padding: 0.75rem;
|
||||
margin-bottom: 0.5rem;
|
||||
background: #1e293b;
|
||||
border: 1px solid #334155;
|
||||
border-radius: 0.5rem;
|
||||
cursor: pointer;
|
||||
transition: all 0.15s ease;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.task-item:hover {
|
||||
background: #334155;
|
||||
border-color: #475569;
|
||||
}
|
||||
|
||||
.task-item-id {
|
||||
font-family: monospace;
|
||||
font-size: 0.75rem;
|
||||
color: #64748b;
|
||||
}
|
||||
|
||||
.task-item-plugin {
|
||||
flex: 1;
|
||||
font-size: 0.875rem;
|
||||
color: #f1f5f9;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.task-item-status {
|
||||
font-size: 0.625rem;
|
||||
font-weight: 600;
|
||||
text-transform: uppercase;
|
||||
padding: 0.25rem 0.5rem;
|
||||
border-radius: 9999px;
|
||||
}
|
||||
|
||||
.task-item-status.running,
|
||||
.task-item-status.pending {
|
||||
background: rgba(34, 211, 238, 0.15);
|
||||
color: #22d3ee;
|
||||
}
|
||||
|
||||
.task-item-status.completed,
|
||||
.task-item-status.success {
|
||||
background: rgba(74, 222, 128, 0.15);
|
||||
color: #4ade80;
|
||||
}
|
||||
|
||||
.task-item-status.failed,
|
||||
.task-item-status.error {
|
||||
background: rgba(248, 113, 113, 0.15);
|
||||
color: #f87171;
|
||||
}
|
||||
|
||||
.task-item-status.cancelled {
|
||||
background: rgba(100, 116, 139, 0.15);
|
||||
color: #94a3b8;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
.empty-icon {
|
||||
width: 3rem;
|
||||
height: 3rem;
|
||||
margin-bottom: 0.75rem;
|
||||
color: #334155;
|
||||
}
|
||||
|
||||
.empty-state p {
|
||||
font-size: 0.875rem;
|
||||
color: #475569;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -363,183 +363,19 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
@apply max-w-7xl mx-auto px-4 py-6;
|
||||
}
|
||||
|
||||
.header {
|
||||
@apply flex items-center justify-between mb-6;
|
||||
}
|
||||
|
||||
.title {
|
||||
@apply text-2xl font-bold text-gray-900;
|
||||
}
|
||||
|
||||
.env-selector {
|
||||
@apply flex items-center space-x-4;
|
||||
}
|
||||
|
||||
.env-dropdown {
|
||||
@apply px-4 py-2 border border-gray-300 rounded-lg bg-white focus:outline-none focus:ring-2 focus:ring-blue-500;
|
||||
}
|
||||
|
||||
.refresh-btn {
|
||||
@apply px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 transition-colors;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
@apply px-4 py-2 border border-gray-300 rounded-lg bg-white focus:outline-none focus:ring-2 focus:ring-blue-500;
|
||||
}
|
||||
|
||||
.error-banner {
|
||||
@apply bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4 flex items-center justify-between;
|
||||
}
|
||||
|
||||
.retry-btn {
|
||||
@apply px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700 transition-colors;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
@apply flex items-center justify-between mb-4 gap-4;
|
||||
}
|
||||
|
||||
.selection-buttons {
|
||||
@apply flex items-center gap-2;
|
||||
}
|
||||
|
||||
.dataset-grid {
|
||||
@apply bg-white border border-gray-200 rounded-lg overflow-hidden;
|
||||
}
|
||||
|
||||
.grid-header {
|
||||
@apply grid grid-cols-12 gap-4 px-6 py-3 bg-gray-50 border-b border-gray-200 font-semibold text-sm text-gray-700;
|
||||
}
|
||||
|
||||
.grid-row {
|
||||
@apply grid grid-cols-12 gap-4 px-6 py-4 border-b border-gray-200 hover:bg-gray-50 transition-colors;
|
||||
}
|
||||
|
||||
.grid-row:last-child {
|
||||
@apply border-b-0;
|
||||
}
|
||||
|
||||
.col-checkbox {
|
||||
@apply col-span-1;
|
||||
}
|
||||
|
||||
.col-table-name {
|
||||
@apply col-span-3 font-medium text-gray-900;
|
||||
}
|
||||
|
||||
.col-schema {
|
||||
@apply col-span-2;
|
||||
}
|
||||
|
||||
.col-mapping {
|
||||
@apply col-span-2;
|
||||
}
|
||||
|
||||
.col-task {
|
||||
@apply col-span-3;
|
||||
}
|
||||
|
||||
.col-actions {
|
||||
@apply col-span-1;
|
||||
}
|
||||
|
||||
.mapping-progress {
|
||||
@apply w-24 h-2 rounded-full overflow-hidden;
|
||||
}
|
||||
|
||||
.mapping-bar {
|
||||
@apply h-full transition-all duration-300;
|
||||
}
|
||||
|
||||
.task-status {
|
||||
@apply inline-flex items-center space-x-2 cursor-pointer hover:text-blue-600 transition-colors;
|
||||
}
|
||||
|
||||
.action-btn {
|
||||
@apply px-3 py-1 text-sm border border-gray-300 rounded hover:bg-gray-100 transition-colors;
|
||||
}
|
||||
|
||||
.action-btn.primary {
|
||||
@apply bg-blue-600 text-white border-blue-600 hover:bg-blue-700;
|
||||
}
|
||||
|
||||
.empty-state {
|
||||
@apply py-12 text-center text-gray-500;
|
||||
}
|
||||
|
||||
.skeleton {
|
||||
@apply animate-pulse bg-gray-200 rounded;
|
||||
}
|
||||
|
||||
.floating-panel {
|
||||
@apply fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 shadow-lg p-4 transition-transform transform translate-y-full;
|
||||
}
|
||||
|
||||
.floating-panel.visible {
|
||||
@apply transform translate-y-0;
|
||||
}
|
||||
|
||||
.modal-overlay {
|
||||
@apply fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50;
|
||||
}
|
||||
|
||||
.modal {
|
||||
@apply bg-white rounded-lg shadow-xl max-w-2xl w-full mx-4 max-h-[80vh] overflow-y-auto;
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
@apply px-6 py-4 border-b border-gray-200 flex items-center justify-between relative;
|
||||
}
|
||||
|
||||
.close-modal-btn {
|
||||
@apply absolute top-4 right-4 p-2 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-full transition-all;
|
||||
}
|
||||
|
||||
.modal-body {
|
||||
@apply px-6 py-4;
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
@apply px-6 py-4 border-t border-gray-200 flex justify-end gap-3;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
@apply flex items-center justify-between px-4 py-3 bg-gray-50 border-t border-gray-200;
|
||||
}
|
||||
|
||||
.pagination-info {
|
||||
@apply text-sm text-gray-600;
|
||||
}
|
||||
|
||||
.pagination-controls {
|
||||
@apply flex items-center gap-2;
|
||||
}
|
||||
|
||||
.page-btn {
|
||||
@apply px-3 py-1 border border-gray-300 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed;
|
||||
}
|
||||
|
||||
.page-btn.active {
|
||||
@apply bg-blue-600 text-white border-blue-600;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="container">
|
||||
<div class="max-w-[80rem] mx-auto px-4 pt-6 pb-6">
|
||||
<!-- Header -->
|
||||
<div class="header">
|
||||
<h1 class="title">{$t.nav?.datasets || 'Datasets'}</h1>
|
||||
<div class="env-selector">
|
||||
<select class="env-dropdown" bind:value={selectedEnv} on:change={handleEnvChange}>
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h1 class="text-2xl font-bold text-gray-900">{$t.nav?.datasets || 'Datasets'}</h1>
|
||||
<div class="flex items-center gap-4">
|
||||
<select class="px-2 py-1 border border-gray-300 rounded bg-white focus:outline-none focus:ring-2 focus:ring-blue-500" bind:value={selectedEnv} on:change={handleEnvChange}>
|
||||
{#each environments as env}
|
||||
<option value={env.id}>{env.name}</option>
|
||||
{/each}
|
||||
</select>
|
||||
<button class="refresh-btn" on:click={loadDatasets}>
|
||||
<button class="px-2 py-1 bg-blue-600 text-white rounded hover:bg-blue-700" on:click={loadDatasets}>
|
||||
{$t.common?.refresh || 'Refresh'}
|
||||
</button>
|
||||
</div>
|
||||
@@ -547,9 +383,9 @@
|
||||
|
||||
<!-- Error Banner -->
|
||||
{#if error}
|
||||
<div class="error-banner">
|
||||
<div class="bg-red-100 border border-red-400 text-red-700 px-3 py-2 rounded mb-4 flex items-center justify-between">
|
||||
<span>{error}</span>
|
||||
<button class="retry-btn" on:click={loadDatasets}>
|
||||
<button class="px-2 py-1 bg-red-600 text-white rounded hover:bg-red-700" on:click={loadDatasets}>
|
||||
{$t.common?.retry || 'Retry'}
|
||||
</button>
|
||||
</div>
|
||||
@@ -557,29 +393,29 @@
|
||||
|
||||
<!-- Loading State -->
|
||||
{#if isLoading}
|
||||
<div class="dataset-grid">
|
||||
<div class="grid-header">
|
||||
<div class="col-checkbox skeleton h-4"></div>
|
||||
<div class="col-table-name skeleton h-4"></div>
|
||||
<div class="col-schema skeleton h-4"></div>
|
||||
<div class="col-mapping skeleton h-4"></div>
|
||||
<div class="col-task skeleton h-4"></div>
|
||||
<div class="col-actions skeleton h-4"></div>
|
||||
<div class="bg-white border border-gray-200 rounded overflow-hidden">
|
||||
<div class="grid grid-cols-12 gap-4 px-6 py-3 bg-gray-50 border-b border-gray-200 text-sm font-semibold text-gray-500">
|
||||
<div class="col-span-1 animate-pulse bg-gray-200 rounded h-4"></div>
|
||||
<div class="col-span-3 animate-pulse bg-gray-200 rounded h-4"></div>
|
||||
<div class="col-span-2 animate-pulse bg-gray-200 rounded h-4"></div>
|
||||
<div class="col-span-2 animate-pulse bg-gray-200 rounded h-4"></div>
|
||||
<div class="col-span-3 animate-pulse bg-gray-200 rounded h-4"></div>
|
||||
<div class="col-span-1 animate-pulse bg-gray-200 rounded h-4"></div>
|
||||
</div>
|
||||
{#each Array(5) as _}
|
||||
<div class="grid-row">
|
||||
<div class="col-checkbox skeleton h-4"></div>
|
||||
<div class="col-table-name skeleton h-4"></div>
|
||||
<div class="col-schema skeleton h-4"></div>
|
||||
<div class="col-mapping skeleton h-4"></div>
|
||||
<div class="col-task skeleton h-4"></div>
|
||||
<div class="col-actions skeleton h-4"></div>
|
||||
<div class="grid grid-cols-12 gap-4 px-6 py-4 border-b border-gray-200">
|
||||
<div class="col-span-1 animate-pulse bg-gray-200 rounded h-4"></div>
|
||||
<div class="col-span-3 animate-pulse bg-gray-200 rounded h-4"></div>
|
||||
<div class="col-span-2 animate-pulse bg-gray-200 rounded h-4"></div>
|
||||
<div class="col-span-2 animate-pulse bg-gray-200 rounded h-4"></div>
|
||||
<div class="col-span-3 animate-pulse bg-gray-200 rounded h-4"></div>
|
||||
<div class="col-span-1 animate-pulse bg-gray-200 rounded h-4"></div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{:else if datasets.length === 0}
|
||||
<!-- Empty State -->
|
||||
<div class="empty-state">
|
||||
<div class="py-12 text-center text-gray-500">
|
||||
<svg class="w-16 h-16 mx-auto mb-4 text-gray-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M3 3h18v18H3V3zm16 16V5H5v14h14z"/>
|
||||
</svg>
|
||||
@@ -587,17 +423,17 @@
|
||||
</div>
|
||||
{:else}
|
||||
<!-- Toolbar -->
|
||||
<div class="toolbar">
|
||||
<div class="selection-buttons">
|
||||
<div class="flex items-center justify-between mb-4 gap-4">
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
class="action-btn"
|
||||
class="px-2 py-1 text-sm border border-gray-300 rounded hover:bg-gray-100"
|
||||
on:click={handleSelectAll}
|
||||
disabled={total === 0}
|
||||
>
|
||||
{isAllSelected ? 'Deselect All' : 'Select All'}
|
||||
</button>
|
||||
<button
|
||||
class="action-btn"
|
||||
class="px-2 py-1 text-sm border border-gray-300 rounded hover:bg-gray-100"
|
||||
on:click={handleSelectVisible}
|
||||
disabled={datasets.length === 0}
|
||||
>
|
||||
@@ -612,7 +448,7 @@
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
class="search-input"
|
||||
class="px-2 py-1 border border-gray-300 rounded bg-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder="Search datasets..."
|
||||
on:input={handleSearch}
|
||||
value={searchQuery}
|
||||
@@ -621,22 +457,22 @@
|
||||
</div>
|
||||
|
||||
<!-- Dataset Grid -->
|
||||
<div class="dataset-grid">
|
||||
<div class="bg-white border border-gray-200 rounded overflow-hidden">
|
||||
<!-- Grid Header -->
|
||||
<div class="grid-header">
|
||||
<div class="col-checkbox"></div>
|
||||
<div class="col-table-name">{$t.datasets?.table_name || 'Table Name'}</div>
|
||||
<div class="col-schema">{$t.datasets?.schema || 'Schema'}</div>
|
||||
<div class="col-mapping">{$t.datasets?.mapped_fields || 'Mapped Fields'}</div>
|
||||
<div class="col-task">{$t.datasets?.last_task || 'Last Task'}</div>
|
||||
<div class="col-actions">{$t.datasets?.actions || 'Actions'}</div>
|
||||
<div class="grid grid-cols-12 gap-4 px-6 py-3 bg-gray-50 border-b border-gray-200 text-sm font-semibold text-gray-500">
|
||||
<div class="col-span-1"></div>
|
||||
<div class="col-span-3 font-medium text-gray-700">{$t.datasets?.table_name || 'Table Name'}</div>
|
||||
<div class="col-span-2">{$t.datasets?.schema || 'Schema'}</div>
|
||||
<div class="col-span-2">{$t.datasets?.mapped_fields || 'Mapped Fields'}</div>
|
||||
<div class="col-span-3">{$t.datasets?.last_task || 'Last Task'}</div>
|
||||
<div class="col-span-1">{$t.datasets?.actions || 'Actions'}</div>
|
||||
</div>
|
||||
|
||||
<!-- Grid Rows -->
|
||||
{#each datasets as dataset}
|
||||
<div class="grid-row">
|
||||
<div class="grid grid-cols-12 gap-4 px-6 py-4 border-b border-gray-200 hover:bg-gray-50 last:border-b-0">
|
||||
<!-- Checkbox -->
|
||||
<div class="col-checkbox">
|
||||
<div class="col-span-1">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={selectedIds.has(dataset.id)}
|
||||
@@ -645,7 +481,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Table Name -->
|
||||
<div class="col-table-name">
|
||||
<div class="col-span-3 font-medium text-gray-900">
|
||||
<a
|
||||
href={`/datasets/${dataset.id}?env_id=${selectedEnv}`}
|
||||
class="text-blue-600 hover:text-blue-800 hover:underline"
|
||||
@@ -655,15 +491,15 @@
|
||||
</div>
|
||||
|
||||
<!-- Schema -->
|
||||
<div class="col-schema">
|
||||
<div class="col-span-2">
|
||||
{dataset.schema}
|
||||
</div>
|
||||
|
||||
<!-- Mapping Progress -->
|
||||
<div class="col-mapping">
|
||||
<div class="col-span-2">
|
||||
{#if dataset.mappedFields}
|
||||
<div class="mapping-progress" title="{$t.datasets?.mapped_of_total || 'Mapped of total'}: {dataset.mappedFields.mapped} / {dataset.mappedFields.total}">
|
||||
<div class="mapping-bar {getMappingProgressClass(dataset.mappedFields.mapped, dataset.mappedFields.total)}" style="width: {dataset.mappedFields.mapped / dataset.mappedFields.total * 100}%"></div>
|
||||
<div class="w-24 h-2 rounded-full overflow-hidden" title="{$t.datasets?.mapped_of_total || 'Mapped of total'}: {dataset.mappedFields.mapped} / {dataset.mappedFields.total}">
|
||||
<div class="h-full transition-all {getMappingProgressClass(dataset.mappedFields.mapped, dataset.mappedFields.total)}" style="width: {dataset.mappedFields.mapped / dataset.mappedFields.total * 100}%"></div>
|
||||
</div>
|
||||
{:else}
|
||||
<span class="text-gray-400">-</span>
|
||||
@@ -671,10 +507,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Last Task -->
|
||||
<div class="col-task">
|
||||
<div class="col-span-3">
|
||||
{#if dataset.lastTask}
|
||||
<div
|
||||
class="task-status"
|
||||
class="inline-flex items-center gap-2 cursor-pointer hover:text-blue-600"
|
||||
on:click={() => handleTaskStatusClick(dataset)}
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@@ -699,10 +535,10 @@
|
||||
</div>
|
||||
|
||||
<!-- Actions -->
|
||||
<div class="col-actions">
|
||||
<div class="col-span-1">
|
||||
{#if dataset.actions.includes('map_columns')}
|
||||
<button
|
||||
class="action-btn primary"
|
||||
class="px-1 py-0.5 text-sm bg-blue-600 text-white rounded hover:bg-blue-700"
|
||||
on:click={() => handleAction(dataset, 'map_columns')}
|
||||
aria-label={$t.datasets?.action_map_columns || 'Map Columns'}
|
||||
>
|
||||
@@ -716,20 +552,20 @@
|
||||
|
||||
<!-- Pagination -->
|
||||
{#if totalPages > 1}
|
||||
<div class="pagination">
|
||||
<div class="pagination-info">
|
||||
<div class="flex items-center justify-between px-3 py-3 bg-gray-50 border-t border-gray-200">
|
||||
<div class="text-sm text-gray-500">
|
||||
Showing {((currentPage - 1) * pageSize) + 1}-{Math.min(currentPage * pageSize, total)} of {total}
|
||||
</div>
|
||||
<div class="pagination-controls">
|
||||
<div class="flex items-center gap-2">
|
||||
<button
|
||||
class="page-btn"
|
||||
class="px-2 py-1 text-sm border border-gray-300 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
on:click={() => handlePageChange(1)}
|
||||
disabled={currentPage === 1}
|
||||
>
|
||||
First
|
||||
</button>
|
||||
<button
|
||||
class="page-btn"
|
||||
class="px-2 py-1 text-sm border border-gray-300 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
on:click={() => handlePageChange(currentPage - 1)}
|
||||
disabled={currentPage === 1}
|
||||
>
|
||||
@@ -737,21 +573,21 @@
|
||||
</button>
|
||||
{#each Array.from({length: totalPages}, (_, i) => i + 1) as pageNum}
|
||||
<button
|
||||
class="page-btn {pageNum === currentPage ? 'active' : ''}"
|
||||
class="px-2 py-1 text-sm border rounded {pageNum === currentPage ? 'bg-blue-600 text-white border-blue-600' : 'border-gray-300 hover:bg-gray-100'}"
|
||||
on:click={() => handlePageChange(pageNum)}
|
||||
>
|
||||
{pageNum}
|
||||
</button>
|
||||
{/each}
|
||||
<button
|
||||
class="page-btn"
|
||||
class="px-2 py-1 text-sm border border-gray-300 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
on:click={() => handlePageChange(currentPage + 1)}
|
||||
disabled={currentPage === totalPages}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
<button
|
||||
class="page-btn"
|
||||
class="px-2 py-1 text-sm border border-gray-300 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
on:click={() => handlePageChange(totalPages)}
|
||||
disabled={currentPage === totalPages}
|
||||
>
|
||||
@@ -760,7 +596,7 @@
|
||||
</div>
|
||||
<div>
|
||||
<select
|
||||
class="env-dropdown"
|
||||
class="px-2 py-1 border border-gray-300 rounded bg-white focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
value={pageSize}
|
||||
on:change={handlePageSizeChange}
|
||||
>
|
||||
@@ -776,7 +612,7 @@
|
||||
|
||||
<!-- Floating Bulk Action Panel -->
|
||||
{#if selectedIds.size > 0}
|
||||
<div class="floating-panel visible">
|
||||
<div class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 shadow-lg p-4 translate-y-0">
|
||||
<div class="flex items-center justify-between max-w-7xl mx-auto">
|
||||
<div class="flex items-center gap-4">
|
||||
<span class="font-medium">
|
||||
@@ -785,19 +621,19 @@
|
||||
</div>
|
||||
<div class="flex gap-3">
|
||||
<button
|
||||
class="action-btn primary"
|
||||
class="px-3 py-1.5 bg-blue-600 text-white rounded hover:bg-blue-700"
|
||||
on:click={() => showMapColumnsModal = true}
|
||||
>
|
||||
Map Columns
|
||||
</button>
|
||||
<button
|
||||
class="action-btn primary"
|
||||
class="px-3 py-1.5 bg-blue-600 text-white rounded hover:bg-blue-700"
|
||||
on:click={() => showGenerateDocsModal = true}
|
||||
>
|
||||
Generate Docs
|
||||
</button>
|
||||
<button
|
||||
class="action-btn"
|
||||
class="px-3 py-1.5 border border-gray-300 rounded hover:bg-gray-100"
|
||||
on:click={() => selectedIds.clear()}
|
||||
>
|
||||
Cancel
|
||||
@@ -810,23 +646,23 @@
|
||||
|
||||
<!-- Map Columns Modal -->
|
||||
{#if showMapColumnsModal}
|
||||
<div class="modal-overlay" on:click={() => showMapColumnsModal = false}>
|
||||
<div class="modal" on:click|stopPropagation>
|
||||
<div class="modal-header">
|
||||
<div class="fixed inset-0 bg-black/50 flex items-center justify-center z-50" on:click={() => showMapColumnsModal = false}>
|
||||
<div class="bg-white rounded-lg shadow-2xl max-w-xl w-full m-4 max-h-[80vh] overflow-y-auto" on:click|stopPropagation>
|
||||
<div class="px-4 py-3 border-b border-gray-200 flex items-center justify-between relative">
|
||||
<h2 class="text-xl font-bold">Bulk Column Mapping</h2>
|
||||
<button on:click={() => showMapColumnsModal = false} class="close-modal-btn" aria-label="Close modal">
|
||||
<button on:click={() => showMapColumnsModal = false} class="absolute top-4 right-4 p-1 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-full" aria-label="Close modal">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="p-4">
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-2">Source Type</label>
|
||||
<select
|
||||
class="env-dropdown w-full"
|
||||
class="w-full px-2 py-1 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
bind:value={mapSourceType}
|
||||
>
|
||||
<option value="postgresql">PostgreSQL Comments</option>
|
||||
@@ -838,7 +674,7 @@
|
||||
<label class="block text-sm font-medium mb-2">Connection ID</label>
|
||||
<input
|
||||
type="text"
|
||||
class="search-input w-full"
|
||||
class="w-full px-2 py-1 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder="Enter connection ID..."
|
||||
bind:value={mapConnectionId}
|
||||
/>
|
||||
@@ -869,11 +705,11 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="action-btn" on:click={() => showMapColumnsModal = false}>Cancel</button>
|
||||
<div class="px-4 py-3 border-t border-gray-200 flex justify-end gap-3">
|
||||
<button class="px-3 py-1.5 border border-gray-300 rounded hover:bg-gray-100" on:click={() => showMapColumnsModal = false}>Cancel</button>
|
||||
<button
|
||||
type="button"
|
||||
class="action-btn primary"
|
||||
class="px-3 py-1.5 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
on:click|preventDefault={handleBulkMapColumns}
|
||||
disabled={selectedIds.size === 0 || (mapSourceType === 'postgresql' && !mapConnectionId) || (mapSourceType === 'xlsx' && (!mapFileData || mapFileData.length === 0))}
|
||||
>
|
||||
@@ -886,23 +722,23 @@
|
||||
|
||||
<!-- Generate Docs Modal -->
|
||||
{#if showGenerateDocsModal}
|
||||
<div class="modal-overlay" on:click={() => showGenerateDocsModal = false}>
|
||||
<div class="modal" on:click|stopPropagation>
|
||||
<div class="modal-header">
|
||||
<div class="fixed inset-0 bg-black/50 flex items-center justify-center z-50" on:click={() => showGenerateDocsModal = false}>
|
||||
<div class="bg-white rounded-lg shadow-2xl max-w-xl w-full m-4 max-h-[80vh] overflow-y-auto" on:click|stopPropagation>
|
||||
<div class="px-4 py-3 border-b border-gray-200 flex items-center justify-between relative">
|
||||
<h2 class="text-xl font-bold">Bulk Documentation Generation</h2>
|
||||
<button on:click={() => showGenerateDocsModal = false} class="close-modal-btn" aria-label="Close modal">
|
||||
<button on:click={() => showGenerateDocsModal = false} class="absolute top-4 right-4 p-1 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-full" aria-label="Close modal">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="p-4">
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium mb-2">LLM Provider</label>
|
||||
<select
|
||||
class="env-dropdown w-full"
|
||||
class="w-full px-2 py-1 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
bind:value={llmProvider}
|
||||
>
|
||||
<option value="">Select LLM provider...</option>
|
||||
@@ -925,10 +761,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button class="action-btn" on:click={() => showGenerateDocsModal = false}>Cancel</button>
|
||||
<div class="px-4 py-3 border-t border-gray-200 flex justify-end gap-3">
|
||||
<button class="px-3 py-1.5 border border-gray-300 rounded hover:bg-gray-100" on:click={() => showGenerateDocsModal = false}>Cancel</button>
|
||||
<button
|
||||
class="action-btn primary"
|
||||
class="px-3 py-1.5 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
on:click={handleBulkGenerateDocs}
|
||||
disabled={!llmProvider || selectedIds.size === 0}
|
||||
>
|
||||
@@ -940,4 +776,5 @@
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
<!-- [/DEF:DatasetHub:Page] -->
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
# @INVARIANT: All DEF anchors must have matching closing anchors; TIER determines validation strictness.
|
||||
# @RELATION: READS -> FileSystem
|
||||
# @RELATION: PRODUCES -> semantics/semantic_map.json
|
||||
# @RELATION: PRODUCES -> specs/project_map.md
|
||||
# @RELATION: PRODUCES -> .ai/PROJECT_MAP.md
|
||||
# @RELATION: PRODUCES -> semantics/reports/semantic_report_*.md
|
||||
|
||||
# [SECTION: IMPORTS]
|
||||
@@ -82,7 +82,7 @@ IGNORE_FILES = {
|
||||
"package-lock.json", "poetry.lock", "yarn.lock"
|
||||
}
|
||||
OUTPUT_JSON = "semantics/semantic_map.json"
|
||||
OUTPUT_COMPRESSED_MD = "specs/project_map.md"
|
||||
OUTPUT_COMPRESSED_MD = ".ai/PROJECT_MAP.md"
|
||||
REPORTS_DIR = "semantics/reports"
|
||||
|
||||
# Tier-based mandatory tags
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,76 +0,0 @@
|
||||
# Semantic Map Generator & Validator Design
|
||||
|
||||
## Objective
|
||||
Create a Python script (`generate_semantic_map.py`) to:
|
||||
1. Scan the codebase (`backend/`, `frontend/`) for Semantic Protocol markers.
|
||||
2. Generate a **Full Semantic Map** (JSON) for detailed machine processing.
|
||||
3. Generate a **Compressed Project Map** (Markdown) for LLM context window (~4000 tokens).
|
||||
4. Generate a **Compliance Report** (Markdown) with history tracking.
|
||||
|
||||
## Scope
|
||||
* **Languages**: Python (`.py`), Svelte (`.svelte`), JavaScript/TypeScript (`.js`, `.ts`).
|
||||
* **Protocol**: Based on `semantic_protocol.md`.
|
||||
|
||||
## 1. Parsing Logic
|
||||
|
||||
The script will use Regex to parse files textually.
|
||||
|
||||
### Python Patterns
|
||||
* **Anchor Start**: `r"#\s*\[DEF:(?P<name>[\w\.]+):(?P<type>\w+)\]"`
|
||||
* **Anchor End**: `r"#\s*\[/DEF:(?P<name>[\w\.]+):(?P<type>\w+)\]"`
|
||||
* **Tags**: `r"#\s*@(?P<tag>[A-Z_]+):\s*(?P<value>.*)"`
|
||||
|
||||
### Svelte/JS Patterns
|
||||
* **HTML Anchor Start**: `r"<!--\s*\[DEF:(?P<name>[\w\.]+):(?P<type>\w+)\]\s*-->"`
|
||||
* **HTML Anchor End**: `r"<!--\s*\[/DEF:(?P<name>[\w\.]+):(?P<type>\w+)\]\s*-->"`
|
||||
* **JS Anchor Start**: `r"//\s*\[DEF:(?P<name>[\w\.]+):(?P<type>\w+)\]"`
|
||||
* **JS Anchor End**: `r"//\s*\[/DEF:(?P<name>[\w\.]+):(?P<type>\w+)\]"`
|
||||
* **HTML Tags**: `r"@(?P<tag>[A-Z_]+):\s*(?P<value>.*)"` (inside comments)
|
||||
* **JSDoc Tags**: `r"\*\s*@(?P<tag>[a-z]+)\s+(?P<value>.*)"`
|
||||
* **Relation Tag**: `r"//\s*@RELATION:\s*(?P<type>\w+)\s*->\s*(?P<target>.*)"`
|
||||
|
||||
## 2. Output Files & Structure
|
||||
|
||||
### A. Full Map (`semantics/semantic_map.json`)
|
||||
Detailed hierarchical JSON containing all metadata, line numbers, and relations.
|
||||
```json
|
||||
{
|
||||
"project_root": "/home/user/ss-tools",
|
||||
"generated_at": "ISO-DATE",
|
||||
"modules": [ ... ]
|
||||
}
|
||||
```
|
||||
|
||||
### B. Compressed Map (`specs/project_map.md`)
|
||||
Optimized for "Full Attention" (max ~4000 tokens).
|
||||
* **Format**: Markdown Tree.
|
||||
* **Content**:
|
||||
* List of high-level Modules/Components.
|
||||
* Only critical tags: `@PURPOSE`, `@LAYER`.
|
||||
* List of public Functions/Actions (names only, or brief summary).
|
||||
* Key Relations (`DEPENDS_ON`).
|
||||
* *Omit*: Internal implementation details, line numbers, minor tags.
|
||||
|
||||
### C. Compliance Report (`semantics/reports/semantic_report_YYYYMMDD_HHMMSS.md`)
|
||||
* **Metrics**: Global Coverage %, Module-level scores.
|
||||
* **Errors**: List of broken anchors or missing mandatory tags.
|
||||
* **History**: Timestamped filename ensures history tracking.
|
||||
|
||||
## 3. Validation Rules (Scoring)
|
||||
|
||||
### Critical Errors (0% score for entity)
|
||||
1. **Unmatched Anchors**: Start tag without End tag.
|
||||
|
||||
### Metadata Warnings (Reduces score)
|
||||
1. **Missing Mandatory Tags**: `Module`/`Component` needs `@PURPOSE`, `@LAYER`.
|
||||
|
||||
## 4. Implementation Plan
|
||||
|
||||
1. **Setup**: Create `generate_semantic_map.py` and directories (`semantics/`, `semantics/reports/`).
|
||||
2. **Parser**: Implement Regex patterns.
|
||||
3. **Walker**: Recursive file walk ignoring standard ignore patterns.
|
||||
4. **Generators**:
|
||||
* `MapGenerator`: JSON dump.
|
||||
* `ContextGenerator`: Markdown tree builder with token awareness (heuristic).
|
||||
* `ReportGenerator`: Scoring and markdown formatting.
|
||||
5. **Execution**: Run script.
|
||||
Reference in New Issue
Block a user