oh-my-copilot 4.13.0 → 4.13.2

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 (420) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/README.md +2 -2
  4. package/agents/analyst.agent.md +2 -1
  5. package/agents/architect.agent.md +2 -1
  6. package/agents/code-reviewer.agent.md +2 -1
  7. package/agents/critic.agent.md +2 -1
  8. package/agents/debugger.agent.md +2 -1
  9. package/agents/designer.agent.md +2 -1
  10. package/agents/devils-advocate.agent.md +2 -1
  11. package/agents/document-specialist.agent.md +2 -1
  12. package/agents/executor.agent.md +2 -1
  13. package/agents/explore.agent.md +2 -1
  14. package/agents/git-master.agent.md +2 -1
  15. package/agents/planner.agent.md +2 -1
  16. package/agents/qa-tester.agent.md +2 -1
  17. package/agents/scientist.agent.md +2 -1
  18. package/agents/security-reviewer.agent.md +2 -1
  19. package/agents/test-engineer.agent.md +2 -1
  20. package/agents/verifier.agent.md +2 -1
  21. package/agents/writer.agent.md +2 -1
  22. package/bridge/cli.cjs +2823 -1491
  23. package/bridge/mcp-server.cjs +15 -2
  24. package/bridge/run-mcp-server.sh +1 -1
  25. package/bridge/runtime-cli.cjs +3589 -2448
  26. package/bridge/team-bridge.cjs +6 -4
  27. package/bridge/team-mcp.cjs +19607 -0
  28. package/bridge/team.js +3576 -2080
  29. package/dist/__tests__/auto-slash-aliases.test.js +5 -5
  30. package/dist/__tests__/auto-slash-aliases.test.js.map +1 -1
  31. package/dist/__tests__/bedrock-lm-suffix-hook.test.js +2 -2
  32. package/dist/__tests__/bedrock-lm-suffix-hook.test.js.map +1 -1
  33. package/dist/__tests__/cleanup-orphans-unref.test.d.ts +2 -0
  34. package/dist/__tests__/cleanup-orphans-unref.test.d.ts.map +1 -0
  35. package/dist/__tests__/cleanup-orphans-unref.test.js +44 -0
  36. package/dist/__tests__/cleanup-orphans-unref.test.js.map +1 -0
  37. package/dist/__tests__/context-safety.test.js +3 -3
  38. package/dist/__tests__/context-safety.test.js.map +1 -1
  39. package/dist/__tests__/hooks/learner/bridge.test.js +106 -0
  40. package/dist/__tests__/hooks/learner/bridge.test.js.map +1 -1
  41. package/dist/__tests__/hooks/learner/parser.test.js +30 -0
  42. package/dist/__tests__/hooks/learner/parser.test.js.map +1 -1
  43. package/dist/__tests__/hooks.test.js +47 -0
  44. package/dist/__tests__/hooks.test.js.map +1 -1
  45. package/dist/__tests__/hud/extra-usage.test.js +42 -0
  46. package/dist/__tests__/hud/extra-usage.test.js.map +1 -1
  47. package/dist/__tests__/hud/render-enterprise.test.d.ts +5 -0
  48. package/dist/__tests__/hud/render-enterprise.test.d.ts.map +1 -0
  49. package/dist/__tests__/hud/render-enterprise.test.js +232 -0
  50. package/dist/__tests__/hud/render-enterprise.test.js.map +1 -0
  51. package/dist/__tests__/hud/render-rate-limits-priority.test.js +159 -0
  52. package/dist/__tests__/hud/render-rate-limits-priority.test.js.map +1 -1
  53. package/dist/__tests__/hud/stdin-session-scope.test.d.ts +2 -0
  54. package/dist/__tests__/hud/stdin-session-scope.test.d.ts.map +1 -0
  55. package/dist/__tests__/hud/stdin-session-scope.test.js +169 -0
  56. package/dist/__tests__/hud/stdin-session-scope.test.js.map +1 -0
  57. package/dist/__tests__/hud/usage-api.test.js +111 -1
  58. package/dist/__tests__/hud/usage-api.test.js.map +1 -1
  59. package/dist/__tests__/issue-2652-runtime-wiring-and-output-contract.test.js +2 -0
  60. package/dist/__tests__/issue-2652-runtime-wiring-and-output-contract.test.js.map +1 -1
  61. package/dist/__tests__/keyword-detector-echo-guard.test.d.ts +2 -0
  62. package/dist/__tests__/keyword-detector-echo-guard.test.d.ts.map +1 -0
  63. package/dist/__tests__/keyword-detector-echo-guard.test.js +218 -0
  64. package/dist/__tests__/keyword-detector-echo-guard.test.js.map +1 -0
  65. package/dist/__tests__/keyword-detector-script.test.js +2 -1
  66. package/dist/__tests__/keyword-detector-script.test.js.map +1 -1
  67. package/dist/__tests__/omc-cli-rendering.test.js +13 -10
  68. package/dist/__tests__/omc-cli-rendering.test.js.map +1 -1
  69. package/dist/__tests__/pre-tool-enforcer.test.js +22 -38
  70. package/dist/__tests__/pre-tool-enforcer.test.js.map +1 -1
  71. package/dist/__tests__/preemptive-compaction-hook.test.js +63 -0
  72. package/dist/__tests__/preemptive-compaction-hook.test.js.map +1 -1
  73. package/dist/__tests__/safe-command-approver.test.d.ts +2 -0
  74. package/dist/__tests__/safe-command-approver.test.d.ts.map +1 -0
  75. package/dist/__tests__/safe-command-approver.test.js +103 -0
  76. package/dist/__tests__/safe-command-approver.test.js.map +1 -0
  77. package/dist/__tests__/skills.test.js +18 -0
  78. package/dist/__tests__/skills.test.js.map +1 -1
  79. package/dist/__tests__/state-root-resolution.test.js +64 -0
  80. package/dist/__tests__/state-root-resolution.test.js.map +1 -1
  81. package/dist/cli/__tests__/launch.test.js +24 -0
  82. package/dist/cli/__tests__/launch.test.js.map +1 -1
  83. package/dist/cli/__tests__/team-status-worktree.test.d.ts +2 -0
  84. package/dist/cli/__tests__/team-status-worktree.test.d.ts.map +1 -0
  85. package/dist/cli/__tests__/team-status-worktree.test.js +96 -0
  86. package/dist/cli/__tests__/team-status-worktree.test.js.map +1 -0
  87. package/dist/cli/__tests__/team.test.js +164 -0
  88. package/dist/cli/__tests__/team.test.js.map +1 -1
  89. package/dist/cli/__tests__/tmux-utils.test.js +18 -3
  90. package/dist/cli/__tests__/tmux-utils.test.js.map +1 -1
  91. package/dist/cli/autoresearch-setup-session.d.ts.map +1 -1
  92. package/dist/cli/autoresearch-setup-session.js +1 -0
  93. package/dist/cli/autoresearch-setup-session.js.map +1 -1
  94. package/dist/cli/commands/team.js +1 -1
  95. package/dist/cli/launch.d.ts.map +1 -1
  96. package/dist/cli/launch.js +10 -2
  97. package/dist/cli/launch.js.map +1 -1
  98. package/dist/cli/team.d.ts.map +1 -1
  99. package/dist/cli/team.js +103 -4
  100. package/dist/cli/team.js.map +1 -1
  101. package/dist/cli/tmux-utils.d.ts.map +1 -1
  102. package/dist/cli/tmux-utils.js +5 -2
  103. package/dist/cli/tmux-utils.js.map +1 -1
  104. package/dist/cli/utils/formatting.d.ts +0 -10
  105. package/dist/cli/utils/formatting.d.ts.map +1 -1
  106. package/dist/cli/utils/formatting.js +0 -52
  107. package/dist/cli/utils/formatting.js.map +1 -1
  108. package/dist/config/loader.d.ts.map +1 -1
  109. package/dist/config/loader.js +34 -8
  110. package/dist/config/loader.js.map +1 -1
  111. package/dist/features/__tests__/magic-keywords.test.d.ts +2 -0
  112. package/dist/features/__tests__/magic-keywords.test.d.ts.map +1 -0
  113. package/dist/features/__tests__/magic-keywords.test.js +19 -0
  114. package/dist/features/__tests__/magic-keywords.test.js.map +1 -0
  115. package/dist/features/delegation-enforcer.d.ts +2 -0
  116. package/dist/features/delegation-enforcer.d.ts.map +1 -1
  117. package/dist/features/delegation-enforcer.js +10 -0
  118. package/dist/features/delegation-enforcer.js.map +1 -1
  119. package/dist/features/magic-keywords.d.ts +1 -1
  120. package/dist/features/magic-keywords.d.ts.map +1 -1
  121. package/dist/features/magic-keywords.js +5 -192
  122. package/dist/features/magic-keywords.js.map +1 -1
  123. package/dist/hooks/__tests__/bridge-routing.test.js +23 -0
  124. package/dist/hooks/__tests__/bridge-routing.test.js.map +1 -1
  125. package/dist/hooks/bridge-normalize.d.ts +5 -0
  126. package/dist/hooks/bridge-normalize.d.ts.map +1 -1
  127. package/dist/hooks/bridge-normalize.js +6 -0
  128. package/dist/hooks/bridge-normalize.js.map +1 -1
  129. package/dist/hooks/bridge.d.ts +4 -0
  130. package/dist/hooks/bridge.d.ts.map +1 -1
  131. package/dist/hooks/bridge.js +60 -3
  132. package/dist/hooks/bridge.js.map +1 -1
  133. package/dist/hooks/keyword-detector/index.js +1 -1
  134. package/dist/hooks/keyword-detector/index.js.map +1 -1
  135. package/dist/hooks/keyword-detector/ultrawork/__tests__/index.test.d.ts +2 -0
  136. package/dist/hooks/keyword-detector/ultrawork/__tests__/index.test.d.ts.map +1 -0
  137. package/dist/hooks/keyword-detector/ultrawork/__tests__/index.test.js +37 -0
  138. package/dist/hooks/keyword-detector/ultrawork/__tests__/index.test.js.map +1 -0
  139. package/dist/hooks/keyword-detector/ultrawork/default.d.ts +3 -0
  140. package/dist/hooks/keyword-detector/ultrawork/default.d.ts.map +1 -0
  141. package/dist/hooks/keyword-detector/ultrawork/default.js +67 -0
  142. package/dist/hooks/keyword-detector/ultrawork/default.js.map +1 -0
  143. package/dist/hooks/keyword-detector/ultrawork/gemini.d.ts +3 -0
  144. package/dist/hooks/keyword-detector/ultrawork/gemini.d.ts.map +1 -0
  145. package/dist/hooks/keyword-detector/ultrawork/gemini.js +47 -0
  146. package/dist/hooks/keyword-detector/ultrawork/gemini.js.map +1 -0
  147. package/dist/hooks/keyword-detector/ultrawork/gpt.d.ts +3 -0
  148. package/dist/hooks/keyword-detector/ultrawork/gpt.d.ts.map +1 -0
  149. package/dist/hooks/keyword-detector/ultrawork/gpt.js +52 -0
  150. package/dist/hooks/keyword-detector/ultrawork/gpt.js.map +1 -0
  151. package/dist/hooks/keyword-detector/ultrawork/index.d.ts +8 -0
  152. package/dist/hooks/keyword-detector/ultrawork/index.d.ts.map +1 -0
  153. package/dist/hooks/keyword-detector/ultrawork/index.js +24 -0
  154. package/dist/hooks/keyword-detector/ultrawork/index.js.map +1 -0
  155. package/dist/hooks/keyword-detector/ultrawork/planner.d.ts +3 -0
  156. package/dist/hooks/keyword-detector/ultrawork/planner.d.ts.map +1 -0
  157. package/dist/hooks/keyword-detector/ultrawork/planner.js +57 -0
  158. package/dist/hooks/keyword-detector/ultrawork/planner.js.map +1 -0
  159. package/dist/hooks/keyword-detector/ultrawork/source-detector.d.ts +6 -0
  160. package/dist/hooks/keyword-detector/ultrawork/source-detector.d.ts.map +1 -0
  161. package/dist/hooks/keyword-detector/ultrawork/source-detector.js +37 -0
  162. package/dist/hooks/keyword-detector/ultrawork/source-detector.js.map +1 -0
  163. package/dist/hooks/learner/bridge.d.ts +2 -0
  164. package/dist/hooks/learner/bridge.d.ts.map +1 -1
  165. package/dist/hooks/learner/bridge.js +15 -109
  166. package/dist/hooks/learner/bridge.js.map +1 -1
  167. package/dist/hooks/learner/index.d.ts.map +1 -1
  168. package/dist/hooks/learner/index.js +51 -14
  169. package/dist/hooks/learner/index.js.map +1 -1
  170. package/dist/hooks/learner/parser.d.ts +9 -0
  171. package/dist/hooks/learner/parser.d.ts.map +1 -1
  172. package/dist/hooks/learner/parser.js +18 -5
  173. package/dist/hooks/learner/parser.js.map +1 -1
  174. package/dist/hooks/learner/types.d.ts +6 -0
  175. package/dist/hooks/learner/types.d.ts.map +1 -1
  176. package/dist/hooks/persistent-mode/index.d.ts.map +1 -1
  177. package/dist/hooks/persistent-mode/index.js +7 -4
  178. package/dist/hooks/persistent-mode/index.js.map +1 -1
  179. package/dist/hooks/persistent-mode/session-isolation.test.js +8 -3
  180. package/dist/hooks/persistent-mode/session-isolation.test.js.map +1 -1
  181. package/dist/hooks/persistent-mode/stop-hook-blocking.test.js +142 -7
  182. package/dist/hooks/persistent-mode/stop-hook-blocking.test.js.map +1 -1
  183. package/dist/hooks/project-memory/__tests__/learner.test.js +7 -0
  184. package/dist/hooks/project-memory/__tests__/learner.test.js.map +1 -1
  185. package/dist/hooks/project-memory/learner.d.ts +1 -1
  186. package/dist/hooks/project-memory/learner.d.ts.map +1 -1
  187. package/dist/hooks/project-memory/learner.js +3 -0
  188. package/dist/hooks/project-memory/learner.js.map +1 -1
  189. package/dist/hooks/session-end/index.d.ts.map +1 -1
  190. package/dist/hooks/session-end/index.js +43 -0
  191. package/dist/hooks/session-end/index.js.map +1 -1
  192. package/dist/hooks/skill-bridge.cjs +116 -87
  193. package/dist/hud/__tests__/enterprise-cost.test.d.ts +5 -0
  194. package/dist/hud/__tests__/enterprise-cost.test.d.ts.map +1 -0
  195. package/dist/hud/__tests__/enterprise-cost.test.js +151 -0
  196. package/dist/hud/__tests__/enterprise-cost.test.js.map +1 -0
  197. package/dist/hud/__tests__/usage-api-enterprise.test.d.ts +5 -0
  198. package/dist/hud/__tests__/usage-api-enterprise.test.d.ts.map +1 -0
  199. package/dist/hud/__tests__/usage-api-enterprise.test.js +249 -0
  200. package/dist/hud/__tests__/usage-api-enterprise.test.js.map +1 -0
  201. package/dist/hud/elements/enterprise-cost.d.ts +16 -0
  202. package/dist/hud/elements/enterprise-cost.d.ts.map +1 -0
  203. package/dist/hud/elements/enterprise-cost.js +63 -0
  204. package/dist/hud/elements/enterprise-cost.js.map +1 -0
  205. package/dist/hud/elements/permission.d.ts.map +1 -1
  206. package/dist/hud/elements/permission.js +2 -5
  207. package/dist/hud/elements/permission.js.map +1 -1
  208. package/dist/hud/elements/session.d.ts.map +1 -1
  209. package/dist/hud/elements/session.js +5 -9
  210. package/dist/hud/elements/session.js.map +1 -1
  211. package/dist/hud/index.d.ts.map +1 -1
  212. package/dist/hud/index.js +22 -5
  213. package/dist/hud/index.js.map +1 -1
  214. package/dist/hud/render.d.ts.map +1 -1
  215. package/dist/hud/render.js +34 -2
  216. package/dist/hud/render.js.map +1 -1
  217. package/dist/hud/stdin.d.ts.map +1 -1
  218. package/dist/hud/stdin.js +49 -5
  219. package/dist/hud/stdin.js.map +1 -1
  220. package/dist/hud/types.d.ts +16 -0
  221. package/dist/hud/types.d.ts.map +1 -1
  222. package/dist/hud/types.js +1 -1
  223. package/dist/hud/types.js.map +1 -1
  224. package/dist/hud/usage-api.d.ts +19 -1
  225. package/dist/hud/usage-api.d.ts.map +1 -1
  226. package/dist/hud/usage-api.js +101 -18
  227. package/dist/hud/usage-api.js.map +1 -1
  228. package/dist/installer/__tests__/hook-templates.test.js +23 -0
  229. package/dist/installer/__tests__/hook-templates.test.js.map +1 -1
  230. package/dist/installer/hooks.d.ts +4 -2
  231. package/dist/installer/hooks.d.ts.map +1 -1
  232. package/dist/installer/hooks.js +5 -94
  233. package/dist/installer/hooks.js.map +1 -1
  234. package/dist/installer/index.d.ts +1 -0
  235. package/dist/installer/index.d.ts.map +1 -1
  236. package/dist/installer/index.js +64 -24
  237. package/dist/installer/index.js.map +1 -1
  238. package/dist/installer/mcp-registry.d.ts.map +1 -1
  239. package/dist/installer/mcp-registry.js +3 -2
  240. package/dist/installer/mcp-registry.js.map +1 -1
  241. package/dist/mcp/__tests__/team-server-artifact-convergence.test.js +156 -4
  242. package/dist/mcp/__tests__/team-server-artifact-convergence.test.js.map +1 -1
  243. package/dist/mcp/omc-tools-server.d.ts +11 -17
  244. package/dist/mcp/omc-tools-server.d.ts.map +1 -1
  245. package/dist/mcp/omc-tools-server.js +22 -32
  246. package/dist/mcp/omc-tools-server.js.map +1 -1
  247. package/dist/mcp/team-job-convergence.d.ts +9 -2
  248. package/dist/mcp/team-job-convergence.d.ts.map +1 -1
  249. package/dist/mcp/team-job-convergence.js +35 -14
  250. package/dist/mcp/team-job-convergence.js.map +1 -1
  251. package/dist/mcp/team-server.d.ts.map +1 -1
  252. package/dist/mcp/team-server.js +93 -13
  253. package/dist/mcp/team-server.js.map +1 -1
  254. package/dist/ralphthon/prd.d.ts.map +1 -1
  255. package/dist/ralphthon/prd.js +13 -17
  256. package/dist/ralphthon/prd.js.map +1 -1
  257. package/dist/shared/types.d.ts +3 -1
  258. package/dist/shared/types.d.ts.map +1 -1
  259. package/dist/team/__tests__/api-interop.cleanup.test.d.ts +2 -0
  260. package/dist/team/__tests__/api-interop.cleanup.test.d.ts.map +1 -0
  261. package/dist/team/__tests__/api-interop.cleanup.test.js +234 -0
  262. package/dist/team/__tests__/api-interop.cleanup.test.js.map +1 -0
  263. package/dist/team/__tests__/api-interop.dispatch.test.js +2 -1
  264. package/dist/team/__tests__/api-interop.dispatch.test.js.map +1 -1
  265. package/dist/team/__tests__/git-worktree.test.js +164 -3
  266. package/dist/team/__tests__/git-worktree.test.js.map +1 -1
  267. package/dist/team/__tests__/model-contract.test.js +38 -22
  268. package/dist/team/__tests__/model-contract.test.js.map +1 -1
  269. package/dist/team/__tests__/resolved-routing-snapshot.test.js +29 -1
  270. package/dist/team/__tests__/resolved-routing-snapshot.test.js.map +1 -1
  271. package/dist/team/__tests__/runtime-cli.test.js +2 -2
  272. package/dist/team/__tests__/runtime-cli.test.js.map +1 -1
  273. package/dist/team/__tests__/runtime-prompt-mode.test.js +17 -17
  274. package/dist/team/__tests__/runtime-prompt-mode.test.js.map +1 -1
  275. package/dist/team/__tests__/runtime-v2-role-routing.test.js +7 -1
  276. package/dist/team/__tests__/runtime-v2-role-routing.test.js.map +1 -1
  277. package/dist/team/__tests__/runtime-v2.dispatch.test.js +145 -16
  278. package/dist/team/__tests__/runtime-v2.dispatch.test.js.map +1 -1
  279. package/dist/team/__tests__/runtime-v2.monitor.test.d.ts +2 -0
  280. package/dist/team/__tests__/runtime-v2.monitor.test.d.ts.map +1 -0
  281. package/dist/team/__tests__/runtime-v2.monitor.test.js +219 -0
  282. package/dist/team/__tests__/runtime-v2.monitor.test.js.map +1 -0
  283. package/dist/team/__tests__/runtime-v2.shutdown.test.d.ts +2 -0
  284. package/dist/team/__tests__/runtime-v2.shutdown.test.d.ts.map +1 -0
  285. package/dist/team/__tests__/runtime-v2.shutdown.test.js +292 -0
  286. package/dist/team/__tests__/runtime-v2.shutdown.test.js.map +1 -0
  287. package/dist/team/__tests__/scaling-launch-config.test.js +204 -4
  288. package/dist/team/__tests__/scaling-launch-config.test.js.map +1 -1
  289. package/dist/team/__tests__/stage-router.test.js +29 -1
  290. package/dist/team/__tests__/stage-router.test.js.map +1 -1
  291. package/dist/team/__tests__/team-summary-worktree.test.d.ts +2 -0
  292. package/dist/team/__tests__/team-summary-worktree.test.d.ts.map +1 -0
  293. package/dist/team/__tests__/team-summary-worktree.test.js +85 -0
  294. package/dist/team/__tests__/team-summary-worktree.test.js.map +1 -0
  295. package/dist/team/__tests__/tmux-session-liveness.test.d.ts +2 -0
  296. package/dist/team/__tests__/tmux-session-liveness.test.d.ts.map +1 -0
  297. package/dist/team/__tests__/tmux-session-liveness.test.js +37 -0
  298. package/dist/team/__tests__/tmux-session-liveness.test.js.map +1 -0
  299. package/dist/team/__tests__/worker-bootstrap.test.js +47 -1
  300. package/dist/team/__tests__/worker-bootstrap.test.js.map +1 -1
  301. package/dist/team/__tests__/worktree-contract-fields.test.d.ts +2 -0
  302. package/dist/team/__tests__/worktree-contract-fields.test.d.ts.map +1 -0
  303. package/dist/team/__tests__/worktree-contract-fields.test.js +157 -0
  304. package/dist/team/__tests__/worktree-contract-fields.test.js.map +1 -0
  305. package/dist/team/api-interop.d.ts +2 -1
  306. package/dist/team/api-interop.d.ts.map +1 -1
  307. package/dist/team/api-interop.js +121 -14
  308. package/dist/team/api-interop.js.map +1 -1
  309. package/dist/team/capabilities.d.ts.map +1 -1
  310. package/dist/team/capabilities.js +2 -0
  311. package/dist/team/capabilities.js.map +1 -1
  312. package/dist/team/cli-worker-contract.d.ts +7 -6
  313. package/dist/team/cli-worker-contract.d.ts.map +1 -1
  314. package/dist/team/cli-worker-contract.js +7 -6
  315. package/dist/team/cli-worker-contract.js.map +1 -1
  316. package/dist/team/events.d.ts +3 -0
  317. package/dist/team/events.d.ts.map +1 -1
  318. package/dist/team/events.js +2 -1
  319. package/dist/team/events.js.map +1 -1
  320. package/dist/team/git-worktree.d.ts +78 -10
  321. package/dist/team/git-worktree.d.ts.map +1 -1
  322. package/dist/team/git-worktree.js +453 -97
  323. package/dist/team/git-worktree.js.map +1 -1
  324. package/dist/team/governance.d.ts +3 -2
  325. package/dist/team/governance.d.ts.map +1 -1
  326. package/dist/team/governance.js.map +1 -1
  327. package/dist/team/model-contract.d.ts +18 -2
  328. package/dist/team/model-contract.d.ts.map +1 -1
  329. package/dist/team/model-contract.js +55 -27
  330. package/dist/team/model-contract.js.map +1 -1
  331. package/dist/team/monitor.d.ts.map +1 -1
  332. package/dist/team/monitor.js +47 -3
  333. package/dist/team/monitor.js.map +1 -1
  334. package/dist/team/runtime-v2.d.ts +9 -0
  335. package/dist/team/runtime-v2.d.ts.map +1 -1
  336. package/dist/team/runtime-v2.js +347 -120
  337. package/dist/team/runtime-v2.js.map +1 -1
  338. package/dist/team/runtime.d.ts.map +1 -1
  339. package/dist/team/runtime.js +4 -1
  340. package/dist/team/runtime.js.map +1 -1
  341. package/dist/team/scaling.d.ts.map +1 -1
  342. package/dist/team/scaling.js +110 -13
  343. package/dist/team/scaling.js.map +1 -1
  344. package/dist/team/state/tasks.d.ts.map +1 -1
  345. package/dist/team/state/tasks.js +1 -0
  346. package/dist/team/state/tasks.js.map +1 -1
  347. package/dist/team/team-ops.d.ts.map +1 -1
  348. package/dist/team/team-ops.js +112 -16
  349. package/dist/team/team-ops.js.map +1 -1
  350. package/dist/team/tmux-session.d.ts +17 -29
  351. package/dist/team/tmux-session.d.ts.map +1 -1
  352. package/dist/team/tmux-session.js +116 -107
  353. package/dist/team/tmux-session.js.map +1 -1
  354. package/dist/team/types.d.ts +31 -17
  355. package/dist/team/types.d.ts.map +1 -1
  356. package/dist/team/types.js.map +1 -1
  357. package/dist/team/worker-bootstrap.d.ts +7 -0
  358. package/dist/team/worker-bootstrap.d.ts.map +1 -1
  359. package/dist/team/worker-bootstrap.js +27 -13
  360. package/dist/team/worker-bootstrap.js.map +1 -1
  361. package/dist/team/worker-canonicalization.d.ts.map +1 -1
  362. package/dist/team/worker-canonicalization.js +2 -0
  363. package/dist/team/worker-canonicalization.js.map +1 -1
  364. package/dist/utils/frontmatter.d.ts.map +1 -1
  365. package/dist/utils/frontmatter.js +1 -16
  366. package/dist/utils/frontmatter.js.map +1 -1
  367. package/dist/utils/omc-cli-rendering.d.ts.map +1 -1
  368. package/dist/utils/omc-cli-rendering.js +1 -12
  369. package/dist/utils/omc-cli-rendering.js.map +1 -1
  370. package/dist/utils/resolve-node.d.ts.map +1 -1
  371. package/dist/utils/resolve-node.js +22 -28
  372. package/dist/utils/resolve-node.js.map +1 -1
  373. package/docs/MIGRATION.md +1003 -0
  374. package/docs/REFERENCE.md +4 -0
  375. package/docs/TEAM-WORKTREE-MODE.md +86 -0
  376. package/docs/copilot-instructions.md +1 -1
  377. package/docs/reference/compatibility.md +1 -1
  378. package/hooks/hooks.json +34 -13
  379. package/package.json +1 -1
  380. package/scripts/cleanup-orphans.mjs +24 -3
  381. package/scripts/context-safety.mjs +10 -11
  382. package/scripts/keyword-detector.debug.mjs +2 -2
  383. package/scripts/keyword-detector.mjs +219 -57
  384. package/scripts/lib/state-root.cjs +1 -1
  385. package/scripts/lib/state-root.mjs +3 -3
  386. package/scripts/persistent-mode.cjs +30 -4
  387. package/scripts/persistent-mode.mjs +28 -2
  388. package/scripts/plugin-setup.mjs +8 -7
  389. package/scripts/post-tool-rules-injector.mjs +1 -1
  390. package/scripts/post-tool-verifier.mjs +55 -3
  391. package/scripts/pre-tool-enforcer.mjs +9 -21
  392. package/scripts/project-memory-session.mjs +1 -1
  393. package/scripts/run.cjs +9 -9
  394. package/scripts/safe-command-approver.mjs +156 -0
  395. package/scripts/session-start.mjs +91 -11
  396. package/scripts/setup-copilot-instructions.sh +5 -4
  397. package/scripts/skill-injector.mjs +60 -23
  398. package/scripts/test-pr25.sh +1 -1
  399. package/scripts/uninstall.sh +1 -1
  400. package/scripts/verify-deliverables.mjs +1 -1
  401. package/skills/deep-interview/SKILL.md +23 -10
  402. package/skills/learner/SKILL.md +1 -1
  403. package/skills/project-session-manager/lib/config.sh +1 -1
  404. package/skills/project-session-manager/lib/parse.sh +1 -1
  405. package/skills/project-session-manager/lib/providers/azure-devops.sh +1 -1
  406. package/skills/project-session-manager/lib/providers/bitbucket.sh +1 -1
  407. package/skills/project-session-manager/lib/providers/gitea.sh +1 -1
  408. package/skills/project-session-manager/lib/providers/github.sh +1 -1
  409. package/skills/project-session-manager/lib/providers/gitlab.sh +1 -1
  410. package/skills/project-session-manager/lib/providers/interface.sh +1 -1
  411. package/skills/project-session-manager/lib/providers/jira.sh +1 -1
  412. package/skills/project-session-manager/lib/session.sh +1 -1
  413. package/skills/project-session-manager/lib/tmux.sh +1 -1
  414. package/skills/project-session-manager/lib/worktree.sh +1 -1
  415. package/skills/project-session-manager/psm.sh +1 -1
  416. package/skills/project-session-manager/tests/test-psm-prompt-injection.sh +1 -1
  417. package/skills/skill/SKILL.md +1 -1
  418. package/templates/hooks/keyword-detector.mjs +183 -26
  419. package/templates/hooks/persistent-mode.mjs +28 -2
  420. package/templates/hooks/session-start.mjs +126 -11
