gsd-pi 2.43.0-next.8 → 2.44.0-dev.62b5d6c

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 (244) hide show
  1. package/dist/cli.js +13 -1
  2. package/dist/help-text.js +24 -0
  3. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +21 -8
  4. package/dist/resources/extensions/gsd/auto-prompts.js +130 -51
  5. package/dist/resources/extensions/gsd/auto-worktree.js +16 -2
  6. package/dist/resources/extensions/gsd/dispatch-guard.js +34 -10
  7. package/dist/resources/extensions/gsd/markdown-renderer.js +7 -5
  8. package/dist/resources/extensions/gsd/reactive-graph.js +13 -2
  9. package/dist/resources/extensions/gsd/skill-health.js +3 -1
  10. package/dist/resources/extensions/gsd/tools/plan-milestone.js +2 -11
  11. package/dist/resources/extensions/gsd/tools/plan-slice.js +2 -10
  12. package/dist/resources/extensions/gsd/visualizer-data.js +45 -13
  13. package/dist/resources/extensions/gsd/workspace-index.js +46 -15
  14. package/dist/web/standalone/.next/BUILD_ID +1 -1
  15. package/dist/web/standalone/.next/app-path-routes-manifest.json +17 -17
  16. package/dist/web/standalone/.next/build-manifest.json +3 -3
  17. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  18. package/dist/web/standalone/.next/required-server-files.json +4 -4
  19. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  20. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  21. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  22. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  23. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  24. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  25. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  26. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  27. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  28. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  29. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  30. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  31. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  32. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  33. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  34. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  36. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  40. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  41. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  42. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  43. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  44. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  45. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  46. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  47. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  48. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  49. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  50. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  51. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  52. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  53. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  54. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  55. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  56. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  57. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  58. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  59. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  60. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  62. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  64. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  66. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  68. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  70. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  72. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  74. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  76. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  78. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  80. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  82. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  84. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  86. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  88. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  90. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  92. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  94. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  96. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  98. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  100. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  102. package/dist/web/standalone/.next/server/app/api/switch-root/route_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  104. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  106. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  108. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  110. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  112. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  114. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  116. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  118. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  119. package/dist/web/standalone/.next/server/app/index.html +1 -1
  120. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  121. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  122. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  123. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  124. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  125. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/page.js +2 -2
  127. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  128. package/dist/web/standalone/.next/server/app-paths-manifest.json +17 -17
  129. package/dist/web/standalone/.next/server/chunks/229.js +1 -1
  130. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  131. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  132. package/dist/web/standalone/.next/server/middleware.js +2 -2
  133. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  134. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  135. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  136. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  137. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  138. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-f2a7482d42a5614b.js +1 -0
  139. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +1 -0
  140. package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +1 -0
  141. package/dist/web/standalone/.next/static/chunks/{main-app-2f2ee7b85712c2bd.js → main-app-fdab67f7802d7832.js} +1 -1
  142. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  143. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  144. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  145. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  146. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  147. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  148. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  149. package/dist/web/standalone/server.js +1 -1
  150. package/package.json +4 -4
  151. package/packages/pi-coding-agent/dist/core/agent-session.d.ts +3 -3
  152. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  153. package/packages/pi-coding-agent/dist/core/agent-session.js +11 -34
  154. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  155. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts +2 -2
  156. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  157. package/packages/pi-coding-agent/dist/core/compaction/branch-summarization.js.map +1 -1
  158. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts +2 -2
  159. package/packages/pi-coding-agent/dist/core/compaction/compaction.d.ts.map +1 -1
  160. package/packages/pi-coding-agent/dist/core/compaction/compaction.js.map +1 -1
  161. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +4 -4
  162. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  163. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts +1 -1
  164. package/packages/pi-coding-agent/dist/core/extensions/index.d.ts.map +1 -1
  165. package/packages/pi-coding-agent/dist/core/extensions/index.js.map +1 -1
  166. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  167. package/packages/pi-coding-agent/dist/core/extensions/loader.js +18 -0
  168. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  169. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts +37 -0
  170. package/packages/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
  171. package/packages/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
  172. package/packages/pi-coding-agent/dist/core/fallback-resolver.d.ts.map +1 -1
  173. package/packages/pi-coding-agent/dist/core/fallback-resolver.js +2 -3
  174. package/packages/pi-coding-agent/dist/core/fallback-resolver.js.map +1 -1
  175. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js +12 -2
  176. package/packages/pi-coding-agent/dist/core/fallback-resolver.test.js.map +1 -1
  177. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts +38 -0
  178. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.d.ts.map +1 -0
  179. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js +192 -0
  180. package/packages/pi-coding-agent/dist/core/lifecycle-hooks.js.map +1 -0
  181. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts +2 -0
  182. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.d.ts.map +1 -0
  183. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +255 -0
  184. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -0
  185. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +15 -0
  186. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  187. package/packages/pi-coding-agent/dist/core/model-registry.js +40 -3
  188. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  189. package/packages/pi-coding-agent/dist/core/package-commands.d.ts +25 -0
  190. package/packages/pi-coding-agent/dist/core/package-commands.d.ts.map +1 -0
  191. package/packages/pi-coding-agent/dist/core/package-commands.js +253 -0
  192. package/packages/pi-coding-agent/dist/core/package-commands.js.map +1 -0
  193. package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts +2 -0
  194. package/packages/pi-coding-agent/dist/core/package-commands.test.d.ts.map +1 -0
  195. package/packages/pi-coding-agent/dist/core/package-commands.test.js +225 -0
  196. package/packages/pi-coding-agent/dist/core/package-commands.test.js.map +1 -0
  197. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  198. package/packages/pi-coding-agent/dist/core/sdk.js +4 -0
  199. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  200. package/packages/pi-coding-agent/dist/index.d.ts +3 -1
  201. package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
  202. package/packages/pi-coding-agent/dist/index.js +1 -0
  203. package/packages/pi-coding-agent/dist/index.js.map +1 -1
  204. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  205. package/packages/pi-coding-agent/dist/main.js +11 -199
  206. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  207. package/packages/pi-coding-agent/package.json +1 -1
  208. package/packages/pi-coding-agent/src/core/agent-session.ts +13 -37
  209. package/packages/pi-coding-agent/src/core/compaction/branch-summarization.ts +2 -2
  210. package/packages/pi-coding-agent/src/core/compaction/compaction.ts +3 -3
  211. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +4 -4
  212. package/packages/pi-coding-agent/src/core/extensions/index.ts +5 -0
  213. package/packages/pi-coding-agent/src/core/extensions/loader.ts +23 -0
  214. package/packages/pi-coding-agent/src/core/extensions/types.ts +44 -0
  215. package/packages/pi-coding-agent/src/core/fallback-resolver.test.ts +15 -2
  216. package/packages/pi-coding-agent/src/core/fallback-resolver.ts +2 -3
  217. package/packages/pi-coding-agent/src/core/lifecycle-hooks.ts +274 -0
  218. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +288 -0
  219. package/packages/pi-coding-agent/src/core/model-registry.ts +39 -3
  220. package/packages/pi-coding-agent/src/core/package-commands.test.ts +240 -0
  221. package/packages/pi-coding-agent/src/core/package-commands.ts +310 -0
  222. package/packages/pi-coding-agent/src/core/sdk.ts +4 -0
  223. package/packages/pi-coding-agent/src/index.ts +7 -0
  224. package/packages/pi-coding-agent/src/main.ts +11 -232
  225. package/pkg/package.json +1 -1
  226. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +22 -7
  227. package/src/resources/extensions/gsd/auto-prompts.ts +109 -42
  228. package/src/resources/extensions/gsd/auto-worktree.ts +16 -3
  229. package/src/resources/extensions/gsd/dispatch-guard.ts +28 -10
  230. package/src/resources/extensions/gsd/markdown-renderer.ts +7 -5
  231. package/src/resources/extensions/gsd/reactive-graph.ts +12 -2
  232. package/src/resources/extensions/gsd/skill-health.ts +2 -1
  233. package/src/resources/extensions/gsd/tests/auto-stash-merge.test.ts +3 -3
  234. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +1 -1
  235. package/src/resources/extensions/gsd/tools/plan-milestone.ts +1 -18
  236. package/src/resources/extensions/gsd/tools/plan-slice.ts +1 -15
  237. package/src/resources/extensions/gsd/visualizer-data.ts +46 -14
  238. package/src/resources/extensions/gsd/workspace-index.ts +49 -18
  239. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-e07acdb7dd069836.js +0 -1
  240. package/dist/web/standalone/.next/static/chunks/app/layout-745c6ed5fea5fb06.js +0 -1
  241. package/dist/web/standalone/.next/static/chunks/app/page-801b53eff6e83579.js +0 -1
  242. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-e6255954dccfcf0a.js +0 -1
  243. /package/dist/web/standalone/.next/static/{drUWS0zys9uepCfCwecJv → fOnWQBjWXMKUs4bqTg530}/_buildManifest.js +0 -0
  244. /package/dist/web/standalone/.next/static/{drUWS0zys9uepCfCwecJv → fOnWQBjWXMKUs4bqTg530}/_ssgManifest.js +0 -0
