gsd-pi 2.41.0 → 2.42.0-dev.eedc83f

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 (483) hide show
  1. package/README.md +92 -29
  2. package/dist/cli-web-branch.d.ts +6 -0
  3. package/dist/cli-web-branch.js +17 -0
  4. package/dist/cli.js +15 -1
  5. package/dist/onboarding.js +2 -1
  6. package/dist/resource-loader.js +39 -6
  7. package/dist/resources/extensions/async-jobs/async-bash-tool.js +52 -4
  8. package/dist/resources/extensions/gsd/auto/loop.js +89 -1
  9. package/dist/resources/extensions/gsd/auto/phases.js +28 -10
  10. package/dist/resources/extensions/gsd/auto/session.js +6 -0
  11. package/dist/resources/extensions/gsd/auto-dashboard.js +8 -2
  12. package/dist/resources/extensions/gsd/auto-dispatch.js +19 -2
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +7 -0
  14. package/dist/resources/extensions/gsd/auto-prompts.js +1 -1
  15. package/dist/resources/extensions/gsd/auto-recovery.js +12 -4
  16. package/dist/resources/extensions/gsd/auto-start.js +8 -3
  17. package/dist/resources/extensions/gsd/auto-worktree.js +147 -13
  18. package/dist/resources/extensions/gsd/auto.js +64 -2
  19. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +199 -164
  20. package/dist/resources/extensions/gsd/bootstrap/journal-tools.js +62 -0
  21. package/dist/resources/extensions/gsd/bootstrap/register-extension.js +2 -0
  22. package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +25 -3
  23. package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +7 -2
  24. package/dist/resources/extensions/gsd/commands/catalog.js +40 -1
  25. package/dist/resources/extensions/gsd/commands/handlers/core.js +1 -0
  26. package/dist/resources/extensions/gsd/commands/handlers/ops.js +5 -0
  27. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +146 -0
  28. package/dist/resources/extensions/gsd/context-injector.js +74 -0
  29. package/dist/resources/extensions/gsd/context-store.js +4 -3
  30. package/dist/resources/extensions/gsd/custom-execution-policy.js +47 -0
  31. package/dist/resources/extensions/gsd/custom-verification.js +145 -0
  32. package/dist/resources/extensions/gsd/custom-workflow-engine.js +164 -0
  33. package/dist/resources/extensions/gsd/dashboard-overlay.js +1 -0
  34. package/dist/resources/extensions/gsd/db-writer.js +5 -2
  35. package/dist/resources/extensions/gsd/definition-loader.js +352 -0
  36. package/dist/resources/extensions/gsd/detection.js +20 -1
  37. package/dist/resources/extensions/gsd/dev-execution-policy.js +24 -0
  38. package/dist/resources/extensions/gsd/dev-workflow-engine.js +82 -0
  39. package/dist/resources/extensions/gsd/doctor-checks.js +31 -1
  40. package/dist/resources/extensions/gsd/doctor-providers.js +10 -0
  41. package/dist/resources/extensions/gsd/doctor.js +11 -1
  42. package/dist/resources/extensions/gsd/engine-resolver.js +40 -0
  43. package/dist/resources/extensions/gsd/engine-types.js +8 -0
  44. package/dist/resources/extensions/gsd/execution-policy.js +8 -0
  45. package/dist/resources/extensions/gsd/exit-command.js +12 -2
  46. package/dist/resources/extensions/gsd/export.js +9 -13
  47. package/dist/resources/extensions/gsd/extension-manifest.json +2 -2
  48. package/dist/resources/extensions/gsd/files.js +28 -11
  49. package/dist/resources/extensions/gsd/forensics.js +94 -3
  50. package/dist/resources/extensions/gsd/git-constants.js +1 -0
  51. package/dist/resources/extensions/gsd/git-service.js +73 -3
  52. package/dist/resources/extensions/gsd/graph.js +225 -0
  53. package/dist/resources/extensions/gsd/gsd-db.js +25 -8
  54. package/dist/resources/extensions/gsd/guided-flow-queue.js +1 -1
  55. package/dist/resources/extensions/gsd/guided-flow.js +7 -3
  56. package/dist/resources/extensions/gsd/journal.js +85 -0
  57. package/dist/resources/extensions/gsd/md-importer.js +5 -0
  58. package/dist/resources/extensions/gsd/milestone-ids.js +1 -1
  59. package/dist/resources/extensions/gsd/native-git-bridge.js +3 -2
  60. package/dist/resources/extensions/gsd/post-unit-hooks.js +24 -412
  61. package/dist/resources/extensions/gsd/preferences-types.js +2 -0
  62. package/dist/resources/extensions/gsd/preferences.js +60 -8
  63. package/dist/resources/extensions/gsd/prompt-loader.js +34 -4
  64. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +11 -10
  65. package/dist/resources/extensions/gsd/prompts/discuss-headless.md +2 -2
  66. package/dist/resources/extensions/gsd/prompts/discuss.md +1 -1
  67. package/dist/resources/extensions/gsd/prompts/forensics.md +12 -5
  68. package/dist/resources/extensions/gsd/prompts/queue.md +1 -1
  69. package/dist/resources/extensions/gsd/repo-identity.js +92 -7
  70. package/dist/resources/extensions/gsd/rule-registry.js +489 -0
  71. package/dist/resources/extensions/gsd/rule-types.js +6 -0
  72. package/dist/resources/extensions/gsd/run-manager.js +134 -0
  73. package/dist/resources/extensions/gsd/service-tier.js +147 -0
  74. package/dist/resources/extensions/gsd/session-lock.js +2 -2
  75. package/dist/resources/extensions/gsd/structured-data-formatter.js +2 -1
  76. package/dist/resources/extensions/gsd/templates/decisions.md +2 -2
  77. package/dist/resources/extensions/gsd/workflow-engine.js +7 -0
  78. package/dist/resources/extensions/gsd/workflow-templates.js +13 -1
  79. package/dist/resources/extensions/gsd/worktree-manager.js +20 -6
  80. package/dist/resources/extensions/gsd/worktree-resolver.js +21 -4
  81. package/dist/resources/extensions/mcp-client/index.js +2 -1
  82. package/dist/resources/extensions/search-the-web/tool-search.js +3 -3
  83. package/dist/resources/extensions/subagent/index.js +7 -3
  84. package/dist/resources/extensions/voice/index.js +4 -4
  85. package/dist/resources/skills/create-workflow/SKILL.md +103 -0
  86. package/dist/resources/skills/create-workflow/references/feature-patterns.md +128 -0
  87. package/dist/resources/skills/create-workflow/references/verification-policies.md +76 -0
  88. package/dist/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
  89. package/dist/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
  90. package/dist/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
  91. package/dist/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
  92. package/dist/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
  93. package/dist/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
  94. package/dist/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
  95. package/dist/web/standalone/.next/BUILD_ID +1 -1
  96. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  97. package/dist/web/standalone/.next/build-manifest.json +4 -4
  98. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  99. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  100. package/dist/web/standalone/.next/required-server-files.json +3 -3
  101. package/dist/web/standalone/.next/server/app/_global-error/page.js +3 -3
  102. package/dist/web/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  103. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  104. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  105. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  106. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  107. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  108. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  109. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  110. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  111. package/dist/web/standalone/.next/server/app/_not-found/page.js +2 -2
  112. package/dist/web/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  113. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  114. package/dist/web/standalone/.next/server/app/_not-found.rsc +3 -3
  115. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
  116. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  117. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
  118. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  119. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  120. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  121. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  122. package/dist/web/standalone/.next/server/app/api/boot/route_client-reference-manifest.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  124. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route_client-reference-manifest.js +1 -1
  125. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  126. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route_client-reference-manifest.js +1 -1
  127. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +2 -2
  128. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route_client-reference-manifest.js +1 -1
  129. package/dist/web/standalone/.next/server/app/api/browse-directories/route.js +1 -1
  130. package/dist/web/standalone/.next/server/app/api/browse-directories/route_client-reference-manifest.js +1 -1
  131. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  132. package/dist/web/standalone/.next/server/app/api/captures/route_client-reference-manifest.js +1 -1
  133. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  134. package/dist/web/standalone/.next/server/app/api/cleanup/route_client-reference-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/app/api/dev-mode/route.js +1 -1
  136. package/dist/web/standalone/.next/server/app/api/dev-mode/route_client-reference-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  138. package/dist/web/standalone/.next/server/app/api/doctor/route_client-reference-manifest.js +1 -1
  139. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  140. package/dist/web/standalone/.next/server/app/api/export-data/route_client-reference-manifest.js +1 -1
  141. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  142. package/dist/web/standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
  143. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  144. package/dist/web/standalone/.next/server/app/api/forensics/route_client-reference-manifest.js +1 -1
  145. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  146. package/dist/web/standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
  147. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  148. package/dist/web/standalone/.next/server/app/api/history/route_client-reference-manifest.js +1 -1
  149. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  150. package/dist/web/standalone/.next/server/app/api/hooks/route_client-reference-manifest.js +1 -1
  151. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  152. package/dist/web/standalone/.next/server/app/api/inspect/route_client-reference-manifest.js +1 -1
  153. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  154. package/dist/web/standalone/.next/server/app/api/knowledge/route_client-reference-manifest.js +1 -1
  155. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  156. package/dist/web/standalone/.next/server/app/api/live-state/route_client-reference-manifest.js +1 -1
  157. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  158. package/dist/web/standalone/.next/server/app/api/onboarding/route_client-reference-manifest.js +1 -1
  159. package/dist/web/standalone/.next/server/app/api/preferences/route.js +1 -1
  160. package/dist/web/standalone/.next/server/app/api/preferences/route_client-reference-manifest.js +1 -1
  161. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  162. package/dist/web/standalone/.next/server/app/api/projects/route_client-reference-manifest.js +1 -1
  163. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  164. package/dist/web/standalone/.next/server/app/api/recovery/route_client-reference-manifest.js +1 -1
  165. package/dist/web/standalone/.next/server/app/api/remote-questions/route.js +5 -5
  166. package/dist/web/standalone/.next/server/app/api/remote-questions/route_client-reference-manifest.js +1 -1
  167. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  168. package/dist/web/standalone/.next/server/app/api/session/browser/route_client-reference-manifest.js +1 -1
  169. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  170. package/dist/web/standalone/.next/server/app/api/session/command/route_client-reference-manifest.js +1 -1
  171. package/dist/web/standalone/.next/server/app/api/session/events/route.js +2 -2
  172. package/dist/web/standalone/.next/server/app/api/session/events/route_client-reference-manifest.js +1 -1
  173. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  174. package/dist/web/standalone/.next/server/app/api/session/manage/route_client-reference-manifest.js +1 -1
  175. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  176. package/dist/web/standalone/.next/server/app/api/settings-data/route_client-reference-manifest.js +1 -1
  177. package/dist/web/standalone/.next/server/app/api/shutdown/route.js +1 -1
  178. package/dist/web/standalone/.next/server/app/api/shutdown/route_client-reference-manifest.js +1 -1
  179. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  180. package/dist/web/standalone/.next/server/app/api/skill-health/route_client-reference-manifest.js +1 -1
  181. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  182. package/dist/web/standalone/.next/server/app/api/steer/route_client-reference-manifest.js +1 -1
  183. package/dist/web/standalone/.next/server/app/api/terminal/input/route.js +1 -1
  184. package/dist/web/standalone/.next/server/app/api/terminal/input/route_client-reference-manifest.js +1 -1
  185. package/dist/web/standalone/.next/server/app/api/terminal/resize/route.js +2 -2
  186. package/dist/web/standalone/.next/server/app/api/terminal/resize/route_client-reference-manifest.js +1 -1
  187. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +2 -2
  188. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route_client-reference-manifest.js +1 -1
  189. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +4 -4
  190. package/dist/web/standalone/.next/server/app/api/terminal/stream/route_client-reference-manifest.js +1 -1
  191. package/dist/web/standalone/.next/server/app/api/terminal/upload/route.js +1 -1
  192. package/dist/web/standalone/.next/server/app/api/terminal/upload/route_client-reference-manifest.js +1 -1
  193. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  194. package/dist/web/standalone/.next/server/app/api/undo/route_client-reference-manifest.js +1 -1
  195. package/dist/web/standalone/.next/server/app/api/update/route.js +1 -1
  196. package/dist/web/standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  197. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  198. package/dist/web/standalone/.next/server/app/api/visualizer/route_client-reference-manifest.js +1 -1
  199. package/dist/web/standalone/.next/server/app/index.html +1 -1
  200. package/dist/web/standalone/.next/server/app/index.rsc +4 -4
  201. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  202. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +4 -4
  203. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  204. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +3 -3
  205. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  206. package/dist/web/standalone/.next/server/app/page.js +2 -2
  207. package/dist/web/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  208. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  209. package/dist/web/standalone/.next/server/chunks/229.js +3 -3
  210. package/dist/web/standalone/.next/server/chunks/471.js +3 -3
  211. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  212. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  213. package/dist/web/standalone/.next/server/middleware.js +2 -2
  214. package/dist/web/standalone/.next/server/next-font-manifest.js +1 -1
  215. package/dist/web/standalone/.next/server/next-font-manifest.json +1 -1
  216. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  217. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  218. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  219. package/dist/web/standalone/.next/static/chunks/4024.c195dc1fdd2adbea.js +9 -0
  220. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-f2a7482d42a5614b.js +1 -0
  221. package/dist/web/standalone/.next/static/chunks/app/layout-a16c7a7ecdf0c2cf.js +1 -0
  222. package/dist/web/standalone/.next/static/chunks/app/page-b9367c5ae13b99c6.js +1 -0
  223. package/dist/web/standalone/.next/static/chunks/{main-app-2f2ee7b85712c2bd.js → main-app-fdab67f7802d7832.js} +1 -1
  224. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-459824ffb8c323dd.js +1 -0
  225. package/dist/web/standalone/.next/static/chunks/{webpack-9afaaebf6042a1d7.js → webpack-fa307370fcf9fb2c.js} +1 -1
  226. package/dist/web/standalone/node_modules/node-pty/build/Makefile +2 -2
  227. package/dist/web/standalone/node_modules/node-pty/build/Release/pty.node +0 -0
  228. package/dist/web/standalone/node_modules/node-pty/build/pty.target.mk +14 -14
  229. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api.target.mk +14 -14
  230. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_except.target.mk +14 -14
  231. package/dist/web/standalone/node_modules/node-pty/node-addon-api/node_addon_api_maybe.target.mk +14 -14
  232. package/dist/web/standalone/server.js +1 -1
  233. package/dist/web-mode.d.ts +4 -0
  234. package/dist/web-mode.js +69 -11
  235. package/package.json +1 -1
  236. package/packages/native/src/__tests__/text.test.mjs +33 -0
  237. package/packages/pi-agent-core/dist/agent.d.ts.map +1 -1
  238. package/packages/pi-agent-core/dist/agent.js +2 -0
  239. package/packages/pi-agent-core/dist/agent.js.map +1 -1
  240. package/packages/pi-agent-core/dist/types.d.ts +6 -0
  241. package/packages/pi-agent-core/dist/types.d.ts.map +1 -1
  242. package/packages/pi-agent-core/dist/types.js.map +1 -1
  243. package/packages/pi-agent-core/src/agent.test.ts +53 -0
  244. package/packages/pi-agent-core/src/agent.ts +3 -0
  245. package/packages/pi-agent-core/src/types.ts +6 -0
  246. package/packages/pi-agent-core/tsconfig.json +1 -1
  247. package/packages/pi-ai/dist/models.d.ts +5 -3
  248. package/packages/pi-ai/dist/models.d.ts.map +1 -1
  249. package/packages/pi-ai/dist/models.generated.d.ts +801 -1468
  250. package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
  251. package/packages/pi-ai/dist/models.generated.js +1135 -1588
  252. package/packages/pi-ai/dist/models.generated.js.map +1 -1
  253. package/packages/pi-ai/dist/models.js.map +1 -1
  254. package/packages/pi-ai/dist/utils/oauth/github-copilot.d.ts.map +1 -1
  255. package/packages/pi-ai/dist/utils/oauth/github-copilot.js +60 -2
  256. package/packages/pi-ai/dist/utils/oauth/github-copilot.js.map +1 -1
  257. package/packages/pi-ai/scripts/generate-models.ts +1543 -0
  258. package/packages/pi-ai/src/models.generated.ts +1140 -1593
  259. package/packages/pi-ai/src/models.ts +7 -4
  260. package/packages/pi-ai/src/utils/oauth/github-copilot.ts +74 -2
  261. package/packages/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
  262. package/packages/pi-coding-agent/dist/core/agent-session.js +8 -1
  263. package/packages/pi-coding-agent/dist/core/agent-session.js.map +1 -1
  264. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +7 -0
  265. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  266. package/packages/pi-coding-agent/dist/core/auth-storage.js +29 -2
  267. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  268. package/packages/pi-coding-agent/dist/core/auth-storage.test.js +60 -0
  269. package/packages/pi-coding-agent/dist/core/auth-storage.test.js.map +1 -1
  270. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js +3 -1
  271. package/packages/pi-coding-agent/dist/core/discovery-cache.test.js.map +1 -1
  272. package/packages/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
  273. package/packages/pi-coding-agent/dist/core/extensions/loader.js +18 -0
  274. package/packages/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
  275. package/packages/pi-coding-agent/dist/core/lsp/client.d.ts.map +1 -1
  276. package/packages/pi-coding-agent/dist/core/lsp/client.js +23 -0
  277. package/packages/pi-coding-agent/dist/core/lsp/client.js.map +1 -1
  278. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  279. package/packages/pi-coding-agent/dist/core/model-registry.js +2 -0
  280. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  281. package/packages/pi-coding-agent/dist/core/package-manager.d.ts +6 -0
  282. package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
  283. package/packages/pi-coding-agent/dist/core/package-manager.js +63 -11
  284. package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
  285. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +9 -0
  286. package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
  287. package/packages/pi-coding-agent/dist/core/resource-loader.js +20 -6
  288. package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
  289. package/packages/pi-coding-agent/dist/core/system-prompt.d.ts.map +1 -1
  290. package/packages/pi-coding-agent/dist/core/system-prompt.js +6 -5
  291. package/packages/pi-coding-agent/dist/core/system-prompt.js.map +1 -1
  292. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
  293. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.js +3 -0
  294. package/packages/pi-coding-agent/dist/modes/interactive/components/extension-editor.js.map +1 -1
  295. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  296. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +9 -6
  297. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  298. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
  299. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +10 -7
  300. package/packages/pi-coding-agent/dist/modes/interactive/components/login-dialog.js.map +1 -1
  301. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  302. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +34 -10
  303. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  304. package/packages/pi-coding-agent/package.json +1 -1
  305. package/packages/pi-coding-agent/src/core/agent-session.ts +7 -1
  306. package/packages/pi-coding-agent/src/core/auth-storage.test.ts +68 -0
  307. package/packages/pi-coding-agent/src/core/auth-storage.ts +30 -2
  308. package/packages/pi-coding-agent/src/core/discovery-cache.test.ts +4 -2
  309. package/packages/pi-coding-agent/src/core/extensions/loader.ts +18 -0
  310. package/packages/pi-coding-agent/src/core/lsp/client.ts +29 -0
  311. package/packages/pi-coding-agent/src/core/model-registry.ts +3 -0
  312. package/packages/pi-coding-agent/src/core/package-manager.ts +99 -58
  313. package/packages/pi-coding-agent/src/core/resource-loader.ts +24 -6
  314. package/packages/pi-coding-agent/src/core/system-prompt.ts +6 -5
  315. package/packages/pi-coding-agent/src/modes/interactive/components/extension-editor.ts +3 -0
  316. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +10 -6
  317. package/packages/pi-coding-agent/src/modes/interactive/components/login-dialog.ts +11 -7
  318. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +36 -11
  319. package/pkg/package.json +1 -1
  320. package/src/resources/extensions/async-jobs/async-bash-timeout.test.ts +122 -0
  321. package/src/resources/extensions/async-jobs/async-bash-tool.ts +40 -4
  322. package/src/resources/extensions/gsd/auto/loop-deps.ts +5 -1
  323. package/src/resources/extensions/gsd/auto/loop.ts +101 -1
  324. package/src/resources/extensions/gsd/auto/phases.ts +30 -10
  325. package/src/resources/extensions/gsd/auto/session.ts +6 -0
  326. package/src/resources/extensions/gsd/auto/types.ts +4 -0
  327. package/src/resources/extensions/gsd/auto-dashboard.ts +9 -2
  328. package/src/resources/extensions/gsd/auto-dispatch.ts +25 -5
  329. package/src/resources/extensions/gsd/auto-post-unit.ts +8 -0
  330. package/src/resources/extensions/gsd/auto-prompts.ts +1 -1
  331. package/src/resources/extensions/gsd/auto-recovery.ts +12 -4
  332. package/src/resources/extensions/gsd/auto-start.ts +8 -3
  333. package/src/resources/extensions/gsd/auto-worktree.ts +162 -18
  334. package/src/resources/extensions/gsd/auto.ts +71 -2
  335. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +209 -162
  336. package/src/resources/extensions/gsd/bootstrap/journal-tools.ts +62 -0
  337. package/src/resources/extensions/gsd/bootstrap/register-extension.ts +2 -0
  338. package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +25 -4
  339. package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +9 -2
  340. package/src/resources/extensions/gsd/commands/catalog.ts +40 -1
  341. package/src/resources/extensions/gsd/commands/handlers/core.ts +1 -0
  342. package/src/resources/extensions/gsd/commands/handlers/ops.ts +5 -0
  343. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +164 -0
  344. package/src/resources/extensions/gsd/context-injector.ts +100 -0
  345. package/src/resources/extensions/gsd/context-store.ts +4 -3
  346. package/src/resources/extensions/gsd/custom-execution-policy.ts +73 -0
  347. package/src/resources/extensions/gsd/custom-verification.ts +180 -0
  348. package/src/resources/extensions/gsd/custom-workflow-engine.ts +216 -0
  349. package/src/resources/extensions/gsd/dashboard-overlay.ts +1 -0
  350. package/src/resources/extensions/gsd/db-writer.ts +6 -2
  351. package/src/resources/extensions/gsd/definition-loader.ts +462 -0
  352. package/src/resources/extensions/gsd/detection.ts +20 -1
  353. package/src/resources/extensions/gsd/dev-execution-policy.ts +51 -0
  354. package/src/resources/extensions/gsd/dev-workflow-engine.ts +110 -0
  355. package/src/resources/extensions/gsd/doctor-checks.ts +32 -1
  356. package/src/resources/extensions/gsd/doctor-providers.ts +13 -0
  357. package/src/resources/extensions/gsd/doctor-types.ts +1 -0
  358. package/src/resources/extensions/gsd/doctor.ts +12 -1
  359. package/src/resources/extensions/gsd/engine-resolver.ts +57 -0
  360. package/src/resources/extensions/gsd/engine-types.ts +71 -0
  361. package/src/resources/extensions/gsd/execution-policy.ts +43 -0
  362. package/src/resources/extensions/gsd/exit-command.ts +14 -2
  363. package/src/resources/extensions/gsd/export.ts +8 -15
  364. package/src/resources/extensions/gsd/extension-manifest.json +2 -2
  365. package/src/resources/extensions/gsd/files.ts +29 -12
  366. package/src/resources/extensions/gsd/forensics.ts +101 -3
  367. package/src/resources/extensions/gsd/git-constants.ts +1 -0
  368. package/src/resources/extensions/gsd/git-service.ts +76 -6
  369. package/src/resources/extensions/gsd/graph.ts +312 -0
  370. package/src/resources/extensions/gsd/gsd-db.ts +37 -8
  371. package/src/resources/extensions/gsd/guided-flow-queue.ts +1 -1
  372. package/src/resources/extensions/gsd/guided-flow.ts +7 -3
  373. package/src/resources/extensions/gsd/journal.ts +134 -0
  374. package/src/resources/extensions/gsd/md-importer.ts +6 -0
  375. package/src/resources/extensions/gsd/milestone-ids.ts +1 -1
  376. package/src/resources/extensions/gsd/native-git-bridge.ts +3 -2
  377. package/src/resources/extensions/gsd/post-unit-hooks.ts +24 -462
  378. package/src/resources/extensions/gsd/preferences-types.ts +6 -0
  379. package/src/resources/extensions/gsd/preferences.ts +63 -6
  380. package/src/resources/extensions/gsd/prompt-loader.ts +35 -4
  381. package/src/resources/extensions/gsd/prompts/complete-milestone.md +11 -10
  382. package/src/resources/extensions/gsd/prompts/discuss-headless.md +2 -2
  383. package/src/resources/extensions/gsd/prompts/discuss.md +1 -1
  384. package/src/resources/extensions/gsd/prompts/forensics.md +12 -5
  385. package/src/resources/extensions/gsd/prompts/queue.md +1 -1
  386. package/src/resources/extensions/gsd/repo-identity.ts +95 -7
  387. package/src/resources/extensions/gsd/rule-registry.ts +599 -0
  388. package/src/resources/extensions/gsd/rule-types.ts +68 -0
  389. package/src/resources/extensions/gsd/run-manager.ts +180 -0
  390. package/src/resources/extensions/gsd/service-tier.ts +184 -0
  391. package/src/resources/extensions/gsd/session-lock.ts +2 -2
  392. package/src/resources/extensions/gsd/structured-data-formatter.ts +3 -1
  393. package/src/resources/extensions/gsd/templates/decisions.md +2 -2
  394. package/src/resources/extensions/gsd/tests/activity-log.test.ts +31 -69
  395. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +103 -120
  396. package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +85 -0
  397. package/src/resources/extensions/gsd/tests/auto-secrets-gate.test.ts +2 -2
  398. package/src/resources/extensions/gsd/tests/auto-worktree-milestone-merge.test.ts +202 -0
  399. package/src/resources/extensions/gsd/tests/bundled-workflow-defs.test.ts +180 -0
  400. package/src/resources/extensions/gsd/tests/captures.test.ts +12 -1
  401. package/src/resources/extensions/gsd/tests/commands-workflow-custom.test.ts +283 -0
  402. package/src/resources/extensions/gsd/tests/context-injector.test.ts +313 -0
  403. package/src/resources/extensions/gsd/tests/context-store.test.ts +10 -5
  404. package/src/resources/extensions/gsd/tests/continue-here.test.ts +20 -20
  405. package/src/resources/extensions/gsd/tests/custom-engine-loop-integration.test.ts +540 -0
  406. package/src/resources/extensions/gsd/tests/custom-verification.test.ts +382 -0
  407. package/src/resources/extensions/gsd/tests/custom-workflow-engine.test.ts +339 -0
  408. package/src/resources/extensions/gsd/tests/dashboard-custom-engine.test.ts +87 -0
  409. package/src/resources/extensions/gsd/tests/db-writer.test.ts +10 -0
  410. package/src/resources/extensions/gsd/tests/definition-loader.test.ts +778 -0
  411. package/src/resources/extensions/gsd/tests/dev-engine-wrapper.test.ts +318 -0
  412. package/src/resources/extensions/gsd/tests/doctor-completion-deferral.test.ts +15 -10
  413. package/src/resources/extensions/gsd/tests/doctor-fixlevel.test.ts +5 -4
  414. package/src/resources/extensions/gsd/tests/doctor-roadmap-summary-atomicity.test.ts +167 -0
  415. package/src/resources/extensions/gsd/tests/doctor-task-done-missing-summary-slice-loop.test.ts +174 -0
  416. package/src/resources/extensions/gsd/tests/e2e-workflow-pipeline-integration.test.ts +476 -0
  417. package/src/resources/extensions/gsd/tests/engine-interfaces-contract.test.ts +271 -0
  418. package/src/resources/extensions/gsd/tests/exit-command.test.ts +55 -0
  419. package/src/resources/extensions/gsd/tests/forensics-dedup.test.ts +48 -0
  420. package/src/resources/extensions/gsd/tests/forensics-issue-routing.test.ts +43 -0
  421. package/src/resources/extensions/gsd/tests/git-locale.test.ts +133 -0
  422. package/src/resources/extensions/gsd/tests/git-service.test.ts +49 -0
  423. package/src/resources/extensions/gsd/tests/graph-operations.test.ts +599 -0
  424. package/src/resources/extensions/gsd/tests/gsd-db.test.ts +8 -1
  425. package/src/resources/extensions/gsd/tests/gsd-tools.test.ts +7 -7
  426. package/src/resources/extensions/gsd/tests/iterate-engine-integration.test.ts +429 -0
  427. package/src/resources/extensions/gsd/tests/journal-integration.test.ts +513 -0
  428. package/src/resources/extensions/gsd/tests/journal-query-tool.test.ts +147 -0
  429. package/src/resources/extensions/gsd/tests/journal.test.ts +341 -0
  430. package/src/resources/extensions/gsd/tests/manifest-status.test.ts +73 -82
  431. package/src/resources/extensions/gsd/tests/md-importer.test.ts +31 -1
  432. package/src/resources/extensions/gsd/tests/memory-store.test.ts +2 -2
  433. package/src/resources/extensions/gsd/tests/milestone-id-reservation.test.ts +1 -1
  434. package/src/resources/extensions/gsd/tests/parsers.test.ts +110 -0
  435. package/src/resources/extensions/gsd/tests/preferences.test.ts +47 -25
  436. package/src/resources/extensions/gsd/tests/prompt-db.test.ts +3 -1
  437. package/src/resources/extensions/gsd/tests/repo-identity-worktree.test.ts +61 -1
  438. package/src/resources/extensions/gsd/tests/routing-history.test.ts +11 -22
  439. package/src/resources/extensions/gsd/tests/rule-registry.test.ts +413 -0
  440. package/src/resources/extensions/gsd/tests/run-manager.test.ts +229 -0
  441. package/src/resources/extensions/gsd/tests/service-tier.test.ts +127 -0
  442. package/src/resources/extensions/gsd/tests/skill-lifecycle.test.ts +2 -2
  443. package/src/resources/extensions/gsd/tests/stalled-tool-recovery.test.ts +102 -0
  444. package/src/resources/extensions/gsd/tests/structured-data-formatter.test.ts +4 -3
  445. package/src/resources/extensions/gsd/tests/symlink-numbered-variants.test.ts +151 -0
  446. package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +45 -0
  447. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +117 -0
  448. package/src/resources/extensions/gsd/tests/triage-dispatch.test.ts +6 -1
  449. package/src/resources/extensions/gsd/tests/verification-gate.test.ts +156 -263
  450. package/src/resources/extensions/gsd/tests/windows-path-normalization.test.ts +99 -0
  451. package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -0
  452. package/src/resources/extensions/gsd/tests/worktree-db.test.ts +4 -0
  453. package/src/resources/extensions/gsd/tests/worktree-health-dispatch.test.ts +135 -0
  454. package/src/resources/extensions/gsd/tests/worktree-manager.test.ts +203 -106
  455. package/src/resources/extensions/gsd/tests/worktree-resolver.test.ts +78 -3
  456. package/src/resources/extensions/gsd/tests/worktree-symlink-removal.test.ts +140 -0
  457. package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +74 -0
  458. package/src/resources/extensions/gsd/types.ts +3 -0
  459. package/src/resources/extensions/gsd/workflow-engine.ts +38 -0
  460. package/src/resources/extensions/gsd/workflow-templates.ts +12 -1
  461. package/src/resources/extensions/gsd/worktree-manager.ts +21 -6
  462. package/src/resources/extensions/gsd/worktree-resolver.ts +32 -11
  463. package/src/resources/extensions/mcp-client/index.ts +5 -1
  464. package/src/resources/extensions/search-the-web/tool-search.ts +3 -3
  465. package/src/resources/extensions/subagent/index.ts +7 -3
  466. package/src/resources/extensions/voice/index.ts +4 -4
  467. package/src/resources/skills/create-workflow/SKILL.md +103 -0
  468. package/src/resources/skills/create-workflow/references/feature-patterns.md +128 -0
  469. package/src/resources/skills/create-workflow/references/verification-policies.md +76 -0
  470. package/src/resources/skills/create-workflow/references/yaml-schema-v1.md +46 -0
  471. package/src/resources/skills/create-workflow/templates/blog-post-pipeline.yaml +60 -0
  472. package/src/resources/skills/create-workflow/templates/code-audit.yaml +60 -0
  473. package/src/resources/skills/create-workflow/templates/release-checklist.yaml +66 -0
  474. package/src/resources/skills/create-workflow/templates/workflow-definition.yaml +32 -0
  475. package/src/resources/skills/create-workflow/workflows/create-from-scratch.md +104 -0
  476. package/src/resources/skills/create-workflow/workflows/create-from-template.md +72 -0
  477. package/dist/web/standalone/.next/static/chunks/4024.279c423e4661ece1.js +0 -9
  478. package/dist/web/standalone/.next/static/chunks/app/_not-found/page-e07acdb7dd069836.js +0 -1
  479. package/dist/web/standalone/.next/static/chunks/app/layout-745c6ed5fea5fb06.js +0 -1
  480. package/dist/web/standalone/.next/static/chunks/app/page-801b53eff6e83579.js +0 -1
  481. package/dist/web/standalone/.next/static/chunks/next/dist/client/components/builtin/global-error-e6255954dccfcf0a.js +0 -1
  482. /package/dist/web/standalone/.next/static/{Ute3pMouVczQyT15qrBBO → JUBX5FUR73jiViQU5a-Cx}/_buildManifest.js +0 -0
  483. /package/dist/web/standalone/.next/static/{Ute3pMouVczQyT15qrBBO → JUBX5FUR73jiViQU5a-Cx}/_ssgManifest.js +0 -0
