@proflandrigan/shards 1.1.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 (397) hide show
  1. package/README.md +475 -0
  2. package/package.json +37 -0
  3. package/src/agents/academic.md +276 -0
  4. package/src/agents/ai-engineer.md +377 -0
  5. package/src/agents/analytics-engineer.md +364 -0
  6. package/src/agents/applied-ml-scientist.md +410 -0
  7. package/src/agents/backend-engineer.md +255 -0
  8. package/src/agents/bi-engineer.md +333 -0
  9. package/src/agents/data-analyst.md +343 -0
  10. package/src/agents/data-engineer.md +260 -0
  11. package/src/agents/data-modeller.md +386 -0
  12. package/src/agents/data-scientist.md +366 -0
  13. package/src/agents/deep-learning-engineer.md +389 -0
  14. package/src/agents/ml-engineer.md +424 -0
  15. package/src/agents/mlops-engineer.md +339 -0
  16. package/src/agents/researcher.md +187 -0
  17. package/src/agents/specific_instructions/academic/critical_review.md +263 -0
  18. package/src/agents/specific_instructions/academic/report.md +113 -0
  19. package/src/agents/specific_instructions/ai_engineer/advise.md +162 -0
  20. package/src/agents/specific_instructions/ai_engineer/bi_engineer_handoff.md +86 -0
  21. package/src/agents/specific_instructions/ai_engineer/experiment.md +471 -0
  22. package/src/agents/specific_instructions/ai_engineer/experiment_ui_mode.md +44 -0
  23. package/src/agents/specific_instructions/ai_engineer/phases/index.md +45 -0
  24. package/src/agents/specific_instructions/ai_engineer/phases/phase-1.md +55 -0
  25. package/src/agents/specific_instructions/ai_engineer/phases/phase-2.md +86 -0
  26. package/src/agents/specific_instructions/ai_engineer/phases/phase-3.md +96 -0
  27. package/src/agents/specific_instructions/ai_engineer/phases/phase-4.md +138 -0
  28. package/src/agents/specific_instructions/ai_engineer/phases/phase-5.md +157 -0
  29. package/src/agents/specific_instructions/ai_engineer/phases/phase-6.md +196 -0
  30. package/src/agents/specific_instructions/ai_engineer/phases/phase-7.md +313 -0
  31. package/src/agents/specific_instructions/ai_engineer/phases.md +1011 -0
  32. package/src/agents/specific_instructions/ai_engineer/prompt_lab.md +161 -0
  33. package/src/agents/specific_instructions/ai_engineer/prompt_lab_ui_mode.md +28 -0
  34. package/src/agents/specific_instructions/ai_engineer/research.md +393 -0
  35. package/src/agents/specific_instructions/ai_engineer/research_ui_mode.md +66 -0
  36. package/src/agents/specific_instructions/ai_engineer/review.md +159 -0
  37. package/src/agents/specific_instructions/ai_engineer/validation_checklist.md +182 -0
  38. package/src/agents/specific_instructions/analytics_engineer/advise.md +155 -0
  39. package/src/agents/specific_instructions/analytics_engineer/bi_engineer_handoff.md +91 -0
  40. package/src/agents/specific_instructions/analytics_engineer/data_analyst_handoff.md +84 -0
  41. package/src/agents/specific_instructions/analytics_engineer/deep_phases.md +818 -0
  42. package/src/agents/specific_instructions/analytics_engineer/phases_deep/index.md +24 -0
  43. package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-1.md +77 -0
  44. package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-2.md +106 -0
  45. package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-3.md +93 -0
  46. package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-4.md +79 -0
  47. package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-5.md +61 -0
  48. package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-6.md +45 -0
  49. package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-7.md +235 -0
  50. package/src/agents/specific_instructions/analytics_engineer/phases_deep/phase-8.md +221 -0
  51. package/src/agents/specific_instructions/analytics_engineer/phases_quick/index.md +19 -0
  52. package/src/agents/specific_instructions/analytics_engineer/phases_quick/phase-1.md +47 -0
  53. package/src/agents/specific_instructions/analytics_engineer/phases_quick/phase-2.md +78 -0
  54. package/src/agents/specific_instructions/analytics_engineer/quick_phases.md +112 -0
  55. package/src/agents/specific_instructions/analytics_engineer/review.md +167 -0
  56. package/src/agents/specific_instructions/analytics_engineer/service_mode.md +369 -0
  57. package/src/agents/specific_instructions/analytics_engineer/ui_mode.md +45 -0
  58. package/src/agents/specific_instructions/analytics_engineer/update.md +162 -0
  59. package/src/agents/specific_instructions/analytics_engineer/validation_checklist.md +121 -0
  60. package/src/agents/specific_instructions/applied_ml_scientist/advise.md +143 -0
  61. package/src/agents/specific_instructions/applied_ml_scientist/phases/index.md +21 -0
  62. package/src/agents/specific_instructions/applied_ml_scientist/phases/phase-1.md +51 -0
  63. package/src/agents/specific_instructions/applied_ml_scientist/phases/phase-2.md +66 -0
  64. package/src/agents/specific_instructions/applied_ml_scientist/phases/phase-3.md +113 -0
  65. package/src/agents/specific_instructions/applied_ml_scientist/phases/phase-4.md +104 -0
  66. package/src/agents/specific_instructions/applied_ml_scientist/phases/phase-5.md +156 -0
  67. package/src/agents/specific_instructions/applied_ml_scientist/phases.md +428 -0
  68. package/src/agents/specific_instructions/applied_ml_scientist/research.md +379 -0
  69. package/src/agents/specific_instructions/applied_ml_scientist/review.md +142 -0
  70. package/src/agents/specific_instructions/applied_ml_scientist/validation_checklist.md +136 -0
  71. package/src/agents/specific_instructions/backend_engineer/clean.md +149 -0
  72. package/src/agents/specific_instructions/backend_engineer/review.md +91 -0
  73. package/src/agents/specific_instructions/backend_engineer/review_checklist.md +54 -0
  74. package/src/agents/specific_instructions/backend_engineer/service_mode.md +67 -0
  75. package/src/agents/specific_instructions/bi_engineer/advise.md +137 -0
  76. package/src/agents/specific_instructions/bi_engineer/data_analyst_handoff.md +77 -0
  77. package/src/agents/specific_instructions/bi_engineer/incoming_handoff.md +45 -0
  78. package/src/agents/specific_instructions/bi_engineer/phases/index.md +20 -0
  79. package/src/agents/specific_instructions/bi_engineer/phases/phase-1.md +164 -0
  80. package/src/agents/specific_instructions/bi_engineer/phases/phase-2.md +92 -0
  81. package/src/agents/specific_instructions/bi_engineer/phases/phase-3.md +121 -0
  82. package/src/agents/specific_instructions/bi_engineer/phases/phase-4.md +106 -0
  83. package/src/agents/specific_instructions/bi_engineer/phases.md +451 -0
  84. package/src/agents/specific_instructions/bi_engineer/review.md +166 -0
  85. package/src/agents/specific_instructions/bi_engineer/update.md +147 -0
  86. package/src/agents/specific_instructions/bi_engineer/validation_checklist.md +124 -0
  87. package/src/agents/specific_instructions/data_analyst/advise.md +138 -0
  88. package/src/agents/specific_instructions/data_analyst/explain.md +221 -0
  89. package/src/agents/specific_instructions/data_analyst/incoming_handoff.md +40 -0
  90. package/src/agents/specific_instructions/data_analyst/phases/index.md +20 -0
  91. package/src/agents/specific_instructions/data_analyst/phases/phase-1.md +159 -0
  92. package/src/agents/specific_instructions/data_analyst/phases/phase-2.md +112 -0
  93. package/src/agents/specific_instructions/data_analyst/phases/phase-3.md +265 -0
  94. package/src/agents/specific_instructions/data_analyst/phases/phase-4.md +100 -0
  95. package/src/agents/specific_instructions/data_analyst/phases.md +501 -0
  96. package/src/agents/specific_instructions/data_analyst/review.md +138 -0
  97. package/src/agents/specific_instructions/data_analyst/ui_mode.md +26 -0
  98. package/src/agents/specific_instructions/data_analyst/update.md +144 -0
  99. package/src/agents/specific_instructions/data_analyst/validation_checklist.md +95 -0
  100. package/src/agents/specific_instructions/data_engineer/advise.md +137 -0
  101. package/src/agents/specific_instructions/data_engineer/phases.md +466 -0
  102. package/src/agents/specific_instructions/data_engineer/phases_deep/index.md +23 -0
  103. package/src/agents/specific_instructions/data_engineer/phases_deep/phase-1.md +49 -0
  104. package/src/agents/specific_instructions/data_engineer/phases_deep/phase-2.md +93 -0
  105. package/src/agents/specific_instructions/data_engineer/phases_deep/phase-3.md +55 -0
  106. package/src/agents/specific_instructions/data_engineer/phases_deep/phase-4.md +48 -0
  107. package/src/agents/specific_instructions/data_engineer/phases_deep/phase-5.md +40 -0
  108. package/src/agents/specific_instructions/data_engineer/phases_deep/phase-6.md +102 -0
  109. package/src/agents/specific_instructions/data_engineer/phases_deep/phase-7.md +87 -0
  110. package/src/agents/specific_instructions/data_engineer/phases_quick/index.md +19 -0
  111. package/src/agents/specific_instructions/data_engineer/phases_quick/phase-1.md +45 -0
  112. package/src/agents/specific_instructions/data_engineer/phases_quick/phase-2.md +54 -0
  113. package/src/agents/specific_instructions/data_engineer/review.md +135 -0
  114. package/src/agents/specific_instructions/data_engineer/validation_checklist.md +136 -0
  115. package/src/agents/specific_instructions/data_modeller/advise.md +137 -0
  116. package/src/agents/specific_instructions/data_modeller/phases.md +581 -0
  117. package/src/agents/specific_instructions/data_modeller/phases_deep/index.md +23 -0
  118. package/src/agents/specific_instructions/data_modeller/phases_deep/phase-1.md +52 -0
  119. package/src/agents/specific_instructions/data_modeller/phases_deep/phase-2.md +113 -0
  120. package/src/agents/specific_instructions/data_modeller/phases_deep/phase-3.md +47 -0
  121. package/src/agents/specific_instructions/data_modeller/phases_deep/phase-4.md +51 -0
  122. package/src/agents/specific_instructions/data_modeller/phases_deep/phase-5.md +45 -0
  123. package/src/agents/specific_instructions/data_modeller/phases_deep/phase-6.md +105 -0
  124. package/src/agents/specific_instructions/data_modeller/phases_deep/phase-7.md +136 -0
  125. package/src/agents/specific_instructions/data_modeller/phases_quick/index.md +19 -0
  126. package/src/agents/specific_instructions/data_modeller/phases_quick/phase-1.md +47 -0
  127. package/src/agents/specific_instructions/data_modeller/phases_quick/phase-2.md +65 -0
  128. package/src/agents/specific_instructions/data_modeller/review.md +141 -0
  129. package/src/agents/specific_instructions/data_modeller/service_mode.md +218 -0
  130. package/src/agents/specific_instructions/data_modeller/validation_checklist.md +125 -0
  131. package/src/agents/specific_instructions/data_scientist/advise.md +158 -0
  132. package/src/agents/specific_instructions/data_scientist/bi_engineer_handoff.md +63 -0
  133. package/src/agents/specific_instructions/data_scientist/experiment.md +482 -0
  134. package/src/agents/specific_instructions/data_scientist/experiment_ui_mode.md +44 -0
  135. package/src/agents/specific_instructions/data_scientist/explain.md +247 -0
  136. package/src/agents/specific_instructions/data_scientist/greenfield_data.md +35 -0
  137. package/src/agents/specific_instructions/data_scientist/ml_engineer_handoff.md +52 -0
  138. package/src/agents/specific_instructions/data_scientist/notebook_walkthrough.md +76 -0
  139. package/src/agents/specific_instructions/data_scientist/phases/index.md +24 -0
  140. package/src/agents/specific_instructions/data_scientist/phases/phase-1.md +45 -0
  141. package/src/agents/specific_instructions/data_scientist/phases/phase-2.md +67 -0
  142. package/src/agents/specific_instructions/data_scientist/phases/phase-3.md +89 -0
  143. package/src/agents/specific_instructions/data_scientist/phases/phase-4.md +143 -0
  144. package/src/agents/specific_instructions/data_scientist/phases/phase-5.md +71 -0
  145. package/src/agents/specific_instructions/data_scientist/phases/phase-6.md +239 -0
  146. package/src/agents/specific_instructions/data_scientist/phases/phase-7.md +207 -0
  147. package/src/agents/specific_instructions/data_scientist/phases.md +651 -0
  148. package/src/agents/specific_instructions/data_scientist/research.md +345 -0
  149. package/src/agents/specific_instructions/data_scientist/research_ui_mode.md +52 -0
  150. package/src/agents/specific_instructions/data_scientist/review.md +136 -0
  151. package/src/agents/specific_instructions/data_scientist/service_mode.md +247 -0
  152. package/src/agents/specific_instructions/data_scientist/validation_checklist.md +183 -0
  153. package/src/agents/specific_instructions/deep_learning_engineer/advise.md +145 -0
  154. package/src/agents/specific_instructions/deep_learning_engineer/phases/index.md +21 -0
  155. package/src/agents/specific_instructions/deep_learning_engineer/phases/phase-1.md +74 -0
  156. package/src/agents/specific_instructions/deep_learning_engineer/phases/phase-2.md +98 -0
  157. package/src/agents/specific_instructions/deep_learning_engineer/phases/phase-3.md +76 -0
  158. package/src/agents/specific_instructions/deep_learning_engineer/phases/phase-4.md +128 -0
  159. package/src/agents/specific_instructions/deep_learning_engineer/phases/phase-5.md +292 -0
  160. package/src/agents/specific_instructions/deep_learning_engineer/phases.md +567 -0
  161. package/src/agents/specific_instructions/deep_learning_engineer/research.md +389 -0
  162. package/src/agents/specific_instructions/deep_learning_engineer/review.md +155 -0
  163. package/src/agents/specific_instructions/deep_learning_engineer/validation_checklist.md +147 -0
  164. package/src/agents/specific_instructions/ml_engineer/advise.md +174 -0
  165. package/src/agents/specific_instructions/ml_engineer/bi_engineer_handoff.md +71 -0
  166. package/src/agents/specific_instructions/ml_engineer/experiment.md +474 -0
  167. package/src/agents/specific_instructions/ml_engineer/experiment_ui_mode.md +44 -0
  168. package/src/agents/specific_instructions/ml_engineer/notebook_walkthrough.md +75 -0
  169. package/src/agents/specific_instructions/ml_engineer/phases/index.md +25 -0
  170. package/src/agents/specific_instructions/ml_engineer/phases/phase-1.md +49 -0
  171. package/src/agents/specific_instructions/ml_engineer/phases/phase-2.md +75 -0
  172. package/src/agents/specific_instructions/ml_engineer/phases/phase-3.md +124 -0
  173. package/src/agents/specific_instructions/ml_engineer/phases/phase-4.md +279 -0
  174. package/src/agents/specific_instructions/ml_engineer/phases/phase-5.md +160 -0
  175. package/src/agents/specific_instructions/ml_engineer/phases/phase-6-5.md +170 -0
  176. package/src/agents/specific_instructions/ml_engineer/phases/phase-6.md +295 -0
  177. package/src/agents/specific_instructions/ml_engineer/phases/phase-7.md +337 -0
  178. package/src/agents/specific_instructions/ml_engineer/phases.md +1068 -0
  179. package/src/agents/specific_instructions/ml_engineer/research.md +437 -0
  180. package/src/agents/specific_instructions/ml_engineer/research_ui_mode.md +71 -0
  181. package/src/agents/specific_instructions/ml_engineer/review.md +187 -0
  182. package/src/agents/specific_instructions/ml_engineer/service_mode.md +273 -0
  183. package/src/agents/specific_instructions/ml_engineer/validation_checklist.md +185 -0
  184. package/src/agents/specific_instructions/mlops_engineer/advise.md +139 -0
  185. package/src/agents/specific_instructions/mlops_engineer/phases/index.md +23 -0
  186. package/src/agents/specific_instructions/mlops_engineer/phases/phase-1.md +52 -0
  187. package/src/agents/specific_instructions/mlops_engineer/phases/phase-2.md +86 -0
  188. package/src/agents/specific_instructions/mlops_engineer/phases/phase-3.md +105 -0
  189. package/src/agents/specific_instructions/mlops_engineer/phases/phase-4.md +128 -0
  190. package/src/agents/specific_instructions/mlops_engineer/phases/phase-5.md +106 -0
  191. package/src/agents/specific_instructions/mlops_engineer/phases/phase-6.md +128 -0
  192. package/src/agents/specific_instructions/mlops_engineer/phases/phase-7.md +144 -0
  193. package/src/agents/specific_instructions/mlops_engineer/phases.md +671 -0
  194. package/src/agents/specific_instructions/mlops_engineer/review.md +164 -0
  195. package/src/agents/specific_instructions/mlops_engineer/service_mode.md +81 -0
  196. package/src/agents/specific_instructions/mlops_engineer/validation_checklist.md +151 -0
  197. package/src/agents/specific_instructions/researcher/critical_review.md +292 -0
  198. package/src/agents/specific_instructions/researcher/review_checklist.md +67 -0
  199. package/src/agents/specific_instructions/researcher/service_mode.md +224 -0
  200. package/src/agents/specific_instructions/shared/auto_verify_mode.md +141 -0
  201. package/src/agents/specific_instructions/shared/autonomous_research.md +1289 -0
  202. package/src/agents/specific_instructions/shared/behavioral_rules.md +36 -0
  203. package/src/agents/specific_instructions/shared/diverge_protocol.md +387 -0
  204. package/src/agents/specific_instructions/shared/engineering_guidelines.md +136 -0
  205. package/src/agents/specific_instructions/shared/experiment_versioning.md +184 -0
  206. package/src/agents/specific_instructions/shared/goal_mode.md +187 -0
  207. package/src/agents/specific_instructions/shared/incremental_testing.md +139 -0
  208. package/src/agents/specific_instructions/shared/intent_discovery.md +223 -0
  209. package/src/agents/specific_instructions/shared/join_path_protocol.md +168 -0
  210. package/src/agents/specific_instructions/shared/knowledge_checkpoint.md +83 -0
  211. package/src/agents/specific_instructions/shared/knowledge_harvest.md +220 -0
  212. package/src/agents/specific_instructions/shared/knowledge_retrieval.md +100 -0
  213. package/src/agents/specific_instructions/shared/notebook_walkthrough_protocol.md +367 -0
  214. package/src/agents/specific_instructions/shared/reviewer_verdict_protocol.md +74 -0
  215. package/src/agents/specific_instructions/shared/swarm_protocol.md +97 -0
  216. package/src/agents/specific_instructions/shared/validation_protocol.md +139 -0
  217. package/src/agents/specific_instructions/syn/arbiter.md +140 -0
  218. package/src/agents/specific_instructions/syn/brainstorm.md +550 -0
  219. package/src/agents/specific_instructions/syn/code_review.md +232 -0
  220. package/src/agents/specific_instructions/syn/diff.md +239 -0
  221. package/src/agents/specific_instructions/syn/final_review.md +65 -0
  222. package/src/agents/specific_instructions/syn/fixer.md +240 -0
  223. package/src/agents/specific_instructions/syn/free_form.md +130 -0
  224. package/src/agents/specific_instructions/syn/knowledge.md +468 -0
  225. package/src/agents/specific_instructions/syn/notebook_walkthrough.md +78 -0
  226. package/src/agents/specific_instructions/syn/panel_review.md +634 -0
  227. package/src/agents/specific_instructions/syn/pm.md +453 -0
  228. package/src/agents/specific_instructions/syn/pr_review.md +255 -0
  229. package/src/agents/specific_instructions/syn/slides.md +417 -0
  230. package/src/agents/syn.md +729 -0
  231. package/src/commands/academic.md +41 -0
  232. package/src/commands/ai-engineer.md +45 -0
  233. package/src/commands/analytics-engineer.md +48 -0
  234. package/src/commands/applied-ml-scientist.md +45 -0
  235. package/src/commands/backend-engineer.md +35 -0
  236. package/src/commands/bi-engineer.md +40 -0
  237. package/src/commands/brainstorm.md +24 -0
  238. package/src/commands/data-analyst.md +38 -0
  239. package/src/commands/data-engineer.md +37 -0
  240. package/src/commands/data-modeller.md +38 -0
  241. package/src/commands/data-scientist.md +38 -0
  242. package/src/commands/deep-learning-engineer.md +47 -0
  243. package/src/commands/end.md +49 -0
  244. package/src/commands/knowledge.md +24 -0
  245. package/src/commands/ml-engineer.md +42 -0
  246. package/src/commands/mlops-engineer.md +47 -0
  247. package/src/commands/notebook-walkthrough.md +58 -0
  248. package/src/commands/researcher.md +40 -0
  249. package/src/commands/resume.md +57 -0
  250. package/src/commands/review-pr.md +26 -0
  251. package/src/commands/shards-guide.md +41 -0
  252. package/src/commands/shards-ui.md +32 -0
  253. package/src/commands/shards.md +41 -0
  254. package/src/docs/01-getting-started/concepts.md +109 -0
  255. package/src/docs/01-getting-started/first-session.md +79 -0
  256. package/src/docs/01-getting-started/install.md +61 -0
  257. package/src/docs/02-agents/academic.md +71 -0
  258. package/src/docs/02-agents/ai-engineer.md +78 -0
  259. package/src/docs/02-agents/analytics-engineer.md +58 -0
  260. package/src/docs/02-agents/applied-ml-scientist.md +59 -0
  261. package/src/docs/02-agents/backend-engineer.md +58 -0
  262. package/src/docs/02-agents/bi-engineer.md +65 -0
  263. package/src/docs/02-agents/data-analyst.md +67 -0
  264. package/src/docs/02-agents/data-engineer.md +57 -0
  265. package/src/docs/02-agents/data-modeller.md +51 -0
  266. package/src/docs/02-agents/data-scientist.md +78 -0
  267. package/src/docs/02-agents/deep-learning-engineer.md +64 -0
  268. package/src/docs/02-agents/ml-engineer.md +80 -0
  269. package/src/docs/02-agents/mlops-engineer.md +59 -0
  270. package/src/docs/02-agents/overview.md +62 -0
  271. package/src/docs/02-agents/researcher.md +73 -0
  272. package/src/docs/02-agents/syn.md +88 -0
  273. package/src/docs/03-protocols/auto-verify.md +82 -0
  274. package/src/docs/03-protocols/autonomous-research.md +59 -0
  275. package/src/docs/03-protocols/behavioral-rules.md +35 -0
  276. package/src/docs/03-protocols/diverge.md +50 -0
  277. package/src/docs/03-protocols/engineering-guidelines.md +56 -0
  278. package/src/docs/03-protocols/experiment-versioning.md +38 -0
  279. package/src/docs/03-protocols/gate-pattern.md +65 -0
  280. package/src/docs/03-protocols/incremental-testing.md +68 -0
  281. package/src/docs/03-protocols/join-path.md +46 -0
  282. package/src/docs/03-protocols/knowledge-ledger.md +70 -0
  283. package/src/docs/03-protocols/reviewer-verdicts.md +39 -0
  284. package/src/docs/03-protocols/swarm.md +40 -0
  285. package/src/docs/03-protocols/validation.md +174 -0
  286. package/src/docs/04-ui/activity-bar.md +70 -0
  287. package/src/docs/04-ui/chat-pane.md +80 -0
  288. package/src/docs/04-ui/code-intel.md +62 -0
  289. package/src/docs/04-ui/file-editing.md +61 -0
  290. package/src/docs/04-ui/git.md +54 -0
  291. package/src/docs/04-ui/keybindings.md +79 -0
  292. package/src/docs/04-ui/knowledge-map.md +76 -0
  293. package/src/docs/04-ui/overview.md +93 -0
  294. package/src/docs/04-ui/panels.md +49 -0
  295. package/src/docs/04-ui/pinboard-selection.md +66 -0
  296. package/src/docs/04-ui/quick-open-palette.md +56 -0
  297. package/src/docs/04-ui/sessions.md +81 -0
  298. package/src/docs/04-ui/settings-permissions.md +56 -0
  299. package/src/docs/05-commands/reference.md +59 -0
  300. package/src/docs/06-outputs/directory-map.md +116 -0
  301. package/src/docs/07-workflows/ai-eval-first.md +57 -0
  302. package/src/docs/07-workflows/deep-study-to-production.md +76 -0
  303. package/src/docs/07-workflows/diverge-exploration.md +77 -0
  304. package/src/docs/07-workflows/quick-analysis.md +45 -0
  305. package/src/docs/08-integrations/claude-code-auto-mode.md +191 -0
  306. package/src/docs/08-integrations/google-slides.md +175 -0
  307. package/src/docs/README.md +30 -0
  308. package/src/docs/manifest.json +108 -0
  309. package/src/templates/analysis-template.md +20 -0
  310. package/src/templates/branch-report.md +46 -0
  311. package/src/templates/diff-report.md +88 -0
  312. package/src/templates/knowledge-index.md +7 -0
  313. package/src/templates/model-card-schema.json +186 -0
  314. package/src/templates/model-card-schema.md +88 -0
  315. package/src/templates/model-card.md +124 -0
  316. package/src/templates/project-plan.md +47 -0
  317. package/src/templates/project-specs.md +81 -0
  318. package/src/templates/report-template.md +43 -0
  319. package/src/templates/study-template.md +25 -0
  320. package/src/ui/cc-readonly.js +181 -0
  321. package/src/ui/chat-session.js +466 -0
  322. package/src/ui/css/base.css +136 -0
  323. package/src/ui/css/brainstorm.css +525 -0
  324. package/src/ui/css/chat.css +1405 -0
  325. package/src/ui/css/editor.css +546 -0
  326. package/src/ui/css/eval-dashboard.css +157 -0
  327. package/src/ui/css/experiment.css +237 -0
  328. package/src/ui/css/guide.css +186 -0
  329. package/src/ui/css/knowledge-map.css +383 -0
  330. package/src/ui/css/layout.css +431 -0
  331. package/src/ui/css/model-card.css +161 -0
  332. package/src/ui/css/notebook-walkthrough.css +271 -0
  333. package/src/ui/css/pr-review.css +403 -0
  334. package/src/ui/css/prompt-lab.css +325 -0
  335. package/src/ui/css/sessions.css +258 -0
  336. package/src/ui/css/sidebar.css +661 -0
  337. package/src/ui/css/terminal.css +113 -0
  338. package/src/ui/css/theme-light.css +542 -0
  339. package/src/ui/index.html +389 -0
  340. package/src/ui/js/agents.js +32 -0
  341. package/src/ui/js/bookmarks.js +230 -0
  342. package/src/ui/js/chat.js +1776 -0
  343. package/src/ui/js/code-intel.js +328 -0
  344. package/src/ui/js/command-palette.js +142 -0
  345. package/src/ui/js/events.js +591 -0
  346. package/src/ui/js/explorer.js +317 -0
  347. package/src/ui/js/file-view.js +477 -0
  348. package/src/ui/js/git.js +536 -0
  349. package/src/ui/js/guide.js +198 -0
  350. package/src/ui/js/hud.js +75 -0
  351. package/src/ui/js/init.js +351 -0
  352. package/src/ui/js/knowledge-map.js +906 -0
  353. package/src/ui/js/markdown.js +114 -0
  354. package/src/ui/js/monaco.js +164 -0
  355. package/src/ui/js/notebook-walkthrough.js +272 -0
  356. package/src/ui/js/notebook.js +448 -0
  357. package/src/ui/js/panels.js +2681 -0
  358. package/src/ui/js/pinboard.js +186 -0
  359. package/src/ui/js/quick-open.js +164 -0
  360. package/src/ui/js/selection-context.js +131 -0
  361. package/src/ui/js/sessions.js +256 -0
  362. package/src/ui/js/settings.js +476 -0
  363. package/src/ui/js/split-view.js +82 -0
  364. package/src/ui/js/state.js +343 -0
  365. package/src/ui/js/table.js +161 -0
  366. package/src/ui/js/tabs.js +284 -0
  367. package/src/ui/js/tabular.js +125 -0
  368. package/src/ui/js/terminal.js +354 -0
  369. package/src/ui/js/timeline.js +137 -0
  370. package/src/ui/js/utils.js +293 -0
  371. package/src/ui/notebook-kernel.py +790 -0
  372. package/src/ui/open-browser.js +55 -0
  373. package/src/ui/permission-pattern.js +42 -0
  374. package/src/ui/relay.js +513 -0
  375. package/src/ui/server.js +3072 -0
  376. package/src/ui/session-index.js +225 -0
  377. package/src/ui/shards_icon.png +0 -0
  378. package/src/ui/spawn-server.js +41 -0
  379. package/src/ui/symbol-index.js +813 -0
  380. package/src/ui/ui-push.js +177 -0
  381. package/tools/gate-hook/VALIDATION_SPEC.md +273 -0
  382. package/tools/gate-hook/__tests__/auto-verify.test.js +343 -0
  383. package/tools/gate-hook/auto-allowlist.js +179 -0
  384. package/tools/gate-hook/auto-state.js +68 -0
  385. package/tools/gate-hook/classify.js +21 -0
  386. package/tools/gate-hook/log.js +57 -0
  387. package/tools/gate-hook/parser.js +205 -0
  388. package/tools/gate-hook/sql-guard.js +230 -0
  389. package/tools/gate-hook/state.js +170 -0
  390. package/tools/gate-hook/sweep.js +139 -0
  391. package/tools/gate-hook/transcript.js +45 -0
  392. package/tools/gate-hook/validation.js +321 -0
  393. package/tools/gate-hook.js +475 -0
  394. package/tools/install.js +914 -0
  395. package/tools/shards-gates.js +311 -0
  396. package/tools/shards-sessions.js +261 -0
  397. package/tools/shards-ui.js +377 -0
