commandmate 0.11.4 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (591) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +395 -303
  3. package/.next/app-path-routes-manifest.json +31 -22
  4. package/.next/build-manifest.json +5 -5
  5. package/.next/prerender-manifest.json +12 -12
  6. package/.next/react-loadable-manifest.json +8 -6
  7. package/.next/required-server-files.json +1 -1
  8. package/.next/routes-manifest.json +66 -0
  9. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  10. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/app/update/route_client-reference-manifest.js +1 -1
  12. package/.next/server/app/api/app/update-check/route.js +1 -1
  13. package/.next/server/app/api/app/update-check/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/assistant/conversation/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/assistant/current-output/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/assistant/messages/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/assistant/session/route_client-reference-manifest.js +1 -1
  18. package/.next/server/app/api/assistant/start/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/assistant/terminal/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/assistant/tools/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/auth/login/route_client-reference-manifest.js +1 -1
  22. package/.next/server/app/api/auth/logout/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/auth/status/route_client-reference-manifest.js +1 -1
  24. package/.next/server/app/api/daily-summary/route.js +1 -1
  25. package/.next/server/app/api/daily-summary/route.js.nft.json +1 -1
  26. package/.next/server/app/api/daily-summary/route_client-reference-manifest.js +1 -1
  27. package/.next/server/app/api/daily-summary/status/route.js +1 -1
  28. package/.next/server/app/api/daily-summary/status/route.js.nft.json +1 -1
  29. package/.next/server/app/api/daily-summary/status/route_client-reference-manifest.js +1 -1
  30. package/.next/server/app/api/external-apps/[id]/health/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/external-apps/[id]/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/external-apps/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/hooks/claude-done/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/ollama/models/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/api/push/subscriptions/route.js +1 -1
  36. package/.next/server/app/api/push/subscriptions/route_client-reference-manifest.js +1 -1
  37. package/.next/server/app/api/push/vapid/route_client-reference-manifest.js +1 -1
  38. package/.next/server/app/api/repositories/[id]/route_client-reference-manifest.js +1 -1
  39. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route.js +1 -1
  40. package/.next/server/app/api/repositories/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  41. package/.next/server/app/api/repositories/[id]/todos/route.js +1 -1
  42. package/.next/server/app/api/repositories/[id]/todos/route_client-reference-manifest.js +1 -1
  43. package/.next/server/app/api/repositories/clone/[jobId]/route_client-reference-manifest.js +1 -1
  44. package/.next/server/app/api/repositories/clone/route_client-reference-manifest.js +1 -1
  45. package/.next/server/app/api/repositories/excluded/route_client-reference-manifest.js +1 -1
  46. package/.next/server/app/api/repositories/restore/route_client-reference-manifest.js +1 -1
  47. package/.next/server/app/api/repositories/route_client-reference-manifest.js +1 -1
  48. package/.next/server/app/api/repositories/scan/route_client-reference-manifest.js +1 -1
  49. package/.next/server/app/api/repositories/sync/route_client-reference-manifest.js +1 -1
  50. package/.next/server/app/api/sidebar/group-order/route_client-reference-manifest.js +1 -1
  51. package/.next/server/app/api/skills/[id]/route.js +1 -0
  52. package/.next/server/app/api/skills/[id]/route.js.nft.json +1 -0
  53. package/.next/server/app/api/skills/[id]/route_client-reference-manifest.js +1 -0
  54. package/.next/server/app/api/skills/route.js +1 -0
  55. package/.next/server/app/api/skills/route.js.nft.json +1 -0
  56. package/.next/server/app/api/skills/route_client-reference-manifest.js +1 -0
  57. package/.next/server/app/api/slash-commands/route_client-reference-manifest.js +1 -1
  58. package/.next/server/app/api/templates/[id]/route_client-reference-manifest.js +1 -1
  59. package/.next/server/app/api/templates/route_client-reference-manifest.js +1 -1
  60. package/.next/server/app/api/todos/route.js +1 -1
  61. package/.next/server/app/api/todos/route_client-reference-manifest.js +1 -1
  62. package/.next/server/app/api/worktrees/[id]/auto-yes/route_client-reference-manifest.js +1 -1
  63. package/.next/server/app/api/worktrees/[id]/capture/route_client-reference-manifest.js +1 -1
  64. package/.next/server/app/api/worktrees/[id]/cli-tool/route.js +1 -1
  65. package/.next/server/app/api/worktrees/[id]/cli-tool/route_client-reference-manifest.js +1 -1
  66. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route.js +1 -1
  67. package/.next/server/app/api/worktrees/[id]/cmate/schedules/route_client-reference-manifest.js +1 -1
  68. package/.next/server/app/api/worktrees/[id]/current-output/route_client-reference-manifest.js +1 -1
  69. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route.js +1 -1
  70. package/.next/server/app/api/worktrees/[id]/execution-logs/[logId]/route_client-reference-manifest.js +1 -1
  71. package/.next/server/app/api/worktrees/[id]/execution-logs/route.js +1 -1
  72. package/.next/server/app/api/worktrees/[id]/execution-logs/route_client-reference-manifest.js +1 -1
  73. package/.next/server/app/api/worktrees/[id]/files/[...path]/route_client-reference-manifest.js +1 -1
  74. package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js +1 -1
  75. package/.next/server/app/api/worktrees/[id]/git/branch/create/route.js.nft.json +1 -1
  76. package/.next/server/app/api/worktrees/[id]/git/branch/create/route_client-reference-manifest.js +1 -1
  77. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js +1 -1
  78. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route.js.nft.json +1 -1
  79. package/.next/server/app/api/worktrees/[id]/git/branch/delete/route_client-reference-manifest.js +1 -1
  80. package/.next/server/app/api/worktrees/[id]/git/branches/route.js +1 -1
  81. package/.next/server/app/api/worktrees/[id]/git/branches/route.js.nft.json +1 -1
  82. package/.next/server/app/api/worktrees/[id]/git/branches/route_client-reference-manifest.js +1 -1
  83. package/.next/server/app/api/worktrees/[id]/git/checkout/route.js +1 -1
  84. package/.next/server/app/api/worktrees/[id]/git/checkout/route.js.nft.json +1 -1
  85. package/.next/server/app/api/worktrees/[id]/git/checkout/route_client-reference-manifest.js +1 -1
  86. package/.next/server/app/api/worktrees/[id]/git/commit/route.js +1 -1
  87. package/.next/server/app/api/worktrees/[id]/git/commit/route.js.nft.json +1 -1
  88. package/.next/server/app/api/worktrees/[id]/git/commit/route_client-reference-manifest.js +1 -1
  89. package/.next/server/app/api/worktrees/[id]/git/diff/route.js +1 -1
  90. package/.next/server/app/api/worktrees/[id]/git/diff/route.js.nft.json +1 -1
  91. package/.next/server/app/api/worktrees/[id]/git/diff/route_client-reference-manifest.js +1 -1
  92. package/.next/server/app/api/worktrees/[id]/git/fetch/route.js +1 -1
  93. package/.next/server/app/api/worktrees/[id]/git/fetch/route.js.nft.json +1 -1
  94. package/.next/server/app/api/worktrees/[id]/git/fetch/route_client-reference-manifest.js +1 -1
  95. package/.next/server/app/api/worktrees/[id]/git/log/route.js +1 -1
  96. package/.next/server/app/api/worktrees/[id]/git/log/route.js.nft.json +1 -1
  97. package/.next/server/app/api/worktrees/[id]/git/log/route_client-reference-manifest.js +1 -1
  98. package/.next/server/app/api/worktrees/[id]/git/pull/route.js +1 -1
  99. package/.next/server/app/api/worktrees/[id]/git/pull/route.js.nft.json +1 -1
  100. package/.next/server/app/api/worktrees/[id]/git/pull/route_client-reference-manifest.js +1 -1
  101. package/.next/server/app/api/worktrees/[id]/git/push/route.js +1 -1
  102. package/.next/server/app/api/worktrees/[id]/git/push/route.js.nft.json +1 -1
  103. package/.next/server/app/api/worktrees/[id]/git/push/route_client-reference-manifest.js +1 -1
  104. package/.next/server/app/api/worktrees/[id]/git/reset/route.js +1 -1
  105. package/.next/server/app/api/worktrees/[id]/git/reset/route.js.nft.json +1 -1
  106. package/.next/server/app/api/worktrees/[id]/git/reset/route_client-reference-manifest.js +1 -1
  107. package/.next/server/app/api/worktrees/[id]/git/revert/route.js +1 -1
  108. package/.next/server/app/api/worktrees/[id]/git/revert/route.js.nft.json +1 -1
  109. package/.next/server/app/api/worktrees/[id]/git/revert/route_client-reference-manifest.js +1 -1
  110. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js +1 -1
  111. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route.js.nft.json +1 -1
  112. package/.next/server/app/api/worktrees/[id]/git/show/[commitHash]/route_client-reference-manifest.js +1 -1
  113. package/.next/server/app/api/worktrees/[id]/git/stage/route.js +1 -1
  114. package/.next/server/app/api/worktrees/[id]/git/stage/route.js.nft.json +1 -1
  115. package/.next/server/app/api/worktrees/[id]/git/stage/route_client-reference-manifest.js +1 -1
  116. package/.next/server/app/api/worktrees/[id]/git/staged/route.js +1 -1
  117. package/.next/server/app/api/worktrees/[id]/git/staged/route.js.nft.json +1 -1
  118. package/.next/server/app/api/worktrees/[id]/git/staged/route_client-reference-manifest.js +1 -1
  119. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js +1 -1
  120. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route.js.nft.json +1 -1
  121. package/.next/server/app/api/worktrees/[id]/git/stash/[index]/route_client-reference-manifest.js +1 -1
  122. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js +1 -1
  123. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route.js.nft.json +1 -1
  124. package/.next/server/app/api/worktrees/[id]/git/stash/apply/route_client-reference-manifest.js +1 -1
  125. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js +1 -1
  126. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route.js.nft.json +1 -1
  127. package/.next/server/app/api/worktrees/[id]/git/stash/pop/route_client-reference-manifest.js +1 -1
  128. package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js +1 -1
  129. package/.next/server/app/api/worktrees/[id]/git/stash/push/route.js.nft.json +1 -1
  130. package/.next/server/app/api/worktrees/[id]/git/stash/push/route_client-reference-manifest.js +1 -1
  131. package/.next/server/app/api/worktrees/[id]/git/stash/route.js +1 -1
  132. package/.next/server/app/api/worktrees/[id]/git/stash/route.js.nft.json +1 -1
  133. package/.next/server/app/api/worktrees/[id]/git/stash/route_client-reference-manifest.js +1 -1
  134. package/.next/server/app/api/worktrees/[id]/git/status/route.js +1 -1
  135. package/.next/server/app/api/worktrees/[id]/git/status/route.js.nft.json +1 -1
  136. package/.next/server/app/api/worktrees/[id]/git/status/route_client-reference-manifest.js +1 -1
  137. package/.next/server/app/api/worktrees/[id]/git/unstage/route.js +1 -1
  138. package/.next/server/app/api/worktrees/[id]/git/unstage/route.js.nft.json +1 -1
  139. package/.next/server/app/api/worktrees/[id]/git/unstage/route_client-reference-manifest.js +1 -1
  140. package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js +1 -1
  141. package/.next/server/app/api/worktrees/[id]/git/working-diff/route.js.nft.json +1 -1
  142. package/.next/server/app/api/worktrees/[id]/git/working-diff/route_client-reference-manifest.js +1 -1
  143. package/.next/server/app/api/worktrees/[id]/interrupt/route_client-reference-manifest.js +1 -1
  144. package/.next/server/app/api/worktrees/[id]/kill-session/route_client-reference-manifest.js +1 -1
  145. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route.js +1 -1
  146. package/.next/server/app/api/worktrees/[id]/logs/[filename]/route_client-reference-manifest.js +1 -1
  147. package/.next/server/app/api/worktrees/[id]/logs/route.js +1 -1
  148. package/.next/server/app/api/worktrees/[id]/logs/route_client-reference-manifest.js +1 -1
  149. package/.next/server/app/api/worktrees/[id]/marp-render/route.js +1 -1
  150. package/.next/server/app/api/worktrees/[id]/marp-render/route_client-reference-manifest.js +1 -1
  151. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route.js +1 -1
  152. package/.next/server/app/api/worktrees/[id]/memos/[memoId]/route_client-reference-manifest.js +1 -1
  153. package/.next/server/app/api/worktrees/[id]/memos/route.js +1 -1
  154. package/.next/server/app/api/worktrees/[id]/memos/route_client-reference-manifest.js +1 -1
  155. package/.next/server/app/api/worktrees/[id]/messages/route.js +1 -1
  156. package/.next/server/app/api/worktrees/[id]/messages/route_client-reference-manifest.js +1 -1
  157. package/.next/server/app/api/worktrees/[id]/prompt-response/route_client-reference-manifest.js +1 -1
  158. package/.next/server/app/api/worktrees/[id]/respond/route_client-reference-manifest.js +1 -1
  159. package/.next/server/app/api/worktrees/[id]/route.js +1 -1
  160. package/.next/server/app/api/worktrees/[id]/route.js.nft.json +1 -1
  161. package/.next/server/app/api/worktrees/[id]/route_client-reference-manifest.js +1 -1
  162. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route.js +1 -1
  163. package/.next/server/app/api/worktrees/[id]/schedules/[scheduleId]/route_client-reference-manifest.js +1 -1
  164. package/.next/server/app/api/worktrees/[id]/schedules/active/route.js +1 -1
  165. package/.next/server/app/api/worktrees/[id]/schedules/active/route_client-reference-manifest.js +1 -1
  166. package/.next/server/app/api/worktrees/[id]/schedules/route.js +1 -1
  167. package/.next/server/app/api/worktrees/[id]/schedules/route_client-reference-manifest.js +1 -1
  168. package/.next/server/app/api/worktrees/[id]/search/route_client-reference-manifest.js +1 -1
  169. package/.next/server/app/api/worktrees/[id]/send/route.js +1 -1
  170. package/.next/server/app/api/worktrees/[id]/send/route.js.nft.json +1 -1
  171. package/.next/server/app/api/worktrees/[id]/send/route_client-reference-manifest.js +1 -1
  172. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route.js +1 -0
  173. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route.js.nft.json +1 -0
  174. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/install/route_client-reference-manifest.js +1 -0
  175. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js +1 -0
  176. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route.js.nft.json +1 -0
  177. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/plan/route_client-reference-manifest.js +1 -0
  178. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js +1 -0
  179. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.js.nft.json +1 -0
  180. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall/route_client-reference-manifest.js +1 -0
  181. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js +1 -0
  182. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.js.nft.json +1 -0
  183. package/.next/server/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route_client-reference-manifest.js +1 -0
  184. package/.next/server/app/api/worktrees/[id]/skills/route.js +23 -0
  185. package/.next/server/app/api/worktrees/[id]/skills/route.js.nft.json +1 -0
  186. package/.next/server/app/api/worktrees/[id]/skills/route_client-reference-manifest.js +1 -0
  187. package/.next/server/app/api/worktrees/[id]/slash-commands/route.js +1 -1
  188. package/.next/server/app/api/worktrees/[id]/slash-commands/route_client-reference-manifest.js +1 -1
  189. package/.next/server/app/api/worktrees/[id]/special-keys/route_client-reference-manifest.js +1 -1
  190. package/.next/server/app/api/worktrees/[id]/start-polling/route_client-reference-manifest.js +1 -1
  191. package/.next/server/app/api/worktrees/[id]/terminal/route_client-reference-manifest.js +1 -1
  192. package/.next/server/app/api/worktrees/[id]/timers/history/route.js +1 -1
  193. package/.next/server/app/api/worktrees/[id]/timers/history/route_client-reference-manifest.js +1 -1
  194. package/.next/server/app/api/worktrees/[id]/timers/route_client-reference-manifest.js +1 -1
  195. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route.js +1 -1
  196. package/.next/server/app/api/worktrees/[id]/todos/[todoId]/route_client-reference-manifest.js +1 -1
  197. package/.next/server/app/api/worktrees/[id]/todos/route.js +1 -1
  198. package/.next/server/app/api/worktrees/[id]/todos/route_client-reference-manifest.js +1 -1
  199. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route.js +1 -1
  200. package/.next/server/app/api/worktrees/[id]/tree/[...path]/route_client-reference-manifest.js +1 -1
  201. package/.next/server/app/api/worktrees/[id]/tree/route.js +1 -1
  202. package/.next/server/app/api/worktrees/[id]/tree/route_client-reference-manifest.js +1 -1
  203. package/.next/server/app/api/worktrees/[id]/upload/[...path]/route_client-reference-manifest.js +1 -1
  204. package/.next/server/app/api/worktrees/[id]/viewed/route.js +1 -1
  205. package/.next/server/app/api/worktrees/[id]/viewed/route_client-reference-manifest.js +1 -1
  206. package/.next/server/app/api/worktrees/route_client-reference-manifest.js +1 -1
  207. package/.next/server/app/chat/page.js +2 -2
  208. package/.next/server/app/chat/page.js.nft.json +1 -1
  209. package/.next/server/app/chat/page_client-reference-manifest.js +1 -1
  210. package/.next/server/app/login/page.js.nft.json +1 -1
  211. package/.next/server/app/login/page_client-reference-manifest.js +1 -1
  212. package/.next/server/app/manifest.webmanifest/route_client-reference-manifest.js +1 -1
  213. package/.next/server/app/more/page.js +2 -2
  214. package/.next/server/app/more/page.js.nft.json +1 -1
  215. package/.next/server/app/more/page_client-reference-manifest.js +1 -1
  216. package/.next/server/app/offline/page.js.nft.json +1 -1
  217. package/.next/server/app/offline/page_client-reference-manifest.js +1 -1
  218. package/.next/server/app/page.js +1 -1
  219. package/.next/server/app/page.js.nft.json +1 -1
  220. package/.next/server/app/page_client-reference-manifest.js +1 -1
  221. package/.next/server/app/proxy/[...path]/route_client-reference-manifest.js +1 -1
  222. package/.next/server/app/repositories/page.js +1 -1
  223. package/.next/server/app/repositories/page.js.nft.json +1 -1
  224. package/.next/server/app/repositories/page_client-reference-manifest.js +1 -1
  225. package/.next/server/app/review/page.js +1 -1
  226. package/.next/server/app/review/page.js.nft.json +1 -1
  227. package/.next/server/app/review/page_client-reference-manifest.js +1 -1
  228. package/.next/server/app/sessions/page.js +1 -1
  229. package/.next/server/app/sessions/page.js.nft.json +1 -1
  230. package/.next/server/app/sessions/page_client-reference-manifest.js +1 -1
  231. package/.next/server/app/skills/[skillId]/page.js +2 -0
  232. package/.next/server/app/skills/[skillId]/page.js.nft.json +1 -0
  233. package/.next/server/app/skills/[skillId]/page_client-reference-manifest.js +1 -0
  234. package/.next/server/app/skills/page.js +2 -0
  235. package/.next/server/app/skills/page.js.nft.json +1 -0
  236. package/.next/server/app/skills/page_client-reference-manifest.js +1 -0
  237. package/.next/server/app/worktrees/[id]/files/[...path]/page.js +2 -2
  238. package/.next/server/app/worktrees/[id]/files/[...path]/page.js.nft.json +1 -1
  239. package/.next/server/app/worktrees/[id]/files/[...path]/page_client-reference-manifest.js +1 -1
  240. package/.next/server/app/worktrees/[id]/page.js +9 -9
  241. package/.next/server/app/worktrees/[id]/page.js.nft.json +1 -1
  242. package/.next/server/app/worktrees/[id]/page_client-reference-manifest.js +1 -1
  243. package/.next/server/app/worktrees/[id]/terminal/page.js +3 -3
  244. package/.next/server/app/worktrees/[id]/terminal/page.js.nft.json +1 -1
  245. package/.next/server/app/worktrees/[id]/terminal/page_client-reference-manifest.js +1 -1
  246. package/.next/server/app-paths-manifest.json +31 -22
  247. package/.next/server/chunks/1117.js +1 -1
  248. package/.next/server/chunks/120.js +1 -0
  249. package/.next/server/chunks/1808.js +1 -0
  250. package/.next/server/chunks/186.js +1 -0
  251. package/.next/server/chunks/2119.js +1 -1
  252. package/.next/server/chunks/22.js +1 -0
  253. package/.next/server/chunks/2328.js +1 -0
  254. package/.next/server/chunks/2445.js +1 -1
  255. package/.next/server/chunks/3042.js +2 -0
  256. package/.next/server/chunks/3543.js +1 -1
  257. package/.next/server/chunks/3708.js +1 -0
  258. package/.next/server/chunks/3945.js +1 -1
  259. package/.next/server/chunks/5064.js +1 -0
  260. package/.next/server/chunks/5226.js +28 -0
  261. package/.next/server/chunks/5306.js +2 -0
  262. package/.next/server/chunks/5312.js +1 -0
  263. package/.next/server/chunks/5326.js +1 -0
  264. package/.next/server/chunks/5381.js +1 -1
  265. package/.next/server/chunks/5456.js +1 -0
  266. package/.next/server/chunks/5571.js +1 -1
  267. package/.next/server/chunks/5959.js +2 -2
  268. package/.next/server/chunks/6065.js +1 -0
  269. package/.next/server/chunks/6130.js +1 -0
  270. package/.next/server/chunks/6285.js +1 -1
  271. package/.next/server/chunks/646.js +6 -6
  272. package/.next/server/chunks/{9968.js → 7587.js} +1 -1
  273. package/.next/server/chunks/8584.js +1 -0
  274. package/.next/server/chunks/8681.js +1 -1
  275. package/.next/server/chunks/8807.js +950 -804
  276. package/.next/server/chunks/9123.js +1 -1
  277. package/.next/server/middleware-build-manifest.js +1 -1
  278. package/.next/server/middleware-manifest.json +5 -5
  279. package/.next/server/middleware-react-loadable-manifest.js +1 -1
  280. package/.next/server/pages/500.html +1 -1
  281. package/.next/server/server-reference-manifest.json +1 -1
  282. package/.next/static/D-aoE4gWfuCUN0GqEPIX3/_buildManifest.js +1 -0
  283. package/.next/static/chunks/1668-7484081c45a44f89.js +1 -0
  284. package/.next/static/chunks/3418-7e47651340d940b0.js +1 -0
  285. package/.next/static/chunks/4027-0c529b322be7d4d8.js +1 -0
  286. package/.next/static/chunks/{4560-64b1461fd996127a.js → 4560-04e5aebcab96bfa1.js} +1 -1
  287. package/.next/static/chunks/6007-de36119357dcd418.js +1 -0
  288. package/.next/static/chunks/{6488-76295bf0184b101f.js → 6488-e257111ca7389d05.js} +1 -1
  289. package/.next/static/chunks/{8965-872d8de254196cec.js → 6497-dc26c6c6b0b15adf.js} +1 -1
  290. package/.next/static/chunks/790-d8e6acd26e03679c.js +1 -0
  291. package/.next/static/chunks/8361.4bf062be2d2962f4.js +1 -0
  292. package/.next/static/chunks/app/api/app/update/route-56dad0523d3c4a92.js +1 -0
  293. package/.next/static/chunks/app/api/app/update-check/route-56dad0523d3c4a92.js +1 -0
  294. package/.next/static/chunks/app/api/assistant/conversation/route-56dad0523d3c4a92.js +1 -0
  295. package/.next/static/chunks/app/api/assistant/current-output/route-56dad0523d3c4a92.js +1 -0
  296. package/.next/static/chunks/app/api/assistant/messages/route-56dad0523d3c4a92.js +1 -0
  297. package/.next/static/chunks/app/api/assistant/session/route-56dad0523d3c4a92.js +1 -0
  298. package/.next/static/chunks/app/api/assistant/start/route-56dad0523d3c4a92.js +1 -0
  299. package/.next/static/chunks/app/api/assistant/terminal/route-56dad0523d3c4a92.js +1 -0
  300. package/.next/static/chunks/app/api/assistant/tools/route-56dad0523d3c4a92.js +1 -0
  301. package/.next/static/chunks/app/api/auth/login/route-56dad0523d3c4a92.js +1 -0
  302. package/.next/static/chunks/app/api/auth/logout/route-56dad0523d3c4a92.js +1 -0
  303. package/.next/static/chunks/app/api/auth/status/route-56dad0523d3c4a92.js +1 -0
  304. package/.next/static/chunks/app/api/daily-summary/route-56dad0523d3c4a92.js +1 -0
  305. package/.next/static/chunks/app/api/daily-summary/status/route-56dad0523d3c4a92.js +1 -0
  306. package/.next/static/chunks/app/api/external-apps/[id]/health/route-56dad0523d3c4a92.js +1 -0
  307. package/.next/static/chunks/app/api/external-apps/[id]/route-56dad0523d3c4a92.js +1 -0
  308. package/.next/static/chunks/app/api/external-apps/route-56dad0523d3c4a92.js +1 -0
  309. package/.next/static/chunks/app/api/hooks/claude-done/route-56dad0523d3c4a92.js +1 -0
  310. package/.next/static/chunks/app/api/ollama/models/route-56dad0523d3c4a92.js +1 -0
  311. package/.next/static/chunks/app/api/push/subscriptions/route-56dad0523d3c4a92.js +1 -0
  312. package/.next/static/chunks/app/api/push/vapid/route-56dad0523d3c4a92.js +1 -0
  313. package/.next/static/chunks/app/api/repositories/[id]/route-56dad0523d3c4a92.js +1 -0
  314. package/.next/static/chunks/app/api/repositories/[id]/todos/[todoId]/route-56dad0523d3c4a92.js +1 -0
  315. package/.next/static/chunks/app/api/repositories/[id]/todos/route-56dad0523d3c4a92.js +1 -0
  316. package/.next/static/chunks/app/api/repositories/clone/[jobId]/route-56dad0523d3c4a92.js +1 -0
  317. package/.next/static/chunks/app/api/repositories/clone/route-56dad0523d3c4a92.js +1 -0
  318. package/.next/static/chunks/app/api/repositories/excluded/route-56dad0523d3c4a92.js +1 -0
  319. package/.next/static/chunks/app/api/repositories/restore/route-56dad0523d3c4a92.js +1 -0
  320. package/.next/static/chunks/app/api/repositories/route-56dad0523d3c4a92.js +1 -0
  321. package/.next/static/chunks/app/api/repositories/scan/route-56dad0523d3c4a92.js +1 -0
  322. package/.next/static/chunks/app/api/repositories/sync/route-56dad0523d3c4a92.js +1 -0
  323. package/.next/static/chunks/app/api/sidebar/group-order/route-56dad0523d3c4a92.js +1 -0
  324. package/.next/static/chunks/app/api/skills/[id]/route-56dad0523d3c4a92.js +1 -0
  325. package/.next/static/chunks/app/api/skills/route-56dad0523d3c4a92.js +1 -0
  326. package/.next/static/chunks/app/api/slash-commands/route-56dad0523d3c4a92.js +1 -0
  327. package/.next/static/chunks/app/api/templates/[id]/route-56dad0523d3c4a92.js +1 -0
  328. package/.next/static/chunks/app/api/templates/route-56dad0523d3c4a92.js +1 -0
  329. package/.next/static/chunks/app/api/todos/route-56dad0523d3c4a92.js +1 -0
  330. package/.next/static/chunks/app/api/worktrees/[id]/auto-yes/route-56dad0523d3c4a92.js +1 -0
  331. package/.next/static/chunks/app/api/worktrees/[id]/capture/route-56dad0523d3c4a92.js +1 -0
  332. package/.next/static/chunks/app/api/worktrees/[id]/cli-tool/route-56dad0523d3c4a92.js +1 -0
  333. package/.next/static/chunks/app/api/worktrees/[id]/cmate/schedules/route-56dad0523d3c4a92.js +1 -0
  334. package/.next/static/chunks/app/api/worktrees/[id]/current-output/route-56dad0523d3c4a92.js +1 -0
  335. package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/[logId]/route-56dad0523d3c4a92.js +1 -0
  336. package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/route-56dad0523d3c4a92.js +1 -0
  337. package/.next/static/chunks/app/api/worktrees/[id]/files/[...path]/route-56dad0523d3c4a92.js +1 -0
  338. package/.next/static/chunks/app/api/worktrees/[id]/git/branch/create/route-56dad0523d3c4a92.js +1 -0
  339. package/.next/static/chunks/app/api/worktrees/[id]/git/branch/delete/route-56dad0523d3c4a92.js +1 -0
  340. package/.next/static/chunks/app/api/worktrees/[id]/git/branches/route-56dad0523d3c4a92.js +1 -0
  341. package/.next/static/chunks/app/api/worktrees/[id]/git/checkout/route-56dad0523d3c4a92.js +1 -0
  342. package/.next/static/chunks/app/api/worktrees/[id]/git/commit/route-56dad0523d3c4a92.js +1 -0
  343. package/.next/static/chunks/app/api/worktrees/[id]/git/diff/route-56dad0523d3c4a92.js +1 -0
  344. package/.next/static/chunks/app/api/worktrees/[id]/git/fetch/route-56dad0523d3c4a92.js +1 -0
  345. package/.next/static/chunks/app/api/worktrees/[id]/git/log/route-56dad0523d3c4a92.js +1 -0
  346. package/.next/static/chunks/app/api/worktrees/[id]/git/pull/route-56dad0523d3c4a92.js +1 -0
  347. package/.next/static/chunks/app/api/worktrees/[id]/git/push/route-56dad0523d3c4a92.js +1 -0
  348. package/.next/static/chunks/app/api/worktrees/[id]/git/reset/route-56dad0523d3c4a92.js +1 -0
  349. package/.next/static/chunks/app/api/worktrees/[id]/git/revert/route-56dad0523d3c4a92.js +1 -0
  350. package/.next/static/chunks/app/api/worktrees/[id]/git/show/[commitHash]/route-56dad0523d3c4a92.js +1 -0
  351. package/.next/static/chunks/app/api/worktrees/[id]/git/stage/route-56dad0523d3c4a92.js +1 -0
  352. package/.next/static/chunks/app/api/worktrees/[id]/git/staged/route-56dad0523d3c4a92.js +1 -0
  353. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/[index]/route-56dad0523d3c4a92.js +1 -0
  354. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/apply/route-56dad0523d3c4a92.js +1 -0
  355. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/pop/route-56dad0523d3c4a92.js +1 -0
  356. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/push/route-56dad0523d3c4a92.js +1 -0
  357. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/route-56dad0523d3c4a92.js +1 -0
  358. package/.next/static/chunks/app/api/worktrees/[id]/git/status/route-56dad0523d3c4a92.js +1 -0
  359. package/.next/static/chunks/app/api/worktrees/[id]/git/unstage/route-56dad0523d3c4a92.js +1 -0
  360. package/.next/static/chunks/app/api/worktrees/[id]/git/working-diff/route-56dad0523d3c4a92.js +1 -0
  361. package/.next/static/chunks/app/api/worktrees/[id]/interrupt/route-56dad0523d3c4a92.js +1 -0
  362. package/.next/static/chunks/app/api/worktrees/[id]/kill-session/route-56dad0523d3c4a92.js +1 -0
  363. package/.next/static/chunks/app/api/worktrees/[id]/logs/[filename]/route-56dad0523d3c4a92.js +1 -0
  364. package/.next/static/chunks/app/api/worktrees/[id]/logs/route-56dad0523d3c4a92.js +1 -0
  365. package/.next/static/chunks/app/api/worktrees/[id]/marp-render/route-56dad0523d3c4a92.js +1 -0
  366. package/.next/static/chunks/app/api/worktrees/[id]/memos/[memoId]/route-56dad0523d3c4a92.js +1 -0
  367. package/.next/static/chunks/app/api/worktrees/[id]/memos/route-56dad0523d3c4a92.js +1 -0
  368. package/.next/static/chunks/app/api/worktrees/[id]/messages/route-56dad0523d3c4a92.js +1 -0
  369. package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/route-56dad0523d3c4a92.js +1 -0
  370. package/.next/static/chunks/app/api/worktrees/[id]/respond/route-56dad0523d3c4a92.js +1 -0
  371. package/.next/static/chunks/app/api/worktrees/[id]/route-56dad0523d3c4a92.js +1 -0
  372. package/.next/static/chunks/app/api/worktrees/[id]/schedules/[scheduleId]/route-56dad0523d3c4a92.js +1 -0
  373. package/.next/static/chunks/app/api/worktrees/[id]/schedules/active/route-56dad0523d3c4a92.js +1 -0
  374. package/.next/static/chunks/app/api/worktrees/[id]/schedules/route-56dad0523d3c4a92.js +1 -0
  375. package/.next/static/chunks/app/api/worktrees/[id]/search/route-56dad0523d3c4a92.js +1 -0
  376. package/.next/static/chunks/app/api/worktrees/[id]/send/route-56dad0523d3c4a92.js +1 -0
  377. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/install/route-56dad0523d3c4a92.js +1 -0
  378. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/plan/route-56dad0523d3c4a92.js +1 -0
  379. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall/route-56dad0523d3c4a92.js +1 -0
  380. package/.next/static/chunks/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route-56dad0523d3c4a92.js +1 -0
  381. package/.next/static/chunks/app/api/worktrees/[id]/skills/route-56dad0523d3c4a92.js +1 -0
  382. package/.next/static/chunks/app/api/worktrees/[id]/slash-commands/route-56dad0523d3c4a92.js +1 -0
  383. package/.next/static/chunks/app/api/worktrees/[id]/special-keys/route-56dad0523d3c4a92.js +1 -0
  384. package/.next/static/chunks/app/api/worktrees/[id]/start-polling/route-56dad0523d3c4a92.js +1 -0
  385. package/.next/static/chunks/app/api/worktrees/[id]/terminal/route-56dad0523d3c4a92.js +1 -0
  386. package/.next/static/chunks/app/api/worktrees/[id]/timers/history/route-56dad0523d3c4a92.js +1 -0
  387. package/.next/static/chunks/app/api/worktrees/[id]/timers/route-56dad0523d3c4a92.js +1 -0
  388. package/.next/static/chunks/app/api/worktrees/[id]/todos/[todoId]/route-56dad0523d3c4a92.js +1 -0
  389. package/.next/static/chunks/app/api/worktrees/[id]/todos/route-56dad0523d3c4a92.js +1 -0
  390. package/.next/static/chunks/app/api/worktrees/[id]/tree/[...path]/route-56dad0523d3c4a92.js +1 -0
  391. package/.next/static/chunks/app/api/worktrees/[id]/tree/route-56dad0523d3c4a92.js +1 -0
  392. package/.next/static/chunks/app/api/worktrees/[id]/upload/[...path]/route-56dad0523d3c4a92.js +1 -0
  393. package/.next/static/chunks/app/api/worktrees/[id]/viewed/route-56dad0523d3c4a92.js +1 -0
  394. package/.next/static/chunks/app/api/worktrees/route-56dad0523d3c4a92.js +1 -0
  395. package/.next/static/chunks/app/chat/{page-9ed2ffd98eb4ae18.js → page-9cf4ba62e21d9074.js} +1 -1
  396. package/.next/static/chunks/app/manifest.webmanifest/route-56dad0523d3c4a92.js +1 -0
  397. package/.next/static/chunks/app/more/{page-a496425bba427b48.js → page-082d4ae496f9a36e.js} +1 -1
  398. package/.next/static/chunks/app/{page-15bfd76bcf65842d.js → page-af457ca5876ed616.js} +1 -1
  399. package/.next/static/chunks/app/proxy/[...path]/route-56dad0523d3c4a92.js +1 -0
  400. package/.next/static/chunks/app/repositories/{page-d214522ab8792ce7.js → page-75f0d70452c6b6c0.js} +1 -1
  401. package/.next/static/chunks/app/review/{page-1dadf0b5d7129598.js → page-f431d630097c2e85.js} +1 -1
  402. package/.next/static/chunks/app/sessions/{page-96f007d986c5f327.js → page-20f07a99db64d2ca.js} +1 -1
  403. package/.next/static/chunks/app/skills/[skillId]/page-68ed5e9186efe56d.js +1 -0
  404. package/.next/static/chunks/app/skills/page-46242c428ee8bccf.js +1 -0
  405. package/.next/static/chunks/app/worktrees/[id]/page-bf811e793052c917.js +1 -0
  406. package/.next/static/chunks/app/worktrees/[id]/terminal/page-a75fe180a7233b2b.js +1 -0
  407. package/.next/static/chunks/webpack-0f9275e279c058eb.js +1 -0
  408. package/.next/static/css/b4bdb1f3457fe9a7.css +1 -0
  409. package/.next/trace +11 -10
  410. package/.next/types/app/api/skills/[id]/route.ts +347 -0
  411. package/.next/types/app/api/skills/route.ts +347 -0
  412. package/.next/types/app/api/worktrees/[id]/skills/[skillId]/install/route.ts +347 -0
  413. package/.next/types/app/api/worktrees/[id]/skills/[skillId]/plan/route.ts +347 -0
  414. package/.next/types/app/api/worktrees/[id]/skills/[skillId]/uninstall/route.ts +347 -0
  415. package/.next/types/app/api/worktrees/[id]/skills/[skillId]/uninstall-plan/route.ts +347 -0
  416. package/.next/types/app/api/worktrees/[id]/skills/route.ts +347 -0
  417. package/.next/types/app/skills/[skillId]/page.ts +84 -0
  418. package/.next/types/app/skills/page.ts +84 -0
  419. package/.next/types/routes.d.ts +11 -2
  420. package/.next/types/validator.ts +81 -0
  421. package/dist/cli/commands/skill-format.d.ts +28 -0
  422. package/dist/cli/commands/skill-format.d.ts.map +1 -0
  423. package/dist/cli/commands/skill-format.js +163 -0
  424. package/dist/cli/commands/skill-guards.d.ts +53 -0
  425. package/dist/cli/commands/skill-guards.d.ts.map +1 -0
  426. package/dist/cli/commands/skill-guards.js +188 -0
  427. package/dist/cli/commands/skill.d.ts +24 -0
  428. package/dist/cli/commands/skill.d.ts.map +1 -0
  429. package/dist/cli/commands/skill.js +365 -0
  430. package/dist/cli/docs/agent-operations.d.ts +1 -1
  431. package/dist/cli/docs/agent-operations.d.ts.map +1 -1
  432. package/dist/cli/docs/agent-operations.js +36 -0
  433. package/dist/cli/program.d.ts.map +1 -1
  434. package/dist/cli/program.js +11 -0
  435. package/dist/cli/types/api-responses.d.ts +215 -0
  436. package/dist/cli/types/api-responses.d.ts.map +1 -1
  437. package/dist/cli/types/index.d.ts +60 -0
  438. package/dist/cli/types/index.d.ts.map +1 -1
  439. package/dist/cli/types/index.js +23 -1
  440. package/dist/cli/utils/api-client.d.ts +19 -1
  441. package/dist/cli/utils/api-client.d.ts.map +1 -1
  442. package/dist/cli/utils/api-client.js +41 -4
  443. package/dist/server/server.js +57 -0
  444. package/dist/server/src/config/activity-bar-config.js +2 -0
  445. package/dist/server/src/config/git-status-config.js +83 -0
  446. package/dist/server/src/config/skill-security-config.js +139 -0
  447. package/dist/server/src/lib/db/migrations/index.js +8 -0
  448. package/dist/server/src/lib/db/migrations/runner.js +1 -1
  449. package/dist/server/src/lib/db/migrations/v44-skill-operations.js +81 -0
  450. package/dist/server/src/lib/db/migrations/v45-skill-installations.js +59 -0
  451. package/dist/server/src/lib/db/migrations/v46-skill-installations-cascade.js +107 -0
  452. package/dist/server/src/lib/db/migrations/v47-skill-installations-roots.js +70 -0
  453. package/dist/server/src/lib/db/worktree-db.js +9 -4
  454. package/dist/server/src/lib/git/git-errors.js +336 -0
  455. package/dist/server/src/lib/git/git-exec.js +285 -0
  456. package/dist/server/src/lib/skills/compatibility.js +194 -0
  457. package/dist/server/src/lib/skills/constants.js +252 -0
  458. package/dist/server/src/lib/skills/errors.js +82 -0
  459. package/dist/server/src/lib/skills/index.js +91 -0
  460. package/dist/server/src/lib/skills/install-apply.js +670 -0
  461. package/dist/server/src/lib/skills/install-plan.js +582 -0
  462. package/dist/server/src/lib/skills/installed-state.js +127 -0
  463. package/dist/server/src/lib/skills/integrity.js +225 -0
  464. package/dist/server/src/lib/skills/json-schema.js +365 -0
  465. package/dist/server/src/lib/skills/operation-audit.js +120 -0
  466. package/dist/server/src/lib/skills/operation-journal.js +286 -0
  467. package/dist/server/src/lib/skills/operation-lock.js +339 -0
  468. package/dist/server/src/lib/skills/operation-reconciler.js +107 -0
  469. package/dist/server/src/lib/skills/operation-store.js +153 -0
  470. package/dist/server/src/lib/skills/package-reader.js +495 -0
  471. package/dist/server/src/lib/skills/package-validator.js +451 -0
  472. package/dist/server/src/lib/skills/preview-diff.js +627 -0
  473. package/dist/server/src/lib/skills/safe-yaml.js +593 -0
  474. package/dist/server/src/lib/skills/schema.js +1248 -0
  475. package/dist/server/src/lib/skills/semver.js +193 -0
  476. package/dist/server/src/lib/skills/snapshot-store.js +334 -0
  477. package/dist/server/src/lib/skills/startup-reconcile.js +138 -0
  478. package/dist/server/src/lib/skills/uninstall-apply.js +495 -0
  479. package/dist/server/src/lib/skills/uninstall-plan.js +479 -0
  480. package/dist/server/src/types/skills.js +17 -0
  481. package/package.json +1 -1
  482. package/.next/server/chunks/129.js +0 -1
  483. package/.next/server/chunks/2478.js +0 -1
  484. package/.next/server/chunks/9886.js +0 -1
  485. package/.next/static/0_lnKsT0DH-MnHhnV5n-l/_buildManifest.js +0 -1
  486. package/.next/static/chunks/3165-87bf884f7f3d15cf.js +0 -1
  487. package/.next/static/chunks/6416.6756b7ad06dd96f7.js +0 -1
  488. package/.next/static/chunks/8676.57260a06f6554e7e.js +0 -1
  489. package/.next/static/chunks/app/api/app/update/route-7536041a7a89616d.js +0 -1
  490. package/.next/static/chunks/app/api/app/update-check/route-7536041a7a89616d.js +0 -1
  491. package/.next/static/chunks/app/api/assistant/conversation/route-7536041a7a89616d.js +0 -1
  492. package/.next/static/chunks/app/api/assistant/current-output/route-7536041a7a89616d.js +0 -1
  493. package/.next/static/chunks/app/api/assistant/messages/route-7536041a7a89616d.js +0 -1
  494. package/.next/static/chunks/app/api/assistant/session/route-7536041a7a89616d.js +0 -1
  495. package/.next/static/chunks/app/api/assistant/start/route-7536041a7a89616d.js +0 -1
  496. package/.next/static/chunks/app/api/assistant/terminal/route-7536041a7a89616d.js +0 -1
  497. package/.next/static/chunks/app/api/assistant/tools/route-7536041a7a89616d.js +0 -1
  498. package/.next/static/chunks/app/api/auth/login/route-7536041a7a89616d.js +0 -1
  499. package/.next/static/chunks/app/api/auth/logout/route-7536041a7a89616d.js +0 -1
  500. package/.next/static/chunks/app/api/auth/status/route-7536041a7a89616d.js +0 -1
  501. package/.next/static/chunks/app/api/daily-summary/route-7536041a7a89616d.js +0 -1
  502. package/.next/static/chunks/app/api/daily-summary/status/route-7536041a7a89616d.js +0 -1
  503. package/.next/static/chunks/app/api/external-apps/[id]/health/route-7536041a7a89616d.js +0 -1
  504. package/.next/static/chunks/app/api/external-apps/[id]/route-7536041a7a89616d.js +0 -1
  505. package/.next/static/chunks/app/api/external-apps/route-7536041a7a89616d.js +0 -1
  506. package/.next/static/chunks/app/api/hooks/claude-done/route-7536041a7a89616d.js +0 -1
  507. package/.next/static/chunks/app/api/ollama/models/route-7536041a7a89616d.js +0 -1
  508. package/.next/static/chunks/app/api/push/subscriptions/route-7536041a7a89616d.js +0 -1
  509. package/.next/static/chunks/app/api/push/vapid/route-7536041a7a89616d.js +0 -1
  510. package/.next/static/chunks/app/api/repositories/[id]/route-7536041a7a89616d.js +0 -1
  511. package/.next/static/chunks/app/api/repositories/[id]/todos/[todoId]/route-7536041a7a89616d.js +0 -1
  512. package/.next/static/chunks/app/api/repositories/[id]/todos/route-7536041a7a89616d.js +0 -1
  513. package/.next/static/chunks/app/api/repositories/clone/[jobId]/route-7536041a7a89616d.js +0 -1
  514. package/.next/static/chunks/app/api/repositories/clone/route-7536041a7a89616d.js +0 -1
  515. package/.next/static/chunks/app/api/repositories/excluded/route-7536041a7a89616d.js +0 -1
  516. package/.next/static/chunks/app/api/repositories/restore/route-7536041a7a89616d.js +0 -1
  517. package/.next/static/chunks/app/api/repositories/route-7536041a7a89616d.js +0 -1
  518. package/.next/static/chunks/app/api/repositories/scan/route-7536041a7a89616d.js +0 -1
  519. package/.next/static/chunks/app/api/repositories/sync/route-7536041a7a89616d.js +0 -1
  520. package/.next/static/chunks/app/api/sidebar/group-order/route-7536041a7a89616d.js +0 -1
  521. package/.next/static/chunks/app/api/slash-commands/route-7536041a7a89616d.js +0 -1
  522. package/.next/static/chunks/app/api/templates/[id]/route-7536041a7a89616d.js +0 -1
  523. package/.next/static/chunks/app/api/templates/route-7536041a7a89616d.js +0 -1
  524. package/.next/static/chunks/app/api/todos/route-7536041a7a89616d.js +0 -1
  525. package/.next/static/chunks/app/api/worktrees/[id]/auto-yes/route-7536041a7a89616d.js +0 -1
  526. package/.next/static/chunks/app/api/worktrees/[id]/capture/route-7536041a7a89616d.js +0 -1
  527. package/.next/static/chunks/app/api/worktrees/[id]/cli-tool/route-7536041a7a89616d.js +0 -1
  528. package/.next/static/chunks/app/api/worktrees/[id]/cmate/schedules/route-7536041a7a89616d.js +0 -1
  529. package/.next/static/chunks/app/api/worktrees/[id]/current-output/route-7536041a7a89616d.js +0 -1
  530. package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/[logId]/route-7536041a7a89616d.js +0 -1
  531. package/.next/static/chunks/app/api/worktrees/[id]/execution-logs/route-7536041a7a89616d.js +0 -1
  532. package/.next/static/chunks/app/api/worktrees/[id]/files/[...path]/route-7536041a7a89616d.js +0 -1
  533. package/.next/static/chunks/app/api/worktrees/[id]/git/branch/create/route-7536041a7a89616d.js +0 -1
  534. package/.next/static/chunks/app/api/worktrees/[id]/git/branch/delete/route-7536041a7a89616d.js +0 -1
  535. package/.next/static/chunks/app/api/worktrees/[id]/git/branches/route-7536041a7a89616d.js +0 -1
  536. package/.next/static/chunks/app/api/worktrees/[id]/git/checkout/route-7536041a7a89616d.js +0 -1
  537. package/.next/static/chunks/app/api/worktrees/[id]/git/commit/route-7536041a7a89616d.js +0 -1
  538. package/.next/static/chunks/app/api/worktrees/[id]/git/diff/route-7536041a7a89616d.js +0 -1
  539. package/.next/static/chunks/app/api/worktrees/[id]/git/fetch/route-7536041a7a89616d.js +0 -1
  540. package/.next/static/chunks/app/api/worktrees/[id]/git/log/route-7536041a7a89616d.js +0 -1
  541. package/.next/static/chunks/app/api/worktrees/[id]/git/pull/route-7536041a7a89616d.js +0 -1
  542. package/.next/static/chunks/app/api/worktrees/[id]/git/push/route-7536041a7a89616d.js +0 -1
  543. package/.next/static/chunks/app/api/worktrees/[id]/git/reset/route-7536041a7a89616d.js +0 -1
  544. package/.next/static/chunks/app/api/worktrees/[id]/git/revert/route-7536041a7a89616d.js +0 -1
  545. package/.next/static/chunks/app/api/worktrees/[id]/git/show/[commitHash]/route-7536041a7a89616d.js +0 -1
  546. package/.next/static/chunks/app/api/worktrees/[id]/git/stage/route-7536041a7a89616d.js +0 -1
  547. package/.next/static/chunks/app/api/worktrees/[id]/git/staged/route-7536041a7a89616d.js +0 -1
  548. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/[index]/route-7536041a7a89616d.js +0 -1
  549. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/apply/route-7536041a7a89616d.js +0 -1
  550. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/pop/route-7536041a7a89616d.js +0 -1
  551. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/push/route-7536041a7a89616d.js +0 -1
  552. package/.next/static/chunks/app/api/worktrees/[id]/git/stash/route-7536041a7a89616d.js +0 -1
  553. package/.next/static/chunks/app/api/worktrees/[id]/git/status/route-7536041a7a89616d.js +0 -1
  554. package/.next/static/chunks/app/api/worktrees/[id]/git/unstage/route-7536041a7a89616d.js +0 -1
  555. package/.next/static/chunks/app/api/worktrees/[id]/git/working-diff/route-7536041a7a89616d.js +0 -1
  556. package/.next/static/chunks/app/api/worktrees/[id]/interrupt/route-7536041a7a89616d.js +0 -1
  557. package/.next/static/chunks/app/api/worktrees/[id]/kill-session/route-7536041a7a89616d.js +0 -1
  558. package/.next/static/chunks/app/api/worktrees/[id]/logs/[filename]/route-7536041a7a89616d.js +0 -1
  559. package/.next/static/chunks/app/api/worktrees/[id]/logs/route-7536041a7a89616d.js +0 -1
  560. package/.next/static/chunks/app/api/worktrees/[id]/marp-render/route-7536041a7a89616d.js +0 -1
  561. package/.next/static/chunks/app/api/worktrees/[id]/memos/[memoId]/route-7536041a7a89616d.js +0 -1
  562. package/.next/static/chunks/app/api/worktrees/[id]/memos/route-7536041a7a89616d.js +0 -1
  563. package/.next/static/chunks/app/api/worktrees/[id]/messages/route-7536041a7a89616d.js +0 -1
  564. package/.next/static/chunks/app/api/worktrees/[id]/prompt-response/route-7536041a7a89616d.js +0 -1
  565. package/.next/static/chunks/app/api/worktrees/[id]/respond/route-7536041a7a89616d.js +0 -1
  566. package/.next/static/chunks/app/api/worktrees/[id]/route-7536041a7a89616d.js +0 -1
  567. package/.next/static/chunks/app/api/worktrees/[id]/schedules/[scheduleId]/route-7536041a7a89616d.js +0 -1
  568. package/.next/static/chunks/app/api/worktrees/[id]/schedules/active/route-7536041a7a89616d.js +0 -1
  569. package/.next/static/chunks/app/api/worktrees/[id]/schedules/route-7536041a7a89616d.js +0 -1
  570. package/.next/static/chunks/app/api/worktrees/[id]/search/route-7536041a7a89616d.js +0 -1
  571. package/.next/static/chunks/app/api/worktrees/[id]/send/route-7536041a7a89616d.js +0 -1
  572. package/.next/static/chunks/app/api/worktrees/[id]/slash-commands/route-7536041a7a89616d.js +0 -1
  573. package/.next/static/chunks/app/api/worktrees/[id]/special-keys/route-7536041a7a89616d.js +0 -1
  574. package/.next/static/chunks/app/api/worktrees/[id]/start-polling/route-7536041a7a89616d.js +0 -1
  575. package/.next/static/chunks/app/api/worktrees/[id]/terminal/route-7536041a7a89616d.js +0 -1
  576. package/.next/static/chunks/app/api/worktrees/[id]/timers/history/route-7536041a7a89616d.js +0 -1
  577. package/.next/static/chunks/app/api/worktrees/[id]/timers/route-7536041a7a89616d.js +0 -1
  578. package/.next/static/chunks/app/api/worktrees/[id]/todos/[todoId]/route-7536041a7a89616d.js +0 -1
  579. package/.next/static/chunks/app/api/worktrees/[id]/todos/route-7536041a7a89616d.js +0 -1
  580. package/.next/static/chunks/app/api/worktrees/[id]/tree/[...path]/route-7536041a7a89616d.js +0 -1
  581. package/.next/static/chunks/app/api/worktrees/[id]/tree/route-7536041a7a89616d.js +0 -1
  582. package/.next/static/chunks/app/api/worktrees/[id]/upload/[...path]/route-7536041a7a89616d.js +0 -1
  583. package/.next/static/chunks/app/api/worktrees/[id]/viewed/route-7536041a7a89616d.js +0 -1
  584. package/.next/static/chunks/app/api/worktrees/route-7536041a7a89616d.js +0 -1
  585. package/.next/static/chunks/app/manifest.webmanifest/route-7536041a7a89616d.js +0 -1
  586. package/.next/static/chunks/app/proxy/[...path]/route-7536041a7a89616d.js +0 -1
  587. package/.next/static/chunks/app/worktrees/[id]/page-9a4ce51e697baac6.js +0 -1
  588. package/.next/static/chunks/app/worktrees/[id]/terminal/page-ed4590b024edd8d6.js +0 -1
  589. package/.next/static/chunks/webpack-2e3739a831868daa.js +0 -1
  590. package/.next/static/css/d7e2e8d1b8d69d36.css +0 -1
  591. /package/.next/static/{0_lnKsT0DH-MnHhnV5n-l → D-aoE4gWfuCUN0GqEPIX3}/_ssgManifest.js +0 -0
