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,1248 @@
1
+ "use strict";
2
+ /**
3
+ * Schema validation for the Agent Skills distribution contract (Issue #1228)
4
+ *
5
+ * Pure functions over already-parsed values: no filesystem, no network, no YAML
6
+ * parser. The caller parses `commandmate.skill.yaml` under
7
+ * {@link SKILL_YAML_SAFE_PROFILE} and hands the resulting `unknown` here.
8
+ *
9
+ * Every validator is fail-closed and total: it returns a
10
+ * {@link SkillValidationResult} rather than throwing, and on success returns a
11
+ * freshly constructed object so no unvalidated property from the input
12
+ * survives.
13
+ *
14
+ * @module lib/skills/schema
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.SKILL_OPTIONAL_FIELDS = exports.SKILL_DOCUMENT_FIELDS = void 0;
18
+ exports.foldSkillIdForCollision = foldSkillIdForCollision;
19
+ exports.validateSkillId = validateSkillId;
20
+ exports.detectSkillIdCollision = detectSkillIdCollision;
21
+ exports.validateSkillIdentityConsistency = validateSkillIdentityConsistency;
22
+ exports.validateSkillPayloadPath = validateSkillPayloadPath;
23
+ exports.validateSkillManifest = validateSkillManifest;
24
+ exports.validateSkillCatalog = validateSkillCatalog;
25
+ exports.validateSkillInstallReceipt = validateSkillInstallReceipt;
26
+ exports.validateManifestFileSet = validateManifestFileSet;
27
+ exports.resolveEffectiveSkillRisk = resolveEffectiveSkillRisk;
28
+ exports.computeSkillRisk = computeSkillRisk;
29
+ exports.canonicalizeSkillReceipt = canonicalizeSkillReceipt;
30
+ const types_1 = require("../../lib/cli-tools/types");
31
+ const constants_1 = require("../../lib/skills/constants");
32
+ const errors_1 = require("../../lib/skills/errors");
33
+ const semver_1 = require("../../lib/skills/semver");
34
+ // =============================================================================
35
+ // Allowed field sets (schema_version 1 is closed: unknown fields are rejected)
36
+ // =============================================================================
37
+ const MANIFEST_FIELDS = [
38
+ 'schema_version',
39
+ 'id',
40
+ 'name',
41
+ 'version',
42
+ 'summary',
43
+ 'description',
44
+ 'capabilities',
45
+ 'expected_outcomes',
46
+ 'provider',
47
+ 'license',
48
+ 'homepage',
49
+ 'keywords',
50
+ 'compatibility',
51
+ 'requirements',
52
+ 'declared_permissions',
53
+ 'declared_risk',
54
+ 'risk_rationale',
55
+ 'files',
56
+ ];
57
+ const CATALOG_FIELDS = ['schema_version', 'entries'];
58
+ const CATALOG_ENTRY_FIELDS = [
59
+ 'id',
60
+ 'name',
61
+ 'summary',
62
+ 'provider',
63
+ 'license',
64
+ 'homepage',
65
+ 'keywords',
66
+ 'latest',
67
+ 'versions',
68
+ ];
69
+ const CATALOG_VERSION_FIELDS = [
70
+ 'version',
71
+ 'changelog',
72
+ 'published_at',
73
+ 'source',
74
+ 'artifact',
75
+ 'compatibility',
76
+ 'declared_risk',
77
+ ];
78
+ const RECEIPT_FIELDS = [
79
+ 'schema_version',
80
+ 'skill_id',
81
+ 'version',
82
+ 'install_root',
83
+ 'install_roots',
84
+ 'source',
85
+ 'artifact',
86
+ 'files',
87
+ 'declared_risk',
88
+ 'computed_risk',
89
+ 'effective_risk',
90
+ 'declared_permissions',
91
+ 'agent_compatibility',
92
+ ];
93
+ const PROVIDER_FIELDS = ['name', 'url', 'contact'];
94
+ const COMPATIBILITY_FIELDS = ['commandmate', 'agents'];
95
+ const AGENT_COMPAT_FIELDS = ['agent', 'support', 'evidence'];
96
+ const REQUIREMENTS_FIELDS = ['commands', 'network_hosts'];
97
+ const COMMAND_FIELDS = ['name', 'version_range'];
98
+ const FILE_ENTRY_FIELDS = ['path', 'sha256', 'size', 'kind', 'executable', 'script'];
99
+ const SOURCE_FIELDS = ['repository', 'ref', 'commit'];
100
+ const ARTIFACT_FIELDS = ['asset_name', 'url', 'sha256', 'size', 'content_type', 'format'];
101
+ const RECEIPT_ARTIFACT_FIELDS = ['asset_name', 'sha256', 'size', 'format'];
102
+ const INSTALLED_FILE_FIELDS = ['path', 'sha256', 'size', 'executable'];
103
+ /** Field name lists, exposed so schema-parity tests can compare them to the JSON Schema. */
104
+ exports.SKILL_DOCUMENT_FIELDS = {
105
+ manifest: MANIFEST_FIELDS,
106
+ catalog: CATALOG_FIELDS,
107
+ catalogEntry: CATALOG_ENTRY_FIELDS,
108
+ catalogVersion: CATALOG_VERSION_FIELDS,
109
+ receipt: RECEIPT_FIELDS,
110
+ provider: PROVIDER_FIELDS,
111
+ compatibility: COMPATIBILITY_FIELDS,
112
+ agentCompatibility: AGENT_COMPAT_FIELDS,
113
+ requirements: REQUIREMENTS_FIELDS,
114
+ requirementCommand: COMMAND_FIELDS,
115
+ fileEntry: FILE_ENTRY_FIELDS,
116
+ source: SOURCE_FIELDS,
117
+ artifact: ARTIFACT_FIELDS,
118
+ receiptArtifact: RECEIPT_ARTIFACT_FIELDS,
119
+ installedFile: INSTALLED_FILE_FIELDS,
120
+ };
121
+ /** Optional fields per document, exposed for the same parity check. */
122
+ exports.SKILL_OPTIONAL_FIELDS = {
123
+ manifest: ['homepage', 'keywords'],
124
+ catalog: [],
125
+ catalogEntry: ['homepage', 'keywords'],
126
+ catalogVersion: [],
127
+ receipt: ['install_roots'],
128
+ provider: ['url', 'contact'],
129
+ compatibility: [],
130
+ agentCompatibility: [],
131
+ requirements: [],
132
+ requirementCommand: ['version_range'],
133
+ fileEntry: [],
134
+ source: [],
135
+ artifact: [],
136
+ receiptArtifact: [],
137
+ installedFile: [],
138
+ };
139
+ function isPlainObject(value) {
140
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
141
+ }
142
+ function has(obj, key) {
143
+ return Object.prototype.hasOwnProperty.call(obj, key);
144
+ }
145
+ function readObject(value, path, errors) {
146
+ if (!isPlainObject(value)) {
147
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.NOT_AN_OBJECT, path, `${path || '/'} must be an object`));
148
+ return null;
149
+ }
150
+ return value;
151
+ }
152
+ function checkUnknownFields(obj, allowed, path, errors) {
153
+ for (const key of Object.keys(obj)) {
154
+ if (!allowed.includes(key)) {
155
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.UNKNOWN_FIELD, (0, errors_1.joinPath)(path, key), `unknown field is not allowed in schema_version ${constants_1.SKILL_SCHEMA_VERSION}`));
156
+ }
157
+ }
158
+ }
159
+ function readString(obj, key, parent, errors, options = {}) {
160
+ const path = (0, errors_1.joinPath)(parent, key);
161
+ if (!has(obj, key) || obj[key] === undefined) {
162
+ if (!options.optional) {
163
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, path, `${key} is required`));
164
+ }
165
+ return undefined;
166
+ }
167
+ const value = obj[key];
168
+ if (typeof value !== 'string') {
169
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INVALID_TYPE, path, `${key} must be a string`));
170
+ return undefined;
171
+ }
172
+ // A field with a domain-specific error code reports that code for every
173
+ // violation, so a truncated digest reads as "invalid digest" rather than as a
174
+ // generic length problem.
175
+ const lengthCode = options.formatCode ?? errors_1.SkillContractErrorCode.LIMIT_EXCEEDED;
176
+ const min = options.minLength ?? 1;
177
+ if (value.length < min) {
178
+ errors.push((0, errors_1.skillError)(lengthCode, path, `${key} is shorter than the minimum`, { minLength: min }));
179
+ return undefined;
180
+ }
181
+ if (options.maxLength !== undefined && value.length > options.maxLength) {
182
+ errors.push((0, errors_1.skillError)(lengthCode, path, `${key} exceeds the maximum length`, {
183
+ maxLength: options.maxLength,
184
+ }));
185
+ return undefined;
186
+ }
187
+ if (options.pattern && !options.pattern.test(value)) {
188
+ errors.push((0, errors_1.skillError)(options.formatCode ?? errors_1.SkillContractErrorCode.INVALID_FORMAT, path, `${key} does not match the required format`, options.patternName ? { format: options.patternName } : undefined));
189
+ return undefined;
190
+ }
191
+ return value;
192
+ }
193
+ function readInteger(obj, key, parent, errors, bounds) {
194
+ const path = (0, errors_1.joinPath)(parent, key);
195
+ if (!has(obj, key) || obj[key] === undefined) {
196
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, path, `${key} is required`));
197
+ return undefined;
198
+ }
199
+ const value = obj[key];
200
+ if (typeof value !== 'number' || !Number.isInteger(value)) {
201
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INVALID_TYPE, path, `${key} must be an integer`));
202
+ return undefined;
203
+ }
204
+ if (value < bounds.min || value > bounds.max) {
205
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.LIMIT_EXCEEDED, path, `${key} is out of range`, bounds));
206
+ return undefined;
207
+ }
208
+ return value;
209
+ }
210
+ function readBoolean(obj, key, parent, errors) {
211
+ const path = (0, errors_1.joinPath)(parent, key);
212
+ if (!has(obj, key) || obj[key] === undefined) {
213
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, path, `${key} is required`));
214
+ return undefined;
215
+ }
216
+ const value = obj[key];
217
+ if (typeof value !== 'boolean') {
218
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INVALID_TYPE, path, `${key} must be a boolean`));
219
+ return undefined;
220
+ }
221
+ return value;
222
+ }
223
+ function readArray(obj, key, parent, errors, options) {
224
+ const path = (0, errors_1.joinPath)(parent, key);
225
+ if (!has(obj, key) || obj[key] === undefined) {
226
+ if (!options.optional) {
227
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, path, `${key} is required`));
228
+ }
229
+ return undefined;
230
+ }
231
+ const value = obj[key];
232
+ if (!Array.isArray(value)) {
233
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INVALID_TYPE, path, `${key} must be an array`));
234
+ return undefined;
235
+ }
236
+ if (value.length > options.maxItems) {
237
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.LIMIT_EXCEEDED, path, `${key} has too many items`, {
238
+ maxItems: options.maxItems,
239
+ }));
240
+ return undefined;
241
+ }
242
+ return value;
243
+ }
244
+ function readEnum(obj, key, parent, errors, allowed) {
245
+ const path = (0, errors_1.joinPath)(parent, key);
246
+ if (!has(obj, key) || obj[key] === undefined) {
247
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, path, `${key} is required`));
248
+ return undefined;
249
+ }
250
+ const value = obj[key];
251
+ if (typeof value !== 'string' || !allowed.includes(value)) {
252
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INVALID_ENUM, path, `${key} is not an allowed value`, {
253
+ allowed: allowed.join('|'),
254
+ }));
255
+ return undefined;
256
+ }
257
+ return value;
258
+ }
259
+ function readStringList(obj, key, parent, errors, options) {
260
+ const raw = readArray(obj, key, parent, errors, {
261
+ maxItems: options.maxItems,
262
+ optional: options.optional,
263
+ });
264
+ if (raw === undefined)
265
+ return undefined;
266
+ const out = [];
267
+ let failed = false;
268
+ raw.forEach((item, index) => {
269
+ const path = (0, errors_1.joinPath)((0, errors_1.joinPath)(parent, key), index);
270
+ if (typeof item !== 'string' || item.length === 0 || item.length > options.maxLength) {
271
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INVALID_TYPE, path, 'item must be a bounded string', {
272
+ maxLength: options.maxLength,
273
+ }));
274
+ failed = true;
275
+ return;
276
+ }
277
+ if (options.pattern && !options.pattern.test(item)) {
278
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INVALID_FORMAT, path, 'item does not match the required format'));
279
+ failed = true;
280
+ return;
281
+ }
282
+ out.push(item);
283
+ });
284
+ return failed ? undefined : out;
285
+ }
286
+ function readHttpsUrl(obj, key, parent, errors, options = {}) {
287
+ const value = readString(obj, key, parent, errors, { optional: options.optional, maxLength: 512 });
288
+ if (value === undefined)
289
+ return undefined;
290
+ if (!value.startsWith(constants_1.HTTPS_URL_PREFIX)) {
291
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INVALID_FORMAT, (0, errors_1.joinPath)(parent, key), `${key} must be an https URL`));
292
+ return undefined;
293
+ }
294
+ return value;
295
+ }
296
+ function readSchemaVersion(obj, errors) {
297
+ const path = '/schema_version';
298
+ const value = obj['schema_version'];
299
+ if (value === undefined) {
300
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.SCHEMA_VERSION_UNSUPPORTED, path, 'schema_version is required'));
301
+ return undefined;
302
+ }
303
+ if (value !== constants_1.SKILL_SCHEMA_VERSION) {
304
+ // Fail closed: a future schema_version is rejected, never best-effort parsed.
305
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.SCHEMA_VERSION_UNSUPPORTED, path, 'schema_version is not supported by this build', { supported: constants_1.SKILL_SCHEMA_VERSION }));
306
+ return undefined;
307
+ }
308
+ return constants_1.SKILL_SCHEMA_VERSION;
309
+ }
310
+ // =============================================================================
311
+ // Skill ID
312
+ // =============================================================================
313
+ /**
314
+ * Fold a name for collision detection.
315
+ *
316
+ * Case folding plus NFKC catches directory names that differ only by case or by
317
+ * a compatibility-equivalent Unicode form but collide on a case-insensitive or
318
+ * normalizing filesystem.
319
+ */
320
+ function foldSkillIdForCollision(name) {
321
+ return name.normalize('NFKC').toLowerCase();
322
+ }
323
+ /** Validate a Skill ID against the slug grammar and the reserved list. */
324
+ function validateSkillId(id, path = '/id') {
325
+ if (typeof id !== 'string' || id.length === 0) {
326
+ return (0, errors_1.skillFail)([(0, errors_1.skillError)(errors_1.SkillContractErrorCode.ID_INVALID, path, 'id must be a non-empty string')]);
327
+ }
328
+ if (id.length > constants_1.SKILL_ID_MAX_LENGTH) {
329
+ return (0, errors_1.skillFail)([
330
+ (0, errors_1.skillError)(errors_1.SkillContractErrorCode.ID_INVALID, path, 'id exceeds the maximum length', {
331
+ maxLength: constants_1.SKILL_ID_MAX_LENGTH,
332
+ }),
333
+ ]);
334
+ }
335
+ if (!constants_1.SKILL_ID_PATTERN.test(id)) {
336
+ return (0, errors_1.skillFail)([
337
+ (0, errors_1.skillError)(errors_1.SkillContractErrorCode.ID_INVALID, path, 'id must be a lowercase ASCII slug', {
338
+ format: 'lowercase-slug',
339
+ }),
340
+ ]);
341
+ }
342
+ if (constants_1.RESERVED_SKILL_IDS.includes(id)) {
343
+ return (0, errors_1.skillFail)([(0, errors_1.skillError)(errors_1.SkillContractErrorCode.ID_RESERVED, path, 'id is reserved')]);
344
+ }
345
+ return (0, errors_1.skillOk)(id);
346
+ }
347
+ /**
348
+ * Detect a case/Unicode collision between a new ID and existing directory names.
349
+ *
350
+ * @returns the colliding existing name, or null when the ID is free.
351
+ */
352
+ function detectSkillIdCollision(id, existingNames) {
353
+ const folded = foldSkillIdForCollision(id);
354
+ for (const name of existingNames) {
355
+ if (name === id)
356
+ continue;
357
+ if (foldSkillIdForCollision(name) === folded)
358
+ return name;
359
+ }
360
+ return null;
361
+ }
362
+ /**
363
+ * Check that the directory name, the SKILL.md frontmatter name and the manifest
364
+ * agree, which is what stops a package from installing under a name the user
365
+ * never reviewed.
366
+ */
367
+ function validateSkillIdentityConsistency(input) {
368
+ const idResult = validateSkillId(input.manifestId);
369
+ if (!idResult.ok)
370
+ return idResult;
371
+ const errors = [];
372
+ if (input.directoryName !== input.manifestId) {
373
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.ID_MISMATCH, '/id', 'directory name does not match the manifest id'));
374
+ }
375
+ if (input.skillMdName !== input.manifestName) {
376
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.ID_MISMATCH, '/name', 'SKILL.md name does not match the manifest name'));
377
+ }
378
+ return errors.length > 0 ? (0, errors_1.skillFail)(errors) : (0, errors_1.skillOk)(input.manifestId);
379
+ }
380
+ // =============================================================================
381
+ // Payload paths
382
+ // =============================================================================
383
+ const WINDOWS_DRIVE_PATH = /^[A-Za-z]:/;
384
+ /** NUL and other control bytes are rejected by code point, not by a control regex. */
385
+ function hasControlCharOrBackslash(value) {
386
+ for (let i = 0; i < value.length; i++) {
387
+ const code = value.charCodeAt(i);
388
+ if (code < 0x20 || code === 0x7f || code === 0x5c)
389
+ return true;
390
+ }
391
+ return false;
392
+ }
393
+ /**
394
+ * Validate a payload path declared in a manifest or receipt.
395
+ *
396
+ * String-level only: it rejects everything that could escape the Skill root
397
+ * before any filesystem call happens. Real-path/symlink checks stay with the
398
+ * installer (#1231), which owns the filesystem.
399
+ */
400
+ function validateSkillPayloadPath(value, path) {
401
+ const fail = (message, detail) => (0, errors_1.skillFail)([(0, errors_1.skillError)(errors_1.SkillContractErrorCode.FILE_PATH_UNSAFE, path, message, detail)]);
402
+ if (typeof value !== 'string' || value.length === 0)
403
+ return fail('path must be a non-empty string');
404
+ if (value.length > constants_1.SKILL_PATH_MAX_LENGTH) {
405
+ return fail('path exceeds the maximum length', { maxLength: constants_1.SKILL_PATH_MAX_LENGTH });
406
+ }
407
+ if (hasControlCharOrBackslash(value))
408
+ return fail('path contains a control character or a backslash');
409
+ if (value.startsWith('/') || WINDOWS_DRIVE_PATH.test(value))
410
+ return fail('path must be relative');
411
+ if (value !== value.normalize('NFC'))
412
+ return fail('path must be NFC-normalized');
413
+ if (value.includes('//'))
414
+ return fail('path must not contain empty segments');
415
+ if (value.endsWith('/'))
416
+ return fail('path must not be a directory entry');
417
+ const segments = value.split('/');
418
+ if (segments.length > constants_1.SKILL_PATH_MAX_DEPTH) {
419
+ return fail('path is nested too deeply', { maxDepth: constants_1.SKILL_PATH_MAX_DEPTH });
420
+ }
421
+ for (const segment of segments) {
422
+ if (segment === '.' || segment === '..')
423
+ return fail('path must not contain "." or ".." segments');
424
+ if (segment.length > constants_1.SKILL_PATH_SEGMENT_MAX_LENGTH) {
425
+ return fail('path segment is too long', { maxLength: constants_1.SKILL_PATH_SEGMENT_MAX_LENGTH });
426
+ }
427
+ if (segment !== segment.trim())
428
+ return fail('path segment must not be padded with whitespace');
429
+ }
430
+ return (0, errors_1.skillOk)(value);
431
+ }
432
+ // =============================================================================
433
+ // Shared sub-object validators
434
+ // =============================================================================
435
+ function readProvider(parentObj, parent, errors) {
436
+ const path = (0, errors_1.joinPath)(parent, 'provider');
437
+ const raw = parentObj['provider'];
438
+ if (raw === undefined) {
439
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, path, 'provider is required'));
440
+ return undefined;
441
+ }
442
+ const obj = readObject(raw, path, errors);
443
+ if (!obj)
444
+ return undefined;
445
+ checkUnknownFields(obj, PROVIDER_FIELDS, path, errors);
446
+ const name = readString(obj, 'name', path, errors, { maxLength: constants_1.SKILL_NAME_MAX_LENGTH });
447
+ const url = readHttpsUrl(obj, 'url', path, errors, { optional: true });
448
+ const contact = readString(obj, 'contact', path, errors, { optional: true, maxLength: 200 });
449
+ if (name === undefined)
450
+ return undefined;
451
+ return { name, ...(url !== undefined ? { url } : {}), ...(contact !== undefined ? { contact } : {}) };
452
+ }
453
+ function readAgentCompatibility(raw, path, errors) {
454
+ const obj = readObject(raw, path, errors);
455
+ if (!obj)
456
+ return undefined;
457
+ checkUnknownFields(obj, AGENT_COMPAT_FIELDS, path, errors);
458
+ const agent = readString(obj, 'agent', path, errors, { maxLength: 40 });
459
+ if (agent !== undefined && !(0, types_1.isCliToolType)(agent)) {
460
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INVALID_ENUM, (0, errors_1.joinPath)(path, 'agent'), 'agent is not a known CLI tool'));
461
+ return undefined;
462
+ }
463
+ const support = readEnum(obj, 'support', path, errors, constants_1.SKILL_AGENT_SUPPORT_VALUES);
464
+ const evidence = readString(obj, 'evidence', path, errors, { maxLength: constants_1.SKILL_EVIDENCE_MAX_LENGTH });
465
+ if (agent === undefined || support === undefined || evidence === undefined)
466
+ return undefined;
467
+ return { agent, support, evidence };
468
+ }
469
+ function readCompatibility(parentObj, parent, errors) {
470
+ const path = (0, errors_1.joinPath)(parent, 'compatibility');
471
+ const raw = parentObj['compatibility'];
472
+ if (raw === undefined) {
473
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, path, 'compatibility is required'));
474
+ return undefined;
475
+ }
476
+ const obj = readObject(raw, path, errors);
477
+ if (!obj)
478
+ return undefined;
479
+ checkUnknownFields(obj, COMPATIBILITY_FIELDS, path, errors);
480
+ const commandmate = readString(obj, 'commandmate', path, errors, { maxLength: 100 });
481
+ if (commandmate !== undefined && !(0, semver_1.isValidSkillVersionRange)(commandmate)) {
482
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.VERSION_RANGE_INVALID, (0, errors_1.joinPath)(path, 'commandmate'), 'commandmate is not a supported version range'));
483
+ return undefined;
484
+ }
485
+ const rawAgents = readArray(obj, 'agents', path, errors, { maxItems: 20 });
486
+ if (commandmate === undefined || rawAgents === undefined)
487
+ return undefined;
488
+ const agents = [];
489
+ const seen = new Set();
490
+ let failed = false;
491
+ rawAgents.forEach((item, index) => {
492
+ const itemPath = (0, errors_1.joinPath)((0, errors_1.joinPath)(path, 'agents'), index);
493
+ const parsed = readAgentCompatibility(item, itemPath, errors);
494
+ if (!parsed) {
495
+ failed = true;
496
+ return;
497
+ }
498
+ if (seen.has(parsed.agent)) {
499
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.DUPLICATE_ENTRY, itemPath, 'agent is declared more than once'));
500
+ failed = true;
501
+ return;
502
+ }
503
+ seen.add(parsed.agent);
504
+ agents.push(parsed);
505
+ });
506
+ return failed ? undefined : { commandmate, agents };
507
+ }
508
+ function readRequirements(parentObj, parent, errors) {
509
+ const path = (0, errors_1.joinPath)(parent, 'requirements');
510
+ const raw = parentObj['requirements'];
511
+ if (raw === undefined) {
512
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, path, 'requirements is required'));
513
+ return undefined;
514
+ }
515
+ const obj = readObject(raw, path, errors);
516
+ if (!obj)
517
+ return undefined;
518
+ checkUnknownFields(obj, REQUIREMENTS_FIELDS, path, errors);
519
+ const rawCommands = readArray(obj, 'commands', path, errors, { maxItems: constants_1.SKILL_COMMANDS_MAX_COUNT });
520
+ const networkHosts = readStringList(obj, 'network_hosts', path, errors, {
521
+ maxItems: constants_1.SKILL_NETWORK_HOSTS_MAX_COUNT,
522
+ maxLength: 253,
523
+ pattern: constants_1.NETWORK_HOST_PATTERN,
524
+ });
525
+ if (rawCommands === undefined || networkHosts === undefined)
526
+ return undefined;
527
+ const commands = [];
528
+ let failed = false;
529
+ rawCommands.forEach((item, index) => {
530
+ const itemPath = (0, errors_1.joinPath)((0, errors_1.joinPath)(path, 'commands'), index);
531
+ const cmdObj = readObject(item, itemPath, errors);
532
+ if (!cmdObj) {
533
+ failed = true;
534
+ return;
535
+ }
536
+ checkUnknownFields(cmdObj, COMMAND_FIELDS, itemPath, errors);
537
+ const name = readString(cmdObj, 'name', itemPath, errors, {
538
+ maxLength: 64,
539
+ pattern: constants_1.COMMAND_NAME_PATTERN,
540
+ patternName: 'command-name',
541
+ });
542
+ const range = readString(cmdObj, 'version_range', itemPath, errors, {
543
+ optional: true,
544
+ maxLength: 100,
545
+ });
546
+ if (range !== undefined && !(0, semver_1.isValidSkillVersionRange)(range)) {
547
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.VERSION_RANGE_INVALID, (0, errors_1.joinPath)(itemPath, 'version_range'), 'version_range is not a supported version range'));
548
+ failed = true;
549
+ return;
550
+ }
551
+ if (name === undefined) {
552
+ failed = true;
553
+ return;
554
+ }
555
+ commands.push({ name, ...(range !== undefined ? { version_range: range } : {}) });
556
+ });
557
+ return failed ? undefined : { commands, network_hosts: networkHosts };
558
+ }
559
+ function readSource(parentObj, parent, errors) {
560
+ const path = (0, errors_1.joinPath)(parent, 'source');
561
+ const raw = parentObj['source'];
562
+ if (raw === undefined) {
563
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, path, 'source is required'));
564
+ return undefined;
565
+ }
566
+ const obj = readObject(raw, path, errors);
567
+ if (!obj)
568
+ return undefined;
569
+ checkUnknownFields(obj, SOURCE_FIELDS, path, errors);
570
+ const repository = readString(obj, 'repository', path, errors, {
571
+ maxLength: 140,
572
+ pattern: constants_1.REPOSITORY_SLUG_PATTERN,
573
+ patternName: 'owner/name',
574
+ });
575
+ const ref = readString(obj, 'ref', path, errors, {
576
+ maxLength: 100,
577
+ pattern: constants_1.GIT_REF_PATTERN,
578
+ patternName: 'git-ref',
579
+ });
580
+ if (ref !== undefined && ref.includes('..')) {
581
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INVALID_FORMAT, (0, errors_1.joinPath)(path, 'ref'), 'ref must not contain ".."'));
582
+ return undefined;
583
+ }
584
+ const commit = readString(obj, 'commit', path, errors, {
585
+ maxLength: 40,
586
+ minLength: 40,
587
+ pattern: constants_1.GIT_COMMIT_SHA_PATTERN,
588
+ patternName: 'sha1-40-hex',
589
+ formatCode: errors_1.SkillContractErrorCode.SOURCE_COMMIT_INVALID,
590
+ });
591
+ if (repository === undefined || ref === undefined || commit === undefined)
592
+ return undefined;
593
+ return { repository, ref, commit };
594
+ }
595
+ function readArtifact(parentObj, parent, errors) {
596
+ const path = (0, errors_1.joinPath)(parent, 'artifact');
597
+ const raw = parentObj['artifact'];
598
+ if (raw === undefined) {
599
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, path, 'artifact is required'));
600
+ return undefined;
601
+ }
602
+ const obj = readObject(raw, path, errors);
603
+ if (!obj)
604
+ return undefined;
605
+ checkUnknownFields(obj, ARTIFACT_FIELDS, path, errors);
606
+ const assetName = readString(obj, 'asset_name', path, errors, { maxLength: 200 });
607
+ const url = readHttpsUrl(obj, 'url', path, errors);
608
+ const sha256 = readString(obj, 'sha256', path, errors, {
609
+ minLength: 64,
610
+ maxLength: 64,
611
+ pattern: constants_1.SHA256_HEX_PATTERN,
612
+ patternName: 'sha256-lowercase-hex',
613
+ formatCode: errors_1.SkillContractErrorCode.DIGEST_INVALID,
614
+ });
615
+ const size = readInteger(obj, 'size', path, errors, { min: 1, max: constants_1.SKILL_ARTIFACT_MAX_SIZE });
616
+ const contentType = readString(obj, 'content_type', path, errors, { maxLength: 100 });
617
+ const format = readEnum(obj, 'format', path, errors, [constants_1.SKILL_ARTIFACT_FORMAT]);
618
+ if (contentType !== undefined && contentType !== constants_1.SKILL_ARTIFACT_CONTENT_TYPE) {
619
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.ARTIFACT_INVALID, (0, errors_1.joinPath)(path, 'content_type'), 'content_type must be the fixed artifact media type', { expected: constants_1.SKILL_ARTIFACT_CONTENT_TYPE }));
620
+ return undefined;
621
+ }
622
+ if (assetName === undefined ||
623
+ url === undefined ||
624
+ sha256 === undefined ||
625
+ size === undefined ||
626
+ contentType === undefined ||
627
+ format === undefined) {
628
+ return undefined;
629
+ }
630
+ return { asset_name: assetName, url, sha256, size, content_type: contentType, format };
631
+ }
632
+ // =============================================================================
633
+ // Manifest
634
+ // =============================================================================
635
+ function readFileEntries(parentObj, parent, errors) {
636
+ const path = (0, errors_1.joinPath)(parent, 'files');
637
+ const raw = readArray(parentObj, 'files', parent, errors, { maxItems: constants_1.SKILL_FILES_MAX_COUNT });
638
+ if (raw === undefined)
639
+ return undefined;
640
+ const entries = [];
641
+ const seenFolded = new Set();
642
+ let failed = false;
643
+ raw.forEach((item, index) => {
644
+ const itemPath = (0, errors_1.joinPath)(path, index);
645
+ const obj = readObject(item, itemPath, errors);
646
+ if (!obj) {
647
+ failed = true;
648
+ return;
649
+ }
650
+ checkUnknownFields(obj, FILE_ENTRY_FIELDS, itemPath, errors);
651
+ const pathResult = validateSkillPayloadPath(obj['path'], (0, errors_1.joinPath)(itemPath, 'path'));
652
+ const sha256 = readString(obj, 'sha256', itemPath, errors, {
653
+ minLength: 64,
654
+ maxLength: 64,
655
+ pattern: constants_1.SHA256_HEX_PATTERN,
656
+ patternName: 'sha256-lowercase-hex',
657
+ formatCode: errors_1.SkillContractErrorCode.DIGEST_INVALID,
658
+ });
659
+ const size = readInteger(obj, 'size', itemPath, errors, { min: 0, max: constants_1.SKILL_FILE_MAX_SIZE });
660
+ const kind = readEnum(obj, 'kind', itemPath, errors, constants_1.SKILL_FILE_KINDS);
661
+ const executable = readBoolean(obj, 'executable', itemPath, errors);
662
+ const script = readBoolean(obj, 'script', itemPath, errors);
663
+ if (!pathResult.ok) {
664
+ errors.push(...pathResult.errors);
665
+ failed = true;
666
+ return;
667
+ }
668
+ if (sha256 === undefined ||
669
+ size === undefined ||
670
+ kind === undefined ||
671
+ executable === undefined ||
672
+ script === undefined) {
673
+ failed = true;
674
+ return;
675
+ }
676
+ const filePath = pathResult.value;
677
+ if (filePath === constants_1.SKILL_MANIFEST_FILENAME) {
678
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.FILE_SET_MISMATCH, (0, errors_1.joinPath)(itemPath, 'path'), 'the manifest must not declare a digest for itself'));
679
+ failed = true;
680
+ return;
681
+ }
682
+ const folded = foldSkillIdForCollision(filePath);
683
+ if (seenFolded.has(folded)) {
684
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.FILE_PATH_DUPLICATE, (0, errors_1.joinPath)(itemPath, 'path'), 'path collides with another declared file'));
685
+ failed = true;
686
+ return;
687
+ }
688
+ seenFolded.add(folded);
689
+ entries.push({ path: filePath, sha256, size, kind, executable, script });
690
+ });
691
+ if (failed)
692
+ return undefined;
693
+ const skillMd = entries.filter((e) => e.path === constants_1.SKILL_MD_FILENAME);
694
+ if (skillMd.length !== 1) {
695
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.FILE_SET_MISMATCH, path, `files must declare exactly one ${constants_1.SKILL_MD_FILENAME}`));
696
+ return undefined;
697
+ }
698
+ if (skillMd[0].kind !== 'skill_md') {
699
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INCONSISTENT_VALUE, path, `${constants_1.SKILL_MD_FILENAME} must be declared with kind "skill_md"`));
700
+ return undefined;
701
+ }
702
+ return entries;
703
+ }
704
+ /** Validate a parsed `commandmate.skill.yaml` document. */
705
+ function validateSkillManifest(input) {
706
+ const errors = [];
707
+ const obj = readObject(input, '', errors);
708
+ if (!obj)
709
+ return (0, errors_1.skillFail)(errors);
710
+ const schemaVersion = readSchemaVersion(obj, errors);
711
+ if (schemaVersion === undefined)
712
+ return (0, errors_1.skillFail)(errors);
713
+ checkUnknownFields(obj, MANIFEST_FIELDS, '', errors);
714
+ const idResult = validateSkillId(obj['id']);
715
+ if (!idResult.ok)
716
+ errors.push(...idResult.errors);
717
+ const name = readString(obj, 'name', '', errors, { maxLength: constants_1.SKILL_NAME_MAX_LENGTH });
718
+ const version = readString(obj, 'version', '', errors, { maxLength: 64 });
719
+ if (version !== undefined && !(0, semver_1.isValidSemVer)(version)) {
720
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.VERSION_INVALID, '/version', 'version must be SemVer 2.0 without a "v" prefix'));
721
+ }
722
+ const summary = readString(obj, 'summary', '', errors, { maxLength: constants_1.SKILL_SUMMARY_MAX_LENGTH });
723
+ const description = readString(obj, 'description', '', errors, {
724
+ maxLength: constants_1.SKILL_DESCRIPTION_MAX_LENGTH,
725
+ });
726
+ const capabilities = readStringList(obj, 'capabilities', '', errors, {
727
+ maxItems: constants_1.SKILL_BULLET_MAX_COUNT,
728
+ maxLength: constants_1.SKILL_BULLET_MAX_LENGTH,
729
+ });
730
+ const expectedOutcomes = readStringList(obj, 'expected_outcomes', '', errors, {
731
+ maxItems: constants_1.SKILL_BULLET_MAX_COUNT,
732
+ maxLength: constants_1.SKILL_BULLET_MAX_LENGTH,
733
+ });
734
+ const provider = readProvider(obj, '', errors);
735
+ const license = readString(obj, 'license', '', errors, {
736
+ maxLength: 64,
737
+ pattern: constants_1.SPDX_LICENSE_PATTERN,
738
+ patternName: 'spdx-license-id',
739
+ });
740
+ const homepage = readHttpsUrl(obj, 'homepage', '', errors, { optional: true });
741
+ const keywords = readStringList(obj, 'keywords', '', errors, {
742
+ maxItems: constants_1.SKILL_KEYWORDS_MAX_COUNT,
743
+ maxLength: constants_1.SKILL_KEYWORD_MAX_LENGTH,
744
+ optional: true,
745
+ });
746
+ const compatibility = readCompatibility(obj, '', errors);
747
+ const requirements = readRequirements(obj, '', errors);
748
+ const declaredPermissions = readStringList(obj, 'declared_permissions', '', errors, {
749
+ maxItems: constants_1.SKILL_DECLARED_PERMISSIONS.length,
750
+ maxLength: 40,
751
+ });
752
+ if (declaredPermissions) {
753
+ for (const [index, permission] of declaredPermissions.entries()) {
754
+ if (!constants_1.SKILL_DECLARED_PERMISSIONS.includes(permission)) {
755
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INVALID_ENUM, (0, errors_1.joinPath)('/declared_permissions', index), 'declared permission is not an allowed value'));
756
+ }
757
+ }
758
+ }
759
+ const declaredRisk = readEnum(obj, 'declared_risk', '', errors, constants_1.SKILL_RISK_LEVELS);
760
+ const riskRationale = readString(obj, 'risk_rationale', '', errors, {
761
+ maxLength: constants_1.SKILL_RATIONALE_MAX_LENGTH,
762
+ });
763
+ const files = readFileEntries(obj, '', errors);
764
+ // Capabilities and expected outcomes are what the install dialog shows (UX-01),
765
+ // so an empty list is a contract violation rather than an acceptable default.
766
+ if (capabilities && capabilities.length === 0) {
767
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, '/capabilities', 'capabilities must not be empty'));
768
+ }
769
+ if (expectedOutcomes && expectedOutcomes.length === 0) {
770
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, '/expected_outcomes', 'expected_outcomes must not be empty'));
771
+ }
772
+ if (errors.length > 0 ||
773
+ !idResult.ok ||
774
+ name === undefined ||
775
+ version === undefined ||
776
+ summary === undefined ||
777
+ description === undefined ||
778
+ capabilities === undefined ||
779
+ expectedOutcomes === undefined ||
780
+ provider === undefined ||
781
+ license === undefined ||
782
+ compatibility === undefined ||
783
+ requirements === undefined ||
784
+ declaredPermissions === undefined ||
785
+ declaredRisk === undefined ||
786
+ riskRationale === undefined ||
787
+ files === undefined) {
788
+ return (0, errors_1.skillFail)(errors.length > 0
789
+ ? errors
790
+ : [(0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, '', 'manifest is incomplete')]);
791
+ }
792
+ return (0, errors_1.skillOk)({
793
+ schema_version: schemaVersion,
794
+ id: idResult.value,
795
+ name,
796
+ version,
797
+ summary,
798
+ description,
799
+ capabilities,
800
+ expected_outcomes: expectedOutcomes,
801
+ provider,
802
+ license,
803
+ ...(homepage !== undefined ? { homepage } : {}),
804
+ ...(keywords !== undefined ? { keywords } : {}),
805
+ compatibility,
806
+ requirements,
807
+ declared_permissions: declaredPermissions,
808
+ declared_risk: declaredRisk,
809
+ risk_rationale: riskRationale,
810
+ files,
811
+ });
812
+ }
813
+ // =============================================================================
814
+ // Catalog
815
+ // =============================================================================
816
+ function readCatalogVersion(raw, path, skillId, errors) {
817
+ const obj = readObject(raw, path, errors);
818
+ if (!obj)
819
+ return undefined;
820
+ checkUnknownFields(obj, CATALOG_VERSION_FIELDS, path, errors);
821
+ const version = readString(obj, 'version', path, errors, { maxLength: 64 });
822
+ if (version !== undefined && !(0, semver_1.isValidSemVer)(version)) {
823
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.VERSION_INVALID, (0, errors_1.joinPath)(path, 'version'), 'version must be SemVer 2.0'));
824
+ return undefined;
825
+ }
826
+ const changelog = readString(obj, 'changelog', path, errors, { maxLength: constants_1.SKILL_CHANGELOG_MAX_LENGTH });
827
+ const publishedAt = readString(obj, 'published_at', path, errors, {
828
+ maxLength: 30,
829
+ pattern: constants_1.RFC3339_UTC_PATTERN,
830
+ patternName: 'rfc3339-utc',
831
+ });
832
+ const source = readSource(obj, path, errors);
833
+ const artifact = readArtifact(obj, path, errors);
834
+ const compatibility = readCompatibility(obj, path, errors);
835
+ const declaredRisk = readEnum(obj, 'declared_risk', path, errors, constants_1.SKILL_RISK_LEVELS);
836
+ if (version === undefined ||
837
+ changelog === undefined ||
838
+ publishedAt === undefined ||
839
+ source === undefined ||
840
+ artifact === undefined ||
841
+ compatibility === undefined ||
842
+ declaredRisk === undefined) {
843
+ return undefined;
844
+ }
845
+ const expectedAsset = (0, constants_1.buildSkillAssetName)(skillId, version);
846
+ if (artifact.asset_name !== expectedAsset) {
847
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.ARTIFACT_INVALID, (0, errors_1.joinPath)((0, errors_1.joinPath)(path, 'artifact'), 'asset_name'), 'asset_name must follow the <skill-id>-<version>.tar.gz convention', { expected: expectedAsset }));
848
+ return undefined;
849
+ }
850
+ return {
851
+ version,
852
+ changelog,
853
+ published_at: publishedAt,
854
+ source,
855
+ artifact,
856
+ compatibility,
857
+ declared_risk: declaredRisk,
858
+ };
859
+ }
860
+ function readCatalogEntry(raw, path, errors) {
861
+ const obj = readObject(raw, path, errors);
862
+ if (!obj)
863
+ return undefined;
864
+ checkUnknownFields(obj, CATALOG_ENTRY_FIELDS, path, errors);
865
+ const idResult = validateSkillId(obj['id'], (0, errors_1.joinPath)(path, 'id'));
866
+ if (!idResult.ok) {
867
+ errors.push(...idResult.errors);
868
+ return undefined;
869
+ }
870
+ const id = idResult.value;
871
+ const name = readString(obj, 'name', path, errors, { maxLength: constants_1.SKILL_NAME_MAX_LENGTH });
872
+ const summary = readString(obj, 'summary', path, errors, { maxLength: constants_1.SKILL_SUMMARY_MAX_LENGTH });
873
+ const provider = readProvider(obj, path, errors);
874
+ const license = readString(obj, 'license', path, errors, {
875
+ maxLength: 64,
876
+ pattern: constants_1.SPDX_LICENSE_PATTERN,
877
+ patternName: 'spdx-license-id',
878
+ });
879
+ const homepage = readHttpsUrl(obj, 'homepage', path, errors, { optional: true });
880
+ const keywords = readStringList(obj, 'keywords', path, errors, {
881
+ maxItems: constants_1.SKILL_KEYWORDS_MAX_COUNT,
882
+ maxLength: constants_1.SKILL_KEYWORD_MAX_LENGTH,
883
+ optional: true,
884
+ });
885
+ const latest = readString(obj, 'latest', path, errors, { maxLength: 64 });
886
+ const rawVersions = readArray(obj, 'versions', path, errors, {
887
+ maxItems: constants_1.SKILL_CATALOG_VERSIONS_MAX_COUNT,
888
+ });
889
+ if (name === undefined ||
890
+ summary === undefined ||
891
+ provider === undefined ||
892
+ license === undefined ||
893
+ latest === undefined ||
894
+ rawVersions === undefined) {
895
+ return undefined;
896
+ }
897
+ if (rawVersions.length === 0) {
898
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, (0, errors_1.joinPath)(path, 'versions'), 'versions must not be empty'));
899
+ return undefined;
900
+ }
901
+ const versions = [];
902
+ const seenVersions = new Set();
903
+ let failed = false;
904
+ rawVersions.forEach((item, index) => {
905
+ const itemPath = (0, errors_1.joinPath)((0, errors_1.joinPath)(path, 'versions'), index);
906
+ const parsed = readCatalogVersion(item, itemPath, id, errors);
907
+ if (!parsed) {
908
+ failed = true;
909
+ return;
910
+ }
911
+ if (seenVersions.has(parsed.version)) {
912
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.DUPLICATE_ENTRY, itemPath, 'version is listed more than once'));
913
+ failed = true;
914
+ return;
915
+ }
916
+ seenVersions.add(parsed.version);
917
+ versions.push(parsed);
918
+ });
919
+ if (failed)
920
+ return undefined;
921
+ if (!seenVersions.has(latest)) {
922
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.CATALOG_LATEST_UNRESOLVED, (0, errors_1.joinPath)(path, 'latest'), 'latest must reference a listed version'));
923
+ return undefined;
924
+ }
925
+ return {
926
+ id,
927
+ name,
928
+ summary,
929
+ provider,
930
+ license,
931
+ ...(homepage !== undefined ? { homepage } : {}),
932
+ ...(keywords !== undefined ? { keywords } : {}),
933
+ latest,
934
+ versions,
935
+ };
936
+ }
937
+ /** Validate a parsed Catalog document. */
938
+ function validateSkillCatalog(input) {
939
+ const errors = [];
940
+ const obj = readObject(input, '', errors);
941
+ if (!obj)
942
+ return (0, errors_1.skillFail)(errors);
943
+ const schemaVersion = readSchemaVersion(obj, errors);
944
+ if (schemaVersion === undefined)
945
+ return (0, errors_1.skillFail)(errors);
946
+ checkUnknownFields(obj, CATALOG_FIELDS, '', errors);
947
+ const rawEntries = readArray(obj, 'entries', '', errors, {
948
+ maxItems: constants_1.SKILL_CATALOG_ENTRIES_MAX_COUNT,
949
+ });
950
+ if (rawEntries === undefined)
951
+ return (0, errors_1.skillFail)(errors);
952
+ const entries = [];
953
+ const seenIds = new Set();
954
+ rawEntries.forEach((item, index) => {
955
+ const itemPath = (0, errors_1.joinPath)('/entries', index);
956
+ const parsed = readCatalogEntry(item, itemPath, errors);
957
+ if (!parsed)
958
+ return;
959
+ const folded = foldSkillIdForCollision(parsed.id);
960
+ if (seenIds.has(folded)) {
961
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.ID_COLLISION, itemPath, 'entry id collides with another entry'));
962
+ return;
963
+ }
964
+ seenIds.add(folded);
965
+ entries.push(parsed);
966
+ });
967
+ if (errors.length > 0)
968
+ return (0, errors_1.skillFail)(errors);
969
+ return (0, errors_1.skillOk)({ schema_version: schemaVersion, entries });
970
+ }
971
+ // =============================================================================
972
+ // Receipt
973
+ // =============================================================================
974
+ function readReceiptArtifact(parentObj, parent, errors) {
975
+ const path = (0, errors_1.joinPath)(parent, 'artifact');
976
+ const raw = parentObj['artifact'];
977
+ if (raw === undefined) {
978
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, path, 'artifact is required'));
979
+ return undefined;
980
+ }
981
+ const obj = readObject(raw, path, errors);
982
+ if (!obj)
983
+ return undefined;
984
+ checkUnknownFields(obj, RECEIPT_ARTIFACT_FIELDS, path, errors);
985
+ const assetName = readString(obj, 'asset_name', path, errors, { maxLength: 200 });
986
+ const sha256 = readString(obj, 'sha256', path, errors, {
987
+ minLength: 64,
988
+ maxLength: 64,
989
+ pattern: constants_1.SHA256_HEX_PATTERN,
990
+ patternName: 'sha256-lowercase-hex',
991
+ formatCode: errors_1.SkillContractErrorCode.DIGEST_INVALID,
992
+ });
993
+ const size = readInteger(obj, 'size', path, errors, { min: 1, max: constants_1.SKILL_ARTIFACT_MAX_SIZE });
994
+ const format = readEnum(obj, 'format', path, errors, [constants_1.SKILL_ARTIFACT_FORMAT]);
995
+ if (assetName === undefined || sha256 === undefined || size === undefined || format === undefined) {
996
+ return undefined;
997
+ }
998
+ return { asset_name: assetName, sha256, size, format };
999
+ }
1000
+ function readInstalledFiles(parentObj, parent, errors) {
1001
+ const path = (0, errors_1.joinPath)(parent, 'files');
1002
+ const raw = readArray(parentObj, 'files', parent, errors, { maxItems: constants_1.SKILL_FILES_MAX_COUNT });
1003
+ if (raw === undefined)
1004
+ return undefined;
1005
+ const files = [];
1006
+ let failed = false;
1007
+ raw.forEach((item, index) => {
1008
+ const itemPath = (0, errors_1.joinPath)(path, index);
1009
+ const obj = readObject(item, itemPath, errors);
1010
+ if (!obj) {
1011
+ failed = true;
1012
+ return;
1013
+ }
1014
+ checkUnknownFields(obj, INSTALLED_FILE_FIELDS, itemPath, errors);
1015
+ const pathResult = validateSkillPayloadPath(obj['path'], (0, errors_1.joinPath)(itemPath, 'path'));
1016
+ const sha256 = readString(obj, 'sha256', itemPath, errors, {
1017
+ minLength: 64,
1018
+ maxLength: 64,
1019
+ pattern: constants_1.SHA256_HEX_PATTERN,
1020
+ patternName: 'sha256-lowercase-hex',
1021
+ formatCode: errors_1.SkillContractErrorCode.DIGEST_INVALID,
1022
+ });
1023
+ const size = readInteger(obj, 'size', itemPath, errors, { min: 0, max: constants_1.SKILL_FILE_MAX_SIZE });
1024
+ const executable = readBoolean(obj, 'executable', itemPath, errors);
1025
+ if (!pathResult.ok) {
1026
+ errors.push(...pathResult.errors);
1027
+ failed = true;
1028
+ return;
1029
+ }
1030
+ if (sha256 === undefined || size === undefined || executable === undefined) {
1031
+ failed = true;
1032
+ return;
1033
+ }
1034
+ files.push({ path: pathResult.value, sha256, size, executable });
1035
+ });
1036
+ if (failed)
1037
+ return undefined;
1038
+ // Receipts must be byte-reproducible, so the file list has one canonical order.
1039
+ for (let i = 1; i < files.length; i++) {
1040
+ if (files[i - 1].path >= files[i].path) {
1041
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INCONSISTENT_VALUE, path, 'files must be sorted by path in ascending order without duplicates'));
1042
+ return undefined;
1043
+ }
1044
+ }
1045
+ return files;
1046
+ }
1047
+ /** Validate a parsed install receipt. */
1048
+ function validateSkillInstallReceipt(input) {
1049
+ const errors = [];
1050
+ const obj = readObject(input, '', errors);
1051
+ if (!obj)
1052
+ return (0, errors_1.skillFail)(errors);
1053
+ const schemaVersion = readSchemaVersion(obj, errors);
1054
+ if (schemaVersion === undefined)
1055
+ return (0, errors_1.skillFail)(errors);
1056
+ checkUnknownFields(obj, RECEIPT_FIELDS, '', errors);
1057
+ const idResult = validateSkillId(obj['skill_id'], '/skill_id');
1058
+ if (!idResult.ok)
1059
+ errors.push(...idResult.errors);
1060
+ const version = readString(obj, 'version', '', errors, { maxLength: 64 });
1061
+ if (version !== undefined && !(0, semver_1.isValidSemVer)(version)) {
1062
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.VERSION_INVALID, '/version', 'version must be SemVer 2.0'));
1063
+ }
1064
+ const installRoot = readString(obj, 'install_root', '', errors, { maxLength: 200 });
1065
+ // Optional (#1460): absent means a single-root install rooted at install_root.
1066
+ const installRootsPresent = obj['install_roots'] !== undefined;
1067
+ const installRoots = installRootsPresent
1068
+ ? readStringList(obj, 'install_roots', '', errors, {
1069
+ maxItems: constants_1.SKILL_INSTALL_ROOT_PREFIXES.length,
1070
+ maxLength: 200,
1071
+ })
1072
+ : undefined;
1073
+ const source = readSource(obj, '', errors);
1074
+ const artifact = readReceiptArtifact(obj, '', errors);
1075
+ const files = readInstalledFiles(obj, '', errors);
1076
+ const declaredRisk = readEnum(obj, 'declared_risk', '', errors, constants_1.SKILL_RISK_LEVELS);
1077
+ const computedRisk = readEnum(obj, 'computed_risk', '', errors, constants_1.SKILL_RISK_LEVELS);
1078
+ const effectiveRisk = readEnum(obj, 'effective_risk', '', errors, constants_1.SKILL_RISK_LEVELS);
1079
+ const declaredPermissions = readStringList(obj, 'declared_permissions', '', errors, {
1080
+ maxItems: constants_1.SKILL_DECLARED_PERMISSIONS.length,
1081
+ maxLength: 40,
1082
+ });
1083
+ if (declaredPermissions) {
1084
+ for (const [index, permission] of declaredPermissions.entries()) {
1085
+ if (!constants_1.SKILL_DECLARED_PERMISSIONS.includes(permission)) {
1086
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INVALID_ENUM, (0, errors_1.joinPath)('/declared_permissions', index), 'declared permission is not an allowed value'));
1087
+ }
1088
+ }
1089
+ }
1090
+ const rawAgents = readArray(obj, 'agent_compatibility', '', errors, { maxItems: 20 });
1091
+ const agentCompatibility = [];
1092
+ if (rawAgents) {
1093
+ rawAgents.forEach((item, index) => {
1094
+ const parsed = readAgentCompatibility(item, (0, errors_1.joinPath)('/agent_compatibility', index), errors);
1095
+ if (parsed)
1096
+ agentCompatibility.push(parsed);
1097
+ });
1098
+ }
1099
+ if (idResult.ok && installRoot !== undefined) {
1100
+ const expectedRoot = `${constants_1.SKILL_INSTALL_ROOT_PREFIX}/${idResult.value}`;
1101
+ if (installRoot !== expectedRoot) {
1102
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INCONSISTENT_VALUE, '/install_root', 'install_root must be the repository-relative skill root', { expected: expectedRoot }));
1103
+ }
1104
+ }
1105
+ // Multi-root receipt (#1460): if present, install_roots must be the ordered set
1106
+ // of known-prefix roots for this skill, primary first and equal to install_root.
1107
+ if (idResult.ok && installRoot !== undefined && installRoots !== undefined) {
1108
+ const allowed = constants_1.SKILL_INSTALL_ROOT_PREFIXES.map((prefix) => `${prefix}/${idResult.value}`);
1109
+ if (installRoots.length === 0) {
1110
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INCONSISTENT_VALUE, '/install_roots', 'install_roots must not be empty'));
1111
+ }
1112
+ else if (installRoots[0] !== installRoot) {
1113
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INCONSISTENT_VALUE, '/install_roots/0', 'install_roots[0] must equal install_root (the primary root)', { expected: installRoot }));
1114
+ }
1115
+ const seen = new Set();
1116
+ installRoots.forEach((root, index) => {
1117
+ if (!allowed.includes(root)) {
1118
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INCONSISTENT_VALUE, `/install_roots/${index}`, 'install_roots entry must be a known repository-relative skill root'));
1119
+ }
1120
+ if (seen.has(root)) {
1121
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INCONSISTENT_VALUE, `/install_roots/${index}`, 'install_roots must not repeat a root'));
1122
+ }
1123
+ seen.add(root);
1124
+ });
1125
+ }
1126
+ if (idResult.ok && version !== undefined && artifact !== undefined) {
1127
+ const expectedAsset = (0, constants_1.buildSkillAssetName)(idResult.value, version);
1128
+ if (artifact.asset_name !== expectedAsset) {
1129
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.ARTIFACT_INVALID, '/artifact/asset_name', 'asset_name must follow the <skill-id>-<version>.tar.gz convention', { expected: expectedAsset }));
1130
+ }
1131
+ }
1132
+ if (declaredRisk !== undefined && computedRisk !== undefined && effectiveRisk !== undefined) {
1133
+ const expected = resolveEffectiveSkillRisk(declaredRisk, computedRisk);
1134
+ if (effectiveRisk !== expected) {
1135
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.INCONSISTENT_VALUE, '/effective_risk', 'effective_risk must be the higher of declared_risk and computed_risk', { expected }));
1136
+ }
1137
+ }
1138
+ if (errors.length > 0 ||
1139
+ !idResult.ok ||
1140
+ version === undefined ||
1141
+ installRoot === undefined ||
1142
+ source === undefined ||
1143
+ artifact === undefined ||
1144
+ files === undefined ||
1145
+ declaredRisk === undefined ||
1146
+ computedRisk === undefined ||
1147
+ effectiveRisk === undefined ||
1148
+ declaredPermissions === undefined ||
1149
+ rawAgents === undefined) {
1150
+ return (0, errors_1.skillFail)(errors.length > 0
1151
+ ? errors
1152
+ : [(0, errors_1.skillError)(errors_1.SkillContractErrorCode.MISSING_FIELD, '', 'receipt is incomplete')]);
1153
+ }
1154
+ return (0, errors_1.skillOk)({
1155
+ schema_version: schemaVersion,
1156
+ skill_id: idResult.value,
1157
+ version,
1158
+ install_root: installRoot,
1159
+ ...(installRoots !== undefined ? { install_roots: installRoots } : {}),
1160
+ source,
1161
+ artifact,
1162
+ files,
1163
+ declared_risk: declaredRisk,
1164
+ computed_risk: computedRisk,
1165
+ effective_risk: effectiveRisk,
1166
+ declared_permissions: declaredPermissions,
1167
+ agent_compatibility: agentCompatibility,
1168
+ });
1169
+ }
1170
+ // =============================================================================
1171
+ // Cross-document rules
1172
+ // =============================================================================
1173
+ /**
1174
+ * Compare the manifest's declared file set with the package's payload set.
1175
+ *
1176
+ * The comparison set is every regular payload file in the archive minus the
1177
+ * manifest itself and minus directory entries; the manifest's own integrity is
1178
+ * covered by the Catalog artifact digest, so it declares no self-digest.
1179
+ */
1180
+ function validateManifestFileSet(manifest, payloadPaths) {
1181
+ const declared = new Set(manifest.files.map((f) => f.path));
1182
+ const actual = new Set(payloadPaths.filter((p) => p !== constants_1.SKILL_MANIFEST_FILENAME));
1183
+ const errors = [];
1184
+ for (const path of declared) {
1185
+ if (!actual.has(path)) {
1186
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.FILE_SET_MISMATCH, '/files', 'declared file is absent from the package', {
1187
+ path,
1188
+ }));
1189
+ }
1190
+ }
1191
+ for (const path of actual) {
1192
+ if (!declared.has(path)) {
1193
+ errors.push((0, errors_1.skillError)(errors_1.SkillContractErrorCode.FILE_SET_MISMATCH, '/files', 'package contains an undeclared file', {
1194
+ path,
1195
+ }));
1196
+ }
1197
+ }
1198
+ return errors.length > 0 ? (0, errors_1.skillFail)(errors) : (0, errors_1.skillOk)([...declared].sort());
1199
+ }
1200
+ /** Resolve the effective risk shown to the user: the higher of the two inputs. */
1201
+ function resolveEffectiveSkillRisk(declared, computed) {
1202
+ return constants_1.SKILL_RISK_ORDER[computed] > constants_1.SKILL_RISK_ORDER[declared] ? computed : declared;
1203
+ }
1204
+ /**
1205
+ * Derive the risk level CommandMate computes from inspection facts.
1206
+ *
1207
+ * Deterministic and independent of the publisher's own claim, so a package
1208
+ * cannot talk its way down to `low`.
1209
+ */
1210
+ function computeSkillRisk(inspection) {
1211
+ if (inspection.executable_paths.length > 0 ||
1212
+ inspection.declared_permissions.includes('credential_access')) {
1213
+ return 'high';
1214
+ }
1215
+ if (inspection.script_paths.length > 0 ||
1216
+ inspection.network_hosts.length > 0 ||
1217
+ inspection.declared_permissions.includes('process_execution') ||
1218
+ inspection.declared_permissions.includes('filesystem_write')) {
1219
+ return 'moderate';
1220
+ }
1221
+ return 'low';
1222
+ }
1223
+ // =============================================================================
1224
+ // Canonicalization
1225
+ // =============================================================================
1226
+ function canonicalize(value) {
1227
+ if (Array.isArray(value))
1228
+ return value.map(canonicalize);
1229
+ if (isPlainObject(value)) {
1230
+ const out = {};
1231
+ for (const key of Object.keys(value).sort()) {
1232
+ if (value[key] === undefined)
1233
+ continue;
1234
+ out[key] = canonicalize(value[key]);
1235
+ }
1236
+ return out;
1237
+ }
1238
+ return value;
1239
+ }
1240
+ /**
1241
+ * Serialize a receipt deterministically: keys sorted, no insignificant
1242
+ * whitespace, no undefined members. Two installs of the same version from the
1243
+ * same commit produce byte-identical output, which is what makes a receipt
1244
+ * diffable and hashable.
1245
+ */
1246
+ function canonicalizeSkillReceipt(receipt) {
1247
+ return JSON.stringify(canonicalize(receipt));
1248
+ }