@@ -0,0 +1,180 @@
1
+ /**
2
+ * run-manager.ts — Create and list isolated workflow run directories.
3
+ *
4
+ * Each run lives under `.gsd/workflow-runs/<name>/<timestamp>/` and contains:
5
+ * - DEFINITION.yaml — frozen snapshot of the workflow definition at run-creation time
6
+ * - GRAPH.yaml — initialized step graph with all steps pending
7
+ * - PARAMS.json — (optional) parameter overrides used for this run
8
+ *
9
+ * Observability:
10
+ * - All run state is on disk in human-readable YAML/JSON — inspectable with cat/less.
11
+ * - `listRuns()` returns structured metadata including step counts and overall status.
12
+ * - Timestamp directory names are filesystem-safe (ISO with hyphens replacing colons).
13
+ * - Errors include the full path context for diagnosis.
14
+ */
15
+
16
+ import { mkdirSync, writeFileSync, existsSync, readdirSync, statSync } from "node:fs";
17
+ import { join } from "node:path";
18
+ import { stringify } from "yaml";
19
+ import { loadDefinition, substituteParams } from "./definition-loader.js";
20
+ import { initializeGraph, writeGraph, readGraph } from "./graph.js";
21
+ import type { WorkflowDefinition } from "./definition-loader.js";
22
+ import type { WorkflowGraph } from "./graph.js";
23
+
24
+ // ─── Types ───────────────────────────────────────────────────────────────
25
+
26
+ export interface RunMetadata {
27
+ /** Workflow definition name. */
28
+ name: string;
29
+ /** Filesystem-safe timestamp string used as dir name. */
30
+ timestamp: string;
31
+ /** Full path to the run directory. */
32
+ runDir: string;
33
+ /** Step counts derived from GRAPH.yaml. */
34
+ steps: { total: number; completed: number; pending: number; active: number };
35
+ /** Overall status derived from step states. */
36
+ status: "pending" | "running" | "complete";
37
+ }
38
+
39
+ // ─── Constants ───────────────────────────────────────────────────────────
40
+
41
+ const RUNS_DIR = "workflow-runs";
42
+ const DEFS_DIR = "workflow-defs";
43
+
44
+ // ─── Helpers ─────────────────────────────────────────────────────────────
45
+
46
+ /**
47
+ * Generate a filesystem-safe timestamp: `YYYY-MM-DDTHH-MM-SS`.
48
+ * Replaces colons with hyphens so the string is safe as a directory name
49
+ * on all platforms (Windows forbids colons in paths).
50
+ */
51
+ function makeTimestamp(date: Date = new Date()): string {
52
+ return date.toISOString().replace(/:/g, "-").replace(/\.\d{3}Z$/, "");
53
+ }
54
+
55
+ /**
56
+ * Derive overall status from a graph's step statuses.
57
+ */
58
+ function deriveStatus(graph: WorkflowGraph): "pending" | "running" | "complete" {
59
+ const hasActive = graph.steps.some((s) => s.status === "active");
60
+ const allDone = graph.steps.every(
61
+ (s) => s.status === "complete" || s.status === "expanded",
62
+ );
63
+ if (allDone) return "complete";
64
+ if (hasActive) return "running";
65
+ return "pending";
66
+ }
67
+
68
+ // ─── Public API ──────────────────────────────────────────────────────────
69
+
70
+ /**
71
+ * Create a new isolated run directory for a workflow definition.
72
+ *
73
+ * 1. Loads the definition from `<basePath>/.gsd/workflow-defs/<defName>.yaml`
74
+ * 2. Applies parameter substitution if overrides are provided
75
+ * 3. Creates `<basePath>/.gsd/workflow-runs/<defName>/<timestamp>/`
76
+ * 4. Writes frozen DEFINITION.yaml, initialized GRAPH.yaml, and optional PARAMS.json
77
+ *
78
+ * @param basePath — project root directory
79
+ * @param defName — definition filename (without .yaml extension)
80
+ * @param overrides — optional parameter overrides (merged with definition defaults)
81
+ * @returns Full path to the created run directory
82
+ * @throws Error if the definition file doesn't exist or is invalid
83
+ */
84
+ export function createRun(
85
+ basePath: string,
86
+ defName: string,
87
+ overrides?: Record<string, string>,
88
+ ): string {
89
+ const defsDir = join(basePath, ".gsd", DEFS_DIR);
90
+
91
+ // Load and validate the definition
92
+ const rawDef = loadDefinition(defsDir, defName);
93
+
94
+ // Apply parameter substitution if overrides provided
95
+ const def: WorkflowDefinition = overrides
96
+ ? substituteParams(rawDef, overrides)
97
+ : substituteParams(rawDef); // still resolve default params if any
98
+
99
+ // Create the run directory
100
+ const timestamp = makeTimestamp();
101
+ const runDir = join(basePath, ".gsd", RUNS_DIR, defName, timestamp);
102
+ mkdirSync(runDir, { recursive: true });
103
+
104
+ // Freeze the definition as DEFINITION.yaml
105
+ writeFileSync(join(runDir, "DEFINITION.yaml"), stringify(def), "utf-8");
106
+
107
+ // Initialize and write GRAPH.yaml
108
+ const graph = initializeGraph(def);
109
+ writeGraph(runDir, graph);
110
+
111
+ // Write PARAMS.json if overrides were provided
112
+ if (overrides && Object.keys(overrides).length > 0) {
113
+ writeFileSync(
114
+ join(runDir, "PARAMS.json"),
115
+ JSON.stringify(overrides, null, 2),
116
+ "utf-8",
117
+ );
118
+ }
119
+
120
+ return runDir;
121
+ }
122
+
123
+ /**
124
+ * List existing workflow runs with metadata.
125
+ *
126
+ * Scans `<basePath>/.gsd/workflow-runs/` for run directories. Each run's
127
+ * GRAPH.yaml is read to derive step counts and overall status.
128
+ *
129
+ * @param basePath — project root directory
130
+ * @param defName — optional filter: only list runs for this definition name
131
+ * @returns Array of run metadata, sorted newest-first within each definition
132
+ */
133
+ export function listRuns(basePath: string, defName?: string): RunMetadata[] {
134
+ const runsRoot = join(basePath, ".gsd", RUNS_DIR);
135
+ if (!existsSync(runsRoot)) return [];
136
+
137
+ const results: RunMetadata[] = [];
138
+
139
+ // Get workflow name directories
140
+ const nameDirs = defName ? [defName] : readdirSync(runsRoot).filter((entry) => {
141
+ const full = join(runsRoot, entry);
142
+ return statSync(full).isDirectory();
143
+ });
144
+
145
+ for (const name of nameDirs) {
146
+ const nameDir = join(runsRoot, name);
147
+ if (!existsSync(nameDir)) continue;
148
+
149
+ const timestamps = readdirSync(nameDir).filter((entry) => {
150
+ const full = join(nameDir, entry);
151
+ return statSync(full).isDirectory();
152
+ });
153
+
154
+ // Sort newest-first (ISO strings sort lexicographically)
155
+ timestamps.sort().reverse();
156
+
157
+ for (const ts of timestamps) {
158
+ const runDir = join(nameDir, ts);
159
+ try {
160
+ const graph = readGraph(runDir);
161
+ const total = graph.steps.length;
162
+ const completed = graph.steps.filter((s) => s.status === "complete").length;
163
+ const pending = graph.steps.filter((s) => s.status === "pending").length;
164
+ const active = graph.steps.filter((s) => s.status === "active").length;
165
+
166
+ results.push({
167
+ name,
168
+ timestamp: ts,
169
+ runDir,
170
+ steps: { total, completed, pending, active },
171
+ status: deriveStatus(graph),
172
+ });
173
+ } catch {
174
+ // Skip runs with invalid/missing GRAPH.yaml
175
+ }
176
+ }
177
+ }
178
+
179
+ return results;
180
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Service Tier — gating, status formatting, icon resolution, and
3
+ * the /gsd fast command handler.
4
+ *
5
+ * Service tiers (priority/flex) are an OpenAI feature that only applies
6
+ * to gpt-5.4 variants. This module centralizes the model-gating logic
7
+ * so that icons, preferences, and the before_provider_request hook all
8
+ * use a single source of truth.
9
+ */
10
+
11
+ import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
12
+
13
+ import { existsSync, readFileSync } from "node:fs";
14
+ import { saveFile } from "./files.js";
15
+ import {
16
+ getGlobalGSDPreferencesPath,
17
+ loadEffectiveGSDPreferences,
18
+ loadGlobalGSDPreferences,
19
+ } from "./preferences.js";
20
+ import { ensurePreferencesFile, serializePreferencesToFrontmatter } from "./commands-prefs-wizard.js";
21
+
22
+ // ─── Types ───────────────────────────────────────────────────────────────────
23
+
24
+ export type ServiceTierSetting = "priority" | "flex" | undefined;
25
+
26
+ const SERVICE_TIER_SCOPE_NOTE = "Only affects gpt-5.4 models, regardless of provider.";
27
+
28
+ // ─── Gating ──────────────────────────────────────────────────────────────────
29
+
30
+ /**
31
+ * Returns true when the given model ID supports OpenAI service tiers.
32
+ * Currently only gpt-5.4 variants qualify.
33
+ */
34
+ export function supportsServiceTier(modelId: string): boolean {
35
+ if (!modelId) return false;
36
+ // Strip provider prefix if present (e.g. "openai/gpt-5.4" → "gpt-5.4")
37
+ const bare = modelId.includes("/") ? modelId.split("/").pop()! : modelId;
38
+ return bare.startsWith("gpt-5.4");
39
+ }
40
+
41
+ // ─── Status Formatting ───────────────────────────────────────────────────────
42
+
43
+ /**
44
+ * Human-readable description of the current service tier setting.
45
+ */
46
+ export function formatServiceTierStatus(tier: ServiceTierSetting): string {
47
+ if (!tier) {
48
+ return [
49
+ "Service tier: disabled",
50
+ "",
51
+ "Usage:",
52
+ " /gsd fast on Set to priority (2x cost, faster)",
53
+ " /gsd fast flex Set to flex (0.5x cost, slower)",
54
+ " /gsd fast off Disable service tier",
55
+ "",
56
+ SERVICE_TIER_SCOPE_NOTE,
57
+ ].join("\n");
58
+ }
59
+
60
+ const label = tier === "priority" ? "priority (2x cost, faster)" : "flex (0.5x cost, slower)";
61
+ return [
62
+ `Service tier: ${label}`,
63
+ "",
64
+ "Usage:",
65
+ " /gsd fast on Set to priority (2x cost, faster)",
66
+ " /gsd fast flex Set to flex (0.5x cost, slower)",
67
+ " /gsd fast off Disable service tier",
68
+ "",
69
+ SERVICE_TIER_SCOPE_NOTE,
70
+ ].join("\n");
71
+ }
72
+
73
+ export function formatServiceTierFooterStatus(
74
+ tier: ServiceTierSetting,
75
+ modelId: string | undefined,
76
+ ): string | undefined {
77
+ if (!tier || !modelId || !supportsServiceTier(modelId)) return undefined;
78
+ return tier === "priority" ? "fast: ⚡ priority" : "fast: 💰 flex";
79
+ }
80
+
81
+ // ─── Icon Resolution ─────────────────────────────────────────────────────────
82
+
83
+ /**
84
+ * Returns the appropriate icon for the active service tier and model.
85
+ * Returns empty string when the tier is inactive or the model doesn't
86
+ * support service tiers.
87
+ */
88
+ export function resolveServiceTierIcon(tier: ServiceTierSetting, modelId: string): string {
89
+ if (!tier || !supportsServiceTier(modelId)) return "";
90
+ return tier === "priority" ? "⚡" : "💰";
91
+ }
92
+
93
+ // ─── Preference Read ─────────────────────────────────────────────────────────
94
+
95
+ /**
96
+ * Read the effective service_tier setting from preferences.
97
+ */
98
+ export function getEffectiveServiceTier(): ServiceTierSetting {
99
+ const prefs = loadEffectiveGSDPreferences()?.preferences;
100
+ const raw = prefs?.service_tier;
101
+ if (raw === "priority" || raw === "flex") return raw;
102
+ return undefined;
103
+ }
104
+
105
+ // ─── Preference Write ────────────────────────────────────────────────────────
106
+
107
+ function extractBodyAfterFrontmatter(content: string): string | null {
108
+ const start = content.startsWith("---\n") ? 4 : content.startsWith("---\r\n") ? 5 : -1;
109
+ if (start === -1) return null;
110
+ const closingIdx = content.indexOf("\n---", start);
111
+ if (closingIdx === -1) return null;
112
+ const after = content.slice(closingIdx + 4);
113
+ return after.trim() ? after : null;
114
+ }
115
+
116
+ async function writeGlobalServiceTier(
117
+ ctx: ExtensionCommandContext,
118
+ tier: ServiceTierSetting,
119
+ ): Promise<void> {
120
+ const path = getGlobalGSDPreferencesPath();
121
+ await ensurePreferencesFile(path, ctx, "global");
122
+
123
+ const existing = loadGlobalGSDPreferences();
124
+ const prefs: Record<string, unknown> = existing?.preferences ? { ...existing.preferences } : {};
125
+ prefs.version = prefs.version || 1;
126
+
127
+ if (tier) {
128
+ prefs.service_tier = tier;
129
+ } else {
130
+ delete prefs.service_tier;
131
+ }
132
+
133
+ const frontmatter = serializePreferencesToFrontmatter(prefs);
134
+ let body = "\n# GSD Skill Preferences\n\nSee `~/.gsd/agent/extensions/gsd/docs/preferences-reference.md` for full field documentation and examples.\n";
135
+ if (existsSync(path)) {
136
+ const preserved = extractBodyAfterFrontmatter(readFileSync(path, "utf-8"));
137
+ if (preserved) body = preserved;
138
+ }
139
+
140
+ await saveFile(path, `---\n${frontmatter}---${body}`);
141
+ await ctx.waitForIdle();
142
+ await ctx.reload();
143
+ }
144
+
145
+ // ─── Command Handler ─────────────────────────────────────────────────────────
146
+
147
+ /**
148
+ * Handle `/gsd fast [on|off|flex|status]`.
149
+ */
150
+ export async function handleFast(args: string, ctx: ExtensionCommandContext): Promise<void> {
151
+ const trimmed = args.trim().toLowerCase();
152
+
153
+ if (!trimmed || trimmed === "status") {
154
+ const tier = getEffectiveServiceTier();
155
+ ctx.ui.notify(formatServiceTierStatus(tier), "info");
156
+ return;
157
+ }
158
+
159
+ if (trimmed === "on") {
160
+ await writeGlobalServiceTier(ctx, "priority");
161
+ ctx.ui.setStatus("gsd-fast", formatServiceTierFooterStatus("priority", ctx.model?.id));
162
+ ctx.ui.notify("Service tier set to priority (2x cost, faster responses). Only affects gpt-5.4 models, regardless of provider.", "info");
163
+ return;
164
+ }
165
+
166
+ if (trimmed === "off") {
167
+ await writeGlobalServiceTier(ctx, undefined);
168
+ ctx.ui.setStatus("gsd-fast", undefined);
169
+ ctx.ui.notify("Service tier disabled.", "info");
170
+ return;
171
+ }
172
+
173
+ if (trimmed === "flex") {
174
+ await writeGlobalServiceTier(ctx, "flex");
175
+ ctx.ui.setStatus("gsd-fast", formatServiceTierFooterStatus("flex", ctx.model?.id));
176
+ ctx.ui.notify("Service tier set to flex (0.5x cost, slower responses). Only affects gpt-5.4 models, regardless of provider.", "info");
177
+ return;
178
+ }
179
+
180
+ ctx.ui.notify(
181
+ "Usage: /gsd fast [on|off|flex|status]\n\n on Priority tier (2x cost, faster)\n off Disable service tier\n flex Flex tier (0.5x cost, slower)\n status Show current setting",
182
+ "warning",
183
+ );
184
+ }
@@ -239,7 +239,7 @@ export function acquireSessionLock(basePath: string): SessionLockResult {
239
239
  const elapsed = Date.now() - _lockAcquiredAt;
240
240
  if (elapsed < 1_800_000) {
241
241
  process.stderr.write(
242
- `[gsd] Lock heartbeat mismatch after ${Math.round(elapsed / 1000)}s — event loop stall, continuing.\n`,
242
+ `[gsd] Lock heartbeat caught up after ${Math.round(elapsed / 1000)}s — long LLM call, no action needed.\n`,
243
243
  );
244
244
  return; // Suppress false positive
245
245
  }
@@ -299,7 +299,7 @@ export function acquireSessionLock(basePath: string): SessionLockResult {
299
299
  const elapsed = Date.now() - _lockAcquiredAt;
300
300
  if (elapsed < 1_800_000) {
301
301
  process.stderr.write(
302
- `[gsd] Lock heartbeat mismatch after ${Math.round(elapsed / 1000)}s — event loop stall, continuing.\n`,
302
+ `[gsd] Lock heartbeat caught up after ${Math.round(elapsed / 1000)}s — long LLM call, no action needed.\n`,
303
303
  );
304
304
  return;
305
305
  }
@@ -25,6 +25,7 @@ interface DecisionInput {
25
25
  choice: string;
26
26
  rationale: string;
27
27
  revisable: string;
28
+ made_by?: string;
28
29
  }
29
30
 
30
31
  interface RequirementInput {
@@ -61,6 +62,7 @@ export function formatDecisionCompact(decision: DecisionInput): string {
61
62
  decision.choice,
62
63
  decision.rationale,
63
64
  decision.revisable,
65
+ decision.made_by ?? 'agent',
64
66
  ].join(" | ");
65
67
  }
66
68
 
@@ -70,7 +72,7 @@ export function formatDecisionsCompact(decisions: DecisionInput[]): string {
70
72
  return "# Decisions (compact)\n(none)";
71
73
  }
72
74
 
73
- const header = "# Decisions (compact)\nFields: id | when | scope | decision | choice | rationale | revisable";
75
+ const header = "# Decisions (compact)\nFields: id | when | scope | decision | choice | rationale | revisable | made_by";
74
76
  const lines = decisions.map(formatDecisionCompact);
75
77
  return `${header}\n\n${lines.join("\n")}`;
76
78
  }
@@ -4,5 +4,5 @@
4
4
  To reverse a decision, add a new row that supersedes it.
5
5
  Read this file at the start of any planning or research phase. -->
6
6
 
7
- | # | When | Scope | Decision | Choice | Rationale | Revisable? |
8
- |---|------|-------|----------|--------|-----------|------------|
7
+ | # | When | Scope | Decision | Choice | Rationale | Revisable? | Made By |
8
+ |---|------|-------|----------|--------|-----------|------------|---------|
@@ -4,7 +4,7 @@
4
4
  * - activity-log-save.test.ts (caching, dedup, collision recovery)
5
5
  */
6
6
 
7
- import test from "node:test";
7
+ import { describe, test, beforeEach, afterEach } from "node:test";
8
8
  import assert from "node:assert/strict";
9
9
  import { existsSync, mkdtempSync, mkdirSync, readdirSync, realpathSync, rmSync, utimesSync, writeFileSync, readFileSync } from "node:fs";
10
10
  import { join, dirname } from "node:path";
@@ -48,9 +48,12 @@ function createCtx(entries: unknown[]) {
48
48
 
49
49
  // ── Pruning ──────────────────────────────────────────────────────────────────
50
50
 
51
- test("pruneActivityLogs deletes old files, keeps recent and highest-seq", () => {
52
- const dir = createTmpDir();
53
- try {
51
+ describe("pruneActivityLogs", () => {
52
+ let dir: string;
53
+ beforeEach(() => { dir = createTmpDir(); });
54
+ afterEach(() => { rmSync(dir, { recursive: true, force: true }); });
55
+
56
+ test("deletes old files, keeps recent and highest-seq", () => {
54
57
  const f001 = writeActivityFile(dir, "001", "execute-task-M001-S01-T01");
55
58
  writeActivityFile(dir, "002", "execute-task-M001-S01-T02");
56
59
  writeActivityFile(dir, "003", "execute-task-M001-S01-T03");
@@ -61,14 +64,9 @@ test("pruneActivityLogs deletes old files, keeps recent and highest-seq", () =>
61
64
  assert.ok(!remaining.includes("001-execute-task-M001-S01-T01.jsonl"));
62
65
  assert.ok(remaining.includes("002-execute-task-M001-S01-T02.jsonl"));
63
66
  assert.ok(remaining.includes("003-execute-task-M001-S01-T03.jsonl"));
64
- } finally {
65
- rmSync(dir, { recursive: true, force: true });
66
- }
67
- });
67
+ });
68
68
 
69
- test("pruneActivityLogs preserves highest-seq even when all files are old", () => {
70
- const dir = createTmpDir();
71
- try {
69
+ test("preserves highest-seq even when all files are old", () => {
72
70
  const f001 = writeActivityFile(dir, "001", "t1");
73
71
  const f002 = writeActivityFile(dir, "002", "t2");
74
72
  const f003 = writeActivityFile(dir, "003", "t3");
@@ -78,14 +76,9 @@ test("pruneActivityLogs preserves highest-seq even when all files are old", () =
78
76
  const remaining = listFiles(dir);
79
77
  assert.equal(remaining.length, 1);
80
78
  assert.ok(remaining[0].startsWith("003-"));
81
- } finally {
82
- rmSync(dir, { recursive: true, force: true });
83
- }
84
- });
79
+ });
85
80
 
86
- test("pruneActivityLogs with retentionDays=0 keeps only highest-seq", () => {
87
- const dir = createTmpDir();
88
- try {
81
+ test("with retentionDays=0 keeps only highest-seq", () => {
89
82
  writeActivityFile(dir, "001", "t1");
90
83
  writeActivityFile(dir, "002", "t2");
91
84
  writeActivityFile(dir, "003", "t3");
@@ -94,51 +87,31 @@ test("pruneActivityLogs with retentionDays=0 keeps only highest-seq", () => {
94
87
  const remaining = listFiles(dir);
95
88
  assert.equal(remaining.length, 1);
96
89
  assert.ok(remaining[0].startsWith("003-"));
97
- } finally {
98
- rmSync(dir, { recursive: true, force: true });
99
- }
100
- });
90
+ });
101
91
 
102
- test("pruneActivityLogs no-op when all files are recent", () => {
103
- const dir = createTmpDir();
104
- try {
92
+ test("no-op when all files are recent", () => {
105
93
  writeActivityFile(dir, "001", "t1");
106
94
  writeActivityFile(dir, "002", "t2");
107
95
  writeActivityFile(dir, "003", "t3");
108
96
 
109
97
  pruneActivityLogs(dir, 30);
110
98
  assert.equal(listFiles(dir).length, 3);
111
- } finally {
112
- rmSync(dir, { recursive: true, force: true });
113
- }
114
- });
99
+ });
115
100
 
116
- test("pruneActivityLogs handles empty directory", () => {
117
- const dir = createTmpDir();
118
- try {
101
+ test("handles empty directory", () => {
119
102
  assert.doesNotThrow(() => pruneActivityLogs(dir, 30));
120
103
  assert.equal(readdirSync(dir).length, 0);
121
- } finally {
122
- rmSync(dir, { recursive: true, force: true });
123
- }
124
- });
104
+ });
125
105
 
126
- test("pruneActivityLogs preserves single old file (it is highest-seq)", () => {
127
- const dir = createTmpDir();
128
- try {
106
+ test("preserves single old file (it is highest-seq)", () => {
129
107
  const f = writeActivityFile(dir, "001", "t1");
130
108
  backdateFile(f, 100);
131
109
 
132
110
  pruneActivityLogs(dir, 30);
133
111
  assert.equal(listFiles(dir).length, 1);
134
- } finally {
135
- rmSync(dir, { recursive: true, force: true });
136
- }
137
- });
112
+ });
138
113
 
139
- test("pruneActivityLogs ignores non-matching filenames", () => {
140
- const dir = createTmpDir();
141
- try {
114
+ test("ignores non-matching filenames", () => {
142
115
  const f001 = writeActivityFile(dir, "001", "t1");
143
116
  writeFileSync(join(dir, "notes.txt"), "some notes\n", "utf-8");
144
117
  backdateFile(f001, 40);
@@ -148,16 +121,17 @@ test("pruneActivityLogs ignores non-matching filenames", () => {
148
121
  assert.ok(remaining.includes("notes.txt"));
149
122
  // 001 is the only seq file, so it's highest-seq and survives
150
123
  assert.ok(remaining.includes("001-t1.jsonl"));
151
- } finally {
152
- rmSync(dir, { recursive: true, force: true });
153
- }
124
+ });
154
125
  });
155
126
 
156
127
  // ── Save: caching, dedup, collision recovery ─────────────────────────────────
157
128
 
158
- test("saveActivityLog caches sequence instead of rescanning", () => {
159
- const baseDir = createTmpDir();
160
- try {
129
+ describe("saveActivityLog", () => {
130
+ let baseDir: string;
131
+ beforeEach(() => { baseDir = createTmpDir(); });
132
+ afterEach(() => { rmSync(baseDir, { recursive: true, force: true }); });
133
+
134
+ test("caches sequence instead of rescanning", () => {
161
135
  saveActivityLog(createCtx([{ kind: "first", n: 1 }]) as any, baseDir, "execute-task", "M001/S01/T01");
162
136
  writeFileSync(join(activityDir(baseDir), "999-external.jsonl"), '{"x":1}\n', "utf-8");
163
137
  saveActivityLog(createCtx([{ kind: "second", n: 2 }]) as any, baseDir, "execute-task", "M001/S01/T02");
@@ -166,14 +140,9 @@ test("saveActivityLog caches sequence instead of rescanning", () => {
166
140
  assert.ok(files.includes("001-execute-task-M001-S01-T01.jsonl"));
167
141
  assert.ok(files.includes("002-execute-task-M001-S01-T02.jsonl"));
168
142
  assert.ok(!files.some(f => f.startsWith("1000-")));
169
- } finally {
170
- rmSync(baseDir, { recursive: true, force: true });
171
- }
172
- });
143
+ });
173
144
 
174
- test("saveActivityLog deduplicates identical snapshots for same unit", () => {
175
- const baseDir = createTmpDir();
176
- try {
145
+ test("deduplicates identical snapshots for same unit", () => {
177
146
  const ctx = createCtx([{ role: "assistant", content: "same" }]);
178
147
  saveActivityLog(ctx as any, baseDir, "plan-slice", "M002/S01");
179
148
  saveActivityLog(ctx as any, baseDir, "plan-slice", "M002/S01");
@@ -184,14 +153,9 @@ test("saveActivityLog deduplicates identical snapshots for same unit", () => {
184
153
  saveActivityLog(createCtx([{ role: "assistant", content: "changed" }]) as any, baseDir, "plan-slice", "M002/S01");
185
154
  files = listFiles(activityDir(baseDir));
186
155
  assert.equal(files.length, 2);
187
- } finally {
188
- rmSync(baseDir, { recursive: true, force: true });
189
- }
190
- });
156
+ });
191
157
 
192
- test("saveActivityLog recovers on sequence collision", () => {
193
- const baseDir = createTmpDir();
194
- try {
158
+ test("recovers on sequence collision", () => {
195
159
  saveActivityLog(createCtx([{ turn: 1 }]) as any, baseDir, "execute-task", "M003/S02/T01");
196
160
  writeFileSync(join(activityDir(baseDir), "002-execute-task-M003-S02-T02.jsonl"), '{"collision":true}\n', "utf-8");
197
161
  saveActivityLog(createCtx([{ turn: 2 }]) as any, baseDir, "execute-task", "M003/S02/T02");
@@ -199,9 +163,7 @@ test("saveActivityLog recovers on sequence collision", () => {
199
163
  const files = listFiles(activityDir(baseDir));
200
164
  assert.ok(files.includes("002-execute-task-M003-S02-T02.jsonl"));
201
165
  assert.ok(files.includes("003-execute-task-M003-S02-T02.jsonl"));
202
- } finally {
203
- rmSync(baseDir, { recursive: true, force: true });
204
- }
166
+ });
205
167
  });
206
168
 
207
169
  // ── Prompt text assertion ────────────────────────────────────────────────────