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,819 @@
|
|
|
1
|
+
// Skills Manager View
|
|
2
|
+
// Manages Claude Code skills (.claude/skills/)
|
|
3
|
+
|
|
4
|
+
// ========== Skills State ==========
|
|
5
|
+
var skillsData = {
|
|
6
|
+
projectSkills: [],
|
|
7
|
+
userSkills: []
|
|
8
|
+
};
|
|
9
|
+
var selectedSkill = null;
|
|
10
|
+
var skillsLoading = false;
|
|
11
|
+
|
|
12
|
+
// ========== Main Render Function ==========
|
|
13
|
+
async function renderSkillsManager() {
|
|
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="skills-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 skills data
|
|
30
|
+
await loadSkillsData();
|
|
31
|
+
|
|
32
|
+
// Render the main view
|
|
33
|
+
renderSkillsView();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function loadSkillsData() {
|
|
37
|
+
skillsLoading = true;
|
|
38
|
+
try {
|
|
39
|
+
const response = await fetch('/api/skills?path=' + encodeURIComponent(projectPath));
|
|
40
|
+
if (!response.ok) throw new Error('Failed to load skills');
|
|
41
|
+
const data = await response.json();
|
|
42
|
+
skillsData = {
|
|
43
|
+
projectSkills: data.projectSkills || [],
|
|
44
|
+
userSkills: data.userSkills || []
|
|
45
|
+
};
|
|
46
|
+
// Update badge
|
|
47
|
+
updateSkillsBadge();
|
|
48
|
+
} catch (err) {
|
|
49
|
+
console.error('Failed to load skills:', err);
|
|
50
|
+
skillsData = { projectSkills: [], userSkills: [] };
|
|
51
|
+
} finally {
|
|
52
|
+
skillsLoading = false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function updateSkillsBadge() {
|
|
57
|
+
const badge = document.getElementById('badgeSkills');
|
|
58
|
+
if (badge) {
|
|
59
|
+
const total = skillsData.projectSkills.length + skillsData.userSkills.length;
|
|
60
|
+
badge.textContent = total;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function renderSkillsView() {
|
|
65
|
+
const container = document.getElementById('mainContent');
|
|
66
|
+
if (!container) return;
|
|
67
|
+
|
|
68
|
+
const projectSkills = skillsData.projectSkills || [];
|
|
69
|
+
const userSkills = skillsData.userSkills || [];
|
|
70
|
+
|
|
71
|
+
container.innerHTML = `
|
|
72
|
+
<div class="skills-manager">
|
|
73
|
+
<!-- Header -->
|
|
74
|
+
<div class="skills-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-primary/10 rounded-lg flex items-center justify-center">
|
|
78
|
+
<i data-lucide="sparkles" class="w-5 h-5 text-primary"></i>
|
|
79
|
+
</div>
|
|
80
|
+
<div>
|
|
81
|
+
<h2 class="text-lg font-semibold text-foreground">${t('skills.title')}</h2>
|
|
82
|
+
<p class="text-sm text-muted-foreground">${t('skills.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="openSkillCreateModal()">
|
|
87
|
+
<i data-lucide="plus" class="w-4 h-4"></i>
|
|
88
|
+
${t('skills.create')}
|
|
89
|
+
</button>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<!-- Project Skills Section -->
|
|
94
|
+
<div class="skills-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-primary"></i>
|
|
98
|
+
<h3 class="text-lg font-semibold text-foreground">${t('skills.projectSkills')}</h3>
|
|
99
|
+
<span class="text-xs px-2 py-0.5 bg-primary/10 text-primary rounded-full">.claude/skills/</span>
|
|
100
|
+
</div>
|
|
101
|
+
<span class="text-sm text-muted-foreground">${projectSkills.length} ${t('skills.skillsCount')}</span>
|
|
102
|
+
</div>
|
|
103
|
+
|
|
104
|
+
${projectSkills.length === 0 ? `
|
|
105
|
+
<div class="skills-empty-state bg-card border border-border rounded-lg p-6 text-center">
|
|
106
|
+
<div class="text-muted-foreground mb-3"><i data-lucide="sparkles" class="w-10 h-10 mx-auto"></i></div>
|
|
107
|
+
<p class="text-muted-foreground">${t('skills.noProjectSkills')}</p>
|
|
108
|
+
<p class="text-sm text-muted-foreground mt-1">${t('skills.createHint')}</p>
|
|
109
|
+
</div>
|
|
110
|
+
` : `
|
|
111
|
+
<div class="skills-grid grid gap-3">
|
|
112
|
+
${projectSkills.map(skill => renderSkillCard(skill, 'project')).join('')}
|
|
113
|
+
</div>
|
|
114
|
+
`}
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<!-- User Skills Section -->
|
|
118
|
+
<div class="skills-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-indigo"></i>
|
|
122
|
+
<h3 class="text-lg font-semibold text-foreground">${t('skills.userSkills')}</h3>
|
|
123
|
+
<span class="text-xs px-2 py-0.5 bg-indigo/10 text-indigo rounded-full">~/.claude/skills/</span>
|
|
124
|
+
</div>
|
|
125
|
+
<span class="text-sm text-muted-foreground">${userSkills.length} ${t('skills.skillsCount')}</span>
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
${userSkills.length === 0 ? `
|
|
129
|
+
<div class="skills-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('skills.noUserSkills')}</p>
|
|
132
|
+
<p class="text-sm text-muted-foreground mt-1">${t('skills.userSkillsHint')}</p>
|
|
133
|
+
</div>
|
|
134
|
+
` : `
|
|
135
|
+
<div class="skills-grid grid gap-3">
|
|
136
|
+
${userSkills.map(skill => renderSkillCard(skill, 'user')).join('')}
|
|
137
|
+
</div>
|
|
138
|
+
`}
|
|
139
|
+
</div>
|
|
140
|
+
|
|
141
|
+
<!-- Skill Detail Panel -->
|
|
142
|
+
${selectedSkill ? renderSkillDetailPanel(selectedSkill) : ''}
|
|
143
|
+
</div>
|
|
144
|
+
`;
|
|
145
|
+
|
|
146
|
+
// Initialize Lucide icons
|
|
147
|
+
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function renderSkillCard(skill, location) {
|
|
151
|
+
const hasAllowedTools = skill.allowedTools && skill.allowedTools.length > 0;
|
|
152
|
+
const hasSupportingFiles = skill.supportingFiles && skill.supportingFiles.length > 0;
|
|
153
|
+
const locationIcon = location === 'project' ? 'folder' : 'user';
|
|
154
|
+
const locationClass = location === 'project' ? 'text-primary' : 'text-indigo';
|
|
155
|
+
const locationBg = location === 'project' ? 'bg-primary/10' : 'bg-indigo/10';
|
|
156
|
+
|
|
157
|
+
return `
|
|
158
|
+
<div class="skill-card bg-card border border-border rounded-lg p-4 hover:shadow-md transition-all cursor-pointer"
|
|
159
|
+
onclick="showSkillDetail('${escapeHtml(skill.name)}', '${location}')">
|
|
160
|
+
<div class="flex items-start justify-between mb-3">
|
|
161
|
+
<div class="flex items-center gap-3">
|
|
162
|
+
<div class="w-10 h-10 ${locationBg} rounded-lg flex items-center justify-center">
|
|
163
|
+
<i data-lucide="sparkles" class="w-5 h-5 ${locationClass}"></i>
|
|
164
|
+
</div>
|
|
165
|
+
<div>
|
|
166
|
+
<h4 class="font-semibold text-foreground">${escapeHtml(skill.name)}</h4>
|
|
167
|
+
${skill.version ? `<span class="text-xs text-muted-foreground">v${escapeHtml(skill.version)}</span>` : ''}
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
<div class="flex items-center gap-1">
|
|
171
|
+
<span class="inline-flex items-center px-2 py-0.5 text-xs font-medium rounded-full ${locationBg} ${locationClass}">
|
|
172
|
+
<i data-lucide="${locationIcon}" class="w-3 h-3 mr-1"></i>
|
|
173
|
+
${location}
|
|
174
|
+
</span>
|
|
175
|
+
</div>
|
|
176
|
+
</div>
|
|
177
|
+
|
|
178
|
+
<p class="text-sm text-muted-foreground mb-3 line-clamp-2">${escapeHtml(skill.description || t('skills.noDescription'))}</p>
|
|
179
|
+
|
|
180
|
+
<div class="flex items-center gap-3 text-xs text-muted-foreground">
|
|
181
|
+
${hasAllowedTools ? `
|
|
182
|
+
<span class="flex items-center gap-1">
|
|
183
|
+
<i data-lucide="lock" class="w-3 h-3"></i>
|
|
184
|
+
${skill.allowedTools.length} ${t('skills.tools')}
|
|
185
|
+
</span>
|
|
186
|
+
` : ''}
|
|
187
|
+
${hasSupportingFiles ? `
|
|
188
|
+
<span class="flex items-center gap-1">
|
|
189
|
+
<i data-lucide="file-text" class="w-3 h-3"></i>
|
|
190
|
+
${skill.supportingFiles.length} ${t('skills.files')}
|
|
191
|
+
</span>
|
|
192
|
+
` : ''}
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
`;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function renderSkillDetailPanel(skill) {
|
|
199
|
+
const hasAllowedTools = skill.allowedTools && skill.allowedTools.length > 0;
|
|
200
|
+
const hasSupportingFiles = skill.supportingFiles && skill.supportingFiles.length > 0;
|
|
201
|
+
|
|
202
|
+
return `
|
|
203
|
+
<div class="skill-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">
|
|
204
|
+
<div class="flex items-center justify-between px-5 py-4 border-b border-border">
|
|
205
|
+
<h3 class="text-lg font-semibold text-foreground">${escapeHtml(skill.name)}</h3>
|
|
206
|
+
<button class="w-8 h-8 flex items-center justify-center text-xl text-muted-foreground hover:text-foreground hover:bg-hover rounded"
|
|
207
|
+
onclick="closeSkillDetail()">×</button>
|
|
208
|
+
</div>
|
|
209
|
+
<div class="flex-1 overflow-y-auto p-5">
|
|
210
|
+
<div class="space-y-6">
|
|
211
|
+
<!-- Description -->
|
|
212
|
+
<div>
|
|
213
|
+
<h4 class="text-sm font-semibold text-foreground mb-2">${t('skills.descriptionLabel')}</h4>
|
|
214
|
+
<p class="text-sm text-muted-foreground">${escapeHtml(skill.description || t('skills.noDescription'))}</p>
|
|
215
|
+
</div>
|
|
216
|
+
|
|
217
|
+
<!-- Metadata -->
|
|
218
|
+
<div>
|
|
219
|
+
<h4 class="text-sm font-semibold text-foreground mb-2">${t('skills.metadata')}</h4>
|
|
220
|
+
<div class="grid grid-cols-2 gap-3">
|
|
221
|
+
<div class="bg-muted/50 rounded-lg p-3">
|
|
222
|
+
<span class="text-xs text-muted-foreground">${t('skills.location')}</span>
|
|
223
|
+
<p class="text-sm font-medium text-foreground">${escapeHtml(skill.location)}</p>
|
|
224
|
+
</div>
|
|
225
|
+
${skill.version ? `
|
|
226
|
+
<div class="bg-muted/50 rounded-lg p-3">
|
|
227
|
+
<span class="text-xs text-muted-foreground">${t('skills.version')}</span>
|
|
228
|
+
<p class="text-sm font-medium text-foreground">${escapeHtml(skill.version)}</p>
|
|
229
|
+
</div>
|
|
230
|
+
` : ''}
|
|
231
|
+
</div>
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
<!-- Allowed Tools -->
|
|
235
|
+
${hasAllowedTools ? `
|
|
236
|
+
<div>
|
|
237
|
+
<h4 class="text-sm font-semibold text-foreground mb-2">${t('skills.allowedTools')}</h4>
|
|
238
|
+
<div class="flex flex-wrap gap-2">
|
|
239
|
+
${skill.allowedTools.map(tool => `
|
|
240
|
+
<span class="px-2 py-1 text-xs bg-muted rounded-lg font-mono">${escapeHtml(tool)}</span>
|
|
241
|
+
`).join('')}
|
|
242
|
+
</div>
|
|
243
|
+
</div>
|
|
244
|
+
` : ''}
|
|
245
|
+
|
|
246
|
+
<!-- Supporting Files -->
|
|
247
|
+
${hasSupportingFiles ? `
|
|
248
|
+
<div>
|
|
249
|
+
<h4 class="text-sm font-semibold text-foreground mb-2">${t('skills.supportingFiles')}</h4>
|
|
250
|
+
<div class="space-y-2">
|
|
251
|
+
${skill.supportingFiles.map(file => `
|
|
252
|
+
<div class="flex items-center gap-2 p-2 bg-muted/50 rounded-lg">
|
|
253
|
+
<i data-lucide="file-text" class="w-4 h-4 text-muted-foreground"></i>
|
|
254
|
+
<span class="text-sm font-mono text-foreground">${escapeHtml(file)}</span>
|
|
255
|
+
</div>
|
|
256
|
+
`).join('')}
|
|
257
|
+
</div>
|
|
258
|
+
</div>
|
|
259
|
+
` : ''}
|
|
260
|
+
|
|
261
|
+
<!-- Path -->
|
|
262
|
+
<div>
|
|
263
|
+
<h4 class="text-sm font-semibold text-foreground mb-2">${t('skills.path')}</h4>
|
|
264
|
+
<code class="block p-3 bg-muted rounded-lg text-xs font-mono text-muted-foreground break-all">${escapeHtml(skill.path)}</code>
|
|
265
|
+
</div>
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
|
|
269
|
+
<!-- Actions -->
|
|
270
|
+
<div class="px-5 py-4 border-t border-border flex justify-between">
|
|
271
|
+
<button class="px-4 py-2 text-sm text-destructive hover:bg-destructive/10 rounded-lg transition-colors flex items-center gap-2"
|
|
272
|
+
onclick="deleteSkill('${escapeHtml(skill.name)}', '${skill.location}')">
|
|
273
|
+
<i data-lucide="trash-2" class="w-4 h-4"></i>
|
|
274
|
+
${t('common.delete')}
|
|
275
|
+
</button>
|
|
276
|
+
<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"
|
|
277
|
+
onclick="editSkill('${escapeHtml(skill.name)}', '${skill.location}')">
|
|
278
|
+
<i data-lucide="edit" class="w-4 h-4"></i>
|
|
279
|
+
${t('common.edit')}
|
|
280
|
+
</button>
|
|
281
|
+
</div>
|
|
282
|
+
</div>
|
|
283
|
+
<div class="skill-detail-overlay fixed inset-0 bg-black/50 z-40" onclick="closeSkillDetail()"></div>
|
|
284
|
+
`;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async function showSkillDetail(skillName, location) {
|
|
288
|
+
try {
|
|
289
|
+
const response = await fetch('/api/skills/' + encodeURIComponent(skillName) + '?location=' + location + '&path=' + encodeURIComponent(projectPath));
|
|
290
|
+
if (!response.ok) throw new Error('Failed to load skill detail');
|
|
291
|
+
const data = await response.json();
|
|
292
|
+
selectedSkill = data.skill;
|
|
293
|
+
renderSkillsView();
|
|
294
|
+
} catch (err) {
|
|
295
|
+
console.error('Failed to load skill detail:', err);
|
|
296
|
+
if (window.showToast) {
|
|
297
|
+
showToast(t('skills.loadError'), 'error');
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function closeSkillDetail() {
|
|
303
|
+
selectedSkill = null;
|
|
304
|
+
renderSkillsView();
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async function deleteSkill(skillName, location) {
|
|
308
|
+
if (!confirm(t('skills.deleteConfirm', { name: skillName }))) return;
|
|
309
|
+
|
|
310
|
+
try {
|
|
311
|
+
const response = await fetch('/api/skills/' + encodeURIComponent(skillName), {
|
|
312
|
+
method: 'DELETE',
|
|
313
|
+
headers: { 'Content-Type': 'application/json' },
|
|
314
|
+
body: JSON.stringify({ location, projectPath })
|
|
315
|
+
});
|
|
316
|
+
if (!response.ok) throw new Error('Failed to delete skill');
|
|
317
|
+
|
|
318
|
+
selectedSkill = null;
|
|
319
|
+
await loadSkillsData();
|
|
320
|
+
renderSkillsView();
|
|
321
|
+
|
|
322
|
+
if (window.showToast) {
|
|
323
|
+
showToast(t('skills.deleted'), 'success');
|
|
324
|
+
}
|
|
325
|
+
} catch (err) {
|
|
326
|
+
console.error('Failed to delete skill:', err);
|
|
327
|
+
if (window.showToast) {
|
|
328
|
+
showToast(t('skills.deleteError'), 'error');
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function editSkill(skillName, location) {
|
|
334
|
+
// Open edit modal (to be implemented with modal)
|
|
335
|
+
if (window.showToast) {
|
|
336
|
+
showToast(t('skills.editNotImplemented'), 'info');
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// ========== Create Skill Modal ==========
|
|
341
|
+
var skillCreateState = {
|
|
342
|
+
mode: 'import', // 'import' or 'cli-generate'
|
|
343
|
+
location: 'project',
|
|
344
|
+
sourcePath: '',
|
|
345
|
+
customName: '',
|
|
346
|
+
validationResult: null,
|
|
347
|
+
// CLI Generate mode fields
|
|
348
|
+
generationType: 'description', // 'description' or 'template'
|
|
349
|
+
description: '',
|
|
350
|
+
skillName: ''
|
|
351
|
+
};
|
|
352
|
+
|
|
353
|
+
function openSkillCreateModal() {
|
|
354
|
+
// Reset state
|
|
355
|
+
skillCreateState = {
|
|
356
|
+
mode: 'import',
|
|
357
|
+
location: 'project',
|
|
358
|
+
sourcePath: '',
|
|
359
|
+
customName: '',
|
|
360
|
+
validationResult: null,
|
|
361
|
+
generationType: 'description',
|
|
362
|
+
description: '',
|
|
363
|
+
skillName: ''
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
// Create modal HTML
|
|
367
|
+
const modalHtml = `
|
|
368
|
+
<div class="modal-overlay fixed inset-0 bg-black/50 z-50 flex items-center justify-center" onclick="closeSkillCreateModal(event)">
|
|
369
|
+
<div class="modal-dialog bg-card rounded-lg shadow-lg w-full max-w-2xl mx-4" onclick="event.stopPropagation()">
|
|
370
|
+
<!-- Header -->
|
|
371
|
+
<div class="flex items-center justify-between px-6 py-4 border-b border-border">
|
|
372
|
+
<h3 class="text-lg font-semibold text-foreground">${t('skills.createSkill')}</h3>
|
|
373
|
+
<button class="w-8 h-8 flex items-center justify-center text-xl text-muted-foreground hover:text-foreground hover:bg-hover rounded"
|
|
374
|
+
onclick="closeSkillCreateModal()">×</button>
|
|
375
|
+
</div>
|
|
376
|
+
|
|
377
|
+
<!-- Body -->
|
|
378
|
+
<div class="p-6 space-y-5">
|
|
379
|
+
<!-- Location Selection -->
|
|
380
|
+
<div>
|
|
381
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('skills.location')}</label>
|
|
382
|
+
<div class="grid grid-cols-2 gap-3">
|
|
383
|
+
<button class="location-btn px-4 py-3 text-left border-2 rounded-lg transition-all ${skillCreateState.location === 'project' ? 'border-primary bg-primary/10' : 'border-border hover:border-primary/50'}"
|
|
384
|
+
onclick="selectSkillLocation('project')">
|
|
385
|
+
<div class="flex items-center gap-2">
|
|
386
|
+
<i data-lucide="folder" class="w-5 h-5"></i>
|
|
387
|
+
<div>
|
|
388
|
+
<div class="font-medium">${t('skills.projectSkills')}</div>
|
|
389
|
+
<div class="text-xs text-muted-foreground">.claude/skills/</div>
|
|
390
|
+
</div>
|
|
391
|
+
</div>
|
|
392
|
+
</button>
|
|
393
|
+
<button class="location-btn px-4 py-3 text-left border-2 rounded-lg transition-all ${skillCreateState.location === 'user' ? 'border-primary bg-primary/10' : 'border-border hover:border-primary/50'}"
|
|
394
|
+
onclick="selectSkillLocation('user')">
|
|
395
|
+
<div class="flex items-center gap-2">
|
|
396
|
+
<i data-lucide="user" class="w-5 h-5"></i>
|
|
397
|
+
<div>
|
|
398
|
+
<div class="font-medium">${t('skills.userSkills')}</div>
|
|
399
|
+
<div class="text-xs text-muted-foreground">~/.claude/skills/</div>
|
|
400
|
+
</div>
|
|
401
|
+
</div>
|
|
402
|
+
</button>
|
|
403
|
+
</div>
|
|
404
|
+
</div>
|
|
405
|
+
|
|
406
|
+
<!-- Mode Selection -->
|
|
407
|
+
<div>
|
|
408
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('skills.createMode')}</label>
|
|
409
|
+
<div class="grid grid-cols-2 gap-3">
|
|
410
|
+
<button class="mode-btn px-4 py-3 text-left border-2 rounded-lg transition-all ${skillCreateState.mode === 'import' ? 'border-primary bg-primary/10' : 'border-border hover:border-primary/50'}"
|
|
411
|
+
onclick="switchSkillCreateMode('import')">
|
|
412
|
+
<div class="flex items-center gap-2">
|
|
413
|
+
<i data-lucide="folder-input" class="w-5 h-5"></i>
|
|
414
|
+
<div>
|
|
415
|
+
<div class="font-medium">${t('skills.importFolder')}</div>
|
|
416
|
+
<div class="text-xs text-muted-foreground">${t('skills.importFolderHint')}</div>
|
|
417
|
+
</div>
|
|
418
|
+
</div>
|
|
419
|
+
</button>
|
|
420
|
+
<button class="mode-btn px-4 py-3 text-left border-2 rounded-lg transition-all ${skillCreateState.mode === 'cli-generate' ? 'border-primary bg-primary/10' : 'border-border hover:border-primary/50'}"
|
|
421
|
+
onclick="switchSkillCreateMode('cli-generate')">
|
|
422
|
+
<div class="flex items-center gap-2">
|
|
423
|
+
<i data-lucide="sparkles" class="w-5 h-5"></i>
|
|
424
|
+
<div>
|
|
425
|
+
<div class="font-medium">${t('skills.cliGenerate')}</div>
|
|
426
|
+
<div class="text-xs text-muted-foreground">${t('skills.cliGenerateHint')}</div>
|
|
427
|
+
</div>
|
|
428
|
+
</div>
|
|
429
|
+
</button>
|
|
430
|
+
</div>
|
|
431
|
+
</div>
|
|
432
|
+
|
|
433
|
+
<!-- Import Mode Content -->
|
|
434
|
+
<div id="skillImportMode" style="display: ${skillCreateState.mode === 'import' ? 'block' : 'none'}">
|
|
435
|
+
<!-- Source Folder Path -->
|
|
436
|
+
<div>
|
|
437
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('skills.sourceFolder')}</label>
|
|
438
|
+
<div class="flex gap-2">
|
|
439
|
+
<input type="text" id="skillSourcePath"
|
|
440
|
+
class="flex-1 px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
|
|
441
|
+
placeholder="${t('skills.sourceFolderPlaceholder')}"
|
|
442
|
+
value="${skillCreateState.sourcePath}">
|
|
443
|
+
<button class="px-4 py-2 bg-primary/10 text-primary rounded-lg hover:bg-primary/20 transition-colors text-sm"
|
|
444
|
+
onclick="browseSkillFolder()">
|
|
445
|
+
<i data-lucide="folder-open" class="w-4 h-4"></i>
|
|
446
|
+
</button>
|
|
447
|
+
</div>
|
|
448
|
+
<p class="text-xs text-muted-foreground mt-1">${t('skills.sourceFolderHint')}</p>
|
|
449
|
+
</div>
|
|
450
|
+
|
|
451
|
+
<!-- Custom Name -->
|
|
452
|
+
<div>
|
|
453
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('skills.customName')} <span class="text-muted-foreground">${t('common.optional')}</span></label>
|
|
454
|
+
<input type="text" id="skillCustomName"
|
|
455
|
+
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"
|
|
456
|
+
placeholder="${t('skills.customNamePlaceholder')}"
|
|
457
|
+
value="${skillCreateState.customName}">
|
|
458
|
+
<p class="text-xs text-muted-foreground mt-1">${t('skills.customNameHint')}</p>
|
|
459
|
+
</div>
|
|
460
|
+
|
|
461
|
+
<!-- Validation Result -->
|
|
462
|
+
<div id="skillValidationResult"></div>
|
|
463
|
+
</div>
|
|
464
|
+
|
|
465
|
+
<!-- CLI Generate Mode Content -->
|
|
466
|
+
<div id="skillCliGenerateMode" style="display: ${skillCreateState.mode === 'cli-generate' ? 'block' : 'none'}">
|
|
467
|
+
<!-- Skill Name (Required for CLI Generate) -->
|
|
468
|
+
<div>
|
|
469
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('skills.skillName')} <span class="text-destructive">*</span></label>
|
|
470
|
+
<input type="text" id="skillGenerateName"
|
|
471
|
+
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"
|
|
472
|
+
placeholder="${t('skills.skillNamePlaceholder')}"
|
|
473
|
+
value="${skillCreateState.skillName}">
|
|
474
|
+
<p class="text-xs text-muted-foreground mt-1">${t('skills.skillNameHint')}</p>
|
|
475
|
+
</div>
|
|
476
|
+
|
|
477
|
+
<!-- Generation Type Selection -->
|
|
478
|
+
<div>
|
|
479
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('skills.generationType')}</label>
|
|
480
|
+
<div class="flex gap-3">
|
|
481
|
+
<button class="flex-1 px-4 py-3 text-left border-2 rounded-lg transition-all ${skillCreateState.generationType === 'description' ? 'border-primary bg-primary/10' : 'border-border hover:border-primary/50'}"
|
|
482
|
+
onclick="switchSkillGenerationType('description')">
|
|
483
|
+
<div class="flex items-center gap-2">
|
|
484
|
+
<i data-lucide="file-text" class="w-5 h-5"></i>
|
|
485
|
+
<div>
|
|
486
|
+
<div class="font-medium text-sm">${t('skills.fromDescription')}</div>
|
|
487
|
+
<div class="text-xs text-muted-foreground">${t('skills.fromDescriptionHint')}</div>
|
|
488
|
+
</div>
|
|
489
|
+
</div>
|
|
490
|
+
</button>
|
|
491
|
+
<button class="flex-1 px-4 py-3 text-left border-2 rounded-lg transition-all opacity-50 cursor-not-allowed"
|
|
492
|
+
disabled>
|
|
493
|
+
<div class="flex items-center gap-2">
|
|
494
|
+
<i data-lucide="layout-template" class="w-5 h-5"></i>
|
|
495
|
+
<div>
|
|
496
|
+
<div class="font-medium text-sm">${t('skills.fromTemplate')}</div>
|
|
497
|
+
<div class="text-xs text-muted-foreground">${t('skills.comingSoon')}</div>
|
|
498
|
+
</div>
|
|
499
|
+
</div>
|
|
500
|
+
</button>
|
|
501
|
+
</div>
|
|
502
|
+
</div>
|
|
503
|
+
|
|
504
|
+
<!-- Description Text Area (for 'description' type) -->
|
|
505
|
+
<div id="skillDescriptionArea" style="display: ${skillCreateState.generationType === 'description' ? 'block' : 'none'}">
|
|
506
|
+
<label class="block text-sm font-medium text-foreground mb-2">${t('skills.descriptionLabel')} <span class="text-destructive">*</span></label>
|
|
507
|
+
<textarea id="skillDescription"
|
|
508
|
+
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"
|
|
509
|
+
placeholder="${t('skills.descriptionPlaceholder')}"
|
|
510
|
+
rows="6">${skillCreateState.description}</textarea>
|
|
511
|
+
<p class="text-xs text-muted-foreground mt-1">${t('skills.descriptionGenerateHint')}</p>
|
|
512
|
+
</div>
|
|
513
|
+
|
|
514
|
+
<!-- CLI Generate Info -->
|
|
515
|
+
<div class="p-3 bg-blue-500/10 border border-blue-500/20 rounded-lg">
|
|
516
|
+
<div class="flex items-start gap-2">
|
|
517
|
+
<i data-lucide="info" class="w-4 h-4 text-blue-600 mt-0.5"></i>
|
|
518
|
+
<div class="text-sm text-blue-600">
|
|
519
|
+
<p class="font-medium">${t('skills.cliGenerateInfo')}</p>
|
|
520
|
+
<p class="text-xs mt-1">${t('skills.cliGenerateTimeHint')}</p>
|
|
521
|
+
</div>
|
|
522
|
+
</div>
|
|
523
|
+
</div>
|
|
524
|
+
</div>
|
|
525
|
+
</div>
|
|
526
|
+
|
|
527
|
+
<!-- Footer -->
|
|
528
|
+
<div class="flex items-center justify-end gap-3 px-6 py-4 border-t border-border">
|
|
529
|
+
<button class="px-4 py-2 text-sm text-muted-foreground hover:text-foreground transition-colors"
|
|
530
|
+
onclick="closeSkillCreateModal()">
|
|
531
|
+
${t('common.cancel')}
|
|
532
|
+
</button>
|
|
533
|
+
${skillCreateState.mode === 'import' ? `
|
|
534
|
+
<button class="px-4 py-2 text-sm bg-primary/10 text-primary rounded-lg hover:bg-primary/20 transition-colors"
|
|
535
|
+
onclick="validateSkillImport()">
|
|
536
|
+
${t('skills.validate')}
|
|
537
|
+
</button>
|
|
538
|
+
<button class="px-4 py-2 text-sm bg-primary text-primary-foreground rounded-lg hover:opacity-90 transition-opacity"
|
|
539
|
+
onclick="createSkill()">
|
|
540
|
+
${t('skills.import')}
|
|
541
|
+
</button>
|
|
542
|
+
` : `
|
|
543
|
+
<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"
|
|
544
|
+
onclick="createSkill()">
|
|
545
|
+
<i data-lucide="sparkles" class="w-4 h-4"></i>
|
|
546
|
+
${t('skills.generate')}
|
|
547
|
+
</button>
|
|
548
|
+
`}
|
|
549
|
+
</div>
|
|
550
|
+
</div>
|
|
551
|
+
</div>
|
|
552
|
+
`;
|
|
553
|
+
|
|
554
|
+
// Add to DOM
|
|
555
|
+
const modalContainer = document.createElement('div');
|
|
556
|
+
modalContainer.id = 'skillCreateModal';
|
|
557
|
+
modalContainer.innerHTML = modalHtml;
|
|
558
|
+
document.body.appendChild(modalContainer);
|
|
559
|
+
|
|
560
|
+
// Initialize Lucide icons
|
|
561
|
+
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
function closeSkillCreateModal(event) {
|
|
565
|
+
if (event && event.target !== event.currentTarget) return;
|
|
566
|
+
const modal = document.getElementById('skillCreateModal');
|
|
567
|
+
if (modal) modal.remove();
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function selectSkillLocation(location) {
|
|
571
|
+
skillCreateState.location = location;
|
|
572
|
+
|
|
573
|
+
// Update button styles without re-rendering modal
|
|
574
|
+
const buttons = document.querySelectorAll('.location-btn');
|
|
575
|
+
buttons.forEach(btn => {
|
|
576
|
+
const isProject = btn.querySelector('.font-medium')?.textContent?.includes(t('skills.projectSkills'));
|
|
577
|
+
const isUser = btn.querySelector('.font-medium')?.textContent?.includes(t('skills.userSkills'));
|
|
578
|
+
|
|
579
|
+
if ((isProject && location === 'project') || (isUser && location === 'user')) {
|
|
580
|
+
btn.classList.remove('border-border', 'hover:border-primary/50');
|
|
581
|
+
btn.classList.add('border-primary', 'bg-primary/10');
|
|
582
|
+
} else {
|
|
583
|
+
btn.classList.remove('border-primary', 'bg-primary/10');
|
|
584
|
+
btn.classList.add('border-border', 'hover:border-primary/50');
|
|
585
|
+
}
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
function switchSkillCreateMode(mode) {
|
|
590
|
+
skillCreateState.mode = mode;
|
|
591
|
+
// Re-render modal
|
|
592
|
+
closeSkillCreateModal();
|
|
593
|
+
openSkillCreateModal();
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function switchSkillGenerationType(type) {
|
|
597
|
+
skillCreateState.generationType = type;
|
|
598
|
+
// Re-render modal
|
|
599
|
+
closeSkillCreateModal();
|
|
600
|
+
openSkillCreateModal();
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
function browseSkillFolder() {
|
|
604
|
+
// Use browser prompt for now (Phase 3 will implement file browser)
|
|
605
|
+
const path = prompt(t('skills.enterFolderPath'), skillCreateState.sourcePath);
|
|
606
|
+
if (path !== null) {
|
|
607
|
+
skillCreateState.sourcePath = path;
|
|
608
|
+
document.getElementById('skillSourcePath').value = path;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
async function validateSkillImport() {
|
|
613
|
+
const sourcePathInput = document.getElementById('skillSourcePath');
|
|
614
|
+
const sourcePath = sourcePathInput ? sourcePathInput.value.trim() : skillCreateState.sourcePath;
|
|
615
|
+
|
|
616
|
+
if (!sourcePath) {
|
|
617
|
+
showValidationResult({ valid: false, errors: [t('skills.sourceFolderRequired')], skillInfo: null });
|
|
618
|
+
return;
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
skillCreateState.sourcePath = sourcePath;
|
|
622
|
+
|
|
623
|
+
// Show loading state
|
|
624
|
+
showValidationResult({ loading: true });
|
|
625
|
+
|
|
626
|
+
try {
|
|
627
|
+
const response = await fetch('/api/skills/validate-import', {
|
|
628
|
+
method: 'POST',
|
|
629
|
+
headers: { 'Content-Type': 'application/json' },
|
|
630
|
+
body: JSON.stringify({ sourcePath })
|
|
631
|
+
});
|
|
632
|
+
|
|
633
|
+
if (!response.ok) throw new Error('Validation request failed');
|
|
634
|
+
|
|
635
|
+
const result = await response.json();
|
|
636
|
+
skillCreateState.validationResult = result;
|
|
637
|
+
showValidationResult(result);
|
|
638
|
+
} catch (err) {
|
|
639
|
+
console.error('Failed to validate skill:', err);
|
|
640
|
+
showValidationResult({ valid: false, errors: [t('skills.validationError')], skillInfo: null });
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
function showValidationResult(result) {
|
|
645
|
+
const container = document.getElementById('skillValidationResult');
|
|
646
|
+
if (!container) return;
|
|
647
|
+
|
|
648
|
+
if (result.loading) {
|
|
649
|
+
container.innerHTML = `
|
|
650
|
+
<div class="flex items-center gap-2 p-3 bg-muted/50 rounded-lg">
|
|
651
|
+
<i data-lucide="loader-2" class="w-4 h-4 animate-spin"></i>
|
|
652
|
+
<span class="text-sm text-muted-foreground">${t('skills.validating')}</span>
|
|
653
|
+
</div>
|
|
654
|
+
`;
|
|
655
|
+
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
if (result.valid) {
|
|
660
|
+
container.innerHTML = `
|
|
661
|
+
<div class="p-4 bg-green-500/10 border border-green-500/20 rounded-lg">
|
|
662
|
+
<div class="flex items-center gap-2 text-green-600 mb-2">
|
|
663
|
+
<i data-lucide="check-circle" class="w-5 h-5"></i>
|
|
664
|
+
<span class="font-medium">${t('skills.validSkill')}</span>
|
|
665
|
+
</div>
|
|
666
|
+
<div class="space-y-1 text-sm">
|
|
667
|
+
<div><span class="text-muted-foreground">${t('skills.name')}:</span> <span class="font-medium">${escapeHtml(result.skillInfo.name)}</span></div>
|
|
668
|
+
<div><span class="text-muted-foreground">${t('skills.description')}:</span> <span>${escapeHtml(result.skillInfo.description)}</span></div>
|
|
669
|
+
${result.skillInfo.version ? `<div><span class="text-muted-foreground">${t('skills.version')}:</span> <span>${escapeHtml(result.skillInfo.version)}</span></div>` : ''}
|
|
670
|
+
${result.skillInfo.supportingFiles && result.skillInfo.supportingFiles.length > 0 ? `<div><span class="text-muted-foreground">${t('skills.supportingFiles')}:</span> <span>${result.skillInfo.supportingFiles.length} ${t('skills.files')}</span></div>` : ''}
|
|
671
|
+
</div>
|
|
672
|
+
</div>
|
|
673
|
+
`;
|
|
674
|
+
} else {
|
|
675
|
+
container.innerHTML = `
|
|
676
|
+
<div class="p-4 bg-destructive/10 border border-destructive/20 rounded-lg">
|
|
677
|
+
<div class="flex items-center gap-2 text-destructive mb-2">
|
|
678
|
+
<i data-lucide="x-circle" class="w-5 h-5"></i>
|
|
679
|
+
<span class="font-medium">${t('skills.invalidSkill')}</span>
|
|
680
|
+
</div>
|
|
681
|
+
<ul class="space-y-1 text-sm">
|
|
682
|
+
${result.errors.map(error => `<li class="text-destructive">• ${escapeHtml(error)}</li>`).join('')}
|
|
683
|
+
</ul>
|
|
684
|
+
</div>
|
|
685
|
+
`;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if (typeof lucide !== 'undefined') lucide.createIcons();
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
async function createSkill() {
|
|
692
|
+
if (skillCreateState.mode === 'import') {
|
|
693
|
+
// Import Mode Logic
|
|
694
|
+
const sourcePathInput = document.getElementById('skillSourcePath');
|
|
695
|
+
const customNameInput = document.getElementById('skillCustomName');
|
|
696
|
+
|
|
697
|
+
const sourcePath = sourcePathInput ? sourcePathInput.value.trim() : skillCreateState.sourcePath;
|
|
698
|
+
const customName = customNameInput ? customNameInput.value.trim() : skillCreateState.customName;
|
|
699
|
+
|
|
700
|
+
if (!sourcePath) {
|
|
701
|
+
if (window.showToast) {
|
|
702
|
+
showToast(t('skills.sourceFolderRequired'), 'error');
|
|
703
|
+
}
|
|
704
|
+
return;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
// Validate first if not already validated
|
|
708
|
+
if (!skillCreateState.validationResult || !skillCreateState.validationResult.valid) {
|
|
709
|
+
if (window.showToast) {
|
|
710
|
+
showToast(t('skills.validateFirst'), 'error');
|
|
711
|
+
}
|
|
712
|
+
return;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
try {
|
|
716
|
+
const response = await fetch('/api/skills/create', {
|
|
717
|
+
method: 'POST',
|
|
718
|
+
headers: { 'Content-Type': 'application/json' },
|
|
719
|
+
body: JSON.stringify({
|
|
720
|
+
mode: 'import',
|
|
721
|
+
location: skillCreateState.location,
|
|
722
|
+
sourcePath,
|
|
723
|
+
skillName: customName || undefined,
|
|
724
|
+
projectPath
|
|
725
|
+
})
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
if (!response.ok) {
|
|
729
|
+
const error = await response.json();
|
|
730
|
+
throw new Error(error.error || 'Failed to create skill');
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
const result = await response.json();
|
|
734
|
+
|
|
735
|
+
// Close modal
|
|
736
|
+
closeSkillCreateModal();
|
|
737
|
+
|
|
738
|
+
// Reload skills data
|
|
739
|
+
await loadSkillsData();
|
|
740
|
+
renderSkillsView();
|
|
741
|
+
|
|
742
|
+
// Show success message
|
|
743
|
+
if (window.showToast) {
|
|
744
|
+
showToast(t('skills.created', { name: result.skillName }), 'success');
|
|
745
|
+
}
|
|
746
|
+
} catch (err) {
|
|
747
|
+
console.error('Failed to create skill:', err);
|
|
748
|
+
if (window.showToast) {
|
|
749
|
+
showToast(err.message || t('skills.createError'), 'error');
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
} else if (skillCreateState.mode === 'cli-generate') {
|
|
753
|
+
// CLI Generate Mode Logic
|
|
754
|
+
const skillNameInput = document.getElementById('skillGenerateName');
|
|
755
|
+
const descriptionInput = document.getElementById('skillDescription');
|
|
756
|
+
|
|
757
|
+
const skillName = skillNameInput ? skillNameInput.value.trim() : skillCreateState.skillName;
|
|
758
|
+
const description = descriptionInput ? descriptionInput.value.trim() : skillCreateState.description;
|
|
759
|
+
|
|
760
|
+
// Validation
|
|
761
|
+
if (!skillName) {
|
|
762
|
+
if (window.showToast) {
|
|
763
|
+
showToast(t('skills.skillNameRequired'), 'error');
|
|
764
|
+
}
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
if (skillCreateState.generationType === 'description' && !description) {
|
|
769
|
+
if (window.showToast) {
|
|
770
|
+
showToast(t('skills.descriptionRequired'), 'error');
|
|
771
|
+
}
|
|
772
|
+
return;
|
|
773
|
+
}
|
|
774
|
+
|
|
775
|
+
try {
|
|
776
|
+
// Show generating progress toast
|
|
777
|
+
if (window.showToast) {
|
|
778
|
+
showToast(t('skills.generating'), 'info');
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
const response = await fetch('/api/skills/create', {
|
|
782
|
+
method: 'POST',
|
|
783
|
+
headers: { 'Content-Type': 'application/json' },
|
|
784
|
+
body: JSON.stringify({
|
|
785
|
+
mode: 'cli-generate',
|
|
786
|
+
location: skillCreateState.location,
|
|
787
|
+
generationType: skillCreateState.generationType,
|
|
788
|
+
skillName,
|
|
789
|
+
description: skillCreateState.generationType === 'description' ? description : undefined,
|
|
790
|
+
projectPath
|
|
791
|
+
})
|
|
792
|
+
});
|
|
793
|
+
|
|
794
|
+
if (!response.ok) {
|
|
795
|
+
const error = await response.json();
|
|
796
|
+
throw new Error(error.error || 'Failed to generate skill');
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
const result = await response.json();
|
|
800
|
+
|
|
801
|
+
// Close modal
|
|
802
|
+
closeSkillCreateModal();
|
|
803
|
+
|
|
804
|
+
// Reload skills data
|
|
805
|
+
await loadSkillsData();
|
|
806
|
+
renderSkillsView();
|
|
807
|
+
|
|
808
|
+
// Show success message
|
|
809
|
+
if (window.showToast) {
|
|
810
|
+
showToast(t('skills.generated', { name: result.skillName }), 'success');
|
|
811
|
+
}
|
|
812
|
+
} catch (err) {
|
|
813
|
+
console.error('Failed to generate skill:', err);
|
|
814
|
+
if (window.showToast) {
|
|
815
|
+
showToast(err.message || t('skills.generateError'), 'error');
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
}
|