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,828 @@
1
+ // Rules Manager View
2
+ // Manages Claude Code rules (.claude/rules/)
3
+
4
+ // ========== Rules State ==========
5
+ var rulesData = {
6
+ projectRules: [],
7
+ userRules: []
8
+ };
9
+ var selectedRule = null;
10
+ var rulesLoading = false;
11
+
12
+ // ========== Main Render Function ==========
13
+ async function renderRulesManager() {
14
+ const container = document.getElementById('mainContent');
15
+ if (!container) return;
16
+
17
+ // Hide stats grid and search
18
+ const statsGrid = document.getElementById('statsGrid');
19
+ const searchInput = document.getElementById('searchInput');
20
+ if (statsGrid) statsGrid.style.display = 'none';
21
+ if (searchInput) searchInput.parentElement.style.display = 'none';
22
+
23
+ // Show loading state
24
+ container.innerHTML = '<div class="rules-manager loading">' +
25
+ '<div class="loading-spinner"><i data-lucide="loader-2" class="w-8 h-8 animate-spin"></i></div>' +
26
+ '<p>' + t('common.loading') + '</p>' +
27
+ '</div>';
28
+
29
+ // Load rules data
30
+ await loadRulesData();
31
+
32
+ // Render the main view
33
+ renderRulesView();
34
+ }
35
+
36
+ async function loadRulesData() {
37
+ rulesLoading = true;
38
+ try {
39
+ const response = await fetch('/api/rules?path=' + encodeURIComponent(projectPath));
40
+ if (!response.ok) throw new Error('Failed to load rules');
41
+ const data = await response.json();
42
+ rulesData = {
43
+ projectRules: data.projectRules || [],
44
+ userRules: data.userRules || []
45
+ };
46
+ // Update badge
47
+ updateRulesBadge();
48
+ } catch (err) {
49
+ console.error('Failed to load rules:', err);
50
+ rulesData = { projectRules: [], userRules: [] };
51
+ } finally {
52
+ rulesLoading = false;
53
+ }
54
+ }
55
+
56
+ function updateRulesBadge() {
57
+ const badge = document.getElementById('badgeRules');
58
+ if (badge) {
59
+ const total = rulesData.projectRules.length + rulesData.userRules.length;
60
+ badge.textContent = total;
61
+ }
62
+ }
63
+
64
+ function renderRulesView() {
65
+ const container = document.getElementById('mainContent');
66
+ if (!container) return;
67
+
68
+ const projectRules = rulesData.projectRules || [];
69
+ const userRules = rulesData.userRules || [];
70
+
71
+ container.innerHTML = `
72
+ <div class="rules-manager">
73
+ <!-- Header -->
74
+ <div class="rules-header mb-6">
75
+ <div class="flex items-center justify-between">
76
+ <div class="flex items-center gap-3">
77
+ <div class="w-10 h-10 bg-success/10 rounded-lg flex items-center justify-center">
78
+ <i data-lucide="book-open" class="w-5 h-5 text-success"></i>
79
+ </div>
80
+ <div>
81
+ <h2 class="text-lg font-semibold text-foreground">${t('rules.title')}</h2>
82
+ <p class="text-sm text-muted-foreground">${t('rules.description')}</p>
83
+ </div>
84
+ </div>
85
+ <button class="px-4 py-2 text-sm bg-primary text-primary-foreground rounded-lg hover:opacity-90 transition-opacity flex items-center gap-2"
86
+ onclick="openRuleCreateModal()">
87
+ <i data-lucide="plus" class="w-4 h-4"></i>
88
+ ${t('rules.create')}
89
+ </button>
90
+ </div>
91
+ </div>
92
+
93
+ <!-- Project Rules Section -->
94
+ <div class="rules-section mb-6">
95
+ <div class="flex items-center justify-between mb-4">
96
+ <div class="flex items-center gap-2">
97
+ <i data-lucide="folder" class="w-5 h-5 text-success"></i>
98
+ <h3 class="text-lg font-semibold text-foreground">${t('rules.projectRules')}</h3>
99
+ <span class="text-xs px-2 py-0.5 bg-success/10 text-success rounded-full">.claude/rules/</span>
100
+ </div>
101
+ <span class="text-sm text-muted-foreground">${projectRules.length} ${t('rules.rulesCount')}</span>
102
+ </div>
103
+
104
+ ${projectRules.length === 0 ? `
105
+ <div class="rules-empty-state bg-card border border-border rounded-lg p-6 text-center">
106
+ <div class="text-muted-foreground mb-3"><i data-lucide="book-open" class="w-10 h-10 mx-auto"></i></div>
107
+ <p class="text-muted-foreground">${t('rules.noProjectRules')}</p>
108
+ <p class="text-sm text-muted-foreground mt-1">${t('rules.createHint')}</p>
109
+ </div>
110
+ ` : `
111
+ <div class="rules-grid grid gap-3">
112
+ ${projectRules.map(rule => renderRuleCard(rule, 'project')).join('')}
113
+ </div>
114
+ `}
115
+ </div>
116
+
117
+ <!-- User Rules Section -->
118
+ <div class="rules-section mb-6">
119
+ <div class="flex items-center justify-between mb-4">
120
+ <div class="flex items-center gap-2">
121
+ <i data-lucide="user" class="w-5 h-5 text-orange"></i>
122
+ <h3 class="text-lg font-semibold text-foreground">${t('rules.userRules')}</h3>
123
+ <span class="text-xs px-2 py-0.5 bg-orange/10 text-orange rounded-full">~/.claude/rules/</span>
124
+ </div>
125
+ <span class="text-sm text-muted-foreground">${userRules.length} ${t('rules.rulesCount')}</span>
126
+ </div>
127
+
128
+ ${userRules.length === 0 ? `
129
+ <div class="rules-empty-state bg-card border border-border rounded-lg p-6 text-center">
130
+ <div class="text-muted-foreground mb-3"><i data-lucide="user" class="w-10 h-10 mx-auto"></i></div>
131
+ <p class="text-muted-foreground">${t('rules.noUserRules')}</p>
132
+ <p class="text-sm text-muted-foreground mt-1">${t('rules.userRulesHint')}</p>
133
+ </div>
134
+ ` : `
135
+ <div class="rules-grid grid gap-3">
136
+ ${userRules.map(rule => renderRuleCard(rule, 'user')).join('')}
137
+ </div>
138
+ `}
139
+ </div>
140
+
141
+ <!-- Rule Detail Panel -->
142
+ ${selectedRule ? renderRuleDetailPanel(selectedRule) : ''}
143
+ </div>
144
+ `;
145
+
146
+ // Initialize Lucide icons
147
+ if (typeof lucide !== 'undefined') lucide.createIcons();
148
+ }
149
+
150
+ function renderRuleCard(rule, location) {
151
+ const hasPathCondition = rule.paths && rule.paths.length > 0;
152
+ const isGlobal = !hasPathCondition;
153
+ const locationIcon = location === 'project' ? 'folder' : 'user';
154
+ const locationClass = location === 'project' ? 'text-success' : 'text-orange';
155
+ const locationBg = location === 'project' ? 'bg-success/10' : 'bg-orange/10';
156
+
157
+ // Get preview of content (first 100 chars)
158
+ const contentPreview = rule.content ? rule.content.substring(0, 100).replace(/\n/g, ' ') + (rule.content.length > 100 ? '...' : '') : '';
159
+
160
+ return `
161
+ <div class="rule-card bg-card border border-border rounded-lg p-4 hover:shadow-md transition-all cursor-pointer"
162
+ onclick="showRuleDetail('${escapeHtml(rule.name)}', '${location}')">
163
+ <div class="flex items-start justify-between mb-3">
164
+ <div class="flex items-center gap-3">
165
+ <div class="w-10 h-10 ${locationBg} rounded-lg flex items-center justify-center">
166
+ <i data-lucide="file-text" class="w-5 h-5 ${locationClass}"></i>
167
+ </div>
168
+ <div>
169
+ <h4 class="font-semibold text-foreground">${escapeHtml(rule.name)}</h4>
170
+ ${rule.subdirectory ? `<span class="text-xs text-muted-foreground">${escapeHtml(rule.subdirectory)}/</span>` : ''}
171
+ </div>
172
+ </div>
173
+ <div class="flex items-center gap-2">
174
+ ${isGlobal ? `
175
+ <span class="inline-flex items-center px-2 py-0.5 text-xs font-medium rounded-full bg-primary/10 text-primary">
176
+ <i data-lucide="globe" class="w-3 h-3 mr-1"></i>
177
+ global
178
+ </span>
179
+ ` : `
180
+ <span class="inline-flex items-center px-2 py-0.5 text-xs font-medium rounded-full bg-warning/10 text-warning">
181
+ <i data-lucide="filter" class="w-3 h-3 mr-1"></i>
182
+ conditional
183
+ </span>
184
+ `}
185
+ <span class="inline-flex items-center px-2 py-0.5 text-xs font-medium rounded-full ${locationBg} ${locationClass}">
186
+ <i data-lucide="${locationIcon}" class="w-3 h-3 mr-1"></i>
187
+ ${location}
188
+ </span>
189
+ </div>
190
+ </div>
191
+
192
+ ${contentPreview ? `
193
+ <p class="text-sm text-muted-foreground mb-3 line-clamp-2 font-mono">${escapeHtml(contentPreview)}</p>
194
+ ` : ''}
195
+
196
+ ${hasPathCondition ? `
197
+ <div class="flex items-center gap-2 text-xs text-muted-foreground mt-2">
198
+ <i data-lucide="filter" class="w-3 h-3"></i>
199
+ <span class="font-mono">${escapeHtml(rule.paths.join(', '))}</span>
200
+ </div>
201
+ ` : ''}
202
+ </div>
203
+ `;
204
+ }
205
+
206
+ function renderRuleDetailPanel(rule) {
207
+ const hasPathCondition = rule.paths && rule.paths.length > 0;
208
+
209
+ return `
210
+ <div class="rule-detail-panel fixed top-0 right-0 w-1/2 max-w-xl h-full bg-card border-l border-border shadow-lg z-50 flex flex-col">
211
+ <div class="flex items-center justify-between px-5 py-4 border-b border-border">
212
+ <h3 class="text-lg font-semibold text-foreground">${escapeHtml(rule.name)}</h3>
213
+ <button class="w-8 h-8 flex items-center justify-center text-xl text-muted-foreground hover:text-foreground hover:bg-hover rounded"
214
+ onclick="closeRuleDetail()">&times;</button>
215
+ </div>
216
+ <div class="flex-1 overflow-y-auto p-5">
217
+ <div class="space-y-6">
218
+ <!-- Type -->
219
+ <div>
220
+ <h4 class="text-sm font-semibold text-foreground mb-2">${t('rules.typeLabel')}</h4>
221
+ <div class="flex items-center gap-2">
222
+ ${hasPathCondition ? `
223
+ <span class="inline-flex items-center px-3 py-1 text-sm font-medium rounded-lg bg-warning/10 text-warning">
224
+ <i data-lucide="filter" class="w-4 h-4 mr-2"></i>
225
+ ${t('rules.conditional')}
226
+ </span>
227
+ ` : `
228
+ <span class="inline-flex items-center px-3 py-1 text-sm font-medium rounded-lg bg-primary/10 text-primary">
229
+ <i data-lucide="globe" class="w-4 h-4 mr-2"></i>
230
+ ${t('rules.global')}
231
+ </span>
232
+ `}
233
+ </div>
234
+ </div>
235
+
236
+ <!-- Path Conditions -->
237
+ ${hasPathCondition ? `
238
+ <div>
239
+ <h4 class="text-sm font-semibold text-foreground mb-2">${t('rules.pathConditions')}</h4>
240
+ <div class="space-y-2">
241
+ ${rule.paths.map(path => `
242
+ <div class="flex items-center gap-2 p-2 bg-muted/50 rounded-lg">
243
+ <i data-lucide="file-code" class="w-4 h-4 text-muted-foreground"></i>
244
+ <code class="text-sm font-mono text-foreground">${escapeHtml(path)}</code>
245
+ </div>
246
+ `).join('')}
247
+ </div>
248
+ </div>
249
+ ` : ''}
250
+
251
+ <!-- Content -->
252
+ <div>
253
+ <h4 class="text-sm font-semibold text-foreground mb-2">${t('rules.content')}</h4>
254
+ <div class="bg-muted rounded-lg p-4 max-h-96 overflow-y-auto">
255
+ <pre class="text-sm font-mono text-foreground whitespace-pre-wrap">${escapeHtml(rule.content || '')}</pre>
256
+ </div>
257
+ </div>
258
+
259
+ <!-- Path -->
260
+ <div>
261
+ <h4 class="text-sm font-semibold text-foreground mb-2">${t('rules.filePath')}</h4>
262
+ <code class="block p-3 bg-muted rounded-lg text-xs font-mono text-muted-foreground break-all">${escapeHtml(rule.path)}</code>
263
+ </div>
264
+ </div>
265
+ </div>
266
+
267
+ <!-- Actions -->
268
+ <div class="px-5 py-4 border-t border-border flex justify-between">
269
+ <button class="px-4 py-2 text-sm text-destructive hover:bg-destructive/10 rounded-lg transition-colors flex items-center gap-2"
270
+ onclick="deleteRule('${escapeHtml(rule.name)}', '${rule.location}')">
271
+ <i data-lucide="trash-2" class="w-4 h-4"></i>
272
+ ${t('common.delete')}
273
+ </button>
274
+ <button class="px-4 py-2 text-sm bg-primary text-primary-foreground rounded-lg hover:opacity-90 transition-opacity flex items-center gap-2"
275
+ onclick="editRule('${escapeHtml(rule.name)}', '${rule.location}')">
276
+ <i data-lucide="edit" class="w-4 h-4"></i>
277
+ ${t('common.edit')}
278
+ </button>
279
+ </div>
280
+ </div>
281
+ <div class="rule-detail-overlay fixed inset-0 bg-black/50 z-40" onclick="closeRuleDetail()"></div>
282
+ `;
283
+ }
284
+
285
+ async function showRuleDetail(ruleName, location) {
286
+ try {
287
+ const response = await fetch('/api/rules/' + encodeURIComponent(ruleName) + '?location=' + location + '&path=' + encodeURIComponent(projectPath));
288
+ if (!response.ok) throw new Error('Failed to load rule detail');
289
+ const data = await response.json();
290
+ selectedRule = data.rule;
291
+ renderRulesView();
292
+ } catch (err) {
293
+ console.error('Failed to load rule detail:', err);
294
+ if (window.showToast) {
295
+ showToast(t('rules.loadError'), 'error');
296
+ }
297
+ }
298
+ }
299
+
300
+ function closeRuleDetail() {
301
+ selectedRule = null;
302
+ renderRulesView();
303
+ }
304
+
305
+ async function deleteRule(ruleName, location) {
306
+ if (!confirm(t('rules.deleteConfirm', { name: ruleName }))) return;
307
+
308
+ try {
309
+ const response = await fetch('/api/rules/' + encodeURIComponent(ruleName), {
310
+ method: 'DELETE',
311
+ headers: { 'Content-Type': 'application/json' },
312
+ body: JSON.stringify({ location, projectPath })
313
+ });
314
+ if (!response.ok) throw new Error('Failed to delete rule');
315
+
316
+ selectedRule = null;
317
+ await loadRulesData();
318
+ renderRulesView();
319
+
320
+ if (window.showToast) {
321
+ showToast(t('rules.deleted'), 'success');
322
+ }
323
+ } catch (err) {
324
+ console.error('Failed to delete rule:', err);
325
+ if (window.showToast) {
326
+ showToast(t('rules.deleteError'), 'error');
327
+ }
328
+ }
329
+ }
330
+
331
+ function editRule(ruleName, location) {
332
+ // Open edit modal (to be implemented with modal)
333
+ if (window.showToast) {
334
+ showToast(t('rules.editNotImplemented'), 'info');
335
+ }
336
+ }
337
+
338
+ // ========== Create Rule Modal ==========
339
+ var ruleCreateState = {
340
+ location: 'project',
341
+ fileName: '',
342
+ subdirectory: '',
343
+ isConditional: false,
344
+ paths: [''],
345
+ content: '',
346
+ mode: 'input',
347
+ generationType: 'description',
348
+ description: '',
349
+ extractScope: '',
350
+ extractFocus: ''
351
+ };
352
+
353
+ function openRuleCreateModal() {
354
+ // Reset state
355
+ ruleCreateState = {
356
+ location: 'project',
357
+ fileName: '',
358
+ subdirectory: '',
359
+ isConditional: false,
360
+ paths: [''],
361
+ content: '',
362
+ mode: 'input',
363
+ generationType: 'description',
364
+ description: '',
365
+ extractScope: '',
366
+ extractFocus: ''
367
+ };
368
+
369
+ // Create modal HTML
370
+ const modalHtml = `
371
+ <div class="modal-overlay fixed inset-0 bg-black/50 z-50 flex items-center justify-center" onclick="closeRuleCreateModal(event)">
372
+ <div class="modal-dialog bg-card rounded-lg shadow-lg w-full max-w-2xl max-h-[90vh] mx-4 flex flex-col" onclick="event.stopPropagation()">
373
+ <!-- Header -->
374
+ <div class="flex items-center justify-between px-6 py-4 border-b border-border">
375
+ <h3 class="text-lg font-semibold text-foreground">${t('rules.createRule')}</h3>
376
+ <button class="w-8 h-8 flex items-center justify-center text-xl text-muted-foreground hover:text-foreground hover:bg-hover rounded"
377
+ onclick="closeRuleCreateModal()">&times;</button>
378
+ </div>
379
+
380
+ <!-- Body -->
381
+ <div class="flex-1 overflow-y-auto p-6 space-y-5">
382
+ <!-- Location Selection -->
383
+ <div>
384
+ <label class="block text-sm font-medium text-foreground mb-2">${t('rules.location')}</label>
385
+ <div class="grid grid-cols-2 gap-3">
386
+ <button class="location-btn px-4 py-3 text-left border-2 rounded-lg transition-all ${ruleCreateState.location === 'project' ? 'border-primary bg-primary/10' : 'border-border hover:border-primary/50'}"
387
+ onclick="selectRuleLocation('project')">
388
+ <div class="flex items-center gap-2">
389
+ <i data-lucide="folder" class="w-5 h-5"></i>
390
+ <div>
391
+ <div class="font-medium">${t('rules.projectRules')}</div>
392
+ <div class="text-xs text-muted-foreground">.claude/rules/</div>
393
+ </div>
394
+ </div>
395
+ </button>
396
+ <button class="location-btn px-4 py-3 text-left border-2 rounded-lg transition-all ${ruleCreateState.location === 'user' ? 'border-primary bg-primary/10' : 'border-border hover:border-primary/50'}"
397
+ onclick="selectRuleLocation('user')">
398
+ <div class="flex items-center gap-2">
399
+ <i data-lucide="user" class="w-5 h-5"></i>
400
+ <div>
401
+ <div class="font-medium">${t('rules.userRules')}</div>
402
+ <div class="text-xs text-muted-foreground">~/.claude/rules/</div>
403
+ </div>
404
+ </div>
405
+ </button>
406
+ </div>
407
+ </div>
408
+
409
+ <!-- Mode Selection -->
410
+ <div>
411
+ <label class="block text-sm font-medium text-foreground mb-2">${t('rules.createMode')}</label>
412
+ <div class="grid grid-cols-2 gap-3">
413
+ <button class="mode-btn px-4 py-3 text-left border-2 rounded-lg transition-all ${ruleCreateState.mode === 'input' ? 'border-primary bg-primary/10' : 'border-border hover:border-primary/50'}"
414
+ onclick="switchRuleCreateMode('input')">
415
+ <div class="flex items-center gap-2">
416
+ <i data-lucide="edit" class="w-5 h-5"></i>
417
+ <div>
418
+ <div class="font-medium">${t('rules.manualInput')}</div>
419
+ <div class="text-xs text-muted-foreground">${t('rules.manualInputHint')}</div>
420
+ </div>
421
+ </div>
422
+ </button>
423
+ <button class="mode-btn px-4 py-3 text-left border-2 rounded-lg transition-all ${ruleCreateState.mode === 'cli-generate' ? 'border-primary bg-primary/10' : 'border-border hover:border-primary/50'}"
424
+ onclick="switchRuleCreateMode('cli-generate')">
425
+ <div class="flex items-center gap-2">
426
+ <i data-lucide="sparkles" class="w-5 h-5"></i>
427
+ <div>
428
+ <div class="font-medium">${t('rules.cliGenerate')}</div>
429
+ <div class="text-xs text-muted-foreground">${t('rules.cliGenerateHint')}</div>
430
+ </div>
431
+ </div>
432
+ </button>
433
+ </div>
434
+ </div>
435
+
436
+ <!-- File Name -->
437
+ <div>
438
+ <label class="block text-sm font-medium text-foreground mb-2">${t('rules.fileName')}</label>
439
+ <input type="text" id="ruleFileName"
440
+ class="w-full px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
441
+ placeholder="my-rule.md"
442
+ value="${ruleCreateState.fileName}">
443
+ <p class="text-xs text-muted-foreground mt-1">${t('rules.fileNameHint')}</p>
444
+ </div>
445
+
446
+ <!-- Subdirectory -->
447
+ <div>
448
+ <label class="block text-sm font-medium text-foreground mb-2">${t('rules.subdirectory')} <span class="text-muted-foreground">${t('common.optional')}</span></label>
449
+ <input type="text" id="ruleSubdirectory"
450
+ class="w-full px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
451
+ placeholder="category/subcategory"
452
+ value="${ruleCreateState.subdirectory}">
453
+ <p class="text-xs text-muted-foreground mt-1">${t('rules.subdirectoryHint')}</p>
454
+ </div>
455
+
456
+ <!-- CLI Generation Type (CLI mode only) -->
457
+ <div id="ruleGenerationTypeSection" style="display: ${ruleCreateState.mode === 'cli-generate' ? 'block' : 'none'}">
458
+ <label class="block text-sm font-medium text-foreground mb-2">${t('rules.generationType')}</label>
459
+ <div class="flex gap-3">
460
+ <label class="flex items-center gap-2 cursor-pointer">
461
+ <input type="radio" name="ruleGenType" value="description"
462
+ class="w-4 h-4 text-primary bg-background border-border focus:ring-2 focus:ring-primary"
463
+ ${ruleCreateState.generationType === 'description' ? 'checked' : ''}
464
+ onchange="switchRuleGenerationType('description')">
465
+ <span class="text-sm">${t('rules.fromDescription')}</span>
466
+ </label>
467
+ <label class="flex items-center gap-2 cursor-pointer">
468
+ <input type="radio" name="ruleGenType" value="extract"
469
+ class="w-4 h-4 text-primary bg-background border-border focus:ring-2 focus:ring-primary"
470
+ ${ruleCreateState.generationType === 'extract' ? 'checked' : ''}
471
+ onchange="switchRuleGenerationType('extract')">
472
+ <span class="text-sm">${t('rules.fromCodeExtract')}</span>
473
+ </label>
474
+ </div>
475
+ </div>
476
+
477
+ <!-- Description Input (CLI mode, description type) -->
478
+ <div id="ruleDescriptionSection" style="display: ${ruleCreateState.mode === 'cli-generate' && ruleCreateState.generationType === 'description' ? 'block' : 'none'}">
479
+ <label class="block text-sm font-medium text-foreground mb-2">${t('rules.description')}</label>
480
+ <textarea id="ruleDescription"
481
+ class="w-full px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
482
+ rows="4"
483
+ placeholder="${t('rules.descriptionPlaceholder')}">${ruleCreateState.description}</textarea>
484
+ <p class="text-xs text-muted-foreground mt-1">${t('rules.descriptionHint')}</p>
485
+ </div>
486
+
487
+ <!-- Code Extract Options (CLI mode, extract type) -->
488
+ <div id="ruleExtractSection" style="display: ${ruleCreateState.mode === 'cli-generate' && ruleCreateState.generationType === 'extract' ? 'block' : 'none'}">
489
+ <div class="space-y-4">
490
+ <div>
491
+ <label class="block text-sm font-medium text-foreground mb-2">${t('rules.extractScope')}</label>
492
+ <input type="text" id="ruleExtractScope"
493
+ class="w-full px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary font-mono"
494
+ placeholder="src/**/*.ts"
495
+ value="${ruleCreateState.extractScope}">
496
+ <p class="text-xs text-muted-foreground mt-1">${t('rules.extractScopeHint')}</p>
497
+ </div>
498
+ <div>
499
+ <label class="block text-sm font-medium text-foreground mb-2">${t('rules.extractFocus')}</label>
500
+ <input type="text" id="ruleExtractFocus"
501
+ class="w-full px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
502
+ placeholder="naming, error-handling, state-management"
503
+ value="${ruleCreateState.extractFocus}">
504
+ <p class="text-xs text-muted-foreground mt-1">${t('rules.extractFocusHint')}</p>
505
+ </div>
506
+ </div>
507
+ </div>
508
+
509
+ <!-- Conditional Rule Toggle (Manual mode only) -->
510
+ <div id="ruleConditionalSection" style="display: ${ruleCreateState.mode === 'input' ? 'block' : 'none'}">
511
+ <label class="flex items-center gap-2 cursor-pointer">
512
+ <input type="checkbox" id="ruleConditional"
513
+ class="w-4 h-4 text-primary bg-background border-border rounded focus:ring-2 focus:ring-primary"
514
+ ${ruleCreateState.isConditional ? 'checked' : ''}
515
+ onchange="toggleRuleConditional()">
516
+ <span class="text-sm font-medium text-foreground">${t('rules.conditionalRule')}</span>
517
+ </label>
518
+ <p class="text-xs text-muted-foreground mt-1 ml-6">${t('rules.conditionalHint')}</p>
519
+ </div>
520
+
521
+ <!-- Path Conditions -->
522
+ <div id="rulePathsContainer" style="display: ${ruleCreateState.isConditional ? 'block' : 'none'}">
523
+ <label class="block text-sm font-medium text-foreground mb-2">${t('rules.pathConditions')}</label>
524
+ <div id="rulePathsList" class="space-y-2">
525
+ ${ruleCreateState.paths.map((path, index) => `
526
+ <div class="flex gap-2">
527
+ <input type="text" class="rule-path-input flex-1 px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
528
+ placeholder="src/**/*.ts"
529
+ value="${path}"
530
+ data-index="${index}">
531
+ ${index > 0 ? `
532
+ <button class="px-3 py-2 text-destructive hover:bg-destructive/10 rounded-lg transition-colors"
533
+ onclick="removeRulePath(${index})">
534
+ <i data-lucide="x" class="w-4 h-4"></i>
535
+ </button>
536
+ ` : ''}
537
+ </div>
538
+ `).join('')}
539
+ </div>
540
+ <button class="mt-2 px-3 py-1.5 text-sm text-primary hover:bg-primary/10 rounded-lg transition-colors flex items-center gap-1"
541
+ onclick="addRulePath()">
542
+ <i data-lucide="plus" class="w-4 h-4"></i>
543
+ ${t('rules.addPath')}
544
+ </button>
545
+ </div>
546
+
547
+ <!-- Content (Manual mode only) -->
548
+ <div id="ruleContentSection" style="display: ${ruleCreateState.mode === 'input' ? 'block' : 'none'}">
549
+ <label class="block text-sm font-medium text-foreground mb-2">${t('rules.content')}</label>
550
+ <textarea id="ruleContent"
551
+ class="w-full px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary font-mono"
552
+ rows="10"
553
+ placeholder="${t('rules.contentPlaceholder')}">${ruleCreateState.content}</textarea>
554
+ <p class="text-xs text-muted-foreground mt-1">${t('rules.contentHint')}</p>
555
+ </div>
556
+ </div>
557
+
558
+ <!-- Footer -->
559
+ <div class="flex items-center justify-end gap-3 px-6 py-4 border-t border-border">
560
+ <button class="px-4 py-2 text-sm text-muted-foreground hover:text-foreground transition-colors"
561
+ onclick="closeRuleCreateModal()">
562
+ ${t('common.cancel')}
563
+ </button>
564
+ <button class="px-4 py-2 text-sm bg-primary text-primary-foreground rounded-lg hover:opacity-90 transition-opacity"
565
+ onclick="createRule()">
566
+ ${t('rules.create')}
567
+ </button>
568
+ </div>
569
+ </div>
570
+ </div>
571
+ `;
572
+
573
+ // Add to DOM
574
+ const modalContainer = document.createElement('div');
575
+ modalContainer.id = 'ruleCreateModal';
576
+ modalContainer.innerHTML = modalHtml;
577
+ document.body.appendChild(modalContainer);
578
+
579
+ // Initialize Lucide icons
580
+ if (typeof lucide !== 'undefined') lucide.createIcons();
581
+ }
582
+
583
+ function closeRuleCreateModal(event) {
584
+ if (event && event.target !== event.currentTarget) return;
585
+ const modal = document.getElementById('ruleCreateModal');
586
+ if (modal) modal.remove();
587
+ }
588
+
589
+ function selectRuleLocation(location) {
590
+ ruleCreateState.location = location;
591
+
592
+ // Update button styles without re-rendering modal
593
+ const buttons = document.querySelectorAll('.location-btn');
594
+ buttons.forEach(btn => {
595
+ const isProject = btn.querySelector('.font-medium')?.textContent?.includes(t('rules.projectRules'));
596
+ const isUser = btn.querySelector('.font-medium')?.textContent?.includes(t('rules.userRules'));
597
+
598
+ if ((isProject && location === 'project') || (isUser && location === 'user')) {
599
+ btn.classList.remove('border-border', 'hover:border-primary/50');
600
+ btn.classList.add('border-primary', 'bg-primary/10');
601
+ } else {
602
+ btn.classList.remove('border-primary', 'bg-primary/10');
603
+ btn.classList.add('border-border', 'hover:border-primary/50');
604
+ }
605
+ });
606
+ }
607
+
608
+ function toggleRuleConditional() {
609
+ ruleCreateState.isConditional = !ruleCreateState.isConditional;
610
+ const pathsContainer = document.getElementById('rulePathsContainer');
611
+ if (pathsContainer) {
612
+ pathsContainer.style.display = ruleCreateState.isConditional ? 'block' : 'none';
613
+ }
614
+ }
615
+
616
+ function addRulePath() {
617
+ ruleCreateState.paths.push('');
618
+ // Re-render paths list
619
+ const pathsList = document.getElementById('rulePathsList');
620
+ if (pathsList) {
621
+ const index = ruleCreateState.paths.length - 1;
622
+ const pathHtml = `
623
+ <div class="flex gap-2">
624
+ <input type="text" class="rule-path-input flex-1 px-3 py-2 bg-background border border-border rounded-lg text-sm focus:outline-none focus:ring-2 focus:ring-primary"
625
+ placeholder="src/**/*.ts"
626
+ value=""
627
+ data-index="${index}">
628
+ <button class="px-3 py-2 text-destructive hover:bg-destructive/10 rounded-lg transition-colors"
629
+ onclick="removeRulePath(${index})">
630
+ <i data-lucide="x" class="w-4 h-4"></i>
631
+ </button>
632
+ </div>
633
+ `;
634
+ pathsList.insertAdjacentHTML('beforeend', pathHtml);
635
+ if (typeof lucide !== 'undefined') lucide.createIcons();
636
+ }
637
+ }
638
+
639
+ function removeRulePath(index) {
640
+ ruleCreateState.paths.splice(index, 1);
641
+ // Re-render paths list
642
+ closeRuleCreateModal();
643
+ openRuleCreateModal();
644
+ }
645
+
646
+ function switchRuleCreateMode(mode) {
647
+ ruleCreateState.mode = mode;
648
+
649
+ // Toggle visibility of sections
650
+ const generationTypeSection = document.getElementById('ruleGenerationTypeSection');
651
+ const descriptionSection = document.getElementById('ruleDescriptionSection');
652
+ const extractSection = document.getElementById('ruleExtractSection');
653
+ const conditionalSection = document.getElementById('ruleConditionalSection');
654
+ const contentSection = document.getElementById('ruleContentSection');
655
+
656
+ if (mode === 'cli-generate') {
657
+ if (generationTypeSection) generationTypeSection.style.display = 'block';
658
+ if (conditionalSection) conditionalSection.style.display = 'none';
659
+ if (contentSection) contentSection.style.display = 'none';
660
+
661
+ // Show appropriate generation section
662
+ if (ruleCreateState.generationType === 'description') {
663
+ if (descriptionSection) descriptionSection.style.display = 'block';
664
+ if (extractSection) extractSection.style.display = 'none';
665
+ } else {
666
+ if (descriptionSection) descriptionSection.style.display = 'none';
667
+ if (extractSection) extractSection.style.display = 'block';
668
+ }
669
+ } else {
670
+ if (generationTypeSection) generationTypeSection.style.display = 'none';
671
+ if (descriptionSection) descriptionSection.style.display = 'none';
672
+ if (extractSection) extractSection.style.display = 'none';
673
+ if (conditionalSection) conditionalSection.style.display = 'block';
674
+ if (contentSection) contentSection.style.display = 'block';
675
+ }
676
+
677
+ // Re-render modal to update button states
678
+ closeRuleCreateModal();
679
+ openRuleCreateModal();
680
+ }
681
+
682
+ function switchRuleGenerationType(type) {
683
+ ruleCreateState.generationType = type;
684
+
685
+ // Toggle visibility of generation sections
686
+ const descriptionSection = document.getElementById('ruleDescriptionSection');
687
+ const extractSection = document.getElementById('ruleExtractSection');
688
+
689
+ if (type === 'description') {
690
+ if (descriptionSection) descriptionSection.style.display = 'block';
691
+ if (extractSection) extractSection.style.display = 'none';
692
+ } else if (type === 'extract') {
693
+ if (descriptionSection) descriptionSection.style.display = 'none';
694
+ if (extractSection) extractSection.style.display = 'block';
695
+ }
696
+ }
697
+
698
+ async function createRule() {
699
+ const fileNameInput = document.getElementById('ruleFileName');
700
+ const subdirectoryInput = document.getElementById('ruleSubdirectory');
701
+ const contentInput = document.getElementById('ruleContent');
702
+ const pathInputs = document.querySelectorAll('.rule-path-input');
703
+ const descriptionInput = document.getElementById('ruleDescription');
704
+ const extractScopeInput = document.getElementById('ruleExtractScope');
705
+ const extractFocusInput = document.getElementById('ruleExtractFocus');
706
+
707
+ const fileName = fileNameInput ? fileNameInput.value.trim() : ruleCreateState.fileName;
708
+ const subdirectory = subdirectoryInput ? subdirectoryInput.value.trim() : ruleCreateState.subdirectory;
709
+
710
+ // Validate file name
711
+ if (!fileName) {
712
+ if (window.showToast) {
713
+ showToast(t('rules.fileNameRequired'), 'error');
714
+ }
715
+ return;
716
+ }
717
+
718
+ if (!fileName.endsWith('.md')) {
719
+ if (window.showToast) {
720
+ showToast(t('rules.fileNameMustEndMd'), 'error');
721
+ }
722
+ return;
723
+ }
724
+
725
+ // Prepare request based on mode
726
+ let requestBody;
727
+
728
+ if (ruleCreateState.mode === 'cli-generate') {
729
+ // CLI generation mode
730
+ const description = descriptionInput ? descriptionInput.value.trim() : ruleCreateState.description;
731
+ const extractScope = extractScopeInput ? extractScopeInput.value.trim() : ruleCreateState.extractScope;
732
+ const extractFocus = extractFocusInput ? extractFocusInput.value.trim() : ruleCreateState.extractFocus;
733
+
734
+ // Validate based on generation type
735
+ if (ruleCreateState.generationType === 'description' && !description) {
736
+ if (window.showToast) {
737
+ showToast(t('rules.descriptionRequired'), 'error');
738
+ }
739
+ return;
740
+ }
741
+
742
+ if (ruleCreateState.generationType === 'extract' && !extractScope) {
743
+ if (window.showToast) {
744
+ showToast(t('rules.extractScopeRequired'), 'error');
745
+ }
746
+ return;
747
+ }
748
+
749
+ requestBody = {
750
+ mode: 'cli-generate',
751
+ fileName,
752
+ location: ruleCreateState.location,
753
+ subdirectory: subdirectory || undefined,
754
+ projectPath,
755
+ generationType: ruleCreateState.generationType,
756
+ description: ruleCreateState.generationType === 'description' ? description : undefined,
757
+ extractScope: ruleCreateState.generationType === 'extract' ? extractScope : undefined,
758
+ extractFocus: ruleCreateState.generationType === 'extract' ? extractFocus : undefined
759
+ };
760
+
761
+ // Show progress message
762
+ if (window.showToast) {
763
+ showToast(t('rules.cliGenerating'), 'info');
764
+ }
765
+ } else {
766
+ // Manual input mode
767
+ const content = contentInput ? contentInput.value.trim() : ruleCreateState.content;
768
+
769
+ // Collect paths from inputs
770
+ const paths = [];
771
+ if (ruleCreateState.isConditional && pathInputs) {
772
+ pathInputs.forEach(input => {
773
+ const path = input.value.trim();
774
+ if (path) paths.push(path);
775
+ });
776
+ }
777
+
778
+ // Validate content
779
+ if (!content) {
780
+ if (window.showToast) {
781
+ showToast(t('rules.contentRequired'), 'error');
782
+ }
783
+ return;
784
+ }
785
+
786
+ requestBody = {
787
+ mode: 'input',
788
+ fileName,
789
+ content,
790
+ paths: paths.length > 0 ? paths : undefined,
791
+ location: ruleCreateState.location,
792
+ subdirectory: subdirectory || undefined,
793
+ projectPath
794
+ };
795
+ }
796
+
797
+ try {
798
+ const response = await fetch('/api/rules/create', {
799
+ method: 'POST',
800
+ headers: { 'Content-Type': 'application/json' },
801
+ body: JSON.stringify(requestBody)
802
+ });
803
+
804
+ if (!response.ok) {
805
+ const error = await response.json();
806
+ throw new Error(error.error || 'Failed to create rule');
807
+ }
808
+
809
+ const result = await response.json();
810
+
811
+ // Close modal
812
+ closeRuleCreateModal();
813
+
814
+ // Reload rules data
815
+ await loadRulesData();
816
+ renderRulesView();
817
+
818
+ // Show success message
819
+ if (window.showToast) {
820
+ showToast(t('rules.created', { name: result.fileName }), 'success');
821
+ }
822
+ } catch (err) {
823
+ console.error('Failed to create rule:', err);
824
+ if (window.showToast) {
825
+ showToast(err.message || t('rules.createError'), 'error');
826
+ }
827
+ }
828
+ }