claude-code-workflow 6.3.37 → 6.3.39

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 (173) hide show
  1. package/.claude/commands/workflow/lite-execute.md +2 -0
  2. package/.codex/agents/action-planning-agent.md +885 -0
  3. package/.codex/agents/ccw-loop-b-complete.md +227 -0
  4. package/.codex/agents/ccw-loop-b-debug.md +172 -0
  5. package/.codex/agents/ccw-loop-b-develop.md +147 -0
  6. package/.codex/agents/ccw-loop-b-init.md +82 -0
  7. package/.codex/agents/ccw-loop-b-validate.md +204 -0
  8. package/.codex/agents/ccw-loop-executor.md +260 -0
  9. package/.codex/agents/cli-discuss-agent.md +391 -0
  10. package/.codex/agents/cli-execution-agent.md +333 -0
  11. package/.codex/agents/cli-explore-agent.md +186 -0
  12. package/.codex/agents/cli-lite-planning-agent.md +736 -0
  13. package/.codex/agents/cli-planning-agent.md +562 -0
  14. package/.codex/agents/code-developer.md +408 -0
  15. package/.codex/agents/conceptual-planning-agent.md +321 -0
  16. package/.codex/agents/context-search-agent.md +585 -0
  17. package/.codex/agents/debug-explore-agent.md +436 -0
  18. package/.codex/agents/doc-generator.md +334 -0
  19. package/.codex/agents/issue-plan-agent.md +417 -0
  20. package/.codex/agents/issue-queue-agent.md +311 -0
  21. package/.codex/agents/memory-bridge.md +96 -0
  22. package/.codex/agents/test-context-search-agent.md +402 -0
  23. package/.codex/agents/test-fix-agent.md +359 -0
  24. package/.codex/agents/ui-design-agent.md +595 -0
  25. package/.codex/agents/universal-executor.md +135 -0
  26. package/.codex/prompts/clean.md +409 -0
  27. package/.codex/prompts/issue-discover-by-prompt.md +364 -0
  28. package/.codex/prompts/issue-discover.md +261 -0
  29. package/.codex/prompts/issue-execute.md +10 -0
  30. package/.codex/prompts/issue-new.md +285 -0
  31. package/.codex/prompts/issue-plan.md +161 -63
  32. package/.codex/prompts/issue-queue.md +298 -288
  33. package/.codex/prompts/lite-execute.md +627 -133
  34. package/.codex/prompts/lite-fix.md +670 -0
  35. package/.codex/prompts/lite-plan-a.md +337 -0
  36. package/.codex/prompts/lite-plan-b.md +485 -0
  37. package/.codex/prompts/{lite-plan.md → lite-plan-c.md} +601 -469
  38. package/.codex/skills/ccw-loop/README.md +171 -0
  39. package/.codex/skills/ccw-loop/SKILL.md +349 -0
  40. package/.codex/skills/ccw-loop/phases/actions/action-complete.md +269 -0
  41. package/.codex/skills/ccw-loop/phases/actions/action-debug.md +286 -0
  42. package/.codex/skills/ccw-loop/phases/actions/action-develop.md +183 -0
  43. package/.codex/skills/ccw-loop/phases/actions/action-init.md +164 -0
  44. package/.codex/skills/ccw-loop/phases/actions/action-menu.md +205 -0
  45. package/.codex/skills/ccw-loop/phases/actions/action-validate.md +250 -0
  46. package/.codex/skills/ccw-loop/phases/orchestrator.md +416 -0
  47. package/.codex/skills/ccw-loop/phases/state-schema.md +388 -0
  48. package/.codex/skills/ccw-loop/specs/action-catalog.md +182 -0
  49. package/.codex/skills/ccw-loop-b/README.md +301 -0
  50. package/.codex/skills/ccw-loop-b/SKILL.md +322 -0
  51. package/.codex/skills/ccw-loop-b/phases/orchestrator.md +257 -0
  52. package/.codex/skills/ccw-loop-b/phases/state-schema.md +181 -0
  53. package/.codex/skills/ccw-loop-b/specs/action-catalog.md +383 -0
  54. package/.codex/skills/parallel-dev-cycle/README.md +382 -0
  55. package/.codex/skills/parallel-dev-cycle/SKILL.md +512 -0
  56. package/.codex/skills/parallel-dev-cycle/phases/agents/code-developer.md +242 -0
  57. package/.codex/skills/parallel-dev-cycle/phases/agents/exploration-planner.md +285 -0
  58. package/.codex/skills/parallel-dev-cycle/phases/agents/requirements-analyst.md +285 -0
  59. package/.codex/skills/parallel-dev-cycle/phases/agents/validation-archivist.md +381 -0
  60. package/.codex/skills/parallel-dev-cycle/phases/orchestrator.md +696 -0
  61. package/.codex/skills/parallel-dev-cycle/phases/state-schema.md +436 -0
  62. package/.codex/skills/parallel-dev-cycle/specs/communication-optimization.md +423 -0
  63. package/.codex/skills/parallel-dev-cycle/specs/coordination-protocol.md +391 -0
  64. package/.codex/skills/parallel-dev-cycle/specs/versioning-strategy.md +330 -0
  65. package/ccw/dist/cli.d.ts.map +1 -1
  66. package/ccw/dist/cli.js +4 -0
  67. package/ccw/dist/cli.js.map +1 -1
  68. package/ccw/dist/commands/install.d.ts.map +1 -1
  69. package/ccw/dist/commands/install.js +39 -8
  70. package/ccw/dist/commands/install.js.map +1 -1
  71. package/ccw/dist/commands/issue.d.ts +3 -0
  72. package/ccw/dist/commands/issue.d.ts.map +1 -1
  73. package/ccw/dist/commands/issue.js +107 -0
  74. package/ccw/dist/commands/issue.js.map +1 -1
  75. package/ccw/dist/commands/upgrade.js +1 -1
  76. package/ccw/dist/commands/upgrade.js.map +1 -1
  77. package/ccw/dist/config/litellm-api-config-manager.d.ts.map +1 -1
  78. package/ccw/dist/config/litellm-api-config-manager.js +3 -2
  79. package/ccw/dist/config/litellm-api-config-manager.js.map +1 -1
  80. package/ccw/dist/core/memory-embedder-bridge.d.ts.map +1 -1
  81. package/ccw/dist/core/memory-embedder-bridge.js +2 -5
  82. package/ccw/dist/core/memory-embedder-bridge.js.map +1 -1
  83. package/ccw/dist/core/routes/cli-routes.js.map +1 -1
  84. package/ccw/dist/core/routes/codexlens/config-handlers.d.ts.map +1 -1
  85. package/ccw/dist/core/routes/codexlens/config-handlers.js +7 -6
  86. package/ccw/dist/core/routes/codexlens/config-handlers.js.map +1 -1
  87. package/ccw/dist/core/routes/codexlens/semantic-handlers.d.ts.map +1 -1
  88. package/ccw/dist/core/routes/codexlens/semantic-handlers.js +2 -2
  89. package/ccw/dist/core/routes/codexlens/semantic-handlers.js.map +1 -1
  90. package/ccw/dist/core/routes/graph-routes.d.ts.map +1 -1
  91. package/ccw/dist/core/routes/graph-routes.js +17 -2
  92. package/ccw/dist/core/routes/graph-routes.js.map +1 -1
  93. package/ccw/dist/core/routes/issue-routes.d.ts.map +1 -1
  94. package/ccw/dist/core/routes/issue-routes.js +280 -33
  95. package/ccw/dist/core/routes/issue-routes.js.map +1 -1
  96. package/ccw/dist/core/routes/loop-v2-routes.d.ts +9 -0
  97. package/ccw/dist/core/routes/loop-v2-routes.d.ts.map +1 -1
  98. package/ccw/dist/core/routes/loop-v2-routes.js +56 -4
  99. package/ccw/dist/core/routes/loop-v2-routes.js.map +1 -1
  100. package/ccw/dist/core/routes/system-routes.d.ts.map +1 -1
  101. package/ccw/dist/core/routes/system-routes.js +3 -2
  102. package/ccw/dist/core/routes/system-routes.js.map +1 -1
  103. package/ccw/dist/core/server.d.ts.map +1 -1
  104. package/ccw/dist/core/server.js +5 -3
  105. package/ccw/dist/core/server.js.map +1 -1
  106. package/ccw/dist/tools/claude-cli-tools.d.ts.map +1 -1
  107. package/ccw/dist/tools/claude-cli-tools.js +4 -3
  108. package/ccw/dist/tools/claude-cli-tools.js.map +1 -1
  109. package/ccw/dist/tools/cli-config-manager.d.ts +1 -0
  110. package/ccw/dist/tools/cli-config-manager.d.ts.map +1 -1
  111. package/ccw/dist/tools/cli-config-manager.js +2 -1
  112. package/ccw/dist/tools/cli-config-manager.js.map +1 -1
  113. package/ccw/dist/tools/codex-lens-lsp.d.ts.map +1 -1
  114. package/ccw/dist/tools/codex-lens-lsp.js +2 -5
  115. package/ccw/dist/tools/codex-lens-lsp.js.map +1 -1
  116. package/ccw/dist/tools/codex-lens.d.ts.map +1 -1
  117. package/ccw/dist/tools/codex-lens.js +22 -32
  118. package/ccw/dist/tools/codex-lens.js.map +1 -1
  119. package/ccw/dist/tools/litellm-client.d.ts +6 -0
  120. package/ccw/dist/tools/litellm-client.d.ts.map +1 -1
  121. package/ccw/dist/tools/litellm-client.js +15 -2
  122. package/ccw/dist/tools/litellm-client.js.map +1 -1
  123. package/ccw/dist/tools/loop-task-manager.d.ts +13 -2
  124. package/ccw/dist/tools/loop-task-manager.d.ts.map +1 -1
  125. package/ccw/dist/tools/loop-task-manager.js.map +1 -1
  126. package/ccw/dist/tools/native-session-discovery.d.ts.map +1 -1
  127. package/ccw/dist/tools/native-session-discovery.js +35 -7
  128. package/ccw/dist/tools/native-session-discovery.js.map +1 -1
  129. package/ccw/dist/utils/codexlens-path.d.ts +36 -0
  130. package/ccw/dist/utils/codexlens-path.d.ts.map +1 -0
  131. package/ccw/dist/utils/codexlens-path.js +56 -0
  132. package/ccw/dist/utils/codexlens-path.js.map +1 -0
  133. package/ccw/dist/utils/uv-manager.d.ts.map +1 -1
  134. package/ccw/dist/utils/uv-manager.js +3 -2
  135. package/ccw/dist/utils/uv-manager.js.map +1 -1
  136. package/ccw/src/cli.ts +4 -0
  137. package/ccw/src/commands/install.ts +51 -8
  138. package/ccw/src/commands/issue.ts +119 -0
  139. package/ccw/src/commands/upgrade.ts +1 -1
  140. package/ccw/src/config/litellm-api-config-manager.ts +3 -2
  141. package/ccw/src/core/memory-embedder-bridge.ts +2 -6
  142. package/ccw/src/core/routes/cli-routes.ts +1 -1
  143. package/ccw/src/core/routes/codexlens/config-handlers.ts +7 -6
  144. package/ccw/src/core/routes/codexlens/semantic-handlers.ts +2 -2
  145. package/ccw/src/core/routes/graph-routes.ts +18 -2
  146. package/ccw/src/core/routes/issue-routes.ts +308 -33
  147. package/ccw/src/core/routes/loop-v2-routes.ts +64 -6
  148. package/ccw/src/core/routes/system-routes.ts +3 -2
  149. package/ccw/src/core/server.ts +6 -3
  150. package/ccw/src/templates/dashboard-css/02-session.css +2 -0
  151. package/ccw/src/templates/dashboard-css/04-lite-tasks.css +103 -1
  152. package/ccw/src/templates/dashboard-css/32-issue-manager.css +32 -0
  153. package/ccw/src/templates/dashboard-js/components/cli-history.js +48 -48
  154. package/ccw/src/templates/dashboard-js/components/navigation.js +6 -0
  155. package/ccw/src/templates/dashboard-js/components/notifications.js +6 -0
  156. package/ccw/src/templates/dashboard-js/components/version-check.js +38 -0
  157. package/ccw/src/templates/dashboard-js/i18n.js +126 -0
  158. package/ccw/src/templates/dashboard-js/state.js +2 -0
  159. package/ccw/src/templates/dashboard-js/views/cli-manager.js +1 -1
  160. package/ccw/src/templates/dashboard-js/views/issue-manager.js +183 -1
  161. package/ccw/src/templates/dashboard-js/views/lite-tasks.js +55 -11
  162. package/ccw/src/templates/dashboard-js/views/loop-monitor.js +112 -11
  163. package/ccw/src/templates/dashboard.html +48 -2
  164. package/ccw/src/tools/claude-cli-tools.ts +4 -3
  165. package/ccw/src/tools/cli-config-manager.ts +3 -1
  166. package/ccw/src/tools/codex-lens-lsp.ts +2 -5
  167. package/ccw/src/tools/codex-lens.ts +27 -38
  168. package/ccw/src/tools/litellm-client.ts +16 -2
  169. package/ccw/src/tools/loop-task-manager.ts +13 -2
  170. package/ccw/src/tools/native-session-discovery.ts +38 -7
  171. package/ccw/src/utils/codexlens-path.ts +60 -0
  172. package/ccw/src/utils/uv-manager.ts +3 -2
  173. package/package.json +1 -1
