@assistkick/create 1.10.0 → 1.12.0

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 (209) hide show
  1. package/dist/src/scaffolder.d.ts +12 -1
  2. package/dist/src/scaffolder.js +40 -3
  3. package/dist/src/scaffolder.js.map +1 -1
  4. package/package.json +1 -1
  5. package/templates/assistkick-product-system/package.json +1 -1
  6. package/templates/assistkick-product-system/packages/backend/package.json +1 -0
  7. package/templates/assistkick-product-system/packages/backend/src/mcp/permission_mcp_server.ts +196 -0
  8. package/templates/assistkick-product-system/packages/backend/src/routes/agents.ts +31 -7
  9. package/templates/assistkick-product-system/packages/backend/src/routes/auth.ts +15 -12
  10. package/templates/assistkick-product-system/packages/backend/src/routes/chat_files.test.ts +95 -0
  11. package/templates/assistkick-product-system/packages/backend/src/routes/chat_files.ts +97 -0
  12. package/templates/assistkick-product-system/packages/backend/src/routes/chat_permission.ts +94 -0
  13. package/templates/assistkick-product-system/packages/backend/src/routes/chat_sessions.ts +189 -0
  14. package/templates/assistkick-product-system/packages/backend/src/routes/chat_upload.test.ts +131 -0
  15. package/templates/assistkick-product-system/packages/backend/src/routes/chat_upload.ts +94 -0
  16. package/templates/assistkick-product-system/packages/backend/src/routes/files.test.ts +12 -3
  17. package/templates/assistkick-product-system/packages/backend/src/routes/files.ts +2 -2
  18. package/templates/assistkick-product-system/packages/backend/src/routes/git.ts +390 -22
  19. package/templates/assistkick-product-system/packages/backend/src/routes/git_branches.test.ts +306 -0
  20. package/templates/assistkick-product-system/packages/backend/src/routes/git_connect.test.ts +133 -0
  21. package/templates/assistkick-product-system/packages/backend/src/routes/pipeline.ts +66 -9
  22. package/templates/assistkick-product-system/packages/backend/src/routes/preview.ts +204 -0
  23. package/templates/assistkick-product-system/packages/backend/src/routes/projects.test.ts +205 -0
  24. package/templates/assistkick-product-system/packages/backend/src/routes/projects.ts +37 -9
  25. package/templates/assistkick-product-system/packages/backend/src/routes/skills.test.ts +139 -0
  26. package/templates/assistkick-product-system/packages/backend/src/routes/skills.ts +95 -0
  27. package/templates/assistkick-product-system/packages/backend/src/routes/terminal.ts +5 -4
  28. package/templates/assistkick-product-system/packages/backend/src/routes/users.ts +4 -4
  29. package/templates/assistkick-product-system/packages/backend/src/routes/video.ts +8 -8
  30. package/templates/assistkick-product-system/packages/backend/src/routes/workflow_groups.ts +5 -5
  31. package/templates/assistkick-product-system/packages/backend/src/routes/workflows.ts +6 -6
  32. package/templates/assistkick-product-system/packages/backend/src/server.ts +107 -27
  33. package/templates/assistkick-product-system/packages/backend/src/services/agent_service.test.ts +105 -203
  34. package/templates/assistkick-product-system/packages/backend/src/services/agent_service.ts +76 -266
  35. package/templates/assistkick-product-system/packages/backend/src/services/chat_cli_bridge.test.ts +427 -0
  36. package/templates/assistkick-product-system/packages/backend/src/services/chat_cli_bridge.ts +345 -0
  37. package/templates/assistkick-product-system/packages/backend/src/services/chat_message_repository.test.ts +170 -0
  38. package/templates/assistkick-product-system/packages/backend/src/services/chat_message_repository.ts +106 -0
  39. package/templates/assistkick-product-system/packages/backend/src/services/chat_session_service.test.ts +217 -0
  40. package/templates/assistkick-product-system/packages/backend/src/services/chat_session_service.ts +188 -0
  41. package/templates/assistkick-product-system/packages/backend/src/services/chat_ws_handler.test.ts +1243 -0
  42. package/templates/assistkick-product-system/packages/backend/src/services/chat_ws_handler.ts +894 -0
  43. package/templates/assistkick-product-system/packages/backend/src/services/coherence-review.ts +3 -3
  44. package/templates/assistkick-product-system/packages/backend/src/services/dev_command_detector.test.ts +85 -0
  45. package/templates/assistkick-product-system/packages/backend/src/services/dev_command_detector.ts +54 -0
  46. package/templates/assistkick-product-system/packages/backend/src/services/email_service.ts +13 -10
  47. package/templates/assistkick-product-system/packages/backend/src/services/init.ts +11 -3
  48. package/templates/assistkick-product-system/packages/backend/src/services/invitation_service.ts +1 -1
  49. package/templates/assistkick-product-system/packages/backend/src/services/password_reset_service.ts +1 -1
  50. package/templates/assistkick-product-system/packages/backend/src/services/permission_service.test.ts +243 -0
  51. package/templates/assistkick-product-system/packages/backend/src/services/permission_service.ts +259 -0
  52. package/templates/assistkick-product-system/packages/backend/src/services/preview_server_manager.test.ts +172 -0
  53. package/templates/assistkick-product-system/packages/backend/src/services/preview_server_manager.ts +225 -0
  54. package/templates/assistkick-product-system/packages/backend/src/services/project_service.test.ts +29 -0
  55. package/templates/assistkick-product-system/packages/backend/src/services/project_service.ts +17 -0
  56. package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.test.ts +255 -0
  57. package/templates/assistkick-product-system/packages/backend/src/services/project_workspace_service.ts +300 -25
  58. package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.test.ts +44 -0
  59. package/templates/assistkick-product-system/packages/backend/src/services/pty_session_manager.ts +62 -7
  60. package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.test.ts +77 -6
  61. package/templates/assistkick-product-system/packages/backend/src/services/ssh_key_service.ts +129 -8
  62. package/templates/assistkick-product-system/packages/backend/src/services/terminal_ws_handler.ts +2 -1
  63. package/templates/assistkick-product-system/packages/backend/src/services/title_generator_service.test.ts +45 -0
  64. package/templates/assistkick-product-system/packages/backend/src/services/title_generator_service.ts +157 -0
  65. package/templates/assistkick-product-system/packages/backend/src/services/tts_service.ts +4 -3
  66. package/templates/assistkick-product-system/packages/backend/src/services/video_render_service.ts +3 -3
  67. package/templates/assistkick-product-system/packages/frontend/package.json +5 -0
  68. package/templates/assistkick-product-system/packages/frontend/src/App.tsx +2 -0
  69. package/templates/assistkick-product-system/packages/frontend/src/api/client.ts +336 -5
  70. package/templates/assistkick-product-system/packages/frontend/src/components/AgentsView.tsx +192 -12
  71. package/templates/assistkick-product-system/packages/frontend/src/components/AttachmentPreviewList.tsx +98 -0
  72. package/templates/assistkick-product-system/packages/frontend/src/components/AutocompleteDropdown.tsx +65 -0
  73. package/templates/assistkick-product-system/packages/frontend/src/components/ChatAttachButton.tsx +56 -0
  74. package/templates/assistkick-product-system/packages/frontend/src/components/ChatDropZone.tsx +80 -0
  75. package/templates/assistkick-product-system/packages/frontend/src/components/ChatMessageBubble.tsx +155 -0
  76. package/templates/assistkick-product-system/packages/frontend/src/components/ChatMessageContent.tsx +182 -0
  77. package/templates/assistkick-product-system/packages/frontend/src/components/ChatMessageInput.tsx +233 -0
  78. package/templates/assistkick-product-system/packages/frontend/src/components/ChatSessionSidebar.tsx +218 -0
  79. package/templates/assistkick-product-system/packages/frontend/src/components/ChatStopButton.tsx +32 -0
  80. package/templates/assistkick-product-system/packages/frontend/src/components/ChatTodoSidebar.tsx +113 -0
  81. package/templates/assistkick-product-system/packages/frontend/src/components/ChatView.tsx +842 -0
  82. package/templates/assistkick-product-system/packages/frontend/src/components/CommitMessageModal.tsx +82 -0
  83. package/templates/assistkick-product-system/packages/frontend/src/components/DiagramOverlay.tsx +160 -0
  84. package/templates/assistkick-product-system/packages/frontend/src/components/EditorTabBar.tsx +5 -5
  85. package/templates/assistkick-product-system/packages/frontend/src/components/FileTree.tsx +9 -10
  86. package/templates/assistkick-product-system/packages/frontend/src/components/FileTreeInlineInput.tsx +5 -5
  87. package/templates/assistkick-product-system/packages/frontend/src/components/FilesView.tsx +112 -41
  88. package/templates/assistkick-product-system/packages/frontend/src/components/GraphLegend.tsx +2 -2
  89. package/templates/assistkick-product-system/packages/frontend/src/components/HighlightedText.tsx +87 -0
  90. package/templates/assistkick-product-system/packages/frontend/src/components/ImageLightbox.tsx +192 -0
  91. package/templates/assistkick-product-system/packages/frontend/src/components/KanbanView.tsx +2 -2
  92. package/templates/assistkick-product-system/packages/frontend/src/components/MentionPill.tsx +33 -0
  93. package/templates/assistkick-product-system/packages/frontend/src/components/MermaidBlock.tsx +148 -0
  94. package/templates/assistkick-product-system/packages/frontend/src/components/PermissionDialog.tsx +91 -0
  95. package/templates/assistkick-product-system/packages/frontend/src/components/PermissionModeSelector.tsx +229 -0
  96. package/templates/assistkick-product-system/packages/frontend/src/components/ProjectSelector.tsx +249 -83
  97. package/templates/assistkick-product-system/packages/frontend/src/components/QueuedMessageBubble.tsx +38 -0
  98. package/templates/assistkick-product-system/packages/frontend/src/components/SidePanel.tsx +212 -117
  99. package/templates/assistkick-product-system/packages/frontend/src/components/SystemPromptAccordion.tsx +48 -0
  100. package/templates/assistkick-product-system/packages/frontend/src/components/TaskIcon.tsx +11 -0
  101. package/templates/assistkick-product-system/packages/frontend/src/components/TerminalView.tsx +25 -9
  102. package/templates/assistkick-product-system/packages/frontend/src/components/ToolDiffView.tsx +114 -0
  103. package/templates/assistkick-product-system/packages/frontend/src/components/ToolResultCard.tsx +87 -0
  104. package/templates/assistkick-product-system/packages/frontend/src/components/ToolUseCard.tsx +149 -0
  105. package/templates/assistkick-product-system/packages/frontend/src/components/Toolbar.tsx +25 -8
  106. package/templates/assistkick-product-system/packages/frontend/src/components/UnifiedGitWidget.tsx +722 -0
  107. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/GroupNode.tsx +2 -0
  108. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/NodePalette.tsx +2 -1
  109. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/ProgrammableNode.tsx +178 -0
  110. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowCanvas.tsx +3 -0
  111. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/WorkflowMonitorModal.tsx +103 -9
  112. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/monitor_nodes.tsx +26 -2
  113. package/templates/assistkick-product-system/packages/frontend/src/components/workflow/workflow_types.ts +42 -1
  114. package/templates/assistkick-product-system/packages/frontend/src/hooks/useDocumentTitle.ts +11 -0
  115. package/templates/assistkick-product-system/packages/frontend/src/hooks/useProjects.ts +1 -0
  116. package/templates/assistkick-product-system/packages/frontend/src/hooks/use_chat_stream.ts +826 -0
  117. package/templates/assistkick-product-system/packages/frontend/src/hooks/use_file_tree_cache.ts +69 -0
  118. package/templates/assistkick-product-system/packages/frontend/src/hooks/use_mention_autocomplete.ts +284 -0
  119. package/templates/assistkick-product-system/packages/frontend/src/lib/attachment_manager.test.ts +183 -0
  120. package/templates/assistkick-product-system/packages/frontend/src/lib/attachment_manager.ts +150 -0
  121. package/templates/assistkick-product-system/packages/frontend/src/lib/chat_message_helpers.test.ts +305 -0
  122. package/templates/assistkick-product-system/packages/frontend/src/lib/chat_message_helpers.ts +113 -0
  123. package/templates/assistkick-product-system/packages/frontend/src/lib/context_usage_helpers.test.ts +157 -0
  124. package/templates/assistkick-product-system/packages/frontend/src/lib/context_usage_helpers.ts +95 -0
  125. package/templates/assistkick-product-system/packages/frontend/src/lib/mermaid_helpers.test.ts +65 -0
  126. package/templates/assistkick-product-system/packages/frontend/src/lib/mermaid_helpers.ts +110 -0
  127. package/templates/assistkick-product-system/packages/frontend/src/lib/message_queue.ts +66 -0
  128. package/templates/assistkick-product-system/packages/frontend/src/lib/tool_use_summary.test.ts +124 -0
  129. package/templates/assistkick-product-system/packages/frontend/src/lib/tool_use_summary.ts +112 -0
  130. package/templates/assistkick-product-system/packages/frontend/src/routes/AgentsRoute.tsx +2 -0
  131. package/templates/assistkick-product-system/packages/frontend/src/routes/ChatRoute.tsx +8 -0
  132. package/templates/assistkick-product-system/packages/frontend/src/routes/CoherenceRoute.tsx +2 -0
  133. package/templates/assistkick-product-system/packages/frontend/src/routes/DashboardLayout.tsx +0 -4
  134. package/templates/assistkick-product-system/packages/frontend/src/routes/DesignSystemRoute.tsx +2 -0
  135. package/templates/assistkick-product-system/packages/frontend/src/routes/FilesRoute.tsx +2 -0
  136. package/templates/assistkick-product-system/packages/frontend/src/routes/GraphRoute.tsx +2 -0
  137. package/templates/assistkick-product-system/packages/frontend/src/routes/KanbanRoute.tsx +2 -0
  138. package/templates/assistkick-product-system/packages/frontend/src/routes/TerminalRoute.tsx +2 -0
  139. package/templates/assistkick-product-system/packages/frontend/src/routes/UsersRoute.tsx +2 -0
  140. package/templates/assistkick-product-system/packages/frontend/src/routes/VideographyRoute.tsx +2 -0
  141. package/templates/assistkick-product-system/packages/frontend/src/routes/WorkflowsRoute.tsx +2 -0
  142. package/templates/assistkick-product-system/packages/frontend/src/routes/accept_invitation.tsx +2 -0
  143. package/templates/assistkick-product-system/packages/frontend/src/routes/forgot_password.tsx +2 -0
  144. package/templates/assistkick-product-system/packages/frontend/src/routes/login.tsx +2 -0
  145. package/templates/assistkick-product-system/packages/frontend/src/routes/register.tsx +2 -0
  146. package/templates/assistkick-product-system/packages/frontend/src/routes/reset_password.tsx +2 -0
  147. package/templates/assistkick-product-system/packages/frontend/src/stores/useAttachmentStore.ts +66 -0
  148. package/templates/assistkick-product-system/packages/frontend/src/stores/useChatSessionStore.ts +107 -0
  149. package/templates/assistkick-product-system/packages/frontend/src/stores/useMessageQueueStore.ts +110 -0
  150. package/templates/assistkick-product-system/packages/frontend/src/stores/usePreviewStore.ts +78 -0
  151. package/templates/assistkick-product-system/packages/frontend/src/stores/useProjectStore.ts +7 -0
  152. package/templates/assistkick-product-system/packages/frontend/src/stores/useSidePanelStore.ts +6 -1
  153. package/templates/assistkick-product-system/packages/frontend/src/styles/index.css +30 -357
  154. package/templates/assistkick-product-system/packages/frontend/src/utils/parse_node_markdown.test.ts +115 -0
  155. package/templates/assistkick-product-system/packages/frontend/src/utils/parse_node_markdown.ts +91 -0
  156. package/templates/assistkick-product-system/packages/frontend/src/utils/preview_utils.test.ts +30 -0
  157. package/templates/assistkick-product-system/packages/frontend/src/utils/preview_utils.ts +3 -0
  158. package/templates/assistkick-product-system/packages/shared/db/migrate.ts +82 -0
  159. package/templates/assistkick-product-system/packages/shared/db/migrations/0000_outgoing_ultron.sql +277 -0
  160. package/templates/assistkick-product-system/packages/shared/db/migrations/0015_magenta_jazinda.sql +1 -0
  161. package/templates/assistkick-product-system/packages/shared/db/migrations/0016_giant_xorn.sql +1 -0
  162. package/templates/assistkick-product-system/packages/shared/db/migrations/0017_sloppy_mentor.sql +6 -0
  163. package/templates/assistkick-product-system/packages/shared/db/migrations/0018_vengeful_kabuki.sql +9 -0
  164. package/templates/assistkick-product-system/packages/shared/db/migrations/0019_careful_sentinels.sql +8 -0
  165. package/templates/assistkick-product-system/packages/shared/db/migrations/0020_clever_spot.sql +27 -0
  166. package/templates/assistkick-product-system/packages/shared/db/migrations/0021_graceful_hex.sql +1 -0
  167. package/templates/assistkick-product-system/packages/shared/db/migrations/0022_short_kingpin.sql +1 -0
  168. package/templates/assistkick-product-system/packages/shared/db/migrations/0023_ambiguous_sharon_carter.sql +1 -0
  169. package/templates/assistkick-product-system/packages/shared/db/migrations/0024_fat_unus.sql +1 -0
  170. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0000_snapshot.json +972 -22
  171. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0015_snapshot.json +1552 -0
  172. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0016_snapshot.json +1560 -0
  173. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0017_snapshot.json +1598 -0
  174. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0018_snapshot.json +1657 -0
  175. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0019_snapshot.json +1709 -0
  176. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0020_snapshot.json +1733 -0
  177. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0021_snapshot.json +1740 -0
  178. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0022_snapshot.json +1755 -0
  179. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0023_snapshot.json +1762 -0
  180. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0024_snapshot.json +1769 -0
  181. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/_journal.json +2 -100
  182. package/templates/assistkick-product-system/packages/shared/db/schema.ts +40 -1
  183. package/templates/assistkick-product-system/packages/shared/lib/claude-service.test.ts +236 -0
  184. package/templates/assistkick-product-system/packages/shared/lib/claude-service.ts +46 -5
  185. package/templates/assistkick-product-system/packages/shared/lib/git_workflow.ts +65 -39
  186. package/templates/assistkick-product-system/packages/shared/lib/programmable_node_executor.test.ts +173 -0
  187. package/templates/assistkick-product-system/packages/shared/lib/programmable_node_executor.ts +213 -0
  188. package/templates/assistkick-product-system/packages/shared/lib/validator.test.ts +70 -0
  189. package/templates/assistkick-product-system/packages/shared/lib/validator.ts +17 -1
  190. package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.test.ts +803 -27
  191. package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.ts +502 -68
  192. package/templates/assistkick-product-system/packages/shared/lib/workflow_orchestrator.ts +4 -4
  193. package/templates/assistkick-product-system/packages/shared/package.json +2 -1
  194. package/templates/assistkick-product-system/packages/shared/test_fixtures/hanging_stream.mjs +46 -0
  195. package/templates/assistkick-product-system/packages/shared/tools/add_node.test.ts +44 -0
  196. package/templates/assistkick-product-system/packages/shared/tools/add_node.ts +7 -0
  197. package/templates/assistkick-product-system/packages/shared/tools/remove_node.ts +2 -1
  198. package/templates/assistkick-product-system/packages/shared/tools/resolve_question.ts +2 -1
  199. package/templates/assistkick-product-system/packages/shared/tools/update_node.ts +2 -1
  200. package/templates/assistkick-product-system/tests/message_queue.test.ts +178 -0
  201. package/templates/assistkick-product-system/tests/message_queue_per_session.test.ts +143 -0
  202. package/templates/skills/assistkick-bootstrap/SKILL.md +26 -26
  203. package/templates/skills/assistkick-code-reviewer/SKILL.md +45 -46
  204. package/templates/skills/assistkick-db-explorer/SKILL.md +13 -13
  205. package/templates/skills/assistkick-debugger/SKILL.md +23 -23
  206. package/templates/skills/assistkick-developer/SKILL.md +59 -63
  207. package/templates/skills/assistkick-interview/SKILL.md +26 -26
  208. package/templates/skills/assistkick-video-composition-agent/SKILL.md +231 -0
  209. package/templates/skills/assistkick-video-script-writer/SKILL.md +136 -0