@@ -0,0 +1,310 @@
1
+ import chalk from "chalk";
2
+ import { DefaultPackageManager } from "./package-manager.js";
3
+ import { prepareLifecycleHooks, runLifecycleHooks } from "./lifecycle-hooks.js";
4
+ import { SettingsManager } from "./settings-manager.js";
5
+
6
+ export type PackageCommand = "install" | "remove" | "update" | "list";
7
+
8
+ export interface PackageCommandOptions {
9
+ command: PackageCommand;
10
+ source?: string;
11
+ local: boolean;
12
+ help: boolean;
13
+ invalidOption?: string;
14
+ }
15
+
16
+ export interface PackageCommandRunnerOptions {
17
+ appName: string;
18
+ args: string[];
19
+ cwd: string;
20
+ agentDir: string;
21
+ stdout?: NodeJS.WriteStream;
22
+ stderr?: NodeJS.WriteStream;
23
+ allowedCommands?: ReadonlySet<PackageCommand>;
24
+ }
25
+
26
+ export interface PackageCommandRunnerResult {
27
+ handled: boolean;
28
+ exitCode: number;
29
+ }
30
+
31
+ function reportSettingsErrors(settingsManager: SettingsManager, context: string, stderr: NodeJS.WriteStream): void {
32
+ const errors = settingsManager.drainErrors();
33
+ for (const { scope, error } of errors) {
34
+ stderr.write(chalk.yellow(`Warning (${context}, ${scope} settings): ${error.message}`) + "\n");
35
+ if (error.stack) {
36
+ stderr.write(chalk.dim(error.stack) + "\n");
37
+ }
38
+ }
39
+ }
40
+
41
+ export function getPackageCommandUsage(appName: string, command: PackageCommand): string {
42
+ switch (command) {
43
+ case "install":
44
+ return `${appName} install <source> [-l]`;
45
+ case "remove":
46
+ return `${appName} remove <source> [-l]`;
47
+ case "update":
48
+ return `${appName} update [source]`;
49
+ case "list":
50
+ return `${appName} list`;
51
+ }
52
+ }
53
+
54
+ function printPackageCommandHelp(
55
+ appName: string,
56
+ command: PackageCommand,
57
+ stdout: NodeJS.WriteStream,
58
+ ): void {
59
+ switch (command) {
60
+ case "install":
61
+ stdout.write(`${chalk.bold("Usage:")}
62
+ ${getPackageCommandUsage(appName, "install")}
63
+
64
+ Install a package, add it to settings, and run lifecycle hooks.
65
+
66
+ Options:
67
+ -l, --local Install project-locally (.pi/settings.json)
68
+
69
+ Examples:
70
+ ${appName} install npm:@foo/bar
71
+ ${appName} install git:github.com/user/repo
72
+ ${appName} install git:git@github.com:user/repo
73
+ ${appName} install https://github.com/user/repo
74
+ ${appName} install ssh://git@github.com/user/repo
75
+ ${appName} install ./local/path
76
+ `);
77
+ return;
78
+ case "remove":
79
+ stdout.write(`${chalk.bold("Usage:")}
80
+ ${getPackageCommandUsage(appName, "remove")}
81
+
82
+ Remove a package and its source from settings.
83
+
84
+ Options:
85
+ -l, --local Remove from project settings (.pi/settings.json)
86
+
87
+ Example:
88
+ ${appName} remove npm:@foo/bar
89
+ `);
90
+ return;
91
+ case "update":
92
+ stdout.write(`${chalk.bold("Usage:")}
93
+ ${getPackageCommandUsage(appName, "update")}
94
+
95
+ Update installed packages.
96
+ If <source> is provided, only that package is updated.
97
+ `);
98
+ return;
99
+ case "list":
100
+ stdout.write(`${chalk.bold("Usage:")}
101
+ ${getPackageCommandUsage(appName, "list")}
102
+
103
+ List installed packages from user and project settings.
104
+ `);
105
+ return;
106
+ }
107
+ }
108
+
109
+ export function parsePackageCommand(
110
+ args: string[],
111
+ allowedCommands?: ReadonlySet<PackageCommand>,
112
+ ): PackageCommandOptions | undefined {
113
+ const [command, ...rest] = args;
114
+ if (command !== "install" && command !== "remove" && command !== "update" && command !== "list") {
115
+ return undefined;
116
+ }
117
+ if (allowedCommands && !allowedCommands.has(command)) {
118
+ return undefined;
119
+ }
120
+
121
+ let local = false;
122
+ let help = false;
123
+ let invalidOption: string | undefined;
124
+ let source: string | undefined;
125
+
126
+ for (const arg of rest) {
127
+ if (arg === "-h" || arg === "--help") {
128
+ help = true;
129
+ continue;
130
+ }
131
+ if (arg === "-l" || arg === "--local") {
132
+ if (command === "install" || command === "remove") {
133
+ local = true;
134
+ } else {
135
+ invalidOption = invalidOption ?? arg;
136
+ }
137
+ continue;
138
+ }
139
+ if (arg.startsWith("-")) {
140
+ invalidOption = invalidOption ?? arg;
141
+ continue;
142
+ }
143
+ if (!source) {
144
+ source = arg;
145
+ }
146
+ }
147
+
148
+ return { command, source, local, help, invalidOption };
149
+ }
150
+
151
+ export async function runPackageCommand(
152
+ options: PackageCommandRunnerOptions,
153
+ ): Promise<PackageCommandRunnerResult> {
154
+ const stdout = options.stdout ?? process.stdout;
155
+ const stderr = options.stderr ?? process.stderr;
156
+ const parsed = parsePackageCommand(options.args, options.allowedCommands);
157
+ if (!parsed) {
158
+ return { handled: false, exitCode: 0 };
159
+ }
160
+
161
+ if (parsed.help) {
162
+ printPackageCommandHelp(options.appName, parsed.command, stdout);
163
+ return { handled: true, exitCode: 0 };
164
+ }
165
+
166
+ if (parsed.invalidOption) {
167
+ stderr.write(chalk.red(`Unknown option ${parsed.invalidOption} for "${parsed.command}".`) + "\n");
168
+ stderr.write(chalk.dim(`Use "${options.appName} --help" or "${getPackageCommandUsage(options.appName, parsed.command)}".`) + "\n");
169
+ return { handled: true, exitCode: 1 };
170
+ }
171
+
172
+ const source = parsed.source;
173
+ if ((parsed.command === "install" || parsed.command === "remove") && !source) {
174
+ stderr.write(chalk.red(`Missing ${parsed.command} source.`) + "\n");
175
+ stderr.write(chalk.dim(`Usage: ${getPackageCommandUsage(options.appName, parsed.command)}`) + "\n");
176
+ return { handled: true, exitCode: 1 };
177
+ }
178
+
179
+ const settingsManager = SettingsManager.create(options.cwd, options.agentDir);
180
+ reportSettingsErrors(settingsManager, "package command", stderr);
181
+ const packageManager = new DefaultPackageManager({
182
+ cwd: options.cwd,
183
+ agentDir: options.agentDir,
184
+ settingsManager,
185
+ });
186
+ packageManager.setProgressCallback((event) => {
187
+ if (event.type === "start" && event.message) {
188
+ stdout.write(chalk.dim(`${event.message}\n`));
189
+ }
190
+ });
191
+
192
+ try {
193
+ switch (parsed.command) {
194
+ case "install": {
195
+ const lifecycleOptions = {
196
+ source: source!,
197
+ local: parsed.local,
198
+ cwd: options.cwd,
199
+ agentDir: options.agentDir,
200
+ appName: options.appName,
201
+ packageManager,
202
+ stdout,
203
+ stderr,
204
+ };
205
+
206
+ const beforeInstallHooks = await prepareLifecycleHooks(lifecycleOptions, "source");
207
+ const beforeInstallResult = await runLifecycleHooks(beforeInstallHooks, "beforeInstall");
208
+
209
+ await packageManager.install(source!, { local: parsed.local });
210
+ packageManager.addSourceToSettings(source!, { local: parsed.local });
211
+
212
+ const afterInstallHooks = await prepareLifecycleHooks(lifecycleOptions, "installed", {
213
+ verifyRuntimeDependencies: true,
214
+ });
215
+ const afterInstallResult = await runLifecycleHooks(afterInstallHooks, "afterInstall");
216
+
217
+ const hookErrors = beforeInstallResult.hookErrors + afterInstallResult.hookErrors;
218
+ if (hookErrors > 0) {
219
+ stderr.write(chalk.yellow(`Lifecycle hooks completed with ${hookErrors} hook error(s).`) + "\n");
220
+ }
221
+ stdout.write(chalk.green(`Installed ${source}`) + "\n");
222
+ return { handled: true, exitCode: 0 };
223
+ }
224
+
225
+ case "remove": {
226
+ const lifecycleOptions = {
227
+ source: source!,
228
+ local: parsed.local,
229
+ cwd: options.cwd,
230
+ agentDir: options.agentDir,
231
+ appName: options.appName,
232
+ packageManager,
233
+ stdout,
234
+ stderr,
235
+ };
236
+ const removeHooks = await prepareLifecycleHooks(lifecycleOptions, "installed");
237
+ const beforeRemoveResult = await runLifecycleHooks(removeHooks, "beforeRemove");
238
+
239
+ await packageManager.remove(source!, { local: parsed.local });
240
+ const removed = packageManager.removeSourceFromSettings(source!, { local: parsed.local });
241
+
242
+ const afterRemoveResult = await runLifecycleHooks(removeHooks, "afterRemove");
243
+ const hookErrors = beforeRemoveResult.hookErrors + afterRemoveResult.hookErrors;
244
+ if (hookErrors > 0) {
245
+ stderr.write(chalk.yellow(`Lifecycle hooks completed with ${hookErrors} hook error(s).`) + "\n");
246
+ }
247
+
248
+ if (!removed) {
249
+ stderr.write(chalk.red(`No matching package found for ${source}`) + "\n");
250
+ return { handled: true, exitCode: 1 };
251
+ }
252
+ stdout.write(chalk.green(`Removed ${source}`) + "\n");
253
+ return { handled: true, exitCode: 0 };
254
+ }
255
+
256
+ case "list": {
257
+ const globalSettings = settingsManager.getGlobalSettings();
258
+ const projectSettings = settingsManager.getProjectSettings();
259
+ const globalPackages = globalSettings.packages ?? [];
260
+ const projectPackages = projectSettings.packages ?? [];
261
+
262
+ if (globalPackages.length === 0 && projectPackages.length === 0) {
263
+ stdout.write(chalk.dim("No packages installed.") + "\n");
264
+ return { handled: true, exitCode: 0 };
265
+ }
266
+
267
+ const formatPackage = (pkg: (typeof globalPackages)[number], scope: "user" | "project") => {
268
+ const pkgSource = typeof pkg === "string" ? pkg : pkg.source;
269
+ const filtered = typeof pkg === "object";
270
+ const display = filtered ? `${pkgSource} (filtered)` : pkgSource;
271
+ stdout.write(` ${display}\n`);
272
+ const path = packageManager.getInstalledPath(pkgSource, scope);
273
+ if (path) {
274
+ stdout.write(chalk.dim(` ${path}`) + "\n");
275
+ }
276
+ };
277
+
278
+ if (globalPackages.length > 0) {
279
+ stdout.write(chalk.bold("User packages:") + "\n");
280
+ for (const pkg of globalPackages) {
281
+ formatPackage(pkg, "user");
282
+ }
283
+ }
284
+
285
+ if (projectPackages.length > 0) {
286
+ if (globalPackages.length > 0) stdout.write("\n");
287
+ stdout.write(chalk.bold("Project packages:") + "\n");
288
+ for (const pkg of projectPackages) {
289
+ formatPackage(pkg, "project");
290
+ }
291
+ }
292
+
293
+ return { handled: true, exitCode: 0 };
294
+ }
295
+
296
+ case "update":
297
+ await packageManager.update(source);
298
+ if (source) {
299
+ stdout.write(chalk.green(`Updated ${source}`) + "\n");
300
+ } else {
301
+ stdout.write(chalk.green("Updated packages") + "\n");
302
+ }
303
+ return { handled: true, exitCode: 0 };
304
+ }
305
+ } catch (error) {
306
+ const message = error instanceof Error ? error.message : "Unknown package command error";
307
+ stderr.write(chalk.red(`Error: ${message}`) + "\n");
308
+ return { handled: true, exitCode: 1 };
309
+ }
310
+ }
@@ -333,6 +333,10 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
333
333
  if (!resolvedProvider) {
334
334
  throw new Error("No model selected");
335
335
  }
