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
@@ -333,8 +333,9 @@ export class CompactionOrchestrator {
333
333
  type: "auto_compaction_end",
334
334
  result: undefined,
335
335
  aborted: true,
336
- willRetry: false,
336
+ willRetry,
337
337
  });
338
+ this._scheduleAutoCompactionFollowup(willRetry);
338
339
  return;
339
340
  }
340
341
 
@@ -392,22 +393,7 @@ export class CompactionOrchestrator {
392
393
 
393
394
  const result: CompactionResult = { summary, firstKeptEntryId, tokensBefore, details };
394
395
  this._deps.emit({ type: "auto_compaction_end", result, aborted: false, willRetry });
395
-
396
- if (willRetry) {
397
- const messages = this._deps.agent.state.messages;
398
- const lastMsg = messages[messages.length - 1];
399
- if (lastMsg?.role === "assistant" && (lastMsg as AssistantMessage).stopReason === "error") {
400
- this._deps.agent.replaceMessages(messages.slice(0, -1));
401
- }
402
-
403
- setTimeout(() => {
404
- this._deps.agent.continue().catch(() => {});
405
- }, 100);
406
- } else if (this._deps.agent.hasQueuedMessages()) {
407
- setTimeout(() => {
408
- this._deps.agent.continue().catch(() => {});
409
- }, 100);
410
- }
396
+ this._scheduleAutoCompactionFollowup(willRetry);
411
397
  } catch (error) {
412
398
  // Distinguish the "no usable summary" failure (issue #4665) so the UI
413
399
  // can surface a clearer message than a generic compaction failure.
@@ -430,4 +416,25 @@ export class CompactionOrchestrator {
430
416
  this._autoCompactionAbortController = undefined;
431
417
  }
432
418
  }
419
+
420
+ private _scheduleAutoCompactionFollowup(willRetry: boolean): void {
421
+ if (willRetry) {
422
+ const messages = this._deps.agent.state.messages;
423
+ const lastMsg = messages[messages.length - 1];
424
+ if (lastMsg?.role === "assistant" && (lastMsg as AssistantMessage).stopReason === "error") {
425
+ this._deps.agent.replaceMessages(messages.slice(0, -1));
426
+ }
427
+
428
+ setTimeout(() => {
429
+ this._deps.agent.continue().catch(() => {});
430
+ }, 100);
431
+ return;
432
+ }
433
+
434
+ if (this._deps.agent.hasQueuedMessages()) {
435
+ setTimeout(() => {
436
+ this._deps.agent.continue().catch(() => {});
437
+ }, 100);
438
+ }
439
+ }
433
440
  }
@@ -3,7 +3,8 @@
3
3
 
4
4
  import { describe, it } from "node:test";
5
5
  import assert from "node:assert/strict";
6
- import { CredentialCooldownError } from "./sdk.js";
6
+ import { canRestoreSessionModel, CredentialCooldownError } from "./sdk.js";
7
+ import type { Model } from "@gsd/pi-ai";
7
8
 
8
9
  // ─── CredentialCooldownError ──────────────────────────────────────────────────
9
10
 
@@ -87,3 +88,26 @@ describe("CredentialCooldownError", () => {
87
88
  assert.equal(plain.retryAfterMs, 15_000);
88
89
  });
89
90
  });
91
+
92
+ describe("canRestoreSessionModel", () => {
93
+ const model = {
94
+ provider: "claude-code",
95
+ id: "claude-sonnet",
96
+ } as Model<any>;
97
+
98
+ it("allows keyless external providers when the provider is request-ready", () => {
99
+ const registry = {
100
+ isProviderRequestReady: (provider: string) => provider === "claude-code",
101
+ };
102
+
103
+ assert.equal(canRestoreSessionModel(registry, model), true);
104
+ });
105
+
106
+ it("blocks restore when the provider is not request-ready", () => {
107
+ const registry = {
108
+ isProviderRequestReady: () => false,
109
+ };
110
+
111
+ assert.equal(canRestoreSessionModel(registry, model), false);
112
+ });
113
+ });
@@ -31,6 +31,13 @@ export class CredentialCooldownError extends Error {
31
31
  this.retryAfterMs = retryAfterMs;
32
32
  }
33
33
  }
34
+
35
+ export function canRestoreSessionModel(
36
+ modelRegistry: Pick<ModelRegistry, "isProviderRequestReady">,
37
+ model: Model<any>,
38
+ ): boolean {
39
+ return modelRegistry.isProviderRequestReady(model.provider);
40
+ }
34
41
  import { Agent, type AgentMessage, type ThinkingLevel } from "@gsd/pi-agent-core";
35
42
  import type { Message, Model } from "@gsd/pi-ai";
36
43
  import { getAgentDir, getDocsPath } from "../config.js";
@@ -262,9 +269,9 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {}
262
269
  // If session has data, try to restore model from it
