gsd-pi 2.78.0-dev.aeeb2ca00 → 2.78.1-dev.0fdacd524

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 (471) hide show
  1. package/README.md +8 -7
  2. package/dist/bundled-resource-path.d.ts +7 -0
  3. package/dist/bundled-resource-path.js +34 -2
  4. package/dist/claude-cli-check.js +77 -38
  5. package/dist/cli-policy.d.ts +13 -0
  6. package/dist/cli-policy.js +17 -0
  7. package/dist/cli.js +95 -55
  8. package/dist/headless-query.d.ts +22 -0
  9. package/dist/headless-query.js +43 -8
  10. package/dist/headless.d.ts +10 -0
  11. package/dist/headless.js +16 -1
  12. package/dist/loader.js +9 -13
  13. package/dist/onboarding.d.ts +10 -0
  14. package/dist/onboarding.js +2 -2
  15. package/dist/provider-migrations.d.ts +2 -2
  16. package/dist/provider-migrations.js +5 -2
  17. package/dist/resource-loader.d.ts +5 -2
  18. package/dist/resource-loader.js +30 -13
  19. package/dist/resources/.managed-resources-content-hash +1 -0
  20. package/dist/resources/extensions/claude-code-cli/readiness.js +90 -46
  21. package/dist/resources/extensions/google-search/index.js +2 -6
  22. package/dist/resources/extensions/gsd/auto/loop.js +23 -0
  23. package/dist/resources/extensions/gsd/auto/phases.js +5 -13
  24. package/dist/resources/extensions/gsd/auto/run-unit.js +26 -12
  25. package/dist/resources/extensions/gsd/auto/session.js +5 -6
  26. package/dist/resources/extensions/gsd/auto-dashboard.js +3 -2
  27. package/dist/resources/extensions/gsd/auto-direct-dispatch.js +55 -21
  28. package/dist/resources/extensions/gsd/auto-dispatch.js +18 -6
  29. package/dist/resources/extensions/gsd/auto-prompts.js +69 -2
  30. package/dist/resources/extensions/gsd/auto-recovery.js +43 -4
  31. package/dist/resources/extensions/gsd/auto-runtime-state.js +31 -0
  32. package/dist/resources/extensions/gsd/auto-start.js +1 -1
  33. package/dist/resources/extensions/gsd/auto-tool-tracking.js +2 -2
  34. package/dist/resources/extensions/gsd/auto-worktree.js +60 -13
  35. package/dist/resources/extensions/gsd/auto.js +39 -14
  36. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +14 -2
  37. package/dist/resources/extensions/gsd/bootstrap/exec-tools.js +7 -5
  38. package/dist/resources/extensions/gsd/bootstrap/query-tools.js +2 -2
  39. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +5 -4
  40. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +112 -31
  41. package/dist/resources/extensions/gsd/bootstrap/register-shortcuts.js +11 -6
  42. package/dist/resources/extensions/gsd/bootstrap/subagent-input.js +22 -0
  43. package/dist/resources/extensions/gsd/bootstrap/system-context.js +45 -8
  44. package/dist/resources/extensions/gsd/bootstrap/write-gate.js +121 -3
  45. package/dist/resources/extensions/gsd/commands/catalog.js +76 -5
  46. package/dist/resources/extensions/gsd/commands/handlers/core.js +23 -1
  47. package/dist/resources/extensions/gsd/commands/handlers/ops.js +8 -0
  48. package/dist/resources/extensions/gsd/commands-config.js +3 -2
  49. package/dist/resources/extensions/gsd/commands-extensions.js +46 -3
  50. package/dist/resources/extensions/gsd/commands-handlers.js +3 -2
  51. package/dist/resources/extensions/gsd/commands-mcp-status.js +3 -1
  52. package/dist/resources/extensions/gsd/commands-prefs-wizard.js +10 -1
  53. package/dist/resources/extensions/gsd/commands-worktree.js +309 -0
  54. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -1
  55. package/dist/resources/extensions/gsd/docs/preferences-reference.md +10 -0
  56. package/dist/resources/extensions/gsd/doctor-providers.js +2 -1
  57. package/dist/resources/extensions/gsd/doctor-runtime-checks.js +39 -1
  58. package/dist/resources/extensions/gsd/error-classifier.js +1 -1
  59. package/dist/resources/extensions/gsd/forensics.js +10 -8
  60. package/dist/resources/extensions/gsd/git-service.js +12 -5
  61. package/dist/resources/extensions/gsd/gsd-db.js +11 -2
  62. package/dist/resources/extensions/gsd/guided-flow.js +25 -24
  63. package/dist/resources/extensions/gsd/home-dir.js +16 -0
  64. package/dist/resources/extensions/gsd/key-manager.js +2 -1
  65. package/dist/resources/extensions/gsd/memory-store.js +66 -31
  66. package/dist/resources/extensions/gsd/migrate/command.js +3 -2
  67. package/dist/resources/extensions/gsd/milestone-id-reservation.js +36 -0
  68. package/dist/resources/extensions/gsd/model-router.js +114 -9
  69. package/dist/resources/extensions/gsd/native-git-bridge.js +7 -1
  70. package/dist/resources/extensions/gsd/preferences-models.js +91 -15
  71. package/dist/resources/extensions/gsd/preferences-types.js +2 -0
  72. package/dist/resources/extensions/gsd/preferences-validation.js +32 -0
  73. package/dist/resources/extensions/gsd/preferences.js +5 -3
  74. package/dist/resources/extensions/gsd/prompt-loader.js +23 -12
  75. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +10 -0
  76. package/dist/resources/extensions/gsd/prompts/complete-slice.md +10 -0
  77. package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  78. package/dist/resources/extensions/gsd/prompts/parallel-research-slices.md +2 -0
  79. package/dist/resources/extensions/gsd/prompts/plan-slice.md +10 -0
  80. package/dist/resources/extensions/gsd/prompts/refine-slice.md +10 -0
  81. package/dist/resources/extensions/gsd/prompts/rewrite-docs.md +2 -0
  82. package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +9 -3
  83. package/dist/resources/extensions/gsd/state.js +42 -0
  84. package/dist/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
  85. package/dist/resources/extensions/gsd/tools/memory-tools.js +18 -1
  86. package/dist/resources/extensions/gsd/unit-context-manifest.js +29 -4
  87. package/dist/resources/extensions/gsd/visualizer-overlay.js +1 -1
  88. package/dist/resources/extensions/gsd/watch/header-renderer.js +3 -1
  89. package/dist/resources/extensions/gsd/worktree-command.js +26 -46
  90. package/dist/resources/extensions/gsd/worktree-manager.js +20 -1
  91. package/dist/resources/extensions/gsd/worktree-resolver.js +4 -13
  92. package/dist/resources/extensions/gsd/worktree-root.js +124 -0
  93. package/dist/resources/extensions/gsd/worktree-session-state.js +33 -0
  94. package/dist/resources/extensions/gsd/worktree.js +4 -115
  95. package/dist/resources/extensions/mcp-client/index.js +6 -9
  96. package/dist/resources/extensions/ollama/index.js +15 -2
  97. package/dist/resources/extensions/ollama/model-capabilities.js +31 -0
  98. package/dist/resources/extensions/ollama/ollama-client.js +40 -4
  99. package/dist/resources/extensions/slash-commands/create-extension.js +36 -22
  100. package/dist/resources/extensions/subagent/index.js +324 -178
  101. package/dist/resources/skills/create-gsd-extension/SKILL.md +9 -5
  102. package/dist/resources/skills/create-gsd-extension/references/custom-commands.md +1 -1
  103. package/dist/resources/skills/create-gsd-extension/references/custom-rendering.md +5 -5
  104. package/dist/resources/skills/create-gsd-extension/references/custom-tools.md +4 -4
  105. package/dist/resources/skills/create-gsd-extension/references/custom-ui.md +6 -6
  106. package/dist/resources/skills/create-gsd-extension/references/events-reference.md +3 -3
  107. package/dist/resources/skills/create-gsd-extension/references/packaging-distribution.md +1 -1
  108. package/dist/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +3 -3
  109. package/dist/resources/skills/create-gsd-extension/workflows/create-extension.md +32 -12
  110. package/dist/resources/skills/lint/SKILL.md +4 -0
  111. package/dist/resources/skills/review/SKILL.md +4 -0
  112. package/dist/resources/skills/test/SKILL.md +3 -0
  113. package/dist/rtk-shared.d.ts +3 -0
  114. package/dist/rtk-shared.js +17 -0
  115. package/dist/rtk.d.ts +2 -5
  116. package/dist/rtk.js +3 -20
  117. package/dist/runtime-checks.d.ts +27 -0
  118. package/dist/runtime-checks.js +38 -0
  119. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  120. package/dist/web/standalone/.next/BUILD_ID +1 -1
  121. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  122. package/dist/web/standalone/.next/build-manifest.json +3 -3
  123. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  124. package/dist/web/standalone/.next/react-loadable-manifest.json +44 -4
  125. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  126. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  127. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  132. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  133. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  134. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  136. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  137. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  138. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  139. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  140. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  141. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  142. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  143. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/session/events/route.js +4 -2
  146. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  147. package/dist/web/standalone/.next/server/app/index.html +1 -1
  148. package/dist/web/standalone/.next/server/app/index.rsc +2 -2
  149. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  150. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +2 -2
  151. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  152. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  153. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  154. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  156. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  158. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  160. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  161. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  162. package/dist/web/standalone/.next/server/webpack-runtime.js +1 -1
  163. package/dist/web/standalone/.next/static/chunks/2556.0527fea66e123b7f.js +1 -0
  164. package/dist/web/standalone/.next/static/chunks/2824.08296bc2f9654698.js +1 -0
  165. package/dist/web/standalone/.next/static/chunks/3026.3af53b279375f082.js +1 -0
  166. package/dist/web/standalone/.next/static/chunks/315.6f68ae79b67d25cf.js +1 -0
  167. package/dist/web/standalone/.next/static/chunks/3497.4bfc60a3b3dea717.js +1 -0
  168. package/dist/web/standalone/.next/static/chunks/5516.4a07c872b5c3a663.js +1 -0
  169. package/dist/web/standalone/.next/static/chunks/8336.31b019697882acfb.js +10 -0
  170. package/dist/web/standalone/.next/static/chunks/8845.c9702695e8c5a9c5.js +2 -0
  171. package/dist/web/standalone/.next/static/chunks/9058.01ef3a463bda88f1.js +20 -0
  172. package/dist/web/standalone/.next/static/chunks/9441.1081da1125d1764f.js +1 -0
  173. package/dist/web/standalone/.next/static/chunks/app/{page-5b113fd32bc2a1c3.js → page-9bf2e0c50fb2ca05.js} +1 -1
  174. package/dist/web/standalone/.next/static/chunks/webpack-f9f0dc45e4f3ac10.js +1 -0
  175. package/dist/web/standalone/package.json +2 -1
  176. package/dist/welcome-screen.js +27 -1
  177. package/dist/worktree-cli.d.ts +1 -0
  178. package/dist/worktree-cli.js +9 -3
  179. package/dist/worktree-status-banner.d.ts +1 -0
  180. package/dist/worktree-status-banner.js +132 -0
  181. package/package.json +1 -3
  182. package/packages/daemon/package.json +2 -2
  183. package/packages/mcp-server/dist/alias-telemetry.d.ts +8 -0
  184. package/packages/mcp-server/dist/alias-telemetry.d.ts.map +1 -0
  185. package/packages/mcp-server/dist/alias-telemetry.js +30 -0
  186. package/packages/mcp-server/dist/alias-telemetry.js.map +1 -0
  187. package/packages/mcp-server/dist/workflow-tools.d.ts.map +1 -1
  188. package/packages/mcp-server/dist/workflow-tools.js +74 -46
  189. package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
  190. package/packages/mcp-server/package.json +2 -2
  191. package/packages/mcp-server/src/alias-telemetry.test.ts +78 -0
  192. package/packages/mcp-server/src/alias-telemetry.ts +30 -0
  193. package/packages/mcp-server/src/workflow-tools.test.ts +78 -0
  194. package/packages/mcp-server/src/workflow-tools.ts +93 -58
  195. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  196. package/packages/native/package.json +1 -1
  197. package/packages/native/tsconfig.tsbuildinfo +1 -1
  198. package/packages/pi-agent-core/package.json +1 -1
  199. package/packages/pi-agent-core/tsconfig.tsbuildinfo +1 -1
  200. package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.d.ts +2 -0
  201. package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.d.ts.map +1 -0
  202. package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.js +231 -0
  203. package/packages/pi-ai/dist/providers/anthropic-shared.cache-breakpoint.test.js.map +1 -0
  204. package/packages/pi-ai/dist/providers/anthropic-shared.d.ts.map +1 -1
  205. package/packages/pi-ai/dist/providers/anthropic-shared.js +48 -19
  206. package/packages/pi-ai/dist/providers/anthropic-shared.js.map +1 -1
  207. package/packages/pi-ai/dist/types.d.ts +13 -0
  208. package/packages/pi-ai/dist/types.d.ts.map +1 -1
  209. package/packages/pi-ai/dist/types.js.map +1 -1
  210. package/packages/pi-ai/dist/utils/repair-tool-json.d.ts.map +1 -1
  211. package/packages/pi-ai/dist/utils/repair-tool-json.js +24 -3
  212. package/packages/pi-ai/dist/utils/repair-tool-json.js.map +1 -1
  213. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js +26 -0
  214. package/packages/pi-ai/dist/utils/tests/repair-tool-json.test.js.map +1 -1
  215. package/packages/pi-ai/package.json +1 -1
  216. package/packages/pi-ai/src/providers/anthropic-shared.cache-breakpoint.test.ts +289 -0
  217. package/packages/pi-ai/src/providers/anthropic-shared.ts +52 -20
  218. package/packages/pi-ai/src/types.ts +13 -0
  219. package/packages/pi-ai/src/utils/repair-tool-json.ts +24 -3
  220. package/packages/pi-ai/src/utils/tests/repair-tool-json.test.ts +32 -0
  221. package/packages/pi-ai/tsconfig.tsbuildinfo +1 -1
  222. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  223. package/packages/pi-coding-agent/dist/core/agent-session.js +6 -0
  224. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  225. package/packages/pi-coding-agent/dist/core/messages.d.ts.map +1 -1
  226. package/packages/pi-coding-agent/dist/core/messages.js +4 -0
  227. package/packages/pi-coding-agent/dist/core/messages.js.map +1 -1
  228. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js +19 -2
  229. package/packages/pi-coding-agent/dist/core/model-registry-auth-mode.test.js.map +1 -1
  230. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +10 -0
  231. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  232. package/packages/pi-coding-agent/dist/core/model-registry.js +18 -0
  233. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  234. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts +13 -0
  235. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  236. package/packages/pi-coding-agent/dist/core/system-prompt.js +20 -16
  237. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  238. package/packages/pi-coding-agent/dist/core/token-telemetry.d.ts +37 -0
  239. package/packages/pi-coding-agent/dist/core/token-telemetry.d.ts.map +1 -0
  240. package/packages/pi-coding-agent/dist/core/token-telemetry.js +49 -0
  241. package/packages/pi-coding-agent/dist/core/token-telemetry.js.map +1 -0
  242. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.d.ts +2 -0
  243. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.d.ts.map +1 -0
  244. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js +133 -0
  245. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.js.map +1 -0
  246. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js +1 -1
  247. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.js.map +1 -1
  248. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js +14 -1
  249. package/packages/pi-coding-agent/dist/modes/interactive/controllers/input-controller.test.js.map +1 -1
  250. package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.d.ts +2 -0
  251. package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.d.ts.map +1 -0
  252. package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.js +78 -0
  253. package/packages/pi-coding-agent/dist/tests/system-prompt-cache-stability.test.js.map +1 -0
  254. package/packages/pi-coding-agent/dist/tests/token-telemetry.test.d.ts +2 -0
  255. package/packages/pi-coding-agent/dist/tests/token-telemetry.test.d.ts.map +1 -0
  256. package/packages/pi-coding-agent/dist/tests/token-telemetry.test.js +181 -0
  257. package/packages/pi-coding-agent/dist/tests/token-telemetry.test.js.map +1 -0
  258. package/packages/pi-coding-agent/package.json +1 -1
  259. package/packages/pi-coding-agent/src/core/agent-session.ts +7 -0
  260. package/packages/pi-coding-agent/src/core/messages.ts +4 -0
  261. package/packages/pi-coding-agent/src/core/model-registry-auth-mode.test.ts +32 -2
  262. package/packages/pi-coding-agent/src/core/model-registry.ts +21 -0
  263. package/packages/pi-coding-agent/src/core/system-prompt.ts +33 -15
  264. package/packages/pi-coding-agent/src/core/token-telemetry.ts +77 -0
  265. package/packages/pi-coding-agent/src/modes/interactive/components/tool-card-cleanup-and-success-runtime.test.ts +212 -0
  266. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.test.ts +17 -1
  267. package/packages/pi-coding-agent/src/modes/interactive/controllers/input-controller.ts +1 -1
  268. package/packages/pi-coding-agent/src/tests/system-prompt-cache-stability.test.ts +102 -0
  269. package/packages/pi-coding-agent/src/tests/token-telemetry.test.ts +200 -0
  270. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  271. package/packages/pi-tui/dist/__tests__/autocomplete.test.js +17 -3
  272. package/packages/pi-tui/dist/__tests__/autocomplete.test.js.map +1 -1
  273. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.d.ts +2 -0
  274. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.d.ts.map +1 -0
  275. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.js +161 -0
  276. package/packages/pi-tui/dist/components/__tests__/leak-fixes-runtime.test.js.map +1 -0
  277. package/packages/pi-tui/package.json +1 -1
  278. package/packages/pi-tui/src/__tests__/autocomplete.test.ts +20 -3
  279. package/packages/pi-tui/src/components/__tests__/leak-fixes-runtime.test.ts +219 -0
  280. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  281. package/packages/rpc-client/package.json +1 -1
  282. package/pkg/package.json +1 -1
  283. package/src/resources/extensions/claude-code-cli/readiness.ts +92 -47
  284. package/src/resources/extensions/google-search/index.ts +2 -9
  285. package/src/resources/extensions/gsd/auto/loop.ts +24 -2
  286. package/src/resources/extensions/gsd/auto/phases.ts +6 -14
  287. package/src/resources/extensions/gsd/auto/run-unit.ts +26 -12
  288. package/src/resources/extensions/gsd/auto/session.ts +5 -6
  289. package/src/resources/extensions/gsd/auto/types.ts +1 -0
  290. package/src/resources/extensions/gsd/auto-dashboard.ts +3 -2
  291. package/src/resources/extensions/gsd/auto-direct-dispatch.ts +60 -24
  292. package/src/resources/extensions/gsd/auto-dispatch.ts +18 -6
  293. package/src/resources/extensions/gsd/auto-prompts.ts +66 -2
  294. package/src/resources/extensions/gsd/auto-recovery.ts +46 -8
  295. package/src/resources/extensions/gsd/auto-runtime-state.ts +51 -0
  296. package/src/resources/extensions/gsd/auto-start.ts +1 -1
  297. package/src/resources/extensions/gsd/auto-tool-tracking.ts +2 -4
  298. package/src/resources/extensions/gsd/auto-worktree.ts +82 -12
  299. package/src/resources/extensions/gsd/auto.ts +37 -10
  300. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +15 -13
  301. package/src/resources/extensions/gsd/bootstrap/exec-tools.ts +8 -7
  302. package/src/resources/extensions/gsd/bootstrap/query-tools.ts +2 -2
  303. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +10 -9
  304. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +121 -31
  305. package/src/resources/extensions/gsd/bootstrap/register-shortcuts.ts +12 -6
  306. package/src/resources/extensions/gsd/bootstrap/subagent-input.ts +20 -0
  307. package/src/resources/extensions/gsd/bootstrap/system-context.ts +50 -8
  308. package/src/resources/extensions/gsd/bootstrap/write-gate.ts +141 -11
  309. package/src/resources/extensions/gsd/commands/catalog.ts +82 -5
  310. package/src/resources/extensions/gsd/commands/handlers/core.ts +23 -1
  311. package/src/resources/extensions/gsd/commands/handlers/ops.ts +10 -0
  312. package/src/resources/extensions/gsd/commands-config.ts +3 -2
  313. package/src/resources/extensions/gsd/commands-extensions.ts +43 -3
  314. package/src/resources/extensions/gsd/commands-handlers.ts +3 -2
  315. package/src/resources/extensions/gsd/commands-mcp-status.ts +3 -1
  316. package/src/resources/extensions/gsd/commands-prefs-wizard.ts +15 -1
  317. package/src/resources/extensions/gsd/commands-worktree.ts +383 -0
  318. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -1
  319. package/src/resources/extensions/gsd/docs/preferences-reference.md +10 -0
  320. package/src/resources/extensions/gsd/doctor-providers.ts +2 -1
  321. package/src/resources/extensions/gsd/doctor-runtime-checks.ts +39 -1
  322. package/src/resources/extensions/gsd/doctor-types.ts +3 -1
  323. package/src/resources/extensions/gsd/error-classifier.ts +1 -1
  324. package/src/resources/extensions/gsd/forensics.ts +12 -7
  325. package/src/resources/extensions/gsd/git-service.ts +13 -5
  326. package/src/resources/extensions/gsd/gsd-db.ts +12 -2
  327. package/src/resources/extensions/gsd/guided-flow.ts +27 -26
  328. package/src/resources/extensions/gsd/home-dir.ts +19 -0
  329. package/src/resources/extensions/gsd/journal.ts +4 -1
  330. package/src/resources/extensions/gsd/key-manager.ts +2 -1
  331. package/src/resources/extensions/gsd/memory-store.ts +81 -28
  332. package/src/resources/extensions/gsd/migrate/command.ts +3 -2
  333. package/src/resources/extensions/gsd/milestone-id-reservation.ts +47 -0
  334. package/src/resources/extensions/gsd/model-router.ts +172 -9
  335. package/src/resources/extensions/gsd/native-git-bridge.ts +7 -1
  336. package/src/resources/extensions/gsd/preferences-models.ts +101 -15
  337. package/src/resources/extensions/gsd/preferences-types.ts +6 -0
  338. package/src/resources/extensions/gsd/preferences-validation.ts +35 -0
  339. package/src/resources/extensions/gsd/preferences.ts +16 -2
  340. package/src/resources/extensions/gsd/prompt-loader.ts +26 -12
  341. package/src/resources/extensions/gsd/prompts/complete-milestone.md +10 -0
  342. package/src/resources/extensions/gsd/prompts/complete-slice.md +10 -0
  343. package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
  344. package/src/resources/extensions/gsd/prompts/parallel-research-slices.md +2 -0
  345. package/src/resources/extensions/gsd/prompts/plan-slice.md +10 -0
  346. package/src/resources/extensions/gsd/prompts/refine-slice.md +10 -0
  347. package/src/resources/extensions/gsd/prompts/rewrite-docs.md +2 -0
  348. package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +9 -3
  349. package/src/resources/extensions/gsd/state.ts +42 -0
  350. package/src/resources/extensions/gsd/templates/PREFERENCES.md +1 -0
  351. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +179 -1
  352. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +58 -0
  353. package/src/resources/extensions/gsd/tests/auto-session-encapsulation.test.ts +24 -5
  354. package/src/resources/extensions/gsd/tests/auto-supervisor.test.mjs +21 -4
  355. package/src/resources/extensions/gsd/tests/bootstrap-derive-state-db-open.test.ts +1 -1
  356. package/src/resources/extensions/gsd/tests/budget-prediction.test.ts +138 -211
  357. package/src/resources/extensions/gsd/tests/bundled-skill-triggers.test.ts +50 -27
  358. package/src/resources/extensions/gsd/tests/commands-extensions-version-compare.test.ts +58 -0
  359. package/src/resources/extensions/gsd/tests/commands-worktree-clean.test.ts +48 -0
  360. package/src/resources/extensions/gsd/tests/complete-slice-verification-gate.test.ts +142 -59
  361. package/src/resources/extensions/gsd/tests/complete-slice.test.ts +7 -4
  362. package/src/resources/extensions/gsd/tests/completed-at-reconcile.test.ts +89 -32
  363. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +41 -23
  364. package/src/resources/extensions/gsd/tests/db-path-worktree-symlink.test.ts +3 -43
  365. package/src/resources/extensions/gsd/tests/debug-logger.test.ts +5 -3
  366. package/src/resources/extensions/gsd/tests/deferred-milestone-dir-4996.test.ts +116 -0
  367. package/src/resources/extensions/gsd/tests/discuss-empty-db-fallback.test.ts +22 -87
  368. package/src/resources/extensions/gsd/tests/discuss-queued-milestones.test.ts +7 -118
  369. package/src/resources/extensions/gsd/tests/discuss-tool-scope-leak.test.ts +18 -60
  370. package/src/resources/extensions/gsd/tests/doctor-orphan-milestone-4996.test.ts +100 -0
  371. package/src/resources/extensions/gsd/tests/double-merge-guard.test.ts +14 -76
  372. package/src/resources/extensions/gsd/tests/ensure-preconditions-guard-4996.test.ts +93 -0
  373. package/src/resources/extensions/gsd/tests/false-degraded-mode-warning.test.ts +22 -83
  374. package/src/resources/extensions/gsd/tests/finalize-timeout-guard.test.ts +1 -63
  375. package/src/resources/extensions/gsd/tests/find-missing-summaries-closed-runtime.test.ts +47 -0
  376. package/src/resources/extensions/gsd/tests/forensics-stuck-loops.test.ts +26 -1
  377. package/src/resources/extensions/gsd/tests/gitignore-bg-shell-runtime.test.ts +63 -0
  378. package/src/resources/extensions/gsd/tests/google-search-stub.test.ts +25 -65
  379. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +30 -0
  380. package/src/resources/extensions/gsd/tests/gsd-no-project-error-runtime.test.ts +81 -0
  381. package/src/resources/extensions/gsd/tests/headless-answers.test.ts +14 -4
  382. package/src/resources/extensions/gsd/tests/health-widget.test.ts +22 -12
  383. package/src/resources/extensions/gsd/tests/help-menu-coverage.test.ts +57 -0
  384. package/src/resources/extensions/gsd/tests/home-dir.test.ts +52 -0
  385. package/src/resources/extensions/gsd/tests/import-done-milestones-runtime.test.ts +145 -0
  386. package/src/resources/extensions/gsd/tests/init-prefs-routing.test.ts +64 -1
  387. package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +72 -1
  388. package/src/resources/extensions/gsd/tests/integration/token-savings.test.ts +0 -23
  389. package/src/resources/extensions/gsd/tests/memory-store.test.ts +128 -0
  390. package/src/resources/extensions/gsd/tests/memory-tools.test.ts +33 -1
  391. package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +124 -0
  392. package/src/resources/extensions/gsd/tests/milestone-id-gap-reuse-4996.test.ts +152 -0
  393. package/src/resources/extensions/gsd/tests/milestone-report-path.test.ts +18 -1
  394. package/src/resources/extensions/gsd/tests/model-router.test.ts +169 -8
  395. package/src/resources/extensions/gsd/tests/native-git-infra-errors.test.ts +50 -0
  396. package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +8 -0
  397. package/src/resources/extensions/gsd/tests/parallel-crash-recovery.test.ts +32 -43
  398. package/src/resources/extensions/gsd/tests/phases-merge-error-stops-auto.test.ts +4 -10
  399. package/src/resources/extensions/gsd/tests/preferences.test.ts +127 -0
  400. package/src/resources/extensions/gsd/tests/prompt-step-ordering.test.ts +16 -0
  401. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +7 -0
  402. package/src/resources/extensions/gsd/tests/quick-turn-end-cleanup.test.ts +6 -6
  403. package/src/resources/extensions/gsd/tests/register-hooks-compaction-checkpoint.test.ts +93 -0
  404. package/src/resources/extensions/gsd/tests/safety-harness-false-positives.test.ts +34 -0
  405. package/src/resources/extensions/gsd/tests/session-start-footer.test.ts +168 -19
  406. package/src/resources/extensions/gsd/tests/slice-parallel-orchestrator.test.ts +7 -1
  407. package/src/resources/extensions/gsd/tests/smart-entry-complete.test.ts +23 -1
  408. package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +17 -1
  409. package/src/resources/extensions/gsd/tests/system-context-message-routing.test.ts +101 -0
  410. package/src/resources/extensions/gsd/tests/token-profile.test.ts +51 -4
  411. package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +7 -16
  412. package/src/resources/extensions/gsd/tests/unit-context-manifest.test.ts +38 -3
  413. package/src/resources/extensions/gsd/tests/unstructured-continue-context-injection.test.ts +5 -7
  414. package/src/resources/extensions/gsd/tests/uok-gitops-turn-action.test.ts +15 -1
  415. package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -6
  416. package/src/resources/extensions/gsd/tests/worktree-path-injection.test.ts +235 -0
  417. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +34 -33
  418. package/src/resources/extensions/gsd/tests/worktree.test.ts +8 -0
  419. package/src/resources/extensions/gsd/tests/write-gate-planning-unit.test.ts +131 -1
  420. package/src/resources/extensions/gsd/tools/memory-tools.ts +17 -1
  421. package/src/resources/extensions/gsd/unit-context-manifest.ts +44 -12
  422. package/src/resources/extensions/gsd/visualizer-overlay.ts +1 -1
  423. package/src/resources/extensions/gsd/watch/header-renderer.ts +3 -1
  424. package/src/resources/extensions/gsd/workflow-logger.ts +1 -0
  425. package/src/resources/extensions/gsd/worktree-command.ts +31 -44
  426. package/src/resources/extensions/gsd/worktree-manager.ts +40 -1
  427. package/src/resources/extensions/gsd/worktree-resolver.ts +4 -14
  428. package/src/resources/extensions/gsd/worktree-root.ts +144 -0
  429. package/src/resources/extensions/gsd/worktree-session-state.ts +35 -0
  430. package/src/resources/extensions/gsd/worktree.ts +8 -119
  431. package/src/resources/extensions/mcp-client/index.ts +6 -10
  432. package/src/resources/extensions/mcp-client/tests/global-config.test.ts +91 -0
  433. package/src/resources/extensions/ollama/index.ts +16 -2
  434. package/src/resources/extensions/ollama/model-capabilities.ts +34 -0
  435. package/src/resources/extensions/ollama/ollama-client.ts +41 -4
  436. package/src/resources/extensions/ollama/tests/model-capabilities.test.ts +96 -0
  437. package/src/resources/extensions/ollama/tests/ollama-client-timeout-env.test.ts +147 -0
  438. package/src/resources/extensions/slash-commands/create-extension.ts +38 -24
  439. package/src/resources/extensions/subagent/index.ts +165 -7
  440. package/src/resources/skills/create-gsd-extension/SKILL.md +9 -5
  441. package/src/resources/skills/create-gsd-extension/references/custom-commands.md +1 -1
  442. package/src/resources/skills/create-gsd-extension/references/custom-rendering.md +5 -5
  443. package/src/resources/skills/create-gsd-extension/references/custom-tools.md +4 -4
  444. package/src/resources/skills/create-gsd-extension/references/custom-ui.md +6 -6
  445. package/src/resources/skills/create-gsd-extension/references/events-reference.md +3 -3
  446. package/src/resources/skills/create-gsd-extension/references/packaging-distribution.md +1 -1
  447. package/src/resources/skills/create-gsd-extension/references/remote-execution-overrides.md +3 -3
  448. package/src/resources/skills/create-gsd-extension/templates/extension-skeleton.ts +2 -2
  449. package/src/resources/skills/create-gsd-extension/templates/stateful-tool-skeleton.ts +3 -3
  450. package/src/resources/skills/create-gsd-extension/templates/templates.test.ts +58 -0
  451. package/src/resources/skills/create-gsd-extension/workflows/create-extension.md +32 -12
  452. package/src/resources/skills/lint/SKILL.md +4 -0
  453. package/src/resources/skills/review/SKILL.md +4 -0
  454. package/src/resources/skills/test/SKILL.md +3 -0
  455. package/dist/resources/extensions/browser-tools/tests/browser-tools-integration.test.mjs +0 -601
  456. package/dist/resources/extensions/browser-tools/tests/browser-tools-unit.test.cjs +0 -651
  457. package/dist/resources/extensions/browser-tools/tests/capture-sharp-optional.test.cjs +0 -91
  458. package/dist/resources/extensions/gsd/tests/auto-supervisor.test.mjs +0 -53
  459. package/dist/resources/extensions/gsd/tests/dist-redirect.mjs +0 -112
  460. package/dist/resources/extensions/gsd/tests/resolve-ts-hooks.mjs +0 -23
  461. package/dist/resources/extensions/gsd/tests/resolve-ts.mjs +0 -5
  462. package/dist/resources/skills/github-workflows/references/gh/tests/__init__.py +0 -0
  463. package/dist/resources/skills/github-workflows/references/gh/tests/test_github_project_setup.py +0 -608
  464. package/dist/web/standalone/.next/static/chunks/2826.e9f5195e91f9cad2.js +0 -11
  465. package/dist/web/standalone/.next/static/chunks/3621.fc7480022c972438.js +0 -20
  466. package/dist/web/standalone/.next/static/chunks/webpack-2e68521d7c82f7c2.js +0 -1
  467. package/src/resources/extensions/gsd/tests/copy-planning-artifacts-samepath.test.ts +0 -22
  468. package/src/resources/extensions/gsd/tests/discuss-slice-structured-questions.test.ts +0 -47
  469. package/src/resources/extensions/gsd/tests/empty-content-abort-loop.test.ts +0 -75
  470. /package/dist/web/standalone/.next/static/{cAJH99yNS1UPbeSEiNRrV → 4iu6IYeYfxOq8OidlDqp6}/_buildManifest.js +0 -0
  471. /package/dist/web/standalone/.next/static/{cAJH99yNS1UPbeSEiNRrV → 4iu6IYeYfxOq8OidlDqp6}/_ssgManifest.js +0 -0
