oh-my-claude-sisyphus 3.6.1 → 3.6.3

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 (308) hide show
  1. package/commands/doctor.md +1 -1
  2. package/commands/psm.md +180 -0
  3. package/dist/__tests__/analytics/analytics-summary.test.d.ts +2 -0
  4. package/dist/__tests__/analytics/analytics-summary.test.d.ts.map +1 -0
  5. package/dist/__tests__/analytics/analytics-summary.test.js +267 -0
  6. package/dist/__tests__/analytics/analytics-summary.test.js.map +1 -0
  7. package/dist/__tests__/analytics/cost-estimator.test.d.ts +2 -0
  8. package/dist/__tests__/analytics/cost-estimator.test.d.ts.map +1 -0
  9. package/dist/__tests__/analytics/cost-estimator.test.js +212 -0
  10. package/dist/__tests__/analytics/cost-estimator.test.js.map +1 -0
  11. package/dist/__tests__/hooks/auto-slash-command/executor.test.d.ts +7 -0
  12. package/dist/__tests__/hooks/auto-slash-command/executor.test.d.ts.map +1 -0
  13. package/dist/__tests__/hooks/auto-slash-command/executor.test.js +374 -0
  14. package/dist/__tests__/hooks/auto-slash-command/executor.test.js.map +1 -0
  15. package/dist/__tests__/hud/auto-tracking.integration.test.d.ts +2 -0
  16. package/dist/__tests__/hud/auto-tracking.integration.test.d.ts.map +1 -0
  17. package/dist/__tests__/hud/auto-tracking.integration.test.js +12 -0
  18. package/dist/__tests__/hud/auto-tracking.integration.test.js.map +1 -0
  19. package/dist/__tests__/installer.test.js +1 -1
  20. package/dist/__tests__/learned-skills/config.test.d.ts +2 -0
  21. package/dist/__tests__/learned-skills/config.test.d.ts.map +1 -0
  22. package/dist/__tests__/learned-skills/config.test.js +37 -0
  23. package/dist/__tests__/learned-skills/config.test.js.map +1 -0
  24. package/dist/__tests__/learned-skills/detector.test.d.ts +2 -0
  25. package/dist/__tests__/learned-skills/detector.test.d.ts.map +1 -0
  26. package/dist/__tests__/learned-skills/detector.test.js +99 -0
  27. package/dist/__tests__/learned-skills/detector.test.js.map +1 -0
  28. package/dist/__tests__/learned-skills/finder.test.d.ts +2 -0
  29. package/dist/__tests__/learned-skills/finder.test.d.ts.map +1 -0
  30. package/dist/__tests__/learned-skills/finder.test.js +59 -0
  31. package/dist/__tests__/learned-skills/finder.test.js.map +1 -0
  32. package/dist/__tests__/learned-skills/loader.test.d.ts +2 -0
  33. package/dist/__tests__/learned-skills/loader.test.d.ts.map +1 -0
  34. package/dist/__tests__/learned-skills/loader.test.js +69 -0
  35. package/dist/__tests__/learned-skills/loader.test.js.map +1 -0
  36. package/dist/__tests__/learned-skills/parser.test.d.ts +2 -0
  37. package/dist/__tests__/learned-skills/parser.test.d.ts.map +1 -0
  38. package/dist/__tests__/learned-skills/parser.test.js +81 -0
  39. package/dist/__tests__/learned-skills/parser.test.js.map +1 -0
  40. package/dist/__tests__/learned-skills/validator.test.d.ts +2 -0
  41. package/dist/__tests__/learned-skills/validator.test.d.ts.map +1 -0
  42. package/dist/__tests__/learned-skills/validator.test.js +85 -0
  43. package/dist/__tests__/learned-skills/validator.test.js.map +1 -0
  44. package/dist/__tests__/skills.test.js +6 -5
  45. package/dist/__tests__/skills.test.js.map +1 -1
  46. package/dist/agents/codex-agents.d.ts +20 -0
  47. package/dist/agents/codex-agents.d.ts.map +1 -0
  48. package/dist/agents/codex-agents.js +36 -0
  49. package/dist/agents/codex-agents.js.map +1 -0
  50. package/dist/agents/document-writer.d.ts +11 -0
  51. package/dist/agents/document-writer.d.ts.map +1 -0
  52. package/dist/agents/document-writer.js +209 -0
  53. package/dist/agents/document-writer.js.map +1 -0
  54. package/dist/agents/frontend-engineer.d.ts +11 -0
  55. package/dist/agents/frontend-engineer.d.ts.map +1 -0
  56. package/dist/agents/frontend-engineer.js +115 -0
  57. package/dist/agents/frontend-engineer.js.map +1 -0
  58. package/dist/agents/librarian.d.ts +12 -0
  59. package/dist/agents/librarian.d.ts.map +1 -0
  60. package/dist/agents/librarian.js +103 -0
  61. package/dist/agents/librarian.js.map +1 -0
  62. package/dist/agents/metis.d.ts +12 -0
  63. package/dist/agents/metis.d.ts.map +1 -0
  64. package/dist/agents/metis.js +117 -0
  65. package/dist/agents/metis.js.map +1 -0
  66. package/dist/agents/momus.d.ts +12 -0
  67. package/dist/agents/momus.d.ts.map +1 -0
  68. package/dist/agents/momus.js +128 -0
  69. package/dist/agents/momus.js.map +1 -0
  70. package/dist/agents/multimodal-looker.d.ts +11 -0
  71. package/dist/agents/multimodal-looker.d.ts.map +1 -0
  72. package/dist/agents/multimodal-looker.js +70 -0
  73. package/dist/agents/multimodal-looker.js.map +1 -0
  74. package/dist/agents/oracle.d.ts +13 -0
  75. package/dist/agents/oracle.d.ts.map +1 -0
  76. package/dist/agents/oracle.js +191 -0
  77. package/dist/agents/oracle.js.map +1 -0
  78. package/dist/agents/orchestrator-sisyphus.d.ts +11 -0
  79. package/dist/agents/orchestrator-sisyphus.d.ts.map +1 -0
  80. package/dist/agents/orchestrator-sisyphus.js +115 -0
  81. package/dist/agents/orchestrator-sisyphus.js.map +1 -0
  82. package/dist/agents/prometheus.d.ts +12 -0
  83. package/dist/agents/prometheus.d.ts.map +1 -0
  84. package/dist/agents/prometheus.js +195 -0
  85. package/dist/agents/prometheus.js.map +1 -0
  86. package/dist/agents/sisyphus-junior.d.ts +12 -0
  87. package/dist/agents/sisyphus-junior.d.ts.map +1 -0
  88. package/dist/agents/sisyphus-junior.js +93 -0
  89. package/dist/agents/sisyphus-junior.js.map +1 -0
  90. package/dist/cli/analytics.js +0 -0
  91. package/dist/cli/components/CostDashboard.d.ts +15 -0
  92. package/dist/cli/components/CostDashboard.d.ts.map +1 -0
  93. package/dist/cli/components/CostDashboard.js +15 -0
  94. package/dist/cli/components/CostDashboard.js.map +1 -0
  95. package/dist/cli/components/LiveStats.d.ts +16 -0
  96. package/dist/cli/components/LiveStats.d.ts.map +1 -0
  97. package/dist/cli/components/LiveStats.js +16 -0
  98. package/dist/cli/components/LiveStats.js.map +1 -0
  99. package/dist/cli/components/SessionBrowser.d.ts +14 -0
  100. package/dist/cli/components/SessionBrowser.d.ts.map +1 -0
  101. package/dist/cli/components/SessionBrowser.js +14 -0
  102. package/dist/cli/components/SessionBrowser.js.map +1 -0
  103. package/dist/cli/index.js +0 -0
  104. package/dist/cli/tui.d.ts +21 -0
  105. package/dist/cli/tui.d.ts.map +1 -0
  106. package/dist/cli/tui.js +21 -0
  107. package/dist/cli/tui.js.map +1 -0
  108. package/dist/hooks/autopilot/signals.d.ts +20 -0
  109. package/dist/hooks/autopilot/signals.d.ts.map +1 -0
  110. package/dist/hooks/autopilot/signals.js +75 -0
  111. package/dist/hooks/autopilot/signals.js.map +1 -0
  112. package/dist/hooks/autopilot/summary.d.ts +27 -0
  113. package/dist/hooks/autopilot/summary.d.ts.map +1 -0
  114. package/dist/hooks/autopilot/summary.js +160 -0
  115. package/dist/hooks/autopilot/summary.js.map +1 -0
  116. package/dist/hooks/autopilot/transition.d.ts +39 -0
  117. package/dist/hooks/autopilot/transition.d.ts.map +1 -0
  118. package/dist/hooks/autopilot/transition.js +216 -0
  119. package/dist/hooks/autopilot/transition.js.map +1 -0
  120. package/dist/hooks/context-window-limit-recovery/constants.d.ts +28 -0
  121. package/dist/hooks/context-window-limit-recovery/constants.d.ts.map +1 -0
  122. package/dist/hooks/context-window-limit-recovery/constants.js +85 -0
  123. package/dist/hooks/context-window-limit-recovery/constants.js.map +1 -0
  124. package/dist/hooks/context-window-limit-recovery/index.d.ts +62 -0
  125. package/dist/hooks/context-window-limit-recovery/index.d.ts.map +1 -0
  126. package/dist/hooks/context-window-limit-recovery/index.js +201 -0
  127. package/dist/hooks/context-window-limit-recovery/index.js.map +1 -0
  128. package/dist/hooks/context-window-limit-recovery/parser.d.ts +31 -0
  129. package/dist/hooks/context-window-limit-recovery/parser.d.ts.map +1 -0
  130. package/dist/hooks/context-window-limit-recovery/parser.js +241 -0
  131. package/dist/hooks/context-window-limit-recovery/parser.js.map +1 -0
  132. package/dist/hooks/context-window-limit-recovery/types.d.ts +84 -0
  133. package/dist/hooks/context-window-limit-recovery/types.d.ts.map +1 -0
  134. package/dist/hooks/context-window-limit-recovery/types.js +34 -0
  135. package/dist/hooks/context-window-limit-recovery/types.js.map +1 -0
  136. package/dist/hooks/edit-error-recovery/index.d.ts +62 -0
  137. package/dist/hooks/edit-error-recovery/index.d.ts.map +1 -0
  138. package/dist/hooks/edit-error-recovery/index.js +89 -0
  139. package/dist/hooks/edit-error-recovery/index.js.map +1 -0
  140. package/dist/hooks/learned-skills/config.d.ts +53 -0
  141. package/dist/hooks/learned-skills/config.d.ts.map +1 -0
  142. package/dist/hooks/learned-skills/config.js +103 -0
  143. package/dist/hooks/learned-skills/config.js.map +1 -0
  144. package/dist/hooks/learned-skills/constants.d.ts +24 -0
  145. package/dist/hooks/learned-skills/constants.d.ts.map +1 -0
  146. package/dist/hooks/learned-skills/constants.js +26 -0
  147. package/dist/hooks/learned-skills/constants.js.map +1 -0
  148. package/dist/hooks/learned-skills/detection-hook.d.ts +39 -0
  149. package/dist/hooks/learned-skills/detection-hook.d.ts.map +1 -0
  150. package/dist/hooks/learned-skills/detection-hook.js +83 -0
  151. package/dist/hooks/learned-skills/detection-hook.js.map +1 -0
  152. package/dist/hooks/learned-skills/detector.d.ts +30 -0
  153. package/dist/hooks/learned-skills/detector.d.ts.map +1 -0
  154. package/dist/hooks/learned-skills/detector.js +150 -0
  155. package/dist/hooks/learned-skills/detector.js.map +1 -0
  156. package/dist/hooks/learned-skills/finder.d.ts +21 -0
  157. package/dist/hooks/learned-skills/finder.d.ts.map +1 -0
  158. package/dist/hooks/learned-skills/finder.js +117 -0
  159. package/dist/hooks/learned-skills/finder.js.map +1 -0
  160. package/dist/hooks/learned-skills/index.d.ts +62 -0
  161. package/dist/hooks/learned-skills/index.d.ts.map +1 -0
  162. package/dist/hooks/learned-skills/index.js +137 -0
  163. package/dist/hooks/learned-skills/index.js.map +1 -0
  164. package/dist/hooks/learned-skills/loader.d.ts +20 -0
  165. package/dist/hooks/learned-skills/loader.d.ts.map +1 -0
  166. package/dist/hooks/learned-skills/loader.js +107 -0
  167. package/dist/hooks/learned-skills/loader.js.map +1 -0
  168. package/dist/hooks/learned-skills/parser.d.ts +21 -0
  169. package/dist/hooks/learned-skills/parser.d.ts.map +1 -0
  170. package/dist/hooks/learned-skills/parser.js +190 -0
  171. package/dist/hooks/learned-skills/parser.js.map +1 -0
  172. package/dist/hooks/learned-skills/promotion.d.ts +29 -0
  173. package/dist/hooks/learned-skills/promotion.d.ts.map +1 -0
  174. package/dist/hooks/learned-skills/promotion.js +87 -0
  175. package/dist/hooks/learned-skills/promotion.js.map +1 -0
  176. package/dist/hooks/learned-skills/types.d.ts +109 -0
  177. package/dist/hooks/learned-skills/types.d.ts.map +1 -0
  178. package/dist/hooks/learned-skills/types.js +8 -0
  179. package/dist/hooks/learned-skills/types.js.map +1 -0
  180. package/dist/hooks/learned-skills/validator.d.ts +15 -0
  181. package/dist/hooks/learned-skills/validator.d.ts.map +1 -0
  182. package/dist/hooks/learned-skills/validator.js +87 -0
  183. package/dist/hooks/learned-skills/validator.js.map +1 -0
  184. package/dist/hooks/learned-skills/writer.d.ts +27 -0
  185. package/dist/hooks/learned-skills/writer.d.ts.map +1 -0
  186. package/dist/hooks/learned-skills/writer.js +126 -0
  187. package/dist/hooks/learned-skills/writer.js.map +1 -0
  188. package/dist/hooks/mnemosyne/config.d.ts +53 -0
  189. package/dist/hooks/mnemosyne/config.d.ts.map +1 -0
  190. package/dist/hooks/mnemosyne/config.js +103 -0
  191. package/dist/hooks/mnemosyne/config.js.map +1 -0
  192. package/dist/hooks/mnemosyne/constants.d.ts +24 -0
  193. package/dist/hooks/mnemosyne/constants.d.ts.map +1 -0
  194. package/dist/hooks/mnemosyne/constants.js +26 -0
  195. package/dist/hooks/mnemosyne/constants.js.map +1 -0
  196. package/dist/hooks/mnemosyne/detection-hook.d.ts +39 -0
  197. package/dist/hooks/mnemosyne/detection-hook.d.ts.map +1 -0
  198. package/dist/hooks/mnemosyne/detection-hook.js +83 -0
  199. package/dist/hooks/mnemosyne/detection-hook.js.map +1 -0
  200. package/dist/hooks/mnemosyne/detector.d.ts +30 -0
  201. package/dist/hooks/mnemosyne/detector.d.ts.map +1 -0
  202. package/dist/hooks/mnemosyne/detector.js +150 -0
  203. package/dist/hooks/mnemosyne/detector.js.map +1 -0
  204. package/dist/hooks/mnemosyne/finder.d.ts +21 -0
  205. package/dist/hooks/mnemosyne/finder.d.ts.map +1 -0
  206. package/dist/hooks/mnemosyne/finder.js +117 -0
  207. package/dist/hooks/mnemosyne/finder.js.map +1 -0
  208. package/dist/hooks/mnemosyne/index.d.ts +62 -0
  209. package/dist/hooks/mnemosyne/index.d.ts.map +1 -0
  210. package/dist/hooks/mnemosyne/index.js +137 -0
  211. package/dist/hooks/mnemosyne/index.js.map +1 -0
  212. package/dist/hooks/mnemosyne/loader.d.ts +20 -0
  213. package/dist/hooks/mnemosyne/loader.d.ts.map +1 -0
  214. package/dist/hooks/mnemosyne/loader.js +113 -0
  215. package/dist/hooks/mnemosyne/loader.js.map +1 -0
  216. package/dist/hooks/mnemosyne/parser.d.ts +21 -0
  217. package/dist/hooks/mnemosyne/parser.d.ts.map +1 -0
  218. package/dist/hooks/mnemosyne/parser.js +190 -0
  219. package/dist/hooks/mnemosyne/parser.js.map +1 -0
  220. package/dist/hooks/mnemosyne/promotion.d.ts +29 -0
  221. package/dist/hooks/mnemosyne/promotion.d.ts.map +1 -0
  222. package/dist/hooks/mnemosyne/promotion.js +87 -0
  223. package/dist/hooks/mnemosyne/promotion.js.map +1 -0
  224. package/dist/hooks/mnemosyne/types.d.ts +109 -0
  225. package/dist/hooks/mnemosyne/types.d.ts.map +1 -0
  226. package/dist/hooks/mnemosyne/types.js +8 -0
  227. package/dist/hooks/mnemosyne/types.js.map +1 -0
  228. package/dist/hooks/mnemosyne/validator.d.ts +15 -0
  229. package/dist/hooks/mnemosyne/validator.d.ts.map +1 -0
  230. package/dist/hooks/mnemosyne/validator.js +87 -0
  231. package/dist/hooks/mnemosyne/validator.js.map +1 -0
  232. package/dist/hooks/mnemosyne/writer.d.ts +27 -0
  233. package/dist/hooks/mnemosyne/writer.d.ts.map +1 -0
  234. package/dist/hooks/mnemosyne/writer.js +126 -0
  235. package/dist/hooks/mnemosyne/writer.js.map +1 -0
  236. package/dist/hooks/ralph-loop/index.d.ts +116 -0
  237. package/dist/hooks/ralph-loop/index.d.ts.map +1 -0
  238. package/dist/hooks/ralph-loop/index.js +322 -0
  239. package/dist/hooks/ralph-loop/index.js.map +1 -0
  240. package/dist/hooks/ralph-prd/index.d.ts +130 -0
  241. package/dist/hooks/ralph-prd/index.d.ts.map +1 -0
  242. package/dist/hooks/ralph-prd/index.js +310 -0
  243. package/dist/hooks/ralph-prd/index.js.map +1 -0
  244. package/dist/hooks/ralph-progress/index.d.ts +102 -0
  245. package/dist/hooks/ralph-progress/index.d.ts.map +1 -0
  246. package/dist/hooks/ralph-progress/index.js +408 -0
  247. package/dist/hooks/ralph-progress/index.js.map +1 -0
  248. package/dist/hooks/ralph-verifier/index.d.ts +72 -0
  249. package/dist/hooks/ralph-verifier/index.d.ts.map +1 -0
  250. package/dist/hooks/ralph-verifier/index.js +223 -0
  251. package/dist/hooks/ralph-verifier/index.js.map +1 -0
  252. package/dist/hooks/session-recovery/constants.d.ts +56 -0
  253. package/dist/hooks/session-recovery/constants.d.ts.map +1 -0
  254. package/dist/hooks/session-recovery/constants.js +78 -0
  255. package/dist/hooks/session-recovery/constants.js.map +1 -0
  256. package/dist/hooks/session-recovery/index.d.ts +53 -0
  257. package/dist/hooks/session-recovery/index.d.ts.map +1 -0
  258. package/dist/hooks/session-recovery/index.js +321 -0
  259. package/dist/hooks/session-recovery/index.js.map +1 -0
  260. package/dist/hooks/session-recovery/storage.d.ts +76 -0
  261. package/dist/hooks/session-recovery/storage.d.ts.map +1 -0
  262. package/dist/hooks/session-recovery/storage.js +383 -0
  263. package/dist/hooks/session-recovery/storage.js.map +1 -0
  264. package/dist/hooks/session-recovery/types.d.ts +145 -0
  265. package/dist/hooks/session-recovery/types.d.ts.map +1 -0
  266. package/dist/hooks/session-recovery/types.js +8 -0
  267. package/dist/hooks/session-recovery/types.js.map +1 -0
  268. package/dist/hooks/sisyphus-orchestrator/constants.d.ts +23 -0
  269. package/dist/hooks/sisyphus-orchestrator/constants.d.ts.map +1 -0
  270. package/dist/hooks/sisyphus-orchestrator/constants.js +142 -0
  271. package/dist/hooks/sisyphus-orchestrator/constants.js.map +1 -0
  272. package/dist/hooks/sisyphus-orchestrator/index.d.ts +113 -0
  273. package/dist/hooks/sisyphus-orchestrator/index.d.ts.map +1 -0
  274. package/dist/hooks/sisyphus-orchestrator/index.js +309 -0
  275. package/dist/hooks/sisyphus-orchestrator/index.js.map +1 -0
  276. package/dist/hooks/subagent-tracker/index.d.ts +83 -0
  277. package/dist/hooks/subagent-tracker/index.d.ts.map +1 -0
  278. package/dist/hooks/subagent-tracker/index.js +207 -0
  279. package/dist/hooks/subagent-tracker/index.js.map +1 -0
  280. package/dist/hooks/ultraqa-loop/index.d.ts +94 -0
  281. package/dist/hooks/ultraqa-loop/index.d.ts.map +1 -0
  282. package/dist/hooks/ultraqa-loop/index.js +216 -0
  283. package/dist/hooks/ultraqa-loop/index.js.map +1 -0
  284. package/dist/hooks/ultrawork-state/index.d.ts +62 -0
  285. package/dist/hooks/ultrawork-state/index.d.ts.map +1 -0
  286. package/dist/hooks/ultrawork-state/index.js +208 -0
  287. package/dist/hooks/ultrawork-state/index.js.map +1 -0
  288. package/dist/hud/sisyphus-state.d.ts +31 -0
  289. package/dist/hud/sisyphus-state.d.ts.map +1 -0
  290. package/dist/hud/sisyphus-state.js +163 -0
  291. package/dist/hud/sisyphus-state.js.map +1 -0
  292. package/dist/installer/index.d.ts +1 -1
  293. package/dist/installer/index.js +1 -1
  294. package/docs/MIGRATION.md +2 -2
  295. package/docs/design/project-session-manager.md +1033 -0
  296. package/package.json +1 -1
  297. package/skills/doctor/SKILL.md +1 -1
  298. package/skills/project-session-manager/SKILL.md +410 -0
  299. package/skills/project-session-manager/lib/config.sh +86 -0
  300. package/skills/project-session-manager/lib/parse.sh +121 -0
  301. package/skills/project-session-manager/lib/session.sh +132 -0
  302. package/skills/project-session-manager/lib/tmux.sh +103 -0
  303. package/skills/project-session-manager/lib/worktree.sh +171 -0
  304. package/skills/project-session-manager/psm.sh +629 -0
  305. package/skills/project-session-manager/templates/feature.md +56 -0
  306. package/skills/project-session-manager/templates/issue-fix.md +57 -0
  307. package/skills/project-session-manager/templates/pr-review.md +65 -0
  308. package/skills/project-session-manager/templates/projects.json +19 -0
