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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gsd/pi-coding-agent",
3
- "version": "2.41.0",
3
+ "version": "2.42.0",
4
4
  "description": "Coding agent CLI (vendored from pi-mono)",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -687,6 +687,8 @@ export class AgentSession {
687
687
  * Call this when completely done with the session.
688
688
  */
689
689
  dispose(): void {
690
+ this._extensionErrorUnsubscriber?.();
691
+ this._extensionErrorUnsubscriber = undefined;
690
692
  this._disconnectFromAgent();
691
693
  this._eventListeners = [];
692
694
  }
@@ -1928,7 +1930,11 @@ export class AgentSession {
1928
1930
  runner.setUIContext(this._extensionUIContext);
1929
1931
  runner.bindCommandContext(this._extensionCommandContextActions);
1930
1932
 
1931
- this._extensionErrorUnsubscriber?.();
1933
+ try {
1934
+ this._extensionErrorUnsubscriber?.();
1935
+ } catch {
1936
+ // Ignore errors from previous unsubscriber
1937
+ }
1932
1938
  this._extensionErrorUnsubscriber = this._extensionErrorListener
1933
1939
  ? runner.onError(this._extensionErrorListener)
1934
1940
  : undefined;
@@ -263,6 +263,74 @@ describe("AuthStorage — areAllCredentialsBackedOff", () => {
263
263
  });
264
264
  });
265
265
 
266
+ // ─── mismatched oauth credential for non-OAuth provider (#2083) ───────────────
267
+
268
+ describe("AuthStorage — oauth credential for non-OAuth provider (#2083)", () => {
269
+ it("returns undefined when openrouter has type:oauth (no registered OAuth provider)", async () => {
270
+ // Simulates the bug: OpenRouter credential stored as type:"oauth"
271
+ // but OpenRouter is not a registered OAuth provider.
272
+ const storage = inMemory({
273
+ openrouter: {
274
+ type: "oauth",
275
+ access_token: "sk-or-v1-fake",
276
+ refresh_token: "rt-fake",
277
+ expires: Date.now() + 3_600_000,
278
+ },
279
+ });
280
+
281
+ // Before the fix, getApiKey returns undefined because
282
+ // resolveCredentialApiKey calls getOAuthProvider("openrouter") → null → undefined.
283
+ // The key in the oauth credential is never extracted.
284
+ const key = await storage.getApiKey("openrouter");
285
+ // After the fix, the oauth credential with an unrecognised provider
286
+ // should be skipped, and getApiKey should fall through to env / fallback.
287
+ assert.equal(key, undefined);
288
+ });
289
+
290
+ it("falls through to env var when openrouter has type:oauth credential", async () => {
291
+ const storage = inMemory({
292
+ openrouter: {
293
+ type: "oauth",
294
+ access_token: "sk-or-v1-fake",
295
+ refresh_token: "rt-fake",
296
+ expires: Date.now() + 3_600_000,
297
+ },
298
+ });
299
+
300
+ // Simulate OPENROUTER_API_KEY being set via env
301
+ const origEnv = process.env.OPENROUTER_API_KEY;
302
+ try {
303
+ process.env.OPENROUTER_API_KEY = "sk-or-v1-env-key";
304
+ const key = await storage.getApiKey("openrouter");
305
+ assert.equal(key, "sk-or-v1-env-key");
306
+ } finally {
307
+ if (origEnv === undefined) {
308
+ delete process.env.OPENROUTER_API_KEY;
309
+ } else {
310
+ process.env.OPENROUTER_API_KEY = origEnv;
311
+ }
312
+ }
313
+ });
314
+
315
+ it("falls through to fallback resolver when openrouter has type:oauth credential", async () => {
316
+ const storage = inMemory({
317
+ openrouter: {
318
+ type: "oauth",
319
+ access_token: "sk-or-v1-fake",
320
+ refresh_token: "rt-fake",
321
+ expires: Date.now() + 3_600_000,
322
+ },
323
+ });
324
+
325
+ storage.setFallbackResolver((provider) =>
326
+ provider === "openrouter" ? "sk-or-v1-fallback" : undefined,
327
+ );
328
+
329
+ const key = await storage.getApiKey("openrouter");
330
+ assert.equal(key, "sk-or-v1-fallback");
331
+ });
332
+ });
333
+
266
334
  // ─── getAll truncation ────────────────────────────────────────────────────────