336
+ const authMode = modelRegistry.getProviderAuthMode(resolvedProvider);
337
+ if (authMode === "externalCli" || authMode === "none") {
338
+ return undefined;
339
+ }
336
340
 
337
341
  // Retry key resolution with backoff to handle transient network failures
338
342
  // (e.g., OAuth token refresh failing due to brief connectivity loss).
@@ -94,6 +94,11 @@ export type {
94
94
  MessageRenderOptions,
95
95
  ProviderConfig,
96
96
  ProviderModelConfig,
97
+ LifecycleHookContext,
98
+ LifecycleHookHandler,
99
+ LifecycleHookMap,
100
+ LifecycleHookPhase,
101
+ LifecycleHookScope,
97
102
  ReadToolCallEvent,
98
103
  RegisteredCommand,
99
104
  RegisteredTool,
@@ -152,6 +157,8 @@ export type {
152
157
  ResolvedResource,
153
158
  } from "./core/package-manager.js";
154
159
  export { DefaultPackageManager } from "./core/package-manager.js";
160
+ export type { PackageCommand, PackageCommandOptions, PackageCommandRunnerOptions, PackageCommandRunnerResult } from "./core/package-commands.js";
161
+ export { getPackageCommandUsage, parsePackageCommand, runPackageCommand } from "./core/package-commands.js";
155
162
  export type { ResourceCollision, ResourceDiagnostic, ResourceLoader } from "./core/resource-loader.js";
156
163
  export { DefaultResourceLoader } from "./core/resource-loader.js";
157
164
  // SDK for programmatic usage
@@ -20,6 +20,7 @@ import type { LoadExtensionsResult } from "./core/extensions/index.js";
20
20
  import { KeybindingsManager } from "./core/keybindings.js";
21
21
  import { ModelRegistry } from "./core/model-registry.js";
22
22
  import { resolveCliModel, resolveModelScope, type ScopedModel } from "./core/model-resolver.js";
23
+ import { runPackageCommand } from "./core/package-commands.js";
23
24
  import { DefaultPackageManager } from "./core/package-manager.js";
24
25
  import { DefaultResourceLoader } from "./core/resource-loader.js";
25
26
  import { type CreateAgentSessionOptions, createAgentSession } from "./core/sdk.js";
@@ -69,237 +70,6 @@ function isTruthyEnvFlag(value: string | undefined): boolean {
69
70
  return value === "1" || value.toLowerCase() === "true" || value.toLowerCase() === "yes";
70
71
  }
71
72
 
72
- type PackageCommand = "install" | "remove" | "update" | "list";
73
-
74
- interface PackageCommandOptions {
75
- command: PackageCommand;
76
- source?: string;
77
- local: boolean;
78
- help: boolean;
79
- invalidOption?: string;
80
- }
81
-
82
- function getPackageCommandUsage(command: PackageCommand): string {
83
- switch (command) {
84
- case "install":
85
- return `${APP_NAME} install <source> [-l]`;
86
- case "remove":
87
- return `${APP_NAME} remove <source> [-l]`;
88
- case "update":
89
- return `${APP_NAME} update [source]`;
90
- case "list":
91
- return `${APP_NAME} list`;
92
- }
93
- }
94
-
95
- function printPackageCommandHelp(command: PackageCommand): void {
96
- switch (command) {
97
- case "install":
98
- console.log(`${chalk.bold("Usage:")}
99
- ${getPackageCommandUsage("install")}
100
-
101
- Install a package and add it to settings.
102
-
103
- Options:
104
- -l, --local Install project-locally (.pi/settings.json)
105
-
106
- Examples:
107
- ${APP_NAME} install npm:@foo/bar
108
- ${APP_NAME} install git:github.com/user/repo
109
- ${APP_NAME} install git:git@github.com:user/repo
110
- ${APP_NAME} install https://github.com/user/repo
111
- ${APP_NAME} install ssh://git@github.com/user/repo
112
- ${APP_NAME} install ./local/path
113
- `);
114
- return;
115
-
116
- case "remove":
117
- console.log(`${chalk.bold("Usage:")}
118
- ${getPackageCommandUsage("remove")}
119
-
120
- Remove a package and its source from settings.
121
-
122
- Options:
123
- -l, --local Remove from project settings (.pi/settings.json)
124
-
125
- Example:
126
- ${APP_NAME} remove npm:@foo/bar
127
- `);
128
- return;
129
-
130
- case "update":
131
- console.log(`${chalk.bold("Usage:")}
132
- ${getPackageCommandUsage("update")}
133
-
134
- Update installed packages.
135
- If <source> is provided, only that package is updated.
136
- `);
137
- return;
138
-
139
- case "list":
140
- console.log(`${chalk.bold("Usage:")}
141
- ${getPackageCommandUsage("list")}
142
-
143
- List installed packages from user and project settings.
144
- `);
145
- return;
146
- }
147
- }
148
-
149
- function parsePackageCommand(args: string[]): PackageCommandOptions | undefined {
150
- const [command, ...rest] = args;
151
- if (command !== "install" && command !== "remove" && command !== "update" && command !== "list") {
152
- return undefined;
153
- }
154
-
155
- let local = false;
156
- let help = false;
157
- let invalidOption: string | undefined;
158
- let source: string | undefined;
159
-
160
- for (const arg of rest) {
161
- if (arg === "-h" || arg === "--help") {
162
- help = true;
163
- continue;
164
- }
165
-
166
- if (arg === "-l" || arg === "--local") {
167
- if (command === "install" || command === "remove") {
168
- local = true;
169
- } else {
170
- invalidOption = invalidOption ?? arg;
171
- }
172
- continue;
173
- }
174
-
175
- if (arg.startsWith("-")) {
176
- invalidOption = invalidOption ?? arg;
177
- continue;
178
- }
179
-
180
- if (!source) {
181
- source = arg;
182
- }
183
- }
184
-
185
- return { command, source, local, help, invalidOption };
186
- }
187
-
188
- async function handlePackageCommand(args: string[]): Promise<boolean> {
189
- const options = parsePackageCommand(args);
190
- if (!options) {
191
- return false;
192
- }
193
-
194
- if (options.help) {
195
- printPackageCommandHelp(options.command);
196
- return true;
197
- }
198
-
199
- if (options.invalidOption) {
200
- console.error(chalk.red(`Unknown option ${options.invalidOption} for "${options.command}".`));
201
- console.error(chalk.dim(`Use "${APP_NAME} --help" or "${getPackageCommandUsage(options.command)}".`));
202
- process.exitCode = 1;
203
- return true;
204
- }
205
-
206
- const source = options.source;
207
- if ((options.command === "install" || options.command === "remove") && !source) {
208
- console.error(chalk.red(`Missing ${options.command} source.`));
209
- console.error(chalk.dim(`Usage: ${getPackageCommandUsage(options.command)}`));
210
- process.exitCode = 1;
211
- return true;
212
- }
213
-
214
- const cwd = process.cwd();
215
- const agentDir = getAgentDir();
216
- const settingsManager = SettingsManager.create(cwd, agentDir);
217
- reportSettingsErrors(settingsManager, "package command");
218
- const packageManager = new DefaultPackageManager({ cwd, agentDir, settingsManager });
219
-
220
- packageManager.setProgressCallback((event) => {
221
- if (event.type === "start") {
222
- process.stdout.write(chalk.dim(`${event.message}\n`));
223
- }
224
- });
225
-
226
- try {
227
- switch (options.command) {
228
- case "install":
229
- await packageManager.install(source!, { local: options.local });
230
- packageManager.addSourceToSettings(source!, { local: options.local });
231
- console.log(chalk.green(`Installed ${source}`));
232
- return true;
233
-
234
- case "remove": {
235
- await packageManager.remove(source!, { local: options.local });
236
- const removed = packageManager.removeSourceFromSettings(source!, { local: options.local });
237
- if (!removed) {
238
- console.error(chalk.red(`No matching package found for ${source}`));
239
- process.exitCode = 1;
240
- return true;
241
- }
242
- console.log(chalk.green(`Removed ${source}`));
243
- return true;
244
- }
245
-
246
- case "list": {
247
- const globalSettings = settingsManager.getGlobalSettings();
248
- const projectSettings = settingsManager.getProjectSettings();
249
- const globalPackages = globalSettings.packages ?? [];
250
- const projectPackages = projectSettings.packages ?? [];
251
-
252
- if (globalPackages.length === 0 && projectPackages.length === 0) {
253
- console.log(chalk.dim("No packages installed."));
254
- return true;
255
- }
256
-
257
- const formatPackage = (pkg: (typeof globalPackages)[number], scope: "user" | "project") => {
258
- const source = typeof pkg === "string" ? pkg : pkg.source;
259
- const filtered = typeof pkg === "object";
260
- const display = filtered ? `${source} (filtered)` : source;
261
- console.log(` ${display}`);
262
- const path = packageManager.getInstalledPath(source, scope);
263
- if (path) {
264
- console.log(chalk.dim(` ${path}`));
265
- }
266
- };
267
-
268
- if (globalPackages.length > 0) {
269
- console.log(chalk.bold("User packages:"));
270
- for (const pkg of globalPackages) {
271
- formatPackage(pkg, "user");
272
- }
273
- }
274
-
275
- if (projectPackages.length > 0) {
276
- if (globalPackages.length > 0) console.log();
277
- console.log(chalk.bold("Project packages:"));
278
- for (const pkg of projectPackages) {
279
- formatPackage(pkg, "project");
280
- }
281
- }
282
-
283
- return true;
284
- }
285
-
286
- case "update":
287
- await packageManager.update(source);
288
- if (source) {
289
- console.log(chalk.green(`Updated ${source}`));
290
- } else {
291
- console.log(chalk.green("Updated packages"));
292
- }
293
- return true;
294
- }
295
- } catch (error: unknown) {
296
- const message = error instanceof Error ? error.message : "Unknown package command error";
297
- console.error(chalk.red(`Error: ${message}`));
298
- process.exitCode = 1;
299
- return true;
300
- }
301
- }
302
-
303
73
  async function prepareInitialMessage(
304
74
  parsed: Args,
305
75
  autoResizeImages: boolean,
@@ -590,7 +360,16 @@ export async function main(args: string[]) {
590
360
  process.env.PI_SKIP_VERSION_CHECK = "1";
591
361
  }
592
362
 
593
- if (await handlePackageCommand(args)) {
363
+ const packageCommand = await runPackageCommand({
364
+ appName: APP_NAME,
365
+ args,
366
+ cwd: process.cwd(),
367
+ agentDir: getAgentDir(),
368
+ stdout: process.stdout,
369
+ stderr: process.stderr,
370
+ });
371
+ if (packageCommand.handled) {
372
+ process.exitCode = packageCommand.exitCode;
594
373
  return;
595
374
  }
596
375
 
package/pkg/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glittercowboy/gsd",
3
- "version": "2.43.0",
3
+ "version": "2.44.0",
4
4
  "piConfig": {
5
5
  "name": "gsd",
6
6
  "configDir": ".gsd"
@@ -11,6 +11,7 @@ import type {
11
11
  import { deriveState } from "./state.js";
12
12
  import { loadFile } from "./files.js";
13
13
  import { isDbAvailable, getMilestoneSlices } from "./gsd-db.js";
14
+ import { parseRoadmap } from "./parsers-legacy.js";
14
15
  import {
15
16
  resolveMilestoneFile, resolveSliceFile, relSliceFile,
16
17
  } from "./paths.js";
@@ -152,13 +153,20 @@ export async function dispatchDirectPhase(
152
153
 
153
154
  case "reassess":
154
155
  case "reassess-roadmap": {
155
- // DB primary path — get completed slices
156
+ // DB primary path — get completed slices, fall back to file parsing when DB has no data
156
157
  let completedSliceIds: string[] = [];
157
158
  if (isDbAvailable()) {
158
159
  completedSliceIds = getMilestoneSlices(mid).filter(s => s.status === "complete").map(s => s.id);
159
- } else {
160
- ctx.ui.notify("Cannot dispatch reassess-roadmap: DB unavailable.", "warning");
161
- return;
160
+ }
161
+ if (completedSliceIds.length === 0) {
162
+ // File-based fallback: parse roadmap checkboxes
163
+ const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
164
+ if (roadmapPath) {
165
+ const roadmapContent = await loadFile(roadmapPath);
166
+ if (roadmapContent) {
167
+ completedSliceIds = parseRoadmap(roadmapContent).slices.filter(s => s.done).map(s => s.id);
168
+ }
169
+ }
162
170
  }
163
171
  if (completedSliceIds.length === 0) {
164
172
  ctx.ui.notify("Cannot dispatch reassess-roadmap: no completed slices.", "warning");
@@ -180,9 +188,16 @@ export async function dispatchDirectPhase(
180
188
  let uatCompletedSliceIds: string[] = [];
181
189
  if (isDbAvailable()) {
182
190
  uatCompletedSliceIds = getMilestoneSlices(mid).filter(s => s.status === "complete").map(s => s.id);
183
- } else {
184
- ctx.ui.notify("Cannot dispatch run-uat: DB unavailable.", "warning");
185
- return;
191
+ }
192
+ if (uatCompletedSliceIds.length === 0) {
193
+ // File-based fallback: parse roadmap checkboxes
194
+ const roadmapPath = resolveMilestoneFile(base, mid, "ROADMAP");
195
+ if (roadmapPath) {
196
+ const roadmapContent = await loadFile(roadmapPath);
197
+ if (roadmapContent) {
198
+ uatCompletedSliceIds = parseRoadmap(roadmapContent).slices.filter(s => s.done).map(s => s.id);
199
+ }
200
+ }
186
201
  }
187
202
  if (uatCompletedSliceIds.length === 0) {
188
203
  ctx.ui.notify("Cannot dispatch run-uat: no completed slices.", "warning");