@@ -5,106 +5,8 @@
5
5
  {
6
6
  "idx": 0,
7
7
  "version": "6",
8
- "when": 1772730355833,
9
- "tag": "0000_dashing_gorgon",
10
- "breakpoints": true
11
- },
12
- {
13
- "idx": 1,
14
- "version": "6",
15
- "when": 1772802625250,
16
- "tag": "0001_vengeful_wallop",
17
- "breakpoints": true
18
- },
19
- {
20
- "idx": 2,
21
- "version": "6",
22
- "when": 1772807644324,
23
- "tag": "0002_greedy_excalibur",
24
- "breakpoints": true
25
- },
26
- {
27
- "idx": 3,
28
- "version": "6",
29
- "when": 1772812820535,
30
- "tag": "0003_lonely_cyclops",
31
- "breakpoints": true
32
- },
33
- {
34
- "idx": 4,
35
- "version": "6",
36
- "when": 1772975082564,
37
- "tag": "0004_tidy_matthew_murdock",
38
- "breakpoints": true
39
- },
40
- {
41
- "idx": 5,
42
- "version": "6",
43
- "when": 1772982318304,
44
- "tag": "0005_mysterious_falcon",
45
- "breakpoints": true
46
- },
47
- {
48
- "idx": 6,
49
- "version": "6",
50
- "when": 1772984904854,
51
- "tag": "0006_next_venom",
52
- "breakpoints": true
53
- },
54
- {
55
- "idx": 7,
56
- "version": "6",
57
- "when": 1773003174080,
58
- "tag": "0007_deep_barracuda",
59
- "breakpoints": true
60
- },
61
- {
62
- "idx": 8,
63
- "version": "6",
64
- "when": 1773122459461,
65
- "tag": "0008_puzzling_hannibal_king",
66
- "breakpoints": true
67
- },
68
- {
69
- "idx": 9,
70
- "version": "6",
71
- "when": 1773127312138,
72
- "tag": "0009_amused_beast",
73
- "breakpoints": true
74
- },
75
- {
76
- "idx": 10,
77
- "version": "6",
78
- "when": 1773143546640,
79
- "tag": "0010_spotty_moira_mactaggert",
80
- "breakpoints": true
81
- },
82
- {
83
- "idx": 11,
84
- "version": "6",
85
- "when": 1773169770877,
86
- "tag": "0011_supreme_doctor_octopus",
87
- "breakpoints": true
88
- },
89
- {
90
- "idx": 12,
91
- "version": "6",
92
- "when": 1773170271654,
93
- "tag": "0011_goofy_snowbird",
94
- "breakpoints": true
95
- },
96
- {
97
- "idx": 13,
98
- "version": "6",
99
- "when": 1773179139368,
100
- "tag": "0013_reflective_prowler",
101
- "breakpoints": true
102
- },
103
- {
104
- "idx": 14,
105
- "version": "6",
106
- "when": 1773187819583,
107
- "tag": "0014_nifty_punisher",
8
+ "when": 1773826299804,
9
+ "tag": "0000_outgoing_ultron",
108
10
  "breakpoints": true
109
11
  }
