@assistkick/create 1.10.0 → 1.11.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 (206) 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/migrations/0015_magenta_jazinda.sql +1 -0
  159. package/templates/assistkick-product-system/packages/shared/db/migrations/0016_giant_xorn.sql +1 -0
  160. package/templates/assistkick-product-system/packages/shared/db/migrations/0017_sloppy_mentor.sql +6 -0
  161. package/templates/assistkick-product-system/packages/shared/db/migrations/0018_vengeful_kabuki.sql +9 -0
  162. package/templates/assistkick-product-system/packages/shared/db/migrations/0019_careful_sentinels.sql +8 -0
  163. package/templates/assistkick-product-system/packages/shared/db/migrations/0020_clever_spot.sql +27 -0
  164. package/templates/assistkick-product-system/packages/shared/db/migrations/0021_graceful_hex.sql +1 -0
  165. package/templates/assistkick-product-system/packages/shared/db/migrations/0022_short_kingpin.sql +1 -0
  166. package/templates/assistkick-product-system/packages/shared/db/migrations/0023_ambiguous_sharon_carter.sql +1 -0
  167. package/templates/assistkick-product-system/packages/shared/db/migrations/0024_fat_unus.sql +1 -0
  168. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0015_snapshot.json +1552 -0
  169. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0016_snapshot.json +1560 -0
  170. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0017_snapshot.json +1598 -0
  171. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0018_snapshot.json +1657 -0
  172. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0019_snapshot.json +1709 -0
  173. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0020_snapshot.json +1733 -0
  174. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0021_snapshot.json +1740 -0
  175. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0022_snapshot.json +1755 -0
  176. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0023_snapshot.json +1762 -0
  177. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/0024_snapshot.json +1769 -0
  178. package/templates/assistkick-product-system/packages/shared/db/migrations/meta/_journal.json +70 -0
  179. package/templates/assistkick-product-system/packages/shared/db/schema.ts +40 -1
  180. package/templates/assistkick-product-system/packages/shared/lib/claude-service.test.ts +236 -0
  181. package/templates/assistkick-product-system/packages/shared/lib/claude-service.ts +46 -5
  182. package/templates/assistkick-product-system/packages/shared/lib/git_workflow.ts +65 -39
  183. package/templates/assistkick-product-system/packages/shared/lib/programmable_node_executor.test.ts +173 -0
  184. package/templates/assistkick-product-system/packages/shared/lib/programmable_node_executor.ts +213 -0
  185. package/templates/assistkick-product-system/packages/shared/lib/validator.test.ts +70 -0
  186. package/templates/assistkick-product-system/packages/shared/lib/validator.ts +17 -1
  187. package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.test.ts +803 -27
  188. package/templates/assistkick-product-system/packages/shared/lib/workflow_engine.ts +502 -68
  189. package/templates/assistkick-product-system/packages/shared/lib/workflow_orchestrator.ts +4 -4
  190. package/templates/assistkick-product-system/packages/shared/package.json +2 -1
  191. package/templates/assistkick-product-system/packages/shared/test_fixtures/hanging_stream.mjs +46 -0
  192. package/templates/assistkick-product-system/packages/shared/tools/add_node.test.ts +44 -0
  193. package/templates/assistkick-product-system/packages/shared/tools/add_node.ts +7 -0
  194. package/templates/assistkick-product-system/packages/shared/tools/remove_node.ts +2 -1
  195. package/templates/assistkick-product-system/packages/shared/tools/resolve_question.ts +2 -1
  196. package/templates/assistkick-product-system/packages/shared/tools/update_node.ts +2 -1
  197. package/templates/assistkick-product-system/tests/message_queue.test.ts +178 -0
  198. package/templates/assistkick-product-system/tests/message_queue_per_session.test.ts +143 -0
  199. package/templates/skills/assistkick-bootstrap/SKILL.md +26 -26
  200. package/templates/skills/assistkick-code-reviewer/SKILL.md +45 -46
  201. package/templates/skills/assistkick-db-explorer/SKILL.md +13 -13
  202. package/templates/skills/assistkick-debugger/SKILL.md +23 -23
  203. package/templates/skills/assistkick-developer/SKILL.md +59 -63
  204. package/templates/skills/assistkick-interview/SKILL.md +26 -26
  205. package/templates/skills/assistkick-video-composition-agent/SKILL.md +231 -0
  206. package/templates/skills/assistkick-video-script-writer/SKILL.md +136 -0