@@ -289,6 +289,65 @@ const i18n = {
289
289
  'cli.fileBrowserApiError': 'Server restart required to enable file browser',
290
290
  'cli.fileBrowserManualHint': 'Type the full path above and click Select (e.g., C:\\Users\\name\\.gemini)',
291
291
 
292
+ // CLI History & Execution
293
+ 'cli.executionHistory': 'Execution History',
294
+ 'cli.conversationDetail': 'Conversation Detail',
295
+ 'cli.nativeSessionDetail': 'Native Session Detail',
296
+ 'cli.viewFullConversation': 'View Full Process Conversation',
297
+ 'cli.perTurnView': 'Per-Turn View',
298
+ 'cli.concatenatedView': 'Concatenated View',
299
+ 'cli.userPrompt': 'User Prompt',
300
+ 'cli.assistantResponse': 'Assistant Response',
301
+ 'cli.user': 'User',
302
+ 'cli.assistant': 'Assistant',
303
+ 'cli.latest': 'Latest',
304
+ 'cli.turn': 'Turn',
305
+ 'cli.thinkingProcess': 'Thinking Process',
306
+ 'cli.thoughts': 'thoughts',
307
+ 'cli.toolCalls': 'Tool Calls',
308
+ 'cli.totalTokens': 'Total Tokens',
309
+ 'cli.input': 'Input',
310
+ 'cli.output': 'Output',
311
+ 'cli.cached': 'Cached',
312
+ 'cli.concatenatedPrompt': 'Concatenated Prompt (sent to CLI)',
313
+ 'cli.sessionId': 'Session ID',
314
+
315
+ // CLI History Actions & Buttons
316
+ 'cli.refresh': 'Refresh',
317
+ 'cli.copyId': 'Copy ID',
318
+ 'cli.copyFullPrompt': 'Copy Full Prompt',
319
+ 'cli.delete': 'Delete',
320
+ 'cli.exportJson': 'Export JSON',
321
+ 'cli.copyFilePath': 'Copy File Path',
322
+ 'cli.copySessionId': 'Copy Session ID',
323
+ 'cli.viewNativeSession': 'View Native Session',
324
+ 'cli.viewDetails': 'View Details',
325
+ 'cli.searchHistory': 'Search history...',
326
+ 'cli.allTools': 'All Tools',
327
+ 'cli.noExecutions': 'No executions yet',
328
+ 'cli.noMatchingResults': 'No matching results',
329
+
330
+ // CLI History Messages
331
+ 'cli.conversationNotFound': 'Conversation not found',
332
+ 'cli.nativeSessionNotFound': 'Native session not found',
333
+ 'cli.historyRefreshed': 'History refreshed',
334
+ 'cli.executionDeleted': 'Execution deleted',
335
+ 'cli.deleteFailed': 'Delete failed',
336
+ 'cli.idCopied': 'ID copied',
337
+ 'cli.promptCopied': 'Prompt copied to clipboard',
338
+ 'cli.fullPromptCopied': 'Full prompt copied to clipboard',
339
+ 'cli.sessionIdCopied': 'Session ID copied',
340
+ 'cli.filePathCopied': 'File path copied',
341
+ 'cli.pathNotAvailable': 'Path not available',
342
+ 'cli.noSessionData': 'No session data',
343
+ 'cli.sessionExported': 'Session exported',
344
+ 'cli.failedToCopy': 'Failed to copy',
345
+ 'cli.executionNotFound': 'Execution not found',
346
+
347
+ // CLI History Confirm Dialog
348
+ 'cli.confirmDelete': 'Delete this execution record? This action cannot be undone.',
349
+ 'cli.nativeSessionBadge': 'Native session',
350
+
292
351
  // CodexLens Configuration
293
352
  'codexlens.config': 'CodexLens Configuration',
294
353
  'codexlens.configDesc': 'Manage code indexing, semantic search, and embedding models',
@@ -2202,6 +2261,10 @@ const i18n = {
2202
2261
  'loop.kanban.noBoardData': 'No tasks to display',
2203
2262
  'loop.listView': 'List View',
2204
2263
  'loop.addTask': 'Add Task',
2264
+ 'loop.add': 'Add',
2265
+ 'loop.save': 'Save',
2266
+ 'loop.cancel': 'Cancel',
2267
+ 'loop.loadToolsError': 'Failed to load available tools. Please try again.',
2205
2268
 
2206
2269
  // Navigation & Grouping
2207
2270
  'loop.nav.groupBy': 'Group By',
@@ -2871,6 +2934,65 @@ const i18n = {
2871
2934
  'cli.fileBrowserApiError': '需要重启服务器以启用文件浏览器',
2872
2935
  'cli.fileBrowserManualHint': '请在上方输入完整路径后点击选择(如 C:\\Users\\用户名\\.gemini)',
2873
2936
 
2937
+ // CLI 历史与执行
2938
+ 'cli.executionHistory': '执行历史',
2939
+ 'cli.conversationDetail': '对话详情',
2940
+ 'cli.nativeSessionDetail': '原生会话详情',
2941
+ 'cli.viewFullConversation': '查看完整过程对话',
2942
+ 'cli.perTurnView': '按轮次查看',
2943
+ 'cli.concatenatedView': '合并视图',
2944
+ 'cli.userPrompt': '用户提示词',
2945
+ 'cli.assistantResponse': '助手回复',
2946
+ 'cli.user': '用户',
2947
+ 'cli.assistant': '助手',
2948
+ 'cli.latest': '最新',
2949
+ 'cli.turn': '轮次',
2950
+ 'cli.thinkingProcess': '思考过程',
2951
+ 'cli.thoughts': '个思考',
2952
+ 'cli.toolCalls': '工具调用',
2953
+ 'cli.totalTokens': '总令牌数',
2954
+ 'cli.input': '输入',
2955
+ 'cli.output': '输出',
2956
+ 'cli.cached': '已缓存',
2957
+ 'cli.concatenatedPrompt': '合并提示词(发送至 CLI)',
2958
+ 'cli.sessionId': '会话 ID',
2959
+
2960
+ // CLI 历史操作与按钮
2961
+ 'cli.refresh': '刷新',
2962
+ 'cli.copyId': '复制 ID',
2963
+ 'cli.copyFullPrompt': '复制完整提示词',
2964
+ 'cli.delete': '删除',
2965
+ 'cli.exportJson': '导出 JSON',
2966
+ 'cli.copyFilePath': '复制文件路径',
2967
+ 'cli.copySessionId': '复制会话 ID',
2968
+ 'cli.viewNativeSession': '查看原生会话',
2969
+ 'cli.viewDetails': '查看详情',
2970
+ 'cli.searchHistory': '搜索历史...',
2971
+ 'cli.allTools': '所有工具',
2972
+ 'cli.noExecutions': '暂无执行记录',
2973
+ 'cli.noMatchingResults': '无匹配结果',
2974
+
2975
+ // CLI 历史消息
2976
+ 'cli.conversationNotFound': '未找到对话',
2977
+ 'cli.nativeSessionNotFound': '未找到原生会话',
2978
+ 'cli.historyRefreshed': '历史已刷新',
2979
+ 'cli.executionDeleted': '执行记录已删除',
2980
+ 'cli.deleteFailed': '删除失败',
2981
+ 'cli.idCopied': 'ID 已复制',
2982
+ 'cli.promptCopied': '提示词已复制到剪贴板',
2983
+ 'cli.fullPromptCopied': '完整提示词已复制到剪贴板',
2984
+ 'cli.sessionIdCopied': '会话 ID 已复制',
2985
+ 'cli.filePathCopied': '文件路径已复制',
2986
+ 'cli.pathNotAvailable': '路径不可用',
2987
+ 'cli.noSessionData': '无会话数据',
2988
+ 'cli.sessionExported': '会话已导出',
2989
+ 'cli.failedToCopy': '复制失败',
2990
+ 'cli.executionNotFound': '未找到执行记录',
2991
+
2992
+ // CLI 历史确认对话框
2993
+ 'cli.confirmDelete': '删除此执行记录?此操作无法撤销。',
2994
+ 'cli.nativeSessionBadge': '原生会话',
2995
+
2874
2996
  // CodexLens 配置
2875
2997
  'codexlens.config': 'CodexLens 配置',
2876
2998
  'codexlens.configDesc': '管理代码索引、语义搜索和嵌入模型',
@@ -4796,6 +4918,10 @@ const i18n = {
4796
4918
  'loop.kanban.noBoardData': '没有要显示的任务',
4797
4919
  'loop.listView': '列表视图',
4798
4920
  'loop.addTask': '添加任务',
4921
+ 'loop.add': '添加',
4922
+ 'loop.save': '保存',
4923
+ 'loop.cancel': '取消',
4924
+ 'loop.loadToolsError': '加载可用工具失败,请重试。',
4799
4925
 
4800
4926
  // Navigation & Grouping
4801
4927
  'loop.nav.groupBy': '分组',
@@ -36,10 +36,12 @@ const sessionDataStore = {};
36
36
  // Store lite task session data for detail page access
37
37
  // Key: session key, Value: lite session data object
38
38
  const liteTaskDataStore = {};
39
+ window.liteTaskDataStore = liteTaskDataStore;
39
40
 
40
41
  // Store task JSON data in a global map instead of inline script tags
41
42
  // Key: unique task ID, Value: raw task JSON data
42
43
  const taskJsonStore = {};
44
+ window.taskJsonStore = taskJsonStore;
43
45
 
44
46
  // ========== Global Notification Queue ==========
45
47
  // Notification queue visible from any view (persisted to localStorage)
@@ -570,7 +570,7 @@ var fileBrowserState = {
570
570
 
571
571
  function showFileBrowserModal(onSelect) {
572
572
  fileBrowserState.onSelect = onSelect;
573
- fileBrowserState.showHidden = false;
573
+ fileBrowserState.showHidden = true;
574
574
 
575
575
  // Create modal overlay
576
576
  var overlay = document.createElement('div');
@@ -185,6 +185,14 @@ function renderIssueView() {
185
185
  </div>
186
186
 
187
187
  <div class="flex items-center gap-3">
188
+ <!-- Pull from GitHub Button -->
189
+ <button class="issue-pull-btn" onclick="showPullIssuesModal()" title="Pull issues from GitHub repository">
190
+ <svg class="w-4 h-4 mr-1.5" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
191
+ <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v 3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
192
+ </svg>
193
+ <span>Pull from GitHub</span>
194
+ </button>
195
+
188
196
  <!-- Create Button -->
189
197
  <button class="issue-create-btn" onclick="showCreateIssueModal()">
190
198
  <i data-lucide="plus" class="w-4 h-4"></i>
@@ -281,6 +289,59 @@ function renderIssueView() {
281
289
  </div>
282
290
  </div>
283
291
  </div>
292
+
293
+ <!-- Pull Issues Modal -->
294
+ <div id="pullIssuesModal" class="issue-modal hidden">
295
+ <div class="issue-modal-backdrop" onclick="hidePullIssuesModal()"></div>
296
+ <div class="issue-modal-content">
297
+ <div class="issue-modal-header">
298
+ <h3>
299
+ <svg class="w-5 h-5 inline mr-2 -mt-1" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
300
+ <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
301
+ </svg>
302
+ Pull Issues from GitHub
303
+ </h3>
304
+ <button class="btn-icon" onclick="hidePullIssuesModal()">
305
+ <i data-lucide="x" class="w-5 h-5"></i>
306
+ </button>
307
+ </div>
308
+ <div class="issue-modal-body">
309
+ <div class="form-group">
310
+ <label>Issue State</label>
311
+ <select id="pullIssueState">
312
+ <option value="open" selected>Open</option>
313
+ <option value="closed">Closed</option>
314
+ <option value="all">All</option>
315
+ </select>
316
+ </div>
317
+ <div class="form-group">
318
+ <label>Maximum Issues</label>
319
+ <input type="number" id="pullIssueLimit" value="20" min="1" max="100" />
320
+ </div>
321
+ <div class="form-group">
322
+ <label>Labels (optional)</label>
323
+ <input type="text" id="pullIssueLabels" placeholder="bug, enhancement (comma-separated)" />
324
+ </div>
325
+ <div class="form-group">
326
+ <label class="checkbox-label">
327
+ <input type="checkbox" id="pullDownloadImages" checked />
328
+ <span>Download images to local</span>
329
+ </label>
330
+ <p class="form-hint text-xs text-muted-foreground mt-1">Images will be saved to .workflow/issues/images/ and links updated in issue context</p>
331
+ </div>
332
+ <div id="pullIssueResult" class="pull-result hidden mt-4 p-3 rounded-md bg-muted"></div>
333
+ </div>
334
+ <div class="issue-modal-footer">
335
+ <button class="btn-secondary" onclick="hidePullIssuesModal()">Cancel</button>
336
+ <button class="btn-primary" id="pullIssuesBtn" onclick="pullGitHubIssues()">
337
+ <svg class="w-4 h-4 mr-1 inline" viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
338
+ <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
339
+ </svg>
340
+ Pull Issues
341
+ </button>
342
+ </div>
343
+ </div>
344
+ </div>
284
345
  </div>
285
346
  `;
286
347
 
@@ -650,7 +711,7 @@ function renderQueueCard(queue, isActive) {
650
711
  <span class="queue-card-id font-mono">${safeQueueId}</span>
651
712
  <div class="queue-card-badges">
652
713
  ${isActive ? '<span class="queue-active-badge">Active</span>' : ''}
653
- <span class="queue-status-badge ${statusClass}">${queue.status || 'unknown'}</span>
714
+ ${!isActive || queue.status !== 'active' ? `<span class="queue-status-badge ${statusClass}">${queue.status || 'unknown'}</span>` : ''}
654
715
  </div>
655
716
  </div>
656
717
 
@@ -2627,6 +2688,127 @@ function hideCreateIssueModal() {
2627
2688
  }
2628
2689
  }
2629
2690
 
2691
+ // ========== Pull Issues Modal ==========
2692
+ function showPullIssuesModal() {
2693
+ const modal = document.getElementById('pullIssuesModal');
2694
+ if (modal) {
2695
+ modal.classList.remove('hidden');
2696
+ // Reset result area
2697
+ const resultDiv = document.getElementById('pullIssueResult');
2698
+ if (resultDiv) {
2699
+ resultDiv.classList.add('hidden');
2700
+ resultDiv.innerHTML = '';
2701
+ }
2702
+ lucide.createIcons();
2703
+ }
2704
+ }
2705
+
2706
+ function hidePullIssuesModal() {
2707
+ const modal = document.getElementById('pullIssuesModal');
2708
+ if (modal) {
2709
+ modal.classList.add('hidden');
2710
+ // Clear form
2711
+ const stateSelect = document.getElementById('pullIssueState');
2712
+ const limitInput = document.getElementById('pullIssueLimit');
2713
+ const labelsInput = document.getElementById('pullIssueLabels');
2714
+ const downloadImagesCheck = document.getElementById('pullDownloadImages');
2715
+ if (stateSelect) stateSelect.value = 'open';
2716
+ if (limitInput) limitInput.value = '20';
2717
+ if (labelsInput) labelsInput.value = '';
2718
+ if (downloadImagesCheck) downloadImagesCheck.checked = true;
2719
+ }
2720
+ }
2721
+
2722
+ async function pullGitHubIssues() {
2723
+ const stateSelect = document.getElementById('pullIssueState');
2724
+ const limitInput = document.getElementById('pullIssueLimit');
2725
+ const labelsInput = document.getElementById('pullIssueLabels');
2726
+ const downloadImagesCheck = document.getElementById('pullDownloadImages');
2727
+ const resultDiv = document.getElementById('pullIssueResult');
2728
+ const pullBtn = document.getElementById('pullIssuesBtn');
2729
+
2730
+ const state = stateSelect?.value || 'open';
2731
+ const limit = parseInt(limitInput?.value || '20');
2732
+ const labels = labelsInput?.value?.trim();
2733
+ const downloadImages = downloadImagesCheck?.checked || false;
2734
+
2735
+ // Disable button and show loading
2736
+ if (pullBtn) {
2737
+ pullBtn.disabled = true;
2738
+ pullBtn.innerHTML = '<i data-lucide="loader-2" class="w-4 h-4 mr-1 animate-spin"></i>' + (t('common.loading') || 'Loading...');
2739
+ lucide.createIcons();
2740
+ }
2741
+
2742
+ try {
2743
+ const params = new URLSearchParams({
2744
+ path: projectPath,
2745
+ state: state,
2746
+ limit: limit.toString(),
2747
+ downloadImages: downloadImages.toString()
2748
+ });
2749
+ if (labels) params.set('labels', labels);
2750
+
2751
+ const response = await fetch('/api/issues/pull?' + params.toString(), {
2752
+ method: 'POST'
2753
+ });
2754
+
2755
+ const result = await response.json();
2756
+
2757
+ if (!response.ok || result.error) {
2758
+ showNotification(result.error || 'Failed to pull issues', 'error');
2759
+ if (resultDiv) {
2760
+ resultDiv.classList.remove('hidden');
2761
+ resultDiv.innerHTML = `<p class="text-destructive">${result.error || 'Failed to pull issues'}</p>`;
2762
+ }
2763
+ return;
2764
+ }
2765
+
2766
+ // Show results
2767
+ if (resultDiv) {
2768
+ resultDiv.classList.remove('hidden');
2769
+ resultDiv.innerHTML = `
2770
+ <div class="flex items-start gap-2">
2771
+ <i data-lucide="check-circle" class="w-5 h-5 text-success mt-0.5"></i>
2772
+ <div class="flex-1">
2773
+ <p class="font-medium mb-2">${t('issues.pullSuccess') || 'GitHub Issues Pulled Successfully'}</p>
2774
+ <div class="text-sm text-muted-foreground space-y-1">
2775
+ <p>✓ Imported: <strong>${result.imported || 0}</strong> new issues</p>
2776
+ <p>✓ Updated: <strong>${result.updated || 0}</strong> existing issues</p>
2777
+ <p>✓ Skipped: <strong>${result.skipped || 0}</strong> unchanged issues</p>
2778
+ ${result.images_downloaded > 0 ? `<p>✓ Downloaded: <strong>${result.images_downloaded}</strong> images</p>` : ''}
2779
+ </div>
2780
+ </div>
2781
+ </div>
2782
+ `;
2783
+ lucide.createIcons();
2784
+ }
2785
+
2786
+ showNotification(`Pulled ${result.imported + result.updated} issues from GitHub`, 'success');
2787
+
2788
+ // Reload data after 1 second
2789
+ setTimeout(async () => {
2790
+ await loadIssueData();
2791
+ renderIssueView();
2792
+ hidePullIssuesModal();
2793
+ }, 1500);
2794
+
2795
+ } catch (err) {
2796
+ console.error('Failed to pull issues:', err);
2797
+ showNotification('Failed to pull issues', 'error');
2798
+ if (resultDiv) {
2799
+ resultDiv.classList.remove('hidden');
2800
+ resultDiv.innerHTML = `<p class="text-destructive">${err.message || 'Unknown error occurred'}</p>`;
2801
+ }
2802
+ } finally {
2803
+ // Re-enable button
2804
+ if (pullBtn) {
2805
+ pullBtn.disabled = false;
2806
+ pullBtn.innerHTML = '<i data-lucide="download" class="w-4 h-4 mr-1"></i>' + (t('issues.pull') || 'Pull');
2807
+ lucide.createIcons();
2808
+ }
2809
+ }
2810
+ }
2811
+
2630
2812
  async function createIssue() {
2631
2813
  const idInput = document.getElementById('newIssueId');
2632
2814
  const titleInput = document.getElementById('newIssueTitle');
@@ -418,7 +418,7 @@ function showMultiCliDetailPage(sessionKey) {
418
418
  </div>
419
419
 
420
420
  <!-- Tab Content -->
421
- <div class="detail-tab-content" id="multiCliDetailTabContent">
421
+ <div class="detail-tab-content active" id="multiCliDetailTabContent">
422
422
  ${renderMultiCliTasksTab(session)}
423
423
  </div>
424
424
  </div>
@@ -653,12 +653,17 @@ function switchMultiCliDetailTab(tabName) {
653
653
  break;
654
654
  case 'context':
655
655
  loadAndRenderMultiCliContextTab(session, contentArea);
656
+ contentArea.classList.add('active');
656
657
  return; // Early return as this is async
657
658
  case 'summary':
658
659
  loadAndRenderMultiCliSummaryTab(session, contentArea);
660
+ contentArea.classList.add('active');
659
661
  return; // Early return as this is async
660
662
  }
661
663
 
664
+ // Add active class to show content
665
+ contentArea.classList.add('active');
666
+
662
667
  // Re-initialize after tab switch
663
668
  setTimeout(() => {
664
669
  if (typeof lucide !== 'undefined') lucide.createIcons();
@@ -1097,13 +1102,52 @@ function renderMultiCliSummaryContent(summary, session) {
1097
1102
  <span class="section-label"><i data-lucide="lightbulb" class="w-4 h-4 inline mr-1"></i> ${t('multiCli.summary.solutions')} (${synthesis.solutions.length})</span>
1098
1103
  </div>
1099
1104
  <div class="collapsible-content collapsed">
1100
- ${synthesis.solutions.map((sol, idx) => `
1101
- <div class="solution-summary-item">
1102
- <span class="solution-num">#${idx + 1}</span>
1103
- <span class="solution-name">${escapeHtml(getI18nText(sol.title) || sol.id || `${t('multiCli.summary.solution')} ${idx + 1}`)}</span>
1104
- ${sol.feasibility?.score ? `<span class="feasibility-badge">${Math.round(sol.feasibility.score * 100)}%</span>` : ''}
1105
- </div>
1106
- `).join('')}
1105
+ ${synthesis.solutions.map((sol, idx) => {
1106
+ const name = getI18nText(sol.name) || sol.title || sol.id || `${t('multiCli.summary.solution')} ${idx + 1}`;
1107
+ const summary = getI18nText(sol.summary) || '';
1108
+ const feasibility = sol.feasibility?.score || sol.feasibility || 0;
1109
+ const effort = sol.effort || '';
1110
+ const risk = sol.risk || '';
1111
+ const pros = sol.pros || [];
1112
+ const cons = sol.cons || [];
1113
+
1114
+ return `
1115
+ <div class="solution-card">
1116
+ <div class="solution-header">
1117
+ <div class="solution-title-row">
1118
+ <span class="solution-num">#${idx + 1}</span>
1119
+ <span class="solution-name">${escapeHtml(name)}</span>
1120
+ </div>
1121
+ <div class="solution-badges">
1122
+ ${feasibility ? `<span class="badge feasibility">${Math.round(feasibility * 100)}%</span>` : ''}
1123
+ ${effort ? `<span class="badge effort ${escapeHtml(effort)}">${escapeHtml(effort)}</span>` : ''}
1124
+ ${risk ? `<span class="badge risk ${escapeHtml(risk)}">${escapeHtml(risk)}</span>` : ''}
1125
+ </div>
1126
+ </div>
1127
+ ${summary ? `
1128
+ <div class="solution-summary">
1129
+ <p>${escapeHtml(summary)}</p>
1130
+ </div>
1131
+ ` : ''}
1132
+ ${pros.length > 0 ? `
1133
+ <div class="solution-details">
1134
+ <h5 class="details-label">✓ ${t('multiCli.summary.pros') || 'Pros'}:</h5>
1135
+ <ul class="details-list">
1136
+ ${pros.map(p => `<li>${escapeHtml(getI18nText(p) || p)}</li>`).join('')}
1137
+ </ul>
1138
+ </div>
1139
+ ` : ''}
1140
+ ${cons.length > 0 ? `
1141
+ <div class="solution-details">
1142
+ <h5 class="details-label">✗ ${t('multiCli.summary.cons') || 'Cons'}:</h5>
1143
+ <ul class="details-list">
1144
+ ${cons.map(c => `<li>${escapeHtml(getI18nText(c) || c)}</li>`).join('')}
1145
+ </ul>
1146
+ </div>
1147
+ ` : ''}
1148
+ </div>
1149
+ `;
1150
+ }).join('')}
1107
1151
  </div>
1108
1152
  </div>
1109
1153
  `);
@@ -2722,12 +2766,12 @@ function showLiteTaskDetailPage(sessionKey) {
2722
2766
  <div class="detail-header">
2723
2767
  <button class="btn-back" onclick="goBackToLiteTasks()">
2724
2768
  <span class="back-icon">←</span>
2725
- <span>Back to ${session.type === 'lite-plan' ? 'Lite Plan' : 'Lite Fix'}</span>
2769
+ <span>${session.type === 'lite-plan' ? t('lite.backToList', { type: 'Plan' }) : session.type === 'lite-fix' ? t('lite.backToList', { type: 'Fix' }) : t('multiCli.backToList')}</span>
2726
2770
  </button>
2727
2771
  <div class="detail-title-row">
2728
- <h2 class="detail-session-id">${session.type === 'lite-plan' ? '<i data-lucide="file-edit" class="w-5 h-5 inline mr-2"></i>' : '<i data-lucide="wrench" class="w-5 h-5 inline mr-2"></i>'} ${escapeHtml(session.id)}</h2>
2772
+ <h2 class="detail-session-id">${session.type === 'lite-plan' ? '<i data-lucide="file-edit" class="w-5 h-5 inline mr-2"></i>' : session.type === 'lite-fix' ? '<i data-lucide="wrench" class="w-5 h-5 inline mr-2"></i>' : '<i data-lucide="speech-icon" class="w-5 h-5 inline mr-2"></i>'} ${escapeHtml(session.id)}</h2>
2729
2773
  <div class="detail-badges">
2730
- <span class="session-type-badge ${session.type}">${session.type}</span>
2774
+ <span class="session-type-badge ${session.type}">${session.type === 'multi-cli-plan' ? 'MULTI-CLI' : session.type}</span>
2731
2775
  </div>
2732
2776
  </div>
2733
2777
  </div>
@@ -1012,15 +1012,24 @@ async function saveTaskOrder(loopId, newOrder) {
1012
1012
 
1013
1013
  /**
1014
1014
  * Show add task modal
1015
+ * Loads enabled tools before displaying modal to prevent race conditions
1015
1016
  */
1016
1017
  async function showAddTaskModal(loopId) {
1017
- // Get enabled tools
1018
- const enabledTools = await getEnabledTools();
1019
-
1020
- // Build tool options HTML
1021
- const toolOptions = enabledTools.map(tool =>
1022
- `<option value="${tool}">${tool.charAt(0).toUpperCase() + tool.slice(1)}</option>`
1023
- ).join('');
1018
+ // Find and disable the "Add Task" button to prevent multiple clicks during loading
1019
+ const addTaskButton = event?.target;
1020
+ if (addTaskButton) {
1021
+ addTaskButton.disabled = true;
1022
+ const originalText = addTaskButton.innerHTML;
1023
+ addTaskButton.innerHTML = '<i class="spinner"></i> ' + (t('common.loading') || 'Loading...');
1024
+
1025
+ try {
1026
+ // Get enabled tools (this ensures tools are loaded before modal opens)
1027
+ const enabledTools = await getEnabledTools();
1028
+
1029
+ // Build tool options HTML
1030
+ const toolOptions = enabledTools.map(tool =>
1031
+ `<option value="${tool}">${tool.charAt(0).toUpperCase() + tool.slice(1)}</option>`
1032
+ ).join('');
1024
1033
 
1025
1034
  const modal = document.createElement('div');
1026
1035
  modal.id = 'addTaskModal';
@@ -1075,11 +1084,103 @@ async function showAddTaskModal(loopId) {
1075
1084
  </div>
1076
1085
  `;
1077
1086
 
1078
- document.body.appendChild(modal);
1079
- if (typeof lucide !== 'undefined') lucide.createIcons();
1087
+ document.body.appendChild(modal);
1088
+ if (typeof lucide !== 'undefined') lucide.createIcons();
1080
1089
 
1081
- // Focus on description field
1082
- setTimeout(() => document.getElementById('taskDescription').focus(), 100);
1090
+ // Focus on description field
1091
+ setTimeout(() => document.getElementById('taskDescription').focus(), 100);
1092
+
1093
+ } catch (err) {
1094
+ console.error('Failed to show add task modal:', err);
1095
+ alert(t('loop.loadToolsError') || 'Failed to load available tools. Please try again.');
1096
+ } finally {
1097
+ // Restore button state
1098
+ if (addTaskButton) {
1099
+ addTaskButton.disabled = false;
1100
+ addTaskButton.innerHTML = originalText;
1101
+ }
1102
+ }
1103
+ } else {
1104
+ // Fallback if event is not available (shouldn't happen normally)
1105
+ const enabledTools = await getEnabledTools();
1106
+ const toolOptions = enabledTools.map(tool =>
1107
+ `<option value="${tool}">${tool.charAt(0).toUpperCase() + tool.slice(1)}</option>`
1108
+ ).join('');
1109
+
1110
+ const modal = document.createElement('div');
1111
+ modal.id = 'addTaskModal';
1112
+ modal.className = 'modal-overlay';
1113
+ modal.innerHTML = `
1114
+ <div class="modal-content">
1115
+ <div class="modal-header">
1116
+ <h3><i data-lucide="plus-circle" class="w-5 h-5"></i> ${t('loop.addTask') || 'Add Task'}</h3>
1117
+ <button class="modal-close" onclick="closeTaskModal()">
1118
+ <i data-lucide="x" class="w-5 h-5"></i>
1119
+ </button>
1120
+ </div>
1121
+ <div class="modal-body">
1122
+ <form id="addTaskForm" onsubmit="handleAddTask(event, '${loopId}')">
1123
+ <div id="addTaskError" class="alert alert-error" style="display: none;"></div>
1124
+
1125
+ <!-- Description -->
1126
+ <div class="form-group">
1127
+ <label for="taskDescription">${t('loop.taskDescription') || 'Task Description'} <span class="required">*</span></label>
1128
+ <textarea id="taskDescription" name="description" rows="3" required
1129
+ placeholder="${t('loop.taskDescriptionPlaceholder') || 'Describe what this task should do...'}"
1130
+ class="form-control"></textarea>
1131
+ </div>
1132
+
1133
+ <!-- Tool -->
1134
+ <div class="form-group">
1135
+ <label for="taskTool">${t('loop.tool') || 'Tool'}</label>
1136
+ <select id="taskTool" name="tool" class="form-control">
1137
+ ${toolOptions}
1138
+ </select>
1139
+ </div>
1140
+
1141
+ <!-- Mode -->
1142
+ <div class="form-group">
1143
+ <label for="taskMode">${t('loop.mode') || 'Mode'}</label>
1144
+ <select id="taskMode" name="mode" class="form-control">
1145
+ <option value="analysis">${t('loop.modeAnalysis') || 'Analysis'}</option>
1146
+ <option value="write">${t('loop.modeWrite') || 'Write'}</option>
1147
+ <option value="review">${t('loop.modeReview') || 'Review'}</option>
1148
+ </select>
1149
+ </div>
1150
+
1151
+ <!-- Prompt Template -->
1152
+ <div class="form-group">
1153
+ <label for="taskPrompt">${t('loop.promptTemplate') || 'Prompt Template'} <span class="required">*</span></label>
1154
+ <textarea id="taskPrompt" name="prompt_template" rows="5" required
1155
+ placeholder="${t('loop.promptPlaceholder') || 'Enter the prompt to execute...'}"
1156
+ class="form-control"></textarea>
1157
+ <small class="form-help">${t('loop.promptHelp') || 'Variables: {iteration}, {output_prev}'}</small>
1158
+ </div>
1159
+
1160
+ <!-- Error Handling -->
1161
+ <div class="form-group">
1162
+ <label for="taskOnError">${t('loop.onError') || 'On Error'}</label>
1163
+ <select id="taskOnError" name="on_error" class="form-control">
1164
+ <option value="continue">${t('loop.errorContinue') || 'Continue'}</option>
1165
+ <option value="pause">${t('loop.errorPause') || 'Pause'}</option>
1166
+ <option value="fail_fast">${t('loop.errorFailFast') || 'Fail Fast'}</option>
1167
+ </select>
1168
+ </div>
1169
+
1170
+ <!-- Form Actions -->
1171
+ <div class="modal-footer">
1172
+ <button type="button" class="btn btn-secondary" onclick="closeTaskModal()">${t('loop.cancel') || 'Cancel'}</button>
1173
+ <button type="submit" class="btn btn-primary">${t('loop.add') || 'Add'}</button>
1174
+ </div>
1175
+ </form>
1176
+ </div>
1177
+ </div>
1178
+ `;
1179
+
1180
+ document.body.appendChild(modal);
1181
+ if (typeof lucide !== 'undefined') lucide.createIcons();
1182
+ setTimeout(() => document.getElementById('taskDescription').focus(), 100);
1183
+ }
1083
1184
  }
1084
1185
 
1085
1186
  /**