gsd-pi 2.77.0-dev.c9c8932c6 → 2.77.0-dev.eaa4973bc

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 (245) hide show
  1. package/dist/cli-web-branch.d.ts +1 -0
  2. package/dist/cli-web-branch.js +3 -0
  3. package/dist/cli.js +24 -2
  4. package/dist/provider-migrations.d.ts +18 -0
  5. package/dist/provider-migrations.js +14 -0
  6. package/dist/resources/extensions/claude-code-cli/stream-adapter.js +14 -10
  7. package/dist/resources/extensions/gsd/abandon-detect.js +44 -0
  8. package/dist/resources/extensions/gsd/auto/resolve.js +24 -0
  9. package/dist/resources/extensions/gsd/auto/run-unit.js +10 -2
  10. package/dist/resources/extensions/gsd/auto/turn-epoch.js +95 -0
  11. package/dist/resources/extensions/gsd/auto-dispatch.js +24 -0
  12. package/dist/resources/extensions/gsd/auto-loop.js +1 -1
  13. package/dist/resources/extensions/gsd/auto-post-unit.js +31 -0
  14. package/dist/resources/extensions/gsd/auto-timeout-recovery.js +11 -5
  15. package/dist/resources/extensions/gsd/auto-unit-closeout.js +11 -2
  16. package/dist/resources/extensions/gsd/auto-worktree.js +58 -8
  17. package/dist/resources/extensions/gsd/auto.js +4 -0
  18. package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +4 -2
  19. package/dist/resources/extensions/gsd/commands/handlers/workflow.js +31 -4
  20. package/dist/resources/extensions/gsd/file-lock.js +49 -9
  21. package/dist/resources/extensions/gsd/git-service.js +1 -0
  22. package/dist/resources/extensions/gsd/gitignore.js +1 -0
  23. package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -1
  24. package/dist/resources/extensions/gsd/journal.js +17 -2
  25. package/dist/resources/extensions/gsd/milestone-actions.js +15 -0
  26. package/dist/resources/extensions/gsd/reports.js +5 -4
  27. package/dist/resources/extensions/gsd/tools/complete-slice.js +21 -0
  28. package/dist/resources/extensions/gsd/tools/complete-task.js +31 -0
  29. package/dist/resources/extensions/gsd/uok/audit.js +18 -2
  30. package/dist/resources/extensions/gsd/workflow-logger.js +10 -2
  31. package/dist/resources/extensions/gsd/worktree-manager.js +1 -0
  32. package/dist/resources/extensions/mcp-client/auth.js +10 -1
  33. package/dist/resources/extensions/mcp-client/index.js +118 -9
  34. package/dist/resources/skills/create-skill/SKILL.md +2 -2
  35. package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
  36. package/dist/resources/skills/create-skill/workflows/audit-skill.md +4 -4
  37. package/dist/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
  38. package/dist/tsconfig.extensions.tsbuildinfo +1 -1
  39. package/dist/web/standalone/.next/BUILD_ID +1 -1
  40. package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
  41. package/dist/web/standalone/.next/build-manifest.json +3 -3
  42. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  43. package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
  44. package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
  45. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  49. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  53. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  56. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  57. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  58. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  59. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  60. package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
  61. package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
  62. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
  63. package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
  64. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
  65. package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
  66. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +1 -1
  67. package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
  68. package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
  69. package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
  70. package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
  71. package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
  72. package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
  73. package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
  74. package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
  75. package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
  76. package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
  77. package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
  78. package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
  79. package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
  80. package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
  81. package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
  82. package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
  83. package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
  84. package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
  85. package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
  86. package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
  87. package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
  88. package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
  89. package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
  90. package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
  91. package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
  92. package/dist/web/standalone/.next/server/app/api/notifications/route.js +1 -1
  93. package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
  94. package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
  95. package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
  96. package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
  97. package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
  98. package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
  99. package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
  100. package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
  101. package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
  102. package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
  103. package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
  104. package/dist/web/standalone/.next/server/app/api/session/events/route.js +1 -1
  105. package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
  106. package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
  107. package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
  108. package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
  109. package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
  110. package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
  111. package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
  112. package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
  113. package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
  114. package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
  115. package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
  116. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
  117. package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
  118. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
  119. package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
  120. package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
  121. package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
  122. package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
  123. package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
  124. package/dist/web/standalone/.next/server/app/index.html +1 -1
  125. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  126. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  127. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  128. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  129. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  130. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  131. package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
  132. package/dist/web/standalone/.next/server/chunks/1926.js +1 -0
  133. package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
  134. package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
  135. package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
  136. package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
  137. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  138. package/dist/web/standalone/.next/server/pages/500.html +1 -1
  139. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  140. package/dist/web/standalone/.next/static/chunks/2826.e9f5195e91f9cad2.js +11 -0
  141. package/dist/web/standalone/.next/static/chunks/{webpack-1832629448831fdc.js → webpack-2e68521d7c82f7c2.js} +1 -1
  142. package/package.json +3 -3
  143. package/packages/mcp-server/README.md +3 -3
  144. package/packages/mcp-server/dist/env-writer.d.ts +1 -0
  145. package/packages/mcp-server/dist/env-writer.d.ts.map +1 -1
  146. package/packages/mcp-server/dist/env-writer.js +74 -6
  147. package/packages/mcp-server/dist/env-writer.js.map +1 -1
  148. package/packages/mcp-server/dist/server.d.ts.map +1 -1
  149. package/packages/mcp-server/dist/server.js +25 -2
  150. package/packages/mcp-server/dist/server.js.map +1 -1
  151. package/packages/mcp-server/src/env-writer.test.ts +79 -1
  152. package/packages/mcp-server/src/env-writer.ts +76 -6
  153. package/packages/mcp-server/src/server.ts +29 -2
  154. package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
  155. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts +1 -0
  156. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
  157. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +21 -16
  158. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
  159. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts +2 -0
  160. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts.map +1 -0
  161. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js +130 -0
  162. package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js.map +1 -0
  163. package/packages/pi-coding-agent/dist/core/sdk.d.ts +1 -0
  164. package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
  165. package/packages/pi-coding-agent/dist/core/sdk.js +4 -1
  166. package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
  167. package/packages/pi-coding-agent/dist/core/sdk.test.js +19 -1
  168. package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -1
  169. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +15 -6
  170. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -1
  171. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
  172. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -5
  173. package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
  174. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +7 -1
  175. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  176. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +31 -9
  177. package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
  178. package/packages/pi-coding-agent/src/core/compaction-orchestrator.test.ts +154 -0
  179. package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +24 -17
  180. package/packages/pi-coding-agent/src/core/sdk.test.ts +25 -1
  181. package/packages/pi-coding-agent/src/core/sdk.ts +10 -3
  182. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +17 -7
  183. package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +14 -5
  184. package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +45 -11
  185. package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
  186. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +19 -0
  187. package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
  188. package/packages/pi-tui/dist/stdin-buffer.d.ts +7 -0
  189. package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
  190. package/packages/pi-tui/dist/stdin-buffer.js +20 -0
  191. package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
  192. package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +25 -0
  193. package/packages/pi-tui/src/stdin-buffer.ts +26 -0
  194. package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
  195. package/src/resources/extensions/claude-code-cli/stream-adapter.ts +14 -10
  196. package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +22 -16
  197. package/src/resources/extensions/gsd/abandon-detect.ts +62 -0
  198. package/src/resources/extensions/gsd/auto/resolve.ts +29 -0
  199. package/src/resources/extensions/gsd/auto/run-unit.ts +16 -2
  200. package/src/resources/extensions/gsd/auto/turn-epoch.ts +108 -0
  201. package/src/resources/extensions/gsd/auto-dispatch.ts +20 -0
  202. package/src/resources/extensions/gsd/auto-loop.ts +1 -1
  203. package/src/resources/extensions/gsd/auto-post-unit.ts +30 -0
  204. package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -5
  205. package/src/resources/extensions/gsd/auto-unit-closeout.ts +14 -3
  206. package/src/resources/extensions/gsd/auto-worktree.ts +60 -5
  207. package/src/resources/extensions/gsd/auto.ts +5 -0
  208. package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -2
  209. package/src/resources/extensions/gsd/commands/handlers/workflow.ts +27 -8
  210. package/src/resources/extensions/gsd/file-lock.ts +84 -11
  211. package/src/resources/extensions/gsd/git-service.ts +1 -0
  212. package/src/resources/extensions/gsd/gitignore.ts +1 -0
  213. package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -1
  214. package/src/resources/extensions/gsd/journal.ts +27 -2
  215. package/src/resources/extensions/gsd/milestone-actions.ts +18 -0
  216. package/src/resources/extensions/gsd/reports.ts +5 -4
  217. package/src/resources/extensions/gsd/tests/auto-loop.test.ts +11 -2
  218. package/src/resources/extensions/gsd/tests/auto-mode-guards.test.ts +79 -0
  219. package/src/resources/extensions/gsd/tests/file-lock.test.ts +86 -12
  220. package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +30 -0
  221. package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
  222. package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +76 -0
  223. package/src/resources/extensions/gsd/tests/provider-errors.test.ts +39 -25
  224. package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +181 -0
  225. package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +13 -7
  226. package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +170 -0
  227. package/src/resources/extensions/gsd/tests/rewrite-docs-abandon-detect.test.ts +195 -0
  228. package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +2 -2
  229. package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +50 -2
  230. package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +162 -0
  231. package/src/resources/extensions/gsd/tools/complete-slice.ts +38 -0
  232. package/src/resources/extensions/gsd/tools/complete-task.ts +49 -0
  233. package/src/resources/extensions/gsd/uok/audit.ts +20 -2
  234. package/src/resources/extensions/gsd/workflow-logger.ts +22 -3
  235. package/src/resources/extensions/gsd/worktree-manager.ts +1 -0
  236. package/src/resources/extensions/mcp-client/auth.ts +12 -1
  237. package/src/resources/extensions/mcp-client/index.ts +129 -10
  238. package/src/resources/skills/create-skill/SKILL.md +2 -2
  239. package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
  240. package/src/resources/skills/create-skill/workflows/audit-skill.md +4 -4
  241. package/src/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
  242. package/dist/web/standalone/.next/server/chunks/7461.js +0 -1
  243. package/dist/web/standalone/.next/static/chunks/2826.d445fb428ef41fa1.js +0 -9
  244. /package/dist/web/standalone/.next/static/{H51SzzS_EEgdBsDVhrLBv → 5wbu35_C2_MQ3Jj1lEVDx}/_buildManifest.js +0 -0
  245. /package/dist/web/standalone/.next/static/{H51SzzS_EEgdBsDVhrLBv → 5wbu35_C2_MQ3Jj1lEVDx}/_ssgManifest.js +0 -0