@@ -55,7 +55,7 @@ export class WorkflowOrchestrator {
55
55
 
56
56
  // Fire-and-forget — loop runs in the background
57
57
  this.runLoop().catch(err => {
58
- this.log('ORCHESTRATOR', `Play All UNCAUGHT ERROR: ${err.message}`);
58
+ this.log('ORCHESTRATOR', `Play All UNCAUGHT ERROR:`, err.stack || err.message);
59
59
  }).finally(() => {
60
60
  this.active = false;
61
61
  this.currentFeatureId = null;
@@ -100,7 +100,7 @@ export class WorkflowOrchestrator {
100
100
  kanbanData = await this.loadKanban(this.projectId);
101
101
  graphData = await this.readGraph(this.projectId);
102
102
  } catch (err: any) {
103
- this.log('ORCHESTRATOR', `Failed to fetch data: ${err.message}`);
103
+ this.log('ORCHESTRATOR', `Failed to fetch data:`, err.stack || err.message);
104
104
  break;
105
105
  }
106
106
 
@@ -167,7 +167,7 @@ export class WorkflowOrchestrator {
167
167
  try {
168
168
  await this.workflowEngine.start(card.id, defaultWorkflow.id, this.projectId);
169
169
  } catch (err: any) {
170
- this.log('ORCHESTRATOR', `Failed to start workflow for ${card.id}: ${err.message}`);
170
+ this.log('ORCHESTRATOR', `Failed to start workflow for ${card.id}:`, err.stack || err.message);
171
171
  continue;
172
172
  }
173
173
 
@@ -201,7 +201,7 @@ export class WorkflowOrchestrator {
201
201
  return;
202
202
  }
203
203
  } catch (err: any) {
204
- this.log('ORCHESTRATOR', `Error polling status for ${featureId}: ${err.message}`);
204
+ this.log('ORCHESTRATOR', `Error polling status for ${featureId}:`, err.stack || err.message);
205
205
  return;
206
206
  }
207
207
 
@@ -19,7 +19,8 @@
19
19
  "dotenv": "^17.3.1",
20
20
  "drizzle-orm": "^0.45.1",
21
21
  "glob": "11.1.0",
22
- "gray-matter": "^4.0.3"
22
+ "gray-matter": "^4.0.3",
23
+ "isolated-vm": "^6.1.0"
23
24
  },
24
25
  "devDependencies": {
25
26
  "@types/node": "^25.3.3",
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Test fixture: simulates a Claude CLI process in stream-json mode
3
+ * that emits a result event but never exits (hangs).
4
+ * Used by claude-service tests to verify the post-result timeout.
5
+ *
6
+ * Usage: node hanging_stream.mjs [--exit-after-ms <ms>]
7
+ * No args: emits result event and hangs indefinitely
8
+ * --exit-after-ms <ms>: emits result event and exits normally after <ms> milliseconds
9
+ */
10
+
11
+ // Read stdin (prompt) to avoid broken pipe
12
+ process.stdin.resume();
13
+ process.stdin.on('data', () => {});
14
+ process.stdin.on('end', () => {});
15
+
16
+ // Emit an assistant event
17
+ const assistantEvent = JSON.stringify({
18
+ type: 'assistant',
19
+ message: {
20
+ content: [{ type: 'text', text: 'Implementation complete.' }],
21
+ usage: { input_tokens: 100, output_tokens: 50 },
22
+ },
23
+ });
24
+ process.stdout.write(assistantEvent + '\n');
25
+
26
+ // Emit a result event (this signals the conversation is complete)
27
+ const resultEvent = JSON.stringify({
28
+ type: 'result',
29
+ result: 'Test result output from the agent.',
30
+ cost_usd: 0.01,
31
+ duration_ms: 1234,
32
+ num_turns: 1,
33
+ stop_reason: 'end_turn',
34
+ model: 'claude-test',
35
+ });
36
+ process.stdout.write(resultEvent + '\n');
37
+
38
+ // Parse args
39
+ const exitAfterIdx = process.argv.indexOf('--exit-after-ms');
40
+ if (exitAfterIdx !== -1) {
41
+ const ms = parseInt(process.argv[exitAfterIdx + 1], 10);
42
+ setTimeout(() => process.exit(0), ms);
43
+ } else {
44
+ // Hang indefinitely — keep the event loop alive with a long timer
45
+ setInterval(() => {}, 60_000);
46
+ }
@@ -16,6 +16,25 @@ const deriveFeatureType = (
16
16
  return null;
17
17
  };
18
18
 
19
+ /**
20
+ * Determines whether a new node should be auto-added to the kanban backlog.
21
+ * Mirrors the logic in add_node.ts.
22
+ */
23
+ const shouldAutoAddToKanban = (nodeType: string): boolean => {
24
+ return nodeType === 'feature';
25
+ };
26
+
27
+ /**
28
+ * Builds the initial kanban entry for a newly created feature.
29
+ * Mirrors the entry shape passed to saveKanbanEntry in add_node.ts.
30
+ */
31
+ const buildInitialKanbanEntry = () => ({
32
+ column: 'backlog',
33
+ rejection_count: 0,
34
+ notes: [],
35
+ reviews: [],
36
+ });
37
+
19
38
  describe('deriveFeatureType', () => {
20
39
  it('returns "video" for feature nodes in video projects', () => {
21
40
  assert.equal(deriveFeatureType('feature', 'video'), 'video');
@@ -41,3 +60,28 @@ describe('deriveFeatureType', () => {
41
60
  assert.equal(deriveFeatureType('decision', 'software'), null);
42
61
  });
43
62
  });
63
+
64
+ describe('shouldAutoAddToKanban', () => {
65
+ it('returns true for feature nodes', () => {
66
+ assert.equal(shouldAutoAddToKanban('feature'), true);
67
+ });
68
+
69
+ it('returns false for non-feature node types', () => {
70
+ assert.equal(shouldAutoAddToKanban('component'), false);
71
+ assert.equal(shouldAutoAddToKanban('decision'), false);
72
+ assert.equal(shouldAutoAddToKanban('epic'), false);
73
+ assert.equal(shouldAutoAddToKanban('data_entity'), false);
74
+ assert.equal(shouldAutoAddToKanban('tech_choice'), false);
75
+ assert.equal(shouldAutoAddToKanban('non_functional_requirement'), false);
76
+ });
77
+ });
78
+
79
+ describe('buildInitialKanbanEntry', () => {
80
+ it('creates a backlog entry with zeroed counters', () => {
81
+ const entry = buildInitialKanbanEntry();
82
+ assert.equal(entry.column, 'backlog');
83
+ assert.equal(entry.rejection_count, 0);
84
+ assert.deepEqual(entry.notes, []);
85
+ assert.deepEqual(entry.reviews, []);
86
+ });
87
+ });
@@ -14,6 +14,7 @@ import { getDb } from '../lib/db.js';
14
14
  import { nodes, projects } from '../db/schema.js';
15
15
  import { deriveMetadata, templateSections } from '../lib/markdown.js';
16
16
  import { assertValidType, assertUniqueName } from '../lib/validator.js';
17
+ import { saveKanbanEntry } from '../lib/kanban.js';
17
18
 
18
19
  program
19
20
  .requiredOption('--type <type>', 'Node type (e.g., feature, component, decision)')
@@ -96,6 +97,12 @@ const opts = program.opts();
96
97
  projectId: opts.projectId,
97
98
  });
98
99
 
100
+ // Auto-add features to the kanban backlog
101
+ if (opts.type === 'feature') {
102
+ await saveKanbanEntry(id, { column: 'backlog', rejection_count: 0, notes: [], reviews: [] }, opts.projectId);
103
+ console.log(chalk.green(`✓ Added ${id} to kanban backlog`));
104
+ }
105
+
99
106
  console.log(chalk.green(`✓ Created ${opts.type} node: ${id}`));
100
107
  console.log(JSON.stringify({ id, type: opts.type, name: opts.name }));
101
108
  } catch (err) {
@@ -10,7 +10,7 @@ import { eq, or } from 'drizzle-orm';
10
10
  import { createInterface } from 'node:readline';
11
11
  import { getDb } from '../lib/db.js';
12
12
  import { getNode } from '../lib/graph.js';
13
- import { assertNodeExists } from '../lib/validator.js';
13
+ import { assertNodeExists, assertNotDone } from '../lib/validator.js';
14
14
  import { nodes, edges, kanban, reviewMeta } from '../db/schema.js';
15
15
 
16
16
  program
@@ -35,6 +35,7 @@ const confirm = async (message: string): Promise<boolean> => {
35
35
  (async () => {
36
36
  try {
37
37
  await assertNodeExists(id);
38
+ await assertNotDone(id);
38
39
 
39
40
  const node = await getNode(id);
40
41
  const db = getDb();
@@ -8,7 +8,7 @@ import { program } from 'commander';
8
8
  import chalk from 'chalk';
9
9
  import { readGraph, patchNode } from '../lib/graph.js';
10
10
  import { readNode, writeNode, deriveMetadata } from '../lib/markdown.js';
11
- import { assertNodeExists } from '../lib/validator.js';
11
+ import { assertNodeExists, assertNotDone } from '../lib/validator.js';
12
12
 
13
13
  program
14
14
  .argument('<id>', 'Node ID containing the question')
@@ -23,6 +23,7 @@ const opts = program.opts();
23
23
  (async () => {
24
24
  try {
25
25
  await assertNodeExists(id);
26
+ await assertNotDone(id);
26
27
 
27
28
  const graph = await readGraph();
28
29
  const nodeMeta = graph.nodes.find(n => n.id === id);
@@ -8,7 +8,7 @@ import { program } from 'commander';
8
8
  import chalk from 'chalk';
9
9
  import { readGraph, patchNode } from '../lib/graph.js';
10
10
  import { readNode, writeNode, appendToSection, setSection, deriveMetadata } from '../lib/markdown.js';
11
- import { assertNodeExists } from '../lib/validator.js';
11
+ import { assertNodeExists, assertNotDone } from '../lib/validator.js';
12
12
  import { VALID_STATUSES, VALID_PRIORITIES, VALID_FEATURE_KINDS } from '../lib/constants.js';
13
13
  import { getKanbanEntry, saveKanbanEntry } from '../lib/kanban.js';
14
14
 
@@ -32,6 +32,7 @@ const opts = program.opts();
32
32
  (async () => {
33
33
  try {
34
34
  await assertNodeExists(id);
35
+ await assertNotDone(id);
35
36
 
36
37
  const graph = await readGraph();
37
38
  const nodeMeta = graph.nodes.find(n => n.id === id);
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Tests for the Chat v2 Message Queue.
3
+ * Validates enqueue, remove, clear, drainAll, and mergeTexts operations.
4
+ * Uses node:test built-in runner.
5
+ */
6
+ import { describe, it, beforeEach } from 'node:test';
7
+ import assert from 'node:assert/strict';
8
+ import { MessageQueue } from '../packages/frontend/src/lib/message_queue.ts';
9
+
10
+ describe('MessageQueue', () => {
11
+ let queue: MessageQueue;
12
+
13
+ beforeEach(() => {
14
+ queue = new MessageQueue();
15
+ });
16
+
17
+ describe('enqueue', () => {
18
+ it('adds a message to an empty queue', () => {
19
+ queue.enqueue('Hello');
20
+
21
+ assert.equal(queue.getLength(), 1);
22
+ assert.equal(queue.getQueue()[0].text, 'Hello');
23
+ });
24
+
25
+ it('appends multiple messages in order', () => {
26
+ queue.enqueue('First');
27
+ queue.enqueue('Second');
28
+ queue.enqueue('Third');
29
+
30
+ const items = queue.getQueue();
31
+ assert.equal(items.length, 3);
32
+ assert.equal(items[0].text, 'First');
33
+ assert.equal(items[1].text, 'Second');
34
+ assert.equal(items[2].text, 'Third');
35
+ });
36
+
37
+ it('generates unique IDs for each message', () => {
38
+ queue.enqueue('A');
39
+ queue.enqueue('B');
40
+
41
+ const items = queue.getQueue();
42
+ assert.notEqual(items[0].id, items[1].id);
43
+ });
44
+
45
+ it('sets createdAt timestamp', () => {
46
+ const before = Date.now();
47
+ queue.enqueue('Test');
48
+ const after = Date.now();
49
+
50
+ const msg = queue.getQueue()[0];
51
+ assert.ok(msg.createdAt >= before);
52
+ assert.ok(msg.createdAt <= after);
53
+ });
54
+
55
+ it('returns the enqueued message', () => {
56
+ const msg = queue.enqueue('Return me');
57
+
58
+ assert.equal(msg.text, 'Return me');
59
+ assert.ok(msg.id.startsWith('q_'));
60
+ });
61
+ });
62
+
63
+ describe('remove', () => {
64
+ it('removes a specific message by id', () => {
65
+ queue.enqueue('Keep');
66
+ queue.enqueue('Remove me');
67
+ queue.enqueue('Also keep');
68
+
69
+ const removeId = queue.getQueue()[1].id;
70
+ const removed = queue.remove(removeId);
71
+
72
+ assert.equal(removed, true);
73
+ assert.equal(queue.getLength(), 2);
74
+ assert.equal(queue.getQueue()[0].text, 'Keep');
75
+ assert.equal(queue.getQueue()[1].text, 'Also keep');
76
+ });
77
+
78
+ it('returns false when id does not exist', () => {
79
+ queue.enqueue('Only one');
80
+
81
+ const removed = queue.remove('nonexistent_id');
82
+
83
+ assert.equal(removed, false);
84
+ assert.equal(queue.getLength(), 1);
85
+ });
86
+ });
87
+
88
+ describe('clear', () => {
89
+ it('removes all messages from the queue', () => {
90
+ queue.enqueue('One');
91
+ queue.enqueue('Two');
92
+ queue.enqueue('Three');
93
+
94
+ queue.clear();
95
+
96
+ assert.equal(queue.getLength(), 0);
97
+ });
98
+
99
+ it('is safe to call on an empty queue', () => {
100
+ queue.clear();
101
+
102
+ assert.equal(queue.getLength(), 0);
103
+ });
104
+ });
105
+
106
+ describe('drainAll', () => {
107
+ it('returns all messages and empties the queue', () => {
108
+ queue.enqueue('First');
109
+ queue.enqueue('Second');
110
+
111
+ const drained = queue.drainAll();
112
+
113
+ assert.equal(drained.length, 2);
114
+ assert.equal(drained[0].text, 'First');
115
+ assert.equal(drained[1].text, 'Second');
116
+ assert.equal(queue.getLength(), 0);
117
+ });
118
+
119
+ it('returns empty array when queue is empty', () => {
120
+ const drained = queue.drainAll();
121
+
122
+ assert.equal(drained.length, 0);
123
+ });
124
+
125
+ it('subsequent drain returns empty after first drain', () => {
126
+ queue.enqueue('Once');
127
+
128
+ const first = queue.drainAll();
129
+ const second = queue.drainAll();
130
+
131
+ assert.equal(first.length, 1);
132
+ assert.equal(second.length, 0);
133
+ });
134
+ });
135
+
136
+ describe('mergeTexts', () => {
137
+ it('merges messages with double newline separator', () => {
138
+ queue.enqueue('Fix the bug in auth');
139
+ queue.enqueue('Also update the docs');
140
+ queue.enqueue('Run the tests when done');
141
+
142
+ const drained = queue.drainAll();
143
+ const merged = MessageQueue.mergeTexts(drained);
144
+
145
+ assert.equal(
146
+ merged,
147
+ 'Fix the bug in auth\n\nAlso update the docs\n\nRun the tests when done',
148
+ );
149
+ });
150
+
151
+ it('returns single message text without separator', () => {
152
+ queue.enqueue('Only one message');
153
+
154
+ const drained = queue.drainAll();
155
+ const merged = MessageQueue.mergeTexts(drained);
156
+
157
+ assert.equal(merged, 'Only one message');
158
+ });
159
+
160
+ it('returns empty string for empty array', () => {
161
+ const merged = MessageQueue.mergeTexts([]);
162
+
163
+ assert.equal(merged, '');
164
+ });
165
+ });
166
+
167
+ describe('getQueue immutability', () => {
168
+ it('returns a readonly snapshot that is not affected by later enqueues', () => {
169
+ queue.enqueue('Original');
170
+ const snapshot = queue.getQueue();
171
+
172
+ queue.enqueue('New');
173
+
174
+ assert.equal(snapshot.length, 1);
175
+ assert.equal(queue.getLength(), 2);
176
+ });
177
+ });
178
+ });
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Tests for per-session message queue scoping.
3
+ *
4
+ * Validates that the MessageQueue class correctly isolates queues when used
5
+ * in a per-session Map pattern (as useMessageQueueStore does internally).
6
+ * Uses node:test built-in runner.
7
+ */
8
+ import { describe, it, beforeEach } from 'node:test';
9
+ import assert from 'node:assert/strict';
10
+ import { MessageQueue } from '../packages/frontend/src/lib/message_queue.ts';
11
+
12
+ describe('Per-session MessageQueue isolation', () => {
13
+ let sessionQueues: Map<string, MessageQueue>;
14
+
15
+ const getOrCreateQueue = (sessionId: string): MessageQueue => {
16
+ let mq = sessionQueues.get(sessionId);
17
+ if (!mq) {
18
+ mq = new MessageQueue();
19
+ sessionQueues.set(sessionId, mq);
20
+ }
21
+ return mq;
22
+ };
23
+
24
+ beforeEach(() => {
25
+ sessionQueues = new Map();
26
+ });
27
+
28
+ it('enqueues messages to separate sessions independently', () => {
29
+ const queueA = getOrCreateQueue('session_a');
30
+ const queueB = getOrCreateQueue('session_b');
31
+
32
+ queueA.enqueue('Message for A');
33
+ queueB.enqueue('Message for B');
34
+ queueA.enqueue('Second message for A');
35
+
36
+ assert.equal(queueA.getLength(), 2);
37
+ assert.equal(queueB.getLength(), 1);
38
+ assert.equal(queueA.getQueue()[0].text, 'Message for A');
39
+ assert.equal(queueB.getQueue()[0].text, 'Message for B');
40
+ });
41
+
42
+ it('draining one session does not affect another', () => {
43
+ const queueA = getOrCreateQueue('session_a');
44
+ const queueB = getOrCreateQueue('session_b');
45
+
46
+ queueA.enqueue('A1');
47
+ queueA.enqueue('A2');
48
+ queueB.enqueue('B1');
49
+
50
+ const drained = queueA.drainAll();
51
+
52
+ assert.equal(drained.length, 2);
53
+ assert.equal(queueA.getLength(), 0);
54
+ assert.equal(queueB.getLength(), 1);
55
+ assert.equal(queueB.getQueue()[0].text, 'B1');
56
+ });
57
+
58
+ it('clearing one session preserves the other', () => {
59
+ const queueA = getOrCreateQueue('session_a');
60
+ const queueB = getOrCreateQueue('session_b');
61
+
62
+ queueA.enqueue('A1');
63
+ queueB.enqueue('B1');
64
+ queueB.enqueue('B2');
65
+
66
+ queueA.clear();
67
+
68
+ assert.equal(queueA.getLength(), 0);
69
+ assert.equal(queueB.getLength(), 2);
70
+ });
71
+
72
+ it('removing a message from one session does not affect another', () => {
73
+ const queueA = getOrCreateQueue('session_a');
74
+ const queueB = getOrCreateQueue('session_b');
75
+
76
+ const msgA = queueA.enqueue('A1');
77
+ queueB.enqueue('B1');
78
+
79
+ queueA.remove(msgA.id);
80
+
81
+ assert.equal(queueA.getLength(), 0);
82
+ assert.equal(queueB.getLength(), 1);
83
+ });
84
+
85
+ it('switching active session shows correct queue', () => {
86
+ const queueA = getOrCreateQueue('session_a');
87
+ const queueB = getOrCreateQueue('session_b');
88
+
89
+ queueA.enqueue('A1');
90
+ queueA.enqueue('A2');
91
+ queueB.enqueue('B1');
92
+
93
+ // Simulate switching to session_b — visible queue is session_b's
94
+ let activeSessionId = 'session_b';
95
+ let visibleQueue = [...getOrCreateQueue(activeSessionId).getQueue()];
96
+ assert.equal(visibleQueue.length, 1);
97
+ assert.equal(visibleQueue[0].text, 'B1');
98
+
99
+ // Switch back to session_a
100
+ activeSessionId = 'session_a';
101
+ visibleQueue = [...getOrCreateQueue(activeSessionId).getQueue()];
102
+ assert.equal(visibleQueue.length, 2);
103
+ assert.equal(visibleQueue[0].text, 'A1');
104
+ });
105
+
106
+ it('draining a specific session while viewing another returns correct messages', () => {
107
+ const queueA = getOrCreateQueue('session_a');
108
+ const queueB = getOrCreateQueue('session_b');
109
+
110
+ queueA.enqueue('A1');
111
+ queueA.enqueue('A2');
112
+ queueB.enqueue('B1');
113
+
114
+ // Active session is B, but we drain A (onStreamEnd scenario)
115
+ const drained = queueA.drainAll();
116
+
117
+ assert.equal(drained.length, 2);
118
+ assert.equal(drained[0].text, 'A1');
119
+ assert.equal(drained[1].text, 'A2');
120
+ // Session B still has its message
121
+ assert.equal(queueB.getLength(), 1);
122
+ });
123
+
124
+ it('creating a new session starts with empty queue', () => {
125
+ getOrCreateQueue('session_a').enqueue('A1');
126
+
127
+ const queueNew = getOrCreateQueue('session_new');
128
+
129
+ assert.equal(queueNew.getLength(), 0);
130
+ });
131
+
132
+ it('merged texts from drained session are correct', () => {
133
+ const queueA = getOrCreateQueue('session_a');
134
+
135
+ queueA.enqueue('Fix the bug');
136
+ queueA.enqueue('Also update docs');
137
+
138
+ const drained = queueA.drainAll();
139
+ const merged = MessageQueue.mergeTexts(drained);
140
+
141
+ assert.equal(merged, 'Fix the bug\n\nAlso update docs');
142
+ });
143
+ });
@@ -13,7 +13,7 @@ priorities, and preferences**. You interact with the graph exclusively
13
13
  through the tools below.
14
14
 
15
15
  All tools live in `assistkick-product-system/packages/shared/tools/` and
16
- are run with `npx tsx`.
16
+ are run with `pnpm tsx`.
17
17
 
18
18
  ## Bootstrap Philosophy
19
19
  Unlike a greenfield interview, the project already exists. The codebase is
@@ -205,33 +205,33 @@ Use the same `<project_id>` on **every** tool call in this session.
205
205
 
206
206
  ### start_session
207
207
  ```
208
- npx tsx packages/shared/tools/start_session.ts --project-id <project_id>
208
+ pnpm tsx packages/shared/tools/start_session.ts --project-id <project_id>
209
209
  ```
210
210
 
211
211
  ### end_session
212
212
  ```
213
- npx tsx packages/shared/tools/end_session.ts --project-id <project_id> --summary "..." --nodes-touched "feat_001,dec_001" --questions-resolved 3
213
+ pnpm tsx packages/shared/tools/end_session.ts --project-id <project_id> --summary "..." --nodes-touched "feat_001,dec_001" --questions-resolved 3
214
214
  ```
215
215
 
216
216
  ### search_nodes
217
217
  ```
218
- npx tsx packages/shared/tools/search_nodes.ts --project-id <project_id> --query "keyword"
219
- npx tsx packages/shared/tools/search_nodes.ts --project-id <project_id> --type feature
220
- npx tsx packages/shared/tools/search_nodes.ts --project-id <project_id> --has-open-questions
221
- npx tsx packages/shared/tools/search_nodes.ts --project-id <project_id> --completeness-below 0.5
218
+ pnpm tsx packages/shared/tools/search_nodes.ts --project-id <project_id> --query "keyword"
219
+ pnpm tsx packages/shared/tools/search_nodes.ts --project-id <project_id> --type feature
220
+ pnpm tsx packages/shared/tools/search_nodes.ts --project-id <project_id> --has-open-questions
221
+ pnpm tsx packages/shared/tools/search_nodes.ts --project-id <project_id> --completeness-below 0.5
222
222
  ```
223
223
 
224
224
  ### get_node
225
225
  ```
226
- npx tsx packages/shared/tools/get_node.ts <node_id> --project-id <project_id>
227
- npx tsx packages/shared/tools/get_node.ts --name "Node Name" --project-id <project_id>
226
+ pnpm tsx packages/shared/tools/get_node.ts <node_id> --project-id <project_id>
227
+ pnpm tsx packages/shared/tools/get_node.ts --name "Node Name" --project-id <project_id>
228
228
  ```
229
229
  Returns the node content (formatted as markdown) plus a Relations section listing
230
230
  all connected nodes with direction, relation type, name, type, and status.
231
231
 
232
232
  ### add_node
233
233
  ```
234
- npx tsx packages/shared/tools/add_node.ts --project-id <project_id> --type <type> --name "Name" --description "..."
234
+ pnpm tsx packages/shared/tools/add_node.ts --project-id <project_id> --type <type> --name "Name" --description "..."
235
235
  ```
236
236
  Valid types: feature, component, data_entity, decision, tech_choice,
237
237
  non_functional_requirement, design_token, design_pattern, user_role,
@@ -239,23 +239,23 @@ flow, assumption, open_question
239
239
 
240
240
  ### update_node
241
241
  ```
242
- npx tsx packages/shared/tools/update_node.ts <id> --project-id <project_id> --add-acceptance-criteria "..."
243
- npx tsx packages/shared/tools/update_node.ts <id> --project-id <project_id> --add-open-question "..."
244
- npx tsx packages/shared/tools/update_node.ts <id> --project-id <project_id> --add-note "Session N: ..."
245
- npx tsx packages/shared/tools/update_node.ts <id> --project-id <project_id> --set-status <draft|partially_defined|defined>
246
- npx tsx packages/shared/tools/update_node.ts <id> --project-id <project_id> --set-priority <low|medium|high|blocking>
247
- npx tsx packages/shared/tools/update_node.ts <id> --project-id <project_id> --set-description "..."
248
- npx tsx packages/shared/tools/update_node.ts <id> --project-id <project_id> --set-section "SectionName=content"
242
+ pnpm tsx packages/shared/tools/update_node.ts <id> --project-id <project_id> --add-acceptance-criteria "..."
243
+ pnpm tsx packages/shared/tools/update_node.ts <id> --project-id <project_id> --add-open-question "..."
244
+ pnpm tsx packages/shared/tools/update_node.ts <id> --project-id <project_id> --add-note "Session N: ..."
245
+ pnpm tsx packages/shared/tools/update_node.ts <id> --project-id <project_id> --set-status <draft|partially_defined|defined>
246
+ pnpm tsx packages/shared/tools/update_node.ts <id> --project-id <project_id> --set-priority <low|medium|high|blocking>
247
+ pnpm tsx packages/shared/tools/update_node.ts <id> --project-id <project_id> --set-description "..."
248
+ pnpm tsx packages/shared/tools/update_node.ts <id> --project-id <project_id> --set-section "SectionName=content"
249
249
  ```
250
250
 
251
251
  ### resolve_question
252
252
  ```
253
- npx tsx packages/shared/tools/resolve_question.ts <id> --project-id <project_id> --question "..." --answer "..."
253
+ pnpm tsx packages/shared/tools/resolve_question.ts <id> --project-id <project_id> --question "..." --answer "..."
254
254
  ```
255
255
 
256
256
  ### add_edge
257
257
  ```
258
- npx tsx packages/shared/tools/add_edge.ts <from_id> <relation> <to_id> --project-id <project_id>
258
+ pnpm tsx packages/shared/tools/add_edge.ts <from_id> <relation> <to_id> --project-id <project_id>
259
259
  ```
260
260
  Valid relations: contains, depends_on, governed_by, constrained_by,
261
261
  implemented_with, reads_writes, exposes, consumes, performed_by,
@@ -263,25 +263,25 @@ escalates_to, relates_to
263
263
 
264
264
  ### remove_edge
265
265
  ```
266
- npx tsx packages/shared/tools/remove_edge.ts <from_id> <relation> <to_id> --project-id <project_id>
266
+ pnpm tsx packages/shared/tools/remove_edge.ts <from_id> <relation> <to_id> --project-id <project_id>
267
267
  ```
268
268
 
269
269
  ### get_gaps
270
270
  ```
271
- npx tsx packages/shared/tools/get_gaps.ts --project-id <project_id>
272
- npx tsx packages/shared/tools/get_gaps.ts --project-id <project_id> --blocking-only
273
- npx tsx packages/shared/tools/get_gaps.ts --project-id <project_id> --type feature
271
+ pnpm tsx packages/shared/tools/get_gaps.ts --project-id <project_id>
272
+ pnpm tsx packages/shared/tools/get_gaps.ts --project-id <project_id> --blocking-only
273
+ pnpm tsx packages/shared/tools/get_gaps.ts --project-id <project_id> --type feature
274
274
  ```
275
275
 
276
276
  ### get_status
277
277
  ```
278
- npx tsx packages/shared/tools/get_status.ts --project-id <project_id>
278
+ pnpm tsx packages/shared/tools/get_status.ts --project-id <project_id>
279
279
  ```
280
280
 
281
281
  ### rebuild_index
282
282
  ```
283
- npx tsx packages/shared/tools/rebuild_index.ts --project-id <project_id>
284
- npx tsx packages/shared/tools/rebuild_index.ts --project-id <project_id> --dry-run
283
+ pnpm tsx packages/shared/tools/rebuild_index.ts --project-id <project_id>
284
+ pnpm tsx packages/shared/tools/rebuild_index.ts --project-id <project_id> --dry-run
285
285
  ```
286
286
 
287
287
  ## Search Strategy