@opengsd/gsd-pi 1.0.2-dev.5961fbf → 1.0.2-dev.5f7864c
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/README.md +63 -12
- package/dist/onboarding.js +22 -3
- package/dist/resource-loader.d.ts +2 -0
- package/dist/resource-loader.js +18 -1
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/context7/index.js +12 -2
- package/dist/resources/extensions/get-secrets-from-user.js +16 -16
- package/dist/resources/extensions/google-cli/index.js +30 -0
- package/dist/resources/extensions/google-cli/models.js +55 -0
- package/dist/resources/extensions/google-cli/package.json +11 -0
- package/dist/resources/extensions/google-cli/readiness.js +12 -0
- package/dist/resources/extensions/google-cli/stream-adapter.js +191 -0
- package/dist/resources/extensions/gsd/auto/session.js +3 -0
- package/dist/resources/extensions/gsd/auto-start.js +232 -49
- package/dist/resources/extensions/gsd/bootstrap/db-tools.js +4 -3
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +17 -15
- package/dist/resources/extensions/gsd/closeout-recovery.js +7 -1
- package/dist/resources/extensions/gsd/commands/handlers/auto.js +9 -1
- package/dist/resources/extensions/gsd/commands-handlers.js +3 -0
- package/dist/resources/extensions/gsd/commands-usage.js +105 -1
- package/dist/resources/extensions/gsd/config-overlay.js +20 -14
- package/dist/resources/extensions/gsd/context-overlay.js +22 -16
- package/dist/resources/extensions/gsd/dashboard-overlay.js +10 -23
- package/dist/resources/extensions/gsd/doctor-providers.js +54 -24
- package/dist/resources/extensions/gsd/git-conflict-state.js +26 -1
- package/dist/resources/extensions/gsd/guided-flow.js +1 -1
- package/dist/resources/extensions/gsd/key-manager.js +45 -13
- package/dist/resources/extensions/gsd/notification-overlay.js +8 -9
- package/dist/resources/extensions/gsd/parallel-monitor-overlay.js +15 -13
- package/dist/resources/extensions/gsd/prompt-loader.js +2 -0
- package/dist/resources/extensions/gsd/prompts/discuss.md +4 -2
- package/dist/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/dist/resources/extensions/gsd/queue-reorder-ui.js +28 -18
- package/dist/resources/extensions/gsd/tools/complete-task.js +9 -0
- package/dist/resources/extensions/gsd/tools/workflow-tool-executors.js +40 -1
- package/dist/resources/extensions/gsd/tui/render-kit.js +51 -0
- package/dist/resources/extensions/gsd/vision-ask.js +22 -0
- package/dist/resources/extensions/gsd/visualizer-overlay.js +8 -36
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +24 -3
- package/dist/resources/extensions/search-the-web/native-search.js +57 -8
- package/dist/resources/extensions/shared/confirm-ui.js +9 -6
- package/dist/resources/extensions/shared/dialog-frame.js +42 -0
- package/dist/resources/extensions/shared/interview-ui.js +42 -30
- package/dist/resources/extensions/shared/next-action-ui.js +6 -6
- package/dist/resources/shared/package-manager-detection.js +36 -0
- package/dist/update-check.d.ts +6 -2
- package/dist/update-check.js +7 -3
- package/dist/web/standalone/.next/BUILD_ID +1 -1
- package/dist/web/standalone/.next/app-path-routes-manifest.json +6 -6
- package/dist/web/standalone/.next/build-manifest.json +2 -2
- package/dist/web/standalone/.next/prerender-manifest.json +3 -3
- 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/update/route.js +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 +6 -6
- package/dist/web/standalone/.next/server/chunks/1834.js +2 -2
- package/dist/web/standalone/.next/server/middleware-build-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/package.json +1 -1
- package/packages/cloud-mcp-gateway/package.json +2 -2
- package/packages/contracts/package.json +1 -1
- package/packages/daemon/package.json +4 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts +12 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.d.ts.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js +45 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/dialog-container.js.map +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts +3 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js +11 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-editor.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts +3 -3
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js +13 -11
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-input.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts +3 -3
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js +12 -10
- package/packages/gsd-agent-modes/dist/modes/interactive/components/extension-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js +1 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/components/index.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js +2 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts +6 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js +9 -6
- package/packages/gsd-agent-modes/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js +0 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/components/transcript-design.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts +3 -0
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js +144 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-auth.js.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js +2 -14
- package/packages/gsd-agent-modes/dist/modes/interactive/interactive-selectors-session.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/dist/workflow-tools.js +1 -1
- package/packages/mcp-server/dist/workflow-tools.js.map +1 -1
- package/packages/mcp-server/package.json +3 -3
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +13 -13
- package/packages/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/packages/pi-agent-core/package.json +1 -1
- package/packages/pi-ai/dist/models.generated.d.ts +57 -17
- package/packages/pi-ai/dist/models.generated.d.ts.map +1 -1
- package/packages/pi-ai/dist/models.generated.js +64 -28
- package/packages/pi-ai/dist/models.generated.js.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/anthropic.js +50 -0
- package/packages/pi-ai/dist/providers/anthropic.js.map +1 -1
- package/packages/pi-ai/dist/types.d.ts +2 -0
- package/packages/pi-ai/dist/types.d.ts.map +1 -1
- package/packages/pi-ai/dist/types.js.map +1 -1
- package/packages/pi-ai/package.json +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +1 -1
- package/packages/rpc-client/package.json +2 -2
- package/pkg/package.json +1 -1
- package/scripts/install/detect-existing.js +17 -3
- package/scripts/install/npm-global.js +103 -33
- package/scripts/install.js +1 -0
- package/src/resources/extensions/context7/index.ts +15 -2
- package/src/resources/extensions/get-secrets-from-user.ts +17 -16
- package/src/resources/extensions/google-cli/index.ts +34 -0
- package/src/resources/extensions/google-cli/models.ts +57 -0
- package/src/resources/extensions/google-cli/package.json +11 -0
- package/src/resources/extensions/google-cli/readiness.ts +15 -0
- package/src/resources/extensions/google-cli/stream-adapter.ts +245 -0
- package/src/resources/extensions/gsd/auto/session.ts +3 -0
- package/src/resources/extensions/gsd/auto-start.ts +307 -56
- package/src/resources/extensions/gsd/bootstrap/db-tools.ts +4 -3
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +22 -15
- package/src/resources/extensions/gsd/closeout-recovery.ts +6 -1
- package/src/resources/extensions/gsd/commands/handlers/auto.ts +9 -1
- package/src/resources/extensions/gsd/commands-handlers.ts +2 -0
- package/src/resources/extensions/gsd/commands-usage.ts +110 -5
- package/src/resources/extensions/gsd/config-overlay.ts +19 -16
- package/src/resources/extensions/gsd/context-overlay.ts +24 -19
- package/src/resources/extensions/gsd/dashboard-overlay.ts +14 -27
- package/src/resources/extensions/gsd/doctor-providers.ts +55 -27
- package/src/resources/extensions/gsd/git-conflict-state.ts +25 -1
- package/src/resources/extensions/gsd/guided-flow.ts +1 -1
- package/src/resources/extensions/gsd/key-manager.ts +57 -14
- package/src/resources/extensions/gsd/notification-overlay.ts +12 -11
- package/src/resources/extensions/gsd/parallel-monitor-overlay.ts +16 -12
- package/src/resources/extensions/gsd/prompt-loader.ts +2 -0
- package/src/resources/extensions/gsd/prompts/discuss.md +4 -2
- package/src/resources/extensions/gsd/prompts/guided-discuss-milestone.md +2 -0
- package/src/resources/extensions/gsd/queue-reorder-ui.ts +29 -20
- package/src/resources/extensions/gsd/tests/auto-start-orphan-bootstrap.test.ts +436 -0
- package/src/resources/extensions/gsd/tests/closeout-recovery.test.ts +15 -0
- package/src/resources/extensions/gsd/tests/collect-from-manifest.test.ts +31 -0
- package/src/resources/extensions/gsd/tests/commands-context.test.ts +5 -3
- package/src/resources/extensions/gsd/tests/commands-dispatcher-workspace-git.test.ts +15 -2
- package/src/resources/extensions/gsd/tests/commands-usage.test.ts +97 -0
- package/src/resources/extensions/gsd/tests/context-chart.test.ts +9 -0
- package/src/resources/extensions/gsd/tests/dashboard-overlay.test.ts +25 -0
- package/src/resources/extensions/gsd/tests/discuss-prompt.test.ts +4 -2
- package/src/resources/extensions/gsd/tests/doctor-providers.test.ts +105 -0
- package/src/resources/extensions/gsd/tests/guided-discuss-milestone-prompt-rendering.test.ts +6 -0
- package/src/resources/extensions/gsd/tests/key-manager.test.ts +23 -4
- package/src/resources/extensions/gsd/tests/notification-overlay.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/orphaned-worktree-audit.test.ts +70 -10
- package/src/resources/extensions/gsd/tests/parallel-monitor-overlay.test.ts +7 -1
- package/src/resources/extensions/gsd/tests/queue-reorder-ui.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/show-config-command.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/start-auto-detached.test.ts +13 -2
- package/src/resources/extensions/gsd/tests/tool-param-optionality.test.ts +24 -1
- package/src/resources/extensions/gsd/tests/tui-border-assertions.ts +28 -0
- package/src/resources/extensions/gsd/tests/tui-render-kit.test.ts +14 -0
- package/src/resources/extensions/gsd/tests/vision-ask.test.ts +23 -0
- package/src/resources/extensions/gsd/tests/visualizer-overlay.test.ts +6 -1
- package/src/resources/extensions/gsd/tests/workflow-mcp-auto-prep.test.ts +60 -0
- package/src/resources/extensions/gsd/tests/workflow-tool-executors.test.ts +54 -0
- package/src/resources/extensions/gsd/tests/workspace-git-preflight.test.ts +16 -1
- package/src/resources/extensions/gsd/tests/worktree-lifecycle.test.ts +28 -0
- package/src/resources/extensions/gsd/tests/zombie-gsd-state.test.ts +45 -1
- package/src/resources/extensions/gsd/tools/complete-task.ts +9 -0
- package/src/resources/extensions/gsd/tools/workflow-tool-executors.ts +56 -4
- package/src/resources/extensions/gsd/tui/render-kit.ts +82 -0
- package/src/resources/extensions/gsd/vision-ask.ts +28 -0
- package/src/resources/extensions/gsd/visualizer-overlay.ts +12 -40
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +37 -2
- package/src/resources/extensions/search-the-web/native-search.ts +60 -8
- package/src/resources/extensions/shared/confirm-ui.ts +8 -12
- package/src/resources/extensions/shared/dialog-frame.ts +71 -0
- package/src/resources/extensions/shared/interview-ui.ts +43 -42
- package/src/resources/extensions/shared/next-action-ui.ts +6 -6
- package/src/resources/extensions/shared/tests/confirm-ui.test.ts +57 -0
- package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +163 -0
- package/src/resources/extensions/shared/tests/next-action-ui-hasui.test.ts +55 -0
- package/src/resources/shared/package-manager-detection.ts +39 -0
- /package/dist/web/standalone/.next/static/{spUYLkQXoHJyxYOMH9VQy → IjxvcC7sl_MHNKXsUZrAy}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{spUYLkQXoHJyxYOMH9VQy → IjxvcC7sl_MHNKXsUZrAy}/_ssgManifest.js +0 -0
|
@@ -678,8 +678,9 @@ export function registerDbTools(pi) {
|
|
|
678
678
|
promptSnippet: "Complete a GSD task (DB write + summary render + checkbox toggle)",
|
|
679
679
|
promptGuidelines: [
|
|
680
680
|
"Use gsd_task_complete (or gsd_complete_task) when a task is finished and needs to be recorded.",
|
|
681
|
-
"
|
|
682
|
-
"
|
|
681
|
+
"Include verification whenever possible. If verification is omitted, the executor derives it from verificationEvidence when possible.",
|
|
682
|
+
"verificationEvidence is an array of objects with command, exitCode, verdict, durationMs.",
|
|
683
|
+
"The tool validates required fields and returns an error message if verification cannot be derived.",
|
|
683
684
|
"On success, returns the summaryPath where the SUMMARY.md was written.",
|
|
684
685
|
"Idempotent — calling with the same params twice will upsert (INSERT OR REPLACE) without error.",
|
|
685
686
|
],
|
|
@@ -690,7 +691,7 @@ export function registerDbTools(pi) {
|
|
|
690
691
|
milestoneId: Type.String({ description: "Milestone ID (e.g. M001)" }),
|
|
691
692
|
oneLiner: Type.String({ description: "One-line summary of what was accomplished" }),
|
|
692
693
|
narrative: Type.String({ description: "Detailed narrative of what happened during the task" }),
|
|
693
|
-
verification: Type.String({ description: "What was verified and how — commands run, tests passed, behavior confirmed" }),
|
|
694
|
+
verification: Type.Optional(Type.String({ description: "What was verified and how — commands run, tests passed, behavior confirmed. If omitted, derived from verificationEvidence when possible." })),
|
|
694
695
|
// ── Enrichment metadata (optional — defaults to empty) ────────────
|
|
695
696
|
deviations: Type.Optional(Type.String({ description: "Deviations from the task plan, or 'None.'" })),
|
|
696
697
|
knownIssues: Type.Optional(Type.String({ description: "Known issues discovered but not fixed, or 'None.'" })),
|
|
@@ -418,6 +418,17 @@ function initSessionNotifications(ctx) {
|
|
|
418
418
|
installNotifyInterceptor(ctx);
|
|
419
419
|
initNotificationWidget(ctx);
|
|
420
420
|
}
|
|
421
|
+
async function prepareWorkflowMcpForHookContext(ctx, basePath) {
|
|
422
|
+
// Skip MCP auto-prep when running inside an auto-worktree. The worktree
|
|
423
|
+
// already has .mcp.json from createAutoWorktree, and re-running the writer
|
|
424
|
+
// post-chdir rewrites the file mid-run (non-idempotent due to cwd-relative
|
|
425
|
+
// CLI path resolution), dirtying the tree and breaking the milestone merge.
|
|
426
|
+
const { isInAutoWorktree } = await import("../auto-worktree.js");
|
|
427
|
+
if (isInAutoWorktree(basePath))
|
|
428
|
+
return;
|
|
429
|
+
const { prepareWorkflowMcpForProject } = await import("../workflow-mcp-auto-prep.js");
|
|
430
|
+
prepareWorkflowMcpForProject(ctx, basePath);
|
|
431
|
+
}
|
|
421
432
|
export function registerHooks(pi, ecosystemHandlers) {
|
|
422
433
|
// ADR-005 Phase 3b: surface pi-ai ProviderSwitchReport via audit, notification, and counter.
|
|
423
434
|
// Idempotent — only the first registerHooks call installs.
|
|
@@ -438,12 +449,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
438
449
|
await syncServiceTierStatus(ctx);
|
|
439
450
|
await applyDisabledModelProviderPolicy(ctx);
|
|
440
451
|
await applyCompactionThresholdOverride(ctx);
|
|
441
|
-
|
|
442
|
-
const { isInAutoWorktree } = await import("../auto-worktree.js");
|
|
443
|
-
if (!isInAutoWorktree(basePath)) {
|
|
444
|
-
const { prepareWorkflowMcpForProject } = await import("../workflow-mcp-auto-prep.js");
|
|
445
|
-
prepareWorkflowMcpForProject(ctx, basePath);
|
|
446
|
-
}
|
|
452
|
+
await prepareWorkflowMcpForHookContext(ctx, basePath);
|
|
447
453
|
// Apply show_token_cost preference (#1515)
|
|
448
454
|
try {
|
|
449
455
|
const { loadEffectiveGSDPreferences } = await import("../preferences.js");
|
|
@@ -468,15 +474,7 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
468
474
|
await syncServiceTierStatus(ctx);
|
|
469
475
|
await applyDisabledModelProviderPolicy(ctx);
|
|
470
476
|
await applyCompactionThresholdOverride(ctx);
|
|
471
|
-
|
|
472
|
-
// already has .mcp.json from createAutoWorktree, and re-running the writer
|
|
473
|
-
// post-chdir rewrites the file mid-run (non-idempotent due to cwd-relative
|
|
474
|
-
// CLI path resolution), dirtying the tree and breaking the milestone merge.
|
|
475
|
-
const { isInAutoWorktree } = await import("../auto-worktree.js");
|
|
476
|
-
if (!isInAutoWorktree(basePath)) {
|
|
477
|
-
const { prepareWorkflowMcpForProject } = await import("../workflow-mcp-auto-prep.js");
|
|
478
|
-
prepareWorkflowMcpForProject(ctx, basePath);
|
|
479
|
-
}
|
|
477
|
+
await prepareWorkflowMcpForHookContext(ctx, basePath);
|
|
480
478
|
await loadToolApiKeysForSession();
|
|
481
479
|
if (!isAutoActive()) {
|
|
482
480
|
ctx.ui.setWidget("gsd-progress", undefined);
|
|
@@ -511,6 +509,10 @@ export function registerHooks(pi, ecosystemHandlers) {
|
|
|
511
509
|
}
|
|
512
510
|
}
|
|
513
511
|
clearDeferredApprovalGate(beforeAgentBasePath);
|
|
512
|
+
// session_start can fire before the active provider has settled. By
|
|
513
|
+
// before_agent_start, Claude Code CLI sessions should get the same
|
|
514
|
+
// project MCP config that /gsd mcp init would write.
|
|
515
|
+
await prepareWorkflowMcpForHookContext(ctx, beforeAgentBasePath);
|
|
514
516
|
// GSD's own context injection (existing behavior — unchanged).
|
|
515
517
|
const { buildBeforeAgentStartResult } = await import("./system-context.js");
|
|
516
518
|
const gsdResult = await buildBeforeAgentStartResult(event, ctx);
|
|
@@ -167,7 +167,13 @@ export function getCloseoutManualResolveBlocker(basePath) {
|
|
|
167
167
|
if (conflictProbe.status === "dirty" && conflictProbe.unmerged.length > 0) {
|
|
168
168
|
return `Unmerged paths remain in ${basePath}: ${conflictProbe.unmerged.slice(0, 5).join(", ")}`;
|
|
169
169
|
}
|
|
170
|
-
|
|
170
|
+
let status;
|
|
171
|
+
try {
|
|
172
|
+
status = runGit(basePath, ["status", "--porcelain"]);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return `Could not inspect git status in ${basePath}.`;
|
|
176
|
+
}
|
|
171
177
|
if (status) {
|
|
172
178
|
return `Working tree still has uncommitted changes in ${basePath}. Commit, stash, or run /gsd closeout retry first.`;
|
|
173
179
|
}
|
|
@@ -197,7 +197,15 @@ export async function handleAutoCommand(trimmed, ctx, pi) {
|
|
|
197
197
|
if (trimmed === "") {
|
|
198
198
|
if (!(await guardRemoteSession(ctx, pi)))
|
|
199
199
|
return true;
|
|
200
|
-
|
|
200
|
+
const basePath = projectRoot();
|
|
201
|
+
const { hasGsdBootstrapArtifacts } = await import("../../detection.js");
|
|
202
|
+
const { gsdRoot } = await import("../../paths.js");
|
|
203
|
+
if (!hasGsdBootstrapArtifacts(gsdRoot(basePath))) {
|
|
204
|
+
const { showSmartEntry } = await import("../../guided-flow.js");
|
|
205
|
+
await showSmartEntry(ctx, pi, basePath, { step: true });
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
if (await hasUnresolvedCloseoutBlocker(ctx, basePath))
|
|
201
209
|
return true;
|
|
202
210
|
const { showGsdHome } = await import("../../gsd-command-home.js");
|
|
203
211
|
await showGsdHome(ctx, pi, projectRoot());
|
|
@@ -17,6 +17,7 @@ import { isAutoActive, checkRemoteAutoSession } from "./auto.js";
|
|
|
17
17
|
import { getAutoWorktreePath } from "./auto-worktree.js";
|
|
18
18
|
import { currentDirectoryRoot, projectRoot } from "./commands/context.js";
|
|
19
19
|
import { loadPrompt } from "./prompt-loader.js";
|
|
20
|
+
import { isPnpmInstall } from "../../shared/package-manager-detection.js";
|
|
20
21
|
import { buildDoctorHealIssuePayload, buildDoctorHealSummary, buildWorkflowDispatchContent, } from "./workflow-protocol.js";
|
|
21
22
|
import { restoreGsdWorkflowTools, scopeGsdWorkflowToolsForDispatch, } from "./bootstrap/register-hooks.js";
|
|
22
23
|
const UPDATE_REGISTRY_URL = "https://registry.npmjs.org/@opengsd%2fgsd-pi/latest";
|
|
@@ -42,6 +43,8 @@ function isBunInstall(argv1 = process.argv[1]) {
|
|
|
42
43
|
function resolveInstallCommand(pkg) {
|
|
43
44
|
if (isBunInstall())
|
|
44
45
|
return `bun add -g ${pkg}`;
|
|
46
|
+
if (isPnpmInstall())
|
|
47
|
+
return `pnpm add -g ${pkg}`;
|
|
45
48
|
return `npm install -g ${pkg}`;
|
|
46
49
|
}
|
|
47
50
|
async function fetchLatestVersionForCommand() {
|
|
@@ -3,8 +3,10 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Shows current LLM context window usage and session token totals.
|
|
5
5
|
*/
|
|
6
|
+
import { Key, matchesKey } from "@gsd/pi-tui";
|
|
6
7
|
import { formatCost, formatPercent, formatTokenCount } from "./metrics.js";
|
|
7
8
|
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
|
9
|
+
import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
|
|
8
10
|
export function scanSessionTokenTotals(entries) {
|
|
9
11
|
const totals = {
|
|
10
12
|
input: 0,
|
|
@@ -115,6 +117,97 @@ export function formatUsageReport(options) {
|
|
|
115
117
|
}
|
|
116
118
|
return lines.join("\n");
|
|
117
119
|
}
|
|
120
|
+
async function showUsageDialog(ctx, reportText) {
|
|
121
|
+
return ctx.ui.custom((tui, theme, _kb, done) => {
|
|
122
|
+
let cachedLines;
|
|
123
|
+
let cachedWidth;
|
|
124
|
+
let cachedRows;
|
|
125
|
+
let cachedScrollOffset;
|
|
126
|
+
let scrollOffset = 0;
|
|
127
|
+
let lastMaxScroll = 0;
|
|
128
|
+
let lastVisibleRows = 1;
|
|
129
|
+
function render(width) {
|
|
130
|
+
const terminalRows = process.stdout.rows || 0;
|
|
131
|
+
if (cachedLines &&
|
|
132
|
+
cachedWidth === width &&
|
|
133
|
+
cachedRows === terminalRows &&
|
|
134
|
+
cachedScrollOffset === scrollOffset) {
|
|
135
|
+
return cachedLines;
|
|
136
|
+
}
|
|
137
|
+
const contentWidth = Math.max(1, width - 4);
|
|
138
|
+
const body = reportText.split("\n");
|
|
139
|
+
if (body[0] === "Context Usage")
|
|
140
|
+
body.shift();
|
|
141
|
+
while (body[0] === "")
|
|
142
|
+
body.shift();
|
|
143
|
+
const maxOverlayRows = terminalRows > 0 ? Math.max(5, Math.floor(terminalRows * 0.8)) : 24;
|
|
144
|
+
const frameRows = 4;
|
|
145
|
+
const visibleRows = Math.max(1, maxOverlayRows - frameRows);
|
|
146
|
+
const maxScroll = Math.max(0, body.length - visibleRows);
|
|
147
|
+
scrollOffset = Math.min(Math.max(scrollOffset, 0), maxScroll);
|
|
148
|
+
lastMaxScroll = maxScroll;
|
|
149
|
+
lastVisibleRows = visibleRows;
|
|
150
|
+
const visible = body.slice(scrollOffset, scrollOffset + visibleRows);
|
|
151
|
+
const scrollable = body.length > visibleRows;
|
|
152
|
+
cachedLines = renderDialogFrame(theme, "Context Usage", visible, width, {
|
|
153
|
+
footer: renderKeyHints(theme, scrollable ? ["↑↓ scroll", "any key close"] : ["any key close"], contentWidth),
|
|
154
|
+
scroll: { offset: scrollOffset, visibleRows, totalRows: body.length },
|
|
155
|
+
});
|
|
156
|
+
cachedWidth = width;
|
|
157
|
+
cachedRows = terminalRows;
|
|
158
|
+
cachedScrollOffset = scrollOffset;
|
|
159
|
+
return cachedLines;
|
|
160
|
+
}
|
|
161
|
+
function scrollBy(delta) {
|
|
162
|
+
if (lastMaxScroll <= 0)
|
|
163
|
+
return false;
|
|
164
|
+
const nextOffset = Math.min(Math.max(scrollOffset + delta, 0), lastMaxScroll);
|
|
165
|
+
if (nextOffset !== scrollOffset) {
|
|
166
|
+
scrollOffset = nextOffset;
|
|
167
|
+
cachedLines = undefined;
|
|
168
|
+
cachedScrollOffset = undefined;
|
|
169
|
+
tui.requestRender();
|
|
170
|
+
}
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
render,
|
|
175
|
+
invalidate: () => {
|
|
176
|
+
cachedLines = undefined;
|
|
177
|
+
cachedWidth = undefined;
|
|
178
|
+
cachedRows = undefined;
|
|
179
|
+
cachedScrollOffset = undefined;
|
|
180
|
+
},
|
|
181
|
+
handleInput: (data) => {
|
|
182
|
+
if (matchesKey(data, Key.down) || matchesKey(data, "j")) {
|
|
183
|
+
if (scrollBy(1))
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (matchesKey(data, Key.up) || matchesKey(data, "k")) {
|
|
187
|
+
if (scrollBy(-1))
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (matchesKey(data, Key.pageDown)) {
|
|
191
|
+
if (scrollBy(lastVisibleRows))
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
if (matchesKey(data, Key.pageUp)) {
|
|
195
|
+
if (scrollBy(-lastVisibleRows))
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
done(true);
|
|
199
|
+
},
|
|
200
|
+
};
|
|
201
|
+
}, {
|
|
202
|
+
overlay: true,
|
|
203
|
+
overlayOptions: {
|
|
204
|
+
width: "70%",
|
|
205
|
+
minWidth: 64,
|
|
206
|
+
maxHeight: "80%",
|
|
207
|
+
anchor: "center",
|
|
208
|
+
},
|
|
209
|
+
});
|
|
210
|
+
}
|
|
118
211
|
export async function handleUsage(args, ctx) {
|
|
119
212
|
const contextUsage = ctx.getContextUsage?.();
|
|
120
213
|
const sessionTotals = scanSessionTokenTotals(ctx.sessionManager.getEntries());
|
|
@@ -133,5 +226,16 @@ export async function handleUsage(args, ctx) {
|
|
|
133
226
|
}, null, 2), "info");
|
|
134
227
|
return;
|
|
135
228
|
}
|
|
136
|
-
|
|
229
|
+
const reportText = formatUsageReport({ modelLabel, contextUsage, sessionTotals });
|
|
230
|
+
if (ctx.hasUI) {
|
|
231
|
+
try {
|
|
232
|
+
const result = await showUsageDialog(ctx, reportText);
|
|
233
|
+
if (result !== undefined)
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// Fall back to text notify below when custom overlays are unavailable.
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
ctx.ui.notify(reportText, "info");
|
|
137
241
|
}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* Opened via `/gsd show-config` or `/gsd config`.
|
|
8
8
|
*/
|
|
9
9
|
import { matchesKey, Key, truncateToWidth } from "@gsd/pi-tui";
|
|
10
|
+
import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
|
|
10
11
|
import { loadEffectiveGSDPreferences, loadGlobalGSDPreferences, loadProjectGSDPreferences, getGlobalGSDPreferencesPath, getProjectGSDPreferencesPath, resolveDynamicRoutingConfig, resolveEffectiveProfile, resolveModelWithFallbacksForUnit, resolveAutoSupervisorConfig, } from "./preferences.js";
|
|
11
12
|
function collectConfigSections() {
|
|
12
13
|
const sections = [];
|
|
@@ -227,6 +228,7 @@ export class GSDConfigOverlay {
|
|
|
227
228
|
onClose;
|
|
228
229
|
sections;
|
|
229
230
|
cachedLines;
|
|
231
|
+
cachedWidth;
|
|
230
232
|
scrollOffset = 0;
|
|
231
233
|
disposed = false;
|
|
232
234
|
constructor(tui, theme, onClose) {
|
|
@@ -237,6 +239,7 @@ export class GSDConfigOverlay {
|
|
|
237
239
|
}
|
|
238
240
|
invalidate() {
|
|
239
241
|
this.cachedLines = undefined;
|
|
242
|
+
this.cachedWidth = undefined;
|
|
240
243
|
}
|
|
241
244
|
dispose() {
|
|
242
245
|
this.disposed = true;
|
|
@@ -273,14 +276,12 @@ export class GSDConfigOverlay {
|
|
|
273
276
|
}
|
|
274
277
|
}
|
|
275
278
|
render(width) {
|
|
276
|
-
if (this.cachedLines)
|
|
279
|
+
if (this.cachedLines && this.cachedWidth === width)
|
|
277
280
|
return this.cachedLines;
|
|
278
281
|
const t = this.theme;
|
|
279
|
-
const w = Math.max(
|
|
282
|
+
const w = Math.max(1, width);
|
|
283
|
+
const contentWidth = Math.max(1, w - 4);
|
|
280
284
|
const allLines = [];
|
|
281
|
-
// Header
|
|
282
|
-
allLines.push(t.bold(t.fg("accent", " GSD Configuration ")));
|
|
283
|
-
allLines.push(t.fg("muted", "\u2500".repeat(w)));
|
|
284
285
|
// Find max label width for alignment
|
|
285
286
|
let maxLabel = 0;
|
|
286
287
|
for (const section of this.sections) {
|
|
@@ -291,22 +292,27 @@ export class GSDConfigOverlay {
|
|
|
291
292
|
}
|
|
292
293
|
const labelPad = Math.min(maxLabel + 2, 24);
|
|
293
294
|
for (const section of this.sections) {
|
|
294
|
-
allLines.
|
|
295
|
+
if (allLines.length > 0)
|
|
296
|
+
allLines.push("");
|
|
295
297
|
allLines.push(t.bold(t.fg("accent", ` ${section.title}`)));
|
|
296
298
|
for (const row of section.rows) {
|
|
297
299
|
const label = t.fg("muted", ` ${row.label.padEnd(labelPad)}`);
|
|
298
300
|
const value = row.accent ? t.bold(row.value) : row.value;
|
|
299
|
-
allLines.push(truncateToWidth(`${label}${value}`,
|
|
301
|
+
allLines.push(truncateToWidth(`${label}${value}`, contentWidth));
|
|
300
302
|
}
|
|
301
303
|
}
|
|
302
|
-
allLines.push("");
|
|
303
|
-
allLines.push(t.fg("muted", ` ${"\u2500".repeat(w - 4)}`));
|
|
304
|
-
allLines.push(t.fg("muted", " esc/q close \u2502 \u2191\u2193/jk scroll \u2502 /gsd prefs to edit"));
|
|
305
304
|
// Apply scroll
|
|
306
|
-
const
|
|
305
|
+
const terminalRows = process.stdout.rows || 32;
|
|
306
|
+
const maxBodyRows = Math.max(1, Math.min(allLines.length, terminalRows - 12));
|
|
307
|
+
const maxScroll = Math.max(0, allLines.length - maxBodyRows);
|
|
307
308
|
this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
|
|
308
|
-
const visible = allLines.slice(this.scrollOffset);
|
|
309
|
-
|
|
310
|
-
|
|
309
|
+
const visible = allLines.slice(this.scrollOffset, this.scrollOffset + maxBodyRows);
|
|
310
|
+
const footer = renderKeyHints(t, ["esc/q close", "\u2191\u2193/jk scroll", "/gsd prefs to edit"], contentWidth);
|
|
311
|
+
this.cachedLines = renderDialogFrame(t, "GSD Configuration", visible, w, {
|
|
312
|
+
footer,
|
|
313
|
+
scroll: { offset: this.scrollOffset, visibleRows: maxBodyRows, totalRows: allLines.length },
|
|
314
|
+
});
|
|
315
|
+
this.cachedWidth = width;
|
|
316
|
+
return this.cachedLines;
|
|
311
317
|
}
|
|
312
318
|
}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { matchesKey, Key, truncateToWidth } from "@gsd/pi-tui";
|
|
5
5
|
import { formatTokenCount } from "./metrics.js";
|
|
6
|
-
import { renderProgressBar, rightAlign } from "./tui/render-kit.js";
|
|
6
|
+
import { renderDialogFrame, renderKeyHints, renderProgressBar, rightAlign } from "./tui/render-kit.js";
|
|
7
7
|
const SECTION_COLORS = ["accent", "success", "warning", "borderAccent", "text"];
|
|
8
8
|
export function getContextChartTotals(report) {
|
|
9
9
|
const systemTokens = report.systemSections.reduce((sum, section) => sum + section.tokens, 0);
|
|
@@ -47,6 +47,7 @@ export class GSDContextOverlay {
|
|
|
47
47
|
onClose;
|
|
48
48
|
report;
|
|
49
49
|
cachedLines;
|
|
50
|
+
cachedWidth;
|
|
50
51
|
scrollOffset = 0;
|
|
51
52
|
disposed = false;
|
|
52
53
|
constructor(tui, theme, report, onClose) {
|
|
@@ -57,6 +58,7 @@ export class GSDContextOverlay {
|
|
|
57
58
|
}
|
|
58
59
|
invalidate() {
|
|
59
60
|
this.cachedLines = undefined;
|
|
61
|
+
this.cachedWidth = undefined;
|
|
60
62
|
}
|
|
61
63
|
dispose() {
|
|
62
64
|
this.disposed = true;
|
|
@@ -92,21 +94,20 @@ export class GSDContextOverlay {
|
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
96
|
render(width) {
|
|
95
|
-
if (this.cachedLines)
|
|
97
|
+
if (this.cachedLines && this.cachedWidth === width)
|
|
96
98
|
return this.cachedLines;
|
|
97
99
|
const theme = this.theme;
|
|
98
|
-
const w = Math.max(
|
|
100
|
+
const w = Math.max(1, width);
|
|
101
|
+
const contentWidth = Math.max(1, w - 4);
|
|
99
102
|
const totals = getContextChartTotals(this.report);
|
|
100
103
|
const chartTotal = Math.max(totals.inContext, totals.estimated, 1);
|
|
101
104
|
const lines = [];
|
|
102
|
-
lines.push(theme.bold(theme.fg("accent", " Context Breakdown ")));
|
|
103
|
-
lines.push(theme.fg("muted", "─".repeat(w)));
|
|
104
105
|
if (this.report.modelLabel) {
|
|
105
|
-
lines.push(rightAlign(theme.fg("muted", "Model"), theme.fg("text", this.report.modelLabel),
|
|
106
|
+
lines.push(rightAlign(theme.fg("muted", "Model"), theme.fg("text", this.report.modelLabel), contentWidth));
|
|
106
107
|
}
|
|
107
108
|
lines.push("");
|
|
108
109
|
if (totals.window != null) {
|
|
109
|
-
const usageBarWidth = Math.max(
|
|
110
|
+
const usageBarWidth = Math.max(8, contentWidth - 28);
|
|
110
111
|
const usageBar = renderProgressBar(theme, totals.inContext, totals.window, usageBarWidth, {
|
|
111
112
|
filledColor: totals.inContext / totals.window > 0.85 ? "warning" : "accent",
|
|
112
113
|
});
|
|
@@ -115,7 +116,7 @@ export class GSDContextOverlay {
|
|
|
115
116
|
else {
|
|
116
117
|
lines.push(` ${theme.fg("muted", "Estimated")} ${theme.fg("text", formatTokenCount(chartTotal))}`);
|
|
117
118
|
}
|
|
118
|
-
const splitWidth = Math.max(
|
|
119
|
+
const splitWidth = Math.max(8, Math.floor((contentWidth - 8) / 2));
|
|
119
120
|
const systemBar = renderProgressBar(theme, totals.systemTokens, chartTotal, splitWidth, { filledColor: "accent" });
|
|
120
121
|
const convBar = renderProgressBar(theme, totals.conversationTokens, chartTotal, splitWidth, { filledColor: "success" });
|
|
121
122
|
lines.push("");
|
|
@@ -123,17 +124,17 @@ export class GSDContextOverlay {
|
|
|
123
124
|
lines.push(` ${theme.fg("success", "History")} ${convBar} ${theme.fg("muted", formatPct(totals.conversationTokens, chartTotal))}`);
|
|
124
125
|
lines.push("");
|
|
125
126
|
lines.push(theme.bold(theme.fg("accent", " System prompt")));
|
|
126
|
-
lines.push(...renderSectionBars(theme, this.report.systemSections, chartTotal,
|
|
127
|
+
lines.push(...renderSectionBars(theme, this.report.systemSections, chartTotal, contentWidth, 22));
|
|
127
128
|
lines.push("");
|
|
128
129
|
lines.push(theme.bold(theme.fg("accent", " Conversation")));
|
|
129
|
-
lines.push(...renderSectionBars(theme, this.report.conversationSections, chartTotal,
|
|
130
|
+
lines.push(...renderSectionBars(theme, this.report.conversationSections, chartTotal, contentWidth, 22));
|
|
130
131
|
lines.push("");
|
|
131
132
|
lines.push(theme.bold(theme.fg("accent", " Skills")));
|
|
132
133
|
const { skills } = this.report;
|
|
133
134
|
if (skills.available.length > 0) {
|
|
134
135
|
lines.push(` ${theme.fg("muted", "Available")} ${theme.fg("text", `${skills.available.length}`)}`);
|
|
135
136
|
const preview = skills.available.slice(0, 8).join(", ");
|
|
136
|
-
lines.push(truncateToWidth(` ${preview}${skills.available.length > 8 ? "…" : ""}`,
|
|
137
|
+
lines.push(truncateToWidth(` ${preview}${skills.available.length > 8 ? "…" : ""}`, contentWidth));
|
|
137
138
|
}
|
|
138
139
|
else {
|
|
139
140
|
lines.push(theme.fg("dim", " none in prompt"));
|
|
@@ -147,12 +148,17 @@ export class GSDContextOverlay {
|
|
|
147
148
|
lines.push("");
|
|
148
149
|
lines.push(theme.bold(theme.fg("accent", " Agents")));
|
|
149
150
|
lines.push(` ${theme.fg("muted", "Subagent spawns")} ${theme.fg("text", String(this.report.subagentSpawns))}`);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
const maxScroll = Math.max(0, lines.length - 24);
|
|
151
|
+
const terminalRows = process.stdout.rows || 32;
|
|
152
|
+
const maxBodyRows = Math.max(1, Math.min(lines.length, terminalRows - 12));
|
|
153
|
+
const maxScroll = Math.max(0, lines.length - maxBodyRows);
|
|
154
154
|
this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
|
|
155
|
-
|
|
155
|
+
const visible = lines.slice(this.scrollOffset, this.scrollOffset + maxBodyRows);
|
|
156
|
+
const footer = renderKeyHints(theme, ["esc/q close", "↑↓ scroll", "/gsd context --open"], contentWidth);
|
|
157
|
+
this.cachedLines = renderDialogFrame(theme, "Context Breakdown", visible, w, {
|
|
158
|
+
footer,
|
|
159
|
+
scroll: { offset: this.scrollOffset, visibleRows: maxBodyRows, totalRows: lines.length },
|
|
160
|
+
});
|
|
161
|
+
this.cachedWidth = width;
|
|
156
162
|
return this.cachedLines;
|
|
157
163
|
}
|
|
158
164
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Toggled with Ctrl+Alt+G (⌃⌥G on macOS), Ctrl+Shift+G fallback,
|
|
7
7
|
* or opened from /gsd status.
|
|
8
8
|
*/
|
|
9
|
-
import { truncateToWidth,
|
|
9
|
+
import { truncateToWidth, matchesKey, Key } from "@gsd/pi-tui";
|
|
10
10
|
import { deriveState } from "./state.js";
|
|
11
11
|
import { loadFile } from "./files.js";
|
|
12
12
|
import { isDbAvailable, getMilestoneSlices, getSliceTasks } from "./gsd-db.js";
|
|
@@ -21,6 +21,7 @@ import { estimateTimeRemaining } from "./auto-dashboard.js";
|
|
|
21
21
|
import { computeProgressScore } from "./progress-score.js";
|
|
22
22
|
import { runEnvironmentChecks } from "./doctor-environment.js";
|
|
23
23
|
import { formattedShortcutPair } from "./shortcut-defs.js";
|
|
24
|
+
import { renderDialogFrame, renderKeyHints } from "./tui/render-kit.js";
|
|
24
25
|
export function unitLabel(type) {
|
|
25
26
|
switch (type) {
|
|
26
27
|
case "discuss-milestone":
|
|
@@ -222,30 +223,20 @@ export class GSDDashboardOverlay {
|
|
|
222
223
|
}
|
|
223
224
|
const content = this.buildContentLines(width);
|
|
224
225
|
const viewportHeight = Math.max(5, process.stdout.rows ? process.stdout.rows - 8 : 24);
|
|
225
|
-
const
|
|
226
|
-
const visibleContentRows = Math.max(1, viewportHeight - chromeHeight);
|
|
226
|
+
const visibleContentRows = Math.max(1, viewportHeight - 4);
|
|
227
227
|
const maxScroll = Math.max(0, content.length - visibleContentRows);
|
|
228
228
|
this.scrollOffset = Math.min(this.scrollOffset, maxScroll);
|
|
229
229
|
const visibleContent = content.slice(this.scrollOffset, this.scrollOffset + visibleContentRows);
|
|
230
|
-
const
|
|
230
|
+
const contentWidth = Math.max(1, width - 4);
|
|
231
|
+
const footer = renderKeyHints(this.theme, ["↑↓ scroll", "g/G top/end", `Esc/${formattedShortcutPair("dashboard")} close`], contentWidth);
|
|
232
|
+
const lines = renderDialogFrame(this.theme, "GSD Dashboard", visibleContent, width, {
|
|
233
|
+
footer,
|
|
234
|
+
scroll: { offset: this.scrollOffset, visibleRows: visibleContentRows, totalRows: content.length },
|
|
235
|
+
});
|
|
231
236
|
this.cachedWidth = width;
|
|
232
237
|
this.cachedLines = lines;
|
|
233
238
|
return lines;
|
|
234
239
|
}
|
|
235
|
-
wrapInBox(inner, width) {
|
|
236
|
-
const th = this.theme;
|
|
237
|
-
const border = (s) => th.fg("borderAccent", s);
|
|
238
|
-
const innerWidth = width - 4;
|
|
239
|
-
const lines = [];
|
|
240
|
-
lines.push(border("╭" + "─".repeat(width - 2) + "╮"));
|
|
241
|
-
for (const line of inner) {
|
|
242
|
-
const truncated = truncateToWidth(line, innerWidth);
|
|
243
|
-
const padWidth = Math.max(0, innerWidth - visibleWidth(truncated));
|
|
244
|
-
lines.push(border("│") + " " + truncated + " ".repeat(padWidth) + " " + border("│"));
|
|
245
|
-
}
|
|
246
|
-
lines.push(border("╰" + "─".repeat(width - 2) + "╯"));
|
|
247
|
-
return lines;
|
|
248
|
-
}
|
|
249
240
|
buildContentLines(width) {
|
|
250
241
|
const th = this.theme;
|
|
251
242
|
const shellWidth = width - 4;
|
|
@@ -260,7 +251,6 @@ export class GSDDashboardOverlay {
|
|
|
260
251
|
const blank = () => row("");
|
|
261
252
|
const hr = () => row(th.fg("dim", "─".repeat(contentWidth)));
|
|
262
253
|
const centered = (content) => row(centerLine(content, contentWidth));
|
|
263
|
-
const title = th.fg("accent", th.bold("GSD Dashboard"));
|
|
264
254
|
const isRemote = !!this.dashData.remoteSession;
|
|
265
255
|
const status = this.dashData.active
|
|
266
256
|
? `${Date.now() % 2000 < 1000 ? th.fg("success", "●") : th.fg("dim", "○")} ${th.fg("success", "AUTO")}`
|
|
@@ -287,7 +277,7 @@ export class GSDDashboardOverlay {
|
|
|
287
277
|
else if (isRemote) {
|
|
288
278
|
elapsedParts = th.fg("dim", `since ${this.dashData.remoteSession.startedAt.replace("T", " ").slice(0, 19)}`);
|
|
289
279
|
}
|
|
290
|
-
lines.push(row(joinColumns(`${
|
|
280
|
+
lines.push(row(joinColumns(`${status}${worktreeTag}`, elapsedParts, contentWidth)));
|
|
291
281
|
// Progress score — traffic light indicator (#1221)
|
|
292
282
|
if (this.dashData.active || this.dashData.paused) {
|
|
293
283
|
const progressScore = computeProgressScore();
|
|
@@ -528,9 +518,6 @@ export class GSDDashboardOverlay {
|
|
|
528
518
|
}
|
|
529
519
|
}
|
|
530
520
|
}
|
|
531
|
-
lines.push(blank());
|
|
532
|
-
lines.push(hr());
|
|
533
|
-
lines.push(centered(th.fg("dim", `↑↓ scroll · g/G top/end · Esc/${formattedShortcutPair("dashboard")} close`)));
|
|
534
521
|
return lines;
|
|
535
522
|
}
|
|
536
523
|
renderProgressRow(label, done, total, color, width) {
|