263
270
  if (!model && hasExistingSession && existingSession.model) {
264
271
  const restoredModel = modelRegistry.find(existingSession.model.provider, existingSession.model.modelId);
265
- if (restoredModel && (await modelRegistry.getApiKey(restoredModel))) {
266
- model = restoredModel;
267
- }
272
+ if (restoredModel && canRestoreSessionModel(modelRegistry, restoredModel)) {
273
+ model = restoredModel;
274
+ }
268
275
  if (!model) {
269
276
  modelFallbackMessage = `Could not restore model ${existingSession.model.provider}/${existingSession.model.modelId}`;
270
277
  }
@@ -1,14 +1,11 @@
1
- // GSD-2 — Provider display name mapping tests
1
+ // GSD-2 — Provider display name + auth badge tests
2
2
  import { test, describe } from "node:test";
3
3
  import assert from "node:assert/strict";
4
- import { providerDisplayName } from "../model-selector.js";
4
+ import { providerAuthBadge, providerDisplayName } from "../model-selector.js";
5
5
 
6
6
  describe("providerDisplayName", () => {
7
- test("renames 'anthropic' to 'anthropic-api'", () => {
8
- assert.equal(providerDisplayName("anthropic"), "anthropic-api");
9
- });
10
-
11
- test("passes through unmapped providers unchanged", () => {
7
+ test("passes providers through unchanged", () => {
8
+ assert.equal(providerDisplayName("anthropic"), "anthropic");
12
9
  assert.equal(providerDisplayName("claude-code"), "claude-code");
13
10
  assert.equal(providerDisplayName("openai"), "openai");
14
11
  assert.equal(providerDisplayName("bedrock"), "bedrock");
@@ -16,3 +13,16 @@ describe("providerDisplayName", () => {
16
13
  assert.equal(providerDisplayName("openrouter"), "openrouter");
17
14
  });
18
15
  });
16
+
17
+ describe("providerAuthBadge", () => {
18
+ test("returns human-readable labels for each auth mode", () => {
19
+ assert.equal(providerAuthBadge("apiKey"), "API key");
20
+ assert.equal(providerAuthBadge("oauth"), "OAuth");
21
+ assert.equal(providerAuthBadge("externalCli"), "CLI");
22
+ });
23
+
24
+ test("returns empty string for 'none' and undefined", () => {
25
+ assert.equal(providerAuthBadge("none"), "");
26
+ assert.equal(providerAuthBadge(undefined), "");
27
+ });
28
+ });
@@ -2,7 +2,7 @@ import { type Component, truncateToWidth, visibleWidth } from "@gsd/pi-tui";
2
2
  import type { AgentSession } from "../../../core/agent-session.js";
3
3
  import type { ReadonlyFooterDataProvider } from "../../../core/footer-data-provider.js";
4
4
  import { theme } from "../theme/theme.js";
5
- import { providerDisplayName } from "./model-selector.js";
5
+ import { providerAuthBadge, providerDisplayName } from "./model-selector.js";
6
6
 
7
7
  /**
8
8
  * Sanitize text for display in a single-line status.
@@ -199,13 +199,22 @@ export class FooterComponent implements Component {
199
199
  thinkingLevel === "off" ? `${modelName} • thinking off` : `${modelName} • ${thinkingLevel}`;
200
200
  }
201
201
 
202
- // Prepend the provider in parentheses if there are multiple providers and there's enough room
202
+ // Prepend the provider in parentheses if there are multiple providers and there's enough room.
203
+ // Include the auth mode so users can tell at a glance whether the active model is
204
+ // API-key-backed, OAuth-backed, or delegated to a third-party CLI.
203
205
  let rightSide = rightSideWithoutProvider;
204
206
  if (this.footerData.getAvailableProviderCount() > 1 && displayModel) {
205
- rightSide = `(${providerDisplayName(displayModel.provider)}) ${rightSideWithoutProvider}`;
207
+ const authMode = this.session.modelRegistry.getProviderAuthMode(displayModel.provider);
208
+ const authLabel = providerAuthBadge(authMode);
209
+ const providerLabel = providerDisplayName(displayModel.provider);
210
+ const parenthetical = authLabel ? `${providerLabel} · ${authLabel}` : providerLabel;
211
+ rightSide = `(${parenthetical}) ${rightSideWithoutProvider}`;
206
212
  if (statsLeftWidth + minPadding + visibleWidth(rightSide) > width) {
207
- // Too wide, fall back
208
- rightSide = rightSideWithoutProvider;
213
+ // Too wide: drop the auth suffix first, then fall back to no parenthetical.
214
+ rightSide = `(${providerLabel}) ${rightSideWithoutProvider}`;
215
+ if (statsLeftWidth + minPadding + visibleWidth(rightSide) > width) {
216
+ rightSide = rightSideWithoutProvider;
217
+ }
209
218
  }
210
219
  }
211
220
 
@@ -9,19 +9,32 @@ import {
9
9
  Text,
10
10
  type TUI,
11
11
  } from "@gsd/pi-tui";
12
- import type { ModelRegistry } from "../../../core/model-registry.js";
12
+ import type { ModelRegistry, ProviderAuthMode } from "../../../core/model-registry.js";
13
13
  import type { SettingsManager } from "../../../core/settings-manager.js";
14
14
  import { theme } from "../theme/theme.js";
15
15
  import { DynamicBorder } from "./dynamic-border.js";
16
16
  import { keyHint } from "./keybinding-hints.js";
17
17
 
18
- /** Display names for providers in the model selector UI. */
19
- const PROVIDER_DISPLAY_NAMES: Record<string, string> = {
20
- anthropic: "anthropic-api",
21
- };
22
-
23
18
  export function providerDisplayName(provider: string): string {
24
- return PROVIDER_DISPLAY_NAMES[provider] ?? provider;
19
+ return provider;
20
+ }
21
+
22
+ /**
23
+ * Short, user-facing label for a provider's auth mode. Returned strings are
24
+ * suitable for use as a suffix/badge alongside the provider name.
25
+ * Returns an empty string for modes that don't need a badge (e.g. "none").
26
+ */
27
+ export function providerAuthBadge(authMode?: ProviderAuthMode): string {
28
+ switch (authMode) {
29
+ case "apiKey":
30
+ return "API key";
31
+ case "oauth":
32
+ return "OAuth";
33
+ case "externalCli":
34
+ return "CLI";
35
+ default:
36
+ return "";
37
+ }
25
38
  }
26
39
 
27
40
  function formatTokenCount(count: number): string {
@@ -140,7 +153,8 @@ export class ModelSelectorComponent extends Container implements Focusable {
140
153
  this.scopeHintText = new Text(this.getScopeHintText(), 0, 0);
141
154
  this.addChild(this.scopeHintText);
142
155
  } else {
143
- const hintText = "Only showing models with configured API keys (see README for details)";
156
+ const hintText =
157
+ "Only showing models with configured credentials (API key, OAuth, or CLI). See README for details.";
144
158
  this.addChild(new Text(theme.fg("warning", hintText), 0, 0));
145
159
  }
146
160
  this.addChild(new Spacer(1));
@@ -409,7 +423,12 @@ export class ModelSelectorComponent extends Container implements Focusable {
409
423
 
410
424
  const ctx = formatTokenCount(item.model.contextWindow);
411
425
  const ctxBadge = theme.fg("muted", `${ctx}`);
412
- const providerBadge = theme.fg("muted", `[${providerDisplayName(item.provider)}]`);
426
+ const authMode = this.modelRegistry.getProviderAuthMode(item.provider);
427
+ const authLabel = providerAuthBadge(authMode);
428
+ const providerBadgeText = authLabel
429
+ ? `[${providerDisplayName(item.provider)} · ${authLabel}]`
430
+ : `[${providerDisplayName(item.provider)}]`;
431
+ const providerBadge = theme.fg("muted", providerBadgeText);
413
432
  const checkmark = isCurrent ? theme.fg("success", " ✓") : "";
414
433
 
415
434
  let line: string;
@@ -445,7 +464,19 @@ export class ModelSelectorComponent extends Container implements Focusable {
445
464
  const maxVisible = 12;
446
465
 
447
466
  if (this.groupedRows.length === 0) {
448
- this.listContainer.addChild(new Text(theme.fg("muted", " No models available"), 0, 0));
467
+ this.listContainer.addChild(
468
+ new Text(theme.fg("muted", " No providers configured."), 0, 0),
469
+ );
470
+ this.listContainer.addChild(
471
+ new Text(
472
+ theme.fg(
473
+ "muted",
474
+ " Run /login (OAuth), set an API key, or install a CLI provider. See README.",
475
+ ),
476
+ 0,
477
+ 0,
478
+ ),
479
+ );
449
480
  return;
450
481
  }
451
482
 
@@ -467,11 +498,14 @@ export class ModelSelectorComponent extends Container implements Focusable {
467
498
  // Provider group header — always unselectable
468
499
  const providerLabel = theme.fg("borderAccent", providerDisplayName(row.provider));
469
500
  const count = theme.fg("muted", ` (${row.count})`);
501
+ const authMode = this.modelRegistry.getProviderAuthMode(row.provider);
502
+ const authLabel = providerAuthBadge(authMode);
503
+ const authText = authLabel ? theme.fg("muted", ` · via ${authLabel}`) : "";
470
504
  // Add blank line before header if not the very first visible row
471
505
  if (i > startIndex) {
472
506
  this.listContainer.addChild(new Text("", 0, 0));
473
507
  }
474
- this.listContainer.addChild(new Text(` ${providerLabel}${count}`, 0, 0));
508
+ this.listContainer.addChild(new Text(` ${providerLabel}${count}${authText}`, 0, 0));
475
509
  } else {
476
510
  // Model row
477
511
  const isSelected = i === this.selectedGroupIndex;