110
12
  ]
@@ -130,6 +130,7 @@ export const projects = sqliteTable('projects', {
130
130
  gitAuthMethod: text('git_auth_method'),
131
131
  sshPrivateKeyEncrypted: text('ssh_private_key_encrypted'),
132
132
  sshPublicKey: text('ssh_public_key'),
133
+ previewCommand: text('preview_command'),
133
134
  createdAt: text('created_at').notNull(),
134
135
  updatedAt: text('updated_at').notNull(),
135
136
  });
@@ -141,6 +142,7 @@ export const terminalSessions = sqliteTable('terminal_sessions', {
141
142
  projectId: text('project_id').notNull(),
142
143
  projectName: text('project_name').notNull(),
143
144
  name: text('name').notNull(),
145
+ sessionType: text('session_type').notNull().default('claude'),
144
146
  createdAt: text('created_at').notNull(),
145
147
  lastUsedAt: text('last_used_at').notNull(),
146
148
  });
@@ -174,7 +176,10 @@ export const pipelineOutputs = sqliteTable('pipeline_outputs', {
174
176
  export const agents = sqliteTable('agents', {
175
177
  id: text('id').primaryKey(),
176
178
  name: text('name').notNull(),
177
- promptTemplate: text('prompt_template').notNull(),
179
+ model: text('model').notNull().default('claude-opus-4-6'),
180
+ skills: text('skills').notNull().default('[]'),
181
+ grounding: text('grounding').notNull().default(''),
182
+ defaultGrounding: text('default_grounding'),
178
183
  projectId: text('project_id'),
179
184
  isDefault: integer('is_default').notNull().default(0),
180
185
  createdAt: text('created_at').notNull(),
@@ -228,6 +233,8 @@ export const workflowNodeExecutions = sqliteTable('workflow_node_executions', {
228
233
  outputData: text('output_data'),
229
234
  error: text('error'),
230
235
  attempt: integer('attempt').notNull().default(1),
236
+ cycle: integer('cycle').notNull().default(1),
237
+ claudeSessionId: text('claude_session_id'),
231
238
  });
232
239
 
233
240
  // --- workflow_tool_calls table ---
@@ -240,6 +247,38 @@ export const workflowToolCalls = sqliteTable('workflow_tool_calls', {
240
247
  createdAt: text('created_at').notNull(),
241
248
  });
242
249
 
250
+ // --- chat_permission_rules table ---
251
+ export const chatPermissionRules = sqliteTable('chat_permission_rules', {
252
+ id: text('id').primaryKey(),
253
+ projectId: text('project_id').notNull(),
254
+ toolName: text('tool_name').notNull(),
255
+ createdAt: text('created_at').notNull(),
256
+ });
257
+
258
+ // --- chat_messages table ---
259
+ export const chatMessages = sqliteTable('chat_messages', {
260
+ id: text('id').primaryKey(),
261
+ sessionId: text('session_id').notNull(),
262
+ role: text('role').notNull(),
263
+ content: text('content').notNull(),
264
+ orderIndex: integer('order_index').notNull(),
265
+ createdAt: text('created_at').notNull(),
266
+ });
267
+
268
+ // --- chat_sessions table ---
269
+ export const chatSessions = sqliteTable('chat_sessions', {
270
+ id: text('id').primaryKey(),
271
+ claudeSessionId: text('claude_session_id').notNull(),
272
+ projectId: text('project_id').notNull(),
273
+ name: text('name').notNull(),
274
+ permissionMode: text('permission_mode'),
275
+ continuationContext: text('continuation_context'),
276
+ systemPrompt: text('system_prompt'),
277
+ contextUsageJson: text('context_usage_json'),
278
+ createdAt: text('created_at').notNull(),
279
+ updatedAt: text('updated_at').notNull(),
280
+ });
281
+
243
282
  // --- video_renders table ---
244
283
  export const videoRenders = sqliteTable('video_renders', {
245
284
  id: text('id').primaryKey(),
@@ -0,0 +1,236 @@
1
+ import { describe, it, mock } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { spawn } from 'node:child_process';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { dirname, join } from 'node:path';
6
+ import {
7
+ emitResultEvent,
8
+ emitToolUseEvents,
9
+ emitAssistantTextEvents,
10
+ emitAssistantUsage,
11
+ createClaudeService,
12
+ } from './claude-service.ts';
13
+
14
+ const __dirname = dirname(fileURLToPath(import.meta.url));
15
+ const FIXTURES_DIR = join(__dirname, '..', 'test_fixtures');
16
+ const HANGING_SCRIPT = join(FIXTURES_DIR, 'hanging_stream.mjs');
17
+
18
+ // --- Unit tests for exported event parsers ---
19
+
20
+ describe('emitResultEvent', () => {
21
+ it('fires callback with metadata for a result event', () => {
22
+ const resultJson = JSON.stringify({
23
+ type: 'result',
24
+ cost_usd: 0.05,
25
+ duration_ms: 2000,
26
+ num_turns: 3,
27
+ stop_reason: 'end_turn',
28
+ model: 'claude-opus-4-6',
29
+ });
30
+ const cb = mock.fn();
31
+ emitResultEvent(resultJson, cb);
32
+ assert.equal(cb.mock.calls.length, 1);
33
+ const metadata = cb.mock.calls[0].arguments[0];
34
+ assert.equal(metadata.costUsd, 0.05);
35
+ assert.equal(metadata.durationMs, 2000);
36
+ assert.equal(metadata.numTurns, 3);
37
+ assert.equal(metadata.stopReason, 'end_turn');
38
+ assert.equal(metadata.model, 'claude-opus-4-6');
39
+ });
40
+
41
+ it('does not fire for non-result events', () => {
42
+ const assistantJson = JSON.stringify({
43
+ type: 'assistant',
44
+ message: { content: [{ type: 'text', text: 'hello' }] },
45
+ });
46
+ const cb = mock.fn();
47
+ emitResultEvent(assistantJson, cb);
48
+ assert.equal(cb.mock.calls.length, 0);
49
+ });
50
+
51
+ it('does not fire for invalid JSON', () => {
52
+ const cb = mock.fn();
53
+ emitResultEvent('not json at all', cb);
54
+ assert.equal(cb.mock.calls.length, 0);
55
+ });
56
+
57
+ it('extracts contextWindow from modelUsage', () => {
58
+ const resultJson = JSON.stringify({
59
+ type: 'result',
60
+ model: 'claude-opus-4-6',
61
+ modelUsage: {
62
+ 'claude-opus-4-6': { contextWindow: 85 },
63
+ },
64
+ });
65
+ const cb = mock.fn();
66
+ emitResultEvent(resultJson, cb);
67
+ assert.equal(cb.mock.calls[0].arguments[0].contextWindow, 85);
68
+ });
69
+ });
70
+
71
+ describe('emitToolUseEvents', () => {
72
+ it('fires callback for tool_use blocks', () => {
73
+ const json = JSON.stringify({
74
+ type: 'assistant',
75
+ message: {
76
+ content: [
77
+ { type: 'tool_use', name: 'Read', input: { file_path: '/tmp/test.ts' } },
78
+ { type: 'text', text: 'reading file' },
79
+ { type: 'tool_use', name: 'Edit', input: { file_path: '/tmp/test.ts' } },
80
+ ],
81
+ },
82
+ });
83
+ const cb = mock.fn();
84
+ emitToolUseEvents(json, cb);
85
+ assert.equal(cb.mock.calls.length, 2);
86
+ assert.equal(cb.mock.calls[0].arguments[0], 'Read');
87
+ assert.equal(cb.mock.calls[1].arguments[0], 'Edit');
88
+ });
89
+
90
+ it('does not fire for non-assistant events', () => {
91
+ const json = JSON.stringify({ type: 'result', result: 'done' });
92
+ const cb = mock.fn();
93
+ emitToolUseEvents(json, cb);
94
+ assert.equal(cb.mock.calls.length, 0);
95
+ });
96
+ });
97
+
98
+ describe('emitAssistantTextEvents', () => {
99
+ it('fires callback for text blocks', () => {
100
+ const json = JSON.stringify({
101
+ type: 'assistant',
102
+ message: {
103
+ content: [
104
+ { type: 'text', text: 'Hello world' },
105
+ { type: 'tool_use', name: 'Read', input: {} },
106
+ { type: 'text', text: 'Goodbye' },
107
+ ],
108
+ },
109
+ });
110
+ const cb = mock.fn();
111
+ emitAssistantTextEvents(json, cb);
112
+ assert.equal(cb.mock.calls.length, 2);
113
+ assert.equal(cb.mock.calls[0].arguments[0], 'Hello world');
114
+ assert.equal(cb.mock.calls[1].arguments[0], 'Goodbye');
115
+ });
116
+ });
117
+
118
+ describe('emitAssistantUsage', () => {
119
+ it('fires callback with usage data', () => {
120
+ const json = JSON.stringify({
121
+ type: 'assistant',
122
+ message: {
123
+ content: [],
124
+ usage: { input_tokens: 100, output_tokens: 50 },
125
+ },
126
+ });
127
+ const cb = mock.fn();
128
+ emitAssistantUsage(json, cb);
129
+ assert.equal(cb.mock.calls.length, 1);
130
+ assert.deepEqual(cb.mock.calls[0].arguments[0], { input_tokens: 100, output_tokens: 50 });
131
+ });
132
+ });
133
+
134
+ // --- Integration tests for post-result timeout ---
135
+
136
+ describe('spawnClaude post-result timeout', () => {
137
+ it('kills a hanging process after result event and resolves successfully', async () => {
138
+ // This test spawns a process that emits a result event but never exits.
139
+ // We use a very short timeout (500ms) to keep the test fast.
140
+ // We can't use createClaudeService.spawnClaude directly because it hardcodes
141
+ // 'claude' as the command. Instead, we replicate the timeout logic pattern
142
+ // using spawn directly to verify the behavior.
143
+ const child = spawn('node', [HANGING_SCRIPT], {
144
+ cwd: process.cwd(),
145
+ stdio: ['pipe', 'pipe', 'pipe'],
146
+ });
147
+
148
+ const result = await new Promise<{ output: string; killedByTimeout: boolean }>((resolve) => {
149
+ let stdout = '';
150
+ let resultReceived = false;
151
+ let killedByTimeout = false;
152
+ let postResultTimer: ReturnType<typeof setTimeout> | null = null;
153
+ let sigkillTimer: ReturnType<typeof setTimeout> | null = null;
154
+ const POST_RESULT_TIMEOUT_MS = 500;
155
+
156
+ const startPostResultTimeout = () => {
157
+ if (postResultTimer) return;
158
+ resultReceived = true;
159
+ postResultTimer = setTimeout(() => {
160
+ killedByTimeout = true;
161
+ child.kill('SIGTERM');
162
+ sigkillTimer = setTimeout(() => {
163
+ try { child.kill('SIGKILL'); } catch { /* already dead */ }
164
+ }, 2_000);
165
+ }, POST_RESULT_TIMEOUT_MS);
166
+ };
167
+
168
+ child.stdout.on('data', (d) => {
169
+ const chunk = d.toString();
170
+ stdout += chunk;
171
+ for (const line of chunk.split('\n')) {
172
+ if (line.trim()) {
173
+ emitResultEvent(line.trim(), () => startPostResultTimeout());
174
+ }
175
+ }
176
+ });
177
+
178
+ child.stdin.write('test prompt');
179
+ child.stdin.end();
180
+
181
+ child.on('close', () => {
182
+ if (postResultTimer) clearTimeout(postResultTimer);
183
+ if (sigkillTimer) clearTimeout(sigkillTimer);
184
+ resolve({ output: stdout, killedByTimeout });
185
+ });
186
+ });
187
+
188
+ assert.equal(result.killedByTimeout, true, 'Process should have been killed by timeout');
189
+ assert.ok(result.output.includes('"type":"result"'), 'Output should contain result event');
190
+ });
191
+
192
+ it('does not kill the process when it exits normally before timeout', async () => {
193
+ // Process exits after 100ms, well before the 2000ms timeout
194
+ const child = spawn('node', [HANGING_SCRIPT, '--exit-after-ms', '100'], {
195
+ cwd: process.cwd(),
196
+ stdio: ['pipe', 'pipe', 'pipe'],
197
+ });
198
+
199
+ const result = await new Promise<{ killedByTimeout: boolean; exitCode: number | null }>((resolve) => {
200
+ let killedByTimeout = false;
201
+ let postResultTimer: ReturnType<typeof setTimeout> | null = null;
202
+ let sigkillTimer: ReturnType<typeof setTimeout> | null = null;
203
+
204
+ const startPostResultTimeout = () => {
205
+ if (postResultTimer) return;
206
+ postResultTimer = setTimeout(() => {
207
+ killedByTimeout = true;
208
+ child.kill('SIGTERM');
209
+ sigkillTimer = setTimeout(() => {
210
+ try { child.kill('SIGKILL'); } catch { /* already dead */ }
211
+ }, 2_000);
212
+ }, 2_000);
213
+ };
214
+
215
+ child.stdout.on('data', (d) => {
216
+ for (const line of d.toString().split('\n')) {
217
+ if (line.trim()) {
218
+ emitResultEvent(line.trim(), () => startPostResultTimeout());
219
+ }
220
+ }
221
+ });
222
+
223
+ child.stdin.write('test prompt');
224
+ child.stdin.end();
225
+
226
+ child.on('close', (code) => {
227
+ if (postResultTimer) clearTimeout(postResultTimer);
228
+ if (sigkillTimer) clearTimeout(sigkillTimer);
229
+ resolve({ killedByTimeout, exitCode: code });
230
+ });
231
+ });
232
+
233
+ assert.equal(result.killedByTimeout, false, 'Process should NOT have been killed by timeout');
234
+ assert.equal(result.exitCode, 0, 'Process should have exited normally');
235
+ });
236
+ });
@@ -205,7 +205,7 @@ export const emitAssistantUsage = (jsonStr, callback) => {
205
205
  * @returns {{ spawnClaude: function, spawnCommand: function }}
206
206
  */
207
207
  export const createClaudeService = ({ verbose = false, log: logFn }) => {
208
- const spawnClaude = (prompt, cwd, label = 'claude', { onToolUse, onResult, onTurnUsage, onAssistantText } = {} as any) => new Promise((resolve, reject) => {
208
+ const spawnClaude = (prompt, cwd, label = 'claude', { onToolUse, onResult, onTurnUsage, onAssistantText, onSpawn, sessionId, resume: resumeSessionId, postResultTimeoutMs = 60_000, model: modelOverride } = {} as any) => new Promise((resolve, reject) => {
209
209
  const promptPreview = prompt.slice(0, 100).replace(/\n/g, '\\n');
210
210
  logFn('CLAUDE', `Spawning ${label} in ${cwd} — prompt length: ${prompt.length} chars`);
211
211
  logFn('CLAUDE', `Prompt preview: "${promptPreview}..."`);
@@ -214,7 +214,19 @@ export const createClaudeService = ({ verbose = false, log: logFn }) => {
214
214
  const hasCallbacks = !!(onToolUse || onResult || onTurnUsage || onAssistantText);
215
215
  const useStreamJson = verbose || hasCallbacks;
216
216
 
217
- const claudeArgs = ['--dangerously-skip-permissions', '-p', '-'];
217
+ const claudeArgs: string[] = [];
218
+ if (resumeSessionId) {
219
+ // Resume an existing session — '--resume <id>' restores conversation context
220
+ claudeArgs.push('--resume', resumeSessionId, '--dangerously-skip-permissions', '-p', '-');
221
+ } else {
222
+ claudeArgs.push('--dangerously-skip-permissions', '-p', '-');
223
+ if (sessionId) {
224
+ claudeArgs.push('--session-id', sessionId);
225
+ }
226
+ }
227
+ if (modelOverride) {
228
+ claudeArgs.push('--model', modelOverride);
229
+ }
218
230
  if (useStreamJson) {
219
231
  claudeArgs.push('--verbose', '--output-format', 'stream-json');
220
232
  }
@@ -224,9 +236,29 @@ export const createClaudeService = ({ verbose = false, log: logFn }) => {
224
236
  env: process.env,
225
237
  stdio: ['pipe', 'pipe', 'pipe'],
226
238
  });
239
+
240
+ // Expose child process reference to caller for kill support
241
+ if (onSpawn) onSpawn(child);
227
242
  let stdout = '';
228
243
  let stderr = '';
229
244
  let lineBuf = '';
245
+ let resultReceived = false;
246
+ let killedByTimeout = false;
247
+ let postResultTimer: ReturnType<typeof setTimeout> | null = null;
248
+ let sigkillTimer: ReturnType<typeof setTimeout> | null = null;
249
+
250
+ const startPostResultTimeout = () => {
251
+ if (postResultTimer || !useStreamJson) return;
252
+ resultReceived = true;
253
+ postResultTimer = setTimeout(() => {
254
+ logFn('CLAUDE', `WARNING: ${label} process did not exit after result event — killing after ${postResultTimeoutMs / 1000}s timeout`);
255
+ killedByTimeout = true;
256
+ child.kill('SIGTERM');
257
+ sigkillTimer = setTimeout(() => {
258
+ try { child.kill('SIGKILL'); } catch { /* already dead */ }
259
+ }, 5_000);
260
+ }, postResultTimeoutMs);
261
+ };
230
262
 
231
263
  const tag = `${label.toUpperCase()}`;
232
264
 
@@ -241,7 +273,10 @@ export const createClaudeService = ({ verbose = false, log: logFn }) => {
241
273
  if (line.trim()) {
242
274
  if (verbose) formatStreamEvent(line.trim(), tag);
243
275
  if (onToolUse) emitToolUseEvents(line.trim(), onToolUse);
244
- if (onResult) emitResultEvent(line.trim(), onResult);
276
+ emitResultEvent(line.trim(), (metadata) => {
277
+ if (onResult) onResult(metadata);
278
+ startPostResultTimeout();
279
+ });
245
280
  if (onTurnUsage) emitAssistantUsage(line.trim(), onTurnUsage);
246
281
  if (onAssistantText) emitAssistantTextEvents(line.trim(), onAssistantText);
247
282
  }
@@ -264,6 +299,8 @@ export const createClaudeService = ({ verbose = false, log: logFn }) => {
264
299
  logFn('CLAUDE', `Prompt written to stdin, waiting for ${label} to complete...`);
265
300
 
266
301
  child.on('close', code => {
302
+ if (postResultTimer) clearTimeout(postResultTimer);
303
+ if (sigkillTimer) clearTimeout(sigkillTimer);
267
304
  if (useStreamJson && lineBuf.trim()) {
268
305
  if (verbose) formatStreamEvent(lineBuf.trim(), tag);
269
306
  if (onToolUse) emitToolUseEvents(lineBuf.trim(), onToolUse);
@@ -271,9 +308,13 @@ export const createClaudeService = ({ verbose = false, log: logFn }) => {
271
308
  if (onAssistantText) emitAssistantTextEvents(lineBuf.trim(), onAssistantText);
272
309
  if (onTurnUsage) emitAssistantUsage(lineBuf.trim(), onTurnUsage);
273
310
  }
274
- if (code === 0) {
311
+ if (code === 0 || killedByTimeout) {
275
312
  const result = useStreamJson ? extractResultText(stdout) : stdout;
276
- logFn('CLAUDE', `${label} OK — result length: ${result.length} chars`);
313
+ if (killedByTimeout) {
314
+ logFn('CLAUDE', `${label} — process killed by post-result timeout, treating as success (result length: ${result.length} chars)`);
315
+ } else {
316
+ logFn('CLAUDE', `${label} OK — result length: ${result.length} chars`);
317
+ }
277
318
  resolve(result);
278
319
  } else {
279
320
  logFn('CLAUDE', `${label} FAIL exit=${code} stderr=${stderr.slice(0, 500).trim()}`);