@@ -0,0 +1,629 @@
1
+ #!/bin/bash
2
+ # Project Session Manager (PSM) - Main Script
3
+ # Usage: psm.sh <command> [args...]
4
+
5
+ set -euo pipefail
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+
9
+ # Source library files
10
+ source "$SCRIPT_DIR/lib/config.sh"
11
+ source "$SCRIPT_DIR/lib/parse.sh"
12
+ source "$SCRIPT_DIR/lib/worktree.sh"
13
+ source "$SCRIPT_DIR/lib/tmux.sh"
14
+ source "$SCRIPT_DIR/lib/session.sh"
15
+
16
+ # Colors for output
17
+ RED='\033[0;31m'
18
+ GREEN='\033[0;32m'
19
+ YELLOW='\033[1;33m'
20
+ BLUE='\033[0;34m'
21
+ NC='\033[0m' # No Color
22
+
23
+ # Logging
24
+ log_info() { echo -e "${BLUE}[PSM]${NC} $*"; }
25
+ log_success() { echo -e "${GREEN}[PSM]${NC} $*"; }
26
+ log_warn() { echo -e "${YELLOW}[PSM]${NC} $*"; }
27
+ log_error() { echo -e "${RED}[PSM]${NC} $*" >&2; }
28
+
29
+ # Check dependencies
30
+ check_dependencies() {
31
+ local missing=()
32
+
33
+ if ! command -v git &> /dev/null; then
34
+ missing+=("git")
35
+ fi
36
+
37
+ if ! command -v jq &> /dev/null; then
38
+ missing+=("jq")
39
+ fi
40
+
41
+ if ! command -v gh &> /dev/null; then
42
+ missing+=("gh (GitHub CLI)")
43
+ fi
44
+
45
+ if [[ ${#missing[@]} -gt 0 ]]; then
46
+ log_error "Missing required dependencies: ${missing[*]}"
47
+ log_info "Install with:"
48
+ log_info " Ubuntu/Debian: sudo apt install git jq gh"
49
+ log_info " macOS: brew install git jq gh"
50
+ exit 1
51
+ fi
52
+
53
+ # tmux is optional but warn if missing
54
+ if ! command -v tmux &> /dev/null; then
55
+ log_warn "tmux not found. Sessions will be created without tmux."
56
+ fi
57
+ }
58
+
59
+ # Print usage
60
+ usage() {
61
+ cat << 'EOF'
62
+ Project Session Manager (PSM) - Isolated dev environments
63
+
64
+ Usage: psm <command> [args...]
65
+
66
+ Commands:
67
+ review <ref> Create PR review session
68
+ fix <ref> Create issue fix session
69
+ feature <proj> <name> Create feature development session
70
+ list [project] List active sessions
71
+ attach <session> Attach to existing session
72
+ kill <session> Kill and cleanup session
73
+ cleanup [--force] Clean merged PRs and closed issues
74
+ status Show current session info
75
+
76
+ Reference formats:
77
+ omc#123 Project alias + number
78
+ owner/repo#123 Full GitHub reference
79
+ https://... GitHub URL
80
+ #123 Number only (uses current repo)
81
+
82
+ Examples:
83
+ psm review omc#123
84
+ psm fix Yeachan-Heo/oh-my-claudecode#42
85
+ psm feature omc add-webhooks
86
+ psm list
87
+ psm attach omc:pr-123
88
+ psm kill omc:pr-123
89
+ psm cleanup
90
+ EOF
91
+ }
92
+
93
+ # Command: review
94
+ cmd_review() {
95
+ local ref="$1"
96
+ local no_claude="${2:-false}"
97
+ local no_tmux="${3:-false}"
98
+
99
+ log_info "Parsing reference: $ref"
100
+
101
+ # Parse reference
102
+ local parsed
103
+ parsed=$(psm_parse_ref "$ref")
104
+ if [[ $? -ne 0 ]] || [[ "$parsed" == error* ]]; then
105
+ log_error "Failed to parse reference: $ref"
106
+ return 1
107
+ fi
108
+
109
+ IFS='|' read -r type alias repo pr_number local_path base <<< "$parsed"
110
+
111
+ if [[ -z "$repo" ]]; then
112
+ log_error "Could not determine repository"
113
+ return 1
114
+ fi
115
+
116
+ log_info "Fetching PR #${pr_number} from ${repo}..."
117
+
118
+ # Fetch PR info
119
+ local pr_info
120
+ pr_info=$(gh pr view "$pr_number" --repo "$repo" --json number,title,author,headRefName,baseRefName,body,url 2>/dev/null) || {
121
+ log_error "Failed to fetch PR #${pr_number}. Check if the PR exists and you have access."
122
+ return 1
123
+ }
124
+
125
+ local pr_title=$(echo "$pr_info" | jq -r '.title')
126
+ local pr_author=$(echo "$pr_info" | jq -r '.author.login')
127
+ local head_branch=$(echo "$pr_info" | jq -r '.headRefName')
128
+ local base_branch=$(echo "$pr_info" | jq -r '.baseRefName')
129
+ local pr_url=$(echo "$pr_info" | jq -r '.url')
130
+
131
+ log_info "PR: #${pr_number} - ${pr_title}"
132
+ log_info "Author: @${pr_author}"
133
+ log_info "Branch: ${head_branch} -> ${base_branch}"
134
+
135
+ # Determine alias if not set
136
+ if [[ -z "$alias" ]]; then
137
+ alias=$(echo "$repo" | tr '/' '-')
138
+ fi
139
+
140
+ # Determine local path
141
+ if [[ -z "$local_path" || ! -d "$local_path" ]]; then
142
+ # Clone if needed
143
+ local_path="${HOME}/Workspace/$(basename "$repo")"
144
+ if [[ ! -d "$local_path" ]]; then
145
+ log_info "Cloning repository to $local_path..."
146
+ git clone "https://github.com/${repo}.git" "$local_path" || {
147
+ log_error "Failed to clone repository"
148
+ return 1
149
+ }
150
+ fi
151
+ fi
152
+
153
+ # Create worktree
154
+ log_info "Creating worktree..."
155
+ local worktree_result
156
+ worktree_result=$(psm_create_pr_worktree "$local_path" "$alias" "$pr_number" "$head_branch")
157
+
158
+ local worktree_status
159
+ local worktree_path
160
+ IFS='|' read -r worktree_status worktree_path <<< "$worktree_result"
161
+
162
+ if [[ "$worktree_status" == "exists" ]]; then
163
+ log_warn "Worktree already exists at $worktree_path"
164
+ log_info "Use 'psm attach ${alias}:pr-${pr_number}' to attach"
165
+ return 0
166
+ elif [[ "$worktree_status" == "error" ]]; then
167
+ log_error "Failed to create worktree: $worktree_path"
168
+ return 1
169
+ fi
170
+
171
+ log_success "Worktree created at $worktree_path"
172
+
173
+ # Create tmux session
174
+ local session_name="psm:${alias}:pr-${pr_number}"
175
+ local session_id="${alias}:pr-${pr_number}"
176
+
177
+ if [[ "$no_tmux" != "true" ]]; then
178
+ log_info "Creating tmux session..."
179
+ local tmux_result
180
+ tmux_result=$(psm_create_tmux_session "$session_name" "$worktree_path")
181
+
182
+ local tmux_status
183
+ IFS='|' read -r tmux_status _ <<< "$tmux_result"
184
+
185
+ if [[ "$tmux_status" == "error" ]]; then
186
+ log_warn "Could not create tmux session. Continuing without tmux."
187
+ elif [[ "$tmux_status" == "exists" ]]; then
188
+ log_warn "Tmux session already exists"
189
+ else
190
+ log_success "Tmux session created: $session_name"
191
+
192
+ # Launch Claude Code
193
+ if [[ "$no_claude" != "true" ]]; then
194
+ log_info "Launching Claude Code..."
195
+ psm_launch_claude "$session_name"
196
+ fi
197
+ fi
198
+ fi
199
+
200
+ # Create session metadata
201
+ local metadata=$(cat << EOF
202
+ {
203
+ "pr_number": $pr_number,
204
+ "pr_title": $(echo "$pr_title" | jq -R .),
205
+ "pr_author": "$pr_author",
206
+ "pr_url": "$pr_url"
207
+ }
208
+ EOF
209
+ )
210
+
211
+ # Add to registry
212
+ psm_add_session "$session_id" "review" "$alias" "pr-${pr_number}" "$head_branch" "$base_branch" "$session_name" "$worktree_path" "$local_path" "$metadata"
213
+
214
+ # Output summary
215
+ echo ""
216
+ log_success "Session ready!"
217
+ echo ""
218
+ echo " ID: $session_id"
219
+ echo " Type: review"
220
+ echo " PR: #${pr_number} - ${pr_title}"
221
+ echo " Worktree: $worktree_path"
222
+ echo " Tmux: $session_name"
223
+ echo ""
224
+ echo "Commands:"
225
+ echo " Attach: tmux attach -t $session_name"
226
+ echo " Kill: psm kill $session_id"
227
+ echo " Cleanup: psm cleanup"
228
+ echo ""
229
+ }
230
+
231
+ # Command: fix
232
+ cmd_fix() {
233
+ local ref="$1"
234
+ local no_claude="${2:-false}"
235
+
236
+ log_info "Parsing reference: $ref"
237
+
238
+ local parsed
239
+ parsed=$(psm_parse_ref "$ref")
240
+ if [[ $? -ne 0 ]] || [[ "$parsed" == error* ]]; then
241
+ log_error "Failed to parse reference: $ref"
242
+ return 1
243
+ fi
244
+
245
+ IFS='|' read -r type alias repo issue_number local_path base <<< "$parsed"
246
+
247
+ if [[ -z "$repo" ]]; then
248
+ log_error "Could not determine repository"
249
+ return 1
250
+ fi
251
+
252
+ log_info "Fetching issue #${issue_number} from ${repo}..."
253
+
254
+ # Fetch issue info
255
+ local issue_info
256
+ issue_info=$(gh issue view "$issue_number" --repo "$repo" --json number,title,body,labels,url 2>/dev/null) || {
257
+ log_error "Failed to fetch issue #${issue_number}"
258
+ return 1
259
+ }
260
+
261
+ local issue_title=$(echo "$issue_info" | jq -r '.title')
262
+ local issue_url=$(echo "$issue_info" | jq -r '.url')
263
+ local slug=$(psm_slugify "$issue_title" 20)
264
+
265
+ log_info "Issue: #${issue_number} - ${issue_title}"
266
+
267
+ # Determine alias
268
+ if [[ -z "$alias" ]]; then
269
+ alias=$(echo "$repo" | tr '/' '-')
270
+ fi
271
+
272
+ # Determine local path
273
+ if [[ -z "$local_path" || ! -d "$local_path" ]]; then
274
+ local_path="${HOME}/Workspace/$(basename "$repo")"
275
+ if [[ ! -d "$local_path" ]]; then
276
+ log_info "Cloning repository..."
277
+ git clone "https://github.com/${repo}.git" "$local_path" || return 1
278
+ fi
279
+ fi
280
+
281
+ # Create worktree
282
+ log_info "Creating worktree and branch..."
283
+ local worktree_result
284
+ worktree_result=$(psm_create_issue_worktree "$local_path" "$alias" "$issue_number" "$slug" "$base")
285
+
286
+ local worktree_status worktree_path branch_name
287
+ IFS='|' read -r worktree_status worktree_path branch_name <<< "$worktree_result"
288
+
289
+ if [[ "$worktree_status" == "exists" ]]; then
290
+ log_warn "Worktree already exists at $worktree_path"
291
+ return 0
292
+ elif [[ "$worktree_status" == "error" ]]; then
293
+ log_error "Failed to create worktree: $worktree_path"
294
+ return 1
295
+ fi
296
+
297
+ log_success "Worktree created at $worktree_path"
298
+ log_info "Branch: $branch_name"
299
+
300
+ # Create tmux session
301
+ local session_name="psm:${alias}:issue-${issue_number}"
302
+ local session_id="${alias}:issue-${issue_number}"
303
+
304
+ log_info "Creating tmux session..."
305
+ psm_create_tmux_session "$session_name" "$worktree_path"
306
+
307
+ if [[ "$no_claude" != "true" ]]; then
308
+ psm_launch_claude "$session_name"
309
+ fi
310
+
311
+ # Create metadata
312
+ local metadata=$(cat << EOF
313
+ {
314
+ "issue_number": $issue_number,
315
+ "issue_title": $(echo "$issue_title" | jq -R .),
316
+ "issue_url": "$issue_url"
317
+ }
318
+ EOF
319
+ )
320
+
321
+ psm_add_session "$session_id" "fix" "$alias" "issue-${issue_number}" "$branch_name" "$base" "$session_name" "$worktree_path" "$local_path" "$metadata"
322
+
323
+ echo ""
324
+ log_success "Session ready!"
325
+ echo ""
326
+ echo " ID: $session_id"
327
+ echo " Type: fix"
328
+ echo " Issue: #${issue_number} - ${issue_title}"
329
+ echo " Branch: $branch_name"
330
+ echo " Worktree: $worktree_path"
331
+ echo " Tmux: $session_name"
332
+ echo ""
333
+ }
334
+
335
+ # Command: feature
336
+ cmd_feature() {
337
+ local project="$1"
338
+ local feature_name="$2"
339
+
340
+ log_info "Creating feature session for: $feature_name"
341
+
342
+ # Resolve project
343
+ local project_info
344
+ project_info=$(psm_get_project "$project")
345
+ if [[ $? -ne 0 ]]; then
346
+ log_error "Unknown project: $project"
347
+ return 1
348
+ fi
349
+
350
+ IFS='|' read -r repo local_path base <<< "$project_info"
351
+
352
+ if [[ ! -d "$local_path" ]]; then
353
+ log_error "Local path not found: $local_path"
354
+ return 1
355
+ fi
356
+
357
+ # Create worktree
358
+ log_info "Creating worktree and branch..."
359
+ local worktree_result
360
+ worktree_result=$(psm_create_feature_worktree "$local_path" "$project" "$feature_name" "$base")
361
+
362
+ local worktree_status worktree_path branch_name
363
+ IFS='|' read -r worktree_status worktree_path branch_name <<< "$worktree_result"
364
+
365
+ if [[ "$worktree_status" == "exists" ]]; then
366
+ log_warn "Worktree already exists at $worktree_path"
367
+ return 0
368
+ elif [[ "$worktree_status" == "error" ]]; then
369
+ log_error "Failed to create worktree"
370
+ return 1
371
+ fi
372
+
373
+ log_success "Worktree created at $worktree_path"
374
+
375
+ local safe_name=$(psm_sanitize "$feature_name")
376
+ local session_name="psm:${project}:feat-${safe_name}"
377
+ local session_id="${project}:feat-${safe_name}"
378
+
379
+ psm_create_tmux_session "$session_name" "$worktree_path"
380
+ psm_launch_claude "$session_name"
381
+
382
+ psm_add_session "$session_id" "feature" "$project" "feat-${safe_name}" "$branch_name" "$base" "$session_name" "$worktree_path" "$local_path" "{}"
383
+
384
+ echo ""
385
+ log_success "Session ready!"
386
+ echo ""
387
+ echo " ID: $session_id"
388
+ echo " Type: feature"
389
+ echo " Branch: $branch_name"
390
+ echo " Worktree: $worktree_path"
391
+ echo " Tmux: $session_name"
392
+ echo ""
393
+ }
394
+
395
+ # Command: list
396
+ cmd_list() {
397
+ local project="${1:-}"
398
+
399
+ echo ""
400
+ echo "Active PSM Sessions:"
401
+ echo ""
402
+ printf "%-25s | %-8s | %-10s | %s\n" "ID" "Type" "State" "Worktree"
403
+ printf "%-25s-+-%-8s-+-%-10s-+-%s\n" "-------------------------" "--------" "----------" "----------------------------------------"
404
+
405
+ psm_list_sessions "$project" | while IFS='|' read -r id type state worktree; do
406
+ # Check if tmux session exists
407
+ local tmux_state="detached"
408
+ if psm_tmux_session_exists "psm:${id}"; then
409
+ tmux_state="$state"
410
+ else
411
+ tmux_state="no-tmux"
412
+ fi
413
+
414
+ printf "%-25s | %-8s | %-10s | %s\n" "$id" "$type" "$tmux_state" "$worktree"
415
+ done
416
+
417
+ echo ""
418
+ }
419
+
420
+ # Command: attach
421
+ cmd_attach() {
422
+ local session_id="$1"
423
+ local session_name="psm:${session_id}"
424
+
425
+ if ! psm_tmux_session_exists "$session_name"; then
426
+ log_error "Session not found: $session_name"
427
+ log_info "Use 'psm list' to see available sessions"
428
+ return 1
429
+ fi
430
+
431
+ echo "Attaching to $session_name..."
432
+ echo "Run: tmux attach -t $session_name"
433
+ }
434
+
435
+ # Command: kill
436
+ cmd_kill() {
437
+ local session_id="$1"
438
+
439
+ log_info "Killing session: $session_id"
440
+
441
+ # Get session info
442
+ local session_json
443
+ session_json=$(psm_get_session "$session_id")
444
+ if [[ -z "$session_json" ]]; then
445
+ log_error "Session not found in registry: $session_id"
446
+ return 1
447
+ fi
448
+
449
+ local tmux_name=$(echo "$session_json" | jq -r '.tmux')
450
+ local worktree_path=$(echo "$session_json" | jq -r '.worktree')
451
+ local source_repo=$(echo "$session_json" | jq -r '.source_repo')
452
+
453
+ # Kill tmux
454
+ psm_kill_tmux_session "$tmux_name"
455
+ log_info "Killed tmux session: $tmux_name"
456
+
457
+ # Remove worktree
458
+ psm_remove_worktree "$source_repo" "$worktree_path"
459
+ log_info "Removed worktree: $worktree_path"
460
+
461
+ # Remove from registry
462
+ psm_remove_session "$session_id"
463
+ log_info "Removed from registry"
464
+
465
+ log_success "Session killed: $session_id"
466
+ }
467
+
468
+ # Command: cleanup
469
+ cmd_cleanup() {
470
+ local force="${1:-false}"
471
+
472
+ log_info "Starting cleanup..."
473
+
474
+ local cleaned=0
475
+
476
+ # Check PR sessions (use process substitution to avoid subshell)
477
+ while IFS='|' read -r id pr_number project; do
478
+ if [[ -z "$id" ]]; then continue; fi
479
+
480
+ local repo=$(psm_get_project "$project" | cut -d'|' -f1)
481
+
482
+ if [[ -n "$repo" && -n "$pr_number" ]]; then
483
+ local pr_state=$(gh pr view "$pr_number" --repo "$repo" --json merged 2>/dev/null | jq -r '.merged')
484
+ if [[ "$pr_state" == "true" ]]; then
485
+ log_info "PR #${pr_number} is merged - cleaning up $id"
486
+ cmd_kill "$id"
487
+ ((cleaned++))
488
+ fi
489
+ fi
490
+ done < <(psm_get_review_sessions)
491
+
492
+ # Check issue sessions (use process substitution to avoid subshell)
493
+ while IFS='|' read -r id issue_number project; do
494
+ if [[ -z "$id" ]]; then continue; fi
495
+
496
+ local repo=$(psm_get_project "$project" | cut -d'|' -f1)
497
+
498
+ if [[ -n "$repo" && -n "$issue_number" ]]; then
499
+ local issue_state=$(gh issue view "$issue_number" --repo "$repo" --json closed 2>/dev/null | jq -r '.closed')
500
+ if [[ "$issue_state" == "true" ]]; then
501
+ log_info "Issue #${issue_number} is closed - cleaning up $id"
502
+ cmd_kill "$id"
503
+ ((cleaned++))
504
+ fi
505
+ fi
506
+ done < <(psm_get_fix_sessions)
507
+
508
+ if [[ $cleaned -eq 0 ]]; then
509
+ log_success "Cleanup complete - no sessions to clean"
510
+ else
511
+ log_success "Cleanup complete - removed $cleaned session(s)"
512
+ fi
513
+ }
514
+
515
+ # Command: status
516
+ cmd_status() {
517
+ # Try to detect current session
518
+ local current_session=$(psm_current_tmux_session)
519
+
520
+ if [[ -n "$current_session" && "$current_session" == psm:* ]]; then
521
+ local session_id="${current_session#psm:}"
522
+ local session_json=$(psm_get_session "$session_id")
523
+
524
+ if [[ -n "$session_json" ]]; then
525
+ echo ""
526
+ echo "Current Session: $session_id"
527
+ echo ""
528
+ echo " Type: $(echo "$session_json" | jq -r '.type')"
529
+ echo " Branch: $(echo "$session_json" | jq -r '.branch')"
530
+ echo " Base: $(echo "$session_json" | jq -r '.base')"
531
+ echo " Worktree: $(echo "$session_json" | jq -r '.worktree')"
532
+ echo " Created: $(echo "$session_json" | jq -r '.created_at')"
533
+ echo ""
534
+ return 0
535
+ fi
536
+ fi
537
+
538
+ # Check if we're in a worktree
539
+ local cwd=$(pwd)
540
+ local worktree_root=$(psm_get_worktree_root)
541
+
542
+ if [[ "$cwd" == "$worktree_root"* ]]; then
543
+ local meta_file="${cwd}/.psm-session.json"
544
+ if [[ -f "$meta_file" ]]; then
545
+ cat "$meta_file" | jq .
546
+ return 0
547
+ fi
548
+ fi
549
+
550
+ log_info "Not in a PSM session"
551
+ log_info "Use 'psm list' to see available sessions"
552
+ }
553
+
554
+ # Main entry point
555
+ main() {
556
+ if [[ $# -eq 0 ]]; then
557
+ usage
558
+ exit 0
559
+ fi
560
+
561
+ # Check dependencies first
562
+ check_dependencies
563
+
564
+ # Initialize PSM
565
+ psm_init
566
+
567
+ local cmd="$1"
568
+ shift
569
+
570
+ case "$cmd" in
571
+ review|r|pr)
572
+ if [[ $# -lt 1 ]]; then
573
+ log_error "Usage: psm review <ref>"
574
+ exit 1
575
+ fi
576
+ cmd_review "$@"
577
+ ;;
578
+ fix|issue|i)
579
+ if [[ $# -lt 1 ]]; then
580
+ log_error "Usage: psm fix <ref>"
581
+ exit 1
582
+ fi
583
+ cmd_fix "$@"
584
+ ;;
585
+ feature|feat|f)
586
+ if [[ $# -lt 2 ]]; then
587
+ log_error "Usage: psm feature <project> <name>"
588
+ exit 1
589
+ fi
590
+ cmd_feature "$@"
591
+ ;;
592
+ list|ls|l)
593
+ cmd_list "$@"
594
+ ;;
595
+ attach|a)
596
+ if [[ $# -lt 1 ]]; then
597
+ log_error "Usage: psm attach <session>"
598
+ exit 1
599
+ fi
600
+ cmd_attach "$@"
601
+ ;;
602
+ kill|k|rm)
603
+ if [[ $# -lt 1 ]]; then
604
+ log_error "Usage: psm kill <session>"
605
+ exit 1
606
+ fi
607
+ cmd_kill "$@"
608
+ ;;
609
+ cleanup|gc|clean)
610
+ cmd_cleanup "$@"
611
+ ;;
612
+ status|st)
613
+ cmd_status
614
+ ;;
615
+ help|-h|--help)
616
+ usage
617
+ ;;
618
+ *)
619
+ log_error "Unknown command: $cmd"
620
+ usage
621
+ exit 1
622
+ ;;
623
+ esac
624
+ }
625
+
626
+ # Run if executed directly
627
+ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
628
+ main "$@"
629
+ fi
@@ -0,0 +1,56 @@
1
+ # Feature Development Context
2
+
3
+ You are developing feature: **{{FEATURE_NAME}}**
4
+
5
+ ## Details
6
+
7
+ - **Branch**: `{{BRANCH_NAME}}`
8
+ - **Base**: `{{BASE_BRANCH}}`
9
+ - **Project**: {{PROJECT}}
10
+
11
+ ## Feature Scope
12
+
13
+ {{FEATURE_DESCRIPTION}}
14
+
15
+ ## Development Approach
16
+
17
+ 1. **Plan**
18
+ - Define requirements
19
+ - Break into subtasks
20
+ - Identify dependencies
21
+
22
+ 2. **Implement**
23
+ - Follow project patterns
24
+ - Write clean, testable code
25
+ - Commit incrementally
26
+
27
+ 3. **Test**
28
+ - Unit tests for new code
29
+ - Integration tests if needed
30
+ - Manual testing
31
+
32
+ 4. **Document**
33
+ - Update relevant docs
34
+ - Add code comments where needed
35
+ - Update CHANGELOG if applicable
36
+
37
+ ## Commands
38
+
39
+ ```bash
40
+ # Run tests
41
+ npm test # or appropriate test command
42
+
43
+ # Check build
44
+ npm run build # or appropriate build command
45
+
46
+ # Create PR when ready
47
+ gh pr create --title "Feature: {{FEATURE_NAME}}" --body "## Summary\n\n<description>\n\n## Changes\n\n- <change 1>\n- <change 2>"
48
+ ```
49
+
50
+ ## Feature Checklist
51
+
52
+ - [ ] Requirements understood
53
+ - [ ] Implementation complete
54
+ - [ ] Tests written and passing
55
+ - [ ] Documentation updated
56
+ - [ ] Ready for PR