@@ -703,6 +703,55 @@ export function detectWriteFailure(output) {
703
703
  return errorPatterns.some(pattern => pattern.test(cleaned));
704
704
  }
705
705
 
706
+ // Detect Copilot CLI's deterministic write/edit success markers so docs or
707
+ // serialized tool output containing diagnostic prose do not override success.
708
+ export function isCopilotCliWriteSuccess(output) {
709
+ if (!output) return false;
710
+
711
+ const cleaned = stripClaudeTempCwdErrors(output);
712
+ const successPatterns = [
713
+ /(^|\n)The file .+ has been updated successfully\.?(\n|$)/i,
714
+ /(^|\n)File (?:created|written|updated) successfully(?:\s+at:\s*.+)?\.?(\n|$)/i,
715
+ /(^|\n).*file state is current in your context\b.*(\n|$)/i,
716
+ ];
717
+
718
+ return successPatterns.some(pattern => pattern.test(cleaned));
719
+ }
720
+
721
+ function extractTextFromKnownToolResponseField(value, depth = 0) {
722
+ if (typeof value === 'string') return [value];
723
+ if (!value || depth > 4) return [];
724
+
725
+ if (Array.isArray(value)) {
726
+ return value.flatMap(item => extractTextFromKnownToolResponseField(item, depth + 1));
727
+ }
728
+
729
+ if (typeof value !== 'object') return [];
730
+
731
+ const textFields = ['text', 'message', 'result', 'output', 'stdout'];
732
+ const texts = [];
733
+ for (const field of textFields) {
734
+ if (typeof value[field] === 'string') {
735
+ texts.push(value[field]);
736
+ }
737
+ }
738
+
739
+ if (
740
+ 'content' in value &&
741
+ value.content &&
742
+ (Array.isArray(value.content) || typeof value.content === 'object')
743
+ ) {
744
+ texts.push(...extractTextFromKnownToolResponseField(value.content, depth + 1));
745
+ }
746
+
747
+ return texts;
748
+ }
749
+
750
+ function hasStructuredWriteSuccess(rawResponse) {
751
+ if (!rawResponse || typeof rawResponse === 'string') return false;
752
+ return extractTextFromKnownToolResponseField(rawResponse).some(isCopilotCliWriteSuccess);
753
+ }
754
+
706
755
  // Get agent completion summary from tracking state