@@ -479,6 +479,7 @@ const SKIP_PATHS = [
479
479
  ".gsd/worktrees/",
480
480
  ".gsd/runtime/",
481
481
  ".gsd/activity/",
482
+ ".gsd/audit/",
482
483
  ".gsd/forensics/",
483
484
  ".gsd/parallel/",
484
485
  ".gsd/journal/",
@@ -10,7 +10,16 @@
10
10
  // ─── Env resolution ───────────────────────────────────────────────────────────
11
11
  /** Resolve `${VAR}` references in a string against `process.env`. */
12
12
  function resolveEnvValue(value) {
13
- return value.replace(/\$\{([^}]+)\}/g, (_match, varName) => process.env[varName] ?? "");
13
+ return value.replace(/\$\{([^}]+)\}/g, (_match, varName) => {
14
+ const resolved = process.env[varName];
15
+ if (resolved === undefined || resolved === "") {
16
+ // eslint-disable-next-line no-console
17
+ console.warn(`[mcp-client auth] Environment variable "${varName}" referenced in MCP server config is unset. ` +
18
+ `Requests will go out with a malformed header and the remote server will likely reject them with 401.`);
19
+ return "";
20
+ }
21
+ return resolved;
22
+ });
14
23
  }
15
24
  function resolveHeaders(raw) {
16
25
  const resolved = {};
@@ -21,8 +21,38 @@ import { join } from "node:path";
21
21
  import { buildHttpTransportOpts } from "./auth.js";
22
22
  // ─── Connection Manager ───────────────────────────────────────────────────────
23
23
  const connections = new Map();
24
+ const pendingConnections = new Map();
24
25
  let configCache = null;
25
26
  const toolCache = new Map();
27
+ const trustedStdioServers = new Set();
28
+ const CHILD_ENV_ALLOWLIST = new Set([
29
+ "PATH",
30
+ "Path",
31
+ "HOME",
32
+ "USER",
33
+ "USERNAME",
34
+ "USERPROFILE",
35
+ "SHELL",
36
+ "TMPDIR",
37
+ "TEMP",
38
+ "TMP",
39
+ "SystemRoot",
40
+ "WINDIR",
41
+ "APPDATA",
42
+ "LOCALAPPDATA",
43
+ "XDG_CONFIG_HOME",
44
+ "XDG_CACHE_HOME",
45
+ ]);
46
+ function stdioTrustKey(config) {
47
+ return JSON.stringify({
48
+ name: config.name,
49
+ sourcePath: config.sourcePath,
50
+ command: config.command,
51
+ args: config.args ?? [],
52
+ cwd: config.cwd,
53
+ env: config.env ?? {},
54
+ });
55
+ }
26
56
  function readConfigs() {
27
57
  if (configCache)
28
58
  return configCache;
@@ -57,6 +87,7 @@ function readConfigs() {
57
87
  servers.push({
58
88
  name,
59
89
  transport,
90
+ sourcePath: configPath,
60
91
  ...(hasCommand && {
61
92
  command: config.command,
62
93
  args: Array.isArray(config.args) ? config.args : undefined,
@@ -78,6 +109,42 @@ function readConfigs() {
78
109
  configCache = servers;
79
110
  return servers;
80
111
  }
112
+ export function _buildMcpChildEnvForTest(configEnv) {
113
+ const childEnv = {};
114
+ for (const key of CHILD_ENV_ALLOWLIST) {
115
+ const value = process.env[key];
116
+ if (typeof value === "string")
117
+ childEnv[key] = value;
118
+ }
119
+ return {
120
+ ...childEnv,
121
+ ...(configEnv ? resolveEnv(configEnv) : {}),
122
+ };
123
+ }
124
+ export function _buildMcpTrustConfirmOptionsForTest(signal) {
125
+ return signal ? { timeout: 120_000, signal } : { timeout: 120_000 };
126
+ }
127
+ async function assertTrustedStdioServer(config, ctx, signal) {
128
+ if (config.transport !== "stdio")
129
+ return undefined;
130
+ const trustKey = stdioTrustKey(config);
131
+ if (trustedStdioServers.has(trustKey))
132
+ return undefined;
133
+ if (!ctx?.hasUI) {
134
+ throw new Error(`MCP server "${config.name}" is a project-local stdio command from ${config.sourcePath}. ` +
135
+ "Run this from an interactive GSD session and approve the server before use.");
136
+ }
137
+ const commandLine = [config.command, ...(config.args ?? [])].filter(Boolean).join(" ");
138
+ const envKeys = Object.keys(config.env ?? {});
139
+ const envSummary = envKeys.length > 0
140
+ ? `\n\nConfigured environment keys: ${envKeys.join(", ")}`
141
+ : "\n\nNo explicit environment keys configured.";
142
+ const approved = await ctx.ui.confirm(`Trust MCP server "${config.name}"?`, `Project config ${config.sourcePath} wants to start:\n\n${commandLine}${envSummary}\n\nOnly approve MCP servers you trust.`, _buildMcpTrustConfirmOptionsForTest(signal));
143
+ if (!approved) {
144
+ throw new Error(`MCP server "${config.name}" was not approved by the user.`);
145
+ }
146
+ return trustKey;
147
+ }
81
148
  function getServerConfig(name) {
82
149
  const trimmed = name.trim();
83
150
  return readConfigs().find((s) => s.name === trimmed ||
@@ -96,7 +163,7 @@ function resolveEnv(env) {
96
163
  }
97
164
  return resolved;
98
165
  }
99
- async function getOrConnect(name, signal) {
166
+ async function getOrConnect(name, signal, ctx) {
100
167
  const config = getServerConfig(name);
101
168
  if (!config)
102
169
  throw new Error(`Unknown MCP server: "${name}". Use mcp_servers to list available servers.`);
@@ -105,13 +172,28 @@ async function getOrConnect(name, signal) {
105
172
  const existing = connections.get(config.name);
106
173
  if (existing)
107
174
  return existing.client;
175
+ const pending = pendingConnections.get(config.name);
176
+ if (pending)
177
+ return pending;
178
+ const connectionPromise = connectServer(config, signal, ctx);
179
+ pendingConnections.set(config.name, connectionPromise);
180
+ try {
181
+ return await connectionPromise;
182
+ }
183
+ finally {
184
+ pendingConnections.delete(config.name);
185
+ }
186
+ }
187
+ async function connectServer(config, signal, ctx) {
108
188
  const client = new Client({ name: "gsd", version: "1.0.0" });
109
189
  let transport;
190
+ let approvedTrustKey;
110
191
  if (config.transport === "stdio" && config.command) {
192
+ approvedTrustKey = await assertTrustedStdioServer(config, ctx, signal);
111
193
  transport = new StdioClientTransport({
112
194
  command: config.command,
113
195
  args: config.args,
114
- env: config.env ? { ...process.env, ...resolveEnv(config.env) } : undefined,
196
+ env: _buildMcpChildEnvForTest(config.env),
115
197
  cwd: config.cwd,
116
198
  stderr: "pipe",
117
199
  });
@@ -127,9 +209,28 @@ async function getOrConnect(name, signal) {
127
209
  else {
128
210
  throw new Error(`Server "${config.name}" has unsupported transport: ${config.transport}`);
129
211
  }
130
- await client.connect(transport, { signal, timeout: 30000 });
131
- connections.set(config.name, { client, transport });
132
- return client;
212
+ try {
213
+ await client.connect(transport, { signal, timeout: 30000 });
214
+ if (approvedTrustKey)
215
+ trustedStdioServers.add(approvedTrustKey);
216
+ connections.set(config.name, { client, transport });
217
+ return client;
218
+ }
219
+ catch (err) {
220
+ try {
221
+ await transport.close();
222
+ }
223
+ catch {
224
+ // Best-effort cleanup after a failed or aborted connection attempt.
225
+ }
226
+ try {
227
+ await client.close();
228
+ }
229
+ catch {
230
+ // Best-effort cleanup after a failed or aborted connection attempt.
231
+ }
232
+ throw err;
233
+ }
133
234
  }
134
235
  async function closeAll() {
135
236
  const closing = Array.from(connections.entries()).map(async ([name, conn]) => {
@@ -139,9 +240,17 @@ async function closeAll() {
139
240
  catch {
140
241
  // Best-effort cleanup
141
242
  }
243
+ try {
244
+ await conn.transport.close();
245
+ }
246
+ catch {
247
+ // Best-effort cleanup
248
+ }
142
249
  connections.delete(name);
143
250
  });
144
251
  await Promise.allSettled(closing);
252
+ pendingConnections.clear();
253
+ trustedStdioServers.clear();
145
254
  toolCache.clear();
146
255
  }
147
256
  // ─── Formatters ───────────────────────────────────────────────────────────────
@@ -249,7 +358,7 @@ export default function (pi) {
249
358
  description: "MCP server name (from mcp_servers output), e.g. 'railway', 'twitter-mcp', 'linear'",
250
359
  }),
251
360
  }),
252
- async execute(_id, params, signal) {
361
+ async execute(_id, params, signal, _onUpdate, ctx) {
253
362
  try {
254
363
  // Return cached tools if available
255
364
  const cached = toolCache.get(params.server);
@@ -265,7 +374,7 @@ export default function (pi) {
265
374
  details: { server: params.server, toolCount: cached.length, cached: true },
266
375
  };
267
376
  }
268
- const client = await getOrConnect(params.server, signal);
377
+ const client = await getOrConnect(params.server, signal, ctx);
269
378
  const result = await client.listTools(undefined, { signal, timeout: 30000 });
270
379
  const tools = (result.tools ?? []).map((t) => ({
271
380
  name: t.name,
@@ -326,9 +435,9 @@ export default function (pi) {
326
435
  description: "Tool arguments as key-value pairs matching the tool's input schema",
327
436
  })),
328
437
  }),
329
- async execute(_id, params, signal) {
438
+ async execute(_id, params, signal, _onUpdate, ctx) {
330
439
  try {
331
- const client = await getOrConnect(params.server, signal);
440
+ const client = await getOrConnect(params.server, signal, ctx);
332
441
  const result = await client.callTool({ name: params.tool, arguments: params.args ?? {} }, undefined, { signal, timeout: 60000 });
333
442
  // Serialize result content to text
334
443
  const contentItems = result.content;
@@ -88,8 +88,8 @@ Then proceed directly to the workflow.
88
88
  ## Skill Structure Quick Reference
89
89
 
90
90
  **Skill directories:**
91
- - Global: `~/.gsd/agent/skills/{skill-name}/`
92
- - Project-local: `.pi/agent/skills/{skill-name}/`
91
+ - Global: `~/.agents/skills/{skill-name}/`
92
+ - Project-local: `.agents/skills/{skill-name}/`
93
93
 
94
94
  **Simple skill (single file):**
95
95
  ```yaml
@@ -5,13 +5,13 @@ GSD-specific skill ecosystem details: directory conventions, discovery mechanics
5
5
  <skill_directories>
6
6
  GSD supports two skill directories, checked in order:
7
7
 
8
- **User-scope (global):** `~/.gsd/agent/skills/`
8
+ **User-scope (global):** `~/.agents/skills/`
9
9
  - Available in every GSD session regardless of working directory
10
- - Installed by default or by the user
10
+ - Installed via [skills.sh](https://skills.sh) or manually
11
11
 
12
- **Project-scope (local):** `.pi/agent/skills/`
12
+ **Project-scope (local):** `.agents/skills/`
13
13
  - Available only when GSD runs inside the project directory
14
- - The project-local directory uses `.pi` (inherited from the pi base), **not** `.gsd`
14
+ - Committable to version control so team members share the same skill set
15
15
  - Ideal for project-specific workflows, deploy scripts, or conventions
16
16
 
17
17
  Skills in both directories follow the same SKILL.md format and router pattern conventions.
@@ -16,22 +16,22 @@
16
16
  Enumerate skills from both directories:
17
17
  ```bash
18
18
  echo "=== Global skills ==="
19
- ls ~/.gsd/agent/skills/ 2>/dev/null || echo "(none)"
19
+ ls ~/.agents/skills/ 2>/dev/null || echo "(none)"
20
20
 
21
21
  echo "=== Project-local skills ==="
22
- ls .pi/agent/skills/ 2>/dev/null || echo "(none)"
22
+ ls .agents/skills/ 2>/dev/null || echo "(none)"
23
23
  ```
24
24
 
25
25
  Present as:
26
26
  ```
27
27
  Available skills:
28
28
 
29
- Global (~/.gsd/agent/skills/):
29
+ Global (~/.agents/skills/):
30
30
  1. create-skill
31
31
  2. manage-stripe
32
32
  ...
33
33
 
34
- Project-local (.pi/agent/skills/):
34
+ Project-local (.agents/skills/):
35
35
  3. project-deploy
36
36
  ...
37
37
  ```
@@ -15,8 +15,8 @@
15
15
  **Ask the user:**
16
16
  "Should this skill be global or project-local?"
17
17
 
18
- 1. **Global** (`~/.gsd/agent/skills/`) — Available in all GSD sessions
19
- 2. **Project-local** (`.pi/agent/skills/`) — Available only in this project
18
+ 1. **Global** (`~/.agents/skills/`) — Available in all GSD sessions
19
+ 2. **Project-local** (`.agents/skills/`) — Available only in this project
20
20
 
21
21
  ## Step 2: Adaptive Requirements Gathering
22
22
 
@@ -99,11 +99,11 @@ See references/recommended-structure.md for templates.
99
99
  ## Step 5: Create Directory
100
100
 
101
101
  Use the scope selected in Step 1 to determine the base path:
102
- - **Global:** `~/.gsd/agent/skills/{skill-name}`
103
- - **Project-local:** `.pi/agent/skills/{skill-name}`
102
+ - **Global:** `~/.agents/skills/{skill-name}`
103
+ - **Project-local:** `.agents/skills/{skill-name}`
104
104
 
105
105
  ```bash
106
- BASE_PATH="{selected-base}/agent/skills/{skill-name}"
106
+ BASE_PATH="{selected-base}/skills/{skill-name}"
107
107
  mkdir -p $BASE_PATH
108
108
  # If complex:
109
109
  mkdir -p $BASE_PATH/workflows