@@ -0,0 +1,286 @@
1
+ "use strict";
2
+ /**
3
+ * Operation journal and idempotency for Skill operations (Issue #1234)
4
+ *
5
+ * The journal is the crash-recovery record that lets install/uninstall converge
6
+ * on one answer after a restart. Its central rule is that the **filesystem
7
+ * atomic rename is the commit point**: once an operation reaches FS_COMMITTED,
8
+ * the payload exists and a later DB or index failure must not be reported as a
9
+ * rollback. Such an operation moves to FAILED_RECONCILABLE and is driven
10
+ * forward from the receipt, never backwards.
11
+ *
12
+ * ```text
13
+ * PREPARING ──▶ FS_COMMITTED ──▶ INDEXED ──▶ SUCCEEDED
14
+ * │ │ │
15
+ * └──────────────┴──────────────┴──▶ FAILED_RECONCILABLE ──▶ INDEXED/SUCCEEDED
16
+ * ```
17
+ *
18
+ * The reverse edge out of FAILED_RECONCILABLE is guarded: it is only legal when
19
+ * the entry recorded a filesystem commit. A failure before the commit point is
20
+ * genuinely rolled back and stays terminal.
21
+ *
22
+ * Idempotency keys are bound to actor, operation, target and plan. Replaying a
23
+ * request returns the recorded entry instead of writing the payload twice; the
24
+ * *same* key with a *different* binding is a conflict rather than a silent
25
+ * substitution of someone else's plan.
26
+ *
27
+ * @module lib/skills/operation-journal
28
+ */
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.SKILL_JOURNAL_RETENTION_MS = exports.SkillOperationTransitionError = exports.SKILL_OPERATION_STATES = void 0;
31
+ exports.computeSkillOperationBindingHash = computeSkillOperationBindingHash;
32
+ exports.deriveSkillOperationIdempotencyKey = deriveSkillOperationIdempotencyKey;
33
+ exports.readSkillOperationJournal = readSkillOperationJournal;
34
+ exports.listSkillOperationJournal = listSkillOperationJournal;
35
+ exports.writeSkillOperationJournal = writeSkillOperationJournal;
36
+ exports.deleteSkillOperationJournal = deleteSkillOperationJournal;
37
+ exports.pruneExpiredSkillOperationJournal = pruneExpiredSkillOperationJournal;
38
+ exports.beginSkillOperation = beginSkillOperation;
39
+ exports.transitionSkillOperation = transitionSkillOperation;
40
+ exports.hasSkillFilesystemCommit = hasSkillFilesystemCommit;
41
+ exports.isSkillOperationTerminal = isSkillOperationTerminal;
42
+ const fs_1 = require("fs");
43
+ const path_1 = require("path");
44
+ const crypto_1 = require("crypto");
45
+ const operation_store_1 = require("../../lib/skills/operation-store");
46
+ /**
47
+ * Journal states.
48
+ *
49
+ * Local to this module rather than added to the #1228 contract: these describe
50
+ * CommandMate's internal execution, not the published distribution documents.
51
+ */
52
+ exports.SKILL_OPERATION_STATES = [
53
+ 'PREPARING',
54
+ 'FS_COMMITTED',
55
+ 'INDEXED',
56
+ 'SUCCEEDED',
57
+ 'FAILED_RECONCILABLE',
58
+ ];
59
+ /** Legal forward edges. Anything else is a programming error. */
60
+ const ALLOWED_TRANSITIONS = {
61
+ PREPARING: ['FS_COMMITTED', 'FAILED_RECONCILABLE'],
62
+ FS_COMMITTED: ['INDEXED', 'FAILED_RECONCILABLE'],
63
+ INDEXED: ['SUCCEEDED', 'FAILED_RECONCILABLE'],
64
+ FAILED_RECONCILABLE: ['INDEXED', 'SUCCEEDED', 'FAILED_RECONCILABLE'],
65
+ SUCCEEDED: [],
66
+ };
67
+ /** Raised on an illegal state transition. */
68
+ class SkillOperationTransitionError extends Error {
69
+ from;
70
+ to;
71
+ constructor(from, to, reason) {
72
+ super(`Illegal Skill operation transition ${from} -> ${to}: ${reason}`);
73
+ this.from = from;
74
+ this.to = to;
75
+ this.name = 'SkillOperationTransitionError';
76
+ }
77
+ }
78
+ exports.SkillOperationTransitionError = SkillOperationTransitionError;
79
+ function canonicalJson(value) {
80
+ if (value === null || typeof value !== 'object')
81
+ return JSON.stringify(value) ?? 'null';
82
+ if (Array.isArray(value))
83
+ return `[${value.map(canonicalJson).join(',')}]`;
84
+ const entries = Object.entries(value)
85
+ .filter(([, v]) => v !== undefined)
86
+ .sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
87
+ return `{${entries.map(([k, v]) => `${JSON.stringify(k)}:${canonicalJson(v)}`).join(',')}}`;
88
+ }
89
+ /**
90
+ * Digest of everything an idempotency key is bound to.
91
+ *
92
+ * Two requests may only share a key when they mean the same thing: same actor,
93
+ * same operation, same target and same resolved plan.
94
+ */
95
+ function computeSkillOperationBindingHash(binding) {
96
+ return (0, crypto_1.createHash)('sha256')
97
+ .update(canonicalJson({
98
+ actor: binding.actor,
99
+ operation: binding.operation,
100
+ target: binding.target,
101
+ planHash: binding.planHash,
102
+ }))
103
+ .digest('hex');
104
+ }
105
+ /**
106
+ * Derive an idempotency key when the client did not supply one.
107
+ * Identical requests then collapse onto one operation by construction.
108
+ */
109
+ function deriveSkillOperationIdempotencyKey(binding) {
110
+ return computeSkillOperationBindingHash(binding);
111
+ }
112
+ function getJournalDir(options) {
113
+ return (0, operation_store_1.ensureSkillStateDir)(operation_store_1.SKILL_JOURNAL_DIRNAME, options);
114
+ }
115
+ /** Journal filename. The key is hashed so a client-supplied string never names a file. */
116
+ function getJournalPath(idempotencyKey, options) {
117
+ const digest = (0, crypto_1.createHash)('sha256').update(idempotencyKey).digest('hex');
118
+ return (0, path_1.join)(getJournalDir(options), `${digest}.json`);
119
+ }
120
+ function isJournalEntry(value) {
121
+ if (typeof value !== 'object' || value === null)
122
+ return false;
123
+ const entry = value;
124
+ return (typeof entry.operationId === 'string' &&
125
+ typeof entry.idempotencyKey === 'string' &&
126
+ typeof entry.bindingHash === 'string' &&
127
+ typeof entry.state === 'string' &&
128
+ exports.SKILL_OPERATION_STATES.includes(entry.state));
129
+ }
130
+ /** Read the entry recorded for an idempotency key. */
131
+ function readSkillOperationJournal(idempotencyKey, options = {}) {
132
+ const entry = (0, operation_store_1.readSkillStateFile)(getJournalPath(idempotencyKey, options));
133
+ return isJournalEntry(entry) ? entry : null;
134
+ }
135
+ /** Every entry currently on disk, oldest first. */
136
+ function listSkillOperationJournal(options = {}) {
137
+ const dir = getJournalDir(options);
138
+ const entries = [];
139
+ for (const name of (0, fs_1.readdirSync)(dir)) {
140
+ if (!name.endsWith('.json'))
141
+ continue;
142
+ const parsed = (0, operation_store_1.readSkillStateFile)((0, path_1.join)(dir, name));
143
+ if (isJournalEntry(parsed))
144
+ entries.push(parsed);
145
+ }
146
+ return entries.sort((a, b) => a.createdAt - b.createdAt);
147
+ }
148
+ /** Persist an entry. */
149
+ function writeSkillOperationJournal(entry, options = {}) {
150
+ (0, operation_store_1.writeSkillStateFile)(getJournalPath(entry.idempotencyKey, options), entry);
151
+ }
152
+ /** Drop an entry once it is past its retention window. */
153
+ function deleteSkillOperationJournal(idempotencyKey, options = {}) {
154
+ try {
155
+ (0, fs_1.unlinkSync)(getJournalPath(idempotencyKey, options));
156
+ }
157
+ catch {
158
+ // Already collected.
159
+ }
160
+ }
161
+ /**
162
+ * How long a terminal journal entry is kept before it becomes collectable.
163
+ *
164
+ * The journal is the crash-recovery and idempotency record, not the audit trail
165
+ * (that lives in the append-only `skill_operations` table). A terminal entry is
166
+ * only still useful for the window during which a client might retry the same
167
+ * idempotency key; past it, the entry is pure growth. Seven days comfortably
168
+ * covers realistic retry and support windows while bounding the directory to the
169
+ * operations of one window rather than of all time (Issue #1428).
170
+ */
171
+ exports.SKILL_JOURNAL_RETENTION_MS = 7 * 24 * 60 * 60 * 1000;
172
+ /**
173
+ * Collect terminal journal entries whose retention window has elapsed.
174
+ *
175
+ * Only {@link isSkillOperationTerminal} entries are eligible: SUCCEEDED, and a
176
+ * pre-commit FAILED_RECONCILABLE that rolled back cleanly. A FAILED_RECONCILABLE
177
+ * that *did* commit to the filesystem is non-terminal — it still owes the
178
+ * reconciler an index write — and is never pruned, so a genuine
179
+ * payload-on-disk/no-index inconsistency is not silently discarded. Retention is
180
+ * measured from `updatedAt`, which for a terminal entry is the moment it reached
181
+ * its terminal state and never moves again.
182
+ *
183
+ * Uniform retention across both terminal outcomes is deliberate (Issue #1428):
184
+ * a SUCCEEDED entry that were deleted immediately would let a delayed retry of
185
+ * the *same* idempotency key re-run the install and hit a spurious
186
+ * DESTINATION_EXISTS, so success and failure expire on the same clock and a key
187
+ * becomes reusable at a single, predictable time regardless of outcome.
188
+ *
189
+ * @returns the idempotency keys of the entries that were pruned.
190
+ */
191
+ function pruneExpiredSkillOperationJournal(options = {}) {
192
+ const now = options.now ?? Date.now();
193
+ const retentionMs = options.retentionMs ?? exports.SKILL_JOURNAL_RETENTION_MS;
194
+ const pruned = [];
195
+ for (const entry of listSkillOperationJournal(options)) {
196
+ if (!isSkillOperationTerminal(entry))
197
+ continue;
198
+ if (now - entry.updatedAt <= retentionMs)
199
+ continue;
200
+ deleteSkillOperationJournal(entry.idempotencyKey, options);
201
+ pruned.push(entry.idempotencyKey);
202
+ }
203
+ return pruned;
204
+ }
205
+ /**
206
+ * Open an operation, or return the one this request already started.
207
+ *
208
+ * A replay hands back the recorded entry so the caller can answer with the
209
+ * original outcome instead of writing the payload a second time.
210
+ */
211
+ function beginSkillOperation(input, options = {}) {
212
+ const bindingHash = computeSkillOperationBindingHash(input.binding);
213
+ const idempotencyKey = input.idempotencyKey ?? deriveSkillOperationIdempotencyKey(input.binding);
214
+ const existing = readSkillOperationJournal(idempotencyKey, options);
215
+ if (existing !== null) {
216
+ if (existing.bindingHash !== bindingHash) {
217
+ return { ok: false, reason: 'IDEMPOTENCY_KEY_CONFLICT', entry: existing };
218
+ }
219
+ return { ok: true, entry: existing, replayed: true };
220
+ }
221
+ const now = options.now ?? Date.now();
222
+ const entry = {
223
+ schemaVersion: 1,
224
+ operationId: (0, crypto_1.randomUUID)(),
225
+ idempotencyKey,
226
+ bindingHash,
227
+ operation: input.binding.operation,
228
+ state: 'PREPARING',
229
+ actor: input.binding.actor,
230
+ target: input.binding.target,
231
+ source: input.source ?? null,
232
+ lockKey: input.lockKey,
233
+ createdAt: now,
234
+ updatedAt: now,
235
+ fsCommittedAt: null,
236
+ receiptDigest: null,
237
+ error: null,
238
+ history: [{ state: 'PREPARING', at: now }],
239
+ };
240
+ writeSkillOperationJournal(entry, options);
241
+ return { ok: true, entry, replayed: false };
242
+ }
243
+ /**
244
+ * Advance an operation to its next state and persist it.
245
+ *
246
+ * @throws SkillOperationTransitionError when the edge is not legal, or when a
247
+ * recovery edge is attempted on an operation that never reached the commit
248
+ * point (there is no receipt to converge from).
249
+ */
250
+ function transitionSkillOperation(entry, next, patch = {}, options = {}) {
251
+ if (!ALLOWED_TRANSITIONS[entry.state].includes(next)) {
252
+ throw new SkillOperationTransitionError(entry.state, next, 'edge is not defined');
253
+ }
254
+ const now = options.now ?? Date.now();
255
+ const fsCommittedAt = next === 'FS_COMMITTED' ? (entry.fsCommittedAt ?? now) : entry.fsCommittedAt;
256
+ if ((next === 'INDEXED' || next === 'SUCCEEDED') && fsCommittedAt === null) {
257
+ throw new SkillOperationTransitionError(entry.state, next, 'no filesystem commit point was recorded');
258
+ }
259
+ const updated = {
260
+ ...entry,
261
+ state: next,
262
+ updatedAt: now,
263
+ fsCommittedAt,
264
+ source: patch.source !== undefined ? patch.source : entry.source,
265
+ receiptDigest: patch.receiptDigest !== undefined ? patch.receiptDigest : entry.receiptDigest,
266
+ error: patch.error !== undefined
267
+ ? patch.error === null
268
+ ? null
269
+ : { code: patch.error.code, message: (0, operation_store_1.redactSkillOperationText)(patch.error.message) }
270
+ : entry.error,
271
+ history: [...entry.history, { state: next, at: now }],
272
+ };
273
+ writeSkillOperationJournal(updated, options);
274
+ return updated;
275
+ }
276
+ /** Whether the payload is known to exist, regardless of how the DB side ended. */
277
+ function hasSkillFilesystemCommit(entry) {
278
+ return entry.fsCommittedAt !== null;
279
+ }
280
+ /** Whether an entry still needs work from the reconciler. */
281
+ function isSkillOperationTerminal(entry) {
282
+ if (entry.state === 'SUCCEEDED')
283
+ return true;
284
+ // A failure before the commit point rolled back cleanly; nothing to converge.
285
+ return entry.state === 'FAILED_RECONCILABLE' && !hasSkillFilesystemCommit(entry);
286
+ }
@@ -0,0 +1,339 @@
1
+ "use strict";
2
+ /**
3
+ * Cross-process exclusive lock for Skill operations (Issue #1234)
4
+ *
5
+ * Extends the O_EXCL pattern of `lib/app-update/update-lock` with the three
6
+ * properties a Skill operation needs and a self-update does not:
7
+ *
8
+ * - **Owner nonce.** Release and renew require the caller to present the nonce
9
+ * written at acquisition, so no process can drop a lock it does not hold.
10
+ * - **Lease heartbeat.** {@link renewSkillOperationLease} can extend a lease so
11
+ * a long operation is not reclaimed by age. It is not yet wired into the
12
+ * routes, so owner liveness below — not the heartbeat — is what currently
13
+ * keeps a live operation safe (Issue #1427).
14
+ * - **Owner liveness.** A lock whose lease expired is reclaimed only when the
15
+ * owning PID is verifiably gone on this host. A live owner that missed a
16
+ * heartbeat keeps its lock, including a same-process concurrent operation:
17
+ * reclaiming it would let two processes write the same payload.
18
+ *
19
+ * The lock key is a digest of the *resolved* worktree path and the validated
20
+ * Skill ID, so no untrusted name ever reaches a filename.
21
+ *
22
+ * @module lib/skills/operation-lock
23
+ */
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.SKILL_LOCK_FOREIGN_HOST_GRACE_MS = exports.SKILL_LOCK_LEASE_MS = void 0;
26
+ exports.buildSkillOperationLockKey = buildSkillOperationLockKey;
27
+ exports.readSkillOperationLock = readSkillOperationLock;
28
+ exports.describeSkillLockHolder = describeSkillLockHolder;
29
+ exports.evaluateSkillLock = evaluateSkillLock;
30
+ exports.acquireSkillOperationLock = acquireSkillOperationLock;
31
+ exports.renewSkillOperationLease = renewSkillOperationLease;
32
+ exports.releaseSkillOperationLock = releaseSkillOperationLock;
33
+ exports.listSkillOperationLockKeys = listSkillOperationLockKeys;
34
+ exports.releaseOrphanSkillLocks = releaseOrphanSkillLocks;
35
+ const fs_1 = require("fs");
36
+ const os_1 = require("os");
37
+ const path_1 = require("path");
38
+ const crypto_1 = require("crypto");
39
+ const operation_store_1 = require("../../lib/skills/operation-store");
40
+ /** Lease length. A holder renews well before this; a crash expires it. */
41
+ exports.SKILL_LOCK_LEASE_MS = 30_000;
42
+ /**
43
+ * Extra wait before reclaiming a lock owned by another host.
44
+ * Liveness cannot be checked across hosts, so time is the only evidence there.
45
+ */
46
+ exports.SKILL_LOCK_FOREIGN_HOST_GRACE_MS = 10 * 60_000;
47
+ /**
48
+ * Identifies this process across restarts. A PID alone is reusable; combined
49
+ * with this value a record can be recognised as "written by me".
50
+ */
51
+ const PROCESS_GENERATION = (0, crypto_1.randomUUID)();
52
+ function defaultIsProcessAlive(pid) {
53
+ if (!Number.isInteger(pid) || pid <= 0)
54
+ return false;
55
+ try {
56
+ process.kill(pid, 0);
57
+ return true;
58
+ }
59
+ catch (error) {
60
+ // EPERM means the process exists but belongs to another user.
61
+ return error.code === 'EPERM';
62
+ }
63
+ }
64
+ /**
65
+ * Lock key for a (worktree, skill) pair.
66
+ *
67
+ * @param worktreeRealPath - Server-resolved, symlink-free worktree path. Two
68
+ * registrations pointing at the same directory must produce the same key, so
69
+ * the caller is responsible for having called realpath.
70
+ * @param skillId - Skill ID already validated against the contract grammar.
71
+ */
72
+ function buildSkillOperationLockKey(worktreeRealPath, skillId) {
73
+ return (0, crypto_1.createHash)('sha256').update(`${worktreeRealPath}\x00${skillId}`).digest('hex');
74
+ }
75
+ function getLockDir(options) {
76
+ return (0, operation_store_1.ensureSkillStateDir)(operation_store_1.SKILL_LOCK_DIRNAME, options);
77
+ }
78
+ function getLockPath(key, options) {
79
+ return (0, path_1.join)(getLockDir(options), `${key}.lock`);
80
+ }
81
+ function isLockRecord(value) {
82
+ if (typeof value !== 'object' || value === null)
83
+ return false;
84
+ const record = value;
85
+ const owner = record.owner;
86
+ return (typeof record.key === 'string' &&
87
+ typeof record.operationId === 'string' &&
88
+ typeof record.leaseExpiresAt === 'number' &&
89
+ Number.isFinite(record.leaseExpiresAt) &&
90
+ typeof owner === 'object' &&
91
+ owner !== null &&
92
+ typeof owner.nonce === 'string' &&
93
+ typeof owner.pid === 'number' &&
94
+ typeof owner.host === 'string');
95
+ }
96
+ /** Read a lock record. Returns null when absent or unparseable. */
97
+ function readSkillOperationLock(key, options = {}) {
98
+ const record = (0, operation_store_1.readSkillStateFile)(getLockPath(key, options));
99
+ return isLockRecord(record) ? record : null;
100
+ }
101
+ /** Public, non-sensitive view of a lock record. */
102
+ function describeSkillLockHolder(record) {
103
+ return {
104
+ operationId: record.operationId,
105
+ acquiredAt: record.acquiredAt,
106
+ leaseExpiresAt: record.leaseExpiresAt,
107
+ };
108
+ }
109
+ /**
110
+ * Decide how an observed record may be treated, given the clock and liveness.
111
+ *
112
+ * Ordering matters: a valid lease short-circuits every other consideration, so
113
+ * a live holder is never reclaimed regardless of what its PID looks like. Once
114
+ * the lease has lapsed on this host, PID liveness is the *only* remaining
115
+ * evidence — a lock is reclaimed only when its owning process is verifiably gone.
116
+ *
117
+ * Same-process locks are deliberately not shortcut to RECLAIMABLE (Issue #1427).
118
+ * Every Next.js route handler runs in one shared process and none renews its
119
+ * lease ({@link renewSkillOperationLease} has no production caller), so a lapsed
120
+ * lease is not evidence that a *concurrent* same-process operation abandoned its
121
+ * lock. Shortcutting it to reclaimable let a second request steal a live
122
+ * install's lock ~one lease window in and write the same payload underneath it.
123
+ * A same-process owner that is still alive now resolves to HELD_BY_LIVE_OWNER
124
+ * and is left alone.
125
+ *
126
+ * Tradeoff: this process can no longer instantly reclaim a lock it truly leaked
127
+ * (acquired but never released). While the process stays alive such a lock reads
128
+ * as HELD_BY_LIVE_OWNER; it clears only on an explicit release or after the
129
+ * process exits — a later process then sees the dead PID and reclaims it. Note
130
+ * this is stronger than "next acquire waits at most one lease window": with no
131
+ * heartbeat there is no time-based signal, so within one live process the lock
132
+ * is held until release/exit, not merely until the lease lapses. In practice the
133
+ * acquire path always releases in a `finally`, so the only real remnant is a
134
+ * crash — and crash orphans are unaffected: a new process has a different
135
+ * generation and finds the old PID gone, so the liveness branch below reclaims
136
+ * them exactly as before.
137
+ */
138
+ function evaluateSkillLock(record, options = {}) {
139
+ if (record === null)
140
+ return 'FREE';
141
+ const now = options.now ?? Date.now();
142
+ if (now < record.leaseExpiresAt)
143
+ return 'HELD';
144
+ const isAlive = options.isProcessAlive ?? defaultIsProcessAlive;
145
+ if (record.owner.host !== (0, os_1.hostname)()) {
146
+ const expiredFor = now - record.leaseExpiresAt;
147
+ return expiredFor > exports.SKILL_LOCK_FOREIGN_HOST_GRACE_MS
148
+ ? 'RECLAIMABLE'
149
+ : 'HELD_UNVERIFIABLE_OWNER';
150
+ }
151
+ return isAlive(record.owner.pid) ? 'HELD_BY_LIVE_OWNER' : 'RECLAIMABLE';
152
+ }
153
+ function buildRecord(key, operationId, now, leaseMs) {
154
+ return {
155
+ schemaVersion: 1,
156
+ key,
157
+ operationId,
158
+ owner: {
159
+ nonce: (0, crypto_1.randomBytes)(24).toString('hex'),
160
+ pid: process.pid,
161
+ host: (0, os_1.hostname)(),
162
+ processGeneration: PROCESS_GENERATION,
163
+ },
164
+ acquiredAt: now,
165
+ renewedAt: now,
166
+ leaseExpiresAt: now + leaseMs,
167
+ };
168
+ }
169
+ /** Create the lock file, failing when it already exists. */
170
+ function tryCreate(lockPath, record) {
171
+ let fd;
172
+ try {
173
+ fd = (0, fs_1.openSync)(lockPath, fs_1.constants.O_CREAT | fs_1.constants.O_EXCL | fs_1.constants.O_WRONLY, operation_store_1.SKILL_STATE_FILE_MODE);
174
+ }
175
+ catch {
176
+ return false;
177
+ }
178
+ try {
179
+ (0, fs_1.writeSync)(fd, JSON.stringify(record));
180
+ return true;
181
+ }
182
+ finally {
183
+ (0, fs_1.closeSync)(fd);
184
+ }
185
+ }
186
+ /**
187
+ * Move a reclaimable lock aside atomically, then re-check it.
188
+ *
189
+ * The rename is the mutual exclusion: only one reclaimer can move the file, so
190
+ * a second reclaimer fails and reports RACE_LOST instead of also proceeding.
191
+ * The post-rename re-check closes the window where the holder renewed its lease
192
+ * between our read and our rename; in that case the file is put back.
193
+ */
194
+ function reclaim(lockPath, observed, options) {
195
+ const stagePath = `${lockPath}.reclaim-${(0, crypto_1.randomBytes)(8).toString('hex')}`;
196
+ try {
197
+ (0, fs_1.renameSync)(lockPath, stagePath);
198
+ }
199
+ catch {
200
+ return { ok: false, reason: 'RACE_LOST' };
201
+ }
202
+ const staged = (0, operation_store_1.readSkillStateFile)(stagePath);
203
+ const stagedRecord = isLockRecord(staged) ? staged : null;
204
+ const stillReclaimable = observed === null
205
+ ? // The file was unparseable; only proceed if it still is.
206
+ stagedRecord === null
207
+ : stagedRecord === null ||
208
+ (stagedRecord.owner.nonce === observed.owner.nonce &&
209
+ evaluateSkillLock(stagedRecord, options) === 'RECLAIMABLE');
210
+ if (!stillReclaimable) {
211
+ try {
212
+ (0, fs_1.renameSync)(stagePath, lockPath);
213
+ }
214
+ catch {
215
+ // The holder already re-created its own lock; nothing was lost.
216
+ }
217
+ return { ok: false, reason: 'RACE_LOST' };
218
+ }
219
+ try {
220
+ (0, fs_1.unlinkSync)(stagePath);
221
+ }
222
+ catch {
223
+ // Already gone; the lock path is what matters.
224
+ }
225
+ return { ok: true };
226
+ }
227
+ /**
228
+ * Take the exclusive lock for one (worktree, skill) pair.
229
+ *
230
+ * @returns the record on success. The caller must keep it: renew and release
231
+ * both require the nonce it carries.
232
+ */
233
+ function acquireSkillOperationLock(input, options = {}) {
234
+ const now = options.now ?? Date.now();
235
+ const leaseMs = input.leaseMs ?? exports.SKILL_LOCK_LEASE_MS;
236
+ const lockPath = getLockPath(input.key, options);
237
+ const record = buildRecord(input.key, input.operationId, now, leaseMs);
238
+ if (tryCreate(lockPath, record)) {
239
+ return { ok: true, lock: record, reclaimed: false };
240
+ }
241
+ const observed = readSkillOperationLock(input.key, options);
242
+ // A file that exists but does not parse can never expire on its own, so it is
243
+ // reclaimable rather than "free" — free would mean the create below succeeds.
244
+ const disposition = observed === null
245
+ ? (0, fs_1.existsSync)(lockPath)
246
+ ? 'RECLAIMABLE'
247
+ : 'FREE'
248
+ : evaluateSkillLock(observed, options);
249
+ const heldBy = observed ? describeSkillLockHolder(observed) : null;
250
+ if (disposition === 'HELD' || disposition === 'HELD_BY_LIVE_OWNER') {
251
+ return { ok: false, reason: disposition, heldBy };
252
+ }
253
+ if (disposition === 'HELD_UNVERIFIABLE_OWNER') {
254
+ return { ok: false, reason: 'HELD_UNVERIFIABLE_OWNER', heldBy };
255
+ }
256
+ if (disposition === 'FREE') {
257
+ // The file vanished between the failed create and the read.
258
+ return tryCreate(lockPath, record)
259
+ ? { ok: true, lock: record, reclaimed: false }
260
+ : { ok: false, reason: 'RACE_LOST', heldBy: null };
261
+ }
262
+ // RECLAIMABLE.
263
+ const reclaimed = reclaim(lockPath, observed, options);
264
+ if (!reclaimed.ok) {
265
+ return { ok: false, reason: reclaimed.reason, heldBy };
266
+ }
267
+ return tryCreate(lockPath, record)
268
+ ? { ok: true, lock: record, reclaimed: true }
269
+ : { ok: false, reason: 'RACE_LOST', heldBy: null };
270
+ }
271
+ /**
272
+ * Extend the lease. Fails when the caller is not the current owner, which is
273
+ * how a process that was reclaimed learns it must stop writing.
274
+ *
275
+ * @returns the refreshed record, or null when the lock was lost.
276
+ */
277
+ function renewSkillOperationLease(lock, options = {}) {
278
+ const current = readSkillOperationLock(lock.key, options);
279
+ if (current === null || current.owner.nonce !== lock.owner.nonce)
280
+ return null;
281
+ const now = options.now ?? Date.now();
282
+ const leaseMs = lock.leaseExpiresAt - lock.renewedAt;
283
+ const renewed = {
284
+ ...current,
285
+ renewedAt: now,
286
+ leaseExpiresAt: now + (leaseMs > 0 ? leaseMs : exports.SKILL_LOCK_LEASE_MS),
287
+ };
288
+ (0, operation_store_1.writeSkillStateFile)(getLockPath(lock.key, options), renewed);
289
+ return renewed;
290
+ }
291
+ /**
292
+ * Drop the lock. Owner-only: presenting a stale or foreign nonce is refused so
293
+ * no operation can release another operation's resource.
294
+ */
295
+ function releaseSkillOperationLock(lock, options = {}) {
296
+ const current = readSkillOperationLock(lock.key, options);
297
+ if (current === null || current.owner.nonce !== lock.owner.nonce)
298
+ return false;
299
+ try {
300
+ (0, fs_1.unlinkSync)(getLockPath(lock.key, options));
301
+ return true;
302
+ }
303
+ catch {
304
+ return false;
305
+ }
306
+ }
307
+ /** Keys of every lock file currently present. */
308
+ function listSkillOperationLockKeys(options = {}) {
309
+ return (0, fs_1.readdirSync)(getLockDir(options))
310
+ .filter((name) => name.endsWith('.lock'))
311
+ .map((name) => name.slice(0, -'.lock'.length));
312
+ }
313
+ /**
314
+ * Remove locks whose owner is verifiably gone.
315
+ *
316
+ * Used by startup reconciliation. A lock is only removed when
317
+ * {@link evaluateSkillLock} says RECLAIMABLE, so a live owner — even one whose
318
+ * lease lapsed — keeps its lock.
319
+ *
320
+ * @returns keys of the locks that were removed.
321
+ */
322
+ function releaseOrphanSkillLocks(options = {}) {
323
+ const released = [];
324
+ for (const key of listSkillOperationLockKeys(options)) {
325
+ const record = readSkillOperationLock(key, options);
326
+ // A file that exists but does not parse can never expire on its own.
327
+ const disposition = record === null ? 'RECLAIMABLE' : evaluateSkillLock(record, options);
328
+ if (disposition !== 'RECLAIMABLE')
329
+ continue;
330
+ try {
331
+ (0, fs_1.unlinkSync)(getLockPath(key, options));
332
+ released.push(key);
333
+ }
334
+ catch {
335
+ // Someone else cleaned it up first.
336
+ }
337
+ }
338
+ return released;
339
+ }