@@ -0,0 +1,181 @@
1
+ 'use strict';
2
+
3
+ // Replicates Claude Code's built-in read-only classifier. The UI's intercept
4
+ // path checks only .claude/settings.json allow rules, so CC's built-in
5
+ // read-only commands wrongly surface as permission cards. This module mirrors
6
+ // CC's built-in set so those commands auto-approve.
7
+
8
+ // Tools that CC treats as read-only built-ins in every permission mode.
9
+ const CC_READONLY_TOOLS = new Set([
10
+ 'Read', 'Glob', 'Grep', 'WebSearch',
11
+ ]);
12
+
13
+ // Bash command prefixes that CC treats as read-only built-ins.
14
+ // Matched as: command.trim() === prefix || command.startsWith(prefix + ' ')
15
+ const CC_READONLY_BASH_PREFIXES = [
16
+ // Bare read-only commands (from the install.js built-ins comment)
17
+ 'ls', 'cat', 'echo', 'pwd', 'head', 'tail', 'grep', 'find', 'wc',
18
+ 'which', 'diff', 'stat', 'du', 'cd',
19
+ // Read-only git forms (from READONLY_PRESET). Only subcommand forms that
20
+ // cannot mutate refs/config are listed: bare `git branch`/`git tag`/
21
+ // `git remote` also match `-d`, `-D`, `-m`, `-M`, `add`, `remove`,
22
+ // `set-url`, and positional-arg creation, so they must NOT be treated as
23
+ // read-only.
24
+ 'git status',
25
+ 'git log',
26
+ 'git diff',
27
+ 'git show',
28
+ 'git rev-parse',
29
+ 'git stash list',
30
+ 'git branch --list',
31
+ 'git branch -a',
32
+ 'git branch -r',
33
+ 'git branch -v',
34
+ 'git branch -vv',
35
+ 'git branch --remotes',
36
+ 'git branch --merged',
37
+ 'git branch --no-merged',
38
+ 'git branch --show-current',
39
+ 'git branch --contains',
40
+ 'git tag --list',
41
+ 'git tag -l',
42
+ 'git remote -v',
43
+ 'git remote get-url',
44
+ 'git remote show',
45
+ ];
46
+
47
+ // Bash patterns that indicate destructive intent. Even if a more permissive
48
+ // prefix matches above, these veto the auto-approval. Belt-and-braces.
49
+ const DESTRUCTIVE_MARKERS = [
50
+ /\brm\b/, /\bmv\b/, /\bcp\s+-/, // basic destructive
51
+ />\s*[^|]/, // shell redirect to file
52
+ />>\s*/, // append redirect
53
+ /\bsudo\b/,
54
+ /\bcurl\b/, /\bwget\b/, // network fetches that may exfiltrate
55
+ /\|\s*sh\b/, /\|\s*bash\b/, // pipe-to-shell
56
+ /\$\([^)]/, // command substitution — bail (could hide anything)
57
+ /`[^`]/, // backtick command substitution
58
+ // find — -delete and -exec/-execdir/-ok/-okdir run arbitrary (often
59
+ // destructive) work with no `rm`/`;` present to trip the other markers;
60
+ // -fprint/-fprint0/-fprintf/-fls write output to a file (path-controlled
61
+ // write). `-ok` must not match `-okdir` (its exec-per-file prompt sibling),
62
+ // and `-fprint` must not match `-fprintf`, so each is listed separately;
63
+ // `-printf`/`-ls`/`-print0` (stdout-only forms) stay read-only.
64
+ /\s-delete\b/,
65
+ /\s-exec\b/,
66
+ /\s-execdir\b/,
67
+ /\s-ok\b/,
68
+ /\s-okdir\b/,
69
+ /\s-fprint(?:0)?\b/,
70
+ /\s-fprintf\b/,
71
+ /\s-fls\b/,
72
+ // git branch — the `-v`/`-vv` listing forms silently become CREATES when a
73
+ // bare branch name follows (`git branch -v feature` creates `feature`).
74
+ // Listing with `-v`/`-vv` never takes a positional, so any non-option token
75
+ // right after them is a create intent.
76
+ /\bgit\s+branch\s+-v+\s+[^\s-]/,
77
+ // git diff/show/log — --output=FILE / --output FILE / -o FILE silently
78
+ // writes a patch file. `--output-indicator-*` (a read-only diff styling
79
+ // flag) must not match.
80
+ /--output(?=\s|=)/,
81
+ /\bgit\s+(?:diff|show|log)\b[^\n]*\s-o(?=\s*\S)/,
82
+ ];
83
+
84
+ // Compound separator detection — a single allow shouldn't authorize
85
+ // `safe-cmd && rm -rf /`. If we see compound separators, bail.
86
+ // Covers `&&`, `||`, `;`, `|`, a lone backgrounding `&` (`cat x & rm ...`),
87
+ // and a literal newline (a command separator in bash when the model emits a
88
+ // multi-line tool call). `&&`/`||` are matched by their own alternatives so
89
+ // lone `&`/`|` (e.g. inside `$((..))` arithmetic) can't double-match.
90
+ const COMPOUND_SEPARATORS = /(\&\&|\|\||[;&\n]|\|(?!\|))/;
91
+
92
+ function isReadOnlyTool(toolName) {
93
+ if (!toolName) return false;
94
+ return CC_READONLY_TOOLS.has(toolName);
95
+ }
96
+
97
+ // Mask literal quoted spans so the veto scanners don't fire on them (used by
98
+ // isCcReadOnlyBash). Single quotes are fully literal to bash — mask through
99
+ // the closing quote. Double quotes are masked only when the span contains no
100
+ // `$`, backtick, or backslash, since those can still trigger expansion or
101
+ // command substitution inside the quotes.
102
+ function maskQuotedRegions(cmd) {
103
+ let out = '';
104
+ for (let i = 0; i < cmd.length; i++) {
105
+ const ch = cmd[i];
106
+ if (ch === "'") {
107
+ const end = cmd.indexOf("'", i + 1);
108
+ const stop = end === -1 ? cmd.length : end + 1;
109
+ out += ' '.repeat(stop - i);
110
+ i = stop - 1;
111
+ } else if (ch === '"') {
112
+ const end = cmd.indexOf('"', i + 1);
113
+ if (end === -1) {
114
+ out += ch;
115
+ continue;
116
+ }
117
+ const span = cmd.slice(i + 1, end);
118
+ if (!/[$`\\]/.test(span)) {
119
+ out += ' '.repeat(end - i + 1);
120
+ i = end;
121
+ } else {
122
+ out += ch;
123
+ }
124
+ } else {
125
+ out += ch;
126
+ }
127
+ }
128
+ return out;
129
+ }
130
+
131
+ function isCcReadOnlyBash(command) {
132
+ if (typeof command !== 'string') return false;
133
+ const cmd = command.trim();
134
+ if (!cmd) return false;
135
+
136
+ // Veto scans run over the whole command string, so skip literal spans:
137
+ // `grep 'rm' file` and `echo "a|b"` are read-only and must not be vetoed by
138
+ // word matches inside quoted text. Everything inside single quotes is
139
+ // literal to bash (mask outright). Double quotes only mask when the span
140
+ // can't execute anything — a `$`, backtick, or backslash inside double
141
+ // quotes can still run expansion/command substitution, so those spans stay
142
+ // visible to the veto scanners.
143
+ const masked = maskQuotedRegions(cmd);
144
+
145
+ // Reject compound commands outright.
146
+ if (COMPOUND_SEPARATORS.test(masked)) return false;
147
+
148
+ // Destructive markers veto.
149
+ for (const re of DESTRUCTIVE_MARKERS) {
150
+ if (re.test(masked)) return false;
151
+ }
152
+
153
+ // Prefix match against the read-only list.
154
+ for (const prefix of CC_READONLY_BASH_PREFIXES) {
155
+ if (cmd === prefix) return true;
156
+ if (cmd.startsWith(prefix + ' ')) return true;
157
+ }
158
+
159
+ return false;
160
+ }
161
+
162
+ function isCcReadOnlyAutoApprovable(toolName, toolInput) {
163
+ if (!toolName) return false;
164
+
165
+ // Always-safe tools
166
+ if (isReadOnlyTool(toolName)) return true;
167
+
168
+ if (toolName !== 'Bash') return false;
169
+ if (!toolInput || typeof toolInput.command !== 'string') return false;
170
+
171
+ return isCcReadOnlyBash(toolInput.command);
172
+ }
173
+
174
+ module.exports = {
175
+ CC_READONLY_TOOLS,
176
+ CC_READONLY_BASH_PREFIXES,
177
+ isReadOnlyTool,
178
+ isCcReadOnlyBash,
179
+ isCcReadOnlyAutoApprovable,
180
+ maskQuotedRegions,
181
+ };
@@ -0,0 +1,466 @@
1
+ 'use strict';
2
+
3
+ const { spawn } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const { randomUUID } = require('crypto');
7
+
8
+ const LOG_FILE = path.join(process.cwd(), '.shards', 'ui.log');
9
+
10
+ function log(msg) {
11
+ const ts = new Date().toISOString();
12
+ try { fs.appendFileSync(LOG_FILE, `[${ts}] [chat-session] ${msg}\n`); } catch {}
13
+ }
14
+
15
+ class ChatSession {
16
+ constructor({ agent, sessionId, resumeSessionId, cwd, sessionsDir, permissionMode, model, onEvent, onExit, addDir, mcpConfig, betas }) {
17
+ this.agent = agent;
18
+ this.sessionId = sessionId || randomUUID();
19
+ this.resumeSessionId = resumeSessionId || null;
20
+ this.cwd = cwd || process.cwd();
21
+ this.sessionsDir = sessionsDir || path.join(this.cwd, '.shards', 'sessions');
22
+ this.permissionMode = permissionMode || 'acceptEdits';
23
+ this.model = model || null;
24
+ this.addDir = addDir || null;
25
+ this.mcpConfig = mcpConfig || null;
26
+ this.betas = betas || null;
27
+ this.onEvent = onEvent || (() => {});
28
+ this.onExit = onExit || (() => {});
29
+ this.child = null;
30
+ this.startedAt = null;
31
+ this._buffer = '';
32
+ this._responding = false;
33
+ }
34
+
35
+ start() {
36
+ const args = [
37
+ '-p',
38
+ '--output-format', 'stream-json',
39
+ '--input-format', 'stream-json',
40
+ '--verbose',
41
+ '--include-partial-messages',
42
+ '--forward-subagent-text',
43
+ '--permission-mode', this.permissionMode,
44
+ ];
45
+
46
+ if (this.agent) {
47
+ args.push('--agent', this.agent);
48
+ }
49
+
50
+ if (this.resumeSessionId) {
51
+ args.push('--resume', this.resumeSessionId);
52
+ args.push('--fork-session');
53
+ // Omit --session-id when forking; CLI generates the new ID
54
+ } else {
55
+ args.push('--session-id', this.sessionId);
56
+ }
57
+
58
+ if (this.model) {
59
+ args.push('--model', this.model);
60
+ }
61
+
62
+ if (this.addDir) {
63
+ args.push('--add-dir', this.addDir);
64
+ }
65
+
66
+ if (this.mcpConfig) {
67
+ args.push('--mcp-config', this.mcpConfig);
68
+ }
69
+
70
+ if (this.betas) {
71
+ args.push('--betas', this.betas);
72
+ }
73
+
74
+ log(`Spawning claude CLI for agent="${this.agent || '(plain)'}" session="${this.sessionId}" permissionMode="${this.permissionMode}"${this.resumeSessionId ? ` resume="${this.resumeSessionId}"` : ''}`);
75
+
76
+ // P4: Spawn detached so process survives server restarts
77
+ this.child = spawn('claude', args, {
78
+ cwd: this.cwd,
79
+ detached: true,
80
+ stdio: ['pipe', 'pipe', 'pipe'],
81
+ env: { ...process.env },
82
+ });
83
+
84
+ // Don't let the child keep the parent alive
85
+ this.child.unref();
86
+
87
+ this.startedAt = new Date().toISOString();
88
+ log(`claude process spawned, PID=${this.child.pid}`);
89
+
90
+ // P4: Write session metadata for reconnection
91
+ this._writeMetadata();
92
+
93
+ this._attachStreams();
94
+ }
95
+
96
+ // P4: Reconnect to an existing detached process
97
+ reconnect(pid) {
98
+ log(`Attempting reconnect to PID=${pid} for session="${this.sessionId}"`);
99
+
100
+ // We can't reattach to stdio of a detached process without IPC.
101
+ // Instead, we verify the process is alive and mark it as connected.
102
+ // The process will eventually exit and we'll detect that via polling.
103
+ try {
104
+ process.kill(pid, 0); // throws if not alive
105
+ } catch {
106
+ log(`PID=${pid} is not alive, cannot reconnect`);
107
+ return false;
108
+ }
109
+
110
+ this.startedAt = this.startedAt || new Date().toISOString();
111
+ this._responding = false;
112
+
113
+ // Start a heartbeat poller to detect when the process dies
114
+ this._heartbeatInterval = setInterval(() => {
115
+ try {
116
+ process.kill(pid, 0);
117
+ this._updateMetadata();
118
+ } catch {
119
+ // Process died while server was down or between heartbeats
120
+ clearInterval(this._heartbeatInterval);
121
+ this._heartbeatInterval = null;
122
+ log(`Heartbeat: PID=${pid} is dead for session="${this.sessionId}"`);
123
+ this._removeMetadata();
124
+ this.onExit({ code: null, sessionId: this.sessionId });
125
+ }
126
+ }, 5000);
127
+
128
+ this._reconnectedPid = pid;
129
+ return true;
130
+ }
131
+
132
+ _attachStreams() {
133
+ // Parse stdout line by line (JSONL)
134
+ this.child.stdout.on('data', (chunk) => {
135
+ this._buffer += chunk.toString();
136
+ const lines = this._buffer.split('\n');
137
+ this._buffer = lines.pop();
138
+ for (const line of lines) {
139
+ if (line.trim()) this._parseLine(line.trim());
140
+ }
141
+ });
142
+
143
+ this.child.stderr.on('data', (chunk) => {
144
+ const text = chunk.toString().trim();
145
+ if (text) {
146
+ log(`stderr: ${text}`);
147
+ this.onEvent({ type: 'chat-stderr', text, sessionId: this.sessionId });
148
+ }
149
+ });
150
+
151
+ this.child.on('close', (code) => {
152
+ log(`claude process exited, code=${code}, agent="${this.agent}", session="${this.sessionId}"`);
153
+ this.child = null;
154
+ this._responding = false;
155
+ this._removeMetadata();
156
+ this.onExit({ code, sessionId: this.sessionId });
157
+ });
158
+
159
+ this.child.on('error', (err) => {
160
+ log(`claude process error: ${err.message}`);
161
+ this.onEvent({ type: 'chat-error', error: err.message, sessionId: this.sessionId });
162
+ });
163
+ }
164
+
165
+ _parseLine(line) {
166
+ let data;
167
+ try {
168
+ data = JSON.parse(line);
169
+ } catch {
170
+ return;
171
+ }
172
+
173
+ const { type } = data;
174
+
175
+ if (type === 'system' && data.subtype === 'init') {
176
+ // When forking, the CLI assigns a new session ID internally. We do NOT
177
+ // update this.sessionId — the server's sessions map and the browser both
178
+ // know us by the original randomUUID. If we changed it here, all
179
+ // subsequent broadcasts would carry the CLI-assigned ID and the browser
180
+ // would silently drop them because it can't find a matching session.
181
+ // The CLI's internal ID is irrelevant for in-memory routing; the
182
+ // metadata file (written by start()) keeps the original ID for
183
+ // reconnectOrCleanup to find. See the integration audit for the full
184
+ // trace of why this.sessionId must stay unchanged.
185
+ this.onEvent({ type: 'chat-init', sessionId: this.sessionId, data });
186
+ return;
187
+ }
188
+
189
+ if (type === 'stream_event') {
190
+ const evt = data.event;
191
+ if (!evt) return;
192
+
193
+ if (evt.type === 'content_block_delta' && evt.delta) {
194
+ if (evt.delta.type === 'text_delta') {
195
+ this._responding = true;
196
+ this.onEvent({
197
+ type: 'chat-token',
198
+ text: evt.delta.text,
199
+ index: evt.index,
200
+ sessionId: this.sessionId,
201
+ });
202
+ } else if (evt.delta.type === 'input_json_delta') {
203
+ this.onEvent({
204
+ type: 'chat-tool-input-delta',
205
+ partial_json: evt.delta.partial_json,
206
+ index: evt.index,
207
+ sessionId: this.sessionId,
208
+ });
209
+ } else if (evt.delta.type === 'thinking_delta') {
210
+ this._responding = true;
211
+ this.onEvent({
212
+ type: 'chat-thinking-token',
213
+ text: evt.delta.thinking,
214
+ index: evt.index,
215
+ sessionId: this.sessionId,
216
+ });
217
+ }
218
+ return;
219
+ }
220
+
221
+ if (evt.type === 'content_block_start' && evt.content_block) {
222
+ if (evt.content_block.type === 'tool_use') {
223
+ this.onEvent({
224
+ type: 'chat-tool-use',
225
+ tool: evt.content_block.name,
226
+ id: evt.content_block.id,
227
+ index: evt.index,
228
+ sessionId: this.sessionId,
229
+ });
230
+ }
231
+ return;
232
+ }
233
+
234
+ if (evt.type === 'content_block_stop') {
235
+ this.onEvent({
236
+ type: 'chat-block-stop',
237
+ index: evt.index,
238
+ sessionId: this.sessionId,
239
+ });
240
+ return;
241
+ }
242
+
243
+ if (evt.type === 'message_start') {
244
+ const usage = evt.message && evt.message.usage;
245
+ if (usage && typeof usage.input_tokens === 'number') {
246
+ this.onEvent({
247
+ type: 'chat-usage',
248
+ sessionId: this.sessionId,
249
+ usage: {
250
+ inputTokens: usage.input_tokens,
251
+ cacheReadTokens: usage.cache_read_input_tokens || 0,
252
+ cacheCreationTokens: usage.cache_creation_input_tokens || 0,
253
+ outputTokens: usage.output_tokens || 0,
254
+ },
255
+ });
256
+ }
257
+ return;
258
+ }
259
+ if (evt.type === 'message_delta' || evt.type === 'message_stop') {
260
+ return;
261
+ }
262
+
263
+ return;
264
+ }
265
+
266
+ if (type === 'assistant') {
267
+ const content = data.message && data.message.content;
268
+ const hasText = Array.isArray(content) && content.some(b => b.type === 'text');
269
+ if (!hasText) return;
270
+ this._responding = false;
271
+ this.onEvent({
272
+ type: 'chat-message',
273
+ content,
274
+ sessionId: this.sessionId,
275
+ });
276
+ return;
277
+ }
278
+
279
+ if (type === 'result') {
280
+ this._responding = false;
281
+ this.onEvent({
282
+ type: 'chat-turn-end',
283
+ sessionId: this.sessionId,
284
+ cost: data.cost_usd,
285
+ duration: data.duration_ms,
286
+ });
287
+ return;
288
+ }
289
+
290
+ this.onEvent({ type: 'chat-unknown', raw: data, sessionId: this.sessionId });
291
+ }
292
+
293
+ send(message, attachments) {
294
+ if (!this.child || !this.child.stdin.writable) {
295
+ throw new Error('Chat session is not running');
296
+ }
297
+ // Build the content array. Anthropic's Messages API recommends image blocks
298
+ // before the text block when both are present, since the text typically
299
+ // references the image. An empty text block is invalid, so we omit it when
300
+ // the user sent only attachments.
301
+ const content = [];
302
+ if (Array.isArray(attachments)) {
303
+ for (const a of attachments) {
304
+ if (!a || !a.dataBase64 || !a.mediaType) continue;
305
+ content.push({
306
+ type: 'image',
307
+ source: {
308
+ type: 'base64',
309
+ media_type: a.mediaType,
310
+ data: a.dataBase64,
311
+ },
312
+ });
313
+ }
314
+ }
315
+ if (message && message.length > 0) {
316
+ content.push({ type: 'text', text: message });
317
+ }
318
+ if (content.length === 0) {
319
+ // Should be unreachable — /chat/send rejects empty payloads — but guard
320
+ // against a degenerate input rather than emit an invalid stream-json frame.
321
+ throw new Error('Empty message: no text and no valid attachments');
322
+ }
323
+ const payload = {
324
+ type: 'user',
325
+ message: {
326
+ role: 'user',
327
+ content,
328
+ },
329
+ };
330
+ this.child.stdin.write(JSON.stringify(payload) + '\n');
331
+ this._responding = true;
332
+ this._updateMetadata();
333
+ }
334
+
335
+ stop() {
336
+ if (this._heartbeatInterval) {
337
+ clearInterval(this._heartbeatInterval);
338
+ this._heartbeatInterval = null;
339
+ }
340
+ if (this._reconnectedPid) {
341
+ try { process.kill(this._reconnectedPid, 'SIGTERM'); } catch {}
342
+ this._reconnectedPid = null;
343
+ }
344
+ if (this.child) {
345
+ this.child.kill('SIGTERM');
346
+ }
347
+ }
348
+
349
+ get isRunning() {
350
+ return this.child !== null || this._reconnectedPid !== null;
351
+ }
352
+
353
+ get isResponding() {
354
+ return this._responding;
355
+ }
356
+
357
+ get info() {
358
+ return {
359
+ agent: this.agent,
360
+ sessionId: this.sessionId,
361
+ startedAt: this.startedAt,
362
+ running: this.isRunning,
363
+ responding: this._responding,
364
+ };
365
+ }
366
+
367
+ // P4: Session metadata persistence
368
+
369
+ _metadataPath(sid) {
370
+ return path.join(this.sessionsDir, `${sid || this.sessionId}.json`);
371
+ }
372
+
373
+ _writeMetadata() {
374
+ try {
375
+ fs.mkdirSync(this.sessionsDir, { recursive: true });
376
+ fs.writeFileSync(this._metadataPath(), JSON.stringify({
377
+ sessionId: this.sessionId,
378
+ agent: this.agent,
379
+ pid: this.child ? this.child.pid : (this._reconnectedPid || null),
380
+ startedAt: this.startedAt,
381
+ lastActivityAt: new Date().toISOString(),
382
+ }));
383
+ } catch {}
384
+ }
385
+
386
+ _updateMetadata() {
387
+ try {
388
+ const meta = JSON.parse(fs.readFileSync(this._metadataPath(), 'utf8'));
389
+ meta.lastActivityAt = new Date().toISOString();
390
+ fs.writeFileSync(this._metadataPath(), JSON.stringify(meta));
391
+ } catch {}
392
+ }
393
+
394
+ _removeMetadata() {
395
+ try { fs.unlinkSync(this._metadataPath()); } catch {}
396
+ }
397
+ }
398
+
399
+ // P4: Reconnect to orphaned sessions or clean up dead ones
400
+ function reconnectOrCleanup(sessionsDir, sessionsMap, SessionStoreClass, onEvent, onExit, cwd) {
401
+ if (!fs.existsSync(sessionsDir)) return;
402
+
403
+ try {
404
+ const files = fs.readdirSync(sessionsDir);
405
+ for (const file of files) {
406
+ if (!file.endsWith('.json')) continue;
407
+
408
+ const metaPath = path.join(sessionsDir, file);
409
+ let meta;
410
+ try {
411
+ meta = JSON.parse(fs.readFileSync(metaPath, 'utf8'));
412
+ } catch {
413
+ try { fs.unlinkSync(metaPath); } catch {}
414
+ continue;
415
+ }
416
+
417
+ const { sessionId, agent, pid } = meta;
418
+ if (!pid || !sessionId) {
419
+ try { fs.unlinkSync(metaPath); } catch {}
420
+ continue;
421
+ }
422
+
423
+ // Check if the process is still alive
424
+ let alive = false;
425
+ try {
426
+ process.kill(pid, 0);
427
+ alive = true;
428
+ } catch {}
429
+
430
+ if (!alive) {
431
+ // Process died while server was down — clean up
432
+ log(`reconnectOrCleanup: session ${sessionId} (PID=${pid}) is dead, cleaning up`);
433
+ try { fs.unlinkSync(metaPath); } catch {}
434
+ continue;
435
+ }
436
+
437
+ // Process is alive — attempt reconnect
438
+ log(`reconnectOrCleanup: reconnecting to session ${sessionId} (PID=${pid}, agent=${agent})`);
439
+
440
+ const chatSess = new ChatSession({
441
+ agent,
442
+ sessionId,
443
+ cwd,
444
+ sessionsDir,
445
+ onEvent,
446
+ onExit,
447
+ });
448
+ chatSess.startedAt = meta.startedAt;
449
+
450
+ if (chatSess.reconnect(pid)) {
451
+ const store = new SessionStoreClass({ sessionId, agent });
452
+ store.chatSession = chatSess;
453
+ store.createdAt = new Date(meta.startedAt);
454
+ store.lastActivityAt = new Date(meta.lastActivityAt || meta.startedAt);
455
+ sessionsMap.set(sessionId, store);
456
+ log(`reconnectOrCleanup: successfully reconnected session ${sessionId}`);
457
+ } else {
458
+ try { fs.unlinkSync(metaPath); } catch {}
459
+ }
460
+ }
461
+ } catch (err) {
462
+ log(`reconnectOrCleanup error: ${err.message}`);
463
+ }
464
+ }
465
+
466
+ module.exports = { ChatSession, reconnectOrCleanup };