gsd-pi 2.44.0-dev.73f2fd5 → 2.44.0-dev.8894d5b

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 (164) hide show
  1. package/dist/resources/extensions/gsd/auto/infra-errors.js +0 -3
  2. package/dist/resources/extensions/gsd/auto/phases.js +36 -36
  3. package/dist/resources/extensions/gsd/auto-prompts.js +1 -24
  4. package/dist/resources/extensions/gsd/auto-timers.js +3 -57
  5. package/dist/resources/extensions/gsd/auto-worktree-sync.js +0 -4
  6. package/dist/resources/extensions/gsd/auto-worktree.js +6 -9
  7. package/dist/resources/extensions/gsd/auto.js +3 -30
  8. package/dist/resources/extensions/gsd/bootstrap/db-tools.js +0 -136
  9. package/dist/resources/extensions/gsd/commands/catalog.js +1 -6
  10. package/dist/resources/extensions/gsd/commands/handlers/core.js +0 -1
  11. package/dist/resources/extensions/gsd/commands/handlers/ops.js +0 -5
  12. package/dist/resources/extensions/gsd/db-writer.js +16 -34
  13. package/dist/resources/extensions/gsd/doctor.js +0 -8
  14. package/dist/resources/extensions/gsd/git-service.js +3 -8
  15. package/dist/resources/extensions/gsd/gsd-db.js +1 -12
  16. package/dist/resources/extensions/gsd/markdown-renderer.js +1 -1
  17. package/dist/resources/extensions/gsd/prompts/complete-milestone.md +4 -2
  18. package/dist/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  19. package/dist/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  20. package/dist/resources/extensions/gsd/prompts/replan-slice.md +14 -3
  21. package/dist/resources/extensions/gsd/prompts/validate-milestone.md +37 -7
  22. package/dist/resources/extensions/gsd/provider-error-pause.js +0 -7
  23. package/dist/resources/extensions/gsd/tools/plan-slice.js +0 -1
  24. package/dist/resources/extensions/gsd/tools/plan-task.js +0 -1
  25. package/dist/resources/extensions/gsd/tools/replan-slice.js +0 -2
  26. package/dist/resources/extensions/gsd/worktree-resolver.js +0 -6
  27. package/dist/resources/extensions/mcp-client/index.js +0 -14
  28. package/dist/web/standalone/.next/BUILD_ID +1 -1
  29. package/dist/web/standalone/.next/app-path-routes-manifest.json +20 -20
  30. package/dist/web/standalone/.next/build-manifest.json +2 -2
  31. package/dist/web/standalone/.next/prerender-manifest.json +3 -3
  32. package/dist/web/standalone/.next/server/app/_global-error.html +2 -2
  33. package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
  34. package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  35. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  36. package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  37. package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  38. package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  39. package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  40. package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
  41. package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
  42. package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  43. package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  44. package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  45. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  46. package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  47. package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  48. package/dist/web/standalone/.next/server/app/index.html +1 -1
  49. package/dist/web/standalone/.next/server/app/index.rsc +1 -1
  50. package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  51. package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
  52. package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  53. package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
  54. package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  55. package/dist/web/standalone/.next/server/app-paths-manifest.json +20 -20
  56. package/dist/web/standalone/.next/server/pages/404.html +1 -1
  57. package/dist/web/standalone/.next/server/pages/500.html +2 -2
  58. package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
  59. package/package.json +1 -1
  60. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts +1 -3
  61. package/packages/pi-coding-agent/dist/core/auth-storage.d.ts.map +1 -1
  62. package/packages/pi-coding-agent/dist/core/auth-storage.js +1 -15
  63. package/packages/pi-coding-agent/dist/core/auth-storage.js.map +1 -1
  64. package/packages/pi-coding-agent/dist/core/model-registry.d.ts +0 -11
  65. package/packages/pi-coding-agent/dist/core/model-registry.d.ts.map +1 -1
  66. package/packages/pi-coding-agent/dist/core/model-registry.js +1 -20
  67. package/packages/pi-coding-agent/dist/core/model-registry.js.map +1 -1
  68. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts +0 -3
  69. package/packages/pi-coding-agent/dist/core/settings-manager.d.ts.map +1 -1
  70. package/packages/pi-coding-agent/dist/core/settings-manager.js +0 -6
  71. package/packages/pi-coding-agent/dist/core/settings-manager.js.map +1 -1
  72. package/packages/pi-coding-agent/dist/main.d.ts.map +1 -1
  73. package/packages/pi-coding-agent/dist/main.js +0 -17
  74. package/packages/pi-coding-agent/dist/main.js.map +1 -1
  75. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts +1 -3
  76. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  77. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js +1 -8
  78. package/packages/pi-coding-agent/dist/modes/interactive/components/assistant-message.js.map +1 -1
  79. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts +0 -2
  80. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  81. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js +0 -12
  82. package/packages/pi-coding-agent/dist/modes/interactive/components/settings-selector.js.map +1 -1
  83. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  84. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js +1 -4
  85. package/packages/pi-coding-agent/dist/modes/interactive/components/tool-execution.js.map +1 -1
  86. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts +2 -5
  87. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  88. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js +2 -13
  89. package/packages/pi-coding-agent/dist/modes/interactive/components/user-message.js.map +1 -1
  90. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
  91. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js +8 -17
  92. package/packages/pi-coding-agent/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
  93. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  94. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js +3 -7
  95. package/packages/pi-coding-agent/dist/modes/interactive/interactive-mode.js.map +1 -1
  96. package/packages/pi-coding-agent/src/core/auth-storage.ts +1 -15
  97. package/packages/pi-coding-agent/src/core/model-registry.ts +1 -21
  98. package/packages/pi-coding-agent/src/core/settings-manager.ts +0 -9
  99. package/packages/pi-coding-agent/src/main.ts +0 -19
  100. package/packages/pi-coding-agent/src/modes/interactive/components/assistant-message.ts +0 -10
  101. package/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +0 -15
  102. package/packages/pi-coding-agent/src/modes/interactive/components/tool-execution.ts +1 -3
  103. package/packages/pi-coding-agent/src/modes/interactive/components/user-message.ts +3 -18
  104. package/packages/pi-coding-agent/src/modes/interactive/controllers/chat-controller.ts +7 -16
  105. package/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +1 -8
  106. package/src/resources/extensions/gsd/auto/infra-errors.ts +0 -3
  107. package/src/resources/extensions/gsd/auto/phases.ts +48 -45
  108. package/src/resources/extensions/gsd/auto-prompts.ts +1 -24
  109. package/src/resources/extensions/gsd/auto-timers.ts +3 -64
  110. package/src/resources/extensions/gsd/auto-worktree-sync.ts +0 -5
  111. package/src/resources/extensions/gsd/auto-worktree.ts +6 -9
  112. package/src/resources/extensions/gsd/auto.ts +3 -37
  113. package/src/resources/extensions/gsd/bootstrap/db-tools.ts +0 -129
  114. package/src/resources/extensions/gsd/commands/catalog.ts +1 -6
  115. package/src/resources/extensions/gsd/commands/handlers/core.ts +0 -1
  116. package/src/resources/extensions/gsd/commands/handlers/ops.ts +0 -5
  117. package/src/resources/extensions/gsd/db-writer.ts +17 -39
  118. package/src/resources/extensions/gsd/doctor.ts +1 -7
  119. package/src/resources/extensions/gsd/git-service.ts +2 -6
  120. package/src/resources/extensions/gsd/gsd-db.ts +1 -16
  121. package/src/resources/extensions/gsd/markdown-renderer.ts +1 -1
  122. package/src/resources/extensions/gsd/prompts/complete-milestone.md +4 -2
  123. package/src/resources/extensions/gsd/prompts/plan-slice.md +1 -1
  124. package/src/resources/extensions/gsd/prompts/reassess-roadmap.md +6 -6
  125. package/src/resources/extensions/gsd/prompts/replan-slice.md +14 -3
  126. package/src/resources/extensions/gsd/prompts/validate-milestone.md +37 -7
  127. package/src/resources/extensions/gsd/provider-error-pause.ts +0 -9
  128. package/src/resources/extensions/gsd/tests/db-writer.test.ts +0 -79
  129. package/src/resources/extensions/gsd/tests/infra-error.test.ts +2 -20
  130. package/src/resources/extensions/gsd/tests/prompt-contracts.test.ts +7 -11
  131. package/src/resources/extensions/gsd/tests/tool-naming.test.ts +1 -2
  132. package/src/resources/extensions/gsd/tools/plan-slice.ts +0 -2
  133. package/src/resources/extensions/gsd/tools/plan-task.ts +0 -2
  134. package/src/resources/extensions/gsd/tools/replan-slice.ts +0 -3
  135. package/src/resources/extensions/gsd/worktree-resolver.ts +0 -7
  136. package/src/resources/extensions/mcp-client/index.ts +0 -20
  137. package/dist/resources/extensions/gsd/commands-mcp-status.js +0 -187
  138. package/dist/resources/extensions/gsd/tools/validate-milestone.js +0 -88
  139. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts +0 -15
  140. package/packages/pi-coding-agent/dist/core/local-model-check.d.ts.map +0 -1
  141. package/packages/pi-coding-agent/dist/core/local-model-check.js +0 -41
  142. package/packages/pi-coding-agent/dist/core/local-model-check.js.map +0 -1
  143. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts +0 -2
  144. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.d.ts.map +0 -1
  145. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js +0 -32
  146. package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/timestamp.test.js.map +0 -1
  147. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts +0 -15
  148. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.d.ts.map +0 -1
  149. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js +0 -40
  150. package/packages/pi-coding-agent/dist/modes/interactive/components/timestamp.js.map +0 -1
  151. package/packages/pi-coding-agent/src/core/local-model-check.ts +0 -45
  152. package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/timestamp.test.ts +0 -38
  153. package/packages/pi-coding-agent/src/modes/interactive/components/timestamp.ts +0 -48
  154. package/src/resources/extensions/gsd/commands-mcp-status.ts +0 -247
  155. package/src/resources/extensions/gsd/tests/auto-pr-bugs.test.ts +0 -88
  156. package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +0 -114
  157. package/src/resources/extensions/gsd/tests/est-annotation-timeout.test.ts +0 -120
  158. package/src/resources/extensions/gsd/tests/mcp-status.test.ts +0 -103
  159. package/src/resources/extensions/gsd/tests/merge-conflict-stops-loop.test.ts +0 -66
  160. package/src/resources/extensions/gsd/tests/stop-auto-merge-back.test.ts +0 -67
  161. package/src/resources/extensions/gsd/tests/terminated-transient.test.ts +0 -49
  162. package/src/resources/extensions/gsd/tools/validate-milestone.ts +0 -127
  163. /package/dist/web/standalone/.next/static/{kxxAA66bah_yhPYqLBHE2 → oZMtyM-zfu6Inx-S59cOl}/_buildManifest.js +0 -0
  164. /package/dist/web/standalone/.next/static/{kxxAA66bah_yhPYqLBHE2 → oZMtyM-zfu6Inx-S59cOl}/_ssgManifest.js +0 -0