267
335
 
268
336
  describe("AuthStorage — getAll()", () => {
@@ -202,6 +202,7 @@ export class AuthStorage {
202
202
  private fallbackResolver?: (provider: string) => string | undefined;
203
203
  private loadError: Error | null = null;
204
204
  private errors: Error[] = [];
205
+ private credentialChangeListeners: Set<() => void> = new Set();
205
206
 
206
207
  /**
207
208
  * Round-robin index per provider. Incremented on each call to getApiKey
@@ -263,6 +264,25 @@ export class AuthStorage {
263
264
  this.fallbackResolver = resolver;
264
265
  }
265
266
 
267
+ /**
268
+ * Register a callback to be notified when credentials change (e.g., after OAuth token refresh).
269
+ * Returns a function to unregister the listener.
270
+ */
271
+ onCredentialChange(listener: () => void): () => void {
272
+ this.credentialChangeListeners.add(listener);
273
+ return () => this.credentialChangeListeners.delete(listener);
274
+ }
275
+
276
+ private notifyCredentialChange(): void {
277
+ for (const listener of this.credentialChangeListeners) {
278
+ try {
279
+ listener();
280
+ } catch {
281
+ // Don't let listener errors break the refresh flow
282
+ }
283
+ }
284
+ }
285
+
266
286
  private recordError(error: unknown): void {
267
287
  const normalizedError = error instanceof Error ? error : new Error(String(error));
268
288
  this.errors.push(normalizedError);
@@ -667,6 +687,11 @@ export class AuthStorage {
667
687
  return { result: refreshed, next: JSON.stringify(merged, null, 2) };
668
688
  });
669
689
 
690
+ // Notify listeners after credential change (e.g., model registry refresh)
691
+ if (result) {
692
+ queueMicrotask(() => this.notifyCredentialChange());
693
+ }
694
+
670
695
  return result;
671
696
  }
672
697
 
@@ -731,9 +756,12 @@ export class AuthStorage {
731
756
  if (credentials.length > 0) {
732
757
  const index = this.selectCredentialIndex(providerId, credentials, sessionId);
733
758
  if (index >= 0) {
734
- return this.resolveCredentialApiKey(providerId, credentials[index]);
759
+ const resolved = await this.resolveCredentialApiKey(providerId, credentials[index]);
760
+ if (resolved) return resolved;
761
+ // Credential unresolvable (e.g. type:"oauth" for a non-OAuth provider) —
762
+ // fall through to env / fallback instead of returning undefined (#2083)
735
763
  }
736
- // All credentials backed off - fall through to env/fallback
764
+ // All credentials backed off or unresolvable - fall through to env/fallback
737
765
  }
738
766
 
739
767
  // Fall back to environment variable
@@ -1,5 +1,5 @@
1
1
  import assert from "node:assert/strict";
2
- import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
2
+ import { mkdirSync, rmSync, writeFileSync } from "node:fs";
3
3
  import { tmpdir } from "node:os";
4
4
  import { join } from "node:path";
5
5
  import { afterEach, beforeEach, describe, it } from "node:test";
@@ -59,7 +59,9 @@ describe("ModelDiscoveryCache — basic operations", () => {
59
59
 
60
60
  cache.clear("openai");
61
61
  assert.equal(cache.get("openai"), undefined);
62
- assert.ok(cache.get("google"));
62
+ const googleEntry = cache.get("google");
63
+ assert.ok(googleEntry);
64
+ assert.equal(googleEntry.models[0].id, "gemini-pro");
63
65
  });
64
66
 
65
67
  it("clear without provider removes all entries", () => {
@@ -569,6 +569,24 @@ function createExtensionAPI(
569
569
  }
570
570
 
571
571
  async function loadExtensionModule(extensionPath: string) {
572
+ // Pre-compiled extension loading: if the source is .ts and a sibling .js
573
+ // file exists with matching or newer mtime, use native import() to skip
574
+ // jiti JIT compilation entirely. This is the biggest startup win for
575
+ // bundled extensions that have already been built.
576
+ if (extensionPath.endsWith(".ts")) {
577
+ const jsPath = extensionPath.replace(/\.ts$/, ".js");
578
+ try {
579
+ const [tsStat, jsStat] = [fs.statSync(extensionPath), fs.statSync(jsPath)];
580
+ if (jsStat.mtimeMs >= tsStat.mtimeMs) {
581
+ const module = await import(jsPath);
582
+ const factory = (module.default ?? module) as ExtensionFactory;
583
+ return typeof factory !== "function" ? undefined : factory;
584
+ }
585
+ } catch {
586
+ // .js file doesn't exist or stat failed — fall through to jiti
587
+ }
588
+ }
589
+
572
590
  const jiti = createJiti(import.meta.url, {
573
591
  moduleCache: false,
574
592
  ...getJitiOptions(),
@@ -29,6 +29,9 @@ let idleTimeoutMs: number | null = null;
29
29
  let idleCheckInterval: ReturnType<typeof setInterval> | null = null;
30
30
  const IDLE_CHECK_INTERVAL_MS = 60 * 1000;
31
31
 
32
+ /** Maximum allowed size for the message buffer (10 MB). */
33
+ const MAX_MESSAGE_BUFFER_SIZE = 10 * 1024 * 1024;
34
+
32
35
  /**
33
36
  * Configure the idle timeout for LSP clients.
34
37
  */
@@ -52,6 +55,10 @@ function startIdleChecker(): void {
52
55
  shutdownClient(key);
53
56
  }
54
57
  }
58
+ // Stop the checker if there are no more clients to monitor
59
+ if (clients.size === 0) {
60
+ stopIdleChecker();
61
+ }
55
62
  }, IDLE_CHECK_INTERVAL_MS);
56
63
  }
57
64
 
@@ -252,6 +259,17 @@ async function startMessageReader(client: LspClient): Promise<void> {
252
259
  return new Promise<void>((resolve) => {
253
260
  stdout.on("data", async (chunk: Buffer) => {
254
261
  const currentBuffer: Buffer = Buffer.concat([client.messageBuffer, chunk]);
262
+
263
+ if (currentBuffer.length > MAX_MESSAGE_BUFFER_SIZE) {
264
+ if (process.env.DEBUG) {
265
+ console.error(
266
+ `[lsp] Message buffer exceeded ${MAX_MESSAGE_BUFFER_SIZE} bytes (${currentBuffer.length}), discarding`,
267
+ );
268
+ }
269
+ client.messageBuffer = Buffer.alloc(0);
270
+ return;
271
+ }
272
+
255
273
  client.messageBuffer = currentBuffer;
256
274
 
257
275
  let workingBuffer = currentBuffer;
@@ -708,6 +726,14 @@ function shutdownClient(key: string): void {
708
726
  client.proc.kill();
709
727
  }
710
728
  clients.delete(key);
729
+ clientLocks.delete(key);
730
+
731
+ // Clean up any file operation locks associated with this client
732
+ for (const lockKey of Array.from(fileOperationLocks.keys())) {
733
+ if (lockKey.startsWith(`${key}:`)) {
734
+ fileOperationLocks.delete(lockKey);
735
+ }
736
+ }
711
737
  }
712
738
 
713
739
  // =============================================================================
@@ -822,6 +848,9 @@ async function sendNotification(client: LspClient, method: string, params: unkno
822
848
  function shutdownAll(): void {
823
849
  const clientsToShutdown = Array.from(clients.values());
824
850
  clients.clear();
851
+ clientLocks.clear();
852
+ fileOperationLocks.clear();
853
+ stopIdleChecker();
825
854
 
826
855
  const err = new Error("LSP client shutdown");
827
856
  for (const client of clientsToShutdown) {
@@ -243,6 +243,9 @@ export class ModelRegistry {
243
243
  return undefined;
244
244
  });
245
245
 
246
+ // Refresh models when credentials change (e.g., OAuth token refresh with new model limits)
247
+ this.authStorage.onCredentialChange(() => this.refresh());
248
+
246
249
  // Load models
247
250
  this.loadModels();
248
251
  }
@@ -1562,6 +1562,26 @@ export class DefaultPackageManager implements PackageManager {
1562
1562
  }
1563
1563
  }
1564
1564
 
1565
+ /**
1566
+ * Batch-discover which resource subdirectories exist under a parent dir.
1567
+ * A single readdirSync replaces 4 separate existsSync probes, reducing
1568
+ * syscalls during startup.
1569
+ */
1570
+ private discoverResourceSubdirs(baseDir: string): Set<string> {
1571
+ try {
1572
+ const entries = readdirSync(baseDir, { withFileTypes: true });
1573
+ const names = new Set<string>();
1574
+ for (const e of entries) {
1575
+ if (e.isDirectory() || e.isSymbolicLink()) {
1576
+ names.add(e.name);
1577
+ }
1578
+ }
1579
+ return names;
1580
+ } catch {
1581
+ return new Set();
1582
+ }
1583
+ }
1584
+
1565
1585
  private addAutoDiscoveredResources(
1566
1586
  accumulator: ResourceAccumulator,
1567
1587
  globalSettings: ReturnType<SettingsManager["getGlobalSettings"]>,
@@ -1595,6 +1615,11 @@ export class DefaultPackageManager implements PackageManager {
1595
1615
  themes: (projectSettings.themes ?? []) as string[],
1596
1616
  };
1597
1617
 
1618
+ // Batch directory discovery: one readdir of each parent replaces up to
1619
+ // 4 separate existsSync calls per base directory, cutting syscalls.
1620
+ const projectSubdirs = this.discoverResourceSubdirs(projectBaseDir);
1621
+ const userSubdirs = this.discoverResourceSubdirs(globalBaseDir);
1622
+
1598
1623
  const userDirs = {
1599
1624
  extensions: join(globalBaseDir, "extensions"),
1600
1625
  skills: join(globalBaseDir, "skills"),
@@ -1626,66 +1651,82 @@ export class DefaultPackageManager implements PackageManager {
1626
1651
  }
1627
1652
  };
1628
1653
 
1629
- addResources(
1630
- "extensions",
1631
- collectAutoExtensionEntries(projectDirs.extensions),
1632
- projectMetadata,
1633
- projectOverrides.extensions,
1634
- projectBaseDir,
1635
- );
1636
- addResources(
1637
- "skills",
1638
- [
1639
- ...collectAutoSkillEntries(projectDirs.skills),
1654
+ // Project resources — skip collect calls when the parent readdir shows
1655
+ // the subdirectory doesn't exist (avoids redundant existsSync + readdirSync).
1656
+ if (projectSubdirs.has("extensions")) {
1657
+ addResources(
1658
+ "extensions",
1659
+ collectAutoExtensionEntries(projectDirs.extensions),
1660
+ projectMetadata,
1661
+ projectOverrides.extensions,
1662
+ projectBaseDir,
1663
+ );
1664
+ }
1665
+ {
1666
+ const skillEntries = [
1667
+ ...(projectSubdirs.has("skills") ? collectAutoSkillEntries(projectDirs.skills) : []),
1640
1668
  ...projectAgentsSkillDirs.flatMap((dir) => collectAutoSkillEntries(dir)),
1641
- ],
1642
- projectMetadata,
1643
- projectOverrides.skills,
1644
- projectBaseDir,
1645
- );
1646
- addResources(
1647
- "prompts",
1648
- collectAutoPromptEntries(projectDirs.prompts),
1649
- projectMetadata,
1650
- projectOverrides.prompts,
1651
- projectBaseDir,
1652
- );
1653
- addResources(
1654
- "themes",
1655
- collectAutoThemeEntries(projectDirs.themes),
1656
- projectMetadata,
1657
- projectOverrides.themes,
1658
- projectBaseDir,
1659
- );
1669
+ ];
1670
+ if (skillEntries.length > 0) {
1671
+ addResources("skills", skillEntries, projectMetadata, projectOverrides.skills, projectBaseDir);
1672
+ }
1673
+ }
1674
+ if (projectSubdirs.has("prompts")) {
1675
+ addResources(
1676
+ "prompts",
1677
+ collectAutoPromptEntries(projectDirs.prompts),
1678
+ projectMetadata,
1679
+ projectOverrides.prompts,
1680
+ projectBaseDir,
1681
+ );
1682
+ }
1683
+ if (projectSubdirs.has("themes")) {
1684
+ addResources(
1685
+ "themes",
1686
+ collectAutoThemeEntries(projectDirs.themes),
1687
+ projectMetadata,
1688
+ projectOverrides.themes,
1689
+ projectBaseDir,
1690
+ );
1691
+ }
1660
1692
 
1661
- addResources(
1662
- "extensions",
1663
- collectAutoExtensionEntries(userDirs.extensions),
1664
- userMetadata,
1665
- userOverrides.extensions,
1666
- globalBaseDir,
1667
- );
1668
- addResources(
1669
- "skills",
1670
- [...collectAutoSkillEntries(userDirs.skills), ...collectAutoSkillEntries(userAgentsSkillsDir)],
1671
- userMetadata,
1672
- userOverrides.skills,
1673
- globalBaseDir,
1674
- );
1675
- addResources(
1676
- "prompts",
1677
- collectAutoPromptEntries(userDirs.prompts),
1678
- userMetadata,
1679
- userOverrides.prompts,
1680
- globalBaseDir,
1681
- );
1682
- addResources(
1683
- "themes",
1684
- collectAutoThemeEntries(userDirs.themes),
1685
- userMetadata,
1686
- userOverrides.themes,
1687
- globalBaseDir,
1688
- );
1693
+ // User (global) resources
1694
+ if (userSubdirs.has("extensions")) {
1695
+ addResources(
1696
+ "extensions",
1697
+ collectAutoExtensionEntries(userDirs.extensions),
1698
+ userMetadata,
1699
+ userOverrides.extensions,
1700
+ globalBaseDir,
1701
+ );
1702
+ }
1703
+ {
1704
+ const skillEntries = [
1705
+ ...(userSubdirs.has("skills") ? collectAutoSkillEntries(userDirs.skills) : []),
1706
+ ...collectAutoSkillEntries(userAgentsSkillsDir),
1707
+ ];
1708
+ if (skillEntries.length > 0) {
1709
+ addResources("skills", skillEntries, userMetadata, userOverrides.skills, globalBaseDir);
1710
+ }
1711
+ }
1712
+ if (userSubdirs.has("prompts")) {
1713
+ addResources(
1714
+ "prompts",
1715
+ collectAutoPromptEntries(userDirs.prompts),
1716
+ userMetadata,
1717
+ userOverrides.prompts,
1718
+ globalBaseDir,
1719
+ );
1720
+ }
1721
+ if (userSubdirs.has("themes")) {
1722
+ addResources(
1723
+ "themes",
1724
+ collectAutoThemeEntries(userDirs.themes),
1725
+ userMetadata,
1726
+ userOverrides.themes,
1727
+ globalBaseDir,
1728
+ );
1729
+ }
1689
1730
  }
1690
1731
 
1691
1732
  private collectFilesFromPaths(paths: string[], resourceType: ResourceType): string[] {
@@ -1,6 +1,6 @@
1
1
  import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
2
2
  import { homedir } from "node:os";
3
- import { join, resolve, sep } from "node:path";
3
+ import { basename, dirname, join, resolve, sep } from "node:path";
4
4
  import chalk from "chalk";
5
5
  import { CONFIG_DIR_NAME, getAgentDir } from "../config.js";
6
6
  import { loadThemeFromPath, type Theme } from "../modes/interactive/theme/theme.js";
@@ -127,6 +127,8 @@ export interface DefaultResourceLoaderOptions {
127
127
  noThemes?: boolean;
128
128
  systemPrompt?: string;
129
129
  appendSystemPrompt?: string;
130
+ /** Names of bundled extensions (used to identify built-in extensions in conflict detection). */
131
+ bundledExtensionNames?: Set<string>;
130
132
  extensionsOverride?: (base: LoadExtensionsResult) => LoadExtensionsResult;
131
133
  skillsOverride?: (base: { skills: Skill[]; diagnostics: ResourceDiagnostic[] }) => {
132
134
  skills: Skill[];
@@ -164,6 +166,7 @@ export class DefaultResourceLoader implements ResourceLoader {
164
166
  private noThemes: boolean;
165
167
  private systemPromptSource?: string;
166
168
  private appendSystemPromptSource?: string;
169
+ private bundledExtensionNames: Set<string>;
167
170
  private extensionsOverride?: (base: LoadExtensionsResult) => LoadExtensionsResult;
168
171
  private skillsOverride?: (base: { skills: Skill[]; diagnostics: ResourceDiagnostic[] }) => {
169
172
  skills: Skill[];
@@ -219,6 +222,7 @@ export class DefaultResourceLoader implements ResourceLoader {
219
222
  this.noThemes = options.noThemes ?? false;
220
223
  this.systemPromptSource = options.systemPrompt;
221
224
  this.appendSystemPromptSource = options.appendSystemPrompt;
225
+ this.bundledExtensionNames = options.bundledExtensionNames ?? new Set();
222
226
  this.extensionsOverride = options.extensionsOverride;
223
227
  this.skillsOverride = options.skillsOverride;
224
228
  this.promptsOverride = options.promptsOverride;
@@ -790,6 +794,19 @@ export class DefaultResourceLoader implements ResourceLoader {
790
794
  return target.startsWith(prefix);
791
795
  }
792
796
 
797
+ /**
798
+ * Extract the extension name from its path.
799
+ * For root-level files: basename without extension (e.g. "search-the-web.ts" → "search-the-web")
800
+ * For subdirectory extensions: the directory name (e.g. "/path/to/gsd/index.ts" → "gsd")
801
+ */
802
+ private getExtensionNameFromPath(extPath: string): string {
803
+ const base = basename(extPath);
804
+ if (base === "index.js" || base === "index.ts") {
805
+ return basename(dirname(extPath));
806
+ }
807
+ return base.replace(/\.(?:ts|js)$/, "");
808
+ }
809
+
793
810
  private detectExtensionConflicts(extensions: Extension[]): Array<{ path: string; message: string }> {
794
811
  const conflicts: Array<{ path: string; message: string }> = [];
795
812
 
@@ -803,9 +820,10 @@ export class DefaultResourceLoader implements ResourceLoader {
803
820
  for (const toolName of ext.tools.keys()) {
804
821
  const existingOwner = toolOwners.get(toolName);
805
822
  if (existingOwner && existingOwner !== ext.path) {
806
- // Determine if the existing owner is a built-in (not a user extension)
807
- const isBuiltIn = !existingOwner.includes("/.gsd/agent/extensions/") &&
808
- !existingOwner.includes("/.gsd/extensions/");
823
+ // Determine if the existing owner is a bundled extension by checking
824
+ // its name against the canonical bundled extensions list
825
+ const ownerName = this.getExtensionNameFromPath(existingOwner);
826
+ const isBuiltIn = this.bundledExtensionNames.has(ownerName);
809
827
  const hint = isBuiltIn
810
828
  ? ` (built-in tool supersedes — consider removing ${ext.path})`
811
829
  : "";
@@ -822,8 +840,8 @@ export class DefaultResourceLoader implements ResourceLoader {
822
840
  for (const commandName of ext.commands.keys()) {
823
841
  const existingOwner = commandOwners.get(commandName);
824
842
  if (existingOwner && existingOwner !== ext.path) {
825
- const isBuiltIn = !existingOwner.includes("/.gsd/agent/extensions/") &&
826
- !existingOwner.includes("/.gsd/extensions/");
843
+ const ownerName = this.getExtensionNameFromPath(existingOwner);
844
+ const isBuiltIn = this.bundledExtensionNames.has(ownerName);
827
845
  const hint = isBuiltIn
828
846
  ? ` (built-in command supersedes — consider removing ${ext.path})`
829
847
  : "";
@@ -84,9 +84,9 @@ export function buildSystemPrompt(options: BuildSystemPromptOptions = {}): strin
84
84
  }
85
85
  }
86
86
 
87
- // Append skills section (only if read tool is available)
88
- const customPromptHasRead = !selectedTools || selectedTools.includes("read");
89
- if (customPromptHasRead && skills.length > 0) {
87
+ // Append skills section (if read or Skill tool is available)
88
+ const customPromptHasSkillAccess = !selectedTools || selectedTools.includes("read") || selectedTools.includes("Skill");
89
+ if (customPromptHasSkillAccess && skills.length > 0) {
90
90
  prompt += formatSkillsForPrompt(skills);
91
91
  }
92
92
 
@@ -232,8 +232,9 @@ Pi documentation (read only when the user asks about pi itself, its SDK, extensi
232
232
  }
233
233
  }
234
234
 
235
- // Append skills section (only if read tool is available)
236
- if (hasRead && skills.length > 0) {
235
+ // Append skills section (if read or Skill tool is available)
236
+ const hasSkill = tools.includes("Skill");
237
+ if ((hasRead || hasSkill) && skills.length > 0) {
237
238
  prompt += formatSkillsForPrompt(skills);
238
239
  }
239
240
 
@@ -113,6 +113,9 @@ export class ExtensionEditorComponent extends Container implements Focusable {
113
113
  private openExternalEditor(): void {
114
114
  const editorCmd = process.env.VISUAL || process.env.EDITOR;
115
115
  if (!editorCmd) {
116
+ // No editor configured — nothing to do.
117
+ // The main interactive-mode handler shows a warning with an iTerm2 hint;
118
+ // this component is a secondary editor so we silently bail.
116
119
  return;
117
120
  }
118
121
 
@@ -68,10 +68,14 @@ export class FooterComponent implements Component {
68
68
  const totalCacheWrite = usageTotals.cacheWrite;
69
69
  const totalCost = usageTotals.cost;
70
70
 
71
+ // Use activeInferenceModel during streaming to show the model actually
72
+ // being used, not the configured model which may have been switched mid-turn.
73
+ const displayModel = state.activeInferenceModel ?? state.model;
74
+
71
75
  // Calculate context usage from session (handles compaction correctly).
72
76
  // After compaction, tokens are unknown until the next LLM response.
73
77
  const contextUsage = this.session.getContextUsage();
74
- const contextWindow = contextUsage?.contextWindow ?? state.model?.contextWindow ?? 0;
78
+ const contextWindow = contextUsage?.contextWindow ?? displayModel?.contextWindow ?? 0;
75
79
  const contextPercentValue = contextUsage?.percent ?? 0;
76
80
  const contextPercent = contextUsage?.percent !== null ? contextPercentValue.toFixed(1) : "?";
77
81
 
@@ -102,7 +106,7 @@ export class FooterComponent implements Component {
102
106
  if (totalCacheWrite) statsParts.push(`W${formatTokens(totalCacheWrite)}`);
103
107
 
104
108
  // Show cost with "(sub)" indicator if using OAuth subscription
105
- const usingSubscription = state.model ? this.session.modelRegistry.isUsingOAuth(state.model) : false;
109
+ const usingSubscription = displayModel ? this.session.modelRegistry.isUsingOAuth(displayModel) : false;
106
110
  if (totalCost || usingSubscription) {
107
111
  const costStr = `$${totalCost.toFixed(3)}${usingSubscription ? " (sub)" : ""}`;
108
112
  statsParts.push(costStr);
@@ -127,7 +131,7 @@ export class FooterComponent implements Component {
127
131
  let statsLeft = statsParts.join(" ");
128
132
 
129
133
  // Add model name on the right side, plus thinking level if model supports it
130
- const modelName = state.model?.id || "no-model";
134
+ const modelName = displayModel?.id || "no-model";
131
135
 
132
136
  let statsLeftWidth = visibleWidth(statsLeft);
133
137
 
@@ -142,7 +146,7 @@ export class FooterComponent implements Component {
142
146
 
143
147
  // Add thinking level indicator if model supports reasoning
144
148
  let rightSideWithoutProvider = modelName;
145
- if (state.model?.reasoning) {
149
+ if (displayModel?.reasoning) {
146
150
  const thinkingLevel = state.thinkingLevel || "off";
147
151
  rightSideWithoutProvider =
148
152
  thinkingLevel === "off" ? `${modelName} • thinking off` : `${modelName} • ${thinkingLevel}`;
@@ -150,8 +154,8 @@ export class FooterComponent implements Component {
150
154
 
151
155
  // Prepend the provider in parentheses if there are multiple providers and there's enough room
152
156
  let rightSide = rightSideWithoutProvider;
153
- if (this.footerData.getAvailableProviderCount() > 1 && state.model) {
154
- rightSide = `(${state.model!.provider}) ${rightSideWithoutProvider}`;
157
+ if (this.footerData.getAvailableProviderCount() > 1 && displayModel) {
158
+ rightSide = `(${displayModel.provider}) ${rightSideWithoutProvider}`;
155
159
  if (statsLeftWidth + minPadding + visibleWidth(rightSide) > width) {
156
160
  // Too wide, fall back
157
161
  rightSide = rightSideWithoutProvider;