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.
Files changed (437) hide show
  1. package/.claude/CLAUDE.md +10 -0
  2. package/.claude/agents/action-planning-agent.md +857 -778
  3. package/.claude/agents/cli-execution-agent.md +266 -269
  4. package/.claude/agents/cli-explore-agent.md +2 -2
  5. package/.claude/agents/cli-lite-planning-agent.md +142 -92
  6. package/.claude/agents/cli-planning-agent.md +4 -4
  7. package/.claude/agents/code-developer.md +7 -6
  8. package/.claude/agents/conceptual-planning-agent.md +2 -2
  9. package/.claude/agents/context-search-agent.md +31 -32
  10. package/.claude/agents/doc-generator.md +4 -4
  11. package/.claude/agents/memory-bridge.md +93 -93
  12. package/.claude/agents/test-context-search-agent.md +8 -7
  13. package/.claude/agents/test-fix-agent.md +7 -6
  14. package/.claude/commands/clean.md +516 -0
  15. package/.claude/commands/memory/compact.md +383 -0
  16. package/.claude/commands/memory/docs-full-cli.md +471 -471
  17. package/.claude/commands/memory/docs-related-cli.md +386 -386
  18. package/.claude/commands/memory/docs.md +615 -615
  19. package/.claude/commands/memory/load.md +5 -5
  20. package/.claude/commands/memory/tech-research-rules.md +310 -0
  21. package/.claude/commands/memory/update-full.md +332 -332
  22. package/.claude/commands/memory/workflow-skill-memory.md +4 -4
  23. package/.claude/commands/task/create.md +151 -151
  24. package/.claude/commands/version.md +254 -254
  25. package/.claude/commands/workflow/brainstorm/api-designer.md +587 -585
  26. package/.claude/commands/workflow/brainstorm/artifacts.md +1 -0
  27. package/.claude/commands/workflow/brainstorm/auto-parallel.md +443 -443
  28. package/.claude/commands/workflow/brainstorm/data-architect.md +220 -220
  29. package/.claude/commands/workflow/brainstorm/product-manager.md +200 -200
  30. package/.claude/commands/workflow/brainstorm/product-owner.md +200 -200
  31. package/.claude/commands/workflow/brainstorm/scrum-master.md +200 -200
  32. package/.claude/commands/workflow/brainstorm/subject-matter-expert.md +200 -200
  33. package/.claude/commands/workflow/brainstorm/system-architect.md +389 -387
  34. package/.claude/commands/workflow/brainstorm/ui-designer.md +221 -221
  35. package/.claude/commands/workflow/brainstorm/ux-expert.md +221 -221
  36. package/.claude/commands/workflow/debug.md +321 -0
  37. package/.claude/commands/workflow/execute.md +13 -0
  38. package/.claude/commands/workflow/init.md +165 -164
  39. package/.claude/commands/workflow/lite-execute.md +119 -13
  40. package/.claude/commands/workflow/lite-fix.md +623 -621
  41. package/.claude/commands/workflow/lite-plan.md +610 -592
  42. package/.claude/commands/workflow/plan.md +5 -5
  43. package/.claude/commands/workflow/review-module-cycle.md +2 -0
  44. package/.claude/commands/workflow/review-session-cycle.md +2 -0
  45. package/.claude/commands/workflow/review.md +297 -291
  46. package/.claude/commands/workflow/session/complete.md +153 -500
  47. package/.claude/commands/workflow/session/list.md +95 -95
  48. package/.claude/commands/workflow/session/resume.md +60 -60
  49. package/.claude/commands/workflow/session/start.md +199 -199
  50. package/.claude/commands/workflow/tdd-plan.md +3 -3
  51. package/.claude/commands/workflow/tdd-verify.md +23 -9
  52. package/.claude/commands/workflow/test-cycle-execute.md +2 -0
  53. package/.claude/commands/workflow/test-fix-gen.md +699 -699
  54. package/.claude/commands/workflow/tools/conflict-resolution.md +104 -18
  55. package/.claude/commands/workflow/tools/context-gather.md +436 -434
  56. package/.claude/commands/workflow/tools/task-generate-agent.md +490 -291
  57. package/.claude/commands/workflow/tools/task-generate-tdd.md +18 -10
  58. package/.claude/commands/workflow/tools/test-concept-enhanced.md +2 -1
  59. package/.claude/commands/workflow/tools/test-context-gather.md +1 -0
  60. package/.claude/commands/workflow/tools/test-task-generate.md +1 -0
  61. package/.claude/commands/workflow/ui-design/import-from-code.md +9 -6
  62. package/.claude/skills/command-guide/SKILL.md +5 -5
  63. package/.claude/skills/command-guide/index/all-commands.json +1 -1
  64. package/.claude/skills/command-guide/index/by-category.json +1 -1
  65. package/.claude/skills/command-guide/index/by-use-case.json +1 -1
  66. package/.claude/skills/command-guide/reference/agents/action-planning-agent.md +857 -778
  67. package/.claude/skills/command-guide/reference/agents/cli-execution-agent.md +266 -269
  68. package/.claude/skills/command-guide/reference/agents/cli-explore-agent.md +2 -2
  69. package/.claude/skills/command-guide/reference/agents/cli-lite-planning-agent.md +142 -92
  70. package/.claude/skills/command-guide/reference/agents/cli-planning-agent.md +4 -4
  71. package/.claude/skills/command-guide/reference/agents/code-developer.md +7 -6
  72. package/.claude/skills/command-guide/reference/agents/conceptual-planning-agent.md +2 -2
  73. package/.claude/skills/command-guide/reference/agents/context-search-agent.md +31 -32
  74. package/.claude/skills/command-guide/reference/agents/doc-generator.md +4 -4
  75. package/.claude/skills/command-guide/reference/agents/memory-bridge.md +93 -93
  76. package/.claude/skills/command-guide/reference/agents/test-context-search-agent.md +8 -7
  77. package/.claude/skills/command-guide/reference/agents/test-fix-agent.md +7 -6
  78. package/.claude/skills/command-guide/reference/commands/memory/docs-full-cli.md +471 -471
  79. package/.claude/skills/command-guide/reference/commands/memory/docs-related-cli.md +386 -386
  80. package/.claude/skills/command-guide/reference/commands/memory/docs.md +17 -16
  81. package/.claude/skills/command-guide/reference/commands/memory/load.md +5 -5
  82. package/.claude/skills/command-guide/reference/commands/memory/tech-research.md +194 -357
  83. package/.claude/skills/command-guide/reference/commands/memory/update-full.md +332 -332
  84. package/.claude/skills/command-guide/reference/commands/memory/workflow-skill-memory.md +4 -4
  85. package/.claude/skills/command-guide/reference/commands/task/create.md +151 -151
  86. package/.claude/skills/command-guide/reference/commands/version.md +254 -254
  87. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/api-designer.md +585 -585
  88. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/auto-parallel.md +443 -443
  89. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/data-architect.md +220 -220
  90. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-manager.md +200 -200
  91. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/product-owner.md +200 -200
  92. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/scrum-master.md +200 -200
  93. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/subject-matter-expert.md +200 -200
  94. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/system-architect.md +387 -387
  95. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ui-designer.md +221 -221
  96. package/.claude/skills/command-guide/reference/commands/workflow/brainstorm/ux-expert.md +221 -221
  97. package/.claude/skills/command-guide/reference/commands/workflow/execute.md +25 -20
  98. package/.claude/skills/command-guide/reference/commands/workflow/init.md +164 -164
  99. package/.claude/skills/command-guide/reference/commands/workflow/lite-execute.md +748 -686
  100. package/.claude/skills/command-guide/reference/commands/workflow/lite-fix.md +664 -621
  101. package/.claude/skills/command-guide/reference/commands/workflow/lite-plan.md +645 -592
  102. package/.claude/skills/command-guide/reference/commands/workflow/plan.md +5 -5
  103. package/.claude/skills/command-guide/reference/commands/workflow/review.md +25 -18
  104. package/.claude/skills/command-guide/reference/commands/workflow/session/complete.md +547 -500
  105. package/.claude/skills/command-guide/reference/commands/workflow/session/list.md +45 -27
  106. package/.claude/skills/command-guide/reference/commands/workflow/session/resume.md +35 -19
  107. package/.claude/skills/command-guide/reference/commands/workflow/session/start.md +90 -33
  108. package/.claude/skills/command-guide/reference/commands/workflow/tdd-plan.md +3 -3
  109. package/.claude/skills/command-guide/reference/commands/workflow/tdd-verify.md +23 -9
  110. package/.claude/skills/command-guide/reference/commands/workflow/test-fix-gen.md +699 -699
  111. package/.claude/skills/command-guide/reference/commands/workflow/tools/conflict-resolution.md +103 -17
  112. package/.claude/skills/command-guide/reference/commands/workflow/tools/context-gather.md +434 -434
  113. package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-agent.md +487 -291
  114. package/.claude/skills/command-guide/reference/commands/workflow/tools/task-generate-tdd.md +17 -10
  115. package/.claude/skills/command-guide/reference/commands/workflow/tools/test-concept-enhanced.md +1 -1
  116. package/.claude/skills/command-guide/reference/commands/workflow/ui-design/import-from-code.md +6 -6
  117. package/.claude/workflows/chinese-response.md +38 -0
  118. package/.claude/workflows/cli-templates/prompts/rules/rule-api.txt +122 -0
  119. package/.claude/workflows/cli-templates/prompts/rules/rule-components.txt +122 -0
  120. package/.claude/workflows/cli-templates/prompts/rules/rule-config.txt +89 -0
  121. package/.claude/workflows/cli-templates/prompts/rules/rule-core.txt +60 -0
  122. package/.claude/workflows/cli-templates/prompts/rules/rule-patterns.txt +70 -0
  123. package/.claude/workflows/cli-templates/prompts/rules/rule-testing.txt +81 -0
  124. package/.claude/workflows/cli-templates/prompts/rules/tech-rules-agent-prompt.txt +89 -0
  125. package/.claude/workflows/cli-templates/prompts/workflow/gemini-solution-design.txt +131 -131
  126. package/.claude/workflows/cli-templates/prompts/workflow/skill-conflict-patterns.txt +5 -9
  127. package/.claude/workflows/cli-templates/prompts/workflow/skill-lessons-learned.txt +5 -9
  128. package/.claude/workflows/cli-templates/protocols/analysis-protocol.md +112 -0
  129. package/.claude/workflows/cli-templates/protocols/write-protocol.md +201 -0
  130. package/.claude/workflows/cli-templates/schemas/conflict-resolution-schema.json +137 -0
  131. package/.claude/workflows/cli-templates/schemas/debug-log-json-schema.json +127 -0
  132. package/.claude/workflows/cli-templates/schemas/fix-plan-json-schema.json +25 -0
  133. package/.claude/workflows/cli-templates/schemas/plan-json-schema.json +25 -0
  134. package/.claude/workflows/cli-tools-usage.md +526 -0
  135. package/{CLAUDE.md → .claude/workflows/coding-philosophy.md} +24 -45
  136. package/.claude/workflows/context-tools.md +84 -0
  137. package/.claude/workflows/file-modification.md +64 -0
  138. package/.claude/workflows/tool-strategy.md +216 -79
  139. package/.claude/workflows/windows-platform.md +16 -0
  140. package/.claude/workflows/workflow-architecture.md +942 -942
  141. package/.codex/AGENTS.md +63 -330
  142. package/.codex/prompts/debug.md +318 -0
  143. package/.codex/prompts/execute.md +273 -0
  144. package/.codex/prompts/lite-execute.md +164 -0
  145. package/.codex/prompts/lite-plan.md +469 -0
  146. package/.codex/prompts.zip +0 -0
  147. package/.gemini/GEMINI.md +25 -164
  148. package/.qwen/QWEN.md +0 -139
  149. package/README.md +29 -9
  150. package/ccw/README.md +30 -6
  151. package/ccw/bin/ccw-mcp.js +7 -0
  152. package/ccw/bin/ccw.js +9 -9
  153. package/ccw/package.json +65 -47
  154. package/ccw/src/.workflow/.cli-history/history.db +0 -0
  155. package/ccw/src/.workflow/.cli-history/history.db-shm +0 -0
  156. package/ccw/src/.workflow/.cli-history/history.db-wal +0 -0
  157. package/ccw/src/cli.ts +244 -0
  158. package/ccw/src/commands/cli.ts +740 -0
  159. package/ccw/src/commands/core-memory.ts +770 -0
  160. package/ccw/src/commands/hook.ts +315 -0
  161. package/ccw/src/commands/install.ts +519 -0
  162. package/ccw/src/commands/{list.js → list.ts} +1 -1
  163. package/ccw/src/commands/memory.ts +1090 -0
  164. package/ccw/src/commands/{serve.js → serve.ts} +14 -5
  165. package/ccw/src/commands/session-path-resolver.ts +372 -0
  166. package/ccw/src/commands/session.ts +1141 -0
  167. package/ccw/src/commands/{stop.js → stop.ts} +16 -6
  168. package/ccw/src/commands/tool.ts +201 -0
  169. package/ccw/src/commands/{uninstall.js → uninstall.ts} +89 -40
  170. package/ccw/src/commands/{upgrade.js → upgrade.ts} +68 -23
  171. package/ccw/src/commands/{view.js → view.ts} +22 -8
  172. package/ccw/src/config/storage-paths.ts +670 -0
  173. package/ccw/src/core/cache-manager.ts +294 -0
  174. package/ccw/src/core/claude-freshness.ts +319 -0
  175. package/ccw/src/core/core-memory-store.ts +1528 -0
  176. package/ccw/src/core/{dashboard-generator-patch.js → dashboard-generator-patch.ts} +18 -0
  177. package/ccw/src/core/{dashboard-generator.js → dashboard-generator.ts} +69 -12
  178. package/ccw/src/core/data-aggregator.ts +584 -0
  179. package/ccw/src/core/history-importer.ts +625 -0
  180. package/ccw/src/core/{lite-scanner.js → lite-scanner-complete.ts} +162 -66
  181. package/ccw/src/core/lite-scanner.ts +469 -0
  182. package/ccw/src/core/{manifest.js → manifest.ts} +104 -34
  183. package/ccw/src/core/memory-embedder-bridge.ts +262 -0
  184. package/ccw/src/core/memory-store.ts +978 -0
  185. package/ccw/src/core/routes/ccw-routes.ts +96 -0
  186. package/ccw/src/core/routes/claude-routes.ts +1183 -0
  187. package/ccw/src/core/routes/cli-routes.ts +561 -0
  188. package/ccw/src/core/routes/codexlens-routes.ts +806 -0
  189. package/ccw/src/core/routes/core-memory-routes.ts +605 -0
  190. package/ccw/src/core/routes/files-routes.ts +428 -0
  191. package/ccw/src/core/routes/graph-routes.md +164 -0
  192. package/ccw/src/core/routes/graph-routes.ts +626 -0
  193. package/ccw/src/core/routes/help-routes.ts +308 -0
  194. package/ccw/src/core/routes/hooks-routes.ts +405 -0
  195. package/ccw/src/core/routes/mcp-routes.ts +1271 -0
  196. package/ccw/src/core/routes/mcp-routes.ts.backup +550 -0
  197. package/ccw/src/core/routes/mcp-templates-db.ts +268 -0
  198. package/ccw/src/core/routes/memory-routes.ts +1206 -0
  199. package/ccw/src/core/routes/rules-routes.ts +526 -0
  200. package/ccw/src/core/routes/session-routes.ts +467 -0
  201. package/ccw/src/core/routes/skills-routes.ts +599 -0
  202. package/ccw/src/core/routes/status-routes.ts +57 -0
  203. package/ccw/src/core/routes/system-routes.ts +427 -0
  204. package/ccw/src/core/server.ts +431 -0
  205. package/ccw/src/core/session-clustering-service.ts +1258 -0
  206. package/ccw/src/core/session-scanner.ts +283 -0
  207. package/ccw/src/core/websocket.ts +190 -0
  208. package/ccw/src/{index.js → index.ts} +1 -0
  209. package/ccw/src/mcp-server/index.ts +186 -0
  210. package/ccw/src/templates/assets/css/github-dark.min.css +10 -0
  211. package/ccw/src/templates/assets/css/github.min.css +10 -0
  212. package/ccw/src/templates/assets/js/cytoscape.min.js +32 -0
  213. package/ccw/src/templates/assets/js/d3.min.js +2 -0
  214. package/ccw/src/templates/assets/js/highlight.min.js +1244 -0
  215. package/ccw/src/templates/assets/js/lucide.min.js +12 -0
  216. package/ccw/src/templates/assets/js/marked.min.js +69 -0
  217. package/ccw/src/templates/assets/js/tailwind.js +83 -0
  218. package/ccw/src/templates/dashboard-css/01-base.css +11 -0
  219. package/ccw/src/templates/dashboard-css/02-session.css +22 -0
  220. package/ccw/src/templates/dashboard-css/04-lite-tasks.css +10 -0
  221. package/ccw/src/templates/dashboard-css/06-cards.css +10 -4
  222. package/ccw/src/templates/dashboard-css/07-managers.css +1178 -7
  223. package/ccw/src/templates/dashboard-css/09-explorer.css +23 -12
  224. package/ccw/src/templates/dashboard-css/10-cli-status.css +337 -0
  225. package/ccw/src/templates/dashboard-css/11-cli-history.css +271 -0
  226. package/ccw/src/templates/dashboard-css/12-cli-legacy.css +796 -0
  227. package/ccw/src/templates/dashboard-css/13-cli-ccw.css +199 -0
  228. package/ccw/src/templates/dashboard-css/14-cli-modals.css +258 -0
  229. package/ccw/src/templates/dashboard-css/15-cli-endpoints.css +305 -0
  230. package/ccw/src/templates/dashboard-css/16-cli-session.css +241 -0
  231. package/ccw/src/templates/dashboard-css/17-cli-conversation.css +283 -0
  232. package/ccw/src/templates/dashboard-css/18-cli-settings.css +160 -0
  233. package/ccw/src/templates/dashboard-css/19-cli-native-session.css +496 -0
  234. package/ccw/src/templates/dashboard-css/20-cli-taskqueue.css +188 -0
  235. package/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css +310 -0
  236. package/ccw/src/templates/dashboard-css/22-cli-semantic.css +240 -0
  237. package/ccw/src/templates/dashboard-css/23-memory.css +2390 -0
  238. package/ccw/src/templates/dashboard-css/24-prompt-history.css +1089 -0
  239. package/ccw/src/templates/dashboard-css/25-skills-rules.css +326 -0
  240. package/ccw/src/templates/dashboard-css/26-claude-manager.css +908 -0
  241. package/ccw/src/templates/dashboard-css/27-graph-explorer.css +1678 -0
  242. package/ccw/src/templates/dashboard-css/28-mcp-manager.css +748 -0
  243. package/ccw/src/templates/dashboard-css/29-help.css +264 -0
  244. package/ccw/src/templates/dashboard-css/30-core-memory.css +1700 -0
  245. package/ccw/src/templates/dashboard-js/api.js +162 -142
  246. package/ccw/src/templates/dashboard-js/components/carousel.js +4 -4
  247. package/ccw/src/templates/dashboard-js/components/cli-history.js +876 -0
  248. package/ccw/src/templates/dashboard-js/components/cli-status.js +978 -0
  249. package/ccw/src/templates/dashboard-js/components/global-notifications.js +508 -219
  250. package/ccw/src/templates/dashboard-js/components/hook-manager.js +1277 -282
  251. package/ccw/src/templates/dashboard-js/components/index-manager.js +302 -0
  252. package/ccw/src/templates/dashboard-js/components/mcp-manager.js +718 -27
  253. package/ccw/src/templates/dashboard-js/components/modals.js +66 -0
  254. package/ccw/src/templates/dashboard-js/components/navigation.js +80 -12
  255. package/ccw/src/templates/dashboard-js/components/notifications.js +758 -194
  256. package/ccw/src/templates/dashboard-js/components/storage-manager.js +478 -0
  257. package/ccw/src/templates/dashboard-js/components/tabs-other.js +157 -6
  258. package/ccw/src/templates/dashboard-js/components/task-queue-sidebar.js +716 -0
  259. package/ccw/src/templates/dashboard-js/help-i18n.js +272 -0
  260. package/ccw/src/templates/dashboard-js/i18n.js +2807 -0
  261. package/ccw/src/templates/dashboard-js/main.js +15 -0
  262. package/ccw/src/templates/dashboard-js/state.js +243 -42
  263. package/ccw/src/templates/dashboard-js/utils.js +47 -1
  264. package/ccw/src/templates/dashboard-js/views/claude-manager.js +912 -0
  265. package/ccw/src/templates/dashboard-js/views/cli-manager.js +2272 -0
  266. package/ccw/src/templates/dashboard-js/views/codexlens-manager.js +964 -0
  267. package/ccw/src/templates/dashboard-js/views/core-memory-clusters.js +503 -0
  268. package/ccw/src/templates/dashboard-js/views/core-memory.js +782 -0
  269. package/ccw/src/templates/dashboard-js/views/explorer.js +888 -852
  270. package/ccw/src/templates/dashboard-js/views/graph-explorer.js +1157 -0
  271. package/ccw/src/templates/dashboard-js/views/help.js +856 -0
  272. package/ccw/src/templates/dashboard-js/views/history.js +337 -0
  273. package/ccw/src/templates/dashboard-js/views/home.js +61 -15
  274. package/ccw/src/templates/dashboard-js/views/hook-manager.js +311 -43
  275. package/ccw/src/templates/dashboard-js/views/lite-tasks.js +204 -28
  276. package/ccw/src/templates/dashboard-js/views/mcp-manager.js +2187 -411
  277. package/ccw/src/templates/dashboard-js/views/mcp-manager.js.backup +1729 -0
  278. package/ccw/src/templates/dashboard-js/views/mcp-manager.js.new +928 -0
  279. package/ccw/src/templates/dashboard-js/views/memory.js +1221 -0
  280. package/ccw/src/templates/dashboard-js/views/prompt-history.js +713 -0
  281. package/ccw/src/templates/dashboard-js/views/rules-manager.js +828 -0
  282. package/ccw/src/templates/dashboard-js/views/session-detail.js +54 -53
  283. package/ccw/src/templates/dashboard-js/views/skills-manager.js +819 -0
  284. package/ccw/src/templates/dashboard.html +185 -85
  285. package/ccw/src/templates/hooks-config-example.json +60 -0
  286. package/ccw/src/tools/classify-folders.ts +245 -0
  287. package/ccw/src/tools/cli-config-manager.ts +268 -0
  288. package/ccw/src/tools/cli-executor.ts +2014 -0
  289. package/ccw/src/tools/cli-history-store.ts +1195 -0
  290. package/ccw/src/tools/codex-lens.ts +1141 -0
  291. package/ccw/src/tools/{convert-tokens-to-css.js → convert-tokens-to-css.ts} +73 -23
  292. package/ccw/src/tools/core-memory.ts +444 -0
  293. package/ccw/src/tools/detect-changed-modules.ts +325 -0
  294. package/ccw/src/tools/{discover-design-files.js → discover-design-files.ts} +74 -24
  295. package/ccw/src/tools/edit-file.ts +568 -0
  296. package/ccw/src/tools/{generate-module-docs.js → generate-module-docs.ts} +207 -185
  297. package/ccw/src/tools/{get-modules-by-depth.js → get-modules-by-depth.ts} +120 -79
  298. package/ccw/src/tools/index.ts +370 -0
  299. package/ccw/src/tools/native-session-discovery.ts +795 -0
  300. package/ccw/src/tools/notifier.ts +129 -0
  301. package/ccw/src/tools/read-file.ts +410 -0
  302. package/ccw/src/tools/resume-strategy.ts +345 -0
  303. package/ccw/src/tools/session-content-parser.ts +619 -0
  304. package/ccw/src/tools/session-manager.ts +1026 -0
  305. package/ccw/src/tools/smart-context.ts +228 -0
  306. package/ccw/src/tools/smart-search.ts +2065 -0
  307. package/ccw/src/tools/smart-search.ts.backup +1233 -0
  308. package/ccw/src/tools/storage-manager.ts +455 -0
  309. package/ccw/src/tools/write-file.ts +222 -0
  310. package/ccw/src/types/config.ts +11 -0
  311. package/ccw/src/types/index.ts +3 -0
  312. package/ccw/src/types/session.ts +25 -0
  313. package/ccw/src/types/tool.ts +41 -0
  314. package/ccw/src/utils/{browser-launcher.js → browser-launcher.ts} +10 -8
  315. package/ccw/src/utils/file-utils.ts +48 -0
  316. package/ccw/src/utils/{path-resolver.js → path-resolver.ts} +114 -78
  317. package/ccw/src/utils/path-validator.ts +153 -0
  318. package/ccw/src/utils/{ui.js → ui.ts} +32 -25
  319. package/codex-lens/pyproject.toml +48 -0
  320. package/codex-lens/src/codexlens/.workflow/.cli-history/history.db +0 -0
  321. package/codex-lens/src/codexlens/__init__.py +28 -0
  322. package/codex-lens/src/codexlens/__main__.py +14 -0
  323. package/codex-lens/src/codexlens/__pycache__/__init__.cpython-313.pyc +0 -0
  324. package/codex-lens/src/codexlens/__pycache__/__main__.cpython-313.pyc +0 -0
  325. package/codex-lens/src/codexlens/__pycache__/config.cpython-313.pyc +0 -0
  326. package/codex-lens/src/codexlens/__pycache__/entities.cpython-313.pyc +0 -0
  327. package/codex-lens/src/codexlens/__pycache__/errors.cpython-313.pyc +0 -0
  328. package/codex-lens/src/codexlens/cli/__init__.py +27 -0
  329. package/codex-lens/src/codexlens/cli/__pycache__/__init__.cpython-313.pyc +0 -0
  330. package/codex-lens/src/codexlens/cli/__pycache__/commands.cpython-313.pyc +0 -0
  331. package/codex-lens/src/codexlens/cli/__pycache__/embedding_manager.cpython-313.pyc +0 -0
  332. package/codex-lens/src/codexlens/cli/__pycache__/model_manager.cpython-313.pyc +0 -0
  333. package/codex-lens/src/codexlens/cli/__pycache__/output.cpython-313.pyc +0 -0
  334. package/codex-lens/src/codexlens/cli/commands.py +1931 -0
  335. package/codex-lens/src/codexlens/cli/embedding_manager.py +620 -0
  336. package/codex-lens/src/codexlens/cli/model_manager.py +289 -0
  337. package/codex-lens/src/codexlens/cli/output.py +124 -0
  338. package/codex-lens/src/codexlens/config.py +201 -0
  339. package/codex-lens/src/codexlens/entities.py +121 -0
  340. package/codex-lens/src/codexlens/errors.py +55 -0
  341. package/codex-lens/src/codexlens/indexing/README.md +77 -0
  342. package/codex-lens/src/codexlens/indexing/__init__.py +4 -0
  343. package/codex-lens/src/codexlens/indexing/__pycache__/__init__.cpython-313.pyc +0 -0
  344. package/codex-lens/src/codexlens/indexing/__pycache__/symbol_extractor.cpython-313.pyc +0 -0
  345. package/codex-lens/src/codexlens/indexing/symbol_extractor.py +243 -0
  346. package/codex-lens/src/codexlens/parsers/__init__.py +8 -0
  347. package/codex-lens/src/codexlens/parsers/__pycache__/__init__.cpython-313.pyc +0 -0
  348. package/codex-lens/src/codexlens/parsers/__pycache__/encoding.cpython-313.pyc +0 -0
  349. package/codex-lens/src/codexlens/parsers/__pycache__/factory.cpython-313.pyc +0 -0
  350. package/codex-lens/src/codexlens/parsers/__pycache__/tokenizer.cpython-313.pyc +0 -0
  351. package/codex-lens/src/codexlens/parsers/__pycache__/treesitter_parser.cpython-313.pyc +0 -0
  352. package/codex-lens/src/codexlens/parsers/encoding.py +202 -0
  353. package/codex-lens/src/codexlens/parsers/factory.py +256 -0
  354. package/codex-lens/src/codexlens/parsers/tokenizer.py +98 -0
  355. package/codex-lens/src/codexlens/parsers/treesitter_parser.py +335 -0
  356. package/codex-lens/src/codexlens/search/__init__.py +15 -0
  357. package/codex-lens/src/codexlens/search/__pycache__/__init__.cpython-313.pyc +0 -0
  358. package/codex-lens/src/codexlens/search/__pycache__/chain_search.cpython-313.pyc +0 -0
  359. package/codex-lens/src/codexlens/search/__pycache__/enrichment.cpython-313.pyc +0 -0
  360. package/codex-lens/src/codexlens/search/__pycache__/hybrid_search.cpython-313.pyc +0 -0
  361. package/codex-lens/src/codexlens/search/__pycache__/query_parser.cpython-313.pyc +0 -0
  362. package/codex-lens/src/codexlens/search/__pycache__/ranking.cpython-313.pyc +0 -0
  363. package/codex-lens/src/codexlens/search/chain_search.py +647 -0
  364. package/codex-lens/src/codexlens/search/enrichment.py +150 -0
  365. package/codex-lens/src/codexlens/search/hybrid_search.py +313 -0
  366. package/codex-lens/src/codexlens/search/query_parser.py +242 -0
  367. package/codex-lens/src/codexlens/search/ranking.py +274 -0
  368. package/codex-lens/src/codexlens/semantic/__init__.py +39 -0
  369. package/codex-lens/src/codexlens/semantic/__pycache__/__init__.cpython-313.pyc +0 -0
  370. package/codex-lens/src/codexlens/semantic/__pycache__/ann_index.cpython-313.pyc +0 -0
  371. package/codex-lens/src/codexlens/semantic/__pycache__/chunker.cpython-313.pyc +0 -0
  372. package/codex-lens/src/codexlens/semantic/__pycache__/code_extractor.cpython-313.pyc +0 -0
  373. package/codex-lens/src/codexlens/semantic/__pycache__/embedder.cpython-313.pyc +0 -0
  374. package/codex-lens/src/codexlens/semantic/__pycache__/graph_analyzer.cpython-313.pyc +0 -0
  375. package/codex-lens/src/codexlens/semantic/__pycache__/llm_enhancer.cpython-313.pyc +0 -0
  376. package/codex-lens/src/codexlens/semantic/__pycache__/vector_store.cpython-313.pyc +0 -0
  377. package/codex-lens/src/codexlens/semantic/ann_index.py +414 -0
  378. package/codex-lens/src/codexlens/semantic/chunker.py +448 -0
  379. package/codex-lens/src/codexlens/semantic/code_extractor.py +274 -0
  380. package/codex-lens/src/codexlens/semantic/embedder.py +185 -0
  381. package/codex-lens/src/codexlens/semantic/vector_store.py +955 -0
  382. package/codex-lens/src/codexlens/storage/__init__.py +29 -0
  383. package/codex-lens/src/codexlens/storage/__pycache__/__init__.cpython-313.pyc +0 -0
  384. package/codex-lens/src/codexlens/storage/__pycache__/dir_index.cpython-313.pyc +0 -0
  385. package/codex-lens/src/codexlens/storage/__pycache__/file_cache.cpython-313.pyc +0 -0
  386. package/codex-lens/src/codexlens/storage/__pycache__/index_tree.cpython-313.pyc +0 -0
  387. package/codex-lens/src/codexlens/storage/__pycache__/migration_manager.cpython-313.pyc +0 -0
  388. package/codex-lens/src/codexlens/storage/__pycache__/path_mapper.cpython-313.pyc +0 -0
  389. package/codex-lens/src/codexlens/storage/__pycache__/registry.cpython-313.pyc +0 -0
  390. package/codex-lens/src/codexlens/storage/__pycache__/sqlite_store.cpython-313.pyc +0 -0
  391. package/codex-lens/src/codexlens/storage/__pycache__/sqlite_utils.cpython-313.pyc +0 -0
  392. package/codex-lens/src/codexlens/storage/dir_index.py +1850 -0
  393. package/codex-lens/src/codexlens/storage/file_cache.py +32 -0
  394. package/codex-lens/src/codexlens/storage/index_tree.py +776 -0
  395. package/codex-lens/src/codexlens/storage/migration_manager.py +154 -0
  396. package/codex-lens/src/codexlens/storage/migrations/__init__.py +1 -0
  397. package/codex-lens/src/codexlens/storage/migrations/__pycache__/__init__.cpython-313.pyc +0 -0
  398. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_001_normalize_keywords.cpython-313.pyc +0 -0
  399. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_002_add_token_metadata.cpython-313.pyc +0 -0
  400. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_003_code_relationships.cpython-313.pyc +0 -0
  401. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_004_dual_fts.cpython-313.pyc +0 -0
  402. package/codex-lens/src/codexlens/storage/migrations/__pycache__/migration_005_cleanup_unused_fields.cpython-313.pyc +0 -0
  403. package/codex-lens/src/codexlens/storage/migrations/migration_001_normalize_keywords.py +123 -0
  404. package/codex-lens/src/codexlens/storage/migrations/migration_002_add_token_metadata.py +48 -0
  405. package/codex-lens/src/codexlens/storage/migrations/migration_004_dual_fts.py +232 -0
  406. package/codex-lens/src/codexlens/storage/migrations/migration_005_cleanup_unused_fields.py +196 -0
  407. package/codex-lens/src/codexlens/storage/path_mapper.py +274 -0
  408. package/codex-lens/src/codexlens/storage/registry.py +670 -0
  409. package/codex-lens/src/codexlens/storage/sqlite_store.py +576 -0
  410. package/codex-lens/src/codexlens/storage/sqlite_utils.py +64 -0
  411. package/package.json +4 -1
  412. package/.claude/commands/memory/tech-research.md +0 -477
  413. package/.claude/scripts/classify-folders.sh +0 -39
  414. package/.claude/scripts/convert_tokens_to_css.sh +0 -229
  415. package/.claude/scripts/detect_changed_modules.sh +0 -161
  416. package/.claude/scripts/discover-design-files.sh +0 -87
  417. package/.claude/scripts/extract-animations.js +0 -243
  418. package/.claude/scripts/extract-computed-styles.js +0 -118
  419. package/.claude/scripts/extract-layout-structure.js +0 -411
  420. package/.claude/scripts/generate_module_docs.sh +0 -717
  421. package/.claude/scripts/get_modules_by_depth.sh +0 -170
  422. package/.claude/scripts/ui-generate-preview.sh +0 -395
  423. package/.claude/scripts/ui-instantiate-prototypes.sh +0 -815
  424. package/.claude/scripts/update_module_claude.sh +0 -337
  425. package/.claude/workflows/context-search-strategy.md +0 -77
  426. package/.claude/workflows/intelligent-tools-strategy.md +0 -662
  427. package/ccw/src/cli.js +0 -119
  428. package/ccw/src/commands/install.js +0 -324
  429. package/ccw/src/commands/tool.js +0 -138
  430. package/ccw/src/core/data-aggregator.js +0 -409
  431. package/ccw/src/core/server.js +0 -2063
  432. package/ccw/src/core/session-scanner.js +0 -235
  433. package/ccw/src/tools/classify-folders.js +0 -204
  434. package/ccw/src/tools/detect-changed-modules.js +0 -288
  435. package/ccw/src/tools/edit-file.js +0 -266
  436. package/ccw/src/tools/index.js +0 -176
  437. 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()">&times;</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()">&times;</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
+ }