@@ -1,41 +0,0 @@
1
- /**
2
- * local-model-check.ts — Utility to detect if a model baseUrl is local.
3
- *
4
- * Leaf module with zero transitive dependencies on TypeScript parameter properties.
5
- * Used by ModelRegistry and tests.
6
- */
7
- /**
8
- * Check if a model's baseUrl points to a local endpoint.
9
- * Returns true for localhost, 127.0.0.1, 0.0.0.0, ::1, or unix socket paths.
10
- * Returns false if baseUrl is empty (cloud provider) or points to a remote host.
11
- */
12
- export function isLocalModel(model) {
13
- const url = model.baseUrl;
14
- if (!url)
15
- return false;
16
- // Unix socket paths
17
- if (url.startsWith("unix://") || url.startsWith("unix:"))
18
- return true;
19
- try {
20
- const parsed = new URL(url);
21
- const hostname = parsed.hostname;
22
- if (hostname === "localhost" ||
23
- hostname === "127.0.0.1" ||
24
- hostname === "0.0.0.0" ||
25
- hostname === "::1" ||
26
- hostname === "[::1]") {
27
- return true;
28
- }
29
- }
30
- catch {
31
- // If URL parsing fails, check raw string for local patterns
32
- if (url.includes("localhost") ||
33
- url.includes("127.0.0.1") ||
34
- url.includes("0.0.0.0") ||
35
- url.includes("[::1]")) {
36
- return true;
37
- }
38
- }
39
- return false;
40
- }
41
- //# sourceMappingURL=local-model-check.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"local-model-check.js","sourceRoot":"","sources":["../../src/core/local-model-check.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,KAA0B;IACtD,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC;IAC1B,IAAI,CAAC,GAAG;QAAE,OAAO,KAAK,CAAC;IAEvB,oBAAoB;IACpB,IAAI,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,IAAI,CAAC;IAEtE,IAAI,CAAC;QACJ,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;QAC5B,MAAM,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;QACjC,IACC,QAAQ,KAAK,WAAW;YACxB,QAAQ,KAAK,WAAW;YACxB,QAAQ,KAAK,SAAS;YACtB,QAAQ,KAAK,KAAK;YAClB,QAAQ,KAAK,OAAO,EACnB,CAAC;YACF,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAAC,MAAM,CAAC;QACR,4DAA4D;QAC5D,IACC,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC;YACzB,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC;YACzB,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC;YACvB,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,EACpB,CAAC;YACF,OAAO,IAAI,CAAC;QACb,CAAC;IACF,CAAC;IAED,OAAO,KAAK,CAAC;AACd,CAAC","sourcesContent":["/**\n * local-model-check.ts — Utility to detect if a model baseUrl is local.\n *\n * Leaf module with zero transitive dependencies on TypeScript parameter properties.\n * Used by ModelRegistry and tests.\n */\n\n/**\n * Check if a model's baseUrl points to a local endpoint.\n * Returns true for localhost, 127.0.0.1, 0.0.0.0, ::1, or unix socket paths.\n * Returns false if baseUrl is empty (cloud provider) or points to a remote host.\n */\nexport function isLocalModel(model: { baseUrl: string }): boolean {\n\tconst url = model.baseUrl;\n\tif (!url) return false;\n\n\t// Unix socket paths\n\tif (url.startsWith(\"unix://\") || url.startsWith(\"unix:\")) return true;\n\n\ttry {\n\t\tconst parsed = new URL(url);\n\t\tconst hostname = parsed.hostname;\n\t\tif (\n\t\t\thostname === \"localhost\" ||\n\t\t\thostname === \"127.0.0.1\" ||\n\t\t\thostname === \"0.0.0.0\" ||\n\t\t\thostname === \"::1\" ||\n\t\t\thostname === \"[::1]\"\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t} catch {\n\t\t// If URL parsing fails, check raw string for local patterns\n\t\tif (\n\t\t\turl.includes(\"localhost\") ||\n\t\t\turl.includes(\"127.0.0.1\") ||\n\t\t\turl.includes(\"0.0.0.0\") ||\n\t\t\turl.includes(\"[::1]\")\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n"]}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=timestamp.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"timestamp.test.d.ts","sourceRoot":"","sources":["../../../../../src/modes/interactive/components/__tests__/timestamp.test.ts"],"names":[],"mappings":""}
@@ -1,32 +0,0 @@
1
- import { test, describe } from "node:test";
2
- import assert from "node:assert/strict";
3
- import { formatTimestamp } from "../timestamp.js";
4
- describe("formatTimestamp", () => {
5
- // Use a fixed local timestamp to avoid timezone issues
6
- const d = new Date(2026, 2, 24, 10, 34, 0); // Mar 24, 2026 10:34:00 local time
7
- const ts = d.getTime();
8
- test("date-time-iso format (default)", () => {
9
- assert.equal(formatTimestamp(ts, "date-time-iso"), "2026-03-24 10:34");
10
- assert.equal(formatTimestamp(ts), "2026-03-24 10:34"); // default
11
- });
12
- test("date-time-us format", () => {
13
- assert.equal(formatTimestamp(ts, "date-time-us"), "03-24-2026 10:34 AM");
14
- });
15
- test("US format handles PM correctly", () => {
16
- const pm = new Date(2026, 2, 24, 14, 5, 0).getTime();
17
- assert.equal(formatTimestamp(pm, "date-time-us"), "03-24-2026 2:05 PM");
18
- });
19
- test("US format handles noon as 12 PM", () => {
20
- const noon = new Date(2026, 2, 24, 12, 0, 0).getTime();
21
- assert.equal(formatTimestamp(noon, "date-time-us"), "03-24-2026 12:00 PM");
22
- });
23
- test("US format handles midnight as 12 AM", () => {
24
- const midnight = new Date(2026, 2, 24, 0, 0, 0).getTime();
25
- assert.equal(formatTimestamp(midnight, "date-time-us"), "03-24-2026 12:00 AM");
26
- });
27
- test("ISO format pads single digit months and days", () => {
28
- const jan1 = new Date(2026, 0, 1, 9, 5, 0).getTime();
29
- assert.equal(formatTimestamp(jan1, "date-time-iso"), "2026-01-01 09:05");
30
- });
31
- });
32
- //# sourceMappingURL=timestamp.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"timestamp.test.js","sourceRoot":"","sources":["../../../../../src/modes/interactive/components/__tests__/timestamp.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAC3C,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAElD,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAChC,uDAAuD;IACvD,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,mCAAmC;IAC/E,MAAM,EAAE,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC;IAEvB,IAAI,CAAC,gCAAgC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,EAAE,eAAe,CAAC,EAAE,kBAAkB,CAAC,CAAC;QACvE,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC,EAAE,kBAAkB,CAAC,CAAC,CAAC,UAAU;IAClE,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,qBAAqB,EAAE,GAAG,EAAE;QAChC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,EAAE,cAAc,CAAC,EAAE,qBAAqB,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,gCAAgC,EAAE,GAAG,EAAE;QAC3C,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QACrD,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,EAAE,cAAc,CAAC,EAAE,oBAAoB,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,iCAAiC,EAAE,GAAG,EAAE;QAC5C,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QACvD,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,EAAE,cAAc,CAAC,EAAE,qBAAqB,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAChD,MAAM,QAAQ,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,QAAQ,EAAE,cAAc,CAAC,EAAE,qBAAqB,CAAC,CAAC;IAChF,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,8CAA8C,EAAE,GAAG,EAAE;QACzD,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QACrD,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,IAAI,EAAE,eAAe,CAAC,EAAE,kBAAkB,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC","sourcesContent":["import { test, describe } from \"node:test\";\nimport assert from \"node:assert/strict\";\nimport { formatTimestamp } from \"../timestamp.js\";\n\ndescribe(\"formatTimestamp\", () => {\n\t// Use a fixed local timestamp to avoid timezone issues\n\tconst d = new Date(2026, 2, 24, 10, 34, 0); // Mar 24, 2026 10:34:00 local time\n\tconst ts = d.getTime();\n\n\ttest(\"date-time-iso format (default)\", () => {\n\t\tassert.equal(formatTimestamp(ts, \"date-time-iso\"), \"2026-03-24 10:34\");\n\t\tassert.equal(formatTimestamp(ts), \"2026-03-24 10:34\"); // default\n\t});\n\n\ttest(\"date-time-us format\", () => {\n\t\tassert.equal(formatTimestamp(ts, \"date-time-us\"), \"03-24-2026 10:34 AM\");\n\t});\n\n\ttest(\"US format handles PM correctly\", () => {\n\t\tconst pm = new Date(2026, 2, 24, 14, 5, 0).getTime();\n\t\tassert.equal(formatTimestamp(pm, \"date-time-us\"), \"03-24-2026 2:05 PM\");\n\t});\n\n\ttest(\"US format handles noon as 12 PM\", () => {\n\t\tconst noon = new Date(2026, 2, 24, 12, 0, 0).getTime();\n\t\tassert.equal(formatTimestamp(noon, \"date-time-us\"), \"03-24-2026 12:00 PM\");\n\t});\n\n\ttest(\"US format handles midnight as 12 AM\", () => {\n\t\tconst midnight = new Date(2026, 2, 24, 0, 0, 0).getTime();\n\t\tassert.equal(formatTimestamp(midnight, \"date-time-us\"), \"03-24-2026 12:00 AM\");\n\t});\n\n\ttest(\"ISO format pads single digit months and days\", () => {\n\t\tconst jan1 = new Date(2026, 0, 1, 9, 5, 0).getTime();\n\t\tassert.equal(formatTimestamp(jan1, \"date-time-iso\"), \"2026-01-01 09:05\");\n\t});\n});\n"]}
@@ -1,15 +0,0 @@
1
- /**
2
- * Timestamp formatting for message display.
3
- *
4
- * Formats:
5
- * - "time-date-iso": 10:34 2025-03-24 (default)
6
- * - "date-time-iso": 2025-03-24 10:34
7
- * - "time-date-us": 10:34 AM 03/24/2025
8
- * - "date-time-us": 03/24/2025 10:34 AM
9
- */
10
- export type TimestampFormat = "date-time-iso" | "date-time-us";
11
- /**
12
- * Format a timestamp for message display using the specified format.
13
- */
14
- export declare function formatTimestamp(timestamp: number, format?: TimestampFormat): string;
15
- //# sourceMappingURL=timestamp.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"timestamp.d.ts","sourceRoot":"","sources":["../../../../src/modes/interactive/components/timestamp.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,eAAe,GAAG,eAAe,GAAG,cAAc,CAAC;AAyB/D;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,GAAE,eAAiC,GAAG,MAAM,CASpG"}
@@ -1,40 +0,0 @@
1
- /**
2
- * Timestamp formatting for message display.
3
- *
4
- * Formats:
5
- * - "time-date-iso": 10:34 2025-03-24 (default)
6
- * - "date-time-iso": 2025-03-24 10:34
7
- * - "time-date-us": 10:34 AM 03/24/2025
8
- * - "date-time-us": 03/24/2025 10:34 AM
9
- */
10
- function pad2(n) {
11
- return n.toString().padStart(2, "0");
12
- }
13
- function isoDate(d) {
14
- return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
15
- }
16
- function isoTime(d) {
17
- return `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
18
- }
19
- function usDate(d) {
20
- return `${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}-${d.getFullYear()}`;
21
- }
22
- function usTime(d) {
23
- const hours = d.getHours();
24
- const period = hours >= 12 ? "PM" : "AM";
25
- const h = hours % 12 || 12;
26
- return `${h}:${pad2(d.getMinutes())} ${period}`;
27
- }
28
- /**
29
- * Format a timestamp for message display using the specified format.
30
- */
31
- export function formatTimestamp(timestamp, format = "date-time-iso") {
32
- const d = new Date(timestamp);
33
- switch (format) {
34
- case "date-time-iso":
35
- return `${isoDate(d)} ${isoTime(d)}`;
36
- case "date-time-us":
37
- return `${usDate(d)} ${usTime(d)}`;
38
- }
39
- }
40
- //# sourceMappingURL=timestamp.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"timestamp.js","sourceRoot":"","sources":["../../../../src/modes/interactive/components/timestamp.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,SAAS,IAAI,CAAC,CAAS;IACtB,OAAO,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,OAAO,CAAC,CAAO;IACvB,OAAO,GAAG,CAAC,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;AAC5E,CAAC;AAED,SAAS,OAAO,CAAC,CAAO;IACvB,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,EAAE,CAAC;AACxD,CAAC;AAED,SAAS,MAAM,CAAC,CAAO;IACtB,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;AAC5E,CAAC;AAED,SAAS,MAAM,CAAC,CAAO;IACtB,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC3B,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;IACzC,MAAM,CAAC,GAAG,KAAK,GAAG,EAAE,IAAI,EAAE,CAAC;IAC3B,OAAO,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,IAAI,MAAM,EAAE,CAAC;AACjD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,SAAiB,EAAE,SAA0B,eAAe;IAC3F,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC;IAE9B,QAAQ,MAAM,EAAE,CAAC;QAChB,KAAK,eAAe;YACnB,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACtC,KAAK,cAAc;YAClB,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;IACrC,CAAC;AACF,CAAC","sourcesContent":["/**\n * Timestamp formatting for message display.\n *\n * Formats:\n * - \"time-date-iso\": 10:34 2025-03-24 (default)\n * - \"date-time-iso\": 2025-03-24 10:34\n * - \"time-date-us\": 10:34 AM 03/24/2025\n * - \"date-time-us\": 03/24/2025 10:34 AM\n */\n\nexport type TimestampFormat = \"date-time-iso\" | \"date-time-us\";\n\nfunction pad2(n: number): string {\n\treturn n.toString().padStart(2, \"0\");\n}\n\nfunction isoDate(d: Date): string {\n\treturn `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;\n}\n\nfunction isoTime(d: Date): string {\n\treturn `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;\n}\n\nfunction usDate(d: Date): string {\n\treturn `${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}-${d.getFullYear()}`;\n}\n\nfunction usTime(d: Date): string {\n\tconst hours = d.getHours();\n\tconst period = hours >= 12 ? \"PM\" : \"AM\";\n\tconst h = hours % 12 || 12;\n\treturn `${h}:${pad2(d.getMinutes())} ${period}`;\n}\n\n/**\n * Format a timestamp for message display using the specified format.\n */\nexport function formatTimestamp(timestamp: number, format: TimestampFormat = \"date-time-iso\"): string {\n\tconst d = new Date(timestamp);\n\n\tswitch (format) {\n\t\tcase \"date-time-iso\":\n\t\t\treturn `${isoDate(d)} ${isoTime(d)}`;\n\t\tcase \"date-time-us\":\n\t\t\treturn `${usDate(d)} ${usTime(d)}`;\n\t}\n}\n"]}
@@ -1,45 +0,0 @@
1
- /**
2
- * local-model-check.ts — Utility to detect if a model baseUrl is local.
3
- *
4
- * Leaf module with zero transitive dependencies on TypeScript parameter properties.
5
- * Used by ModelRegistry and tests.
6
- */
7
-
8
- /**
9
- * Check if a model's baseUrl points to a local endpoint.
10
- * Returns true for localhost, 127.0.0.1, 0.0.0.0, ::1, or unix socket paths.
11
- * Returns false if baseUrl is empty (cloud provider) or points to a remote host.
12
- */
13
- export function isLocalModel(model: { baseUrl: string }): boolean {
14
- const url = model.baseUrl;
15
- if (!url) return false;
16
-
17
- // Unix socket paths
18
- if (url.startsWith("unix://") || url.startsWith("unix:")) return true;
19
-
20
- try {
21
- const parsed = new URL(url);
22
- const hostname = parsed.hostname;
23
- if (
24
- hostname === "localhost" ||
25
- hostname === "127.0.0.1" ||
26
- hostname === "0.0.0.0" ||
27
- hostname === "::1" ||
28
- hostname === "[::1]"
29
- ) {
30
- return true;
31
- }
32
- } catch {
33
- // If URL parsing fails, check raw string for local patterns
34
- if (
35
- url.includes("localhost") ||
36
- url.includes("127.0.0.1") ||
37
- url.includes("0.0.0.0") ||
38
- url.includes("[::1]")
39
- ) {
40
- return true;
41
- }
42
- }
43
-
44
- return false;
45
- }
@@ -1,38 +0,0 @@
1
- import { test, describe } from "node:test";
2
- import assert from "node:assert/strict";
3
- import { formatTimestamp } from "../timestamp.js";
4
-
5
- describe("formatTimestamp", () => {
6
- // Use a fixed local timestamp to avoid timezone issues
7
- const d = new Date(2026, 2, 24, 10, 34, 0); // Mar 24, 2026 10:34:00 local time
8
- const ts = d.getTime();
9
-
10
- test("date-time-iso format (default)", () => {
11
- assert.equal(formatTimestamp(ts, "date-time-iso"), "2026-03-24 10:34");
12
- assert.equal(formatTimestamp(ts), "2026-03-24 10:34"); // default
13
- });
14
-
15
- test("date-time-us format", () => {
16
- assert.equal(formatTimestamp(ts, "date-time-us"), "03-24-2026 10:34 AM");
17
- });
18
-
19
- test("US format handles PM correctly", () => {
20
- const pm = new Date(2026, 2, 24, 14, 5, 0).getTime();
21
- assert.equal(formatTimestamp(pm, "date-time-us"), "03-24-2026 2:05 PM");
22
- });
23
-
24
- test("US format handles noon as 12 PM", () => {
25
- const noon = new Date(2026, 2, 24, 12, 0, 0).getTime();
26
- assert.equal(formatTimestamp(noon, "date-time-us"), "03-24-2026 12:00 PM");
27
- });
28
-
29
- test("US format handles midnight as 12 AM", () => {
30
- const midnight = new Date(2026, 2, 24, 0, 0, 0).getTime();
31
- assert.equal(formatTimestamp(midnight, "date-time-us"), "03-24-2026 12:00 AM");
32
- });
33
-
34
- test("ISO format pads single digit months and days", () => {
35
- const jan1 = new Date(2026, 0, 1, 9, 5, 0).getTime();
36
- assert.equal(formatTimestamp(jan1, "date-time-iso"), "2026-01-01 09:05");
37
- });
38
- });
@@ -1,48 +0,0 @@
1
- /**
2
- * Timestamp formatting for message display.
3
- *
4
- * Formats:
5
- * - "time-date-iso": 10:34 2025-03-24 (default)
6
- * - "date-time-iso": 2025-03-24 10:34
7
- * - "time-date-us": 10:34 AM 03/24/2025
8
- * - "date-time-us": 03/24/2025 10:34 AM
9
- */
10
-
11
- export type TimestampFormat = "date-time-iso" | "date-time-us";
12
-
13
- function pad2(n: number): string {
14
- return n.toString().padStart(2, "0");
15
- }
16
-
17
- function isoDate(d: Date): string {
18
- return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}`;
19
- }
20
-
21
- function isoTime(d: Date): string {
22
- return `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;
23
- }
24
-
25
- function usDate(d: Date): string {
26
- return `${pad2(d.getMonth() + 1)}-${pad2(d.getDate())}-${d.getFullYear()}`;
27
- }
28
-
29
- function usTime(d: Date): string {
30
- const hours = d.getHours();
31
- const period = hours >= 12 ? "PM" : "AM";
32
- const h = hours % 12 || 12;
33
- return `${h}:${pad2(d.getMinutes())} ${period}`;
34
- }
35
-
36
- /**
37
- * Format a timestamp for message display using the specified format.
38
- */
39
- export function formatTimestamp(timestamp: number, format: TimestampFormat = "date-time-iso"): string {
40
- const d = new Date(timestamp);
41
-
42
- switch (format) {
43
- case "date-time-iso":
44
- return `${isoDate(d)} ${isoTime(d)}`;
45
- case "date-time-us":
46
- return `${usDate(d)} ${usTime(d)}`;
47
- }
48
- }
@@ -1,247 +0,0 @@
1
- /**
2
- * MCP Status — `/gsd mcp` command handler.
3
- *
4
- * Shows configured MCP servers, their connection status, and available tools.
5
- *
6
- * Subcommands:
7
- * /gsd mcp — Overview of all servers (alias: /gsd mcp status)
8
- * /gsd mcp status — Same as bare /gsd mcp
9
- * /gsd mcp check <srv> — Detailed status for a specific server
10
- */
11
-
12
- import type { ExtensionCommandContext } from "@gsd/pi-coding-agent";
13
-
14
- import { existsSync, readFileSync } from "node:fs";
15
- import { join } from "node:path";
16
-
17
- // ─── Types ──────────────────────────────────────────────────────────────────
18
-
19
- export interface McpServerStatus {
20
- name: string;
21
- transport: "stdio" | "http" | "unknown";
22
- connected: boolean;
23
- toolCount: number;
24
- error: string | undefined;
25
- }
26
-
27
- export interface McpServerDetail extends McpServerStatus {
28
- tools: string[];
29
- }
30
-
31
- // ─── Config reader (standalone — does not import mcp-client internals) ──────
32
-
33
- interface McpServerRawConfig {
34
- name: string;
35
- transport: "stdio" | "http" | "unknown";
36
- command?: string;
37
- args?: string[];
38
- url?: string;
39
- }
40
-
41
- function readMcpConfigs(): McpServerRawConfig[] {
42
- const servers: McpServerRawConfig[] = [];
43
- const seen = new Set<string>();
44
- const configPaths = [
45
- join(process.cwd(), ".mcp.json"),
46
- join(process.cwd(), ".gsd", "mcp.json"),
47
- ];
48
-
49
- for (const configPath of configPaths) {
50
- try {
51
- if (!existsSync(configPath)) continue;
52
- const raw = readFileSync(configPath, "utf-8");
53
- const data = JSON.parse(raw) as Record<string, unknown>;
54
- const mcpServers = (data.mcpServers ?? data.servers) as
55
- | Record<string, Record<string, unknown>>
56
- | undefined;
57
- if (!mcpServers || typeof mcpServers !== "object") continue;
58
-
59
- for (const [name, config] of Object.entries(mcpServers)) {
60
- if (seen.has(name)) continue;
61
- seen.add(name);
62
-
63
- const hasCommand = typeof config.command === "string";
64
- const hasUrl = typeof config.url === "string";
65
- const transport: McpServerRawConfig["transport"] = hasCommand
66
- ? "stdio"
67
- : hasUrl
68
- ? "http"
69
- : "unknown";
70
-
71
- servers.push({
72
- name,
73
- transport,
74
- ...(hasCommand && {
75
- command: config.command as string,
76
- args: Array.isArray(config.args) ? (config.args as string[]) : undefined,
77
- }),
78
- ...(hasUrl && { url: config.url as string }),
79
- });
80
- }
81
- } catch {
82
- // Non-fatal — config file may not exist or be malformed
83
- }
84
- }
85
-
86
- return servers;
87
- }
88
-
89
- // ─── Formatters (exported for testing) ──────────────────────────────────────
90
-
91
- export function formatMcpStatusReport(servers: McpServerStatus[]): string {
92
- if (servers.length === 0) {
93
- return [
94
- "No MCP servers configured.",
95
- "",
96
- "Add servers to .mcp.json or .gsd/mcp.json to enable MCP integrations.",
97
- "See: https://modelcontextprotocol.io/quickstart",
98
- ].join("\n");
99
- }
100
-
101
- const lines: string[] = [`MCP Server Status — ${servers.length} server(s)\n`];
102
-
103
- for (const s of servers) {
104
- const icon = s.error ? "✗" : s.connected ? "✓" : "○";
105
- const status = s.error
106
- ? `error: ${s.error}`
107
- : s.connected
108
- ? `connected — ${s.toolCount} tools`
109
- : "disconnected";
110
- lines.push(` ${icon} ${s.name} (${s.transport}) — ${status}`);
111
- }
112
-
113
- lines.push("");
114
- lines.push("Use /gsd mcp check <server> for details on a specific server.");
115
- lines.push("Use mcp_discover to connect and list tools for a server.");
116
-
117
- return lines.join("\n");
118
- }
119
-
120
- export function formatMcpServerDetail(server: McpServerDetail): string {
121
- const lines: string[] = [`MCP Server: ${server.name}\n`];
122
-
123
- lines.push(` Transport: ${server.transport}`);
124
-
125
- if (server.error) {
126
- lines.push(` Status: error`);
127
- lines.push(` Error: ${server.error}`);
128
- } else if (server.connected) {
129
- lines.push(` Status: connected`);
130
- lines.push(` Tools: ${server.toolCount}`);
131
- if (server.tools.length > 0) {
132
- lines.push("");
133
- lines.push(" Available tools:");
134
- for (const tool of server.tools) {
135
- lines.push(` - ${tool}`);
136
- }
137
- }
138
- } else {
139
- lines.push(` Status: disconnected`);
140
- lines.push("");
141
- lines.push(` Run mcp_discover("${server.name}") to connect and list tools.`);
142
- }
143
-
144
- return lines.join("\n");
145
- }
146
-
147
- // ─── Command handler ────────────────────────────────────────────────────────
148
-
149
- /**
150
- * Handle `/gsd mcp [status|check <server>]`.
151
- */
152
- export async function handleMcpStatus(
153
- args: string,
154
- ctx: ExtensionCommandContext,
155
- ): Promise<void> {
156
- const trimmed = args.trim().toLowerCase();
157
- const configs = readMcpConfigs();
158
-
159
- // /gsd mcp check <server>
160
- if (trimmed.startsWith("check ")) {
161
- const serverName = args.trim().slice("check ".length).trim();
162
- const config = configs.find((c) => c.name === serverName);
163
- if (!config) {
164
- const available = configs.map((c) => c.name).join(", ") || "(none)";
165
- ctx.ui.notify(
166
- `Unknown MCP server: "${serverName}"\n\nAvailable: ${available}`,
167
- "warning",
168
- );
169
- return;
170
- }
171
-
172
- // Try to get connection/tool info from the mcp-client module if available
173
- let connected = false;
174
- let toolNames: string[] = [];
175
- let error: string | undefined;
176
- try {
177
- const mcpClient = await import("../mcp-client/index.js");
178
- // Access the module's connection state if exported; fall back gracefully
179
- const mod = mcpClient as Record<string, unknown>;
180
- if (typeof mod.getConnectionStatus === "function") {
181
- const status = (mod.getConnectionStatus as (name: string) => { connected: boolean; tools: string[]; error?: string })(serverName);
182
- connected = status.connected;
183
- toolNames = status.tools;
184
- error = status.error;
185
- }
186
- } catch {
187
- // mcp-client may not expose status helpers — that's fine
188
- }
189
-
190
- ctx.ui.notify(
191
- formatMcpServerDetail({
192
- name: config.name,
193
- transport: config.transport,
194
- connected,
195
- toolCount: toolNames.length,
196
- tools: toolNames,
197
- error,
198
- }),
199
- "info",
200
- );
201
- return;
202
- }
203
-
204
- // /gsd mcp or /gsd mcp status
205
- if (!trimmed || trimmed === "status") {
206
- // Build status for each server
207
- const statuses: McpServerStatus[] = [];
208
-
209
- for (const config of configs) {
210
- let connected = false;
211
- let toolCount = 0;
212
- let error: string | undefined;
213
-
214
- try {
215
- const mcpClient = await import("../mcp-client/index.js");
216
- const mod = mcpClient as Record<string, unknown>;
217
- if (typeof mod.getConnectionStatus === "function") {
218
- const status = (mod.getConnectionStatus as (name: string) => { connected: boolean; tools: string[]; error?: string })(config.name);
219
- connected = status.connected;
220
- toolCount = status.tools.length;
221
- error = status.error;
222
- }
223
- } catch {
224
- // Fall back to unknown state
225
- }
226
-
227
- statuses.push({
228
- name: config.name,
229
- transport: config.transport,
230
- connected,
231
- toolCount,
232
- error,
233
- });
234
- }
235
-
236
- ctx.ui.notify(formatMcpStatusReport(statuses), "info");
237
- return;
238
- }
239
-
240
- // Unknown subcommand
241
- ctx.ui.notify(
242
- "Usage: /gsd mcp [status|check <server>]\n\n" +
243
- " status Show all MCP server statuses (default)\n" +
244
- " check <server> Detailed status for a specific server",
245
- "warning",
246
- );
247
- }
@@ -1,88 +0,0 @@
1
- /**
2
- * auto-pr-bugs.test.ts — Regression tests for #2302.
3
- *
4
- * Three interacting bugs prevented auto_pr from ever creating a PR:
5
- * 1. auto_pr was gated on `pushed` (which requires auto_push)
6
- * 2. Milestone branch was not pushed to remote before PR creation
7
- * 3. createDraftPR in git-service.ts lacked --head/--base parameters
8
- */
9
-
10
- import test from "node:test";
11
- import assert from "node:assert/strict";
12
- import { readFileSync } from "node:fs";
13
- import { join } from "node:path";
14
-
15
- // ─── Bug 1: auto_pr should not depend on auto_push / pushed flag ────────────
16
-
17
- const autoWorktreeSrcPath = join(import.meta.dirname, "..", "auto-worktree.ts");
18
- const autoWorktreeSrc = readFileSync(autoWorktreeSrcPath, "utf-8");
19
-
20
- test("#2302 bug 1: auto_pr condition should not require pushed flag", () => {
21
- // Find the auto_pr block in mergeMilestoneToMain
22
- const autoPrIdx = autoWorktreeSrc.indexOf("auto_pr");
23
- assert.ok(autoPrIdx !== -1, "auto_pr reference exists in auto-worktree.ts");
24
-
25
- // Get context around the auto_pr check
26
- const lineStart = autoWorktreeSrc.lastIndexOf("\n", autoPrIdx) + 1;
27
- const lineEnd = autoWorktreeSrc.indexOf("\n", autoPrIdx);
28
- const autoPrLine = autoWorktreeSrc.slice(lineStart, lineEnd);
29
-
30
- // The condition should NOT include `&& pushed`
31
- assert.ok(
32
- !autoPrLine.includes("&& pushed"),
33
- "auto_pr condition should not be gated on pushed flag (auto_push dependency)",
34
- );
35
- });
36
-
37
- // ─── Bug 2: phases.ts should not duplicate PR creation ──────────────────────
38
-
39
- const phasesSrcPath = join(import.meta.dirname, "..", "auto", "phases.ts");
40
- const phasesSrc = readFileSync(phasesSrcPath, "utf-8");
41
-
42
- test("#2302 bug 2: phases.ts should not call createDraftPR (handled by mergeMilestoneToMain)", () => {
43
- // After fix, phases.ts should not import or call createDraftPR because
44
- // PR creation is handled inside mergeMilestoneToMain in auto-worktree.ts
45
- const createDraftPRCalls = phasesSrc.match(/createDraftPR\(/g) || [];
46
-
47
- assert.equal(
48
- createDraftPRCalls.length,
49
- 0,
50
- "phases.ts should not call createDraftPR — it's handled by mergeMilestoneToMain",
51
- );
52
- });
53
-
54
- // ─── Bug 3: createDraftPR should accept head and base branch parameters ─────
55
-
56
- const gitServiceSrcPath = join(import.meta.dirname, "..", "git-service.ts");
57
- const gitServiceSrc = readFileSync(gitServiceSrcPath, "utf-8");
58
-
59
- test("#2302 bug 3: createDraftPR should accept head and base branch parameters", () => {
60
- // Find the createDraftPR function signature
61
- const fnIdx = gitServiceSrc.indexOf("function createDraftPR");
62
- assert.ok(fnIdx !== -1, "createDraftPR function exists");
63
-
64
- // Get the function signature (up to the closing paren)
65
- const sigEnd = gitServiceSrc.indexOf(")", fnIdx);
66
- const signature = gitServiceSrc.slice(fnIdx, sigEnd);
67
-
68
- // Should have head and base parameters
69
- assert.ok(
70
- signature.includes("head") || signature.includes("branch"),
71
- "createDraftPR should accept a head/branch parameter",
72
- );
73
- });
74
-
75
- test("#2302 bug 3: createDraftPR should pass --head and --base to gh pr create", () => {
76
- const fnIdx = gitServiceSrc.indexOf("function createDraftPR");
77
- const fnEnd = gitServiceSrc.indexOf("\n}", fnIdx);
78
- const fnBody = gitServiceSrc.slice(fnIdx, fnEnd);
79
-
80
- assert.ok(
81
- fnBody.includes("--head"),
82
- "createDraftPR should pass --head to gh pr create",
83
- );
84
- assert.ok(
85
- fnBody.includes("--base"),
86
- "createDraftPR should pass --base to gh pr create",
87
- );
88
- });