@@ -1,608 +0,0 @@
1
- """Tests for github_project_setup.py — milestone/issue workflow automation.
2
-
3
- Each test class maps to one CLI command (one step in the workflow):
4
-
5
- Step 1 labels — create/update label taxonomy
6
- Step 2 milestone list — list milestones
7
- Step 3 milestone create — create a new milestone
8
- Step 4 issue create — create an issue with labels and optional milestone
9
- Step 5 milestone start — bulk-transition status:needs-grooming → status:in-progress
10
- Step 6 issue list — list issues (post-start verification)
11
-
12
- Tests: every happy-path and key error-path for each command
13
- How: Typer CliRunner + unittest.mock to mock PyGithub calls (no network)
14
- Why: Prove each workflow step executes correctly and exits with the right code
15
- """
16
-
17
- from __future__ import annotations
18
-
19
- import importlib.util
20
- import sys
21
- from pathlib import Path
22
- from unittest.mock import MagicMock, patch
23
-
24
- from typer.testing import CliRunner
25
-
26
- # ---------------------------------------------------------------------------
27
- # Load github_project_setup as a module (filename contains underscores so
28
- # a plain import works, but we use importlib for clarity and path safety).
29
- # ---------------------------------------------------------------------------
30
- _SCRIPT = Path(__file__).parent.parent / "scripts" / "github_project_setup.py"
31
- _spec = importlib.util.spec_from_file_location("github_project_setup", _SCRIPT)
32
- assert _spec is not None, f"Cannot find spec for {_SCRIPT}"
33
- assert _spec.loader is not None, f"Cannot find loader for {_SCRIPT}"
34
- _gps = importlib.util.module_from_spec(_spec)
35
- sys.modules["github_project_setup"] = _gps
36
- _spec.loader.exec_module(_gps)
37
-
38
- app = _gps.app
39
-
40
- runner = CliRunner()
41
-
42
-
43
- # ---------------------------------------------------------------------------
44
- # Shared helpers
45
- # ---------------------------------------------------------------------------
46
-
47
-
48
- def _make_label(name: str) -> MagicMock:
49
- lbl = MagicMock()
50
- lbl.name = name
51
- return lbl
52
-
53
-
54
- def _make_issue(number: int, title: str, labels: list[str]) -> MagicMock:
55
- issue = MagicMock()
56
- issue.number = number
57
- issue.title = title
58
- issue.labels = [_make_label(n) for n in labels]
59
- return issue
60
-
61
-
62
- def _make_milestone(
63
- number: int,
64
- title: str,
65
- state: str = "open",
66
- open_issues: int = 2,
67
- closed_issues: int = 1,
68
- due_on: object = None,
69
- html_url: str = "https://github.com/owner/repo/milestone/1",
70
- ) -> MagicMock:
71
- m = MagicMock()
72
- m.number = number
73
- m.title = title
74
- m.state = state
75
- m.open_issues = open_issues
76
- m.closed_issues = closed_issues
77
- m.due_on = due_on
78
- m.html_url = html_url
79
- return m
80
-
81
-
82
- # ---------------------------------------------------------------------------
83
- # Step 1 — labels command
84
- # ---------------------------------------------------------------------------
85
-
86
-
87
- class TestLabelsCommand:
88
- """Step 1: create/update the label taxonomy."""
89
-
90
- def test_creates_missing_labels(self) -> None:
91
- """Labels that don't exist are created; output confirms creation."""
92
- mock_repo = MagicMock()
93
- mock_repo.get_labels.return_value = [] # no existing labels
94
-
95
- with (
96
- patch.dict("os.environ", {"GITHUB_TOKEN": "test-token"}),
97
- patch("github_project_setup.get_repo", return_value=mock_repo),
98
- patch("github_project_setup.Github"),
99
- ):
100
- result = runner.invoke(app, ["labels", "--repo", "owner/repo"])
101
-
102
- assert result.exit_code == 0, result.output
103
- assert mock_repo.create_label.called
104
- assert "created" in result.output
105
-
106
- def test_skips_existing_labels_without_force(self) -> None:
107
- """Existing labels are skipped when --force is not passed."""
108
- existing = _make_label("priority:p0")
109
- mock_repo = MagicMock()
110
- mock_repo.get_labels.return_value = [existing]
111
-
112
- with (
113
- patch.dict("os.environ", {"GITHUB_TOKEN": "test-token"}),
114
- patch("github_project_setup.get_repo", return_value=mock_repo),
115
- patch("github_project_setup.Github"),
116
- ):
117
- result = runner.invoke(app, ["labels", "--repo", "owner/repo"])
118
-
119
- assert result.exit_code == 0, result.output
120
- assert "exists" in result.output
121
-
122
- def test_force_updates_existing_labels(self) -> None:
123
- """--force flag causes existing labels to be updated."""
124
- existing_label = _make_label("priority:p0")
125
- mock_repo = MagicMock()
126
- mock_repo.get_labels.return_value = [existing_label]
127
-
128
- with (
129
- patch.dict("os.environ", {"GITHUB_TOKEN": "test-token"}),
130
- patch("github_project_setup.get_repo", return_value=mock_repo),
131
- patch("github_project_setup.Github"),
132
- ):
133
- result = runner.invoke(app, ["labels", "--repo", "owner/repo", "--force"])
134
-
135
- assert result.exit_code == 0, result.output
136
- assert existing_label.edit.called
137
- assert "updated" in result.output
138
-
139
- def test_missing_token_exits_nonzero(self) -> None:
140
- """Missing GITHUB_TOKEN exits with code 1."""
141
- env = {k: v for k, v in __import__("os").environ.items() if k != "GITHUB_TOKEN"}
142
- with patch.dict("os.environ", env, clear=True):
143
- result = runner.invoke(app, ["labels"])
144
-
145
- assert result.exit_code == 1
146
-
147
-
148
- # ---------------------------------------------------------------------------
149
- # Step 2 — milestone list
150
- # ---------------------------------------------------------------------------
151
-
152
-
153
- class TestMilestoneList:
154
- """Step 2: list milestones (read-only verification step)."""
155
-
156
- def test_lists_milestones(self) -> None:
157
- """Open and closed milestones are printed with number, state, title."""
158
- m1 = _make_milestone(1, "v1.0 — Skills Foundation", open_issues=5)
159
- m2 = _make_milestone(2, "v1.1 — Quality Gates", state="closed")
160
- mock_repo = MagicMock()
161
- mock_repo.get_milestones.return_value = [m1, m2]
162
-
163
- with (
164
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
165
- patch("github_project_setup.get_repo", return_value=mock_repo),
166
- patch("github_project_setup.Github"),
167
- ):
168
- result = runner.invoke(app, ["milestone", "list"])
169
-
170
- assert result.exit_code == 0, result.output
171
- assert "# 1" in result.output
172
- assert "v1.0" in result.output
173
- assert "# 2" in result.output
174
-
175
- def test_empty_repo_prints_no_milestones(self) -> None:
176
- """Empty milestone list prints a 'No milestones.' message."""
177
- mock_repo = MagicMock()
178
- mock_repo.get_milestones.return_value = []
179
-
180
- with (
181
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
182
- patch("github_project_setup.get_repo", return_value=mock_repo),
183
- patch("github_project_setup.Github"),
184
- ):
185
- result = runner.invoke(app, ["milestone", "list"])
186
-
187
- assert result.exit_code == 0
188
- assert "No milestones" in result.output
189
-
190
-
191
- # ---------------------------------------------------------------------------
192
- # Step 3 — milestone create
193
- # ---------------------------------------------------------------------------
194
-
195
-
196
- class TestMilestoneCreate:
197
- """Step 3: create a new milestone."""
198
-
199
- def test_creates_milestone_title_only(self) -> None:
200
- """Milestone is created with title only (no due date, no description)."""
201
- new_ms = _make_milestone(3, "test-milestone")
202
- mock_repo = MagicMock()
203
- mock_repo.create_milestone.return_value = new_ms
204
-
205
- with (
206
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
207
- patch("github_project_setup.get_repo", return_value=mock_repo),
208
- patch("github_project_setup.Github"),
209
- ):
210
- result = runner.invoke(app, ["milestone", "create", "--title", "test-milestone"])
211
-
212
- assert result.exit_code == 0, result.output
213
- mock_repo.create_milestone.assert_called_once_with(title="test-milestone")
214
- assert "Created milestone #3" in result.output
215
-
216
- def test_creates_milestone_with_due_date(self) -> None:
217
- """Due date is parsed and passed as datetime to create_milestone."""
218
- new_ms = _make_milestone(4, "sprint")
219
- mock_repo = MagicMock()
220
- mock_repo.create_milestone.return_value = new_ms
221
-
222
- with (
223
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
224
- patch("github_project_setup.get_repo", return_value=mock_repo),
225
- patch("github_project_setup.Github"),
226
- ):
227
- result = runner.invoke(app, ["milestone", "create", "--title", "sprint", "--due", "2026-03-31"])
228
-
229
- assert result.exit_code == 0, result.output
230
- call_kwargs = mock_repo.create_milestone.call_args[1]
231
- assert "due_on" in call_kwargs
232
- assert call_kwargs["due_on"].year == 2026
233
-
234
- def test_creates_milestone_with_description(self) -> None:
235
- """Description is included when provided."""
236
- new_ms = _make_milestone(5, "release")
237
- mock_repo = MagicMock()
238
- mock_repo.create_milestone.return_value = new_ms
239
-
240
- with (
241
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
242
- patch("github_project_setup.get_repo", return_value=mock_repo),
243
- patch("github_project_setup.Github"),
244
- ):
245
- result = runner.invoke(
246
- app, ["milestone", "create", "--title", "release", "--description", "Release milestone"]
247
- )
248
-
249
- assert result.exit_code == 0, result.output
250
- call_kwargs = mock_repo.create_milestone.call_args[1]
251
- assert call_kwargs.get("description") == "Release milestone"
252
-
253
-
254
- # ---------------------------------------------------------------------------
255
- # Step 4 — issue create
256
- # ---------------------------------------------------------------------------
257
-
258
-
259
- class TestIssueCreate:
260
- """Step 4: create an issue with labels and optional milestone."""
261
-
262
- def test_creates_issue_with_all_labels(self) -> None:
263
- """Issue created with priority, type, and status:needs-grooming labels."""
264
- new_issue = _make_issue(42, "feat: add skill", [])
265
- new_issue.html_url = "https://github.com/owner/repo/issues/42"
266
- mock_repo = MagicMock()
267
- mock_repo.create_issue.return_value = new_issue
268
- mock_repo.get_label.side_effect = _make_label
269
-
270
- with (
271
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
272
- patch("github_project_setup.get_repo", return_value=mock_repo),
273
- patch("github_project_setup.Github"),
274
- ):
275
- result = runner.invoke(
276
- app,
277
- [
278
- "issue",
279
- "create",
280
- "--title",
281
- "feat: add skill",
282
- "--priority-label",
283
- "priority:p1",
284
- "--type-label",
285
- "type:feature",
286
- ],
287
- )
288
-
289
- assert result.exit_code == 0, result.output
290
- assert "Created issue #42" in result.output
291
- # Verify labels passed to create_issue include all three
292
- call_kwargs = mock_repo.create_issue.call_args[1]
293
- label_names = [lbl.name for lbl in call_kwargs["labels"]]
294
- assert "status:needs-grooming" in label_names
295
- assert "priority:p1" in label_names
296
- assert "type:feature" in label_names
297
-
298
- def test_creates_issue_with_milestone(self) -> None:
299
- """Issue is assigned to milestone when --milestone is provided."""
300
- new_issue = _make_issue(43, "fix: bug", [])
301
- new_issue.html_url = "https://github.com/owner/repo/issues/43"
302
- milestone_obj = _make_milestone(1, "v1.0")
303
- mock_repo = MagicMock()
304
- mock_repo.create_issue.return_value = new_issue
305
- mock_repo.get_label.side_effect = _make_label
306
- mock_repo.get_milestone.return_value = milestone_obj
307
-
308
- with (
309
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
310
- patch("github_project_setup.get_repo", return_value=mock_repo),
311
- patch("github_project_setup.Github"),
312
- ):
313
- result = runner.invoke(app, ["issue", "create", "--title", "fix: bug", "--milestone", "1"])
314
-
315
- assert result.exit_code == 0, result.output
316
- call_kwargs = mock_repo.create_issue.call_args[1]
317
- assert call_kwargs["milestone"] is milestone_obj
318
-
319
- def test_missing_title_exits_nonzero(self) -> None:
320
- """Missing --title exits with code 1."""
321
- with (
322
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
323
- patch("github_project_setup.Github"),
324
- patch("github_project_setup.get_repo", return_value=MagicMock()),
325
- ):
326
- result = runner.invoke(app, ["issue", "create"])
327
-
328
- assert result.exit_code == 1
329
-
330
- def test_unknown_label_is_skipped_not_fatal(self) -> None:
331
- """Unknown label prints a warning but issue is still created."""
332
- from github import GithubException
333
-
334
- new_issue = _make_issue(44, "test", [])
335
- new_issue.html_url = "https://github.com/owner/repo/issues/44"
336
- mock_repo = MagicMock()
337
- mock_repo.create_issue.return_value = new_issue
338
- mock_repo.get_label.side_effect = GithubException(404, "not found")
339
-
340
- with (
341
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
342
- patch("github_project_setup.get_repo", return_value=mock_repo),
343
- patch("github_project_setup.Github"),
344
- ):
345
- result = runner.invoke(
346
- app, ["issue", "create", "--title", "test", "--priority-label", "priority:p99-nonexistent"]
347
- )
348
-
349
- assert result.exit_code == 0, result.output
350
- assert "Created issue" in result.output
351
-
352
-
353
- # ---------------------------------------------------------------------------
354
- # Step 5 — milestone start (the new command)
355
- # ---------------------------------------------------------------------------
356
-
357
-
358
- class TestMilestoneStart:
359
- """Step 5: bulk-transition status:needs-grooming → status:in-progress."""
360
-
361
- def _setup_repo(
362
- self, issues: list[MagicMock] | None = None, milestone_state: str = "open"
363
- ) -> tuple[MagicMock, MagicMock]:
364
- """Return (mock_repo, milestone) with issues attached."""
365
- if issues is None:
366
- issues = [
367
- _make_issue(10, "First issue", ["priority:p1", "status:needs-grooming"]),
368
- _make_issue(11, "Second issue", ["priority:p2", "status:needs-grooming"]),
369
- ]
370
- milestone = _make_milestone(1, "v1.0", state=milestone_state, open_issues=len(issues))
371
- mock_repo = MagicMock()
372
- mock_repo.get_milestone.return_value = milestone
373
- mock_repo.get_issues.return_value = issues
374
- mock_repo.get_label.return_value = _make_label("status:in-progress")
375
- return mock_repo, milestone
376
-
377
- # --- happy path ---
378
-
379
- def test_transitions_needs_grooming_to_in_progress(self) -> None:
380
- """Each issue has status:needs-grooming removed and status:in-progress added."""
381
- mock_repo, _ = self._setup_repo()
382
-
383
- with (
384
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
385
- patch("github_project_setup.get_repo", return_value=mock_repo),
386
- patch("github_project_setup.Github"),
387
- ):
388
- result = runner.invoke(app, ["milestone", "start", "--number", "1"])
389
-
390
- assert result.exit_code == 0, result.output
391
- # Both issues should have been edited
392
- for iss in mock_repo.get_issues.return_value:
393
- iss.edit.assert_called_once()
394
- call_kwargs = iss.edit.call_args[1]
395
- assert "status:in-progress" in call_kwargs["labels"]
396
- assert "status:needs-grooming" not in call_kwargs["labels"]
397
-
398
- def test_skips_already_in_progress_issues(self) -> None:
399
- """Issues already labeled status:in-progress are skipped, not double-edited."""
400
- issues = [_make_issue(20, "already done", ["priority:p1", "status:in-progress"])]
401
- mock_repo, _ = self._setup_repo(issues=issues)
402
-
403
- with (
404
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
405
- patch("github_project_setup.get_repo", return_value=mock_repo),
406
- patch("github_project_setup.Github"),
407
- ):
408
- result = runner.invoke(app, ["milestone", "start", "--number", "1"])
409
-
410
- assert result.exit_code == 0, result.output
411
- # edit must NOT have been called
412
- issues[0].edit.assert_not_called()
413
- assert "skipped" in result.output
414
-
415
- def test_creates_in_progress_label_when_missing(self) -> None:
416
- """status:in-progress label is created if it doesn't exist in the repo."""
417
- from github import GithubException
418
-
419
- issues = [_make_issue(30, "work", ["status:needs-grooming"])]
420
- new_label = _make_label("status:in-progress")
421
- mock_repo, _ = self._setup_repo(issues=issues)
422
- mock_repo.get_label.side_effect = GithubException(404, "not found")
423
- mock_repo.create_label.return_value = new_label
424
-
425
- with (
426
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
427
- patch("github_project_setup.get_repo", return_value=mock_repo),
428
- patch("github_project_setup.Github"),
429
- ):
430
- result = runner.invoke(app, ["milestone", "start", "--number", "1"])
431
-
432
- assert result.exit_code == 0, result.output
433
- mock_repo.create_label.assert_called_once()
434
-
435
- def test_summary_counts_reported(self) -> None:
436
- """Final summary line shows transitioned/skipped/failed counts."""
437
- issues = [
438
- _make_issue(40, "pending", ["status:needs-grooming"]),
439
- _make_issue(41, "already", ["status:in-progress"]),
440
- ]
441
- mock_repo, _ = self._setup_repo(issues=issues)
442
-
443
- with (
444
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
445
- patch("github_project_setup.get_repo", return_value=mock_repo),
446
- patch("github_project_setup.Github"),
447
- ):
448
- result = runner.invoke(app, ["milestone", "start", "--number", "1"])
449
-
450
- assert result.exit_code == 0, result.output
451
- assert "1 transitioned" in result.output
452
- assert "1 already in-progress" in result.output
453
- assert "0 failed" in result.output
454
-
455
- # --- error paths ---
456
-
457
- def test_closed_milestone_exits_nonzero(self) -> None:
458
- """Closed milestone exits with code 1 and explains the error."""
459
- mock_repo, _ = self._setup_repo(milestone_state="closed")
460
-
461
- with (
462
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
463
- patch("github_project_setup.get_repo", return_value=mock_repo),
464
- patch("github_project_setup.Github"),
465
- ):
466
- result = runner.invoke(app, ["milestone", "start", "--number", "1"])
467
-
468
- assert result.exit_code == 1
469
- assert "already closed" in result.stderr
470
-
471
- def test_empty_milestone_exits_zero_with_warning(self) -> None:
472
- """Milestone with zero open issues exits 0 and prints a warning."""
473
- milestone = _make_milestone(1, "empty", open_issues=0)
474
- mock_repo = MagicMock()
475
- mock_repo.get_milestone.return_value = milestone
476
-
477
- with (
478
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
479
- patch("github_project_setup.get_repo", return_value=mock_repo),
480
- patch("github_project_setup.Github"),
481
- ):
482
- result = runner.invoke(app, ["milestone", "start", "--number", "1"])
483
-
484
- assert result.exit_code == 0
485
- assert "no open issues" in result.output.lower()
486
-
487
- def test_milestone_not_found_lists_open_milestones(self) -> None:
488
- """Non-existent milestone prints open milestones and exits 1."""
489
- from github import GithubException
490
-
491
- open_ms = _make_milestone(2, "v2.0")
492
- mock_repo = MagicMock()
493
- mock_repo.get_milestone.side_effect = GithubException(404, "not found")
494
- mock_repo.get_milestones.return_value = [open_ms]
495
-
496
- with (
497
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
498
- patch("github_project_setup.get_repo", return_value=mock_repo),
499
- patch("github_project_setup.Github"),
500
- ):
501
- result = runner.invoke(app, ["milestone", "start", "--number", "999"])
502
-
503
- assert result.exit_code == 1
504
- assert "v2.0" in result.stderr
505
-
506
- def test_per_issue_failure_continues_and_exits_nonzero(self) -> None:
507
- """Failure on one issue is logged; remaining issues are attempted; exit code 1."""
508
- from github import GithubException
509
-
510
- good_issue = _make_issue(50, "good", ["status:needs-grooming"])
511
- bad_issue = _make_issue(51, "bad", ["status:needs-grooming"])
512
- bad_issue.edit.side_effect = GithubException(403, "forbidden")
513
- issues = [good_issue, bad_issue]
514
- mock_repo, _ = self._setup_repo(issues=issues)
515
-
516
- with (
517
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
518
- patch("github_project_setup.get_repo", return_value=mock_repo),
519
- patch("github_project_setup.Github"),
520
- ):
521
- result = runner.invoke(app, ["milestone", "start", "--number", "1"])
522
-
523
- assert result.exit_code == 1
524
- good_issue.edit.assert_called_once() # good issue was still processed
525
- assert "FAILED" in result.stderr
526
-
527
- def test_preserves_non_status_labels(self) -> None:
528
- """priority:p1 label is preserved; only status:needs-grooming is removed."""
529
- issues = [_make_issue(60, "preserve labels", ["priority:p1", "type:feature", "status:needs-grooming"])]
530
- mock_repo, _ = self._setup_repo(issues=issues)
531
-
532
- with (
533
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
534
- patch("github_project_setup.get_repo", return_value=mock_repo),
535
- patch("github_project_setup.Github"),
536
- ):
537
- result = runner.invoke(app, ["milestone", "start", "--number", "1"])
538
-
539
- assert result.exit_code == 0, result.output
540
- call_kwargs = issues[0].edit.call_args[1]
541
- assert "priority:p1" in call_kwargs["labels"]
542
- assert "type:feature" in call_kwargs["labels"]
543
- assert "status:needs-grooming" not in call_kwargs["labels"]
544
- assert "status:in-progress" in call_kwargs["labels"]
545
-
546
-
547
- # ---------------------------------------------------------------------------
548
- # Step 6 — issue list (verification step after start)
549
- # ---------------------------------------------------------------------------
550
-
551
-
552
- class TestIssueList:
553
- """Step 6: list issues to verify status labels after milestone start."""
554
-
555
- def test_lists_open_issues_with_labels_and_milestone(self) -> None:
556
- """Issue list shows number, title, labels, and milestone."""
557
- issue = _make_issue(70, "do work", ["priority:p1", "status:in-progress"])
558
- issue.milestone = _make_milestone(1, "v1.0")
559
- mock_repo = MagicMock()
560
- mock_repo.get_issues.return_value = [issue]
561
-
562
- with (
563
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
564
- patch("github_project_setup.get_repo", return_value=mock_repo),
565
- patch("github_project_setup.Github"),
566
- ):
567
- result = runner.invoke(app, ["issue", "list", "--state", "open"])
568
-
569
- assert result.exit_code == 0, result.output
570
- assert "# 70" in result.output
571
- assert "status:in-progress" in result.output
572
- assert "v1.0" in result.output
573
-
574
- def test_empty_issue_list_prints_message(self) -> None:
575
- """No matching issues prints 'No issues found.'"""
576
- mock_repo = MagicMock()
577
- mock_repo.get_issues.return_value = []
578
-
579
- with (
580
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
581
- patch("github_project_setup.get_repo", return_value=mock_repo),
582
- patch("github_project_setup.Github"),
583
- ):
584
- result = runner.invoke(app, ["issue", "list"])
585
-
586
- assert result.exit_code == 0
587
- assert "No issues found" in result.output
588
-
589
- def test_priority_filter_passes_label_to_api(self) -> None:
590
- """--priority p1 filters issues by the priority:p1 label."""
591
- p1_label = _make_label("priority:p1")
592
- issue = _make_issue(80, "p1 work", ["priority:p1"])
593
- issue.milestone = None
594
- mock_repo = MagicMock()
595
- mock_repo.get_label.return_value = p1_label
596
- mock_repo.get_issues.return_value = [issue]
597
-
598
- with (
599
- patch.dict("os.environ", {"GITHUB_TOKEN": "tok"}),
600
- patch("github_project_setup.get_repo", return_value=mock_repo),
601
- patch("github_project_setup.Github"),
602
- ):
603
- result = runner.invoke(app, ["issue", "list", "--priority", "p1"])
604
-
605
- assert result.exit_code == 0, result.output
606
- mock_repo.get_label.assert_called_with("priority:p1")
607
- call_kwargs = mock_repo.get_issues.call_args[1]
608
- assert "labels" in call_kwargs