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.
- package/dist/cli-web-branch.d.ts +1 -0
- package/dist/cli-web-branch.js +3 -0
- package/dist/cli.js +24 -2
- package/dist/provider-migrations.d.ts +18 -0
- package/dist/provider-migrations.js +14 -0
- package/dist/resources/extensions/claude-code-cli/stream-adapter.js +14 -10
- package/dist/resources/extensions/gsd/abandon-detect.js +44 -0
- package/dist/resources/extensions/gsd/auto/resolve.js +24 -0
- package/dist/resources/extensions/gsd/auto/run-unit.js +10 -2
- package/dist/resources/extensions/gsd/auto/turn-epoch.js +95 -0
- package/dist/resources/extensions/gsd/auto-dispatch.js +24 -0
- package/dist/resources/extensions/gsd/auto-loop.js +1 -1
- package/dist/resources/extensions/gsd/auto-post-unit.js +31 -0
- package/dist/resources/extensions/gsd/auto-timeout-recovery.js +11 -5
- package/dist/resources/extensions/gsd/auto-unit-closeout.js +11 -2
- package/dist/resources/extensions/gsd/auto-worktree.js +58 -8
- package/dist/resources/extensions/gsd/auto.js +4 -0
- package/dist/resources/extensions/gsd/bootstrap/provider-error-resume.js +4 -2
- package/dist/resources/extensions/gsd/commands/handlers/workflow.js +31 -4
- package/dist/resources/extensions/gsd/file-lock.js +49 -9
- package/dist/resources/extensions/gsd/git-service.js +1 -0
- package/dist/resources/extensions/gsd/gitignore.js +1 -0
- package/dist/resources/extensions/gsd/guided-flow-queue.js +4 -1
- package/dist/resources/extensions/gsd/journal.js +17 -2
- package/dist/resources/extensions/gsd/milestone-actions.js +15 -0
- package/dist/resources/extensions/gsd/reports.js +5 -4
- package/dist/resources/extensions/gsd/tools/complete-slice.js +21 -0
- package/dist/resources/extensions/gsd/tools/complete-task.js +31 -0
- package/dist/resources/extensions/gsd/uok/audit.js +18 -2
- package/dist/resources/extensions/gsd/workflow-logger.js +10 -2
- package/dist/resources/extensions/gsd/worktree-manager.js +1 -0
- package/dist/resources/extensions/mcp-client/auth.js +10 -1
- package/dist/resources/extensions/mcp-client/index.js +118 -9
- package/dist/resources/skills/create-skill/SKILL.md +2 -2
- package/dist/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
- package/dist/resources/skills/create-skill/workflows/audit-skill.md +4 -4
- package/dist/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
- package/dist/tsconfig.extensions.tsbuildinfo +1 -1
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +13 -13
- package/dist/web/standalone/.next/build-manifest.json +3 -3
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- package/dist/web/standalone/.next/react-loadable-manifest.json +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.html +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.html +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/boot/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/input/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/resize/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/bridge-terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/captures/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/cleanup/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/doctor/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/export-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/forensics/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/history/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/hooks/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/inspect/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/knowledge/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/live-state/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/notifications/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/onboarding/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/recovery/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/browser/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/command/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/events/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/session/manage/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/settings-data/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/skill-health/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/steer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/switch-root/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/sessions/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/terminal/stream/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/undo/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js +1 -1
- package/dist/web/standalone/.next/server/app/api/visualizer/route.js.nft.json +1 -1
- package/dist/web/standalone/.next/server/app/index.html +1 -1
- package/dist/web/standalone/.next/server/app/index.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/dist/web/standalone/.next/server/app-paths-manifest.json +13 -13
- package/dist/web/standalone/.next/server/chunks/1926.js +1 -0
- package/dist/web/standalone/.next/server/chunks/6897.js +1 -1
- package/dist/web/standalone/.next/server/middleware-build-manifest.js +1 -1
- package/dist/web/standalone/.next/server/middleware-manifest.json +5 -5
- package/dist/web/standalone/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/dist/web/standalone/.next/server/pages/404.html +1 -1
- package/dist/web/standalone/.next/server/pages/500.html +1 -1
- package/dist/web/standalone/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/standalone/.next/static/chunks/2826.e9f5195e91f9cad2.js +11 -0
- package/dist/web/standalone/.next/static/chunks/{webpack-1832629448831fdc.js → webpack-2e68521d7c82f7c2.js} +1 -1
- package/package.json +3 -3
- package/packages/mcp-server/README.md +3 -3
- package/packages/mcp-server/dist/env-writer.d.ts +1 -0
- package/packages/mcp-server/dist/env-writer.d.ts.map +1 -1
- package/packages/mcp-server/dist/env-writer.js +74 -6
- package/packages/mcp-server/dist/env-writer.js.map +1 -1
- package/packages/mcp-server/dist/server.d.ts.map +1 -1
- package/packages/mcp-server/dist/server.js +25 -2
- package/packages/mcp-server/dist/server.js.map +1 -1
- package/packages/mcp-server/src/env-writer.test.ts +79 -1
- package/packages/mcp-server/src/env-writer.ts +76 -6
- package/packages/mcp-server/src/server.ts +29 -2
- package/packages/mcp-server/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js +21 -16
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts +2 -0
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js +130 -0
- package/packages/pi-coding-agent/dist/core/compaction-orchestrator.test.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts +1 -0
- package/packages/pi-coding-agent/dist/core/sdk.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.js +4 -1
- package/packages/pi-coding-agent/dist/core/sdk.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/sdk.test.js +19 -1
- package/packages/pi-coding-agent/dist/core/sdk.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js +15 -6
- package/packages/pi-coding-agent/dist/modes/interactive/components/__tests__/provider-display-name.test.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -5
- package/packages/pi-coding-agent/dist/modes/interactive/components/footer.js.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts +7 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js +31 -9
- package/packages/pi-coding-agent/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/packages/pi-coding-agent/src/core/compaction-orchestrator.test.ts +154 -0
- package/packages/pi-coding-agent/src/core/compaction-orchestrator.ts +24 -17
- package/packages/pi-coding-agent/src/core/sdk.test.ts +25 -1
- package/packages/pi-coding-agent/src/core/sdk.ts +10 -3
- package/packages/pi-coding-agent/src/modes/interactive/components/__tests__/provider-display-name.test.ts +17 -7
- package/packages/pi-coding-agent/src/modes/interactive/components/footer.ts +14 -5
- package/packages/pi-coding-agent/src/modes/interactive/components/model-selector.ts +45 -11
- package/packages/pi-coding-agent/tsconfig.tsbuildinfo +1 -1
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js +19 -0
- package/packages/pi-tui/dist/__tests__/stdin-buffer.test.js.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.d.ts +7 -0
- package/packages/pi-tui/dist/stdin-buffer.d.ts.map +1 -1
- package/packages/pi-tui/dist/stdin-buffer.js +20 -0
- package/packages/pi-tui/dist/stdin-buffer.js.map +1 -1
- package/packages/pi-tui/src/__tests__/stdin-buffer.test.ts +25 -0
- package/packages/pi-tui/src/stdin-buffer.ts +26 -0
- package/packages/pi-tui/tsconfig.tsbuildinfo +1 -1
- package/src/resources/extensions/claude-code-cli/stream-adapter.ts +14 -10
- package/src/resources/extensions/claude-code-cli/tests/stream-adapter.test.ts +22 -16
- package/src/resources/extensions/gsd/abandon-detect.ts +62 -0
- package/src/resources/extensions/gsd/auto/resolve.ts +29 -0
- package/src/resources/extensions/gsd/auto/run-unit.ts +16 -2
- package/src/resources/extensions/gsd/auto/turn-epoch.ts +108 -0
- package/src/resources/extensions/gsd/auto-dispatch.ts +20 -0
- package/src/resources/extensions/gsd/auto-loop.ts +1 -1
- package/src/resources/extensions/gsd/auto-post-unit.ts +30 -0
- package/src/resources/extensions/gsd/auto-timeout-recovery.ts +12 -5
- package/src/resources/extensions/gsd/auto-unit-closeout.ts +14 -3
- package/src/resources/extensions/gsd/auto-worktree.ts +60 -5
- package/src/resources/extensions/gsd/auto.ts +5 -0
- package/src/resources/extensions/gsd/bootstrap/provider-error-resume.ts +6 -2
- package/src/resources/extensions/gsd/commands/handlers/workflow.ts +27 -8
- package/src/resources/extensions/gsd/file-lock.ts +84 -11
- package/src/resources/extensions/gsd/git-service.ts +1 -0
- package/src/resources/extensions/gsd/gitignore.ts +1 -0
- package/src/resources/extensions/gsd/guided-flow-queue.ts +4 -1
- package/src/resources/extensions/gsd/journal.ts +27 -2
- package/src/resources/extensions/gsd/milestone-actions.ts +18 -0
- package/src/resources/extensions/gsd/reports.ts +5 -4
- package/src/resources/extensions/gsd/tests/auto-loop.test.ts +11 -2
- package/src/resources/extensions/gsd/tests/auto-mode-guards.test.ts +79 -0
- package/src/resources/extensions/gsd/tests/file-lock.test.ts +86 -12
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +30 -0
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +3 -2
- package/src/resources/extensions/gsd/tests/mcp-client-security.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/provider-errors.test.ts +39 -25
- package/src/resources/extensions/gsd/tests/queue-auto-guard.test.ts +181 -0
- package/src/resources/extensions/gsd/tests/quick-auto-guard.test.ts +13 -7
- package/src/resources/extensions/gsd/tests/require-slice-discussion-dispatch.test.ts +170 -0
- package/src/resources/extensions/gsd/tests/rewrite-docs-abandon-detect.test.ts +195 -0
- package/src/resources/extensions/gsd/tests/stuck-detection-coverage.test.ts +2 -2
- package/src/resources/extensions/gsd/tests/triage-resolution.test.ts +50 -2
- package/src/resources/extensions/gsd/tests/turn-epoch.test.ts +162 -0
- package/src/resources/extensions/gsd/tools/complete-slice.ts +38 -0
- package/src/resources/extensions/gsd/tools/complete-task.ts +49 -0
- package/src/resources/extensions/gsd/uok/audit.ts +20 -2
- package/src/resources/extensions/gsd/workflow-logger.ts +22 -3
- package/src/resources/extensions/gsd/worktree-manager.ts +1 -0
- package/src/resources/extensions/mcp-client/auth.ts +12 -1
- package/src/resources/extensions/mcp-client/index.ts +129 -10
- package/src/resources/skills/create-skill/SKILL.md +2 -2
- package/src/resources/skills/create-skill/references/gsd-skill-ecosystem.md +4 -4
- package/src/resources/skills/create-skill/workflows/audit-skill.md +4 -4
- package/src/resources/skills/create-skill/workflows/create-new-skill.md +5 -5
- package/dist/web/standalone/.next/server/chunks/7461.js +0 -1
- package/dist/web/standalone/.next/static/chunks/2826.d445fb428ef41fa1.js +0 -9
- /package/dist/web/standalone/.next/static/{H51SzzS_EEgdBsDVhrLBv → 5wbu35_C2_MQ3Jj1lEVDx}/_buildManifest.js +0 -0
- /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
|
|
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
|
-
|
|
266
|
-
|
|
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
|
|
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("
|
|
8
|
-
assert.equal(providerDisplayName("anthropic"), "anthropic
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
|
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(
|
|
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;
|