@opengsd/gsd-pi 1.4.0-dev.c18009cd → 1.5.0-dev.4fb2d460
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 +10 -10
- package/dist/resources/.managed-resources-content-hash +1 -1
- package/dist/resources/extensions/ask-user-questions.js +1 -1
- package/dist/resources/extensions/gsd/auto/closeout.js +97 -5
- package/dist/resources/extensions/gsd/auto/orchestrator.js +4 -3
- package/dist/resources/extensions/gsd/auto/pre-dispatch.js +6 -3
- package/dist/resources/extensions/gsd/auto/unit-phase.js +5 -9
- package/dist/resources/extensions/gsd/auto-artifact-paths.js +12 -3
- package/dist/resources/extensions/gsd/auto-direct-dispatch.js +11 -7
- package/dist/resources/extensions/gsd/auto-dispatch.js +16 -2
- package/dist/resources/extensions/gsd/auto-recovery.js +50 -6
- package/dist/resources/extensions/gsd/auto-start.js +4 -3
- package/dist/resources/extensions/gsd/auto-worktree-branch-lifecycle.js +189 -0
- package/dist/resources/extensions/gsd/auto-worktree-cleanup.js +133 -0
- package/dist/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.js +35 -0
- package/dist/resources/extensions/gsd/auto-worktree-creation.js +130 -0
- package/dist/resources/extensions/gsd/auto-worktree-entry.js +118 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-already-merged.js +98 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-branch-head.js +52 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-cleanup.js +87 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-code-changes.js +46 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-db-ready.js +68 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-integration-branch.js +51 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-message.js +106 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-pre-teardown.js +64 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge-stash.js +168 -0
- package/dist/resources/extensions/gsd/auto-worktree-merge.js +302 -0
- package/dist/resources/extensions/gsd/auto-worktree-milestone-shelter.js +119 -0
- package/dist/resources/extensions/gsd/auto-worktree-path-resolution.js +5 -0
- package/dist/resources/extensions/gsd/auto-worktree-path-utils.js +5 -0
- package/dist/resources/extensions/gsd/auto-worktree-resource-version.js +41 -0
- package/dist/resources/extensions/gsd/auto-worktree-runtime-cleanup.js +99 -0
- package/dist/resources/extensions/gsd/auto-worktree-session-registry.js +57 -0
- package/dist/resources/extensions/gsd/auto-worktree-sync.js +249 -0
- package/dist/resources/extensions/gsd/auto-worktree-teardown.js +120 -0
- package/dist/resources/extensions/gsd/auto-worktree.js +20 -2073
- package/dist/resources/extensions/gsd/auto.js +9 -3
- package/dist/resources/extensions/gsd/bootstrap/dynamic-tools.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/register-hooks.js +20 -2
- package/dist/resources/extensions/gsd/bootstrap/system-context.js +1 -1
- package/dist/resources/extensions/gsd/bootstrap/tool-call-loop-guard.js +185 -27
- package/dist/resources/extensions/gsd/codebase-generator.js +7 -1
- package/dist/resources/extensions/gsd/commands-handlers.js +1 -1
- package/dist/resources/extensions/gsd/commands-workflow-templates.js +3 -3
- package/dist/resources/extensions/gsd/db/queries.js +9 -9
- package/dist/resources/extensions/gsd/db/writers/cascades.js +20 -2
- package/dist/resources/extensions/gsd/doctor-engine-checks.js +93 -11
- package/dist/resources/extensions/gsd/flat-phase-migration.js +32 -3
- package/dist/resources/extensions/gsd/forensics.js +1 -1
- package/dist/resources/extensions/gsd/git-conflict-resolve.js +2 -2
- package/dist/resources/extensions/gsd/git-service.js +45 -0
- package/dist/resources/extensions/gsd/gsd-db.js +23 -11
- package/dist/resources/extensions/gsd/guided-flow.js +22 -17
- package/dist/resources/extensions/gsd/markdown-renderer.js +15 -3
- package/dist/resources/extensions/gsd/md-importer.js +89 -23
- package/dist/resources/extensions/gsd/migration-auto-check.js +30 -3
- package/dist/resources/extensions/gsd/milestone-merge-transaction.js +11 -0
- package/dist/resources/extensions/gsd/milestone-settlement.js +1 -1
- package/dist/resources/extensions/gsd/parallel-merge.js +1 -1
- package/dist/resources/extensions/gsd/parallel-orchestrator.js +3 -1
- package/dist/resources/extensions/gsd/paths.js +17 -3
- package/dist/resources/extensions/gsd/preferences-skills.js +10 -16
- package/dist/resources/extensions/gsd/preferences-types.js +1 -0
- package/dist/resources/extensions/gsd/preferences-validation.js +82 -0
- package/dist/resources/extensions/gsd/preferences.js +20 -0
- package/dist/resources/extensions/gsd/prompts/system.md +6 -6
- package/dist/resources/extensions/gsd/quick.js +12 -3
- package/dist/resources/extensions/gsd/skill-discovery.js +36 -23
- package/dist/resources/extensions/gsd/slice-parallel-orchestrator.js +2 -1
- package/dist/resources/extensions/gsd/state/derive/from-db.js +88 -153
- package/dist/resources/extensions/gsd/tool-contract.js +14 -0
- package/dist/resources/extensions/gsd/tools/reopen-slice.js +5 -0
- package/dist/resources/extensions/gsd/tools/reopen-task.js +13 -5
- package/dist/resources/extensions/gsd/unit-registry.js +12 -2
- package/dist/resources/extensions/gsd/unmerged-milestone-guard.js +1 -1
- package/dist/resources/extensions/gsd/validation-block-guard.js +2 -1
- package/dist/resources/extensions/gsd/workspace-git-preflight.js +2 -2
- package/dist/resources/extensions/gsd/worktree-command.js +1 -1
- package/dist/resources/extensions/gsd/worktree-lifecycle.js +14 -9
- package/dist/resources/extensions/gsd/worktree-reentry.js +2 -1
- package/dist/resources/extensions/shared/interview-ui.js +62 -9
- 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 +8 -8
- 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/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 +8 -8
- 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/dist/web/standalone/node_modules/@gsd/native/package.json +1 -1
- package/dist/web/standalone/node_modules/node-pty/build/Makefile +1 -1
- package/integrations/hermes/open_gsd_hermes/gsd_client.py +24 -35
- package/integrations/hermes/tests/test_gsd_client_timeout.py +4 -4
- package/package.json +6 -6
- 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/dist/export-html/template.js +53 -4
- package/packages/gsd-agent-core/package.json +5 -5
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.d.ts.map +1 -1
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js +3 -2
- package/packages/gsd-agent-modes/dist/modes/interactive/controllers/chat-controller.js.map +1 -1
- package/packages/gsd-agent-modes/package.json +7 -7
- package/packages/mcp-server/package.json +4 -4
- package/packages/native/package.json +1 -1
- package/packages/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/packages/pi-agent-core/dist/agent-loop.js +14 -9
- 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/index.d.ts +1 -0
- package/packages/pi-ai/dist/index.d.ts.map +1 -1
- package/packages/pi-ai/dist/index.js +1 -0
- package/packages/pi-ai/dist/index.js.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.d.ts.map +1 -1
- package/packages/pi-ai/dist/providers/transform-messages.js +7 -3
- package/packages/pi-ai/dist/providers/transform-messages.js.map +1 -1
- package/packages/pi-ai/dist/tool-result-content.d.ts +3 -0
- package/packages/pi-ai/dist/tool-result-content.d.ts.map +1 -0
- package/packages/pi-ai/dist/tool-result-content.js +62 -0
- package/packages/pi-ai/dist/tool-result-content.js.map +1 -0
- package/packages/pi-ai/dist/types.d.ts +8 -20
- 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/dist/core/package-manager.d.ts +9 -0
- package/packages/pi-coding-agent/dist/core/package-manager.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/package-manager.js +74 -53
- package/packages/pi-coding-agent/dist/core/package-manager.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts +6 -0
- package/packages/pi-coding-agent/dist/core/resource-loader.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/resource-loader.js +30 -2
- package/packages/pi-coding-agent/dist/core/resource-loader.js.map +1 -1
- package/packages/pi-coding-agent/dist/core/skill-directories.d.ts +66 -0
- package/packages/pi-coding-agent/dist/core/skill-directories.d.ts.map +1 -0
- package/packages/pi-coding-agent/dist/core/skill-directories.js +138 -0
- package/packages/pi-coding-agent/dist/core/skill-directories.js.map +1 -0
- package/packages/pi-coding-agent/dist/core/skills.d.ts +4 -1
- package/packages/pi-coding-agent/dist/core/skills.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/core/skills.js +4 -1
- package/packages/pi-coding-agent/dist/core/skills.js.map +1 -1
- package/packages/pi-coding-agent/dist/index.d.ts +1 -0
- package/packages/pi-coding-agent/dist/index.d.ts.map +1 -1
- package/packages/pi-coding-agent/dist/index.js +1 -0
- package/packages/pi-coding-agent/dist/index.js.map +1 -1
- package/packages/pi-coding-agent/package.json +7 -7
- package/packages/pi-tui/package.json +2 -2
- package/packages/rpc-client/package.json +2 -2
- package/pkg/dist/core/export-html/template.js +53 -4
- package/pkg/package.json +1 -1
- package/src/resources/extensions/ask-user-questions.ts +1 -1
- package/src/resources/extensions/gsd/auto/closeout.ts +114 -7
- package/src/resources/extensions/gsd/auto/orchestrator.ts +4 -3
- package/src/resources/extensions/gsd/auto/pre-dispatch.ts +6 -3
- package/src/resources/extensions/gsd/auto/unit-phase.ts +5 -9
- package/src/resources/extensions/gsd/auto-artifact-paths.ts +12 -3
- package/src/resources/extensions/gsd/auto-direct-dispatch.ts +13 -7
- package/src/resources/extensions/gsd/auto-dispatch.ts +18 -2
- package/src/resources/extensions/gsd/auto-recovery.ts +50 -6
- package/src/resources/extensions/gsd/auto-start.ts +5 -3
- package/src/resources/extensions/gsd/auto-worktree-branch-lifecycle.ts +237 -0
- package/src/resources/extensions/gsd/auto-worktree-cleanup.ts +166 -0
- package/src/resources/extensions/gsd/auto-worktree-conflict-auto-resolve.ts +37 -0
- package/src/resources/extensions/gsd/auto-worktree-creation.ts +171 -0
- package/src/resources/extensions/gsd/auto-worktree-entry.ts +154 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-already-merged.ts +161 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-branch-head.ts +83 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-cleanup.ts +132 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-code-changes.ts +71 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-db-ready.ts +112 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-integration-branch.ts +99 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-message.ts +166 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-pre-teardown.ts +93 -0
- package/src/resources/extensions/gsd/auto-worktree-merge-stash.ts +213 -0
- package/src/resources/extensions/gsd/auto-worktree-merge.ts +391 -0
- package/src/resources/extensions/gsd/auto-worktree-milestone-shelter.ts +159 -0
- package/src/resources/extensions/gsd/auto-worktree-path-resolution.ts +6 -0
- package/src/resources/extensions/gsd/auto-worktree-path-utils.ts +10 -0
- package/src/resources/extensions/gsd/auto-worktree-resource-version.ts +44 -0
- package/src/resources/extensions/gsd/auto-worktree-runtime-cleanup.ts +119 -0
- package/src/resources/extensions/gsd/auto-worktree-session-registry.ts +71 -0
- package/src/resources/extensions/gsd/auto-worktree-sync.ts +370 -0
- package/src/resources/extensions/gsd/auto-worktree-teardown.ts +161 -0
- package/src/resources/extensions/gsd/auto-worktree.ts +69 -2429
- package/src/resources/extensions/gsd/auto.ts +11 -17
- package/src/resources/extensions/gsd/bootstrap/dynamic-tools.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/register-hooks.ts +20 -2
- package/src/resources/extensions/gsd/bootstrap/system-context.ts +1 -1
- package/src/resources/extensions/gsd/bootstrap/tool-call-loop-guard.ts +218 -27
- package/src/resources/extensions/gsd/codebase-generator.ts +7 -1
- package/src/resources/extensions/gsd/commands-handlers.ts +1 -1
- package/src/resources/extensions/gsd/commands-workflow-templates.ts +3 -3
- package/src/resources/extensions/gsd/db/queries.ts +9 -9
- package/src/resources/extensions/gsd/db/writers/cascades.ts +23 -1
- package/src/resources/extensions/gsd/doctor-engine-checks.ts +109 -10
- package/src/resources/extensions/gsd/flat-phase-migration.ts +34 -3
- package/src/resources/extensions/gsd/forensics.ts +1 -1
- package/src/resources/extensions/gsd/git-conflict-resolve.ts +2 -2
- package/src/resources/extensions/gsd/git-service.ts +53 -0
- package/src/resources/extensions/gsd/gsd-db.ts +33 -11
- package/src/resources/extensions/gsd/guided-flow.ts +26 -18
- package/src/resources/extensions/gsd/markdown-renderer.ts +15 -3
- package/src/resources/extensions/gsd/md-importer.ts +93 -22
- package/src/resources/extensions/gsd/migration-auto-check.ts +32 -3
- package/src/resources/extensions/gsd/milestone-merge-transaction.ts +15 -0
- package/src/resources/extensions/gsd/milestone-settlement.ts +1 -1
- package/src/resources/extensions/gsd/parallel-merge.ts +1 -1
- package/src/resources/extensions/gsd/parallel-orchestrator.ts +3 -1
- package/src/resources/extensions/gsd/paths.ts +21 -3
- package/src/resources/extensions/gsd/preferences-skills.ts +10 -16
- package/src/resources/extensions/gsd/preferences-types.ts +30 -0
- package/src/resources/extensions/gsd/preferences-validation.ts +69 -0
- package/src/resources/extensions/gsd/preferences.ts +20 -0
- package/src/resources/extensions/gsd/prompts/system.md +6 -6
- package/src/resources/extensions/gsd/quick.ts +11 -3
- package/src/resources/extensions/gsd/skill-discovery.ts +47 -23
- package/src/resources/extensions/gsd/slice-parallel-orchestrator.ts +3 -1
- package/src/resources/extensions/gsd/state/derive/from-db.ts +201 -157
- package/src/resources/extensions/gsd/tests/auto-artifact-paths.test.ts +169 -1
- package/src/resources/extensions/gsd/tests/auto-loop-no-copy-artifacts.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-recovery.test.ts +57 -0
- package/src/resources/extensions/gsd/tests/auto-start-clean-runtime-db-gated.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-warning-noise-regression.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/auto-worktree-auto-resolve.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-already-merged.test.ts +177 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-branch-head.test.ts +118 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-cleanup.test.ts +115 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-code-changes.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-db-ready.test.ts +140 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-integration-branch.test.ts +123 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-message.test.ts +114 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-pre-teardown.test.ts +84 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-merge-stash.test.ts +70 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-milestone-shelter.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-registry.test.ts +6 -6
- package/src/resources/extensions/gsd/tests/auto-worktree-resource-version.test.ts +59 -0
- package/src/resources/extensions/gsd/tests/auto-worktree-untracked-content.test.ts +3 -1
- package/src/resources/extensions/gsd/tests/codebase-generator.test.ts +22 -0
- package/src/resources/extensions/gsd/tests/completed-units-metrics-sync.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/derive-state-db.test.ts +4 -0
- package/src/resources/extensions/gsd/tests/doctor-scope-db-unavailable.test.ts +174 -0
- package/src/resources/extensions/gsd/tests/fast-forward-reused-milestone-branch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/flat-phase-migration.test.ts +71 -1
- package/src/resources/extensions/gsd/tests/flat-phase-renderer.test.ts +25 -1
- package/src/resources/extensions/gsd/tests/gsd-db.test.ts +40 -0
- package/src/resources/extensions/gsd/tests/import-completion-lost-update.test.ts +196 -0
- package/src/resources/extensions/gsd/tests/integration/all-milestones-complete-merge.test.ts +4 -6
- package/src/resources/extensions/gsd/tests/integration/auto-stash-merge.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/integration/auto-worktree-milestone-merge.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/integration/auto-worktree.test.ts +7 -8
- package/src/resources/extensions/gsd/tests/integration/feature-branch-lifecycle-integration.test.ts +2 -5
- package/src/resources/extensions/gsd/tests/integration/git-service.test.ts +76 -0
- package/src/resources/extensions/gsd/tests/integration/merge-cwd-restore.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/merge-preserve-worktree-on-preteardown-error.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/integration/merge-strategy-regular.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/integration/milestone-transition-worktree.test.ts +5 -7
- package/src/resources/extensions/gsd/tests/integration/workspace-collapse-integration.test.ts +2 -4
- package/src/resources/extensions/gsd/tests/journal-integration.test.ts +16 -15
- package/src/resources/extensions/gsd/tests/merge-closeout-consistency-gate.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/merge-db-cycle.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/merge-self-branch-guard.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/migration-auto-check.test.ts +91 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-stash-restore.test.ts +439 -0
- package/src/resources/extensions/gsd/tests/milestone-merge-transaction.test.ts +24 -0
- package/src/resources/extensions/gsd/tests/none-mode-gates.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/originalbase-path-comparison.test.ts +3 -3
- package/src/resources/extensions/gsd/tests/parallel-worker-lock-contention.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/preferences-worktree-sync.test.ts +1 -4
- package/src/resources/extensions/gsd/tests/preferences.test.ts +19 -0
- package/src/resources/extensions/gsd/tests/prefs-wizard-coverage.test.ts +5 -0
- package/src/resources/extensions/gsd/tests/reopen-slice.test.ts +52 -0
- package/src/resources/extensions/gsd/tests/runtime-invariant-modules.test.ts +20 -0
- package/src/resources/extensions/gsd/tests/skill-discovery.test.ts +46 -0
- package/src/resources/extensions/gsd/tests/stale-worktree-cwd.test.ts +3 -5
- package/src/resources/extensions/gsd/tests/stash-pop-gsd-conflict.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/stash-queued-context-files.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/steer-worktree-path.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/sync-worktree-skip-current.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/system-flat-phase-layout.test.ts +33 -0
- package/src/resources/extensions/gsd/tests/teardown-chdir-failure-clears-registry.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/teardown-cleanup-parity.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/teardown-failure-clears-registry.test.ts +4 -4
- package/src/resources/extensions/gsd/tests/tool-call-loop-guard.test.ts +196 -0
- package/src/resources/extensions/gsd/tests/uat-stuck-loop-orphaned-worktree.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/unit-registry.test.ts +26 -1
- package/src/resources/extensions/gsd/tests/worktree-db-integration.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-db-respawn-truncation.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-db-same-file.test.ts +1 -3
- package/src/resources/extensions/gsd/tests/worktree-expected-warnings.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-git-pathspec.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-main-branch.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-preferences-sync.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-reentry.test.ts +2 -1
- package/src/resources/extensions/gsd/tests/worktree-sync-milestones.test.ts +5 -2
- package/src/resources/extensions/gsd/tests/worktree-sync-overwrite-loop.test.ts +1 -1
- package/src/resources/extensions/gsd/tests/worktree-sync-tasks.test.ts +1 -1
- package/src/resources/extensions/gsd/tool-contract.ts +29 -0
- package/src/resources/extensions/gsd/tools/reopen-slice.ts +5 -0
- package/src/resources/extensions/gsd/tools/reopen-task.ts +13 -5
- package/src/resources/extensions/gsd/unit-registry.ts +16 -2
- package/src/resources/extensions/gsd/unmerged-milestone-guard.ts +1 -1
- package/src/resources/extensions/gsd/validation-block-guard.ts +2 -1
- package/src/resources/extensions/gsd/workspace-git-preflight.ts +2 -2
- package/src/resources/extensions/gsd/worktree-command.ts +1 -1
- package/src/resources/extensions/gsd/worktree-lifecycle.ts +19 -15
- package/src/resources/extensions/gsd/worktree-reentry.ts +2 -1
- package/src/resources/extensions/shared/interview-ui.ts +58 -11
- package/src/resources/extensions/shared/tests/interview-ui-border.test.ts +32 -0
- /package/dist/web/standalone/.next/static/{L2UMqXELiDH3oz-7yguXp → gXoWec4UNqcR0tkuHwYCr}/_buildManifest.js +0 -0
- /package/dist/web/standalone/.next/static/{L2UMqXELiDH3oz-7yguXp → gXoWec4UNqcR0tkuHwYCr}/_ssgManifest.js +0 -0
|
@@ -85,6 +85,18 @@ export interface UnitWorkflowDispatchReadinessInput {
|
|
|
85
85
|
activeTools?: string[];
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
+
export interface WorkflowDispatchModelContext {
|
|
89
|
+
provider?: string;
|
|
90
|
+
baseUrl?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface UnitWorkflowDispatchReadinessForModelInput
|
|
94
|
+
extends Omit<UnitWorkflowDispatchReadinessInput, "provider" | "authMode" | "baseUrl"> {
|
|
95
|
+
model?: WorkflowDispatchModelContext | null;
|
|
96
|
+
fallbackModel?: WorkflowDispatchModelContext | null;
|
|
97
|
+
getProviderAuthMode?: (provider: string) => WorkflowCapabilityOptions["authMode"] | undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
88
100
|
export function compileUnitContextContract(unitType: string): UnitContextContractResult {
|
|
89
101
|
const manifest = resolveManifest(unitType);
|
|
90
102
|
if (!manifest) {
|
|
@@ -115,6 +127,23 @@ export function getUnitWorkflowDispatchReadinessError(
|
|
|
115
127
|
);
|
|
116
128
|
}
|
|
117
129
|
|
|
130
|
+
export function getUnitWorkflowDispatchReadinessErrorForModel(
|
|
131
|
+
input: UnitWorkflowDispatchReadinessForModelInput,
|
|
132
|
+
): string | null {
|
|
133
|
+
const provider = input.model?.provider ?? input.fallbackModel?.provider;
|
|
134
|
+
const baseUrl = input.model?.baseUrl ?? input.fallbackModel?.baseUrl;
|
|
135
|
+
return getUnitWorkflowDispatchReadinessError({
|
|
136
|
+
provider,
|
|
137
|
+
unitType: input.unitType,
|
|
138
|
+
projectRoot: input.projectRoot,
|
|
139
|
+
env: input.env,
|
|
140
|
+
surface: input.surface,
|
|
141
|
+
authMode: provider ? input.getProviderAuthMode?.(provider) : undefined,
|
|
142
|
+
baseUrl,
|
|
143
|
+
activeTools: input.activeTools,
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
118
147
|
export function compileUnitToolContract(unitType: string): ToolContractResult {
|
|
119
148
|
const manifest = resolveManifest(unitType);
|
|
120
149
|
const surfaceContract = getUnitToolSurfaceContract(unitType);
|
|
@@ -5,6 +5,11 @@
|
|
|
5
5
|
* tasks back to "pending". This is intentional — if you're reopening a
|
|
6
6
|
* slice, you're re-doing the work. Partial resets create ambiguous state.
|
|
7
7
|
*
|
|
8
|
+
* Also recovers a desynced slice (#1205): when a UAT→planning fallback leaves
|
|
9
|
+
* the slice open (e.g. "pending") but its tasks still "complete", this clears
|
|
10
|
+
* that state so the planner can re-plan without hitting "already complete"
|
|
11
|
+
* rejections.
|
|
12
|
+
*
|
|
8
13
|
* The parent milestone must still be open (not complete).
|
|
9
14
|
*/
|
|
10
15
|
|
|
@@ -24,8 +24,8 @@ import { writeManifest } from "../workflow-manifest.js";
|
|
|
24
24
|
import { appendEvent } from "../workflow-events.js";
|
|
25
25
|
import { logWarning } from "../workflow-logger.js";
|
|
26
26
|
import { existsSync, unlinkSync } from "node:fs";
|
|
27
|
-
import { join } from "node:path";
|
|
28
|
-
import { resolveTasksDir, clearPathCache } from "../paths.js";
|
|
27
|
+
import { join, basename, dirname } from "node:path";
|
|
28
|
+
import { resolveTasksDir, resolveSlicePath, clearPathCache } from "../paths.js";
|
|
29
29
|
|
|
30
30
|
export interface ReopenTaskParams {
|
|
31
31
|
milestoneId: string;
|
|
@@ -106,10 +106,18 @@ export async function handleReopenTask(
|
|
|
106
106
|
// ── Clean up stale filesystem artifacts (M12 fix) ────────────────────────
|
|
107
107
|
// Without this, the DB-filesystem reconciler sees the SUMMARY.md and
|
|
108
108
|
// auto-corrects the task back to "complete", making reopen a no-op (#3161).
|
|
109
|
+
// Legacy layout keeps the summary under a tasks/ subdir; flat-phase writes
|
|
110
|
+
// TID-SUMMARY.md directly in the phase dir. A tasks/ subdir may still exist
|
|
111
|
+
// in flat-phase for auxiliary artifacts — its mere existence must NOT redirect
|
|
112
|
+
// summary cleanup into tasks/ (#1208).
|
|
109
113
|
try {
|
|
110
|
-
const
|
|
111
|
-
if (
|
|
112
|
-
const
|
|
114
|
+
const slicePath = resolveSlicePath(basePath, params.milestoneId, params.sliceId);
|
|
115
|
+
if (slicePath) {
|
|
116
|
+
const isLegacySlice = basename(dirname(slicePath)) === "slices";
|
|
117
|
+
const summaryDir = isLegacySlice
|
|
118
|
+
? (resolveTasksDir(basePath, params.milestoneId, params.sliceId) ?? slicePath)
|
|
119
|
+
: slicePath;
|
|
120
|
+
const summaryPath = join(summaryDir, `${params.taskId}-SUMMARY.md`);
|
|
113
121
|
if (existsSync(summaryPath)) unlinkSync(summaryPath);
|
|
114
122
|
}
|
|
115
123
|
} catch (cleanupErr) {
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
// Not yet declared here (remaining ADR-033 steps): the manifest data
|
|
22
22
|
// (`UNIT_MANIFESTS` stays in unit-context-manifest.ts, already type-enforced
|
|
23
23
|
// against the registry's `UnitType`). Prompt-template association is declared
|
|
24
|
-
// for direct one-template units
|
|
25
|
-
// with
|
|
24
|
+
// for direct one-template units and verified conditional template sets;
|
|
25
|
+
// composition logic stays with prompt builders.
|
|
26
26
|
|
|
27
27
|
import type { CanonicalWorkflowToolName } from "@opengsd/contracts";
|
|
28
28
|
import { BROWSER_CONTRACT_TOOL_NAMES } from "../shared/browser-contract.js";
|
|
@@ -68,6 +68,11 @@ export interface UnitDescriptor {
|
|
|
68
68
|
* verified prompt associations.
|
|
69
69
|
*/
|
|
70
70
|
readonly promptTemplate?: string;
|
|
71
|
+
/**
|
|
72
|
+
* Prompt template ids a conditional or composite builder may choose from.
|
|
73
|
+
* Omitted unless every listed association is verified against the builder.
|
|
74
|
+
*/
|
|
75
|
+
readonly promptTemplates?: readonly string[];
|
|
71
76
|
/** `null` = the unit has no scoped gsd-tool contract. */
|
|
72
77
|
readonly toolContract: UnitToolSurfaceContract | null;
|
|
73
78
|
}
|
|
@@ -137,6 +142,7 @@ export const UNIT_REGISTRY = {
|
|
|
137
142
|
kind: "primary",
|
|
138
143
|
scopeClass: "standard",
|
|
139
144
|
phaseChain: ["discuss", "planning"],
|
|
145
|
+
promptTemplates: ["discuss", "discuss-headless", "guided-discuss-milestone"],
|
|
140
146
|
toolContract: {
|
|
141
147
|
allowedGsdTools: [
|
|
142
148
|
"gsd_summary_save",
|
|
@@ -526,3 +532,11 @@ export function getUnitPhaseChain(unitType: string): readonly GSDModelPhaseKey[]
|
|
|
526
532
|
export function getUnitPromptTemplate(unitType: string): string | undefined {
|
|
527
533
|
return getUnitDescriptor(unitType)?.promptTemplate;
|
|
528
534
|
}
|
|
535
|
+
|
|
536
|
+
/** Prompt template ids for any verified direct or conditional prompt builder. */
|
|
537
|
+
export function getUnitPromptTemplates(unitType: string): readonly string[] {
|
|
538
|
+
const descriptor = getUnitDescriptor(unitType);
|
|
539
|
+
if (!descriptor) return [];
|
|
540
|
+
if (descriptor.promptTemplates) return descriptor.promptTemplates;
|
|
541
|
+
return descriptor.promptTemplate ? [descriptor.promptTemplate] : [];
|
|
542
|
+
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
nativeDiffNumstat,
|
|
10
10
|
nativeIsAncestor,
|
|
11
11
|
} from "./native-git-bridge.js";
|
|
12
|
-
import { autoWorktreeBranch } from "./auto-worktree.js";
|
|
12
|
+
import { autoWorktreeBranch } from "./auto-worktree-branch-lifecycle.js";
|
|
13
13
|
import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
|
14
14
|
import { getAllMilestones } from "./gsd-db.js";
|
|
15
15
|
import { resolveMilestoneIntegrationBranch } from "./git-service.js";
|
|
@@ -3,7 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
import { existsSync } from "node:fs";
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { isInAutoWorktree } from "./auto-worktree-entry.js";
|
|
7
|
+
import { getAutoWorktreePath } from "./auto-worktree-path-resolution.js";
|
|
7
8
|
import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
|
8
9
|
import { refreshWorkflowDatabaseFromDisk } from "./db-workspace.js";
|
|
9
10
|
import { getIsolationMode } from "./preferences.js";
|
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
|
|
4
4
|
import { existsSync, realpathSync } from "node:fs";
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { isSafeToAutoResolve } from "./auto-worktree-conflict-auto-resolve.js";
|
|
7
|
+
import { getAutoWorktreePath } from "./auto-worktree-path-resolution.js";
|
|
8
8
|
import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
|
9
9
|
import {
|
|
10
10
|
listMergeStateBlockers,
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
import type { ExtensionAPI, ExtensionCommandContext } from "@gsd/pi-coding-agent";
|
|
14
14
|
import { loadPrompt } from "./prompt-loader.js";
|
|
15
15
|
import { autoCommitCurrentBranch, getMainBranch, resolveGitHeadPath, nudgeGitBranchCache } from "./worktree.js";
|
|
16
|
-
import { runWorktreePostCreateHook } from "./
|
|
16
|
+
import { runWorktreePostCreateHook } from "./worktree-post-create-hook.js";
|
|
17
17
|
import { showConfirm } from "../shared/tui.js";
|
|
18
18
|
import { gsdRoot, milestonesDir, resolveGsdPathContract } from "./paths.js";
|
|
19
19
|
import {
|
|
@@ -68,19 +68,21 @@ import {
|
|
|
68
68
|
getCurrentBranch,
|
|
69
69
|
} from "./worktree.js";
|
|
70
70
|
import { nativeCheckoutBranch } from "./native-git-bridge.js";
|
|
71
|
-
// ADR-016 phase 2 / C2 (#5625):
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
71
|
+
// ADR-016 phase 2 / C2 (#5625): lifecycle uses focused auto-worktree
|
|
72
|
+
// modules instead of the legacy compatibility barrel. Branch, entry/path,
|
|
73
|
+
// creation, and teardown primitives are still implementation-level seams for
|
|
74
|
+
// Lifecycle; tests vary them through `WorktreeLifecycleTestOverrides` below.
|
|
75
75
|
import {
|
|
76
76
|
autoWorktreeBranch,
|
|
77
|
-
createAutoWorktree,
|
|
78
|
-
enterAutoWorktree,
|
|
79
77
|
enterBranchModeForMilestone,
|
|
80
|
-
|
|
78
|
+
} from "./auto-worktree-branch-lifecycle.js";
|
|
79
|
+
import { createAutoWorktree } from "./auto-worktree-creation.js";
|
|
80
|
+
import {
|
|
81
|
+
enterAutoWorktree,
|
|
81
82
|
isInAutoWorktree,
|
|
82
|
-
|
|
83
|
-
} from "./auto-worktree.js";
|
|
83
|
+
} from "./auto-worktree-entry.js";
|
|
84
|
+
import { getAutoWorktreePath } from "./auto-worktree-path-resolution.js";
|
|
85
|
+
import { teardownAutoWorktree } from "./auto-worktree-teardown.js";
|
|
84
86
|
import { resolveRoadmapForMilestoneMerge } from "./milestone-merge-roadmap.js";
|
|
85
87
|
import type { MilestoneMergeTransactionRunner } from "./milestone-merge-transaction.js";
|
|
86
88
|
|
|
@@ -353,7 +355,7 @@ export interface MergeContext {
|
|
|
353
355
|
originalBasePath: string;
|
|
354
356
|
/**
|
|
355
357
|
* Current worktree path or project root when in branch mode. Used as the
|
|
356
|
-
* cwd anchor for
|
|
358
|
+
* cwd anchor for the milestone merge transaction and the source for
|
|
357
359
|
* `Projection.finalizeProjectionForMerge`.
|
|
358
360
|
*/
|
|
359
361
|
worktreeBasePath: string;
|
|
@@ -381,7 +383,8 @@ export interface MergeStandaloneResult {
|
|
|
381
383
|
pushed: boolean;
|
|
382
384
|
/**
|
|
383
385
|
* Commit message produced by the squash merge, if available. Forwarded
|
|
384
|
-
* from
|
|
386
|
+
* from the milestone merge transaction. Only populated when
|
|
387
|
+
* `merged === true`.
|
|
385
388
|
*/
|
|
386
389
|
commitMessage?: string;
|
|
387
390
|
}
|
|
@@ -1373,8 +1376,9 @@ function _mergeBranchModeImpl(
|
|
|
1373
1376
|
* **CWD anchor**: anchors `process.cwd()` at `originalBasePath` before
|
|
1374
1377
|
* non-worktree merge paths to mirror the single-loop guard against ENOENT
|
|
1375
1378
|
* after teardown (de73fb43d). Worktree-mode merge paths keep the real
|
|
1376
|
-
* worktree as cwd because
|
|
1377
|
-
*
|
|
1379
|
+
* worktree as cwd because the default milestone merge transaction delegates
|
|
1380
|
+
* to the legacy merge primitive, which infers source worktree state from
|
|
1381
|
+
* `process.cwd()`. Best-effort; silent on failure.
|
|
1378
1382
|
*
|
|
1379
1383
|
* **Failure handling**: `MergeConflictError` and other unrecoverable errors
|
|
1380
1384
|
* propagate to the caller. The caller is responsible for any state restore
|
|
@@ -1475,8 +1479,8 @@ export function mergeMilestoneStandalone(
|
|
|
1475
1479
|
|
|
1476
1480
|
// Set cwd to the correct anchor before dispatching to mode implementations.
|
|
1477
1481
|
// Worktree mode / in-worktree override must run from the live worktree so
|
|
1478
|
-
//
|
|
1479
|
-
// the original project root. Best-effort for synthetic test paths.
|
|
1482
|
+
// The default merge transaction can find worktree-local state; branch mode
|
|
1483
|
+
// runs from the original project root. Best-effort for synthetic test paths.
|
|
1480
1484
|
const targetCwd = mode === "worktree" || inWorktree
|
|
1481
1485
|
? worktreeBasePath
|
|
1482
1486
|
: originalBasePath;
|
|
@@ -8,7 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
import { readdirSync } from "node:fs";
|
|
10
10
|
|
|
11
|
-
import { enterAutoWorktree
|
|
11
|
+
import { enterAutoWorktree } from "./auto-worktree-entry.js";
|
|
12
|
+
import { getAutoWorktreePath } from "./auto-worktree-path-resolution.js";
|
|
12
13
|
import { getIsolationMode } from "./preferences.js";
|
|
13
14
|
import { allWorktreesDirs } from "./worktree-manager.js";
|
|
14
15
|
import { isGsdWorktreePath, resolveWorktreeProjectRoot } from "./worktree-root.js";
|
|
@@ -244,6 +244,14 @@ export async function showInterviewRound(
|
|
|
244
244
|
let completed = false;
|
|
245
245
|
let removeAbortListener: (() => void) | undefined;
|
|
246
246
|
|
|
247
|
+
// Preview-panel scrolling. previewScroll is the first visible line of the
|
|
248
|
+
// side-by-side preview column; the viewport/total are captured on each
|
|
249
|
+
// render so PgUp/PgDn input can clamp against real bounds.
|
|
250
|
+
let previewScroll = 0;
|
|
251
|
+
let previewViewport = 0;
|
|
252
|
+
let previewTotal = 0;
|
|
253
|
+
function resetPreviewScroll() { previewScroll = 0; }
|
|
254
|
+
|
|
247
255
|
function finish(result: RoundResult) {
|
|
248
256
|
if (completed) return;
|
|
249
257
|
completed = true;
|
|
@@ -309,6 +317,7 @@ export async function showInterviewRound(
|
|
|
309
317
|
if (newIdx === currentIdx) return;
|
|
310
318
|
saveEditorToState();
|
|
311
319
|
currentIdx = newIdx;
|
|
320
|
+
resetPreviewScroll();
|
|
312
321
|
loadStateToEditor();
|
|
313
322
|
focusNotes = states[currentIdx].notesVisible && states[currentIdx].notes.length > 0;
|
|
314
323
|
refresh();
|
|
@@ -455,9 +464,20 @@ export async function showInterviewRound(
|
|
|
455
464
|
if (matchesKey(data, Key.right)) { switchQuestion((currentIdx + 1) % questions.length); return; }
|
|
456
465
|
}
|
|
457
466
|
|
|
467
|
+
// ── Preview scrolling ────────────────────────────────────────
|
|
468
|
+
if (matchesKey(data, Key.pageUp)) {
|
|
469
|
+
if (previewScroll > 0) { previewScroll = Math.max(0, previewScroll - previewViewport); refresh(); }
|
|
470
|
+
return;
|
|
471
|
+
}
|
|
472
|
+
if (matchesKey(data, Key.pageDown)) {
|
|
473
|
+
const maxScroll = Math.max(0, previewTotal - previewViewport);
|
|
474
|
+
if (previewScroll < maxScroll) { previewScroll = Math.min(maxScroll, previewScroll + previewViewport); refresh(); }
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
|
|
458
478
|
// ── Cursor navigation ────────────────────────────────────────
|
|
459
|
-
if (matchesKey(data, Key.up)) { st.cursorIndex = (st.cursorIndex - 1 + optCount) % optCount; refresh(); return; }
|
|
460
|
-
if (matchesKey(data, Key.down)) { st.cursorIndex = (st.cursorIndex + 1) % optCount; refresh(); return; }
|
|
479
|
+
if (matchesKey(data, Key.up)) { st.cursorIndex = (st.cursorIndex - 1 + optCount) % optCount; resetPreviewScroll(); refresh(); return; }
|
|
480
|
+
if (matchesKey(data, Key.down)) { st.cursorIndex = (st.cursorIndex + 1) % optCount; resetPreviewScroll(); refresh(); return; }
|
|
461
481
|
|
|
462
482
|
if (multiSel) {
|
|
463
483
|
const doneI = noneOrDoneIdx(currentIdx);
|
|
@@ -562,6 +582,12 @@ export async function showInterviewRound(
|
|
|
562
582
|
|
|
563
583
|
// ── Preview helpers ──────────────────────────────────────────────
|
|
564
584
|
|
|
585
|
+
// Centered dim label between horizontal rules, used to mark hidden/scrollable rows.
|
|
586
|
+
function scrollIndicator(lbl: string, colWidth: number): string {
|
|
587
|
+
const d = "─".repeat(Math.max(0, Math.floor((colWidth - lbl.length - 2) / 2)));
|
|
588
|
+
return truncateToWidth(theme.fg("dim", ` ${d} ${lbl} ${d}`), colWidth);
|
|
589
|
+
}
|
|
590
|
+
|
|
565
591
|
let mdThemeCache: ReturnType<typeof getMarkdownTheme> | null = null;
|
|
566
592
|
let previewCache: { markdown: string; width: number; lines: string[] } | null = null;
|
|
567
593
|
|
|
@@ -666,6 +692,10 @@ export async function showInterviewRound(
|
|
|
666
692
|
const useSideBySide = questionHasAnyPreview()
|
|
667
693
|
&& contentWidth >= (MIN_OPTIONS_WIDTH + MIN_PREVIEW_WIDTH + DIVIDER_WIDTH);
|
|
668
694
|
|
|
695
|
+
// No scrollable preview unless the side-by-side path sets these below.
|
|
696
|
+
previewTotal = 0;
|
|
697
|
+
previewViewport = 0;
|
|
698
|
+
|
|
669
699
|
if (useSideBySide) {
|
|
670
700
|
// ── Preview path ──────────────────────────────────────
|
|
671
701
|
const ui = makeUI(theme, contentWidth);
|
|
@@ -707,19 +737,35 @@ export async function showInterviewRound(
|
|
|
707
737
|
const leftLines = fullLeft.slice(0, maxBody);
|
|
708
738
|
if (fullLeft.length > maxBody) {
|
|
709
739
|
const n = fullLeft.length - maxBody + 1;
|
|
710
|
-
|
|
711
|
-
const d = "─".repeat(Math.max(0, Math.floor((leftWidth - lbl.length - 2) / 2)));
|
|
712
|
-
leftLines[maxBody - 1] = truncateToWidth(theme.fg("dim", ` ${d} ${lbl} ${d}`), leftWidth);
|
|
740
|
+
leftLines[maxBody - 1] = scrollIndicator(`+${n} lines hidden`, leftWidth);
|
|
713
741
|
}
|
|
714
742
|
|
|
715
743
|
const preview = getCurrentPreview();
|
|
716
744
|
const fullRight = preview ? renderPreviewColumn(preview, previewWidth) : [];
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
745
|
+
// The first two lines are the pinned "Preview" header; the body
|
|
746
|
+
// below them scrolls via PgUp/PgDn so no content is unreachable.
|
|
747
|
+
const headerRows = fullRight.length > 0 ? 2 : 0;
|
|
748
|
+
const previewBody = fullRight.slice(headerRows);
|
|
749
|
+
const bodyViewport = Math.max(1, maxBody - headerRows);
|
|
750
|
+
previewTotal = previewBody.length;
|
|
751
|
+
previewViewport = bodyViewport;
|
|
752
|
+
const maxScroll = Math.max(0, previewBody.length - bodyViewport);
|
|
753
|
+
if (previewScroll > maxScroll) previewScroll = maxScroll;
|
|
754
|
+
|
|
755
|
+
const rightLines = fullRight.slice(0, headerRows);
|
|
756
|
+
if (previewBody.length <= bodyViewport) {
|
|
757
|
+
rightLines.push(...previewBody);
|
|
758
|
+
} else {
|
|
759
|
+
rightLines.push(...previewBody.slice(previewScroll, previewScroll + bodyViewport));
|
|
760
|
+
const hiddenAbove = previewScroll;
|
|
761
|
+
const hiddenBelow = previewBody.length - (previewScroll + bodyViewport);
|
|
762
|
+
// Overwrite the top/bottom visible rows with scroll indicators.
|
|
763
|
+
if (hiddenAbove > 0) {
|
|
764
|
+
rightLines[headerRows] = scrollIndicator(`▲ ${hiddenAbove} more`, previewWidth);
|
|
765
|
+
}
|
|
766
|
+
if (hiddenBelow > 0) {
|
|
767
|
+
rightLines[rightLines.length - 1] = scrollIndicator(`▼ ${hiddenBelow} more · PgUp/PgDn`, previewWidth);
|
|
768
|
+
}
|
|
723
769
|
}
|
|
724
770
|
|
|
725
771
|
while (leftLines.length < maxBody) leftLines.push("");
|
|
@@ -744,6 +790,7 @@ export async function showInterviewRound(
|
|
|
744
790
|
if (isMultiQuestion) hints.push("←/→ navigate");
|
|
745
791
|
hints.push(isLast && allAnswered() ? "enter to review" : "enter to next");
|
|
746
792
|
}
|
|
793
|
+
if (previewTotal > previewViewport) hints.push("pgup/pgdn scroll preview");
|
|
747
794
|
hints.push("esc to exit");
|
|
748
795
|
const footer = ui.hints(hints)[0] ?? "";
|
|
749
796
|
|
|
@@ -16,6 +16,8 @@ import {
|
|
|
16
16
|
const ANSI_PATTERN = /\x1b\[[0-9;?]*[ -/]*[@-~]/g;
|
|
17
17
|
const ENTER = "\r";
|
|
18
18
|
const ESC = "\x1b";
|
|
19
|
+
const PAGE_DOWN = "\x1b[6~";
|
|
20
|
+
const PAGE_UP = "\x1b[5~";
|
|
19
21
|
|
|
20
22
|
before(() => { initTheme(); });
|
|
21
23
|
|
|
@@ -160,4 +162,34 @@ describe("interview-ui dialog borders", () => {
|
|
|
160
162
|
const widget = await captureWrapUpWidget();
|
|
161
163
|
assertFullOuterBorder(widget.render(80), 80);
|
|
162
164
|
});
|
|
165
|
+
|
|
166
|
+
it("makes an overflowing preview scrollable with PgUp/PgDn", async () => {
|
|
167
|
+
const longPreview = Array.from({ length: 60 }, (_, i) => `line ${i + 1}`).join("\n");
|
|
168
|
+
const widget = await captureInterviewWidget([{
|
|
169
|
+
...questions[0],
|
|
170
|
+
options: [
|
|
171
|
+
{ label: "Web App", description: "Frontend or full-stack", preview: longPreview },
|
|
172
|
+
],
|
|
173
|
+
}]);
|
|
174
|
+
|
|
175
|
+
// Initial render: content overflows, so a bottom "more" indicator and the
|
|
176
|
+
// scroll hint are shown, and the border stays intact.
|
|
177
|
+
const initial = stripAnsi(widget.render(100).join("\n"));
|
|
178
|
+
assertFullOuterBorder(widget.render(100), 100);
|
|
179
|
+
assert.match(initial, /▼ \d+ more/, "bottom scroll indicator should appear when preview overflows");
|
|
180
|
+
assert.match(initial, /pgup\/pgdn scroll preview/, "footer should hint at preview scrolling");
|
|
181
|
+
assert.doesNotMatch(initial, /▲ \d+ more/, "top indicator should be absent before scrolling");
|
|
182
|
+
|
|
183
|
+
// Scroll down: content below is now revealed and a top indicator appears.
|
|
184
|
+
widget.handleInput(PAGE_DOWN);
|
|
185
|
+
const scrolled = stripAnsi(widget.render(100).join("\n"));
|
|
186
|
+
assertFullOuterBorder(widget.render(100), 100);
|
|
187
|
+
assert.match(scrolled, /▲ \d+ more/, "top scroll indicator should appear after scrolling down");
|
|
188
|
+
assert.ok(scrolled !== initial, "scrolling should change the rendered preview");
|
|
189
|
+
|
|
190
|
+
// Scroll back up returns to the original view.
|
|
191
|
+
widget.handleInput(PAGE_UP);
|
|
192
|
+
const back = stripAnsi(widget.render(100).join("\n"));
|
|
193
|
+
assert.doesNotMatch(back, /▲ \d+ more/, "top indicator should disappear after scrolling back to top");
|
|
194
|
+
});
|
|
163
195
|
});
|
|
File without changes
|
|
File without changes
|