707
756
  function getAgentCompletionSummary(directory, quietLevel = QUIET_LEVEL) {
708
757
  const trackingFile = join(directory, '.omcp', 'state', 'subagent-tracking.json');
@@ -731,7 +780,7 @@ function getAgentCompletionSummary(directory, quietLevel = QUIET_LEVEL) {
731
780
 
732
781
  // Generate contextual message
733
782
  function generateMessage(toolName, toolOutput, sessionId, toolCount, directory, options = {}) {
734
- const { wasTruncated = false, rawLength = 0 } = options;
783
+ const { wasTruncated = false, rawLength = 0, structuredWriteSuccess = false } = options;
735
784
  let message = '';
736
785
 
737
786
  switch (toolName) {
@@ -782,7 +831,7 @@ function generateMessage(toolName, toolOutput, sessionId, toolCount, directory,
782
831
  }
783
832
 
784
833
  case 'Edit':
785
- if (detectWriteFailure(toolOutput)) {
834
+ if (!structuredWriteSuccess && !isCopilotCliWriteSuccess(toolOutput) && detectWriteFailure(toolOutput)) {
786
835
  message = 'Edit operation failed. Verify file exists and content matches exactly.';
787
836
  } else if (QUIET_LEVEL === 0) {
788
837
  message = 'Code modified. Verify changes work as expected before marking complete.';
@@ -790,7 +839,7 @@ function generateMessage(toolName, toolOutput, sessionId, toolCount, directory,
790
839
  break;
791
840
 
792
841
  case 'Write':
793
- if (detectWriteFailure(toolOutput)) {
842
+ if (!structuredWriteSuccess && !isCopilotCliWriteSuccess(toolOutput) && detectWriteFailure(toolOutput)) {
794
843
  message = 'Write operation failed. Check file permissions and directory existence.';
795
844
  } else if (QUIET_LEVEL === 0) {
796
845
  message = 'File written. Test the changes to ensure they work correctly.';
@@ -847,6 +896,8 @@ async function main() {
847
896
 
848
897
  const toolName = data.tool_name || data.toolName || '';
849
898
  const rawResponse = data.tool_response || data.toolOutput || '';
899
+ const structuredWriteSuccess =
900
+ (toolName === 'Write' || toolName === 'Edit') && hasStructuredWriteSuccess(rawResponse);
850
901
  const toolOutput = typeof rawResponse === 'string' ? rawResponse : JSON.stringify(rawResponse);
851
902
  const { clipped: clippedToolOutput, wasTruncated } = clipToolOutputForAnalysis(toolName, toolOutput);
852
903
  const sessionId = data.session_id || data.sessionId || 'unknown';
@@ -892,6 +943,7 @@ async function main() {
892
943
  generateMessage(toolName, clippedToolOutput, sessionId, toolCount, directory, {
893
944
  wasTruncated,
894
945
  rawLength: toolOutput.length,
946
+ structuredWriteSuccess,
895
947
  }),
896
948
  maybeBuildPreemptiveCompactionMessage(toolName, data, directory),
897
949
  );
@@ -82,10 +82,10 @@ function readAgentDefinitionModel(subagentType) {
82
82
  // Reject path traversal: agent names are simple identifiers; no path separators allowed.
83
83
  if (!/^[a-zA-Z0-9_-]+$/.test(agentType)) return null;
84
84
  // Build a prioritised list of agents/ directories to search.
85
- // CLAUDE_PLUGIN_ROOT is tried first when set; the script-relative path is always the
85
+ // PLUGIN_ROOT is tried first when set; the script-relative path is always the
86
86
  // final fallback. Checking per-file (not just per-directory) means a partially-populated
87
87
  // plugin install doesn't hide agents that exist in the script-relative tree.
88
- const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT;
88
+ const pluginRoot = process.env.PLUGIN_ROOT || process.env.CLAUDE_PLUGIN_ROOT;
89
89
  const scriptAgentsDir = join(dirname(fileURLToPath(import.meta.url)), '..', 'agents');
90
90
  const candidateDirs = [
91
91
  ...(pluginRoot ? [join(pluginRoot, 'agents')] : []),
@@ -755,12 +755,8 @@ async function main() {
755
755
  ? `Set ANTHROPIC_DEFAULT_${derivedTier}_MODEL=<valid-bedrock-id> in settings.json env, or set OMC_SUBAGENT_MODEL as a global override.`
756
756
  : `Remove the \`model\` parameter, or set ANTHROPIC_DEFAULT_SONNET_MODEL=<valid-bedrock-id> in settings.json env.`;
757
757
  console.log(JSON.stringify({
758
- continue: true,
759
- hookSpecificOutput: {
760
- hookEventName: 'PreToolUse',
761
- permissionDecision: 'deny',
762
- permissionDecisionReason: `[MODEL ROUTING] This environment uses a non-standard provider (Bedrock/Vertex/proxy). ${guidance} The model "${toolModel}" is not valid for this provider.`
763
- }
758
+ permissionDecision: 'deny',
759
+ permissionDecisionReason: `[MODEL ROUTING] This environment uses a non-standard provider (Bedrock/Vertex/proxy). ${guidance} The model "${toolModel}" is not valid for this provider.`
764
760
  }));
765
761
  return;
766
762
  }
@@ -777,12 +773,8 @@ async function main() {
777
773
  ? `Pass model="${tierAlias}" explicitly on this ${toolName} call — tier aliases resolve cleanly on Bedrock.`
778
774
  : `Pass model="${tierAlias}" explicitly on this ${toolName} call, and set ANTHROPIC_DEFAULT_${tierAlias.toUpperCase()}_MODEL=<valid-bedrock-id> in settings.json env.`;
779
775
  console.log(JSON.stringify({
780
- continue: true,
781
- hookSpecificOutput: {
782
- hookEventName: 'PreToolUse',
783
- permissionDecision: 'deny',
784
- permissionDecisionReason: `[MODEL ROUTING] Your session model "${sessionModel}" has a context-window suffix ([1m]) that sub-agents cannot inherit — the runtime strips it to a bare Anthropic model ID which is invalid on Bedrock. ${suggestion}`
785
- }
776
+ permissionDecision: 'deny',
777
+ permissionDecisionReason: `[MODEL ROUTING] Your session model "${sessionModel}" has a context-window suffix ([1m]) that sub-agents cannot inherit — the runtime strips it to a bare Anthropic model ID which is invalid on Bedrock. ${suggestion}`
786
778
  }));
787
779
  return;
788
780
  }
@@ -804,12 +796,8 @@ async function main() {
804
796
  const guidance = `Add model="${defTierAlias}" to this ${toolName} call — tier aliases resolve to configured provider models (${resolvedModel}).`;
805
797
  const agentType = (toolInput.subagent_type).replace(/^oh-my-copilot:/, '');
806
798
  console.log(JSON.stringify({
807
- continue: true,
808
- hookSpecificOutput: {
809
- hookEventName: 'PreToolUse',
810
- permissionDecision: 'deny',
811
- permissionDecisionReason: `[MODEL ROUTING] Agent type "${agentType}" has model "${agentDefModel}" in its definition, which is not valid for this Bedrock/Vertex/proxy environment. ${guidance}`
812
- }
799
+ permissionDecision: 'deny',
800
+ permissionDecisionReason: `[MODEL ROUTING] Agent type "${agentType}" has model "${agentDefModel}" in its definition, which is not valid for this Bedrock/Vertex/proxy environment. ${guidance}`
813
801
  }));
814
802
  return;
815
803
  }
@@ -823,7 +811,7 @@ async function main() {
823
811
  // Fires in PreToolUse so users get notified BEFORE the tool blocks for input (#597)
824
812
  if (toolName === 'AskUserQuestion') {
825
813
  try {
826
- const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT;
814
+ const pluginRoot = process.env.PLUGIN_ROOT || process.env.CLAUDE_PLUGIN_ROOT;
827
815
  if (pluginRoot) {
828
816
  const { notify } = await import(pathToFileURL(join(pluginRoot, 'dist', 'notifications', 'index.js')).href);
829
817
 
@@ -12,7 +12,7 @@ const __filename = fileURLToPath(import.meta.url);
12
12
  const __dirname = dirname(__filename);
13
13
 
14
14
  function getRuntimeBaseDir() {
15
- return process.env.CLAUDE_PLUGIN_ROOT || join(__dirname, '..');
15
+ return process.env.PLUGIN_ROOT || process.env.CLAUDE_PLUGIN_ROOT || join(__dirname, '..');
16
16
  }
17
17
 
18
18
  // Import timeout-protected stdin reader (prevents hangs on Linux/Windows, see issue #240, #524)
package/scripts/run.cjs CHANGED
@@ -10,9 +10,9 @@
10
10
  * /usr/bin/sh is a PE32+ binary the OS refuses to execute natively.
11
11
  * Fixes issues #909, #899, #892, #869.
12
12
  *
13
- * Usage (from hooks.json, after setup patches the absolute node path in):
14
- * /abs/path/to/node "${CLAUDE_PLUGIN_ROOT}/scripts/run.cjs" \
15
- * "${CLAUDE_PLUGIN_ROOT}/scripts/<hook>.mjs" [args...]
13
+ * Usage (from hooks.json):
14
+ * /abs/path/to/node "${PLUGIN_ROOT}/scripts/run.cjs" \
15
+ * "${PLUGIN_ROOT}/scripts/<hook>.mjs" [args...]
16
16
  *
17
17
  * During post-install setup, the leading `node` token is replaced with
18
18
  * process.execPath so nvm/fnm users and Windows users all get the right binary.
@@ -24,16 +24,16 @@ const { join, basename, dirname } = require('path');
24
24
 
25
25
  const target = process.argv[2];
26
26
  if (!target) {
27
- // Nothing to run — exit cleanly so Claude Code hooks are never blocked.
27
+ // Nothing to run — exit cleanly so hooks are never blocked.
28
28
  process.exit(0);
29
29
  }
30
30
 
31
31
  /**
32
- * Resolve the hook script target path, handling stale CLAUDE_PLUGIN_ROOT.
32
+ * Resolve the hook script target path, handling stale PLUGIN_ROOT.
33
33
  *
34
34
  * When a plugin update replaces an old version directory with a symlink (or
35
35
  * deletes it entirely), sessions that still reference the old version via
36
- * CLAUDE_PLUGIN_ROOT will fail with MODULE_NOT_FOUND.
36
+ * PLUGIN_ROOT will fail with MODULE_NOT_FOUND.
37
37
  *
38
38
  * Resolution strategy:
39
39
  * 1. Use the target as-is if it exists.
@@ -57,10 +57,10 @@ function resolveTarget(targetPath) {
57
57
  }
58
58
 
59
59
  // Fallback: scan plugin cache for the same script in the latest version.
60
- // CLAUDE_PLUGIN_ROOT is e.g. ~/.claude/plugins/cache/omc/oh-my-copilot/4.2.14
60
+ // PLUGIN_ROOT is e.g. ~/.copilot/plugins/cache/omc/oh-my-copilot/4.2.14
61
61
  // We look one level up for sibling version directories.
62
62
  try {
63
- const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT;
63
+ const pluginRoot = process.env.PLUGIN_ROOT || process.env.CLAUDE_PLUGIN_ROOT;
64
64
  if (!pluginRoot) return null;
65
65
 
66
66
  const cacheBase = dirname(pluginRoot); // .../oh-my-copilot/
@@ -134,7 +134,7 @@ function resolveHookTimeoutMs(targetPath, extraArgs) {
134
134
  const resolved = resolveTarget(target);
135
135
  if (!resolved) {
136
136
  // Target not found anywhere — exit cleanly so hooks are never blocked.
137
- // This is the graceful fallback for stale CLAUDE_PLUGIN_ROOT paths.
137
+ // This is the graceful fallback for stale PLUGIN_ROOT paths.
138
138
  process.exit(0);
139
139
  }
140
140
 
@@ -0,0 +1,156 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * OMC Safe Command Approver (PreToolUse)
5
+ *
6
+ * Auto-approves known-safe Bash commands (git status, npm test, dotnet build, etc.)
7
+ * so they don't trigger an interactive permission prompt. Works on both Copilot CLI
8
+ * and Claude Code — migrated from the Claude-Code-only permissionRequest handler.
9
+ *
10
+ * For non-Bash tools or unrecognised commands, outputs nothing (passes through to
11
+ * the runtime's native permission flow).
12
+ *
13
+ * Hook output (preToolUse — Copilot CLI compliant):
14
+ * - Allow ({ permissionDecision: "allow" }) for safe commands
15
+ * - No output for everything else (defer to runtime)
16
+ */
17
+
18
+ import { readStdin } from './lib/stdin.mjs';
19
+
20
+ // --- Safe command patterns (mirrored from src/hooks/permission-handler/index.ts) ---
21
+
22
+ const SAFE_PATTERNS = [
23
+ /^git (status|diff|log|branch|show|fetch)/,
24
+ /^npm (test|run (test|lint|build|check|typecheck))/,
25
+ /^pnpm (test|run (test|lint|build|check|typecheck))/,
26
+ /^yarn (test|run (test|lint|build|check|typecheck))/,
27
+ /^tsc( |$)/,
28
+ /^gh (issue|pr) (view|list|status)\b/,
29
+ /^eslint /,
30
+ /^prettier /,
31
+ /^cargo (test|check|clippy|build)/,
32
+ /^pytest/,
33
+ /^python -m pytest/,
34
+ /^ls( |$)/,
35
+ /^grep /,
36
+ /^find /,
37
+ /^wc /,
38
+ /^pwd$/,
39
+ /^which /,
40
+ /^echo /,
41
+ /^env$/,
42
+ /^node --version$/,
43
+ /^dotnet (--version|--list-sdks|--list-runtimes|--info)$/,
44
+ /^dotnet (build|test|run|restore|clean)( |$)/,
45
+ /^gh (pr|issue|repo|api|run|workflow) (view|list|status|diff|checks)/,
46
+ /^gh auth status/,
47
+ /^az (account show|group list|resource list|ad signed-in-user show)/,
48
+ /^az devops (project list|configure)/,
49
+ /^az pipelines (list|show|runs list)/,
50
+ /^az repos (list|show|pr list)/,
51
+ ];
52
+
53
+ // Shell metacharacters that enable command chaining / injection
54
+ const DANGEROUS_SHELL_CHARS = /[;&|`$()<>\n\r\t\0\\{}\[\]*?~!#]/;
55
+
56
+ // Heredoc operator detection
57
+ const HEREDOC_PATTERN = /<<[-~]?\s*['"]?\w+['"]?/;
58
+
59
+ const SAFE_HEREDOC_PATTERNS = [
60
+ /^git commit\b/,
61
+ /^git tag\b/,
62
+ ];
63
+
64
+ const SAFE_RIPGREP_FLAGS = new Set([
65
+ '-n', '--line-number', '-S', '--smart-case', '-F', '--fixed-strings',
66
+ '-i', '--ignore-case', '--no-heading',
67
+ ]);
68
+
69
+ function isSafeCommand(command) {
70
+ const trimmed = command.trim();
71
+ if (DANGEROUS_SHELL_CHARS.test(trimmed)) return false;
72
+ return SAFE_PATTERNS.some(p => p.test(trimmed));
73
+ }
74
+
75
+ function isHeredocWithSafeBase(command) {
76
+ const trimmed = command.trim();
77
+ if (!trimmed.includes('\n')) return false;
78
+ if (!HEREDOC_PATTERN.test(trimmed)) return false;
79
+ const firstLine = trimmed.split('\n')[0].trim();
80
+ return SAFE_HEREDOC_PATTERNS.some(p => p.test(firstLine));
81
+ }
82
+
83
+ function tokenizeShellCommand(command) {
84
+ const tokens = [];
85
+ let current = '';
86
+ let quote = null;
87
+ for (const char of command.trim()) {
88
+ if (quote) { if (char === quote) quote = null; else current += char; continue; }
89
+ if (char === '"' || char === "'") { quote = char; continue; }
90
+ if (/\s/.test(char)) { if (current) { tokens.push(current); current = ''; } continue; }
91
+ current += char;
92
+ }
93
+ if (quote) return null;
94
+ if (current) tokens.push(current);
95
+ return tokens;
96
+ }
97
+
98
+ function isRipgrepReadOnly(tokens) {
99
+ if (tokens[0] !== 'rg') return false;
100
+ for (let i = 1; i < tokens.length; i++) {
101
+ const t = tokens[i];
102
+ if (t.startsWith('-')) {
103
+ if (SAFE_RIPGREP_FLAGS.has(t)) continue;
104
+ if (t.startsWith('--type=') || t.startsWith('--glob=') || t.startsWith('-g')) continue;
105
+ if (t === '--type' || t === '--glob' || t === '-g' || t === '-t') { i++; continue; }
106
+ return false;
107
+ }
108
+ }
109
+ return true;
110
+ }
111
+
112
+ function isSafeRepoInspectionCommand(command) {
113
+ const tokens = tokenizeShellCommand(command);
114
+ if (!tokens || tokens.length === 0) return false;
115
+ if (isRipgrepReadOnly(tokens)) return true;
116
+ if (/^cat( |$)/.test(command) || /^head( |$)/.test(command) || /^tail( |$)/.test(command)) return true;
117
+ return false;
118
+ }
119
+
120
+ function isSafeTargetedLocalTestCommand(command) {
121
+ const tokens = tokenizeShellCommand(command);
122
+ if (!tokens || tokens.length < 2) return false;
123
+ const bin = tokens[0];
124
+ if (bin === 'npx' && tokens[1] === 'vitest' && tokens.includes('run') && tokens.some(t => t.endsWith('.test.ts') || t.endsWith('.test.js'))) return true;
125
+ if (bin === 'pytest' && tokens.some(t => t.endsWith('.py') || t.includes('::') || t.startsWith('tests/'))) return true;
126
+ if (bin === 'go' && tokens[1] === 'test' && tokens.some(t => t.startsWith('./') || t.includes('...'))) return true;
127
+ return false;
128
+ }
129
+
130
+ async function main() {
131
+ try {
132
+ const input = await readStdin();
133
+ const data = JSON.parse(input);
134
+
135
+ const toolName = data.tool_name || data.toolName || '';
136
+
137
+ // Only process Bash tool calls
138
+ if (toolName !== 'Bash') return;
139
+
140
+ const command = data.tool_input?.command ?? data.toolInput?.command;
141
+ if (!command || typeof command !== 'string') return;
142
+
143
+ const trimmed = command.trim();
144
+ if (!trimmed) return;
145
+
146
+ if (isSafeCommand(trimmed) || isHeredocWithSafeBase(trimmed)
147
+ || isSafeRepoInspectionCommand(trimmed) || isSafeTargetedLocalTestCommand(trimmed)) {
148
+ console.log(JSON.stringify({ permissionDecision: 'allow' }));
149
+ }
150
+ // No output for unrecognised commands — defer to runtime's native permission flow
151
+ } catch {
152
+ // On error, produce no output — never block on hook failure
153
+ }
154
+ }
155
+
156
+ main();
@@ -48,8 +48,32 @@ function readJsonFile(path) {
48
48
  }
49
49
  }
50
50
 
51
+
52
+ const SESSION_ID_ALLOWLIST = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,255}$/;
53
+ const WORKFLOW_SLOT_TOMBSTONE_TTL_MS = 24 * 60 * 60 * 1000;
54
+
55
+ function isWorkflowSlotTombstonedForMode(omcRoot, mode, sessionId) {
56
+ const safeSessionId = typeof sessionId === 'string' && SESSION_ID_ALLOWLIST.test(sessionId) ? sessionId : '';
57
+ const ledgerPath = safeSessionId
58
+ ? join(omcRoot, 'state', 'sessions', safeSessionId, 'skill-active-state.json')
59
+ : join(omcRoot, 'state', 'skill-active-state.json');
60
+ const ledger = readJsonFile(ledgerPath);
61
+ const slot = ledger?.active_skills?.[mode];
62
+ if (!slot || typeof slot !== 'object') return false;
63
+ if (typeof slot.completed_at !== 'string' || !slot.completed_at) return false;
64
+ const completedAt = new Date(slot.completed_at).getTime();
65
+ if (!Number.isFinite(completedAt)) return true;
66
+ return Date.now() - completedAt < WORKFLOW_SLOT_TOMBSTONE_TTL_MS;
67
+ }
68
+
69
+ function shouldRestoreModeState(omcRoot, mode, state, sessionId) {
70
+ if (!state?.active) return false;
71
+ if (isWorkflowSlotTombstonedForMode(omcRoot, mode, sessionId)) return false;
72
+ return true;
73
+ }
74
+
51
75
  function getRuntimeBaseDir() {
52
- return process.env.CLAUDE_PLUGIN_ROOT || join(__dirname, '..');
76
+ return process.env.PLUGIN_ROOT || process.env.CLAUDE_PLUGIN_ROOT || join(__dirname, '..');
53
77
  }
54
78
 
55
79
  async function loadProjectMemoryModules() {
@@ -143,16 +167,71 @@ function semverCompare(a, b) {
143
167
  return 0;
144
168
  }
145
169
 
170
+ const SESSION_START_CONTEXT_BUDGET = 6000;
171
+ const SESSION_START_OMISSION_NOTICE = '[Additional SessionStart context omitted to preserve the 6000-character aggregate budget.]';
172
+
173
+ function compactBudgetedText(text, maxChars) {
174
+ const notice = '\n...[truncated to preserve SessionStart context budget]';
175
+ if (!text || text.length <= maxChars) return text || '';
176
+ if (maxChars <= notice.length) return notice.slice(0, Math.max(0, maxChars));
177
+ return `${text.slice(0, maxChars - notice.length).trimEnd()}${notice}`;
178
+ }
179
+
180
+ function buildSessionStartAdditionalContext(messages) {
181
+ if (!Array.isArray(messages) || messages.length === 0) return '';
182
+
183
+ const sections = messages.map((message, index) => ({ index, message }));
184
+ const priorityOrder = [
185
+ /\[MODEL ROUTING OVERRIDE/,
186
+ /\[AUTOPILOT MODE RESTORED\]/,
187
+ /\[ULTRAWORK MODE RESTORED\]/,
188
+ /\[RALPH LOOP RESTORED\]/,
189
+ /\[PROJECT MEMORY\]/,
190
+ /\[NOTEPAD - Priority Context\]/,
191
+ /\[PENDING TASKS DETECTED\]/,
192
+ ];
193
+ const prioritized = [];
194
+ const remaining = [];
195
+ for (const section of sections) {
196
+ const score = priorityOrder.findIndex((pattern) => pattern.test(section.message));
197
+ if (score !== -1) prioritized.push({ ...section, score });
198
+ else remaining.push({ ...section, score: priorityOrder.length + section.index });
199
+ }
200
+ const ordered = [...prioritized.sort((a, b) => a.score - b.score || a.index - b.index), ...remaining]
201
+ .map((entry) => entry.message);
202
+
203
+ let used = 0;
204
+ const selected = [];
205
+ for (const message of ordered) {
206
+ const separator = selected.length > 0 ? 1 : 0;
207
+ if (used + separator + message.length > SESSION_START_CONTEXT_BUDGET) {
208
+ const remainingBudget = SESSION_START_CONTEXT_BUDGET - used - separator;
209
+ if (remainingBudget > 0) {
210
+ selected.push(
211
+ remainingBudget > 120
212
+ ? compactBudgetedText(message, remainingBudget)
213
+ : compactBudgetedText(SESSION_START_OMISSION_NOTICE, remainingBudget),
214
+ );
215
+ }
216
+ break;
217
+ }
218
+ selected.push(message);
219
+ used += separator + message.length;
220
+ }
221
+
222
+ return selected.join('\n');
223
+ }
224
+
146
225
  // Extract OMC version from CLAUDE.md content
147
226
  function extractOmcVersion(content) {
148
227
  const match = content.match(/<!-- OMC:VERSION:(\d+\.\d+\.\d+[^\s]*?) -->/);
149
228
  return match ? match[1] : null;
150
229
  }
151
230
 
152
- // Get plugin version from CLAUDE_PLUGIN_ROOT
231
+ // Get plugin version from PLUGIN_ROOT
153
232
  function getPluginVersion() {
154
233
  try {
155
- const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT;
234
+ const pluginRoot = process.env.PLUGIN_ROOT || process.env.CLAUDE_PLUGIN_ROOT;
156
235
  if (!pluginRoot) return null;
157
236
  const pkg = readJsonFile(join(pluginRoot, 'package.json'));
158
237
  return pkg?.version || null;
@@ -401,7 +480,7 @@ async function main() {
401
480
  } catch {}
402
481
 
403
482
  // Warn if silentAutoUpdate is enabled but running in plugin mode (#1773)
404
- if (process.env.CLAUDE_PLUGIN_ROOT) {
483
+ if (process.env.PLUGIN_ROOT || process.env.CLAUDE_PLUGIN_ROOT) {
405
484
  try {
406
485
  const omcConfigPath = join(configDir, '.omc-config.json');
407
486
  const omcConfig = readJsonFile(omcConfigPath);
@@ -434,7 +513,7 @@ async function main() {
434
513
  ultraworkState = readJsonFile(join(omcRoot, 'state', 'ultrawork-state.json'));
435
514
  }
436
515
 
437
- if (ultraworkState?.active) {
516
+ if (shouldRestoreModeState(omcRoot, 'ultrawork', ultraworkState, sessionId)) {
438
517
  messages.push(`<session-restore>
439
518
 
440
519
  [ULTRAWORK MODE RESTORED]
@@ -467,7 +546,7 @@ Treat this as prior-session context only. Prioritize the user's newest request,
467
546
  ralphState = readJsonFile(join(omcRoot, 'ralph-state.json'));
468
547
  }
469
548
  }
470
- if (ralphState?.active) {
549
+ if (shouldRestoreModeState(omcRoot, 'ralph', ralphState, sessionId)) {
471
550
  messages.push(`<session-restore>
472
551
 
473
552
  [RALPH LOOP RESTORED]
@@ -627,12 +706,13 @@ ${cleanContent}
627
706
  }
628
707
  }
629
708
 
630
- // Guard against CLAUDE_PLUGIN_ROOT pointing to a stale/deleted version.
709
+ // Guard against PLUGIN_ROOT pointing to a stale/deleted version.
631
710
  // When an old version directory is removed during upgrade but a running
632
- // session still has the old CLAUDE_PLUGIN_ROOT in its environment, the
711
+ // session still has the old PLUGIN_ROOT in its environment, the
633
712
  // directory won't exist. Create a symlink so subsequent hook invocations
634
713
  // via run.cjs resolve correctly.
635
- const pluginRootEnv = process.env.CLAUDE_PLUGIN_ROOT?.replace(/[\/\\]+$/, ''); // strip trailing separators
714
+ const pluginRootEnv = (process.env.PLUGIN_ROOT || process.env.CLAUDE_PLUGIN_ROOT || '')
715
+ .replace(/[\/\\]+$/, ''); // strip trailing separators
636
716
  if (pluginRootEnv && !existsSync(pluginRootEnv)) {
637
717
  const pluginRootVersion = basename(pluginRootEnv);
638
718
  if (/^\d+\.\d+\.\d+/.test(pluginRootVersion) && versions.length > 0) {
@@ -667,7 +747,7 @@ ${cleanContent}
667
747
 
668
748
  // Send session-start notification (non-blocking, fire-and-forget)
669
749
  try {
670
- const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT;
750
+ const pluginRoot = process.env.PLUGIN_ROOT || process.env.CLAUDE_PLUGIN_ROOT;
671
751
  if (pluginRoot) {
672
752
  const { notify } = await import(pathToFileURL(join(pluginRoot, 'dist', 'notifications', 'index.js')).href);
673
753
  // Fire and forget - don't await, don't block session start
@@ -697,7 +777,7 @@ ${cleanContent}
697
777
  continue: true,
698
778
  hookSpecificOutput: {
699
779
  hookEventName: 'SessionStart',
700
- additionalContext: messages.join('\n')
780
+ additionalContext: buildSessionStartAdditionalContext(messages)
701
781
  }
702
782
  }));
703
783
  } else {
@@ -115,13 +115,14 @@ ensure_local_omc_git_exclude() {
115
115
 
116
116
  cat >> "$exclude_path" <<'EOF'
117
117
  # BEGIN OMC local artifacts
118
- .omc/*
119
- !.omc/skills/
120
- !.omc/skills/**
118
+ !.omcp/
119
+ .omcp/*
120
+ !.omcp/skills/
121
+ !.omcp/skills/**
121
122
  # END OMC local artifacts
122
123
  EOF
123
124
 
124
- echo "Configured git exclude for local .omc artifacts (preserving .omc/skills/)"
125
+ echo "Configured git exclude for local .omcp artifacts (preserving .omcp/skills/)"
125
126
  }
126
127
 
127
128
  # Determine target path