claude-code-workflow 6.1.4 → 6.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/CLAUDE.md +10 -0
- package/.claude/agents/action-planning-agent.md +857 -778
- package/.claude/agents/cli-execution-agent.md +266 -269
- package/.claude/agents/cli-explore-agent.md +2 -2
- package/.claude/agents/cli-lite-planning-agent.md +142 -92
- package/.claude/agents/cli-planning-agent.md +4 -4
- package/.claude/agents/code-developer.md +7 -6
- package/.claude/agents/conceptual-planning-agent.md +2 -2
- package/.claude/agents/context-search-agent.md +31 -32
- package/.claude/agents/doc-generator.md +4 -4
- package/.claude/agents/memory-bridge.md +93 -93
- package/.claude/agents/test-context-search-agent.md +8 -7
- package/.claude/agents/test-fix-agent.md +7 -6
- package/.claude/commands/clean.md +516 -0
- package/.claude/commands/memory/compact.md +383 -0
- package/.claude/commands/memory/docs-full-cli.md +471 -471
- package/.claude/commands/memory/docs-related-cli.md +386 -386
- package/.claude/commands/memory/docs.md +615 -615
- package/.claude/commands/memory/load.md +5 -5
- package/.claude/commands/memory/tech-research-rules.md +310 -0
- package/.claude/commands/memory/update-full.md +332 -332
- package/.claude/commands/memory/workflow-skill-memory.md +4 -4
- package/.claude/commands/task/create.md +151 -151
- package/.claude/commands/version.md +254 -254
- package/.claude/commands/workflow/brainstorm/api-designer.md +587 -585
- package/.claude/commands/workflow/brainstorm/artifacts.md +1 -0
- package/.claude/commands/workflow/brainstorm/auto-parallel.md +443 -443
- package/.claude/commands/workflow/brainstorm/data-architect.md +220 -220
- package/.claude/commands/workflow/brainstorm/product-manager.md +200 -200
- package/.claude/commands/workflow/brainstorm/product-owner.md +200 -200
- package/.claude/commands/workflow/brainstorm/scrum-master.md +200 -200
- package/.claude/commands/workflow/brainstorm/subject-matter-expert.md +200 -200
- package/.claude/commands/workflow/brainstorm/system-architect.md +389 -387
- package/.claude/commands/workflow/brainstorm/ui-designer.md +221 -221
- package/.claude/commands/workflow/brainstorm/ux-expert.md +221 -221
- package/.claude/commands/workflow/debug.md +321 -0
- package/.claude/commands/workflow/execute.md +13 -0
- package/.claude/commands/workflow/init.md +165 -164
- package/.claude/commands/workflow/lite-execute.md +119 -13
- package/.claude/commands/workflow/lite-fix.md +623 -621
- package/.claude/commands/workflow/lite-plan.md +610 -592
- package/.claude/commands/workflow/plan.md +5 -5
- package/.claude/commands/workflow/review-module-cycle.md +2 -0
- package/.claude/commands/workflow/review-session-cycle.md +2 -0
- package/.claude/commands/workflow/review.md +297 -291
- package/.claude/commands/workflow/session/complete.md +153 -500
- package/.claude/commands/workflow/session/list.md +95 -95
- package/.claude/commands/workflow/session/resume.md +60 -60
- package/.claude/commands/workflow/session/start.md +199 -199
- package/.claude/commands/workflow/tdd-plan.md +3 -3
- package/.claude/commands/workflow/tdd-verify.md +23 -9
- package/.claude/commands/workflow/test-cycle-execute.md +2 -0
- package/.claude/commands/workflow/test-fix-gen.md +699 -699
- package/.claude/commands/workflow/tools/conflict-resolution.md +104 -18
- package/.claude/commands/workflow/tools/context-gather.md +436 -434
- package/.claude/commands/workflow/tools/task-generate-agent.md +490 -291
- package/.claude/commands/workflow/tools/task-generate-tdd.md +18 -10
- package/.claude/commands/workflow/tools/test-concept-enhanced.md +2 -1
- package/.claude/commands/workflow/tools/test-context-gather.md +1 -0
- package/.claude/commands/workflow/tools/test-task-generate.md +1 -0
- package/.claude/commands/workflow/ui-design/import-from-code.md +9 -6
- package/.claude/skills/command-guide/SKILL.md +5 -5
- package/.claude/skills/command-guide/index/all-commands.json +1 -1
- package/.claude/skills/command-guide/index/by-category.json +1 -1
- package/.claude/skills/command-guide/index/by-use-case.json +1 -1
- package/.claude/skills/command-guide/reference/agents/action-planning-agent.md +857 -778
- package/.claude/skills/command-guide/reference/agents/cli-execution-agent.md +266 -269
- package/.claude/skills/command-guide/reference/agents/cli-explore-agent.md +2 -2
- package/.claude/skills/command-guide/reference/agents/cli-lite-planning-agent.md +142 -92
- package/.claude/skills/command-guide/reference/agents/cli-planning-agent.md +4 -4
- package/.claude/skills/command-guide/reference/agents/code-developer.md +7 -6
- package/.claude/skills/command-guide/reference/agents/conceptual-planning-agent.md +2 -2
- package/.claude/skills/command-guide/reference/agents/context-search-agent.md +31 -32
- package/.claude/skills/command-guide/reference/agents/doc-generator.md +4 -4
- package/.claude/skills/command-guide/reference/agents/memory-bridge.md +93 -93
- package/.claude/skills/command-guide/reference/agents/test-context-search-agent.md +8 -7
- package/.claude/skills/command-guide/reference/agents/test-fix-agent.md +7 -6
- package/.claude/skills/command-guide/reference/commands/memory/docs-full-cli.md +471 -471
- package/.claude/skills/command-guide/reference/commands/memory/docs-related-cli.md +386 -386
- package/.claude/skills/command-guide/reference/commands/memory/docs.md +17 -16
- package/.claude/skills/command-guide/reference/commands/memory/load.md +5 -5
- package/.claude/skills/command-guide/reference/commands/memory/tech-research.md +194 -357
- package/.claude/skills/command-guide/reference/commands/memory/update-full.md +332 -332
- package/.claude/skills/command-guide/reference/commands/memory/workflow-skill-memory.md +4 -4
- package/.claude/skills/command-guide/reference/commands/task/create.md +151 -151
- package/.claude/skills/command-guide/reference/commands/version.md +254 -254
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/api-designer.md +585 -585
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/auto-parallel.md +443 -443
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/data-architect.md +220 -220
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-manager.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-owner.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/scrum-master.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/subject-matter-expert.md +200 -200
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/system-architect.md +387 -387
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ui-designer.md +221 -221
- package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ux-expert.md +221 -221
- package/.claude/skills/command-guide/reference/commands/workflow/execute.md +25 -20
- package/.claude/skills/command-guide/reference/commands/workflow/init.md +164 -164
- package/.claude/skills/command-guide/reference/commands/workflow/lite-execute.md +748 -686
- package/.claude/skills/command-guide/reference/commands/workflow/lite-fix.md +664 -621
- package/.claude/skills/command-guide/reference/commands/workflow/lite-plan.md +645 -592
- package/.claude/skills/command-guide/reference/commands/workflow/plan.md +5 -5
- package/.claude/skills/command-guide/reference/commands/workflow/review.md +25 -18
- package/.claude/skills/command-guide/reference/commands/workflow/session/complete.md +547 -500
- package/.claude/skills/command-guide/reference/commands/workflow/session/list.md +45 -27
- package/.claude/skills/command-guide/reference/commands/workflow/session/resume.md +35 -19
- package/.claude/skills/command-guide/reference/commands/workflow/session/start.md +90 -33
- package/.claude/skills/command-guide/reference/commands/workflow/tdd-plan.md +3 -3
- package/.claude/skills/command-guide/reference/commands/workflow/tdd-verify.md +23 -9
- package/.claude/skills/command-guide/reference/commands/workflow/test-fix-gen.md +699 -699
- package/.claude/skills/command-guide/reference/commands/workflow/tools/conflict-resolution.md +103 -17
- package/.claude/skills/command-guide/reference/commands/workflow/tools/context-gather.md +434 -434
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-agent.md +487 -291
- package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-tdd.md +17 -10
- package/.claude/skills/command-guide/reference/commands/workflow/tools/test-concept-enhanced.md +1 -1
- package/.claude/skills/command-guide/reference/commands/workflow/ui-design/import-from-code.md +6 -6
- package/.claude/workflows/chinese-response.md +38 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-api.txt +122 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-components.txt +122 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-config.txt +89 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-core.txt +60 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-patterns.txt +70 -0
- package/.claude/workflows/cli-templates/prompts/rules/rule-testing.txt +81 -0
- package/.claude/workflows/cli-templates/prompts/rules/tech-rules-agent-prompt.txt +89 -0
- package/.claude/workflows/cli-templates/prompts/workflow/gemini-solution-design.txt +131 -131
- package/.claude/workflows/cli-templates/prompts/workflow/skill-conflict-patterns.txt +5 -9
- package/.claude/workflows/cli-templates/prompts/workflow/skill-lessons-learned.txt +5 -9
- package/.claude/workflows/cli-templates/protocols/analysis-protocol.md +112 -0
- package/.claude/workflows/cli-templates/protocols/write-protocol.md +201 -0
- package/.claude/workflows/cli-templates/schemas/conflict-resolution-schema.json +137 -0
- package/.claude/workflows/cli-templates/schemas/debug-log-json-schema.json +127 -0
- package/.claude/workflows/cli-templates/schemas/fix-plan-json-schema.json +25 -0
- package/.claude/workflows/cli-templates/schemas/plan-json-schema.json +25 -0
- package/.claude/workflows/cli-tools-usage.md +526 -0
- package/{CLAUDE.md → .claude/workflows/coding-philosophy.md} +24 -45
- package/.claude/workflows/context-tools.md +84 -0
- package/.claude/workflows/file-modification.md +64 -0
- package/.claude/workflows/tool-strategy.md +216 -79
- package/.claude/workflows/windows-platform.md +16 -0
- package/.claude/workflows/workflow-architecture.md +942 -942
- package/.codex/AGENTS.md +63 -330
- package/.codex/prompts/debug.md +318 -0
- package/.codex/prompts/execute.md +273 -0
- package/.codex/prompts/lite-execute.md +164 -0
- package/.codex/prompts/lite-plan.md +469 -0
- package/.codex/prompts.zip +0 -0
- package/.gemini/GEMINI.md +25 -164
- package/.qwen/QWEN.md +0 -139
- package/README.md +29 -9
- package/ccw/README.md +30 -6
- package/ccw/bin/ccw-mcp.js +7 -0
- package/ccw/bin/ccw.js +9 -9
- package/ccw/package.json +65 -47
- package/ccw/src/.workflow/.cli-history/history.db +0 -0
- package/ccw/src/.workflow/.cli-history/history.db-shm +0 -0
- package/ccw/src/.workflow/.cli-history/history.db-wal +0 -0
- package/ccw/src/cli.ts +244 -0
- package/ccw/src/commands/cli.ts +740 -0
- package/ccw/src/commands/core-memory.ts +770 -0
- package/ccw/src/commands/hook.ts +315 -0
- package/ccw/src/commands/install.ts +519 -0
- package/ccw/src/commands/{list.js → list.ts} +1 -1
- package/ccw/src/commands/memory.ts +1090 -0
- package/ccw/src/commands/{serve.js → serve.ts} +14 -5
- package/ccw/src/commands/session-path-resolver.ts +372 -0
- package/ccw/src/commands/session.ts +1141 -0
- package/ccw/src/commands/{stop.js → stop.ts} +16 -6
- package/ccw/src/commands/tool.ts +201 -0
- package/ccw/src/commands/{uninstall.js → uninstall.ts} +89 -40
- package/ccw/src/commands/{upgrade.js → upgrade.ts} +68 -23
- package/ccw/src/commands/{view.js → view.ts} +22 -8
- package/ccw/src/config/storage-paths.ts +670 -0
- package/ccw/src/core/cache-manager.ts +294 -0
- package/ccw/src/core/claude-freshness.ts +319 -0
- package/ccw/src/core/core-memory-store.ts +1528 -0
- package/ccw/src/core/{dashboard-generator-patch.js → dashboard-generator-patch.ts} +18 -0
- package/ccw/src/core/{dashboard-generator.js → dashboard-generator.ts} +69 -12
- package/ccw/src/core/data-aggregator.ts +584 -0
- package/ccw/src/core/history-importer.ts +625 -0
- package/ccw/src/core/{lite-scanner.js → lite-scanner-complete.ts} +162 -66
- package/ccw/src/core/lite-scanner.ts +469 -0
- package/ccw/src/core/{manifest.js → manifest.ts} +104 -34
- package/ccw/src/core/memory-embedder-bridge.ts +262 -0
- package/ccw/src/core/memory-store.ts +978 -0
- package/ccw/src/core/routes/ccw-routes.ts +96 -0
- package/ccw/src/core/routes/claude-routes.ts +1183 -0
- package/ccw/src/core/routes/cli-routes.ts +561 -0
- package/ccw/src/core/routes/codexlens-routes.ts +806 -0
- package/ccw/src/core/routes/core-memory-routes.ts +605 -0
- package/ccw/src/core/routes/files-routes.ts +428 -0
- package/ccw/src/core/routes/graph-routes.md +164 -0
- package/ccw/src/core/routes/graph-routes.ts +626 -0
- package/ccw/src/core/routes/help-routes.ts +308 -0
- package/ccw/src/core/routes/hooks-routes.ts +405 -0
- package/ccw/src/core/routes/mcp-routes.ts +1271 -0
- package/ccw/src/core/routes/mcp-routes.ts.backup +550 -0
- package/ccw/src/core/routes/mcp-templates-db.ts +268 -0
- package/ccw/src/core/routes/memory-routes.ts +1206 -0
- package/ccw/src/core/routes/rules-routes.ts +526 -0
- package/ccw/src/core/routes/session-routes.ts +467 -0
- package/ccw/src/core/routes/skills-routes.ts +599 -0
- package/ccw/src/core/routes/status-routes.ts +57 -0
- package/ccw/src/core/routes/system-routes.ts +427 -0
- package/ccw/src/core/server.ts +431 -0
- package/ccw/src/core/session-clustering-service.ts +1258 -0
- package/ccw/src/core/session-scanner.ts +283 -0
- package/ccw/src/core/websocket.ts +190 -0
- package/ccw/src/{index.js → index.ts} +1 -0
- package/ccw/src/mcp-server/index.ts +186 -0
- package/ccw/src/templates/assets/css/github-dark.min.css +10 -0
- package/ccw/src/templates/assets/css/github.min.css +10 -0
- package/ccw/src/templates/assets/js/cytoscape.min.js +32 -0
- package/ccw/src/templates/assets/js/d3.min.js +2 -0
- package/ccw/src/templates/assets/js/highlight.min.js +1244 -0
- package/ccw/src/templates/assets/js/lucide.min.js +12 -0
- package/ccw/src/templates/assets/js/marked.min.js +69 -0
- package/ccw/src/templates/assets/js/tailwind.js +83 -0
- package/ccw/src/templates/dashboard-css/01-base.css +11 -0
- package/ccw/src/templates/dashboard-css/02-session.css +22 -0
- package/ccw/src/templates/dashboard-css/04-lite-tasks.css +10 -0
- package/ccw/src/templates/dashboard-css/06-cards.css +10 -4
- package/ccw/src/templates/dashboard-css/07-managers.css +1178 -7
- package/ccw/src/templates/dashboard-css/09-explorer.css +23 -12
- package/ccw/src/templates/dashboard-css/10-cli-status.css +337 -0
- package/ccw/src/templates/dashboard-css/11-cli-history.css +271 -0
- package/ccw/src/templates/dashboard-css/12-cli-legacy.css +796 -0
- package/ccw/src/templates/dashboard-css/13-cli-ccw.css +199 -0
- package/ccw/src/templates/dashboard-css/14-cli-modals.css +258 -0
- package/ccw/src/templates/dashboard-css/15-cli-endpoints.css +305 -0
- package/ccw/src/templates/dashboard-css/16-cli-session.css +241 -0
- package/ccw/src/templates/dashboard-css/17-cli-conversation.css +283 -0
- package/ccw/src/templates/dashboard-css/18-cli-settings.css +160 -0
- package/ccw/src/templates/dashboard-css/19-cli-native-session.css +496 -0
- package/ccw/src/templates/dashboard-css/20-cli-taskqueue.css +188 -0
- package/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css +310 -0
- package/ccw/src/templates/dashboard-css/22-cli-semantic.css +240 -0
- package/ccw/src/templates/dashboard-css/23-memory.css +2390 -0
- package/ccw/src/templates/dashboard-css/24-prompt-history.css +1089 -0
- package/ccw/src/templates/dashboard-css/25-skills-rules.css +326 -0
- package/ccw/src/templates/dashboard-css/26-claude-manager.css +908 -0
- package/ccw/src/templates/dashboard-css/27-graph-explorer.css +1678 -0
- package/ccw/src/templates/dashboard-css/28-mcp-manager.css +748 -0
- package/ccw/src/templates/dashboard-css/29-help.css +264 -0
- package/ccw/src/templates/dashboard-css/30-core-memory.css +1700 -0
- package/ccw/src/templates/dashboard-js/api.js +162 -142
- package/ccw/src/templates/dashboard-js/components/carousel.js +4 -4
- package/ccw/src/templates/dashboard-js/components/cli-history.js +876 -0
- package/ccw/src/templates/dashboard-js/components/cli-status.js +978 -0
- package/ccw/src/templates/dashboard-js/components/global-notifications.js +508 -219
- package/ccw/src/templates/dashboard-js/components/hook-manager.js +1277 -282
- package/ccw/src/templates/dashboard-js/components/index-manager.js +302 -0
- package/ccw/src/templates/dashboard-js/components/mcp-manager.js +718 -27
- package/ccw/src/templates/dashboard-js/components/modals.js +66 -0
- package/ccw/src/templates/dashboard-js/components/navigation.js +80 -12
- package/ccw/src/templates/dashboard-js/components/notifications.js +758 -194
- package/ccw/src/templates/dashboard-js/components/storage-manager.js +478 -0
- package/ccw/src/templates/dashboard-js/components/tabs-other.js +157 -6
- package/ccw/src/templates/dashboard-js/components/task-queue-sidebar.js +716 -0
- package/ccw/src/templates/dashboard-js/help-i18n.js +272 -0
- package/ccw/src/templates/dashboard-js/i18n.js +2807 -0
- package/ccw/src/templates/dashboard-js/main.js +15 -0
- package/ccw/src/templates/dashboard-js/state.js +243 -42
- package/ccw/src/templates/dashboard-js/utils.js +47 -1
- package/ccw/src/templates/dashboard-js/views/claude-manager.js +912 -0
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +2272 -0
- package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +964 -0
- package/ccw/src/templates/dashboard-js/views/core-memory-clusters.js +503 -0
- package/ccw/src/templates/dashboard-js/views/core-memory.js +782 -0
- package/ccw/src/templates/dashboard-js/views/explorer.js +888 -852
- package/ccw/src/templates/dashboard-js/views/graph-explorer.js +1157 -0
- package/ccw/src/templates/dashboard-js/views/help.js +856 -0
- package/ccw/src/templates/dashboard-js/views/history.js +337 -0
- package/ccw/src/templates/dashboard-js/views/home.js +61 -15
- package/ccw/src/templates/dashboard-js/views/hook-manager.js +311 -43
- package/ccw/src/templates/dashboard-js/views/lite-tasks.js +204 -28
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js +2187 -411
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js.backup +1729 -0
- package/ccw/src/templates/dashboard-js/views/mcp-manager.js.new +928 -0
- package/ccw/src/templates/dashboard-js/views/memory.js +1221 -0
- package/ccw/src/templates/dashboard-js/views/prompt-history.js +713 -0
- package/ccw/src/templates/dashboard-js/views/rules-manager.js +828 -0
- package/ccw/src/templates/dashboard-js/views/session-detail.js +54 -53
- package/ccw/src/templates/dashboard-js/views/skills-manager.js +819 -0
- package/ccw/src/templates/dashboard.html +185 -85
- package/ccw/src/templates/hooks-config-example.json +60 -0
- package/ccw/src/tools/classify-folders.ts +245 -0
- package/ccw/src/tools/cli-config-manager.ts +268 -0
- package/ccw/src/tools/cli-executor.ts +2014 -0
- package/ccw/src/tools/cli-history-store.ts +1195 -0
- package/ccw/src/tools/codex-lens.ts +1141 -0
- package/ccw/src/tools/{convert-tokens-to-css.js → convert-tokens-to-css.ts} +73 -23
- package/ccw/src/tools/core-memory.ts +444 -0
- package/ccw/src/tools/detect-changed-modules.ts +325 -0
- package/ccw/src/tools/{discover-design-files.js → discover-design-files.ts} +74 -24
- package/ccw/src/tools/edit-file.ts +568 -0
- package/ccw/src/tools/{generate-module-docs.js → generate-module-docs.ts} +207 -185
- package/ccw/src/tools/{get-modules-by-depth.js → get-modules-by-depth.ts} +120 -79
- package/ccw/src/tools/index.ts +370 -0
- package/ccw/src/tools/native-session-discovery.ts +795 -0
- package/ccw/src/tools/notifier.ts +129 -0
- package/ccw/src/tools/read-file.ts +410 -0
- package/ccw/src/tools/resume-strategy.ts +345 -0
- package/ccw/src/tools/session-content-parser.ts +619 -0
- package/ccw/src/tools/session-manager.ts +1026 -0
- package/ccw/src/tools/smart-context.ts +228 -0
- package/ccw/src/tools/smart-search.ts +2065 -0
- package/ccw/src/tools/smart-search.ts.backup +1233 -0
- package/ccw/src/tools/storage-manager.ts +455 -0
- package/ccw/src/tools/write-file.ts +222 -0
- package/ccw/src/types/config.ts +11 -0
- package/ccw/src/types/index.ts +3 -0
- package/ccw/src/types/session.ts +25 -0
- package/ccw/src/types/tool.ts +41 -0
- package/ccw/src/utils/{browser-launcher.js → browser-launcher.ts} +10 -8
- package/ccw/src/utils/file-utils.ts +48 -0
- package/ccw/src/utils/{path-resolver.js → path-resolver.ts} +114 -78
- package/ccw/src/utils/path-validator.ts +153 -0
- package/ccw/src/utils/{ui.js → ui.ts} +32 -25
- package/codex-lens/pyproject.toml +48 -0
- package/codex-lens/src/codexlens/.workflow/.cli-history/history.db +0 -0
- package/codex-lens/src/codexlens/__init__.py +28 -0
- package/codex-lens/src/codexlens/__main__.py +14 -0
- package/codex-lens/src/codexlens/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/__main__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/entities.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/__pycache__/errors.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__init__.py +27 -0
- package/codex-lens/src/codexlens/cli/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/__pycache__/output.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/cli/commands.py +1931 -0
- package/codex-lens/src/codexlens/cli/embedding_manager.py +620 -0
- package/codex-lens/src/codexlens/cli/model_manager.py +289 -0
- package/codex-lens/src/codexlens/cli/output.py +124 -0
- package/codex-lens/src/codexlens/config.py +201 -0
- package/codex-lens/src/codexlens/entities.py +121 -0
- package/codex-lens/src/codexlens/errors.py +55 -0
- package/codex-lens/src/codexlens/indexing/README.md +77 -0
- package/codex-lens/src/codexlens/indexing/__init__.py +4 -0
- package/codex-lens/src/codexlens/indexing/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/indexing/__pycache__/symbol_extractor.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/indexing/symbol_extractor.py +243 -0
- package/codex-lens/src/codexlens/parsers/__init__.py +8 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/encoding.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/factory.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/tokenizer.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/__pycache__/treesitter_parser.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/parsers/encoding.py +202 -0
- package/codex-lens/src/codexlens/parsers/factory.py +256 -0
- package/codex-lens/src/codexlens/parsers/tokenizer.py +98 -0
- package/codex-lens/src/codexlens/parsers/treesitter_parser.py +335 -0
- package/codex-lens/src/codexlens/search/__init__.py +15 -0
- package/codex-lens/src/codexlens/search/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/enrichment.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/query_parser.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/search/chain_search.py +647 -0
- package/codex-lens/src/codexlens/search/enrichment.py +150 -0
- package/codex-lens/src/codexlens/search/hybrid_search.py +313 -0
- package/codex-lens/src/codexlens/search/query_parser.py +242 -0
- package/codex-lens/src/codexlens/search/ranking.py +274 -0
- package/codex-lens/src/codexlens/semantic/__init__.py +39 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/ann_index.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/code_extractor.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/graph_analyzer.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/llm_enhancer.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/semantic/ann_index.py +414 -0
- package/codex-lens/src/codexlens/semantic/chunker.py +448 -0
- package/codex-lens/src/codexlens/semantic/code_extractor.py +274 -0
- package/codex-lens/src/codexlens/semantic/embedder.py +185 -0
- package/codex-lens/src/codexlens/semantic/vector_store.py +955 -0
- package/codex-lens/src/codexlens/storage/__init__.py +29 -0
- package/codex-lens/src/codexlens/storage/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/dir_index.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/file_cache.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/migration_manager.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/registry.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/sqlite_store.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/__pycache__/sqlite_utils.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/dir_index.py +1850 -0
- package/codex-lens/src/codexlens/storage/file_cache.py +32 -0
- package/codex-lens/src/codexlens/storage/index_tree.py +776 -0
- package/codex-lens/src/codexlens/storage/migration_manager.py +154 -0
- package/codex-lens/src/codexlens/storage/migrations/__init__.py +1 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/__init__.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_001_normalize_keywords.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_002_add_token_metadata.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_003_code_relationships.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_004_dual_fts.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_005_cleanup_unused_fields.cpython-313.pyc +0 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_001_normalize_keywords.py +123 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_002_add_token_metadata.py +48 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_004_dual_fts.py +232 -0
- package/codex-lens/src/codexlens/storage/migrations/migration_005_cleanup_unused_fields.py +196 -0
- package/codex-lens/src/codexlens/storage/path_mapper.py +274 -0
- package/codex-lens/src/codexlens/storage/registry.py +670 -0
- package/codex-lens/src/codexlens/storage/sqlite_store.py +576 -0
- package/codex-lens/src/codexlens/storage/sqlite_utils.py +64 -0
- package/package.json +4 -1
- package/.claude/commands/memory/tech-research.md +0 -477
- package/.claude/scripts/classify-folders.sh +0 -39
- package/.claude/scripts/convert_tokens_to_css.sh +0 -229
- package/.claude/scripts/detect_changed_modules.sh +0 -161
- package/.claude/scripts/discover-design-files.sh +0 -87
- package/.claude/scripts/extract-animations.js +0 -243
- package/.claude/scripts/extract-computed-styles.js +0 -118
- package/.claude/scripts/extract-layout-structure.js +0 -411
- package/.claude/scripts/generate_module_docs.sh +0 -717
- package/.claude/scripts/get_modules_by_depth.sh +0 -170
- package/.claude/scripts/ui-generate-preview.sh +0 -395
- package/.claude/scripts/ui-instantiate-prototypes.sh +0 -815
- package/.claude/scripts/update_module_claude.sh +0 -337
- package/.claude/workflows/context-search-strategy.md +0 -77
- package/.claude/workflows/intelligent-tools-strategy.md +0 -662
- package/ccw/src/cli.js +0 -119
- package/ccw/src/commands/install.js +0 -324
- package/ccw/src/commands/tool.js +0 -138
- package/ccw/src/core/data-aggregator.js +0 -409
- package/ccw/src/core/server.js +0 -2063
- package/ccw/src/core/session-scanner.js +0 -235
- package/ccw/src/tools/classify-folders.js +0 -204
- package/ccw/src/tools/detect-changed-modules.js +0 -288
- package/ccw/src/tools/edit-file.js +0 -266
- package/ccw/src/tools/index.js +0 -176
- package/ccw/src/utils/file-utils.js +0 -48
|
@@ -0,0 +1,828 @@
|
|
|
1
|
+
// Rules Manager View
|
|
2
|
+
// Manages Claude Code rules (.claude/rules/)
|
|
3
|
+
|
|
4
|
+
// ========== Rules State ==========
|
|
5
|
+
var rulesData = {
|
|
6
|
+
projectRules: [],
|
|
7
|
+
userRules: []
|
|
8
|
+
};
|
|
9
|
+
var selectedRule = null;
|
|
10
|
+
var rulesLoading = false;
|
|
11
|
+
|
|
12
|
+
// ========== Main Render Function ==========
|
|
13
|
+
async function renderRulesManager() {
|
|
14
|
+
const container = document.getElementById('mainContent');
|
|
15
|
+
if (!container) return;
|
|
16
|
+
|
|
17
|
+
// Hide stats grid and search
|
|
18
|
+
const statsGrid = document.getElementById('statsGrid');
|
|
19
|
+
const searchInput = document.getElementById('searchInput');
|
|
20
|
+
if (statsGrid) statsGrid.style.display = 'none';
|
|
21
|
+
if (searchInput) searchInput.parentElement.style.display = 'none';
|
|
22
|
+
|
|
23
|
+
// Show loading state
|
|
24
|
+
container.innerHTML = '<div class="rules-manager loading">' +
|
|
25
|
+
'<div class="loading-spinner"><i data-lucide="loader-2" class="w-8 h-8 animate-spin"></i></div>' +
|
|
26
|
+
'<p>' + t('common.loading') + '</p>' +
|
|
27
|
+
'</div>';
|
|
28
|
+
|
|
29
|
+
// Load rules data
|
|
30
|
+
await loadRulesData();
|
|
31
|
+
|
|
32
|
+
// Render the main view
|
|
33
|
+
renderRulesView();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function loadRulesData() {
|
|
37
|
+
rulesLoading = true;
|
|
38
|
+
try {
|
|
39
|
+
const response = await fetch('/api/rules?path=' + encodeURIComponent(projectPath));
|
|
40
|
+
if (!response.ok) throw new Error('Failed to load rules');
|
|
41
|
+
const data = await response.json();
|
|
42
|
+
rulesData = {
|
|
43
|
+
projectRules: data.projectRules || [],
|
|
44
|
+
userRules: data.userRules || []
|
|
45
|
+
};
|
|
46
|
+
// Update badge
|
|
47
|
+
updateRulesBadge();
|
|
48
|
+
} catch (err) {
|
|
49
|
+
console.error('Failed to load rules:', err);
|
|
50
|
+
rulesData = { projectRules: [], userRules: [] };
|
|
51
|
+
} finally {
|
|
52
|
+
rulesLoading = false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function updateRulesBadge() {
|
|
57
|
+
const badge = document.getElementById('badgeRules');
|
|
58
|
+
if (badge) {
|
|
59
|
+
const total = rulesData.projectRules.length + rulesData.userRules.length;
|
|
60
|
+
badge.textContent = total;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function renderRulesView() {
|
|
65
|
+
const container = document.getElementById('mainContent');
|
|
66
|
+
if (!container) return;
|
|
67
|
+
|
|
68
|
+
const projectRules = rulesData.projectRules || [];
|
|
69
|
+
const userRules = rulesData.userRules || [];
|
|
70
|
+
|
|
71
|
+
container.innerHTML = `
|
|
72
|
+
<div class="rules-manager">
|
|
73
|
+
<!-- Header -->
|
|
74
|
+
<div class="rules-header mb-6">
|
|
75
|
+
<div class="flex items-center justify-between">
|
|
76
|
+
<div class="flex items-center gap-3">
|
|
77
|
+
<div class="w-10 h-10 bg-success/10 rounded-lg flex items-center justify-center">
|
|
78
|
+
<i data-lucide="book-open" class="w-5 h-5 text-success"></i>
|
|
79
|
+
</div>
|
|
80
|
+
<div>
|
|
81
|
+
<h2 class="text-lg font-semibold text-foreground">${t('rules.title')}</h2>
|
|
82
|
+
<p class="text-sm text-muted-foreground">${t('rules.description')}</p>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
85
|
+
<button class="px-4 py-2 text-sm bg-primary text-primary-foreground rounded-lg hover:opacity-90 transition-opacity flex items-center gap-2"
|
|
86
|
+
onclick="openRuleCreateModal()">
|
|
87
|
+
<i data-lucide="plus" class="w-4 h-4"></i>
|
|
88
|
+
${t('rules.create')}
|
|
89
|
+
</button>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<!-- Project Rules Section -->
|
|
94
|
+
<div class="rules-section mb-6">
|
|
95
|
+
<div class="flex items-center justify-between mb-4">
|
|
96
|
+
<div class="flex items-center gap-2">
|
|
97
|
+
<i data-lucide="folder" class="w-5 h-5 text-success"></i>
|
|
98
|
+
<h3 class="text-lg font-semibold text-foreground">${t('rules.projectRules')}</h3>
|
|
99
|
+
<span class="text-xs px-2 py-0.5 bg-success/10 text-success rounded-full">.claude/rules/</span>
|
|
100
|
+
</div>
|
|
101
|
+
<span class="text-sm text-muted-foreground">${projectRules.length} ${t('rules.rulesCount')}</span>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
${projectRules.length === 0 ? `
|
|
105
|
+
<div class="rules-empty-state bg-card border border-border rounded-lg p-6 text-center">
|
|
106
|
+
<div class="text-muted-foreground mb-3"><i data-lucide="book-open" class="w-10 h-10 mx-auto"></i></div>
|
|
107
|
+
<p class="text-muted-foreground">${t('rules.noProjectRules')}</p>
|
|
108
|
+
<p class="text-sm text-muted-foreground mt-1">${t('rules.createHint')}</p>
|
|
109
|
+
</div>
|
|
110
|
+
` : `
|
|
111
|
+
<div class="rules-grid grid gap-3">
|
|
112
|
+
${projectRules.map(rule => renderRuleCard(rule, 'project')).join('')}
|
|
113
|
+
</div>
|
|
114
|
+
`}
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<!-- User Rules Section -->
|
|
118
|
+
<div class="rules-section mb-6">
|
|
119
|
+
<div class="flex items-center justify-between mb-4">
|
|
120
|
+
<div class="flex items-center gap-2">
|
|
121
|
+
<i data-lucide="user" class="w-5 h-5 text-orange"></i>
|
|
122
|
+
<h3 class="text-lg font-semibold text-foreground">${t('rules.userRules')}</h3>
|
|
123
|
+
<span class="text-xs px-2 py-0.5 bg-orange/10 text-orange rounded-full">~/.claude/rules/</span>
|
|
124
|
+
</div>
|
|
125
|
+
<span class="text-sm text-muted-foreground">${userRules.length} ${t('rules.rulesCount')}</span>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
${userRules.length === 0 ? `
|
|
129
|
+
<div class="rules-empty-state bg-card border border-border rounded-lg p-6 text-center">
|
|
130
|
+
<div class="text-muted-foreground mb-3"><i data-lucide="user" class="w-10 h-10 mx-auto"></i></div>
|
|
131
|
+
<p class="text-muted-foreground">${t('rules.noUserRules')}</p>
|
|
132
|
+
<p class="text-sm text-muted-foreground mt-1">${t('rules.userRulesHint')}</p>
|
|
133
|
+
</div>
|
|
134
|
+
` : `
|
|
135
|
+
<div class="rules-grid grid gap-3">
|
|
136
|
+
${userRules.map(rule => renderRuleCard(rule, 'user')).join('')}
|
|
137
|
+
</div>
|
|
138
|
+
`}
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<!-- Rule Detail Panel -->
|
|
142
|
+
${selectedRule ? renderRuleDetailPanel(selectedRule) : ''}
|
|
143
|
+
</div>
|
|
144
|
+
`;
|
|
145
|
+
|
|
146
|
+
// Initialize Lucide icons
|
|
147
|
+
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function renderRuleCard(rule, location) {
|
|
151
|
+
const hasPathCondition = rule.paths && rule.paths.length > 0;
|
|
152
|
+
const isGlobal = !hasPathCondition;
|
|
153
|
+
const locationIcon = location === 'project' ? 'folder' : 'user';
|
|
154
|
+
const locationClass = location === 'project' ? 'text-success' : 'text-orange';
|
|
155
|
+
const locationBg = location === 'project' ? 'bg-success/10' : 'bg-orange/10';
|
|
156
|
+
|
|
157
|
+
// Get preview of content (first 100 chars)
|
|
158
|
+
const contentPreview = rule.content ? rule.content.substring(0, 100).replace(/\n/g, ' ') + (rule.content.length > 100 ? '...' : '') : '';
|
|
159
|
+
|
|
160
|
+
return `
|
|
161
|
+
<div class="rule-card bg-card border border-border rounded-lg p-4 hover:shadow-md transition-all cursor-pointer"
|
|
162
|
+
onclick="showRuleDetail('${escapeHtml(rule.name)}', '${location}')">
|
|
163
|
+
<div class="flex items-start justify-between mb-3">
|
|
164
|
+
<div class="flex items-center gap-3">
|
|
165
|
+
<div class="w-10 h-10 ${locationBg} rounded-lg flex items-center justify-center">
|
|
166
|
+
<i data-lucide="file-text" class="w-5 h-5 ${locationClass}"></i>
|
|
167
|
+
</div>
|
|
168
|
+
<div>
|
|
169
|
+
<h4 class="font-semibold text-foreground">${escapeHtml(rule.name)}</h4>
|
|
170
|
+
${rule.subdirectory ? `<span class="text-xs text-muted-foreground">${escapeHtml(rule.subdirectory)}/</span>` : ''}
|
|
171
|
+
</div>
|
|
172
|
+
</div>
|
|
173
|
+
<div class="flex items-center gap-2">
|
|
174
|
+
${isGlobal ? `
|
|
175
|
+
<span class="inline-flex items-center px-2 py-0.5 text-xs font-medium rounded-full bg-primary/10 text-primary">
|
|
176
|
+
<i data-lucide="globe" class="w-3 h-3 mr-1"></i>
|
|
177
|
+
global
|
|
178
|
+
</span>
|
|
179
|
+
` : `
|
|
180
|
+
<span class="inline-flex items-center px-2 py-0.5 text-xs font-medium rounded-full bg-warning/10 text-warning">
|
|
181
|
+
<i data-lucide="filter" class="w-3 h-3 mr-1"></i>
|
|
182
|
+
conditional
|
|
183
|
+
</span>
|
|
184
|
+
`}
|
|
185
|
+
<span class="inline-flex items-center px-2 py-0.5 text-xs font-medium rounded-full ${locationBg} ${locationClass}">
|
|
186
|
+
<i data-lucide="${locationIcon}" class="w-3 h-3 mr-1"></i>
|
|
187
|
+
${location}
|
|
188
|
+
</span>
|
|
189
|
+
</div>
|
|
190
|
+
</div>
|
|
191
|
+
|
|
192
|
+
${contentPreview ? `
|
|
193
|
+
<p class="text-sm text-muted-foreground mb-3 line-clamp-2 font-mono">${escapeHtml(contentPreview)}</p>
|
|
194
|
+
` : ''}
|
|
195
|
+
|
|
196
|
+
${hasPathCondition ? `
|
|
197
|
+
<div class="flex items-center gap-2 text-xs text-muted-foreground mt-2">
|
|
198
|
+
<i data-lucide="filter" class="w-3 h-3"></i>
|
|
199
|
+
<span class="font-mono">${escapeHtml(rule.paths.join(', '))}</span>
|
|
200
|
+
</div>
|
|
201
|
+
` : ''}
|
|
202
|
+
</div>
|
|
203
|
+
`;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function renderRuleDetailPanel(rule) {
|
|
207
|
+
const hasPathCondition = rule.paths && rule.paths.length > 0;
|
|
208
|
+
|
|
209
|
+
return `
|
|
210
|
+
<div class="rule-detail-panel fixed top-0 right-0 w-1/2 max-w-xl h-full bg-card border-l border-border shadow-lg z-50 flex flex-col">
|
|
211
|
+
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
|
212
|
+
<h3 class="text-lg font-semibold text-foreground">${escapeHtml(rule.name)}</h3>
|
|
213
|
+
<button class="w-8 h-8 flex items-center justify-center text-xl text-muted-foreground hover:text-foreground hover:bg-hover rounded"
|
|
214
|
+
onclick="closeRuleDetail()">×</button>
|
|
215
|
+
</div>
|
|
216
|
+
<div class="flex-1 overflow-y-auto p-5">
|
|
217
|
+
<div class="space-y-6">
|
|
218
|
+
<!-- Type -->
|
|
219
|
+
<div>
|
|
220
|
+
<h4 class="text-sm font-semibold text-foreground mb-2">${t('rules.typeLabel')}</h4>
|
|
221
|
+
<div class="flex items-center gap-2">
|
|
222
|
+
${hasPathCondition ? `
|
|
223
|
+
<span class="inline-flex items-center px-3 py-1 text-sm font-medium rounded-lg bg-warning/10 text-warning">
|
|
224
|
+
<i data-lucide="filter" class="w-4 h-4 mr-2"></i>
|
|
225
|
+
${t('rules.conditional')}
|
|
226
|
+
</span>
|
|
227
|
+
` : `
|
|
228
|
+
<span class="inline-flex items-center px-3 py-1 text-sm font-medium rounded-lg bg-primary/10 text-primary">
|
|
229
|
+
<i data-lucide="globe" class="w-4 h-4 mr-2"></i>
|
|
230
|
+
${t('rules.global')}
|
|
231
|
+
</span>
|
|
232
|
+
`}
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
|
|
236
|
+
<!-- Path Conditions -->
|
|
237
|
+
${hasPathCondition ? `
|
|
238
|
+
<div>
|
|
239
|
+
<h4 class="text-sm font-semibold text-foreground mb-2">${t('rules.pathConditions')}</h4>
|
|
240
|
+
<div class="space-y-2">
|
|
241
|
+
${rule.paths.map(path => `
|
|
242
|
+
<div class="flex items-center gap-2 p-2 bg-muted/50 rounded-lg">
|
|
243
|
+
<i data-lucide="file-code" class="w-4 h-4 text-muted-foreground"></i>
|
|
244
|
+
<code class="text-sm font-mono text-foreground">${escapeHtml(path)}</code>
|
|
245
|
+
</div>
|
|
246
|
+
`).join('')}
|
|
247
|
+
</div>
|
|
248
|
+
</div>
|
|
249
|
+
` : ''}
|
|
250
|
+
|
|
251
|
+
<!-- Content -->
|
|
252
|
+
<div>
|
|
253
|
+
<h4 class="text-sm font-semibold text-foreground mb-2">${t('rules.content')}</h4>
|
|
254
|
+
<div class="bg-muted rounded-lg p-4 max-h-96 overflow-y-auto">
|
|
255
|
+
<pre class="text-sm font-mono text-foreground whitespace-pre-wrap">${escapeHtml(rule.content || '')}</pre>
|
|
256
|
+
</div>
|
|
257
|
+
</div>
|
|
258
|
+
|
|
259
|
+
<!-- Path -->
|
|
260
|
+
<div>
|
|
261
|
+
<h4 class="text-sm font-semibold text-foreground mb-2">${t('rules.filePath')}</h4>
|
|
262
|
+
<code class="block p-3 bg-muted rounded-lg text-xs font-mono text-muted-foreground break-all">${escapeHtml(rule.path)}</code>
|
|
263
|
+
</div>
|
|
264
|
+
</div>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<!-- Actions -->
|
|
268
|
+
<div class="px-5 py-4 border-t border-border flex justify-between">
|
|
269
|
+
<button class="px-4 py-2 text-sm text-destructive hover:bg-destructive/10 rounded-lg transition-colors flex items-center gap-2"
|
|
270
|
+
onclick="deleteRule('${escapeHtml(rule.name)}', '${rule.location}')">
|
|
271
|
+
<i data-lucide="trash-2" class="w-4 h-4"></i>
|
|
272
|
+
${t('common.delete')}
|
|
273
|
+
</button>
|
|
274
|
+
<button class="px-4 py-2 text-sm bg-primary text-primary-foreground rounded-lg hover:opacity-90 transition-opacity flex items-center gap-2"
|
|
275
|
+
onclick="editRule('${escapeHtml(rule.name)}', '${rule.location}')">
|
|
276
|
+
<i data-lucide="edit" class="w-4 h-4"></i>
|
|
277
|
+
${t('common.edit')}
|
|
278
|
+
</button>
|
|
279
|
+
</div>
|
|
280
|
+
</div>
|
|
281
|
+
<div class="rule-detail-overlay fixed inset-0 bg-black/50 z-40" onclick="closeRuleDetail()"></div>
|
|
282
|
+
`;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
async function showRuleDetail(ruleName, location) {
|
|
286
|
+
try {
|
|
287
|
+
const response = await fetch('/api/rules/' + encodeURIComponent(ruleName) + '?location=' + location + '&path=' + encodeURIComponent(projectPath));
|
|
288
|
+
if (!response.ok) throw new Error('Failed to load rule detail');
|
|
289
|
+
const data = await response.json();
|
|
290
|
+
selectedRule = data.rule;
|
|
291
|
+
renderRulesView();
|
|
292
|
+
} catch (err) {
|
|
293
|
+
console.error('Failed to load rule detail:', err);
|
|
294
|
+
if (window.showToast) {
|
|
295
|
+
showToast(t('rules.loadError'), 'error');
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function closeRuleDetail() {
|
|
301
|
+
selectedRule = null;
|
|
302
|
+
renderRulesView();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
async function deleteRule(ruleName, location) {
|
|
306
|
+
if (!confirm(t('rules.deleteConfirm', { name: ruleName }))) return;
|
|
307
|
+
|
|
308
|
+
try {
|
|
309
|
+
const response = await fetch('/api/rules/' + encodeURIComponent(ruleName), {
|
|
310
|
+
method: 'DELETE',
|
|
311
|
+
headers: { 'Content-Type': 'application/json' },
|
|
312
|
+
body: JSON.stringify({ location, projectPath })
|
|
313
|
+
});
|
|
314
|
+
if (!response.ok) throw new Error('Failed to delete rule');
|
|
315
|
+
|
|
316
|
+
selectedRule = null;
|
|
317
|
+
await loadRulesData();
|
|
318
|
+
renderRulesView();
|
|
319
|
+
|
|
320
|
+
if (window.showToast) {
|
|
321
|
+
showToast(t('rules.deleted'), 'success');
|
|
322
|
+
}
|
|
323
|
+
} catch (err) {
|
|
324
|
+
console.error('Failed to delete rule:', err);
|
|
325
|
+
if (window.showToast) {
|
|
326
|
+
showToast(t('rules.deleteError'), 'error');
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function editRule(ruleName, location) {
|
|
332
|
+
// Open edit modal (to be implemented with modal)
|
|
333
|
+
if (window.showToast) {
|
|
334
|
+
showToast(t('rules.editNotImplemented'), 'info');
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// ========== Create Rule Modal ==========
|
|
339
|
+
var ruleCreateState = {
|
|
340
|
+
location: 'project',
|
|
341
|
+
fileName: '',
|
|
342
|
+
subdirectory: '',
|
|
343
|
+
isConditional: false,
|
|
344
|
+
paths: [''],
|
|
345
|
+
content: '',
|
|
346
|
+
mode: 'input',
|
|
347
|
+
generationType: 'description',
|
|
348
|
+
description: '',
|
|
349
|
+
extractScope: '',
|
|
350
|
+
extractFocus: ''
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
function openRuleCreateModal() {
|
|
354
|
+
// Reset state
|
|
355
|
+
ruleCreateState = {
|
|
356
|
+
location: 'project',
|
|
357
|
+
fileName: '',
|
|
358
|
+
subdirectory: '',
|
|
359
|
+
isConditional: false,
|
|
360
|
+
paths: [''],
|
|
361
|
+
content: '',
|
|
362
|
+
mode: 'input',
|
|
363
|
+
generationType: 'description',
|
|
364
|
+
description: '',
|
|
365
|
+
extractScope: '',
|
|
366
|
+
extractFocus: ''
|
|
367
|
+
};
|
|
368
|
+
|
|
369
|
+
// Create modal HTML
|
|
370
|
+
const modalHtml = `
|
|
371
|
+
<div class="modal-overlay fixed inset-0 bg-black/50 z-50 flex items-center justify-center" onclick="closeRuleCreateModal(event)">
|
|
372
|
+
<div class="modal-dialog bg-card rounded-lg shadow-lg w-full max-w-2xl max-h-[90vh] mx-4 flex flex-col" onclick="event.stopPropagation()">
|
|
373
|
+
<!-- Header -->
|
|
374
|
+
<div class="flex items-center justify-between px-6 py-4 border-b border-border">
|
|
375
|
+
<h3 class="text-lg font-semibold text-foreground">${t('rules.createRule')}</h3>
|
|
376
|
+
<button class="w-8 h-8 flex items-center justify-center text-xl text-muted-foreground hover:text-foreground hover:bg-hover rounded"
|
|
377
|
+
onclick="closeRuleCreateModal()">×</button>
|
|
378
|
+
</div>
|
|
379
|
+
|
|
380
|
+
<!-- Body -->
|
|
381
|
+
<div class="flex-1 overflow-y-auto p-6 space-y-5">
|
|
382
|
+
<!-- Location Selection -->
|
|
383
|
+
<div>
|
|
384
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('rules.location')}</label>
|
|
385
|
+
<div class="grid grid-cols-2 gap-3">
|
|
386
|
+
<button class="location-btn px-4 py-3 text-left border-2 rounded-lg transition-all ${ruleCreateState.location === 'project' ? 'border-primary bg-primary/10' : 'border-border hover:border-primary/50'}"
|
|
387
|
+
onclick="selectRuleLocation('project')">
|
|
388
|
+
<div class="flex items-center gap-2">
|
|
389
|
+
<i data-lucide="folder" class="w-5 h-5"></i>
|
|
390
|
+
<div>
|
|
391
|
+
<div class="font-medium">${t('rules.projectRules')}</div>
|
|
392
|
+
<div class="text-xs text-muted-foreground">.claude/rules/</div>
|
|
393
|
+
</div>
|
|
394
|
+
</div>
|
|
395
|
+
</button>
|
|
396
|
+
<button class="location-btn px-4 py-3 text-left border-2 rounded-lg transition-all ${ruleCreateState.location === 'user' ? 'border-primary bg-primary/10' : 'border-border hover:border-primary/50'}"
|
|
397
|
+
onclick="selectRuleLocation('user')">
|
|
398
|
+
<div class="flex items-center gap-2">
|
|
399
|
+
<i data-lucide="user" class="w-5 h-5"></i>
|
|
400
|
+
<div>
|
|
401
|
+
<div class="font-medium">${t('rules.userRules')}</div>
|
|
402
|
+
<div class="text-xs text-muted-foreground">~/.claude/rules/</div>
|
|
403
|
+
</div>
|
|
404
|
+
</div>
|
|
405
|
+
</button>
|
|
406
|
+
</div>
|
|
407
|
+
</div>
|
|
408
|
+
|
|
409
|
+
<!-- Mode Selection -->
|
|
410
|
+
<div>
|
|
411
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('rules.createMode')}</label>
|
|
412
|
+
<div class="grid grid-cols-2 gap-3">
|
|
413
|
+
<button class="mode-btn px-4 py-3 text-left border-2 rounded-lg transition-all ${ruleCreateState.mode === 'input' ? 'border-primary bg-primary/10' : 'border-border hover:border-primary/50'}"
|
|
414
|
+
onclick="switchRuleCreateMode('input')">
|
|
415
|
+
<div class="flex items-center gap-2">
|
|
416
|
+
<i data-lucide="edit" class="w-5 h-5"></i>
|
|
417
|
+
<div>
|
|
418
|
+
<div class="font-medium">${t('rules.manualInput')}</div>
|
|
419
|
+
<div class="text-xs text-muted-foreground">${t('rules.manualInputHint')}</div>
|
|
420
|
+
</div>
|
|
421
|
+
</div>
|
|
422
|
+
</button>
|
|
423
|
+
<button class="mode-btn px-4 py-3 text-left border-2 rounded-lg transition-all ${ruleCreateState.mode === 'cli-generate' ? 'border-primary bg-primary/10' : 'border-border hover:border-primary/50'}"
|
|
424
|
+
onclick="switchRuleCreateMode('cli-generate')">
|
|
425
|
+
<div class="flex items-center gap-2">
|
|
426
|
+
<i data-lucide="sparkles" class="w-5 h-5"></i>
|
|
427
|
+
<div>
|
|
428
|
+
<div class="font-medium">${t('rules.cliGenerate')}</div>
|
|
429
|
+
<div class="text-xs text-muted-foreground">${t('rules.cliGenerateHint')}</div>
|
|
430
|
+
</div>
|
|
431
|
+
</div>
|
|
432
|
+
</button>
|
|
433
|
+
</div>
|
|
434
|
+
</div>
|
|
435
|
+
|
|
436
|
+
<!-- File Name -->
|
|
437
|
+
<div>
|
|
438
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('rules.fileName')}</label>
|
|
439
|
+
<input type="text" id="ruleFileName"
|
|
440
|
+
class="w-full px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
|
|
441
|
+
placeholder="my-rule.md"
|
|
442
|
+
value="${ruleCreateState.fileName}">
|
|
443
|
+
<p class="text-xs text-muted-foreground mt-1">${t('rules.fileNameHint')}</p>
|
|
444
|
+
</div>
|
|
445
|
+
|
|
446
|
+
<!-- Subdirectory -->
|
|
447
|
+
<div>
|
|
448
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('rules.subdirectory')} <span class="text-muted-foreground">${t('common.optional')}</span></label>
|
|
449
|
+
<input type="text" id="ruleSubdirectory"
|
|
450
|
+
class="w-full px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
|
|
451
|
+
placeholder="category/subcategory"
|
|
452
|
+
value="${ruleCreateState.subdirectory}">
|
|
453
|
+
<p class="text-xs text-muted-foreground mt-1">${t('rules.subdirectoryHint')}</p>
|
|
454
|
+
</div>
|
|
455
|
+
|
|
456
|
+
<!-- CLI Generation Type (CLI mode only) -->
|
|
457
|
+
<div id="ruleGenerationTypeSection" style="display: ${ruleCreateState.mode === 'cli-generate' ? 'block' : 'none'}">
|
|
458
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('rules.generationType')}</label>
|
|
459
|
+
<div class="flex gap-3">
|
|
460
|
+
<label class="flex items-center gap-2 cursor-pointer">
|
|
461
|
+
<input type="radio" name="ruleGenType" value="description"
|
|
462
|
+
class="w-4 h-4 text-primary bg-background border-border focus:ring-2 focus:ring-primary"
|
|
463
|
+
${ruleCreateState.generationType === 'description' ? 'checked' : ''}
|
|
464
|
+
onchange="switchRuleGenerationType('description')">
|
|
465
|
+
<span class="text-sm">${t('rules.fromDescription')}</span>
|
|
466
|
+
</label>
|
|
467
|
+
<label class="flex items-center gap-2 cursor-pointer">
|
|
468
|
+
<input type="radio" name="ruleGenType" value="extract"
|
|
469
|
+
class="w-4 h-4 text-primary bg-background border-border focus:ring-2 focus:ring-primary"
|
|
470
|
+
${ruleCreateState.generationType === 'extract' ? 'checked' : ''}
|
|
471
|
+
onchange="switchRuleGenerationType('extract')">
|
|
472
|
+
<span class="text-sm">${t('rules.fromCodeExtract')}</span>
|
|
473
|
+
</label>
|
|
474
|
+
</div>
|
|
475
|
+
</div>
|
|
476
|
+
|
|
477
|
+
<!-- Description Input (CLI mode, description type) -->
|
|
478
|
+
<div id="ruleDescriptionSection" style="display: ${ruleCreateState.mode === 'cli-generate' && ruleCreateState.generationType === 'description' ? 'block' : 'none'}">
|
|
479
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('rules.description')}</label>
|
|
480
|
+
<textarea id="ruleDescription"
|
|
481
|
+
class="w-full px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
|
|
482
|
+
rows="4"
|
|
483
|
+
placeholder="${t('rules.descriptionPlaceholder')}">${ruleCreateState.description}</textarea>
|
|
484
|
+
<p class="text-xs text-muted-foreground mt-1">${t('rules.descriptionHint')}</p>
|
|
485
|
+
</div>
|
|
486
|
+
|
|
487
|
+
<!-- Code Extract Options (CLI mode, extract type) -->
|
|
488
|
+
<div id="ruleExtractSection" style="display: ${ruleCreateState.mode === 'cli-generate' && ruleCreateState.generationType === 'extract' ? 'block' : 'none'}">
|
|
489
|
+
<div class="space-y-4">
|
|
490
|
+
<div>
|
|
491
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('rules.extractScope')}</label>
|
|
492
|
+
<input type="text" id="ruleExtractScope"
|
|
493
|
+
class="w-full px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary font-mono"
|
|
494
|
+
placeholder="src/**/*.ts"
|
|
495
|
+
value="${ruleCreateState.extractScope}">
|
|
496
|
+
<p class="text-xs text-muted-foreground mt-1">${t('rules.extractScopeHint')}</p>
|
|
497
|
+
</div>
|
|
498
|
+
<div>
|
|
499
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('rules.extractFocus')}</label>
|
|
500
|
+
<input type="text" id="ruleExtractFocus"
|
|
501
|
+
class="w-full px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
|
|
502
|
+
placeholder="naming, error-handling, state-management"
|
|
503
|
+
value="${ruleCreateState.extractFocus}">
|
|
504
|
+
<p class="text-xs text-muted-foreground mt-1">${t('rules.extractFocusHint')}</p>
|
|
505
|
+
</div>
|
|
506
|
+
</div>
|
|
507
|
+
</div>
|
|
508
|
+
|
|
509
|
+
<!-- Conditional Rule Toggle (Manual mode only) -->
|
|
510
|
+
<div id="ruleConditionalSection" style="display: ${ruleCreateState.mode === 'input' ? 'block' : 'none'}">
|
|
511
|
+
<label class="flex items-center gap-2 cursor-pointer">
|
|
512
|
+
<input type="checkbox" id="ruleConditional"
|
|
513
|
+
class="w-4 h-4 text-primary bg-background border-border rounded focus:ring-2 focus:ring-primary"
|
|
514
|
+
${ruleCreateState.isConditional ? 'checked' : ''}
|
|
515
|
+
onchange="toggleRuleConditional()">
|
|
516
|
+
<span class="text-sm font-medium text-foreground">${t('rules.conditionalRule')}</span>
|
|
517
|
+
</label>
|
|
518
|
+
<p class="text-xs text-muted-foreground mt-1 ml-6">${t('rules.conditionalHint')}</p>
|
|
519
|
+
</div>
|
|
520
|
+
|
|
521
|
+
<!-- Path Conditions -->
|
|
522
|
+
<div id="rulePathsContainer" style="display: ${ruleCreateState.isConditional ? 'block' : 'none'}">
|
|
523
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('rules.pathConditions')}</label>
|
|
524
|
+
<div id="rulePathsList" class="space-y-2">
|
|
525
|
+
${ruleCreateState.paths.map((path, index) => `
|
|
526
|
+
<div class="flex gap-2">
|
|
527
|
+
<input type="text" class="rule-path-input flex-1 px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
|
|
528
|
+
placeholder="src/**/*.ts"
|
|
529
|
+
value="${path}"
|
|
530
|
+
data-index="${index}">
|
|
531
|
+
${index > 0 ? `
|
|
532
|
+
<button class="px-3 py-2 text-destructive hover:bg-destructive/10 rounded-lg transition-colors"
|
|
533
|
+
onclick="removeRulePath(${index})">
|
|
534
|
+
<i data-lucide="x" class="w-4 h-4"></i>
|
|
535
|
+
</button>
|
|
536
|
+
` : ''}
|
|
537
|
+
</div>
|
|
538
|
+
`).join('')}
|
|
539
|
+
</div>
|
|
540
|
+
<button class="mt-2 px-3 py-1.5 text-sm text-primary hover:bg-primary/10 rounded-lg transition-colors flex items-center gap-1"
|
|
541
|
+
onclick="addRulePath()">
|
|
542
|
+
<i data-lucide="plus" class="w-4 h-4"></i>
|
|
543
|
+
${t('rules.addPath')}
|
|
544
|
+
</button>
|
|
545
|
+
</div>
|
|
546
|
+
|
|
547
|
+
<!-- Content (Manual mode only) -->
|
|
548
|
+
<div id="ruleContentSection" style="display: ${ruleCreateState.mode === 'input' ? 'block' : 'none'}">
|
|
549
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('rules.content')}</label>
|
|
550
|
+
<textarea id="ruleContent"
|
|
551
|
+
class="w-full px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary font-mono"
|
|
552
|
+
rows="10"
|
|
553
|
+
placeholder="${t('rules.contentPlaceholder')}">${ruleCreateState.content}</textarea>
|
|
554
|
+
<p class="text-xs text-muted-foreground mt-1">${t('rules.contentHint')}</p>
|
|
555
|
+
</div>
|
|
556
|
+
</div>
|
|
557
|
+
|
|
558
|
+
<!-- Footer -->
|
|
559
|
+
<div class="flex items-center justify-end gap-3 px-6 py-4 border-t border-border">
|
|
560
|
+
<button class="px-4 py-2 text-sm text-muted-foreground hover:text-foreground transition-colors"
|
|
561
|
+
onclick="closeRuleCreateModal()">
|
|
562
|
+
${t('common.cancel')}
|
|
563
|
+
</button>
|
|
564
|
+
<button class="px-4 py-2 text-sm bg-primary text-primary-foreground rounded-lg hover:opacity-90 transition-opacity"
|
|
565
|
+
onclick="createRule()">
|
|
566
|
+
${t('rules.create')}
|
|
567
|
+
</button>
|
|
568
|
+
</div>
|
|
569
|
+
</div>
|
|
570
|
+
</div>
|
|
571
|
+
`;
|
|
572
|
+
|
|
573
|
+
// Add to DOM
|
|
574
|
+
const modalContainer = document.createElement('div');
|
|
575
|
+
modalContainer.id = 'ruleCreateModal';
|
|
576
|
+
modalContainer.innerHTML = modalHtml;
|
|
577
|
+
document.body.appendChild(modalContainer);
|
|
578
|
+
|
|
579
|
+
// Initialize Lucide icons
|
|
580
|
+
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
function closeRuleCreateModal(event) {
|
|
584
|
+
if (event && event.target !== event.currentTarget) return;
|
|
585
|
+
const modal = document.getElementById('ruleCreateModal');
|
|
586
|
+
if (modal) modal.remove();
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
function selectRuleLocation(location) {
|
|
590
|
+
ruleCreateState.location = location;
|
|
591
|
+
|
|
592
|
+
// Update button styles without re-rendering modal
|
|
593
|
+
const buttons = document.querySelectorAll('.location-btn');
|
|
594
|
+
buttons.forEach(btn => {
|
|
595
|
+
const isProject = btn.querySelector('.font-medium')?.textContent?.includes(t('rules.projectRules'));
|
|
596
|
+
const isUser = btn.querySelector('.font-medium')?.textContent?.includes(t('rules.userRules'));
|
|
597
|
+
|
|
598
|
+
if ((isProject && location === 'project') || (isUser && location === 'user')) {
|
|
599
|
+
btn.classList.remove('border-border', 'hover:border-primary/50');
|
|
600
|
+
btn.classList.add('border-primary', 'bg-primary/10');
|
|
601
|
+
} else {
|
|
602
|
+
btn.classList.remove('border-primary', 'bg-primary/10');
|
|
603
|
+
btn.classList.add('border-border', 'hover:border-primary/50');
|
|
604
|
+
}
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function toggleRuleConditional() {
|
|
609
|
+
ruleCreateState.isConditional = !ruleCreateState.isConditional;
|
|
610
|
+
const pathsContainer = document.getElementById('rulePathsContainer');
|
|
611
|
+
if (pathsContainer) {
|
|
612
|
+
pathsContainer.style.display = ruleCreateState.isConditional ? 'block' : 'none';
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
function addRulePath() {
|
|
617
|
+
ruleCreateState.paths.push('');
|
|
618
|
+
// Re-render paths list
|
|
619
|
+
const pathsList = document.getElementById('rulePathsList');
|
|
620
|
+
if (pathsList) {
|
|
621
|
+
const index = ruleCreateState.paths.length - 1;
|
|
622
|
+
const pathHtml = `
|
|
623
|
+
<div class="flex gap-2">
|
|
624
|
+
<input type="text" class="rule-path-input flex-1 px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
|
|
625
|
+
placeholder="src/**/*.ts"
|
|
626
|
+
value=""
|
|
627
|
+
data-index="${index}">
|
|
628
|
+
<button class="px-3 py-2 text-destructive hover:bg-destructive/10 rounded-lg transition-colors"
|
|
629
|
+
onclick="removeRulePath(${index})">
|
|
630
|
+
<i data-lucide="x" class="w-4 h-4"></i>
|
|
631
|
+
</button>
|
|
632
|
+
</div>
|
|
633
|
+
`;
|
|
634
|
+
pathsList.insertAdjacentHTML('beforeend', pathHtml);
|
|
635
|
+
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
function removeRulePath(index) {
|
|
640
|
+
ruleCreateState.paths.splice(index, 1);
|
|
641
|
+
// Re-render paths list
|
|
642
|
+
closeRuleCreateModal();
|
|
643
|
+
openRuleCreateModal();
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
function switchRuleCreateMode(mode) {
|
|
647
|
+
ruleCreateState.mode = mode;
|
|
648
|
+
|
|
649
|
+
// Toggle visibility of sections
|
|
650
|
+
const generationTypeSection = document.getElementById('ruleGenerationTypeSection');
|
|
651
|
+
const descriptionSection = document.getElementById('ruleDescriptionSection');
|
|
652
|
+
const extractSection = document.getElementById('ruleExtractSection');
|
|
653
|
+
const conditionalSection = document.getElementById('ruleConditionalSection');
|
|
654
|
+
const contentSection = document.getElementById('ruleContentSection');
|
|
655
|
+
|
|
656
|
+
if (mode === 'cli-generate') {
|
|
657
|
+
if (generationTypeSection) generationTypeSection.style.display = 'block';
|
|
658
|
+
if (conditionalSection) conditionalSection.style.display = 'none';
|
|
659
|
+
if (contentSection) contentSection.style.display = 'none';
|
|
660
|
+
|
|
661
|
+
// Show appropriate generation section
|
|
662
|
+
if (ruleCreateState.generationType === 'description') {
|
|
663
|
+
if (descriptionSection) descriptionSection.style.display = 'block';
|
|
664
|
+
if (extractSection) extractSection.style.display = 'none';
|
|
665
|
+
} else {
|
|
666
|
+
if (descriptionSection) descriptionSection.style.display = 'none';
|
|
667
|
+
if (extractSection) extractSection.style.display = 'block';
|
|
668
|
+
}
|
|
669
|
+
} else {
|
|
670
|
+
if (generationTypeSection) generationTypeSection.style.display = 'none';
|
|
671
|
+
if (descriptionSection) descriptionSection.style.display = 'none';
|
|
672
|
+
if (extractSection) extractSection.style.display = 'none';
|
|
673
|
+
if (conditionalSection) conditionalSection.style.display = 'block';
|
|
674
|
+
if (contentSection) contentSection.style.display = 'block';
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// Re-render modal to update button states
|
|
678
|
+
closeRuleCreateModal();
|
|
679
|
+
openRuleCreateModal();
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
function switchRuleGenerationType(type) {
|
|
683
|
+
ruleCreateState.generationType = type;
|
|
684
|
+
|
|
685
|
+
// Toggle visibility of generation sections
|
|
686
|
+
const descriptionSection = document.getElementById('ruleDescriptionSection');
|
|
687
|
+
const extractSection = document.getElementById('ruleExtractSection');
|
|
688
|
+
|
|
689
|
+
if (type === 'description') {
|
|
690
|
+
if (descriptionSection) descriptionSection.style.display = 'block';
|
|
691
|
+
if (extractSection) extractSection.style.display = 'none';
|
|
692
|
+
} else if (type === 'extract') {
|
|
693
|
+
if (descriptionSection) descriptionSection.style.display = 'none';
|
|
694
|
+
if (extractSection) extractSection.style.display = 'block';
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
async function createRule() {
|
|
699
|
+
const fileNameInput = document.getElementById('ruleFileName');
|
|
700
|
+
const subdirectoryInput = document.getElementById('ruleSubdirectory');
|
|
701
|
+
const contentInput = document.getElementById('ruleContent');
|
|
702
|
+
const pathInputs = document.querySelectorAll('.rule-path-input');
|
|
703
|
+
const descriptionInput = document.getElementById('ruleDescription');
|
|
704
|
+
const extractScopeInput = document.getElementById('ruleExtractScope');
|
|
705
|
+
const extractFocusInput = document.getElementById('ruleExtractFocus');
|
|
706
|
+
|
|
707
|
+
const fileName = fileNameInput ? fileNameInput.value.trim() : ruleCreateState.fileName;
|
|
708
|
+
const subdirectory = subdirectoryInput ? subdirectoryInput.value.trim() : ruleCreateState.subdirectory;
|
|
709
|
+
|
|
710
|
+
// Validate file name
|
|
711
|
+
if (!fileName) {
|
|
712
|
+
if (window.showToast) {
|
|
713
|
+
showToast(t('rules.fileNameRequired'), 'error');
|
|
714
|
+
}
|
|
715
|
+
return;
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
if (!fileName.endsWith('.md')) {
|
|
719
|
+
if (window.showToast) {
|
|
720
|
+
showToast(t('rules.fileNameMustEndMd'), 'error');
|
|
721
|
+
}
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
// Prepare request based on mode
|
|
726
|
+
let requestBody;
|
|
727
|
+
|
|
728
|
+
if (ruleCreateState.mode === 'cli-generate') {
|
|
729
|
+
// CLI generation mode
|
|
730
|
+
const description = descriptionInput ? descriptionInput.value.trim() : ruleCreateState.description;
|
|
731
|
+
const extractScope = extractScopeInput ? extractScopeInput.value.trim() : ruleCreateState.extractScope;
|
|
732
|
+
const extractFocus = extractFocusInput ? extractFocusInput.value.trim() : ruleCreateState.extractFocus;
|
|
733
|
+
|
|
734
|
+
// Validate based on generation type
|
|
735
|
+
if (ruleCreateState.generationType === 'description' && !description) {
|
|
736
|
+
if (window.showToast) {
|
|
737
|
+
showToast(t('rules.descriptionRequired'), 'error');
|
|
738
|
+
}
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
if (ruleCreateState.generationType === 'extract' && !extractScope) {
|
|
743
|
+
if (window.showToast) {
|
|
744
|
+
showToast(t('rules.extractScopeRequired'), 'error');
|
|
745
|
+
}
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
requestBody = {
|
|
750
|
+
mode: 'cli-generate',
|
|
751
|
+
fileName,
|
|
752
|
+
location: ruleCreateState.location,
|
|
753
|
+
subdirectory: subdirectory || undefined,
|
|
754
|
+
projectPath,
|
|
755
|
+
generationType: ruleCreateState.generationType,
|
|
756
|
+
description: ruleCreateState.generationType === 'description' ? description : undefined,
|
|
757
|
+
extractScope: ruleCreateState.generationType === 'extract' ? extractScope : undefined,
|
|
758
|
+
extractFocus: ruleCreateState.generationType === 'extract' ? extractFocus : undefined
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
// Show progress message
|
|
762
|
+
if (window.showToast) {
|
|
763
|
+
showToast(t('rules.cliGenerating'), 'info');
|
|
764
|
+
}
|
|
765
|
+
} else {
|
|
766
|
+
// Manual input mode
|
|
767
|
+
const content = contentInput ? contentInput.value.trim() : ruleCreateState.content;
|
|
768
|
+
|
|
769
|
+
// Collect paths from inputs
|
|
770
|
+
const paths = [];
|
|
771
|
+
if (ruleCreateState.isConditional && pathInputs) {
|
|
772
|
+
pathInputs.forEach(input => {
|
|
773
|
+
const path = input.value.trim();
|
|
774
|
+
if (path) paths.push(path);
|
|
775
|
+
});
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// Validate content
|
|
779
|
+
if (!content) {
|
|
780
|
+
if (window.showToast) {
|
|
781
|
+
showToast(t('rules.contentRequired'), 'error');
|
|
782
|
+
}
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
requestBody = {
|
|
787
|
+
mode: 'input',
|
|
788
|
+
fileName,
|
|
789
|
+
content,
|
|
790
|
+
paths: paths.length > 0 ? paths : undefined,
|
|
791
|
+
location: ruleCreateState.location,
|
|
792
|
+
subdirectory: subdirectory || undefined,
|
|
793
|
+
projectPath
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
try {
|
|
798
|
+
const response = await fetch('/api/rules/create', {
|
|
799
|
+
method: 'POST',
|
|
800
|
+
headers: { 'Content-Type': 'application/json' },
|
|
801
|
+
body: JSON.stringify(requestBody)
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
if (!response.ok) {
|
|
805
|
+
const error = await response.json();
|
|
806
|
+
throw new Error(error.error || 'Failed to create rule');
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
const result = await response.json();
|
|
810
|
+
|
|
811
|
+
// Close modal
|
|
812
|
+
closeRuleCreateModal();
|
|
813
|
+
|
|
814
|
+
// Reload rules data
|
|
815
|
+
await loadRulesData();
|
|
816
|
+
renderRulesView();
|
|
817
|
+
|
|
818
|
+
// Show success message
|
|
819
|
+
if (window.showToast) {
|
|
820
|
+
showToast(t('rules.created', { name: result.fileName }), 'success');
|
|
821
|
+
}
|
|
822
|
+
} catch (err) {
|
|
823
|
+
console.error('Failed to create rule:', err);
|
|
824
|
+
if (window.showToast) {
|
|
825
|
+
showToast(err.message || t('rules.createError'), 'error');
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|